feat(prd): one transitional PRD authority — RI-4-001 (#1275) (#1294)
ci/woodpecker/push/publish Pipeline was canceled

Co-authored-by: fargo <[email protected]>
This commit was merged in pull request #1294.
This commit is contained in:
2026-08-18 05:56:51 +00:00
committed by jarvis
parent d7e303d3c0
commit d92de53399
12 changed files with 1552 additions and 59 deletions
+74 -14
View File
@@ -1,6 +1,6 @@
import { Command } from 'commander';
import { createPrd, listPrds, loadPrd } from './prd.js';
import { PrdService } from './service.js';
import { runPrdWizard } from './wizard.js';
interface InitCommandOptions {
@@ -18,6 +18,22 @@ interface ShowCommandOptions {
readonly id?: string;
}
interface ImportCommandOptions {
readonly project: string;
readonly file: string;
readonly acceptSuccessor?: boolean;
}
interface ExportCommandOptions {
readonly project: string;
readonly id?: string;
readonly out?: string;
}
function serviceFor(project: string): PrdService {
return new PrdService({ projectPath: project });
}
export function buildPrdyCli(): Command {
const program = new Command();
program.name('mosaic').description('Mosaic CLI').exitOverride();
@@ -38,11 +54,9 @@ export function buildPrdyCli(): Command {
template: options.template,
interactive: true,
})
: await createPrd({
: await serviceFor(options.project).create({
name: options.name,
projectPath: options.project,
template: options.template,
interactive: false,
});
console.log(
@@ -52,6 +66,7 @@ export function buildPrdyCli(): Command {
id: doc.id,
title: doc.title,
status: doc.status,
version: doc.version,
projectPath: doc.projectPath,
},
null,
@@ -65,7 +80,7 @@ export function buildPrdyCli(): Command {
.description('List PRD documents for a project')
.requiredOption('--project <path>', 'Project path')
.action(async (options: ListCommandOptions) => {
const docs = await listPrds(options.project);
const docs = await serviceFor(options.project).list();
console.log(JSON.stringify(docs, null, 2));
});
@@ -75,20 +90,65 @@ export function buildPrdyCli(): Command {
.requiredOption('--project <path>', 'Project path')
.option('--id <id>', 'PRD document id')
.action(async (options: ShowCommandOptions) => {
if (options.id !== undefined) {
const docs = await listPrds(options.project);
const match = docs.find((doc) => doc.id === options.id);
const doc = await serviceFor(options.project).get(options.id);
console.log(JSON.stringify(doc, null, 2));
});
if (match === undefined) {
throw new Error(`PRD id not found: ${options.id}`);
}
prdy
.command('import')
.description('Import a YAML PRD document (validated; conflicts propose a successor)')
.requiredOption('--project <path>', 'Project path')
.requiredOption('--file <file>', 'Path to YAML PRD document')
.option('--accept-successor', 'Accept a conflicted import as the next version')
.action(async (options: ImportCommandOptions) => {
const service = serviceFor(options.project);
const input = { filePath: options.file };
console.log(JSON.stringify(match, null, 2));
if (options.acceptSuccessor) {
const successor = await service.acceptSuccessor(input);
console.log(
JSON.stringify(
{
ok: true,
outcome: 'successor-accepted',
id: successor.id,
version: successor.version,
},
null,
2,
),
);
return;
}
const doc = await loadPrd(options.project);
console.log(JSON.stringify(doc, null, 2));
const result = await service.importDocument(input);
console.log(
JSON.stringify(
{
ok: true,
outcome: result.kind,
id: result.document.id,
version: result.document.version,
status: result.document.status,
},
null,
2,
),
);
});
prdy
.command('export')
.description('Render a PRD to a labeled generated-view Markdown file')
.requiredOption('--project <path>', 'Project path')
.option('--id <id>', 'PRD document id')
.option('--out <path>', 'Output path (default docs/prdy/<id>.md)')
.action(async (options: ExportCommandOptions) => {
const result = await serviceFor(options.project).exportMarkdown({
id: options.id,
outPath: options.out,
});
console.log(JSON.stringify({ ok: true, filePath: result.filePath }, null, 2));
});
return program;