@monoes/monomindcli 1.11.8 → 1.11.10
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/agents/github/issue-tracker.md +5 -5
- package/.claude/agents/github/pr-manager.md +5 -5
- package/.claude/agents/github/release-manager.md +3 -3
- package/.claude/agents/github/repo-architect.md +3 -3
- package/.claude/agents/github/swarm-issue.md +1 -1
- package/.claude/agents/github/sync-coordinator.md +1 -1
- package/.claude/agents/github/workflow-automation.md +1 -1
- package/.claude/commands/github/repo-architect.md +1 -1
- package/.claude/commands/github/sync-coordinator.md +1 -1
- package/.claude/commands/mastermind/createorg.md +4 -1
- package/.claude/commands/mastermind/help.md +2 -2
- package/.claude/commands/mastermind/orgs.md +21 -0
- package/.claude/commands/mastermind/orgstatus.md +59 -0
- package/.claude/commands/mastermind/runorg.md +4 -2
- package/.claude/commands/mastermind/stoporg.md +78 -0
- package/.claude/commands/mastermind/swarm.md +1 -1
- package/.claude/helpers/handlers/gates-handler.cjs +135 -0
- package/.claude/helpers/handlers/task-handler.cjs +7 -3
- package/.claude/helpers/hook-handler.cjs +11 -2
- package/.claude/helpers/intelligence.cjs +87 -0
- package/.claude/helpers/learning-service.mjs +60 -0
- package/.claude/helpers/memory.cjs +69 -0
- package/.claude/helpers/router.cjs +68 -0
- package/.claude/helpers/session.cjs +63 -0
- package/.claude/helpers/utils/monograph.cjs +4 -2
- package/.claude/helpers/utils/telemetry.cjs +3 -2
- package/.claude/skills/agentic-jujutsu/SKILL.md +1 -1
- package/.claude/skills/hive-mind-advanced/SKILL.md +4 -4
- package/.claude/skills/mastermind/_agent-select.md +2 -2
- package/.claude/skills/mastermind/access.md +11 -11
- package/.claude/skills/mastermind/adapter-manager.md +13 -13
- package/.claude/skills/mastermind/adapters.md +7 -7
- package/.claude/skills/mastermind/agent-detail.md +1 -1
- package/.claude/skills/mastermind/agents.md +5 -5
- package/.claude/skills/mastermind/approval-detail.md +6 -6
- package/.claude/skills/mastermind/approve.md +9 -10
- package/.claude/skills/mastermind/backup.md +2 -2
- package/.claude/skills/mastermind/bootstrap.md +2 -2
- package/.claude/skills/mastermind/companies.md +7 -7
- package/.claude/skills/mastermind/createorg.md +213 -8
- package/.claude/skills/mastermind/diagnose.md +4 -4
- package/.claude/skills/mastermind/env.md +1 -1
- package/.claude/skills/mastermind/environments.md +8 -8
- package/.claude/skills/mastermind/export.md +12 -3
- package/.claude/skills/mastermind/goal-detail.md +9 -9
- package/.claude/skills/mastermind/goals.md +4 -4
- package/.claude/skills/mastermind/heartbeat.md +1 -1
- package/.claude/skills/mastermind/idea.md +4 -4
- package/.claude/skills/mastermind/import.md +8 -8
- package/.claude/skills/mastermind/inbox.md +4 -4
- package/.claude/skills/mastermind/instance-settings.md +9 -9
- package/.claude/skills/mastermind/instance.md +9 -7
- package/.claude/skills/mastermind/invite-landing.md +5 -5
- package/.claude/skills/mastermind/invites.md +12 -12
- package/.claude/skills/mastermind/issue-detail.md +8 -8
- package/.claude/skills/mastermind/monitor.md +11 -11
- package/.claude/skills/mastermind/my-issues.md +6 -6
- package/.claude/skills/mastermind/new-agent.md +4 -4
- package/.claude/skills/mastermind/org-chart.md +8 -6
- package/.claude/skills/mastermind/org-settings.md +58 -21
- package/.claude/skills/mastermind/orgs.md +98 -0
- package/.claude/skills/mastermind/orgstatus.md +194 -0
- package/.claude/skills/mastermind/plan-to-tasks.md +1 -1
- package/.claude/skills/mastermind/plugin-manager.md +12 -12
- package/.claude/skills/mastermind/plugin-settings.md +5 -5
- package/.claude/skills/mastermind/plugins.md +5 -5
- package/.claude/skills/mastermind/profile.md +2 -2
- package/.claude/skills/mastermind/project-detail.md +12 -12
- package/.claude/skills/mastermind/project-workspace.md +4 -4
- package/.claude/skills/mastermind/projects.md +4 -4
- package/.claude/skills/mastermind/review.md +50 -0
- package/.claude/skills/mastermind/routine-detail.md +3 -3
- package/.claude/skills/mastermind/routines.md +7 -6
- package/.claude/skills/mastermind/runorg.md +178 -8
- package/.claude/skills/mastermind/search.md +6 -6
- package/.claude/skills/mastermind/secrets.md +6 -6
- package/.claude/skills/mastermind/skills.md +4 -4
- package/.claude/skills/mastermind/stoporg.md +138 -0
- package/.claude/skills/mastermind/workspace-detail.md +5 -5
- package/.claude/skills/mastermind/workspaces.md +9 -9
- package/.claude/skills/performance-analysis/SKILL.md +3 -3
- package/.claude/skills/sparc-methodology/SKILL.md +2 -2
- package/.claude/skills/swarm-advanced/SKILL.md +4 -4
- package/README.md +129 -376
- package/dist/src/agents/registry-builder.d.ts +27 -1
- package/dist/src/agents/registry-builder.d.ts.map +1 -1
- package/dist/src/agents/registry-builder.js +2 -2
- package/dist/src/agents/registry-builder.js.map +1 -1
- package/dist/src/commands/agent.d.ts.map +1 -1
- package/dist/src/commands/agent.js +4 -9
- package/dist/src/commands/agent.js.map +1 -1
- package/dist/src/commands/analyze.d.ts +1 -1
- package/dist/src/commands/analyze.js +1 -1
- package/dist/src/commands/claims.d.ts +1 -1
- package/dist/src/commands/claims.js +2 -2
- package/dist/src/commands/claims.js.map +1 -1
- package/dist/src/commands/cleanup.d.ts +1 -1
- package/dist/src/commands/cleanup.js +1 -1
- package/dist/src/commands/completions.d.ts +1 -1
- package/dist/src/commands/completions.js +1 -1
- package/dist/src/commands/deployment.d.ts +1 -1
- package/dist/src/commands/deployment.js +2 -2
- package/dist/src/commands/deployment.js.map +1 -1
- package/dist/src/commands/doctor.d.ts +1 -1
- package/dist/src/commands/doctor.d.ts.map +1 -1
- package/dist/src/commands/doctor.js +69 -4
- package/dist/src/commands/doctor.js.map +1 -1
- package/dist/src/commands/guidance.d.ts.map +1 -1
- package/dist/src/commands/guidance.js +129 -0
- package/dist/src/commands/guidance.js.map +1 -1
- package/dist/src/commands/index.d.ts.map +1 -1
- package/dist/src/commands/index.js +4 -0
- package/dist/src/commands/index.js.map +1 -1
- package/dist/src/commands/init.d.ts.map +1 -1
- package/dist/src/commands/init.js +18 -0
- package/dist/src/commands/init.js.map +1 -1
- package/dist/src/commands/monovector/import.d.ts +1 -1
- package/dist/src/commands/monovector/import.js +1 -1
- package/dist/src/commands/monovector/index.d.ts +1 -1
- package/dist/src/commands/monovector/index.js +1 -1
- package/dist/src/commands/monovector/setup.d.ts +1 -1
- package/dist/src/commands/monovector/setup.js +2 -2
- package/dist/src/commands/neural.d.ts +1 -1
- package/dist/src/commands/neural.js +2 -2
- package/dist/src/commands/neural.js.map +1 -1
- package/dist/src/commands/performance.d.ts +1 -1
- package/dist/src/commands/performance.js +2 -2
- package/dist/src/commands/performance.js.map +1 -1
- package/dist/src/commands/platforms.d.ts +1 -1
- package/dist/src/commands/platforms.js +1 -1
- package/dist/src/commands/plugins.d.ts +1 -1
- package/dist/src/commands/plugins.d.ts.map +1 -1
- package/dist/src/commands/plugins.js +2 -4
- package/dist/src/commands/plugins.js.map +1 -1
- package/dist/src/commands/providers.d.ts +1 -1
- package/dist/src/commands/providers.js +2 -2
- package/dist/src/commands/providers.js.map +1 -1
- package/dist/src/commands/route.d.ts +1 -1
- package/dist/src/commands/route.d.ts.map +1 -1
- package/dist/src/commands/route.js +5 -11
- package/dist/src/commands/route.js.map +1 -1
- package/dist/src/commands/security.d.ts +1 -1
- package/dist/src/commands/security.d.ts.map +1 -1
- package/dist/src/commands/security.js +140 -91
- package/dist/src/commands/security.js.map +1 -1
- package/dist/src/dlq/dlq-replayer.d.ts +7 -1
- package/dist/src/dlq/dlq-replayer.d.ts.map +1 -1
- package/dist/src/dlq/dlq-replayer.js.map +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +10 -26
- package/dist/src/index.js.map +1 -1
- package/dist/src/init/claudemd-generator.js +2 -2
- package/dist/src/init/claudemd-generator.js.map +1 -1
- package/dist/src/init/executor.js +3 -3
- package/dist/src/init/settings-generator.js +2 -2
- package/dist/src/init/settings-generator.js.map +1 -1
- package/dist/src/mcp-client.d.ts +5 -0
- package/dist/src/mcp-client.d.ts.map +1 -1
- package/dist/src/mcp-client.js +7 -0
- package/dist/src/mcp-client.js.map +1 -1
- package/dist/src/mcp-server.d.ts.map +1 -1
- package/dist/src/mcp-server.js +17 -1
- package/dist/src/mcp-server.js.map +1 -1
- package/dist/src/mcp-tools/a2a-tools.js +6 -6
- package/dist/src/mcp-tools/a2a-tools.js.map +1 -1
- package/dist/src/mcp-tools/auto-install.d.ts +2 -2
- package/dist/src/mcp-tools/auto-install.js +1 -1
- package/dist/src/mcp-tools/auto-install.js.map +1 -1
- package/dist/src/mcp-tools/hive-mind-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/hive-mind-tools.js +1 -52
- package/dist/src/mcp-tools/hive-mind-tools.js.map +1 -1
- package/dist/src/mcp-tools/index.d.ts +4 -0
- package/dist/src/mcp-tools/index.d.ts.map +1 -1
- package/dist/src/mcp-tools/index.js +4 -0
- package/dist/src/mcp-tools/index.js.map +1 -1
- package/dist/src/mcp-tools/monograph-compat.d.ts.map +1 -1
- package/dist/src/mcp-tools/monograph-compat.js +1 -2
- package/dist/src/mcp-tools/monograph-compat.js.map +1 -1
- package/dist/src/mcp-tools/monograph-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/monograph-tools.js +107 -5
- package/dist/src/mcp-tools/monograph-tools.js.map +1 -1
- package/dist/src/mcp-tools/security-tools.d.ts +6 -6
- package/dist/src/mcp-tools/security-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/security-tools.js +48 -61
- package/dist/src/mcp-tools/security-tools.js.map +1 -1
- package/dist/src/memory/memory-bridge.d.ts +0 -1
- package/dist/src/memory/memory-bridge.d.ts.map +1 -1
- package/dist/src/memory/memory-bridge.js +232 -57
- package/dist/src/memory/memory-bridge.js.map +1 -1
- package/dist/src/memory/memory-initializer.d.ts.map +1 -1
- package/dist/src/memory/memory-initializer.js +3 -32
- package/dist/src/memory/memory-initializer.js.map +1 -1
- package/dist/src/plugins/store/discovery.d.ts.map +1 -1
- package/dist/src/plugins/store/discovery.js +0 -69
- package/dist/src/plugins/store/discovery.js.map +1 -1
- package/dist/src/routing/embed-worker.d.ts +2 -0
- package/dist/src/routing/embed-worker.d.ts.map +1 -0
- package/dist/src/routing/embed-worker.js +55 -0
- package/dist/src/routing/embed-worker.js.map +1 -0
- package/dist/src/routing/embedder.d.ts +31 -0
- package/dist/src/routing/embedder.d.ts.map +1 -0
- package/dist/src/routing/embedder.js +0 -0
- package/dist/src/routing/embedder.js.map +1 -0
- package/dist/src/routing/llm-caller.d.ts +1 -1
- package/dist/src/routing/llm-caller.d.ts.map +1 -1
- package/dist/src/routing/llm-caller.js +18 -3
- package/dist/src/routing/llm-caller.js.map +1 -1
- package/dist/src/routing/route-layer-factory.d.ts +9 -0
- package/dist/src/routing/route-layer-factory.d.ts.map +1 -0
- package/dist/src/routing/route-layer-factory.js +151 -0
- package/dist/src/routing/route-layer-factory.js.map +1 -0
- package/dist/src/services/worker-daemon.d.ts.map +1 -1
- package/dist/src/services/worker-daemon.js +0 -1
- package/dist/src/services/worker-daemon.js.map +1 -1
- package/dist/src/suggest.d.ts +1 -1
- package/dist/src/suggest.js +1 -1
- package/dist/src/ui/server.mjs +5 -2
- package/dist/src/update/checker.d.ts.map +1 -1
- package/dist/src/update/checker.js +18 -5
- package/dist/src/update/checker.js.map +1 -1
- package/dist/src/update/validator.d.ts.map +1 -1
- package/dist/src/update/validator.js +15 -6
- package/dist/src/update/validator.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +9 -10
- package/scripts/publish-registry.ts +0 -2
- package/scripts/understand-analyze.mjs +1 -1
|
@@ -53,7 +53,7 @@ Show all routines with their schedule and status:
|
|
|
53
53
|
|
|
54
54
|
```bash
|
|
55
55
|
jq -r '
|
|
56
|
-
.routines[] |
|
|
56
|
+
(.routines // [])[] |
|
|
57
57
|
"[\(.id)] \(.name) agent=\(.agent_id) schedule=\"\(.schedule)\" status=\(.status // "active")\n" +
|
|
58
58
|
" task: \(.task_title)\n concurrency: \(.concurrency) catchup: \(.catchup)\n last_run: \(.last_run // "never") next_run: \(.next_run // "unknown")"
|
|
59
59
|
' "$routinesFile" 2>/dev/null || echo "No routines defined."
|
|
@@ -114,7 +114,7 @@ After creating, use `ScheduleWakeup` to schedule the first trigger at the approp
|
|
|
114
114
|
Manually trigger a routine immediately (same as a scheduled run):
|
|
115
115
|
|
|
116
116
|
```bash
|
|
117
|
-
routine=$(jq --arg id "$routine_id" '.routines[] | select(.id == $id)' "$routinesFile")
|
|
117
|
+
routine=$(jq --arg id "$routine_id" '(.routines // [])[] | select(.id == $id)' "$routinesFile")
|
|
118
118
|
rt_agent=$(echo "$routine" | jq -r '.agent_id')
|
|
119
119
|
rt_task=$(echo "$routine" | jq -r '.task_title')
|
|
120
120
|
rt_context=$(echo "$routine" | jq -r '.context // ""')
|
|
@@ -122,7 +122,8 @@ rt_concurrency=$(echo "$routine" | jq -r '.concurrency')
|
|
|
122
122
|
|
|
123
123
|
# Check concurrency policy
|
|
124
124
|
stateFile=".monomind/orgs/${org_name}-state.json"
|
|
125
|
-
|
|
125
|
+
[ ! -f "$stateFile" ] && echo '{"agents":{}}' > "$stateFile"
|
|
126
|
+
agent_status=$(jq -r --arg a "$rt_agent" '.agents[$a].status // "idle"' "$stateFile")
|
|
126
127
|
|
|
127
128
|
case "$rt_concurrency" in
|
|
128
129
|
skip_if_active)
|
|
@@ -141,7 +142,7 @@ Update routine's `last_run` and schedule next wakeup:
|
|
|
141
142
|
```bash
|
|
142
143
|
tmp="${routinesFile}.tmp"
|
|
143
144
|
jq --arg id "$routine_id" --arg ts "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
|
|
144
|
-
'.routines = [.routines[] | if .id == $id then .last_run = $ts else . end]' \
|
|
145
|
+
'.routines = [(.routines // [])[] | if .id == $id then .last_run = $ts else . end]' \
|
|
145
146
|
"$routinesFile" > "$tmp" && mv "$tmp" "$routinesFile"
|
|
146
147
|
```
|
|
147
148
|
|
|
@@ -150,7 +151,7 @@ jq --arg id "$routine_id" --arg ts "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
|
|
|
150
151
|
```bash
|
|
151
152
|
tmp="${routinesFile}.tmp"
|
|
152
153
|
jq --arg id "$routine_id" --arg status "$action" \
|
|
153
|
-
'.routines = [.routines[] | if .id == $id then .status = $status else . end]' \
|
|
154
|
+
'.routines = [(.routines // [])[] | if .id == $id then .status = $status else . end]' \
|
|
154
155
|
"$routinesFile" > "$tmp" && mv "$tmp" "$routinesFile"
|
|
155
156
|
echo "Routine $routine_id set to: $action"
|
|
156
157
|
```
|
|
@@ -159,7 +160,7 @@ echo "Routine $routine_id set to: $action"
|
|
|
159
160
|
|
|
160
161
|
```bash
|
|
161
162
|
tmp="${routinesFile}.tmp"
|
|
162
|
-
jq --arg id "$routine_id" '.routines = [.routines[] | select(.id != $id)]' \
|
|
163
|
+
jq --arg id "$routine_id" '.routines = [(.routines // [])[] | select(.id != $id)]' \
|
|
163
164
|
"$routinesFile" > "$tmp" && mv "$tmp" "$routinesFile"
|
|
164
165
|
echo "Routine $routine_id removed."
|
|
165
166
|
```
|
|
@@ -31,7 +31,7 @@ If `caller` is not "command", load brain context following _protocol.md Brain Lo
|
|
|
31
31
|
|
|
32
32
|
Read `.monomind/orgs/<org_name>.json`. If the file does not exist:
|
|
33
33
|
```bash
|
|
34
|
-
orgs=$(ls .monomind/orgs/*.json 2>/dev/null | xargs -I{} basename {} .json)
|
|
34
|
+
orgs=$(ls .monomind/orgs/*.json 2>/dev/null | grep -vE -- '-approvals|-state|-activity|-goals|-routines|-projects|-members|-issues|-workspaces|-worktrees|-environments|-plugins|-adapters|-bootstrap|-threads|-budgets|-project-workspaces|-approval-comments' | xargs -I{} basename {} .json)
|
|
35
35
|
if [ -z "$orgs" ]; then
|
|
36
36
|
echo "No saved orgs found. Run /mastermind:createorg to define one."
|
|
37
37
|
else
|
|
@@ -44,6 +44,170 @@ Validate the config has at minimum: `name`, `goal`, `roles` (non-empty array), `
|
|
|
44
44
|
|
|
45
45
|
---
|
|
46
46
|
|
|
47
|
+
## Step 1.5 — Detect Scheduled Org
|
|
48
|
+
|
|
49
|
+
After loading the org config, check whether this is a scheduled (loop) org:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
orgFile=".monomind/orgs/${org_name}.json"
|
|
53
|
+
has_schedule=$(jq -r 'if .loop.poll_interval_minutes then "yes" else "no" end' "$orgFile")
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
If `has_schedule == "yes"`, this is a **scheduled org**. Follow the **Scheduled Org Path** below (Steps 1.6 onward) instead of the standard Steps 2–8.
|
|
57
|
+
|
|
58
|
+
If `has_schedule == "no"`, skip to **Step 2** (standard persistent daemon path).
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Step 1.6 — Scheduled Org Path
|
|
63
|
+
|
|
64
|
+
This section handles orgs created with `--schedule`. The loop is owned by the org — it starts with `runorg`, runs each iteration via the loop prompt file, and stops with `stoporg`.
|
|
65
|
+
|
|
66
|
+
### 1.6.1 — Guard against double-activation, then set status to "active"
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
orgFile=".monomind/orgs/${org_name}.json"
|
|
70
|
+
current_loop_status=$(jq -r '.status // "stopped"' "$orgFile")
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
If `current_loop_status == "active"`:
|
|
74
|
+
- Print:
|
|
75
|
+
```
|
|
76
|
+
WARNING: Org '<org_name>' is already active. Starting a second instance would create parallel loop chains.
|
|
77
|
+
To restart cleanly: run /mastermind:stoporg --org <org_name> first, then /mastermind:runorg --org <org_name>.
|
|
78
|
+
To force restart anyway, set status to "stopped" in .monomind/orgs/<org_name>.json and re-run.
|
|
79
|
+
```
|
|
80
|
+
- Return `status: blocked`. **STOP — do not proceed.**
|
|
81
|
+
|
|
82
|
+
If `current_loop_status == "paused"`:
|
|
83
|
+
- Print: "Org '<org_name>' was paused. Reactivating..."
|
|
84
|
+
- Proceed (set to "active" below).
|
|
85
|
+
|
|
86
|
+
For all other statuses (stopped, or absent):
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
tmp="${orgFile}.tmp"
|
|
90
|
+
jq '.status = "active"' "$orgFile" > "$tmp" && mv "$tmp" "$orgFile"
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### 1.6.2 — Derive scheduled-org variables
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
orgName=$(jq -r '.name' "$orgFile")
|
|
97
|
+
goal="${task:-$(jq -r '.goal' "$orgFile")}"
|
|
98
|
+
sessionId="$session_id"
|
|
99
|
+
poll_interval_minutes=$(jq -r '.loop.poll_interval_minutes' "$orgFile")
|
|
100
|
+
poll_interval_seconds=$(( poll_interval_minutes * 60 ))
|
|
101
|
+
run_prompt_file=$(jq -r '.loop.run_prompt_file' "$orgFile")
|
|
102
|
+
REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
|
|
103
|
+
CTRL_URL=$(jq -r '.url // "http://localhost:4242"' "$REPO_ROOT/.monomind/control.json" 2>/dev/null || echo "http://localhost:4242")
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### 1.6.3 — Emit org:start event
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
curl -s -X POST "${CTRL_URL}/api/mastermind/event" \
|
|
110
|
+
-H "Content-Type: application/json" \
|
|
111
|
+
-d "$(jq -cn \
|
|
112
|
+
--arg session "$sessionId" \
|
|
113
|
+
--arg org "$orgName" \
|
|
114
|
+
--arg goal "$goal" \
|
|
115
|
+
--arg proj "$REPO_ROOT" \
|
|
116
|
+
'{type:"org:start",session:$session,org:$org,goal:$goal,project:$proj,ts:(now*1000|floor)}')" || true
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### 1.6.4 — Execute first iteration inline
|
|
120
|
+
|
|
121
|
+
Read the loop prompt file and execute its instructions directly (this IS the first iteration):
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
[ ! -f "$run_prompt_file" ] && {
|
|
125
|
+
echo "ERROR: Loop prompt file '${run_prompt_file}' not found."
|
|
126
|
+
echo "Re-run: /mastermind:createorg --name ${orgName} --schedule \"every ${poll_interval_minutes} minutes\" to regenerate it."
|
|
127
|
+
exit 1
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Execute the steps described in `$run_prompt_file` — the file contains the full iteration instructions for this org. Follow them exactly, starting from Step 0 (status gate) through the org-specific work steps.
|
|
132
|
+
|
|
133
|
+
Since this is the first run and status was just set to "active", Step 0 will pass. The org-specific iteration steps run normally.
|
|
134
|
+
|
|
135
|
+
### 1.6.5 — Schedule next iteration via ScheduleWakeup
|
|
136
|
+
|
|
137
|
+
After the iteration completes, re-check status and schedule the next wakeup:
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
LOOP_STATUS=$(jq -r '.status // "stopped"' "$orgFile" 2>/dev/null || echo "stopped")
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
If `LOOP_STATUS == "active"` or `LOOP_STATUS == "paused"`:
|
|
144
|
+
|
|
145
|
+
1. Read the loop prompt:
|
|
146
|
+
```bash
|
|
147
|
+
LOOP_PROMPT=$(cat "$run_prompt_file")
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
2. Call `ScheduleWakeup` with:
|
|
151
|
+
- `delaySeconds`: `$poll_interval_seconds`
|
|
152
|
+
- `reason`: `"<orgName>: next scheduled poll (every <poll_interval_minutes> min)"`
|
|
153
|
+
- `prompt`: full contents of `$LOOP_PROMPT`
|
|
154
|
+
|
|
155
|
+
3. Update `next_run` in org JSON:
|
|
156
|
+
```bash
|
|
157
|
+
next_ts=$(( $(date +%s) + poll_interval_seconds ))
|
|
158
|
+
next_iso=$(date -u -r "$next_ts" +%Y-%m-%dT%H:%M:%SZ 2>/dev/null \
|
|
159
|
+
|| date -u -d "@$next_ts" +%Y-%m-%dT%H:%M:%SZ 2>/dev/null \
|
|
160
|
+
|| python3 -c "import datetime; print(datetime.datetime.utcfromtimestamp($next_ts).strftime('%Y-%m-%dT%H:%M:%SZ'))")
|
|
161
|
+
tmp="${orgFile}.tmp"
|
|
162
|
+
jq --arg next "$next_iso" '.loop.next_run = $next' "$orgFile" > "$tmp" && mv "$tmp" "$orgFile"
|
|
163
|
+
curl -s -X POST "${CTRL_URL}/api/mastermind/event" \
|
|
164
|
+
-H "Content-Type: application/json" \
|
|
165
|
+
-d "$(jq -cn --arg org "$orgName" --arg next "$next_iso" --arg proj "$REPO_ROOT" \
|
|
166
|
+
'{type:"org:loop:scheduled",org:$org,next_run:$next,project:$proj,ts:(now*1000|floor)}')" || true
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
If `LOOP_STATUS` is anything else → print "Org was stopped during this run — loop will not continue." No ScheduleWakeup.
|
|
170
|
+
|
|
171
|
+
### 1.6.6 — Report to user
|
|
172
|
+
|
|
173
|
+
```
|
|
174
|
+
╔══════════════════════════════════════════════════════════╗
|
|
175
|
+
║ ORG STARTED: <orgName> ║
|
|
176
|
+
║ GOAL: <goal> ║
|
|
177
|
+
║ MODE: scheduled loop ║
|
|
178
|
+
╚══════════════════════════════════════════════════════════╝
|
|
179
|
+
|
|
180
|
+
SCHEDULE
|
|
181
|
+
────────
|
|
182
|
+
Interval: every <poll_interval_minutes> minutes
|
|
183
|
+
Status: active
|
|
184
|
+
Next run: <next_iso (or "see .monomind/orgs/<orgName>.json")>
|
|
185
|
+
|
|
186
|
+
To stop: /mastermind:stoporg --org <orgName>
|
|
187
|
+
Status: /mastermind:orgstatus --org <orgName>
|
|
188
|
+
All orgs: /mastermind:orgs
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### 1.6.7 — Return (skip Steps 2–8)
|
|
192
|
+
|
|
193
|
+
```yaml
|
|
194
|
+
domain: ops
|
|
195
|
+
status: complete
|
|
196
|
+
decisions:
|
|
197
|
+
- what: "Scheduled org <orgName> activated, first iteration complete, next wakeup in <poll_interval_minutes> min"
|
|
198
|
+
why: "Loop started by runorg; ScheduleWakeup queued"
|
|
199
|
+
confidence: 0.9
|
|
200
|
+
outcome: pending
|
|
201
|
+
next_actions:
|
|
202
|
+
- "Stop: /mastermind:stoporg --org <orgName>"
|
|
203
|
+
- "Status: /mastermind:orgstatus --org <orgName>"
|
|
204
|
+
run_id: "<runId>"
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
**STOP HERE** — do not execute Steps 2–8 for scheduled orgs.
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
47
211
|
## Step 2 — Derive Variables
|
|
48
212
|
|
|
49
213
|
Before spawning any agents, derive all variables from the loaded config. These are used in Steps 3 and 4.
|
|
@@ -91,9 +255,13 @@ stopFile=".monomind/orgs/.stops/${orgName}.stop"
|
|
|
91
255
|
memNs="org:${orgName}"
|
|
92
256
|
topology=$(jq -r '.topology' "$orgFile")
|
|
93
257
|
checkpointMin=$(jq -r '.run_config.checkpoint_interval_min // 30' "$orgFile")
|
|
94
|
-
bossRole_id=$(jq -r '[.roles[] | select(.reports_to == null)][0].id' "$orgFile")
|
|
95
|
-
bossRole_title=$(jq -r '[.roles[] | select(.reports_to == null)][0].title' "$orgFile")
|
|
96
|
-
bossRole_agent_type=$(jq -r '[.roles[] | select(.reports_to == null)][0].agent_type' "$orgFile")
|
|
258
|
+
bossRole_id=$(jq -r '[(.roles // [])[] | select(.reports_to == null or .reports_to == "")][0].id' "$orgFile")
|
|
259
|
+
bossRole_title=$(jq -r '[(.roles // [])[] | select(.reports_to == null or .reports_to == "")][0].title' "$orgFile")
|
|
260
|
+
bossRole_agent_type=$(jq -r '[(.roles // [])[] | select(.reports_to == null or .reports_to == "")][0].agent_type' "$orgFile")
|
|
261
|
+
if [ -z "$bossRole_id" ] || [ "$bossRole_id" = "null" ]; then
|
|
262
|
+
echo "ERROR: Org '${org_name}' has no root role (reports_to: null). Check the org config."
|
|
263
|
+
exit 1
|
|
264
|
+
fi
|
|
97
265
|
board_id=$(jq -r '.board_id // empty' "$orgFile")
|
|
98
266
|
todo_col=$(jq -r '.todo_col_id // empty' "$orgFile")
|
|
99
267
|
doing_col=$(jq -r '.doing_col_id // empty' "$orgFile")
|
|
@@ -110,8 +278,10 @@ runId=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
|
110
278
|
The board and column IDs were written into the org config by `createorg`. If missing, the org was not created correctly.
|
|
111
279
|
|
|
112
280
|
```bash
|
|
113
|
-
[ -z "$board_id" ]
|
|
281
|
+
[ -z "$board_id" ] && { echo "ERROR: org config missing board_id — re-run /mastermind:createorg --name ${orgName} to rebuild the org."; exit 1; }
|
|
114
282
|
[ -z "$todo_col" ] && { echo "ERROR: org config missing todo_col_id — re-run /mastermind:createorg --name ${orgName}."; exit 1; }
|
|
283
|
+
[ -z "$doing_col" ] && { echo "ERROR: org config missing doing_col_id — re-run /mastermind:createorg --name ${orgName}."; exit 1; }
|
|
284
|
+
[ -z "$done_col" ] && { echo "ERROR: org config missing done_col_id — re-run /mastermind:createorg --name ${orgName}."; exit 1; }
|
|
115
285
|
```
|
|
116
286
|
|
|
117
287
|
**Create stop-file and state directories:**
|
|
@@ -236,7 +406,7 @@ APPROVAL GATE (when governance.policy is "board" or "strict"):
|
|
|
236
406
|
Before any external action (sending emails, posting content, making purchases, modifying infrastructure):
|
|
237
407
|
approvalsFile=".monomind/orgs/${orgName}-approvals.json"
|
|
238
408
|
[ ! -f "$approvalsFile" ] && echo '{"approvals":[]}' > "$approvalsFile"
|
|
239
|
-
approval_id="req-$(date +%s)"
|
|
409
|
+
approval_id="req-$(date +%s)-$$-$RANDOM"
|
|
240
410
|
jq --arg id "$approval_id" --arg agent "<role_id>" --arg title "<action summary>" \
|
|
241
411
|
--arg action "<full action description>" --arg risk "medium" \
|
|
242
412
|
'.approvals += [{"id":$id,"agent_id":$agent,"title":$title,"action":$action,"risk_level":$risk,"status":"pending","requested_at":(now|todate)}]' \
|
|
@@ -249,9 +419,9 @@ APPROVAL GATE (when governance.policy is "board" or "strict"):
|
|
|
249
419
|
# Check the approvals file first (updated by both dashboard UI and /mastermind:approve command),
|
|
250
420
|
# then fall back to memory in case an external notifier wrote there.
|
|
251
421
|
for i in $(seq 1 60); do
|
|
252
|
-
status=$(jq --arg id "$approval_id" '.approvals[] | select(.id == $id) | .status // ""' "$approvalsFile" 2>/dev/null || echo "")
|
|
422
|
+
status=$(jq -r --arg id "$approval_id" '(.approvals // [])[] | select(.id == $id) | .status // ""' "$approvalsFile" 2>/dev/null || echo "")
|
|
253
423
|
if [ -z "$status" ] || [ "$status" = "pending" ]; then
|
|
254
|
-
mem_status=$(npx monomind@latest memory
|
|
424
|
+
mem_status=$(npx monomind@latest memory get --key "approval:${approval_id}" --namespace "${memNs}" 2>/dev/null | jq -r '.status // ""' 2>/dev/null)
|
|
255
425
|
[ -n "$mem_status" ] && status="$mem_status"
|
|
256
426
|
fi
|
|
257
427
|
[ "$status" = "approved" ] && break
|
|
@@ -34,7 +34,7 @@ If `caller` is not "command", load brain context following _protocol.md Brain Lo
|
|
|
34
34
|
if [ -n "$org_name" ]; then
|
|
35
35
|
orgs="$org_name"
|
|
36
36
|
else
|
|
37
|
-
orgs=$(ls .monomind/orgs/*.json 2>/dev/null | grep -
|
|
37
|
+
orgs=$(ls .monomind/orgs/*.json 2>/dev/null | grep -vE -- '-approvals|-state|-activity|-goals|-routines|-projects|-members|-issues|-workspaces|-worktrees|-environments|-plugins|-adapters|-bootstrap|-threads|-budgets|-project-workspaces|-approval-comments' | xargs -I{} basename {} .json | sort)
|
|
38
38
|
fi
|
|
39
39
|
[ -z "$orgs" ] && { echo "No orgs found. Run /mastermind:createorg first."; exit 0; }
|
|
40
40
|
```
|
|
@@ -61,7 +61,7 @@ for org in $orgs; do
|
|
|
61
61
|
# ── Agents ────────────────────────────────────────
|
|
62
62
|
if [ "$scope" = "all" ] || [ "$scope" = "agents" ]; then
|
|
63
63
|
hits=$(jq -r --arg q "$query_lower" \
|
|
64
|
-
'.roles[] | select((.id + " " + .title + " " + (.responsibilities // [] | join(" "))) | ascii_downcase | test($q)) |
|
|
64
|
+
'(.roles // [])[] | select((.id + " " + .title + " " + (.responsibilities // [] | join(" "))) | ascii_downcase | test($q)) |
|
|
65
65
|
"[AGENT] \(.id): \(.title) type=\(.agent_type)"' \
|
|
66
66
|
"$orgFile" 2>/dev/null | head -"$limit")
|
|
67
67
|
if [ -n "$hits" ]; then
|
|
@@ -76,7 +76,7 @@ for org in $orgs; do
|
|
|
76
76
|
goalsFile=".monomind/orgs/${org}-goals.json"
|
|
77
77
|
if [ -f "$goalsFile" ] && { [ "$scope" = "all" ] || [ "$scope" = "goals" ]; }; then
|
|
78
78
|
hits=$(jq -r --arg q "$query_lower" \
|
|
79
|
-
'.goals[] | select((.title + " " + (.description // "") + " " + (.status // "")) | ascii_downcase | test($q)) |
|
|
79
|
+
'(.goals // [])[] | select((.title + " " + (.description // "") + " " + (.status // "")) | ascii_downcase | test($q)) |
|
|
80
80
|
"[GOAL] [\(.id)] \(.title) status=\(.status // "open")"' \
|
|
81
81
|
"$goalsFile" 2>/dev/null | head -"$limit")
|
|
82
82
|
if [ -n "$hits" ]; then
|
|
@@ -91,7 +91,7 @@ for org in $orgs; do
|
|
|
91
91
|
routinesFile=".monomind/orgs/${org}-routines.json"
|
|
92
92
|
if [ -f "$routinesFile" ] && { [ "$scope" = "all" ] || [ "$scope" = "routines" ]; }; then
|
|
93
93
|
hits=$(jq -r --arg q "$query_lower" \
|
|
94
|
-
'.routines[] | select((.name + " " + (.description // "") + " " + (.schedule // "")) | ascii_downcase | test($q)) |
|
|
94
|
+
'(.routines // [])[] | select((.name + " " + (.description // "") + " " + (.schedule // "")) | ascii_downcase | test($q)) |
|
|
95
95
|
"[ROUTINE] \(.name) schedule=\(.schedule // "-")"' \
|
|
96
96
|
"$routinesFile" 2>/dev/null | head -"$limit")
|
|
97
97
|
if [ -n "$hits" ]; then
|
|
@@ -106,7 +106,7 @@ for org in $orgs; do
|
|
|
106
106
|
approvalsFile=".monomind/orgs/${org}-approvals.json"
|
|
107
107
|
if [ -f "$approvalsFile" ] && { [ "$scope" = "all" ] || [ "$scope" = "approvals" ]; }; then
|
|
108
108
|
hits=$(jq -r --arg q "$query_lower" \
|
|
109
|
-
'.approvals[] | select((.title + " " + (.action // "") + " " + (.agent_id // "")) | ascii_downcase | test($q)) |
|
|
109
|
+
'(.approvals // [])[] | select((.title + " " + (.action // "") + " " + (.agent_id // "")) | ascii_downcase | test($q)) |
|
|
110
110
|
"[APPROVAL] [\(.id)] \(.agent_id): \(.title) status=\(.status)"' \
|
|
111
111
|
"$approvalsFile" 2>/dev/null | head -"$limit")
|
|
112
112
|
if [ -n "$hits" ]; then
|
|
@@ -121,7 +121,7 @@ for org in $orgs; do
|
|
|
121
121
|
projectsFile=".monomind/orgs/${org}-projects.json"
|
|
122
122
|
if [ -f "$projectsFile" ] && { [ "$scope" = "all" ] || [ "$scope" = "projects" ]; }; then
|
|
123
123
|
hits=$(jq -r --arg q "$query_lower" \
|
|
124
|
-
'.projects[] | select((.name + " " + (.description // "") + " " + (.lead // "")) | ascii_downcase | test($q)) |
|
|
124
|
+
'(.projects // [])[] | select((.name + " " + (.description // "") + " " + (.lead // "")) | ascii_downcase | test($q)) |
|
|
125
125
|
"[PROJECT] \(.name) status=\(.status // "active") lead=\(.lead // "-")"' \
|
|
126
126
|
"$projectsFile" 2>/dev/null | head -"$limit")
|
|
127
127
|
if [ -n "$hits" ]; then
|
|
@@ -61,7 +61,7 @@ Show all registered secrets for this org (metadata only, masked values):
|
|
|
61
61
|
|
|
62
62
|
```bash
|
|
63
63
|
jq -r '
|
|
64
|
-
.secrets[] |
|
|
64
|
+
(.secrets // [])[] |
|
|
65
65
|
"[\(.name)] provider=\(.provider) hint=\(.masked_hint // "***") set=\(.set_at // "unknown") rotated=\(.rotated_at // "never")"
|
|
66
66
|
' "$secretsFile" 2>/dev/null || echo "No secrets registered."
|
|
67
67
|
```
|
|
@@ -108,7 +108,7 @@ jq --arg name "$secret_name" \
|
|
|
108
108
|
--arg provider "${provider:-local}" \
|
|
109
109
|
--arg hint "$hint" \
|
|
110
110
|
--arg ts "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
|
|
111
|
-
'.secrets = [.secrets[] | select(.name != $name)] +
|
|
111
|
+
'.secrets = [(.secrets // [])[] | select(.name != $name)] +
|
|
112
112
|
[{"name":$name,"provider":$provider,"masked_hint":$hint,"set_at":$ts}]' \
|
|
113
113
|
"$secretsFile" > "$tmp" && mv "$tmp" "$secretsFile"
|
|
114
114
|
|
|
@@ -128,7 +128,7 @@ Generate a new value from env var and update:
|
|
|
128
128
|
# Same as set but also records rotated_at
|
|
129
129
|
tmp="${secretsFile}.tmp"
|
|
130
130
|
jq --arg name "$secret_name" --arg ts "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
|
|
131
|
-
'.secrets = [.secrets[] | if .name == $name then .rotated_at = $ts | .set_at = $ts else . end]' \
|
|
131
|
+
'.secrets = [(.secrets // [])[] | if .name == $name then .rotated_at = $ts | .set_at = $ts else . end]' \
|
|
132
132
|
"$secretsFile" > "$tmp" && mv "$tmp" "$secretsFile"
|
|
133
133
|
# Then re-run the set logic above with new value
|
|
134
134
|
```
|
|
@@ -140,7 +140,7 @@ Remove secret value and registry entry:
|
|
|
140
140
|
```bash
|
|
141
141
|
rm -f ".monomind/orgs/.secrets/${org_name}/${secret_name}"
|
|
142
142
|
tmp="${secretsFile}.tmp"
|
|
143
|
-
jq --arg name "$secret_name" '.secrets = [.secrets[] | select(.name != $name)]' \
|
|
143
|
+
jq --arg name "$secret_name" '.secrets = [(.secrets // [])[] | select(.name != $name)]' \
|
|
144
144
|
"$secretsFile" > "$tmp" && mv "$tmp" "$secretsFile"
|
|
145
145
|
echo "Secret $secret_name revoked."
|
|
146
146
|
```
|
|
@@ -152,9 +152,9 @@ Show which agents reference each secret in their adapter_config or responsibilit
|
|
|
152
152
|
```bash
|
|
153
153
|
orgFile=".monomind/orgs/${org_name}.json"
|
|
154
154
|
echo "=== SECRET USAGE AUDIT — org: $org_name ==="
|
|
155
|
-
jq -r '.roles[] | "\(.id): \(.responsibilities | join(", "))"' "$orgFile" | \
|
|
155
|
+
jq -r '(.roles // [])[] | "\(.id): \((.responsibilities // []) | join(", "))"' "$orgFile" | \
|
|
156
156
|
while IFS=: read -r role resp; do
|
|
157
|
-
refs=$(jq -r '.secrets[].name' "$secretsFile" | while read -r sname; do
|
|
157
|
+
refs=$(jq -r '(.secrets // [])[].name' "$secretsFile" | while read -r sname; do
|
|
158
158
|
echo "$resp" | grep -q "$sname" && echo " → $sname"
|
|
159
159
|
done)
|
|
160
160
|
[ -n "$refs" ] && echo "$role$refs"
|
|
@@ -76,12 +76,12 @@ orgFile=".monomind/orgs/${org_name}.json"
|
|
|
76
76
|
echo "SKILL MAP — org: $org_name"
|
|
77
77
|
echo "────────────────────────────────────────────────────────"
|
|
78
78
|
|
|
79
|
-
jq -r '.roles[] | "[\(.id)] \(.title) agent_type=\(.agent_type)"' "$orgFile" | while IFS= read -r line; do
|
|
79
|
+
jq -r '(.roles // [])[] | "[\(.id)] \(.title) agent_type=\(.agent_type)"' "$orgFile" | while IFS= read -r line; do
|
|
80
80
|
echo "$line"
|
|
81
81
|
roleId=$(echo "$line" | grep -o '^\[[^]]*\]' | tr -d '[]')
|
|
82
82
|
# Show skills configured for this role
|
|
83
83
|
mappedSkills=$(jq -r --arg id "$roleId" \
|
|
84
|
-
'.roles[] | select(.id == $id) | .skills // [] | join(", ")' \
|
|
84
|
+
'(.roles // [])[] | select(.id == $id) | .skills // [] | join(", ")' \
|
|
85
85
|
"$orgFile" 2>/dev/null)
|
|
86
86
|
if [ -n "$mappedSkills" ] && [ "$mappedSkills" != "null" ]; then
|
|
87
87
|
echo " Skills: $mappedSkills"
|
|
@@ -126,12 +126,12 @@ orgFile=".monomind/orgs/${org_name}.json"
|
|
|
126
126
|
tmp="${orgFile}.tmp"
|
|
127
127
|
if [ "$action" = "enable" ]; then
|
|
128
128
|
jq --arg id "$role_id" --arg skill "$skill_name" \
|
|
129
|
-
'.roles = [.roles[] | if .id == $id then .skills = ((.skills // []) + [$skill] | unique) else . end]' \
|
|
129
|
+
'.roles = [(.roles // [])[] | if .id == $id then .skills = ((.skills // []) + [$skill] | unique) else . end]' \
|
|
130
130
|
"$orgFile" > "$tmp" && mv "$tmp" "$orgFile"
|
|
131
131
|
echo "Enabled skill '$skill_name' for role '$role_id'"
|
|
132
132
|
else
|
|
133
133
|
jq --arg id "$role_id" --arg skill "$skill_name" \
|
|
134
|
-
'.roles = [.roles[] | if .id == $id then .skills = ((.skills // []) | map(select(. != $skill))) else . end]' \
|
|
134
|
+
'.roles = [(.roles // [])[] | if .id == $id then .skills = ((.skills // []) | map(select(. != $skill))) else . end]' \
|
|
135
135
|
"$orgFile" > "$tmp" && mv "$tmp" "$orgFile"
|
|
136
136
|
echo "Disabled skill '$skill_name' for role '$role_id'"
|
|
137
137
|
fi
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mastermind-stoporg
|
|
3
|
+
description: Mastermind stoporg — stop a running scheduled org loop by setting its status to "stopped". The next scheduled wakeup will read the status, skip all work, and not reschedule. Loop dies within one interval — no orphaned wakeups.
|
|
4
|
+
type: domain-skill
|
|
5
|
+
default_mode: auto
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Mastermind Stop Org
|
|
9
|
+
|
|
10
|
+
This skill is invoked by `mastermind:stoporg` or directly via `/mastermind:stoporg`.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Inputs
|
|
15
|
+
|
|
16
|
+
- `org_name`: name of the org to stop (matches `.monomind/orgs/<org_name>.json`)
|
|
17
|
+
- `session_id`: session ID generated by the command wrapper
|
|
18
|
+
- `caller`: command | master
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Step 0 — Brain Load (standalone only)
|
|
23
|
+
|
|
24
|
+
If `caller` is not "command", load brain context following _protocol.md Brain Load Procedure with namespace: `ops`.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Step 1 — Validate Org
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
orgFile=".monomind/orgs/${org_name}.json"
|
|
32
|
+
[ ! -f "$orgFile" ] && {
|
|
33
|
+
echo "ERROR: Org '${org_name}' not found."
|
|
34
|
+
echo "Available orgs: $(ls .monomind/orgs/*.json 2>/dev/null | grep -vE -- '-approvals|-state|-activity|-goals|-routines|-projects|-members|-issues|-workspaces|-worktrees|-environments|-plugins|-adapters|-bootstrap|-threads|-budgets|-project-workspaces|-approval-comments' | xargs -I{} basename {} .json | tr '\n' ' ')"
|
|
35
|
+
exit 1
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Read current status:
|
|
40
|
+
```bash
|
|
41
|
+
current_status=$(jq -r '.status // "no-schedule"' "$orgFile")
|
|
42
|
+
has_schedule=$(jq -r 'if .loop.poll_interval_minutes then "yes" else "no" end' "$orgFile")
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
If `has_schedule == "no"`:
|
|
46
|
+
```bash
|
|
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")
|
|
49
|
+
# Write stop file so any running boss agent detects it at next loop iteration
|
|
50
|
+
mkdir -p ".monomind/orgs/.stops"
|
|
51
|
+
touch ".monomind/orgs/.stops/${org_name}.stop"
|
|
52
|
+
# Also POST to the control server in case a dashboard-started instance is running
|
|
53
|
+
curl -s -X POST "${CTRL_URL}/api/orgs/${org_name}/stop" >/dev/null 2>&1 || true
|
|
54
|
+
echo "Stop signal sent to org '${org_name}' (non-scheduled). The boss agent will exit at the next loop checkpoint."
|
|
55
|
+
```
|
|
56
|
+
- Exit.
|
|
57
|
+
|
|
58
|
+
If `current_status == "stopped"`:
|
|
59
|
+
- Print: "Org '<org_name>' is already stopped."
|
|
60
|
+
- Exit.
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Step 2 — Set Status to Stopped and Clear next_run
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
orgFile=".monomind/orgs/${org_name}.json"
|
|
68
|
+
tmp="${orgFile}.tmp"
|
|
69
|
+
# Clear next_run to avoid showing a stale future timestamp in orgstatus
|
|
70
|
+
jq '.status = "stopped" | if .loop then .loop.next_run = null else . end' "$orgFile" > "$tmp" && mv "$tmp" "$orgFile"
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Step 3 — Write Stop File (for any running boss agents)
|
|
76
|
+
|
|
77
|
+
Any persistent boss agent checks for this file at the start of each loop iteration:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
mkdir -p .monomind/orgs/.stops
|
|
81
|
+
touch ".monomind/orgs/.stops/${org_name}.stop"
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## Step 4 — Emit Dashboard Events
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
|
|
90
|
+
CTRL_URL=$(jq -r '.url // "http://localhost:4242"' "$REPO_ROOT/.monomind/control.json" 2>/dev/null || echo "http://localhost:4242")
|
|
91
|
+
|
|
92
|
+
# org:stop — signals dashboard to update status to stopped
|
|
93
|
+
curl -s -X POST "${CTRL_URL}/api/mastermind/event" \
|
|
94
|
+
-H "Content-Type: application/json" \
|
|
95
|
+
-d "$(jq -cn \
|
|
96
|
+
--arg session "${session_id:-manual}" \
|
|
97
|
+
--arg org "$org_name" \
|
|
98
|
+
--arg proj "$REPO_ROOT" \
|
|
99
|
+
'{type:"org:stop",session:$session,org:$org,project:$proj,ts:(now*1000|floor)}')" || true
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Step 5 — Report to User
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
✓ Org "<org_name>" stopped.
|
|
108
|
+
|
|
109
|
+
Current status: stopped
|
|
110
|
+
The loop will exit at its next scheduled wakeup without rescheduling.
|
|
111
|
+
Loop fully dead within: ≤<poll_interval_minutes> minutes
|
|
112
|
+
|
|
113
|
+
To restart: /mastermind:runorg --org <org_name>
|
|
114
|
+
Status: /mastermind:orgstatus --org <org_name>
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## Step 6 — Return Output
|
|
120
|
+
|
|
121
|
+
```yaml
|
|
122
|
+
domain: ops
|
|
123
|
+
status: complete
|
|
124
|
+
decisions:
|
|
125
|
+
- what: "Org <org_name> stopped"
|
|
126
|
+
why: "status set to 'stopped'; next wakeup exits without rescheduling"
|
|
127
|
+
confidence: 1.0
|
|
128
|
+
outcome: shipped
|
|
129
|
+
next_actions:
|
|
130
|
+
- "To restart: /mastermind:runorg --org <org_name>"
|
|
131
|
+
- "To check current state: /mastermind:orgstatus --org <org_name>"
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## Step 7 — Brain Write (standalone only)
|
|
137
|
+
|
|
138
|
+
If `caller` is not "command", follow _protocol.md Brain Write Procedure for domain `ops`.
|
|
@@ -56,7 +56,7 @@ orgFile=".monomind/orgs/${org_name}.json"
|
|
|
56
56
|
wsFile=".monomind/orgs/${org_name}-workspaces.json"
|
|
57
57
|
[ ! -f "$wsFile" ] && { echo "ERROR: No workspaces file for org '$org_name'. Create workspaces via /mastermind:workspaces."; exit 1; }
|
|
58
58
|
|
|
59
|
-
wsDef=$(jq -r --arg id "$workspace_id" '.workspaces[] | select(.id == $id)' "$wsFile")
|
|
59
|
+
wsDef=$(jq -r --arg id "$workspace_id" '(.workspaces // [])[] | select(.id == $id)' "$wsFile")
|
|
60
60
|
[ -z "$wsDef" ] && { echo "ERROR: Workspace '$workspace_id' not found in org '$org_name'."; exit 1; }
|
|
61
61
|
|
|
62
62
|
issuesFile=".monomind/orgs/${org_name}-issues.json"
|
|
@@ -145,7 +145,7 @@ else
|
|
|
145
145
|
ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
146
146
|
tmp="${wsFile}.tmp"
|
|
147
147
|
jq --arg id "$workspace_id" --arg ts "$ts" \
|
|
148
|
-
'.workspaces = [.workspaces[] | if .id == $id then .last_provisioned = $ts else . end]' \
|
|
148
|
+
'.workspaces = [(.workspaces // [])[] | if .id == $id then .last_provisioned = $ts else . end]' \
|
|
149
149
|
"$wsFile" > "$tmp" && mv "$tmp" "$wsFile"
|
|
150
150
|
echo " Provision complete."
|
|
151
151
|
} || echo " Provision command exited with error."
|
|
@@ -230,7 +230,7 @@ echo "────────────────────────
|
|
|
230
230
|
if [ ! -f "$issuesFile" ]; then
|
|
231
231
|
echo " No issues file found."
|
|
232
232
|
else
|
|
233
|
-
jq -r --arg wid "$workspace_id" '.issues[] |
|
|
233
|
+
jq -r --arg wid "$workspace_id" '(.issues // [])[] |
|
|
234
234
|
select(.workspace_id == $wid or (.assigned_workspace == $wid)) |
|
|
235
235
|
[.id, (.status // "open"), (.priority // "medium"), (.title // "(no title)")] | @tsv' \
|
|
236
236
|
"$issuesFile" | while IFS=$'\t' read -r id st pri title; do
|
|
@@ -250,7 +250,7 @@ if [ ! -f "$routinesFile" ]; then
|
|
|
250
250
|
else
|
|
251
251
|
# Show routines that have workspace-specific variable bindings
|
|
252
252
|
jq -r --arg wid "$workspace_id" \
|
|
253
|
-
'.routines[] | select((.variables // {}) | to_entries[] | .key | startswith("WS_") or contains("workspace")) |
|
|
253
|
+
'(.routines // [])[] | select((.variables // {}) | to_entries[] | .key | startswith("WS_") or contains("workspace")) |
|
|
254
254
|
"\(.id) \(.name // "(no name)") vars: \((.variables // {}) | keys | join(", "))"' \
|
|
255
255
|
"$routinesFile" 2>/dev/null || echo " No routines with workspace-specific variables."
|
|
256
256
|
fi
|
|
@@ -279,7 +279,7 @@ if [ -n "$provision_command" ] || [ -n "$teardown_command" ] || [ -n "$cleanup_c
|
|
|
279
279
|
--arg base "${base_ref:-}" \
|
|
280
280
|
--arg branch "${branch_name:-}" \
|
|
281
281
|
--arg ts "$ts" \
|
|
282
|
-
'.workspaces = [.workspaces[] | if .id == $id then
|
|
282
|
+
'.workspaces = [(.workspaces // [])[] | if .id == $id then
|
|
283
283
|
if .config == null then .config = {} else . end |
|
|
284
284
|
(if $prov != "" then .config.provisionCommand = $prov else . end) |
|
|
285
285
|
(if $td != "" then .config.teardownCommand = $td else . end) |
|