@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,291 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mastermind-issue-detail
|
|
3
|
+
description: Mastermind issue-detail — deep per-issue/task inspection and management. Show thread summary, run history, comments, sub-issues, file attachments, assign, close, and recovery actions for a single task within an org.
|
|
4
|
+
type: domain-skill
|
|
5
|
+
default_mode: auto
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Mastermind Issue Detail
|
|
9
|
+
|
|
10
|
+
This skill is invoked by `mastermind:issue-detail` or directly via `/mastermind:issue-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 issue belongs to (required)
|
|
18
|
+
- `issue_id`: issue id/slug (required)
|
|
19
|
+
- `action`: show | thread | runs | sub-issues | attachments | comment | assign | close | reopen | recover
|
|
20
|
+
- `comment_body`: comment text (required for comment action)
|
|
21
|
+
- `assignee_id`: agent id to assign (required for assign action)
|
|
22
|
+
- `recovery_action`: accept | reject (for recover action)
|
|
23
|
+
- `days`: lookback window for run history (default 14)
|
|
24
|
+
- `caller`: command | master
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Issue Status Flow
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
open → in_progress → done
|
|
32
|
+
↓
|
|
33
|
+
blocked → in_progress
|
|
34
|
+
↓
|
|
35
|
+
cancelled
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Recovery actions apply when an issue enters `needs_recovery` state after a failed run.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Step 0 — Brain Load (standalone only)
|
|
43
|
+
|
|
44
|
+
If `caller` is not "command", load brain context following _protocol.md Brain Load Procedure with namespace: `ops`.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Step 1 — Load Issue Data
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
orgFile=".monomind/orgs/${org_name}.json"
|
|
52
|
+
[ ! -f "$orgFile" ] && { echo "ERROR: Org '${org_name}' not found."; exit 1; }
|
|
53
|
+
|
|
54
|
+
issuesFile=".monomind/orgs/${org_name}-issues.json"
|
|
55
|
+
[ ! -f "$issuesFile" ] && { echo "ERROR: No issues file for org '$org_name'. Create tasks via /mastermind:tasks."; exit 1; }
|
|
56
|
+
|
|
57
|
+
issueDef=$(jq -r --arg id "$issue_id" '.issues[] | select(.id == $id or .slug == $id)' "$issuesFile")
|
|
58
|
+
[ -z "$issueDef" ] && { echo "ERROR: Issue '$issue_id' not found in org '$org_name'."; exit 1; }
|
|
59
|
+
|
|
60
|
+
resolvedId=$(echo "$issueDef" | jq -r '.id')
|
|
61
|
+
activityFile=".monomind/orgs/${org_name}-activity.jsonl"
|
|
62
|
+
threadFile=".monomind/orgs/${org_name}-threads.jsonl"
|
|
63
|
+
days=${days:-14}
|
|
64
|
+
cutoff=$(date -u -v-${days}d +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -u -d "${days} days ago" +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || echo "")
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Step 2 — Execute Action
|
|
70
|
+
|
|
71
|
+
### show (default)
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
echo "ISSUE DETAIL — $issue_id @ $org_name"
|
|
75
|
+
echo "────────────────────────────────────────────────────────"
|
|
76
|
+
|
|
77
|
+
echo "$issueDef" | jq -r '
|
|
78
|
+
" ID: \(.id)",
|
|
79
|
+
" Title: \(.title // "(no title)")",
|
|
80
|
+
" Status: \(.status // "open")",
|
|
81
|
+
" Priority: \(.priority // "medium")",
|
|
82
|
+
" Assignee: \(.assignee_id // "(unassigned)")",
|
|
83
|
+
" Project: \(.project_id // "(none)")",
|
|
84
|
+
" Created: \(.created_at // "-")",
|
|
85
|
+
" Updated: \(.updated_at // "-")"
|
|
86
|
+
'
|
|
87
|
+
|
|
88
|
+
# Sub-issues
|
|
89
|
+
subCount=$(jq --arg pid "$resolvedId" '[.issues[] | select(.parent_id == $pid)] | length' "$issuesFile" 2>/dev/null || echo 0)
|
|
90
|
+
echo " Sub-issues: $subCount"
|
|
91
|
+
|
|
92
|
+
# Attachments
|
|
93
|
+
attCount=$(echo "$issueDef" | jq -r '(.attachments // []) | length')
|
|
94
|
+
echo " Attachments: $attCount"
|
|
95
|
+
|
|
96
|
+
# Recovery
|
|
97
|
+
recoveryStatus=$(echo "$issueDef" | jq -r '.recovery_status // "none"')
|
|
98
|
+
[ "$recoveryStatus" != "none" ] && echo "" && echo " RECOVERY STATUS: $recoveryStatus"
|
|
99
|
+
|
|
100
|
+
# Description
|
|
101
|
+
desc=$(echo "$issueDef" | jq -r '.description // ""')
|
|
102
|
+
if [ -n "$desc" ]; then
|
|
103
|
+
echo ""
|
|
104
|
+
echo "DESCRIPTION"
|
|
105
|
+
echo "────────────────────────────────────────────────────────"
|
|
106
|
+
echo "$desc" | head -10
|
|
107
|
+
fi
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### thread
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
echo "THREAD — $issue_id"
|
|
114
|
+
echo "────────────────────────────────────────────────────────"
|
|
115
|
+
|
|
116
|
+
found=0
|
|
117
|
+
if [ -f "$threadFile" ]; then
|
|
118
|
+
while IFS= read -r line; do
|
|
119
|
+
iid=$(echo "$line" | jq -r '.issue_id // ""')
|
|
120
|
+
[ "$iid" != "$resolvedId" ] && continue
|
|
121
|
+
ts=$(echo "$line" | jq -r '.ts // ""')
|
|
122
|
+
role=$(echo "$line" | jq -r '.role // "agent"')
|
|
123
|
+
body=$(echo "$line" | jq -r '.body // ""' | head -3)
|
|
124
|
+
msgType=$(echo "$line" | jq -r '.type // "message"')
|
|
125
|
+
printf "\n [%s] %-10s (%s)\n" "$ts" "$role" "$msgType"
|
|
126
|
+
echo "$body" | while IFS= read -r l; do echo " $l"; done
|
|
127
|
+
found=$((found + 1))
|
|
128
|
+
done < "$threadFile"
|
|
129
|
+
fi
|
|
130
|
+
|
|
131
|
+
[ "$found" -eq 0 ] && echo " No thread messages for this issue."
|
|
132
|
+
echo ""
|
|
133
|
+
echo " $found message(s). To add a comment: --action comment --comment-body '...'"
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### runs
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
echo "RUN HISTORY — $issue_id (last ${days} days)"
|
|
140
|
+
echo "────────────────────────────────────────────────────────"
|
|
141
|
+
printf "%-26s %-12s %-8s %-14s %s\n" "TIMESTAMP" "STATUS" "TOKENS" "AGENT" "SUMMARY"
|
|
142
|
+
echo "────────────────────────────────────────────────────────"
|
|
143
|
+
|
|
144
|
+
found=0
|
|
145
|
+
if [ -f "$activityFile" ]; then
|
|
146
|
+
while IFS= read -r line; do
|
|
147
|
+
iid=$(echo "$line" | jq -r '.issue_id // ""')
|
|
148
|
+
[ "$iid" != "$resolvedId" ] && continue
|
|
149
|
+
ts=$(echo "$line" | jq -r '.ts // ""')
|
|
150
|
+
[ -n "$cutoff" ] && [ "$ts" \< "$cutoff" ] && continue
|
|
151
|
+
st=$(echo "$line" | jq -r '.status // "-"')
|
|
152
|
+
tok=$(echo "$line" | jq -r '.tokens // "-"')
|
|
153
|
+
ag=$(echo "$line" | jq -r '.agent // "-"')
|
|
154
|
+
summary=$(echo "$line" | jq -r '.summary // .type // "-"' | cut -c1-30)
|
|
155
|
+
printf "%-26s %-12s %-8s %-14s %s\n" "$ts" "$st" "$tok" "$ag" "$summary"
|
|
156
|
+
found=$((found + 1))
|
|
157
|
+
done < "$activityFile"
|
|
158
|
+
fi
|
|
159
|
+
|
|
160
|
+
[ "$found" -eq 0 ] && echo " No runs found in the last $days days."
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### sub-issues
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
echo "SUB-ISSUES — $issue_id"
|
|
167
|
+
echo "────────────────────────────────────────────────────────"
|
|
168
|
+
printf "%-24s %-12s %-10s %s\n" "ID" "STATUS" "PRIORITY" "TITLE"
|
|
169
|
+
echo "────────────────────────────────────────────────────────"
|
|
170
|
+
|
|
171
|
+
count=0
|
|
172
|
+
jq -r --arg pid "$resolvedId" '.issues[] | select(.parent_id == $pid) |
|
|
173
|
+
[.id, (.status // "open"), (.priority // "medium"), (.title // "(no title)")] | @tsv' \
|
|
174
|
+
"$issuesFile" 2>/dev/null | while IFS=$'\t' read -r id st pri title; do
|
|
175
|
+
printf "%-24s %-12s %-10s %s\n" "$id" "$st" "$pri" "$title"
|
|
176
|
+
count=$((count + 1))
|
|
177
|
+
done
|
|
178
|
+
|
|
179
|
+
echo ""
|
|
180
|
+
echo "To create a sub-issue: /mastermind:tasks --org $org_name --action create --parent-id $issue_id"
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### attachments
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
echo "ATTACHMENTS — $issue_id"
|
|
187
|
+
echo "────────────────────────────────────────────────────────"
|
|
188
|
+
atts=$(echo "$issueDef" | jq -r '(.attachments // [])[]' 2>/dev/null)
|
|
189
|
+
if [ -z "$atts" ]; then
|
|
190
|
+
echo " No attachments."
|
|
191
|
+
else
|
|
192
|
+
echo "$issueDef" | jq -r '(.attachments // [])[] |
|
|
193
|
+
" [\(.type // "file")] \(.name // .path // "unnamed") — \(.size_bytes // "?") bytes — added \(.added_at // "?")"'
|
|
194
|
+
fi
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### comment
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
[ -z "$comment_body" ] && { echo "ERROR: --comment-body required."; exit 1; }
|
|
201
|
+
ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
202
|
+
|
|
203
|
+
entry=$(jq -cn --arg iid "$resolvedId" --arg body "$comment_body" --arg ts "$ts" \
|
|
204
|
+
'{"issue_id":$iid,"role":"user","type":"comment","body":$body,"ts":$ts}')
|
|
205
|
+
echo "$entry" >> "$threadFile"
|
|
206
|
+
|
|
207
|
+
echo "Comment added to issue '$issue_id'."
|
|
208
|
+
echo " Body: $comment_body"
|
|
209
|
+
echo " Time: $ts"
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### assign
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
[ -z "$assignee_id" ] && { echo "ERROR: --assignee-id required."; exit 1; }
|
|
216
|
+
|
|
217
|
+
# Validate agent exists in org
|
|
218
|
+
exists=$(jq --arg id "$assignee_id" '[.roles[] | select(.id == $id)] | length' "$orgFile")
|
|
219
|
+
[ "$exists" -eq 0 ] && echo "WARNING: Agent '$assignee_id' not found in org '$org_name'. Assigning anyway."
|
|
220
|
+
|
|
221
|
+
ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
222
|
+
tmp="${issuesFile}.tmp"
|
|
223
|
+
jq --arg id "$resolvedId" --arg ag "$assignee_id" --arg ts "$ts" \
|
|
224
|
+
'.issues = [.issues[] | if .id == $id then .assignee_id = $ag | .updated_at = $ts else . end]' \
|
|
225
|
+
"$issuesFile" > "$tmp" && mv "$tmp" "$issuesFile"
|
|
226
|
+
|
|
227
|
+
echo "Issue '$issue_id' assigned to '$assignee_id'."
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### close
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
234
|
+
tmp="${issuesFile}.tmp"
|
|
235
|
+
jq --arg id "$resolvedId" --arg ts "$ts" \
|
|
236
|
+
'.issues = [.issues[] | if .id == $id then .status = "done" | .updated_at = $ts | .closed_at = $ts else . end]' \
|
|
237
|
+
"$issuesFile" > "$tmp" && mv "$tmp" "$issuesFile"
|
|
238
|
+
echo "Issue '$issue_id' → done (closed at $ts)."
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### reopen
|
|
242
|
+
|
|
243
|
+
```bash
|
|
244
|
+
ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
245
|
+
tmp="${issuesFile}.tmp"
|
|
246
|
+
jq --arg id "$resolvedId" --arg ts "$ts" \
|
|
247
|
+
'.issues = [.issues[] | if .id == $id then .status = "open" | .updated_at = $ts | .closed_at = null else . end]' \
|
|
248
|
+
"$issuesFile" > "$tmp" && mv "$tmp" "$issuesFile"
|
|
249
|
+
echo "Issue '$issue_id' → reopened."
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### recover
|
|
253
|
+
|
|
254
|
+
```bash
|
|
255
|
+
[ -z "$recovery_action" ] && { echo "ERROR: --recovery-action required (accept|reject)."; exit 1; }
|
|
256
|
+
case "$recovery_action" in accept|reject) : ;; *)
|
|
257
|
+
echo "ERROR: --recovery-action must be 'accept' or 'reject'."; exit 1 ;;
|
|
258
|
+
esac
|
|
259
|
+
|
|
260
|
+
ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
261
|
+
newStatus=$([ "$recovery_action" = "accept" ] && echo "in_progress" || echo "cancelled")
|
|
262
|
+
|
|
263
|
+
tmp="${issuesFile}.tmp"
|
|
264
|
+
jq --arg id "$resolvedId" --arg st "$newStatus" --arg ts "$ts" --arg ra "$recovery_action" \
|
|
265
|
+
'.issues = [.issues[] | if .id == $id then
|
|
266
|
+
.status = $st | .recovery_status = $ra | .updated_at = $ts
|
|
267
|
+
else . end]' \
|
|
268
|
+
"$issuesFile" > "$tmp" && mv "$tmp" "$issuesFile"
|
|
269
|
+
|
|
270
|
+
echo "Recovery action '$recovery_action' applied to '$issue_id'."
|
|
271
|
+
echo " New status: $newStatus"
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
## Step 3 — Return Output
|
|
277
|
+
|
|
278
|
+
```yaml
|
|
279
|
+
domain: ops
|
|
280
|
+
status: complete
|
|
281
|
+
action: <action>
|
|
282
|
+
org: <org_name>
|
|
283
|
+
issue_id: <issue_id>
|
|
284
|
+
issue_status: <status>
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
## Step 4 — Brain Write (standalone only)
|
|
290
|
+
|
|
291
|
+
If `caller` is not "command", follow _protocol.md Brain Write Procedure for domain `ops`.
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mastermind-issues
|
|
3
|
+
description: Mastermind issues — list, create, update, and close org-level issues (tasks/tickets) with search, assignee, status, and workspace filters. Mirrors Issues.tsx. For personal assigned issues use mastermind:my-issues; for issue detail use mastermind:issue-detail.
|
|
4
|
+
type: domain-skill
|
|
5
|
+
default_mode: auto
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Mastermind Issues
|
|
9
|
+
|
|
10
|
+
This skill is invoked by `mastermind:issues` or directly via `/mastermind:issues`.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Inputs
|
|
15
|
+
|
|
16
|
+
- `brain_context`: BRAIN CONTEXT block (injected by command, or loaded below if standalone)
|
|
17
|
+
- `org_name`: org to query (required)
|
|
18
|
+
- `action`: list | create | update | close | search
|
|
19
|
+
- `issue_id`: issue ID (required for update/close)
|
|
20
|
+
- `query`: search term (for search)
|
|
21
|
+
- `status`: open | in_progress | in_review | done | cancelled (filter)
|
|
22
|
+
- `assignee`: agent ID filter
|
|
23
|
+
- `workspace`: workspace ID filter
|
|
24
|
+
- `title`: issue title (for create)
|
|
25
|
+
- `description`: issue body (for create)
|
|
26
|
+
- `priority`: low | medium | high | urgent (for create/update)
|
|
27
|
+
- `limit`: max results (default: 50)
|
|
28
|
+
- `caller`: command | master
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Step 0 — Brain Load (standalone only)
|
|
33
|
+
|
|
34
|
+
If `caller` is not "command", load brain context following _protocol.md Brain Load Procedure with namespace: `ops`.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Step 1 — Load Issues File
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
orgFile=".monomind/orgs/${org_name}.json"
|
|
42
|
+
[ ! -f "$orgFile" ] && { echo "ERROR: Org '${org_name}' not found."; exit 1; }
|
|
43
|
+
|
|
44
|
+
issuesFile=".monomind/orgs/${org_name}-issues.json"
|
|
45
|
+
[ ! -f "$issuesFile" ] && echo '{"issues":[]}' > "$issuesFile"
|
|
46
|
+
|
|
47
|
+
limit="${limit:-50}"
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Step 2 — Execute Action
|
|
53
|
+
|
|
54
|
+
### list (default)
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
echo "ISSUES — $org_name"
|
|
58
|
+
echo "────────────────────────────────────────────────────────"
|
|
59
|
+
|
|
60
|
+
python3 - "$issuesFile" "${status:-}" "${assignee:-}" "${workspace:-}" "$limit" <<'PYEOF'
|
|
61
|
+
import json, sys
|
|
62
|
+
data = json.load(open(sys.argv[1]))
|
|
63
|
+
status_f = sys.argv[2]
|
|
64
|
+
assignee_f = sys.argv[3]
|
|
65
|
+
workspace_f = sys.argv[4]
|
|
66
|
+
limit = int(sys.argv[5])
|
|
67
|
+
|
|
68
|
+
issues = data.get("issues", [])
|
|
69
|
+
if status_f:
|
|
70
|
+
issues = [i for i in issues if i.get("status") == status_f]
|
|
71
|
+
if assignee_f:
|
|
72
|
+
issues = [i for i in issues if i.get("assigneeId") == assignee_f]
|
|
73
|
+
if workspace_f:
|
|
74
|
+
issues = [i for i in issues if i.get("workspaceId") == workspace_f]
|
|
75
|
+
|
|
76
|
+
issues = issues[:limit]
|
|
77
|
+
|
|
78
|
+
if not issues:
|
|
79
|
+
print(" (no issues match filters)")
|
|
80
|
+
else:
|
|
81
|
+
print(f" {'ID':<28} {'STATUS':<14} {'PRI':<8} {'TITLE':<38} ASSIGNEE")
|
|
82
|
+
print(" " + "─" * 102)
|
|
83
|
+
for iss in issues:
|
|
84
|
+
iid = iss.get("id","?")[:28]
|
|
85
|
+
st = iss.get("status","open")[:14]
|
|
86
|
+
pri = iss.get("priority","medium")[:8]
|
|
87
|
+
title = (iss.get("title") or "-")[:38]
|
|
88
|
+
asgn = (iss.get("assigneeTitle") or iss.get("assigneeId") or "—")[:20]
|
|
89
|
+
print(f" {iid:<28} {st:<14} {pri:<8} {title:<38} {asgn}")
|
|
90
|
+
|
|
91
|
+
print(f"\n Showing {len(issues)} issue(s).")
|
|
92
|
+
PYEOF
|
|
93
|
+
|
|
94
|
+
echo ""
|
|
95
|
+
echo " Create: /mastermind:issues --org $org_name --action create --title 'My Issue'"
|
|
96
|
+
echo " Detail: /mastermind:issue-detail --org $org_name --issue-id <id>"
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### search
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
[ -z "$query" ] && { echo "ERROR: --query required."; exit 1; }
|
|
103
|
+
|
|
104
|
+
q=$(echo "$query" | tr '[:upper:]' '[:lower:]')
|
|
105
|
+
|
|
106
|
+
echo "ISSUE SEARCH — $org_name query: '$query'"
|
|
107
|
+
echo "────────────────────────────────────────────────────────"
|
|
108
|
+
|
|
109
|
+
python3 - "$issuesFile" "$q" "$limit" <<'PYEOF'
|
|
110
|
+
import json, sys
|
|
111
|
+
data = json.load(open(sys.argv[1]))
|
|
112
|
+
q = sys.argv[2]
|
|
113
|
+
limit = int(sys.argv[3])
|
|
114
|
+
|
|
115
|
+
issues = data.get("issues", [])
|
|
116
|
+
matched = [i for i in issues
|
|
117
|
+
if q in (i.get("title") or "").lower()
|
|
118
|
+
or q in (i.get("description") or "").lower()
|
|
119
|
+
or q in (i.get("id") or "").lower()][:limit]
|
|
120
|
+
|
|
121
|
+
if not matched:
|
|
122
|
+
print(f" (no issues match '{q}')")
|
|
123
|
+
else:
|
|
124
|
+
for iss in matched:
|
|
125
|
+
iid = iss.get("id","?")
|
|
126
|
+
title = iss.get("title","-")
|
|
127
|
+
st = iss.get("status","?")
|
|
128
|
+
print(f" [{st}] {iid} {title}")
|
|
129
|
+
|
|
130
|
+
print(f"\n {len(matched)} match(es).")
|
|
131
|
+
PYEOF
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### create
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
[ -z "$title" ] && { echo "ERROR: --title required."; exit 1; }
|
|
138
|
+
|
|
139
|
+
ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
140
|
+
newId="issue-$(python3 -c 'import time; print(int(time.time()*1000))')"
|
|
141
|
+
|
|
142
|
+
python3 - "$issuesFile" "$newId" "$title" "${description:-}" "${priority:-medium}" "${assignee:-}" "${workspace:-}" "$ts" <<'PYEOF'
|
|
143
|
+
import json, sys
|
|
144
|
+
path, iid, title, desc, pri, asgn, ws, ts = sys.argv[1:]
|
|
145
|
+
data = json.load(open(path))
|
|
146
|
+
issue = {
|
|
147
|
+
"id": iid, "title": title, "description": desc,
|
|
148
|
+
"status": "open", "priority": pri,
|
|
149
|
+
"assigneeId": asgn or None, "workspaceId": ws or None,
|
|
150
|
+
"createdAt": ts, "updatedAt": ts
|
|
151
|
+
}
|
|
152
|
+
data.setdefault("issues", []).append(issue)
|
|
153
|
+
with open(path, "w") as f:
|
|
154
|
+
json.dump(data, f, indent=2)
|
|
155
|
+
print(f" Created: {iid}")
|
|
156
|
+
print(f" Title: {title}")
|
|
157
|
+
print(f" Status: open | Priority: {pri}")
|
|
158
|
+
PYEOF
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### update
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
[ -z "$issue_id" ] && { echo "ERROR: --issue-id required."; exit 1; }
|
|
165
|
+
ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
166
|
+
|
|
167
|
+
python3 - "$issuesFile" "$issue_id" "${status:-}" "${priority:-}" "${title:-}" "$ts" <<'PYEOF'
|
|
168
|
+
import json, sys
|
|
169
|
+
path, iid, new_st, new_pri, new_title, ts = sys.argv[1:]
|
|
170
|
+
data = json.load(open(path))
|
|
171
|
+
issues = data.get("issues", [])
|
|
172
|
+
found = False
|
|
173
|
+
for iss in issues:
|
|
174
|
+
if iss.get("id") == iid:
|
|
175
|
+
if new_st: iss["status"] = new_st
|
|
176
|
+
if new_pri: iss["priority"] = new_pri
|
|
177
|
+
if new_title: iss["title"] = new_title
|
|
178
|
+
iss["updatedAt"] = ts
|
|
179
|
+
found = True
|
|
180
|
+
break
|
|
181
|
+
if not found:
|
|
182
|
+
print(f"ERROR: Issue '{iid}' not found.")
|
|
183
|
+
sys.exit(1)
|
|
184
|
+
data["issues"] = issues
|
|
185
|
+
with open(path, "w") as f:
|
|
186
|
+
json.dump(data, f, indent=2)
|
|
187
|
+
print(f" Updated: {iid} (updatedAt: {ts})")
|
|
188
|
+
PYEOF
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### close
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
[ -z "$issue_id" ] && { echo "ERROR: --issue-id required."; exit 1; }
|
|
195
|
+
ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
196
|
+
|
|
197
|
+
python3 - "$issuesFile" "$issue_id" "$ts" <<'PYEOF'
|
|
198
|
+
import json, sys
|
|
199
|
+
path, iid, ts = sys.argv[1], sys.argv[2], sys.argv[3]
|
|
200
|
+
data = json.load(open(path))
|
|
201
|
+
issues = data.get("issues", [])
|
|
202
|
+
found = False
|
|
203
|
+
for iss in issues:
|
|
204
|
+
if iss.get("id") == iid:
|
|
205
|
+
iss["status"] = "done"
|
|
206
|
+
iss["closedAt"] = ts
|
|
207
|
+
iss["updatedAt"] = ts
|
|
208
|
+
found = True
|
|
209
|
+
break
|
|
210
|
+
if not found:
|
|
211
|
+
print(f"ERROR: Issue '{iid}' not found.")
|
|
212
|
+
sys.exit(1)
|
|
213
|
+
data["issues"] = issues
|
|
214
|
+
with open(path, "w") as f:
|
|
215
|
+
json.dump(data, f, indent=2)
|
|
216
|
+
print(f" Closed: {iid} (closedAt: {ts})")
|
|
217
|
+
PYEOF
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## Step 3 — Return Output
|
|
223
|
+
|
|
224
|
+
```yaml
|
|
225
|
+
domain: ops
|
|
226
|
+
status: complete
|
|
227
|
+
action: <action>
|
|
228
|
+
org_name: <org_name>
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## Step 4 — Brain Write (standalone only)
|
|
234
|
+
|
|
235
|
+
If `caller` is not "command", follow _protocol.md Brain Write Procedure for domain `ops`.
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mastermind-join-queue
|
|
3
|
+
description: Mastermind join-queue — lists pending join requests for an org, approves or rejects them, and filters by request type (human/agent/all) and status. Mirrors JoinRequestQueue.tsx.
|
|
4
|
+
type: domain-skill
|
|
5
|
+
default_mode: auto
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Mastermind Join Queue
|
|
9
|
+
|
|
10
|
+
This skill is invoked by `mastermind:join-queue` or directly via `/mastermind:join-queue`.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Inputs
|
|
15
|
+
|
|
16
|
+
- `brain_context`: BRAIN CONTEXT block (injected by command, or loaded below if standalone)
|
|
17
|
+
- `org_name`: org to manage join requests for (required)
|
|
18
|
+
- `action`: list | approve | reject
|
|
19
|
+
- `request_id`: join request ID (required for approve/reject)
|
|
20
|
+
- `status`: pending_approval | approved | rejected (filter; default: pending_approval)
|
|
21
|
+
- `request_type`: all | human | agent (filter; default: all)
|
|
22
|
+
- `caller`: command | master
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Step 0 — Brain Load (standalone only)
|
|
27
|
+
|
|
28
|
+
If `caller` is not "command", load brain context following _protocol.md Brain Load Procedure with namespace: `ops`.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Step 1 — Load Org
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
orgFile=".monomind/orgs/${org_name}.json"
|
|
36
|
+
[ ! -f "$orgFile" ] && { echo "ERROR: Org '${org_name}' not found."; exit 1; }
|
|
37
|
+
|
|
38
|
+
joinFile=".monomind/orgs/${org_name}-join-requests.json"
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Step 2 — Execute Action
|
|
44
|
+
|
|
45
|
+
### list (default)
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
statusFilter="${status:-pending_approval}"
|
|
49
|
+
typeFilter="${request_type:-all}"
|
|
50
|
+
|
|
51
|
+
echo "JOIN REQUESTS — $org_name (status: $statusFilter type: $typeFilter)"
|
|
52
|
+
echo "────────────────────────────────────────────────────────"
|
|
53
|
+
|
|
54
|
+
if [ ! -f "$joinFile" ]; then
|
|
55
|
+
echo " No join requests found."
|
|
56
|
+
echo ""
|
|
57
|
+
echo " Approve: /mastermind:join-queue --org $org_name --action approve --request-id <id>"
|
|
58
|
+
exit 0
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
python3 - "$joinFile" "$statusFilter" "$typeFilter" <<'PYEOF'
|
|
62
|
+
import json, sys
|
|
63
|
+
data = json.load(open(sys.argv[1]))
|
|
64
|
+
status_f = sys.argv[2]
|
|
65
|
+
type_f = sys.argv[3]
|
|
66
|
+
|
|
67
|
+
requests = data.get("requests", [])
|
|
68
|
+
filtered = [r for r in requests
|
|
69
|
+
if r.get("status") == status_f
|
|
70
|
+
and (type_f == "all" or r.get("type") == type_f)]
|
|
71
|
+
|
|
72
|
+
if not filtered:
|
|
73
|
+
print(" (no matching requests)")
|
|
74
|
+
else:
|
|
75
|
+
print(f" {'ID':<32} {'TYPE':<8} {'REQUESTER':<28} {'STATUS':<20} {'CREATED'}")
|
|
76
|
+
print(" " + "─" * 102)
|
|
77
|
+
for r in filtered:
|
|
78
|
+
rid = r.get("id","?")[:32]
|
|
79
|
+
rtype = r.get("type","?")[:8]
|
|
80
|
+
req = (r.get("requesterName") or r.get("requesterId","?"))[:28]
|
|
81
|
+
st = r.get("status","?")[:20]
|
|
82
|
+
created = r.get("createdAt","-")[:10]
|
|
83
|
+
print(f" {rid:<32} {rtype:<8} {req:<28} {st:<20} {created}")
|
|
84
|
+
|
|
85
|
+
print(f"\n Total: {len(filtered)} request(s) (status={status_f}, type={type_f})")
|
|
86
|
+
PYEOF
|
|
87
|
+
|
|
88
|
+
echo ""
|
|
89
|
+
echo " Approve: /mastermind:join-queue --org $org_name --action approve --request-id <id>"
|
|
90
|
+
echo " Reject: /mastermind:join-queue --org $org_name --action reject --request-id <id>"
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### approve
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
[ -z "$request_id" ] && { echo "ERROR: --request-id required."; exit 1; }
|
|
97
|
+
[ ! -f "$joinFile" ] && { echo "ERROR: No join requests file found for org '${org_name}'."; exit 1; }
|
|
98
|
+
|
|
99
|
+
ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
100
|
+
|
|
101
|
+
python3 - "$joinFile" "$request_id" "$ts" <<'PYEOF'
|
|
102
|
+
import json, sys
|
|
103
|
+
path, rid, ts = sys.argv[1], sys.argv[2], sys.argv[3]
|
|
104
|
+
data = json.load(open(path))
|
|
105
|
+
requests = data.get("requests", [])
|
|
106
|
+
found = False
|
|
107
|
+
for r in requests:
|
|
108
|
+
if r.get("id") == rid:
|
|
109
|
+
r["status"] = "approved"
|
|
110
|
+
r["resolvedAt"] = ts
|
|
111
|
+
found = True
|
|
112
|
+
break
|
|
113
|
+
if not found:
|
|
114
|
+
print(f"ERROR: Request '{rid}' not found.")
|
|
115
|
+
sys.exit(1)
|
|
116
|
+
data["requests"] = requests
|
|
117
|
+
with open(path, "w") as f:
|
|
118
|
+
json.dump(data, f, indent=2)
|
|
119
|
+
print(f" Approved: {rid} (resolvedAt: {ts})")
|
|
120
|
+
PYEOF
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### reject
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
[ -z "$request_id" ] && { echo "ERROR: --request-id required."; exit 1; }
|
|
127
|
+
[ ! -f "$joinFile" ] && { echo "ERROR: No join requests file found for org '${org_name}'."; exit 1; }
|
|
128
|
+
|
|
129
|
+
ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
130
|
+
|
|
131
|
+
python3 - "$joinFile" "$request_id" "$ts" <<'PYEOF'
|
|
132
|
+
import json, sys
|
|
133
|
+
path, rid, ts = sys.argv[1], sys.argv[2], sys.argv[3]
|
|
134
|
+
data = json.load(open(path))
|
|
135
|
+
requests = data.get("requests", [])
|
|
136
|
+
found = False
|
|
137
|
+
for r in requests:
|
|
138
|
+
if r.get("id") == rid:
|
|
139
|
+
r["status"] = "rejected"
|
|
140
|
+
r["resolvedAt"] = ts
|
|
141
|
+
found = True
|
|
142
|
+
break
|
|
143
|
+
if not found:
|
|
144
|
+
print(f"ERROR: Request '{rid}' not found.")
|
|
145
|
+
sys.exit(1)
|
|
146
|
+
data["requests"] = requests
|
|
147
|
+
with open(path, "w") as f:
|
|
148
|
+
json.dump(data, f, indent=2)
|
|
149
|
+
print(f" Rejected: {rid} (resolvedAt: {ts})")
|
|
150
|
+
PYEOF
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## Step 3 — Return Output
|
|
156
|
+
|
|
157
|
+
```yaml
|
|
158
|
+
domain: ops
|
|
159
|
+
status: complete
|
|
160
|
+
action: <action>
|
|
161
|
+
org_name: <org_name>
|
|
162
|
+
status_filter: <status>
|
|
163
|
+
type_filter: <request_type>
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## Step 4 — Brain Write (standalone only)
|
|
169
|
+
|
|
170
|
+
If `caller` is not "command", follow _protocol.md Brain Write Procedure for domain `ops`.
|