@monoes/monomindcli 1.9.17 → 1.10.1
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/_repeat.md +182 -39
- package/.claude/commands/mastermind/architect.md +17 -11
- package/.claude/commands/mastermind/brain.md +4 -0
- package/.claude/commands/mastermind/build.md +4 -0
- package/.claude/commands/mastermind/content.md +4 -0
- package/.claude/commands/mastermind/createorg.md +5 -3
- package/.claude/commands/mastermind/finance.md +4 -0
- package/.claude/commands/mastermind/idea.md +4 -0
- package/.claude/commands/mastermind/marketing.md +4 -0
- package/.claude/commands/mastermind/master.md +63 -37
- package/.claude/commands/mastermind/ops.md +4 -0
- package/.claude/commands/mastermind/release.md +4 -0
- package/.claude/commands/mastermind/research.md +4 -0
- package/.claude/commands/mastermind/review.md +4 -0
- package/.claude/commands/mastermind/runorg.md +5 -3
- package/.claude/commands/mastermind/sales.md +4 -0
- package/.claude/commands/mastermind/techport.md +9 -0
- package/.claude/commands/monomind/do.md +5 -1
- package/.claude/commands/monomind/idea.md +5 -1
- package/.claude/commands/monomind/improve.md +5 -1
- package/.claude/commands/monomind/repeat.md +85 -29
- package/.claude/commands/monomind/review.md +6 -2
- package/.claude/commands/monomind/understand.md +10 -8
- package/.claude/helpers/extras-registry.json +235 -235
- package/.claude/helpers/graphify-freshen.cjs +13 -1
- package/.claude/helpers/hook-handler.cjs +1 -1
- package/.claude/helpers/router.cjs +4 -1
- package/.claude/skills/mastermind/_protocol.md +28 -21
- package/.claude/skills/mastermind/access.md +236 -0
- package/.claude/skills/mastermind/activity.md +191 -0
- package/.claude/skills/mastermind/adapter-manager.md +259 -0
- package/.claude/skills/mastermind/adapters.md +204 -0
- package/.claude/skills/mastermind/agent-detail.md +242 -0
- package/.claude/skills/mastermind/agents.md +178 -0
- package/.claude/skills/mastermind/approval-detail.md +259 -0
- package/.claude/skills/mastermind/approve.md +181 -0
- package/.claude/skills/mastermind/architect.md +24 -8
- package/.claude/skills/mastermind/backup.md +197 -0
- package/.claude/skills/mastermind/bootstrap.md +190 -0
- package/.claude/skills/mastermind/budgets.md +237 -0
- package/.claude/skills/mastermind/companies.md +256 -0
- package/.claude/skills/mastermind/costs.md +151 -0
- package/.claude/skills/mastermind/createorg.md +23 -5
- package/.claude/skills/mastermind/diagnose.md +249 -0
- package/.claude/skills/mastermind/env.md +198 -0
- package/.claude/skills/mastermind/environments.md +250 -0
- package/.claude/skills/mastermind/export.md +324 -0
- package/.claude/skills/mastermind/goal-detail.md +255 -0
- package/.claude/skills/mastermind/goals.md +149 -0
- package/.claude/skills/mastermind/heartbeat.md +164 -0
- package/.claude/skills/mastermind/idea.md +250 -122
- package/.claude/skills/mastermind/import.md +281 -0
- package/.claude/skills/mastermind/inbox.md +214 -0
- package/.claude/skills/mastermind/instance-settings.md +315 -0
- package/.claude/skills/mastermind/instance.md +231 -0
- package/.claude/skills/mastermind/invite-landing.md +227 -0
- package/.claude/skills/mastermind/invites.md +254 -0
- package/.claude/skills/mastermind/issue-detail.md +291 -0
- package/.claude/skills/mastermind/issues.md +235 -0
- package/.claude/skills/mastermind/join-queue.md +170 -0
- package/.claude/skills/mastermind/liveness.md +392 -0
- package/.claude/skills/mastermind/memory.md +321 -0
- package/.claude/skills/mastermind/my-issues.md +146 -0
- package/.claude/skills/mastermind/new-agent.md +241 -0
- package/.claude/skills/mastermind/org-chart.md +207 -0
- package/.claude/skills/mastermind/org-settings.md +217 -0
- package/.claude/skills/mastermind/plan-to-tasks.md +136 -0
- package/.claude/skills/mastermind/plugin-manager.md +241 -0
- package/.claude/skills/mastermind/plugin-settings.md +273 -0
- package/.claude/skills/mastermind/plugins.md +190 -0
- package/.claude/skills/mastermind/profile.md +187 -0
- package/.claude/skills/mastermind/project-detail.md +249 -0
- package/.claude/skills/mastermind/project-workspace.md +244 -0
- package/.claude/skills/mastermind/projects.md +164 -0
- package/.claude/skills/mastermind/routine-detail.md +253 -0
- package/.claude/skills/mastermind/routines.md +202 -0
- package/.claude/skills/mastermind/runorg.md +74 -9
- package/.claude/skills/mastermind/search.md +186 -0
- package/.claude/skills/mastermind/secrets.md +199 -0
- package/.claude/skills/mastermind/skills.md +156 -0
- package/.claude/skills/mastermind/tasks.md +149 -0
- package/.claude/skills/mastermind/techport.md +5 -5
- package/.claude/skills/mastermind/threads.md +259 -0
- package/.claude/skills/mastermind/tree-control.md +250 -0
- package/.claude/skills/mastermind/wiki.md +314 -0
- package/.claude/skills/mastermind/workspace-detail.md +317 -0
- package/.claude/skills/mastermind/workspaces.md +261 -0
- package/.claude/skills/mastermind/worktree.md +187 -0
- package/dist/src/init/executor.js +8 -8
- package/dist/src/init/executor.js.map +1 -1
- package/dist/src/init/statusline-generator.d.ts.map +1 -1
- package/dist/src/init/statusline-generator.js +12 -0
- package/dist/src/init/statusline-generator.js.map +1 -1
- package/dist/src/ui/.monomind/data/ranked-context.json +1 -1
- package/dist/src/ui/.monomind/loops/mastermind-review-1778664132789.json +16 -0
- package/dist/src/ui/.monomind/sessions/current.json +5 -5
- package/dist/src/ui/.monomind/sessions/session-1776778451399.json +15 -0
- package/dist/src/ui/dashboard.html +3030 -181
- package/dist/src/ui/data/mastermind-events.jsonl +8 -0
- package/dist/src/ui/data/mastermind-sessions.json +1 -0
- package/dist/src/ui/server.mjs +738 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/.claude/skills/.monomind/data/ranked-context.json +0 -5
- package/.claude/skills/.monomind/sessions/current.json +0 -13
- package/.claude/skills/.monomind/sessions/session-1777829336455.json +0 -15
- package/.claude/skills/.monomind/sessions/session-1777831614725.json +0 -15
- package/.claude/skills/.monomind/sessions/session-1777832095857.json +0 -15
- package/.claude/skills/.monomind/sessions/session-1777839814183.json +0 -15
- package/.claude/skills/.monomind/sessions/session-1777841847131.json +0 -15
- package/.claude/skills/.monomind/sessions/session-1777843309463.json +0 -15
- package/.claude/skills/.monomind/sessions/session-1777880867159.json +0 -15
- package/.claude/skills/.monomind/sessions/session-1777881884593.json +0 -15
- package/.claude/skills/.monomind/sessions/session-1777884090471.json +0 -15
- package/.claude/skills/.monomind/sessions/session-1777884808221.json +0 -15
- package/.claude/skills/.monomind/sessions/session-1777885672155.json +0 -15
- package/.claude/skills/.monomind/sessions/session-1777886852818.json +0 -15
- package/.claude/skills/.monomind/sessions/session-1777896532690.json +0 -15
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mastermind-wiki
|
|
3
|
+
description: Mastermind wiki — org-scoped knowledge base with ingest, query, maintain, lint, and distill operations. Stores durable synthesis in .monomind/orgs/<org>/wiki/ with page citations, raw sources, and change log. Port of Paperclip's LLM Wiki plugin skills adapted for mastermind orgs.
|
|
4
|
+
type: domain-skill
|
|
5
|
+
default_mode: auto
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Mastermind Wiki
|
|
9
|
+
|
|
10
|
+
This skill is invoked by `mastermind:wiki` or directly via `/mastermind:wiki`.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Inputs
|
|
15
|
+
|
|
16
|
+
- `brain_context`: BRAIN CONTEXT block (injected by command, or loaded below if standalone)
|
|
17
|
+
- `org_name`: org whose wiki to operate on (required)
|
|
18
|
+
- `action`: query | ingest | list | maintain | lint | distill | page
|
|
19
|
+
- `question`: question or search term (required for query)
|
|
20
|
+
- `source`: path or URL to ingest (required for ingest)
|
|
21
|
+
- `page_slug`: wiki page slug to read/write (required for page)
|
|
22
|
+
- `content`: content to write to a page (required for page write)
|
|
23
|
+
- `caller`: command | master
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Wiki Structure
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
.monomind/orgs/<org>/wiki/
|
|
31
|
+
index.md ← navigation hub; must be kept current
|
|
32
|
+
log.md ← append-only change log
|
|
33
|
+
concepts/ ← concepts, definitions, architectural decisions
|
|
34
|
+
projects/ ← per-project knowledge (standup.md + index.md)
|
|
35
|
+
synthesis/ ← synthesized answers filed from queries
|
|
36
|
+
raw/ ← raw source material (never modified after ingest)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**Invariants:**
|
|
40
|
+
- Raw sources in `raw/` are NEVER modified after ingest
|
|
41
|
+
- Every durable page write must append a `log.md` entry
|
|
42
|
+
- `index.md` must be updated when pages are added or removed
|
|
43
|
+
- Answers cite wiki pages or raw sources inline, not in footnote blocks
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Step 0 — Brain Load (standalone only)
|
|
48
|
+
|
|
49
|
+
If `caller` is not "command", load brain context following _protocol.md Brain Load Procedure with namespace: `ops`.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Step 1 — Resolve Wiki Root
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
orgFile=".monomind/orgs/${org_name}.json"
|
|
57
|
+
[ ! -f "$orgFile" ] && { echo "ERROR: Org '${org_name}' not found."; exit 1; }
|
|
58
|
+
|
|
59
|
+
wikiRoot=".monomind/orgs/${org_name}/wiki"
|
|
60
|
+
mkdir -p "$wikiRoot/concepts" "$wikiRoot/projects" "$wikiRoot/synthesis" "$wikiRoot/raw"
|
|
61
|
+
|
|
62
|
+
if [ ! -f "$wikiRoot/index.md" ]; then
|
|
63
|
+
cat > "$wikiRoot/index.md" << EOF
|
|
64
|
+
# Wiki — ${org_name}
|
|
65
|
+
|
|
66
|
+
This is the org knowledge base. Navigate by category or search with \`/mastermind:wiki --action query\`.
|
|
67
|
+
|
|
68
|
+
## Concepts
|
|
69
|
+
(none yet)
|
|
70
|
+
|
|
71
|
+
## Projects
|
|
72
|
+
(none yet)
|
|
73
|
+
|
|
74
|
+
## Synthesis
|
|
75
|
+
(none yet)
|
|
76
|
+
EOF
|
|
77
|
+
fi
|
|
78
|
+
|
|
79
|
+
[ ! -f "$wikiRoot/log.md" ] && echo "# Wiki Log — ${org_name}" > "$wikiRoot/log.md"
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Step 2 — Execute Action
|
|
85
|
+
|
|
86
|
+
### query (default)
|
|
87
|
+
|
|
88
|
+
Answer a question from what the wiki contains, with citations.
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
[ -z "$question" ] && { echo "ERROR: --question required."; exit 1; }
|
|
92
|
+
echo "WIKI QUERY — ${org_name}"
|
|
93
|
+
echo "Q: $question"
|
|
94
|
+
echo "────────────────────────────────────────────────────────"
|
|
95
|
+
|
|
96
|
+
python3 - "$wikiRoot" "$question" <<'PYEOF'
|
|
97
|
+
import os, sys, re
|
|
98
|
+
root, query = sys.argv[1], sys.argv[2].lower()
|
|
99
|
+
hits = []
|
|
100
|
+
|
|
101
|
+
def scan_dir(d, prefix):
|
|
102
|
+
if not os.path.isdir(d): return
|
|
103
|
+
for fname in os.listdir(d):
|
|
104
|
+
if not fname.endswith(".md"): continue
|
|
105
|
+
fpath = os.path.join(d, fname)
|
|
106
|
+
try:
|
|
107
|
+
text = open(fpath).read()
|
|
108
|
+
if query in text.lower():
|
|
109
|
+
snippet = ""
|
|
110
|
+
for line in text.split("\n"):
|
|
111
|
+
if query in line.lower():
|
|
112
|
+
snippet = line.strip()[:120]
|
|
113
|
+
break
|
|
114
|
+
hits.append((prefix + "/" + fname, snippet))
|
|
115
|
+
except: pass
|
|
116
|
+
|
|
117
|
+
scan_dir(os.path.join(root, "concepts"), "concepts")
|
|
118
|
+
scan_dir(os.path.join(root, "synthesis"), "synthesis")
|
|
119
|
+
scan_dir(os.path.join(root, "projects"), "projects")
|
|
120
|
+
scan_dir(os.path.join(root, "raw"), "raw")
|
|
121
|
+
|
|
122
|
+
if not hits:
|
|
123
|
+
print(" No wiki pages match that query.")
|
|
124
|
+
print(" Use --action ingest to add source material, or --action distill to synthesize from org data.")
|
|
125
|
+
else:
|
|
126
|
+
print(f" {len(hits)} page(s) match:")
|
|
127
|
+
for path, snippet in hits[:10]:
|
|
128
|
+
print(f"\n [[{path}]]")
|
|
129
|
+
if snippet: print(f" → {snippet}")
|
|
130
|
+
PYEOF
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### list
|
|
134
|
+
|
|
135
|
+
Show all wiki pages.
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
echo "WIKI INDEX — ${org_name}"
|
|
139
|
+
echo "────────────────────────────────────────────────────────"
|
|
140
|
+
cat "$wikiRoot/index.md"
|
|
141
|
+
echo ""
|
|
142
|
+
echo " Raw sources: $(ls $wikiRoot/raw/ 2>/dev/null | wc -l) file(s)"
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### ingest
|
|
146
|
+
|
|
147
|
+
Add a raw source file to the wiki. Raw sources are immutable after ingest.
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
[ -z "$source" ] && { echo "ERROR: --source required (path to file)."; exit 1; }
|
|
151
|
+
ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
152
|
+
srcBase=$(basename "$source")
|
|
153
|
+
dstPath="$wikiRoot/raw/$srcBase"
|
|
154
|
+
|
|
155
|
+
if [ -f "$dstPath" ]; then
|
|
156
|
+
echo " Already ingested: $srcBase"
|
|
157
|
+
else
|
|
158
|
+
cp "$source" "$dstPath" && echo " Ingested: $srcBase → $wikiRoot/raw/"
|
|
159
|
+
echo "$(date -u +%Y-%m-%d) | ingest | raw/$srcBase" >> "$wikiRoot/log.md"
|
|
160
|
+
fi
|
|
161
|
+
echo " To synthesize a page from this source, use: /mastermind:wiki --action distill --source $srcBase"
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### page
|
|
165
|
+
|
|
166
|
+
Read or write a specific wiki page.
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
[ -z "$page_slug" ] && { echo "ERROR: --page-slug required."; exit 1; }
|
|
170
|
+
ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
171
|
+
|
|
172
|
+
if [ -n "$content" ]; then
|
|
173
|
+
# Write/update
|
|
174
|
+
pageDir="$wikiRoot/$(dirname $page_slug)"
|
|
175
|
+
mkdir -p "$pageDir"
|
|
176
|
+
pagePath="$wikiRoot/${page_slug}.md"
|
|
177
|
+
echo "$content" > "$pagePath"
|
|
178
|
+
echo "$(date -u +%Y-%m-%d) | update | ${page_slug}" >> "$wikiRoot/log.md"
|
|
179
|
+
echo " Page written: $pagePath"
|
|
180
|
+
echo " Remember to update index.md if this is a new page."
|
|
181
|
+
else
|
|
182
|
+
# Read
|
|
183
|
+
pagePath="$wikiRoot/${page_slug}.md"
|
|
184
|
+
if [ -f "$pagePath" ]; then
|
|
185
|
+
cat "$pagePath"
|
|
186
|
+
else
|
|
187
|
+
echo " Page not found: $page_slug"
|
|
188
|
+
echo " Available pages:"
|
|
189
|
+
find "$wikiRoot" -name "*.md" ! -name "index.md" ! -name "log.md" | sed "s|$wikiRoot/||"
|
|
190
|
+
fi
|
|
191
|
+
fi
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### distill
|
|
195
|
+
|
|
196
|
+
Synthesize a wiki page from raw sources and org data. The AI synthesizes based on context, writes the page, and logs it.
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
[ -z "$page_slug" ] && { echo "ERROR: --page-slug required."; exit 1; }
|
|
200
|
+
ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
201
|
+
pagePath="$wikiRoot/${page_slug}.md"
|
|
202
|
+
|
|
203
|
+
echo "WIKI DISTILL — ${org_name}"
|
|
204
|
+
echo "Target: ${page_slug}"
|
|
205
|
+
echo "────────────────────────────────────────────────────────"
|
|
206
|
+
|
|
207
|
+
if [ -n "$source" ] && [ -f "$wikiRoot/raw/$source" ]; then
|
|
208
|
+
echo "Source: $wikiRoot/raw/$source"
|
|
209
|
+
cat "$wikiRoot/raw/$source"
|
|
210
|
+
fi
|
|
211
|
+
|
|
212
|
+
echo ""
|
|
213
|
+
echo " Use the above source material to write a synthesis page at $pagePath."
|
|
214
|
+
echo " The page should: answer the most important questions, cite raw/ sources inline,"
|
|
215
|
+
echo " use a terse factual voice, and avoid summarizing what is already obvious."
|
|
216
|
+
echo " After writing, update index.md to link to the new page and append a distill log entry."
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### maintain
|
|
220
|
+
|
|
221
|
+
Check wiki health: stale pages, missing index links, unreferenced raw sources.
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
echo "WIKI HEALTH — ${org_name}"
|
|
225
|
+
echo "────────────────────────────────────────────────────────"
|
|
226
|
+
|
|
227
|
+
python3 - "$wikiRoot" <<'PYEOF'
|
|
228
|
+
import os, sys
|
|
229
|
+
root = sys.argv[1]
|
|
230
|
+
|
|
231
|
+
pages = []
|
|
232
|
+
for subdir in ["concepts","projects","synthesis"]:
|
|
233
|
+
d = os.path.join(root, subdir)
|
|
234
|
+
if not os.path.isdir(d): continue
|
|
235
|
+
for f in os.listdir(d):
|
|
236
|
+
if f.endswith(".md"): pages.append(f"{subdir}/{f}")
|
|
237
|
+
|
|
238
|
+
raw_sources = os.listdir(os.path.join(root,"raw")) if os.path.isdir(os.path.join(root,"raw")) else []
|
|
239
|
+
|
|
240
|
+
# Check index.md links
|
|
241
|
+
index_text = open(os.path.join(root,"index.md")).read() if os.path.exists(os.path.join(root,"index.md")) else ""
|
|
242
|
+
missing_links = [p for p in pages if p not in index_text]
|
|
243
|
+
orphan_raw = [r for r in raw_sources if r not in index_text and not any(r in open(os.path.join(root,p)).read() for p in pages if os.path.exists(os.path.join(root,p)))]
|
|
244
|
+
|
|
245
|
+
print(f" Pages: {len(pages)}")
|
|
246
|
+
print(f" Raw sources: {len(raw_sources)}")
|
|
247
|
+
print()
|
|
248
|
+
if missing_links:
|
|
249
|
+
print(f" ⚠ {len(missing_links)} page(s) not in index.md:")
|
|
250
|
+
for p in missing_links: print(f" · {p}")
|
|
251
|
+
else:
|
|
252
|
+
print(" ✓ All pages listed in index.md")
|
|
253
|
+
if orphan_raw:
|
|
254
|
+
print(f"\n ⚠ {len(orphan_raw)} raw source(s) not referenced by any page:")
|
|
255
|
+
for r in orphan_raw: print(f" · raw/{r}")
|
|
256
|
+
else:
|
|
257
|
+
print(" ✓ All raw sources referenced")
|
|
258
|
+
PYEOF
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### lint
|
|
262
|
+
|
|
263
|
+
Validate page formatting: headers, citations, no broken links.
|
|
264
|
+
|
|
265
|
+
```bash
|
|
266
|
+
echo "WIKI LINT — ${org_name}"
|
|
267
|
+
echo "────────────────────────────────────────────────────────"
|
|
268
|
+
|
|
269
|
+
python3 - "$wikiRoot" <<'PYEOF'
|
|
270
|
+
import os, sys, re
|
|
271
|
+
root = sys.argv[1]
|
|
272
|
+
issues = []
|
|
273
|
+
|
|
274
|
+
for subdir in ["concepts","projects","synthesis"]:
|
|
275
|
+
d = os.path.join(root, subdir)
|
|
276
|
+
if not os.path.isdir(d): continue
|
|
277
|
+
for fname in os.listdir(d):
|
|
278
|
+
if not fname.endswith(".md"): continue
|
|
279
|
+
fpath = os.path.join(d, fname)
|
|
280
|
+
text = open(fpath).read()
|
|
281
|
+
path = f"{subdir}/{fname}"
|
|
282
|
+
if not text.strip().startswith("#"):
|
|
283
|
+
issues.append(f" {path}: missing H1 title")
|
|
284
|
+
wikilinks = re.findall(r'\[\[([^\]]+)\]\]', text)
|
|
285
|
+
for wl in wikilinks:
|
|
286
|
+
candidate = os.path.join(root, wl.lstrip("/"))
|
|
287
|
+
if not os.path.exists(candidate) and not os.path.exists(candidate+".md"):
|
|
288
|
+
issues.append(f" {path}: broken wiki-link [[{wl}]]")
|
|
289
|
+
|
|
290
|
+
if not issues:
|
|
291
|
+
print(" ✓ No lint issues found.")
|
|
292
|
+
else:
|
|
293
|
+
print(f" {len(issues)} issue(s):")
|
|
294
|
+
for i in issues: print(i)
|
|
295
|
+
PYEOF
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
## Step 3 — Return Output
|
|
301
|
+
|
|
302
|
+
```yaml
|
|
303
|
+
domain: ops
|
|
304
|
+
status: complete
|
|
305
|
+
action: <action>
|
|
306
|
+
org_name: <org_name>
|
|
307
|
+
wiki_root: .monomind/orgs/<org_name>/wiki/
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
---
|
|
311
|
+
|
|
312
|
+
## Step 4 — Brain Write (standalone only)
|
|
313
|
+
|
|
314
|
+
If `caller` is not "command", follow _protocol.md Brain Write Procedure for domain `ops`.
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mastermind-workspace-detail
|
|
3
|
+
description: Mastermind workspace-detail — deep per-execution-workspace inspection and runtime control. Manage services, provision/teardown/cleanup commands, linked issues and routines, runtime logs, and configuration for a single execution workspace.
|
|
4
|
+
type: domain-skill
|
|
5
|
+
default_mode: confirm
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Mastermind Workspace Detail
|
|
9
|
+
|
|
10
|
+
This skill is invoked by `mastermind:workspace-detail` or directly via `/mastermind:workspace-detail`.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Inputs
|
|
15
|
+
|
|
16
|
+
- `brain_context`: BRAIN CONTEXT block (injected by command, or loaded below if standalone)
|
|
17
|
+
- `org_name`: org the workspace belongs to (required)
|
|
18
|
+
- `workspace_id`: execution workspace id (required)
|
|
19
|
+
- `action`: show | services | provision | teardown | cleanup | runtime-logs | issues | routines | config
|
|
20
|
+
- `provision_command`: shell command to provision the workspace (for config action)
|
|
21
|
+
- `teardown_command`: shell command to tear down the workspace (for config action)
|
|
22
|
+
- `cleanup_command`: shell command for workspace cleanup (for config action)
|
|
23
|
+
- `cwd`: working directory override (for config action)
|
|
24
|
+
- `repo_url`: repository URL (for config action)
|
|
25
|
+
- `base_ref`: git base ref/branch (for config action)
|
|
26
|
+
- `branch_name`: branch name for the workspace (for config action)
|
|
27
|
+
- `log_lines`: number of runtime log lines to show (default 50)
|
|
28
|
+
- `caller`: command | master
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Workspace Tabs (mirrors ExecutionWorkspaceDetail.tsx)
|
|
33
|
+
|
|
34
|
+
| Tab | Description |
|
|
35
|
+
|-----|-------------|
|
|
36
|
+
| `services` | Running service processes in this workspace |
|
|
37
|
+
| `configuration` | Provision/teardown/cleanup commands, repo, branch, cwd |
|
|
38
|
+
| `runtime_logs` | Live or recent runtime logs from workspace processes |
|
|
39
|
+
| `issues` | Issues currently assigned to or running in this workspace |
|
|
40
|
+
| `routines` | Routines with workspace-specific variable bindings |
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Step 0 — Brain Load (standalone only)
|
|
45
|
+
|
|
46
|
+
If `caller` is not "command", load brain context following _protocol.md Brain Load Procedure with namespace: `ops`.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Step 1 — Load Workspace Data
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
orgFile=".monomind/orgs/${org_name}.json"
|
|
54
|
+
[ ! -f "$orgFile" ] && { echo "ERROR: Org '${org_name}' not found."; exit 1; }
|
|
55
|
+
|
|
56
|
+
wsFile=".monomind/orgs/${org_name}-workspaces.json"
|
|
57
|
+
[ ! -f "$wsFile" ] && { echo "ERROR: No workspaces file for org '$org_name'. Create workspaces via /mastermind:workspaces."; exit 1; }
|
|
58
|
+
|
|
59
|
+
wsDef=$(jq -r --arg id "$workspace_id" '.workspaces[] | select(.id == $id)' "$wsFile")
|
|
60
|
+
[ -z "$wsDef" ] && { echo "ERROR: Workspace '$workspace_id' not found in org '$org_name'."; exit 1; }
|
|
61
|
+
|
|
62
|
+
issuesFile=".monomind/orgs/${org_name}-issues.json"
|
|
63
|
+
routinesFile=".monomind/orgs/${org_name}-routines.json"
|
|
64
|
+
logFile=".monomind/orgs/${org_name}-workspace-logs/${workspace_id}.log"
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Step 2 — Execute Action
|
|
70
|
+
|
|
71
|
+
### show (default)
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
echo "EXECUTION WORKSPACE — $workspace_id @ $org_name"
|
|
75
|
+
echo "────────────────────────────────────────────────────────"
|
|
76
|
+
|
|
77
|
+
echo "$wsDef" | jq -r '
|
|
78
|
+
" ID: \(.id)",
|
|
79
|
+
" Project: \(.project_id // "(none)")",
|
|
80
|
+
" Agent: \(.agent_id // "(unassigned)")",
|
|
81
|
+
" Status: \(.status // "unknown")",
|
|
82
|
+
" Branch: \(.branch // "?")",
|
|
83
|
+
" Base ref: \(.base_ref // "?")",
|
|
84
|
+
" Repo URL: \(.repo_url // "(local)")",
|
|
85
|
+
" CWD: \(.cwd // .worktree_path // "(none)")",
|
|
86
|
+
" Created: \(.createdAt // "-")",
|
|
87
|
+
" Last active: \(.lastActiveAt // "-")"
|
|
88
|
+
'
|
|
89
|
+
|
|
90
|
+
# Services
|
|
91
|
+
svcCount=$(echo "$wsDef" | jq -r '(.services // []) | length')
|
|
92
|
+
echo ""
|
|
93
|
+
echo " Services running: $svcCount"
|
|
94
|
+
echo "$wsDef" | jq -r '(.services // [])[] | " · \(.)"'
|
|
95
|
+
|
|
96
|
+
# Config summary
|
|
97
|
+
hasProvision=$(echo "$wsDef" | jq -r 'if .config.provisionCommand then "yes" else "no" end')
|
|
98
|
+
hasTeardown=$(echo "$wsDef" | jq -r 'if .config.teardownCommand then "yes" else "no" end')
|
|
99
|
+
echo ""
|
|
100
|
+
echo " Provision cmd: $hasProvision"
|
|
101
|
+
echo " Teardown cmd: $hasTeardown"
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### services
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
echo "SERVICES — $workspace_id"
|
|
108
|
+
echo "────────────────────────────────────────────────────────"
|
|
109
|
+
|
|
110
|
+
services=$(echo "$wsDef" | jq -r '(.services // [])[]')
|
|
111
|
+
if [ -z "$services" ]; then
|
|
112
|
+
echo " No services running."
|
|
113
|
+
else
|
|
114
|
+
echo "$wsDef" | jq -r '.services // [] | to_entries[] |
|
|
115
|
+
" [\(.key)] \(.value)"' 2>/dev/null || \
|
|
116
|
+
echo "$wsDef" | jq -r '(.services // [])[] | " · \(.)"'
|
|
117
|
+
fi
|
|
118
|
+
|
|
119
|
+
echo ""
|
|
120
|
+
echo " Workspace path: $(echo "$wsDef" | jq -r '.worktree_path // "(none)"')"
|
|
121
|
+
echo " Status: $(echo "$wsDef" | jq -r '.status // "unknown"')"
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### provision
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
echo "PROVISION — $workspace_id"
|
|
128
|
+
echo "────────────────────────────────────────────────────────"
|
|
129
|
+
|
|
130
|
+
provCmd=$(echo "$wsDef" | jq -r '.config.provisionCommand // ""')
|
|
131
|
+
wsPath=$(echo "$wsDef" | jq -r '.worktree_path // .cwd // ""')
|
|
132
|
+
|
|
133
|
+
if [ -z "$provCmd" ]; then
|
|
134
|
+
echo " No provision command configured."
|
|
135
|
+
echo " Set one: --action config --provision-command 'npm install && npm run build'"
|
|
136
|
+
else
|
|
137
|
+
echo " Command: $provCmd"
|
|
138
|
+
echo " CWD: $wsPath"
|
|
139
|
+
echo ""
|
|
140
|
+
echo " To run: cd '$wsPath' && $provCmd"
|
|
141
|
+
echo ""
|
|
142
|
+
if [ -d "$wsPath" ] && [ -n "$provCmd" ]; then
|
|
143
|
+
echo " Executing provision command…"
|
|
144
|
+
(cd "$wsPath" && eval "$provCmd") && {
|
|
145
|
+
ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
146
|
+
tmp="${wsFile}.tmp"
|
|
147
|
+
jq --arg id "$workspace_id" --arg ts "$ts" \
|
|
148
|
+
'.workspaces = [.workspaces[] | if .id == $id then .last_provisioned = $ts else . end]' \
|
|
149
|
+
"$wsFile" > "$tmp" && mv "$tmp" "$wsFile"
|
|
150
|
+
echo " Provision complete."
|
|
151
|
+
} || echo " Provision command exited with error."
|
|
152
|
+
else
|
|
153
|
+
[ -z "$wsPath" ] && echo " ERROR: No worktree_path set — cannot execute provision command automatically."
|
|
154
|
+
fi
|
|
155
|
+
fi
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### teardown
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
echo "TEARDOWN — $workspace_id"
|
|
162
|
+
echo "────────────────────────────────────────────────────────"
|
|
163
|
+
|
|
164
|
+
tdCmd=$(echo "$wsDef" | jq -r '.config.teardownCommand // ""')
|
|
165
|
+
wsPath=$(echo "$wsDef" | jq -r '.worktree_path // .cwd // ""')
|
|
166
|
+
|
|
167
|
+
if [ -z "$tdCmd" ]; then
|
|
168
|
+
echo " No teardown command configured."
|
|
169
|
+
else
|
|
170
|
+
echo " Command: $tdCmd"
|
|
171
|
+
echo " CWD: $wsPath"
|
|
172
|
+
if [ -d "$wsPath" ]; then
|
|
173
|
+
echo " Executing teardown command…"
|
|
174
|
+
(cd "$wsPath" && eval "$tdCmd") && echo " Teardown complete." || echo " Teardown command exited with error."
|
|
175
|
+
fi
|
|
176
|
+
fi
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### cleanup
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
echo "CLEANUP — $workspace_id"
|
|
183
|
+
echo "────────────────────────────────────────────────────────"
|
|
184
|
+
|
|
185
|
+
cleanCmd=$(echo "$wsDef" | jq -r '.config.cleanupCommand // ""')
|
|
186
|
+
wsPath=$(echo "$wsDef" | jq -r '.worktree_path // .cwd // ""')
|
|
187
|
+
|
|
188
|
+
if [ -z "$cleanCmd" ]; then
|
|
189
|
+
echo " No cleanup command configured."
|
|
190
|
+
else
|
|
191
|
+
echo " Command: $cleanCmd"
|
|
192
|
+
if [ -d "$wsPath" ]; then
|
|
193
|
+
(cd "$wsPath" && eval "$cleanCmd") && echo " Cleanup complete." || echo " Cleanup exited with error."
|
|
194
|
+
fi
|
|
195
|
+
fi
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### runtime-logs
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
lines=${log_lines:-50}
|
|
202
|
+
echo "RUNTIME LOGS — $workspace_id (last $lines lines)"
|
|
203
|
+
echo "────────────────────────────────────────────────────────"
|
|
204
|
+
|
|
205
|
+
if [ -f "$logFile" ]; then
|
|
206
|
+
tail -${lines} "$logFile"
|
|
207
|
+
else
|
|
208
|
+
# Try workspace path stderr/stdout logs
|
|
209
|
+
wsPath=$(echo "$wsDef" | jq -r '.worktree_path // ""')
|
|
210
|
+
found=false
|
|
211
|
+
for logPath in "${wsPath}/.monomind/runtime.log" "${wsPath}/logs/runtime.log" "${wsPath}/output.log"; do
|
|
212
|
+
if [ -f "$logPath" ]; then
|
|
213
|
+
tail -${lines} "$logPath"
|
|
214
|
+
found=true
|
|
215
|
+
break
|
|
216
|
+
fi
|
|
217
|
+
done
|
|
218
|
+
"$found" || echo " No runtime logs found. Logs are written to .monomind/workspace-logs/$workspace_id.log during runs."
|
|
219
|
+
fi
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### issues
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
echo "ISSUES — workspace: $workspace_id"
|
|
226
|
+
echo "────────────────────────────────────────────────────────"
|
|
227
|
+
printf "%-24s %-12s %-10s %s\n" "ID" "STATUS" "PRIORITY" "TITLE"
|
|
228
|
+
echo "────────────────────────────────────────────────────────"
|
|
229
|
+
|
|
230
|
+
if [ ! -f "$issuesFile" ]; then
|
|
231
|
+
echo " No issues file found."
|
|
232
|
+
else
|
|
233
|
+
jq -r --arg wid "$workspace_id" '.issues[] |
|
|
234
|
+
select(.workspace_id == $wid or (.assigned_workspace == $wid)) |
|
|
235
|
+
[.id, (.status // "open"), (.priority // "medium"), (.title // "(no title)")] | @tsv' \
|
|
236
|
+
"$issuesFile" | while IFS=$'\t' read -r id st pri title; do
|
|
237
|
+
printf "%-24s %-12s %-10s %s\n" "$id" "$st" "$pri" "$title"
|
|
238
|
+
done || echo " No issues assigned to this workspace."
|
|
239
|
+
fi
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### routines
|
|
243
|
+
|
|
244
|
+
```bash
|
|
245
|
+
echo "ROUTINES — workspace: $workspace_id"
|
|
246
|
+
echo "────────────────────────────────────────────────────────"
|
|
247
|
+
|
|
248
|
+
if [ ! -f "$routinesFile" ]; then
|
|
249
|
+
echo " No routines file found."
|
|
250
|
+
else
|
|
251
|
+
# Show routines that have workspace-specific variable bindings
|
|
252
|
+
jq -r --arg wid "$workspace_id" \
|
|
253
|
+
'.routines[] | select((.variables // {}) | to_entries[] | .key | startswith("WS_") or contains("workspace")) |
|
|
254
|
+
"\(.id) \(.name // "(no name)") vars: \((.variables // {}) | keys | join(", "))"' \
|
|
255
|
+
"$routinesFile" 2>/dev/null || echo " No routines with workspace-specific variables."
|
|
256
|
+
fi
|
|
257
|
+
|
|
258
|
+
echo ""
|
|
259
|
+
echo "To run a routine with workspace vars: /mastermind:routine-detail --org $org_name --routine-id <id> --action variables"
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### config
|
|
263
|
+
|
|
264
|
+
```bash
|
|
265
|
+
echo "WORKSPACE CONFIG — $workspace_id"
|
|
266
|
+
echo "────────────────────────────────────────────────────────"
|
|
267
|
+
|
|
268
|
+
if [ -n "$provision_command" ] || [ -n "$teardown_command" ] || [ -n "$cleanup_command" ] || \
|
|
269
|
+
[ -n "$cwd" ] || [ -n "$repo_url" ] || [ -n "$base_ref" ] || [ -n "$branch_name" ]; then
|
|
270
|
+
|
|
271
|
+
ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
272
|
+
tmp="${wsFile}.tmp"
|
|
273
|
+
jq --arg id "$workspace_id" \
|
|
274
|
+
--arg prov "${provision_command:-}" \
|
|
275
|
+
--arg td "${teardown_command:-}" \
|
|
276
|
+
--arg clean "${cleanup_command:-}" \
|
|
277
|
+
--arg cwd_ "${cwd:-}" \
|
|
278
|
+
--arg repo "${repo_url:-}" \
|
|
279
|
+
--arg base "${base_ref:-}" \
|
|
280
|
+
--arg branch "${branch_name:-}" \
|
|
281
|
+
--arg ts "$ts" \
|
|
282
|
+
'.workspaces = [.workspaces[] | if .id == $id then
|
|
283
|
+
if .config == null then .config = {} else . end |
|
|
284
|
+
(if $prov != "" then .config.provisionCommand = $prov else . end) |
|
|
285
|
+
(if $td != "" then .config.teardownCommand = $td else . end) |
|
|
286
|
+
(if $clean != "" then .config.cleanupCommand = $clean else . end) |
|
|
287
|
+
(if $cwd_ != "" then .cwd = $cwd_ else . end) |
|
|
288
|
+
(if $repo != "" then .repo_url = $repo else . end) |
|
|
289
|
+
(if $base != "" then .base_ref = $base else . end) |
|
|
290
|
+
(if $branch != "" then .branch = $branch else . end) |
|
|
291
|
+
.lastActiveAt = $ts
|
|
292
|
+
else . end]' \
|
|
293
|
+
"$wsFile" > "$tmp" && mv "$tmp" "$wsFile"
|
|
294
|
+
echo "Config updated for workspace '$workspace_id'."
|
|
295
|
+
else
|
|
296
|
+
echo "$wsDef" | jq '{id, project_id, agent_id, status, branch, base_ref, repo_url, cwd, config}'
|
|
297
|
+
fi
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
---
|
|
301
|
+
|
|
302
|
+
## Step 3 — Return Output
|
|
303
|
+
|
|
304
|
+
```yaml
|
|
305
|
+
domain: ops
|
|
306
|
+
status: complete
|
|
307
|
+
action: <action>
|
|
308
|
+
org: <org_name>
|
|
309
|
+
workspace_id: <workspace_id>
|
|
310
|
+
workspace_status: <status>
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
---
|
|
314
|
+
|
|
315
|
+
## Step 4 — Brain Write (standalone only)
|
|
316
|
+
|
|
317
|
+
If `caller` is not "command", follow _protocol.md Brain Write Procedure for domain `ops`.
|