mcpField
A
ast-index

ast-index

github.com/defendend开发58139 次安装4 周前更新
代码仓库

关于 ast-index

ast-index 是面向多语言、多平台项目的 Rust 代码索引与搜索命令行工具,适合需要理解代码结构和追踪符号引用的开发者。它结合 SQLite 与 FTS5,并提供相关性排序、符号关系及 Git 历史排序能力。

主要功能

  1. 01跨多语言项目建立索引
  2. 02按意图或符号搜索代码
  3. 03查看定义、调用与继承关系
  4. 04按 Git 历史和依赖关系排序
  5. 05查找符号使用位置与文件

适用场景

  1. 01了解代码库中特定功能的实现
  2. 02重构前追踪符号的使用位置
  3. 03从多个同名实现中筛选候选项
  4. 04定位项目中的类、函数和测试

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/defendend/claude-ast-index-search --skill ast-index

安装后在 Claude Code 中输入/ast-index确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
android-commands.md
cpp-commands.md
csharp-commands.md
dart-commands.md
go-commands.md
ios-commands.md
matlab-commands.md
module-commands.md
perl-commands.md
proto-commands.md
python-commands.md
ruby-commands.md
rust-commands.md
typescript-commands.md
wsdl-commands.md

详细介绍

ast-index - 多平台项目的代码搜索

快速的原生 Rust CLI,可使用 SQLite + FTS5 索引,在 Android/Kotlin/Java、iOS/Swift/ObjC、Dart/Flutter、TypeScript/JavaScript、Rust、Ruby、C#、Scala、PHP、Perl、Python、Go、C++ 和 Proto 项目中进行结构化代码搜索。

关键规则

任何代码搜索任务都必须始终先使用 ast-index。 以下规则为强制要求:

  1. ast-index 是主要搜索工具 — 在 grep、ripgrep 或 Search 工具之前使用它
  2. 根据已知信息选择命令:
    • 你有一个意图或描述(“如何处理身份验证”“处理更新管理员”)→ ast-index explore "<query>"。它会按相关性排序并打印源码。
    • 你有一个确切的标识符(UserService、parseConfig)→ ast-index search / symbol / class。需要定义主体时,在 symbol 中添加 --with-content;不确定确切限定名称或类型时,在 search 中添加该选项。
    • 如果多词查询没有字面匹配,search 本身会回退到 explore 排序,因此选错命令并不会造成严重问题 — 但对于问题,explore 才是正确的首选调用。
  3. 不要重复搜索结果 — 如果 ast-index 找到了用法/实现,这就是完整答案
  4. ast-index 返回结果后,不要为了“完整性”再运行 grep
  5. 不要重新读取 --with-content 返回的主体 — 成功返回的结果可替代通常的 sed / awk / grep / rg 或读取文件步骤。只有在主体被截断或不可用,或者需要定义之外的文本时,才使用这些工具。
  6. 仅在以下情况使用 grep/Search:
    • ast-index 返回空结果
    • 搜索正则表达式模式(ast-index 使用字面匹配)
    • 搜索代码中的字符串字面量("some text")—— usages 和 refs 会跳过字符串和注释中的名称
    • 搜索注释内容

原因: ast-index 的速度比 grep 快 17-69 倍(1-10ms,而 grep 为 200ms-3s),并且能返回结构化、准确的结果。

前置条件

使用前安装 CLI:

brew tap defendend/ast-index
brew install ast-index

在项目根目录初始化索引:

cd /path/to/project
ast-index rebuild

索引存储在 ~/Library/Caches/ast-index/<project-hash>/index.db(macOS)或 ~/.cache/ast-index/<project-hash>/index.db(Linux)。重建会生成全新索引并替换旧索引;具名子树和收集到的 Git 历史记录(hotspots --collect)会予以保留。

支持的项目

平台语言模块系统
Android/JavaKotlin、JavaGradle (build.gradle.kts)、Maven (pom.xml)
iOSSwift、Objective-CSPM (Package.swift)
WebTypeScript、JavaScript、React、Vue、Sveltepackage.json
RustRustCargo.toml
RubyRuby、Rails、RSpecGemfile
.NETC#、ASP.NET、Unity*.csproj
Dart/FlutterDartpubspec.yaml
ScalaScalaBazel (WORKSPACE, BUILD)
PHPPHPcomposer.json
PerlPerlMakefile.PL、Build.PL
PythonPython无(*.py 文件)
GoGo无(*.go 文件)
ProtoProtocol Buffers (proto2/proto3)无(*.proto 文件)
WSDLWSDL、XSD无(.wsdl、.xsd 文件)
C/C++C、C++ (JNI、uservices)无(.cpp、.h、*.hpp 文件)
GodotGDScriptproject.godot
混合以上全部全部

项目类型会根据标记文件自动检测(build.gradle.kts、Package.swift、Makefile.PL 等)。Python、Go、Proto、WSDL 和 C++ 文件会与主要项目类型的文件一同编入索引。

不会索引或搜索压缩后的 JavaScript/CSS:文件名为 *.min.* 或 *-min.* 的 .js/.mjs/.cjs/.css 文件,或前 64 KiB 为压缩器输出的文件(代码行平均长度为 1000 字节以上,而非一条长字符串)。基于 grep 的命令也会跳过这些文件;对这类文件运行 outline/imports 时会打印 Skipped: minified file,而不是进行解析。设置 AST_INDEX_SKIP_MINIFIED=0 可关闭此过滤。

