mcpField
C
codependix-triage

codependix-triage

github.com/organizzolini测试与质量0279 次安装今天更新
代码仓库

关于 codependix-triage

用于排查 Codependix 运行结果的 Skill,面向处理依赖图和导出的开发者。它区分边界违规、报告过期、项目失败、命令错误及未生成文件等情况,并说明排查方向。

主要功能

  1. 01分类运行结果与失败类型
  2. 02追踪依赖边界违规
  3. 03更新过期的图导出
  4. 04诊断项目及 NestJS 失败
  5. 05检查选择项和 CLI 参数

适用场景

  1. 01调查失败的边界门槛
  2. 02更新过期的依赖图报告
  3. 03排查项目导出缺失的原因

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/organizzolini/codebase --skill codependix-triage

安装后在 Claude Code 中输入/codependix-triage确认已加载。

详细介绍

处理 codependix 故障

Codependix 会报告几种不同的结果,而读懂具体发生了哪一种,就是大部分工作。首先要区分它们:边界违规是真实代码中的真实边,过期导出是漂移,失败是项目根本没能生成结果,而完全没有写入任何内容的运行通常不属于上述任何一种。

边界违规

--check boundaries 发现了一条边或一个环,违反了已声明的规则。每条违规都会指出图级别、发现违规的范围、规则、两个端点、被归责的项目,以及规则给出的相关原因。

从故障报告中指出的项目入手。 在 Nx 工作区中,每个项目都有自己的 codependix-gate 目标,因此 nx run <project>:codependix-gate 显示失败,表示某项发现被归责给该项目:要么是指向拥有其源代码的项目的违规边,要么是某个环上的每个项目。使用相同的目标重现问题,或运行 codependix map --check boundaries --projects <project> --config configuration/codependix.config.ts,并添加 --format json 以数据形式读取发现结果。导致目标失败的发现会归责给对应项目;显示“in dependency X, not failing”的行只是说明,真正失败的是 X 自己的目标。应在说明指出的位置修复,而不是在打印说明的项目中修复。

这是唯一一种重新运行无法修复的发现。 没有内容过期,也无需重新生成:这条边确实存在于代码中,必须做出以下两种选择之一。

  1. 移除这条边。 这通常是正确的做法,而且通常比看起来简单——将类型移入 *.types.ts 文件,反转依赖关系,或将共享部分提取到双方都可以依赖的包中。
  2. 更改规则,前提是规则本身有问题。这是一个有意为之的决定,应连同原因一起记录在 codependix.config.ts 中,而不是悄悄放宽选择器,直到运行通过。

切勿仅为让失败的检查通过,就缩小选择器范围、添加排除项或删除规则。为了通过检查而放宽的门禁,不再能保护任何东西,后续读者也无从得知它原本的作用。

如果违规出现在 nx 级别,并且提到的边背后没有 import 语句,这正是该级别的意义所在:implicitDependencies 条目是真实的项目图边,而 @nx/enforce-module-boundaries 无法看到它。应移除该条目,否则就必须更改规则。

--check reports 发现过期内容

一个或多个已配置导出与重新构建的图不一致。运行结果会列出相关项目。

重新运行 --write。这就是全部修复方法。 图会随着其描述的工作区变化,因此项目图一旦改变,所有基于该图生成的导出都会过期——这是需要刷新的漂移,而不是需要调查的缺陷。

切勿手动编辑锚点标记之间的内容。 下一次 --write 会整体替换该代码块,因此编辑过的图表会成为一次差异,并在下次运行时悄然消失。独立的 Markdown 文件也一样:codependix 拥有其全部内容。

过期检查还有两点并不代表:

  • 这不是 conformetry 一致性差异。 codependix:start / codependix:end 标记是 codependix 自己的语法,不依赖任何 conformetry-* 包。在这里运行一致性检查或尝试使用 conformetry 生成器都无济于事。
  • 这并不能证明缺少锚点。 从未导出过的项目没有可供比较的代码块,因此会像其他漂移一样报告为过期。

失败的项目

