mcpField
Z
zzop

zzop

本地服务
eezz4.github.io开发工具06 天前更新

关于 zzop

zzop 是面向编码 Agent 和开发者的确定性代码库分析引擎。它梳理代码结构并关联前端调用与后端路由,输出可重复的 JSON 结果,且不发起网络请求。

主要功能

  1. 01分析 TypeScript、JavaScript、Python、Java、C#、Go 和 Rust
  2. 02关联前端调用与后端路由
  3. 03识别风险、死代码和重构目标
  4. 04输出可重复的 JSON 结果
  5. 05通过 MCP 服务或 CLI 运行
  6. 06提供编写配置所需的契约资源

适用场景

  1. 01为编码 Agent 提供代码库概览
  2. 02查找未命中后端路由的前端调用
  3. 03在 CI 中运行带严重性门槛的检查

MCP 相关

`zzop-mcp` 二进制通过 stdio 向 MCP 客户端提供分析工具和 `zzop://contract/*` 资源。它与 CLI 使用相同的引擎和处理程序。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

暂未收录安装方式

我们还没有获取到这个服务的安装包或远程地址,请按项目 README 中的说明安装。

代码仓库
安装包
mcpbzzop-mcp-win32-x64-msvc.mcpb0.40.0
mcpbzzop-mcp-darwin-x64.mcpb0.40.0
mcpbzzop-mcp-darwin-arm64.mcpb0.40.0
mcpbzzop-mcp-linux-x64-gnu.mcpb0.40.0
mcpbzzop-mcp-linux-arm64-gnu.mcpb0.40.0

工具

还没有获取到工具列表

本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。

详细介绍

zzop(零痛点区)

CI npm License: MIT

你的 AI 编码 Agent 无法读取整个代码库。zzop 会读取它,并且每次都以同样的方式给出答案。

它会解析 TypeScript/JavaScript、Python、Java、C#、Go 和 Rust,以及 Prisma 和 SQL 架构。其他任何语言的文件只能通过指定其扩展名的逐行扫描规则来处理——对大多数语言来说,没有这样的规则;请参阅支持的语言。

让 zzop 分析一个代码库,或同时分析你的前端和后端,它会返回一份 JSON 文档,描述代码库中的实际情况:哪些前端调用能到达哪些后端路由,哪些调用无处可达;哪些地方看起来有风险,哪些代码已经无用,应该先从哪里开始重构,以及本次运行无法看到什么。Agent 会以此为起点,而不是根据少数几个有空间打开的文件来猜测。

zzop 不会编写代码。它让代码生成器据以工作的理解准确且可重复——输入相同的提交,输出逐字节相同的发现——因此 Agent 编写的内容依据的是代码的实际行为,而不是从片面读取中推断出的结果。要改进的是理解,而不是能力。

看它如何发现问题

**中断一条路由**展示了其中一种关联轴,只需一次改动——这是此工具报告的四种关联之一,也是最难通过其他方式发现的一种:在一对没有共享代码和类型的前后端项目中,重命名一个后端路由。前端仍然可以编译,测试也仍然通过——而 zzop 会指出中断两端的文件和行号(此处为精简版;演示页面展示了运行结果的原始格式):

=== unprovided consumes ===
  "PUT /api/user"      @ fe-vite     src/pages/Settings.jsx:19    ← the call now hits nothing

=== unconsumed provides ===
  "PUT /api/users/me"  @ be-express  src/app/routes/auth/auth.controller.ts:61   ← the route nobody calls

几秒钟就能运行这个演示,使用本仓库自带的一对项目,无需下载任何内容——演示项目已提交在这里,克隆本仓库即可获取:

git clone https://github.com/eezz4/zzop && cd zzop
bash docs/demo/break-a-route-shipped.sh    # needs a zzop binary and node, nothing else

该脚本会在 target/release/ 中查找二进制文件,或查找 PATH 上的任意 zzop;如果两处都找不到,它会告诉你如何获取一个。它会分析临时副本,不会修改 docs/demo/pair/。

