diff --git a/.claude/skills/team-lifecycle/SKILL.md b/.claude/skills/team-lifecycle/SKILL.md index 828b28a4..d66e9b06 100644 --- a/.claude/skills/team-lifecycle/SKILL.md +++ b/.claude/skills/team-lifecycle/SKILL.md @@ -310,6 +310,22 @@ Task({ }) ``` +## Shared Spec Resources + +Writer 和 Reviewer 角色在 spec 模式下使用本 skill 内置的标准和模板(从 spec-generator 复制,独立维护): + +| Resource | Path | Usage | +|----------|------|-------| +| Document Standards | `specs/document-standards.md` | YAML frontmatter、命名规范、内容结构 | +| Quality Gates | `specs/quality-gates.md` | Per-phase 质量门禁、评分标尺 | +| Product Brief Template | `templates/product-brief.md` | DRAFT-001 文档生成 | +| Requirements Template | `templates/requirements-prd.md` | DRAFT-002 文档生成 | +| Architecture Template | `templates/architecture-doc.md` | DRAFT-003 文档生成 | +| Epics Template | `templates/epics-template.md` | DRAFT-004 文档生成 | + +> Writer 在执行每个 DRAFT-* 任务前 **必须先 Read** 对应的 template 文件和 document-standards.md。 +> 从 `roles/` 子目录引用时路径为 `../specs/` 和 `../templates/`。 + ## Error Handling | Scenario | Resolution | diff --git a/.claude/skills/team-lifecycle/roles/analyst.md b/.claude/skills/team-lifecycle/roles/analyst.md index 4e034911..13c09068 100644 --- a/.claude/skills/team-lifecycle/roles/analyst.md +++ b/.claude/skills/team-lifecycle/roles/analyst.md @@ -65,7 +65,12 @@ const sessionFolder = sessionMatch ? sessionMatch[1].trim() : '.workflow/.spec-t // Parse topic from task description const topicLines = task.description.split('\n').filter(l => !l.startsWith('Session:') && !l.startsWith('输出:') && l.trim()) -const topic = topicLines[0] || task.subject.replace('RESEARCH-001: ', '') +const rawTopic = topicLines[0] || task.subject.replace('RESEARCH-001: ', '') + +// 支持文件引用输入(与 spec-generator Phase 1 一致) +const topic = (rawTopic.startsWith('@') || rawTopic.endsWith('.md') || rawTopic.endsWith('.txt')) + ? Read(rawTopic.replace(/^@/, '')) + : rawTopic // Use Gemini CLI for seed analysis Bash({ @@ -122,6 +127,9 @@ const specConfig = { topic: topic, status: "research_complete", complexity: seedAnalysis.complexity_assessment || "moderate", + depth: task.description.match(/讨论深度:\s*(.+)/)?.[1] || "standard", + focus_areas: seedAnalysis.exploration_dimensions || [], + mode: "interactive", // team 模式始终交互 phases_completed: ["discovery"], created_at: new Date().toISOString(), session_folder: sessionFolder, diff --git a/.claude/skills/team-lifecycle/roles/coordinator.md b/.claude/skills/team-lifecycle/roles/coordinator.md index dc11a384..44a63c90 100644 --- a/.claude/skills/team-lifecycle/roles/coordinator.md +++ b/.claude/skills/team-lifecycle/roles/coordinator.md @@ -321,9 +321,184 @@ AskUserQuestion({ ] }] }) -// 新需求 → 回到 Phase 1(复用 team,新建任务链) -// 交付执行 → 提示可用的执行 workflow -// 关闭 → shutdown 给每个 teammate → TeamDelete() + +// === 新需求 → 回到 Phase 1(复用 team,新建任务链)=== + +// === 交付执行 → Handoff 逻辑 === +if (userChoice === '交付执行') { + AskUserQuestion({ + questions: [{ + question: "选择交付方式:", + header: "Handoff", + multiSelect: false, + options: [ + { label: "lite-plan", description: "逐 Epic 轻量执行" }, + { label: "full-plan", description: "完整规划(创建 WFS session + .brainstorming/ 桥接)" }, + { label: "req-plan", description: "需求级路线图规划" }, + { label: "create-issues", description: "每个 Epic 创建 issue" } + ] + }] + }) + + // 读取 spec 文档 + const specConfig = JSON.parse(Read(`${specSessionFolder}/spec-config.json`)) + const specSummary = Read(`${specSessionFolder}/spec-summary.md`) + const productBrief = Read(`${specSessionFolder}/product-brief.md`) + const requirementsIndex = Read(`${specSessionFolder}/requirements/_index.md`) + const architectureIndex = Read(`${specSessionFolder}/architecture/_index.md`) + const epicsIndex = Read(`${specSessionFolder}/epics/_index.md`) + const epicFiles = Glob(`${specSessionFolder}/epics/EPIC-*.md`) + + if (handoffChoice === 'lite-plan') { + // 读取首个 MVP Epic → 调用 lite-plan + const firstMvpFile = epicFiles.find(f => { + const content = Read(f) + return content.includes('mvp: true') + }) + const epicContent = Read(firstMvpFile) + const title = epicContent.match(/^#\s+(.+)/m)?.[1] || '' + const description = epicContent.match(/## Description\n([\s\S]*?)(?=\n## )/)?.[1]?.trim() || '' + Skill({ skill: "workflow:lite-plan", args: `"${title}: ${description}"` }) + } + + if (handoffChoice === 'full-plan' || handoffChoice === 'req-plan') { + // === 桥接: 构建 .brainstorming/ 兼容结构 === + // 从 spec-generator Phase 6 Step 6 适配 + + // Step A: 构建结构化描述 + const structuredDesc = `GOAL: ${specConfig.seed_analysis?.problem_statement || specConfig.topic} +SCOPE: ${specConfig.complexity} complexity +CONTEXT: Generated from spec team session ${specConfig.session_id}. Source: ${specSessionFolder}/` + + // Step B: 创建 WFS session + Skill({ skill: "workflow:session:start", args: `--auto "${structuredDesc}"` }) + // → 产出 sessionId (WFS-xxx) 和 session 目录 + + // Step C: 创建 .brainstorming/ 桥接文件 + const brainstormDir = `.workflow/active/${sessionId}/.brainstorming` + Bash(`mkdir -p "${brainstormDir}/feature-specs"`) + + // C.1: guidance-specification.md(action-planning-agent 最高优先读取) + Write(`${brainstormDir}/guidance-specification.md`, ` +# ${specConfig.seed_analysis?.problem_statement || specConfig.topic} - Confirmed Guidance Specification + +**Source**: spec-team session ${specConfig.session_id} +**Generated**: ${new Date().toISOString()} +**Spec Directory**: ${specSessionFolder} + +## 1. Project Positioning & Goals +${extractSection(productBrief, "Vision")} +${extractSection(productBrief, "Goals")} + +## 2. Requirements Summary +${extractSection(requirementsIndex, "Functional Requirements")} + +## 3. Architecture Decisions +${extractSection(architectureIndex, "Architecture Decision Records")} +${extractSection(architectureIndex, "Technology Stack")} + +## 4. Implementation Scope +${extractSection(epicsIndex, "Epic Overview")} +${extractSection(epicsIndex, "MVP Scope")} + +## Feature Decomposition +${extractSection(epicsIndex, "Traceability Matrix")} + +## Appendix: Source Documents +| Document | Path | Description | +|----------|------|-------------| +| Product Brief | ${specSessionFolder}/product-brief.md | Vision, goals, scope | +| Requirements | ${specSessionFolder}/requirements/ | _index.md + REQ-*.md + NFR-*.md | +| Architecture | ${specSessionFolder}/architecture/ | _index.md + ADR-*.md | +| Epics | ${specSessionFolder}/epics/ | _index.md + EPIC-*.md | +| Readiness Report | ${specSessionFolder}/readiness-report.md | Quality validation | +`) + + // C.2: feature-index.json(EPIC → Feature 映射) + const features = epicFiles.map(epicFile => { + const content = Read(epicFile) + const fmMatch = content.match(/^---\n([\s\S]*?)\n---/) + const fm = fmMatch ? parseYAML(fmMatch[1]) : {} + const basename = epicFile.replace(/.*[/\\]/, '').replace('.md', '') + const epicNum = (fm.id || '').replace('EPIC-', '') + const slug = basename.replace(/^EPIC-\d+-/, '') + return { + id: `F-${epicNum}`, slug, name: content.match(/^#\s+(.+)/m)?.[1] || '', + priority: fm.mvp ? "High" : "Medium", + spec_path: `${brainstormDir}/feature-specs/F-${epicNum}-${slug}.md`, + source_epic: fm.id, source_file: epicFile + } + }) + Write(`${brainstormDir}/feature-specs/feature-index.json`, JSON.stringify({ + version: "1.0", source: "spec-team", + spec_session: specConfig.session_id, features, cross_cutting_specs: [] + }, null, 2)) + + // C.3: Feature-spec 文件(EPIC → F-*.md 转换) + features.forEach(feature => { + const epicContent = Read(feature.source_file) + Write(feature.spec_path, ` +# Feature Spec: ${feature.source_epic} - ${feature.name} + +**Source**: ${feature.source_file} +**Priority**: ${feature.priority === "High" ? "MVP" : "Post-MVP"} + +## Description +${extractSection(epicContent, "Description")} + +## Stories +${extractSection(epicContent, "Stories")} + +## Requirements +${extractSection(epicContent, "Requirements")} + +## Architecture +${extractSection(epicContent, "Architecture")} +`) + }) + + // Step D: 调用下游 workflow + if (handoffChoice === 'full-plan') { + Skill({ skill: "workflow:plan", args: `"${structuredDesc}"` }) + } else { + Skill({ skill: "workflow:req-plan-with-file", args: `"${specConfig.seed_analysis?.problem_statement || specConfig.topic}"` }) + } + } + + if (handoffChoice === 'create-issues') { + // 逐 EPIC 文件创建 issue + epicFiles.forEach(epicFile => { + const content = Read(epicFile) + const title = content.match(/^#\s+(.+)/m)?.[1] || '' + const description = content.match(/## Description\n([\s\S]*?)(?=\n## )/)?.[1]?.trim() || '' + Skill({ skill: "issue:new", args: `"${title}: ${description}"` }) + }) + } +} + +// === 关闭 → shutdown 给每个 teammate → TeamDelete() === +``` + +#### Helper Functions Reference (pseudocode) + +```javascript +// Extract a named ## section from a markdown document +function extractSection(markdown, sectionName) { + // Return content between ## {sectionName} and next ## heading + const regex = new RegExp(`## ${sectionName}\\n([\\s\\S]*?)(?=\\n## |$)`) + return markdown.match(regex)?.[1]?.trim() || '' +} + +// Parse YAML frontmatter string into object +function parseYAML(yamlStr) { + // Simple key-value parsing from YAML frontmatter + const result = {} + yamlStr.split('\n').forEach(line => { + const match = line.match(/^(\w+):\s*(.+)/) + if (match) result[match[1]] = match[2].replace(/^["']|["']$/g, '') + }) + return result +} ``` ## Session File Structure diff --git a/.claude/skills/team-lifecycle/roles/reviewer.md b/.claude/skills/team-lifecycle/roles/reviewer.md index 6efb1930..fb3e3fc4 100644 --- a/.claude/skills/team-lifecycle/roles/reviewer.md +++ b/.claude/skills/team-lifecycle/roles/reviewer.md @@ -101,6 +101,10 @@ if (reviewMode === 'spec') { const sessionMatch = task.description.match(/Session:\s*(.+)/) const sessionFolder = sessionMatch ? sessionMatch[1].trim() : '' + // 加载质量门禁标准(引用 spec-generator 共享资源) + let qualityGates = null + try { qualityGates = Read('../specs/quality-gates.md') } catch {} + // Load all spec documents const documents = { config: null, discoveryContext: null, productBrief: null, @@ -227,6 +231,7 @@ if (reviewMode === 'spec') { // Completeness (25%): all sections present with content function scoreCompleteness(docs) { let score = 0 + const issues = [] const checks = [ { name: 'spec-config.json', present: !!docs.config, weight: 5 }, { name: 'discovery-context.json', present: !!docs.discoveryContext, weight: 10 }, @@ -238,8 +243,54 @@ if (reviewMode === 'spec') { { name: 'epics/_index.md', present: !!docs.epicsIndex, weight: 10 }, { name: 'EPIC-* files', present: docs.epics.length > 0, weight: 5 } ] - checks.forEach(c => { if (c.present) score += c.weight }) - return { score, issues: checks.filter(c => !c.present).map(c => `Missing: ${c.name}`) } + checks.forEach(c => { if (c.present) score += c.weight; else issues.push(`Missing: ${c.name}`) }) + + // 增强: section 内容检查(不仅检查文件是否存在,还检查关键 section 是否有实质内容) + if (docs.productBrief) { + const briefSections = ['## Vision', '## Problem Statement', '## Target Users', '## Goals', '## Scope'] + const missingSections = briefSections.filter(s => !docs.productBrief.includes(s)) + if (missingSections.length > 0) { + score -= missingSections.length * 3 + issues.push(`Product Brief missing sections: ${missingSections.join(', ')}`) + } + } + + if (docs.requirementsIndex) { + const reqSections = ['## Functional Requirements', '## Non-Functional Requirements', '## MoSCoW Summary'] + const missingReqSections = reqSections.filter(s => !docs.requirementsIndex.includes(s)) + if (missingReqSections.length > 0) { + score -= missingReqSections.length * 3 + issues.push(`Requirements index missing sections: ${missingReqSections.join(', ')}`) + } + } + + if (docs.architectureIndex) { + const archSections = ['## Architecture Decision Records', '## Technology Stack'] + const missingArchSections = archSections.filter(s => !docs.architectureIndex.includes(s)) + if (missingArchSections.length > 0) { + score -= missingArchSections.length * 3 + issues.push(`Architecture index missing sections: ${missingArchSections.join(', ')}`) + } + if (!docs.architectureIndex.includes('```mermaid')) { + score -= 5 + issues.push('Architecture index missing Mermaid component diagram') + } + } + + if (docs.epicsIndex) { + const epicsSections = ['## Epic Overview', '## MVP Scope'] + const missingEpicsSections = epicsSections.filter(s => !docs.epicsIndex.includes(s)) + if (missingEpicsSections.length > 0) { + score -= missingEpicsSections.length * 3 + issues.push(`Epics index missing sections: ${missingEpicsSections.join(', ')}`) + } + if (!docs.epicsIndex.includes('```mermaid')) { + score -= 5 + issues.push('Epics index missing Mermaid dependency diagram') + } + } + + return { score: Math.max(0, score), issues } } // Consistency (25%): terminology, format, references @@ -391,6 +442,31 @@ version: 1 ## Quality Gate: ${qualityGate} +## Per-Phase Quality Gates +${qualityGates ? `_(Applied from ../specs/quality-gates.md)_ + +### Phase 2 (Product Brief) +- Vision statement: ${docs.productBrief?.includes('## Vision') ? 'PASS' : 'MISSING'} +- Problem statement specificity: ${docs.productBrief?.match(/## Problem/)?.length ? 'PASS' : 'MISSING'} +- Target users >= 1: ${docs.productBrief?.includes('## Target Users') ? 'PASS' : 'MISSING'} +- Measurable goals >= 2: ${docs.productBrief?.includes('## Goals') ? 'PASS' : 'MISSING'} + +### Phase 3 (Requirements) +- Functional requirements >= 3: ${docs.requirements.length >= 3 ? 'PASS' : 'FAIL (' + docs.requirements.length + ')'} +- Acceptance criteria present: ${docs.requirements.some(r => /acceptance|criteria/i.test(r)) ? 'PASS' : 'MISSING'} +- MoSCoW priority tags: ${docs.requirementsIndex?.includes('Must') ? 'PASS' : 'MISSING'} + +### Phase 4 (Architecture) +- Component diagram: ${docs.architectureIndex?.includes('mermaid') ? 'PASS' : 'MISSING'} +- ADR with alternatives: ${docs.adrs.some(a => /alternative|option/i.test(a)) ? 'PASS' : 'MISSING'} +- Tech stack specified: ${docs.architectureIndex?.includes('Technology') ? 'PASS' : 'MISSING'} + +### Phase 5 (Epics) +- MVP subset tagged: ${docs.epics.some(e => /mvp:\s*true/i.test(e)) ? 'PASS' : 'MISSING'} +- Dependency map: ${docs.epicsIndex?.includes('mermaid') ? 'PASS' : 'MISSING'} +- Story sizing: ${docs.epics.some(e => /\b[SMLX]{1,2}\b|Small|Medium|Large/.test(e)) ? 'PASS' : 'MISSING'} +` : '_(quality-gates.md not loaded)_'} + ## Issues Found ${allSpecIssues.map(i => '- ' + i).join('\n') || 'None'} diff --git a/.claude/skills/team-lifecycle/roles/writer.md b/.claude/skills/team-lifecycle/roles/writer.md index f2631063..b6348263 100644 --- a/.claude/skills/team-lifecycle/roles/writer.md +++ b/.claude/skills/team-lifecycle/roles/writer.md @@ -106,17 +106,564 @@ if (docType === 'epics') { ### Phase 3: Document Generation (type-specific) -Route to specific generation logic based on document type: +**前置步骤(所有类型共用)**: -**DRAFT-001: Product Brief** — Multi-perspective analysis using 3 parallel CLI analyses (product/technical/user), then synthesize into product-brief.md with YAML frontmatter. +```javascript +// 1. 加载格式规范 +const docStandards = Read('../specs/document-standards.md') -**DRAFT-002: Requirements/PRD** — Expand requirements from Product Brief via CLI. Generate REQ-NNN functional requirements + NFR-{type}-NNN non-functional requirements with MoSCoW prioritization. Output to requirements/ directory. +// 2. 加载对应 template 文件(路径见 SKILL.md Shared Spec Resources) +const templateMap = { + 'product-brief': '../templates/product-brief.md', + 'requirements': '../templates/requirements-prd.md', + 'architecture': '../templates/architecture-doc.md', + 'epics': '../templates/epics-template.md' +} +const template = Read(templateMap[docType]) -**DRAFT-003: Architecture** — Design system architecture from requirements via CLI. Generate architecture/_index.md + ADR-*.md files with tech stack, component diagrams (Mermaid), and data model. +// 3. 构建 sharedContext +const seedAnalysis = specConfig?.seed_analysis || discoveryContext?.seed_analysis || {} +const sharedContext = ` +SEED: ${specConfig?.topic || ''} +PROBLEM: ${seedAnalysis.problem_statement || ''} +TARGET USERS: ${(seedAnalysis.target_users || []).join(', ')} +DOMAIN: ${seedAnalysis.domain || ''} +CONSTRAINTS: ${(seedAnalysis.constraints || []).join(', ')} +FOCUS AREAS: ${(specConfig?.focus_areas || []).join(', ')} +${priorDocs.discoveryContext ? ` +CODEBASE CONTEXT: +- Existing patterns: ${JSON.parse(priorDocs.discoveryContext).existing_patterns?.slice(0,5).join(', ') || 'none'} +- Tech stack: ${JSON.stringify(JSON.parse(priorDocs.discoveryContext).tech_stack || {})} +` : ''}` -**DRAFT-004: Epics & Stories** — Decompose requirements into EPIC-* with STORY-* user stories, cross-Epic dependency map, MVP scope definition, and execution order. Output to epics/ directory. +// 4. 路由到具体类型 +``` -Each uses CLI tools (gemini/codex/claude) for multi-perspective analysis, with discussion feedback integration from the preceding DISCUSS round. +#### DRAFT-001: Product Brief + +3 路并行 CLI 分析(产品视角/技术视角/用户视角),综合后生成 product-brief.md。 + +```javascript +if (docType === 'product-brief') { + // === 并行 CLI 分析 === + + // 产品视角 (Gemini) + Bash({ + command: `ccw cli -p "PURPOSE: Product analysis for specification - identify market fit, user value, and success criteria. +Success: Clear vision, measurable goals, competitive positioning. + +${sharedContext} + +TASK: +- Define product vision (1-3 sentences, aspirational) +- Analyze market/competitive landscape +- Define 3-5 measurable success metrics +- Identify scope boundaries (in-scope vs out-of-scope) +- Assess user value proposition +- List assumptions that need validation + +MODE: analysis +EXPECTED: Structured product analysis with: vision, goals with metrics, scope, competitive positioning, assumptions +CONSTRAINTS: Focus on 'what' and 'why', not 'how' +" --tool gemini --mode analysis`, + run_in_background: true + }) + + // 技术视角 (Codex) + Bash({ + command: `ccw cli -p "PURPOSE: Technical feasibility analysis for specification - assess implementation viability and constraints. +Success: Clear technical constraints, integration complexity, technology recommendations. + +${sharedContext} + +TASK: +- Assess technical feasibility of the core concept +- Identify technical constraints and blockers +- Evaluate integration complexity with existing systems +- Recommend technology approach (high-level) +- Identify technical risks and dependencies +- Estimate complexity: simple/moderate/complex + +MODE: analysis +EXPECTED: Technical analysis with: feasibility assessment, constraints, integration complexity, tech recommendations, risks +CONSTRAINTS: Focus on feasibility and constraints, not detailed architecture +" --tool codex --mode analysis`, + run_in_background: true + }) + + // 用户视角 (Claude) + Bash({ + command: `ccw cli -p "PURPOSE: User experience analysis for specification - understand user journeys, pain points, and UX considerations. +Success: Clear user personas, journey maps, UX requirements. + +${sharedContext} + +TASK: +- Elaborate user personas with goals and frustrations +- Map primary user journey (happy path) +- Identify key pain points in current experience +- Define UX success criteria +- List accessibility and usability considerations +- Suggest interaction patterns + +MODE: analysis +EXPECTED: User analysis with: personas, journey map, pain points, UX criteria, interaction recommendations +CONSTRAINTS: Focus on user needs and experience, not implementation +" --tool claude --mode analysis`, + run_in_background: true + }) + + // STOP: Wait for all 3 CLI results + + // === 综合三视角 === + const synthesis = { + convergent_themes: [], // 三视角一致的主题 + conflicts: [], // 视角冲突点 + product_insights: [], // 产品视角独特洞察 + technical_insights: [], // 技术视角独特洞察 + user_insights: [] // 用户视角独特洞察 + } + + // === 整合讨论反馈 === + if (discussionFeedback) { + // 从 discuss-001-scope.md 提取共识和调整建议 + // 将讨论结论融入 synthesis + } + + // === 按 template 生成文档 === + const frontmatter = `--- +session_id: ${specConfig?.session_id || 'unknown'} +phase: 2 +document_type: product-brief +status: draft +generated_at: ${new Date().toISOString()} +version: 1 +dependencies: + - spec-config.json + - discovery-context.json +---` + + // 填充 template 中所有 section: Vision, Problem Statement, Target Users, Goals, Scope + // 应用 document-standards.md 格式规范 + + Write(`${sessionFolder}/product-brief.md`, `${frontmatter}\n\n${filledContent}`) + outputPath = 'product-brief.md' +} +``` + +#### DRAFT-002: Requirements/PRD + +通过 Gemini CLI 扩展需求,生成 REQ-NNN + NFR-{type}-NNN 文件。 + +```javascript +if (docType === 'requirements') { + // === 需求扩展 CLI === + Bash({ + command: `ccw cli -p "PURPOSE: Generate detailed functional and non-functional requirements from product brief. +Success: Complete PRD with testable acceptance criteria for every requirement. + +PRODUCT BRIEF CONTEXT: +${priorDocs.productBrief?.slice(0, 3000) || ''} + +${sharedContext} + +TASK: +- For each goal in the product brief, generate 3-7 functional requirements +- Each requirement must have: + - Unique ID: REQ-NNN (zero-padded) + - Clear title + - Detailed description + - User story: As a [persona], I want [action] so that [benefit] + - 2-4 specific, testable acceptance criteria +- Generate non-functional requirements: + - Performance (response times, throughput) + - Security (authentication, authorization, data protection) + - Scalability (user load, data volume) + - Usability (accessibility, learnability) +- Assign MoSCoW priority: Must/Should/Could/Won't +- Output structure per requirement: ID, title, description, user_story, acceptance_criteria[], priority, traces + +MODE: analysis +EXPECTED: Structured requirements with: ID, title, description, user story, acceptance criteria, priority, traceability to goals +CONSTRAINTS: Every requirement must be specific enough to estimate and test. No vague requirements. +" --tool gemini --mode analysis`, + run_in_background: true + }) + + // Wait for CLI result + + // === 整合讨论反馈 === + if (discussionFeedback) { + // 从 discuss-002-brief.md 提取需求调整建议 + // 合并新增/修改/删除需求 + } + + // === 生成 requirements/ 目录 === + Bash(`mkdir -p "${sessionFolder}/requirements"`) + + const timestamp = new Date().toISOString() + + // Parse CLI output → funcReqs[], nfReqs[] + const funcReqs = parseFunctionalRequirements(cliOutput) + const nfReqs = parseNonFunctionalRequirements(cliOutput) + + // 写入独立 REQ-*.md 文件(每个功能需求一个文件) + funcReqs.forEach(req => { + const reqFrontmatter = `--- +id: REQ-${req.id} +title: "${req.title}" +priority: ${req.priority} +status: draft +traces: + - product-brief.md +---` + const reqContent = `${reqFrontmatter} + +# REQ-${req.id}: ${req.title} + +## Description +${req.description} + +## User Story +${req.user_story} + +## Acceptance Criteria +${req.acceptance_criteria.map((ac, i) => `${i+1}. ${ac}`).join('\n')} +` + Write(`${sessionFolder}/requirements/REQ-${req.id}-${req.slug}.md`, reqContent) + }) + + // 写入独立 NFR-*.md 文件 + nfReqs.forEach(nfr => { + const nfrFrontmatter = `--- +id: NFR-${nfr.type}-${nfr.id} +type: ${nfr.type} +title: "${nfr.title}" +status: draft +traces: + - product-brief.md +---` + const nfrContent = `${nfrFrontmatter} + +# NFR-${nfr.type}-${nfr.id}: ${nfr.title} + +## Requirement +${nfr.requirement} + +## Metric & Target +${nfr.metric} — Target: ${nfr.target} +` + Write(`${sessionFolder}/requirements/NFR-${nfr.type}-${nfr.id}-${nfr.slug}.md`, nfrContent) + }) + + // 写入 _index.md(汇总 + 链接) + const indexFrontmatter = `--- +session_id: ${specConfig?.session_id || 'unknown'} +phase: 3 +document_type: requirements-index +status: draft +generated_at: ${timestamp} +version: 1 +dependencies: + - product-brief.md +---` + const indexContent = `${indexFrontmatter} + +# Requirements (PRD) + +## Summary +Total: ${funcReqs.length} functional + ${nfReqs.length} non-functional requirements + +## Functional Requirements +| ID | Title | Priority | Status | +|----|-------|----------|--------| +${funcReqs.map(r => `| [REQ-${r.id}](REQ-${r.id}-${r.slug}.md) | ${r.title} | ${r.priority} | draft |`).join('\n')} + +## Non-Functional Requirements +| ID | Type | Title | +|----|------|-------| +${nfReqs.map(n => `| [NFR-${n.type}-${n.id}](NFR-${n.type}-${n.id}-${n.slug}.md) | ${n.type} | ${n.title} |`).join('\n')} + +## MoSCoW Summary +- **Must**: ${funcReqs.filter(r => r.priority === 'Must').length} +- **Should**: ${funcReqs.filter(r => r.priority === 'Should').length} +- **Could**: ${funcReqs.filter(r => r.priority === 'Could').length} +- **Won't**: ${funcReqs.filter(r => r.priority === "Won't").length} +` + Write(`${sessionFolder}/requirements/_index.md`, indexContent) + outputPath = 'requirements/_index.md' +} +``` + +#### DRAFT-003: Architecture + +两阶段 CLI:Gemini 架构设计 + Codex 架构挑战/审查。 + +```javascript +if (docType === 'architecture') { + // === 阶段1: 架构设计 (Gemini) === + Bash({ + command: `ccw cli -p "PURPOSE: Generate technical architecture for the specified requirements. +Success: Complete component architecture, tech stack, and ADRs with justified decisions. + +PRODUCT BRIEF (summary): +${priorDocs.productBrief?.slice(0, 3000) || ''} + +REQUIREMENTS: +${priorDocs.requirementsIndex?.slice(0, 5000) || ''} + +${sharedContext} + +TASK: +- Define system architecture style (monolith, microservices, serverless, etc.) with justification +- Identify core components and their responsibilities +- Create component interaction diagram (Mermaid graph TD format) +- Specify technology stack: languages, frameworks, databases, infrastructure +- Generate 2-4 Architecture Decision Records (ADRs): + - Each ADR: context, decision, 2-3 alternatives with pros/cons, consequences + - Focus on: data storage, API design, authentication, key technical choices +- Define data model: key entities and relationships (Mermaid erDiagram format) +- Identify security architecture: auth, authorization, data protection +- List API endpoints (high-level) + +MODE: analysis +EXPECTED: Complete architecture with: style justification, component diagram, tech stack table, ADRs, data model, security controls, API overview +CONSTRAINTS: Architecture must support all Must-have requirements. Prefer proven technologies. +" --tool gemini --mode analysis`, + run_in_background: true + }) + + // Wait for Gemini result + + // === 阶段2: 架构审查 (Codex) === + Bash({ + command: `ccw cli -p "PURPOSE: Critical review of proposed architecture - identify weaknesses and risks. +Success: Actionable feedback with specific concerns and improvement suggestions. + +PROPOSED ARCHITECTURE: +${geminiArchitectureOutput.slice(0, 5000)} + +REQUIREMENTS CONTEXT: +${priorDocs.requirementsIndex?.slice(0, 2000) || ''} + +TASK: +- Challenge each ADR: are the alternatives truly the best options? +- Identify scalability bottlenecks in the component design +- Assess security gaps: authentication, authorization, data protection +- Evaluate technology choices: maturity, community support, fit +- Check for over-engineering or under-engineering +- Verify architecture covers all Must-have requirements +- Rate overall architecture quality: 1-5 with justification + +MODE: analysis +EXPECTED: Architecture review with: per-ADR feedback, scalability concerns, security gaps, technology risks, quality rating +CONSTRAINTS: Be genuinely critical, not just validating. Focus on actionable improvements. +" --tool codex --mode analysis`, + run_in_background: true + }) + + // Wait for Codex result + + // === 整合讨论反馈 === + if (discussionFeedback) { + // 从 discuss-003-requirements.md 提取架构相关反馈 + // 合并到架构设计中 + } + + // === 代码库集成映射(条件性) === + let integrationMapping = null + if (priorDocs.discoveryContext) { + const dc = JSON.parse(priorDocs.discoveryContext) + if (dc.relevant_files) { + integrationMapping = dc.relevant_files.map(f => ({ + new_component: '...', + existing_module: f.path, + integration_type: 'Extend|Replace|New', + notes: f.rationale + })) + } + } + + // === 生成 architecture/ 目录 === + Bash(`mkdir -p "${sessionFolder}/architecture"`) + + const timestamp = new Date().toISOString() + const adrs = parseADRs(geminiArchitectureOutput, codexReviewOutput) + + // 写入独立 ADR-*.md 文件 + adrs.forEach(adr => { + const adrFrontmatter = `--- +id: ADR-${adr.id} +title: "${adr.title}" +status: draft +traces: + - ../requirements/_index.md +---` + const adrContent = `${adrFrontmatter} + +# ADR-${adr.id}: ${adr.title} + +## Context +${adr.context} + +## Decision +${adr.decision} + +## Alternatives +${adr.alternatives.map((alt, i) => `### Option ${i+1}: ${alt.name}\n- **Pros**: ${alt.pros.join(', ')}\n- **Cons**: ${alt.cons.join(', ')}`).join('\n\n')} + +## Consequences +${adr.consequences} + +## Review Feedback +${adr.reviewFeedback || 'N/A'} +` + Write(`${sessionFolder}/architecture/ADR-${adr.id}-${adr.slug}.md`, adrContent) + }) + + // 写入 _index.md(含 Mermaid 组件图 + ER图 + 链接) + const archIndexFrontmatter = `--- +session_id: ${specConfig?.session_id || 'unknown'} +phase: 4 +document_type: architecture-index +status: draft +generated_at: ${timestamp} +version: 1 +dependencies: + - ../product-brief.md + - ../requirements/_index.md +---` + // 包含: system overview, component diagram (Mermaid), tech stack table, + // ADR links table, data model (Mermaid erDiagram), API design, security controls + Write(`${sessionFolder}/architecture/_index.md`, archIndexContent) + outputPath = 'architecture/_index.md' +} +``` + +#### DRAFT-004: Epics & Stories + +通过 Gemini CLI 分解为 Epic,生成 EPIC-*.md 文件。 + +```javascript +if (docType === 'epics') { + // === Epic 分解 CLI === + Bash({ + command: `ccw cli -p "PURPOSE: Decompose requirements into executable Epics and Stories for implementation planning. +Success: 3-7 Epics with prioritized Stories, dependency map, and MVP subset clearly defined. + +PRODUCT BRIEF (summary): +${priorDocs.productBrief?.slice(0, 2000) || ''} + +REQUIREMENTS: +${priorDocs.requirementsIndex?.slice(0, 5000) || ''} + +ARCHITECTURE (summary): +${priorDocs.architectureIndex?.slice(0, 3000) || ''} + +TASK: +- Group requirements into 3-7 logical Epics: + - Each Epic: EPIC-NNN ID, title, description, priority (Must/Should/Could) + - Group by functional domain or user journey stage + - Tag MVP Epics (minimum set for initial release) +- For each Epic, generate 2-5 Stories: + - Each Story: STORY-{EPIC}-NNN ID, title + - User story format: As a [persona], I want [action] so that [benefit] + - 2-4 acceptance criteria per story (testable) + - Relative size estimate: S/M/L/XL + - Trace to source requirement(s): REQ-NNN +- Create dependency map: + - Cross-Epic dependencies (which Epics block others) + - Mermaid graph LR format + - Recommended execution order with rationale +- Define MVP: + - Which Epics are in MVP + - MVP definition of done (3-5 criteria) + - What is explicitly deferred post-MVP + +MODE: analysis +EXPECTED: Structured output with: Epic list (ID, title, priority, MVP flag), Stories per Epic (ID, user story, AC, size, trace), dependency Mermaid diagram, execution order, MVP definition +CONSTRAINTS: Every Must-have requirement must appear in at least one Story. Stories must be small enough to implement independently. Dependencies should be minimized across Epics. +" --tool gemini --mode analysis`, + run_in_background: true + }) + + // Wait for CLI result + + // === 整合讨论反馈 === + if (discussionFeedback) { + // 从 discuss-004-architecture.md 提取执行相关反馈 + // 调整 Epic 粒度、MVP 范围 + } + + // === 生成 epics/ 目录 === + Bash(`mkdir -p "${sessionFolder}/epics"`) + + const timestamp = new Date().toISOString() + const epicsList = parseEpics(cliOutput) + + // 写入独立 EPIC-*.md 文件(含 stories) + epicsList.forEach(epic => { + const epicFrontmatter = `--- +id: EPIC-${epic.id} +title: "${epic.title}" +priority: ${epic.priority} +mvp: ${epic.mvp} +size: ${epic.size} +requirements: +${epic.reqs.map(r => ` - ${r}`).join('\n')} +architecture: +${epic.adrs.map(a => ` - ${a}`).join('\n')} +dependencies: +${epic.deps.map(d => ` - ${d}`).join('\n')} +status: draft +---` + const storiesContent = epic.stories.map(s => `### ${s.id}: ${s.title} + +**User Story**: ${s.user_story} +**Size**: ${s.size} +**Traces**: ${s.traces.join(', ')} + +**Acceptance Criteria**: +${s.acceptance_criteria.map((ac, i) => `${i+1}. ${ac}`).join('\n')} +`).join('\n') + + const epicContent = `${epicFrontmatter} + +# EPIC-${epic.id}: ${epic.title} + +## Description +${epic.description} + +## Stories +${storiesContent} + +## Requirements +${epic.reqs.map(r => `- [${r}](../requirements/${r}.md)`).join('\n')} + +## Architecture +${epic.adrs.map(a => `- [${a}](../architecture/${a}.md)`).join('\n')} +` + Write(`${sessionFolder}/epics/EPIC-${epic.id}-${epic.slug}.md`, epicContent) + }) + + // 写入 _index.md(含 Mermaid 依赖图 + MVP + 链接) + const epicsIndexFrontmatter = `--- +session_id: ${specConfig?.session_id || 'unknown'} +phase: 5 +document_type: epics-index +status: draft +generated_at: ${timestamp} +version: 1 +dependencies: + - ../requirements/_index.md + - ../architecture/_index.md +---` + // 包含: Epic overview table (with links), dependency Mermaid diagram, + // execution order, MVP scope, traceability matrix + Write(`${sessionFolder}/epics/_index.md`, epicsIndexContent) + outputPath = 'epics/_index.md' +} +``` ### Phase 4: Self-Validation diff --git a/.claude/skills/team-lifecycle/specs/document-standards.md b/.claude/skills/team-lifecycle/specs/document-standards.md new file mode 100644 index 00000000..2820cd98 --- /dev/null +++ b/.claude/skills/team-lifecycle/specs/document-standards.md @@ -0,0 +1,192 @@ +# Document Standards + +Defines format conventions, YAML frontmatter schema, naming rules, and content structure for all spec-generator outputs. + +## When to Use + +| Phase | Usage | Section | +|-------|-------|---------| +| All Phases | Frontmatter format | YAML Frontmatter Schema | +| All Phases | File naming | Naming Conventions | +| Phase 2-5 | Document structure | Content Structure | +| Phase 6 | Validation reference | All sections | + +--- + +## YAML Frontmatter Schema + +Every generated document MUST begin with YAML frontmatter: + +```yaml +--- +session_id: SPEC-{slug}-{YYYY-MM-DD} +phase: {1-6} +document_type: {product-brief|requirements|architecture|epics|readiness-report|spec-summary} +status: draft|review|complete +generated_at: {ISO8601 timestamp} +stepsCompleted: [] +version: 1 +dependencies: + - {list of input documents used} +--- +``` + +### Field Definitions + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `session_id` | string | Yes | Session identifier matching spec-config.json | +| `phase` | number | Yes | Phase number that generated this document (1-6) | +| `document_type` | string | Yes | One of: product-brief, requirements, architecture, epics, readiness-report, spec-summary | +| `status` | enum | Yes | draft (initial), review (user reviewed), complete (finalized) | +| `generated_at` | string | Yes | ISO8601 timestamp of generation | +| `stepsCompleted` | array | Yes | List of step IDs completed during generation | +| `version` | number | Yes | Document version, incremented on re-generation | +| `dependencies` | array | No | List of input files this document depends on | + +### Status Transitions + +``` +draft -> review -> complete + | ^ + +-------------------+ (direct promotion in auto mode) +``` + +- **draft**: Initial generation, not yet user-reviewed +- **review**: User has reviewed and provided feedback +- **complete**: Finalized, ready for downstream consumption + +In auto mode (`-y`), documents are promoted directly from `draft` to `complete`. + +--- + +## Naming Conventions + +### Session ID Format + +``` +SPEC-{slug}-{YYYY-MM-DD} +``` + +- **slug**: Lowercase, alphanumeric + Chinese characters, hyphens as separators, max 40 chars +- **date**: UTC+8 date in YYYY-MM-DD format + +Examples: +- `SPEC-task-management-system-2026-02-11` +- `SPEC-user-auth-oauth-2026-02-11` + +### Output Files + +| File | Phase | Description | +|------|-------|-------------| +| `spec-config.json` | 1 | Session configuration and state | +| `discovery-context.json` | 1 | Codebase exploration results (optional) | +| `product-brief.md` | 2 | Product brief document | +| `requirements.md` | 3 | PRD document | +| `architecture.md` | 4 | Architecture decisions document | +| `epics.md` | 5 | Epic/Story breakdown document | +| `readiness-report.md` | 6 | Quality validation report | +| `spec-summary.md` | 6 | One-page executive summary | + +### Output Directory + +``` +.workflow/.spec/{session-id}/ +``` + +--- + +## Content Structure + +### Heading Hierarchy + +- `#` (H1): Document title only (one per document) +- `##` (H2): Major sections +- `###` (H3): Subsections +- `####` (H4): Detail items (use sparingly) + +Maximum depth: 4 levels. Prefer flat structures. + +### Section Ordering + +Every document follows this general pattern: + +1. **YAML Frontmatter** (mandatory) +2. **Title** (H1) +3. **Executive Summary** (2-3 sentences) +4. **Core Content Sections** (H2, document-specific) +5. **Open Questions / Risks** (if applicable) +6. **References / Traceability** (links to upstream/downstream docs) + +### Formatting Rules + +| Element | Format | Example | +|---------|--------|---------| +| Requirements | `REQ-{NNN}` prefix | REQ-001: User login | +| Acceptance criteria | Checkbox list | `- [ ] User can log in with email` | +| Architecture decisions | `ADR-{NNN}` prefix | ADR-001: Use PostgreSQL | +| Epics | `EPIC-{NNN}` prefix | EPIC-001: Authentication | +| Stories | `STORY-{EPIC}-{NNN}` prefix | STORY-001-001: Login form | +| Priority tags | MoSCoW labels | `[Must]`, `[Should]`, `[Could]`, `[Won't]` | +| Mermaid diagrams | Fenced code blocks | ````mermaid ... ``` `` | +| Code examples | Language-tagged blocks | ````typescript ... ``` `` | + +### Cross-Reference Format + +Use relative references between documents: + +```markdown +See [Product Brief](product-brief.md#section-name) for details. +Derived from [REQ-001](requirements.md#req-001). +``` + +### Language + +- Document body: Follow user's input language (Chinese or English) +- Technical identifiers: Always English (REQ-001, ADR-001, EPIC-001) +- YAML frontmatter keys: Always English + +--- + +## spec-config.json Schema + +```json +{ + "session_id": "string (required)", + "seed_input": "string (required) - original user input", + "input_type": "text|file (required)", + "timestamp": "ISO8601 (required)", + "mode": "interactive|auto (required)", + "complexity": "simple|moderate|complex (required)", + "depth": "light|standard|comprehensive (required)", + "focus_areas": ["string array"], + "seed_analysis": { + "problem_statement": "string", + "target_users": ["string array"], + "domain": "string", + "constraints": ["string array"], + "dimensions": ["string array - 3-5 exploration dimensions"] + }, + "has_codebase": "boolean", + "phasesCompleted": [ + { + "phase": "number (1-6)", + "name": "string (phase name)", + "output_file": "string (primary output file)", + "completed_at": "ISO8601" + } + ] +} +``` + +--- + +## Validation Checklist + +- [ ] Every document starts with valid YAML frontmatter +- [ ] `session_id` matches across all documents in a session +- [ ] `status` field reflects current document state +- [ ] All cross-references resolve to valid targets +- [ ] Heading hierarchy is correct (no skipped levels) +- [ ] Technical identifiers use correct prefixes +- [ ] Output files are in the correct directory diff --git a/.claude/skills/team-lifecycle/specs/quality-gates.md b/.claude/skills/team-lifecycle/specs/quality-gates.md new file mode 100644 index 00000000..ae968436 --- /dev/null +++ b/.claude/skills/team-lifecycle/specs/quality-gates.md @@ -0,0 +1,207 @@ +# Quality Gates + +Per-phase quality gate criteria and scoring dimensions for spec-generator outputs. + +## When to Use + +| Phase | Usage | Section | +|-------|-------|---------| +| Phase 2-5 | Post-generation self-check | Per-Phase Gates | +| Phase 6 | Cross-document validation | Cross-Document Validation | +| Phase 6 | Final scoring | Scoring Dimensions | + +--- + +## Quality Thresholds + +| Gate | Score | Action | +|------|-------|--------| +| **Pass** | >= 80% | Continue to next phase | +| **Review** | 60-79% | Log warnings, continue with caveats | +| **Fail** | < 60% | Must address issues before continuing | + +In auto mode (`-y`), Review-level issues are logged but do not block progress. + +--- + +## Scoring Dimensions + +### 1. Completeness (25%) + +All required sections present with substantive content. + +| Score | Criteria | +|-------|----------| +| 100% | All template sections filled with detailed content | +| 75% | All sections present, some lack detail | +| 50% | Major sections present but minor sections missing | +| 25% | Multiple major sections missing or empty | +| 0% | Document is a skeleton only | + +### 2. Consistency (25%) + +Terminology, formatting, and references are uniform across documents. + +| Score | Criteria | +|-------|----------| +| 100% | All terms consistent, all references valid, formatting uniform | +| 75% | Minor terminology variations, all references valid | +| 50% | Some inconsistent terms, 1-2 broken references | +| 25% | Frequent inconsistencies, multiple broken references | +| 0% | Documents contradict each other | + +### 3. Traceability (25%) + +Requirements, architecture decisions, and stories trace back to goals. + +| Score | Criteria | +|-------|----------| +| 100% | Every story traces to a requirement, every requirement traces to a goal | +| 75% | Most items traceable, few orphans | +| 50% | Partial traceability, some disconnected items | +| 25% | Weak traceability, many orphan items | +| 0% | No traceability between documents | + +### 4. Depth (25%) + +Content provides sufficient detail for execution teams. + +| Score | Criteria | +|-------|----------| +| 100% | Acceptance criteria specific and testable, architecture decisions justified, stories estimable | +| 75% | Most items detailed enough, few vague areas | +| 50% | Mix of detailed and vague content | +| 25% | Mostly high-level, lacking actionable detail | +| 0% | Too abstract for execution | + +--- + +## Per-Phase Quality Gates + +### Phase 1: Discovery + +| Check | Criteria | Severity | +|-------|----------|----------| +| Session ID valid | Matches `SPEC-{slug}-{date}` format | Error | +| Problem statement exists | Non-empty, >= 20 characters | Error | +| Target users identified | >= 1 user group | Error | +| Dimensions generated | 3-5 exploration dimensions | Warning | +| Constraints listed | >= 0 (can be empty with justification) | Info | + +### Phase 2: Product Brief + +| Check | Criteria | Severity | +|-------|----------|----------| +| Vision statement | Clear, 1-3 sentences | Error | +| Problem statement | Specific and measurable | Error | +| Target users | >= 1 persona with needs described | Error | +| Goals defined | >= 2 measurable goals | Error | +| Success metrics | >= 2 quantifiable metrics | Warning | +| Scope boundaries | In-scope and out-of-scope listed | Warning | +| Multi-perspective | >= 2 CLI perspectives synthesized | Info | + +### Phase 3: Requirements (PRD) + +| Check | Criteria | Severity | +|-------|----------|----------| +| Functional requirements | >= 3 with REQ-NNN IDs | Error | +| Acceptance criteria | Every requirement has >= 1 criterion | Error | +| MoSCoW priority | Every requirement tagged | Error | +| Non-functional requirements | >= 1 (performance, security, etc.) | Warning | +| User stories | >= 1 per Must-have requirement | Warning | +| Traceability | Requirements trace to product brief goals | Warning | + +### Phase 4: Architecture + +| Check | Criteria | Severity | +|-------|----------|----------| +| Component diagram | Present (Mermaid or ASCII) | Error | +| Tech stack specified | Languages, frameworks, key libraries | Error | +| ADR present | >= 1 Architecture Decision Record | Error | +| ADR has alternatives | Each ADR lists >= 2 options considered | Warning | +| Integration points | External systems/APIs identified | Warning | +| Data model | Key entities and relationships described | Warning | +| Codebase mapping | Mapped to existing code (if has_codebase) | Info | + +### Phase 5: Epics & Stories + +| Check | Criteria | Severity | +|-------|----------|----------| +| Epics defined | 3-7 epics with EPIC-NNN IDs | Error | +| MVP subset | >= 1 epic tagged as MVP | Error | +| Stories per epic | 2-5 stories per epic | Error | +| Story format | "As a...I want...So that..." pattern | Warning | +| Dependency map | Cross-epic dependencies documented | Warning | +| Estimation hints | Relative sizing (S/M/L/XL) per story | Info | +| Traceability | Stories trace to requirements | Warning | + +### Phase 6: Readiness Check + +| Check | Criteria | Severity | +|-------|----------|----------| +| All documents exist | product-brief, requirements, architecture, epics | Error | +| Frontmatter valid | All YAML frontmatter parseable and correct | Error | +| Cross-references valid | All document links resolve | Error | +| Overall score >= 60% | Weighted average across 4 dimensions | Error | +| No unresolved Errors | All Error-severity issues addressed | Error | +| Summary generated | spec-summary.md created | Warning | + +--- + +## Cross-Document Validation + +Checks performed during Phase 6 across all documents: + +### Completeness Matrix + +``` +Product Brief goals -> Requirements (each goal has >= 1 requirement) +Requirements -> Architecture (each Must requirement has design coverage) +Requirements -> Epics (each Must requirement appears in >= 1 story) +Architecture ADRs -> Epics (tech choices reflected in implementation stories) +``` + +### Consistency Checks + +| Check | Documents | Rule | +|-------|-----------|------| +| Terminology | All | Same term used consistently (no synonyms for same concept) | +| User personas | Brief + PRD + Epics | Same user names/roles throughout | +| Scope | Brief + PRD | PRD scope does not exceed brief scope | +| Tech stack | Architecture + Epics | Stories reference correct technologies | + +### Traceability Matrix Format + +```markdown +| Goal | Requirements | Architecture | Epics | +|------|-------------|--------------|-------| +| G-001: ... | REQ-001, REQ-002 | ADR-001 | EPIC-001 | +| G-002: ... | REQ-003 | ADR-002 | EPIC-002, EPIC-003 | +``` + +--- + +## Issue Classification + +### Error (Must Fix) + +- Missing required document or section +- Broken cross-references +- Contradictory information between documents +- Empty acceptance criteria on Must-have requirements +- No MVP subset defined in epics + +### Warning (Should Fix) + +- Vague acceptance criteria +- Missing non-functional requirements +- No success metrics defined +- Incomplete traceability +- Missing architecture review notes + +### Info (Nice to Have) + +- Could add more detailed personas +- Consider additional ADR alternatives +- Story estimation hints missing +- Mermaid diagrams could be more detailed diff --git a/.claude/skills/team-lifecycle/templates/architecture-doc.md b/.claude/skills/team-lifecycle/templates/architecture-doc.md new file mode 100644 index 00000000..5106de03 --- /dev/null +++ b/.claude/skills/team-lifecycle/templates/architecture-doc.md @@ -0,0 +1,254 @@ +# Architecture Document Template (Directory Structure) + +Template for generating architecture decision documents as a directory of individual ADR files in Phase 4. + +## Usage Context + +| Phase | Usage | +|-------|-------| +| Phase 4 (Architecture) | Generate `architecture/` directory from requirements analysis | +| Output Location | `{workDir}/architecture/` | + +## Output Structure + +``` +{workDir}/architecture/ +├── _index.md # Overview, components, tech stack, data model, security +├── ADR-001-{slug}.md # Individual Architecture Decision Record +├── ADR-002-{slug}.md +└── ... +``` + +--- + +## Template: _index.md + +```markdown +--- +session_id: {session_id} +phase: 4 +document_type: architecture-index +status: draft +generated_at: {timestamp} +version: 1 +dependencies: + - ../spec-config.json + - ../product-brief.md + - ../requirements/_index.md +--- + +# Architecture: {product_name} + +{executive_summary - high-level architecture approach and key decisions} + +## System Overview + +### Architecture Style +{description of chosen architecture style: microservices, monolith, serverless, etc.} + +### System Context Diagram + +```mermaid +C4Context + title System Context Diagram + Person(user, "User", "Primary user") + System(system, "{product_name}", "Core system") + System_Ext(ext1, "{external_system}", "{description}") + Rel(user, system, "Uses") + Rel(system, ext1, "Integrates with") +``` + +## Component Architecture + +### Component Diagram + +```mermaid +graph TD + subgraph "{product_name}" + A[Component A] --> B[Component B] + B --> C[Component C] + A --> D[Component D] + end + B --> E[External Service] +``` + +### Component Descriptions + +| Component | Responsibility | Technology | Dependencies | +|-----------|---------------|------------|--------------| +| {component_name} | {what it does} | {tech stack} | {depends on} | + +## Technology Stack + +### Core Technologies + +| Layer | Technology | Version | Rationale | +|-------|-----------|---------|-----------| +| Frontend | {technology} | {version} | {why chosen} | +| Backend | {technology} | {version} | {why chosen} | +| Database | {technology} | {version} | {why chosen} | +| Infrastructure | {technology} | {version} | {why chosen} | + +### Key Libraries & Frameworks + +| Library | Purpose | License | +|---------|---------|---------| +| {library_name} | {purpose} | {license} | + +## Architecture Decision Records + +| ADR | Title | Status | Key Choice | +|-----|-------|--------|------------| +| [ADR-001](ADR-001-{slug}.md) | {title} | Accepted | {one-line summary} | +| [ADR-002](ADR-002-{slug}.md) | {title} | Accepted | {one-line summary} | +| [ADR-003](ADR-003-{slug}.md) | {title} | Proposed | {one-line summary} | + +## Data Architecture + +### Data Model + +```mermaid +erDiagram + ENTITY_A ||--o{ ENTITY_B : "has many" + ENTITY_A { + string id PK + string name + datetime created_at + } + ENTITY_B { + string id PK + string entity_a_id FK + string value + } +``` + +### Data Storage Strategy + +| Data Type | Storage | Retention | Backup | +|-----------|---------|-----------|--------| +| {type} | {storage solution} | {retention policy} | {backup strategy} | + +## API Design + +### API Overview + +| Endpoint | Method | Purpose | Auth | +|----------|--------|---------|------| +| {/api/resource} | {GET/POST/etc} | {purpose} | {auth type} | + +## Security Architecture + +### Security Controls + +| Control | Implementation | Requirement | +|---------|---------------|-------------| +| Authentication | {approach} | [NFR-S-{NNN}](../requirements/NFR-S-{NNN}-{slug}.md) | +| Authorization | {approach} | [NFR-S-{NNN}](../requirements/NFR-S-{NNN}-{slug}.md) | +| Data Protection | {approach} | [NFR-S-{NNN}](../requirements/NFR-S-{NNN}-{slug}.md) | + +## Infrastructure & Deployment + +### Deployment Architecture + +{description of deployment model: containers, serverless, VMs, etc.} + +### Environment Strategy + +| Environment | Purpose | Configuration | +|-------------|---------|---------------| +| Development | Local development | {config} | +| Staging | Pre-production testing | {config} | +| Production | Live system | {config} | + +## Codebase Integration + +{if has_codebase is true:} + +### Existing Code Mapping + +| New Component | Existing Module | Integration Type | Notes | +|--------------|----------------|------------------|-------| +| {component} | {existing module path} | Extend/Replace/New | {notes} | + +### Migration Notes +{any migration considerations for existing code} + +## Quality Attributes + +| Attribute | Target | Measurement | ADR Reference | +|-----------|--------|-------------|---------------| +| Performance | {target} | {how measured} | [ADR-{NNN}](ADR-{NNN}-{slug}.md) | +| Scalability | {target} | {how measured} | [ADR-{NNN}](ADR-{NNN}-{slug}.md) | +| Reliability | {target} | {how measured} | [ADR-{NNN}](ADR-{NNN}-{slug}.md) | + +## Risks & Mitigations + +| Risk | Impact | Probability | Mitigation | +|------|--------|-------------|------------| +| {risk} | High/Medium/Low | High/Medium/Low | {mitigation approach} | + +## Open Questions + +- [ ] {architectural question 1} +- [ ] {architectural question 2} + +## References + +- Derived from: [Requirements](../requirements/_index.md), [Product Brief](../product-brief.md) +- Next: [Epics & Stories](../epics/_index.md) +``` + +--- + +## Template: ADR-NNN-{slug}.md (Individual Architecture Decision Record) + +```markdown +--- +id: ADR-{NNN} +status: Accepted +traces_to: [{REQ-NNN}, {NFR-X-NNN}] +date: {timestamp} +--- + +# ADR-{NNN}: {decision_title} + +## Context + +{what is the situation that motivates this decision} + +## Decision + +{what is the chosen approach} + +## Alternatives Considered + +| Option | Pros | Cons | +|--------|------|------| +| {option_1 - chosen} | {pros} | {cons} | +| {option_2} | {pros} | {cons} | +| {option_3} | {pros} | {cons} | + +## Consequences + +- **Positive**: {positive outcomes} +- **Negative**: {tradeoffs accepted} +- **Risks**: {risks to monitor} + +## Traces + +- **Requirements**: [REQ-{NNN}](../requirements/REQ-{NNN}-{slug}.md), [NFR-X-{NNN}](../requirements/NFR-X-{NNN}-{slug}.md) +- **Implemented by**: [EPIC-{NNN}](../epics/EPIC-{NNN}-{slug}.md) (added in Phase 5) +``` + +--- + +## Variable Descriptions + +| Variable | Source | Description | +|----------|--------|-------------| +| `{session_id}` | spec-config.json | Session identifier | +| `{timestamp}` | Runtime | ISO8601 generation timestamp | +| `{product_name}` | product-brief.md | Product/feature name | +| `{NNN}` | Auto-increment | ADR/requirement number | +| `{slug}` | Auto-generated | Kebab-case from decision title | +| `{has_codebase}` | spec-config.json | Whether existing codebase exists | diff --git a/.claude/skills/team-lifecycle/templates/epics-template.md b/.claude/skills/team-lifecycle/templates/epics-template.md new file mode 100644 index 00000000..939d933c --- /dev/null +++ b/.claude/skills/team-lifecycle/templates/epics-template.md @@ -0,0 +1,196 @@ +# Epics & Stories Template (Directory Structure) + +Template for generating epic/story breakdown as a directory of individual Epic files in Phase 5. + +## Usage Context + +| Phase | Usage | +|-------|-------| +| Phase 5 (Epics & Stories) | Generate `epics/` directory from requirements decomposition | +| Output Location | `{workDir}/epics/` | + +## Output Structure + +``` +{workDir}/epics/ +├── _index.md # Overview table + dependency map + MVP scope + execution order +├── EPIC-001-{slug}.md # Individual Epic with its Stories +├── EPIC-002-{slug}.md +└── ... +``` + +--- + +## Template: _index.md + +```markdown +--- +session_id: {session_id} +phase: 5 +document_type: epics-index +status: draft +generated_at: {timestamp} +version: 1 +dependencies: + - ../spec-config.json + - ../product-brief.md + - ../requirements/_index.md + - ../architecture/_index.md +--- + +# Epics & Stories: {product_name} + +{executive_summary - overview of epic structure and MVP scope} + +## Epic Overview + +| Epic ID | Title | Priority | MVP | Stories | Est. Size | +|---------|-------|----------|-----|---------|-----------| +| [EPIC-001](EPIC-001-{slug}.md) | {title} | Must | Yes | {n} | {S/M/L/XL} | +| [EPIC-002](EPIC-002-{slug}.md) | {title} | Must | Yes | {n} | {S/M/L/XL} | +| [EPIC-003](EPIC-003-{slug}.md) | {title} | Should | No | {n} | {S/M/L/XL} | + +## Dependency Map + +```mermaid +graph LR + EPIC-001 --> EPIC-002 + EPIC-001 --> EPIC-003 + EPIC-002 --> EPIC-004 + EPIC-003 --> EPIC-005 +``` + +### Dependency Notes +{explanation of why these dependencies exist and suggested execution order} + +### Recommended Execution Order +1. [EPIC-{NNN}](EPIC-{NNN}-{slug}.md): {reason - foundational} +2. [EPIC-{NNN}](EPIC-{NNN}-{slug}.md): {reason - depends on #1} +3. ... + +## MVP Scope + +### MVP Epics +{list of epics included in MVP with justification, linking to each} + +### MVP Definition of Done +- [ ] {MVP completion criterion 1} +- [ ] {MVP completion criterion 2} +- [ ] {MVP completion criterion 3} + +## Traceability Matrix + +| Requirement | Epic | Stories | Architecture | +|-------------|------|---------|--------------| +| [REQ-001](../requirements/REQ-001-{slug}.md) | [EPIC-001](EPIC-001-{slug}.md) | STORY-001-001, STORY-001-002 | [ADR-001](../architecture/ADR-001-{slug}.md) | +| [REQ-002](../requirements/REQ-002-{slug}.md) | [EPIC-001](EPIC-001-{slug}.md) | STORY-001-003 | Component B | +| [REQ-003](../requirements/REQ-003-{slug}.md) | [EPIC-002](EPIC-002-{slug}.md) | STORY-002-001 | [ADR-002](../architecture/ADR-002-{slug}.md) | + +## Estimation Summary + +| Size | Meaning | Count | +|------|---------|-------| +| S | Small - well-understood, minimal risk | {n} | +| M | Medium - some complexity, moderate risk | {n} | +| L | Large - significant complexity, should consider splitting | {n} | +| XL | Extra Large - high complexity, must split before implementation | {n} | + +## Risks & Considerations + +| Risk | Affected Epics | Mitigation | +|------|---------------|------------| +| {risk description} | [EPIC-{NNN}](EPIC-{NNN}-{slug}.md) | {mitigation} | + +## Open Questions + +- [ ] {question about scope or implementation 1} +- [ ] {question about scope or implementation 2} + +## References + +- Derived from: [Requirements](../requirements/_index.md), [Architecture](../architecture/_index.md) +- Handoff to: execution workflows (lite-plan, plan, req-plan) +``` + +--- + +## Template: EPIC-NNN-{slug}.md (Individual Epic) + +```markdown +--- +id: EPIC-{NNN} +priority: {Must|Should|Could} +mvp: {true|false} +size: {S|M|L|XL} +requirements: [REQ-{NNN}] +architecture: [ADR-{NNN}] +dependencies: [EPIC-{NNN}] +status: draft +--- + +# EPIC-{NNN}: {epic_title} + +**Priority**: {Must|Should|Could} +**MVP**: {Yes|No} +**Estimated Size**: {S|M|L|XL} + +## Description + +{detailed epic description} + +## Requirements + +- [REQ-{NNN}](../requirements/REQ-{NNN}-{slug}.md): {title} +- [REQ-{NNN}](../requirements/REQ-{NNN}-{slug}.md): {title} + +## Architecture + +- [ADR-{NNN}](../architecture/ADR-{NNN}-{slug}.md): {title} +- Component: {component_name} + +## Dependencies + +- [EPIC-{NNN}](EPIC-{NNN}-{slug}.md) (blocking): {reason} +- [EPIC-{NNN}](EPIC-{NNN}-{slug}.md) (soft): {reason} + +## Stories + +### STORY-{EPIC}-001: {story_title} + +**User Story**: As a {persona}, I want to {action} so that {benefit}. + +**Acceptance Criteria**: +- [ ] {criterion 1} +- [ ] {criterion 2} +- [ ] {criterion 3} + +**Size**: {S|M|L|XL} +**Traces to**: [REQ-{NNN}](../requirements/REQ-{NNN}-{slug}.md) + +--- + +### STORY-{EPIC}-002: {story_title} + +**User Story**: As a {persona}, I want to {action} so that {benefit}. + +**Acceptance Criteria**: +- [ ] {criterion 1} +- [ ] {criterion 2} + +**Size**: {S|M|L|XL} +**Traces to**: [REQ-{NNN}](../requirements/REQ-{NNN}-{slug}.md) +``` + +--- + +## Variable Descriptions + +| Variable | Source | Description | +|----------|--------|-------------| +| `{session_id}` | spec-config.json | Session identifier | +| `{timestamp}` | Runtime | ISO8601 generation timestamp | +| `{product_name}` | product-brief.md | Product/feature name | +| `{EPIC}` | Auto-increment | Epic number (3 digits) | +| `{NNN}` | Auto-increment | Story/requirement number | +| `{slug}` | Auto-generated | Kebab-case from epic/story title | +| `{S\|M\|L\|XL}` | CLI analysis | Relative size estimate | diff --git a/.claude/skills/team-lifecycle/templates/product-brief.md b/.claude/skills/team-lifecycle/templates/product-brief.md new file mode 100644 index 00000000..ffbdf437 --- /dev/null +++ b/.claude/skills/team-lifecycle/templates/product-brief.md @@ -0,0 +1,133 @@ +# Product Brief Template + +Template for generating product brief documents in Phase 2. + +## Usage Context + +| Phase | Usage | +|-------|-------| +| Phase 2 (Product Brief) | Generate product-brief.md from multi-CLI analysis | +| Output Location | `{workDir}/product-brief.md` | + +--- + +## Template + +```markdown +--- +session_id: {session_id} +phase: 2 +document_type: product-brief +status: draft +generated_at: {timestamp} +stepsCompleted: [] +version: 1 +dependencies: + - spec-config.json +--- + +# Product Brief: {product_name} + +{executive_summary - 2-3 sentences capturing the essence of the product/feature} + +## Vision + +{vision_statement - clear, aspirational 1-3 sentence statement of what success looks like} + +## Problem Statement + +### Current Situation +{description of the current state and pain points} + +### Impact +{quantified impact of the problem - who is affected, how much, how often} + +## Target Users + +{for each user persona:} + +### {Persona Name} +- **Role**: {user's role/context} +- **Needs**: {primary needs related to this product} +- **Pain Points**: {current frustrations} +- **Success Criteria**: {what success looks like for this user} + +## Goals & Success Metrics + +| Goal ID | Goal | Success Metric | Target | +|---------|------|----------------|--------| +| G-001 | {goal description} | {measurable metric} | {specific target} | +| G-002 | {goal description} | {measurable metric} | {specific target} | + +## Scope + +### In Scope +- {feature/capability 1} +- {feature/capability 2} +- {feature/capability 3} + +### Out of Scope +- {explicitly excluded item 1} +- {explicitly excluded item 2} + +### Assumptions +- {key assumption 1} +- {key assumption 2} + +## Competitive Landscape + +| Aspect | Current State | Proposed Solution | Advantage | +|--------|--------------|-------------------|-----------| +| {aspect} | {how it's done now} | {our approach} | {differentiator} | + +## Constraints & Dependencies + +### Technical Constraints +- {constraint 1} +- {constraint 2} + +### Business Constraints +- {constraint 1} + +### Dependencies +- {external dependency 1} +- {external dependency 2} + +## Multi-Perspective Synthesis + +### Product Perspective +{summary of product/market analysis findings} + +### Technical Perspective +{summary of technical feasibility and constraints} + +### User Perspective +{summary of user journey and UX considerations} + +### Convergent Themes +{themes where all perspectives agree} + +### Conflicting Views +{areas where perspectives differ, with notes on resolution approach} + +## Open Questions + +- [ ] {unresolved question 1} +- [ ] {unresolved question 2} + +## References + +- Derived from: [spec-config.json](spec-config.json) +- Next: [Requirements PRD](requirements.md) +``` + +## Variable Descriptions + +| Variable | Source | Description | +|----------|--------|-------------| +| `{session_id}` | spec-config.json | Session identifier | +| `{timestamp}` | Runtime | ISO8601 generation timestamp | +| `{product_name}` | Seed analysis | Product/feature name | +| `{executive_summary}` | CLI synthesis | 2-3 sentence summary | +| `{vision_statement}` | CLI product perspective | Aspirational vision | +| All `{...}` fields | CLI analysis outputs | Filled from multi-perspective analysis | diff --git a/.claude/skills/team-lifecycle/templates/requirements-prd.md b/.claude/skills/team-lifecycle/templates/requirements-prd.md new file mode 100644 index 00000000..0b1dbf28 --- /dev/null +++ b/.claude/skills/team-lifecycle/templates/requirements-prd.md @@ -0,0 +1,224 @@ +# Requirements PRD Template (Directory Structure) + +Template for generating Product Requirements Document as a directory of individual requirement files in Phase 3. + +## Usage Context + +| Phase | Usage | +|-------|-------| +| Phase 3 (Requirements) | Generate `requirements/` directory from product brief expansion | +| Output Location | `{workDir}/requirements/` | + +## Output Structure + +``` +{workDir}/requirements/ +├── _index.md # Summary + MoSCoW table + traceability matrix + links +├── REQ-001-{slug}.md # Individual functional requirement +├── REQ-002-{slug}.md +├── NFR-P-001-{slug}.md # Non-functional: Performance +├── NFR-S-001-{slug}.md # Non-functional: Security +├── NFR-SC-001-{slug}.md # Non-functional: Scalability +├── NFR-U-001-{slug}.md # Non-functional: Usability +└── ... +``` + +--- + +## Template: _index.md + +```markdown +--- +session_id: {session_id} +phase: 3 +document_type: requirements-index +status: draft +generated_at: {timestamp} +version: 1 +dependencies: + - ../spec-config.json + - ../product-brief.md +--- + +# Requirements: {product_name} + +{executive_summary - brief overview of what this PRD covers and key decisions} + +## Requirement Summary + +| Priority | Count | Coverage | +|----------|-------|----------| +| Must Have | {n} | {description of must-have scope} | +| Should Have | {n} | {description of should-have scope} | +| Could Have | {n} | {description of could-have scope} | +| Won't Have | {n} | {description of explicitly excluded} | + +## Functional Requirements + +| ID | Title | Priority | Traces To | +|----|-------|----------|-----------| +| [REQ-001](REQ-001-{slug}.md) | {title} | Must | [G-001](../product-brief.md#goals--success-metrics) | +| [REQ-002](REQ-002-{slug}.md) | {title} | Must | [G-001](../product-brief.md#goals--success-metrics) | +| [REQ-003](REQ-003-{slug}.md) | {title} | Should | [G-002](../product-brief.md#goals--success-metrics) | + +## Non-Functional Requirements + +### Performance + +| ID | Title | Target | +|----|-------|--------| +| [NFR-P-001](NFR-P-001-{slug}.md) | {title} | {target value} | + +### Security + +| ID | Title | Standard | +|----|-------|----------| +| [NFR-S-001](NFR-S-001-{slug}.md) | {title} | {standard/framework} | + +### Scalability + +| ID | Title | Target | +|----|-------|--------| +| [NFR-SC-001](NFR-SC-001-{slug}.md) | {title} | {target value} | + +### Usability + +| ID | Title | Target | +|----|-------|--------| +| [NFR-U-001](NFR-U-001-{slug}.md) | {title} | {target value} | + +## Data Requirements + +### Data Entities + +| Entity | Description | Key Attributes | +|--------|-------------|----------------| +| {entity_name} | {description} | {attr1, attr2, attr3} | + +### Data Flows + +{description of key data flows, optionally with Mermaid diagram} + +## Integration Requirements + +| System | Direction | Protocol | Data Format | Notes | +|--------|-----------|----------|-------------|-------| +| {system_name} | Inbound/Outbound/Both | {REST/gRPC/etc} | {JSON/XML/etc} | {notes} | + +## Constraints & Assumptions + +### Constraints +- {technical or business constraint 1} +- {technical or business constraint 2} + +### Assumptions +- {assumption 1 - must be validated} +- {assumption 2 - must be validated} + +## Priority Rationale + +{explanation of MoSCoW prioritization decisions, especially for Should/Could boundaries} + +## Traceability Matrix + +| Goal | Requirements | +|------|-------------| +| G-001 | [REQ-001](REQ-001-{slug}.md), [REQ-002](REQ-002-{slug}.md), [NFR-P-001](NFR-P-001-{slug}.md) | +| G-002 | [REQ-003](REQ-003-{slug}.md), [NFR-S-001](NFR-S-001-{slug}.md) | + +## Open Questions + +- [ ] {unresolved question 1} +- [ ] {unresolved question 2} + +## References + +- Derived from: [Product Brief](../product-brief.md) +- Next: [Architecture](../architecture/_index.md) +``` + +--- + +## Template: REQ-NNN-{slug}.md (Individual Functional Requirement) + +```markdown +--- +id: REQ-{NNN} +type: functional +priority: {Must|Should|Could|Won't} +traces_to: [G-{NNN}] +status: draft +--- + +# REQ-{NNN}: {requirement_title} + +**Priority**: {Must|Should|Could|Won't} + +## Description + +{detailed requirement description} + +## User Story + +As a {persona}, I want to {action} so that {benefit}. + +## Acceptance Criteria + +- [ ] {specific, testable criterion 1} +- [ ] {specific, testable criterion 2} +- [ ] {specific, testable criterion 3} + +## Traces + +- **Goal**: [G-{NNN}](../product-brief.md#goals--success-metrics) +- **Architecture**: [ADR-{NNN}](../architecture/ADR-{NNN}-{slug}.md) (if applicable) +- **Implemented by**: [EPIC-{NNN}](../epics/EPIC-{NNN}-{slug}.md) (added in Phase 5) +``` + +--- + +## Template: NFR-{type}-NNN-{slug}.md (Individual Non-Functional Requirement) + +```markdown +--- +id: NFR-{type}-{NNN} +type: non-functional +category: {Performance|Security|Scalability|Usability} +priority: {Must|Should|Could} +status: draft +--- + +# NFR-{type}-{NNN}: {requirement_title} + +**Category**: {Performance|Security|Scalability|Usability} +**Priority**: {Must|Should|Could} + +## Requirement + +{detailed requirement description} + +## Metric & Target + +| Metric | Target | Measurement Method | +|--------|--------|--------------------| +| {metric} | {target value} | {how measured} | + +## Traces + +- **Goal**: [G-{NNN}](../product-brief.md#goals--success-metrics) +- **Architecture**: [ADR-{NNN}](../architecture/ADR-{NNN}-{slug}.md) (if applicable) +``` + +--- + +## Variable Descriptions + +| Variable | Source | Description | +|----------|--------|-------------| +| `{session_id}` | spec-config.json | Session identifier | +| `{timestamp}` | Runtime | ISO8601 generation timestamp | +| `{product_name}` | product-brief.md | Product/feature name | +| `{NNN}` | Auto-increment | Requirement number (zero-padded 3 digits) | +| `{slug}` | Auto-generated | Kebab-case from requirement title | +| `{type}` | Category | P (Performance), S (Security), SC (Scalability), U (Usability) | +| `{Must\|Should\|Could\|Won't}` | User input / auto | MoSCoW priority tag | diff --git a/ccw/frontend/src/components/terminal-dashboard/DashboardToolbar.tsx b/ccw/frontend/src/components/terminal-dashboard/DashboardToolbar.tsx index 4fdc013b..7e9a12fb 100644 --- a/ccw/frontend/src/components/terminal-dashboard/DashboardToolbar.tsx +++ b/ccw/frontend/src/components/terminal-dashboard/DashboardToolbar.tsx @@ -2,13 +2,12 @@ // DashboardToolbar Component // ======================================== // Top toolbar for Terminal Dashboard V2. -// Provides toggle buttons for floating panels (Sessions/Issues/Queue/Inspector) -// and layout preset controls. +// Provides toggle buttons for floating panels (Issues/Queue/Inspector) +// and layout preset controls. Sessions sidebar is always visible. import { useCallback, useMemo } from 'react'; import { useIntl } from 'react-intl'; import { - FolderTree, AlertCircle, ListChecks, Info, @@ -19,22 +18,16 @@ import { } from 'lucide-react'; import { cn } from '@/lib/utils'; import { Badge } from '@/components/ui/Badge'; -import { - useSessionManagerStore, - selectGroups, - selectTerminalMetas, -} from '@/stores/sessionManagerStore'; import { useIssueQueueIntegrationStore, selectAssociationChain, } from '@/stores/issueQueueIntegrationStore'; import { useIssues, useIssueQueue } from '@/hooks/useIssues'; import { useTerminalGridStore } from '@/stores/terminalGridStore'; -import type { TerminalStatus } from '@/types/terminal-dashboard'; // ========== Types ========== -export type PanelId = 'sessions' | 'issues' | 'queue' | 'inspector'; +export type PanelId = 'issues' | 'queue' | 'inspector'; interface DashboardToolbarProps { activePanel: PanelId | null; @@ -55,20 +48,6 @@ const LAYOUT_PRESETS = [ export function DashboardToolbar({ activePanel, onTogglePanel }: DashboardToolbarProps) { const { formatMessage } = useIntl(); - // Session count - const groups = useSessionManagerStore(selectGroups); - const terminalMetas = useSessionManagerStore(selectTerminalMetas); - const sessionCount = useMemo(() => { - const allSessionIds = groups.flatMap((g) => g.sessionIds); - let activeCount = 0; - for (const sid of allSessionIds) { - const meta = terminalMetas[sid]; - const status: TerminalStatus = meta?.status ?? 'idle'; - if (status === 'active') activeCount++; - } - return activeCount > 0 ? activeCount : allSessionIds.length; - }, [groups, terminalMetas]); - // Issues count const { openCount } = useIssues(); @@ -100,13 +79,6 @@ export function DashboardToolbar({ activePanel, onTogglePanel }: DashboardToolba return (