@monoes/monomindcli 2.10.10 → 2.10.13
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/brain.md +14 -14
- package/.claude/commands/mastermind/help.md +2 -2
- package/.claude/commands/mastermind/master.md +24 -19
- package/.claude/commands/mastermind/memory.md +8 -8
- package/.claude/commands/mastermind/monoswarm.md +4 -4
- package/.claude/commands/mastermind.md +7 -7
- package/.claude/commands/truth/start.md +3 -3
- package/.claude/skills/mastermind/SKILL.md +7 -16
- package/.claude/skills/mastermind-debug/SKILL.md +3 -3
- package/.claude/skills/mastermind-design/SKILL.md +2 -0
- package/.claude/skills/mastermind-execute/SKILL.md +66 -11
- package/.claude/skills/mastermind-idea/SKILL.md +9 -2
- package/.claude/skills/mastermind-intake/SKILL.md +31 -7
- package/.claude/skills/mastermind-issue-detail/SKILL.md +70 -16
- package/.claude/skills/mastermind-issues/SKILL.md +111 -16
- package/.claude/skills/mastermind-liveness/SKILL.md +96 -26
- package/.claude/skills/mastermind-my-issues/SKILL.md +40 -8
- package/.claude/skills/mastermind-org/SKILL.md +2 -0
- package/.claude/skills/mastermind-plan/SKILL.md +7 -16
- package/.claude/skills/mastermind-plan-to-tasks/SKILL.md +132 -24
- package/.claude/skills/mastermind-protocol/SKILL.md +33 -22
- package/.claude/skills/mastermind-runorg/SKILL.md +22 -3
- package/.claude/skills/mastermind-skill-builder/SKILL.md +1 -1
- package/.claude/skills/mastermind-tasks/SKILL.md +5 -0
- package/.claude/skills/mastermind-techport/SKILL.md +1 -1
- package/.claude/skills/performance-analysis/SKILL.md +1 -1
- package/.claude/skills/verification-quality/SKILL.md +2 -3
- package/README.md +2 -2
- package/dist/src/commands/doc.js +2 -2
- package/dist/src/commands/doc.js.map +1 -1
- package/dist/src/commands/doctor-project-checks.d.ts.map +1 -1
- package/dist/src/commands/doctor-project-checks.js +20 -1
- package/dist/src/commands/doctor-project-checks.js.map +1 -1
- package/dist/src/commands/monograph.d.ts.map +1 -1
- package/dist/src/commands/monograph.js +11 -4
- package/dist/src/commands/monograph.js.map +1 -1
- package/dist/src/commands/org-observe.d.ts.map +1 -1
- package/dist/src/commands/org-observe.js +56 -6
- package/dist/src/commands/org-observe.js.map +1 -1
- package/dist/src/commands/org.d.ts +26 -0
- package/dist/src/commands/org.d.ts.map +1 -1
- package/dist/src/commands/org.js +144 -28
- package/dist/src/commands/org.js.map +1 -1
- package/dist/src/init/executor.d.ts.map +1 -1
- package/dist/src/init/executor.js +10 -9
- package/dist/src/init/executor.js.map +1 -1
- package/dist/src/init/settings-generator.d.ts.map +1 -1
- package/dist/src/init/settings-generator.js.map +1 -1
- package/dist/src/init/write-codex.d.ts.map +1 -1
- package/dist/src/init/write-codex.js.map +1 -1
- package/dist/src/knowledge/document-pipeline.d.ts +5 -0
- package/dist/src/knowledge/document-pipeline.d.ts.map +1 -1
- package/dist/src/knowledge/document-pipeline.js +32 -16
- package/dist/src/knowledge/document-pipeline.js.map +1 -1
- package/dist/src/mcp-tools/hooks-routing.d.ts +9 -0
- package/dist/src/mcp-tools/hooks-routing.d.ts.map +1 -1
- package/dist/src/mcp-tools/hooks-routing.js +12 -1
- package/dist/src/mcp-tools/hooks-routing.js.map +1 -1
- package/dist/src/mcp-tools/knowledge-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/knowledge-tools.js +105 -13
- package/dist/src/mcp-tools/knowledge-tools.js.map +1 -1
- package/dist/src/mcp-tools/memory-tools.d.ts +13 -0
- package/dist/src/mcp-tools/memory-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/memory-tools.js +257 -31
- package/dist/src/mcp-tools/memory-tools.js.map +1 -1
- package/dist/src/mcp-tools/monograph/health-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/monograph/health-tools.js +99 -42
- package/dist/src/mcp-tools/monograph/health-tools.js.map +1 -1
- package/dist/src/mcp-tools/monograph/impact-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/monograph/impact-tools.js +123 -51
- package/dist/src/mcp-tools/monograph/impact-tools.js.map +1 -1
- package/dist/src/mcp-tools/monograph/query-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/monograph/query-tools.js +113 -96
- package/dist/src/mcp-tools/monograph/query-tools.js.map +1 -1
- package/dist/src/mcp-tools/monograph/shared.d.ts +37 -4
- package/dist/src/mcp-tools/monograph/shared.d.ts.map +1 -1
- package/dist/src/mcp-tools/monograph/shared.js +75 -56
- package/dist/src/mcp-tools/monograph/shared.js.map +1 -1
- package/dist/src/memory/memory-bridge.d.ts +60 -1
- package/dist/src/memory/memory-bridge.d.ts.map +1 -1
- package/dist/src/memory/memory-bridge.js +172 -42
- package/dist/src/memory/memory-bridge.js.map +1 -1
- package/dist/src/memory/memory-kg.d.ts +495 -28
- package/dist/src/memory/memory-kg.d.ts.map +1 -1
- package/dist/src/memory/memory-kg.js +2186 -251
- package/dist/src/memory/memory-kg.js.map +1 -1
- package/dist/src/memory/query-router.d.ts +51 -0
- package/dist/src/memory/query-router.d.ts.map +1 -1
- package/dist/src/memory/query-router.js +38 -2
- package/dist/src/memory/query-router.js.map +1 -1
- package/dist/src/orgrt/agent-exec.d.ts.map +1 -1
- package/dist/src/orgrt/agent-exec.js +7 -0
- package/dist/src/orgrt/agent-exec.js.map +1 -1
- package/dist/src/orgrt/agent-runner.d.ts +26 -1
- package/dist/src/orgrt/agent-runner.d.ts.map +1 -1
- package/dist/src/orgrt/agent-runner.js +73 -22
- package/dist/src/orgrt/agent-runner.js.map +1 -1
- package/dist/src/orgrt/antigravity-runner.d.ts +1 -1
- package/dist/src/orgrt/antigravity-runner.d.ts.map +1 -1
- package/dist/src/orgrt/antigravity-runner.js +36 -19
- package/dist/src/orgrt/antigravity-runner.js.map +1 -1
- package/dist/src/orgrt/approvals.d.ts +26 -2
- package/dist/src/orgrt/approvals.d.ts.map +1 -1
- package/dist/src/orgrt/approvals.js +67 -7
- package/dist/src/orgrt/approvals.js.map +1 -1
- package/dist/src/orgrt/broker.d.ts +21 -2
- package/dist/src/orgrt/broker.d.ts.map +1 -1
- package/dist/src/orgrt/broker.js +56 -8
- package/dist/src/orgrt/broker.js.map +1 -1
- package/dist/src/orgrt/bus.d.ts +8 -0
- package/dist/src/orgrt/bus.d.ts.map +1 -1
- package/dist/src/orgrt/bus.js +27 -0
- package/dist/src/orgrt/bus.js.map +1 -1
- package/dist/src/orgrt/checkpoint-ops.d.ts.map +1 -1
- package/dist/src/orgrt/checkpoint-ops.js +15 -5
- package/dist/src/orgrt/checkpoint-ops.js.map +1 -1
- package/dist/src/orgrt/checkpoint.d.ts +42 -4
- package/dist/src/orgrt/checkpoint.d.ts.map +1 -1
- package/dist/src/orgrt/checkpoint.js +75 -4
- package/dist/src/orgrt/checkpoint.js.map +1 -1
- package/dist/src/orgrt/codex-runner.d.ts +1 -1
- package/dist/src/orgrt/codex-runner.d.ts.map +1 -1
- package/dist/src/orgrt/codex-runner.js +50 -23
- package/dist/src/orgrt/codex-runner.js.map +1 -1
- package/dist/src/orgrt/copilot-runner.d.ts +24 -2
- package/dist/src/orgrt/copilot-runner.d.ts.map +1 -1
- package/dist/src/orgrt/copilot-runner.js +257 -157
- package/dist/src/orgrt/copilot-runner.js.map +1 -1
- package/dist/src/orgrt/cross-org.d.ts +10 -3
- package/dist/src/orgrt/cross-org.d.ts.map +1 -1
- package/dist/src/orgrt/cross-org.js +225 -10
- package/dist/src/orgrt/cross-org.js.map +1 -1
- package/dist/src/orgrt/crush-runner.d.ts +22 -2
- package/dist/src/orgrt/crush-runner.d.ts.map +1 -1
- package/dist/src/orgrt/crush-runner.js +227 -120
- package/dist/src/orgrt/crush-runner.js.map +1 -1
- package/dist/src/orgrt/daemon.d.ts +77 -7
- package/dist/src/orgrt/daemon.d.ts.map +1 -1
- package/dist/src/orgrt/daemon.js +989 -385
- package/dist/src/orgrt/daemon.js.map +1 -1
- package/dist/src/orgrt/decisions.d.ts +2 -2
- package/dist/src/orgrt/decisions.d.ts.map +1 -1
- package/dist/src/orgrt/decisions.js +90 -18
- package/dist/src/orgrt/decisions.js.map +1 -1
- package/dist/src/orgrt/grok-runner.d.ts +29 -3
- package/dist/src/orgrt/grok-runner.d.ts.map +1 -1
- package/dist/src/orgrt/grok-runner.js +286 -150
- package/dist/src/orgrt/grok-runner.js.map +1 -1
- package/dist/src/orgrt/kimicode-runner.d.ts +5 -5
- package/dist/src/orgrt/kimicode-runner.d.ts.map +1 -1
- package/dist/src/orgrt/kimicode-runner.js +53 -32
- package/dist/src/orgrt/kimicode-runner.js.map +1 -1
- package/dist/src/orgrt/mailbox.d.ts +15 -0
- package/dist/src/orgrt/mailbox.d.ts.map +1 -1
- package/dist/src/orgrt/mailbox.js +29 -1
- package/dist/src/orgrt/mailbox.js.map +1 -1
- package/dist/src/orgrt/migrate.d.ts.map +1 -1
- package/dist/src/orgrt/migrate.js +8 -5
- package/dist/src/orgrt/migrate.js.map +1 -1
- package/dist/src/orgrt/opencode-runner.d.ts +1 -1
- package/dist/src/orgrt/opencode-runner.d.ts.map +1 -1
- package/dist/src/orgrt/opencode-runner.js +29 -3
- package/dist/src/orgrt/opencode-runner.js.map +1 -1
- package/dist/src/orgrt/org-memory.d.ts +19 -3
- package/dist/src/orgrt/org-memory.d.ts.map +1 -1
- package/dist/src/orgrt/org-memory.js +110 -38
- package/dist/src/orgrt/org-memory.js.map +1 -1
- package/dist/src/orgrt/pi-rpc-runner.d.ts +3 -1
- package/dist/src/orgrt/pi-rpc-runner.d.ts.map +1 -1
- package/dist/src/orgrt/pi-rpc-runner.js +35 -3
- package/dist/src/orgrt/pi-rpc-runner.js.map +1 -1
- package/dist/src/orgrt/pi-runner.d.ts +25 -2
- package/dist/src/orgrt/pi-runner.d.ts.map +1 -1
- package/dist/src/orgrt/pi-runner.js +271 -152
- package/dist/src/orgrt/pi-runner.js.map +1 -1
- package/dist/src/orgrt/policy.d.ts +1 -0
- package/dist/src/orgrt/policy.d.ts.map +1 -1
- package/dist/src/orgrt/policy.js +199 -39
- package/dist/src/orgrt/policy.js.map +1 -1
- package/dist/src/orgrt/provider.d.ts +4 -0
- package/dist/src/orgrt/provider.d.ts.map +1 -1
- package/dist/src/orgrt/provider.js +16 -0
- package/dist/src/orgrt/provider.js.map +1 -1
- package/dist/src/orgrt/qwen-rpc-runner.d.ts +3 -1
- package/dist/src/orgrt/qwen-rpc-runner.d.ts.map +1 -1
- package/dist/src/orgrt/qwen-rpc-runner.js +35 -3
- package/dist/src/orgrt/qwen-rpc-runner.js.map +1 -1
- package/dist/src/orgrt/qwen-runner.d.ts +30 -3
- package/dist/src/orgrt/qwen-runner.d.ts.map +1 -1
- package/dist/src/orgrt/qwen-runner.js +282 -142
- package/dist/src/orgrt/qwen-runner.js.map +1 -1
- package/dist/src/orgrt/role-slot.d.ts +88 -0
- package/dist/src/orgrt/role-slot.d.ts.map +1 -0
- package/dist/src/orgrt/role-slot.js +133 -0
- package/dist/src/orgrt/role-slot.js.map +1 -0
- package/dist/src/orgrt/runtime-options.d.ts +17 -0
- package/dist/src/orgrt/runtime-options.d.ts.map +1 -0
- package/dist/src/orgrt/runtime-options.js +32 -0
- package/dist/src/orgrt/runtime-options.js.map +1 -0
- package/dist/src/orgrt/scheduler-integration.d.ts +11 -0
- package/dist/src/orgrt/scheduler-integration.d.ts.map +1 -1
- package/dist/src/orgrt/scheduler-integration.js +75 -17
- package/dist/src/orgrt/scheduler-integration.js.map +1 -1
- package/dist/src/orgrt/scheduler.d.ts +4 -0
- package/dist/src/orgrt/scheduler.d.ts.map +1 -1
- package/dist/src/orgrt/scheduler.js +7 -1
- package/dist/src/orgrt/scheduler.js.map +1 -1
- package/dist/src/orgrt/server.d.ts +8 -3
- package/dist/src/orgrt/server.d.ts.map +1 -1
- package/dist/src/orgrt/server.js +48 -13
- package/dist/src/orgrt/server.js.map +1 -1
- package/dist/src/orgrt/session.d.ts +26 -2
- package/dist/src/orgrt/session.d.ts.map +1 -1
- package/dist/src/orgrt/session.js +98 -4
- package/dist/src/orgrt/session.js.map +1 -1
- package/dist/src/orgrt/task-dag.d.ts +5 -0
- package/dist/src/orgrt/task-dag.d.ts.map +1 -1
- package/dist/src/orgrt/task-dag.js +41 -0
- package/dist/src/orgrt/task-dag.js.map +1 -1
- package/dist/src/orgrt/test-loop.js +2 -2
- package/dist/src/orgrt/test-loop.js.map +1 -1
- package/dist/src/orgrt/types.d.ts +14 -2
- package/dist/src/orgrt/types.d.ts.map +1 -1
- package/dist/src/orgrt/types.js +15 -1
- package/dist/src/orgrt/types.js.map +1 -1
- package/dist/src/orgrt/vercel-runner.d.ts.map +1 -1
- package/dist/src/orgrt/vercel-runner.js +4 -0
- package/dist/src/orgrt/vercel-runner.js.map +1 -1
- package/dist/src/ui/routes-org.mjs +27 -7
- package/dist/src/ui/server.mjs +82 -48
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -2
- package/dist/src/ui/data/mastermind-sessions.json +0 -1
|
@@ -28,7 +28,7 @@ This skill is invoked by `mastermind:issue-detail` or directly via `/mastermind:
|
|
|
28
28
|
## Issue Status Flow
|
|
29
29
|
|
|
30
30
|
```
|
|
31
|
-
|
|
31
|
+
todo → in_progress → in_review → done
|
|
32
32
|
↓
|
|
33
33
|
blocked → in_progress
|
|
34
34
|
↓
|
|
@@ -52,7 +52,7 @@ orgFile=".monomind/orgs/${org_name}.json"
|
|
|
52
52
|
[ ! -f "$orgFile" ] && { echo "ERROR: Org '${org_name}' not found."; exit 1; }
|
|
53
53
|
|
|
54
54
|
issuesFile=".monomind/orgs/${org_name}-issues.json"
|
|
55
|
-
[ ! -f "$issuesFile" ] && { echo "ERROR: No issues file for org '$org_name'. Create
|
|
55
|
+
[ ! -f "$issuesFile" ] && { echo "ERROR: No issues file for org '$org_name'. Create issues via /mastermind:issues --action create."; exit 1; }
|
|
56
56
|
|
|
57
57
|
issueDef=$(jq -r --arg id "$issue_id" '(.issues // [])[] | select(.id == $id or .slug == $id)' "$issuesFile")
|
|
58
58
|
[ -z "$issueDef" ] && { echo "ERROR: Issue '$issue_id' not found in org '$org_name'."; exit 1; }
|
|
@@ -64,6 +64,38 @@ days=${days:-14}
|
|
|
64
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
65
|
```
|
|
66
66
|
|
|
67
|
+
Normalize any legacy records written by a pre-2.10 version of these skills. Idempotent — safe to run on every load.
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
python3 - "$issuesFile" <<'PYEOF'
|
|
71
|
+
import json, sys
|
|
72
|
+
path = sys.argv[1]
|
|
73
|
+
data = json.load(open(path))
|
|
74
|
+
RENAME = {
|
|
75
|
+
"assignee_id": "assigneeId", "assigned_to": "assigneeId",
|
|
76
|
+
"created_at": "createdAt", "updated_at": "updatedAt",
|
|
77
|
+
"closed_at": "closedAt", "project_id": "projectId",
|
|
78
|
+
"parent_id": "parentId", "recovery_status": "recoveryStatus",
|
|
79
|
+
"lastActivityAt": "updatedAt",
|
|
80
|
+
}
|
|
81
|
+
changed = False
|
|
82
|
+
for iss in data.get("issues", []):
|
|
83
|
+
for old, new in RENAME.items():
|
|
84
|
+
if old in iss:
|
|
85
|
+
iss.setdefault(new, iss.pop(old))
|
|
86
|
+
iss.pop(old, None)
|
|
87
|
+
changed = True
|
|
88
|
+
if iss.get("status") == "open":
|
|
89
|
+
iss["status"] = "todo"
|
|
90
|
+
changed = True
|
|
91
|
+
if changed:
|
|
92
|
+
tmp = path + ".tmp"
|
|
93
|
+
with open(tmp, "w") as f:
|
|
94
|
+
json.dump(data, f, indent=2)
|
|
95
|
+
import os; os.replace(tmp, path)
|
|
96
|
+
PYEOF
|
|
97
|
+
```
|
|
98
|
+
|
|
67
99
|
---
|
|
68
100
|
|
|
69
101
|
## Step 2 — Execute Action
|
|
@@ -77,16 +109,17 @@ echo "────────────────────────
|
|
|
77
109
|
echo "$issueDef" | jq -r '
|
|
78
110
|
" ID: \(.id)",
|
|
79
111
|
" Title: \(.title // "(no title)")",
|
|
80
|
-
" Status: \(.status // "
|
|
112
|
+
" Status: \(.status // "todo")",
|
|
81
113
|
" Priority: \(.priority // "medium")",
|
|
82
|
-
" Assignee: \(.
|
|
83
|
-
"
|
|
84
|
-
"
|
|
85
|
-
"
|
|
114
|
+
" Assignee: \(.assigneeId // "(unassigned)")",
|
|
115
|
+
" Agent: \(.assigneeAgentId // "(none)")",
|
|
116
|
+
" Project: \(.projectId // "(none)")",
|
|
117
|
+
" Created: \(.createdAt // "-")",
|
|
118
|
+
" Updated: \(.updatedAt // "-")"
|
|
86
119
|
'
|
|
87
120
|
|
|
88
121
|
# Sub-issues
|
|
89
|
-
subCount=$(jq --arg pid "$resolvedId" '[(.issues // [])[] | select(.
|
|
122
|
+
subCount=$(jq --arg pid "$resolvedId" '[(.issues // [])[] | select(.parentId == $pid)] | length' "$issuesFile" 2>/dev/null || echo 0)
|
|
90
123
|
echo " Sub-issues: $subCount"
|
|
91
124
|
|
|
92
125
|
# Attachments
|
|
@@ -94,7 +127,7 @@ attCount=$(echo "$issueDef" | jq -r '(.attachments // []) | length')
|
|
|
94
127
|
echo " Attachments: $attCount"
|
|
95
128
|
|
|
96
129
|
# Recovery
|
|
97
|
-
recoveryStatus=$(echo "$issueDef" | jq -r '.
|
|
130
|
+
recoveryStatus=$(echo "$issueDef" | jq -r '.recoveryStatus // "none"')
|
|
98
131
|
[ "$recoveryStatus" != "none" ] && echo "" && echo " RECOVERY STATUS: $recoveryStatus"
|
|
99
132
|
|
|
100
133
|
# Description
|
|
@@ -169,15 +202,15 @@ printf "%-24s %-12s %-10s %s\n" "ID" "STATUS" "PRIORITY" "TITLE"
|
|
|
169
202
|
echo "────────────────────────────────────────────────────────"
|
|
170
203
|
|
|
171
204
|
count=0
|
|
172
|
-
jq -r --arg pid "$resolvedId" '(.issues // [])[] | select(.
|
|
173
|
-
[.id, (.status // "
|
|
205
|
+
jq -r --arg pid "$resolvedId" '(.issues // [])[] | select(.parentId == $pid) |
|
|
206
|
+
[.id, (.status // "todo"), (.priority // "medium"), (.title // "(no title)")] | @tsv' \
|
|
174
207
|
"$issuesFile" 2>/dev/null | while IFS=$'\t' read -r id st pri title; do
|
|
175
208
|
printf "%-24s %-12s %-10s %s\n" "$id" "$st" "$pri" "$title"
|
|
176
209
|
count=$((count + 1))
|
|
177
210
|
done
|
|
178
211
|
|
|
179
212
|
echo ""
|
|
180
|
-
echo "To create a sub-issue: /mastermind:
|
|
213
|
+
echo "To create a sub-issue: /mastermind:issues --org $org_name --action create --title '<title>' --parent-id $issue_id"
|
|
181
214
|
```
|
|
182
215
|
|
|
183
216
|
### attachments
|
|
@@ -221,10 +254,16 @@ exists=$(jq --arg id "$assignee_id" '[(.roles // [])[] | select(.id == $id)] | l
|
|
|
221
254
|
ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
222
255
|
tmp="${issuesFile}.tmp"
|
|
223
256
|
jq --arg id "$resolvedId" --arg ag "$assignee_id" --arg ts "$ts" \
|
|
224
|
-
'.issues = [(.issues // [])[] | if .id == $id then .
|
|
257
|
+
'.issues = [(.issues // [])[] | if .id == $id then .assigneeId = $ag | .assigneeAgentId = $ag | .assigneeUserId = null | .updatedAt = $ts else . end]' \
|
|
225
258
|
"$issuesFile" > "$tmp" && mv "$tmp" "$issuesFile"
|
|
226
259
|
|
|
227
260
|
echo "Issue '$issue_id' assigned to '$assignee_id'."
|
|
261
|
+
|
|
262
|
+
activityFile=".monomind/orgs/${org_name}-activity.jsonl"
|
|
263
|
+
currentStatus=$(jq -r --arg id "$resolvedId" '(.issues // [])[] | select(.id == $id) | .status // "todo"' "$issuesFile")
|
|
264
|
+
jq -cn --arg iid "$resolvedId" --arg ts "$ts" --arg st "$currentStatus" --arg ag "$assignee_id" --arg sm "assign $resolvedId" \
|
|
265
|
+
'{issue_id:$iid, ts:$ts, status:$st, tokens:null, agent:$ag, type:"assign", summary:$sm}' \
|
|
266
|
+
>> "$activityFile"
|
|
228
267
|
```
|
|
229
268
|
|
|
230
269
|
### close
|
|
@@ -233,9 +272,14 @@ echo "Issue '$issue_id' assigned to '$assignee_id'."
|
|
|
233
272
|
ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
234
273
|
tmp="${issuesFile}.tmp"
|
|
235
274
|
jq --arg id "$resolvedId" --arg ts "$ts" \
|
|
236
|
-
'.issues = [(.issues // [])[] | if .id == $id then .status = "done" | .
|
|
275
|
+
'.issues = [(.issues // [])[] | if .id == $id then .status = "done" | .updatedAt = $ts | .closedAt = $ts else . end]' \
|
|
237
276
|
"$issuesFile" > "$tmp" && mv "$tmp" "$issuesFile"
|
|
238
277
|
echo "Issue '$issue_id' → done (closed at $ts)."
|
|
278
|
+
|
|
279
|
+
activityFile=".monomind/orgs/${org_name}-activity.jsonl"
|
|
280
|
+
jq -cn --arg iid "$resolvedId" --arg ts "$ts" --arg st "done" --arg ag "operator" --arg sm "close $resolvedId" \
|
|
281
|
+
'{issue_id:$iid, ts:$ts, status:$st, tokens:null, agent:$ag, type:"close", summary:$sm}' \
|
|
282
|
+
>> "$activityFile"
|
|
239
283
|
```
|
|
240
284
|
|
|
241
285
|
### reopen
|
|
@@ -244,9 +288,14 @@ echo "Issue '$issue_id' → done (closed at $ts)."
|
|
|
244
288
|
ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
245
289
|
tmp="${issuesFile}.tmp"
|
|
246
290
|
jq --arg id "$resolvedId" --arg ts "$ts" \
|
|
247
|
-
'.issues = [(.issues // [])[] | if .id == $id then .status = "
|
|
291
|
+
'.issues = [(.issues // [])[] | if .id == $id then .status = "todo" | .updatedAt = $ts | .closedAt = null else . end]' \
|
|
248
292
|
"$issuesFile" > "$tmp" && mv "$tmp" "$issuesFile"
|
|
249
293
|
echo "Issue '$issue_id' → reopened."
|
|
294
|
+
|
|
295
|
+
activityFile=".monomind/orgs/${org_name}-activity.jsonl"
|
|
296
|
+
jq -cn --arg iid "$resolvedId" --arg ts "$ts" --arg st "todo" --arg ag "operator" --arg sm "reopen $resolvedId" \
|
|
297
|
+
'{issue_id:$iid, ts:$ts, status:$st, tokens:null, agent:$ag, type:"reopen", summary:$sm}' \
|
|
298
|
+
>> "$activityFile"
|
|
250
299
|
```
|
|
251
300
|
|
|
252
301
|
### recover
|
|
@@ -263,12 +312,17 @@ newStatus=$([ "$recovery_action" = "accept" ] && echo "in_progress" || echo "can
|
|
|
263
312
|
tmp="${issuesFile}.tmp"
|
|
264
313
|
jq --arg id "$resolvedId" --arg st "$newStatus" --arg ts "$ts" --arg ra "$recovery_action" \
|
|
265
314
|
'.issues = [(.issues // [])[] | if .id == $id then
|
|
266
|
-
.status = $st | .
|
|
315
|
+
.status = $st | .recoveryStatus = $ra | .updatedAt = $ts
|
|
267
316
|
else . end]' \
|
|
268
317
|
"$issuesFile" > "$tmp" && mv "$tmp" "$issuesFile"
|
|
269
318
|
|
|
270
319
|
echo "Recovery action '$recovery_action' applied to '$issue_id'."
|
|
271
320
|
echo " New status: $newStatus"
|
|
321
|
+
|
|
322
|
+
activityFile=".monomind/orgs/${org_name}-activity.jsonl"
|
|
323
|
+
jq -cn --arg iid "$resolvedId" --arg ts "$ts" --arg st "$newStatus" --arg ag "operator" --arg sm "recover $resolvedId" \
|
|
324
|
+
'{issue_id:$iid, ts:$ts, status:$st, tokens:null, agent:$ag, type:"recover", summary:$sm}' \
|
|
325
|
+
>> "$activityFile"
|
|
272
326
|
```
|
|
273
327
|
|
|
274
328
|
---
|
|
@@ -18,13 +18,14 @@ This skill is invoked by `mastermind:issues` or directly via `/mastermind:issues
|
|
|
18
18
|
- `action`: list | create | update | close | search
|
|
19
19
|
- `issue_id`: issue ID (required for update/close)
|
|
20
20
|
- `query`: search term (for search)
|
|
21
|
-
- `status`:
|
|
21
|
+
- `status`: todo | in_progress | blocked | in_review | done | cancelled (filter)
|
|
22
22
|
- `assignee`: agent ID filter
|
|
23
23
|
- `workspace`: workspace ID filter
|
|
24
24
|
- `title`: issue title (for create)
|
|
25
25
|
- `description`: issue body (for create)
|
|
26
26
|
- `priority`: low | medium | high | urgent (for create/update)
|
|
27
27
|
- `limit`: max results (default: 50)
|
|
28
|
+
- `parent_id`: parent issue id, making the new issue a sub-issue (for create)
|
|
28
29
|
- `caller`: command | master
|
|
29
30
|
|
|
30
31
|
---
|
|
@@ -47,6 +48,45 @@ issuesFile=".monomind/orgs/${org_name}-issues.json"
|
|
|
47
48
|
limit="${limit:-50}"
|
|
48
49
|
```
|
|
49
50
|
|
|
51
|
+
Normalize any legacy records written by a pre-2.10 version of these skills. Idempotent — safe to run on every load.
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
python3 - "$issuesFile" <<'PYEOF'
|
|
55
|
+
import json, sys
|
|
56
|
+
path = sys.argv[1]
|
|
57
|
+
data = json.load(open(path))
|
|
58
|
+
RENAME = {
|
|
59
|
+
"assignee_id": "assigneeId", "assigned_to": "assigneeId",
|
|
60
|
+
"created_at": "createdAt", "updated_at": "updatedAt",
|
|
61
|
+
"closed_at": "closedAt", "project_id": "projectId",
|
|
62
|
+
"parent_id": "parentId", "recovery_status": "recoveryStatus",
|
|
63
|
+
"lastActivityAt": "updatedAt",
|
|
64
|
+
}
|
|
65
|
+
changed = False
|
|
66
|
+
for iss in data.get("issues", []):
|
|
67
|
+
for old, new in RENAME.items():
|
|
68
|
+
if old in iss:
|
|
69
|
+
iss.setdefault(new, iss.pop(old))
|
|
70
|
+
iss.pop(old, None)
|
|
71
|
+
changed = True
|
|
72
|
+
if iss.get("status") == "open":
|
|
73
|
+
iss["status"] = "todo"
|
|
74
|
+
changed = True
|
|
75
|
+
if changed:
|
|
76
|
+
tmp = path + ".tmp"
|
|
77
|
+
with open(tmp, "w") as f:
|
|
78
|
+
json.dump(data, f, indent=2)
|
|
79
|
+
import os; os.replace(tmp, path)
|
|
80
|
+
PYEOF
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
> **These issues are not auto-consumed by the org runtime.** `OrgDaemon` builds its `TaskDag`
|
|
84
|
+
> fresh in memory on every start and never reads `<org>-issues.json` (verified: zero references
|
|
85
|
+
> in `packages/@monomind/cli/src/orgrt/`). Issues created here are tracked by the
|
|
86
|
+
> `mastermind-issues` / `mastermind-my-issues` / `mastermind-liveness` skills and shown in the
|
|
87
|
+
> dashboard, but running `monomind org run <org>` will not pick them up. Drive execution from
|
|
88
|
+
> this file with `mastermind-execute`, or pass work explicitly via `org run --task`.
|
|
89
|
+
|
|
50
90
|
---
|
|
51
91
|
|
|
52
92
|
## Step 2 — Execute Action
|
|
@@ -82,7 +122,7 @@ else:
|
|
|
82
122
|
print(" " + "─" * 102)
|
|
83
123
|
for iss in issues:
|
|
84
124
|
iid = iss.get("id","?")[:28]
|
|
85
|
-
st = iss.get("status","
|
|
125
|
+
st = iss.get("status","todo")[:14]
|
|
86
126
|
pri = iss.get("priority","medium")[:8]
|
|
87
127
|
title = (iss.get("title") or "-")[:38]
|
|
88
128
|
asgn = (iss.get("assigneeTitle") or iss.get("assigneeId") or "—")[:20]
|
|
@@ -137,24 +177,42 @@ PYEOF
|
|
|
137
177
|
[ -z "$title" ] && { echo "ERROR: --title required."; exit 1; }
|
|
138
178
|
|
|
139
179
|
ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
140
|
-
newId="issue-$(python3 -c 'import time; print(int(time.time()*1000))')"
|
|
180
|
+
newId="issue-$(python3 -c 'import time; print(int(time.time()*1000))')-001"
|
|
181
|
+
|
|
182
|
+
python3 - "$issuesFile" "$newId" "$title" "${description:-}" "${priority:-medium}" "${assignee:-}" "${workspace:-}" "${parent_id:-}" "$ts" <<'PYEOF'
|
|
183
|
+
import json, os, sys
|
|
184
|
+
path, iid, title, desc, pri, asgn, ws, parent, ts = sys.argv[1:]
|
|
185
|
+
|
|
186
|
+
VALID_PRIORITY = {"low","medium","high","urgent"}
|
|
187
|
+
if pri not in VALID_PRIORITY:
|
|
188
|
+
print(f"ERROR: priority '{pri}' must be one of {sorted(VALID_PRIORITY)}.")
|
|
189
|
+
sys.exit(1)
|
|
141
190
|
|
|
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
191
|
data = json.load(open(path))
|
|
192
|
+
issues = data.setdefault("issues", [])
|
|
193
|
+
|
|
194
|
+
if parent and not any(i.get("id") == parent for i in issues):
|
|
195
|
+
print(f"ERROR: parent issue '{parent}' not found.")
|
|
196
|
+
sys.exit(1)
|
|
197
|
+
|
|
146
198
|
issue = {
|
|
147
199
|
"id": iid, "title": title, "description": desc,
|
|
148
|
-
"status": "
|
|
149
|
-
"assigneeId": asgn or None,
|
|
150
|
-
"
|
|
200
|
+
"status": "todo", "priority": pri,
|
|
201
|
+
"assigneeId": asgn or None,
|
|
202
|
+
"assigneeAgentId": None, "assigneeUserId": None,
|
|
203
|
+
"parentId": parent or None,
|
|
204
|
+
"projectId": None, "workspaceId": ws or None,
|
|
205
|
+
"blockedByIssueIds": [],
|
|
206
|
+
"createdAt": ts, "updatedAt": ts,
|
|
151
207
|
}
|
|
152
|
-
|
|
153
|
-
|
|
208
|
+
issues.append(issue)
|
|
209
|
+
tmp = path + ".tmp"
|
|
210
|
+
with open(tmp, "w") as f:
|
|
154
211
|
json.dump(data, f, indent=2)
|
|
212
|
+
os.replace(tmp, path)
|
|
155
213
|
print(f" Created: {iid}")
|
|
156
214
|
print(f" Title: {title}")
|
|
157
|
-
print(f" Status:
|
|
215
|
+
print(f" Status: todo | Priority: {pri}" + (f" | Parent: {parent}" if parent else ""))
|
|
158
216
|
PYEOF
|
|
159
217
|
```
|
|
160
218
|
|
|
@@ -165,8 +223,18 @@ PYEOF
|
|
|
165
223
|
ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
166
224
|
|
|
167
225
|
python3 - "$issuesFile" "$issue_id" "${status:-}" "${priority:-}" "${title:-}" "$ts" <<'PYEOF'
|
|
168
|
-
import json, sys
|
|
226
|
+
import json, os, sys
|
|
169
227
|
path, iid, new_st, new_pri, new_title, ts = sys.argv[1:]
|
|
228
|
+
|
|
229
|
+
VALID_STATUS = {"todo","in_progress","blocked","in_review","done","cancelled"}
|
|
230
|
+
VALID_PRIORITY = {"low","medium","high","urgent"}
|
|
231
|
+
if new_st and new_st not in VALID_STATUS:
|
|
232
|
+
print(f"ERROR: status '{new_st}' must be one of {sorted(VALID_STATUS)}.")
|
|
233
|
+
sys.exit(1)
|
|
234
|
+
if new_pri and new_pri not in VALID_PRIORITY:
|
|
235
|
+
print(f"ERROR: priority '{new_pri}' must be one of {sorted(VALID_PRIORITY)}.")
|
|
236
|
+
sys.exit(1)
|
|
237
|
+
|
|
170
238
|
data = json.load(open(path))
|
|
171
239
|
issues = data.get("issues", [])
|
|
172
240
|
found = False
|
|
@@ -182,8 +250,10 @@ if not found:
|
|
|
182
250
|
print(f"ERROR: Issue '{iid}' not found.")
|
|
183
251
|
sys.exit(1)
|
|
184
252
|
data["issues"] = issues
|
|
185
|
-
|
|
253
|
+
tmp = path + ".tmp"
|
|
254
|
+
with open(tmp, "w") as f:
|
|
186
255
|
json.dump(data, f, indent=2)
|
|
256
|
+
os.replace(tmp, path)
|
|
187
257
|
print(f" Updated: {iid} (updatedAt: {ts})")
|
|
188
258
|
PYEOF
|
|
189
259
|
```
|
|
@@ -195,7 +265,7 @@ PYEOF
|
|
|
195
265
|
ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
196
266
|
|
|
197
267
|
python3 - "$issuesFile" "$issue_id" "$ts" <<'PYEOF'
|
|
198
|
-
import json, sys
|
|
268
|
+
import json, os, sys
|
|
199
269
|
path, iid, ts = sys.argv[1], sys.argv[2], sys.argv[3]
|
|
200
270
|
data = json.load(open(path))
|
|
201
271
|
issues = data.get("issues", [])
|
|
@@ -211,14 +281,39 @@ if not found:
|
|
|
211
281
|
print(f"ERROR: Issue '{iid}' not found.")
|
|
212
282
|
sys.exit(1)
|
|
213
283
|
data["issues"] = issues
|
|
214
|
-
|
|
284
|
+
tmp = path + ".tmp"
|
|
285
|
+
with open(tmp, "w") as f:
|
|
215
286
|
json.dump(data, f, indent=2)
|
|
287
|
+
os.replace(tmp, path)
|
|
216
288
|
print(f" Closed: {iid} (closedAt: {ts})")
|
|
217
289
|
PYEOF
|
|
218
290
|
```
|
|
219
291
|
|
|
220
292
|
---
|
|
221
293
|
|
|
294
|
+
## Step 2.5 — Append Activity Record
|
|
295
|
+
|
|
296
|
+
After any `create`, `update`, or `close` action succeeds, append one line to the org's
|
|
297
|
+
activity log. This is the only writer for `<org>-activity.jsonl`; seven skills read it.
|
|
298
|
+
|
|
299
|
+
```bash
|
|
300
|
+
activityFile=".monomind/orgs/${org_name}-activity.jsonl"
|
|
301
|
+
jq -cn \
|
|
302
|
+
--arg iid "${affected_issue_id}" \
|
|
303
|
+
--arg ts "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
|
|
304
|
+
--arg st "${resulting_status}" \
|
|
305
|
+
--arg ag "${assignee:-operator}" \
|
|
306
|
+
--arg act "${action}" \
|
|
307
|
+
--arg sm "${action} ${affected_issue_id}" \
|
|
308
|
+
'{issue_id:$iid, ts:$ts, status:$st, tokens:null, agent:$ag, type:$act, summary:$sm}' \
|
|
309
|
+
>> "$activityFile"
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
`affected_issue_id` is `$newId` for `create` and `$issue_id` for `update`/`close`;
|
|
313
|
+
`resulting_status` is `todo`, the new status, or `done` respectively.
|
|
314
|
+
|
|
315
|
+
---
|
|
316
|
+
|
|
222
317
|
## Step 3 — Return Output
|
|
223
318
|
|
|
224
319
|
```yaml
|
|
@@ -64,6 +64,38 @@ issuesFile=".monomind/orgs/${org_name}-issues.json"
|
|
|
64
64
|
stateFile=".monomind/orgs/${org_name}-state.json"
|
|
65
65
|
```
|
|
66
66
|
|
|
67
|
+
Normalize any legacy records written by a pre-2.10 version of these skills. Idempotent — safe to run on every load. Guarded because this skill tolerates a missing issues file.
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
[ -f "$issuesFile" ] && python3 - "$issuesFile" <<'PYEOF'
|
|
71
|
+
import json, sys
|
|
72
|
+
path = sys.argv[1]
|
|
73
|
+
data = json.load(open(path))
|
|
74
|
+
RENAME = {
|
|
75
|
+
"assignee_id": "assigneeId", "assigned_to": "assigneeId",
|
|
76
|
+
"created_at": "createdAt", "updated_at": "updatedAt",
|
|
77
|
+
"closed_at": "closedAt", "project_id": "projectId",
|
|
78
|
+
"parent_id": "parentId", "recovery_status": "recoveryStatus",
|
|
79
|
+
"lastActivityAt": "updatedAt",
|
|
80
|
+
}
|
|
81
|
+
changed = False
|
|
82
|
+
for iss in data.get("issues", []):
|
|
83
|
+
for old, new in RENAME.items():
|
|
84
|
+
if old in iss:
|
|
85
|
+
iss.setdefault(new, iss.pop(old))
|
|
86
|
+
iss.pop(old, None)
|
|
87
|
+
changed = True
|
|
88
|
+
if iss.get("status") == "open":
|
|
89
|
+
iss["status"] = "todo"
|
|
90
|
+
changed = True
|
|
91
|
+
if changed:
|
|
92
|
+
tmp = path + ".tmp"
|
|
93
|
+
with open(tmp, "w") as f:
|
|
94
|
+
json.dump(data, f, indent=2)
|
|
95
|
+
import os; os.replace(tmp, path)
|
|
96
|
+
PYEOF
|
|
97
|
+
```
|
|
98
|
+
|
|
67
99
|
---
|
|
68
100
|
|
|
69
101
|
## Step 2 — Execute Action
|
|
@@ -108,35 +140,44 @@ now = datetime.utcnow()
|
|
|
108
140
|
|
|
109
141
|
for iss in issues:
|
|
110
142
|
status = iss.get("status","")
|
|
111
|
-
|
|
143
|
+
iid = iss.get("id","?")
|
|
144
|
+
title = (iss.get("title") or "?")[:50]
|
|
145
|
+
|
|
146
|
+
if status in terminal_statuses:
|
|
147
|
+
continue
|
|
148
|
+
if status not in non_terminal_statuses:
|
|
149
|
+
# Silently skipping an unknown status is how issues become invisible.
|
|
150
|
+
warnings.append((iid, title, status, f"unknown status '{status}' — outside the canonical vocabulary"))
|
|
112
151
|
continue
|
|
113
152
|
|
|
114
|
-
aId = iss.get("assigneeAgentId")
|
|
153
|
+
aId = iss.get("assigneeAgentId")
|
|
115
154
|
uId = iss.get("assigneeUserId")
|
|
116
|
-
iid = iss.get("id","?")
|
|
117
|
-
title = iss.get("title","?")[:50]
|
|
118
155
|
|
|
119
|
-
#
|
|
156
|
+
# Human-owned: the next move belongs to a person, not an execution path.
|
|
120
157
|
if uId and not aId:
|
|
121
158
|
healthy.append((iid, title, status, "user-owned"))
|
|
122
159
|
continue
|
|
123
160
|
|
|
124
|
-
# Evaluate liveness
|
|
125
161
|
paths = []
|
|
126
162
|
|
|
127
163
|
run_id = iss.get("executionRunId") or iss.get("checkoutRunId")
|
|
128
164
|
if run_id and run_id in active_runs:
|
|
129
165
|
paths.append("active-run")
|
|
130
166
|
|
|
167
|
+
resolved_ids = {i.get("id") for i in issues if i.get("status") in terminal_statuses}
|
|
131
168
|
blockers = iss.get("blockedByIssueIds") or []
|
|
132
|
-
if status == "blocked"
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
169
|
+
if status == "blocked":
|
|
170
|
+
if blockers:
|
|
171
|
+
unresolved = [b for b in blockers if b not in resolved_ids]
|
|
172
|
+
if unresolved:
|
|
173
|
+
paths.append(f"blocked-by:{','.join(unresolved[:2])}")
|
|
174
|
+
else:
|
|
175
|
+
warnings.append((iid, title, status, "all blockers resolved but issue still blocked"))
|
|
176
|
+
elif not iss.get("recoveryActions"):
|
|
177
|
+
# Liveness Contract: blocked requires a named dependency or an
|
|
178
|
+
# explicit human decision. This issue records neither.
|
|
179
|
+
stalled.append((iid, title, status, "blocked with no blockedByIssueIds and no recovery action"))
|
|
180
|
+
continue
|
|
140
181
|
|
|
141
182
|
if iss.get("executionPolicy", {}).get("monitor", {}).get("nextCheckAt"):
|
|
142
183
|
paths.append("monitor")
|
|
@@ -150,7 +191,10 @@ for iss in issues:
|
|
|
150
191
|
if iss.get("currentParticipant"):
|
|
151
192
|
paths.append("participant")
|
|
152
193
|
|
|
153
|
-
|
|
194
|
+
if status == "in_review" and not (iss.get("reviewerId") or iss.get("currentParticipant")):
|
|
195
|
+
stalled.append((iid, title, status, "in_review with no named reviewer"))
|
|
196
|
+
continue
|
|
197
|
+
|
|
154
198
|
if status == "in_progress" and aId and not paths:
|
|
155
199
|
updated = iss.get("updatedAt","")
|
|
156
200
|
if updated:
|
|
@@ -159,16 +203,19 @@ for iss in issues:
|
|
|
159
203
|
if age > timedelta(hours=2):
|
|
160
204
|
stalled.append((iid, title, status, f"in_progress {int(age.total_seconds()//3600)}h with no active path"))
|
|
161
205
|
continue
|
|
162
|
-
except:
|
|
206
|
+
except Exception:
|
|
207
|
+
pass
|
|
163
208
|
stalled.append((iid, title, status, "in_progress with no active execution path"))
|
|
164
209
|
continue
|
|
165
210
|
|
|
166
|
-
if
|
|
167
|
-
warnings.append((iid, title, status, "todo assigned to agent — may need wakeup"))
|
|
168
|
-
elif paths:
|
|
211
|
+
if paths:
|
|
169
212
|
healthy.append((iid, title, status, " + ".join(paths)))
|
|
213
|
+
elif not aId:
|
|
214
|
+
warnings.append((iid, title, status, "no assignee — nothing will pick this up"))
|
|
215
|
+
elif status == "todo":
|
|
216
|
+
warnings.append((iid, title, status, "todo assigned to agent — may need wakeup"))
|
|
170
217
|
else:
|
|
171
|
-
|
|
218
|
+
stalled.append((iid, title, status, f"{status} with an agent assignee but no execution path"))
|
|
172
219
|
|
|
173
220
|
print(f" ✓ Healthy: {len(healthy)}")
|
|
174
221
|
if healthy:
|
|
@@ -206,7 +253,7 @@ Claim an issue for execution by an agent run. Sets `checkoutRunId` and `executio
|
|
|
206
253
|
ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
207
254
|
|
|
208
255
|
python3 - "$issuesFile" "$issue_id" "$agent_id" "$run_id" "$ts" <<'PYEOF'
|
|
209
|
-
import json, sys
|
|
256
|
+
import json, os, sys
|
|
210
257
|
|
|
211
258
|
path, iid, agentId, runId, ts = sys.argv[1:]
|
|
212
259
|
data = json.load(open(path))
|
|
@@ -224,6 +271,7 @@ for iss in issues:
|
|
|
224
271
|
iss["executionRunId"] = runId
|
|
225
272
|
iss["assigneeId"] = agentId
|
|
226
273
|
iss["assigneeAgentId"]= agentId
|
|
274
|
+
iss["assigneeUserId"] = None
|
|
227
275
|
iss["status"] = "in_progress"
|
|
228
276
|
iss["checkedOutAt"] = ts
|
|
229
277
|
iss["updatedAt"] = ts
|
|
@@ -237,9 +285,16 @@ if not found:
|
|
|
237
285
|
sys.exit(1)
|
|
238
286
|
|
|
239
287
|
data["issues"] = issues
|
|
240
|
-
|
|
288
|
+
tmp = path + ".tmp"
|
|
289
|
+
with open(tmp, "w") as f:
|
|
241
290
|
json.dump(data, f, indent=2)
|
|
291
|
+
os.replace(tmp, path)
|
|
242
292
|
PYEOF
|
|
293
|
+
|
|
294
|
+
activityFile=".monomind/orgs/${org_name}-activity.jsonl"
|
|
295
|
+
jq -cn --arg iid "$issue_id" --arg ts "$ts" --arg st "in_progress" --arg ag "$agent_id" --arg sm "checkout $issue_id" \
|
|
296
|
+
'{issue_id:$iid, ts:$ts, status:$st, tokens:null, agent:$ag, type:"checkout", summary:$sm}' \
|
|
297
|
+
>> "$activityFile"
|
|
243
298
|
```
|
|
244
299
|
|
|
245
300
|
### release
|
|
@@ -269,13 +324,21 @@ for iss in issues:
|
|
|
269
324
|
print(f" RELEASED: Checkout cleared for issue {iid}")
|
|
270
325
|
print(f" Status remains: {iss.get('status','?')} — update separately if needed.")
|
|
271
326
|
data["issues"] = issues
|
|
272
|
-
|
|
327
|
+
tmp = path + ".tmp"
|
|
328
|
+
with open(tmp, "w") as f:
|
|
273
329
|
json.dump(data, f, indent=2)
|
|
330
|
+
os.replace(tmp, path)
|
|
274
331
|
sys.exit(0)
|
|
275
332
|
|
|
276
333
|
print(f" ERROR: Issue '{iid}' not found.")
|
|
277
334
|
sys.exit(1)
|
|
278
335
|
PYEOF
|
|
336
|
+
|
|
337
|
+
activityFile=".monomind/orgs/${org_name}-activity.jsonl"
|
|
338
|
+
currentStatus=$(jq -r --arg id "$issue_id" '(.issues // [])[] | select(.id == $id) | .status // "todo"' "$issuesFile")
|
|
339
|
+
jq -cn --arg iid "$issue_id" --arg ts "$ts" --arg st "$currentStatus" --arg ag "${agent_id:-operator}" --arg sm "release $issue_id" \
|
|
340
|
+
'{issue_id:$iid, ts:$ts, status:$st, tokens:null, agent:$ag, type:"release", summary:$sm}' \
|
|
341
|
+
>> "$activityFile"
|
|
279
342
|
```
|
|
280
343
|
|
|
281
344
|
### wakeup
|
|
@@ -296,7 +359,7 @@ if not iss:
|
|
|
296
359
|
print(f" ERROR: Issue '{iid}' not found.")
|
|
297
360
|
sys.exit(1)
|
|
298
361
|
|
|
299
|
-
checkout_agent = iss.get("assigneeAgentId") or
|
|
362
|
+
checkout_agent = iss.get("assigneeAgentId") or ""
|
|
300
363
|
checkout_run = iss.get("checkoutRunId","")
|
|
301
364
|
|
|
302
365
|
# Port of Paperclip's shouldWakeAssigneeOnCheckout logic
|
|
@@ -338,7 +401,7 @@ ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
|
338
401
|
recoveryId="recovery-$(python3 -c 'import time; print(int(time.time()*1000))')"
|
|
339
402
|
|
|
340
403
|
python3 - "$issuesFile" "$issue_id" "$recoveryId" "${agent_id:-operator}" "$reason" "$ts" <<'PYEOF'
|
|
341
|
-
import json, sys
|
|
404
|
+
import json, os, sys
|
|
342
405
|
|
|
343
406
|
path, iid, rid, owner, cause, ts = sys.argv[1:]
|
|
344
407
|
data = json.load(open(path))
|
|
@@ -359,8 +422,10 @@ for iss in issues:
|
|
|
359
422
|
iss["status"] = "blocked"
|
|
360
423
|
iss["updatedAt"] = ts
|
|
361
424
|
data["issues"] = issues
|
|
362
|
-
|
|
425
|
+
tmp = path + ".tmp"
|
|
426
|
+
with open(tmp, "w") as f:
|
|
363
427
|
json.dump(data, f, indent=2)
|
|
428
|
+
os.replace(tmp, path)
|
|
364
429
|
print(f" RECOVERY ACTION FILED: {rid}")
|
|
365
430
|
print(f" Issue {iid} → status: blocked (pending recovery)")
|
|
366
431
|
print(f" Owner: {owner}")
|
|
@@ -371,6 +436,11 @@ for iss in issues:
|
|
|
371
436
|
print(f" ERROR: Issue '{iid}' not found.")
|
|
372
437
|
sys.exit(1)
|
|
373
438
|
PYEOF
|
|
439
|
+
|
|
440
|
+
activityFile=".monomind/orgs/${org_name}-activity.jsonl"
|
|
441
|
+
jq -cn --arg iid "$issue_id" --arg ts "$ts" --arg st "blocked" --arg ag "${agent_id:-operator}" --arg sm "recover $issue_id" \
|
|
442
|
+
'{issue_id:$iid, ts:$ts, status:$st, tokens:null, agent:$ag, type:"recover", summary:$sm}' \
|
|
443
|
+
>> "$activityFile"
|
|
374
444
|
```
|
|
375
445
|
|
|
376
446
|
---
|