脚本会在每个步骤断言关联状态,而不是打印状态,因此一旦某个说法不再成立,脚本就会失败,而不是继续讲述。CI 会在推送到 main 时以及拉取请求中运行此脚本;在开发分支上,负责检查它的流程是 scripts/ci-local.sh。

该页面本身是对同一改动的讲解式演练,展示在两个独立编写的代码库上:每条命令及其输出都完整写出,因此无需运行任何内容,也能从头到尾读完。页面背后的脚本 docs/demo/break-a-route.sh 是维护者工具,而非首次运行命令——它会构建一个 cargo 示例(因此需要源码检出版本,而非已发布的二进制文件),并分析你在 corpus/oss/fe-vite 和 corpus/oss/be-express 提供的两个代码库。corpus/oss/ 已被 git 忽略,本仓库不会附带这些目录——它们是第三方代码库检出内容,我们无权重新分发;请参阅 CONTRIBUTING.md,了解如何使用你自己的语料库。(我们确实编写的合成语料库已提交在 cases/ 中——其中只有一个文件例外:一个必须包含有效供应商令牌字面量的 fixture,因此完全无法提交;其 README 说明了这对基准分数的影响。)

你需要哪一个二进制文件?

zzop 提供两个无需 Node 的二进制文件。安装前,请先决定需要哪一个:

如果你想要使用使用方式
让 AI Agent(Claude Code、Claude Desktop、任何 MCP 客户端)回答有关代码仓库的问题zzop-mcp — 一个基于 stdio 的 MCP 服务安装插件或 .mcpb 捆绑包,然后由 Agent 调用工具。你无需运行任何命令。→ 在 Claude Code 中使用
自行运行分析 — 在终端、CI 任务或脚本中zzop — 一个普通的 CLI每棵目录树运行一次 zzop init,然后运行 zzop analyze . 或 zzop cross --config …。JSON 输出到 stdout。→ 在终端或 CI 中使用

两个二进制文件都会通过同一引擎调用相同的共享处理程序,因此,针对同一路径的工具调用和 CLI 运行会给出相同的结果。两者都不会发起任何网络请求 — 它们完全不依赖 HTTP(隐私)。

快速开始

