Răsfoiți Sursa

fix: bundle codegraph install scripts from upstream, rewrite SKILL.md as agent instructions

kekezack 1 lună în urmă
părinte
comite
b39f441dba

+ 53 - 195
skills/code-dev/codegraph/SKILL.md

@@ -1,242 +1,100 @@
 ---
 name: "codegraph"
-description: CodeGraph — 预构建的代码知识图谱 MCP 工具集。为 AI 编程智能体提供语义级代码理解:一次调用获取符号源码、调用链路、影响范围和全文本搜索。支持 35+ 语言、17+ Web 框架路由识别、iOS/RN 跨语言桥接。自动同步文件变更。用于架构理解、代码搜索、变更影响分析、跨文件流程追踪等场景。
+description: CodeGraph — 代码知识图谱 MCP 工具集。为 AI 编程智能体提供语义级代码理解:一次调用获取符号源码、调用链路、影响范围。支持 35+ 语言、17+ Web 框架路由、iOS/RN 跨语言桥接。自动同步文件变更。
 ---
 
 # CodeGraph
 
-CodeGraph is a pre-indexed code knowledge graph + MCP server. It parses your codebase with tree-sitter (backed by a native Rust kernel), stores every symbol, edge, and file in SQLite (FTS5), and exposes it to AI agents through MCP tools. Auto-syncs on file changes.
-
-**Repo**: <https://github.com/colbymchenry/codegraph>
-**Version**: 1.5.0+
+预构建的代码知识图谱 + MCP 服务器。解析代码库后用 SQLite(FTS5)存储所有符号、调用边、文件,通过 MCP 工具暴露给 Agent。自动同步文件变更。
 
 ---
 
-## Quick Start
+## 安装
 
-### 1. Install CodeGraph CLI
+本技能附带原版安装脚本(`scripts/install.ps1` / `scripts/install.sh`),复制本目录后执行:
 
 ```bash
-# Via npm (any platform)
-npm i -g @colbymchenry/codegraph
-
-# Or via installer (no Node.js required):
-#   macOS/Linux: curl -fsSL https://raw.githubusercontent.com/colbymchenry/codegraph/main/install.sh | sh
-#   Windows: irm https://raw.githubusercontent.com/colbymchenry/codegraph/main/install.ps1 | iex
-```
-
-### 2. Wire up your agent
-
-```bash
-codegraph install
-```
+# 从技能目录运行安装脚本
+cd ~/.agents/skills/codegraph/scripts
 
-Auto-detects and configures: Claude Code, Cursor, Codex CLI, OpenCode, Hermes Agent, Gemini CLI, Antigravity IDE, Kiro.
+# macOS / Linux
+chmod +x install.sh && ./install.sh
 
-### 3. Initialize a project
-
-```bash
-cd your-project
-codegraph init
+# Windows PowerShell
+.\install.ps1
 ```
 
-Creates `.codegraph/` directory and builds the full knowledge graph.
+安装脚本自动完成:装 CLI → 连线 Agent → 建索引。完成后重启 Agent。
 
 ---
 
-## MCP Tools
-
-CodeGraph exposes the following MCP tools when running as `codegraph serve --mcp`:
-
-### `codegraph_explore` (PRIMARY — call first)
-
-Answer almost any question in one call: "how does X work", a flow ("how does X reach Y"), or surveying an area.
-
-```
-Input: {
-  query: string          // Symbol names, file names, or natural language
-  projectPath?: string   // Path to indexed project (default: cwd)
-  maxFiles?: number      // Max files to include
-}
-Output: Symbols' verbatim source grouped by file + call paths + blast radius
-```
-
-### `codegraph_node`
+## MCP 工具
 
-Two modes:
-1. **Read a file** — pass `file` (path or basename) without `symbol` → returns line-numbered source (Read-equivalent)
-2. **One symbol** — returns location, signature, source, caller/callee trail
+### `codegraph_explore` — 主工具,优先用
 
 ```
-Input: {
-  symbol?: string        // Symbol name (qualified or short)
-  file?: string          // File path or basename
-  line?: number          // Line number (disambiguation)
-  includeCode?: boolean  // Include source code (default: true)
-  projectPath?: string
-}
+codegraph_explore query:"AuthService loginUser UserRepository"
+codegraph_explore query:"用户登录请求的完整链路"
+codegraph_explore query:"app.ts"
 ```
 
