feat: add SpecDialog component for editing spec frontmatter

- Implement SpecDialog for managing spec details including title, read mode, priority, and keywords.
- Add validation and keyword management functionality.
- Integrate SpecDialog into SpecsSettingsPage for editing specs.

feat: create index file for specs components

- Export SpecCard, SpecDialog, and related types from a new index file for better organization.

feat: implement SpecsSettingsPage for managing specs and hooks

- Create main settings page with tabs for Project Specs, Personal Specs, Hooks, Injection, and Settings.
- Integrate SpecDialog and HookDialog for editing specs and hooks.
- Add search functionality and mock data for specs and hooks.

feat: add spec management API routes

- Implement API endpoints for listing specs, getting spec details, updating frontmatter, rebuilding indices, and initializing the spec system.
- Handle errors and responses appropriately for each endpoint.
This commit is contained in:
catlog22
2026-02-26 22:03:13 +08:00
parent 430d817e43
commit 6155fcc7b8
115 changed files with 4883 additions and 21127 deletions

View File

@@ -205,7 +205,7 @@ export async function aggregateData(sessions: ScanSessionsResult, workflowDir: s
join(workflowDir, 'active'),
join(workflowDir, 'archives'),
join(workflowDir, 'project-tech.json'),
join(workflowDir, 'project-guidelines.json'),
join(workflowDir, 'specs'),
...sessions.active.map(s => s.path),
...sessions.archived.map(s => s.path)
];
@@ -564,14 +564,12 @@ function sortTaskIds(a: string, b: string): number {
}
/**
* Load project overview from project-tech.json and project-guidelines.json
* Load project overview from project-tech.json
* @param workflowDir - Path to .workflow directory
* @returns Project overview data or null if not found
*/
export function loadProjectOverview(workflowDir: string): ProjectOverview | null {
const techFile = join(workflowDir, 'project-tech.json');
const guidelinesFile = join(workflowDir, 'project-guidelines.json');
if (!existsSync(techFile)) {
console.log(`Project file not found at: ${techFile}`);
return null;
@@ -607,44 +605,9 @@ export function loadProjectOverview(workflowDir: string): ProjectOverview | null
});
};
// Load guidelines from separate file if exists
let guidelines: ProjectGuidelines | null = null;
if (existsSync(guidelinesFile)) {
try {
const guidelinesContent = readFileSync(guidelinesFile, 'utf8');
const guidelinesData = JSON.parse(guidelinesContent) as Record<string, unknown>;
const conventions = guidelinesData.conventions as Record<string, string[]> | undefined;
const constraints = guidelinesData.constraints as Record<string, string[]> | undefined;
guidelines = {
conventions: {
coding_style: conventions?.coding_style || [],
naming_patterns: conventions?.naming_patterns || [],
file_structure: conventions?.file_structure || [],
documentation: conventions?.documentation || []
},
constraints: {
architecture: constraints?.architecture || [],
tech_stack: constraints?.tech_stack || [],
performance: constraints?.performance || [],
security: constraints?.security || []
},
quality_rules: (guidelinesData.quality_rules as Array<{ rule: string; scope: string; enforced_by?: string }>) || [],
learnings: (guidelinesData.learnings as Array<{
date: string;
session_id?: string;
insight: string;
context?: string;
category?: string;
}>) || [],
_metadata: guidelinesData._metadata as ProjectGuidelines['_metadata'] | undefined
};
console.log(`Successfully loaded project guidelines`);
} catch (guidelinesErr) {
console.error(`Failed to parse project-guidelines.json:`, (guidelinesErr as Error).message);
}
}
// Guidelines now managed by spec system (ccw spec load)
// Return null - dashboard doesn't need guidelines data directly
const guidelines: ProjectGuidelines | null = null;
return {
projectName: (projectData.project_name as string) || 'Unknown',