核心命令

探索(单次获取上下文)

explore - 为查询中最相关的符号排序,展示最佳文件 ——提供类型或模块的大纲及行范围(其中的定义、用 → 标记选中的定义)、函数的源码(从磁盘实时读取)、 图邻居(调用者/子类),并按路径约定定位测试 ——一次调用即可完成。若要了解某个领域,优先使用此工具,而不是反复搜索和读取;接下来读取大纲中某一行指向的代码片段。 与语言无关且能识别供应商(node_modules 中的 .d.ts 和跨技术栈匹配会降低排名,但不会删除)。

ast-index explore applicant merge MergeService   # bag of symbol/file names
ast-index explore "how does auth session work"   # natural-language question
ast-index explore PaymentService --rwr           # --rwr: re-rank via call/inheritance graph
ast-index explore Repository --max-files 8        # cap source files shown (default 6)
ast-index explore Session request --rwr --format json
  • 默认(Stage A)按词法匹配和多词印证进行排序。问题中的词也会连在一起读取(pdf to html service 可找到 PdfToHtmlService),并用于匹配文件路径,因此可以通过 CamelCase 类的组成词找到该类;文件所命名的类型排名高于辅助项,而语句(has_many :x、scope、include)和仅包含命名空间的模块排名低于定义。问题中的词(how、does、work)会被忽略。
  • --rwr(Stage B)会在内存中构建调用/继承图,并按个性化 PageRank 重新排序,在“图邻居”部分展示调用者/子类。速度稍慢;适合关注谁调用了什么的场景。
通用搜索

search - 同时搜索文件、符号和模块。

ast-index search "Payment"           # Finds files, classes, functions matching "Payment"
ast-index search "Payment" --with-content  # Include matched symbol bodies
ast-index search "ViewModel"         # Returns files, symbols, modules in ranked order
ast-index search "Store" --fuzzy     # Fuzzy: exact → prefix → contains matching
ast-index search "Handler" --module "core/"  # Search within a module
ast-index search "Handler" --with-content  # Include matched symbol bodies
ast-index search "UserService"       # Find Java/Spring services
ast-index search "@RestController"   # Find Spring REST controllers (annotation search)
ast-index search "@GetMapping"       # Find GET endpoint mappings

符号按层级排列:先是名称完全匹配,然后是名称最后一个 :: 或 . 段与查询匹配的符号(例如,查询 Invoice 会匹配 Billing::Invoice,查询 email 会匹配模式列 users.email),最后是部分匹配。在每个层级中,定义排在导入之前,项目代码排在 node_modules 之前;在部分匹配中,测试符号(测试文件、test_*、TestX)排在最后。

search --rank <preset> - 根据文件的 Git 历史和符号在依赖图中的位置,为“文件”和“符号”部分重新排序,并在每个结果旁附上说明其排名依据的档案。当问题不是“X 在哪里”,而是“这些 X 中哪个更合适”时使用:

ast-index search Service --fuzzy --module app/services/ --rank proven  # a settled example to copy
ast-index search Merge --rank risky                   # dangerous to touch: many dependents + unstable history
ast-index search Import --rank hotspots               # keeps being changed and fixed
ast-index search Import --rank hotspots --exclude-tests  # same, spec/test files left out
ast-index search Event --module app/models/ --rank central  # what the rest leans on (PageRank)
ast-index --format json search Merge --rank risky     # rank.applied / rank.missing + per-result dossier
预设分数需要
provenmean(1 − hotspot score, maturity, used 1/0) × substance(存根为 0.5)× lineage(基类不再有扩展时为 0.5)hotspots --collect + graph build
hotspots文件热点分数(提交次数、变更量、修复错误比例 pct)hotspots --collect
risky依赖者 pct × 热点分数两者
centralPageRank pctgraph build
  • 相关性仍是首要因素:候选范围是普通排序中排名最高的 100 个项目符号;名称完全匹配始终排在部分匹配之前;在同一层级中,排序依据为 0.9 × score + 0.1 × 1/(1 + position/20)。文件路径匹配会根据匹配所在位置(文件名主体、文件名、目录)计算相关性。
  • 历史记录按文件统计——同一文件中的所有符号共享该历史记录(输出中标为“文件历史”)。图数据按符号统计;文件结果会采用其最强符号的图数据。
  • 缺失数据绝不会按零分参与排序:不会应用预设,结果保留普通顺序,输出会指出要运行的命令(JSON 中的 rank.missing[].command)。过时的图会触发警告。
  • 第三方代码(node_modules、.d.ts)不会计分,并会列在所有项目结果之后。
  • 这些公式通过在一个包含 4 万个文件的单体仓库上回测下一年的错误修复情况来选定;proven 还参考了人工判断的“该复制哪一个”查询;相关数据见 USER_GUIDE.md(“搜索结果排序”)。数据表现安全,并不代表它就是一个好的范例:proven 无法判断团队更偏好两种现存风格中的哪一种。
文件搜索

file - 按名称模式查找文件。

ast-index file "Fragment.kt"         # Find files ending with Fragment.kt
ast-index file "ViewController"      # Find iOS view controllers
符号搜索

symbol - 按名称查找符号(类、接口、函数、属性)。

