feat(cli): add settings file support for builtin Claude

- Enhance CLI status rendering to display settings file information for builtin Claude.
- Introduce settings file input in CLI manager for configuring the path to settings.json.
- Update Claude CLI tool interface to include settingsFile property.
- Implement settings file resolution and validation in CLI executor.
- Create a new collaborative planning workflow command with detailed documentation.
- Add test scripts for debugging tool configuration and command building.
This commit is contained in:
catlog22
2026-01-30 10:07:02 +08:00
parent 4b69492b16
commit 3f46a02df3
12 changed files with 1130 additions and 1267 deletions

View File

@@ -0,0 +1,836 @@
---
name: workflow:collaborative-plan
description: Unified collaborative planning with dynamic requirement splitting, parallel sub-agent exploration/understanding/planning, and automatic merge. Each agent maintains process files for full traceability.
argument-hint: "[-y|--yes] <task description> [--max-agents=5] [--depth=normal|deep] [--merge-rule=consensus|priority]"
allowed-tools: TodoWrite(*), Task(*), AskUserQuestion(*), Read(*), Bash(*), Write(*), Glob(*), Grep(*), mcp__ace-tool__search_context(*)
---
## Auto Mode
When `--yes` or `-y`: Auto-approve splits, use default merge rule, skip confirmations.
# Collaborative Planning Command
## Quick Start
```bash
# Basic usage
/workflow:collaborative-plan "Implement real-time notification system"
# With options
/workflow:collaborative-plan "Refactor authentication module" --max-agents=4
/workflow:collaborative-plan "Add payment gateway support" --depth=deep
/workflow:collaborative-plan "Migrate to microservices" --merge-rule=priority
```
**Context Source**: ACE semantic search + Per-agent CLI exploration
**Output Directory**: `.workflow/.planning/{session-id}/`
**Default Max Agents**: 5 (actual count based on requirement complexity)
**CLI Tools**: cli-lite-planning-agent (internally calls ccw cli with gemini/codex/qwen)
**Schema**: plan-json-schema.json (sub-plans & final plan share same base schema)
## Overview
Unified collaborative planning workflow that:
1. **Analyzes** complex requirements and splits into sub-requirements
2. **Spawns** parallel sub-agents, each responsible for one sub-requirement
3. **Each agent** maintains process files: exploration.md → understanding.md → sub-plan.json
4. **Merges** all sub-plans into unified plan.json with conflict resolution
```
┌─────────────────────────────────────────────────────────────────────────┐
│ COLLABORATIVE PLANNING │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ Phase 1: Requirement Analysis & Splitting │
│ ├─ Analyze requirement complexity │
│ ├─ Identify 2-5 sub-requirements (focus areas) │
│ └─ Write requirement-analysis.json │
│ │
│ Phase 2: Parallel Sub-Agent Execution │
│ ┌──────────────┬──────────────┬──────────────┐ │
│ │ Agent 1 │ Agent 2 │ Agent N │ │
│ ├──────────────┼──────────────┼──────────────┤ │
│ │ exploration │ exploration │ exploration │ → exploration.md │
│ │ understanding│ understanding│ understanding│ → understanding.md │
│ │ planning │ planning │ planning │ → sub-plan.json │
│ └──────────────┴──────────────┴──────────────┘ │
│ │
│ Phase 3: Cross-Verification & Conflict Detection │
│ ├─ Load all sub-plan.json files │
│ ├─ Detect conflicts (effort, approach, dependencies) │
│ └─ Write conflicts.json │
│ │
│ Phase 4: Merge & Synthesis │
│ ├─ Resolve conflicts using merge-rule │
│ ├─ Merge all sub-plans into unified plan │
│ └─ Write plan.json + plan.md │
│ │
└─────────────────────────────────────────────────────────────────────────┘
```
## Output Structure
```
.workflow/.planning/{CPLAN-slug-YYYY-MM-DD}/
├── requirement-analysis.json # Phase 1: Requirement breakdown
├── agents/ # Phase 2: Per-agent process files
│ ├── {focus-area-1}/
│ │ ├── exploration.md # What was discovered
│ │ ├── understanding.md # Synthesized insights
│ │ └── sub-plan.json # Agent's plan for this focus area
│ ├── {focus-area-2}/
│ │ └── ...
│ └── {focus-area-N}/
│ └── ...
├── conflicts.json # Phase 3: Detected conflicts
├── plan.json # Phase 4: Unified merged plan
└── plan.md # Phase 4: Human-readable plan
```
## Implementation
### Session Initialization
```javascript
const getUtc8ISOString = () => new Date(Date.now() + 8 * 60 * 60 * 1000).toISOString()
const taskDescription = "$ARGUMENTS"
const taskSlug = taskDescription.toLowerCase()
.replace(/[^a-z0-9\u4e00-\u9fa5]+/g, '-')
.substring(0, 30)
const sessionId = `CPLAN-${taskSlug}-${getUtc8ISOString().substring(0, 10)}`
const sessionFolder = `.workflow/.planning/${sessionId}`
// Parse options
const maxAgents = parseInt($ARGUMENTS.match(/--max-agents=(\d+)/)?.[1] || '5')
const depth = $ARGUMENTS.match(/--depth=(normal|deep)/)?.[1] || 'normal'
const mergeRule = $ARGUMENTS.match(/--merge-rule=(consensus|priority)/)?.[1] || 'consensus'
const autoMode = $ARGUMENTS.includes('--yes') || $ARGUMENTS.includes('-y')
Bash(`mkdir -p ${sessionFolder}/agents`)
```
### Phase 1: Requirement Analysis & Splitting
Use CLI to analyze and split requirements:
```javascript
TodoWrite({ todos: [
{ content: "Phase 1: Requirement Analysis", status: "in_progress", activeForm: "Analyzing requirements" },
{ content: "Phase 2: Parallel Agent Execution", status: "pending", activeForm: "Running agents" },
{ content: "Phase 3: Conflict Detection", status: "pending", activeForm: "Detecting conflicts" },
{ content: "Phase 4: Merge & Synthesis", status: "pending", activeForm: "Merging plans" }
]})
// Step 1.1: Use CLI to analyze requirement and propose splits
Bash({
command: `ccw cli -p "
PURPOSE: Analyze requirement and identify distinct sub-requirements/focus areas
Success: 2-${maxAgents} clearly separated sub-requirements that can be planned independently
TASK:
• Understand the overall requirement: '${taskDescription}'
• Identify major components, features, or concerns
• Split into 2-${maxAgents} independent sub-requirements
• Each sub-requirement should be:
- Self-contained (can be planned independently)
- Non-overlapping (minimal dependency on other sub-requirements)
- Roughly equal in complexity
• For each sub-requirement, provide:
- focus_area: Short identifier (e.g., 'auth-backend', 'ui-components')
- description: What this sub-requirement covers
- key_concerns: Main challenges or considerations
- suggested_cli_tool: Which CLI tool is best suited (gemini/codex/qwen)
MODE: analysis
CONTEXT: @**/*
EXPECTED: JSON output with structure:
{
\"original_requirement\": \"...\",
\"complexity\": \"low|medium|high\",
\"sub_requirements\": [
{
\"index\": 1,
\"focus_area\": \"...\",
\"description\": \"...\",
\"key_concerns\": [\"...\"],
\"suggested_cli_tool\": \"gemini|codex|qwen\",
\"estimated_effort\": \"low|medium|high\"
}
],
\"dependencies_between_subs\": [
{ \"from\": 1, \"to\": 2, \"reason\": \"...\" }
],
\"rationale\": \"Why this split was chosen\"
}
CONSTRAINTS: Maximum ${maxAgents} sub-requirements | Ensure clear boundaries
" --tool gemini --mode analysis`,
run_in_background: true
})
// Wait for CLI completion and parse result
// ... (hook callback will provide result)
```
**After CLI completes**:
```javascript
// Parse CLI output to extract sub-requirements
const analysisResult = parseCLIOutput(cliOutput)
const subRequirements = analysisResult.sub_requirements
// Write requirement-analysis.json
Write(`${sessionFolder}/requirement-analysis.json`, JSON.stringify({
session_id: sessionId,
original_requirement: taskDescription,
analysis_timestamp: getUtc8ISOString(),
complexity: analysisResult.complexity,
sub_requirements: subRequirements,
dependencies_between_subs: analysisResult.dependencies_between_subs,
rationale: analysisResult.rationale,
options: { maxAgents, depth, mergeRule }
}, null, 2))
// Create agent folders
subRequirements.forEach(sub => {
Bash(`mkdir -p ${sessionFolder}/agents/${sub.focus_area}`)
})
// User confirmation (unless auto mode)
if (!autoMode) {
AskUserQuestion({
questions: [{
question: `已识别 ${subRequirements.length} 个子需求:\n${subRequirements.map((s, i) => `${i+1}. ${s.focus_area}: ${s.description}`).join('\n')}\n\n确认开始并行规划?`,
header: "Confirm Split",
multiSelect: false,
options: [
{ label: "开始规划", description: "启动并行sub-agent" },
{ label: "调整拆分", description: "修改子需求划分" },
{ label: "取消", description: "退出规划" }
]
}]
})
}
```
### Phase 2: Parallel Sub-Agent Execution
Launch one agent per sub-requirement, each maintaining its own process files:
```javascript
TodoWrite({ todos: [
{ content: "Phase 1: Requirement Analysis", status: "completed", activeForm: "Analyzing requirements" },
{ content: "Phase 2: Parallel Agent Execution", status: "in_progress", activeForm: "Running agents" },
...subRequirements.map((sub, i) => ({
content: ` → Agent ${i+1}: ${sub.focus_area}`,
status: "pending",
activeForm: `Planning ${sub.focus_area}`
})),
{ content: "Phase 3: Conflict Detection", status: "pending", activeForm: "Detecting conflicts" },
{ content: "Phase 4: Merge & Synthesis", status: "pending", activeForm: "Merging plans" }
]})
// Launch all sub-agents in parallel
const agentPromises = subRequirements.map((sub, index) => {
return Task({
subagent_type: "cli-lite-planning-agent",
run_in_background: false,
description: `Plan: ${sub.focus_area}`,
prompt: `
## Sub-Agent Mission
You are responsible for planning ONE sub-requirement of a larger task.
Maintain 3 process files documenting your exploration, understanding, and plan.
## Your Focus Area
**Index**: ${index + 1}
**Focus Area**: ${sub.focus_area}
**Description**: ${sub.description}
**Key Concerns**: ${sub.key_concerns.join(', ')}
**Suggested Tool**: ${sub.suggested_cli_tool}
**Depth**: ${depth}
## Parent Context
**Original Requirement**: ${taskDescription}
**Session**: ${sessionId}
**Your Folder**: ${sessionFolder}/agents/${sub.focus_area}/
## Schema Reference
Execute: cat ~/.claude/workflows/cli-templates/schemas/plan-json-schema.json
## Execution Process (3 Stages)
### Stage 1: Exploration (→ exploration.md)
Use ccw cli to explore the codebase for your focus area:
\`\`\`bash
ccw cli -p "
PURPOSE: Explore codebase for ${sub.focus_area}
Success: Identify all relevant files, patterns, and constraints
TASK:
• Find existing code related to ${sub.focus_area}
• Identify current architecture and patterns
• Discover integration points and dependencies
• Note any constraints or limitations
CONTEXT: @**/*
MODE: analysis
" --tool ${sub.suggested_cli_tool} --mode analysis
\`\`\`
After CLI completes, write exploration.md:
\`\`\`markdown
# Exploration: ${sub.focus_area}
## Discovered Files
- [list relevant files with brief descriptions]
## Current Architecture
- [describe existing structure]
## Integration Points
- [list dependencies and interfaces]
## Constraints & Limitations
- [note any blockers or constraints]
## Key Findings
- [most important discoveries]
\`\`\`
### Stage 2: Understanding (→ understanding.md)
Synthesize exploration findings into actionable understanding:
\`\`\`markdown
# Understanding: ${sub.focus_area}
## Problem Statement
[Restate what needs to be done for this focus area]
## Current State Analysis
[What exists now, what's missing]
## Proposed Approach
[High-level strategy for implementation]
## Technical Decisions
- Decision 1: [choice] because [rationale]
- Decision 2: [choice] because [rationale]
## Risks & Mitigations
- Risk 1: [description] → Mitigation: [approach]
## Dependencies on Other Sub-Requirements
- Depends on: [list any dependencies on other focus areas]
- Provides for: [what this provides to other focus areas]
## Key Insights
[Most important understanding gained]
\`\`\`
### Stage 3: Planning (→ sub-plan.json)
Generate sub-plan.json following plan-json-schema.json:
- 2-5 tasks for this focus area
- Clear modification_points with file, target, change
- Verification criteria (unit_tests, integration_tests, manual_checks)
- Risk assessment per task
- Dependencies (internal to this sub-plan)
- Add source_agent: "${sub.focus_area}" to _metadata
## Output Requirements
Write exactly 3 files:
1. \`${sessionFolder}/agents/${sub.focus_area}/exploration.md\`
2. \`${sessionFolder}/agents/${sub.focus_area}/understanding.md\`
3. \`${sessionFolder}/agents/${sub.focus_area}/sub-plan.json\`
## Success Criteria
- [ ] Exploration covers all relevant code areas
- [ ] Understanding synthesizes findings into clear approach
- [ ] sub-plan.json follows plan-json-schema.json with 2-5 tasks
- [ ] Each task has modification_points, acceptance, verification
- [ ] Dependencies clearly stated
- [ ] All 3 files written to correct location
`
})
})
// Wait for all agents to complete
const agentResults = await Promise.all(agentPromises)
```
### Phase 3: Cross-Verification & Conflict Detection
Load all sub-plans and detect conflicts:
```javascript
TodoWrite({ todos: [
{ content: "Phase 1: Requirement Analysis", status: "completed", activeForm: "Analyzing requirements" },
{ content: "Phase 2: Parallel Agent Execution", status: "completed", activeForm: "Running agents" },
{ content: "Phase 3: Conflict Detection", status: "in_progress", activeForm: "Detecting conflicts" },
{ content: "Phase 4: Merge & Synthesis", status: "pending", activeForm: "Merging plans" }
]})
// Load all sub-plans
const subPlans = subRequirements.map(sub => {
const planPath = `${sessionFolder}/agents/${sub.focus_area}/sub-plan.json`
const content = Read(planPath)
return {
focus_area: sub.focus_area,
index: sub.index,
plan: JSON.parse(content)
}
})
// Detect conflicts
const conflicts = {
detected_at: getUtc8ISOString(),
total_sub_plans: subPlans.length,
conflicts: []
}
// 1. Effort conflicts (same task estimated differently)
const effortConflicts = detectEffortConflicts(subPlans)
conflicts.conflicts.push(...effortConflicts)
// 2. File conflicts (multiple agents modifying same file)
const fileConflicts = detectFileConflicts(subPlans)
conflicts.conflicts.push(...fileConflicts)
// 3. Approach conflicts (different approaches to same problem)
const approachConflicts = detectApproachConflicts(subPlans)
conflicts.conflicts.push(...approachConflicts)
// 4. Dependency conflicts (circular or missing dependencies)
const dependencyConflicts = detectDependencyConflicts(subPlans)
conflicts.conflicts.push(...dependencyConflicts)
// Write conflicts.json
Write(`${sessionFolder}/conflicts.json`, JSON.stringify(conflicts, null, 2))
console.log(`
## Conflict Detection Complete
**Total Sub-Plans**: ${subPlans.length}
**Conflicts Found**: ${conflicts.conflicts.length}
${conflicts.conflicts.length > 0 ? `
### Conflicts:
${conflicts.conflicts.map((c, i) => `
${i+1}. **${c.type}** (${c.severity})
- Agents: ${c.agents_involved.join(' vs ')}
- Issue: ${c.description}
- Suggested Resolution: ${c.suggested_resolution}
`).join('\n')}
` : '✅ No conflicts detected - sub-plans are compatible'}
`)
```
**Conflict Detection Functions**:
```javascript
function detectFileConflicts(subPlans) {
const fileModifications = {}
const conflicts = []
subPlans.forEach(sp => {
sp.plan.tasks.forEach(task => {
task.modification_points?.forEach(mp => {
if (!fileModifications[mp.file]) {
fileModifications[mp.file] = []
}
fileModifications[mp.file].push({
focus_area: sp.focus_area,
task_id: task.id,
target: mp.target,
change: mp.change
})
})
})
})
Object.entries(fileModifications).forEach(([file, mods]) => {
if (mods.length > 1) {
const agents = [...new Set(mods.map(m => m.focus_area))]
if (agents.length > 1) {
conflicts.push({
type: "file_conflict",
severity: "high",
file: file,
agents_involved: agents,
modifications: mods,
description: `Multiple agents modifying ${file}`,
suggested_resolution: "Sequence modifications or consolidate"
})
}
}
})
return conflicts
}
function detectEffortConflicts(subPlans) {
// Compare effort estimates across similar tasks
// Return conflicts where estimates differ by >50%
return []
}
function detectApproachConflicts(subPlans) {
// Analyze approaches for contradictions
// Return conflicts where approaches are incompatible
return []
}
function detectDependencyConflicts(subPlans) {
// Check for circular dependencies
// Check for missing dependencies
return []
}
```
### Phase 4: Merge & Synthesis
Use cli-lite-planning-agent to merge all sub-plans:
```javascript
TodoWrite({ todos: [
{ content: "Phase 1: Requirement Analysis", status: "completed", activeForm: "Analyzing requirements" },
{ content: "Phase 2: Parallel Agent Execution", status: "completed", activeForm: "Running agents" },
{ content: "Phase 3: Conflict Detection", status: "completed", activeForm: "Detecting conflicts" },
{ content: "Phase 4: Merge & Synthesis", status: "in_progress", activeForm: "Merging plans" }
]})
// Collect all understanding documents for context
const understandingDocs = subRequirements.map(sub => {
const path = `${sessionFolder}/agents/${sub.focus_area}/understanding.md`
return {
focus_area: sub.focus_area,
content: Read(path)
}
})
// Invoke planning agent to merge
Task({
subagent_type: "cli-lite-planning-agent",
run_in_background: false,
description: "Merge sub-plans into unified plan",
prompt: `
## Mission: Merge Multiple Sub-Plans
Merge ${subPlans.length} sub-plans into a single unified plan.
## Schema Reference
Execute: cat ~/.claude/workflows/cli-templates/schemas/plan-json-schema.json
The merged plan follows the SAME schema as lite-plan, with ONE additional field:
- \`merge_metadata\`: Object containing merge-specific information
## Project Context
1. Read: .workflow/project-tech.json
2. Read: .workflow/project-guidelines.json
## Original Requirement
${taskDescription}
## Sub-Plans to Merge
${subPlans.map(sp => `
### Sub-Plan: ${sp.focus_area}
\`\`\`json
${JSON.stringify(sp.plan, null, 2)}
\`\`\`
`).join('\n')}
## Understanding Documents
${understandingDocs.map(ud => `
### Understanding: ${ud.focus_area}
${ud.content}
`).join('\n')}
## Detected Conflicts
\`\`\`json
${JSON.stringify(conflicts, null, 2)}
\`\`\`
## Merge Rules
**Rule**: ${mergeRule}
${mergeRule === 'consensus' ? `
- Equal weight to all sub-plans
- Conflicts resolved by finding middle ground
- Combine overlapping tasks
` : `
- Priority based on sub-requirement index
- Earlier agents' decisions take precedence
- Later agents adapt to earlier decisions
`}
## Requirements
1. **Task Consolidation**:
- Combine tasks that modify same files
- Preserve unique tasks from each sub-plan
- Ensure no task duplication
- Maintain clear task boundaries
2. **Dependency Resolution**:
- Cross-reference dependencies between sub-plans
- Create global task ordering
- Handle inter-sub-plan dependencies
3. **Conflict Resolution**:
- Apply ${mergeRule} rule to resolve conflicts
- Document resolution rationale
- Ensure no contradictions in final plan
4. **Metadata Preservation**:
- Track which sub-plan each task originated from (source_agent field)
- Include merge_metadata with:
- merged_from: list of sub-plan focus areas
- conflicts_resolved: count
- merge_rule: ${mergeRule}
## Output
Write to ${sessionFolder}/plan.json following plan-json-schema.json.
Add ONE extension field for merge tracking:
\`\`\`json
{
// ... all standard plan-json-schema fields ...
"merge_metadata": {
"source_session": "${sessionId}",
"merged_from": ["focus-area-1", "focus-area-2"],
"sub_plan_count": N,
"conflicts_detected": N,
"conflicts_resolved": N,
"merge_rule": "${mergeRule}",
"merged_at": "ISO-timestamp"
}
}
\`\`\`
Each task should include \`source_agent\` field indicating which sub-plan it originated from.
## Success Criteria
- [ ] All sub-plan tasks included (or explicitly merged)
- [ ] Conflicts resolved per ${mergeRule} rule
- [ ] Dependencies form valid DAG (no cycles)
- [ ] merge_metadata present
- [ ] Schema compliance verified
- [ ] plan.json written to ${sessionFolder}/plan.json
`
})
// Generate human-readable plan.md
const plan = JSON.parse(Read(`${sessionFolder}/plan.json`))
const planMd = generatePlanMarkdown(plan, subRequirements, conflicts)
Write(`${sessionFolder}/plan.md`, planMd)
```
**Markdown Generation**:
```javascript
function generatePlanMarkdown(plan, subRequirements, conflicts) {
return `# Collaborative Planning Session
**Session ID**: ${plan._metadata?.session_id || sessionId}
**Original Requirement**: ${taskDescription}
**Created**: ${getUtc8ISOString()}
---
## Sub-Requirements Analyzed
${subRequirements.map((sub, i) => `
### ${i+1}. ${sub.focus_area}
${sub.description}
- **Key Concerns**: ${sub.key_concerns.join(', ')}
- **Estimated Effort**: ${sub.estimated_effort}
`).join('\n')}
---
## Conflict Resolution
${conflicts.conflicts.length > 0 ? `
**Conflicts Detected**: ${conflicts.conflicts.length}
**Merge Rule**: ${mergeRule}
${conflicts.conflicts.map((c, i) => `
${i+1}. **${c.type}** - ${c.description}
- Resolution: ${c.suggested_resolution}
`).join('\n')}
` : '✅ No conflicts detected'}
---
## Merged Plan
### Summary
${plan.summary}
### Approach
${plan.approach}
---
## Tasks
${plan.tasks.map((task, i) => `
### ${task.id}: ${task.title}
**Source**: ${task.source_agent || 'merged'}
**Scope**: ${task.scope}
**Action**: ${task.action}
**Complexity**: ${task.effort?.complexity || 'medium'}
${task.description}
**Modification Points**:
${task.modification_points?.map(mp => `- \`${mp.file}\`${mp.target}: ${mp.change}`).join('\n') || 'N/A'}
**Implementation**:
${task.implementation?.map((step, idx) => `${idx+1}. ${step}`).join('\n') || 'N/A'}
**Acceptance Criteria**:
${task.acceptance?.map(ac => `- ${ac}`).join('\n') || 'N/A'}
**Dependencies**: ${task.depends_on?.join(', ') || 'None'}
---
`).join('\n')}
## Execution
\`\`\`bash
# Execute this plan
/workflow:unified-execute-with-file -p ${sessionFolder}/plan.json
# Or with auto-confirmation
/workflow:unified-execute-with-file -y -p ${sessionFolder}/plan.json
\`\`\`
---
## Agent Process Files
${subRequirements.map(sub => `
### ${sub.focus_area}
- Exploration: \`${sessionFolder}/agents/${sub.focus_area}/exploration.md\`
- Understanding: \`${sessionFolder}/agents/${sub.focus_area}/understanding.md\`
- Sub-Plan: \`${sessionFolder}/agents/${sub.focus_area}/sub-plan.json\`
`).join('\n')}
---
**Generated by**: /workflow:collaborative-plan
**Merge Rule**: ${mergeRule}
`
}
```
### Completion
```javascript
TodoWrite({ todos: [
{ content: "Phase 1: Requirement Analysis", status: "completed", activeForm: "Analyzing requirements" },
{ content: "Phase 2: Parallel Agent Execution", status: "completed", activeForm: "Running agents" },
{ content: "Phase 3: Conflict Detection", status: "completed", activeForm: "Detecting conflicts" },
{ content: "Phase 4: Merge & Synthesis", status: "completed", activeForm: "Merging plans" }
]})
console.log(`
✅ Collaborative Planning Complete
**Session**: ${sessionId}
**Sub-Agents**: ${subRequirements.length}
**Conflicts Resolved**: ${conflicts.conflicts.length}
## Output Files
📁 ${sessionFolder}/
├── requirement-analysis.json # Requirement breakdown
├── agents/ # Per-agent process files
${subRequirements.map(sub => `│ ├── ${sub.focus_area}/
│ │ ├── exploration.md
│ │ ├── understanding.md
│ │ └── sub-plan.json`).join('\n')}
├── conflicts.json # Detected conflicts
├── plan.json # Unified plan (execution-ready)
└── plan.md # Human-readable plan
## Next Steps
Execute the plan:
\`\`\`bash
/workflow:unified-execute-with-file -p ${sessionFolder}/plan.json
\`\`\`
Review a specific agent's work:
\`\`\`bash
cat ${sessionFolder}/agents/{focus-area}/understanding.md
\`\`\`
`)
```
## Configuration
| Flag | Default | Description |
|------|---------|-------------|
| `--max-agents` | 5 | Maximum sub-agents to spawn |
| `--depth` | normal | Exploration depth: normal or deep |
| `--merge-rule` | consensus | Conflict resolution: consensus or priority |
| `-y, --yes` | false | Auto-confirm all decisions |
## Error Handling
| Error | Resolution |
|-------|------------|
| Requirement too simple | Use single-agent lite-plan instead |
| Agent fails | Retry once, then continue with partial results |
| Merge conflicts unresolvable | Ask user for manual resolution |
| CLI timeout | Use fallback CLI tool |
| File write fails | Retry with alternative path |
## vs Other Planning Commands
| Command | Use Case |
|---------|----------|
| **collaborative-plan** | Complex multi-aspect requirements needing parallel exploration |
| lite-plan | Simple single-focus tasks |
| multi-cli-plan | Iterative cross-verification with convergence |
## Best Practices
1. **Be Specific**: Detailed requirements lead to better splits
2. **Review Process Files**: Check exploration.md and understanding.md for insights
3. **Trust the Merge**: Conflict resolution follows defined rules
4. **Iterate if Needed**: Re-run with different --merge-rule if results unsatisfactory
---
**Now execute collaborative-plan for**: $ARGUMENTS

View File

@@ -1,807 +0,0 @@
---
name: merge-plans-with-file
description: Merge multiple planning/brainstorm/analysis outputs, resolve conflicts, and synthesize unified plan. Designed for multi-team input aggregation and final plan crystallization
argument-hint: "[-y|--yes] [-r|--rule consensus|priority|hierarchy] \"plan or topic name\""
allowed-tools: TodoWrite(*), Task(*), AskUserQuestion(*), Read(*), Grep(*), Glob(*), Bash(*), Edit(*), Write(*)
---
## Auto Mode
When `--yes` or `-y`: Auto-resolve conflicts using specified rule (consensus/priority/hierarchy), minimal user prompts.
# Workflow Merge-Plans-With-File Command (/workflow:merge-plans-with-file)
## Overview
Plan aggregation and conflict resolution workflow. Takes multiple planning artifacts (brainstorm conclusions, analysis recommendations, quick-plans, implementation plans) and synthesizes them into a unified, conflict-resolved execution plan.
**Core workflow**: Load Sources → Parse Plans → Conflict Analysis → Arbitration → Unified Plan
**Key features**:
- **Multi-Source Support**: Brainstorm, analysis, quick-plan, IMPL_PLAN, task JSONs
- **Parallel Conflict Detection**: Identify all contradictions across input plans
- **Conflict Resolution**: Consensus, priority-based, or hierarchical resolution modes
- **Unified Synthesis**: Single authoritative plan from multiple perspectives
- **Decision Tracking**: Full audit trail of conflicts and resolutions
- **Resumable**: Save intermediate states, refine resolutions
## Usage
```bash
/workflow:merge-plans-with-file [FLAGS] <PLAN_NAME_OR_PATTERN>
# Flags
-y, --yes Auto-resolve conflicts using rule, skip confirmations
-r, --rule <rule> Conflict resolution rule: consensus (default) | priority | hierarchy
-o, --output <path> Output directory (default: .workflow/.merged/{name})
# Arguments
<plan-name-or-pattern> Plan name or glob pattern to identify input files/sessions
Examples: "auth-module", "*.analysis-*.json", "PLAN-*"
# Examples
/workflow:merge-plans-with-file "authentication" # Auto-detect all auth-related plans
/workflow:merge-plans-with-file -y -r priority "payment-system" # Auto-resolve with priority rule
/workflow:merge-plans-with-file -r hierarchy "feature-complete" # Use hierarchy rule (requires user ranking)
```
## Execution Process
```
Discovery & Loading:
├─ Search for planning artifacts matching pattern
├─ Load all synthesis.json, conclusions.json, IMPL_PLAN.md
├─ Parse each into normalized task/plan structure
└─ Validate data completeness
Session Initialization:
├─ Create .workflow/.merged/{sessionId}/
├─ Initialize merge.md with plan summary
├─ Index all source plans
└─ Extract planning metadata and constraints
Phase 1: Plan Normalization
├─ Convert all formats to common task representation
├─ Extract tasks, dependencies, effort, risks
├─ Identify plan scope and boundaries
├─ Validate no duplicate tasks
└─ Aggregate recommendations from each plan
Phase 2: Conflict Detection (Parallel)
├─ Architecture conflicts: different design approaches
├─ Task conflicts: overlapping responsibilities or different priorities
├─ Effort conflicts: vastly different estimates
├─ Risk assessment conflicts: different risk levels
├─ Scope conflicts: different feature inclusions
└─ Generate conflict matrix with severity levels
Phase 3: Consensus Building / Arbitration
├─ For each conflict, analyze source rationale
├─ Apply resolution rule (consensus/priority/hierarchy)
├─ Escalate unresolvable conflicts to user (unless --yes)
├─ Document decision rationale
└─ Generate resolutions.json
Phase 4: Plan Synthesis
├─ Merge task lists (remove duplicates, combine insights)
├─ Integrate dependencies from all sources
├─ Consolidate effort and risk estimates
├─ Generate unified execution sequence
├─ Create final unified plan
└─ Output ready for execution
Output:
├─ .workflow/.merged/{sessionId}/merge.md (merge process & decisions)
├─ .workflow/.merged/{sessionId}/source-index.json (input sources)
├─ .workflow/.merged/{sessionId}/conflicts.json (conflict matrix)
├─ .workflow/.merged/{sessionId}/resolutions.json (how conflicts were resolved)
├─ .workflow/.merged/{sessionId}/unified-plan.json (final merged plan)
└─ .workflow/.merged/{sessionId}/unified-plan.md (execution-ready markdown)
```
## Implementation
### Phase 1: Plan Discovery & Loading
```javascript
const getUtc8ISOString = () => new Date(Date.now() + 8 * 60 * 60 * 1000).toISOString()
// Parse arguments
const planPattern = "$PLAN_NAME_OR_PATTERN"
const resolutionRule = $ARGUMENTS.match(/--rule\s+(\w+)/)?.[1] || 'consensus'
const isAutoMode = $ARGUMENTS.includes('--yes') || $ARGUMENTS.includes('-y')
// Generate session ID
const mergeSlug = planPattern.toLowerCase()
.replace(/[*?]/g, '-')
.replace(/[^a-z0-9\u4e00-\u9fa5-]+/g, '-')
.substring(0, 30)
const dateStr = getUtc8ISOString().substring(0, 10)
const sessionId = `MERGE-${mergeSlug}-${dateStr}`
const sessionFolder = `.workflow/.merged/${sessionId}`
bash(`mkdir -p ${sessionFolder}`)
// Discover all relevant planning artifacts
const discoveryPaths = [
`.workflow/.brainstorm/*/${planPattern}*/synthesis.json`,
`.workflow/.analysis/*/${planPattern}*/conclusions.json`,
`.workflow/.planning/*/${planPattern}*/synthesis.json`,
`.workflow/.plan/${planPattern}*IMPL_PLAN.md`,
`.workflow/*/${planPattern}*.json`
]
const sourcePlans = []
for (const pattern of discoveryPaths) {
const matches = glob(pattern)
for (const path of matches) {
try {
const content = Read(path)
const plan = parsePlanFile(path, content)
if (plan && plan.tasks?.length > 0) {
sourcePlans.push({
source_path: path,
source_type: identifySourceType(path),
plan: plan,
loaded_at: getUtc8ISOString()
})
}
} catch (e) {
console.warn(`Failed to load plan from ${path}: ${e.message}`)
}
}
}
if (sourcePlans.length === 0) {
console.error(`
## Error: No Plans Found
Pattern: ${planPattern}
Searched locations:
${discoveryPaths.join('\n')}
Available plans in .workflow/:
`)
bash(`find .workflow -name "*.json" -o -name "*PLAN.md" | head -20`)
return { status: 'error', message: 'No plans found' }
}
console.log(`
## Plans Discovered
Total: ${sourcePlans.length}
${sourcePlans.map(sp => `- ${sp.source_type}: ${sp.source_path}`).join('\n')}
`)
```
---
### Phase 2: Plan Normalization
```javascript
// Normalize all plans to common format
const normalizedPlans = sourcePlans.map((sourcePlan, idx) => {
const plan = sourcePlan.plan
const tasks = plan.tasks || []
return {
index: idx,
source: sourcePlan.source_path,
source_type: sourcePlan.source_type,
metadata: {
title: plan.title || `Plan ${idx + 1}`,
topic: plan.topic || plan.planning_topic || 'unknown',
timestamp: plan.completed || plan.timestamp || sourcePlan.loaded_at,
source_ideas: plan.top_ideas?.length || 0,
complexity: plan.complexity_level || 'unknown'
},
// Normalized tasks
tasks: tasks.map(task => ({
id: task.id || `T${idx}-${task.title?.substring(0, 20)}`,
title: task.title || task.content,
description: task.description || '',
type: task.type || inferType(task),
priority: task.priority || 'normal',
// Effort estimation
effort: {
estimated: task.estimated_duration || task.effort_estimate || 'unknown',
from_plan: idx
},
// Risk assessment
risk: {
level: task.risk_level || 'medium',
from_plan: idx
},
// Dependencies
dependencies: task.dependencies || [],
// Source tracking
source_plan_index: idx,
original_id: task.id,
// Quality tracking
success_criteria: task.success_criteria || [],
challenges: task.challenges || []
}))
}
})
// Save source index
const sourceIndex = {
session_id: sessionId,
merge_timestamp: getUtc8ISOString(),
pattern: planPattern,
total_source_plans: sourcePlans.length,
sources: normalizedPlans.map(p => ({
index: p.index,
source_path: p.source,
source_type: p.source_type,
topic: p.metadata.topic,
task_count: p.tasks.length
}))
}
Write(`${sessionFolder}/source-index.json`, JSON.stringify(sourceIndex, null, 2))
```
---
### Phase 3: Conflict Detection
```javascript
// Detect conflicts across plans
const conflictDetector = {
// Architecture conflicts
architectureConflicts: [],
// Task conflicts (duplicates, different scope)
taskConflicts: [],
// Effort conflicts
effortConflicts: [],
// Risk assessment conflicts
riskConflicts: [],
// Scope conflicts
scopeConflicts: [],
// Priority conflicts
priorityConflicts: []
}
// Algorithm 1: Detect similar tasks across plans
const allTasks = normalizedPlans.flatMap(p => p.tasks)
const taskGroups = groupSimilarTasks(allTasks)
for (const group of taskGroups) {
if (group.tasks.length > 1) {
// Same task appears in multiple plans
const efforts = group.tasks.map(t => t.effort.estimated)
const effortVariance = calculateVariance(efforts)
if (effortVariance > 0.5) {
// Significant difference in effort estimates
conflictDetector.effortConflicts.push({
task_group: group.title,
conflicting_tasks: group.tasks.map((t, i) => ({
id: t.id,
from_plan: t.source_plan_index,
effort: t.effort.estimated
})),
variance: effortVariance,
severity: 'high'
})
}
// Check for scope differences
const scopeDifferences = analyzeScopeDifferences(group.tasks)
if (scopeDifferences.length > 0) {
conflictDetector.taskConflicts.push({
task_group: group.title,
scope_differences: scopeDifferences,
severity: 'medium'
})
}
}
}
// Algorithm 2: Architecture conflicts
const architectures = normalizedPlans.map(p => p.metadata.complexity)
if (new Set(architectures).size > 1) {
conflictDetector.architectureConflicts.push({
different_approaches: true,
complexity_levels: architectures.map((a, i) => ({
plan: i,
complexity: a
})),
severity: 'high'
})
}
// Algorithm 3: Risk assessment conflicts
const riskLevels = allTasks.map(t => ({ task: t.id, risk: t.risk.level }))
const taskRisks = {}
for (const tr of riskLevels) {
if (!taskRisks[tr.task]) taskRisks[tr.task] = []
taskRisks[tr.task].push(tr.risk)
}
for (const [task, risks] of Object.entries(taskRisks)) {
if (new Set(risks).size > 1) {
conflictDetector.riskConflicts.push({
task: task,
conflicting_risk_levels: risks,
severity: 'medium'
})
}
}
// Save conflicts
Write(`${sessionFolder}/conflicts.json`, JSON.stringify(conflictDetector, null, 2))
```
---
### Phase 4: Conflict Resolution
```javascript
// Resolve conflicts based on selected rule
const resolutions = {
resolution_rule: resolutionRule,
timestamp: getUtc8ISOString(),
effort_resolutions: [],
architecture_resolutions: [],
risk_resolutions: [],
scope_resolutions: [],
priority_resolutions: []
}
// Resolution Strategy 1: Consensus
if (resolutionRule === 'consensus') {
for (const conflict of conflictDetector.effortConflicts) {
// Use median or average
const efforts = conflict.conflicting_tasks.map(t => parseEffort(t.effort))
const resolved_effort = calculateMedian(efforts)
resolutions.effort_resolutions.push({
conflict: conflict.task_group,
original_estimates: efforts,
resolved_estimate: resolved_effort,
method: 'consensus-median',
rationale: 'Used median of all estimates'
})
}
}
// Resolution Strategy 2: Priority-Based
else if (resolutionRule === 'priority') {
// Use the plan from highest priority source (first or most recent)
for (const conflict of conflictDetector.effortConflicts) {
const highestPriority = conflict.conflicting_tasks[0] // First plan has priority
resolutions.effort_resolutions.push({
conflict: conflict.task_group,
conflicting_estimates: conflict.conflicting_tasks.map(t => t.effort),
resolved_estimate: highestPriority.effort,
selected_from_plan: highestPriority.from_plan,
method: 'priority-based',
rationale: `Selected estimate from plan ${highestPriority.from_plan} (highest priority)`
})
}
}
// Resolution Strategy 3: Hierarchy (requires user ranking)
else if (resolutionRule === 'hierarchy') {
if (!isAutoMode) {
// Ask user to rank plan importance
const planRanking = AskUserQuestion({
questions: [{
question: "请按重要性排序这些规划(从最重要到最不重要):",
header: "Plan Ranking",
multiSelect: false,
options: normalizedPlans.slice(0, 5).map(p => ({
label: `Plan ${p.index}: ${p.metadata.title.substring(0, 40)}`,
description: `${p.tasks.length} tasks, complexity: ${p.metadata.complexity}`
}))
}]
})
// Apply hierarchy
const hierarchy = extractHierarchy(planRanking)
for (const conflict of conflictDetector.effortConflicts) {
const topPriorityTask = conflict.conflicting_tasks
.sort((a, b) => hierarchy[a.from_plan] - hierarchy[b.from_plan])[0]
resolutions.effort_resolutions.push({
conflict: conflict.task_group,
resolved_estimate: topPriorityTask.effort,
selected_from_plan: topPriorityTask.from_plan,
method: 'hierarchy-based',
rationale: `Selected from highest-ranked plan`
})
}
}
}
Write(`${sessionFolder}/resolutions.json`, JSON.stringify(resolutions, null, 2))
```
---
### Phase 5: Plan Synthesis
```javascript
// Merge all tasks into unified plan
const unifiedTasks = []
const processedTaskIds = new Set()
for (const task of allTasks) {
const taskKey = generateTaskKey(task)
if (processedTaskIds.has(taskKey)) {
// Task already added, skip
continue
}
processedTaskIds.add(taskKey)
// Apply resolution if this task has conflicts
let resolvedTask = { ...task }
const effortResolution = resolutions.effort_resolutions
.find(r => r.conflict === taskKey)
if (effortResolution) {
resolvedTask.effort.estimated = effortResolution.resolved_estimate
resolvedTask.effort.resolution_method = effortResolution.method
}
unifiedTasks.push({
id: taskKey,
title: task.title,
description: task.description,
type: task.type,
priority: task.priority,
effort: resolvedTask.effort,
risk: task.risk,
dependencies: task.dependencies,
success_criteria: [...new Set([
...task.success_criteria,
...findRelatedTasks(task, allTasks)
.flatMap(t => t.success_criteria)
])],
challenges: [...new Set([
...task.challenges,
...findRelatedTasks(task, allTasks)
.flatMap(t => t.challenges)
])],
source_plans: [
...new Set(allTasks
.filter(t => generateTaskKey(t) === taskKey)
.map(t => t.source_plan_index))
]
})
}
// Generate execution sequence
const executionSequence = topologicalSort(unifiedTasks)
const criticalPath = identifyCriticalPath(unifiedTasks, executionSequence)
// Final unified plan
const unifiedPlan = {
session_id: sessionId,
merge_timestamp: getUtc8ISOString(),
summary: {
total_source_plans: normalizedPlans.length,
original_tasks_total: allTasks.length,
merged_tasks: unifiedTasks.length,
conflicts_resolved: Object.values(conflictDetector).flat().length,
resolution_rule: resolutionRule
},
merged_metadata: {
topics: [...new Set(normalizedPlans.map(p => p.metadata.topic))],
average_complexity: calculateAverage(normalizedPlans.map(p => parseComplexity(p.metadata.complexity))),
combined_scope: estimateScope(unifiedTasks)
},
tasks: unifiedTasks,
execution_sequence: executionSequence,
critical_path: criticalPath,
risks: aggregateRisks(unifiedTasks),
success_criteria: aggregateSuccessCriteria(unifiedTasks),
audit_trail: {
source_plans: normalizedPlans.length,
conflicts_detected: Object.values(conflictDetector).flat().length,
conflicts_resolved: Object.values(resolutions).flat().length,
resolution_method: resolutionRule
}
}
Write(`${sessionFolder}/unified-plan.json`, JSON.stringify(unifiedPlan, null, 2))
```
---
### Phase 6: Generate Execution Plan
```markdown
# Merged Planning Session
**Session ID**: ${sessionId}
**Pattern**: ${planPattern}
**Created**: ${getUtc8ISOString()}
---
## Merge Summary
**Source Plans**: ${unifiedPlan.summary.total_source_plans}
**Original Tasks**: ${unifiedPlan.summary.original_tasks_total}
**Merged Tasks**: ${unifiedPlan.summary.merged_tasks}
**Tasks Deduplicated**: ${unifiedPlan.summary.original_tasks_total - unifiedPlan.summary.merged_tasks}
**Conflicts Resolved**: ${unifiedPlan.summary.conflicts_resolved}
**Resolution Method**: ${unifiedPlan.summary.resolution_rule}
---
## Merged Plan Overview
**Topics**: ${unifiedPlan.merged_metadata.topics.join(', ')}
**Combined Complexity**: ${unifiedPlan.merged_metadata.average_complexity}
**Total Scope**: ${unifiedPlan.merged_metadata.combined_scope}
---
## Unified Task List
${unifiedPlan.tasks.map((task, i) => `
${i+1}. **${task.id}: ${task.title}**
- Type: ${task.type}
- Effort: ${task.effort.estimated}
- Risk: ${task.risk.level}
- Source Plans: ${task.source_plans.join(', ')}
- ${task.description}
`).join('\n')}
---
## Execution Sequence
**Critical Path**: ${unifiedPlan.critical_path.join(' → ')}
**Execution Order**:
${unifiedPlan.execution_sequence.map((id, i) => `${i+1}. ${id}`).join('\n')}
---
## Conflict Resolution Report
**Total Conflicts**: ${unifiedPlan.summary.conflicts_resolved}
**Resolved Conflicts**:
${Object.entries(resolutions).flatMap(([key, items]) =>
items.slice(0, 3).map((item, i) => `
- ${key.replace('_', ' ')}: ${item.rationale || item.method}
`)
).join('\n')}
**Full Report**: See \`conflicts.json\` and \`resolutions.json\`
---
## Risks & Considerations
**Aggregated Risks**:
${unifiedPlan.risks.slice(0, 5).map(r => `- **${r.title}**: ${r.mitigation}`).join('\n')}
**Combined Success Criteria**:
${unifiedPlan.success_criteria.slice(0, 5).map(c => `- ${c}`).join('\n')}
---
## Next Steps
### Option 1: Direct Execution
Execute merged plan with unified-execute-with-file:
\`\`\`
/workflow:unified-execute-with-file -p ${sessionFolder}/unified-plan.json
\`\`\`
### Option 2: Detailed Planning
Create detailed IMPL_PLAN from merged plan:
\`\`\`
/workflow:plan "Based on merged plan from $(echo ${planPattern})"
\`\`\`
### Option 3: Review Conflicts
Review detailed conflict analysis:
\`\`\`
cat ${sessionFolder}/resolutions.json
\`\`\`
---
## Artifacts
- **source-index.json** - All input plans and sources
- **conflicts.json** - Conflict detection results
- **resolutions.json** - How each conflict was resolved
- **unified-plan.json** - Merged plan data structure (for execution)
- **unified-plan.md** - This document (human-readable)
```
---
## Session Folder Structure
```
.workflow/.merged/{sessionId}/
├── merge.md # Merge process and decisions
├── source-index.json # All input plan sources
├── conflicts.json # Detected conflicts
├── resolutions.json # Conflict resolutions applied
├── unified-plan.json # Merged plan (machine-parseable, for execution)
└── unified-plan.md # Execution-ready plan (human-readable)
```
---
## Resolution Rules
### Rule 1: Consensus (default)
- Use median or average of conflicting estimates
- Good for: Multiple similar perspectives
- Tradeoff: May miss important minority viewpoints
### Rule 2: Priority-Based
- First plan has highest priority, subsequent plans are fallback
- Good for: Clear ranking of plan sources
- Tradeoff: Discards valuable alternative perspectives
### Rule 3: Hierarchy
- User explicitly ranks importance of each plan
- Good for: Mixed-source plans (engineering + product + leadership)
- Tradeoff: Requires user input
---
## Input Format Support
| Source Type | Detection | Parsing | Notes |
|-------------|-----------|---------|-------|
| **Brainstorm** | `.brainstorm/*/synthesis.json` | Top ideas → tasks | Ideas converted to work items |
| **Analysis** | `.analysis/*/conclusions.json` | Recommendations → tasks | Recommendations prioritized |
| **Quick-Plan** | `.planning/*/synthesis.json` | Direct task list | Already normalized |
| **IMPL_PLAN** | `*IMPL_PLAN.md` | Markdown → tasks | Parsed from markdown structure |
| **Task JSON** | `.json` with `tasks` key | Direct mapping | Requires standard schema |
---
## Error Handling
| Situation | Action |
|-----------|--------|
| No plans found | Suggest search terms, list available plans |
| Incompatible formats | Skip unsupported format, continue with others |
| Circular dependencies | Alert user, suggest manual review |
| Unresolvable conflicts | Require user decision (unless --yes + conflict rule) |
| Contradictory recommendations | Document both options for user consideration |
---
## Usage Patterns
### Pattern 1: Merge Multiple Brainstorms
```bash
/workflow:merge-plans-with-file "authentication" -y -r consensus
# → Finds all brainstorm sessions with "auth"
# → Merges top ideas into unified task list
# → Uses consensus method for conflicts
```
### Pattern 2: Synthesize Team Input
```bash
/workflow:merge-plans-with-file "payment-integration" -r hierarchy
# → Loads plans from different team members
# → Asks for ranking by importance
# → Applies hierarchy-based conflict resolution
```
### Pattern 3: Bridge Planning Phases
```bash
/workflow:merge-plans-with-file "user-auth" -f analysis
# → Takes analysis conclusions
# → Merges with existing quick-plans
# → Produces execution-ready plan
```
---
## Advanced: Custom Conflict Resolution
For complex conflict scenarios, create custom resolution script:
```
.workflow/.merged/{sessionId}/
└── custom-resolutions.js (optional)
- Define custom conflict resolution logic
- Applied after automatic resolution
- Override specific decisions
```
---
## Best Practices
1. **Before merging**:
- Ensure all source plans have same quality level
- Verify plans address same scope/topic
- Document any special considerations
2. **During merging**:
- Review conflict matrix (conflicts.json)
- Understand resolution rationale (resolutions.json)
- Challenge assumptions if results seem odd
3. **After merging**:
- Validate unified plan makes sense
- Review critical path
- Ensure no important details lost
- Execute or iterate if needed
---
## Integration with Other Workflows
```
Multiple Brainstorms / Analyses
├─ brainstorm-with-file (session 1)
├─ brainstorm-with-file (session 2)
├─ analyze-with-file (session 3)
merge-plans-with-file ◄──── This workflow
unified-plan.json
├─ /workflow:unified-execute-with-file (direct execution)
├─ /workflow:plan (detailed planning)
└─ /workflow:quick-plan-with-file (refinement)
```
---
## Comparison: When to Use Which Merge Rule
| Rule | Use When | Pros | Cons |
|------|----------|------|------|
| **Consensus** | Similar-quality inputs | Fair, balanced | May miss extremes |
| **Priority** | Clear hierarchy | Simple, predictable | May bias to first input |
| **Hierarchy** | Mixed stakeholders | Respects importance | Requires user ranking |
---
**Ready to execute**: Run `/workflow:merge-plans-with-file` to start merging plans!

