monomind 2.1.0 → 2.1.3
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 +74 -92
- package/package.json +3 -3
- package/packages/@monomind/cli/.claude/helpers/handlers/capture-handler.cjs +24 -10
- package/packages/@monomind/cli/.claude/helpers/handlers/gates-handler.cjs +2 -2
- package/packages/@monomind/cli/.claude/helpers/handlers/route-handler.cjs +29 -0
- package/packages/@monomind/cli/.claude/helpers/handlers/session-handler.cjs +35 -23
- package/packages/@monomind/cli/.claude/helpers/hook-handler.cjs +21 -0
- package/packages/@monomind/cli/.claude/helpers/utils/monograph.cjs +73 -2
- package/packages/@monomind/cli/README.md +74 -92
- package/packages/@monomind/cli/dist/src/browser/workflow/store.d.ts +2 -2
- package/packages/@monomind/cli/dist/src/commands/browse.d.ts +1 -1
- package/packages/@monomind/cli/dist/src/commands/doctor-env-checks.js +5 -0
- package/packages/@monomind/cli/dist/src/commands/org.js +46 -29
- package/packages/@monomind/cli/dist/src/commands/platforms.d.ts +1 -1
- package/packages/@monomind/cli/dist/src/init/executor.js +30 -6
- package/packages/@monomind/cli/dist/src/mcp-tools/auto-install.d.ts +8 -8
- package/packages/@monomind/cli/dist/src/mcp-tools/coherence/types.d.ts +31 -31
- package/packages/@monomind/cli/dist/src/mcp-tools/hive-mind-tools.js +5 -1
- package/packages/@monomind/cli/dist/src/mcp-tools/monograph-tools.js +28 -3
- package/packages/@monomind/cli/dist/src/mcp-tools/quality/coverage-analysis/prioritize-gaps.d.ts +36 -36
- package/packages/@monomind/cli/dist/src/mcp-tools/quality/security-compliance/detect-secrets.d.ts +4 -4
- package/packages/@monomind/cli/dist/src/memory/ewc-consolidation.d.ts +12 -0
- package/packages/@monomind/cli/dist/src/memory/sona-optimizer.d.ts +12 -0
- package/packages/@monomind/cli/dist/src/orgrt/broker.d.ts +3 -1
- package/packages/@monomind/cli/dist/src/orgrt/broker.js +8 -3
- package/packages/@monomind/cli/dist/src/orgrt/bus.d.ts +5 -1
- package/packages/@monomind/cli/dist/src/orgrt/bus.js +5 -1
- package/packages/@monomind/cli/dist/src/orgrt/daemon.d.ts +17 -1
- package/packages/@monomind/cli/dist/src/orgrt/daemon.js +115 -21
- package/packages/@monomind/cli/dist/src/orgrt/forwarder.js +41 -8
- package/packages/@monomind/cli/dist/src/orgrt/inbox.d.ts +11 -0
- package/packages/@monomind/cli/dist/src/orgrt/inbox.js +56 -0
- package/packages/@monomind/cli/dist/src/orgrt/policy.d.ts +5 -1
- package/packages/@monomind/cli/dist/src/orgrt/policy.js +58 -5
- package/packages/@monomind/cli/dist/src/orgrt/server.d.ts +3 -2
- package/packages/@monomind/cli/dist/src/orgrt/server.js +7 -40
- package/packages/@monomind/cli/dist/src/orgrt/session.d.ts +10 -1
- package/packages/@monomind/cli/dist/src/orgrt/session.js +24 -1
- package/packages/@monomind/cli/dist/src/orgrt/test-loop.js +8 -8
- package/packages/@monomind/cli/dist/src/orgrt/types.d.ts +52 -52
- package/packages/@monomind/cli/dist/src/output.d.ts +29 -29
- package/packages/@monomind/cli/dist/src/output.js +10 -2
- package/packages/@monomind/cli/dist/src/types.d.ts +2 -2
- package/packages/@monomind/cli/dist/src/ui/dashboard.html +203 -9
- package/packages/@monomind/cli/dist/src/ui/orgs-files.js +192 -0
- package/packages/@monomind/cli/dist/src/ui/orgs.html +21 -52
- package/packages/@monomind/cli/dist/src/ui/server.mjs +42 -6
- package/packages/@monomind/cli/package.json +12 -16
- package/packages/@monomind/cli/dist/src/orgrt/live.html +0 -56
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
<h1 align="center">Monomind</h1>
|
|
6
6
|
|
|
7
7
|
<p align="center">
|
|
8
|
-
<strong>
|
|
9
|
-
|
|
8
|
+
<strong>An open-source MCP server that extends Claude Code with a codebase knowledge graph, persistent memory, and multi-agent coordination.</strong><br/>
|
|
9
|
+
MIT licensed · Fully local · No data leaves your machine
|
|
10
10
|
</p>
|
|
11
11
|
|
|
12
12
|
<p align="center">
|
|
@@ -30,126 +30,105 @@
|
|
|
30
30
|
|
|
31
31
|
## What is Monomind?
|
|
32
32
|
|
|
33
|
-
Claude Code
|
|
33
|
+
Monomind is an **open-source CLI and MCP server** that plugs into Claude Code via the standard [Model Context Protocol](https://modelcontextprotocol.io/). It adds capabilities that Claude Code doesn't ship with out of the box:
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
- **Codebase knowledge graph** — tree-sitter parses your code into a SQLite-backed graph of files, functions, classes, and their relationships. Query imports, callers, and blast radius before making changes.
|
|
36
|
+
- **Persistent memory** — a JSON pattern store with episodic recall that survives across sessions. Agents and orgs share context without re-prompting.
|
|
37
|
+
- **Multi-agent coordination** — in-session, spawn ad-hoc agent teams via Claude Code's Task tool; for persistent background work, `monomind org run` starts a real SDK-backed daemon with policy-gated role agents and a live dashboard.
|
|
38
|
+
- **Reusable slash commands** — 30+ development workflows (build, review, debug, TDD, architecture) available as `/mastermind:*` commands inside Claude Code.
|
|
36
39
|
|
|
37
40
|
```bash
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
# Or run the autonomous code improvement loop
|
|
43
|
-
/mastermind:autodev --tillend --focus security
|
|
41
|
+
npm install -g monomind # MIT licensed, 0 external API calls
|
|
42
|
+
cd your-project && monomind init
|
|
43
|
+
claude mcp add monomind npx monomind mcp start
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
### Trust & Security
|
|
47
|
+
|
|
48
|
+
| Concern | Answer |
|
|
49
|
+
|---|---|
|
|
50
|
+
| **License** | [MIT](LICENSE) — use it however you want |
|
|
51
|
+
| **Data privacy** | Everything runs locally. No telemetry, no phone-home, no external API calls from Monomind itself. Your code stays on your machine. |
|
|
52
|
+
| **Dependencies** | Standard npm packages (tree-sitter, sql.js, zod). No native binaries. No post-install scripts that download code. |
|
|
53
|
+
| **Permissions** | Registers as an MCP server — Claude Code controls what tools are available and prompts you before executing anything sensitive. |
|
|
54
|
+
| **Source** | Fully open. Read every line at [github.com/monoes/monomind](https://github.com/monoes/monomind). |
|
|
55
|
+
| **Maintenance** | Active development, regular releases on npm. |
|
|
47
56
|
|
|
48
57
|
---
|
|
49
58
|
|
|
50
59
|
## 🏢 Autonomous Organizations
|
|
51
60
|
|
|
52
|
-
> **This is the headline feature.**
|
|
61
|
+
> **This is the headline feature.** `monomind org run` starts a persistent, SDK-backed daemon that runs an autonomous agent organization — roles, hierarchy, policy-gated tool access, a live dashboard — until you stop it.
|
|
53
62
|
|
|
54
63
|
### The idea
|
|
55
64
|
|
|
56
|
-
Every business function needs a team.
|
|
65
|
+
Every business function needs a team. Define the org once as a JSON file — goal, roles, who reports to whom, per-role tool/file/budget policy — then run it as a real background daemon backed by the Claude Agent SDK. It persists across sessions, serves a live WebSocket dashboard, and can discover and message other Monomind orgs running on the same machine.
|
|
57
66
|
|
|
58
67
|
```mermaid
|
|
59
68
|
flowchart TD
|
|
60
69
|
U(["You"])
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
BOSS["Boss Agent\
|
|
64
|
-
W["Writer
|
|
70
|
+
DEF["org.json\nGoal + roles + policy"]
|
|
71
|
+
RUN["monomind org run\nStart SDK daemon"]
|
|
72
|
+
BOSS["Boss Agent\nAgent SDK session"]
|
|
73
|
+
W["Writer"]
|
|
65
74
|
S["SEO Specialist"]
|
|
66
75
|
R["Reviewer"]
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
MEM[("Persistent\nMemory")]
|
|
76
|
+
DASH[("Live Dashboard\n:4243")]
|
|
77
|
+
XORG[("Other orgs\ncross-process")]
|
|
70
78
|
|
|
71
|
-
U -->
|
|
79
|
+
U --> DEF --> RUN --> BOSS
|
|
72
80
|
BOSS -->|spawns| W
|
|
73
81
|
BOSS -->|spawns| S
|
|
74
82
|
BOSS -->|spawns| R
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
W <-->|stores output| MEM
|
|
78
|
-
S <-->|reads context| MEM
|
|
83
|
+
RUN <-->|serves| DASH
|
|
84
|
+
RUN <-.->|--cross-process| XORG
|
|
79
85
|
|
|
80
86
|
style BOSS fill:#00D2AA22,stroke:#00D2AA
|
|
81
|
-
style
|
|
82
|
-
style
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
### Two commands to a running org
|
|
86
|
-
|
|
87
|
-
**Step 1 — Design it:**
|
|
88
|
-
|
|
87
|
+
style DASH fill:#F59E0B22,stroke:#F59E0B
|
|
88
|
+
style XORG fill:#8B5CF622,stroke:#8B5CF6
|
|
89
89
|
```
|
|
90
|
-
/ mastermind:createorg content-team
|
|
91
|
-
"Build and publish 3 blog posts per week on AI dev tools"
|
|
92
|
-
|
|
93
|
-
Deriving roles from goal...
|
|
94
|
-
|
|
95
|
-
╔ ORG: content-team
|
|
96
|
-
║ TOPOLOGY: star (5 roles)
|
|
97
90
|
|
|
98
|
-
|
|
99
|
-
writer → Content Creator
|
|
100
|
-
reviewer → reviewer
|
|
101
|
-
marketer → Growth Hacker
|
|
102
|
-
seo → SEO Specialist
|
|
91
|
+
### Run one
|
|
103
92
|
|
|
104
|
-
|
|
105
|
-
|
|
93
|
+
```bash
|
|
94
|
+
# .monomind/orgs/<name>.json defines the org: goal, roles, policy.
|
|
95
|
+
# See .monomind/orgs/sample-team.json in a fresh `monomind init` for a working example.
|
|
106
96
|
|
|
107
|
-
|
|
108
|
-
→ Run: /mastermind:runorg --org content-team
|
|
109
|
-
```
|
|
97
|
+
monomind org run content-team --task "Build and publish 3 blog posts per week"
|
|
110
98
|
|
|
111
|
-
|
|
99
|
+
# ✓ Live dashboard: http://localhost:4243
|
|
100
|
+
# ✓ Boss agent (Claude Agent SDK session) spawns, reads the org goal,
|
|
101
|
+
# assigns work to role agents, coordinates until the task completes
|
|
102
|
+
# or you stop it.
|
|
112
103
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
# Boss agent spawns in background
|
|
117
|
-
# Coordinates all roles via shared task board
|
|
118
|
-
# Checkpoints every 30 minutes
|
|
119
|
-
# Loops until you stop it
|
|
104
|
+
monomind org status content-team # runtime state
|
|
105
|
+
monomind org stop content-team # request a graceful stop
|
|
106
|
+
monomind org list # every org + status
|
|
120
107
|
```
|
|
121
108
|
|
|
122
109
|
### What runs under the hood
|
|
123
110
|
|
|
124
111
|
| What | How |
|
|
125
112
|
|---|---|
|
|
126
|
-
| **
|
|
127
|
-
| **
|
|
128
|
-
| **
|
|
129
|
-
| **
|
|
130
|
-
| **
|
|
131
|
-
| **Governance** | `auto` (free), `board` (approve sensitive), `strict` (approve all external actions) |
|
|
132
|
-
|
|
133
|
-
### Topology is auto-derived
|
|
134
|
-
|
|
135
|
-
```mermaid
|
|
136
|
-
graph LR
|
|
137
|
-
A["1-3 roles"] -->|mesh| B["All-to-all\ndirect comms"]
|
|
138
|
-
C["4-6 roles"] -->|star| D["Boss to workers\nfan-out"]
|
|
139
|
-
E["7+ roles"] -->|hierarchical| F["Boss to leads to workers\nmiddle management"]
|
|
140
|
-
```
|
|
113
|
+
| **OrgDaemon** | Hosts one or more orgs in a single process; real Claude Agent SDK sessions per role, not simulated |
|
|
114
|
+
| **PolicyEngine** | Per-role gates on tool access, file read/write scope, web access, token budget — enforced, with a full audit trail |
|
|
115
|
+
| **Live dashboard** | WebSocket-served at `:4243` by default (`--port` to change, `--serve=false` to disable) |
|
|
116
|
+
| **Cross-process comms** | `--cross-process` (default on) lets orgs on different `monomind` processes/projects discover and message each other |
|
|
117
|
+
| **Scheduling** | `monomind org serve` hosts orgs whose definition has a `schedule` field, running them on interval |
|
|
141
118
|
|
|
142
119
|
### Org management commands
|
|
143
120
|
|
|
144
121
|
```bash
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
122
|
+
monomind org run <name> [--task "..."] [--port N] [--cross-process] # start a daemon
|
|
123
|
+
monomind org stop <name> # request a running org to stop
|
|
124
|
+
monomind org status [name] # runtime state for one or all orgs
|
|
125
|
+
monomind org list # list every org + status
|
|
126
|
+
monomind org serve [--port N] # host-only mode, runs scheduled orgs
|
|
127
|
+
monomind org delete <name> # remove an org
|
|
151
128
|
```
|
|
152
129
|
|
|
130
|
+
> **Note:** the older `/mastermind:createorg` + `/mastermind:runorg` prompt-orchestrated flow is deprecated — it has no delivery guarantees or ground-truth event stream. It still runs for orgs not yet migrated, but new orgs should use `monomind org run` directly against a hand-authored `.monomind/orgs/<name>.json`.
|
|
131
|
+
|
|
153
132
|
---
|
|
154
133
|
|
|
155
134
|
## ⚡ The Autonomous Build Loop
|
|
@@ -206,11 +185,11 @@ claude mcp add monomind npx monomind mcp start
|
|
|
206
185
|
monomind doctor --fix
|
|
207
186
|
```
|
|
208
187
|
|
|
209
|
-
Open Claude Code. You now have
|
|
188
|
+
Open Claude Code. You now have 60+ slash commands available:
|
|
210
189
|
|
|
211
190
|
```bash
|
|
212
191
|
/mastermind:autodev --tillend # start autonomous code loop
|
|
213
|
-
|
|
192
|
+
monomind org run my-team # run your first AI org (see .monomind/orgs/sample-team.json)
|
|
214
193
|
/mastermind:help # show all commands
|
|
215
194
|
```
|
|
216
195
|
|
|
@@ -262,7 +241,7 @@ Before touching any file, Monomind queries **Monograph** — a SQLite-backed kno
|
|
|
262
241
|
|
|
263
242
|
## 🎣 Hooks & Workers
|
|
264
243
|
|
|
265
|
-
Monomind wires
|
|
244
|
+
Monomind wires 29 hook subcommands into Claude Code across edit, task, command, and session lifecycle events — logging patterns, routing agents, and feeding the intelligence system.
|
|
266
245
|
|
|
267
246
|
```mermaid
|
|
268
247
|
flowchart LR
|
|
@@ -296,7 +275,7 @@ const result = await fence.detect(userInput);
|
|
|
296
275
|
|
|
297
276
|
---
|
|
298
277
|
|
|
299
|
-
## 📋
|
|
278
|
+
## 📋 60+ Slash Commands
|
|
300
279
|
|
|
301
280
|
Everything runs from inside Claude Code via slash commands. Here's the highlight reel:
|
|
302
281
|
|
|
@@ -315,9 +294,9 @@ Everything runs from inside Claude Code via slash commands. Here's the highlight
|
|
|
315
294
|
### Organizations
|
|
316
295
|
| Command | What it does |
|
|
317
296
|
|---|---|
|
|
318
|
-
|
|
|
319
|
-
|
|
|
320
|
-
|
|
|
297
|
+
| `monomind org run <name>` | Start an org as a real SDK-backed daemon |
|
|
298
|
+
| `monomind org status` / `list` | Runtime state for one or all orgs |
|
|
299
|
+
| `monomind org stop <name>` | Request a graceful stop |
|
|
321
300
|
| `/mastermind:approve` | Action pending approval requests |
|
|
322
301
|
|
|
323
302
|
### Business Domains
|
|
@@ -329,7 +308,7 @@ Everything runs from inside Claude Code via slash commands. Here's the highlight
|
|
|
329
308
|
| `/mastermind:finance` | Budgets, invoicing, modeling |
|
|
330
309
|
| `/mastermind:ops` | Operations and workflow automation |
|
|
331
310
|
|
|
332
|
-
**[→ Full reference (
|
|
311
|
+
**[→ Full reference (60+ commands)](https://monoes.github.io/monomind/#slash)**
|
|
333
312
|
|
|
334
313
|
---
|
|
335
314
|
|
|
@@ -351,24 +330,27 @@ graph TD
|
|
|
351
330
|
CC["Claude Code"]
|
|
352
331
|
MCP["MCP Server\nmonomind mcp start"]
|
|
353
332
|
D["Background Workers\n(@monomind/hooks, in-process)"]
|
|
333
|
+
ORG["OrgDaemon\nmonomind org run\nreal SDK sessions"]
|
|
354
334
|
|
|
355
|
-
CC <-->|"MCP tools: monograph, memory
|
|
335
|
+
CC <-->|"MCP tools: monograph, memory"| MCP
|
|
356
336
|
MCP <--> D
|
|
357
337
|
|
|
358
338
|
D --> ADB[("Memory store\npatterns + episodes")]
|
|
359
339
|
D --> MG[("Monograph\ncode graph")]
|
|
360
|
-
D --> HK["Hooks\
|
|
361
|
-
D --> SW["Swarm\n4 topologies\n3 consensus strategies"]
|
|
340
|
+
D --> HK["Hooks\n29 subcommands"]
|
|
362
341
|
|
|
363
|
-
CC -->|"Task tool - spawns agents"| AG["
|
|
342
|
+
CC -->|"Task tool - spawns agents"| AG["In-session agents\narchitect, coder\ntester, reviewer\nsecurity, perf"]
|
|
364
343
|
AG <-->|reads and writes| ADB
|
|
344
|
+
ORG -->|"spawns, policy-gated"| RA["Role agents"]
|
|
345
|
+
ORG <-->|reads and writes| ADB
|
|
365
346
|
|
|
366
347
|
style CC fill:#00D2AA22,stroke:#00D2AA
|
|
367
348
|
style AG fill:#8B5CF622,stroke:#8B5CF6
|
|
368
349
|
style ADB fill:#F59E0B22,stroke:#F59E0B
|
|
350
|
+
style ORG fill:#F59E0B22,stroke:#F59E0B
|
|
369
351
|
```
|
|
370
352
|
|
|
371
|
-
**Claude Code
|
|
353
|
+
**Claude Code's Task tool drives in-session multi-agent work; `monomind org run` drives persistent background orgs.** Your data never leaves your machine.
|
|
372
354
|
|
|
373
355
|
---
|
|
374
356
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { WorkflowDef, RunRecord } from './types.js';
|
|
2
2
|
export declare class WorkflowStoreError extends Error {
|
|
3
|
-
readonly cause?: unknown
|
|
4
|
-
constructor(message: string, cause?: unknown
|
|
3
|
+
readonly cause?: unknown;
|
|
4
|
+
constructor(message: string, cause?: unknown);
|
|
5
5
|
}
|
|
6
6
|
export declare function readWorkflow(filePath: string): Promise<WorkflowDef>;
|
|
7
7
|
export declare function writeRunRecord(record: RunRecord): Promise<void>;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
declare const browseCommand: {
|
|
2
|
-
subcommands: import("../types.js").Command[];
|
|
3
2
|
name: string;
|
|
4
3
|
description: string;
|
|
5
4
|
aliases?: string[];
|
|
@@ -7,6 +6,7 @@ declare const browseCommand: {
|
|
|
7
6
|
examples?: import("@monoes/monobrowse/cli/types").CommandExample[];
|
|
8
7
|
action?: import("@monoes/monobrowse/cli/types").CommandAction;
|
|
9
8
|
hidden?: boolean;
|
|
9
|
+
subcommands: import("../types.js").Command[];
|
|
10
10
|
};
|
|
11
11
|
export default browseCommand;
|
|
12
12
|
//# sourceMappingURL=browse.d.ts.map
|
|
@@ -87,6 +87,11 @@ export async function checkDiskSpace() {
|
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
export async function checkBuildTools() {
|
|
90
|
+
// Only meaningful for Node/TS projects — a Go, Python, or Rust repo has no
|
|
91
|
+
// reason to install TypeScript, and warning about it there is just noise.
|
|
92
|
+
if (!existsSync(join(process.cwd(), 'package.json'))) {
|
|
93
|
+
return { name: 'TypeScript', status: 'pass', message: 'N/A — no package.json (not a Node.js project)' };
|
|
94
|
+
}
|
|
90
95
|
try {
|
|
91
96
|
const tscVersion = await runCommand('npx tsc --version', 10000);
|
|
92
97
|
if (!tscVersion || tscVersion.includes('not found')) {
|
|
@@ -19,12 +19,20 @@ function validateOrgName(name) {
|
|
|
19
19
|
}
|
|
20
20
|
return { ok: true, name };
|
|
21
21
|
}
|
|
22
|
-
/**
|
|
23
|
-
*
|
|
24
|
-
|
|
22
|
+
/** Suffixes of org-internal artifact files (state/goals/threads/etc) that
|
|
23
|
+
* share the `<org>.json`/`.jsonl` naming pattern with the org's own config
|
|
24
|
+
* file. Single source of truth for both listOrgConfigFiles() (which must
|
|
25
|
+
* exclude them when discovering real org configs) and deleteAction (which
|
|
26
|
+
* must remove all of them when deleting an org). */
|
|
27
|
+
const ORG_ARTIFACT_SUFFIXES = [
|
|
28
|
+
'-state', '-goals', '-threads', '-activity', '-approvals', '-members', '-secrets', '-budgets',
|
|
29
|
+
'-routines', '-issues', '-projects', '-workspaces', '-worktrees', '-environments',
|
|
30
|
+
'-plugins', '-adapters', '-join-requests', '-bootstrap', '-project-workspaces',
|
|
31
|
+
'-approval-comments', '-skills',
|
|
32
|
+
];
|
|
25
33
|
function listOrgConfigFiles(orgsDir) {
|
|
26
34
|
return readdirSync(orgsDir)
|
|
27
|
-
.filter(f => f.endsWith('.json') && !ORG_ARTIFACT_SUFFIXES.some(suf => f.includes(suf)));
|
|
35
|
+
.filter(f => f.endsWith('.json') && !f.startsWith('._') && !ORG_ARTIFACT_SUFFIXES.some(suf => f.includes(suf)));
|
|
28
36
|
}
|
|
29
37
|
/** Remove a lingering stopfile so a fresh `org run` doesn't self-terminate. */
|
|
30
38
|
export const clearStopfile = (cwd, name) => {
|
|
@@ -32,22 +40,27 @@ export const clearStopfile = (cwd, name) => {
|
|
|
32
40
|
};
|
|
33
41
|
const runAction = async (ctx) => {
|
|
34
42
|
if (!ctx.args[0])
|
|
35
|
-
return { success: false, message: 'org name required: monomind org run <name> [--task "..."]
|
|
43
|
+
return { success: false, message: 'org name required: monomind org run <name> [--task "..."]' };
|
|
36
44
|
const validated = validateOrgName(ctx.args[0]);
|
|
37
45
|
if (!validated.ok)
|
|
38
46
|
return validated.result;
|
|
39
47
|
const name = validated.name;
|
|
48
|
+
// A repeated --task flag is promoted to an array by the parser (deliberate,
|
|
49
|
+
// documented behavior elsewhere — repeats never silently drop a value); a
|
|
50
|
+
// plain `as string` cast would let that array flow straight into the org's
|
|
51
|
+
// goal and get stringified as "a,b" with no warning. Checked before any
|
|
52
|
+
// side effects (starting the xdeliver listener) run.
|
|
53
|
+
const taskFlag = ctx.flags['task'];
|
|
54
|
+
if (Array.isArray(taskFlag))
|
|
55
|
+
return { success: false, message: '--task was passed more than once — pass it exactly once' };
|
|
40
56
|
const crossProcess = ctx.flags['crossProcess'] !== false;
|
|
41
57
|
const daemon = new OrgDaemon(ctx.cwd, { crossProcess });
|
|
42
58
|
let srv;
|
|
43
|
-
if (
|
|
44
|
-
|
|
45
|
-
srv
|
|
46
|
-
log(output.info(`org live view: http://localhost:${srv.port}`));
|
|
47
|
-
if (crossProcess)
|
|
48
|
-
daemon.setInboxUrl(`http://127.0.0.1:${srv.port}`);
|
|
59
|
+
if (crossProcess) {
|
|
60
|
+
srv = await startOrgServer(daemon, 0);
|
|
61
|
+
daemon.setInboxUrl(`http://127.0.0.1:${srv.port}`);
|
|
49
62
|
}
|
|
50
|
-
const running = await daemon.startOrg(name,
|
|
63
|
+
const running = await daemon.startOrg(name, taskFlag);
|
|
51
64
|
log(output.info(`org ${name} running (${running.def.roles.length} agents, run ${running.run}) — Ctrl-C or "monomind org stop ${name}" to stop`));
|
|
52
65
|
// stopfile poll lets `org stop` work from another terminal;
|
|
53
66
|
// clear any stale stopfile from a previous run before polling
|
|
@@ -101,10 +114,12 @@ const statusAction = async (ctx) => {
|
|
|
101
114
|
const serveAction = async (ctx) => {
|
|
102
115
|
const crossProcess = ctx.flags['crossProcess'] !== false;
|
|
103
116
|
const daemon = new OrgDaemon(ctx.cwd, { crossProcess });
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
117
|
+
let srv;
|
|
118
|
+
if (crossProcess) {
|
|
119
|
+
srv = await startOrgServer(daemon, 0);
|
|
107
120
|
daemon.setInboxUrl(`http://127.0.0.1:${srv.port}`);
|
|
121
|
+
}
|
|
122
|
+
log(output.info('org daemon serving — Ctrl-C to stop'));
|
|
108
123
|
// schedule orgs whose definition declares an interval (e.g. "15m", "2h")
|
|
109
124
|
const { OrgScheduler, parseSchedule } = await import('../orgrt/scheduler.js');
|
|
110
125
|
const sched = new OrgScheduler(async (name, intervalMs) => {
|
|
@@ -137,7 +152,7 @@ const serveAction = async (ctx) => {
|
|
|
137
152
|
});
|
|
138
153
|
const orgDir = join(ctx.cwd, ORG_DIR);
|
|
139
154
|
if (existsSync(orgDir)) {
|
|
140
|
-
for (const f of
|
|
155
|
+
for (const f of listOrgConfigFiles(orgDir)) {
|
|
141
156
|
try {
|
|
142
157
|
const def = JSON.parse(readFileSync(join(orgDir, f), 'utf8'));
|
|
143
158
|
const ms = parseSchedule(def.schedule);
|
|
@@ -150,13 +165,15 @@ const serveAction = async (ctx) => {
|
|
|
150
165
|
log(output.info(`scheduled org ${stem} every ${Math.round(ms / 60_000)}m`));
|
|
151
166
|
}
|
|
152
167
|
}
|
|
153
|
-
catch {
|
|
168
|
+
catch (err) {
|
|
169
|
+
log(output.warning(`org file ${f}: could not parse — skipping (${err instanceof Error ? err.message : 'invalid JSON'})`));
|
|
170
|
+
}
|
|
154
171
|
}
|
|
155
172
|
}
|
|
156
173
|
await new Promise(r => { process.once('SIGINT', () => r()); process.once('SIGTERM', () => r()); });
|
|
157
174
|
sched.stop();
|
|
158
175
|
await daemon.stopAll();
|
|
159
|
-
srv
|
|
176
|
+
srv?.close();
|
|
160
177
|
return { success: true };
|
|
161
178
|
};
|
|
162
179
|
const testLoopAction = async (ctx) => {
|
|
@@ -191,7 +208,7 @@ const deleteAction = async (ctx) => {
|
|
|
191
208
|
log(output.error('Usage: monomind org delete <name>'));
|
|
192
209
|
return { success: false, message: 'org name required' };
|
|
193
210
|
}
|
|
194
|
-
if (
|
|
211
|
+
if (!ORG_NAME_RE.test(orgName)) {
|
|
195
212
|
log(output.error(`Invalid org name: ${orgName}`));
|
|
196
213
|
return { success: false, message: 'invalid org name' };
|
|
197
214
|
}
|
|
@@ -208,12 +225,8 @@ const deleteAction = async (ctx) => {
|
|
|
208
225
|
log(output.error(`Org not found: ${orgName}`));
|
|
209
226
|
return { success: false, message: 'org not found' };
|
|
210
227
|
}
|
|
211
|
-
const suffixes = ['', '-state', '-goals', '-routines', '-approvals', '-activity',
|
|
212
|
-
'-issues', '-members', '-projects', '-workspaces', '-worktrees', '-environments',
|
|
213
|
-
'-plugins', '-adapters', '-budgets', '-threads', '-secrets', '-join-requests',
|
|
214
|
-
'-bootstrap', '-project-workspaces', '-approval-comments', '-skills'];
|
|
215
228
|
let removed = 0;
|
|
216
|
-
for (const suf of
|
|
229
|
+
for (const suf of ['', ...ORG_ARTIFACT_SUFFIXES]) {
|
|
217
230
|
for (const ext of ['.json', '.jsonl']) {
|
|
218
231
|
const f = join(orgsDir, `${orgName}${suf}${ext}`);
|
|
219
232
|
try {
|
|
@@ -248,7 +261,7 @@ const deleteAction = async (ctx) => {
|
|
|
248
261
|
};
|
|
249
262
|
const markCompleteAction = async (ctx) => {
|
|
250
263
|
const orgName = ctx.args[0];
|
|
251
|
-
if (!orgName ||
|
|
264
|
+
if (!orgName || !ORG_NAME_RE.test(orgName)) {
|
|
252
265
|
log(output.error('Usage: monomind org mark-complete <name>'));
|
|
253
266
|
return { success: false, message: 'valid org name required' };
|
|
254
267
|
}
|
|
@@ -284,8 +297,6 @@ export const orgCommand = {
|
|
|
284
297
|
name: 'run', description: 'Start an org (foreground daemon)',
|
|
285
298
|
options: [
|
|
286
299
|
{ name: 'task', description: 'Override the org goal for this run', type: 'string' },
|
|
287
|
-
{ name: 'serve', description: 'Serve the live dashboard (default true)', type: 'boolean', default: true },
|
|
288
|
-
{ name: 'port', description: 'Live dashboard port', type: 'number', default: 4243 },
|
|
289
300
|
{ name: 'cross-process', description: 'Discover and message orgs hosted by other monomind processes on this machine (default true)', type: 'boolean', default: true },
|
|
290
301
|
],
|
|
291
302
|
examples: [{ command: 'monomind org run growth --task "weekly report"', description: 'Run the growth org once with a task' }],
|
|
@@ -296,7 +307,6 @@ export const orgCommand = {
|
|
|
296
307
|
{
|
|
297
308
|
name: 'serve', description: 'Start the daemon server only (hosts scheduled orgs)',
|
|
298
309
|
options: [
|
|
299
|
-
{ name: 'port', description: 'Port', type: 'number', default: 4243 },
|
|
300
310
|
{ name: 'cross-process', description: 'Discover and message orgs hosted by other monomind processes on this machine (default true)', type: 'boolean', default: true },
|
|
301
311
|
],
|
|
302
312
|
action: serveAction,
|
|
@@ -315,7 +325,14 @@ export const orgCommand = {
|
|
|
315
325
|
{ name: 'mark-complete', description: 'Manually close a stale/crashed run', action: markCompleteAction },
|
|
316
326
|
],
|
|
317
327
|
examples: [{ command: 'monomind org run my-org', description: 'Run an org under full daemon control' }],
|
|
318
|
-
action: async () =>
|
|
328
|
+
action: async () => {
|
|
329
|
+
// index.ts's dispatcher never prints result.message on a failed action —
|
|
330
|
+
// it only exits with result.exitCode — so this must log itself or bare
|
|
331
|
+
// `monomind org` exits silently with code 1 and zero output.
|
|
332
|
+
const message = 'usage: monomind org <run|stop|status|serve|test-loop|list|delete|mark-complete>';
|
|
333
|
+
log(output.error(message));
|
|
334
|
+
return { success: false, message };
|
|
335
|
+
},
|
|
319
336
|
};
|
|
320
337
|
export default orgCommand;
|
|
321
338
|
//# sourceMappingURL=org.js.map
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* github.com/monoes/monomind
|
|
6
6
|
*/
|
|
7
7
|
import type { Command } from '../types.js';
|
|
8
|
-
export declare const SUPPORTED_PLATFORMS: readonly [
|
|
8
|
+
export declare const SUPPORTED_PLATFORMS: readonly ['claude', 'gemini', 'cursor', 'vscode', 'copilot', 'opencode', 'aider', 'kiro', 'trae', 'claw', 'droid', 'antigravity', 'hermes', 'codex'];
|
|
9
9
|
export type Platform = typeof SUPPORTED_PLATFORMS[number];
|
|
10
10
|
export declare const platformsCommand: Command;
|
|
11
11
|
//# sourceMappingURL=platforms.d.ts.map
|
|
@@ -575,6 +575,13 @@ export async function executeUpgrade(targetDir, upgradeSettings = false) {
|
|
|
575
575
|
const destHelpersDir = path.join(targetDir, '.claude', 'helpers');
|
|
576
576
|
// Copy top-level critical files atomically
|
|
577
577
|
const criticalHelpers = ['auto-memory-hook.mjs', 'hook-handler.cjs', 'intelligence.cjs', 'statusline.cjs', 'graphify-freshen.cjs'];
|
|
578
|
+
// Generated fallback for any critical helper missing from the source dir itself
|
|
579
|
+
// (e.g. the published npm template lacking auto-memory-hook.mjs).
|
|
580
|
+
const criticalGenerators = {
|
|
581
|
+
'hook-handler.cjs': generateHookHandler,
|
|
582
|
+
'intelligence.cjs': generateIntelligenceStub,
|
|
583
|
+
'auto-memory-hook.mjs': generateAutoMemoryHook,
|
|
584
|
+
};
|
|
578
585
|
for (const helperName of criticalHelpers) {
|
|
579
586
|
const targetPath = path.join(destHelpersDir, helperName);
|
|
580
587
|
const sourcePath = path.join(sourceHelpersForUpgrade, helperName);
|
|
@@ -594,6 +601,17 @@ export async function executeUpgrade(targetDir, upgradeSettings = false) {
|
|
|
594
601
|
catch { }
|
|
595
602
|
fs.renameSync(tmp, targetPath);
|
|
596
603
|
}
|
|
604
|
+
else if (!fs.existsSync(targetPath) && criticalGenerators[helperName]) {
|
|
605
|
+
const content = criticalGenerators[helperName]();
|
|
606
|
+
const tmp = `${targetPath}.${process.pid}.tmp`;
|
|
607
|
+
fs.writeFileSync(tmp, content, 'utf-8');
|
|
608
|
+
try {
|
|
609
|
+
fs.chmodSync(tmp, 0o755);
|
|
610
|
+
}
|
|
611
|
+
catch { }
|
|
612
|
+
fs.renameSync(tmp, targetPath);
|
|
613
|
+
result.created.push(`.claude/helpers/${helperName}`);
|
|
614
|
+
}
|
|
597
615
|
}
|
|
598
616
|
// Always recursively sync subdirectories (utils/, handlers/) — required by hook-handler.cjs.
|
|
599
617
|
// Uses recursive copy so any future nested subdirs are also covered.
|
|
@@ -1222,7 +1240,6 @@ async function writeHelpers(targetDir, options, result) {
|
|
|
1222
1240
|
const sourceHelpersDir = findSourceHelpersDir(options.sourceBaseDir);
|
|
1223
1241
|
// Try to copy existing helpers from source first (recursive — includes utils/ and handlers/)
|
|
1224
1242
|
if (sourceHelpersDir && fs.existsSync(sourceHelpersDir)) {
|
|
1225
|
-
let copiedCount = 0;
|
|
1226
1243
|
const copyRecursive = (srcDir, destDir, relBase) => {
|
|
1227
1244
|
fs.mkdirSync(destDir, { recursive: true });
|
|
1228
1245
|
for (const entry of fs.readdirSync(srcDir, { withFileTypes: true })) {
|
|
@@ -1242,7 +1259,6 @@ async function writeHelpers(targetDir, options, result) {
|
|
|
1242
1259
|
fs.chmodSync(destPath, '755');
|
|
1243
1260
|
}
|
|
1244
1261
|
result.created.files.push(`.claude/helpers/${relPath}`);
|
|
1245
|
-
copiedCount++;
|
|
1246
1262
|
}
|
|
1247
1263
|
else {
|
|
1248
1264
|
result.skipped.push(`.claude/helpers/${relPath}`);
|
|
@@ -1251,11 +1267,12 @@ async function writeHelpers(targetDir, options, result) {
|
|
|
1251
1267
|
}
|
|
1252
1268
|
};
|
|
1253
1269
|
copyRecursive(sourceHelpersDir, helpersDir, '');
|
|
1254
|
-
if (copiedCount > 0) {
|
|
1255
|
-
return; // Skip generating if we copied from source
|
|
1256
|
-
}
|
|
1257
1270
|
}
|
|
1258
|
-
//
|
|
1271
|
+
// Always run the fallback generator too — it only fills in files still missing
|
|
1272
|
+
// after the source copy above (it no-ops on anything the copy already wrote).
|
|
1273
|
+
// Without this, a source dir that's present but incomplete (e.g. missing
|
|
1274
|
+
// auto-memory-hook.mjs) silently ships a project wired to hooks that reference
|
|
1275
|
+
// a file that was never installed.
|
|
1259
1276
|
const helpers = {
|
|
1260
1277
|
'pre-commit': generatePreCommitHook(),
|
|
1261
1278
|
'post-commit': generatePostCommitHook(),
|
|
@@ -1268,6 +1285,13 @@ async function writeHelpers(targetDir, options, result) {
|
|
|
1268
1285
|
};
|
|
1269
1286
|
for (const [name, content] of Object.entries(helpers)) {
|
|
1270
1287
|
const filePath = path.join(helpersDir, name);
|
|
1288
|
+
// If the source dir has this file, copyRecursive above already applied
|
|
1289
|
+
// the correct (force-aware) copy — never let this generated fallback
|
|
1290
|
+
// clobber it with a bare-bones stub. Only step in when source truly
|
|
1291
|
+
// doesn't have the file, regardless of `force`.
|
|
1292
|
+
const inSource = !!(sourceHelpersDir && fs.existsSync(path.join(sourceHelpersDir, name)));
|
|
1293
|
+
if (inSource)
|
|
1294
|
+
continue;
|
|
1271
1295
|
if (!fs.existsSync(filePath) || options.force) {
|
|
1272
1296
|
atomicWriteFile(filePath, content);
|
|
1273
1297
|
// Make shell scripts executable
|
|
@@ -47,12 +47,12 @@ export declare function resetInstallAttempts(): void;
|
|
|
47
47
|
*/
|
|
48
48
|
export declare const OPTIONAL_PACKAGES: {
|
|
49
49
|
readonly 'monofence-ai': {
|
|
50
|
-
readonly description:
|
|
51
|
-
readonly tools: readonly [
|
|
50
|
+
readonly description: 'AI manipulation defense (prompt injection, PII detection)';
|
|
51
|
+
readonly tools: readonly ['aidefence_scan', 'aidefence_analyze', 'aidefence_stats', 'aidefence_learn'];
|
|
52
52
|
};
|
|
53
53
|
readonly 'onnxruntime-node': {
|
|
54
|
-
readonly description:
|
|
55
|
-
readonly tools: readonly [
|
|
54
|
+
readonly description: 'ONNX runtime for neural network inference';
|
|
55
|
+
readonly tools: readonly ['neural_*'];
|
|
56
56
|
};
|
|
57
57
|
};
|
|
58
58
|
declare const _default: {
|
|
@@ -62,12 +62,12 @@ declare const _default: {
|
|
|
62
62
|
resetInstallAttempts: typeof resetInstallAttempts;
|
|
63
63
|
OPTIONAL_PACKAGES: {
|
|
64
64
|
readonly 'monofence-ai': {
|
|
65
|
-
readonly description:
|
|
66
|
-
readonly tools: readonly [
|
|
65
|
+
readonly description: 'AI manipulation defense (prompt injection, PII detection)';
|
|
66
|
+
readonly tools: readonly ['aidefence_scan', 'aidefence_analyze', 'aidefence_stats', 'aidefence_learn'];
|
|
67
67
|
};
|
|
68
68
|
readonly 'onnxruntime-node': {
|
|
69
|
-
readonly description:
|
|
70
|
-
readonly tools: readonly [
|
|
69
|
+
readonly description: 'ONNX runtime for neural network inference';
|
|
70
|
+
readonly tools: readonly ['neural_*'];
|
|
71
71
|
};
|
|
72
72
|
};
|
|
73
73
|
};
|