-### `codegraph_search`
+返回源码 + 调用路径 + 影响范围。**返回的源码视为已 Read**,不要再用 Read 重读。
 
-Quick symbol search by name. Returns locations only (no code).
+### `codegraph_node` — 读文件 / 看符号
 
 ```
-Input: {
-  query: string          // Symbol name to search
-  kind?: string          // Filter by node kind (class, function, etc.)
-  limit?: number         // Max results
-  projectPath?: string
-}
+codegraph_node file:"src/services/user.ts"
+codegraph_node symbol:"getUserById"
+codegraph_node symbol:"getUserById" file:"user.ts"
 ```
 
-### `codegraph_callers` / `codegraph_callees`
-
-Find what calls a function / what a function calls.
+### `codegraph_search` — 搜符号位置
 
 ```
-Input: {
-  symbol: string         // Symbol name
-  limit?: number
-  projectPath?: string
-}
+codegraph_search query:"UserRepo"
+codegraph_search query:"getUser" kind:"function"
 ```
 
-### `codegraph_impact`
-
-List symbols affected by changing a symbol.
+### `codegraph_callers` / `codegraph_callees` — 调用关系
 
 ```
-Input: {
-  symbol: string         // Symbol to analyze
-  depth?: number         // Traversal depth (default: 2)
-  projectPath?: string
-}
+codegraph_callers symbol:"handleRequest"
+codegraph_callees symbol:"handleRequest"
 ```
 
-### `codegraph_files`
-
-Show file structure of the indexed project.
+### `codegraph_impact` — 改代码前看影响
 
 ```
-Input: {
-  format?: "tree" | "list"
-  filter?: string        // Glob pattern
-  maxDepth?: number
-  projectPath?: string
-}
+codegraph_impact symbol:"UserService"
+codegraph_impact symbol:"UserService" depth:3
 ```
 
-### `codegraph_status`
-
-Check if a project is indexed and see its statistics.
+### `codegraph_files` — 项目文件结构
 
 ```
-Input: {
-  projectPath?: string   // If omitted, checks the current project
-}
+codegraph_files
+codegraph_files filter:"src/**/*.ts"
 ```
 
 ---
 
