feat(wave3): add @mosaic/cli — unified mosaic CLI entry point

- Root Commander program with version + description
- Subcommand groups: coord, prdy, queue, quality-rails
- Single `mosaic` binary entry point
- Depends on all @mosaic/* workspace packages
This commit is contained in:
2026-03-06 20:22:37 -06:00
parent 7f7109fc09
commit 0193861784
13 changed files with 859 additions and 0 deletions

View File

@@ -0,0 +1,5 @@
#!/usr/bin/env node
import { rootCommand } from '../src/root-command.js';
rootCommand.parseAsync(process.argv);

View File

@@ -0,0 +1,15 @@
import tsParser from '@typescript-eslint/parser';
export default [
{
files: ['src/**/*.ts', 'bin/**/*.ts', 'tests/**/*.ts'],
languageOptions: {
parser: tsParser,
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
},
},
rules: {},
},
];

33
packages/cli/package.json Normal file
View File

@@ -0,0 +1,33 @@
{
"name": "@mosaic/cli",
"version": "0.1.0",
"type": "module",
"description": "Mosaic unified CLI — the mosaic command",
"bin": {
"mosaic": "./dist/bin/mosaic.js"
},
"scripts": {
"build": "tsc -p tsconfig.json",
"typecheck": "tsc --noEmit",
"lint": "eslint src/",
"test": "vitest run"
},
"dependencies": {
"@mosaic/types": "workspace:*",
"@mosaic/coord": "workspace:*",
"@mosaic/queue": "workspace:*",
"commander": "^13",
"picocolors": "^1.1"
},
"devDependencies": {
"@types/node": "^22",
"@typescript-eslint/parser": "^8",
"eslint": "^9",
"typescript": "^5",
"vitest": "^2"
},
"publishConfig": {
"registry": "https://git.mosaicstack.dev/api/packages/mosaic/npm",
"access": "public"
}
}

View File

@@ -0,0 +1,15 @@
import { Command } from 'commander';
import { buildCoordCli } from '@mosaic/coord/dist/cli.js';
const COMMAND_NAME = 'coord';
export function registerCoordCommand(program: Command): void {
const coordCommand = buildCoordCli().commands.find((command) => command.name() === COMMAND_NAME);
if (coordCommand === undefined) {
throw new Error('Expected @mosaic/coord to expose a "coord" command.');
}
program.addCommand(coordCommand);
}

View File

@@ -0,0 +1,13 @@
import { Command } from 'commander';
import pc from 'picocolors';
// TODO(wave3): Replace this temporary shim once @mosaic/prdy lands in main.
export function registerPrdyCommand(program: Command): void {
program
.command('prdy')
.description('PRD workflow commands')
.action(() => {
console.error(pc.yellow('@mosaic/prdy CLI is not available in this workspace yet.'));
process.exitCode = 1;
});
}

View File

@@ -0,0 +1,15 @@
import { Command } from 'commander';
import pc from 'picocolors';
// TODO(wave3): Replace this temporary shim once @mosaic/quality-rails lands in main.
export function registerQualityRailsCommand(program: Command): void {
program
.command('quality-rails')
.description('Quality rail commands')
.action(() => {
console.error(
pc.yellow('@mosaic/quality-rails CLI is not available in this workspace yet.'),
);
process.exitCode = 1;
});
}

View File

@@ -0,0 +1,15 @@
import { Command } from 'commander';
import { buildQueueCli } from '@mosaic/queue';
const COMMAND_NAME = 'queue';
export function registerQueueCommand(program: Command): void {
const queueCommand = buildQueueCli().commands.find((command) => command.name() === COMMAND_NAME);
if (queueCommand === undefined) {
throw new Error('Expected @mosaic/queue to expose a "queue" command.');
}
program.addCommand(queueCommand);
}

View File

@@ -0,0 +1 @@
export { rootCommand } from './root-command.js';

View File

@@ -0,0 +1,17 @@
import { Command } from 'commander';
import { registerCoordCommand } from './commands/coord.js';
import { registerPrdyCommand } from './commands/prdy.js';
import { registerQualityRailsCommand } from './commands/quality-rails.js';
import { registerQueueCommand } from './commands/queue.js';
import { VERSION } from './version.js';
export const rootCommand = new Command()
.name('mosaic')
.version(VERSION)
.description('Mosaic — AI agent orchestration platform');
registerCoordCommand(rootCommand);
registerPrdyCommand(rootCommand);
registerQueueCommand(rootCommand);
registerQualityRailsCommand(rootCommand);

View File

@@ -0,0 +1 @@
export const VERSION = '0.1.0';

View File

@@ -0,0 +1,18 @@
import { describe, expect, it } from 'vitest';
import { rootCommand } from '../src/root-command.js';
describe('rootCommand', () => {
it('registers all top-level subcommand groups', () => {
const registeredSubcommands = rootCommand.commands
.map((command) => command.name())
.sort((left, right) => left.localeCompare(right));
expect(registeredSubcommands).toEqual([
'coord',
'prdy',
'quality-rails',
'queue',
]);
});
});

View File

@@ -0,0 +1,5 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": { "outDir": "dist", "rootDir": "." },
"include": ["src", "bin"]
}

706
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff