Travsr-com/travsr-lang
GitHub: Travsr-com/travsr-lang
该项目为 Travsr 代码图谱工具提供基于 SCIP/LSIF 的多语言深度语义分析插件,支持按语言按需安装。
Stars: 1 | Forks: 0
# travsr-lang
[](https://github.com/Travsr-com/travsr-lang/actions/workflows/ci.yml)
[](https://github.com/Travsr-com/travsr-lang/actions/workflows/release.yml)
[](LICENSE)
## 背景
Travsr 为你的代码库构建一个图,并通过 MCP 将其提供出去,以便 AI agent 遍历其结构,而不是从文本块中进行猜测。它包含两个分析阶段:
**阶段 A**(内置于核心 `travsr` 二进制文件中)——通过 Tree-sitter 进行结构化解析。快速、零外部依赖,始终开启。为每种受支持的语言提供类、函数、方法和导入节点。
**阶段 B**(此仓库)——通过外部 LSIF/SCIP 工具进行深度语义分析。添加调用边、类型解析、跨模块引用和 go-to-definition 数据。需要安装外部工具,并根据 ADR-017 在沙盒子进程中运行。
阶段 B 可按语言和按代码库选择启用。只需安装你需要的内容。
## 可用语言包
所有 10 种外部语言都有可用的阶段 B 支持。通过 `travsr lang add ` 安装其中任何一个(参见[安装说明](#installation))。
| npm 包 | 语言 | 底层工具 | 沙盒 |
|---|---|---|---|
| `@travsr-plugin/go` | Go `.go` | `scip-go` | Standard |
| `@travsr-plugin/python` | Python `.py` | `scip-python` | Standard |
| `@travsr-plugin/ruby` | Ruby `.rb` | `scip-ruby` | Standard |
| `@travsr-plugin/php` | PHP `.php` | `scip-php` | Standard |
| `@travsr-plugin/cpp` | C++ `.cpp .cc .cxx .hpp` | `scip-clang` | Standard |
| `@travsr-plugin/c` | C `.c .h` | `scip-clang` | Standard |
| `@travsr-plugin/java` | Java `.java` | `scip-java` | **RequiresElevated** |
| `@travsr-plugin/kotlin` | Kotlin `.kt` | `scip-java` | **RequiresElevated** |
| `@travsr-plugin/csharp` | C# `.cs` | `scip-dotnet` | **RequiresElevated** |
| `@travsr-plugin/scala` | Scala `.scala` | `scip-scala` | **RequiresElevated** |
**沙盒类别:**
- **Standard** —— 无网络访问,无依赖下载。通过代码库信任授权启用。
- **RequiresElevated** —— 构建工具(Maven, Gradle, NuGet, sbt)在分析时下载依赖。需要代码库信任授权**并且**通过 `travsr lang approve` 获得明确的 PSE 签署同意(ADR-017 规则 1)。
## 安装说明
### 1. Standard 语言
```
# 安装语言包 — 这会安装 travsr-lang-* wrapper binary
# 并警告您底层工具是否仍然缺失。
travsr lang add go
travsr lang add python
travsr lang add php
travsr lang add ruby
travsr lang add cpp
travsr lang add c
```
如果 wrapper 不在 PATH 中,`travsr lang add` 会自动运行 `npm install -g @travsr-plugin/`。在 npm 安装之后,它会检查底层工具(`scip-go`、`scip-python` 等)是否也存在,如果不存在,则打印安装命令:
```
✓ @travsr-plugin/go installed.
Warning: scip-go not found on PATH.
Install it: go install github.com/sourcegraph/scip-go/cmd/scip-go@latest
Phase B for 'go' will be inactive until scip-go is installed.
✓ 'go' Phase B registered.
```
安装底层工具,然后运行 `travsr lang list` 以确认该语言达到 `✓ active` 状态。
### 2. RequiresElevated 语言(Java, Kotlin, C#, Scala)
这些语言需要它们的构建工具链在分析时运行(用于 Maven, Gradle, NuGet, sbt 的网络访问权限)。必须在 `travsr lang add` 接受它们之前记录 PSE 审批。
```
# 1. 首先记录 PSE 批准
travsr lang approve java \
--approved-by \
--reason "Maven resolution for acme/backend semantic analysis" \
--permitted-hosts repo1.maven.org,repo.maven.apache.org,plugins.gradle.org
# 2. 添加语言(安装 @travsr-plugin/java,警告关于 scip-java)
travsr lang add java
# 3. 安装底层工具
# 参见:https://github.com/sourcegraph/scip-java/releases
# 4. 为特定仓库激活
travsr lang add java --corpus github.com/acme/backend
```
### 3. 检查所有语言的状态
```
travsr lang list
```
```
LANGUAGE PACKAGE SANDBOX STATUS
--------------------------------------------------------------------------------
typescript @travsr-plugin/typescript Standard ✓ active
javascript @travsr-plugin/typescript Standard ✓ active
rust rustup component add... Standard ✓ active
go @travsr-plugin/go Standard ✓ active
python @travsr-plugin/python Standard wrapper-only (travsr-lang-python installed, scip-python missing — pip install scip-python)
java @travsr-plugin/java Elevated needs PSE approval (travsr lang approve)
kotlin @travsr-plugin/kotlin Elevated needs PSE approval (travsr lang approve)
scala @travsr-plugin/scala Elevated needs PSE approval (travsr lang approve)
ruby @travsr-plugin/ruby Standard not installed — npm install -g @travsr-plugin/ruby (experimental)
php @travsr-plugin/php Standard not installed — npm install -g @travsr-plugin/php
csharp @travsr-plugin/csharp Elevated needs PSE approval (travsr lang approve)
cpp @travsr-plugin/cpp Standard not installed — npm install -g @travsr-plugin/cpp (requires compile_commands.json)
c @travsr-plugin/c Standard not installed — npm install -g @travsr-plugin/c (requires compile_commands.json)
```
**三种状态:**
| 状态 | 含义 |
|---|---|
| `not-installed` | PATH 中既没有 `travsr-lang-*` wrapper,也没有底层工具 |
| `wrapper-only` | npm 包已安装,但缺少底层的 `scip-*` 工具 —— 请参见提示 |
| `✓ active` | wrapper 和工具都在 PATH 中,语言已注册,沙盒可用 |
## npm 包
每种语言都作为 `@travsr-plugin` scope 下的一个 npm 包分发。当你运行 `npm install -g @travsr-plugin/go` 时,一个 `postinstall` 脚本会:
1. 检测你的平台(`process.platform`)和架构(`process.arch`)
2. 解析匹配的预构建 Rust target triple
3. 从带标签的 GitHub Release 下载 `travsr-lang-go-{target}` 二进制文件
4. 下载相应的 `.sha256` 校验文件
5. 验证 SHA256 —— 如果哈希值不匹配则中止
6. 使用 `chmod 0o755` 将二进制文件写入 `/bin/travsr-lang-go`
7. npm 的 `bin` 字段将 `travsr-lang-go` 连接到你的 PATH 上
**受支持的平台:**
| 操作系统 | 架构 | Target |
|---|---|---|
| macOS | Intel (x64) | `x86_64-apple-darwin` |
| macOS | Apple Silicon (arm64) | `aarch64-apple-darwin` |
| Linux | x86_64 | `x86_64-unknown-linux-gnu` |
| Linux | arm64 | `aarch64-unknown-linux-gnu` |
| Windows | 任意 | 不支持 —— 阶段 B 不可用(优雅退出)|
## 架构
### 工作原理
此仓库中的每个 crate 都是一个最小化的 Rust 二进制文件,它使用 Travsr 插件协议(通过 stdin/stdout 进行带有长度前缀的 JSON 传输,定义于 `travsr-plugin-protocol`)。
当 `travsr lang add ` 注册一个包时,Travsr daemon 会:
1. 在 `~/.travsr/lang.toml` 中记录该二进制文件
2. 在每次 `init` 或 commit-hook 运行时,通过 `CatalogResolver` 解析该二进制文件(检查 PATH 上的 `travsr-lang-`)
3. 将其作为**沙盒子进程**生成(ADR-017 `SandboxPolicy::Standard` 或 `Elevated`)
4. 发送 `InvokeRequest { root, corpus }` —— 二进制文件运行外部工具,解析 SCIP 输出,并返回 `InvokeResponse { nodes, edges }`
5. daemon 将这些节点和边合并到图中,归属于 `corpus`
沙盒强制执行:无网络(Standard),只读代码库根目录,只写临时 scratch tmpdir,清洗环境变量(仅保留 `PATH`, `LANG`, `LC_ALL`, `TMPDIR`),限制 CPU/RAM/运行时间。
### 协议
所有包共享来自 `travsr-plugin-sdk` 的相同通信协议:
```
daemon stdin → HandshakeRequest → InvokeRequest { root, corpus }
daemon stdout ← HandshakeResponse ← InvokeResponse { nodes, edges }
```
组帧:4 字节大端序长度前缀 + JSON payload。版本不匹配会在握手时被捕获 —— daemon 会拒绝其不支持 `protocol_version` 的二进制文件。
### 依赖项
每个包仅依赖于已发布的 crate —— 没有 `[patch.crates-io]` 或本地路径 hack:
```
[dependencies]
travsr-plugin-sdk = "0.7.0"
travsr-core = "0.7.0"
```
## 发布流水线
发布过程是完全自动化的。推送一个 semver 标签以触发跨平台构建和 npm 发布:
```
git tag v0.1.0
git push origin v0.1.0
```
发布工作流(`.github/workflows/release.yml`)运行三个作业:
1. **`create-release`** —— 立即创建 GitHub Release
2. **`build`(4 个并行作业)** —— 为每个 target 构建所有 10 个 `travsr-lang-*` 二进制文件,剥离它们,计算 SHA256,并向 release 上传 40 个文件(10 个二进制文件 + 10 个 `.sha256` 校验文件)
3. **`publish-npm`** —— 在所有构建完成后,根据 git 标签提升每个 `package.json` 的版本,并使用 `--access public` 将所有 10 个 `@travsr-plugin/` 包发布到 npm
## 添加语言
为新语言添加阶段 B 支持需要在此仓库和核心 travsr 仓库中进行更改。
### 1. 创建 crate
```
mkdir -p crates//src
```
**`crates//Cargo.toml`:**
```
[package]
name = "travsr-lang-"
description = "Travsr Phase B — semantic analysis via "
version.workspace = true
edition.workspace = true
license.workspace = true
authors.workspace = true
repository.workspace = true
rust-version.workspace = true
[[bin]]
name = "travsr-lang-"
path = "src/main.rs"
[dependencies]
travsr-plugin-sdk = { workspace = true }
travsr-lang-scip-reader = { workspace = true } # if using SCIP output
anyhow = { workspace = true }
tracing = { workspace = true }
tracing-subscriber = { workspace = true }
```
**`crates//src/main.rs`:**
```
use travsr_plugin_sdk::{
run_plugin, InvokeRequest, InvokeResponse, ParseRequest, ParseResponse, Plugin,
};
use travsr_core::Language;
struct MyLangPhaseB;
impl Plugin for MyLangPhaseB {
fn language(&self) -> Language { Language:: }
fn extensions(&self) -> &[&str] { &["ext"] }
fn supports_phase_b(&self) -> bool { tool_available() }
fn parse(&self, _req: &ParseRequest) -> ParseResponse {
// Phase A is handled by the core daemon — this binary is Phase B only.
ParseResponse::default()
}
fn invoke_phase_b(&self, req: &InvokeRequest) -> InvokeResponse {
match run_tool(&req.root, req.corpus.as_str()) {
Ok(resp) => resp,
Err(e) => {
tracing::warn!("tool failed: {e}");
InvokeResponse::default()
}
}
}
}
fn main() {
tracing_subscriber::fmt().init();
run_plugin(MyLangPhaseB);
}
```
### 2. 添加 npm 包
创建 `npm//package.json` 和 `npm//.gitignore`:
```
{
"name": "@travsr-plugin/",
"version": "0.1.0",
"description": "Travsr Phase B — semantic analysis (travsr-lang- binary)",
"license": "MIT",
"repository": { "type": "git", "url": "https://github.com/Travsr-com/travsr-lang" },
"scripts": { "postinstall": "node postinstall.js" },
"bin": { "travsr-lang-": "./bin/travsr-lang-" },
"publishConfig": { "access": "public" },
"engines": { "node": ">=16" }
}
```
```
# npm//.gitignore
bin/
```
共享的 `npm/postinstall.js` 会在发布时由发布工作流复制到每个包目录中 —— 源码树中不需要每个包单独的 postinstall.js。
### 3. 在核心仓库中添加目录条目
在 [travsr](https://github.com/Travsr-com/travsr) 仓库中打开 `crates/travsr-plugin-host/src/phase_b/catalog.rs` 并添加一个 `PhaseBEntry`:
```
PhaseBEntry {
language: "",
npm_package: Some("@travsr-plugin/"),
command: "",
args: &["{root}", "--output", "{output}"],
output_format: OutputFormat::Scip, // or Lsif
sandbox: SandboxRequirement::Standard, // or RequiresElevated
install_hint: "npm install -g @travsr-plugin/",
underlying_tool_hint: "",
provider_binary: Some("travsr-lang-"),
elevated_hosts: &[], // fill for RequiresElevated
},
```
将语言二进制文件添加到 `.github/workflows/release.yml` 的构建矩阵中(`build` 和 `publish-npm` 作业中的 `BINS` 数组)。
### 4. 提交一个 PR
- CI 会运行 `cargo fmt`, `cargo clippy`, `cargo check`, `cargo test`
- 包含至少一个在小型 fixture 上调用 `invoke_phase_b` 的集成测试
## 仓库结构
```
travsr-lang/
├── .github/
│ └── workflows/
│ ├── ci.yml ← fmt + clippy + check + test on every PR
│ └── release.yml ← cross-platform build + npm publish on v* tags
├── Cargo.toml ← workspace root (travsr-plugin-sdk = "0.7.0")
├── README.md
├── npm/
│ ├── postinstall.js ← shared download/SHA256-verify/install script
│ ├── go/ ← @travsr-plugin/go
│ ├── python/ ← @travsr-plugin/python
│ ├── java/ ← @travsr-plugin/java
│ ├── kotlin/ ← @travsr-plugin/kotlin
│ ├── scala/ ← @travsr-plugin/scala
│ ├── ruby/ ← @travsr-plugin/ruby
│ ├── php/ ← @travsr-plugin/php
│ ├── csharp/ ← @travsr-plugin/csharp
│ ├── cpp/ ← @travsr-plugin/cpp
│ └── c/ ← @travsr-plugin/c
└── crates/
├── scip-reader/ ← shared SCIP binary-format ingestion library
├── go/ ← Go (scip-go) · Standard
├── python/ ← Python (scip-python) · Standard
├── php/ ← PHP (scip-php) · Standard
├── ruby/ ← Ruby (scip-ruby) · Standard
├── java/ ← Java (scip-java) · RequiresElevated
├── kotlin/ ← Kotlin (scip-java) · RequiresElevated
├── csharp/ ← C# (scip-dotnet) · RequiresElevated
├── scala/ ← Scala (scip-scala) · RequiresElevated
├── cpp/ ← C++ (scip-clang) · Standard
└── c/ ← C (scip-clang) · Standard
```
## 版本兼容性
| travsr-lang | travsr-plugin-sdk | travsr-core | 协议版本 |
|---|---|---|---|
| 0.1.x | 0.7.0 | 0.7.0 | 1 |
插件协议版本会在握手时检查。如果 daemon 和包的版本不兼容,该二进制文件在注册时会被拒绝并给出明确的错误 —— 绝不会悄无声息地发生不匹配。
## 开发
```
# 构建所有包
cargo build --workspace
# 检查所有包
cargo check --workspace
# 运行测试
cargo test --workspace
# 格式化
cargo fmt --all
# Lint
cargo clippy --all-targets -- -D warnings
```
## 安全性
阶段 B 包在由 Travsr daemon 强制执行的操作系统级沙盒中运行(ADR-017):
- **网络:** 完全拒绝(Standard)或限制为明确的 host 允许列表(Elevated,需要 PSE 签署同意)
- **文件系统:** 代码库根目录是只读的;每次调用的临时 scratch tmpdir 是唯一可写的路径;所有其他路径均被拒绝
- **环境:** 仅传入 `PATH`, `LANG`, `LC_ALL`, `TMPDIR` —— 没有任何机密、token、SSH 密钥或云凭证
- **资源:** 强制执行 CPU、RAM 和运行时间限制;超过运行时间上限的插件将被终止
如果宿主机上不可用沙盒机制(Linux 上的 `bwrap`,macOS 上的 `sandbox-exec`),该语言将被**完全禁用** —— 它绝不会在退而求其次的情况下进行无沙盒运行(ADR-017 规则 2:fail-closed)。
有关完整的安全策略,请参见 [ADR-017](https://github.com/Travsr-com/travsr/blob/master/docs/adrs/ADR-017-unified-plugin-sandbox-trust.md)。
## 许可证
MIT —— 参见 [LICENSE](LICENSE)。
[Travsr](https://travsr.com) 项目的一部分。
标签:AI辅助编程, LSIF, SCIP, 代码分析, 代码索引, 凭证管理, 可视化界面, 插件, 暗色界面, 通知系统