mcpField
M
meta-reviewing-cli-reviewing

meta-reviewing-cli-reviewing

github.com/agents-inc测试与质量2657 次安装2 天前更新
代码仓库

关于 meta-reviewing-cli-reviewing

用于审查 CLI 代码的技能,提供安全性、行为、配置、测试和用户反馈检查清单,帮助审查者按严重程度分类问题并说明影响。

主要功能

  1. 01信号与取消处理检查
  2. 02退出码与异步解析审查
  3. 03进度提示与错误消息检查
  4. 04配置优先级审查
  5. 05帮助文本与测试覆盖检查
  6. 06问题严重性分类

适用场景

  1. 01审查 Commander.js 代码变更
  2. 02检查 @clack/prompts 取消处理
  3. 03审计 CLI 错误处理
  4. 04评估 CLI 测试与配置

安装

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

$npx skills add https://github.com/agents-inc/skills --skill meta-reviewing-cli-reviewing

安装后在 Claude Code 中输入/meta-reviewing-cli-reviewing确认已加载。

附带文件examples/core.mdmetadata.yaml

详细介绍

CLI 代码审查模式

快速指南: 审查 CLI 代码时,检查 SIGINT 处理、p.isCancel() 检查、退出码常量、parseAsync() 的使用,以及用户反馈(加载动画、清晰的错误信息)。检查配置层级、帮助文本质量和试运行支持。区分严重程度(必须修复、建议修复、可改进),并说明每个问题的重要原因。


<critical_requirements>

关键要求:审查 CLI 代码之前

所有代码都必须遵循项目在 CLAUDE.md 中的约定(kebab-case、命名导出、导入顺序、import type、命名常量)

(必须确认 CLI 入口点中存在 SIGINT(Ctrl+C)处理)

(必须确认每次调用 @clack/prompts 后都调用 p.isCancel())

(必须确认退出码使用命名常量——标记 process.exit() 中的任何魔法数字)

(必须确认异步操作使用 parseAsync(),而不是 parse())

(必须确认在任何控制台输出或错误处理之前停止加载动画)

</critical_requirements>


自动检测: 审查 CLI、检查 CLI 代码、CLI PR 审查、Commander.js 审查、@clack/prompts 审查、CLI 质量、CLI 错误处理审查、退出码审查

适用场景:

  • 审查使用 Commander.js 构建的 CLI 应用
  • 审查使用 @clack/prompts 的交互式提示
  • 检查 CLI 错误处理和退出码模式
  • 评估 CLI 用户体验(帮助文本、加载动画、反馈)
  • 验证 CLI 测试是否充分
  • 审查配置管理模式

不适用场景:

  • 实现 CLI 代码时(请使用相应的 CLI 实现技能)
  • 进行与 CLI 无关的一般代码审查时
  • 审查后端 API 时

涵盖的关键模式:

  • CLI 专属审查清单
  • 退出码和信号处理验证
  • 用户体验审查标准
  • 错误消息质量评估
  • 测试充分性清单
  • 配置层级审查
  • 命令结构和组织审查
  • CLI 问题的严重程度分类

详细资源:


理念

CLI 用户体验至关重要。 与提供视觉反馈的 Web 应用不同,CLI 工具完全通过文本进行交互。糟糕的错误消息、缺失的进度指示或意外退出都会损害用户信任。审查时应体谅最终用户。

审查 CLI 代码时:

  • 确认所有调用 process.exit() 的路径都使用命名常量
  • 检查每个异步操作是否都有视觉反馈(加载动画)
  • 确保在所有情况下都能妥善处理取消操作
  • 验证错误消息是否说明了什么操作失败,以及如何修复
  • 确认帮助文本实用,并且包含示例

不应过于苛刻的情况:

  • 如果功能正确,不要因为帮助文本措辞而阻止 PR
  • 对于耗时不到 500ms 的操作,不要强制要求加载动画
  • 如果颜色选择遵循现有模式,不要吹毛求疵
  • 如果 CLI 足够简单,不要要求添加详细模式

核心原则:

  • 安全第一: 退出码和信号处理不可妥协
  • 用户共情: 每条错误消息都应引导用户解决问题
  • 一致性: 所有命令都应遵循相同的模式
  • 可测试性: CLI 代码应可在不启动进程的情况下进行测试

