mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-28 09:23:08 +08:00
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:
@@ -834,7 +834,7 @@ todos = [
|
||||
| `workflow:unified-execute-with-file` | Universal execution engine - consumes plan output from collaborative-plan, req-plan, brainstorm |
|
||||
| `workflow:clean` | Intelligent code cleanup - mainline detection, stale artifact removal |
|
||||
| `workflow:init` | Initialize `.workflow/project-tech.json` with project analysis |
|
||||
| `workflow:init-guidelines` | Interactive wizard to fill `project-guidelines.json` |
|
||||
| `workflow:init-guidelines` | Interactive wizard to fill `specs/*.md` |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -160,7 +160,7 @@ ${issueList}
|
||||
|
||||
### Project Context (MANDATORY)
|
||||
1. Read: .workflow/project-tech.json (technology stack, architecture)
|
||||
2. Read: .workflow/project-guidelines.json (constraints and conventions)
|
||||
2. Read: .workflow/specs/*.md (constraints and conventions)
|
||||
|
||||
### Workflow
|
||||
1. Fetch issue details: ccw issue status <id> --json
|
||||
|
||||
@@ -571,27 +571,22 @@ CONSTRAINTS: ${perspective.constraints}
|
||||
.map(r => r.action)
|
||||
.join('\n') || conclusions.summary
|
||||
|
||||
// 2. Extract exploration digest (inline data, not path reference)
|
||||
const explorationDigest = { relevant_files: [], patterns: [], key_findings: [] }
|
||||
// 2. Assemble compact analysis context as inline memory block
|
||||
const contextLines = [
|
||||
`## Prior Analysis (${sessionId})`,
|
||||
`**Summary**: ${conclusions.summary}`
|
||||
]
|
||||
const codebasePath = `${sessionFolder}/exploration-codebase.json`
|
||||
if (file_exists(codebasePath)) {
|
||||
const data = JSON.parse(Read(codebasePath))
|
||||
explorationDigest.relevant_files = data.relevant_files || []
|
||||
explorationDigest.patterns = data.patterns || []
|
||||
explorationDigest.key_findings = data.key_findings || []
|
||||
const files = (data.relevant_files || []).slice(0, 8).map(f => f.path || f.file || f).filter(Boolean)
|
||||
const findings = (data.key_findings || []).slice(0, 5)
|
||||
if (files.length) contextLines.push(`**Key Files**: ${files.join(', ')}`)
|
||||
if (findings.length) contextLines.push(`**Key Findings**:\n${findings.map(f => `- ${f}`).join('\n')}`)
|
||||
}
|
||||
|
||||
// 3. Write handoff file to analysis session folder
|
||||
Write(`${sessionFolder}/handoff-lite-plan.json`, JSON.stringify({
|
||||
source_session: sessionId,
|
||||
summary: conclusions.summary,
|
||||
recommendations: conclusions.recommendations,
|
||||
decision_trail: conclusions.decision_trail,
|
||||
exploration_digest: explorationDigest
|
||||
}, null, 2))
|
||||
|
||||
// 4. Call lite-plan with --from-analysis handoff
|
||||
Skill(skill="workflow-lite-plan", args=`--from-analysis ${sessionFolder}/handoff-lite-plan.json "${taskDescription}"`)
|
||||
// 3. Call lite-plan with enriched task description (no special flags)
|
||||
Skill(skill="workflow-lite-plan", args=`"${taskDescription}\n\n${contextLines.join('\n')}"`)
|
||||
}
|
||||
```
|
||||
|
||||
@@ -774,7 +769,7 @@ User agrees with current direction, wants deeper code analysis
|
||||
- Need simple task breakdown
|
||||
- Focus on quick execution planning
|
||||
|
||||
> **Note**: Phase 4「生成任务」auto-generates `--from-analysis` handoff. Manual invocation normally not needed after analysis.
|
||||
> **Note**: Phase 4「生成任务」assembles analysis context as inline `## Prior Analysis` block in task description, allowing lite-plan to skip redundant exploration automatically.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -495,8 +495,8 @@ if (fileExists(projectPath)) {
|
||||
Write(projectPath, JSON.stringify(project, null, 2))
|
||||
}
|
||||
|
||||
// Update project-guidelines.json: remove learnings referencing deleted sessions
|
||||
const guidelinesPath = '.workflow/project-guidelines.json'
|
||||
// Update specs/*.md: remove learnings referencing deleted sessions
|
||||
const guidelinesPath = '.workflow/specs/*.md'
|
||||
if (fileExists(guidelinesPath)) {
|
||||
const guidelines = JSON.parse(Read(guidelinesPath))
|
||||
const deletedSessionIds = results.deleted
|
||||
@@ -566,7 +566,7 @@ Cleanup manifest archived to: ${sessionFolder}/cleanup-manifest.json
|
||||
|
||||
## Related Commands
|
||||
|
||||
- `/workflow:session:sync` - Sync session work to project-guidelines + project-tech (正向写入)
|
||||
- `/workflow:session:sync` - Sync session work to specs/*.md + project-tech (正向写入)
|
||||
- `/workflow:session:complete` - Properly archive active sessions
|
||||
- `memory-capture` skill - Save session memory before cleanup
|
||||
- `workflow-execute` skill - View current workflow state
|
||||
|
||||
@@ -208,7 +208,7 @@ Task(
|
||||
### Project Context (MANDATORY)
|
||||
Read and incorporate:
|
||||
- \`.workflow/project-tech.json\` (if exists): Technology stack, architecture
|
||||
- \`.workflow/project-guidelines.json\` (if exists): Constraints, conventions -- apply as HARD CONSTRAINTS on sub-domain splitting and plan structure
|
||||
- \`.workflow/specs/*.md\` (if exists): Constraints, conventions -- apply as HARD CONSTRAINTS on sub-domain splitting and plan structure
|
||||
|
||||
### Input Requirements
|
||||
${taskDescription}
|
||||
@@ -357,7 +357,7 @@ subDomains.map(sub =>
|
||||
### Project Context (MANDATORY)
|
||||
Read and incorporate:
|
||||
- \`.workflow/project-tech.json\` (if exists): Technology stack, architecture
|
||||
- \`.workflow/project-guidelines.json\` (if exists): Constraints, conventions -- apply as HARD CONSTRAINTS
|
||||
- \`.workflow/specs/*.md\` (if exists): Constraints, conventions -- apply as HARD CONSTRAINTS
|
||||
|
||||
## Dual Output Tasks
|
||||
|
||||
|
||||
@@ -630,7 +630,7 @@ Why is config value None during update?
|
||||
|
||||
## Post-Completion Expansion
|
||||
|
||||
**Auto-sync**: 执行 `/workflow:session:sync -y "{summary}"` 更新 project-guidelines + project-tech。
|
||||
**Auto-sync**: 执行 `/workflow:session:sync -y "{summary}"` 更新 specs/*.md + project-tech。
|
||||
|
||||
完成后询问用户是否扩展为issue(test/enhance/refactor/doc),选中项调用 `/issue:new "{summary} - {dimension}"`
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: init-guidelines
|
||||
description: Interactive wizard to fill project-guidelines.json based on project analysis
|
||||
description: Interactive wizard to fill specs/*.md based on project analysis
|
||||
argument-hint: "[--reset]"
|
||||
examples:
|
||||
- /workflow:init-guidelines
|
||||
@@ -11,7 +11,7 @@ examples:
|
||||
|
||||
## Overview
|
||||
|
||||
Interactive multi-round wizard that analyzes the current project (via `project-tech.json`) and asks targeted questions to populate `.workflow/project-guidelines.json` with coding conventions, constraints, and quality rules.
|
||||
Interactive multi-round wizard that analyzes the current project (via `project-tech.json`) and asks targeted questions to populate `.workflow/specs/*.md` with coding conventions, constraints, and quality rules.
|
||||
|
||||
**Design Principle**: Questions are dynamically generated based on the project's tech stack, architecture, and patterns — not generic boilerplate.
|
||||
|
||||
@@ -31,7 +31,7 @@ Input Parsing:
|
||||
|
||||
Step 1: Check Prerequisites
|
||||
├─ project-tech.json must exist (run /workflow:init first)
|
||||
├─ project-guidelines.json: check if populated or scaffold-only
|
||||
├─ specs/*.md: check if populated or scaffold-only
|
||||
└─ If populated + no --reset → Ask: "Guidelines already exist. Overwrite or append?"
|
||||
|
||||
Step 2: Load Project Context
|
||||
@@ -44,7 +44,7 @@ Step 3: Multi-Round Interactive Questionnaire
|
||||
├─ Round 4: Performance & Security Constraints (performance, security)
|
||||
└─ Round 5: Quality Rules (quality_rules)
|
||||
|
||||
Step 4: Write project-guidelines.json
|
||||
Step 4: Write specs/*.md
|
||||
|
||||
Step 5: Display Summary
|
||||
```
|
||||
@@ -55,7 +55,7 @@ Step 5: Display Summary
|
||||
|
||||
```bash
|
||||
bash(test -f .workflow/project-tech.json && echo "TECH_EXISTS" || echo "TECH_NOT_FOUND")
|
||||
bash(test -f .workflow/project-guidelines.json && echo "GUIDELINES_EXISTS" || echo "GUIDELINES_NOT_FOUND")
|
||||
bash(test -f .workflow/specs/coding-conventions.md && echo "SPECS_EXISTS" || echo "SPECS_NOT_FOUND")
|
||||
```
|
||||
|
||||
**If TECH_NOT_FOUND**: Exit with message
|
||||
@@ -71,12 +71,10 @@ const reset = $ARGUMENTS.includes('--reset')
|
||||
**If GUIDELINES_EXISTS and not --reset**: Check if guidelines are populated (not just scaffold)
|
||||
|
||||
```javascript
|
||||
const guidelines = JSON.parse(Read('.workflow/project-guidelines.json'))
|
||||
const isPopulated =
|
||||
guidelines.conventions.coding_style.length > 0 ||
|
||||
guidelines.conventions.naming_patterns.length > 0 ||
|
||||
guidelines.constraints.architecture.length > 0 ||
|
||||
guidelines.constraints.tech_stack.length > 0
|
||||
// Check if specs already have content via ccw spec list
|
||||
const specsList = Bash('ccw spec list --json 2>/dev/null || echo "{}"')
|
||||
const specsData = JSON.parse(specsList)
|
||||
const isPopulated = (specsData.total || 0) > 5 // More than seed docs
|
||||
|
||||
if (isPopulated) {
|
||||
AskUserQuestion({
|
||||
@@ -326,64 +324,76 @@ AskUserQuestion({
|
||||
|
||||
**Process Round 5 answers** → add to `quality_rules` array as `{ rule, scope, enforced_by }` objects.
|
||||
|
||||
### Step 4: Write project-guidelines.json
|
||||
### Step 4: Write specs/*.md
|
||||
|
||||
For each category of collected answers, append rules to the corresponding spec MD file. Each spec file uses YAML frontmatter with `readMode`, `priority`, and `keywords`.
|
||||
|
||||
```javascript
|
||||
// Build the final guidelines object
|
||||
const finalGuidelines = {
|
||||
conventions: {
|
||||
coding_style: existingCodingStyle.concat(newCodingStyle),
|
||||
naming_patterns: existingNamingPatterns.concat(newNamingPatterns),
|
||||
file_structure: existingFileStructure.concat(newFileStructure),
|
||||
documentation: existingDocumentation.concat(newDocumentation)
|
||||
},
|
||||
constraints: {
|
||||
architecture: existingArchitecture.concat(newArchitecture),
|
||||
tech_stack: existingTechStack.concat(newTechStack),
|
||||
performance: existingPerformance.concat(newPerformance),
|
||||
security: existingSecurity.concat(newSecurity)
|
||||
},
|
||||
quality_rules: existingQualityRules.concat(newQualityRules),
|
||||
learnings: existingLearnings, // Preserve existing learnings
|
||||
_metadata: {
|
||||
created_at: existingMetadata?.created_at || new Date().toISOString(),
|
||||
version: "1.0.0",
|
||||
last_updated: new Date().toISOString(),
|
||||
updated_by: "workflow:init-guidelines"
|
||||
}
|
||||
// Helper: append rules to a spec MD file
|
||||
function appendRulesToSpecFile(filePath, rules) {
|
||||
if (rules.length === 0) return
|
||||
const existing = Read(filePath)
|
||||
// Append new rules as markdown list items after existing content
|
||||
const newContent = existing.trimEnd() + '\n' + rules.map(r => `- ${r}`).join('\n') + '\n'
|
||||
Write(filePath, newContent)
|
||||
}
|
||||
|
||||
Write('.workflow/project-guidelines.json', JSON.stringify(finalGuidelines, null, 2))
|
||||
// Write conventions
|
||||
appendRulesToSpecFile('.workflow/specs/coding-conventions.md',
|
||||
[...newCodingStyle, ...newNamingPatterns, ...newFileStructure, ...newDocumentation])
|
||||
|
||||
// Write constraints
|
||||
appendRulesToSpecFile('.workflow/specs/architecture-constraints.md',
|
||||
[...newArchitecture, ...newTechStack, ...newPerformance, ...newSecurity])
|
||||
|
||||
// Write quality rules (create file if needed)
|
||||
if (newQualityRules.length > 0) {
|
||||
const qualityPath = '.workflow/specs/quality-rules.md'
|
||||
if (!file_exists(qualityPath)) {
|
||||
Write(qualityPath, `---
|
||||
title: Quality Rules
|
||||
readMode: required
|
||||
priority: high
|
||||
keywords: [quality, testing, coverage, lint]
|
||||
---
|
||||
|
||||
# Quality Rules
|
||||
|
||||
`)
|
||||
}
|
||||
appendRulesToSpecFile(qualityPath,
|
||||
newQualityRules.map(q => `${q.rule} (scope: ${q.scope}, enforced by: ${q.enforced_by})`))
|
||||
}
|
||||
|
||||
// Rebuild spec index after writing
|
||||
Bash('ccw spec rebuild')
|
||||
```
|
||||
|
||||
### Step 5: Display Summary
|
||||
|
||||
```javascript
|
||||
const countConventions = finalGuidelines.conventions.coding_style.length
|
||||
+ finalGuidelines.conventions.naming_patterns.length
|
||||
+ finalGuidelines.conventions.file_structure.length
|
||||
+ finalGuidelines.conventions.documentation.length
|
||||
const countConventions = newCodingStyle.length + newNamingPatterns.length
|
||||
+ newFileStructure.length + newDocumentation.length
|
||||
const countConstraints = newArchitecture.length + newTechStack.length
|
||||
+ newPerformance.length + newSecurity.length
|
||||
const countQuality = newQualityRules.length
|
||||
|
||||
const countConstraints = finalGuidelines.constraints.architecture.length
|
||||
+ finalGuidelines.constraints.tech_stack.length
|
||||
+ finalGuidelines.constraints.performance.length
|
||||
+ finalGuidelines.constraints.security.length
|
||||
|
||||
const countQuality = finalGuidelines.quality_rules.length
|
||||
// Get updated spec list
|
||||
const specsList = Bash('ccw spec list --json 2>/dev/null || echo "{}"')
|
||||
|
||||
console.log(`
|
||||
✓ Project guidelines configured
|
||||
|
||||
## Summary
|
||||
- Conventions: ${countConventions} rules (coding: ${cs}, naming: ${np}, files: ${fs}, docs: ${doc})
|
||||
- Constraints: ${countConstraints} rules (arch: ${ar}, tech: ${ts}, perf: ${pf}, security: ${sc})
|
||||
- Quality rules: ${countQuality}
|
||||
- Conventions: ${countConventions} rules added to coding-conventions.md
|
||||
- Constraints: ${countConstraints} rules added to architecture-constraints.md
|
||||
- Quality rules: ${countQuality} rules added to quality-rules.md
|
||||
|
||||
File: .workflow/project-guidelines.json
|
||||
Spec index rebuilt. Use \`ccw spec list\` to view all specs.
|
||||
|
||||
Next steps:
|
||||
- Use /workflow:session:solidify to add individual rules later
|
||||
- Guidelines will be auto-loaded by /workflow:plan for task generation
|
||||
- Specs are auto-loaded via hook on each prompt
|
||||
`)
|
||||
```
|
||||
|
||||
|
||||
@@ -10,11 +10,11 @@ examples:
|
||||
# Workflow Init Command (/workflow:init)
|
||||
|
||||
## Overview
|
||||
Initialize `.workflow/project-tech.json` and `.workflow/project-guidelines.json` with comprehensive project understanding by delegating analysis to **cli-explore-agent**.
|
||||
Initialize `.workflow/project-tech.json` and `.workflow/specs/*.md` with comprehensive project understanding by delegating analysis to **cli-explore-agent**.
|
||||
|
||||
**Dual File System**:
|
||||
- `project-tech.json`: Auto-generated technical analysis (stack, architecture, components)
|
||||
- `project-guidelines.json`: User-maintained rules and constraints (created as scaffold)
|
||||
- `specs/*.md`: User-maintained rules and constraints (created as scaffold)
|
||||
|
||||
**Note**: This command may be called by other workflow commands. Upon completion, return immediately to continue the calling workflow without interrupting the task flow.
|
||||
|
||||
@@ -43,7 +43,7 @@ Analysis Flow:
|
||||
│ ├─ Synthesis and merge
|
||||
│ └─ Write .workflow/project-tech.json
|
||||
├─ Create guidelines scaffold (if not exists)
|
||||
│ └─ Write .workflow/project-guidelines.json (empty structure)
|
||||
│ └─ Write .workflow/specs/*.md (empty structure)
|
||||
├─ Display summary
|
||||
└─ Ask about guidelines configuration
|
||||
├─ If guidelines empty → Ask user: "Configure now?" or "Skip"
|
||||
@@ -53,7 +53,7 @@ Analysis Flow:
|
||||
|
||||
Output:
|
||||
├─ .workflow/project-tech.json (+ .backup if regenerate)
|
||||
└─ .workflow/project-guidelines.json (scaffold or configured)
|
||||
└─ .workflow/specs/*.md (scaffold or configured)
|
||||
```
|
||||
|
||||
## Implementation
|
||||
@@ -69,14 +69,14 @@ const regenerate = $ARGUMENTS.includes('--regenerate')
|
||||
|
||||
```bash
|
||||
bash(test -f .workflow/project-tech.json && echo "TECH_EXISTS" || echo "TECH_NOT_FOUND")
|
||||
bash(test -f .workflow/project-guidelines.json && echo "GUIDELINES_EXISTS" || echo "GUIDELINES_NOT_FOUND")
|
||||
bash(test -f .workflow/specs/coding-conventions.md && echo "SPECS_EXISTS" || echo "SPECS_NOT_FOUND")
|
||||
```
|
||||
|
||||
**If BOTH_EXIST and no --regenerate**: Exit early
|
||||
```
|
||||
Project already initialized:
|
||||
- Tech analysis: .workflow/project-tech.json
|
||||
- Guidelines: .workflow/project-guidelines.json
|
||||
- Guidelines: .workflow/specs/*.md
|
||||
|
||||
Use /workflow:init --regenerate to rebuild tech analysis
|
||||
Use /workflow:session:solidify to add guidelines
|
||||
@@ -159,33 +159,13 @@ Project root: ${projectRoot}
|
||||
)
|
||||
```
|
||||
|
||||
### Step 3.5: Create Guidelines Scaffold (if not exists)
|
||||
### Step 3.5: Initialize Spec System (if not exists)
|
||||
|
||||
```javascript
|
||||
// Only create if not exists (never overwrite user guidelines)
|
||||
if (!file_exists('.workflow/project-guidelines.json')) {
|
||||
const guidelinesScaffold = {
|
||||
conventions: {
|
||||
coding_style: [],
|
||||
naming_patterns: [],
|
||||
file_structure: [],
|
||||
documentation: []
|
||||
},
|
||||
constraints: {
|
||||
architecture: [],
|
||||
tech_stack: [],
|
||||
performance: [],
|
||||
security: []
|
||||
},
|
||||
quality_rules: [],
|
||||
learnings: [],
|
||||
_metadata: {
|
||||
created_at: new Date().toISOString(),
|
||||
version: "1.0.0"
|
||||
}
|
||||
};
|
||||
|
||||
Write('.workflow/project-guidelines.json', JSON.stringify(guidelinesScaffold, null, 2));
|
||||
// Initialize spec system if not already initialized
|
||||
if (!file_exists('.workflow/specs/coding-conventions.md')) {
|
||||
Bash('ccw spec init');
|
||||
Bash('ccw spec rebuild');
|
||||
}
|
||||
```
|
||||
|
||||
@@ -193,10 +173,10 @@ if (!file_exists('.workflow/project-guidelines.json')) {
|
||||
|
||||
```javascript
|
||||
const projectTech = JSON.parse(Read('.workflow/project-tech.json'));
|
||||
const guidelinesExists = file_exists('.workflow/project-guidelines.json');
|
||||
const specsInitialized = file_exists('.workflow/specs/coding-conventions.md');
|
||||
|
||||
console.log(`
|
||||
✓ Project initialized successfully
|
||||
Project initialized successfully
|
||||
|
||||
## Project Overview
|
||||
Name: ${projectTech.project_name}
|
||||
@@ -213,7 +193,7 @@ Components: ${projectTech.overview.key_components.length} core modules
|
||||
---
|
||||
Files created:
|
||||
- Tech analysis: .workflow/project-tech.json
|
||||
- Guidelines: .workflow/project-guidelines.json ${guidelinesExists ? '(scaffold)' : ''}
|
||||
- Specs: .workflow/specs/ ${specsInitialized ? '(initialized)' : ''}
|
||||
${regenerate ? '- Backup: .workflow/project-tech.json.backup' : ''}
|
||||
`);
|
||||
```
|
||||
@@ -223,20 +203,16 @@ ${regenerate ? '- Backup: .workflow/project-tech.json.backup' : ''}
|
||||
After displaying the summary, ask the user if they want to configure project guidelines interactively.
|
||||
|
||||
```javascript
|
||||
// Check if guidelines are just a scaffold (empty) or already populated
|
||||
const guidelines = JSON.parse(Read('.workflow/project-guidelines.json'));
|
||||
const isGuidelinesPopulated =
|
||||
guidelines.conventions.coding_style.length > 0 ||
|
||||
guidelines.conventions.naming_patterns.length > 0 ||
|
||||
guidelines.constraints.architecture.length > 0 ||
|
||||
guidelines.constraints.security.length > 0;
|
||||
// Check if specs have user content beyond seed documents
|
||||
const specsList = Bash('ccw spec list --json');
|
||||
const specsCount = JSON.parse(specsList).total || 0;
|
||||
|
||||
// Only ask if guidelines are not yet populated
|
||||
if (!isGuidelinesPopulated) {
|
||||
// Only ask if specs are just seeds
|
||||
if (specsCount <= 5) {
|
||||
const userChoice = AskUserQuestion({
|
||||
questions: [{
|
||||
question: "Would you like to configure project guidelines now? The wizard will ask targeted questions based on your tech stack.",
|
||||
header: "Guidelines",
|
||||
question: "Would you like to configure project specs now? The wizard will ask targeted questions based on your tech stack.",
|
||||
header: "Specs",
|
||||
multiSelect: false,
|
||||
options: [
|
||||
{
|
||||
@@ -245,26 +221,26 @@ if (!isGuidelinesPopulated) {
|
||||
},
|
||||
{
|
||||
label: "Skip for now",
|
||||
description: "You can run /workflow:init-guidelines later or use /workflow:session:solidify to add rules individually"
|
||||
description: "You can run /workflow:init-guidelines later or use ccw spec load to import specs"
|
||||
}
|
||||
]
|
||||
}]
|
||||
});
|
||||
|
||||
if (userChoice.answers["Guidelines"] === "Configure now (Recommended)") {
|
||||
console.log("\n🔧 Starting guidelines configuration wizard...\n");
|
||||
if (userChoice.answers["Specs"] === "Configure now (Recommended)") {
|
||||
console.log("\nStarting specs configuration wizard...\n");
|
||||
Skill(skill="workflow:init-guidelines");
|
||||
} else {
|
||||
console.log(`
|
||||
Next steps:
|
||||
- Use /workflow:init-guidelines to configure guidelines interactively
|
||||
- Use /workflow:session:solidify to add individual rules
|
||||
- Use /workflow:init-guidelines to configure specs interactively
|
||||
- Use ccw spec load to import specs from external sources
|
||||
- Use /workflow:plan to start planning
|
||||
`);
|
||||
}
|
||||
} else {
|
||||
console.log(`
|
||||
Guidelines already configured (${guidelines.conventions.coding_style.length + guidelines.constraints.architecture.length}+ rules).
|
||||
Specs already configured (${specsCount} spec files).
|
||||
|
||||
Next steps:
|
||||
- Use /workflow:init-guidelines --reset to reconfigure
|
||||
|
||||
@@ -843,7 +843,7 @@ AskUserQuestion({
|
||||
|
||||
## Post-Completion Expansion
|
||||
|
||||
**Auto-sync**: 执行 `/workflow:session:sync -y "{summary}"` 更新 project-guidelines + project-tech。
|
||||
**Auto-sync**: 执行 `/workflow:session:sync -y "{summary}"` 更新 specs/*.md + project-tech。
|
||||
|
||||
完成后询问用户是否扩展为issue(test/enhance/refactor/doc),选中项调用 `/issue:new "{summary} - {dimension}"`
|
||||
|
||||
|
||||
@@ -347,7 +347,7 @@ Bash(`mkdir -p ${sessionFolder}`)
|
||||
1. Run: ccw tool exec get_modules_by_depth '{}'
|
||||
2. Execute relevant searches based on requirement keywords
|
||||
3. Read: .workflow/project-tech.json (if exists)
|
||||
4. Read: .workflow/project-guidelines.json (if exists)
|
||||
4. Read: .workflow/specs/*.md (if exists)
|
||||
|
||||
## Exploration Focus
|
||||
- Identify modules/components related to the requirement
|
||||
|
||||
@@ -111,7 +111,7 @@ rm -f .workflow/archives/$SESSION_ID/.archiving
|
||||
|
||||
### Phase 4: Auto-Sync Project State
|
||||
|
||||
Execute `/workflow:session:sync -y "{description}"` to update both `project-guidelines.json` and `project-tech.json` from session context.
|
||||
Execute `/workflow:session:sync -y "{description}"` to update both `specs/*.md` and `project-tech.json` from session context.
|
||||
|
||||
Description 取自 Phase 2 的 `workflow-session.json` description 字段。
|
||||
|
||||
@@ -135,5 +135,5 @@ When `--yes` or `-y` flag is used:
|
||||
Phase 1: find session → create .archiving marker
|
||||
Phase 2: read key files → build manifest entry (no writes)
|
||||
Phase 3: mkdir → mv → update manifest.json → rm marker
|
||||
Phase 4: /workflow:session:sync -y → update project-guidelines + project-tech
|
||||
Phase 4: /workflow:session:sync -y → update specs/*.md + project-tech
|
||||
```
|
||||
|
||||
@@ -18,7 +18,7 @@ When `--yes` or `-y`: Auto-categorize and add guideline without confirmation.
|
||||
|
||||
## Overview
|
||||
|
||||
Crystallizes ephemeral session context (insights, decisions, constraints) into permanent project guidelines stored in `.workflow/project-guidelines.json`. This ensures valuable learnings persist across sessions and inform future planning.
|
||||
Crystallizes ephemeral session context (insights, decisions, constraints) into permanent project guidelines stored in `.workflow/specs/*.md`. This ensures valuable learnings persist across sessions and inform future planning.
|
||||
|
||||
## Use Cases
|
||||
|
||||
@@ -113,34 +113,14 @@ ELSE (convention/constraint/learning):
|
||||
### Step 1: Ensure Guidelines File Exists
|
||||
|
||||
```bash
|
||||
bash(test -f .workflow/project-guidelines.json && echo "EXISTS" || echo "NOT_FOUND")
|
||||
bash(test -f .workflow/specs/coding-conventions.md && echo "EXISTS" || echo "NOT_FOUND")
|
||||
```
|
||||
|
||||
**If NOT_FOUND**, create scaffold:
|
||||
**If NOT_FOUND**, initialize spec system:
|
||||
|
||||
```javascript
|
||||
const scaffold = {
|
||||
conventions: {
|
||||
coding_style: [],
|
||||
naming_patterns: [],
|
||||
file_structure: [],
|
||||
documentation: []
|
||||
},
|
||||
constraints: {
|
||||
architecture: [],
|
||||
tech_stack: [],
|
||||
performance: [],
|
||||
security: []
|
||||
},
|
||||
quality_rules: [],
|
||||
learnings: [],
|
||||
_metadata: {
|
||||
created_at: new Date().toISOString(),
|
||||
version: "1.0.0"
|
||||
}
|
||||
};
|
||||
|
||||
Write('.workflow/project-guidelines.json', JSON.stringify(scaffold, null, 2));
|
||||
```bash
|
||||
Bash('ccw spec init')
|
||||
Bash('ccw spec rebuild')
|
||||
```
|
||||
|
||||
### Step 2: Auto-detect Type (if not specified)
|
||||
@@ -203,33 +183,40 @@ function buildEntry(rule, type, category, sessionId) {
|
||||
}
|
||||
```
|
||||
|
||||
### Step 4: Update Guidelines File
|
||||
### Step 4: Update Spec Files
|
||||
|
||||
```javascript
|
||||
const guidelines = JSON.parse(Read('.workflow/project-guidelines.json'));
|
||||
|
||||
if (type === 'convention') {
|
||||
if (!guidelines.conventions[category]) {
|
||||
guidelines.conventions[category] = [];
|
||||
}
|
||||
if (!guidelines.conventions[category].includes(rule)) {
|
||||
guidelines.conventions[category].push(rule);
|
||||
}
|
||||
} else if (type === 'constraint') {
|
||||
if (!guidelines.constraints[category]) {
|
||||
guidelines.constraints[category] = [];
|
||||
}
|
||||
if (!guidelines.constraints[category].includes(rule)) {
|
||||
guidelines.constraints[category].push(rule);
|
||||
}
|
||||
} else if (type === 'learning') {
|
||||
guidelines.learnings.push(buildEntry(rule, type, category, sessionId));
|
||||
// Map type+category to target spec file
|
||||
const specFileMap = {
|
||||
convention: '.workflow/specs/coding-conventions.md',
|
||||
constraint: '.workflow/specs/architecture-constraints.md'
|
||||
}
|
||||
|
||||
guidelines._metadata.updated_at = new Date().toISOString();
|
||||
guidelines._metadata.last_solidified_by = sessionId;
|
||||
if (type === 'convention' || type === 'constraint') {
|
||||
const targetFile = specFileMap[type]
|
||||
const existing = Read(targetFile)
|
||||
|
||||
Write('.workflow/project-guidelines.json', JSON.stringify(guidelines, null, 2));
|
||||
// Deduplicate: skip if rule text already exists in the file
|
||||
if (!existing.includes(rule)) {
|
||||
const ruleText = `- [${category}] ${rule}`
|
||||
const newContent = existing.trimEnd() + '\n' + ruleText + '\n'
|
||||
Write(targetFile, newContent)
|
||||
}
|
||||
} else if (type === 'learning') {
|
||||
// Learnings go to coding-conventions.md as a special section
|
||||
const targetFile = '.workflow/specs/coding-conventions.md'
|
||||
const existing = Read(targetFile)
|
||||
const entry = buildEntry(rule, type, category, sessionId)
|
||||
const learningText = `- [learning/${category}] ${entry.insight} (${entry.date})`
|
||||
|
||||
if (!existing.includes(entry.insight)) {
|
||||
const newContent = existing.trimEnd() + '\n' + learningText + '\n'
|
||||
Write(targetFile, newContent)
|
||||
}
|
||||
}
|
||||
|
||||
// Rebuild spec index after modification
|
||||
Bash('ccw spec rebuild')
|
||||
```
|
||||
|
||||
### Step 5: Display Confirmation
|
||||
@@ -241,7 +228,7 @@ Type: ${type}
|
||||
Category: ${category}
|
||||
Rule: "${rule}"
|
||||
|
||||
Location: .workflow/project-guidelines.json -> ${type}s.${category}
|
||||
Location: .workflow/specs/*.md -> ${type}s.${category}
|
||||
|
||||
Total ${type}s in ${category}: ${count}
|
||||
```
|
||||
@@ -386,7 +373,7 @@ AskUserQuestion({
|
||||
/workflow:session:solidify "Use async/await instead of callbacks" --type convention --category coding_style
|
||||
```
|
||||
|
||||
Result in `project-guidelines.json`:
|
||||
Result in `specs/*.md`:
|
||||
```json
|
||||
{
|
||||
"conventions": {
|
||||
@@ -444,7 +431,7 @@ Result: Creates a new CMEM with consolidated content from the 10 most recent non
|
||||
|
||||
## Integration with Planning
|
||||
|
||||
The `project-guidelines.json` is consumed by:
|
||||
The `specs/*.md` is consumed by:
|
||||
|
||||
1. **`workflow-plan` skill (context-gather phase)**: Loads guidelines into context-package.json
|
||||
2. **`workflow-plan` skill**: Passes guidelines to task generation agent
|
||||
@@ -462,4 +449,4 @@ This ensures all future planning respects solidified rules without users needing
|
||||
|
||||
- `/workflow:session:start` - Start a session (may prompt for solidify at end)
|
||||
- `/workflow:session:complete` - Complete session (prompts for learnings to solidify)
|
||||
- `/workflow:init` - Creates project-guidelines.json scaffold if missing
|
||||
- `/workflow:init` - Creates specs/*.md scaffold if missing
|
||||
|
||||
@@ -44,7 +44,7 @@ ERROR: Invalid session type. Valid types: workflow, review, tdd, test, docs
|
||||
```bash
|
||||
# Check if project state exists (both files required)
|
||||
bash(test -f .workflow/project-tech.json && echo "TECH_EXISTS" || echo "TECH_NOT_FOUND")
|
||||
bash(test -f .workflow/project-guidelines.json && echo "GUIDELINES_EXISTS" || echo "GUIDELINES_NOT_FOUND")
|
||||
bash(test -f .workflow/specs/*.md && echo "GUIDELINES_EXISTS" || echo "GUIDELINES_NOT_FOUND")
|
||||
```
|
||||
|
||||
**If either NOT_FOUND**, delegate to `/workflow:init`:
|
||||
@@ -53,14 +53,14 @@ bash(test -f .workflow/project-guidelines.json && echo "GUIDELINES_EXISTS" || ec
|
||||
Skill(skill="workflow:init");
|
||||
|
||||
// Wait for init completion
|
||||
// project-tech.json and project-guidelines.json will be created
|
||||
// project-tech.json and specs/*.md will be created
|
||||
```
|
||||
|
||||
**Output**:
|
||||
- If BOTH_EXIST: `PROJECT_STATE: initialized`
|
||||
- If NOT_FOUND: Calls `/workflow:init` → creates:
|
||||
- `.workflow/project-tech.json` with full technical analysis
|
||||
- `.workflow/project-guidelines.json` with empty scaffold
|
||||
- `.workflow/specs/*.md` with empty scaffold
|
||||
|
||||
**Note**: `/workflow:init` uses cli-explore-agent to build comprehensive project understanding (technology stack, architecture, key components). This step runs once per project. Subsequent executions skip initialization.
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
---
|
||||
name: sync
|
||||
description: Quick-sync session work to project-guidelines and project-tech
|
||||
description: Quick-sync session work to specs/*.md and project-tech
|
||||
argument-hint: "[-y|--yes] [\"what was done\"]"
|
||||
allowed-tools: Bash(*), Read(*), Write(*), Edit(*)
|
||||
---
|
||||
|
||||
# Session Sync (/workflow:session:sync)
|
||||
|
||||
One-shot update `project-guidelines.json` + `project-tech.json` from current session context.
|
||||
One-shot update `specs/*.md` + `project-tech.json` from current session context.
|
||||
|
||||
**Design**: Scan context → extract → write. No interactive wizards.
|
||||
|
||||
@@ -73,7 +73,8 @@ Analyze context and produce two update payloads. Use LLM reasoning (current agen
|
||||
// RULE: Only extract genuinely reusable insights. Skip trivial/obvious items.
|
||||
// RULE: Deduplicate against existing guidelines before adding.
|
||||
|
||||
const existingGuidelines = JSON.parse(Read('.workflow/project-guidelines.json'))
|
||||
// Load existing specs via ccw spec load
|
||||
const existingSpecs = Bash('ccw spec load --dimension specs 2>/dev/null || echo ""')
|
||||
const guidelineUpdates = [] // populated by agent analysis
|
||||
|
||||
// ── Tech extraction ──
|
||||
@@ -123,7 +124,7 @@ Tech [${detectCategory(summary)}]:
|
||||
${techEntry.title}
|
||||
|
||||
Target files:
|
||||
.workflow/project-guidelines.json
|
||||
.workflow/specs/*.md
|
||||
.workflow/project-tech.json
|
||||
`)
|
||||
|
||||
@@ -136,33 +137,31 @@ if (!autoYes) {
|
||||
## Step 4: Write
|
||||
|
||||
```javascript
|
||||
// ── Update project-guidelines.json ──
|
||||
// ── Update specs/*.md ──
|
||||
if (guidelineUpdates.length > 0) {
|
||||
const guidelines = JSON.parse(Read('.workflow/project-guidelines.json'))
|
||||
// Map guideline types to spec files
|
||||
const specFileMap = {
|
||||
convention: '.workflow/specs/coding-conventions.md',
|
||||
constraint: '.workflow/specs/architecture-constraints.md',
|
||||
learning: '.workflow/specs/coding-conventions.md' // learnings appended to conventions
|
||||
}
|
||||
|
||||
for (const g of guidelineUpdates) {
|
||||
if (g.type === 'learning') {
|
||||
// Deduplicate by insight text
|
||||
if (!guidelines.learnings.some(l => l.insight === g.text)) {
|
||||
guidelines.learnings.push({
|
||||
date: new Date().toISOString().split('T')[0],
|
||||
session_id: techEntry.session_id,
|
||||
insight: g.text,
|
||||
category: g.category
|
||||
})
|
||||
}
|
||||
} else {
|
||||
// convention or constraint
|
||||
const section = g.type === 'convention' ? 'conventions' : 'constraints'
|
||||
if (!guidelines[section][g.category]) guidelines[section][g.category] = []
|
||||
if (!guidelines[section][g.category].includes(g.text)) {
|
||||
guidelines[section][g.category].push(g.text)
|
||||
}
|
||||
const targetFile = specFileMap[g.type]
|
||||
const existing = Read(targetFile)
|
||||
const ruleText = g.type === 'learning'
|
||||
? `- [${g.category}] ${g.text} (learned: ${new Date().toISOString().split('T')[0]})`
|
||||
: `- [${g.category}] ${g.text}`
|
||||
|
||||
// Deduplicate: skip if text already in file
|
||||
if (!existing.includes(g.text)) {
|
||||
const newContent = existing.trimEnd() + '\n' + ruleText + '\n'
|
||||
Write(targetFile, newContent)
|
||||
}
|
||||
}
|
||||
|
||||
guidelines._metadata.updated_at = new Date().toISOString()
|
||||
Write('.workflow/project-guidelines.json', JSON.stringify(guidelines, null, 2))
|
||||
// Rebuild spec index after writing
|
||||
Bash('ccw spec rebuild')
|
||||
}
|
||||
|
||||
// ── Update project-tech.json ──
|
||||
|
||||
@@ -476,9 +476,9 @@ ${recommendations.map(r => \`- ${r}\`).join('\\n')}
|
||||
// Read project-tech.json (if exists)
|
||||
const projectTech = file_exists('.workflow/project-tech.json')
|
||||
? JSON.parse(Read('.workflow/project-tech.json')) : null
|
||||
// Read project-guidelines.json (if exists)
|
||||
const projectGuidelines = file_exists('.workflow/project-guidelines.json')
|
||||
? JSON.parse(Read('.workflow/project-guidelines.json')) : null
|
||||
// Read specs/*.md (if exists)
|
||||
const projectGuidelines = file_exists('.workflow/specs/*.md')
|
||||
? JSON.parse(Read('.workflow/specs/*.md')) : null
|
||||
```
|
||||
|
||||
```javascript
|
||||
|
||||
Reference in New Issue
Block a user