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>
This commit is contained in:
co-authored by
Claude Opus 5
parent
6d0f60f32c
commit
62e0a89b0e
@@ -3,14 +3,6 @@
|
||||
import { trail, hopLabel, encodeTrail } from '../lib/trail.svelte';
|
||||
import { navigate, symbolHref, flowHref } from '../lib/router.svelte';
|
||||
|
||||
/**
|
||||
* "Read as flow" replays the trail as a computed path in the Flow view,
|
||||
* which is phase 2 (CG-50). The control is built and wired; it stays hidden
|
||||
* until there is a view to send it to, because a button that lands on a
|
||||
* placeholder is worse than no button.
|
||||
*/
|
||||
const READ_AS_FLOW = false;
|
||||
|
||||
let hops = $derived(trail.hops);
|
||||
|
||||
function step(index: number) {
|
||||
@@ -20,9 +12,14 @@
|
||||
navigate(symbolHref(hop.id, { trail: encodeTrail(trail.hops) }));
|
||||
}
|
||||
|
||||
/**
|
||||
* The walk itself IS the flow: the Flow view does not search for a path, it
|
||||
* looks up the edge already joining each consecutive pair and draws the cards
|
||||
* at those lines. So the trail travels under the same `t` param it uses
|
||||
* everywhere else — a flow read from a trail is one walk under two lenses.
|
||||
*/
|
||||
function readAsFlow() {
|
||||
// The flow key is the walk itself; the Flow view (phase 2) replays it.
|
||||
navigate(flowHref(encodeTrail(hops)));
|
||||
navigate(flowHref({ trail: encodeTrail(hops) }));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -84,7 +81,7 @@
|
||||
|
||||
<span class="spacer"></span>
|
||||
|
||||
{#if READ_AS_FLOW && hops.length > 1}
|
||||
{#if hops.length > 1}
|
||||
<button type="button" class="tb-btn" onclick={readAsFlow}>Read as flow</button>
|
||||
{/if}
|
||||
{#if hops.length > 0}
|
||||
|
||||
Reference in New Issue
Block a user