axel-setup 0.2.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/CHANGELOG.md +218 -0
- package/CONTRIBUTING.md +58 -0
- package/LICENSE +21 -0
- package/README.md +518 -0
- package/agents/api-design.md +51 -0
- package/agents/bughunter.md +136 -0
- package/agents/changelog.md +89 -0
- package/agents/cleanup.md +126 -0
- package/agents/compare-branch.md +35 -0
- package/agents/cross-repo.md +97 -0
- package/agents/db-check.md +14 -0
- package/agents/debug.md +47 -0
- package/agents/deploy-check.md +100 -0
- package/agents/draft-message.md +19 -0
- package/agents/excelsior-coordinator.md +75 -0
- package/agents/excelsior-verifier.md +94 -0
- package/agents/feature.md +48 -0
- package/agents/harness-optimizer.md +40 -0
- package/agents/incident.md +48 -0
- package/agents/linear-task.md +18 -0
- package/agents/onboard.md +24 -0
- package/agents/perf.md +44 -0
- package/agents/production-validator.md +96 -0
- package/agents/review.md +113 -0
- package/agents/security-check.md +29 -0
- package/agents/sprint-summary.md +15 -0
- package/agents/tdd-mainder.md +178 -0
- package/agents/test-gen.md +39 -0
- package/axel-manifest.json +129 -0
- package/bin/axel-setup.js +597 -0
- package/bootstrap.sh +1087 -0
- package/commands/create-pr.md +13 -0
- package/commands/daily.md +182 -0
- package/commands/deslop.md +13 -0
- package/commands/draft-message.md +23 -0
- package/commands/eod-review.md +154 -0
- package/commands/execute-prp.md +37 -0
- package/commands/generate-prp.md +75 -0
- package/commands/multi-repo-feature.md +60 -0
- package/commands/roadmap.md +31 -0
- package/commands/sprint-status.md +486 -0
- package/commands/style.md +68 -0
- package/commands/visualize.md +17 -0
- package/docs/roadmap/multi-runtime.md +73 -0
- package/docs/superpowers/plans/2026-06-12-setup-hardening-roadmap.md +61 -0
- package/hooks/desktop-notify.sh +26 -0
- package/hooks/enforce-agent-model.jq +14 -0
- package/hooks/gsd-context-monitor.js +156 -0
- package/hooks/linear-lifecycle-sync.sh +112 -0
- package/hooks/memory-dedup.sh +122 -0
- package/hooks/memory-extractor.sh +218 -0
- package/hooks/post-commit-memory-trigger.sh +16 -0
- package/hooks/post-commit-verify.sh +41 -0
- package/hooks/post-edit-lint.sh +43 -0
- package/hooks/precompact-save-context.sh +124 -0
- package/hooks/priority-map-staleness.sh +29 -0
- package/hooks/proactive-resolver.sh +104 -0
- package/hooks/session-auto-title.sh +165 -0
- package/hooks/session-checkpoint.sh +97 -0
- package/hooks/session-cost-log.sh +77 -0
- package/hooks/session-log-action.sh +36 -0
- package/hooks/session-log-prompt.sh +25 -0
- package/hooks/session-restore.sh +45 -0
- package/hooks/session-save.sh +81 -0
- package/hooks/session-summarize.sh +154 -0
- package/hooks/validate-commit-format.sh +38 -0
- package/hooks/weekly-priority-map-review.sh +143 -0
- package/install.sh +46 -0
- package/package.json +67 -0
- package/scripts/ci/bootstrap-dry-run.sh +40 -0
- package/scripts/ci/check.sh +65 -0
- package/scripts/posthog-snapshot-loader.sh +112 -0
- package/skills/context-budget/SKILL.md +86 -0
- package/skills/memory-review/SKILL.md +100 -0
- package/skills/model-routing/SKILL.md +70 -0
- package/skills/posthog-weekly/SKILL.md +271 -0
- package/skills/ui-ux-pro-max/SKILL.md +377 -0
- package/skills/ui-ux-pro-max/data/charts.csv +26 -0
- package/skills/ui-ux-pro-max/data/colors.csv +97 -0
- package/skills/ui-ux-pro-max/data/icons.csv +101 -0
- package/skills/ui-ux-pro-max/data/landing.csv +31 -0
- package/skills/ui-ux-pro-max/data/products.csv +97 -0
- package/skills/ui-ux-pro-max/data/react-performance.csv +45 -0
- package/skills/ui-ux-pro-max/data/stacks/astro.csv +54 -0
- package/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
- package/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
- package/skills/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
- package/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
- package/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
- package/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
- package/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
- package/skills/ui-ux-pro-max/data/stacks/react.csv +54 -0
- package/skills/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
- package/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
- package/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
- package/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -0
- package/skills/ui-ux-pro-max/data/styles.csv +68 -0
- package/skills/ui-ux-pro-max/data/typography.csv +58 -0
- package/skills/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
- package/skills/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
- package/skills/ui-ux-pro-max/data/web-interface.csv +31 -0
- package/skills/ui-ux-pro-max/scripts/core.py +253 -0
- package/skills/ui-ux-pro-max/scripts/design_system.py +1067 -0
- package/skills/ui-ux-pro-max/scripts/search.py +114 -0
- package/templates/AGENTS.runtime.md +17 -0
- package/templates/CLAUDE.md +252 -0
- package/templates/claude-monitor.plist +35 -0
- package/templates/keybindings.json +13 -0
- package/templates/merge-settings.jq +53 -0
- package/templates/review-upgrades.md +44 -0
- package/templates/settings.json +255 -0
- package/templates/statusline-command.sh +182 -0
- package/tests/fixtures/hooks/events.json +32 -0
- package/tools/session-costs-view.sh +128 -0
- package/tools/session-dashboard-gen.sh +369 -0
- package/tools/session-live.sh +173 -0
- package/tools/session-server.js +441 -0
package/bootstrap.sh
ADDED
|
@@ -0,0 +1,1087 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# ============================================================================
|
|
3
|
+
# AXEL Onboarding Bootstrap — Claude Code Team Configuration
|
|
4
|
+
# Autonomous eXcelsior Engineering Layer
|
|
5
|
+
#
|
|
6
|
+
# ADDITIVE MODE: This script ONLY adds new things. It never overwrites
|
|
7
|
+
# existing files, hooks, memory, settings, or CLAUDE.md. Your personal
|
|
8
|
+
# configuration and memory are preserved completely.
|
|
9
|
+
#
|
|
10
|
+
# Usage: bash bootstrap.sh [--user-name "Tu Nombre"] [--dry-run]
|
|
11
|
+
#
|
|
12
|
+
# What this does:
|
|
13
|
+
# 1. Backs up your existing ~/.claude/ config (safety net)
|
|
14
|
+
# 2. ADDS hooks that don't already exist (never overwrites)
|
|
15
|
+
# 3. ADDS commands/skills/agents that don't already exist
|
|
16
|
+
# 4. Installs plugins you don't have yet (skips already-installed)
|
|
17
|
+
# 5. MERGES new hook wiring + features into your existing settings.json
|
|
18
|
+
# 6. Sets up memory directory structure (preserves all existing memory)
|
|
19
|
+
# 7. Offers a team CLAUDE.md only if you don't have one
|
|
20
|
+
#
|
|
21
|
+
# Note: GSD (get-shit-done) is NOT vendored by AXEL. Install/update it via its
|
|
22
|
+
# own installer (npx get-shit-done-cc); AXEL consumes the live GSD skills.
|
|
23
|
+
#
|
|
24
|
+
# Prerequisites:
|
|
25
|
+
# - Claude Code CLI installed (claude --version)
|
|
26
|
+
# - Node.js >= 18 (for hook scripts)
|
|
27
|
+
# - jq (for JSON processing in hooks and settings merge)
|
|
28
|
+
# - python3 (for some hook scripts)
|
|
29
|
+
# ============================================================================
|
|
30
|
+
|
|
31
|
+
set -euo pipefail
|
|
32
|
+
|
|
33
|
+
# --- Configuration ---
|
|
34
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
35
|
+
CLAUDE_DIR="$HOME/.claude"
|
|
36
|
+
CODEX_DIR="${CODEX_HOME:-$HOME/.codex}"
|
|
37
|
+
BACKUP_DIR="$CLAUDE_DIR/backups/pre-axel-$(date +%Y%m%d_%H%M%S)"
|
|
38
|
+
DRY_RUN=false
|
|
39
|
+
TARGET="claude"
|
|
40
|
+
OUTPUT_DIR=""
|
|
41
|
+
USER_NAME=""
|
|
42
|
+
USER_CONTEXT=""
|
|
43
|
+
ASSISTANT_LANGUAGE=""
|
|
44
|
+
ENABLE_POSTHOG=false
|
|
45
|
+
POSTHOG_PROJECT_CONTEXT=""
|
|
46
|
+
PROFILE="core"
|
|
47
|
+
SKIP_PLUGINS=false
|
|
48
|
+
SKIP_MONITOR=false
|
|
49
|
+
SKIP_KEYBINDINGS=false
|
|
50
|
+
SKIP_CLAUDE_MD=false
|
|
51
|
+
SKIP_GSD=false
|
|
52
|
+
NO_LAUNCHD=false
|
|
53
|
+
|
|
54
|
+
# Counters
|
|
55
|
+
HOOKS_ADDED=0
|
|
56
|
+
HOOKS_UPGRADED=0
|
|
57
|
+
CMDS_ADDED=0
|
|
58
|
+
CMDS_UPGRADED=0
|
|
59
|
+
AGENTS_ADDED=0
|
|
60
|
+
AGENTS_UPGRADED=0
|
|
61
|
+
SKILLS_ADDED=0
|
|
62
|
+
SKILLS_SKIPPED=0
|
|
63
|
+
SCRIPTS_ADDED=0
|
|
64
|
+
SCRIPTS_SKIPPED=0
|
|
65
|
+
MONITOR_SKIPPED=0
|
|
66
|
+
GSD_SKIPPED=0
|
|
67
|
+
KEYBINDINGS_SKIPPED=0
|
|
68
|
+
CLAUDE_MD_SKIPPED=0
|
|
69
|
+
UPGRADES_DIR="$CLAUDE_DIR/axel-upgrades"
|
|
70
|
+
|
|
71
|
+
# Colors
|
|
72
|
+
RED='\033[0;31m'
|
|
73
|
+
GREEN='\033[0;32m'
|
|
74
|
+
YELLOW='\033[0;33m'
|
|
75
|
+
BLUE='\033[0;34m'
|
|
76
|
+
BOLD='\033[1m'
|
|
77
|
+
DIM='\033[2m'
|
|
78
|
+
RESET='\033[0m'
|
|
79
|
+
|
|
80
|
+
log() { printf "${GREEN}[AXEL]${RESET} %s\n" "$1"; }
|
|
81
|
+
warn() { printf "${YELLOW}[WARN]${RESET} %s\n" "$1"; }
|
|
82
|
+
error() { printf "${RED}[ERROR]${RESET} %s\n" "$1" >&2; }
|
|
83
|
+
info() { printf "${BLUE}[INFO]${RESET} %s\n" "$1"; }
|
|
84
|
+
skip() { printf "${DIM} skip: %s (already up to date)${RESET}\n" "$1"; }
|
|
85
|
+
upgrade() { printf "${YELLOW} upgrade: %s (saved for review)${RESET}\n" "$1"; }
|
|
86
|
+
|
|
87
|
+
# --- Parse arguments ---
|
|
88
|
+
while [[ $# -gt 0 ]]; do
|
|
89
|
+
case $1 in
|
|
90
|
+
--user-name) USER_NAME="$2"; shift 2 ;;
|
|
91
|
+
--user-context) USER_CONTEXT="$2"; shift 2 ;;
|
|
92
|
+
--language) ASSISTANT_LANGUAGE="$2"; shift 2 ;;
|
|
93
|
+
--enable-posthog) ENABLE_POSTHOG=true; shift ;;
|
|
94
|
+
--posthog-context) POSTHOG_PROJECT_CONTEXT="$2"; shift 2 ;;
|
|
95
|
+
--profile) PROFILE="$2"; shift 2 ;;
|
|
96
|
+
--target) TARGET="$2"; shift 2 ;;
|
|
97
|
+
--output) OUTPUT_DIR="$2"; shift 2 ;;
|
|
98
|
+
--skip-plugins) SKIP_PLUGINS=true; shift ;;
|
|
99
|
+
--skip-monitor) SKIP_MONITOR=true; shift ;;
|
|
100
|
+
--skip-keybindings) SKIP_KEYBINDINGS=true; shift ;;
|
|
101
|
+
--skip-claude-md) SKIP_CLAUDE_MD=true; shift ;;
|
|
102
|
+
--skip-gsd) SKIP_GSD=true; shift ;;
|
|
103
|
+
--no-launchd) NO_LAUNCHD=true; shift ;;
|
|
104
|
+
--dry-run) DRY_RUN=true; shift ;;
|
|
105
|
+
-h|--help)
|
|
106
|
+
echo "Usage: bash bootstrap.sh [options]"
|
|
107
|
+
echo ""
|
|
108
|
+
echo "This script is ADDITIVE — it only adds new things, never overwrites."
|
|
109
|
+
echo "Your existing memory, settings, hooks, and CLAUDE.md are preserved."
|
|
110
|
+
echo ""
|
|
111
|
+
echo "Options:"
|
|
112
|
+
echo " --user-name NAME Your name (used in session summaries)"
|
|
113
|
+
echo " --user-context TEXT Short self-description used in hook prompts,"
|
|
114
|
+
echo " e.g. 'Tech Lead at Acme, backend-focused'"
|
|
115
|
+
echo " --language LANG Language the assistant should respond in inside"
|
|
116
|
+
echo " hook-generated prompts (e.g. 'spanish', 'english')"
|
|
117
|
+
echo " --enable-posthog Install the /posthog-weekly skill and the"
|
|
118
|
+
echo " PostHog snapshot loader. Off by default — only"
|
|
119
|
+
echo " enable if your team uses the PostHog MCP."
|
|
120
|
+
echo " --posthog-context TEXT Required with --enable-posthog. Short product"
|
|
121
|
+
echo " description used in the analytical prompt,"
|
|
122
|
+
echo " e.g. 'Acme ATS — recruiting platform with AI"
|
|
123
|
+
echo " sourcing'. Helps the agent frame findings."
|
|
124
|
+
echo " --profile NAME Install profile: core, personal, team-safe,"
|
|
125
|
+
echo " minimal, ci, or full. Defaults to core."
|
|
126
|
+
echo " --target NAME Runtime target: claude, codex, or generic."
|
|
127
|
+
echo " Defaults to claude."
|
|
128
|
+
echo " --output DIR Export directory for --target generic"
|
|
129
|
+
echo " --skip-plugins Do not install Claude marketplace plugins"
|
|
130
|
+
echo " --skip-monitor Do not install usage monitor tools"
|
|
131
|
+
echo " --skip-keybindings Do not install keybindings.json"
|
|
132
|
+
echo " --skip-claude-md Do not create ~/CLAUDE.md"
|
|
133
|
+
echo " --skip-gsd Do not run the external GSD installer"
|
|
134
|
+
echo " --no-launchd Do not install or load the macOS launchd agent"
|
|
135
|
+
echo " --dry-run Show what would be done without doing it"
|
|
136
|
+
exit 0
|
|
137
|
+
;;
|
|
138
|
+
*) error "Unknown option: $1"; exit 1 ;;
|
|
139
|
+
esac
|
|
140
|
+
done
|
|
141
|
+
|
|
142
|
+
case "$PROFILE" in
|
|
143
|
+
default) PROFILE="core" ;;
|
|
144
|
+
core|personal|team-safe|minimal|ci|full) ;;
|
|
145
|
+
*) error "Unknown profile: $PROFILE"; exit 1 ;;
|
|
146
|
+
esac
|
|
147
|
+
|
|
148
|
+
case "$TARGET" in
|
|
149
|
+
default) TARGET="claude" ;;
|
|
150
|
+
claude|codex|generic) ;;
|
|
151
|
+
*) error "Unknown target: $TARGET"; exit 1 ;;
|
|
152
|
+
esac
|
|
153
|
+
|
|
154
|
+
if [ "$TARGET" = "generic" ] && [ -z "$OUTPUT_DIR" ]; then
|
|
155
|
+
error "--output is required when using --target generic"
|
|
156
|
+
exit 1
|
|
157
|
+
fi
|
|
158
|
+
|
|
159
|
+
case "$PROFILE" in
|
|
160
|
+
core)
|
|
161
|
+
SKIP_PLUGINS=true
|
|
162
|
+
SKIP_MONITOR=true
|
|
163
|
+
SKIP_KEYBINDINGS=true
|
|
164
|
+
SKIP_GSD=true
|
|
165
|
+
NO_LAUNCHD=true
|
|
166
|
+
;;
|
|
167
|
+
minimal)
|
|
168
|
+
SKIP_PLUGINS=true
|
|
169
|
+
SKIP_MONITOR=true
|
|
170
|
+
SKIP_KEYBINDINGS=true
|
|
171
|
+
;;
|
|
172
|
+
ci)
|
|
173
|
+
SKIP_PLUGINS=true
|
|
174
|
+
SKIP_MONITOR=true
|
|
175
|
+
SKIP_KEYBINDINGS=true
|
|
176
|
+
SKIP_CLAUDE_MD=true
|
|
177
|
+
SKIP_GSD=true
|
|
178
|
+
NO_LAUNCHD=true
|
|
179
|
+
;;
|
|
180
|
+
esac
|
|
181
|
+
|
|
182
|
+
# --- Prerequisites check ---
|
|
183
|
+
log "Checking prerequisites..."
|
|
184
|
+
|
|
185
|
+
check_cmd() {
|
|
186
|
+
if ! command -v "$1" &>/dev/null; then
|
|
187
|
+
error "$1 is required but not installed."
|
|
188
|
+
return 1
|
|
189
|
+
fi
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
MISSING=0
|
|
193
|
+
if [ "$TARGET" = "claude" ]; then
|
|
194
|
+
check_cmd "claude" || MISSING=1
|
|
195
|
+
fi
|
|
196
|
+
check_cmd "node" || MISSING=1
|
|
197
|
+
check_cmd "jq" || MISSING=1
|
|
198
|
+
check_cmd "python3" || MISSING=1
|
|
199
|
+
|
|
200
|
+
if [ "$MISSING" -eq 1 ]; then
|
|
201
|
+
error "Install missing prerequisites and try again."
|
|
202
|
+
exit 1
|
|
203
|
+
fi
|
|
204
|
+
|
|
205
|
+
NODE_VER=$(node --version | sed 's/v//' | cut -d. -f1)
|
|
206
|
+
if [ "$NODE_VER" -lt 18 ]; then
|
|
207
|
+
error "Node.js >= 18 required (found v$NODE_VER)"
|
|
208
|
+
exit 1
|
|
209
|
+
fi
|
|
210
|
+
|
|
211
|
+
log "All prerequisites OK"
|
|
212
|
+
|
|
213
|
+
# --- Prompt for user name if not provided ---
|
|
214
|
+
if [ -z "$USER_NAME" ]; then
|
|
215
|
+
printf "${BOLD}Enter your name (for session summaries): ${RESET}"
|
|
216
|
+
read -r USER_NAME
|
|
217
|
+
if [ -z "$USER_NAME" ]; then
|
|
218
|
+
USER_NAME=$(whoami)
|
|
219
|
+
warn "Using system username: $USER_NAME"
|
|
220
|
+
fi
|
|
221
|
+
fi
|
|
222
|
+
|
|
223
|
+
# --- Defaults for user context and language (never prompt, just fall back) ---
|
|
224
|
+
if [ -z "$USER_CONTEXT" ]; then
|
|
225
|
+
USER_CONTEXT="a software engineer"
|
|
226
|
+
fi
|
|
227
|
+
if [ -z "$ASSISTANT_LANGUAGE" ]; then
|
|
228
|
+
ASSISTANT_LANGUAGE="english"
|
|
229
|
+
fi
|
|
230
|
+
info "Hook prompts will address you as: $USER_CONTEXT (responses in $ASSISTANT_LANGUAGE)"
|
|
231
|
+
|
|
232
|
+
# --- PostHog gating: only install the skill if --enable-posthog AND a context ---
|
|
233
|
+
if $ENABLE_POSTHOG && [ -z "$POSTHOG_PROJECT_CONTEXT" ]; then
|
|
234
|
+
POSTHOG_PROJECT_CONTEXT="a SaaS product (no detailed context provided — pass --posthog-context to refine)"
|
|
235
|
+
warn "--enable-posthog is set but --posthog-context is empty. Using a generic placeholder."
|
|
236
|
+
fi
|
|
237
|
+
if $ENABLE_POSTHOG; then
|
|
238
|
+
info "PostHog integration: ENABLED. Will install /posthog-weekly skill + snapshot loader."
|
|
239
|
+
info " Project context: $POSTHOG_PROJECT_CONTEXT"
|
|
240
|
+
fi
|
|
241
|
+
info "Install target: $TARGET"
|
|
242
|
+
|
|
243
|
+
# --- Dry run guard ---
|
|
244
|
+
run() {
|
|
245
|
+
if $DRY_RUN; then
|
|
246
|
+
info "[DRY RUN] $*"
|
|
247
|
+
else
|
|
248
|
+
"$@"
|
|
249
|
+
fi
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
settings_for_profile() {
|
|
253
|
+
local src="$1"
|
|
254
|
+
local dest="$2"
|
|
255
|
+
|
|
256
|
+
if [ "$PROFILE" = "personal" ] || [ "$PROFILE" = "full" ]; then
|
|
257
|
+
cp "$src" "$dest"
|
|
258
|
+
return
|
|
259
|
+
fi
|
|
260
|
+
|
|
261
|
+
jq '
|
|
262
|
+
.permissions.defaultMode = "acceptEdits" |
|
|
263
|
+
.permissions.allow = ((.permissions.allow // []) | map(select(. != "Bash(*)"))) |
|
|
264
|
+
.skipDangerousModePermissionPrompt = false
|
|
265
|
+
' "$src" > "$dest"
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
write_processed_skill() {
|
|
269
|
+
local src="$1"
|
|
270
|
+
local dest="$2"
|
|
271
|
+
|
|
272
|
+
sed \
|
|
273
|
+
-e "s|{{POSTHOG_PROJECT_CONTEXT}}|$POSTHOG_PROJECT_CONTEXT|g" \
|
|
274
|
+
-e "s|{{ASSISTANT_LANGUAGE}}|$ASSISTANT_LANGUAGE|g" \
|
|
275
|
+
-e "s|{{USER_NAME}}|$USER_NAME|g" \
|
|
276
|
+
-e "s|{{USER_CONTEXT}}|$USER_CONTEXT|g" \
|
|
277
|
+
"$src" > "$dest"
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
copy_skill_file() {
|
|
281
|
+
local src="$1"
|
|
282
|
+
local dest="$2"
|
|
283
|
+
local rel="$3"
|
|
284
|
+
|
|
285
|
+
if $DRY_RUN; then
|
|
286
|
+
info "[DRY RUN] Would add skill asset: $rel"
|
|
287
|
+
return
|
|
288
|
+
fi
|
|
289
|
+
|
|
290
|
+
mkdir -p "$(dirname "$dest")"
|
|
291
|
+
if [ "$(basename "$src")" = "SKILL.md" ]; then
|
|
292
|
+
write_processed_skill "$src" "$dest"
|
|
293
|
+
else
|
|
294
|
+
cp -p "$src" "$dest"
|
|
295
|
+
fi
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
propose_skill_upgrade() {
|
|
299
|
+
local src="$1"
|
|
300
|
+
local dest="$2"
|
|
301
|
+
local rel="$3"
|
|
302
|
+
local skill_name="$4"
|
|
303
|
+
local proposed
|
|
304
|
+
|
|
305
|
+
proposed=$(mktemp)
|
|
306
|
+
if [ "$(basename "$src")" = "SKILL.md" ]; then
|
|
307
|
+
write_processed_skill "$src" "$proposed"
|
|
308
|
+
else
|
|
309
|
+
cp "$src" "$proposed"
|
|
310
|
+
fi
|
|
311
|
+
|
|
312
|
+
if [ ! -f "$dest" ] || ! diff -q "$proposed" "$dest" >/dev/null 2>&1; then
|
|
313
|
+
if ! $DRY_RUN; then
|
|
314
|
+
mkdir -p "$UPGRADES_DIR/skills/$skill_name/$(dirname "$rel")"
|
|
315
|
+
cp "$proposed" "$UPGRADES_DIR/skills/$skill_name/$rel"
|
|
316
|
+
else
|
|
317
|
+
info "[DRY RUN] Would propose skill asset upgrade: $skill_name/$rel"
|
|
318
|
+
fi
|
|
319
|
+
upgrade "skill: $skill_name/$rel"
|
|
320
|
+
SKILLS_UPGRADED=$((SKILLS_UPGRADED + 1))
|
|
321
|
+
fi
|
|
322
|
+
|
|
323
|
+
rm -f "$proposed"
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
# Helper: copy file; if destination exists AND differs, save AXEL version for review
|
|
327
|
+
add_or_upgrade() {
|
|
328
|
+
local src="$1"
|
|
329
|
+
local dest="$2"
|
|
330
|
+
local label="$3"
|
|
331
|
+
local added_var="$4"
|
|
332
|
+
local upgraded_var="$5"
|
|
333
|
+
local upgrade_subdir="$6" # e.g., "hooks", "commands", "agents"
|
|
334
|
+
|
|
335
|
+
if [ -f "$dest" ]; then
|
|
336
|
+
# Check if files differ (content-based, ignoring whitespace)
|
|
337
|
+
if ! diff -q "$src" "$dest" >/dev/null 2>&1; then
|
|
338
|
+
# Different content — save AXEL version as upgrade proposal
|
|
339
|
+
if $DRY_RUN; then
|
|
340
|
+
info "[DRY RUN] Would propose upgrade: $label"
|
|
341
|
+
else
|
|
342
|
+
mkdir -p "$UPGRADES_DIR/$upgrade_subdir"
|
|
343
|
+
cp "$src" "$UPGRADES_DIR/$upgrade_subdir/$(basename "$dest")"
|
|
344
|
+
fi
|
|
345
|
+
upgrade "$label"
|
|
346
|
+
eval "$upgraded_var=\$((\$$upgraded_var + 1))"
|
|
347
|
+
fi
|
|
348
|
+
# Same content — nothing to do
|
|
349
|
+
else
|
|
350
|
+
if $DRY_RUN; then
|
|
351
|
+
info "[DRY RUN] Would add: $label"
|
|
352
|
+
else
|
|
353
|
+
cp "$src" "$dest"
|
|
354
|
+
fi
|
|
355
|
+
eval "$added_var=\$((\$$added_var + 1))"
|
|
356
|
+
fi
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
runtime_root_for_target() {
|
|
360
|
+
case "$TARGET" in
|
|
361
|
+
codex) printf "%s" "$CODEX_DIR" ;;
|
|
362
|
+
generic) printf "%s" "$OUTPUT_DIR" ;;
|
|
363
|
+
*) printf "%s" "$CLAUDE_DIR" ;;
|
|
364
|
+
esac
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
copy_runtime_asset() {
|
|
368
|
+
local src="$1"
|
|
369
|
+
local dest="$2"
|
|
370
|
+
local label="$3"
|
|
371
|
+
local category="$4"
|
|
372
|
+
local upgrades_dir="$5"
|
|
373
|
+
local proposed=""
|
|
374
|
+
local compare_src="$src"
|
|
375
|
+
|
|
376
|
+
if [ "$(basename "$src")" = "SKILL.md" ]; then
|
|
377
|
+
proposed=$(mktemp)
|
|
378
|
+
write_processed_skill "$src" "$proposed"
|
|
379
|
+
compare_src="$proposed"
|
|
380
|
+
fi
|
|
381
|
+
|
|
382
|
+
if [ -f "$dest" ]; then
|
|
383
|
+
if ! diff -q "$compare_src" "$dest" >/dev/null 2>&1; then
|
|
384
|
+
if $DRY_RUN; then
|
|
385
|
+
info "[DRY RUN] Would propose upgrade: $label"
|
|
386
|
+
else
|
|
387
|
+
mkdir -p "$upgrades_dir/$category/$(dirname "$label")"
|
|
388
|
+
cp "$compare_src" "$upgrades_dir/$category/$label"
|
|
389
|
+
fi
|
|
390
|
+
upgrade "$label"
|
|
391
|
+
RUNTIME_UPGRADED=$((RUNTIME_UPGRADED + 1))
|
|
392
|
+
fi
|
|
393
|
+
else
|
|
394
|
+
if $DRY_RUN; then
|
|
395
|
+
info "[DRY RUN] Would add: $label"
|
|
396
|
+
else
|
|
397
|
+
mkdir -p "$(dirname "$dest")"
|
|
398
|
+
cp "$compare_src" "$dest"
|
|
399
|
+
fi
|
|
400
|
+
RUNTIME_ADDED=$((RUNTIME_ADDED + 1))
|
|
401
|
+
fi
|
|
402
|
+
|
|
403
|
+
if [ -n "$proposed" ]; then
|
|
404
|
+
rm -f "$proposed"
|
|
405
|
+
fi
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
write_manifest() {
|
|
409
|
+
local dest_dir="$1"
|
|
410
|
+
|
|
411
|
+
if $DRY_RUN; then
|
|
412
|
+
info "[DRY RUN] Would install axel-manifest.json with target: $TARGET, profile: $PROFILE"
|
|
413
|
+
return
|
|
414
|
+
fi
|
|
415
|
+
|
|
416
|
+
jq \
|
|
417
|
+
--arg profile "$PROFILE" \
|
|
418
|
+
--arg target "$TARGET" \
|
|
419
|
+
--arg installedRoot "$dest_dir" \
|
|
420
|
+
--argjson skipPlugins "$SKIP_PLUGINS" \
|
|
421
|
+
--argjson skipMonitor "$SKIP_MONITOR" \
|
|
422
|
+
--argjson skipKeybindings "$SKIP_KEYBINDINGS" \
|
|
423
|
+
--argjson skipClaudeMd "$SKIP_CLAUDE_MD" \
|
|
424
|
+
--argjson skipGsd "$SKIP_GSD" \
|
|
425
|
+
--argjson noLaunchd "$NO_LAUNCHD" \
|
|
426
|
+
--argjson enablePosthog "$ENABLE_POSTHOG" \
|
|
427
|
+
'. + {
|
|
428
|
+
profile: $profile,
|
|
429
|
+
target: $target,
|
|
430
|
+
installedRoot: $installedRoot,
|
|
431
|
+
enabled: {
|
|
432
|
+
"enable-posthog": $enablePosthog
|
|
433
|
+
},
|
|
434
|
+
skipped: {
|
|
435
|
+
"skip-plugins": $skipPlugins,
|
|
436
|
+
"skip-monitor": $skipMonitor,
|
|
437
|
+
"skip-keybindings": $skipKeybindings,
|
|
438
|
+
"skip-claude-md": $skipClaudeMd,
|
|
439
|
+
"skip-gsd": $skipGsd,
|
|
440
|
+
"no-launchd": $noLaunchd
|
|
441
|
+
}
|
|
442
|
+
}' \
|
|
443
|
+
"$SCRIPT_DIR/axel-manifest.json" > "$dest_dir/axel-manifest.json"
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
current_upgrade_path() {
|
|
447
|
+
local root_label="$1"
|
|
448
|
+
local category="$2"
|
|
449
|
+
local rel="$3"
|
|
450
|
+
|
|
451
|
+
case "$category" in
|
|
452
|
+
instructions) printf "%s/%s" "$root_label" "$rel" ;;
|
|
453
|
+
*) printf "%s/%s/%s" "$root_label" "$category" "$rel" ;;
|
|
454
|
+
esac
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
write_upgrade_review() {
|
|
458
|
+
local upgrades_dir="$1"
|
|
459
|
+
local root_label="$2"
|
|
460
|
+
local target_name="$3"
|
|
461
|
+
local category
|
|
462
|
+
local current_path
|
|
463
|
+
local rel
|
|
464
|
+
|
|
465
|
+
log "Generating upgrade review prompt..."
|
|
466
|
+
mkdir -p "$upgrades_dir"
|
|
467
|
+
cp "$SCRIPT_DIR/templates/review-upgrades.md" "$upgrades_dir/REVIEW.md"
|
|
468
|
+
|
|
469
|
+
cat > "$upgrades_dir/MANIFEST.md" << MANIFEST_EOF
|
|
470
|
+
# AXEL Upgrade Manifest
|
|
471
|
+
|
|
472
|
+
Generated: $(date +%Y-%m-%d\ %H:%M)
|
|
473
|
+
Target: $target_name
|
|
474
|
+
|
|
475
|
+
## Files to review
|
|
476
|
+
|
|
477
|
+
These files already existed on your system but the AXEL package has improved versions.
|
|
478
|
+
Your agent should compare and merge the best parts of each file before anything is applied.
|
|
479
|
+
|
|
480
|
+
MANIFEST_EOF
|
|
481
|
+
|
|
482
|
+
for category in hooks commands agents skills scripts instructions tools templates; do
|
|
483
|
+
if [ -d "$upgrades_dir/$category" ]; then
|
|
484
|
+
echo "### $category" >> "$upgrades_dir/MANIFEST.md"
|
|
485
|
+
while IFS= read -r f; do
|
|
486
|
+
rel="${f#"$upgrades_dir/$category/"}"
|
|
487
|
+
current_path=$(current_upgrade_path "$root_label" "$category" "$rel")
|
|
488
|
+
echo "- \`$rel\`: upgrade at \`$upgrades_dir/$category/$rel\`, current at \`$current_path\`" >> "$upgrades_dir/MANIFEST.md"
|
|
489
|
+
done < <(find "$upgrades_dir/$category" -type f | sort)
|
|
490
|
+
echo "" >> "$upgrades_dir/MANIFEST.md"
|
|
491
|
+
fi
|
|
492
|
+
done
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
install_portable_target() {
|
|
496
|
+
local runtime_root
|
|
497
|
+
local upgrades_dir
|
|
498
|
+
|
|
499
|
+
runtime_root=$(runtime_root_for_target)
|
|
500
|
+
upgrades_dir="$runtime_root/axel-upgrades"
|
|
501
|
+
RUNTIME_ADDED=0
|
|
502
|
+
RUNTIME_UPGRADED=0
|
|
503
|
+
|
|
504
|
+
log "Installing AXEL portable runtime assets..."
|
|
505
|
+
info "Runtime root: $runtime_root"
|
|
506
|
+
info "Claude-only hooks, settings, plugins, keybindings, launchd, and GSD installers are skipped for target: $TARGET"
|
|
507
|
+
|
|
508
|
+
for dir in skills agents commands scripts; do
|
|
509
|
+
run mkdir -p "$runtime_root/$dir"
|
|
510
|
+
done
|
|
511
|
+
|
|
512
|
+
copy_runtime_asset \
|
|
513
|
+
"$SCRIPT_DIR/templates/AGENTS.runtime.md" \
|
|
514
|
+
"$runtime_root/AGENTS.md" \
|
|
515
|
+
"AGENTS.md" \
|
|
516
|
+
"instructions" \
|
|
517
|
+
"$upgrades_dir"
|
|
518
|
+
|
|
519
|
+
if [ -d "$SCRIPT_DIR/skills" ]; then
|
|
520
|
+
for skill_dir in "$SCRIPT_DIR/skills/"*/; do
|
|
521
|
+
[ -d "$skill_dir" ] || continue
|
|
522
|
+
SKILL_NAME=$(basename "$skill_dir")
|
|
523
|
+
if [ "$SKILL_NAME" = "posthog-weekly" ] && ! $ENABLE_POSTHOG; then
|
|
524
|
+
info " skip: posthog-weekly (use --enable-posthog to install)"
|
|
525
|
+
continue
|
|
526
|
+
fi
|
|
527
|
+
|
|
528
|
+
while IFS= read -r -d '' skill_file; do
|
|
529
|
+
rel="${skill_file#"$skill_dir"}"
|
|
530
|
+
copy_runtime_asset \
|
|
531
|
+
"$skill_file" \
|
|
532
|
+
"$runtime_root/skills/$SKILL_NAME/$rel" \
|
|
533
|
+
"skills/$SKILL_NAME/$rel" \
|
|
534
|
+
"skills" \
|
|
535
|
+
"$upgrades_dir"
|
|
536
|
+
done < <(find "$skill_dir" -type f ! -path '*/__pycache__/*' ! -name '*.pyc' -print0)
|
|
537
|
+
done
|
|
538
|
+
fi
|
|
539
|
+
|
|
540
|
+
for agent_file in "$SCRIPT_DIR/agents/"*.md; do
|
|
541
|
+
[ -f "$agent_file" ] || continue
|
|
542
|
+
copy_runtime_asset \
|
|
543
|
+
"$agent_file" \
|
|
544
|
+
"$runtime_root/agents/$(basename "$agent_file")" \
|
|
545
|
+
"agents/$(basename "$agent_file")" \
|
|
546
|
+
"agents" \
|
|
547
|
+
"$upgrades_dir"
|
|
548
|
+
done
|
|
549
|
+
|
|
550
|
+
for cmd_file in "$SCRIPT_DIR/commands/"*.md; do
|
|
551
|
+
[ -f "$cmd_file" ] || continue
|
|
552
|
+
copy_runtime_asset \
|
|
553
|
+
"$cmd_file" \
|
|
554
|
+
"$runtime_root/commands/$(basename "$cmd_file")" \
|
|
555
|
+
"commands/$(basename "$cmd_file")" \
|
|
556
|
+
"commands" \
|
|
557
|
+
"$upgrades_dir"
|
|
558
|
+
done
|
|
559
|
+
|
|
560
|
+
if [ -d "$SCRIPT_DIR/scripts" ]; then
|
|
561
|
+
for script_file in "$SCRIPT_DIR/scripts/"*.sh; do
|
|
562
|
+
[ -f "$script_file" ] || continue
|
|
563
|
+
BASE_SCRIPT=$(basename "$script_file")
|
|
564
|
+
if [ "$BASE_SCRIPT" = "posthog-snapshot-loader.sh" ] && ! $ENABLE_POSTHOG; then
|
|
565
|
+
info " skip: $BASE_SCRIPT (use --enable-posthog to install)"
|
|
566
|
+
continue
|
|
567
|
+
fi
|
|
568
|
+
copy_runtime_asset \
|
|
569
|
+
"$script_file" \
|
|
570
|
+
"$runtime_root/scripts/$BASE_SCRIPT" \
|
|
571
|
+
"scripts/$BASE_SCRIPT" \
|
|
572
|
+
"scripts" \
|
|
573
|
+
"$upgrades_dir"
|
|
574
|
+
if ! $DRY_RUN; then
|
|
575
|
+
chmod +x "$runtime_root/scripts/$BASE_SCRIPT"
|
|
576
|
+
fi
|
|
577
|
+
done
|
|
578
|
+
fi
|
|
579
|
+
|
|
580
|
+
write_manifest "$runtime_root"
|
|
581
|
+
|
|
582
|
+
if [ "$RUNTIME_UPGRADED" -gt 0 ] && ! $DRY_RUN; then
|
|
583
|
+
write_upgrade_review "$upgrades_dir" "$runtime_root" "$TARGET"
|
|
584
|
+
fi
|
|
585
|
+
|
|
586
|
+
echo ""
|
|
587
|
+
printf "${GREEN}${BOLD}============================================${RESET}\n"
|
|
588
|
+
printf "${GREEN}${BOLD} AXEL Portable Runtime Complete!${RESET}\n"
|
|
589
|
+
printf "${GREEN}${BOLD}============================================${RESET}\n"
|
|
590
|
+
echo ""
|
|
591
|
+
info "Target: $TARGET"
|
|
592
|
+
info "Profile: $PROFILE"
|
|
593
|
+
info "Runtime root: $runtime_root"
|
|
594
|
+
info "Files added: $RUNTIME_ADDED"
|
|
595
|
+
info "Upgrades available: $RUNTIME_UPGRADED"
|
|
596
|
+
info "Claude Code remains the default target. This target installs portable AXEL assets only."
|
|
597
|
+
echo ""
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
if [ "$TARGET" != "claude" ]; then
|
|
601
|
+
install_portable_target
|
|
602
|
+
exit 0
|
|
603
|
+
fi
|
|
604
|
+
|
|
605
|
+
# --- Backup existing config (safety net, always) ---
|
|
606
|
+
if [ -d "$CLAUDE_DIR" ] && [ -f "$CLAUDE_DIR/settings.json" ]; then
|
|
607
|
+
log "Creating safety backup at $BACKUP_DIR"
|
|
608
|
+
run mkdir -p "$BACKUP_DIR"
|
|
609
|
+
for item in settings.json settings.local.json keybindings.json; do
|
|
610
|
+
[ -f "$CLAUDE_DIR/$item" ] && run cp "$CLAUDE_DIR/$item" "$BACKUP_DIR/$item"
|
|
611
|
+
done
|
|
612
|
+
[ -d "$CLAUDE_DIR/hooks" ] && run cp -r "$CLAUDE_DIR/hooks" "$BACKUP_DIR/hooks"
|
|
613
|
+
fi
|
|
614
|
+
|
|
615
|
+
# --- Create directory structure (mkdir -p is already additive) ---
|
|
616
|
+
log "Ensuring directory structure..."
|
|
617
|
+
for dir in hooks commands agents skills memory memory/decisions sessions sessions/checkpoints logs; do
|
|
618
|
+
run mkdir -p "$CLAUDE_DIR/$dir"
|
|
619
|
+
done
|
|
620
|
+
|
|
621
|
+
# ============================================================================
|
|
622
|
+
# 1. HOOKS — Only add new ones, never overwrite existing
|
|
623
|
+
# ============================================================================
|
|
624
|
+
log "Adding hooks..."
|
|
625
|
+
|
|
626
|
+
for hook_file in "$SCRIPT_DIR/hooks/"*; do
|
|
627
|
+
[ -f "$hook_file" ] || continue
|
|
628
|
+
BASENAME=$(basename "$hook_file")
|
|
629
|
+
DEST="$CLAUDE_DIR/hooks/$BASENAME"
|
|
630
|
+
|
|
631
|
+
# Hooks need placeholder substitution, so we use a temp file for comparison.
|
|
632
|
+
# Keep the sed list in sync with any new {{PLACEHOLDER}} added to hook files.
|
|
633
|
+
PROCESSED=$(mktemp)
|
|
634
|
+
sed \
|
|
635
|
+
-e "s|{{USER_NAME}}|$USER_NAME|g" \
|
|
636
|
+
-e "s|{{USER_CONTEXT}}|$USER_CONTEXT|g" \
|
|
637
|
+
-e "s|{{ASSISTANT_LANGUAGE}}|$ASSISTANT_LANGUAGE|g" \
|
|
638
|
+
"$hook_file" > "$PROCESSED"
|
|
639
|
+
|
|
640
|
+
if [ -f "$DEST" ]; then
|
|
641
|
+
if ! diff -q "$PROCESSED" "$DEST" >/dev/null 2>&1; then
|
|
642
|
+
if ! $DRY_RUN; then
|
|
643
|
+
mkdir -p "$UPGRADES_DIR/hooks"
|
|
644
|
+
cp "$PROCESSED" "$UPGRADES_DIR/hooks/$BASENAME"
|
|
645
|
+
fi
|
|
646
|
+
upgrade "$BASENAME"
|
|
647
|
+
HOOKS_UPGRADED=$((HOOKS_UPGRADED + 1))
|
|
648
|
+
fi
|
|
649
|
+
else
|
|
650
|
+
if ! $DRY_RUN; then
|
|
651
|
+
cp "$PROCESSED" "$DEST"
|
|
652
|
+
chmod +x "$DEST"
|
|
653
|
+
else
|
|
654
|
+
info "[DRY RUN] Would add hook: $BASENAME"
|
|
655
|
+
fi
|
|
656
|
+
HOOKS_ADDED=$((HOOKS_ADDED + 1))
|
|
657
|
+
fi
|
|
658
|
+
rm -f "$PROCESSED"
|
|
659
|
+
done
|
|
660
|
+
|
|
661
|
+
log "Hooks: $HOOKS_ADDED new, $HOOKS_UPGRADED upgrades available"
|
|
662
|
+
|
|
663
|
+
# ============================================================================
|
|
664
|
+
# 2. COMMANDS — Only add new ones
|
|
665
|
+
# ============================================================================
|
|
666
|
+
log "Adding commands..."
|
|
667
|
+
|
|
668
|
+
for cmd_file in "$SCRIPT_DIR/commands/"*.md; do
|
|
669
|
+
[ -f "$cmd_file" ] || continue
|
|
670
|
+
BASENAME=$(basename "$cmd_file")
|
|
671
|
+
add_or_upgrade "$cmd_file" "$CLAUDE_DIR/commands/$BASENAME" "$BASENAME" "CMDS_ADDED" "CMDS_UPGRADED" "commands"
|
|
672
|
+
done
|
|
673
|
+
|
|
674
|
+
# GSD (get-shit-done) is intentionally NOT vendored by AXEL. It ships and
|
|
675
|
+
# updates through its own installer, so bundling a frozen copy only caused
|
|
676
|
+
# version + command-format skew (the colon-form /gsd: commands were removed
|
|
677
|
+
# upstream in favor of /gsd- skills). AXEL consumes the live GSD skills/agents.
|
|
678
|
+
if [ -d "$CLAUDE_DIR/skills" ] && ls "$CLAUDE_DIR"/skills/gsd-* >/dev/null 2>&1; then
|
|
679
|
+
skip "GSD (managed by its own installer)"
|
|
680
|
+
else
|
|
681
|
+
info "GSD not detected — install it separately: npx get-shit-done-cc@latest --claude --global"
|
|
682
|
+
fi
|
|
683
|
+
|
|
684
|
+
log "Commands: $CMDS_ADDED new, $CMDS_UPGRADED upgrades"
|
|
685
|
+
|
|
686
|
+
# ============================================================================
|
|
687
|
+
# 3. AGENTS — Only add new ones
|
|
688
|
+
# ============================================================================
|
|
689
|
+
log "Adding agents..."
|
|
690
|
+
|
|
691
|
+
for agent_file in "$SCRIPT_DIR/agents/"*.md; do
|
|
692
|
+
[ -f "$agent_file" ] || continue
|
|
693
|
+
BASENAME=$(basename "$agent_file")
|
|
694
|
+
add_or_upgrade "$agent_file" "$CLAUDE_DIR/agents/$BASENAME" "$BASENAME" "AGENTS_ADDED" "AGENTS_UPGRADED" "agents"
|
|
695
|
+
done
|
|
696
|
+
|
|
697
|
+
log "Agents: $AGENTS_ADDED new, $AGENTS_UPGRADED upgrades available"
|
|
698
|
+
|
|
699
|
+
# ============================================================================
|
|
700
|
+
# 4. SKILLS — Only add new skill directories
|
|
701
|
+
# ============================================================================
|
|
702
|
+
log "Adding skills..."
|
|
703
|
+
|
|
704
|
+
SKILLS_ADDED=0
|
|
705
|
+
SKILLS_UPGRADED=0
|
|
706
|
+
if [ -d "$SCRIPT_DIR/skills" ]; then
|
|
707
|
+
for skill_dir in "$SCRIPT_DIR/skills/"*/; do
|
|
708
|
+
[ -d "$skill_dir" ] || continue
|
|
709
|
+
SKILL_NAME=$(basename "$skill_dir")
|
|
710
|
+
|
|
711
|
+
# Gate optional skills behind feature flags
|
|
712
|
+
if [ "$SKILL_NAME" = "posthog-weekly" ] && ! $ENABLE_POSTHOG; then
|
|
713
|
+
info " skip: posthog-weekly (use --enable-posthog to install)"
|
|
714
|
+
SKILLS_SKIPPED=$((SKILLS_SKIPPED + 1))
|
|
715
|
+
continue
|
|
716
|
+
fi
|
|
717
|
+
|
|
718
|
+
if [ -d "$CLAUDE_DIR/skills/$SKILL_NAME" ]; then
|
|
719
|
+
while IFS= read -r -d '' skill_file; do
|
|
720
|
+
rel="${skill_file#"$skill_dir"}"
|
|
721
|
+
dest="$CLAUDE_DIR/skills/$SKILL_NAME/$rel"
|
|
722
|
+
propose_skill_upgrade "$skill_file" "$dest" "$rel" "$SKILL_NAME"
|
|
723
|
+
done < <(find "$skill_dir" -type f ! -path '*/__pycache__/*' ! -name '*.pyc' -print0)
|
|
724
|
+
else
|
|
725
|
+
run mkdir -p "$CLAUDE_DIR/skills/$SKILL_NAME"
|
|
726
|
+
while IFS= read -r -d '' skill_file; do
|
|
727
|
+
rel="${skill_file#"$skill_dir"}"
|
|
728
|
+
dest="$CLAUDE_DIR/skills/$SKILL_NAME/$rel"
|
|
729
|
+
copy_skill_file "$skill_file" "$dest" "$SKILL_NAME/$rel"
|
|
730
|
+
done < <(find "$skill_dir" -type f ! -path '*/__pycache__/*' ! -name '*.pyc' -print0)
|
|
731
|
+
SKILLS_ADDED=$((SKILLS_ADDED + 1))
|
|
732
|
+
fi
|
|
733
|
+
done
|
|
734
|
+
fi
|
|
735
|
+
|
|
736
|
+
# ============================================================================
|
|
737
|
+
# 4b. SCRIPTS — Helper bash scripts called by skills/commands (PostHog, etc.)
|
|
738
|
+
# ============================================================================
|
|
739
|
+
if [ -d "$SCRIPT_DIR/scripts" ]; then
|
|
740
|
+
log "Adding helper scripts..."
|
|
741
|
+
run mkdir -p "$CLAUDE_DIR/scripts"
|
|
742
|
+
for script_file in "$SCRIPT_DIR/scripts/"*.sh; do
|
|
743
|
+
[ -f "$script_file" ] || continue
|
|
744
|
+
BASE_SCRIPT=$(basename "$script_file")
|
|
745
|
+
|
|
746
|
+
# Gate optional helpers behind feature flags (mirror skill gating)
|
|
747
|
+
if [ "$BASE_SCRIPT" = "posthog-snapshot-loader.sh" ] && ! $ENABLE_POSTHOG; then
|
|
748
|
+
info " skip: $BASE_SCRIPT (use --enable-posthog to install)"
|
|
749
|
+
SCRIPTS_SKIPPED=$((SCRIPTS_SKIPPED + 1))
|
|
750
|
+
continue
|
|
751
|
+
fi
|
|
752
|
+
|
|
753
|
+
DEST_SCRIPT="$CLAUDE_DIR/scripts/$BASE_SCRIPT"
|
|
754
|
+
if [ -f "$DEST_SCRIPT" ]; then
|
|
755
|
+
if ! diff -q "$script_file" "$DEST_SCRIPT" >/dev/null 2>&1; then
|
|
756
|
+
if ! $DRY_RUN; then
|
|
757
|
+
mkdir -p "$UPGRADES_DIR/scripts"
|
|
758
|
+
cp "$script_file" "$UPGRADES_DIR/scripts/$BASE_SCRIPT"
|
|
759
|
+
fi
|
|
760
|
+
upgrade "script: $BASE_SCRIPT"
|
|
761
|
+
fi
|
|
762
|
+
else
|
|
763
|
+
run cp "$script_file" "$DEST_SCRIPT"
|
|
764
|
+
run chmod +x "$DEST_SCRIPT"
|
|
765
|
+
info " added: scripts/$BASE_SCRIPT"
|
|
766
|
+
SCRIPTS_ADDED=$((SCRIPTS_ADDED + 1))
|
|
767
|
+
fi
|
|
768
|
+
done
|
|
769
|
+
fi
|
|
770
|
+
|
|
771
|
+
# ============================================================================
|
|
772
|
+
# 5. PLUGINS — Install only those not already present
|
|
773
|
+
# ============================================================================
|
|
774
|
+
log "Installing plugins (skipping already-installed)..."
|
|
775
|
+
|
|
776
|
+
PLUGINS=(
|
|
777
|
+
"frontend-design"
|
|
778
|
+
"context7"
|
|
779
|
+
"ruby-lsp"
|
|
780
|
+
"typescript-lsp"
|
|
781
|
+
"pyright-lsp"
|
|
782
|
+
"code-simplifier"
|
|
783
|
+
"hookify"
|
|
784
|
+
"claude-md-management"
|
|
785
|
+
"commit-commands"
|
|
786
|
+
"pr-review-toolkit"
|
|
787
|
+
)
|
|
788
|
+
|
|
789
|
+
PLUGINS_ADDED=0
|
|
790
|
+
PLUGINS_SKIPPED=0
|
|
791
|
+
|
|
792
|
+
if $SKIP_PLUGINS; then
|
|
793
|
+
PLUGINS_SKIPPED=${#PLUGINS[@]}
|
|
794
|
+
info "Plugins skipped by profile or --skip-plugins"
|
|
795
|
+
else
|
|
796
|
+
# Check which plugins are already installed
|
|
797
|
+
INSTALLED_PLUGINS=""
|
|
798
|
+
if [ -f "$CLAUDE_DIR/plugins/installed_plugins.json" ]; then
|
|
799
|
+
INSTALLED_PLUGINS=$(cat "$CLAUDE_DIR/plugins/installed_plugins.json")
|
|
800
|
+
fi
|
|
801
|
+
|
|
802
|
+
for plugin in "${PLUGINS[@]}"; do
|
|
803
|
+
PLUGIN_KEY="${plugin}@claude-plugins-official"
|
|
804
|
+
if echo "$INSTALLED_PLUGINS" | grep -q "\"$PLUGIN_KEY\"" 2>/dev/null; then
|
|
805
|
+
skip "plugin: $plugin"
|
|
806
|
+
PLUGINS_SKIPPED=$((PLUGINS_SKIPPED + 1))
|
|
807
|
+
else
|
|
808
|
+
if $DRY_RUN; then
|
|
809
|
+
info "[DRY RUN] Would install plugin: $plugin"
|
|
810
|
+
else
|
|
811
|
+
log " Installing $plugin..."
|
|
812
|
+
claude plugins install "$plugin" 2>/dev/null || warn "Failed to install $plugin (may need manual install)"
|
|
813
|
+
fi
|
|
814
|
+
PLUGINS_ADDED=$((PLUGINS_ADDED + 1))
|
|
815
|
+
fi
|
|
816
|
+
done
|
|
817
|
+
fi
|
|
818
|
+
|
|
819
|
+
log "Plugins: $PLUGINS_ADDED added, $PLUGINS_SKIPPED already installed"
|
|
820
|
+
|
|
821
|
+
# ============================================================================
|
|
822
|
+
# 6. SETTINGS.JSON — MERGE, never replace
|
|
823
|
+
# ============================================================================
|
|
824
|
+
log "Merging settings.json (preserving all existing config)..."
|
|
825
|
+
|
|
826
|
+
AXEL_SETTINGS="$SCRIPT_DIR/templates/settings.json"
|
|
827
|
+
EXISTING_SETTINGS="$CLAUDE_DIR/settings.json"
|
|
828
|
+
AXEL_SETTINGS_PROFILED=$(mktemp)
|
|
829
|
+
settings_for_profile "$AXEL_SETTINGS" "$AXEL_SETTINGS_PROFILED"
|
|
830
|
+
|
|
831
|
+
if $DRY_RUN; then
|
|
832
|
+
info "[DRY RUN] Would merge AXEL settings into existing settings.json"
|
|
833
|
+
elif [ ! -f "$EXISTING_SETTINGS" ]; then
|
|
834
|
+
# No existing settings — just copy ours
|
|
835
|
+
cp "$AXEL_SETTINGS_PROFILED" "$EXISTING_SETTINGS"
|
|
836
|
+
log " Created new settings.json (no existing config found)"
|
|
837
|
+
else
|
|
838
|
+
# Deep merge using jq filter file (avoids shell escape issues)
|
|
839
|
+
# Strategy: existing always wins for scalars; arrays/objects get unioned
|
|
840
|
+
MERGE_FILTER="$SCRIPT_DIR/templates/merge-settings.jq"
|
|
841
|
+
MERGED_FILE=$(mktemp)
|
|
842
|
+
|
|
843
|
+
if jq -s -f "$MERGE_FILTER" "$EXISTING_SETTINGS" "$AXEL_SETTINGS_PROFILED" > "$MERGED_FILE" 2>/dev/null; then
|
|
844
|
+
# Validate the output is valid JSON before replacing
|
|
845
|
+
if jq '.' "$MERGED_FILE" >/dev/null 2>&1; then
|
|
846
|
+
mv "$MERGED_FILE" "$EXISTING_SETTINGS"
|
|
847
|
+
log " Settings merged successfully (your existing config preserved)"
|
|
848
|
+
else
|
|
849
|
+
rm -f "$MERGED_FILE"
|
|
850
|
+
warn "Settings merge produced invalid JSON — original preserved"
|
|
851
|
+
cp "$AXEL_SETTINGS_PROFILED" "$CLAUDE_DIR/settings.axel-template.json"
|
|
852
|
+
fi
|
|
853
|
+
else
|
|
854
|
+
rm -f "$MERGED_FILE"
|
|
855
|
+
warn "Settings merge failed — your original settings.json is untouched"
|
|
856
|
+
warn "AXEL settings saved to: $CLAUDE_DIR/settings.axel-template.json"
|
|
857
|
+
cp "$AXEL_SETTINGS_PROFILED" "$CLAUDE_DIR/settings.axel-template.json"
|
|
858
|
+
fi
|
|
859
|
+
fi
|
|
860
|
+
rm -f "$AXEL_SETTINGS_PROFILED"
|
|
861
|
+
|
|
862
|
+
# ============================================================================
|
|
863
|
+
# 6b. AXEL MANIFEST — Machine-readable install inventory for doctor/tests
|
|
864
|
+
# ============================================================================
|
|
865
|
+
log "Installing AXEL manifest..."
|
|
866
|
+
write_manifest "$CLAUDE_DIR"
|
|
867
|
+
|
|
868
|
+
# ============================================================================
|
|
869
|
+
# 7. STATUSLINE — Add only if not present
|
|
870
|
+
# ============================================================================
|
|
871
|
+
if [ ! -f "$CLAUDE_DIR/statusline-command.sh" ]; then
|
|
872
|
+
log "Adding statusline script..."
|
|
873
|
+
run cp "$SCRIPT_DIR/templates/statusline-command.sh" "$CLAUDE_DIR/statusline-command.sh"
|
|
874
|
+
run chmod +x "$CLAUDE_DIR/statusline-command.sh"
|
|
875
|
+
else
|
|
876
|
+
skip "statusline-command.sh"
|
|
877
|
+
fi
|
|
878
|
+
|
|
879
|
+
# ============================================================================
|
|
880
|
+
# 7b. USAGE MONITOR — session cost log + live dashboard + web server
|
|
881
|
+
# ============================================================================
|
|
882
|
+
log "Setting up usage monitor..."
|
|
883
|
+
|
|
884
|
+
MONITOR_TOOLS=(session-server.js session-live.sh session-dashboard-gen.sh session-costs-view.sh)
|
|
885
|
+
MONITOR_ADDED=0
|
|
886
|
+
if $SKIP_MONITOR; then
|
|
887
|
+
MONITOR_SKIPPED=${#MONITOR_TOOLS[@]}
|
|
888
|
+
info "Usage monitor skipped by profile or --skip-monitor"
|
|
889
|
+
else
|
|
890
|
+
# Ensure tools dir exists
|
|
891
|
+
run mkdir -p "$CLAUDE_DIR/tools" "$CLAUDE_DIR/logs"
|
|
892
|
+
|
|
893
|
+
for tool in "${MONITOR_TOOLS[@]}"; do
|
|
894
|
+
src="$SCRIPT_DIR/tools/$tool"
|
|
895
|
+
dest="$CLAUDE_DIR/tools/$tool"
|
|
896
|
+
[ -f "$src" ] || continue
|
|
897
|
+
if [ ! -f "$dest" ]; then
|
|
898
|
+
if ! $DRY_RUN; then cp "$src" "$dest" && chmod +x "$dest"; else info "[DRY RUN] Would add tool: $tool"; fi
|
|
899
|
+
MONITOR_ADDED=$((MONITOR_ADDED + 1))
|
|
900
|
+
else
|
|
901
|
+
skip "tools/$tool"
|
|
902
|
+
fi
|
|
903
|
+
done
|
|
904
|
+
fi
|
|
905
|
+
|
|
906
|
+
# Install launchd service (macOS only) — auto-starts web monitor on login
|
|
907
|
+
if ! $SKIP_MONITOR && [[ "$OSTYPE" == "darwin"* ]]; then
|
|
908
|
+
PLIST_LABEL="com.${USERNAME:-$(whoami)}.claude-monitor"
|
|
909
|
+
PLIST_DEST="$HOME/Library/LaunchAgents/${PLIST_LABEL}.plist"
|
|
910
|
+
PLIST_SRC="$SCRIPT_DIR/templates/claude-monitor.plist"
|
|
911
|
+
NODE_BIN=$(which node 2>/dev/null || echo "/usr/local/bin/node")
|
|
912
|
+
|
|
913
|
+
if [ ! -f "$PLIST_DEST" ]; then
|
|
914
|
+
if $NO_LAUNCHD; then
|
|
915
|
+
info "launchd agent skipped by --no-launchd or profile"
|
|
916
|
+
elif ! $DRY_RUN; then
|
|
917
|
+
mkdir -p "$(dirname "$PLIST_DEST")"
|
|
918
|
+
sed -e "s|{{USERNAME}}|${USERNAME:-$(whoami)}|g" \
|
|
919
|
+
-e "s|{{HOME}}|$HOME|g" \
|
|
920
|
+
-e "s|{{NODE_PATH}}|$NODE_BIN|g" \
|
|
921
|
+
"$PLIST_SRC" > "$PLIST_DEST"
|
|
922
|
+
launchctl load "$PLIST_DEST" 2>/dev/null && \
|
|
923
|
+
log " Usage monitor started at http://localhost:9119" || \
|
|
924
|
+
warn " launchd load failed — run manually: node ~/.claude/tools/session-server.js"
|
|
925
|
+
else
|
|
926
|
+
info "[DRY RUN] Would install launchd agent: $PLIST_LABEL"
|
|
927
|
+
fi
|
|
928
|
+
else
|
|
929
|
+
skip "launchd agent: $PLIST_LABEL"
|
|
930
|
+
fi
|
|
931
|
+
fi
|
|
932
|
+
|
|
933
|
+
log "Usage monitor: $MONITOR_ADDED tools added | Dashboard: http://localhost:9119"
|
|
934
|
+
|
|
935
|
+
# ============================================================================
|
|
936
|
+
# 8. KEYBINDINGS — Merge, not replace
|
|
937
|
+
# ============================================================================
|
|
938
|
+
if $SKIP_KEYBINDINGS; then
|
|
939
|
+
KEYBINDINGS_SKIPPED=1
|
|
940
|
+
info "keybindings.json skipped by profile or --skip-keybindings"
|
|
941
|
+
elif [ ! -f "$CLAUDE_DIR/keybindings.json" ]; then
|
|
942
|
+
log "Adding keybindings..."
|
|
943
|
+
run cp "$SCRIPT_DIR/templates/keybindings.json" "$CLAUDE_DIR/keybindings.json"
|
|
944
|
+
else
|
|
945
|
+
skip "keybindings.json (preserving your custom bindings)"
|
|
946
|
+
fi
|
|
947
|
+
|
|
948
|
+
# ============================================================================
|
|
949
|
+
# 9. MEMORY SYSTEM — Only ensure structure exists, NEVER touch content
|
|
950
|
+
# ============================================================================
|
|
951
|
+
log "Ensuring memory system structure..."
|
|
952
|
+
|
|
953
|
+
run mkdir -p "$CLAUDE_DIR/memory/decisions"
|
|
954
|
+
|
|
955
|
+
if [ ! -f "$CLAUDE_DIR/memory/MEMORY.md" ]; then
|
|
956
|
+
if ! $DRY_RUN; then
|
|
957
|
+
cat > "$CLAUDE_DIR/memory/MEMORY.md" << 'EOF'
|
|
958
|
+
# Memory Index
|
|
959
|
+
|
|
960
|
+
This file is automatically maintained. Each entry points to a memory file.
|
|
961
|
+
Memory types: user, feedback, project, reference.
|
|
962
|
+
EOF
|
|
963
|
+
else
|
|
964
|
+
info "[DRY RUN] Would create MEMORY.md index"
|
|
965
|
+
fi
|
|
966
|
+
log " MEMORY.md index is missing"
|
|
967
|
+
else
|
|
968
|
+
MEMORY_COUNT=$(find "$CLAUDE_DIR/memory" -maxdepth 1 -type f -name '*.md' ! -name MEMORY.md | wc -l | tr -d ' ')
|
|
969
|
+
log " Memory intact: $MEMORY_COUNT existing memories preserved"
|
|
970
|
+
fi
|
|
971
|
+
|
|
972
|
+
# ============================================================================
|
|
973
|
+
# 10. TEAM CLAUDE.MD — Offer only if not present
|
|
974
|
+
# ============================================================================
|
|
975
|
+
if $SKIP_CLAUDE_MD; then
|
|
976
|
+
CLAUDE_MD_SKIPPED=1
|
|
977
|
+
info "~/CLAUDE.md skipped by profile or --skip-claude-md"
|
|
978
|
+
elif [ ! -f "$HOME/CLAUDE.md" ]; then
|
|
979
|
+
log "Creating starter CLAUDE.md..."
|
|
980
|
+
run cp "$SCRIPT_DIR/templates/CLAUDE.md" "$HOME/CLAUDE.md"
|
|
981
|
+
if $DRY_RUN; then
|
|
982
|
+
log " Would create ~/CLAUDE.md"
|
|
983
|
+
else
|
|
984
|
+
log " Created ~/CLAUDE.md — customize it for your workflow"
|
|
985
|
+
fi
|
|
986
|
+
else
|
|
987
|
+
CLAUDE_MD_LINES=$(wc -l < "$HOME/CLAUDE.md" | tr -d ' ')
|
|
988
|
+
log " ~/CLAUDE.md preserved ($CLAUDE_MD_LINES lines)"
|
|
989
|
+
fi
|
|
990
|
+
|
|
991
|
+
# ============================================================================
|
|
992
|
+
# 11. GSD (Get Shit Done) package
|
|
993
|
+
# ============================================================================
|
|
994
|
+
if $SKIP_GSD; then
|
|
995
|
+
GSD_SKIPPED=1
|
|
996
|
+
info "GSD external installer skipped by profile or --skip-gsd"
|
|
997
|
+
elif [ -d "$CLAUDE_DIR/get-shit-done" ]; then
|
|
998
|
+
log "GSD already installed, skipping"
|
|
999
|
+
else
|
|
1000
|
+
log "Installing GSD (Get Shit Done) package..."
|
|
1001
|
+
if $DRY_RUN; then
|
|
1002
|
+
info "[DRY RUN] Would install get-shit-done-cc via npx"
|
|
1003
|
+
else
|
|
1004
|
+
npx -y get-shit-done-cc@latest 2>/dev/null && log "GSD installed" || warn "GSD install failed — install manually: npx get-shit-done-cc@latest"
|
|
1005
|
+
fi
|
|
1006
|
+
fi
|
|
1007
|
+
|
|
1008
|
+
# ============================================================================
|
|
1009
|
+
# 12. UPGRADE REVIEW PROMPT — Generate if there are upgrades to review
|
|
1010
|
+
# ============================================================================
|
|
1011
|
+
TOTAL_UPGRADES=$((HOOKS_UPGRADED + CMDS_UPGRADED + AGENTS_UPGRADED + SKILLS_UPGRADED))
|
|
1012
|
+
|
|
1013
|
+
if [ "$TOTAL_UPGRADES" -gt 0 ] && ! $DRY_RUN; then
|
|
1014
|
+
write_upgrade_review "$UPGRADES_DIR" "$HOME/.claude" "$TARGET"
|
|
1015
|
+
fi
|
|
1016
|
+
|
|
1017
|
+
# ============================================================================
|
|
1018
|
+
# DONE — Summary
|
|
1019
|
+
# ============================================================================
|
|
1020
|
+
echo ""
|
|
1021
|
+
printf "${GREEN}${BOLD}============================================${RESET}\n"
|
|
1022
|
+
printf "${GREEN}${BOLD} AXEL Onboarding Complete!${RESET}\n"
|
|
1023
|
+
printf "${GREEN}${BOLD}============================================${RESET}\n"
|
|
1024
|
+
echo ""
|
|
1025
|
+
log "All changes are ADDITIVE — nothing was overwritten or deleted."
|
|
1026
|
+
info "Install profile: $PROFILE"
|
|
1027
|
+
info "Install target: $TARGET"
|
|
1028
|
+
if $DRY_RUN; then
|
|
1029
|
+
info "Safety backup would be at: $BACKUP_DIR"
|
|
1030
|
+
else
|
|
1031
|
+
log "Safety backup at: $BACKUP_DIR"
|
|
1032
|
+
fi
|
|
1033
|
+
echo ""
|
|
1034
|
+
|
|
1035
|
+
printf "${BOLD}What was added (new files):${RESET}\n"
|
|
1036
|
+
info " Hooks: $HOOKS_ADDED new"
|
|
1037
|
+
info " Commands: $CMDS_ADDED new"
|
|
1038
|
+
info " Agents: $AGENTS_ADDED new"
|
|
1039
|
+
info " Skills: $SKILLS_ADDED new"
|
|
1040
|
+
info " Plugins: $PLUGINS_ADDED new ($PLUGINS_SKIPPED already installed)"
|
|
1041
|
+
info " Scripts: $SCRIPTS_ADDED new ($SCRIPTS_SKIPPED skipped)"
|
|
1042
|
+
info " Monitor: $MONITOR_ADDED tools ($MONITOR_SKIPPED skipped) | http://localhost:9119"
|
|
1043
|
+
info " GSD: $GSD_SKIPPED skipped"
|
|
1044
|
+
info " Keybinds: $KEYBINDINGS_SKIPPED skipped"
|
|
1045
|
+
info " CLAUDE.md:$CLAUDE_MD_SKIPPED skipped"
|
|
1046
|
+
echo ""
|
|
1047
|
+
|
|
1048
|
+
if [ "$TOTAL_UPGRADES" -gt 0 ]; then
|
|
1049
|
+
printf "${YELLOW}${BOLD}Upgrades available: $TOTAL_UPGRADES files have improved versions${RESET}\n"
|
|
1050
|
+
info " Hooks: $HOOKS_UPGRADED | Commands: $CMDS_UPGRADED"
|
|
1051
|
+
info " Agents: $AGENTS_UPGRADED | Skills: $SKILLS_UPGRADED"
|
|
1052
|
+
echo ""
|
|
1053
|
+
printf "${BOLD}To review and apply upgrades, run this in Claude Code:${RESET}\n"
|
|
1054
|
+
echo ""
|
|
1055
|
+
printf " ${GREEN}Read the file ~/.claude/axel-upgrades/REVIEW.md and follow its instructions${RESET}\n"
|
|
1056
|
+
echo ""
|
|
1057
|
+
info "Your agent will compare each file, explain what's better,"
|
|
1058
|
+
info "and let you decide what to merge. Nothing changes without your approval."
|
|
1059
|
+
echo ""
|
|
1060
|
+
fi
|
|
1061
|
+
|
|
1062
|
+
printf "${BOLD}What was preserved:${RESET}\n"
|
|
1063
|
+
info " Your existing memory (all files intact)"
|
|
1064
|
+
info " Your existing settings (merged, not replaced)"
|
|
1065
|
+
info " Your existing CLAUDE.md"
|
|
1066
|
+
info " Your existing hooks, commands, and agents"
|
|
1067
|
+
echo ""
|
|
1068
|
+
|
|
1069
|
+
info "Next steps:"
|
|
1070
|
+
info " 1. Restart Claude Code to load AXEL updates"
|
|
1071
|
+
if $SKIP_GSD; then
|
|
1072
|
+
TRY_COMMANDS="/daily, /style"
|
|
1073
|
+
else
|
|
1074
|
+
TRY_COMMANDS="/daily, /style, /gsd-help"
|
|
1075
|
+
fi
|
|
1076
|
+
if [ "$TOTAL_UPGRADES" -gt 0 ]; then
|
|
1077
|
+
info " 2. Review upgrades: paste the command above into Claude Code"
|
|
1078
|
+
info " 3. Try: $TRY_COMMANDS"
|
|
1079
|
+
else
|
|
1080
|
+
info " 2. Try: $TRY_COMMANDS"
|
|
1081
|
+
fi
|
|
1082
|
+
if [ "$PROFILE" = "core" ]; then
|
|
1083
|
+
info " AXEL installed public safe defaults. Use --profile personal for fuller local automation."
|
|
1084
|
+
else
|
|
1085
|
+
info " AXEL will continue learning your personal preferences"
|
|
1086
|
+
fi
|
|
1087
|
+
echo ""
|