核心模式

模式 1:CLI 审查清单

每次审查 CLI 代码时,都使用这份全面的清单。

入口点验证
## CLI Entry Point Review

**Signal Handling:**

- [ ] SIGINT handler exists in entry point
- [ ] SIGINT calls process.exit with EXIT_CODES.CANCELLED
- [ ] Other relevant signals handled (SIGTERM for containers)

**Command Registration:**

- [ ] Commands imported and registered cleanly
- [ ] parseAsync() used (not parse()) for async actions
- [ ] Global error handler with catch() on main()
- [ ] configureOutput() used for colored errors
- [ ] showHelpAfterError(true) enabled

**Global Options:**

- [ ] --dry-run supported for destructive operations
- [ ] --verbose supported for debug output
- [ ] --help generates useful output
- [ ] --version displays correct version

重要原因: 入口点问题会影响每条命令。缺少 SIGINT 处理会导致用户无法取消;缺少 parseAsync 会悄无声息地吞掉错误。


模式 2:退出码审查

确认所有退出路径都使用命名常量。

退出码验证清单
## Exit Codes Review

**Named Constants:**

- [ ] Exit codes defined as named constants (e.g., EXIT_CODES object)
- [ ] All exit codes have JSDoc descriptions
- [ ] Uses `as const` for type inference

**Usage Audit:**

- [ ] No magic numbers in process.exit() calls
- [ ] Correct exit code for each scenario:
  - Success: EXIT_CODES.SUCCESS (0)
  - General error: EXIT_CODES.ERROR (1)
  - Invalid args: EXIT_CODES.INVALID_ARGS (2)
  - User cancelled: EXIT_CODES.CANCELLED
  - Validation failed: EXIT_CODES.VALIDATION_ERROR
// Must Fix: Magic number exit code
process.exit(1); // What does 1 mean?

// Good: Named constant
process.exit(EXIT_CODES.VALIDATION_ERROR);

重要原因: 魔法退出码难以维护。依赖你的 CLI 的脚本需要可预测且有文档说明的退出码。

模式 3:提示词取消处理审查

每次调用 @clack/prompts 都必须检查是否已取消。

取消处理审计
// Must Fix: Missing isCancel check
const name = await p.text({ message: "Name:" });
// User presses Ctrl+C - name is Symbol, code continues with garbage

// Good: Proper cancellation handling
const name = await p.text({ message: "Name:" });
if (p.isCancel(name)) {
  p.cancel("Setup cancelled");
  process.exit(EXIT_CODES.CANCELLED);
}

审查清单:

## Prompt Cancellation Review

For EACH @clack/prompts call (p.text, p.select, p.confirm, p.multiselect):

- [ ] p.isCancel() check immediately follows
- [ ] p.cancel() called with descriptive message
- [ ] process.exit() called with EXIT_CODES.CANCELLED
- [ ] No code executes after isCancel returns true

**重要性:**缺少 isCancel 检查会导致用户按下 Ctrl+C 时出现未定义行为。代码会继续执行,并将 Symbol 值当作预期的字符串/布尔值处理。


模式 4:异步操作审查

检查所有异步任务是否使用加载指示器并处理错误。

加载指示器使用审查
// Must Fix: No feedback for long operation
const data = await fetchRemoteConfig(); // User sees nothing

// Good: Spinner with descriptive messages
const s = p.spinner();
s.start("Fetching configuration...");
try {
  const data = await fetchRemoteConfig();
  s.stop(`Loaded ${data.items.length} items`);
} catch (error) {
  s.stop("Failed to fetch configuration");
  p.log.error(error.message);
  process.exit(EXIT_CODES.NETWORK_ERROR);
}

审查清单:

## Async Operations Review

For EACH async operation (API calls, file operations, network):

- [ ] Spinner started with descriptive message
- [ ] Spinner stopped before any console output
- [ ] Spinner stopped before error logging
- [ ] Success message includes result info
- [ ] Error handling exists with appropriate exit code

**重要性:**用户需要知道操作正在进行。没有任何反馈的操作会让人觉得程序坏了。


模式 5:错误消息质量审查

评估错误消息是否能指导用户采取行动。

错误消息标准
## Error Message Review

For EACH error path:

