---
name: astgrep
description: "Unified code search via ast-grep (AST structural) + ripgrep (text). TRIGGER when: searching code patterns, finding function calls, AST pattern matching, text keyword search, refactor locating, legacy code scanning, structural code rewrite. BLOCKING: sg-rewrite --apply (modifies files). SKIP: remote GitHub search (use github skill's gh-search-code), natural language code explanation without patterns, Nushell files (.nu not supported by ast-grep)."
version: "5.1.0"
user-invocable: true
argument-hint: "<sg-search|sg-rewrite|rg-search|sg-langs|sg-check> [query] [--lang] [--path] [--rule] [--kind] [--globs] [--apply]"
effort: low
---

# astgrep — ast-grep + ripgrep

## Step 1: 初始化

对话中仅执行一次。检测方式：`which sg-check` 非空则已加载。

```nu
use skills/astgrep/astgrep.nu *
sg-check
```

`sg-check` 返回 `{sg: {installed, version}, rg: {installed, version}}`。需要 `sg`（ast-grep）和 `rg`（ripgrep）已安装。

## Step 2: 搜索

1. **`sg-search`** — AST 结构化搜索（精确模式匹配）
2. **`rg-search`** — 文本搜索（通用 fallback）
3. 远程 GitHub 代码搜索 → 使用 github skill 的 `gh-search-code`

## Step 3: 重写

`sg-rewrite` 默认 dry-run（预览 diff），加 `--apply` 真正写入。

## 命令速查

### 搜索

| 命令 | 说明 |
|------|------|
| `sg-search <query> [--lang] [--path] [--rule] [--kind] [--globs]` | AST 结构化搜索 |
| `rg-search <query> [--path] [--glob] [--type] [-C]` | 文本搜索 |

### 重写

| 命令 | 说明 |
|------|------|
| `sg-rewrite <query> <replacement> [--lang] [--path]` | AST 重写预览（dry-run） |
| `sg-rewrite <query> <replacement> --apply` | AST 重写（写入文件） |

### 辅助

| 命令 | 说明 |
|------|------|
| `sg-langs` | 支持的语言 + 扩展名映射 |
| `sg-check` | 检查 sg/rg 安装状态 |

## sg-search 三种模式

```nu
sg-search "console.log($A)" --lang js          # Pattern 模式
sg-search --rule rule.yml --path ./src         # Rule 模式（YAML 规则）
sg-search --kind function_declaration --lang rs # Kind 模式（节点类型）
```

→ 元变量语法（`$VAR` / `$$$ARGS` / `$_`）、YAML rule 关系约束（inside/has/not）深度示例见 [patterns.md](references/patterns.md)。

## 返回值

### sg-search / rg-search

| 字段 | 类型 | 说明 |
|------|------|------|
| engine | string | `"sg"` 或 `"rg"` |
| file | string | 文件路径 |
| line | int | 行号（1-based） |
| text | string | 匹配文本 |
| metavars | record? | sg 元变量 `{$VAR: "value"}`，rg 为 null |

### sg-rewrite (dry-run)

同 sg-search，额外字段：

| 字段 | 类型 | 说明 |
|------|------|------|
| replacement | string | 替换后的文本 |

### sg-rewrite (--apply)

| 字段 | 类型 | 说明 |
|------|------|------|
| applied | bool | `true` |
| file | string | 搜索路径 |
| changes | int | 变更数量 |

### sg-check

| 字段 | 类型 | 说明 |
|------|------|------|
| sg.installed | bool | ast-grep 是否安装 |
| sg.version | string | 版本号 |
| rg.installed | bool | ripgrep 是否安装 |
| rg.version | string | 版本号 |

## 错误恢复

| 场景 | 做法 |
|------|------|
| sg pattern 语法错误 | 简化 pattern 或用 `--kind` 替代 |
| sg 语言不支持（如 .nu） | 切换 `rg-search` |
| 无结果 | 尝试简化 pattern、切换引擎、添加 `--globs` |
| rewrite 没改文件 | 默认 dry-run，需加 `--apply` |
| rg exit 1 无 stderr | 正常无匹配，返回空列表 |

## 典型用法

```nu
# AST 搜索：找到所有 console.log 调用
sg-search "console.log($MSG)" --lang js --path ./src

# AST 搜索：YAML 规则
sg-search --rule rules/no-await-in-promise.yml --path ./src

# AST 搜索：按节点类型
sg-search --kind function_declaration --lang rust --path ./crates

# 重写预览（不修改文件）
sg-rewrite "oldApi($PARAM)" "newApi($PARAM)" --lang ts --path ./src

# 确认后应用
sg-rewrite "oldApi($PARAM)" "newApi($PARAM)" --lang ts --path ./src --apply

# 文本搜索
rg-search "TODO:" --path ./src --glob "*.ts"

# 查看支持语言
sg-langs

# 混合管道：sg + rg 结果合并后分析
let sg = (sg-search "fetch($URL)" --lang ts --path ./src)
let rg = (rg-search "fetch(" --path ./src --glob "*.ts")
$sg | append $rg | group-by file | to nuon
```

## 注意事项

- **sg line 是 0-based**，Nu 层已统一 +1 转为 1-based
- **rewrite 安全**：默认 dry-run 不修改任何文件，`--apply` 才真正写入
- **远程搜索**请使用 github skill 的 `gh-search-code`
- **语言陷阱**：`.tsx` 用 `Tsx` 非 `TypeScript`；`--globs`（sg）vs `--glob`（rg）；`.nu`/Dart/Zig/SQL 不支持 → 用 `rg-search`。→ 完整语言-扩展映射 + 陷阱见 [langs.md](references/langs.md)
- **`$history.N`**：见下方 `## $history 用法` 小节

## $history 与数据处理

通用规则见 browse SKILL.md 的 `## $history 用法`。

### 搜索结果是同构列表，直接管道操作

sg-search / rg-search 返回 `list<{engine, file, line, text, metavars}>`，可直接筛选：

```nu
# 赋值给变量（跨命令安全）
let result = (sg-search "$A && $B" --lang typescript --path sdk/src/)
$result | where file =~ 'twitter'

# 或 MCP 截断时赋值捕获完整结果
sg-search "$A && $B" --lang typescript --path sdk/src/
# 输出截断 → 第一条 evaluate 中赋值
let result = ($history.N)
$result | where engine == 'sg' | length
$result | where metavars != null | get metavars
```

→ 更多 Nu 分析模式（sg+rg 混合去重、metavar 聚合统计、按 file 分组热点定位）见 [patterns.md](references/patterns.md)。

## 模块结构

```text
astgrep/
  astgrep.nu    — 导出命令（sg-search/sg-rewrite/rg-search/sg-langs/sg-check）
  references/
    patterns.md — pattern 语法 / YAML rule / Nu 分析模式
    langs.md    — 语言-扩展映射表 + 语言陷阱
  SKILL.md      — 本文档
```
