From 8b4b3816f178bb038de88b4beab835b0d357e9dc Mon Sep 17 00:00:00 2001 From: toukanno Date: Mon, 23 Mar 2026 21:57:27 +0900 Subject: [PATCH] feat: dynamic tool detection, Windows support, cursor docs, cross-platform commands - install.sh: add resolve_tool_path() for dynamic binary detection via command -v / which, store and display resolved paths in tool labels - install.sh: add platform detection (linux/macos/wsl/windows-gitbash) with WSL/Git Bash warnings and install.ps1 guidance - scripts/install.ps1: add PowerShell install script for Windows-native support (claude-code, copilot, cursor, aider, windsurf) - integrations/cursor/README.md: align with standard integration README format, add Rule Format section with frontmatter documentation - engineering agents (devops-automator, security-engineer, sre, git-workflow-master): add cross-platform command reference tables with Linux/macOS/Windows equivalents Closes #205, Closes #179, Closes #229, Closes #153 Co-Authored-By: Claude Opus 4.6 (1M context) --- engineering/engineering-devops-automator.md | 17 ++ .../engineering-git-workflow-master.md | 14 ++ engineering/engineering-security-engineer.md | 17 ++ engineering/engineering-sre.md | 17 ++ integrations/cursor/README.md | 28 ++- scripts/install.ps1 | 225 ++++++++++++++++++ scripts/install.sh | 158 ++++++++++-- 7 files changed, 456 insertions(+), 20 deletions(-) create mode 100644 scripts/install.ps1 diff --git a/engineering/engineering-devops-automator.md b/engineering/engineering-devops-automator.md index a9e7cac0..de3cc294 100644 --- a/engineering/engineering-devops-automator.md +++ b/engineering/engineering-devops-automator.md @@ -371,6 +371,23 @@ You're successful when: - Predictive alerting using machine learning algorithms - Comprehensive compliance and audit automation +## 🖥️ Cross-Platform Command Reference + +When providing CLI commands, be aware of platform differences and offer alternatives: + +| Task | Linux/Bash | macOS | Windows (PowerShell) | +|------|-----------|-------|---------------------| +| List processes | `ps aux` | `ps aux` | `Get-Process` | +| Kill process | `kill -9 ` | `kill -9 ` | `Stop-Process -Id -Force` | +| Check open ports | `ss -tlnp` / `netstat -tlnp` | `lsof -i -P` | `Get-NetTCPConnection` | +| Service management | `systemctl start/stop/status` | `launchctl load/unload` | `Start-Service / Stop-Service` | +| Environment vars | `export VAR=val` | `export VAR=val` | `$env:VAR = "val"` | +| File permissions | `chmod 755 file` | `chmod 755 file` | `icacls file /grant Users:F` | +| Package manager | `apt-get` / `yum` | `brew` | `winget` / `choco` | +| Resource usage | `top` / `htop` | `top` / `htop` | `Get-Process \| Sort-Object CPU` | + +> **Note**: Docker and Kubernetes CLI commands (`docker`, `kubectl`, `helm`) are cross-platform and work identically on all OS platforms. + --- **Instructions Reference**: Your detailed DevOps methodology is in your core training - refer to comprehensive infrastructure patterns, deployment strategies, and monitoring frameworks for complete guidance. \ No newline at end of file diff --git a/engineering/engineering-git-workflow-master.md b/engineering/engineering-git-workflow-master.md index d00b608b..974f2dc2 100644 --- a/engineering/engineering-git-workflow-master.md +++ b/engineering/engineering-git-workflow-master.md @@ -82,3 +82,17 @@ git push origin --delete feat/my-feature - Always show the safe version of dangerous commands - Warn about destructive operations before suggesting them - Provide recovery steps alongside risky operations + +## 🖥️ Cross-Platform Notes + +Git CLI commands are cross-platform, but shell helpers differ: + +| Task | Linux/macOS (Bash/Zsh) | Windows (PowerShell) | +|------|----------------------|---------------------| +| Set env var for command | `GIT_AUTHOR_DATE="..." git commit` | `$env:GIT_AUTHOR_DATE="..."; git commit` | +| Find files in repo | `find . -name "*.js"` | `Get-ChildItem -Recurse -Filter "*.js"` | +| Pipe grep on log | `git log --oneline \| grep fix` | `git log --oneline \| Select-String fix` | +| Edit global config | `git config --global -e` (opens `$EDITOR`) | `git config --global -e` (opens default editor) | +| Line ending config | `git config core.autocrlf input` | `git config core.autocrlf true` | + +> **Tip**: Always set `core.autocrlf` appropriately for your OS. Use `.gitattributes` for project-wide line ending rules. diff --git a/engineering/engineering-security-engineer.md b/engineering/engineering-security-engineer.md index 4b24d283..dbfa82c0 100644 --- a/engineering/engineering-security-engineer.md +++ b/engineering/engineering-security-engineer.md @@ -272,6 +272,23 @@ You're successful when: - Post-incident remediation and hardening recommendations - Breach impact assessment and containment strategies +## 🖥️ Cross-Platform Command Reference + +When providing security commands, be aware of platform differences: + +| Task | Linux/Bash | macOS | Windows (PowerShell) | +|------|-----------|-------|---------------------| +| Check open ports | `ss -tlnp` / `netstat -tlnp` | `lsof -i -P -n` | `Get-NetTCPConnection` | +| View active connections | `netstat -an` | `netstat -an` | `Get-NetTCPConnection -State Established` | +| Firewall rules | `iptables -L` / `ufw status` | `pfctl -sr` | `Get-NetFirewallRule` | +| File hash (SHA256) | `sha256sum file` | `shasum -a 256 file` | `Get-FileHash file -Algorithm SHA256` | +| Find SUID files | `find / -perm -4000` | `find / -perm -4000` | N/A (use `icacls` for ACL audit) | +| User audit | `cat /etc/passwd` | `dscl . -list /Users` | `Get-LocalUser` | +| Log review | `journalctl -u service` | `log show --predicate ...` | `Get-EventLog -LogName Security` | +| Certificate check | `openssl s_client -connect` | `openssl s_client -connect` | `Test-NetConnection` / `certutil` | + +> **Note**: Tools like `nmap`, `nikto`, `trivy`, and `semgrep` are cross-platform and work the same on all OS platforms. + --- **Instructions Reference**: Your detailed security methodology is in your core training — refer to comprehensive threat modeling frameworks, vulnerability assessment techniques, and security architecture patterns for complete guidance. diff --git a/engineering/engineering-sre.md b/engineering/engineering-sre.md index 592c7ab9..6a03e89d 100644 --- a/engineering/engineering-sre.md +++ b/engineering/engineering-sre.md @@ -88,3 +88,20 @@ slos: - Frame reliability as investment: "This automation saves 4 hours/week of toil" - Use risk language: "This deployment has a 15% chance of exceeding our latency SLO" - Be direct about trade-offs: "We can ship this feature, but we'll need to defer the migration" + +## 🖥️ Cross-Platform Command Reference + +When providing diagnostic or operational commands, offer platform-appropriate alternatives: + +| Task | Linux/Bash | macOS | Windows (PowerShell) | +|------|-----------|-------|---------------------| +| CPU/memory usage | `top` / `htop` | `top` / `htop` | `Get-Process \| Sort-Object CPU -Desc` | +| Disk usage | `df -h` | `df -h` | `Get-PSDrive -PSProvider FileSystem` | +| Process tree | `pstree` / `ps auxf` | `pstree` (brew) | `Get-CimInstance Win32_Process` | +| Network diagnostics | `ss -tlnp` | `lsof -i -P` | `Get-NetTCPConnection` | +| DNS lookup | `dig` / `nslookup` | `dig` / `nslookup` | `Resolve-DnsName` | +| Service logs | `journalctl -u svc` | `log show --predicate` | `Get-EventLog` / `Get-WinEvent` | +| Cron/scheduled tasks | `crontab -l` | `crontab -l` | `Get-ScheduledTask` | +| Resource limits | `ulimit -a` | `ulimit -a` / `launchctl limit` | N/A (use Group Policy) | + +> **Note**: Container and orchestration CLIs (`docker`, `kubectl`, `helm`, `terraform`) work identically across all platforms. diff --git a/integrations/cursor/README.md b/integrations/cursor/README.md index 679e3f96..6194a606 100644 --- a/integrations/cursor/README.md +++ b/integrations/cursor/README.md @@ -1,7 +1,8 @@ # Cursor Integration -Converts all 61 Agency agents into Cursor `.mdc` rule files. Rules are -**project-scoped** — install them from your project root. +Converts all Agency agents into Cursor `.mdc` rule files following the +[standard Cursor rules format](https://docs.cursor.com/context/rules). +Rules are **project-scoped** -- install them from your project root. ## Install @@ -31,8 +32,31 @@ alwaysApply: true --- ``` +## Rule Format + +Each generated `.mdc` file follows the standard Cursor rule format with +YAML frontmatter: + +```yaml +--- +description: Expert frontend developer specializing in modern web technologies... +globs: "" +alwaysApply: false +--- +``` + +- **description** -- shown in the Cursor rule picker to help identify the agent +- **globs** -- file patterns that auto-activate the rule (empty = manual activation) +- **alwaysApply** -- set to `true` to apply the rule to every conversation + +After installing, customize `globs` and `alwaysApply` per-agent to match +your project needs. For example, set the Frontend Developer rule to activate +on `**/*.tsx,**/*.ts` files. + ## Regenerate +After modifying agents, regenerate the rule files: + ```bash ./scripts/convert.sh --tool cursor ``` diff --git a/scripts/install.ps1 b/scripts/install.ps1 new file mode 100644 index 00000000..aea35a1f --- /dev/null +++ b/scripts/install.ps1 @@ -0,0 +1,225 @@ +#Requires -Version 5.1 +<# +.SYNOPSIS + Install The Agency agents into your local agentic tool(s) on Windows. + +.DESCRIPTION + Windows-native counterpart of install.sh. Reads converted files from + integrations/ and copies them to the appropriate config directory for each + tool. Run scripts/convert.sh (via WSL or Git Bash) first if integrations/ + is missing or stale. + +.PARAMETER Tool + Install only the specified tool. Valid values: + claude-code, copilot, antigravity, gemini-cli, opencode, openclaw, + cursor, aider, windsurf, qwen, all (default). + +.PARAMETER Help + Show this help message. + +.EXAMPLE + .\scripts\install.ps1 + .\scripts\install.ps1 -Tool claude-code + .\scripts\install.ps1 -Tool cursor +#> + +[CmdletBinding()] +param( + [ValidateSet('claude-code','copilot','antigravity','gemini-cli','opencode', + 'openclaw','cursor','aider','windsurf','qwen','all')] + [string]$Tool = 'all', + + [switch]$Help +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +# --------------------------------------------------------------------------- +# Paths +# --------------------------------------------------------------------------- +$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path +$RepoRoot = Split-Path -Parent $ScriptDir +$Integrations = Join-Path $RepoRoot 'integrations' + +$AllTools = @( + 'claude-code','copilot','antigravity','gemini-cli','opencode', + 'openclaw','cursor','aider','windsurf','qwen' +) + +# --------------------------------------------------------------------------- +# Helpers +# --------------------------------------------------------------------------- +function Write-Ok { param([string]$Msg) Write-Host "[OK] $Msg" -ForegroundColor Green } +function Write-Warn { param([string]$Msg) Write-Host "[!!] $Msg" -ForegroundColor Yellow } +function Write-Err { param([string]$Msg) Write-Host "[ERR] $Msg" -ForegroundColor Red } +function Write-Header { param([string]$Msg) Write-Host "`n$Msg" -ForegroundColor White -NoNewline; Write-Host "" } + +function Resolve-ToolPath { + param([string]$Binary) + $cmd = Get-Command $Binary -ErrorAction SilentlyContinue + if ($cmd) { return $cmd.Source } + return $null +} + +# --------------------------------------------------------------------------- +# Tool detection +# --------------------------------------------------------------------------- +function Test-ToolDetected { + param([string]$ToolName) + switch ($ToolName) { + 'claude-code' { return ((Resolve-ToolPath 'claude') -or (Test-Path "$env:USERPROFILE\.claude")) } + 'copilot' { return ((Resolve-ToolPath 'code') -or (Test-Path "$env:USERPROFILE\.github") -or (Test-Path "$env:USERPROFILE\.copilot")) } + 'antigravity' { return (Test-Path "$env:USERPROFILE\.gemini\antigravity\skills") } + 'gemini-cli' { return ((Resolve-ToolPath 'gemini') -or (Test-Path "$env:USERPROFILE\.gemini")) } + 'cursor' { return ((Resolve-ToolPath 'cursor') -or (Test-Path "$env:USERPROFILE\.cursor")) } + 'opencode' { return ((Resolve-ToolPath 'opencode') -or (Test-Path "$env:USERPROFILE\.config\opencode")) } + 'aider' { return [bool](Resolve-ToolPath 'aider') } + 'openclaw' { return ((Resolve-ToolPath 'openclaw') -or (Test-Path "$env:USERPROFILE\.openclaw")) } + 'windsurf' { return ((Resolve-ToolPath 'windsurf') -or (Test-Path "$env:USERPROFILE\.codeium")) } + 'qwen' { return ((Resolve-ToolPath 'qwen') -or (Test-Path "$env:USERPROFILE\.qwen")) } + default { return $false } + } +} + +# --------------------------------------------------------------------------- +# Installers +# --------------------------------------------------------------------------- +function Install-ClaudeCode { + $dest = Join-Path $env:USERPROFILE '.claude\agents' + New-Item -ItemType Directory -Path $dest -Force | Out-Null + $count = 0 + $agentDirs = @('academic','design','engineering','game-development','marketing', + 'paid-media','sales','product','project-management','testing', + 'support','spatial-computing','specialized') + foreach ($dir in $agentDirs) { + $dirPath = Join-Path $RepoRoot $dir + if (-not (Test-Path $dirPath)) { continue } + Get-ChildItem -Path $dirPath -Filter '*.md' -File | ForEach-Object { + $firstLine = Get-Content $_.FullName -TotalCount 1 + if ($firstLine -eq '---') { + Copy-Item $_.FullName -Destination $dest -Force + $count++ + } + } + } + Write-Ok "Claude Code: $count agents -> $dest" +} + +function Install-Copilot { + $destGH = Join-Path $env:USERPROFILE '.github\agents' + $destCop = Join-Path $env:USERPROFILE '.copilot\agents' + New-Item -ItemType Directory -Path $destGH -Force | Out-Null + New-Item -ItemType Directory -Path $destCop -Force | Out-Null + $count = 0 + $agentDirs = @('academic','design','engineering','game-development','marketing', + 'paid-media','sales','product','project-management','testing', + 'support','spatial-computing','specialized') + foreach ($dir in $agentDirs) { + $dirPath = Join-Path $RepoRoot $dir + if (-not (Test-Path $dirPath)) { continue } + Get-ChildItem -Path $dirPath -Filter '*.md' -File | ForEach-Object { + $firstLine = Get-Content $_.FullName -TotalCount 1 + if ($firstLine -eq '---') { + Copy-Item $_.FullName -Destination $destGH -Force + Copy-Item $_.FullName -Destination $destCop -Force + $count++ + } + } + } + Write-Ok "Copilot: $count agents -> $destGH" + Write-Ok "Copilot: $count agents -> $destCop" +} + +function Install-Cursor { + $src = Join-Path $Integrations 'cursor\rules' + $dest = Join-Path $PWD '.cursor\rules' + if (-not (Test-Path $src)) { Write-Err "integrations/cursor missing. Run convert.sh first."; return } + New-Item -ItemType Directory -Path $dest -Force | Out-Null + $count = 0 + Get-ChildItem -Path $src -Filter '*.mdc' -File | ForEach-Object { + Copy-Item $_.FullName -Destination $dest -Force + $count++ + } + Write-Ok "Cursor: $count rules -> $dest" + Write-Warn "Cursor: project-scoped. Run from your project root to install there." +} + +function Install-Aider { + $src = Join-Path $Integrations 'aider\CONVENTIONS.md' + $dest = Join-Path $PWD 'CONVENTIONS.md' + if (-not (Test-Path $src)) { Write-Err "integrations/aider/CONVENTIONS.md missing. Run convert.sh first."; return } + if (Test-Path $dest) { Write-Warn "Aider: CONVENTIONS.md already exists at $dest (remove to reinstall)."; return } + Copy-Item $src -Destination $dest -Force + Write-Ok "Aider: installed -> $dest" +} + +function Install-Windsurf { + $src = Join-Path $Integrations 'windsurf\.windsurfrules' + $dest = Join-Path $PWD '.windsurfrules' + if (-not (Test-Path $src)) { Write-Err "integrations/windsurf/.windsurfrules missing. Run convert.sh first."; return } + if (Test-Path $dest) { Write-Warn "Windsurf: .windsurfrules already exists at $dest (remove to reinstall)."; return } + Copy-Item $src -Destination $dest -Force + Write-Ok "Windsurf: installed -> $dest" +} + +function Install-Tool { + param([string]$ToolName) + switch ($ToolName) { + 'claude-code' { Install-ClaudeCode } + 'copilot' { Install-Copilot } + 'cursor' { Install-Cursor } + 'aider' { Install-Aider } + 'windsurf' { Install-Windsurf } + default { Write-Warn "$ToolName: PowerShell installer not yet implemented. Use install.sh via WSL or Git Bash." } + } +} + +# --------------------------------------------------------------------------- +# Main +# --------------------------------------------------------------------------- +if ($Help) { + Get-Help $MyInvocation.MyCommand.Path -Detailed + exit 0 +} + +if (-not (Test-Path $Integrations)) { + Write-Err "integrations/ not found. Run ./scripts/convert.sh first (via WSL or Git Bash)." + exit 1 +} + +Write-Header "The Agency -- Installing agents (PowerShell)" +Write-Host " Repo: $RepoRoot" +Write-Host " Platform: Windows (PowerShell $($PSVersionTable.PSVersion))" +Write-Host "" + +$selectedTools = @() +if ($Tool -eq 'all') { + foreach ($t in $AllTools) { + if (Test-ToolDetected $t) { + $selectedTools += $t + Write-Host " [*] $t detected" -ForegroundColor Green + } else { + Write-Host " [ ] $t not found" -ForegroundColor DarkGray + } + } +} else { + $selectedTools = @($Tool) +} + +if ($selectedTools.Count -eq 0) { + Write-Warn "No tools selected or detected. Nothing to install." + Write-Host " Tip: use -Tool to force-install a specific tool." + exit 0 +} + +Write-Host "" +$installed = 0 +foreach ($t in $selectedTools) { + Install-Tool $t + $installed++ +} + +Write-Host "" +Write-Ok "Done! Installed $installed tool(s)." +Write-Host "" diff --git a/scripts/install.sh b/scripts/install.sh index 9bc4f1d8..390b848e 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -129,19 +129,113 @@ check_integrations() { fi } +# --------------------------------------------------------------------------- +# Platform detection +# --------------------------------------------------------------------------- +detect_platform() { + case "$(uname -s 2>/dev/null)" in + Linux*) + if grep -qiE '(microsoft|wsl)' /proc/version 2>/dev/null; then + echo "wsl" + else + echo "linux" + fi + ;; + Darwin*) echo "macos" ;; + CYGWIN*|MINGW*|MSYS*) echo "windows-gitbash" ;; + *) echo "unknown" ;; + esac +} + +PLATFORM="$(detect_platform)" + +# --------------------------------------------------------------------------- +# Dynamic tool path resolution (Issue #205) +# +# resolve_tool_path +# Prints the absolute path of a tool binary if found, empty string otherwise. +# Uses 'command -v' (POSIX) with 'which' as fallback. +# --------------------------------------------------------------------------- +resolve_tool_path() { + local bin="$1" + local path="" + path="$(command -v "$bin" 2>/dev/null)" && [[ -n "$path" ]] && { echo "$path"; return 0; } + path="$(which "$bin" 2>/dev/null)" && [[ -n "$path" ]] && { echo "$path"; return 0; } + return 1 +} + +# Associative-array-like storage for resolved paths (bash 3 compatible) +declare -a TOOL_PATHS=() +declare -a TOOL_NAMES=() + +# Store a resolved tool path for later retrieval +store_tool_path() { + local name="$1" path="$2" + TOOL_NAMES+=("$name") + TOOL_PATHS+=("$path") +} + +# Retrieve a stored tool path by name +get_tool_path() { + local name="$1" i=0 + for (( i=0; i<${#TOOL_NAMES[@]}; i++ )); do + if [[ "${TOOL_NAMES[$i]}" == "$name" ]]; then + echo "${TOOL_PATHS[$i]}" + return 0 + fi + done + return 1 +} + # --------------------------------------------------------------------------- # Tool detection # --------------------------------------------------------------------------- -detect_claude_code() { [[ -d "${HOME}/.claude" ]]; } -detect_copilot() { command -v code >/dev/null 2>&1 || [[ -d "${HOME}/.github" || -d "${HOME}/.copilot" ]]; } +detect_claude_code() { + local p + p="$(resolve_tool_path claude 2>/dev/null)" && { store_tool_path "claude" "$p"; true; } || true + [[ -n "$(get_tool_path claude 2>/dev/null)" ]] || [[ -d "${HOME}/.claude" ]] +} +detect_copilot() { + local p + p="$(resolve_tool_path code 2>/dev/null)" && { store_tool_path "code" "$p"; true; } || true + [[ -n "$(get_tool_path code 2>/dev/null)" ]] || [[ -d "${HOME}/.github" || -d "${HOME}/.copilot" ]] +} detect_antigravity() { [[ -d "${HOME}/.gemini/antigravity/skills" ]]; } -detect_gemini_cli() { command -v gemini >/dev/null 2>&1 || [[ -d "${HOME}/.gemini" ]]; } -detect_cursor() { command -v cursor >/dev/null 2>&1 || [[ -d "${HOME}/.cursor" ]]; } -detect_opencode() { command -v opencode >/dev/null 2>&1 || [[ -d "${HOME}/.config/opencode" ]]; } -detect_aider() { command -v aider >/dev/null 2>&1; } -detect_openclaw() { command -v openclaw >/dev/null 2>&1 || [[ -d "${HOME}/.openclaw" ]]; } -detect_windsurf() { command -v windsurf >/dev/null 2>&1 || [[ -d "${HOME}/.codeium" ]]; } -detect_qwen() { command -v qwen >/dev/null 2>&1 || [[ -d "${HOME}/.qwen" ]]; } +detect_gemini_cli() { + local p + p="$(resolve_tool_path gemini 2>/dev/null)" && { store_tool_path "gemini" "$p"; true; } || true + [[ -n "$(get_tool_path gemini 2>/dev/null)" ]] || [[ -d "${HOME}/.gemini" ]] +} +detect_cursor() { + local p + p="$(resolve_tool_path cursor 2>/dev/null)" && { store_tool_path "cursor" "$p"; true; } || true + [[ -n "$(get_tool_path cursor 2>/dev/null)" ]] || [[ -d "${HOME}/.cursor" ]] +} +detect_opencode() { + local p + p="$(resolve_tool_path opencode 2>/dev/null)" && { store_tool_path "opencode" "$p"; true; } || true + [[ -n "$(get_tool_path opencode 2>/dev/null)" ]] || [[ -d "${HOME}/.config/opencode" ]] +} +detect_aider() { + local p + p="$(resolve_tool_path aider 2>/dev/null)" && { store_tool_path "aider" "$p"; true; } || true + [[ -n "$(get_tool_path aider 2>/dev/null)" ]] +} +detect_openclaw() { + local p + p="$(resolve_tool_path openclaw 2>/dev/null)" && { store_tool_path "openclaw" "$p"; true; } || true + [[ -n "$(get_tool_path openclaw 2>/dev/null)" ]] || [[ -d "${HOME}/.openclaw" ]] +} +detect_windsurf() { + local p + p="$(resolve_tool_path windsurf 2>/dev/null)" && { store_tool_path "windsurf" "$p"; true; } || true + [[ -n "$(get_tool_path windsurf 2>/dev/null)" ]] || [[ -d "${HOME}/.codeium" ]] +} +detect_qwen() { + local p + p="$(resolve_tool_path qwen 2>/dev/null)" && { store_tool_path "qwen" "$p"; true; } || true + [[ -n "$(get_tool_path qwen 2>/dev/null)" ]] || [[ -d "${HOME}/.qwen" ]] +} is_detected() { case "$1" in @@ -161,17 +255,36 @@ is_detected() { # Fixed-width labels: name (14) + detail (24) = 38 visible chars tool_label() { + local resolved="" case "$1" in - claude-code) printf "%-14s %s" "Claude Code" "(claude.ai/code)" ;; - copilot) printf "%-14s %s" "Copilot" "(~/.github + ~/.copilot)" ;; + claude-code) + resolved="$(get_tool_path claude 2>/dev/null)" + printf "%-14s %s" "Claude Code" "${resolved:+(${resolved}) }(claude.ai/code)" ;; + copilot) + resolved="$(get_tool_path code 2>/dev/null)" + printf "%-14s %s" "Copilot" "${resolved:+(${resolved}) }(~/.github + ~/.copilot)" ;; antigravity) printf "%-14s %s" "Antigravity" "(~/.gemini/antigravity)" ;; - gemini-cli) printf "%-14s %s" "Gemini CLI" "(gemini extension)" ;; - opencode) printf "%-14s %s" "OpenCode" "(opencode.ai)" ;; - openclaw) printf "%-14s %s" "OpenClaw" "(~/.openclaw)" ;; - cursor) printf "%-14s %s" "Cursor" "(.cursor/rules)" ;; - aider) printf "%-14s %s" "Aider" "(CONVENTIONS.md)" ;; - windsurf) printf "%-14s %s" "Windsurf" "(.windsurfrules)" ;; - qwen) printf "%-14s %s" "Qwen Code" "(~/.qwen/agents)" ;; + gemini-cli) + resolved="$(get_tool_path gemini 2>/dev/null)" + printf "%-14s %s" "Gemini CLI" "${resolved:+(${resolved}) }(gemini extension)" ;; + opencode) + resolved="$(get_tool_path opencode 2>/dev/null)" + printf "%-14s %s" "OpenCode" "${resolved:+(${resolved}) }(opencode.ai)" ;; + openclaw) + resolved="$(get_tool_path openclaw 2>/dev/null)" + printf "%-14s %s" "OpenClaw" "${resolved:+(${resolved}) }(~/.openclaw)" ;; + cursor) + resolved="$(get_tool_path cursor 2>/dev/null)" + printf "%-14s %s" "Cursor" "${resolved:+(${resolved}) }(.cursor/rules)" ;; + aider) + resolved="$(get_tool_path aider 2>/dev/null)" + printf "%-14s %s" "Aider" "${resolved:+(${resolved}) }(CONVENTIONS.md)" ;; + windsurf) + resolved="$(get_tool_path windsurf 2>/dev/null)" + printf "%-14s %s" "Windsurf" "${resolved:+(${resolved}) }(.windsurfrules)" ;; + qwen) + resolved="$(get_tool_path qwen 2>/dev/null)" + printf "%-14s %s" "Qwen Code" "${resolved:+(${resolved}) }(~/.qwen/agents)" ;; esac } @@ -507,6 +620,15 @@ main() { check_integrations + # Platform info + if [[ "$PLATFORM" == "wsl" ]]; then + warn "Running under WSL. Windows-native tools may not be detected." + dim " Tip: For Windows-native installs, use scripts/install.ps1 from PowerShell." + elif [[ "$PLATFORM" == "windows-gitbash" ]]; then + warn "Running under Git Bash. Some paths may differ from native Windows." + dim " Tip: For full Windows support, use scripts/install.ps1 from PowerShell." + fi + # Validate explicit tool if [[ "$tool" != "all" ]]; then local valid=false t