View File

@@ -155,27 +155,65 @@ bash(`mkdir -p ${executionFolder}`)
## Plan Format Parsers ## Plan Format Parsers
Support multiple plan sources: Support multiple plan sources (all JSON plans follow plan-json-schema.json):
```javascript ```javascript
function parsePlan(content, filePath) { function parsePlan(content, filePath) {
const ext = filePath.split('.').pop() const ext = filePath.split('.').pop()
if (filePath.includes('IMPL_PLAN')) { if (filePath.includes('IMPL_PLAN')) {
return parseImplPlan(content) // From /workflow:plan return parseImplPlan(content) // From /workflow:plan (markdown)
} else if (filePath.includes('brainstorm')) { } else if (filePath.includes('brainstorm')) {
return parseBrainstormPlan(content) // From /workflow:brainstorm-with-file return parseBrainstormPlan(content) // From /workflow:brainstorm-with-file
} else if (filePath.includes('synthesis')) { } else if (filePath.includes('synthesis')) {
return parseSynthesisPlan(content) // From /workflow:brainstorm-with-file synthesis.json return parseSynthesisPlan(content) // From /workflow:brainstorm-with-file synthesis.json
} else if (filePath.includes('conclusions')) { } else if (filePath.includes('conclusions')) {
return parseConclusionsPlan(content) // From /workflow:analyze-with-file conclusions.json return parseConclusionsPlan(content) // From /workflow:analyze-with-file conclusions.json
} else if (filePath.endsWith('.json') && content.includes('tasks')) { } else if (filePath.endsWith('.json') && content.includes('"tasks"')) {
return parseTaskJson(content) // Direct task JSON return parsePlanJson(content) // Standard plan-json-schema (lite-plan, collaborative-plan, sub-plans)
} }
throw new Error(`Unsupported plan format: ${filePath}`) throw new Error(`Unsupported plan format: ${filePath}`)
} }
// Standard plan-json-schema parser
// Handles: lite-plan, collaborative-plan, sub-plans (all follow same schema)
function parsePlanJson(content) {
const plan = JSON.parse(content)
return {
type: plan.merge_metadata ? 'collaborative-plan' : 'lite-plan',
title: plan.summary?.split('.')[0] || 'Untitled Plan',
slug: plan._metadata?.session_id || generateSlug(plan.summary),
summary: plan.summary,
approach: plan.approach,
tasks: plan.tasks.map(task => ({
id: task.id,
type: inferTaskTypeFromAction(task.action),
title: task.title,
description: task.description,
dependencies: task.depends_on || [],
agent_type: selectAgentFromTask(task),
prompt: buildPromptFromTask(task),
files_to_modify: task.modification_points?.map(mp => mp.file) || [],
expected_output: task.acceptance || [],
priority: task.effort?.complexity === 'high' ? 'high' : 'normal',
estimated_duration: task.effort?.estimated_hours ? `${task.effort.estimated_hours}h` : null,
verification: task.verification,
risks: task.risks,
source_agent: task.source_agent // From collaborative-plan sub-agents
})),
flow_control: plan.flow_control,
data_flow: plan.data_flow,
design_decisions: plan.design_decisions,
estimatedDuration: plan.estimated_time,
recommended_execution: plan.recommended_execution,
complexity: plan.complexity,
merge_metadata: plan.merge_metadata, // Present if from collaborative-plan
_metadata: plan._metadata
}
}
// IMPL_PLAN.md parser // IMPL_PLAN.md parser
function parseImplPlan(content) { function parseImplPlan(content) {
// Extract: // Extract:
@@ -216,6 +254,65 @@ function parseSynthesisPlan(content) {
recommendations: synthesis.recommendations recommendations: synthesis.recommendations
} }
} }
// Helper: Infer task type from action field
function inferTaskTypeFromAction(action) {
const actionMap = {
'Create': 'code',
'Update': 'code',
'Implement': 'code',
'Refactor': 'code',
'Add': 'code',
'Delete': 'code',
'Configure': 'config',
'Test': 'test',
'Fix': 'debug'
}
return actionMap[action] || 'code'
}
// Helper: Select agent based on task properties
function selectAgentFromTask(task) {
if (task.verification?.unit_tests?.length > 0) {
return 'tdd-developer'
} else if (task.action === 'Test') {
return 'test-fix-agent'
} else if (task.action === 'Fix') {
return 'debug-explore-agent'
} else {
return 'code-developer'
}
}
// Helper: Build prompt from task details
function buildPromptFromTask(task) {
let prompt = `## Task: ${task.title}\n\n${task.description}\n\n`
if (task.modification_points?.length > 0) {
prompt += `### Modification Points\n`
task.modification_points.forEach(mp => {
prompt += `- **${mp.file}**: ${mp.target}${mp.change}\n`
})
prompt += '\n'
}
if (task.implementation?.length > 0) {
prompt += `### Implementation Steps\n`
task.implementation.forEach((step, i) => {
prompt += `${i + 1}. ${step}\n`
})
prompt += '\n'
}
if (task.acceptance?.length > 0) {
prompt += `### Acceptance Criteria\n`
task.acceptance.forEach(ac => {
prompt += `- ${ac}\n`
})
}
return prompt
}
``` ```
--- ---

