git clone https://github.com/your-org/OpenCodeRAG.git
cd OpenCodeRAG
npm install --legacy-peer-depsLanceDB and other dependencies have peer dependency conflicts —
--legacy-peer-depsis required.
| Command | Description |
|---|---|
npm test |
Run all tests (node --import tsx --test --test-force-exit "src/**/*.test.ts") |
npm run typecheck |
Type-check without emitting (tsc --noEmit) |
npm run cli |
Run the CLI via tsx src/cli.ts |
npm run build |
Build TypeScript to dist/ |
npm run release:patch |
Bump version, build, publish |
Framework: Node.js built-in test runner (node:test), no Jest/Mocha/Vitest.
# Run all tests
npm test
# Run a single test file
node --import tsx --test src/__tests__/chunker/fallback.test.ts
# Run chunker tests
node --import tsx --test "src/__tests__/chunker/*.test.ts"
# Run with typecheck first
npm run typecheck && npm testImportant: --test-force-exit is required because chokidar and LanceDB leave open handles. Without it, the test suite hangs after completion.
LanceDB tests: Use memory:// URI — data is discarded after each test. Requires native binary support (works on Win/Linux/Mac x64+arm).
Test file structure: Mirrors src/ — src/__tests__/chunker/ tests src/chunker/, etc.
The test suite currently has 589+ tests (1 integration test requiring the OpenCode binary, all others unit tests).
TypeScript is used for type checking only — there is no build step for development. tsx handles TypeScript at runtime.
npm run typecheck # tsc --noEmitAll imports use .js extensions and node: prefixes:
import { readFileSync } from "node:fs";
import path from "node:path";
import { Chunk } from "./core/interfaces.js";Module boundaries are defined by interfaces in core/interfaces.ts. Concrete implementations implement them:
class LanceDbStore implements VectorStore { ... }
class OllamaEmbedder implements EmbeddingProvider { ... }
class TypeScriptChunker extends TreeSitterChunker { ... }Dispatch is handled through factories:
getChunker(filePath)/chunkFile(filePath, content)createEmbedder(config)/embedBatch(embedder, texts)createDescriptionProvider(config)
LanceDbStore implements VectorStore; provider classes implement EmbeddingProvider.
Plugin and CLI catch errors silently where appropriate. Type errors are surfaced via TypeScript.
Simple internal uuid() in chunker/uuid.ts (no external dependency).
src/
core/ — Interfaces, config, manifest, runtime overrides
chunker/ — All chunker implementations (25 files)
embedder/ — Embedding providers + HTTP transport
describer/ — LLM description providers
vectorstore/ — LanceDB vector store
retriever/ — Retrieval pipeline + keyword index
opencode/ — OpenCode integration utilities
tui/ — TUI sidebar components
types/ — Local type declarations
indexer.ts — Index pipeline
watcher.ts — Background file watcher
plugin.ts — Main plugin
cli.ts — CLI interface
tui.ts — TUI plugin
index.ts — Public API exports
__tests__/ — Test suite
- Create
src/embedder/<name>.tsimplementingEmbeddingProvider - Add dispatch in
createEmbedder()infactory.ts - Update
RagConfig.embedding.providerunion type inconfig.ts
See Chunking.
npm run release:patchThis runs scripts/release-patch.js which:
- Creates a new git branch
- Bumps the patch version
- Builds the project (
tsc -p tsconfig.build.json) - Runs tests
- Creates a git tag and commit
- Publishes to npm (dry-run supported via
--dryflag)
- Use
--legacy-peer-deps— LanceDB has peer dependency conflicts - Corporate SSL:
set NODE_TLS_REJECT_UNAUTHORIZED=0beforenpm install
LanceDB's TS API expects Record<string, unknown>[] for data inputs. Cast through unknown:
await table.add(rows as unknown as Record<string, unknown>[]);@vscode/tree-sitter-wasmprovides pre-built WASM grammars for 16 languages- Self-bundled
.wasmfiles inwasm/cover 12 additional languages - All parsing is WASM-based via
web-tree-sitter web-tree-sitterusesNodetype (notSyntaxNode)Parseris a class (notnew Parser())Languageis a top-level class
@opencode-ai/plugin lives in .opencode/node_modules/ — not installed via npm. Types are declared locally in src/types/opencode-plugin.d.ts.
loadConfig()deep-merges per section (not recursive)- CLI auto-detects
./opencode-rag.jsonand./.opencode/rag.json - Default config is the fallback when no file is found
- Ollama may return
{ embedding: number[] }or{ embeddings: number[][] }— both shapes are accepted embedding.timeoutMsdefaults to 30000ms (was 5000ms, too short for cold starts)