feat: complete CLI command parity — add coord, prdy, seq, upgrade
The #351 merge landed before the force-push with full commands. This adds the missing subcommands: - mosaic coord {init,status,mission,continue,run,smoke,resume} → delegates to tools/orchestrator/*.sh with --claude/--codex/--pi/--yolo - mosaic prdy {init,update,validate,status} → delegates to tools/prdy/*.sh with --claude/--codex/--pi - mosaic seq {check,fix,start} → sequential-thinking MCP management (native TS) - mosaic upgrade {release,check,project} → delegates to tools/_scripts/mosaic-release-upgrade and mosaic-upgrade Also removes duplicate prdy registration (was in both launch.ts and the old registerPrdyCommand — now only in launch.ts).
This commit is contained in:
@@ -461,23 +461,191 @@ function execRuntime(cmd: string, args: string[]): void {
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Framework script delegation (for tools that remain in bash) ─────────────
|
||||
// ─── Framework script/tool delegation ───────────────────────────────────────
|
||||
|
||||
function delegateToFrameworkScript(script: string, args: string[]): never {
|
||||
const scriptPath = join(MOSAIC_HOME, 'tools', '_scripts', script);
|
||||
function delegateToScript(scriptPath: string, args: string[], env?: Record<string, string>): never {
|
||||
if (!existsSync(scriptPath)) {
|
||||
console.error(`[mosaic] Script not found: ${scriptPath}`);
|
||||
process.exit(1);
|
||||
}
|
||||
try {
|
||||
execFileSync(scriptPath, args, { stdio: 'inherit' });
|
||||
execFileSync('bash', [scriptPath, ...args], {
|
||||
stdio: 'inherit',
|
||||
env: { ...process.env, ...env },
|
||||
});
|
||||
process.exit(0);
|
||||
} catch (err) {
|
||||
process.exit((err as { status?: number }).status ?? 1);
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Commander registration ──────────────────────────────────────────────────
|
||||
function fwScript(name: string): string {
|
||||
return join(MOSAIC_HOME, 'tools', '_scripts', name);
|
||||
}
|
||||
|
||||
function toolScript(toolDir: string, name: string): string {
|
||||
return join(MOSAIC_HOME, 'tools', toolDir, name);
|
||||
}
|
||||
|
||||
// ─── Coord (mission orchestrator) ───────────────────────────────────────────
|
||||
|
||||
const COORD_SUBCMDS: Record<string, string> = {
|
||||
status: 'session-status.sh',
|
||||
session: 'session-status.sh',
|
||||
init: 'mission-init.sh',
|
||||
mission: 'mission-status.sh',
|
||||
progress: 'mission-status.sh',
|
||||
continue: 'continue-prompt.sh',
|
||||
next: 'continue-prompt.sh',
|
||||
run: 'session-run.sh',
|
||||
start: 'session-run.sh',
|
||||
smoke: 'smoke-test.sh',
|
||||
test: 'smoke-test.sh',
|
||||
resume: 'session-resume.sh',
|
||||
recover: 'session-resume.sh',
|
||||
};
|
||||
|
||||
function runCoord(args: string[]): never {
|
||||
checkMosaicHome();
|
||||
let runtime = 'claude';
|
||||
let yoloFlag = '';
|
||||
const coordArgs: string[] = [];
|
||||
|
||||
for (const arg of args) {
|
||||
if (arg === '--claude' || arg === '--codex' || arg === '--pi') {
|
||||
runtime = arg.slice(2);
|
||||
} else if (arg === '--yolo') {
|
||||
yoloFlag = '--yolo';
|
||||
} else {
|
||||
coordArgs.push(arg);
|
||||
}
|
||||
}
|
||||
|
||||
const subcmd = coordArgs[0] ?? 'help';
|
||||
const subArgs = coordArgs.slice(1);
|
||||
const script = COORD_SUBCMDS[subcmd];
|
||||
|
||||
if (!script) {
|
||||
console.log(`mosaic coord — mission coordinator tools
|
||||
|
||||
Commands:
|
||||
init --name <name> [opts] Initialize a new mission
|
||||
mission [--project <path>] Show mission progress dashboard
|
||||
status [--project <path>] Check agent session health
|
||||
continue [--project <path>] Generate continuation prompt
|
||||
run [--project <path>] Launch runtime with mission context
|
||||
smoke Run orchestration smoke checks
|
||||
resume [--project <path>] Crash recovery
|
||||
|
||||
Runtime: --claude (default) | --codex | --pi | --yolo`);
|
||||
process.exit(subcmd === 'help' ? 0 : 1);
|
||||
}
|
||||
|
||||
if (yoloFlag) subArgs.unshift(yoloFlag);
|
||||
delegateToScript(toolScript('orchestrator', script), subArgs, {
|
||||
MOSAIC_COORD_RUNTIME: runtime,
|
||||
});
|
||||
}
|
||||
|
||||
// ─── Prdy (PRD tools via framework scripts) ─────────────────────────────────
|
||||
|
||||
const PRDY_SUBCMDS: Record<string, string> = {
|
||||
init: 'prdy-init.sh',
|
||||
update: 'prdy-update.sh',
|
||||
validate: 'prdy-validate.sh',
|
||||
check: 'prdy-validate.sh',
|
||||
status: 'prdy-status.sh',
|
||||
};
|
||||
|
||||
function runPrdyLocal(args: string[]): never {
|
||||
checkMosaicHome();
|
||||
let runtime = 'claude';
|
||||
const prdyArgs: string[] = [];
|
||||
|
||||
for (const arg of args) {
|
||||
if (arg === '--claude' || arg === '--codex' || arg === '--pi') {
|
||||
runtime = arg.slice(2);
|
||||
} else {
|
||||
prdyArgs.push(arg);
|
||||
}
|
||||
}
|
||||
|
||||
const subcmd = prdyArgs[0] ?? 'help';
|
||||
const subArgs = prdyArgs.slice(1);
|
||||
const script = PRDY_SUBCMDS[subcmd];
|
||||
|
||||
if (!script) {
|
||||
console.log(`mosaic prdy — PRD creation and validation
|
||||
|
||||
Commands:
|
||||
init [--project <path>] [--name <feature>] Create docs/PRD.md
|
||||
update [--project <path>] Update existing PRD
|
||||
validate [--project <path>] Check PRD completeness
|
||||
status [--project <path>] Quick PRD health check
|
||||
|
||||
Runtime: --claude (default) | --codex | --pi`);
|
||||
process.exit(subcmd === 'help' ? 0 : 1);
|
||||
}
|
||||
|
||||
delegateToScript(toolScript('prdy', script), subArgs, {
|
||||
MOSAIC_PRDY_RUNTIME: runtime,
|
||||
});
|
||||
}
|
||||
|
||||
// ─── Seq (sequential-thinking MCP) ──────────────────────────────────────────
|
||||
|
||||
function runSeq(args: string[]): never {
|
||||
checkMosaicHome();
|
||||
const action = args[0] ?? 'check';
|
||||
const rest = args.slice(1);
|
||||
const checker = fwScript('mosaic-ensure-sequential-thinking');
|
||||
|
||||
switch (action) {
|
||||
case 'check':
|
||||
delegateToScript(checker, ['--check', ...rest]);
|
||||
break; // unreachable
|
||||
case 'fix':
|
||||
case 'apply':
|
||||
delegateToScript(checker, rest);
|
||||
break;
|
||||
case 'start': {
|
||||
console.log('[mosaic] Starting sequential-thinking MCP server...');
|
||||
try {
|
||||
execFileSync('npx', ['-y', '@modelcontextprotocol/server-sequential-thinking', ...rest], {
|
||||
stdio: 'inherit',
|
||||
});
|
||||
process.exit(0);
|
||||
} catch (err) {
|
||||
process.exit((err as { status?: number }).status ?? 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
console.error(`[mosaic] Unknown seq subcommand '${action}'. Use: check|fix|start`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Upgrade ────────────────────────────────────────────────────────────────
|
||||
|
||||
function runUpgrade(args: string[]): never {
|
||||
checkMosaicHome();
|
||||
const subcmd = args[0];
|
||||
|
||||
if (!subcmd || subcmd === 'release') {
|
||||
delegateToScript(fwScript('mosaic-release-upgrade'), args.slice(subcmd === 'release' ? 1 : 0));
|
||||
} else if (subcmd === 'check') {
|
||||
delegateToScript(fwScript('mosaic-release-upgrade'), ['--dry-run', ...args.slice(1)]);
|
||||
} else if (subcmd === 'project') {
|
||||
delegateToScript(fwScript('mosaic-upgrade'), args.slice(1));
|
||||
} else if (subcmd.startsWith('-')) {
|
||||
delegateToScript(fwScript('mosaic-release-upgrade'), args);
|
||||
} else {
|
||||
delegateToScript(fwScript('mosaic-upgrade'), args);
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Commander registration ─────────────────────────────────────────────────
|
||||
|
||||
export function registerLaunchCommands(program: Command): void {
|
||||
// Runtime launchers
|
||||
@@ -509,15 +677,58 @@ export function registerLaunchCommands(program: Command): void {
|
||||
launchRuntime(runtime as RuntimeName, cmd.args, true);
|
||||
});
|
||||
|
||||
// Framework management commands (delegate to bash scripts)
|
||||
const frameworkCommands: Record<string, { desc: string; script: string }> = {
|
||||
// Coord (mission orchestrator)
|
||||
program
|
||||
.command('coord')
|
||||
.description('Mission coordinator tools (init, status, run, continue, resume)')
|
||||
.allowUnknownOption(true)
|
||||
.allowExcessArguments(true)
|
||||
.action((_opts: unknown, cmd: Command) => {
|
||||
runCoord(cmd.args);
|
||||
});
|
||||
|
||||
// Prdy (PRD tools via local framework scripts)
|
||||
program
|
||||
.command('prdy')
|
||||
.description('PRD creation and validation (init, update, validate, status)')
|
||||
.allowUnknownOption(true)
|
||||
.allowExcessArguments(true)
|
||||
.action((_opts: unknown, cmd: Command) => {
|
||||
runPrdyLocal(cmd.args);
|
||||
});
|
||||
|
||||
// Seq (sequential-thinking MCP management)
|
||||
program
|
||||
.command('seq')
|
||||
.description('sequential-thinking MCP management (check/fix/start)')
|
||||
.allowUnknownOption(true)
|
||||
.allowExcessArguments(true)
|
||||
.action((_opts: unknown, cmd: Command) => {
|
||||
runSeq(cmd.args);
|
||||
});
|
||||
|
||||
// Upgrade (release + project)
|
||||
program
|
||||
.command('upgrade')
|
||||
.description('Upgrade Mosaic release or project files')
|
||||
.allowUnknownOption(true)
|
||||
.allowExcessArguments(true)
|
||||
.action((_opts: unknown, cmd: Command) => {
|
||||
runUpgrade(cmd.args);
|
||||
});
|
||||
|
||||
// Direct framework script delegates
|
||||
const directCommands: Record<string, { desc: string; script: string }> = {
|
||||
init: { desc: 'Generate SOUL.md (agent identity contract)', script: 'mosaic-init' },
|
||||
doctor: { desc: 'Health audit — detect drift and missing files', script: 'mosaic-doctor' },
|
||||
sync: { desc: 'Sync skills from canonical source', script: 'mosaic-sync-skills' },
|
||||
bootstrap: { desc: 'Bootstrap a repo with Mosaic standards', script: 'mosaic-bootstrap-repo' },
|
||||
bootstrap: {
|
||||
desc: 'Bootstrap a repo with Mosaic standards',
|
||||
script: 'mosaic-bootstrap-repo',
|
||||
},
|
||||
};
|
||||
|
||||
for (const [name, { desc, script }] of Object.entries(frameworkCommands)) {
|
||||
for (const [name, { desc, script }] of Object.entries(directCommands)) {
|
||||
program
|
||||
.command(name)
|
||||
.description(desc)
|
||||
@@ -525,7 +736,7 @@ export function registerLaunchCommands(program: Command): void {
|
||||
.allowExcessArguments(true)
|
||||
.action((_opts: unknown, cmd: Command) => {
|
||||
checkMosaicHome();
|
||||
delegateToFrameworkScript(script, cmd.args);
|
||||
delegateToScript(fwScript(script), cmd.args);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user