Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

codemap

Local-first repo intelligence for JavaScript/TypeScript codebases, built so AI coding agents can find the right files, symbols and routes before editing.

Source code never leaves the machine. The index is a plain SQLite file beside the repo.

Status

v1 command set complete: index, files, symbol, map and task all work end to end (see the SRS).

Install

cargo build --release

Use

# Build or refresh the index
codemap index /path/to/repo

# What's in there
codemap files /path/to/repo --kind source
codemap files /path/to/repo --json

# Where is this symbol, and what depends on its file
codemap symbol /path/to/repo ConfirmSubmitButton

# High-level repo map
codemap map /path/to/repo

# Paste a ticket, get the files to read first
codemap task /path/to/repo --text "$(pbpaste)"
codemap task /path/to/repo --text "..." --json --limit 8

Example, against a real Next.js app:

$ codemap index ./aircraftspa
indexed /path/to/aircraftspa
  files            202
  symbols          238
  imports          343 (146 resolved locally)
  packages         1
  index            /path/to/aircraftspa/.codemap/index.db

$ codemap symbol ./aircraftspa ConfirmSubmitButton
ConfirmSubmitButton exported component — src/components/ConfirmSubmitButton.tsx:13-35
  imported by 2 file(s):
    src/app/account/aircraft/page.tsx
    src/components/ConfirmSubmitButton.test.tsx

Does it actually work?

The honest test is whether a real ticket finds the files a human went to. Pasting the text of CHA-1924 — a bug about the Cancel button on the requests page — into an index of the app it was filed against:

$ codemap task ./aircraftspa --text "My Requests Cancel button has no
  confirmation dialog and no revert. Clicking Cancel this request immediately
  changes the request status from Requested to Cancelled..."

**Confidence:** high

## Candidate files
- `src/app/account/requests/actions.ts` (102) — path contains requests;
      defines `cancelRequestAction` (function); imported by 2 file(s)
- `src/lib/portal-db.ts` (90) — defines `cancelRequest` (function);
      imported by 11 file(s)
- `src/app/account/requests/[id]/page.tsx` (61) — path contains requests;
      defines `RequestDetail` (component)

## Candidate symbols
- `cancelRequestAction` (function) — `src/app/account/requests/actions.ts:7-16`
- `cancelRequest` (function) — `src/lib/portal-db.ts:212-230`

Those are the three files that actually had to change, ranked top, with line ranges — from the ticket text alone, no LLM involved.

Ranking

Terms are lowercased, stopword-filtered and matched against paths and symbol names. Identifiers are split on case and separators, so a task written in prose ("submit button") matches ConfirmSubmitButton — without that, prose almost never matches camelCase.

Weights put a symbol-name hit above an incidental path hit, so naming a function surfaces its file rather than every file sharing a directory word. Test files are penalised (context, not usually the edit site) and widely-imported files get a small, capped bonus — capped, or every util file wins regardless of the task.

Every result carries the reasons that produced it. The SRS requires citation over assertion, and an unexplained ranking is not reviewable.

Ranking is deterministic: ties break on path, never on hash iteration order, so the same task text against the same index always produces the same pack.

What it extracts

Per file: language, classification (source / test / config / manifest / instructions / docs), and owning package in a monorepo.

Per source file, via tree-sitter: imports (including export … from re-exports), exports, functions, classes, and arrow functions assigned to a binding — the last being the dominant modern style and invisible to anything that only reads function_declaration.

React components are flagged when a PascalCase name and JSX appear together. Either signal alone is not enough: function Card() { return 42 } is not a component, and function renderRow() { return <tr/> } is not either.

Route handlers are flagged with the reason attached, so output can cite why rather than assert it — exports GET, POST, under an api/ directory, named route. Test files beside a handler are excluded.

Import resolution

Relative specifiers and tsconfig/jsconfig paths aliases resolve to indexed files; bare specifiers (react) are package dependencies and stay unresolved.

Alias support matters more than it sounds: on the Next.js app above there are 36 relative imports against 109 @/… aliases, so without it roughly three-quarters of the dependency graph is missing. tsconfig is parsed tolerantly — comments and trailing commas are common and legal to TypeScript, and a strict JSON parse silently yields no aliases on a large share of real repos.

Design notes

  • Syntax only. No type checking, no module-graph evaluation. Extraction stays fast and dependency-free; the output is candidates an agent then reads, not a verified answer.
  • Indexing is a full rebuild in one transaction. A failed index leaves the previous one intact rather than a half-written mixture of two scans.
  • Paths are normalised to /, so an index built on Windows matches one built on Unix — paths are the join key for every other table.
  • Schema changes rebuild rather than migrate. The index is derived, so rebuilding is always correct and always cheap.

Development

cargo test
cargo clippy --all-targets
cargo fmt --check

About

Local-first Rust CLI that builds agent-ready structured intelligence about JS/TS repos

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages