@fractary/faber-cli 1.6.1 → 1.6.3

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.
@@ -1 +1 @@
1
- {"version":3,"file":"runs.d.ts","sourceRoot":"","sources":["../../src/commands/runs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAYpC,wBAAgB,iBAAiB,IAAI,OAAO,CA0I3C"}
1
+ {"version":3,"file":"runs.d.ts","sourceRoot":"","sources":["../../src/commands/runs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAapC,wBAAgB,iBAAiB,IAAI,OAAO,CAoM3C"}
@@ -12,6 +12,7 @@
12
12
  * - Contains the run ID of the currently active workflow in this worktree
13
13
  */
14
14
  import { Command } from 'commander';
15
+ import * as fs from 'fs';
15
16
  import { FABER_RUNS_DIR, ACTIVE_RUN_ID_FILE, getRunsDir, getRunDir, getPlanPath, getStatePath, getActiveRunIdPath, RELATIVE_PATHS, } from '@fractary/faber';
16
17
  export function createRunsCommand() {
17
18
  const runsCmd = new Command('runs')
@@ -150,5 +151,61 @@ export function createRunsCommand() {
150
151
  console.log(` Active Run ID File: ${RELATIVE_PATHS.ACTIVE_RUN_ID_FILE}`);
151
152
  }
152
153
  });
154
+ runsCmd
155
+ .command('verify-complete')
156
+ .description('Verify that all phases and steps in a run are completed or skipped')
157
+ .argument('<run_id>', 'Run ID to verify')
158
+ .option('--json', 'Output as JSON')
159
+ .action((runId, options) => {
160
+ try {
161
+ const statePath = getStatePath(runId);
162
+ if (!fs.existsSync(statePath)) {
163
+ console.error(`Error: State file not found: ${statePath}`);
164
+ process.exit(2);
165
+ }
166
+ const state = JSON.parse(fs.readFileSync(statePath, 'utf-8'));
167
+ const pending = [];
168
+ // Check each phase and its steps
169
+ if (state.phases && typeof state.phases === 'object') {
170
+ for (const [phaseName, phase] of Object.entries(state.phases)) {
171
+ if (phase.enabled === false)
172
+ continue;
173
+ if (phase.steps && typeof phase.steps === 'object') {
174
+ for (const [stepId, step] of Object.entries(phase.steps)) {
175
+ const status = step.status || 'pending';
176
+ if (status !== 'completed' && status !== 'success' && status !== 'skipped') {
177
+ pending.push(`${phaseName}:${stepId} (${status})`);
178
+ }
179
+ }
180
+ }
181
+ else {
182
+ // Phase without steps — check phase-level status
183
+ const phaseStatus = phase.status || 'pending';
184
+ if (phaseStatus !== 'completed' && phaseStatus !== 'success' && phaseStatus !== 'skipped') {
185
+ pending.push(`${phaseName} (${phaseStatus})`);
186
+ }
187
+ }
188
+ }
189
+ }
190
+ const pass = pending.length === 0;
191
+ if (options.json) {
192
+ console.log(JSON.stringify({ pass, pending }, null, 2));
193
+ }
194
+ else if (pass) {
195
+ console.log('✓ All phases and steps are completed');
196
+ }
197
+ else {
198
+ console.log(`✗ ${pending.length} item(s) still pending:`);
199
+ for (const item of pending) {
200
+ console.log(` - ${item}`);
201
+ }
202
+ }
203
+ process.exit(pass ? 0 : 1);
204
+ }
205
+ catch (error) {
206
+ console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
207
+ process.exit(2);
208
+ }
209
+ });
153
210
  return runsCmd;
154
211
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fractary/faber-cli",
3
- "version": "1.6.1",
3
+ "version": "1.6.3",
4
4
  "description": "FABER CLI - Command-line interface for FABER development toolkit",
5
5
  "main": "dist/index.js",
6
6
  "bin": {