ast-index symbol "PaymentInteractor" # Find exact symbol
ast-index symbol "PaymentInteractor" --with-content  # Include its source body
ast-index symbol "Presenter"         # Find all presenters
ast-index symbol "Store" --fuzzy     # Fuzzy: exact → prefix → contains matching
ast-index symbol "Mapper" --in-file "payments/" --limit 10  # Scoped search
ast-index symbol "Mapper" --with-content  # Include bounded source bodies
ast-index symbol "@Service"          # Find all @Service annotations

命名空间类可通过短名称或完整名称查找:LedgerImporter 和 Billing::LedgerImporter 都能找到 class Billing::LedgerImporter(在 class、refs、hierarchy、implementations 中也一样)。精确匹配的短名称优先于带命名空间的名称。usages Billing::LedgerImporter 会列出行中写出完整名称的 LedgerImporter 引用;usages LedgerImporter 会列出所有引用。

类搜索

class - 查找类、接口或协议定义。

ast-index class "BaseFragment"       # Find Android base fragment
ast-index class "UIViewController"   # Find iOS view controller subclass
ast-index class "Store" --fuzzy      # Find all classes containing "Store"
ast-index class "Repository" --module "features/payments"  # Filter by module
ast-index class "UserController"     # Find Java/Spring controller class
用法搜索

usages - 查找符号所有被使用的位置。重构时至关重要。

ast-index usages "PaymentRepository" # Find all usages of repository
ast-index usages "onClick"           # Find all click handler usages
ast-index usages "fetchData" --in-file "src/api/"  # Scoped to file path
ast-index usages "Repository" --module "features/auth" --limit 100
ast-index usages "parse_config"      # snake_case calls: Python, Rust, Go, C, PHP, ...

用法(此处以及 refs 中)会先列出生产文件,再列出测试文件;每组按路径和行号排列。在 JSON 中,测试引用带有 "test": true。

