Compare commits
2 Commits
mosaic-v0.
...
0c431371b0
| Author | SHA1 | Date | |
|---|---|---|---|
| 0c431371b0 | |||
| 5e3634ba09 |
@@ -15,7 +15,15 @@
|
||||
"typecheck": "tsc --noEmit",
|
||||
"test": "vitest run --passWithNoTests"
|
||||
},
|
||||
"dependencies": {
|
||||
"@clack/prompts": "^0.9.0",
|
||||
"commander": "^12.0.0",
|
||||
"js-yaml": "^4.1.0",
|
||||
"zod": "^3.22.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/js-yaml": "^4.0.9",
|
||||
"@types/node": "^22.0.0",
|
||||
"typescript": "^5.8.0",
|
||||
"vitest": "^2.0.0"
|
||||
}
|
||||
|
||||
100
packages/prdy/src/cli.ts
Normal file
100
packages/prdy/src/cli.ts
Normal file
@@ -0,0 +1,100 @@
|
||||
import { Command } from 'commander';
|
||||
|
||||
import { createPrd, listPrds, loadPrd } from './prd.js';
|
||||
import { runPrdWizard } from './wizard.js';
|
||||
|
||||
interface InitCommandOptions {
|
||||
readonly name: string;
|
||||
readonly project: string;
|
||||
readonly template?: 'software' | 'feature' | 'spike';
|
||||
}
|
||||
|
||||
interface ListCommandOptions {
|
||||
readonly project: string;
|
||||
}
|
||||
|
||||
interface ShowCommandOptions {
|
||||
readonly project: string;
|
||||
readonly id?: string;
|
||||
}
|
||||
|
||||
export function buildPrdyCli(): Command {
|
||||
const program = new Command();
|
||||
program.name('mosaic').description('Mosaic CLI').exitOverride();
|
||||
|
||||
const prdy = program.command('prdy').description('PRD wizard commands');
|
||||
|
||||
prdy
|
||||
.command('init')
|
||||
.description('Create a PRD document')
|
||||
.requiredOption('--name <name>', 'PRD name')
|
||||
.requiredOption('--project <path>', 'Project path')
|
||||
.option('--template <template>', 'Template (software|feature|spike)')
|
||||
.action(async (options: InitCommandOptions) => {
|
||||
const doc = process.stdout.isTTY
|
||||
? await runPrdWizard({
|
||||
name: options.name,
|
||||
projectPath: options.project,
|
||||
template: options.template,
|
||||
interactive: true,
|
||||
})
|
||||
: await createPrd({
|
||||
name: options.name,
|
||||
projectPath: options.project,
|
||||
template: options.template,
|
||||
interactive: false,
|
||||
});
|
||||
|
||||
console.log(
|
||||
JSON.stringify(
|
||||
{
|
||||
ok: true,
|
||||
id: doc.id,
|
||||
title: doc.title,
|
||||
status: doc.status,
|
||||
projectPath: doc.projectPath,
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
prdy
|
||||
.command('list')
|
||||
.description('List PRD documents for a project')
|
||||
.requiredOption('--project <path>', 'Project path')
|
||||
.action(async (options: ListCommandOptions) => {
|
||||
const docs = await listPrds(options.project);
|
||||
console.log(JSON.stringify(docs, null, 2));
|
||||
});
|
||||
|
||||
prdy
|
||||
.command('show')
|
||||
.description('Show a PRD document')
|
||||
.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);
|
||||
|
||||
if (match === undefined) {
|
||||
throw new Error(`PRD id not found: ${options.id}`);
|
||||
}
|
||||
|
||||
console.log(JSON.stringify(match, null, 2));
|
||||
return;
|
||||
}
|
||||
|
||||
const doc = await loadPrd(options.project);
|
||||
console.log(JSON.stringify(doc, null, 2));
|
||||
});
|
||||
|
||||
return program;
|
||||
}
|
||||
|
||||
export async function runPrdyCli(argv: readonly string[] = process.argv): Promise<void> {
|
||||
const program = buildPrdyCli();
|
||||
await program.parseAsync(argv);
|
||||
}
|
||||
@@ -1 +1,12 @@
|
||||
export const VERSION = '0.0.0';
|
||||
export { createPrd, loadPrd, savePrd, listPrds } from './prd.js';
|
||||
export { runPrdWizard } from './wizard.js';
|
||||
export { buildPrdyCli, runPrdyCli } from './cli.js';
|
||||
export { BUILTIN_PRD_TEMPLATES, resolveTemplate } from './templates.js';
|
||||
export type {
|
||||
PrdStatus,
|
||||
PrdTemplate,
|
||||
PrdTemplateSection,
|
||||
PrdSection,
|
||||
PrdDocument,
|
||||
CreatePrdOptions,
|
||||
} from './types.js';
|
||||
|
||||
199
packages/prdy/src/prd.ts
Normal file
199
packages/prdy/src/prd.ts
Normal file
@@ -0,0 +1,199 @@
|
||||
import { type Dirent, promises as fs } from 'node:fs';
|
||||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
|
||||
import yaml from 'js-yaml';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { resolveTemplate } from './templates.js';
|
||||
import type { CreatePrdOptions, PrdDocument } from './types.js';
|
||||
|
||||
const PRD_DIRECTORY = path.join('docs', 'prdy');
|
||||
const PRD_FILE_EXTENSIONS = new Set(['.yaml', '.yml']);
|
||||
|
||||
const prdSectionSchema = z.object({
|
||||
id: z.string().min(1),
|
||||
title: z.string().min(1),
|
||||
fields: z.record(z.string(), z.string()),
|
||||
});
|
||||
|
||||
const prdDocumentSchema = z.object({
|
||||
id: z.string().min(1),
|
||||
title: z.string().min(1),
|
||||
status: z.enum(['draft', 'review', 'approved', 'archived']),
|
||||
projectPath: z.string().min(1),
|
||||
template: z.string().min(1),
|
||||
sections: z.array(prdSectionSchema),
|
||||
createdAt: z.string().datetime(),
|
||||
updatedAt: z.string().datetime(),
|
||||
});
|
||||
|
||||
function expandHome(projectPath: string): string {
|
||||
if (!projectPath.startsWith('~')) {
|
||||
return projectPath;
|
||||
}
|
||||
|
||||
if (projectPath === '~') {
|
||||
return os.homedir();
|
||||
}
|
||||
|
||||
if (projectPath.startsWith('~/')) {
|
||||
return path.join(os.homedir(), projectPath.slice(2));
|
||||
}
|
||||
|
||||
return projectPath;
|
||||
}
|
||||
|
||||
function resolveProjectPath(projectPath: string): string {
|
||||
return path.resolve(expandHome(projectPath));
|
||||
}
|
||||
|
||||
function toSlug(value: string): string {
|
||||
return value
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9]+/g, '-')
|
||||
.replace(/^-+|-+$/g, '')
|
||||
.replace(/-{2,}/g, '-');
|
||||
}
|
||||
|
||||
function buildTimestamp(date: Date): { datePart: string; timePart: string } {
|
||||
const iso = date.toISOString();
|
||||
return {
|
||||
datePart: iso.slice(0, 10).replace(/-/g, ''),
|
||||
timePart: iso.slice(11, 19).replace(/:/g, ''),
|
||||
};
|
||||
}
|
||||
|
||||
function buildPrdId(name: string): string {
|
||||
const slug = toSlug(name);
|
||||
const { datePart, timePart } = buildTimestamp(new Date());
|
||||
return `${slug || 'prd'}-${datePart}-${timePart}`;
|
||||
}
|
||||
|
||||
function prdDirectory(projectPath: string): string {
|
||||
return path.join(projectPath, PRD_DIRECTORY);
|
||||
}
|
||||
|
||||
function prdFilePath(projectPath: string, id: string): string {
|
||||
return path.join(prdDirectory(projectPath), `${id}.yaml`);
|
||||
}
|
||||
|
||||
function isNodeErrorWithCode(error: unknown, code: string): boolean {
|
||||
return (
|
||||
typeof error === 'object' &&
|
||||
error !== null &&
|
||||
'code' in error &&
|
||||
(error as { code?: string }).code === code
|
||||
);
|
||||
}
|
||||
|
||||
async function writeFileAtomic(filePath: string, content: string): Promise<void> {
|
||||
const directory = path.dirname(filePath);
|
||||
await fs.mkdir(directory, { recursive: true });
|
||||
|
||||
const tempPath = path.join(
|
||||
directory,
|
||||
`.${path.basename(filePath)}.tmp-${process.pid}-${Date.now()}-${Math.random()
|
||||
.toString(16)
|
||||
.slice(2)}`,
|
||||
);
|
||||
|
||||
await fs.writeFile(tempPath, content, 'utf8');
|
||||
await fs.rename(tempPath, filePath);
|
||||
}
|
||||
|
||||
export async function createPrd(options: CreatePrdOptions): Promise<PrdDocument> {
|
||||
const resolvedProjectPath = resolveProjectPath(options.projectPath);
|
||||
const template = resolveTemplate(options.template);
|
||||
const now = new Date().toISOString();
|
||||
|
||||
const document: PrdDocument = {
|
||||
id: buildPrdId(options.name),
|
||||
title: options.name.trim(),
|
||||
status: 'draft',
|
||||
projectPath: resolvedProjectPath,
|
||||
template: template.id,
|
||||
sections: template.sections.map((section) => ({
|
||||
id: section.id,
|
||||
title: section.title,
|
||||
fields: Object.fromEntries(section.fields.map((field) => [field, ''])),
|
||||
})),
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
};
|
||||
|
||||
await savePrd(document);
|
||||
return document;
|
||||
}
|
||||
|
||||
export async function loadPrd(projectPath: string): Promise<PrdDocument> {
|
||||
const documents = await listPrds(projectPath);
|
||||
if (documents.length === 0) {
|
||||
const resolvedProjectPath = resolveProjectPath(projectPath);
|
||||
throw new Error(`No PRD documents found in ${prdDirectory(resolvedProjectPath)}`);
|
||||
}
|
||||
|
||||
return documents[0]!;
|
||||
}
|
||||
|
||||
export async function savePrd(doc: PrdDocument): Promise<void> {
|
||||
const normalized = prdDocumentSchema.parse({
|
||||
...doc,
|
||||
projectPath: resolveProjectPath(doc.projectPath),
|
||||
});
|
||||
|
||||
const filePath = prdFilePath(normalized.projectPath, normalized.id);
|
||||
const serialized = yaml.dump(normalized, {
|
||||
noRefs: true,
|
||||
sortKeys: false,
|
||||
lineWidth: 120,
|
||||
});
|
||||
|
||||
const content = serialized.endsWith('\n') ? serialized : `${serialized}\n`;
|
||||
await writeFileAtomic(filePath, content);
|
||||
}
|
||||
|
||||
export async function listPrds(projectPath: string): Promise<PrdDocument[]> {
|
||||
const resolvedProjectPath = resolveProjectPath(projectPath);
|
||||
const directory = prdDirectory(resolvedProjectPath);
|
||||
|
||||
let entries: Dirent[];
|
||||
try {
|
||||
entries = await fs.readdir(directory, { withFileTypes: true, encoding: 'utf8' });
|
||||
} catch (error) {
|
||||
if (isNodeErrorWithCode(error, 'ENOENT')) {
|
||||
return [];
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
|
||||
const documents: PrdDocument[] = [];
|
||||
|
||||
for (const entry of entries) {
|
||||
if (!entry.isFile()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const ext = path.extname(entry.name);
|
||||
if (!PRD_FILE_EXTENSIONS.has(ext)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const filePath = path.join(directory, entry.name);
|
||||
const raw = await fs.readFile(filePath, 'utf8');
|
||||
|
||||
let parsed: unknown;
|
||||
try {
|
||||
parsed = yaml.load(raw);
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to parse PRD file ${filePath}: ${String(error)}`);
|
||||
}
|
||||
|
||||
const document = prdDocumentSchema.parse(parsed);
|
||||
documents.push(document);
|
||||
}
|
||||
|
||||
documents.sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
|
||||
return documents;
|
||||
}
|
||||
93
packages/prdy/src/templates.ts
Normal file
93
packages/prdy/src/templates.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
import type { PrdTemplate } from './types.js';
|
||||
|
||||
export const BUILTIN_PRD_TEMPLATES: Record<string, PrdTemplate> = {
|
||||
software: {
|
||||
id: 'software',
|
||||
name: 'Software Project',
|
||||
fields: ['owner', 'status', 'scopeVersion', 'successMetrics'],
|
||||
sections: [
|
||||
{ id: 'introduction', title: 'Introduction', fields: ['context', 'objective'] },
|
||||
{ id: 'problem-statement', title: 'Problem Statement', fields: ['painPoints'] },
|
||||
{ id: 'scope-non-goals', title: 'Scope / Non-Goals', fields: ['inScope', 'outOfScope'] },
|
||||
{ id: 'user-stories', title: 'User Stories / Requirements', fields: ['stories'] },
|
||||
{ id: 'functional-requirements', title: 'Functional Requirements', fields: ['requirements'] },
|
||||
{
|
||||
id: 'non-functional-requirements',
|
||||
title: 'Non-Functional Requirements',
|
||||
fields: ['performance', 'reliability', 'security'],
|
||||
},
|
||||
{ id: 'acceptance-criteria', title: 'Acceptance Criteria', fields: ['criteria'] },
|
||||
{
|
||||
id: 'technical-considerations',
|
||||
title: 'Technical Considerations',
|
||||
fields: ['constraints', 'dependencies'],
|
||||
},
|
||||
{
|
||||
id: 'risks-open-questions',
|
||||
title: 'Risks / Open Questions',
|
||||
fields: ['risks', 'openQuestions'],
|
||||
},
|
||||
{
|
||||
id: 'milestones-delivery',
|
||||
title: 'Milestones / Delivery',
|
||||
fields: ['milestones', 'timeline'],
|
||||
},
|
||||
],
|
||||
},
|
||||
feature: {
|
||||
id: 'feature',
|
||||
name: 'Feature PRD',
|
||||
fields: ['owner', 'status', 'releaseTarget'],
|
||||
sections: [
|
||||
{ id: 'problem-statement', title: 'Problem Statement', fields: ['problem'] },
|
||||
{ id: 'goals', title: 'Goals', fields: ['goals'] },
|
||||
{ id: 'scope', title: 'Scope', fields: ['inScope', 'outOfScope'] },
|
||||
{ id: 'user-stories', title: 'User Stories', fields: ['stories'] },
|
||||
{ id: 'requirements', title: 'Requirements', fields: ['functional', 'nonFunctional'] },
|
||||
{ id: 'acceptance-criteria', title: 'Acceptance Criteria', fields: ['criteria'] },
|
||||
{
|
||||
id: 'technical-considerations',
|
||||
title: 'Technical Considerations',
|
||||
fields: ['constraints'],
|
||||
},
|
||||
{
|
||||
id: 'risks-open-questions',
|
||||
title: 'Risks / Open Questions',
|
||||
fields: ['risks', 'questions'],
|
||||
},
|
||||
{ id: 'milestones', title: 'Milestones', fields: ['milestones'] },
|
||||
{ id: 'success-metrics', title: 'Success Metrics / Testing', fields: ['metrics', 'testing'] },
|
||||
],
|
||||
},
|
||||
spike: {
|
||||
id: 'spike',
|
||||
name: 'Research Spike',
|
||||
fields: ['owner', 'status', 'decisionDeadline'],
|
||||
sections: [
|
||||
{ id: 'background', title: 'Background', fields: ['context'] },
|
||||
{ id: 'research-questions', title: 'Research Questions', fields: ['questions'] },
|
||||
{ id: 'constraints', title: 'Constraints', fields: ['constraints'] },
|
||||
{ id: 'options', title: 'Options Considered', fields: ['options'] },
|
||||
{ id: 'evaluation', title: 'Evaluation Criteria', fields: ['criteria'] },
|
||||
{ id: 'findings', title: 'Findings', fields: ['findings'] },
|
||||
{ id: 'recommendation', title: 'Recommendation', fields: ['recommendation'] },
|
||||
{ id: 'risks', title: 'Risks / Unknowns', fields: ['risks', 'unknowns'] },
|
||||
{ id: 'next-steps', title: 'Next Steps', fields: ['nextSteps'] },
|
||||
{ id: 'milestones', title: 'Milestones / Delivery', fields: ['milestones'] },
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export function resolveTemplate(templateName?: string): PrdTemplate {
|
||||
const name =
|
||||
templateName === undefined || templateName.trim().length === 0 ? 'software' : templateName;
|
||||
|
||||
const template = BUILTIN_PRD_TEMPLATES[name];
|
||||
if (template === undefined) {
|
||||
throw new Error(
|
||||
`Unknown PRD template: ${name}. Expected one of: ${Object.keys(BUILTIN_PRD_TEMPLATES).join(', ')}`,
|
||||
);
|
||||
}
|
||||
|
||||
return template;
|
||||
}
|
||||
38
packages/prdy/src/types.ts
Normal file
38
packages/prdy/src/types.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
export type PrdStatus = 'draft' | 'review' | 'approved' | 'archived';
|
||||
|
||||
export interface PrdTemplateSection {
|
||||
id: string;
|
||||
title: string;
|
||||
fields: string[];
|
||||
}
|
||||
|
||||
export interface PrdTemplate {
|
||||
id: string;
|
||||
name: string;
|
||||
sections: PrdTemplateSection[];
|
||||
fields: string[];
|
||||
}
|
||||
|
||||
export interface PrdSection {
|
||||
id: string;
|
||||
title: string;
|
||||
fields: Record<string, string>;
|
||||
}
|
||||
|
||||
export interface PrdDocument {
|
||||
id: string;
|
||||
title: string;
|
||||
status: PrdStatus;
|
||||
projectPath: string;
|
||||
template: string;
|
||||
sections: PrdSection[];
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
export interface CreatePrdOptions {
|
||||
name: string;
|
||||
projectPath: string;
|
||||
template?: string;
|
||||
interactive?: boolean;
|
||||
}
|
||||
103
packages/prdy/src/wizard.ts
Normal file
103
packages/prdy/src/wizard.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
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;
|
||||
}
|
||||
65
pnpm-lock.yaml
generated
65
pnpm-lock.yaml
generated
@@ -395,7 +395,26 @@ importers:
|
||||
version: 2.1.9(@types/node@22.19.15)(lightningcss@1.31.1)
|
||||
|
||||
packages/prdy:
|
||||
dependencies:
|
||||
'@clack/prompts':
|
||||
specifier: ^0.9.0
|
||||
version: 0.9.1
|
||||
commander:
|
||||
specifier: ^12.0.0
|
||||
version: 12.1.0
|
||||
js-yaml:
|
||||
specifier: ^4.1.0
|
||||
version: 4.1.1
|
||||
zod:
|
||||
specifier: ^3.22.0
|
||||
version: 3.25.76
|
||||
devDependencies:
|
||||
'@types/js-yaml':
|
||||
specifier: ^4.0.9
|
||||
version: 4.0.9
|
||||
'@types/node':
|
||||
specifier: ^22.0.0
|
||||
version: 22.19.15
|
||||
typescript:
|
||||
specifier: ^5.8.0
|
||||
version: 5.9.3
|
||||
@@ -706,6 +725,12 @@ packages:
|
||||
'@borewit/text-codec@0.2.2':
|
||||
resolution: {integrity: sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ==}
|
||||
|
||||
'@clack/core@0.4.1':
|
||||
resolution: {integrity: sha512-Pxhij4UXg8KSr7rPek6Zowm+5M22rbd2g1nfojHJkxp5YkFqiZ2+YLEM/XGVIzvGOcM0nqjIFxrpDwWRZYWYjA==}
|
||||
|
||||
'@clack/prompts@0.9.1':
|
||||
resolution: {integrity: sha512-JIpyaboYZeWYlyP0H+OoPPxd6nqueG/CmN6ixBiNFsIDHREevjIf0n0Ohh5gr5C8pEDknzgvz+pIJ8dMhzWIeg==}
|
||||
|
||||
'@discordjs/builders@1.13.1':
|
||||
resolution: {integrity: sha512-cOU0UDHc3lp/5nKByDxkmRiNZBpdp0kx55aarbiAfakfKJHlxv/yFW1zmIqCAmwH5CRlrH9iMFKJMpvW4DPB+w==}
|
||||
engines: {node: '>=16.11.0'}
|
||||
@@ -2779,6 +2804,9 @@ packages:
|
||||
'@types/estree@1.0.8':
|
||||
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
|
||||
|
||||
'@types/js-yaml@4.0.9':
|
||||
resolution: {integrity: sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==}
|
||||
|
||||
'@types/json-schema@7.0.15':
|
||||
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
|
||||
|
||||
@@ -3253,6 +3281,10 @@ packages:
|
||||
colorette@2.0.20:
|
||||
resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==}
|
||||
|
||||
commander@12.1.0:
|
||||
resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
commander@13.1.0:
|
||||
resolution: {integrity: sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==}
|
||||
engines: {node: '>=18'}
|
||||
@@ -4658,6 +4690,9 @@ packages:
|
||||
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
sisteransi@1.0.5:
|
||||
resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==}
|
||||
|
||||
slice-ansi@5.0.0:
|
||||
resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -5146,6 +5181,9 @@ packages:
|
||||
peerDependencies:
|
||||
zod: ^3.25 || ^4
|
||||
|
||||
zod@3.25.76:
|
||||
resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==}
|
||||
|
||||
zod@4.3.6:
|
||||
resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==}
|
||||
|
||||
@@ -5594,6 +5632,17 @@ snapshots:
|
||||
|
||||
'@borewit/text-codec@0.2.2': {}
|
||||
|
||||
'@clack/core@0.4.1':
|
||||
dependencies:
|
||||
picocolors: 1.1.1
|
||||
sisteransi: 1.0.5
|
||||
|
||||
'@clack/prompts@0.9.1':
|
||||
dependencies:
|
||||
'@clack/core': 0.4.1
|
||||
picocolors: 1.1.1
|
||||
sisteransi: 1.0.5
|
||||
|
||||
'@discordjs/builders@1.13.1':
|
||||
dependencies:
|
||||
'@discordjs/formatters': 0.6.2
|
||||
@@ -6330,8 +6379,8 @@ snapshots:
|
||||
'@mistralai/mistralai@1.14.1':
|
||||
dependencies:
|
||||
ws: 8.19.0
|
||||
zod: 4.3.6
|
||||
zod-to-json-schema: 3.25.1(zod@4.3.6)
|
||||
zod: 3.25.76
|
||||
zod-to-json-schema: 3.25.1(zod@3.25.76)
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- utf-8-validate
|
||||
@@ -7659,6 +7708,8 @@ snapshots:
|
||||
|
||||
'@types/estree@1.0.8': {}
|
||||
|
||||
'@types/js-yaml@4.0.9': {}
|
||||
|
||||
'@types/json-schema@7.0.15': {}
|
||||
|
||||
'@types/memcached@2.2.10':
|
||||
@@ -8116,6 +8167,8 @@ snapshots:
|
||||
|
||||
colorette@2.0.20: {}
|
||||
|
||||
commander@12.1.0: {}
|
||||
|
||||
commander@13.1.0: {}
|
||||
|
||||
concat-map@0.0.1: {}
|
||||
@@ -9568,6 +9621,8 @@ snapshots:
|
||||
|
||||
signal-exit@4.1.0: {}
|
||||
|
||||
sisteransi@1.0.5: {}
|
||||
|
||||
slice-ansi@5.0.0:
|
||||
dependencies:
|
||||
ansi-styles: 6.2.3
|
||||
@@ -10021,8 +10076,14 @@ snapshots:
|
||||
|
||||
yoga-layout@3.2.1: {}
|
||||
|
||||
zod-to-json-schema@3.25.1(zod@3.25.76):
|
||||
dependencies:
|
||||
zod: 3.25.76
|
||||
|
||||
zod-to-json-schema@3.25.1(zod@4.3.6):
|
||||
dependencies:
|
||||
zod: 4.3.6
|
||||
|
||||
zod@3.25.76: {}
|
||||
|
||||
zod@4.3.6: {}
|
||||
|
||||
Reference in New Issue
Block a user