47576b392ed31912cfbec5742e094daf8031ed32
6
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
47576b392e |
feat(ui): saved trails — a walk you named, kept, and still true after a re-index (CG-60)
Save trail on the trail bar writes the walk to .codegraph/ui/trails/ as one JSON file, listed on the empty screen and on Entry points above the derived suggestions, reopened at the symbol you left with the whole path restored. A hop is stored by qualified name, kind and file — never by node id, which contains a start line and so changes the first time anybody edits above the symbol. Every hop is re-resolved against the current index on the way out and each row says what became of it: still here, moved to another file, now ambiguous, or gone. A hole is never stitched over: the row opens the longest run of CONSECUTIVE resolved hops and says which ones those are, because the trail is a path and a skipped hop would draw a call that does not exist. This is the first write the viewer makes, and the boundary moved with it: POST/DELETE answer under /api/ only, must carry X-CodeGraph-UI and application/json (neither of which a cross-origin form can produce without a preflight this server answers none of), and --read-only refuses both while still listing what is there. The blanket "read-only" claim is retired from the banner, the README, the CLI help and the docs site in favour of the narrower true one. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
c15413f200 |
feat(ui): the viewer's screens as @colbymchenry/codegraph-ui, behind one adapter (CG-61)
`ui/src` now builds two ways from one tree: the static app `codegraph ui` serves, and — via `svelte-package` — a Svelte library the Pro app imports. A forked component would be a second answer to the same question about the same graph, so there is no fork. Everything a screen knows arrives through a `GraphAdapter`: eleven methods answering the wire shapes verbatim, with `createHttpAdapter()` (the loopback JSON API) as the default and a host's in-process engine reads as the point. `lib/api.ts` became a one-line-per-call facade over it, which is why no call site in the views changed. The payload types moved to `lib/wire.ts` — no imports, no runtime — so a host can depend on the vocabulary alone. Two more seams and one guard: - `lib/navigation.ts` holds the href builders behind a `NavigationDriver`, so a host addresses its own URL space. The app's half — the hash parser and the live route, which attach window listeners at module scope — stays in `router.svelte.ts` and is pruned out of the package: rendering a Symbol view must not install a hash router in somebody else's application. - `lib/theme.css` carries the design tokens and maps Svelte Flow's `--xy-*` variables onto them, so a host never sees library defaults. Dark now also answers to a bare `[data-theme]`, which is how `<CodegraphUi theme>` themes a container rather than the document. - `scripts/check-ui-package.mjs` prunes the app's shell, resolves the extensionless specifiers svelte-package leaves behind, and asserts that nothing but `lib/adapter.js` reaches the network. The search box, its keyboard and its panel are one component now (`SearchPalette`), because splitting them is what breaks a palette. `__tests__/ui-package.test.ts` mounts the three screens from the package entry against a mock adapter in jsdom; it runs as a second vitest project so the `browser` resolve condition it needs cannot reach the engine's suites. Versioned with the engine. Prepared, not published: `private: true` is the guard and `pack-npm.sh` only packs a tarball under CODEGRAPH_PACK_UI=1. |
||
|
|
62e0a89b0e |
feat(ui): the Flow strip — how one symbol reaches another, one card per hop (CG-50)
Ask "how does execute reach getFile" in the search box and the viewer draws the call path between them, left to right, opening every card at the exact line that makes the next call. Dynamic-dispatch hops are dashed and name the site they were wired at; "Read as flow" turns a trail walked by hand into the same strip. The path finder is NOT new. `codegraph_explore` already leads its answers with the longest call chain among the symbols an agent named, and a viewer that drew a different path would get the two quoted against each other in a review. So the search moved out of `ToolHandler` into `src/graph/named-symbol-flow.ts` and both callers ride it — same tokens, same overload rules, same synthesized edges. What stayed behind in `tools.ts` is the prose. A pinned from/to question is the same search with two options changed, because both ends being named is the evidence explore's one-unnamed-bridge cap stands in for: it bridges freely, keeps twelve candidates per endpoint instead of six (the CLI's own `main` sorts seventh of ten), and searches from both ends at once — identical paths to the one-way walk on twelve measured pairs, 3-6x faster. `/api/flow` is deliberately the one endpoint with no cache: its cards carry source read from disk, and a drift verdict changes without the index changing. Verified on this repo (`execute` to `rowToFileRecord`, 8 hops; `main` to `resolveOne`, 7) and on a fresh excalidraw index, where `mutateElement` to `renderStaticScene` crosses callback, react-render and jsx-child hops and lists exactly the hops `codegraph_explore` prints. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
87afc50e76 |
feat(ui): the search palette, entry points and a trail that survives the URL (CG-45)
Search: `/` or ⌘K focuses the box; results arrive grouped by kind with their
glyph, signature and file:line, ↑/↓/Enter walk them, Esc dismisses. A group
appears where its best result did, so flattening the groups reproduces the
ranking the keyboard walks — the panel's flat item list IS that concatenation.
A flow question ("how does X reach Y", "X -> Y") is recognised and searches
both endpoints with a note, rather than offering a row that would land on the
phase-2 Flow view.
Entry points answer "where do I start" on the empty screen and in the resting
palette, all derived from the graph: routes, files that run something at module
level (the engine records a top-level statement as an edge out of the file node,
which is what makes src/bin/codegraph.ts the root of the CLI flow — ranked by
calls x the files they reach, so a registration table calling into itself does
not outrank the CLI), and the most depended-on symbols. Tests are excluded from
both derived lists.
Trail: hops record the direction they were walked (→ into a call, ← up to a
caller), clicking one truncates back to it, Clear keeps the place instead of
throwing it away, and the whole walk travels in the URL. A shared or reloaded
trail arrives as ids, so hops learn their names back through a new batch
endpoint and a session name cache — without it, walking back across a
truncation redrew earlier hops as raw hashes. "Read as flow" stays hidden until
there is a Flow view to send it to.
New endpoints: /api/entrypoints and /api/nodes. New engine reads:
getTopCallingFiles, getFileDependentCounts.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
||
|
|
5cecaabfc2 |
feat(ui): the Symbol view — callers, gutter-ported source, line-anchored callee rail (CG-44)
The core screen of `codegraph ui`: who calls a symbol on the left, its verbatim body in the middle with a port on every line that has an outgoing edge, and what it calls on the right — each callee row placed beside the line that makes the call, with a hairline connector between them. The callee rail is the part that is not a list. A row wants to sit at the centre of its first call-site line and is pushed down only when that would collide with the row above, so the rail keeps source order; the connector still runs to the real line, so the displacement is visible rather than silent. Positions come from measuring the laid-out DOM, so they are recomputed on resize, on font load and whenever a fold opens. Honesty is carried in the drawing, not in a footnote: a filled port means the resolver matched something on that line and a hollow one means it only guessed; uncertain connectors are dashed and their targets fold away behind their count; synthesized edges are dashed differently and tagged with the mechanism that made them; references that leave the index are text with a soft underline rather than links to nowhere, and they are counted. Long bodies keep their head plus a window round every call site — windowed on graph edges only, since a function calling `console.log` two hundred times would otherwise window round every line and buy nothing. Containers over 80 lines show a members outline with per-member fan-in/fan-out instead of 700 lines of braces. Two small additions to the read-only API this needed: * `/api/node` gives every outline member its own fanIn/fanOut (two batched queries for the whole outline). A class's own fan-out is nearly always zero because its methods do the calling, so without these the outline cannot say which member carries weight. * `/api/stats` gains `blastScale` — the denominator the blast bar is drawn against, so one symbol's radius reads as wide or narrow *for this repo*. It is measured across the index's 24 most-depended-on symbols (found with a new `getTopDependedOn`, distinct dependents rather than edges), memoised against the index stamp, and reported as sampled; a symbol wider than the sample becomes the scale instead of overflowing the track. Verified against a real index in a real browser: parity with the prototype on `CodeGraph.sync` (259 lines, 27 callee rows, no overlaps), `GraphTraverser` (20-member outline), a 773-line function (26 windows, 78 connectors), light and dark, hover linking in both directions, keyboard-only navigation, and reflow on resize and on fold toggles. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
a72f22a6d3 |
feat(ui): scaffold the codegraph ui viewer as a Svelte 5 + Vite workspace (CG-40)
Adds `ui/` as an npm workspace (Svelte 5.56 + Vite 7, devDependencies only — the engine's runtime dependencies are untouched) and chains its build into `npm run build`, so the browser viewer ships inside `dist/` with everything else: `build-bundle.sh` already copies `dist` wholesale and `pack-npm.sh` packs that bundle. Output is `dist/viewer/`, NOT `dist/ui/`: `src/ui/` is the engine's terminal ui (shimmer progress + its worker) and tsc compiles it to `dist/ui/`, so emitting there both deletes those modules — the CLI then dies at startup with `Cannot find module '../ui/shimmer-progress'` — and would leave the static server handing out compiled engine internals. The design spec is corrected to match. `scripts/check-ui-build.mjs` is the release guard: index.html must exist, be non-trivial, and every local asset it references must be on disk, and the compiled engine next door must still be intact. It runs after every UI build, again in `build-bundle.sh` once the bundle stage has copied `dist`, and again in `pack-npm.sh` once each archive is unpacked — so a broken viewer fails the release instead of shipping a CLI that serves a 404. `vite build` does not override an ambient NODE_ENV, so a shell or runner with NODE_ENV=development silently shipped dev-mode Svelte (~13 kB of dev-only runtime checks, warning in the user's console). The config now pins production for `command === 'build'`; macOS and Windows ARM64 then emit byte-identical bundle hashes. The shell itself follows docs/design/codegraph-ui-design-spec.md §2–§3.1: design tokens as CSS custom properties (light on bare `:root`, dark under both `prefers-color-scheme` and `[data-theme="dark"]`), square corners, hairline rules, one oxblood accent; top bar 48px / trail bar 34px / main; a hash router over `#/s/<id>`, `#/file/<path>`, with `#/map` and `#/flow` reserved for phase 2. Fonts are vendored through @fontsource rather than fetched, so a local reader works offline and never announces the project to a CDN. Verified: clean `npm run build` from an empty dist on macOS and on the Windows ARM64 VM (forward-slash asset URLs, CLI still starts, both assertion failure modes exit 1); `dist/viewer` present in a real darwin-arm64 bundle and in the packed npm platform package; shell geometry, tokens, all seven routes, both themes and font loading checked in headless Chromium with no console errors; `npm test` unaffected. |