diff --git a/fedac/native/ac-os b/fedac/native/ac-os index 03e3a8200..ec7bfe874 100755 --- a/fedac/native/ac-os +++ b/fedac/native/ac-os @@ -130,13 +130,28 @@ build_initramfs() { # Copy fresh binary into initramfs sudo cp "${BUILD_DIR}/ac-native" "${INITRAMFS_ROOT}/ac-native" - # Claude Code native binary (no Node.js needed) + # Claude Code native binary (no Node.js needed). + # Look in the builder's home first; if nothing's installed (oven build + # machines don't ship claude pre-installed) fall back to downloading + # the latest native binary via claude.ai/install.sh so every OS build + # ships a working /bin/claude instead of the "claude: command not + # found" that was leaving devices broken post-flash. local CLAUDE_NATIVE="${HOME}/.local/share/claude/versions" local CLAUDE_BIN="" if [ -d "${CLAUDE_NATIVE}" ]; then - # Find the latest version binary CLAUDE_BIN=$(ls -t "${CLAUDE_NATIVE}/"* 2>/dev/null | head -1) fi + if [ -z "${CLAUDE_BIN}" ] || [ ! -f "${CLAUDE_BIN}" ]; then + log "Claude native binary not found locally; fetching via claude.ai/install.sh..." + # install.sh is safe to run on CI — writes to $HOME/.local only. + if curl -fsSL https://claude.ai/install.sh | bash 2>&1 | sed 's/^/ [claude-install] /' | tail -20; then + if [ -d "${CLAUDE_NATIVE}" ]; then + CLAUDE_BIN=$(ls -t "${CLAUDE_NATIVE}/"* 2>/dev/null | head -1) + fi + else + log " claude-install failed (non-fatal — will ship image without /bin/claude)" + fi + fi if [ -n "${CLAUDE_BIN}" ] && [ -f "${CLAUDE_BIN}" ]; then log "Bundling Claude Code (native binary)..." sudo cp "${CLAUDE_BIN}" "${INITRAMFS_ROOT}/bin/claude" diff --git a/fedac/native/initramfs/init b/fedac/native/initramfs/init index bc1b80e65..285cb7ff2 100755 --- a/fedac/native/initramfs/init +++ b/fedac/native/initramfs/init @@ -69,7 +69,11 @@ if [ -f /claude-creds.json ] || [ -f /claude-token ]; then mkdir -p /tmp/.claude [ -f /claude-creds.json ] && cp /claude-creds.json /tmp/.claude/.credentials.json cp /claude-state.json /tmp/.claude.json 2>/dev/null - printf '{"permissions":{"allow":["Bash(*)","Read(*)","Write(*)","Edit(*)","Glob(*)","Grep(*)","WebFetch(*)","WebSearch(*)"]},"autoUpdates":false,"installMethod":"native"}\n' > /tmp/.claude/settings.json + # Pin Claude's default model to the "sonnet" alias — Anthropic's + # CLI resolves "sonnet" to the latest Sonnet family member, which + # is currently Sonnet 4.7. Users who want a specific pinned version + # can override by writing a different model string into this file. + printf '{"permissions":{"allow":["Bash(*)","Read(*)","Write(*)","Edit(*)","Glob(*)","Grep(*)","WebFetch(*)","WebSearch(*)"]},"autoUpdates":false,"installMethod":"native","model":"sonnet"}\n' > /tmp/.claude/settings.json fi if [ -f /tangled-key ] || [ -f /tangled-ssh-config ] || [ -f /tangled-known-hosts ]; then mkdir -p /tmp/.ssh diff --git a/fedac/native/src/pty.c b/fedac/native/src/pty.c index fd7bca3ac..1d490a954 100644 --- a/fedac/native/src/pty.c +++ b/fedac/native/src/pty.c @@ -563,6 +563,12 @@ int pty_spawn(ACPty *pty, int cols, int rows, const char *cmd, char *const argv[ setenv("LOGNAME", "root", 1); setenv("GIT_TERMINAL_PROMPT", "0", 1); setenv("CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC", "1", 1); + // Pin Claude's default model to "sonnet" — Anthropic's CLI resolves + // that alias to the latest Sonnet family member, currently 4.7. + // Setting ANTHROPIC_MODEL belt-and-suspenders alongside the same + // key in /tmp/.claude/settings.json so either resolution path + // lands on 4.7 instead of whatever the CLI's built-in default is. + setenv("ANTHROPIC_MODEL", "sonnet", 0); // SSL certs for API connections setenv("SSL_CERT_FILE", "/etc/pki/tls/certs/ca-bundle.crt", 0); setenv("SSL_CERT_DIR", "/etc/ssl/certs", 0);