feat: Add global relationships management to GlobalSymbolIndex

- Introduced a new schema version (v2) with a global_relationships table.
- Implemented CRUD operations for file relationships, including update and delete functionalities.
- Added query capabilities for relationships by target and symbols.
- Created migration logic from v1 to v2 schema.
- Enhanced tests for global relationships, covering various scenarios including insertion, querying, and deletion.

docs: Add update-single command for generating module documentation

- Created a new command to generate manual-style documentation (CLAUDE.md) for a single module.
- Detailed execution process and implementation phases for the command.
- Included usage examples and error handling guidelines.

feat: Implement team command for CLI interface

- Added a new team command for logging and retrieving messages in a team message bus.
- Supported subcommands for logging, reading, listing, and checking status of messages.
- Included error handling and JSON output options.

test: Add comprehensive tests for global relationships

- Developed extensive tests for the global_relationships table in GlobalSymbolIndex.
- Covered schema creation, migration, CRUD operations, and performance benchmarks.
- Ensured project isolation and validated query functionalities for relationships.
This commit is contained in:
catlog22
2026-02-13 11:39:53 +08:00
parent e88d552cd1
commit 17f52da4c6
21 changed files with 1587 additions and 127 deletions

View File

@@ -68,14 +68,15 @@ const task = plan.tasks.find(t => t.id === taskId)
const context = {
// Base context
scope: task.scope,
modification_points: task.modification_points,
files: task.files, // File-level changes (each has .change)
implementation: task.implementation,
// Medium/High complexity: WHY + HOW to verify
// Medium/High complexity: WHY + HOW to verify (PLANNING section)
reference: task.reference, // Reference patterns/files
rationale: task.rationale?.chosen_approach, // Why this approach
verification: task.verification?.success_metrics, // How to verify success
success_metrics: task.test?.success_metrics, // How to verify success
// High complexity: risks + code skeleton
// High complexity: risks + code skeleton (PLANNING section)
risks: task.risks?.map(r => r.mitigation), // Risk mitigations to follow
code_skeleton: task.code_skeleton, // Interface/function signatures
@@ -165,8 +166,8 @@ TASK: {task.implementation.join('\n')}
Key functions: {task.code_skeleton.key_functions.map(f => f.signature)}
# Include verification in EXPECTED
EXPECTED: {task.acceptance.join(', ')}
Success metrics: {task.verification.success_metrics.join(', ')}
EXPECTED: {task.convergence.criteria.join(', ')}
Success metrics: {task.test.success_metrics.join(', ')}
# Include risk mitigations in CONSTRAINTS (High)
CONSTRAINTS: {constraints}
@@ -268,8 +269,8 @@ find .workflow/active/ -name 'WFS-*' -type d
## Phase 5: Log {path} | Summary {summary_path}
[Medium/High] Verification Checklist:
- Unit Tests: {task.verification.unit_tests.join(', ')}
- Success Metrics: {task.verification.success_metrics.join(', ')}
- Unit Tests: {task.test.unit.join(', ')}
- Success Metrics: {task.test.success_metrics.join(', ')}
## Next Steps: {actions}
```

View File

@@ -77,7 +77,7 @@ You are a specialized roadmap planning agent that decomposes requirements into s
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
risks: [{description: string, probability: "Low"|"Medium"|"High", impact: "Low"|"Medium"|"High", mitigation: string}], // Structured risk items for this layer
effort: "small" | "medium" | "large", // Effort estimate
depends_on: ["L{n}"] // Preceding layers
}
@@ -297,8 +297,9 @@ function parseProgressiveLayers(cliOutput) {
scope: scopeMatch?.[1].split(/[,]/).map(s => s.trim()).filter(Boolean) || [],
excludes: excludesMatch?.[1].split(/[,]/).map(s => s.trim()).filter(Boolean) || [],
convergence,
risk_items: riskMatch
risks: riskMatch
? riskMatch[1].split('\n').map(s => s.replace(/^- /, '').trim()).filter(Boolean)
.map(desc => ({description: desc, probability: "Medium", impact: "Medium", mitigation: "N/A"}))
: [],
effort: normalizeEffort(effortMatch?.[1].trim()),
depends_on: parseDependsOn(dependsMatch?.[1], 'L')
@@ -600,14 +601,14 @@ ${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.risks.length ? l.risks.map(r => `\n- ⚠️ ${r.description} (概率: ${r.probability}, 影响: ${r.impact}, 缓解: ${r.mitigation})`).join('') : '无'}
**工作量**: ${l.effort}
`).join('\n---\n\n')}
## 风险汇总
${layers.flatMap(l => l.risk_items.map(r => `- **${l.id}**: ${r}`)).join('\n') || '无已识别风险'}
${layers.flatMap(l => l.risks.map(r => `- **${l.id}**: ${r.description} (概率: ${r.probability}, 影响: ${r.impact})`)).join('\n') || '无已识别风险'}
## 下一步
@@ -683,7 +684,7 @@ function manualProgressiveDecomposition(requirement, context) {
verification: "手动测试核心流程",
definition_of_done: "用户可完成一次核心操作的完整流程"
},
risk_items: ["技术选型待验证"], effort: "medium", depends_on: []
risks: [{description: "技术选型待验证", probability: "Medium", impact: "Medium", mitigation: "待评估"}], effort: "medium", depends_on: []
},
{
id: "L1", name: "可用", goal: "关键用户路径完善",
@@ -693,7 +694,7 @@ function manualProgressiveDecomposition(requirement, context) {
verification: "单元测试 + 手动测试错误场景",
definition_of_done: "用户遇到问题时有清晰的引导和恢复路径"
},
risk_items: [], effort: "medium", depends_on: ["L0"]
risks: [], effort: "medium", depends_on: ["L0"]
}
]
}

