fix(explore): accurately resolve query file paths and find camelCase symbols
Previously, `codegraph_explore` queries explicitly naming files by path (e.g., `src/routes/m/projects/[id]/runs/[runId]/+page.svelte`) were shredded. Bracketed path segments exploded into "named symbol" seeds, and FTS on fragments like `page` or `runs` admitted every sibling file, starving the user's intended target. This change introduces: - **Query path pinning:** File paths named in a query are now resolved against the index, "pinned," and stripped from the query. Pinned files are guaranteed inclusion, top ranking, and fair allocation. Unresolvable path-like spans are reported. - **Segment vocabulary supplement:** Natural language query terms (e.g., "auto-scroll to bottom") can now reach camelCase identifiers (e.g., `pinFeedIfNearBottom`, `feedAtBottom`) by matching against their constituent segments. - **Variable seeding:** `variable` and `constant` node kinds are now included in identifier seeding, improving recall for `$state`-style variables common in frameworks like Svelte.
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "explore-path-pinning-fixture",
|
||||
"version": "1.0.0",
|
||||
"private": true
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/** In-memory registry of task runs, keyed by run id. */
|
||||
|
||||
export interface Scope {
|
||||
projectId: string;
|
||||
label: string;
|
||||
}
|
||||
|
||||
export const runId = 'run-000';
|
||||
|
||||
const runs = new Map<string, { id: string; scope: Scope; status: string }>();
|
||||
|
||||
export function registerRun(id: string, scope: Scope): void {
|
||||
runs.set(id, { id, scope, status: 'queued' });
|
||||
}
|
||||
|
||||
export function getRun(id: string): { id: string; scope: Scope; status: string } | null {
|
||||
return runs.get(id) ?? null;
|
||||
}
|
||||
|
||||
export function listRuns(scope: Scope): string[] {
|
||||
return [...runs.values()]
|
||||
.filter((r) => r.scope.projectId === scope.projectId)
|
||||
.map((r) => r.id);
|
||||
}
|
||||
|
||||
export function stopRun(id: string): boolean {
|
||||
const run = runs.get(id);
|
||||
if (!run) return false;
|
||||
run.status = 'cancelled';
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/** Detached chat window page — session presence + streaming state. */
|
||||
|
||||
let chatAtBottom = true;
|
||||
let isStreaming = false;
|
||||
let messages: string[] = [];
|
||||
|
||||
export function handleMessagesScroll(distance: number): void {
|
||||
chatAtBottom = distance < 50;
|
||||
}
|
||||
|
||||
export function sendMessage(text: string): void {
|
||||
messages = [...messages, text];
|
||||
isStreaming = true;
|
||||
}
|
||||
|
||||
export function stopResponse(): void {
|
||||
isStreaming = false;
|
||||
}
|
||||
|
||||
export function redock(): void {
|
||||
messages = [];
|
||||
isStreaming = false;
|
||||
chatAtBottom = true;
|
||||
}
|
||||
|
||||
export function chatSnapshot(): { messages: string[]; streaming: boolean } {
|
||||
return { messages: [...messages], streaming: isStreaming };
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
/** Mobile run feed — event stream + scroll pinning for the run page. */
|
||||
|
||||
export interface FeedEvent {
|
||||
id: string;
|
||||
kind: 'output' | 'tool' | 'error';
|
||||
content: string;
|
||||
}
|
||||
|
||||
const EVENT_CAP = 300;
|
||||
|
||||
let events: FeedEvent[] = [];
|
||||
let workingLine: string | null = null;
|
||||
|
||||
/** Whether the reader is at the tail of the feed (within 50px). */
|
||||
let feedAtBottom = true;
|
||||
|
||||
interface FeedElement {
|
||||
scrollTop: number;
|
||||
scrollHeight: number;
|
||||
clientHeight: number;
|
||||
}
|
||||
|
||||
let feedEl: FeedElement | null = null;
|
||||
|
||||
export function bindFeedElement(el: FeedElement | null): void {
|
||||
feedEl = el;
|
||||
}
|
||||
|
||||
/** Track the reader's position; called from the feed's scroll listener. */
|
||||
export function handleFeedScroll(): void {
|
||||
const el = feedEl;
|
||||
if (!el) return;
|
||||
feedAtBottom = el.scrollHeight - el.scrollTop - el.clientHeight < 50;
|
||||
}
|
||||
|
||||
/** Re-pin after async content growth (image loads), only when at the tail. */
|
||||
export function pinFeedIfNearBottom(): void {
|
||||
const el = feedEl;
|
||||
if (!el) return;
|
||||
if (feedAtBottom) {
|
||||
el.scrollTop = el.scrollHeight;
|
||||
}
|
||||
}
|
||||
|
||||
export function appendEvent(event: FeedEvent): void {
|
||||
events = events.length >= EVENT_CAP
|
||||
? [...events.slice(-(EVENT_CAP - 1)), event]
|
||||
: [...events, event];
|
||||
if (feedAtBottom) {
|
||||
pinFeedIfNearBottom();
|
||||
}
|
||||
}
|
||||
|
||||
export function setWorkingLine(line: string | null): void {
|
||||
workingLine = line;
|
||||
pinFeedIfNearBottom();
|
||||
}
|
||||
|
||||
export function resetFeed(): void {
|
||||
events = [];
|
||||
workingLine = null;
|
||||
feedAtBottom = true;
|
||||
}
|
||||
|
||||
export function feedSnapshot(): { events: FeedEvent[]; workingLine: string | null } {
|
||||
return { events: [...events], workingLine };
|
||||
}
|
||||
Reference in New Issue
Block a user