Files
stack/packages/prdy/src/wizard.ts
Jason Woltje f94f9f672b
Some checks failed
ci/woodpecker/push/ci Pipeline failed
feat(prdy): migrate @mosaic/prdy from v0 to v1 (#101)
Co-authored-by: Jason Woltje <jason@diversecanvas.com>
Co-committed-by: Jason Woltje <jason@diversecanvas.com>
2026-03-15 00:44:02 +00:00

104 lines
2.7 KiB
TypeScript

import path from 'node:path';
import { cancel, intro, isCancel, outro, select, text } from '@clack/prompts';
import { createPrd, savePrd } from './prd.js';
import type { CreatePrdOptions, PrdDocument } from './types.js';
interface WizardAnswers {
goals: string;
constraints: string;
milestones: string;
}
function updateSectionField(doc: PrdDocument, sectionKeyword: string, value: string): void {
const section = doc.sections.find((candidate) => candidate.id.includes(sectionKeyword));
if (section === undefined) {
return;
}
const fieldName =
Object.keys(section.fields).find((field) => field.toLowerCase().includes(sectionKeyword)) ??
Object.keys(section.fields)[0];
if (fieldName !== undefined) {
section.fields[fieldName] = value;
}
}
async function promptText(message: string, initialValue = ''): Promise<string> {
const response = await text({
message,
initialValue,
});
if (isCancel(response)) {
cancel('PRD wizard cancelled.');
throw new Error('PRD wizard cancelled');
}
return response.trim();
}
async function promptTemplate(template?: string): Promise<string> {
if (template !== undefined && template.trim().length > 0) {
return template;
}
const choice = await select({
message: 'PRD type',
options: [
{ value: 'software', label: 'Software project' },
{ value: 'feature', label: 'Feature' },
{ value: 'spike', label: 'Research spike' },
],
});
if (isCancel(choice)) {
cancel('PRD wizard cancelled.');
throw new Error('PRD wizard cancelled');
}
return choice;
}
function applyWizardAnswers(doc: PrdDocument, answers: WizardAnswers): PrdDocument {
updateSectionField(doc, 'goal', answers.goals);
updateSectionField(doc, 'constraint', answers.constraints);
updateSectionField(doc, 'milestone', answers.milestones);
doc.updatedAt = new Date().toISOString();
return doc;
}
export async function runPrdWizard(options: CreatePrdOptions): Promise<PrdDocument> {
intro('Mosaic PRD wizard');
const name =
options.name.trim().length > 0 ? options.name.trim() : await promptText('Project name');
const template = await promptTemplate(options.template);
const goals = await promptText('Primary goals');
const constraints = await promptText('Key constraints');
const milestones = await promptText('Planned milestones');
const doc = await createPrd({
...options,
name,
template,
interactive: true,
});
const updated = applyWizardAnswers(doc, {
goals,
constraints,
milestones,
});
await savePrd(updated);
outro(`PRD created: ${path.join(updated.projectPath, 'docs', 'prdy', `${updated.id}.yaml`)}`);
return updated;
}