monomind 1.14.4 → 1.14.6
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/.claude/commands/mastermind/approve.md +1 -1
- package/.claude/commands/mastermind/createorg.md +1 -1
- package/.claude/commands/mastermind/master.md +1 -1
- package/.claude/commands/mastermind/runorg.md +31 -6
- package/.claude/skills/mastermind/_repeat.md +9 -6
- package/.claude/skills/mastermind/runorg.md +27 -15
- package/.claude/skills/mastermind/stoporg.md +1 -1
- package/README.md +0 -10
- package/package.json +2 -2
- package/packages/@monomind/cli/README.md +0 -10
- package/packages/@monomind/cli/dist/src/commands/org.js +107 -86
- package/packages/@monomind/cli/dist/src/mcp-tools/monograph-tools.js +91 -20
- package/packages/@monomind/cli/package.json +2 -2
|
@@ -73,7 +73,7 @@ curl -s -X POST "${CTRL_URL}/api/mastermind/event" \
|
|
|
73
73
|
-d "$(jq -cn \
|
|
74
74
|
--arg session "$session_id" \
|
|
75
75
|
--arg org "$org_name" \
|
|
76
|
-
--arg proj "$
|
|
76
|
+
--arg proj "$REPO_ROOT" \
|
|
77
77
|
'{type:"session:start",session:$session,domain:"ops",prompt:("Approve requests for org: "+$org),mode:"confirm",project:$proj,ts:(now*1000|floor)}')" || true
|
|
78
78
|
```
|
|
79
79
|
|
|
@@ -108,7 +108,7 @@ curl -s -X POST "${CTRL_URL}/api/mastermind/event" \
|
|
|
108
108
|
--arg session "$session_id" \
|
|
109
109
|
--arg prompt "$prompt" \
|
|
110
110
|
--arg mode "$mode" \
|
|
111
|
-
--arg proj "$
|
|
111
|
+
--arg proj "$REPO_ROOT" \
|
|
112
112
|
'{type:"session:start",session:$session,domain:"ops",prompt:$prompt,mode:$mode,project:$proj,ts:(now*1000|floor)}')" || true
|
|
113
113
|
```
|
|
114
114
|
|
|
@@ -316,7 +316,7 @@ jq -n --arg sid "$SESSION_ID" --arg proj "$project_name" --arg prompt "$resolved
|
|
|
316
316
|
CTRL_URL=$(jq -r '.url // "http://localhost:4242"' "$REPO_ROOT/.monomind/control.json" 2>/dev/null || echo "http://localhost:4242")
|
|
317
317
|
curl -s -o /dev/null -X POST "${CTRL_URL}/api/mastermind/event" \
|
|
318
318
|
-H "Content-Type: application/json" \
|
|
319
|
-
-d "$(jq -cn --arg sid "$SESSION_ID" --arg prompt "$resolved_prompt" --arg mode "$mode" --arg proj "$
|
|
319
|
+
-d "$(jq -cn --arg sid "$SESSION_ID" --arg prompt "$resolved_prompt" --arg mode "$mode" --arg proj "$REPO_ROOT" \
|
|
320
320
|
'{type:"session:start",session:$sid,prompt:$prompt,mode:$mode,project:$proj,ts:(now*1000|floor)}')" || true
|
|
321
321
|
```
|
|
322
322
|
|
|
@@ -44,7 +44,26 @@ No orgs yet? Run `/mastermind:createorg` to define one.
|
|
|
44
44
|
|
|
45
45
|
---
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
**STEP 0 — Extract loop-control flags (do this FIRST, before any other parsing)**
|
|
48
|
+
|
|
49
|
+
Scan `$ARGUMENTS` for these flags and store their values. Remove them from the argument string before Step 1:
|
|
50
|
+
|
|
51
|
+
| Flag | Variable | Default |
|
|
52
|
+
|---|---|---|
|
|
53
|
+
| `--rep <N>` | `current_rep = N` | absent |
|
|
54
|
+
| `--loop <id>` | `LOOP_ID = id` | absent |
|
|
55
|
+
| `--tillend` | `tillend_mode = true` | false |
|
|
56
|
+
| `--maxruns <N>` | `tillend_maxruns = N` | 50 |
|
|
57
|
+
| `--wait <N>` | `wait_seconds = N` | 60 |
|
|
58
|
+
| `--repeat <N>` | `repeat_count = N` | 0 |
|
|
59
|
+
|
|
60
|
+
⚠️ **CRITICAL — CONTINUATION RUNS DO NOT SKIP WORK.** When `--rep N` is present, this is a scheduled continuation triggered by ScheduleWakeup. The org's FULL work cycle MUST still execute every time: session variables → session:start event → Skill("mastermind:runorg") → session:complete event. NEVER short-circuit or skip the org work because `--rep` is present. The `--rep` / `--loop` flags are only consumed by `Skill("mastermind:_repeat")` at the end.
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
**STEP 1 — Parse org-specific flags**
|
|
65
|
+
|
|
66
|
+
From the remaining `$ARGUMENTS` (after loop flags removed in Step 0):
|
|
48
67
|
- `--org <name>` → org_name = <name>
|
|
49
68
|
- `--task <task>` → task_override = <task> (if omitted, task_override = null — the skill uses org's stored goal)
|
|
50
69
|
- Remaining text = additional context passed to the boss agent
|
|
@@ -68,11 +87,15 @@ If the file does not exist, stop and suggest running `/mastermind:createorg --na
|
|
|
68
87
|
|
|
69
88
|
Load brain context for the `ops` domain (follow _protocol.md Brain Load Procedure, namespace: `ops`).
|
|
70
89
|
|
|
71
|
-
|
|
90
|
+
Resolve session ID and project root:
|
|
72
91
|
```bash
|
|
73
92
|
REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
|
|
74
|
-
session_id="mm-$(date -u +%Y%m%dT%H%M%S)"
|
|
75
93
|
CTRL_URL=$(jq -r '.url // "http://localhost:4242"' "$REPO_ROOT/.monomind/control.json" 2>/dev/null || echo "http://localhost:4242")
|
|
94
|
+
# Reuse the loop's original sessionId for continuation runs (keeps all reps under one session)
|
|
95
|
+
if [ -n "${LOOP_ID:-}" ] && [ -f ".monomind/loops/${LOOP_ID}.json" ]; then
|
|
96
|
+
session_id=$(jq -r '.sessionId // empty' ".monomind/loops/${LOOP_ID}.json" 2>/dev/null)
|
|
97
|
+
fi
|
|
98
|
+
session_id="${session_id:-mm-$(date -u +%Y%m%dT%H%M%S)}"
|
|
76
99
|
```
|
|
77
100
|
|
|
78
101
|
Emit `session:start` to dashboard:
|
|
@@ -82,7 +105,7 @@ curl -s -X POST "${CTRL_URL}/api/mastermind/event" \
|
|
|
82
105
|
-d "$(jq -cn \
|
|
83
106
|
--arg session "$session_id" \
|
|
84
107
|
--arg org "$org_name" \
|
|
85
|
-
--arg proj "$
|
|
108
|
+
--arg proj "$REPO_ROOT" \
|
|
86
109
|
'{type:"session:start",session:$session,domain:"ops",prompt:("Running org: "+$org),mode:"auto",project:$proj,ts:(now*1000|floor)}')" || true
|
|
87
110
|
```
|
|
88
111
|
|
|
@@ -93,7 +116,8 @@ curl -s -X POST "${CTRL_URL}/api/mastermind/event" \
|
|
|
93
116
|
-d "$(jq -cn \
|
|
94
117
|
--arg session "$session_id" \
|
|
95
118
|
--arg org "$org_name" \
|
|
96
|
-
|
|
119
|
+
--arg proj "$REPO_ROOT" \
|
|
120
|
+
'{type:"domain:dispatch",session:$session,domain:"ops",cmd:("Starting org "+$org+" as persistent daemon"),project:$proj,ts:(now*1000|floor)}')" || true
|
|
97
121
|
```
|
|
98
122
|
|
|
99
123
|
Invoke `Skill("mastermind:runorg")` passing: brain_context, org_name: `$org_name`, session_id: `$session_id`, task: task_override, caller: "command".
|
|
@@ -105,7 +129,8 @@ curl -s -X POST "${CTRL_URL}/api/mastermind/event" \
|
|
|
105
129
|
-d "$(jq -cn \
|
|
106
130
|
--arg session "$session_id" \
|
|
107
131
|
--arg status "<status>" \
|
|
108
|
-
|
|
132
|
+
--arg proj "$REPO_ROOT" \
|
|
133
|
+
'{type:"session:complete",session:$session,domain:"ops",status:$status,domains:["ops"],project:$proj,ts:(now*1000|floor)}')" || true
|
|
109
134
|
```
|
|
110
135
|
|
|
111
136
|
Follow _protocol.md Brain Write Procedure for domain `ops`.
|
|
@@ -44,10 +44,11 @@ Set `TILLEND_EMPTY=true` **only if BOTH are zero for this round**.
|
|
|
44
44
|
```
|
|
45
45
|
- Emit dashboard event (non-fatal if control server is not running):
|
|
46
46
|
```bash
|
|
47
|
-
|
|
47
|
+
REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
|
|
48
|
+
CTRL_URL=$(jq -r '.url // "http://localhost:4242"' "$REPO_ROOT/.monomind/control.json" 2>/dev/null || echo "http://localhost:4242")
|
|
48
49
|
curl -s -X POST "${CTRL_URL}/api/mastermind/event" \
|
|
49
50
|
-H "Content-Type: application/json" \
|
|
50
|
-
-d "{\"type\":\"loop:complete\",\"loopId\":\"${LOOP_ID}\",\"command\":\"/<command>\",\"mode\":\"tillend\",\"ranReps\":<current_rep>,\"reason\":\"empty-round\",\"ts\":$(date +%s)000}" || true
|
|
51
|
+
-d "{\"type\":\"loop:complete\",\"loopId\":\"${LOOP_ID}\",\"command\":\"/<command>\",\"mode\":\"tillend\",\"ranReps\":<current_rep>,\"reason\":\"empty-round\",\"project\":\"${REPO_ROOT}\",\"ts\":$(date +%s)000}" || true
|
|
51
52
|
```
|
|
52
53
|
- Run: `rm -f ".monomind/loops/${LOOP_ID}.json"`
|
|
53
54
|
- **END**.
|
|
@@ -73,10 +74,11 @@ If `current_rep >= repeat_count`:
|
|
|
73
74
|
- Output: `[repeat] All <repeat_count> runs of /<command> complete.`
|
|
74
75
|
- Emit dashboard event:
|
|
75
76
|
```bash
|
|
76
|
-
|
|
77
|
+
REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
|
|
78
|
+
CTRL_URL=$(jq -r '.url // "http://localhost:4242"' "$REPO_ROOT/.monomind/control.json" 2>/dev/null || echo "http://localhost:4242")
|
|
77
79
|
curl -s -X POST "${CTRL_URL}/api/mastermind/event" \
|
|
78
80
|
-H "Content-Type: application/json" \
|
|
79
|
-
-d "{\"type\":\"loop:complete\",\"loopId\":\"${LOOP_ID}\",\"command\":\"/<command>\",\"ranReps\":<repeat_count>,\"ts\":$(date +%s)000}" || true
|
|
81
|
+
-d "{\"type\":\"loop:complete\",\"loopId\":\"${LOOP_ID}\",\"command\":\"/<command>\",\"ranReps\":<repeat_count>,\"project\":\"${REPO_ROOT}\",\"ts\":$(date +%s)000}" || true
|
|
80
82
|
```
|
|
81
83
|
- Run: `rm -f ".monomind/loops/${LOOP_ID}.json"`
|
|
82
84
|
- **END**.
|
|
@@ -120,10 +122,11 @@ EOF
|
|
|
120
122
|
|
|
121
123
|
Emit `loop:tick`:
|
|
122
124
|
```bash
|
|
123
|
-
|
|
125
|
+
REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
|
|
126
|
+
CTRL_URL=$(jq -r '.url // "http://localhost:4242"' "$REPO_ROOT/.monomind/control.json" 2>/dev/null || echo "http://localhost:4242")
|
|
124
127
|
curl -s -X POST "${CTRL_URL}/api/mastermind/event" \
|
|
125
128
|
-H "Content-Type: application/json" \
|
|
126
|
-
-d "{\"type\":\"loop:tick\",\"loopId\":\"${LOOP_ID}\",\"command\":\"/<command>\",\"completedRep\":<current_rep>,\"nextRep\":<next_rep>,\"nextAt\":${NEXT_AT},\"ts\":$(date +%s)000}" || true
|
|
129
|
+
-d "{\"type\":\"loop:tick\",\"loopId\":\"${LOOP_ID}\",\"command\":\"/<command>\",\"completedRep\":<current_rep>,\"nextRep\":<next_rep>,\"nextAt\":${NEXT_AT},\"project\":\"${REPO_ROOT}\",\"ts\":$(date +%s)000}" || true
|
|
127
130
|
```
|
|
128
131
|
|
|
129
132
|
**Call `ScheduleWakeup` now** — this is a mandatory tool call:
|
|
@@ -40,7 +40,7 @@ fi
|
|
|
40
40
|
```
|
|
41
41
|
Return `status: blocked` with message: "Org '<org_name>' not found. Run /mastermind:createorg to define it."
|
|
42
42
|
|
|
43
|
-
Validate the config has at minimum: `name`, `goal`, `roles` (non-empty array)
|
|
43
|
+
Validate the config has at minimum: `name`, `goal`, `roles` (non-empty array). The `communication` field is optional; fall back to `edges` if absent (both have the same schema: `from`, `to`, `type`).
|
|
44
44
|
|
|
45
45
|
---
|
|
46
46
|
|
|
@@ -351,7 +351,7 @@ YOUR TEAM (direct reports):
|
|
|
351
351
|
${directReports.map(r => `• ${r.title} (subagent_type="${r.agent_type}") — ${r.responsibilities.join(', ')}`).join('\n')}
|
|
352
352
|
|
|
353
353
|
FULL COMMUNICATION TOPOLOGY:
|
|
354
|
-
${orgConfig.communication.map(e => `${e.from} → ${e.to} (${e.type})`).join('\n')}
|
|
354
|
+
${(orgConfig.communication || orgConfig.edges || []).map(e => `${e.from} → ${e.to} (${e.type})`).join('\n')}
|
|
355
355
|
|
|
356
356
|
SHARED INFRASTRUCTURE:
|
|
357
357
|
- Task board (monotask): board_id=<board_id>
|
|
@@ -508,9 +508,20 @@ OPERATING LOOP:
|
|
|
508
508
|
-d "$(jq -cn --arg s "${sessionId}" --arg o "${orgName}" --arg rid "${runId}" \
|
|
509
509
|
--arg from "<role_id>" --arg msg "Completed: <one-sentence summary of output>" \
|
|
510
510
|
'{type:"org:comms",session:$s,org:$o,runId:$rid,from:$from,to:"boss",msg:$msg,ts:(now*1000|floor)}')" || true
|
|
511
|
+
# TOKEN TRACKING — estimate and persist token usage to state.json for the Budgets dashboard:
|
|
512
|
+
# Count approximate output tokens from your work (1 word ≈ 1.3 tokens):
|
|
513
|
+
_tok_out=$(echo -n "<paste a representative sample of your final output here>" | wc -w)
|
|
514
|
+
_tok_out=$(( _tok_out * 13 / 10 ))
|
|
515
|
+
_tok_in=8000 # fixed estimate for task context
|
|
516
|
+
stateFile="$REPO_ROOT/.monomind/orgs/${orgName}-state.json"
|
|
517
|
+
[ -f "$stateFile" ] && jq --arg id "<role_id>" --argjson in $_tok_in --argjson out $_tok_out \
|
|
518
|
+
'.agents[$id].tokens_in = ((.agents[$id].tokens_in // 0) + $in) | .agents[$id].tokens_out = ((.agents[$id].tokens_out // 0) + $out)' \
|
|
519
|
+
"$stateFile" > "${stateFile}.tmp" && mv "${stateFile}.tmp" "$stateFile" || true
|
|
511
520
|
|
|
512
521
|
Fill in the literal values for orgName="${orgName}", runId="${runId}", sessionId="${sessionId}" — embed them
|
|
513
522
|
directly in the prompt string so the specialist doesn't need to resolve them.
|
|
523
|
+
For token tracking: set _tok_out to the actual word count of your output text (use wc -w on your
|
|
524
|
+
output), and replace <role_id> with the literal role id string.
|
|
514
525
|
|
|
515
526
|
5. Collect completed results from memory (search "${memNs}:report:")
|
|
516
527
|
|
|
@@ -526,8 +537,7 @@ OPERATING LOOP:
|
|
|
526
537
|
jq -cn --arg runId "${runId}" --arg org "${orgName}" --argjson pend "${pending_count:-0}" \
|
|
527
538
|
'{type:"run:cycle:complete",runId:$runId,org:$org,pending:$pend,ts:(now*1000|floor)}' >> "${runFile}" || true
|
|
528
539
|
activityFile=".monomind/orgs/${orgName}-activity.jsonl"
|
|
529
|
-
|
|
530
|
-
'{type:"run:cycle:complete",org:$org,runId:$runId,ts:(now*1000|floor),pending:$pend}' >> "$activityFile" 2>/dev/null || true
|
|
540
|
+
echo "{\"type\":\"run:cycle:complete\",\"org\":\"${orgName}\",\"runId\":\"${runId}\",\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"pending\":${pending_count:-0}}" >> "$activityFile" 2>/dev/null || true
|
|
531
541
|
|
|
532
542
|
8. REQUIRED — emit org:checkpoint with a one-sentence progress summary (include runId):
|
|
533
543
|
curl -s -X POST "${CTRL_URL}/api/mastermind/event" -H "Content-Type: application/json" \
|
|
@@ -551,24 +561,26 @@ START NOW: resolve CTRL_URL, check for stop signal, assess the board, create ini
|
|
|
551
561
|
|
|
552
562
|
## Step 5 — Emit Boss Online Event
|
|
553
563
|
|
|
554
|
-
Emit `org:agent:online` for the boss role (team member events are emitted by the boss itself)
|
|
564
|
+
Emit `org:agent:online` for the boss role (team member events are emitted by the boss itself).
|
|
565
|
+
|
|
566
|
+
**IMPORTANT**: Shell variables do NOT persist across separate Bash tool calls. Read the `ORG_VARS:` line printed in Step 2+3 and substitute each literal value directly into the curl command before running it. Do NOT use `$variableName` syntax — replace each placeholder with its literal string from `ORG_VARS:`.
|
|
555
567
|
|
|
556
568
|
```bash
|
|
557
|
-
|
|
569
|
+
# Replace <CTRL_URL>, <sessionId>, <orgName>, <runId>, <bossRole_id>, <bossRole_title>, <bossRole_agent_type>, <REPO_ROOT>
|
|
570
|
+
# with the LITERAL values from the ORG_VARS: line printed in Step 2+3.
|
|
571
|
+
curl -s -X POST "<CTRL_URL>/api/mastermind/event" \
|
|
558
572
|
-H "Content-Type: application/json" \
|
|
559
573
|
-d "$(jq -cn \
|
|
560
|
-
--arg session "
|
|
561
|
-
--arg org "
|
|
562
|
-
--arg runId "
|
|
563
|
-
--arg role "
|
|
564
|
-
--arg title "
|
|
565
|
-
--arg agent_type "
|
|
566
|
-
--arg proj "
|
|
574
|
+
--arg session "<sessionId>" \
|
|
575
|
+
--arg org "<orgName>" \
|
|
576
|
+
--arg runId "<runId>" \
|
|
577
|
+
--arg role "<bossRole_id>" \
|
|
578
|
+
--arg title "<bossRole_title>" \
|
|
579
|
+
--arg agent_type "<bossRole_agent_type>" \
|
|
580
|
+
--arg proj "<REPO_ROOT>" \
|
|
567
581
|
'{type:"org:agent:online",session:$session,org:$org,runId:$runId,role:$role,title:$title,agent_type:$agent_type,project:$proj,ts:(now*1000|floor)}')" || true
|
|
568
582
|
```
|
|
569
583
|
|
|
570
|
-
(Use the scalar string variables `$bossRole_id`, `$bossRole_title`, `$bossRole_agent_type` derived by extracting fields from `bossRole` before constructing the curl call. `CTRL_URL`, `MONO_DIR`, and `runId` were resolved in Step 3 — reuse those variables.)
|
|
571
|
-
|
|
572
584
|
---
|
|
573
585
|
|
|
574
586
|
## Step 6 — Report to User
|
|
@@ -108,7 +108,7 @@ curl -s -X POST "${CTRL_URL}/api/mastermind/event" \
|
|
|
108
108
|
|
|
109
109
|
Current status: stopped
|
|
110
110
|
The loop will exit at its next scheduled wakeup without rescheduling.
|
|
111
|
-
Loop fully dead within:
|
|
111
|
+
Loop fully dead within: ≤$(jq -r '.loop.poll_interval_minutes // "?"' "$orgFile") minutes
|
|
112
112
|
|
|
113
113
|
To restart: /mastermind:runorg --org <org_name>
|
|
114
114
|
Status: /mastermind:orgstatus --org <org_name>
|
package/README.md
CHANGED
|
@@ -139,16 +139,6 @@ graph LR
|
|
|
139
139
|
E["7+ roles"] -->|hierarchical| F["Boss to leads to workers\nmiddle management"]
|
|
140
140
|
```
|
|
141
141
|
|
|
142
|
-
### Pre-built org types
|
|
143
|
-
|
|
144
|
-
| Org | Goal | Roles |
|
|
145
|
-
|---|---|---|
|
|
146
|
-
| `content-team` | 3 posts/week on AI tools | Director · Writer · Reviewer · SEO · Growth |
|
|
147
|
-
| `dev-squad` | Features from design spec | Lead · Architect · Developer · QA |
|
|
148
|
-
| `research-lab` | Weekly competitive intelligence | Director · Researcher · Analyst · Writer |
|
|
149
|
-
| `sales-engine` | ICP research + outreach sequences | Director · Outbound · Email · Researcher |
|
|
150
|
-
| `ops-squad` | 24/7 monitoring + incident response | SRE · Security · Perf · Incident Cmdr |
|
|
151
|
-
|
|
152
142
|
### Org management commands
|
|
153
143
|
|
|
154
144
|
```bash
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "monomind",
|
|
3
|
-
"version": "1.14.
|
|
3
|
+
"version": "1.14.6",
|
|
4
4
|
"description": "Monomind - Enterprise AI agent orchestration for Claude Code. Deploy 60+ specialized agents in coordinated swarms with self-learning, fault-tolerant consensus, vector memory, and MCP integration",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -147,4 +147,4 @@
|
|
|
147
147
|
"access": "public",
|
|
148
148
|
"tag": "latest"
|
|
149
149
|
}
|
|
150
|
-
}
|
|
150
|
+
}
|
|
@@ -139,16 +139,6 @@ graph LR
|
|
|
139
139
|
E["7+ roles"] -->|hierarchical| F["Boss to leads to workers\nmiddle management"]
|
|
140
140
|
```
|
|
141
141
|
|
|
142
|
-
### Pre-built org types
|
|
143
|
-
|
|
144
|
-
| Org | Goal | Roles |
|
|
145
|
-
|---|---|---|
|
|
146
|
-
| `content-team` | 3 posts/week on AI tools | Director · Writer · Reviewer · SEO · Growth |
|
|
147
|
-
| `dev-squad` | Features from design spec | Lead · Architect · Developer · QA |
|
|
148
|
-
| `research-lab` | Weekly competitive intelligence | Director · Researcher · Analyst · Writer |
|
|
149
|
-
| `sales-engine` | ICP research + outreach sequences | Director · Outbound · Email · Researcher |
|
|
150
|
-
| `ops-squad` | 24/7 monitoring + incident response | SRE · Security · Perf · Incident Cmdr |
|
|
151
|
-
|
|
152
142
|
### Org management commands
|
|
153
143
|
|
|
154
144
|
```bash
|
|
@@ -1,93 +1,114 @@
|
|
|
1
1
|
import { output } from '../output.js';
|
|
2
2
|
import { existsSync, unlinkSync, rmSync, readdirSync } from 'fs';
|
|
3
3
|
import { join, resolve } from 'path';
|
|
4
|
-
|
|
5
4
|
const orgCommand = {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
output.info(' delete <name> Delete an org and all its data');
|
|
25
|
-
return { success: true };
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
if (sub === 'list') {
|
|
29
|
-
const cwd = context?.projectPath || process.cwd();
|
|
30
|
-
const orgsDir = join(cwd, '.monomind', 'orgs');
|
|
31
|
-
if (!existsSync(orgsDir)) {
|
|
32
|
-
output.info('No orgs directory found. Create an org first with /mastermind:createorg');
|
|
33
|
-
return { success: true };
|
|
34
|
-
}
|
|
35
|
-
const ignore = ['-state','-goals','-threads','-activity','-approvals','-members','-secrets','-budgets','-routines','-issues','-projects','-workspaces','-worktrees','-environments','-plugins','-adapters','-join-requests','-bootstrap','-project-workspaces','-approval-comments','-skills'];
|
|
36
|
-
const configs = readdirSync(orgsDir)
|
|
37
|
-
.filter(f => f.endsWith('.json') && !ignore.some(s => f.includes(s)));
|
|
38
|
-
if (!configs.length) { output.info('No orgs found.'); return { success: true }; }
|
|
39
|
-
output.info(`Found ${configs.length} org(s):`);
|
|
40
|
-
for (const f of configs) output.info(` • ${f.replace('.json', '')}`);
|
|
41
|
-
return { success: true };
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (sub === 'delete') {
|
|
45
|
-
const orgName = args[1];
|
|
46
|
-
if (!orgName) {
|
|
47
|
-
output.error('Usage: monomind org delete <name>');
|
|
48
|
-
return { success: false, error: 'org name required' };
|
|
49
|
-
}
|
|
50
|
-
if (!/^[a-z0-9][a-z0-9_-]*$/i.test(orgName)) {
|
|
51
|
-
output.error(`Invalid org name: ${orgName}`);
|
|
52
|
-
return { success: false, error: 'invalid org name' };
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const confirmed = args.includes('--yes') || args.includes('-y');
|
|
56
|
-
if (!confirmed) {
|
|
57
|
-
output.warn(`This will permanently delete org "${orgName}" and all its data.`);
|
|
58
|
-
output.warn('Pass --yes to confirm.');
|
|
59
|
-
return { success: false, error: 'confirmation required' };
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const cwd = resolve(context?.projectPath || process.cwd());
|
|
63
|
-
const orgsDir = join(cwd, '.monomind', 'orgs');
|
|
64
|
-
const configFile = join(orgsDir, `${orgName}.json`);
|
|
65
|
-
if (!existsSync(configFile)) {
|
|
66
|
-
output.error(`Org not found: ${orgName}`);
|
|
67
|
-
return { success: false, error: 'org not found' };
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const suffixes = ['','-state','-goals','-routines','-approvals','-activity','-issues','-members','-projects','-workspaces','-worktrees','-environments','-plugins','-adapters','-budgets','-threads','-secrets','-join-requests','-bootstrap','-project-workspaces','-approval-comments','-skills'];
|
|
71
|
-
let removed = 0;
|
|
72
|
-
for (const suf of suffixes) {
|
|
73
|
-
for (const ext of ['.json', '.jsonl']) {
|
|
74
|
-
const f = join(orgsDir, `${orgName}${suf}${ext}`);
|
|
75
|
-
try { if (existsSync(f)) { unlinkSync(f); removed++; } } catch (_) {}
|
|
5
|
+
name: 'org',
|
|
6
|
+
description: 'Manage monomind organisations',
|
|
7
|
+
subcommands: ['delete', 'list'],
|
|
8
|
+
usage: 'monomind org <subcommand> [options]',
|
|
9
|
+
examples: [
|
|
10
|
+
'monomind org list',
|
|
11
|
+
'monomind org delete my-org',
|
|
12
|
+
'monomind org delete my-org --yes',
|
|
13
|
+
],
|
|
14
|
+
async execute(args, context) {
|
|
15
|
+
const sub = args[0];
|
|
16
|
+
if (!sub || sub === 'help') {
|
|
17
|
+
output.info('Usage: monomind org <subcommand>');
|
|
18
|
+
output.info('');
|
|
19
|
+
output.info('Subcommands:');
|
|
20
|
+
output.info(' list List all orgs in the current project');
|
|
21
|
+
output.info(' delete <name> Delete an org and all its data');
|
|
22
|
+
return { success: true };
|
|
76
23
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
24
|
+
if (sub === 'list') {
|
|
25
|
+
const cwd = context.projectPath || process.cwd();
|
|
26
|
+
const orgsDir = join(cwd, '.monomind', 'orgs');
|
|
27
|
+
if (!existsSync(orgsDir)) {
|
|
28
|
+
output.info('No orgs directory found. Create an org first with /mastermind:createorg');
|
|
29
|
+
return { success: true };
|
|
30
|
+
}
|
|
31
|
+
const configs = readdirSync(orgsDir)
|
|
32
|
+
.filter(f => f.endsWith('.json') && !f.includes('-state') && !f.includes('-goals')
|
|
33
|
+
&& !f.includes('-threads') && !f.includes('-activity') && !f.includes('-approvals')
|
|
34
|
+
&& !f.includes('-members') && !f.includes('-secrets') && !f.includes('-budgets'));
|
|
35
|
+
if (!configs.length) {
|
|
36
|
+
output.info('No orgs found.');
|
|
37
|
+
return { success: true };
|
|
38
|
+
}
|
|
39
|
+
output.info(`Found ${configs.length} org(s):`);
|
|
40
|
+
for (const f of configs)
|
|
41
|
+
output.info(` • ${f.replace('.json', '')}`);
|
|
42
|
+
return { success: true };
|
|
43
|
+
}
|
|
44
|
+
if (sub === 'delete') {
|
|
45
|
+
const orgName = args[1];
|
|
46
|
+
if (!orgName) {
|
|
47
|
+
output.error('Usage: monomind org delete <name>');
|
|
48
|
+
return { success: false, error: 'org name required' };
|
|
49
|
+
}
|
|
50
|
+
if (!/^[a-z0-9][a-z0-9_-]*$/i.test(orgName)) {
|
|
51
|
+
output.error(`Invalid org name: ${orgName}`);
|
|
52
|
+
return { success: false, error: 'invalid org name' };
|
|
53
|
+
}
|
|
54
|
+
const confirmed = args.includes('--yes') || args.includes('-y');
|
|
55
|
+
if (!confirmed) {
|
|
56
|
+
output.warn(`This will permanently delete org "${orgName}" and all its data.`);
|
|
57
|
+
output.warn('Pass --yes to confirm.');
|
|
58
|
+
return { success: false, error: 'confirmation required' };
|
|
59
|
+
}
|
|
60
|
+
const cwd = resolve(context.projectPath || process.cwd());
|
|
61
|
+
const orgsDir = join(cwd, '.monomind', 'orgs');
|
|
62
|
+
const configFile = join(orgsDir, `${orgName}.json`);
|
|
63
|
+
if (!existsSync(configFile)) {
|
|
64
|
+
output.error(`Org not found: ${orgName}`);
|
|
65
|
+
return { success: false, error: 'org not found' };
|
|
66
|
+
}
|
|
67
|
+
const suffixes = ['', '-state', '-goals', '-routines', '-approvals', '-activity',
|
|
68
|
+
'-issues', '-members', '-projects', '-workspaces', '-worktrees', '-environments',
|
|
69
|
+
'-plugins', '-adapters', '-budgets', '-threads', '-secrets', '-join-requests',
|
|
70
|
+
'-bootstrap', '-project-workspaces', '-approval-comments', '-skills'];
|
|
71
|
+
let removed = 0;
|
|
72
|
+
for (const suf of suffixes) {
|
|
73
|
+
for (const ext of ['.json', '.jsonl']) {
|
|
74
|
+
const f = join(orgsDir, `${orgName}${suf}${ext}`);
|
|
75
|
+
try {
|
|
76
|
+
if (existsSync(f)) {
|
|
77
|
+
unlinkSync(f);
|
|
78
|
+
removed++;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
catch (_) { }
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// Remove stop file
|
|
85
|
+
try {
|
|
86
|
+
unlinkSync(join(orgsDir, '.stops', `${orgName}.stop`));
|
|
87
|
+
}
|
|
88
|
+
catch (_) { }
|
|
89
|
+
// Remove org subdirectory
|
|
90
|
+
const orgSubDir = join(orgsDir, orgName);
|
|
91
|
+
try {
|
|
92
|
+
if (existsSync(orgSubDir))
|
|
93
|
+
rmSync(orgSubDir, { recursive: true, force: true });
|
|
94
|
+
}
|
|
95
|
+
catch (_) { }
|
|
96
|
+
// Remove loop prompt file
|
|
97
|
+
try {
|
|
98
|
+
unlinkSync(join(cwd, '.monomind', 'loops', `${orgName}.md`));
|
|
99
|
+
}
|
|
100
|
+
catch (_) { }
|
|
101
|
+
// Remove run prompt file
|
|
102
|
+
try {
|
|
103
|
+
unlinkSync(join(cwd, '.monomind', 'orgs', `${orgName}-run.md`));
|
|
104
|
+
}
|
|
105
|
+
catch (_) { }
|
|
106
|
+
output.success(`Org "${orgName}" deleted (${removed} file(s) removed).`);
|
|
107
|
+
return { success: true };
|
|
108
|
+
}
|
|
109
|
+
output.error(`Unknown subcommand: ${sub}. Run "monomind org help" for usage.`);
|
|
110
|
+
return { success: false, error: `unknown subcommand: ${sub}` };
|
|
111
|
+
},
|
|
91
112
|
};
|
|
92
|
-
|
|
93
113
|
export default orgCommand;
|
|
114
|
+
//# sourceMappingURL=org.js.map
|
|
@@ -544,10 +544,58 @@ const monographReportTool = {
|
|
|
544
544
|
}
|
|
545
545
|
},
|
|
546
546
|
};
|
|
547
|
+
// ── Shared staleness helper ───────────────────────────────────────────────────
|
|
548
|
+
/** Guard against concurrent background buildAsync calls on the same DB. */
|
|
549
|
+
let _buildInProgress = false;
|
|
550
|
+
/**
|
|
551
|
+
* Compute how many commits the index is behind HEAD.
|
|
552
|
+
* Returns { commitsBehind, lastCommit } — or null if the index has never been
|
|
553
|
+
* built or git is unavailable.
|
|
554
|
+
*/
|
|
555
|
+
async function computeCommitsBehind(repoPath) {
|
|
556
|
+
const { openDb, closeDb } = await import('@monoes/monograph');
|
|
557
|
+
const { execSync } = await import('child_process');
|
|
558
|
+
const db = openDb(join(repoPath, '.monomind', 'monograph.db'));
|
|
559
|
+
try {
|
|
560
|
+
const meta = db.prepare("SELECT value FROM index_meta WHERE key = 'last_commit_hash'").get() ?? db.prepare("SELECT value FROM index_meta WHERE key = 'lastCommit'").get();
|
|
561
|
+
const lastCommit = meta?.value ?? null;
|
|
562
|
+
if (!lastCommit || !/^[0-9a-f]{7,40}$/i.test(lastCommit))
|
|
563
|
+
return null;
|
|
564
|
+
try {
|
|
565
|
+
const out = execSync(`git rev-list --count ${lastCommit}..HEAD`, {
|
|
566
|
+
cwd: repoPath, encoding: 'utf-8',
|
|
567
|
+
}).trim();
|
|
568
|
+
return { commitsBehind: parseInt(out, 10), lastCommit };
|
|
569
|
+
}
|
|
570
|
+
catch {
|
|
571
|
+
return null;
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
finally {
|
|
575
|
+
closeDb(db);
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
/**
|
|
579
|
+
* Fire-and-forget background rebuild. Uses a module-level guard so concurrent
|
|
580
|
+
* MCP tool calls (e.g. repeated monograph_suggest_auto) don't pile up builds.
|
|
581
|
+
* threshold: minimum commitsBehind to trigger (default 1, Task 2 uses 10).
|
|
582
|
+
*/
|
|
583
|
+
function triggerBackgroundBuildIfNeeded(repoPath, commitsBehind, threshold = 1) {
|
|
584
|
+
if (commitsBehind < threshold)
|
|
585
|
+
return false;
|
|
586
|
+
if (_buildInProgress)
|
|
587
|
+
return false;
|
|
588
|
+
_buildInProgress = true;
|
|
589
|
+
void import('@monoes/monograph')
|
|
590
|
+
.then(({ buildAsync }) => buildAsync(repoPath, { codeOnly: true }))
|
|
591
|
+
.catch(() => { })
|
|
592
|
+
.finally(() => { _buildInProgress = false; });
|
|
593
|
+
return true;
|
|
594
|
+
}
|
|
547
595
|
// ── monograph_staleness ───────────────────────────────────────────────────────
|
|
548
596
|
const monographStalenessTool = {
|
|
549
597
|
name: 'monograph_staleness',
|
|
550
|
-
description: 'Git staleness detection: compares the commit hash at last index build against current HEAD.
|
|
598
|
+
description: 'Git staleness detection: compares the commit hash at last index build against current HEAD. When the index is more than 10 commits behind HEAD it automatically triggers a background rebuild. Returns { commitsBehind, status, triggered }.',
|
|
551
599
|
inputSchema: {
|
|
552
600
|
type: 'object',
|
|
553
601
|
properties: {
|
|
@@ -555,26 +603,16 @@ const monographStalenessTool = {
|
|
|
555
603
|
},
|
|
556
604
|
},
|
|
557
605
|
handler: async (input) => {
|
|
558
|
-
const { getMonographStaleness } = await import('@monoes/monograph');
|
|
559
606
|
const repoPath = input.path ?? getProjectCwd();
|
|
560
|
-
const
|
|
561
|
-
if (!
|
|
562
|
-
return text(
|
|
563
|
-
}
|
|
564
|
-
const
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
const
|
|
568
|
-
|
|
569
|
-
lines.push(`Stale since: ${r.staleSince}`);
|
|
570
|
-
if (r.changedSince.length > 0) {
|
|
571
|
-
const shown = r.changedSince.slice(0, 10);
|
|
572
|
-
const more = r.changedSince.length - shown.length;
|
|
573
|
-
lines.push(`Changed files (${r.changedSince.length}):${shown.map(f => `\n ${f}`).join('')}${more > 0 ? `\n … ${more} more` : ''}`);
|
|
574
|
-
}
|
|
575
|
-
if (r.isStale)
|
|
576
|
-
lines.push('Action: run monograph_build to re-index');
|
|
577
|
-
return text(lines.join('\n'));
|
|
607
|
+
const result = await computeCommitsBehind(repoPath);
|
|
608
|
+
if (!result) {
|
|
609
|
+
return text(JSON.stringify({ commitsBehind: 0, status: 'unknown', triggered: false }));
|
|
610
|
+
}
|
|
611
|
+
const { commitsBehind } = result;
|
|
612
|
+
const AUTO_BUILD_THRESHOLD = 10;
|
|
613
|
+
const triggered = triggerBackgroundBuildIfNeeded(repoPath, commitsBehind, AUTO_BUILD_THRESHOLD + 1);
|
|
614
|
+
const status = triggered ? 'building' : commitsBehind === 0 ? 'fresh' : 'stale';
|
|
615
|
+
return text(JSON.stringify({ commitsBehind, status, triggered }));
|
|
578
616
|
},
|
|
579
617
|
};
|
|
580
618
|
// ── monograph_snapshot ────────────────────────────────────────────────────────
|
|
@@ -1735,6 +1773,38 @@ const monographNeighborsTool = {
|
|
|
1735
1773
|
}
|
|
1736
1774
|
},
|
|
1737
1775
|
};
|
|
1776
|
+
// ── monograph_suggest_auto ────────────────────────────────────────────────────
|
|
1777
|
+
const monographSuggestAutoTool = {
|
|
1778
|
+
name: 'monograph_suggest_auto',
|
|
1779
|
+
description: 'Like monograph_suggest but health-aware: checks staleness first and triggers a background rebuild when the index is behind HEAD before returning suggestions. Result includes a _staleness annotation.',
|
|
1780
|
+
inputSchema: {
|
|
1781
|
+
type: 'object',
|
|
1782
|
+
properties: {
|
|
1783
|
+
task: { type: 'string', description: 'Optional task description for task-relevance scoring' },
|
|
1784
|
+
limit: { type: 'number', description: 'Max questions (default 10)' },
|
|
1785
|
+
},
|
|
1786
|
+
},
|
|
1787
|
+
handler: async (input) => {
|
|
1788
|
+
const repoPath = getProjectCwd();
|
|
1789
|
+
// Check staleness and trigger rebuild if needed (threshold: any staleness).
|
|
1790
|
+
const stalenessResult = await computeCommitsBehind(repoPath);
|
|
1791
|
+
const commitsBehind = stalenessResult?.commitsBehind ?? 0;
|
|
1792
|
+
const triggered = triggerBackgroundBuildIfNeeded(repoPath, commitsBehind, 1);
|
|
1793
|
+
const stalenessStatus = triggered ? 'building' : commitsBehind === 0 ? 'fresh' : 'stale';
|
|
1794
|
+
// Delegate to the base suggest tool — no logic duplication.
|
|
1795
|
+
const baseResult = await monographSuggestTool.handler(input);
|
|
1796
|
+
// Append staleness annotation to the text content.
|
|
1797
|
+
const stalenessAnnotation = `\n_staleness: ${JSON.stringify({ commitsBehind, status: stalenessStatus, triggered })}`;
|
|
1798
|
+
if (baseResult && Array.isArray(baseResult.content)) {
|
|
1799
|
+
const content = baseResult.content;
|
|
1800
|
+
if (content.length > 0 && content[0].type === 'text') {
|
|
1801
|
+
content[0].text += stalenessAnnotation;
|
|
1802
|
+
}
|
|
1803
|
+
return baseResult;
|
|
1804
|
+
}
|
|
1805
|
+
return baseResult;
|
|
1806
|
+
},
|
|
1807
|
+
};
|
|
1738
1808
|
// ── Export all tools ──────────────────────────────────────────────────────────
|
|
1739
1809
|
export const monographTools = [
|
|
1740
1810
|
monographBuildTool,
|
|
@@ -1747,6 +1817,7 @@ export const monographTools = [
|
|
|
1747
1817
|
monographCommunityTool,
|
|
1748
1818
|
monographSurprisesTool,
|
|
1749
1819
|
monographSuggestTool,
|
|
1820
|
+
monographSuggestAutoTool,
|
|
1750
1821
|
monographVisualizeTool,
|
|
1751
1822
|
monographWatchTool,
|
|
1752
1823
|
monographWatchStopTool,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@monoes/monomindcli",
|
|
3
|
-
"version": "1.14.
|
|
3
|
+
"version": "1.14.6",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Monomind CLI - Enterprise AI agent orchestration with 60+ specialized agents, swarm coordination, MCP server, self-learning hooks, and vector memory for Claude Code",
|
|
6
6
|
"main": "dist/src/index.js",
|
|
@@ -104,4 +104,4 @@
|
|
|
104
104
|
"access": "public",
|
|
105
105
|
"tag": "latest"
|
|
106
106
|
}
|
|
107
|
-
}
|
|
107
|
+
}
|