#!/usr/bin/env bash # # Manual install script for KernelPilot skills. # Installs LightOp/DCU and Triton/DCU skills directly into Claude and/or Codex # skill directories without requiring the Claude or Codex CLI tools. # # Usage: # ./install-lightop-skills-manual.sh # ./install-lightop-skills-manual.sh --target claude # ./install-lightop-skills-manual.sh --target codex # ./install-lightop-skills-manual.sh --target both # # Optional: # KERNELPILOT_ROOT=/path/to/kernel-pilot ./install-lightop-skills-manual.sh # CLAUDE_SKILLS_DIR=/path/to/skills ./install-lightop-skills-manual.sh --target claude # CODEX_SKILLS_DIR=/path/to/skills ./install-lightop-skills-manual.sh --target codex # PIP_INSTALL_ARGS="--user --disable-pip-version-check" ./install-lightop-skills-manual.sh # set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd)" KERNELPILOT_ROOT="${KERNELPILOT_ROOT:-$SCRIPT_DIR}" TARGET="both" INSTALL_PIP="true" DRY_RUN="false" if [[ -z "${PIP_INSTALL_ARGS+x}" ]]; then PIP_INSTALL_ARGS="--user --disable-pip-version-check" fi CLAUDE_SKILLS_DIR="${CLAUDE_SKILLS_DIR:-${HOME}/.claude/skills}" CODEX_SKILLS_DIR="${CODEX_SKILLS_DIR:-${CODEX_HOME:-${HOME}/.codex}/skills}" # ---- Paths within the KernelPilot checkout ---- KNOWLEDGE_SRC="${KERNELPILOT_ROOT}/knowledge" NCUREPORT_SRC="${KERNELPILOT_ROOT}/humanize/skills/ncu-report" AGENTLOOP_SRC="${KERNELPILOT_ROOT}/humanize/skills/humanize-kernel-agent-loop" TRITON_AGENT_SRC="${KERNELPILOT_ROOT}/humanize/skills/triton-kernel-agent-loop" TRITON_KNOWLEDGE_SRC="${KERNELPILOT_ROOT}/humanize/skills/triton-kernel-knowledge" TRITON_PROFILER_SRC="${KERNELPILOT_ROOT}/humanize/skills/triton-dcu-profiler-report" HUMANIZE_RUNTIME="${KERNELPILOT_ROOT}/humanize" # ---- Skill definitions ---- # Each entry: "name|source_type|source_path|extra" # source_type: "symlink", "hydrate", or "hydrate-dir" SKILLS=( "lightop-kernel-knowledge|symlink|${KNOWLEDGE_SRC}|" "dcu-profiler-report|symlink|${NCUREPORT_SRC}|" "lightop-kernel-agent-loop|hydrate|${AGENTLOOP_SRC}/SKILL.md|${HUMANIZE_RUNTIME}" "triton-kernel-agent-loop|hydrate-dir|${TRITON_AGENT_SRC}|${HUMANIZE_RUNTIME}" "triton-kernel-knowledge|hydrate-dir|${TRITON_KNOWLEDGE_SRC}|${HUMANIZE_RUNTIME}" "triton-dcu-profiler-report|hydrate-dir|${TRITON_PROFILER_SRC}|${HUMANIZE_RUNTIME}" ) usage() { cat <<'EOF' Install KernelPilot skills manually. Usage: install-lightop-skills-manual.sh [options] Options: --target MODE claude|codex|both (default: both) --kernelpilot-root PATH KernelPilot checkout root (default: script dir) --claude-skills-dir PATH Claude skills dir (default: ~/.claude/skills) --codex-skills-dir PATH Codex skills dir (default: ${CODEX_HOME:-~/.codex}/skills) --skip-pip Do not install knowledge/requirements.txt --dry-run Print actions without writing PIP_INSTALL_ARGS Extra args for pip install (default: --user --disable-pip-version-check) -h, --help Show this help EOF } log() { printf '[install-kernelpilot-skills] %s\n' "$*"; } die() { printf '[install-kernelpilot-skills] Error: %s\n' "$*" >&2; exit 1; } resolve_kernelpilot_root() { KERNELPILOT_ROOT="$(cd "$KERNELPILOT_ROOT" 2>/dev/null && pwd || true)" [[ -n "$KERNELPILOT_ROOT" ]] || die "could not resolve KernelPilot root" KNOWLEDGE_SRC="${KERNELPILOT_ROOT}/knowledge" NCUREPORT_SRC="${KERNELPILOT_ROOT}/humanize/skills/ncu-report" AGENTLOOP_SRC="${KERNELPILOT_ROOT}/humanize/skills/humanize-kernel-agent-loop" TRITON_AGENT_SRC="${KERNELPILOT_ROOT}/humanize/skills/triton-kernel-agent-loop" TRITON_KNOWLEDGE_SRC="${KERNELPILOT_ROOT}/humanize/skills/triton-kernel-knowledge" TRITON_PROFILER_SRC="${KERNELPILOT_ROOT}/humanize/skills/triton-dcu-profiler-report" HUMANIZE_RUNTIME="${KERNELPILOT_ROOT}/humanize" SKILLS=( "lightop-kernel-knowledge|symlink|${KNOWLEDGE_SRC}|" "dcu-profiler-report|symlink|${NCUREPORT_SRC}|" "lightop-kernel-agent-loop|hydrate|${AGENTLOOP_SRC}/SKILL.md|${HUMANIZE_RUNTIME}" "triton-kernel-agent-loop|hydrate-dir|${TRITON_AGENT_SRC}|${HUMANIZE_RUNTIME}" "triton-kernel-knowledge|hydrate-dir|${TRITON_KNOWLEDGE_SRC}|${HUMANIZE_RUNTIME}" "triton-dcu-profiler-report|hydrate-dir|${TRITON_PROFILER_SRC}|${HUMANIZE_RUNTIME}" ) } preflight() { local path for path in "$KNOWLEDGE_SRC/SKILL.md" "$NCUREPORT_SRC/SKILL.md" "$AGENTLOOP_SRC/SKILL.md" "$TRITON_AGENT_SRC/SKILL.md" "$TRITON_KNOWLEDGE_SRC/SKILL.md" "$TRITON_PROFILER_SRC/SKILL.md"; do [[ -e "$path" ]] || die "not found: $path" done } hydrate_file() { local file="$1" local runtime="$2" local tmp tmp="${file}.tmp" sed \ "s|{{HUMANIZE_RUNTIME_ROOT}}|${runtime}|g; s|{{KERNELPILOT_ROOT}}|${KERNELPILOT_ROOT}|g" \ "$file" > "$tmp" mv "$tmp" "$file" } install_skill_dir() { local skills_dir="$1" local label="$2" local entry name kind src runtime target log "target: $label" log "skills dir: $skills_dir" if [[ "$DRY_RUN" != "true" ]]; then mkdir -p "$skills_dir" fi for entry in "${SKILLS[@]}"; do IFS='|' read -r name kind src runtime <<< "$entry" target="${skills_dir}/${name}" if [[ "$DRY_RUN" == "true" ]]; then log "DRY-RUN remove existing: ${target}" elif [[ -L "$target" ]] || [[ -d "$target" ]]; then log "removing existing: ${target}" rm -rf "$target" elif [[ -e "$target" ]]; then die "$target exists and is not a symlink or directory" fi case "$kind" in symlink) if [[ "$DRY_RUN" == "true" ]]; then log "DRY-RUN link ${name} -> ${src}" else log "linking ${name} -> ${src}" ln -sf "$src" "$target" fi ;; hydrate) if [[ "$DRY_RUN" == "true" ]]; then log "DRY-RUN create ${name} with hydrated paths" else log "creating ${name} with hydrated paths" mkdir -p "$target" sed \ "s|{{HUMANIZE_RUNTIME_ROOT}}|${runtime}|g; s|{{KERNELPILOT_ROOT}}|${KERNELPILOT_ROOT}|g" \ "$src" > "${target}/SKILL.md" fi ;; hydrate-dir) if [[ "$DRY_RUN" == "true" ]]; then log "DRY-RUN copy ${name} with hydrated paths" else log "copying ${name} with hydrated paths" mkdir -p "$target" cp -a "$src/." "$target/" hydrate_file "${target}/SKILL.md" "$runtime" fi ;; *) die "unknown install kind: ${kind}" ;; esac done } install_python_deps() { if [[ "$INSTALL_PIP" != "true" ]]; then return fi if [[ ! -f "${KNOWLEDGE_SRC}/requirements.txt" ]]; then return fi if [[ "$DRY_RUN" == "true" ]]; then log "DRY-RUN python3 -m pip install ${PIP_INSTALL_ARGS} -r ${KNOWLEDGE_SRC}/requirements.txt" else log "installing Python dependencies..." # Default to user-site installation because skill installs usually run # on shared machines where /usr/local is not writable. python3 -m pip install ${PIP_INSTALL_ARGS} -r "${KNOWLEDGE_SRC}/requirements.txt" fi } while [[ $# -gt 0 ]]; do case "$1" in --target) [[ -n "${2:-}" ]] || die "--target requires a value" case "$2" in claude|codex|both) TARGET="$2" ;; *) die "--target must be one of: claude, codex, both" ;; esac shift 2 ;; --kernelpilot-root) [[ -n "${2:-}" ]] || die "--kernelpilot-root requires a value" KERNELPILOT_ROOT="$2" shift 2 ;; --claude-skills-dir) [[ -n "${2:-}" ]] || die "--claude-skills-dir requires a value" CLAUDE_SKILLS_DIR="$2" shift 2 ;; --codex-skills-dir) [[ -n "${2:-}" ]] || die "--codex-skills-dir requires a value" CODEX_SKILLS_DIR="$2" shift 2 ;; --skip-pip) INSTALL_PIP="false" shift ;; --dry-run) DRY_RUN="true" shift ;; -h|--help) usage exit 0 ;; *) die "unknown option: $1" ;; esac done resolve_kernelpilot_root preflight log "kernelpilot root: $KERNELPILOT_ROOT" log "target mode: $TARGET" case "$TARGET" in claude) install_skill_dir "$CLAUDE_SKILLS_DIR" "claude" ;; codex) install_skill_dir "$CODEX_SKILLS_DIR" "codex" ;; both) install_skill_dir "$CLAUDE_SKILLS_DIR" "claude" install_skill_dir "$CODEX_SKILLS_DIR" "codex" ;; esac install_python_deps cat <