两个二进制文件都不需要 Node.js、npm 或编译器。可通过以下四种方式之一获取:

  • 下载二进制文件。 从 GitHub Releases 下载适用于你平台的 zzop-cli-<platform>[.exe](CLI)和/或 zzop-mcp-<platform>[.exe](MCP 服务)资源,然后直接运行,或将它们放到 PATH 中。每个版本还包含一个 SHA256SUMS 资源,其中列出了所有这些资源的校验和。⚠ 较旧的固定版本可能根本没有可下载的发布版本——请查看 VERSIONING.md 中的 Breaking in the current 0.x,它是唯一说明哪些标签包含资源的文档;没有资源的版本需要从源代码构建。(本句曾写着资源“从 v0.30.0 起”提供,并建议你检查较旧的固定版本。这两部分都写于 2026-09-23 历史记录重写之前,之后都不再成立:对于 v0.30.0 到 v0.34.0 之间的标签,没什么可检查的,因为发布版本本身已不存在。)使用 sha256sum -c SHA256SUMS --ignore-missing 验证;如果 macOS 设备上没有 sha256sum,则使用 shasum -a 256 -c SHA256SUMS --ignore-missing。其作用范围有限,但值得说明:它可以检测下载文件是否损坏,也为通过其他渠道获取摘要的人提供验证方式。它无法防范发布源遭到入侵——能够替换资源的攻击者也能同时替换旁边的 SHA256SUMS——而 TLS 已能阻止中间人攻击。 各平台实际经过验证的内容有所不同,选择平台前值得了解这一点。 测试套件仅在 Linux x64 上运行。每个发布版本的构建都会通过运行 version 并与清单比对来进行冒烟测试,测试平台包括 Windows x64、macOS arm64 和 Linux x64;两个交叉编译目标(macOS x64、Linux arm64)无法在构建它们的运行器上执行,因此完全不会进行冒烟测试。因此,在 macOS 和 Windows 上,已验证的只有二进制文件能够加载和链接;分析行为则已在 Linux 上验证,并假定在其他平台上也成立。引擎没有平台专属的代码路径,只有一个例外,因此这一假设是合理的,但并非承诺。值得指出这个例外,因为它最不适合用该假设来涵盖:crates/summary/src/siblings.rs 会在 Windows 上以不区分大小写的方式折叠目录名称,否则不区分大小写的文件系统可能会把你已分析的根目录报告为自身尚未分析的同级目录。这个大小写折叠的 Windows 分支在任何地方都没有执行过:测试套件在 Linux 上运行,不会进入该分支;开发者的 Mac 也无法测试另一分支,因为 APFS 默认不区分大小写,测试会因此自行跳过。源码在跳过提示中说明了这一点。复核方式:git grep -nE 'cfg!?\(\s*(not\()?\s*(windows|unix|target_os|target_family)' -- 'crates/**/*.rs' 'parser/**/*.rs' 'rules/**/*.rs' 'packages/**/*.rs'。
  • Claude Code 插件。 依次运行 /plugin marketplace add eezz4/zzop 和 /plugin install zzop@zzop——请参阅下文的 在 Claude Code 中使用。(Windows:安装钩子需要 POSIX shell——官方支持的方式是使用 Git for Windows;详情请参阅 packages/README.md。)
  • Claude Desktop。 一键式 .mcpb 捆绑包(拖放安装)——安装前安装程序应了解的信息(更新需要手动进行;在 macOS 上,无签名二进制文件会触发 Gatekeeper;隐私声明)请参阅 packages/mcpb/BUNDLE-README.md——v0.32.0 之后发布的捆绑包会将该文件作为自身的 README;v0.32.0 及更早版本的捆绑包则不包含该文件,这正是这里提供安装前指引的原因。 打包详情:packages/mcpb/README.md。
  • npm。 npm i -g @zzop/cli 会安装上文完全相同的 zzop 二进制文件,并作为 npm 依赖为你的平台下载——zzop help 列出的每个子命令,其输出都逐字节相同;除了一个微型启动脚本外,不需要 Node 运行时,也没有可能与原生二进制文件产生差异的独立 JS 实现。如果项目已通过 npm 管理工具链,这种方式很方便。请参阅 packages/cli/README.md。

在 Claude Code 中使用(MCP 插件)

面向 Agent 的使用方式。zzop-mcp 是一个内置 MCP 服务的独立二进制文件;安装一次后,就可以用自然语言提问,由 Agent 选择工具。

  1. /plugin marketplace add eezz4/zzop — 然后运行 /plugin install zzop@zzop(分为两个独立步骤)。
  2. 开始一个新会话。插件会在首次运行时下载适用于你平台的二进制文件;不会将其放入 PATH。首次会话不会列出 zzop 工具——工具列表会在下载完成前确定——因此请重启一次 Claude Code,工具就会出现(钩子也会在 stdout 中提示这一点)。安装完成后,如果有更新版本,会通知你,不会在你不知情的情况下安装。

该服务提供 analyze_repo、cross_repo、check_file、check_endpoint、check_coverage、module_map、analyze_envelope、validate_envelope、validate_rule_pack 这些工具,以及承载编写约定的 zzop://contract/* 资源(包括 envelope schema、DSL 参考、规则目录、配置项和带注释的入门配置),因此只需二进制文件即可编写适配器或规则包。zzop-mcp 本身不接受分析子命令:直接运行或使用 mcp 会提供 stdio 服务,其他形式只有 version/help。

完整的安装、工具和资源参考见 packages/README.md,准确的参数格式见 docs/modules/mcp.md。

在终端或 CI 中使用(zzop CLI)

