indexion-refactor

indexion-refactor

编写代码后,检测并清理三个层面的重复——复制粘贴块、跨包共享代码、不必要的包装器以及概念层面的单一真实来源(SoT)违规。使用 indexion 检测、修复并验证。

1Star
2Fork
更新于 2026/7/11
SKILL.md
readonly只读
name
indexion-refactor
description

编写代码后,检测并清理三个层面的重复——复制粘贴块、跨包共享代码、不必要的包装器以及概念层面的单一真实来源(SoT)违规。使用 indexion 检测、修复并验证。

indexion refactor — 代码库重构

使用 indexion 的分析命令检测并消除文本、结构和概念三个层面的重复,然后验证 SoT 是否得到执行。

何时使用

  • 添加新抽象(类型、模块、API 层)后
  • 引入新文件格式或 I/O 边界后
  • 修复需要因同一原因修改 3 个以上文件时
  • 添加了“防护”或“跳过”以解决结构性问题时
  • opendirENOENT 或类似文件系统错误从意外路径出现时
  • 跨包提取共享代码时
  • 重构后清理(移除琐碎的包装函数)时
  • 定期对代码库进行 SoT 健康检查

三个层面的重复

层面 定义 工具 示例
文本 复制粘贴的代码块、相同的函数 plan refactor is_whitespace 在 5 个模块中复制
结构 相同逻辑结构但不同名称 plan solidplan unwrap 跨包提取候选、琐碎包装器
概念 同一领域概念独立实现 explore + 手动分析 三个模块各自判断“这是归档文件吗?”

文本重复容易发现和修复。概念重复最难且最危险——它不会产生复制粘贴匹配,但意味着更改一个概念需要更新每个分散的实现。

工作流程

阶段 1:清除文本重复(plan refactor

从高置信度匹配开始,逐步降低。

# 步骤 1:查找 90% 以上的重复(高置信度)
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_dirget_global_cache_dir 共享 95% 的结构,提取为 resolve_os_dir

# 步骤 2:在合并前使用 grep 追踪引用
indexion grep "TypeIdent:TfidfEmbeddingProvider" src/
indexion grep --semantic=name:is_whitespace src/

# 步骤 3:修复,然后重新运行以确认重复已消除
indexion plan refactor --threshold=0.9 --include='*.mbt' ...

# 步骤 4:降低阈值并迭代
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() 函数)——@argparse API 模式,非重复
  • 语义不同但结构相似的函数is_disqualifying_keyword vs is_skip_token)——不同目的

阶段 2:提取跨包共享代码(plan solid

在清理每个目录内部后,查找应在包间共享的代码。

# 查找两个包之间的重叠
indexion plan solid --from=src/a,src/b

# 指定提取目标
indexion plan solid --from=src/a,src/b --to=src/common

# 使用树编辑距离进行精确的函数级匹配
indexion plan solid --from=src/a,src/b --strategy=apted

# 更高阈值以获得更严格的匹配
indexion plan solid --from=src/a,src/b --threshold=0.95

# 过滤文件
indexion plan solid --from=src/a,src/b --include='*.mbt' --exclude='*_test.mbt'

plan solidplan 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 规范目录

工作流程:

  1. 先对每个目录单独运行 plan refactor 清理内部重复
  2. 运行 plan solid --from=dirA,dirB 查找跨目录提取候选
  3. 按照计划建议提取共享代码
  4. 使用 indexion grep "TypeIdent:SharedType" 验证所有引用已更新

阶段 3:移除不必要的包装器(plan unwrap

合并后,清理那些增加间接性而无价值的琐碎委托函数。

# 步骤 1:快速检查
indexion grep --semantic=proxy src/

# 步骤 2:详细报告
indexion plan unwrap --include='*.mbt' --exclude='*_wbtest.mbt' \
  --exclude='*moon.pkg*' --exclude='*pkg.generated*' src/

# 步骤 3:预览更改(安全——不修改文件)
indexion plan unwrap --dry-run --include='*.mbt' --exclude='*_wbtest.mbt' \
  --exclude='*moon.pkg*' --exclude='*pkg.generated*' src/

# 步骤 4:应用修复
indexion plan unwrap --fix --include='*.mbt' --exclude='*_wbtest.mbt' \
  --exclude='*moon.pkg*' --exclude='*pkg.generated*' src/

# 步骤 5:运行测试
moon test --target native

检测内容: 函数体为单个函数调用且所有参数作为简单标识符转发——无控制流、无转换。

// 检测到(默认)——琐碎委托
fn matches_pattern(text : String, pat : String) -> Bool {
  @glob.glob_match(text, pat)
}

// 默认排除(使用 --all 包含)
fn length(self : MyList) -> Int {
  self.items.length()    // 自委托(封装)
}
fn emit(value : String) -> Action {
  Emit(value)            // 裸构造函数
}

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 + 分析)

这是最难的层面。文本和结构工具无法发现它,因为代码不同——但概念相同。

# 查找共享词汇的文件(= 在同一概念领域工作)
indexion explore --threshold=0.4 \
  --include='*.mbt' --exclude='*_wbtest.mbt' \
  --exclude='*moon.pkg*' --exclude='*pkg.generated*' \
  src/ cmd/

相似度在 40-60% 且无结构重复的文件是概念邻居——它们使用相同术语,因为处理同一领域。

对于每个高相似度对,问:“它们共享什么概念,谁拥有它?”

# 通过树结构比较检查共享词汇
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 } 防护 “真实路径 vs 虚拟路径” 让类型系统阻止虚拟路径到达此处
两个文件都调用 buf.write_string("\n"); buf.write_string(x) “连接文本条目” join_text_entries() 提取到拥有模块

