mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-28 09:23:08 +08:00
refactor(spec): update folder structure and dimensions
- Change folder from .workflow/ to .ccw/ - Reduce dimensions from 4 to 2: specs, personal - Remove changelog and roadmap dimensions - Update help text and examples Folder structure: - .ccw/specs/ - Project rules and conventions - .ccw/personal/ - Personal preferences (supports global ~/.ccw/personal/) - .ccw/.spec-index/ - Index cache Keyword categories for workflow stages: - exploration - Code exploration, analysis, debugging - planning - Task planning, requirements - execution - Implementation, testing, deployment
This commit is contained in:
@@ -95,7 +95,7 @@ async function loadAction(options: SpecOptions): Promise<void> {
|
||||
|
||||
const result = await loadSpecs({
|
||||
projectPath,
|
||||
dimension: dimension as 'specs' | 'roadmap' | 'changelog' | 'personal' | undefined,
|
||||
dimension: dimension as 'specs' | 'personal' | undefined,
|
||||
keywords,
|
||||
outputFormat: stdin ? 'hook' : 'cli',
|
||||
stdinData,
|
||||
@@ -355,12 +355,12 @@ ${chalk.bold('USAGE')}
|
||||
${chalk.bold('SUBCOMMANDS')}
|
||||
load Load specs matching dimension/keywords (CLI or Hook mode)
|
||||
list List all indexed specs with readMode and keyword info
|
||||
rebuild Force re-scan of MD files and rebuild .spec-index cache
|
||||
rebuild Force re-scan of MD files and rebuild .ccw/.spec-index cache
|
||||
status Show per-dimension stats (total, required, optional, freshness)
|
||||
init Create 4-dimension directory structure with seed MD documents
|
||||
init Create 2-dimension directory structure with seed MD documents
|
||||
|
||||
${chalk.bold('OPTIONS')}
|
||||
--dimension <dim> Target dimension: specs, roadmap, changelog, personal
|
||||
--dimension <dim> Target dimension: specs, personal
|
||||
--keywords <text> Keywords for spec matching (space or comma separated)
|
||||
--stdin Read input from stdin (Hook mode)
|
||||
--json Output as JSON
|
||||
@@ -368,7 +368,7 @@ ${chalk.bold('OPTIONS')}
|
||||
${chalk.bold('KEYWORD CATEGORIES')}
|
||||
Use these predefined keywords to load specs for specific workflow stages:
|
||||
${chalk.cyan('exploration')} - Code exploration, analysis, debugging context
|
||||
${chalk.cyan('planning')} - Task planning, roadmap, requirements context
|
||||
${chalk.cyan('planning')} - Task planning, requirements context
|
||||
${chalk.cyan('execution')} - Implementation, testing, deployment context
|
||||
|
||||
${chalk.bold('EXAMPLES')}
|
||||
@@ -400,7 +400,7 @@ ${chalk.bold('EXAMPLES')}
|
||||
ccw spec rebuild
|
||||
|
||||
${chalk.gray('# Rebuild single dimension:')}
|
||||
ccw spec rebuild --dimension roadmap
|
||||
ccw spec rebuild --dimension specs
|
||||
|
||||
${chalk.gray('# Check system status:')}
|
||||
ccw spec status
|
||||
@@ -1,10 +1,10 @@
|
||||
/**
|
||||
* Spec Index Builder
|
||||
*
|
||||
* Scans .workflow/{dimension}/*.md files, parses YAML frontmatter via
|
||||
* gray-matter, and writes .spec-index/{dimension}.index.json cache files.
|
||||
* Scans .ccw/{dimension}/*.md files, parses YAML frontmatter via
|
||||
* gray-matter, and writes .ccw/.spec-index/{dimension}.index.json cache files.
|
||||
*
|
||||
* Supports 4 dimensions: specs, roadmap, changelog, personal
|
||||
* Supports 2 dimensions: specs, personal
|
||||
*
|
||||
* YAML Frontmatter Schema:
|
||||
* ---
|
||||
@@ -83,9 +83,11 @@ export interface DimensionIndex {
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* The 4 supported spec dimensions.
|
||||
* The 2 supported spec dimensions.
|
||||
* - specs: Project rules and conventions
|
||||
* - personal: Personal preferences (supports global ~/.ccw/personal/)
|
||||
*/
|
||||
export const SPEC_DIMENSIONS = ['specs', 'roadmap', 'changelog', 'personal'] as const;
|
||||
export const SPEC_DIMENSIONS = ['specs', 'personal'] as const;
|
||||
|
||||
export type SpecDimension = typeof SPEC_DIMENSIONS[number];
|
||||
|
||||
@@ -100,9 +102,9 @@ const VALID_READ_MODES = ['required', 'optional'] as const;
|
||||
const VALID_PRIORITIES = ['critical', 'high', 'medium', 'low'] as const;
|
||||
|
||||
/**
|
||||
* Directory name for spec index cache files (inside .workflow/).
|
||||
* Directory name for spec index cache files (inside .ccw/).
|
||||
*/
|
||||
const WORKFLOW_DIR = '.workflow';
|
||||
const CCW_DIR = '.ccw';
|
||||
const SPEC_INDEX_DIR = '.spec-index';
|
||||
|
||||
// ============================================================================
|
||||
@@ -114,27 +116,27 @@ const SPEC_INDEX_DIR = '.spec-index';
|
||||
*
|
||||
* @param projectPath - Project root directory
|
||||
* @param dimension - The dimension name
|
||||
* @returns Absolute path to .workflow/.spec-index/{dimension}.index.json
|
||||
* @returns Absolute path to .ccw/.spec-index/{dimension}.index.json
|
||||
*/
|
||||
export function getIndexPath(projectPath: string, dimension: string): string {
|
||||
return join(projectPath, WORKFLOW_DIR, SPEC_INDEX_DIR, `${dimension}.index.json`);
|
||||
return join(projectPath, CCW_DIR, SPEC_INDEX_DIR, `${dimension}.index.json`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path to the .workflow/{dimension} directory.
|
||||
* Get the path to the .ccw/{dimension} directory.
|
||||
*
|
||||
* @param projectPath - Project root directory
|
||||
* @param dimension - The dimension name
|
||||
* @returns Absolute path to .workflow/{dimension}/
|
||||
* @returns Absolute path to .ccw/{dimension}/
|
||||
*/
|
||||
export function getDimensionDir(projectPath: string, dimension: string): string {
|
||||
return join(projectPath, '.workflow', dimension);
|
||||
return join(projectPath, CCW_DIR, dimension);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the index for a single dimension.
|
||||
*
|
||||
* Scans .workflow/{dimension}/*.md files, parses YAML frontmatter,
|
||||
* Scans .ccw/{dimension}/*.md files, parses YAML frontmatter,
|
||||
* extracts the 5 required fields, and returns a DimensionIndex.
|
||||
*
|
||||
* Files with malformed or missing frontmatter are skipped gracefully.
|
||||
@@ -194,15 +196,15 @@ export async function buildDimensionIndex(
|
||||
}
|
||||
|
||||
/**
|
||||
* Build indices for all 4 dimensions and write to .spec-index/.
|
||||
* Build indices for all dimensions and write to .ccw/.spec-index/.
|
||||
*
|
||||
* Creates .spec-index/ directory if it doesn't exist.
|
||||
* Creates .ccw/.spec-index/ directory if it doesn't exist.
|
||||
* Writes {dimension}.index.json for each dimension.
|
||||
*
|
||||
* @param projectPath - Project root directory
|
||||
*/
|
||||
export async function buildAllIndices(projectPath: string): Promise<void> {
|
||||
const indexDir = join(projectPath, WORKFLOW_DIR, SPEC_INDEX_DIR);
|
||||
const indexDir = join(projectPath, CCW_DIR, SPEC_INDEX_DIR);
|
||||
|
||||
// Ensure .spec-index directory exists
|
||||
if (!existsSync(indexDir)) {
|
||||
@@ -283,7 +285,7 @@ export async function getDimensionIndex(
|
||||
// Build fresh and cache
|
||||
const index = await buildDimensionIndex(projectPath, dimension);
|
||||
|
||||
const indexDir = join(projectPath, WORKFLOW_DIR, SPEC_INDEX_DIR);
|
||||
const indexDir = join(projectPath, CCW_DIR, SPEC_INDEX_DIR);
|
||||
if (!existsSync(indexDir)) {
|
||||
mkdirSync(indexDir, { recursive: true });
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
/**
|
||||
* Spec Init - Initialize the 4-dimension spec system
|
||||
* Spec Init - Initialize the 2-dimension spec system
|
||||
*
|
||||
* Creates .workflow/specs/, .workflow/roadmap/, .workflow/changelog/,
|
||||
* .workflow/personal/, and .workflow/.spec-index/ directories with
|
||||
* seed MD documents containing YAML frontmatter templates.
|
||||
* Creates .ccw/specs/, .ccw/personal/,
|
||||
* and .ccw/.spec-index/ directories with seed MD documents
|
||||
* containing YAML frontmatter templates.
|
||||
*
|
||||
* Idempotent: skips existing files, only creates missing directories/files.
|
||||
*/
|
||||
@@ -39,7 +39,7 @@ export interface InitResult {
|
||||
// Constants
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export const DIMENSIONS = ['specs', 'roadmap', 'changelog', 'personal'] as const;
|
||||
export const DIMENSIONS = ['specs', 'personal'] as const;
|
||||
export const INDEX_DIR = '.spec-index';
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -55,7 +55,7 @@ export const SEED_DOCS: Map<string, SeedDoc[]> = new Map([
|
||||
frontmatter: {
|
||||
title: 'Coding Conventions',
|
||||
dimension: 'specs',
|
||||
keywords: ['typescript', 'naming', 'style', 'convention'],
|
||||
keywords: ['typescript', 'naming', 'style', 'convention', 'exploration', 'planning', 'execution'],
|
||||
readMode: 'required',
|
||||
priority: 'high',
|
||||
},
|
||||
@@ -91,7 +91,7 @@ export const SEED_DOCS: Map<string, SeedDoc[]> = new Map([
|
||||
frontmatter: {
|
||||
title: 'Architecture Constraints',
|
||||
dimension: 'specs',
|
||||
keywords: ['architecture', 'module', 'layer', 'pattern'],
|
||||
keywords: ['architecture', 'module', 'layer', 'pattern', 'exploration', 'planning'],
|
||||
readMode: 'required',
|
||||
priority: 'high',
|
||||
},
|
||||
@@ -174,40 +174,6 @@ export const SEED_DOCS: Map<string, SeedDoc[]> = new Map([
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
'roadmap',
|
||||
[
|
||||
{
|
||||
filename: 'current.md',
|
||||
frontmatter: {
|
||||
title: 'Current Roadmap',
|
||||
dimension: 'roadmap',
|
||||
keywords: ['roadmap', 'plan', 'milestone'],
|
||||
readMode: 'optional',
|
||||
priority: 'medium',
|
||||
},
|
||||
body: `# Current Roadmap
|
||||
|
||||
## Active Milestone
|
||||
|
||||
- Milestone name and target date
|
||||
- Key deliverables
|
||||
|
||||
## Upcoming
|
||||
|
||||
- Next planned features or improvements
|
||||
|
||||
## Completed
|
||||
|
||||
- Recently completed milestones for reference
|
||||
`,
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
'changelog',
|
||||
[],
|
||||
],
|
||||
]);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -246,29 +212,29 @@ export function formatFrontmatter(fm: SpecFrontmatter): string {
|
||||
* @returns InitResult with lists of created/skipped paths
|
||||
*/
|
||||
export function initSpecSystem(projectPath: string): InitResult {
|
||||
const workflowDir = join(projectPath, '.workflow');
|
||||
const ccwDir = join(projectPath, '.ccw');
|
||||
const result: InitResult = {
|
||||
created: [],
|
||||
skipped: [],
|
||||
directories: [],
|
||||
};
|
||||
|
||||
// Ensure .workflow root exists
|
||||
if (!existsSync(workflowDir)) {
|
||||
mkdirSync(workflowDir, { recursive: true });
|
||||
// Ensure .ccw root exists
|
||||
if (!existsSync(ccwDir)) {
|
||||
mkdirSync(ccwDir, { recursive: true });
|
||||
}
|
||||
|
||||
// Create dimension directories
|
||||
for (const dim of DIMENSIONS) {
|
||||
const dirPath = join(workflowDir, dim);
|
||||
const dirPath = join(ccwDir, dim);
|
||||
if (!existsSync(dirPath)) {
|
||||
mkdirSync(dirPath, { recursive: true });
|
||||
result.directories.push(dirPath);
|
||||
}
|
||||
}
|
||||
|
||||
// Create index directory at project root (matches spec-index-builder.ts location)
|
||||
const indexPath = join(projectPath, INDEX_DIR);
|
||||
// Create index directory inside .ccw (matches spec-index-builder.ts location)
|
||||
const indexPath = join(ccwDir, INDEX_DIR);
|
||||
if (!existsSync(indexPath)) {
|
||||
mkdirSync(indexPath, { recursive: true });
|
||||
result.directories.push(indexPath);
|
||||
@@ -276,7 +242,7 @@ export function initSpecSystem(projectPath: string): InitResult {
|
||||
|
||||
// Write seed documents per dimension
|
||||
for (const [dimension, docs] of SEED_DOCS) {
|
||||
const dimDir = join(workflowDir, dimension);
|
||||
const dimDir = join(ccwDir, dimension);
|
||||
|
||||
for (const doc of docs) {
|
||||
const filePath = join(dimDir, doc.filename);
|
||||
@@ -105,9 +105,7 @@ interface LoadedSpec {
|
||||
*/
|
||||
const DIMENSION_PRIORITY: Record<string, number> = {
|
||||
personal: 1,
|
||||
changelog: 2,
|
||||
roadmap: 3,
|
||||
specs: 4,
|
||||
specs: 2,
|
||||
};
|
||||
|
||||
/**
|
||||
Reference in New Issue
Block a user