diff --git a/README.md b/README.md index baeb02a..fa3770c 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,13 @@ curl -fsSL "https://gl.isitsoft.kr/publicproj/install-sh/-/raw/main/install-ctop curl -LsSf https://astral.sh/uv/install.sh | sh ``` +> 설치 후 `${HOME}/.local/bin`이 PATH에 없으면 추가하세요: +> +> ```bash +> echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc +> source ~/.bashrc +> ``` + **pi (Pi Coding Agent + 추천 패키지):** ```bash @@ -92,6 +99,12 @@ powershell -ExecutionPolicy Bypass -c "$t=\"$env:TEMP\install-ctop.ps1\"; iwr -u powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex" ``` +> 설치 후 `$env:USERPROFILE\.local\bin`이 PATH에 없으면 추가하세요: +> +> ```powershell +> [System.Environment]::SetEnvironmentVariable('Path', $env:USERPROFILE + '\.local\bin;' + [System.Environment]::GetEnvironmentVariable('Path', 'User'), 'User') +> ``` + **pi (Pi Coding Agent + 추천 패키지):** ```powershell diff --git a/install-pi.ps1 b/install-pi.ps1 index f1bd100..6f847a4 100644 --- a/install-pi.ps1 +++ b/install-pi.ps1 @@ -97,30 +97,73 @@ if ($piCmd) { Success "Pi installed via npm" } -# Verify pi is available +# ──────────────────────────────────────────── +# Resolve pi binary path (may not be in PATH yet after fresh install) +# ──────────────────────────────────────────── +$piBin = $null + +# 1) Try current PATH $piCmd = Get-Command pi -ErrorAction SilentlyContinue if ($piCmd) { - Success "Pi is available: $($piCmd.Source)" -} else { - # Refresh PATH for current session + $piBin = $piCmd.Source +} + +# 2) Refresh PATH from registry and try again +if (-not $piBin) { $env:Path = [System.Environment]::GetEnvironmentVariable('Path', 'User') + ';' + [System.Environment]::GetEnvironmentVariable('Path', 'Machine') $piCmd = Get-Command pi -ErrorAction SilentlyContinue if ($piCmd) { - Success "Pi is available: $($piCmd.Source)" - } else { - ErrExit "'pi' command not found. Check your PATH." + $piBin = $piCmd.Source } } +# 3) Try common npm global locations +if (-not $piBin) { + $npmPrefix = & npm config get prefix 2>$null + if ($LASTEXITPR -eq 0 -and $npmPrefix) { + $candidate = Join-Path $npmPrefix 'pi.cmd' + if (Test-Path $candidate) { $piBin = $candidate } + if (-not $piBin) { + $candidate = Join-Path $npmPrefix 'pi' + if (Test-Path $candidate) { $piBin = $candidate } + } + } +} + +# 4) Try well-known locations +if (-not $piBin) { + $candidates = @( + (Join-Path $env:APPDATA 'npm\pi.cmd'), + (Join-Path $env:APPDATA 'npm\pi'), + 'C:\Program Files\nodejs\pi.cmd', + 'C:\Program Files\nodejs\pi' + ) + foreach ($c in $candidates) { + if (Test-Path $c) { $piBin = $c; break } + } +} + +if ($piBin) { + # Add pi's directory to PATH for this session + $piDir = Split-Path $piBin + if ($env:Path -notlike "*$piDir*") { + $env:Path = "$piDir;$env:Path" + Info "Added $piDir to PATH for this session" + } + Success "Pi is available: $piBin" +} else { + ErrExit "'pi' command not found after installation. Check your PATH or reinstall Node.js." +} + # ──────────────────────────────────────────── -# Step 2: Install packages +# Step 2: Install packages using the resolved pi binary # ──────────────────────────────────────────── if ($SkipPackages) { Info "Skipping package installation (-SkipPackages flag)." } else { Info "" Info "Installing Pi packages..." - Info "────────────────────────────────────────" + Info "---------------------------------------------------" $total = $Packages.Count $count = 0 @@ -133,7 +176,7 @@ if ($SkipPackages) { Info "[$count/$total] $name - $desc" try { - & pi install "npm:$name" 2>&1 | Out-Null + & $piBin install "npm:$name" 2>&1 | Out-Null if ($LASTEXITPR -eq 0) { Success " -> $name installed" } else { @@ -147,7 +190,7 @@ if ($SkipPackages) { } Info "" - Info "────────────────────────────────────────" + Info "---------------------------------------------------" if ($failed.Count -eq 0) { Success "All packages installed! ($total/$total)" } else { @@ -170,6 +213,15 @@ Info "==================================================" Success "Pi Coding Agent installation complete!" Info "==================================================" Info "" +Info "Pi binary: $piBin" +Info "" +$piDir = Split-Path $piBin +$userPath = [System.Environment]::GetEnvironmentVariable('Path', 'User') +if ($userPath -notlike "*$piDir*") { + Info "NOTE: Add $piDir to your PATH permanently by running:" + Info " [System.Environment]::SetEnvironmentVariable('Path', '$piDir;' + [System.Environment]::GetEnvironmentVariable('Path', 'User'), 'User')" +} +Info "" Info "Getting started:" Info " 1. Navigate to your project: cd C:\path\to\project" Info " 2. Start Pi: pi" diff --git a/install-pi.sh b/install-pi.sh index bab8321..dabeb95 100755 --- a/install-pi.sh +++ b/install-pi.sh @@ -23,36 +23,39 @@ PI_NPM_PACKAGE="@earendil-works/pi-coding-agent" # Packages to install after pi is available # Format: "package_name|description" PACKAGES=( - "pi-subagents|Delegate work to focused child agents — code review, scouting, implementation, parallel audits, orchestration, background jobs" - "context-mode|Context window protection — sandbox tools, session continuity, BM25 knowledge base, think-in-code paradigm" - "pi-mcp-adapter|Use MCP servers with Pi without burning your context window — one proxy tool instead of hundreds" - "pi-web-access|Web search, content extraction, and video understanding — zero-config Exa search, Perplexity, Gemini, YouTube" - "@plannotator/pi-extension|File-based plan mode with visual browser UI for reviewing, annotating, and approving agent plans" - "@juicesharp/rpiv-ask-user-question|Structured questionnaire tool with typed options — the model asks you instead of guessing" - "pi-lens|Real-time code feedback — LSP diagnostics, linters, formatters, type-checking, structural analysis, read-before-edit guard" - "@juicesharp/rpiv-todo|Persistent todo list across sessions — tasks survive /reload and compaction with dependency tracking" - "pi-simplify|Review recently changed code for clarity, consistency, and maintainability improvements" - "@juicesharp/rpiv-advisor|Second opinion from a stronger reviewer model before the agent acts" - "@juicesharp/rpiv-pi|Skill-based development workflow — discover, research, design, plan, implement, validate pipeline with named subagents" - "@samfp/pi-memory|Persistent memory for Pi — learns corrections, preferences, and project patterns across sessions" - "pi-btw|Parallel side conversations (/btw) without interrupting the main agent run" - "pi-docparser|Document parsing tool — PDFs, Office docs, spreadsheets, images, and OCR via LiteParse" - "pi-ollama-cloud|Ollama Cloud provider plugin — dynamic model discovery, web search and fetch tools, no local server required" + "pi-subagents|Delegate work to focused child agents — code review, scouting, implementation, parallel audits, orchestration, background jobs" + "context-mode|Context window protection — sandbox tools, session continuity, BM25 knowledge base, think-in-code paradigm" + "pi-mcp-adapter|Use MCP servers with Pi without burning your context window — one proxy tool instead of hundreds" + "pi-web-access|Web search, content extraction, and video understanding — zero-config Exa search, Perplexity, Gemini, YouTube" + "@plannotator/pi-extension|File-based plan mode with visual browser UI for reviewing, annotating, and approving agent plans" + "@juicesharp/rpiv-ask-user-question|Structured questionnaire tool with typed options — the model asks you instead of guessing" + "pi-lens|Real-time code feedback — LSP diagnostics, linters, formatters, type-checking, structural analysis, read-before-edit guard" + "@juicesharp/rpiv-todo|Persistent todo list across sessions — tasks survive /reload and compaction with dependency tracking" + "pi-simplify|Review recently changed code for clarity, consistency, and maintainability improvements" + "@juicesharp/rpiv-advisor|Second opinion from a stronger reviewer model before the agent acts" + "@juicesharp/rpiv-pi|Skill-based development workflow — discover, research, design, plan, implement, validate pipeline with named subagents" + "@samfp/pi-memory|Persistent memory for Pi — learns corrections, preferences, and project patterns across sessions" + "pi-btw|Parallel side conversations (/btw) without interrupting the main agent run" + "pi-docparser|Document parsing tool — PDFs, Office docs, spreadsheets, images, and OCR via LiteParse" + "pi-ollama-cloud|Ollama Cloud provider plugin — dynamic model discovery, web search and fetch tools, no local server required" ) # ──────────────────────────────────────────── # Utility functions (all stderr output) # ──────────────────────────────────────────── -info() { echo "[INFO] $*" >&2; } -warn() { echo "[WARN] $*" >&2; } -error() { echo "[ERROR] $*" >&2; exit 1; } +info() { echo "[INFO] $*" >&2; } +warn() { echo "[WARN] $*" >&2; } +error() { + echo "[ERROR] $*" >&2 + exit 1 +} success() { echo "[OK] $*" >&2; } # ──────────────────────────────────────────── # Check required commands # ──────────────────────────────────────────── for cmd in curl; do - command -v "$cmd" &>/dev/null || error "'$cmd' is required." + command -v "$cmd" &>/dev/null || error "'$cmd' is required." done # ──────────────────────────────────────────── @@ -62,10 +65,10 @@ OS="$(uname -s)" ARCH="$(uname -m)" case "$OS" in - Darwin|Linux) ;; - *) - error "Unsupported OS: $OS. This script only supports macOS and Linux." - ;; +Darwin | Linux) ;; +*) + error "Unsupported OS: $OS. This script only supports macOS and Linux." + ;; esac info "Platform: $OS ($ARCH)" @@ -76,36 +79,71 @@ info "Platform: $OS ($ARCH)" info "Installing Pi Coding Agent..." if command -v pi &>/dev/null; then - CURRENT_VER="$(pi --version 2>/dev/null || echo 'unknown')" - info "Pi is already installed (version: $CURRENT_VER). Skipping installation." + CURRENT_VER="$(pi --version 2>/dev/null || echo 'unknown')" + info "Pi is already installed (version: $CURRENT_VER). Skipping installation." else - # Try curl-based installer first - if curl -fsSL "$PI_INSTALL_URL" 2>/dev/null | sh; then - success "Pi installed via curl installer" - else - # Fallback to npm - info "curl install failed. Falling back to npm..." - command -v npm &>/dev/null || error "npm is required. Install Node.js 18+: https://nodejs.org/" - npm install -g "$PI_NPM_PACKAGE" - success "Pi installed via npm" - fi -fi - -# Verify pi is available (may need to re-hash PATH) -if command -v pi &>/dev/null; then - success "Pi is available: $(command -v pi)" -else - # Try common locations - export PATH="$HOME/.local/bin:$HOME/.npm/bin:$HOME/.nvm/versions/node/$(ls "$HOME/.nvm/versions/node/" 2>/dev/null | tail -1)/bin:$PATH" - if command -v pi &>/dev/null; then - success "Pi is available: $(command -v pi)" - else - error "'pi' command not found. Check your PATH." - fi + # Try curl-based installer first + if curl -fsSL "$PI_INSTALL_URL" 2>/dev/null | sh; then + success "Pi installed via curl installer" + else + # Fallback to npm + info "curl install failed. Falling back to npm..." + command -v npm &>/dev/null || error "npm is required. Install Node.js 18+: https://nodejs.org/" + npm install -g "$PI_NPM_PACKAGE" + success "Pi installed via npm" + fi fi # ──────────────────────────────────────────── -# Step 2: Install packages +# Resolve pi binary path (may not be in PATH yet after fresh install) +# ──────────────────────────────────────────── +PI_BIN="" + +# 1) Try current PATH +if command -v pi &>/dev/null; then + PI_BIN="$(command -v pi)" +fi + +# 2) Try expanding common locations where npm/pip install globally +if [ -z "$PI_BIN" ]; then + for candidate in \ + "$HOME/.local/bin/pi" \ + "$HOME/.npm/bin/pi" \ + "/usr/local/bin/pi" \ + "$HOME/.nvm/versions/node/$(ls "$HOME/.nvm/versions/node/" 2>/dev/null | tail -1)/bin/pi" \ + "$NVM_DIR/versions/node/$(ls "$NVM_DIR/versions/node/" 2>/dev/null | tail -1)/bin/pi"; do + if [ -x "$candidate" ]; then + PI_BIN="$candidate" + break + fi + done +fi + +# 3) Try npm prefix to locate the global bin +if [ -z "$PI_BIN" ] && command -v npm &>/dev/null; then + NPM_PREFIX="$(npm config get prefix 2>/dev/null || true)" + if [ -n "$NPM_PREFIX" ] && [ -x "$NPM_PREFIX/bin/pi" ]; then + PI_BIN="$NPM_PREFIX/bin/pi" + fi +fi + +# Add pi's directory to PATH for this session so pi install subprocess works +if [ -n "$PI_BIN" ]; then + PI_DIR="$(dirname "$PI_BIN")" + case ":$PATH:" in + *":$PI_DIR:"*) ;; # already in PATH + *) + export PATH="$PI_DIR:$PATH" + info "Added $PI_DIR to PATH for this session" + ;; + esac + success "Pi is available: $PI_BIN" +else + error "'pi' command not found. Check your PATH or reinstall Node.js." +fi + +# ──────────────────────────────────────────── +# Step 2: Install packages using the resolved pi binary # ──────────────────────────────────────────── info "" info "Installing Pi packages..." @@ -116,32 +154,32 @@ COUNT=0 FAILED=() for entry in "${PACKAGES[@]}"; do - PKG="${entry%%|*}" - DESC="${entry#*|}" - COUNT=$((COUNT + 1)) + PKG="${entry%%|*}" + DESC="${entry#*|}" + COUNT=$((COUNT + 1)) - info "[$COUNT/$TOTAL] $PKG — $DESC" - if pi install "npm:$PKG" 2>&1; then - success " → $PKG installed" - else - warn " → $PKG failed (install manually later: pi install npm:$PKG)" - FAILED+=("$PKG") - fi + info "[$COUNT/$TOTAL] $PKG — $DESC" + if "$PI_BIN" install "npm:$PKG" 2>&1; then + success " → $PKG installed" + else + warn " → $PKG failed (install manually later: pi install npm:$PKG)" + FAILED+=("$PKG") + fi done info "" info "────────────────────────────────────────" if [ ${#FAILED[@]} -eq 0 ]; then - success "All packages installed! ($TOTAL/$TOTAL)" + success "All packages installed! ($TOTAL/$TOTAL)" else - warn "Some packages failed to install:" - for pkg in "${FAILED[@]}"; do - warn " - $pkg" - done - info "You can install failed packages manually with:" - for pkg in "${FAILED[@]}"; do - info " pi install npm:$pkg" - done + warn "Some packages failed to install:" + for pkg in "${FAILED[@]}"; do + warn " - $pkg" + done + info "You can install failed packages manually with:" + for pkg in "${FAILED[@]}"; do + info " pi install npm:$pkg" + done fi # ──────────────────────────────────────────── @@ -152,6 +190,23 @@ info "════════════════════════ success "Pi Coding Agent installation complete!" info "══════════════════════════════════════════" info "" +info "Pi binary: $PI_BIN" +info "" +if [ -n "$PI_DIR" ]; then + case ":$PATH:" in + *":$PI_DIR:"*) ;; + *) + SHELL_RC="" + if [ -f "$HOME/.bashrc" ]; then SHELL_RC="$HOME/.bashrc"; elif [ -f "$HOME/.zshrc" ]; then SHELL_RC="$HOME/.zshrc"; fi + if [ -n "$SHELL_RC" ]; then + info "NOTE: Add $PI_DIR to your PATH permanently by running:" + info " echo 'export PATH=\"$PI_DIR:\$PATH\"' >> $SHELL_RC" + info " source $SHELL_RC" + fi + ;; + esac +fi +info "" info "Getting started:" info " 1. Navigate to your project: cd /path/to/project" info " 2. Start Pi: pi" @@ -167,4 +222,4 @@ info " pi list — Show installed packages" info "" info "For Ollama Cloud:" info " Set your API key in ~/.pi/agent/auth.json" -info " See: https://pi.dev/packages/pi-ollama-cloud" \ No newline at end of file +info " See: https://pi.dev/packages/pi-ollama-cloud"