失败会按项目收集,并按名称报告。一个项目失败不会阻止其余项目继续运行——该轮次中所有剩余项目仍会运行,并且无论较早的图类型是否失败,都会尝试全部四种图类型的处理。因此,运行结果列出三个失败,意味着有三件事需要修复,而不是一次不稳定的运行需要重试。

Markdown 文件不存在

这是唯一一个会直接导致失败的锚点问题。缺失的锚点块会在 --write 时自动创建;缺失的文件则不会,因为完全没有 readme 的项目是比锚点块未放置更严重的问题,而凭空创建文件就等于撰写一份没人要求的文档。

创建该文件——项目 readme 至少要有一个标题——然后重新运行。

使用 --write 时缺少锚点块

这不算失败。--write 会在以下两个安全位置之一创建锚点块:

  • 在文件末尾追加一个新的 ## 🕸️ Codependix 部分,其中包含一行介绍和一个用于图类型的 ### <Subheading>。
  • 如果之前的图类型已创建 ## 🕸️ Codependix 部分,则在现有部分末尾插入一个新的 ### <Subheading>。

它绝不会将锚点块放到其他人正在编写的文档中的其他位置,也绝不会重复标题。如果锚点块出现在你不希望它出现的位置,只需手动移动整个标记对一次,之后每次 --write 都会在原位置替换内容。

NestJS 项目无法启动其容器

NestJS 阶段会以预览模式探索项目的容器:注册所有模块和提供程序,但不会实例化任何模块或提供程序。对于使用 TypeOrmModule.forRootAsync 选项工厂构建的项目,不会连接数据库,因此导致此阶段失败的,一定是在模块_注册_期间抛出异常的情况——例如,某个模块的静态 forRoot 参数读取了一个不存在的变量、模块文件顶层抛出异常,或者项目的根模块未导出此阶段所需的内容。请检查这些位置。

失败会归因于容器无法启动的项目;如果失败所涉及的模块或类属于另一个项目,错误消息会指出该项目。例如,某项目导入了一个在导入时抛出异常的实体包,那么该项目也会失败,而修复应在包所属项目中进行。实体文件之间的值导入循环可能导致装饰器在模块完成求值之前读取类,此时会显示为 Cannot access 'X' before initialization——这是启动失败,不是 acyclic 检查结果。

应用程序以 nestjsModules.rootModules 条目指定的模块及导出为根;没有此类文件的库包则以一个合成模块为根,该模块由它定义的所有 *.module.ts 构建而成。因此,某个模块文件如果无法独立导入,就会导致库包失败,而应用程序可能不会察觉。

有两种看似合理、实则无效的修复方法:启动或初始化数据库(该阶段不会连接数据库),以及先构建项目(该阶段会直接导入项目自身的 TypeScript 模块源文件)。

如果通过其他加载器从 TypeScript 源文件运行 CLI,请确认装饰器元数据能够保留下来:NestJS 构造函数注入会读取元数据,而纯类型剥离会将其擦除,导致容器无法解析自身的提供程序。已发布的 codependix 二进制文件会自行注册一个保留装饰器的加载器,Nx gate 也会这样做(通过 @codependix/nx/loader,工作区无需安装 @swc-node/register);手动编写的调用也必须如此。该加载器会读取工作区根目录的 tsconfig.json,因此,如果根目录的 tsconfig.json 未启用装饰器元数据输出,也会以相同方式失败。

无法构建 Nx 项目图

nxProjects 层级会为整个工作区构建一张图,因此无法构建时,失败会归因于每个受检查的项目:每个 gate 都会报告该问题;当受检查的项目不止一个时,报告行会显示“所有 N 个受检查项目”,而不是列出项目名称。这是一个问题,不是 N 个问题。请检查项目图本身,而不是某个具体项目——任何阻碍其构建的因素都会以相同方式阻碍每个 gate。

绿色运行,但评估的内容少于预期

--projects 或 --tags 列表中,即使一个项目存在、另一个不存在,运行仍会继续,并且只评估匹配的条目。运行会在 stderr 中记录 🕸️ Ignored selection entries that matched no project,列出未匹配的 projects 和 tags,并提示检查拼写;最终退出状态由匹配的条目决定。若选择来自手动输入的列表,请在运行成功后查看 stderr,并在信任结果前修正拼写。若一个条目都未匹配,则会直接拒绝运行。

