计划执行与检查节点
executing-plans
按既定实施计划完成工作,保持过程检查和反馈。
scaffold-cli-command【效率与协作】使用 Commander.js 搭建带选项、action 处理器、三种输出模式(人类可读、 quiet、JSON)和可选 ceremony 变体的新 CLI 命令的脚手架。涵盖命令命名、 选项设计、共享上下文模式、错误处理和集成测试。在向现有 Commander.js CLI 添加命令、从零设计新 CLI 工具,或在多命令 CLI 中标准化命令结构时使用。
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
向 Commander.js CLI 应用添加新命令,附一致的选项处理、三种输出模式和集成测试。
gather、audit、sync)cli/index.js)<name> 或 [names...])选择传达命令动作的动词。将命令分组为类别:
| 类别 | 动词 | 模式 |
|---|---|---|
| CRUD | install、uninstall、list、search | 操作内容 |
| 生命周期 | init、sync、audit | 管理项目状态 |
| Ceremony | gather、scatter、tend、campfire | 温暖叙事输出 |
命名约定:
install-skill —— 让选项指定什么)<required>、[optional] 或 [variadic...]program
.command('gather <name>')
.description('Gather a team around the campfire')
预期结果: 已定义命令名、描述和位置参数。
失败处理: 若动词与现有命令重叠,要么组合它们(向现有命令添加选项),要么在描述中清晰区分。
每个命令应支持一组标准共享选项加上命令特定的。
标准选项(按需包含):
.option('-n, --dry-run', 'Preview without making changes')
.option('-q, --quiet', 'Suppress human-readable output')
.option('--json', 'Output as JSON')
.option('-f, --framework <id>', 'Target specific framework')
.option('-g, --global', 'Use global scope')
.option('--scope <scope>', 'Scope: project, workspace, global', 'project')
.option('--source <path>', 'Path to tool root directory')
命令特定选项 —— 仅添加命令需要的:
.option('--ceremonial', 'Show each item arriving individually')
.option('--only <items>', 'Comma-separated subset to include')
.option('-y, --yes', 'Skip confirmation prompts')
设计规则:
-n)--dry-run)以求清晰预期结果: 包含标准和自定义选项的完整选项链。
失败处理: 若积累太多选项(>8),考虑拆分为子命令或分组相关选项。
action 处理器遵循一致模式:
.action(async (name, options) => {
// 1. Get shared context (registries, adapters, paths)
const ctx = getContext(options);
// 2. Resolve what to operate on
const items = resolveItems(ctx, name, options);
if (!items || items.length === 0) {
reporter.error('Nothing found.');
process.exit(1);
}
// 3. Preview if dry-run
if (options.dryRun) reporter.printDryRun();
// 4. Execute the operation
const results = await executeOperation(items, ctx, options);
// 5. Output results (3 modes)
if (options.json) {
console.log(JSON.stringify(results, null, 2));
} else if (options.quiet) {
reporter.printResults(results);
} else {
printHumanOutput(results, options);
}
})
getContext() 共享辅助器集中:
预期结果: 遵循 5 步模式的 action 处理器:context → resolve → preview → execute → output。
失败处理: 若命令不适合 resolve-then-execute 模式(如纯信息性如 detect),简化为:context → compute → output。
每个命令应支持三种输出模式:
默认(人类可读):
Installing 3 item(s) to Claude Code...
+ create-skill [claude-code] .claude/skills/create-skill
+ write-tests [claude-code] .claude/skills/write-tests
= commit-changes [claude-code] (skipped)
2 installed, 1 skipped
Quiet (--quiet):
标准 reporter 输出 —— 带状态图标(+、-、=、!)的简洁行,无 ceremony,无装饰。
JSON (--json):
{
"command": "install",
"items": 3,
"installed": 2,
"skipped": 1,
"failed": 0
}
实现模式:
if (options.json) {
console.log(JSON.stringify(data, null, 2));
return;
}
if (options.quiet) {
reporter.printResults(results);
return;
}
// Default: human-readable output
printHumanReadable(results, options);
预期结果: 所有三种模式产出有用输出。JSON 可解析。Quiet 简洁。默认信息丰富。
失败处理: 若命令无有意义的 JSON 表达(如 detect),跳过 JSON 模式并记录原因。
对受益于温暖叙事输出而非事务性报告的命令:
if (options.json) {
ceremonyReporter.printJson(data);
} else if (options.quiet) {
reporter.printResults(results);
} else {
ceremonyReporter.printArrival({
teamId: name,
agents,
results: { installed, skipped, failed },
ceremonial: options.ceremonial || false,
});
}
Ceremony 输出遵循语调规则:
详细终端输出模式见 design-cli-output 技能。
预期结果: 遵循所有语调规则、产出温暖、信息丰富叙事的 ceremony 输出。
失败处理: 若 ceremony 输出感觉勉强或不增加超出标准输出的信息,跳过它。不是每个命令都需要 ceremony 变体。
// Unknown item
if (!item) {
reporter.error(`Unknown: ${name}. Use 'tool list' to browse.`);
process.exit(1);
}
// Confirmation for destructive actions
if (!options.yes && !options.quiet && !options.dryRun) {
const answer = await askYesNo('Proceed?');
if (!answer) {
console.log(' Cancelled.');
return;
}
}
// State validation
if (!state.fires[name]) {
reporter.error(`Not active. Nothing to remove.`);
process.exit(1);
}
错误设计原则:
process.exit(1)--yes 绕过)预期结果: 所有错误路径产出有帮助消息。破坏性操作需要确认。
失败处理: 若确认提示干扰脚本,确保 --yes 和 --quiet 都绕过它们。
import { describe, it, after } from 'node:test';
import assert from 'node:assert/strict';
import { execSync } from 'child_process';
const CLI = 'node cli/index.js';
function run(args) {
return execSync(`${CLI} ${args}`, { encoding: 'utf8', timeout: 10000 });
}
describe('new-command', () => {
after(() => { /* cleanup created files/state */ });
it('dry-run shows preview', () => {
const out = run('new-command arg --dry-run');
assert.match(out, /DRY RUN/);
});
it('--json outputs valid JSON', () => {
const out = run('new-command arg --json');
const start = out.indexOf('{');
const data = JSON.parse(out.slice(start));
assert.equal(data.command, 'new-command');
});
it('rejects unknown input', () => {
assert.throws(() => run('new-command nonexistent'), /Unknown/);
});
});
详细 CLI 测试模式见 test-cli-application 技能。
预期结果: 至少 3 个测试:dry-run、JSON 输出、错误情况。复杂命令更多。
失败处理: 若 execSync 超时,增加超时或检查阻塞命令的交互提示。
--help 中--dry-run、--quiet、--json)正确工作--yes 绕过)--json。--yes 并确保 --quiet 抑制提示。process.exit(1)。解析 CLI 输出的工具先检查退出码。--scope 的选项应有合理默认,使用户不必每次指定。--quiet 标志意味着"机器最少输出"。若 ceremony 文本泄漏到 quiet 模式,脚本会在意外输出上损坏。build-cli-plugin —— 构建命令操作的适配器/插件test-cli-application —— 超出第 7 步基础的全面 CLI 测试模式design-cli-output —— 所有详细级别的终端输出设计install-almanac-content —— 结构良好 CLI 命令技能的示例