Import claude-code-switcher from the Windows build
Source of truth so far has been c:\Users\smoido\projects\cli on the Windows box, which has no git history of its own. This is that tree copied verbatim over SSH, minus dist/ - the PowerShell build, the POSIX port under linux/, and the presets both share. Recorded as its own commit so that everything after it is a reviewable diff rather than an undifferentiated first drop.
This commit is contained in:
Executable
+139
@@ -0,0 +1,139 @@
|
||||
#!/usr/bin/env bash
|
||||
# One-time installer for claude-mode (Linux / macOS).
|
||||
#
|
||||
# Installs to ~/.claude-mode, symlinks the entry point into ~/.local/bin, and
|
||||
# adds a marked block to your shell rc for the `claude` wrapper.
|
||||
#
|
||||
# Idempotent: safe to re-run to upgrade. Existing presets are kept unless
|
||||
# --force is passed. ~/.claude/settings.json is NOT touched here - only by an
|
||||
# actual `claude-mode <mode>`.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
FORCE=0
|
||||
SKIP_KEY=0
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--force) FORCE=1 ;;
|
||||
--skip-key-prompt) SKIP_KEY=1 ;;
|
||||
-h|--help) echo "usage: install.sh [--force] [--skip-key-prompt]"; exit 0 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
SRC="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
ROOT="${CM_ROOT:-$HOME/.claude-mode}"
|
||||
BINDIR="$HOME/.local/bin"
|
||||
|
||||
green() { printf ' \033[32mok \033[0m %s\n' "$*"; }
|
||||
warn() { printf ' \033[33mwarn\033[0m %s\n' "$*"; }
|
||||
fail() { printf ' \033[31mFAIL\033[0m %s\n' "$*"; }
|
||||
|
||||
printf '\ninstalling claude-mode -> %s\n' "$ROOT"
|
||||
|
||||
# --- preflight -------------------------------------------------------------
|
||||
PY="${CLAUDE_MODE_PYTHON:-python3}"
|
||||
if ! command -v "$PY" >/dev/null 2>&1; then
|
||||
fail "python3 not found. claude-mode uses it for JSON handling."
|
||||
fail "install it (apt install python3 / dnf install python3 / brew install python) and re-run."
|
||||
exit 1
|
||||
fi
|
||||
green "python3: $(command -v "$PY")"
|
||||
|
||||
if ! command -v curl >/dev/null 2>&1; then
|
||||
warn 'curl not found - `models` and `doctor` network checks will not work'
|
||||
fi
|
||||
if ! command -v claude >/dev/null 2>&1; then
|
||||
warn 'claude is not on PATH - claude-mode installs anyway, but nothing uses its config yet'
|
||||
fi
|
||||
|
||||
# --- directories -----------------------------------------------------------
|
||||
mkdir -p "$ROOT/bin" "$ROOT/presets" "$ROOT/vault" "$ROOT/backups" "$BINDIR"
|
||||
chmod 700 "$ROOT" "$ROOT/vault" 2>/dev/null || true
|
||||
|
||||
# --- payload ---------------------------------------------------------------
|
||||
install -m 0755 "$SRC/claude-mode" "$ROOT/bin/claude-mode"
|
||||
install -m 0755 "$SRC/claude-key-helper.sh" "$ROOT/bin/claude-key-helper.sh"
|
||||
install -m 0644 "$SRC/cm-json.py" "$ROOT/bin/cm-json.py"
|
||||
install -m 0644 "$SRC/cm-vault.sh" "$ROOT/bin/cm-vault.sh"
|
||||
green 'copied claude-mode + helpers'
|
||||
|
||||
# --- presets (shared with the Windows build) -------------------------------
|
||||
PRESET_SRC="$SRC/../presets"
|
||||
[ -d "$PRESET_SRC" ] || PRESET_SRC="$SRC/presets"
|
||||
if [ -d "$PRESET_SRC" ]; then
|
||||
for f in "$PRESET_SRC"/*.json; do
|
||||
[ -e "$f" ] || continue
|
||||
base="$(basename "$f")"
|
||||
if [ -e "$ROOT/presets/$base" ] && [ "$FORCE" -eq 0 ]; then
|
||||
printf ' skip preset %s (exists; --force to overwrite)\n' "${base%.json}"
|
||||
else
|
||||
install -m 0644 "$f" "$ROOT/presets/$base"
|
||||
green "preset ${base%.json}"
|
||||
fi
|
||||
done
|
||||
else
|
||||
warn 'no presets directory found in the payload'
|
||||
fi
|
||||
|
||||
# --- initial state ---------------------------------------------------------
|
||||
if [ ! -f "$ROOT/state.json" ]; then
|
||||
printf '{\n "mode": "anthropic",\n "preset": "",\n "writtenEnvKeys": []\n}\n' > "$ROOT/state.json"
|
||||
green 'state.json initialised (mode=anthropic)'
|
||||
fi
|
||||
|
||||
# --- PATH entry ------------------------------------------------------------
|
||||
ln -sf "$ROOT/bin/claude-mode" "$BINDIR/claude-mode"
|
||||
green "linked $BINDIR/claude-mode"
|
||||
|
||||
case ":$PATH:" in
|
||||
*":$BINDIR:"*) ;;
|
||||
*) warn "$BINDIR is not on PATH - add it in your shell rc: export PATH=\"\$HOME/.local/bin:\$PATH\"" ;;
|
||||
esac
|
||||
|
||||
# --- shell rc block --------------------------------------------------------
|
||||
SNIPPET="$SRC/shell-snippet.sh"
|
||||
START='# >>> claude-mode >>>'
|
||||
END='# <<< claude-mode <<<'
|
||||
|
||||
add_block() {
|
||||
local rc="$1"
|
||||
[ -f "$rc" ] || return 0
|
||||
if grep -qF "$START" "$rc" 2>/dev/null; then
|
||||
# replace the existing block in place
|
||||
"$PY" - "$rc" "$SNIPPET" "$START" "$END" <<'PYEOF'
|
||||
import sys, re
|
||||
rc, snip, start, end = sys.argv[1:5]
|
||||
body = open(rc, encoding='utf-8').read()
|
||||
new = open(snip, encoding='utf-8').read().rstrip('\n')
|
||||
pattern = re.compile(re.escape(start) + r'.*?' + re.escape(end), re.S)
|
||||
open(rc, 'w', encoding='utf-8').write(pattern.sub(lambda _: new, body))
|
||||
PYEOF
|
||||
green "updated claude-mode block in $rc"
|
||||
else
|
||||
printf '\n%s\n' "$(cat "$SNIPPET")" >> "$rc"
|
||||
green "appended claude-mode block to $rc"
|
||||
fi
|
||||
}
|
||||
|
||||
RC_TOUCHED=0
|
||||
for rc in "$HOME/.bashrc" "$HOME/.zshrc"; do
|
||||
if [ -f "$rc" ]; then add_block "$rc"; RC_TOUCHED=1; fi
|
||||
done
|
||||
[ "$RC_TOUCHED" -eq 0 ] && warn 'no ~/.bashrc or ~/.zshrc found - the `claude` wrapper was not installed'
|
||||
|
||||
# --- key -------------------------------------------------------------------
|
||||
if [ "$SKIP_KEY" -eq 0 ]; then
|
||||
# shellcheck source=/dev/null
|
||||
. "$ROOT/bin/cm-vault.sh"
|
||||
if cm_vault_has openrouter && [ "$FORCE" -eq 0 ]; then
|
||||
green 'OpenRouter key already stored'
|
||||
else
|
||||
printf '\n'
|
||||
"$ROOT/bin/claude-mode" set-key openrouter || warn 'key not stored - run `claude-mode set-key openrouter` later'
|
||||
fi
|
||||
fi
|
||||
|
||||
printf '\ndone. Open a new shell, then:\n'
|
||||
printf ' claude-mode\n'
|
||||
printf ' claude-mode status\n'
|
||||
printf ' claude-mode doctor\n'
|
||||
Reference in New Issue
Block a user