- [ ] Message explains WHAT failed (not just "Error")
- [ ] Message explains WHY it failed (permission, network, validation)
- [ ] Message suggests HOW to fix it (retry, check config, provide flag)
- [ ] Uses picocolors consistently (red for errors, yellow for warnings)
- [ ] Includes relevant context (file path, option name, command)
// Must Fix: Unhelpful error
p.log.error("Failed");

// Should Fix: Better but no resolution
p.log.error(`Config file not found: ${configPath}`);

// Good: Actionable error
p.log.error(`Config file not found: ${configPath}`);
p.log.info(`Run 'mycli init' to create one, or specify path with --config`);

**重要性:**可指导用户采取行动的错误消息能减轻支持负担,并改善用户体验。用户不应陷入无从下手的境地。


模式 6:配置层级审查

检查配置解析是否遵循正确的优先级。

配置优先级清单
## Configuration Review

**Precedence Order (highest to lowest):**

1. [ ] CLI flags (--source, --config)
2. [ ] Environment variables (MYAPP_SOURCE)
3. [ ] Project config (.myapp/config.yaml in cwd)
4. [ ] Global config (~/.myapp/config.yaml)
5. [ ] Default values (hardcoded constants)

**Implementation:**

- [ ] resolveConfig function exists and follows precedence
- [ ] Empty flag values handled (--source "" should error or skip)
- [ ] Missing config files handled gracefully (no crash)
- [ ] Source/origin tracked for debugging (--verbose shows where value came from)

**重要性:**配置优先级不正确会让用户困惑。如果环境变量覆盖了标志参数,那就是一个错误。


模式 7:帮助文本审查

评估命令文档的质量。

帮助文本清单
## Help Text Review

**Command Documentation:**

- [ ] Description is clear and concise
- [ ] All options have descriptions
- [ ] Required vs optional options clear
- [ ] Default values documented in option descriptions

**Examples Section:**

- [ ] Common use cases shown
- [ ] Examples are copy-paste ready
- [ ] Complex options demonstrated

**Consistency:**

- [ ] Naming follows conventions (--dry-run not --dryRun)
- [ ] Short flags used for common options (-f for --force)
- [ ] Help shown after errors (showHelpAfterError enabled)

模式 8:测试充分性审查

检查 CLI 测试是否覆盖关键路径。

CLI 测试清单
## Testing Review

**Command Testing:**

- [ ] Happy path tested for each command
- [ ] Invalid arguments tested (missing required, unknown options)
- [ ] --help output tested
- [ ] exitOverride() used to prevent process.exit in tests

**Prompt Testing:**

- [ ] @clack/prompts mocked properly
- [ ] Cancellation flow tested (isCancel returns true)
- [ ] Validation rejection tested
- [ ] Multiple selection paths tested

**File System Testing:**

- [ ] In-memory filesystem used for isolated tests
- [ ] Config loading tested (missing, invalid, valid)
- [ ] File write operations tested

**Exit Code Testing:**

- [ ] Success exits with 0
- [ ] Each error type returns correct non-zero code
- [ ] Cancellation exits with CANCELLED code

查看 examples/core.md,了解审查时需要查找的测试代码模式。


模式 9:命令结构审查

检查命令组织是否合理。

结构清单
## Command Structure Review

**Organization:**

- [ ] Related commands grouped as subcommands (config show, config set)
- [ ] Each command in separate file
- [ ] No god commands (> 200 lines)
- [ ] Shared utilities extracted to lib/

**Options:**

- [ ] Global options defined on parent (--verbose, --dry-run)
- [ ] optsWithGlobals() used to access parent options
- [ ] Option names consistent across commands

**Arguments:**

- [ ] Positional arguments have clear names
- [ ] Required vs optional arguments documented
- [ ] Argument validation happens early in action

模式 10:安全审查

检查 CLI 特有的安全问题。

安全清单
## CLI Security Review

**Input Validation:**

- [ ] No shell injection (user input not concatenated into shell commands)
- [ ] File paths validated before operations
- [ ] URLs validated before fetch

**Secrets Handling:**

- [ ] API keys/tokens not logged (even in verbose mode)
- [ ] Sensitive options not shown in help output
- [ ] Config files with secrets have appropriate permissions warning