View File

@@ -1,450 +0,0 @@
---
description: Multi-agent rapid planning with minimal documentation, conflict resolution, and actionable synthesis. Lightweight planning from raw task, brainstorm, or analysis artifacts
argument-hint: "TOPIC=\"<planning topic or task>\" [--from=brainstorm|analysis|task|raw] [--perspectives=arch,impl,risk,decision] [--auto] [--verbose]"
---
# Codex Quick-Plan-With-File Prompt
## Overview
Multi-agent rapid planning workflow with **minimal documentation overhead**. Coordinates parallel agent analysis (architecture, implementation, validation, decision), synthesizes conflicting perspectives into actionable decisions, and generates an implementation-ready plan.
**Core workflow**: Parse Input → Parallel Analysis → Conflict Resolution → Plan Synthesis → Output
**Key features**:
- **Format Agnostic**: Consumes brainstorm conclusions, analysis recommendations, quick tasks, or raw descriptions
- **Minimal Docs**: Single plan.md (no lengthy timeline documentation)
- **Parallel Multi-Agent**: 4 concurrent perspectives for rapid analysis
- **Conflict Resolution**: Automatic conflict detection and synthesis
- **Actionable Output**: Direct task breakdown ready for execution
## Target Planning
**$TOPIC**
- `--from`: Input source type (brainstorm | analysis | task | raw) - auto-detected if omitted
- `--perspectives`: Which perspectives to use (arch, impl, risk, decision) - all by default
- `--auto`: Auto-confirm decisions, minimal user prompts
- `--verbose`: Verbose output with all reasoning
## Execution Process
```
Phase 1: Input Validation & Loading
├─ Parse input: topic | artifact reference
├─ Load artifact if referenced (synthesis.json | conclusions.json)
├─ Extract constraints and key requirements
└─ Initialize session folder
Phase 2: Parallel Multi-Agent Analysis (concurrent)
├─ Agent 1 (Architecture): Design decomposition, patterns, scalability
├─ Agent 2 (Implementation): Tech stack, feasibility, effort estimates
├─ Agent 3 (Validation): Risk matrix, testing strategy, monitoring
├─ Agent 4 (Decision): Recommendations, tradeoffs, execution strategy
└─ Aggregate findings into perspectives.json
Phase 3: Conflict Detection & Resolution
├─ Detect: effort conflicts, architecture conflicts, risk conflicts
├─ Analyze rationale for each conflict
├─ Synthesis via arbitration: generate unified recommendation
├─ Document conflicts and resolutions
└─ Update plan.md
Phase 4: Plan Synthesis
├─ Consolidate all insights
├─ Generate task breakdown (5-8 major tasks)
├─ Create execution strategy and dependencies
├─ Document assumptions and risks
└─ Output plan.md + synthesis.json
Output:
├─ .workflow/.planning/{sessionId}/plan.md (minimal, actionable)
├─ .workflow/.planning/{sessionId}/perspectives.json (agent findings)
├─ .workflow/.planning/{sessionId}/conflicts.json (decision points)
└─ .workflow/.planning/{sessionId}/synthesis.json (task breakdown for execution)
```
## Implementation Details
### Phase 1: Session Setup & Input Loading
```javascript
const getUtc8ISOString = () => new Date(Date.now() + 8 * 60 * 60 * 1000).toISOString()
// Parse input
const planSlug = "$TOPIC".toLowerCase()
.replace(/[^a-z0-9\u4e00-\u9fa5]+/g, '-')
.substring(0, 30)
const sessionId = `PLAN-${planSlug}-${getUtc8ISOString().substring(0, 10)}`
const sessionFolder = `.workflow/.planning/${sessionId}`
// Detect input type
let artifact = null
if ($TOPIC.startsWith('BS-') || "$TOPIC".includes('brainstorm')) {
artifact = loadBrainstormArtifact($TOPIC)
} else if ($TOPIC.startsWith('ANL-') || "$TOPIC".includes('analysis')) {
artifact = loadAnalysisArtifact($TOPIC)
}
bash(`mkdir -p ${sessionFolder}`)
```
### Phase 2: Parallel Multi-Agent Analysis
Run 4 agents in parallel using ccw cli:
```javascript
// Launch all 4 agents concurrently with Bash run_in_background
const agentPromises = []
// Agent 1 - Architecture (Gemini)
agentPromises.push(
Bash({
command: `ccw cli -p "
PURPOSE: Architecture & high-level design for '${planningTopic}'
Success: Clear component decomposition and architectural approach
TASK:
• Decompose problem into major components/modules
• Identify architectural patterns and integration points
• Design component interfaces and data models
• Assess scalability and maintainability implications
• Propose architectural approach with rationale
MODE: analysis
CONTEXT: @**/*
${artifact ? \`| Source artifact: \${artifact.type}\` : ''}
EXPECTED:
- Component decomposition (list with responsibilities)
- Module interfaces and contracts
- Data flow between components
- Architectural patterns applied (e.g., MVC, Event-Driven, etc.)
- Scalability assessment (1-5 rating with rationale)
- Architectural risks identified
CONSTRAINTS: Focus on long-term maintainability and extensibility
" --tool gemini --mode analysis`,
run_in_background: true
})
)
// Agent 2 - Implementation (Codex)
agentPromises.push(
Bash({
command: \`ccw cli -p "
PURPOSE: Implementation approach & technical feasibility for '\${planningTopic}'
Success: Concrete implementation strategy with realistic estimates
TASK:
• Evaluate technical feasibility of proposed approach
• Identify required technologies and dependencies
• Estimate effort: analysis/design/coding/testing/deployment
• Suggest implementation phases and milestones
• Highlight technical blockers and challenges
MODE: analysis
CONTEXT: @**/*
\${artifact ? \`| Source artifact: \${artifact.type}\` : ''}
EXPECTED:
- Technology stack recommendation (languages, frameworks, tools)
- Implementation complexity: high|medium|low (with justification)
- Effort breakdown (hours or complexity: analysis, design, coding, testing, deployment)
- Key technical decisions with tradeoffs explained
- Potential blockers and mitigation strategies
- Suggested implementation phases with sequencing
- Reusable components or libraries identified
CONSTRAINTS: Realistic with current tech stack
" --tool codex --mode analysis\`,
run_in_background: true
})
)
// Agent 3 - Validation & Risk (Claude)
agentPromises.push(
Bash({
command: \`ccw cli -p "
PURPOSE: Risk analysis and validation strategy for '\${planningTopic}'
Success: Comprehensive risk matrix with testing and deployment strategy
TASK:
• Identify technical risks and failure scenarios
• Assess timeline and resource risks
• Define validation/testing strategy (unit, integration, e2e, performance)
• Suggest monitoring and observability requirements
• Propose deployment strategy and rollback plan
MODE: analysis
CONTEXT: @**/*
\${artifact ? \`| Source artifact: \${artifact.type}\` : ''}
EXPECTED:
- Risk matrix (likelihood × impact, each 1-5)
- Top 3 technical risks with mitigation approaches
- Top 3 timeline/resource risks with mitigation
- Testing strategy (what to test, how, when, acceptance criteria)
- Deployment strategy (staged rollout, blue-green, canary, etc.)
- Rollback plan and recovery procedures
- Monitoring/observability requirements (metrics, logs, alerts)
- Overall risk rating: low|medium|high (with confidence)
CONSTRAINTS: Be realistic, not pessimistic
" --tool claude --mode analysis\`,
run_in_background: true
})
)
// Agent 4 - Strategic Decision (Gemini)
agentPromises.push(
Bash({
command: \`ccw cli -p "
PURPOSE: Strategic decisions and execution recommendations for '\${planningTopic}'
Success: Clear recommended approach with tradeoff analysis
TASK:
• Synthesize all perspectives into strategic recommendations
• Identify 2-3 critical decision points with recommended choices
• Clearly outline key tradeoffs (speed vs quality, scope vs timeline, risk vs cost)
• Propose go/no-go decision criteria and success metrics
• Suggest execution strategy and resource sequencing
MODE: analysis
CONTEXT: @**/*
\${artifact ? \`| Source artifact: \${artifact.type}\` : ''}
EXPECTED:
- Primary recommendation with strong rationale (1-2 paragraphs)
- Alternative approaches with pros/cons (2-3 alternatives)
- 2-3 critical decision points:
- What decision needs to be made
- Trade-offs for each option
- Recommended choice and why
- Key trade-offs explained (what we're optimizing for: speed/quality/risk/cost)
- Success metrics and go/no-go criteria
- Resource requirements and critical path items
- Suggested execution sequencing and phases
CONSTRAINTS: Focus on actionable decisions, provide clear rationale
" --tool gemini --mode analysis\`,
run_in_background: true
})
)
// Wait for all agents to complete
const [archResult, implResult, riskResult, decisionResult] = await Promise.all(agentPromises)
// Parse and extract findings from each agent result
const architecture = parseArchitectureResult(archResult)
const implementation = parseImplementationResult(implResult)
const validation = parseValidationResult(riskResult)
const recommendation = parseDecisionResult(decisionResult)
```
**Agent Focus Areas**:
| Agent | Perspective | Focus Areas |
|-------|-------------|------------|
| Gemini (Design) | Architecture patterns | Components, interfaces, scalability, patterns |
| Codex (Build) | Implementation reality | Tech stack, complexity, effort, blockers |
| Claude (Validate) | Risk & testing | Risk matrix, testing strategy, deployment, monitoring |
| Gemini (Decide) | Strategic synthesis | Recommendations, trade-offs, critical decisions |
### Phase 3: Parse & Aggregate Perspectives
```javascript
const perspectives = {
session_id: sessionId,
topic: "$TOPIC",
timestamp: getUtc8ISOString(),
architecture: {
components: [...],
patterns: [...],
scalability_rating: 3,
risks: [...]
},
implementation: {
technology_stack: [...],
complexity: "medium",
effort_breakdown: { analysis: 2, design: 3, coding: 8, testing: 4 },
blockers: [...]
},
validation: {
risk_matrix: [...],
top_risks: [{ title, impact, mitigation }, ...],
testing_strategy: "...",
monitoring: [...]
},
recommendation: {
primary_approach: "...",
alternatives: [...],
critical_decisions: [...],
tradeoffs: [...]
}
}
Write(`${sessionFolder}/perspectives.json`, JSON.stringify(perspectives, null, 2))
```
### Phase 4: Conflict Detection
Detect conflicts:
- Effort variance: Are estimates consistent?
- Risk disagreement: Do arch and validation agree on risks?
- Scope confusion: Are recommendations aligned?
- Architecture mismatch: Do design and implementation agree?
For each conflict: document it, then run synthesis arbitration.
### Phase 5: Generate Plan
```markdown
# Quick Planning Session
**Session ID**: ${sessionId}
**Topic**: $TOPIC
**Created**: ${timestamp}
---
## Executive Summary
${synthesis.executive_summary}
**Complexity**: ${synthesis.complexity_level}
**Estimated Effort**: ${formatEffort(synthesis.effort_breakdown)}
**Optimization Focus**: ${synthesis.optimization_focus}
---
## Architecture
**Primary Pattern**: ${synthesis.architecture_approach}
**Key Components**:
${synthesis.key_components.map((c, i) => `${i+1}. ${c.name}: ${c.responsibility}`).join('\n')}
---
## Implementation Strategy
**Technology Stack**:
${synthesis.technology_stack.map(t => `- ${t}`).join('\n')}
**Phases**:
${synthesis.phases.map((p, i) => `${i+1}. ${p.name} (${p.effort})`).join('\n')}
---
## Risk Assessment
**Overall Risk**: ${synthesis.overall_risk_level}
**Top 3 Risks**:
${synthesis.top_risks.map((r, i) => `${i+1}. **${r.title}** (Impact: ${r.impact})\n Mitigation: ${r.mitigation}`).join('\n\n')}
---
## Task Breakdown (Ready for Execution)
${synthesis.tasks.map((task, i) => `
${i+1}. **${task.id}: ${task.title}** (Effort: ${task.effort})
${task.description}
Dependencies: ${task.dependencies.join(', ') || 'none'}
`).join('\n')}
---
## Next Steps
**Execute with**:
\`\`\`
/workflow:unified-execute-with-file -p ${sessionFolder}/synthesis.json
\`\`\`
**Detailed planning if needed**:
\`\`\`
/workflow:plan "Based on: $TOPIC"
\`\`\`
```
## Session Folder Structure
```
.workflow/.planning/{sessionId}/
├── plan.md # Minimal, actionable
├── perspectives.json # Agent findings
├── conflicts.json # Conflicts & resolutions (if any)
└── synthesis.json # Task breakdown for execution
```
## Multi-Agent Coordination
| Agent | Perspective | Tools | Output |
|-------|-------------|-------|--------|
| Gemini (Design) | Architecture patterns | Design thinking, cross-domain | Components, patterns, scalability |
| Codex (Build) | Implementation reality | Tech stack evaluation | Stack, effort, feasibility |
| Claude (Validate) | Risk & testing | Risk assessment, QA | Risks, testing strategy |
| Gemini (Decide) | Strategic synthesis | Decision analysis | Recommendations, tradeoffs |
## Error Handling
| Situation | Action |
|-----------|--------|
| Agents conflict | Arbitration agent synthesizes recommendation |
| Missing blockers | Continue with available context, note gaps |
| Unclear input | Ask for clarification on planning focus |
| Estimate too high | Suggest MVP approach or phasing |
## Integration Flow
```
Raw Task / Brainstorm / Analysis
quick-plan-with-file (5-10 min)
├─ plan.md
├─ perspectives.json
└─ synthesis.json
unified-execute-with-file
Implementation
```
## Usage Patterns
**Pattern 1: Quick planning from task**
```
TOPIC="实现实时通知系统" --auto
→ Creates actionable plan in ~5 minutes
```
**Pattern 2: Convert brainstorm to execution plan**
```
TOPIC="BS-notifications-2025-01-28" --from=brainstorm
→ Reads synthesis.json from brainstorm
→ Generates implementation plan
```
**Pattern 3: From analysis to plan**
```
TOPIC="ANL-auth-2025-01-28" --from=analysis
→ Converts conclusions.json to executable plan
```
---
**Now execute quick-plan-with-file for topic**: $TOPIC

View File

@@ -525,6 +525,33 @@ function renderCliStatus() {
const enabledCliSettings = isClaude ? cliSettingsEndpoints.filter(ep => ep.enabled) : []; const enabledCliSettings = isClaude ? cliSettingsEndpoints.filter(ep => ep.enabled) : [];
const hasCliSettings = enabledCliSettings.length > 0; const hasCliSettings = enabledCliSettings.length > 0;
// Build Settings File info for builtin Claude
let settingsFileInfo = '';
if (isClaude && config.type === 'builtin' && config.settingsFile) {
const settingsFile = config.settingsFile;
// Simple path resolution attempt for display (no actual filesystem access)
const resolvedPath = settingsFile.startsWith('~')
? settingsFile.replace('~', (typeof os !== 'undefined' && os.homedir) ? os.homedir() : '~')
: settingsFile;
settingsFileInfo = `
<div class="cli-settings-info mt-2 p-2 rounded bg-muted/50 text-xs">
<div class="flex items-center gap-1 text-muted-foreground mb-1">
<i data-lucide="file-key" class="w-3 h-3"></i>
<span>Settings File:</span>
</div>
<div class="text-foreground font-mono text-[10px] break-all" title="${resolvedPath}">
${settingsFile}
</div>
${settingsFile !== resolvedPath ? `
<div class="text-muted-foreground mt-1 font-mono text-[10px] break-all">
${resolvedPath}
</div>
` : ''}
</div>
`;
}
// Build CLI Settings badge for Claude // Build CLI Settings badge for Claude
let cliSettingsBadge = ''; let cliSettingsBadge = '';
if (isClaude && hasCliSettings) { if (isClaude && hasCliSettings) {
@@ -588,6 +615,7 @@ function renderCliStatus() {
} }
</div> </div>
</div> </div>
${settingsFileInfo}
${cliSettingsInfo} ${cliSettingsInfo}
<div class="cli-tool-actions mt-3 flex gap-2"> <div class="cli-tool-actions mt-3 flex gap-2">
${isAvailable ? (isEnabled ${isAvailable ? (isEnabled

View File

@@ -562,6 +562,27 @@ function buildToolConfigModalContent(tool, config, models, status) {
'</div>' '</div>'
) : '') + ) : '') +
// Claude Settings File Section (only for builtin claude type)
(tool === 'claude' && config.type === 'builtin' ? (
'<div class="tool-config-section">' +
'<h4><i data-lucide="file-key" class="w-3.5 h-3.5"></i> Settings File <span class="text-muted">(optional)</span></h4>' +
'<div class="env-file-input-group">' +
'<div class="env-file-input-row">' +
'<input type="text" id="claudeSettingsFileInput" class="tool-config-input" ' +
'placeholder="~/path/to/settings.json or D:\\path\\to\\settings.json" ' +
'value="' + (config.settingsFile ? escapeHtml(config.settingsFile) : '') + '" />' +
'<button type="button" class="btn-sm btn-outline" id="claudeSettingsFileBrowseBtn">' +
'<i data-lucide="folder-open" class="w-3.5 h-3.5"></i> Browse' +
'</button>' +
'</div>' +
'<p class="env-file-hint">' +
'<i data-lucide="info" class="w-3 h-3"></i> ' +
'Path to Claude CLI settings.json file (supports ~, absolute, and Windows paths)' +
'</p>' +
'</div>' +
'</div>'
) : '') +
// Footer // Footer
'<div class="tool-config-footer">' + '<div class="tool-config-footer">' +
'<button class="btn btn-outline" onclick="closeModal()">' + t('common.cancel') + '</button>' + '<button class="btn btn-outline" onclick="closeModal()">' + t('common.cancel') + '</button>' +
@@ -1124,6 +1145,10 @@ function initToolConfigModalEvents(tool, currentConfig, models) {
var envFileInput = document.getElementById('envFileInput'); var envFileInput = document.getElementById('envFileInput');
var envFile = envFileInput ? envFileInput.value.trim() : ''; var envFile = envFileInput ? envFileInput.value.trim() : '';
// Get settingsFile value (only for builtin claude)
var claudeSettingsFileInput = document.getElementById('claudeSettingsFileInput');
var settingsFile = claudeSettingsFileInput ? claudeSettingsFileInput.value.trim() : '';
try { try {
var updateData = { var updateData = {
primaryModel: primaryModel, primaryModel: primaryModel,
@@ -1137,6 +1162,11 @@ function initToolConfigModalEvents(tool, currentConfig, models) {
updateData.envFile = envFile || null; updateData.envFile = envFile || null;
} }
// Only include settingsFile for builtin claude tool
if (tool === 'claude' && config.type === 'builtin') {
updateData.settingsFile = settingsFile || null;
}
await updateCliToolConfig(tool, updateData); await updateCliToolConfig(tool, updateData);
// Reload config to reflect changes // Reload config to reflect changes
await loadCliToolConfig(); await loadCliToolConfig();
@@ -1164,6 +1194,20 @@ function initToolConfigModalEvents(tool, currentConfig, models) {
}; };
} }
// Claude Settings File browse button (only for builtin claude)
var claudeSettingsFileBrowseBtn = document.getElementById('claudeSettingsFileBrowseBtn');
if (claudeSettingsFileBrowseBtn) {
claudeSettingsFileBrowseBtn.onclick = function() {
showFileBrowserModal(function(selectedPath) {
var claudeSettingsFileInput = document.getElementById('claudeSettingsFileInput');
if (claudeSettingsFileInput && selectedPath) {
claudeSettingsFileInput.value = selectedPath;
claudeSettingsFileInput.focus();
}
});
};
}
// Initialize lucide icons in modal // Initialize lucide icons in modal
if (window.lucide) lucide.createIcons(); if (window.lucide) lucide.createIcons();
} }

View File

@@ -56,6 +56,12 @@ export interface ClaudeCliTool {
* Supports both absolute paths and paths relative to home directory (e.g., ~/.my-env) * Supports both absolute paths and paths relative to home directory (e.g., ~/.my-env)
*/ */
envFile?: string; envFile?: string;
/**
* Path to Claude CLI settings.json file (builtin claude only)
* Passed to Claude CLI via --settings parameter
* Supports ~, absolute, relative, and Windows paths
*/
settingsFile?: string;
} }
export type CliToolName = 'gemini' | 'qwen' | 'codex' | 'claude' | 'opencode' | string; export type CliToolName = 'gemini' | 'qwen' | 'codex' | 'claude' | 'opencode' | string;
@@ -279,7 +285,8 @@ function ensureToolTags(tool: Partial<ClaudeCliTool>): ClaudeCliTool {
primaryModel: tool.primaryModel, primaryModel: tool.primaryModel,
secondaryModel: tool.secondaryModel, secondaryModel: tool.secondaryModel,
tags: tool.tags ?? [], tags: tool.tags ?? [],
envFile: tool.envFile envFile: tool.envFile,
settingsFile: tool.settingsFile
}; };
} }
@@ -1015,6 +1022,7 @@ export function getToolConfig(projectDir: string, tool: string): {
secondaryModel: string; secondaryModel: string;
tags?: string[]; tags?: string[];
envFile?: string; envFile?: string;
settingsFile?: string;
} { } {
const config = loadClaudeCliTools(projectDir); const config = loadClaudeCliTools(projectDir);
const toolConfig = config.tools[tool]; const toolConfig = config.tools[tool];
@@ -1034,7 +1042,8 @@ export function getToolConfig(projectDir: string, tool: string): {
primaryModel: toolConfig.primaryModel ?? '', primaryModel: toolConfig.primaryModel ?? '',
secondaryModel: toolConfig.secondaryModel ?? '', secondaryModel: toolConfig.secondaryModel ?? '',
tags: toolConfig.tags, tags: toolConfig.tags,
envFile: toolConfig.envFile envFile: toolConfig.envFile,
settingsFile: toolConfig.settingsFile
}; };
} }
@@ -1051,6 +1060,7 @@ export function updateToolConfig(
availableModels: string[]; availableModels: string[];
tags: string[]; tags: string[];
envFile: string | null; envFile: string | null;
settingsFile: string | null;
}> }>
): ClaudeCliToolsConfig { ): ClaudeCliToolsConfig {
const config = loadClaudeCliTools(projectDir); const config = loadClaudeCliTools(projectDir);
@@ -1079,6 +1089,14 @@ export function updateToolConfig(
config.tools[tool].envFile = updates.envFile; config.tools[tool].envFile = updates.envFile;
} }
} }
// Handle settingsFile: set to undefined if null/empty, otherwise set value
if (updates.settingsFile !== undefined) {
if (updates.settingsFile === null || updates.settingsFile === '') {
delete config.tools[tool].settingsFile;
} else {
config.tools[tool].settingsFile = updates.settingsFile;
}
}
saveClaudeCliTools(projectDir, config); saveClaudeCliTools(projectDir, config);
} }

