The UserPromptSubmit hook's structural-prompt gate was English-only, so a structural question written in Chinese — or any non-Latin script — silently injected nothing: JS `\b` is ASCII-only and never matches between Han characters, so the keyword regex couldn't fire (and couldn't be extended in place). To the user the hook looked unwired, with no error to explain why. Make the gate language-aware, split into tested helpers in directory.ts: - hasStructuralKeyword: English (\b-guarded) + CJK structural keywords. - extractCodeTokens: identifier-shaped tokens (camelCase / snake_case / name() / a.b) in any language — verified against the index via getNodesByName before firing, so a tech brand like `JavaScript` that looks like a symbol but isn't one here doesn't inject ~16KB of spurious context. - isStructuralPrompt: the cheap candidate gate (keyword OR code-token). Adds 21 unit tests for the gate (previously untested) covering the reporter's verification table plus the false-positive guards. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
703629edc3
commit
b45f309a1b
+16
-6
@@ -26,7 +26,7 @@
|
||||
import { Command } from 'commander';
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
import { getCodeGraphDir, isInitialized, unsafeIndexRootReason, findNearestCodeGraphRoot, planFrontload } from '../directory';
|
||||
import { getCodeGraphDir, isInitialized, unsafeIndexRootReason, findNearestCodeGraphRoot, planFrontload, hasStructuralKeyword, extractCodeTokens } from '../directory';
|
||||
import { detectWorktreeIndexMismatch, worktreeMismatchWarning } from '../sync/worktree';
|
||||
import { createShimmerProgress } from '../ui/shimmer-progress';
|
||||
import { getGlyphs } from '../ui/glyphs';
|
||||
@@ -1053,11 +1053,15 @@ program
|
||||
try { input = JSON.parse(raw); } catch { return; }
|
||||
const prompt = String(input.prompt || '');
|
||||
|
||||
// Gate: only structural / flow / impact / where-how prompts get context.
|
||||
// A cheap regex keeps every other prompt ("fix this typo") a zero-cost
|
||||
// no-op so we never add latency where there's no structural answer to give.
|
||||
const STRUCTURAL = /\b(how|where|trace|flow|path|reach(?:es|ed)?|call(?:s|ed|er|ers|ee)?|depend|impact|affect|wired?|connect|implement|architect|structure|breaks?|what calls|why does)\b/i;
|
||||
if (!prompt || !STRUCTURAL.test(prompt)) return;
|
||||
// Gate: only structural / flow / impact / where-how prompts get context, so
|
||||
// every other prompt ("fix this typo") stays a zero-cost no-op. Language-aware
|
||||
// (English + CJK keywords, plus code-shaped tokens) so it fires for non-English
|
||||
// prompts too (issue #994). A keyword fires on its own; a code-token is only a
|
||||
// CANDIDATE — verified against the graph below, so a tech brand ("JavaScript")
|
||||
// that looks like a symbol but isn't one here doesn't inject spurious context.
|
||||
const keyworded = hasStructuralKeyword(prompt);
|
||||
const codeTokens = keyworded ? [] : extractCodeTokens(prompt);
|
||||
if (!keyworded && codeTokens.length === 0) return;
|
||||
|
||||
// Decide what to inject, shaped by WHERE the index(es) are: the nearest
|
||||
// indexed ancestor of cwd, or — when cwd is an un-indexed workspace root
|
||||
@@ -1079,6 +1083,12 @@ program
|
||||
const { default: CodeGraph } = await loadCodeGraph();
|
||||
const cg = await CodeGraph.open(plan.exploreRoot);
|
||||
try {
|
||||
// Code-token-only prompt: require that at least one token is a REAL symbol
|
||||
// in THIS index before front-loading. Without it, a brand name or common
|
||||
// word that merely looks like code ("JavaScript", "GitHub") would run
|
||||
// explore and inject ~16KB of low-relevance context (issue #994 follow-up).
|
||||
// A keyword-bearing prompt skips this — the keyword is signal enough.
|
||||
if (!keyworded && !codeTokens.some((t) => cg.getNodesByName(t).length > 0)) return;
|
||||
const { ToolHandler } = await import('../mcp/tools');
|
||||
const handler = new ToolHandler(cg);
|
||||
const result = await handler.execute('codegraph_explore', { query: prompt });
|
||||
|
||||
Reference in New Issue
Block a user