@jokeran/frontend-code-skimmer
Frontend-Code-Skimmer MCP
不读全文,只看骨架;不搜字符,搜语义关联。
AI 代码助手的智能代码索引引擎,面向 Vue 2 / Vue 3 / React / 纯 TS/JS 工具模块 的结构化检索与影响分析场景。
当前版本的能力重点:
skimmer_query作为唯一推荐入口:一句自然语言后端自动分派多路并行查询,一次返回符号/片段/调用链/行为/影响/数据流与组件语义流- 来源类问题会区分直接赋值/缓存读取、后端字段初始化、下游属性修改,避免把所有关联接口都解释成“原始来源”
- 同一方法甚至同一行出现多次同名请求调用时,会结合赋值片段和 endpoint 精确绑定当前调用点
- 支持 Vue 2、Vue 3、React 组件/模块索引
precision_mode="precise"支持 JS / JSX / TS / TSX 的跨文件 import/export 精确绑定- 对 纯 TS/JS 工具类模块 提供基础符号提取(class / method / function / constant)
skimmer_index_health可显示真实失败文件与错误信息,便于排障skimmer_search_snippets已支持 query intent 分类 + snippet-first 排序 + 业务文件优先
解决什么问题?
- 一次问全貌,少绕圈子:
skimmer_query用一句自然语言聚合多维度,命中即自足返回(top-1 内联源码、附一层调用链),避免"查符号→看代码→看调用方"逐跳追加调用 - 7000 行大文件:
skimmer_get_component_outline将其压缩为 60 行骨架,节省 95% Token - 自然语言第一跳太吵:
skimmer_search_snippets直接返回高相关代码片段,避免先猜函数名再二跳读文件 - API 查询先落到 util 包装层:
skimmer_search_snippets会优先抬升views/pages/features等业务实现,压低config/utils/helpers这类通用封装 - 函数名拼写错误:搜
changeCash能找到changeCashValue,自动提示 "cash 可能是 cache 的拼写错误";低分弱匹配(默认 <78%)自动折叠,不刷屏 - 不知道函数名:
skimmer_find_by_behavior按行为搜索,搜storage直接列出所有操作 localStorage 的函数 - 同名函数串台:
skimmer_find_symbol/skimmer_find_by_behavior/skimmer_get_call_graph支持file_path过滤 - 修改前评估影响:
skimmer_get_blast_radius告诉你改一个函数会影响哪些地方 - 变量数据流追踪:
skimmer_trace_data_lifecycle一次聚合声明、属性修改、参数传递、读取引用、Storage 落点 5 个维度;对const x = this.getXxx()这类赋值自动解析来源函数的行为标签(如缓存回显 → localStorage.getItem) - 原始来源不混淆:查询“某变量从哪个接口/缓存获取原始值”时,优先给出直接赋值或缓存读取,再补充后端字段初始化接口;对象别名传播后的下游请求不直接当作原始来源
- 父子组件状态流转:查询 props、事件、
v-model、Context 或 Store 通信时,可查看父组件绑定、静态 import 的子组件文件以及子端 prop/emit 定义,不必只靠调用图猜值如何传递 - 常见局部别名不串链:
params、storP等对象别名按方法作用域隔离,减少跨方法同名变量污染 - Vue 证据行号可直接定位:行为证据统一使用整个
.vueSFC 的真实文件行号,可直接交给 Read 或代码切片工具 - 模板事件不断链:
@click/@initReceiveAdr等 Vue 模板事件、ReactonXxxJSX 事件都作为调用边入库,skimmer_get_call_graph能查到"模板事件 → 方法"这一跳(🖼️ / ⚛️ 标记) - 索引过期行号偏移:
skimmer_get_component_outline和skimmer_get_code_slice会自动检测索引是否过期并给出警告 - 纯 TS/JS 工具类模块也能审:支持提取 class、method、top-level function、const,适合 parser / indexer / cache / CLI / MCP 工具模块
- 跨文件 import 关系误判少:precise 模式会识别本地 shadowing,import 名在局部作用域被参数/变量遮蔽时不会误标为精确边
- 索引坏了怎么查:
skimmer_index_health可直接看到失败文件数量、最近失败文件和错误摘要
12 个 MCP 工具
| 工具 | 用途 |
|---|---|
skimmer_query |
🚀 唯一推荐入口:自然语言智能查询;来源类问题区分直接来源、后端初始化与下游修改 |
skimmer_index_project |
初始化/更新代码索引(支持 force: true 全量重建) |
skimmer_get_component_outline |
获取文件骨架(极致 Token 节省,自动检测索引过期) |
skimmer_find_symbol |
智能符号搜索(精确 → FTS5 → Levenshtein 三层,top-1 内联源码) |
skimmer_search_snippets |
代码片段搜索(snippet-first,适合自然语言第一跳) |
skimmer_get_code_slice |
精准代码切片(只取一个函数,自动检测行号偏移) |
skimmer_find_by_behavior |
按行为标签搜索(绕过命名问题) |
skimmer_trace_data_lifecycle |
变量完整生命周期追踪(聚合 5 维度、作用域消歧、精确绑定请求调用点) |
skimmer_get_call_graph |
函数调用关系图谱(支持 callers / callees / both) |
skimmer_get_blast_radius |
修改影响范围评估 |
skimmer_index_health |
索引健康检查(索引文件/符号/关系/行为、失败文件、watcher、DB 大小) |
skimmer_get_project_overview |
项目整体概览(文件数、符号数、框架分布) |
最近增强 / 稳定性说明
- 跨组件语义值流(v0.8.2,SQLite schema v23):
skimmer_query新增semantic_flow查询意图;自然语言提到 props、事件、父子组件、Context 或 Store 时,会直接查询语义边- Vue2 / Vue3 支持静态模板 prop、callback、事件绑定;Vue2
v-model对应value/input,Vue3 对应modelValue/update:modelValue - Vue3 支持
defineProps、defineEmits、provide/inject;React Hooks 支持 JSX prop/callback、createContext/useContext、state setter、selector/dispatch/store 读写 - 静态 import 可跨文件定位子组件;最多跟随 8 层可证明的 default-export barrel,并展示子组件定义文件和行号
- 证据边界(2026-09-28 批次 B,待评审):语义边
evidence记录表达式事实(exact/heuristic等),已验证的静态组件文件记录在target_file;MCP 单独展示文件绑定、子端 prop/事件定义,callback/事件参数映射未证明时明确停止。Vue 事件与 JSX 的条件、||、??、调用和 inline callback 保留完整原式及未证明的分支,不虚构单一路径。 - 本地 Vue2 样本实测:
apply-claim126 文件 / 790 条语义边 / 124 条静态目标绑定;clouds-crm-front982 文件 / 25,240 条语义边 / 1,053 条静态目标绑定 - 升级注意:0.8.3 版本代码已增至 schema v27;旧库升级后 Vue 2/3、React、JS/TS 索引首次普通刷新会重新解析一次(补齐渲染位置及表达式证据),再次无变化不重复重建。v20–v22 历史升级会重解析已有文件一次。旧 v23 路径曾实测 126 文件约 1.12 秒、982 文件约 15.94 秒;这些数字不是 v27 性能记录
- 后续计划、测试理由、验收指标和未覆盖边界见 NEXT_UPGRADE_ROADMAP.md
- 组件使用关系入索引 —— React JSX / Vue 模板(v0.8.0):
<Button />、<Form.Item />(React)与<pagination />、<el-button />(Vue 模板)现在都是component_render关系,skimmer_get_blast_radius/skimmer_get_call_graph在组件类符号上不再大面积空结果(展示层标 🧩 组件渲染)- 归因规则:
<Form.Item />归到根对象Form(它才是被 import 进来的名字);组件内定义的function Inner(){}/const renderItem = () => {}各自的 JSX 归它们自己,匿名回调(items.map(i => <Row />))归外层组件 - Vue 模板扫描前先剥离 HTML 注释、属性值与插值 → 注释掉的组件、
:tip="'<el-button>'"这类字符串不会误入关系 - 实测:ant-design 关系 8781 → 13671(精确边占比 18.7% → 40%,call_graph 空结果 37.5% → 30%);shadcn/ui 关系 10725 → 71850(精确边 12.5% → 53.6%);vue2-admin 的
<Pagination />可查到精确调用方
- 行为语义扩展到现代前端生态(v0.8.0):
- 行为类别 8 → 18(新增
state/effect/memo/ref/context/store/data/form/realtime/worker),覆盖useState/useEffect/useMemo/useRef/useContext/useSelector/useQuery/useMutation/useForm/useI18n等;React.useState(...)命名空间式调用同样识别 find_by_behavior的keyword现在同时匹配参数值 / API 名 / 符号名,可直接搜业务词- 实测行为覆盖率:react-hook-form 3.8% → 48.3%|ant-design 5.0% → 31.9%|shadcn/ui 3.1% → 20.7%
- 行为类别 8 → 18(新增
- 精确度:barrel 再导出链 + 符号表校验(v0.8.0):
export { X } from './y'/export * from './y'/export { default as X } from './y'会顺着链落到真正的定义文件(最多 8 层,带去环),不再指向空壳index.ts- 精确提示只写向真实存在的符号:追不到目标就保留原值(宁可不命中,不伪造)
- 实测 ant-design 提示命中率 74.5% → 87.5%(
nameMismatch69 → 0);shadcn/ui 97.5%
- Vue 2 覆盖补齐(v0.8.0):
- 普通
.js / .ts里的 mixin / 自定义指令 / 插件(export default { bind(){} }、install(Vue){})不再 0 符号,新增directive类别 - SFC 的
export default { name: 'Pagination' }映射为真实组件符号名(否则精确提示停在::default);<script>顶层函数/常量入索引 - Babel AST 的
StringLiteral全面支持:组件名、数组式props: ['value']、'kebab-case': fn字符串键选项
- 普通
- 影响面与索引可观测性(v0.8.0):
blast_radius区分「📤 导出符号(仓库内无调用者属正常)」与「真无人用」,并把影响面拆成「M 处调用 + K 处组件渲染」- 新增
max_affected_files(默认 200)控制 precise 反向依赖扩散上限,截断时明确提示(此前逐文件写 stderr,ant-design 上 674 条刷屏) - 索引阶段计时区分墙钟(
filesPhaseMs)与并发累计(readFilesMs/parseMs/saveToDbMs),不再出现「累计 > 总耗时」的困惑;behaviorSearch上限 200 可配并提示截断
- 查询性能(v0.8.0):自然语言长句不再触发 Levenshtein 模糊匹配(实测占
search()总耗时 92% 且命中恒为 0)→ TanStack Query 上skimmer_query23.2ms → 3.6ms - 升级注意(v0.8.0):新增 migration v18 持久化
symbols.is_exported,升级后会把文件指纹置空 → 老库下次索引会全量重解析一次(ant-design 约 32s,属预期);大型 monorepo 建议调大max_affected_files - React Hooks 数据流与写入链路升级(v0.7.5):
- useState setter 入符号索引:
const [payData, payDataSet] = useState({})现在会额外产出payDataSet [state_setter/react]符号(symbols.state_name记录它写入的 state,migration v17)。此前 setter 完全不进符号表,skimmer_find_symbol("payDataSet")只能靠 FTS5 前缀匹配到payData - state_write 写入口:新增
state_write关系(handler/effect → state),skimmer_trace_data_lifecycle的「② 属性修改」现在会列出payDataSet(...)调用点;skimmer_get_call_graph("payDataSet")可反查调用者 - Promise 回调归因:
extractCallbackFunctionCalls/extractCallbackBehaviors改为递归收集任意位置的匿名回调(IIFE、new Promise、回调内再套 Promise),修复.then((res) => setX(res.data))类写入口漏检 - data_flow 形态补齐:新增成员调用(
await api.getData())、对象/数组解构、可选链与??兜底、Promise 回调写入;过滤useState/map/filter等噪声。真实项目数据流覆盖率 53.8% → 79.7% - 请求封装识别统一:
network-wrappers.ts由 React/Vue2/Vue3/工具类解析器共用;post(url)这类变量实参保留,仅排除「字面量且不像路径」的get('key') - 误报收敛:
<Form onFinish={handleSubmit} />这类「引用 handler」不再把组件染成wrapped_network;声明初始化归入「🌱 初始化来源」而非「❓ 未知来源」 - JSX 内联 handler:
onClick={() => payDataSet(x)}的调用与写入口也会归因到组件
- useState setter 入符号索引:
- tsconfig paths 别名真解析 + 索引健康度升级(v0.7.04):
- precise 模式现在会读取「最近祖先」
tsconfig.json/jsconfig.json的compilerOptions.baseUrl+paths,支持精确映射、通配符(如@components/*)、extends继承链(含省略.json的写法和<包名>/tsconfig.json) - 不再“谎报精确”:解析不到本地文件的 import(未映射别名、node_modules 裸模块)一律保留 heuristic,不再生成指向不存在文件的 precise 提示
- 遇到
package.json/.git项目边界即停止向上查找,嵌套子项目不会误用父项目 paths - 配置解析带 10s TTL 缓存,改了 tsconfig 重新索引即可生效;别名解析走缓存,裸模块解析实测约 2.4µs/次
skimmer_index_health新增分维度解析覆盖率(符号/调用关系/行为/数据流 × 有产出文件占比)、precise / heuristic 边数、precise 待处理数- ⚠️ 行为变化:外部库/未解析别名不再计入 precise,precise 边数会下降;首次重新索引因 import 签名变化可能触发一次较多文件重算
- precise 模式现在会读取「最近祖先」
- 文件监听自愈 + 关闭安全(v0.7.0):
- watcher 遇到
error(EMFILE / 权限抖动 / 临时文件竞态等瞬时故障)不再永久钉死在errored,而是线性退避自动重建(WATCH_RESTART_DELAY_MS=2000ms × 尝试次数,上限 5 次),重建成功即恢复running - 每个 watcher 实例带世代号(epoch):出错实例一旦失效,其迟到的
ready/error事件一律被丢弃,不会错误清零重试计数,首次重建稳定记录为「第 1 次尝试」 - 重建期间(旧 watcher 已停、新 watcher 尚未
ready,ignoreInitial生效)发生的文件增删改会被补扫(resync) 兜底:重建实例ready后自动跑一次签名驱动的增量索引,补齐窗口期缺口,不会漏索引 - 关闭安全:
closeProject()/closeAll()/ 进程SIGINT|SIGTERM退出前,都会先await watcher.stop()(内部等待进行中的补扫收尾)再关闭数据库,杜绝补扫落库过程中触发The database connection is not open - 上述行为均有回归测试覆盖(含「首次 ready 前就 error」「退避期间旧实例迟到 ready」「关闭时补扫仍在进行」三个竞态场景)
- watcher 遇到
- 调用点与证据链准确性升级(v0.6.97):
- 同一方法内多次调用同名请求函数时,结合当前赋值片段、endpoint detail 和调用行绑定 behavior,不再简单取第一条同名调用
- 同一行存在多个不同 endpoint 也可消歧,例如
savedData = request('/right-api')不会误绑定同一行的/wrong-api - 对象别名持久化方法作用域,避免
params、storP等常见局部变量跨方法串链 - Vue 2 / Vue 3 behavior 行号统一换算为整个 SFC 的真实文件行号,证据可直接用于代码定位
- 三元表达式变量提取 + 信息屏蔽彻底解决(v0.6.9):
- 新增
extractTernaryVariables()支持从(type == 1 ? cashData?.receiveAdr : cashData?.fetchAdr)提取cashData - 递归溯源引擎集成三元表达式候选项(
ternary_ref),追踪优先级:函数 → 三元变量 → 普通变量 → fallback - 工具描述强化"不可过度信任"警告:明确"返回 0 ≠ 不存在","必须启动人工推理"
- "未找到链路"输出增强为 10+ 行强警告 + 人工验证步骤,防止模型因工具返回空就放弃推理
- 三层防御解决信息屏蔽问题:工具层覆盖更多表达式模式 + 描述层强制怀疑 + 输出层强警告
- 新增
- answer-first 返回(v0.6):
skimmer_query定为唯一推荐入口,命中即自足返回(top-1 内联源码 + 一层调用链摘要),命中成功不再推销其它工具;空结果自动放宽重查一次,仍空则明确告知"确认无结果 + 已尝试的查询方式",杜绝空转 - 递归赋值溯源(v0.6.3-v0.6.8):
skimmer_trace_data_lifecycle对const x = this.getXxx()这类"赋值右侧是函数调用"自动递归追踪到localStorage.getItem,打通storageParams ← savedData ← getPageCashF() ← localStorage完整链路;支持 || fallback 追踪 - camelCase / v-model 模板事件入库(v0.6):Vue 模板事件提取覆盖
@initReceiveAdr(camelCase 自定义事件)、@update:modelValue(v-model 语法糖)、带修饰符事件,跨"模板事件 → 方法"的调用链不再断链 - response_format + 参数容错(v0.6):检索类工具支持
response_format: concise|detailed(默认 concise 省 token);trace_data_lifecycle接受 variable 的多种别名参数;find_symbol低分弱匹配按min_score(默认 78)折叠 - 引用度加权排序(v0.6):
find_symbol/skimmer_query对被引用多的核心 API 加权,并对与已验证符号同文件/同目录的候选加分 - JSX precise 生效:precise 模式不再局限于
ts/tsx,现在会对js/jsx/ts/tsx模块做跨文件 import/export 绑定增强 - re-export / barrel 链扩散更完整:
selective_precise=true会把re-export也纳入依赖签名和反向依赖扩散,barrel 变更不再只重算当前文件 - local shadowing 保护:若 import 名在函数局部被参数或变量重新声明,会保留 heuristic,避免把本地变量误判成跨文件精确调用
- 工具类模块覆盖增强:新增 Tooling TS/JS Parser,能抽取 class、class method、top-level function、constant 等基础符号
- index health 更真实:索引失败文件会持久化,
skimmer_index_health可查看最近失败文件和错误,而不是只看总量 - snippet 搜索引入 query intent:区分
symbol_like / behavior_like / api_like / natural_language,工具输出会直接显示意图,便于调权和排障 - 业务文件优先排序:对
views/pages/features/modules等业务文件加分,对config/utils/helpers/lib/shared等通用封装降权;在真实 Vue2 项目中,localStorage setItem已可优先命中业务页实现而不是mUtils.js - 评测集已固化:仓库内有固定 snippet 回归测试,外部真实项目可通过
eval/snippet-suites/*.json+npm run eval:snippet一键复跑;预检独立核对源码与索引,区分样本过期STALE与索引异常ERROR(开发版,2026-09-28)
v0.8.3 版本进展(2026-09-29)
- Vue 2 来源名修复保留 schema v24 升级路径;上一批 A 新增 schema v25,使 Vue 2 / Vue 3 / React 文件指纹一次性失效。下次普通索引会重解析并替换旧语义边,再次不变索引不重复重建;无需手动 force。
- 组件绑定核对实际 default / named / alias 导出及 JSX 词法引用,支持可证明的静态 namespace 成员和 re-export;Vue 同时核对 setup 导入或 Options 注册。缺失、动态、歧义导出与局部遮蔽不再猜外部目标。
- React setter 按声明身份对应 state,识别运行时 React
useState导入/别名并排除 type-only 与同名普通函数;Context、dispatch、store 参数遮蔽也不再借用外层绑定。 - 批次 B(2026-09-28,已评审):schema v26 增加
semantic_edges.source_offset,文件内 UTF-16 属性/事件 offset 区分同行静态实例;source_line对应属性行。v-model同位置的 prop 与事件分开保留。目标查找按属性位置隔离同一行不同导出成员和局部遮蔽。语义查询焦点过滤先于数据库 80 条预算,展示最多 12 条并提示截断;确定的子文件定义使用精确路径。 - 批次 C(2026-09-28,已评审):三个真实仓库的固定 SHA、源码指纹与人工期望形成 13 个 MCP 样本,修复前后完整原始报告只存本地
eval/results/(Git 忽略)。其中 10 个局部静态场景 PASS、3 个完整路径 BOUNDARY;不得把 BOUNDARY 当成端到端已完成。Vue 2 真实仓库中合法的换行多语句@事件原被 Vue 3 编译器误计为 7 个解析失败,现在仅在 Babel 证实为多条表达式语句时放行,非法事件仍失败;schema v27 对旧 Vue 2 索引执行一次性指纹失效,普通增量索引清理旧错误。 - 批次 D(2026-09-28,已验收):Vue 3
script setup的静态组件绑定可在 MCPskimmer_query中展示逐项文件、行号、offset 和证据:父 prop、子 prop 声明/读取、字面量 emit、父事件绑定、handler 形参与直接 ref 写入。子端支持直接props.value或模板参数emitChange(props.value)→emit('change', next)。默认/静态命名无修饰符v-model还支持ref(props.visible)→watch(ref, val)→emit('update:visible', val)→ 父 ref 的静态回写;输出明确标出子 ref 初始化不保证后续事件值等于原 prop。动态、分支、同名歧义或索引过期时给出边界/停止理由;父子文件哈希与当前源码不一致时只显示历史表达式与陈旧提示,不输出旧[precise]目标和子定义。C 的三个复杂真实路径仍为 BOUNDARY;新增apply-claim-new真实命名v-model固定样本在相同问题与 SHA 下从 1 PASS/1 BOUNDARY 提升为 2 PASS/0 BOUNDARY。 - 批次 E 部分(2026-09-29,待整体评审):React JS/TS 的静态 JSX prop → 子端直接读取并触发 callback → 父端直接 setter / 单参数 handler → useState 写入,Vue 2 Options API 的受限 value/input v-model → 子端 data 初始化 → watch 事件 → 父 data 状态回流,均可在 MCP
skimmer_query按文件/行号/offset 查询。必须先有静态目标文件与新鲜索引;动态 spread、一般条件表达式、覆写、间接 callback/复杂 model 停止推断;条件挂载下的受限关闭控制路径单独标注;Vue 2 仅在组件挂载时发生更新,子 data 初始值不能等同后来 watch 事件值。同一固定apply-claimVue 2 问题由 BOUNDARY → PASS;严格逐跳样本见 vue2-jr-select-flow.json。React JS/TS 已有定向/MCP 参数值流正例;固定oneclaim-fe原 inline callback 仍 BOUNDARY。新增 oneclaim-fe 关闭控制样本 在固定 SHA 下为 3 PASS/0 FAIL,证明visible受控属性、子端事件绑定、无参数onClose()与父端setShowEditDialog(false)的静态控制路径;第三方组件是否实际触发事件未由静态分析证明,initData参数值流仍明确停止。E 批原定的真实“prop 值 → callback 实参 → 父写入”正例仍待补齐。 - v0.8.4(2026-10-02,缺陷修复):按全仓缺陷审计(见 bug-hunt/BUG_REPORT.md)修复 39 条已确认缺陷(5 high / 16 medium / 18 low):
.vueOptions API 被误判为 Vue3 特征导致整文件 0 符号、chokidar v4 下文件监听完全失效、allow_fallback_scan降级检索不可用(提前 return + ESCAPE 语法错误)、component-outline丢失 class/directive/export 类别、Vue 文件 import 遮蔽保护 fail-open,以及索引陈旧检测、迁移 schema 漂移、中文检索分词、路径规范化与工具契约等。行为变更:省略project_path且无历史项目时改为明确报错(不再静默使用服务端 cwd 建库);SKIMMER_DB现在始终生效。npx tsc --noEmit通过、npm test270/270 通过。 - 发布产物检查补齐
@vue/compiler-dom直接依赖以修复 ESM 启动问题,并更新 Hono 生产约束;当前版本为0.8.4,推送v0.8.4tag 后由 GitHub Actions 发布到 npm。功能与适用边界见 升级路线图。
真实项目 MCP 基线(批次 C)
固定样本在 eval/real-projects/;先编译测试入口,再运行对应真实仓库(需具备样本固定的来源、SHA 和干净工作区):
rtk npm run eval:real-mcp -- --suite eval/real-projects/vue3-apply-claim-new.json --project /path/to/apply-claim-new --out eval/results/vue3-now.json
若已有同一 suite 与源码快照生成的基线,再加 --baseline eval/results/vue3-before.json。评测使用 MCP 工具与临时 SQLite 数据库,报告记录完整工具响应、索引错误、环境与版本;FAIL、STALE、ERROR 或不可比较均非零退出。BOUNDARY 表示当前只证明了局部边、没有完成整条回流;原始报告可能包含业务源码,默认不入库。其他场景使用同目录的 React/Vue 2 suite,结果与适用边界见 升级路线图。
安装
方式一:npx 直接使用(推荐)
无需克隆仓库,直接在 MCP 配置中使用 npm 的 latest 版本:
{
"mcpServers": {
"frontend-code-skimmer": {
"command": "npx",
"args": ["-y", "@jokeran/frontend-code-skimmer"]
}
}
}
方式二:本地克隆构建
git clone <this-repo>
cd frontend-code-skimmer
# 使用 v0.8.4 版本
git checkout v0.8.4
npm install
npm run build
方式三:运行 snippet 评测集(开发调权用)
# 仓库内固定评测集
npm test
# apply-claim 真实项目相关性回归(项目路径需对应此 suite)
npm run eval:snippet -- --project /path/to/apply-claim --suite ./eval/snippet-suites/apply-claim.json
说明:
npm test会跑固定 fixture 评测集,适合日常开发时快速防回归npm run eval:snippet用于真实项目相关性回归,适合调权、改 query 规则、评估业务文件优先是否生效- 预检检查
expectedTopSymbols、expectedTopFilePrefixes和topResultsMustContain;top1 的符号与路径列表均是候选集合,只要求同一条索引记录同时满足两个条件,不要求所有备选路径存在 - 仅在独立源码清单中找不到文件或目标符号文本时标记
STALE;源码仍有候选而索引没有时标记ERROR。文本出现在注释或字符串里也保守报ERROR,不把解析回归静默当成过期 - 退出码:
0= 所有样本通过;1= 断言失败、索引/配置/读取异常;2= 无错误但含过期样本,评测不完整。STALE不增加 fail 数,但不代表评测通过;错误优先于过期 - 使用临时 SQLite 数据库并在结束后关闭、清理,不覆盖项目已有 MCP 索引;suite 不能为空,
topN为 1–20 的整数 - 这是 SearchEngine/SQLite 层评测,不等同于 MCP 端到端验收;行为有效性、真实仓库 commit 固定与前后报告比较仍待完成
eval/snippet-suites/*.json只属于研发保障设施,不参与运行时主链路
配置(Cursor / Claude Desktop)
npx 安装(推荐)
{
"mcpServers": {
"frontend-code-skimmer": {
"command": "npx",
"args": ["-y", "@jokeran/frontend-code-skimmer"],
"autoApprove": [
"skimmer_query", "skimmer_index_project", "skimmer_get_component_outline",
"skimmer_find_symbol", "skimmer_search_snippets", "skimmer_get_code_slice",
"skimmer_find_by_behavior", "skimmer_trace_data_lifecycle",
"skimmer_get_call_graph", "skimmer_get_blast_radius",
"skimmer_index_health", "skimmer_get_project_overview"
]
}
}
}
本地构建安装
{
"mcpServers": {
"frontend-code-skimmer": {
"command": "node",
"args": ["/path/to/frontend-code-skimmer/dist/index.js"],
"autoApprove": [
"skimmer_query", "skimmer_index_project", "skimmer_get_component_outline",
"skimmer_find_symbol", "skimmer_search_snippets", "skimmer_get_code_slice",
"skimmer_find_by_behavior", "skimmer_trace_data_lifecycle",
"skimmer_get_call_graph", "skimmer_get_blast_radius",
"skimmer_index_health", "skimmer_get_project_overview"
]
}
}
}
不需要任何 env 配置。项目路径在每次工具调用时动态指定。
多项目工作流
优先从编辑器工作区、已打开文件和当前上下文自动推断项目根目录绝对路径,填入 project_path(无需向用户追问)。
项目 A: skimmer_index_project({ project_path: "/work/project-a" })
项目 B: skimmer_index_project({ project_path: "/work/project-b" })
→ 两个项目的索引同时缓存(最多 8 个项目,LRU 淘汰)
→ 查项目 A:
skimmer_get_component_outline({ project_path: "/work/project-a", file_path: "src/views/home.vue" })
→ 查项目 B:
skimmer_find_symbol({ project_path: "/work/project-b", query: "handleSubmit" })
→ 省略 project_path 时,自动使用上次操作的项目:
skimmer_find_symbol({ query: "handleSubmit" })
→ 文件修改后强制全量重建索引:
skimmer_index_project({ project_path: "/work/project-a", force: true })
数据库存放位置
| 情况 | 数据库位置 |
|---|---|
| 项目目录可写 | <项目根>/.agent/skimmer_find_symbol/.skimmer-index.db |
| 项目只读 | ~/.frontend-code-skimmer/databases/<hash>_<path尾部>.db |
| 自定义路径 | SKIMMER_DB 环境变量指定的路径(仅单项目场景有效) |
环境变量(全部可选)
| 变量 | 说明 | 默认值 |
|---|---|---|
SKIMMER_PROJECT |
全局默认项目路径 | 无 |
SKIMMER_AUTO_INDEX |
启动时自动索引默认项目(需配合上一项使用) | false |
SKIMMER_DB |
自定义数据库路径(仅单项目场景有效) | 自动 |
SKIMMER_MAX_OPEN_PROJECTS |
最大同时打开的项目数(LRU 淘汰) | 8 |
SKIMMER_DB_IDLE_MINUTES |
项目空闲多久后自动关闭数据库连接(分钟) | 30 |
SKIMMER_DB_TTL_DAYS |
全局缓存数据库的 TTL(天),过期自动清理 | 14 |
使用示例
1. 首次使用
调用 skimmer_index_project → 等待索引完成(50 个文件约 2 秒)
1.5 ⭐ 一句话智能查询(唯一推荐入口)
调用 skimmer_query({ question: "提交按钮的数据流是怎样的" })
调用 skimmer_query({ question: "persistDraft 改了会影响哪些地方" })
调用 skimmer_query({ question: "所有写 localStorage 的地方" })
调用 skimmer_query({ question: "src/views/apply/index.vue 中 storageParams 是从哪个接口获取的原始值" })
→ 必填参数名是 question(不是 query);为容错也接受别名 query / q,内部会归一到 question
→ 来源类问题会收敛到 lifecycle/source 主链:先识别直接来源,再补充后端字段初始化来源
→ 示例结论:直接来源是 `localStorage.getItem("apply-claim/apply-cash")`;缓存缺失字段的后端初始化来源是 `/gw/generic/bx/newh5/m/queryApplyDynamicInfoFromServiceType`
→ “直接来源”和“字段初始化来源”可能不同;下游属性修改关联的 endpoint 不等于原始来源
→ 后端按意图自动分派多路并行查询,一次返回全貌(命中即内联 top-1 源码 + 一层调用链)
→ 命中成功不再推销其它工具;结果为空时自动放宽重查一次,仍空则明确告知"确认无结果 + 已尝试的查询方式"
→ 下面 2~11 的细粒度工具是本入口的"深入维度",仅在需要单维度精查时使用
2. 快速了解组件
调用 skimmer_get_component_outline({ file_path: "src/views/apply/index.vue" })
→ 返回组件所有方法、状态、行为标签的骨架视图(7000 行 → 60 行)
→ 若文件在索引后被修改,自动输出 ⚠️ [索引已过期] 警告并提示重建
3. 查找拼写错误的函数
调用 skimmer_find_symbol({ query: "changeCash" })
→ 找到 changeCashValue,提示 "cash 可能是 cache 的拼写错误"
→ 行为标签显示: [storage:localStorage.setItem]
3.5 ⭐ 自然语言第一跳代码片段搜索
调用 skimmer_search_snippets({ query: "save to cache" })
→ 直接返回 changeCacheValue / persistDraft 等高相关代码片段
→ 优先看 snippet,不必先猜函数名再调用 get_code_slice
→ 输出会显示查询意图,如 `behavior_like`
调用 skimmer_search_snippets({ query: "localStorage setItem" })
→ 直接返回 localStorage.setItem 所在实现片段
→ 显式 API 查询会识别为 `api_like`,优先按行为实现排序
→ 若同时存在业务页实现和 util 封装,默认优先业务文件
当前排序信号(面向 Agent 第一跳):
- query intent:
symbol_like / behavior_like / api_like / natural_language - definition boost:可执行定义(function / method / hook / lifecycle)优先于常量/元数据
- file coherence:同一文件内多处相关命中会整体抬升
- file role:
views/pages/features/modules业务文件优先,config/utils/helpers/lib/shared通用封装降权 - noise penalty:测试、mock、demo、声明文件降权
4. 查找操作本地存储的函数
调用 skimmer_find_by_behavior({ category: "storage", operation: "setItem", file_path: "src/views/apply/index.vue" })
→ 列出所有写入 localStorage 的函数,带文件位置
5. 变量完整数据流追踪(query 的深入维度)
调用 skimmer_trace_data_lifecycle({
variable: "storageParams",
file_path: "src/views/apply/index.vue",
storage_api: "localStorage",
max_depth: 2
})
→ 一次返回 5 个维度:
① 声明 & 整体赋值(含来源分层:初始化/缓存回显/用户交互;赋值右侧是函数调用时自动解析来源)
② 属性修改(object.prop = xxx,含别名展开)
③ 作为参数被传入的调用
④ template 绑定 / watch / computed / return 中的读取引用
⑤ Storage 落点追踪(自动顺着调用链打通到 localStorage 写入)
→ 同名请求调用会结合赋值片段、endpoint 和调用行消歧;对象别名按方法作用域隔离
→ Vue 文件中的行为证据使用整个 SFC 的真实行号,可直接定位源代码
→ variable 参数支持 variable_name / symbol_name / symbol / name 别名容错
→ 默认 concise 只列命中行;response_format: "detailed" 附前后各 2 行上下文
6. 单维度追踪(trace_data_lifecycle 已覆盖)
# 只想看某变量的赋值/属性修改,直接用 trace_data_lifecycle 并按需读对应维度即可
skimmer_trace_data_lifecycle({ variable: "changeResult", file_path: "src/views/apply/index.vue" })
说明:
- 变量数据流一律用
skimmer_trace_data_lifecycle,它一次聚合声明、属性修改、参数传递、读取引用、Storage 落点五个维度,并对const x = this.getXxx()这类"赋值右侧是函数调用"自动解析来源函数的行为标签。 - 完整生命周期中的“属性修改”可能包含对象别名传播后的下游请求;判断原始来源时按“直接赋值/缓存读取 > 后端字段初始化 > 下游属性修改”的顺序解读。
- 如果问题本身是“从哪个接口/缓存获取原始值”,优先调用
skimmer_query并在问题中带上相对文件路径;需要展开全部证据时再调用本工具。 - 早期的
skimmer_trace_assignments/skimmer_trace_property_changes两个降级工具已合并进skimmer_trace_data_lifecycle,不再单独暴露。
7. 函数调用图谱 & 影响评估
skimmer_get_call_graph({ symbol_name: "saveToCache", direction: "both" })
skimmer_get_blast_radius({ symbol_name: "saveToCache" })
8. 精度模式(precise)
precision_mode="precise" 用于增强跨文件 import/export 绑定。
前提与边界:
- 需要项目根目录存在
tsconfig.json或jsconfig.json,否则会自动降级到heuristic - 会读取该配置(含最近祖先配置)的
compilerOptions.baseUrl+paths解析别名,支持通配符与extends继承;遇到package.json/.git项目边界即停止向上查找 - 解析不到本地文件的 import(未映射别名、node_modules 裸模块)保留 heuristic,不会伪造精确绑定
- 当前精确绑定覆盖 JS / JSX / TS / TSX 文件
- 适合查
import { foo } from './bar'这类跨文件调用,不等于完整类型系统求值 - 若 import 名在局部作用域被参数/变量遮蔽,会保留 heuristic,避免误判
示例:
skimmer_index_project({
project_path: "/work/project-a",
precision_mode: "precise"
})
9. 选择性 precise 重算(大项目推荐)
selective_precise=true 会在索引后只重算变更文件 + 受影响文件,降低 precise 全量成本。
当前规则:
body_only:只重算当前文件 preciseimport_changed:只重算当前文件export_changed/full_changed:重算当前文件 + 所有直接/间接依赖它的文件re-export/ barrel 链会纳入 import 签名与反向依赖扩散
示例:
skimmer_index_project({
project_path: "/work/project-a",
precision_mode: "precise",
selective_precise: true,
max_precise_files: 20
})
10. 索引行号不准怎么办?
行号偏移的根本原因通常是索引未及时更新。排查步骤:
skimmer_get_component_outline返回⚠️ [索引已过期]→ 立即执行第 3 步skimmer_get_code_slice返回⚠️ [行号偏移]→ 说明代码切片位置不对- 强制重建:
skimmer_index_project({ project_path: "...", force: true })
当前增量索引使用 mtime + 文件大小 做快速跳过,能覆盖大多数变更场景;如果你的编辑器或同步工具存在极端时间戳行为,仍建议在异常时执行
force: true全量重建。
11. 索引坏了怎么排障?
skimmer_index_health({ project_path: "/work/project-a" })
可直接看到:
- 已索引文件数 / 符号数 / 关系数 / 行为数
- 最后索引时间
- 失败文件数量
- 最近失败文件和错误信息
- watcher 是否活跃
- 数据库大小与路径
当你发现“文件明明在,但工具查不到”时,先看这里,而不是只看总文件数。
框架支持
| 类型 | 解析方式 | 支持范围 | 说明 |
|---|---|---|---|
| Vue 2 | @vue/compiler-sfc + @babel/parser |
Options API | 仅解析 SFC 块和 AST,不执行模板代码;适合组件骨架、行为标签、调用关系 |
| Vue 3 | @vue/compiler-sfc + @babel/parser |
<script setup> + Composition API |
适合现代 Vue 单文件组件分析 |
| React | @babel/parser + JSX |
函数组件 + Hooks | 适合组件骨架、事件入口、行为标签、调用关系 |
| 纯 TS/JS 工具模块 | @babel/parser |
class / method / top-level function / constant | 基础结构化符号提取,适合 parser / indexer / cache / CLI / MCP / util,不等于完整框架语义分析 |
行为检测
自动识别以下 API 调用并打上标签:
storage:localStorage / sessionStoragenetwork:axios / fetchrouter:$router / useRouter / navigatevuex:$store / useStore / dispatch / commitdom:document / $refs / $nextTickevent:$emit / EventBustimer:setTimeout / setIntervali18n:$t / useI18n
Version History
| Version | Released | License |
|---|---|---|
| 0.8.4 | ||
| 0.8.3 | ||
| 0.8.2 | ||
| 0.8.1 | ||
| 0.8.0 | ||
| 0.7.5 | ||
| 0.7.4 | ||
| 0.7.3 | ||
| 0.7.2 | ||
| 0.7.1 | ||
| 0.7.0 | ||
| 0.6.99 | ||
| 0.6.98 | ||
| 0.6.97 | ||
| 0.6.93 | ||
| 0.6.91 | ||
| 0.6.1 | ||
| 0.5.1 | ||
| 0.4.9 | ||
| 0.4.8 | ||
| 0.4.7 | ||
| 0.4.6 | ||
| 0.4.5 | ||
| 0.4.4 | ||
| 0.4.3 | ||
| 0.4.2 | ||
| 0.4.1 | ||
| 0.4.0 | ||
| 0.2.7 | ||
| 0.2.6 |
Showing the latest 30 of 38. See every release on npm