# 多 Shell 后端方案：tree-sitter 接入与 PowerShell 支持

> **现状注记（2026-09-13）**：本文是早期设计草案，其中「bash 暂保留
> just-bash、仅 pwsh 用 tree-sitter」的共存方案已被取代——bash 后端已完成
> just-bash → tree-sitter-bash（CST）迁移，运行时依赖收敛到 web-tree-sitter
> 单包（wasm 随共享核心 ast-guard-core 发布），核心解析/意图/策略代码已提取
> 到独立仓库 ast-guard-core（pi 与 dsh 共用）。本文其余部分仅作设计背景保留。

状态：草案（待评审）
作者：—
日期：—

## 1. 背景与现状

### 1.1 当前解析架构

本项目**不是手写 bash 解析器**。语法层使用第三方库 `just-bash`（v2.14.5，纯 TS，提供完整类型化 AST），手写的是语义分析层：

| 层 | 文件 | 内容 |
| --- | --- | --- |
| 语法层（第三方） | `just-bash` | `ScriptNode → StatementNode → PipelineNode → CommandNode → WordNode` 类型化 AST，word 内细分为 `Literal / SingleQuoted / DoubleQuoted / Escaped / TildeExpansion / ParameterExpansion / CommandSubstitution / ProcessSubstitution` 等判别联合 |
| 语义分析（手写） | `src/bash/analyze.ts`（770 行） | 遍历 AST → `CommandInvocation`/`PipelineInvocation`：argv、重定向、stdin/stdout、子进程边界链、静态变量追踪、函数展开、`bash -c`/`eval`/`exec` 嵌套解析 |
| Word 渲染（手写） | `src/bash/words.ts`（64 行） | word → `ShellWordValue`（dynamic/quoted/text + alternatives） |

入口：`src/engine/evaluate.ts` 调用 `analyzeBash(input.script)`，消费 `BashAnalysis` 结果。

### 1.2 本方案的动机

- **支持 pwsh**：没有 "just-powershell" 之类的类型化解析器等价物；PowerShell 语法规模庞大，手写解析器不现实。`tree-sitter-powershell` 是支持 pwsh 唯一现实的统一路线。
- **统一引擎**：tree-sitter 一套运行时 + 多语言 grammar（bash / powershell / zsh），可复用一个分析框架。
- **健壮性**：`tree-sitter-bash` 被 GitHub 等大厂使用，边界情况覆盖优于 just-bash；且错误容忍（产生 ERROR 节点仍可部分遍历）。

### 1.3 非目标（明确不做）

- **不为 bash 本身换解析器**：just-bash 工作正常、类型安全、407 个测试全过。本方案中 bash 后端保持 just-bash，直到其暴露出解析缺陷。
- **不追求 100% 语义等价**：多语言分析采用"保守近似"（over-approximation）原则，与现有 `walkStatement` 短路处理、if/while/case 分支全遍历的设计哲学一致——安全工具多拦截优于漏拦截。
- **不做 PowerShell 解释器/求值**：只做静态命令提取与危险操作识别。

## 2. 目标架构

### 2.1 分层

```
engine/evaluate.ts          ← 策略评估入口（不变）
        │
        ▼
shell/ (新抽象层，语言无关)
  types.ts                  ← 语言无关分析模型（从 src/bash/types.ts 提炼）
  interface.ts              ← ShellBackend 接口：parse(script) → ShellAnalysis
        │
        ├── backends/bash-justbash.ts   ← 现有 src/bash/* 封装（语法层 = just-bash）
        └── backends/pwsh-treesitter.ts ← 新增（语法层 = tree-sitter-powershell）
```

要点：

1. `CommandInvocation`（argv / redirections / stdin / stdout / boundaryPath）**已基本是 shell 无关模型**，作为抽象层的基础。
2. `engine/evaluate.ts` 与策略层只依赖语言无关接口，不感知后端差异。
3. bash 先保留 just-bash 后端，pwsh 用 tree-sitter 后端；两个后端共存于同一接口下。日后若需迁移 bash 到 tree-sitter-bash，只新增一个后端，不动引擎。

### 2.2 语言无关分析模型（草案）

从现有 `src/bash/types.ts` 提炼，需参数化 bash 特有概念：

