feat(cli): add phase dependency and dispatch commands
Add phase command group with dependency management and dispatch operations: - cw phase add-dependency: Create dependency between phases - cw phase dependencies: List dependencies for a phase - cw phase queue: Queue phase for execution - cw phase dispatch: Dispatch next available phase - cw phase queue-status: Show queued, ready, and blocked phases
This commit is contained in:
120
src/cli/index.ts
120
src/cli/index.ts
@@ -824,6 +824,126 @@ export function createCli(serverHandler?: (port?: number) => Promise<void>): Com
|
||||
}
|
||||
});
|
||||
|
||||
// Phase command group
|
||||
const phaseCommand = program
|
||||
.command('phase')
|
||||
.description('Phase dependency and dispatch management');
|
||||
|
||||
// cw phase add-dependency --phase <id> --depends-on <id>
|
||||
phaseCommand
|
||||
.command('add-dependency')
|
||||
.description('Add a dependency between phases')
|
||||
.requiredOption('--phase <id>', 'Phase that depends on another')
|
||||
.requiredOption('--depends-on <id>', 'Phase that must complete first')
|
||||
.action(async (options: { phase: string; dependsOn: string }) => {
|
||||
try {
|
||||
const client = createDefaultTrpcClient();
|
||||
await client.createPhaseDependency.mutate({
|
||||
phaseId: options.phase,
|
||||
dependsOnPhaseId: options.dependsOn,
|
||||
});
|
||||
console.log(`Added dependency: phase ${options.phase} depends on ${options.dependsOn}`);
|
||||
} catch (error) {
|
||||
console.error('Failed to add dependency:', (error as Error).message);
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
|
||||
// cw phase dependencies <phaseId>
|
||||
phaseCommand
|
||||
.command('dependencies <phaseId>')
|
||||
.description('List dependencies for a phase')
|
||||
.action(async (phaseId: string) => {
|
||||
try {
|
||||
const client = createDefaultTrpcClient();
|
||||
const result = await client.getPhaseDependencies.query({ phaseId });
|
||||
if (result.dependencies.length === 0) {
|
||||
console.log('No dependencies');
|
||||
return;
|
||||
}
|
||||
console.log('Dependencies:');
|
||||
for (const dep of result.dependencies) {
|
||||
console.log(` ${dep}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to get dependencies:', (error as Error).message);
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
|
||||
// cw phase queue <phaseId>
|
||||
phaseCommand
|
||||
.command('queue <phaseId>')
|
||||
.description('Queue a phase for execution')
|
||||
.action(async (phaseId: string) => {
|
||||
try {
|
||||
const client = createDefaultTrpcClient();
|
||||
await client.queuePhase.mutate({ phaseId });
|
||||
console.log(`Phase ${phaseId} queued for execution`);
|
||||
} catch (error) {
|
||||
console.error('Failed to queue phase:', (error as Error).message);
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
|
||||
// cw phase dispatch
|
||||
phaseCommand
|
||||
.command('dispatch')
|
||||
.description('Dispatch next available phase')
|
||||
.action(async () => {
|
||||
try {
|
||||
const client = createDefaultTrpcClient();
|
||||
const result = await client.dispatchNextPhase.mutate();
|
||||
if (result.success) {
|
||||
console.log('Phase dispatched successfully');
|
||||
console.log(` Phase: ${result.phaseId}`);
|
||||
} else {
|
||||
console.log('Dispatch failed');
|
||||
console.log(` Phase: ${result.phaseId || '(none)'}`);
|
||||
console.log(` Reason: ${result.reason}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to dispatch phase:', (error as Error).message);
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
|
||||
// cw phase queue-status
|
||||
phaseCommand
|
||||
.command('queue-status')
|
||||
.description('Show phase queue status')
|
||||
.action(async () => {
|
||||
try {
|
||||
const client = createDefaultTrpcClient();
|
||||
const state = await client.getPhaseQueueState.query();
|
||||
|
||||
console.log('Phase Queue Status');
|
||||
console.log('==================');
|
||||
console.log(`Queued: ${state.queued.length}`);
|
||||
console.log(`Ready: ${state.ready.length}`);
|
||||
console.log(`Blocked: ${state.blocked.length}`);
|
||||
|
||||
if (state.ready.length > 0) {
|
||||
console.log('');
|
||||
console.log('Ready phases:');
|
||||
for (const phase of state.ready) {
|
||||
console.log(` ${phase.phaseId}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (state.blocked.length > 0) {
|
||||
console.log('');
|
||||
console.log('Blocked phases:');
|
||||
for (const bp of state.blocked) {
|
||||
console.log(` ${bp.phaseId}: ${bp.reason}`);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to get queue status:', (error as Error).message);
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
|
||||
// Plan command group
|
||||
const planCommand = program
|
||||
.command('plan')
|
||||
|
||||
Reference in New Issue
Block a user