mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-14 02:42:04 +08:00
- 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.
27 KiB
27 KiB
CCW Orchestrator
无状态编排器:分析输入 → 选择工作流链 → TODO 跟踪执行
Architecture
┌────────────────────────────────────────────────────────────────┐
│ 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 │
└────────────────────────────────────────────────────────────────┘
References:
- specs/requirement-analysis.md - Dimension extraction & clarity scoring
- specs/output-templates.md - Standardized output templates
CLI Enhancement Config
| 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 |
Settings in index/intent-rules.json. Fallback: gemini → qwen → rule-based.
Core Helpers
// === 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
}
}
// === 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() }
Phase 1: Input Analysis
const intentRules = JSON.parse(Read('.claude/skills/ccw/index/intent-rules.json'))
const chains = JSON.parse(Read('.claude/skills/ccw/index/workflow-chains.json'))
function analyzeInput(userInput) {
const input = userInput.trim()
// Explicit command passthrough
if (input.match(/^\/(?:workflow|issue|memory|task):/)) {
return { type: 'explicit', command: input, passthrough: true }
}
return {
type: 'natural',
text: input,
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) {
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, vc] of Object.entries(config.variants)) {
const vPatterns = vc.patterns || vc.triggers || []
if (matchesAny(text, vPatterns)) {
if (intentType === 'bugfix') {
if (matchesAny(text, config.variants.standard?.patterns || []))
return { type: intentType, variant, workflow: vc.workflow }
} else {
return { type: intentType, variant, workflow: vc.workflow }
}
}
}
if (config.variants.standard && matchesAny(text, config.variants.standard.patterns))
return { type: intentType, variant: 'standard', workflow: config.variants.standard.workflow }
}
// 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) {
if (matchesAny(text, config.patterns.batch_keywords) && matchesAny(text, config.patterns.action_keywords))
return { type: intentType, workflow: config.workflow }
}
}
return { type: 'feature' }
}
function assessComplexity(text, indicators) {
let score = 0
for (const [level, config] of Object.entries(indicators)) {
if (config.patterns) {
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'
}
function detectToolPreference(text, triggers) {
for (const [tool, config] of Object.entries(triggers)) {
if (matchesAny(text, config.explicit) || matchesAny(text, config.semantic)) return tool
}
return null
}
function calculateMatchCount(text, patterns) {
let count = 0
for (const [, config] of Object.entries(patterns)) {
if (config.variants) {
for (const [, vc] of Object.entries(config.variants)) {
if (matchesAny(text, vc.patterns || vc.triggers || [])) count++
}
}
if (config.patterns && !config.require_both && matchesAny(text, config.patterns)) count++
}
return count
}
Dimension Extraction (WHAT/WHERE/WHY/HOW)
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
},
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: []
}
}
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)))
}
function identifyMissing(d) {
const missing = []
if (!d.what.target) missing.push('what.target')
if (d.where.scope === 'unknown') missing.push('where.scope')
return missing
}
Phase 1.5: CLI-Assisted Classification
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
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
function selectChain(analysis) {
const { intent, complexity } = analysis
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]
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 }
}
Phase 2.5: CLI-Assisted Action Planning
async function cliAssistedPlanning(analysis, selectedChain, intentRules) {
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?.length > 200)
if (!shouldUseCli) return { useDefaultChain: true, chain: selectedChain }
console.log('### CLI-Assisted Action Planning\n')
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: false,
chain: { ...selectedChain, steps: parsed.modified_steps },
reasoning: parsed.reasoning, risks: parsed.risks, cliInjections: parsed.cli_injections, source: 'cli-planned'
}
}
return { useDefaultChain: true, chain: selectedChain, suggestions: parsed.suggestions, risks: parsed.risks, source: 'cli-reviewed' }
}
Phase 3: User Confirmation
function confirmChain(selectedChain, analysis) {
if (selectedChain.steps.length <= 2 && analysis.complexity === 'low') return selectedChain
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,
options: [
{ label: "Proceed", description: `Execute ${selectedChain.steps.length} steps` },
{ label: "Rapid", description: "Use lite-plan → lite-execute" },
{ label: "Full", description: "Use brainstorm → plan → execute" },
{ label: "Manual", description: "Specify commands manually" }
]
}]
})
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
function setupTodoTracking(chain, analysis) {
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})`
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
async function executeChain(execution, analysis) {
const { chain, todos } = execution
let step = 0
const timings = []
while (step < chain.steps.length) {
const s = chain.steps[step]
const start = Date.now()
// 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 ${step + 1}/${chain.steps.length}: ${s.command}`)
// 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 (r.Step === 'Skip') { timings.push('skipped'); step++; continue }
if (r.Step === 'Abort') break
}
// 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
}
step++
// Check auto_continue
if (!s.auto_continue && step < chain.steps.length) {
console.log(`\nPaused. Next: ${chain.steps[step].command}. Type "continue" to proceed.`)
break
}
}
// Final status
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: step, total: chain.steps.length, timings }
}
Main Orchestration Entry
async function ccwOrchestrate(userInput) {
console.log('## CCW Orchestrator\n')
// Phase 1: Input Analysis
const ruleBasedAnalysis = analyzeInput(userInput)
// Handle passthrough commands
if (ruleBasedAnalysis.passthrough) {
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 Classification
const analysis = await cliAssistedClassification(userInput, ruleBasedAnalysis, intentRules)
// 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 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. Specify commands directly.'); return }
// Phase 4: Setup TODO
const execution = setupTodoTracking(confirmedChain, analysis)
// Phase 5: Execute
return await executeChain(execution, analysis)
}
Decision Matrix
| Intent | Complexity | Chain | Steps |
|---|---|---|---|
| bugfix | * | bugfix | lite-fix |
| issue | * | issue | plan → queue → execute |
| exploration | * | full | brainstorm → 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/medium+ | docs | update-related / docs → execute |
| feature | low/medium/high | rapid/coupled/full | lite-plan / plan → verify / brainstorm |
Continuation Commands
| Input | Action |
|---|---|
continue |
Next step |
skip |
Skip current |
abort |
Stop workflow |
/workflow:* |
Specific command |
| Natural language | Re-analyze |