Travsr-com/travsr-lang

GitHub: Travsr-com/travsr-lang

该项目为 Travsr 代码图谱工具提供基于 SCIP/LSIF 的多语言深度语义分析插件,支持按语言按需安装。

Stars: 1 | Forks: 0

# travsr-lang [![CI](https://static.pigsec.cn/wp-content/uploads/repos/cas/39/39faa54be350a1dab8afd3b2fb8c1c83e4d9cff84abfef2374d19a18053687c4.svg)](https://github.com/Travsr-com/travsr-lang/actions/workflows/ci.yml) [![Release](https://static.pigsec.cn/wp-content/uploads/repos/cas/b1/b1ec6734607356de5e66298dcbb11c80f5768f551f256bc24acd405b659ced1e.svg)](https://github.com/Travsr-com/travsr-lang/actions/workflows/release.yml) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](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, 代码分析, 代码索引, 凭证管理, 可视化界面, 插件, 暗色界面, 通知系统