From f4f7ea2d271829c84280e260da79ffed2eab60ea Mon Sep 17 00:00:00 2001 From: andres Date: Sat, 19 Sep 2026 11:56:24 +0200 Subject: [PATCH] feat(install): install and upgrade from GitHub Releases without npm - Bundles ship a codegraph-vba launcher next to codegraph, and install.sh links both, so agent MCP configs and Dysflow resolve it without npm. - codegraph-vba install runs the GitHub installer script instead of npm. - The release workflow publishes to npm only when NPM_TOKEN is set, and an npm failure no longer fails the release. - README and CLI hints lead with the GitHub installer. Closes #326 --- .github/workflows/release.yml | 29 +++++++- CHANGELOG.md | 4 ++ README.md | 43 ++++++------ __tests__/bundle-launchers.test.ts | 103 +++++++++++++++++++++++++++++ __tests__/upgrade.test.ts | 17 +++++ install.sh | 16 +++-- scripts/build-bundle.sh | 9 +++ src/bin/codegraph.ts | 3 +- src/installer/index.ts | 16 +++-- src/upgrade/index.ts | 13 ++++ 10 files changed, 218 insertions(+), 35 deletions(-) create mode 100644 __tests__/bundle-launchers.test.ts diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3e2ab7e8..82a7b5aa 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,13 +10,17 @@ name: Release # native compilation, so cross-packaging is fine), # 4. creates the GitHub Release (tag v) with all archives, using the # release notes from CHANGELOG.md, -# 5. publishes the npm thin-installer (shim + per-platform packages). +# 5. publishes the npm thin-installer (shim + per-platform packages) — OPTIONAL. # # Before triggering: bump package.json on the default branch, and dispatch this # workflow from that branch — a guard step rejects anything else, because step 2 # pushes its commit to whichever branch triggered the run. CHANGELOG.md entries # can live under `## [Unreleased]`; step 2 moves them. Never pre-create a -# `## []` block. Set the NPM_TOKEN secret. +# `## []` block. +# +# GitHub Releases is the required channel: install.sh / install.ps1 and +# `codegraph-vba upgrade` only need the release assets. Step 5 runs only when the +# NPM_TOKEN secret is set, and an npm failure never fails the release (#326). on: workflow_dispatch: {} @@ -154,7 +158,25 @@ jobs: gh release create "$TAG" release/codegraph-vba-* release/SHA256SUMS --title "$TITLE" --notes-file notes.md fi + - name: Check npm credentials + # Secrets can't be read in `if:`, so expose only whether one is set. + id: npm + env: + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + run: | + if [ -n "$NPM_TOKEN" ]; then + echo "enabled=true" >> "$GITHUB_OUTPUT" + else + echo "enabled=false" >> "$GITHUB_OUTPUT" + echo "::warning::NPM_TOKEN is not set — skipping npm publish. The GitHub Release is complete." + fi + - name: Publish to npm + # Optional channel (#326): a dead or revoked token must not turn a + # release red after its GitHub Release already shipped. + id: publish + if: steps.npm.outputs.enabled == 'true' + continue-on-error: true env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} run: | @@ -178,6 +200,8 @@ jobs: done < <(find release/npm -name 'package.json' -not -path '*/node_modules/*' -not -path '*/lib/*' -not -path '*/bin/*' -exec dirname {} \; | sort -u) - name: Verify every package is actually on the registry + if: steps.publish.outcome == 'success' + continue-on-error: true env: # Per-package patience. Each per-platform package bundles a Node # runtime and unpacks to ~200 MB over ~1,000 files, and npm's @@ -211,6 +235,7 @@ jobs: done < <(find release/npm -name 'package.json' -not -path '*/node_modules/*' -not -path '*/lib/*' -not -path '*/bin/*' -exec dirname {} \; | sort -u) - name: Sync packages to npmmirror + if: steps.publish.outcome == 'success' # npmmirror/cnpm mirror lazily and frequently never pull the per-platform # optionalDependencies on their own, so `npm i` there fails with # "no prebuilt bundle" (issue #303). Nudge a sync now so mirror users get diff --git a/CHANGELOG.md b/CHANGELOG.md index 0686cc96..b8bc1223 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,10 @@ and adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### New Features + +- CodeGraph-VBA now installs and upgrades entirely from GitHub Releases, with no npm needed: the one-line installers put both `codegraph` and `codegraph-vba` on your PATH, and `codegraph-vba install` sets up the CLI the same way. (#326) + ## [2.0.0] - 2026-09-19 diff --git a/README.md b/README.md index ab5c3c29..9b884c35 100644 --- a/README.md +++ b/README.md @@ -57,14 +57,14 @@ See [fork capabilities and lineage](docs/fork-capabilities.md) for the delivered **Why fork?** To add VBA / Access language support that does not exist upstream, so agents can navigate Microsoft Access projects managed by Dysflow the same way they navigate TypeScript or Python today. See the [VBA / Access + Dysflow integration](#vba--access--dysflow-integration) section below for the feature spec, the pattern table, and the hard invariants. -**The fork is published to npm as `@aroman22/codegraph-vba`.** The upstream package `@colbymchenry/codegraph` does **not** have VBA / Access support — install `@aroman22/codegraph-vba` to get it: +**The fork ships through [GitHub Releases](https://github.com/ardelperal/codegraph-vba/releases).** The upstream package `@colbymchenry/codegraph` does **not** have VBA / Access support — install this fork to get it: ```bash -# Option A — install from npm (easiest; gets you the codegraph-vba CLI on PATH): -npm i -g @aroman22/codegraph-vba -# or with pnpm: -pnpm add -g codegraph-vba -# or the one-line OS installer (no Node required) — see Get Started below. +# Option A — one-line installer from GitHub Releases (no Node, no npm): +# macOS / Linux +curl -fsSL https://raw.githubusercontent.com/ardelperal/codegraph-vba/main/install.sh | sh +# Windows (PowerShell) +irm https://raw.githubusercontent.com/ardelperal/codegraph-vba/main/install.ps1 | iex ``` ```bash @@ -98,17 +98,15 @@ curl -fsSL https://raw.githubusercontent.com/ardelperal/codegraph-vba/main/insta irm https://raw.githubusercontent.com/ardelperal/codegraph-vba/main/install.ps1 | iex ``` -
-Already have Node? Use npm instead (works on any version) - -```bash -npm i -g @aroman22/codegraph-vba -``` - CodeGraph bundles its own runtime — nothing to compile, no native build, works the same everywhere. The installer puts `codegraph-vba` on your PATH but **doesn't change your current shell** — open a new terminal before the next step so the command resolves. **Upgrade any time** with `codegraph-vba upgrade` — it detects how you installed (bundle, npm, or npx) and updates in place. Add `--check` to see if an update is available, or `codegraph-vba upgrade ` to pin one. +
+npm (legacy) + +The npm package `@aroman22/codegraph-vba` is published only on a best-effort basis and can lag behind GitHub Releases. Prefer the installer above; if you already installed through npm, re-run the installer to switch. +
### 2. Wire up your agent(s) @@ -119,7 +117,7 @@ In a **new terminal**, run the installer to connect CodeGraph to the agents you codegraph-vba install ``` -Detects and auto-configures Claude Code, Cursor, Codex CLI, opencode, Hermes Agent, Gemini CLI, Antigravity IDE, and Kiro — wiring the CodeGraph MCP server into each. **This is the step that connects CodeGraph to your agent;** installing the CLI in step 1 does not do it on its own. It only wires up your agent — it does **not** index any code; building each project's graph is the separate `codegraph-vba init` in step 3. (Shortcut: `npx codegraph-vba` downloads and runs this in one go.) +Detects and auto-configures Claude Code, Cursor, Codex CLI, opencode, Hermes Agent, Gemini CLI, Antigravity IDE, and Kiro — wiring the CodeGraph MCP server into each. **This is the step that connects CodeGraph to your agent;** installing the CLI in step 1 does not do it on its own. It only wires up your agent — it does **not** index any code; building each project's graph is the separate `codegraph-vba init` in step 3. ### 3. Initialize each project @@ -552,8 +550,10 @@ payload as JSON. ### 1. Run the Installer +Install the CLI (see [Get Started](#get-started)), then run: + ```bash -npx codegraph-vba +codegraph-vba install ``` The installer will: @@ -600,9 +600,10 @@ That's it — your agent will use CodeGraph tools automatically when a `.codegra
Manual Setup (Alternative) -**Install globally:** +**Install the CLI:** ```bash -npm i -g @aroman22/codegraph-vba +curl -fsSL https://raw.githubusercontent.com/ardelperal/codegraph-vba/main/install.sh | sh # macOS / Linux +irm https://raw.githubusercontent.com/ardelperal/codegraph-vba/main/install.ps1 | iex # Windows ``` **Add to `~/.claude.json`:** @@ -883,9 +884,9 @@ compile) for all three desktop OSes, on both Intel/AMD (x64) and ARM (arm64): | Platform | Architectures | Install | |----------|---------------|---------| -| Windows | x64, arm64 | PowerShell installer or npm | -| macOS | x64, arm64 | shell installer or npm | -| Linux | x64, arm64 | shell installer or npm | +| Windows | x64, arm64 | PowerShell installer | +| macOS | x64, arm64 | shell installer | +| Linux | x64, arm64 | shell installer | See [Get Started](#get-started) for the one-line install commands. @@ -972,7 +973,7 @@ Framework routing is validated the same way, on a canonical app per framework: E **MCP hits `database is locked`** — current builds shouldn't: CodeGraph bundles its own Node runtime and uses Node's built-in `node:sqlite` in WAL mode, where concurrent reads never block on a writer. If you still see it: -- **You're on an old (pre-0.9) install.** Reinstall to get the bundled runtime — `curl -fsSL https://raw.githubusercontent.com/ardelperal/codegraph-vba/main/install.sh | sh` (macOS/Linux), `irm https://raw.githubusercontent.com/ardelperal/codegraph-vba/main/install.ps1 | iex` (Windows), or `npm i -g @aroman22/codegraph-vba@latest`. +- **You're on an old (pre-0.9) install.** Reinstall to get the bundled runtime — `curl -fsSL https://raw.githubusercontent.com/ardelperal/codegraph-vba/main/install.sh | sh` (macOS/Linux), `irm https://raw.githubusercontent.com/ardelperal/codegraph-vba/main/install.ps1 | iex` (Windows). - **`codegraph-vba status` shows `Journal:` other than `wal`** — WAL couldn't be enabled on this filesystem (common on network shares and WSL2 `/mnt`), so reads can block on writes. Move the project (with its `.codegraph/` folder) onto a local disk. **MCP server not connecting** — Your agent starts the server itself, so you don't launch it by hand. Make sure the project is initialized and indexed (`codegraph-vba status`) and that the path in your MCP config is correct. If it still won't connect, re-run `codegraph-vba install` to rewrite the config. diff --git a/__tests__/bundle-launchers.test.ts b/__tests__/bundle-launchers.test.ts new file mode 100644 index 00000000..0181f7f2 --- /dev/null +++ b/__tests__/bundle-launchers.test.ts @@ -0,0 +1,103 @@ +/** + * Bundle launcher names (issue #326). + * + * Agent MCP configs and Dysflow launch `codegraph-vba`, so a GitHub-only + * install (no npm) must put that name on PATH next to `codegraph`. These tests + * extract the REAL launcher block from `scripts/build-bundle.sh` and the REAL + * link block from `install.sh` (between their marker comments) and run them + * against temp fixtures — no build, no download. + * + * POSIX only: both blocks are shell, and the install.sh block uses symlinks. + */ + +import { describe, it, expect, beforeEach, afterEach } from 'vitest'; +import { spawnSync } from 'child_process'; +import * as fs from 'fs'; +import * as os from 'os'; +import * as path from 'path'; + +const ROOT = path.join(__dirname, '..'); + +function extractBlock(file: string, marker: string): string { + const lines = fs.readFileSync(path.join(ROOT, file), 'utf8').replace(/\r\n/g, '\n').split('\n'); + const i = lines.findIndex((l) => l.trim() === `# >>> ${marker}`); + const j = lines.findIndex((l) => l.trim() === `# <<< ${marker}`); + if (i < 0 || j < 0 || j <= i) throw new Error(`${marker} markers not found in ${file}`); + return lines.slice(i + 1, j).join('\n'); +} + +function shq(s: string): string { + return `'${s.replace(/'/g, `'\\''`)}'`; +} + +function run(shell: string, script: string): { code: number; stdout: string; stderr: string } { + const r = spawnSync(shell, ['-c', script], { encoding: 'utf8' }); + return { code: r.status ?? -1, stdout: r.stdout ?? '', stderr: r.stderr ?? '' }; +} + +describe.skipIf(process.platform === 'win32')('bundle launchers (#326)', () => { + let tmp: string; + + beforeEach(() => { + tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'cg-launchers-')); + }); + afterEach(() => { + fs.rmSync(tmp, { recursive: true, force: true }); + }); + + function stageBundle(osfam: string): string { + const stage = path.join(tmp, 'stage'); + fs.mkdirSync(path.join(stage, 'bin'), { recursive: true }); + // Stand-in for the vendored Node: prints the args it was exec'd with. + const fakeNode = path.join(tmp, 'fake-node'); + fs.writeFileSync(fakeNode, '#!/bin/sh\necho "node $*"\n', { mode: 0o755 }); + const script = + `set -eu\nOSFAM=${shq(osfam)}\nSTAGE=${shq(stage)}\nNODE_BIN=${shq(fakeNode)}\n` + + extractBlock('scripts/build-bundle.sh', 'CODEGRAPH_LAUNCHERS'); + const r = run('bash', script); + expect(r.code, r.stderr).toBe(0); + return stage; + } + + it('POSIX bundles ship an executable codegraph-vba launcher that runs the CLI', () => { + const stage = stageBundle('linux'); + const launcher = path.join(stage, 'bin', 'codegraph-vba'); + expect(fs.statSync(launcher).mode & 0o111).not.toBe(0); + + const r = spawnSync(launcher, ['--version'], { encoding: 'utf8' }); + expect(r.status).toBe(0); + expect(r.stdout).toContain(`${path.join(stage, 'lib/dist/bin/codegraph.js')} --version`); + }); + + it('Windows bundles ship codegraph-vba.cmd identical to codegraph.cmd', () => { + const stage = stageBundle('win32'); + const cmd = fs.readFileSync(path.join(stage, 'bin', 'codegraph.cmd'), 'utf8'); + expect(fs.readFileSync(path.join(stage, 'bin', 'codegraph-vba.cmd'), 'utf8')).toBe(cmd); + }); + + function linkLaunchers(dest: string): { binDir: string; stdout: string } { + const binDir = path.join(tmp, 'bin'); + const script = + `set -eu\nBIN_DIR=${shq(binDir)}\ndest=${shq(dest)}\n` + + extractBlock('install.sh', 'CODEGRAPH_LINK_LAUNCHERS'); + const r = run('sh', script); + expect(r.code, r.stderr).toBe(0); + return { binDir, stdout: r.stdout }; + } + + it('install.sh links both launchers onto PATH', () => { + const dest = stageBundle('linux'); + const { binDir } = linkLaunchers(dest); + expect(fs.readlinkSync(path.join(binDir, 'codegraph'))).toBe(path.join(dest, 'bin', 'codegraph')); + expect(fs.readlinkSync(path.join(binDir, 'codegraph-vba'))).toBe(path.join(dest, 'bin', 'codegraph-vba')); + }); + + it('install.sh leaves no dangling codegraph-vba link for an older bundle that lacks it', () => { + const dest = path.join(tmp, 'old-bundle'); + fs.mkdirSync(path.join(dest, 'bin'), { recursive: true }); + fs.writeFileSync(path.join(dest, 'bin', 'codegraph'), '#!/bin/sh\n', { mode: 0o755 }); + const { binDir } = linkLaunchers(dest); + expect(fs.existsSync(path.join(binDir, 'codegraph'))).toBe(true); + expect(fs.existsSync(path.join(binDir, 'codegraph-vba'))).toBe(false); + }); +}); diff --git a/__tests__/upgrade.test.ts b/__tests__/upgrade.test.ts index e781185e..7942c93a 100644 --- a/__tests__/upgrade.test.ts +++ b/__tests__/upgrade.test.ts @@ -21,6 +21,9 @@ import { readInstalledPackageVersion, resolveNpmGlobalRoot, NPM_PACKAGE, + cliInstallCommand, + INSTALL_SH_URL, + INSTALL_PS1_URL, type InstallMethod, type UpgradeDeps, } from '../src/upgrade'; @@ -154,6 +157,18 @@ describe('detectInstallMethod', () => { }); }); +describe('cliInstallCommand (#326)', () => { + it('installs from this repo\'s GitHub installer script, never npm', () => { + expect(cliInstallCommand('win32')).toContain(`irm ${INSTALL_PS1_URL} | iex`); + expect(cliInstallCommand('linux')).toBe(`curl -fsSL ${INSTALL_SH_URL} | sh`); + expect(cliInstallCommand('darwin')).toBe(`curl -fsSL ${INSTALL_SH_URL} | sh`); + for (const platform of ['win32', 'linux', 'darwin'] as const) { + expect(cliInstallCommand(platform)).not.toMatch(/\bnpm\b/); + } + expect(INSTALL_PS1_URL).toBe('https://raw.githubusercontent.com/ardelperal/codegraph-vba/main/install.ps1'); + }); +}); + describe('deriveInstallDir', () => { it('unix: returns the dir above versions/', () => { expect(deriveInstallDir('/a/b/.codegraph/versions/v1.2.3', 'unix', () => true)).toBe('/a/b/.codegraph'); @@ -403,6 +418,8 @@ describe('runUpgrade', () => { const code = await runUpgrade({}, deps); expect(code).toBe(1); expect(calls.errors.join('\n')).toMatch(/npm exited/i); + // The way out of a broken npm install is the npm-free installer (#326). + expect(calls.logs.join('\n')).toContain(cliInstallCommand('linux')); }); it('npx: nothing to upgrade', async () => { diff --git a/install.sh b/install.sh index 172089b1..829490d5 100755 --- a/install.sh +++ b/install.sh @@ -22,9 +22,9 @@ 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 -f "$BIN_DIR/codegraph" "$BIN_DIR/codegraph-vba" rm -rf "$INSTALL_DIR" - echo "CodeGraph uninstalled (removed $INSTALL_DIR and $BIN_DIR/codegraph)." + echo "CodeGraph uninstalled (removed $INSTALL_DIR, $BIN_DIR/codegraph and $BIN_DIR/codegraph-vba)." exit 0 fi @@ -76,13 +76,21 @@ mkdir -p "$dest" # Archives contain a top-level codegraph-/ 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. +# 4. Symlink the launchers onto PATH and mark the current version. +# >>> CODEGRAPH_LINK_LAUNCHERS mkdir -p "$BIN_DIR" ln -sf "$dest/bin/codegraph" "$BIN_DIR/codegraph" +echo "Linked $BIN_DIR/codegraph" +# Agent MCP configs and Dysflow launch `codegraph-vba` (issue #326). Bundles +# older than the release that added it only ship `codegraph`. +if [ -f "$dest/bin/codegraph-vba" ]; then + ln -sf "$dest/bin/codegraph-vba" "$BIN_DIR/codegraph-vba" + echo "Linked $BIN_DIR/codegraph-vba" +fi +# <<< CODEGRAPH_LINK_LAUNCHERS 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/ dir (~50 MB with the vendored Node diff --git a/scripts/build-bundle.sh b/scripts/build-bundle.sh index 29a99508..50159ea6 100755 --- a/scripts/build-bundle.sh +++ b/scripts/build-bundle.sh @@ -101,10 +101,16 @@ rm -f "$STAGE/lib/package-lock.json" "$STAGE/lib/pnpm-lock.yaml" # it. See issues #293/#298 and src/extraction/wasm-runtime-flags.ts. (The CLI # also self-relaunches with this flag when launched without it, so non-bundled # runs are covered too; passing it here avoids that extra spawn.) +# +# Two launcher names, same program: `codegraph` and `codegraph-vba`. Agent MCP +# configs and Dysflow launch `codegraph-vba`, so a GitHub-only install must put +# that name on PATH too (issue #326). +# >>> CODEGRAPH_LAUNCHERS if [ "$OSFAM" = "win32" ]; then cp "$NODE_BIN" "$STAGE/node.exe" printf '@"%%~dp0..\\node.exe" --liftoff-only "%%~dp0..\\lib\\dist\\bin\\codegraph.js" %%*\r\n' \ > "$STAGE/bin/codegraph.cmd" + cp "$STAGE/bin/codegraph.cmd" "$STAGE/bin/codegraph-vba.cmd" else cp "$NODE_BIN" "$STAGE/node" cat > "$STAGE/bin/codegraph" <<'LAUNCH' @@ -129,7 +135,10 @@ export CODEGRAPH_HOST_PPID exec "$DIR/node" --liftoff-only "$DIR/lib/dist/bin/codegraph.js" "$@" LAUNCH chmod +x "$STAGE/bin/codegraph" + cp "$STAGE/bin/codegraph" "$STAGE/bin/codegraph-vba" + chmod +x "$STAGE/bin/codegraph-vba" fi +# <<< CODEGRAPH_LAUNCHERS # 5. Archive (.zip for Windows, .tar.gz otherwise). mkdir -p "$OUT" diff --git a/src/bin/codegraph.ts b/src/bin/codegraph.ts index 19e98f83..6b7a49b1 100644 --- a/src/bin/codegraph.ts +++ b/src/bin/codegraph.ts @@ -54,7 +54,8 @@ async function loadCodeGraph(): Promise { console.error(`\x1b[31m${getGlyphs().err}\x1b[0m Failed to load CodeGraph modules.`); console.error(`\n Node: ${process.version} Platform: ${process.platform} ${process.arch}`); console.error(`\n Error: ${msg}`); - console.error('\n Try reinstalling with: npm install -g @colbymchenry/codegraph\n'); + const { cliInstallCommand } = await import('../upgrade'); + console.error(`\n Try reinstalling with: ${cliInstallCommand(process.platform)}\n`); process.exit(1); } } diff --git a/src/installer/index.ts b/src/installer/index.ts index f082d306..41a09b75 100644 --- a/src/installer/index.ts +++ b/src/installer/index.ts @@ -29,6 +29,7 @@ import { watchDisabledReason } from '../sync/watch-policy'; import { isGitRepo, isSyncHookInstalled, installGitSyncHook } from '../sync/git-hooks'; import { getCodeGraphDir, codeGraphDirName } from '../directory'; import { getTelemetry, TELEMETRY_DOCS } from '../telemetry'; +import { cliInstallCommand } from '../upgrade'; // Backwards-compat: keep these named exports — downstream code may // import them. The shim in `config-writer.ts` continues to re-export @@ -100,8 +101,8 @@ export async function runInstallerWithOptions(opts: RunInstallerOptions): Promis return; } - // Step 2: install the codegraph npm package on PATH (always offered; - // matches existing behavior). Skipped when --yes (assume present). + // Step 2: install the CLI on PATH from GitHub Releases (always offered; + // no npm — issue #326). Skipped when --yes (assume present). if (!useDefaults) { const shouldInstallGlobally = await clack.confirm({ message: 'Install the codegraph CLI on your PATH? (Required so agents can launch the MCP server)', @@ -114,14 +115,15 @@ export async function runInstallerWithOptions(opts: RunInstallerOptions): Promis if (shouldInstallGlobally) { const s = clack.spinner(); s.start('Installing codegraph CLI...'); + const installCommand = cliInstallCommand(process.platform); try { - // Generous bound (slow networks / cold npm cache) — but bounded, so a - // wedged npm can't hang the interactive installer forever (#1139). - execSync('npm install -g @aroman22/codegraph-vba', { stdio: 'pipe', windowsHide: true, timeout: 120_000 }); + // Generous bound (the bundle carries its own Node runtime) — but + // bounded, so a wedged download can't hang the installer forever (#1139). + execSync(installCommand, { stdio: 'pipe', windowsHide: true, timeout: 300_000 }); s.stop('Installed codegraph CLI on PATH'); } catch { - s.stop('Could not install (permission denied)'); - clack.log.warn('Try: sudo npm install -g @aroman22/codegraph-vba'); + s.stop('Could not install the codegraph CLI'); + clack.log.warn(`Run it yourself: ${installCommand}`); } } else { clack.log.info('Skipped CLI install — agents will not be able to launch the MCP server without it'); diff --git a/src/upgrade/index.ts b/src/upgrade/index.ts index 3a675267..01cfba44 100644 --- a/src/upgrade/index.ts +++ b/src/upgrade/index.ts @@ -33,6 +33,18 @@ export const REPO = 'ardelperal/codegraph-vba'; export const NPM_PACKAGE = '@aroman22/codegraph-vba'; const RAW_BASE = `https://raw.githubusercontent.com/${REPO}/main`; export const INSTALL_SH_URL = `${RAW_BASE}/install.sh`; +export const INSTALL_PS1_URL = `${RAW_BASE}/install.ps1`; + +/** + * The one-line shell command that installs the CLI from GitHub Releases on + * this platform (issue #326 — no npm). Used both to run the install and in + * user-facing hints, so the two can never disagree. + */ +export function cliInstallCommand(platform: NodeJS.Platform): string { + return platform === 'win32' + ? `powershell -NoProfile -ExecutionPolicy Bypass -Command "irm ${INSTALL_PS1_URL} | iex"` + : `curl -fsSL ${INSTALL_SH_URL} | sh`; +} // --------------------------------------------------------------------------- // Install-method detection (pure — fully unit-testable via injected probes) @@ -794,6 +806,7 @@ function upgradeNpm( deps.log(c.dim('If this is a permissions error (EACCES), your global prefix needs sudo, or use a')); deps.log(c.dim('Node version manager (nvm/fnm) so global installs don’t require root.')); } + deps.log(c.dim(`Or switch to the standalone install, which needs no npm: ${cliInstallCommand(deps.platform)}`)); return 1; } deps.log('');