Merge branch 'main' into fix/update-nanoclaw-skill-v2
This commit is contained in:
@@ -6,8 +6,8 @@ This is NanoClaw v2, a ground-up rewrite with breaking changes throughout. It ca
|
||||
|
||||
**Do this instead:**
|
||||
1. Abort the merge: `git merge --abort` (or `git reset --hard ORIG_HEAD` if the merge already completed).
|
||||
2. Tell the user, verbatim: *"This is the v2 rewrite — it can't be merged into your existing install. Run `bash migrate-v2.sh` to migrate instead."*
|
||||
3. Wait for the user to confirm before doing anything else. Do not attempt the migration yourself.
|
||||
2. Tell the user, verbatim: *"This is the v2 rewrite — it can't be merged into your existing install. Exit Claude Code (or open a separate terminal) and run `bash migrate-v2.sh` from the shell."*
|
||||
3. Wait for the user to confirm before doing anything else. Do not run the migration script yourself — it requires an interactive terminal and cannot be run from within Claude Code.
|
||||
|
||||
If you are a fresh install (you ran `git clone`, not `git pull`) and there are no conflicts, ignore this banner and continue below.
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
# Run from the v2 directory:
|
||||
# bash migrate-v2.sh
|
||||
#
|
||||
# If you're in Claude Code, exit first or open a separate terminal.
|
||||
#
|
||||
# Finds v1 automatically (sibling directory, or $NANOCLAW_V1_PATH).
|
||||
# Installs prerequisites (Node, pnpm, deps) via the existing setup.sh
|
||||
# bootstrap, then runs the migration steps.
|
||||
@@ -17,6 +19,19 @@ set -uo pipefail
|
||||
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
cd "$PROJECT_ROOT"
|
||||
|
||||
# This script has interactive prompts (channel selection, service switchover)
|
||||
# and streams progress output — it must run in a real terminal, not inside
|
||||
# a tool subprocess (e.g. Claude Code's Bash tool, which collapses output).
|
||||
if ! [ -t 0 ] || ! [ -t 1 ]; then
|
||||
echo "This script requires an interactive terminal."
|
||||
echo ""
|
||||
echo "If you're in Claude Code, exit first or open a separate terminal,"
|
||||
echo "then run:"
|
||||
echo " bash migrate-v2.sh"
|
||||
echo ""
|
||||
exit 1
|
||||
fi
|
||||
|
||||
LOGS_DIR="$PROJECT_ROOT/logs"
|
||||
STEPS_DIR="$LOGS_DIR/migrate-steps"
|
||||
MIGRATE_LOG="$LOGS_DIR/migrate-v2.log"
|
||||
@@ -547,6 +562,26 @@ echo
|
||||
echo "$(bold 'Service switchover')"
|
||||
echo
|
||||
|
||||
# Disable the v1 service so it doesn't auto-start, but leave the unit file
|
||||
# on disk so the user can rollback with: systemctl --user start nanoclaw
|
||||
# Idempotent — safe to call multiple times.
|
||||
disable_v1_service() {
|
||||
if [ "$PLATFORM_SERVICE" = "systemd" ]; then
|
||||
local v1_file="$HOME/.config/systemd/user/${V1_SERVICE}.service"
|
||||
if [ -f "$v1_file" ] || [ -L "$v1_file" ]; then
|
||||
systemctl --user stop "$V1_SERVICE" 2>/dev/null || true
|
||||
systemctl --user disable "$V1_SERVICE" 2>/dev/null || true
|
||||
step_ok "Disabled $V1_SERVICE (unit file kept for rollback)"
|
||||
fi
|
||||
elif [ "$PLATFORM_SERVICE" = "launchd" ]; then
|
||||
local v1_plist="$HOME/Library/LaunchAgents/${V1_SERVICE}.plist"
|
||||
if [ -f "$v1_plist" ] || [ -L "$v1_plist" ]; then
|
||||
launchctl unload "$v1_plist" 2>/dev/null || true
|
||||
step_ok "Unloaded $V1_SERVICE (plist kept for rollback)"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Detect platform and service names
|
||||
V1_SERVICE=""
|
||||
V2_SERVICE=""
|
||||
@@ -635,16 +670,14 @@ if [ "$V1_RUNNING" = "true" ]; then
|
||||
SERVICE_SWITCHED=false
|
||||
else
|
||||
step_ok "Keeping v2 service"
|
||||
# Disable v1 from auto-starting
|
||||
if [ "$PLATFORM_SERVICE" = "systemd" ]; then
|
||||
systemctl --user disable "$V1_SERVICE" 2>/dev/null || true
|
||||
fi
|
||||
disable_v1_service
|
||||
fi
|
||||
else
|
||||
step_skip "Service switchover skipped"
|
||||
fi
|
||||
else
|
||||
step_skip "v1 service not running — nothing to switch"
|
||||
disable_v1_service
|
||||
fi
|
||||
|
||||
echo
|
||||
@@ -676,6 +709,16 @@ echo " $(green '✓') Channels installed: ${SELECTED_CHANNELS[*]}"
|
||||
fi
|
||||
echo " $(green '✓') Container skills copied"
|
||||
echo " $(green '✓') Container image built"
|
||||
if [ "$SERVICE_SWITCHED" = "true" ] && [ -n "$V2_SERVICE" ]; then
|
||||
echo " $(green '✓') Service switched to v2 $(dim "($V2_SERVICE)")"
|
||||
echo
|
||||
echo " $(bold 'Rollback to v1:')"
|
||||
if [ "$PLATFORM_SERVICE" = "systemd" ]; then
|
||||
echo " $(dim '$') systemctl --user stop $V2_SERVICE && systemctl --user start $V1_SERVICE"
|
||||
elif [ "$PLATFORM_SERVICE" = "launchd" ]; then
|
||||
echo " $(dim '$') launchctl unload ~/Library/LaunchAgents/${V2_SERVICE}.plist && launchctl load ~/Library/LaunchAgents/${V1_SERVICE}.plist"
|
||||
fi
|
||||
fi
|
||||
echo
|
||||
echo " $(bold 'What still needs a human:')"
|
||||
if [ "$ONECLI_OK" = "false" ]; then
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
import fs from 'fs';
|
||||
|
||||
import * as p from '@clack/prompts';
|
||||
import { styleText } from 'node:util';
|
||||
|
||||
const CHANNELS = [
|
||||
{ value: 'telegram', label: 'Telegram' },
|
||||
@@ -47,7 +48,7 @@ async function main(): Promise<void> {
|
||||
}
|
||||
|
||||
const selected = await p.multiselect({
|
||||
message: 'Which channels do you want to set up?',
|
||||
message: 'Which channels do you want to set up?\n' + styleText('dim', ' space to select, enter to confirm') + '\n',
|
||||
options: CHANNELS,
|
||||
required: false,
|
||||
});
|
||||
|
||||
@@ -115,9 +115,43 @@ function installOnecliCliOnly(): { stdout: string; ok: boolean } {
|
||||
return { stdout: upstream.stdout + (upstream.stderr ?? '') + '\n' + fallback.stdout, ok: fallback.ok };
|
||||
}
|
||||
|
||||
// Remove containers in the "onecli" compose project whose service name isn't
|
||||
// in the v2 set. Pre-v2 OneCLI used service "app" (container onecli-app-1);
|
||||
// v2 uses "onecli". Compose flags the old container as an orphan but won't
|
||||
// stop it without --remove-orphans, leaving port 10254 bound and crashing
|
||||
// the new bring-up. Filed upstream; this is the downstream workaround.
|
||||
function removeLegacyOnecliContainers(): string {
|
||||
const out: string[] = [];
|
||||
let list = '';
|
||||
try {
|
||||
list = execSync(
|
||||
`docker ps -a --filter "label=com.docker.compose.project=onecli" --format '{{.Names}}|{{.Label "com.docker.compose.service"}}'`,
|
||||
{ encoding: 'utf-8', stdio: ['ignore', 'pipe', 'pipe'] },
|
||||
).trim();
|
||||
} catch {
|
||||
return '';
|
||||
}
|
||||
if (!list) return '';
|
||||
const v2Services = new Set(['onecli', 'postgres']);
|
||||
for (const line of list.split('\n')) {
|
||||
const [name, service] = line.split('|');
|
||||
if (!name || !service || v2Services.has(service)) continue;
|
||||
out.push(`Removing legacy OneCLI container: ${name} (service=${service})`);
|
||||
try {
|
||||
execSync(`docker rm -f ${JSON.stringify(name)}`, { stdio: ['ignore', 'pipe', 'pipe'] });
|
||||
} catch (err) {
|
||||
out.push(` rm failed (continuing): ${(err as Error).message}`);
|
||||
}
|
||||
}
|
||||
return out.join('\n');
|
||||
}
|
||||
|
||||
function installOnecli(): { stdout: string; ok: boolean } {
|
||||
let stdout = '';
|
||||
|
||||
const cleanup = removeLegacyOnecliContainers();
|
||||
if (cleanup) stdout += cleanup + '\n';
|
||||
|
||||
// Gateway install (docker-compose based, no rate-limit concerns).
|
||||
const gw = runInstall('curl -fsSL onecli.sh/install | sh');
|
||||
stdout += gw.stdout;
|
||||
|
||||
@@ -51,6 +51,26 @@ command -v script >/dev/null \
|
||||
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.
|
||||
@@ -58,6 +78,7 @@ 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
|
||||
|
||||
Reference in New Issue
Block a user