Files
nanoclaw/setup/register-claude-token.sh
exe.dev user e34380656c feat(setup): headless-aware Claude sign-in pre-message
The pre-message printed by setup/register-claude-token.sh used to
say "A browser window will open for you to sign in with your
Claude account." Accurate on a laptop or desktop, but a lie on
headless devices (Pi, SSH'd-into Linux server, CI) where the
browser auto-open never lands and the user actually has to copy
the URL `claude setup-token` prints to another device.

Add a small bash isHeadless check (mirrors `isHeadless()` in
setup/platform.ts: Linux without DISPLAY / WAYLAND_DISPLAY) and
swap the heredoc accordingly:

  - Headless: "A sign-in link will appear for you to sign in with
    your Claude account. When you finish, we'll save the token
    to your OneCLI vault automatically."
  - GUI: existing "A browser window will open…" copy, unchanged.

The trailing "Press Enter to continue, or edit the command first."
line and the actual `claude setup-token` invocation are unchanged
— only the leading sentence flips.
2026-05-03 12:48:37 +00:00

128 lines
4.5 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
# Register a Claude subscription OAuth token with OneCLI — the *only* auth
# path that needs a TTY break in the flow. Paste-based paths (existing
# OAuth token / API key) are handled in-process by setup/auto.ts using
# clack prompts, then onecli secrets create is invoked directly from TS.
#
# Flow:
# 1. Run `claude setup-token` under a PTY (via script(1)) so the browser
# OAuth dance works and its token is captured into a tempfile.
# 2. Regex the sk-ant-oat…AA token out of the ANSI-stripped capture.
# 3. Register it with OneCLI.
#
# Env overrides:
# SECRET_NAME OneCLI secret name (default: Anthropic)
# HOST_PATTERN OneCLI host pattern (default: api.anthropic.com)
# Prefer bash 4+ (for `read -e -i` readline preload). macOS ships 3.2 in
# /bin/bash, but Homebrew users usually have 5.x first on PATH. The
# readline preload is optional — on 3.x we fall back to a plain prompt.
SECRET_NAME="${SECRET_NAME:-Anthropic}"
HOST_PATTERN="${HOST_PATTERN:-api.anthropic.com}"
command -v onecli >/dev/null \
|| { echo "onecli not found. Install it first (see /setup §4)." >&2; exit 1; }
if ! command -v claude >/dev/null 2>&1; then
echo "Claude Code CLI not found — installing it now (needed for subscription sign-in)…"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
if ! bash "$SCRIPT_DIR/install-claude.sh"; then
echo >&2
echo "Couldn't install the Claude Code CLI automatically." >&2
echo "Install it manually with" >&2
echo " curl -fsSL https://claude.ai/install.sh | bash" >&2
echo "and re-run setup." >&2
exit 1
fi
# install-claude.sh PATH additions are scoped to its own subshell; redo
# them here so the rest of this script can see the fresh `claude` binary.
if [ -d "$HOME/.local/bin" ] && [[ ":$PATH:" != *":$HOME/.local/bin:"* ]]; then
export PATH="$HOME/.local/bin:$PATH"
fi
hash -r 2>/dev/null || true
fi
command -v script >/dev/null \
|| { echo "script(1) is required for PTY capture." >&2; exit 1; }
tmpfile=$(mktemp -t claude-setup-token.XXXXXX)
trap 'rm -f "$tmpfile"' EXIT
# Detect headless. Mirrors `isHeadless()` in setup/platform.ts: on Linux
# with neither DISPLAY nor WAYLAND_DISPLAY set, no graphical session
# exists, so `claude setup-token` won't be able to auto-open a browser
# and the user will need to copy the printed sign-in URL by hand. The
# pre-message copy below is swapped accordingly so we don't promise a
# browser pop that will never happen.
is_headless=0
if [ "$(uname -s)" = "Linux" ] && [ -z "${DISPLAY:-}" ] && [ -z "${WAYLAND_DISPLAY:-}" ]; then
is_headless=1
fi
if [ "$is_headless" = "1" ]; then
cat <<'EOF'
A sign-in link will appear for you to sign in with your Claude account.
When you finish, we'll save the token to your OneCLI vault automatically.
Press Enter to continue, or edit the command first.
EOF
else
cat <<'EOF'
A browser window will open for you to sign in with your Claude account.
When you finish, we'll save the token to your OneCLI vault automatically.
Press Enter to continue, or edit the command first.
EOF
fi
cmd="claude setup-token"
if [ "${BASH_VERSINFO[0]:-0}" -ge 4 ]; then
# bash 4+: pre-fill the readline buffer so Enter literally submits.
read -r -e -i "$cmd" -p "$ " cmd </dev/tty
else
# bash 3.x (macOS default /bin/bash): no readline preload. Fall back.
echo "$ $cmd"
read -r -p "Press Enter to run, Ctrl-C to abort. " _ </dev/tty
fi
# `script` arg order differs between BSD (macOS) and util-linux.
if script --version 2>/dev/null | grep -q util-linux; then
script -q -c "$cmd" "$tmpfile"
else
# BSD script: command is argv after the file, so let it word-split.
# shellcheck disable=SC2086
script -q "$tmpfile" $cmd
fi
# Strip ANSI codes + newlines (TTY wraps the token mid-string), then match
# the sk-ant-oat…AA token. perl because BSD grep caps {n,m} at 255.
token=$(sed $'s/\x1b\\[[0-9;]*[a-zA-Z]//g' "$tmpfile" \
| tr -d '\n\r' \
| perl -ne 'print "$1\n" while /(sk-ant-oat[A-Za-z0-9_-]{80,500}AA)/g' \
| tail -1 || true)
if [ -z "$token" ]; then
keep=$(mktemp -t claude-setup-token-log.XXXXXX)
cp "$tmpfile" "$keep"
echo >&2
echo "No sk-ant-oat…AA token found. Raw log: $keep" >&2
exit 1
fi
echo
echo "Got token: ${token:0:16}${token: -4}"
echo "Saving it to your OneCLI vault as '${SECRET_NAME}' (host: ${HOST_PATTERN})…"
onecli secrets create \
--name "$SECRET_NAME" \
--type anthropic \
--value "$token" \
--host-pattern "$HOST_PATTERN"
echo "Done."