@wazir-dev/cli 1.1.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. package/CHANGELOG.md +74 -10
  2. package/README.md +15 -15
  3. package/assets/demo.cast +47 -0
  4. package/assets/demo.gif +0 -0
  5. package/docs/anti-patterns/AP-23-skipping-enabled-workflows.md +28 -0
  6. package/docs/anti-patterns/AP-24-clarifier-deciding-scope.md +34 -0
  7. package/docs/concepts/architecture.md +1 -1
  8. package/docs/concepts/roles-and-workflows.md +2 -0
  9. package/docs/concepts/why-wazir.md +59 -0
  10. package/docs/decisions/2026-03-19-deferred-items.md +564 -0
  11. package/docs/decisions/2026-03-19-enhancement-decisions.md +300 -0
  12. package/docs/readmes/INDEX.md +21 -5
  13. package/docs/readmes/features/expertise/README.md +2 -2
  14. package/docs/readmes/features/exports/README.md +2 -2
  15. package/docs/readmes/features/hooks/pre-compact-summary.md +1 -1
  16. package/docs/readmes/features/schemas/README.md +3 -0
  17. package/docs/readmes/features/skills/README.md +17 -0
  18. package/docs/readmes/features/skills/clarifier.md +5 -0
  19. package/docs/readmes/features/skills/claude-cli.md +5 -0
  20. package/docs/readmes/features/skills/codex-cli.md +5 -0
  21. package/docs/readmes/features/skills/dispatching-parallel-agents.md +5 -0
  22. package/docs/readmes/features/skills/executing-plans.md +5 -0
  23. package/docs/readmes/features/skills/executor.md +5 -0
  24. package/docs/readmes/features/skills/finishing-a-development-branch.md +5 -0
  25. package/docs/readmes/features/skills/gemini-cli.md +5 -0
  26. package/docs/readmes/features/skills/humanize.md +5 -0
  27. package/docs/readmes/features/skills/init-pipeline.md +5 -0
  28. package/docs/readmes/features/skills/receiving-code-review.md +5 -0
  29. package/docs/readmes/features/skills/requesting-code-review.md +5 -0
  30. package/docs/readmes/features/skills/reviewer.md +5 -0
  31. package/docs/readmes/features/skills/subagent-driven-development.md +5 -0
  32. package/docs/readmes/features/skills/using-git-worktrees.md +5 -0
  33. package/docs/readmes/features/skills/wazir.md +5 -0
  34. package/docs/readmes/features/skills/writing-skills.md +5 -0
  35. package/docs/readmes/features/workflows/prepare-next.md +1 -1
  36. package/docs/reference/configuration-reference.md +47 -6
  37. package/docs/reference/hooks.md +1 -0
  38. package/docs/reference/launch-checklist.md +4 -4
  39. package/docs/reference/review-loop-pattern.md +119 -9
  40. package/docs/reference/roles-reference.md +1 -0
  41. package/docs/reference/skill-tiers.md +147 -0
  42. package/docs/reference/tooling-cli.md +3 -1
  43. package/docs/truth-claims.yaml +12 -0
  44. package/expertise/antipatterns/process/ai-coding-antipatterns.md +214 -1
  45. package/exports/hosts/claude/.claude/commands/plan-review.md +3 -1
  46. package/exports/hosts/claude/.claude/commands/verify.md +30 -1
  47. package/exports/hosts/claude/.claude/settings.json +9 -0
  48. package/exports/hosts/claude/CLAUDE.md +1 -1
  49. package/exports/hosts/claude/export.manifest.json +6 -4
  50. package/exports/hosts/claude/host-package.json +3 -1
  51. package/exports/hosts/codex/AGENTS.md +1 -1
  52. package/exports/hosts/codex/export.manifest.json +6 -4
  53. package/exports/hosts/codex/host-package.json +3 -1
  54. package/exports/hosts/cursor/.cursor/hooks.json +4 -0
  55. package/exports/hosts/cursor/.cursor/rules/wazir-core.mdc +1 -1
  56. package/exports/hosts/cursor/export.manifest.json +6 -4
  57. package/exports/hosts/cursor/host-package.json +3 -1
  58. package/exports/hosts/gemini/GEMINI.md +1 -1
  59. package/exports/hosts/gemini/export.manifest.json +6 -4
  60. package/exports/hosts/gemini/host-package.json +3 -1
  61. package/hooks/context-mode-router +191 -0
  62. package/hooks/definitions/context_mode_router.yaml +19 -0
  63. package/hooks/hooks.json +31 -6
  64. package/hooks/protected-path-write-guard +8 -0
  65. package/hooks/routing-matrix.json +45 -0
  66. package/hooks/session-start +62 -1
  67. package/llms-full.txt +937 -134
  68. package/package.json +2 -4
  69. package/schemas/hook.schema.json +2 -1
  70. package/schemas/phase-report.schema.json +89 -0
  71. package/schemas/usage.schema.json +25 -1
  72. package/schemas/wazir-manifest.schema.json +19 -0
  73. package/skills/brainstorming/SKILL.md +32 -157
  74. package/skills/clarifier/SKILL.md +289 -111
  75. package/skills/claude-cli/SKILL.md +320 -0
  76. package/skills/codex-cli/SKILL.md +260 -0
  77. package/skills/debugging/SKILL.md +13 -0
  78. package/skills/design/SKILL.md +13 -0
  79. package/skills/dispatching-parallel-agents/SKILL.md +13 -0
  80. package/skills/executing-plans/SKILL.md +13 -0
  81. package/skills/executor/SKILL.md +139 -19
  82. package/skills/finishing-a-development-branch/SKILL.md +13 -0
  83. package/skills/gemini-cli/SKILL.md +260 -0
  84. package/skills/humanize/SKILL.md +13 -0
  85. package/skills/init-pipeline/SKILL.md +72 -164
  86. package/skills/prepare-next/SKILL.md +81 -10
  87. package/skills/receiving-code-review/SKILL.md +13 -0
  88. package/skills/requesting-code-review/SKILL.md +13 -0
  89. package/skills/reviewer/SKILL.md +369 -24
  90. package/skills/run-audit/SKILL.md +13 -0
  91. package/skills/scan-project/SKILL.md +13 -0
  92. package/skills/self-audit/SKILL.md +217 -16
  93. package/skills/skill-research/SKILL.md +188 -0
  94. package/skills/subagent-driven-development/SKILL.md +13 -0
  95. package/skills/subagent-driven-development/code-quality-reviewer-prompt.md +2 -0
  96. package/skills/subagent-driven-development/implementer-prompt.md +8 -0
  97. package/skills/subagent-driven-development/spec-reviewer-prompt.md +7 -0
  98. package/skills/tdd/SKILL.md +13 -0
  99. package/skills/using-git-worktrees/SKILL.md +13 -0
  100. package/skills/using-skills/SKILL.md +13 -0
  101. package/skills/verification/SKILL.md +54 -3
  102. package/skills/wazir/SKILL.md +464 -381
  103. package/skills/writing-plans/SKILL.md +14 -1
  104. package/skills/writing-skills/SKILL.md +13 -0
  105. package/templates/artifacts/implementation-plan.md +3 -0
  106. package/templates/artifacts/tasks-template.md +133 -0
  107. package/templates/examples/phase-report.example.json +48 -0
  108. package/tooling/src/adapters/composition-engine.js +256 -0
  109. package/tooling/src/adapters/model-router.js +84 -0
  110. package/tooling/src/capture/command.js +41 -2
  111. package/tooling/src/capture/run-config.js +3 -1
  112. package/tooling/src/capture/store.js +56 -0
  113. package/tooling/src/capture/usage.js +106 -0
  114. package/tooling/src/capture/user-input.js +66 -0
  115. package/tooling/src/checks/ac-matrix.js +256 -0
  116. package/tooling/src/checks/command-registry.js +12 -0
  117. package/tooling/src/checks/docs-truth.js +1 -1
  118. package/tooling/src/checks/security-sensitivity.js +69 -0
  119. package/tooling/src/checks/skills.js +111 -0
  120. package/tooling/src/cli.js +31 -20
  121. package/tooling/src/commands/stats.js +161 -0
  122. package/tooling/src/commands/validate.js +5 -1
  123. package/tooling/src/export/compiler.js +33 -37
  124. package/tooling/src/gating/agent.js +145 -0
  125. package/tooling/src/guards/phase-prerequisite-guard.js +185 -0
  126. package/tooling/src/hooks/routing-logic.js +69 -0
  127. package/tooling/src/init/auto-detect.js +258 -0
  128. package/tooling/src/init/command.js +38 -170
  129. package/tooling/src/input/scanner.js +46 -0
  130. package/tooling/src/reports/command.js +103 -0
  131. package/tooling/src/reports/phase-report.js +323 -0
  132. package/tooling/src/state/command.js +160 -0
  133. package/tooling/src/state/db.js +287 -0
  134. package/tooling/src/status/command.js +58 -1
  135. package/tooling/src/verify/proof-collector.js +299 -0
  136. package/wazir.manifest.yaml +26 -14
  137. package/workflows/plan-review.md +3 -1
  138. package/workflows/verify.md +30 -1