```ts
export type ShellLanguage = "bash" | "powershell";

export interface ShellAnalysis {
  language: ShellLanguage;
  commands: CommandInvocation[];
  pipelines: PipelineInvocation[];
  parseError?: string;
}

export type CommandSource =
  | "top-level"
  | "compound"
  | "subshell"          // bash: ( ) ; pwsh: 无对应（脚本块不等价）
  | "background"
  | "command-substitution"
  | "process-substitution"
  | "shell-c"           // bash -c / pwsh -Command
  | "eval"              // bash eval / pwsh Invoke-Expression (iex)
  | "exec"              // bash exec / pwsh 无对应（. 点源为 dot-source）
  | "dot-source"        // pwsh: . script.ps1（新 shell 领域）
  | "function";
```

需要讨论的差异点（详见 §5）：

- **heredoc / here-string**：bash 的 `<<` heredoc 与 pwsh 的 `@'...'@` here-string 形态不同，但都可映射到 `kind: "heredoc"`。
- **管道与 stderr**：pwsh 管道传对象而非字节流，`2>&1 |` 语义不同；`|&` 是 bash 专有。
- **`&&` / `||`**：pwsh 7+ 支持，语义与 bash 一致，可在 Statement 层复用。
- **变量**：`$var` vs `${var}`，参数展开操作符（`${x:-y}` 等）为 bash 专有，pwsh 用 `$PSDefaultParameterValues` 等不同机制。

## 3. tree-sitter 技术方案

### 3.1 依赖选型

| 依赖 | 用途 | 备注 |
| --- | --- | --- |
| `web-tree-sitter` | WASM 运行时 | Node 环境可用，异步初始化 |
| `tree-sitter-powershell` grammar（wharflab） | pwsh 语法 | VS Code 正在迁移采纳，成熟度可用 |
| （可选）`tree-sitter-bash` grammar | 未来 bash 迁移 | 本方案暂不引入 |

### 3.2 运行时资产

tree-sitter 需要为每个语言打包 `.wasm` grammar 文件：

```
src/shell/grammars/
  tree-sitter-powershell.wasm
  （未来）tree-sitter-bash.wasm
```

- 需要把 `.wasm` 纳入 `package.json` 的 `files` 发布白名单。
- 初始化是异步的（`await Parser.init()` / `Language.load()`），需要设计懒加载单例，避免每次分析重复初始化。
- 这是一个相对 just-bash（纯 TS、同步、零资产）的退步点，需在文档与性能基准中明确记录。

### 3.3 无类型 CST 的处理策略

just-bash 的判别联合（如 `part.type === "ParameterExpansion" && part.operation.type === "PatternReplacement"`）是 analyze.ts / words.ts 大量逻辑的骨架。tree-sitter 只有 `SyntaxNode` + 字符串 node type，需要：

1. **类型守卫层**：为常用 CST 节点写 `isX(node)` 守卫（如 `isSimpleCommand`、`isRedirectedStatement`），把字符串分派收敛到守卫层，业务逻辑保持类型化。
2. **word 渲染重写**：`words.ts` 需基于 CST 形态重建（bash 的 `simple_expansion` / `command_substitution` 等节点，pwsh 的 `variable_expression` / `command_expression` 等）。
3. **语义需自建**：CST 不区分 heredoc/here-string/文件重定向（都是 `redirected_statement`），`2>&1 |` 的 stderr 入管道、`~user`、`${var:...}` 等现有语义要在 walk 里重新解释。

## 4. 实施步骤（Roadmap）

### Phase 1：抽象层落地（不动引擎行为）

1. 新建 `src/shell/types.ts`，从 `src/bash/types.ts` 提炼语言无关模型（`ShellLanguage`、`ShellAnalysis`、参数化的 `CommandSource`）。
2. 定义 `ShellBackend` 接口：`parse(script): ShellAnalysis`。
3. 将现有 `src/bash/*` 封装为 `backends/bash-justbash.ts`，输出语言无关模型。
4. 更新 `engine/evaluate.ts` 调用新接口。
5. **验收**：全部 407 个测试原样通过，行为零变化。

### Phase 2：tree-sitter 脚手架（✅ 已落地，commit `1a8bc41` 后）