-## CLI Commands
-
-```bash
-codegraph                         # Interactive installer
-codegraph install                 # Wire up agents
-codegraph uninstall               # Remove CodeGraph from agents + CLI
-codegraph init [path]             # Initialize + build graph
-codegraph uninit [path]           # Remove CodeGraph from project
-codegraph index [path]            # Full re-index
-codegraph sync [path]             # Incremental sync
-codegraph status [path]           # Show index statistics
-codegraph unlock [path]           # Remove stale lock file
-codegraph query <search>          # Search symbols
-codegraph explore <query>         # CLI equivalent of codegraph_explore
-codegraph node <symbol|file>      # CLI equivalent of codegraph_node
-codegraph callers <symbol>        # Find callers
-codegraph callees <symbol>        # Find callees
-codegraph impact <symbol>         # Impact analysis
-codegraph affected [files...]     # Find affected test files
-codegraph daemon                  # Manage background daemons
-codegraph upgrade [version]       # Update to latest
-codegraph version                 # Print version
-codegraph help [command]          # Show help
-```
-
-### `codegraph affected`
-
-Trace import dependencies to find which test files are affected by changes:
-
-```bash
-codegraph affected src/utils.ts src/api.ts
-git diff --name-only | codegraph affected --stdin
-codegraph affected src/auth.ts --filter "e2e/*"
-```
-
----
-
-## Configuration
-
-Zero-config by default. Optional `codegraph.json` at project root:
-
-```json
-{
-  "exclude": ["static/", "**/vendor/**"],
-  "include": ["Tools/", "Local/typescript/"],
-  "extensions": {
-    ".dota_lua": "lua",
-    ".tpl": "php"
-  }
-}
-```
-
-### Environment Variables
-
-| Variable | Purpose |
-|----------|---------|
-| `CODEGRAPH_WATCH_DEBOUNCE_MS` | File watcher debounce (clamped 100ms–60s, default 2000ms) |
-| `CODEGRAPH_MCP_TOOLS` | Re-enable hidden tools: `explore,node,search,callers` |
-| `CODEGRAPH_EXPLORE_LINENUMS` | Set to `0` to disable line numbers |
-| `CODEGRAPH_NO_DAEMON` | Disable background daemon (sandboxed environments) |
-| `CODEGRAPH_TELEMETRY` | Set to `0` to disable telemetry |
-| `DO_NOT_TRACK` | Also disables telemetry |
-| `CODEGRAPH_DAEMON_IDLE_TIMEOUT_MS` | Daemon idle timeout |
-
----
-
-## Key Features
-
-- **35+ Languages**: TypeScript, JavaScript, Python, Go, Rust, Java, C#, PHP, Ruby, C/C++, Swift, Kotlin, Scala, Dart, Lua, and more
-- **17+ Framework Routes**: Django, Flask, FastAPI, Express, NestJS, Laravel, Rails, Spring, Gin, ASP.NET, Vapor, React Router, SvelteKit, Vue/Nuxt, Astro
-- **Cross-language Bridging**: Swift ↔ ObjC, React Native (legacy bridge, TurboModules, Fabric, Paper), Expo Modules
-- **Dynamic Dispatch**: Callbacks, React re-render, interface→impl, JSX children — edges grep can't follow
-- **Auto-sync**: Native file watcher (FSEvents/inotify/RDCW) with debounced re-index
-- **100% Local**: SQLite database, no data leaves your machine
-- **Benchmark**: 89% fewer tool calls, 60% cheaper, 69% fewer tokens vs. unassisted agent (validated on 7 repos)
-
----
-
-## Agent Usage Guidance
-
-When CodeGraph's MCP server is active:
-
-1. **Call `codegraph_explore` FIRST** for any structural/flow question — it returns verbatim source grouped by file, call paths, and blast radius. Usually the only call needed.
-
-2. **Treat returned source as already Read** — do NOT re-open those files with the Read tool.
-
-3. **For a flow question** ("how does X reach Y"), name the symbols spanning the flow in the query (e.g. `mutateElement renderScene`). CodeGraph surfaces the path between them, including dynamic-dispatch hops.
-
-4. **For reading a file or symbol**, use `codegraph_explore` with its name/path — you get line-numbered source (safe to Edit from) plus impact info.
-
-5. **Don't grep then Read** — one `codegraph_explore` replaces the entire search+read loop.
-
-6. **After edits, check the staleness banner** — files listed as pending need a direct Read; everything else is fresh.
-
-7. **Monorepo support**: pass `projectPath` to query a specific sub-project that has a `.codegraph/` index.
-
----
-
-## Supported Languages
-
-TypeScript (`.ts`, `.tsx`), JavaScript (`.js`, `.jsx`, `.mjs`), ArkTS (`.ets`), Python (`.py`), Go (`.go`), Rust (`.rs`), Java (`.java`), C# (`.cs`), PHP (`.php`), Ruby (`.rb`), C (`.c`, `.h`), C++ (`.cpp`, `.hpp`, `.cc`), Objective-C (`.m`, `.mm`, `.h`), Metal (`.metal`), CUDA (`.cu`, `.cuh`), Swift (`.swift`), Kotlin (`.kt`, `.kts`), Scala (`.scala`, `.sc`), Dart (`.dart`), Svelte (`.svelte`), Vue (`.vue`), Astro (`.astro`), Liquid (`.liquid`), Pascal/Delphi (`.pas`, `.dpr`, `.dpk`, `.lpr`), Lua (`.lua`), R (`.R`, `.r`), Luau (`.luau`), CFML (`.cfc`, `.cfm`, `.cfs`), COBOL (`.cbl`, `.cob`, `.cpy`), VB.NET (`.vb`), Erlang (`.erl`, `.hrl`, `.escript`), Solidity (`.sol`), Terraform/OpenTofu (`.tf`, `.tfvars`, `.tofu`), Nix (`.nix`).
+## 工具选择
+
+| 场景 | 工具 |
+|------|------|
+| 查架构/流程 | `codegraph_explore` |
+| 读文件 | `codegraph_node file:"路径"` |
+| 查符号定义+调用者 | `codegraph_node symbol:"名"` |
+| 搜符号位置 | `codegraph_search` |
+| 改前看影响 | `codegraph_impact` |
+| 查谁调了我 | `codegraph_callers` |
+| 查我调了谁 | `codegraph_callees` |
+
+## 反模式
+
+| ❌ 不要 | ✅ 应该 |
+|---------|---------|
+| `Read file` | `codegraph_node file` |
+| `Grep` → `Read` 循环 | 一次 `codegraph_explore` |
+| 手搓调用链 | `codegraph_explore query:"A B C"` |
+| 直接改代码 | 先 `codegraph_impact` |

