dsh-code-index 0.10.2 → 0.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client/index.tsx"],"sourcesContent":["/**\n * Browser half of dsh-code-index: structured result cards for the code_* tools\n * plus a settings card for the `code-index` namespace.\n *\n * Deliberately imports no harness client package: this bundle only needs\n * `react` (a shell platform module) plus the slot registry and settings scope\n * services reached through the plugin context. Keeping the surface local avoids\n * a dependency on a synchronized client-package version.\n */\n\nimport { useEffect, useState, type ReactNode } from 'react'\n\n/** Minimal structural view of the client plugin context this bundle uses. */\ninterface ClientContextLike {\n effect(fn: () => (() => void) | void): void\n slots: {\n inject(name: string, run: () => Iterable<unknown>): void\n register(entry: Record<string, unknown>, component: (props: never) => ReactNode): () => void\n }\n inject?(deps: string[], run: (ctx: ClientContextLike) => void): unknown\n settingsScope?: { bind(spec: { namespace: string }): SettingsScopeLike<CodeIndexSettings> }\n configForms?: { get(id: string): SettingsScopeLike<CodeIndexSettings> | undefined }\n locale?: { register(namespace: string, dictionaries: { zh: Record<string, string>; en: Record<string, string> }): () => void }\n}\n\ninterface SettingsSnapshot<T> {\n status: 'loading' | 'ready' | 'unavailable'\n value: T | undefined\n writable: boolean\n}\n\ninterface SettingsScopeLike<T> {\n getSnapshot(): SettingsSnapshot<T>\n subscribe(listener: () => void): () => void\n set(field: string, value: unknown): Promise<void>\n unset(field: string): Promise<void>\n}\n\ninterface CodeIndexSettings {\n excludeDirs?: string[]\n mapTopFiles?: number\n mapMaxChars?: number\n mapTtlMs?: number\n autoInject?: boolean\n codeHealth?: boolean\n toolSurface?: 'full' | 'compact'\n}\n\ninterface ToolCallHead {\n name?: string\n argsRaw?: string\n}\n\ninterface TextContent {\n type?: string\n text?: string\n}\n\ninterface ToolResultLike {\n call?: ToolCallHead | null\n content?: readonly TextContent[]\n isError?: boolean\n resultView?: unknown\n}\n\ninterface SearchView {\n card: 'search'\n shape?: 'matches' | 'paths'\n files?: Array<{ path: string; matches?: Array<{ lineNumber: number; line: string }> }>\n paths?: string[]\n truncated?: boolean\n total?: number\n}\n\ninterface ToolViewProps {\n toolName: string\n block: ToolResultLike & ToolCallHead\n openFile?: (path: string, options?: unknown) => void\n}\n\nconst CARD_STYLE: Record<string, string | number> = {\n border: '1px solid var(--dsh-border, #333)',\n borderRadius: 6,\n padding: '6px 8px',\n fontFamily: 'var(--dsh-mono-font, monospace)',\n fontSize: 12,\n margin: '4px 0',\n}\n\nconst ROW_STYLE: Record<string, string | number> = {\n display: 'flex',\n gap: 8,\n alignItems: 'baseline',\n}\n\nfunction parseArgs(raw: string | undefined): Record<string, unknown> {\n if (!raw) return {}\n try {\n const value: unknown = JSON.parse(raw)\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : {}\n } catch {\n return {}\n }\n}\n\nfunction summarizeArgs(args: Record<string, unknown>): string {\n const parts: string[] = []\n for (const key of ['task', 'query', 'symbol', 'action', 'direction', 'kind', 'budgetChars']) {\n const value = args[key]\n if (typeof value === 'string' && value) parts.push(`${key}=${value}`)\n }\n return parts.join(' ')\n}\n\nfunction asSearchView(view: unknown): SearchView | undefined {\n if (typeof view !== 'object' || view === null || Array.isArray(view)) return undefined\n const record = view as Record<string, unknown>\n return record.card === 'search' ? (record as unknown as SearchView) : undefined\n}\n\nfunction resultText(block: ToolResultLike): string {\n return (block.content ?? [])\n .filter((part) => part.type === 'text' && typeof part.text === 'string')\n .map((part) => part.text ?? '')\n .join('\\n')\n}\n\n/** One code tool's card: argument summary, structured search matches, or text. */\nfunction CodeToolCard(props: ToolViewProps): ReactNode {\n const { toolName, block, openFile } = props\n const head: ToolCallHead = block.call ?? block\n const summary = summarizeArgs(parseArgs(head.argsRaw))\n const search = asSearchView(block.resultView)\n const isError = block.isError === true\n\n return (\n <div style={CARD_STYLE}>\n <div style={ROW_STYLE}>\n <strong>{toolName}</strong>\n {summary ? <span style={{ opacity: 0.75 }}>{summary}</span> : null}\n {isError ? <span style={{ color: '#e5534b' }}>error</span> : null}\n </div>\n {search?.shape === 'matches' && search.files ? (\n <div style={{ marginTop: 4 }}>\n {search.files.map((file) => (\n <div key={file.path}>\n <div style={{ opacity: 0.85 }}>{file.path}</div>\n {(file.matches ?? []).map((match, index) => (\n <div\n key={`${match.lineNumber}-${index}`}\n style={{ paddingLeft: 12, cursor: openFile ? 'pointer' : 'default' }}\n onClick={() => openFile?.(file.path, { line: match.lineNumber })}\n >\n <span style={{ opacity: 0.6 }}>{match.lineNumber}</span> {match.line}\n </div>\n ))}\n </div>\n ))}\n {search.truncated ? <div style={{ opacity: 0.6 }}>… truncated ({search.total} total)</div> : null}\n </div>\n ) : (\n <pre style={{ margin: '4px 0 0', whiteSpace: 'pre-wrap', maxHeight: 220, overflow: 'auto' }}>\n {resultText(block)}\n </pre>\n )}\n </div>\n )\n}\n\n/** Mirrors the first-party plugin card + field CSS modules, under our own class names. */\nconst CARD_CSS = `\n.dci-card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;list-style:none;transition:border-color .16s,background .16s}\n.dci-card:hover{border-color:var(--dsw-alias-label-dimmed)}\n.dci-cardOpen{background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-label-dimmed)}\n.dci-header{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;align-items:center;gap:12px;padding:14px 16px;display:flex}\n.dci-header:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}\n.dci-headText{flex-direction:column;flex:1 1 0%;gap:4px;min-width:0;display:flex}\n.dci-name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}\n.dci-description{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}\n.dci-chevron{color:var(--dsw-alias-label-tertiary);flex:0 0 auto;transition:transform .16s}\n.dci-chevronOpen{transform:rotate(180deg)}\n.dci-body{border-top:1px solid var(--dsw-alias-border-l2);margin:0 16px;padding-bottom:8px}\n.dci-field{flex-direction:column;gap:6px;padding:12px 0;display:flex}\n.dci-field+.dci-field{border-top:1px solid var(--dsw-alias-border-l2)}\n.dci-head{align-items:center;gap:8px;display:flex}\n.dci-label{min-width:0;color:var(--dsw-alias-label-primary);flex:1 1 0%;font-size:13px;font-weight:500;line-height:1.5}\n.dci-input{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);height:34px;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font:inherit;font-size:13px;line-height:1.5}\n.dci-input:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}\n.dci-input:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}\n.dci-check{width:16px;height:16px;flex:0 0 auto;accent-color:var(--dsw-alias-brand-primary)}\n.dci-hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}\n.dci-footer{border-top:1px solid var(--dsw-alias-border-l2);justify-content:flex-end;align-items:center;gap:8px;padding:12px 0 4px;display:flex}\n.dci-discard,.dci-save{appearance:none;font:inherit;cursor:pointer;border:1px solid transparent;border-radius:8px;padding:5px 14px;font-size:13px;line-height:1.5}\n.dci-discard{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:0 0}\n.dci-discard:hover:not(:disabled){color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-dimmed)}\n.dci-save{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3)}\n.dci-discard:disabled,.dci-save:disabled{opacity:.4;cursor:default}\n`\n\nconst CHEVRON_PATH =\n 'M11.8486 5.5L11.4238 5.92383L8.69727 8.65137C8.44157 8.90706 8.21562 9.13382 8.01172 9.29785C7.79912 9.46883 7.55595 9.61756 7.25 9.66602C7.08435 9.69222 6.91565 9.69222 6.75 9.66602C6.44405 9.61756 6.20088 9.46883 5.98828 9.29785C5.78438 9.13382 5.55843 8.90706 5.30273 8.65137L2.57617 5.92383L2.15137 5.5L3 4.65137L3.42383 5.07617L6.15137 7.80273C6.42595 8.07732 6.59876 8.24849 6.74023 8.3623C6.87291 8.46904 6.92272 8.47813 6.9375 8.48047C6.97895 8.48703 7.02105 8.48703 7.0625 8.48047C7.07728 8.47813 7.12709 8.46904 7.25977 8.3623C7.40124 8.24849 7.57405 8.07732 7.84863 7.80273L10.5762 5.07617L11 4.65137L11.8486 5.5Z'\n\nconst SETTINGS_DEFAULTS = { autoInject: true, codeHealth: false, mapTopFiles: 24 }\nconst SETTINGS_FIELDS = ['autoInject', 'codeHealth', 'mapTopFiles'] as const\n\n/** Settings card for `code-index`, laid out like the first-party plugin cards. */\nexport const SETTINGS_EN = {\n collapse: 'Collapse settings', expand: 'Expand settings',\n description: 'Project-aware live structural context: symbol search, repo map, and call graph.',\n autoInject: 'Inject repo map', autoInjectHint: 'Add a compact ranked map of the current project to the system prompt.',\n codeHealth: 'Code health tool', codeHealthHint: 'Register code_health for dependency cycles and orphan modules (restart required).',\n mapFiles: 'Map files', mapFilesHint: 'Maximum number of files shown in each repo map.',\n discard: 'Discard changes', save: 'Save', unavailable: 'Settings service unavailable.',\n}\nexport const SETTINGS_ZH = {\n collapse: '收起设置', expand: '展开设置',\n description: '项目感知的实时结构化上下文:符号搜索、仓库地图与调用图。',\n autoInject: '自动注入仓库地图', autoInjectHint: '把当前项目的精简排名地图注入系统提示词。',\n codeHealth: '代码健康工具', codeHealthHint: '注册 code_health 工具,报告环依赖与孤儿模块(重启后生效)。',\n mapFiles: '地图文件数', mapFilesHint: '仓库地图中最多展示的文件数。',\n discard: '放弃修改', save: '保存', unavailable: '设置服务不可用。',\n}\n\nfunction CodeIndexSettingsCard(props: { scope?: SettingsScopeLike<CodeIndexSettings>; t?: (key: string) => string }): ReactNode {\n const scope = props.scope ?? null\n const t = props.t ?? ((key: string) => SETTINGS_EN[key as keyof typeof SETTINGS_EN] ?? key)\n const [open, setOpen] = useState(false)\n const [snapshot, setSnapshot] = useState<SettingsSnapshot<CodeIndexSettings> | null>(\n scope ? scope.getSnapshot() : null,\n )\n const [draft, setDraft] = useState<CodeIndexSettings | null>(null)\n\n useEffect(() => {\n if (!scope) return\n setSnapshot(scope.getSnapshot())\n return scope.subscribe(() => setSnapshot(scope.getSnapshot()))\n }, [scope])\n\n const resolved = snapshot?.value ?? {}\n const form: CodeIndexSettings = { ...SETTINGS_DEFAULTS, ...resolved, ...draft }\n const writable = snapshot?.writable ?? false\n const changed = (key: (typeof SETTINGS_FIELDS)[number]): boolean =>\n form[key] !== (resolved[key] ?? SETTINGS_DEFAULTS[key])\n const dirty = draft !== null && SETTINGS_FIELDS.some(changed)\n\n const edit = (key: (typeof SETTINGS_FIELDS)[number], value: string | number | boolean): void => {\n setDraft({ ...form, [key]: value })\n }\n const save = (): void => {\n if (!scope) return\n for (const key of SETTINGS_FIELDS) {\n if (changed(key)) {\n scope.set(key, form[key]).catch((error: unknown) => {\n console.error('[dsh-code-index] settings save failed', error)\n })\n }\n }\n setDraft(null)\n }\n\n return (\n <li className={open ? 'dci-card dci-cardOpen' : 'dci-card'}>\n <style>{CARD_CSS}</style>\n <button\n type=\"button\"\n className=\"dci-header\"\n aria-expanded={open}\n aria-label={`${t(open ? 'collapse' : 'expand')}: dsh-code-index`}\n onClick={() => { setOpen(!open) }}\n >\n <span className=\"dci-headText\">\n <span className=\"dci-name\">dsh-code-index</span>\n <span className=\"dci-description\">{t('description')}</span>\n </span>\n <svg className={open ? 'dci-chevron dci-chevronOpen' : 'dci-chevron'} width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d={CHEVRON_PATH} fill=\"currentColor\" />\n </svg>\n </button>\n {open ? (\n <div className=\"dci-body\">\n <div className=\"dci-field\">\n <div className=\"dci-head\">\n <label className=\"dci-label\" htmlFor=\"dci-auto-inject\">{t('autoInject')}</label>\n <input\n id=\"dci-auto-inject\"\n className=\"dci-check\"\n type=\"checkbox\"\n checked={form.autoInject}\n disabled={!writable}\n onChange={(event) => { edit('autoInject', event.target.checked) }}\n />\n </div>\n <p className=\"dci-hint\">{t('autoInjectHint')}</p>\n </div>\n <div className=\"dci-field\">\n <div className=\"dci-head\">\n <label className=\"dci-label\" htmlFor=\"dci-code-health\">{t('codeHealth')}</label>\n <input\n id=\"dci-code-health\"\n className=\"dci-check\"\n type=\"checkbox\"\n checked={form.codeHealth}\n disabled={!writable}\n onChange={(event) => { edit('codeHealth', event.target.checked) }}\n />\n </div>\n <p className=\"dci-hint\">{t('codeHealthHint')}</p>\n </div>\n <div className=\"dci-field\">\n <div className=\"dci-head\">\n <label className=\"dci-label\" htmlFor=\"dci-map-files\">{t('mapFiles')}</label>\n </div>\n <input\n id=\"dci-map-files\"\n className=\"dci-input\"\n type=\"text\"\n inputMode=\"numeric\"\n value={String(form.mapTopFiles)}\n disabled={!writable}\n onChange={(event) => { edit('mapTopFiles', Number(event.target.value)) }}\n />\n <p className=\"dci-hint\">{t('mapFilesHint')}</p>\n </div>\n <div className=\"dci-footer\">\n <button type=\"button\" className=\"dci-discard\" disabled={!dirty || !writable} onClick={() => { setDraft(null) }}>\n {t('discard')}\n </button>\n <button type=\"button\" className=\"dci-save\" disabled={!dirty || !writable} onClick={save}>{t('save')}</button>\n </div>\n </div>\n ) : null}\n {scope ? null : <p className=\"dci-hint\" style={{ padding: '0 16px 12px' }}>{t('unavailable')}</p>}\n </li>\n )\n}\n\nexport const name = 'dsh-code-index'\n\n/** `slots` is required; config and locale services are injected optionally. */\nexport const inject = ['slots']\n\nconst TOOLVIEW_KEYS = [\n 'code_index',\n 'code_symbols',\n 'code_search',\n 'code_map',\n 'code_refs',\n 'code_change_context',\n 'code_context',\n 'code_health',\n]\n\nexport function apply(ctx: ClientContextLike): void {\n const card = CodeToolCard as unknown as (props: never) => ReactNode\n ctx.inject?.(['locale'], (localized) => {\n if (localized.locale) localized.effect(() => localized.locale!.register('settings.codeIndex', { zh: SETTINGS_ZH, en: SETTINGS_EN }))\n })\n ctx.slots.inject('tool.call.toolview', function* () {\n for (const key of TOOLVIEW_KEYS) {\n yield ctx.slots.register({ name: 'tool.call.toolview', key }, card)\n }\n })\n\n // New DSH exposes per-plugin volatile config forms and the plugin settings\n // tab. Keep the prior settingsScope slot for clients that still provide it.\n ctx.inject?.(['configForms'], (configured) => {\n const form = configured.configForms?.get('dsh-code-index') ?? configured.configForms?.get('code-index')\n if (!form) return\n configured.slots.inject('settings.plugins.tab', function* () {\n yield configured.slots.register(\n {\n name: 'settings.plugins.tab',\n id: 'code-index',\n order: 60,\n label: 'Code Index',\n locale: 'settings.codeIndex',\n inject: () => ({ scope: form }),\n },\n CodeIndexSettingsCard as unknown as (props: never) => ReactNode,\n )\n })\n })\n ctx.inject?.(['settingsScope'], (legacy) => {\n const settingsScope = legacy.settingsScope?.bind({ namespace: 'code-index' })\n legacy.slots.inject('settings.plugin.item', function* () {\n yield legacy.slots.register(\n {\n name: 'settings.plugin.item',\n key: 'code-index',\n locale: 'settings.codeIndex',\n inject: () => ({ scope: settingsScope }),\n },\n CodeIndexSettingsCard as unknown as (props: never) => ReactNode,\n )\n })\n })\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/client/index.tsx","../src/client/impact-xray.tsx","../src/impact-xray-model.ts","../src/client/xray-locales.ts"],"sourcesContent":["/**\n * Browser half of dsh-code-index: structured result cards for the code_* tools\n * plus a settings card for the `code-index` namespace.\n *\n * Deliberately imports no harness client package: this bundle only needs\n * `react` (a shell platform module) plus the slot registry and settings scope\n * services reached through the plugin context. Keeping the surface local avoids\n * a dependency on a synchronized client-package version.\n */\n\nimport { useEffect, useState, type ReactNode } from 'react'\nimport { asImpactXray, ImpactXrayCard, XrayFallback } from './impact-xray.js'\nimport { XRAY_EN, XRAY_ZH, type XrayLocaleStore } from './xray-locales.js'\n\n/** Minimal structural view of the client plugin context this bundle uses. */\ninterface ClientContextLike {\n effect(fn: () => (() => void) | void): void\n slots: {\n inject(name: string, run: () => Iterable<unknown>): void\n register(entry: Record<string, unknown>, component: (props: never) => ReactNode): () => void\n }\n inject?(deps: string[], run: (ctx: ClientContextLike) => void): unknown\n settingsScope?: { bind(spec: { namespace: string }): SettingsScopeLike<CodeIndexSettings> }\n configForms?: { get(id: string): SettingsScopeLike<CodeIndexSettings> | undefined }\n locale?: { register(namespace: string, dictionaries: { zh: Record<string, string>; en: Record<string, string> }): () => void\n getSnapshot?(): { active?: string }; subscribe?(listener: () => void): () => void }\n}\n\ninterface SettingsSnapshot<T> {\n status: 'loading' | 'ready' | 'unavailable'\n value: T | undefined\n writable: boolean\n}\n\ninterface SettingsScopeLike<T> {\n getSnapshot(): SettingsSnapshot<T>\n subscribe(listener: () => void): () => void\n set(field: string, value: unknown): Promise<void>\n unset(field: string): Promise<void>\n}\n\ninterface CodeIndexSettings {\n excludeDirs?: string[]\n mapTopFiles?: number\n mapMaxChars?: number\n mapTtlMs?: number\n autoInject?: boolean\n codeHealth?: boolean\n toolSurface?: 'full' | 'compact'\n}\n\ninterface ToolCallHead {\n name?: string\n argsRaw?: string\n}\n\ninterface TextContent {\n type?: string\n text?: string\n}\n\ninterface ToolResultLike {\n call?: ToolCallHead | null\n content?: readonly TextContent[]\n isError?: boolean\n resultView?: unknown\n meta?: unknown\n}\n\ninterface SearchView {\n card: 'search'\n shape?: 'matches' | 'paths'\n files?: Array<{ path: string; matches?: Array<{ lineNumber: number; line: string }> }>\n paths?: string[]\n truncated?: boolean\n total?: number\n}\n\ninterface ToolViewProps {\n phase?: string\n toolName: string\n block: ToolResultLike & ToolCallHead\n openFile?: (path: string, options?: unknown) => void\n localeStore?: XrayLocaleStore\n}\n\nconst CARD_STYLE: Record<string, string | number> = {\n border: '1px solid var(--dsh-border, #333)',\n borderRadius: 6,\n padding: '6px 8px',\n fontFamily: 'var(--dsh-mono-font, monospace)',\n fontSize: 12,\n margin: '4px 0',\n}\n\nconst ROW_STYLE: Record<string, string | number> = {\n display: 'flex',\n gap: 8,\n alignItems: 'baseline',\n}\n\nfunction parseArgs(raw: string | undefined): Record<string, unknown> {\n if (!raw) return {}\n try {\n const value: unknown = JSON.parse(raw)\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : {}\n } catch {\n return {}\n }\n}\n\nfunction summarizeArgs(args: Record<string, unknown>): string {\n const parts: string[] = []\n for (const key of ['task', 'query', 'symbol', 'action', 'direction', 'kind', 'budgetChars']) {\n const value = args[key]\n if (typeof value === 'string' && value) parts.push(`${key}=${value}`)\n }\n return parts.join(' ')\n}\n\nfunction asSearchView(view: unknown): SearchView | undefined {\n if (typeof view !== 'object' || view === null || Array.isArray(view)) return undefined\n const record = view as Record<string, unknown>\n return record.card === 'search' ? (record as unknown as SearchView) : undefined\n}\n\nfunction resultText(block: ToolResultLike): string {\n return (block.content ?? [])\n .filter((part) => part.type === 'text' && typeof part.text === 'string')\n .map((part) => part.text ?? '')\n .join('\\n')\n}\n\n/** One code tool's card: argument summary, structured search matches, or text. */\nfunction CodeToolCard(props: ToolViewProps): ReactNode {\n const { toolName, block, openFile } = props\n const head: ToolCallHead = block.call ?? block\n const args = parseArgs(head.argsRaw)\n const summary = summarizeArgs(args)\n const search = asSearchView(block.resultView)\n const isError = block.isError === true\n const xray = !isError && toolName === 'code_change_context' ? asImpactXray(block.meta) : null\n if (xray) return <ImpactXrayCard view={xray} openFile={openFile} localeStore={props.localeStore} rawText={resultText(block)} />\n if (toolName === 'code_change_context' && args.outputFormat === 'xray') return <XrayFallback loading={props.phase !== 'result' && !block.content} text={resultText(block)} localeStore={props.localeStore} />\n\n return (\n <div style={CARD_STYLE}>\n <div style={ROW_STYLE}>\n <strong>{toolName}</strong>\n {summary ? <span style={{ opacity: 0.75 }}>{summary}</span> : null}\n {isError ? <span style={{ color: '#e5534b' }}>error</span> : null}\n </div>\n {search?.shape === 'matches' && search.files ? (\n <div style={{ marginTop: 4 }}>\n {search.files.map((file) => (\n <div key={file.path}>\n <div style={{ opacity: 0.85 }}>{file.path}</div>\n {(file.matches ?? []).map((match, index) => (\n <div\n key={`${match.lineNumber}-${index}`}\n style={{ paddingLeft: 12, cursor: openFile ? 'pointer' : 'default' }}\n onClick={() => openFile?.(file.path, { line: match.lineNumber })}\n >\n <span style={{ opacity: 0.6 }}>{match.lineNumber}</span> {match.line}\n </div>\n ))}\n </div>\n ))}\n {search.truncated ? <div style={{ opacity: 0.6 }}>… truncated ({search.total} total)</div> : null}\n </div>\n ) : (\n <pre style={{ margin: '4px 0 0', whiteSpace: 'pre-wrap', maxHeight: 220, overflow: 'auto' }}>\n {resultText(block)}\n </pre>\n )}\n </div>\n )\n}\n\n/** Mirrors the first-party plugin card + field CSS modules, under our own class names. */\nconst CARD_CSS = `\n.dci-card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;list-style:none;transition:border-color .16s,background .16s}\n.dci-card:hover{border-color:var(--dsw-alias-label-dimmed)}\n.dci-cardOpen{background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-label-dimmed)}\n.dci-header{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;align-items:center;gap:12px;padding:14px 16px;display:flex}\n.dci-header:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}\n.dci-headText{flex-direction:column;flex:1 1 0%;gap:4px;min-width:0;display:flex}\n.dci-name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}\n.dci-description{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}\n.dci-chevron{color:var(--dsw-alias-label-tertiary);flex:0 0 auto;transition:transform .16s}\n.dci-chevronOpen{transform:rotate(180deg)}\n.dci-body{border-top:1px solid var(--dsw-alias-border-l2);margin:0 16px;padding-bottom:8px}\n.dci-field{flex-direction:column;gap:6px;padding:12px 0;display:flex}\n.dci-field+.dci-field{border-top:1px solid var(--dsw-alias-border-l2)}\n.dci-head{align-items:center;gap:8px;display:flex}\n.dci-label{min-width:0;color:var(--dsw-alias-label-primary);flex:1 1 0%;font-size:13px;font-weight:500;line-height:1.5}\n.dci-input{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);height:34px;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font:inherit;font-size:13px;line-height:1.5}\n.dci-input:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}\n.dci-input:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}\n.dci-check{width:16px;height:16px;flex:0 0 auto;accent-color:var(--dsw-alias-brand-primary)}\n.dci-hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}\n.dci-footer{border-top:1px solid var(--dsw-alias-border-l2);justify-content:flex-end;align-items:center;gap:8px;padding:12px 0 4px;display:flex}\n.dci-discard,.dci-save{appearance:none;font:inherit;cursor:pointer;border:1px solid transparent;border-radius:8px;padding:5px 14px;font-size:13px;line-height:1.5}\n.dci-discard{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:0 0}\n.dci-discard:hover:not(:disabled){color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-dimmed)}\n.dci-save{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3)}\n.dci-discard:disabled,.dci-save:disabled{opacity:.4;cursor:default}\n`\n\nconst CHEVRON_PATH =\n 'M11.8486 5.5L11.4238 5.92383L8.69727 8.65137C8.44157 8.90706 8.21562 9.13382 8.01172 9.29785C7.79912 9.46883 7.55595 9.61756 7.25 9.66602C7.08435 9.69222 6.91565 9.69222 6.75 9.66602C6.44405 9.61756 6.20088 9.46883 5.98828 9.29785C5.78438 9.13382 5.55843 8.90706 5.30273 8.65137L2.57617 5.92383L2.15137 5.5L3 4.65137L3.42383 5.07617L6.15137 7.80273C6.42595 8.07732 6.59876 8.24849 6.74023 8.3623C6.87291 8.46904 6.92272 8.47813 6.9375 8.48047C6.97895 8.48703 7.02105 8.48703 7.0625 8.48047C7.07728 8.47813 7.12709 8.46904 7.25977 8.3623C7.40124 8.24849 7.57405 8.07732 7.84863 7.80273L10.5762 5.07617L11 4.65137L11.8486 5.5Z'\n\nconst SETTINGS_DEFAULTS = { autoInject: true, codeHealth: false, mapTopFiles: 24 }\nconst SETTINGS_FIELDS = ['autoInject', 'codeHealth', 'mapTopFiles'] as const\n\n/** Settings card for `code-index`, laid out like the first-party plugin cards. */\nexport const SETTINGS_EN = {\n collapse: 'Collapse settings', expand: 'Expand settings',\n description: 'Project-aware live structural context: symbol search, repo map, and call graph.',\n autoInject: 'Inject repo map', autoInjectHint: 'Add a compact ranked map of the current project to the system prompt.',\n codeHealth: 'Code health tool', codeHealthHint: 'Register code_health for dependency cycles and orphan modules (restart required).',\n mapFiles: 'Map files', mapFilesHint: 'Maximum number of files shown in each repo map.',\n discard: 'Discard changes', save: 'Save', unavailable: 'Settings service unavailable.',\n}\nexport const SETTINGS_ZH = {\n collapse: '收起设置', expand: '展开设置',\n description: '项目感知的实时结构化上下文:符号搜索、仓库地图与调用图。',\n autoInject: '自动注入仓库地图', autoInjectHint: '把当前项目的精简排名地图注入系统提示词。',\n codeHealth: '代码健康工具', codeHealthHint: '注册 code_health 工具,报告环依赖与孤儿模块(重启后生效)。',\n mapFiles: '地图文件数', mapFilesHint: '仓库地图中最多展示的文件数。',\n discard: '放弃修改', save: '保存', unavailable: '设置服务不可用。',\n}\n\nfunction CodeIndexSettingsCard(props: { scope?: SettingsScopeLike<CodeIndexSettings>; t?: (key: string) => string }): ReactNode {\n const scope = props.scope ?? null\n const t = props.t ?? ((key: string) => SETTINGS_EN[key as keyof typeof SETTINGS_EN] ?? key)\n const [open, setOpen] = useState(false)\n const [snapshot, setSnapshot] = useState<SettingsSnapshot<CodeIndexSettings> | null>(\n scope ? scope.getSnapshot() : null,\n )\n const [draft, setDraft] = useState<CodeIndexSettings | null>(null)\n\n useEffect(() => {\n if (!scope) return\n setSnapshot(scope.getSnapshot())\n return scope.subscribe(() => setSnapshot(scope.getSnapshot()))\n }, [scope])\n\n const resolved = snapshot?.value ?? {}\n const form: CodeIndexSettings = { ...SETTINGS_DEFAULTS, ...resolved, ...draft }\n const writable = snapshot?.writable ?? false\n const changed = (key: (typeof SETTINGS_FIELDS)[number]): boolean =>\n form[key] !== (resolved[key] ?? SETTINGS_DEFAULTS[key])\n const dirty = draft !== null && SETTINGS_FIELDS.some(changed)\n\n const edit = (key: (typeof SETTINGS_FIELDS)[number], value: string | number | boolean): void => {\n setDraft({ ...form, [key]: value })\n }\n const save = (): void => {\n if (!scope) return\n for (const key of SETTINGS_FIELDS) {\n if (changed(key)) {\n scope.set(key, form[key]).catch((error: unknown) => {\n console.error('[dsh-code-index] settings save failed', error)\n })\n }\n }\n setDraft(null)\n }\n\n return (\n <li className={open ? 'dci-card dci-cardOpen' : 'dci-card'}>\n <style>{CARD_CSS}</style>\n <button\n type=\"button\"\n className=\"dci-header\"\n aria-expanded={open}\n aria-label={`${t(open ? 'collapse' : 'expand')}: dsh-code-index`}\n onClick={() => { setOpen(!open) }}\n >\n <span className=\"dci-headText\">\n <span className=\"dci-name\">dsh-code-index</span>\n <span className=\"dci-description\">{t('description')}</span>\n </span>\n <svg className={open ? 'dci-chevron dci-chevronOpen' : 'dci-chevron'} width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d={CHEVRON_PATH} fill=\"currentColor\" />\n </svg>\n </button>\n {open ? (\n <div className=\"dci-body\">\n <div className=\"dci-field\">\n <div className=\"dci-head\">\n <label className=\"dci-label\" htmlFor=\"dci-auto-inject\">{t('autoInject')}</label>\n <input\n id=\"dci-auto-inject\"\n className=\"dci-check\"\n type=\"checkbox\"\n checked={form.autoInject}\n disabled={!writable}\n onChange={(event) => { edit('autoInject', event.target.checked) }}\n />\n </div>\n <p className=\"dci-hint\">{t('autoInjectHint')}</p>\n </div>\n <div className=\"dci-field\">\n <div className=\"dci-head\">\n <label className=\"dci-label\" htmlFor=\"dci-code-health\">{t('codeHealth')}</label>\n <input\n id=\"dci-code-health\"\n className=\"dci-check\"\n type=\"checkbox\"\n checked={form.codeHealth}\n disabled={!writable}\n onChange={(event) => { edit('codeHealth', event.target.checked) }}\n />\n </div>\n <p className=\"dci-hint\">{t('codeHealthHint')}</p>\n </div>\n <div className=\"dci-field\">\n <div className=\"dci-head\">\n <label className=\"dci-label\" htmlFor=\"dci-map-files\">{t('mapFiles')}</label>\n </div>\n <input\n id=\"dci-map-files\"\n className=\"dci-input\"\n type=\"text\"\n inputMode=\"numeric\"\n value={String(form.mapTopFiles)}\n disabled={!writable}\n onChange={(event) => { edit('mapTopFiles', Number(event.target.value)) }}\n />\n <p className=\"dci-hint\">{t('mapFilesHint')}</p>\n </div>\n <div className=\"dci-footer\">\n <button type=\"button\" className=\"dci-discard\" disabled={!dirty || !writable} onClick={() => { setDraft(null) }}>\n {t('discard')}\n </button>\n <button type=\"button\" className=\"dci-save\" disabled={!dirty || !writable} onClick={save}>{t('save')}</button>\n </div>\n </div>\n ) : null}\n {scope ? null : <p className=\"dci-hint\" style={{ padding: '0 16px 12px' }}>{t('unavailable')}</p>}\n </li>\n )\n}\n\nexport const name = 'dsh-code-index'\n\n/** `slots` is required; config and locale services are injected optionally. */\nexport const inject = ['slots']\n\nconst TOOLVIEW_KEYS = [\n 'code_index',\n 'code_symbols',\n 'code_search',\n 'code_map',\n 'code_refs',\n 'code_change_context',\n 'code_context',\n 'code_health',\n]\n\nexport function apply(ctx: ClientContextLike): void {\n let locale: ClientContextLike['locale']\n const listeners = new Set<() => void>()\n const localeStore: XrayLocaleStore = { getSnapshot: () => locale?.getSnapshot?.().active ?? 'en',\n subscribe: (fn) => { listeners.add(fn); return () => { listeners.delete(fn) } } }\n const card = ((props: ToolViewProps) => <CodeToolCard {...props} localeStore={localeStore} />) as unknown as (props: never) => ReactNode\n ctx.inject?.(['locale'], (localized) => {\n if (localized.locale) localized.effect(() => localized.locale!.register('settings.codeIndex', { zh: SETTINGS_ZH, en: SETTINGS_EN }))\n if (localized.locale) localized.effect(() => {\n const service = localized.locale!\n locale = service\n const unregister = service.register('tools.impactXray', { zh: XRAY_ZH, en: XRAY_EN })\n const notify = (): void => { for (const fn of listeners) fn() }\n const off = service.subscribe?.(notify)\n notify()\n return () => { off?.(); unregister(); locale = undefined; notify() }\n })\n })\n ctx.slots.inject('tool.call.toolview', function* () {\n for (const key of TOOLVIEW_KEYS) {\n yield ctx.slots.register({ name: 'tool.call.toolview', key }, card)\n }\n })\n\n // New DSH exposes per-plugin volatile config forms and the plugin settings\n // tab. Keep the prior settingsScope slot for clients that still provide it.\n ctx.inject?.(['configForms'], (configured) => {\n const form = configured.configForms?.get('dsh-code-index') ?? configured.configForms?.get('code-index')\n if (!form) return\n configured.slots.inject('settings.plugins.tab', function* () {\n yield configured.slots.register(\n {\n name: 'settings.plugins.tab',\n id: 'code-index',\n order: 60,\n label: 'Code Index',\n locale: 'settings.codeIndex',\n inject: () => ({ scope: form }),\n },\n CodeIndexSettingsCard as unknown as (props: never) => ReactNode,\n )\n })\n })\n ctx.inject?.(['settingsScope'], (legacy) => {\n const settingsScope = legacy.settingsScope?.bind({ namespace: 'code-index' })\n legacy.slots.inject('settings.plugin.item', function* () {\n yield legacy.slots.register(\n {\n name: 'settings.plugin.item',\n key: 'code-index',\n locale: 'settings.codeIndex',\n inject: () => ({ scope: settingsScope }),\n },\n CodeIndexSettingsCard as unknown as (props: never) => ReactNode,\n )\n })\n })\n}\n","import { useEffect, useMemo, useRef, useState, useSyncExternalStore, type ReactNode } from 'react'\nimport { XRAY_LIMITS, type ImpactXray, type XrayEvidence, type XrayEdge, type XrayNode } from '../impact-xray-model.js'\nimport { FALLBACK_LOCALE, xrayTranslator, type XrayLocaleStore, type XrayTranslate } from './xray-locales.js'\n\nconst record = (v: unknown): v is Record<string, unknown> => typeof v === 'object' && v !== null && !Array.isArray(v)\nconst string = (v: unknown): v is string => typeof v === 'string' && v.length <= 4096\nconst line = (v: unknown): v is number => Number.isSafeInteger(v) && Number(v) >= 1\nconst label = (v: unknown): boolean => v === 'exact' || v === 'import-scoped' || v === 'name-only'\nconst evidence = (v: unknown): boolean => record(v) && string(v.file) && line(v.line) && line(v.startLine) &&\n (v.side === 'current' || v.side === 'base') && (v.ref === undefined || string(v.ref)) &&\n (v.type === undefined || string(v.type) && ['declaration', 'call-site', 'import-site', 'test-lead', 'unmapped-change'].includes(v.type)) &&\n (v.code === undefined || typeof v.code === 'string' && v.code.length <= XRAY_LIMITS.evidenceChars) && (v.gap === undefined || string(v.gap))\n\n/** Persisted results are untrusted input; reject malformed or oversized graphs. */\nexport function asImpactXray(v: unknown): ImpactXray | null {\n if (!record(v) || v.card !== 'impact-xray' || (v.version !== 1 && v.version !== 2) || !string(v.root) ||\n !string(v.source) || !['git', 'diff', 'files', 'symbols'].includes(v.source) || typeof v.truncated !== 'boolean') return null\n if (!Array.isArray(v.nodes) || v.nodes.length > XRAY_LIMITS.nodes || !Array.isArray(v.edges) || v.edges.length > XRAY_LIMITS.edges ||\n !Array.isArray(v.gaps) || v.gaps.length > 24 || !v.gaps.every(string)) return null\n if (!v.nodes.every(n => record(n) && string(n.id) && string(n.name) && string(n.kind) && string(n.file) && line(n.line) &&\n typeof n.changed === 'boolean' && string(n.reason) && evidence(n.evidence) &&\n (n.category === undefined || string(n.category) && ['change', 'caller', 'impact', 'module', 'test'].includes(n.category)) &&\n (n.resolution === undefined || label(n.resolution)) && (n.change === undefined || string(n.change)) &&\n (n.depth === undefined || Number.isInteger(n.depth) && Number(n.depth) >= 0 && Number(n.depth) <= 6))) return null\n const ids = new Set(v.nodes.map(n => n.id))\n if (ids.size !== v.nodes.length || !v.edges.every(e => record(e) && string(e.id) && ids.has(e.from) && ids.has(e.to) &&\n label(e.resolution) && string(e.reason) && evidence(e.evidence) && (e.kind === undefined || e.kind === 'call' || e.kind === 'import'))) return null\n const edgeIds = new Set(v.edges.map(e => e.id))\n if (edgeIds.size !== v.edges.length) return null\n if (!Array.isArray(v.tests) || v.tests.length > 8 || !v.tests.every(t => record(t) && string(t.file) && string(t.reason) && label(t.resolution) &&\n (t.nodeId === undefined || ids.has(t.nodeId)))) return null\n if (!Array.isArray(v.imports) || v.imports.length > 8 || !v.imports.every(i => record(i) && string(i.file) && string(i.changedFile) && string(i.specifier) &&\n i.resolution === 'import-scoped' && (i.edgeId === undefined || edgeIds.has(i.edgeId)))) return null\n if (v.paths !== undefined && (!Array.isArray(v.paths) || v.paths.length > XRAY_LIMITS.paths || !v.paths.every(p => record(p) && string(p.id) &&\n string(p.from) && string(p.to) && label(p.resolution) && typeof p.omitted === 'boolean' && Array.isArray(p.edgeIds) && p.edgeIds.length <= 6 && p.edgeIds.every(id => edgeIds.has(id))))) return null\n if (v.unmapped !== undefined && (!Array.isArray(v.unmapped) || v.unmapped.length > 8 || !v.unmapped.every(u => record(u) && string(u.file) &&\n string(u.reason) && (u.side === 'base' || u.side === 'current') && evidence(u.evidence) && Array.isArray(u.ranges) && u.ranges.length <= 16 &&\n u.ranges.every(r => record(r) && line(r.startLine) && line(r.endLine) && r.endLine >= r.startLine)))) return null\n if (v.bounds !== undefined && (!record(v.bounds) || typeof v.bounds.projection !== 'boolean' || !record(v.bounds.analysis) || !record(v.bounds.totals) ||\n !['callers', 'dependents', 'paths', 'impact', 'tests'].every(k => typeof (v.bounds as Record<string, Record<string, unknown>>).analysis[k] === 'boolean') ||\n !['changed', 'callers', 'impact', 'imports', 'tests', 'paths', 'unmapped'].every(k => Number.isSafeInteger((v.bounds as Record<string, Record<string, unknown>>).totals[k]) && Number((v.bounds as Record<string, Record<string, unknown>>).totals[k]) >= 0))) return null\n return v as unknown as ImpactXray\n}\n\nexport function sourcePath(root: string, file: string): string | null {\n const base = root.replace(/\\\\/g, '/'), relative = file.replace(/\\\\/g, '/')\n if (!(/^[A-Za-z]:\\//.test(base) || base.startsWith('/')) || !relative || /[\\u0000-\\u001f]/.test(base + relative) ||\n relative.startsWith('/') || relative.split('/').some(part => part === '..') || relative.includes(':')) return null\n return `${base.replace(/\\/$/, '')}/${relative}`\n}\ntype OpenFile = (path: string, options?: unknown) => unknown\ntype Selection = { type: 'node' | 'edge' | 'unmapped'; id: string }\nconst CSS = `\n.ix-dialog{width:min(1180px,96vw);max-width:96vw;max-height:90vh;padding:0;border:0;border-radius:12px;background:#161b24;color:#e7edf5;overflow:auto}.ix-dialog::backdrop{background:#000b}.ix-dialog .ix{min-height:70vh}.ix-dialog .ix-workspace{display:grid;grid-template-columns:minmax(0,1.2fr) minmax(0,1fr);gap:16px}.ix-dialog .ix-evidence{grid-column:2;grid-row:1}.ix-dialog .ix-relations{grid-column:1;grid-row:1}.ix-dialog .ix .pane{max-height:420px}.ix-dialog .ix .graph{max-height:410px}.ix-dialog .ix .code{max-height:240px}@media(max-width:750px){.ix-dialog .ix-workspace{display:block}}\n.ix .change-center{border-left:3px solid #f49b5c;background:#f49b5c0c;border-radius:6px;padding:8px 10px;margin:8px 0}.ix .change-center .chips{margin-top:5px}.ix .metrics{display:flex;gap:6px;flex-wrap:wrap;margin:8px 0}.ix .metrics span{padding:3px 8px;border-radius:5px;background:#65baf212}.ix .uncertainty{color:#e7b852;font-size:11px}.ix .heading{justify-content:space-between}.ix .heading h3{margin:0}.ix .heading .bar{margin:0}.ix .legend{margin:7px 0}\n.ix{border:1px solid var(--dsw-alias-border-l2,#455164);border-radius:12px;background:var(--dsw-alias-bg-layer-2,#161b24);color:var(--dsw-alias-label-primary,#e7edf5);font:12px/1.5 system-ui,sans-serif;padding:12px;overflow-wrap:anywhere;container-type:inline-size}\n.ix *{box-sizing:border-box}.ix h3,.ix p{margin:0 0 7px}.ix h3{font-size:17px}.ix small,.ix .muted{opacity:.72}.ix button,.ix select{font:inherit;color:inherit;border:1px solid var(--dsw-alias-border-l2,#4c586a);border-radius:6px;background:var(--dsw-alias-bg-layer-3,#253042);padding:4px 7px;cursor:pointer}.ix button:disabled{opacity:.35;cursor:default}.ix button:hover:not(:disabled),.ix button[aria-pressed=true]{border-color:#65baf2;background:var(--dsw-alias-bg-layer-1,#33465b)}.ix button:focus-visible,.ix select:focus-visible{outline:2px solid #65baf2;outline-offset:2px}.ix .bar{display:flex;gap:6px;align-items:center;flex-wrap:wrap;margin:8px 0}.ix .badge{font-size:10px;border-radius:4px;padding:1px 4px;background:#374151;color:#fff;white-space:nowrap}.ix .low{color:#e7b852}.ix .pane{border:1px solid var(--dsw-alias-border-l2,#455164);border-radius:8px;padding:9px;margin:8px 0;max-height:250px;overflow:auto}.ix .code{font:11px/1.6 var(--dsh-mono-font,monospace);white-space:pre-wrap;margin:8px 0;max-height:130px;overflow:auto}.ix .code span{display:block}.ix .code .focus{background:#28475b66}.ix .lane{display:grid;grid-template-columns:minmax(0,1fr) 100px minmax(0,1fr);align-items:center;gap:6px;margin:8px 0}.ix .node{text-align:left;min-height:45px;min-width:0;overflow:hidden}.ix .node.changed{border-left:3px solid #f49b5c}.ix .node small{display:block;font-size:10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.ix .edge{border:0;background:none!important;padding:0;display:flex;flex-direction:column;align-items:center}.ix .edge svg{width:100%;height:20px}.ix .edge small{font-size:9px}.ix .graph{max-height:310px;overflow:auto;padding:0 3px}.ix .notice{border-left:3px solid #e7b852;padding:5px 8px;margin:7px 0}.ix summary{cursor:pointer}.ix .tabs button[aria-pressed=true]{border-bottom:2px solid #65baf2}.ix .chips{display:flex;gap:5px;flex-wrap:wrap}.ix .chips button{text-align:left;max-width:100%}@container(max-width:360px){.ix .lane{grid-template-columns:minmax(0,1fr) 72px minmax(0,1fr)}.ix .node{font-size:11px;padding:4px}.ix .edge small{font-size:8px}}\n`\n\nfunction Evidence({ value, root, openFile, t }: { value: XrayEvidence; root: string; openFile?: OpenFile; t: XrayTranslate }): ReactNode {\n const [failed, setFailed] = useState(false)\n const path = sourcePath(root, value.file)\n const canOpen = value.side === 'current' && path && openFile && value.code !== undefined\n return <>\n <p><strong>{value.file}:{value.line}</strong> · {t(value.side)}{value.ref ? ` @ ${value.ref}` : ''}</p>\n <small>{t('evidenceType')}: {t(value.type ?? 'declaration')}</small>\n {value.code !== undefined ? <pre className=\"code\">{value.code.split('\\n').map((code, i) => <span className={value.startLine + i === value.line ? 'focus' : ''} key={i}>{value.startLine + i} {code}</span>)}</pre> : <p className=\"notice\" role=\"status\">{t(value.gap ?? 'missing')}</p>}\n <p className=\"muted\">{t('snapshot')}</p>\n {canOpen ? <button type=\"button\" onClick={() => { setFailed(false); try { Promise.resolve(openFile(path, { line: value.line })).catch(() => setFailed(true)) } catch { setFailed(true) } }}>{t('open', { line: value.line })}</button> : <small>{t('noOpen')}</small>}\n {failed ? <p role=\"alert\">{t('openFailed')}</p> : null}\n </>\n}\n\nexport function ImpactXrayCard({ view, openFile, localeStore = FALLBACK_LOCALE, rawText = '' }: { view: ImpactXray; openFile?: OpenFile; localeStore?: XrayLocaleStore; rawText?: string }): ReactNode {\n const active = useSyncExternalStore(localeStore.subscribe, localeStore.getSnapshot, localeStore.getSnapshot)\n const [language, setLanguage] = useState<string | null>(null)\n const t = xrayTranslator(language ?? active)\n const [tab, setTab] = useState('calls'), [visible, setVisible] = useState(6), [confidence, setConfidence] = useState('all'), [depth, setDepth] = useState(6)\n const [pathId, setPathId] = useState<string | null>(null)\n const [history, setHistory] = useState<Selection[]>(view.nodes[0] ? [{ type: 'node', id: view.nodes[0].id }] : [])\n const [cursor, setCursor] = useState(view.nodes.length ? 0 : -1), [showEvidence, setShowEvidence] = useState(true)\n const pane = useRef<HTMLDivElement>(null)\n const dialog = useRef<HTMLDialogElement>(null)\n const [focused, setFocused] = useState(false)\n useEffect(() => { if (focused && dialog.current && !dialog.current.open) dialog.current.showModal() }, [focused])\n const byId = useMemo(() => new Map(view.nodes.map(n => [n.id, n])), [view])\n const centers = view.nodes.filter(n => n.changed && n.kind !== 'module')\n const callCount = view.edges.filter(e => e.kind !== 'import').length\n const importCount = view.edges.length - callCount\n const weakCount = view.edges.filter(e => e.resolution === 'name-only').length\n const selected = history[cursor]\n const selectedNode = selected?.type === 'node' ? byId.get(selected.id) : undefined\n const selectedEdge = selected?.type === 'edge' ? view.edges.find(e => e.id === selected.id) : undefined\n const unmapped = selected?.type === 'unmapped' ? view.unmapped?.[Number(selected.id)] : undefined\n const selectedEvidence = selectedNode?.evidence ?? selectedEdge?.evidence ?? unmapped?.evidence\n const pick = (type: Selection['type'], id: string): void => {\n setHistory(h => [...h.slice(0, cursor + 1), { type, id }].slice(-32)); setCursor(Math.min(cursor + 1, 31)); setShowEvidence(true)\n requestAnimationFrame(() => pane.current?.scrollIntoView({ block: 'nearest' }))\n }\n const path = view.paths?.find(p => p.id === pathId)\n const filtered = view.edges.filter(e => (tab === 'imports' ? e.kind === 'import' : e.kind !== 'import') &&\n (confidence === 'all' || e.resolution === confidence) && (byId.get(e.from)?.depth ?? 1) <= depth && (!path || path.edgeIds.includes(e.id)))\n const nodeButton = (n: XrayNode): ReactNode => <button type=\"button\" key={n.id} className={`node ${n.changed ? 'changed' : ''}`} aria-pressed={selectedNode?.id === n.id} onClick={() => pick('node', n.id)}>\n {n.name}<small>{n.file}:{n.line}</small><span className=\"badge\">{t(n.category ?? (n.changed ? 'change' : 'caller'))}</span>\n </button>\n const graph = <>\n <div className=\"bar\"><label>{t('depth')} <select aria-label={t('depth')} value={depth} onChange={e => setDepth(Number(e.target.value))}>{[1, 2, 3, 4, 5, 6].map(d => <option key={d}>{d}</option>)}</select></label>\n <select aria-label={t('all')} value={confidence} onChange={e => setConfidence(e.target.value)}><option value=\"all\">{t('all')}</option>{['exact', 'import-scoped', 'name-only'].map(s => <option value={s} key={s}>{t(s)}</option>)}</select>\n <button type=\"button\" onClick={() => { setDepth(6); setConfidence('all'); setPathId(null); setVisible(6) }}>{t('reset')}</button>\n </div>\n <small>{t('rows', { shown: Math.min(visible, filtered.length), total: filtered.length })}</small>\n <div className=\"graph\" aria-label={t(tab === 'imports' ? 'imports' : 'calls')}>\n {filtered.slice(0, visible).map(e => <div className=\"lane\" key={e.id}>\n {nodeButton(byId.get(e.from)!)}\n <button type=\"button\" className={`edge ${e.resolution === 'name-only' ? 'low' : ''}`} aria-pressed={selectedEdge?.id === e.id} aria-label={`${t('inspect')}: ${byId.get(e.from)!.name} → ${byId.get(e.to)!.name} · ${e.resolution}`} onClick={() => pick('edge', e.id)}>\n <small>{e.resolution}</small><svg viewBox=\"0 0 100 20\" aria-hidden=\"true\"><path d=\"M 2 10 H 88\" stroke={e.resolution === 'name-only' ? '#e7b852' : '#65baf2'} strokeWidth=\"2\" strokeDasharray={e.resolution === 'exact' ? undefined : e.resolution === 'name-only' ? '2 5' : '9 5'} /><path d=\"M 87 5 L 96 10 L 87 15\" fill=\"none\" stroke=\"#65baf2\" strokeWidth=\"2\" /></svg><small>{t(e.kind ?? 'call')}</small>\n </button>{nodeButton(byId.get(e.to)!)}</div>)}\n {!filtered.length ? <p role=\"status\">{t(view.nodes.length ? 'noMatch' : 'empty')}</p> : null}\n </div>\n <div className=\"bar\">{visible < filtered.length ? <button type=\"button\" onClick={() => setVisible(v => v + 6)}>{t('expand')} (+6)</button> : null}{visible > 6 ? <button type=\"button\" onClick={() => setVisible(6)}>{t('collapse')}</button> : null}</div>\n </>\n const card = <section className=\"ix\" aria-label=\"Impact X-Ray\"><style>{CSS}</style>\n <div className=\"bar heading\"><h3>Impact X-Ray</h3><div className=\"bar\"><button type=\"button\" aria-label=\"English\" onClick={() => setLanguage('en')}>EN</button><button type=\"button\" aria-label=\"简体中文\" onClick={() => setLanguage('zh')}>简体中文</button><button type=\"button\" onClick={() => setFocused(v => !v)}>{t(focused ? 'closeView' : 'focusView')}</button></div></div>\n <p>{t('subtitle')}</p><small>{t('source')}: {t(view.source)} · {t('snapshotCounts')}</small>\n <div className=\"change-center\"><strong>{t(view.source === 'git' || view.source === 'diff' ? 'changeCenter' : 'selectionCenter')}</strong>\n {centers.length ? <div className=\"chips\">{centers.map(nodeButton)}</div> : <p>{t('noCenter')}</p>}</div>\n <div className=\"metrics\" aria-label={t('snapshotCounts')}><span>{t('callCount', { count: callCount })}</span><span>{t('importCount', { count: importCount })}</span><span>{t('testCount', { count: view.tests.length })}</span></div>\n <p className=\"uncertainty\">{t('potential')} · {t('weakCount', { count: weakCount })} · {t('unmappedCount', { count: view.unmapped?.length ?? 0 })}</p>\n {view.version === 1 ? <p className=\"notice\">{t('saved')}</p> : null}\n {view.truncated ? <p className=\"notice\">{t('displayCut')}</p> : null}\n <div className=\"ix-workspace\"><div className=\"ix-evidence\">\n <div className=\"bar\"><strong>{t('inspect')}</strong><button type=\"button\" aria-label={t('back')} disabled={cursor <= 0} onClick={() => setCursor(c => c - 1)}>←</button><button type=\"button\" aria-label={t('forward')} disabled={cursor >= history.length - 1} onClick={() => setCursor(c => c + 1)}>→</button><button type=\"button\" onClick={() => setShowEvidence(v => !v)}>{t(showEvidence ? 'collapse' : 'expand')}</button></div>\n {showEvidence ? <div className=\"pane\" ref={pane} aria-live=\"polite\">\n <p><strong>{selectedNode?.name ?? (selectedEdge ? `${byId.get(selectedEdge.from)?.name} → ${byId.get(selectedEdge.to)?.name}` : unmapped?.file ?? t('inspect'))}</strong></p>\n {selectedEdge || selectedNode ? <p>{t('reason')}: {t(selectedEdge?.reason ?? selectedNode!.reason)} {selectedNode?.change ? `· ${t(selectedNode.change)}` : ''} {selectedEdge?.resolution || selectedNode?.resolution ? `· ${t(selectedEdge?.resolution ?? selectedNode!.resolution!)}` : ''}</p> : null}\n {selectedEvidence ? <Evidence key={`${selected?.type}:${selected?.id}`} value={selectedEvidence} root={view.root} openFile={openFile && focused ? (file, options) => Promise.resolve(openFile(file, options)).then(() => setFocused(false)) : openFile} t={t} /> : <p>{t('missing')}</p>}\n </div> : null}\n </div><div className=\"ix-relations\"><div className=\"bar tabs\" role=\"group\">{['calls', 'imports', 'tests', 'paths', 'gaps'].map(key => <button type=\"button\" key={key} aria-pressed={tab === key} onClick={() => { setTab(key); setVisible(6); if (key !== 'calls') setPathId(null) }}>{t(key)}</button>)}</div>\n {tab === 'calls' ? <>{graph}<details className=\"legend\"><summary>{t('legendTitle')}</summary><p>{t('legend')}</p></details></> : null}\n {tab === 'imports' ? <>{graph}<details className=\"legend\"><summary>{t('legendTitle')}</summary><p>{t('legend')}</p></details>{view.imports.filter(i => !i.edgeId).map((i, n) => <p className=\"notice\" key={n}>{i.file} → {i.changedFile} · {t('import-site-unavailable')}</p>)}</> : null}\n {tab === 'tests' ? <><p>{t('testCaveat')}</p>{!view.tests.length ? <p>{t('noTests')}</p> : view.tests.map((test, i) => <div className=\"bar\" key={i}>\n {test.nodeId && byId.has(test.nodeId) ? nodeButton(byId.get(test.nodeId)!) : <span>{test.file} · {t('missing')}</span>}<span>{t(test.resolution)} · {t(test.reason)}</span>\n </div>)}</> : null}\n {tab === 'paths' ? <>{!view.paths?.length ? <p>{t('noPaths')}</p> : view.paths.map(p => <div className=\"pane\" key={p.id}><strong>{p.from} → {p.to}</strong><p>{t('pathConfidence')}: {t(p.resolution)}</p>{p.omitted ? <p className=\"notice\">{t('incompletePath')}</p> : null}<div className=\"bar\">{p.edgeIds.map((id, i) => <button type=\"button\" key={`${id}:${i}`} onClick={() => pick('edge', id)}>{t('pathStep', { step: i + 1, total: p.edgeIds.length })}</button>)}<button type=\"button\" disabled={p.omitted} onClick={() => { setPathId(p.id); setTab('calls'); setVisible(48); setConfidence('all'); setDepth(6) }}>{t('calls')}</button></div></div>)}</> : null}\n {tab === 'gaps' ? <><h4>{t('unmapped')}</h4>{view.unmapped?.map((u, i) => <div key={i}><button type=\"button\" onClick={() => pick('unmapped', String(i))}>{u.file} · {t(u.side)}</button><p>{t(u.reason)} · {t('ranges')}: {u.ranges.map(r => `${r.startLine}–${r.endLine}`).join(', ')}</p></div>)}\n {view.bounds && Object.values(view.bounds.analysis).some(Boolean) ? <p className=\"notice\">{t('analysisCut')}: {Object.entries(view.bounds.analysis).filter(([, v]) => v).map(([k]) => t(k)).join(', ')}</p> : null}\n {view.bounds?.projection ? <p className=\"notice\">{t('displayCut')}</p> : null}{view.bounds?.text ? <p>{t('textCut')}</p> : null}\n {view.gaps.map((gap, i) => <p className=\"notice\" key={i}>{t(gap)}</p>)}<p>{t('caveat')}</p></> : null}\n </div></div><details><summary>{t('uncertain')}</summary><p>{t('caveat')}</p></details>\n {rawText ? <details><summary>{t('raw')}</summary><pre className=\"code\">{rawText}</pre></details> : null}\n </section>\n return focused ? <dialog className=\"ix-dialog\" ref={dialog} aria-label=\"Impact X-Ray\" onClose={() => setFocused(false)}>{card}</dialog> : card\n}\n\nexport function XrayFallback({ loading, text, localeStore = FALLBACK_LOCALE }: { loading: boolean; text: string; localeStore?: XrayLocaleStore }): ReactNode {\n const active = useSyncExternalStore(localeStore.subscribe, localeStore.getSnapshot, localeStore.getSnapshot), t = xrayTranslator(active)\n return <section className=\"ix\" role={loading ? 'status' : 'alert'}><style>{CSS}</style><h3>Impact X-Ray</h3><p>{t(loading ? 'loading' : 'error')}</p>{!loading ? <><p>{t('fallback')}</p><pre className=\"code\">{text}</pre></> : null}</section>\n}\n","import type { ChangeContextResult, ImpactHop } from './change-context.js'\n\n/** Browser-safe presentation contract. Persisted v1 PoCs remain readable. */\nexport const XRAY_LIMITS = { nodes: 32, edges: 48, paths: 12, evidenceChars: 900, metadataBytes: 96_000 } as const\nexport interface XrayEvidence {\n file: string\n line: number\n startLine: number\n side: 'current' | 'base'\n ref?: string\n type?: 'declaration' | 'call-site' | 'import-site' | 'test-lead' | 'unmapped-change'\n code?: string\n gap?: string\n}\nexport interface XrayNode {\n id: string\n name: string\n kind: string\n file: string\n line: number\n changed: boolean\n category?: 'change' | 'caller' | 'impact' | 'module' | 'test'\n depth?: number\n resolution?: ImpactHop['resolution']\n change?: string\n reason: string\n evidence: XrayEvidence\n}\nexport interface XrayEdge {\n id: string\n from: string\n to: string\n kind?: 'call' | 'import'\n resolution: ImpactHop['resolution']\n reason: string\n evidence: XrayEvidence\n}\nexport interface XrayPath {\n id: string\n from: string\n to: string\n edgeIds: string[]\n resolution: ImpactHop['resolution']\n omitted: boolean\n}\nexport interface ImpactXray {\n card: 'impact-xray'\n version: 1 | 2\n root: string\n source: ChangeContextResult['source']\n nodes: XrayNode[]\n edges: XrayEdge[]\n tests: Array<ChangeContextResult['tests'][number] & { nodeId?: string }>\n imports: Array<ChangeContextResult['importDependents'][number] & { edgeId?: string }>\n paths?: XrayPath[]\n unmapped?: Array<ChangeContextResult['unmapped'][number] & { evidence: XrayEvidence }>\n bounds?: { analysis: ChangeContextResult['truncated']; projection: boolean; text?: boolean; totals: { changed: number; callers: number; impact: number; imports: number; tests: number; paths: number; unmapped: number } }\n gaps: string[]\n truncated: boolean\n}\n","export const XRAY_EN = {\n changeCenter: 'Changed symbols', selectionCenter: 'Selected symbols · not a proven edit', noCenter: 'No mapped symbol. Inspect unmapped changes in Gaps & limits.',\n snapshotCounts: 'In this bounded snapshot', callCount: '{count} call relations', importCount: '{count} import relations', testCount: '{count} test leads',\n weakCount: '{count} name-only candidates', unmappedCount: '{count} unmapped entries', legendTitle: 'Line styles & direction',\n focusView: 'Expand view', closeView: 'Close expanded view',\n subtitle: 'See the blast radius before your AI edits the code.', calls: 'Call graph', imports: 'Import graph', tests: 'Test leads', paths: 'Impact paths', gaps: 'Gaps & limits',\n potential: 'Potential impact, not a runtime guarantee', changed: 'Changed / selected', snapshot: 'Source snapshot captured with this result. The working tree may since have changed.',\n exact: 'exact · structurally resolved', 'import-scoped': 'import-scoped · import scope', 'name-only': 'name-only · low confidence',\n legend: 'Solid: exact. Dashed: import-scoped. Dotted amber: name-only. Arrows follow actual caller → callee or importer → module.',\n inspect: 'Inspect the evidence', reason: 'Included because', evidenceType: 'Evidence type', source: 'Change source', current: 'current', base: 'base',\n empty: 'No mapped symbols or relationships. Check unmapped changes and analysis gaps.', loading: 'Analyzing changes…', error: 'Impact X-Ray unavailable', fallback: 'Showing the original tool text. Rerun with outputFormat=\"xray\" to request fresh evidence.',\n expand: 'Expand', collapse: 'Collapse', all: 'All confidence levels', depth: 'Max caller depth', rows: '{shown} / {total} relations', nodes: '{count} nodes',\n open: 'Open current file at line {line}', openFailed: 'The host could not open this file. The saved source snapshot remains available.', noOpen: 'Native file preview unavailable for this evidence.',\n raw: 'Original tool text', back: 'Previous selection', forward: 'Next selection', reset: 'Reset filters', noMatch: 'No relations match these filters.',\n uncertain: 'Know what remains uncertain', caveat: 'exact describes structural resolution under the index, not guaranteed runtime behavior. Test leads do not prove coverage. Ownerless calls, dynamic dispatch and historical call graphs may be absent.',\n analysisCut: 'The analysis engine truncated these categories', displayCut: 'The presentation budget omitted some rows or source. Missing rows are not proof of no impact.', textCut: 'The optional X-Ray text was shortened; the default text tool is unchanged.',\n saved: 'Saved PoC result: some newer evidence fields are unavailable. The original relationships are preserved.',\n pathConfidence: 'Whole-path confidence', incompletePath: 'Some path steps are outside this bounded snapshot.', pathStep: 'Step {step} / {total}',\n noTests: 'No related indexed tests found. This does not establish test coverage.', noPaths: 'No entry-point paths were returned.', testCaveat: 'A test lead is a candidate to inspect, not proof that the test calls a particular function or will fail.',\n unmapped: 'Unmapped changes', ranges: 'Changed line ranges', missing: 'No source evidence available.',\n 'source-unavailable': 'Source is unavailable, stale, unindexed, or outside the repository.', 'line-unavailable': 'The recorded line is no longer available.', 'source-budget': 'Source exceeds the evidence budget. No partial line is presented as complete code.',\n 'endpoint-unavailable': 'A relationship endpoint is absent from the current index.', 'import-site-unavailable': 'An import lead lacks an indexed import statement or a displayed endpoint.', 'metadata-budget': 'Presentation exceeds its size budget. Select a smaller change set.',\n 'declaration': 'declaration window', 'call-site': 'actual call site', 'import-site': 'actual import statement', 'test-lead': 'test file context (not a call proof)', 'unmapped-change': 'unmapped diff context',\n 'diff-mapping': 'diff intersects the declaration', 'explicit-selection': 'explicit selection; not a proven edit', 'changed-module': 'module with a mapped or unmapped change', module: 'module context', 'import-dependent': 'module imports a changed file',\n 'structural-owner': 'AST structural owner', 'local-unique': 'same-file name candidate; shadowing is not ruled out', 'explicit-import-binding': 'explicit imported binding', 'namespace-import': 'namespace import scope', 'resolved-import-module': 'name exists in an imported module', 'global-name': 'repository-wide name match',\n 'changed-test': 'the test file changed', 'imports-changed-file': 'imports a changed file', 'imports-impact-file': 'imports a caller/impact file', 'references-symbol-name': 'matches a changed symbol name', 'path-convention': 'matches a test path convention only',\n 'outside-symbol': 'changed lines are outside indexed declarations', 'base-content-unavailable': 'baseline content could not be mapped',\n modified: 'modified', added: 'added', deleted: 'deleted', renamed: 'renamed', unclassified: 'unclassified',\n change: 'change', caller: 'direct caller', impact: 'indirect caller', test: 'test', call: 'call', import: 'import',\n git: 'working-tree Git diff', diff: 'supplied diff', files: 'explicit files', symbols: 'explicit symbols',\n} as const\nexport type XrayKey = keyof typeof XRAY_EN\nexport const XRAY_ZH: Record<XrayKey, string> = {\n changeCenter: '真实变更中心', selectionCenter: '选择中心 · 不证明实际修改', noCenter: '未映射到符号,请在“缺口与边界”检查未映射变更。',\n snapshotCounts: '本次有界快照', callCount: '{count} 条调用关系', importCount: '{count} 条导入关系', testCount: '{count} 条测试线索',\n weakCount: '{count} 条仅名称候选', unmappedCount: '{count} 项未映射变更', legendTitle: '线型与箭头方向',\n focusView: '放大查看', closeView: '关闭放大视图',\n subtitle: '在 AI 修改代码前,看清潜在影响范围。', calls: '调用图', imports: '导入图', tests: '测试线索', paths: '影响路径', gaps: '缺口与边界',\n potential: '潜在影响,不是运行时保证', changed: '变更 / 选择中心', snapshot: '这是本次结果保存的源码快照,工作区随后可能已经变化。',\n exact: 'exact · 结构解析', 'import-scoped': 'import-scoped · 导入范围', 'name-only': 'name-only · 低置信度',\n legend: '实线:exact;虚线:import-scoped;黄色点线:name-only。箭头保留真实调用者 → 被调用者或导入者 → 模块方向。',\n inspect: '检查源码证据', reason: '纳入原因', evidenceType: '证据类型', source: '变更来源', current: '当前', base: '基线',\n empty: '没有映射到符号或关系,请查看未映射变更和分析缺口。', loading: '正在分析变更…', error: 'Impact X-Ray 暂不可用', fallback: '下方保留原始工具文本。使用 outputFormat=\"xray\" 重新运行可请求新的证据快照。',\n expand: '展开', collapse: '收起', all: '全部置信度', depth: '最大调用者深度', rows: '{shown} / {total} 条关系', nodes: '{count} 个节点',\n open: '打开当前文件第 {line} 行', openFailed: '宿主未能打开文件,仍可查看已保存的源码快照。', noOpen: '该证据没有可用的原生文件预览入口。',\n raw: '原始工具文本', back: '上一个选择', forward: '下一个选择', reset: '重置筛选', noMatch: '没有符合当前筛选的关系。',\n uncertain: '了解仍不确定的部分', caveat: 'exact 表示索引模型内的结构解析,不保证运行时行为。测试线索不证明覆盖率;模块级无所属调用、动态分派及历史调用图可能未覆盖。',\n analysisCut: '分析引擎已裁剪以下类别', displayCut: '展示预算省略了部分行或源码;没有显示不代表没有影响。', textCut: '可选 X-Ray 模式的文本已缩短;默认文本工具保持不变。',\n saved: '这是已保存的 PoC 结果,部分新证据字段不可用;原始关系仍被保留。',\n pathConfidence: '整条路径置信度', incompletePath: '部分路径步骤不在本次有界快照内。', pathStep: '第 {step} / {total} 步',\n noTests: '未找到相关的已索引测试;这不能证明测试覆盖情况。', noPaths: '分析未返回入口路径。', testCaveat: '测试线索是待检查的候选,不证明测试调用了某个函数,也不保证测试会失败。',\n unmapped: '未映射变更', ranges: '变更行范围', missing: '没有可用的源码证据。',\n 'source-unavailable': '源码不可用、已过期、未索引,或位于仓库范围之外。', 'line-unavailable': '记录的行号已不可用。', 'source-budget': '源码超出证据预算,不将截断行伪装成完整代码。',\n 'endpoint-unavailable': '当前索引缺少关系端点。', 'import-site-unavailable': '导入线索缺少已索引的导入语句或可显示的端点。', 'metadata-budget': '展示结果超出体积预算,请缩小变更选择。',\n 'declaration': '声明窗口', 'call-site': '真实调用位置', 'import-site': '真实导入语句', 'test-lead': '测试文件上下文(不是调用证明)', 'unmapped-change': '未映射差异上下文',\n 'diff-mapping': '差异行与声明相交', 'explicit-selection': '显式选择,不证明实际发生修改', 'changed-module': '包含已映射或未映射变更的模块', module: '模块上下文', 'import-dependent': '模块导入了变更文件',\n 'structural-owner': 'AST 结构所属关系', 'local-unique': '同文件名称候选,尚不能排除遮蔽', 'explicit-import-binding': '显式导入绑定', 'namespace-import': 'namespace 导入范围', 'resolved-import-module': '名称存在于已导入模块', 'global-name': '仓库范围名称匹配',\n 'changed-test': '测试文件发生变更', 'imports-changed-file': '导入了变更文件', 'imports-impact-file': '导入了调用者或影响文件', 'references-symbol-name': '匹配变更符号名称', 'path-convention': '仅匹配测试路径惯例',\n 'outside-symbol': '变更行位于已索引声明范围之外', 'base-content-unavailable': '无法映射基线内容',\n modified: '修改', added: '新增', deleted: '删除', renamed: '重命名', unclassified: '未分类',\n change: '变更', caller: '直接调用者', impact: '间接调用者', test: '测试', call: '调用', import: '导入',\n git: '工作区 Git 差异', diff: '输入差异', files: '显式文件选择', symbols: '显式符号选择',\n}\nexport type XrayTranslate = (key: string, params?: Record<string, string | number>) => string\nexport function xrayTranslator(language: string): XrayTranslate {\n const dict = language.toLowerCase().startsWith('zh') ? XRAY_ZH : XRAY_EN\n return (key, params = {}) => (Object.hasOwn(dict, key) ? (dict as Record<string, string>)[key]! : key).replace(/\\{(\\w+)\\}/g, (match, name: string) => String(params[name] ?? match))\n}\nexport interface XrayLocaleStore { getSnapshot(): string; subscribe(listener: () => void): () => void }\nexport const FALLBACK_LOCALE: XrayLocaleStore = { getSnapshot: () => 'en', subscribe: () => () => {} }\n"],"mappings":"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","names":["import_react","name","import_jsx_runtime","record"]}
package/dist/index.d.ts CHANGED
@@ -417,6 +417,7 @@ interface ChangeContextResult {
417
417
  };
