From 266f6f11ec6fdd57150522cfd4d01922b45a9c0c Mon Sep 17 00:00:00 2001 From: catlog22 Date: Wed, 14 Jan 2026 21:07:52 +0800 Subject: [PATCH] feat: Enhance documentation diagnosis and category mapping - Introduced action to diagnose documentation structure, identifying redundancies and conflicts. - Added centralized category mappings in JSON format for improved detection and strategy application. - Updated existing functions to utilize new mappings for taxonomy and strategy matching. - Implemented new detection patterns for documentation redundancy and conflict. - Expanded state schema to include documentation diagnosis results. - Enhanced severity criteria and strategy selection guide to accommodate new documentation issues. --- .claude/skills/ccw/phases/orchestrator.md | 1300 ++++++----------- .claude/skills/skill-tuning/SKILL.md | 76 +- .../actions/action-analyze-requirements.md | 108 +- .../phases/actions/action-diagnose-docs.md | 299 ++++ .../skill-tuning/phases/orchestrator.md | 9 +- .../skill-tuning/phases/state-schema.md | 31 +- .../skill-tuning/specs/category-mappings.json | 263 ++++ .../skill-tuning/specs/dimension-mapping.md | 6 + .../skill-tuning/specs/problem-taxonomy.md | 49 + .../skill-tuning/specs/tuning-strategies.md | 145 ++ 10 files changed, 1340 insertions(+), 946 deletions(-) create mode 100644 .claude/skills/skill-tuning/phases/actions/action-diagnose-docs.md create mode 100644 .claude/skills/skill-tuning/specs/category-mappings.json diff --git a/.claude/skills/ccw/phases/orchestrator.md b/.claude/skills/ccw/phases/orchestrator.md index 64c95b32..c886c83e 100644 --- a/.claude/skills/ccw/phases/orchestrator.md +++ b/.claude/skills/ccw/phases/orchestrator.md @@ -5,238 +5,142 @@ ## Architecture ``` -┌──────────────────────────────────────────────────────────────────┐ -│ CCW Orchestrator (CLI-Enhanced + Requirement Analysis) │ -├──────────────────────────────────────────────────────────────────┤ -│ │ -│ Phase 1: Input Analysis (Rule-Based, Fast Path) │ -│ ├─ Parse input (natural language / explicit command) │ -│ ├─ Classify intent (bugfix / feature / issue / ui / docs) │ -│ ├─ Assess complexity (low / medium / high) │ -│ └─ Extract requirement dimensions (WHAT/WHERE/WHY/HOW) │ -│ │ -│ Phase 1.5: CLI-Assisted Classification (Smart Path) │ -│ ├─ Trigger: low match count / high complexity / long input │ -│ ├─ Use Gemini CLI for semantic intent understanding │ -│ ├─ Get confidence score and reasoning │ -│ └─ Fallback to rule-based if CLI fails │ -│ │ -│ Phase 1.75: Requirement Clarification (NEW) │ -│ ├─ Calculate clarity score (0-3) │ -│ ├─ Trigger: clarity_score < 2 OR missing critical dimensions │ -│ ├─ Generate targeted clarification questions │ -│ └─ Refine requirement dimensions with user input │ -│ │ -│ Phase 2: Chain Selection │ -│ ├─ Load index/workflow-chains.json │ -│ ├─ Match intent → chain(s) │ -│ ├─ Filter by complexity │ -│ └─ Select optimal chain │ -│ │ -│ Phase 2.5: CLI-Assisted Action Planning (Optimization) │ -│ ├─ Trigger: high complexity / many steps / long request │ -│ ├─ Use Gemini CLI to optimize execution strategy │ -│ ├─ Suggest step modifications or CLI injections │ -│ └─ Identify risks and provide mitigations │ -│ │ -│ Phase 3: User Confirmation (optional) │ -│ ├─ Display selected chain and steps │ -│ └─ Allow modification or manual selection │ -│ │ -│ Phase 4: TODO Tracking Setup │ -│ ├─ Create TodoWrite with chain steps │ -│ └─ Mark first step as in_progress │ -│ │ -│ Phase 5: Execution Loop │ -│ ├─ Execute current step (SlashCommand) │ -│ ├─ Update TODO status (completed) │ -│ ├─ Check auto_continue flag │ -│ └─ Proceed to next step or wait for user │ -│ │ -└──────────────────────────────────────────────────────────────────┘ +┌────────────────────────────────────────────────────────────────┐ +│ CCW Orchestrator (CLI-Enhanced + Requirement Analysis) │ +├────────────────────────────────────────────────────────────────┤ +│ Phase 1 │ Input Analysis (rule-based, fast path) │ +│ Phase 1.5 │ CLI Classification (semantic, smart path) │ +│ Phase 1.75│ Requirement Clarification (clarity < 2) │ +│ Phase 2 │ Chain Selection (intent → workflow) │ +│ Phase 2.5 │ CLI Action Planning (high complexity) │ +│ Phase 3 │ User Confirmation (optional) │ +│ Phase 4 │ TODO Tracking Setup │ +│ Phase 5 │ Execution Loop │ +└────────────────────────────────────────────────────────────────┘ ``` -## Requirement Analysis Integration +**References**: +- [specs/requirement-analysis.md](../specs/requirement-analysis.md) - Dimension extraction & clarity scoring +- [specs/output-templates.md](../specs/output-templates.md) - Standardized output templates -See [specs/requirement-analysis.md](../specs/requirement-analysis.md) for full specification. +## CLI Enhancement Config -### Clarity Scoring +| Feature | Trigger | Default Tool | +|---------|---------|--------------| +| Classification | matchCount < 2 OR complexity = high OR input > 100 chars | gemini | +| Action Planning | complexity = high OR steps >= 3 OR input > 200 chars | gemini | -| Score | Level | Action | -|-------|-------|--------| -| 0 | 模糊 | 必须澄清 | -| 1 | 基本 | 建议澄清 | -| 2 | 清晰 | 可直接执行 | -| 3 | 详细 | 直接执行 | +Settings in `index/intent-rules.json`. Fallback: gemini → qwen → rule-based. -### Dimension Extraction +--- + +## Core Helpers ```javascript -// Extract requirement dimensions during Phase 1 -function extractDimensions(input) { - return { - what: extractWhat(input), // Action + Target - where: extractWhere(input), // Scope + Paths - why: extractWhy(input), // Goal + Motivation - how: extractHow(input), // Constraints + Preferences - clarity_score: 0, // Calculated later - missing_dimensions: [] // Identified later +// === Pattern Matching === +const matchesAny = (text, patterns) => + Array.isArray(patterns) && patterns.some(p => text.toLowerCase().includes(p.toLowerCase())) + +// === CLI Execution Helper === +async function executeCli(prompt, config, purpose) { + const tool = config.default_tool || 'gemini' + const timeout = config.timeout_ms || 60000 + + try { + const escaped = prompt.replace(/"/g, '\\"').replace(/\n/g, '\\n') + const result = Bash({ + command: `ccw cli -p "${escaped}" --tool ${tool} --mode analysis`, + run_in_background: false, + timeout + }) + + const jsonMatch = result.match(/\{[\s\S]*\}/) + if (!jsonMatch) throw new Error('No JSON in CLI response') + return JSON.parse(jsonMatch[0]) + } catch (error) { + console.log(`> CLI ${purpose} failed: ${error.message}, falling back`) + return null } } -``` -## Output Templates Integration - -See [specs/output-templates.md](../specs/output-templates.md) for full specification. - -All output uses standardized templates for consistency: -- Classification Summary -- Requirement Analysis -- Planning Summary -- Execution Progress -- Workflow Complete - -## CLI Enhancement Features - -### Trigger Conditions - -| Feature | Trigger Condition | Default Tool | -|---------|------------------|--------------| -| CLI Classification | matchCount < 2 OR complexity = high OR input > 100 chars | gemini | -| CLI Action Planning | complexity = high OR steps >= 3 OR input > 200 chars | gemini | - -### Fallback Behavior - -- **Classification**: If CLI fails, falls back to rule-based classification -- **Action Planning**: If CLI fails, uses default chain without optimization -- **Tool Fallback**: Primary tool (gemini) -> Secondary tool (qwen) - -### Configuration - -All CLI enhancement settings are in `index/intent-rules.json`: - -```json -{ - "cli_classification": { - "enabled": true, - "trigger_conditions": { ... }, - "default_tool": "gemini", - "fallback_tool": "qwen" - }, - "cli_action_planning": { - "enabled": true, - "trigger_conditions": { ... }, - "allow_step_modification": true - } +// === TODO Tracking Helpers === +function updateTodos(todos, updates) { + TodoWrite({ todos: todos.map((t, i) => updates[i] ? { ...t, ...updates[i] } : t) }) } + +function formatDuration(ms) { return (ms / 1000).toFixed(1) } +function timestamp() { return new Date().toLocaleTimeString() } ``` -## Implementation +--- -### Phase 1: Input Analysis +## Phase 1: Input Analysis ```javascript -// Load external configuration (externalized for flexibility) const intentRules = JSON.parse(Read('.claude/skills/ccw/index/intent-rules.json')) -const capabilities = JSON.parse(Read('.claude/skills/ccw/index/command-capabilities.json')) +const chains = JSON.parse(Read('.claude/skills/ccw/index/workflow-chains.json')) function analyzeInput(userInput) { const input = userInput.trim() - - // Check for explicit command passthrough + + // Explicit command passthrough if (input.match(/^\/(?:workflow|issue|memory|task):/)) { return { type: 'explicit', command: input, passthrough: true } } - - // Classify intent using external rules - const intent = classifyIntent(input, intentRules.intent_patterns) - - // Assess complexity using external indicators - const complexity = assessComplexity(input, intentRules.complexity_indicators) - - // Detect tool preferences using external triggers - const toolPreference = detectToolPreference(input, intentRules.cli_tool_triggers) - + return { type: 'natural', text: input, - intent, - complexity, - toolPreference, + intent: classifyIntent(input, intentRules.intent_patterns), + complexity: assessComplexity(input, intentRules.complexity_indicators), + toolPreference: detectToolPreference(input, intentRules.cli_tool_triggers), passthrough: false } } function classifyIntent(text, patterns) { - // Sort by priority - const sorted = Object.entries(patterns) - .sort((a, b) => a[1].priority - b[1].priority) - + const sorted = Object.entries(patterns).sort((a, b) => a[1].priority - b[1].priority) + for (const [intentType, config] of sorted) { // Handle variants (bugfix, ui, docs) if (config.variants) { - for (const [variant, variantConfig] of Object.entries(config.variants)) { - const variantPatterns = variantConfig.patterns || variantConfig.triggers || [] - if (matchesAnyPattern(text, variantPatterns)) { - // For bugfix, check if standard patterns also match + for (const [variant, vc] of Object.entries(config.variants)) { + const vPatterns = vc.patterns || vc.triggers || [] + if (matchesAny(text, vPatterns)) { if (intentType === 'bugfix') { - const standardMatch = matchesAnyPattern(text, config.variants.standard?.patterns || []) - if (standardMatch) { - return { type: intentType, variant, workflow: variantConfig.workflow } - } + if (matchesAny(text, config.variants.standard?.patterns || [])) + return { type: intentType, variant, workflow: vc.workflow } } else { - return { type: intentType, variant, workflow: variantConfig.workflow } + return { type: intentType, variant, workflow: vc.workflow } } } } - // Check default variant - if (config.variants.standard) { - if (matchesAnyPattern(text, config.variants.standard.patterns)) { - return { type: intentType, variant: 'standard', workflow: config.variants.standard.workflow } - } - } + if (config.variants.standard && matchesAny(text, config.variants.standard.patterns)) + return { type: intentType, variant: 'standard', workflow: config.variants.standard.workflow } } - - // Handle simple patterns (exploration, tdd, review) - if (config.patterns && !config.require_both) { - if (matchesAnyPattern(text, config.patterns)) { - return { type: intentType, workflow: config.workflow } - } - } - - // Handle dual-pattern matching (issue_batch) + + // Simple patterns + if (config.patterns && !config.require_both && matchesAny(text, config.patterns)) + return { type: intentType, workflow: config.workflow } + + // Dual-pattern (issue_batch) if (config.require_both && config.patterns) { - const matchBatch = matchesAnyPattern(text, config.patterns.batch_keywords) - const matchAction = matchesAnyPattern(text, config.patterns.action_keywords) - if (matchBatch && matchAction) { + if (matchesAny(text, config.patterns.batch_keywords) && matchesAny(text, config.patterns.action_keywords)) return { type: intentType, workflow: config.workflow } - } } } - - // Default to feature return { type: 'feature' } } -function matchesAnyPattern(text, patterns) { - if (!Array.isArray(patterns)) return false - const lowerText = text.toLowerCase() - return patterns.some(p => lowerText.includes(p.toLowerCase())) -} - function assessComplexity(text, indicators) { let score = 0 - for (const [level, config] of Object.entries(indicators)) { if (config.patterns) { - for (const [category, patternConfig] of Object.entries(config.patterns)) { - if (matchesAnyPattern(text, patternConfig.keywords)) { - score += patternConfig.weight || 1 - } + for (const [, pc] of Object.entries(config.patterns)) { + if (matchesAny(text, pc.keywords)) score += pc.weight || 1 } } } - if (score >= indicators.high.score_threshold) return 'high' if (score >= indicators.medium.score_threshold) return 'medium' return 'low' @@ -244,552 +148,322 @@ function assessComplexity(text, indicators) { function detectToolPreference(text, triggers) { for (const [tool, config] of Object.entries(triggers)) { - // Check explicit triggers - if (matchesAnyPattern(text, config.explicit)) return tool - // Check semantic triggers - if (matchesAnyPattern(text, config.semantic)) return tool + if (matchesAny(text, config.explicit) || matchesAny(text, config.semantic)) return tool } return null } -// Calculate match count for confidence assessment function calculateMatchCount(text, patterns) { let count = 0 - for (const [intentType, config] of Object.entries(patterns)) { + for (const [, config] of Object.entries(patterns)) { if (config.variants) { - for (const [variant, variantConfig] of Object.entries(config.variants)) { - const variantPatterns = variantConfig.patterns || variantConfig.triggers || [] - if (matchesAnyPattern(text, variantPatterns)) count++ + for (const [, vc] of Object.entries(config.variants)) { + if (matchesAny(text, vc.patterns || vc.triggers || [])) count++ } } - if (config.patterns && !config.require_both) { - if (matchesAnyPattern(text, config.patterns)) count++ - } + if (config.patterns && !config.require_both && matchesAny(text, config.patterns)) count++ } return count } ``` -### Phase 1.5: CLI-Assisted Classification +--- -For ambiguous or complex inputs, use CLI tools for semantic understanding. +## Dimension Extraction (WHAT/WHERE/WHY/HOW) ```javascript -// CLI-assisted classification for ambiguous inputs -async function cliAssistedClassification(input, ruleBasedResult, intentRules) { - const cliConfig = intentRules.cli_classification - - // Skip if CLI classification is disabled - if (!cliConfig || !cliConfig.enabled) { - return { ...ruleBasedResult, source: 'rules', matchCount: 0 } - } - - // Calculate match count for confidence assessment - const matchCount = calculateMatchCount(input, intentRules.intent_patterns) - - // Determine if CLI classification should be triggered - const triggers = cliConfig.trigger_conditions - const shouldUseCli = - matchCount < triggers.low_match_count || - ruleBasedResult.complexity === triggers.complexity_trigger || - input.length > triggers.min_input_length || - matchesAnyPattern(input, triggers.ambiguous_patterns) - - if (!shouldUseCli) { - return { ...ruleBasedResult, source: 'rules', matchCount } - } - - console.log('### CLI-Assisted Intent Classification\n') - console.log('> Using CLI for semantic understanding of ambiguous input...\n') - - // Build CLI prompt for intent classification - const cliPrompt = ` -PURPOSE: Classify user request intent and recommend optimal workflow -TASK: -- Analyze the semantic meaning of the user request -- Classify into one of: bugfix, feature, exploration, ui, issue, tdd, review, docs -- Assess complexity: low, medium, high -- Recommend workflow chain based on intent and complexity -- Provide confidence score (0-1) - -MODE: analysis -CONTEXT: User request analysis for workflow orchestration -EXPECTED: JSON output with structure: -{ - "intent": { - "type": "bugfix|feature|exploration|ui|issue|tdd|review|docs", - "variant": "optional variant like hotfix, imitate, incremental", - "confidence": 0.0-1.0, - "reasoning": "brief explanation of classification" +const PATTERNS = { + actions: { + create: /创建|新增|添加|实现|生成|create|add|implement|generate/i, + fix: /修复|修正|解决|fix|repair|resolve|debug/i, + refactor: /重构|优化结构|重写|refactor|restructure|rewrite/i, + optimize: /优化|提升|改进|性能|optimize|improve|enhance|performance/i, + analyze: /分析|理解|探索|研究|analyze|understand|explore|research/i, + review: /审查|检查|评估|review|check|assess|audit/i }, - "complexity": { - "level": "low|medium|high", - "factors": ["factor1", "factor2"], - "confidence": 0.0-1.0 - }, - "recommended_workflow": { - "chain_id": "rapid|full|coupled|bugfix|issue|tdd|ui|review-fix|docs", - "reasoning": "why this workflow is optimal" - }, - "tool_preference": { - "suggested": "gemini|qwen|codex|null", - "reasoning": "optional reasoning" + files: /(\S+\.(ts|js|py|md|json|yaml|yml|tsx|jsx|vue|css|scss))/g, + modules: /(src\/\S+|lib\/\S+|packages\/\S+|components\/\S+)/g, + dirs: /(\/[\w\-\.\/]+)/g, + systemScope: /全局|全部|整个|all|entire|whole|系统/i, + goal: /(?:为了|因为|目的是|to|for|because)\s+([^,,。]+)/i, + motivation: /(?:需要|想要|希望|want|need|should)\s+([^,,。]+)/i, + must: /(?:必须|一定要|需要|must|required)\s+([^,,。]+)/i, + mustNot: /(?:不要|禁止|不能|避免|must not|don't|avoid)\s+([^,,。]+)/i, + prefer: /(?:应该|最好|建议|should|prefer)\s+([^,,。]+)/i, + unclear: /不知道|不确定|maybe|可能|how to|怎么/i, + helpRequest: /帮我|help me|请问/i +} + +function extractDimensions(input) { + // WHAT + let action = null + for (const [key, pattern] of Object.entries(PATTERNS.actions)) { + if (pattern.test(input)) { action = key; break } + } + const targetMatch = input.match(/(?:对|in|for|the)\s+([^\s,,。]+)/i) + + // WHERE + const files = [...input.matchAll(PATTERNS.files)].map(m => m[1]) + const modules = [...input.matchAll(PATTERNS.modules)].map(m => m[1]) + const dirs = [...input.matchAll(PATTERNS.dirs)].map(m => m[1]) + const paths = [...new Set([...files, ...modules, ...dirs])] + const scope = files.length > 0 ? 'file' : modules.length > 0 ? 'module' : PATTERNS.systemScope.test(input) ? 'system' : 'unknown' + + // WHY + const goalMatch = input.match(PATTERNS.goal) + const motivationMatch = input.match(PATTERNS.motivation) + + // HOW + const constraints = [] + const mustMatch = input.match(PATTERNS.must) + const mustNotMatch = input.match(PATTERNS.mustNot) + if (mustMatch) constraints.push(mustMatch[1].trim()) + if (mustNotMatch) constraints.push('NOT: ' + mustNotMatch[1].trim()) + const prefMatch = input.match(PATTERNS.prefer) + const preferences = prefMatch ? [prefMatch[1].trim()] : null + + return { + what: { action, target: targetMatch?.[1] || null, description: input.substring(0, 100) }, + where: { scope, paths: paths.length > 0 ? paths : null, patterns: null }, + why: { goal: goalMatch?.[1]?.trim() || null, motivation: motivationMatch?.[1]?.trim() || null, success_criteria: null }, + how: { constraints: constraints.length > 0 ? constraints : null, preferences, approach: null }, + clarity_score: 0, + missing_dimensions: [] } } -USER REQUEST: -${input} - -RULES: Output ONLY valid JSON without markdown code blocks. Be concise but accurate. -` - - // Select CLI tool (default or fallback) - const tool = cliConfig.default_tool || 'gemini' - const timeout = cliConfig.timeout_ms || 60000 - - try { - // Execute CLI call synchronously for classification - const escapedPrompt = cliPrompt.replace(/"/g, '\\"').replace(/\n/g, '\\n') - const cliResult = Bash({ - command: `ccw cli -p "${escapedPrompt}" --tool ${tool} --mode analysis`, - run_in_background: false, - timeout: timeout - }) - - // Parse CLI result - extract JSON from response - const jsonMatch = cliResult.match(/\{[\s\S]*\}/) - if (!jsonMatch) { - throw new Error('No JSON found in CLI response') - } - - const parsed = JSON.parse(jsonMatch[0]) - - console.log(` -**CLI Classification Result**: -- **Intent**: ${parsed.intent.type}${parsed.intent.variant ? ` (${parsed.intent.variant})` : ''} -- **Complexity**: ${parsed.complexity.level} -- **Confidence**: ${(parsed.intent.confidence * 100).toFixed(0)}% -- **Reasoning**: ${parsed.intent.reasoning} -- **Recommended Chain**: ${parsed.recommended_workflow.chain_id} -`) - - return { - type: 'natural', - text: input, - intent: { - type: parsed.intent.type, - variant: parsed.intent.variant, - workflow: parsed.recommended_workflow.chain_id - }, - complexity: parsed.complexity.level, - toolPreference: parsed.tool_preference?.suggested || ruleBasedResult.toolPreference, - confidence: parsed.intent.confidence, - source: 'cli', - cliReasoning: parsed.intent.reasoning, - passthrough: false - } - } catch (error) { - console.log(`> CLI classification failed: ${error.message}`) - console.log('> Falling back to rule-based classification\n') - - // Try fallback tool if available - if (cliConfig.fallback_tool && cliConfig.fallback_tool !== tool) { - console.log(`> Attempting fallback with ${cliConfig.fallback_tool}...`) - // Could recursively call with fallback tool, but for simplicity, just return rule-based - } - - return { ...ruleBasedResult, source: 'rules', matchCount } - } -} -``` - -### Phase 1.75: Requirement Clarification - -当需求不够清晰时,主动向用户发起澄清。 - -```javascript -// Requirement clarification for ambiguous inputs -async function clarifyRequirement(analysis, dimensions) { - // Skip if already clear - if (dimensions.clarity_score >= 2) { - return { needsClarification: false, dimensions } - } - - // Skip for explicit commands - if (analysis.passthrough) { - return { needsClarification: false, dimensions } - } - - console.log('### Requirement Clarification\n') - console.log('> Your request needs more detail. Let me ask a few questions.\n') - - // Generate questions based on missing dimensions - const questions = generateClarificationQuestions(dimensions) - - if (questions.length === 0) { - return { needsClarification: false, dimensions } - } - - // Display current understanding - console.log(` -**Current Understanding**: -| Dimension | Value | Status | -|-----------|-------|--------| -| WHAT | ${dimensions.what.action || 'unknown'} ${dimensions.what.target || ''} | ${dimensions.what.target ? '✓' : '⚠'} | -| WHERE | ${dimensions.where.scope}: ${dimensions.where.paths?.join(', ') || 'unknown'} | ${dimensions.where.paths?.length ? '✓' : '⚠'} | -| WHY | ${dimensions.why.goal || 'not specified'} | ${dimensions.why.goal ? '✓' : '○'} | -| HOW | ${dimensions.how.constraints?.join(', ') || 'no constraints'} | ○ | - -**Clarity Score**: ${dimensions.clarity_score}/3 -`) - - // Ask user for clarification (max 4 questions) - const responses = AskUserQuestion({ - questions: questions.slice(0, 4) - }) - - // Refine dimensions with user responses - const refinedDimensions = refineDimensions(dimensions, responses) - refinedDimensions.clarity_score = Math.min(3, dimensions.clarity_score + 1) - - console.log('> Requirements clarified. Proceeding with workflow selection.\n') - - return { needsClarification: false, dimensions: refinedDimensions } +function calculateClarityScore(input, d) { + let score = 0 + if (d.what.action) score += 0.5 + if (d.what.target) score += 0.5 + if (d.where.paths?.length > 0) score += 0.5 + if (d.where.scope !== 'unknown') score += 0.5 + if (d.why.goal) score += 0.5 + if (d.how.constraints?.length > 0) score += 0.5 + if (PATTERNS.unclear.test(input)) score -= 0.5 + if (PATTERNS.helpRequest.test(input)) score -= 0.5 + return Math.max(0, Math.min(3, Math.round(score))) } -// Generate clarification questions based on missing info -function generateClarificationQuestions(dimensions) { - const questions = [] - - // WHAT: If target is unclear - if (!dimensions.what.target) { - questions.push({ - question: "你想要对什么进行操作?", - header: "目标", - multiSelect: false, - options: [ - { label: "特定文件", description: "修改特定的文件或代码" }, - { label: "功能模块", description: "处理整个功能模块" }, - { label: "系统级", description: "架构或系统级变更" }, - { label: "让我指定", description: "我会提供具体说明" } - ] - }) - } - - // WHERE: If scope is unknown - if (dimensions.where.scope === 'unknown' && !dimensions.where.paths?.length) { - questions.push({ - question: "操作的范围是什么?", - header: "范围", - multiSelect: false, - options: [ - { label: "自动发现", description: "分析代码库后推荐相关位置" }, - { label: "当前目录", description: "只在当前工作目录" }, - { label: "全项目", description: "整个项目范围" }, - { label: "让我指定", description: "我会提供具体路径" } - ] - }) - } - - // WHY: If goal is unclear for complex tasks - if (!dimensions.why.goal && dimensions.what.action !== 'analyze') { - questions.push({ - question: "这个操作的主要目标是什么?", - header: "目标", - multiSelect: false, - options: [ - { label: "修复问题", description: "解决已知的Bug或错误" }, - { label: "新增功能", description: "添加新的能力或特性" }, - { label: "改进质量", description: "提升性能、可维护性" }, - { label: "代码审查", description: "检查和评估代码" } - ] - }) - } - - // HOW: If constraints matter for the task - if (dimensions.what.action === 'refactor' || dimensions.what.action === 'create') { - questions.push({ - question: "有什么特殊要求或限制?", - header: "约束", - multiSelect: true, - options: [ - { label: "保持兼容", description: "不破坏现有功能" }, - { label: "最小改动", description: "尽量少修改文件" }, - { label: "包含测试", description: "需要添加测试" }, - { label: "无特殊要求", description: "按最佳实践处理" } - ] - }) - } - - return questions -} - -// Refine dimensions based on user responses -function refineDimensions(dimensions, responses) { - const refined = { ...dimensions } - - // Apply user selections to dimensions - if (responses['目标']) { - if (responses['目标'] === '特定文件') { - refined.where.scope = 'file' - } else if (responses['目标'] === '功能模块') { - refined.where.scope = 'module' - } else if (responses['目标'] === '系统级') { - refined.where.scope = 'system' - } - } - - if (responses['范围']) { - if (responses['范围'] === '全项目') { - refined.where.scope = 'system' - } else if (responses['范围'] === '当前目录') { - refined.where.scope = 'module' - } - } - - if (responses['目标']) { - const goalMapping = { - '修复问题': 'fix bug', - '新增功能': 'add feature', - '改进质量': 'improve quality', - '代码审查': 'code review' - } - refined.why.goal = goalMapping[responses['目标']] || responses['目标'] - } - - if (responses['约束']) { - const constraints = Array.isArray(responses['约束']) ? responses['约束'] : [responses['约束']] - refined.how.constraints = constraints.filter(c => c !== '无特殊要求') - } - - // Update missing dimensions - refined.missing_dimensions = identifyMissing(refined) - - return refined -} - -// Identify still-missing dimensions -function identifyMissing(dimensions) { +function identifyMissing(d) { const missing = [] - if (!dimensions.what.target) missing.push('what.target') - if (dimensions.where.scope === 'unknown') missing.push('where.scope') - // why and how are optional + if (!d.what.target) missing.push('what.target') + if (d.where.scope === 'unknown') missing.push('where.scope') return missing } ``` -### Phase 2: Chain Selection +--- + +## Phase 1.5: CLI-Assisted Classification ```javascript -// Load workflow chains index -const chains = JSON.parse(Read('.claude/skills/ccw/index/workflow-chains.json')) +async function cliAssistedClassification(input, ruleBasedResult, intentRules) { + const cfg = intentRules.cli_classification + if (!cfg?.enabled) return { ...ruleBasedResult, source: 'rules', matchCount: 0 } + + const matchCount = calculateMatchCount(input, intentRules.intent_patterns) + const triggers = cfg.trigger_conditions + const shouldUseCli = matchCount < triggers.low_match_count || + ruleBasedResult.complexity === triggers.complexity_trigger || + input.length > triggers.min_input_length || + matchesAny(input, triggers.ambiguous_patterns) + + if (!shouldUseCli) return { ...ruleBasedResult, source: 'rules', matchCount } + + console.log('### CLI-Assisted Intent Classification\n') + + const prompt = ` +PURPOSE: Classify user request intent and recommend optimal workflow +TASK: Analyze semantic meaning, classify intent, assess complexity, recommend workflow +MODE: analysis +USER REQUEST: ${input} +EXPECTED: JSON { intent: { type, variant?, confidence, reasoning }, complexity: { level, factors, confidence }, recommended_workflow: { chain_id, reasoning }, tool_preference?: { suggested, reasoning } } +RULES: Output ONLY valid JSON. Types: bugfix|feature|exploration|ui|issue|tdd|review|docs. Chains: rapid|full|coupled|bugfix|issue|tdd|ui|review-fix|docs` + const parsed = await executeCli(prompt, cfg, 'classification') + if (!parsed) return { ...ruleBasedResult, source: 'rules', matchCount } + + console.log(`**CLI Result**: ${parsed.intent.type}${parsed.intent.variant ? ` (${parsed.intent.variant})` : ''} | ${parsed.complexity.level} | ${(parsed.intent.confidence * 100).toFixed(0)}% confidence`) + + return { + type: 'natural', text: input, + intent: { type: parsed.intent.type, variant: parsed.intent.variant, workflow: parsed.recommended_workflow.chain_id }, + complexity: parsed.complexity.level, + toolPreference: parsed.tool_preference?.suggested || ruleBasedResult.toolPreference, + confidence: parsed.intent.confidence, + source: 'cli', cliReasoning: parsed.intent.reasoning, passthrough: false + } +} +``` + +--- + +## Phase 1.75: Requirement Clarification + +```javascript +async function clarifyRequirement(analysis, dimensions) { + if (dimensions.clarity_score >= 2 || analysis.passthrough) + return { needsClarification: false, dimensions } + + console.log('### Requirement Clarification\n') + console.log(`**Clarity**: ${dimensions.clarity_score}/3 | WHAT: ${dimensions.what.action || '?'} | WHERE: ${dimensions.where.scope} | WHY: ${dimensions.why.goal || '?'}`) + + const questions = generateClarificationQuestions(dimensions) + if (questions.length === 0) return { needsClarification: false, dimensions } + + const responses = AskUserQuestion({ questions: questions.slice(0, 4) }) + const refined = refineDimensions(dimensions, responses) + refined.clarity_score = Math.min(3, dimensions.clarity_score + 1) + + return { needsClarification: false, dimensions: refined } +} + +function generateClarificationQuestions(d) { + const Q = [] + + if (!d.what.target) Q.push({ + question: "你想要对什么进行操作?", header: "目标", multiSelect: false, + options: [ + { label: "特定文件", description: "修改特定的文件或代码" }, + { label: "功能模块", description: "处理整个功能模块" }, + { label: "系统级", description: "架构或系统级变更" }, + { label: "让我指定", description: "我会提供具体说明" } + ] + }) + + if (d.where.scope === 'unknown' && !d.where.paths?.length) Q.push({ + question: "操作的范围是什么?", header: "范围", multiSelect: false, + options: [ + { label: "自动发现", description: "分析代码库后推荐相关位置" }, + { label: "当前目录", description: "只在当前工作目录" }, + { label: "全项目", description: "整个项目范围" }, + { label: "让我指定", description: "我会提供具体路径" } + ] + }) + + if (!d.why.goal && d.what.action !== 'analyze') Q.push({ + question: "这个操作的主要目标是什么?", header: "目标类型", multiSelect: false, + options: [ + { label: "修复问题", description: "解决已知的Bug或错误" }, + { label: "新增功能", description: "添加新的能力或特性" }, + { label: "改进质量", description: "提升性能、可维护性" }, + { label: "代码审查", description: "检查和评估代码" } + ] + }) + + if (d.what.action === 'refactor' || d.what.action === 'create') Q.push({ + question: "有什么特殊要求或限制?", header: "约束", multiSelect: true, + options: [ + { label: "保持兼容", description: "不破坏现有功能" }, + { label: "最小改动", description: "尽量少修改文件" }, + { label: "包含测试", description: "需要添加测试" }, + { label: "无特殊要求", description: "按最佳实践处理" } + ] + }) + + return Q +} + +function refineDimensions(d, responses) { + const r = { ...d, what: { ...d.what }, where: { ...d.where }, why: { ...d.why }, how: { ...d.how } } + + const scopeMap = { '特定文件': 'file', '功能模块': 'module', '系统级': 'system', '全项目': 'system', '当前目录': 'module' } + const goalMap = { '修复问题': 'fix bug', '新增功能': 'add feature', '改进质量': 'improve quality', '代码审查': 'code review' } + + if (responses['目标'] && scopeMap[responses['目标']]) r.where.scope = scopeMap[responses['目标']] + if (responses['范围'] && scopeMap[responses['范围']]) r.where.scope = scopeMap[responses['范围']] + if (responses['目标类型'] && goalMap[responses['目标类型']]) r.why.goal = goalMap[responses['目标类型']] + if (responses['约束']) { + const c = Array.isArray(responses['约束']) ? responses['约束'] : [responses['约束']] + r.how.constraints = c.filter(x => x !== '无特殊要求') + } + + r.missing_dimensions = identifyMissing(r) + return r +} +``` + +--- + +## Phase 2: Chain Selection + +```javascript function selectChain(analysis) { const { intent, complexity } = analysis - - // Map intent type (from intent-rules.json) to chain ID (from workflow-chains.json) - const chainMapping = { - 'bugfix': 'bugfix', - 'issue_batch': 'issue', // intent-rules.json key → chains.json chain ID - 'exploration': 'full', - 'ui_design': 'ui', // intent-rules.json key → chains.json chain ID - 'tdd': 'tdd', - 'review': 'review-fix', - 'documentation': 'docs', // intent-rules.json key → chains.json chain ID - 'feature': null // Use complexity fallback - } - - let chainId = chainMapping[intent.type] - - // Fallback to complexity-based selection - if (!chainId) { - chainId = chains.chain_selection_rules.complexity_fallback[complexity] + const chainMap = { + bugfix: 'bugfix', issue_batch: 'issue', exploration: 'full', ui_design: 'ui', + tdd: 'tdd', review: 'review-fix', documentation: 'docs', feature: null } + let chainId = chainMap[intent.type] || chains.chain_selection_rules.complexity_fallback[complexity] const chain = chains.chains[chainId] - - // Handle variants let steps = chain.steps + if (chain.variants) { const variant = intent.variant || Object.keys(chain.variants)[0] steps = chain.variants[variant].steps } - return { - id: chainId, - name: chain.name, - description: chain.description, - steps, - complexity: chain.complexity, - estimated_time: chain.estimated_time - } + return { id: chainId, name: chain.name, description: chain.description, steps, complexity: chain.complexity, estimated_time: chain.estimated_time } } ``` -### Phase 2.5: CLI-Assisted Action Planning +--- -For high complexity tasks, use CLI to plan optimal execution strategy. +## Phase 2.5: CLI-Assisted Action Planning ```javascript -// CLI-assisted action planning for complex tasks async function cliAssistedPlanning(analysis, selectedChain, intentRules) { - const planConfig = intentRules.cli_action_planning - - // Skip if action planning is disabled - if (!planConfig || !planConfig.enabled) { - return { useDefaultChain: true, chain: selectedChain } - } - - // Determine if CLI planning should be triggered - const triggers = planConfig.trigger_conditions - const shouldUseCli = - analysis.complexity === triggers.complexity_threshold || + const cfg = intentRules.cli_action_planning + if (!cfg?.enabled) return { useDefaultChain: true, chain: selectedChain } + + const triggers = cfg.trigger_conditions + const shouldUseCli = analysis.complexity === triggers.complexity_threshold || selectedChain.steps.length >= triggers.step_count_threshold || - (analysis.text && analysis.text.length > 200) - - if (!shouldUseCli) { - return { useDefaultChain: true, chain: selectedChain } - } - + (analysis.text?.length > 200) + + if (!shouldUseCli) return { useDefaultChain: true, chain: selectedChain } + console.log('### CLI-Assisted Action Planning\n') - console.log('> Using CLI to optimize execution strategy for complex task...\n') - - // Build CLI prompt for action planning - const planningPrompt = ` -PURPOSE: Plan optimal workflow execution strategy for complex task -TASK: -- Review the selected workflow chain and its steps -- Consider task complexity, dependencies, and potential risks -- Suggest step modifications, additions, or reordering if beneficial -- Identify potential risks and provide mitigations -- Recommend CLI tool injection points for efficiency - -MODE: analysis -CONTEXT: -- User Intent: ${analysis.intent.type}${analysis.intent.variant ? ` (${analysis.intent.variant})` : ''} -- Complexity: ${analysis.complexity} -- Selected Chain: ${selectedChain.name} -- Current Steps: ${selectedChain.steps.map((s, i) => `${i + 1}. ${s.command}`).join(', ')} -- User Request: ${analysis.text ? analysis.text.substring(0, 200) : 'N/A'} - -EXPECTED: JSON output with structure: -{ - "recommendation": "use_default|modify|upgrade", - "modified_steps": [ - { "command": "/workflow:xxx", "optional": false, "auto_continue": true, "reason": "why this step" } - ], - "cli_injections": [ - { "before_step": 1, "tool": "gemini", "mode": "analysis", "purpose": "pre-analysis" } - ], - "reasoning": "explanation of recommendations", - "risks": ["risk1", "risk2"], - "mitigations": ["mitigation1", "mitigation2"], - "suggestions": ["suggestion1", "suggestion2"] -} - -RULES: Output ONLY valid JSON. If no modifications needed, set recommendation to "use_default" and leave modified_steps empty. -` - - const tool = planConfig.default_tool || 'gemini' - const timeout = planConfig.timeout_ms || 60000 - - try { - const escapedPrompt = planningPrompt.replace(/"/g, '\\"').replace(/\n/g, '\\n') - const cliResult = Bash({ - command: `ccw cli -p "${escapedPrompt}" --tool ${tool} --mode analysis`, - run_in_background: false, - timeout: timeout - }) - - // Parse CLI result - const jsonMatch = cliResult.match(/\{[\s\S]*\}/) - if (!jsonMatch) { - throw new Error('No JSON found in CLI response') - } - - const parsed = JSON.parse(jsonMatch[0]) - - // Display planning results - console.log(` -**CLI Planning Result**: -- **Recommendation**: ${parsed.recommendation} -- **Reasoning**: ${parsed.reasoning} -${parsed.risks && parsed.risks.length > 0 ? `- **Risks**: ${parsed.risks.join(', ')}` : ''} -${parsed.suggestions && parsed.suggestions.length > 0 ? `- **Suggestions**: ${parsed.suggestions.join(', ')}` : ''} -`) - - // Handle step modification - if (parsed.recommendation === 'modify' && parsed.modified_steps && parsed.modified_steps.length > 0) { - if (planConfig.allow_step_modification) { - console.log('> Applying modified execution plan\n') - return { - useDefaultChain: false, - chain: { - ...selectedChain, - steps: parsed.modified_steps - }, - reasoning: parsed.reasoning, - risks: parsed.risks, - cliInjections: parsed.cli_injections, - source: 'cli-planned' - } - } else { - console.log('> Step modification disabled, using default chain with suggestions\n') - } - } - - // Handle upgrade recommendation - if (parsed.recommendation === 'upgrade') { - console.log('> CLI recommends upgrading to a more comprehensive workflow\n') - // Could select a more complex chain here - } + + const prompt = ` +PURPOSE: Plan optimal workflow execution strategy +CONTEXT: Intent=${analysis.intent.type}, Complexity=${analysis.complexity}, Chain=${selectedChain.name}, Steps=${selectedChain.steps.map(s => s.command).join(',')} +USER REQUEST: ${analysis.text?.substring(0, 200) || 'N/A'} +EXPECTED: JSON { recommendation: "use_default|modify|upgrade", modified_steps?: [], cli_injections?: [], reasoning, risks?: [], suggestions?: [] } +RULES: Output ONLY valid JSON. If no modifications needed, use "use_default".` + const parsed = await executeCli(prompt, cfg, 'planning') + if (!parsed) return { useDefaultChain: true, chain: selectedChain, source: 'default' } + + console.log(`**Planning**: ${parsed.recommendation}${parsed.reasoning ? ` - ${parsed.reasoning}` : ''}`) + + if (parsed.recommendation === 'modify' && parsed.modified_steps?.length > 0 && cfg.allow_step_modification) { return { - useDefaultChain: true, - chain: selectedChain, - suggestions: parsed.suggestions, - risks: parsed.risks, - cliInjections: parsed.cli_injections, - source: 'cli-reviewed' + useDefaultChain: false, + chain: { ...selectedChain, steps: parsed.modified_steps }, + reasoning: parsed.reasoning, risks: parsed.risks, cliInjections: parsed.cli_injections, source: 'cli-planned' } - } catch (error) { - console.log(`> CLI planning failed: ${error.message}`) - console.log('> Using default chain without optimization\n') - - return { useDefaultChain: true, chain: selectedChain, source: 'default' } } + + return { useDefaultChain: true, chain: selectedChain, suggestions: parsed.suggestions, risks: parsed.risks, source: 'cli-reviewed' } } ``` -### Phase 3: User Confirmation +--- + +## Phase 3: User Confirmation ```javascript function confirmChain(selectedChain, analysis) { - // Skip confirmation for simple chains - if (selectedChain.steps.length <= 2 && analysis.complexity === 'low') { - return selectedChain - } + if (selectedChain.steps.length <= 2 && analysis.complexity === 'low') return selectedChain - console.log(` -## CCW Workflow Selection - -**Task**: ${analysis.text.substring(0, 80)}... -**Intent**: ${analysis.intent.type}${analysis.intent.variant ? ` (${analysis.intent.variant})` : ''} -**Complexity**: ${analysis.complexity} - -**Selected Chain**: ${selectedChain.name} -**Description**: ${selectedChain.description} -**Estimated Time**: ${selectedChain.estimated_time} - -**Steps**: -${selectedChain.steps.map((s, i) => `${i + 1}. ${s.command}${s.optional ? ' (optional)' : ''}`).join('\n')} -`) + console.log(`\n## CCW Workflow: ${selectedChain.name}\n**Intent**: ${analysis.intent.type} | **Complexity**: ${analysis.complexity}\n**Steps**: ${selectedChain.steps.map((s, i) => `${i + 1}. ${s.command}`).join(' → ')}`) const response = AskUserQuestion({ questions: [{ - question: `Proceed with ${selectedChain.name}?`, - header: "Confirm", - multiSelect: false, + question: `Proceed with ${selectedChain.name}?`, header: "Confirm", multiSelect: false, options: [ { label: "Proceed", description: `Execute ${selectedChain.steps.length} steps` }, { label: "Rapid", description: "Use lite-plan → lite-execute" }, @@ -799,227 +473,217 @@ ${selectedChain.steps.map((s, i) => `${i + 1}. ${s.command}${s.optional ? ' (opt }] }) - // Handle alternative selection - if (response.Confirm === 'Rapid') { - return selectChain({ intent: { type: 'feature' }, complexity: 'low' }) - } - if (response.Confirm === 'Full') { - return chains.chains['full'] - } - if (response.Confirm === 'Manual') { - return null // User will specify - } - + if (response.Confirm === 'Rapid') return selectChain({ intent: { type: 'feature' }, complexity: 'low' }) + if (response.Confirm === 'Full') return chains.chains['full'] + if (response.Confirm === 'Manual') return null return selectedChain } ``` -### Phase 4: TODO Tracking Setup +--- + +## Phase 4: TODO Tracking Setup ```javascript function setupTodoTracking(chain, analysis) { - const todos = chain.steps.map((step, index) => ({ - content: `[${index + 1}/${chain.steps.length}] ${step.command}`, - status: index === 0 ? 'in_progress' : 'pending', - activeForm: `Executing ${step.command}` - })) - - // Add header todo - todos.unshift({ - content: `CCW: ${chain.name} (${chain.steps.length} steps)`, - status: 'in_progress', - activeForm: `Running ${chain.name} workflow` - }) - + const todos = [ + { content: `CCW: ${chain.name} (${chain.steps.length} steps)`, status: 'in_progress', activeForm: `Running ${chain.name} workflow` }, + ...chain.steps.map((step, i) => ({ + content: `[${i + 1}/${chain.steps.length}] ${step.command}`, + status: i === 0 ? 'in_progress' : 'pending', + activeForm: `Executing ${step.command}` + })) + ] TodoWrite({ todos }) + return { chain, currentStep: 0, todos } +} + +function trackCommandDispatch(command) { + const name = command.split(' ')[0] + const todos = [ + { content: `CCW: Direct Command Dispatch`, status: 'in_progress', activeForm: `Dispatching ${name}` }, + { content: `[${timestamp()}] ${command}`, status: 'in_progress', activeForm: `Executing ${name}` } + ] + TodoWrite({ todos }) + return { command, startTime: Date.now(), todos } +} + +function markCommandResult(tracking, success, error) { + const duration = formatDuration(Date.now() - tracking.startTime) + const name = tracking.command.split(' ')[0] + const icon = success ? '✓' : '✗' + const suffix = success ? `(${duration}s)` : `(failed: ${error})` - return { - chain, - currentStep: 0, - todos - } + TodoWrite({ todos: [ + { content: `CCW: Direct Command Dispatch`, status: 'completed', activeForm: success ? `Completed ${name}` : 'Failed' }, + { content: `${icon} ${tracking.command} ${suffix}`, status: 'completed', activeForm: success ? `Completed ${name}` : 'Failed' } + ]}) } ``` -### Phase 5: Execution Loop +--- + +## Phase 5: Execution Loop ```javascript async function executeChain(execution, analysis) { const { chain, todos } = execution - let currentStep = 0 + let step = 0 + const timings = [] - while (currentStep < chain.steps.length) { - const step = chain.steps[currentStep] + while (step < chain.steps.length) { + const s = chain.steps[step] + const start = Date.now() - // Update TODO: mark current as in_progress - const updatedTodos = todos.map((t, i) => ({ - ...t, - status: i === 0 - ? 'in_progress' - : i === currentStep + 1 - ? 'in_progress' - : i <= currentStep - ? 'completed' - : 'pending' - })) - TodoWrite({ todos: updatedTodos }) + // Update TODO: current step in_progress + const updated = todos.map((t, i) => { + if (i === 0) return { ...t, status: 'in_progress' } + if (i === step + 1) return { ...t, status: 'in_progress', content: `[${step + 1}/${chain.steps.length}] ${s.command} (started ${timestamp()})` } + if (i <= step) { + const tm = timings[i - 1] + return { ...t, status: 'completed', content: tm === 'skipped' ? `⊘ ${t.content}` : `✓ [${i}/${chain.steps.length}] ${chain.steps[i-1].command} (${tm}s)` } + } + return { ...t, status: 'pending' } + }) + TodoWrite({ todos: updated }) - console.log(`\n### Step ${currentStep + 1}/${chain.steps.length}: ${step.command}\n`) + console.log(`\n### Step ${step + 1}/${chain.steps.length}: ${s.command}`) - // Check for confirmation requirement - if (step.confirm_before) { - const proceed = AskUserQuestion({ - questions: [{ - question: `Ready to execute ${step.command}?`, - header: "Step", - multiSelect: false, - options: [ - { label: "Execute", description: "Run this step" }, - { label: "Skip", description: "Skip to next step" }, - { label: "Abort", description: "Stop workflow" } - ] - }] + // Confirmation if required + if (s.confirm_before) { + const r = AskUserQuestion({ + questions: [{ question: `Execute ${s.command}?`, header: "Step", multiSelect: false, + options: [{ label: "Execute", description: "Run" }, { label: "Skip", description: "Skip" }, { label: "Abort", description: "Stop" }] }] }) - - if (proceed.Step === 'Skip') { - currentStep++ - continue - } - if (proceed.Step === 'Abort') { - break - } + if (r.Step === 'Skip') { timings.push('skipped'); step++; continue } + if (r.Step === 'Abort') break } - // Execute the command - const args = analysis.text - SlashCommand(step.command, { args }) + // Execute + try { + SlashCommand(s.command, { args: analysis.text }) + const duration = formatDuration(Date.now() - start) + timings.push(duration) + updated[step + 1] = { ...updated[step + 1], status: 'completed', content: `✓ [${step + 1}/${chain.steps.length}] ${s.command} (${duration}s)` } + TodoWrite({ todos: updated }) + console.log(`> Completed (${duration}s)`) + } catch (error) { + updated[step + 1] = { ...updated[step + 1], status: 'completed', content: `✗ [${step + 1}/${chain.steps.length}] ${s.command} (failed)` } + TodoWrite({ todos: updated }) + console.log(`> Failed: ${error.message}`) + + const r = AskUserQuestion({ + questions: [{ question: `Step failed. Proceed?`, header: "Error", multiSelect: false, + options: [{ label: "Retry", description: "Retry" }, { label: "Skip", description: "Skip" }, { label: "Abort", description: "Stop" }] }] + }) + if (r.Error === 'Retry') continue + if (r.Error === 'Abort') break + } - // Mark step as completed - updatedTodos[currentStep + 1].status = 'completed' - TodoWrite({ todos: updatedTodos }) - - currentStep++ + step++ // Check auto_continue - if (!step.auto_continue && currentStep < chain.steps.length) { - console.log(` -Step completed. Next: ${chain.steps[currentStep].command} -Type "continue" to proceed or specify different action. -`) - // Wait for user input before continuing + if (!s.auto_continue && step < chain.steps.length) { + console.log(`\nPaused. Next: ${chain.steps[step].command}. Type "continue" to proceed.`) break } } // Final status - if (currentStep >= chain.steps.length) { - const finalTodos = todos.map(t => ({ ...t, status: 'completed' })) - TodoWrite({ todos: finalTodos }) - - console.log(`\n✓ ${chain.name} workflow completed (${chain.steps.length} steps)`) + if (step >= chain.steps.length) { + const total = timings.filter(t => t !== 'skipped').reduce((sum, t) => sum + parseFloat(t), 0).toFixed(1) + const final = todos.map((t, i) => { + if (i === 0) return { ...t, status: 'completed', content: `✓ CCW: ${chain.name} completed (${total}s)`, activeForm: 'Complete' } + const tm = timings[i - 1] + return { ...t, status: 'completed', content: tm === 'skipped' ? `⊘ [${i}/${chain.steps.length}] ${chain.steps[i-1].command}` : `✓ [${i}/${chain.steps.length}] ${chain.steps[i-1].command} (${tm}s)` } + }) + TodoWrite({ todos: final }) + console.log(`\n✓ ${chain.name} completed (${chain.steps.length} steps, ${total}s)`) } - return { completed: currentStep, total: chain.steps.length } + return { completed: step, total: chain.steps.length, timings } } ``` +--- + ## Main Orchestration Entry ```javascript async function ccwOrchestrate(userInput) { console.log('## CCW Orchestrator\n') - - // Phase 1: Analyze input (rule-based, fast path) + + // Phase 1: Input Analysis const ruleBasedAnalysis = analyzeInput(userInput) - - // Handle explicit command passthrough + + // Handle passthrough commands if (ruleBasedAnalysis.passthrough) { - console.log(`Direct command: ${ruleBasedAnalysis.command}`) - return SlashCommand(ruleBasedAnalysis.command) + console.log(`Direct: ${ruleBasedAnalysis.command}`) + const tracking = trackCommandDispatch(ruleBasedAnalysis.command) + try { + const result = SlashCommand(ruleBasedAnalysis.command) + markCommandResult(tracking, true) + return result + } catch (error) { + markCommandResult(tracking, false, error.message) + throw error + } } - - // Phase 1.5: CLI-Assisted Classification (smart path for ambiguous inputs) + + // Phase 1.5: CLI Classification const analysis = await cliAssistedClassification(userInput, ruleBasedAnalysis, intentRules) - - // Display classification source - if (analysis.source === 'cli') { - console.log(` -### Classification Summary -- **Source**: CLI-Assisted (${analysis.confidence ? (analysis.confidence * 100).toFixed(0) + '% confidence' : 'semantic analysis'}) -- **Intent**: ${analysis.intent.type}${analysis.intent.variant ? ` (${analysis.intent.variant})` : ''} -- **Complexity**: ${analysis.complexity} -${analysis.cliReasoning ? `- **Reasoning**: ${analysis.cliReasoning}` : ''} -`) - } else { - console.log(` -### Classification Summary -- **Source**: Rule-Based (fast path) -- **Intent**: ${analysis.intent.type}${analysis.intent.variant ? ` (${analysis.intent.variant})` : ''} -- **Complexity**: ${analysis.complexity} -`) - } - - // Phase 2: Select chain + + // Extract dimensions + const dimensions = extractDimensions(userInput) + dimensions.clarity_score = calculateClarityScore(userInput, dimensions) + dimensions.missing_dimensions = identifyMissing(dimensions) + + console.log(`### Classification\n**Source**: ${analysis.source} | **Intent**: ${analysis.intent.type}${analysis.intent.variant ? ` (${analysis.intent.variant})` : ''} | **Complexity**: ${analysis.complexity} | **Clarity**: ${dimensions.clarity_score}/3`) + + // Phase 1.75: Clarification + const { dimensions: refined } = await clarifyRequirement(analysis, dimensions) + analysis.dimensions = refined + + // Phase 2: Chain Selection const selectedChain = selectChain(analysis) - - // Phase 2.5: CLI-Assisted Action Planning (for high complexity) - const planningResult = await cliAssistedPlanning(analysis, selectedChain, intentRules) - const optimizedChain = planningResult.chain - - // Display planning result if CLI was used - if (planningResult.source === 'cli-planned' || planningResult.source === 'cli-reviewed') { - console.log(` -### Planning Summary -- **Source**: CLI-Assisted -${planningResult.reasoning ? `- **Reasoning**: ${planningResult.reasoning}` : ''} -${planningResult.risks && planningResult.risks.length > 0 ? `- **Identified Risks**: ${planningResult.risks.join(', ')}` : ''} -${planningResult.suggestions && planningResult.suggestions.length > 0 ? `- **Suggestions**: ${planningResult.suggestions.join(', ')}` : ''} -`) - } - - // Phase 3: Confirm (for complex workflows) + + // Phase 2.5: CLI Planning + const { chain: optimizedChain, source: planSource, reasoning, risks } = await cliAssistedPlanning(analysis, selectedChain, intentRules) + if (planSource?.includes('cli')) console.log(`### Planning\n${reasoning || ''}${risks?.length ? ` | Risks: ${risks.join(', ')}` : ''}`) + + // Phase 3: Confirm const confirmedChain = confirmChain(optimizedChain, analysis) - if (!confirmedChain) { - console.log('Manual mode selected. Specify commands directly.') - return - } - - // Phase 4: Setup TODO tracking + if (!confirmedChain) { console.log('Manual mode. Specify commands directly.'); return } + + // Phase 4: Setup TODO const execution = setupTodoTracking(confirmedChain, analysis) - + // Phase 5: Execute - const result = await executeChain(execution, analysis) - - return result + return await executeChain(execution, analysis) } ``` +--- + ## Decision Matrix | Intent | Complexity | Chain | Steps | |--------|------------|-------|-------| -| bugfix (standard) | * | bugfix | lite-fix | -| bugfix (hotfix) | * | bugfix | lite-fix --hotfix | +| bugfix | * | bugfix | lite-fix | | issue | * | issue | plan → queue → execute | | exploration | * | full | brainstorm → plan → execute | -| ui (explore) | * | ui | ui-design:explore → sync → plan → execute | -| ui (imitate) | * | ui | ui-design:imitate → sync → plan → execute | +| ui | * | ui | ui-design → sync → plan → execute | | tdd | * | tdd | tdd-plan → execute → tdd-verify | | review | * | review-fix | review-session-cycle → review-fix | -| docs | low | docs | update-related | -| docs | medium+ | docs | docs → execute | -| feature | low | rapid | lite-plan → lite-execute | -| feature | medium | coupled | plan → verify → execute | -| feature | high | full | brainstorm → plan → execute | +| docs | low/medium+ | docs | update-related / docs → execute | +| feature | low/medium/high | rapid/coupled/full | lite-plan / plan → verify / brainstorm | ## Continuation Commands -After each step pause: - -| User Input | Action | -|------------|--------| -| `continue` | Execute next step | -| `skip` | Skip current step | +| Input | Action | +|-------|--------| +| `continue` | Next step | +| `skip` | Skip current | | `abort` | Stop workflow | -| `/workflow:*` | Execute specific command | -| Natural language | Re-analyze and potentially switch chains | +| `/workflow:*` | Specific command | +| Natural language | Re-analyze | diff --git a/.claude/skills/skill-tuning/SKILL.md b/.claude/skills/skill-tuning/SKILL.md index 70b312ee..7b7682d5 100644 --- a/.claude/skills/skill-tuning/SKILL.md +++ b/.claude/skills/skill-tuning/SKILL.md @@ -65,10 +65,11 @@ Based on comprehensive analysis, skill-tuning addresses **core skill issues** an | Priority | Problem | Root Cause | Solution Strategy | |----------|---------|------------|-------------------| -| **P0** | Data Flow Disruption | Scattered state, inconsistent formats | Centralized session store, transactional updates | -| **P1** | Agent Coordination | Fragile call chains, merge complexity | Dedicated orchestrator, enforced data contracts | -| **P2** | Context Explosion | Token accumulation, multi-turn bloat | Context summarization, sliding window, structured state | -| **P3** | Long-tail Forgetting | Early constraint loss | Constraint injection, checkpointing, goal alignment | +| **P0** | Authoring Principles Violation | 中间文件存储, State膨胀, 文件中转 | eliminate_intermediate_files, minimize_state, context_passing | +| **P1** | Data Flow Disruption | Scattered state, inconsistent formats | state_centralization, schema_enforcement | +| **P2** | Agent Coordination | Fragile call chains, merge complexity | error_wrapping, result_validation | +| **P3** | Context Explosion | Token accumulation, multi-turn bloat | sliding_window, context_summarization | +| **P4** | Long-tail Forgetting | Early constraint loss | constraint_injection, checkpoint_restore | ### General Optimization Areas (按需分析 via Gemini CLI) @@ -228,6 +229,11 @@ RULES: $(cat ~/.claude/workflows/cli-templates/protocols/analysis-protocol.md) | │ → Detect result passing issues │ │ → Output: agent-diagnosis.json │ ├─────────────────────────────────────────────────────────────────────────────┤ +│ action-diagnose-docs: Documentation Structure Analysis (Optional) │ +│ → Detect definition duplicates across files │ +│ → Detect conflicting definitions │ +│ → Output: docs-diagnosis.json │ +├─────────────────────────────────────────────────────────────────────────────┤ │ action-generate-report: Consolidated Report │ │ → Merge all diagnosis results │ │ → Prioritize issues by severity │ @@ -275,7 +281,8 @@ Bash(`mkdir -p "${workDir}/fixes"`); │ ├── context-diagnosis.json # Context explosion analysis │ ├── memory-diagnosis.json # Long-tail forgetting analysis │ ├── dataflow-diagnosis.json # Data flow analysis -│ └── agent-diagnosis.json # Agent coordination analysis +│ ├── agent-diagnosis.json # Agent coordination analysis +│ └── docs-diagnosis.json # Documentation structure analysis (optional) ├── backups/ │ └── {skill-name}-backup/ # Original skill files backup ├── fixes/ @@ -287,58 +294,14 @@ Bash(`mkdir -p "${workDir}/fixes"`); ## State Schema -```typescript -interface TuningState { - status: 'pending' | 'running' | 'completed' | 'failed'; - target_skill: { - name: string; - path: string; - execution_mode: 'sequential' | 'autonomous'; - }; - user_issue_description: string; - diagnosis: { - context: DiagnosisResult | null; - memory: DiagnosisResult | null; - dataflow: DiagnosisResult | null; - agent: DiagnosisResult | null; - }; - issues: Issue[]; - proposed_fixes: Fix[]; - applied_fixes: AppliedFix[]; - iteration_count: number; - max_iterations: number; - quality_score: number; - completed_actions: string[]; - current_action: string | null; - errors: Error[]; - error_count: number; -} +详细状态结构定义请参阅 [phases/state-schema.md](phases/state-schema.md)。 -interface DiagnosisResult { - status: 'completed' | 'skipped'; - issues_found: number; - severity: 'critical' | 'high' | 'medium' | 'low' | 'none'; - details: any; -} - -interface Issue { - id: string; - type: 'context_explosion' | 'memory_loss' | 'dataflow_break' | 'agent_failure'; - severity: 'critical' | 'high' | 'medium' | 'low'; - location: string; - description: string; - evidence: string[]; -} - -interface Fix { - id: string; - issue_id: string; - strategy: string; - description: string; - changes: FileChange[]; - risk: 'low' | 'medium' | 'high'; -} -``` +核心状态字段: +- `status`: 工作流状态 (pending/running/completed/failed) +- `target_skill`: 目标 skill 信息 +- `diagnosis`: 各维度诊断结果 +- `issues`: 发现的问题列表 +- `proposed_fixes`: 建议的修复方案 ## Reference Documents @@ -352,6 +315,7 @@ interface Fix { | [phases/actions/action-diagnose-memory.md](phases/actions/action-diagnose-memory.md) | Long-tail forgetting diagnosis | | [phases/actions/action-diagnose-dataflow.md](phases/actions/action-diagnose-dataflow.md) | Data flow diagnosis | | [phases/actions/action-diagnose-agent.md](phases/actions/action-diagnose-agent.md) | Agent coordination diagnosis | +| [phases/actions/action-diagnose-docs.md](phases/actions/action-diagnose-docs.md) | Documentation structure diagnosis | | [phases/actions/action-generate-report.md](phases/actions/action-generate-report.md) | Report generation | | [phases/actions/action-propose-fixes.md](phases/actions/action-propose-fixes.md) | Fix proposal | | [phases/actions/action-apply-fix.md](phases/actions/action-apply-fix.md) | Fix application | diff --git a/.claude/skills/skill-tuning/phases/actions/action-analyze-requirements.md b/.claude/skills/skill-tuning/phases/actions/action-analyze-requirements.md index ea36a35c..8102243d 100644 --- a/.claude/skills/skill-tuning/phases/actions/action-analyze-requirements.md +++ b/.claude/skills/skill-tuning/phases/actions/action-analyze-requirements.md @@ -85,62 +85,55 @@ RULES: ### Phase 2: Spec 匹配 -基于 `specs/dimension-mapping.md` 规则为每个维度匹配检测模式和修复策略: +基于 `specs/category-mappings.json` 配置为每个维度匹配检测模式和修复策略: ```javascript +// 加载集中式映射配置 +const mappings = JSON.parse(Read('specs/category-mappings.json')); + function matchSpecs(dimensions) { - // 加载映射规则 - const mappingRules = loadMappingRules(); - return dimensions.map(dim => { // 匹配 taxonomy pattern - const taxonomyMatch = findTaxonomyMatch(dim.inferred_category, mappingRules); - + const taxonomyMatch = findTaxonomyMatch(dim.inferred_category); + // 匹配 strategy - const strategyMatch = findStrategyMatch(dim.inferred_category, mappingRules); - + const strategyMatch = findStrategyMatch(dim.inferred_category); + // 判断是否满足(核心标准:有修复策略) const hasFix = strategyMatch !== null && strategyMatch.strategies.length > 0; - + return { dimension_id: dim.id, taxonomy_match: taxonomyMatch, strategy_match: strategyMatch, has_fix: hasFix, - needs_gemini_analysis: taxonomyMatch === null // 无内置检测时需要 Gemini 深度分析 + needs_gemini_analysis: taxonomyMatch === null || mappings.categories[dim.inferred_category]?.needs_gemini_analysis }; }); } -function findTaxonomyMatch(category, rules) { - const patternMapping = { - 'context_explosion': { category: 'context_explosion', pattern_ids: ['CTX-001', 'CTX-002', 'CTX-003', 'CTX-004', 'CTX-005'], severity_hint: 'high' }, - 'memory_loss': { category: 'memory_loss', pattern_ids: ['MEM-001', 'MEM-002', 'MEM-003', 'MEM-004', 'MEM-005'], severity_hint: 'high' }, - 'dataflow_break': { category: 'dataflow_break', pattern_ids: ['DF-001', 'DF-002', 'DF-003', 'DF-004', 'DF-005'], severity_hint: 'critical' }, - 'agent_failure': { category: 'agent_failure', pattern_ids: ['AGT-001', 'AGT-002', 'AGT-003', 'AGT-004', 'AGT-005', 'AGT-006'], severity_hint: 'high' }, - 'performance': { category: 'performance', pattern_ids: ['CTX-001', 'CTX-003'], severity_hint: 'medium' }, - 'error_handling': { category: 'error_handling', pattern_ids: ['AGT-001', 'AGT-002'], severity_hint: 'medium' } +function findTaxonomyMatch(category) { + const config = mappings.categories[category]; + if (!config || config.pattern_ids.length === 0) return null; + + return { + category: category, + pattern_ids: config.pattern_ids, + severity_hint: config.severity_hint }; - - return patternMapping[category] || null; } -function findStrategyMatch(category, rules) { - const strategyMapping = { - 'context_explosion': { strategies: ['sliding_window', 'path_reference', 'context_summarization', 'structured_state'], risk_levels: ['low', 'low', 'low', 'medium'] }, - 'memory_loss': { strategies: ['constraint_injection', 'state_constraints_field', 'checkpoint_restore', 'goal_embedding'], risk_levels: ['low', 'low', 'low', 'medium'] }, - 'dataflow_break': { strategies: ['state_centralization', 'schema_enforcement', 'field_normalization'], risk_levels: ['medium', 'low', 'low'] }, - 'agent_failure': { strategies: ['error_wrapping', 'result_validation', 'flatten_nesting'], risk_levels: ['low', 'low', 'medium'] }, - 'prompt_quality': { strategies: ['structured_prompt', 'output_schema', 'grounding_context', 'format_enforcement'], risk_levels: ['low', 'low', 'medium', 'low'] }, - 'architecture': { strategies: ['phase_decomposition', 'interface_contracts', 'plugin_architecture'], risk_levels: ['medium', 'medium', 'high'] }, - 'performance': { strategies: ['token_budgeting', 'parallel_execution', 'result_caching', 'lazy_loading'], risk_levels: ['low', 'low', 'low', 'low'] }, - 'error_handling': { strategies: ['graceful_degradation', 'error_propagation', 'structured_logging'], risk_levels: ['low', 'low', 'low'] }, - 'output_quality': { strategies: ['quality_gates', 'output_validation', 'template_enforcement'], risk_levels: ['low', 'low', 'low'] }, - 'user_experience': { strategies: ['progress_tracking', 'status_communication', 'interactive_checkpoints'], risk_levels: ['low', 'low', 'low'] } +function findStrategyMatch(category) { + const config = mappings.categories[category]; + if (!config) { + // Fallback to custom from config + return mappings.fallback; + } + + return { + strategies: config.strategies, + risk_levels: config.risk_levels }; - - // Fallback to custom - return strategyMapping[category] || { strategies: ['custom'], risk_levels: ['medium'] }; } ``` @@ -224,11 +217,10 @@ function detectAmbiguities(dimensions, specMatches) { } function suggestInterpretations(dim) { - // 基于关键词推荐可能的解释 - const categories = [ - 'context_explosion', 'memory_loss', 'dataflow_break', 'agent_failure', - 'prompt_quality', 'architecture', 'performance', 'error_handling' - ]; + // 基于 mappings 配置推荐可能的解释 + const categories = Object.keys(mappings.categories).filter( + cat => cat !== 'authoring_principles_violation' // 排除内部检测类别 + ); return categories.slice(0, 4); // 返回最常见的 4 个作为选项 } @@ -240,12 +232,10 @@ function hasConflictingKeywords(keywords) { } function getKeywordCategoryHint(keyword) { + // 从 mappings.keywords 构建查找表(合并中英文关键词) const keywordMap = { - '慢': 'performance', 'slow': 'performance', - '遗忘': 'memory_loss', 'forget': 'memory_loss', - '状态': 'dataflow_break', 'state': 'dataflow_break', - 'agent': 'agent_failure', '失败': 'agent_failure', - 'token': 'context_explosion', '上下文': 'context_explosion' + ...mappings.keywords.chinese, + ...mappings.keywords.english }; return keywordMap[keyword.toLowerCase()]; } @@ -281,33 +271,13 @@ async function handleAmbiguities(ambiguities, dimensions) { } function getCategoryLabel(category) { - const labels = { - 'context_explosion': '上下文膨胀', - 'memory_loss': '指令遗忘', - 'dataflow_break': '数据流问题', - 'agent_failure': 'Agent 协调问题', - 'prompt_quality': '提示词质量', - 'architecture': '架构问题', - 'performance': '性能问题', - 'error_handling': '错误处理', - 'custom': '其他问题' - }; - return labels[category] || category; + // 从 mappings 配置加载标签 + return mappings.category_labels_chinese[category] || category; } function getCategoryDescription(category) { - const descriptions = { - 'context_explosion': 'Token 累积导致上下文过大', - 'memory_loss': '早期指令或约束在后期丢失', - 'dataflow_break': '状态数据在阶段间不一致', - 'agent_failure': '子 Agent 调用失败或结果异常', - 'prompt_quality': '提示词模糊导致输出不稳定', - 'architecture': '阶段划分或模块结构不合理', - 'performance': '执行慢或 Token 消耗高', - 'error_handling': '错误恢复机制不完善', - 'custom': '需要自定义分析的问题' - }; - return descriptions[category] || '需要进一步分析'; + // 从 mappings 配置加载描述 + return mappings.category_descriptions[category] || 'Requires further analysis'; } ``` diff --git a/.claude/skills/skill-tuning/phases/actions/action-diagnose-docs.md b/.claude/skills/skill-tuning/phases/actions/action-diagnose-docs.md new file mode 100644 index 00000000..f76f46e1 --- /dev/null +++ b/.claude/skills/skill-tuning/phases/actions/action-diagnose-docs.md @@ -0,0 +1,299 @@ +# Action: Diagnose Documentation Structure + +检测目标 skill 中的文档冗余和冲突问题。 + +## Purpose + +- 检测重复定义(State Schema、映射表、类型定义等) +- 检测冲突定义(优先级定义不一致、实现与文档漂移等) +- 生成合并和解决冲突的建议 + +## Preconditions + +- [ ] `state.status === 'running'` +- [ ] `state.target_skill !== null` +- [ ] `!state.diagnosis.docs` +- [ ] 用户指定 focus_areas 包含 'docs' 或 'all',或需要全面诊断 + +## Detection Patterns + +### DOC-RED-001: 核心定义重复 + +检测 State Schema、核心接口等在多处定义: + +```javascript +async function detectDefinitionDuplicates(skillPath) { + const patterns = [ + { name: 'state_schema', regex: /interface\s+(TuningState|State)\s*\{/g }, + { name: 'fix_strategy', regex: /type\s+FixStrategy\s*=/g }, + { name: 'issue_type', regex: /type:\s*['"]?(context_explosion|memory_loss|dataflow_break)/g } + ]; + + const files = Glob('**/*.md', { cwd: skillPath }); + const duplicates = []; + + for (const pattern of patterns) { + const matches = []; + for (const file of files) { + const content = Read(`${skillPath}/${file}`); + if (pattern.regex.test(content)) { + matches.push({ file, pattern: pattern.name }); + } + } + if (matches.length > 1) { + duplicates.push({ + type: pattern.name, + files: matches.map(m => m.file), + severity: 'high' + }); + } + } + + return duplicates; +} +``` + +### DOC-RED-002: 硬编码配置重复 + +检测 action 文件中硬编码与 spec 文档的重复: + +```javascript +async function detectHardcodedDuplicates(skillPath) { + const actionFiles = Glob('phases/actions/*.md', { cwd: skillPath }); + const specFiles = Glob('specs/*.md', { cwd: skillPath }); + + const duplicates = []; + + for (const actionFile of actionFiles) { + const content = Read(`${skillPath}/${actionFile}`); + + // 检测硬编码的映射对象 + const hardcodedPatterns = [ + /const\s+\w*[Mm]apping\s*=\s*\{/g, + /patternMapping\s*=\s*\{/g, + /strategyMapping\s*=\s*\{/g + ]; + + for (const pattern of hardcodedPatterns) { + if (pattern.test(content)) { + duplicates.push({ + type: 'hardcoded_mapping', + file: actionFile, + description: '硬编码映射可能与 specs/ 中的定义重复', + severity: 'high' + }); + } + } + } + + return duplicates; +} +``` + +### DOC-CON-001: 优先级定义冲突 + +检测 P0-P3 等优先级在不同文件中的定义不一致: + +```javascript +async function detectPriorityConflicts(skillPath) { + const files = Glob('**/*.md', { cwd: skillPath }); + const priorityDefs = {}; + + const priorityPattern = /\*\*P(\d+)\*\*[:\s]+([^\|]+)/g; + + for (const file of files) { + const content = Read(`${skillPath}/${file}`); + let match; + while ((match = priorityPattern.exec(content)) !== null) { + const priority = `P${match[1]}`; + const definition = match[2].trim(); + + if (!priorityDefs[priority]) { + priorityDefs[priority] = []; + } + priorityDefs[priority].push({ file, definition }); + } + } + + const conflicts = []; + for (const [priority, defs] of Object.entries(priorityDefs)) { + const uniqueDefs = [...new Set(defs.map(d => d.definition))]; + if (uniqueDefs.length > 1) { + conflicts.push({ + key: priority, + definitions: defs, + severity: 'critical' + }); + } + } + + return conflicts; +} +``` + +### DOC-CON-002: 实现与文档漂移 + +检测硬编码与文档表格的不一致: + +```javascript +async function detectImplementationDrift(skillPath) { + // 比较 category-mappings.json 与 specs/*.md 中的表格 + const mappingsFile = `${skillPath}/specs/category-mappings.json`; + + if (!fileExists(mappingsFile)) { + return []; // 无集中配置,跳过 + } + + const mappings = JSON.parse(Read(mappingsFile)); + const conflicts = []; + + // 与 dimension-mapping.md 对比 + const dimMapping = Read(`${skillPath}/specs/dimension-mapping.md`); + + for (const [category, config] of Object.entries(mappings.categories)) { + // 检查策略是否在文档中提及 + for (const strategy of config.strategies || []) { + if (!dimMapping.includes(strategy)) { + conflicts.push({ + type: 'mapping', + key: `${category}.strategies`, + issue: `策略 ${strategy} 在 JSON 中定义但未在文档中提及` + }); + } + } + } + + return conflicts; +} +``` + +## Execution + +```javascript +async function executeDiagnosis(state, workDir) { + console.log('=== Diagnosing Documentation Structure ==='); + + const skillPath = state.target_skill.path; + const issues = []; + + // 1. 检测冗余 + const definitionDups = await detectDefinitionDuplicates(skillPath); + const hardcodedDups = await detectHardcodedDuplicates(skillPath); + + for (const dup of [...definitionDups, ...hardcodedDups]) { + issues.push({ + id: `DOC-RED-${issues.length + 1}`, + type: 'doc_redundancy', + severity: dup.severity, + location: { files: dup.files || [dup.file] }, + description: dup.description || `${dup.type} 在多处定义`, + evidence: dup.files || [dup.file], + root_cause: '缺乏单一真相来源', + impact: '维护困难,易产生不一致', + suggested_fix: 'consolidate_to_ssot' + }); + } + + // 2. 检测冲突 + const priorityConflicts = await detectPriorityConflicts(skillPath); + const driftConflicts = await detectImplementationDrift(skillPath); + + for (const conflict of priorityConflicts) { + issues.push({ + id: `DOC-CON-${issues.length + 1}`, + type: 'doc_conflict', + severity: 'critical', + location: { files: conflict.definitions.map(d => d.file) }, + description: `${conflict.key} 在不同文件中定义不一致`, + evidence: conflict.definitions.map(d => `${d.file}: ${d.definition}`), + root_cause: '定义更新后未同步', + impact: '行为不可预测', + suggested_fix: 'reconcile_conflicting_definitions' + }); + } + + // 3. 生成报告 + const severity = issues.some(i => i.severity === 'critical') ? 'critical' : + issues.some(i => i.severity === 'high') ? 'high' : + issues.length > 0 ? 'medium' : 'none'; + + const result = { + status: 'completed', + issues_found: issues.length, + severity: severity, + execution_time_ms: Date.now() - startTime, + details: { + patterns_checked: ['DOC-RED-001', 'DOC-RED-002', 'DOC-CON-001', 'DOC-CON-002'], + patterns_matched: issues.map(i => i.id.split('-').slice(0, 2).join('-')), + evidence: issues.flatMap(i => i.evidence), + recommendations: generateRecommendations(issues) + }, + redundancies: issues.filter(i => i.type === 'doc_redundancy'), + conflicts: issues.filter(i => i.type === 'doc_conflict') + }; + + // 写入诊断结果 + Write(`${workDir}/diagnosis/docs-diagnosis.json`, JSON.stringify(result, null, 2)); + + return { + stateUpdates: { + 'diagnosis.docs': result, + issues: [...state.issues, ...issues] + }, + outputFiles: [`${workDir}/diagnosis/docs-diagnosis.json`], + summary: `文档诊断完成:发现 ${issues.length} 个问题 (${severity})` + }; +} + +function generateRecommendations(issues) { + const recommendations = []; + + if (issues.some(i => i.type === 'doc_redundancy')) { + recommendations.push('使用 consolidate_to_ssot 策略合并重复定义'); + recommendations.push('考虑创建 specs/category-mappings.json 集中管理配置'); + } + + if (issues.some(i => i.type === 'doc_conflict')) { + recommendations.push('使用 reconcile_conflicting_definitions 策略解决冲突'); + recommendations.push('建立文档同步检查机制'); + } + + return recommendations; +} +``` + +## Output + +### State Updates + +```javascript +{ + stateUpdates: { + 'diagnosis.docs': { + status: 'completed', + issues_found: N, + severity: 'critical|high|medium|low|none', + redundancies: [...], + conflicts: [...] + }, + issues: [...existingIssues, ...newIssues] + } +} +``` + +### Output Files + +- `${workDir}/diagnosis/docs-diagnosis.json` - 完整诊断结果 + +## Error Handling + +| Error | Recovery | +|-------|----------| +| 文件读取失败 | 记录警告,继续处理其他文件 | +| 正则匹配超时 | 跳过该模式,记录 skipped | +| JSON 解析失败 | 跳过配置对比,仅进行模式检测 | + +## Next Actions + +- 如果发现 critical 问题 → 优先进入 action-propose-fixes +- 如果无问题 → 继续下一个诊断或 action-generate-report diff --git a/.claude/skills/skill-tuning/phases/orchestrator.md b/.claude/skills/skill-tuning/phases/orchestrator.md index 1b8ed36c..4319f4a6 100644 --- a/.claude/skills/skill-tuning/phases/orchestrator.md +++ b/.claude/skills/skill-tuning/phases/orchestrator.md @@ -93,7 +93,7 @@ function selectNextAction(state) { } // 4. Run diagnosis in order (only if not completed) - const diagnosisOrder = ['context', 'memory', 'dataflow', 'agent']; + const diagnosisOrder = ['context', 'memory', 'dataflow', 'agent', 'docs']; for (const diagType of diagnosisOrder) { if (state.diagnosis[diagType] === null) { @@ -101,6 +101,10 @@ function selectNextAction(state) { if (!state.focus_areas.length || state.focus_areas.includes(diagType)) { return `action-diagnose-${diagType}`; } + // For docs diagnosis, also check 'all' focus_area + if (diagType === 'docs' && state.focus_areas.includes('all')) { + return 'action-diagnose-docs'; + } } } @@ -175,7 +179,7 @@ function shouldTriggerGeminiAnalysis(state) { } // 标准诊断完成但问题未得到解决,需要深度分析 - const diagnosisComplete = ['context', 'memory', 'dataflow', 'agent'].every( + const diagnosisComplete = ['context', 'memory', 'dataflow', 'agent', 'docs'].every( d => state.diagnosis[d] !== null ); if (diagnosisComplete && @@ -318,6 +322,7 @@ After completing the action: | [action-diagnose-memory](actions/action-diagnose-memory.md) | Analyze long-tail forgetting | status === 'running' | Sets diagnosis.memory | | [action-diagnose-dataflow](actions/action-diagnose-dataflow.md) | Analyze data flow issues | status === 'running' | Sets diagnosis.dataflow | | [action-diagnose-agent](actions/action-diagnose-agent.md) | Analyze agent coordination | status === 'running' | Sets diagnosis.agent | +| [action-diagnose-docs](actions/action-diagnose-docs.md) | Analyze documentation structure | status === 'running', focus includes 'docs' | Sets diagnosis.docs | | [action-gemini-analysis](actions/action-gemini-analysis.md) | Deep analysis via Gemini CLI | User request OR critical issues | Sets gemini_analysis, adds issues | | [action-generate-report](actions/action-generate-report.md) | Generate consolidated report | All diagnoses complete | Creates tuning-report.md | | [action-propose-fixes](actions/action-propose-fixes.md) | Generate fix proposals | Report generated, issues > 0 | Sets proposed_fixes | diff --git a/.claude/skills/skill-tuning/phases/state-schema.md b/.claude/skills/skill-tuning/phases/state-schema.md index bf344a9d..14e02709 100644 --- a/.claude/skills/skill-tuning/phases/state-schema.md +++ b/.claude/skills/skill-tuning/phases/state-schema.md @@ -30,6 +30,7 @@ interface TuningState { memory: DiagnosisResult | null; dataflow: DiagnosisResult | null; agent: DiagnosisResult | null; + docs: DocsDiagnosisResult | null; // 文档结构诊断 }; // === Issues Found === @@ -138,6 +139,33 @@ interface DiagnosisResult { }; } +interface DocsDiagnosisResult extends DiagnosisResult { + redundancies: Redundancy[]; + conflicts: Conflict[]; +} + +interface Redundancy { + id: string; // e.g., "DOC-RED-001" + type: 'state_schema' | 'strategy_mapping' | 'type_definition' | 'other'; + files: string[]; // 涉及的文件列表 + description: string; // 冗余描述 + severity: 'high' | 'medium' | 'low'; + merge_suggestion: string; // 合并建议 +} + +interface Conflict { + id: string; // e.g., "DOC-CON-001" + type: 'priority' | 'mapping' | 'definition'; + files: string[]; // 涉及的文件列表 + key: string; // 冲突的键/概念 + definitions: { + file: string; + value: string; + location?: string; + }[]; + resolution_suggestion: string; // 解决建议 +} + interface Evidence { file: string; line?: number; @@ -241,7 +269,8 @@ interface ErrorEntry { "context": null, "memory": null, "dataflow": null, - "agent": null + "agent": null, + "docs": null }, "issues": [], "issues_by_severity": { diff --git a/.claude/skills/skill-tuning/specs/category-mappings.json b/.claude/skills/skill-tuning/specs/category-mappings.json new file mode 100644 index 00000000..f05960b8 --- /dev/null +++ b/.claude/skills/skill-tuning/specs/category-mappings.json @@ -0,0 +1,263 @@ +{ + "version": "1.0.0", + "description": "Centralized category mappings for skill-tuning analysis and fix proposal", + "categories": { + "authoring_principles_violation": { + "pattern_ids": ["APV-001", "APV-002", "APV-003", "APV-004", "APV-005", "APV-006"], + "severity_hint": "critical", + "strategies": ["eliminate_intermediate_files", "minimize_state", "context_passing"], + "risk_levels": ["low", "low", "low"], + "detection_focus": "Intermediate files, state bloat, file relay patterns", + "priority_order": [1, 2, 3] + }, + "context_explosion": { + "pattern_ids": ["CTX-001", "CTX-002", "CTX-003", "CTX-004", "CTX-005"], + "severity_hint": "high", + "strategies": ["sliding_window", "path_reference", "context_summarization", "structured_state"], + "risk_levels": ["low", "low", "low", "medium"], + "detection_focus": "Token accumulation, content passing patterns", + "priority_order": [1, 2, 3, 4] + }, + "memory_loss": { + "pattern_ids": ["MEM-001", "MEM-002", "MEM-003", "MEM-004", "MEM-005"], + "severity_hint": "high", + "strategies": ["constraint_injection", "state_constraints_field", "checkpoint_restore", "goal_embedding"], + "risk_levels": ["low", "low", "low", "medium"], + "detection_focus": "Constraint propagation, checkpoint mechanisms", + "priority_order": [1, 2, 3, 4] + }, + "dataflow_break": { + "pattern_ids": ["DF-001", "DF-002", "DF-003", "DF-004", "DF-005"], + "severity_hint": "critical", + "strategies": ["state_centralization", "schema_enforcement", "field_normalization"], + "risk_levels": ["medium", "low", "low"], + "detection_focus": "State storage, schema validation", + "priority_order": [1, 2, 3] + }, + "agent_failure": { + "pattern_ids": ["AGT-001", "AGT-002", "AGT-003", "AGT-004", "AGT-005", "AGT-006"], + "severity_hint": "high", + "strategies": ["error_wrapping", "result_validation", "flatten_nesting"], + "risk_levels": ["low", "low", "medium"], + "detection_focus": "Error handling, result validation", + "priority_order": [1, 2, 3] + }, + "prompt_quality": { + "pattern_ids": [], + "severity_hint": "medium", + "strategies": ["structured_prompt", "output_schema", "grounding_context", "format_enforcement"], + "risk_levels": ["low", "low", "medium", "low"], + "detection_focus": null, + "needs_gemini_analysis": true, + "priority_order": [1, 2, 3, 4] + }, + "architecture": { + "pattern_ids": [], + "severity_hint": "medium", + "strategies": ["phase_decomposition", "interface_contracts", "plugin_architecture", "state_machine"], + "risk_levels": ["medium", "medium", "high", "medium"], + "detection_focus": null, + "needs_gemini_analysis": true, + "priority_order": [1, 2, 3, 4] + }, + "performance": { + "pattern_ids": ["CTX-001", "CTX-003"], + "severity_hint": "medium", + "strategies": ["token_budgeting", "parallel_execution", "result_caching", "lazy_loading"], + "risk_levels": ["low", "low", "low", "low"], + "detection_focus": "Reuses context explosion detection", + "priority_order": [1, 2, 3, 4] + }, + "error_handling": { + "pattern_ids": ["AGT-001", "AGT-002"], + "severity_hint": "medium", + "strategies": ["graceful_degradation", "error_propagation", "structured_logging", "error_context"], + "risk_levels": ["low", "low", "low", "low"], + "detection_focus": "Reuses agent failure detection", + "priority_order": [1, 2, 3, 4] + }, + "output_quality": { + "pattern_ids": [], + "severity_hint": "medium", + "strategies": ["quality_gates", "output_validation", "template_enforcement", "completeness_check"], + "risk_levels": ["low", "low", "low", "low"], + "detection_focus": null, + "needs_gemini_analysis": true, + "priority_order": [1, 2, 3, 4] + }, + "user_experience": { + "pattern_ids": [], + "severity_hint": "low", + "strategies": ["progress_tracking", "status_communication", "interactive_checkpoints", "guided_workflow"], + "risk_levels": ["low", "low", "low", "low"], + "detection_focus": null, + "needs_gemini_analysis": true, + "priority_order": [1, 2, 3, 4] + } + }, + "keywords": { + "chinese": { + "token": "context_explosion", + "上下文": "context_explosion", + "爆炸": "context_explosion", + "太长": "context_explosion", + "超限": "context_explosion", + "膨胀": "context_explosion", + "遗忘": "memory_loss", + "忘记": "memory_loss", + "指令丢失": "memory_loss", + "约束消失": "memory_loss", + "目标漂移": "memory_loss", + "状态": "dataflow_break", + "数据": "dataflow_break", + "格式": "dataflow_break", + "不一致": "dataflow_break", + "丢失": "dataflow_break", + "损坏": "dataflow_break", + "agent": "agent_failure", + "子任务": "agent_failure", + "失败": "agent_failure", + "嵌套": "agent_failure", + "调用": "agent_failure", + "协调": "agent_failure", + "慢": "performance", + "性能": "performance", + "效率": "performance", + "延迟": "performance", + "提示词": "prompt_quality", + "输出不稳定": "prompt_quality", + "幻觉": "prompt_quality", + "架构": "architecture", + "结构": "architecture", + "模块": "architecture", + "耦合": "architecture", + "扩展": "architecture", + "错误": "error_handling", + "异常": "error_handling", + "恢复": "error_handling", + "降级": "error_handling", + "崩溃": "error_handling", + "输出": "output_quality", + "质量": "output_quality", + "验证": "output_quality", + "不完整": "output_quality", + "交互": "user_experience", + "体验": "user_experience", + "进度": "user_experience", + "反馈": "user_experience", + "不清晰": "user_experience", + "中间文件": "authoring_principles_violation", + "临时文件": "authoring_principles_violation", + "文件中转": "authoring_principles_violation", + "state膨胀": "authoring_principles_violation" + }, + "english": { + "token": "context_explosion", + "context": "context_explosion", + "explosion": "context_explosion", + "overflow": "context_explosion", + "bloat": "context_explosion", + "forget": "memory_loss", + "lost": "memory_loss", + "drift": "memory_loss", + "constraint": "memory_loss", + "goal": "memory_loss", + "state": "dataflow_break", + "data": "dataflow_break", + "format": "dataflow_break", + "inconsistent": "dataflow_break", + "corrupt": "dataflow_break", + "agent": "agent_failure", + "subtask": "agent_failure", + "fail": "agent_failure", + "nested": "agent_failure", + "call": "agent_failure", + "coordinate": "agent_failure", + "slow": "performance", + "performance": "performance", + "efficiency": "performance", + "latency": "performance", + "prompt": "prompt_quality", + "unstable": "prompt_quality", + "hallucination": "prompt_quality", + "architecture": "architecture", + "structure": "architecture", + "module": "architecture", + "coupling": "architecture", + "error": "error_handling", + "exception": "error_handling", + "recovery": "error_handling", + "crash": "error_handling", + "output": "output_quality", + "quality": "output_quality", + "validation": "output_quality", + "incomplete": "output_quality", + "interaction": "user_experience", + "ux": "user_experience", + "progress": "user_experience", + "feedback": "user_experience", + "intermediate": "authoring_principles_violation", + "temp": "authoring_principles_violation", + "relay": "authoring_principles_violation" + } + }, + "category_labels": { + "context_explosion": "Context Explosion", + "memory_loss": "Long-tail Forgetting", + "dataflow_break": "Data Flow Disruption", + "agent_failure": "Agent Coordination Failure", + "prompt_quality": "Prompt Quality", + "architecture": "Architecture", + "performance": "Performance", + "error_handling": "Error Handling", + "output_quality": "Output Quality", + "user_experience": "User Experience", + "authoring_principles_violation": "Authoring Principles Violation", + "custom": "Custom" + }, + "category_labels_chinese": { + "context_explosion": "Context Explosion", + "memory_loss": "Long-tail Forgetting", + "dataflow_break": "Data Flow Disruption", + "agent_failure": "Agent Coordination Failure", + "prompt_quality": "Prompt Quality", + "architecture": "Architecture Issues", + "performance": "Performance Issues", + "error_handling": "Error Handling", + "output_quality": "Output Quality", + "user_experience": "User Experience", + "authoring_principles_violation": "Authoring Principles Violation", + "custom": "Other Issues" + }, + "category_descriptions": { + "context_explosion": "Token accumulation causing prompt size to grow unbounded", + "memory_loss": "Early instructions or constraints lost in later phases", + "dataflow_break": "State data inconsistency between phases", + "agent_failure": "Sub-agent call failures or abnormal results", + "prompt_quality": "Vague prompts causing unstable outputs", + "architecture": "Improper phase division or module structure", + "performance": "Slow execution or high token consumption", + "error_handling": "Incomplete error recovery mechanisms", + "output_quality": "Output validation or completeness issues", + "user_experience": "Interaction or feedback clarity issues", + "authoring_principles_violation": "Violation of skill authoring principles", + "custom": "Requires custom analysis" + }, + "fix_priority_order": { + "P0": ["dataflow_break", "authoring_principles_violation"], + "P1": ["agent_failure"], + "P2": ["context_explosion"], + "P3": ["memory_loss"] + }, + "cross_category_dependencies": { + "context_explosion": ["memory_loss"], + "dataflow_break": ["agent_failure"], + "agent_failure": ["context_explosion"] + }, + "fallback": { + "strategies": ["custom"], + "risk_levels": ["medium"], + "has_fix": true, + "needs_gemini_analysis": true + } +} diff --git a/.claude/skills/skill-tuning/specs/dimension-mapping.md b/.claude/skills/skill-tuning/specs/dimension-mapping.md index e7ebd7eb..6d2b39c1 100644 --- a/.claude/skills/skill-tuning/specs/dimension-mapping.md +++ b/.claude/skills/skill-tuning/specs/dimension-mapping.md @@ -29,6 +29,8 @@ | 错误, 异常, 恢复, 降级, 崩溃 | error, exception, recovery, crash | error_handling | agent_failure | | 输出, 质量, 格式, 验证, 不完整 | output, quality, validation, incomplete | output_quality | - | | 交互, 体验, 进度, 反馈, 不清晰 | interaction, ux, progress, feedback | user_experience | - | +| 重复, 冗余, 多处定义, 相同内容 | duplicate, redundant, multiple definitions | doc_redundancy | - | +| 冲突, 不一致, 定义不同, 矛盾 | conflict, inconsistent, mismatch, contradiction | doc_conflict | - | ### Matching Algorithm @@ -86,6 +88,8 @@ function matchCategory(keywords) { | error_handling | AGT-001, AGT-002 | (复用 agent 检测) | | output_quality | - | (无内置检测,需 Gemini 分析) | | user_experience | - | (无内置检测,需 Gemini 分析) | +| doc_redundancy | DOC-RED-001, DOC-RED-002, DOC-RED-003 | 重复定义检测 | +| doc_conflict | DOC-CON-001, DOC-CON-002 | 冲突定义检测 | --- @@ -101,6 +105,8 @@ function matchCategory(keywords) { | memory_loss | constraint_injection, state_constraints_field, checkpoint_restore, goal_embedding | Low-Medium | | dataflow_break | state_centralization, schema_enforcement, field_normalization | Low-Medium | | agent_failure | error_wrapping, result_validation, flatten_nesting | Low-Medium | +| doc_redundancy | consolidate_to_ssot, centralize_mapping_config | Low-Medium | +| doc_conflict | reconcile_conflicting_definitions | Low | ### Extended Categories (需 Gemini 生成策略) diff --git a/.claude/skills/skill-tuning/specs/problem-taxonomy.md b/.claude/skills/skill-tuning/specs/problem-taxonomy.md index d599e207..1490bfd7 100644 --- a/.claude/skills/skill-tuning/specs/problem-taxonomy.md +++ b/.claude/skills/skill-tuning/specs/problem-taxonomy.md @@ -156,6 +156,53 @@ Classification of skill execution issues with detection patterns and severity cr --- +### 5. Documentation Redundancy (P5) + +**Definition**: 同一定义(如 State Schema、映射表、类型定义)在多个文件中重复出现,导致维护困难和不一致风险。 + +**Root Causes**: +- 缺乏单一真相来源 (SSOT) +- 复制粘贴代替引用 +- 硬编码配置代替集中管理 + +**Detection Patterns**: + +| Pattern ID | Regex/Check | Description | +|------------|-------------|-------------| +| DOC-RED-001 | 跨文件语义比较 | 找到 State Schema 等核心概念的重复定义 | +| DOC-RED-002 | 代码块 vs 规范表对比 | action 文件中硬编码与 spec 文档的重复 | +| DOC-RED-003 | `/interface\s+(\w+)/` 同名扫描 | 多处定义的 interface/type | + +**Impact Levels**: +- **High**: 核心定义(State Schema, 映射表)重复 +- **Medium**: 类型定义重复 +- **Low**: 示例代码重复 + +--- + +### 6. Documentation Conflict (P6) + +**Definition**: 同一概念在不同文件中定义不一致,导致行为不可预测和文档误导。 + +**Root Causes**: +- 定义更新后未同步其他位置 +- 实现与文档漂移 +- 缺乏一致性校验 + +**Detection Patterns**: + +| Pattern ID | Regex/Check | Description | +|------------|-------------|-------------| +| DOC-CON-001 | 键值一致性校验 | 同一键(如优先级)在不同文件中值不同 | +| DOC-CON-002 | 实现 vs 文档对比 | 硬编码配置与文档对应项不一致 | + +**Impact Levels**: +- **Critical**: 优先级/类别定义冲突 +- **High**: 策略映射不一致 +- **Medium**: 示例与实际不符 + +--- + ## Severity Criteria ### Global Severity Matrix @@ -215,6 +262,8 @@ function calculateIssueSeverity(issue) { | Long-tail Forgetting | constraint_injection, state_constraints_field, checkpoint | 1, 2, 3 | | Data Flow Disruption | state_centralization, schema_enforcement, field_normalization | 1, 2, 3 | | Agent Coordination | error_wrapping, result_validation, flatten_nesting | 1, 2, 3 | +| **Documentation Redundancy** | consolidate_to_ssot, centralize_mapping_config | 1, 2 | +| **Documentation Conflict** | reconcile_conflicting_definitions | 1 | --- diff --git a/.claude/skills/skill-tuning/specs/tuning-strategies.md b/.claude/skills/skill-tuning/specs/tuning-strategies.md index 0130c5b8..ecfa9853 100644 --- a/.claude/skills/skill-tuning/specs/tuning-strategies.md +++ b/.claude/skills/skill-tuning/specs/tuning-strategies.md @@ -675,6 +675,144 @@ if (parsedA.needs_agent_b) { --- +## Documentation Strategies + +文档去重和冲突解决策略。 + +--- + +### Strategy: consolidate_to_ssot + +**Purpose**: 将重复定义合并到单一真相来源 (Single Source of Truth)。 + +**Implementation**: +```javascript +// 合并流程 +async function consolidateToSSOT(state, duplicates) { + // 1. 识别最完整的定义位置 + const canonical = selectCanonicalSource(duplicates); + + // 2. 确保规范位置包含完整定义 + const fullDefinition = mergeDefinitions(duplicates); + Write(canonical.file, fullDefinition); + + // 3. 替换其他位置为引用 + for (const dup of duplicates.filter(d => d.file !== canonical.file)) { + const reference = generateReference(canonical.file, dup.type); + // 例如: "详见 [state-schema.md](phases/state-schema.md)" + replaceWithReference(dup.file, dup.location, reference); + } + + return { canonical: canonical.file, removed: duplicates.length - 1 }; +} + +function selectCanonicalSource(duplicates) { + // 优先级: specs/ > phases/ > SKILL.md + const priority = ['specs/', 'phases/', 'SKILL.md']; + return duplicates.sort((a, b) => { + const aIdx = priority.findIndex(p => a.file.includes(p)); + const bIdx = priority.findIndex(p => b.file.includes(p)); + return aIdx - bIdx; + })[0]; +} +``` + +**Risk**: Low +**Verification**: +- 确认只有一处包含完整定义 +- 其他位置包含有效引用链接 + +--- + +### Strategy: centralize_mapping_config + +**Purpose**: 将硬编码配置提取到集中的 JSON 文件,代码改为加载配置。 + +**Implementation**: +```javascript +// 1. 创建集中配置文件 +const config = { + version: "1.0.0", + categories: { + context_explosion: { + pattern_ids: ["CTX-001", "CTX-002"], + strategies: ["sliding_window", "path_reference"] + } + // ... 从硬编码中提取 + } +}; +Write('specs/category-mappings.json', JSON.stringify(config, null, 2)); + +// 2. 重构代码加载配置 +// Before: +function findTaxonomyMatch(category) { + const patternMapping = { + 'context_explosion': { category: 'context_explosion', pattern_ids: [...] } + // 硬编码 + }; + return patternMapping[category]; +} + +// After: +function findTaxonomyMatch(category) { + const mappings = JSON.parse(Read('specs/category-mappings.json')); + const config = mappings.categories[category]; + if (!config) return null; + return { category, pattern_ids: config.pattern_ids, severity_hint: config.severity_hint }; +} +``` + +**Risk**: Medium (需要测试配置加载逻辑) +**Verification**: +- JSON 文件语法正确 +- 所有原硬编码的值都已迁移 +- 功能行为不变 + +--- + +### Strategy: reconcile_conflicting_definitions + +**Purpose**: 调和冲突的定义,由用户选择正确版本后统一更新。 + +**Implementation**: +```javascript +async function reconcileConflicts(conflicts) { + for (const conflict of conflicts) { + // 1. 展示冲突给用户 + const options = conflict.definitions.map(def => ({ + label: `${def.file}: ${def.value}`, + description: `来自 ${def.file}` + })); + + const choice = await AskUserQuestion({ + questions: [{ + question: `发现冲突定义: "${conflict.key}",请选择正确版本`, + header: '冲突解决', + options: options, + multiSelect: false + }] + }); + + // 2. 更新所有文件为选中的版本 + const selected = conflict.definitions[choice.index]; + for (const def of conflict.definitions) { + if (def.file !== selected.file) { + updateDefinition(def.file, conflict.key, selected.value); + } + } + } + + return { resolved: conflicts.length }; +} +``` + +**Risk**: Low (用户确认后执行) +**Verification**: +- 所有位置的定义一致 +- 无新冲突产生 + +--- + ## Strategy Selection Guide ``` @@ -735,6 +873,13 @@ Issue Type: User Experience ├── unclear status? → status_communication ├── no feedback? → interactive_checkpoints └── confusing flow? → guided_workflow + +Issue Type: Documentation Redundancy +├── 核心定义重复? → consolidate_to_ssot +└── 硬编码配置重复? → centralize_mapping_config + +Issue Type: Documentation Conflict +└── 定义不一致? → reconcile_conflicting_definitions ``` ---