Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion eval/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@coderadar/eval",
"version": "0.1.0",
"version": "0.2.0",
"private": true,
"description": "CodeRadar eval harness — scans failure-mode fixtures, diffs against golden outputs, emits the scorecard that gates every phase.",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "coderadar",
"private": true,
"version": "0.1.0",
"version": "0.2.0",
"description": "Static analysis toolkit that maps UI components to their data sources (APIs, state, events) — enabling AI agents to trace any screenshot back to the code and data behind it.",
"license": "MIT",
"packageManager": "pnpm@11.2.2",
Expand Down
57 changes: 34 additions & 23 deletions packages/cli/README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# ui-lineage

**Map UI components to their data sources and user journeys** — trace any screenshot or ticket back to the code, APIs, state, and navigation behind it. Deterministic static analysis for React/TSX. No LLM, no network calls.
**Map UI components to their data, journeys, and behavior** — trace any screenshot or ticket back to the code, APIs, state, events, and navigation behind it. Deterministic static analysis for React/TSX. No LLM in the core, no network calls.

`ui-lineage` scans a React codebase into a **lineage graph** and lets you query it three ways:
`ui-lineage` scans a React codebase into a **lineage graph** and answers three questions:

- **match** — text seen on screen → the component(s) that render it
- **trace** — a component → every API, state slice, and event that feeds it (attributed *per instance*, so a shared `<DataTable>` on the Users page reports `/api/users` while the same component on Invoices reports `/api/invoices`)
- **journeys** — a page → the user-action paths leading out of it (click → navigate → click…), lazily expanded and cycle-safe
1. **match** — text or structure seen on screen → the component(s) that render it (rarity-weighted, fuzzy/OCR-tolerant, structure-aware, with business-vocab aliases and human corrections, and *calibrated* confidence).
2. **trace** — a component → every API, state slice, and event that feeds it, *attributed per instance* (a shared `<DataTable>` reports `/api/users` on the Users page and `/api/invoices` on Invoices).
3. **journeys** — a page → the user-action paths out of it (click → navigate → click…), lazily expanded and cycle-safe, with flag/role conditions.

## Install

Expand All @@ -20,47 +20,58 @@ Requires Node ≥ 20.
## CLI

```bash
# 1. Scan a React app into a graph
ui-lineage scan ./src -o app.graph.json

# 2. Find a component from on-screen text
ui-lineage find "All invoices" -g app.graph.json

# 3. Trace a component (or an instance id) to its data
ui-lineage trace InvoicesPage -g app.graph.json

# 4. Walk the user journeys from a page or route
ui-lineage journeys /users -g app.graph.json
ui-lineage scan ./src -o app.graph.json # scan a React app into a graph
ui-lineage find "All invoices" -g app.graph.json # text → component
ui-lineage find "invoice widget" -a aliases.yaml # resolve business vocabulary
ui-lineage trace InvoicesPage -g app.graph.json # component → data/state/events
ui-lineage journeys /users -g app.graph.json # user-journey paths from a page
ui-lineage correct BillingCard "amount owed" # record a correction for next time
```

`journeys` output reads left-to-right, with `↩ cycle` where a list ⇄ detail loop closes:
`journeys` reads left-to-right, with `↩ cycle` where a list ⇄ detail loop closes:

```
▸ /users • onClick() → /users/:userId ▸ /users/:userId • onClick() → /users ▸ /users ↩ cycle
▸ /users • onClick() → /users/:id ▸ /users/:id • onClick() → /users ▸ /users ↩ cycle
▸ /users • onClick() ⇢ fetch /api/users
```

## Library

```ts
import { scanReact, resolveHookEdges, journeys, traceLineage, matchComponentsByText } from "ui-lineage";
import {
scanReact, resolveHookEdges,
matchComponents, traceLineage, journeys,
recordCorrection, loadCorrections,
} from "ui-lineage";

const graph = resolveHookEdges(scanReact({ root: "./src" }));

const match = matchComponentsByText(graph, ["All invoices"]);
const match = matchComponents(graph, { terms: ["All invoices"] });
const lineage = traceLineage(graph, match.candidates[0].value.component.id);
const paths = journeys(graph, "/users", { depth: 3 });
```