面向用户的使用方式。编写 zzop.config.jsonc 并运行,类似 ESLint。必须提供配置——两个二进制文件的每种分析方式都会拒绝分析没有配置的目录,因为否则 zzop 会猜测项目相关名称(例如你如何称呼身份验证守卫、哪些横幅标记生成的文件),而这些都应写在该文件中;你未声明的键不是 zzop 会擅自做出的判断:

zzop init                               # write the starter config — do this first, once per tree
zzop analyze .                          # analyze one repo/tree -> JSON findings summary
zzop analyze --config ci/zzop.config.jsonc   # same, for a config that does not sit at the tree root
zzop analyze . --severity critical --limit 10  # narrow the findings LIST (counts always cover everything)
zzop cross --config zzop.config.jsonc   # cross-layer join, driven by that config
zzop analyze . --fail-on critical       # THE CI GATE: exit 3 when anything at/above that severity exists
zzop <subcommand> --help                # that one subcommand's own line (exit 0); `zzop help` prints them all

zzop --help 是规范的子命令列表——本 README 不会重复列出。

除非另有指定,否则退出代码为 0。 如果不使用 --fail-on,运行结果只回答“zzop 是否运行”,因此即使目录中全是严重问题,退出代码仍为 0;使用该选项后,达到或超过指定严重级别的问题会使退出代码变为 3(第三种代码,因此 CI 日志可以区分配置错误 1 和实际发现的问题),但完整回复仍会输出到 stdout。请检查你的构建实际会如何处理,而不要只看这段说明: zzop analyze . --fail-on critical; echo $?。完整的退出代码表(包括 --rule ID 无法匹配时返回的 2)见 docs/getting-started.md。

运行会在分析的目录中写入文件。 首次分析会在配置文件旁创建 .zzop/cache/(默认的 cacheDir),并在其中保存每个文件的分析缓存——这些纯粹是派生状态,可以安全删除,下次运行时会重新生成;缓存会随着目录增长,而不是一直保持很小(可用 du -sh .zzop 测量;本仓库自身的缓存大小不值得在此列出,因为它会随每次运行而变化)。zzop init 会自动在该目录的 .gitignore 中添加锚定的 **/.zzop/ 行;设置 "cacheDir": null 则不会写入任何内容。

若要持续跟踪约定的变化,而不是只查看某一时刻的状态,请提交一份结构清单,并与之后的运行结果进行差异比较——其结构与 lint 基线文件相同,由你自行维护,而不是由 zzop 维护:

zzop manifest ./api ./web > contracts.json   # identity only: provides/edges/bucket membership
zzop diff contracts.json contracts.new.json  # read `transitions` first — a key that left `edges`
                                             # for `unprovidedConsumes` is a broken contract
zzop facts ./api ./web > facts.json          # post-assembly facts (per-tree CommonIr + the whole join,
                                             # uncapped) for your own rule program
zzop graph ./api ./web > join.mmd            # the cross-layer join as mermaid, for any renderer —
                                             # scoped with --scope/--top, every cap disclosed in the file
zzop graph . --domain dep > imports.mmd      # the FILE import graph instead — cycles drawn as hexagons
                                             # with thick arrows, from the engine's own circular findings
zzop graph . --domain risk > risk.mmd        # blast-radius hubs + extraction seams. The health SCORES
                                             # are NOT drawn — a table of numbers is not a graph
zzop graph . --domain posture               # the mutating attack surface and its guard status —
                                             # a box means GUARDED-OR-EXEMPT, never proven guarded
zzop graph . --domain cochange > churn.mmd   # which files keep changing TOGETHER, from git history —
                                             # not imports, so it finds the coupling no dep graph can see
zzop graph . --domain dep --fold 2           # the SAME import graph with each path's first 2 segments
                                             # drawn as one box — the module map you were trying to see
                                             # IS the picture, and every edge says how many file edges
                                             # it collapsed. --fold 1 for the top-level view
zzop map . --fold 2                          # the same folding as DATA, not a picture: one row per
                                             # module with its files, lines and the imports between
                                             # modules. `--fold` is the only knob (NOT --depth, which
                                             # is git's), and `moduleEdges` counts edges BETWEEN
                                             # modules while `fileImports` counts every file-level one

