@monoes/monomindcli 1.9.17 → 1.10.0

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.
Files changed (118) hide show
  1. package/.claude/commands/mastermind/_repeat.md +182 -39
  2. package/.claude/commands/mastermind/architect.md +17 -11
  3. package/.claude/commands/mastermind/brain.md +4 -0
  4. package/.claude/commands/mastermind/build.md +4 -0
  5. package/.claude/commands/mastermind/content.md +4 -0
  6. package/.claude/commands/mastermind/createorg.md +5 -3
  7. package/.claude/commands/mastermind/finance.md +4 -0
  8. package/.claude/commands/mastermind/idea.md +4 -0
  9. package/.claude/commands/mastermind/marketing.md +4 -0
  10. package/.claude/commands/mastermind/master.md +63 -37
  11. package/.claude/commands/mastermind/ops.md +4 -0
  12. package/.claude/commands/mastermind/release.md +4 -0
  13. package/.claude/commands/mastermind/research.md +4 -0
  14. package/.claude/commands/mastermind/review.md +4 -0
  15. package/.claude/commands/mastermind/runorg.md +5 -3
  16. package/.claude/commands/mastermind/sales.md +4 -0
  17. package/.claude/commands/mastermind/techport.md +9 -0
  18. package/.claude/commands/monomind/do.md +5 -1
  19. package/.claude/commands/monomind/idea.md +5 -1
  20. package/.claude/commands/monomind/improve.md +5 -1
  21. package/.claude/commands/monomind/repeat.md +85 -29
  22. package/.claude/commands/monomind/review.md +6 -2
  23. package/.claude/commands/monomind/understand.md +10 -8
  24. package/.claude/helpers/extras-registry.json +235 -235
  25. package/.claude/helpers/graphify-freshen.cjs +13 -1
  26. package/.claude/helpers/hook-handler.cjs +1 -1
  27. package/.claude/helpers/router.cjs +4 -1
  28. package/.claude/skills/mastermind/_protocol.md +28 -21
  29. package/.claude/skills/mastermind/access.md +236 -0
  30. package/.claude/skills/mastermind/activity.md +191 -0
  31. package/.claude/skills/mastermind/adapter-manager.md +259 -0
  32. package/.claude/skills/mastermind/adapters.md +204 -0
  33. package/.claude/skills/mastermind/agent-detail.md +242 -0
  34. package/.claude/skills/mastermind/agents.md +178 -0
  35. package/.claude/skills/mastermind/approval-detail.md +259 -0
  36. package/.claude/skills/mastermind/approve.md +181 -0
  37. package/.claude/skills/mastermind/architect.md +24 -8
  38. package/.claude/skills/mastermind/backup.md +197 -0
  39. package/.claude/skills/mastermind/bootstrap.md +190 -0
  40. package/.claude/skills/mastermind/budgets.md +237 -0
  41. package/.claude/skills/mastermind/companies.md +256 -0
  42. package/.claude/skills/mastermind/costs.md +151 -0
  43. package/.claude/skills/mastermind/createorg.md +23 -5
  44. package/.claude/skills/mastermind/diagnose.md +249 -0
  45. package/.claude/skills/mastermind/env.md +198 -0
  46. package/.claude/skills/mastermind/environments.md +250 -0
  47. package/.claude/skills/mastermind/export.md +324 -0
  48. package/.claude/skills/mastermind/goal-detail.md +255 -0
  49. package/.claude/skills/mastermind/goals.md +149 -0
  50. package/.claude/skills/mastermind/heartbeat.md +164 -0
  51. package/.claude/skills/mastermind/idea.md +250 -122
  52. package/.claude/skills/mastermind/import.md +281 -0
  53. package/.claude/skills/mastermind/inbox.md +214 -0
  54. package/.claude/skills/mastermind/instance-settings.md +315 -0
  55. package/.claude/skills/mastermind/instance.md +231 -0
  56. package/.claude/skills/mastermind/invite-landing.md +227 -0
  57. package/.claude/skills/mastermind/invites.md +254 -0
  58. package/.claude/skills/mastermind/issue-detail.md +291 -0
  59. package/.claude/skills/mastermind/issues.md +235 -0
  60. package/.claude/skills/mastermind/join-queue.md +170 -0
  61. package/.claude/skills/mastermind/liveness.md +392 -0
  62. package/.claude/skills/mastermind/memory.md +321 -0
  63. package/.claude/skills/mastermind/my-issues.md +146 -0
  64. package/.claude/skills/mastermind/new-agent.md +241 -0
  65. package/.claude/skills/mastermind/org-chart.md +207 -0
  66. package/.claude/skills/mastermind/org-settings.md +217 -0
  67. package/.claude/skills/mastermind/plan-to-tasks.md +136 -0
  68. package/.claude/skills/mastermind/plugin-manager.md +241 -0
  69. package/.claude/skills/mastermind/plugin-settings.md +273 -0
  70. package/.claude/skills/mastermind/plugins.md +190 -0
  71. package/.claude/skills/mastermind/profile.md +187 -0
  72. package/.claude/skills/mastermind/project-detail.md +249 -0
  73. package/.claude/skills/mastermind/project-workspace.md +244 -0
  74. package/.claude/skills/mastermind/projects.md +164 -0
  75. package/.claude/skills/mastermind/routine-detail.md +253 -0
  76. package/.claude/skills/mastermind/routines.md +202 -0
  77. package/.claude/skills/mastermind/runorg.md +74 -9
  78. package/.claude/skills/mastermind/search.md +186 -0
  79. package/.claude/skills/mastermind/secrets.md +199 -0
  80. package/.claude/skills/mastermind/skills.md +156 -0
  81. package/.claude/skills/mastermind/tasks.md +149 -0
  82. package/.claude/skills/mastermind/techport.md +5 -5
  83. package/.claude/skills/mastermind/threads.md +259 -0
  84. package/.claude/skills/mastermind/tree-control.md +250 -0
  85. package/.claude/skills/mastermind/wiki.md +314 -0
  86. package/.claude/skills/mastermind/workspace-detail.md +317 -0
  87. package/.claude/skills/mastermind/workspaces.md +261 -0
  88. package/.claude/skills/mastermind/worktree.md +187 -0
  89. package/dist/src/init/executor.js +8 -8
  90. package/dist/src/init/executor.js.map +1 -1
  91. package/dist/src/init/statusline-generator.d.ts.map +1 -1
  92. package/dist/src/init/statusline-generator.js +12 -0
  93. package/dist/src/init/statusline-generator.js.map +1 -1
  94. package/dist/src/ui/.monomind/data/ranked-context.json +1 -1
  95. package/dist/src/ui/.monomind/loops/mastermind-review-1778664132789.json +16 -0
  96. package/dist/src/ui/.monomind/sessions/current.json +5 -5
  97. package/dist/src/ui/.monomind/sessions/session-1776778451399.json +15 -0
  98. package/dist/src/ui/dashboard.html +3030 -181
  99. package/dist/src/ui/data/mastermind-events.jsonl +8 -0
  100. package/dist/src/ui/data/mastermind-sessions.json +1 -0
  101. package/dist/src/ui/server.mjs +738 -0
  102. package/dist/tsconfig.tsbuildinfo +1 -1
  103. package/package.json +1 -1
  104. package/.claude/skills/.monomind/data/ranked-context.json +0 -5
  105. package/.claude/skills/.monomind/sessions/current.json +0 -13
  106. package/.claude/skills/.monomind/sessions/session-1777829336455.json +0 -15
  107. package/.claude/skills/.monomind/sessions/session-1777831614725.json +0 -15
  108. package/.claude/skills/.monomind/sessions/session-1777832095857.json +0 -15
  109. package/.claude/skills/.monomind/sessions/session-1777839814183.json +0 -15
  110. package/.claude/skills/.monomind/sessions/session-1777841847131.json +0 -15
  111. package/.claude/skills/.monomind/sessions/session-1777843309463.json +0 -15
  112. package/.claude/skills/.monomind/sessions/session-1777880867159.json +0 -15
  113. package/.claude/skills/.monomind/sessions/session-1777881884593.json +0 -15
  114. package/.claude/skills/.monomind/sessions/session-1777884090471.json +0 -15
  115. package/.claude/skills/.monomind/sessions/session-1777884808221.json +0 -15
  116. package/.claude/skills/.monomind/sessions/session-1777885672155.json +0 -15
  117. package/.claude/skills/.monomind/sessions/session-1777886852818.json +0 -15
  118. 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`.