Every query returns a `QueryResult` envelope — ranked `candidates` with evidence and confidence, or an honest `ambiguous` / `declined`.
Every query returns a `QueryResult` envelope — ranked `candidates` with evidence and confidence, or an honest `ambiguous` (with a disambiguation question built from the candidates' differences) / `declined` (machine-readable reason).

### Screenshots (`ui-lineage/vision`)

```ts
import { StubVisionAdapter, matchFromVision } from "ui-lineage/vision";
```

Turn a screenshot into `{ terms, structure, annotations }` and match it — terms the user circled are weighted 3×; a non-app image declines. The Claude-vision adapter needs `@anthropic-ai/sdk` installed separately; the stub and matching helpers do not. Images are processed in memory, never persisted.

## What it understands

Endpoints (constants, templates, API wrappers, react-query/SWR), i18n text, cross-file instance trees and per-instance prop-flow, Redux/Zustand stores, portals/modals/toasts, React Router & Next.js routes, and action effects (navigate / fetch / dispatch / setState) mined from event handlers.
Endpoints (constants, templates, API wrappers, react-query/SWR), i18n text, cross-file instance trees & per-instance prop-flow, Redux/Zustand stores, portals/modals/toasts, React Router & Next.js routes, action effects (navigate/fetch/dispatch/setState), form libraries & non-JSX events (react-hook-form, `addEventListener`, hotkeys), and feature-flag/role conditions.

## New in 0.2.0

User journeys · action effects · form & non-JSX events · flag/role conditions · a real matching engine (rarity + fuzzy/OCR + structural + most-specific-subtree) · screenshot/vision adapter · alias glossary + corrections store · calibrated confidence with honesty metrics.

## Status

Early (v0.1). The matching engine, screenshot adapter, and MCP server are on the roadmap. Output is deterministic and language-agnostic (plain JSON graph), designed to feed AI agents as a context provider — not to be one.
Pre-1.0. The context-bundle orchestrator and MCP server are next. Output is deterministic and language-agnostic (a plain JSON graph), designed to feed AI agents as a context provider — not to be one.

## License

Expand Down
5 changes: 3 additions & 2 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ui-lineage",
"version": "0.1.0",
"version": "0.2.0",
"description": "Map UI components to their data sources and user journeys — trace any screenshot back to the code, APIs, state, and navigation behind it. Deterministic static analysis for React/TSX.",
"license": "MIT",
"type": "module",
Expand All @@ -18,7 +18,8 @@
"./vision": {
"types": "./dist/vision.d.ts",
"default": "./dist/vision.js"
}
},
"./package.json": "./package.json"
},
"files": [
"dist",
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ program
.description(
"Map UI components to their data sources and user journeys — trace any screenshot back to the code, APIs, state, and navigation behind it.",
)
.version("0.1.0");
.version("0.2.0");

program
.command("scan")
Expand Down
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@coderadar/core",
"version": "0.1.0",
"version": "0.2.0",
"private": true,
"description": "CodeRadar lineage graph schema — the language-agnostic contract every parser emits and every agent consumes. Bundled into the published `ui-lineage` package.",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion packages/parser-react/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@coderadar/parser-react",
"version": "0.1.0",
"version": "0.2.0",
"private": true,
"description": "React/TSX parser for CodeRadar — extracts components, hooks, data sources, state, and events into a lineage graph. Bundled into the published `ui-lineage` package.",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion packages/parser-react/src/scan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ export function scanReact(options: ScanOptions): LineageGraph {
version: 2,
root,
generatedAt: new Date().toISOString(),
generator: "@coderadar/parser-react@0.1.0",
generator: "ui-lineage@0.2.0",
nodes: [...nodes.values()],
edges,
};
Expand Down
2 changes: 1 addition & 1 deletion packages/vision/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@coderadar/vision",
"version": "0.1.0",
"version": "0.2.0",
"private": true,
"description": "Screenshot → { terms, structure, annotations } vision adapter for ui-lineage. Images are processed in memory and never persisted (G7). Bundled into the published ui-lineage package.",
"license": "MIT",
Expand Down
Loading