feat: add setup skill with scripted steps (#258)

Replace inline SKILL.md instructions with executable shell scripts
for each setup phase (environment check, deps, container, auth,
groups, channels, mounts, service, verify). Scripts emit structured
status blocks for reliable parsing.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
gavrielc
2026-02-16 00:23:49 +02:00
committed by GitHub
parent 5694ac9b87
commit 88140ec1bb
15 changed files with 1883 additions and 667 deletions

View File

@@ -0,0 +1,197 @@
#!/bin/bash
set -euo pipefail
# 08-setup-service.sh — Generate and load service manager config
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../../../.." && pwd)"
LOG_FILE="$PROJECT_ROOT/logs/setup.log"
mkdir -p "$PROJECT_ROOT/logs"
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] [setup-service] $*" >> "$LOG_FILE"; }
cd "$PROJECT_ROOT"
# Parse args
PLATFORM=""
while [[ $# -gt 0 ]]; do
case $1 in
--platform) PLATFORM="$2"; shift 2 ;;
*) shift ;;
esac
done
# Auto-detect platform
if [ -z "$PLATFORM" ]; then
case "$(uname -s)" in
Darwin*) PLATFORM="macos" ;;
Linux*) PLATFORM="linux" ;;
*) PLATFORM="unknown" ;;
esac
fi
NODE_PATH=$(which node)
PROJECT_PATH="$PROJECT_ROOT"
HOME_PATH="$HOME"
log "Setting up service: platform=$PLATFORM node=$NODE_PATH project=$PROJECT_PATH"
# Build first
log "Building TypeScript"
if ! npm run build >> "$LOG_FILE" 2>&1; then
log "Build failed"
cat <<EOF
=== NANOCLAW SETUP: SETUP_SERVICE ===
SERVICE_TYPE: unknown
NODE_PATH: $NODE_PATH
PROJECT_PATH: $PROJECT_PATH
STATUS: failed
ERROR: build_failed
LOG: logs/setup.log
=== END ===
EOF
exit 1
fi
# Create logs directory
mkdir -p "$PROJECT_PATH/logs"
case "$PLATFORM" in
macos)
PLIST_PATH="$HOME_PATH/Library/LaunchAgents/com.nanoclaw.plist"
log "Generating launchd plist at $PLIST_PATH"
mkdir -p "$HOME_PATH/Library/LaunchAgents"
cat > "$PLIST_PATH" <<PLISTEOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.nanoclaw</string>
<key>ProgramArguments</key>
<array>
<string>${NODE_PATH}</string>
<string>${PROJECT_PATH}/dist/index.js</string>
</array>
<key>WorkingDirectory</key>
<string>${PROJECT_PATH}</string>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>EnvironmentVariables</key>
<dict>
<key>PATH</key>
<string>/usr/local/bin:/usr/bin:/bin:${HOME_PATH}/.local/bin</string>
<key>HOME</key>
<string>${HOME_PATH}</string>
</dict>
<key>StandardOutPath</key>
<string>${PROJECT_PATH}/logs/nanoclaw.log</string>
<key>StandardErrorPath</key>
<string>${PROJECT_PATH}/logs/nanoclaw.error.log</string>
</dict>
</plist>
PLISTEOF
log "Loading launchd service"
if launchctl load "$PLIST_PATH" >> "$LOG_FILE" 2>&1; then
log "launchctl load succeeded"
else
log "launchctl load failed (may already be loaded)"
fi
# Verify
SERVICE_LOADED="false"
if launchctl list 2>/dev/null | grep -q "com.nanoclaw"; then
SERVICE_LOADED="true"
log "Service verified as loaded"
else
log "Service not found in launchctl list"
fi
cat <<EOF
=== NANOCLAW SETUP: SETUP_SERVICE ===
SERVICE_TYPE: launchd
NODE_PATH: $NODE_PATH
PROJECT_PATH: $PROJECT_PATH
PLIST_PATH: $PLIST_PATH
SERVICE_LOADED: $SERVICE_LOADED
STATUS: success
LOG: logs/setup.log
=== END ===
EOF
;;
linux)
UNIT_DIR="$HOME_PATH/.config/systemd/user"
UNIT_PATH="$UNIT_DIR/nanoclaw.service"
mkdir -p "$UNIT_DIR"
log "Generating systemd unit at $UNIT_PATH"
cat > "$UNIT_PATH" <<UNITEOF
[Unit]
Description=NanoClaw Personal Assistant
After=network.target
[Service]
Type=simple
ExecStart=${NODE_PATH} ${PROJECT_PATH}/dist/index.js
WorkingDirectory=${PROJECT_PATH}
Restart=always
RestartSec=5
Environment=HOME=${HOME_PATH}
Environment=PATH=/usr/local/bin:/usr/bin:/bin:${HOME_PATH}/.local/bin
StandardOutput=append:${PROJECT_PATH}/logs/nanoclaw.log
StandardError=append:${PROJECT_PATH}/logs/nanoclaw.error.log
[Install]
WantedBy=default.target
UNITEOF
log "Enabling and starting systemd service"
systemctl --user daemon-reload >> "$LOG_FILE" 2>&1 || true
systemctl --user enable nanoclaw >> "$LOG_FILE" 2>&1 || true
systemctl --user start nanoclaw >> "$LOG_FILE" 2>&1 || true
# Verify
SERVICE_LOADED="false"
if systemctl --user is-active nanoclaw >/dev/null 2>&1; then
SERVICE_LOADED="true"
log "Service verified as active"
else
log "Service not active"
fi
cat <<EOF
=== NANOCLAW SETUP: SETUP_SERVICE ===
SERVICE_TYPE: systemd
NODE_PATH: $NODE_PATH
PROJECT_PATH: $PROJECT_PATH
UNIT_PATH: $UNIT_PATH
SERVICE_LOADED: $SERVICE_LOADED
STATUS: success
LOG: logs/setup.log
=== END ===
EOF
;;
*)
log "Unsupported platform: $PLATFORM"
cat <<EOF
=== NANOCLAW SETUP: SETUP_SERVICE ===
SERVICE_TYPE: unknown
NODE_PATH: $NODE_PATH
PROJECT_PATH: $PROJECT_PATH
STATUS: failed
ERROR: unsupported_platform
LOG: logs/setup.log
=== END ===
EOF
exit 1
;;
esac