大型代码库需要几分钟,而且上面的每条命令都要等到完成后才会写入任何内容。 没有进度输出:回复是一个先组装再写入的文档,因此中断运行会得到零字节,而不是部分答案;运行期间看起来也与卡住毫无区别。根据本项目自身语料库的测量结果:3,800 个文件的代码树只需几秒,zzop facts 处理包含 24,000 个文件的单体代码库需要约 50 秒,生成 10.8 MB;ASP.NET 规模的代码树(17,000 个文件,1.26M 条已解析导入边)运行 analyze 需要约 8 分钟。⚠ 这些数据来自浅克隆,你的代码树很可能不是。 这些数据所用的语料库代码树各只有一个提交(git -C corpus/frameworks/aspnetcore rev-list --count HEAD → 1),因此其中的 git 阶段耗时为零。在有历史记录的代码库中,它可能占据全部耗时的大头:docs/modules/mcp.md 记录了一个有 16,485 个提交的代码树上,git log --numstat 耗时 548 秒,而全部分析只需 13 秒——工作量是后者的 42 倍,这些数据从未涵盖这种因素。将输出重定向到文件并等待;如果需要设定上限,请自行用 timeout 包装调用,并将被终止视为没有答案,绝不能视为结果干净。

清单有意不设上限,也不包含文件或行号,因此纯重构会产生空 diff,而离开关联范围的路由也不会被摘要的上限掩盖。除非传入 --allow-tool-drift,否则 diff 会拒绝比较来自不同 zzop 构建版本的两个清单(传入后会披露差异);对于可归因于覆盖范围丢失来源的移除项,它会标记为 blindnessSuspect,而不会将其称为删除。

这种拒绝机制让清单的有效期只有一个发布周期。 tool 包含发布版本号、全部八个解析器指纹和引擎指纹,因此每次发布都会变化——包括没有更改你所用功能的发布。因此,已提交的基线会在下一次升级时失效,升级时需要重新运行 zzop manifest 并重新提交。--allow-tool-drift 适用于你决定自行解读的一次性比较,不要将它当作常规做法:它也是唯一会检查两个文件是否采用相同清单格式的选项,因为没有其他机制会比较它们的行结构。

