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({
|
const result = await loadSpecs({
|
||||||
projectPath,
|
projectPath,
|
||||||
dimension: dimension as 'specs' | 'roadmap' | 'changelog' | 'personal' | undefined,
|
dimension: dimension as 'specs' | 'personal' | undefined,
|
||||||
keywords,
|
keywords,
|
||||||
outputFormat: stdin ? 'hook' : 'cli',
|
outputFormat: stdin ? 'hook' : 'cli',
|
||||||
stdinData,
|
stdinData,
|
||||||
@@ -355,12 +355,12 @@ ${chalk.bold('USAGE')}
|
|||||||
${chalk.bold('SUBCOMMANDS')}
|
${chalk.bold('SUBCOMMANDS')}
|
||||||
load Load specs matching dimension/keywords (CLI or Hook mode)
|
load Load specs matching dimension/keywords (CLI or Hook mode)
|
||||||
list List all indexed specs with readMode and keyword info
|
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)
|
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')}
|
${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)
|
--keywords <text> Keywords for spec matching (space or comma separated)
|
||||||
--stdin Read input from stdin (Hook mode)
|
--stdin Read input from stdin (Hook mode)
|
||||||
--json Output as JSON
|
--json Output as JSON
|
||||||
@@ -368,7 +368,7 @@ ${chalk.bold('OPTIONS')}
|
|||||||
${chalk.bold('KEYWORD CATEGORIES')}
|
${chalk.bold('KEYWORD CATEGORIES')}
|
||||||
Use these predefined keywords to load specs for specific workflow stages:
|
Use these predefined keywords to load specs for specific workflow stages:
|
||||||
${chalk.cyan('exploration')} - Code exploration, analysis, debugging context
|
${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.cyan('execution')} - Implementation, testing, deployment context
|
||||||
|
|
||||||
${chalk.bold('EXAMPLES')}
|
${chalk.bold('EXAMPLES')}
|
||||||
@@ -400,7 +400,7 @@ ${chalk.bold('EXAMPLES')}
|
|||||||
ccw spec rebuild
|
ccw spec rebuild
|
||||||
|
|
||||||
${chalk.gray('# Rebuild single dimension:')}
|
${chalk.gray('# Rebuild single dimension:')}
|
||||||
ccw spec rebuild --dimension roadmap
|
ccw spec rebuild --dimension specs
|
||||||
|
|
||||||
${chalk.gray('# Check system status:')}
|
${chalk.gray('# Check system status:')}
|
||||||
ccw spec status
|
ccw spec status
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
/**
|
/**
|
||||||
* Spec Index Builder
|
* Spec Index Builder
|
||||||
*
|
*
|
||||||
* Scans .workflow/{dimension}/*.md files, parses YAML frontmatter via
|
* Scans .ccw/{dimension}/*.md files, parses YAML frontmatter via
|
||||||
* gray-matter, and writes .spec-index/{dimension}.index.json cache files.
|
* 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:
|
* 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];
|
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;
|
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';
|
const SPEC_INDEX_DIR = '.spec-index';
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@@ -114,27 +116,27 @@ const SPEC_INDEX_DIR = '.spec-index';
|
|||||||
*
|
*
|
||||||
* @param projectPath - Project root directory
|
* @param projectPath - Project root directory
|
||||||
* @param dimension - The dimension name
|
* @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 {
|
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 projectPath - Project root directory
|
||||||
* @param dimension - The dimension name
|
* @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 {
|
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.
|
* 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.
|
* extracts the 5 required fields, and returns a DimensionIndex.
|
||||||
*
|
*
|
||||||
* Files with malformed or missing frontmatter are skipped gracefully.
|
* 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.
|
* Writes {dimension}.index.json for each dimension.
|
||||||
*
|
*
|
||||||
* @param projectPath - Project root directory
|
* @param projectPath - Project root directory
|
||||||
*/
|
*/
|
||||||
export async function buildAllIndices(projectPath: string): Promise<void> {
|
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
|
// Ensure .spec-index directory exists
|
||||||
if (!existsSync(indexDir)) {
|
if (!existsSync(indexDir)) {
|
||||||
@@ -283,7 +285,7 @@ export async function getDimensionIndex(
|
|||||||
// Build fresh and cache
|
// Build fresh and cache
|
||||||
const index = await buildDimensionIndex(projectPath, dimension);
|
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)) {
|
if (!existsSync(indexDir)) {
|
||||||
mkdirSync(indexDir, { recursive: true });
|
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/,
|
* Creates .ccw/specs/, .ccw/personal/,
|
||||||
* .workflow/personal/, and .workflow/.spec-index/ directories with
|
* and .ccw/.spec-index/ directories with seed MD documents
|
||||||
* seed MD documents containing YAML frontmatter templates.
|
* containing YAML frontmatter templates.
|
||||||
*
|
*
|
||||||
* Idempotent: skips existing files, only creates missing directories/files.
|
* Idempotent: skips existing files, only creates missing directories/files.
|
||||||
*/
|
*/
|
||||||
@@ -39,7 +39,7 @@ export interface InitResult {
|
|||||||
// Constants
|
// Constants
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
export const DIMENSIONS = ['specs', 'roadmap', 'changelog', 'personal'] as const;
|
export const DIMENSIONS = ['specs', 'personal'] as const;
|
||||||
export const INDEX_DIR = '.spec-index';
|
export const INDEX_DIR = '.spec-index';
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@@ -55,7 +55,7 @@ export const SEED_DOCS: Map<string, SeedDoc[]> = new Map([
|
|||||||
frontmatter: {
|
frontmatter: {
|
||||||
title: 'Coding Conventions',
|
title: 'Coding Conventions',
|
||||||
dimension: 'specs',
|
dimension: 'specs',
|
||||||
keywords: ['typescript', 'naming', 'style', 'convention'],
|
keywords: ['typescript', 'naming', 'style', 'convention', 'exploration', 'planning', 'execution'],
|
||||||
readMode: 'required',
|
readMode: 'required',
|
||||||
priority: 'high',
|
priority: 'high',
|
||||||
},
|
},
|
||||||
@@ -91,7 +91,7 @@ export const SEED_DOCS: Map<string, SeedDoc[]> = new Map([
|
|||||||
frontmatter: {
|
frontmatter: {
|
||||||
title: 'Architecture Constraints',
|
title: 'Architecture Constraints',
|
||||||
dimension: 'specs',
|
dimension: 'specs',
|
||||||
keywords: ['architecture', 'module', 'layer', 'pattern'],
|
keywords: ['architecture', 'module', 'layer', 'pattern', 'exploration', 'planning'],
|
||||||
readMode: 'required',
|
readMode: 'required',
|
||||||
priority: 'high',
|
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
|
* @returns InitResult with lists of created/skipped paths
|
||||||
*/
|
*/
|
||||||
export function initSpecSystem(projectPath: string): InitResult {
|
export function initSpecSystem(projectPath: string): InitResult {
|
||||||
const workflowDir = join(projectPath, '.workflow');
|
const ccwDir = join(projectPath, '.ccw');
|
||||||
const result: InitResult = {
|
const result: InitResult = {
|
||||||
created: [],
|
created: [],
|
||||||
skipped: [],
|
skipped: [],
|
||||||
directories: [],
|
directories: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
// Ensure .workflow root exists
|
// Ensure .ccw root exists
|
||||||
if (!existsSync(workflowDir)) {
|
if (!existsSync(ccwDir)) {
|
||||||
mkdirSync(workflowDir, { recursive: true });
|
mkdirSync(ccwDir, { recursive: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create dimension directories
|
// Create dimension directories
|
||||||
for (const dim of DIMENSIONS) {
|
for (const dim of DIMENSIONS) {
|
||||||
const dirPath = join(workflowDir, dim);
|
const dirPath = join(ccwDir, dim);
|
||||||
if (!existsSync(dirPath)) {
|
if (!existsSync(dirPath)) {
|
||||||
mkdirSync(dirPath, { recursive: true });
|
mkdirSync(dirPath, { recursive: true });
|
||||||
result.directories.push(dirPath);
|
result.directories.push(dirPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create index directory at project root (matches spec-index-builder.ts location)
|
// Create index directory inside .ccw (matches spec-index-builder.ts location)
|
||||||
const indexPath = join(projectPath, INDEX_DIR);
|
const indexPath = join(ccwDir, INDEX_DIR);
|
||||||
if (!existsSync(indexPath)) {
|
if (!existsSync(indexPath)) {
|
||||||
mkdirSync(indexPath, { recursive: true });
|
mkdirSync(indexPath, { recursive: true });
|
||||||
result.directories.push(indexPath);
|
result.directories.push(indexPath);
|
||||||
@@ -276,7 +242,7 @@ export function initSpecSystem(projectPath: string): InitResult {
|
|||||||
|
|
||||||
// Write seed documents per dimension
|
// Write seed documents per dimension
|
||||||
for (const [dimension, docs] of SEED_DOCS) {
|
for (const [dimension, docs] of SEED_DOCS) {
|
||||||
const dimDir = join(workflowDir, dimension);
|
const dimDir = join(ccwDir, dimension);
|
||||||
|
|
||||||
for (const doc of docs) {
|
for (const doc of docs) {
|
||||||
const filePath = join(dimDir, doc.filename);
|
const filePath = join(dimDir, doc.filename);
|
||||||
@@ -105,9 +105,7 @@ interface LoadedSpec {
|
|||||||
*/
|
*/
|
||||||
const DIMENSION_PRIORITY: Record<string, number> = {
|
const DIMENSION_PRIORITY: Record<string, number> = {
|
||||||
personal: 1,
|
personal: 1,
|
||||||
changelog: 2,
|
specs: 2,
|
||||||
roadmap: 3,
|
|
||||||
specs: 4,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Reference in New Issue
Block a user