Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 27 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,17 @@ name: Release
# native compilation, so cross-packaging is fine),
# 4. creates the GitHub Release (tag v<version>) 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
# `## [<version>]` block. Set the NPM_TOKEN secret.
# `## [<version>]` 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: {}

Expand Down Expand Up @@ -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: |
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
43 changes: 22 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
```

<details>
<summary><b>Already have Node? Use npm instead (works on any version)</b></summary>

```bash
npm i -g @aroman22/codegraph-vba
```

<sub>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.</sub>

<sub>**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 <version>` to pin one.</sub>

<details>
<summary><b>npm (legacy)</b></summary>

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.

</details>

### 2. Wire up your agent(s)
Expand All @@ -119,7 +117,7 @@ In a **new terminal**, run the installer to connect CodeGraph to the agents you
codegraph-vba install
```

<sub>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.)</sub>
<sub>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.</sub>

### 3. Initialize each project

Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -600,9 +600,10 @@ That's it — your agent will use CodeGraph tools automatically when a `.codegra
<details>
<summary><strong>Manual Setup (Alternative)</strong></summary>

**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`:**
Expand Down Expand Up @@ -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.

Expand Down Expand Up @@ -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.
Expand Down
103 changes: 103 additions & 0 deletions __tests__/bundle-launchers.test.ts
Original file line number Diff line number Diff line change
@@ -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);
});
});
17 changes: 17 additions & 0 deletions __tests__/upgrade.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ import {
readInstalledPackageVersion,
resolveNpmGlobalRoot,
NPM_PACKAGE,
cliInstallCommand,
INSTALL_SH_URL,
INSTALL_PS1_URL,
type InstallMethod,
type UpgradeDeps,
} from '../src/upgrade';
Expand Down Expand Up @@ -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');
Expand Down Expand Up @@ -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 () => {
Expand Down
16 changes: 12 additions & 4 deletions install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -76,13 +76,21 @@ 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.
# 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/<v> dir (~50 MB with the vendored Node
Expand Down
9 changes: 9 additions & 0 deletions scripts/build-bundle.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -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"
Expand Down
3 changes: 2 additions & 1 deletion src/bin/codegraph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ async function loadCodeGraph(): Promise<typeof import('../index')> {
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);
}
}
Expand Down
Loading
Loading