View File

@@ -81,10 +81,10 @@ interface Task {
scope: string; // Required: module path or feature area
action: Action; // Required: Create|Update|Implement|...
description?: string;
modification_points?: Array<{file, target, change}>;
files?: Array<{path, target, change}>;
implementation: string[]; // Required: step-by-step guide
test?: { unit?, integration?, commands?, coverage_target? };
acceptance: { criteria: string[], verification: string[] }; // Required
convergence: { criteria: string[], verification: string[] }; // Required
commit?: { type, scope, message_template, breaking? };
depends_on?: string[];
priority?: number; // 1-5 (default: 3)
@@ -202,14 +202,14 @@ function extractFromLitePlan(folderPath) {
scope: t.scope || '',
action: t.action || 'Implement',
description: t.description || t.title,
modification_points: t.modification_points || [],
files: (t.modification_points || []).map(mp => ({ path: mp.file, target: mp.target, change: mp.change })),
implementation: Array.isArray(t.implementation) ? t.implementation : [t.implementation || ''],
test: t.verification ? {
unit: t.verification.unit_tests,
integration: t.verification.integration_tests,
commands: t.verification.manual_checks
} : {},
acceptance: {
convergence: {
criteria: Array.isArray(t.acceptance) ? t.acceptance : [t.acceptance || ''],
verification: t.verification?.manual_checks || []
},
@@ -258,10 +258,10 @@ function extractFromWorkflowSession(sessionPath) {
scope: task.scope || inferScopeFromTask(task),
action: capitalizeAction(task.type) || 'Implement',
description: task.description,
modification_points: task.implementation?.modification_points || [],
files: (task.implementation?.modification_points || []).map(mp => ({ path: mp.file, target: mp.target, change: mp.change })),
implementation: task.implementation?.steps || [],
test: task.implementation?.test || {},
acceptance: {
convergence: {
criteria: task.acceptance_criteria || [],
verification: task.verification_steps || []
},
@@ -286,10 +286,10 @@ function extractFromWorkflowSession(sessionPath) {
}
function inferScopeFromTask(task) {
if (task.implementation?.modification_points?.length) {
const files = task.implementation.modification_points.map(m => m.file);
if (task.files?.length) {
const paths = task.files.map(f => f.path);
// Find common directory prefix
const dirs = files.map(f => f.split('/').slice(0, -1).join('/'));
const dirs = paths.map(p => p.split('/').slice(0, -1).join('/'));
return [...new Set(dirs)][0] || '';
}
return '';
@@ -354,10 +354,10 @@ ${fileContent}`;
scope: t.scope || '',
action: validateAction(t.action) || 'Implement',
description: t.description || t.title,
modification_points: t.modification_points || [],
files: (t.modification_points || []).map(mp => ({ path: mp.file, target: mp.target, change: mp.change })),
implementation: Array.isArray(t.implementation) ? t.implementation : [t.implementation || ''],
test: t.test || {},
acceptance: {
convergence: {
criteria: Array.isArray(t.acceptance) ? t.acceptance : [t.acceptance || ''],
verification: t.verification || []
},
@@ -406,10 +406,10 @@ function extractFromJsonFile(filePath) {
scope: t.scope || '',
action: t.action || 'Implement',
description: t.description || t.title,
modification_points: t.modification_points || [],
files: (t.modification_points || []).map(mp => ({ path: mp.file, target: mp.target, change: mp.change })),
implementation: Array.isArray(t.implementation) ? t.implementation : [t.implementation || ''],
test: t.test || t.verification || {},
acceptance: normalizeAcceptance(t.acceptance),
convergence: normalizeConvergence(t.acceptance, t.convergence),
depends_on: t.depends_on || [],
priority: t.priority || 3
}));
@@ -431,11 +431,13 @@ function extractFromJsonFile(filePath) {
throw new Error('E002: JSON file does not contain valid plan structure (missing tasks array)');
}
function normalizeAcceptance(acceptance) {
if (!acceptance) return { criteria: [], verification: [] };
if (typeof acceptance === 'object' && acceptance.criteria) return acceptance;
if (Array.isArray(acceptance)) return { criteria: acceptance, verification: [] };
return { criteria: [String(acceptance)], verification: [] };
function normalizeConvergence(acceptance, convergence) {
// Prefer new convergence field; fall back to legacy acceptance
const source = convergence || acceptance;
if (!source) return { criteria: [], verification: [] };
if (typeof source === 'object' && source.criteria) return source;
if (Array.isArray(source)) return { criteria: source, verification: [] };
return { criteria: [String(source)], verification: [] };
}
```

View File

@@ -0,0 +1,347 @@
---
name: update-single
description: Update single module CLAUDE.md using Explore agent for deep codebase understanding, producing manual-style documentation (handbook, not API reference)
argument-hint: "<path> [--tool gemini|qwen|codex]"
allowed-tools: Task(*), Bash(*), AskUserQuestion(*)
---
# Single Module Documentation Update (/memory:update-single)
## Overview
Generates a manual-style CLAUDE.md for a single target directory using Explore agent for deep semantic codebase understanding. The output reads like a module handbook — explaining what it does, how to use it, and how it integrates — rather than dry API documentation.
**Core capabilities:**
- Explore agent for semantic codebase exploration (not just file scanning)
- Manual/handbook-style output (usage guide, not reference docs)
- Interactive confirmation with exploration summary preview
- Tool fallback (gemini→qwen→codex)
## Usage
```bash
/memory:update-single <path> [--tool gemini|qwen|codex]
# Arguments
<path> Target directory path (required)
# Options
--tool <gemini|qwen|codex> Primary CLI tool (default: gemini)
# Examples
/memory:update-single src/auth
/memory:update-single .claude/commands --tool qwen
/memory:update-single ccw/frontend/src/components/issue
```
## Output Artifacts
| Artifact | Description |
|----------|-------------|
| `<path>/CLAUDE.md` | Manual-style module handbook |
**CLAUDE.md Style** — "说明书" not "文档":
- What this module does (purpose & responsibility)
- How to use it (patterns, conventions, examples)
- How it integrates (dependencies, exports, data flow)
- Important constraints (gotchas, rules, limitations)
## Execution Process
```
Phase 1: Target Validation & Scan
├─ Parse arguments (path, --tool)
├─ Validate target directory exists
└─ Quick structure scan (file count, types, depth)
Phase 2: Deep Exploration (Explore Agent)
├─ Launch Explore agent with "very thorough" level
├─ Analyze purpose, structure, patterns, exports, dependencies
└─ Build comprehensive module understanding
Phase 3: Confirmation
├─ Display exploration summary (key findings)
└─ AskUserQuestion: Generate / Cancel
Phase 4: Generate CLAUDE.md (CLI Tool)
├─ Construct manual-style prompt from exploration results
├─ Execute ccw cli with --mode write
├─ Tool fallback on failure
└─ Write to <path>/CLAUDE.md
Phase 5: Verification
└─ Display generated CLAUDE.md preview + stats
```
## Implementation
### Phase 1: Target Validation & Scan
```javascript
// Parse arguments
const args = $ARGUMENTS.trim()
const parts = args.split(/\s+/)
const toolFlagIdx = parts.indexOf('--tool')
const primaryTool = toolFlagIdx !== -1 ? parts[toolFlagIdx + 1] : 'gemini'
const targetPath = parts.find(p => !p.startsWith('--') && p !== primaryTool)
if (!targetPath) {
console.log('ERROR: <path> is required. Usage: /memory:update-single <path> [--tool gemini|qwen|codex]')
return
}
// Validate path exists
Bash({ command: `test -d "${targetPath}" && echo "EXISTS" || echo "NOT_FOUND"`, run_in_background: false })
// → NOT_FOUND: abort with error
// Quick structure scan
Bash({ command: `find "${targetPath}" -maxdepth 3 -type f -not -path "*/node_modules/*" -not -path "*/.git/*" | wc -l`, run_in_background: false })
Bash({ command: `ls "${targetPath}"`, run_in_background: false })
// Check existing CLAUDE.md
const hasExisting = file_exists(`${targetPath}/CLAUDE.md`)
console.log(`
## Target: ${targetPath}
Files: ${fileCount}
Existing CLAUDE.md: ${hasExisting ? 'Yes (will be overwritten)' : 'No (new)'}
Tool: ${primaryTool}
Launching deep exploration...
`)
```
### Phase 2: Deep Exploration (Explore Agent)
**⚠️ CRITICAL**: Use `run_in_background: false` — exploration results are REQUIRED before generation.
```javascript
const explorationResult = Task(
subagent_type="Explore",
run_in_background=false,
description=`Explore: ${targetPath}`,
prompt=`
Thoroughly explore the module at "${targetPath}" with "very thorough" level. I need comprehensive understanding for generating a manual-style CLAUDE.md (说明书).
## Exploration Focus
Analyze from these 7 dimensions:
1. **Purpose & Responsibility**
- What problem does this module solve?
- What is its core responsibility in the larger system?
- One-sentence summary a developer would use to describe it
2. **Directory Structure & Key Files**
- Map directory layout and file organization
- Identify entry points, core logic files, utilities, types
- Note any naming conventions or organizational patterns
3. **Code Patterns & Conventions**
- Common patterns used (factory, observer, middleware, hooks, etc.)
- Import/export conventions
- Error handling patterns
- State management approach (if applicable)
4. **Public API / Exports**
- What does this module expose to the outside?
- Key functions, classes, components, types exported
- How do consumers typically import from this module?
5. **Dependencies & Integration**
- External packages this module depends on
- Internal modules it imports from
- Modules that depend on this one (reverse dependencies)
- Data flow: how data enters and exits this module
6. **Constraints & Gotchas**
- Non-obvious rules a developer must follow
- Performance considerations
- Security-sensitive areas
- Common pitfalls or mistakes
7. **Development Workflow**
- How to add new functionality to this module
- Testing approach used
- Build/compilation specifics (if any)
## Output Format
Return a structured summary covering all 7 dimensions above. Include specific file:line references where relevant. Focus on **actionable knowledge** — what a developer needs to know to work with this module effectively.
`
)
```
### Phase 3: Confirmation
```javascript
console.log(`
## Exploration Summary
${explorationResult}
---
**Will generate**: ${targetPath}/CLAUDE.md
**Style**: Manual/handbook (说明书)
**Tool**: ${primaryTool}
`)
AskUserQuestion({
questions: [{
question: `Generate manual-style CLAUDE.md for "${targetPath}"?`,
header: "Confirm",
multiSelect: false,
options: [
{ label: "Generate", description: "Write CLAUDE.md based on exploration" },
{ label: "Cancel", description: "Abort without changes" }
]
}]
})
// Cancel → abort
```
### Phase 4: Generate CLAUDE.md (CLI Tool)
**Tool fallback hierarchy**:
```javascript
const toolOrder = {
'gemini': ['gemini', 'qwen', 'codex'],
'qwen': ['qwen', 'gemini', 'codex'],
'codex': ['codex', 'gemini', 'qwen']
}[primaryTool]
```
**Generation via ccw cli**:
```javascript
for (let tool of toolOrder) {
Bash({
command: `ccw cli -p "PURPOSE: Generate a manual-style CLAUDE.md (说明书) for the module at current directory.
This CLAUDE.md should read like a developer handbook — practical, actionable, concise.
## Exploration Context (use as primary source)
${explorationResult}
## CLAUDE.md Structure Requirements
Generate CLAUDE.md following this exact structure:
### 1. Title & Summary
\`# <Module Name>\`
> One-line description of purpose
### 2. Responsibilities
- Bullet list of what this module owns
- Keep to 3-7 items, each one sentence
### 3. Structure
\`\`\`
directory-tree/
├── key-files-only
└── with-brief-annotations
\`\`\`
### 4. Key Patterns
- Code conventions specific to THIS module
- Import patterns, naming rules, style decisions
- NOT generic best practices — only module-specific patterns
### 5. Usage
- How other modules use this one
- Common import/usage examples (real code, not pseudo-code)
### 6. Integration Points
- **Depends on**: modules/packages this uses (with purpose)
- **Used by**: modules that import from here
### 7. Constraints & Gotchas
- Non-obvious rules developers MUST follow
- Common mistakes to avoid
- Performance or security notes
## Style Rules
- Be CONCISE: each section 3-10 lines max
- Be PRACTICAL: actionable knowledge only, no boilerplate
- Be SPECIFIC: reference actual files and patterns, not generic advice
- No API reference listings — this is a handbook, not a reference doc
- Total length: 50-150 lines of markdown
- Language: Match the project's primary language (check existing CLAUDE.md files)
MODE: write
CONTEXT: @**/*
EXPECTED: Single CLAUDE.md file at ./CLAUDE.md following the structure above
CONSTRAINTS: Only write CLAUDE.md, no other files" --tool ${tool} --mode write --cd "${targetPath}"`,
run_in_background: false
})
if (exit_code === 0) {
console.log(`${targetPath}/CLAUDE.md generated with ${tool}`)
break
}
console.log(`⚠️ ${tool} failed, trying next...`)
}
```
### Phase 5: Verification
```javascript
// Check file was created/updated
Bash({ command: `test -f "${targetPath}/CLAUDE.md" && echo "EXISTS" || echo "MISSING"`, run_in_background: false })
// Show stats
Bash({ command: `wc -l "${targetPath}/CLAUDE.md"`, run_in_background: false })
// Preview first 30 lines
Read(`${targetPath}/CLAUDE.md`, { limit: 30 })
console.log(`
## Result
✅ Generated: ${targetPath}/CLAUDE.md
Lines: ${lineCount}
Style: Manual/handbook format
Tool: ${usedTool}
`)
```
## CLAUDE.md Output Style Guide
The generated CLAUDE.md is a **说明书 (handbook)**, NOT a reference doc:
| Aspect | Handbook Style ✅ | Reference Doc Style ❌ |
|--------|-------------------|----------------------|
| Purpose | "This module handles user auth" | "Authentication module" |
| Content | How to work with it | What every function does |
| Patterns | "Always use `createAuthMiddleware()`" | "List of all exports" |
| Constraints | "Never store tokens in localStorage" | "Token storage API" |
| Length | 50-150 lines | 300+ lines |
| Audience | Developer joining the team | API consumer |
## Error Handling
| Error | Resolution |
|-------|------------|
| Path not found | Abort with clear error message |
| Explore agent failure | Fallback to basic `ls` + `head` file scan, continue |
| All CLI tools fail | Report failure with last error, suggest `--tool` override |
| Empty directory | Abort — nothing to document |
| Existing CLAUDE.md | Overwrite entirely (full regeneration) |
## Usage Examples
```bash
# Generate handbook for a module
/memory:update-single src/auth
# Use specific tool
/memory:update-single .claude/commands --tool qwen
# Deep nested module
/memory:update-single ccw/frontend/src/components/issue
# Root-level documentation
/memory:update-single .
```

View File

@@ -34,6 +34,26 @@ mcp__ccw-tools__team_msg({ operation: "read", team: teamName, id: "MSG-003" })
**日志位置**: `.workflow/.team-msg/{team-name}/messages.jsonl`
**消息类型**: `plan_ready | plan_approved | plan_revision | task_unblocked | impl_complete | impl_progress | test_result | review_result | fix_required | error | shutdown`
### CLI 回退
`mcp__ccw-tools__team_msg` MCP 不可用时,使用 `ccw team` CLI 作为等效回退:
```javascript
// 回退: 将 MCP 调用替换为 Bash CLI参数一一对应
// log
Bash(`ccw team log --team "${teamName}" --from "coordinator" --to "planner" --type "plan_approved" --summary "Plan已批准" --json`)
// list
Bash(`ccw team list --team "${teamName}" --last 10 --json`)
// list (带过滤)
Bash(`ccw team list --team "${teamName}" --from "tester" --last 5 --json`)
// status
Bash(`ccw team status --team "${teamName}" --json`)
// read
Bash(`ccw team read --team "${teamName}" --id "MSG-003" --json`)
```
**参数映射**: `team_msg(params)``ccw team <operation> --team <team> [--from/--to/--type/--summary/--ref/--data/--id/--last] [--json]`
## Usage
```bash

View File

@@ -15,7 +15,7 @@ Team executor role command. Operates as a teammate within an Agent Team, respons
**Core capabilities:**
- Task discovery from shared team task list (IMPL-* tasks)
- Plan loading and task decomposition
- Code implementation following plan modification points
- Code implementation following plan files list
- Self-validation: syntax checks, acceptance criteria verification
- Progress reporting to coordinator
- Sub-agent delegation for complex tasks
@@ -71,7 +71,7 @@ Phase 2: Task Grouping
Phase 3: Code Implementation
├─ For each task in plan:
│ ├─ Read modification points
│ ├─ Read files list
│ ├─ Read reference patterns
│ ├─ Implement changes (Edit/Write)
│ ├─ Complex tasks → code-developer sub-agent
@@ -186,8 +186,8 @@ function buildExecutionPrompt(planTask) {
**Scope**: \`${planTask.scope}\` | **Action**: ${planTask.action || 'implement'}
### Modification Points
${(planTask.modification_points || []).map(p => `- **${p.file}** → \`${p.target}\`: ${p.change}`).join('\n')}
### Files
${(planTask.files || []).map(f => `- **${f.path}** → \`${f.target}\`: ${f.change}`).join('\n')}
### How to do it
${planTask.description}
@@ -199,7 +199,7 @@ ${(planTask.implementation || []).map(step => `- ${step}`).join('\n')}
- Files: ${planTask.reference?.files?.join(', ') || 'N/A'}
### Done when
${(planTask.acceptance || []).map(c => `- [ ] ${c}`).join('\n')}
${(planTask.convergence?.criteria || []).map(c => `- [ ] ${c}`).join('\n')}
`
}
@@ -212,11 +212,11 @@ for (const batch of batches) {
// Simple task: direct implementation
const t = batch.tasks[0]
// Read target files, apply modifications using Edit/Write
for (const mp of (t.modification_points || [])) {
const content = Read(mp.file)
// Apply change based on modification point description
Edit({ file_path: mp.file, old_string: "...", new_string: "..." })
changedFiles.push(mp.file)
for (const f of (t.files || [])) {
const content = Read(f.path)
// Apply change based on file entry description
Edit({ file_path: f.path, old_string: "...", new_string: "..." })
changedFiles.push(f.path)
}
} else {
// Complex task(s): delegate to code-developer sub-agent
@@ -241,7 +241,7 @@ Complete each task according to its "Done when" checklist.`
// Collect changed files from sub-agent results
batch.tasks.forEach(t => {
(t.modification_points || []).forEach(mp => changedFiles.push(mp.file))
(t.files || []).forEach(f => changedFiles.push(f.path))
})
}
@@ -269,7 +269,7 @@ if (hasSyntaxErrors) {
// Step 2: Verify acceptance criteria
const acceptanceStatus = plan.tasks.map(t => ({
title: t.title,
criteria: (t.acceptance || []).map(c => ({
criteria: (t.convergence?.criteria || []).map(c => ({
criterion: c,
met: true // Evaluate based on implementation
}))
@@ -341,7 +341,7 @@ if (nextTasks.length > 0) {
```javascript
function isSimpleTask(task) {
return (task.modification_points || []).length <= 2 &&
return (task.files || []).length <= 2 &&
!task.code_skeleton &&
(task.risks || []).length === 0
}

View File

@@ -41,7 +41,8 @@ When `--yes` or `-y`: Auto-approve splits, skip confirmations.
| Artifact | Description |
|----------|-------------|
| `planning-context.md` | Evidence paths + synthesized understanding |
| `plan.json` | Complete agent plan (detailed implementation) |
| `plan.json` | Plan overview with task_ids[] (NO embedded tasks[]) |
| `.task/TASK-*.json` | Independent task files following task-schema.json |
| Updates to `plan-note.md` | Agent fills pre-allocated sections |
### Phase 3: Final Output
@@ -96,12 +97,15 @@ Unified collaborative planning workflow using **Plan Note** architecture:
```
.workflow/.planning/{CPLAN-slug-YYYY-MM-DD}/
├── plan-note.md # Core: Requirements + Tasks + Conflicts
├── plan-note.md # Core: Requirements + Tasks + Conflicts
├── requirement-analysis.json # Phase 1: Sub-domain assignments
├── agents/ # Phase 2: Per-agent detailed plans
│ ├── {focus-area-1}/
│ │ ├── planning-context.md # Evidence + understanding
│ │ ── plan.json # Complete agent plan
│ │ ── plan.json # Plan overview with task_ids[] (NO embedded tasks[])
│ │ └── .task/ # Independent task files
│ │ ├── TASK-{ID}.json # Task file following task-schema.json
│ │ └── ...
│ ├── {focus-area-2}/
│ │ └── ...
│ └── {focus-area-N}/
@@ -280,8 +284,8 @@ Structure Requirements:
| Task | Output | Description |
|------|--------|-------------|
| Generate plan.json | `{sessionFolder}/agents/{focus-area}/plan.json` | Complete detailed plan following schema |
| Update plan-note.md | Sync to shared file | Fill pre-allocated "任务池" and "上下文证据" sections |
| Generate plan.json + .task/*.json | `{sessionFolder}/agents/{focus-area}/plan.json` + `.task/` | Two-layer output: plan overview + independent task files |
| Update plan-note.md | Sync to shared file | Fill pre-allocated task pool and evidence sections |
**Task Summary Format** (for plan-note.md):
- Task header: `### TASK-{ID}: {Title} [{focus-area}]`
@@ -347,9 +351,18 @@ subDomains.map(sub =>
## Dual Output Tasks
### Task 1: Generate Complete plan.json
Output: ${sessionFolder}/agents/${sub.focus_area}/plan.json
Schema: ~/.ccw/workflows/cli-templates/schemas/plan-json-schema.json
### Task 1: Generate Two-Layer Plan Output
Output: ${sessionFolder}/agents/${sub.focus_area}/plan.json (overview with task_ids[])
Output: ${sessionFolder}/agents/${sub.focus_area}/.task/TASK-*.json (independent task files)
Schema (plan): ~/.ccw/workflows/cli-templates/schemas/plan-overview-base-schema.json
Schema (tasks): ~/.ccw/workflows/cli-templates/schemas/task-schema.json
**Two-Layer Output Format**:
- plan.json: Overview with task_ids[] referencing .task/ files (NO tasks[] array)
- .task/TASK-*.json: Independent task files following task-schema.json
- plan.json required: summary, approach, task_ids, task_count, _metadata (with plan_type)
- Task files required: id, title, description, depends_on, convergence (with criteria[])
- Task fields: files[].change (not modification_points), convergence.criteria (not acceptance), test (not verification)
### Task 2: Sync Summary to plan-note.md
@@ -365,12 +378,14 @@ Schema: ~/.ccw/workflows/cli-templates/schemas/plan-json-schema.json
- 相关文件, 现有模式, 约束
## Execution Steps
1. Generate complete plan.json
2. Extract summary from plan.json
3. Read ${sessionFolder}/plan-note.md
4. Locate and replace your task pool section
5. Locate and replace your evidence section
6. Write back plan-note.md
1. Create .task/ directory: mkdir -p ${sessionFolder}/agents/${sub.focus_area}/.task
2. Generate individual task files in .task/TASK-*.json following task-schema.json
3. Generate plan.json with task_ids[] referencing .task/ files (NO embedded tasks[])
4. Extract summary from .task/*.json files
5. Read ${sessionFolder}/plan-note.md
6. Locate and replace your task pool section
7. Locate and replace your evidence section
8. Write back plan-note.md
## Important
- Only modify your pre-allocated sections

View File

@@ -122,11 +122,15 @@ fileContent = Read(filePath)
try {
jsonData = JSON.parse(fileContent)
// Check if plan.json from lite-plan session
if (jsonData.summary && jsonData.approach && jsonData.tasks) {
// Check if plan.json from lite-plan session (two-layer format: task_ids[])
if (jsonData.summary && jsonData.approach && jsonData.task_ids) {
planObject = jsonData
originalUserInput = jsonData.summary
isPlanJson = true
// Load tasks from .task/*.json files
const planDir = filePath.replace(/[/\\][^/\\]+$/, '') // parent directory
planObject._loadedTasks = loadTaskFiles(planDir, jsonData.task_ids)
} else {
// Valid JSON but not plan.json - treat as plain text
originalUserInput = fileContent
@@ -155,6 +159,23 @@ If `isPlanJson === false`:
- AskUserQuestion: Select code review tool
- Proceed to execution with full context
## Helper Functions
```javascript
// Load task files from .task/ directory (two-layer format)
function loadTaskFiles(planDir, taskIds) {
return taskIds.map(id => {
const taskPath = `${planDir}/.task/${id}.json`
return JSON.parse(Read(taskPath))
})
}
// Get tasks array from loaded .task/*.json files
function getTasks(planObject) {
return planObject._loadedTasks || []
}
```
## Execution Process
```
@@ -202,7 +223,7 @@ if (executionContext) {
📋 Execution Strategy (from lite-plan):
Method: ${executionContext.executionMethod}
Review: ${executionContext.codeReviewTool}
Tasks: ${executionContext.planObject.tasks.length}
Tasks: ${getTasks(executionContext.planObject).length}
Complexity: ${executionContext.planObject.complexity}
${executionContext.executorAssignments ? ` Assignments: ${JSON.stringify(executionContext.executorAssignments)}` : ''}
`)
@@ -277,7 +298,7 @@ function createExecutionCalls(tasks, executionMethod) {
return calls
}
executionCalls = createExecutionCalls(planObject.tasks, executionMethod).map(c => ({ ...c, id: `[${c.groupId}]` }))
executionCalls = createExecutionCalls(getTasks(planObject), executionMethod).map(c => ({ ...c, id: `[${c.groupId}]` }))
TodoWrite({
todos: executionCalls.map(c => ({
@@ -345,14 +366,14 @@ for (const call of sequential) {
```javascript
function buildExecutionPrompt(batch) {
// Task template (6 parts: Modification Points → Why → How → Reference → Risks → Done)
// Task template (6 parts: Files → Why → How → Reference → Risks → Done)
const formatTask = (t) => `
## ${t.title}
**Scope**: \`${t.scope}\` | **Action**: ${t.action}
### Modification Points
${t.modification_points.map(p => `- **${p.file}** → \`${p.target}\`: ${p.change}`).join('\n')}
### Files
${(t.files || []).map(f => `- **${f.path}** → \`${f.target || ''}\`: ${f.change || (f.changes || []).join(', ') || ''}`).join('\n')}
${t.rationale ? `
### Why this approach (Medium/High)
@@ -384,8 +405,8 @@ ${t.risks.map(r => `- ${r.description} → **${r.mitigation}**`).join('\n')}
` : ''}
### Done when
${t.acceptance.map(c => `- [ ] ${c}`).join('\n')}
${t.verification?.success_metrics?.length > 0 ? `\n**Success metrics**: ${t.verification.success_metrics.join(', ')}` : ''}`
${(t.convergence?.criteria || []).map(c => `- [ ] ${c}`).join('\n')}
${(t.test?.success_metrics || []).length > 0 ? `\n**Success metrics**: ${t.test.success_metrics.join(', ')}` : ''}`
// Build prompt
const sections = []
@@ -505,11 +526,11 @@ Progress tracked at batch level (not individual task level). Icons: ⚡ (paralle
**Skip Condition**: Only run if `codeReviewTool ≠ "Skip"`
**Review Focus**: Verify implementation against plan acceptance criteria and verification requirements
- Read plan.json for task acceptance criteria and verification checklist
- Check each acceptance criterion is fulfilled
- Verify success metrics from verification field (Medium/High complexity)
- Run unit/integration tests specified in verification field
**Review Focus**: Verify implementation against plan convergence criteria and test requirements
- Read plan.json + .task/*.json for task convergence criteria and test checklist
- Check each convergence criterion is fulfilled
- Verify success metrics from test field (Medium/High complexity)
- Run unit/integration tests specified in test field
- Validate code quality and identify issues
- Ensure alignment with planned approach and risk mitigations
@@ -522,24 +543,24 @@ Progress tracked at batch level (not individual task level). Icons: ⚡ (paralle
**Unified Review Template** (All tools use same standard):
**Review Criteria**:
- **Acceptance Criteria**: Verify each criterion from plan.tasks[].acceptance
- **Verification Checklist** (Medium/High): Check unit_tests, integration_tests, success_metrics from plan.tasks[].verification
- **Convergence Criteria**: Verify each criterion from task convergence.criteria
- **Test Checklist** (Medium/High): Check unit, integration, success_metrics from task test
- **Code Quality**: Analyze quality, identify issues, suggest improvements
- **Plan Alignment**: Validate implementation matches planned approach and risk mitigations
**Shared Prompt Template** (used by all CLI tools):
```
PURPOSE: Code review for implemented changes against plan acceptance criteria and verification requirements
TASK: • Verify plan acceptance criteria fulfillment • Check verification requirements (unit tests, success metrics) • Analyze code quality • Identify issues • Suggest improvements • Validate plan adherence and risk mitigations
PURPOSE: Code review for implemented changes against plan convergence criteria and test requirements
TASK: • Verify plan convergence criteria fulfillment • Check test requirements (unit, integration, success_metrics) • Analyze code quality • Identify issues • Suggest improvements • Validate plan adherence and risk mitigations
MODE: analysis
CONTEXT: @**/* @{plan.json} [@{exploration.json}] | Memory: Review lite-execute changes against plan requirements including verification checklist
CONTEXT: @**/* @{plan.json} @{.task/*.json} [@{exploration.json}] | Memory: Review lite-execute changes against plan requirements including test checklist
EXPECTED: Quality assessment with:
- Acceptance criteria verification (all tasks)
- Verification checklist validation (Medium/High: unit_tests, integration_tests, success_metrics)
- Convergence criteria verification (all tasks from .task/*.json)
- Test checklist validation (Medium/High: unit, integration, success_metrics)
- Issue identification
- Recommendations
Explicitly check each acceptance criterion and verification item from plan.json tasks.
CONSTRAINTS: Focus on plan acceptance criteria, verification requirements, and plan adherence | analysis=READ-ONLY
Explicitly check each convergence criterion and test item from .task/*.json files.
CONSTRAINTS: Focus on plan convergence criteria, test requirements, and plan adherence | analysis=READ-ONLY
```
**Tool-Specific Execution** (Apply shared prompt template above):
@@ -628,7 +649,7 @@ function detectSubFeature(tasks) {
const category = detectCategory(`${planObject.summary} ${planObject.approach}`)
const entry = {
title: planObject.summary.slice(0, 60),
sub_feature: detectSubFeature(planObject.tasks),
sub_feature: detectSubFeature(getTasks(planObject)),
date: new Date().toISOString().split('T')[0],
description: planObject.approach.slice(0, 100),
status: previousExecutionResults.every(r => r.status === 'completed') ? 'completed' : 'partial',
@@ -673,11 +694,15 @@ Passed from lite-plan via global variable:
planObject: {
summary: string,
approach: string,
tasks: [...],
task_ids: string[], // Task IDs referencing .task/*.json files
task_count: number, // Number of tasks
_loadedTasks: [...], // Populated at runtime from .task/*.json files
estimated_time: string,
recommended_execution: string,
complexity: string
},
// Task file paths (populated for two-layer format)
taskFiles: [{id: string, path: string}] | null,
explorationsContext: {...} | null, // Multi-angle explorations
explorationAngles: string[], // List of exploration angles
explorationManifest: {...} | null, // Exploration manifest

View File

@@ -82,8 +82,8 @@ Phase 4: User Decision
└─ Cancel → Save session
Phase 5: Plan Generation & Execution Handoff
├─ Generate plan.json (via @cli-lite-planning-agent)
├─ Build executionContext with user selections
├─ Generate plan.json + .task/*.json (via @cli-lite-planning-agent, two-layer output)
├─ Build executionContext with user selections and taskFiles
└─ Execute to /workflow:lite-execute --in-memory
```
@@ -93,7 +93,7 @@ Phase 5: Plan Generation & Execution Handoff
|-------|---------------|
| **Orchestrator** | Session management, ACE context, user decisions, phase transitions, executionContext assembly |
| **@cli-discuss-agent** | Multi-CLI execution (Gemini/Codex/Claude), cross-verification, solution synthesis, synthesis.json output |
| **@cli-lite-planning-agent** | Task decomposition, plan.json generation following schema |
| **@cli-lite-planning-agent** | Task decomposition, two-layer output: plan.json (overview with task_ids[]) + .task/*.json (task files) |
## Core Responsibilities
@@ -360,13 +360,22 @@ Task({
description: "Generate implementation plan",
prompt: `
## Schema Reference
Execute: cat ~/.ccw/workflows/cli-templates/schemas/plan-json-schema.json
Execute: cat ~/.ccw/workflows/cli-templates/schemas/plan-overview-base-schema.json
Execute: cat ~/.ccw/workflows/cli-templates/schemas/task-schema.json
## Output Format: Two-Layer Structure
- plan.json: Overview with task_ids[] referencing .task/ files (NO tasks[] array)
- .task/TASK-*.json: Independent task files following task-schema.json
plan.json required: summary, approach, task_ids, task_count, _metadata (with plan_type)
Task files required: id, title, description, depends_on, convergence (with criteria[])
Task fields: files[].change (not modification_points), convergence.criteria (not acceptance), test (not verification)
## Context-Package (from orchestrator)
${JSON.stringify(contextPackage, null, 2)}
## Execution Process
1. Read plan-json-schema.json for output structure
1. Read plan-overview-base-schema.json + task-schema.json for output structure
2. Read project-tech.json and project-guidelines.json
3. Parse context-package fields:
- solution: name, feasibility, summary
@@ -377,19 +386,23 @@ ${JSON.stringify(contextPackage, null, 2)}
- constraints: user requirements
4. Use implementation_plan.tasks[] as task foundation
5. Preserve task dependencies (depends_on) and execution_flow
6. Expand tasks with detailed acceptance criteria
7. Generate plan.json following schema exactly
6. Expand tasks with convergence.criteria (testable completion conditions)
7. Create .task/ directory and write individual TASK-*.json files
8. Generate plan.json with task_ids[] referencing .task/ files
## Output
- ${sessionFolder}/plan.json
- ${sessionFolder}/plan.json (overview with task_ids[])
- ${sessionFolder}/.task/TASK-*.json (independent task files)
## Completion Checklist
- [ ] plan.json preserves task dependencies from implementation_plan
- [ ] plan.json has task_ids[] and task_count (NO embedded tasks[])
- [ ] .task/*.json files preserve task dependencies from implementation_plan
- [ ] Task execution order follows execution_flow
- [ ] Key_points reflected in task descriptions
- [ ] User constraints applied to implementation
- [ ] Acceptance criteria are testable
- [ ] Schema fields match plan-json-schema.json exactly
- [ ] convergence.criteria are testable
- [ ] plan.json follows plan-overview-base-schema.json
- [ ] Task files follow task-schema.json
`
})
```
@@ -399,9 +412,13 @@ ${JSON.stringify(contextPackage, null, 2)}
// After plan.json is generated by cli-lite-planning-agent
const plan = JSON.parse(Read(`${sessionFolder}/plan.json`))
// Load task files from .task/ directory (two-layer format)
const taskFiles = plan.task_ids.map(id => `${sessionFolder}/.task/${id}.json`)
// Build executionContext (same structure as lite-plan)
executionContext = {
planObject: plan,
taskFiles: taskFiles, // Paths to .task/*.json files (two-layer format)
explorationsContext: null, // Multi-CLI doesn't use exploration files
explorationAngles: [], // No exploration angles
explorationManifest: null, // No manifest
@@ -420,6 +437,7 @@ executionContext = {
explorations: [], // No explorations in multi-CLI workflow
explorations_manifest: null,
plan: `${sessionFolder}/plan.json`,
task_dir: plan.task_ids ? `${sessionFolder}/.task/` : null,
synthesis_rounds: Array.from({length: currentRound}, (_, i) =>
`${sessionFolder}/rounds/${i+1}/synthesis.json`
),
@@ -445,7 +463,11 @@ Skill(skill="workflow:lite-execute", args="--in-memory")
│ ├── 2/synthesis.json # Round 2 analysis (cli-discuss-agent)
│ └── .../
├── context-package.json # Extracted context for planning (orchestrator)
── plan.json # Structured plan (cli-lite-planning-agent)
── plan.json # Plan overview with task_ids[] (NO embedded tasks[])
└── .task/ # Independent task files
├── TASK-001.json # Task file following task-schema.json
├── TASK-002.json
└── ...
```
**File Producers**:
@@ -455,7 +477,8 @@ Skill(skill="workflow:lite-execute", args="--in-memory")
| `session-state.json` | Orchestrator | Session metadata, rounds, decisions |
| `rounds/*/synthesis.json` | cli-discuss-agent | Solutions, convergence, cross-verification |
| `context-package.json` | Orchestrator | Extracted solution, dependencies, consensus for planning |
| `plan.json` | cli-lite-planning-agent | Structured tasks for lite-execute |
| `plan.json` | cli-lite-planning-agent | Plan overview with task_ids[] referencing .task/ files |
| `.task/*.json` | cli-lite-planning-agent | Independent task files following task-schema.json |
## synthesis.json Schema

View File

@@ -115,8 +115,8 @@ Requirement-level layered roadmap planning command. Decomposes a requirement int
## Convergence Criteria Details
{Expanded convergence for each layer/task}
## Risk Items
{Aggregated risk_items}
## Risks
{Aggregated risks}
## Next Steps
{Execution guidance}
@@ -158,11 +158,11 @@ Each line = one layer. Layer naming convention:
| 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[]`
**Schema**: `id, name, goal, scope[], excludes[], convergence{}, risks[], 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"]}
{"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"},"risks":[{"description":"JWT library selection needs validation","probability":"Medium","impact":"Medium","mitigation":"N/A"}],"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"},"risks":[],"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).
@@ -467,7 +467,7 @@ Bash(`mkdir -p ${sessionFolder}`)
${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
- Each layer: id (L0-L3), name, goal, scope, excludes, convergence, risks, 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` :