Skip to content

feat(npm): restore programmatic/embedded SDK API (#354)#603

Merged
colbymchenry merged 1 commit into
mainfrom
fix/sdk-programmatic-api
Jun 1, 2026
Merged

feat(npm): restore programmatic/embedded SDK API (#354)#603
colbymchenry merged 1 commit into
mainfrom
fix/sdk-programmatic-api

Conversation

@colbymchenry
Copy link
Copy Markdown
Owner

Closes #354.

Problem

The 0.9.x thin-installer made @colbymchenry/codegraph a bin-only shim — the compiled library moved into the per-platform optionalDependency bundle and the main package re-exported nothing. So for anyone embedding CodeGraph as a library (the issue author runs it inside an Electron app, upgrading from 0.8.0):

  • require("@colbymchenry/codegraph")MODULE_NOT_FOUND
  • no types, no main, no exports

Fix

Restore programmatic use without re-bloating the thin shim or duplicating the ~49 MB of tree-sitter grammars the per-platform bundle already carries:

  • mainnpm-sdk.js re-exports the installed per-platform bundle's compiled library (lib/dist/index.js) at runtime, reusing that bundle's own node_modules. Falls back to a self-healed cache bundle (issue no prebuilt bundle for darwin-arm64 #303 path), else throws an actionable "install from the official registry" error instead of a bare MODULE_NOT_FOUND.
  • types → ship the .d.ts tree only (~590 KB) in the main package, built from the same release so it can never skew from the runtime it re-exports.
  • exports map resolves the types condition (nodenext) and the default entry.
  • DatabaseConnection + QueryBuilder are now top-level exports, so embedded callers get the building blocks from the package entry rather than deep dist/ imports (which the shim no longer ships). Everything else the issue lists (CodeGraph, initGrammars/loadGrammarsForLanguages, FileLock) was already a top-level export.

The CLI/MCP bin keeps exec'ing the bundled Node — only library consumers run on their own runtime, which must be Node 22.5+ for the built-in node:sqlite (Electron qualifies when its Node is ≥22.5). node:sqlite is touched lazily, so require() itself loads fine on older Node and only errors when a graph is actually opened.

Note on what is not restored

The config.js module (validateConfig/createDefaultConfig/CodeGraphConfig) the issue mentions was removed in 0.9.x when CodeGraph went zero-config (indexing is driven by .gitignore); it isn't reintroduced here.

Validation

End-to-end against real packed artifacts (not mocks):

  1. Built a real darwin-arm64 bundle (build-bundle.sh) and packed the npm packages (pack-npm.sh).
  2. Assembled a throwaway consumer node_modules from exactly those artifacts and, on the host Node (v22.20.0):
    • require("@colbymchenry/codegraph") exposes CodeGraph, DatabaseConnection, QueryBuilder, initGrammars, FileLock, getDatabasePath, MCPServer, default = CodeGraph.
    • Full round-trip: CodeGraph.initindexAll (real tree-sitter, 1 file / 3 nodes / 3 edges) → searchNodes, plus the low-level DatabaseConnection.open + new QueryBuilder path.
    • Types type-check under nodenext (exercises exports.types) and classic node resolution with realistic settings (skipLibCheck: true + @types/node).
    • The CLI shim still launches the bundled Node (--version, status).
  3. npm test: 1090 passing; the only failures are the 5 pre-existing npm-shim.test.ts download-fallback cases, which fail identically on origin/main (unrelated, environmental). New __tests__/npm-sdk.test.ts covers SDK resolution, cache fallback, and the missing-bundle error.

🤖 Generated with Claude Code

The 0.9.x thin-installer turned @colbymchenry/codegraph into a bin-only
shim: require("@colbymchenry/codegraph") threw MODULE_NOT_FOUND and no
types shipped, breaking embedded library consumers (e.g. Electron apps)
upgrading from 0.8.0.

Restore programmatic use without re-bloating the thin shim or duplicating
the ~49 MB of grammars the per-platform bundle already carries:

- main -> npm-sdk.js re-exports the installed per-platform bundle's compiled
  library (lib/dist/index.js) at runtime, reusing that bundle's own deps; it
  falls back to a self-healed cache bundle, else throws an actionable error.
- types -> ship the .d.ts tree only (~590 KB) in the main package, built from
  the same release so it can never skew from the runtime it re-exports.
- exports map resolves the `types` condition (nodenext) and the default entry.
- DatabaseConnection + QueryBuilder are now top-level exports, so embedded
  callers get the building blocks from the package entry instead of deep
  dist/ imports (which the shim no longer ships).

The CLI/MCP `bin` keeps execing the bundled Node; only library consumers run
on their own runtime, which must be Node 22.5+ for the built-in node:sqlite.

Validated end-to-end: built a real darwin-arm64 bundle, packed the npm
packages, installed them into a throwaway consumer, and confirmed require()
plus a full init/indexAll/searchNodes round-trip and the low-level
DatabaseConnection/QueryBuilder path all work on the host Node; types resolve
under both nodenext and classic node resolution; and the CLI shim still
launches. New hermetic tests cover npm-sdk resolution, cache fallback, and the
missing-bundle error.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@colbymchenry colbymchenry merged commit 89d4d37 into main Jun 1, 2026
@colbymchenry colbymchenry deleted the fix/sdk-programmatic-api branch June 1, 2026 00:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0.9.x SDK/programmatic API usage: timeline and plan?

1 participant