Claude sub-agents, PRD, MCP improvements (#359)
1. Added Claude Code sub-agents 2. Added PRD tool to MCP Server 3. Added MCP Server UI to Dev Tools 4. Improved MCP Server Database Tool 5. Updated dependencies
This commit is contained in:
committed by
GitHub
parent
02e2502dcc
commit
2b8572baaa
@@ -0,0 +1,35 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const CreatePRDSchema = z.object({
|
||||
title: z
|
||||
.string()
|
||||
.min(1, 'Title is required')
|
||||
.max(200, 'Title must be less than 200 characters'),
|
||||
overview: z
|
||||
.string()
|
||||
.min(1, 'Overview is required')
|
||||
.max(1000, 'Overview must be less than 1000 characters'),
|
||||
problemStatement: z
|
||||
.string()
|
||||
.min(1, 'Problem statement is required')
|
||||
.max(1000, 'Problem statement must be less than 1000 characters'),
|
||||
marketOpportunity: z
|
||||
.string()
|
||||
.min(1, 'Market opportunity is required')
|
||||
.max(1000, 'Market opportunity must be less than 1000 characters'),
|
||||
targetUsers: z
|
||||
.array(z.string().min(1, 'Target user cannot be empty'))
|
||||
.min(1, 'At least one target user is required'),
|
||||
solutionDescription: z
|
||||
.string()
|
||||
.min(1, 'Solution description is required')
|
||||
.max(1000, 'Solution description must be less than 1000 characters'),
|
||||
keyFeatures: z
|
||||
.array(z.string().min(1, 'Feature cannot be empty'))
|
||||
.min(1, 'At least one key feature is required'),
|
||||
successMetrics: z
|
||||
.array(z.string().min(1, 'Metric cannot be empty'))
|
||||
.min(1, 'At least one success metric is required'),
|
||||
});
|
||||
|
||||
export type CreatePRDData = z.infer<typeof CreatePRDSchema>;
|
||||
48
apps/dev-tool/app/mcp-server/_lib/server/prd-loader.ts
Normal file
48
apps/dev-tool/app/mcp-server/_lib/server/prd-loader.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { relative } from 'node:path';
|
||||
|
||||
import { PRDManager } from '@kit/mcp-server/prd-manager';
|
||||
|
||||
interface PRDSummary {
|
||||
filename: string;
|
||||
title: string;
|
||||
lastUpdated: string;
|
||||
progress: number;
|
||||
totalStories: number;
|
||||
completedStories: number;
|
||||
}
|
||||
|
||||
export async function loadPRDs(): Promise<PRDSummary[]> {
|
||||
try {
|
||||
PRDManager.setRootPath(relative(process.cwd(), '../..'));
|
||||
|
||||
// Use the actual PRDManager to list PRDs
|
||||
const prdFiles = await PRDManager.listPRDs();
|
||||
|
||||
const prdSummaries: PRDSummary[] = [];
|
||||
|
||||
// Load each PRD to get its details
|
||||
for (const filename of prdFiles) {
|
||||
try {
|
||||
const content = await PRDManager.getPRDContent(filename);
|
||||
const prd = JSON.parse(content);
|
||||
|
||||
prdSummaries.push({
|
||||
filename,
|
||||
title: prd.introduction.title,
|
||||
lastUpdated: prd.metadata.lastUpdated,
|
||||
progress: prd.progress.overall,
|
||||
totalStories: prd.progress.total,
|
||||
completedStories: prd.progress.completed,
|
||||
});
|
||||
} catch (prdError) {
|
||||
console.error(`Failed to load PRD ${filename}:`, prdError);
|
||||
// Continue with other PRDs even if one fails
|
||||
}
|
||||
}
|
||||
|
||||
return prdSummaries;
|
||||
} catch (error) {
|
||||
console.error('Failed to load PRDs:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
78
apps/dev-tool/app/mcp-server/_lib/server/prd-page.loader.ts
Normal file
78
apps/dev-tool/app/mcp-server/_lib/server/prd-page.loader.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import 'server-only';
|
||||
|
||||
import { relative } from 'node:path';
|
||||
|
||||
import { PRDManager } from '@kit/mcp-server/prd-manager';
|
||||
|
||||
export interface CustomPhase {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
color: string;
|
||||
order: number;
|
||||
userStoryIds: string[];
|
||||
}
|
||||
|
||||
export interface PRDData {
|
||||
introduction: {
|
||||
title: string;
|
||||
overview: string;
|
||||
lastUpdated: string;
|
||||
};
|
||||
problemStatement: {
|
||||
problem: string;
|
||||
marketOpportunity: string;
|
||||
targetUsers: string[];
|
||||
};
|
||||
solutionOverview: {
|
||||
description: string;
|
||||
keyFeatures: string[];
|
||||
successMetrics: string[];
|
||||
};
|
||||
userStories: Array<{
|
||||
id: string;
|
||||
title: string;
|
||||
userStory: string;
|
||||
businessValue: string;
|
||||
acceptanceCriteria: string[];
|
||||
priority: 'P0' | 'P1' | 'P2' | 'P3';
|
||||
status:
|
||||
| 'not_started'
|
||||
| 'research'
|
||||
| 'in_progress'
|
||||
| 'review'
|
||||
| 'completed'
|
||||
| 'blocked';
|
||||
notes?: string;
|
||||
estimatedComplexity?: string;
|
||||
dependencies?: string[];
|
||||
completedAt?: string;
|
||||
}>;
|
||||
customPhases?: CustomPhase[];
|
||||
metadata: {
|
||||
version: string;
|
||||
created: string;
|
||||
lastUpdated: string;
|
||||
approver: string;
|
||||
};
|
||||
progress: {
|
||||
overall: number;
|
||||
completed: number;
|
||||
total: number;
|
||||
blocked: number;
|
||||
};
|
||||
}
|
||||
|
||||
export async function loadPRDPageData(filename: string): Promise<PRDData> {
|
||||
try {
|
||||
PRDManager.setRootPath(relative(process.cwd(), '../..'));
|
||||
|
||||
const content = await PRDManager.getPRDContent(filename);
|
||||
|
||||
return JSON.parse(content) as PRDData;
|
||||
} catch (error) {
|
||||
console.error(`Failed to load PRD ${filename}:`, error);
|
||||
|
||||
throw new Error(`PRD not found: ${filename}`);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user