create-egregore 0.17.3 → 0.18.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/assets/egregore-launcher.js +1965 -0
- package/assets/egregore-launcher.sh +385 -0
- package/bin/cli.js +472 -81
- package/lib/api.js +3 -3
- package/lib/auth.js +255 -20
- package/lib/codex-runtime.js +268 -0
- package/lib/commands.js +31 -0
- package/lib/context.js +1 -1
- package/lib/local.js +618 -193
- package/lib/setup.js +837 -85
- package/lib/ui.js +780 -84
- package/package.json +17 -4
- package/runtime/codex/.codex/config.toml +15 -0
- package/runtime/codex/.codex/hooks/branch-guard.js +234 -0
- package/runtime/codex/.codex/hooks.json +17 -0
- package/runtime/codex/.codex/skills/activity/SKILL.md +70 -0
- package/runtime/codex/.codex/skills/add/SKILL.md +25 -0
- package/runtime/codex/.codex/skills/announce/SKILL.md +54 -0
- package/runtime/codex/.codex/skills/answer/SKILL.md +25 -0
- package/runtime/codex/.codex/skills/archive/SKILL.md +41 -0
- package/runtime/codex/.codex/skills/ask/SKILL.md +59 -0
- package/runtime/codex/.codex/skills/branch/SKILL.md +25 -0
- package/runtime/codex/.codex/skills/checkup/SKILL.md +41 -0
- package/runtime/codex/.codex/skills/comment/SKILL.md +25 -0
- package/runtime/codex/.codex/skills/commit/SKILL.md +25 -0
- package/runtime/codex/.codex/skills/contribute/SKILL.md +25 -0
- package/runtime/codex/.codex/skills/dark-mode/SKILL.md +25 -0
- package/runtime/codex/.codex/skills/dashboard/SKILL.md +59 -0
- package/runtime/codex/.codex/skills/deep-reflect/SKILL.md +70 -0
- package/runtime/codex/.codex/skills/delete-user/SKILL.md +25 -0
- package/runtime/codex/.codex/skills/edit/SKILL.md +25 -0
- package/runtime/codex/.codex/skills/edit-process/SKILL.md +25 -0
- package/runtime/codex/.codex/skills/egregore-voice/SKILL.md +25 -0
- package/runtime/codex/.codex/skills/emissary/SKILL.md +41 -0
- package/runtime/codex/.codex/skills/env/SKILL.md +25 -0
- package/runtime/codex/.codex/skills/handoff/SKILL.md +67 -0
- package/runtime/codex/.codex/skills/harvest/SKILL.md +107 -0
- package/runtime/codex/.codex/skills/infra/SKILL.md +41 -0
- package/runtime/codex/.codex/skills/ingest/SKILL.md +25 -0
- package/runtime/codex/.codex/skills/ingest-google/SKILL.md +25 -0
- package/runtime/codex/.codex/skills/ingest-user-interview/SKILL.md +41 -0
- package/runtime/codex/.codex/skills/invite/SKILL.md +40 -0
- package/runtime/codex/.codex/skills/issue/SKILL.md +41 -0
- package/runtime/codex/.codex/skills/me/SKILL.md +25 -0
- package/runtime/codex/.codex/skills/meeting/SKILL.md +41 -0
- package/runtime/codex/.codex/skills/note/SKILL.md +25 -0
- package/runtime/codex/.codex/skills/onboarding/SKILL.md +41 -0
- package/runtime/codex/.codex/skills/pr/SKILL.md +25 -0
- package/runtime/codex/.codex/skills/project/SKILL.md +41 -0
- package/runtime/codex/.codex/skills/pull/SKILL.md +25 -0
- package/runtime/codex/.codex/skills/push/SKILL.md +25 -0
- package/runtime/codex/.codex/skills/quest/SKILL.md +77 -0
- package/runtime/codex/.codex/skills/quest-suggest/SKILL.md +25 -0
- package/runtime/codex/.codex/skills/reflect/SKILL.md +41 -0
- package/runtime/codex/.codex/skills/review-pr/SKILL.md +41 -0
- package/runtime/codex/.codex/skills/save/SKILL.md +62 -0
- package/runtime/codex/.codex/skills/setup/SKILL.md +25 -0
- package/runtime/codex/.codex/skills/summon/SKILL.md +41 -0
- package/runtime/codex/.codex/skills/sync-repos/SKILL.md +25 -0
- package/runtime/codex/.codex/skills/telegram-connect/SKILL.md +25 -0
- package/runtime/codex/.codex/skills/telemetry/SKILL.md +25 -0
- package/runtime/codex/.codex/skills/test/SKILL.md +41 -0
- package/runtime/codex/.codex/skills/the-spiral/SKILL.md +84 -0
- package/runtime/codex/.codex/skills/todo/SKILL.md +41 -0
- package/runtime/codex/.codex/skills/tui-design/SKILL.md +41 -0
- package/runtime/codex/.codex/skills/tutorial/SKILL.md +41 -0
- package/runtime/codex/.codex/skills/update/SKILL.md +25 -0
- package/runtime/codex/.codex/skills/view/SKILL.md +41 -0
- package/runtime/codex/.codex/skills/visual-explain/SKILL.md +41 -0
- package/runtime/codex/.codex/skills/wrap/SKILL.md +55 -0
- package/runtime/codex/.codex/spec-manifest.json +108 -0
- package/runtime/codex/AGENTS.md +328 -0
- package/runtime/codex/bin/activity-data.sh +180 -0
- package/runtime/codex/bin/agent.sh +669 -0
- package/runtime/codex/bin/codex-install-skills.sh +78 -0
- package/runtime/codex/bin/codex-render-spec.mjs +308 -0
- package/runtime/codex/bin/codex-session-start.sh +238 -0
- package/runtime/codex/bin/codex-skill-render.mjs +315 -0
- package/runtime/codex/bin/codex-sync-skills.sh +223 -0
- package/runtime/codex/bin/dashboard-data.sh +178 -0
- package/runtime/codex/bin/graph-batch.sh +60 -0
- package/runtime/codex/bin/graph-op.sh +397 -0
- package/runtime/codex/bin/graph-wal.sh +228 -0
- package/runtime/codex/bin/graph.sh +141 -0
- package/runtime/codex/bin/handoff-pr-backfill.sh +86 -0
- package/runtime/codex/bin/handoff-run.sh +569 -0
- package/runtime/codex/bin/handoff-save-egregore.sh +131 -0
- package/runtime/codex/bin/index-handoff.sh +306 -0
- package/runtime/codex/bin/lib/artifact-id.sh +46 -0
- package/runtime/codex/bin/lib/config.sh +71 -0
- package/runtime/codex/bin/lib/context.sh +511 -0
- package/runtime/codex/bin/lib/dashboard-artifact.sh +142 -0
- package/runtime/codex/bin/lib/edit-loopback.mjs +652 -0
- package/runtime/codex/bin/lib/ensure-develop.sh +183 -0
- package/runtime/codex/bin/lib/git-sync.sh +262 -0
- package/runtime/codex/bin/lib/greeting.sh +432 -0
- package/runtime/codex/bin/lib/hash.sh +13 -0
- package/runtime/codex/bin/lib/identity.sh +164 -0
- package/runtime/codex/bin/lib/permissions.sh +106 -0
- package/runtime/codex/bin/lib/time.sh +56 -0
- package/runtime/codex/bin/lib/worktree-links.sh +54 -0
- package/runtime/codex/bin/notify.sh +207 -0
- package/runtime/codex/bin/publish-artifact.sh +187 -0
- package/runtime/codex/bin/publish-references.sh +144 -0
- package/runtime/codex/bin/repo-state.sh +99 -0
- package/runtime/codex/bin/telemetry.sh +350 -0
- package/runtime/codex/bin/worktree-create.sh +115 -0
- package/runtime/codex/bin/worktree-remove.sh +50 -0
- package/runtime/codex/bin/worktree.sh +199 -0
- package/runtime/codex/manifest.json +162 -0
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# egregore-launcher-version: 0.4.9
|
|
3
|
+
# egregore — launch an Egregore instance in Claude Code.
|
|
4
|
+
# Reads ~/.egregore/instances.json for the registry of installed egregores.
|
|
5
|
+
#
|
|
6
|
+
# Usage:
|
|
7
|
+
# egregore pick an instance (or launch the only one)
|
|
8
|
+
# egregore <slug|name> launch the matching instance
|
|
9
|
+
# egregore ls | list list installed instances
|
|
10
|
+
# egregore use <slug> set the default for bare `egregore`
|
|
11
|
+
# egregore prune remove entries whose path is gone
|
|
12
|
+
# egregore rm <slug|path> remove a specific entry
|
|
13
|
+
# egregore help | --help
|
|
14
|
+
# egregore --version
|
|
15
|
+
#
|
|
16
|
+
# Installed by create-egregore. Safe to move or edit — persistent state lives
|
|
17
|
+
# only in ~/.egregore/instances.json and ~/.egregore/default.
|
|
18
|
+
#
|
|
19
|
+
# The first line's "egregore-launcher-version" comment is read by
|
|
20
|
+
# installLauncherBinary() so newer create-egregore installs can auto-upgrade
|
|
21
|
+
# a stale binary. Don't rename or remove it.
|
|
22
|
+
|
|
23
|
+
set -u
|
|
24
|
+
|
|
25
|
+
VERSION="0.4.9"
|
|
26
|
+
REGISTRY="${HOME}/.egregore/instances.json"
|
|
27
|
+
DEFAULT_FILE="${HOME}/.egregore/default"
|
|
28
|
+
|
|
29
|
+
# ── colors ────────────────────────────────────────────────────────
|
|
30
|
+
if [ -t 1 ] && [ -z "${NO_COLOR:-}" ]; then
|
|
31
|
+
RESET=$'\e[0m'; BOLD=$'\e[1m'; DIM=$'\e[2m'
|
|
32
|
+
CYAN=$'\e[36m'; GREEN=$'\e[32m'; YELLOW=$'\e[33m'; RED=$'\e[31m'
|
|
33
|
+
else
|
|
34
|
+
RESET=""; BOLD=""; DIM=""; CYAN=""; GREEN=""; YELLOW=""; RED=""
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
die() {
|
|
38
|
+
printf '%segregore:%s %s\n' "$RED" "$RESET" "$*" >&2
|
|
39
|
+
exit 1
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
banner() {
|
|
43
|
+
printf '\n'
|
|
44
|
+
printf '%s%s ███████╗ ██████╗ ██████╗ ███████╗ ██████╗ ██████╗ ██████╗ ███████╗%s\n' "$BOLD" "$CYAN" "$RESET"
|
|
45
|
+
printf '%s%s ██╔════╝██╔════╝ ██╔══██╗██╔════╝██╔════╝ ██╔═══██╗██╔══██╗██╔════╝%s\n' "$BOLD" "$CYAN" "$RESET"
|
|
46
|
+
printf '%s%s █████╗ ██║ ███╗██████╔╝█████╗ ██║ ███╗██║ ██║██████╔╝█████╗%s\n' "$BOLD" "$CYAN" "$RESET"
|
|
47
|
+
printf '%s%s ██╔══╝ ██║ ██║██╔══██╗██╔══╝ ██║ ██║██║ ██║██╔══██╗██╔══╝%s\n' "$BOLD" "$CYAN" "$RESET"
|
|
48
|
+
printf '%s%s ███████╗╚██████╔╝██║ ██║███████╗╚██████╔╝╚██████╔╝██║ ██║███████╗%s\n' "$BOLD" "$CYAN" "$RESET"
|
|
49
|
+
printf '%s%s ╚══════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝%s\n' "$BOLD" "$CYAN" "$RESET"
|
|
50
|
+
printf '\n'
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
require_jq() {
|
|
54
|
+
command -v jq >/dev/null 2>&1 || die "jq is required but not installed (brew install jq)."
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
require_registry() {
|
|
58
|
+
[ -f "$REGISTRY" ] || die "No egregores installed yet. Run: npx -y create-egregore@latest"
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
list_instances() {
|
|
62
|
+
# Prints: <slug>\t<name>\t<path>
|
|
63
|
+
jq -r '.[] | [.slug, .name, .path] | @tsv' "$REGISTRY"
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
instance_count() {
|
|
67
|
+
jq 'length' "$REGISTRY"
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
resolve_instance() {
|
|
71
|
+
# $1 = slug or name (fuzzy-ish: exact slug first, then exact name, then case-insensitive contains)
|
|
72
|
+
local query="$1"
|
|
73
|
+
local result
|
|
74
|
+
result=$(jq -r --arg q "$query" '.[] | select(.slug == $q) | .path' "$REGISTRY" | head -n1)
|
|
75
|
+
if [ -z "$result" ]; then
|
|
76
|
+
result=$(jq -r --arg q "$query" '.[] | select(.name == $q) | .path' "$REGISTRY" | head -n1)
|
|
77
|
+
fi
|
|
78
|
+
if [ -z "$result" ]; then
|
|
79
|
+
local qlower
|
|
80
|
+
qlower=$(printf '%s' "$query" | tr '[:upper:]' '[:lower:]')
|
|
81
|
+
result=$(jq -r --arg q "$qlower" '
|
|
82
|
+
.[] | select((.slug | ascii_downcase | contains($q)) or (.name | ascii_downcase | contains($q))) | .path' "$REGISTRY" | head -n1)
|
|
83
|
+
fi
|
|
84
|
+
printf '%s' "$result"
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
launch() {
|
|
88
|
+
local target_path="$1"
|
|
89
|
+
local target_slug="${2:-}"
|
|
90
|
+
[ -d "$target_path" ] || die "Instance path does not exist: $target_path"
|
|
91
|
+
command -v claude >/dev/null 2>&1 || die "Claude Code is not installed. Install it from https://code.claude.com then try again."
|
|
92
|
+
if [ -n "$target_slug" ]; then
|
|
93
|
+
printf ' %s→%s launching %s%s%s ...\n\n' "$DIM" "$RESET" "$BOLD" "$target_slug" "$RESET"
|
|
94
|
+
fi
|
|
95
|
+
cd "$target_path" || die "Could not cd into $target_path"
|
|
96
|
+
exec claude start
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
cmd_ls() {
|
|
100
|
+
require_jq
|
|
101
|
+
require_registry
|
|
102
|
+
local default=""
|
|
103
|
+
[ -f "$DEFAULT_FILE" ] && default=$(cat "$DEFAULT_FILE" 2>/dev/null)
|
|
104
|
+
banner
|
|
105
|
+
local count
|
|
106
|
+
count=$(instance_count)
|
|
107
|
+
local plural="s"
|
|
108
|
+
[ "$count" -eq 1 ] && plural=""
|
|
109
|
+
printf ' %s%d egregore%s registered%s\n\n' "$BOLD" "$count" "$plural" "$RESET"
|
|
110
|
+
printf ' %s%-22s %-24s %s%s\n' "$DIM" "SLUG" "NAME" "PATH" "$RESET"
|
|
111
|
+
while IFS=$'\t' read -r slug name path; do
|
|
112
|
+
if [ "$slug" = "$default" ]; then
|
|
113
|
+
printf ' %s●%s %s%-22s%s %-24s %s%s%s\n' "$GREEN" "$RESET" "$BOLD" "$slug" "$RESET" "$name" "$DIM" "$path" "$RESET"
|
|
114
|
+
else
|
|
115
|
+
printf ' %-22s %-24s %s%s%s\n' "$slug" "$name" "$DIM" "$path" "$RESET"
|
|
116
|
+
fi
|
|
117
|
+
done < <(list_instances)
|
|
118
|
+
printf '\n'
|
|
119
|
+
if [ -n "$default" ]; then
|
|
120
|
+
printf ' %s●%s = default (bare %segregore%s launches this)\n\n' "$GREEN" "$RESET" "$BOLD" "$RESET"
|
|
121
|
+
fi
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
cmd_use() {
|
|
125
|
+
require_jq
|
|
126
|
+
require_registry
|
|
127
|
+
local slug="${1:-}"
|
|
128
|
+
[ -n "$slug" ] || die "Usage: egregore use <slug>"
|
|
129
|
+
local found
|
|
130
|
+
found=$(jq -r --arg q "$slug" '.[] | select(.slug == $q) | .slug' "$REGISTRY" | head -n1)
|
|
131
|
+
[ -n "$found" ] || die "No instance with slug '$slug'. Run: egregore ls"
|
|
132
|
+
mkdir -p "$(dirname "$DEFAULT_FILE")"
|
|
133
|
+
printf '%s\n' "$found" > "$DEFAULT_FILE"
|
|
134
|
+
printf ' %s✓%s default set to %s%s%s\n' "$GREEN" "$RESET" "$BOLD" "$found" "$RESET"
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
# ── registry maintenance ─────────────────────────────────────────
|
|
138
|
+
#
|
|
139
|
+
# Atomic write: filter via jq to a tmp file, then rename. Backup every
|
|
140
|
+
# mutation to ~/.egregore/instances.json.bak.<timestamp> so a mis-click
|
|
141
|
+
# is always reversible.
|
|
142
|
+
|
|
143
|
+
backup_registry() {
|
|
144
|
+
local ts
|
|
145
|
+
ts=$(date +%Y%m%d-%H%M%S)
|
|
146
|
+
local bak="${HOME}/.egregore/instances.json.bak.${ts}"
|
|
147
|
+
cp "$REGISTRY" "$bak"
|
|
148
|
+
printf '%s' "$bak"
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
cmd_prune() {
|
|
152
|
+
require_jq
|
|
153
|
+
require_registry
|
|
154
|
+
banner
|
|
155
|
+
|
|
156
|
+
# Collect stale entries (path doesn't exist on disk)
|
|
157
|
+
local -a stale_slugs=()
|
|
158
|
+
local -a stale_paths=()
|
|
159
|
+
while IFS=$'\t' read -r slug path; do
|
|
160
|
+
[ -d "$path" ] || { stale_slugs+=("$slug"); stale_paths+=("$path"); }
|
|
161
|
+
done < <(jq -r '.[] | [.slug, .path] | @tsv' "$REGISTRY")
|
|
162
|
+
|
|
163
|
+
local count_before count_stale
|
|
164
|
+
count_before=$(instance_count)
|
|
165
|
+
count_stale=${#stale_paths[@]}
|
|
166
|
+
|
|
167
|
+
if [ "$count_stale" -eq 0 ]; then
|
|
168
|
+
printf ' %s✓%s registry is clean — %d entries, all paths exist.\n\n' "$GREEN" "$RESET" "$count_before"
|
|
169
|
+
return 0
|
|
170
|
+
fi
|
|
171
|
+
|
|
172
|
+
printf ' %s⚠%s %d of %d entries have missing paths:\n\n' "$YELLOW" "$RESET" "$count_stale" "$count_before"
|
|
173
|
+
local i=0
|
|
174
|
+
while [ "$i" -lt "$count_stale" ]; do
|
|
175
|
+
printf ' %s✗%s %-22s %s%s%s\n' "$RED" "$RESET" "${stale_slugs[$i]}" "$DIM" "${stale_paths[$i]}" "$RESET"
|
|
176
|
+
i=$((i + 1))
|
|
177
|
+
done
|
|
178
|
+
printf '\n'
|
|
179
|
+
|
|
180
|
+
# Dry run short-circuit
|
|
181
|
+
if [ "${1:-}" = "--dry-run" ] || [ "${1:-}" = "-n" ]; then
|
|
182
|
+
printf ' %s(dry run — nothing removed. re-run without --dry-run to apply.)%s\n\n' "$DIM" "$RESET"
|
|
183
|
+
return 0
|
|
184
|
+
fi
|
|
185
|
+
|
|
186
|
+
printf ' %s?%s remove them? [y/N]: ' "$CYAN" "$RESET"
|
|
187
|
+
read -r confirm
|
|
188
|
+
case "$confirm" in
|
|
189
|
+
y|Y|yes|YES) ;;
|
|
190
|
+
*) printf ' %sCancelled.%s\n\n' "$DIM" "$RESET"; return 0 ;;
|
|
191
|
+
esac
|
|
192
|
+
|
|
193
|
+
local bak
|
|
194
|
+
bak=$(backup_registry)
|
|
195
|
+
|
|
196
|
+
local tmp="${REGISTRY}.tmp.$$"
|
|
197
|
+
# Keep only entries whose path still exists. The filesystem is the source
|
|
198
|
+
# of truth — no path strings in the filter itself.
|
|
199
|
+
jq '[.[] | select(.path as $p | ($p | @sh) as $_ | true)]' "$REGISTRY" > /dev/null 2>&1 || true
|
|
200
|
+
# Actual filter: stream entries, read each path, bash test, emit if exists.
|
|
201
|
+
# We rebuild the JSON array outside jq because jq can't check filesystem.
|
|
202
|
+
{
|
|
203
|
+
printf '['
|
|
204
|
+
local first=1
|
|
205
|
+
while IFS=$'\t' read -r slug name path; do
|
|
206
|
+
if [ -d "$path" ]; then
|
|
207
|
+
[ "$first" -eq 0 ] && printf ','
|
|
208
|
+
jq -n --arg slug "$slug" --arg name "$name" --arg path "$path" \
|
|
209
|
+
'{slug: $slug, name: $name, path: $path}' | jq -c .
|
|
210
|
+
first=0
|
|
211
|
+
fi
|
|
212
|
+
done < <(jq -r '.[] | [.slug, .name, .path] | @tsv' "$REGISTRY")
|
|
213
|
+
printf ']'
|
|
214
|
+
} | jq '.' > "$tmp"
|
|
215
|
+
|
|
216
|
+
mv "$tmp" "$REGISTRY"
|
|
217
|
+
local count_after
|
|
218
|
+
count_after=$(instance_count)
|
|
219
|
+
printf ' %s✓%s pruned %d — %d remain.\n' "$GREEN" "$RESET" "$((count_before - count_after))" "$count_after"
|
|
220
|
+
printf ' %sbackup:%s %s\n\n' "$DIM" "$RESET" "$bak"
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
cmd_rm() {
|
|
224
|
+
require_jq
|
|
225
|
+
require_registry
|
|
226
|
+
local target="${1:-}"
|
|
227
|
+
[ -n "$target" ] || die "Usage: egregore rm <slug-or-path>"
|
|
228
|
+
|
|
229
|
+
# Find matches: exact slug, exact path, or substring match on either
|
|
230
|
+
local matches
|
|
231
|
+
matches=$(jq -r --arg q "$target" '
|
|
232
|
+
.[] | select(.slug == $q or .path == $q or
|
|
233
|
+
(.slug | contains($q)) or (.path | contains($q)))
|
|
234
|
+
| [.slug, .name, .path] | @tsv' "$REGISTRY")
|
|
235
|
+
|
|
236
|
+
if [ -z "$matches" ]; then
|
|
237
|
+
die "No instance matching '$target'. Run: egregore ls"
|
|
238
|
+
fi
|
|
239
|
+
|
|
240
|
+
local match_count
|
|
241
|
+
match_count=$(printf '%s\n' "$matches" | wc -l | tr -d ' ')
|
|
242
|
+
|
|
243
|
+
if [ "$match_count" -gt 1 ]; then
|
|
244
|
+
printf '\n %s⚠%s %d instances match %s"%s"%s:\n\n' "$YELLOW" "$RESET" "$match_count" "$BOLD" "$target" "$RESET"
|
|
245
|
+
printf '%s\n' "$matches" | while IFS=$'\t' read -r slug name path; do
|
|
246
|
+
printf ' %-22s %-24s %s%s%s\n' "$slug" "$name" "$DIM" "$path" "$RESET"
|
|
247
|
+
done
|
|
248
|
+
printf '\n %sUse an exact path to pick one:%s\n' "$DIM" "$RESET"
|
|
249
|
+
printf ' egregore rm <full-path>\n\n'
|
|
250
|
+
exit 1
|
|
251
|
+
fi
|
|
252
|
+
|
|
253
|
+
local slug name path
|
|
254
|
+
IFS=$'\t' read -r slug name path <<< "$matches"
|
|
255
|
+
printf '\n about to remove:\n'
|
|
256
|
+
printf ' %-22s %-24s %s%s%s\n\n' "$slug" "$name" "$DIM" "$path" "$RESET"
|
|
257
|
+
printf ' %s?%s confirm? [y/N]: ' "$CYAN" "$RESET"
|
|
258
|
+
read -r confirm
|
|
259
|
+
case "$confirm" in
|
|
260
|
+
y|Y|yes|YES) ;;
|
|
261
|
+
*) printf ' %sCancelled.%s\n\n' "$DIM" "$RESET"; return 0 ;;
|
|
262
|
+
esac
|
|
263
|
+
|
|
264
|
+
local bak
|
|
265
|
+
bak=$(backup_registry)
|
|
266
|
+
|
|
267
|
+
local tmp="${REGISTRY}.tmp.$$"
|
|
268
|
+
jq --arg p "$path" '[.[] | select(.path != $p)]' "$REGISTRY" > "$tmp"
|
|
269
|
+
mv "$tmp" "$REGISTRY"
|
|
270
|
+
|
|
271
|
+
printf ' %s✓%s removed.\n' "$GREEN" "$RESET"
|
|
272
|
+
printf ' %sbackup:%s %s\n\n' "$DIM" "$RESET" "$bak"
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
cmd_help() {
|
|
276
|
+
banner
|
|
277
|
+
printf ' %sUSAGE%s\n' "$BOLD" "$RESET"
|
|
278
|
+
printf ' %segregore%s pick an instance (or launch the only one)\n' "$CYAN" "$RESET"
|
|
279
|
+
printf ' %segregore %s<slug|name>%s launch the matching instance\n' "$CYAN" "$DIM" "$RESET"
|
|
280
|
+
printf ' %segregore ls%s list installed instances\n' "$CYAN" "$RESET"
|
|
281
|
+
printf ' %segregore use %s<slug>%s set the default for bare `egregore`\n' "$CYAN" "$DIM" "$RESET"
|
|
282
|
+
printf ' %segregore prune%s remove entries whose path is gone %s(--dry-run to preview)%s\n' "$CYAN" "$RESET" "$DIM" "$RESET"
|
|
283
|
+
printf ' %segregore rm %s<slug-or-path>%s remove a specific entry\n' "$CYAN" "$DIM" "$RESET"
|
|
284
|
+
printf ' %segregore --help%s\n' "$CYAN" "$RESET"
|
|
285
|
+
printf ' %segregore --version%s\n' "$CYAN" "$RESET"
|
|
286
|
+
printf '\n %sREGISTRY%s\n' "$BOLD" "$RESET"
|
|
287
|
+
printf ' Instances live in ~/.egregore/instances.json (written by the installer).\n'
|
|
288
|
+
printf ' Default selection lives in ~/.egregore/default.\n'
|
|
289
|
+
printf ' Every mutation backs up to ~/.egregore/instances.json.bak.<timestamp>.\n\n'
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
# ── picker ────────────────────────────────────────────────────────
|
|
293
|
+
#
|
|
294
|
+
# Shown when the user runs bare `egregore` with multiple instances and no
|
|
295
|
+
# default set. Numbered list + prompt that accepts numeric or slug input.
|
|
296
|
+
|
|
297
|
+
picker() {
|
|
298
|
+
banner
|
|
299
|
+
printf ' %s◆%s pick an instance to launch:\n\n' "$CYAN" "$RESET"
|
|
300
|
+
local -a slug_arr=()
|
|
301
|
+
local -a path_arr=()
|
|
302
|
+
local -a name_arr=()
|
|
303
|
+
while IFS=$'\t' read -r slug name path; do
|
|
304
|
+
slug_arr+=("$slug")
|
|
305
|
+
path_arr+=("$path")
|
|
306
|
+
name_arr+=("$name")
|
|
307
|
+
done < <(list_instances)
|
|
308
|
+
|
|
309
|
+
local default=""
|
|
310
|
+
[ -f "$DEFAULT_FILE" ] && default=$(cat "$DEFAULT_FILE" 2>/dev/null)
|
|
311
|
+
|
|
312
|
+
local idx=1
|
|
313
|
+
for slug in "${slug_arr[@]}"; do
|
|
314
|
+
local marker=" "
|
|
315
|
+
[ "$slug" = "$default" ] && marker="${GREEN}●${RESET} "
|
|
316
|
+
printf ' %s%2d)%s %s %s%-22s%s %s%s%s\n' \
|
|
317
|
+
"$DIM" "$idx" "$RESET" "$marker" "$BOLD" "$slug" "$RESET" "$DIM" "${name_arr[$((idx-1))]}" "$RESET"
|
|
318
|
+
idx=$((idx + 1))
|
|
319
|
+
done
|
|
320
|
+
printf '\n'
|
|
321
|
+
printf ' %s?%s enter number or slug: ' "$CYAN" "$RESET"
|
|
322
|
+
read -r choice
|
|
323
|
+
[ -n "$choice" ] || die "No selection."
|
|
324
|
+
|
|
325
|
+
# Numeric choice
|
|
326
|
+
if printf '%s' "$choice" | grep -Eq '^[0-9]+$'; then
|
|
327
|
+
local chosen_idx=$((choice - 1))
|
|
328
|
+
if [ "$chosen_idx" -ge 0 ] && [ "$chosen_idx" -lt "${#path_arr[@]}" ]; then
|
|
329
|
+
launch "${path_arr[$chosen_idx]}" "${slug_arr[$chosen_idx]}"
|
|
330
|
+
fi
|
|
331
|
+
die "Invalid selection: $choice"
|
|
332
|
+
fi
|
|
333
|
+
|
|
334
|
+
# Non-numeric: treat as slug/name
|
|
335
|
+
local target
|
|
336
|
+
target=$(resolve_instance "$choice")
|
|
337
|
+
[ -n "$target" ] || die "No instance matching '$choice'."
|
|
338
|
+
launch "$target" "$choice"
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
# ── main ──────────────────────────────────────────────────────────
|
|
342
|
+
|
|
343
|
+
case "${1:-}" in
|
|
344
|
+
--help|-h|help) cmd_help; exit 0 ;;
|
|
345
|
+
--version|-V|version) echo "egregore $VERSION"; exit 0 ;;
|
|
346
|
+
ls|list) shift; cmd_ls "$@"; exit 0 ;;
|
|
347
|
+
use) shift; cmd_use "$@"; exit 0 ;;
|
|
348
|
+
prune) shift; cmd_prune "$@"; exit 0 ;;
|
|
349
|
+
rm|remove) shift; cmd_rm "$@"; exit 0 ;;
|
|
350
|
+
esac
|
|
351
|
+
|
|
352
|
+
require_jq
|
|
353
|
+
require_registry
|
|
354
|
+
|
|
355
|
+
count=$(instance_count)
|
|
356
|
+
|
|
357
|
+
if [ "$count" -eq 0 ]; then
|
|
358
|
+
die "No egregores installed yet. Run: npx -y create-egregore@latest"
|
|
359
|
+
fi
|
|
360
|
+
|
|
361
|
+
# Explicit instance requested — fast path, no banner
|
|
362
|
+
if [ $# -gt 0 ]; then
|
|
363
|
+
target=$(resolve_instance "$1")
|
|
364
|
+
[ -n "$target" ] || die "No instance matching '$1'. Run: egregore ls"
|
|
365
|
+
launch "$target" "$1"
|
|
366
|
+
fi
|
|
367
|
+
|
|
368
|
+
# No args — use default if set, or only instance, else picker
|
|
369
|
+
if [ -f "$DEFAULT_FILE" ]; then
|
|
370
|
+
default_slug=$(cat "$DEFAULT_FILE" 2>/dev/null)
|
|
371
|
+
if [ -n "$default_slug" ]; then
|
|
372
|
+
target=$(jq -r --arg q "$default_slug" '.[] | select(.slug == $q) | .path' "$REGISTRY" | head -n1)
|
|
373
|
+
if [ -n "$target" ]; then
|
|
374
|
+
launch "$target" "$default_slug"
|
|
375
|
+
fi
|
|
376
|
+
fi
|
|
377
|
+
fi
|
|
378
|
+
|
|
379
|
+
if [ "$count" -eq 1 ]; then
|
|
380
|
+
target=$(jq -r '.[0].path' "$REGISTRY")
|
|
381
|
+
slug=$(jq -r '.[0].slug' "$REGISTRY")
|
|
382
|
+
launch "$target" "$slug"
|
|
383
|
+
fi
|
|
384
|
+
|
|
385
|
+
picker
|