Files
claude/scripts/run.sh
2026-02-02 22:43:15 +01:00

176 lines
5.0 KiB
Bash

#!/bin/bash
set -e
SKILL_DIR="$(dirname "$(dirname "$0")")"
CLAUDE_PORT="${CLAUDE_PORT:-8888}"
CLAUDE_MODEL="${CLAUDE_MODEL:-claude-sonnet-4-20250514}"
CLAUDE_MAX_TURNS="${CLAUDE_MAX_TURNS:-10}"
SKILLS_DIR="${SKILLS_DIR:-/skills}"
SYSTEM_PROMPT_FILE="$SKILL_DIR/prompts/system.md"
# Create HTTP handler
create_handler() {
cat > /tmp/claude_handler.sh << 'HANDLER'
#!/bin/bash
SKILL_DIR="${SKILL_DIR}"
CLAUDE_MODEL="${CLAUDE_MODEL:-claude-sonnet-4-20250514}"
CLAUDE_MAX_TURNS="${CLAUDE_MAX_TURNS:-10}"
SKILLS_DIR="${SKILLS_DIR:-/skills}"
SYSTEM_PROMPT_FILE="${SYSTEM_PROMPT_FILE}"
# Read HTTP request
read -r request_line
method=$(echo "$request_line" | cut -d' ' -f1)
path=$(echo "$request_line" | cut -d' ' -f2)
# Read headers
content_length=0
while read -r header; do
header=$(echo "$header" | tr -d '\r')
[ -z "$header" ] && break
if [[ "$header" =~ ^[Cc]ontent-[Ll]ength:\ *([0-9]+) ]]; then
content_length="${BASH_REMATCH[1]}"
fi
done
# Read body
body=""
if [ "$content_length" -gt 0 ]; then
body=$(head -c "$content_length")
fi
# Response helper
send_response() {
local status="$1"
local content_type="$2"
local body="$3"
local body_length=${#body}
printf "HTTP/1.1 %s\r\n" "$status"
printf "Content-Type: %s\r\n" "$content_type"
printf "Content-Length: %d\r\n" "$body_length"
printf "Connection: close\r\n"
printf "\r\n"
printf "%s" "$body"
}
# Health check
if [ "$path" = "/health" ]; then
if command -v claude &>/dev/null; then
send_response "200 OK" "application/json" '{"status":"ok","claude":"available"}'
else
send_response "503 Service Unavailable" "application/json" '{"status":"error","claude":"not found"}'
fi
exit 0
fi
# Execute endpoint (one-shot)
if [ "$path" = "/execute" ] && [ "$method" = "POST" ]; then
prompt=$(echo "$body" | jq -r '.prompt // empty')
if [ -z "$prompt" ]; then
send_response "400 Bad Request" "application/json" '{"error":"Missing prompt field"}'
exit 0
fi
# Build claude command
cd "$SKILLS_DIR"
# Run claude with system prompt
result=$(claude --print \
--model "$CLAUDE_MODEL" \
--max-turns "$CLAUDE_MAX_TURNS" \
--system-prompt "$(cat "$SYSTEM_PROMPT_FILE")" \
--allowedTools "Bash,Read,Write,Edit,Glob,Grep" \
"$prompt" 2>&1) || {
error_msg=$(echo "$result" | jq -Rs '.')
send_response "500 Internal Server Error" "application/json" "{\"success\":false,\"error\":$error_msg}"
exit 0
}
# Return result
result_json=$(echo "$result" | jq -Rs '.')
send_response "200 OK" "application/json" "{\"success\":true,\"result\":$result_json}"
exit 0
fi
# Chat endpoint (simplified, non-streaming for now)
if [ "$path" = "/chat" ] && [ "$method" = "POST" ]; then
message=$(echo "$body" | jq -r '.message // empty')
session_id=$(echo "$body" | jq -r '.session_id // empty')
if [ -z "$message" ]; then
send_response "400 Bad Request" "application/json" '{"error":"Missing message field"}'
exit 0
fi
cd "$SKILLS_DIR"
# Build command
claude_args=(
"--print"
"--model" "$CLAUDE_MODEL"
"--max-turns" "1"
"--system-prompt" "$(cat "$SYSTEM_PROMPT_FILE")"
"--allowedTools" "Bash,Read,Write,Edit,Glob,Grep"
)
# Resume session if provided
if [ -n "$session_id" ]; then
claude_args+=("--resume" "$session_id")
fi
result=$(claude "${claude_args[@]}" "$message" 2>&1) || {
error_msg=$(echo "$result" | jq -Rs '.')
send_response "500 Internal Server Error" "application/json" "{\"success\":false,\"error\":$error_msg}"
exit 0
}
result_json=$(echo "$result" | jq -Rs '.')
send_response "200 OK" "application/json" "{\"success\":true,\"response\":$result_json}"
exit 0
fi
# Skills list
if [ "$path" = "/skills" ] && [ "$method" = "GET" ]; then
skills="[]"
for skill_dir in "$SKILLS_DIR"/*/; do
skill_name=$(basename "$skill_dir")
skill_md="$skill_dir/SKILL.md"
if [ -f "$skill_md" ]; then
desc=$(yq -r '.description // "No description"' < <(sed -n '/^---$/,/^---$/p' "$skill_md" | sed '1d;$d') 2>/dev/null || echo "")
skills=$(echo "$skills" | jq --arg name "$skill_name" --arg desc "$desc" '. + [{"name":$name,"description":$desc}]')
fi
done
send_response "200 OK" "application/json" "$skills"
exit 0
fi
# Not found
send_response "404 Not Found" "application/json" '{"error":"Endpoints: POST /execute, POST /chat, GET /skills, GET /health"}'
HANDLER
chmod +x /tmp/claude_handler.sh
# Export vars for handler
export SKILL_DIR
export CLAUDE_MODEL
export CLAUDE_MAX_TURNS
export SKILLS_DIR
export SYSTEM_PROMPT_FILE
}
# Serve HTTP API
serve_api() {
echo "Starting Claude HTTP API on port $CLAUDE_PORT..."
echo "Model: $CLAUDE_MODEL"
echo "Max turns: $CLAUDE_MAX_TURNS"
echo "Working directory: $SKILLS_DIR"
exec socat TCP-LISTEN:$CLAUDE_PORT,reuseaddr,fork EXEC:"/tmp/claude_handler.sh"
}
create_handler
serve_api