refactor(commands): add command contract and migrate shell completion

This commit is contained in:
Tam Nhu Tran committed 2026-02-12 12:59:17 +07:00
1 parent e68ae5b166
commit fc4b77bc52
4 files changed
+300 -30

No files matched your search

@@ -0,0 +1,30 @@
/**
* Command Execution Contract
*
* Standardized lifecycle: parse -> validate -> execute -> render
* for CLI command handlers.
*/
export interface CommandExecutionContract<TParsedArgs, TExecutionResult> {
parse(rawArgs: string[]): TParsedArgs;
validate(parsedArgs: TParsedArgs): void;
execute(parsedArgs: TParsedArgs): Promise<TExecutionResult> | TExecutionResult;
render(
result: TExecutionResult,
context: { rawArgs: string[]; parsedArgs: TParsedArgs }
): Promise<void> | void;
}
/**
* Run a command through the standard lifecycle.
*/
export async function runCommandWithContract<TParsedArgs, TExecutionResult>(
rawArgs: string[],
contract: CommandExecutionContract<TParsedArgs, TExecutionResult>
): Promise<{ parsedArgs: TParsedArgs; result: TExecutionResult }> {
const parsedArgs = contract.parse(rawArgs);
contract.validate(parsedArgs);
const result = await contract.execute(parsedArgs);
await contract.render(result, { rawArgs, parsedArgs });
return { parsedArgs, result };
}
+71 -30
View File
@@ -5,6 +5,75 @@
*/
import { initUI, header, ok, fail, color } from '../utils/ui';
import {
runCommandWithContract,
type CommandExecutionContract,
} from './command-execution-contract';
type ShellTarget = 'bash' | 'zsh' | 'fish' | 'powershell' | null;
interface ShellCompletionParsedArgs {
targetShell: ShellTarget;
force: boolean;
}
interface ShellCompletionInstallResult {
success: boolean;
alreadyInstalled?: boolean;
message?: string;
reload?: string;
}
interface ShellCompletionInstallerLike {
install(
shell: ShellTarget,
options: { force: boolean }
): ShellCompletionInstallResult;
}
export function parseShellCompletionArgs(args: string[]): ShellCompletionParsedArgs {
let targetShell: ShellTarget = null;
const force = args.includes('--force') || args.includes('-f');
if (args.includes('--bash')) targetShell = 'bash';
else if (args.includes('--zsh')) targetShell = 'zsh';
else if (args.includes('--fish')) targetShell = 'fish';
else if (args.includes('--powershell')) targetShell = 'powershell';
return { targetShell, force };
}
export function createShellCompletionCommandContract(
installer: ShellCompletionInstallerLike
): CommandExecutionContract<ShellCompletionParsedArgs, ShellCompletionInstallResult> {
return {
parse: parseShellCompletionArgs,
validate: () => {
// No validation at this stage to preserve existing behavior exactly.
},
execute: (parsed) => installer.install(parsed.targetShell, { force: parsed.force }),
render: (result, context) => {
if (result.alreadyInstalled && !context.parsedArgs.force) {
console.log(ok('Shell completion already installed'));
console.log(` Use ${color('--force', 'warning')} to reinstall`);
console.log('');
return;
}
console.log(ok('Shell completion installed successfully!'));
console.log('');
console.log(result.message);
console.log('');
console.log(color('To activate:', 'info'));
console.log(` ${result.reload}`);
console.log('');
console.log(color('Then test:', 'info'));
console.log(' ccs <TAB> # See available profiles');
console.log(' ccs auth <TAB> # See auth subcommands');
console.log('');
},
};
}
/**
* Handle shell completion command
@@ -16,38 +85,10 @@ export async function handleShellCompletionCommand(args: string[]): Promise<void
console.log(header('Shell Completion Installer'));
console.log('');
// Parse flags
let targetShell: string | null = null;
const force = args.includes('--force') || args.includes('-f');
if (args.includes('--bash')) targetShell = 'bash';
else if (args.includes('--zsh')) targetShell = 'zsh';
else if (args.includes('--fish')) targetShell = 'fish';
else if (args.includes('--powershell')) targetShell = 'powershell';
try {
const installer = new ShellCompletionInstaller();
const result = installer.install(targetShell as 'bash' | 'zsh' | 'fish' | 'powershell' | null, {
force,
});
if (result.alreadyInstalled && !force) {
console.log(ok('Shell completion already installed'));
console.log(` Use ${color('--force', 'warning')} to reinstall`);
console.log('');
return;
}
console.log(ok('Shell completion installed successfully!'));
console.log('');
console.log(result.message);
console.log('');
console.log(color('To activate:', 'info'));
console.log(` ${result.reload}`);
console.log('');
console.log(color('Then test:', 'info'));
console.log(' ccs <TAB> # See available profiles');
console.log(' ccs auth <TAB> # See auth subcommands');
console.log('');
const contract = createShellCompletionCommandContract(installer);
await runCommandWithContract(args, contract);
} catch (error) {
const err = error as Error;
console.error(fail(`Error: ${err.message}`));