被拒绝的命令行

--check 接受从 boundaries 和 reports 中选取的逗号分隔集合,且会在执行任何其他操作前读取整个命令行:

  • --check needs a value — 单独使用 --check,或其值仅包含分隔符。请指定集合,不要删掉该标志。若将其理解为“什么都不检查”,就会变成一个永远不会失败的检查。
  • --check does not accept "..." — 使用了其他工具的名称。limits 属于 codometer,depth 属于 callidescope;只有 reports 是共用项。
  • --write cannot be combined with --check reports — 刚写出的导出内容不可能在同一次运行中已过时。--write --check boundaries 则合法。
  • 既未指定 --check,也未指定 --write:在终端中会询问是否继续,在其他环境中则会拒绝运行——包括 Agent 或 CI 作业发起的运行,因为它们没有终端可供回答。不会推断操作,也不会默认写入。

同一命令行上的所有错误都会先汇总,再一并报告,因此两条报错意味着有两项需要修正,而不是需要运行两次。

命令应为 codependix map,而非单独的 codependix:没有子命令的命令行会在此处之前被参数解析器拒绝。未指定 --config <path> 的命令行也会被拒绝(在此仓库中为 --config configuration/codependix.config.ts):该标志是必需的,错误信息会指出这一点。

--write 未生成任何文件

这是最安静的结果,而且几乎从来不是 bug:运行以状态码 0 退出,报告所有已配置的导出内容均为最新,但没有写入任何内容,因为没有配置任何内容。每个未设置的 target 默认都是 "none",而解析为 "none" 的项目会直接从结果中排除,不会报告为最新状态。因此,报告中的项目数为 0,意味着 codependix 被配置为不生成任何内容。

在怀疑工具之前,请按顺序检查以下各项:

  1. --config 指向的是你想指定的文件吗? 该标志是必需的,文件也必须存在,因此路径缺失或拼写错误都会明确报错;但指向了错误的文件,其效果就和空文件完全一样。
  2. 是否设置了 target? 即使图类型包含目标位置,但没有 target,解析结果仍为 "none"。
  3. 字段是否拼写为 defaults? default 会作为未知键被剥除,不会产生任何效果。
  4. 配置中是否指定了 include? 默认不选择任何内容,因此只指定 defaults 的配置不会选中任何项目,也不会导出内容。运行会发出警告 — 🕸️ Selected no project to export — 但仍以状态码 0 退出;无论如何,--check boundaries 都会通过,因为它会评估所有项目,不受 include 影响。若要覆盖整个工作区,请编写 include: ["**"]。
  5. 项目是否匹配 include,且未被 exclude 排除? 两者都会同时针对项目的 Nx 名称和相对于工作区的根路径进行匹配。
  6. --directory 是否指向工作区根目录? 所有项目路径都会相对于该目录解析,而不是把它当作要扫描的子树 — Nx 会根据进程的工作目录解析整个图。如果该参数指向单个项目的文件夹,运行仍会读取整个图,但会将每个项目解析到该文件夹下,因此导出内容可能写入意外位置,或因找不到相应的 readme 而失败。

codependix-configure skill 涵盖了上述每个字段。

被拒绝的配置

验证会拒绝两种目标不匹配的情况,而不会悄悄导出部分请求内容:目标为 "both" 或 "json",但没有 json 目的地;以及目标为 "both" 或 "markdown",但没有 markdown 目的地。markdown 目的地既未指定 anchor 也未指定 path 时,也会出于同样的原因被拒绝——没有信息说明导出内容要放在哪里。

这是谁的问题:图还是代码

完成的导出是一种描述,而非判决——导出不会对代码库的结构施加任何限制,只有声明的边界规则才会。图中显示的令人担忧之处(例如循环依赖,或项目依赖项远超预期)是代码中的真实问题,即使没有规则对此作出判定也是如此。修复应在代码中进行,而非修改用于导出图的配置。更改任何内容之前,请使用 codependix-navigate 技能,先理解图实际表达的内容。

评论

支持 Markdown