**Dependency Injection:**

- [ ] Arguments not passed directly to child_process
- [ ] execa or similar used instead of exec when needed

<decision_framework>

决策框架

CLI 问题的严重程度分类
Is this a safety/correctness issue?
├─ Missing SIGINT handler → MUST FIX
├─ Missing p.isCancel() check → MUST FIX
├─ Magic number exit code → MUST FIX
├─ parse() instead of parseAsync() → MUST FIX
├─ Missing error handling on async → MUST FIX
└─ NO → Is it a user experience issue?
    ├─ Missing spinner for >500ms operation → SHOULD FIX
    ├─ Unhelpful error message → SHOULD FIX
    ├─ Incorrect config precedence → SHOULD FIX
    ├─ Missing --help descriptions → SHOULD FIX
    └─ NO → Is it an enhancement?
        ├─ Could add --json output → NICE TO HAVE
        ├─ Could add more examples in help → NICE TO HAVE
        ├─ Could improve verbose logging → NICE TO HAVE
        └─ Style preference → DON'T MENTION
批准决策框架

批准条件:

  • 已确认所有 SIGINT/取消处理逻辑
  • 所有退出码都使用具名常量
  • 异步命令使用 parseAsync()
  • 异步操作均有错误处理
  • 测试覆盖关键路径

要求修改的情况:

  • 缺少 p.isCancel() 检查(任何提示词)
  • process.exit() 中使用魔法数字
  • 异步操作使用 parse()
  • 长时间运行的操作缺少加载指示器
  • 错误消息缺乏帮助

需要重大修改的情况:

  • 入口点没有 SIGINT 处理程序
  • 系统性地缺少取消处理
  • 未定义退出码常量
  • 未建立错误处理模式
  • 存在安全漏洞(Shell 注入)

</decision_framework>


<red_flags>

风险提示

高优先级问题(必须修复):

  • 入口点中缺少 process.on("SIGINT", ...)
  • 任意提示调用后都缺少 p.isCancel()
  • 使用 process.exit(1) 或 process.exit(0),而非命名常量
  • 存在异步操作时使用 program.parse(),而非 program.parseAsync()
  • 错误日志输出前未停止微调器(导致输出错乱)
  • 存在 Shell 注入漏洞(在 exec/spawn 中使用用户输入)

中优先级问题(应该修复):

  • 对可能耗时超过 500ms 的操作未显示微调器
  • 错误消息说明了失败原因,却没有说明如何修复
  • 破坏性操作缺少 --dry-run 支持
  • 缺少用于调试的详细模式
  • 配置优先级不正确(环境变量覆盖命令行标志)
  • 缺少对提示词中用户输入的验证
  • 未配置 showHelpAfterError(true)

常见错误:

  • 忘记在 p.cancel() 后调用 process.exit()
  • 未使用 optsWithGlobals() 访问父命令选项
  • 停止微调器前记录日志(输出乱码)
  • 未处理标志的空字符串值
  • 未捕获 YAML 解析错误
  • .action() 回调中的异步错误被吞掉

注意事项与边缘情况:

  • Commander 会自动将选项对象中的 --my-option 转换为 myOption
  • 即使发生错误,也必须调用 Spinner.stop()
  • p.isCancel() 对 Symbol 值返回 true,而不是对 undefined
  • 在异步上下文中调用 process.exit() 时,可能不会等待待处理的 I/O 完成
  • 颜色可能无法在 CI 环境中呈现(检查 NO_COLOR 环境变量)
  • 配置文件可能存在,但 YAML 格式无效

</red_flags>


<critical_reminders>

重要提醒

所有代码都必须遵循 CLAUDE.md 中的项目约定

(必须确认 CLI 入口点中存在 SIGINT(Ctrl+C)处理)

(必须确认每次调用 @clack/prompts 后都会调用 p.isCancel())

(必须确认退出码使用命名常量——标记 process.exit() 中的任何魔法数字)

(必须确认异步操作使用 parseAsync(),而不是 parse())

(必须确认在任何控制台输出或错误处理前都已停止微调器)

若未发现这些问题,CLI 将会在按下 Ctrl+C 时崩溃、使用未记录的退出码,并悄无声息地吞掉错误。

</critical_reminders>

评论

支持 Markdown