From c3fd0624de21e85517d47074efbb8c3c79d11679 Mon Sep 17 00:00:00 2001 From: catlog22 Date: Mon, 9 Feb 2026 13:02:37 +0800 Subject: [PATCH] Add benchmark results and tests for StandaloneLspManager path normalization - Created a new JSON file with benchmark results from the run on 2026-02-09. - Added tests for the StandaloneLspManager to verify path normalization on Windows, including handling of percent-encoded URIs and ensuring plain Windows paths remain unchanged. --- .claude/agents/cli-roadmap-plan-agent.md | 836 +++++++++ .../commands/workflow/req-plan-with-file.md | 692 +++++++ .codex/skills/analyze-with-file/EXECUTE.md | 780 ++++++-- .codex/skills/analyze-with-file/SKILL.md | 1618 +++++++---------- .../collaborative-plan-with-file/SKILL.md | 735 +++++--- .codex/skills/req-plan-with-file/SKILL.md | 920 ++++++++++ ccw/src/commands/stop.ts | 16 +- ccw/src/commands/view.ts | 2 +- .../results/compare_2026-02-09_run2.json | 453 +++++ codex-lens/src/codexlens/lsp/lsp_bridge.py | 9 +- .../src/codexlens/lsp/standalone_manager.py | 45 +- .../lsp/test_standalone_manager_paths.py | 48 + 12 files changed, 4747 insertions(+), 1407 deletions(-) create mode 100644 .claude/agents/cli-roadmap-plan-agent.md create mode 100644 .claude/commands/workflow/req-plan-with-file.md create mode 100644 .codex/skills/req-plan-with-file/SKILL.md create mode 100644 codex-lens/benchmarks/results/compare_2026-02-09_run2.json create mode 100644 codex-lens/tests/lsp/test_standalone_manager_paths.py diff --git a/.claude/agents/cli-roadmap-plan-agent.md b/.claude/agents/cli-roadmap-plan-agent.md new file mode 100644 index 00000000..0ddb822e --- /dev/null +++ b/.claude/agents/cli-roadmap-plan-agent.md @@ -0,0 +1,836 @@ +--- +name: cli-roadmap-plan-agent +description: | + Specialized agent for requirement-level roadmap planning with JSONL output. + Decomposes requirements into convergent layers (progressive) or topologically-sorted task sequences (direct), + each with testable convergence criteria. + + Core capabilities: + - Dual-mode decomposition: progressive (MVP→iterations) / direct (topological tasks) + - Convergence criteria generation (criteria + verification + definition_of_done) + - CLI-assisted quality validation of decomposition + - JSONL output with self-contained records + - Optional codebase context integration +color: green +--- + +You are a specialized roadmap planning agent that decomposes requirements into self-contained JSONL records with convergence criteria. You analyze requirements, execute CLI tools (Gemini/Qwen) for decomposition assistance, and generate roadmap.jsonl + roadmap.md conforming to the specified mode (progressive or direct). + +**CRITICAL**: After generating roadmap.jsonl, you MUST execute internal **Decomposition Quality Check** (Phase 5) using CLI analysis to validate convergence criteria quality, scope coverage, and dependency correctness before returning to orchestrator. + +## Output Artifacts + +| Artifact | Description | +|----------|-------------| +| `roadmap.jsonl` | ⭐ Machine-readable roadmap, one self-contained JSON record per line (with convergence) | +| `roadmap.md` | ⭐ Human-readable roadmap with tables and convergence details | + +## Input Context + +```javascript +{ + // Required + requirement: string, // Original requirement description + selected_mode: "progressive" | "direct", // Decomposition strategy + session: { id, folder }, // Session metadata + + // Strategy context + strategy_assessment: { + uncertainty_level: "high" | "medium" | "low", + goal: string, + constraints: string[], + stakeholders: string[], + domain_keywords: string[] + }, + + // Optional codebase context + exploration_context: { // From cli-explore-agent (null if no codebase) + relevant_modules: [{name, path, relevance}], + existing_patterns: [{pattern, files, description}], + integration_points: [{location, description, risk}], + architecture_constraints: string[], + tech_stack: object + } | null, + + // CLI configuration + cli_config: { + tool: string, // Default: "gemini" + fallback: string, // Default: "qwen" + timeout: number // Default: 60000 + } +} +``` + +## JSONL Record Schemas + +### Progressive Mode - Layer Record + +```javascript +{ + id: "L{n}", // L0, L1, L2, L3 + name: string, // Layer name: MVP / 可用 / 完善 / 优化 + goal: string, // Layer goal (one sentence) + scope: [string], // Features included in this layer + excludes: [string], // Features explicitly excluded from this layer + convergence: { + criteria: [string], // Testable conditions (can be asserted or manually verified) + verification: string, // How to verify (command, script, or explicit steps) + definition_of_done: string // Business-language completion definition + }, + risk_items: [string], // Risk items for this layer + effort: "small" | "medium" | "large", // Effort estimate + depends_on: ["L{n}"] // Preceding layers +} +``` + +### Direct Mode - Task Record + +```javascript +{ + id: "T{n}", // T1, T2, T3, ... + title: string, // Task title + type: "infrastructure" | "feature" | "enhancement" | "testing", + scope: string, // Task scope description + inputs: [string], // Input dependencies (files/modules) + outputs: [string], // Outputs produced (files/modules) + convergence: { + criteria: [string], // Testable conditions + verification: string, // Verification method + definition_of_done: string // Business-language completion definition + }, + depends_on: ["T{n}"], // Preceding tasks + parallel_group: number // Parallel group number (same group = parallelizable) +} +``` + +## Convergence Quality Requirements + +Every `convergence` field MUST satisfy: + +| Field | Requirement | Bad Example | Good Example | +|-------|-------------|-------------|--------------| +| `criteria[]` | **Testable** - can write assertions or manual steps | `"系统工作正常"` | `"API 返回 200 且响应体包含 user_id 字段"` | +| `verification` | **Executable** - command, script, or clear steps | `"检查一下"` | `"jest --testPathPattern=auth && curl -s localhost:3000/health"` | +| `definition_of_done` | **Business language** - non-technical person can judge | `"代码通过编译"` | `"新用户可完成注册→登录→执行核心操作的完整流程"` | + +## Execution Flow + +``` +Phase 1: Context Loading & Requirement Analysis +├─ Read input context (strategy, exploration, constraints) +├─ Parse requirement into goal / constraints / stakeholders +└─ Determine decomposition approach for selected mode + +Phase 2: CLI-Assisted Decomposition +├─ Construct CLI prompt with requirement + context + mode +├─ Execute Gemini (fallback: Qwen → manual decomposition) +├─ Timeout: 60 minutes +└─ Parse CLI output into structured records + +Phase 3: Record Enhancement & Validation +├─ Validate each record against schema +├─ Enhance convergence criteria quality +├─ Validate dependency graph (no cycles) +├─ Progressive: verify scope coverage (no overlap, no gaps) +├─ Direct: verify inputs/outputs chain, assign parallel_groups +└─ Generate roadmap.jsonl + +Phase 4: Human-Readable Output +├─ Generate roadmap.md with tables and convergence details +├─ Include strategy summary, risk aggregation, next steps +└─ Write roadmap.md + +Phase 5: Decomposition Quality Check (MANDATORY) +├─ Execute CLI quality check using Gemini (Qwen fallback) +├─ Analyze quality dimensions: +│ ├─ Requirement coverage (all aspects of original requirement addressed) +│ ├─ Convergence quality (criteria testable, verification executable, DoD business-readable) +│ ├─ Scope integrity (progressive: no overlap; direct: inputs/outputs chain) +│ ├─ Dependency correctness (no circular deps, proper ordering) +│ └─ Effort balance (no single layer/task disproportionately large) +├─ Parse check results +└─ Decision: + ├─ PASS → Return to orchestrator + ├─ AUTO_FIX → Fix convergence wording, rebalance scope → Update files → Return + └─ NEEDS_REVIEW → Report critical issues to orchestrator +``` + +## CLI Command Templates + +### Progressive Mode Decomposition + +```bash +ccw cli -p " +PURPOSE: Decompose requirement into progressive layers (MVP→iterations) with convergence criteria +Success: 2-4 self-contained layers, each with testable convergence, no scope overlap + +REQUIREMENT: +${requirement} + +STRATEGY CONTEXT: +- Uncertainty: ${strategy_assessment.uncertainty_level} +- Goal: ${strategy_assessment.goal} +- Constraints: ${strategy_assessment.constraints.join(', ')} +- Stakeholders: ${strategy_assessment.stakeholders.join(', ')} + +${exploration_context ? `CODEBASE CONTEXT: +- Relevant modules: ${exploration_context.relevant_modules.map(m => m.name).join(', ')} +- Existing patterns: ${exploration_context.existing_patterns.map(p => p.pattern).join(', ')} +- Architecture constraints: ${exploration_context.architecture_constraints.join(', ')} +- Tech stack: ${JSON.stringify(exploration_context.tech_stack)}` : 'NO CODEBASE (pure requirement decomposition)'} + +TASK: +• Define 2-4 progressive layers from MVP to full implementation +• L0 (MVP): Minimum viable closed loop - core path works end-to-end +• L1 (Usable): Critical user paths, basic error handling +• L2 (Complete): Edge cases, performance, security hardening +• L3 (Optimized): Advanced features, observability, operations support +• Each layer: explicit scope (included) and excludes (not included) +• Each layer: convergence with testable criteria, executable verification, business-language DoD +• Risk items per layer + +MODE: analysis +CONTEXT: @**/* +EXPECTED: +For each layer output: +## L{n}: {Name} +**Goal**: {one sentence} +**Scope**: {comma-separated features} +**Excludes**: {comma-separated excluded features} +**Convergence**: +- Criteria: {bullet list of testable conditions} +- Verification: {executable command or steps} +- Definition of Done: {business language sentence} +**Risk Items**: {bullet list} +**Effort**: {small|medium|large} +**Depends On**: {layer IDs or none} + +CONSTRAINTS: +- Each feature belongs to exactly ONE layer (no overlap) +- Criteria must be testable (can write assertions) +- Verification must be executable (commands or explicit steps) +- Definition of Done must be understandable by non-technical stakeholders +- L0 must be a complete closed loop (end-to-end path works) +" --tool ${cli_config.tool} --mode analysis +``` + +### Direct Mode Decomposition + +```bash +ccw cli -p " +PURPOSE: Decompose requirement into topologically-sorted task sequence with convergence criteria +Success: Self-contained tasks with clear inputs/outputs, testable convergence, correct dependency order + +REQUIREMENT: +${requirement} + +STRATEGY CONTEXT: +- Goal: ${strategy_assessment.goal} +- Constraints: ${strategy_assessment.constraints.join(', ')} + +${exploration_context ? `CODEBASE CONTEXT: +- Relevant modules: ${exploration_context.relevant_modules.map(m => m.name).join(', ')} +- Existing patterns: ${exploration_context.existing_patterns.map(p => p.pattern).join(', ')} +- Tech stack: ${JSON.stringify(exploration_context.tech_stack)}` : 'NO CODEBASE (pure requirement decomposition)'} + +TASK: +• Decompose into vertical slices with clear boundaries +• Each task: type (infrastructure|feature|enhancement|testing) +• Each task: explicit inputs (what it needs) and outputs (what it produces) +• Each task: convergence with testable criteria, executable verification, business-language DoD +• Topological sort: respect dependency order +• Assign parallel_group numbers (same group = can run in parallel) + +MODE: analysis +CONTEXT: @**/* +EXPECTED: +For each task output: +## T{n}: {Title} +**Type**: {infrastructure|feature|enhancement|testing} +**Scope**: {description} +**Inputs**: {comma-separated files/modules or 'none'} +**Outputs**: {comma-separated files/modules} +**Convergence**: +- Criteria: {bullet list of testable conditions} +- Verification: {executable command or steps} +- Definition of Done: {business language sentence} +**Depends On**: {task IDs or none} +**Parallel Group**: {number} + +CONSTRAINTS: +- Inputs must come from preceding task outputs or existing resources +- No circular dependencies +- Criteria must be testable +- Verification must be executable +- Tasks in same parallel_group must be truly independent +" --tool ${cli_config.tool} --mode analysis +``` + +## Core Functions + +### CLI Output Parsing + +```javascript +// Parse progressive layers from CLI output +function parseProgressiveLayers(cliOutput) { + const layers = [] + const layerBlocks = cliOutput.split(/## L(\d+):/).slice(1) + + for (let i = 0; i < layerBlocks.length; i += 2) { + const layerId = `L${layerBlocks[i].trim()}` + const text = layerBlocks[i + 1] + + const nameMatch = /^(.+?)(?=\n)/.exec(text) + const goalMatch = /\*\*Goal\*\*:\s*(.+?)(?=\n)/.exec(text) + const scopeMatch = /\*\*Scope\*\*:\s*(.+?)(?=\n)/.exec(text) + const excludesMatch = /\*\*Excludes\*\*:\s*(.+?)(?=\n)/.exec(text) + const effortMatch = /\*\*Effort\*\*:\s*(.+?)(?=\n)/.exec(text) + const dependsMatch = /\*\*Depends On\*\*:\s*(.+?)(?=\n|$)/.exec(text) + const riskMatch = /\*\*Risk Items\*\*:\n((?:- .+?\n)*)/.exec(text) + + const convergence = parseConvergence(text) + + layers.push({ + id: layerId, + name: nameMatch?.[1].trim() || `Layer ${layerId}`, + goal: goalMatch?.[1].trim() || "", + scope: scopeMatch?.[1].split(/[,,]/).map(s => s.trim()).filter(Boolean) || [], + excludes: excludesMatch?.[1].split(/[,,]/).map(s => s.trim()).filter(Boolean) || [], + convergence, + risk_items: riskMatch + ? riskMatch[1].split('\n').map(s => s.replace(/^- /, '').trim()).filter(Boolean) + : [], + effort: normalizeEffort(effortMatch?.[1].trim()), + depends_on: parseDependsOn(dependsMatch?.[1], 'L') + }) + } + + return layers +} + +// Parse direct tasks from CLI output +function parseDirectTasks(cliOutput) { + const tasks = [] + const taskBlocks = cliOutput.split(/## T(\d+):/).slice(1) + + for (let i = 0; i < taskBlocks.length; i += 2) { + const taskId = `T${taskBlocks[i].trim()}` + const text = taskBlocks[i + 1] + + const titleMatch = /^(.+?)(?=\n)/.exec(text) + const typeMatch = /\*\*Type\*\*:\s*(.+?)(?=\n)/.exec(text) + const scopeMatch = /\*\*Scope\*\*:\s*(.+?)(?=\n)/.exec(text) + const inputsMatch = /\*\*Inputs\*\*:\s*(.+?)(?=\n)/.exec(text) + const outputsMatch = /\*\*Outputs\*\*:\s*(.+?)(?=\n)/.exec(text) + const dependsMatch = /\*\*Depends On\*\*:\s*(.+?)(?=\n|$)/.exec(text) + const groupMatch = /\*\*Parallel Group\*\*:\s*(\d+)/.exec(text) + + const convergence = parseConvergence(text) + + tasks.push({ + id: taskId, + title: titleMatch?.[1].trim() || `Task ${taskId}`, + type: normalizeType(typeMatch?.[1].trim()), + scope: scopeMatch?.[1].trim() || "", + inputs: parseList(inputsMatch?.[1]), + outputs: parseList(outputsMatch?.[1]), + convergence, + depends_on: parseDependsOn(dependsMatch?.[1], 'T'), + parallel_group: parseInt(groupMatch?.[1]) || 1 + }) + } + + return tasks +} + +// Parse convergence section from a record block +function parseConvergence(text) { + const criteriaMatch = /- Criteria:\s*((?:.+\n?)+?)(?=- Verification:)/.exec(text) + const verificationMatch = /- Verification:\s*(.+?)(?=\n- Definition)/.exec(text) + const dodMatch = /- Definition of Done:\s*(.+?)(?=\n\*\*|$)/.exec(text) + + const criteria = criteriaMatch + ? criteriaMatch[1].split('\n') + .map(s => s.replace(/^\s*[-•]\s*/, '').trim()) + .filter(s => s && !s.startsWith('Verification') && !s.startsWith('Definition')) + : [] + + return { + criteria: criteria.length > 0 ? criteria : ["Task completed successfully"], + verification: verificationMatch?.[1].trim() || "Manual verification", + definition_of_done: dodMatch?.[1].trim() || "Feature works as expected" + } +} + +// Helper: normalize effort string +function normalizeEffort(effort) { + if (!effort) return "medium" + const lower = effort.toLowerCase() + if (lower.includes('small') || lower.includes('low')) return "small" + if (lower.includes('large') || lower.includes('high')) return "large" + return "medium" +} + +// Helper: normalize task type +function normalizeType(type) { + if (!type) return "feature" + const lower = type.toLowerCase() + if (lower.includes('infra')) return "infrastructure" + if (lower.includes('enhance')) return "enhancement" + if (lower.includes('test')) return "testing" + return "feature" +} + +// Helper: parse comma-separated list +function parseList(text) { + if (!text || text.toLowerCase() === 'none') return [] + return text.split(/[,,]/).map(s => s.trim()).filter(Boolean) +} + +// Helper: parse depends_on field +function parseDependsOn(text, prefix) { + if (!text || text.toLowerCase() === 'none' || text === '[]') return [] + const pattern = new RegExp(`${prefix}\\d+`, 'g') + return (text.match(pattern) || []) +} +``` + +### Validation Functions + +```javascript +// Validate progressive layers +function validateProgressiveLayers(layers) { + const errors = [] + + // Check scope overlap + const allScopes = new Map() + layers.forEach(layer => { + layer.scope.forEach(feature => { + if (allScopes.has(feature)) { + errors.push(`Scope overlap: "${feature}" in both ${allScopes.get(feature)} and ${layer.id}`) + } + allScopes.set(feature, layer.id) + }) + }) + + // Check circular dependencies + const cycleErrors = detectCycles(layers, 'L') + errors.push(...cycleErrors) + + // Check convergence quality + layers.forEach(layer => { + errors.push(...validateConvergence(layer.id, layer.convergence)) + }) + + // Check L0 is self-contained (no depends_on) + const l0 = layers.find(l => l.id === 'L0') + if (l0 && l0.depends_on.length > 0) { + errors.push("L0 (MVP) should not have dependencies") + } + + return errors +} + +// Validate direct tasks +function validateDirectTasks(tasks) { + const errors = [] + + // Check inputs/outputs chain + const availableOutputs = new Set() + const sortedTasks = topologicalSort(tasks) + + sortedTasks.forEach(task => { + task.inputs.forEach(input => { + if (!availableOutputs.has(input)) { + // Check if it's an existing resource (not from a task) + // Only warn, don't error - existing files are valid inputs + } + }) + task.outputs.forEach(output => availableOutputs.add(output)) + }) + + // Check circular dependencies + const cycleErrors = detectCycles(tasks, 'T') + errors.push(...cycleErrors) + + // Check convergence quality + tasks.forEach(task => { + errors.push(...validateConvergence(task.id, task.convergence)) + }) + + // Check parallel_group consistency + const groups = new Map() + tasks.forEach(task => { + if (!groups.has(task.parallel_group)) groups.set(task.parallel_group, []) + groups.get(task.parallel_group).push(task) + }) + groups.forEach((groupTasks, groupId) => { + if (groupTasks.length > 1) { + // Tasks in same group should not depend on each other + const ids = new Set(groupTasks.map(t => t.id)) + groupTasks.forEach(task => { + task.depends_on.forEach(dep => { + if (ids.has(dep)) { + errors.push(`Parallel group ${groupId}: ${task.id} depends on ${dep} but both in same group`) + } + }) + }) + } + }) + + return errors +} + +// Validate convergence quality +function validateConvergence(recordId, convergence) { + const errors = [] + + // Check criteria are testable (not vague) + const vaguePatterns = /正常|正确|好|可以|没问题|works|fine|good|correct/i + convergence.criteria.forEach((criterion, i) => { + if (vaguePatterns.test(criterion) && criterion.length < 15) { + errors.push(`${recordId} criteria[${i}]: Too vague - "${criterion}"`) + } + }) + + // Check verification is executable + if (convergence.verification.length < 10) { + errors.push(`${recordId} verification: Too short, needs executable steps`) + } + + // Check definition_of_done is business language + const technicalPatterns = /compile|build|lint|npm|npx|jest|tsc|eslint/i + if (technicalPatterns.test(convergence.definition_of_done)) { + errors.push(`${recordId} definition_of_done: Should be business language, not technical commands`) + } + + return errors +} + +// Detect circular dependencies +function detectCycles(records, prefix) { + const errors = [] + const graph = new Map(records.map(r => [r.id, r.depends_on])) + const visited = new Set() + const inStack = new Set() + + function dfs(node, path) { + if (inStack.has(node)) { + errors.push(`Circular dependency detected: ${[...path, node].join(' → ')}`) + return + } + if (visited.has(node)) return + + visited.add(node) + inStack.add(node) + ;(graph.get(node) || []).forEach(dep => dfs(dep, [...path, node])) + inStack.delete(node) + } + + records.forEach(r => { + if (!visited.has(r.id)) dfs(r.id, []) + }) + + return errors +} + +// Topological sort +function topologicalSort(tasks) { + const result = [] + const visited = new Set() + const taskMap = new Map(tasks.map(t => [t.id, t])) + + function visit(taskId) { + if (visited.has(taskId)) return + visited.add(taskId) + const task = taskMap.get(taskId) + if (task) { + task.depends_on.forEach(dep => visit(dep)) + result.push(task) + } + } + + tasks.forEach(t => visit(t.id)) + return result +} +``` + +### JSONL & Markdown Generation + +```javascript +// Generate roadmap.jsonl +function generateJsonl(records) { + return records.map(record => JSON.stringify(record)).join('\n') + '\n' +} + +// Generate roadmap.md for progressive mode +function generateProgressiveRoadmapMd(layers, input) { + return `# 需求路线图 + +**Session**: ${input.session.id} +**需求**: ${input.requirement} +**策略**: progressive +**不确定性**: ${input.strategy_assessment.uncertainty_level} +**生成时间**: ${new Date().toISOString()} + +## 策略评估 + +- 目标: ${input.strategy_assessment.goal} +- 约束: ${input.strategy_assessment.constraints.join(', ') || '无'} +- 利益方: ${input.strategy_assessment.stakeholders.join(', ') || '无'} + +## 路线图概览 + +| 层级 | 名称 | 目标 | 工作量 | 依赖 | +|------|------|------|--------|------| +${layers.map(l => `| ${l.id} | ${l.name} | ${l.goal} | ${l.effort} | ${l.depends_on.length ? l.depends_on.join(', ') : '-'} |`).join('\n')} + +## 各层详情 + +${layers.map(l => `### ${l.id}: ${l.name} + +**目标**: ${l.goal} + +**范围**: ${l.scope.join('、')} + +**排除**: ${l.excludes.join('、') || '无'} + +**收敛标准**: +${l.convergence.criteria.map(c => `- ✅ ${c}`).join('\n')} +- 🔍 **验证方法**: ${l.convergence.verification} +- 🎯 **完成定义**: ${l.convergence.definition_of_done} + +**风险项**: ${l.risk_items.length ? l.risk_items.map(r => `\n- ⚠️ ${r}`).join('') : '无'} + +**工作量**: ${l.effort} +`).join('\n---\n\n')} + +## 风险汇总 + +${layers.flatMap(l => l.risk_items.map(r => `- **${l.id}**: ${r}`)).join('\n') || '无已识别风险'} + +## 下一步 + +每个层级可独立执行: +\`\`\`bash +/workflow:lite-plan "${layers[0]?.name}: ${layers[0]?.scope.join(', ')}" +\`\`\` + +路线图 JSONL 文件: \`${input.session.folder}/roadmap.jsonl\` +` +} + +// Generate roadmap.md for direct mode +function generateDirectRoadmapMd(tasks, input) { + return `# 需求路线图 + +**Session**: ${input.session.id} +**需求**: ${input.requirement} +**策略**: direct +**生成时间**: ${new Date().toISOString()} + +## 策略评估 + +- 目标: ${input.strategy_assessment.goal} +- 约束: ${input.strategy_assessment.constraints.join(', ') || '无'} + +## 任务序列 + +| 组 | ID | 标题 | 类型 | 依赖 | +|----|-----|------|------|------| +${tasks.map(t => `| ${t.parallel_group} | ${t.id} | ${t.title} | ${t.type} | ${t.depends_on.length ? t.depends_on.join(', ') : '-'} |`).join('\n')} + +## 各任务详情 + +${tasks.map(t => `### ${t.id}: ${t.title} + +**类型**: ${t.type} | **并行组**: ${t.parallel_group} + +**范围**: ${t.scope} + +**输入**: ${t.inputs.length ? t.inputs.join(', ') : '无(起始任务)'} +**输出**: ${t.outputs.join(', ')} + +**收敛标准**: +${t.convergence.criteria.map(c => `- ✅ ${c}`).join('\n')} +- 🔍 **验证方法**: ${t.convergence.verification} +- 🎯 **完成定义**: ${t.convergence.definition_of_done} +`).join('\n---\n\n')} + +## 下一步 + +每个任务可独立执行: +\`\`\`bash +/workflow:lite-plan "${tasks[0]?.title}: ${tasks[0]?.scope}" +\`\`\` + +路线图 JSONL 文件: \`${input.session.folder}/roadmap.jsonl\` +` +} +``` + +### Fallback Decomposition + +```javascript +// Manual decomposition when CLI fails +function manualProgressiveDecomposition(requirement, context) { + return [ + { + id: "L0", name: "MVP", goal: "最小可用闭环", + scope: ["核心功能"], excludes: ["高级功能", "优化"], + convergence: { + criteria: ["核心路径端到端可跑通"], + verification: "手动测试核心流程", + definition_of_done: "用户可完成一次核心操作的完整流程" + }, + risk_items: ["技术选型待验证"], effort: "medium", depends_on: [] + }, + { + id: "L1", name: "可用", goal: "关键用户路径完善", + scope: ["错误处理", "输入校验"], excludes: ["性能优化", "监控"], + convergence: { + criteria: ["所有用户输入有校验", "错误场景有提示"], + verification: "单元测试 + 手动测试错误场景", + definition_of_done: "用户遇到问题时有清晰的引导和恢复路径" + }, + risk_items: [], effort: "medium", depends_on: ["L0"] + } + ] +} + +function manualDirectDecomposition(requirement, context) { + return [ + { + id: "T1", title: "基础设施搭建", type: "infrastructure", + scope: "项目骨架和基础配置", + inputs: [], outputs: ["project-structure"], + convergence: { + criteria: ["项目可构建无报错", "基础配置完成"], + verification: "npm run build (或对应构建命令)", + definition_of_done: "项目基础框架就绪,可开始功能开发" + }, + depends_on: [], parallel_group: 1 + }, + { + id: "T2", title: "核心功能实现", type: "feature", + scope: "核心业务逻辑", + inputs: ["project-structure"], outputs: ["core-module"], + convergence: { + criteria: ["核心 API/功能可调用", "返回预期结果"], + verification: "运行核心功能测试", + definition_of_done: "核心业务功能可正常使用" + }, + depends_on: ["T1"], parallel_group: 2 + } + ] +} +``` + +## Phase 5: Decomposition Quality Check (MANDATORY) + +### Overview + +After generating roadmap.jsonl, **MUST** execute CLI quality check before returning to orchestrator. + +### Quality Dimensions + +| Dimension | Check Criteria | Critical? | +|-----------|---------------|-----------| +| **Requirement Coverage** | All aspects of original requirement addressed in layers/tasks | Yes | +| **Convergence Quality** | criteria testable, verification executable, DoD business-readable | Yes | +| **Scope Integrity** | Progressive: no overlap/gaps; Direct: inputs/outputs chain valid | Yes | +| **Dependency Correctness** | No circular deps, proper ordering | Yes | +| **Effort Balance** | No single layer/task disproportionately large | No | + +### CLI Quality Check Command + +```bash +ccw cli -p " +PURPOSE: Validate roadmap decomposition quality +Success: All quality dimensions pass + +ORIGINAL REQUIREMENT: +${requirement} + +ROADMAP (${selected_mode} mode): +${roadmapJsonlContent} + +TASK: +• Requirement Coverage: Does the roadmap address ALL aspects of the requirement? +• Convergence Quality: Are criteria testable? Is verification executable? Is DoD business-readable? +• Scope Integrity: ${selected_mode === 'progressive' ? 'No scope overlap between layers, no feature gaps' : 'Inputs/outputs chain is valid, parallel groups are correct'} +• Dependency Correctness: No circular dependencies +• Effort Balance: No disproportionately large items + +MODE: analysis +EXPECTED: +## Quality Check Results +### Requirement Coverage: PASS|FAIL +[details] +### Convergence Quality: PASS|FAIL +[details and specific issues per record] +### Scope Integrity: PASS|FAIL +[details] +### Dependency Correctness: PASS|FAIL +[details] +### Effort Balance: PASS|FAIL +[details] + +## Recommendation: PASS|AUTO_FIX|NEEDS_REVIEW +## Fixes (if AUTO_FIX): +[specific fixes as JSON patches] + +CONSTRAINTS: Read-only validation, do not modify files +" --tool ${cli_config.tool} --mode analysis +``` + +### Auto-Fix Strategy + +| Issue Type | Auto-Fix Action | +|-----------|----------------| +| Vague criteria | Replace with specific, testable conditions | +| Technical DoD | Rewrite in business language | +| Missing scope items | Add to appropriate layer/task | +| Effort imbalance | Suggest split (report to orchestrator) | + +After fixes, update `roadmap.jsonl` and `roadmap.md`. + +## Error Handling + +```javascript +// Fallback chain: Gemini → Qwen → manual decomposition +try { + result = executeCLI(cli_config.tool, prompt) +} catch (error) { + try { + result = executeCLI(cli_config.fallback, prompt) + } catch { + // Manual fallback + records = selected_mode === 'progressive' + ? manualProgressiveDecomposition(requirement, exploration_context) + : manualDirectDecomposition(requirement, exploration_context) + } +} +``` + +## Key Reminders + +**ALWAYS**: +- Parse CLI output into structured records with full convergence fields +- Validate all records against schema before writing JSONL +- Check for circular dependencies +- Ensure convergence criteria are testable (not vague) +- Ensure verification is executable (commands or explicit steps) +- Ensure definition_of_done uses business language +- Run Phase 5 quality check before returning +- Write both roadmap.jsonl AND roadmap.md + +**Bash Tool**: +- Use `run_in_background=false` for all Bash/CLI calls + +**NEVER**: +- Output vague convergence criteria ("works correctly", "系统正常") +- Create circular dependencies +- Skip convergence validation +- Skip Phase 5 quality check +- Return without writing both output files diff --git a/.claude/commands/workflow/req-plan-with-file.md b/.claude/commands/workflow/req-plan-with-file.md new file mode 100644 index 00000000..51d995d0 --- /dev/null +++ b/.claude/commands/workflow/req-plan-with-file.md @@ -0,0 +1,692 @@ +--- +name: req-plan-with-file +description: Requirement-level progressive roadmap planning with JSONL output. Decomposes requirements into convergent layers (MVP→iterations) or topologically-sorted task sequences, each with testable completion criteria. +argument-hint: "[-y|--yes] [-c|--continue] [-m|--mode progressive|direct|auto] \"requirement description\"" +allowed-tools: TodoWrite(*), Task(*), AskUserQuestion(*), Read(*), Grep(*), Glob(*), Bash(*), Edit(*), Write(*) +--- + +## Auto Mode + +When `--yes` or `-y`: Auto-confirm strategy selection, use recommended mode, skip interactive validation rounds. + +# Workflow Req-Plan Command (/workflow:req-plan-with-file) + +## Quick Start + +```bash +# Basic usage +/workflow:req-plan-with-file "Implement user authentication system with OAuth and 2FA" + +# With mode selection +/workflow:req-plan-with-file -m progressive "Build real-time notification system" # Layered MVP→iterations +/workflow:req-plan-with-file -m direct "Refactor payment module" # Topologically-sorted task sequence +/workflow:req-plan-with-file -m auto "Add data export feature" # Auto-select strategy + +# Continue existing session +/workflow:req-plan-with-file --continue "user authentication system" + +# Auto mode +/workflow:req-plan-with-file -y "Implement caching layer" +``` + +**Context Source**: cli-explore-agent (optional) + requirement analysis +**Output Directory**: `.workflow/.req-plan/{session-id}/` +**Core Innovation**: JSONL roadmap where each record is self-contained + has convergence criteria, independently executable via lite-plan + +## Overview + +Requirement-level layered roadmap planning command. Decomposes a requirement into **convergent layers or task sequences**, each record containing explicit completion criteria (convergence), independently executable via `lite-plan`. + +**Dual Modes**: +- **Progressive**: Layered MVP→iterations, suitable for high-uncertainty requirements (validate first, then refine) +- **Direct**: Topologically-sorted task sequence, suitable for low-uncertainty requirements (clear tasks, directly ordered) +- **Auto**: Automatically selects based on uncertainty level + +**Core Workflow**: Requirement Understanding → Strategy Selection → Context Collection (optional) → Decomposition → Validation → Output + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ REQ-PLAN ROADMAP WORKFLOW │ +├─────────────────────────────────────────────────────────────────────────┤ +│ │ +│ Phase 1: Requirement Understanding & Strategy Selection │ +│ ├─ Parse requirement: goal / constraints / stakeholders │ +│ ├─ Assess uncertainty level │ +│ │ ├─ High uncertainty → recommend progressive │ +│ │ └─ Low uncertainty → recommend direct │ +│ ├─ User confirms strategy (-m skips, -y auto-selects recommended) │ +│ └─ Initialize strategy-assessment.json + roadmap.md skeleton │ +│ │ +│ Phase 2: Context Collection (Optional) │ +│ ├─ Detect codebase: package.json / go.mod / src / ... │ +│ ├─ Has codebase → cli-explore-agent explores relevant modules │ +│ └─ No codebase → skip, pure requirement decomposition │ +│ │ +│ Phase 3: Decomposition Execution (cli-roadmap-plan-agent) │ +│ ├─ Progressive: define 2-4 layers, each with full convergence │ +│ ├─ Direct: vertical slicing + topological sort, each with convergence│ +│ └─ Generate roadmap.jsonl (one self-contained record per line) │ +│ │ +│ Phase 4: Interactive Validation & Final Output │ +│ ├─ Display decomposition results (tabular + convergence criteria) │ +│ ├─ User feedback loop (up to 5 rounds) │ +│ ├─ Generate final roadmap.md │ +│ └─ Next steps: layer-by-layer lite-plan / create issue / export │ +│ │ +└─────────────────────────────────────────────────────────────────────────┘ +``` + +## Output + +``` +.workflow/.req-plan/RPLAN-{slug}-{YYYY-MM-DD}/ +├── roadmap.md # ⭐ Human-readable roadmap +├── roadmap.jsonl # ⭐ Machine-readable, one self-contained record per line (with convergence) +├── strategy-assessment.json # Strategy assessment result +└── exploration-codebase.json # Codebase context (optional) +``` + +| File | Phase | Description | +|------|-------|-------------| +| `strategy-assessment.json` | 1 | Uncertainty analysis + mode recommendation + extracted goal/constraints/stakeholders | +| `roadmap.md` (skeleton) | 1 | Initial skeleton with placeholders, finalized in Phase 4 | +| `exploration-codebase.json` | 2 | Codebase context: relevant modules, patterns, integration points (only when codebase exists) | +| `roadmap.jsonl` | 3 | One self-contained JSON record per line with convergence criteria | +| `roadmap.md` (final) | 4 | Human-readable roadmap with tabular display + convergence details, revised per user feedback | + +**roadmap.md template**: + +```markdown +# Requirement Roadmap + +**Session**: RPLAN-{slug}-{date} +**Requirement**: {requirement} +**Strategy**: {progressive|direct} +**Generated**: {timestamp} + +## Strategy Assessment +- Uncertainty level: {high|medium|low} +- Decomposition mode: {progressive|direct} +- Assessment basis: {factors summary} + +## Roadmap +{Tabular display of layers/tasks} + +## Convergence Criteria Details +{Expanded convergence for each layer/task} + +## Risk Items +{Aggregated risk_items} + +## Next Steps +{Execution guidance} +``` + +## Configuration + +| Flag | Default | Description | +|------|---------|-------------| +| `-y, --yes` | false | Auto-confirm all decisions | +| `-c, --continue` | false | Continue existing session | +| `-m, --mode` | auto | Decomposition strategy: progressive / direct / auto | + +**Session ID format**: `RPLAN-{slug}-{YYYY-MM-DD}` +- slug: lowercase, alphanumeric + CJK characters, max 40 chars +- date: YYYY-MM-DD (UTC+8) +- Auto-detect continue: session folder + roadmap.jsonl exists → continue mode + +## JSONL Schema Design + +### Convergence Criteria (convergence field) + +Each JSONL record's `convergence` object contains three levels: + +| Field | Purpose | Requirement | +|-------|---------|-------------| +| `criteria[]` | List of checkable specific conditions | **Testable** (can be written as assertions or manual steps) | +| `verification` | How to verify these conditions | **Executable** (command, script, or explicit steps) | +| `definition_of_done` | One-sentence completion definition | **Business language** (non-technical person can judge) | + +### Progressive Mode + +Each line = one layer. Layer naming convention: + +| Layer | Name | Typical Goal | +|-------|------|--------------| +| L0 | MVP | Minimum viable closed loop, core path works end-to-end | +| L1 | Usable | Key user paths refined, basic error handling | +| L2 | Refined | Edge case handling, performance optimization, security hardening | +| L3 | Optimized | Advanced features, observability, operations support | + +**Schema**: `id, name, goal, scope[], excludes[], convergence{}, risk_items[], effort, depends_on[]` + +```jsonl +{"id":"L0","name":"MVP","goal":"Minimum viable closed loop","scope":["User registration and login","Basic CRUD"],"excludes":["OAuth","2FA"],"convergence":{"criteria":["End-to-end register→login→operate flow works","Core API returns correct responses"],"verification":"curl/Postman manual testing or smoke test script","definition_of_done":"New user can complete the full flow of register→login→perform one core operation"},"risk_items":["JWT library selection needs validation"],"effort":"medium","depends_on":[]} +{"id":"L1","name":"Usable","goal":"Complete key user paths","scope":["Password reset","Input validation","Error messages"],"excludes":["Audit logs","Rate limiting"],"convergence":{"criteria":["All form fields have frontend+backend validation","Password reset email can be sent and reset completed","Error scenarios show user-friendly messages"],"verification":"Unit tests cover validation logic + manual test of reset flow","definition_of_done":"Users have a clear recovery path when encountering input errors or forgotten passwords"},"risk_items":[],"effort":"medium","depends_on":["L0"]} +``` + +**Constraints**: 2-4 layers, L0 must be a self-contained closed loop with no dependencies, each feature belongs to exactly ONE layer (no scope overlap). + +### Direct Mode + +Each line = one task. Task type convention: + +| Type | Use Case | +|------|----------| +| infrastructure | Data models, configuration, scaffolding | +| feature | API, UI, business logic implementation | +| enhancement | Validation, error handling, edge cases | +| testing | Unit tests, integration tests, E2E | + +**Schema**: `id, title, type, scope, inputs[], outputs[], convergence{}, depends_on[], parallel_group` + +```jsonl +{"id":"T1","title":"Establish data model","type":"infrastructure","scope":"DB schema + TypeScript types","inputs":[],"outputs":["schema.prisma","types/user.ts"],"convergence":{"criteria":["Migration executes without errors","TypeScript types compile successfully","Fields cover all business entities"],"verification":"npx prisma migrate dev && npx tsc --noEmit","definition_of_done":"Database schema migrates correctly, type definitions can be referenced by other modules"},"depends_on":[],"parallel_group":1} +{"id":"T2","title":"Implement core API","type":"feature","scope":"CRUD endpoints for User","inputs":["schema.prisma","types/user.ts"],"outputs":["routes/user.ts","controllers/user.ts"],"convergence":{"criteria":["GET/POST/PUT/DELETE return correct status codes","Request/response conforms to schema","No N+1 queries"],"verification":"jest --testPathPattern=user.test.ts","definition_of_done":"All User CRUD endpoints pass integration tests"},"depends_on":["T1"],"parallel_group":2} +``` + +**Constraints**: Inputs must come from preceding task outputs or existing resources, tasks in same parallel_group must be truly independent, no circular dependencies. + +## Implementation + +### Session Initialization + +**Objective**: Create session context and directory structure. + +```javascript +const getUtc8ISOString = () => new Date(Date.now() + 8 * 60 * 60 * 1000).toISOString() + +// Parse flags +const autoYes = $ARGUMENTS.includes('--yes') || $ARGUMENTS.includes('-y') +const continueMode = $ARGUMENTS.includes('--continue') || $ARGUMENTS.includes('-c') +const modeMatch = $ARGUMENTS.match(/(?:--mode|-m)\s+(progressive|direct|auto)/) +const requestedMode = modeMatch ? modeMatch[1] : 'auto' + +// Clean requirement text (remove flags) +const requirement = $ARGUMENTS + .replace(/--yes|-y|--continue|-c|--mode\s+\w+|-m\s+\w+/g, '') + .trim() + +const slug = requirement.toLowerCase() + .replace(/[^a-z0-9\u4e00-\u9fa5]+/g, '-') + .substring(0, 40) +const dateStr = getUtc8ISOString().substring(0, 10) +const sessionId = `RPLAN-${slug}-${dateStr}` +const sessionFolder = `.workflow/.req-plan/${sessionId}` + +// Auto-detect continue: session folder + roadmap.jsonl exists → continue mode +Bash(`mkdir -p ${sessionFolder}`) +``` + +### Phase 1: Requirement Understanding & Strategy Selection + +**Objective**: Parse requirement, assess uncertainty, select decomposition strategy. + +**Prerequisites**: Session initialized, requirement description available. + +**Steps**: + +1. **Parse Requirement** + - Extract core goal (what to achieve) + - Identify constraints (tech stack, timeline, compatibility, etc.) + - Identify stakeholders (users, admins, developers, etc.) + - Identify keywords to determine domain + +2. **Assess Uncertainty Level** + + ```javascript + const uncertaintyFactors = { + scope_clarity: 'low|medium|high', + technical_risk: 'low|medium|high', + dependency_unknown: 'low|medium|high', + domain_familiarity: 'low|medium|high', + requirement_stability: 'low|medium|high' + } + // high uncertainty (>=3 high) → progressive + // low uncertainty (>=3 low) → direct + // otherwise → ask user preference + ``` + +3. **Strategy Selection** (skip if `-m` already specified) + + ```javascript + if (requestedMode !== 'auto') { + selectedMode = requestedMode + } else if (autoYes) { + selectedMode = recommendedMode + } else { + AskUserQuestion({ + questions: [{ + question: `Decomposition strategy selection:\n\nUncertainty assessment: ${uncertaintyLevel}\nRecommended strategy: ${recommendedMode}\n\nSelect decomposition strategy:`, + header: "Strategy", + multiSelect: false, + options: [ + { + label: recommendedMode === 'progressive' ? "Progressive (Recommended)" : "Progressive", + description: "Layered MVP→iterations, validate core first then refine progressively. Suitable for high-uncertainty requirements needing quick validation" + }, + { + label: recommendedMode === 'direct' ? "Direct (Recommended)" : "Direct", + description: "Topologically-sorted task sequence with explicit dependencies. Suitable for clear requirements with confirmed technical approach" + } + ] + }] + }) + } + ``` + +4. **Generate strategy-assessment.json** + + ```javascript + const strategyAssessment = { + session_id: sessionId, + requirement: requirement, + timestamp: getUtc8ISOString(), + uncertainty_factors: uncertaintyFactors, + uncertainty_level: uncertaintyLevel, // 'high' | 'medium' | 'low' + recommended_mode: recommendedMode, + selected_mode: selectedMode, + goal: extractedGoal, + constraints: extractedConstraints, + stakeholders: extractedStakeholders, + domain_keywords: extractedKeywords + } + Write(`${sessionFolder}/strategy-assessment.json`, JSON.stringify(strategyAssessment, null, 2)) + ``` + +5. **Initialize roadmap.md skeleton** (placeholder sections, finalized in Phase 4) + + ```javascript + const roadmapMdSkeleton = `# Requirement Roadmap + +**Session**: ${sessionId} +**Requirement**: ${requirement} +**Strategy**: ${selectedMode} +**Status**: Planning +**Created**: ${getUtc8ISOString()} + +## Strategy Assessment +- Uncertainty level: ${uncertaintyLevel} +- Decomposition mode: ${selectedMode} + +## Roadmap +> To be populated after Phase 3 decomposition + +## Convergence Criteria Details +> To be populated after Phase 3 decomposition + +## Risk Items +> To be populated after Phase 3 decomposition + +## Next Steps +> To be populated after Phase 4 validation +` + Write(`${sessionFolder}/roadmap.md`, roadmapMdSkeleton) + ``` + +**Success Criteria**: +- Requirement goal, constraints, stakeholders identified +- Uncertainty level assessed +- Strategy selected (progressive or direct) +- strategy-assessment.json generated +- roadmap.md skeleton initialized + +### Phase 2: Context Collection (Optional) + +**Objective**: If a codebase exists, collect relevant context to enhance decomposition quality. + +**Prerequisites**: Phase 1 complete. + +**Steps**: + +1. **Detect Codebase** + + ```javascript + const hasCodebase = Bash(` + test -f package.json && echo "nodejs" || + test -f go.mod && echo "golang" || + test -f Cargo.toml && echo "rust" || + test -f pyproject.toml && echo "python" || + test -f pom.xml && echo "java" || + test -d src && echo "generic" || + echo "none" + `).trim() + ``` + +2. **Codebase Exploration** (only when hasCodebase !== 'none') + + ```javascript + if (hasCodebase !== 'none') { + Task({ + subagent_type: "cli-explore-agent", + run_in_background: false, + description: `Explore codebase: ${slug}`, + prompt: ` + ## Exploration Context + Requirement: ${requirement} + Strategy: ${selectedMode} + Project Type: ${hasCodebase} + Session: ${sessionFolder} + + ## MANDATORY FIRST STEPS + 1. Run: ccw tool exec get_modules_by_depth '{}' + 2. Execute relevant searches based on requirement keywords + 3. Read: .workflow/project-tech.json (if exists) + 4. Read: .workflow/project-guidelines.json (if exists) + + ## Exploration Focus + - Identify modules/components related to the requirement + - Find existing patterns that should be followed + - Locate integration points for new functionality + - Assess current architecture constraints + + ## Output + Write findings to: ${sessionFolder}/exploration-codebase.json + + Schema: { + project_type: "${hasCodebase}", + relevant_modules: [{name, path, relevance}], + existing_patterns: [{pattern, files, description}], + integration_points: [{location, description, risk}], + architecture_constraints: [string], + tech_stack: {languages, frameworks, tools}, + _metadata: {timestamp, exploration_scope} + } + ` + }) + } + // No codebase → skip, proceed directly to Phase 3 + ``` + +**Success Criteria**: +- Codebase detection complete +- When codebase exists, exploration-codebase.json generated +- When no codebase, skipped and logged + +### Phase 3: Decomposition Execution + +**Objective**: Execute requirement decomposition via `cli-roadmap-plan-agent`, generating roadmap.jsonl + roadmap.md. + +**Prerequisites**: Phase 1, Phase 2 complete. Strategy selected. Context collected (if applicable). + +**Agent**: `cli-roadmap-plan-agent` (dedicated requirement roadmap planning agent, supports CLI-assisted decomposition + built-in quality checks) + +**Steps**: + +1. **Prepare Context** + + ```javascript + const strategy = JSON.parse(Read(`${sessionFolder}/strategy-assessment.json`)) + let explorationContext = null + if (file_exists(`${sessionFolder}/exploration-codebase.json`)) { + explorationContext = JSON.parse(Read(`${sessionFolder}/exploration-codebase.json`)) + } + ``` + +2. **Invoke cli-roadmap-plan-agent** + + The agent internally executes a 5-phase flow: + - Phase 1: Context loading + requirement analysis + - Phase 2: CLI-assisted decomposition (Gemini → Qwen → manual fallback) + - Phase 3: Record enhancement + validation (schema compliance, dependency checks, convergence quality) + - Phase 4: Generate roadmap.jsonl + roadmap.md + - Phase 5: CLI decomposition quality check (**MANDATORY** - requirement coverage, convergence criteria quality, dependency correctness) + + ```javascript + Task({ + subagent_type: "cli-roadmap-plan-agent", + run_in_background: false, + description: `Roadmap decomposition: ${slug}`, + prompt: ` + ## Roadmap Decomposition Task + + ### Input Context + - **Requirement**: ${requirement} + - **Selected Mode**: ${selectedMode} + - **Session ID**: ${sessionId} + - **Session Folder**: ${sessionFolder} + + ### Strategy Assessment + ${JSON.stringify(strategy, null, 2)} + + ### Codebase Context + ${explorationContext + ? `File: ${sessionFolder}/exploration-codebase.json\n${JSON.stringify(explorationContext, null, 2)}` + : 'No codebase detected - pure requirement decomposition'} + + ### CLI Configuration + - Primary tool: gemini + - Fallback: qwen + - Timeout: 60000ms + + ### Expected Output + 1. **${sessionFolder}/roadmap.jsonl** - One JSON record per line with convergence field + 2. **${sessionFolder}/roadmap.md** - Human-readable roadmap with tables and convergence details + + ### Mode-Specific Requirements + + ${selectedMode === 'progressive' ? `**Progressive Mode**: + - 2-4 layers from MVP to full implementation + - Each layer: id (L0-L3), name, goal, scope, excludes, convergence, risk_items, effort, depends_on + - L0 (MVP) must be a self-contained closed loop with no dependencies + - Scope: each feature belongs to exactly ONE layer (no overlap) + - Layer names: MVP / Usable / Refined / Optimized` : + + `**Direct Mode**: + - Topologically-sorted task sequence + - Each task: id (T1-Tn), title, type, scope, inputs, outputs, convergence, depends_on, parallel_group + - Inputs must come from preceding task outputs or existing resources + - Tasks in same parallel_group must be truly independent`} + + ### Convergence Quality Requirements + - criteria[]: MUST be testable (can write assertions or manual verification steps) + - verification: MUST be executable (command, script, or explicit steps) + - definition_of_done: MUST use business language (non-technical person can judge) + + ### Execution + 1. Analyze requirement and build decomposition context + 2. Execute CLI-assisted decomposition (Gemini, fallback Qwen) + 3. Parse output, validate records, enhance convergence quality + 4. Write roadmap.jsonl + roadmap.md + 5. Execute mandatory quality check (Phase 5) + 6. Return brief completion summary + ` + }) + ``` + +**Success Criteria**: +- roadmap.jsonl generated, each line independently JSON.parse-able +- roadmap.md generated (follows template in Output section) +- Each record contains convergence (criteria + verification + definition_of_done) +- Agent's internal quality check passed +- No circular dependencies +- Progressive: 2-4 layers, no scope overlap +- Direct: tasks have explicit inputs/outputs, parallel_group assigned + +### Phase 4: Interactive Validation & Final Output + +**Objective**: Display decomposition results, collect user feedback, generate final artifacts. + +**Prerequisites**: Phase 3 complete, roadmap.jsonl generated. + +**Steps**: + +1. **Display Decomposition Results** (tabular format) + + **Progressive Mode**: + ```markdown + ## Roadmap Overview + + | Layer | Name | Goal | Scope | Effort | Dependencies | + |-------|------|------|-------|--------|--------------| + | L0 | MVP | ... | ... | medium | - | + | L1 | Usable | ... | ... | medium | L0 | + + ### Convergence Criteria + **L0 - MVP**: + - ✅ Criteria: [criteria list] + - 🔍 Verification: [verification] + - 🎯 Definition of Done: [definition_of_done] + ``` + + **Direct Mode**: + ```markdown + ## Task Sequence + + | Group | ID | Title | Type | Dependencies | + |-------|----|-------|------|--------------| + | 1 | T1 | ... | infrastructure | - | + | 2 | T2 | ... | feature | T1 | + + ### Convergence Criteria + **T1 - Establish Data Model**: + - ✅ Criteria: [criteria list] + - 🔍 Verification: [verification] + - 🎯 Definition of Done: [definition_of_done] + ``` + +2. **User Feedback Loop** (up to 5 rounds, skipped when autoYes) + + ```javascript + if (!autoYes) { + let round = 0 + let continueLoop = true + + while (continueLoop && round < 5) { + round++ + const feedback = AskUserQuestion({ + questions: [{ + question: `Roadmap validation (round ${round}):\nAny feedback on the current decomposition?`, + header: "Feedback", + multiSelect: false, + options: [ + { label: "Approve", description: "Decomposition is reasonable, generate final artifacts" }, + { label: "Adjust Scope", description: "Some layer/task scopes need adjustment" }, + { label: "Modify Convergence", description: "Convergence criteria are not specific or testable enough" }, + { label: "Re-decompose", description: "Overall strategy or layering approach needs change" } + ] + }] + }) + + if (feedback === 'Approve') { + continueLoop = false + } else { + // Handle adjustment based on feedback type + // After adjustment, re-display and return to loop top + } + } + } + ``` + +3. **Finalize roadmap.md** (populate template from Output section with actual data) + + ```javascript + const roadmapMd = ` + # Requirement Roadmap + + **Session**: ${sessionId} + **Requirement**: ${requirement} + **Strategy**: ${selectedMode} + **Generated**: ${getUtc8ISOString()} + + ## Strategy Assessment + - Uncertainty level: ${strategy.uncertainty_level} + - Decomposition mode: ${selectedMode} + + ## Roadmap + ${generateRoadmapTable(items, selectedMode)} + + ## Convergence Criteria Details + ${items.map(item => generateConvergenceSection(item, selectedMode)).join('\n\n')} + + ## Risk Items + ${generateRiskSection(items)} + + ## Next Steps + Each layer/task can be executed independently: + \`\`\`bash + /workflow:lite-plan "${items[0].name || items[0].title}: ${items[0].scope}" + \`\`\` + Roadmap JSONL file: \`${sessionFolder}/roadmap.jsonl\` + ` + Write(`${sessionFolder}/roadmap.md`, roadmapMd) + ``` + +4. **Post-Completion Options** + + ```javascript + if (!autoYes) { + AskUserQuestion({ + questions: [{ + question: "Roadmap generated. Next step:", + header: "Next Step", + multiSelect: false, + options: [ + { label: "Execute First Layer", description: `Launch lite-plan to execute ${items[0].id}` }, + { label: "Create Issue", description: "Create GitHub Issue based on roadmap" }, + { label: "Export Report", description: "Generate standalone shareable roadmap report" }, + { label: "Done", description: "Save roadmap only, execute later" } + ] + }] + }) + } + ``` + + | Selection | Action | + |-----------|--------| + | Execute First Layer | `Skill(skill="workflow:lite-plan", args="${firstItem.scope}")` | + | Create Issue | `Skill(skill="issue:new", args="...")` | + | Export Report | Copy roadmap.md + roadmap.jsonl to user-specified location, or generate standalone HTML/Markdown report | + | Done | Display roadmap file paths, end | + +**Success Criteria**: +- User feedback processed (or skipped via autoYes) +- roadmap.md finalized +- roadmap.jsonl final version updated +- Post-completion options provided + +## Error Handling + +| Error | Resolution | +|-------|------------| +| cli-explore-agent failure | Skip code exploration, proceed with pure requirement decomposition | +| No codebase | Normal flow, skip Phase 2 | +| Circular dependency detected | Prompt user to adjust dependencies, re-decompose | +| User feedback timeout | Save current state, display `--continue` recovery command | +| Max feedback rounds reached | Use current version to generate final artifacts | +| Session folder conflict | Append timestamp suffix | +| JSONL format error | Validate line by line, report problematic lines and fix | + +## Best Practices + +1. **Clear requirement description**: Detailed description → more accurate uncertainty assessment and decomposition +2. **Validate MVP first**: In progressive mode, L0 should be the minimum verifiable closed loop +3. **Testable convergence**: criteria must be writable as assertions or manual steps; definition_of_done should be judgeable by non-technical stakeholders (see Convergence Criteria in JSONL Schema Design) +4. **Agent-First for Exploration**: Delegate codebase exploration to cli-explore-agent, do not analyze directly in main flow +5. **Incremental validation**: Use `--continue` to iterate on existing roadmaps +6. **Independently executable**: Each JSONL record should be independently passable to lite-plan for execution + +## Usage Recommendations + +**Use `/workflow:req-plan-with-file` when:** +- You need to decompose a large requirement into a progressively executable roadmap +- Unsure where to start, need an MVP strategy +- Need to generate a trackable task sequence for the team +- Requirement involves multiple stages or iterations + +**Use `/workflow:lite-plan` when:** +- You have a clear single task to execute +- The requirement is already a layer/task from the roadmap +- No layered planning needed + +**Use `/workflow:collaborative-plan-with-file` when:** +- A single complex task needs multi-agent parallel planning +- Need to analyze the same task from multiple domain perspectives + +**Use `/workflow:analyze-with-file` when:** +- Need in-depth analysis of a technical problem +- Not about planning execution, but understanding and discussion + +--- + +**Now execute req-plan-with-file for**: $ARGUMENTS diff --git a/.codex/skills/analyze-with-file/EXECUTE.md b/.codex/skills/analyze-with-file/EXECUTE.md index 943e5a05..4cbd5407 100644 --- a/.codex/skills/analyze-with-file/EXECUTE.md +++ b/.codex/skills/analyze-with-file/EXECUTE.md @@ -2,214 +2,568 @@ > **Trigger**: User selects "Quick Execute" after Phase 4 completion > **Prerequisites**: `conclusions.json` + `explorations.json`/`perspectives.json` already exist -> **Core Principle**: No additional agent exploration - analysis phase has already gathered sufficient context +> **Core Principle**: No additional exploration — analysis phase has already gathered sufficient context. No CLI delegation — execute tasks directly inline. ## Execution Flow ``` -conclusions.json → quick-plan.json → User Confirmation → Serial Execution → execution-log.md +conclusions.json → execution-plan.jsonl → User Confirmation → Direct Inline Execution → execution.md + execution-events.md ``` --- -## Step 1: Generate quick-plan.json +## Step 1: Generate execution-plan.jsonl -Convert `conclusions.json` recommendations directly into executable tasks. +Convert `conclusions.json` recommendations directly into JSONL execution list. Each line is a self-contained task with convergence criteria. **Conversion Logic**: + ```javascript -const quickPlan = { - session_id: sessionId, - source: "analysis", - source_file: `${sessionFolder}/conclusions.json`, - generated_at: new Date().toISOString(), +const conclusions = JSON.parse(Read(`${sessionFolder}/conclusions.json`)) +const explorations = file_exists(`${sessionFolder}/explorations.json`) + ? JSON.parse(Read(`${sessionFolder}/explorations.json`)) + : file_exists(`${sessionFolder}/perspectives.json`) + ? JSON.parse(Read(`${sessionFolder}/perspectives.json`)) + : null - tasks: conclusions.recommendations.map((rec, index) => ({ - id: `TASK-${String(index + 1).padStart(3, '0')}`, - title: rec.action, - description: rec.rationale, - priority: rec.priority, // high/medium/low - status: "pending", - files_to_modify: extractFilesFromEvidence(rec, explorations), - depends_on: [], // Serial execution - no dependencies needed - context: { - source_conclusions: conclusions.key_conclusions, - evidence: explorations.relevant_files || perspectives.aggregated_findings - } - })), +const tasks = conclusions.recommendations.map((rec, index) => ({ + id: `TASK-${String(index + 1).padStart(3, '0')}`, + title: rec.action, + description: rec.rationale, + type: inferTaskType(rec), // fix | refactor | feature | enhancement | testing + priority: rec.priority, // high | medium | low + files_to_modify: extractFilesFromEvidence(rec, explorations), + depends_on: [], // Serial by default; add dependencies if task ordering matters + convergence: { + criteria: generateCriteria(rec), // Testable conditions + verification: generateVerification(rec), // Executable command or steps + definition_of_done: generateDoD(rec) // Business language + }, + context: { + source_conclusions: conclusions.key_conclusions, + evidence: rec.evidence || [] + } +})) - execution_mode: "serial", - total_tasks: conclusions.recommendations.length -} +// Write one task per line +const jsonlContent = tasks.map(t => JSON.stringify(t)).join('\n') +Write(`${sessionFolder}/execution-plan.jsonl`, jsonlContent) ``` +**Task Type Inference**: + +| Recommendation Pattern | Inferred Type | +|------------------------|---------------| +| "fix", "resolve", "repair" | `fix` | +| "refactor", "restructure", "extract" | `refactor` | +| "add", "implement", "create" | `feature` | +| "improve", "optimize", "enhance" | `enhancement` | +| "test", "coverage", "validate" | `testing` | + **File Extraction Logic**: - Parse evidence from `explorations.json` or `perspectives.json` -- Match recommendation action keywords to relevant_files -- If no specific files, use pattern matching from findings +- Match recommendation action keywords to `relevant_files` +- If no specific files found, use pattern matching from findings +- Include both files to modify and files as read-only context -**Output**: `${sessionFolder}/quick-plan.json` +**Convergence Generation**: + +Each task's `convergence` must satisfy quality standards (same as req-plan-with-file): + +| Field | Requirement | Bad Example | Good Example | +|-------|-------------|-------------|--------------| +| `criteria[]` | **Testable** — assertions or manual steps | `"Code works"` | `"Function returns correct result for edge cases [], null, undefined"` | +| `verification` | **Executable** — command or explicit steps | `"Check it"` | `"jest --testPathPattern=auth.test.ts && npx tsc --noEmit"` | +| `definition_of_done` | **Business language** | `"No errors"` | `"Authentication flow handles all user-facing error scenarios gracefully"` | + +```javascript +// Quality validation before writing +const vaguePatterns = /正常|正确|好|可以|没问题|works|fine|good|correct/i +tasks.forEach(task => { + task.convergence.criteria.forEach((criterion, i) => { + if (vaguePatterns.test(criterion) && criterion.length < 15) { + // Auto-fix: replace with specific condition from rec.evidence + } + }) + const technicalPatterns = /compile|build|lint|npm|npx|jest|tsc|eslint/i + if (technicalPatterns.test(task.convergence.definition_of_done)) { + // Auto-fix: rewrite in business language + } +}) +``` + +**Output**: `${sessionFolder}/execution-plan.jsonl` + +**JSONL Schema** (one task per line): + +```jsonl +{"id":"TASK-001","title":"Fix authentication token refresh","description":"Token refresh fails silently when...","type":"fix","priority":"high","files_to_modify":["src/auth/token.ts","src/middleware/auth.ts"],"depends_on":[],"convergence":{"criteria":["Token refresh returns new valid token","Expired token triggers refresh automatically","Failed refresh redirects to login"],"verification":"jest --testPathPattern=token.test.ts","definition_of_done":"Users remain logged in across token expiration without manual re-login"},"context":{"source_conclusions":[...],"evidence":[...]}} +{"id":"TASK-002","title":"Add input validation to user endpoints","description":"Missing validation allows...","type":"enhancement","priority":"medium","files_to_modify":["src/routes/user.ts","src/validators/user.ts"],"depends_on":["TASK-001"],"convergence":{"criteria":["All user inputs validated against schema","Invalid inputs return 400 with specific error message","SQL injection patterns rejected"],"verification":"jest --testPathPattern=user.validation.test.ts","definition_of_done":"All user-facing inputs are validated with clear error feedback"},"context":{"source_conclusions":[...],"evidence":[...]}} +``` --- -## Step 2: User Confirmation +## Step 2: Pre-Execution Analysis + +Validate feasibility before starting execution. Reference: unified-execute-with-file Phase 2. + +##### Step 2.1: Build Execution Order + +```javascript +const tasks = Read(`${sessionFolder}/execution-plan.jsonl`) + .split('\n').filter(l => l.trim()).map(l => JSON.parse(l)) + +// 1. Dependency validation +const taskIds = new Set(tasks.map(t => t.id)) +const errors = [] +tasks.forEach(task => { + task.depends_on.forEach(dep => { + if (!taskIds.has(dep)) errors.push(`${task.id}: depends on unknown task ${dep}`) + }) +}) + +// 2. Circular dependency detection +function detectCycles(tasks) { + const graph = new Map(tasks.map(t => [t.id, t.depends_on])) + const visited = new Set(), inStack = new Set(), cycles = [] + function dfs(node, path) { + if (inStack.has(node)) { cycles.push([...path, node].join(' → ')); return } + if (visited.has(node)) return + visited.add(node); inStack.add(node) + ;(graph.get(node) || []).forEach(dep => dfs(dep, [...path, node])) + inStack.delete(node) + } + tasks.forEach(t => { if (!visited.has(t.id)) dfs(t.id, []) }) + return cycles +} +const cycles = detectCycles(tasks) +if (cycles.length) errors.push(`Circular dependencies: ${cycles.join('; ')}`) + +// 3. Topological sort for execution order +function topoSort(tasks) { + const inDegree = new Map(tasks.map(t => [t.id, 0])) + tasks.forEach(t => t.depends_on.forEach(dep => { + inDegree.set(dep, (inDegree.get(dep) || 0)) // ensure dep exists + inDegree.set(t.id, inDegree.get(t.id) + 1) + })) + const queue = tasks.filter(t => inDegree.get(t.id) === 0).map(t => t.id) + const order = [] + while (queue.length) { + const id = queue.shift() + order.push(id) + tasks.forEach(t => { + if (t.depends_on.includes(id)) { + inDegree.set(t.id, inDegree.get(t.id) - 1) + if (inDegree.get(t.id) === 0) queue.push(t.id) + } + }) + } + return order +} +const executionOrder = topoSort(tasks) +``` + +##### Step 2.2: Analyze File Conflicts + +```javascript +// Check files modified by multiple tasks +const fileTaskMap = new Map() // file → [taskIds] +tasks.forEach(task => { + task.files_to_modify.forEach(file => { + if (!fileTaskMap.has(file)) fileTaskMap.set(file, []) + fileTaskMap.get(file).push(task.id) + }) +}) + +const conflicts = [] +fileTaskMap.forEach((taskIds, file) => { + if (taskIds.length > 1) { + conflicts.push({ file, tasks: taskIds, resolution: "Execute in dependency order" }) + } +}) + +// Check file existence +const missingFiles = [] +tasks.forEach(task => { + task.files_to_modify.forEach(file => { + if (!file_exists(file)) missingFiles.push({ file, task: task.id, action: "Will be created" }) + }) +}) +``` + +--- + +## Step 3: Initialize Execution Artifacts + +Create `execution.md` and `execution-events.md` before starting. + +##### Step 3.1: Generate execution.md + +```javascript +const executionMd = `# Execution Overview + +## Session Info +- **Session ID**: ${sessionId} +- **Plan Source**: execution-plan.jsonl (from analysis conclusions) +- **Started**: ${getUtc8ISOString()} +- **Total Tasks**: ${tasks.length} +- **Execution Mode**: Direct inline (serial) + +## Source Analysis +- **Conclusions**: ${sessionFolder}/conclusions.json +- **Explorations**: ${explorations ? 'Available' : 'N/A'} +- **Key Conclusions**: ${conclusions.key_conclusions.length} items + +## Task Overview + +| # | ID | Title | Type | Priority | Dependencies | Status | +|---|-----|-------|------|----------|--------------|--------| +${tasks.map((t, i) => `| ${i+1} | ${t.id} | ${t.title} | ${t.type} | ${t.priority} | ${t.depends_on.join(', ') || '-'} | pending |`).join('\n')} + +## Pre-Execution Analysis + +### File Conflicts +${conflicts.length + ? conflicts.map(c => `- **${c.file}**: modified by ${c.tasks.join(', ')} → ${c.resolution}`).join('\n') + : 'No file conflicts detected'} + +### Missing Files +${missingFiles.length + ? missingFiles.map(f => `- **${f.file}** (${f.task}): ${f.action}`).join('\n') + : 'All target files exist'} + +### Dependency Validation +${errors.length ? errors.map(e => `- ⚠ ${e}`).join('\n') : 'No dependency issues'} + +### Execution Order +${executionOrder.map((id, i) => `${i+1}. ${id}`).join('\n')} + +## Execution Timeline +> Updated as tasks complete + +## Execution Summary +> Updated after all tasks complete +` +Write(`${sessionFolder}/execution.md`, executionMd) +``` + +##### Step 3.2: Initialize execution-events.md + +```javascript +const eventsHeader = `# Execution Events + +**Session**: ${sessionId} +**Started**: ${getUtc8ISOString()} +**Source**: execution-plan.jsonl + +--- + +` +Write(`${sessionFolder}/execution-events.md`, eventsHeader) +``` + +--- + +## Step 4: User Confirmation Present generated plan for user approval before execution. **Confirmation Display**: - Total tasks to execute -- Task list with IDs, titles, priorities +- Task list with IDs, titles, types, priorities - Files to be modified -- Execution mode: Serial +- File conflicts and dependency warnings (if any) +- Execution order -**User Options** (ASK_USER - single select): - -| Option | Action | -|--------|--------| -| **Start Execution** | Proceed with serial execution | -| **Adjust Tasks** | Allow user to modify/remove tasks | -| **Cancel** | Cancel execution, keep quick-plan.json | - -**Adjustment Mode** (if selected): -- Display task list with checkboxes -- User can deselect tasks to skip -- User can reorder priorities -- Regenerate quick-plan.json with adjustments - ---- - -## Step 3: Serial Task Execution - -Execute tasks one by one without spawning subagents. - -**IMPORTANT**: This phase does NOT use spawn_agent. Main process executes tasks directly via CLI. - -**Execution Loop**: -``` -For each task in quick-plan.tasks: - ├─ Update task status: "in_progress" - ├─ Execute via CLI (synchronous) - ├─ Record result to execution-log.md - ├─ Update task status: "completed" | "failed" - └─ Continue to next task -``` - -**CLI Execution Pattern**: -```bash -ccw cli -p "PURPOSE: Execute task from analysis -TASK ID: ${task.id} -TASK: ${task.title} -DESCRIPTION: ${task.description} -FILES: ${task.files_to_modify.join(', ')} -CONTEXT: ${JSON.stringify(task.context)} -MODE: write -EXPECTED: Task completed, files modified as specified -" --tool codex --mode write -``` - -**Execution Behavior**: -- One task at a time (serial, no parallel agents) -- Wait for CLI completion before next task -- Record result immediately after completion -- Stop on critical failure (user can choose to continue) - ---- - -## Step 4: Record Execution Log - -Maintain `execution-log.md` as unified execution history. - -**Output**: `${sessionFolder}/execution-log.md` - -**execution-log.md Structure**: - -```markdown -# Execution Log - -## Session Info -- **Session ID**: ${sessionId} -- **Plan Source**: quick-plan.json (from analysis) -- **Started**: ${startTime} -- **Mode**: Serial Execution - -## Task Execution Timeline - -### ${timestamp} - TASK-001: ${title} -- **Status**: completed | failed -- **Duration**: ${duration}s -- **Files Modified**: ${files.join(', ')} -- **Summary**: ${resultSummary} -- **Notes**: ${issues or discoveries} - -### ${timestamp} - TASK-002: ${title} -... - -## Execution Summary -- **Total Tasks**: ${total} -- **Completed**: ${completed} -- **Failed**: ${failed} -- **Success Rate**: ${rate}% -- **Total Duration**: ${duration} -``` - -**Log Entry Fields**: - -| Field | Content | -|-------|---------| -| Timestamp | ISO format execution time | -| Task ID | TASK-XXX identifier | -| Title | Task title from plan | -| Status | completed / failed | -| Duration | Execution time in seconds | -| Files Modified | List of changed files | -| Summary | Brief result description | -| Notes | Issues discovered or special conditions | - ---- - -## Step 5: Update quick-plan.json - -After each task, update plan with execution results. - -**Task Status Updates**: ```javascript -task.status = "completed" | "failed" -task.executed_at = timestamp -task.duration = seconds -task.result = { - success: boolean, - files_modified: string[], - summary: string, - error: string | null +if (!autoYes) { + const confirmation = AskUserQuestion({ + questions: [{ + question: `Execute ${tasks.length} tasks directly?\n\nTasks:\n${tasks.map(t => + ` ${t.id}: ${t.title} (${t.priority})`).join('\n')}\n\nExecution: Direct inline, serial`, + header: "Confirm", + multiSelect: false, + options: [ + { label: "Start Execution", description: "Execute all tasks serially" }, + { label: "Adjust Tasks", description: "Modify, reorder, or remove tasks" }, + { label: "Cancel", description: "Cancel execution, keep execution-plan.jsonl" } + ] + }] + }) + // "Adjust Tasks": display task list, user deselects/reorders, regenerate execution-plan.jsonl + // "Cancel": end workflow, keep artifacts } ``` --- -## Step 6: Completion Summary +## Step 5: Direct Inline Execution -Present final execution results. +Execute tasks one by one directly using tools (Read, Edit, Write, Grep, Glob, Bash). **No CLI delegation** — main process handles all modifications. -**Summary Display**: -- Session ID and folder path -- Execution statistics (completed/failed/total) -- Success rate percentage -- Failed tasks requiring attention (if any) -- Link to execution-log.md for details +### Execution Loop -**Post-Execution Options** (ASK_USER - single select): +``` +For each taskId in executionOrder: + ├─ Load task from execution-plan.jsonl + ├─ Check dependencies satisfied (all deps completed) + ├─ Record START event to execution-events.md + ├─ Execute task directly: + │ ├─ Read target files + │ ├─ Analyze what changes are needed (using task.description + task.context) + │ ├─ Apply modifications (Edit/Write) + │ ├─ Verify convergence criteria + │ └─ Capture files_modified list + ├─ Record COMPLETE/FAIL event to execution-events.md + ├─ Update execution.md task status + ├─ Auto-commit if enabled + └─ Continue to next task (or pause on failure) +``` -| Option | Action | -|--------|--------| -| **Retry Failed** | Re-execute only failed tasks | -| **View Log** | Display execution-log.md content | -| **Create Issue** | Create issue from failed tasks | -| **Done** | End workflow | +##### Step 5.1: Task Execution + +For each task, execute directly using the AI's own tools: + +```javascript +for (const taskId of executionOrder) { + const task = tasks.find(t => t.id === taskId) + const startTime = getUtc8ISOString() + + // 1. Check dependencies + const unmetDeps = task.depends_on.filter(dep => !completedTasks.has(dep)) + if (unmetDeps.length) { + recordEvent(task, 'BLOCKED', `Unmet dependencies: ${unmetDeps.join(', ')}`) + continue + } + + // 2. Record START event + appendToEvents(`## ${getUtc8ISOString()} — ${task.id}: ${task.title} + +**Type**: ${task.type} | **Priority**: ${task.priority} +**Status**: ⏳ IN PROGRESS +**Files**: ${task.files_to_modify.join(', ')} +**Description**: ${task.description} + +### Execution Log +`) + + // 3. Execute task directly + // - Read each file in task.files_to_modify + // - Analyze what changes satisfy task.description + task.convergence.criteria + // - Apply changes using Edit (preferred) or Write (for new files) + // - Use Grep/Glob for discovery if needed + // - Use Bash for build/test verification commands + + // 4. Verify convergence + // - Run task.convergence.verification (if it's a command) + // - Check each criterion in task.convergence.criteria + // - Record verification results + + const endTime = getUtc8ISOString() + const filesModified = getModifiedFiles() // from git status or execution tracking + + // 5. Record completion event + appendToEvents(` +**Status**: ✅ COMPLETED +**Duration**: ${calculateDuration(startTime, endTime)} +**Files Modified**: ${filesModified.join(', ')} + +#### Changes Summary +${changeSummary} + +#### Convergence Verification +${task.convergence.criteria.map((c, i) => `- [${verified[i] ? 'x' : ' '}] ${c}`).join('\n')} +- **Verification**: ${verificationResult} +- **Definition of Done**: ${task.convergence.definition_of_done} + +--- +`) + + // 6. Update execution.md task status + updateTaskStatus(task.id, 'completed', filesModified, changeSummary) + + completedTasks.add(task.id) +} +``` + +##### Step 5.2: Failure Handling + +When a task fails during execution: + +```javascript +// On task failure: +appendToEvents(` +**Status**: ❌ FAILED +**Duration**: ${calculateDuration(startTime, endTime)} +**Error**: ${errorMessage} + +#### Failure Details +${failureDetails} + +#### Attempted Changes +${attemptedChanges} + +--- +`) + +updateTaskStatus(task.id, 'failed', [], errorMessage) +failedTasks.add(task.id) + +// Ask user how to proceed +if (!autoYes) { + const decision = AskUserQuestion({ + questions: [{ + question: `Task ${task.id} failed: ${errorMessage}\nHow to proceed?`, + header: "Failure", + multiSelect: false, + options: [ + { label: "Skip & Continue", description: "Skip this task, continue with next" }, + { label: "Retry", description: "Retry this task" }, + { label: "Abort", description: "Stop execution, keep progress" } + ] + }] + }) +} +``` + +##### Step 5.3: Auto-Commit (if enabled) + +After each successful task, optionally commit changes: + +```javascript +if (autoCommit && task.status === 'completed') { + // 1. Stage modified files + Bash(`git add ${filesModified.join(' ')}`) + + // 2. Generate conventional commit message + const commitType = { + fix: 'fix', refactor: 'refactor', feature: 'feat', + enhancement: 'feat', testing: 'test' + }[task.type] || 'chore' + + const scope = inferScope(filesModified) // e.g., "auth", "user", "api" + + // 3. Commit + Bash(`git commit -m "${commitType}(${scope}): ${task.title}\n\nTask: ${task.id}\nSource: ${sessionId}"`) + + appendToEvents(`**Commit**: \`${commitType}(${scope}): ${task.title}\`\n`) +} +``` + +--- + +## Step 6: Finalize Execution Artifacts + +##### Step 6.1: Update execution.md Summary + +After all tasks complete, append final summary to `execution.md`: + +```javascript +const summary = ` +## Execution Summary + +- **Completed**: ${getUtc8ISOString()} +- **Total Tasks**: ${tasks.length} +- **Succeeded**: ${completedTasks.size} +- **Failed**: ${failedTasks.size} +- **Skipped**: ${skippedTasks.size} +- **Success Rate**: ${Math.round(completedTasks.size / tasks.length * 100)}% + +### Task Results + +| ID | Title | Status | Files Modified | +|----|-------|--------|----------------| +${tasks.map(t => `| ${t.id} | ${t.title} | ${t.status} | ${(t.result?.files_modified || []).join(', ') || '-'} |`).join('\n')} + +${failedTasks.size > 0 ? `### Failed Tasks Requiring Attention + +${[...failedTasks].map(id => { + const t = tasks.find(t => t.id === id) + return `- **${t.id}**: ${t.title} — ${t.result?.error || 'Unknown error'}` +}).join('\n')} +` : ''} +### Artifacts +- **Execution Plan**: ${sessionFolder}/execution-plan.jsonl +- **Execution Overview**: ${sessionFolder}/execution.md +- **Execution Events**: ${sessionFolder}/execution-events.md +` +// Append summary to execution.md +``` + +##### Step 6.2: Finalize execution-events.md + +Append session footer: + +```javascript +appendToEvents(` +--- + +# Session Summary + +- **Session**: ${sessionId} +- **Completed**: ${getUtc8ISOString()} +- **Tasks**: ${completedTasks.size} completed, ${failedTasks.size} failed, ${skippedTasks.size} skipped +- **Total Events**: ${totalEvents} +`) +``` + +##### Step 6.3: Update execution-plan.jsonl + +Rewrite JSONL with execution results per task: + +```javascript +const updatedJsonl = tasks.map(task => JSON.stringify({ + ...task, + status: task.status, // "completed" | "failed" | "skipped" | "pending" + executed_at: task.executed_at, // ISO timestamp + result: { + success: task.status === 'completed', + files_modified: task.result?.files_modified || [], + summary: task.result?.summary || '', + error: task.result?.error || null + } +})).join('\n') +Write(`${sessionFolder}/execution-plan.jsonl`, updatedJsonl) +``` + +--- + +## Step 7: Completion & Follow-up + +Present final execution results and offer next actions. + +```javascript +// Display: session ID, statistics, failed tasks (if any), artifact paths + +if (!autoYes) { + AskUserQuestion({ + questions: [{ + question: `Execution complete: ${completedTasks.size}/${tasks.length} succeeded.\nNext step:`, + header: "Post-Execute", + multiSelect: false, + options: [ + { label: "Retry Failed", description: `Re-execute ${failedTasks.size} failed tasks` }, + { label: "View Events", description: "Display execution-events.md" }, + { label: "Create Issue", description: "Create issue from failed tasks" }, + { label: "Done", description: "End workflow" } + ] + }] + }) +} +``` + +| Selection | Action | +|-----------|--------| +| Retry Failed | Filter tasks with status "failed", re-execute in order, append retry events | +| View Events | Display execution-events.md content | +| Create Issue | `Skill(skill="issue:new", args="...")` from failed task details | +| Done | Display artifact paths, end workflow | **Retry Logic**: -- Filter tasks with status: "failed" -- Re-execute in original order -- Append retry results to execution-log.md +- Filter tasks with `status: "failed"` +- Re-execute in original dependency order +- Append retry events to execution-events.md with `[RETRY]` prefix +- Update execution.md and execution-plan.jsonl --- @@ -220,8 +574,77 @@ When Quick Execute is activated, session folder expands with: ``` {projectRoot}/.workflow/.analysis/ANL-{slug}-{date}/ ├── ... # Phase 1-4 artifacts -├── quick-plan.json # Executable task plan -└── execution-log.md # Execution history +├── execution-plan.jsonl # ⭐ JSONL execution list (one task per line, with convergence) +├── execution.md # Plan overview + task table + execution summary +└── execution-events.md # ⭐ Unified event log (all task executions with details) +``` + +| File | Purpose | +|------|---------| +| `execution-plan.jsonl` | Self-contained task list from conclusions, each line has convergence criteria | +| `execution.md` | Overview: plan source, task table, pre-execution analysis, execution timeline, final summary | +| `execution-events.md` | Chronological event stream: task start/complete/fail with details, changes, verification results | + +--- + +## execution-events.md Template + +```markdown +# Execution Events + +**Session**: ANL-xxx-2025-01-21 +**Started**: 2025-01-21T10:00:00+08:00 +**Source**: execution-plan.jsonl + +--- + +## 2025-01-21T10:01:00+08:00 — TASK-001: Fix authentication token refresh + +**Type**: fix | **Priority**: high +**Status**: ⏳ IN PROGRESS +**Files**: src/auth/token.ts, src/middleware/auth.ts +**Description**: Token refresh fails silently when... + +### Execution Log +- Read src/auth/token.ts (245 lines) +- Found issue at line 89: missing await on refreshToken() +- Applied fix: added await keyword +- Read src/middleware/auth.ts (120 lines) +- Updated error handler at line 45 + +**Status**: ✅ COMPLETED +**Duration**: 45s +**Files Modified**: src/auth/token.ts, src/middleware/auth.ts + +#### Changes Summary +- Added `await` to `refreshToken()` call in token.ts:89 +- Updated error handler to propagate refresh failures in auth.ts:45 + +#### Convergence Verification +- [x] Token refresh returns new valid token +- [x] Expired token triggers refresh automatically +- [x] Failed refresh redirects to login +- **Verification**: jest --testPathPattern=token.test.ts → PASS +- **Definition of Done**: Users remain logged in across token expiration without manual re-login + +**Commit**: `fix(auth): Fix authentication token refresh` + +--- + +## 2025-01-21T10:02:30+08:00 — TASK-002: Add input validation + +**Type**: enhancement | **Priority**: medium +**Status**: ⏳ IN PROGRESS +... + +--- + +# Session Summary + +- **Session**: ANL-xxx-2025-01-21 +- **Completed**: 2025-01-21T10:05:00+08:00 +- **Tasks**: 2 completed, 0 failed, 0 skipped +- **Total Events**: 2 ``` --- @@ -230,16 +653,21 @@ When Quick Execute is activated, session folder expands with: | Situation | Action | Recovery | |-----------|--------|----------| -| Task execution fails | Record failure in execution-log.md, ask user | Retry, skip, or abort remaining tasks | -| CLI timeout | Mark task as failed with timeout reason | User can retry or skip | -| No recommendations in conclusions | Cannot generate quick-plan.json | Inform user, suggest using lite-plan instead | -| File conflict during execution | Document in execution-log.md | Resolve manually or adjust task order | +| Task execution fails | Record failure in execution-events.md, ask user | Retry, skip, or abort | +| Verification command fails | Mark criterion as unverified, continue | Note in events, manual check needed | +| No recommendations in conclusions | Cannot generate execution-plan.jsonl | Inform user, suggest lite-plan | +| File conflict during execution | Document in execution-events.md | Resolve in dependency order | +| Circular dependencies detected | Stop, report error | Fix dependencies in execution-plan.jsonl | +| All tasks fail | Record all failures, suggest analysis review | Re-run analysis or manual intervention | +| Missing target file | Attempt to create if task.type is "feature" | Log as warning for other types | --- ## Success Criteria -- All tasks executed (or explicitly skipped) -- `quick-plan.json` updated with final statuses -- `execution-log.md` contains complete history +- `execution-plan.jsonl` generated with convergence criteria per task +- `execution.md` contains plan overview, task table, pre-execution analysis, final summary +- `execution-events.md` contains chronological event stream with convergence verification +- All tasks executed (or explicitly skipped) via direct inline execution +- Each task's convergence criteria checked and recorded - User informed of results and next steps diff --git a/.codex/skills/analyze-with-file/SKILL.md b/.codex/skills/analyze-with-file/SKILL.md index 2fc8856f..47a87f7b 100644 --- a/.codex/skills/analyze-with-file/SKILL.md +++ b/.codex/skills/analyze-with-file/SKILL.md @@ -1,456 +1,382 @@ --- name: analyze-with-file -description: Interactive collaborative analysis with documented discussions, parallel subagent exploration, and evolving understanding. Parallel analysis for Codex. +description: Interactive collaborative analysis with documented discussions, inline exploration, and evolving understanding. Serial execution with no agent delegation. argument-hint: "TOPIC=\"\" [--depth=quick|standard|deep] [--continue]" --- -# Codex Analyze-With-File Workflow - -## Quick Start - -Interactive collaborative analysis workflow with **documented discussion process**. Records understanding evolution, facilitates multi-round Q&A, and uses **parallel subagent exploration** for deep analysis. - -**Core workflow**: Topic → Parallel Explore → Discuss → Document → Refine → Conclude → (Optional) Quick Execute +# Codex Analyze-With-File Prompt ## Overview -This workflow enables iterative exploration and refinement of complex topics through parallel-capable phases: +Interactive collaborative analysis workflow with **documented discussion process**. Records understanding evolution, facilitates multi-round Q&A, and uses inline search tools for deep exploration. -1. **Topic Understanding** - Parse the topic and identify analysis dimensions -2. **Parallel Exploration** - Gather codebase context via parallel subagents (up to 4) -3. **Interactive Discussion** - Multi-round Q&A with user feedback and direction adjustments -4. **Synthesis & Conclusion** - Consolidate insights and generate actionable recommendations -5. **Quick Execute** *(Optional)* - Convert conclusions to plan.json and execute serially with logging +**Core workflow**: Topic → Explore → Discuss → Document → Refine → Conclude → (Optional) Quick Execute -The key innovation is **documented discussion timeline** that captures the evolution of understanding across all phases, enabling users to track how insights develop and assumptions are corrected. +**Key features**: +- **Documented discussion timeline**: Captures understanding evolution across all phases +- **Multi-perspective analysis**: Supports up to 4 analysis perspectives (serial, inline) +- **Interactive discussion**: Multi-round Q&A with user feedback and direction adjustments +- **Quick execute**: Convert conclusions directly to executable tasks -**Codex-Specific Features**: -- Parallel subagent execution via `spawn_agent` + batch `wait({ ids: [...] })` -- Role loading via path (agent reads `~/.codex/agents/*.md` itself) -- Deep interaction with `send_input` for multi-round within single agent -- Explicit lifecycle management with `close_agent` +## Auto Mode + +When `--yes` or `-y`: Auto-confirm exploration decisions, use recommended analysis angles, skip interactive scoping. + +## Quick Start + +```bash +# Basic usage +/codex:analyze-with-file TOPIC="How to optimize this project's authentication architecture" + +# With depth selection +/codex:analyze-with-file TOPIC="Performance bottleneck analysis" --depth=deep + +# Continue existing session +/codex:analyze-with-file TOPIC="authentication architecture" --continue + +# Auto mode (skip confirmations) +/codex:analyze-with-file -y TOPIC="Caching strategy analysis" +``` + +## Target Topic + +**$TOPIC** ## Analysis Flow ``` -Session Detection - ├─ Check if analysis session exists for topic - ├─ EXISTS + discussion.md → Continue mode - └─ NOT_FOUND → New session mode +Step 0: Session Setup + ├─ Parse topic, flags (--depth, --continue, -y) + ├─ Generate session ID: ANL-{slug}-{date} + └─ Create session folder (or detect existing → continue mode) -Phase 1: Topic Understanding - ├─ Parse topic/question - ├─ Identify analysis dimensions (architecture, implementation, performance, security, concept, comparison, decision) - ├─ Initial scoping with user (focus areas, perspectives, analysis depth) +Step 1: Topic Understanding + ├─ Parse topic, identify analysis dimensions + ├─ Initial scoping with user (focus areas, perspectives, depth) └─ Initialize discussion.md -Phase 2: Parallel Exploration (Subagent Execution) - ├─ Determine exploration mode (single vs multi-perspective) - ├─ Parallel: spawn_agent × N (up to 4 perspectives) - ├─ Batch wait: wait({ ids: [agent1, agent2, ...] }) - ├─ Aggregate findings from all perspectives - ├─ Synthesize convergent/conflicting themes (if multi-perspective) - └─ Write explorations.json or perspectives.json +Step 2: Exploration (Inline, No Agents) + ├─ Detect codebase → search relevant modules, patterns + │ ├─ Read project-tech.json / project-guidelines.json (if exists) + │ └─ Use Grep, Glob, Read, mcp__ace-tool__search_context + ├─ Multi-perspective analysis (if selected, serial) + │ ├─ Single: Comprehensive analysis + │ └─ Multi (≤4): Serial per-perspective analysis with synthesis + ├─ Aggregate findings → explorations.json / perspectives.json + └─ Update discussion.md with Round 1 -Phase 3: Interactive Discussion (Multi-Round) - ├─ Present exploration findings to user - ├─ Gather user feedback (deepen, adjust direction, ask questions, complete) - ├─ Execute targeted analysis via send_input or new subagent +Step 3: Interactive Discussion (Multi-Round, max 5) + ├─ Present exploration findings + ├─ Gather user feedback + ├─ Process response: + │ ├─ Deepen → deeper inline analysis in current direction + │ ├─ Adjust → new inline analysis with adjusted focus + │ ├─ Questions → direct answers with evidence + │ └─ Complete → exit loop for synthesis ├─ Update discussion.md with each round - └─ Repeat until clarity achieved (max 5 rounds) + └─ Repeat until user selects complete or max rounds -Phase 4: Synthesis & Conclusion - ├─ Consolidate all insights and discussion rounds - ├─ Generate final conclusions with recommendations - ├─ Update discussion.md with synthesis - └─ Offer follow-up options (quick execute, create issue, generate task, export report) +Step 4: Synthesis & Conclusion + ├─ Consolidate all insights → conclusions.json + ├─ Update discussion.md with final synthesis + └─ Offer options: quick execute / create issue / generate task / export / done -Phase 5: Quick Execute (Optional - user selects "简要执行") - ├─ Convert conclusions.recommendations → quick-plan.json - ├─ Present plan for user confirmation - ├─ Serial task execution via CLI (no agent exploration) - ├─ Record each task result to execution-log.md - └─ Report completion summary with statistics +Step 5: Quick Execute (Optional - user selects) + ├─ Convert conclusions.recommendations → execution-plan.jsonl (with convergence) + ├─ Pre-execution analysis (dependencies, file conflicts, execution order) + ├─ User confirmation + ├─ Direct inline execution (Read/Edit/Write/Grep/Glob/Bash) + ├─ Record events → execution-events.md, update execution.md + └─ Report completion summary ``` -## Output Structure +## Configuration -``` -{projectRoot}/.workflow/.analysis/ANL-{slug}-{date}/ -├── discussion.md # ⭐ Evolution of understanding & discussions -├── exploration-codebase.json # Phase 2: Codebase context (single perspective) -├── explorations/ # Phase 2: Multi-perspective explorations (if selected) -│ ├── technical.json -│ ├── architectural.json -│ └── ... -├── explorations.json # Phase 2: Single perspective findings -├── perspectives.json # Phase 2: Multi-perspective findings with synthesis -├── conclusions.json # Phase 4: Final synthesis with recommendations -├── quick-plan.json # Phase 5: Executable task plan (if quick execute) -└── execution-log.md # Phase 5: Execution history (if quick execute) -``` +| Flag | Default | Description | +|------|---------|-------------| +| `-y, --yes` | false | Auto-confirm all decisions | +| `--continue` | false | Continue existing session | +| `--depth` | standard | Analysis depth: quick / standard / deep | -## Output Artifacts - -### Phase 1: Topic Understanding - -| Artifact | Purpose | -|----------|---------| -| `discussion.md` | Initialized with session metadata and initial questions | -| Session variables | Topic slug, dimensions, focus areas, perspectives, analysis depth | - -### Phase 2: Parallel Exploration - -| Artifact | Purpose | -|----------|---------| -| `exploration-codebase.json` | Single perspective: Codebase context (relevant files, patterns, constraints) | -| `explorations/*.json` | Multi-perspective: Individual exploration results per perspective | -| `explorations.json` | Single perspective: Aggregated findings | -| `perspectives.json` | Multi-perspective: Findings with synthesis (convergent/conflicting themes) | -| Updated `discussion.md` | Round 1: Exploration results and initial analysis | - -### Phase 3: Interactive Discussion - -| Artifact | Purpose | -|----------|---------| -| Updated `discussion.md` | Round N (2-5): User feedback, direction adjustments, corrected assumptions | -| Subagent analysis results | Deepened analysis, adjusted perspective, or specific question answers | - -### Phase 4: Synthesis & Conclusion - -| Artifact | Purpose | -|----------|---------| -| `conclusions.json` | Final synthesis: key conclusions, recommendations, open questions | -| Final `discussion.md` | Complete analysis timeline with conclusions and final understanding | - -### Phase 5: Quick Execute (Optional) - -| Artifact | Purpose | -|----------|---------| -| `quick-plan.json` | Executable task plan converted from recommendations | -| `execution-log.md` | Unified execution history with task results and statistics | - ---- +**Session ID format**: `ANL-{slug}-{YYYY-MM-DD}` +- slug: lowercase, alphanumeric + CJK characters, max 40 chars +- date: YYYY-MM-DD (UTC+8) +- Auto-detect continue: session folder + discussion.md exists → continue mode ## Implementation Details ### Session Initialization -##### Step 0: Determine Project Root +##### Step 0: Initialize Session -检测项目根目录,确保 `.workflow/` 产物位置正确: +```javascript +const getUtc8ISOString = () => new Date(Date.now() + 8 * 60 * 60 * 1000).toISOString() -```bash -PROJECT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd) +// Parse flags +const autoYes = $ARGUMENTS.includes('--yes') || $ARGUMENTS.includes('-y') +const continueMode = $ARGUMENTS.includes('--continue') +const depthMatch = $ARGUMENTS.match(/--depth[=\s](quick|standard|deep)/) +const analysisDepth = depthMatch ? depthMatch[1] : 'standard' + +// Extract topic +const topic = $ARGUMENTS.replace(/--yes|-y|--continue|--depth[=\s]\w+|TOPIC=/g, '').replace(/^["']|["']$/g, '').trim() + +// Determine project root +const projectRoot = Bash('git rev-parse --show-toplevel 2>/dev/null || pwd').trim() + +const slug = topic.toLowerCase().replace(/[^a-z0-9\u4e00-\u9fa5]+/g, '-').substring(0, 40) +const dateStr = getUtc8ISOString().substring(0, 10) +const sessionId = `ANL-${slug}-${dateStr}` +const sessionFolder = `${projectRoot}/.workflow/.analysis/${sessionId}` + +// Auto-detect continue: session folder + discussion.md exists → continue mode +// If continue → load discussion.md + explorations, resume from last round +Bash(`mkdir -p ${sessionFolder}`) ``` -优先通过 git 获取仓库根目录;非 git 项目回退到 `pwd` 取当前绝对路径。 -存储为 `{projectRoot}`,后续所有 `.workflow/` 路径必须以此为前缀。 - -The workflow automatically generates a unique session identifier and directory structure based on the topic and current date (UTC+8). - -**Session ID Format**: `ANL-{slug}-{date}` -- `slug`: Lowercase alphanumeric + Chinese characters, max 40 chars (derived from topic) -- `date`: YYYY-MM-DD format (UTC+8) - -**Session Directory**: `{projectRoot}/.workflow/.analysis/{sessionId}/` - -**Auto-Detection**: If session folder exists with discussion.md, automatically enters continue mode. Otherwise, creates new session. - -**Session Variables**: -- `sessionId`: Unique identifier -- `sessionFolder`: Base directory for artifacts -- `mode`: "new" or "continue" -- `dimensions`: Analysis focus areas -- `focusAreas`: User-selected focus areas -- `analysisDepth`: quick|standard|deep - ---- - -## Phase 1: Topic Understanding +### Phase 1: Topic Understanding **Objective**: Parse the topic, identify relevant analysis dimensions, scope the analysis with user input, and initialize the discussion document. -### Step 1.1: Parse Topic & Identify Dimensions +##### Step 1.1: Parse Topic & Identify Dimensions -The workflow analyzes the topic text against predefined analysis dimensions to determine relevant focus areas. +Match topic keywords against analysis dimensions: -**Analysis Dimensions and Keywords**: +```javascript +const ANALYSIS_DIMENSIONS = { + architecture: ['架构', 'architecture', 'design', 'structure', '设计', 'pattern'], + implementation: ['实现', 'implement', 'code', 'coding', '代码', 'logic'], + performance: ['性能', 'performance', 'optimize', 'bottleneck', '优化', 'speed'], + security: ['安全', 'security', 'auth', 'permission', '权限', 'vulnerability'], + concept: ['概念', 'concept', 'theory', 'principle', '原理', 'understand'], + comparison: ['比较', 'compare', 'vs', 'difference', '区别', 'versus'], + decision: ['决策', 'decision', 'choice', 'tradeoff', '选择', 'trade-off'] +} -| Dimension | Keywords | -|-----------|----------| -| architecture | 架构, architecture, design, structure, 设计, pattern | -| implementation | 实现, implement, code, coding, 代码, logic | -| performance | 性能, performance, optimize, bottleneck, 优化, speed | -| security | 安全, security, auth, permission, 权限, vulnerability | -| concept | 概念, concept, theory, principle, 原理, understand | -| comparison | 比较, compare, vs, difference, 区别, versus | -| decision | 决策, decision, choice, tradeoff, 选择, trade-off | +// Match topic text against keyword lists +// If multiple dimensions match, include all +// If none match, default to "architecture" and "implementation" +const dimensions = identifyDimensions(topic, ANALYSIS_DIMENSIONS) +``` -**Matching Logic**: Compare topic text against keyword lists. If multiple dimensions match, include all. If none match, default to "architecture" and "implementation". +##### Step 1.2: Initial Scoping (New Session Only) -### Step 1.2: Initial Scoping (New Session Only) +For new sessions, gather user preferences (skipped in auto mode or continue mode): -For new analysis sessions, gather user preferences before exploration: +```javascript +if (!autoYes && !continueMode) { + // 1. Focus areas (multi-select) + // Generate directions dynamically from detected dimensions (see Dimension-Direction Mapping) + const focusAreas = AskUserQuestion({ + questions: [{ + question: "Select analysis focus areas:", + header: "Focus", + multiSelect: true, + options: generateFocusOptions(dimensions) // Dynamic based on dimensions + }] + }) -**Focus Areas** (Multi-select): -- 代码实现 (Implementation details) -- 架构设计 (Architecture design) -- 最佳实践 (Best practices) -- 问题诊断 (Problem diagnosis) + // 2. Analysis perspectives (multi-select, max 4) + const perspectives = AskUserQuestion({ + questions: [{ + question: "Select analysis perspectives (single = focused, multi = broader coverage):", + header: "Perspectives", + multiSelect: true, + options: [ + { label: "Technical", description: "Implementation patterns, code structure, technical feasibility" }, + { label: "Architectural", description: "System design, scalability, component interactions" }, + { label: "Security", description: "Vulnerabilities, authentication, access control" }, + { label: "Performance", description: "Bottlenecks, optimization, resource utilization" } + ] + }] + }) -**Analysis Perspectives** (Multi-select, max 4 for parallel exploration): -- 技术视角 (Technical - implementation patterns, code structure) -- 架构视角 (Architectural - system design, component interactions) -- 安全视角 (Security - vulnerabilities, access control) -- 性能视角 (Performance - bottlenecks, optimization) + // 3. Analysis depth (single-select, unless --depth already set) + // Quick: surface level | Standard: moderate depth | Deep: comprehensive +} +``` -**Selection Note**: Single perspective = 1 subagent. Multiple perspectives = parallel subagents (up to 4). +##### Step 1.3: Initialize discussion.md -**Analysis Depth** (Single-select): -- 快速概览 (Quick overview, 10-15 minutes, 1 agent) -- 标准分析 (Standard analysis, 30-60 minutes, 1-2 agents) -- 深度挖掘 (Deep dive, 1-2+ hours, up to 4 parallel agents) +```javascript +const discussionMd = `# Analysis Discussion -### Step 1.3: Initialize discussion.md +**Session ID**: ${sessionId} +**Topic**: ${topic} +**Started**: ${getUtc8ISOString()} +**Dimensions**: ${dimensions.join(', ')} +**Depth**: ${analysisDepth} -Create the main discussion document with session metadata, context, and placeholder sections. +## Analysis Context +- Focus areas: ${focusAreas.join(', ')} +- Perspectives: ${selectedPerspectives.map(p => p.name).join(', ')} +- Depth: ${analysisDepth} -**discussion.md Structure**: -- **Header**: Session ID, topic, start time, identified dimensions -- **Analysis Context**: User-selected focus areas, depth level, scope -- **Initial Questions**: Key questions to guide the analysis -- **Discussion Timeline**: Round-by-round findings and insights -- **Current Understanding**: To be populated after exploration +## Initial Questions +${generateInitialQuestions(topic, dimensions).map(q => `- ${q}`).join('\n')} -**Key Features**: -- Serves as the primary artifact throughout the workflow -- Captures all rounds of discussion and findings -- Documents assumption corrections and insight evolution -- Enables session continuity across multiple interactions +--- + +## Discussion Timeline + +> Rounds will be appended below as analysis progresses. + +--- + +## Current Understanding + +> To be populated after exploration. +` +Write(`${sessionFolder}/discussion.md`, discussionMd) +``` **Success Criteria**: -- Session folder created successfully -- discussion.md initialized with all metadata +- Session folder created with discussion.md initialized - Analysis dimensions identified -- User preferences captured +- User preferences captured (focus, perspectives, depth) ---- +### Phase 2: Exploration -## Phase 2: Parallel Exploration +**Objective**: Gather codebase context and execute analysis to build understanding. All exploration done inline — no agent delegation. -**Objective**: Gather codebase context and execute deep analysis via parallel subagents to build understanding of the topic. +##### Step 2.1: Detect Codebase & Explore -**Execution Model**: Parallel subagent execution - spawn multiple agents for different perspectives, batch wait for all results, then aggregate. - -**Key API Pattern**: -``` -spawn_agent × N → wait({ ids: [...] }) → aggregate → close_agent × N -``` - -### Step 2.1: Determine Exploration Mode - -Based on user's perspective selection in Phase 1, choose exploration mode: - -| Mode | Condition | Subagents | Output | -|------|-----------|-----------|--------| -| Single | Default or 1 perspective selected | 1 agent | `exploration-codebase.json`, `explorations.json` | -| Multi-perspective | 2-4 perspectives selected | 2-4 agents | `explorations/*.json`, `perspectives.json` | - -### Step 2.2: Parallel Subagent Exploration - -**⚠️ IMPORTANT**: Role files are NOT read by main process. Pass path in message, agent reads itself. - -**Single Perspective Exploration**: +Search the codebase directly using available tools: ```javascript -// spawn_agent with role path (agent reads itself) -const explorationAgent = spawn_agent({ - message: ` -## TASK ASSIGNMENT +const hasCodebase = Bash(` + test -f package.json && echo "nodejs" || + test -f go.mod && echo "golang" || + test -f Cargo.toml && echo "rust" || + test -f pyproject.toml && echo "python" || + test -f pom.xml && echo "java" || + test -d src && echo "generic" || + echo "none" +`).trim() -### MANDATORY FIRST STEPS (Agent Execute) -1. **Read role definition**: ~/.codex/agents/cli-explore-agent.md (MUST read first) -2. Read: ${projectRoot}/.workflow/project-tech.json -3. Read: ${projectRoot}/.workflow/project-guidelines.json +if (hasCodebase !== 'none') { + // 1. Read project metadata (if exists) + // - .workflow/project-tech.json (tech stack info) + // - .workflow/project-guidelines.json (project conventions) ---- + // 2. Search codebase for relevant content + // Use: Grep, Glob, Read, or mcp__ace-tool__search_context + // Search based on topic keywords and identified dimensions + // Focus on: + // - Modules/components related to the topic + // - Existing patterns and code structure + // - Integration points and constraints + // - Relevant configuration and dependencies -## Analysis Context -Topic: ${topic_or_question} -Dimensions: ${dimensions.join(', ')} -Session: ${sessionFolder} - -## Exploration Tasks -1. Run: ccw tool exec get_modules_by_depth '{}' -2. Execute relevant searches based on topic keywords -3. Analyze identified files for patterns and constraints - -## Deliverables -Write findings to: ${sessionFolder}/exploration-codebase.json - -Schema: {relevant_files, patterns, constraints, integration_points, key_findings, _metadata} - -## Success Criteria -- [ ] Role definition read -- [ ] At least 5 relevant files identified -- [ ] Patterns and constraints documented -- [ ] JSON output follows schema -` -}) - -// Wait for single agent -const result = wait({ ids: [explorationAgent], timeout_ms: 600000 }) - -// Clean up -close_agent({ id: explorationAgent }) -``` - -**Multi-Perspective Parallel Exploration** (up to 4 agents): - -```javascript -// Define perspectives based on user selection -const selectedPerspectives = [ - { name: 'technical', focus: 'Implementation patterns and code structure' }, - { name: 'architectural', focus: 'System design and component interactions' }, - { name: 'security', focus: 'Security patterns and vulnerabilities' }, - { name: 'performance', focus: 'Performance bottlenecks and optimization' } -].slice(0, userSelectedCount) // Max 4 - -// Parallel spawn - all agents start immediately -const agentIds = selectedPerspectives.map(perspective => { - return spawn_agent({ - message: ` -## TASK ASSIGNMENT - -### MANDATORY FIRST STEPS (Agent Execute) -1. **Read role definition**: ~/.codex/agents/cli-explore-agent.md (MUST read first) -2. Read: ${projectRoot}/.workflow/project-tech.json -3. Read: ${projectRoot}/.workflow/project-guidelines.json - ---- - -## Analysis Context -Topic: ${topic_or_question} -Perspective: ${perspective.name} - ${perspective.focus} -Session: ${sessionFolder} - -## Perspective-Specific Exploration -Focus on ${perspective.focus} aspects of the topic. - -## Exploration Tasks -1. Run: ccw tool exec get_modules_by_depth '{}' -2. Execute searches focused on ${perspective.name} patterns -3. Identify ${perspective.name}-specific findings - -## Deliverables -Write findings to: ${sessionFolder}/explorations/${perspective.name}.json - -Schema: { - perspective: "${perspective.name}", - relevant_files, patterns, key_findings, - perspective_insights, open_questions, - _metadata + // 3. Write findings + Write(`${sessionFolder}/exploration-codebase.json`, JSON.stringify({ + project_type: hasCodebase, + relevant_files: [...], // [{path, relevance, summary}] + patterns: [...], // [{pattern, files, description}] + constraints: [...], // Architectural constraints found + integration_points: [...], // [{location, description}] + key_findings: [...], // Main insights from code search + _metadata: { timestamp: getUtc8ISOString(), exploration_scope: '...' } + }, null, 2)) } - -## Success Criteria -- [ ] Role definition read -- [ ] Perspective-specific insights identified -- [ ] At least 3 relevant findings -- [ ] JSON output follows schema -` - }) -}) - -// Batch wait - TRUE PARALLELISM (key Codex advantage) -const results = wait({ - ids: agentIds, - timeout_ms: 600000 // 10 minutes for all -}) - -// Handle timeout -if (results.timed_out) { - // Some agents may still be running - // Decide: continue waiting or use completed results -} - -// Collect results from all perspectives -const completedFindings = {} -agentIds.forEach((agentId, index) => { - const perspective = selectedPerspectives[index] - if (results.status[agentId].completed) { - completedFindings[perspective.name] = results.status[agentId].completed - } -}) - -// Batch cleanup -agentIds.forEach(id => close_agent({ id })) ``` -### Step 2.3: Aggregate Findings +##### Step 2.2: Multi-Perspective Analysis (if selected) -**Single Perspective Aggregation**: +Analyze the topic from each selected perspective. All analysis done inline by the AI. -Create `explorations.json` from single agent output: -- Extract key findings from exploration-codebase.json -- Organize by analysis dimensions -- Generate discussion points and open questions - -**Multi-Perspective Synthesis**: - -Create `perspectives.json` from parallel agent outputs: +**Single perspective** (default): ```javascript -const synthesis = { +// Analyze comprehensively across all identified dimensions +// Use exploration-codebase.json as context +// Focus on: patterns, anti-patterns, potential issues, opportunities + +const findings = { session_id: sessionId, - timestamp: new Date().toISOString(), - topic: topic_or_question, + timestamp: getUtc8ISOString(), + topic: topic, dimensions: dimensions, + sources: [...], // [{type, file, summary}] + key_findings: [...], // Main insights + discussion_points: [...], // Questions for user engagement + open_questions: [...] // Unresolved questions +} +Write(`${sessionFolder}/explorations.json`, JSON.stringify(findings, null, 2)) +``` - // Individual perspective findings - perspectives: selectedPerspectives.map(p => ({ - name: p.name, - findings: completedFindings[p.name]?.key_findings || [], - insights: completedFindings[p.name]?.perspective_insights || [], - questions: completedFindings[p.name]?.open_questions || [] - })), +**Multi-perspective** (2-4 perspectives, serial): - // Cross-perspective synthesis - synthesis: { - convergent_themes: extractConvergentThemes(completedFindings), - conflicting_views: extractConflicts(completedFindings), - unique_contributions: extractUniqueInsights(completedFindings) - }, +```javascript +// Analyze each perspective sequentially +// For each perspective: +// 1. Focus search/analysis on that perspective's concern area +// 2. Generate perspective-specific insights +// 3. Write individual findings - // Aggregated for discussion - aggregated_findings: mergeAllFindings(completedFindings), - discussion_points: generateDiscussionPoints(completedFindings), - open_questions: mergeOpenQuestions(completedFindings) +selectedPerspectives.forEach(perspective => { + // Analyze from this perspective's angle + // Use exploration-codebase.json + dimension focus + // Write to explorations/{perspective.name}.json + Write(`${sessionFolder}/explorations/${perspective.name}.json`, JSON.stringify({ + perspective: perspective.name, + relevant_files: [...], + patterns: [...], + key_findings: [...], + perspective_insights: [...], + open_questions: [...], + _metadata: { timestamp: getUtc8ISOString() } + }, null, 2)) +}) +``` + +##### Step 2.3: Aggregate Findings + +```javascript +// Single perspective → explorations.json already written +// Multi-perspective → synthesize into perspectives.json + +if (selectedPerspectives.length > 1) { + const synthesis = { + session_id: sessionId, + timestamp: getUtc8ISOString(), + topic: topic, + dimensions: dimensions, + + // Individual perspective findings + perspectives: selectedPerspectives.map(p => ({ + name: p.name, + findings: readJson(`${sessionFolder}/explorations/${p.name}.json`).key_findings, + insights: readJson(`${sessionFolder}/explorations/${p.name}.json`).perspective_insights, + questions: readJson(`${sessionFolder}/explorations/${p.name}.json`).open_questions + })), + + // Cross-perspective synthesis + synthesis: { + convergent_themes: [...], // What all perspectives agree on + conflicting_views: [...], // Where perspectives differ + unique_contributions: [...] // Insights unique to specific perspectives + }, + + aggregated_findings: [...], // Main insights across all perspectives + discussion_points: [...], // Questions for user engagement + open_questions: [...] // Unresolved questions + } + Write(`${sessionFolder}/perspectives.json`, JSON.stringify(synthesis, null, 2)) } ``` -**perspectives.json Schema**: -- `session_id`: Session identifier -- `timestamp`: Completion time -- `topic`: Original topic/question -- `dimensions[]`: Analysis dimensions -- `perspectives[]`: [{name, findings, insights, questions}] -- `synthesis`: {convergent_themes, conflicting_views, unique_contributions} -- `aggregated_findings[]`: Main insights across all perspectives -- `discussion_points[]`: Questions for user engagement -- `open_questions[]`: Unresolved questions +##### Step 2.4: Update discussion.md -### Step 2.4: Update discussion.md +Append Round 1 with exploration results: -Append Round 1 with exploration results. - -**Single Perspective Round 1**: +**Single perspective round 1**: - Sources analyzed (files, patterns) - Key findings with evidence - Discussion points for user - Open questions -**Multi-Perspective Round 1**: +**Multi-perspective round 1**: - Per-perspective summary (brief) - Synthesis section: - Convergent themes (what all perspectives agree on) @@ -460,235 +386,95 @@ Append Round 1 with exploration results. - Open questions **Success Criteria**: -- All subagents spawned and completed (or timeout handled) -- `exploration-codebase.json` OR `explorations/*.json` created -- `explorations.json` OR `perspectives.json` created with aggregated findings -- `discussion.md` updated with Round 1 results -- All agents closed properly -- Ready for interactive discussion phase +- exploration-codebase.json created with codebase context (if codebase exists) +- explorations.json (single) or perspectives.json (multi) created with findings +- discussion.md updated with Round 1 results +- Ready for interactive discussion ---- - -## Phase 3: Interactive Discussion +### Phase 3: Interactive Discussion **Objective**: Iteratively refine understanding through multi-round user-guided discussion cycles. **Max Rounds**: 5 discussion rounds (can exit earlier if user indicates analysis is complete) -**Execution Model**: Use `send_input` for deep interaction within same agent context, or spawn new agent for significantly different analysis angles. +##### Step 3.1: Present Findings & Gather Feedback -### Step 3.1: Present Findings & Gather Feedback - -Display current understanding and exploration findings to the user. - -**Presentation Content**: -- Current understanding summary -- Key findings from exploration -- Open questions or areas needing clarification -- Available action options - -**User Feedback Options** (ASK_USER - single select): - -| Option | Purpose | Next Action | -|--------|---------|------------| -| **继续深入** | Analysis direction is correct, deepen investigation | `send_input` to existing agent OR spawn new deepening agent | -| **调整方向** | Different understanding or focus needed | Spawn new agent with adjusted focus | -| **有具体问题** | Specific questions to ask about the topic | `send_input` with specific questions OR spawn Q&A agent | -| **分析完成** | Sufficient information obtained | Exit discussion loop, proceed to synthesis | - -### Step 3.2: Deepen Analysis (via send_input or new agent) - -When user selects "continue deepening", execute more detailed investigation. - -**Option A: send_input to Existing Agent** (preferred if agent still active) +Display current understanding and gather user direction: ```javascript -// Continue with existing agent context (if not closed) -send_input({ - id: explorationAgent, - message: ` -## CONTINUATION: Deepen Analysis +// Display current findings summary from explorations.json or perspectives.json +// Show key points, discussion points, open questions -Based on your initial exploration, the user wants deeper investigation. - -## Focus Areas for Deepening -${previousFindings.discussion_points.map(p => `- ${p}`).join('\n')} - -## Additional Tasks -1. Investigate edge cases and special scenarios -2. Identify patterns not yet discussed -3. Suggest implementation or improvement approaches -4. Provide risk/impact assessments - -## Deliverables -Append to: ${sessionFolder}/explorations.json (add "deepening_round_N" section) - -## Success Criteria -- [ ] Prior findings expanded with specifics -- [ ] Corner cases and limitations identified -- [ ] Concrete improvement strategies proposed -` -}) - -const deepenResult = wait({ ids: [explorationAgent], timeout_ms: 600000 }) +if (!autoYes) { + const feedback = AskUserQuestion({ + questions: [{ + question: `Analysis round ${round}: Feedback on current findings?`, + header: "Direction", + multiSelect: false, + options: [ + { label: "Deepen", description: "Analysis direction is correct, investigate deeper" }, + { label: "Adjust Direction", description: "Different understanding or focus needed" }, + { label: "Specific Questions", description: "Have specific questions to ask" }, + { label: "Analysis Complete", description: "Sufficient information obtained, proceed to synthesis" } + ] + }] + }) +} ``` -**Option B: Spawn New Deepening Agent** (if prior agent closed) +##### Step 3.2: Process User Response +**Deepen** — continue analysis in current direction: ```javascript -const deepeningAgent = spawn_agent({ - message: ` -## TASK ASSIGNMENT - -### MANDATORY FIRST STEPS (Agent Execute) -1. **Read role definition**: ~/.codex/agents/cli-explore-agent.md (MUST read first) -2. Read: ${sessionFolder}/explorations.json (prior findings) -3. Read: ${projectRoot}/.workflow/project-tech.json - ---- - -## Context -Topic: ${topic_or_question} -Prior Findings Summary: ${previousFindings.key_findings.slice(0,3).join('; ')} - -## Deepening Task -Expand on prior findings with more detailed investigation. - -## Focus Areas -${previousFindings.discussion_points.map(p => `- ${p}`).join('\n')} - -## Deliverables -Update: ${sessionFolder}/explorations.json (add deepening insights) -` -}) - -const result = wait({ ids: [deepeningAgent], timeout_ms: 600000 }) -close_agent({ id: deepeningAgent }) +// Deeper inline analysis using search tools +// Investigate edge cases, special scenarios +// Identify patterns not yet discussed +// Suggest improvement approaches +// Provide risk/impact assessments +// Update explorations.json with deepening findings ``` -### Step 3.3: Adjust Direction (new agent) - -When user indicates a different focus is needed, spawn new agent with adjusted perspective. - -**Direction Adjustment Process**: -1. Ask user for adjusted focus area (via ASK_USER) -2. Spawn new agent with different dimension/perspective -3. Compare new insights with prior analysis -4. Identify what was missed and why - +**Adjust Direction** — new focus area: ```javascript -// Spawn agent with adjusted focus -const adjustedAgent = spawn_agent({ - message: ` -## TASK ASSIGNMENT - -### MANDATORY FIRST STEPS (Agent Execute) -1. **Read role definition**: ~/.codex/agents/cli-explore-agent.md (MUST read first) -2. Read: ${sessionFolder}/explorations.json (prior findings) -3. Read: ${projectRoot}/.workflow/project-tech.json - ---- - -## Context -Topic: ${topic_or_question} -Previous Focus: ${previousDimensions.join(', ')} -**New Focus**: ${userAdjustedFocus} - -## Adjusted Analysis Task -Analyze the topic from ${userAdjustedFocus} perspective. - -## Tasks -1. Identify gaps in prior analysis -2. Generate insights specific to new focus -3. Cross-reference with prior findings -4. Explain what was missed and why - -## Deliverables -Update: ${sessionFolder}/explorations.json (add adjusted_direction section) -` +// Ask user for adjusted focus +const adjustedFocus = AskUserQuestion({ + questions: [{ + question: "What should the new analysis focus be?", + header: "New Focus", + multiSelect: false, + options: [ + { label: "Code Details", description: "Deeper into implementation specifics" }, + { label: "Architecture", description: "Broader structural analysis" }, + { label: "Best Practices", description: "Industry standards and recommendations" } + ] + }] }) -const result = wait({ ids: [adjustedAgent], timeout_ms: 600000 }) -close_agent({ id: adjustedAgent }) +// Analyze from adjusted perspective using inline search +// Compare new insights with prior analysis +// Identify what was missed and why +// Update explorations.json with adjusted findings ``` -### Step 3.4: Answer Specific Questions (send_input preferred) - -When user has specific questions, address them directly. - -**Preferred: send_input to Active Agent** - +**Specific Questions** — answer directly: ```javascript -// Capture user questions first -const userQuestions = ASK_USER([{ - id: "user_questions", type: "input", - prompt: "What specific questions do you have?", - options: [/* predefined + custom */] -}]) // BLOCKS (wait for user response) - -// Send questions to active agent -send_input({ - id: activeAgent, - message: ` -## USER QUESTIONS - -Please answer the following questions based on your analysis: - -${userQuestions.map((q, i) => `Q${i+1}: ${q}`).join('\n\n')} - -## Requirements -- Answer each question directly and clearly -- Provide evidence and file references -- Rate confidence for each answer (high/medium/low) -- Suggest related investigation areas -` -}) - -const answerResult = wait({ ids: [activeAgent], timeout_ms: 300000 }) +// Capture user questions via AskUserQuestion (text input) +// Answer each question based on codebase search and analysis +// Provide evidence and file references +// Rate confidence for each answer (high/medium/low) +// Document Q&A in discussion.md ``` -**Alternative: Spawn Q&A Agent** +**Analysis Complete** — exit loop, proceed to Phase 4. -```javascript -const qaAgent = spawn_agent({ - message: ` -## TASK ASSIGNMENT +##### Step 3.3: Document Each Round -### MANDATORY FIRST STEPS (Agent Execute) -1. **Read role definition**: ~/.codex/agents/cli-explore-agent.md (MUST read first) -2. Read: ${sessionFolder}/explorations.json (context) - ---- - -## Q&A Task -Answer user's specific questions: - -${userQuestions.map((q, i) => `Q${i+1}: ${q}`).join('\n\n')} - -## Requirements -- Evidence-based answers with file references -- Confidence rating for each answer -- Suggest related investigation areas - -## Deliverables -Append to: ${sessionFolder}/explorations.json (add qa_round_N section) -` -}) - -const result = wait({ ids: [qaAgent], timeout_ms: 300000 }) -close_agent({ id: qaAgent }) -``` - -### Step 3.5: Document Each Round - -Update discussion.md with results from each discussion round. - -**Round N Sections** (Rounds 3-5): +Update discussion.md with results from each discussion round: | Section | Content | |---------|---------| | User Direction | Action taken (deepen/adjust/questions) and focus area | -| Analysis Results | Key findings, insights, next steps | +| Analysis Results | Key findings, insights, evidence with file references | | Insights | New learnings or clarifications from this round | | Corrected Assumptions | Important wrong→right transformations with explanation | | Open Items | Remaining questions or areas for future investigation | @@ -700,63 +486,42 @@ Update discussion.md with results from each discussion round. - Organized by analysis dimension - Links between rounds showing understanding evolution -**Consolidation Rules**: -- Promote confirmed insights to "What We Established" -- Track important corrections as learnings -- Focus on current understanding, not timeline details -- Avoid repeating discussion details -- Highlight key insights for future reference - **Success Criteria**: - User feedback processed for each round -- `discussion.md` updated with all rounds +- discussion.md updated with all discussion rounds - Assumptions documented and corrected -- Exit condition reached (user selects complete or max rounds reached) +- Exit condition reached (user selects complete or max rounds) ---- +### Phase 4: Synthesis & Conclusion -## Phase 4: Synthesis & Conclusion +**Objective**: Consolidate insights from all discussion rounds, generate conclusions and recommendations. -**Objective**: Consolidate insights from all discussion rounds, generate final conclusions and recommendations, and offer next steps. +##### Step 4.1: Consolidate Insights -### Step 4.1: Consolidate Insights +```javascript +const conclusions = { + session_id: sessionId, + topic: topic, + completed: getUtc8ISOString(), + total_rounds: roundCount, + summary: '...', // Executive summary + key_conclusions: [ // Main conclusions + { point: '...', evidence: '...', confidence: 'high|medium|low' } + ], + recommendations: [ // Actionable recommendations + { action: '...', rationale: '...', priority: 'high|medium|low' } + ], + open_questions: [...], // Unresolved questions + follow_up_suggestions: [ // Next steps + { type: 'issue|task|research', summary: '...' } + ] +} +Write(`${sessionFolder}/conclusions.json`, JSON.stringify(conclusions, null, 2)) +``` -Extract and synthesize all findings from the discussion timeline into coherent conclusions and recommendations. +##### Step 4.2: Final discussion.md Update -**Consolidation Activities**: -1. Review all discussion rounds and accumulated findings -2. Identify confirmed conclusions with evidence -3. Extract actionable recommendations with rationale -4. Note remaining open questions -5. Generate follow-up suggestions - -**conclusions.json Structure**: - -| Field | Purpose | -|-------|---------| -| `session_id` | Reference to analysis session | -| `topic` | Original topic/question | -| `completed` | Completion timestamp | -| `total_rounds` | Number of discussion rounds | -| `summary` | Executive summary of analysis | -| `key_conclusions[]` | Main conclusions with evidence and confidence | -| `recommendations[]` | Actionable recommendations with rationale and priority | -| `open_questions[]` | Unresolved questions for future investigation | -| `follow_up_suggestions[]` | Suggested next steps (issue/task/research) | - -**Key Conclusions Format**: -- `point`: Clear statement of the conclusion -- `evidence`: Supporting evidence or code references -- `confidence`: high|medium|low confidence level - -**Recommendations Format**: -- `action`: Specific recommended action -- `rationale`: Reasoning and benefits -- `priority`: high|medium|low priority - -### Step 4.2: Final discussion.md Update - -Append conclusions section and finalize the understanding document. +Append conclusions section and finalize: **Synthesis & Conclusions Section**: - **Executive Summary**: Overview of analysis findings @@ -772,278 +537,337 @@ Append conclusions section and finalize the understanding document. | What Was Clarified | Important corrections (~~wrong→right~~) | | Key Insights | Valuable learnings for future reference | -**Session Statistics**: -- Total discussion rounds completed -- Key findings identified -- Analysis dimensions covered -- Artifacts generated +**Session Statistics**: Total discussion rounds, key findings count, dimensions covered, artifacts generated. -**Documentation Standards**: -- Clear evidence for conclusions -- Actionable, specific recommendations -- Organized by priority and confidence -- Links to relevant code or discussions - -### Step 4.3: Post-Completion Options - -Offer user follow-up actions based on analysis results. - -**Available Options** (ASK_USER - multi-select): - -| Option | Purpose | Action | -|--------|---------|--------| -| **简要执行** | Quick execute from analysis | Jump to Phase 5: Generate quick-plan.json and execute serially | -| **创建Issue** | Create actionable issue from findings | Launch `issue:new` with conclusions summary | -| **生成任务** | Generate implementation task | Launch `workflow:lite-plan` for task breakdown | -| **导出报告** | Generate standalone analysis report | Create formatted report document | -| **完成** | No further action | End workflow | - -**Success Criteria**: -- `conclusions.json` created with complete synthesis -- `discussion.md` finalized with all conclusions -- User offered meaningful next step options -- Session complete and all artifacts available - ---- - -## Phase 5: Quick Execute (简要执行) - -**Objective**: Convert analysis conclusions directly into executable tasks and run them serially without additional exploration. - -**Trigger**: User selects "简要执行" in Phase 4 post-completion options. - -**Key Principle**: **No additional agent exploration** - analysis phase has already collected all necessary context. - -**详细规范**: 📖 [EXECUTE.md](./EXECUTE.md) - -**Flow Summary**: -``` -conclusions.json → quick-plan.json → 用户确认 → 串行CLI执行 → execution-log.md -``` - -**Steps**: -1. **Generate quick-plan.json** - Convert `conclusions.recommendations` to executable tasks -2. **User Confirmation** - Present plan, user approves / adjusts / cancels -3. **Serial Execution** - Execute tasks via CLI `--mode write`, one at a time -4. **Record Log** - Each task result appended to `execution-log.md` -5. **Update Plan** - Update `quick-plan.json` with execution statuses -6. **Completion** - Report statistics, offer retry/view log/create issue - -**Output**: -- `${sessionFolder}/quick-plan.json` - Executable task plan with statuses -- `${sessionFolder}/execution-log.md` - Unified execution history - ---- - -## Configuration - -### Analysis Perspectives - -Optional multi-perspective parallel exploration (single perspective is default, max 4): - -| Perspective | Role File | Focus | Best For | -|------------|-----------|-------|----------| -| **Technical** | `~/.codex/agents/cli-explore-agent.md` | Implementation, code patterns, technical feasibility | Understanding how and technical details | -| **Architectural** | `~/.codex/agents/cli-explore-agent.md` | System design, scalability, component interactions | Understanding structure and organization | -| **Security** | `~/.codex/agents/cli-explore-agent.md` | Security patterns, vulnerabilities, access control | Identifying security risks | -| **Performance** | `~/.codex/agents/cli-explore-agent.md` | Bottlenecks, optimization, resource utilization | Finding performance issues | - -**Selection**: User can multi-select up to 4 perspectives in Phase 1, or default to single comprehensive view. - -**Subagent Assignment**: Each perspective gets its own subagent for true parallel exploration. - -### Analysis Dimensions Reference - -Dimensions guide the scope and focus of analysis: - -| Dimension | Description | Best For | -|-----------|-------------|----------| -| architecture | System design, component interactions, design patterns | Understanding structure and organization | -| implementation | Code patterns, implementation details, algorithms | Understanding how things work technically | -| performance | Bottlenecks, optimization opportunities, resource usage | Finding and fixing performance issues | -| security | Vulnerabilities, authentication, access control | Identifying and addressing security risks | -| concept | Foundational ideas, principles, theory | Understanding fundamental mechanisms | -| comparison | Comparing solutions, evaluating alternatives | Making informed technology or approach choices | -| decision | Trade-offs, impact analysis, decision rationale | Understanding why decisions were made | - -### Analysis Depth Levels - -| Depth | Duration | Scope | Subagents | -|-------|----------|-------|-----------| -| Quick (快速概览) | 10-15 min | Surface level understanding | 1 agent, short timeout | -| Standard (标准分析) | 30-60 min | Moderate depth with good coverage | 1-2 agents | -| Deep (深度挖掘) | 1-2+ hours | Comprehensive detailed analysis | Up to 4 parallel agents | - -### Focus Areas - -Common focus areas that guide the analysis direction: - -| Focus | Description | -|-------|-------------| -| 代码实现 | Implementation details, code patterns, algorithms | -| 架构设计 | System design, component structure, design patterns | -| 最佳实践 | Industry standards, recommended approaches, patterns | -| 问题诊断 | Identifying root causes, finding issues, debugging | - ---- - -## Error Handling & Recovery - -| Situation | Action | Recovery | -|-----------|--------|----------| -| **Subagent timeout** | Check `results.timed_out`, continue `wait()` or use partial results | Reduce scope, spawn single agent instead of parallel | -| **Agent closed prematurely** | Cannot recover closed agent | Spawn new agent with prior context from explorations.json | -| **Parallel agent partial failure** | Some agents complete, some fail | Use completed results, note gaps in synthesis | -| **send_input to closed agent** | Error: agent not found | Spawn new agent with prior findings as context | -| **No relevant findings** | Broaden search keywords or adjust scope | Ask user for clarification | -| **User disengaged** | Summarize progress and offer break point | Save state, keep agents alive for resume | -| **Max rounds reached (5)** | Force synthesis phase | Highlight remaining questions in conclusions | -| **Session folder conflict** | Append timestamp suffix to session ID | Create unique folder and continue | -| **Quick execute: task fails** | Record failure in execution-log.md, ask user | Retry, skip, or abort remaining tasks | -| **Quick execute: CLI timeout** | Mark task as failed with timeout reason | User can retry or skip | -| **Quick execute: no recommendations** | Cannot generate quick-plan.json | Inform user, suggest using lite-plan instead | - -### Codex-Specific Error Patterns +##### Step 4.3: Post-Completion Options ```javascript -// Safe parallel execution with error handling -try { - const agentIds = perspectives.map(p => spawn_agent({ message: buildPrompt(p) })) - - const results = wait({ ids: agentIds, timeout_ms: 600000 }) - - if (results.timed_out) { - // Handle partial completion - const completed = agentIds.filter(id => results.status[id].completed) - const pending = agentIds.filter(id => !results.status[id].completed) - - // Option 1: Continue waiting for pending - // const moreResults = wait({ ids: pending, timeout_ms: 300000 }) - - // Option 2: Use partial results - // processPartialResults(completed, results) - } - - // Process all results - processResults(agentIds, results) - -} finally { - // ALWAYS cleanup, even on errors - agentIds.forEach(id => { - try { close_agent({ id }) } catch (e) { /* ignore */ } +if (!autoYes) { + AskUserQuestion({ + questions: [{ + question: "Analysis complete. Next step:", + header: "Next Step", + multiSelect: false, + options: [ + { label: "Quick Execute", description: "Convert recommendations to tasks and execute serially" }, + { label: "Create Issue", description: "Create GitHub Issue from conclusions" }, + { label: "Generate Task", description: "Launch lite-plan for implementation planning" }, + { label: "Export Report", description: "Generate standalone analysis report" }, + { label: "Done", description: "Save analysis only, no further action" } + ] + }] }) } ``` ---- +| Selection | Action | +|-----------|--------| +| Quick Execute | Jump to Phase 5 | +| Create Issue | `Skill(skill="issue:new", args="...")` | +| Generate Task | `Skill(skill="workflow:lite-plan", args="...")` | +| Export Report | Copy discussion.md + conclusions.json to user-specified location | +| Done | Display artifact paths, end | -## Iteration Patterns +**Success Criteria**: +- conclusions.json created with complete synthesis +- discussion.md finalized with conclusions +- User offered meaningful next step options -### First Analysis Session (Parallel Mode) +### Phase 5: Quick Execute (Optional) -``` -User initiates: TOPIC="specific question" - ├─ No session exists → New session mode - ├─ Parse topic and identify dimensions - ├─ Scope analysis with user (focus areas, perspectives, depth) - ├─ Create discussion.md - │ - ├─ Determine exploration mode: - │ ├─ Single perspective → 1 subagent - │ └─ Multi-perspective → 2-4 parallel subagents - │ - ├─ Execute parallel exploration: - │ ├─ spawn_agent × N (perspectives) - │ ├─ wait({ ids: [...] }) ← TRUE PARALLELISM - │ └─ close_agent × N - │ - ├─ Aggregate findings (+ synthesis if multi-perspective) - └─ Enter multi-round discussion loop +**Objective**: Convert analysis conclusions into JSONL execution list with convergence criteria, then execute tasks directly inline. + +**Trigger**: User selects "Quick Execute" in Phase 4. + +**Key Principle**: No additional exploration — analysis phase has already collected all necessary context. No CLI delegation — execute directly using tools. + +**Flow**: `conclusions.json → execution-plan.jsonl → User Confirmation → Direct Inline Execution → execution.md + execution-events.md` + +**Full specification**: See `EXECUTE.md` for detailed step-by-step implementation. + +##### Step 5.1: Generate execution-plan.jsonl + +Convert `conclusions.recommendations` into JSONL execution list. Each line is a self-contained task with convergence criteria: + +```javascript +const conclusions = JSON.parse(Read(`${sessionFolder}/conclusions.json`)) +const explorations = file_exists(`${sessionFolder}/explorations.json`) + ? JSON.parse(Read(`${sessionFolder}/explorations.json`)) + : file_exists(`${sessionFolder}/perspectives.json`) + ? JSON.parse(Read(`${sessionFolder}/perspectives.json`)) + : null + +const tasks = conclusions.recommendations.map((rec, index) => ({ + id: `TASK-${String(index + 1).padStart(3, '0')}`, + title: rec.action, + description: rec.rationale, + type: inferTaskType(rec), // fix | refactor | feature | enhancement | testing + priority: rec.priority, + files_to_modify: extractFilesFromEvidence(rec, explorations), + depends_on: [], + convergence: { + criteria: generateCriteria(rec), // Testable conditions + verification: generateVerification(rec), // Executable command or steps + definition_of_done: generateDoD(rec) // Business language + }, + context: { + source_conclusions: conclusions.key_conclusions, + evidence: rec.evidence || [] + } +})) + +// Validate convergence quality (same as req-plan-with-file) +// Write one task per line +Write(`${sessionFolder}/execution-plan.jsonl`, tasks.map(t => JSON.stringify(t)).join('\n')) ``` -### Continue Existing Session +##### Step 5.2: Pre-Execution Analysis -``` -User resumes: TOPIC="same topic" with --continue flag - ├─ Session exists → Continue mode - ├─ Load previous discussion.md - ├─ Load explorations.json or perspectives.json - └─ Resume from last discussion round +Validate feasibility: dependency detection, circular dependency check (DFS), topological sort for execution order, file conflict analysis. + +##### Step 5.3: Initialize Execution Artifacts + +Create `execution.md` (overview with task table, pre-execution analysis, execution timeline placeholder) and `execution-events.md` (chronological event log header). + +##### Step 5.4: User Confirmation + +```javascript +if (!autoYes) { + AskUserQuestion({ + questions: [{ + question: `Execute ${tasks.length} tasks directly?\n\nExecution: Direct inline, serial`, + header: "Confirm", + multiSelect: false, + options: [ + { label: "Start Execution", description: "Execute all tasks serially" }, + { label: "Adjust Tasks", description: "Modify, reorder, or remove tasks" }, + { label: "Cancel", description: "Cancel execution, keep execution-plan.jsonl" } + ] + }] + }) +} ``` -### Discussion Loop (Rounds 2-5) +##### Step 5.5: Direct Inline Execution -``` -Each round: - ├─ Present current findings - ├─ Gather user feedback - ├─ Process response: - │ ├─ Deepen → send_input to active agent OR spawn deepening agent - │ ├─ Adjust → spawn new agent with adjusted focus - │ ├─ Questions → send_input with questions OR spawn Q&A agent - │ └─ Complete → Exit loop for synthesis - ├─ wait({ ids: [...] }) for result - ├─ Update discussion.md - └─ Repeat until user selects complete or max rounds reached +Execute tasks one by one directly using tools (Read, Edit, Write, Grep, Glob, Bash). **No CLI delegation**. + +For each task in execution order: +1. Check dependencies satisfied +2. Record START event to `execution-events.md` +3. Execute: read files → analyze changes → apply modifications → verify convergence +4. Record COMPLETE/FAIL event with convergence verification checklist +5. Update `execution.md` task status +6. Auto-commit if enabled (conventional commit format) + +##### Step 5.6: Finalize & Follow-up + +- Update `execution.md` with final summary (statistics, task results table) +- Finalize `execution-events.md` with session footer +- Update `execution-plan.jsonl` with execution results per task + +```javascript +if (!autoYes) { + AskUserQuestion({ + questions: [{ + question: `Execution complete: ${completedTasks.size}/${tasks.length} succeeded.\nNext step:`, + header: "Post-Execute", + multiSelect: false, + options: [ + { label: "Retry Failed", description: `Re-execute ${failedTasks.size} failed tasks` }, + { label: "View Events", description: "Display execution-events.md" }, + { label: "Create Issue", description: "Create issue from failed tasks" }, + { label: "Done", description: "End workflow" } + ] + }] + }) +} ``` -### Agent Lifecycle Management +**Success Criteria**: +- `execution-plan.jsonl` generated with convergence criteria per task +- `execution.md` contains plan overview, task table, pre-execution analysis, final summary +- `execution-events.md` contains chronological event stream with convergence verification +- All tasks executed (or explicitly skipped) via direct inline execution +- User informed of results and next steps + +## Output Structure ``` -Subagent lifecycle: - ├─ spawn_agent({ message }) → Create with role path + task - ├─ wait({ ids, timeout_ms }) → Get results (ONLY way to get output) - ├─ send_input({ id, message }) → Continue interaction (if not closed) - └─ close_agent({ id }) → Cleanup (MUST do, cannot recover) - -Key rules: - ├─ NEVER close before you're done with an agent - ├─ ALWAYS use wait() to get results, NOT close_agent() - ├─ Batch wait for parallel agents: wait({ ids: [a, b, c] }) - └─ Delay close_agent until all rounds complete (for send_input reuse) +{projectRoot}/.workflow/.analysis/ANL-{slug}-{date}/ +├── discussion.md # Evolution of understanding & discussions +├── exploration-codebase.json # Phase 2: Codebase context +├── explorations/ # Phase 2: Multi-perspective explorations (if selected) +│ ├── technical.json +│ ├── architectural.json +│ └── ... +├── explorations.json # Phase 2: Single perspective aggregated findings +├── perspectives.json # Phase 2: Multi-perspective findings with synthesis +├── conclusions.json # Phase 4: Final synthesis with recommendations +├── execution-plan.jsonl # Phase 5: JSONL execution list with convergence (if quick execute) +├── execution.md # Phase 5: Execution overview + task table + summary (if quick execute) +└── execution-events.md # Phase 5: Chronological event log (if quick execute) ``` -### Completion Flow +| File | Phase | Description | +|------|-------|-------------| +| `discussion.md` | 1 | Initialized with session metadata, finalized in Phase 4 | +| `exploration-codebase.json` | 2 | Codebase context: relevant files, patterns, constraints | +| `explorations/*.json` | 2 | Per-perspective exploration results (multi only) | +| `explorations.json` | 2 | Single perspective aggregated findings | +| `perspectives.json` | 2 | Multi-perspective findings with cross-perspective synthesis | +| `conclusions.json` | 4 | Final synthesis: conclusions, recommendations, open questions | +| `execution-plan.jsonl` | 5 | JSONL execution list from recommendations, each line with convergence criteria | +| `execution.md` | 5 | Execution overview: plan source, task table, pre-execution analysis, final summary | +| `execution-events.md` | 5 | Chronological event stream with task details and convergence verification | -``` -Final synthesis: - ├─ Consolidate all insights from all rounds - ├─ Generate conclusions.json - ├─ Update discussion.md with final synthesis - ├─ close_agent for any remaining active agents - ├─ Offer follow-up options - └─ Archive session artifacts +## Analysis Dimensions Reference + +Dimensions guide the scope and focus of analysis: + +| Dimension | Keywords | Description | +|-----------|----------|-------------| +| architecture | 架构, architecture, design, structure, 设计, pattern | System design, component interactions, design patterns | +| implementation | 实现, implement, code, coding, 代码, logic | Code patterns, implementation details, algorithms | +| performance | 性能, performance, optimize, bottleneck, 优化, speed | Bottlenecks, optimization opportunities, resource usage | +| security | 安全, security, auth, permission, 权限, vulnerability | Vulnerabilities, authentication, access control | +| concept | 概念, concept, theory, principle, 原理, understand | Foundational ideas, principles, theory | +| comparison | 比较, compare, vs, difference, 区别, versus | Comparing solutions, evaluating alternatives | +| decision | 决策, decision, choice, tradeoff, 选择, trade-off | Trade-offs, impact analysis, decision rationale | + +## Analysis Perspectives + +Optional multi-perspective analysis (single perspective is default, max 4): + +| Perspective | Focus | Best For | +|------------|-------|----------| +| **Technical** | Implementation patterns, code structure, technical feasibility | Understanding how and technical details | +| **Architectural** | System design, scalability, component interactions | Understanding structure and organization | +| **Security** | Security patterns, vulnerabilities, access control | Identifying security risks | +| **Performance** | Bottlenecks, optimization, resource utilization | Finding performance issues | + +**Selection**: User can multi-select up to 4 perspectives in Phase 1, or default to single comprehensive view. + +### Analysis Depth Levels + +| Depth | Scope | Description | +|-------|-------|-------------| +| Quick | Surface level understanding | Fast overview, minimal exploration | +| Standard | Moderate depth with good coverage | Balanced analysis (default) | +| Deep | Comprehensive detailed analysis | Thorough multi-round investigation | + +## Dimension-Direction Mapping + +When user selects focus areas, generate directions dynamically from detected dimensions: + +| Dimension | Possible Directions | +|-----------|-------------------| +| architecture | System Design, Component Interactions, Technology Choices, Integration Points, Design Patterns, Scalability Strategy | +| implementation | Code Structure, Implementation Details, Code Patterns, Error Handling, Testing Approach, Algorithm Analysis | +| performance | Performance Bottlenecks, Optimization Opportunities, Resource Utilization, Caching Strategy, Concurrency Issues | +| security | Security Vulnerabilities, Authentication/Authorization, Access Control, Data Protection, Input Validation | +| concept | Conceptual Foundation, Core Mechanisms, Fundamental Patterns, Theory & Principles, Trade-offs & Reasoning | +| comparison | Solution Comparison, Pros & Cons Analysis, Technology Evaluation, Approach Differences | +| decision | Decision Criteria, Trade-off Analysis, Risk Assessment, Impact Analysis, Implementation Implications | + +**Implementation**: Present 2-3 top dimension-related directions, allow user to multi-select and add custom directions. + +## Consolidation Rules + +When updating "Current Understanding" in discussion.md: + +| Rule | Description | +|------|-------------| +| Promote confirmed insights | Move validated findings to "What We Established" | +| Track corrections | Keep important wrong→right transformations | +| Focus on current state | What do we know NOW, not the journey | +| Avoid timeline repetition | Don't copy discussion details into consolidated section | +| Preserve key learnings | Keep insights valuable for future reference | + +**Example**: + +Bad (cluttered): +```markdown +## Current Understanding +In round 1 we discussed X, then in round 2 user said Y... ``` -### Quick Execute Flow (Phase 5) +Good (consolidated): +```markdown +## Current Understanding -``` -User selects "简要执行": - ├─ Read conclusions.json + explorations.json/perspectives.json - ├─ Convert recommendations → quick-plan.json - │ └─ No agent exploration (context already gathered) - ├─ Present plan to user for confirmation - │ ├─ 开始执行 → proceed - │ ├─ 调整任务 → modify and regenerate - │ └─ 取消 → keep plan, exit - │ - ├─ Serial task execution: - │ ├─ TASK-001: CLI --mode write → record to execution-log.md - │ ├─ TASK-002: CLI --mode write → record to execution-log.md - │ └─ (repeat for all tasks) - │ - ├─ Update quick-plan.json with statuses - ├─ Finalize execution-log.md with summary - └─ Offer post-execution options (retry/view log/create issue/done) +### What We Established +- The authentication flow uses JWT with refresh tokens +- Rate limiting is implemented at API gateway level + +### What Was Clarified +- ~~Assumed Redis for sessions~~ → Actually uses database-backed sessions + +### Key Insights +- Current architecture supports horizontal scaling ``` ---- +## Templates + +### discussion.md Structure + +The discussion.md file evolves through the analysis: + +- **Header**: Session ID, topic, start time, identified dimensions +- **Analysis Context**: Focus areas, perspectives, depth level +- **Initial Questions**: Key questions to guide the analysis +- **Discussion Timeline**: Round-by-round findings + - Round 1: Initial Understanding + Exploration Results + - Round 2-N: User feedback + direction adjustments + new insights +- **Synthesis & Conclusions**: Summary, key conclusions, recommendations +- **Current Understanding (Final)**: Consolidated insights +- **Session Statistics**: Rounds completed, findings count, artifacts generated + +### Round Documentation Pattern + +Each discussion round follows a consistent structure: + +```markdown +### Round N - [Deepen|Adjust|Q&A] (timestamp) + +#### User Input +What the user indicated they wanted to focus on + +#### Analysis Results +New findings from this round's analysis +- Finding 1 (evidence: file:line) +- Finding 2 (evidence: file:line) + +#### Insights +Key learnings and clarifications + +#### Corrected Assumptions +- ~~Previous assumption~~ → Corrected understanding + - Reason: Why the assumption was wrong + +#### Open Items +Remaining questions or areas for investigation +``` + +## Error Handling + +| Situation | Action | Recovery | +|-----------|--------|----------| +| No codebase detected | Normal flow, pure topic analysis | Proceed without exploration-codebase.json | +| Codebase search fails | Continue with available context | Note limitation in discussion.md | +| No relevant findings | Broaden search keywords | Ask user for clarification | +| User timeout in discussion | Save state, show resume command | Use `--continue` to resume | +| Max rounds reached (5) | Force synthesis phase | Highlight remaining questions in conclusions | +| Session folder conflict | Append timestamp suffix | Create unique folder and continue | +| Quick execute: task fails | Record failure in execution-events.md | User can retry, skip, or abort | +| Quick execute: verification fails | Mark criterion as unverified, continue | Note in events, manual check | +| Quick execute: no recommendations | Cannot generate execution-plan.jsonl | Suggest using lite-plan instead | ## Best Practices ### Core Principles -1. **Explicit user confirmation required before code modifications**: Any operation involving code changes (including but not limited to file creation, editing, or deletion) must first present the proposed changes to the user and obtain explicit approval before execution. The analysis phase is strictly read-only — no code modifications are permitted without user consent. +1. **Explicit user confirmation required before code modifications**: The analysis phase is strictly read-only. Any code changes (Phase 5 quick execute) require user approval. ### Before Starting Analysis @@ -1060,15 +884,6 @@ User selects "简要执行": 4. **Embrace Corrections**: Track wrong→right transformations as valuable learnings 5. **Iterate Thoughtfully**: Each discussion round should meaningfully refine understanding -### Codex Subagent Best Practices - -1. **Role Path, Not Content**: Pass `~/.codex/agents/*.md` path in message, let agent read itself -2. **Delay close_agent**: Keep agents active for `send_input` reuse during discussion rounds -3. **Batch wait**: Use `wait({ ids: [a, b, c] })` for parallel agents, not sequential waits -4. **Handle Timeouts**: Check `results.timed_out` and decide: continue waiting or use partial results -5. **Explicit Cleanup**: Always `close_agent` when done, even on errors (use try/finally pattern) -6. **send_input vs spawn**: Prefer `send_input` for same-context continuation, `spawn` for new angles - ### Documentation Practices 1. **Evidence-Based**: Every conclusion should reference specific code or patterns @@ -1076,84 +891,29 @@ User selects "简要执行": 3. **Timeline Clarity**: Use clear timestamps for traceability 4. **Evolution Tracking**: Document how understanding changed across rounds 5. **Action Items**: Generate specific, actionable recommendations -6. **Multi-Perspective Synthesis**: When using parallel perspectives, document convergent/conflicting themes +6. **Multi-Perspective Synthesis**: When using multiple perspectives, document convergent/conflicting themes ---- +## When to Use -## Templates & Examples - -### discussion.md Structure - -The discussion.md file evolves through the analysis: - -**Header Section**: -``` -Session ID, topic, start time, identified dimensions -``` - -**Context Section**: -``` -Focus areas selected by user, analysis depth, scope -``` - -**Discussion Timeline**: -``` -Round 1: Initial understanding + exploration results -Round 2: Codebase findings + CLI analysis results -Round 3-5: User feedback + direction adjustments + new insights -``` - -**Conclusions Section**: -``` -Executive summary, key conclusions, recommendations, open questions -``` - -**Final Understanding Section**: -``` -What we established (confirmed points) -What was clarified (corrected assumptions) -Key insights (valuable learnings) -``` - -### Round Documentation Pattern - -Each discussion round follows a consistent structure: - -- **Round Header**: Number, timestamp, and action taken -- **User Input**: What the user indicated they wanted to focus on -- **Analysis Results**: New findings from this round's analysis -- **Insights**: Key learnings and clarifications -- **Corrected Assumptions**: Any wrong→right transformations -- **Next Steps**: Suggested investigation paths - ---- - -## When to Use This Workflow - -### Use analyze-with-file when: +**Use analyze-with-file when:** - Exploring complex topics collaboratively with documented trail - Need multi-round iterative refinement of understanding - Decision-making requires exploring multiple perspectives - Building shared understanding before implementation - Want to document how understanding evolved -### Use Quick Execute (Phase 5) when: +**Use Quick Execute (Phase 5) when:** - Analysis conclusions contain clear, actionable recommendations -- Context is already sufficient - no additional exploration needed -- Want a streamlined analyze → plan → execute pipeline in one session +- Context is already sufficient — no additional exploration needed +- Want a streamlined analyze → JSONL plan → direct execute pipeline - Tasks are relatively independent and can be executed serially -### Use direct execution when: -- Short, focused analysis tasks (single component) -- Clear, well-defined topics with limited scope -- Quick information gathering without iteration -- Quick follow-up to existing session - -### Consider alternatives when: -- Specific bug diagnosis needed → use `workflow:debug-with-file` -- Generating new ideas/solutions → use `workflow:brainstorm-with-file` -- Complex planning with parallel perspectives → use `workflow:collaborative-plan-with-file` -- Ready to implement → use `workflow:lite-plan` +**Consider alternatives when:** +- Specific bug diagnosis needed → use `debug-with-file` +- Generating new ideas/solutions → use `brainstorm-with-file` +- Complex planning with parallel perspectives → use `collaborative-plan-with-file` +- Ready to implement → use `lite-plan` +- Requirement decomposition needed → use `req-plan-with-file` --- diff --git a/.codex/skills/collaborative-plan-with-file/SKILL.md b/.codex/skills/collaborative-plan-with-file/SKILL.md index 546489f9..822aa10a 100644 --- a/.codex/skills/collaborative-plan-with-file/SKILL.md +++ b/.codex/skills/collaborative-plan-with-file/SKILL.md @@ -1,39 +1,82 @@ --- name: collaborative-plan-with-file -description: Parallel collaborative planning with Plan Note - Multi-agent parallel task generation, unified plan-note.md, conflict detection. Codex subagent-optimized. -argument-hint: "TASK=\"\" [--max-agents=5]" +description: Serial collaborative planning with Plan Note - Multi-domain serial task generation, unified plan-note.md, conflict detection. No agent delegation. +argument-hint: "[-y|--yes] [--max-domains=5]" --- -# Codex Collaborative-Plan-With-File Workflow +# Collaborative-Plan-With-File Workflow ## Quick Start -Parallel collaborative planning workflow using **Plan Note** architecture. Spawns parallel subagents for each sub-domain, generates task plans concurrently, and detects conflicts across domains. +Serial collaborative planning workflow using **Plan Note** architecture. Analyzes requirements, identifies sub-domains, generates detailed plans per domain serially, and detects conflicts across domains. -**Core workflow**: Understand → Template → Parallel Subagent Planning → Conflict Detection → Completion +```bash +# Basic usage +/codex:collaborative-plan-with-file "Implement real-time notification system" + +# With options +/codex:collaborative-plan-with-file "Refactor authentication module" --max-domains=4 +/codex:collaborative-plan-with-file "Add payment gateway support" -y +``` + +**Core workflow**: Understand → Template → Serial Domain Planning → Conflict Detection → Completion **Key features**: -- **plan-note.md**: Shared collaborative document with pre-allocated sections -- **Parallel subagent planning**: Each sub-domain planned by its own subagent concurrently +- **plan-note.md**: Shared collaborative document with pre-allocated sections per domain +- **Serial domain planning**: Each sub-domain planned sequentially with full codebase context - **Conflict detection**: Automatic file, dependency, and strategy conflict scanning - **No merge needed**: Pre-allocated sections eliminate merge conflicts -**Codex-Specific Features**: -- Parallel subagent execution via `spawn_agent` + batch `wait({ ids: [...] })` -- Role loading via path (agent reads `~/.codex/agents/*.md` itself) -- Pre-allocated sections per agent = no write conflicts -- Explicit lifecycle management with `close_agent` +## Auto Mode + +When `--yes` or `-y`: Auto-approve splits, skip confirmations. ## Overview -This workflow enables structured planning through parallel-capable phases: +This workflow enables structured planning through sequential phases: -1. **Understanding & Template** - Analyze requirements, identify sub-domains, create plan-note.md template -2. **Parallel Planning** - Spawn subagent per sub-domain, batch wait for all results -3. **Conflict Detection** - Scan plan-note.md for conflicts across all domains -4. **Completion** - Generate human-readable plan.md summary +1. **Understanding & Template** — Analyze requirements, identify sub-domains, create plan-note.md template +2. **Serial Domain Planning** — Plan each sub-domain sequentially using direct search and analysis +3. **Conflict Detection** — Scan plan-note.md for conflicts across all domains +4. **Completion** — Generate human-readable plan.md summary -The key innovation is the **Plan Note** architecture - a shared collaborative document with pre-allocated sections per sub-domain, eliminating merge conflicts. Combined with Codex's true parallel subagent execution, all domains are planned simultaneously. +The key innovation is the **Plan Note** architecture — a shared collaborative document with pre-allocated sections per sub-domain, eliminating merge conflicts even in serial execution. + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ PLAN NOTE COLLABORATIVE PLANNING │ +├─────────────────────────────────────────────────────────────────────────┤ +│ │ +│ Phase 1: Understanding & Template Creation │ +│ ├─ Analyze requirements (inline search & analysis) │ +│ ├─ Identify 2-5 sub-domains (focus areas) │ +│ ├─ Create plan-note.md with pre-allocated sections │ +│ └─ Assign TASK ID ranges (no conflicts) │ +│ │ +│ Phase 2: Serial Domain Planning │ +│ ┌──────────────┐ │ +│ │ Domain 1 │→ Explore codebase → Generate plan.json │ +│ │ Section 1 │→ Fill task pool + evidence in plan-note.md │ +│ └──────┬───────┘ │ +│ ┌──────▼───────┐ │ +│ │ Domain 2 │→ Explore codebase → Generate plan.json │ +│ │ Section 2 │→ Fill task pool + evidence in plan-note.md │ +│ └──────┬───────┘ │ +│ ┌──────▼───────┐ │ +│ │ Domain N │→ ... │ +│ └──────────────┘ │ +│ │ +│ Phase 3: Conflict Detection (Single Source) │ +│ ├─ Parse plan-note.md (all sections) │ +│ ├─ Detect file/dependency/strategy conflicts │ +│ └─ Update plan-note.md conflict section │ +│ │ +│ Phase 4: Completion (No Merge) │ +│ ├─ Generate plan.md (human-readable) │ +│ └─ Ready for execution │ +│ │ +└─────────────────────────────────────────────────────────────────────────┘ +``` ## Output Structure @@ -41,7 +84,7 @@ The key innovation is the **Plan Note** architecture - a shared collaborative do {projectRoot}/.workflow/.planning/CPLAN-{slug}-{date}/ ├── plan-note.md # ⭐ Core: Requirements + Tasks + Conflicts ├── requirement-analysis.json # Phase 1: Sub-domain assignments -├── agents/ # Phase 2: Per-domain plans (serial) +├── domains/ # Phase 2: Per-domain plans │ ├── {domain-1}/ │ │ └── plan.json # Detailed plan │ ├── {domain-2}/ @@ -60,12 +103,12 @@ The key innovation is the **Plan Note** architecture - a shared collaborative do | `plan-note.md` | Collaborative template with pre-allocated task pool and evidence sections per domain | | `requirement-analysis.json` | Sub-domain assignments, TASK ID ranges, complexity assessment | -### Phase 2: Parallel Planning +### Phase 2: Serial Domain Planning | Artifact | Purpose | |----------|---------| -| `agents/{domain}/plan.json` | Detailed implementation plan per domain (from parallel subagent) | -| Updated `plan-note.md` | Task pool and evidence sections filled by each subagent | +| `domains/{domain}/plan.json` | Detailed implementation plan per domain | +| Updated `plan-note.md` | Task pool and evidence sections filled for each domain | ### Phase 3: Conflict Detection @@ -86,31 +129,43 @@ The key innovation is the **Plan Note** architecture - a shared collaborative do ### Session Initialization -##### Step 0: Determine Project Root +##### Step 0: Initialize Session -检测项目根目录,确保 `.workflow/` 产物位置正确: +```javascript +const getUtc8ISOString = () => new Date(Date.now() + 8 * 60 * 60 * 1000).toISOString() -```bash -PROJECT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd) +// Detect project root +const projectRoot = Bash(`git rev-parse --show-toplevel 2>/dev/null || pwd`).trim() + +// Parse arguments +const autoMode = $ARGUMENTS.includes('--yes') || $ARGUMENTS.includes('-y') +const maxDomainsMatch = $ARGUMENTS.match(/--max-domains=(\d+)/) +const maxDomains = maxDomainsMatch ? parseInt(maxDomainsMatch[1]) : 5 + +// Clean task description +const taskDescription = $ARGUMENTS + .replace(/--yes|-y|--max-domains=\d+/g, '') + .trim() + +const slug = taskDescription.toLowerCase() + .replace(/[^a-z0-9\u4e00-\u9fa5]+/g, '-') + .substring(0, 30) +const dateStr = getUtc8ISOString().substring(0, 10) +const sessionId = `CPLAN-${slug}-${dateStr}` +const sessionFolder = `${projectRoot}/.workflow/.planning/${sessionId}` + +// Auto-detect continue: session folder + plan-note.md exists → continue mode +// If continue → load existing state and resume from incomplete phase +Bash(`mkdir -p ${sessionFolder}/domains`) ``` -优先通过 git 获取仓库根目录;非 git 项目回退到 `pwd` 取当前绝对路径。 -存储为 `{projectRoot}`,后续所有 `.workflow/` 路径必须以此为前缀。 - -The workflow automatically generates a unique session identifier and directory structure. - -**Session ID Format**: `CPLAN-{slug}-{date}` -- `slug`: Lowercase alphanumeric, max 30 chars -- `date`: YYYY-MM-DD format (UTC+8) - -**Session Directory**: `{projectRoot}/.workflow/.planning/{sessionId}/` - -**Auto-Detection**: If session folder exists with plan-note.md, automatically enters continue mode. - **Session Variables**: - `sessionId`: Unique session identifier - `sessionFolder`: Base directory for all artifacts - `maxDomains`: Maximum number of sub-domains (default: 5) +- `autoMode`: Boolean for auto-confirmation + +**Auto-Detection**: If session folder exists with plan-note.md, automatically enters continue mode. --- @@ -120,13 +175,17 @@ The workflow automatically generates a unique session identifier and directory s ### Step 1.1: Analyze Task Description -Use built-in tools to understand the task scope and identify sub-domains. +Use built-in tools directly to understand the task scope and identify sub-domains. **Analysis Activities**: -1. **Extract task keywords** - Identify key terms and concepts from the task description -2. **Identify sub-domains** - Split into 2-5 parallelizable focus areas based on task complexity -3. **Assess complexity** - Evaluate overall task complexity (Low/Medium/High) -4. **Search for references** - Find related documentation, README files, and architecture guides +1. **Search for references** — Find related documentation, README files, and architecture guides + - Use: `mcp__ace-tool__search_context`, Grep, Glob, Read + - Read: `.workflow/project-tech.json`, `.workflow/project-guidelines.json` (if exists) +2. **Extract task keywords** — Identify key terms and concepts from the task description +3. **Identify ambiguities** — List any unclear points or multiple possible interpretations +4. **Clarify with user** — If ambiguities found, use AskUserQuestion for clarification +5. **Identify sub-domains** — Split into 2-{maxDomains} parallelizable focus areas based on task complexity +6. **Assess complexity** — Evaluate overall task complexity (Low/Medium/High) **Sub-Domain Identification Patterns**: @@ -138,43 +197,59 @@ Use built-in tools to understand the task scope and identify sub-domains. | Testing | 测试, 验证, QA | | Infrastructure | 部署, 基础, 运维, 配置 | -**Ambiguity Handling**: When the task description is unclear or has multiple interpretations, gather user clarification before proceeding. +**Guideline**: Prioritize identifying latest documentation (README, design docs, architecture guides). When ambiguities exist, ask user for clarification instead of assuming interpretations. ### Step 1.2: Create plan-note.md Template Generate a structured template with pre-allocated sections for each sub-domain. **plan-note.md Structure**: -- **YAML Frontmatter**: session_id, original_requirement, created_at, complexity, sub_domains, status -- **Section: 需求理解**: Core objectives, key points, constraints, split strategy -- **Section: 任务池 - {Domain N}**: Pre-allocated task section per domain (TASK-{range}) -- **Section: 依赖关系**: Auto-generated after all domains complete -- **Section: 冲突标记**: Populated in Phase 3 -- **Section: 上下文证据 - {Domain N}**: Evidence section per domain + +```yaml +--- +session_id: CPLAN-{slug}-{date} +original_requirement: "{task description}" +created_at: "{ISO timestamp}" +complexity: Low | Medium | High +sub_domains: ["{domain-1}", "{domain-2}", ...] +domain_task_id_ranges: + "{domain-1}": [1, 100] + "{domain-2}": [101, 200] +status: planning +--- +``` + +**Sections**: +- `## 需求理解` — Core objectives, key points, constraints, split strategy +- `## 任务池 - {Domain N}` — Pre-allocated task section per domain (TASK-{range}) +- `## 依赖关系` — Auto-generated after all domains complete +- `## 冲突标记` — Populated in Phase 3 +- `## 上下文证据 - {Domain N}` — Evidence section per domain **TASK ID Range Allocation**: Each domain receives a non-overlapping range of 100 IDs (e.g., Domain 1: TASK-001~100, Domain 2: TASK-101~200). ### Step 1.3: Generate requirement-analysis.json -Create the sub-domain configuration document. - -**requirement-analysis.json Structure**: - -| Field | Purpose | -|-------|---------| -| `session_id` | Session identifier | -| `original_requirement` | Task description | -| `complexity` | Low / Medium / High | -| `sub_domains[]` | Array of focus areas with descriptions | -| `sub_domains[].focus_area` | Domain name | -| `sub_domains[].description` | Domain scope description | -| `sub_domains[].task_id_range` | Non-overlapping TASK ID range | -| `sub_domains[].estimated_effort` | Effort estimate | -| `sub_domains[].dependencies` | Cross-domain dependencies | -| `total_domains` | Number of domains identified | +```javascript +Write(`${sessionFolder}/requirement-analysis.json`, JSON.stringify({ + session_id: sessionId, + original_requirement: taskDescription, + complexity: complexity, // Low | Medium | High + sub_domains: subDomains.map(sub => ({ + focus_area: sub.focus_area, + description: sub.description, + task_id_range: sub.task_id_range, + estimated_effort: sub.estimated_effort, + dependencies: sub.dependencies // cross-domain dependencies + })), + total_domains: subDomains.length +}, null, 2)) +``` **Success Criteria**: -- 2-5 clear sub-domains identified +- Latest documentation identified and referenced (if available) +- Ambiguities resolved via user clarification (if any found) +- 2-{maxDomains} clear sub-domains identified - Each sub-domain can be planned independently - Plan Note template includes all pre-allocated sections - TASK ID ranges have no overlap (100 IDs per domain) @@ -182,163 +257,134 @@ Create the sub-domain configuration document. --- -## Phase 2: Parallel Sub-Domain Planning +## Phase 2: Serial Sub-Domain Planning -**Objective**: Spawn parallel subagents for each sub-domain, generating detailed plans and updating plan-note.md concurrently. +**Objective**: Plan each sub-domain sequentially, generating detailed plans and updating plan-note.md. -**Execution Model**: Parallel subagent execution - all domains planned simultaneously via `spawn_agent` + batch `wait`. - -**Key API Pattern**: -``` -spawn_agent × N → wait({ ids: [...] }) → verify outputs → close_agent × N -``` +**Execution Model**: Serial inline execution — each domain explored and planned directly using search tools, one at a time. ### Step 2.1: User Confirmation (unless autoMode) -Display identified sub-domains and confirm before spawning agents. +Display identified sub-domains and confirm before starting. ```javascript -// User confirmation if (!autoMode) { - // Display sub-domains for user approval - // Options: "开始规划" / "调整拆分" / "取消" + AskUserQuestion({ + questions: [{ + question: `已识别 ${subDomains.length} 个子领域:\n${subDomains.map((s, i) => + `${i+1}. ${s.focus_area}: ${s.description}`).join('\n')}\n\n确认开始规划?`, + header: "Confirm", + multiSelect: false, + options: [ + { label: "开始规划", description: "逐域进行规划" }, + { label: "调整拆分", description: "修改子领域划分" }, + { label: "取消", description: "退出规划" } + ] + }] + }) } ``` -### Step 2.2: Parallel Subagent Planning +### Step 2.2: Serial Domain Planning -**⚠️ IMPORTANT**: Role files are NOT read by main process. Pass path in message, agent reads itself. - -**Spawn All Domain Agents in Parallel**: +For each sub-domain, execute the full planning cycle inline: ```javascript -// Create agent directories first -subDomains.forEach(sub => { - // mkdir: ${sessionFolder}/agents/${sub.focus_area}/ -}) +for (const sub of subDomains) { + // 1. Create domain directory + Bash(`mkdir -p ${sessionFolder}/domains/${sub.focus_area}`) -// Parallel spawn - all agents start immediately -const agentIds = subDomains.map(sub => { - return spawn_agent({ - message: ` -## TASK ASSIGNMENT + // 2. Explore codebase for domain-relevant context + // Use: mcp__ace-tool__search_context, Grep, Glob, Read + // Focus on: + // - Modules/components related to this domain + // - Existing patterns to follow + // - Integration points with other domains + // - Architecture constraints -### MANDATORY FIRST STEPS (Agent Execute) -1. **Read role definition**: ~/.codex/agents/cli-lite-planning-agent.md (MUST read first) -2. Read: ${projectRoot}/.workflow/project-tech.json -3. Read: ${projectRoot}/.workflow/project-guidelines.json -4. Read: ${sessionFolder}/plan-note.md (understand template structure) -5. Read: ${sessionFolder}/requirement-analysis.json (understand full context) + // 3. Generate detailed plan.json + const plan = { + session_id: sessionId, + focus_area: sub.focus_area, + description: sub.description, + task_id_range: sub.task_id_range, + generated_at: getUtc8ISOString(), + tasks: [ + // For each task within the assigned ID range: + { + id: `TASK-${String(sub.task_id_range[0]).padStart(3, '0')}`, + title: "...", + complexity: "Low | Medium | High", + depends_on: [], // TASK-xxx references + scope: "...", // Brief scope description + modification_points: [ // file:line → change summary + { file: "...", location: "...", change: "..." } + ], + conflict_risk: "Low | Medium | High", + estimated_effort: "..." + } + // ... more tasks + ], + evidence: { + relevant_files: [...], + existing_patterns: [...], + constraints: [...] + } + } + Write(`${sessionFolder}/domains/${sub.focus_area}/plan.json`, JSON.stringify(plan, null, 2)) ---- + // 4. Sync summary to plan-note.md + // Read current plan-note.md + // Locate pre-allocated sections: + // - Task Pool: "## 任务池 - ${toTitleCase(sub.focus_area)}" + // - Evidence: "## 上下文证据 - ${toTitleCase(sub.focus_area)}" + // Fill with task summaries and evidence + // Write back plan-note.md +} +``` -## Sub-Domain Context -**Focus Area**: ${sub.focus_area} -**Description**: ${sub.description} -**TASK ID Range**: ${sub.task_id_range[0]}-${sub.task_id_range[1]} -**Session**: ${sessionId} +**Task Summary Format** (for plan-note.md task pool sections): -## Dual Output Tasks - -### Task 1: Generate Complete plan.json -Output: ${sessionFolder}/agents/${sub.focus_area}/plan.json - -Include: -- Task breakdown with IDs from assigned range (${sub.task_id_range[0]}-${sub.task_id_range[1]}) -- Dependencies within and across domains -- Files to modify with specific locations -- Effort and complexity estimates per task -- Conflict risk assessment for each task - -### Task 2: Sync Summary to plan-note.md - -**Locate Your Sections** (pre-allocated, ONLY modify these): -- Task Pool: "## 任务池 - ${toTitleCase(sub.focus_area)}" -- Evidence: "## 上下文证据 - ${toTitleCase(sub.focus_area)}" - -**Task Summary Format**: -### TASK-{ID}: {Title} [${sub.focus_area}] +```markdown +### TASK-{ID}: {Title} [{focus-area}] - **状态**: pending - **复杂度**: Low/Medium/High - **依赖**: TASK-xxx (if any) - **范围**: Brief scope description -- **修改点**: file:line - change summary +- **修改点**: `file:location`: change summary - **冲突风险**: Low/Medium/High - -**Evidence Format**: -- 相关文件: File list with relevance -- 现有模式: Patterns identified -- 约束: Constraints discovered - -## Execution Steps -1. Explore codebase for domain-relevant files -2. Generate complete plan.json -3. Extract task summaries from plan.json -4. Read ${sessionFolder}/plan-note.md -5. Locate and fill your pre-allocated task pool section -6. Locate and fill your pre-allocated evidence section -7. Write back plan-note.md - -## Important Rules -- ONLY modify your pre-allocated sections (do NOT touch other domains) -- Use assigned TASK ID range exclusively: ${sub.task_id_range[0]}-${sub.task_id_range[1]} -- Include conflict_risk assessment for each task - -## Success Criteria -- [ ] Role definition read -- [ ] plan.json generated with detailed tasks -- [ ] plan-note.md updated with task pool and evidence -- [ ] All tasks within assigned ID range -` - }) -}) - -// Batch wait - TRUE PARALLELISM (key Codex advantage) -const results = wait({ - ids: agentIds, - timeout_ms: 900000 // 15 minutes for all planning agents -}) - -// Handle timeout -if (results.timed_out) { - const completed = agentIds.filter(id => results.status[id].completed) - const pending = agentIds.filter(id => !results.status[id].completed) - - // Option: Continue waiting or use partial results - // If most agents completed, proceed with partial results -} - -// Verify outputs exist -subDomains.forEach((sub, index) => { - const agentId = agentIds[index] - if (results.status[agentId].completed) { - // Verify: agents/${sub.focus_area}/plan.json exists - // Verify: plan-note.md sections populated - } -}) - -// Batch cleanup -agentIds.forEach(id => close_agent({ id })) ``` +**Evidence Format** (for plan-note.md evidence sections): + +```markdown +- **相关文件**: file list with relevance +- **现有模式**: patterns identified +- **约束**: constraints discovered +``` + +**Domain Planning Rules**: +- Each domain modifies ONLY its pre-allocated sections in plan-note.md +- Use assigned TASK ID range exclusively +- Include `conflict_risk` assessment for each task +- Reference cross-domain dependencies explicitly + ### Step 2.3: Verify plan-note.md Consistency -After all agents complete, verify the shared document. +After all domains are planned, verify the shared document. **Verification Activities**: 1. Read final plan-note.md 2. Verify all task pool sections are populated 3. Verify all evidence sections are populated -4. Check for any accidental cross-section modifications -5. Validate TASK ID uniqueness across all domains +4. Validate TASK ID uniqueness across all domains +5. Check for any section format inconsistencies **Success Criteria**: -- All subagents spawned and completed (or timeout handled) -- `agents/{domain}/plan.json` created for each domain +- `domains/{domain}/plan.json` created for each domain - `plan-note.md` updated with all task pools and evidence sections - Task summaries follow consistent format - No TASK ID overlaps across domains -- All agents closed properly --- @@ -350,13 +396,28 @@ After all agents complete, verify the shared document. Extract all tasks from all "任务池" sections. -**Extraction Activities**: -1. Read plan-note.md content -2. Parse YAML frontmatter for session metadata -3. Identify all "任务池" sections by heading pattern -4. Extract tasks matching pattern: `### TASK-{ID}: {Title} [{domain}]` -5. Parse task details: status, complexity, dependencies, modification points, conflict risk -6. Consolidate into unified task list +```javascript +// parsePlanNote(markdown) +// - Extract YAML frontmatter between `---` markers +// - Scan for heading patterns: /^(#{2,})\s+(.+)$/ +// - Build sections array: { level, heading, start, content } +// - Return: { frontmatter, sections } + +// extractTasksFromSection(content, sectionHeading) +// - Match: /### (TASK-\d+):\s+(.+?)\s+\[(.+?)\]/ +// - For each: extract taskId, title, author +// - Parse details: status, complexity, depends_on, modification_points, conflict_risk +// - Return: array of task objects + +// parseTaskDetails(content) +// - Extract via regex: +// - /\*\*状态\*\*:\s*(.+)/ → status +// - /\*\*复杂度\*\*:\s*(.+)/ → complexity +// - /\*\*依赖\*\*:\s*(.+)/ → depends_on (extract TASK-\d+ references) +// - /\*\*冲突风险\*\*:\s*(.+)/ → conflict_risk +// - Extract modification points: /- `([^`]+):\s*([^`]+)`:\s*(.+)/ → file, location, summary +// - Return: { status, complexity, depends_on[], modification_points[], conflict_risk } +``` ### Step 3.2: Detect Conflicts @@ -370,21 +431,74 @@ Scan all tasks for three categories of conflicts. | dependency_cycle | critical | Circular dependencies in task graph (DFS detection) | Remove or reorganize dependencies | | strategy_conflict | medium | Multiple high-risk tasks in same file from different domains | Review approaches and align on single strategy | -**Detection Activities**: -1. **File Conflicts**: Group modification points by file:location, identify locations modified by multiple domains -2. **Dependency Cycles**: Build dependency graph from task dependencies, detect cycles using depth-first search -3. **Strategy Conflicts**: Group tasks by files they modify, identify files with high-risk tasks from multiple domains +**Detection Functions**: + +```javascript +// detectFileConflicts(tasks) +// Build fileMap: { "file:location": [{ task_id, task_title, source_domain, change }] } +// For each location with modifications from multiple domains: +// → conflict: type='file_conflict', severity='high' +// → include: location, tasks_involved, domains_involved, modifications +// → resolution: 'Coordinate modification order or merge changes' + +// detectDependencyCycles(tasks) +// Build dependency graph: { taskId: [dependsOn_taskIds] } +// DFS with recursion stack to detect cycles: +function detectCycles(tasks) { + const graph = new Map(tasks.map(t => [t.id, t.depends_on || []])) + const visited = new Set(), inStack = new Set(), cycles = [] + function dfs(node, path) { + if (inStack.has(node)) { cycles.push([...path, node].join(' → ')); return } + if (visited.has(node)) return + visited.add(node); inStack.add(node) + ;(graph.get(node) || []).forEach(dep => dfs(dep, [...path, node])) + inStack.delete(node) + } + tasks.forEach(t => { if (!visited.has(t.id)) dfs(t.id, []) }) + return cycles +} + +// detectStrategyConflicts(tasks) +// Group tasks by files they modify +// For each file with tasks from multiple domains: +// Filter for high/medium conflict_risk tasks +// If >1 high-risk from different domains: +// → conflict: type='strategy_conflict', severity='medium' +// → resolution: 'Review approaches and align on single strategy' +``` ### Step 3.3: Generate Conflict Artifacts Write conflict results and update plan-note.md. -**conflicts.json Structure**: -- `detected_at`: Detection timestamp -- `total_conflicts`: Number of conflicts found -- `conflicts[]`: Array of conflict objects with type, severity, tasks involved, description, suggested resolution +```javascript +// 1. Write conflicts.json +Write(`${sessionFolder}/conflicts.json`, JSON.stringify({ + detected_at: getUtc8ISOString(), + total_tasks: allTasks.length, + total_domains: subDomains.length, + total_conflicts: allConflicts.length, + conflicts: allConflicts // { type, severity, tasks_involved, description, suggested_resolution } +}, null, 2)) -**plan-note.md Update**: Locate "冲突标记" section and populate with conflict summary markdown. If no conflicts found, mark as "✅ 无冲突检测到". +// 2. Update plan-note.md "## 冲突标记" section +// generateConflictMarkdown(conflicts): +// If empty: return '✅ 无冲突检测到' +// For each conflict: +// ### CONFLICT-{padded_index}: {description} +// - **严重程度**: critical | high | medium +// - **涉及任务**: TASK-xxx, TASK-yyy +// - **涉及领域**: domain-a, domain-b +// - **问题详情**: (based on conflict type) +// - **建议解决方案**: ... +// - **决策状态**: [ ] 待解决 + +// replaceSectionContent(markdown, sectionHeading, newContent): +// Find section heading position via regex +// Find next heading of same or higher level +// Replace content between heading and next section +// If section not found: append at end +``` **Success Criteria**: - All tasks extracted and analyzed @@ -413,16 +527,85 @@ Create a human-readable summary from plan-note.md content. | 冲突报告 (Conflict Report) | Summary of detected conflicts or "无冲突" | | 执行指令 (Execution) | Command to execute the plan | +```javascript +const planMd = `# Collaborative Plan + +**Session**: ${sessionId} +**Requirement**: ${taskDescription} +**Created**: ${getUtc8ISOString()} +**Complexity**: ${complexity} +**Domains**: ${subDomains.length} + +## 需求理解 + +${requirementSection} + +## 子领域拆分 + +| # | Focus Area | Description | TASK Range | Effort | +|---|-----------|-------------|------------|--------| +${subDomains.map((s, i) => `| ${i+1} | ${s.focus_area} | ${s.description} | ${s.task_id_range[0]}-${s.task_id_range[1]} | ${s.estimated_effort} |`).join('\n')} + +## 任务概览 + +${subDomains.map(sub => { + const domainTasks = allTasks.filter(t => t.source_domain === sub.focus_area) + return `### ${sub.focus_area}\n\n` + + domainTasks.map(t => `- **${t.id}**: ${t.title} (${t.complexity}) ${t.depends_on.length ? '← ' + t.depends_on.join(', ') : ''}`).join('\n') +}).join('\n\n')} + +## 冲突报告 + +${allConflicts.length === 0 + ? '✅ 无冲突检测到' + : allConflicts.map(c => `- **${c.type}** (${c.severity}): ${c.description}`).join('\n')} + +## 执行 + +\`\`\`bash +/workflow:unified-execute-with-file "${sessionFolder}/plan-note.md" +\`\`\` + +**Session artifacts**: \`${sessionFolder}/\` +` +Write(`${sessionFolder}/plan.md`, planMd) +``` + ### Step 4.2: Display Completion Summary Present session statistics and next steps. -**Summary Content**: -- Session ID and directory path -- Total domains planned -- Total tasks generated -- Conflict status -- Execution command for next step +```javascript +// Display: +// - Session ID and directory path +// - Total domains planned +// - Total tasks generated +// - Conflict status (count and severity) +// - Execution command for next step + +if (!autoMode) { + AskUserQuestion({ + questions: [{ + question: `规划完成:\n- ${subDomains.length} 个子领域\n- ${allTasks.length} 个任务\n- ${allConflicts.length} 个冲突\n\n下一步:`, + header: "Next Step", + multiSelect: false, + options: [ + { label: "Execute Plan", description: "使用 unified-execute 执行计划" }, + { label: "Review Conflicts", description: "查看并解决冲突" }, + { label: "Export", description: "导出 plan.md" }, + { label: "Done", description: "保存产物,稍后执行" } + ] + }] + }) +} +``` + +| Selection | Action | +|-----------|--------| +| Execute Plan | `Skill(skill="workflow:unified-execute-with-file", args="${sessionFolder}/plan-note.md")` | +| Review Conflicts | Display conflicts.json content for manual resolution | +| Export | Copy plan.md + plan-note.md to user-specified location | +| Done | Display artifact paths, end workflow | **Success Criteria**: - `plan.md` generated with complete summary @@ -433,73 +616,27 @@ Present session statistics and next steps. ## Configuration -| Parameter | Default | Description | -|-----------|---------|-------------| +| Flag | Default | Description | +|------|---------|-------------| | `--max-domains` | 5 | Maximum sub-domains to identify | - ---- - -## Error Handling & Recovery - -| Situation | Action | Recovery | -|-----------|--------|----------| -| **Subagent timeout** | Check `results.timed_out`, continue `wait()` or use partial results | Reduce scope, plan remaining domains with new agent | -| **Agent closed prematurely** | Cannot recover closed agent | Spawn new agent with domain context | -| **Parallel agent partial failure** | Some domains complete, some fail | Use completed results, re-spawn for failed domains | -| **plan-note.md write conflict** | Multiple agents write simultaneously | Pre-allocated sections prevent this; if detected, re-read and verify | -| **Section not found in plan-note** | Agent creates section defensively | Continue with new section | -| **No tasks generated** | Review domain description | Retry with refined description via new agent | -| **Conflict detection fails** | Continue with empty conflicts | Note in completion summary | -| **Session folder conflict** | Append timestamp suffix | Create unique folder | - -### Codex-Specific Error Patterns - -```javascript -// Safe parallel planning with error handling -try { - const agentIds = subDomains.map(sub => spawn_agent({ message: buildPlanPrompt(sub) })) - - const results = wait({ ids: agentIds, timeout_ms: 900000 }) - - if (results.timed_out) { - const completed = agentIds.filter(id => results.status[id].completed) - const pending = agentIds.filter(id => !results.status[id].completed) - - // Re-spawn for timed-out domains - const retryIds = pending.map((id, i) => { - const sub = subDomains[agentIds.indexOf(id)] - return spawn_agent({ message: buildPlanPrompt(sub) }) - }) - - const retryResults = wait({ ids: retryIds, timeout_ms: 600000 }) - retryIds.forEach(id => { try { close_agent({ id }) } catch(e) {} }) - } - -} finally { - // ALWAYS cleanup - agentIds.forEach(id => { - try { close_agent({ id }) } catch (e) { /* ignore */ } - }) -} -``` - ---- +| `-y, --yes` | false | Auto-confirm all decisions | ## Iteration Patterns -### New Planning Session (Parallel Mode) +### New Planning Session ``` User initiates: TASK="task description" ├─ No session exists → New session mode - ├─ Analyze task and identify sub-domains + ├─ Analyze task with inline search tools + ├─ Identify sub-domains ├─ Create plan-note.md template ├─ Generate requirement-analysis.json │ - ├─ Execute parallel planning: - │ ├─ spawn_agent × N (one per sub-domain) - │ ├─ wait({ ids: [...] }) ← TRUE PARALLELISM - │ └─ close_agent × N + ├─ Serial domain planning: + │ ├─ Domain 1: explore → plan.json → fill plan-note.md + │ ├─ Domain 2: explore → plan.json → fill plan-note.md + │ └─ Domain N: ... │ ├─ Verify plan-note.md consistency ├─ Detect conflicts @@ -514,24 +651,24 @@ User resumes: TASK="same task" ├─ Session exists → Continue mode ├─ Load plan-note.md and requirement-analysis.json ├─ Identify incomplete domains (empty task pool sections) - ├─ Spawn agents for incomplete domains only + ├─ Plan remaining domains serially └─ Continue with conflict detection ``` -### Agent Lifecycle Management +--- -``` -Subagent lifecycle: - ├─ spawn_agent({ message }) → Create with role path + task - ├─ wait({ ids, timeout_ms }) → Get results (ONLY way to get output) - └─ close_agent({ id }) → Cleanup (MUST do, cannot recover) +## Error Handling & Recovery -Key rules: - ├─ Pre-allocated sections = no write conflicts - ├─ ALWAYS use wait() to get results, NOT close_agent() - ├─ Batch wait for all domain agents: wait({ ids: [a, b, c, ...] }) - └─ Verify plan-note.md after batch completion -``` +| Situation | Action | Recovery | +|-----------|--------|----------| +| No codebase detected | Normal flow, pure requirement planning | Proceed without codebase context | +| Codebase search fails | Continue with available context | Note limitation in plan-note.md | +| Domain planning fails | Record error, continue with next domain | Retry failed domain or plan manually | +| Section not found in plan-note | Create section defensively | Continue with new section | +| No tasks generated for a domain | Review domain description | Refine scope and retry | +| Conflict detection fails | Continue with empty conflicts | Note in completion summary | +| Session folder conflict | Append timestamp suffix | Create unique folder | +| plan-note.md format inconsistency | Validate and fix format after each domain | Re-read and normalize | --- @@ -540,25 +677,17 @@ Key rules: ### Before Starting Planning 1. **Clear Task Description**: Detailed requirements lead to better sub-domain splitting -2. **Reference Documentation**: Ensure latest README and design docs are identified +2. **Reference Documentation**: Ensure latest README and design docs are identified during Phase 1 3. **Clarify Ambiguities**: Resolve unclear requirements before committing to sub-domains ### During Planning -1. **Review Plan Note**: Check plan-note.md between phases to verify progress -2. **Verify Domains**: Ensure sub-domains are truly independent and parallelizable +1. **Review Plan Note**: Check plan-note.md between domains to verify progress +2. **Verify Independence**: Ensure sub-domains are truly independent and have minimal overlap 3. **Check Dependencies**: Cross-domain dependencies should be documented explicitly -4. **Inspect Details**: Review `agents/{domain}/plan.json` for specifics when needed - -### Codex Subagent Best Practices - -1. **Role Path, Not Content**: Pass `~/.codex/agents/*.md` path in message, let agent read itself -2. **Pre-allocated Sections**: Each agent only writes to its own sections - no write conflicts -3. **Batch wait**: Use `wait({ ids: [a, b, c] })` for all domain agents, not sequential waits -4. **Handle Timeouts**: Check `results.timed_out`, re-spawn for failed domains -5. **Explicit Cleanup**: Always `close_agent` when done, even on errors (use try/finally) -6. **Verify After Batch**: Read plan-note.md after all agents complete to verify consistency -7. **TASK ID Isolation**: Pre-assigned non-overlapping ranges prevent ID conflicts +4. **Inspect Details**: Review `domains/{domain}/plan.json` for specifics when needed +5. **Consistent Format**: Follow task summary format strictly across all domains +6. **TASK ID Isolation**: Use pre-assigned non-overlapping ranges to prevent ID conflicts ### After Planning @@ -566,6 +695,26 @@ Key rules: 2. **Review Summary**: Check plan.md for completeness and accuracy 3. **Validate Tasks**: Ensure all tasks have clear scope and modification targets +## When to Use + +**Use collaborative-plan-with-file when:** +- A complex task spans multiple sub-domains (backend + frontend + database, etc.) +- Need structured multi-domain task breakdown with conflict detection +- Planning a feature that touches many parts of the codebase +- Want pre-allocated section organization for clear domain separation + +**Use lite-plan when:** +- Single domain, clear task with no sub-domain splitting needed +- Quick planning without conflict detection + +**Use req-plan-with-file when:** +- Requirement-level progressive roadmap needed (MVP → iterations) +- Higher-level decomposition before detailed planning + +**Use analyze-with-file when:** +- Need in-depth analysis before planning +- Understanding and discussion, not task generation + --- -**Now execute collaborative-plan-with-file for**: $TASK +**Now execute collaborative-plan-with-file for**: $ARGUMENTS diff --git a/.codex/skills/req-plan-with-file/SKILL.md b/.codex/skills/req-plan-with-file/SKILL.md new file mode 100644 index 00000000..95f4a177 --- /dev/null +++ b/.codex/skills/req-plan-with-file/SKILL.md @@ -0,0 +1,920 @@ +--- +name: req-plan-with-file +description: Requirement-level progressive roadmap planning with JSONL output. Decomposes requirements into convergent layers (MVP→iterations) or topologically-sorted task sequences, each with testable completion criteria. +argument-hint: "[-y|--yes] [-c|--continue] [-m|--mode progressive|direct|auto] \"requirement description\"" +--- + +# Codex Req-Plan-With-File Prompt + +## Overview + +Requirement-level roadmap planning with **JSONL output and convergence criteria**. Decomposes a requirement into self-contained layers or tasks, each with testable completion criteria, independently executable via `lite-plan`. + +**Core workflow**: Requirement Understanding → Strategy Selection → Context Collection (optional) → Decomposition → Validation → Quality Check → Output + +**Dual modes**: +- **Progressive**: Layered MVP→iterations, suitable for high-uncertainty requirements (validate first, then refine) +- **Direct**: Topologically-sorted task sequence, suitable for low-uncertainty requirements (clear tasks, directly ordered) +- **Auto**: Automatically selects based on uncertainty assessment + +## Auto Mode + +When `--yes` or `-y`: Auto-confirm strategy selection, use recommended mode, skip interactive validation rounds. + +## Quick Start + +```bash +# Basic usage +/codex:req-plan-with-file "Implement user authentication system with OAuth and 2FA" + +# With mode selection +/codex:req-plan-with-file -m progressive "Build real-time notification system" +/codex:req-plan-with-file -m direct "Refactor payment module" +/codex:req-plan-with-file -m auto "Add data export feature" + +# Continue existing session +/codex:req-plan-with-file --continue "user authentication system" + +# Auto mode (skip all confirmations) +/codex:req-plan-with-file -y "Implement caching layer" +``` + +## Target Requirement + +**$ARGUMENTS** + +## Execution Process + +``` +Step 0: Session Setup + ├─ Parse flags (-y, -c, -m) and requirement text + ├─ Generate session ID: RPLAN-{slug}-{date} + └─ Create session folder (or detect existing → continue mode) + +Step 1: Parse Requirement & Select Strategy + ├─ Extract goal, constraints, stakeholders, domain keywords + ├─ Assess uncertainty (5 dimensions) + ├─ Select mode: progressive / direct + ├─ Write strategy-assessment.json + └─ Initialize roadmap.md skeleton + +Step 2: Explore Codebase (Optional) + ├─ Detect project markers (package.json, go.mod, etc.) + ├─ Has codebase → search relevant modules, patterns, integration points + │ ├─ Read project-tech.json / project-guidelines.json (if exists) + │ ├─ Search modules/components related to the requirement + │ └─ Write exploration-codebase.json + └─ No codebase → skip + +Step 3: Decompose Requirement → roadmap.jsonl + ├─ Step 3.1: Build decomposition (requirement + strategy + context) + │ ├─ Generate JSONL records with convergence criteria + │ └─ Apply convergence quality requirements + ├─ Step 3.2: Validate records + │ ├─ Schema compliance, scope integrity + │ ├─ No circular dependencies (topological sort) + │ ├─ Convergence quality (testable criteria, executable verification, business DoD) + │ └─ Write roadmap.jsonl + └─ Step 3.3: Quality check (MANDATORY) + ├─ Requirement coverage, convergence quality, scope integrity + ├─ Dependency correctness, effort balance + └─ Auto-fix or report issues + +Step 4: Validate & Finalize → roadmap.md + ├─ Display decomposition (tabular + convergence details) + ├─ User feedback loop (up to 5 rounds, skip if -y) + ├─ Write final roadmap.md + └─ Next step options: lite-plan / issue / export / done +``` + +## Configuration + +| Flag | Default | Description | +|------|---------|-------------| +| `-y, --yes` | false | Auto-confirm all decisions | +| `-c, --continue` | false | Continue existing session | +| `-m, --mode` | auto | Decomposition strategy: progressive / direct / auto | + +**Session ID format**: `RPLAN-{slug}-{YYYY-MM-DD}` +- slug: lowercase, alphanumeric + CJK characters, max 40 chars +- date: YYYY-MM-DD (UTC+8) +- Auto-detect continue: session folder + roadmap.jsonl exists → continue mode + +## Implementation Details + +### Session Setup + +##### Step 0: Initialize Session + +```javascript +const getUtc8ISOString = () => new Date(Date.now() + 8 * 60 * 60 * 1000).toISOString() + +// Parse flags +const autoYes = $ARGUMENTS.includes('--yes') || $ARGUMENTS.includes('-y') +const continueMode = $ARGUMENTS.includes('--continue') || $ARGUMENTS.includes('-c') +const modeMatch = $ARGUMENTS.match(/(?:--mode|-m)\s+(progressive|direct|auto)/) +const requestedMode = modeMatch ? modeMatch[1] : 'auto' + +// Clean requirement text +const requirement = $ARGUMENTS + .replace(/--yes|-y|--continue|-c|--mode\s+\w+|-m\s+\w+/g, '') + .trim() + +const slug = requirement.toLowerCase() + .replace(/[^a-z0-9\u4e00-\u9fa5]+/g, '-') + .substring(0, 40) +const dateStr = getUtc8ISOString().substring(0, 10) +const sessionId = `RPLAN-${slug}-${dateStr}` +const sessionFolder = `.workflow/.req-plan/${sessionId}` + +// Auto-detect continue: session folder + roadmap.jsonl exists → continue mode +// If continue → skip to Step 4 (load existing roadmap.jsonl, display, collect feedback) +Bash(`mkdir -p ${sessionFolder}`) +``` + +### Phase 1: Parse Requirement & Select Strategy + +**Objective**: Parse requirement, assess uncertainty, select decomposition strategy. + +##### Step 1.1: Analyze Requirement & Select Strategy + +Parse the requirement, evaluate uncertainty across 5 dimensions, and select decomposition strategy in one step: + +```javascript +// 1. Extract from requirement text +const goal = extractCoreGoal(requirement) // What to achieve +const constraints = extractConstraints(requirement) // Tech stack, timeline, compatibility +const stakeholders = extractStakeholders(requirement) // Users, admins, developers +const domainKeywords = extractDomainKeywords(requirement) // Domain-specific terms + +// 2. Assess uncertainty (each: low | medium | high) +const uncertaintyFactors = { + scope_clarity: '...', // Is scope well-defined? + technical_risk: '...', // Known tech vs experimental? + dependency_unknown: '...', // Are dependencies clear? + domain_familiarity: '...', // Team knows this domain? + requirement_stability: '...' // Will requirements change? +} +// >=3 high → progressive, >=3 low → direct, otherwise → ask + +// 3. Select strategy +let selectedMode +if (requestedMode !== 'auto') { + selectedMode = requestedMode +} else if (autoYes) { + selectedMode = recommendedMode +} else { + AskUserQuestion({ + questions: [{ + question: `Decomposition strategy selection:\n\nUncertainty assessment: ${uncertaintyLevel}\nRecommended strategy: ${recommendedMode}\n\nSelect decomposition strategy:`, + header: "Strategy", + multiSelect: false, + options: [ + { + label: recommendedMode === 'progressive' ? "Progressive (Recommended)" : "Progressive", + description: "Layered MVP→iterations, validate core first then refine progressively. Suitable for high-uncertainty requirements needing quick validation" + }, + { + label: recommendedMode === 'direct' ? "Direct (Recommended)" : "Direct", + description: "Topologically-sorted task sequence with explicit dependencies. Suitable for clear requirements with confirmed technical approach" + } + ] + }] + }) +} + +// 4. Write strategy assessment +Write(`${sessionFolder}/strategy-assessment.json`, JSON.stringify({ + session_id: sessionId, + requirement, timestamp: getUtc8ISOString(), + uncertainty_factors: uncertaintyFactors, + uncertainty_level: uncertaintyLevel, + recommended_mode: recommendedMode, + selected_mode: selectedMode, + goal, constraints, stakeholders, + domain_keywords: domainKeywords +}, null, 2)) + +// 5. Initialize roadmap.md skeleton +const roadmapMdSkeleton = `# Requirement Roadmap + +**Session**: ${sessionId} +**Requirement**: ${requirement} +**Strategy**: ${selectedMode} +**Status**: Planning +**Created**: ${getUtc8ISOString()} + +## Strategy Assessment +- Uncertainty level: ${uncertaintyLevel} +- Decomposition mode: ${selectedMode} +- Assessment basis: ${Object.entries(uncertaintyFactors).map(([k,v]) => `${k}=${v}`).join(', ')} + +## Roadmap +> To be populated after Phase 3 decomposition + +## Convergence Criteria Details +> To be populated after Phase 3 decomposition + +## Risk Items +> To be populated after Phase 3 decomposition + +## Next Steps +> To be populated after Phase 4 validation +` +Write(`${sessionFolder}/roadmap.md`, roadmapMdSkeleton) +``` + +**Success Criteria**: +- Requirement goal, constraints, stakeholders, domain keywords identified +- Uncertainty level assessed across 5 dimensions +- Strategy selected (progressive or direct) +- strategy-assessment.json generated +- roadmap.md skeleton initialized + +### Phase 2: Explore Codebase (Optional) + +**Objective**: If a codebase exists, collect relevant context to enhance decomposition quality. + +##### Step 2.1: Detect & Explore + +If a codebase exists, directly search for relevant context. No agent delegation — use search tools inline. + +```javascript +const hasCodebase = Bash(` + test -f package.json && echo "nodejs" || + test -f go.mod && echo "golang" || + test -f Cargo.toml && echo "rust" || + test -f pyproject.toml && echo "python" || + test -f pom.xml && echo "java" || + test -d src && echo "generic" || + echo "none" +`).trim() + +if (hasCodebase !== 'none') { + // 1. Read project metadata (if exists) + // - .workflow/project-tech.json (tech stack info) + // - .workflow/project-guidelines.json (project conventions) + + // 2. Search codebase for modules related to the requirement + // Use: Grep, Glob, Read, or mcp__ace-tool__search_context + // Focus on: + // - Modules/components related to the requirement + // - Existing patterns to follow + // - Integration points for new functionality + // - Architecture constraints + + // 3. Write findings to exploration-codebase.json: + Write(`${sessionFolder}/exploration-codebase.json`, JSON.stringify({ + project_type: hasCodebase, + relevant_modules: [...], // [{name, path, relevance}] + existing_patterns: [...], // [{pattern, files, description}] + integration_points: [...], // [{location, description, risk}] + architecture_constraints: [...], + tech_stack: {languages, frameworks, tools}, + _metadata: {timestamp: getUtc8ISOString(), exploration_scope: '...'} + }, null, 2)) +} +// No codebase → skip, proceed to Phase 3 +``` + +**Success Criteria**: +- Codebase detection complete +- When codebase exists, exploration-codebase.json generated with relevant modules, patterns, integration points +- When no codebase, skipped and proceed to Phase 3 + +### Phase 3: Decompose Requirement + +**Objective**: Execute requirement decomposition, generating validated roadmap.jsonl. + +##### Step 3.1: Generate JSONL Records + +Directly decompose the requirement into JSONL records based on the selected mode. Analyze the requirement yourself and produce the records, referencing strategy assessment and codebase context (if available). + +```javascript +// Load context +const strategy = JSON.parse(Read(`${sessionFolder}/strategy-assessment.json`)) +let explorationContext = null +if (file_exists(`${sessionFolder}/exploration-codebase.json`)) { + explorationContext = JSON.parse(Read(`${sessionFolder}/exploration-codebase.json`)) +} +``` + +**Progressive mode** — generate 2-4 layers: + +```javascript +// Each layer must have: +// - id: L0, L1, L2, L3 +// - name: MVP / Usable / Refined / Optimized +// - goal: what this layer achieves +// - scope[]: features included +// - excludes[]: features explicitly deferred +// - convergence: { criteria[], verification, definition_of_done } +// - risk_items[], effort (small|medium|large), depends_on[] +// +// Rules: +// - L0 (MVP) = self-contained closed loop, no dependencies +// - Each feature in exactly ONE layer (no overlap) +// - 2-4 layers total +// - Convergence MUST satisfy quality requirements (see below) + +const layers = [ + { + id: "L0", name: "MVP", + goal: "...", + scope: ["..."], excludes: ["..."], + convergence: { + criteria: ["... (testable)"], + verification: "... (executable command or steps)", + definition_of_done: "... (business language)" + }, + risk_items: [], effort: "medium", depends_on: [] + }, + // L1, L2, ... +] +``` + +**Direct mode** — generate topologically-sorted tasks: + +```javascript +// Each task must have: +// - id: T1, T2, ... +// - title, type (infrastructure|feature|enhancement|testing) +// - scope, inputs[], outputs[] +// - convergence: { criteria[], verification, definition_of_done } +// - depends_on[], parallel_group +// +// Rules: +// - Inputs must come from preceding task outputs or existing resources +// - Same parallel_group = truly independent +// - No circular dependencies +// - Convergence MUST satisfy quality requirements (see below) + +const tasks = [ + { + id: "T1", title: "...", type: "infrastructure", + scope: "...", inputs: [], outputs: ["..."], + convergence: { + criteria: ["... (testable)"], + verification: "... (executable)", + definition_of_done: "... (business language)" + }, + depends_on: [], parallel_group: 1 + }, + // T2, T3, ... +] +``` + +##### Step 3.2: Validate Records + +Validate all records before writing JSONL. Fix any issues found. + +```javascript +const items = selectedMode === 'progressive' ? layers : tasks +const errors = [] + +// 1. Schema validation: each record has convergence with all 3 fields +items.forEach(item => { + if (!item.convergence?.criteria?.length) errors.push(`${item.id}: missing convergence.criteria`) + if (!item.convergence?.verification) errors.push(`${item.id}: missing convergence.verification`) + if (!item.convergence?.definition_of_done) errors.push(`${item.id}: missing convergence.definition_of_done`) +}) + +// 2. Convergence quality check +const vaguePatterns = /正常|正确|好|可以|没问题|works|fine|good|correct/i +items.forEach(item => { + item.convergence.criteria.forEach((criterion, i) => { + if (vaguePatterns.test(criterion) && criterion.length < 15) { + errors.push(`${item.id} criteria[${i}]: Too vague - "${criterion}"`) + } + }) + if (item.convergence.verification.length < 10) { + errors.push(`${item.id} verification: Too short, needs executable steps`) + } + const technicalPatterns = /compile|build|lint|npm|npx|jest|tsc|eslint/i + if (technicalPatterns.test(item.convergence.definition_of_done)) { + errors.push(`${item.id} definition_of_done: Should be business language, not technical commands`) + } +}) + +// 3. Circular dependency detection +function detectCycles(records, prefix) { + const graph = new Map(records.map(r => [r.id, r.depends_on])) + const visited = new Set(), inStack = new Set(), cycleErrors = [] + function dfs(node, path) { + if (inStack.has(node)) { cycleErrors.push(`Circular: ${[...path, node].join(' → ')}`); return } + if (visited.has(node)) return + visited.add(node); inStack.add(node) + ;(graph.get(node) || []).forEach(dep => dfs(dep, [...path, node])) + inStack.delete(node) + } + records.forEach(r => { if (!visited.has(r.id)) dfs(r.id, []) }) + return cycleErrors +} +errors.push(...detectCycles(items, selectedMode === 'progressive' ? 'L' : 'T')) + +// 4. Mode-specific validation +if (selectedMode === 'progressive') { + // Check 2-4 layers + if (items.length < 2 || items.length > 4) errors.push(`Expected 2-4 layers, got ${items.length}`) + + // Check L0 is self-contained (no depends_on) + const l0 = items.find(l => l.id === 'L0') + if (l0 && l0.depends_on.length > 0) errors.push("L0 (MVP) should not have dependencies") + + // Check scope overlap + const allScopes = new Map() + items.forEach(layer => { + layer.scope.forEach(feature => { + if (allScopes.has(feature)) { + errors.push(`Scope overlap: "${feature}" in both ${allScopes.get(feature)} and ${layer.id}`) + } + allScopes.set(feature, layer.id) + }) + }) +} else { + // Check inputs/outputs chain + const availableOutputs = new Set() + items.forEach(task => { + task.inputs.forEach(input => { + if (!availableOutputs.has(input)) { + // Only warn for non-existing resources - existing files are valid inputs + } + }) + task.outputs.forEach(output => availableOutputs.add(output)) + }) + + // Check parallel_group consistency (same group tasks should not depend on each other) + const groups = new Map() + items.forEach(task => { + if (!groups.has(task.parallel_group)) groups.set(task.parallel_group, []) + groups.get(task.parallel_group).push(task) + }) + groups.forEach((groupTasks, groupId) => { + if (groupTasks.length > 1) { + const ids = new Set(groupTasks.map(t => t.id)) + groupTasks.forEach(task => { + task.depends_on.forEach(dep => { + if (ids.has(dep)) { + errors.push(`Parallel group ${groupId}: ${task.id} depends on ${dep} but both in same group`) + } + }) + }) + } + }) +} + +// 5. Fix errors if any, then write +// If errors found → fix records and re-validate +// Write roadmap.jsonl (one JSON record per line) +const jsonlContent = items.map(item => JSON.stringify(item)).join('\n') +Write(`${sessionFolder}/roadmap.jsonl`, jsonlContent) +``` + +##### Step 3.3: Quality Check (MANDATORY) + +After generating roadmap.jsonl, execute a self-check across 5 quality dimensions before proceeding. + +```javascript +const roadmapJsonlContent = Read(`${sessionFolder}/roadmap.jsonl`) + +// Quality dimensions to verify: +// +// | Dimension | Check Criteria | Critical? | +// |------------------------|-------------------------------------------------------------|-----------| +// | Requirement Coverage | All aspects of original requirement addressed in layers/tasks | Yes | +// | Convergence Quality | criteria testable, verification executable, DoD business-readable | Yes | +// | Scope Integrity | Progressive: no overlap/gaps; Direct: inputs/outputs chain valid | Yes | +// | Dependency Correctness | No circular deps, proper ordering | Yes | +// | Effort Balance | No single layer/task disproportionately large | No | +// +// Decision after check: +// - PASS → proceed to Phase 4 +// - AUTO_FIX → fix convergence wording, rebalance scope, update roadmap.jsonl +// - NEEDS_REVIEW → report issues to user in Phase 4 feedback + +// Auto-fix strategy: +// | Issue Type | Auto-Fix Action | +// |-----------------|----------------------------------------------| +// | Vague criteria | Replace with specific, testable conditions | +// | Technical DoD | Rewrite in business language | +// | Missing scope | Add to appropriate layer/task | +// | Effort imbalance| Split oversized layer/task | + +// After auto-fixes, update roadmap.jsonl +``` + +**Success Criteria**: +- roadmap.jsonl generated, each line independently JSON.parse-able +- Each record contains convergence (criteria + verification + definition_of_done) +- Quality check passed (all critical dimensions) +- No circular dependencies +- Progressive: 2-4 layers, no scope overlap, L0 self-contained +- Direct: tasks have explicit inputs/outputs, parallel_group assigned correctly + +### Phase 4: Validate & Finalize + +**Objective**: Display decomposition results, collect user feedback, generate final artifacts. + +##### Step 4.1: Display Results & Collect Feedback + +Display the decomposition as a table with convergence criteria, then run feedback loop. + +**Progressive Mode display format**: + +```markdown +## Roadmap Overview + +| Layer | Name | Goal | Scope | Effort | Dependencies | +|-------|------|------|-------|--------|--------------| +| L0 | MVP | ... | ... | medium | - | +| L1 | Usable | ... | ... | medium | L0 | + +### Convergence Criteria +**L0 - MVP**: +- Criteria: [criteria list] +- Verification: [verification] +- Definition of Done: [definition_of_done] +``` + +**Direct Mode display format**: + +```markdown +## Task Sequence + +| Group | ID | Title | Type | Dependencies | +|-------|----|-------|------|--------------| +| 1 | T1 | ... | infrastructure | - | +| 2 | T2 | ... | feature | T1 | + +### Convergence Criteria +**T1 - Establish Data Model**: +- Criteria: [criteria list] +- Verification: [verification] +- Definition of Done: [definition_of_done] +``` + +**Feedback loop**: + +```javascript +const items = Read(`${sessionFolder}/roadmap.jsonl`) + .split('\n').filter(l => l.trim()).map(l => JSON.parse(l)) + +// Display tabular results + convergence for each item (using format above) + +if (!autoYes) { + let round = 0, continueLoop = true + while (continueLoop && round < 5) { + round++ + const feedback = AskUserQuestion({ + questions: [{ + question: `Roadmap validation (round ${round}):\nAny feedback on the current decomposition?`, + header: "Feedback", + multiSelect: false, + options: [ + { label: "Approve", description: "Decomposition is reasonable, generate final artifacts" }, + { label: "Adjust Scope", description: "Some layer/task scopes need adjustment" }, + { label: "Modify Convergence", description: "Convergence criteria not specific enough" }, + { label: "Re-decompose", description: "Overall strategy or layering needs change" } + ] + }] + }) + if (feedback === 'Approve') continueLoop = false + // else: apply adjustment, re-write roadmap.jsonl, re-display, loop + } +} +``` + +##### Step 4.2: Write roadmap.md & Next Steps + +Generate final roadmap.md using the generation templates below, then provide post-completion options. + +**Progressive mode roadmap.md generation**: + +```javascript +const roadmapMd = `# Requirement Roadmap + +**Session**: ${sessionId} +**Requirement**: ${requirement} +**Strategy**: progressive +**Uncertainty**: ${strategy.uncertainty_level} +**Generated**: ${getUtc8ISOString()} + +## Strategy Assessment +- Uncertainty level: ${strategy.uncertainty_level} +- Decomposition mode: progressive +- Assessment basis: ${Object.entries(strategy.uncertainty_factors).map(([k,v]) => `${k}=${v}`).join(', ')} +- Goal: ${strategy.goal} +- Constraints: ${strategy.constraints.join(', ') || 'None'} +- Stakeholders: ${strategy.stakeholders.join(', ') || 'None'} + +## Roadmap Overview + +| Layer | Name | Goal | Effort | Dependencies | +|-------|------|------|--------|--------------| +${items.map(l => `| ${l.id} | ${l.name} | ${l.goal} | ${l.effort} | ${l.depends_on.length ? l.depends_on.join(', ') : '-'} |`).join('\n')} + +## Layer Details + +${items.map(l => `### ${l.id}: ${l.name} + +**Goal**: ${l.goal} + +**Scope**: ${l.scope.join(', ')} + +**Excludes**: ${l.excludes.join(', ') || 'None'} + +**Convergence Criteria**: +${l.convergence.criteria.map(c => \`- ${c}\`).join('\n')} +- **Verification**: ${l.convergence.verification} +- **Definition of Done**: ${l.convergence.definition_of_done} + +**Risk Items**: ${l.risk_items.length ? l.risk_items.map(r => \`\n- ${r}\`).join('') : 'None'} + +**Effort**: ${l.effort} +`).join('\n---\n\n')} + +## Risk Summary + +${items.flatMap(l => l.risk_items.map(r => \`- **${l.id}**: ${r}\`)).join('\n') || 'No identified risks'} + +## Next Steps + +Each layer can be executed independently: +\\\`\\\`\\\`bash +/workflow:lite-plan "${items[0]?.name}: ${items[0]?.scope.join(', ')}" +\\\`\\\`\\\` + +Roadmap JSONL file: \\\`${sessionFolder}/roadmap.jsonl\\\` +` +``` + +**Direct mode roadmap.md generation**: + +```javascript +const roadmapMd = `# Requirement Roadmap + +**Session**: ${sessionId} +**Requirement**: ${requirement} +**Strategy**: direct +**Generated**: ${getUtc8ISOString()} + +## Strategy Assessment +- Goal: ${strategy.goal} +- Constraints: ${strategy.constraints.join(', ') || 'None'} +- Assessment basis: ${Object.entries(strategy.uncertainty_factors).map(([k,v]) => `${k}=${v}`).join(', ')} + +## Task Sequence + +| Group | ID | Title | Type | Dependencies | +|-------|----|-------|------|--------------| +${items.map(t => `| ${t.parallel_group} | ${t.id} | ${t.title} | ${t.type} | ${t.depends_on.length ? t.depends_on.join(', ') : '-'} |`).join('\n')} + +## Task Details + +${items.map(t => `### ${t.id}: ${t.title} + +**Type**: ${t.type} | **Parallel Group**: ${t.parallel_group} + +**Scope**: ${t.scope} + +**Inputs**: ${t.inputs.length ? t.inputs.join(', ') : 'None (starting task)'} +**Outputs**: ${t.outputs.join(', ')} + +**Convergence Criteria**: +${t.convergence.criteria.map(c => \`- ${c}\`).join('\n')} +- **Verification**: ${t.convergence.verification} +- **Definition of Done**: ${t.convergence.definition_of_done} +`).join('\n---\n\n')} + +## Next Steps + +Each task can be executed independently: +\\\`\\\`\\\`bash +/workflow:lite-plan "${items[0]?.title}: ${items[0]?.scope}" +\\\`\\\`\\\` + +Roadmap JSONL file: \\\`${sessionFolder}/roadmap.jsonl\\\` +` +``` + +**Write and provide post-completion options**: + +```javascript +Write(`${sessionFolder}/roadmap.md`, roadmapMd) + +// Post-completion options +if (!autoYes) { + AskUserQuestion({ + questions: [{ + question: "Roadmap generated. Next step:", + header: "Next Step", + multiSelect: false, + options: [ + { label: "Execute First Layer", description: `Launch lite-plan to execute ${items[0].id}` }, + { label: "Create Issue", description: "Create GitHub Issue based on roadmap" }, + { label: "Export Report", description: "Generate standalone shareable roadmap report" }, + { label: "Done", description: "Save roadmap only, execute later" } + ] + }] + }) +} +``` + +| Selection | Action | +|-----------|--------| +| Execute First Layer | `Skill(skill="workflow:lite-plan", args="${firstItem.scope}")` | +| Create Issue | `Skill(skill="issue:new", args="...")` | +| Export Report | Copy roadmap.md + roadmap.jsonl to user-specified location | +| Done | Display roadmap file paths, end | + +**Success Criteria**: +- User feedback processed (or skipped via autoYes) +- roadmap.md finalized with full tables and convergence details +- roadmap.jsonl final version updated +- Post-completion options provided + +## Session Folder Structure + +``` +.workflow/.req-plan/RPLAN-{slug}-{YYYY-MM-DD}/ +├── roadmap.md # Human-readable roadmap +├── roadmap.jsonl # Machine-readable, one self-contained record per line +├── strategy-assessment.json # Strategy assessment result +└── exploration-codebase.json # Codebase context (optional) +``` + +| File | Phase | Description | +|------|-------|-------------| +| `strategy-assessment.json` | 1 | Uncertainty analysis + mode recommendation + extracted goal/constraints/stakeholders/domain_keywords | +| `roadmap.md` (skeleton) | 1 | Initial skeleton with placeholders, finalized in Phase 4 | +| `exploration-codebase.json` | 2 | Codebase context: relevant modules, patterns, integration points (only when codebase exists) | +| `roadmap.jsonl` | 3 | One self-contained JSON record per line with convergence criteria | +| `roadmap.md` (final) | 4 | Human-readable roadmap with tabular display + convergence details, revised per user feedback | + +## JSONL Schema + +### Convergence Criteria + +Each record's `convergence` object: + +| Field | Purpose | Requirement | +|-------|---------|-------------| +| `criteria[]` | List of checkable specific conditions | **Testable** - can be written as assertions or manual steps | +| `verification` | How to verify these conditions | **Executable** - command, script, or explicit steps | +| `definition_of_done` | One-sentence completion definition | **Business language** - non-technical person can judge | + +### Progressive Mode (one layer per line) + +| Layer | Name | Typical Goal | +|-------|------|--------------| +| L0 | MVP | Minimum viable closed loop, core path end-to-end | +| L1 | Usable | Key user paths refined, basic error handling | +| L2 | Refined | Edge cases, performance, security hardening | +| L3 | Optimized | Advanced features, observability, operations | + +**Schema**: `id, name, goal, scope[], excludes[], convergence{}, risk_items[], effort, depends_on[]` + +```jsonl +{"id":"L0","name":"MVP","goal":"Minimum viable closed loop","scope":["User registration and login","Basic CRUD"],"excludes":["OAuth","2FA"],"convergence":{"criteria":["End-to-end register→login→operate flow works","Core API returns correct responses"],"verification":"curl/Postman manual testing or smoke test script","definition_of_done":"New user can complete register→login→perform one core operation"},"risk_items":["JWT library selection needs validation"],"effort":"medium","depends_on":[]} +{"id":"L1","name":"Usable","goal":"Complete key user paths","scope":["Password reset","Input validation","Error messages"],"excludes":["Audit logs","Rate limiting"],"convergence":{"criteria":["All form fields have frontend+backend validation","Password reset email can be sent and reset completed","Error scenarios show user-friendly messages"],"verification":"Unit tests cover validation logic + manual test of reset flow","definition_of_done":"Users have a clear recovery path when encountering input errors or forgotten passwords"},"risk_items":[],"effort":"medium","depends_on":["L0"]} +``` + +**Constraints**: 2-4 layers, L0 must be a self-contained closed loop with no dependencies, each feature belongs to exactly ONE layer (no scope overlap). + +### Direct Mode (one task per line) + +| Type | Use Case | +|------|----------| +| infrastructure | Data models, configuration, scaffolding | +| feature | API, UI, business logic implementation | +| enhancement | Validation, error handling, edge cases | +| testing | Unit tests, integration tests, E2E | + +**Schema**: `id, title, type, scope, inputs[], outputs[], convergence{}, depends_on[], parallel_group` + +```jsonl +{"id":"T1","title":"Establish data model","type":"infrastructure","scope":"DB schema + TypeScript types","inputs":[],"outputs":["schema.prisma","types/user.ts"],"convergence":{"criteria":["Migration executes without errors","TypeScript types compile successfully","Fields cover all business entities"],"verification":"npx prisma migrate dev && npx tsc --noEmit","definition_of_done":"Database schema migrates correctly, type definitions can be referenced by other modules"},"depends_on":[],"parallel_group":1} +{"id":"T2","title":"Implement core API","type":"feature","scope":"CRUD endpoints for User","inputs":["schema.prisma","types/user.ts"],"outputs":["routes/user.ts","controllers/user.ts"],"convergence":{"criteria":["GET/POST/PUT/DELETE return correct status codes","Request/response conforms to schema","No N+1 queries"],"verification":"jest --testPathPattern=user.test.ts","definition_of_done":"All User CRUD endpoints pass integration tests"},"depends_on":["T1"],"parallel_group":2} +``` + +**Constraints**: Inputs must come from preceding task outputs or existing resources, tasks in same parallel_group must be truly independent, no circular dependencies. + +## Convergence Quality Requirements + +Every `convergence` field MUST satisfy these quality standards: + +| Field | Requirement | Bad Example | Good Example | +|-------|-------------|-------------|--------------| +| `criteria[]` | **Testable** - can write assertions or manual steps | `"System works correctly"` | `"API returns 200 and response body contains user_id field"` | +| `verification` | **Executable** - command, script, or clear steps | `"Check it"` | `"jest --testPathPattern=auth && curl -s localhost:3000/health"` | +| `definition_of_done` | **Business language** - non-technical person can judge | `"Code compiles"` | `"New user can complete register→login→perform core operation flow"` | + +**NEVER** output vague convergence criteria ("works correctly", "system is normal"). **ALWAYS** ensure: +- criteria are testable (can be written as assertions or manual verification steps) +- verification is executable (commands or explicit steps) +- definition_of_done uses business language (non-technical stakeholders can judge) + +## Fallback Decomposition + +When normal decomposition fails or produces empty results, use fallback templates: + +**Progressive fallback**: +```javascript +[ + { + id: "L0", name: "MVP", goal: "Minimum viable closed loop", + scope: ["Core functionality"], excludes: ["Advanced features", "Optimization"], + convergence: { + criteria: ["Core path works end-to-end"], + verification: "Manual test of core flow", + definition_of_done: "User can complete one full core operation" + }, + risk_items: ["Tech selection needs validation"], effort: "medium", depends_on: [] + }, + { + id: "L1", name: "Usable", goal: "Refine key user paths", + scope: ["Error handling", "Input validation"], excludes: ["Performance optimization", "Monitoring"], + convergence: { + criteria: ["All user inputs validated", "Error scenarios show messages"], + verification: "Unit tests + manual error scenario testing", + definition_of_done: "Users have clear guidance and recovery paths when encountering problems" + }, + risk_items: [], effort: "medium", depends_on: ["L0"] + } +] +``` + +**Direct fallback**: +```javascript +[ + { + id: "T1", title: "Infrastructure setup", type: "infrastructure", + scope: "Project scaffolding and base configuration", + inputs: [], outputs: ["project-structure"], + convergence: { + criteria: ["Project builds without errors", "Base configuration complete"], + verification: "npm run build (or equivalent build command)", + definition_of_done: "Project foundation ready for feature development" + }, + depends_on: [], parallel_group: 1 + }, + { + id: "T2", title: "Core feature implementation", type: "feature", + scope: "Core business logic", + inputs: ["project-structure"], outputs: ["core-module"], + convergence: { + criteria: ["Core API/functionality callable", "Returns expected results"], + verification: "Run core feature tests", + definition_of_done: "Core business functionality works as expected" + }, + depends_on: ["T1"], parallel_group: 2 + } +] +``` + +## Error Handling + +| Situation | Action | +|-----------|--------| +| No codebase detected | Normal flow, skip Phase 2 | +| Codebase search fails | Proceed with pure requirement decomposition | +| Circular dependency in records | Fix dependency graph before writing JSONL | +| User feedback timeout | Save current state, display `--continue` recovery command | +| Max feedback rounds (5) | Use current version to generate final artifacts | +| Session folder conflict | Append timestamp suffix | +| JSONL format error | Validate line by line, report problematic lines and fix | +| Quality check fails | Auto-fix if possible, otherwise report to user in feedback loop | +| Decomposition produces empty results | Use fallback decomposition templates | + +## Best Practices + +1. **Clear requirement description**: Detailed description leads to more accurate uncertainty assessment and decomposition +2. **Validate MVP first**: In progressive mode, L0 should be the minimum verifiable closed loop +3. **Testable convergence**: criteria must be writable as assertions or manual steps; definition_of_done should be judgeable by non-technical stakeholders +4. **Incremental validation**: Use `--continue` to iterate on existing roadmaps +5. **Independently executable**: Each JSONL record should be independently passable to lite-plan for execution + +## When to Use + +**Use req-plan-with-file when:** +- You need to decompose a large requirement into a progressively executable roadmap +- Unsure where to start, need an MVP strategy +- Need to generate a trackable task sequence for the team +- Requirement involves multiple stages or iterations + +**Use lite-plan when:** +- You have a clear single task to execute +- The requirement is already a layer/task from the roadmap +- No layered planning needed + +**Use collaborative-plan-with-file when:** +- A single complex task needs multi-agent parallel planning +- Need to analyze the same task from multiple domain perspectives + +**Use analyze-with-file when:** +- Need in-depth analysis of a technical problem +- Not about planning execution, but understanding and discussion + +--- + +**Now execute the req-plan-with-file workflow for**: $ARGUMENTS diff --git a/ccw/src/commands/stop.ts b/ccw/src/commands/stop.ts index 928022bf..0f0805ef 100644 --- a/ccw/src/commands/stop.ts +++ b/ccw/src/commands/stop.ts @@ -50,9 +50,19 @@ async function killProcess(pid: string): Promise { } /** - * Stop command handler - stops the running CCW dashboard server - * @param {Object} options - Command options + * Clean up React frontend process on the given port */ +async function cleanupReactFrontend(reactPort: number): Promise { + const reactPid = await findProcessOnPort(reactPort); + if (reactPid) { + console.log(chalk.gray(` Cleaning up React frontend on port ${reactPort}...`)); + const killed = await killProcess(reactPid); + if (killed) { + console.log(chalk.green(' React frontend stopped!')); + } + } +} + export async function stopCommand(options: StopOptions): Promise { const port = Number(options.port) || 3456; const reactPort = port + 1; // React frontend runs on port + 1 @@ -92,6 +102,7 @@ export async function stopCommand(options: StopOptions): Promise { await new Promise(resolve => setTimeout(resolve, 500)); if (shutdownResponse && 'ok' in shutdownResponse && shutdownResponse.ok) { + await cleanupReactFrontend(reactPort); console.log(chalk.green.bold('\n Server stopped successfully!\n')); process.exit(0); } @@ -102,6 +113,7 @@ export async function stopCommand(options: StopOptions): Promise { }).catch(() => null); if (!postCheck) { + await cleanupReactFrontend(reactPort); console.log(chalk.green.bold('\n Server stopped successfully!\n')); process.exit(0); } diff --git a/ccw/src/commands/view.ts b/ccw/src/commands/view.ts index baabf78c..5d8d8b0b 100644 --- a/ccw/src/commands/view.ts +++ b/ccw/src/commands/view.ts @@ -110,7 +110,7 @@ export async function viewCommand(options: ViewOptions): Promise { if (frontend === 'react') { urlPath = '/react'; } - const url = `http://${browserHost}:${port}${urlPath}/?path=${encodeURIComponent(result.path!)}`; + const url = `http://${browserHost}:${port}${urlPath}/?path=${encodeURIComponent(workspacePath)}`; if (options.browser !== false) { console.log(chalk.cyan(' Opening in browser...')); diff --git a/codex-lens/benchmarks/results/compare_2026-02-09_run2.json b/codex-lens/benchmarks/results/compare_2026-02-09_run2.json new file mode 100644 index 00000000..7dc36661 --- /dev/null +++ b/codex-lens/benchmarks/results/compare_2026-02-09_run2.json @@ -0,0 +1,453 @@ +{ + "summary": { + "timestamp": "2026-02-09 11:26:54", + "source": "src", + "k": 10, + "coarse_k": 100, + "query_count": 7, + "avg_jaccard_topk": 0.39589733329229126, + "avg_rbo_topk": 0.23139636799510202, + "staged": { + "success": 7, + "avg_latency_ms": 32194.107242865222 + }, + "dense_rerank": { + "success": 7, + "avg_latency_ms": 2643.366857132741 + } + }, + "comparisons": [ + { + "query": "class Config", + "staged": { + "strategy": "staged", + "query": "class Config", + "latency_ms": 43041.41250002384, + "num_results": 10, + "topk_paths": [ + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\api\\semantic.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\parsers\\factory.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\search\\graph_expander.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\watcher\\file_watcher.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\cli\\embedding_manager.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\dir_index.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\lsp\\server.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\api\\references.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\__init__.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\search\\chain_search.py" + ], + "stage_stats": { + "stage_times": { + "stage1_binary_ms": 9864.638805389404, + "stage2_expand_ms": 13012.29190826416, + "stage3_cluster_ms": 13297.565460205078, + "stage4_rerank_ms": 6821.892261505127 + }, + "stage_counts": { + "stage1_candidates": 100, + "stage2_expanded": 149, + "stage3_clustered": 20, + "stage4_reranked": 20 + } + }, + "error": null + }, + "dense_rerank": { + "strategy": "dense_rerank", + "query": "class Config", + "latency_ms": 3209.129799991846, + "num_results": 10, + "topk_paths": [ + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\cli\\commands.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\dir_index.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\semantic\\chunker.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\semantic\\vector_store.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\search\\query_parser.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\semantic\\code_extractor.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\cli\\embedding_manager.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\migration_manager.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\registry.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\sqlite_store.py" + ], + "stage_stats": null, + "error": null + }, + "jaccard_topk": 0.1111111111111111, + "rbo_topk": 0.05429729885142857, + "staged_unique_files_topk": 10, + "dense_unique_files_topk": 10, + "staged_unique_dirs_topk": 8, + "dense_unique_dirs_topk": 4 + }, + { + "query": "def search", + "staged": { + "strategy": "staged", + "query": "def search", + "latency_ms": 37827.209600031376, + "num_results": 10, + "topk_paths": [ + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\cli\\commands.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\global_index.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\search\\ranking.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\semantic\\ann_index.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\dir_index.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\index_tree.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\search\\graph_expander.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\search\\enrichment.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\semantic\\vector_store.py" + ], + "stage_stats": { + "stage_times": { + "stage1_binary_ms": 531.8794250488281, + "stage2_expand_ms": 27009.481191635132, + "stage3_cluster_ms": 7948.509931564331, + "stage4_rerank_ms": 2268.9380645751953 + }, + "stage_counts": { + "stage1_candidates": 100, + "stage2_expanded": 101, + "stage3_clustered": 20, + "stage4_reranked": 20 + } + }, + "error": null + }, + "dense_rerank": { + "strategy": "dense_rerank", + "query": "def search", + "latency_ms": 2540.472400009632, + "num_results": 10, + "topk_paths": [ + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\cli\\commands.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\search\\query_parser.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\semantic\\vector_store.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\search\\hybrid_search.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\index_tree.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\registry.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\dir_index.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\semantic\\code_extractor.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\search\\chain_search.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\semantic\\chunker.py" + ], + "stage_stats": null, + "error": null + }, + "jaccard_topk": 0.26666666666666666, + "rbo_topk": 0.2983708721671428, + "staged_unique_files_topk": 9, + "dense_unique_files_topk": 10, + "staged_unique_dirs_topk": 4, + "dense_unique_dirs_topk": 4 + }, + { + "query": "LspBridge", + "staged": { + "strategy": "staged", + "query": "LspBridge", + "latency_ms": 24744.686599999666, + "num_results": 10, + "topk_paths": [ + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\vector_meta_store.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\search\\graph_expander.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\registry.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\merkle_tree.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\cli\\commands.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\semantic\\code_extractor.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\sqlite_store.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\cli\\embedding_manager.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\dir_index.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\global_index.py" + ], + "stage_stats": { + "stage_times": { + "stage1_binary_ms": 517.8542137145996, + "stage2_expand_ms": 12839.622735977173, + "stage3_cluster_ms": 9154.959678649902, + "stage4_rerank_ms": 2160.0701808929443 + }, + "stage_counts": { + "stage1_candidates": 100, + "stage2_expanded": 100, + "stage3_clustered": 20, + "stage4_reranked": 20 + } + }, + "error": null + }, + "dense_rerank": { + "strategy": "dense_rerank", + "query": "LspBridge", + "latency_ms": 2482.5908999741077, + "num_results": 10, + "topk_paths": [ + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\cli\\commands.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\vector_meta_store.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\search\\graph_expander.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\registry.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\search\\hybrid_search.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\dir_index.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\index_tree.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\sqlite_store.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\semantic\\code_extractor.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\semantic\\chunker.py" + ], + "stage_stats": null, + "error": null + }, + "jaccard_topk": 0.5384615384615384, + "rbo_topk": 0.36639083062285716, + "staged_unique_files_topk": 10, + "dense_unique_files_topk": 10, + "staged_unique_dirs_topk": 4, + "dense_unique_dirs_topk": 4 + }, + { + "query": "graph expansion", + "staged": { + "strategy": "staged", + "query": "graph expansion", + "latency_ms": 25239.59050002694, + "num_results": 10, + "topk_paths": [ + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\cli\\commands.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\search\\chain_search.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\semantic\\gpu_support.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\semantic\\code_extractor.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\cli\\embedding_manager.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\index_tree.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\vector_meta_store.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\global_index.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\search\\hybrid_search.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\migration_manager.py" + ], + "stage_stats": { + "stage_times": { + "stage1_binary_ms": 631.9081783294678, + "stage2_expand_ms": 12570.756196975708, + "stage3_cluster_ms": 9557.724952697754, + "stage4_rerank_ms": 2409.7683429718018 + }, + "stage_counts": { + "stage1_candidates": 100, + "stage2_expanded": 100, + "stage3_clustered": 20, + "stage4_reranked": 20 + } + }, + "error": null + }, + "dense_rerank": { + "strategy": "dense_rerank", + "query": "graph expansion", + "latency_ms": 2574.1938000023365, + "num_results": 10, + "topk_paths": [ + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\index_tree.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\migration_manager.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\search\\hybrid_search.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\search\\chain_search.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\global_index.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\dir_index.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\registry.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\cli\\commands.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\sqlite_store.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\semantic\\vector_store.py" + ], + "stage_stats": null, + "error": null + }, + "jaccard_topk": 0.42857142857142855, + "rbo_topk": 0.13728894791142857, + "staged_unique_files_topk": 10, + "dense_unique_files_topk": 10, + "staged_unique_dirs_topk": 4, + "dense_unique_dirs_topk": 4 + }, + { + "query": "clustering strategy", + "staged": { + "strategy": "staged", + "query": "clustering strategy", + "latency_ms": 28572.93939998746, + "num_results": 10, + "topk_paths": [ + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\search\\ranking.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\registry.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\global_index.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\cli\\commands.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\cli\\embedding_manager.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\dir_index.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\semantic\\chunker.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\sqlite_store.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\cli\\__init__.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\semantic\\vector_store.py" + ], + "stage_stats": { + "stage_times": { + "stage1_binary_ms": 659.6193313598633, + "stage2_expand_ms": 14207.426309585571, + "stage3_cluster_ms": 11513.370037078857, + "stage4_rerank_ms": 2117.546319961548 + }, + "stage_counts": { + "stage1_candidates": 100, + "stage2_expanded": 100, + "stage3_clustered": 20, + "stage4_reranked": 20 + } + }, + "error": null + }, + "dense_rerank": { + "strategy": "dense_rerank", + "query": "clustering strategy", + "latency_ms": 2536.551799982786, + "num_results": 10, + "topk_paths": [ + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\cli\\commands.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\index_tree.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\search\\hybrid_search.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\semantic\\code_extractor.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\semantic\\vector_store.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\search\\__init__.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\semantic\\gpu_support.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\search\\chain_search.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\search\\enrichment.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\semantic\\chunker.py" + ], + "stage_stats": null, + "error": null + }, + "jaccard_topk": 0.17647058823529413, + "rbo_topk": 0.07116480920571429, + "staged_unique_files_topk": 10, + "dense_unique_files_topk": 10, + "staged_unique_dirs_topk": 4, + "dense_unique_dirs_topk": 4 + }, + { + "query": "error handling", + "staged": { + "strategy": "staged", + "query": "error handling", + "latency_ms": 23812.726000010967, + "num_results": 10, + "topk_paths": [ + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\cli\\commands.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\search\\enrichment.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\dir_index.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\semantic\\vector_store.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\search\\hybrid_search.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\search\\chain_search.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\registry.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\semantic\\chunker.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\__init__.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\index_tree.py" + ], + "stage_stats": { + "stage_times": { + "stage1_binary_ms": 475.42428970336914, + "stage2_expand_ms": 12454.935789108276, + "stage3_cluster_ms": 8576.019525527954, + "stage4_rerank_ms": 2265.360116958618 + }, + "stage_counts": { + "stage1_candidates": 100, + "stage2_expanded": 100, + "stage3_clustered": 20, + "stage4_reranked": 20 + } + }, + "error": null + }, + "dense_rerank": { + "strategy": "dense_rerank", + "query": "error handling", + "latency_ms": 2648.7773999869823, + "num_results": 10, + "topk_paths": [ + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\__init__.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\registry.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\search\\hybrid_search.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\cli\\commands.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\index_tree.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\dir_index.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\search\\chain_search.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\semantic\\chunker.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\semantic\\code_extractor.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\cli\\embedding_manager.py" + ], + "stage_stats": null, + "error": null + }, + "jaccard_topk": 0.6666666666666666, + "rbo_topk": 0.21230026104857144, + "staged_unique_files_topk": 10, + "dense_unique_files_topk": 10, + "staged_unique_dirs_topk": 4, + "dense_unique_dirs_topk": 4 + }, + { + "query": "how to parse json", + "staged": { + "strategy": "staged", + "query": "how to parse json", + "latency_ms": 42120.1860999763, + "num_results": 9, + "topk_paths": [ + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\cli\\commands.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\dir_index.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\index_tree.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\semantic\\code_extractor.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\search\\enrichment.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\registry.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\search\\ranking.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\search\\chain_search.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\search\\hybrid_search.py" + ], + "stage_stats": { + "stage_times": { + "stage1_binary_ms": 570.8920955657959, + "stage2_expand_ms": 30054.06880378723, + "stage3_cluster_ms": 9285.51697731018, + "stage4_rerank_ms": 2142.771005630493 + }, + "stage_counts": { + "stage1_candidates": 100, + "stage2_expanded": 100, + "stage3_clustered": 20, + "stage4_reranked": 20 + } + }, + "error": null + }, + "dense_rerank": { + "strategy": "dense_rerank", + "query": "how to parse json", + "latency_ms": 2511.8518999814987, + "num_results": 10, + "topk_paths": [ + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\cli\\commands.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\search\\chain_search.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\index_tree.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\semantic\\code_extractor.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\dir_index.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\search\\hybrid_search.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\search\\ranking.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\semantic\\chunker.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\storage\\sqlite_store.py", + "d:\\claude_dms3\\codex-lens\\src\\codexlens\\semantic\\ann_index.py" + ], + "stage_stats": null, + "error": null + }, + "jaccard_topk": 0.5833333333333334, + "rbo_topk": 0.4799615561585714, + "staged_unique_files_topk": 9, + "dense_unique_files_topk": 10, + "staged_unique_dirs_topk": 4, + "dense_unique_dirs_topk": 4 + } + ] +} \ No newline at end of file diff --git a/codex-lens/src/codexlens/lsp/lsp_bridge.py b/codex-lens/src/codexlens/lsp/lsp_bridge.py index 0e41cc24..63b30830 100644 --- a/codex-lens/src/codexlens/lsp/lsp_bridge.py +++ b/codex-lens/src/codexlens/lsp/lsp_bridge.py @@ -517,10 +517,11 @@ class LspBridge: # Parse URI uri = from_item.get("uri", "") - if uri.startswith("file:///"): - fp = uri[8:] if uri[8:9].isalpha() and uri[9:10] == ":" else uri[7:] - elif uri.startswith("file://"): - fp = uri[7:] + if uri.startswith("file://"): + raw = unquote(uri[7:]) # keep leading slash for Unix paths + if raw.startswith("/") and len(raw) > 2 and raw[2] == ":": + raw = raw[1:] + fp = raw else: fp = uri diff --git a/codex-lens/src/codexlens/lsp/standalone_manager.py b/codex-lens/src/codexlens/lsp/standalone_manager.py index aa6edf6b..369700ca 100644 --- a/codex-lens/src/codexlens/lsp/standalone_manager.py +++ b/codex-lens/src/codexlens/lsp/standalone_manager.py @@ -21,6 +21,7 @@ import sys from dataclasses import dataclass, field from pathlib import Path from typing import Any, Dict, List, Optional, Tuple +from urllib.parse import unquote, urlparse logger = logging.getLogger(__name__) @@ -341,6 +342,7 @@ class StandaloneLspManager: Returns: ServerState for the appropriate language server, or None """ + file_path = self._normalize_file_path(file_path) language_id = self.get_language_id(file_path) if not language_id: logger.debug(f"No language server configured for: {file_path}") @@ -357,6 +359,43 @@ class StandaloneLspManager: # Start new server return await self._start_server(language_id) + + def _normalize_file_path(self, file_path_or_uri: str) -> str: + """Normalize a file path that may be an LSP file URI or URI-path. + + LSP responses often contain `file://` URIs with percent-encoding + (e.g. `file:///d%3A/...`). Some code paths may forward the parsed + URI path (`/d%3A/...`) without the scheme. On Windows, `Path(...)` + would interpret that as a root path on the current drive, producing + invalid paths like `D:\\d%3A\\...`. + """ + if not file_path_or_uri: + return file_path_or_uri + + raw = str(file_path_or_uri).strip() + + if raw.startswith("file:"): + try: + parsed = urlparse(raw) + if parsed.scheme == "file": + raw = unquote(parsed.path) + else: + raw = raw.replace("file:///", "").replace("file://", "") + except Exception: + raw = raw.replace("file:///", "").replace("file://", "") + + # Decode percent-encoded segments (e.g. d%3A -> d:) + if "%3a" in raw.lower(): + try: + raw = unquote(raw) + except Exception: + pass + + # Windows: file URI paths frequently look like "/C:/path"; strip the extra slash. + if raw.startswith("/") and len(raw) > 2 and raw[2] == ":": + raw = raw[1:] + + return raw async def _initialize_server(self, state: ServerState) -> None: """Send initialize request and wait for response via the message queue. @@ -771,6 +810,7 @@ class StandaloneLspManager: def _to_text_document_identifier(self, file_path: str) -> Dict[str, str]: """Create TextDocumentIdentifier from file path.""" + file_path = self._normalize_file_path(file_path) uri = Path(file_path).resolve().as_uri() return {"uri": uri} @@ -783,6 +823,7 @@ class StandaloneLspManager: async def _open_document(self, state: ServerState, file_path: str) -> None: """Send textDocument/didOpen notification.""" + file_path = self._normalize_file_path(file_path) resolved_path = Path(file_path).resolve() try: @@ -1044,7 +1085,7 @@ class StandaloneLspManager: """ # Determine language from item's uri uri = item.get("uri", "") - file_path = uri.replace("file:///", "").replace("file://", "") + file_path = self._normalize_file_path(uri) state = await self._get_server(file_path) if not state: @@ -1075,7 +1116,7 @@ class StandaloneLspManager: """ # Determine language from item's uri uri = item.get("uri", "") - file_path = uri.replace("file:///", "").replace("file://", "") + file_path = self._normalize_file_path(uri) state = await self._get_server(file_path) if not state: diff --git a/codex-lens/tests/lsp/test_standalone_manager_paths.py b/codex-lens/tests/lsp/test_standalone_manager_paths.py new file mode 100644 index 00000000..39b74584 --- /dev/null +++ b/codex-lens/tests/lsp/test_standalone_manager_paths.py @@ -0,0 +1,48 @@ +"""Tests for StandaloneLspManager path normalization (Windows URI handling).""" + +from __future__ import annotations + +import platform + +from codexlens.lsp.standalone_manager import StandaloneLspManager + + +def test_normalize_file_uri_percent_encoded_windows_drive() -> None: + if platform.system() != "Windows": + return + + manager = StandaloneLspManager(workspace_root="D:/Claude_dms3/codex-lens") + + raw = "file:///d%3A/Claude_dms3/codex-lens/src/codexlens/lsp/standalone_manager.py" + normalized = manager._normalize_file_path(raw) + + assert normalized.lower().startswith("d:/") + assert "%3a" not in normalized.lower() + assert "d%3a" not in normalized.lower() + assert "/d%3a" not in normalized.lower() + + +def test_normalize_uri_path_percent_encoded_windows_drive() -> None: + if platform.system() != "Windows": + return + + manager = StandaloneLspManager(workspace_root="D:/Claude_dms3/codex-lens") + + raw = "/d%3A/Claude_dms3/codex-lens/src/codexlens/lsp/standalone_manager.py" + normalized = manager._normalize_file_path(raw) + + assert normalized.lower().startswith("d:/") + assert "%3a" not in normalized.lower() + + +def test_normalize_plain_windows_path_is_unchanged() -> None: + if platform.system() != "Windows": + return + + manager = StandaloneLspManager(workspace_root="D:/Claude_dms3/codex-lens") + + raw = r"D:\Claude_dms3\codex-lens\src\codexlens\lsp\standalone_manager.py" + normalized = manager._normalize_file_path(raw) + + assert normalized == raw +