{"_id":"@alaa-taieb/open-codemap","_rev":"2-a3077a382a2d9412e1989d28f6dd847f","name":"@alaa-taieb/open-codemap","dist-tags":{"latest":"0.1.1"},"versions":{"0.1.0":{"name":"@alaa-taieb/open-codemap","version":"0.1.0","keywords":["code-indexing","retrieval","rag","tree-sitter","embeddings","codebase-indexer","semantic-search"],"author":{"name":"Open-Codemap Contributors"},"license":"MIT","_id":"@alaa-taieb/open-codemap@0.1.0","maintainers":[{"name":"alaa-taieb","email":"alaataieb.tn@gmail.com"}],"homepage":"https://github.com/Alaa-Taieb/Open-Codemap#readme","bugs":{"url":"https://github.com/Alaa-Taieb/Open-Codemap/issues"},"bin":{"open-codemap":"dist/cli/index.js"},"dist":{"shasum":"825c7ddb85cdf5968c10877130ccbfa75ad8569d","tarball":"https://registry.npmjs.org/@alaa-taieb/open-codemap/-/open-codemap-0.1.0.tgz","fileCount":13,"integrity":"sha512-Od/rSEQhSzNtZz/Ybe57iQY0FmNS3l34qrqj6y0AugH5LfachP8w+oz8RcyIs5/d+Hl9yoS1B8TqbVIgFWc0BQ==","signatures":[{"sig":"MEUCIQCrfhRHjnppsIN5lZTr6V5kkVdCxbCGUZJ9uxSW8O60XgIgUgy6/+z/tO8PqsDM9zbgNvU66fDD9ahwMO8iC3BixtI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":467879},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.5","pnpm":">=10"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./api":{"types":"./dist/api/index.d.ts","import":"./dist/api/index.js"},"./cli":{"types":"./dist/cli/index.d.ts","import":"./dist/cli/index.js"}},"gitHead":"8b1e071efe12749ecc0d8c902cad3662936c7929","scripts":{"lint":"eslint .","test":"vitest run","build":"tsup","format":"prettier --write .","prepack":"pnpm build","prepare":"husky || true","typecheck":"tsc --noEmit","test:watch":"vitest","postinstall":"husky install || true","prepublishOnly":"pnpm build"},"_npmUser":{"name":"alaa-taieb","email":"alaataieb.tn@gmail.com"},"repository":{"url":"git+https://github.com/Alaa-Taieb/Open-Codemap.git","type":"git"},"_npmVersion":"11.12.1","description":"Local-first, open-source codebase indexer + retriever — usable as a TypeScript library, a CLI, and an HTTP API.","directories":{},"sideEffects":false,"_nodeVersion":"24.15.0","dependencies":{"ora":"^8.1.0","zod":"^3.23.8","ignore":"^5.3.2","fastify":"^4.28.1","p-limit":"^6.1.0","chokidar":"^4.0.1","commander":"^12.1.0","fast-glob":"^3.3.2","web-tree-sitter":"0.26.11","tree-sitter-wasm":"1.1.2"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.0","husky":"^9.1.6","eslint":"^9.13.0","vitest":"^2.1.8","prettier":"^3.3.3","@eslint/js":"^9.13.0","typescript":"^5.7.2","@types/node":"^22.10.0","lint-staged":"^15.2.10","@changesets/cli":"^2.27.9","@commitlint/cli":"^19.5.0","typescript-eslint":"^8.11.0","@commitlint/config-conventional":"^19.5.0"},"_npmOperationalInternal":{"tmp":"tmp/open-codemap_0.1.0_1784331531462_0.5933659159661981","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@alaa-taieb/open-codemap","version":"0.1.1","description":"Local-first, open-source codebase indexer + retriever — usable as a TypeScript library, a CLI, and an HTTP API.","license":"MIT","repository":{"type":"git","url":"git+https://github.com/Alaa-Taieb/Open-Codemap.git"},"homepage":"https://github.com/Alaa-Taieb/Open-Codemap#readme","bugs":{"url":"https://github.com/Alaa-Taieb/Open-Codemap/issues"},"author":{"name":"Open-Codemap Contributors"},"keywords":["code-indexing","retrieval","rag","tree-sitter","embeddings","codebase-indexer","semantic-search"],"type":"module","engines":{"node":">=22.5","pnpm":">=10"},"sideEffects":false,"main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./cli":{"types":"./dist/cli/index.d.ts","import":"./dist/cli/index.js","require":"./dist/cli/index.cjs"},"./api":{"types":"./dist/api/index.d.ts","import":"./dist/api/index.js","require":"./dist/api/index.cjs"}},"bin":{"open-codemap":"dist/cli/index.js"},"scripts":{"build":"tsup","typecheck":"tsc --noEmit","lint":"eslint .","format":"prettier --write .","test":"vitest run","test:watch":"vitest","prepare":"node -e \"if(require('fs').existsSync('.husky')){require('child_process').execSync('husky',{stdio:'inherit'})}\"","prepublishOnly":"pnpm build","prepack":"pnpm build"},"dependencies":{"chokidar":"^4.0.1","commander":"^12.1.0","fast-glob":"^3.3.2","fastify":"^4.28.1","ignore":"^5.3.2","ora":"^8.1.0","p-limit":"^6.1.0","tree-sitter-wasm":"1.1.2","web-tree-sitter":"0.26.11","zod":"^3.23.8"},"devDependencies":{"@changesets/cli":"^2.27.9","@commitlint/cli":"^19.5.0","@commitlint/config-conventional":"^19.5.0","@eslint/js":"^9.13.0","@types/node":"^22.10.0","eslint":"^9.13.0","husky":"^9.1.6","lint-staged":"^15.2.10","prettier":"^3.3.3","tsup":"^8.3.0","typescript":"^5.7.2","typescript-eslint":"^8.11.0","vitest":"^2.1.8"},"gitHead":"fcb1eab01eed83be35672be7d62e2534f59044d6","_id":"@alaa-taieb/open-codemap@0.1.1","_nodeVersion":"24.15.0","_npmVersion":"11.12.1","dist":{"integrity":"sha512-eqOYLkTi9duSJhS1JSuYrWfWj6nu0freFvGVUQoux4JTglr769USGAbegMEa3ZHo+D6v8c6M60cdzTyWFeUh4g==","shasum":"a1a8d0a50ab266b5132a1b307d971c3fc8c0e16a","tarball":"https://registry.npmjs.org/@alaa-taieb/open-codemap/-/open-codemap-0.1.1.tgz","fileCount":23,"unpackedSize":962752,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCsqYZfgU05My5d/GDkdeiVXMxPoyH8Yr8zNnQibfZfbQIgF6ox9VdhdYJeOUTcP0dbTCmBi8GLGvccy5AcTcSxJFI="}]},"_npmUser":{"name":"alaa-taieb","email":"alaataieb.tn@gmail.com"},"directories":{},"maintainers":[{"name":"alaa-taieb","email":"alaataieb.tn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/open-codemap_0.1.1_1784357819863_0.2770967248430436"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-17T23:38:51.312Z","modified":"2026-07-18T06:57:00.183Z","0.1.0":"2026-07-17T23:38:51.787Z","0.1.1":"2026-07-18T06:57:00.043Z"},"bugs":{"url":"https://github.com/Alaa-Taieb/Open-Codemap/issues"},"author":{"name":"Open-Codemap Contributors"},"license":"MIT","homepage":"https://github.com/Alaa-Taieb/Open-Codemap#readme","keywords":["code-indexing","retrieval","rag","tree-sitter","embeddings","codebase-indexer","semantic-search"],"repository":{"type":"git","url":"git+https://github.com/Alaa-Taieb/Open-Codemap.git"},"description":"Local-first, open-source codebase indexer + retriever — usable as a TypeScript library, a CLI, and an HTTP API.","maintainers":[{"name":"alaa-taieb","email":"alaataieb.tn@gmail.com"}],"readme":"# Open-Codemap\n\n> Local-first, open-source codebase indexer + retriever — usable as a TypeScript library, a CLI, and an HTTP API.\n\nOpen-Codemap parses **any** repository with tree-sitter, chunks it into\nstructurally-coherent units (functions, classes, methods), embeds it with a swappable\nembedder, stores everything in a single portable SQLite file per workspace, and answers\nqueries through **hybrid** retrieval (vector ⊕ BM25 ⊕ graph), fused via Reciprocal Rank\nFusion (RRF).\n\n## Why\n\nAI coding assistants are only as good as the code they can _find_. Generic \"dump the repo\ninto a prompt\" approaches lose structure and drown on large codebases. Open-Codemap gives\nyou precise, ranked code locations — combining **meaning** (embeddings), **exact\nidentifiers** (BM25), and **code-structure relationships** (an import/call graph) — so a\nretrieval call returns the _right_ function, not a fuzzy blob.\n\nIt is local-first and open-source (MIT): one core engine, exposed three ways (library,\nCLI, HTTP API), with no lock-in to a paid embedding provider.\n\n## Quickstart\n\n```bash\npnpm install\npnpm build\n\n# Build an index of any repo (uses the deterministic mock embedder — no API key needed).\nnode dist/cli/index.js index ./my-repo --embedder mock\n\n# Ask an identifier question (exact name match via BM25).\nnode dist/cli/index.js query ./my-repo \"getAuthToken\" --json\n\n# Ask a plain-English question (semantic via vector).\nnode dist/cli/index.js query ./my-repo \"where do we validate login\" --json\n\n# List indexed workspaces.\nnode dist/cli/index.js list ./my-repo\n\n# Start the HTTP API.\nnode dist/cli/index.js serve ./my-repo --embedder mock\n```\n\nA ready-made sample lives in [`examples/sample-repo`](./examples/sample-repo):\n\n```bash\nnode dist/cli/index.js index examples/sample-repo --embedder mock\nnode dist/cli/index.js query examples/sample-repo \"where do we validate login\" --json\n```\n\n### Global install\n\nYou can install the CLI globally and run it from anywhere using the bare `open-codemap` bin:\n\n```bash\nnpm install -g open-codemap\n\n# then use the bare bin from any directory:\nopen-codemap index ./my-repo --embedder mock\nopen-codemap query ./my-repo \"where do we validate login\" --json\n```\n\n## Architecture\n\n```mermaid\nflowchart LR\n  subgraph Core[\"Open-Codemap core (one engine)\"]\n    P[Parser<br/>tree-sitter WASM]\n    C[Chunker<br/>cAST + windowed fallback]\n    E[Embedder<br/>pluggable]\n    S[Store<br/>SQLite + FTS5 + graph]\n    I[Indexer<br/>incremental + watch]\n    R[Retriever<br/>hybrid RRF]\n  end\n\n  Repo[(Repository files)] --> I\n  I --> P --> C --> E --> S\n  Q[Query] --> R\n  S --> R\n\n  subgraph Adapters[\"Thin adapters\"]\n    CLI[CLI<br/>commander + ora]\n    API[HTTP API<br/>Fastify + jobs]\n    LIB[Library<br/>TypeScript]\n  end\n\n  I -.used by.-> CLI\n  R -.used by.-> CLI\n  I -.used by.-> API\n  R -.used by.-> API\n  I -.used by.-> LIB\n  R -.used by.-> LIB\n```\n\n- **Parser** — [`web-tree-sitter`](https://www.npmjs.com/package/web-tree-sitter) with\n  prebuilt grammar `.wasm` from\n  [`tree-sitter-wasm`](https://www.npmjs.com/package/tree-sitter-wasm) (covers the v1\n  set: JavaScript, TypeScript/TSX, Python, Go, Rust, Java, C, C++, C#, Ruby, plus ~140\n  more). Unsupported/unparseable files fall back to a sliding-window chunker.\n- **Chunker** — cAST-style recursive chunking: one chunk per top-level\n  function/class/method, recursively split when over the token budget, with a\n  sliding-window fallback for plain text.\n- **Embedder** — pluggable interface (`mock` / `voyage` / `jina`). The **mock**\n  `HashEmbedder` is deterministic and needs no network or API key — it powers the test\n  suite and quickstart.\n- **Store** — one portable SQLite file per workspace. Relational tables\n  (`chunks`, `symbols`, `edges`, `manifest`) + **FTS5** for BM25 + JS-computed cosine KNN\n  over stored embeddings. The `Store` interface isolates the storage backend so a native\n  `sqlite-vec`/`vec0` engine can be swapped in later.\n- **Indexer** — walks files honoring `.gitignore`, hashes each, and re-embeds **only\n  changed chunks** (incremental). Moved/renamed code is fixed up by `contentHash`\n  without re-embedding. Optional `--watch` mode keeps the index live.\n- **Retriever** — hybrid vector ⊕ BM25 ⊕ graph, fused with RRF (k=60). Optional\n  `expandGraph` pulls in a chunk's import/call neighbors. Degrades gracefully to\n  BM25+graph if the embedder fails.\n\n## Library usage\n\n```ts\nimport {\n  Indexer,\n  Retriever,\n  SqliteStore,\n  WorkspaceRegistry,\n  HashEmbedder,\n  TreeSitterParser,\n} from 'open-codemap';\n\nconst embedder = new HashEmbedder(1024); // swap for VoyageEmbedder / JinaEmbedder\nconst parser = new TreeSitterParser();\nconst registry = new WorkspaceRegistry();\n\nconst indexer = new Indexer({ embedder, parser, registry });\nawait indexer.index('./my-repo'); // builds .codemap/<repo>.sqlite\n\nconst store = await registry.open('./my-repo', { dims: embedder.dims });\n// `repoId` is REQUIRED — the same id the indexer used (a workspace is scoped to one repo).\nconst rid = await registry.resolveRepoId('./my-repo');\nconst retriever = new Retriever({ store, embedder, repoId: rid });\n\nconst results = await retriever.retrieve({\n  text: 'where do we validate login',\n  topK: 5,\n  expandGraph: true,\n});\nfor (const r of results) {\n  console.log(`${r.score.toFixed(3)} [${r.mode}] ${r.chunk.file}:${r.chunk.symbol}`);\n}\n```\n\n> **`repoId` is required.** `new Retriever({ store, embedder })` throws a `ConfigError`\n> (`Retriever requires a \\`repoId\\` ...`) unless `repoId`is supplied. Obtain it via`WorkspaceRegistry.resolveRepoId(repoPath)`or`repoId(repoPath)`.\n\n### Library API notes\n\n- **`QueryRequest` has no `mode`.** `mode` (`bm25` | `vector` | `graph` | `rrf`) is a\n  **result** field on each `QueryResult`, describing which signal contributed the\n  winning RRF term — not something you pass on the request. Requests take\n  `{ text, topK?, filters?, expandGraph? }`.\n- **`embed()` is batched.** Every `Embedder.embed(texts: string[])` takes an **array** of\n  strings and returns `EmbeddingVector[]` (one per input), not a single string. Use\n  `embedBatch(embedder, texts)` to chunk very large inputs into fixed-size batches.\n- **CommonJS is supported.** v0.1.1+ ships dual ESM + CJS builds, so\n  `require('@alaa-taieb/open-codemap')` works in Node CJS / Electron apps:\n\n  ```js\n  const {\n    Indexer,\n    Retriever,\n    HashEmbedder,\n    TreeSitterParser,\n    VERSION,\n  } = require('@alaa-taieb/open-codemap');\n  ```\n\n## Embedder configuration\n\nThe default embedder is **Voyage `code-3`** (`voyage-code-3`, 1024-dim, code-tuned). Set\nthe key via env var or flag:\n\n```bash\nexport VOYAGE_AI_API_KEY=...\nnode dist/cli/index.js index ./my-repo --embedder voyage\n```\n\n| Kind     | Model                | Env var             | Notes                                        |\n| -------- | -------------------- | ------------------- | -------------------------------------------- |\n| `mock`   | `HashEmbedder`       | —                   | Deterministic, no network/key. Tests + demo. |\n| `voyage` | `voyage-code-3`      | `VOYAGE_AI_API_KEY` | Default paid backend (code-tuned, 32K ctx).  |\n| `jina`   | `jina-embeddings-v3` | `JINA_API_KEY`      | OSS-friendly fallback.                       |\n\n> **Switching embedder dims requires re-indexing.** If you change the embedding width\n> (e.g. swap Voyage for an OSS model with different dims), pass `--rebuild` (or\n> `reindex: true` in the library) to drop and recreate the index. The engine enforces\n> dim-consistency so KNN distances stay meaningful.\n\n## HTTP API\n\n```bash\nnode dist/cli/index.js serve ./my-repo --embedder mock --port 8787\n```\n\n| Method | Path          | Body                                                       | Description                                         |\n| ------ | ------------- | ---------------------------------------------------------- | --------------------------------------------------- |\n| POST   | `/index`      | `{ repo, embedder?, reindex? }`                            | Starts a background index job; returns `{ jobId }`. |\n| GET    | `/jobs/:id`   | —                                                          | Poll job status / progress / result.                |\n| POST   | `/query`      | `{ repo, text, topK?, expandGraph?, filters?, embedder? }` | Synchronous hybrid retrieval.                       |\n| GET    | `/workspaces` | —                                                          | List indexed workspaces.                            |\n\n> **`POST /query`** — Pass `repo` (required) to select which indexed workspace to query.\n> All other body fields are optional.\n\n## Scripts\n\n| Script           | Purpose                                   |\n| ---------------- | ----------------------------------------- |\n| `pnpm build`     | Bundle `index` / `cli` / `api` with tsup. |\n| `pnpm typecheck` | `tsc --noEmit` (strict).                  |\n| `pnpm lint`      | ESLint (flat config) + Prettier.          |\n| `pnpm test`      | Vitest unit + integration + e2e.          |\n\n## Limits & open questions\n\n1. **Storage backend is Node's built-in `node:sqlite` (Node 22+) + JS KNN** (not native\n   `sqlite-vec`). The `Store` interface isolates this; a native `vec0` backend is a later\n   swap. Hybrid retrieval behavior is unchanged. Requires Node ≥ 22.5 (see `engines` in\n   `package.json`).\n2. **Embedder dims consistency** — index + query embedders must share `dims`; switching\n   requires `--rebuild`.\n3. **Graph precision** — v1 ships the import graph + a best-effort call graph from\n   tree-sitter symbol queries. Precise call graphs (across files/overloads) are deferred\n   to an optional LSP/SCIP pass.\n4. **Reranker** — RRF-only for MVP; a pluggable `Reranker` hook ships but is optional.\n5. **No C/C++ compiler on some environments** — the WASM tree-sitter choice (plus Node's\n   built-in `node:sqlite`) means Open-Codemap builds and runs with zero native compilation.\n\n## License\n\nMIT\n","readmeFilename":"README.md"}