View File

@@ -9,7 +9,7 @@ import { spawn, ChildProcess } from 'child_process';
import * as fs from 'fs'; import * as fs from 'fs';
import * as path from 'path'; import * as path from 'path';
import * as os from 'os'; import * as os from 'os';
import { validatePath } from '../utils/path-resolver.js'; import { validatePath, resolvePath } from '../utils/path-resolver.js';
import { escapeWindowsArg } from '../utils/shell-escape.js'; import { escapeWindowsArg } from '../utils/shell-escape.js';
import { buildCommand, checkToolAvailability, clearToolCache, debugLog, errorLog, type NativeResumeConfig, type ToolAvailability } from './cli-executor-utils.js'; import { buildCommand, checkToolAvailability, clearToolCache, debugLog, errorLog, type NativeResumeConfig, type ToolAvailability } from './cli-executor-utils.js';
import type { ConversationRecord, ConversationTurn, ExecutionOutput, ExecutionRecord } from './cli-executor-state.js'; import type { ConversationRecord, ConversationTurn, ExecutionOutput, ExecutionRecord } from './cli-executor-state.js';
@@ -85,7 +85,7 @@ import { findEndpointById } from '../config/litellm-api-config-manager.js';
// CLI Settings (CLI封装) integration // CLI Settings (CLI封装) integration
import { loadEndpointSettings, getSettingsFilePath, findEndpoint } from '../config/cli-settings-manager.js'; import { loadEndpointSettings, getSettingsFilePath, findEndpoint } from '../config/cli-settings-manager.js';
import { loadClaudeCliTools, getToolConfig } from './claude-cli-tools.js'; import { loadClaudeCliTools, getToolConfig, getPrimaryModel } from './claude-cli-tools.js';
/** /**
* Parse .env file content into key-value pairs * Parse .env file content into key-value pairs
@@ -338,8 +338,7 @@ import {
import { import {
isToolEnabled as isToolEnabledFromConfig, isToolEnabled as isToolEnabledFromConfig,
enableTool as enableToolFromConfig, enableTool as enableToolFromConfig,
disableTool as disableToolFromConfig, disableTool as disableToolFromConfig
getPrimaryModel
} from './cli-config-manager.js'; } from './cli-config-manager.js';
// Built-in CLI tools // Built-in CLI tools
@@ -794,6 +793,25 @@ async function executeCliTool(
// Use configured primary model if no explicit model provided // Use configured primary model if no explicit model provided
const effectiveModel = model || getPrimaryModel(workingDir, tool); const effectiveModel = model || getPrimaryModel(workingDir, tool);
// Load and validate settings file for Claude tool (builtin only)
let settingsFilePath: string | undefined;
if (tool === 'claude') {
const toolConfig = getToolConfig(workingDir, tool);
if (toolConfig.settingsFile) {
try {
const resolved = resolvePath(toolConfig.settingsFile);
if (fs.existsSync(resolved)) {
settingsFilePath = resolved;
debugLog('SETTINGS_FILE', `Resolved Claude settings file`, { configured: toolConfig.settingsFile, resolved });
} else {
errorLog('SETTINGS_FILE', `Claude settings file not found, skipping`, { configured: toolConfig.settingsFile, resolved });
}
} catch (err) {
errorLog('SETTINGS_FILE', `Failed to resolve Claude settings file`, { configured: toolConfig.settingsFile, error: (err as Error).message });
}
}
}
// Build command // Build command
const { command, args, useStdin, outputFormat: autoDetectedFormat } = buildCommand({ const { command, args, useStdin, outputFormat: autoDetectedFormat } = buildCommand({
tool, tool,
@@ -803,6 +821,7 @@ async function executeCliTool(
dir: cd, dir: cd,
include: includeDirs, include: includeDirs,
nativeResume: nativeResumeConfig, nativeResume: nativeResumeConfig,
settingsFile: settingsFilePath,
reviewOptions: mode === 'review' ? { uncommitted, base, commit, title } : undefined reviewOptions: mode === 'review' ? { uncommitted, base, commit, title } : undefined
}); });

48
test-command-build.mjs Normal file
View File

@@ -0,0 +1,48 @@
import { buildCommand } from './ccw/dist/tools/cli-executor-utils.js';
import { getToolConfig } from './ccw/dist/tools/claude-cli-tools.js';
import { resolvePath } from './ccw/dist/utils/path-resolver.js';
import fs from 'fs';
const workingDir = 'D:\\Claude_dms3';
const tool = 'claude';
// Get tool config
const toolConfig = getToolConfig(workingDir, tool);
console.log('=== Tool Config ===');
console.log(JSON.stringify(toolConfig, null, 2));
// Resolve settings file
let settingsFilePath = undefined;
if (toolConfig.settingsFile) {
try {
const resolved = resolvePath(toolConfig.settingsFile);
console.log(`\n=== Settings File Resolution ===`);
console.log(`Configured: ${toolConfig.settingsFile}`);
console.log(`Resolved: ${resolved}`);
console.log(`Exists: ${fs.existsSync(resolved)}`);
if (fs.existsSync(resolved)) {
settingsFilePath = resolved;
console.log(`✓ Will use settings file: ${settingsFilePath}`);
} else {
console.log(`✗ File not found, skipping`);
}
} catch (err) {
console.log(`✗ Error resolving: ${err.message}`);
}
}
// Build command
const cmdInfo = buildCommand({
tool: 'claude',
prompt: 'test prompt',
mode: 'analysis',
model: 'sonnet',
settingsFile: settingsFilePath
});
console.log('\n=== Command Built ===');
console.log('Command:', cmdInfo.command);
console.log('Args:', JSON.stringify(cmdInfo.args, null, 2));
console.log('\n=== Full Command Line ===');
console.log(`${cmdInfo.command} ${cmdInfo.args.join(' ')}`);

16
test-config-debug.mjs Normal file
View File

@@ -0,0 +1,16 @@
import { getToolConfig, loadClaudeCliTools } from './ccw/dist/tools/claude-cli-tools.js';
const workingDir = 'D:\\Claude_dms3';
const tool = 'claude';
console.log('=== Step 1: Load full config ===');
const fullConfig = loadClaudeCliTools(workingDir);
console.log('Full config:', JSON.stringify(fullConfig, null, 2));
console.log('\n=== Step 2: Get claude tool from config ===');
const claudeTool = fullConfig.tools.claude;
console.log('Claude tool raw:', JSON.stringify(claudeTool, null, 2));
console.log('\n=== Step 3: Get tool config via getToolConfig ===');
const config = getToolConfig(workingDir, tool);
console.log('Claude tool config:', JSON.stringify(config, null, 2));

7
test-config.js Normal file
View File

@@ -0,0 +1,7 @@
const { getToolConfig } = require('./ccw/dist/tools/claude-cli-tools.js');
const workingDir = 'D:\\Claude_dms3';
const tool = 'claude';
const config = getToolConfig(workingDir, tool);
console.log('Claude tool config:', JSON.stringify(config, null, 2));

7
test-config.mjs Normal file
View File

@@ -0,0 +1,7 @@
import { getToolConfig } from './ccw/dist/tools/claude-cli-tools.js';
const workingDir = 'D:\\Claude_dms3';
const tool = 'claude';
const config = getToolConfig(workingDir, tool);
console.log('Claude tool config:', JSON.stringify(config, null, 2));