@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,321 @@
1
+ ---
2
+ name: mastermind-memory
3
+ description: Mastermind memory — org-scoped persistent memory using PARA method (Projects, Areas, Resources, Archives). Ingest facts, recall context, maintain knowledge graph, run weekly synthesis. Reads from .monomind/orgs/<org>-memory/ directory. Port of Paperclip's para-memory-files skill for org-level context.
4
+ type: domain-skill
5
+ default_mode: auto
6
+ ---
7
+
8
+ # Mastermind Memory
9
+
10
+ This skill is invoked by `mastermind:memory` or directly via `/mastermind:memory`.
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 memory to operate on (required)
18
+ - `action`: ingest | recall | query | update | forget | synthesize | decay | list
19
+ - `topic`: topic or entity name (required for ingest/recall/update/forget)
20
+ - `layer`: knowledge | daily | tacit (default: knowledge)
21
+ - `category`: projects | areas | resources | archives (for layer=knowledge; default: resources)
22
+ - `content`: fact or note body (required for ingest/update)
23
+ - `caller`: command | master
24
+
25
+ ---
26
+
27
+ ## Memory Architecture (PARA)
28
+
29
+ Three layers, mirrored to `.monomind/orgs/<org_name>-memory/`:
30
+
31
+ ```
32
+ .monomind/orgs/<org>-memory/
33
+ knowledge/ ← Layer 1: PARA knowledge graph
34
+ projects/<topic>/
35
+ summary.md
36
+ items.yaml
37
+ areas/<topic>/
38
+ summary.md
39
+ items.yaml
40
+ resources/<topic>/
41
+ summary.md
42
+ items.yaml
43
+ archives/<topic>/
44
+ summary.md
45
+ items.yaml
46
+ index.md
47
+ daily/ ← Layer 2: Raw timeline (YYYY-MM-DD.md)
48
+ tacit.md ← Layer 3: Org operating patterns
49
+ ```
50
+
51
+ **PARA rules:**
52
+ - **projects** — active work with a goal/deadline; archive when complete
53
+ - **areas** — ongoing responsibilities, no end date
54
+ - **resources** — reference material, topics of interest
55
+ - **archives** — inactive items from any category
56
+
57
+ ---
58
+
59
+ ## Step 0 — Brain Load (standalone only)
60
+
61
+ If `caller` is not "command", load brain context following _protocol.md Brain Load Procedure with namespace: `ops`.
62
+
63
+ ---
64
+
65
+ ## Step 1 — Resolve Memory Root
66
+
67
+ ```bash
68
+ memRoot=".monomind/orgs/${org_name}-memory"
69
+ mkdir -p "$memRoot/knowledge/projects" "$memRoot/knowledge/areas" \
70
+ "$memRoot/knowledge/resources" "$memRoot/knowledge/archives" \
71
+ "$memRoot/daily"
72
+ ```
73
+
74
+ ---
75
+
76
+ ## Step 2 — Execute Action
77
+
78
+ ### ingest (default for new facts)
79
+
80
+ Store a durable fact in Layer 1 (knowledge graph) or Layer 2 (daily note).
81
+
82
+ ```bash
83
+ ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
84
+ day=$(date -u +%Y-%m-%d)
85
+ layer="${layer:-knowledge}"
86
+ category="${category:-resources}"
87
+ topicSlug=$(echo "${topic:-general}" | tr '[:upper:]' '[:lower:]' | tr ' ' '-' | tr -cd 'a-z0-9-')
88
+
89
+ if [ "$layer" = "daily" ]; then
90
+ dailyFile="$memRoot/daily/${day}.md"
91
+ [ ! -f "$dailyFile" ] && echo "# Daily Notes — ${day}" > "$dailyFile"
92
+ echo "" >> "$dailyFile"
93
+ echo "## [${ts}] ${topic:-note}" >> "$dailyFile"
94
+ echo "${content}" >> "$dailyFile"
95
+ echo " [daily] Appended to $dailyFile"
96
+ elif [ "$layer" = "tacit" ]; then
97
+ [ ! -f "$memRoot/tacit.md" ] && echo "# Org Operating Patterns — ${org_name}" > "$memRoot/tacit.md"
98
+ echo "" >> "$memRoot/tacit.md"
99
+ echo "## ${topic}" >> "$memRoot/tacit.md"
100
+ echo "${content}" >> "$memRoot/tacit.md"
101
+ echo " [tacit] Pattern saved."
102
+ else
103
+ # Layer 1: knowledge graph
104
+ entityDir="$memRoot/knowledge/${category}/${topicSlug}"
105
+ mkdir -p "$entityDir"
106
+ factId="fact-$(python3 -c 'import time; print(int(time.time()*1000))')"
107
+ python3 - "$entityDir/items.yaml" "$factId" "${topic}" "${content}" "$ts" <<'PYEOF'
108
+ import sys, yaml, os
109
+ path, fid, topic, body, ts = sys.argv[1:]
110
+ facts = []
111
+ if os.path.exists(path):
112
+ try:
113
+ with open(path) as f:
114
+ loaded = yaml.safe_load(f)
115
+ if isinstance(loaded, list): facts = loaded
116
+ except: pass
117
+ facts.append({"id": fid, "topic": topic, "body": body, "createdAt": ts, "status": "active"})
118
+ with open(path, "w") as f:
119
+ yaml.dump(facts, f, default_flow_style=False, allow_unicode=True)
120
+ print(f" Fact saved: {fid} → {path}")
121
+ PYEOF
122
+ fi
123
+ ```
124
+
125
+ ### recall / query
126
+
127
+ Search org memory across all layers for a topic or keyword.
128
+
129
+ ```bash
130
+ q="${topic:-${content}}"
131
+ echo "MEMORY RECALL — ${org_name}"
132
+ echo "Query: $q"
133
+ echo "────────────────────────────────────────────────────────"
134
+
135
+ python3 - "$memRoot" "$q" <<'PYEOF'
136
+ import os, sys, yaml, re
137
+ root, query = sys.argv[1], sys.argv[2].lower()
138
+ results = []
139
+
140
+ # Layer 1: scan items.yaml files
141
+ kg = os.path.join(root, "knowledge")
142
+ for cat in ["projects","areas","resources","archives"]:
143
+ cpath = os.path.join(kg, cat)
144
+ if not os.path.isdir(cpath): continue
145
+ for topic in os.listdir(cpath):
146
+ ypath = os.path.join(cpath, topic, "items.yaml")
147
+ if not os.path.exists(ypath): continue
148
+ try:
149
+ facts = yaml.safe_load(open(ypath)) or []
150
+ for f in facts:
151
+ if f.get("status") == "superseded": continue
152
+ body = str(f.get("body","")).lower()
153
+ ftopic = str(f.get("topic","")).lower()
154
+ if query in body or query in ftopic or query in topic.lower():
155
+ results.append(("knowledge/"+cat+"/"+topic, f.get("createdAt","?")[:10], f.get("body","")[:120]))
156
+ except: pass
157
+
158
+ # Layer 2: daily notes
159
+ daily_dir = os.path.join(root, "daily")
160
+ if os.path.isdir(daily_dir):
161
+ for fname in sorted(os.listdir(daily_dir), reverse=True)[:30]:
162
+ try:
163
+ text = open(os.path.join(daily_dir, fname)).read().lower()
164
+ if query in text:
165
+ results.append(("daily/"+fname, fname[:10], "(match in daily notes)"))
166
+ except: pass
167
+
168
+ # Layer 3: tacit
169
+ tacit = os.path.join(root, "tacit.md")
170
+ if os.path.exists(tacit):
171
+ text = open(tacit).read().lower()
172
+ if query in text:
173
+ results.append(("tacit.md", "", "(match in org patterns)"))
174
+
175
+ if not results:
176
+ print(" No matches found.")
177
+ else:
178
+ print(f" {len(results)} result(s):")
179
+ for path, date, body in results[:20]:
180
+ print(f"\n [{date}] {path}")
181
+ print(f" {body[:100]}{'...' if len(body)>100 else ''}")
182
+ PYEOF
183
+ ```
184
+
185
+ ### list
186
+
187
+ List all entities in the knowledge graph.
188
+
189
+ ```bash
190
+ echo "KNOWLEDGE GRAPH — ${org_name}"
191
+ echo "────────────────────────────────────────────────────────"
192
+
193
+ python3 - "$memRoot/knowledge" <<'PYEOF'
194
+ import os, sys, yaml
195
+ kg = sys.argv[1]
196
+ total = 0
197
+ for cat in ["projects","areas","resources","archives"]:
198
+ cpath = os.path.join(kg, cat)
199
+ if not os.path.isdir(cpath): continue
200
+ topics = [d for d in os.listdir(cpath) if os.path.isdir(os.path.join(cpath,d))]
201
+ if not topics: continue
202
+ print(f"\n {cat.upper()} ({len(topics)})")
203
+ for t in sorted(topics):
204
+ ypath = os.path.join(cpath, t, "items.yaml")
205
+ count = 0
206
+ try:
207
+ facts = yaml.safe_load(open(ypath)) or []
208
+ count = len([f for f in facts if f.get("status") != "superseded"])
209
+ except: pass
210
+ print(f" · {t} ({count} facts)")
211
+ total += len(topics)
212
+ print(f"\n Total entities: {total}")
213
+ PYEOF
214
+ ```
215
+
216
+ ### forget
217
+
218
+ Mark a fact as superseded (never delete — supersede).
219
+
220
+ ```bash
221
+ topicSlug=$(echo "${topic}" | tr '[:upper:]' '[:lower:]' | tr ' ' '-' | tr -cd 'a-z0-9-')
222
+ ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
223
+ category="${category:-resources}"
224
+ entityDir="$memRoot/knowledge/${category}/${topicSlug}"
225
+ ypath="$entityDir/items.yaml"
226
+
227
+ python3 - "$ypath" "$ts" "${content:-forgot}" <<'PYEOF'
228
+ import sys, yaml, os
229
+ path, ts, reason = sys.argv[1], sys.argv[2], sys.argv[3]
230
+ if not os.path.exists(path):
231
+ print(" No facts found for this entity.")
232
+ sys.exit(0)
233
+ facts = yaml.safe_load(open(path)) or []
234
+ active = [f for f in facts if f.get("status") == "active"]
235
+ for f in active:
236
+ f["status"] = "superseded"
237
+ f["supersededAt"] = ts
238
+ f["supersededReason"] = reason
239
+ with open(path, "w") as out:
240
+ yaml.dump(facts, out, default_flow_style=False, allow_unicode=True)
241
+ print(f" {len(active)} fact(s) superseded in {path}")
242
+ PYEOF
243
+ ```
244
+
245
+ ### synthesize
246
+
247
+ Rebuild summary.md for an entity from its active facts.
248
+
249
+ ```bash
250
+ topicSlug=$(echo "${topic}" | tr '[:upper:]' '[:lower:]' | tr ' ' '-' | tr -cd 'a-z0-9-')
251
+ category="${category:-resources}"
252
+ entityDir="$memRoot/knowledge/${category}/${topicSlug}"
253
+ ypath="$entityDir/items.yaml"
254
+ [ ! -f "$ypath" ] && { echo " No facts found for '${topic}'."; exit 0; }
255
+
256
+ python3 - "$ypath" "$entityDir/summary.md" "${topic}" <<'PYEOF'
257
+ import sys, yaml
258
+ ypath, sumpath, topic = sys.argv[1], sys.argv[2], sys.argv[3]
259
+ facts = [f for f in (yaml.safe_load(open(ypath)) or []) if f.get("status") == "active"]
260
+ lines = [f"# {topic}", "", f"{len(facts)} active fact(s):", ""]
261
+ for f in facts:
262
+ date = str(f.get("createdAt","?"))[:10]
263
+ lines.append(f"- [{date}] {f.get('body','')}")
264
+ open(sumpath, "w").write("\n".join(lines) + "\n")
265
+ print(f" Summary rebuilt: {sumpath}")
266
+ PYEOF
267
+ ```
268
+
269
+ ### decay
270
+
271
+ Archive entities with no facts updated in the last 90 days.
272
+
273
+ ```bash
274
+ ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
275
+
276
+ python3 - "$memRoot/knowledge" "$ts" <<'PYEOF'
277
+ import os, sys, yaml, shutil
278
+ from datetime import datetime, timedelta
279
+ kg, ts = sys.argv[1], sys.argv[2]
280
+ cutoff = datetime.utcnow() - timedelta(days=90)
281
+ archived = 0
282
+ for cat in ["projects","areas","resources"]:
283
+ cpath = os.path.join(kg, cat)
284
+ if not os.path.isdir(cpath): continue
285
+ for topic in os.listdir(cpath):
286
+ ypath = os.path.join(cpath, topic, "items.yaml")
287
+ if not os.path.exists(ypath): continue
288
+ try:
289
+ facts = yaml.safe_load(open(ypath)) or []
290
+ active = [f for f in facts if f.get("status") == "active"]
291
+ if not active: continue
292
+ last = max(f.get("createdAt","")[:19] for f in active)
293
+ dt = datetime.fromisoformat(last)
294
+ if dt < cutoff:
295
+ dst = os.path.join(kg, "archives", topic)
296
+ shutil.move(os.path.join(cpath, topic), dst)
297
+ archived += 1
298
+ print(f" Archived: {cat}/{topic} (last active: {last[:10]})")
299
+ except: pass
300
+ print(f"\n Decay complete: {archived} entity/entities moved to archives.")
301
+ PYEOF
302
+ ```
303
+
304
+ ---
305
+
306
+ ## Step 3 — Return Output
307
+
308
+ ```yaml
309
+ domain: ops
310
+ status: complete
311
+ action: <action>
312
+ org_name: <org_name>
313
+ layer: <layer>
314
+ topic: <topic>
315
+ ```
316
+
317
+ ---
318
+
319
+ ## Step 4 — Brain Write (standalone only)
320
+
321
+ If `caller` is not "command", follow _protocol.md Brain Write Procedure for domain `ops`.
@@ -0,0 +1,146 @@
1
+ ---
2
+ name: mastermind-my-issues
3
+ description: Mastermind my-issues — filtered issue queue scoped to the current operator or a specific assignee. Lists open and in-progress issues, supports self-assign and unassign. Mirrors MyIssues.tsx.
4
+ type: domain-skill
5
+ default_mode: auto
6
+ ---
7
+
8
+ # Mastermind My Issues
9
+
10
+ This skill is invoked by `mastermind:my-issues` or directly via `/mastermind:my-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 issues from (required)
18
+ - `action`: list | assign-self | unassign | close
19
+ - `assignee_id`: user/agent id to filter by (default: local-operator)
20
+ - `issue_id`: issue id (required for assign-self / unassign / close)
21
+ - `status_filter`: open | in_progress | all (default: open+in_progress)
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 Issues
33
+
34
+ ```bash
35
+ orgFile=".monomind/orgs/${org_name}.json"
36
+ [ ! -f "$orgFile" ] && { echo "ERROR: Org '${org_name}' not found."; exit 1; }
37
+
38
+ issuesFile=".monomind/orgs/${org_name}-issues.json"
39
+ [ ! -f "$issuesFile" ] && { echo "No issues found for org '${org_name}'."; exit 0; }
40
+
41
+ assigneeFilter="${assignee_id:-local-operator}"
42
+ ```
43
+
44
+ ---
45
+
46
+ ## Step 2 — Execute Action
47
+
48
+ ### list (default)
49
+
50
+ ```bash
51
+ statusFilter="${status_filter:-active}"
52
+ echo "MY ISSUES — org: $org_name assignee: $assigneeFilter"
53
+ echo "────────────────────────────────────────────────────────"
54
+ printf "%-24s %-12s %-10s %s\n" "ID" "STATUS" "PRIORITY" "TITLE"
55
+ echo "────────────────────────────────────────────────────────"
56
+
57
+ jq -r --arg uid "$assigneeFilter" --arg sf "$statusFilter" '
58
+ .issues[] |
59
+ select(
60
+ (.assigneeId == $uid or .assigned_to == $uid) and
61
+ (if $sf == "active" then (.status == "open" or .status == "in_progress")
62
+ elif $sf == "all" then true
63
+ else .status == $sf
64
+ end)
65
+ ) |
66
+ [.id, (.status // "open"), (.priority // "medium"), (.title // "(no title)")] | @tsv
67
+ ' "$issuesFile" | while IFS=$'\t' read -r id st pri title; do
68
+ printf "%-24s %-12s %-10s %s\n" "$id" "$st" "$pri" "$title"
69
+ done
70
+
71
+ total=$(jq -r --arg uid "$assigneeFilter" \
72
+ '[.issues[] | select(.assigneeId == $uid or .assigned_to == $uid)] | length' \
73
+ "$issuesFile")
74
+ echo ""
75
+ echo "Total assigned: $total"
76
+ [ "$total" -eq 0 ] && echo " No issues assigned to '$assigneeFilter'. To assign: --action assign-self --issue-id <id>"
77
+ ```
78
+
79
+ ### assign-self
80
+
81
+ ```bash
82
+ [ -z "$issue_id" ] && { echo "ERROR: --issue-id required."; exit 1; }
83
+
84
+ exists=$(jq -r --arg id "$issue_id" '[.issues[] | select(.id == $id)] | length' "$issuesFile")
85
+ [ "$exists" -eq 0 ] && { echo "ERROR: Issue '$issue_id' not found."; exit 1; }
86
+
87
+ ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
88
+ tmp="${issuesFile}.tmp"
89
+ jq --arg id "$issue_id" --arg uid "$assigneeFilter" --arg ts "$ts" \
90
+ '.issues = [.issues[] | if .id == $id then
91
+ .assigneeId = $uid | .lastActivityAt = $ts
92
+ else . end]' \
93
+ "$issuesFile" > "$tmp" && mv "$tmp" "$issuesFile"
94
+
95
+ echo "Issue '$issue_id' assigned to '$assigneeFilter'."
96
+ ```
97
+
98
+ ### unassign
99
+
100
+ ```bash
101
+ [ -z "$issue_id" ] && { echo "ERROR: --issue-id required."; exit 1; }
102
+
103
+ ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
104
+ tmp="${issuesFile}.tmp"
105
+ jq --arg id "$issue_id" --arg ts "$ts" \
106
+ '.issues = [.issues[] | if .id == $id then
107
+ .assigneeId = null | .lastActivityAt = $ts
108
+ else . end]' \
109
+ "$issuesFile" > "$tmp" && mv "$tmp" "$issuesFile"
110
+
111
+ echo "Issue '$issue_id' unassigned."
112
+ ```
113
+
114
+ ### close
115
+
116
+ ```bash
117
+ [ -z "$issue_id" ] && { echo "ERROR: --issue-id required."; exit 1; }
118
+
119
+ ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
120
+ tmp="${issuesFile}.tmp"
121
+ jq --arg id "$issue_id" --arg ts "$ts" \
122
+ '.issues = [.issues[] | if .id == $id then
123
+ .status = "done" | .closedAt = $ts | .lastActivityAt = $ts
124
+ else . end]' \
125
+ "$issuesFile" > "$tmp" && mv "$tmp" "$issuesFile"
126
+
127
+ echo "Issue '$issue_id' closed (status: done)."
128
+ ```
129
+
130
+ ---
131
+
132
+ ## Step 3 — Return Output
133
+
134
+ ```yaml
135
+ domain: ops
136
+ status: complete
137
+ action: <action>
138
+ org: <org_name>
139
+ assignee: <assignee_id>
140
+ ```
141
+
142
+ ---
143
+
144
+ ## Step 4 — Brain Write (standalone only)
145
+
146
+ If `caller` is not "command", follow _protocol.md Brain Write Procedure for domain `ops`.