-
Notifications
You must be signed in to change notification settings - Fork 17
Expand file tree
/
Copy pathsetup
More file actions
executable file
·160 lines (136 loc) · 5.35 KB
/
Copy pathsetup
File metadata and controls
executable file
·160 lines (136 loc) · 5.35 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#!/bin/sh
# brain.md installer — fan out the root-level skills/ to the global skills
# directory of each agent runtime you choose (symlinks). Agent-agnostic, zero
# dependencies, idempotent.
#
# Tools (skills + the brain CLI) install globally, once, across all projects.
# This NEVER touches any project's brain knowledge — that is per-project state,
# created on demand by the brain-setup skill and never managed from here.
#
# Usage: ./setup [--yes|-y]
# --yes, -y non-interactive: install into every detected runtime without
# asking (for CI). Default is to ask about each runtime, y/N.
set -eu
ASSUME_YES=0
for arg in "$@"; do
case "$arg" in
--yes|-y) ASSUME_YES=1 ;;
*) echo "setup: unknown option '$arg'" >&2; exit 2 ;;
esac
done
# Resolve the directory this script lives in (the repo root).
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd -P)
SRC="$SCRIPT_DIR/skills"
if [ ! -d "$SRC" ]; then
echo "setup: no skills/ directory next to this installer ($SRC)" >&2
exit 1
fi
# Discover every skill bundle under skills/ (any directory with a SKILL.md),
# so newly added skills are installed automatically without editing this list.
SKILLS=""
for skill_dir in "$SRC"/*/; do
[ -f "${skill_dir}SKILL.md" ] || continue
SKILLS="$SKILLS $(basename "$skill_dir")"
done
if [ -z "$SKILLS" ]; then
echo "setup: no skill bundles found under $SRC" >&2
exit 1
fi
print_logo() {
cat <<'LOGO'
██████╗ ██████╗ █████╗ ██╗███╗ ██╗ ███╗ ███╗██████╗
██╔══██╗██╔══██╗██╔══██╗██║████╗ ██║ ████╗ ████║██╔══██╗
██████╔╝██████╔╝███████║██║██╔██╗ ██║ ██╔████╔██║██║ ██║
██╔══██╗██╔══██╗██╔══██║██║██║╚██╗██║ ██║╚██╔╝██║██║ ██║
██████╔╝██║ ██║██║ ██║██║██║ ╚████║██╗██║ ╚═╝ ██║██████╔╝
╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝╚═╝╚═╝ ╚═╝╚═════╝
Open Project Brain Standard — install-first, agent-agnostic toolkit.
LOGO
}
# Ask a y/N question. Returns 0 for yes, 1 for no. Honours --yes; reads the
# answer from stdin (a terminal when run interactively, or piped input), and
# defaults to no when stdin is closed/empty.
ask() {
if [ "$ASSUME_YES" -eq 1 ]; then
return 0
fi
printf '%s [y/N] ' "$1"
read -r reply || reply=""
case "$reply" in
[yY]|[yY][eE][sS]) return 0 ;;
*) return 1 ;;
esac
}
print_logo
# Candidate agent runtimes: "<label>:<parent-config-dir>:<skills-dir>". A runtime
# counts as detected only when its parent config dir exists.
CANDIDATES="Claude:$HOME/.claude:$HOME/.claude/skills Codex:$HOME/.codex:$HOME/.codex/skills OpenCode:$HOME/.config/opencode:$HOME/.config/opencode/skills Cursor:$HOME/.cursor:$HOME/.cursor/skills Pi:$HOME/.pi/agent:$HOME/.pi/agent/skills"
DETECTED=""
echo "Detecting supported runtimes:"
for entry in $CANDIDATES; do
label=${entry%%:*}
rest=${entry#*:}
parent=${rest%%:*}
if [ -d "$parent" ]; then
echo " [found] $label ($parent)"
DETECTED="$DETECTED $entry"
else
echo " [missing] $label ($parent)"
fi
done
echo
if [ -z "$DETECTED" ]; then
echo "setup: no agent config directories detected (looked for ~/.claude, ~/.codex, ~/.config/opencode, ~/.cursor, ~/.pi/agent)." >&2
echo "setup: create one, or symlink skills/ manually, then re-run." >&2
exit 1
fi
# Manifest of links we create, so uninstall can clean up exactly what we installed.
STATE_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/brain.md"
MANIFEST="$STATE_DIR/installed-links"
mkdir -p "$STATE_DIR"
: > "$MANIFEST.tmp"
installed_any=0
for entry in $DETECTED; do
label=${entry%%:*}
rest=${entry#*:}
parent=${rest%%:*}
dest=${rest#*:}
if ! ask "Install brain.md skills into $label ($parent)?"; then
echo "setup: skipped $label."
continue
fi
mkdir -p "$dest"
for skill in $SKILLS; do
target="$dest/$skill"
source="$SRC/$skill"
if [ -L "$target" ]; then
rm -f "$target"
elif [ -e "$target" ]; then
# A real (non-symlink) directory is in the way — back it up once, don't destroy it.
backup="$target.pre-brain.bak"
if [ -e "$backup" ]; then
echo "setup: $target exists and $backup is taken; skipping (resolve manually)" >&2
continue
fi
mv "$target" "$backup"
echo "setup: moved existing $target -> $backup"
fi
ln -s "$source" "$target"
printf '%s\n' "$target" >> "$MANIFEST.tmp"
echo "setup: linked $target -> $source"
installed_any=1
done
done
# Merge with any previously recorded links (dedup), so the manifest stays complete.
if [ -f "$MANIFEST" ]; then
cat "$MANIFEST" >> "$MANIFEST.tmp"
fi
sort -u "$MANIFEST.tmp" > "$MANIFEST"
rm -f "$MANIFEST.tmp"
if [ "$installed_any" -eq 0 ]; then
echo "setup: nothing installed (no runtime confirmed)."
exit 0
fi
echo
echo "setup: done. Manifest: $MANIFEST"
echo "setup: run the brain-setup skill inside a project to scaffold its BRAIN.md + brain/."