阶段 5:合并到 SoT

定义概念的模块应该是唯一实现逻辑的模块。

规则:

  1. 一个概念,一个模块,一个函数。 如果“从归档中提取文本”出现在 vfs.mbtdiscover.mbtargs.mbt 中,它应仅属于 vfs.mbt
  2. 调用者接收结果,而非原料。 不要分别导出 is_archive_spec + ArchiveSpec::from_spec + expand_archive。导出 try_extract_archive_text(path, spec) -> String?
  3. 防护是症状,而非修复。 if is_virtual_path(x) { skip } 意味着虚拟路径根本不应到达此处。修复源头,而非接收端。
  4. 从磁盘重新读取已在内存中的内容是概念泄漏。 如果 SupportedFile.content 保存了文本,下游代码不应调用 @fs.read_file_to_string(file.path)

阶段 6:验证

# 确认文本重复已消除
indexion plan refactor --threshold=0.9 \
  --include='*.mbt' --exclude='*_wbtest.mbt' \
  --exclude='*moon.pkg*' --exclude='*pkg.generated*' \
  src/ cmd/indexion/

# 确认概念相似度降低
indexion explore file_a.mbt file_b.mbt --threshold=0

# 确认包装器已清理
indexion plan unwrap --include='*.mbt' --exclude='*_wbtest.mbt' \
  --exclude='*moon.pkg*' --exclude='*pkg.generated*' src/

# 运行测试
moon test --target native

SoT 合并后:

  • 概念拥有者与其调用者之间的文本相似度降低
  • 调用者变得更短(一个 API 调用而非多步逻辑)
  • 概念拥有者可能变大,但它是唯一需要修改的地方

阶段 7:通过测试证明不再复发

编写一个从结构上防止旧模式复发的测试:

test "SoT: SupportedFile.path 始终是真实文件系统路径" {
  // 创建归档,运行 load_supported_file_info
  // 断言:没有路径包含 "!/"
  // 断言:每个路径通过 @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 documentation 中都需要……修复应属于共享管道,而非每个命令。

“相似度只是共享词汇,并非真正的重复”

在不应该共享概念的模块之间出现 40-60% 的 TF-IDF 相似度是一个警告。词汇匹配本身就是信号。

快速参考:何时使用哪个命令

问题 命令
“哪些文件相似?” explore --format=list
“具体重复了什么?” plan refactor --threshold=0.9
“包 A 和 B 之间有哪些代码重叠?” plan solid --from=A,B
“哪些函数是琐碎包装器?” plan unwrapgrep --semantic=proxy
“这些文件共享什么概念?” explore file_a file_b --threshold=0 --strategy=apted
“重复是否已修复?” 使用相同阈值重新运行 plan refactor