+ 91 - 0
skills/code-dev/codegraph/scripts/install.ps1

@@ -0,0 +1,91 @@
+# CodeGraph standalone installer for Windows (PowerShell).
+#
+# Downloads a self-contained bundle (a vendored Node runtime + the app) from
+# GitHub Releases. No Node.js, no build tools required.
+#
+#   irm https://raw.githubusercontent.com/colbymchenry/codegraph/main/install.ps1 | iex
+#
+# Upgrade with `codegraph upgrade` (or just re-run this). To uninstall: remove
+# $env:LOCALAPPDATA\codegraph and drop its \current\bin entry from your user PATH.
+#
+# Environment:
+#   CODEGRAPH_VERSION      release tag to install (default: latest)
+#   CODEGRAPH_INSTALL_DIR  install location (default: %LOCALAPPDATA%\codegraph)
+
+$ErrorActionPreference = 'Stop'
+$repo = 'colbymchenry/codegraph'
+$installDir = if ($env:CODEGRAPH_INSTALL_DIR) { $env:CODEGRAPH_INSTALL_DIR } else { Join-Path $env:LOCALAPPDATA 'codegraph' }
+
+# 1. Detect architecture -> target matching the release archives.
+$arch = if ([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture -eq 'Arm64') { 'arm64' } else { 'x64' }
+$target = "win32-$arch"
+
+# 2. Resolve the version (latest release unless pinned).
+$version = $env:CODEGRAPH_VERSION
+if (-not $version) {
+  $version = (Invoke-RestMethod "https://api.github.com/repos/$repo/releases/latest").tag_name
+}
+if (-not $version) { throw "codegraph: could not resolve latest version; set CODEGRAPH_VERSION." }
+
+# 3. Download + extract the bundle into a stable 'current' dir (overwritten on upgrade).
+$url = "https://github.com/$repo/releases/download/$version/codegraph-$target.zip"
+Write-Host "Installing CodeGraph $version ($target)..."
+$tmp = Join-Path $env:TEMP ("cg-" + [guid]::NewGuid().ToString())
+New-Item -ItemType Directory -Force -Path $tmp | Out-Null
+$zip = Join-Path $tmp 'cg.zip'
+Invoke-WebRequest -Uri $url -OutFile $zip
+
+$dest = Join-Path $installDir 'current'
+if (Test-Path $dest) { Remove-Item -Recurse -Force $dest }
+New-Item -ItemType Directory -Force -Path $dest | Out-Null
+Expand-Archive -Path $zip -DestinationPath $dest -Force
+# Archives contain a top-level codegraph-<target>\ dir; flatten it.
+$inner = Join-Path $dest "codegraph-$target"
+if (Test-Path $inner) {
+  Get-ChildItem -Force $inner | Move-Item -Destination $dest -Force
+  Remove-Item -Recurse -Force $inner
+}
+Remove-Item -Recurse -Force $tmp
+
+# 4. Put the launcher dir on the user's PATH.
+$binDir = Join-Path $dest 'bin'
+$userPath = [Environment]::GetEnvironmentVariable('Path', 'User')
+if (($userPath -split ';') -notcontains $binDir) {
+  [Environment]::SetEnvironmentVariable('Path', "$binDir;$userPath", 'User')
+  Write-Host "Added $binDir to your PATH (restart your terminal to pick it up)."
+}
+
+Write-Host "Installed to $dest"
+
+# 5. Warn if a different codegraph earlier on PATH will shadow this install.
+# Most often a stale `npm i -g @colbymchenry/codegraph`, whose launcher keeps
+# running its own version-pinned bundle — so `codegraph --version` disagrees
+# with what we just installed (issue #1071). Check both the persisted PATH a
+# fresh shell sees (Machine + User) and this session's PATH (catches dirs a
+# shell profile injects, e.g. conda / npm).
+$expected = Join-Path $binDir 'codegraph.cmd'
+function Find-FirstCodegraph([string]$pathStr) {
+  foreach ($dir in ($pathStr -split ';')) {
+    if (-not $dir) { continue }
+    foreach ($leaf in @('codegraph.cmd', 'codegraph.exe', 'codegraph.bat', 'codegraph.ps1')) {
+      $cand = Join-Path $dir $leaf
+      if (Test-Path -LiteralPath $cand) { return $cand }
+    }
+  }
+  return $null
+}
+$machinePath = [Environment]::GetEnvironmentVariable('Path', 'Machine')
+$freshPath = ((@($machinePath, [Environment]::GetEnvironmentVariable('Path', 'User')) | Where-Object { $_ }) -join ';')
+$shadow = $null
+foreach ($winner in @((Find-FirstCodegraph $env:Path), (Find-FirstCodegraph $freshPath))) {
+  if ($winner -and ($winner -ne $expected)) { $shadow = $winner; break }
+}
+if ($shadow) {
+  Write-Warning "Another codegraph is earlier on your PATH and will run instead of this install:"
+  Write-Warning "  $shadow"
+  Write-Warning "  (this install: $expected)"
+  Write-Warning "If 'codegraph --version' shows an unexpected version, remove the other copy"
+  Write-Warning "(e.g. 'npm rm -g @colbymchenry/codegraph') or put '$binDir' first on your PATH."
+}
+
+Write-Host "Run: codegraph --help"

+ 146 - 0
skills/code-dev/codegraph/scripts/install.sh

@@ -0,0 +1,146 @@
+#!/bin/sh
+#
+# CodeGraph standalone installer.
+#
+# Downloads a self-contained bundle (a vendored Node runtime + the app) from
+# GitHub Releases. No Node.js, no build tools, no npm required — ideal for a
+# fresh Linux VPS over SSH.
+#
+#   curl -fsSL https://raw.githubusercontent.com/colbymchenry/codegraph/main/install.sh | sh
+#
+# Upgrade:   run `codegraph upgrade` (or just re-run the same command).
+# Uninstall: curl -fsSL .../install.sh | sh -s -- --uninstall
+#
+# Environment:
+#   CODEGRAPH_VERSION      release tag to install (default: latest)
+#   CODEGRAPH_INSTALL_DIR  bundle location   (default: ~/.codegraph)
+#   CODEGRAPH_BIN_DIR      symlink location  (default: ~/.local/bin)
+set -eu
+
+REPO="colbymchenry/codegraph"
+INSTALL_DIR="${CODEGRAPH_INSTALL_DIR:-$HOME/.codegraph}"
+BIN_DIR="${CODEGRAPH_BIN_DIR:-$HOME/.local/bin}"
+
+if [ "${1:-}" = "--uninstall" ]; then
+  rm -f "$BIN_DIR/codegraph"
+  rm -rf "$INSTALL_DIR"
+  echo "CodeGraph uninstalled (removed $INSTALL_DIR and $BIN_DIR/codegraph)."
+  exit 0
+fi
+
+# 1. Detect platform → target triple matching the release archives.
+os="$(uname -s)"
+arch="$(uname -m)"
+case "$os" in
+  Darwin) os="darwin" ;;
+  Linux)  os="linux" ;;
+  *) echo "codegraph: unsupported OS '$os'." >&2; exit 1 ;;
+esac
+case "$arch" in
+  arm64|aarch64) arch="arm64" ;;
+  x86_64|amd64)  arch="x64" ;;
+  *) echo "codegraph: unsupported architecture '$arch'." >&2; exit 1 ;;
+esac
+target="${os}-${arch}"
+
+# 2. Resolve the version (latest release unless pinned).
+#
+# Resolve "latest" from the releases/latest *web* redirect, not the GitHub API:
+# the unauthenticated API is rate-limited to 60 requests/hour per IP and returns
+# 403 once exhausted — routine on shared/cloud hosts and CI (issue #325). The
+# redirect (github.com/<repo>/releases/latest -> .../releases/tag/vX.Y.Z) has no
+# such limit. Fall back to the API if the redirect can't be read.
+version="${CODEGRAPH_VERSION:-}"
+if [ -z "$version" ]; then
+  version="$(curl -fsSLI -o /dev/null -w '%{url_effective}' "https://github.com/$REPO/releases/latest" \
+    | sed -n 's#.*/releases/tag/##p')"
+fi
+if [ -z "$version" ]; then
+  version="$(curl -fsSL "https://api.github.com/repos/$REPO/releases/latest" \
+    | sed -n 's/.*"tag_name": *"\([^"]*\)".*/\1/p' | head -n1)"
+fi
+[ -n "$version" ] || { echo "codegraph: could not resolve latest version; set CODEGRAPH_VERSION (e.g. CODEGRAPH_VERSION=v0.9.4)." >&2; exit 1; }
+# Release tags are vX.Y.Z; accept a bare X.Y.Z in CODEGRAPH_VERSION too.
+case "$version" in v*) ;; *) version="v$version" ;; esac
+
+# 3. Download + extract the bundle.
+url="https://github.com/$REPO/releases/download/$version/codegraph-${target}.tar.gz"
+echo "Installing CodeGraph $version ($target)..."
+tmp="$(mktemp -d)"
+trap 'rm -rf "$tmp"' EXIT
+curl -fsSL "$url" -o "$tmp/cg.tar.gz" || { echo "codegraph: download failed: $url" >&2; exit 1; }
+
+dest="$INSTALL_DIR/versions/$version"
+rm -rf "$dest"
+mkdir -p "$dest"
+# Archives contain a top-level codegraph-<target>/ dir; strip it.
+tar -xzf "$tmp/cg.tar.gz" -C "$dest" --strip-components=1
+
+# 4. Symlink the launcher onto PATH and mark the current version.
+mkdir -p "$BIN_DIR"
+ln -sf "$dest/bin/codegraph" "$BIN_DIR/codegraph"
+ln -sfn "$dest" "$INSTALL_DIR/current"
+
+echo "Installed to $dest"
+echo "Linked     $BIN_DIR/codegraph"
+
+# 5. Prune older bundles so they don't pile up across upgrades (issue #1074).
+# Each release lives in its own versions/<v> dir (~50 MB with the vendored Node
+# runtime). `codegraph upgrade` re-runs this script, which drops in a new dir
+# and re-points `current` + the launcher — but it never removed the old dirs, so
+# they accumulated indefinitely. Keep only what we just installed ($dest) and
+# delete the rest. Safe even if a daemon is still executing an older bundle: on
+# POSIX the inode stays alive until that process exits, so removing the dir can't
+# break a running process. (Windows installs overwrite a single dir in place and
+# never reach this.) The markers below let a unit test run this exact block.
+# >>> CODEGRAPH_PRUNE_OLD_VERSIONS
+pruned=0
+if [ -d "$INSTALL_DIR/versions" ]; then
+  for d in "$INSTALL_DIR/versions"/*; do
+    [ -d "$d" ] || continue
+    if [ "$d" != "$dest" ]; then
+      if rm -rf "$d"; then
+        pruned=$((pruned + 1))
+      fi
+    fi
+  done
+fi
+if [ "$pruned" -gt 0 ]; then
+  echo "Removed    $pruned older version(s)"
+fi
+# <<< CODEGRAPH_PRUNE_OLD_VERSIONS
+
+# 6. PATH sanity. Two ways this install can fail to be the codegraph that runs:
+#   1. $BIN_DIR isn't on PATH at all.
+#   2. A *different* codegraph sits earlier on PATH and shadows ours — most
+#      often a stale `npm i -g @colbymchenry/codegraph`, whose launcher keeps
+#      running its own version-pinned bundle, so `codegraph --version` disagrees
+#      with what we just installed (issue #1071).
+# Walk PATH once: note whether $BIN_DIR is present and which codegraph wins.
+on_path=0
+winner=""
+oldifs="$IFS"; IFS=:
+for dir in $PATH; do
+  [ -n "$dir" ] || continue
+  if [ "$dir" = "$BIN_DIR" ]; then on_path=1; fi
+  if [ -z "$winner" ] && [ -x "$dir/codegraph" ] && [ ! -d "$dir/codegraph" ]; then
+    winner="$dir/codegraph"
+  fi
+done
+IFS="$oldifs"
+
+if [ "$on_path" -eq 0 ]; then
+  echo ""
+  echo "$BIN_DIR is not on your PATH. Add it:"
+  echo "  export PATH=\"$BIN_DIR:\$PATH\""
+elif [ -n "$winner" ] && [ "$winner" != "$BIN_DIR/codegraph" ]; then
+  echo ""
+  echo "Warning: another codegraph is earlier on your PATH and will run instead:"
+  echo "  $winner"
+  echo "  (this install: $BIN_DIR/codegraph)"
+  echo "If 'codegraph --version' shows an unexpected version, remove the other copy"
+  echo "(e.g. 'npm rm -g @colbymchenry/codegraph') or put $BIN_DIR first on PATH."
+fi
+
+echo ""
+echo "Done. Run: codegraph --help"