@@ -1,201 +1,69 @@
1
- import { execFileSync } from 'node:child_process';
2
1
  import fs from 'node:fs';
3
2
  import path from 'node:path';
4
- import { select } from '@inquirer/prompts';
5
3
 
4
+ import { autoInit, detectHost, detectProjectStack } from './auto-detect.js';
5
+
6
+ /**
7
+ * wazir init [--auto|--force]
8
+ *
9
+ * Default: --auto (zero-config, no prompts, infer everything)
10
+ * --force: reinitialize even if already initialized
11
+ */
6
12
  export async function runInitCommand(parsed, context = {}) {
7
13
  const cwd = context.cwd ?? process.cwd();
8
14
  const wazirDir = path.join(cwd, '.wazir');
9
15
  const configPath = path.join(wazirDir, 'state', 'config.json');
16
+ const isForce = parsed.args.includes('--force');
10
17
 
11
- if (fs.existsSync(configPath) && !parsed.args.includes('--force')) {
18
+ // Already initialized check
19
+ if (fs.existsSync(configPath) && !isForce) {
12
20
  return {
13
21
  exitCode: 1,
14
22
  stderr: 'Pipeline already initialized. Use --force to reinitialize.\n',
15
23
  };
16
24
  }
17
25
 
26
+ // Auto mode — zero-config
18
27
  try {
19
- // Create directories
20
- for (const dir of ['input', 'state', 'runs']) {
21
- fs.mkdirSync(path.join(wazirDir, dir), { recursive: true });
22
- }
23
-
24
- // Pipeline mode
25
- const modelMode = await select({
26
- message: 'How should Wazir run in this project?',
27
- choices: [
28
- { name: 'Single model (Recommended) — slash commands only', value: 'claude-only' },
29
- { name: 'Multi-model — routes by complexity (Haiku/Sonnet/Opus)', value: 'multi-model' },
30
- { name: 'Multi-tool — current model + external tools for reviews', value: 'multi-tool' },
31
- ],
32
- default: 'claude-only',
33
- });
34
-
35
- // Multi-tool tools (conditional)
36
- let multiToolTools = [];
37
- if (modelMode === 'multi-tool') {
38
- const toolChoice = await select({
39
- message: 'Which external tools should Wazir use for reviews?',
40
- choices: [
41
- { name: 'Codex — Send reviews to OpenAI Codex', value: 'codex' },
42
- { name: 'Gemini — Send reviews to Google Gemini', value: 'gemini' },
43
- { name: 'Both — Use Codex and Gemini', value: 'both' },
44
- ],
45
- });
46
- multiToolTools = toolChoice === 'both' ? ['codex', 'gemini'] : [toolChoice];
47
- }
48
-
49
- // Codex model (conditional)
50
- let codexModel = null;
51
- if (multiToolTools.includes('codex')) {
52
- codexModel = await select({
53
- message: 'Which Codex model should Wazir use?',
54
- choices: [
55
- { name: 'gpt-5.3-codex-spark (Recommended) — fast, good for review loops', value: 'gpt-5.3-codex-spark' },
56
- { name: 'gpt-5.4 — slower, deeper analysis for complex reviews', value: 'gpt-5.4' },
57
- ],
58
- default: 'gpt-5.3-codex-spark',
59
- });
60
- }
61
-
62
- // Default depth
63
- const defaultDepth = await select({
64
- message: 'What default depth should runs use?',
65
- choices: [
66
- { name: 'Quick — minimal research, single-pass review', value: 'quick' },
67
- { name: 'Standard (Recommended) — balanced research, multi-pass hardening', value: 'standard' },
68
- { name: 'Deep — extended research, strict review thresholds', value: 'deep' },
69
- ],
70
- default: 'standard',
71
- });
72
-
73
- // Default intent
74
- const defaultIntent = await select({
75
- message: 'What kind of work does this project mostly involve?',
76
- choices: [
77
- { name: 'Feature (Recommended) — new functionality or enhancement', value: 'feature' },
78
- { name: 'Bugfix — fix broken behavior', value: 'bugfix' },
79
- { name: 'Refactor — restructure without changing behavior', value: 'refactor' },
80
- { name: 'Docs — documentation only', value: 'docs' },
81
- { name: 'Spike — research and exploration', value: 'spike' },
82
- ],
83
- default: 'feature',
84
- });
85
-
86
- // Agent Teams (conditional)
87
- let teamMode = 'sequential';
88
- let parallelBackend = 'none';
89
-
90
- const depthAllows = defaultDepth === 'standard' || defaultDepth === 'deep';
91
- const intentAllows = defaultIntent === 'feature' || defaultIntent === 'refactor';
28
+ const result = autoInit(cwd, { context, force: isForce });
92
29
 
93
- if (depthAllows && intentAllows) {
94
- const useTeams = await select({
95
- message: 'Would you like to use Agent Teams for parallel execution?',
96
- choices: [
97
- { name: 'No (Recommended) — sequential, predictable, lower cost', value: 'sequential' },
98
- { name: 'Yes — parallel teammates, faster but experimental (Opus only)', value: 'parallel' },
99
- ],
100
- default: 'sequential',
101
- });
102
- teamMode = useTeams;
103
- parallelBackend = useTeams === 'parallel' ? 'claude_teams' : 'none';
104
-
105
- if (teamMode === 'parallel') {
106
- try {
107
- execFileSync('claude', ['config', 'set', 'env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS', '1'], { stdio: 'pipe' });
108
- } catch {
109
- // claude CLI not available — user will need to set it manually
110
- }
111
- }
112
- }
113
-
114
- // Write config
115
- const config = {
116
- model_mode: modelMode,
117
- ...(modelMode === 'multi-tool' && {
118
- multi_tool: {
119
- tools: multiToolTools,
120
- ...(codexModel && { codex: { model: codexModel } }),
121
- },
122
- }),
123
- default_depth: defaultDepth,
124
- default_intent: defaultIntent,
125
- team_mode: teamMode,
126
- parallel_backend: parallelBackend,
127
- };
128
- fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n');
129
-
130
- // Runtime-specific setup
131
- const filesCreated = ['.wazir/input/', '.wazir/state/', '.wazir/runs/', '.wazir/state/config.json'];
132
-
133
- if (multiToolTools.includes('codex')) {
134
- const content = [
135
- '# Wazir Pipeline',
136
- '',
137
- 'Agent protocols are at `~/.claude/agents/` (global).',
138
- '',
139
- '## Running the Pipeline',
140
- '1. Clarifier: read and follow `~/.claude/agents/clarifier.md` — tasks are in `.wazir/input/`',
141
- '2. Orchestrator: read and follow `~/.claude/agents/orchestrator.md` — start from task 1',
142
- '3. Opus Reviewer: read and follow `~/.claude/agents/opus-reviewer.md` — run all phases',
143
- '',
144
- '## Review Mode',
145
- 'This project uses Codex as a secondary reviewer. Review artifacts are in `.wazir/reviews/`.',
146
- '',
147
- ].join('\n');
148
- fs.writeFileSync(path.join(cwd, 'AGENTS.md'), content);
149
- filesCreated.push('AGENTS.md');
30
+ if (result.alreadyInitialized && !isForce) {
31
+ return {
32
+ exitCode: 0,
33
+ stdout: `Already initialized. Host: ${result.host.host}, Stack: ${result.stack.language}\n`,
34
+ };
150
35
  }
151
36
 
152
- if (multiToolTools.includes('gemini')) {
153
- const content = [
154
- '# Wazir Pipeline',
155
- '',
156
- 'Agent protocols are at `~/.claude/agents/` (global).',
157
- '',
158
- '## Running the Pipeline',
159
- '1. Clarifier: read and follow `~/.claude/agents/clarifier.md` tasks are in `.wazir/input/`',
160
- '2. Orchestrator: read and follow `~/.claude/agents/orchestrator.md` — start from task 1',
161
- '3. Opus Reviewer: read and follow `~/.claude/agents/opus-reviewer.md` — run all phases',
162
- '',
163
- '## Review Mode',
164
- 'This project uses Gemini as a secondary reviewer. Review artifacts are in `.wazir/reviews/`.',
165
- '',
166
- ].join('\n');
167
- fs.writeFileSync(path.join(cwd, 'GEMINI.md'), content);
168
- filesCreated.push('GEMINI.md');
37
+ // Auto-export for detected host
38
+ let exportNote = '';
39
+ try {
40
+ const { buildHostExports } = await import('../export/compiler.js');
41
+ buildHostExports(cwd);
42
+ exportNote = ` Exports: generated for ${result.host.host}\n`;
43
+ } catch {
44
+ exportNote = ' Exports: skipped (run `wazir export build` manually)\n';
169
45
  }
170
46
 
171
47
  const lines = [
172
48
  '',
173
- '\u2705 Pipeline initialized!',
174
- '',
175
- ` Mode: ${modelMode}`,
176
- ` Depth: ${defaultDepth}`,
177
- ` Intent: ${defaultIntent}`,
178
- ` Teams: ${teamMode}`,
49
+ 'Wazir initialized (zero-config).',
179
50
  '',
51
+ ` Host: ${result.host.host} (${result.host.confidence} confidence)`,
52
+ ` Stack: ${result.stack.language}${result.stack.framework ? ` / ${result.stack.framework}` : ''}`,
53
+ ` Mode: ${result.config.model_mode}`,
54
+ ` Depth: ${result.config.default_depth}`,
55
+ exportNote,
180
56
  'Files created:',
181
- ...filesCreated.map((f) => ` - ${f}`),
57
+ ...result.filesCreated.map((f) => ` - ${f}`),
58
+ '',
59
+ 'Next: /wazir <what you want to build>',
182
60
  '',
183
- 'You can now use:',
184
- ' /wazir <your request> \u2014 Run the full pipeline',
185
- ' /clarifier \u2014 Research, clarify, plan',
186
- ' /executor \u2014 Autonomous execution',
187
- ' /reviewer \u2014 Final review and scoring',
61
+ 'Override: `wazir config set model_mode multi-tool`',
188
62
  '',
189
63
  ];
190
64
 
191
- return {
192
- exitCode: 0,
193
- stdout: lines.join('\n'),
194
- };
65
+ return { exitCode: 0, stdout: lines.join('\n') };
195
66
  } catch (error) {
196
- if (error.name === 'ExitPromptError') {
197
- return { exitCode: 130, stderr: '\nInit cancelled.\n' };
198
- }
199
- return { exitCode: 1, stderr: `${error.message}\n` };
67
+ return { exitCode: 1, stderr: `Auto-init failed: ${error.message}\n` };
200
68
  }
201
69
  }
@@ -0,0 +1,46 @@
1
+ import { readdirSync, existsSync } from 'node:fs';
2
+ import { join, resolve, basename } from 'node:path';
3
+
4
+ /**
5
+ * Scan input directories for briefing materials.
6
+ * Globs input/*.md and .wazir/input/*.md (flat, not recursive).
7
+ * Excludes README.md.
8
+ *
9
+ * @param {string} projectRoot - Absolute path to project root
10
+ * @returns {Array<{path: string, auto: boolean}>} Found files with auto flag
11
+ */
12
+ export function scanInputDirectories(projectRoot) {
13
+ const root = resolve(projectRoot);
14
+ const dirs = [
15
+ join(root, 'input'),
16
+ join(root, '.wazir', 'input'),
17
+ ];
18
+
19
+ const results = [];
20
+
21
+ for (const dir of dirs) {
22
+ if (!existsSync(dir)) continue;
23
+
24
+ let entries;
25
+ try {
26
+ entries = readdirSync(dir, { withFileTypes: true });
27
+ } catch {
28
+ continue;
29
+ }
30
+
31
+ for (const entry of entries) {
32
+ if (!entry.isFile()) continue;
33
+ if (!entry.name.endsWith('.md')) continue;
34
+ if (basename(entry.name).toLowerCase() === 'readme.md') continue;
35
+
36
+ results.push({ path: join(dir, entry.name), auto: false });
37
+ }
38
+ }
39
+
40
+ // Single file auto-use
41
+ if (results.length === 1) {
42
+ results[0].auto = true;
43
+ }
44
+
45
+ return results;
46
+ }
@@ -0,0 +1,103 @@
1
+ import path from 'node:path';
2
+
3
+ import { parseCommandOptions } from '../command-options.js';
4
+ import { readYamlFile } from '../loaders.js';
5
+ import { findProjectRoot } from '../project-root.js';
6
+ import { resolveStateRoot } from '../state-root.js';
7
+ import { collectPhaseMetrics, buildPhaseReport } from './phase-report.js';
8
+
9
+ const USAGE = 'Usage: wazir report phase --run <run-id> --phase <phase> [--base <branch>] [--json]';
10
+
11
+ function handlePhase(parsed, context = {}) {
12
+ const { options } = parseCommandOptions(parsed.args, {
13
+ boolean: ['json', 'help'],
14
+ string: ['run', 'phase', 'base', 'state-root'],
15
+ });
16
+
17
+ if (options.help) {
18
+ return {
19
+ exitCode: 0,
20
+ stdout: `${USAGE}\n\nGenerate a structured phase report with metrics from git, tests, and run state.\n`,
21
+ };
22
+ }
23
+
24
+ if (!options.run) {
25
+ return {
26
+ exitCode: 1,
27
+ stderr: `wazir report phase requires --run <id>\n${USAGE}\n`,
28
+ };
29
+ }
30
+
31
+ if (!options.phase) {
32
+ return {
33
+ exitCode: 1,
34
+ stderr: `wazir report phase requires --phase <phase>\n${USAGE}\n`,
35
+ };
36
+ }
37
+
38
+ const projectRoot = findProjectRoot(context.cwd ?? process.cwd());
39
+ const manifest = readYamlFile(path.join(projectRoot, 'wazir.manifest.yaml'));
40
+ const stateRoot = resolveStateRoot(projectRoot, manifest, {
41
+ cwd: context.cwd ?? process.cwd(),
42
+ override: options.stateRoot,
43
+ });
44
+
45
+ const metrics = collectPhaseMetrics({
46
+ projectRoot,
47
+ stateRoot,
48
+ runId: options.run,
49
+ phase: options.phase,
50
+ baseBranch: options.base ?? 'main',
51
+ });
52
+
53
+ const report = buildPhaseReport(metrics);
54
+
55
+ if (options.json) {
56
+ return {
57
+ exitCode: 0,
58
+ stdout: `${JSON.stringify(report, null, 2)}\n`,
59
+ };
60
+ }
61
+
62
+ // Human-readable text output
63
+ const lines = [
64
+ `Phase Report: ${report.phase} (run ${report.run_id})`,
65
+ `Generated: ${report.generated_at}`,
66
+ '',
67
+ 'Tests:',
68
+ ` total: ${report.metrics.tests.total}, passed: ${report.metrics.tests.passed}, failed: ${report.metrics.tests.failed}, skipped: ${report.metrics.tests.skipped}`,
69
+ '',
70
+ 'Diff:',
71
+ ` files changed: ${report.metrics.diff.files_changed}, insertions: ${report.metrics.diff.insertions}, deletions: ${report.metrics.diff.deletions}`,
72
+ '',
73
+ 'Files:',
74
+ ` added: ${report.metrics.files.added.length}, modified: ${report.metrics.files.modified.length}, deleted: ${report.metrics.files.deleted.length}`,
75
+ '',
76
+ `Artifacts: ${report.metrics.artifacts.length}`,
77
+ `Duration: ${report.metrics.duration_seconds !== null ? `${report.metrics.duration_seconds}s` : 'N/A'}`,
78
+ ];
79
+
80
+ return {
81
+ exitCode: 0,
82
+ stdout: `${lines.join('\n')}\n`,
83
+ };
84
+ }
85
+
86
+ export function runReportCommand(parsed, context = {}) {
87
+ try {
88
+ switch (parsed.subcommand) {
89
+ case 'phase':
90
+ return handlePhase(parsed, context);
91
+ default:
92
+ return {
93
+ exitCode: 1,
94
+ stderr: `${USAGE}\n`,
95
+ };
96
+ }
97
+ } catch (error) {
98
+ return {
99
+ exitCode: 1,
100
+ stderr: `${error.message}\n`,
101
+ };
102
+ }
103
+ }