@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,250 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mastermind-environments
|
|
3
|
+
description: Mastermind environments — manage execution environments (local, SSH, sandbox) for an org. Controls where agent workloads run, SSH connection details, and which environment is the default.
|
|
4
|
+
type: domain-skill
|
|
5
|
+
default_mode: confirm
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Mastermind Environments
|
|
9
|
+
|
|
10
|
+
This skill is invoked by `mastermind:environments` or directly via `/mastermind:environments`.
|
|
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 environments for (required)
|
|
18
|
+
- `action`: list | create | edit | delete | probe | set-default
|
|
19
|
+
- `env_id`: environment id (required for edit/delete/probe/set-default)
|
|
20
|
+
- `kind`: local | ssh | sandbox (required for create)
|
|
21
|
+
- `name`: display name (required for create)
|
|
22
|
+
- `host`: SSH hostname or IP (required for ssh kind)
|
|
23
|
+
- `port`: SSH port (default 22)
|
|
24
|
+
- `user`: SSH username (required for ssh kind)
|
|
25
|
+
- `secret_ref`: secret name holding the SSH private key (see mastermind:secrets — NEVER pass raw key values)
|
|
26
|
+
- `work_dir`: remote working directory (default: /tmp/monomind)
|
|
27
|
+
- `caller`: command | master
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Security Constraints
|
|
32
|
+
|
|
33
|
+
- NEVER print SSH private key values
|
|
34
|
+
- NEVER store key material in environment JSON files — store only the secret_ref name
|
|
35
|
+
- SSH keys must be stored via `mastermind:secrets` and referenced by name only
|
|
36
|
+
- Probe connection is read-only (runs `echo ok` over SSH)
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Step 0 — Brain Load (standalone only)
|
|
41
|
+
|
|
42
|
+
If `caller` is not "command", load brain context following _protocol.md Brain Load Procedure with namespace: `ops`.
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Step 1 — Load Environments File
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
orgFile=".monomind/orgs/${org_name}.json"
|
|
50
|
+
[ ! -f "$orgFile" ] && { echo "ERROR: Org '${org_name}' not found."; exit 1; }
|
|
51
|
+
|
|
52
|
+
envFile=".monomind/orgs/${org_name}-environments.json"
|
|
53
|
+
[ ! -f "$envFile" ] && cat > "$envFile" <<'EOF'
|
|
54
|
+
{"environments":[],"default_env":null}
|
|
55
|
+
EOF
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Step 2 — Execute Action
|
|
61
|
+
|
|
62
|
+
### list (default)
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
echo "ENVIRONMENTS — org: $org_name"
|
|
66
|
+
echo "────────────────────────────────────────────────────────"
|
|
67
|
+
printf "%-20s %-10s %-28s %-8s %s\n" "ID" "KIND" "HOST / PATH" "DEFAULT" "SECRET REF"
|
|
68
|
+
echo "────────────────────────────────────────────────────────"
|
|
69
|
+
|
|
70
|
+
defaultEnv=$(jq -r '.default_env // "none"' "$envFile")
|
|
71
|
+
count=$(jq '.environments | length' "$envFile")
|
|
72
|
+
|
|
73
|
+
if [ "$count" -eq 0 ]; then
|
|
74
|
+
echo " No environments. Use --action create to add one."
|
|
75
|
+
else
|
|
76
|
+
jq -r --arg def "$defaultEnv" '.environments[] |
|
|
77
|
+
[
|
|
78
|
+
.id,
|
|
79
|
+
(.kind // "local"),
|
|
80
|
+
(if .kind == "ssh" then ((.user // "?") + "@" + (.host // "?") + ":" + ((.port // 22) | tostring)) else (.work_dir // "(local)") end),
|
|
81
|
+
(if .id == $def then "yes" else "-" end),
|
|
82
|
+
(.secret_ref // "-")
|
|
83
|
+
] | @tsv' "$envFile" | while IFS=$'\t' read -r id kind loc def sref; do
|
|
84
|
+
printf "%-20s %-10s %-28s %-8s %s\n" "$id" "$kind" "$loc" "$def" "$sref"
|
|
85
|
+
done
|
|
86
|
+
fi
|
|
87
|
+
|
|
88
|
+
echo ""
|
|
89
|
+
echo "Total: $count environment(s) | Default: $defaultEnv"
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### create
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
[ -z "$kind" ] && { echo "ERROR: --kind required (local|ssh|sandbox)."; exit 1; }
|
|
96
|
+
[ -z "$name" ] && { echo "ERROR: --name required."; exit 1; }
|
|
97
|
+
case "$kind" in local|ssh|sandbox) : ;; *)
|
|
98
|
+
echo "ERROR: --kind must be local, ssh, or sandbox"; exit 1 ;;
|
|
99
|
+
esac
|
|
100
|
+
if [ "$kind" = "ssh" ]; then
|
|
101
|
+
[ -z "$host" ] && { echo "ERROR: --host required for ssh kind."; exit 1; }
|
|
102
|
+
[ -z "$user" ] && { echo "ERROR: --user required for ssh kind."; exit 1; }
|
|
103
|
+
[ -z "$secret_ref" ] && { echo "WARNING: No --secret-ref supplied. SSH key must be pre-configured on the agent."; }
|
|
104
|
+
fi
|
|
105
|
+
|
|
106
|
+
envId=$(echo "${name}" | tr '[:upper:]' '[:lower:]' | tr -cs 'a-z0-9' '-' | sed 's/^-//;s/-$//')
|
|
107
|
+
ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
108
|
+
|
|
109
|
+
tmp="${envFile}.tmp"
|
|
110
|
+
jq --arg id "$envId" \
|
|
111
|
+
--arg n "$name" \
|
|
112
|
+
--arg kind "$kind" \
|
|
113
|
+
--arg host "${host:-}" \
|
|
114
|
+
--argjson port "${port:-22}" \
|
|
115
|
+
--arg user "${user:-}" \
|
|
116
|
+
--arg sref "${secret_ref:-}" \
|
|
117
|
+
--arg wdir "${work_dir:-/tmp/monomind}" \
|
|
118
|
+
--arg ts "$ts" \
|
|
119
|
+
'.environments = [.environments[] | select(.id != $id)] +
|
|
120
|
+
[{"id":$id,"name":$n,"kind":$kind,
|
|
121
|
+
"host":(if $host != "" then $host else null end),
|
|
122
|
+
"port":(if $host != "" then $port else null end),
|
|
123
|
+
"user":(if $user != "" then $user else null end),
|
|
124
|
+
"secret_ref":(if $sref != "" then $sref else null end),
|
|
125
|
+
"work_dir":$wdir,
|
|
126
|
+
"createdAt":$ts,"lastProbe":null,"probeStatus":null}]' \
|
|
127
|
+
"$envFile" > "$tmp" && mv "$tmp" "$envFile"
|
|
128
|
+
|
|
129
|
+
echo "Created environment: $envId (kind: $kind)"
|
|
130
|
+
[ "$kind" = "ssh" ] && echo " SSH: ${user}@${host}:${port:-22} key ref: ${secret_ref:-(none)}"
|
|
131
|
+
echo "Run --action probe --env-id $envId to verify connectivity."
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### edit
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
[ -z "$env_id" ] && { echo "ERROR: --env-id required."; exit 1; }
|
|
138
|
+
exists=$(jq --arg id "$env_id" '[.environments[] | select(.id == $id)] | length' "$envFile")
|
|
139
|
+
[ "$exists" -eq 0 ] && { echo "ERROR: Environment '$env_id' not found."; exit 1; }
|
|
140
|
+
|
|
141
|
+
tmp="${envFile}.tmp"
|
|
142
|
+
jq --arg id "$env_id" \
|
|
143
|
+
--arg host "${host:-}" \
|
|
144
|
+
--argjson port "${port:-0}" \
|
|
145
|
+
--arg user "${user:-}" \
|
|
146
|
+
--arg sref "${secret_ref:-}" \
|
|
147
|
+
--arg wdir "${work_dir:-}" \
|
|
148
|
+
'.environments = [.environments[] | if .id == $id then
|
|
149
|
+
. *
|
|
150
|
+
(if $host != "" then {"host":$host} else {} end) *
|
|
151
|
+
(if $port > 0 then {"port":$port} else {} end) *
|
|
152
|
+
(if $user != "" then {"user":$user} else {} end) *
|
|
153
|
+
(if $sref != "" then {"secret_ref":$sref} else {} end) *
|
|
154
|
+
(if $wdir != "" then {"work_dir":$wdir} else {} end)
|
|
155
|
+
else . end]' \
|
|
156
|
+
"$envFile" > "$tmp" && mv "$tmp" "$envFile"
|
|
157
|
+
|
|
158
|
+
echo "Updated environment: $env_id"
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### delete
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
[ -z "$env_id" ] && { echo "ERROR: --env-id required."; exit 1; }
|
|
165
|
+
tmp="${envFile}.tmp"
|
|
166
|
+
jq --arg id "$env_id" \
|
|
167
|
+
'.environments = [.environments[] | select(.id != $id)] |
|
|
168
|
+
if .default_env == $id then .default_env = null else . end' \
|
|
169
|
+
"$envFile" > "$tmp" && mv "$tmp" "$envFile"
|
|
170
|
+
echo "Deleted environment: $env_id"
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### probe
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
[ -z "$env_id" ] && { echo "ERROR: --env-id required."; exit 1; }
|
|
177
|
+
envData=$(jq -r --arg id "$env_id" '.environments[] | select(.id == $id)' "$envFile")
|
|
178
|
+
[ -z "$envData" ] && { echo "ERROR: Environment '$env_id' not found."; exit 1; }
|
|
179
|
+
|
|
180
|
+
kind=$(echo "$envData" | jq -r '.kind')
|
|
181
|
+
ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
182
|
+
|
|
183
|
+
case "$kind" in
|
|
184
|
+
local)
|
|
185
|
+
if [ -d "$(echo "$envData" | jq -r '.work_dir // "/tmp/monomind"')" ]; then
|
|
186
|
+
status="ok"
|
|
187
|
+
else
|
|
188
|
+
status="unreachable"
|
|
189
|
+
fi
|
|
190
|
+
;;
|
|
191
|
+
ssh)
|
|
192
|
+
sshHost=$(echo "$envData" | jq -r '.host')
|
|
193
|
+
sshUser=$(echo "$envData" | jq -r '.user')
|
|
194
|
+
sshPort=$(echo "$envData" | jq -r '.port // 22')
|
|
195
|
+
sref=$(echo "$envData" | jq -r '.secret_ref // ""')
|
|
196
|
+
keyPath=""
|
|
197
|
+
[ -n "$sref" ] && keyPath=$(cat ".monomind/orgs/.secrets/${org_name}/${sref}" 2>/dev/null | jq -r '.path // ""' 2>/dev/null || echo "")
|
|
198
|
+
|
|
199
|
+
if [ -n "$keyPath" ] && [ -f "$keyPath" ]; then
|
|
200
|
+
result=$(ssh -i "$keyPath" -p "$sshPort" -o ConnectTimeout=5 -o StrictHostKeyChecking=no \
|
|
201
|
+
"${sshUser}@${sshHost}" "echo ok" 2>&1)
|
|
202
|
+
else
|
|
203
|
+
result=$(ssh -p "$sshPort" -o ConnectTimeout=5 -o StrictHostKeyChecking=no \
|
|
204
|
+
"${sshUser}@${sshHost}" "echo ok" 2>&1)
|
|
205
|
+
fi
|
|
206
|
+
[ "$result" = "ok" ] && status="ok" || status="unreachable"
|
|
207
|
+
;;
|
|
208
|
+
sandbox)
|
|
209
|
+
status="unknown"
|
|
210
|
+
;;
|
|
211
|
+
esac
|
|
212
|
+
|
|
213
|
+
tmp="${envFile}.tmp"
|
|
214
|
+
jq --arg id "$env_id" --arg st "$status" --arg ts "$ts" \
|
|
215
|
+
'.environments = [.environments[] | if .id == $id then .probeStatus = $st | .lastProbe = $ts else . end]' \
|
|
216
|
+
"$envFile" > "$tmp" && mv "$tmp" "$envFile"
|
|
217
|
+
|
|
218
|
+
echo "Probe [$env_id]: $status (checked at $ts)"
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### set-default
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
[ -z "$env_id" ] && { echo "ERROR: --env-id required."; exit 1; }
|
|
225
|
+
exists=$(jq --arg id "$env_id" '[.environments[] | select(.id == $id)] | length' "$envFile")
|
|
226
|
+
[ "$exists" -eq 0 ] && { echo "ERROR: Environment '$env_id' not found."; exit 1; }
|
|
227
|
+
|
|
228
|
+
tmp="${envFile}.tmp"
|
|
229
|
+
jq --arg id "$env_id" '.default_env = $id' "$envFile" > "$tmp" && mv "$tmp" "$envFile"
|
|
230
|
+
echo "Default environment → $env_id"
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## Step 3 — Return Output
|
|
236
|
+
|
|
237
|
+
```yaml
|
|
238
|
+
domain: ops
|
|
239
|
+
status: complete
|
|
240
|
+
action: <action>
|
|
241
|
+
org: <org_name>
|
|
242
|
+
environments_count: <N>
|
|
243
|
+
default_env: <id or null>
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
## Step 4 — Brain Write (standalone only)
|
|
249
|
+
|
|
250
|
+
If `caller` is not "command", follow _protocol.md Brain Write Procedure for domain `ops`.
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mastermind-export
|
|
3
|
+
description: Mastermind export — full org portability. Export an org to a compressed archive (tar.gz or zip) with file tree selection, and import from an archive with collision strategy and adapter override. Mirrors Paperclip's CompanyExport/CompanyImport pages.
|
|
4
|
+
type: domain-skill
|
|
5
|
+
default_mode: confirm
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Mastermind Export
|
|
9
|
+
|
|
10
|
+
This skill is invoked by `mastermind:export` or directly via `/mastermind:export`.
|
|
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 export/import (required)
|
|
18
|
+
- `action`: export | import | preview | list-archives
|
|
19
|
+
- `output_path`: destination path for exported archive (optional, default: `.monomind/exports/<org>-<ts>.tar.gz`)
|
|
20
|
+
- `input_path`: path to archive file to import (required for import)
|
|
21
|
+
- `collision_strategy`: merge | overwrite | skip (default: merge — for import)
|
|
22
|
+
- `adapter_override`: adapter type to substitute during import (optional: claude-local | gemini-local | codex-local)
|
|
23
|
+
- `include`: comma-separated sections to include (config,goals,routines,projects,members,adapters,secrets-refs,activity — default: all except secrets-refs)
|
|
24
|
+
- `dry_run`: true | false — for import, preview changes without writing (default false)
|
|
25
|
+
- `caller`: command | master
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Sections Available for Export
|
|
30
|
+
|
|
31
|
+
| Section | Files Included | Default |
|
|
32
|
+
|---------|---------------|---------|
|
|
33
|
+
| `config` | `<org>.json` | ✓ |
|
|
34
|
+
| `goals` | `<org>-goals.json` | ✓ |
|
|
35
|
+
| `routines` | `<org>-routines.json` | ✓ |
|
|
36
|
+
| `projects` | `<org>-projects.json` | ✓ |
|
|
37
|
+
| `members` | `<org>-members.json` | ✓ |
|
|
38
|
+
| `adapters` | `<org>-adapters.json` | ✓ |
|
|
39
|
+
| `environments` | `<org>-environments.json` | ✓ |
|
|
40
|
+
| `workspaces` | `<org>-workspaces.json` | ✓ |
|
|
41
|
+
| `activity` | `<org>-activity.jsonl` (last 500 events) | ✓ |
|
|
42
|
+
| `secrets-refs` | secret reference names only (NO values) | opt-in |
|
|
43
|
+
|
|
44
|
+
**SECURITY:** Secret *values* are NEVER exported. Only masked reference names may be included if `secrets-refs` is explicitly listed in `include`.
|
|
45
|
+
|
|
46
|
+
## Collision Strategies (import)
|
|
47
|
+
|
|
48
|
+
| Strategy | Behavior |
|
|
49
|
+
|----------|----------|
|
|
50
|
+
| `merge` | New records added; existing records with same ID kept as-is |
|
|
51
|
+
| `overwrite` | New records replace existing ones with same ID |
|
|
52
|
+
| `skip` | Skip entire section if any file already exists in org |
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Step 0 — Brain Load (standalone only)
|
|
57
|
+
|
|
58
|
+
If `caller` is not "command", load brain context following _protocol.md Brain Load Procedure with namespace: `ops`.
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Step 1 — Validate Org
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
orgFile=".monomind/orgs/${org_name}.json"
|
|
66
|
+
[ ! -f "$orgFile" ] && { echo "ERROR: Org '${org_name}' not found."; exit 1; }
|
|
67
|
+
|
|
68
|
+
exportsDir=".monomind/exports"
|
|
69
|
+
mkdir -p "$exportsDir"
|
|
70
|
+
ts=$(date -u +%Y%m%dT%H%M%SZ)
|
|
71
|
+
defaultOutput="${exportsDir}/${org_name}-${ts}.tar.gz"
|
|
72
|
+
outputPath="${output_path:-$defaultOutput}"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Step 2 — Execute Action
|
|
78
|
+
|
|
79
|
+
### preview
|
|
80
|
+
|
|
81
|
+
Show what would be included in an export without writing anything:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
echo "EXPORT PREVIEW — org: $org_name"
|
|
85
|
+
echo "────────────────────────────────────────────────────────"
|
|
86
|
+
|
|
87
|
+
allSections="config goals routines projects members adapters environments workspaces activity"
|
|
88
|
+
includeSections="${include:-$allSections}"
|
|
89
|
+
|
|
90
|
+
for section in $allSections; do
|
|
91
|
+
echo "$includeSections" | grep -qw "$section" || continue
|
|
92
|
+
case "$section" in
|
|
93
|
+
config) srcFile=".monomind/orgs/${org_name}.json" ;;
|
|
94
|
+
goals) srcFile=".monomind/orgs/${org_name}-goals.json" ;;
|
|
95
|
+
routines) srcFile=".monomind/orgs/${org_name}-routines.json" ;;
|
|
96
|
+
projects) srcFile=".monomind/orgs/${org_name}-projects.json" ;;
|
|
97
|
+
members) srcFile=".monomind/orgs/${org_name}-members.json" ;;
|
|
98
|
+
adapters) srcFile=".monomind/orgs/${org_name}-adapters.json" ;;
|
|
99
|
+
environments) srcFile=".monomind/orgs/${org_name}-environments.json" ;;
|
|
100
|
+
workspaces) srcFile=".monomind/orgs/${org_name}-workspaces.json" ;;
|
|
101
|
+
activity) srcFile=".monomind/orgs/${org_name}-activity.jsonl" ;;
|
|
102
|
+
secrets-refs) srcFile=".monomind/orgs/.secrets/${org_name}/" ;;
|
|
103
|
+
esac
|
|
104
|
+
if [ -f "$srcFile" ] || [ -d "$srcFile" ]; then
|
|
105
|
+
size=$(du -sh "$srcFile" 2>/dev/null | cut -f1 || echo "?")
|
|
106
|
+
echo " ✓ $section ($srcFile) [$size]"
|
|
107
|
+
else
|
|
108
|
+
echo " - $section ($srcFile) [not found — will be skipped]"
|
|
109
|
+
fi
|
|
110
|
+
done
|
|
111
|
+
|
|
112
|
+
echo ""
|
|
113
|
+
echo "Output would be: $outputPath"
|
|
114
|
+
echo "Run with --action export to proceed."
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### export
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
echo "Exporting org '$org_name'…"
|
|
121
|
+
|
|
122
|
+
allSections="config goals routines projects members adapters environments workspaces activity"
|
|
123
|
+
includeSections="${include:-$allSections}"
|
|
124
|
+
|
|
125
|
+
# Build list of files to include
|
|
126
|
+
tmpDir=$(mktemp -d)
|
|
127
|
+
orgExportDir="${tmpDir}/${org_name}"
|
|
128
|
+
mkdir -p "$orgExportDir"
|
|
129
|
+
|
|
130
|
+
fileCount=0
|
|
131
|
+
for section in $allSections; do
|
|
132
|
+
echo "$includeSections" | grep -qw "$section" || continue
|
|
133
|
+
case "$section" in
|
|
134
|
+
config) srcFile=".monomind/orgs/${org_name}.json" ; dstName="${org_name}.json" ;;
|
|
135
|
+
goals) srcFile=".monomind/orgs/${org_name}-goals.json" ; dstName="${org_name}-goals.json" ;;
|
|
136
|
+
routines) srcFile=".monomind/orgs/${org_name}-routines.json" ; dstName="${org_name}-routines.json" ;;
|
|
137
|
+
projects) srcFile=".monomind/orgs/${org_name}-projects.json" ; dstName="${org_name}-projects.json" ;;
|
|
138
|
+
members) srcFile=".monomind/orgs/${org_name}-members.json" ; dstName="${org_name}-members.json" ;;
|
|
139
|
+
adapters) srcFile=".monomind/orgs/${org_name}-adapters.json" ; dstName="${org_name}-adapters.json" ;;
|
|
140
|
+
environments) srcFile=".monomind/orgs/${org_name}-environments.json" ; dstName="${org_name}-environments.json" ;;
|
|
141
|
+
workspaces) srcFile=".monomind/orgs/${org_name}-workspaces.json" ; dstName="${org_name}-workspaces.json" ;;
|
|
142
|
+
activity) srcFile=".monomind/orgs/${org_name}-activity.jsonl" ; dstName="${org_name}-activity.jsonl" ;;
|
|
143
|
+
secrets-refs)
|
|
144
|
+
# Export ONLY secret reference names — NO values
|
|
145
|
+
secretsDir=".monomind/orgs/.secrets/${org_name}"
|
|
146
|
+
if [ -d "$secretsDir" ]; then
|
|
147
|
+
refsList=$(ls "$secretsDir" 2>/dev/null | jq -Rsc 'split("\n") | map(select(. != ""))')
|
|
148
|
+
echo "{\"secret_refs\":$refsList,\"note\":\"values_not_exported\"}" > "${orgExportDir}/${org_name}-secret-refs.json"
|
|
149
|
+
echo " ✓ secrets-refs (reference names only)"
|
|
150
|
+
fileCount=$((fileCount + 1))
|
|
151
|
+
fi
|
|
152
|
+
continue ;;
|
|
153
|
+
esac
|
|
154
|
+
if [ -f "$srcFile" ]; then
|
|
155
|
+
# For environments: strip key material before including
|
|
156
|
+
if [ "$section" = "environments" ]; then
|
|
157
|
+
jq '.environments = [.environments[] | del(.key_material,.private_key,.ssh_key,.password)]' \
|
|
158
|
+
"$srcFile" > "${orgExportDir}/${dstName}"
|
|
159
|
+
elif [ "$section" = "activity" ]; then
|
|
160
|
+
# Only last 500 events
|
|
161
|
+
tail -500 "$srcFile" > "${orgExportDir}/${dstName}"
|
|
162
|
+
else
|
|
163
|
+
cp "$srcFile" "${orgExportDir}/${dstName}"
|
|
164
|
+
fi
|
|
165
|
+
echo " ✓ $section"
|
|
166
|
+
fileCount=$((fileCount + 1))
|
|
167
|
+
else
|
|
168
|
+
echo " - $section (skipped — file not found)"
|
|
169
|
+
fi
|
|
170
|
+
done
|
|
171
|
+
|
|
172
|
+
# Write manifest
|
|
173
|
+
jq -cn \
|
|
174
|
+
--arg org "$org_name" \
|
|
175
|
+
--arg ts "$ts" \
|
|
176
|
+
--arg sections "$includeSections" \
|
|
177
|
+
--argjson files "$fileCount" \
|
|
178
|
+
'{"org":$org,"exported_at":$ts,"sections":($sections|split(" ")),"file_count":$files,"version":"1.0"}' \
|
|
179
|
+
> "${orgExportDir}/manifest.json"
|
|
180
|
+
|
|
181
|
+
# Create archive
|
|
182
|
+
tar -czf "$outputPath" -C "$tmpDir" "$org_name" 2>/dev/null
|
|
183
|
+
rm -rf "$tmpDir"
|
|
184
|
+
|
|
185
|
+
echo ""
|
|
186
|
+
echo "Export complete: $outputPath"
|
|
187
|
+
echo " Files: $fileCount | Sections: $includeSections"
|
|
188
|
+
echo " Size: $(du -sh "$outputPath" 2>/dev/null | cut -f1)"
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### import
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
[ -z "$input_path" ] && { echo "ERROR: --input-path required."; exit 1; }
|
|
195
|
+
[ ! -f "$input_path" ] && { echo "ERROR: Archive not found: $input_path"; exit 1; }
|
|
196
|
+
|
|
197
|
+
collision="${collision_strategy:-merge}"
|
|
198
|
+
case "$collision" in merge|overwrite|skip) : ;; *)
|
|
199
|
+
echo "ERROR: --collision-strategy must be merge, overwrite, or skip"; exit 1 ;;
|
|
200
|
+
esac
|
|
201
|
+
|
|
202
|
+
dryRun="${dry_run:-false}"
|
|
203
|
+
[ "$dryRun" = "true" ] && echo "DRY RUN — no changes will be written."
|
|
204
|
+
|
|
205
|
+
echo "IMPORT — org: $org_name"
|
|
206
|
+
echo "Collision strategy: $collision"
|
|
207
|
+
[ -n "$adapter_override" ] && echo "Adapter override: $adapter_override"
|
|
208
|
+
echo "────────────────────────────────────────────────────────"
|
|
209
|
+
|
|
210
|
+
# Extract archive to temp dir
|
|
211
|
+
tmpDir=$(mktemp -d)
|
|
212
|
+
tar -xzf "$input_path" -C "$tmpDir" 2>/dev/null || { echo "ERROR: Failed to extract archive."; rm -rf "$tmpDir"; exit 1; }
|
|
213
|
+
|
|
214
|
+
# Find org dir in archive
|
|
215
|
+
archiveOrgDir=$(find "$tmpDir" -name "manifest.json" -maxdepth 3 | head -1 | xargs dirname 2>/dev/null)
|
|
216
|
+
[ -z "$archiveOrgDir" ] && { echo "ERROR: No manifest.json found in archive. Invalid export?"; rm -rf "$tmpDir"; exit 1; }
|
|
217
|
+
|
|
218
|
+
archiveOrg=$(jq -r '.org // ""' "${archiveOrgDir}/manifest.json")
|
|
219
|
+
echo "Archive org: $archiveOrg → importing as: $org_name"
|
|
220
|
+
echo ""
|
|
221
|
+
|
|
222
|
+
imported=0
|
|
223
|
+
skipped=0
|
|
224
|
+
for srcFile in "${archiveOrgDir}"/*.json "${archiveOrgDir}"/*.jsonl; do
|
|
225
|
+
[ -f "$srcFile" ] || continue
|
|
226
|
+
# Rewrite filename for target org name
|
|
227
|
+
dstName=$(basename "$srcFile" | sed "s/^${archiveOrg}/${org_name}/")
|
|
228
|
+
dstPath=".monomind/orgs/${dstName}"
|
|
229
|
+
|
|
230
|
+
# Skip manifest
|
|
231
|
+
[[ "$dstName" == "manifest.json" ]] && continue
|
|
232
|
+
|
|
233
|
+
# Skip secret refs — never auto-import
|
|
234
|
+
[[ "$dstName" == *secret-refs* ]] && echo " SKIP: secret refs (never auto-imported)" && continue
|
|
235
|
+
|
|
236
|
+
# Apply adapter override
|
|
237
|
+
if [ -n "$adapter_override" ] && [[ "$dstName" == *-adapters.json ]]; then
|
|
238
|
+
echo " OVERRIDE: applying adapter_override=$adapter_override to adapters file"
|
|
239
|
+
fi
|
|
240
|
+
|
|
241
|
+
if [ -f "$dstPath" ]; then
|
|
242
|
+
case "$collision" in
|
|
243
|
+
skip)
|
|
244
|
+
echo " SKIP: $dstName (exists, strategy=skip)"
|
|
245
|
+
skipped=$((skipped + 1))
|
|
246
|
+
continue ;;
|
|
247
|
+
merge)
|
|
248
|
+
echo " MERGE: $dstName"
|
|
249
|
+
if [ "$dryRun" = "false" ]; then
|
|
250
|
+
# JSON files: merge arrays; jsonl files: append deduplicated
|
|
251
|
+
if [[ "$dstPath" == *.jsonl ]]; then
|
|
252
|
+
cat "$srcFile" >> "$dstPath"
|
|
253
|
+
else
|
|
254
|
+
# Merge: combine top-level arrays from both files
|
|
255
|
+
python3 -c "
|
|
256
|
+
import json, sys
|
|
257
|
+
with open('$dstPath') as f: existing = json.load(f)
|
|
258
|
+
with open('$srcFile') as f: incoming = json.load(f)
|
|
259
|
+
for k, v in incoming.items():
|
|
260
|
+
if isinstance(v, list) and isinstance(existing.get(k), list):
|
|
261
|
+
existIds = {i.get('id') for i in existing[k] if isinstance(i,dict)}
|
|
262
|
+
existing[k] += [i for i in v if isinstance(i,dict) and i.get('id') not in existIds]
|
|
263
|
+
elif k not in existing:
|
|
264
|
+
existing[k] = v
|
|
265
|
+
with open('$dstPath', 'w') as f: json.dump(existing, f, indent=2)
|
|
266
|
+
" 2>/dev/null || cp "$srcFile" "$dstPath"
|
|
267
|
+
fi
|
|
268
|
+
fi ;;
|
|
269
|
+
overwrite)
|
|
270
|
+
echo " OVERWRITE: $dstName"
|
|
271
|
+
[ "$dryRun" = "false" ] && cp "$srcFile" "$dstPath" ;;
|
|
272
|
+
esac
|
|
273
|
+
else
|
|
274
|
+
echo " CREATE: $dstName (new)"
|
|
275
|
+
[ "$dryRun" = "false" ] && cp "$srcFile" "$dstPath"
|
|
276
|
+
fi
|
|
277
|
+
imported=$((imported + 1))
|
|
278
|
+
done
|
|
279
|
+
|
|
280
|
+
rm -rf "$tmpDir"
|
|
281
|
+
echo ""
|
|
282
|
+
[ "$dryRun" = "true" ] && echo "DRY RUN complete — $imported file(s) would be imported, $skipped skipped." \
|
|
283
|
+
|| echo "Import complete — $imported file(s) imported, $skipped skipped."
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
### list-archives
|
|
287
|
+
|
|
288
|
+
```bash
|
|
289
|
+
echo "EXPORT ARCHIVES — org: $org_name"
|
|
290
|
+
echo "────────────────────────────────────────────────────────"
|
|
291
|
+
|
|
292
|
+
found=0
|
|
293
|
+
for f in ".monomind/exports/${org_name}-"*.tar.gz ".monomind/exports/${org_name}-"*.zip; do
|
|
294
|
+
[ -f "$f" ] || continue
|
|
295
|
+
size=$(du -sh "$f" 2>/dev/null | cut -f1 || echo "?")
|
|
296
|
+
ts=$(stat -f "%Sm" -t "%Y-%m-%d %H:%M" "$f" 2>/dev/null || stat -c "%y" "$f" 2>/dev/null | cut -c1-16 || echo "?")
|
|
297
|
+
printf " %-50s %8s %s\n" "$(basename "$f")" "$size" "$ts"
|
|
298
|
+
found=$((found + 1))
|
|
299
|
+
done
|
|
300
|
+
|
|
301
|
+
[ "$found" -eq 0 ] && echo " No archives found. Run --action export to create one."
|
|
302
|
+
echo ""
|
|
303
|
+
echo "Total: $found archive(s) in .monomind/exports/"
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
---
|
|
307
|
+
|
|
308
|
+
## Step 3 — Return Output
|
|
309
|
+
|
|
310
|
+
```yaml
|
|
311
|
+
domain: ops
|
|
312
|
+
status: complete
|
|
313
|
+
action: <action>
|
|
314
|
+
org: <org_name>
|
|
315
|
+
output_path: <path if export>
|
|
316
|
+
files_processed: <N>
|
|
317
|
+
collision_strategy: <strategy if import>
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
---
|
|
321
|
+
|
|
322
|
+
## Step 4 — Brain Write (standalone only)
|
|
323
|
+
|
|
324
|
+
If `caller` is not "command", follow _protocol.md Brain Write Procedure for domain `ops`.
|