418
418
  }
419
419
  interface CodeChangeContextArgs {
420
+ outputFormat?: 'text' | 'xray';
420
421
  repoRoot?: string;
421
422
  diff?: string;
422
423
  baseRef?: string;
@@ -571,6 +572,93 @@ declare function renderTaskContext(result: TaskContextResult): string;
571
572
 
572
573
  declare const tools: _deepseek_ai_dsh_tools.ToolDefinition[];
573
574
 
575
+ /** Browser-safe presentation contract. Persisted v1 PoCs remain readable. */
576
+ declare const XRAY_LIMITS: {
577
+ readonly nodes: 32;
578
+ readonly edges: 48;
579
+ readonly paths: 12;
580
+ readonly evidenceChars: 900;
581
+ readonly metadataBytes: 96000;
582
+ };
583
+ interface XrayEvidence {
584
+ file: string;
585
+ line: number;
586
+ startLine: number;
587
+ side: 'current' | 'base';
588
+ ref?: string;
589
+ type?: 'declaration' | 'call-site' | 'import-site' | 'test-lead' | 'unmapped-change';
590
+ code?: string;
591
+ gap?: string;
592
+ }
593
+ interface XrayNode {
594
+ id: string;
595
+ name: string;
596
+ kind: string;
597
+ file: string;
598
+ line: number;
599
+ changed: boolean;
600
+ category?: 'change' | 'caller' | 'impact' | 'module' | 'test';
601
+ depth?: number;
602
+ resolution?: ImpactHop['resolution'];
603
+ change?: string;
604
+ reason: string;
605
+ evidence: XrayEvidence;
606
+ }
607
+ interface XrayEdge {
608
+ id: string;
609
+ from: string;
610
+ to: string;
611
+ kind?: 'call' | 'import';
612
+ resolution: ImpactHop['resolution'];
613
+ reason: string;
614
+ evidence: XrayEvidence;
615
+ }
616
+ interface XrayPath {
617
+ id: string;
618
+ from: string;
619
+ to: string;
620
+ edgeIds: string[];
621
+ resolution: ImpactHop['resolution'];
622
+ omitted: boolean;
623
+ }
624
+ interface ImpactXray {
625
+ card: 'impact-xray';
626
+ version: 1 | 2;
627
+ root: string;
628
+ source: ChangeContextResult['source'];
629
+ nodes: XrayNode[];
630
+ edges: XrayEdge[];
631
+ tests: Array<ChangeContextResult['tests'][number] & {
632
+ nodeId?: string;
633
+ }>;
634
+ imports: Array<ChangeContextResult['importDependents'][number] & {
635
+ edgeId?: string;
636
+ }>;
637
+ paths?: XrayPath[];
638
+ unmapped?: Array<ChangeContextResult['unmapped'][number] & {
639
+ evidence: XrayEvidence;
640
+ }>;
641
+ bounds?: {
642
+ analysis: ChangeContextResult['truncated'];
643
+ projection: boolean;
644
+ text?: boolean;
645
+ totals: {
646
+ changed: number;
647
+ callers: number;
648
+ impact: number;
649
+ imports: number;
650
+ tests: number;
651
+ paths: number;
652
+ unmapped: number;
653
+ };
654
+ };
655
+ gaps: string[];
656
+ truncated: boolean;
657
+ }
658
+
659
+ /** Presentation of existing analysis. Never resolves new function-call edges. */
660
+ declare function buildImpactXray(index: RepoIndex, result: ChangeContextResult): Promise<ImpactXray>;
661
+
574
662
  /** Plugin configuration: merged once at apply time, read wherever needed. */
575
663
 
576
664
  /** DSH 0.1.7+ renders fields marked volatile in its per-plugin config forms. */
@@ -650,4 +738,4 @@ declare const name = "dsh-code-index";
650
738
  declare const inject: readonly ["tools", "systemPrompt"];
651
739
  declare function apply(ctx: MinimalContext, pluginConfig?: PluginConfig): void;
652
740
 
653
- export { type AffectedTest, CACHE_DIR_NAME, type ChangeContextInput, type ChangeContextOptions, type ChangeContextResult, type ChangeKind, type ChangedSymbol, type CodeChangeContextArgs, Config, type ContextFile, type ContextOptions, type ContextPack, type ContextPackItem, type ContextRelationship, type ContextRoute, type ContextSymbol, type ContextTaskKind, DEFAULT_EXCLUDED_DIRS, type DiffHunk, type FileChange, type ImpactHop, type ImpactRow, type ImportDependent, type IndexOptions, type IndexedFile, type ParseDiagnostic, type RepoIndex, SUPPORTED_EXTS, type SymbolInfo, type SymbolKind, type SymbolPath, type TaskContextResult, type UnmappedChange, apply, buildChangeContext, buildIndex, buildIndexWithCache, buildModuleGraph, buildSymbolTable, buildTaskContext, callerCounts, changeContextInputFromArgs, defaultCachePath, extractAll, extractSymbols, findCycles, findOrphanModules, findRepoRoot, indexIntegrityWarnings, inject, languageForFile, loadIndex, name, parseFileToSymbols, parseUnifiedDiff, rankRepoMap, readGitFileAtRef, readWorkingTreeDiff, renderChangeContext, renderContextPack, renderHit, renderRepoMap, renderTaskContext, routeTask, saveIndex, scanRepo, scoreFile, searchSymbols, symbolCount, symbolRefs, tools };
741
+ export { type AffectedTest, CACHE_DIR_NAME, type ChangeContextInput, type ChangeContextOptions, type ChangeContextResult, type ChangeKind, type ChangedSymbol, type CodeChangeContextArgs, Config, type ContextFile, type ContextOptions, type ContextPack, type ContextPackItem, type ContextRelationship, type ContextRoute, type ContextSymbol, type ContextTaskKind, DEFAULT_EXCLUDED_DIRS, type DiffHunk, type FileChange, type ImpactHop, type ImpactRow, type ImpactXray, type ImportDependent, type IndexOptions, type IndexedFile, type ParseDiagnostic, type RepoIndex, SUPPORTED_EXTS, type SymbolInfo, type SymbolKind, type SymbolPath, type TaskContextResult, type UnmappedChange, XRAY_LIMITS, type XrayEdge, type XrayEvidence, type XrayNode, type XrayPath, apply, buildChangeContext, buildImpactXray, buildIndex, buildIndexWithCache, buildModuleGraph, buildSymbolTable, buildTaskContext, callerCounts, changeContextInputFromArgs, defaultCachePath, extractAll, extractSymbols, findCycles, findOrphanModules, findRepoRoot, indexIntegrityWarnings, inject, languageForFile, loadIndex, name, parseFileToSymbols, parseUnifiedDiff, rankRepoMap, readGitFileAtRef, readWorkingTreeDiff, renderChangeContext, renderContextPack, renderHit, renderRepoMap, renderTaskContext, routeTask, saveIndex, scanRepo, scoreFile, searchSymbols, symbolCount, symbolRefs, tools };