@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.
- package/.claude/commands/mastermind/_repeat.md +182 -39
- package/.claude/commands/mastermind/architect.md +17 -11
- package/.claude/commands/mastermind/brain.md +4 -0
- package/.claude/commands/mastermind/build.md +4 -0
- package/.claude/commands/mastermind/content.md +4 -0
- package/.claude/commands/mastermind/createorg.md +5 -3
- package/.claude/commands/mastermind/finance.md +4 -0
- package/.claude/commands/mastermind/idea.md +4 -0
- package/.claude/commands/mastermind/marketing.md +4 -0
- package/.claude/commands/mastermind/master.md +63 -37
- package/.claude/commands/mastermind/ops.md +4 -0
- package/.claude/commands/mastermind/release.md +4 -0
- package/.claude/commands/mastermind/research.md +4 -0
- package/.claude/commands/mastermind/review.md +4 -0
- package/.claude/commands/mastermind/runorg.md +5 -3
- package/.claude/commands/mastermind/sales.md +4 -0
- package/.claude/commands/mastermind/techport.md +9 -0
- package/.claude/commands/monomind/do.md +5 -1
- package/.claude/commands/monomind/idea.md +5 -1
- package/.claude/commands/monomind/improve.md +5 -1
- package/.claude/commands/monomind/repeat.md +85 -29
- package/.claude/commands/monomind/review.md +6 -2
- package/.claude/commands/monomind/understand.md +10 -8
- package/.claude/helpers/extras-registry.json +235 -235
- package/.claude/helpers/graphify-freshen.cjs +13 -1
- package/.claude/helpers/hook-handler.cjs +1 -1
- package/.claude/helpers/router.cjs +4 -1
- package/.claude/skills/mastermind/_protocol.md +28 -21
- package/.claude/skills/mastermind/access.md +236 -0
- package/.claude/skills/mastermind/activity.md +191 -0
- package/.claude/skills/mastermind/adapter-manager.md +259 -0
- package/.claude/skills/mastermind/adapters.md +204 -0
- package/.claude/skills/mastermind/agent-detail.md +242 -0
- package/.claude/skills/mastermind/agents.md +178 -0
- package/.claude/skills/mastermind/approval-detail.md +259 -0
- package/.claude/skills/mastermind/approve.md +181 -0
- package/.claude/skills/mastermind/architect.md +24 -8
- package/.claude/skills/mastermind/backup.md +197 -0
- package/.claude/skills/mastermind/bootstrap.md +190 -0
- package/.claude/skills/mastermind/budgets.md +237 -0
- package/.claude/skills/mastermind/companies.md +256 -0
- package/.claude/skills/mastermind/costs.md +151 -0
- package/.claude/skills/mastermind/createorg.md +23 -5
- package/.claude/skills/mastermind/diagnose.md +249 -0
- package/.claude/skills/mastermind/env.md +198 -0
- package/.claude/skills/mastermind/environments.md +250 -0
- package/.claude/skills/mastermind/export.md +324 -0
- package/.claude/skills/mastermind/goal-detail.md +255 -0
- package/.claude/skills/mastermind/goals.md +149 -0
- package/.claude/skills/mastermind/heartbeat.md +164 -0
- package/.claude/skills/mastermind/idea.md +250 -122
- package/.claude/skills/mastermind/import.md +281 -0
- package/.claude/skills/mastermind/inbox.md +214 -0
- package/.claude/skills/mastermind/instance-settings.md +315 -0
- package/.claude/skills/mastermind/instance.md +231 -0
- package/.claude/skills/mastermind/invite-landing.md +227 -0
- package/.claude/skills/mastermind/invites.md +254 -0
- package/.claude/skills/mastermind/issue-detail.md +291 -0
- package/.claude/skills/mastermind/issues.md +235 -0
- package/.claude/skills/mastermind/join-queue.md +170 -0
- package/.claude/skills/mastermind/liveness.md +392 -0
- package/.claude/skills/mastermind/memory.md +321 -0
- package/.claude/skills/mastermind/my-issues.md +146 -0
- package/.claude/skills/mastermind/new-agent.md +241 -0
- package/.claude/skills/mastermind/org-chart.md +207 -0
- package/.claude/skills/mastermind/org-settings.md +217 -0
- package/.claude/skills/mastermind/plan-to-tasks.md +136 -0
- package/.claude/skills/mastermind/plugin-manager.md +241 -0
- package/.claude/skills/mastermind/plugin-settings.md +273 -0
- package/.claude/skills/mastermind/plugins.md +190 -0
- package/.claude/skills/mastermind/profile.md +187 -0
- package/.claude/skills/mastermind/project-detail.md +249 -0
- package/.claude/skills/mastermind/project-workspace.md +244 -0
- package/.claude/skills/mastermind/projects.md +164 -0
- package/.claude/skills/mastermind/routine-detail.md +253 -0
- package/.claude/skills/mastermind/routines.md +202 -0
- package/.claude/skills/mastermind/runorg.md +74 -9
- package/.claude/skills/mastermind/search.md +186 -0
- package/.claude/skills/mastermind/secrets.md +199 -0
- package/.claude/skills/mastermind/skills.md +156 -0
- package/.claude/skills/mastermind/tasks.md +149 -0
- package/.claude/skills/mastermind/techport.md +5 -5
- package/.claude/skills/mastermind/threads.md +259 -0
- package/.claude/skills/mastermind/tree-control.md +250 -0
- package/.claude/skills/mastermind/wiki.md +314 -0
- package/.claude/skills/mastermind/workspace-detail.md +317 -0
- package/.claude/skills/mastermind/workspaces.md +261 -0
- package/.claude/skills/mastermind/worktree.md +187 -0
- package/dist/src/init/executor.js +8 -8
- package/dist/src/init/executor.js.map +1 -1
- package/dist/src/init/statusline-generator.d.ts.map +1 -1
- package/dist/src/init/statusline-generator.js +12 -0
- package/dist/src/init/statusline-generator.js.map +1 -1
- package/dist/src/ui/.monomind/data/ranked-context.json +1 -1
- package/dist/src/ui/.monomind/loops/mastermind-review-1778664132789.json +16 -0
- package/dist/src/ui/.monomind/sessions/current.json +5 -5
- package/dist/src/ui/.monomind/sessions/session-1776778451399.json +15 -0
- package/dist/src/ui/dashboard.html +3030 -181
- package/dist/src/ui/data/mastermind-events.jsonl +8 -0
- package/dist/src/ui/data/mastermind-sessions.json +1 -0
- package/dist/src/ui/server.mjs +738 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/.claude/skills/.monomind/data/ranked-context.json +0 -5
- package/.claude/skills/.monomind/sessions/current.json +0 -13
- package/.claude/skills/.monomind/sessions/session-1777829336455.json +0 -15
- package/.claude/skills/.monomind/sessions/session-1777831614725.json +0 -15
- package/.claude/skills/.monomind/sessions/session-1777832095857.json +0 -15
- package/.claude/skills/.monomind/sessions/session-1777839814183.json +0 -15
- package/.claude/skills/.monomind/sessions/session-1777841847131.json +0 -15
- package/.claude/skills/.monomind/sessions/session-1777843309463.json +0 -15
- package/.claude/skills/.monomind/sessions/session-1777880867159.json +0 -15
- package/.claude/skills/.monomind/sessions/session-1777881884593.json +0 -15
- package/.claude/skills/.monomind/sessions/session-1777884090471.json +0 -15
- package/.claude/skills/.monomind/sessions/session-1777884808221.json +0 -15
- package/.claude/skills/.monomind/sessions/session-1777885672155.json +0 -15
- package/.claude/skills/.monomind/sessions/session-1777886852818.json +0 -15
- package/.claude/skills/.monomind/sessions/session-1777896532690.json +0 -15
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mastermind-invite-landing
|
|
3
|
+
description: Mastermind invite-landing — accept an org invite as a human member or as an agent. Validates the invite token, presents org/role info, and processes join as human (name/email) or as an agent (adapter type, model, agent name, config). Mirrors InviteLanding.tsx.
|
|
4
|
+
type: domain-skill
|
|
5
|
+
default_mode: confirm
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Mastermind Invite Landing
|
|
9
|
+
|
|
10
|
+
This skill is invoked by `mastermind:invite-landing` or directly via `/mastermind:invite-landing`.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Inputs
|
|
15
|
+
|
|
16
|
+
- `brain_context`: BRAIN CONTEXT block (injected by command, or loaded below if standalone)
|
|
17
|
+
- `action`: show | accept-human | accept-agent | status
|
|
18
|
+
- `token`: invite token (required; extract from monomind://invite?... URL or share link)
|
|
19
|
+
- `org_name`: org name (required unless extractable from token record)
|
|
20
|
+
- `join_as`: human | agent (for accept actions; default: agent in CLI context)
|
|
21
|
+
- `display_name`: human display name (for accept-human)
|
|
22
|
+
- `email`: email address (for accept-human)
|
|
23
|
+
- `agent_name`: agent display name (for accept-agent)
|
|
24
|
+
- `adapter_type`: claude-local | gemini-local | codex-local | cursor | opencode | hermes | http | acpx (for accept-agent; default: claude-local)
|
|
25
|
+
- `model`: model override (for accept-agent; uses adapter default if omitted)
|
|
26
|
+
- `caller`: command | master
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Join Modes
|
|
31
|
+
|
|
32
|
+
| Mode | Who | Required Fields |
|
|
33
|
+
|------|-----|-----------------|
|
|
34
|
+
| `human` | A human operator joining the org | `display_name`, `email` |
|
|
35
|
+
| `agent` | An AI agent joining the org | `agent_name`, `adapter_type` |
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Step 0 — Brain Load (standalone only)
|
|
40
|
+
|
|
41
|
+
If `caller` is not "command", load brain context following _protocol.md Brain Load Procedure with namespace: `ops`.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Step 1 — Validate Token
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
[ -z "$token" ] && { echo "ERROR: --token required. Extract from invite URL: monomind://invite?org=...&token=...&role=..."; exit 1; }
|
|
49
|
+
|
|
50
|
+
# Try to find org from token if org_name not given
|
|
51
|
+
if [ -z "$org_name" ]; then
|
|
52
|
+
# Search all members files for a matching invite token
|
|
53
|
+
for mf in .monomind/orgs/*-members.json; do
|
|
54
|
+
[ -f "$mf" ] || continue
|
|
55
|
+
match=$(jq -r --arg t "$token" '.join_requests[] | select(.token == $t or .id == $t) | .id' "$mf" 2>/dev/null | head -1)
|
|
56
|
+
if [ -n "$match" ]; then
|
|
57
|
+
org_name=$(basename "$mf" "-members.json")
|
|
58
|
+
break
|
|
59
|
+
fi
|
|
60
|
+
done
|
|
61
|
+
[ -z "$org_name" ] && { echo "ERROR: Could not find org for token '$token'. Specify --org-name explicitly."; exit 1; }
|
|
62
|
+
fi
|
|
63
|
+
|
|
64
|
+
membersFile=".monomind/orgs/${org_name}-members.json"
|
|
65
|
+
[ ! -f "$membersFile" ] && { echo "ERROR: Org '$org_name' members file not found."; exit 1; }
|
|
66
|
+
|
|
67
|
+
inviteDef=$(jq -r --arg t "$token" \
|
|
68
|
+
'.join_requests[] | select((.token == $t or .id == $t) and .type == "invite")' \
|
|
69
|
+
"$membersFile" | head -c 4096)
|
|
70
|
+
[ -z "$inviteDef" ] && { echo "ERROR: Invite token '$token' not found or already used."; exit 1; }
|
|
71
|
+
|
|
72
|
+
inviteStatus=$(echo "$inviteDef" | jq -r '.status // "pending"')
|
|
73
|
+
inviteRole=$(echo "$inviteDef" | jq -r '.role // "operator"')
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Step 2 — Execute Action
|
|
79
|
+
|
|
80
|
+
### show (default)
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
echo "INVITE — org: $org_name"
|
|
84
|
+
echo "────────────────────────────────────────────────────────"
|
|
85
|
+
echo " Token: ${token:0:16}…"
|
|
86
|
+
echo " Role: $inviteRole"
|
|
87
|
+
echo " Status: $inviteStatus"
|
|
88
|
+
|
|
89
|
+
inviteCreatedAt=$(echo "$inviteDef" | jq -r '.createdAt // "-"')
|
|
90
|
+
echo " Created: $inviteCreatedAt"
|
|
91
|
+
echo ""
|
|
92
|
+
|
|
93
|
+
if [ "$inviteStatus" = "revoked" ]; then
|
|
94
|
+
echo " This invite has been revoked and can no longer be used."
|
|
95
|
+
elif [ "$inviteStatus" = "accepted" ]; then
|
|
96
|
+
echo " This invite has already been accepted."
|
|
97
|
+
else
|
|
98
|
+
echo " To join as an agent (default in CLI):"
|
|
99
|
+
echo " --action accept-agent --token $token --org-name $org_name --agent-name 'My Agent' --adapter-type claude-local"
|
|
100
|
+
echo ""
|
|
101
|
+
echo " To join as a human:"
|
|
102
|
+
echo " --action accept-human --token $token --org-name $org_name --display-name 'Your Name' --email 'you@example.com'"
|
|
103
|
+
fi
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### accept-human
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
[ "$inviteStatus" != "pending" ] && { echo "ERROR: Invite status is '$inviteStatus' — cannot accept."; exit 1; }
|
|
110
|
+
[ -z "$display_name" ] && { echo "ERROR: --display-name required for human join."; exit 1; }
|
|
111
|
+
[ -z "$email" ] && { echo "ERROR: --email required for human join."; exit 1; }
|
|
112
|
+
|
|
113
|
+
ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
114
|
+
memberId="human-$(echo "${email}" | tr '[:upper:]' '[:lower:]' | tr -cs 'a-z0-9' '-' | sed 's/^-//;s/-$//')"
|
|
115
|
+
|
|
116
|
+
tmp="${membersFile}.tmp"
|
|
117
|
+
# Mark invite accepted and add member record
|
|
118
|
+
jq --arg token "$token" --arg mid "$memberId" --arg name "$display_name" \
|
|
119
|
+
--arg email "$email" --arg role "$inviteRole" --arg ts "$ts" \
|
|
120
|
+
'.join_requests = [.join_requests[] | if (.token == $token or .id == $token) then
|
|
121
|
+
.status = "accepted" | .acceptedAt = $ts | .acceptedAs = "human"
|
|
122
|
+
else . end] |
|
|
123
|
+
.members += [{"id":$mid,"displayName":$name,"email":$email,"role":$role,
|
|
124
|
+
"memberType":"human","status":"active","joinedAt":$ts}]' \
|
|
125
|
+
"$membersFile" > "$tmp" && mv "$tmp" "$membersFile"
|
|
126
|
+
|
|
127
|
+
echo "JOINED as human: $display_name"
|
|
128
|
+
echo " Member ID: $memberId"
|
|
129
|
+
echo " Role: $inviteRole"
|
|
130
|
+
echo " Org: $org_name"
|
|
131
|
+
echo " Email: $email"
|
|
132
|
+
echo " Joined at: $ts"
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### accept-agent
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
[ "$inviteStatus" != "pending" ] && { echo "ERROR: Invite status is '$inviteStatus' — cannot accept."; exit 1; }
|
|
139
|
+
[ -z "$agent_name" ] && { echo "ERROR: --agent-name required for agent join."; exit 1; }
|
|
140
|
+
|
|
141
|
+
adapterType="${adapter_type:-claude-local}"
|
|
142
|
+
case "$adapterType" in
|
|
143
|
+
claude-local|gemini-local|codex-local|cursor|opencode-local|hermes-local|http|acpx) : ;;
|
|
144
|
+
*) echo "ERROR: Unknown adapter type '$adapterType'. Choose: claude-local, gemini-local, codex-local, cursor, opencode-local, hermes-local, http, acpx"; exit 1 ;;
|
|
145
|
+
esac
|
|
146
|
+
|
|
147
|
+
# Resolve default model
|
|
148
|
+
modelId="${model}"
|
|
149
|
+
if [ -z "$modelId" ]; then
|
|
150
|
+
case "$adapterType" in
|
|
151
|
+
claude-local) modelId="claude-sonnet-4-6" ;;
|
|
152
|
+
gemini-local) modelId="gemini-2.0-flash" ;;
|
|
153
|
+
codex-local) modelId="gpt-4o" ;;
|
|
154
|
+
cursor) modelId="cursor-default" ;;
|
|
155
|
+
opencode-local) modelId="opencode-default" ;;
|
|
156
|
+
hermes-local) modelId="hermes-3" ;;
|
|
157
|
+
*) modelId="custom" ;;
|
|
158
|
+
esac
|
|
159
|
+
fi
|
|
160
|
+
|
|
161
|
+
# Generate agent slug
|
|
162
|
+
agentSlug=$(echo "$agent_name" | tr '[:upper:]' '[:lower:]' | tr -cs 'a-z0-9' '-' | sed 's/^-//;s/-$//')
|
|
163
|
+
agentId="agent-${agentSlug}"
|
|
164
|
+
ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
165
|
+
|
|
166
|
+
# Add to members file
|
|
167
|
+
tmp="${membersFile}.tmp"
|
|
168
|
+
jq --arg token "$token" --arg mid "$agentId" --arg name "$agent_name" \
|
|
169
|
+
--arg role "$inviteRole" --arg adapter "$adapterType" --arg model "$modelId" --arg ts "$ts" \
|
|
170
|
+
'.join_requests = [.join_requests[] | if (.token == $token or .id == $token) then
|
|
171
|
+
.status = "accepted" | .acceptedAt = $ts | .acceptedAs = "agent"
|
|
172
|
+
else . end] |
|
|
173
|
+
.members += [{"id":$mid,"displayName":$name,"role":$role,
|
|
174
|
+
"memberType":"agent","adapter":{"type":$adapter,"model":$model},
|
|
175
|
+
"status":"active","joinedAt":$ts}]' \
|
|
176
|
+
"$membersFile" > "$tmp" && mv "$tmp" "$membersFile"
|
|
177
|
+
|
|
178
|
+
# Also add to org roles file so the agent can run
|
|
179
|
+
orgFile=".monomind/orgs/${org_name}.json"
|
|
180
|
+
if [ -f "$orgFile" ]; then
|
|
181
|
+
dupCheck=$(jq -r --arg id "$agentId" '[.roles[] | select(.id == $id)] | length' "$orgFile")
|
|
182
|
+
if [ "$dupCheck" -eq 0 ]; then
|
|
183
|
+
tmp2="${orgFile}.tmp"
|
|
184
|
+
jq --arg id "$agentId" --arg title "$agent_name" \
|
|
185
|
+
--arg adapter "$adapterType" --arg model "$modelId" --arg ts "$ts" \
|
|
186
|
+
'.roles += [{"id":$id,"title":$title,"adapter":{"type":$adapter,"model":$model,"max_tokens":8192},
|
|
187
|
+
"reports_to":null,"governance":null,"skills":[],"created_at":$ts}]' \
|
|
188
|
+
"$orgFile" > "$tmp2" && mv "$tmp2" "$orgFile"
|
|
189
|
+
fi
|
|
190
|
+
fi
|
|
191
|
+
|
|
192
|
+
echo "JOINED as agent: $agent_name"
|
|
193
|
+
echo " Agent ID: $agentId"
|
|
194
|
+
echo " Role: $inviteRole"
|
|
195
|
+
echo " Adapter: $adapterType / $modelId"
|
|
196
|
+
echo " Org: $org_name"
|
|
197
|
+
echo " Joined at: $ts"
|
|
198
|
+
echo ""
|
|
199
|
+
echo " View agent: /mastermind:agent-detail --org $org_name --agent-id $agentId"
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### status
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
echo "INVITE STATUS — token: ${token:0:16}…"
|
|
206
|
+
echo "────────────────────────────────────────────────────────"
|
|
207
|
+
echo "$inviteDef" | jq '{status, role, createdAt, acceptedAt, acceptedAs}'
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## Step 3 — Return Output
|
|
213
|
+
|
|
214
|
+
```yaml
|
|
215
|
+
domain: ops
|
|
216
|
+
status: complete
|
|
217
|
+
action: <action>
|
|
218
|
+
org: <org_name>
|
|
219
|
+
invite_status: <status>
|
|
220
|
+
role: <role>
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
## Step 4 — Brain Write (standalone only)
|
|
226
|
+
|
|
227
|
+
If `caller` is not "command", follow _protocol.md Brain Write Procedure for domain `ops`.
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mastermind-invites
|
|
3
|
+
description: Mastermind invites — manage org invitations and join request queue. Create/revoke invites with role assignment, view invite history, review pending join requests (human and agent), and approve or reject them. Merges CompanyInvites and JoinRequestQueue pages.
|
|
4
|
+
type: domain-skill
|
|
5
|
+
default_mode: confirm
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Mastermind Invites
|
|
9
|
+
|
|
10
|
+
This skill is invoked by `mastermind:invites` or directly via `/mastermind:invites`.
|
|
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 invites for (required)
|
|
18
|
+
- `action`: list | create | revoke | copy-url | join-queue | approve-join | reject-join
|
|
19
|
+
- `role`: owner | admin | operator | viewer (for create; default: operator)
|
|
20
|
+
- `invite_id`: invite id/token (for revoke/copy-url)
|
|
21
|
+
- `request_id`: join request id (for approve-join/reject-join)
|
|
22
|
+
- `request_type`: all | human | agent (for join-queue; default: all)
|
|
23
|
+
- `status_filter`: pending_approval | approved | rejected (for join-queue; default: pending_approval)
|
|
24
|
+
- `caller`: command | master
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Invite Roles
|
|
29
|
+
|
|
30
|
+
| Role | Can Do |
|
|
31
|
+
|------|--------|
|
|
32
|
+
| `owner` | Full control — all permissions |
|
|
33
|
+
| `admin` | Create agents, invite users, assign tasks, approve joins, manage environments |
|
|
34
|
+
| `operator` | Assign tasks, run routines |
|
|
35
|
+
| `viewer` | Read-only access |
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Step 0 — Brain Load (standalone only)
|
|
40
|
+
|
|
41
|
+
If `caller` is not "command", load brain context following _protocol.md Brain Load Procedure with namespace: `ops`.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Step 1 — Load Members File
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
orgFile=".monomind/orgs/${org_name}.json"
|
|
49
|
+
[ ! -f "$orgFile" ] && { echo "ERROR: Org '${org_name}' not found."; exit 1; }
|
|
50
|
+
|
|
51
|
+
membersFile=".monomind/orgs/${org_name}-members.json"
|
|
52
|
+
[ ! -f "$membersFile" ] && echo '{"members":[],"join_requests":[]}' > "$membersFile"
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Step 2 — Execute Action
|
|
58
|
+
|
|
59
|
+
### list (default)
|
|
60
|
+
|
|
61
|
+
Show invite history and member count:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
echo "INVITES — org: $org_name"
|
|
65
|
+
echo "────────────────────────────────────────────────────────"
|
|
66
|
+
|
|
67
|
+
# Active invites (pending in join_requests with type=invite)
|
|
68
|
+
activeInvites=$(jq '[.join_requests[] | select(.type == "invite" and .status == "pending")] | length' "$membersFile")
|
|
69
|
+
totalMembers=$(jq '.members | length' "$membersFile")
|
|
70
|
+
pendingJoins=$(jq '[.join_requests[] | select(.type != "invite" and .status == "pending_approval")] | length' "$membersFile")
|
|
71
|
+
|
|
72
|
+
echo " Members: $totalMembers"
|
|
73
|
+
echo " Pending invites: $activeInvites"
|
|
74
|
+
echo " Pending joins: $pendingJoins"
|
|
75
|
+
echo ""
|
|
76
|
+
|
|
77
|
+
if [ "$activeInvites" -gt 0 ]; then
|
|
78
|
+
echo "ACTIVE INVITES"
|
|
79
|
+
printf " %-28s %-10s %-20s %s\n" "TOKEN" "ROLE" "CREATED" "URL"
|
|
80
|
+
echo " ────────────────────────────────────────────────────────"
|
|
81
|
+
jq -r '.join_requests[] | select(.type == "invite" and .status == "pending") |
|
|
82
|
+
[.token, (.role // "operator"), (.createdAt // "-"), (.inviteUrl // "-")] | @tsv' \
|
|
83
|
+
"$membersFile" | while IFS=$'\t' read -r tok role ts url; do
|
|
84
|
+
printf " %-28s %-10s %-20s %s\n" "${tok:0:24}…" "$role" "$ts" "${url:0:40}…"
|
|
85
|
+
done
|
|
86
|
+
fi
|
|
87
|
+
|
|
88
|
+
echo ""
|
|
89
|
+
echo " To create a new invite: --action create --role <role>"
|
|
90
|
+
[ "$pendingJoins" -gt 0 ] && echo " To review join requests: --action join-queue"
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### create
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
role="${role:-operator}"
|
|
97
|
+
case "$role" in owner|admin|operator|viewer) : ;; *)
|
|
98
|
+
echo "ERROR: --role must be: owner, admin, operator, viewer"; exit 1 ;;
|
|
99
|
+
esac
|
|
100
|
+
|
|
101
|
+
token=$(openssl rand -hex 20 2>/dev/null || python3 -c "import secrets; print(secrets.token_hex(20))")
|
|
102
|
+
inviteUrl="monomind://invite?org=${org_name}&token=${token}&role=${role}"
|
|
103
|
+
ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
104
|
+
|
|
105
|
+
tmp="${membersFile}.tmp"
|
|
106
|
+
jq --arg token "$token" --arg role "$role" --arg ts "$ts" --arg url "$inviteUrl" \
|
|
107
|
+
'.join_requests += [{"id":$token,"type":"invite","role":$role,"status":"pending",
|
|
108
|
+
"token":$token,"inviteUrl":$url,"createdAt":$ts}]' \
|
|
109
|
+
"$membersFile" > "$tmp" && mv "$tmp" "$membersFile"
|
|
110
|
+
|
|
111
|
+
echo "INVITE CREATED"
|
|
112
|
+
echo "────────────────────────────────────────────────────────"
|
|
113
|
+
echo " Role: $role"
|
|
114
|
+
echo " Token: $token"
|
|
115
|
+
echo " URL: $inviteUrl"
|
|
116
|
+
echo " Time: $ts"
|
|
117
|
+
echo ""
|
|
118
|
+
echo "Share the token or URL with the invitee."
|
|
119
|
+
echo "To copy URL hint: --action copy-url --invite-id $token"
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### revoke
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
[ -z "$invite_id" ] && { echo "ERROR: --invite-id required."; exit 1; }
|
|
126
|
+
|
|
127
|
+
# Find the invite
|
|
128
|
+
inviteExists=$(jq -r --arg id "$invite_id" \
|
|
129
|
+
'[.join_requests[] | select((.id == $id or .token == $id) and .type == "invite")] | length' \
|
|
130
|
+
"$membersFile")
|
|
131
|
+
[ "$inviteExists" -eq 0 ] && { echo "ERROR: Invite '$invite_id' not found or already resolved."; exit 1; }
|
|
132
|
+
|
|
133
|
+
ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
134
|
+
tmp="${membersFile}.tmp"
|
|
135
|
+
jq --arg id "$invite_id" --arg ts "$ts" \
|
|
136
|
+
'.join_requests = [.join_requests[] | if (.id == $id or .token == $id) then
|
|
137
|
+
.status = "revoked" | .resolvedAt = $ts
|
|
138
|
+
else . end]' \
|
|
139
|
+
"$membersFile" > "$tmp" && mv "$tmp" "$membersFile"
|
|
140
|
+
|
|
141
|
+
echo "Invite revoked: $invite_id"
|
|
142
|
+
echo " Revoked at: $ts"
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### copy-url
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
[ -z "$invite_id" ] && { echo "ERROR: --invite-id required."; exit 1; }
|
|
149
|
+
|
|
150
|
+
inviteUrl=$(jq -r --arg id "$invite_id" \
|
|
151
|
+
'.join_requests[] | select(.id == $id or .token == $id) | .inviteUrl // ""' \
|
|
152
|
+
"$membersFile")
|
|
153
|
+
[ -z "$inviteUrl" ] && { echo "ERROR: Invite '$invite_id' not found."; exit 1; }
|
|
154
|
+
|
|
155
|
+
echo "INVITE URL"
|
|
156
|
+
echo "────────────────────────────────────────────────────────"
|
|
157
|
+
echo "$inviteUrl"
|
|
158
|
+
echo ""
|
|
159
|
+
echo "(Copy the URL above to share with the invitee)"
|
|
160
|
+
# Try to copy to clipboard if pbcopy/xclip available
|
|
161
|
+
echo "$inviteUrl" | pbcopy 2>/dev/null && echo "(Copied to clipboard)" || true
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### join-queue
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
statusFilter="${status_filter:-pending_approval}"
|
|
168
|
+
typeFilter="${request_type:-all}"
|
|
169
|
+
|
|
170
|
+
echo "JOIN REQUEST QUEUE — org: $org_name"
|
|
171
|
+
echo " Filter: status=$statusFilter type=$typeFilter"
|
|
172
|
+
echo "────────────────────────────────────────────────────────"
|
|
173
|
+
|
|
174
|
+
jq -r --arg st "$statusFilter" --arg type "$typeFilter" '
|
|
175
|
+
.join_requests[] |
|
|
176
|
+
select(
|
|
177
|
+
(.status == $st) and
|
|
178
|
+
(.type != "invite") and
|
|
179
|
+
(if $type == "all" then true
|
|
180
|
+
elif $type == "human" then (.requestType == "human" or .requestType == null)
|
|
181
|
+
else .requestType == "agent"
|
|
182
|
+
end)
|
|
183
|
+
) |
|
|
184
|
+
[.id, (.requestType // "human"), (.role // "viewer"), (.createdAt // "-"), (.message // "(no message)")] | @tsv
|
|
185
|
+
' "$membersFile" | while IFS=$'\t' read -r id rtype role ts msg; do
|
|
186
|
+
echo ""
|
|
187
|
+
echo " [$id] type=$rtype role=$role at=$ts"
|
|
188
|
+
echo " Message: $msg"
|
|
189
|
+
echo " → approve: --action approve-join --request-id $id"
|
|
190
|
+
echo " → reject: --action reject-join --request-id $id"
|
|
191
|
+
done
|
|
192
|
+
|
|
193
|
+
total=$(jq --arg st "$statusFilter" '[.join_requests[] | select(.status == $st and .type != "invite")] | length' "$membersFile")
|
|
194
|
+
[ "$total" -eq 0 ] && echo " No join requests with status='$statusFilter'."
|
|
195
|
+
echo ""
|
|
196
|
+
echo "Total ($statusFilter): $total"
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### approve-join
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
[ -z "$request_id" ] && { echo "ERROR: --request-id required."; exit 1; }
|
|
203
|
+
|
|
204
|
+
reqRole=$(jq -r --arg id "$request_id" \
|
|
205
|
+
'.join_requests[] | select(.id == $id) | .role // "viewer"' "$membersFile")
|
|
206
|
+
[ -z "$reqRole" ] && { echo "ERROR: Request '$request_id' not found."; exit 1; }
|
|
207
|
+
|
|
208
|
+
ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
209
|
+
tmp="${membersFile}.tmp"
|
|
210
|
+
jq --arg id "$request_id" --arg role "$reqRole" --arg ts "$ts" \
|
|
211
|
+
'.join_requests = [.join_requests[] | if .id == $id then .status = "approved" | .resolvedAt = $ts else . end] |
|
|
212
|
+
.members += [{"id":$id,"role":$role,"status":"active","grants":[],"joinedAt":$ts}]' \
|
|
213
|
+
"$membersFile" > "$tmp" && mv "$tmp" "$membersFile"
|
|
214
|
+
|
|
215
|
+
echo "Join request '$request_id' approved."
|
|
216
|
+
echo " Role: $reqRole | Joined: $ts"
|
|
217
|
+
echo " Member added. View members: /mastermind:access --org $org_name --action list"
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### reject-join
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
[ -z "$request_id" ] && { echo "ERROR: --request-id required."; exit 1; }
|
|
224
|
+
|
|
225
|
+
exists=$(jq -r --arg id "$request_id" '[.join_requests[] | select(.id == $id)] | length' "$membersFile")
|
|
226
|
+
[ "$exists" -eq 0 ] && { echo "ERROR: Request '$request_id' not found."; exit 1; }
|
|
227
|
+
|
|
228
|
+
ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
229
|
+
tmp="${membersFile}.tmp"
|
|
230
|
+
jq --arg id "$request_id" --arg ts "$ts" \
|
|
231
|
+
'.join_requests = [.join_requests[] | if .id == $id then .status = "rejected" | .resolvedAt = $ts else . end]' \
|
|
232
|
+
"$membersFile" > "$tmp" && mv "$tmp" "$membersFile"
|
|
233
|
+
|
|
234
|
+
echo "Join request '$request_id' rejected."
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## Step 3 — Return Output
|
|
240
|
+
|
|
241
|
+
```yaml
|
|
242
|
+
domain: ops
|
|
243
|
+
status: complete
|
|
244
|
+
action: <action>
|
|
245
|
+
org: <org_name>
|
|
246
|
+
pending_invites: <N>
|
|
247
|
+
pending_joins: <N>
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## Step 4 — Brain Write (standalone only)
|
|
253
|
+
|
|
254
|
+
If `caller` is not "command", follow _protocol.md Brain Write Procedure for domain `ops`.
|