facts 是另一条不设上限的路径,也是自定义规则扩展点的消费端:当 DSL 无法表达你的规则时,zzop 会在组装和跨层关联完成后输出它所知道的一切——每棵代码树的完整 CommonIr 以及每个关联桶,原样输出——由你自己的程序判断哪些内容算问题。zzop 既不会运行你的程序,也不会读取其结果;数据结构参见 docs/modules/facade.md。 manifest、diff、facts、graph、explain 和 init 都没有对应的 MCP 工具;explain 和 init 仍可通过 MCP 资源访问(zzop://rule/{id} 会针对每个 id 返回 explain 的答案,config-template 则是 init 的文档)。

其余功能包括:coverage(zzop 实际看到每棵代码树的范围;对应的 MCP 工具为 check_coverage)、analyze-envelope、validate-envelope、validate-rule-pack、endpoint、 file(zzop 对某个文件所知道的一切——它所属的代码树、符号、io 事实、两个方向的依赖边,以及锚定于此的所有发现项;其判定结果会说明该文件是否已被分析,因此不会把未进行结构分析的文件误认为“干净”,即使其发现项列表为空)、init(写入带注释的起始文件 zzop.config.jsonc;MCP 也会将同一文档作为 config-template 资源提供)、contract、explain、version、help。完整的 CLI 和配置参考参见 packages/README.md。

若要嵌入引擎,而不是运行任一二进制文件,可直接调用 zzop-facade/zzop-summary crate 的 JSON 输入/JSON 输出接口——它们仅供工作区内部使用,不会发布到 crates.io,因此在进程内依赖 Rust 意味着要 vendoring 此工作区,而不是运行 cargo add。通过 Shell 调用 CLI 的 JSON 子命令则完全不需要链接:

let report: serde_json::Value =
    serde_json::from_str(&zzop_facade::analyze_json(r#"{"root":"."}"#)?)?;

结果(节选)

上面这两个二进制实际打印的内容如下——findings 是一个普查对象,不是数组, 因为回复是一个经过整理的摘要,而不是原始转储。下面的数字来自对本仓库自身 cases/trees/api-be fixture 的一次真实运行,使用从此检出版本构建的 zzop 测得: zzop analyze --config cases/trees/api-be/zzop.config.jsonc。

你用哪个二进制复现这些数字,是这项声明的一部分。 zzop version 只会打印发行 版本号,而 main 在不同发行版之间会保留这个号码——因此,已安装的 @zzop/cli 和此检出版本的构建都可能回答 0.35.0,但合理地报告不同的发现,因为它们是同一版本字符串对应的不同构建。zzop version --verbose 可以区分它们:它会打印每个解析器的指纹和引擎哈希。如果你的计数与下面的代码块不同,请先比较这一行,再判断哪一方有误。

(致下一位编辑:只要 cases/trees/api-be 发生变化,或发行版改变了测量内容,这些数字就会变——而后者涵盖每项规则变更,不只是影响较大的那些。重新运行命令并重新测量;绝不要只修补一个数字。这个代码块曾四次过期,直到机器将其固定下来(2026-08-11、08-15、08-21、09-02);第四次随 v0.34.0 发布,当时所有防护检查都通过了。现在它已被固定:scripts/measure/readme-result-block.sh 会从此检出版本构建 zzop、运行它,并对比代码块中的每一个数字,因此不完整的编辑会在 CI 中变红,而不会进入发布版本。不要手动修补后就相信读数——重新运行它。

有位外部读者在同一天报告此代码块的结果为 87/73,但他们读到的并不是过期的 README:他们使用发布的 @zzop/cli 0.33.0 进行测量,这是同一版本字符串对应的另一个构建,因此得到了合理但不同的答案。上面这一段就是为此而写的。下面的 disclosure 行特意不再列为这些数字之一:请参阅它自己的注释。)

pain 从来不会单独出现。painMeasuredWeight / painTotalWeight 表示这棵代码树实际能根据权重表测量的权重总量;pain: null 表示没有任何指标拥有可统计的数据——这是数据缺失,绝不代表一切正常。

而且,pain 不是缺陷评分。 它完全不包含规则发现:下面这次运行报告了 101 条发现,其中 3 条为严重级别,而其 defect pain 为 0。painByAxis 会拆分这个数字,让区别一目了然——defect(导入循环,唯一的条目)、opinion(barrel 规范、FSD 分层、SDP/Main Sequence、Newman 模块化、LOC 上限——刻意采用相反做法的项目并没有错,只是得分较低),以及 history(重命名变更、总线因子)。这三个轴使用 pain 自身的量表,并且相加后等于 pain。查看 findings 了解缺陷;查看 pain 了解 zzop 对代码组织方式的异议程度。

{
  "fileCount": 98,
  "findings": {
    "total": 101,
    "bySeverity":  { "critical": 3, "warning": 63, "info": 35 },
    "byRule":      { "security/weak-crypto": 6, "db/unawaited-write": 1 },
    "shown":       [ /* 50 here — the listed slice, capped by --limit; each entry has ruleId, severity, file, line, message */ ]
  },
  "architecture": { "pain": 7.5, "painMeasuredWeight": 13.8, "painTotalWeight": 18.6,
                    "painByAxis": [ { "axis": "defect",  "pain": 0.0, "totalWeight": 3.0 },
                                    { "axis": "opinion", "pain": 7.4, "totalWeight": 15.0 },
                                    { "axis": "history", "pain": 0.1, "totalWeight": 0.6 } ],
                    "topRecommendation": null, "criticalTop": [],
                    /* + painMeaning / topRecommendationMeaning / criticalTopMeaning: the sentences
                       that say what each of the three above is, and is NOT, on the wire */ },
  "coverage":     { /* how much of the tree zzop actually saw, per extension */ },
  "coverageGaps": { /* which principal extensions reached no resolved import edge, always present —
                       each row's `kind` ("source", "data-config", "unclassified") says whether the zero
                       means a missing parser or a filetype you have to open to judge */ },
  "disclosure":   { /* the census of zzop's OWN known silent-failure classes, keyed
                       classes / asserted / partial / notYetDetected, plus the `note`,
                       `command` and `resource` that lead to the full text. No counts are
                       copied here: the reply carries its own, and the two that were copied
                       here went stale while the two beside them stayed right — which is
                       indistinguishable from correct until someone re-runs it. Read them
                       with `zzop contract disclosure-classes`, the command the field itself
                       names. */ },
  "warnings":     [ /* anything this run could not provide */ ]
}

每条发现都包含规则 ID、严重级别、file:line 位置和消息——记录本身位于 shown 中。该消息通常是一个 POINTER,而不是规则的说明:如果某条发现的文本由其所属规则定义,则会改为携带 messageBy 字段;你可以根据该发现的 ruleId 阅读完整文本(使用 zzop explain <ruleId> 或 MCP 资源 zzop://rule/{id}),这里也会注明用于静默此规则的配置键。请检查 messageBy 字段,而不是那句话本身。回复中的 findings.messageByIdMeaning 已对此作出说明。bySeverity / byRule 始终统计整个运行的结果,因此 --limit 即使缩短列表,也不会改变它们;正因如此,findings 是一个对象。

每项指标的 scores 代码块、health 对象和 recommendations 不会出现在此传输内容中:经过整理的摘要会将它们折叠进上面的精简 architecture 对象中。它们只有在 zzop-facade 嵌入通道(zzop_facade::analyze_json,就在上方的代码片段中)才会完整提供——该通道的结构请参阅 docs/modules/facade.md。 analyzeTrees(多树分析)还会返回 crossLayerFindings——前端请求与后端路由之间的关联结果——这是单树分析所没有的。

工作原理

每个代码仓库都会被解析为一种与语言无关的中间表示(IR),因此,Python 路由和 TypeScript fetch 最终会成为同类事实。核心在于跨仓库关联:前端调用会跨越仓库边界,与后端路由进行精确匹配;未匹配项也不会被丢弃,而是会被明确指出——大小写或基础路径差异、版本偏差、方法不匹配,都会作为近似匹配结果返回,并标明具体差异维度,无需手动比较。判断近似匹配时依据的是这些维度,而非拼写:复数形式或拼写错误(/api/userss 对比 /api/users)会被报告为未匹配调用,而不会与它可能意指的路由配对——各规则的适用范围见规则目录。除了关联分析,同一引擎还会在每个代码仓库中单独运行分层规则系统(原生全图分析,以及声明式 JSON 规则包),将结构性发现、依赖关系和死代码分析,以及健康度评分,加入同一份 JSON 文档。

每次运行都是确定性的——相同代码输入,得到相同发现结果,输出字节稳定,足以对比两次运行。这使 zzop 既可用作 CI 门禁(读取 JSON 中的严重性计数,在契约发生偏差时阻止 PR 合并),也可作为 Agent 的运行基础,让它无需担心结果不断变化而重复运行。同样重要的是,每次运行都会报告自身的盲区:warnings 和各树的 coverage 统计会说明哪些内容未运行,因此可以区分结果列表较短和引擎存在盲区这两种情况。

完整设计见:docs/ARCHITECTURE.md。输出、严重性语义和抑制机制的说明见:docs/getting-started.md。如果你的技术栈与默认设置不匹配——例如自定义扩展、自有的守卫名称、网关前缀,或尚不存在的规则——docs/extending.md 按使用顺序列出了所有插件接入点。

支持的语言

语言支持情况
TypeScript / JavaScript (.ts, .tsx, .js, .jsx, .mjs, .cjs, .mts, .cts)原生支持,完整 AST(swc)
Python (.py, .pyi)原生支持,完整 AST(ruff,Python 3 — 仅支持 Python 2 的语法会回退到词法解析)
Rust (.rs)原生支持,完整 AST(syn 2)
Go (.go)原生支持,完整 CST(tree-sitter-go 0.25)
Java (.java)原生支持,完整 CST(tree-sitter-java 0.23.5,Java 21 语法)
C# (.cs)原生支持,完整 CST(tree-sitter-c-sharp 0.23.5)
Prisma schema (.prisma)原生支持,词法 schema
SQL (.sql)原生支持,词法解析
其他语言(Ruby、JSP 等)树内词法回退:会遍历并计数文件,且只有 line-scan 规则能处理这些文件。这是上限,不是覆盖承诺——只有当某条内置规则的 file_pattern 指定了扩展名,该规则才能处理对应语言;而对于上表以外的大多数语言,没有任何规则指定相应扩展名,因此覆盖率为零。此行刻意不把零写成具体数字,因为覆盖率因语言而异,也会变化。请在你自己的代码树上测量:运行 zzop analyze <tree>,查看 packsLoaded[].filesInScope——某个 pack 的值为 0,表示该 pack 的规则路径门槛没有一个允许此处的任何字节通过,因此该 pack 的零条发现结果意味着范围未覆盖,绝非代码干净——同时查看 coverageGaps,其中扩展名对应的行会标记 kind: "source"。以这种方式在包含 5 个文件的 Ruby 代码树上测量时,没有任何内置 pack 能处理一个 .rb 文件。要获得一等支持,需使用符合 Normalized AST protocol 的外部解析器适配器。

每个原生解析器提取的内容——路由、消耗内容、框架、完整精度层级——Python v1 范围说明以及 每个解析器的指纹,见 docs/ARCHITECTURE.md。(zzop version 的默认输出不含这些 指纹;它只输出纯版本号,方便脚本解析单个标记。zzop version --verbose——以及输出相同字符串的 zzop-mcp version --verbose——会输出指纹;zzop manifest 的 tool 字段也会在制品中携带相同字符串。)

Rust 有一条其他语言都没有的报告规则:如果某条发现对应的行位于 #[cfg(test)]/#[test] 门控项中,就会被丢弃,因为 Rust 的单元测试位于发布文件内部, 而其他语言依赖的基于路径形状的测试排除规则(foo.test.ts、tests/test_foo.py) 无法识别它们。凭据静态存储规则不受此规则影响,仍会检查这些区域——无论编译器是否保留某个已提交的密钥,它都已泄露——每条规则都会在自己的目录条目中说明这一点。两部分内容见: docs/rules/catalog.md。

扩展名没有原生解析器的常规大小文件也会在输出的 warnings 中主动报告,列出扩展名、文件数量和路径示例,而不会悄然消失;如果分析需要支持该语言,请为其 指定适配器(在 zzop.config.jsonc 中设置 overlays: [...])。

版本控制与稳定性

zzop 仍处于 1.0 之前(0.x)且不稳定 的阶段——任何版本发布都可能改变行为、输出、规则或 默认设置,因此请固定到精确版本(不要使用 ^/~ 范围),并在升级前重新测试。语义 化版本控制从 1.0.0 开始。此前的承诺范围较窄,承诺的是记录方式,而非变更频率:VERSIONING.md 中列出的接口若有破坏性变更,都会在 CHANGELOG.md 中记录新旧两种写法。VERSIONING.md 还会 明确说明这些接口中仍在变化的属性——规则 ID、SourceSymbol.id 的唯一性、原生 ID 命名空间—— 而不是让你从运行结果中自行推断。

目录结构与开发

想要贡献代码,或只是想查看 crate 对照表?CONTRIBUTING.md 同时提供这两方面的信息—— 各 crate 的职责列表,以及构建、测试和测量命令。它们放在那里而非此处,是因为读者阅读此页面是为了决定 是否采用 zzop;在安装之前,没人会询问依赖关系图能回答的问题。

License

MIT — see LICENSE.

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。