fix: install skill as self-contained bundle, harden installer
- Install entire skill dir (SKILL.md + scripts/ + references/) into ~/.openclaw/skills/ (shared skill location per OpenClaw docs) - Scripts live inside the skill folder, not a separate global dir - Node.js 22 check is now a hard error, not a warning - timeout check is a hard error (required for delegate.sh) - Add --force flag to reinstall npm packages on rerun - Pin npm packages to @latest explicitly - Drop darwin from os metadata (requires GNU coreutils) - Fix set -e killing exit code capture in delegate.sh
This commit is contained in:
parent
caf8a05e04
commit
6fbffd98fa
@ -2,7 +2,7 @@
|
||||
name: claude-codex-delegation
|
||||
description: Delegate code-writing, document generation, and analysis tasks to Claude Code or OpenAI Codex sub-processes. Use when you need to spawn a coding agent for file generation, code modification, script writing, or any multi-step coding task. Triggers on "delegate to claude", "delegate to codex", "use claude code", "use codex", "spawn coding agent", "run delegation", or when a task requires writing/modifying code that should be handed off to a sub-process.
|
||||
metadata:
|
||||
{ "openclaw": { "os": ["linux", "darwin"], "requires": { "anyBins": ["claude", "codex"], "bins": ["bash", "timeout"] } } }
|
||||
{ "openclaw": { "os": ["linux"], "requires": { "anyBins": ["claude", "codex"], "bins": ["bash", "timeout"] } } }
|
||||
---
|
||||
|
||||
# Claude Code + Codex Delegation
|
||||
|
||||
@ -1,33 +1,38 @@
|
||||
#!/usr/bin/env bash
|
||||
# install.sh — Install Claude Code + Codex delegation bundle for OpenClaw.
|
||||
# install.sh - Install Claude Code + Codex delegation bundle for OpenClaw.
|
||||
#
|
||||
# Installs the Claude Code and Codex CLIs, copies delegation scripts
|
||||
# into your OpenClaw workspace, and verifies the setup.
|
||||
# Copies the entire skill directory (SKILL.md, scripts, references) into
|
||||
# OpenClaw's shared skill location so the agent can discover and use it.
|
||||
# Optionally installs the Claude Code and Codex CLIs via npm.
|
||||
#
|
||||
# Usage:
|
||||
# install.sh [options]
|
||||
#
|
||||
# Options:
|
||||
# --skip-npm Skip npm package installation (if already installed)
|
||||
# --scripts-dir DIR Where to install scripts (default: ~/.openclaw/scripts)
|
||||
# --skill-dir DIR Override skill install location
|
||||
# (default: ~/.openclaw/skills/claude-codex-delegation)
|
||||
# --force Reinstall npm packages even if already present
|
||||
# --dry-run Show what would be done without doing it
|
||||
# -h, --help Show this help message
|
||||
#
|
||||
# Requirements:
|
||||
# - Node.js 22+ with npm
|
||||
# - Existing OpenClaw installation
|
||||
# - GNU coreutils (timeout, script) on Linux; macOS needs coreutils via brew
|
||||
# - Claude Max or OpenAI subscription (for subscription-based auth)
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
SCRIPTS_DIR="${HOME}/.openclaw/scripts"
|
||||
SKILL_DIR="${HOME}/.openclaw/skills/claude-codex-delegation"
|
||||
SKIP_NPM=false
|
||||
FORCE=false
|
||||
DRY_RUN=false
|
||||
|
||||
# --- Versions (pin to known-good releases) ---
|
||||
CLAUDE_CODE_PKG="@anthropic-ai/claude-code"
|
||||
CODEX_PKG="@openai/codex"
|
||||
# --- Pinned versions ---
|
||||
CLAUDE_CODE_PKG="@anthropic-ai/claude-code@latest"
|
||||
CODEX_PKG="@openai/codex@latest"
|
||||
|
||||
# --- Colors ---
|
||||
RED='\033[0;31m'
|
||||
@ -42,16 +47,14 @@ error() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
|
||||
# --- Parse arguments ---
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--skip-npm|--scripts-dir|--dry-run)
|
||||
if [[ "$1" == "--scripts-dir" ]]; then
|
||||
if [[ $# -lt 2 ]]; then
|
||||
echo "Error: $1 requires a value" >&2
|
||||
exit 1
|
||||
fi
|
||||
--skill-dir)
|
||||
if [[ $# -lt 2 ]]; then
|
||||
echo "Error: $1 requires a value" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;&
|
||||
SKILL_DIR="$2"; shift 2 ;;
|
||||
--skip-npm) SKIP_NPM=true; shift ;;
|
||||
--scripts-dir) SCRIPTS_DIR="$2"; shift 2 ;;
|
||||
--force) FORCE=true; shift ;;
|
||||
--dry-run) DRY_RUN=true; shift ;;
|
||||
-h|--help)
|
||||
sed -n '2,/^$/p' "$0" | sed 's/^# \?//'
|
||||
@ -70,7 +73,7 @@ run() {
|
||||
}
|
||||
|
||||
echo ""
|
||||
echo "Claude Code + Codex Delegation — Installer"
|
||||
echo "Claude Code + Codex Delegation - Installer"
|
||||
echo "============================================"
|
||||
echo ""
|
||||
|
||||
@ -83,8 +86,11 @@ fi
|
||||
|
||||
NODE_MAJOR="$(node -v | sed 's/^v//' | cut -d. -f1)"
|
||||
if [[ "$NODE_MAJOR" -lt 22 ]]; then
|
||||
warn "Node.js $(node -v) detected. Version 22+ is recommended."
|
||||
error "Node.js $(node -v) detected. Version 22+ is required."
|
||||
echo " Install Node.js 22+: curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -"
|
||||
exit 1
|
||||
fi
|
||||
info "Node.js $(node -v)"
|
||||
|
||||
if ! command -v npm &> /dev/null; then
|
||||
error "npm is not installed."
|
||||
@ -98,12 +104,38 @@ if ! command -v openclaw &> /dev/null; then
|
||||
fi
|
||||
info "OpenClaw detected ($(openclaw --version 2>/dev/null || echo 'unknown version'))"
|
||||
|
||||
# --- Install Claude Code ---
|
||||
# --- Check required system utilities ---
|
||||
echo ""
|
||||
echo "Checking system dependencies..."
|
||||
MISSING=0
|
||||
|
||||
if ! command -v timeout &> /dev/null; then
|
||||
error "'timeout' is required but not found."
|
||||
if [[ "$(uname)" == "Darwin" ]]; then
|
||||
echo " Install with: brew install coreutils"
|
||||
fi
|
||||
((MISSING++))
|
||||
else
|
||||
info "timeout: available"
|
||||
fi
|
||||
|
||||
if command -v tmux &> /dev/null; then
|
||||
info "tmux: available"
|
||||
else
|
||||
warn "tmux: not installed (optional, needed for tmux-session.sh)"
|
||||
fi
|
||||
|
||||
if [[ $MISSING -gt 0 ]]; then
|
||||
error "Missing $MISSING required system dependency. Install it and rerun."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- Install Claude Code and Codex ---
|
||||
if ! $SKIP_NPM; then
|
||||
echo ""
|
||||
echo "Installing Claude Code..."
|
||||
if command -v claude &> /dev/null; then
|
||||
info "Claude Code already installed ($(claude --version 2>/dev/null || echo 'unknown version'))"
|
||||
if command -v claude &> /dev/null && ! $FORCE; then
|
||||
info "Claude Code already installed ($(claude --version 2>/dev/null || echo 'unknown version')). Use --force to reinstall."
|
||||
else
|
||||
run npm install -g "$CLAUDE_CODE_PKG"
|
||||
if ! $DRY_RUN; then
|
||||
@ -113,8 +145,8 @@ if ! $SKIP_NPM; then
|
||||
|
||||
echo ""
|
||||
echo "Installing OpenAI Codex CLI..."
|
||||
if command -v codex &> /dev/null; then
|
||||
info "Codex CLI already installed ($(codex --version 2>/dev/null || echo 'unknown version'))"
|
||||
if command -v codex &> /dev/null && ! $FORCE; then
|
||||
info "Codex CLI already installed ($(codex --version 2>/dev/null || echo 'unknown version')). Use --force to reinstall."
|
||||
else
|
||||
run npm install -g "$CODEX_PKG"
|
||||
if ! $DRY_RUN; then
|
||||
@ -123,35 +155,38 @@ if ! $SKIP_NPM; then
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- Install delegation scripts ---
|
||||
# --- Install skill bundle ---
|
||||
# Copies the entire skill directory (SKILL.md, scripts/, references/) into
|
||||
# OpenClaw's shared skill location (~/.openclaw/skills/) so the agent
|
||||
# discovers it automatically. All resources stay inside the skill folder.
|
||||
echo ""
|
||||
echo "Installing delegation scripts to $SCRIPTS_DIR..."
|
||||
run mkdir -p "$SCRIPTS_DIR"
|
||||
|
||||
for script in delegate.sh tmux-session.sh; do
|
||||
SRC="$SCRIPT_DIR/scripts/$script"
|
||||
DST="$SCRIPTS_DIR/$script"
|
||||
if [[ -f "$SRC" ]]; then
|
||||
run cp "$SRC" "$DST"
|
||||
run chmod +x "$DST"
|
||||
info "Installed $script"
|
||||
else
|
||||
warn "Script not found: $SRC"
|
||||
fi
|
||||
done
|
||||
|
||||
# --- Install skill file ---
|
||||
echo ""
|
||||
echo "Installing skill definition..."
|
||||
SKILL_DIR="${HOME}/.openclaw/workspace/skills/claude-codex-delegation"
|
||||
echo "Installing skill bundle to $SKILL_DIR..."
|
||||
run mkdir -p "$SKILL_DIR/scripts"
|
||||
run mkdir -p "$SKILL_DIR/references"
|
||||
|
||||
# SKILL.md
|
||||
if [[ -f "$SCRIPT_DIR/SKILL.md" ]]; then
|
||||
run cp "$SCRIPT_DIR/SKILL.md" "$SKILL_DIR/SKILL.md"
|
||||
info "Installed SKILL.md"
|
||||
fi
|
||||
|
||||
# Scripts (inside the skill directory, not a global scripts dir)
|
||||
for script in delegate.sh tmux-session.sh; do
|
||||
SRC="$SCRIPT_DIR/scripts/$script"
|
||||
DST="$SKILL_DIR/scripts/$script"
|
||||
if [[ -f "$SRC" ]]; then
|
||||
run cp "$SRC" "$DST"
|
||||
run chmod +x "$DST"
|
||||
info "Installed scripts/$script"
|
||||
else
|
||||
error "Script not found: $SRC"
|
||||
fi
|
||||
done
|
||||
|
||||
# References
|
||||
if [[ -f "$SCRIPT_DIR/references/delegation-policy.md" ]]; then
|
||||
run cp "$SCRIPT_DIR/references/delegation-policy.md" "$SKILL_DIR/references/delegation-policy.md"
|
||||
info "Installed delegation-policy.md"
|
||||
info "Installed references/delegation-policy.md"
|
||||
fi
|
||||
|
||||
# --- Verify ---
|
||||
@ -173,43 +208,36 @@ else
|
||||
((ERRORS++))
|
||||
fi
|
||||
|
||||
if [[ -x "$SCRIPTS_DIR/delegate.sh" ]] || $DRY_RUN; then
|
||||
info "delegate.sh: OK"
|
||||
if [[ -f "$SKILL_DIR/SKILL.md" ]] || $DRY_RUN; then
|
||||
info "SKILL.md: OK"
|
||||
else
|
||||
error "delegate.sh: not found or not executable"
|
||||
error "SKILL.md: not found at $SKILL_DIR"
|
||||
((ERRORS++))
|
||||
fi
|
||||
|
||||
if [[ -x "$SCRIPTS_DIR/tmux-session.sh" ]] || $DRY_RUN; then
|
||||
info "tmux-session.sh: OK"
|
||||
if [[ -x "$SKILL_DIR/scripts/delegate.sh" ]] || $DRY_RUN; then
|
||||
info "scripts/delegate.sh: OK"
|
||||
else
|
||||
error "tmux-session.sh: not found or not executable"
|
||||
error "scripts/delegate.sh: not found or not executable"
|
||||
((ERRORS++))
|
||||
fi
|
||||
|
||||
# --- Optional dependencies ---
|
||||
echo ""
|
||||
if command -v tmux &> /dev/null; then
|
||||
info "tmux: available (for long-running sessions)"
|
||||
if [[ -x "$SKILL_DIR/scripts/tmux-session.sh" ]] || $DRY_RUN; then
|
||||
info "scripts/tmux-session.sh: OK"
|
||||
else
|
||||
warn "tmux: not installed (optional — needed for tmux-session.sh)"
|
||||
fi
|
||||
|
||||
if command -v timeout &> /dev/null; then
|
||||
info "timeout: available"
|
||||
else
|
||||
warn "timeout: not found (needed for delegate.sh)"
|
||||
error "scripts/tmux-session.sh: not found or not executable"
|
||||
((ERRORS++))
|
||||
fi
|
||||
|
||||
# --- Auth check ---
|
||||
echo ""
|
||||
echo "Checking auth..."
|
||||
echo " Claude Code auth: run 'claude auth' to verify subscription/OAuth is configured"
|
||||
echo " Codex auth: run 'codex auth' to verify OpenAI subscription is configured"
|
||||
echo " Claude Code: run 'claude auth' to verify subscription/OAuth is configured"
|
||||
echo " Codex: run 'codex auth' to verify OpenAI subscription is configured"
|
||||
echo ""
|
||||
echo " NOTE: The delegation scripts strip API keys from the sub-process"
|
||||
echo " environment. Both Claude Code and Codex must be configured with"
|
||||
echo " subscription/OAuth auth — API key auth will NOT work."
|
||||
echo " environment. Both CLIs must be configured with subscription/OAuth"
|
||||
echo " auth. API key auth will NOT work."
|
||||
|
||||
# --- Summary ---
|
||||
echo ""
|
||||
@ -217,13 +245,15 @@ if [[ $ERRORS -eq 0 ]]; then
|
||||
echo "============================================"
|
||||
info "Installation complete."
|
||||
echo ""
|
||||
echo " Skill installed to: $SKILL_DIR"
|
||||
echo ""
|
||||
echo " Delegate a task:"
|
||||
echo " $SCRIPTS_DIR/delegate.sh --prompt 'Your task' --workdir ~/project"
|
||||
echo " $SKILL_DIR/scripts/delegate.sh --prompt 'Your task' --workdir ~/project"
|
||||
echo ""
|
||||
echo " Long-running task in tmux:"
|
||||
echo " $SCRIPTS_DIR/tmux-session.sh --name my-task --prompt 'Your task' --workdir ~/project"
|
||||
echo " $SKILL_DIR/scripts/tmux-session.sh --name my-task --prompt 'Your task' --workdir ~/project"
|
||||
echo ""
|
||||
echo " See SKILL.md for full usage and security documentation."
|
||||
echo " OpenClaw will discover the skill automatically on next session."
|
||||
echo "============================================"
|
||||
else
|
||||
error "$ERRORS verification error(s). Check the output above."
|
||||
|
||||
@ -185,11 +185,11 @@ ESCAPED_LOG="$(printf '%q' "$LOG_FILE")"
|
||||
|
||||
if $BACKGROUND; then
|
||||
(
|
||||
EXIT_CODE=0
|
||||
timeout "$TIMEOUT" bash -c "$(declare -f run_delegation build_claude_cmd build_codex_cmd); \
|
||||
AGENT='$AGENT' PROMPT='$(printf '%s' "$PROMPT" | sed "s/'/'\\\\''/g")' \
|
||||
WORKDIR=$ESCAPED_WORKDIR LOG_FILE=$ESCAPED_LOG FULL_AUTO=$FULL_AUTO \
|
||||
run_delegation"
|
||||
EXIT_CODE=$?
|
||||
run_delegation" || EXIT_CODE=$?
|
||||
echo ""
|
||||
echo "--- Delegation complete (exit code: $EXIT_CODE) ---"
|
||||
) >> "$LOG_FILE" 2>&1 &
|
||||
@ -197,11 +197,11 @@ if $BACKGROUND; then
|
||||
echo "Background PID: $BG_PID"
|
||||
echo "Monitor: tail -f $LOG_FILE"
|
||||
else
|
||||
EXIT_CODE=0
|
||||
timeout "$TIMEOUT" bash -c "$(declare -f run_delegation build_claude_cmd build_codex_cmd); \
|
||||
AGENT='$AGENT' PROMPT='$(printf '%s' "$PROMPT" | sed "s/'/'\\\\''/g")' \
|
||||
WORKDIR=$ESCAPED_WORKDIR LOG_FILE=$ESCAPED_LOG FULL_AUTO=$FULL_AUTO \
|
||||
run_delegation"
|
||||
EXIT_CODE=$?
|
||||
run_delegation" || EXIT_CODE=$?
|
||||
if [[ $EXIT_CODE -eq 0 ]]; then
|
||||
echo "Delegation complete."
|
||||
elif [[ $EXIT_CODE -eq 124 ]]; then
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user