New:Introducing Socket Scanning for VS Code Marketplace Extensions.Learn more →
Get Started

@bugmojo/codemap

Package Overview
Dependencies
Maintainers
1
Versions
2
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@bugmojo/codemap

Deterministic, framework-aware codebase mapper for BugMojo — turns a repo's routes, components, APIs and forms into Feature rows and a stable code summary. No LLM, no network.

latest
Source
npmnpm
Version
0.1.0
Version published
Weekly downloads
0
Maintainers
1
Weekly downloads
 
Created
Source

@bugmojo/codemap

Deterministic, framework-aware codebase mapper. It turns a repository into the two artefacts the BugMojo agentic-testing loop needs before anyone writes a test case:

  • code_summary.json — a stable, hashable inventory of routes, APIs, components, forms and auth gates (plus the specs that already exist), meant to be committed and diffed.
  • A Feature upsert payload — the rows that anchor coverage, defect attribution and risk in BugMojo, ready for upsert_features (MCP) or feature.featureUpsertMany (tRPC).

No LLM. No network. No database. Same tree in, byte-identical JSON out. The source never leaves the machine; only the derived facts travel.

npx -y @bugmojo/cli map                              # human summary
npx -y @bugmojo/cli map --json                       # code_summary.json
npx -y @bugmojo/cli map --features --project WEB     # upsert_features arguments
npx -y @bugmojo/cli map --out bugmojo/code-summary.json
import { mapCodebase, toCodeSummary, toFeatureUpserts, chunkFeatureUpserts } from '@bugmojo/codemap';

const map = mapCodebase(process.cwd());
const summary = toCodeSummary(map, { rootLabel: '.' });
for (const batch of chunkFeatureUpserts(toFeatureUpserts(map))) {
  await upsertFeatures({ project: 'WEB', features: batch });
}

What it finds

KindSource
ROUTENext.js App Router (app/**/page.tsx), Next.js Pages Router (pages/**), Expo Router (app/**) — with the URL path, dynamic params, route groups, parallel slots, intercepting routes, whether the route sits behind a session, and the data-testid / testID values it renders
APIApp Router route handlers (one feature per exported GET/POST/…), tRPC procedures with their public namespace, query/mutation, procedure base and requirePermission permission, and express/fastify/hono routes
COMPONENTExported React components with their prop names (destructured params or the members of their props type) and their test ids
FLOWForms (<form>, react-hook-form, formik) with the tRPC procedure / HTTP endpoint / server action they submit to, and each auth-gated area with the reason it gates

It also reads existing *.spec.* / *.test.* files as coverage (their titles and any { type: 'bugmojo', description: 'WEB-42' } annotations) so a planner never proposes a case that already has a spec.

Design notes

Why a hand-written scanner and not the TypeScript compiler API. bugmojo map runs inside a customer's repo via npx: it may be plain JS, it may have no tsconfig, and pulling ~25 MB of typescript into a published CLI to answer "which files export a component" is a bad trade. Everything extracted here is syntactic — exported names, JSX attributes, publicProcedure chains — so no type checker is involved either way. One code path also makes byte-for-byte determinism easy to hold.

lexer.ts is what makes regex scanning safe: maskSource() returns a string of the same length as the input with comment bodies, string bodies and regex bodies blanked to spaces. Scan the mask, slice the original — a data-testid inside a comment or a string can never be mistaken for one that renders.

Feature keys are stable, and that is the whole contract. A key is the Feature identity in the ledger (@@unique([project_id, key])), so a key that moves re-creates the row and orphans everything attached to it. The app id comes from the nearest package.json name (@acme/web → web), never from the scan root, and file paths in keys are relative to the package. Running bugmojo map from a monorepo root and from apps/web therefore produces the same keys for the same code.

route:web:/board/[slug]
api:web:GET /api/v1/bugs
api:web:trpc.issue.create
component:web:src/components/ui/button.tsx#Button
flow:web:form:src/app/auth/login/page.tsx#LoginPage
flow:web:auth:src/app/(dashboard)/[companySlug]/layout.tsx

There is no timestamp in code_summary.json. A summary that embeds generated_at differs on every run, so it cannot be committed, diffed, or used as a cache key. It carries a content_hash over its own canonical JSON instead — "did the surface move?" is one string comparison.

Auth inheritance follows the DIRECTORY, not the URL. Route groups make URL-prefix inheritance wrong: (marketing)/layout.tsx and (dashboard)/layout.tsx both sit at /, and only one of them gates.

Components are filtered by default. toFeatureUpserts emits COMPONENT features only for components a test case can target — a route's page component, one rendering a data-testid, or one owning a form. A coverage ledger with 800 button rows is a ledger nobody reads. Pass includeComponents: 'all' when you genuinely want the rest.

Nothing throws. An unreadable file, a cap being hit, a duplicate key: every one of them is a warnings[] entry and the rest of the map still lands.

Limits worth knowing

  • Route paths are the file-system routes. A middleware rewrite (BugMojo's own /login → /auth/login) is not invented here; the mapper reports /auth/login.
  • Props resolve within one file. A props interface imported from another module yields no prop names rather than a guess.
  • Submit targets are only recorded when the code names them literally. A fetch(someUrl) produces no target — a guessed endpoint on a feature row is worse than none.
  • maxFiles defaults to 20 000 and files over 512 KiB are skipped, both with a warning.

License

MIT

Keywords

bugmojo

FAQs

Package last updated on 17 Oct 2026

Related posts