索引的用法包括首字母大写的名称和写作 name( 的调用,也包括 snake_case 和 _private 名称。不会记录保留字(sizeof (x)、#if defined(X)、Go 的 func (r *T)、Python 的 None)。

性能:索引符号的查询约需 8ms。

交叉引用

refs - 在一个视图中显示符号的交叉引用:定义、导入和用法。

ast-index refs "PaymentRepository"   # Definitions + imports + usages
ast-index refs "BaseFragment" --limit 10  # Limit results per section
实现搜索

implementations - 查找所有扩展或实现给定类/接口/协议的类。参数应为父类型,而非方法或函数名称。支持按相关性排序的部分名称匹配(精确匹配 → 后缀匹配 → 包含匹配)。

ast-index implementations "BasePresenter"  # Find all presenter implementations
ast-index implementations "Repository"     # Find repository implementations (exact match)
ast-index implementations "Service"        # Partial: finds UserService, PaymentService impls too
ast-index implementations "ViewModel" --module "features/"  # Scoped to module
ast-index implementations "Repository" --with-content  # Include bounded source bodies
类层次结构

hierarchy - 显示完整的类层次结构树。

ast-index hierarchy "BaseFragment"   # Show fragment inheritance tree
调用者搜索

callers - 查找调用某个函数的行,在查询时按名称匹配(name(、.name 等)。它会打印调用位置,而非每个调用所在的函数;要查看后者,请使用 call-tree。

ast-index callers "onClick"          # Find all onClick calls
ast-index callers "fetchUser"        # Find API call sites

在 Ruby 中,表示符号的方法名称也算作调用位置(before_save :name、 validate :name、delegate :name、map(&:name));:name?、:name! 和 :name= 表示其他方法,不算调用位置,::name 路径也不算(use super::name;、 Billing::Name),除非它被调用(Mod::name(、 Billing::Name.new)。

调用树

call-tree - 显示向上的调用层次结构:每次调用所在的函数,然后是它的调用者。适用于所有已索引语言:对于 tree-sitter 语言(Ruby、TypeScript/JavaScript、Python、Go、Rust、Java、Kotlin、Swift、C#、C/C++、PHP 等),调用者是行范围包含该调用的最内层定义;对于没有行范围的基于正则表达式的解析器(Perl、WSDL/XSD),则回退到该调用上方最近的定义。

ast-index call-tree "processPayment" --depth 3 --limit 10
ast-index call-tree "getUsers"       # Java: finds callers of getUsers() method

每个调用者都会连同其文件一起打印,包括其他文件中同名的定义(两个 it "works" 代码块算作两个调用者)。调用者按名称查找,因此每个名称只展开一次:之后遇到的同名调用者会标记为 (expanded above);(recursive) 只标记其自身调用路径上已有的定义,也就是真正的循环。导入和注解(use、include Mod、Rails 回调)都不构成调用的所属位置,包含它们的定义才是;声明函数本身的行也不算对该函数的调用。

符号依赖图

graph - 根据索引构建的有向符号间依赖图:边表示“包含引用的定义” -> “该引用指向的定义”。与 callers / call-tree(查询时进行文本搜索)不同,它基于预计算的边作答,并说明对每个目标的判断有多确定。

ast-index graph build                                 # Build/refresh the graph (explicit, ~seconds)
ast-index graph status                                # Built? Stale? Edge counts per confidence
ast-index graph dependents ApplicationService         # Who depends on it (incoming edges)
ast-index graph dependents "Billing::Invoice#total"   # A member of one class
ast-index graph dependents MergeService --exclude-tests  # Production dependents only (also on impact)
ast-index graph dependencies CheckoutController --members  # What a class and its methods use
ast-index graph impact PaymentGateway --depth 3       # Blast radius: dependents per depth, files
ast-index graph path OrdersController Invoice         # Shortest dependency path(s) between two symbols
ast-index graph cycles --path app/models              # Strongly connected components
ast-index graph top --kind class --exclude-tests      # Most central symbols (PageRank)
ast-index graph metrics Invoice Payment               # fan-in/out, dependents, PageRank per symbol

每条边都标记了目标解析时的级别: local(同一文件)、scoped(显式命名空间 A::B::Name、词法嵌套、常量接收者 Type.method 或继承/混入)、import(源文件导入目标模块)、unique(该名称在该语言中只有一个定义)、ambiguous(有多个候选,或在类型未知的接收者上调用——candidates 会说明候选数量)。入边数、出边数、依赖者和 PageRank 仅统计已解析的边;歧义边会单独统计,并通过 --include-ambiguous 列出(在 impact 中,该选项会在仅统计已解析边的数字旁给出上限)。

Rust 路径按照编译器的解析方式解析:文件即模块(src/db.rs 是 db),crate:: / super:: / self:: 遍历模块树,use 声明(分组、别名、glob 导入、pub use 重新导出)会绑定名称,因此 db::open_db(...) 会指向 src/db.rs,形成一条 scoped 边,而通过 use 导入的名称会形成一条 import 边。另一个工作区 crate 通过其 Cargo.toml 库名称访问;std:: 和依赖项路径不会解析到同名的项目定义。

类符号仅包含其类级引用(超类、混入);对 dependents / dependencies / impact 传入 --members,可涵盖类内部的定义。path 始终将类视为自身及其成员,并可能从类进入成员(显示为 contains),因为像 Service.call -> process 这样的分派无法静态识别。

一个裸名称可能匹配多个定义(call,或作为模型的 Applicant、TypeScript 类型和规范桩):此时 dependents / dependencies / impact 会合并这些定义的边,说明匹配的定义数量,最多列出 --limit 个,并建议使用 Outer::Name、Class#member、--in-file 或 --kind。

在 Rails 应用中,db/schema.rb 的表会与模型匹配(self.table_name、单表继承、table_name_prefix / isolate_namespace、嵌套、复数形式的类名);在模型内部调用的列读取器或属性方法(status、self.status、status?、saved_change_to_status?)会解析为指向列的 scoped 边:ast-index graph dependents applicants.first_name(或 applicants#first_name)。对其他接收者的调用(applicant.first_name)不会猜测列,因此大多数列读取都不会形成这类边——结果会说明这一点;ast-index usages first_name 会列出每一次读取。graph build 会报告没有模型的表和没有表的模型。

rebuild / update 不会重新构建依赖图。更新改变索引后,查询会打印过时警告(JSON 中为 "stale": true);重新运行 graph build,或在查询中添加 --refresh,即可先重新构建。

文件分析

imports - 列出指定文件中的所有导入。

ast-index imports "path/to/File.kt"  # Show Kotlin file imports

outline - 显示文件中定义的所有符号,解析方式与索引一致(大多数语言使用 tree-sitter)。

ast-index outline "PaymentFragment.kt"    # Show Kotlin fragment structure
ast-index outline "UserController.java"   # Show Java controller methods
ast-index outline "App.tsx"               # Show TypeScript/React components and functions
ast-index outline "handler.rs"            # Show Rust structs, impls, functions
ast-index outline --format json "app.rb"  # {schema_version: 1, file, symbols: [{name, kind, line, end_line}]}

各行按源代码顺序排列。跨多行的定义会显示其范围(:12-40 Invoice [class]),因此 Read 可以精确读取该范围;单行定义则显示为 :12。如果解析器未报告范围,JSON 中的 end_line 为 null。

在 schema 转储文件(db/schema.rb)中,列会折叠到所属表的行中(:96-149 orders [table] 33 columns),以保持大纲简洁;--full 会列出每一列,而 symbol --type column --pattern 'users.*' 会列出单个表的列。

代码质量

todo - 查找代码中的 TODO/FIXME/HACK 注释。

ast-index todo                           # Find all TODO comments
ast-index todo --limit 10                # Limit results

deprecated - 查找 @Deprecated 注解。

ast-index deprecated                     # Find deprecated items

unused-symbols - 查找可能未使用的导出符号。

ast-index unused-symbols --module path/to/module   # In specific module
ast-index unused-symbols --export-only             # Only exported (public) symbols
Git/Arc 集成

changed - 快速汇总检测到的 Git/Arc 仓库中的分支级文件。它比较 merge-base(base, HEAD) 与 HEAD,并报告相对于仓库的路径及 A(新增)、M(修改)、D(删除)或 R(重命名)状态。若未指定 --base,Git 会解析 origin/HEAD,然后依次尝试 origin/main、origin/master、main、master 和 trunk;Arc 使用 trunk。对于重命名,JSON 包含 old_path。

ast-index changed                              # Auto-detect Git base; Arc uses trunk
ast-index changed --base main                  # Explicit base branch
ast-index --format json changed --base trunk   # Stable JSON schema v1
ast-index changed --timeout-ms 30000           # Bound VCS execution time
ast-index changed --verbose                    # Exact VCS argv and timing on stderr

文本输出示例:

Changed files against main (5):
  A  src/new.rs
  M  src/lib.rs
  D  src/obsolete.rs
  R  src/old.rs -> src/current.rs
  M  src/generated\nname.rs

文本模式会转义控制字符和反斜杠,确保每条结果都保持在一行内。 脚本应请求 JSON,而不是解析文本摘要。

JSON 输出示例:

{
  "schema_version": 1,
  "vcs": "git",
  "base": "main",
  "head": "HEAD",
  "scope": null,
  "changes": [
    { "status": "M", "path": "src/lib.rs" },
    { "status": "R", "path": "src/current.rs", "old_path": "src/old.rs" }
  ]
}

在仓库根目录,scope 为 null;在嵌套工作目录中,它是相对于仓库的 目录路径。

changed 直接读取 VCS 状态,不依赖 ast-index 数据库/缓存。其作用范围是当前工作目录,但输出路径仍相对于仓库根目录。 可用它在审查前盘点分支文件;如需补丁块,请使用原始的 git diff / arc diff。 它不会报告变更的符号,也不会包含仅存在于暂存区/未暂存工作树中的修改。

hotspots - 根据文件的 Git 历史对文件进行排名:提交数、变更量(新增 + 删除的行数,以及对于 10 行及以上的文件,相对于当前文件大小的变更量)、修复错误的提交占比、不同作者数、文件年龄,以及距最近一次变更的时间。 在多个相似文件中选择一个作为模式参考,或确定重构范围时可使用它:一个有 28 次提交且 54% 为修复错误提交的文件,与一个仅编写过一次、86 天未改动的文件并不相同。

阈值是此仓库内的百分位数,并非固定值——28 次提交对一个库来说很多,但在单体仓库中可能很寻常。标签旁始终会打印原始数值。

ast-index hotspots --collect                   # Read new Git history, then report
ast-index hotspots --limit 50 --sort fixes     # Report only; no Git subprocess
ast-index hotspots --path src/parsers          # Narrow output; percentiles stay global
ast-index hotspots --exclude-tests             # Hide spec/test files; percentiles stay global
ast-index hotspots --collect --full            # Discard the cursor, rescan everything
ast-index --format json hotspots --limit 10    # Paginated JSON schema v2

收集操作不会自动执行:rebuild 和 update 不会运行它。首次使用 --collect 时,会遍历完整历史并存入按提交划分的存储;之后的运行会通过集合差异将其推进到当前 HEAD——HEAD 不再能到达的提交(切换分支、变基、重置、强制推送)会被扣除,新提交会被添加——因此,切换分支所需的时间与差异提交数成正比,切回时则无需重新读取。所得数值与在该 HEAD 上完整重新收集的结果一致;行数来自工作树,因此未提交的编辑会在后续 --collect 重新计算该文件时,或在使用 --full 时计入。只有游标提交已被垃圾回收、项目根目录发生变化,或使用 --full 时,才会从头重建。rebuild 会保留已收集的历史(它不依赖索引),除非这些历史来自较旧版本、其他工作树或其他作用范围;遇到这种情况时,下次 --collect 会重新读取历史。

标签:churn:high / churn:elevated、rewritten-often(相对变更量,仅适用于 10 行及以上的文件:低于此行数时,行数不再能衡量内容,例如单行打包文件、测试夹具、被掏空的视图)、fixes:high / fixes:elevated(仅适用于至少有 4 次提交的文件)、authors:many、veteran。 --sort 接受 score(默认值)、commits、churn、relative-churn、 fixes、authors、recent。打印的 score 会四舍五入;排序(以及 JSON 中的 score_exact)使用未四舍五入的百分位数均值,因此大型仓库顶部的结果不会都挤成并列。fixes 会按经过历史记录稀疏度折减的修复错误提交占比排序(95% Wilson 区间下限:11 次中的 17 次高于 2 次中的 2 次),提交少于 4 次的文件排在最后。修复错误检测采用提交主题启发式规则(支持英语和俄语;会先去除开头的跟踪器编号;[HOTFIX] / [FIX] 等标签也计为修复);合并提交会被排除,重命名时历史会沿用到新路径。

公共 API

api - 显示模块的公共 API。接受模块路径或模块名称(点号会转换为斜杠)。

ast-index api "path/to/module"           # By path
ast-index api "module.name"              # By module name (dots → slashes)

项目洞察

项目概览

map - 显示精简的项目概览:按大小排列的顶层目录及其符号类型计数。使用 --module 深入查看特定区域的完整类和继承详情。

ast-index map                                # Summary: top 50 dirs with kind counts (~54 lines)
ast-index map --limit 20                     # Show only top 20 directories
ast-index map --module features/payments     # Detailed: classes with inheritance for a module
ast-index map --module src/core --per-dir 10 # More symbols per directory in detailed mode
ast-index map --format json                  # JSON output

摘要模式输出(默认,不使用 --module):

Project: Android (Kotlin/Java) | 29144 files | 859 modules | top 50 of 728 dirs

  features/taxi_order/impl/          1626 files | 371 iface, 94 obj, 1834 cls
  features/masstransit/impl/          862 files | 165 obj, 1261 cls, 280 iface

详细模式输出(使用 --module):

features/payments/impl/ (250 files)
  PaymentInteractor : class > BaseInteractor
  PaymentRepository : interface
  PaymentMapper : class
项目约定

conventions - 从已索引的代码库中自动检测架构模式、框架和命名约定。运行只读 SQL 查询,无需扫描文件。

ast-index conventions                        # Text output (~30 lines)
ast-index conventions --format json          # JSON output

检测内容:

  • 架构:Clean Architecture、Feature-sliced、BLoC、MVC、MVVM、MVP、Redux、Composition API、Hooks
  • 框架:DI(Hilt、Dagger、Koin)、异步(Coroutines、RxJava、Combine)、网络(Retrofit、OkHttp)、数据库(Room、Realm、ActiveRecord、Sequel)、UI(Compose、SwiftUI、React、Flutter)、测试(JUnit、Kotest、XCTest、pytest、Jest、RSpec)、Web(Rails、Django、Flask、FastAPI、Express)、任务(Sidekiq、Celery)——根据导入和 require 名称检测,并按完整名称段匹配(sequel-combine 不会被识别为 Combine)
  • 命名模式:ViewModel、Repository、UseCase、Service、Controller、Fragment 等(附带计数)

常用标志

大多数搜索命令(search、symbol、class、usages、implementations、refs)支持:

标志说明
--fuzzy模糊搜索:精确匹配 → 前缀匹配 → 包含匹配(仅适用于 search、symbol、class)
--in-file <PATH>按文件路径筛选结果(子串匹配;也适用于 callers 和 call-tree)
--module <PATH>按路径前缀筛选结果
--limit <N>返回的最大结果数
--format json输出 JSON,以便进行结构化处理

何时使用 --fuzzy: 不确定准确名称时。ast-index class "Store" --fuzzy 可查找 Store、StoreImpl、AppStore、DataStoreRepository 等。--fuzzy 标志执行三阶段匹配:先精确匹配,再前缀匹配,最后包含匹配。

索引管理

ast-index rebuild                        # Full rebuild with dependencies
ast-index rebuild --no-deps              # Skip module dependency indexing
ast-index rebuild --no-ignore            # Include gitignored files (build/, etc.)
ast-index rebuild --sub-projects         # Index each sub-project separately (large monorepos)
ast-index rebuild -j 32                  # Use 32 threads (for network/FUSE filesystems)
ast-index rebuild -v                     # Verbose logging with timing per step
ast-index update                         # Incremental update (changed files only)
ast-index stats                          # Show index statistics
ast-index clear                          # Delete index for current project
ast-index restore /path/to/index.db      # Restore index from a .db file
ast-index watch                          # Watch for file changes and auto-update index
按目录范围搜索

从子目录运行搜索时,结果会自动限制在该子树中(通过缓存中的索引数据库检测项目根目录):

cd /project/root
ast-index rebuild                        # Index entire project
ast-index search "Payment"              # Finds results across entire project

cd /project/root/services/payments
ast-index search "Payment"              # Only finds results within services/payments/
ast-index class "PaymentService"        # Only classes in services/payments/ subtree

此功能适用于所有搜索命令:search、symbol、class、implementations、usages。

多根项目

为有意跨越同级源代码树的工作区附加具名子树。这些子树会与主项目一同建立索引;主项目必须先建立索引:

ast-index subtree add shared ../shared-library   # Attach a named subtree
ast-index update                                 # Index its files
ast-index subtree list                           # List attached subtrees
ast-index subtree remove shared                  # Detach, then rebuild to drop its files
ast-index --subtree shared search "Payment"      # Query one subtree
ast-index --local search "Payment"               # Query the primary project only

add-root、remove-root 和 list-roots 仍作为兼容别名保留。不要将一个 git worktree 附加到另一个 worktree:每个 worktree 都有自己的索引。

实用命令

ast-index version                    # Show CLI version
ast-index help                       # Show help message
ast-index help <command>             # Show help for specific command
ast-index install-claude-plugin      # Install Claude Code plugin to ~/.claude/plugins/

程序化访问(SQL 和 SDK)

对于需要组合多个查询、筛选或聚合的复杂分析,请使用直接 SQL 访问,而不要串联多个命令。

结构化搜索(ast-grep)

使用 AST 模式进行结构化代码搜索。需要安装 sg(ast-grep)。

# Simple pattern matching
ast-index agrep "router.launch($$$)" --lang kotlin
ast-index agrep "@Inject constructor($$$)" --lang kotlin
ast-index agrep "suspend fun $NAME($$$)" --lang kotlin

# Find classes extending a specific base
ast-index agrep "class $NAME : BasePresenter($$$)" --lang kotlin

# Find async functions (Swift)
ast-index agrep "func $NAME($$$) async" --lang swift

# Find React components
ast-index agrep "export default function $NAME($$$)" --lang typescript

# JSON output for programmatic use
ast-index agrep "@Composable fun $NAME($$$)" --lang kotlin --json

模式语法(ast-grep):

  • $NAME — 匹配单个 AST 节点(捕获为元变量)
  • $$$ — 匹配零个或多个 AST 节点(可变参数)
  • 其他所有内容都是与 AST 匹配的字面模式

何时使用 agrep 而非内置命令:

  • composables、inject、suspend → 使用内置命令(更快,且已预先配置)
  • 自定义结构模式、否定匹配、上下文查询 → 使用 agrep
原始 SQL 查询
# Execute any SELECT query against the index database (JSON output)
ast-index query "SELECT s.name, s.kind, f.path FROM symbols s JOIN files f ON s.file_id = f.id WHERE s.kind = 'class'"

# With limit
ast-index query "SELECT * FROM symbols WHERE name LIKE '%Service%'" --limit 50

# Complex joins — find classes that implement an interface but have no usages
ast-index query "SELECT s.name, f.path FROM symbols s JOIN files f ON s.file_id = f.id JOIN inheritance i ON s.id = i.child_id WHERE i.parent_name = 'Repository' AND s.name NOT IN (SELECT name FROM refs)"

# Find files with most symbols (complexity hotspots)
ast-index query "SELECT f.path, COUNT(*) as sym_count FROM symbols s JOIN files f ON s.file_id = f.id GROUP BY f.id ORDER BY sym_count DESC LIMIT 20"

# Find unused classes (defined but never referenced)
ast-index query "SELECT s.name, s.kind, f.path FROM symbols s JOIN files f ON s.file_id = f.id WHERE s.kind IN ('class', 'interface') AND s.name NOT IN (SELECT name FROM refs) AND s.name NOT IN (SELECT parent_name FROM inheritance)"

# Module dependency analysis — find modules with most dependencies
ast-index query "SELECT m.name, COUNT(*) as dep_count FROM module_deps md JOIN modules m ON md.module_id = m.id GROUP BY m.id ORDER BY dep_count DESC"

# CTE — transitive dependency chain
ast-index query "WITH RECURSIVE chain AS (SELECT md.dep_module_id, m.name, 1 as depth FROM module_deps md JOIN modules m ON md.dep_module_id = m.id WHERE md.module_id = (SELECT id FROM modules WHERE name LIKE '%payments%') UNION ALL SELECT md.dep_module_id, m.name, c.depth + 1 FROM chain c JOIN module_deps md ON md.module_id = c.dep_module_id JOIN modules m ON md.dep_module_id = m.id WHERE c.depth < 5) SELECT DISTINCT name, depth FROM chain ORDER BY depth, name"

安全性:只允许使用 SELECT、WITH 和 EXPLAIN 查询。修改操作(INSERT、UPDATE、DELETE、DROP)会被拦截。

数据库架构
# Show all tables with columns and row counts (JSON)
ast-index schema

主要表:

表描述关键列
files已索引的源文件path、mtime、size
symbols类、函数、属性等name、kind、line、file_id、signature
symbols_fts对符号进行 FTS5 全文搜索name、signature
inheritance父子类型关系child_id、parent_name、kind
refs符号引用/使用情况name、line、file_id、context
modules构建模块(Gradle、Maven 等)name、path、kind
module_deps模块 → 模块依赖module_id、dep_module_id
transitive_deps预先计算的传递依赖module_id、dependency_id、depth
xml_usagesAndroid XML 布局类的使用情况class_name、file_path
resourcesAndroid 资源定义type、name、file_path
直接访问数据库(SDK / 脚本编写)
# Get the SQLite database path for external tools
ast-index db-path
# Output: /Users/me/.cache/ast-index/abc123/index.db

任何支持 SQLite 的语言均可使用此方式:

import sqlite3, json
db_path = subprocess.check_output(["ast-index", "db-path"]).decode().strip()
conn = sqlite3.connect(db_path)

# Example: find all classes implementing an interface with no references
unused_impls = conn.execute("""
    SELECT s.name, f.path, i.parent_name
    FROM symbols s
    JOIN files f ON s.file_id = f.id
    JOIN inheritance i ON s.id = i.child_id
    WHERE s.name NOT IN (SELECT name FROM refs)
    ORDER BY i.parent_name, s.name
""").fetchall()
for name, path, parent in unused_impls:
    print(f"  {name} implements {parent} — {path}")

何时使用 query,何时使用预定义命令:

  • 简单查找 → 使用 search、class、usages(速度更快,输出格式化)
  • 复杂联接、聚合、否定条件 → 使用 query(一次调用即可,无需调用 N 次)
  • 批量分析、脚本编写、CI 流水线 → 使用 db-path + 直接访问 SQLite

性能参考

单次调用的实际耗时(包含进程启动):小型项目,以及一个包含 40k 个文件(30 万个符号)的 Rails + React 单体仓库,页面缓存已预热。

命令小型项目40k 个文件备注
class / symbol~10ms~20ms直接索引查找
usages / implementations~10ms~20-40ms索引引用搜索
imports~10ms~20ms基于文件的查找
outline~10ms~50ms解析文件
search~10ms~250-550msFTS5 符号搜索,并扫描文件内容
explore~15ms~100-150ms--rwr ~200ms
graph queries~10ms~100ms需要 graph build(~1-2s)
callers~20ms~200ms在查询时进行文本匹配
call-tree~20ms~500ms查找调用者的调用者
map / conventions~20ms~0.1-1sSQL 聚合
rebuild秒级分钟级完整项目索引

平台专属命令

Android/Kotlin/Java/Spring

参阅:references/android-commands.md

Java 解析器会索引:类、接口、枚举、方法、构造函数、字段和重要注解(@RestController、@Service、@Repository、@Component、@Entity、@GetMapping、@PostMapping、@Autowired、@Override、@Transactional、@SpringBootApplication、@Test、@Inject、@Data、@Builder 等)。

除 Gradle 模块外,也全面支持 Maven 模块(pom.xml)。

  • DI 命令:provides、inject(@Inject + @Autowired)、annotations
  • Compose 命令:composables、previews
  • 协程命令:suspend、flows
  • XML 命令:xml-usages、resource-usages
  • 代码质量:deprecated、suppress、todo
  • 扩展:extensions
  • 导航:deeplinks
iOS/Swift/ObjC

参阅:references/ios-commands.md

  • Storyboard 和 XIB:storyboard-usages
  • 资源:asset-usages
  • SwiftUI:swiftui
  • Swift 并发:async-funcs、main-actor
  • Combine:publishers
TypeScript/JavaScript

参阅:references/typescript-commands.md

  • 索引:class、interface、type、function、const、装饰器
  • 支持:React(hooks、组件)、Vue SFC、Svelte、NestJS、Angular
  • outline 和 imports 可用于 TS/JS 文件
Rust

参阅:references/rust-commands.md

  • 索引:struct、enum、trait、impl、fn、macro_rules!、mod
  • 支持:派生项、属性(#[test]、#[derive])
  • outline 和 imports 可用于 Rust 文件
Ruby

参阅:references/ruby-commands.md

  • 索引:class、module、def、常量(A::B = ...)、Rails DSL
  • 支持:RSpec(describe、it、let)、Rails(关联、验证)
  • db/schema.rb(即使被 gitignore 忽略也会建立索引):将表作为 table、将列作为 column,命名为 table.column — ast-index search first_name -t column
  • outline 和 imports 适用于 Ruby 文件
C#/.NET

参阅:references/csharp-commands.md

  • 索引:class、interface、struct、record、enum、方法、属性
  • 支持:ASP.NET 属性、Unity(MonoBehaviour、SerializeField)
  • outline 和 imports 适用于 C# 文件
Dart/Flutter

参阅:references/dart-commands.md

  • 索引:class、mixin、extension、extension type、enum、typedef、函数、构造函数
  • 支持:Dart 3 修饰符(sealed、final、base、interface、mixin class)
  • outline 和 imports 适用于 Dart 文件
Python

参阅:references/python-commands.md

  • 索引:class、def、async def、装饰器
  • outline 和 imports 适用于 Python 文件
Go

参阅:references/go-commands.md

  • 索引:package、type struct、type interface、func
  • outline 和 imports 适用于 Go 文件
Scala
  • 索引:class、case class、object、trait、enum(Scala 3)、def、val、var、type、given
  • 支持:继承(extends/with)、伴生对象
  • outline 和 imports 适用于 Scala 文件
PHP
  • 索引:namespace、class、interface、trait、enum、function、method、const、property、use
  • 支持:Laravel(模型、traits、facades)、extends/implements、命名空间导入
  • outline 和 imports 适用于 PHP 文件
Perl

参阅:references/perl-commands.md

  • 导出:perl-exports
  • 子程序:perl-subs
  • POD:perl-pod
  • 导入:perl-imports
  • 测试:perl-tests
模块分析

参阅:references/module-commands.md

  • 模块搜索:module
  • 依赖项:deps、dependents
  • 未使用的依赖项:unused-deps
  • 未使用的符号:unused-symbols
  • 公共 API:api

工作流建议

  1. 在项目根目录运行一次 ast-index rebuild 以构建索引
  2. 开始一个会话,运行 ast-index conventions + ast-index map 以了解项目结构(约 80 行,约 500 个 token)
  3. 使用 ast-index map --module <path> 深入查看特定区域
  4. 探索时使用 ast-index search 进行快速通用搜索
  5. 使用 ast-index class 精确查找类/接口
  6. 重构前使用 ast-index usages 查找所有引用(使用 graph dependents 查找某个定义的依赖方)
  7. 使用 ast-index implementations 了解继承关系
  8. 代码审查前使用 ast-index changed --base main 清点分支文件
  9. 定期运行 ast-index update 以保持索引最新

JSON 输出(可选)

默认输出为人类可读的纯文本——除非确实需要用于脚本的结构化数据,否则请使用默认输出。

仅在以下情况添加 --format json:

  • 以编程方式解析输出(管道、脚本)
  • 需要精确字段值(文件路径、状态、行号、符号类型)
  • 与其他工具集成

支持 JSON 输出的命令包括 search、explore、file、symbol、class、usages、callers、implementations、refs、stats、changed、hotspots、graph …、unused-symbols、map 和 conventions;其他命令(outline、call-tree、hierarchy、imports、todo)无论如何都输出文本。

ast-index --format json search "Query" | jq '.symbols[].path'

其他资源

如需查看平台特定命令的详细信息,请参阅:

  • references/android-commands.md - DI、Compose、Coroutines、XML
  • references/ios-commands.md - Storyboard、SwiftUI、Combine
  • references/typescript-commands.md - React、Vue、Svelte、NestJS、Angular
  • references/rust-commands.md - 结构体、trait、impl 块、宏
  • references/ruby-commands.md - Rails、RSpec、类、模块
  • references/csharp-commands.md - ASP.NET、Unity、控制器、接口
  • references/dart-commands.md - Dart/Flutter 类、mixin、扩展
  • references/perl-commands.md - Perl 导出项、子程序、POD
  • references/python-commands.md - Python 类、函数
  • references/go-commands.md - Go 结构体、接口
  • references/cpp-commands.md - C/C++ 类、JNI 函数
  • references/proto-commands.md - Protocol Buffers 消息、服务
  • references/wsdl-commands.md - WSDL 服务、XSD 类型
  • references/module-commands.md - 模块依赖

评论

支持 Markdown