1. 引入 `web-tree-sitter` + `tree-sitter-bash`，打包 `.wasm` 资产（随 npm 包发布，`require.resolve` 定位）。
2. 懒加载单例：`src/shell/treesitter.ts` 的 `getParser(language)` 缓存初始化结果。
3. 用 `tree-sitter-bash` 做对拍基准：`tests/shell/treesitter.crosscheck.test.ts`，同一脚本下 tree-sitter CST 与 just-bash AST 的命令提取一致性测试（仅用于脚手架验证，不切换后端）。
4. 对拍发现的已知分歧：just-bash 不支持进程替换 `<( )`（抛 `ParseException`），tree-sitter 支持。
5. 暂不引入 `tree-sitter-powershell`（用户约束：先不引入 pwsh）。

### Phase 3：pwsh 后端（✅ 已落地）

1. `src/shell/pwsh.ts`：tree-sitter-powershell CST walk → 语言无关模型（命令名小写化、动态性判定、重定向 fd/管道、iex 静态负载递归解析、parseError 兜底）。同步扩展 `src/shell/types.ts` 的 `CommandSource`（call-operator/dot-source/scriptblock/subexpression/invoke-expression）并导出 `ShellLanguage`。
2. 引擎集成：`src/shell/detect.ts` 启发式语言检测（cmdlet 模式 + pwsh 专属标记），`engine/evaluate.ts` 按检测结果选后端，`subject` = 检测语言；命令名/参数匹配大小写不敏感；`index.ts` 会话初始化预热 pwsh 解析器（`ensurePowerShellReady`）。
3. 文件意图：`src/intents/files.ts` 支持 pwsh 文件命令（get-content/get-childitem/remove-item/set-content/add-content/out-file/clear-content/move-item/copy-item）与 `Set-Location` cd 追踪。
4. 规则：`config/default-policy.yaml` 新增 pwsh 规则（pwsh-remove-item / pwsh-remove-item-dynamic / pwsh-invoke-expression / pwsh-clear-content / pwsh-start-process），`src/i18n.ts` 补中文 reason。
5. **验收**：新增 32 个测试（pwsh 后端单测 / 语言检测 / 引擎集成），全量 check 绿（25 文件 / 439 测试）。

注意：`settings.language` 实为 UI 语言（非脚本语言），脚本语言由检测器自动判定。

### Phase 4（可选，未来）

- 若 just-bash 暴露解析缺陷，按同一接口新增 `backends/bash-treesitter.ts` 替换。

## 5. 风险与开放问题

| # | 问题 | 影响 | 建议 |
| --- | --- | --- | --- |
| 1 | `.wasm` 资产增大包体、异步初始化 | 扩展安装/首次分析变慢 | 懒加载 + 文档记录；bench 对比 |
| 2 | pwsh 管道对象语义与 bash 字节流不同 | 管道相关规则（stderrToPipe 等）语义需重审 | Phase 3 单独设计，不强行复用 |
| 3 | 无类型 CST 增加走查代码量 | 维护成本 | 类型守卫层收敛字符串分派 |
| 4 | pwsh grammar 的 ERROR 节点覆盖 | 解析失败兜底路径 | 复用现有 `parseFailure: ask` 策略 |
| 5 | PowerShell 内联 C# / COM 调用 | 危险操作识别盲区 | 首版保守：识别为 dynamic / 询问 |

## 6. 验收标准

- Phase 1 完成时：407 个测试零改动通过（行为兼容）。
- Phase 3 完成时：
  - `bun run check` 全绿；
  - pwsh 测试套件覆盖：命令提取、危险操作拦截、动态参数、`iex`/`&` 调用运算符、解析失败兜底；
  - bench 报告 tree-sitter 初始化与单次分析耗时，与 just-bash 对比有记录。

## 7. 参考资料

- `tree-sitter-powershell`（wharflab）：https://github.com/wharflab/tree-sitter-powershell
- `web-tree-sitter`：https://github.com/tree-sitter/tree-sitter/tree/master/lib/binding_web
- 现状代码：`src/bash/analyze.ts`、`src/bash/words.ts`、`src/bash/types.ts`、`src/engine/evaluate.ts`
