2 Commits

Author SHA1 Message Date
494da37cb8 feat(wave3): add @mosaic/quality-rails — TypeScript code quality scaffolder
- Project detection: detectProjectKind (node/python/rust/unknown)
- Scaffolder: writes ESLint/Biome/pre-commit configs based on profile
- Embedded templates for strict/standard/minimal profiles
- CLI: quality-rails init | check | doctor
- Depends on @mosaic/types workspace:*
2026-03-06 20:24:20 -06:00
8371783587 feat(wave3): @mosaic/cli unified CLI entry point (#9)
Co-authored-by: Jason Woltje <jason@diversecanvas.com>
Co-committed-by: Jason Woltje <jason@diversecanvas.com>
2026-03-07 02:23:03 +00:00
13 changed files with 187 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"]
}

34
pnpm-lock.yaml generated
View File

@@ -21,6 +21,40 @@ importers:
specifier: ^5
version: 5.9.3
packages/cli:
dependencies:
'@mosaic/coord':
specifier: workspace:*
version: link:../coord
'@mosaic/queue':
specifier: workspace:*
version: link:../queue
'@mosaic/types':
specifier: workspace:*
version: link:../types
commander:
specifier: ^13
version: 13.1.0
picocolors:
specifier: ^1.1
version: 1.1.1
devDependencies:
'@types/node':
specifier: ^22
version: 22.19.15
'@typescript-eslint/parser':
specifier: ^8
version: 8.56.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)
eslint:
specifier: ^9
version: 9.39.4(jiti@2.6.1)
typescript:
specifier: ^5
version: 5.9.3
vitest:
specifier: ^2
version: 2.1.9(@types/node@22.19.15)
packages/coord:
dependencies:
'@mosaic/queue':