mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-04 01:40:45 +08:00
refactor: remove lite-plan-c workflow and update orchestrator UI components
- Deleted the lite-plan-c workflow file to streamline the planning process. - Updated orchestrator localization files to include new variable picker and multi-node selector messages. - Modified PropertyPanel to support new execution modes and added output variable input fields. - Enhanced SlashCommandNode to reflect changes in execution modes. - Introduced MultiNodeSelector component for better node selection management. - Added VariablePicker component for selecting variables with improved UX.
This commit is contained in:
@@ -1,277 +0,0 @@
|
||||
---
|
||||
description: Execute workflow tasks sequentially from session folder. Supports parallel execution and task filtering.
|
||||
argument-hint: "SESSION=<path-to-session-folder> [--parallel] [--filter=<pattern>] [--skip-tests]"
|
||||
---
|
||||
|
||||
# Workflow Execute (Codex Version)
|
||||
|
||||
## Core Principle
|
||||
|
||||
**Serial Execution**: Execute tasks ONE BY ONE in dependency order. Complete current task fully before moving to next. Continue autonomously until ALL tasks complete.
|
||||
|
||||
## Input
|
||||
|
||||
Session folder path via `$SESSION` (e.g., `.workflow/active/WFS-auth-system`)
|
||||
|
||||
- `--parallel`: Execute tasks in parallel (default: sequential)
|
||||
- `--filter`: Filter tasks by pattern (e.g., `IMPL-1.*`)
|
||||
- `--skip-tests`: Skip test execution
|
||||
|
||||
## Task Tracking (JSON Source of Truth + Codex TODO Tool)
|
||||
|
||||
- **Source of truth**: Task state MUST be read from and written to `$SESSION/.task/IMPL-*.json`.
|
||||
- **Markdown views**: `$SESSION/TODO_LIST.md` and `$SESSION/IMPL_PLAN.md` are views; use them for ordering and display, but do NOT trust them for status.
|
||||
- **Codex TODO tool**: Mirror the workflow into the built-in `update_plan` tool so progress is visible and consistent.
|
||||
|
||||
### Status mapping (Task JSON → `update_plan`)
|
||||
|
||||
- Task JSON uses workflow statuses (source of truth): `pending`, `in_progress`, `completed` (optionally also `blocked`, `cancelled`, `container`).
|
||||
- `update_plan` only supports: `pending`, `in_progress`, `completed`.
|
||||
- Map as:
|
||||
- `pending|blocked|cancelled|container` → `pending`
|
||||
- `in_progress` → `in_progress`
|
||||
- `completed` → `completed`
|
||||
|
||||
### `update_plan` rules (must follow)
|
||||
|
||||
1. At most ONE step can be `in_progress` at a time.
|
||||
2. Do NOT jump `pending → completed`; always go through `in_progress`.
|
||||
3. Do NOT batch-complete steps after the fact; update as you go.
|
||||
4. If the plan changes (new tasks, re-order, merge/split), call `update_plan` with an `explanation`.
|
||||
5. After calling `update_plan`, do NOT repeat the full plan in chat; only output a short progress line.
|
||||
6. Keep each `step` short and stable (ID-first), e.g. `IMPL-1.1 - Add JWT middleware`.
|
||||
|
||||
## Autonomous Execution Loop
|
||||
|
||||
```
|
||||
INIT: Validate session folder structure
|
||||
|
||||
WHILE tasks remain:
|
||||
1. Read TODO_LIST.md → Get ordered task IDs (ignore checkbox status)
|
||||
2. For each task ID, read $SESSION/.task/{task-id}.json → Get true status + deps
|
||||
3. Find FIRST eligible task:
|
||||
- status != "completed"
|
||||
- deps = taskJson.depends_on OR taskJson.context.depends_on (source of truth)
|
||||
- deps all completed (from JSON)
|
||||
- task is executable (skip status="container" or tasks with subtasks)
|
||||
4. Mark task JSON status to "in_progress" (immediately)
|
||||
5. Mirror status to `update_plan` (exactly one in_progress)
|
||||
6. Execute task fully (pre-analysis → implementation → verification)
|
||||
7. Mark task JSON status to "completed" (immediately after verification)
|
||||
8. Mirror completion to `update_plan`, output progress line, CONTINUE (DO NOT STOP)
|
||||
|
||||
WHEN all tasks completed:
|
||||
Output final summary
|
||||
```
|
||||
|
||||
## Execution Steps
|
||||
|
||||
### Step 1: Validate Session
|
||||
|
||||
Check required files exist:
|
||||
```
|
||||
$SESSION/
|
||||
├── IMPL_PLAN.md ← Required
|
||||
├── TODO_LIST.md ← Required
|
||||
└── .task/ ← Required, must have IMPL-*.json
|
||||
```
|
||||
|
||||
If missing, report error and stop.
|
||||
|
||||
### Step 2: Parse TODO_LIST.md
|
||||
|
||||
Extract the ordered task list (IDs + titles). Do not treat checkbox states as authoritative.
|
||||
```markdown
|
||||
- ▸ **IMPL-1**: Parent task (container)
|
||||
- [x] IMPL-1: Task 1 title (completed)
|
||||
- [ ] IMPL-1.1: Task 2 title (pending) ← Execute this
|
||||
- [ ] IMPL-2: Task 3 title (pending, depends on IMPL-1.1)
|
||||
```
|
||||
|
||||
### Step 3: Find Next Executable Task
|
||||
|
||||
```javascript
|
||||
// Sequential scan for first eligible task
|
||||
for (task of todoList) {
|
||||
taskJson = read(`$SESSION/.task/${task.id}.json`)
|
||||
if (taskJson.status === "completed") continue
|
||||
if (taskJson.status === "container") continue
|
||||
|
||||
// Check dependencies from task JSON (source of truth)
|
||||
const deps = taskJson.depends_on || taskJson.context?.depends_on || []
|
||||
if (deps.every(dep => read(`$SESSION/.task/${dep}.json`).status === "completed")) {
|
||||
return task // Execute this one
|
||||
}
|
||||
}
|
||||
return null // All done or all blocked
|
||||
```
|
||||
|
||||
### Step 4: Load Task Context
|
||||
|
||||
```bash
|
||||
# Read task definition
|
||||
cat $SESSION/.task/$TASK_ID.json
|
||||
|
||||
# Read context package if exists
|
||||
cat $SESSION/.process/context-package.json
|
||||
```
|
||||
|
||||
### Step 5: Initialize Task Tracking (Codex TODO tool)
|
||||
|
||||
Before executing the first task, initialize `update_plan` from the ordered task list:
|
||||
- Only include executable tasks (skip containers) to avoid non-actionable TODO items.
|
||||
- `step`: Use a stable ID-first label like `IMPL-1.1 - {title}`.
|
||||
- `status`: Map from task JSON status using the rules above.
|
||||
|
||||
Keep this plan updated throughout execution (see rules above).
|
||||
|
||||
Example initialization:
|
||||
```javascript
|
||||
update_plan({
|
||||
plan: [
|
||||
{ step: "IMPL-1.1 - Task title", status: "pending" },
|
||||
{ step: "IMPL-2 - Task title", status: "pending" }
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
### Step 6: Execute Task
|
||||
|
||||
#### 6A: Pre-Analysis (if flow_control.pre_analysis exists)
|
||||
```markdown
|
||||
## Pre-Analysis for: [task.title]
|
||||
|
||||
Execute each step:
|
||||
1. [Read referenced files]
|
||||
2. [Search for patterns]
|
||||
3. [Load dependencies]
|
||||
```
|
||||
|
||||
#### 6B: Implementation
|
||||
```markdown
|
||||
## Implementing: [task.title]
|
||||
|
||||
**Requirements**:
|
||||
- [context.requirements[0]]
|
||||
- ...
|
||||
|
||||
**Steps**:
|
||||
1. [flow_control.implementation_approach[0].step] - [flow_control.implementation_approach[0].action]
|
||||
2. [flow_control.implementation_approach[1].step] - [flow_control.implementation_approach[1].action]
|
||||
...
|
||||
|
||||
**Focus Paths**:
|
||||
- [context.focus_paths[0]]
|
||||
- ...
|
||||
```
|
||||
|
||||
#### 6C: Verification
|
||||
```markdown
|
||||
## Verifying: [task.title]
|
||||
|
||||
**Acceptance Criteria**:
|
||||
- [x] [context.acceptance[0]]
|
||||
- [x] [context.acceptance[1]]
|
||||
|
||||
All criteria met: YES → Mark completed
|
||||
```
|
||||
|
||||
### Step 7: Update Status
|
||||
|
||||
Update task JSON with correct transitions:
|
||||
- Before executing: `pending → in_progress`
|
||||
- After verification: `in_progress → completed`
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "IMPL-1.1",
|
||||
"status": "completed",
|
||||
"completed_at": "2025-12-15T..."
|
||||
}
|
||||
```
|
||||
|
||||
### Step 8: Continue Immediately
|
||||
|
||||
**DO NOT STOP. Return to Step 2 to find next task.**
|
||||
|
||||
Output progress:
|
||||
```
|
||||
✓ [3/7] Completed: IMPL-1.1 - [task title]
|
||||
→ Next: IMPL-2 - [next task title]
|
||||
```
|
||||
|
||||
## Task JSON Structure
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "IMPL-1.1",
|
||||
"title": "Task Title",
|
||||
"status": "pending|in_progress|completed|blocked|cancelled|container",
|
||||
"meta": {
|
||||
"type": "feature|test|docs",
|
||||
"agent": "code-developer|test-fix-agent|..."
|
||||
},
|
||||
"context": {
|
||||
"requirements": ["Requirement 1", "Requirement 2"],
|
||||
"focus_paths": ["src/module/"],
|
||||
"acceptance": ["Criterion 1", "Criterion 2"],
|
||||
"depends_on": ["IMPL-1"]
|
||||
},
|
||||
"flow_control": {
|
||||
"pre_analysis": ["step 1", "step 2"],
|
||||
"implementation_approach": [
|
||||
{ "step": "Step 1", "action": "Do X" },
|
||||
{ "step": "Step 2", "action": "Do Y" }
|
||||
]
|
||||
},
|
||||
"depends_on": ["IMPL-1"]
|
||||
}
|
||||
```
|
||||
|
||||
## Execution Rules
|
||||
|
||||
1. **Never stop mid-workflow** - Continue until all tasks complete
|
||||
2. **One task at a time** - Fully complete before moving on
|
||||
3. **Respect dependencies** - Skip blocked tasks, find next eligible
|
||||
4. **Update status immediately** - Mark `in_progress` on start, `completed` right after verification
|
||||
5. **Self-verify** - All acceptance criteria must pass before marking done
|
||||
6. **Handle blocked state** - If all remaining tasks have unmet deps, report and stop
|
||||
7. **Keep tracking in sync** - Task JSON is truth; `update_plan` must reflect the same state
|
||||
|
||||
## Final Summary
|
||||
|
||||
When ALL tasks completed:
|
||||
|
||||
```markdown
|
||||
## Workflow Execution Complete
|
||||
|
||||
**Session**: $SESSION
|
||||
**Total Tasks**: N
|
||||
**Completed**: N
|
||||
|
||||
### Execution Log
|
||||
| # | Task ID | Title | Status |
|
||||
|---|---------|-------|--------|
|
||||
| 1 | IMPL-1 | ... | ✓ |
|
||||
| 2 | IMPL-1.1 | ... | ✓ |
|
||||
| 3 | IMPL-2 | ... | ✓ |
|
||||
|
||||
### Files Modified
|
||||
- `src/auth/login.ts`
|
||||
- `src/utils/validator.ts`
|
||||
|
||||
### Summary
|
||||
[What was accomplished across all tasks]
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Situation | Action |
|
||||
|-----------|--------|
|
||||
| Session folder not found | Error and stop |
|
||||
| Missing required files | Error: specify which file missing |
|
||||
| Task JSON not found | Error, skip task, continue |
|
||||
| Task blocked (deps not met) | Skip, find next eligible task |
|
||||
| All tasks blocked | Report circular dependency, stop |
|
||||
| Execution error | Report, set task JSON back to `pending`, continue to next eligible task |
|
||||
| Verification failed | Retry once; if still failing, set back to `pending` and continue |
|
||||
@@ -1,684 +0,0 @@
|
||||
---
|
||||
description: Execute tasks based on in-memory plan, prompt description, or file content with optimized Codex subagent orchestration. Supports multiple input modes and execution control.
|
||||
argument-hint: "[--plan=in-memory|<file-path>] [--parallel] [--skip-tests] [--dry-run]"
|
||||
---
|
||||
|
||||
# Workflow Lite-Execute Command (Codex Subagent Version)
|
||||
|
||||
## Overview
|
||||
|
||||
Flexible task execution command with **optimized Codex subagent orchestration**. Supports three input modes: in-memory plan (from lite-plan), direct prompt description, or file content.
|
||||
|
||||
**Core Optimizations:**
|
||||
- **Batch Parallel Execution**: `spawn_agent × N → wait({ ids: [...] })` for independent tasks
|
||||
- **Context Preservation**: Primary executor retained for follow-ups via `send_input()`
|
||||
- **Unified Prompt Builder**: Same template for both Agent and CLI executors
|
||||
- **Explicit Lifecycle**: `spawn_agent → wait → [send_input] → close_agent`
|
||||
|
||||
**Core capabilities:**
|
||||
- Multi-mode input (in-memory plan, prompt description, or file path)
|
||||
- Execution orchestration via Codex subagents with full context
|
||||
- Live progress tracking via TodoWrite at batch level
|
||||
- Optional code review with selected tool (Gemini, Codex, or custom)
|
||||
- Context continuity across multiple executions
|
||||
- Intelligent format detection (Enhanced Task JSON vs plain text)
|
||||
|
||||
## Usage
|
||||
|
||||
### Command Syntax
|
||||
```bash
|
||||
/workflow:lite-execute [FLAGS] <INPUT>
|
||||
```
|
||||
|
||||
### Flags
|
||||
|
||||
- `--plan=in-memory|<file-path>`: Input mode (in-memory plan or file path)
|
||||
- `--parallel`: Execute tasks in parallel (default: sequential)
|
||||
- `--skip-tests`: Skip test execution
|
||||
- `--dry-run`: Preview execution without making changes
|
||||
|
||||
## Input Modes
|
||||
|
||||
### Mode 1: In-Memory Plan
|
||||
|
||||
**Trigger**: Called by lite-plan after Phase 4 approval with `--in-memory` flag
|
||||
|
||||
**Input Source**: `executionContext` global variable set by lite-plan
|
||||
|
||||
**Behavior**:
|
||||
- Skip execution method selection (already set by lite-plan)
|
||||
- Directly proceed to execution with full context
|
||||
- All planning artifacts available (exploration, clarifications, plan)
|
||||
|
||||
### Mode 2: Prompt Description
|
||||
|
||||
**Trigger**: User calls with task description string
|
||||
|
||||
**Input**: Simple task description (e.g., "Add unit tests for auth module")
|
||||
|
||||
**Behavior**:
|
||||
- Store prompt as `originalUserInput`
|
||||
- Create simple execution plan from prompt
|
||||
- AskUserQuestion: Select execution method (Agent/Codex/Auto)
|
||||
- AskUserQuestion: Select code review tool (Skip/Gemini/Codex/Other)
|
||||
- Proceed to execution with `originalUserInput` included
|
||||
|
||||
### Mode 3: File Content
|
||||
|
||||
**Trigger**: User calls with file path
|
||||
|
||||
**Input**: Path to file containing task description or plan.json
|
||||
|
||||
**Behavior**:
|
||||
- Read file and detect format (plan.json vs plain text)
|
||||
- If plan.json: Use `planObject` directly
|
||||
- If plain text: Treat as prompt (same as Mode 2)
|
||||
|
||||
## Execution Process
|
||||
|
||||
```
|
||||
Input Parsing:
|
||||
└─ Decision (mode detection):
|
||||
├─ --in-memory flag → Mode 1: Load executionContext → Skip user selection
|
||||
├─ Ends with .md/.json/.txt → Mode 3: Read file → Detect format
|
||||
│ ├─ Valid plan.json → Use planObject → User selects method + review
|
||||
│ └─ Not plan.json → Treat as prompt → User selects method + review
|
||||
└─ Other → Mode 2: Prompt description → User selects method + review
|
||||
|
||||
Execution (Codex Subagent Pattern):
|
||||
├─ Step 1: Initialize result tracking (previousExecutionResults = [])
|
||||
├─ Step 2: Task grouping & batch creation
|
||||
│ ├─ Extract explicit depends_on (no inference)
|
||||
│ ├─ Group: independent tasks → single parallel batch
|
||||
│ └─ Group: dependent tasks → sequential phases
|
||||
├─ Step 3: Launch execution (spawn_agent × N → wait → close)
|
||||
│ ├─ Phase 1: All independent tasks (spawn_agent × N → batch wait)
|
||||
│ └─ Phase 2+: Dependent tasks (sequential spawn_agent → wait → close)
|
||||
├─ Step 4: Track progress (TodoWrite updates per batch)
|
||||
└─ Step 5: Code review (if codeReviewTool ≠ "Skip")
|
||||
|
||||
Output:
|
||||
└─ Execution complete with results in previousExecutionResults[]
|
||||
```
|
||||
|
||||
## Implementation
|
||||
|
||||
### Step 1: Initialize Execution Tracking
|
||||
|
||||
```javascript
|
||||
// Initialize result tracking
|
||||
previousExecutionResults = []
|
||||
|
||||
// In-Memory Mode: Echo execution strategy
|
||||
if (executionContext) {
|
||||
console.log(`
|
||||
## Execution Strategy (from lite-plan)
|
||||
|
||||
- **Method**: ${executionContext.executionMethod}
|
||||
- **Review**: ${executionContext.codeReviewTool}
|
||||
- **Tasks**: ${executionContext.planObject.tasks.length}
|
||||
- **Complexity**: ${executionContext.planObject.complexity}
|
||||
${executionContext.executorAssignments ? `- **Assignments**: ${JSON.stringify(executionContext.executorAssignments)}` : ''}
|
||||
`)
|
||||
}
|
||||
```
|
||||
|
||||
### Step 2: Task Grouping & Batch Creation
|
||||
|
||||
```javascript
|
||||
// Use explicit depends_on from plan.json (no inference)
|
||||
function extractDependencies(tasks) {
|
||||
const taskIdToIndex = {}
|
||||
tasks.forEach((t, i) => { taskIdToIndex[t.id] = i })
|
||||
|
||||
return tasks.map((task, i) => {
|
||||
const deps = (task.depends_on || [])
|
||||
.map(depId => taskIdToIndex[depId])
|
||||
.filter(idx => idx !== undefined && idx < i)
|
||||
return { ...task, taskIndex: i, dependencies: deps }
|
||||
})
|
||||
}
|
||||
|
||||
// Group into batches: maximize parallel execution
|
||||
function createExecutionBatches(tasks, executionMethod) {
|
||||
const tasksWithDeps = extractDependencies(tasks)
|
||||
const processed = new Set()
|
||||
const batches = []
|
||||
|
||||
// Phase 1: All independent tasks → single parallel batch
|
||||
const independentTasks = tasksWithDeps.filter(t => t.dependencies.length === 0)
|
||||
if (independentTasks.length > 0) {
|
||||
independentTasks.forEach(t => processed.add(t.taskIndex))
|
||||
batches.push({
|
||||
method: executionMethod,
|
||||
executionType: "parallel",
|
||||
groupId: "P1",
|
||||
taskSummary: independentTasks.map(t => t.title).join(' | '),
|
||||
tasks: independentTasks
|
||||
})
|
||||
}
|
||||
|
||||
// Phase 2+: Dependent tasks → sequential batches
|
||||
let remaining = tasksWithDeps.filter(t => !processed.has(t.taskIndex))
|
||||
|
||||
while (remaining.length > 0) {
|
||||
const ready = remaining.filter(t =>
|
||||
t.dependencies.every(d => processed.has(d))
|
||||
)
|
||||
|
||||
if (ready.length === 0) {
|
||||
console.warn('Circular dependency detected, forcing remaining tasks')
|
||||
ready.push(...remaining)
|
||||
}
|
||||
|
||||
ready.forEach(t => processed.add(t.taskIndex))
|
||||
batches.push({
|
||||
method: executionMethod,
|
||||
executionType: ready.length > 1 ? "parallel" : "sequential",
|
||||
groupId: `P${batches.length + 1}`,
|
||||
taskSummary: ready.map(t => t.title).join(' | '),
|
||||
tasks: ready
|
||||
})
|
||||
|
||||
remaining = remaining.filter(t => !processed.has(t.taskIndex))
|
||||
}
|
||||
|
||||
return batches
|
||||
}
|
||||
|
||||
const executionBatches = createExecutionBatches(planObject.tasks, executionMethod)
|
||||
|
||||
TodoWrite({
|
||||
todos: executionBatches.map(b => ({
|
||||
content: `${b.executionType === "parallel" ? "⚡" : "→"} [${b.groupId}] (${b.tasks.length} tasks)`,
|
||||
status: "pending",
|
||||
activeForm: `Executing ${b.groupId}`
|
||||
}))
|
||||
})
|
||||
```
|
||||
|
||||
### Step 3: Launch Execution (Codex Subagent Pattern)
|
||||
|
||||
#### Executor Resolution
|
||||
|
||||
```javascript
|
||||
// Get executor for task (task-level > global)
|
||||
function getTaskExecutor(task) {
|
||||
const assignments = executionContext?.executorAssignments || {}
|
||||
if (assignments[task.id]) {
|
||||
return assignments[task.id].executor // 'gemini' | 'codex' | 'agent'
|
||||
}
|
||||
// Fallback: global executionMethod mapping
|
||||
const method = executionContext?.executionMethod || 'Auto'
|
||||
if (method === 'Agent') return 'agent'
|
||||
if (method === 'Codex') return 'codex'
|
||||
// Auto: based on complexity
|
||||
return planObject.complexity === 'Low' ? 'agent' : 'codex'
|
||||
}
|
||||
```
|
||||
|
||||
#### Unified Task Prompt Builder
|
||||
|
||||
```javascript
|
||||
function buildExecutionPrompt(batch) {
|
||||
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')}
|
||||
|
||||
${t.rationale ? `
|
||||
### Why this approach
|
||||
${t.rationale.chosen_approach}
|
||||
${t.rationale.decision_factors?.length > 0 ? `\nKey factors: ${t.rationale.decision_factors.join(', ')}` : ''}
|
||||
` : ''}
|
||||
|
||||
### How to do it
|
||||
${t.description}
|
||||
|
||||
${t.implementation.map(step => `- ${step}`).join('\n')}
|
||||
|
||||
### Reference
|
||||
- Pattern: ${t.reference?.pattern || 'N/A'}
|
||||
- Files: ${t.reference?.files?.join(', ') || 'N/A'}
|
||||
|
||||
### Done when
|
||||
${t.acceptance.map(c => `- [ ] ${c}`).join('\n')}`
|
||||
|
||||
const sections = []
|
||||
|
||||
if (originalUserInput) sections.push(`## Goal\n${originalUserInput}`)
|
||||
|
||||
sections.push(`## Tasks\n${batch.tasks.map(formatTask).join('\n\n---\n')}`)
|
||||
|
||||
// Context
|
||||
const context = []
|
||||
if (previousExecutionResults.length > 0) {
|
||||
context.push(`### Previous Work\n${previousExecutionResults.map(r => `- ${r.tasksSummary}: ${r.status}`).join('\n')}`)
|
||||
}
|
||||
if (clarificationContext) {
|
||||
context.push(`### Clarifications\n${Object.entries(clarificationContext).map(([q, a]) => `- ${q}: ${a}`).join('\n')}`)
|
||||
}
|
||||
context.push(`### Project Guidelines\n@.workflow/project-guidelines.json`)
|
||||
if (context.length > 0) sections.push(`## Context\n${context.join('\n\n')}`)
|
||||
|
||||
sections.push(`Complete each task according to its "Done when" checklist.`)
|
||||
|
||||
return sections.join('\n\n')
|
||||
}
|
||||
```
|
||||
|
||||
#### Parallel Batch Execution (Codex Pattern)
|
||||
|
||||
```javascript
|
||||
// ==================== CODEX SUBAGENT PATTERN ====================
|
||||
|
||||
async function executeBatch(batch) {
|
||||
const executor = getTaskExecutor(batch.tasks[0])
|
||||
|
||||
if (executor === 'agent') {
|
||||
return executeWithAgent(batch)
|
||||
} else {
|
||||
return executeWithCLI(batch, executor)
|
||||
}
|
||||
}
|
||||
|
||||
// Option A: Agent Execution (spawn_agent pattern)
|
||||
async function executeWithAgent(batch) {
|
||||
// Step 1: Spawn agents for parallel execution (role file read by agent itself)
|
||||
const executionAgents = batch.tasks.map((task, index) => {
|
||||
return spawn_agent({
|
||||
message: `
|
||||
## TASK ASSIGNMENT
|
||||
|
||||
### Execution Context
|
||||
- **Batch ID**: ${batch.groupId}
|
||||
- **Task Index**: ${index + 1} of ${batch.tasks.length}
|
||||
- **Execution Type**: ${batch.executionType}
|
||||
|
||||
### Task Content
|
||||
${buildExecutionPrompt({ ...batch, tasks: [task] })}
|
||||
|
||||
### MANDATORY FIRST STEPS (Agent Execute)
|
||||
1. **Read role definition**: ~/.codex/agents/code-developer.md (MUST read first)
|
||||
2. Read: .workflow/project-tech.json (technology context)
|
||||
3. Read: .workflow/project-guidelines.json (constraints)
|
||||
4. Understand existing patterns before modifying
|
||||
|
||||
### Quality Standards
|
||||
- Follow existing code patterns
|
||||
- Maintain backward compatibility
|
||||
- No unnecessary changes beyond scope
|
||||
|
||||
### Deliverables
|
||||
- Implement task according to "Done when" checklist
|
||||
- Return: Brief completion summary with files modified
|
||||
`
|
||||
})
|
||||
})
|
||||
|
||||
// Step 3: Batch wait for all agents
|
||||
const results = wait({
|
||||
ids: executionAgents,
|
||||
timeout_ms: 900000 // 15 minutes per batch
|
||||
})
|
||||
|
||||
// Step 4: Collect results
|
||||
const batchResult = {
|
||||
executionId: `[${batch.groupId}]`,
|
||||
status: results.timed_out ? 'partial' : 'completed',
|
||||
tasksSummary: batch.taskSummary,
|
||||
completionSummary: '',
|
||||
keyOutputs: '',
|
||||
notes: ''
|
||||
}
|
||||
|
||||
executionAgents.forEach((agentId, index) => {
|
||||
if (results.status[agentId].completed) {
|
||||
batchResult.completionSummary += `Task ${index + 1}: ${results.status[agentId].completed}\n`
|
||||
}
|
||||
})
|
||||
|
||||
// Step 5: Cleanup all agents
|
||||
executionAgents.forEach(id => close_agent({ id }))
|
||||
|
||||
return batchResult
|
||||
}
|
||||
|
||||
// Option B: CLI Execution (ccw cli)
|
||||
async function executeWithCLI(batch, executor) {
|
||||
const sessionId = executionContext?.session?.id || 'standalone'
|
||||
const fixedExecutionId = `${sessionId}-${batch.groupId}`
|
||||
|
||||
const cli_command = `ccw cli -p "${buildExecutionPrompt(batch)}" --tool ${executor} --mode write --id ${fixedExecutionId}`
|
||||
|
||||
// Execute in background
|
||||
Bash({
|
||||
command: cli_command,
|
||||
run_in_background: true
|
||||
})
|
||||
|
||||
// STOP HERE - CLI executes in background, task hook will notify on completion
|
||||
return {
|
||||
executionId: `[${batch.groupId}]`,
|
||||
status: 'in_progress',
|
||||
tasksSummary: batch.taskSummary,
|
||||
fixedCliId: fixedExecutionId
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Execution Flow
|
||||
|
||||
```javascript
|
||||
// ==================== MAIN EXECUTION FLOW ====================
|
||||
|
||||
const parallelBatches = executionBatches.filter(b => b.executionType === "parallel")
|
||||
const sequentialBatches = executionBatches.filter(b => b.executionType === "sequential")
|
||||
|
||||
// Phase 1: Launch all parallel batches (Codex batch wait advantage)
|
||||
if (parallelBatches.length > 0) {
|
||||
TodoWrite({
|
||||
todos: executionBatches.map(b => ({
|
||||
status: b.executionType === "parallel" ? "in_progress" : "pending"
|
||||
}))
|
||||
})
|
||||
|
||||
// Spawn all parallel batch agents at once (role file read by agent itself)
|
||||
const allParallelAgents = []
|
||||
const batchToAgents = new Map()
|
||||
|
||||
for (const batch of parallelBatches) {
|
||||
const executor = getTaskExecutor(batch.tasks[0])
|
||||
|
||||
if (executor === 'agent') {
|
||||
const agents = batch.tasks.map((task, index) => spawn_agent({
|
||||
message: `
|
||||
## TASK: ${task.title}
|
||||
${buildExecutionPrompt({ ...batch, tasks: [task] })}
|
||||
|
||||
### MANDATORY FIRST STEPS (Agent Execute)
|
||||
1. **Read role definition**: ~/.codex/agents/code-developer.md (MUST read first)
|
||||
2. Read: .workflow/project-tech.json
|
||||
3. Read: .workflow/project-guidelines.json
|
||||
`
|
||||
}))
|
||||
|
||||
allParallelAgents.push(...agents)
|
||||
batchToAgents.set(batch.groupId, agents)
|
||||
}
|
||||
}
|
||||
|
||||
// Single batch wait for ALL parallel agents (KEY CODEX ADVANTAGE)
|
||||
if (allParallelAgents.length > 0) {
|
||||
const parallelResults = wait({
|
||||
ids: allParallelAgents,
|
||||
timeout_ms: 900000
|
||||
})
|
||||
|
||||
// Collect results per batch
|
||||
for (const batch of parallelBatches) {
|
||||
const agents = batchToAgents.get(batch.groupId) || []
|
||||
const batchResult = {
|
||||
executionId: `[${batch.groupId}]`,
|
||||
status: 'completed',
|
||||
tasksSummary: batch.taskSummary,
|
||||
completionSummary: agents.map((id, i) =>
|
||||
parallelResults.status[id]?.completed || 'incomplete'
|
||||
).join('\n')
|
||||
}
|
||||
previousExecutionResults.push(batchResult)
|
||||
}
|
||||
|
||||
// Cleanup all parallel agents
|
||||
allParallelAgents.forEach(id => close_agent({ id }))
|
||||
}
|
||||
|
||||
TodoWrite({
|
||||
todos: executionBatches.map(b => ({
|
||||
status: parallelBatches.includes(b) ? "completed" : "pending"
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
// Phase 2: Execute sequential batches one by one
|
||||
for (const batch of sequentialBatches) {
|
||||
TodoWrite({
|
||||
todos: executionBatches.map(b => ({
|
||||
status: b === batch ? "in_progress" : (processed.has(b) ? "completed" : "pending")
|
||||
}))
|
||||
})
|
||||
|
||||
const result = await executeBatch(batch)
|
||||
previousExecutionResults.push(result)
|
||||
|
||||
TodoWrite({
|
||||
todos: executionBatches.map(b => ({
|
||||
status: "completed" /* or "pending" for remaining */
|
||||
}))
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
### Step 4: Progress Tracking
|
||||
|
||||
Progress tracked at batch level. Icons: ⚡ (parallel), → (sequential)
|
||||
|
||||
### Step 5: Code Review (Optional)
|
||||
|
||||
**Skip Condition**: Only run if `codeReviewTool ≠ "Skip"`
|
||||
|
||||
```javascript
|
||||
// ==================== CODE REVIEW (CODEX PATTERN) ====================
|
||||
|
||||
if (codeReviewTool !== 'Skip') {
|
||||
console.log(`
|
||||
## Code Review
|
||||
|
||||
Starting ${codeReviewTool} review...
|
||||
`)
|
||||
|
||||
const reviewPrompt = `
|
||||
PURPOSE: Code review for implemented changes against plan acceptance criteria
|
||||
TASK: • Verify plan acceptance criteria • Check verification requirements • Analyze code quality • Identify issues
|
||||
MODE: analysis
|
||||
CONTEXT: @**/* @${executionContext.session.artifacts.plan} | Memory: Review lite-execute changes
|
||||
EXPECTED: Quality assessment with: acceptance verification, issue identification, recommendations
|
||||
CONSTRAINTS: Focus on plan acceptance criteria | analysis=READ-ONLY
|
||||
`
|
||||
|
||||
if (codeReviewTool === 'Agent Review') {
|
||||
// Spawn review agent (role file read by agent itself)
|
||||
const reviewAgent = spawn_agent({
|
||||
message: `
|
||||
## TASK: Code Review
|
||||
|
||||
${reviewPrompt}
|
||||
|
||||
### MANDATORY FIRST STEPS (Agent Execute)
|
||||
1. **Read role definition**: ~/.codex/agents/code-developer.md (MUST read first)
|
||||
2. Read plan artifact: ${executionContext.session.artifacts.plan}
|
||||
${executionContext.session.artifacts.explorations?.map(e => `3. Read exploration: ${e.path}`).join('\n') || ''}
|
||||
|
||||
### Review Focus
|
||||
1. Verify each acceptance criterion from plan.tasks[].acceptance
|
||||
2. Check verification requirements (unit_tests, success_metrics)
|
||||
3. Validate plan adherence and risk mitigations
|
||||
4. Identify any issues or improvements needed
|
||||
|
||||
### Output Format
|
||||
Summary: [overall assessment]
|
||||
Acceptance: [criterion 1: ✓/✗, criterion 2: ✓/✗, ...]
|
||||
Issues: [list of issues if any]
|
||||
Recommendations: [suggestions]
|
||||
`
|
||||
})
|
||||
|
||||
const reviewResult = wait({
|
||||
ids: [reviewAgent],
|
||||
timeout_ms: 600000
|
||||
})
|
||||
|
||||
console.log(`
|
||||
### Review Complete
|
||||
|
||||
${reviewResult.status[reviewAgent].completed}
|
||||
`)
|
||||
|
||||
close_agent({ id: reviewAgent })
|
||||
|
||||
} else if (codeReviewTool === 'Gemini Review') {
|
||||
// CLI-based review
|
||||
Bash({
|
||||
command: `ccw cli -p "${reviewPrompt}" --tool gemini --mode analysis`,
|
||||
run_in_background: true
|
||||
})
|
||||
// Wait for hook callback
|
||||
|
||||
} else if (codeReviewTool === 'Codex Review') {
|
||||
// Git-aware review
|
||||
Bash({
|
||||
command: `ccw cli --tool codex --mode review --uncommitted`,
|
||||
run_in_background: true
|
||||
})
|
||||
// Wait for hook callback
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 6: Update Development Index
|
||||
|
||||
```javascript
|
||||
// After all executions complete
|
||||
const projectJsonPath = '.workflow/project-tech.json'
|
||||
if (fileExists(projectJsonPath)) {
|
||||
const projectJson = JSON.parse(Read(projectJsonPath))
|
||||
|
||||
if (!projectJson.development_index) {
|
||||
projectJson.development_index = { feature: [], enhancement: [], bugfix: [], refactor: [], docs: [] }
|
||||
}
|
||||
|
||||
function detectCategory(text) {
|
||||
text = text.toLowerCase()
|
||||
if (/\b(fix|bug|error|issue|crash)\b/.test(text)) return 'bugfix'
|
||||
if (/\b(refactor|cleanup|reorganize)\b/.test(text)) return 'refactor'
|
||||
if (/\b(doc|readme|comment)\b/.test(text)) return 'docs'
|
||||
if (/\b(add|new|create|implement)\b/.test(text)) return 'feature'
|
||||
return 'enhancement'
|
||||
}
|
||||
|
||||
const category = detectCategory(`${planObject.summary} ${planObject.approach}`)
|
||||
const entry = {
|
||||
title: planObject.summary.slice(0, 60),
|
||||
date: new Date().toISOString().split('T')[0],
|
||||
description: planObject.approach.slice(0, 100),
|
||||
status: previousExecutionResults.every(r => r.status === 'completed') ? 'completed' : 'partial',
|
||||
session_id: executionContext?.session?.id || null
|
||||
}
|
||||
|
||||
projectJson.development_index[category].push(entry)
|
||||
Write(projectJsonPath, JSON.stringify(projectJson, null, 2))
|
||||
|
||||
console.log(`✓ Development index: [${category}] ${entry.title}`)
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Codex vs Claude Comparison (for this workflow)
|
||||
|
||||
| Aspect | Claude Code Task | Codex Subagent |
|
||||
|--------|------------------|----------------|
|
||||
| **Creation** | `Task({ subagent_type, prompt })` | `spawn_agent({ message: task })` |
|
||||
| **Role Loading** | Auto via `subagent_type` | Agent reads `~/.codex/agents/*.md` in MANDATORY FIRST STEPS |
|
||||
| **Parallel Wait** | Multiple `Task()` calls | **Batch `wait({ ids: [...] })`** |
|
||||
| **Result Retrieval** | Sync return or `TaskOutput` | `wait({ ids }).status[id].completed` |
|
||||
| **Follow-up** | `resume` parameter | `send_input({ id, message })` |
|
||||
| **Cleanup** | Automatic | **Explicit `close_agent({ id })`** |
|
||||
|
||||
**Codex Advantages for lite-execute**:
|
||||
- True parallel execution with batch `wait` for all independent tasks
|
||||
- Single wait call for multiple agents (reduced orchestration overhead)
|
||||
- Fine-grained lifecycle control for complex task graphs
|
||||
|
||||
---
|
||||
|
||||
## Data Structures
|
||||
|
||||
### executionContext (Input - Mode 1)
|
||||
|
||||
```javascript
|
||||
{
|
||||
planObject: {
|
||||
summary: string,
|
||||
approach: string,
|
||||
tasks: [...],
|
||||
estimated_time: string,
|
||||
recommended_execution: string,
|
||||
complexity: string
|
||||
},
|
||||
clarificationContext: {...} | null,
|
||||
executionMethod: "Agent" | "Codex" | "Auto",
|
||||
codeReviewTool: "Skip" | "Gemini Review" | "Codex Review" | string,
|
||||
originalUserInput: string,
|
||||
executorAssignments: {
|
||||
[taskId]: { executor: "gemini" | "codex" | "agent", reason: string }
|
||||
},
|
||||
session: {
|
||||
id: string,
|
||||
folder: string,
|
||||
artifacts: {
|
||||
explorations: [{angle, path}],
|
||||
plan: string
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### executionResult (Output)
|
||||
|
||||
```javascript
|
||||
{
|
||||
executionId: string, // e.g., "[P1]", "[S1]"
|
||||
status: "completed" | "partial" | "failed",
|
||||
tasksSummary: string,
|
||||
completionSummary: string,
|
||||
keyOutputs: string,
|
||||
notes: string,
|
||||
fixedCliId: string | null // For CLI resume capability
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Error | Resolution |
|
||||
|-------|------------|
|
||||
| spawn_agent failure | Fallback to CLI execution |
|
||||
| wait() timeout | Use completed results, log partial status |
|
||||
| Agent crash | Collect partial output, offer retry |
|
||||
| CLI execution failure | Use fixed ID for resume |
|
||||
| Circular dependency | Force remaining tasks with warning |
|
||||
| Missing executionContext | Error: "No execution context found" |
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
**Codex-Specific**:
|
||||
- Pass role file path in MANDATORY FIRST STEPS (agent reads itself)
|
||||
- Use batch `wait({ ids: [...] })` for parallel tasks
|
||||
- Delay `close_agent` until all interactions complete
|
||||
- Track `fixedCliId` for resume capability
|
||||
|
||||
**General**:
|
||||
- Task Grouping: Based on explicit depends_on only
|
||||
- Execution: All independent tasks launch via single batch wait
|
||||
- Progress: TodoWrite at batch level (⚡ parallel, → sequential)
|
||||
|
||||
---
|
||||
|
||||
**Now execute the lite-execute workflow**
|
||||
@@ -1,674 +0,0 @@
|
||||
---
|
||||
description: Lightweight bug diagnosis and fix workflow with optimized Codex subagent patterns. Supports severity and scope control.
|
||||
argument-hint: "BUG=\"<description or error message>\" [--hotfix] [--severity=critical|high|medium|low] [--scope=<path>]"
|
||||
---
|
||||
|
||||
# Workflow Lite-Fix Command (Codex Optimized Version)
|
||||
|
||||
## Overview
|
||||
|
||||
Intelligent lightweight bug fixing command with **optimized subagent orchestration**. Uses merged mode pattern for context preservation across diagnosis, clarification, and fix planning phases.
|
||||
|
||||
**Core Optimizations:**
|
||||
- **Context Preservation**: Primary agent retained across phases via `send_input()`
|
||||
- **Merged Mode**: Diagnosis → Merge → Clarify → Plan in single agent context
|
||||
- **Reduced Agent Cycles**: Minimize spawn/close overhead
|
||||
- **Dual-Role Pattern**: Single agent handles both exploration and planning (Low/Medium)
|
||||
|
||||
**Core capabilities:**
|
||||
- Intelligent bug analysis with automatic severity detection
|
||||
- Parallel code diagnosis via Codex subagents (spawn_agent + batch wait)
|
||||
- **Merged clarification + fix planning** (send_input to retained agent)
|
||||
- Adaptive fix planning based on severity
|
||||
- Two-step confirmation: fix-plan display → user approval
|
||||
- Outputs fix-plan.json file after user confirmation
|
||||
|
||||
## Bug Description
|
||||
|
||||
**Target bug**: $BUG
|
||||
**Hotfix mode**: $HOTFIX
|
||||
|
||||
- `--hotfix`: Hotfix mode, prioritize speed
|
||||
- `--severity`: Bug severity (critical|high|medium|low)
|
||||
- `--scope`: Debug scope limit (file path)
|
||||
|
||||
## Execution Modes
|
||||
|
||||
### Mode Selection Based on Severity
|
||||
|
||||
| Severity | Mode | Pattern | Phases |
|
||||
|----------|------|---------|--------|
|
||||
| Low/Medium | 方案A (合并模式) | Single dual-role agent | 2-phase with send_input |
|
||||
| High/Critical | 方案B (混合模式) | Multi-agent + primary merge | Parallel → Merge → Plan |
|
||||
|
||||
## Execution Process
|
||||
|
||||
```
|
||||
Phase 0: Setup & Severity Assessment
|
||||
├─ Parse input (description, error message, or .md file)
|
||||
├─ Create session folder
|
||||
├─ Intelligent severity pre-assessment (Low/Medium/High/Critical)
|
||||
└─ Select execution mode (方案A or 方案B)
|
||||
|
||||
========== 方案A: Low/Medium Severity (Merged Mode) ==========
|
||||
|
||||
Phase 1A: Dual-Role Agent (Diagnosis + Planning)
|
||||
├─ spawn_agent with combined diagnosis + planning role
|
||||
├─ wait for initial diagnosis
|
||||
└─ Agent retains context for next phase
|
||||
|
||||
Phase 2A: Clarification + Fix Planning (send_input)
|
||||
├─ send_input: clarification answers + "generate fix plan"
|
||||
├─ wait for fix-plan.json generation
|
||||
└─ close_agent (single cleanup)
|
||||
|
||||
========== 方案B: High/Critical Severity (Mixed Mode) ==========
|
||||
|
||||
Phase 1B: Parallel Multi-Angle Diagnosis
|
||||
├─ spawn_agent × N (primary = dual-role, others = explore-only)
|
||||
├─ wait({ ids: [...] }) for all diagnoses
|
||||
└─ Collect all diagnosis results
|
||||
|
||||
Phase 2B: Merge + Clarify (send_input to primary)
|
||||
├─ close_agent × (N-1) non-primary agents
|
||||
├─ send_input to primary: other agents' diagnoses + "merge findings"
|
||||
└─ wait for merged analysis + clarification needs
|
||||
|
||||
Phase 3B: Fix Planning (send_input to primary)
|
||||
├─ send_input: clarification answers + "generate fix plan"
|
||||
├─ wait for fix-plan.json generation
|
||||
└─ close_agent (primary cleanup)
|
||||
|
||||
========== Common Phases ==========
|
||||
|
||||
Phase 4: Confirmation
|
||||
├─ Display fix-plan summary (tasks, severity, risk level)
|
||||
├─ Output confirmation request
|
||||
└─ STOP and wait for user approval
|
||||
|
||||
Phase 5: Output
|
||||
└─ Confirm fix-plan.json written to session folder
|
||||
```
|
||||
|
||||
## Implementation
|
||||
|
||||
### Phase 0: Setup & Severity Assessment
|
||||
|
||||
**Session Setup** (MANDATORY):
|
||||
```javascript
|
||||
// Helper: Get UTC+8 (China Standard Time) ISO string
|
||||
const getUtc8ISOString = () => new Date(Date.now() + 8 * 60 * 60 * 1000).toISOString()
|
||||
|
||||
const bugSlug = "$BUG".toLowerCase().replace(/[^a-z0-9]+/g, '-').substring(0, 40)
|
||||
const dateStr = getUtc8ISOString().substring(0, 10) // Format: 2025-11-29
|
||||
|
||||
const sessionId = `${bugSlug}-${dateStr}`
|
||||
const sessionFolder = `.workflow/.lite-fix/${sessionId}`
|
||||
|
||||
// Create session folder
|
||||
mkdir -p ${sessionFolder}
|
||||
```
|
||||
|
||||
**Hotfix Mode Check**:
|
||||
```javascript
|
||||
const hotfixMode = "$HOTFIX" === "true"
|
||||
|
||||
if (hotfixMode) {
|
||||
// Skip diagnosis, go directly to minimal fix planning
|
||||
proceed_to_direct_fix()
|
||||
}
|
||||
```
|
||||
|
||||
**Severity Assessment**:
|
||||
```javascript
|
||||
// Analyze bug severity based on symptoms, scope, urgency, impact
|
||||
const severity = analyzeBugSeverity("$BUG")
|
||||
// Returns: 'Low' | 'Medium' | 'High' | 'Critical'
|
||||
|
||||
// Mode selection
|
||||
const executionMode = (severity === 'Low' || severity === 'Medium') ? 'A' : 'B'
|
||||
|
||||
console.log(`
|
||||
## Bug Analysis
|
||||
|
||||
**Severity**: ${severity}
|
||||
**Execution Mode**: 方案${executionMode} (${executionMode === 'A' ? '合并模式 - Single Agent' : '混合模式 - Multi-Agent'})
|
||||
`)
|
||||
```
|
||||
|
||||
**Angle Selection** (for diagnosis):
|
||||
```javascript
|
||||
const DIAGNOSIS_ANGLE_PRESETS = {
|
||||
runtime_error: ['error-handling', 'dataflow', 'state-management', 'edge-cases'],
|
||||
performance: ['performance', 'bottlenecks', 'caching', 'data-access'],
|
||||
security: ['security', 'auth-patterns', 'dataflow', 'validation'],
|
||||
data_corruption: ['data-integrity', 'state-management', 'transactions', 'validation'],
|
||||
ui_bug: ['state-management', 'event-handling', 'rendering', 'data-binding'],
|
||||
integration: ['api-contracts', 'error-handling', 'timeouts', 'fallbacks']
|
||||
}
|
||||
|
||||
function selectDiagnosisAngles(bugDescription, count) {
|
||||
const text = bugDescription.toLowerCase()
|
||||
let preset = 'runtime_error'
|
||||
|
||||
if (/slow|timeout|performance|lag|hang/.test(text)) preset = 'performance'
|
||||
else if (/security|auth|permission|access|token/.test(text)) preset = 'security'
|
||||
else if (/corrupt|data|lost|missing|inconsistent/.test(text)) preset = 'data_corruption'
|
||||
else if (/ui|display|render|style|click|button/.test(text)) preset = 'ui_bug'
|
||||
else if (/api|integration|connect|request|response/.test(text)) preset = 'integration'
|
||||
|
||||
return DIAGNOSIS_ANGLE_PRESETS[preset].slice(0, count)
|
||||
}
|
||||
|
||||
const angleCount = severity === 'Critical' ? 4 : (severity === 'High' ? 3 : (severity === 'Medium' ? 2 : 1))
|
||||
const selectedAngles = selectDiagnosisAngles("$BUG", angleCount)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 方案A: Low/Medium Severity (合并模式)
|
||||
|
||||
**Pattern**: Single dual-role agent handles diagnosis + clarification + fix planning with context preserved via `send_input()`.
|
||||
|
||||
### Phase 1A: Dual-Role Agent (Diagnosis + Planning)
|
||||
|
||||
```javascript
|
||||
// ==================== MERGED MODE ====================
|
||||
|
||||
// Step 1: Spawn single dual-role agent (角色文件由 agent 自己读取)
|
||||
const dualAgent = spawn_agent({
|
||||
message: `
|
||||
## PHASE 1: DIAGNOSIS
|
||||
|
||||
### Task Objective
|
||||
Execute comprehensive diagnosis for bug root cause analysis. You have combined diagnosis + planning capabilities.
|
||||
|
||||
### Bug Description
|
||||
$BUG
|
||||
|
||||
### Diagnosis Angles (analyze all)
|
||||
${selectedAngles.map((angle, i) => `${i + 1}. ${angle}`).join('\n')}
|
||||
|
||||
### MANDATORY FIRST STEPS (Agent Execute)
|
||||
1. **Read diagnosis role**: ~/.codex/agents/cli-explore-agent.md (MUST read first)
|
||||
2. **Read planning role**: ~/.codex/agents/cli-lite-planning-agent.md (for Phase 2)
|
||||
3. Run: ccw tool exec get_modules_by_depth '{}' (project structure)
|
||||
4. Run: rg -l "{error_keyword_from_bug}" --type ts (locate relevant files)
|
||||
5. Execute: cat ~/.claude/workflows/cli-templates/schemas/diagnosis-json-schema.json
|
||||
6. Read: .workflow/project-tech.json
|
||||
7. Read: .workflow/project-guidelines.json
|
||||
|
||||
### Diagnosis Tasks
|
||||
For each angle (${selectedAngles.join(', ')}):
|
||||
1. **Error Tracing**: rg for error messages, stack traces
|
||||
2. **Root Cause Analysis**: Identify code paths, edge cases
|
||||
3. **Affected Files**: List with relevance scores
|
||||
|
||||
### Expected Output
|
||||
1. Write diagnosis to: ${sessionFolder}/diagnosis-merged.json
|
||||
2. List any clarification needs (questions + options)
|
||||
3. **DO NOT proceed to fix planning yet** - wait for Phase 2 input
|
||||
|
||||
### Clarification Format (if needed)
|
||||
If you need clarification, output:
|
||||
\`\`\`json
|
||||
{
|
||||
"clarification_needs": [
|
||||
{
|
||||
"question": "...",
|
||||
"context": "...",
|
||||
"options": ["Option 1", "Option 2", "Option 3"],
|
||||
"recommended": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
### Deliverables for Phase 1
|
||||
- Write: ${sessionFolder}/diagnosis-merged.json
|
||||
- Return: Diagnosis summary + clarification needs (if any)
|
||||
`
|
||||
})
|
||||
|
||||
// Step 3: Wait for diagnosis
|
||||
const diagnosisResult = wait({
|
||||
ids: [dualAgent],
|
||||
timeout_ms: 600000 // 10 minutes
|
||||
})
|
||||
|
||||
// Extract clarification needs from result
|
||||
const clarificationNeeds = extractClarificationNeeds(diagnosisResult.status[dualAgent].completed)
|
||||
```
|
||||
|
||||
**Handle Clarification (if needed)**:
|
||||
```javascript
|
||||
if (clarificationNeeds.length > 0) {
|
||||
console.log(`
|
||||
## Clarification Needed
|
||||
|
||||
${clarificationNeeds.map((need, index) => `
|
||||
### Question ${index + 1}
|
||||
|
||||
**${need.question}**
|
||||
|
||||
Context: ${need.context}
|
||||
|
||||
Options:
|
||||
${need.options.map((opt, i) => ` ${i + 1}. ${opt}${need.recommended === i ? ' ★ (Recommended)' : ''}`).join('\n')}
|
||||
`).join('\n')}
|
||||
|
||||
---
|
||||
|
||||
**Please reply with your choices** (e.g., "Q1: 2, Q2: 1") to continue.
|
||||
|
||||
**WAITING FOR USER INPUT...**
|
||||
`)
|
||||
// STOP - Wait for user reply
|
||||
return
|
||||
}
|
||||
```
|
||||
|
||||
### Phase 2A: Clarification + Fix Planning (send_input)
|
||||
|
||||
```javascript
|
||||
// After user replies with clarification answers...
|
||||
const clarificationAnswers = /* user's answers */
|
||||
|
||||
// Step 4: send_input for fix planning (CONTEXT PRESERVED)
|
||||
send_input({
|
||||
id: dualAgent,
|
||||
message: `
|
||||
## PHASE 2: FIX PLANNING
|
||||
|
||||
### User Clarifications
|
||||
${clarificationAnswers || "No clarifications needed"}
|
||||
|
||||
### Schema Reference
|
||||
Execute: cat ~/.claude/workflows/cli-templates/schemas/fix-plan-json-schema.json
|
||||
|
||||
### Generate Fix Plan
|
||||
Based on your diagnosis, generate a comprehensive fix plan:
|
||||
|
||||
1. Read your diagnosis file: ${sessionFolder}/diagnosis-merged.json
|
||||
2. Synthesize root cause from all analyzed angles
|
||||
3. Generate fix-plan.json with:
|
||||
- summary: 2-3 sentence overview
|
||||
- root_cause: Consolidated from diagnosis
|
||||
- strategy: "immediate_patch" | "comprehensive_fix" | "refactor"
|
||||
- tasks: 1-3 structured fix tasks (group by fix area)
|
||||
- severity: ${severity}
|
||||
- risk_level: based on analysis
|
||||
|
||||
### Task Grouping Rules
|
||||
1. Group by fix area (all changes for one fix = one task)
|
||||
2. Avoid file-per-task pattern
|
||||
3. Each task = 10-30 minutes of work
|
||||
4. Prefer parallel tasks (minimal dependencies)
|
||||
|
||||
### Deliverables
|
||||
- Write: ${sessionFolder}/fix-plan.json
|
||||
- Return: Brief fix plan summary
|
||||
`
|
||||
})
|
||||
|
||||
// Step 5: Wait for fix planning
|
||||
const planResult = wait({
|
||||
ids: [dualAgent],
|
||||
timeout_ms: 600000 // 10 minutes
|
||||
})
|
||||
|
||||
// Step 6: Cleanup (single close)
|
||||
close_agent({ id: dualAgent })
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 方案B: High/Critical Severity (混合模式)
|
||||
|
||||
**Pattern**: Parallel multi-angle diagnosis → keep primary agent → send_input for merge + clarify + plan.
|
||||
|
||||
### Phase 1B: Parallel Multi-Angle Diagnosis
|
||||
|
||||
```javascript
|
||||
// ==================== MIXED MODE ====================
|
||||
|
||||
// Step 1: Spawn parallel diagnosis agents (角色文件由 agent 自己读取)
|
||||
// primary = dual-role (diagnosis + planning)
|
||||
const diagnosisAgents = selectedAngles.map((angle, index) => {
|
||||
const isPrimary = index === 0
|
||||
|
||||
return spawn_agent({
|
||||
message: `
|
||||
## TASK ASSIGNMENT
|
||||
|
||||
### Agent Type
|
||||
${isPrimary ? '**PRIMARY** (Dual-role: Diagnosis + Planning)' : `Secondary (Diagnosis only - angle: ${angle})`}
|
||||
|
||||
### Task Objective
|
||||
Execute **${angle}** diagnosis for bug root cause analysis.
|
||||
|
||||
### Bug Description
|
||||
$BUG
|
||||
|
||||
### Diagnosis Angle
|
||||
${angle}
|
||||
|
||||
### Output File
|
||||
${sessionFolder}/diagnosis-${angle}.json
|
||||
|
||||
### MANDATORY FIRST STEPS (Agent Execute)
|
||||
1. **Read diagnosis role**: ~/.codex/agents/cli-explore-agent.md (MUST read first)
|
||||
${isPrimary ? '2. **Read planning role**: ~/.codex/agents/cli-lite-planning-agent.md (for Phase 2 & 3)\n3.' : '2.'} Run: ccw tool exec get_modules_by_depth '{}'
|
||||
${isPrimary ? '4.' : '3.'} Run: rg -l "{error_keyword_from_bug}" --type ts
|
||||
${isPrimary ? '5.' : '4.'} Execute: cat ~/.claude/workflows/cli-templates/schemas/diagnosis-json-schema.json
|
||||
${isPrimary ? '6.' : '5.'} Read: .workflow/project-tech.json
|
||||
${isPrimary ? '7.' : '6.'} Read: .workflow/project-guidelines.json
|
||||
|
||||
### Diagnosis Strategy (${angle} focus)
|
||||
1. **Error Tracing**: rg for error messages, stack traces
|
||||
2. **Root Cause Analysis**: Code paths, edge cases for ${angle}
|
||||
3. **Affected Files**: List with ${angle} relevance
|
||||
|
||||
### Expected Output
|
||||
Write: ${sessionFolder}/diagnosis-${angle}.json
|
||||
Return: 2-3 sentence summary of ${angle} findings
|
||||
|
||||
${isPrimary ? `
|
||||
### PRIMARY AGENT NOTE
|
||||
You will receive follow-up tasks via send_input:
|
||||
- Phase 2: Merge other agents' diagnoses
|
||||
- Phase 3: Generate fix plan
|
||||
Keep your context ready for continuation.
|
||||
` : ''}
|
||||
`
|
||||
})
|
||||
})
|
||||
|
||||
// Step 3: Batch wait for ALL diagnosis agents
|
||||
const diagnosisResults = wait({
|
||||
ids: diagnosisAgents,
|
||||
timeout_ms: 600000 // 10 minutes
|
||||
})
|
||||
|
||||
// Step 4: Collect all diagnosis results
|
||||
const allDiagnoses = selectedAngles.map((angle, index) => ({
|
||||
angle,
|
||||
agentId: diagnosisAgents[index],
|
||||
result: diagnosisResults.status[diagnosisAgents[index]].completed,
|
||||
file: `${sessionFolder}/diagnosis-${angle}.json`
|
||||
}))
|
||||
|
||||
console.log(`
|
||||
## Phase 1B Complete
|
||||
|
||||
Diagnoses collected:
|
||||
${allDiagnoses.map(d => `- ${d.angle}: ${d.file}`).join('\n')}
|
||||
`)
|
||||
```
|
||||
|
||||
### Phase 2B: Merge + Clarify (send_input to primary)
|
||||
|
||||
```javascript
|
||||
// Step 5: Close non-primary agents, keep primary
|
||||
const primaryAgent = diagnosisAgents[0]
|
||||
const primaryAngle = selectedAngles[0]
|
||||
|
||||
diagnosisAgents.slice(1).forEach(id => close_agent({ id }))
|
||||
|
||||
console.log(`
|
||||
## Phase 2B: Merge Analysis
|
||||
|
||||
Closed ${diagnosisAgents.length - 1} secondary agents.
|
||||
Sending merge task to primary agent (${primaryAngle})...
|
||||
`)
|
||||
|
||||
// Step 6: send_input for merge + clarification
|
||||
send_input({
|
||||
id: primaryAgent,
|
||||
message: `
|
||||
## PHASE 2: MERGE + CLARIFY
|
||||
|
||||
### Task
|
||||
Merge all diagnosis findings and identify clarification needs.
|
||||
|
||||
### Your Diagnosis (${primaryAngle})
|
||||
Already in your context from Phase 1.
|
||||
|
||||
### Other Agents' Diagnoses to Merge
|
||||
${allDiagnoses.slice(1).map(d => `
|
||||
#### Diagnosis: ${d.angle}
|
||||
File: ${d.file}
|
||||
Summary: ${d.result}
|
||||
`).join('\n')}
|
||||
|
||||
### Merge Instructions
|
||||
1. Read all diagnosis files:
|
||||
${allDiagnoses.map(d => ` - ${d.file}`).join('\n')}
|
||||
|
||||
2. Synthesize findings:
|
||||
- Identify common root causes across angles
|
||||
- Note conflicting findings
|
||||
- Rank confidence levels
|
||||
|
||||
3. Write merged analysis: ${sessionFolder}/diagnosis-merged.json
|
||||
|
||||
4. List clarification needs (if any):
|
||||
- Questions that need user input
|
||||
- Options with recommendations
|
||||
|
||||
### Expected Output
|
||||
- Write: ${sessionFolder}/diagnosis-merged.json
|
||||
- Return: Merged findings summary + clarification needs
|
||||
`
|
||||
})
|
||||
|
||||
// Step 7: Wait for merge
|
||||
const mergeResult = wait({
|
||||
ids: [primaryAgent],
|
||||
timeout_ms: 300000 // 5 minutes
|
||||
})
|
||||
|
||||
// Extract clarification needs
|
||||
const clarificationNeeds = extractClarificationNeeds(mergeResult.status[primaryAgent].completed)
|
||||
```
|
||||
|
||||
**Handle Clarification (if needed)**:
|
||||
```javascript
|
||||
if (clarificationNeeds.length > 0) {
|
||||
console.log(`
|
||||
## Clarification Needed
|
||||
|
||||
${clarificationNeeds.map((need, index) => `
|
||||
### Question ${index + 1}
|
||||
|
||||
**${need.question}**
|
||||
|
||||
Context: ${need.context}
|
||||
|
||||
Options:
|
||||
${need.options.map((opt, i) => ` ${i + 1}. ${opt}${need.recommended === i ? ' ★ (Recommended)' : ''}`).join('\n')}
|
||||
`).join('\n')}
|
||||
|
||||
---
|
||||
|
||||
**Please reply with your choices** to continue.
|
||||
|
||||
**WAITING FOR USER INPUT...**
|
||||
`)
|
||||
return
|
||||
}
|
||||
```
|
||||
|
||||
### Phase 3B: Fix Planning (send_input to primary)
|
||||
|
||||
```javascript
|
||||
// After user replies with clarification answers...
|
||||
const clarificationAnswers = /* user's answers */
|
||||
|
||||
// Step 8: send_input for fix planning (CONTEXT PRESERVED)
|
||||
send_input({
|
||||
id: primaryAgent,
|
||||
message: `
|
||||
## PHASE 3: FIX PLANNING
|
||||
|
||||
### User Clarifications
|
||||
${clarificationAnswers || "No clarifications needed"}
|
||||
|
||||
### Schema Reference
|
||||
Execute: cat ~/.claude/workflows/cli-templates/schemas/fix-plan-json-schema.json
|
||||
|
||||
### Generate Fix Plan
|
||||
Based on your merged diagnosis, generate a comprehensive fix plan:
|
||||
|
||||
1. Read merged diagnosis: ${sessionFolder}/diagnosis-merged.json
|
||||
2. Consider all ${selectedAngles.length} diagnosis angles
|
||||
3. Generate fix-plan.json with:
|
||||
- summary: 2-3 sentence overview
|
||||
- root_cause: Consolidated from all diagnoses
|
||||
- strategy: "immediate_patch" | "comprehensive_fix" | "refactor"
|
||||
- tasks: 1-5 structured fix tasks
|
||||
- severity: ${severity}
|
||||
- risk_level: based on analysis
|
||||
|
||||
### High/Critical Complexity Fields (REQUIRED)
|
||||
For each task:
|
||||
- rationale: Why this fix approach
|
||||
- verification: How to verify success
|
||||
- risks: Potential issues with fix
|
||||
|
||||
### Task Grouping Rules
|
||||
1. Group by fix area (all changes for one fix = one task)
|
||||
2. Avoid file-per-task pattern
|
||||
3. Each task = 10-45 minutes of work
|
||||
4. True dependencies only (prefer parallel)
|
||||
|
||||
### Deliverables
|
||||
- Write: ${sessionFolder}/fix-plan.json
|
||||
- Return: Brief fix plan summary
|
||||
`
|
||||
})
|
||||
|
||||
// Step 9: Wait for fix planning
|
||||
const planResult = wait({
|
||||
ids: [primaryAgent],
|
||||
timeout_ms: 600000 // 10 minutes
|
||||
})
|
||||
|
||||
// Step 10: Cleanup primary agent
|
||||
close_agent({ id: primaryAgent })
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Common Phases (Both Modes)
|
||||
|
||||
### Phase 4: Confirmation
|
||||
|
||||
```javascript
|
||||
const fixPlan = JSON.parse(Read(`${sessionFolder}/fix-plan.json`))
|
||||
|
||||
console.log(`
|
||||
## Fix Plan
|
||||
|
||||
**Summary**: ${fixPlan.summary}
|
||||
**Root Cause**: ${fixPlan.root_cause}
|
||||
**Strategy**: ${fixPlan.strategy}
|
||||
|
||||
**Tasks** (${fixPlan.tasks.length}):
|
||||
${fixPlan.tasks.map((t, i) => `
|
||||
### Task ${i+1}: ${t.title}
|
||||
- **Description**: ${t.description}
|
||||
- **Scope**: ${t.scope}
|
||||
- **Action**: ${t.action}
|
||||
- **Complexity**: ${t.complexity}
|
||||
- **Dependencies**: ${t.depends_on?.join(', ') || 'None'}
|
||||
`).join('\n')}
|
||||
|
||||
**Severity**: ${fixPlan.severity}
|
||||
**Risk Level**: ${fixPlan.risk_level}
|
||||
**Estimated Time**: ${fixPlan.estimated_time}
|
||||
|
||||
---
|
||||
|
||||
## Confirmation Required
|
||||
|
||||
Please review the fix plan above and reply with:
|
||||
|
||||
- **"Allow"** - Proceed with this fix plan
|
||||
- **"Modify"** - Describe what changes you want
|
||||
- **"Cancel"** - Abort the workflow
|
||||
|
||||
**WAITING FOR USER CONFIRMATION...**
|
||||
`)
|
||||
|
||||
return
|
||||
```
|
||||
|
||||
### Phase 5: Output
|
||||
|
||||
```javascript
|
||||
// After User Confirms "Allow"
|
||||
console.log(`
|
||||
## Fix Plan Output Complete
|
||||
|
||||
**Fix plan file**: ${sessionFolder}/fix-plan.json
|
||||
**Session folder**: ${sessionFolder}
|
||||
|
||||
**Contents**:
|
||||
- diagnosis-merged.json (or diagnosis-{angle}.json files)
|
||||
- fix-plan.json
|
||||
|
||||
---
|
||||
|
||||
You can now use this fix plan with your preferred execution method.
|
||||
`)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Mode Comparison
|
||||
|
||||
| Aspect | 方案A (合并模式) | 方案B (混合模式) |
|
||||
|--------|-----------------|-----------------|
|
||||
| **Severity** | Low/Medium | High/Critical |
|
||||
| **Agents** | 1 (dual-role) | N (parallel) → 1 (primary kept) |
|
||||
| **Phases** | 2 (diagnosis → plan) | 3 (diagnose → merge → plan) |
|
||||
| **Context** | Fully preserved | Merged via send_input |
|
||||
| **Overhead** | Minimal | Higher (parallel coordination) |
|
||||
| **Coverage** | Single comprehensive | Multi-angle deep dive |
|
||||
|
||||
## Optimization Benefits
|
||||
|
||||
| Aspect | Before (Original) | After (Optimized) |
|
||||
|--------|-------------------|-------------------|
|
||||
| **Agent Cycles** | spawn × N → close all → spawn new | spawn → send_input → close once |
|
||||
| **Context Loss** | Diagnosis context lost before planning | Context preserved via send_input |
|
||||
| **Merge Process** | None (separate planning agent) | Explicit merge phase (方案B) |
|
||||
| **Low/Medium** | Same as High/Critical | Simplified single-agent path |
|
||||
|
||||
## Session Folder Structure
|
||||
|
||||
```
|
||||
.workflow/.lite-fix/{bug-slug}-{YYYY-MM-DD}/
|
||||
├── diagnosis-merged.json # 方案A or merged 方案B
|
||||
├── diagnosis-{angle1}.json # 方案B only
|
||||
├── diagnosis-{angle2}.json # 方案B only
|
||||
├── diagnosis-{angle3}.json # 方案B only (if applicable)
|
||||
├── diagnosis-{angle4}.json # 方案B only (if applicable)
|
||||
└── fix-plan.json # Fix plan (after confirmation)
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Error | Resolution |
|
||||
|-------|------------|
|
||||
| spawn_agent failure | Fallback to direct diagnosis |
|
||||
| wait() timeout | Use completed results, continue |
|
||||
| send_input failure | Re-spawn agent with context summary |
|
||||
| Clarification timeout | Use diagnosis findings as-is |
|
||||
| Confirmation timeout | Save context, display resume instructions |
|
||||
| Root cause unclear | Extend diagnosis or escalate to 方案B |
|
||||
|
||||
---
|
||||
|
||||
**Now execute the lite-fix workflow for bug**: $BUG
|
||||
@@ -1,341 +0,0 @@
|
||||
---
|
||||
description: Lightweight interactive planning workflow with single-agent merged mode for explore → clarify → plan full flow. Supports depth control and auto-clarification.
|
||||
argument-hint: "TASK=\"<task description or file.md path>\" [--depth=standard|deep] [--auto-clarify] [--max-rounds=<n>] [--verbose]"
|
||||
---
|
||||
|
||||
# Workflow Lite-Plan-A (Merged Mode)
|
||||
|
||||
## Overview
|
||||
|
||||
Single-agent merged mode for lightweight planning. One agent handles exploration, clarification, and planning in a continuous conversation, maximizing context retention and minimizing agent creation overhead.
|
||||
|
||||
**Core capabilities:**
|
||||
- **Single agent dual-role execution** (explorer + planner in one conversation)
|
||||
- Context automatically preserved across phases (no serialization loss)
|
||||
- Reduced user interaction rounds (1-2 vs 3-4)
|
||||
- Best for Low/Medium complexity tasks with single exploration angle
|
||||
|
||||
## Applicable Scenarios
|
||||
|
||||
- **Low/Medium complexity tasks**
|
||||
- Single exploration angle sufficient
|
||||
- Prioritize minimal agent creation and coherent context
|
||||
- Clear, well-defined tasks within single module
|
||||
|
||||
## Core Advantages
|
||||
|
||||
| Metric | Traditional Separated Mode | Plan-A Merged Mode |
|
||||
|--------|---------------------------|-------------------|
|
||||
| Agent creation count | 2-5 | **1** |
|
||||
| Context transfer | Serialized, lossy | **Automatic retention** |
|
||||
| User interaction rounds | 3-4 | **1-2** |
|
||||
| Execution time | Multiple spawn/close | **30-50%↓** |
|
||||
|
||||
## Task Description
|
||||
|
||||
**Target task**: $TASK
|
||||
|
||||
- `--depth`: Exploration depth (standard|deep)
|
||||
- `--auto-clarify`: Auto clarify, skip confirmation
|
||||
- `--max-rounds`: Max interaction rounds
|
||||
|
||||
## Execution Process
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ spawn_agent (dual role: explorer + planner) │
|
||||
│ ↓ │
|
||||
│ Phase 1: Exploration → output findings + clarification_needs│
|
||||
│ ↓ │
|
||||
│ wait() → get exploration results │
|
||||
│ ↓ │
|
||||
│ [If clarification needed] Main process collects user answers│
|
||||
│ ↓ │
|
||||
│ send_input(clarification_answers + "generate plan") │
|
||||
│ ↓ │
|
||||
│ Phase 2: Planning → output plan.json │
|
||||
│ ↓ │
|
||||
│ wait() → get planning results │
|
||||
│ ↓ │
|
||||
│ close_agent() │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Implementation
|
||||
|
||||
### Session Setup
|
||||
|
||||
**Session Setup** (MANDATORY - follow exactly):
|
||||
```javascript
|
||||
// Helper: Get UTC+8 (China Standard Time) ISO string
|
||||
const getUtc8ISOString = () => new Date(Date.now() + 8 * 60 * 60 * 1000).toISOString()
|
||||
|
||||
const taskSlug = "$TASK".toLowerCase().replace(/[^a-z0-9]+/g, '-').substring(0, 40)
|
||||
const dateStr = getUtc8ISOString().substring(0, 10) // Format: 2025-11-29
|
||||
|
||||
const sessionId = `${taskSlug}-${dateStr}` // e.g., "implement-jwt-refresh-2025-11-29"
|
||||
const sessionFolder = `.workflow/.lite-plan/${sessionId}`
|
||||
|
||||
// Create session folder
|
||||
mkdir -p ${sessionFolder}
|
||||
```
|
||||
|
||||
### Complexity Assessment & Angle Selection
|
||||
|
||||
```javascript
|
||||
const complexity = analyzeTaskComplexity("$TASK")
|
||||
// Plan-A is suitable for Low/Medium; High complexity should use Plan-B
|
||||
|
||||
const ANGLE_PRESETS = {
|
||||
architecture: ['architecture', 'dependencies'],
|
||||
security: ['security', 'auth-patterns'],
|
||||
performance: ['performance', 'bottlenecks'],
|
||||
bugfix: ['error-handling', 'dataflow'],
|
||||
feature: ['patterns', 'integration-points']
|
||||
}
|
||||
|
||||
// Plan-A selects only 1-2 most relevant angles
|
||||
const primaryAngle = selectPrimaryAngle("$TASK")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Phase 1 & 2: Single Agent Dual-Role Execution (Codex Pattern)
|
||||
|
||||
```javascript
|
||||
// ==================== PLAN-A: SINGLE AGENT MERGED MODE ====================
|
||||
|
||||
// Step 1: Create dual-role agent (role files read by agent itself)
|
||||
const agent = spawn_agent({
|
||||
message: `
|
||||
## TASK ASSIGNMENT
|
||||
|
||||
### Overview
|
||||
You will complete this task in TWO phases using a SINGLE conversation:
|
||||
1. **Phase 1**: Explore codebase, output findings and clarification questions
|
||||
2. **Phase 2**: After receiving clarification answers, generate implementation plan
|
||||
|
||||
### Task Description
|
||||
${task_description}
|
||||
|
||||
### Session Info
|
||||
- Session ID: ${sessionId}
|
||||
- Session Folder: ${sessionFolder}
|
||||
- Primary Angle: ${primaryAngle}
|
||||
|
||||
---
|
||||
|
||||
## PHASE 1: EXPLORATION
|
||||
|
||||
### MANDATORY FIRST STEPS (Agent Execute)
|
||||
1. **Read explorer role**: ~/.codex/agents/cli-explore-agent.md (MUST read first)
|
||||
2. **Read planner role**: ~/.codex/agents/cli-lite-planning-agent.md (for Phase 2)
|
||||
3. Run: ccw tool exec get_modules_by_depth '{}'
|
||||
4. Run: rg -l "{keyword_from_task}" --type ts
|
||||
5. Read: .workflow/project-tech.json
|
||||
6. Read: .workflow/project-guidelines.json
|
||||
|
||||
### Exploration Focus: ${primaryAngle}
|
||||
- Identify relevant files and modules
|
||||
- Discover existing patterns and conventions
|
||||
- Map dependencies and integration points
|
||||
- Note constraints and limitations
|
||||
|
||||
### Phase 1 Output Format
|
||||
|
||||
\`\`\`
|
||||
## EXPLORATION COMPLETE
|
||||
|
||||
### Findings Summary
|
||||
- [Key finding 1]
|
||||
- [Key finding 2]
|
||||
- [Key finding 3]
|
||||
|
||||
### Relevant Files
|
||||
| File | Relevance | Rationale |
|
||||
|------|-----------|-----------|
|
||||
| path/to/file1.ts | 0.9 | [reason] |
|
||||
| path/to/file2.ts | 0.8 | [reason] |
|
||||
|
||||
### Patterns to Follow
|
||||
- [Pattern 1 with code example]
|
||||
- [Pattern 2 with code example]
|
||||
|
||||
### Integration Points
|
||||
- [file:line] - [description]
|
||||
|
||||
### Constraints
|
||||
- [Constraint 1]
|
||||
- [Constraint 2]
|
||||
|
||||
CLARIFICATION_NEEDED:
|
||||
Q1: [question] | Options: [A, B, C] | Recommended: [B]
|
||||
Q2: [question] | Options: [A, B] | Recommended: [A]
|
||||
\`\`\`
|
||||
|
||||
**If no clarification needed**, output:
|
||||
\`\`\`
|
||||
CLARIFICATION_NEEDED: NONE
|
||||
|
||||
Ready for Phase 2. Send "PROCEED_TO_PLANNING" to continue.
|
||||
\`\`\`
|
||||
|
||||
### Write Exploration File
|
||||
Write findings to: ${sessionFolder}/exploration.json
|
||||
`
|
||||
})
|
||||
|
||||
// Step 2: Wait for Phase 1 to complete
|
||||
const phase1Result = wait({ ids: [agent], timeout_ms: 600000 })
|
||||
const phase1Output = phase1Result.status[agent].completed
|
||||
|
||||
// Step 3: Handle clarification (if needed)
|
||||
let clarificationAnswers = null
|
||||
|
||||
if (phase1Output.includes('CLARIFICATION_NEEDED:') && !phase1Output.includes('CLARIFICATION_NEEDED: NONE')) {
|
||||
// Parse questions, collect user answers
|
||||
const questions = parseClarificationQuestions(phase1Output)
|
||||
|
||||
// Display questions to user, collect answers
|
||||
console.log(`
|
||||
## Clarification Needed
|
||||
|
||||
${questions.map((q, i) => `
|
||||
### Q${i+1}: ${q.question}
|
||||
Options: ${q.options.join(', ')}
|
||||
Recommended: ${q.recommended}
|
||||
`).join('\n')}
|
||||
|
||||
**Please provide your answers...**
|
||||
`)
|
||||
|
||||
// Wait for user input...
|
||||
clarificationAnswers = collectUserAnswers(questions)
|
||||
}
|
||||
|
||||
// Step 4: Send Phase 2 instruction (continue with same agent)
|
||||
send_input({
|
||||
id: agent,
|
||||
message: `
|
||||
## PHASE 2: GENERATE PLAN
|
||||
|
||||
${clarificationAnswers ? `
|
||||
### Clarification Answers
|
||||
${clarificationAnswers.map(a => `Q: ${a.question}\nA: ${a.answer}`).join('\n\n')}
|
||||
` : '### No clarification needed - proceeding with exploration findings'}
|
||||
|
||||
### Planning Instructions
|
||||
|
||||
1. **Read Schema**
|
||||
Execute: cat ~/.claude/workflows/cli-templates/schemas/plan-json-schema.json
|
||||
|
||||
2. **Generate Plan** based on your exploration findings
|
||||
- Summary: 2-3 sentence overview
|
||||
- Approach: High-level strategy
|
||||
- Tasks: 2-7 tasks grouped by feature (NOT by file)
|
||||
- Each task needs: id, title, scope, action, description, modification_points, implementation, acceptance, depends_on
|
||||
|
||||
3. **Task Grouping Rules**
|
||||
- Group by feature: All changes for one feature = one task
|
||||
- Substantial tasks: 15-60 minutes of work each
|
||||
- True dependencies only: Use depends_on sparingly
|
||||
- Prefer parallel: Most tasks should be independent
|
||||
|
||||
4. **Write Output**
|
||||
Write: ${sessionFolder}/plan.json
|
||||
|
||||
### Output Format
|
||||
Return brief completion summary after writing plan.json
|
||||
`
|
||||
})
|
||||
|
||||
// Step 5: Wait for Phase 2 to complete
|
||||
const phase2Result = wait({ ids: [agent], timeout_ms: 600000 })
|
||||
|
||||
// Step 6: Cleanup
|
||||
close_agent({ id: agent })
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Phase 3: Confirmation
|
||||
|
||||
```javascript
|
||||
const plan = JSON.parse(Read(`${sessionFolder}/plan.json`))
|
||||
|
||||
console.log(`
|
||||
## Implementation Plan
|
||||
|
||||
**Summary**: ${plan.summary}
|
||||
**Approach**: ${plan.approach}
|
||||
**Complexity**: ${plan.complexity}
|
||||
|
||||
**Tasks** (${plan.tasks.length}):
|
||||
${plan.tasks.map((t, i) => `${i+1}. ${t.title} (${t.scope})`).join('\n')}
|
||||
|
||||
**Estimated Time**: ${plan.estimated_time}
|
||||
|
||||
---
|
||||
|
||||
## Confirmation Required
|
||||
|
||||
Please review the plan above and reply with one of the following:
|
||||
|
||||
- **"Allow"** - Proceed with this plan, output plan.json
|
||||
- **"Modify"** - Describe what changes you want to make
|
||||
- **"Cancel"** - Abort the planning workflow
|
||||
|
||||
**WAITING FOR USER CONFIRMATION...**
|
||||
`)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Codex vs Claude Comparison (for merged mode)
|
||||
|
||||
| Aspect | Claude Code Task | Codex Subagent (Plan-A) |
|
||||
|--------|------------------|------------------------|
|
||||
| **Creation** | `Task({ subagent_type, prompt })` | `spawn_agent({ message: role + task })` |
|
||||
| **Role Loading** | Auto via `subagent_type` | Manual: Agent reads `~/.codex/agents/*.md` |
|
||||
| **Multi-phase** | Separate agents or resume | **Single agent + send_input** |
|
||||
| **Context Retention** | Lossy (serialization) | **Automatic (same conversation)** |
|
||||
| **Follow-up** | `resume` parameter | `send_input({ id, message })` |
|
||||
| **Cleanup** | Automatic | **Explicit `close_agent({ id })`** |
|
||||
|
||||
**Plan-A Advantages**:
|
||||
- Zero context loss between phases
|
||||
- Single agent lifecycle to manage
|
||||
- Minimal overhead for simple tasks
|
||||
|
||||
---
|
||||
|
||||
## Session Folder Structure
|
||||
|
||||
```
|
||||
.workflow/.lite-plan/{task-slug}-{YYYY-MM-DD}/
|
||||
├── exploration.json # Phase 1 output
|
||||
└── plan.json # Phase 2 output (after confirmation)
|
||||
```
|
||||
|
||||
## Workflow States
|
||||
|
||||
| State | Action | Next |
|
||||
|-------|--------|------|
|
||||
| Phase 1 Output | Exploration complete | → Wait for clarification or Phase 2 |
|
||||
| Clarification Output | Questions displayed | → Wait for user reply |
|
||||
| User Replied | Answers received | → send_input to Phase 2 |
|
||||
| Phase 2 Output | Plan generated | → Phase 3 (Confirmation) |
|
||||
| User: "Allow" | Confirmed | → Output complete |
|
||||
| User: "Modify" | Changes requested | → send_input with revisions |
|
||||
| User: "Cancel" | Aborted | → close_agent, end workflow |
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Error | Resolution |
|
||||
|-------|------------|
|
||||
| Phase 1 timeout | Continue wait or send_input to request convergence |
|
||||
| Phase 2 timeout | send_input requesting current progress output |
|
||||
| Agent unexpectedly closed | Re-spawn, paste previous output in message |
|
||||
| User cancels | close_agent, preserve generated files |
|
||||
|
||||
**Execute task**: $TASK
|
||||
@@ -1,489 +0,0 @@
|
||||
---
|
||||
description: Lightweight interactive planning workflow with hybrid mode - multi-agent parallel exploration + primary agent merge/clarify/plan. Supports agent count and iteration control.
|
||||
argument-hint: "TASK=\"<task description or file.md path>\" [--num-agents=<n>] [--max-iterations=<n>] [--angles=role1,role2,...]"
|
||||
---
|
||||
|
||||
# Workflow Lite-Plan-B (Hybrid Mode)
|
||||
|
||||
## Overview
|
||||
|
||||
Hybrid mode for complex planning tasks. Multiple agents explore in parallel from different angles, then the primary agent merges findings, handles clarification, and generates the implementation plan while retaining its exploration context.
|
||||
|
||||
**Core capabilities:**
|
||||
- **Parallel multi-angle exploration** via multiple subagents
|
||||
- **Primary agent reuse** for merge, clarification, and planning (context preserved)
|
||||
- Intelligent deduplication and conflict resolution during merge
|
||||
- Best for High complexity tasks requiring cross-module analysis
|
||||
|
||||
## Applicable Scenarios
|
||||
|
||||
- **High complexity tasks**
|
||||
- Multi-angle parallel exploration required
|
||||
- Cross-module or architecture-level changes
|
||||
- Complex dependencies requiring multiple perspectives
|
||||
|
||||
## Core Advantages
|
||||
|
||||
| Metric | Traditional Separated Mode | Plan-B Hybrid Mode |
|
||||
|--------|---------------------------|-------------------|
|
||||
| Agent creation count | N + 1 (fully independent) | **N → 1** (reuse primary agent) |
|
||||
| Context transfer | Full serialization | **Primary agent retained + incremental merge** |
|
||||
| Merge quality | Simple concatenation | **Intelligent agent merge** |
|
||||
| Planning coherence | Low (new agent) | **High (reuses exploration agent)** |
|
||||
|
||||
## Task Description
|
||||
|
||||
**Target task**: $TASK
|
||||
|
||||
- `--num-agents`: Number of parallel agents (default: 4)
|
||||
- `--max-iterations`: Max iteration rounds
|
||||
- `--angles`: Exploration angles (role1,role2,...)
|
||||
|
||||
## Execution Process
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ Phase 1: Parallel Exploration │
|
||||
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
|
||||
│ │Agent 0 │ │Agent 1 │ │Agent 2 │ │Agent 3 │ │
|
||||
│ │(primary)│ │(explore)│ │(explore)│ │(explore)│ │
|
||||
│ │angle-0 │ │angle-1 │ │angle-2 │ │angle-3 │ │
|
||||
│ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │
|
||||
│ │ │ │ │ │
|
||||
│ └───────────┴───────────┴───────────┘ │
|
||||
│ ↓ │
|
||||
│ wait({ ids: all }) │
|
||||
│ ↓ │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ Phase 2: Merge + Clarify │
|
||||
│ ↓ │
|
||||
│ close(Agent 1, 2, 3) ← close non-primary agents │
|
||||
│ ↓ │
|
||||
│ send_input(Agent 0, { │
|
||||
│ other_explorations: [Agent 1,2,3 results], │
|
||||
│ task: "MERGE + CLARIFY" │
|
||||
│ }) │
|
||||
│ ↓ │
|
||||
│ wait() → get merged results + clarification questions │
|
||||
│ ↓ │
|
||||
│ [Collect user answers] │
|
||||
│ ↓ │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ Phase 3: Planning │
|
||||
│ ↓ │
|
||||
│ send_input(Agent 0, { │
|
||||
│ clarification_answers: [...], │
|
||||
│ task: "GENERATE PLAN" │
|
||||
│ }) │
|
||||
│ ↓ │
|
||||
│ wait() → get plan.json │
|
||||
│ ↓ │
|
||||
│ close(Agent 0) │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Implementation
|
||||
|
||||
### Session Setup
|
||||
|
||||
**Session Setup** (MANDATORY - follow exactly):
|
||||
```javascript
|
||||
// Helper: Get UTC+8 (China Standard Time) ISO string
|
||||
const getUtc8ISOString = () => new Date(Date.now() + 8 * 60 * 60 * 1000).toISOString()
|
||||
|
||||
const taskSlug = "$TASK".toLowerCase().replace(/[^a-z0-9]+/g, '-').substring(0, 40)
|
||||
const dateStr = getUtc8ISOString().substring(0, 10) // Format: 2025-11-29
|
||||
|
||||
const sessionId = `${taskSlug}-${dateStr}` // e.g., "implement-jwt-refresh-2025-11-29"
|
||||
const sessionFolder = `.workflow/.lite-plan/${sessionId}`
|
||||
|
||||
// Create session folder
|
||||
mkdir -p ${sessionFolder}
|
||||
```
|
||||
|
||||
### Complexity Assessment & Multi-Angle Selection
|
||||
|
||||
```javascript
|
||||
const complexity = analyzeTaskComplexity("$TASK")
|
||||
// Plan-B is suitable for High complexity
|
||||
|
||||
const ANGLE_PRESETS = {
|
||||
architecture: ['architecture', 'dependencies', 'modularity', 'integration-points'],
|
||||
security: ['security', 'auth-patterns', 'dataflow', 'validation'],
|
||||
performance: ['performance', 'bottlenecks', 'caching', 'data-access'],
|
||||
bugfix: ['error-handling', 'dataflow', 'state-management', 'edge-cases'],
|
||||
feature: ['patterns', 'integration-points', 'testing', 'dependencies']
|
||||
}
|
||||
|
||||
// Plan-B selects 3-4 angles for parallel exploration
|
||||
const selectedAngles = selectAngles("$TASK", 4) // e.g., ['architecture', 'patterns', 'testing', 'dependencies']
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Phase 1: Parallel Exploration (Primary Agent Has Planning Capability)
|
||||
|
||||
```javascript
|
||||
// ==================== PLAN-B: HYBRID MODE ====================
|
||||
|
||||
// Step 1: Create parallel exploration agents (role files read by agents themselves)
|
||||
// First agent is primary, has merge + planning capability
|
||||
const explorationAgents = selectedAngles.map((angle, index) => {
|
||||
const isPrimary = index === 0
|
||||
|
||||
return spawn_agent({
|
||||
message: `
|
||||
## TASK ASSIGNMENT (Phase 1: Exploration)
|
||||
|
||||
### Task Description
|
||||
${task_description}
|
||||
|
||||
### Your Exploration Angle
|
||||
**Angle**: ${angle}
|
||||
**Index**: ${index + 1} of ${selectedAngles.length}
|
||||
**Output File**: ${sessionFolder}/exploration-${angle}.json
|
||||
${isPrimary ? '\n**Note**: You are the PRIMARY agent. After Phase 1, you will receive other agents\' results for merging and planning.' : ''}
|
||||
|
||||
### MANDATORY FIRST STEPS (Agent Execute)
|
||||
1. **Read explorer role**: ~/.codex/agents/cli-explore-agent.md (MUST read first)
|
||||
${isPrimary ? '2. **Read planner role**: ~/.codex/agents/cli-lite-planning-agent.md (for Phase 2 & 3)\n3.' : '2.'} Run: ccw tool exec get_modules_by_depth '{}'
|
||||
${isPrimary ? '4.' : '3.'} Run: rg -l "{keyword}" --type ts
|
||||
${isPrimary ? '5.' : '4.'} Read: .workflow/project-tech.json
|
||||
${isPrimary ? '6.' : '5.'} Read: .workflow/project-guidelines.json
|
||||
|
||||
### Exploration Focus: ${angle}
|
||||
|
||||
**Structural Analysis**:
|
||||
- Identify modules and files related to ${angle}
|
||||
- Map imports/exports and dependencies
|
||||
- Locate entry points and integration surfaces
|
||||
|
||||
**Semantic Analysis**:
|
||||
- How does existing code handle ${angle} concerns?
|
||||
- What patterns are established for ${angle}?
|
||||
- Where would new code integrate from ${angle} viewpoint?
|
||||
|
||||
### Output Format
|
||||
|
||||
Write to ${sessionFolder}/exploration-${angle}.json:
|
||||
\`\`\`json
|
||||
{
|
||||
"angle": "${angle}",
|
||||
"project_structure": [...],
|
||||
"relevant_files": [
|
||||
{"path": "src/file.ts", "relevance": 0.9, "rationale": "..."}
|
||||
],
|
||||
"patterns": [...],
|
||||
"dependencies": [...],
|
||||
"integration_points": [
|
||||
{"location": "file:line", "description": "..."}
|
||||
],
|
||||
"constraints": [...],
|
||||
"clarification_needs": [
|
||||
{"question": "...", "options": ["A", "B"], "recommended": 0, "context": "..."}
|
||||
],
|
||||
"_metadata": {
|
||||
"exploration_angle": "${angle}",
|
||||
"exploration_index": ${index + 1},
|
||||
"timestamp": "..."
|
||||
}
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
### Return
|
||||
2-3 sentence summary of ${angle} findings
|
||||
`
|
||||
})
|
||||
})
|
||||
|
||||
// Step 2: Batch wait for ALL explorations to complete (KEY ADVANTAGE of Codex)
|
||||
const exploreResults = wait({
|
||||
ids: explorationAgents,
|
||||
timeout_ms: 600000 // 10 minutes
|
||||
})
|
||||
|
||||
// Step 3: Collect all exploration results
|
||||
const allExplorations = selectedAngles.map((angle, index) => ({
|
||||
angle: angle,
|
||||
agentId: explorationAgents[index],
|
||||
result: exploreResults.status[explorationAgents[index]].completed,
|
||||
file: `${sessionFolder}/exploration-${angle}.json`
|
||||
}))
|
||||
|
||||
console.log(`
|
||||
## Phase 1 Complete
|
||||
|
||||
Explorations completed:
|
||||
${allExplorations.map(e => `- ${e.angle}: ${e.result.substring(0, 100)}...`).join('\n')}
|
||||
`)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Phase 2: Merge + Clarify (Reuse Primary Agent)
|
||||
|
||||
```javascript
|
||||
// Step 4: Close non-primary agents, keep primary agent (index=0)
|
||||
const primaryAgent = explorationAgents[0]
|
||||
const primaryAngle = selectedAngles[0]
|
||||
|
||||
explorationAgents.slice(1).forEach(id => close_agent({ id }))
|
||||
|
||||
// Step 5: Send merge task to primary agent
|
||||
send_input({
|
||||
id: primaryAgent,
|
||||
message: `
|
||||
## PHASE 2: MERGE + CLARIFY
|
||||
|
||||
You are now in **Merger** role. Combine your ${primaryAngle} findings with other explorations below.
|
||||
|
||||
### Other Explorations to Merge
|
||||
|
||||
${allExplorations.slice(1).map(e => `
|
||||
#### ${e.angle} Exploration
|
||||
**File**: ${e.file}
|
||||
**Summary**: ${e.result}
|
||||
|
||||
Read the full exploration: Read("${e.file}")
|
||||
`).join('\n')}
|
||||
|
||||
### Merge Instructions
|
||||
|
||||
1. **Read All Exploration Files**
|
||||
${allExplorations.map(e => `- Read("${e.file}")`).join('\n ')}
|
||||
|
||||
2. **Consolidate Findings**
|
||||
- **relevant_files**: Deduplicate, keep highest relevance score for each file
|
||||
- **patterns**: Merge unique patterns, note which angle discovered each
|
||||
- **integration_points**: Combine all, group by module
|
||||
- **constraints**: Merge and categorize (hard vs soft constraints)
|
||||
- **clarification_needs**: Deduplicate similar questions
|
||||
|
||||
3. **Write Merged Exploration**
|
||||
Write to: ${sessionFolder}/exploration-merged.json
|
||||
|
||||
4. **Output Clarification Questions**
|
||||
|
||||
Format:
|
||||
\`\`\`
|
||||
MERGED_EXPLORATION_COMPLETE
|
||||
|
||||
Files consolidated: [count]
|
||||
Patterns identified: [count]
|
||||
Integration points: [count]
|
||||
|
||||
CLARIFICATION_NEEDED:
|
||||
Q1: [merged question] | Options: [A, B, C] | Recommended: [X] | Source: [angles]
|
||||
Q2: [merged question] | Options: [A, B] | Recommended: [Y] | Source: [angles]
|
||||
\`\`\`
|
||||
|
||||
If no clarification needed:
|
||||
\`\`\`
|
||||
CLARIFICATION_NEEDED: NONE
|
||||
|
||||
Ready for Phase 3 (Planning). Send clarification answers or "PROCEED_TO_PLANNING".
|
||||
\`\`\`
|
||||
`
|
||||
})
|
||||
|
||||
// Step 6: Wait for merge result
|
||||
const mergeResult = wait({ ids: [primaryAgent], timeout_ms: 300000 })
|
||||
const mergeOutput = mergeResult.status[primaryAgent].completed
|
||||
|
||||
// Step 7: Handle clarification
|
||||
let clarificationAnswers = null
|
||||
|
||||
if (mergeOutput.includes('CLARIFICATION_NEEDED:') && !mergeOutput.includes('CLARIFICATION_NEEDED: NONE')) {
|
||||
const questions = parseClarificationQuestions(mergeOutput)
|
||||
|
||||
console.log(`
|
||||
## Clarification Needed (Merged from ${selectedAngles.length} angles)
|
||||
|
||||
${questions.map((q, i) => `
|
||||
### Q${i+1}: ${q.question}
|
||||
Options: ${q.options.join(', ')}
|
||||
Recommended: ${q.recommended}
|
||||
Source angles: ${q.source}
|
||||
`).join('\n')}
|
||||
|
||||
**Please provide your answers...**
|
||||
`)
|
||||
|
||||
clarificationAnswers = collectUserAnswers(questions)
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Phase 3: Planning (Continue Reusing Primary Agent)
|
||||
|
||||
```javascript
|
||||
// Step 8: Send planning task
|
||||
send_input({
|
||||
id: primaryAgent,
|
||||
message: `
|
||||
## PHASE 3: GENERATE PLAN
|
||||
|
||||
You are now in **Planner** role. Generate implementation plan based on merged explorations.
|
||||
|
||||
${clarificationAnswers ? `
|
||||
### Clarification Answers
|
||||
${clarificationAnswers.map(a => `Q: ${a.question}\nA: ${a.answer}`).join('\n\n')}
|
||||
` : '### No clarification needed'}
|
||||
|
||||
### Planning Instructions
|
||||
|
||||
1. **Read Schema**
|
||||
Execute: cat ~/.claude/workflows/cli-templates/schemas/plan-json-schema.json
|
||||
|
||||
2. **Read Merged Exploration**
|
||||
Read: ${sessionFolder}/exploration-merged.json
|
||||
|
||||
3. **Generate Plan**
|
||||
Based on consolidated findings from ${selectedAngles.length} exploration angles:
|
||||
- ${selectedAngles.join('\n - ')}
|
||||
|
||||
4. **Plan Requirements**
|
||||
- Summary: 2-3 sentence overview
|
||||
- Approach: High-level strategy referencing multiple angles
|
||||
- Tasks: 2-7 tasks grouped by feature (NOT by file)
|
||||
- Each task: id, title, scope, action, description, modification_points, implementation, acceptance, depends_on
|
||||
- Reference exploration angles in task descriptions
|
||||
|
||||
5. **Task Grouping Rules**
|
||||
- Group by feature: All changes for one feature = one task (even if spanning angles)
|
||||
- Substantial tasks: 15-60 minutes each
|
||||
- True dependencies only
|
||||
- Prefer parallel execution
|
||||
|
||||
6. **Write Output**
|
||||
Write: ${sessionFolder}/plan.json
|
||||
|
||||
### Metadata
|
||||
Include in _metadata:
|
||||
- exploration_angles: ${JSON.stringify(selectedAngles)}
|
||||
- planning_mode: "merged-multi-angle"
|
||||
- source_explorations: ${allExplorations.length}
|
||||
|
||||
### Return
|
||||
Brief completion summary
|
||||
`
|
||||
})
|
||||
|
||||
// Step 9: Wait for planning to complete
|
||||
const planResult = wait({ ids: [primaryAgent], timeout_ms: 600000 })
|
||||
|
||||
// Step 10: Final cleanup
|
||||
close_agent({ id: primaryAgent })
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Phase 4: Confirmation
|
||||
|
||||
```javascript
|
||||
const plan = JSON.parse(Read(`${sessionFolder}/plan.json`))
|
||||
|
||||
console.log(`
|
||||
## Implementation Plan (Multi-Angle: ${selectedAngles.join(', ')})
|
||||
|
||||
**Summary**: ${plan.summary}
|
||||
**Approach**: ${plan.approach}
|
||||
**Complexity**: ${plan.complexity}
|
||||
|
||||
**Tasks** (${plan.tasks.length}):
|
||||
${plan.tasks.map((t, i) => `${i+1}. ${t.title} (${t.scope})`).join('\n')}
|
||||
|
||||
**Estimated Time**: ${plan.estimated_time}
|
||||
**Exploration Angles**: ${plan._metadata.exploration_angles.join(', ')}
|
||||
|
||||
---
|
||||
|
||||
## Confirmation Required
|
||||
|
||||
Please review the plan above and reply with one of the following:
|
||||
|
||||
- **"Allow"** - Confirm and finalize plan.json
|
||||
- **"Modify"** - Describe what changes you want to make
|
||||
- **"Cancel"** - Abort the planning workflow
|
||||
|
||||
**WAITING FOR USER CONFIRMATION...**
|
||||
`)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Codex vs Claude Comparison (for hybrid mode)
|
||||
|
||||
| Aspect | Claude Code Task | Codex Subagent (Plan-B) |
|
||||
|--------|------------------|------------------------|
|
||||
| **Creation** | `Task({ subagent_type, prompt })` | `spawn_agent({ message: role + task })` |
|
||||
| **Role Loading** | Auto via `subagent_type` | Manual: Agent reads `~/.codex/agents/*.md` |
|
||||
| **Parallel Wait** | Multiple `Task()` calls | **Batch `wait({ ids: [...] })`** |
|
||||
| **Result Retrieval** | Sync return or `TaskOutput` | `wait({ ids }).status[id].completed` |
|
||||
| **Agent Reuse** | `resume` parameter | **`send_input` to continue** |
|
||||
| **Cleanup** | Automatic | **Explicit `close_agent({ id })`** |
|
||||
|
||||
**Plan-B Advantages**:
|
||||
- True parallel exploration with batch `wait`
|
||||
- Primary agent retains context across all phases
|
||||
- Fine-grained lifecycle control
|
||||
|
||||
---
|
||||
|
||||
## Agent Lifecycle Comparison
|
||||
|
||||
```
|
||||
Traditional Mode:
|
||||
Agent 1 ──────● close
|
||||
Agent 2 ──────● close
|
||||
Agent 3 ──────● close
|
||||
Agent 4 ──────● close
|
||||
Planning Agent ────────────● close
|
||||
|
||||
Plan-B Hybrid Mode:
|
||||
Agent 0 ─────────────────────────────────● close (reused until end)
|
||||
Agent 1 ──────● close
|
||||
Agent 2 ──────● close
|
||||
Agent 3 ──────● close
|
||||
↑ ↑ ↑
|
||||
Phase1 Phase2 Phase3
|
||||
(parallel) (merge+clarify) (planning)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Session Folder Structure
|
||||
|
||||
```
|
||||
.workflow/.lite-plan/{task-slug}-{YYYY-MM-DD}/
|
||||
├── exploration-architecture.json # Angle 1 (primary agent)
|
||||
├── exploration-patterns.json # Angle 2
|
||||
├── exploration-testing.json # Angle 3
|
||||
├── exploration-dependencies.json # Angle 4
|
||||
├── exploration-merged.json # Merged by primary agent
|
||||
└── plan.json # Final plan
|
||||
```
|
||||
|
||||
## Workflow States
|
||||
|
||||
| State | Action | Next |
|
||||
|-------|--------|------|
|
||||
| Phase 1 Complete | All explorations done | → Phase 2 (Merge) |
|
||||
| Phase 2 Output | Merged + questions | → Wait for user reply |
|
||||
| User Replied | Answers received | → send_input to Phase 3 |
|
||||
| Phase 3 Output | Plan generated | → Phase 4 (Confirmation) |
|
||||
| User: "Allow" | Confirmed | → Output complete |
|
||||
| User: "Modify" | Changes requested | → send_input with revisions |
|
||||
| User: "Cancel" | Aborted | → close all agents, end workflow |
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Error | Resolution |
|
||||
|-------|------------|
|
||||
| Partial exploration timeout | Use completed results, note missing angles in merge |
|
||||
| Primary agent unexpectedly closed | Re-spawn, paste existing exploration results in message |
|
||||
| Merge phase timeout | send_input to request current merge progress |
|
||||
| Planning phase timeout | send_input requesting partial plan output |
|
||||
|
||||
**Execute task**: $TASK
|
||||
@@ -1,605 +0,0 @@
|
||||
---
|
||||
description: Lightweight interactive planning workflow with Codex subagent orchestration, outputs plan.json after user confirmation. Supports depth and exploration control.
|
||||
argument-hint: "TASK=\"<description or file.md path>\" [--depth=standard|deep] [--explore] [--auto]"
|
||||
---
|
||||
|
||||
# Workflow Lite-Plan Command (Codex Subagent Version)
|
||||
|
||||
## Overview
|
||||
|
||||
Intelligent lightweight planning command with dynamic workflow adaptation based on task complexity. Uses Codex subagent API for parallel exploration and planning phases.
|
||||
|
||||
**Core capabilities:**
|
||||
- Intelligent task analysis with automatic exploration detection
|
||||
- **Parallel code exploration via Codex subagents** (spawn_agent + batch wait)
|
||||
- Interactive clarification after exploration to gather missing information
|
||||
- Adaptive planning: Low complexity → Direct; Medium/High → cli-lite-planning-agent subagent
|
||||
- Two-step confirmation: plan display → user approval
|
||||
- Outputs plan.json file after user confirmation
|
||||
|
||||
## Task Description
|
||||
|
||||
**Target task**: $TASK
|
||||
**Force exploration**: $EXPLORE
|
||||
|
||||
- `--depth`: Exploration depth (standard|deep)
|
||||
- `--explore`: Force exploration phase
|
||||
- `--auto`: Auto mode, skip confirmation
|
||||
|
||||
## Execution Process
|
||||
|
||||
```
|
||||
Phase 1: Task Analysis & Exploration (Subagent Orchestration)
|
||||
├─ Parse input (description or .md file)
|
||||
├─ Intelligent complexity assessment (Low/Medium/High)
|
||||
├─ Exploration decision (auto-detect or EXPLORE="true")
|
||||
└─ Decision:
|
||||
├─ needsExploration=true → Spawn parallel cli-explore-agent subagents
|
||||
└─ needsExploration=false → Skip to Phase 2/3
|
||||
|
||||
Phase 2: Clarification (optional)
|
||||
├─ Aggregate clarification needs from exploration results
|
||||
├─ Output questions to user
|
||||
└─ STOP and wait for user reply
|
||||
|
||||
Phase 3: Planning (NO CODE EXECUTION - planning only)
|
||||
└─ Decision (based on complexity):
|
||||
├─ Low → Direct planning following schema
|
||||
└─ Medium/High → Spawn cli-lite-planning-agent subagent → plan.json
|
||||
|
||||
Phase 4: Confirmation
|
||||
├─ Display plan summary (tasks, complexity, estimated time)
|
||||
├─ Output confirmation request
|
||||
└─ STOP and wait for user approval
|
||||
|
||||
Phase 5: Output
|
||||
└─ Write plan.json to session folder
|
||||
```
|
||||
|
||||
## Implementation
|
||||
|
||||
### Phase 1: Intelligent Multi-Angle Exploration (Subagent Orchestration)
|
||||
|
||||
**Session Setup** (MANDATORY - follow exactly):
|
||||
```javascript
|
||||
// Helper: Get UTC+8 (China Standard Time) ISO string
|
||||
const getUtc8ISOString = () => new Date(Date.now() + 8 * 60 * 60 * 1000).toISOString()
|
||||
|
||||
const taskSlug = "$TASK".toLowerCase().replace(/[^a-z0-9]+/g, '-').substring(0, 40)
|
||||
const dateStr = getUtc8ISOString().substring(0, 10) // Format: 2025-11-29
|
||||
|
||||
const sessionId = `${taskSlug}-${dateStr}` // e.g., "implement-jwt-refresh-2025-11-29"
|
||||
const sessionFolder = `.workflow/.lite-plan/${sessionId}`
|
||||
|
||||
// Create session folder
|
||||
mkdir -p ${sessionFolder}
|
||||
```
|
||||
|
||||
**Exploration Decision Logic**:
|
||||
```javascript
|
||||
needsExploration = (
|
||||
"$EXPLORE" === "true" ||
|
||||
task.mentions_specific_files ||
|
||||
task.requires_codebase_context ||
|
||||
task.needs_architecture_understanding ||
|
||||
task.modifies_existing_code
|
||||
)
|
||||
|
||||
if (!needsExploration) {
|
||||
// Skip to Phase 2 (Clarification) or Phase 3 (Planning)
|
||||
proceed_to_next_phase()
|
||||
}
|
||||
```
|
||||
|
||||
**Context Protection**: File reading >=50k chars → force `needsExploration=true`
|
||||
|
||||
**Complexity Assessment** (Intelligent Analysis):
|
||||
```javascript
|
||||
// Analyzes task complexity based on:
|
||||
// - Scope: How many systems/modules are affected?
|
||||
// - Depth: Surface change vs architectural impact?
|
||||
// - Risk: Potential for breaking existing functionality?
|
||||
// - Dependencies: How interconnected is the change?
|
||||
|
||||
const complexity = analyzeTaskComplexity("$TASK")
|
||||
// Returns: 'Low' | 'Medium' | 'High'
|
||||
|
||||
// Angle assignment based on task type
|
||||
const ANGLE_PRESETS = {
|
||||
architecture: ['architecture', 'dependencies', 'modularity', 'integration-points'],
|
||||
security: ['security', 'auth-patterns', 'dataflow', 'validation'],
|
||||
performance: ['performance', 'bottlenecks', 'caching', 'data-access'],
|
||||
bugfix: ['error-handling', 'dataflow', 'state-management', 'edge-cases'],
|
||||
feature: ['patterns', 'integration-points', 'testing', 'dependencies']
|
||||
}
|
||||
|
||||
function selectAngles(taskDescription, count) {
|
||||
const text = taskDescription.toLowerCase()
|
||||
let preset = 'feature' // default
|
||||
|
||||
if (/refactor|architect|restructure|modular/.test(text)) preset = 'architecture'
|
||||
else if (/security|auth|permission|access/.test(text)) preset = 'security'
|
||||
else if (/performance|slow|optimi|cache/.test(text)) preset = 'performance'
|
||||
else if (/fix|bug|error|issue|broken/.test(text)) preset = 'bugfix'
|
||||
|
||||
return ANGLE_PRESETS[preset].slice(0, count)
|
||||
}
|
||||
|
||||
const selectedAngles = selectAngles("$TASK", complexity === 'High' ? 4 : (complexity === 'Medium' ? 3 : 1))
|
||||
|
||||
console.log(`
|
||||
## Exploration Plan
|
||||
|
||||
Task Complexity: ${complexity}
|
||||
Selected Angles: ${selectedAngles.join(', ')}
|
||||
|
||||
Launching ${selectedAngles.length} parallel subagent explorations...
|
||||
`)
|
||||
```
|
||||
|
||||
**Launch Parallel Exploration Subagents** (Codex Pattern):
|
||||
|
||||
```javascript
|
||||
// ==================== CODEX SUBAGENT PATTERN ====================
|
||||
|
||||
// Step 1: Spawn parallel exploration subagents (角色文件由 agent 自己读取)
|
||||
const explorationAgents = selectedAngles.map((angle, index) => {
|
||||
return spawn_agent({
|
||||
message: `
|
||||
## TASK ASSIGNMENT
|
||||
|
||||
### Task Objective
|
||||
Execute **${angle}** exploration for task planning context. Analyze codebase from this specific angle to discover relevant structure, patterns, and constraints.
|
||||
|
||||
### Assigned Context
|
||||
- **Exploration Angle**: ${angle}
|
||||
- **Task Description**: $TASK
|
||||
- **Exploration Index**: ${index + 1} of ${selectedAngles.length}
|
||||
- **Output File**: ${sessionFolder}/exploration-${angle}.json
|
||||
|
||||
### MANDATORY FIRST STEPS (Agent Execute)
|
||||
1. **Read role definition**: ~/.codex/agents/cli-explore-agent.md (MUST read first)
|
||||
2. Run: ccw tool exec get_modules_by_depth '{}' (project structure)
|
||||
3. Run: rg -l "{keyword_from_task}" --type ts (locate relevant files)
|
||||
4. Execute: cat ~/.claude/workflows/cli-templates/schemas/explore-json-schema.json (get output schema reference)
|
||||
5. Read: .workflow/project-tech.json (technology stack and architecture context)
|
||||
6. Read: .workflow/project-guidelines.json (user-defined constraints and conventions)
|
||||
|
||||
### Exploration Strategy (${angle} focus)
|
||||
|
||||
**Step 1: Structural Scan** (Bash)
|
||||
- get_modules_by_depth.sh → identify modules related to ${angle}
|
||||
- find/rg → locate files relevant to ${angle} aspect
|
||||
- Analyze imports/dependencies from ${angle} perspective
|
||||
|
||||
**Step 2: Semantic Analysis** (Gemini CLI)
|
||||
- How does existing code handle ${angle} concerns?
|
||||
- What patterns are used for ${angle}?
|
||||
- Where would new code integrate from ${angle} viewpoint?
|
||||
|
||||
**Step 3: Write Output**
|
||||
- Consolidate ${angle} findings into JSON
|
||||
- Identify ${angle}-specific clarification needs
|
||||
|
||||
### Expected Output
|
||||
|
||||
**File**: ${sessionFolder}/exploration-${angle}.json
|
||||
|
||||
**Schema Reference**: Schema obtained in MANDATORY FIRST STEPS step 3, follow schema exactly
|
||||
|
||||
**Required Fields** (all ${angle} focused):
|
||||
- project_structure: Modules/architecture relevant to ${angle}
|
||||
- relevant_files: Files affected from ${angle} perspective
|
||||
**IMPORTANT**: Use object format with relevance scores:
|
||||
\`[{path: "src/file.ts", relevance: 0.85, rationale: "Core ${angle} logic"}]\`
|
||||
- patterns: ${angle}-related patterns to follow
|
||||
- dependencies: Dependencies relevant to ${angle}
|
||||
- integration_points: Where to integrate from ${angle} viewpoint (include file:line locations)
|
||||
- constraints: ${angle}-specific limitations/conventions
|
||||
- clarification_needs: ${angle}-related ambiguities (options array + recommended index)
|
||||
- _metadata.exploration_angle: "${angle}"
|
||||
|
||||
### Success Criteria
|
||||
- [ ] Schema obtained via cat explore-json-schema.json
|
||||
- [ ] get_modules_by_depth.sh executed
|
||||
- [ ] At least 3 relevant files identified with ${angle} rationale
|
||||
- [ ] Patterns are actionable (code examples, not generic advice)
|
||||
- [ ] Integration points include file:line locations
|
||||
- [ ] JSON output follows schema exactly
|
||||
- [ ] clarification_needs includes options + recommended
|
||||
|
||||
### Deliverables
|
||||
Write: ${sessionFolder}/exploration-${angle}.json
|
||||
Return: 2-3 sentence summary of ${angle} findings
|
||||
`
|
||||
})
|
||||
})
|
||||
|
||||
// Step 3: Batch wait for ALL exploration subagents (KEY ADVANTAGE of Codex)
|
||||
const explorationResults = wait({
|
||||
ids: explorationAgents,
|
||||
timeout_ms: 600000 // 10 minutes
|
||||
})
|
||||
|
||||
// Step 4: Handle timeout
|
||||
if (explorationResults.timed_out) {
|
||||
console.log('部分探索超时,继续使用已完成结果')
|
||||
}
|
||||
|
||||
// Step 5: Collect results from completed agents
|
||||
const completedExplorations = {}
|
||||
explorationAgents.forEach((agentId, index) => {
|
||||
const angle = selectedAngles[index]
|
||||
if (explorationResults.status[agentId].completed) {
|
||||
completedExplorations[angle] = explorationResults.status[agentId].completed
|
||||
}
|
||||
})
|
||||
|
||||
// Step 6: Cleanup - close all exploration agents
|
||||
explorationAgents.forEach(id => close_agent({ id }))
|
||||
```
|
||||
|
||||
**Build Exploration Manifest**:
|
||||
```javascript
|
||||
// After all explorations complete, auto-discover all exploration-*.json files
|
||||
const explorationFiles = find(`${sessionFolder}`, "-name", "exploration-*.json")
|
||||
|
||||
const explorationManifest = {
|
||||
session_id: sessionId,
|
||||
task_description: "$TASK",
|
||||
timestamp: getUtc8ISOString(),
|
||||
complexity: complexity,
|
||||
exploration_count: selectedAngles.length,
|
||||
explorations: explorationFiles.map(file => {
|
||||
const data = JSON.parse(Read(file))
|
||||
return {
|
||||
angle: data._metadata.exploration_angle,
|
||||
file: path.basename(file),
|
||||
path: file,
|
||||
index: data._metadata.exploration_index
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
Write(`${sessionFolder}/explorations-manifest.json`, JSON.stringify(explorationManifest, null, 2))
|
||||
|
||||
console.log(`
|
||||
## Exploration Complete
|
||||
|
||||
Generated exploration files in ${sessionFolder}:
|
||||
${explorationManifest.explorations.map(e => `- exploration-${e.angle}.json (angle: ${e.angle})`).join('\n')}
|
||||
|
||||
Manifest: explorations-manifest.json
|
||||
Angles explored: ${explorationManifest.explorations.map(e => e.angle).join(', ')}
|
||||
`)
|
||||
```
|
||||
|
||||
**Output**:
|
||||
- `${sessionFolder}/exploration-{angle1}.json`
|
||||
- `${sessionFolder}/exploration-{angle2}.json`
|
||||
- ... (1-4 files based on complexity)
|
||||
- `${sessionFolder}/explorations-manifest.json`
|
||||
|
||||
---
|
||||
|
||||
### Phase 2: Clarification (Optional)
|
||||
|
||||
**Skip if**: No exploration or `clarification_needs` is empty across all explorations
|
||||
|
||||
**Aggregate clarification needs from all exploration angles**:
|
||||
```javascript
|
||||
// Load manifest and all exploration files
|
||||
const manifest = JSON.parse(Read(`${sessionFolder}/explorations-manifest.json`))
|
||||
const explorations = manifest.explorations.map(exp => ({
|
||||
angle: exp.angle,
|
||||
data: JSON.parse(Read(exp.path))
|
||||
}))
|
||||
|
||||
// Aggregate clarification needs from all explorations
|
||||
const allClarifications = []
|
||||
explorations.forEach(exp => {
|
||||
if (exp.data.clarification_needs?.length > 0) {
|
||||
exp.data.clarification_needs.forEach(need => {
|
||||
allClarifications.push({
|
||||
...need,
|
||||
source_angle: exp.angle
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// Intelligent deduplication: analyze allClarifications by intent
|
||||
const dedupedClarifications = intelligentMerge(allClarifications)
|
||||
```
|
||||
|
||||
**Output Questions and Wait for User Reply**:
|
||||
```javascript
|
||||
if (dedupedClarifications.length > 0) {
|
||||
console.log(`
|
||||
## Clarification Needed
|
||||
|
||||
Based on exploration, the following questions need your input:
|
||||
|
||||
${dedupedClarifications.map((need, index) => `
|
||||
### Question ${index + 1}: [${need.source_angle}]
|
||||
|
||||
**${need.question}**
|
||||
|
||||
Context: ${need.context}
|
||||
|
||||
Options:
|
||||
${need.options.map((opt, i) => ` ${i + 1}. ${opt}${need.recommended === i ? ' ★ (Recommended)' : ''}`).join('\n')}
|
||||
`).join('\n')}
|
||||
|
||||
---
|
||||
|
||||
**Please reply with your choices** (e.g., "Q1: 2, Q2: 1, Q3: 3") to continue planning.
|
||||
|
||||
**WAITING FOR USER INPUT...**
|
||||
`)
|
||||
|
||||
// STOP HERE - Wait for user reply before continuing to Phase 3
|
||||
return
|
||||
}
|
||||
```
|
||||
|
||||
**After User Reply**: Store responses in `clarificationContext` and proceed to Phase 3.
|
||||
|
||||
---
|
||||
|
||||
### Phase 3: Planning
|
||||
|
||||
**IMPORTANT**: Phase 3 is **planning only** - NO code execution.
|
||||
|
||||
**Planning Strategy Selection** (based on Phase 1 complexity):
|
||||
|
||||
**Low Complexity** - Direct Planning:
|
||||
```javascript
|
||||
// Step 1: Read schema
|
||||
const schema = Read("~/.claude/workflows/cli-templates/schemas/plan-json-schema.json")
|
||||
|
||||
// Step 2: Read all exploration files for context
|
||||
const manifest = JSON.parse(Read(`${sessionFolder}/explorations-manifest.json`))
|
||||
manifest.explorations.forEach(exp => {
|
||||
const explorationData = Read(exp.path)
|
||||
console.log(`\n### Exploration: ${exp.angle}\n${explorationData}`)
|
||||
})
|
||||
|
||||
// Step 3: Generate plan following schema (direct, no subagent)
|
||||
const plan = {
|
||||
summary: "Brief description of what will be implemented",
|
||||
approach: "High-level approach and strategy",
|
||||
tasks: [
|
||||
// Each task: { id, title, description, scope, files, depends_on, execution_group, complexity }
|
||||
// Group by feature/module, NOT by file
|
||||
// 2-7 tasks recommended
|
||||
],
|
||||
estimated_time: "Total estimated time",
|
||||
complexity: complexity,
|
||||
_metadata: {
|
||||
timestamp: getUtc8ISOString(),
|
||||
source: "lite-plan",
|
||||
planning_mode: "direct",
|
||||
exploration_angles: manifest.explorations.map(e => e.angle)
|
||||
}
|
||||
}
|
||||
|
||||
// Step 4: Write plan
|
||||
Write(`${sessionFolder}/plan.json`, JSON.stringify(plan, null, 2))
|
||||
|
||||
// Step 5: Proceed to Phase 4 (Confirmation)
|
||||
```
|
||||
|
||||
**Medium/High Complexity** - Spawn cli-lite-planning-agent Subagent:
|
||||
|
||||
```javascript
|
||||
// ==================== CODEX SUBAGENT PATTERN ====================
|
||||
|
||||
// Step 1: Create planning subagent (角色文件由 agent 自己读取)
|
||||
const planningAgent = spawn_agent({
|
||||
message: `
|
||||
## TASK ASSIGNMENT
|
||||
|
||||
### Objective
|
||||
Generate implementation plan and write plan.json.
|
||||
|
||||
### MANDATORY FIRST STEPS (Agent Execute)
|
||||
1. **Read role definition**: ~/.codex/agents/cli-lite-planning-agent.md (MUST read first)
|
||||
2. Execute: cat ~/.claude/workflows/cli-templates/schemas/plan-json-schema.json (get schema reference)
|
||||
3. Read: .workflow/project-tech.json (technology stack, architecture, key components)
|
||||
4. Read: .workflow/project-guidelines.json (user-defined constraints and conventions)
|
||||
|
||||
**CRITICAL**: All generated tasks MUST comply with constraints in project-guidelines.json
|
||||
|
||||
### Task Description
|
||||
$TASK
|
||||
|
||||
### Multi-Angle Exploration Context
|
||||
|
||||
${manifest.explorations.map(exp => `#### Exploration: ${exp.angle} (${exp.file})
|
||||
Path: ${exp.path}
|
||||
|
||||
Read this file for detailed ${exp.angle} analysis.`).join('\n\n')}
|
||||
|
||||
Total explorations: ${manifest.exploration_count}
|
||||
Angles covered: ${manifest.explorations.map(e => e.angle).join(', ')}
|
||||
|
||||
Manifest: ${sessionFolder}/explorations-manifest.json
|
||||
|
||||
### User Clarifications
|
||||
${JSON.stringify(clarificationContext) || "None"}
|
||||
|
||||
### Complexity Level
|
||||
${complexity}
|
||||
|
||||
### Requirements
|
||||
Generate plan.json following the schema obtained above. Key constraints:
|
||||
- tasks: 2-7 structured tasks (**group by feature/module, NOT by file**)
|
||||
- _metadata.exploration_angles: ${JSON.stringify(manifest.explorations.map(e => e.angle))}
|
||||
|
||||
### Task Grouping Rules
|
||||
1. **Group by feature**: All changes for one feature = one task (even if 3-5 files)
|
||||
2. **Group by context**: Tasks with similar context or related functional changes can be grouped together
|
||||
3. **Minimize agent count**: Simple, unrelated tasks can also be grouped to reduce agent execution overhead
|
||||
4. **Avoid file-per-task**: Do NOT create separate tasks for each file
|
||||
5. **Substantial tasks**: Each task should represent 15-60 minutes of work
|
||||
6. **True dependencies only**: Only use depends_on when Task B cannot start without Task A's output
|
||||
7. **Prefer parallel**: Most tasks should be independent (no depends_on)
|
||||
|
||||
### Execution
|
||||
1. Read schema file (cat command above)
|
||||
2. Execute CLI planning using Gemini (Qwen fallback)
|
||||
3. Read ALL exploration files for comprehensive context
|
||||
4. Synthesize findings and generate plan following schema
|
||||
5. Write JSON: Write('${sessionFolder}/plan.json', jsonContent)
|
||||
6. Return brief completion summary
|
||||
|
||||
### Deliverables
|
||||
Write: ${sessionFolder}/plan.json
|
||||
Return: Brief plan summary
|
||||
`
|
||||
})
|
||||
|
||||
// Step 3: Wait for planning subagent to complete
|
||||
const planResult = wait({
|
||||
ids: [planningAgent],
|
||||
timeout_ms: 900000 // 15 minutes
|
||||
})
|
||||
|
||||
// Step 4: Cleanup
|
||||
close_agent({ id: planningAgent })
|
||||
```
|
||||
|
||||
**Output**: `${sessionFolder}/plan.json`
|
||||
|
||||
---
|
||||
|
||||
### Phase 4: Task Confirmation
|
||||
|
||||
**Display Plan Summary**:
|
||||
```javascript
|
||||
const plan = JSON.parse(Read(`${sessionFolder}/plan.json`))
|
||||
|
||||
console.log(`
|
||||
## Implementation Plan
|
||||
|
||||
**Summary**: ${plan.summary}
|
||||
**Approach**: ${plan.approach}
|
||||
|
||||
**Tasks** (${plan.tasks.length}):
|
||||
${plan.tasks.map((t, i) => `
|
||||
### Task ${i+1}: ${t.title}
|
||||
- **Description**: ${t.description}
|
||||
- **Scope**: ${t.scope}
|
||||
- **Files**: ${t.files?.join(', ') || 'N/A'}
|
||||
- **Complexity**: ${t.complexity}
|
||||
- **Dependencies**: ${t.depends_on?.join(', ') || 'None'}
|
||||
`).join('\n')}
|
||||
|
||||
**Overall Complexity**: ${plan.complexity}
|
||||
**Estimated Time**: ${plan.estimated_time}
|
||||
|
||||
---
|
||||
|
||||
## Confirmation Required
|
||||
|
||||
Please review the plan above and reply with one of the following:
|
||||
|
||||
- **"Allow"** - Proceed with this plan, output plan.json
|
||||
- **"Modify"** - Describe what changes you want to make
|
||||
- **"Cancel"** - Abort the planning workflow
|
||||
|
||||
**WAITING FOR USER CONFIRMATION...**
|
||||
`)
|
||||
|
||||
// STOP HERE - Wait for user confirmation before writing plan.json
|
||||
return
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Phase 5: Output Plan File
|
||||
|
||||
**After User Confirms "Allow"**:
|
||||
```javascript
|
||||
// Final plan.json already written in Phase 3
|
||||
console.log(`
|
||||
## Plan Output Complete
|
||||
|
||||
**Plan file written**: ${sessionFolder}/plan.json
|
||||
|
||||
**Session folder**: ${sessionFolder}
|
||||
|
||||
**Contents**:
|
||||
- explorations-manifest.json
|
||||
${manifest.explorations.map(e => `- exploration-${e.angle}.json`).join('\n')}
|
||||
- plan.json
|
||||
|
||||
---
|
||||
|
||||
You can now use this plan with your preferred execution method:
|
||||
- Manual implementation following the tasks
|
||||
- Pass to another tool/agent for execution
|
||||
- Import into project management system
|
||||
`)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Codex vs Claude Comparison (for this workflow)
|
||||
|
||||
| Aspect | Claude Code Task | Codex Subagent |
|
||||
|--------|------------------|----------------|
|
||||
| **Creation** | `Task({ subagent_type, prompt })` | `spawn_agent({ message: role + task })` |
|
||||
| **Role Loading** | Auto via `subagent_type` | Manual: Read `~/.codex/agents/*.md` |
|
||||
| **Parallel Wait** | Multiple `Task()` calls | **Batch `wait({ ids: [...] })`** |
|
||||
| **Result Retrieval** | Sync return or `TaskOutput` | `wait({ ids }).status[id].completed` |
|
||||
| **Follow-up** | `resume` parameter | `send_input({ id, message })` |
|
||||
| **Cleanup** | Automatic | **Explicit `close_agent({ id })`** |
|
||||
|
||||
**Codex Advantages for lite-plan**:
|
||||
- True parallel exploration with batch `wait`
|
||||
- Fine-grained lifecycle control
|
||||
- Efficient multi-agent coordination
|
||||
|
||||
---
|
||||
|
||||
## Session Folder Structure
|
||||
|
||||
```
|
||||
.workflow/.lite-plan/{task-slug}-{YYYY-MM-DD}/
|
||||
├── exploration-{angle1}.json # Exploration angle 1
|
||||
├── exploration-{angle2}.json # Exploration angle 2
|
||||
├── exploration-{angle3}.json # Exploration angle 3 (if applicable)
|
||||
├── exploration-{angle4}.json # Exploration angle 4 (if applicable)
|
||||
├── explorations-manifest.json # Exploration index
|
||||
└── plan.json # Implementation plan (after confirmation)
|
||||
```
|
||||
|
||||
## Workflow States
|
||||
|
||||
| State | Action | Next |
|
||||
|-------|--------|------|
|
||||
| Phase 1 Complete | Exploration done | → Phase 2 or 3 |
|
||||
| Phase 2 Output | Questions displayed | → Wait for user reply |
|
||||
| User Replied | Clarifications received | → Phase 3 |
|
||||
| Phase 3 Complete | Plan generated | → Phase 4 |
|
||||
| Phase 4 Output | Plan displayed | → Wait for user confirmation |
|
||||
| User: "Allow" | Confirmed | → Phase 5 (Write plan.json) |
|
||||
| User: "Modify" | Changes requested | → Revise plan, back to Phase 4 |
|
||||
| User: "Cancel" | Aborted | → End workflow |
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Error | Resolution |
|
||||
|-------|------------|
|
||||
| Subagent spawn failure | Fallback to direct exploration |
|
||||
| wait() timeout | Use completed results, log partial status |
|
||||
| Planning subagent failure | Fallback to direct planning |
|
||||
| Clarification timeout | Use exploration findings as-is |
|
||||
| Confirmation timeout | Save context, display resume instructions |
|
||||
| Modify loop > 3 times | Suggest breaking task into smaller pieces |
|
||||
|
||||
---
|
||||
|
||||
**Now execute the lite-plan workflow for task**: $TASK
|
||||
123
ccw/frontend/src/components/ui/MultiNodeSelector.tsx
Normal file
123
ccw/frontend/src/components/ui/MultiNodeSelector.tsx
Normal file
@@ -0,0 +1,123 @@
|
||||
import * as React from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
import { Check, X } from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
export interface NodeOption {
|
||||
id: string;
|
||||
label: string;
|
||||
type?: string;
|
||||
}
|
||||
|
||||
export interface MultiNodeSelectorProps {
|
||||
availableNodes: NodeOption[];
|
||||
selectedNodes: string[];
|
||||
onChange: (selectedIds: string[]) => void;
|
||||
placeholder?: string;
|
||||
emptyMessage?: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const MultiNodeSelector = React.forwardRef<HTMLDivElement, MultiNodeSelectorProps>(
|
||||
({ availableNodes, selectedNodes, onChange, placeholder, emptyMessage, className }, ref) => {
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
const isSelected = (nodeId: string) => selectedNodes.includes(nodeId);
|
||||
|
||||
const toggleNode = (nodeId: string) => {
|
||||
if (isSelected(nodeId)) {
|
||||
onChange(selectedNodes.filter((id) => id !== nodeId));
|
||||
} else {
|
||||
onChange([...selectedNodes, nodeId]);
|
||||
}
|
||||
};
|
||||
|
||||
const clearSelection = () => {
|
||||
onChange([]);
|
||||
};
|
||||
|
||||
return (
|
||||
<div ref={ref} className={cn("space-y-2", className)}>
|
||||
{/* Selected tags */}
|
||||
{selectedNodes.length > 0 && (
|
||||
<div className="flex flex-wrap gap-2 p-2 rounded-md border border-border bg-muted/30">
|
||||
{selectedNodes.map((nodeId) => {
|
||||
const node = availableNodes.find((n) => n.id === nodeId);
|
||||
return (
|
||||
<span
|
||||
key={nodeId}
|
||||
className="inline-flex items-center gap-1 px-2 py-1 rounded-md bg-primary text-primary-foreground text-xs"
|
||||
>
|
||||
<span>{node?.label || nodeId}</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => toggleNode(nodeId)}
|
||||
className="hover:bg-primary-foreground/20 rounded p-0.5"
|
||||
>
|
||||
<X className="w-3 h-3" />
|
||||
</button>
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
<button
|
||||
type="button"
|
||||
onClick={clearSelection}
|
||||
className="text-xs text-muted-foreground hover:text-foreground underline"
|
||||
>
|
||||
{formatMessage({ id: 'orchestrator.multiNodeSelector.clear' })}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Available nodes list */}
|
||||
<div className="border border-border rounded-md bg-background max-h-48 overflow-y-auto">
|
||||
{availableNodes.length === 0 ? (
|
||||
<div className="p-4 text-sm text-muted-foreground text-center">
|
||||
{emptyMessage || formatMessage({ id: 'orchestrator.multiNodeSelector.empty' })}
|
||||
</div>
|
||||
) : (
|
||||
<div className="p-1">
|
||||
{availableNodes.map((node) => (
|
||||
<div
|
||||
key={node.id}
|
||||
onClick={() => toggleNode(node.id)}
|
||||
className={cn(
|
||||
"flex items-center gap-2 p-2 rounded cursor-pointer transition-colors",
|
||||
"hover:bg-muted",
|
||||
isSelected(node.id) && "bg-muted"
|
||||
)}
|
||||
>
|
||||
<div
|
||||
className={cn(
|
||||
"w-4 h-4 rounded border flex items-center justify-center",
|
||||
isSelected(node.id)
|
||||
? "bg-primary border-primary"
|
||||
: "border-border"
|
||||
)}
|
||||
>
|
||||
{isSelected(node.id) && (
|
||||
<Check className="w-3 h-3 text-primary-foreground" />
|
||||
)}
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="text-sm font-medium text-foreground truncate">
|
||||
{node.label}
|
||||
</div>
|
||||
{node.type && (
|
||||
<div className="text-xs text-muted-foreground">
|
||||
{node.type}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
MultiNodeSelector.displayName = "MultiNodeSelector";
|
||||
|
||||
export { MultiNodeSelector };
|
||||
54
ccw/frontend/src/components/ui/VariablePicker.tsx
Normal file
54
ccw/frontend/src/components/ui/VariablePicker.tsx
Normal file
@@ -0,0 +1,54 @@
|
||||
import * as React from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
export interface VariablePickerProps extends Omit<React.SelectHTMLAttributes<HTMLSelectElement>, 'onChange'> {
|
||||
options: string[];
|
||||
value?: string;
|
||||
onChange?: (value: string) => void;
|
||||
placeholder?: string;
|
||||
emptyMessage?: string;
|
||||
}
|
||||
|
||||
const VariablePicker = React.forwardRef<HTMLSelectElement, VariablePickerProps>(
|
||||
({ className, options, value, onChange, placeholder, emptyMessage, ...props }, ref) => {
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
const handleChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
|
||||
onChange?.(e.target.value);
|
||||
};
|
||||
|
||||
return (
|
||||
<select
|
||||
ref={ref}
|
||||
value={value || ''}
|
||||
onChange={handleChange}
|
||||
className={cn(
|
||||
"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{placeholder && (
|
||||
<option value="">
|
||||
{placeholder}
|
||||
</option>
|
||||
)}
|
||||
{options.length === 0 ? (
|
||||
<option value="" disabled>
|
||||
{emptyMessage || formatMessage({ id: 'orchestrator.variablePicker.empty' })}
|
||||
</option>
|
||||
) : (
|
||||
options.map((option) => (
|
||||
<option key={option} value={option}>
|
||||
{option}
|
||||
</option>
|
||||
))
|
||||
)}
|
||||
</select>
|
||||
);
|
||||
}
|
||||
);
|
||||
VariablePicker.displayName = "VariablePicker";
|
||||
|
||||
export { VariablePicker };
|
||||
@@ -136,6 +136,13 @@
|
||||
"tipLabel": "Tip:",
|
||||
"tip": "Connect nodes by dragging from output to input handles"
|
||||
},
|
||||
"variablePicker": {
|
||||
"empty": "No variables available"
|
||||
},
|
||||
"multiNodeSelector": {
|
||||
"empty": "No nodes available",
|
||||
"clear": "Clear all"
|
||||
},
|
||||
"propertyPanel": {
|
||||
"title": "Properties",
|
||||
"open": "Open properties panel",
|
||||
@@ -175,8 +182,8 @@
|
||||
"failFast": "Fail fast (stop all branches on first error)"
|
||||
},
|
||||
"options": {
|
||||
"modeAnalysis": "Analysis (Read-only)",
|
||||
"modeWrite": "Write (Modify files)",
|
||||
"modeMainprocess": "Main Process",
|
||||
"modeAsync": "Async",
|
||||
"errorStop": "Stop execution",
|
||||
"errorContinue": "Continue",
|
||||
"errorRetry": "Retry",
|
||||
|
||||
@@ -135,6 +135,13 @@
|
||||
"tipLabel": "提示:",
|
||||
"tip": "通过从输出拖动到输入句柄来连接节点"
|
||||
},
|
||||
"variablePicker": {
|
||||
"empty": "没有可用的变量"
|
||||
},
|
||||
"multiNodeSelector": {
|
||||
"empty": "没有可用的节点",
|
||||
"clear": "清除全部"
|
||||
},
|
||||
"propertyPanel": {
|
||||
"title": "属性",
|
||||
"open": "打开属性面板",
|
||||
@@ -174,8 +181,8 @@
|
||||
"failFast": "快速失败 (首次错误时停止所有分支)"
|
||||
},
|
||||
"options": {
|
||||
"modeAnalysis": "分析 (只读)",
|
||||
"modeWrite": "写入 (修改文件)",
|
||||
"modeMainprocess": "主进程",
|
||||
"modeAsync": "异步",
|
||||
"errorStop": "停止执行",
|
||||
"errorContinue": "继续",
|
||||
"errorRetry": "重试",
|
||||
|
||||
@@ -74,16 +74,16 @@ function SlashCommandProperties({
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-foreground mb-1">{formatMessage({ id: 'orchestrator.propertyPanel.labels.executionMode' })}</label>
|
||||
<select
|
||||
value={data.execution?.mode || 'analysis'}
|
||||
value={data.execution?.mode || 'mainprocess'}
|
||||
onChange={(e) =>
|
||||
onChange({
|
||||
execution: { ...data.execution, mode: e.target.value as 'analysis' | 'write' },
|
||||
execution: { ...data.execution, mode: e.target.value as 'mainprocess' | 'async' },
|
||||
})
|
||||
}
|
||||
className="w-full h-10 px-3 rounded-md border border-border bg-background text-foreground text-sm"
|
||||
>
|
||||
<option value="analysis">{formatMessage({ id: 'orchestrator.propertyPanel.options.modeAnalysis' })}</option>
|
||||
<option value="write">{formatMessage({ id: 'orchestrator.propertyPanel.options.modeWrite' })}</option>
|
||||
<option value="mainprocess">{formatMessage({ id: 'orchestrator.propertyPanel.options.modeMainprocess' })}</option>
|
||||
<option value="async">{formatMessage({ id: 'orchestrator.propertyPanel.options.modeAsync' })}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
@@ -109,7 +109,7 @@ function SlashCommandProperties({
|
||||
onChange({
|
||||
execution: {
|
||||
...data.execution,
|
||||
mode: data.execution?.mode || 'analysis',
|
||||
mode: data.execution?.mode || 'mainprocess',
|
||||
timeout: e.target.value ? parseInt(e.target.value) : undefined,
|
||||
},
|
||||
})
|
||||
@@ -117,6 +117,15 @@ function SlashCommandProperties({
|
||||
placeholder={formatMessage({ id: 'orchestrator.propertyPanel.placeholders.timeout' })}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-foreground mb-1">{formatMessage({ id: 'orchestrator.propertyPanel.labels.outputVariable' })}</label>
|
||||
<Input
|
||||
value={data.outputVariable || ''}
|
||||
onChange={(e) => onChange({ outputVariable: e.target.value })}
|
||||
placeholder={formatMessage({ id: 'orchestrator.propertyPanel.placeholders.variableName' })}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -270,6 +279,15 @@ function ConditionalProperties({
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-foreground mb-1">{formatMessage({ id: 'orchestrator.propertyPanel.labels.outputVariable' })}</label>
|
||||
<Input
|
||||
value={data.outputVariable || ''}
|
||||
onChange={(e) => onChange({ outputVariable: e.target.value })}
|
||||
placeholder={formatMessage({ id: 'orchestrator.propertyPanel.placeholders.variableName' })}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -334,6 +352,15 @@ function ParallelProperties({
|
||||
{formatMessage({ id: 'orchestrator.propertyPanel.labels.failFast' })}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-foreground mb-1">{formatMessage({ id: 'orchestrator.propertyPanel.labels.outputVariable' })}</label>
|
||||
<Input
|
||||
value={data.outputVariable || ''}
|
||||
onChange={(e) => onChange({ outputVariable: e.target.value })}
|
||||
placeholder={formatMessage({ id: 'orchestrator.propertyPanel.placeholders.variableName' })}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -17,12 +17,12 @@ interface SlashCommandNodeProps {
|
||||
|
||||
// Mode badge styling
|
||||
const MODE_STYLES = {
|
||||
analysis: 'bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400',
|
||||
write: 'bg-amber-100 text-amber-700 dark:bg-amber-900/30 dark:text-amber-400',
|
||||
mainprocess: 'bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400',
|
||||
async: 'bg-purple-100 text-purple-700 dark:bg-purple-900/30 dark:text-purple-400',
|
||||
};
|
||||
|
||||
export const SlashCommandNode = memo(({ data, selected }: SlashCommandNodeProps) => {
|
||||
const executionMode = data.execution?.mode || 'analysis';
|
||||
const executionMode = data.execution?.mode || 'mainprocess';
|
||||
|
||||
return (
|
||||
<NodeWrapper
|
||||
|
||||
@@ -18,6 +18,7 @@ interface BaseNodeData {
|
||||
executionStatus?: ExecutionStatus;
|
||||
executionError?: string;
|
||||
executionResult?: unknown;
|
||||
outputVariable?: string;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
@@ -26,7 +27,7 @@ export interface SlashCommandNodeData extends BaseNodeData {
|
||||
command: string;
|
||||
args?: string;
|
||||
execution: {
|
||||
mode: 'analysis' | 'write';
|
||||
mode: 'mainprocess' | 'async';
|
||||
timeout?: number;
|
||||
};
|
||||
contextHint?: string;
|
||||
@@ -191,7 +192,7 @@ export const NODE_TYPE_CONFIGS: Record<FlowNodeType, NodeTypeConfig> = {
|
||||
label: 'New Command',
|
||||
command: '',
|
||||
args: '',
|
||||
execution: { mode: 'analysis' },
|
||||
execution: { mode: 'mainprocess' },
|
||||
onError: 'stop',
|
||||
} as SlashCommandNodeData,
|
||||
handles: { inputs: 1, outputs: 1 },
|
||||
|
||||
Reference in New Issue
Block a user