关于 indexion-refactor
indexion-refactor 是用于分析和减少代码重复的技能,面向重构代码库的开发者。它覆盖文本、结构和概念层面的重复,并提供提取共享代码、清理包装函数及验证 SoT 的流程。
主要功能
- 01检测文本级重复代码
- 02发现跨目录共享候选
- 03识别简单委托包装函数
- 04分析概念层面的重复
- 05指导集中实现到 SoT
适用场景
- 01重构前检查重复实现
- 02从多个包提取共享代码
- 03清理重构后多余的包装函数
- 04检查概念逻辑是否分散
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ trkbt10/ indexion-skills --skill indexion-refactor安装后在 Claude Code 中输入/indexion-refactor确认已加载。
详细介绍
indexion 重构 — 代码库重构
使用 indexion 的分析命令检测并消除三个层面的重复——文本、结构和概念—— 然后验证 SoT 是否得到强制执行。
适用场景
- 添加新的抽象(类型、模块、API 层)后
- 引入新的文件格式或 I/O 边界后
- 同一原因导致需要修改 3 个以上文件时
- 添加“守卫”或“跳过”逻辑来规避结构性问题时
- 意外路径出现
opendir、ENOENT或类似文件系统错误时 - 在软件包之间提取共享代码时
- 重构后清理代码时(移除简单的包装函数)
- 定期检查代码库的 SoT 健康状况
三个层面的重复
| 层面 | 含义 | 工具 | 示例 |
|---|---|---|---|
| 文本 | 复制粘贴的代码块、相同的函数 | plan refactor | 在 5 个模块中复制了 is_whitespace |
| 结构 | 逻辑结构相同但名称不同 | plan solid、plan unwrap | 跨软件包提取候选项、简单的包装函数 |
| 概念 | 同一领域概念由不同实现独立实现 | explore + 手动分析 | 三个模块分别判断“这个文件是否为归档文件?” |
文本重复易于发现和修复。概念重复最难处理,也最危险——它不会产生任何复制粘贴匹配项,但意味着修改一个概念时,需要更新所有分散的实现。
工作流
阶段 1:清除文本重复(plan refactor)
从高置信度匹配项开始,逐步处理。
# Step 1: Find 90%+ duplicates (high confidence)
indexion plan refactor --threshold=0.9 \
--include='*.mbt' --exclude='*_wbtest.mbt' \
--exclude='*moon.pkg*' --exclude='*pkg.generated*' \
cmd/indexion/
indexion plan refactor --threshold=0.9 \
--include='*.mbt' --exclude='*_wbtest.mbt' \
--exclude='*moon.pkg*' --exclude='*pkg.generated*' \
src/
分三个部分阅读输出:
| 部分 | 检测内容 | 操作 |
|---|---|---|
| 相似文件 | 整体相似度较高的文件 | 检查是否可以进行结构整合 |
| 重复代码块 | 文件之间逐行相同的代码 | 提取到 @common 或共享模块 |
| 函数级重复 | 结构相似的函数(对函数体使用 TF-IDF) | 统一为单个 SoT 函数 |
同一文件内的重复项(相似度达到 90% 以上的函数)是最有价值的目标——最容易修复,收益也最明确。例如:get_global_data_dir 和
get_global_cache_dir 的结构有 95% 相同,因此提取到 resolve_os_dir。
# Step 2: Use grep to trace references before consolidating
indexion grep "TypeIdent:TfidfEmbeddingProvider" src/
indexion grep --semantic=name:is_whitespace src/
# Step 3: Fix, then re-run to confirm duplicates are gone
indexion plan refactor --threshold=0.9 --include='*.mbt' ...
# Step 4: Lower threshold and iterate
indexion plan refactor --threshold=0.85 --include='*.mbt' ...
plan refactor 选项:
| 选项 | 默认值 | 说明 |
|---|---|---|
--threshold=FLOAT | 0.7 | 最低相似度阈值 |
--strategy=NAME | hybrid | 相似度算法:hybrid、tfidf、bm25、jsd、ncd |
--fdr=FLOAT | 0 | FDR 校正(0=禁用) |
--style=STYLE | raw | 输出:raw、structured |
--format=FORMAT | md | 输出:md、json、text、github-issue |
--name=NAME | -- | 项目名称(用于 structured 样式) |
--include=PATTERN | -- | 包含模式(可重复指定) |
--exclude=PATTERN | -- | 排除模式(可重复指定) |
-o, --output=FILE | stdout | 输出文件路径 |
--specs-dir=DIR | kgfs | KGF 规范目录 |
清理后的保留项(停止信号):
- 平台桩代码(
native.mbt/stub.mbt)——有意进行的平台分支 - 类型方法相似性(不同类型上的
to_string)——类型不同,模式相同 - CLI 命令样板代码(
command()函数)——@argparseAPI 模式,不属于重复 - 语义相似但功能不同的函数(
is_disqualifying_keyword与is_skip_token)——用途不同
阶段 2:提取跨包共享代码(plan solid)
清理完各个目录后,找出应在多个包之间共享的代码。
# Find overlap between two packages
indexion plan solid --from=src/a,src/b
# Specify extraction target
indexion plan solid --from=src/a,src/b --to=src/common
# Use tree edit distance for precise function-level matching
indexion plan solid --from=src/a,src/b --strategy=apted
# Higher threshold for stricter matching
indexion plan solid --from=src/a,src/b --threshold=0.95
# Filter files
indexion plan solid --from=src/a,src/b --include='*.mbt' --exclude='*_test.mbt'
plan solid 与 plan refactor 不同:
plan refactor | plan solid | |
|---|---|---|
| 范围 | 目录内部的重复代码 | 跨目录的重叠代码 |
| 目标 | 在代码库内部整合 | 将共享代码提取到新包中 |
| 输入 | <path> | --from=dirA,dirB |
plan solid 选项:
| 选项 | 默认值 | 说明 |
|---|---|---|
--from=DIRS | (必需) | 源目录(逗号分隔或可重复指定) |
--to=DIR | -- | 提取目标目录 |
--rules=FILE | -- | 规则文件(.solidrc) |
--rule=RULE | -- | 内联规则(可重复指定) |
--threshold=FLOAT | 0.9 | 最低相似度阈值 |
--strategy=NAME | tfidf | 相似度算法:tfidf、apted、tsed |
--include=PATTERN | -- | 包含模式(可重复指定) |
--exclude=PATTERN | -- | 排除模式(可重复指定) |
--format=FORMAT | md | 输出格式:md、json、github-issue |
-o, --output=FILE | stdout | 输出文件路径 |
--specs-dir=DIR | kgfs | KGF 规范目录 |
工作流:
- 先对每个目录单独运行
plan refactor,清理内部重复代码 - 运行
plan solid --from=dirA,dirB,查找跨目录提取候选项 - 根据计划建议提取共享代码
- 使用
indexion grep "TypeIdent:SharedType"验证所有引用均已更新
阶段 3:移除不必要的包装器(plan unwrap)
整合完成后,清理那些只会增加间接调用、没有实际价值的简单委托函数。
# Step 1: Quick check
indexion grep --semantic=proxy src/
# Step 2: Detailed report
indexion plan unwrap --include='*.mbt' --exclude='*_wbtest.mbt' \
--exclude='*moon.pkg*' --exclude='*pkg.generated*' src/
# Step 3: Preview changes (safe — no files modified)
indexion plan unwrap --dry-run --include='*.mbt' --exclude='*_wbtest.mbt' \
--exclude='*moon.pkg*' --exclude='*pkg.generated*' src/
# Step 4: Apply fixes
indexion plan unwrap --fix --include='*.mbt' --exclude='*_wbtest.mbt' \
--exclude='*moon.pkg*' --exclude='*pkg.generated*' src/
# Step 5: Run tests
moon test --target native
检测内容: 函数体只有一次函数调用,且所有参数都以简单标识符的形式原样传递——不包含控制流或转换。
// Detected (default) — trivial delegation
fn matches_pattern(text : String, pat : String) -> Bool {
@glob.glob_match(text, pat)
}
// Excluded by default (use --all to include)
fn length(self : MyList) -> Int {
self.items.length() // self-delegation (encapsulation)
}
fn emit(value : String) -> Action {
Emit(value) // bare constructor
}
plan unwrap 模式:
| 模式 | 标志 | 说明 |
|---|---|---|
| 报告 | (默认) | 列出找到的包装器 |
| 预览 | --dry-run | 显示所有编辑内容,但不修改文件 |
| 修复 | --fix | 应用对文件的编辑 |
plan unwrap 选项:
| 选项 | 默认值 | 说明 |
|---|---|---|
--dry-run | -- | 预览编辑内容 |
--fix | -- | 应用编辑 |
--all | -- | 包含自委托和裸构造函数包装器 |
--include-self | -- | 包含 self.field.method 模式 |
--include-bare | -- | 包含裸构造函数包装器 |
--include=PATTERN | -- | 包含模式(可重复指定) |
--exclude=PATTERN | -- | 排除模式(可重复指定) |
--format=FORMAT | md | 输出格式:md、json、text |
-o, --output=FILE | stdout | 输出文件路径 |
--specs-dir=DIR | kgfs | KGF 规范目录 |
移除前请先审查:
- 平台包装器(FFI、
@osenv_path)是抽象层,并非无意增加的间接调用 - 公共 API 包装器供外部包使用——移除会造成破坏性变更
- 务必先运行
--dry-run
阶段 4:检测概念层面的重复(explore + 分析)
这是最难的一层。文本和结构工具找不到这类重复,因为代码不同——但概念相同。
# Find which files share vocabulary (= work in the same concept domain)
indexion explore --threshold=0.4 \
--include='*.mbt' --exclude='*_wbtest.mbt' \
--exclude='*moon.pkg*' --exclude='*pkg.generated*' \
src/ cmd/
相似度为 40-60% 且不存在结构重复的文件是概念邻居——它们使用相同的术语,因为它们处理的是同一个领域。
对于每一对高相似度文件,都要问:“它们共享什么概念?由谁负责?”
# Inspect shared vocabulary with tree structure comparison
indexion explore file_a.mbt file_b.mbt --threshold=0 --strategy=apted
概念泄漏的常见模式:
| 症状 | 泄漏的概念 | 修复方法 |
|---|---|---|
两个文件都调用 is_X(spec),然后调用 Y::from_spec(spec) | “判断是否为 X 并配置 Y” | 将 try_do_X(path, spec) 提取到负责 X 的模块中 |
两个文件都在内容已加载时调用 @fs.read_file_to_string(path) | “读取文件内容” | 将内容作为参数传递,不要重新读取 |
两个文件都先调用 parent_dir(path),然后调用 @fs.read_dir(dir) | “列出同级文件” | 将目录遍历集中到流水线中 |
多处使用 if is_virtual_path(x) { skip } 守卫 | “真实路径与虚拟路径” | 让类型系统阻止虚拟路径到达此处 |
两个文件都调用 buf.write_string("\n"); buf.write_string(x) | “拼接文本条目” | 将 join_text_entries() 提取到负责此概念的模块中 |
阶段 5:集中到 SoT
定义概念的模块应该是唯一一个实现逻辑的模块。
规则:
- 一个概念、一个模块、一个函数。 如果“从归档中提取文本”出现在
vfs.mbt、discover.mbt和args.mbt中,它就只应属于vfs.mbt。 - 调用方接收结果,而不是原料。 不要分别导出
is_archive_spec、ArchiveSpec::from_spec和expand_archive。应导出try_extract_archive_text(path, spec) -> String?。 - 守卫是症状,不是修复。
if is_virtual_path(x) { skip }意味着虚拟路径本不该到达此处。修复源头,而不是接收端。 - 重新读取已在内存中的磁盘内容是一种概念泄漏。 如果
SupportedFile.content保存了文本,下游代码就不应调用@fs.read_file_to_string(file.path)。
阶段 6:验证
# Confirm textual duplication is gone
indexion plan refactor --threshold=0.9 \
--include='*.mbt' --exclude='*_wbtest.mbt' \
--exclude='*moon.pkg*' --exclude='*pkg.generated*' \
src/ cmd/indexion/
# Confirm concept similarity is reduced
indexion explore file_a.mbt file_b.mbt --threshold=0
# Confirm wrappers are cleaned up
indexion plan unwrap --include='*.mbt' --exclude='*_wbtest.mbt' \
--exclude='*moon.pkg*' --exclude='*pkg.generated*' src/
# Run tests
moon test --target native
集中到 SoT 后:
- 概念负责模块与其调用方之间的文本相似度会降低
- 调用方会变得更短(一次 API 调用取代多步逻辑)
- 概念负责模块可能会变大,但它是唯一需要修改的地方
阶段 7:通过测试证明问题不会复现
编写一个能在结构上阻止旧模式复现的测试:
test "SoT: SupportedFile.path is always a real filesystem path" {
// Create an archive, run load_supported_file_info
// Assert: no path contains "!/"
// Assert: every path passes @fs.path_exists
}
该测试不检查行为——它检查的是 SoT 不变量。
危险信号
“我需要在这里加个守卫”
如果你正在一个不应接收特殊情况的函数中添加 if is_special_case(x) { skip },问题出在上游。该函数的调用方不应该传入这个值。
“它能正常运行,但会向 stderr 打印错误”
C 运行时向 stderr 输出的消息(opendir: No such file or directory)意味着无效数据到达了系统调用。catch 会捕获错误,但 perror() 已经打印了错误。
唯一的修复方法是阻止无效数据到达该调用。
“我会分别在每个命令中修复”
如果 explore、search、grep、reconcile、plan 文档等都需要相同的修复…… 那么修复就应该放在共享流水线中,而不是每个命令中。
“相似度只是因为用了相同的词汇,不是真正的重复”
如果本不应共享概念的模块之间 TF-IDF 相似度达到 40-60%,这就是警告。词汇匹配本身就是信号。
快速参考:何时使用哪个命令
| 问题 | 命令 |
|---|---|
| “哪些文件相似?” | explore --format=list |
| “具体有哪些重复内容?” | plan refactor --threshold=0.9 |
| “软件包 A 和 B 之间有哪些代码重叠?” | plan solid --from=A,B |
| “哪些函数是简单的包装器?” | plan unwrap or grep --semantic=proxy |
| “这些文件有什么共同概念?” | explore file_a file_b --threshold=0 --strategy=apted |
| “重复内容修复了吗?” | 使用相同阈值重新运行 plan refactor |