From e4b898f4015804f09380c83f32939cd20e589683 Mon Sep 17 00:00:00 2001 From: catlog22 Date: Sat, 14 Feb 2026 20:54:05 +0800 Subject: [PATCH] feat: add Terminal Dashboard components and state management - Implement TerminalTabBar for session tab management with status indicators and alert badges. - Create TerminalWorkbench to combine TerminalTabBar and TerminalInstance for terminal session display. - Add localization support for terminal dashboard in English and Chinese. - Develop TerminalDashboardPage for the main layout of the terminal dashboard with a three-column structure. - Introduce Zustand stores for session management and issue/queue integration, handling session groups, terminal metadata, and alert management. - Create a monitor web worker for off-main-thread output analysis, detecting errors and stalls in terminal sessions. - Define TypeScript types for terminal dashboard state management and integration. --- .claude/commands/workflow/execute.md | 599 ------------ .claude/commands/workflow/lite-execute.md | 768 --------------- .claude/commands/workflow/lite-fix.md | 878 ------------------ .claude/commands/workflow/lite-plan.md | 770 --------------- .claude/commands/workflow/multi-cli-plan.md | 602 ------------ .claude/commands/workflow/plan-verify.md | 377 -------- .claude/commands/workflow/plan.md | 705 -------------- .claude/commands/workflow/replan.md | 648 ------------- .../src/components/layout/Sidebar.tsx | 1 + .../terminal-dashboard/AgentList.tsx | 129 +++ .../AssociationHighlight.tsx | 90 ++ .../terminal-dashboard/BottomInspector.tsx | 216 +++++ .../terminal-dashboard/GlobalKpiBar.tsx | 138 +++ .../terminal-dashboard/IssuePanel.tsx | 289 ++++++ .../terminal-dashboard/QueuePanel.tsx | 264 ++++++ .../terminal-dashboard/SessionGroupTree.tsx | 218 +++++ .../terminal-dashboard/TerminalInstance.tsx | 211 +++++ .../terminal-dashboard/TerminalTabBar.tsx | 93 ++ .../terminal-dashboard/TerminalWorkbench.tsx | 49 + .../terminal-panel/TerminalMainArea.tsx | 106 +-- .../terminal-panel/TerminalNavBar.tsx | 47 +- ccw/frontend/src/locales/en/index.ts | 2 + ccw/frontend/src/locales/en/navigation.json | 3 +- .../src/locales/en/terminal-dashboard.json | 81 ++ ccw/frontend/src/locales/zh/index.ts | 2 + ccw/frontend/src/locales/zh/navigation.json | 3 +- .../src/locales/zh/terminal-dashboard.json | 81 ++ ccw/frontend/src/pages/ReviewSessionPage.tsx | 5 +- .../src/pages/TerminalDashboardPage.tsx | 96 ++ ccw/frontend/src/pages/index.ts | 1 + ccw/frontend/src/router.tsx | 6 + ccw/frontend/src/stores/index.ts | 41 + .../src/stores/issueQueueIntegrationStore.ts | 232 +++++ .../src/stores/sessionManagerStore.ts | 205 ++++ ccw/frontend/src/types/index.ts | 18 + ccw/frontend/src/types/terminal-dashboard.ts | 120 +++ ccw/frontend/src/workers/monitor.worker.ts | 154 +++ 37 files changed, 2810 insertions(+), 5438 deletions(-) delete mode 100644 .claude/commands/workflow/execute.md delete mode 100644 .claude/commands/workflow/lite-execute.md delete mode 100644 .claude/commands/workflow/lite-fix.md delete mode 100644 .claude/commands/workflow/lite-plan.md delete mode 100644 .claude/commands/workflow/multi-cli-plan.md delete mode 100644 .claude/commands/workflow/plan-verify.md delete mode 100644 .claude/commands/workflow/plan.md delete mode 100644 .claude/commands/workflow/replan.md create mode 100644 ccw/frontend/src/components/terminal-dashboard/AgentList.tsx create mode 100644 ccw/frontend/src/components/terminal-dashboard/AssociationHighlight.tsx create mode 100644 ccw/frontend/src/components/terminal-dashboard/BottomInspector.tsx create mode 100644 ccw/frontend/src/components/terminal-dashboard/GlobalKpiBar.tsx create mode 100644 ccw/frontend/src/components/terminal-dashboard/IssuePanel.tsx create mode 100644 ccw/frontend/src/components/terminal-dashboard/QueuePanel.tsx create mode 100644 ccw/frontend/src/components/terminal-dashboard/SessionGroupTree.tsx create mode 100644 ccw/frontend/src/components/terminal-dashboard/TerminalInstance.tsx create mode 100644 ccw/frontend/src/components/terminal-dashboard/TerminalTabBar.tsx create mode 100644 ccw/frontend/src/components/terminal-dashboard/TerminalWorkbench.tsx create mode 100644 ccw/frontend/src/locales/en/terminal-dashboard.json create mode 100644 ccw/frontend/src/locales/zh/terminal-dashboard.json create mode 100644 ccw/frontend/src/pages/TerminalDashboardPage.tsx create mode 100644 ccw/frontend/src/stores/issueQueueIntegrationStore.ts create mode 100644 ccw/frontend/src/stores/sessionManagerStore.ts create mode 100644 ccw/frontend/src/types/terminal-dashboard.ts create mode 100644 ccw/frontend/src/workers/monitor.worker.ts diff --git a/.claude/commands/workflow/execute.md b/.claude/commands/workflow/execute.md deleted file mode 100644 index 6c57dd6b..00000000 --- a/.claude/commands/workflow/execute.md +++ /dev/null @@ -1,599 +0,0 @@ ---- -name: execute -description: Coordinate agent execution for workflow tasks with automatic session discovery, parallel task processing, and status tracking -argument-hint: "[-y|--yes] [--resume-session=\"session-id\"] [--with-commit]" ---- - -# Workflow Execute Command - -## Overview -Orchestrates autonomous workflow execution through systematic task discovery, agent coordination, and progress tracking. **Executes entire workflow without user interruption** (except initial session selection if multiple active sessions exist), providing complete context to agents and ensuring proper flow control execution with comprehensive TodoWrite tracking. - -**Resume Mode**: When called with `--resume-session` flag, skips discovery phase and directly enters TodoWrite generation and agent execution for the specified session. - -## Usage - -```bash -# Interactive mode (with confirmations) -/workflow:execute -/workflow:execute --resume-session="WFS-auth" - -# Auto mode (skip confirmations, use defaults) -/workflow:execute --yes -/workflow:execute -y -/workflow:execute -y --resume-session="WFS-auth" - -# With auto-commit (commit after each task completion) -/workflow:execute --with-commit -/workflow:execute -y --with-commit -/workflow:execute -y --with-commit --resume-session="WFS-auth" -``` - -## Auto Mode Defaults - -When `--yes` or `-y` flag is used: -- **Session Selection**: Automatically selects the first (most recent) active session -- **Completion Choice**: Automatically completes session (runs `/workflow:session:complete --yes`) - -When `--with-commit` flag is used: -- **Auto-Commit**: After each agent task completes, commit changes based on summary document -- **Commit Principle**: Minimal commits - only commit files modified by the completed task -- **Commit Message**: Generated from task summary with format: "feat/fix/refactor: {task-title} - {summary}" - -**Flag Parsing**: -```javascript -const autoYes = $ARGUMENTS.includes('--yes') || $ARGUMENTS.includes('-y') -const withCommit = $ARGUMENTS.includes('--with-commit') -``` - -## Performance Optimization Strategy - -**Lazy Loading**: Task JSONs read **on-demand** during execution, not upfront. TODO_LIST.md + IMPL_PLAN.md provide metadata for planning. - -**Loading Strategy**: -- **TODO_LIST.md**: Read in Phase 3 (task metadata, status, dependencies for TodoWrite generation) -- **IMPL_PLAN.md**: Check existence in Phase 2 (normal mode), parse execution strategy in Phase 4A -- **Task JSONs**: Lazy loading - read only when task is about to execute (Phase 4B) - -## Core Rules -**Complete entire workflow autonomously without user interruption, using TodoWrite for comprehensive progress tracking.** -**Execute all discovered pending tasks until workflow completion or blocking dependency.** -**User-choice completion: When all tasks finished, ask user to choose review or complete.** -**ONE AGENT = ONE TASK JSON: Each agent instance executes exactly one task JSON file - never batch multiple tasks into single agent execution.** - -## Core Responsibilities -- **Session Discovery**: Identify and select active workflow sessions -- **Execution Strategy Parsing**: Extract execution model from IMPL_PLAN.md -- **TodoWrite Progress Tracking**: Maintain real-time execution status throughout entire workflow -- **Agent Orchestration**: Coordinate specialized agents with complete context -- **Status Synchronization**: Update task JSON files and workflow state -- **Autonomous Completion**: Continue execution until all tasks complete or reach blocking state -- **Session User-Choice Completion**: Ask user to choose review or complete when all tasks finished - -## Execution Philosophy -- **Progress tracking**: Continuous TodoWrite updates throughout entire workflow execution -- **Autonomous completion**: Execute all tasks without user interruption until workflow complete - -## Execution Process - -``` -Normal Mode: -Phase 1: Discovery - ├─ Count active sessions - └─ Decision: - ├─ count=0 → ERROR: No active sessions - ├─ count=1 → Auto-select session → Phase 2 - └─ count>1 → AskUserQuestion (max 4 options) → Phase 2 - -Phase 2: Planning Document Validation - ├─ Check IMPL_PLAN.md exists - ├─ Check TODO_LIST.md exists - └─ Validate .task/ contains IMPL-*.json files - -Phase 3: TodoWrite Generation - ├─ Update session status to "active" (Step 0) - ├─ Parse TODO_LIST.md for task statuses - ├─ Generate TodoWrite for entire workflow - └─ Prepare session context paths - -Phase 4: Execution Strategy & Task Execution - ├─ Step 4A: Parse execution strategy from IMPL_PLAN.md - └─ Step 4B: Execute tasks with lazy loading - └─ Loop: - ├─ Get next in_progress task from TodoWrite - ├─ Lazy load task JSON - ├─ Launch agent with task context - ├─ Mark task completed (update IMPL-*.json status) - │ # Quick fix: Update task status for ccw dashboard - │ # TS=$(date -Iseconds) && jq --arg ts "$TS" '.status="completed" | .status_history=(.status_history // [])+[{"from":"in_progress","to":"completed","changed_at":$ts}]' IMPL-X.json > tmp.json && mv tmp.json IMPL-X.json - ├─ [with-commit] Commit changes based on summary (minimal principle) - │ # Read summary from .summaries/IMPL-X-summary.md - │ # Extract changed files from summary's "Files Modified" section - │ # Generate commit message: "feat/fix/refactor: {task-title} - {summary}" - │ # git add && git commit -m "" - └─ Advance to next task - -Phase 5: Completion - ├─ Update task statuses in JSON files - ├─ Generate summaries - └─ AskUserQuestion: Choose next step - ├─ "Enter Review" → /workflow:review - └─ "Complete Session" → /workflow:session:complete - -Resume Mode (--resume-session): - ├─ Skip Phase 1 & Phase 2 - └─ Entry Point: Phase 3 (TodoWrite Generation) - ├─ Update session status to "active" (if not already) - └─ Continue: Phase 4 → Phase 5 -``` - -## Execution Lifecycle - -### Phase 1: Discovery -**Applies to**: Normal mode only (skipped in resume mode) - -**Purpose**: Find and select active workflow session with user confirmation when multiple sessions exist - -**Process**: - -#### Step 1.1: Count Active Sessions -```bash -bash(find .workflow/active/ -name "WFS-*" -type d 2>/dev/null | wc -l) -``` - -#### Step 1.2: Handle Session Selection - -**Case A: No Sessions** (count = 0) -``` -ERROR: No active workflow sessions found -Run /workflow:plan "task description" to create a session -``` - -**Case B: Single Session** (count = 1) -```bash -bash(find .workflow/active/ -name "WFS-*" -type d 2>/dev/null | head -1 | xargs basename) -``` -Auto-select and continue to Phase 2. - -**Case C: Multiple Sessions** (count > 1) - -List sessions with metadata and prompt user selection: -```bash -bash(for dir in .workflow/active/WFS-*/; do [ -d "$dir" ] || continue; session=$(basename "$dir"); project=$(jq -r '.project // "Unknown"' "${dir}workflow-session.json" 2>/dev/null || echo "Unknown"); total=$(grep -c '^\- \[' "${dir}TODO_LIST.md" 2>/dev/null || echo 0); completed=$(grep -c '^\- \[x\]' "${dir}TODO_LIST.md" 2>/dev/null || echo 0); if [ "$total" -gt 0 ]; then progress=$((completed * 100 / total)); else progress=0; fi; echo "$session | $project | $completed/$total tasks ($progress%)"; done) -``` - -**Parse --yes flag**: -```javascript -const autoYes = $ARGUMENTS.includes('--yes') || $ARGUMENTS.includes('-y') -``` - -**Conditional Selection**: -```javascript -if (autoYes) { - // Auto mode: Select first session (most recent) - const firstSession = sessions[0] - console.log(`[--yes] Auto-selecting session: ${firstSession.id}`) - selectedSessionId = firstSession.id - // Continue to Phase 2 -} else { - // Interactive mode: Use AskUserQuestion to present formatted options (max 4 options shown) - // If more than 4 sessions, show most recent 4 with "Other" option for manual input - const sessions = getActiveSessions() // sorted by last modified - const displaySessions = sessions.slice(0, 4) - - AskUserQuestion({ - questions: [{ - question: "Multiple active sessions detected. Select one:", - header: "Session", - multiSelect: false, - options: displaySessions.map(s => ({ - label: s.id, - description: `${s.project} | ${s.progress}` - })) - // Note: User can select "Other" to manually enter session ID - }] - }) -} -``` - -**Input Validation**: -- If user selects from options: Use selected session ID -- If user selects "Other" and provides input: Validate session exists -- If validation fails: Show error and re-prompt or suggest available sessions - -Parse user input (supports: number "1", full ID "WFS-auth-system", or partial "auth"), validate selection, and continue to Phase 2. - -#### Step 1.3: Load Session Metadata -```bash -bash(cat .workflow/active/${sessionId}/workflow-session.json) -``` - -**Output**: Store session metadata in memory -**DO NOT read task JSONs yet** - defer until execution phase (lazy loading) - -**Resume Mode**: This entire phase is skipped when `--resume-session="session-id"` flag is provided. - -### Phase 2: Planning Document Validation -**Applies to**: Normal mode only (skipped in resume mode) - -**Purpose**: Validate planning artifacts exist before execution - -**Process**: -1. **Check IMPL_PLAN.md**: Verify file exists (defer detailed parsing to Phase 4A) -2. **Check plan.json**: Verify file exists (structured plan overview, used in Phase 4A) -3. **Check TODO_LIST.md**: Verify file exists (defer reading to Phase 3) -4. **Validate Task Directory**: Ensure `.task/` contains at least one IMPL-*.json file - -**Key Optimization**: Only existence checks here. Actual file reading happens in later phases. - -**Resume Mode**: This phase is skipped when `--resume-session` flag is provided. Resume mode entry point is Phase 3. - -### Phase 3: TodoWrite Generation -**Applies to**: Both normal and resume modes (resume mode entry point) - -**Step 0: Update Session Status to Active** -Before generating TodoWrite, update session status from "planning" to "active": -```bash -# Update session status (idempotent - safe to run if already active) -jq '.status = "active" | .execution_started_at = (.execution_started_at // now | todate)' \ - .workflow/active/${sessionId}/workflow-session.json > tmp.json && \ - mv tmp.json .workflow/active/${sessionId}/workflow-session.json -``` -This ensures the dashboard shows the session as "ACTIVE" during execution. - -**Process**: -1. **Create TodoWrite List**: Generate task list from TODO_LIST.md (not from task JSONs) - - Parse TODO_LIST.md to extract all tasks with current statuses - - Identify first pending task with met dependencies - - Generate comprehensive TodoWrite covering entire workflow -2. **Prepare Session Context**: Inject workflow paths for agent use (using provided session-id) -3. **Validate Prerequisites**: Ensure IMPL_PLAN.md and TODO_LIST.md exist and are valid - -**Resume Mode Behavior**: -- Load existing TODO_LIST.md directly from `.workflow/active/{session-id}/` -- Extract current progress from TODO_LIST.md -- Generate TodoWrite from TODO_LIST.md state -- Proceed immediately to agent execution (Phase 4) - -### Phase 4: Execution Strategy Selection & Task Execution -**Applies to**: Both normal and resume modes - -**Step 4A: Parse Execution Strategy (plan.json preferred, IMPL_PLAN.md fallback)** - -Prefer `plan.json` (structured) over `IMPL_PLAN.md` (human-readable) for execution strategy: -1. **If plan.json exists**: Read `recommended_execution`, `complexity`, `task_ids[]`, `shared_context` -2. **Fallback to IMPL_PLAN.md**: Read Section 4 to extract execution model - -Extract: -- **Execution Model**: Sequential | Parallel | Phased | TDD Cycles -- **Parallelization Opportunities**: Which tasks can run in parallel -- **Serialization Requirements**: Which tasks must run sequentially -- **Critical Path**: Priority execution order - -If neither has execution strategy, use intelligent fallback (analyze task structure). - -**Step 4B: Execute Tasks with Lazy Loading** - -**Key Optimization**: Read task JSON **only when needed** for execution - -**Execution Loop Pattern**: -``` -while (TODO_LIST.md has pending tasks) { - next_task_id = getTodoWriteInProgressTask() - task_json = Read(.workflow/active/{session}/.task/{next_task_id}.json) // Lazy load - executeTaskWithAgent(task_json) - updateTodoListMarkCompleted(next_task_id) - advanceTodoWriteToNextTask() -} -``` - -**Execution Process per Task**: -1. **Identify Next Task**: From TodoWrite, get the next `in_progress` task ID -2. **Load Task JSON on Demand**: Read `.task/{task-id}.json` for current task ONLY -3. **Validate Task Structure**: Ensure required fields exist (id, title, description, depends_on, convergence) -4. **Launch Agent**: Invoke specialized agent with complete context including flow control steps -5. **Monitor Progress**: Track agent execution and handle errors without user interruption -6. **Collect Results**: Gather implementation results and outputs -7. **[with-commit] Auto-Commit**: If `--with-commit` flag enabled, commit changes based on summary - - Read summary from `.summaries/{task-id}-summary.md` - - Extract changed files from summary's "Files Modified" section - - Determine commit type from `meta.type` (feature→feat, bugfix→fix, refactor→refactor) - - Generate commit message: "{type}: {task-title} - {summary-first-line}" - - Commit only modified files (minimal principle): `git add && git commit -m ""` -8. **Continue Workflow**: Identify next pending task from TODO_LIST.md and repeat - -**Note**: TODO_LIST.md updates are handled by agents (e.g., code-developer.md), not by the orchestrator. - - -### Phase 5: Completion -**Applies to**: Both normal and resume modes - -**Process**: -1. **Update Task Status**: Mark completed tasks in JSON files -2. **Generate Summary**: Create task summary in `.summaries/` -3. **Update TodoWrite**: Mark current task complete, advance to next -4. **Synchronize State**: Update session state and workflow status -5. **Check Workflow Complete**: Verify all tasks are completed -6. **User Choice**: When all tasks finished, ask user to choose next step: - -```javascript -// Parse --yes flag -const autoYes = $ARGUMENTS.includes('--yes') || $ARGUMENTS.includes('-y') - -if (autoYes) { - // Auto mode: Complete session automatically - console.log(`[--yes] Auto-selecting: Complete Session`) - Skill(skill="workflow:session:complete", args="--yes") -} else { - // Interactive mode: Ask user - AskUserQuestion({ - questions: [{ - question: "All tasks completed. What would you like to do next?", - header: "Next Step", - multiSelect: false, - options: [ - { - label: "Enter Review", - description: "Run specialized review (security/architecture/quality/action-items)" - }, - { - label: "Complete Session", - description: "Archive session and update manifest" - } - ] - }] - }) -} -``` - -**Based on user selection**: -- **"Enter Review"**: Execute `/workflow:review` -- **"Complete Session"**: Execute `/workflow:session:complete` - -### Post-Completion Expansion - -完成后询问用户是否扩展为issue(test/enhance/refactor/doc),选中项调用 `/issue:new "{summary} - {dimension}"` - -## Execution Strategy (IMPL_PLAN-Driven) - -### Strategy Priority - -**IMPL_PLAN-Driven Execution (Recommended)**: -1. **Read IMPL_PLAN.md execution strategy** (Section 4: Implementation Strategy) -2. **Follow explicit guidance**: - - Execution Model (Sequential/Parallel/Phased/TDD) - - Parallelization Opportunities (which tasks can run in parallel) - - Serialization Requirements (which tasks must run sequentially) - - Critical Path (priority execution order) -3. **Use TODO_LIST.md for status tracking** only -4. **IMPL_PLAN decides "HOW"**, execute.md implements it - -**Intelligent Fallback (When IMPL_PLAN lacks execution details)**: -1. **Analyze task structure**: - - Check `meta.execution_group` in task JSONs - - Analyze `depends_on` relationships - - Understand task complexity and risk -2. **Apply smart defaults**: - - No dependencies + same execution_group → Parallel - - Has dependencies → Sequential (wait for deps) - - Critical/high-risk tasks → Sequential -3. **Conservative approach**: When uncertain, prefer sequential execution - -### Execution Models - -#### 1. Sequential Execution -**When**: IMPL_PLAN specifies "Sequential" OR no clear parallelization guidance -**Pattern**: Execute tasks one by one in TODO_LIST order -**TodoWrite**: ONE task marked as `in_progress` at a time - -#### 2. Parallel Execution -**When**: IMPL_PLAN specifies "Parallel" with clear parallelization opportunities -**Pattern**: Execute independent task groups concurrently by launching multiple agent instances -**TodoWrite**: MULTIPLE tasks (in same batch) marked as `in_progress` simultaneously -**Agent Instantiation**: Launch one agent instance per task (respects ONE AGENT = ONE TASK JSON rule) - -#### 3. Phased Execution -**When**: IMPL_PLAN specifies "Phased" with phase breakdown -**Pattern**: Execute tasks in phases, respect phase boundaries -**TodoWrite**: Within each phase, follow Sequential or Parallel rules - -#### 4. Intelligent Fallback -**When**: IMPL_PLAN lacks execution strategy details -**Pattern**: Analyze task structure and apply smart defaults -**TodoWrite**: Follow Sequential or Parallel rules based on analysis - -### Task Status Logic -``` -pending + dependencies_met → executable -completed → skip -blocked → skip until dependencies clear -``` - -## TodoWrite Coordination - -### TodoWrite Rules (Unified) - -**Rule 1: Initial Creation** -- **Normal Mode**: Generate TodoWrite from discovered pending tasks for entire workflow -- **Resume Mode**: Generate from existing session state and current progress - -**Rule 2: In-Progress Task Count (Execution-Model-Dependent)** -- **Sequential execution**: Mark ONLY ONE task as `in_progress` at a time -- **Parallel batch execution**: Mark ALL tasks in current batch as `in_progress` simultaneously -- **Execution group indicator**: Show `[execution_group: group-id]` for parallel tasks - -**Rule 3: Status Updates** -- **Immediate Updates**: Update status after each task/batch completion without user interruption -- **Status Synchronization**: Sync with JSON task files after updates -- **Continuous Tracking**: Maintain TodoWrite throughout entire workflow execution until completion - -**Rule 4: Workflow Completion Check** -- When all tasks marked `completed`, prompt user to choose review or complete session - -### TodoWrite Tool Usage - -**Example 1: Sequential Execution** -```javascript -TodoWrite({ - todos: [ - { - content: "Execute IMPL-1.1: Design auth schema [code-developer] [FLOW_CONTROL]", - status: "in_progress", // ONE task in progress - activeForm: "Executing IMPL-1.1: Design auth schema" - }, - { - content: "Execute IMPL-1.2: Implement auth logic [code-developer] [FLOW_CONTROL]", - status: "pending", - activeForm: "Executing IMPL-1.2: Implement auth logic" - } - ] -}); -``` - -**Example 2: Parallel Batch Execution** -```javascript -TodoWrite({ - todos: [ - { - content: "Execute IMPL-1.1: Build Auth API [code-developer] [execution_group: parallel-auth-api]", - status: "in_progress", // Batch task 1 - activeForm: "Executing IMPL-1.1: Build Auth API" - }, - { - content: "Execute IMPL-1.2: Build User UI [code-developer] [execution_group: parallel-ui-comp]", - status: "in_progress", // Batch task 2 (running concurrently) - activeForm: "Executing IMPL-1.2: Build User UI" - }, - { - content: "Execute IMPL-1.3: Setup Database [code-developer] [execution_group: parallel-db-schema]", - status: "in_progress", // Batch task 3 (running concurrently) - activeForm: "Executing IMPL-1.3: Setup Database" - }, - { - content: "Execute IMPL-2.1: Integration Tests [test-fix-agent] [depends_on: IMPL-1.1, IMPL-1.2, IMPL-1.3]", - status: "pending", // Next batch (waits for current batch completion) - activeForm: "Executing IMPL-2.1: Integration Tests" - } - ] -}); -``` - -## Agent Execution Pattern - -### Flow Control Execution -**[FLOW_CONTROL]** marker indicates task JSON contains `pre_analysis` steps for context preparation. - -**Note**: Orchestrator does NOT execute flow control steps - Agent interprets and executes them autonomously. - -### Agent Prompt Template -**Path-Based Invocation**: Pass paths and trigger markers, let agent parse task JSON autonomously. - -```bash -Task(subagent_type="{meta.agent}", - run_in_background=false, - prompt="Implement task {task.id}: {task.title} - - [FLOW_CONTROL] - - **Input**: - - Task JSON: {session.task_json_path} - - Context Package: {session.context_package_path} - - **Output Location**: - - Workflow: {session.workflow_dir} - - TODO List: {session.todo_list_path} - - Summaries: {session.summaries_dir} - - **Execution**: Read task JSON → Execute pre_analysis → Check execution_config.method → (CLI: handoff to CLI tool | Agent: direct implementation) → Update TODO_LIST.md → Generate summary", - description="Implement: {task.id}") -``` - -**Key Markers**: -- `Implement` keyword: Triggers tech stack detection and guidelines loading -- `[FLOW_CONTROL]`: Triggers pre_analysis execution - -**Why Path-Based**: Agent (code-developer.md) autonomously: -- Reads and parses task JSON (description, convergence, implementation, execution_config) -- Executes pre_analysis steps (Phase 1: context gathering) -- Checks execution_config.method (Phase 2: determine mode) -- CLI mode: Builds handoff prompt and executes via ccw cli with resume strategy -- Agent mode: Directly implements using modification_points and logic_flow -- Generates structured summary with integration points - -Embedding task content in prompt creates duplication and conflicts with agent's parsing logic. - -### Agent Assignment Rules -``` -meta.agent specified → Use specified agent -meta.agent missing → Infer from meta.type: - - "feature" → @code-developer - - "test-gen" → @code-developer - - "test-fix" → @test-fix-agent - - "review" → @universal-executor - - "docs" → @doc-generator -``` - -## Workflow File Structure Reference -``` -.workflow/active/WFS-[topic-slug]/ -├── workflow-session.json # Session state and metadata -├── plan.json # Structured plan overview (machine-readable) -├── IMPL_PLAN.md # Planning document and requirements (human-readable) -├── TODO_LIST.md # Progress tracking (updated by agents) -├── .task/ # Task definitions (JSON only) -│ ├── IMPL-1.json # Main task definitions -│ └── IMPL-1.1.json # Subtask definitions -├── .summaries/ # Task completion summaries -│ ├── IMPL-1-summary.md # Task completion details -│ └── IMPL-1.1-summary.md # Subtask completion details -└── .process/ # Planning artifacts - ├── context-package.json # Smart context package - └── ANALYSIS_RESULTS.md # Planning analysis results -``` - -## Error Handling & Recovery - -### Common Errors & Recovery - -| Error Type | Cause | Recovery Strategy | Max Attempts | -|-----------|-------|------------------|--------------| -| **Discovery Errors** | -| No active session | No sessions in `.workflow/active/` | Create or resume session: `/workflow:plan "project"` | N/A | -| Multiple sessions | Multiple sessions in `.workflow/active/` | Prompt user selection | N/A | -| Corrupted session | Invalid JSON files | Recreate session structure or validate files | N/A | -| **Execution Errors** | -| Agent failure | Agent crash/timeout | Retry with simplified context | 2 | -| Flow control error | Command failure | Skip optional, fail critical | 1 per step | -| Context loading error | Missing dependencies | Reload from JSON, use defaults | 3 | -| JSON file corruption | File system issues | Restore from backup/recreate | 1 | - -### Error Prevention -- **Pre-flight Checks**: Validate session integrity before execution -- **Backup Strategy**: Create task snapshots before major operations -- **Atomic Updates**: Update JSON files atomically to prevent corruption -- **Dependency Validation**: Check all depends_on references exist -- **Context Verification**: Ensure all required context is available - -## Auto-Commit Mode (--with-commit) - -**Behavior**: After each agent task completes, automatically commit changes based on summary document. - -**Minimal Principle**: Only commit files modified by the completed task. - -**Commit Message Format**: `{type}: {task-title} - {summary}` - -**Type Mapping** (from `meta.type`): -- `feature` → `feat` | `bugfix` → `fix` | `refactor` → `refactor` -- `test-gen` → `test` | `docs` → `docs` | `review` → `chore` - -**Implementation**: -```bash -# 1. Read summary from .summaries/{task-id}-summary.md -# 2. Extract files from "Files Modified" section -# 3. Commit: git add && git commit -m "{type}: {title} - {summary}" -``` - -**Error Handling**: Skip commit on no changes/missing summary, log errors, continue workflow. - - - diff --git a/.claude/commands/workflow/lite-execute.md b/.claude/commands/workflow/lite-execute.md deleted file mode 100644 index 241b2257..00000000 --- a/.claude/commands/workflow/lite-execute.md +++ /dev/null @@ -1,768 +0,0 @@ ---- -name: lite-execute -description: Execute tasks based on in-memory plan, prompt description, or file content -argument-hint: "[-y|--yes] [--in-memory] [\"task description\"|file-path]" -allowed-tools: TodoWrite(*), Task(*), Bash(*) ---- - -# Workflow Lite-Execute Command (/workflow:lite-execute) - -## Overview - -Flexible task execution command supporting three input modes: in-memory plan (from lite-plan), direct prompt description, or file content. Handles execution orchestration, progress tracking, and optional code review. - -**Core capabilities:** -- Multi-mode input (in-memory plan, prompt description, or file path) -- Execution orchestration (Agent or Codex) with full context -- Live progress tracking via TodoWrite at execution call level -- Optional code review with selected tool (Gemini, Agent, or custom) -- Context continuity across multiple executions -- Intelligent format detection (Enhanced Task JSON vs plain text) - -## Usage - -### Command Syntax -```bash -/workflow:lite-execute [FLAGS] - -# Flags ---in-memory Use plan from memory (called by lite-plan) - -# Arguments - Task description string, or path to file (required) -``` - -## 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 - -**Content**: Complete execution context (see Data Structures section) - -**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/Agent/Other) -- Proceed to execution with `originalUserInput` included - -**User Interaction**: -```javascript -// Parse --yes flag -const autoYes = $ARGUMENTS.includes('--yes') || $ARGUMENTS.includes('-y') - -let userSelection - -if (autoYes) { - // Auto mode: Use defaults - console.log(`[--yes] Auto-confirming execution:`) - console.log(` - Execution method: Auto`) - console.log(` - Code review: Skip`) - - userSelection = { - execution_method: "Auto", - code_review_tool: "Skip" - } -} else { - // Interactive mode: Ask user - userSelection = AskUserQuestion({ - questions: [ - { - question: "Select execution method:", - header: "Execution", - multiSelect: false, - options: [ - { label: "Agent", description: "@code-developer agent" }, - { label: "Codex", description: "codex CLI tool" }, - { label: "Auto", description: "Auto-select based on complexity" } - ] - }, - { - question: "Enable code review after execution?", - header: "Code Review", - multiSelect: false, - options: [ - { label: "Skip", description: "No review" }, - { label: "Gemini Review", description: "Gemini CLI tool" }, - { label: "Codex Review", description: "Git-aware review (prompt OR --uncommitted)" }, - { label: "Agent Review", description: "Current agent review" } - ] - } - ] - }) -} -``` - -### Mode 3: File Content - -**Trigger**: User calls with file path - -**Input**: Path to file containing task description or plan.json - -**Step 1: Read and Detect Format** - -```javascript -fileContent = Read(filePath) - -// Attempt JSON parsing -try { - jsonData = JSON.parse(fileContent) - - // Check if plan.json from lite-plan session (two-layer format: task_ids[]) - if (jsonData.summary && jsonData.approach && jsonData.task_ids) { - planObject = jsonData - originalUserInput = jsonData.summary - isPlanJson = true - - // Load tasks from .task/*.json files - const planDir = filePath.replace(/[/\\][^/\\]+$/, '') // parent directory - planObject._loadedTasks = loadTaskFiles(planDir, jsonData.task_ids) - } else { - // Valid JSON but not plan.json - treat as plain text - originalUserInput = fileContent - isPlanJson = false - } -} catch { - // Not valid JSON - treat as plain text prompt - originalUserInput = fileContent - isPlanJson = false -} -``` - -**Step 2: Create Execution Plan** - -If `isPlanJson === true`: -- Use `planObject` directly -- User selects execution method and code review - -If `isPlanJson === false`: -- Treat file content as prompt (same behavior as Mode 2) -- Create simple execution plan from content - -**Step 3: User Interaction** - -- AskUserQuestion: Select execution method (Agent/Codex/Auto) -- AskUserQuestion: Select code review tool -- Proceed to execution with full context - -## Helper Functions - -```javascript -// Load task files from .task/ directory (two-layer format) -function loadTaskFiles(planDir, taskIds) { - return taskIds.map(id => { - const taskPath = `${planDir}/.task/${id}.json` - return JSON.parse(Read(taskPath)) - }) -} - -// Get tasks array from loaded .task/*.json files -function getTasks(planObject) { - return planObject._loadedTasks || [] -} -``` - -## Execution Process - -``` -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: - ├─ Step 1: Initialize result tracking (previousExecutionResults = []) - ├─ Step 2: Task grouping & batch creation - │ ├─ Extract explicit depends_on (no file/keyword inference) - │ ├─ Group: independent tasks → single parallel batch (maximize utilization) - │ ├─ Group: dependent tasks → sequential phases (respect dependencies) - │ └─ Create TodoWrite list for batches - ├─ Step 3: Launch execution - │ ├─ Phase 1: All independent tasks (⚡ single batch, concurrent) - │ └─ Phase 2+: Dependent tasks by dependency order - ├─ Step 4: Track progress (TodoWrite updates per batch) - └─ Step 5: Code review (if codeReviewTool ≠ "Skip") - -Output: - └─ Execution complete with results in previousExecutionResults[] -``` - -## Detailed Execution Steps - -### Step 1: Initialize Execution Tracking - -**Operations**: -- Initialize result tracking for multi-execution scenarios -- Set up `previousExecutionResults` array for context continuity -- **In-Memory Mode**: Echo execution strategy from lite-plan for transparency - -```javascript -// Initialize result tracking -previousExecutionResults = [] - -// In-Memory Mode: Echo execution strategy (transparency before execution) -if (executionContext) { - console.log(` -📋 Execution Strategy (from lite-plan): - Method: ${executionContext.executionMethod} - Review: ${executionContext.codeReviewTool} - Tasks: ${getTasks(executionContext.planObject).length} - Complexity: ${executionContext.planObject.complexity} -${executionContext.executorAssignments ? ` Assignments: ${JSON.stringify(executionContext.executorAssignments)}` : ''} - `) -} -``` - -### Step 2: Task Grouping & Batch Creation - -**Dependency Analysis & Grouping Algorithm**: -```javascript -// Use explicit depends_on from plan.json (no inference from file/keywords) -function extractDependencies(tasks) { - const taskIdToIndex = {} - tasks.forEach((t, i) => { taskIdToIndex[t.id] = i }) - - return tasks.map((task, i) => { - // Only use explicit depends_on from plan.json - 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 createExecutionCalls(tasks, executionMethod) { - const tasksWithDeps = extractDependencies(tasks) - const processed = new Set() - const calls = [] - - // Phase 1: All independent tasks → single parallel batch (maximize utilization) - const independentTasks = tasksWithDeps.filter(t => t.dependencies.length === 0) - if (independentTasks.length > 0) { - independentTasks.forEach(t => processed.add(t.taskIndex)) - calls.push({ - method: executionMethod, - executionType: "parallel", - groupId: "P1", - taskSummary: independentTasks.map(t => t.title).join(' | '), - tasks: independentTasks - }) - } - - // Phase 2: Dependent tasks → sequential batches (respect dependencies) - let sequentialIndex = 1 - let remaining = tasksWithDeps.filter(t => !processed.has(t.taskIndex)) - - while (remaining.length > 0) { - // Find tasks whose dependencies are all satisfied - 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) - } - - // Group ready tasks (can run in parallel within this phase) - ready.forEach(t => processed.add(t.taskIndex)) - calls.push({ - method: executionMethod, - executionType: ready.length > 1 ? "parallel" : "sequential", - groupId: ready.length > 1 ? `P${calls.length + 1}` : `S${sequentialIndex++}`, - taskSummary: ready.map(t => t.title).join(ready.length > 1 ? ' | ' : ' → '), - tasks: ready - }) - - remaining = remaining.filter(t => !processed.has(t.taskIndex)) - } - - return calls -} - -executionCalls = createExecutionCalls(getTasks(planObject), executionMethod).map(c => ({ ...c, id: `[${c.groupId}]` })) - -TodoWrite({ - todos: executionCalls.map(c => ({ - content: `${c.executionType === "parallel" ? "⚡" : "→"} ${c.id} (${c.tasks.length} tasks)`, - status: "pending", - activeForm: `Executing ${c.id}` - })) -}) -``` - -### Step 3: Launch Execution - -**Executor Resolution** (任务级 executor 优先于全局设置): -```javascript -// 获取任务的 executor(优先使用 executorAssignments,fallback 到全局 executionMethod) -function getTaskExecutor(task) { - const assignments = executionContext?.executorAssignments || {} - if (assignments[task.id]) { - return assignments[task.id].executor // 'gemini' | 'codex' | 'agent' - } - // Fallback: 全局 executionMethod 映射 - const method = executionContext?.executionMethod || 'Auto' - if (method === 'Agent') return 'agent' - if (method === 'Codex') return 'codex' - // Auto: 根据复杂度 - return planObject.complexity === 'Low' ? 'agent' : 'codex' -} - -// 按 executor 分组任务 -function groupTasksByExecutor(tasks) { - const groups = { gemini: [], codex: [], agent: [] } - tasks.forEach(task => { - const executor = getTaskExecutor(task) - groups[executor].push(task) - }) - return groups -} -``` - -**Execution Flow**: Parallel batches concurrently → Sequential batches in order -```javascript -const parallel = executionCalls.filter(c => c.executionType === "parallel") -const sequential = executionCalls.filter(c => c.executionType === "sequential") - -// Phase 1: Launch all parallel batches (single message with multiple tool calls) -if (parallel.length > 0) { - TodoWrite({ todos: executionCalls.map(c => ({ status: c.executionType === "parallel" ? "in_progress" : "pending" })) }) - parallelResults = await Promise.all(parallel.map(c => executeBatch(c))) - previousExecutionResults.push(...parallelResults) - TodoWrite({ todos: executionCalls.map(c => ({ status: parallel.includes(c) ? "completed" : "pending" })) }) -} - -// Phase 2: Execute sequential batches one by one -for (const call of sequential) { - TodoWrite({ todos: executionCalls.map(c => ({ status: c === call ? "in_progress" : "..." })) }) - result = await executeBatch(call) - previousExecutionResults.push(result) - TodoWrite({ todos: executionCalls.map(c => ({ status: "completed" or "pending" })) }) -} -``` - -### Unified Task Prompt Builder - -**Task Formatting Principle**: Each task is a self-contained checklist. The executor only needs to know what THIS task requires. Same template for Agent and CLI. - -```javascript -function buildExecutionPrompt(batch) { - // Task template (6 parts: Files → Why → How → Reference → Risks → Done) - const formatTask = (t) => ` -## ${t.title} - -**Scope**: \`${t.scope}\` | **Action**: ${t.action} - -### Files -${(t.files || []).map(f => `- **${f.path}** → \`${f.target || ''}\`: ${f.change || (f.changes || []).join(', ') || ''}`).join('\n')} - -${t.rationale ? ` -### Why this approach (Medium/High) -${t.rationale.chosen_approach} -${t.rationale.decision_factors?.length > 0 ? `\nKey factors: ${t.rationale.decision_factors.join(', ')}` : ''} -${t.rationale.tradeoffs ? `\nTradeoffs: ${t.rationale.tradeoffs}` : ''} -` : ''} - -### How to do it -${t.description} - -${t.implementation.map(step => `- ${step}`).join('\n')} - -${t.code_skeleton ? ` -### Code skeleton (High) -${t.code_skeleton.interfaces?.length > 0 ? `**Interfaces**: ${t.code_skeleton.interfaces.map(i => `\`${i.name}\` - ${i.purpose}`).join(', ')}` : ''} -${t.code_skeleton.key_functions?.length > 0 ? `\n**Functions**: ${t.code_skeleton.key_functions.map(f => `\`${f.signature}\` - ${f.purpose}`).join(', ')}` : ''} -${t.code_skeleton.classes?.length > 0 ? `\n**Classes**: ${t.code_skeleton.classes.map(c => `\`${c.name}\` - ${c.purpose}`).join(', ')}` : ''} -` : ''} - -### Reference -- Pattern: ${t.reference?.pattern || 'N/A'} -- Files: ${t.reference?.files?.join(', ') || 'N/A'} -${t.reference?.examples ? `- Notes: ${t.reference.examples}` : ''} - -${t.risks?.length > 0 ? ` -### Risk mitigations (High) -${t.risks.map(r => `- ${r.description} → **${r.mitigation}**`).join('\n')} -` : ''} - -### Done when -${(t.convergence?.criteria || []).map(c => `- [ ] ${c}`).join('\n')} -${(t.test?.success_metrics || []).length > 0 ? `\n**Success metrics**: ${t.test.success_metrics.join(', ')}` : ''}` - - // Build prompt - const sections = [] - - if (originalUserInput) sections.push(`## Goal\n${originalUserInput}`) - - sections.push(`## Tasks\n${batch.tasks.map(formatTask).join('\n\n---\n')}`) - - // Context (reference only) - 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')}`) - } - if (executionContext?.planObject?.data_flow?.diagram) { - context.push(`### Data Flow\n${executionContext.planObject.data_flow.diagram}`) - } - if (executionContext?.session?.artifacts?.plan) { - context.push(`### Artifacts\nPlan: ${executionContext.session.artifacts.plan}`) - } - // Project guidelines (user-defined constraints from /workflow:session:solidify) - 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') -} -``` - -**Option A: Agent Execution** - -When to use: -- `getTaskExecutor(task) === "agent"` -- 或 `executionMethod = "Agent"` (全局 fallback) -- 或 `executionMethod = "Auto" AND complexity = "Low"` (全局 fallback) - -```javascript -Task( - subagent_type="code-developer", - run_in_background=false, - description=batch.taskSummary, - prompt=buildExecutionPrompt(batch) -) -``` - -**Result Collection**: After completion, collect result following `executionResult` structure (see Data Structures section) - -**Option B: CLI Execution (Codex)** - -When to use: -- `getTaskExecutor(task) === "codex"` -- 或 `executionMethod = "Codex"` (全局 fallback) -- 或 `executionMethod = "Auto" AND complexity = "Medium/High"` (全局 fallback) - -```bash -ccw cli -p "${buildExecutionPrompt(batch)}" --tool codex --mode write -``` - -**Execution with fixed IDs** (predictable ID pattern): -```javascript -// Launch CLI in background, wait for task hook callback -// Generate fixed execution ID: ${sessionId}-${groupId} -const sessionId = executionContext?.session?.id || 'standalone' -const fixedExecutionId = `${sessionId}-${batch.groupId}` // e.g., "implement-auth-2025-12-13-P1" - -// Check if resuming from previous failed execution -const previousCliId = batch.resumeFromCliId || null - -// Build command with fixed ID (and optional resume for continuation) -const cli_command = previousCliId - ? `ccw cli -p "${buildExecutionPrompt(batch)}" --tool codex --mode write --id ${fixedExecutionId} --resume ${previousCliId}` - : `ccw cli -p "${buildExecutionPrompt(batch)}" --tool codex --mode write --id ${fixedExecutionId}` - -// Execute in background, stop output and wait for task hook callback -Bash( - command=cli_command, - run_in_background=true -) -// STOP HERE - CLI executes in background, task hook will notify on completion -``` - -**Resume on Failure** (with fixed ID): -```javascript -// If execution failed or timed out, offer resume option -if (bash_result.status === 'failed' || bash_result.status === 'timeout') { - console.log(` -⚠️ Execution incomplete. Resume available: - Fixed ID: ${fixedExecutionId} - Lookup: ccw cli detail ${fixedExecutionId} - Resume: ccw cli -p "Continue tasks" --resume ${fixedExecutionId} --tool codex --mode write --id ${fixedExecutionId}-retry -`) - - // Store for potential retry in same session - batch.resumeFromCliId = fixedExecutionId -} -``` - -**Result Collection**: After completion, analyze output and collect result following `executionResult` structure (include `cliExecutionId` for resume capability) - -**Option C: CLI Execution (Gemini)** - -When to use: `getTaskExecutor(task) === "gemini"` (分析类任务) - -```bash -# 使用统一的 buildExecutionPrompt,切换 tool 和 mode -ccw cli -p "${buildExecutionPrompt(batch)}" --tool gemini --mode analysis --id ${sessionId}-${batch.groupId} -``` - -### Step 4: Progress Tracking - -Progress tracked at batch level (not individual task level). Icons: ⚡ (parallel, concurrent), → (sequential, one-by-one) - -### Step 5: Code Review (Optional) - -**Skip Condition**: Only run if `codeReviewTool ≠ "Skip"` - -**Review Focus**: Verify implementation against plan convergence criteria and test requirements -- Read plan.json + .task/*.json for task convergence criteria and test checklist -- Check each convergence criterion is fulfilled -- Verify success metrics from test field (Medium/High complexity) -- Run unit/integration tests specified in test field -- Validate code quality and identify issues -- Ensure alignment with planned approach and risk mitigations - -**Operations**: -- Agent Review: Current agent performs direct review -- Gemini Review: Execute gemini CLI with review prompt -- Codex Review: Two options - (A) with prompt for complex reviews, (B) `--uncommitted` flag only for quick reviews -- Custom tool: Execute specified CLI tool (qwen, etc.) - -**Unified Review Template** (All tools use same standard): - -**Review Criteria**: -- **Convergence Criteria**: Verify each criterion from task convergence.criteria -- **Test Checklist** (Medium/High): Check unit, integration, success_metrics from task test -- **Code Quality**: Analyze quality, identify issues, suggest improvements -- **Plan Alignment**: Validate implementation matches planned approach and risk mitigations - -**Shared Prompt Template** (used by all CLI tools): -``` -PURPOSE: Code review for implemented changes against plan convergence criteria and test requirements -TASK: • Verify plan convergence criteria fulfillment • Check test requirements (unit, integration, success_metrics) • Analyze code quality • Identify issues • Suggest improvements • Validate plan adherence and risk mitigations -MODE: analysis -CONTEXT: @**/* @{plan.json} @{.task/*.json} [@{exploration.json}] | Memory: Review lite-execute changes against plan requirements including test checklist -EXPECTED: Quality assessment with: - - Convergence criteria verification (all tasks from .task/*.json) - - Test checklist validation (Medium/High: unit, integration, success_metrics) - - Issue identification - - Recommendations - Explicitly check each convergence criterion and test item from .task/*.json files. -CONSTRAINTS: Focus on plan convergence criteria, test requirements, and plan adherence | analysis=READ-ONLY -``` - -**Tool-Specific Execution** (Apply shared prompt template above): - -```bash -# Method 1: Agent Review (current agent) -# - Read plan.json: ${executionContext.session.artifacts.plan} -# - Apply unified review criteria (see Shared Prompt Template) -# - Report findings directly - -# Method 2: Gemini Review (recommended) -ccw cli -p "[Shared Prompt Template with artifacts]" --tool gemini --mode analysis -# CONTEXT includes: @**/* @${plan.json} [@${exploration.json}] - -# Method 3: Qwen Review (alternative) -ccw cli -p "[Shared Prompt Template with artifacts]" --tool qwen --mode analysis -# Same prompt as Gemini, different execution engine - -# Method 4: Codex Review (git-aware) - Two mutually exclusive options: - -# Option A: With custom prompt (reviews uncommitted by default) -ccw cli -p "[Shared Prompt Template with artifacts]" --tool codex --mode review -# Use for complex reviews with specific focus areas - -# Option B: Target flag only (no prompt allowed) -ccw cli --tool codex --mode review --uncommitted -# Quick review of uncommitted changes without custom instructions - -# ⚠️ IMPORTANT: -p prompt and target flags (--uncommitted/--base/--commit) are MUTUALLY EXCLUSIVE -``` - -**Multi-Round Review with Fixed IDs**: -```javascript -// Generate fixed review ID -const reviewId = `${sessionId}-review` - -// First review pass with fixed ID -const reviewResult = Bash(`ccw cli -p "[Review prompt]" --tool gemini --mode analysis --id ${reviewId}`) - -// If issues found, continue review dialog with fixed ID chain -if (hasUnresolvedIssues(reviewResult)) { - // Resume with follow-up questions - Bash(`ccw cli -p "Clarify the security concerns you mentioned" --resume ${reviewId} --tool gemini --mode analysis --id ${reviewId}-followup`) -} -``` - -**Implementation Note**: Replace `[Shared Prompt Template with artifacts]` placeholder with actual template content, substituting: -- `@{plan.json}` → `@${executionContext.session.artifacts.plan}` -- `[@{exploration.json}]` → exploration files from artifacts (if exists) - -### Step 6: Update Development Index - -**Trigger**: After all executions complete (regardless of code review) - -**Skip Condition**: Skip if `.workflow/project-tech.json` does not exist - -**Operations**: -```javascript -const projectJsonPath = '.workflow/project-tech.json' -if (!fileExists(projectJsonPath)) return // Silent skip - -const projectJson = JSON.parse(Read(projectJsonPath)) - -// Initialize if needed -if (!projectJson.development_index) { - projectJson.development_index = { feature: [], enhancement: [], bugfix: [], refactor: [], docs: [] } -} - -// Detect category from keywords -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' -} - -// Detect sub_feature from task file paths -function detectSubFeature(tasks) { - const dirs = tasks.map(t => t.file?.split('/').slice(-2, -1)[0]).filter(Boolean) - const counts = dirs.reduce((a, d) => { a[d] = (a[d] || 0) + 1; return a }, {}) - return Object.entries(counts).sort((a, b) => b[1] - a[1])[0]?.[0] || 'general' -} - -const category = detectCategory(`${planObject.summary} ${planObject.approach}`) -const entry = { - title: planObject.summary.slice(0, 60), - sub_feature: detectSubFeature(getTasks(planObject)), - date: new Date().toISOString().split('T')[0], - description: planObject.approach.slice(0, 100), - status: previousExecutionResults.every(r => r.status === 'completed') ? 'completed' : 'partial', - session_id: executionContext?.session?.id || null -} - -projectJson.development_index[category].push(entry) -projectJson.statistics.last_updated = new Date().toISOString() -Write(projectJsonPath, JSON.stringify(projectJson, null, 2)) - -console.log(`✓ Development index: [${category}] ${entry.title}`) -``` - -## Best Practices - -**Input Modes**: In-memory (lite-plan), prompt (standalone), file (JSON/text) -**Task Grouping**: Based on explicit depends_on only; independent tasks run in single parallel batch -**Execution**: All independent tasks launch concurrently via single Claude message with multiple tool calls - -## Error Handling - -| Error | Cause | Resolution | -|-------|-------|------------| -| Missing executionContext | --in-memory without context | Error: "No execution context found. Only available when called by lite-plan." | -| File not found | File path doesn't exist | Error: "File not found: {path}. Check file path." | -| Empty file | File exists but no content | Error: "File is empty: {path}. Provide task description." | -| Invalid Enhanced Task JSON | JSON missing required fields | Warning: "Missing required fields. Treating as plain text." | -| Malformed JSON | JSON parsing fails | Treat as plain text (expected for non-JSON files) | -| Execution failure | Agent/Codex crashes | Display error, use fixed ID `${sessionId}-${groupId}` for resume: `ccw cli -p "Continue" --resume --id -retry` | -| Execution timeout | CLI exceeded timeout | Use fixed ID for resume with extended timeout | -| Codex unavailable | Codex not installed | Show installation instructions, offer Agent execution | -| Fixed ID not found | Custom ID lookup failed | Check `ccw cli history`, verify date directories | - -## Data Structures - -### executionContext (Input - Mode 1) - -Passed from lite-plan via global variable: - -```javascript -{ - planObject: { - summary: string, - approach: string, - task_ids: string[], // Task IDs referencing .task/*.json files - task_count: number, // Number of tasks - _loadedTasks: [...], // Populated at runtime from .task/*.json files - estimated_time: string, - recommended_execution: string, - complexity: string - }, - // Task file paths (populated for two-layer format) - taskFiles: [{id: string, path: string}] | null, - explorationsContext: {...} | null, // Multi-angle explorations - explorationAngles: string[], // List of exploration angles - explorationManifest: {...} | null, // Exploration manifest - clarificationContext: {...} | null, - executionMethod: "Agent" | "Codex" | "Auto", // 全局默认 - codeReviewTool: "Skip" | "Gemini Review" | "Agent Review" | string, - originalUserInput: string, - - // 任务级 executor 分配(优先于 executionMethod) - executorAssignments: { - [taskId]: { executor: "gemini" | "codex" | "agent", reason: string } - }, - - // Session artifacts location (saved by lite-plan) - session: { - id: string, // Session identifier: {taskSlug}-{shortTimestamp} - folder: string, // Session folder path: .workflow/.lite-plan/{session-id} - artifacts: { - explorations: [{angle, path}], // exploration-{angle}.json paths - explorations_manifest: string, // explorations-manifest.json path - plan: string // plan.json path (always present) - } - } -} -``` - -**Artifact Usage**: -- Artifact files contain detailed planning context -- Pass artifact paths to CLI tools and agents for enhanced context -- See execution options below for usage examples - -### executionResult (Output) - -Collected after each execution call completes: - -```javascript -{ - executionId: string, // e.g., "[Agent-1]", "[Codex-1]" - status: "completed" | "partial" | "failed", - tasksSummary: string, // Brief description of tasks handled - completionSummary: string, // What was completed - keyOutputs: string, // Files created/modified, key changes - notes: string, // Important context for next execution - fixedCliId: string | null // Fixed CLI execution ID (e.g., "implement-auth-2025-12-13-P1") -} -``` - -Appended to `previousExecutionResults` array for context continuity in multi-execution scenarios. - -## Post-Completion Expansion - -完成后询问用户是否扩展为issue(test/enhance/refactor/doc),选中项调用 `/issue:new "{summary} - {dimension}"` - -**Fixed ID Pattern**: `${sessionId}-${groupId}` enables predictable lookup without auto-generated timestamps. - -**Resume Usage**: If `status` is "partial" or "failed", use `fixedCliId` to resume: -```bash -# Lookup previous execution -ccw cli detail ${fixedCliId} - -# Resume with new fixed ID for retry -ccw cli -p "Continue from where we left off" --resume ${fixedCliId} --tool codex --mode write --id ${fixedCliId}-retry -``` diff --git a/.claude/commands/workflow/lite-fix.md b/.claude/commands/workflow/lite-fix.md deleted file mode 100644 index 985020f1..00000000 --- a/.claude/commands/workflow/lite-fix.md +++ /dev/null @@ -1,878 +0,0 @@ ---- -name: lite-fix -description: Lightweight bug diagnosis and fix workflow with intelligent severity assessment and optional hotfix mode for production incidents -argument-hint: "[-y|--yes] [--hotfix] \"bug description or issue reference\"" -allowed-tools: TodoWrite(*), Task(*), Skill(*), AskUserQuestion(*) ---- - -# Workflow Lite-Fix Command (/workflow:lite-fix) - -## Overview - -Intelligent lightweight bug fixing command with dynamic workflow adaptation based on severity assessment. Focuses on diagnosis phases (root cause analysis, impact assessment, fix planning, confirmation) and delegates execution to `/workflow:lite-execute`. - -**Core capabilities:** -- Intelligent bug analysis with automatic severity detection -- Dynamic code diagnosis (cli-explore-agent) for root cause identification -- Interactive clarification after diagnosis to gather missing information -- Adaptive fix planning strategy (direct Claude vs cli-lite-planning-agent) based on complexity -- Two-step confirmation: fix-plan display -> multi-dimensional input collection -- Execution execute with complete context handoff to lite-execute - -## Usage - -```bash -/workflow:lite-fix [FLAGS] - -# Flags --y, --yes Skip all confirmations (auto mode) ---hotfix, -h Production hotfix mode (minimal diagnosis, fast fix) - -# Arguments - Bug description, error message, or path to .md file (required) - -# Examples -/workflow:lite-fix "用户登录失败" # Interactive mode -/workflow:lite-fix --yes "用户登录失败" # Auto mode (no confirmations) -/workflow:lite-fix -y --hotfix "生产环境数据库连接失败" # Auto + hotfix mode -``` - -## Output Artifacts - -| Artifact | Description | -|----------|-------------| -| `diagnosis-{angle}.json` | Per-angle diagnosis results (1-4 files based on severity) | -| `diagnoses-manifest.json` | Index of all diagnosis files | -| `planning-context.md` | Evidence paths + synthesized understanding | -| `fix-plan.json` | Fix plan overview with `task_ids[]` (plan-overview-fix-schema.json) | -| `.task/FIX-*.json` | Independent fix task files (one per task) | - -**Output Directory**: `.workflow/.lite-fix/{bug-slug}-{YYYY-MM-DD}/` - -**Agent Usage**: -- Low/Medium severity → Direct Claude planning (no agent) -- High/Critical severity → `cli-lite-planning-agent` generates `fix-plan.json` - -**Schema Reference**: `~/.ccw/workflows/cli-templates/schemas/plan-overview-fix-schema.json` - -## Auto Mode Defaults - -When `--yes` or `-y` flag is used: -- **Clarification Questions**: Skipped (no clarification phase) -- **Fix Plan Confirmation**: Auto-selected "Allow" -- **Execution Method**: Auto-selected "Auto" -- **Code Review**: Auto-selected "Skip" -- **Severity**: Uses auto-detected severity (no manual override) -- **Hotfix Mode**: Respects --hotfix flag if present, otherwise normal mode - -**Flag Parsing**: -```javascript -const autoYes = $ARGUMENTS.includes('--yes') || $ARGUMENTS.includes('-y') -const hotfixMode = $ARGUMENTS.includes('--hotfix') || $ARGUMENTS.includes('-h') -``` - -## Execution Process - -``` -Phase 1: Bug Analysis & Diagnosis - |- Parse input (description, error message, or .md file) - |- Intelligent severity pre-assessment (Low/Medium/High/Critical) - |- Diagnosis decision (auto-detect or --hotfix flag) - |- Context protection: If file reading >=50k chars -> force cli-explore-agent - +- Decision: - |- needsDiagnosis=true -> Launch parallel cli-explore-agents (1-4 based on severity) - +- needsDiagnosis=false (hotfix) -> Skip directly to Phase 3 (Fix Planning) - -Phase 2: Clarification (optional, multi-round) - |- Aggregate clarification_needs from all diagnosis angles - |- Deduplicate similar questions - +- Decision: - |- Has clarifications -> AskUserQuestion (max 4 questions per round, multiple rounds allowed) - +- No clarifications -> Skip to Phase 3 - -Phase 3: Fix Planning (NO CODE EXECUTION - planning only) - +- Decision (based on Phase 1 severity): - |- Low/Medium -> Load schema: cat ~/.ccw/workflows/cli-templates/schemas/plan-overview-fix-schema.json -> Direct Claude planning (following schema) -> fix-plan.json -> MUST proceed to Phase 4 - +- High/Critical -> cli-lite-planning-agent -> fix-plan.json -> MUST proceed to Phase 4 - -Phase 4: Confirmation & Selection - |- Display fix-plan summary (tasks, severity, estimated time) - +- AskUserQuestion: - |- Confirm: Allow / Modify / Cancel - |- Execution: Agent / Codex / Auto - +- Review: Gemini / Agent / Skip - -Phase 5: Execute - |- Build executionContext (fix-plan + diagnoses + clarifications + selections) - +- Skill(skill="workflow:lite-execute", args="--in-memory --mode bugfix") -``` - -## Implementation - -### Phase 1: Intelligent Multi-Angle Diagnosis - -**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 bugSlug = bug_description.toLowerCase().replace(/[^a-z0-9]+/g, '-').substring(0, 40) -const dateStr = getUtc8ISOString().substring(0, 10) // Format: 2025-11-29 - -const sessionId = `${bugSlug}-${dateStr}` // e.g., "user-avatar-upload-fails-2025-11-29" -const sessionFolder = `.workflow/.lite-fix/${sessionId}` - -bash(`mkdir -p ${sessionFolder} && test -d ${sessionFolder} && echo "SUCCESS: ${sessionFolder}" || echo "FAILED: ${sessionFolder}"`) -``` - -**Diagnosis Decision Logic**: -```javascript -const hotfixMode = $ARGUMENTS.includes('--hotfix') || $ARGUMENTS.includes('-h') - -needsDiagnosis = ( - !hotfixMode && - ( - bug.lacks_specific_error_message || - bug.requires_codebase_context || - bug.needs_execution_tracing || - bug.root_cause_unclear - ) -) - -if (!needsDiagnosis) { - // Skip to Phase 2 (Clarification) or Phase 3 (Fix Planning) - proceed_to_next_phase() -} -``` - -**Context Protection**: File reading >=50k chars -> force `needsDiagnosis=true` (delegate to cli-explore-agent) - -**Severity Pre-Assessment** (Intelligent Analysis): -```javascript -// Analyzes bug severity based on: -// - Symptoms: Error messages, crash reports, user complaints -// - Scope: How many users/features are affected? -// - Urgency: Production down vs minor inconvenience -// - Impact: Data loss, security, business impact - -const severity = analyzeBugSeverity(bug_description) -// Returns: 'Low' | 'Medium' | 'High' | 'Critical' -// Low: Minor UI issue, localized, no data impact -// Medium: Multiple users affected, degraded functionality -// High: Significant functionality broken, many users affected -// Critical: Production down, data loss risk, security issue - -// Angle assignment based on bug type (orchestrator decides, not agent) -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' // default - - 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 selectedAngles = selectDiagnosisAngles(bug_description, severity === 'Critical' ? 4 : (severity === 'High' ? 3 : (severity === 'Medium' ? 2 : 1))) - -console.log(` -## Diagnosis Plan - -Bug Severity: ${severity} -Selected Angles: ${selectedAngles.join(', ')} - -Launching ${selectedAngles.length} parallel diagnoses... -`) -``` - -**Launch Parallel Diagnoses** - Orchestrator assigns angle to each agent: - -```javascript -// Launch agents with pre-assigned diagnosis angles -const diagnosisTasks = selectedAngles.map((angle, index) => - Task( - subagent_type="cli-explore-agent", - run_in_background=false, - description=`Diagnose: ${angle}`, - prompt=` -## Task Objective -Execute **${angle}** diagnosis for bug root cause analysis. Analyze codebase from this specific angle to discover root cause, affected paths, and fix hints. - -## Output Location - -**Session Folder**: ${sessionFolder} -**Output File**: ${sessionFolder}/diagnosis-${angle}.json - -## Assigned Context -- **Diagnosis Angle**: ${angle} -- **Bug Description**: ${bug_description} -- **Diagnosis Index**: ${index + 1} of ${selectedAngles.length} - -## MANDATORY FIRST STEPS (Execute by Agent) -**You (cli-explore-agent) MUST execute these steps in order:** -1. Run: ccw tool exec get_modules_by_depth '{}' (project structure) -2. Run: rg -l "{error_keyword_from_bug}" --type ts (locate relevant files) -3. Execute: cat ~/.ccw/workflows/cli-templates/schemas/diagnosis-json-schema.json (get output schema reference) -4. Read: .workflow/project-tech.json (technology stack and architecture context) -5. Read: .workflow/project-guidelines.json (user-defined constraints and conventions) - -## Diagnosis Strategy (${angle} focus) - -**Step 1: Error Tracing** (Bash) -- rg for error messages, stack traces, log patterns -- git log --since='2 weeks ago' for recent changes -- Trace execution path in affected modules - -**Step 2: Root Cause Analysis** (Gemini CLI) -- What code paths lead to this ${angle} issue? -- What edge cases are not handled from ${angle} perspective? -- What recent changes might have introduced this bug? - -**Step 3: Write Output** -- Consolidate ${angle} findings into JSON -- Identify ${angle}-specific clarification needs -- Provide fix hints based on ${angle} analysis - -## Expected Output - -**Schema Reference**: Schema obtained in MANDATORY FIRST STEPS step 3, follow schema exactly - -**Required Fields** (all ${angle} focused): -- symptom: Bug symptoms and error messages -- root_cause: Root cause hypothesis from ${angle} perspective - **IMPORTANT**: Use structured format: - \`{file: "src/module/file.ts", line_range: "45-60", issue: "Description", confidence: 0.85}\` -- affected_files: Files involved from ${angle} perspective - **MANDATORY**: Every file MUST use structured object format with ALL required fields: - \`[{path: "src/file.ts", relevance: 0.85, rationale: "Contains handleLogin() at line 45 where null check is missing", change_type: "fix_target", discovery_source: "bash-scan", key_symbols: ["handleLogin"]}]\` - - **rationale** (required): Specific reason why this file is affected (>10 chars, not generic) - - **change_type** (required): fix_target|needs_update|test_coverage|reference_only - - **discovery_source** (recommended): bash-scan|cli-analysis|ace-search|dependency-trace|stack-trace|manual - - **key_symbols** (recommended): Key functions/classes related to the bug -- reproduction_steps: Steps to reproduce the bug -- fix_hints: Suggested fix approaches from ${angle} viewpoint -- dependencies: Dependencies relevant to ${angle} diagnosis -- constraints: ${angle}-specific limitations affecting fix -- clarification_needs: ${angle}-related ambiguities (options array + recommended index) -- _metadata.diagnosis_angle: "${angle}" -- _metadata.diagnosis_index: ${index + 1} - -## Success Criteria -- [ ] Schema obtained via cat diagnosis-json-schema.json -- [ ] get_modules_by_depth.sh executed -- [ ] Root cause identified with confidence score -- [ ] At least 3 affected files identified with specific rationale + change_type -- [ ] Every file has rationale >10 chars (not generic like "Contains ${angle} logic") -- [ ] Every file has change_type classification (fix_target/needs_update/etc.) -- [ ] Fix hints are actionable (specific code changes, not generic advice) -- [ ] Reproduction steps are verifiable -- [ ] JSON output follows schema exactly -- [ ] clarification_needs includes options + recommended - -## Execution -**Write**: \`${sessionFolder}/diagnosis-${angle}.json\` -**Return**: 2-3 sentence summary of ${angle} diagnosis findings -` - ) -) - -// Execute all diagnosis tasks in parallel -``` - -**Auto-discover Generated Diagnosis Files**: -```javascript -// After diagnoses complete, auto-discover all diagnosis-*.json files -const diagnosisFiles = bash(`find ${sessionFolder} -name "diagnosis-*.json" -type f`) - .split('\n') - .filter(f => f.trim()) - -// Read metadata to build manifest -const diagnosisManifest = { - session_id: sessionId, - bug_description: bug_description, - timestamp: getUtc8ISOString(), - severity: severity, - diagnosis_count: diagnosisFiles.length, - diagnoses: diagnosisFiles.map(file => { - const data = JSON.parse(Read(file)) - const filename = path.basename(file) - return { - angle: data._metadata.diagnosis_angle, - file: filename, - path: file, - index: data._metadata.diagnosis_index - } - }) -} - -Write(`${sessionFolder}/diagnoses-manifest.json`, JSON.stringify(diagnosisManifest, null, 2)) - -console.log(` -## Diagnosis Complete - -Generated diagnosis files in ${sessionFolder}: -${diagnosisManifest.diagnoses.map(d => `- diagnosis-${d.angle}.json (angle: ${d.angle})`).join('\n')} - -Manifest: diagnoses-manifest.json -Angles diagnosed: ${diagnosisManifest.diagnoses.map(d => d.angle).join(', ')} -`) -``` - -**Output**: -- `${sessionFolder}/diagnosis-{angle1}.json` -- `${sessionFolder}/diagnosis-{angle2}.json` -- ... (1-4 files based on severity) -- `${sessionFolder}/diagnoses-manifest.json` - ---- - -### Phase 2: Clarification (Optional, Multi-Round) - -**Skip if**: No diagnosis or `clarification_needs` is empty across all diagnoses - -**⚠️ CRITICAL**: AskUserQuestion tool limits max 4 questions per call. **MUST execute multiple rounds** to exhaust all clarification needs - do NOT stop at round 1. - -**Aggregate clarification needs from all diagnosis angles**: -```javascript -// Load manifest and all diagnosis files -const manifest = JSON.parse(Read(`${sessionFolder}/diagnoses-manifest.json`)) -const diagnoses = manifest.diagnoses.map(diag => ({ - angle: diag.angle, - data: JSON.parse(Read(diag.path)) -})) - -// Aggregate clarification needs from all diagnoses -const allClarifications = [] -diagnoses.forEach(diag => { - if (diag.data.clarification_needs?.length > 0) { - diag.data.clarification_needs.forEach(need => { - allClarifications.push({ - ...need, - source_angle: diag.angle - }) - }) - } -}) - -// Deduplicate by question similarity -function deduplicateClarifications(clarifications) { - const unique = [] - clarifications.forEach(c => { - const isDuplicate = unique.some(u => - u.question.toLowerCase() === c.question.toLowerCase() - ) - if (!isDuplicate) unique.push(c) - }) - return unique -} - -const uniqueClarifications = deduplicateClarifications(allClarifications) - -// Parse --yes flag -const autoYes = $ARGUMENTS.includes('--yes') || $ARGUMENTS.includes('-y') - -if (autoYes) { - // Auto mode: Skip clarification phase - console.log(`[--yes] Skipping ${uniqueClarifications.length} clarification questions`) - console.log(`Proceeding to fix planning with diagnosis results...`) - // Continue to Phase 3 -} else if (uniqueClarifications.length > 0) { - // Interactive mode: Multi-round clarification - // ⚠️ MUST execute ALL rounds until uniqueClarifications exhausted - const BATCH_SIZE = 4 - const totalRounds = Math.ceil(uniqueClarifications.length / BATCH_SIZE) - - for (let i = 0; i < uniqueClarifications.length; i += BATCH_SIZE) { - const batch = uniqueClarifications.slice(i, i + BATCH_SIZE) - const currentRound = Math.floor(i / BATCH_SIZE) + 1 - - console.log(`### Clarification Round ${currentRound}/${totalRounds}`) - - AskUserQuestion({ - questions: batch.map(need => ({ - question: `[${need.source_angle}] ${need.question}\n\nContext: ${need.context}`, - header: need.source_angle, - multiSelect: false, - options: need.options.map((opt, index) => { - const isRecommended = need.recommended === index - return { - label: isRecommended ? `${opt} ★` : opt, - description: isRecommended ? `Use ${opt} approach (Recommended)` : `Use ${opt} approach` - } - }) - })) - }) - - // Store batch responses in clarificationContext before next round - } -} -``` - -**Output**: `clarificationContext` (in-memory) - ---- - -### Phase 3: Fix Planning - -**Planning Strategy Selection** (based on Phase 1 severity): - -**IMPORTANT**: Phase 3 is **planning only** - NO code execution. All execution happens in Phase 5 via lite-execute. - -**Low/Medium Severity** - Direct planning by Claude: -```javascript -// Step 1: Read schema -const schema = Bash(`cat ~/.ccw/workflows/cli-templates/schemas/plan-overview-fix-schema.json`) - -// Step 2: Generate fix tasks with NEW field names (Claude directly, no agent) -// Field mapping: modification_points -> files, acceptance -> convergence, verification -> test -const fixTasks = [ - { - id: "FIX-001", - title: "...", - description: "...", - scope: "...", - action: "Fix|Update|Refactor|Add|Delete", - depends_on: [], - convergence: { - criteria: ["..."] // Quantified acceptance criteria - }, - files: [ - { path: "src/module/file.ts", action: "modify", target: "functionName", change: "Description of change" } - ], - implementation: ["Step 1: ...", "Step 2: ..."], - test: { - manual_checks: ["Reproduce issue", "Verify fix"], - success_metrics: ["Issue resolved", "No regressions"] - }, - complexity: "Low|Medium", - - // Medium severity fields (optional for Low, recommended for Medium) - ...(severity === "Medium" ? { - rationale: { - chosen_approach: "Direct fix approach", - alternatives_considered: ["Workaround", "Refactor"], - decision_factors: ["Minimal impact", "Quick turnaround"], - tradeoffs: "Doesn't address underlying issue" - }, - test: { - unit: ["test_bug_fix_basic"], - integration: [], - manual_checks: ["Reproduce issue", "Verify fix"], - success_metrics: ["Issue resolved", "No regressions"] - } - } : {}) - } - // ... additional tasks as needed -] - -// Step 3: Write individual task files to .task/ directory -const taskDir = `${sessionFolder}/.task` -Bash(`mkdir -p "${taskDir}"`) - -fixTasks.forEach(task => { - Write(`${taskDir}/${task.id}.json`, JSON.stringify(task, null, 2)) -}) - -// Step 4: Generate fix-plan overview (NO embedded tasks[]) -const fixPlan = { - summary: "...", - approach: "...", - task_ids: fixTasks.map(t => t.id), - task_count: fixTasks.length, - fix_context: { - root_cause: "...", - strategy: "immediate_patch|comprehensive_fix|refactor", - severity: severity, - risk_level: "..." - }, - estimated_time: "...", - recommended_execution: "Agent", - - // Medium complexity fields (optional for Low) - ...(severity === "Medium" ? { - design_decisions: [ - { - decision: "Use immediate_patch strategy for minimal risk", - rationale: "Keeps changes localized and quick to review", - tradeoff: "Defers comprehensive refactoring" - } - ] - } : {}), - - _metadata: { - timestamp: getUtc8ISOString(), - source: "direct-planning", - planning_mode: "direct", - plan_type: "fix", - complexity: severity === "Medium" ? "Medium" : "Low" - } -} - -// Step 5: Write fix-plan overview to session folder -Write(`${sessionFolder}/fix-plan.json`, JSON.stringify(fixPlan, null, 2)) - -// Step 6: MUST continue to Phase 4 (Confirmation) - DO NOT execute code here -``` - -**High/Critical Severity** - Invoke cli-lite-planning-agent: - -```javascript -Task( - subagent_type="cli-lite-planning-agent", - run_in_background=false, - description="Generate detailed fix plan", - prompt=` -Generate fix plan using two-layer output format. - -## Output Location - -**Session Folder**: ${sessionFolder} -**Output Files**: -- ${sessionFolder}/planning-context.md (evidence + understanding) -- ${sessionFolder}/fix-plan.json (fix plan overview -- NO embedded tasks[]) -- ${sessionFolder}/.task/FIX-*.json (independent fix task files, one per task) - -## Output Schema Reference -Execute: cat ~/.ccw/workflows/cli-templates/schemas/plan-overview-fix-schema.json (get schema reference before generating plan) - -## Project Context (MANDATORY - Read Both Files) -1. Read: .workflow/project-tech.json (technology stack, architecture, key components) -2. Read: .workflow/project-guidelines.json (user-defined constraints and conventions) - -**CRITICAL**: All fix tasks MUST comply with constraints in project-guidelines.json - -## Bug Description -${bug_description} - -## Multi-Angle Diagnosis Context - -${manifest.diagnoses.map(diag => `### Diagnosis: ${diag.angle} (${diag.file}) -Path: ${diag.path} - -Read this file for detailed ${diag.angle} analysis.`).join('\n\n')} - -Total diagnoses: ${manifest.diagnosis_count} -Angles covered: ${manifest.diagnoses.map(d => d.angle).join(', ')} - -Manifest: ${sessionFolder}/diagnoses-manifest.json - -## User Clarifications -${JSON.stringify(clarificationContext) || "None"} - -## Severity Level -${severity} - -## Requirements - -**Output Format**: Two-layer structure: -- fix-plan.json: Overview with task_ids[] referencing .task/ files (NO tasks[] array) -- .task/FIX-*.json: Independent task files following task-schema.json - -**fix-plan.json required fields**: -- summary: 2-3 sentence overview of the fix -- approach: Overall fix approach description -- task_ids: Array of task IDs (e.g., ["FIX-001", "FIX-002"]) -- task_count: Number of tasks -- fix_context: - - root_cause: Consolidated root cause from all diagnoses - - strategy: "immediate_patch" | "comprehensive_fix" | "refactor" - - severity: ${severity} - - risk_level: "Low" | "Medium" | "High" -- estimated_time, recommended_execution -- data_flow (High/Critical REQUIRED): How data flows through affected code - - diagram: "A -> B -> C" style flow - - stages: [{stage, input, output, component}] -- design_decisions (High/Critical REQUIRED): Global fix decisions - - [{decision, rationale, tradeoff}] -- _metadata: - - timestamp, source, planning_mode - - plan_type: "fix" - - complexity: "High" | "Critical" - - diagnosis_angles: ${JSON.stringify(manifest.diagnoses.map(d => d.angle))} - -**Each .task/FIX-*.json required fields**: -- id: "FIX-001" (prefix FIX-, NOT TASK-) -- title: action verb + target (e.g., "Fix token validation edge case") -- description -- scope: module path (src/auth/) or feature name -- action: "Fix" | "Update" | "Refactor" | "Add" | "Delete" -- depends_on: task IDs this task depends on (use sparingly) -- convergence: { criteria: ["Quantified acceptance criterion 1", "..."] } -- files: ALL files to modify for this fix (group related changes) - - [{ path: "src/file.ts", action: "modify|create|delete", target: "component/function", change: "Description of what changes" }] -- implementation: ["Step 1: ...", "Step 2: ..."] (2-5 steps covering all files) -- test: - - unit: ["test names to add/verify"] - - integration: ["integration test names"] - - manual_checks: ["manual verification steps"] - - success_metrics: ["quantified success criteria"] - - **High/Critical complexity fields per task** (REQUIRED): - - rationale: - - chosen_approach: Why this fix approach (not alternatives) - - alternatives_considered: Other approaches evaluated - - decision_factors: Key factors influencing choice - - tradeoffs: Known tradeoffs of this approach - - risks: - - description: Risk description - - probability: Low|Medium|High - - impact: Low|Medium|High - - mitigation: How to mitigate - - fallback: Fallback if fix fails - - code_skeleton (optional): Key interfaces/functions to implement - - interfaces: [{name, definition, purpose}] - - key_functions: [{signature, purpose, returns}] - -**Field name rules** (do NOT use old names): -- files[].change (NOT modification_points) -- convergence.criteria (NOT acceptance) -- test (NOT verification at task level) - -## Task Grouping Rules -1. **Group by fix area**: All changes for one fix = one task (even if 2-3 files) -2. **Avoid file-per-task**: Do NOT create separate tasks for each file -3. **Substantial tasks**: Each task should represent 10-45 minutes of work -4. **True dependencies only**: Only use depends_on when Task B cannot start without Task A's output -5. **Prefer parallel**: Most tasks should be independent (no depends_on) -6. **Task IDs**: Use FIX-001, FIX-002 prefix (NOT TASK-) - -## Execution -1. Read ALL diagnosis files for comprehensive context -2. Execute CLI planning using Gemini (Qwen fallback) with --rule planning-fix-strategy template -3. Synthesize findings from multiple diagnosis angles -4. Generate fix tasks (1-5 tasks): - - Each task file written to \`${sessionFolder}/.task/FIX-NNN.json\` - - For High/Critical: REQUIRED fields (rationale, test, risks, code_skeleton) -5. Generate fix-plan overview: - - Written to \`${sessionFolder}/fix-plan.json\` - - Contains task_ids[] referencing .task/ files (NO embedded tasks[]) - - For High/Critical: REQUIRED fields (data_flow, design_decisions) -6. **Write**: \`${sessionFolder}/planning-context.md\` (evidence paths + understanding) -7. **Write**: \`${sessionFolder}/.task/FIX-*.json\` (individual task files) -8. **Write**: \`${sessionFolder}/fix-plan.json\` (plan overview with task_ids[]) -9. Return brief completion summary - -## Output Format for CLI -Include these sections in your fix-plan output: -- Summary, Root Cause (in fix_context), Strategy (existing) -- Data Flow: Diagram showing affected code paths -- Design Decisions: Key architectural choices in the fix -- Task files: Each with convergence, files, test, rationale (High), risks (High), code_skeleton (High) -` -) -``` - -**Output**: `${sessionFolder}/fix-plan.json` - ---- - -### Phase 4: Task Confirmation & Execution Selection - -**Step 4.1: Display Fix Plan** -```javascript -const fixPlan = JSON.parse(Read(`${sessionFolder}/fix-plan.json`)) - -// Load tasks from .task/ directory (two-layer format) -const tasks = (fixPlan.task_ids || []).map(id => { - return JSON.parse(Read(`${sessionFolder}/.task/${id}.json`)) -}) -const taskList = tasks - -const fixContext = fixPlan.fix_context || {} - -console.log(` -## Fix Plan - -**Summary**: ${fixPlan.summary} -**Root Cause**: ${fixContext.root_cause || fixPlan.root_cause} -**Strategy**: ${fixContext.strategy || fixPlan.strategy} - -**Tasks** (${taskList.length}): -${taskList.map((t, i) => `${i+1}. ${t.title} (${t.scope})`).join('\n')} - -**Severity**: ${fixContext.severity || fixPlan.severity} -**Risk Level**: ${fixContext.risk_level || fixPlan.risk_level} -**Estimated Time**: ${fixPlan.estimated_time} -**Recommended**: ${fixPlan.recommended_execution} -`) -``` - -**Step 4.2: Collect Confirmation** -```javascript -// Parse --yes flag -const autoYes = $ARGUMENTS.includes('--yes') || $ARGUMENTS.includes('-y') - -let userSelection - -if (autoYes) { - // Auto mode: Use defaults - console.log(`[--yes] Auto-confirming fix plan:`) - console.log(` - Confirmation: Allow`) - console.log(` - Execution: Auto`) - console.log(` - Review: Skip`) - - userSelection = { - confirmation: "Allow", - execution_method: "Auto", - code_review_tool: "Skip" - } -} else { - // Interactive mode: Ask user - userSelection = AskUserQuestion({ - questions: [ - { - question: `Confirm fix plan? (${taskList.length} tasks, ${fixContext.severity || fixPlan.severity} severity)`, - header: "Confirm", - multiSelect: false, - options: [ - { label: "Allow", description: "Proceed as-is" }, - { label: "Modify", description: "Adjust before execution" }, - { label: "Cancel", description: "Abort workflow" } - ] - }, - { - question: "Execution method:", - header: "Execution", - multiSelect: false, - options: [ - { label: "Agent", description: "@code-developer agent" }, - { label: "Codex", description: "codex CLI tool" }, - { label: "Auto", description: `Auto: ${(fixContext.severity || fixPlan.severity) === 'Low' ? 'Agent' : 'Codex'}` } - ] - }, - { - question: "Code review after fix?", - header: "Review", - multiSelect: false, - options: [ - { label: "Gemini Review", description: "Gemini CLI" }, - { label: "Agent Review", description: "@code-reviewer" }, - { label: "Skip", description: "No review" } - ] - } - ] - }) -} -``` - ---- - -### Phase 5: Execute to Execution - -**CRITICAL**: lite-fix NEVER executes code directly. ALL execution MUST go through lite-execute. - -**Step 5.1: Build executionContext** - -```javascript -// Load manifest and all diagnosis files -const manifest = JSON.parse(Read(`${sessionFolder}/diagnoses-manifest.json`)) -const diagnoses = {} - -manifest.diagnoses.forEach(diag => { - if (file_exists(diag.path)) { - diagnoses[diag.angle] = JSON.parse(Read(diag.path)) - } -}) - -const fixPlan = JSON.parse(Read(`${sessionFolder}/fix-plan.json`)) - -const fixSeverity = fixPlan.fix_context?.severity || fixPlan.severity - -executionContext = { - mode: "bugfix", - severity: fixSeverity, - planObject: { - ...fixPlan, - // Ensure complexity is set based on severity for new field consumption - complexity: fixPlan.complexity || (fixSeverity === 'Critical' ? 'High' : (fixSeverity === 'High' ? 'High' : 'Medium')) - }, - // Task files from .task/ directory (two-layer format) - taskFiles: (fixPlan.task_ids || []).map(id => ({ - id, - path: `${sessionFolder}/.task/${id}.json` - })), - diagnosisContext: diagnoses, - diagnosisAngles: manifest.diagnoses.map(d => d.angle), - diagnosisManifest: manifest, - clarificationContext: clarificationContext || null, - executionMethod: userSelection.execution_method, - codeReviewTool: userSelection.code_review_tool, - originalUserInput: bug_description, - session: { - id: sessionId, - folder: sessionFolder, - artifacts: { - diagnoses: manifest.diagnoses.map(diag => ({ - angle: diag.angle, - path: diag.path - })), - diagnoses_manifest: `${sessionFolder}/diagnoses-manifest.json`, - fix_plan: `${sessionFolder}/fix-plan.json`, - task_dir: `${sessionFolder}/.task` - } - } -} -``` - -**Step 5.2: Execute** - -```javascript -Skill(skill="workflow:lite-execute", args="--in-memory --mode bugfix") -``` - -## Session Folder Structure - -``` -.workflow/.lite-fix/{bug-slug}-{YYYY-MM-DD}/ -├── diagnosis-{angle1}.json # Diagnosis angle 1 -├── diagnosis-{angle2}.json # Diagnosis angle 2 -├── diagnosis-{angle3}.json # Diagnosis angle 3 (if applicable) -├── diagnosis-{angle4}.json # Diagnosis angle 4 (if applicable) -├── diagnoses-manifest.json # Diagnosis index -├── planning-context.md # Evidence + understanding -├── fix-plan.json # Fix plan overview (task_ids[], NO embedded tasks[]) -└── .task/ # Independent fix task files - ├── FIX-001.json # Fix task 1 - ├── FIX-002.json # Fix task 2 - └── ... # Additional fix tasks -``` - -**Example**: -``` -.workflow/.lite-fix/user-avatar-upload-fails-413-2025-11-25/ -├── diagnosis-error-handling.json -├── diagnosis-dataflow.json -├── diagnosis-validation.json -├── diagnoses-manifest.json -├── planning-context.md -├── fix-plan.json -└── .task/ - ├── FIX-001.json - └── FIX-002.json -``` - -## Error Handling - -| Error | Resolution | -|-------|------------| -| Diagnosis agent failure | Skip diagnosis, continue with bug description only | -| Planning agent failure | Fallback to direct planning by Claude | -| Clarification timeout | Use diagnosis findings as-is | -| Confirmation timeout | Save context, display resume instructions | -| Modify loop > 3 times | Suggest breaking task or using /workflow:plan | -| Root cause unclear | Extend diagnosis time or use broader angles | -| Too complex for lite-fix | Escalate to /workflow:plan --mode bugfix | - - diff --git a/.claude/commands/workflow/lite-plan.md b/.claude/commands/workflow/lite-plan.md deleted file mode 100644 index 5323ea92..00000000 --- a/.claude/commands/workflow/lite-plan.md +++ /dev/null @@ -1,770 +0,0 @@ ---- -name: lite-plan -description: Lightweight interactive planning workflow with in-memory planning, code exploration, and execution execute to lite-execute after user confirmation -argument-hint: "[-y|--yes] [-e|--explore] \"task description\"|file.md" -allowed-tools: TodoWrite(*), Task(*), Skill(*), AskUserQuestion(*) ---- - -# Workflow Lite-Plan Command (/workflow:lite-plan) - -## Overview - -Intelligent lightweight planning command with dynamic workflow adaptation based on task complexity. Focuses on planning phases (exploration, clarification, planning, confirmation) and delegates execution to `/workflow:lite-execute`. - -**Core capabilities:** -- Intelligent task analysis with automatic exploration detection -- Dynamic code exploration (cli-explore-agent) when codebase understanding needed -- Interactive clarification after exploration to gather missing information -- Adaptive planning: Low complexity → Direct Claude; Medium/High → cli-lite-planning-agent -- Two-step confirmation: plan display → multi-dimensional input collection -- Execution execute with complete context handoff to lite-execute - -## Usage - -```bash -/workflow:lite-plan [FLAGS] - -# Flags --y, --yes Skip all confirmations (auto mode) --e, --explore Force code exploration phase (overrides auto-detection) - -# Arguments - Task description or path to .md file (required) - -# Examples -/workflow:lite-plan "实现JWT认证" # Interactive mode -/workflow:lite-plan --yes "实现JWT认证" # Auto mode (no confirmations) -/workflow:lite-plan -y -e "优化数据库查询性能" # Auto mode + force exploration -``` - -## Output Artifacts - -| Artifact | Description | -|----------|-------------| -| `exploration-{angle}.json` | Per-angle exploration results (1-4 files based on complexity) | -| `explorations-manifest.json` | Index of all exploration files | -| `planning-context.md` | Evidence paths + synthesized understanding | -| `plan.json` | Plan overview with task_ids[] (plan-overview-base-schema.json) | -| `.task/TASK-*.json` | Independent task files (one per task) | - -**Output Directory**: `.workflow/.lite-plan/{task-slug}-{YYYY-MM-DD}/` - -**Agent Usage**: -- Low complexity → Direct Claude planning (no agent) -- Medium/High complexity → `cli-lite-planning-agent` generates `plan.json` - -**Schema Reference**: `~/.ccw/workflows/cli-templates/schemas/plan-overview-base-schema.json` - -## Auto Mode Defaults - -When `--yes` or `-y` flag is used: -- **Clarification Questions**: Skipped (no clarification phase) -- **Plan Confirmation**: Auto-selected "Allow" -- **Execution Method**: Auto-selected "Auto" -- **Code Review**: Auto-selected "Skip" - -**Flag Parsing**: -```javascript -const autoYes = $ARGUMENTS.includes('--yes') || $ARGUMENTS.includes('-y') -const forceExplore = $ARGUMENTS.includes('--explore') || $ARGUMENTS.includes('-e') -``` - -## Execution Process - -``` -Phase 1: Task Analysis & Exploration - ├─ Parse input (description or .md file) - ├─ intelligent complexity assessment (Low/Medium/High) - ├─ Exploration decision (auto-detect or --explore flag) - ├─ Context protection: If file reading ≥50k chars → force cli-explore-agent - └─ Decision: - ├─ needsExploration=true → Launch parallel cli-explore-agents (1-4 based on complexity) - └─ needsExploration=false → Skip to Phase 2/3 - -Phase 2: Clarification (optional, multi-round) - ├─ Aggregate clarification_needs from all exploration angles - ├─ Deduplicate similar questions - └─ Decision: - ├─ Has clarifications → AskUserQuestion (max 4 questions per round, multiple rounds allowed) - └─ No clarifications → Skip to Phase 3 - -Phase 3: Planning (NO CODE EXECUTION - planning only) - └─ Decision (based on Phase 1 complexity): - ├─ Low → Load schema: cat ~/.ccw/workflows/cli-templates/schemas/plan-overview-base-schema.json → Direct Claude planning (following schema) → plan.json - └─ Medium/High → cli-lite-planning-agent → plan.json (agent internally executes quality check) - -Phase 4: Confirmation & Selection - ├─ Display plan summary (tasks, complexity, estimated time) - └─ AskUserQuestion: - ├─ Confirm: Allow / Modify / Cancel - ├─ Execution: Agent / Codex / Auto - └─ Review: Gemini / Agent / Skip - -Phase 5: Execute - ├─ Build executionContext (plan + explorations + clarifications + selections) - └─ Skill(skill="workflow:lite-execute", args="--in-memory") -``` - -## Implementation - -### Phase 1: Intelligent Multi-Angle Exploration - -**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_description.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}` - -bash(`mkdir -p ${sessionFolder} && test -d ${sessionFolder} && echo "SUCCESS: ${sessionFolder}" || echo "FAILED: ${sessionFolder}"`) -``` - -**Exploration Decision Logic**: -```javascript -needsExploration = ( - flags.includes('--explore') || flags.includes('-e') || - 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` (delegate to cli-explore-agent) - -**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_description) -// Returns: 'Low' | 'Medium' | 'High' -// Low: Single file, isolated change, minimal risk -// Medium: Multiple files, some dependencies, moderate risk -// High: Cross-module, architectural, high risk - -// Angle assignment based on task type (orchestrator decides, not agent) -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_description, complexity === 'High' ? 4 : (complexity === 'Medium' ? 3 : 1)) - -// Planning strategy determination -const planningStrategy = complexity === 'Low' - ? 'Direct Claude Planning' - : 'cli-lite-planning-agent' - -console.log(` -## Exploration Plan - -Task Complexity: ${complexity} -Selected Angles: ${selectedAngles.join(', ')} -Planning Strategy: ${planningStrategy} - -Launching ${selectedAngles.length} parallel explorations... -`) -``` - -**Launch Parallel Explorations** - Orchestrator assigns angle to each agent: - -**⚠️ CRITICAL - NO BACKGROUND EXECUTION**: -- **MUST NOT use `run_in_background: true`** - exploration results are REQUIRED before planning - - -```javascript -// Launch agents with pre-assigned angles -const explorationTasks = selectedAngles.map((angle, index) => - Task( - subagent_type="cli-explore-agent", - run_in_background=false, // ⚠️ MANDATORY: Must wait for results - description=`Explore: ${angle}`, - prompt=` -## Task Objective -Execute **${angle}** exploration for task planning context. Analyze codebase from this specific angle to discover relevant structure, patterns, and constraints. - -## Output Location - -**Session Folder**: ${sessionFolder} -**Output File**: ${sessionFolder}/exploration-${angle}.json - -## Assigned Context -- **Exploration Angle**: ${angle} -- **Task Description**: ${task_description} -- **Exploration Index**: ${index + 1} of ${selectedAngles.length} - -## MANDATORY FIRST STEPS (Execute by Agent) -**You (cli-explore-agent) MUST execute these steps in order:** -1. Run: ccw tool exec get_modules_by_depth '{}' (project structure) -2. Run: rg -l "{keyword_from_task}" --type ts (locate relevant files) -3. Execute: cat ~/.ccw/workflows/cli-templates/schemas/explore-json-schema.json (get output schema reference) -4. Read: .workflow/project-tech.json (technology stack and architecture context) -5. 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 - -**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 - **MANDATORY**: Every file MUST use structured object format with ALL required fields: - \`[{path: "src/file.ts", relevance: 0.85, rationale: "Contains AuthService.login() - entry point for JWT token generation", role: "modify_target", discovery_source: "bash-scan", key_symbols: ["AuthService", "login"]}]\` - - **rationale** (required): Specific selection basis tied to ${angle} topic (>10 chars, not generic) - - **role** (required): modify_target|dependency|pattern_reference|test_target|type_definition|integration_point|config|context_only - - **discovery_source** (recommended): bash-scan|cli-analysis|ace-search|dependency-trace|manual - - **key_symbols** (recommended): Key functions/classes/types in the file relevant to the task - - Scores: 0.7+ high priority, 0.5-0.7 medium, <0.5 low -- 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 specific rationale + role -- [ ] Every file has rationale >10 chars (not generic like "Related to ${angle}") -- [ ] Every file has role classification (modify_target/dependency/etc.) -- [ ] Patterns are actionable (code examples, not generic advice) -- [ ] Integration points include file:line locations -- [ ] Constraints are project-specific to ${angle} -- [ ] JSON output follows schema exactly -- [ ] clarification_needs includes options + recommended - -## Execution -**Write**: \`${sessionFolder}/exploration-${angle}.json\` -**Return**: 2-3 sentence summary of ${angle} findings -` - ) -) - -// Execute all exploration tasks in parallel -``` - -**Auto-discover Generated Exploration Files**: -```javascript -// After explorations complete, auto-discover all exploration-*.json files -const explorationFiles = bash(`find ${sessionFolder} -name "exploration-*.json" -type f`) - .split('\n') - .filter(f => f.trim()) - -// Read metadata to build manifest -const explorationManifest = { - session_id: sessionId, - task_description: task_description, - timestamp: getUtc8ISOString(), - complexity: complexity, - exploration_count: explorationCount, - explorations: explorationFiles.map(file => { - const data = JSON.parse(Read(file)) - const filename = path.basename(file) - return { - angle: data._metadata.exploration_angle, - file: filename, - 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, Multi-Round) - -**Skip if**: No exploration or `clarification_needs` is empty across all explorations - -**⚠️ CRITICAL**: AskUserQuestion tool limits max 4 questions per call. **MUST execute multiple rounds** to exhaust all clarification needs - do NOT stop at round 1. - -**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 -// - Identify questions with similar intent across different angles -// - Merge similar questions: combine options, consolidate context -// - Produce dedupedClarifications with unique intents only -const dedupedClarifications = intelligentMerge(allClarifications) - -// Parse --yes flag -const autoYes = $ARGUMENTS.includes('--yes') || $ARGUMENTS.includes('-y') - -if (autoYes) { - // Auto mode: Skip clarification phase - console.log(`[--yes] Skipping ${dedupedClarifications.length} clarification questions`) - console.log(`Proceeding to planning with exploration results...`) - // Continue to Phase 3 -} else if (dedupedClarifications.length > 0) { - // Interactive mode: Multi-round clarification - const BATCH_SIZE = 4 - const totalRounds = Math.ceil(dedupedClarifications.length / BATCH_SIZE) - - for (let i = 0; i < dedupedClarifications.length; i += BATCH_SIZE) { - const batch = dedupedClarifications.slice(i, i + BATCH_SIZE) - const currentRound = Math.floor(i / BATCH_SIZE) + 1 - - console.log(`### Clarification Round ${currentRound}/${totalRounds}`) - - AskUserQuestion({ - questions: batch.map(need => ({ - question: `[${need.source_angle}] ${need.question}\n\nContext: ${need.context}`, - header: need.source_angle.substring(0, 12), - multiSelect: false, - options: need.options.map((opt, index) => ({ - label: need.recommended === index ? `${opt} ★` : opt, - description: need.recommended === index ? `Recommended` : `Use ${opt}` - })) - })) - }) - - // Store batch responses in clarificationContext before next round - } -} -``` - -**Output**: `clarificationContext` (in-memory) - ---- - -### Phase 3: Planning - -**Planning Strategy Selection** (based on Phase 1 complexity): - -**IMPORTANT**: Phase 3 is **planning only** - NO code execution. All execution happens in Phase 5 via lite-execute. - -**Executor Assignment** (Claude 智能分配,plan 生成后执行): - -```javascript -// 分配规则(优先级从高到低): -// 1. 用户明确指定:"用 gemini 分析..." → gemini, "codex 实现..." → codex -// 2. 默认 → agent - -const executorAssignments = {} // { taskId: { executor: 'gemini'|'codex'|'agent', reason: string } } - -// Load tasks from .task/ directory for executor assignment -const taskFiles = Glob(`${sessionFolder}/.task/TASK-*.json`) -taskFiles.forEach(taskPath => { - const task = JSON.parse(Read(taskPath)) - // Claude 根据上述规则语义分析,为每个 task 分配 executor - executorAssignments[task.id] = { executor: '...', reason: '...' } -}) -``` - -**Low Complexity** - Direct planning by Claude: -```javascript -// Step 1: Read schema -const schema = Bash(`cat ~/.ccw/workflows/cli-templates/schemas/plan-overview-base-schema.json`) - -// Step 2: ⚠️ MANDATORY - Read and review ALL exploration files -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 task objects (Claude directly, no agent) -// ⚠️ Tasks MUST incorporate insights from exploration files read in Step 2 -// Task fields use NEW names: convergence.criteria (not acceptance), files[].change (not modification_points), test (not verification) -const tasks = [ - { - id: "TASK-001", - title: "...", - description: "...", - depends_on: [], - convergence: { criteria: ["..."] }, - files: [{ path: "...", change: "..." }], - implementation: ["..."], - test: "..." - }, - // ... more tasks -] - -// Step 4: Write task files to .task/ directory -const taskDir = `${sessionFolder}/.task` -Bash(`mkdir -p "${taskDir}"`) -tasks.forEach(task => { - Write(`${taskDir}/${task.id}.json`, JSON.stringify(task, null, 2)) -}) - -// Step 5: Generate plan overview (NO embedded tasks[]) -const plan = { - summary: "...", - approach: "...", - task_ids: tasks.map(t => t.id), - task_count: tasks.length, - complexity: "Low", - estimated_time: "...", - recommended_execution: "Agent", - _metadata: { - timestamp: getUtc8ISOString(), - source: "direct-planning", - planning_mode: "direct", - plan_type: "feature" - } -} - -// Step 6: Write plan overview to session folder -Write(`${sessionFolder}/plan.json`, JSON.stringify(plan, null, 2)) - -// Step 7: MUST continue to Phase 4 (Confirmation) - DO NOT execute code here -``` - -**Medium/High Complexity** - Invoke cli-lite-planning-agent: - -```javascript -Task( - subagent_type="cli-lite-planning-agent", - run_in_background=false, - description="Generate detailed implementation plan", - prompt=` -Generate implementation plan and write plan.json. - -## Output Location - -**Session Folder**: ${sessionFolder} -**Output Files**: -- ${sessionFolder}/planning-context.md (evidence + understanding) -- ${sessionFolder}/plan.json (plan overview -- NO embedded tasks[]) -- ${sessionFolder}/.task/TASK-*.json (independent task files, one per task) - -## Output Schema Reference -Execute: cat ~/.ccw/workflows/cli-templates/schemas/plan-overview-base-schema.json (get schema reference before generating plan) - -## Project Context (MANDATORY - Read Both Files) -1. Read: .workflow/project-tech.json (technology stack, architecture, key components) -2. 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_description} - -## 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 and .task/*.json following the schema obtained above. Key constraints: -- _metadata.exploration_angles: ${JSON.stringify(manifest.explorations.map(e => e.angle))} - -**Output Format**: Two-layer structure: -- plan.json: Overview with task_ids[] referencing .task/ files (NO tasks[] array) -- .task/TASK-*.json: Independent task files following task-schema.json - -plan.json required fields: summary, approach, task_ids, task_count, _metadata (with plan_type: "feature") -Each task file required fields: id, title, description, depends_on, convergence (with criteria[]) -Task fields use: files[].change (not modification_points), convergence.criteria (not acceptance), test (not verification) - -## 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 tasks + plan overview -5. **Write**: \`${sessionFolder}/planning-context.md\` (evidence paths + understanding) -6. **Create**: \`${sessionFolder}/.task/\` directory (mkdir -p) -7. **Write**: \`${sessionFolder}/.task/TASK-001.json\`, \`TASK-002.json\`, etc. (one per task) -8. **Write**: \`${sessionFolder}/plan.json\` (overview with task_ids[], NO tasks[]) -9. Return brief completion summary -` -) -``` - -**Output**: `${sessionFolder}/plan.json` - ---- - -### Phase 4: Task Confirmation & Execution Selection - -**Step 4.1: Display Plan** -```javascript -const plan = JSON.parse(Read(`${sessionFolder}/plan.json`)) - -// Load tasks from .task/ directory -const tasks = (plan.task_ids || []).map(id => { - const taskPath = `${sessionFolder}/.task/${id}.json` - return JSON.parse(Read(taskPath)) -}) -const taskList = tasks - -console.log(` -## Implementation Plan - -**Summary**: ${plan.summary} -**Approach**: ${plan.approach} - -**Tasks** (${taskList.length}): -${taskList.map((t, i) => `${i+1}. ${t.title} (${t.scope || t.files?.[0]?.path || ''})`).join('\n')} - -**Complexity**: ${plan.complexity} -**Estimated Time**: ${plan.estimated_time} -**Recommended**: ${plan.recommended_execution} -`) -``` - -**Step 4.2: Collect Confirmation** -```javascript -// Parse --yes flag -const autoYes = $ARGUMENTS.includes('--yes') || $ARGUMENTS.includes('-y') - -let userSelection - -if (autoYes) { - // Auto mode: Use defaults - console.log(`[--yes] Auto-confirming plan:`) - console.log(` - Confirmation: Allow`) - console.log(` - Execution: Auto`) - console.log(` - Review: Skip`) - - userSelection = { - confirmation: "Allow", - execution_method: "Auto", - code_review_tool: "Skip" - } -} else { - // Interactive mode: Ask user - // Note: Execution "Other" option allows specifying CLI tools from ~/.claude/cli-tools.json - userSelection = AskUserQuestion({ - questions: [ - { - question: `Confirm plan? (${taskList.length} tasks, ${plan.complexity})`, - header: "Confirm", - multiSelect: false, - options: [ - { label: "Allow", description: "Proceed as-is" }, - { label: "Modify", description: "Adjust before execution" }, - { label: "Cancel", description: "Abort workflow" } - ] - }, - { - question: "Execution method:", - header: "Execution", - multiSelect: false, - options: [ - { label: "Agent", description: "@code-developer agent" }, - { label: "Codex", description: "codex CLI tool" }, - { label: "Auto", description: `Auto: ${plan.complexity === 'Low' ? 'Agent' : 'Codex'}` } - ] - }, - { - question: "Code review after execution?", - header: "Review", - multiSelect: false, - options: [ - { label: "Gemini Review", description: "Gemini CLI review" }, - { label: "Codex Review", description: "Git-aware review (prompt OR --uncommitted)" }, - { label: "Agent Review", description: "@code-reviewer agent" }, - { label: "Skip", description: "No review" } - ] - } - ] - }) -} -``` - ---- - -### Phase 5: Execute to Execution - -**CRITICAL**: lite-plan NEVER executes code directly. ALL execution MUST go through lite-execute. - -**Step 5.1: Build executionContext** - -```javascript -// Load manifest and all exploration files -const manifest = JSON.parse(Read(`${sessionFolder}/explorations-manifest.json`)) -const explorations = {} - -manifest.explorations.forEach(exp => { - if (file_exists(exp.path)) { - explorations[exp.angle] = JSON.parse(Read(exp.path)) - } -}) - -const plan = JSON.parse(Read(`${sessionFolder}/plan.json`)) - -executionContext = { - planObject: plan, // plan overview (no tasks[]) - taskFiles: (plan.task_ids || []).map(id => ({ - id, - path: `${sessionFolder}/.task/${id}.json` - })), - explorationsContext: explorations, - explorationAngles: manifest.explorations.map(e => e.angle), - explorationManifest: manifest, - clarificationContext: clarificationContext || null, - executionMethod: userSelection.execution_method, // 全局默认,可被 executorAssignments 覆盖 - codeReviewTool: userSelection.code_review_tool, - originalUserInput: task_description, - - // 任务级 executor 分配(优先于全局 executionMethod) - executorAssignments: executorAssignments, // { taskId: { executor, reason } } - - session: { - id: sessionId, - folder: sessionFolder, - artifacts: { - explorations: manifest.explorations.map(exp => ({ - angle: exp.angle, - path: exp.path - })), - explorations_manifest: `${sessionFolder}/explorations-manifest.json`, - plan: `${sessionFolder}/plan.json`, - task_dir: `${sessionFolder}/.task` - } - } -} -``` - -**Step 5.2: Execute** - -```javascript -Skill(skill="workflow:lite-execute", args="--in-memory") -``` - -## 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 -├── planning-context.md # Evidence paths + understanding -├── plan.json # Plan overview (task_ids[]) -└── .task/ # Task files directory - ├── TASK-001.json - ├── TASK-002.json - └── ... -``` - -**Example**: -``` -.workflow/.lite-plan/implement-jwt-refresh-2025-11-25-14-30-25/ -├── exploration-architecture.json -├── exploration-auth-patterns.json -├── exploration-security.json -├── explorations-manifest.json -├── planning-context.md -├── plan.json -└── .task/ - ├── TASK-001.json - ├── TASK-002.json - └── TASK-003.json -``` - -## Error Handling - -| Error | Resolution | -|-------|------------| -| Exploration agent failure | Skip exploration, continue with task description only | -| Planning agent failure | Fallback to direct planning by Claude | -| Clarification timeout | Use exploration findings as-is | -| Confirmation timeout | Save context, display resume instructions | -| Modify loop > 3 times | Suggest breaking task or using /workflow:plan | diff --git a/.claude/commands/workflow/multi-cli-plan.md b/.claude/commands/workflow/multi-cli-plan.md deleted file mode 100644 index 57ae231d..00000000 --- a/.claude/commands/workflow/multi-cli-plan.md +++ /dev/null @@ -1,602 +0,0 @@ ---- -name: workflow:multi-cli-plan -description: Multi-CLI collaborative planning workflow with ACE context gathering and iterative cross-verification. Uses cli-discuss-agent for Gemini+Codex+Claude analysis to converge on optimal execution plan. -argument-hint: "[-y|--yes] [--max-rounds=3] [--tools=gemini,codex] [--mode=parallel|serial]" -allowed-tools: TodoWrite(*), Task(*), AskUserQuestion(*), Read(*), Bash(*), Write(*), mcp__ace-tool__search_context(*) ---- - -## Auto Mode - -When `--yes` or `-y`: Auto-approve plan, use recommended solution and execution method (Agent, Skip review). - -# Multi-CLI Collaborative Planning Command - -## Quick Start - -```bash -# Basic usage -/workflow:multi-cli-plan "Implement user authentication" - -# With options -/workflow:multi-cli-plan "Add dark mode support" --max-rounds=3 -/workflow:multi-cli-plan "Refactor payment module" --tools=gemini,codex,claude -/workflow:multi-cli-plan "Fix memory leak" --mode=serial -``` - -**Context Source**: ACE semantic search + Multi-CLI analysis -**Output Directory**: `.workflow/.multi-cli-plan/{session-id}/` -**Default Max Rounds**: 3 (convergence may complete earlier) -**CLI Tools**: @cli-discuss-agent (analysis), @cli-lite-planning-agent (plan generation) -**Execution**: Auto-hands off to `/workflow:lite-execute --in-memory` after plan approval - -## What & Why - -### Core Concept - -Multi-CLI collaborative planning with **three-phase architecture**: ACE context gathering → Iterative multi-CLI discussion → Plan generation. Orchestrator delegates analysis to agents, only handles user decisions and session management. - -**Process**: -- **Phase 1**: ACE semantic search gathers codebase context -- **Phase 2**: cli-discuss-agent orchestrates Gemini/Codex/Claude for cross-verified analysis -- **Phase 3-5**: User decision → Plan generation → Execution handoff - -**vs Single-CLI Planning**: -- **Single**: One model perspective, potential blind spots -- **Multi-CLI**: Cross-verification catches inconsistencies, builds consensus on solutions - -### Value Proposition - -1. **Multi-Perspective Analysis**: Gemini + Codex + Claude analyze from different angles -2. **Cross-Verification**: Identify agreements/disagreements, build confidence -3. **User-Driven Decisions**: Every round ends with user decision point -4. **Iterative Convergence**: Progressive refinement until consensus reached - -### Orchestrator Boundary (CRITICAL) - -- **ONLY command** for multi-CLI collaborative planning -- Manages: Session state, user decisions, agent delegation, phase transitions -- Delegates: CLI execution to @cli-discuss-agent, plan generation to @cli-lite-planning-agent - -### Execution Flow - -``` -Phase 1: Context Gathering - └─ ACE semantic search, extract keywords, build context package - -Phase 2: Multi-CLI Discussion (Iterative, via @cli-discuss-agent) - ├─ Round N: Agent executes Gemini + Codex + Claude - ├─ Cross-verify findings, synthesize solutions - ├─ Write synthesis.json to rounds/{N}/ - └─ Loop until convergence or max rounds - -Phase 3: Present Options - └─ Display solutions with trade-offs from agent output - -Phase 4: User Decision - ├─ Select solution approach - ├─ Select execution method (Agent/Codex/Auto) - ├─ Select code review tool (Skip/Gemini/Codex/Agent) - └─ Route: - ├─ Approve → Phase 5 - ├─ Need More Analysis → Return to Phase 2 - └─ Cancel → Save session - -Phase 5: Plan Generation & Execution Handoff - ├─ Generate plan.json + .task/*.json (via @cli-lite-planning-agent, two-layer output) - ├─ Build executionContext with user selections and taskFiles - └─ Execute to /workflow:lite-execute --in-memory -``` - -### Agent Roles - -| Agent | Responsibility | -|-------|---------------| -| **Orchestrator** | Session management, ACE context, user decisions, phase transitions, executionContext assembly | -| **@cli-discuss-agent** | Multi-CLI execution (Gemini/Codex/Claude), cross-verification, solution synthesis, synthesis.json output | -| **@cli-lite-planning-agent** | Task decomposition, two-layer output: plan.json (overview with task_ids[]) + .task/*.json (task files) | - -## Core Responsibilities - -### Phase 1: Context Gathering - -**Session Initialization**: -```javascript -const sessionId = `MCP-${taskSlug}-${date}` -const sessionFolder = `.workflow/.multi-cli-plan/${sessionId}` -Bash(`mkdir -p ${sessionFolder}/rounds`) -``` - -**ACE Context Queries**: -```javascript -const aceQueries = [ - `Project architecture related to ${keywords}`, - `Existing implementations of ${keywords[0]}`, - `Code patterns for ${keywords} features`, - `Integration points for ${keywords[0]}` -] -// Execute via mcp__ace-tool__search_context -``` - -**Context Package** (passed to agent): -- `relevant_files[]` - Files identified by ACE -- `detected_patterns[]` - Code patterns found -- `architecture_insights` - Structure understanding - -### Phase 2: Agent Delegation - -**Core Principle**: Orchestrator only delegates and reads output - NO direct CLI execution. - -**⚠️ CRITICAL - CLI EXECUTION REQUIREMENT**: -- **MUST** execute CLI calls via `Bash` with `run_in_background: true` -- **MUST** wait for hook callback to receive complete results -- **MUST NOT** proceed with next phase until CLI execution fully completes -- Do NOT use `TaskOutput` polling during CLI execution - wait passively for results -- Minimize scope: Proceed only when 100% result available - -**Agent Invocation**: -```javascript -Task({ - subagent_type: "cli-discuss-agent", - run_in_background: false, - description: `Discussion round ${currentRound}`, - prompt: ` -## Input Context -- task_description: ${taskDescription} -- round_number: ${currentRound} -- session: { id: "${sessionId}", folder: "${sessionFolder}" } -- ace_context: ${JSON.stringify(contextPackageage)} -- previous_rounds: ${JSON.stringify(analysisResults)} -- user_feedback: ${userFeedback || 'None'} -- cli_config: { tools: ["gemini", "codex"], mode: "parallel", fallback_chain: ["gemini", "codex", "claude"] } - -## Execution Process -1. Parse input context (handle JSON strings) -2. Check if ACE supplementary search needed -3. Build CLI prompts with context -4. Execute CLIs (parallel or serial per cli_config.mode) -5. Parse CLI outputs, handle failures with fallback -6. Perform cross-verification between CLI results -7. Synthesize solutions, calculate scores -8. Calculate convergence, generate clarification questions -9. Write synthesis.json - -## Output -Write: ${sessionFolder}/rounds/${currentRound}/synthesis.json - -## Completion Checklist -- [ ] All configured CLI tools executed (or fallback triggered) -- [ ] Cross-verification completed with agreements/disagreements -- [ ] 2-3 solutions generated with file:line references -- [ ] Convergence score calculated (0.0-1.0) -- [ ] synthesis.json written with all Primary Fields -` -}) -``` - -**Read Agent Output**: -```javascript -const synthesis = JSON.parse(Read(`${sessionFolder}/rounds/${round}/synthesis.json`)) -// Access top-level fields: solutions, convergence, cross_verification, clarification_questions -``` - -**Convergence Decision**: -```javascript -if (synthesis.convergence.recommendation === 'converged') { - // Proceed to Phase 3 -} else if (synthesis.convergence.recommendation === 'user_input_needed') { - // Collect user feedback, return to Phase 2 -} else { - // Continue to next round if new_insights && round < maxRounds -} -``` - -### Phase 3: Present Options - -**Display from Agent Output** (no processing): -```javascript -console.log(` -## Solution Options - -${synthesis.solutions.map((s, i) => ` -**Option ${i+1}: ${s.name}** -Source: ${s.source_cli.join(' + ')} -Effort: ${s.effort} | Risk: ${s.risk} - -Pros: ${s.pros.join(', ')} -Cons: ${s.cons.join(', ')} - -Files: ${s.affected_files.slice(0,3).map(f => `${f.file}:${f.line}`).join(', ')} -`).join('\n')} - -## Cross-Verification -Agreements: ${synthesis.cross_verification.agreements.length} -Disagreements: ${synthesis.cross_verification.disagreements.length} -`) -``` - -### Phase 4: User Decision - -**Decision Options**: -```javascript -AskUserQuestion({ - questions: [ - { - question: "Which solution approach?", - header: "Solution", - multiSelect: false, - options: solutions.map((s, i) => ({ - label: `Option ${i+1}: ${s.name}`, - description: `${s.effort} effort, ${s.risk} risk` - })).concat([ - { label: "Need More Analysis", description: "Return to Phase 2" } - ]) - }, - { - question: "Execution method:", - header: "Execution", - multiSelect: false, - options: [ - { label: "Agent", description: "@code-developer agent" }, - { label: "Codex", description: "codex CLI tool" }, - { label: "Auto", description: "Auto-select based on complexity" } - ] - }, - { - question: "Code review after execution?", - header: "Review", - multiSelect: false, - options: [ - { label: "Skip", description: "No review" }, - { label: "Gemini Review", description: "Gemini CLI tool" }, - { label: "Codex Review", description: "codex review --uncommitted" }, - { label: "Agent Review", description: "Current agent review" } - ] - } - ] -}) -``` - -**Routing**: -- Approve + execution method → Phase 5 -- Need More Analysis → Phase 2 with feedback -- Cancel → Save session for resumption - -### Phase 5: Plan Generation & Execution Handoff - -**Step 1: Build Context-Package** (Orchestrator responsibility): -```javascript -// Extract key information from user decision and synthesis -const contextPackage = { - // Core solution details - solution: { - name: selectedSolution.name, - source_cli: selectedSolution.source_cli, - feasibility: selectedSolution.feasibility, - effort: selectedSolution.effort, - risk: selectedSolution.risk, - summary: selectedSolution.summary - }, - // Implementation plan (tasks, flow, milestones) - implementation_plan: selectedSolution.implementation_plan, - // Dependencies - dependencies: selectedSolution.dependencies || { internal: [], external: [] }, - // Technical concerns - technical_concerns: selectedSolution.technical_concerns || [], - // Consensus from cross-verification - consensus: { - agreements: synthesis.cross_verification.agreements, - resolved_conflicts: synthesis.cross_verification.resolution - }, - // User constraints (from Phase 4 feedback) - constraints: userConstraints || [], - // Task context - task_description: taskDescription, - session_id: sessionId -} - -// Write context-package for traceability -Write(`${sessionFolder}/context-package.json`, JSON.stringify(contextPackage, null, 2)) -``` - -**Context-Package Schema**: - -| Field | Type | Description | -|-------|------|-------------| -| `solution` | object | User-selected solution from synthesis | -| `solution.name` | string | Solution identifier | -| `solution.feasibility` | number | Viability score (0-1) | -| `solution.summary` | string | Brief analysis summary | -| `implementation_plan` | object | Task breakdown with flow and dependencies | -| `implementation_plan.approach` | string | High-level technical strategy | -| `implementation_plan.tasks[]` | array | Discrete tasks with id, name, depends_on, files | -| `implementation_plan.execution_flow` | string | Task sequence (e.g., "T1 → T2 → T3") | -| `implementation_plan.milestones` | string[] | Key checkpoints | -| `dependencies` | object | Module and package dependencies | -| `technical_concerns` | string[] | Risks and blockers | -| `consensus` | object | Cross-verified agreements from multi-CLI | -| `constraints` | string[] | User-specified constraints from Phase 4 | - -```json -{ - "solution": { - "name": "Strategy Pattern Refactoring", - "source_cli": ["gemini", "codex"], - "feasibility": 0.88, - "effort": "medium", - "risk": "low", - "summary": "Extract payment gateway interface, implement strategy pattern for multi-gateway support" - }, - "implementation_plan": { - "approach": "Define interface → Create concrete strategies → Implement factory → Migrate existing code", - "tasks": [ - {"id": "T1", "name": "Define PaymentGateway interface", "depends_on": [], "files": [{"file": "src/types/payment.ts", "line": 1, "action": "create"}], "key_point": "Include all existing Stripe methods"}, - {"id": "T2", "name": "Implement StripeGateway", "depends_on": ["T1"], "files": [{"file": "src/payment/stripe.ts", "line": 1, "action": "create"}], "key_point": "Wrap existing logic"}, - {"id": "T3", "name": "Create GatewayFactory", "depends_on": ["T1"], "files": [{"file": "src/payment/factory.ts", "line": 1, "action": "create"}], "key_point": null}, - {"id": "T4", "name": "Migrate processor to use factory", "depends_on": ["T2", "T3"], "files": [{"file": "src/payment/processor.ts", "line": 45, "action": "modify"}], "key_point": "Backward compatible"} - ], - "execution_flow": "T1 → (T2 | T3) → T4", - "milestones": ["Interface defined", "Gateway implementations complete", "Migration done"] - }, - "dependencies": { - "internal": ["@/lib/payment-gateway", "@/types/payment"], - "external": ["stripe@^14.0.0"] - }, - "technical_concerns": ["Existing tests must pass", "No breaking API changes"], - "consensus": { - "agreements": ["Use strategy pattern", "Keep existing API"], - "resolved_conflicts": "Factory over DI for simpler integration" - }, - "constraints": ["backward compatible", "no breaking changes to PaymentResult type"], - "task_description": "Refactor payment processing for multi-gateway support", - "session_id": "MCP-payment-refactor-2026-01-14" -} -``` - -**Step 2: Invoke Planning Agent**: -```javascript -Task({ - subagent_type: "cli-lite-planning-agent", - run_in_background: false, - description: "Generate implementation plan", - prompt: ` -## Schema Reference -Execute: cat ~/.ccw/workflows/cli-templates/schemas/plan-overview-base-schema.json -Execute: cat ~/.ccw/workflows/cli-templates/schemas/task-schema.json - -## Output Format: Two-Layer Structure -- plan.json: Overview with task_ids[] referencing .task/ files (NO tasks[] array) -- .task/TASK-*.json: Independent task files following task-schema.json - -plan.json required: summary, approach, task_ids, task_count, _metadata (with plan_type) -Task files required: id, title, description, depends_on, convergence (with criteria[]) -Task fields: files[].change (not modification_points), convergence.criteria (not acceptance), test (not verification) - -## Context-Package (from orchestrator) -${JSON.stringify(contextPackage, null, 2)} - -## Execution Process -1. Read plan-overview-base-schema.json + task-schema.json for output structure -2. Read project-tech.json and project-guidelines.json -3. Parse context-package fields: - - solution: name, feasibility, summary - - implementation_plan: tasks[], execution_flow, milestones - - dependencies: internal[], external[] - - technical_concerns: risks/blockers - - consensus: agreements, resolved_conflicts - - constraints: user requirements -4. Use implementation_plan.tasks[] as task foundation -5. Preserve task dependencies (depends_on) and execution_flow -6. Expand tasks with convergence.criteria (testable completion conditions) -7. Create .task/ directory and write individual TASK-*.json files -8. Generate plan.json with task_ids[] referencing .task/ files - -## Output -- ${sessionFolder}/plan.json (overview with task_ids[]) -- ${sessionFolder}/.task/TASK-*.json (independent task files) - -## Completion Checklist -- [ ] plan.json has task_ids[] and task_count (NO embedded tasks[]) -- [ ] .task/*.json files preserve task dependencies from implementation_plan -- [ ] Task execution order follows execution_flow -- [ ] Key_points reflected in task descriptions -- [ ] User constraints applied to implementation -- [ ] convergence.criteria are testable -- [ ] plan.json follows plan-overview-base-schema.json -- [ ] Task files follow task-schema.json -` -}) -``` - -**Step 3: Build executionContext**: -```javascript -// After plan.json is generated by cli-lite-planning-agent -const plan = JSON.parse(Read(`${sessionFolder}/plan.json`)) - -// Load task files from .task/ directory (two-layer format) -const taskFiles = plan.task_ids.map(id => `${sessionFolder}/.task/${id}.json`) - -// Build executionContext (same structure as lite-plan) -executionContext = { - planObject: plan, - taskFiles: taskFiles, // Paths to .task/*.json files (two-layer format) - explorationsContext: null, // Multi-CLI doesn't use exploration files - explorationAngles: [], // No exploration angles - explorationManifest: null, // No manifest - clarificationContext: null, // Store user feedback from Phase 2 if exists - executionMethod: userSelection.execution_method, // From Phase 4 - codeReviewTool: userSelection.code_review_tool, // From Phase 4 - originalUserInput: taskDescription, - - // Optional: Task-level executor assignments - executorAssignments: null, // Could be enhanced in future - - session: { - id: sessionId, - folder: sessionFolder, - artifacts: { - explorations: [], // No explorations in multi-CLI workflow - explorations_manifest: null, - plan: `${sessionFolder}/plan.json`, - task_dir: plan.task_ids ? `${sessionFolder}/.task/` : null, - synthesis_rounds: Array.from({length: currentRound}, (_, i) => - `${sessionFolder}/rounds/${i+1}/synthesis.json` - ), - context_package: `${sessionFolder}/context-package.json` - } - } -} -``` - -**Step 4: Hand off to Execution**: -```javascript -// Execute to lite-execute with in-memory context -Skill(skill="workflow:lite-execute", args="--in-memory") -``` - -## Output File Structure - -``` -.workflow/.multi-cli-plan/{MCP-task-slug-YYYY-MM-DD}/ -├── session-state.json # Session tracking (orchestrator) -├── rounds/ -│ ├── 1/synthesis.json # Round 1 analysis (cli-discuss-agent) -│ ├── 2/synthesis.json # Round 2 analysis (cli-discuss-agent) -│ └── .../ -├── context-package.json # Extracted context for planning (orchestrator) -├── plan.json # Plan overview with task_ids[] (NO embedded tasks[]) -└── .task/ # Independent task files - ├── TASK-001.json # Task file following task-schema.json - ├── TASK-002.json - └── ... -``` - -**File Producers**: - -| File | Producer | Content | -|------|----------|---------| -| `session-state.json` | Orchestrator | Session metadata, rounds, decisions | -| `rounds/*/synthesis.json` | cli-discuss-agent | Solutions, convergence, cross-verification | -| `context-package.json` | Orchestrator | Extracted solution, dependencies, consensus for planning | -| `plan.json` | cli-lite-planning-agent | Plan overview with task_ids[] referencing .task/ files | -| `.task/*.json` | cli-lite-planning-agent | Independent task files following task-schema.json | - -## synthesis.json Schema - -```json -{ - "round": 1, - "solutions": [{ - "name": "Solution Name", - "source_cli": ["gemini", "codex"], - "feasibility": 0.85, - "effort": "low|medium|high", - "risk": "low|medium|high", - "summary": "Brief analysis summary", - "implementation_plan": { - "approach": "High-level technical approach", - "tasks": [ - {"id": "T1", "name": "Task", "depends_on": [], "files": [], "key_point": "..."} - ], - "execution_flow": "T1 → T2 → T3", - "milestones": ["Checkpoint 1", "Checkpoint 2"] - }, - "dependencies": {"internal": [], "external": []}, - "technical_concerns": ["Risk 1", "Blocker 2"] - }], - "convergence": { - "score": 0.85, - "new_insights": false, - "recommendation": "converged|continue|user_input_needed" - }, - "cross_verification": { - "agreements": [], - "disagreements": [], - "resolution": "..." - }, - "clarification_questions": [] -} -``` - -**Key Planning Fields**: - -| Field | Purpose | -|-------|---------| -| `feasibility` | Viability score (0-1) | -| `implementation_plan.tasks[]` | Discrete tasks with dependencies | -| `implementation_plan.execution_flow` | Task sequence visualization | -| `implementation_plan.milestones` | Key checkpoints | -| `technical_concerns` | Risks and blockers | - -**Note**: Solutions ranked by internal scoring (array order = priority) - -## TodoWrite Structure - -**Initialization**: -```javascript -TodoWrite({ todos: [ - { content: "Phase 1: Context Gathering", status: "in_progress", activeForm: "Gathering context" }, - { content: "Phase 2: Multi-CLI Discussion", status: "pending", activeForm: "Running discussion" }, - { content: "Phase 3: Present Options", status: "pending", activeForm: "Presenting options" }, - { content: "Phase 4: User Decision", status: "pending", activeForm: "Awaiting decision" }, - { content: "Phase 5: Plan Generation", status: "pending", activeForm: "Generating plan" } -]}) -``` - -**During Discussion Rounds**: -```javascript -TodoWrite({ todos: [ - { content: "Phase 1: Context Gathering", status: "completed", activeForm: "Gathering context" }, - { content: "Phase 2: Multi-CLI Discussion", status: "in_progress", activeForm: "Running discussion" }, - { content: " → Round 1: Initial analysis", status: "completed", activeForm: "Analyzing" }, - { content: " → Round 2: Deep verification", status: "in_progress", activeForm: "Verifying" }, - { content: "Phase 3: Present Options", status: "pending", activeForm: "Presenting options" }, - // ... -]}) -``` - -## Error Handling - -| Error | Resolution | -|-------|------------| -| ACE search fails | Fall back to Glob/Grep for file discovery | -| Agent fails | Retry once, then present partial results | -| CLI timeout (in agent) | Agent uses fallback: gemini → codex → claude | -| No convergence | Present best options, flag uncertainty | -| synthesis.json parse error | Request agent retry | -| User cancels | Save session for later resumption | - -## Configuration - -| Flag | Default | Description | -|------|---------|-------------| -| `--max-rounds` | 3 | Maximum discussion rounds | -| `--tools` | gemini,codex | CLI tools for analysis | -| `--mode` | parallel | Execution mode: parallel or serial | -| `--auto-execute` | false | Auto-execute after approval | - -## Best Practices - -1. **Be Specific**: Detailed task descriptions improve ACE context quality -2. **Provide Feedback**: Use clarification rounds to refine requirements -3. **Trust Cross-Verification**: Multi-CLI consensus indicates high confidence -4. **Review Trade-offs**: Consider pros/cons before selecting solution -5. **Check synthesis.json**: Review agent output for detailed analysis -6. **Iterate When Needed**: Don't hesitate to request more analysis - -## Related Commands - -```bash -# Simpler single-round planning -/workflow:lite-plan "task description" - -# Issue-driven discovery -/issue:discover-by-prompt "find issues" - -# View session files -cat .workflow/.multi-cli-plan/{session-id}/plan.json -cat .workflow/.multi-cli-plan/{session-id}/rounds/1/synthesis.json -cat .workflow/.multi-cli-plan/{session-id}/context-package.json - -# Direct execution (if you have plan.json) -/workflow:lite-execute plan.json -``` diff --git a/.claude/commands/workflow/plan-verify.md b/.claude/commands/workflow/plan-verify.md deleted file mode 100644 index c08b2782..00000000 --- a/.claude/commands/workflow/plan-verify.md +++ /dev/null @@ -1,377 +0,0 @@ ---- -name: plan-verify -description: Perform READ-ONLY verification analysis between IMPL_PLAN.md, task JSONs, and brainstorming artifacts. Generates structured report with quality gate recommendation. Does NOT modify any files. -argument-hint: "[optional: --session session-id]" -allowed-tools: Read(*), Write(*), Glob(*), Bash(*) ---- - -## User Input - -```text -$ARGUMENTS -``` - -You **MUST** consider the user input before proceeding (if not empty). - -## Goal - -Generate a comprehensive verification report that identifies inconsistencies, duplications, ambiguities, and underspecified items between action planning artifacts (`IMPL_PLAN.md`, `task.json`) and brainstorming artifacts (`role analysis documents`). This command MUST run only after `/workflow:plan` has successfully produced complete `IMPL_PLAN.md` and task JSON files. - -**Output**: A structured Markdown report saved to `.workflow/active/WFS-{session}/.process/PLAN_VERIFICATION.md` containing: -- Executive summary with quality gate recommendation -- Detailed findings by severity (CRITICAL/HIGH/MEDIUM/LOW) -- Requirements coverage analysis -- Dependency integrity check -- Synthesis alignment validation -- Actionable remediation recommendations - -## Operating Constraints - -**STRICTLY READ-ONLY FOR SOURCE ARTIFACTS**: -- **MUST NOT** modify `IMPL_PLAN.md`, any `task.json` files, or brainstorming artifacts -- **MUST NOT** create or delete task files -- **MUST ONLY** write the verification report to `.process/PLAN_VERIFICATION.md` - -**Synthesis Authority**: The `role analysis documents` are **authoritative** for requirements and design decisions. Any conflicts between IMPL_PLAN/tasks and synthesis are automatically CRITICAL and require adjustment of the plan/tasks—not reinterpretation of requirements. - -**Quality Gate Authority**: The verification report provides a binding recommendation (BLOCK_EXECUTION / PROCEED_WITH_FIXES / PROCEED_WITH_CAUTION / PROCEED) based on objective severity criteria. User MUST review critical/high issues before proceeding with implementation. - -## Execution Steps - -### 1. Initialize Analysis Context - -```bash -# Detect active workflow session -IF --session parameter provided: - session_id = provided session -ELSE: - # Auto-detect active session - active_sessions = bash(find .workflow/active/ -name "WFS-*" -type d 2>/dev/null) - IF active_sessions is empty: - ERROR: "No active workflow session found. Use --session " - EXIT - ELSE IF active_sessions has multiple entries: - # Use most recently modified session - session_id = bash(ls -td .workflow/active/WFS-*/ 2>/dev/null | head -1 | xargs basename) - ELSE: - session_id = basename(active_sessions[0]) - -# Derive absolute paths -session_dir = .workflow/active/WFS-{session} -brainstorm_dir = session_dir/.brainstorming -task_dir = session_dir/.task -process_dir = session_dir/.process -session_file = session_dir/workflow-session.json - -# Create .process directory if not exists (report output location) -IF NOT EXISTS(process_dir): - bash(mkdir -p "{process_dir}") - -# Validate required artifacts -# Note: "role analysis documents" refers to [role]/analysis.md files (e.g., product-manager/analysis.md) -SYNTHESIS_DIR = brainstorm_dir # Contains role analysis files: */analysis.md -IMPL_PLAN = session_dir/IMPL_PLAN.md -TASK_FILES = Glob(task_dir/*.json) -PLANNING_NOTES = session_dir/planning-notes.md # N+1 context and constraints - -# Abort if missing - in order of dependency -SESSION_FILE_EXISTS = EXISTS(session_file) -IF NOT SESSION_FILE_EXISTS: - WARNING: "workflow-session.json not found. User intent alignment verification will be skipped." - # Continue execution - this is optional context, not blocking - -PLANNING_NOTES_EXISTS = EXISTS(PLANNING_NOTES) -IF NOT PLANNING_NOTES_EXISTS: - WARNING: "planning-notes.md not found. Constraints/N+1 context verification will be skipped." - # Continue execution - optional context - -SYNTHESIS_FILES = Glob(brainstorm_dir/*/analysis.md) -IF SYNTHESIS_FILES.count == 0: - ERROR: "No role analysis documents found in .brainstorming/*/analysis.md. Run /workflow:brainstorm:synthesis first" - EXIT - -IF NOT EXISTS(IMPL_PLAN): - ERROR: "IMPL_PLAN.md not found. Run /workflow:plan first" - EXIT - -IF TASK_FILES.count == 0: - ERROR: "No task JSON files found. Run /workflow:plan first" - EXIT -``` - -### 2. Load Artifacts (Progressive Disclosure) - -Load only minimal necessary context from each artifact: - -**From workflow-session.json** (OPTIONAL - Primary Reference for User Intent): -- **ONLY IF EXISTS**: Load user intent context -- Original user prompt/intent (project or description field) -- User's stated goals and objectives -- User's scope definition -- **IF MISSING**: Set user_intent_analysis = "SKIPPED: workflow-session.json not found" - -**From planning-notes.md** (OPTIONAL - Constraints & N+1 Context): -- **ONLY IF EXISTS**: Load planning context -- Consolidated Constraints (numbered list from Phase 1-3) -- N+1 Context: Decisions table (Decision | Rationale | Revisit?) -- N+1 Context: Deferred items list -- **IF MISSING**: Set planning_notes_analysis = "SKIPPED: planning-notes.md not found" - -**From role analysis documents** (AUTHORITATIVE SOURCE): -- Functional Requirements (IDs, descriptions, acceptance criteria) -- Non-Functional Requirements (IDs, targets) -- Business Requirements (IDs, success metrics) -- Key Architecture Decisions -- Risk factors and mitigation strategies -- Implementation Roadmap (high-level phases) - -**From IMPL_PLAN.md**: -- Summary and objectives -- Context Analysis -- Implementation Strategy -- Task Breakdown Summary -- Success Criteria -- Brainstorming Artifacts References (if present) - -**From task.json files**: -- Task IDs -- Titles and descriptions -- Status -- Dependencies (depends_on, blocks) -- Context (requirements, focus_paths, acceptance, artifacts) -- Flow control (pre_analysis, implementation_approach) -- Meta (complexity, priority) - -### 3. Build Semantic Models - -Create internal representations (do not include raw artifacts in output): - -**Requirements inventory**: -- Each functional/non-functional/business requirement with stable ID -- Requirement text, acceptance criteria, priority - -**Architecture decisions inventory**: -- ADRs from synthesis -- Technology choices -- Data model references - -**Task coverage mapping**: -- Map each task to one or more requirements (by ID reference or keyword inference) -- Map each requirement to covering tasks - -**Dependency graph**: -- Task-to-task dependencies (depends_on, blocks) -- Requirement-level dependencies (from synthesis) - -### 4. Detection Passes (Agent-Driven Multi-Dimensional Analysis) - -**Execution Strategy**: -- Single `cli-explore-agent` invocation -- Agent executes multiple CLI analyses internally (different dimensions: A-H) -- Token Budget: 50 findings maximum (aggregate remainder in overflow summary) -- Priority Allocation: CRITICAL (unlimited) → HIGH (15) → MEDIUM (20) → LOW (15) -- Early Exit: If CRITICAL findings > 0 in User Intent/Requirements Coverage, skip LOW/MEDIUM checks - -**Execution Order** (Agent orchestrates internally): - -1. **Tier 1 (CRITICAL Path)**: A, B, C, I - User intent, coverage, consistency, constraints compliance (full analysis) -2. **Tier 2 (HIGH Priority)**: D, E, J - Dependencies, synthesis alignment, N+1 context validation (limit 15 findings) -3. **Tier 3 (MEDIUM Priority)**: F - Specification quality (limit 20 findings) -4. **Tier 4 (LOW Priority)**: G, H - Duplication, feasibility (limit 15 findings) - ---- - -#### Phase 4.1: Launch Unified Verification Agent - -```javascript -Task( - subagent_type="cli-explore-agent", - run_in_background=false, - description="Multi-dimensional plan verification", - prompt=` -## Plan Verification Task - -### MANDATORY FIRST STEPS -1. Read: ~/.ccw/workflows/cli-templates/schemas/plan-verify-agent-schema.json (dimensions & rules) -2. Read: ~/.ccw/workflows/cli-templates/schemas/verify-json-schema.json (output schema) -3. Read: ${session_file} (user intent) -4. Read: ${PLANNING_NOTES} (constraints & N+1 context) -5. Read: ${IMPL_PLAN} (implementation plan) -6. Glob: ${task_dir}/*.json (task files) -7. Glob: ${SYNTHESIS_DIR}/*/analysis.md (role analyses) - -### Execution Flow - -**Load schema → Execute tiered CLI analysis → Aggregate findings → Write JSON** - -FOR each tier in [1, 2, 3, 4]: - - Load tier config from plan-verify-agent-schema.json - - Execute: ccw cli -p "PURPOSE: Verify dimensions {tier.dimensions} - TASK: {tier.checks from schema} - CONTEXT: @${session_dir}/**/* - EXPECTED: Findings JSON with dimension, severity, location, summary, recommendation - CONSTRAINTS: Limit {tier.limit} findings - " --tool gemini --mode analysis --rule {tier.rule} - - Parse findings, check early exit condition - - IF tier == 1 AND critical_count > 0: skip tier 3-4 - -### Output -Write: ${process_dir}/verification-findings.json (follow verify-json-schema.json) -Return: Quality gate decision + 2-3 sentence summary -` -) -``` - ---- - -#### Phase 4.2: Load and Organize Findings - -```javascript -// Load findings (single parse for all subsequent use) -const data = JSON.parse(Read(`${process_dir}/verification-findings.json`)) -const { session_id, timestamp, verification_tiers_completed, findings, summary } = data -const { critical_count, high_count, medium_count, low_count, total_findings, coverage_percentage, recommendation } = summary - -// Group by severity and dimension -const bySeverity = Object.groupBy(findings, f => f.severity) -const byDimension = Object.groupBy(findings, f => f.dimension) - -// Dimension metadata (from schema) -const DIMS = { - A: "User Intent Alignment", B: "Requirements Coverage", C: "Consistency Validation", - D: "Dependency Integrity", E: "Synthesis Alignment", F: "Task Specification Quality", - G: "Duplication Detection", H: "Feasibility Assessment", - I: "Constraints Compliance", J: "N+1 Context Validation" -} -``` - -### 5. Generate Report - -```javascript -// Helper: render dimension section -const renderDimension = (dim) => { - const items = byDimension[dim] || [] - return items.length > 0 - ? items.map(f => `### ${f.id}: ${f.summary}\n- **Severity**: ${f.severity}\n- **Location**: ${f.location.join(', ')}\n- **Recommendation**: ${f.recommendation}`).join('\n\n') - : `> ✅ No ${DIMS[dim]} issues detected.` -} - -// Helper: render severity section -const renderSeverity = (severity, impact) => { - const items = bySeverity[severity] || [] - return items.length > 0 - ? items.map(f => `#### ${f.id}: ${f.summary}\n- **Dimension**: ${f.dimension_name}\n- **Location**: ${f.location.join(', ')}\n- **Impact**: ${impact}\n- **Recommendation**: ${f.recommendation}`).join('\n\n') - : `> ✅ No ${severity.toLowerCase()}-severity issues detected.` -} - -// Build Markdown report -const fullReport = ` -# Plan Verification Report - -**Session**: WFS-${session_id} | **Generated**: ${timestamp} -**Tiers Completed**: ${verification_tiers_completed.join(', ')} - ---- - -## Executive Summary - -| Metric | Value | Status | -|--------|-------|--------| -| Risk Level | ${critical_count > 0 ? 'CRITICAL' : high_count > 0 ? 'HIGH' : medium_count > 0 ? 'MEDIUM' : 'LOW'} | ${critical_count > 0 ? '🔴' : high_count > 0 ? '🟠' : medium_count > 0 ? '🟡' : '🟢'} | -| Critical/High/Medium/Low | ${critical_count}/${high_count}/${medium_count}/${low_count} | | -| Coverage | ${coverage_percentage}% | ${coverage_percentage >= 90 ? '🟢' : coverage_percentage >= 75 ? '🟡' : '🔴'} | - -**Recommendation**: **${recommendation}** - ---- - -## Findings Summary - -| ID | Dimension | Severity | Location | Summary | -|----|-----------|----------|----------|---------| -${findings.map(f => `| ${f.id} | ${f.dimension_name} | ${f.severity} | ${f.location.join(', ')} | ${f.summary} |`).join('\n')} - ---- - -## Analysis by Dimension - -${['A','B','C','D','E','F','G','H','I','J'].map(d => `### ${d}. ${DIMS[d]}\n\n${renderDimension(d)}`).join('\n\n---\n\n')} - ---- - -## Findings by Severity - -### CRITICAL (${critical_count}) -${renderSeverity('CRITICAL', 'Blocks execution')} - -### HIGH (${high_count}) -${renderSeverity('HIGH', 'Fix before execution recommended')} - -### MEDIUM (${medium_count}) -${renderSeverity('MEDIUM', 'Address during/after implementation')} - -### LOW (${low_count}) -${renderSeverity('LOW', 'Optional improvement')} - ---- - -## Next Steps - -${recommendation === 'BLOCK_EXECUTION' ? '🛑 **BLOCK**: Fix critical issues → Re-verify' : - recommendation === 'PROCEED_WITH_FIXES' ? '⚠️ **FIX RECOMMENDED**: Address high issues → Re-verify or Execute' : - '✅ **READY**: Proceed to /workflow:execute'} - -Re-verify: \`/workflow:plan-verify --session ${session_id}\` -Execute: \`/workflow:execute --resume-session="${session_id}"\` -` - -// Write report -Write(`${process_dir}/PLAN_VERIFICATION.md`, fullReport) -console.log(`✅ Report: ${process_dir}/PLAN_VERIFICATION.md\n📊 ${recommendation} | C:${critical_count} H:${high_count} M:${medium_count} L:${low_count} | Coverage:${coverage_percentage}%`) -``` - -### 6. Next Step Selection - -```javascript -const autoYes = $ARGUMENTS.includes('--yes') || $ARGUMENTS.includes('-y') -const canExecute = recommendation !== 'BLOCK_EXECUTION' - -// Auto mode -if (autoYes) { - if (canExecute) { - Skill(skill="workflow:execute", args="--yes --resume-session=\"${session_id}\"") - } else { - console.log(`[--yes] BLOCK_EXECUTION - Fix ${critical_count} critical issues first.`) - } - return -} - -// Interactive mode - build options based on quality gate -const options = canExecute - ? [ - { label: canExecute && recommendation === 'PROCEED_WITH_FIXES' ? "Execute Anyway" : "Execute (Recommended)", - description: "Proceed to /workflow:execute" }, - { label: "Review Report", description: "Review findings before deciding" }, - { label: "Re-verify", description: "Re-run after manual fixes" } - ] - : [ - { label: "Review Report", description: "Review critical issues" }, - { label: "Re-verify", description: "Re-run after fixing issues" } - ] - -const selection = AskUserQuestion({ - questions: [{ - question: `Quality gate: ${recommendation}. Next step?`, - header: "Action", - multiSelect: false, - options - }] -}) - -// Handle selection -if (selection.includes("Execute")) { - Skill(skill="workflow:execute", args="--resume-session=\"${session_id}\"") -} else if (selection === "Re-verify") { - Skill(skill="workflow:plan-verify", args="--session ${session_id}") -} -``` diff --git a/.claude/commands/workflow/plan.md b/.claude/commands/workflow/plan.md deleted file mode 100644 index 3a978333..00000000 --- a/.claude/commands/workflow/plan.md +++ /dev/null @@ -1,705 +0,0 @@ ---- -name: plan -description: 5-phase planning workflow with action-planning-agent task generation, outputs IMPL_PLAN.md and task JSONs -argument-hint: "[-y|--yes] \"text description\"|file.md" -allowed-tools: Skill(*), TodoWrite(*), Read(*), Bash(*) -group: workflow ---- - -## Auto Mode - -When `--yes` or `-y`: Auto-continue all phases (skip confirmations), use recommended conflict resolutions. - -# Workflow Plan Command (/workflow:plan) - -## Coordinator Role - -**This command is a pure orchestrator**: Execute 5 slash commands in sequence (including a quality gate), parse their outputs, pass context between them, and ensure complete execution through **automatic continuation**. - -**Execution Model - Auto-Continue Workflow with Quality Gate**: - -This workflow runs **fully autonomously** once triggered. Phase 3 (conflict resolution) and Phase 4 (task generation) are delegated to specialized agents. - - -1. **User triggers**: `/workflow:plan "task"` -2. **Phase 1 executes** → Session discovery → Auto-continues -3. **Phase 2 executes** → Context gathering → Auto-continues -4. **Phase 3 executes** (optional, if conflict_risk ≥ medium) → Conflict resolution → Auto-continues -5. **Phase 4 executes** → Task generation (task-generate-agent) → Reports final summary - -**Task Attachment Model**: -- Skill execute **expands workflow** by attaching sub-tasks to current TodoWrite -- When a sub-command is executed (e.g., `/workflow:tools:context-gather`), its internal tasks are attached to the orchestrator's TodoWrite -- Orchestrator **executes these attached tasks** sequentially -- After completion, attached tasks are **collapsed** back to high-level phase summary -- This is **task expansion**, not external delegation - -**Auto-Continue Mechanism**: -- TodoList tracks current phase status and dynamically manages task attachment/collapse -- When each phase finishes executing, automatically execute next pending phase -- All phases run autonomously without user interaction (clarification handled in brainstorm phase) -- Progress updates shown at each phase for visibility -- **⚠️ CONTINUOUS EXECUTION** - Do not stop until all phases complete - -## Core Rules - -1. **Start Immediately**: First action is TodoWrite initialization, second action is Phase 1 command execution -2. **No Preliminary Analysis**: Do not read files, analyze structure, or gather context before Phase 1 -3. **Parse Every Output**: Extract required data from each command/agent output for next phase -4. **Auto-Continue via TodoList**: Check TodoList status to execute next pending phase automatically -5. **Track Progress**: Update TodoWrite dynamically with task attachment/collapse pattern -6. **Task Attachment Model**: Skill execute **attaches** sub-tasks to current workflow. Orchestrator **executes** these attached tasks itself, then **collapses** them after completion -7. **⚠️ CRITICAL: DO NOT STOP**: Continuous multi-phase workflow. After executing all attached tasks, immediately collapse them and execute next phase - -## Execution Process - -``` -Input Parsing: - └─ Convert user input to structured format (GOAL/SCOPE/CONTEXT) - -Phase 1: Session Discovery - └─ /workflow:session:start --auto "structured-description" - └─ Output: sessionId (WFS-xxx) - -Phase 2: Context Gathering - └─ /workflow:tools:context-gather --session sessionId "structured-description" - ├─ Tasks attached: Analyze structure → Identify integration → Generate package - └─ Output: contextPath + conflict_risk - -Phase 3: Conflict Resolution - └─ Decision (conflict_risk check): - ├─ conflict_risk ≥ medium → Execute /workflow:tools:conflict-resolution - │ ├─ Tasks attached: Detect conflicts → Present to user → Apply strategies - │ └─ Output: Modified brainstorm artifacts - └─ conflict_risk < medium → Skip to Phase 4 - -Phase 4: Task Generation - └─ /workflow:tools:task-generate-agent --session sessionId - └─ Output: IMPL_PLAN.md, task JSONs, TODO_LIST.md - -Return: - └─ Summary with recommended next steps -``` - -## 5-Phase Execution - -### Phase 1: Session Discovery - -**Step 1.1: Execute** - Create or discover workflow session - -```javascript -Skill(skill="workflow:session:start", args="--auto \"[structured-task-description]\"") -``` - -**Task Description Structure**: -``` -GOAL: [Clear, concise objective] -SCOPE: [What's included/excluded] -CONTEXT: [Relevant background or constraints] -``` - -**Example**: -``` -GOAL: Build JWT-based authentication system -SCOPE: User registration, login, token validation -CONTEXT: Existing user database schema, REST API endpoints -``` - -**Parse Output**: -- Extract: `SESSION_ID: WFS-[id]` (store as `sessionId`) - -**Validation**: -- Session ID successfully extracted -- Session directory `.workflow/active/[sessionId]/` exists - -**Note**: Session directory contains `workflow-session.json` (metadata). Do NOT look for `manifest.json` here - it only exists in `.workflow/archives/` for archived sessions. - -**TodoWrite**: Mark phase 1 completed, phase 2 in_progress - -**After Phase 1**: Initialize planning-notes.md with user intent - -```javascript -// Create planning notes document with N+1 context support -const planningNotesPath = `.workflow/active/${sessionId}/planning-notes.md` -const userGoal = structuredDescription.goal -const userConstraints = structuredDescription.context || "None specified" - -Write(planningNotesPath, `# Planning Notes - -**Session**: ${sessionId} -**Created**: ${new Date().toISOString()} - -## User Intent (Phase 1) - -- **GOAL**: ${userGoal} -- **KEY_CONSTRAINTS**: ${userConstraints} - ---- - -## Context Findings (Phase 2) -(To be filled by context-gather) - -## Conflict Decisions (Phase 3) -(To be filled if conflicts detected) - -## Consolidated Constraints (Phase 4 Input) -1. ${userConstraints} - ---- - -## Task Generation (Phase 4) -(To be filled by action-planning-agent) - -## N+1 Context -### Decisions -| Decision | Rationale | Revisit? | -|----------|-----------|----------| - -### Deferred -- [ ] (For N+1) -`) -``` - -Return to user showing Phase 1 results, then auto-continue to Phase 2 - ---- - -### Phase 2: Context Gathering - -**Step 2.1: Execute** - Gather project context and analyze codebase - -```javascript -Skill(skill="workflow:tools:context-gather", args="--session [sessionId] \"[structured-task-description]\"") -``` - -**Use Same Structured Description**: Pass the same structured format from Phase 1 - -**Input**: `sessionId` from Phase 1 - -**Parse Output**: -- Extract: context-package.json path (store as `contextPath`) -- Typical pattern: `.workflow/active/[sessionId]/.process/context-package.json` - -**Validation**: -- Context package path extracted -- File exists and is valid JSON -- `prioritized_context` field exists - - - -**TodoWrite Update (Phase 2 Skill executed - tasks attached)**: -```json -[ - {"content": "Phase 1: Session Discovery", "status": "completed", "activeForm": "Executing session discovery"}, - {"content": "Phase 2: Context Gathering", "status": "in_progress", "activeForm": "Executing context gathering"}, - {"content": " → Analyze codebase structure", "status": "in_progress", "activeForm": "Analyzing codebase structure"}, - {"content": " → Identify integration points", "status": "pending", "activeForm": "Identifying integration points"}, - {"content": " → Generate context package", "status": "pending", "activeForm": "Generating context package"}, - {"content": "Phase 4: Task Generation", "status": "pending", "activeForm": "Executing task generation"} -] -``` - -**Note**: Skill execute **attaches** context-gather's 3 tasks. Orchestrator **executes** these tasks sequentially. - - - -**TodoWrite Update (Phase 2 completed - tasks collapsed)**: -```json -[ - {"content": "Phase 1: Session Discovery", "status": "completed", "activeForm": "Executing session discovery"}, - {"content": "Phase 2: Context Gathering", "status": "completed", "activeForm": "Executing context gathering"}, - {"content": "Phase 4: Task Generation", "status": "pending", "activeForm": "Executing task generation"} -] -``` - -**Note**: Phase 2 tasks completed and collapsed to summary. - -**After Phase 2**: Update planning-notes.md with context findings, then auto-continue - -```javascript -// Read context-package to extract key findings -const contextPackage = JSON.parse(Read(contextPath)) -const conflictRisk = contextPackage.conflict_detection?.risk_level || 'low' -const criticalFiles = (contextPackage.exploration_results?.aggregated_insights?.critical_files || []) - .slice(0, 5).map(f => f.path) -const archPatterns = contextPackage.project_context?.architecture_patterns || [] -const constraints = contextPackage.exploration_results?.aggregated_insights?.constraints || [] - -// Append Phase 2 findings to planning-notes.md -Edit(planningNotesPath, { - old: '## Context Findings (Phase 2)\n(To be filled by context-gather)', - new: `## Context Findings (Phase 2) - -- **CRITICAL_FILES**: ${criticalFiles.join(', ') || 'None identified'} -- **ARCHITECTURE**: ${archPatterns.join(', ') || 'Not detected'} -- **CONFLICT_RISK**: ${conflictRisk} -- **CONSTRAINTS**: ${constraints.length > 0 ? constraints.join('; ') : 'None'}` -}) - -// Append Phase 2 constraints to consolidated list -Edit(planningNotesPath, { - old: '## Consolidated Constraints (Phase 4 Input)', - new: `## Consolidated Constraints (Phase 4 Input) -${constraints.map((c, i) => `${i + 2}. [Context] ${c}`).join('\n')}` -}) -``` - -Return to user showing Phase 2 results, then auto-continue to Phase 3/4 (depending on conflict_risk) - ---- - -### Phase 3: Conflict Resolution - -**Trigger**: Only execute when context-package.json indicates conflict_risk is "medium" or "high" - -**Step 3.1: Execute** - Detect and resolve conflicts with CLI analysis - -```javascript -Skill(skill="workflow:tools:conflict-resolution", args="--session [sessionId] --context [contextPath]") -``` - -**Input**: -- sessionId from Phase 1 -- contextPath from Phase 2 -- conflict_risk from context-package.json - -**Parse Output**: -- Extract: Execution status (success/skipped/failed) -- Verify: conflict-resolution.json file path (if executed) - -**Validation**: -- File `.workflow/active/[sessionId]/.process/conflict-resolution.json` exists (if executed) - -**Skip Behavior**: -- If conflict_risk is "none" or "low", skip directly to Phase 3.5 -- Display: "No significant conflicts detected, proceeding to clarification" - - - -**TodoWrite Update (Phase 3 Skill executed - tasks attached, if conflict_risk ≥ medium)**: -```json -[ - {"content": "Phase 1: Session Discovery", "status": "completed", "activeForm": "Executing session discovery"}, - {"content": "Phase 2: Context Gathering", "status": "completed", "activeForm": "Executing context gathering"}, - {"content": "Phase 3: Conflict Resolution", "status": "in_progress", "activeForm": "Resolving conflicts"}, - {"content": " → Detect conflicts with CLI analysis", "status": "in_progress", "activeForm": "Detecting conflicts"}, - {"content": " → Present conflicts to user", "status": "pending", "activeForm": "Presenting conflicts"}, - {"content": " → Apply resolution strategies", "status": "pending", "activeForm": "Applying resolution strategies"}, - {"content": "Phase 4: Task Generation", "status": "pending", "activeForm": "Executing task generation"} -] -``` - -**Note**: Skill execute **attaches** conflict-resolution's 3 tasks. Orchestrator **executes** these tasks sequentially. - - - -**TodoWrite Update (Phase 3 completed - tasks collapsed)**: -```json -[ - {"content": "Phase 1: Session Discovery", "status": "completed", "activeForm": "Executing session discovery"}, - {"content": "Phase 2: Context Gathering", "status": "completed", "activeForm": "Executing context gathering"}, - {"content": "Phase 3: Conflict Resolution", "status": "completed", "activeForm": "Resolving conflicts"}, - {"content": "Phase 4: Task Generation", "status": "pending", "activeForm": "Executing task generation"} -] -``` - -**Note**: Phase 3 tasks completed and collapsed to summary. - -**After Phase 3**: Update planning-notes.md with conflict decisions (if executed), then auto-continue - -```javascript -// If Phase 3 was executed, update planning-notes.md -if (conflictRisk >= 'medium') { - const conflictResPath = `.workflow/active/${sessionId}/.process/conflict-resolution.json` - - if (fs.existsSync(conflictResPath)) { - const conflictRes = JSON.parse(Read(conflictResPath)) - const resolved = conflictRes.resolved_conflicts || [] - const modifiedArtifacts = conflictRes.modified_artifacts || [] - const planningConstraints = conflictRes.planning_constraints || [] - - // Update Phase 3 section - Edit(planningNotesPath, { - old: '## Conflict Decisions (Phase 3)\n(To be filled if conflicts detected)', - new: `## Conflict Decisions (Phase 3) - -- **RESOLVED**: ${resolved.map(r => `${r.type} → ${r.strategy}`).join('; ') || 'None'} -- **MODIFIED_ARTIFACTS**: ${modifiedArtifacts.join(', ') || 'None'} -- **CONSTRAINTS**: ${planningConstraints.join('; ') || 'None'}` - }) - - // Append Phase 3 constraints to consolidated list - if (planningConstraints.length > 0) { - const currentNotes = Read(planningNotesPath) - const constraintCount = (currentNotes.match(/^\d+\./gm) || []).length - - Edit(planningNotesPath, { - old: '## Consolidated Constraints (Phase 4 Input)', - new: `## Consolidated Constraints (Phase 4 Input) -${planningConstraints.map((c, i) => `${constraintCount + i + 1}. [Conflict] ${c}`).join('\n')}` - }) - } - } -} -``` - -Return to user showing conflict resolution results (if executed) and selected strategies, then auto-continue to Phase 3.5 - -**Memory State Check**: -- Evaluate current context window usage and memory state -- If memory usage is high (>120K tokens or approaching context limits): - - **Step 3.2: Execute** - Optimize memory before proceeding - - ```javascript - Skill(skill="compact") - ``` - -- Memory compaction is particularly important after analysis phase which may generate extensive documentation -- Ensures optimal performance and prevents context overflow - ---- - -### Phase 3.5: Pre-Task Generation Validation (Optional Quality Gate) - -**Purpose**: Optional quality gate before task generation - primarily handled by brainstorm synthesis phase - - -**Current Behavior**: Auto-skip to Phase 4 (Task Generation) - -**Future Enhancement**: Could add additional validation steps like: -- Cross-reference checks between conflict resolution and brainstorm analyses -- Final sanity checks before task generation -- User confirmation prompt for proceeding - -**TodoWrite**: Mark phase 3.5 completed (auto-skip), phase 4 in_progress - -**After Phase 3.5**: Auto-continue to Phase 4 immediately - ---- - -### Phase 4: Task Generation - -**Relationship with Brainstorm Phase**: -- If brainstorm role analyses exist ([role]/analysis.md files), Phase 3 analysis incorporates them as input -- **User's original intent is ALWAYS primary**: New or refined user goals override brainstorm recommendations -- **Role analysis.md files define "WHAT"**: Requirements, design specs, role-specific insights -- **IMPL_PLAN.md defines "HOW"**: Executable task breakdown, dependencies, implementation sequence -- Task generation translates high-level role analyses into concrete, actionable work items -- **Intent priority**: Current user prompt > role analysis.md files > guidance-specification.md - -**Step 4.1: Execute** - Generate implementation plan and task JSONs - -```javascript -Skill(skill="workflow:tools:task-generate-agent", args="--session [sessionId]") -``` - -**CLI Execution Note**: CLI tool usage is now determined semantically by action-planning-agent based on user's task description. If user specifies "use Codex/Gemini/Qwen for X", CLI tool usage is controlled by `meta.execution_config.method` per task, not by `command` fields in implementation steps. - -**Input**: -- `sessionId` from Phase 1 -- **planning-notes.md**: Consolidated constraints from all phases (Phase 1-3) - - Path: `.workflow/active/[sessionId]/planning-notes.md` - - Contains: User intent, context findings, conflict decisions, consolidated constraints - - **Purpose**: Provides structured, minimal context summary to action-planning-agent - -**Validation**: -- `.workflow/active/[sessionId]/plan.json` exists (structured plan overview) -- `.workflow/active/[sessionId]/IMPL_PLAN.md` exists -- `.workflow/active/[sessionId]/.task/IMPL-*.json` exists (at least one) -- `.workflow/active/[sessionId]/TODO_LIST.md` exists - - - -**TodoWrite Update (Phase 4 Skill executed - agent task attached)**: -```json -[ - {"content": "Phase 1: Session Discovery", "status": "completed", "activeForm": "Executing session discovery"}, - {"content": "Phase 2: Context Gathering", "status": "completed", "activeForm": "Executing context gathering"}, - {"content": "Phase 4: Task Generation", "status": "in_progress", "activeForm": "Executing task generation"} -] -``` - -**Note**: Single agent task attached. Agent autonomously completes discovery, planning, and output generation internally. - - - -**TodoWrite Update (Phase 4 completed)**: -```json -[ - {"content": "Phase 1: Session Discovery", "status": "completed", "activeForm": "Executing session discovery"}, - {"content": "Phase 2: Context Gathering", "status": "completed", "activeForm": "Executing context gathering"}, - {"content": "Phase 4: Task Generation", "status": "completed", "activeForm": "Executing task generation"} -] -``` - -**Note**: Agent task completed. No collapse needed (single task). - -**Step 4.2: User Decision** - Choose next action - -After Phase 4 completes, present user with action choices: - -```javascript -console.log(` -✅ Planning complete for session: ${sessionId} -📊 Tasks generated: ${taskCount} -📋 Plan: .workflow/active/${sessionId}/IMPL_PLAN.md -`); - -// Ask user for next action -const userChoice = AskUserQuestion({ - questions: [{ - question: "Planning complete. What would you like to do next?", - header: "Next Action", - multiSelect: false, - options: [ - { - label: "Verify Plan Quality (Recommended)", - description: "Run quality verification to catch issues before execution. Checks plan structure, task dependencies, and completeness." - }, - { - label: "Start Execution", - description: "Begin implementing tasks immediately. Use this if you've already reviewed the plan or want to start quickly." - }, - { - label: "Review Status Only", - description: "View task breakdown and session status without taking further action. You can decide what to do next manually." - } - ] - }] -}); - -// Execute based on user choice -if (userChoice.answers["Next Action"] === "Verify Plan Quality (Recommended)") { - console.log("\n🔍 Starting plan verification...\n"); - Skill(skill="workflow:plan-verify", args="--session " + sessionId); -} else if (userChoice.answers["Next Action"] === "Start Execution") { - console.log("\n🚀 Starting task execution...\n"); - Skill(skill="workflow:execute", args="--session " + sessionId); -} else if (userChoice.answers["Next Action"] === "Review Status Only") { - console.log("\n📊 Displaying session status...\n"); - Skill(skill="workflow:status", args="--session " + sessionId); -} -``` - -**Return to User**: Based on user's choice, execute the corresponding workflow command. - -## TodoWrite Pattern - -**Core Concept**: Dynamic task attachment and collapse for real-time visibility into workflow execution. - -### Key Principles - -1. **Task Attachment** (when Skill executed): - - Sub-command's internal tasks are **attached** to orchestrator's TodoWrite - - **Phase 2, 3**: Multiple sub-tasks attached (e.g., Phase 2.1, 2.2, 2.3) - - **Phase 4**: Single agent task attached (e.g., "Execute task-generate-agent") - - First attached task marked as `in_progress`, others as `pending` - - Orchestrator **executes** these attached tasks sequentially - -2. **Task Collapse** (after sub-tasks complete): - - **Applies to Phase 2, 3**: Remove detailed sub-tasks from TodoWrite - - **Collapse** to high-level phase summary - - Example: Phase 2.1-2.3 collapse to "Execute context gathering: completed" - - **Phase 4**: No collapse needed (single task, just mark completed) - - Maintains clean orchestrator-level view - -3. **Continuous Execution**: - - After completion, automatically proceed to next pending phase - - No user intervention required between phases - - TodoWrite dynamically reflects current execution state - -**Lifecycle Summary**: Initial pending tasks → Phase executed (tasks ATTACHED) → Sub-tasks executed sequentially → Phase completed (tasks COLLAPSED to summary for Phase 2/3, or marked completed for Phase 4) → Next phase begins → Repeat until all phases complete. - - - -**Note**: See individual Phase descriptions for detailed TodoWrite Update examples: -- **Phase 2, 3**: Multiple sub-tasks with attach/collapse pattern -- **Phase 4**: Single agent task (no collapse needed) - -## Input Processing - -**Convert User Input to Structured Format**: - -1. **Simple Text** → Structure it: - ``` - User: "Build authentication system" - - Structured: - GOAL: Build authentication system - SCOPE: Core authentication features - CONTEXT: New implementation - ``` - -2. **Detailed Text** → Extract components: - ``` - User: "Add JWT authentication with email/password login and token refresh" - - Structured: - GOAL: Implement JWT-based authentication - SCOPE: Email/password login, token generation, token refresh endpoints - CONTEXT: JWT token-based security, refresh token rotation - ``` - -3. **File Reference** (e.g., `requirements.md`) → Read and structure: - - Read file content - - Extract goal, scope, requirements - - Format into structured description - -## Data Flow - -``` -User Input (task description) - ↓ -[Convert to Structured Format] - ↓ Structured Description: - ↓ GOAL: [objective] - ↓ SCOPE: [boundaries] - ↓ CONTEXT: [background] - ↓ -Phase 1: session:start --auto "structured-description" - ↓ Output: sessionId - ↓ Write: planning-notes.md (User Intent section) - ↓ -Phase 2: context-gather --session sessionId "structured-description" - ↓ Input: sessionId + structured description - ↓ Output: contextPath (context-package.json with prioritized_context) + conflict_risk - ↓ Update: planning-notes.md (Context Findings + Consolidated Constraints) - ↓ -Phase 3: conflict-resolution [AUTO-TRIGGERED if conflict_risk ≥ medium] - ↓ Input: sessionId + contextPath + conflict_risk - ↓ Output: Modified brainstorm artifacts - ↓ Update: planning-notes.md (Conflict Decisions + Consolidated Constraints) - ↓ Skip if conflict_risk is none/low → proceed directly to Phase 4 - ↓ -Phase 4: task-generate-agent --session sessionId - ↓ Input: sessionId + planning-notes.md + context-package.json + brainstorm artifacts - ↓ Output: IMPL_PLAN.md, task JSONs, TODO_LIST.md - ↓ -Return summary to user -``` - -**Session Memory Flow**: Each phase receives session ID, which provides access to: -- Previous task summaries -- Existing context and analysis -- Brainstorming artifacts (potentially modified by Phase 3) -- Session-specific configuration - - -## Execution Flow Diagram - -``` -User triggers: /workflow:plan "Build authentication system" - ↓ -[TodoWrite Init] 3 orchestrator-level tasks - ↓ -Phase 1: Session Discovery - → sessionId extracted - ↓ -Phase 2: Context Gathering (Skill executed) - → ATTACH 3 sub-tasks: ← ATTACHED - - → Analyze codebase structure - - → Identify integration points - - → Generate context package - → Execute sub-tasks sequentially - → COLLAPSE tasks ← COLLAPSED - → contextPath + conflict_risk extracted - ↓ -Conditional Branch: Check conflict_risk - ├─ IF conflict_risk ≥ medium: - │ Phase 3: Conflict Resolution (Skill executed) - │ → ATTACH 3 sub-tasks: ← ATTACHED - │ - → Detect conflicts with CLI analysis - │ - → Present conflicts to user - │ - → Apply resolution strategies - │ → Execute sub-tasks sequentially - │ → COLLAPSE tasks ← COLLAPSED - │ - └─ ELSE: Skip Phase 3, proceed to Phase 4 - ↓ -Phase 4: Task Generation (Skill executed) - → Single agent task (no sub-tasks) - → Agent autonomously completes internally: - (discovery → planning → output) - → Outputs: IMPL_PLAN.md, IMPL-*.json, TODO_LIST.md - ↓ -Return summary to user -``` - -**Key Points**: -- **← ATTACHED**: Tasks attached to TodoWrite when Skill executed - - Phase 2, 3: Multiple sub-tasks - - Phase 4: Single agent task -- **← COLLAPSED**: Sub-tasks collapsed to summary after completion (Phase 2, 3 only) -- **Phase 4**: Single agent task, no collapse (just mark completed) -- **Conditional Branch**: Phase 3 only executes if conflict_risk ≥ medium -- **Continuous Flow**: No user intervention between phases - -## Error Handling - -- **Parsing Failure**: If output parsing fails, retry command once, then report error -- **Validation Failure**: If validation fails, report which file/data is missing -- **Command Failure**: Keep phase `in_progress`, report error to user, do not proceed to next phase - -## Coordinator Checklist - -- **Pre-Phase**: Convert user input to structured format (GOAL/SCOPE/CONTEXT) -- Initialize TodoWrite before any command (Phase 3 added dynamically after Phase 2) -- Execute Phase 1 immediately with structured description -- Parse session ID from Phase 1 output, store in memory -- Pass session ID and structured description to Phase 2 command -- Parse context path from Phase 2 output, store in memory -- **Extract conflict_risk from context-package.json**: Determine Phase 3 execution -- **If conflict_risk ≥ medium**: Launch Phase 3 conflict-resolution with sessionId and contextPath -- Wait for Phase 3 to finish executing (if executed), verify conflict-resolution.json created -- **If conflict_risk is none/low**: Skip Phase 3, proceed directly to Phase 4 -- **Build Phase 4 command**: `/workflow:tools:task-generate-agent --session [sessionId]` -- Pass session ID to Phase 4 command -- Verify all Phase 4 outputs -- Update TodoWrite after each phase (dynamically adjust for Phase 3 presence) -- After each phase, automatically continue to next phase based on TodoList status - -## Structure Template Reference - -**Minimal Structure**: -``` -GOAL: [What to achieve] -SCOPE: [What's included] -CONTEXT: [Relevant info] -``` - -**Detailed Structure** (optional, when more context available): -``` -GOAL: [Primary objective] -SCOPE: [Included features/components] -CONTEXT: [Existing system, constraints, dependencies] -REQUIREMENTS: [Specific technical requirements] -CONSTRAINTS: [Limitations or boundaries] -``` - -**Usage in Commands**: -```bash -# Phase 1 -/workflow:session:start --auto "GOAL: Build authentication\nSCOPE: JWT, login, registration\nCONTEXT: REST API" - -# Phase 2 -/workflow:tools:context-gather --session WFS-123 "GOAL: Build authentication\nSCOPE: JWT, login, registration\nCONTEXT: REST API" -``` - -## Related Commands - -**Prerequisite Commands**: -- `/workflow:brainstorm:artifacts` - Optional: Generate role-based analyses before planning (if complex requirements need multiple perspectives) -- `/workflow:brainstorm:synthesis` - Optional: Refine brainstorm analyses with clarifications - -**Called by This Command** (5 phases): -- `/workflow:session:start` - Phase 1: Create or discover workflow session -- `/workflow:tools:context-gather` - Phase 2: Gather project context and analyze codebase -- `/workflow:tools:conflict-resolution` - Phase 3: Detect and resolve conflicts (auto-triggered if conflict_risk ≥ medium) -- `/compact` - Phase 3: Memory optimization (if context approaching limits) -- `/workflow:tools:task-generate-agent` - Phase 4: Generate task JSON files with agent-driven approach - -**Follow-up Commands**: -- `/workflow:plan-verify` - Recommended: Verify plan quality and catch issues before execution -- `/workflow:status` - Review task breakdown and current progress -- `/workflow:execute` - Begin implementation of generated tasks diff --git a/.claude/commands/workflow/replan.md b/.claude/commands/workflow/replan.md deleted file mode 100644 index 947204e8..00000000 --- a/.claude/commands/workflow/replan.md +++ /dev/null @@ -1,648 +0,0 @@ ---- -name: replan -description: Interactive workflow replanning with session-level artifact updates and boundary clarification through guided questioning -argument-hint: "[-y|--yes] [--session session-id] [task-id] \"requirements\"|file.md [--interactive]" -allowed-tools: Read(*), Write(*), Edit(*), TodoWrite(*), Glob(*), Bash(*) ---- - -# Workflow Replan Command - -## Overview -Intelligently replans workflow sessions or individual tasks with interactive boundary clarification and comprehensive artifact updates. - -**Core Capabilities**: -- **Session Replan**: Updates multiple artifacts (IMPL_PLAN.md, TODO_LIST.md, task JSONs) -- **Task Replan**: Focused updates within session context -- **Interactive Clarification**: Guided questioning to define modification boundaries -- **Impact Analysis**: Automatic detection of affected files and dependencies -- **Backup Management**: Preserves previous versions with restore capability - -## Operation Modes - -### Session Replan Mode - -```bash -# Auto-detect active session -/workflow:replan "添加双因素认证支持" - -# Explicit session -/workflow:replan --session WFS-oauth "添加双因素认证支持" - -# File-based input -/workflow:replan --session WFS-oauth requirements-update.md - -# Interactive mode -/workflow:replan --interactive -``` - -### Task Replan Mode - -```bash -# Direct task update -/workflow:replan IMPL-1 "修改为使用 OAuth2.0 标准" - -# Task with explicit session -/workflow:replan --session WFS-oauth IMPL-2 "增加单元测试覆盖率到 90%" - -# Interactive mode -/workflow:replan IMPL-1 --interactive -``` - -## Execution Process - -``` -Input Parsing: - ├─ Parse flags: --session, --interactive - └─ Detect mode: task-id present → Task mode | Otherwise → Session mode - -Phase 1: Mode Detection & Session Discovery - ├─ Detect operation mode (Task vs Session) - ├─ Discover/validate session (--session flag or auto-detect) - └─ Load session context (workflow-session.json, IMPL_PLAN.md, TODO_LIST.md) - -Phase 2: Interactive Requirement Clarification - └─ Decision (by mode): - ├─ Session mode → 3-4 questions (scope, modules, changes, dependencies) - └─ Task mode → 2 questions (update type, ripple effect) - -Phase 3: Impact Analysis & Planning - ├─ Analyze required changes - ├─ Generate modification plan - └─ User confirmation (Execute / Adjust / Cancel) - -Phase 4: Backup Creation - └─ Backup all affected files with manifest - -Phase 5: Apply Modifications - ├─ Update IMPL_PLAN.md (if needed) - ├─ Update TODO_LIST.md (if needed) - ├─ Update/Create/Delete task JSONs - └─ Update session metadata - -Phase 6: Verification & Summary - ├─ Validate consistency (JSON validity, task limits, acyclic dependencies) - └─ Generate change summary -``` - -## Execution Lifecycle - -### Input Parsing - -**Parse flags**: -```javascript -const sessionFlag = $ARGUMENTS.match(/--session\s+(\S+)/)?.[1] -const interactive = $ARGUMENTS.includes('--interactive') -const taskIdMatch = $ARGUMENTS.match(/\b(IMPL-\d+(?:\.\d+)?)\b/) -const taskId = taskIdMatch?.[1] -``` - -### Phase 1: Mode Detection & Session Discovery - -**Process**: -1. **Detect Operation Mode**: - - Check if task ID provided (IMPL-N or IMPL-N.M format) → Task mode - - Otherwise → Session mode - -2. **Discover/Validate Session**: - - Use `--session` flag if provided - - Otherwise auto-detect from `.workflow/active/` - - Validate session exists - -3. **Load Session Context**: - - Read `workflow-session.json` - - List existing tasks - - Read `IMPL_PLAN.md` and `TODO_LIST.md` - -4. **Parse Execution Intent** (from requirements text): - ```javascript - // Dynamic tool detection from cli-tools.json - // Read enabled tools: ["gemini", "qwen", "codex", ...] - const enabledTools = loadEnabledToolsFromConfig(); // See ~/.claude/cli-tools.json - - // Build dynamic patterns from enabled tools - function buildExecPatterns(tools) { - const patterns = { - agent: /改为\s*Agent\s*执行|使用\s*Agent\s*执行/i - }; - tools.forEach(tool => { - // Pattern: "使用 {tool} 执行" or "改用 {tool}" - patterns[`cli_${tool}`] = new RegExp( - `使用\\s*(${tool})\\s*执行|改用\\s*(${tool})`, 'i' - ); - }); - return patterns; - } - - const execPatterns = buildExecPatterns(enabledTools); - - let executionIntent = null - for (const [key, pattern] of Object.entries(execPatterns)) { - if (pattern.test(requirements)) { - executionIntent = key.startsWith('cli_') - ? { method: 'cli', cli_tool: key.replace('cli_', '') } - : { method: 'agent', cli_tool: null } - break - } - } - ``` - -**Output**: Session validated, context loaded, mode determined, **executionIntent parsed** - ---- - -### Auto Mode Support - -When `--yes` or `-y` flag is used, the command skips interactive clarification and uses safe defaults: - -```javascript -const autoYes = $ARGUMENTS.includes('--yes') || $ARGUMENTS.includes('-y') -``` - -**Auto Mode Defaults**: -- **Modification Scope**: `tasks_only` (safest - only update task details) -- **Affected Modules**: All modules related to the task -- **Task Changes**: `update_only` (no structural changes) -- **Dependency Changes**: `no` (preserve existing dependencies) -- **User Confirmation**: Auto-confirm execution - -**Note**: `--interactive` flag overrides `--yes` flag (forces interactive mode). - ---- - -### Phase 2: Interactive Requirement Clarification - -**Purpose**: Define modification scope through guided questioning - -**Auto Mode Check**: -```javascript -if (autoYes && !interactive) { - // Use defaults and skip to Phase 3 - console.log(`[--yes] Using safe defaults for replan:`) - console.log(` - Scope: tasks_only`) - console.log(` - Changes: update_only`) - console.log(` - Dependencies: preserve existing`) - - userSelections = { - scope: 'tasks_only', - modules: 'all_affected', - task_changes: 'update_only', - dependency_changes: false - } - // Proceed to Phase 3 -} -``` - -#### Session Mode Questions - -**Q1: Modification Scope** -```javascript -Options: -- 仅更新任务细节 (tasks_only) -- 修改规划方案 (plan_update) -- 重构任务结构 (task_restructure) -- 全面重规划 (comprehensive) -``` - -**Q2: Affected Modules** (if scope >= plan_update) -```javascript -Options: Dynamically generated from existing tasks' focus_paths -- 认证模块 (src/auth) -- 用户管理 (src/user) -- 全部模块 -``` - -**Q3: Task Changes** (if scope >= task_restructure) -```javascript -Options: -- 添加/删除任务 (add_remove) -- 合并/拆分任务 (merge_split) -- 仅更新内容 (update_only) -// Note: Max 4 options for AskUserQuestion -``` - -**Q4: Dependency Changes** -```javascript -Options: -- 是,需要重新梳理依赖 -- 否,保持现有依赖 -``` - -#### Task Mode Questions - -**Q1: Update Type** -```javascript -Options: -- 需求和验收标准 (requirements & acceptance) -- 实现方案 (implementation_approach) -- 文件范围 (focus_paths) -- 依赖关系 (depends_on) -- 全部更新 -``` - -**Q2: Ripple Effect** -```javascript -Options: -- 是,需要同步更新依赖任务 -- 否,仅影响当前任务 -- 不确定,请帮我分析 -``` - -**Output**: User selections stored, modification boundaries defined - ---- - -### Phase 3: Impact Analysis & Planning - -**Step 3.1: Analyze Required Changes** - -Determine affected files based on clarification: - -```typescript -interface ImpactAnalysis { - affected_files: { - impl_plan: boolean; - todo_list: boolean; - session_meta: boolean; - tasks: string[]; - }; - - operations: { - type: 'create' | 'update' | 'delete' | 'merge' | 'split'; - target: string; - reason: string; - }[]; - - backup_strategy: { - timestamp: string; - files: string[]; - }; -} -``` - -**Step 3.2: Generate Modification Plan** - -```markdown -## 修改计划 - -### 影响范围 -- [ ] IMPL_PLAN.md: 更新技术方案第 3 节 -- [ ] TODO_LIST.md: 添加 2 个新任务,删除 1 个废弃任务 -- [ ] IMPL-001.json: 更新实现方案 -- [ ] workflow-session.json: 更新任务计数 - -### 变更操作 -1. **创建**: IMPL-004.json (双因素认证实现) -2. **更新**: IMPL-001.json (添加 2FA 准备工作) -3. **删除**: IMPL-003.json (已被新方案替代) -``` - -**Step 3.3: User Confirmation** - -```javascript -// Parse --yes flag -const autoYes = $ARGUMENTS.includes('--yes') || $ARGUMENTS.includes('-y') - -if (autoYes) { - // Auto mode: Auto-confirm execution - console.log(`[--yes] Auto-confirming replan execution`) - userConfirmation = '确认执行' - // Proceed to Phase 4 -} else { - // Interactive mode: Ask user - AskUserQuestion({ - questions: [{ - question: "修改计划已生成,请确认操作:", - header: "Confirm", - options: [ - { label: "确认执行", description: "开始应用所有修改" }, - { label: "调整计划", description: "重新回答问题调整范围" }, - { label: "取消操作", description: "放弃本次重规划" } - ], - multiSelect: false - }] - }) -} -``` - -**Output**: Modification plan confirmed or adjusted - ---- - -### Phase 4: Backup Creation - -**Process**: - -1. **Create Backup Directory**: -```bash -timestamp=$(date -u +"%Y-%m-%dT%H-%M-%S") -backup_dir=".workflow/active/$SESSION_ID/.process/backup/replan-$timestamp" -mkdir -p "$backup_dir" -``` - -2. **Backup All Affected Files**: - - IMPL_PLAN.md - - TODO_LIST.md - - workflow-session.json - - Affected task JSONs - -3. **Create Backup Manifest**: -```markdown -# Replan Backup Manifest - -**Timestamp**: {timestamp} -**Reason**: {replan_reason} -**Scope**: {modification_scope} - -## Restoration Command -cp {backup_dir}/* .workflow/active/{session}/ -``` - -**Output**: All files safely backed up with manifest - ---- - -### Phase 5: Apply Modifications - -**Step 5.1: Update IMPL_PLAN.md** (if needed) - -Use Edit tool to modify specific sections: -- Update affected technical sections -- Update modification date - -**Step 5.2: Update TODO_LIST.md** (if needed) - -- Add new tasks with `[ ]` checkbox -- Mark deleted tasks as `[x] ~~task~~ (已废弃)` -- Update modified task descriptions - -**Step 5.3: Update Task JSONs** - -For each affected task: -```typescript -const updated_task = { - ...task, - context: { - ...task.context, - requirements: [...updated_requirements], - acceptance: [...updated_acceptance] - }, - flow_control: { - ...task.flow_control, - implementation_approach: [...updated_steps] - }, - // Update execution config if intent detected - ...(executionIntent && { - meta: { - ...task.meta, - execution_config: { - method: executionIntent.method, - cli_tool: executionIntent.cli_tool, - enable_resume: executionIntent.method !== 'agent' - } - } - }) -}; - -Write({ - file_path: `.workflow/active/${SESSION_ID}/.task/${task_id}.json`, - content: JSON.stringify(updated_task, null, 2) -}); -``` - -**Note**: Implementation approach steps are NO LONGER modified. CLI execution is controlled by task-level `meta.execution_config` only. - -**Step 5.4: Create New Tasks** (if needed) - -Generate complete task JSON with all required fields: -- id, title, status -- meta (type, agent) -- context (requirements, focus_paths, acceptance) -- flow_control (pre_analysis, implementation_approach, target_files) - -**Step 5.5: Delete Obsolete Tasks** (if needed) - -Move to backup instead of hard delete: -```bash -mv ".workflow/active/$SESSION_ID/.task/{task-id}.json" "$backup_dir/" -``` - -**Step 5.6: Update Session Metadata** - -Update workflow-session.json: -- progress.current_tasks -- progress.last_replan -- replan_history array - -**Output**: All modifications applied, artifacts updated - ---- - -### Phase 6: Verification & Summary - -**Step 6.1: Verify Consistency** - -1. Validate all task JSONs are valid JSON -2. Check task count within limits (max 10) -3. Verify dependency graph is acyclic - -**Step 6.2: Generate Change Summary** - -```markdown -## 重规划完成 - -### 会话信息 -- **Session**: {session-id} -- **时间**: {timestamp} -- **备份**: {backup-path} - -### 变更摘要 -**范围**: {scope} -**原因**: {reason} - -### 修改的文件 -- ✓ IMPL_PLAN.md: {changes} -- ✓ TODO_LIST.md: {changes} -- ✓ Task JSONs: {count} files updated - -### 任务变更 -- **新增**: {task-ids} -- **删除**: {task-ids} -- **更新**: {task-ids} - -### 回滚方法 -cp {backup-path}/* .workflow/active/{session}/ -``` - -**Output**: Summary displayed, replan complete - ---- - -## TodoWrite Progress Tracking - -### Session Mode Progress - -```json -[ - {"content": "检测模式和发现会话", "status": "completed", "activeForm": "检测模式和发现会话"}, - {"content": "交互式需求明确", "status": "completed", "activeForm": "交互式需求明确"}, - {"content": "影响分析和计划生成", "status": "completed", "activeForm": "影响分析和计划生成"}, - {"content": "创建备份", "status": "completed", "activeForm": "创建备份"}, - {"content": "更新会话产出文件", "status": "completed", "activeForm": "更新会话产出文件"}, - {"content": "验证一致性", "status": "completed", "activeForm": "验证一致性"} -] -``` - -### Task Mode Progress - -```json -[ - {"content": "检测会话和加载任务", "status": "completed", "activeForm": "检测会话和加载任务"}, - {"content": "交互式更新确认", "status": "completed", "activeForm": "交互式更新确认"}, - {"content": "应用任务修改", "status": "completed", "activeForm": "应用任务修改"} -] -``` - -## Error Handling - -### Session Errors - -```bash -# No active session found -ERROR: No active session found -Run /workflow:session:start to create a session - -# Session not found -ERROR: Session WFS-invalid not found -Available sessions: [list] - -# No changes specified -WARNING: No modifications specified -Use --interactive mode or provide requirements -``` - -### Task Errors - -```bash -# Task not found -ERROR: Task IMPL-999 not found in session -Available tasks: [list] - -# Task completed -WARNING: Task IMPL-001 is completed -Consider creating new task for additional work - -# Circular dependency -ERROR: Circular dependency detected -Resolve dependency conflicts before proceeding -``` - -### Validation Errors - -```bash -# Task limit exceeded -ERROR: Replan would create 12 tasks (limit: 10) -Consider: combining tasks, splitting sessions, or removing tasks - -# Invalid JSON -ERROR: Generated invalid JSON -Backup preserved, rolling back changes -``` - -## File Structure - -``` -.workflow/active/WFS-session-name/ -├── workflow-session.json -├── IMPL_PLAN.md -├── TODO_LIST.md -├── .task/ -│ ├── IMPL-001.json -│ ├── IMPL-002.json -│ └── IMPL-003.json -└── .process/ - ├── context-package.json - └── backup/ - └── replan-{timestamp}/ - ├── MANIFEST.md - ├── IMPL_PLAN.md - ├── TODO_LIST.md - ├── workflow-session.json - └── IMPL-*.json -``` - -## Examples - -### Session Replan - Add Feature - -```bash -/workflow:replan "添加双因素认证支持" - -# Interactive clarification -Q: 修改范围? -A: 全面重规划 - -Q: 受影响模块? -A: 认证模块, API接口 - -Q: 任务变更? -A: 添加新任务, 更新内容 - -# Execution -✓ 创建备份 -✓ 更新 IMPL_PLAN.md -✓ 更新 TODO_LIST.md -✓ 创建 IMPL-004.json -✓ 更新 IMPL-001.json, IMPL-002.json - -重规划完成! 新增 1 任务,更新 2 任务 -``` - -### Task Replan - Update Requirements - -```bash -/workflow:replan IMPL-001 "支持 OAuth2.0 标准" - -# Interactive clarification -Q: 更新部分? -A: 需求和验收标准, 实现方案 - -Q: 影响其他任务? -A: 是,需要同步更新依赖任务 - -# Execution -✓ 创建备份 -✓ 更新 IMPL-001.json -✓ 更新 IMPL-002.json (依赖任务) - -任务重规划完成! 更新 2 个任务 -``` - -### Task Replan - Change Execution Method - -```bash -/workflow:replan IMPL-001 "改用 Codex 执行" - -# Semantic parsing detects executionIntent: -# { method: 'cli', cli_tool: 'codex' } - -# Execution (no interactive questions needed) -✓ 创建备份 -✓ 更新 IMPL-001.json - - meta.execution_config = { method: 'cli', cli_tool: 'codex', enable_resume: true } - -任务执行方式已更新: Agent → CLI (codex) -``` - -```bash -/workflow:replan IMPL-002 "改为 Agent 执行" - -# Semantic parsing detects executionIntent: -# { method: 'agent', cli_tool: null } - -# Execution -✓ 创建备份 -✓ 更新 IMPL-002.json - - meta.execution_config = { method: 'agent', cli_tool: null } - -任务执行方式已更新: CLI → Agent -``` diff --git a/ccw/frontend/src/components/layout/Sidebar.tsx b/ccw/frontend/src/components/layout/Sidebar.tsx index 9a2beca6..4ef36275 100644 --- a/ccw/frontend/src/components/layout/Sidebar.tsx +++ b/ccw/frontend/src/components/layout/Sidebar.tsx @@ -81,6 +81,7 @@ const navGroupDefinitions: NavGroupDef[] = [ { path: '/history', labelKey: 'navigation.main.history', icon: Clock }, { path: '/issues', labelKey: 'navigation.main.issues', icon: AlertCircle }, { path: '/teams', labelKey: 'navigation.main.teams', icon: Users }, + { path: '/terminal-dashboard', labelKey: 'navigation.main.terminalDashboard', icon: Terminal }, ], }, { diff --git a/ccw/frontend/src/components/terminal-dashboard/AgentList.tsx b/ccw/frontend/src/components/terminal-dashboard/AgentList.tsx new file mode 100644 index 00000000..07c4a421 --- /dev/null +++ b/ccw/frontend/src/components/terminal-dashboard/AgentList.tsx @@ -0,0 +1,129 @@ +// ======================================== +// AgentList Component +// ======================================== +// Compact list of active orchestration plans from orchestratorStore. +// Shows plan name, current step progress, and status badge. + +import { useMemo } from 'react'; +import { useIntl } from 'react-intl'; +import { Bot, Loader2 } from 'lucide-react'; +import { cn } from '@/lib/utils'; +import { useOrchestratorStore, selectActivePlans } from '@/stores'; +import { Badge } from '@/components/ui/Badge'; +import type { OrchestrationRunState } from '@/stores/orchestratorStore'; +import type { OrchestrationStatus } from '@/types/orchestrator'; + +// ========== Status Badge Config ========== + +const STATUS_CONFIG: Record< + OrchestrationStatus, + { variant: 'default' | 'info' | 'success' | 'destructive' | 'secondary' | 'warning'; messageId: string } +> = { + running: { variant: 'info', messageId: 'terminalDashboard.agentList.statusRunning' }, + completed: { variant: 'success', messageId: 'terminalDashboard.agentList.statusCompleted' }, + failed: { variant: 'destructive', messageId: 'terminalDashboard.agentList.statusFailed' }, + paused: { variant: 'warning', messageId: 'terminalDashboard.agentList.statusPaused' }, + pending: { variant: 'secondary', messageId: 'terminalDashboard.agentList.statusPending' }, + cancelled: { variant: 'secondary', messageId: 'terminalDashboard.agentList.statusPending' }, +}; + +// ========== AgentListItem ========== + +function AgentListItem({ + runState, +}: { + runState: OrchestrationRunState; +}) { + const { formatMessage } = useIntl(); + const { plan, status, stepStatuses } = runState; + + const totalSteps = plan.steps.length; + const completedSteps = useMemo( + () => + Object.values(stepStatuses).filter( + (s) => s.status === 'completed' || s.status === 'skipped' + ).length, + [stepStatuses] + ); + + const config = STATUS_CONFIG[status] ?? STATUS_CONFIG.pending; + const isRunning = status === 'running'; + + return ( +
+
+ {isRunning ? ( + + ) : ( + + )} +
+ +
+

{plan.name}

+

+ {formatMessage( + { id: 'terminalDashboard.agentList.stepLabel' }, + { current: completedSteps, total: totalSteps } + )} +

+
+ + + {formatMessage({ id: config.messageId })} + +
+ ); +} + +// ========== AgentList Component ========== + +export function AgentList() { + const { formatMessage } = useIntl(); + const activePlans = useOrchestratorStore(selectActivePlans); + + const planEntries = useMemo( + () => Object.entries(activePlans), + [activePlans] + ); + + return ( +
+ {/* Section header */} +
+ +

+ {formatMessage({ id: 'terminalDashboard.agentList.title' })} +

+ {planEntries.length > 0 && ( + + {planEntries.length} + + )} +
+ + {/* Plan list or empty state */} + {planEntries.length === 0 ? ( +
+

+ {formatMessage({ id: 'terminalDashboard.agentList.noAgents' })} +

+
+ ) : ( +
+ {planEntries.map(([planId, runState]) => ( + + ))} +
+ )} +
+ ); +} + +export default AgentList; diff --git a/ccw/frontend/src/components/terminal-dashboard/AssociationHighlight.tsx b/ccw/frontend/src/components/terminal-dashboard/AssociationHighlight.tsx new file mode 100644 index 00000000..070bc784 --- /dev/null +++ b/ccw/frontend/src/components/terminal-dashboard/AssociationHighlight.tsx @@ -0,0 +1,90 @@ +// ======================================== +// AssociationHighlight Context +// ======================================== +// React context provider for cross-panel association chain highlighting. +// Provides ephemeral UI state for linked-chain highlights shared across +// left/middle/right panels. The highlighted chain indicates which +// Issue, QueueItem, and Session are visually linked. +// +// Design rationale: React context chosen over Zustand store because +// highlight state is ephemeral UI state that does not need persistence +// or cross-page sharing. + +import { + createContext, + useContext, + useState, + useCallback, + useMemo, + type ReactNode, +} from 'react'; +import type { AssociationChain } from '@/types/terminal-dashboard'; + +// ========== Context Type ========== + +interface AssociationHighlightContextType { + /** Currently highlighted association chain, or null if nothing is highlighted */ + chain: AssociationChain | null; + /** Set the highlighted chain (pass null to clear) */ + setChain: (chain: AssociationChain | null) => void; + /** Check if a specific entity is part of the current highlighted chain */ + isHighlighted: (entityId: string, entityType: 'issue' | 'queue' | 'session') => boolean; +} + +// ========== Context ========== + +const AssociationHighlightContext = createContext(null); + +// ========== Provider ========== + +export function AssociationHighlightProvider({ children }: { children: ReactNode }) { + const [chain, setChainState] = useState(null); + + const setChain = useCallback((nextChain: AssociationChain | null) => { + setChainState(nextChain); + }, []); + + const isHighlighted = useCallback( + (entityId: string, entityType: 'issue' | 'queue' | 'session'): boolean => { + if (!chain) return false; + switch (entityType) { + case 'issue': + return chain.issueId === entityId; + case 'queue': + return chain.queueItemId === entityId; + case 'session': + return chain.sessionId === entityId; + default: + return false; + } + }, + [chain] + ); + + const value = useMemo( + () => ({ chain, setChain, isHighlighted }), + [chain, setChain, isHighlighted] + ); + + return ( + + {children} + + ); +} + +// ========== Consumer Hook ========== + +/** + * Hook to access the association highlight context. + * Must be used within an AssociationHighlightProvider. + */ +export function useAssociationHighlight(): AssociationHighlightContextType { + const ctx = useContext(AssociationHighlightContext); + if (!ctx) { + throw new Error( + 'useAssociationHighlight must be used within an AssociationHighlightProvider' + ); + } + return ctx; +} diff --git a/ccw/frontend/src/components/terminal-dashboard/BottomInspector.tsx b/ccw/frontend/src/components/terminal-dashboard/BottomInspector.tsx new file mode 100644 index 00000000..a1f90eba --- /dev/null +++ b/ccw/frontend/src/components/terminal-dashboard/BottomInspector.tsx @@ -0,0 +1,216 @@ +// ======================================== +// BottomInspector Component +// ======================================== +// Collapsible bottom panel showing the full association chain +// (Issue -> Queue -> Session) for the currently selected entity. +// Consumes issueQueueIntegrationStore for association chain data +// and useAssociationHighlight context for the highlighted chain. + +import { useState, useCallback, useMemo } from 'react'; +import { useIntl } from 'react-intl'; +import { + ChevronDown, + ChevronUp, + Info, + AlertCircle, + ListChecks, + Terminal, + ArrowRight, +} from 'lucide-react'; +import { cn } from '@/lib/utils'; +import { + useIssueQueueIntegrationStore, + selectAssociationChain, +} from '@/stores/issueQueueIntegrationStore'; +import { useQueueExecutionStore } from '@/stores/queueExecutionStore'; +import { useCliSessionStore } from '@/stores/cliSessionStore'; +import { useAssociationHighlight } from './AssociationHighlight'; + +// ========== Chain Node ========== + +function ChainNode({ + icon: Icon, + label, + entityId, + status, + timestamp, + isLast = false, +}: { + icon: React.ComponentType<{ className?: string }>; + label: string; + entityId: string | null; + status?: string; + timestamp?: string; + isLast?: boolean; +}) { + if (!entityId) { + return ( +
+ + {label} + -- + {!isLast && } +
+ ); + } + + return ( +
+ + {label} + + {entityId} + + {status && ( + + {status} + + )} + {timestamp && ( + + {formatTimestamp(timestamp)} + + )} + {!isLast && } +
+ ); +} + +/** Format ISO timestamp to short readable form */ +function formatTimestamp(ts: string): string { + try { + const date = new Date(ts); + return date.toLocaleTimeString(undefined, { + hour: '2-digit', + minute: '2-digit', + second: '2-digit', + }); + } catch { + return ts; + } +} + +// ========== Main Component ========== + +export function BottomInspector() { + const { formatMessage } = useIntl(); + const [isOpen, setIsOpen] = useState(false); + + const associationChain = useIssueQueueIntegrationStore(selectAssociationChain); + const { chain: highlightedChain } = useAssociationHighlight(); + + // Use highlighted chain from context, fall back to store association chain + const activeChain = highlightedChain ?? associationChain; + + const toggle = useCallback(() => { + setIsOpen((prev) => !prev); + }, []); + + // Resolve additional details from stores + const chainDetails = useMemo(() => { + if (!activeChain) return null; + + const executions = Object.values(useQueueExecutionStore.getState().executions); + const sessions = useCliSessionStore.getState().sessions; + + // Find matching execution for queue status + let queueStatus: string | undefined; + let executionTimestamp: string | undefined; + if (activeChain.queueItemId) { + const exec = executions.find((e) => e.queueItemId === activeChain.queueItemId); + if (exec) { + queueStatus = exec.status; + executionTimestamp = exec.startedAt; + } + } + + // Find session metadata + let sessionStatus: string | undefined; + let sessionTimestamp: string | undefined; + if (activeChain.sessionId) { + const session = sessions[activeChain.sessionId]; + if (session) { + sessionStatus = 'active'; + sessionTimestamp = session.createdAt; + } + } + + return { + queueStatus, + executionTimestamp, + sessionStatus, + sessionTimestamp, + }; + }, [activeChain]); + + const hasChain = activeChain !== null; + + return ( +
+ {/* Toggle button */} + + + {/* Collapsible content */} +
+
+ {hasChain ? ( +
+ {/* Chain label */} +

+ {formatMessage({ id: 'terminalDashboard.inspector.associationChain' })} +

+ {/* Chain visualization: Issue -> Queue -> Session */} +
+ + + +
+
+ ) : ( +

+ {formatMessage({ id: 'terminalDashboard.inspector.noSelection' })} +

+ )} +
+
+
+ ); +} diff --git a/ccw/frontend/src/components/terminal-dashboard/GlobalKpiBar.tsx b/ccw/frontend/src/components/terminal-dashboard/GlobalKpiBar.tsx new file mode 100644 index 00000000..9661f21e --- /dev/null +++ b/ccw/frontend/src/components/terminal-dashboard/GlobalKpiBar.tsx @@ -0,0 +1,138 @@ +// ======================================== +// GlobalKpiBar Component +// ======================================== +// Top bar showing 3 KPI metrics spanning the full page width. +// Metrics: +// 1. Active Sessions - count from sessionManagerStore (wraps cliSessionStore) +// 2. Queue Size - pending/ready items count from useIssueQueue React Query hook +// 3. Alert Count - total alerts from all terminalMetas +// +// Per design spec (V-001): consumes sessionManagerStore, NOT cliSessionStore directly. + +import { useMemo } from 'react'; +import { useIntl } from 'react-intl'; +import { Activity, ListChecks, AlertTriangle } from 'lucide-react'; +import { cn } from '@/lib/utils'; +import { + useSessionManagerStore, + selectGroups, + selectTerminalMetas, +} from '@/stores/sessionManagerStore'; +import { useIssueQueue } from '@/hooks/useIssues'; +import type { TerminalStatus } from '@/types/terminal-dashboard'; + +// ========== KPI Item ========== + +function KpiItem({ + icon: Icon, + label, + value, + variant = 'default', +}: { + icon: React.ComponentType<{ className?: string }>; + label: string; + value: number; + variant?: 'default' | 'primary' | 'warning' | 'destructive'; +}) { + const variantStyles = { + default: 'text-muted-foreground', + primary: 'text-primary', + warning: 'text-warning', + destructive: 'text-destructive', + }; + + return ( +
+ + {label} + + {value} + +
+ ); +} + +// ========== Main Component ========== + +export function GlobalKpiBar() { + const { formatMessage } = useIntl(); + const groups = useSessionManagerStore(selectGroups); + const terminalMetas = useSessionManagerStore(selectTerminalMetas); + const queueQuery = useIssueQueue(); + + // Derive active session count from sessionManagerStore groups + const sessionCount = useMemo(() => { + const allSessionIds = groups.flatMap((g) => g.sessionIds); + // Count sessions that have 'active' status in terminalMetas + let activeCount = 0; + for (const sid of allSessionIds) { + const meta = terminalMetas[sid]; + const status: TerminalStatus = meta?.status ?? 'idle'; + if (status === 'active') { + activeCount++; + } + } + // If no sessions are managed in groups, return total unique session IDs + // This ensures the KPI shows meaningful data even before grouping + return activeCount > 0 ? activeCount : allSessionIds.length; + }, [groups, terminalMetas]); + + // Derive queue pending count from useIssueQueue data + const queuePendingCount = useMemo(() => { + const queue = queueQuery.data; + if (!queue) return 0; + // Count all items across grouped_items + let count = 0; + if (queue.grouped_items) { + for (const items of Object.values(queue.grouped_items)) { + count += items.length; + } + } + // Also count ungrouped tasks and solutions + if (queue.tasks) count += queue.tasks.length; + if (queue.solutions) count += queue.solutions.length; + return count; + }, [queueQuery.data]); + + // Derive total alert count from all terminalMetas + const totalAlerts = useMemo(() => { + let count = 0; + for (const meta of Object.values(terminalMetas)) { + count += meta.alertCount; + } + return count; + }, [terminalMetas]); + + return ( +
+ + +
+ + 0 ? 'warning' : 'default'} + /> + +
+ + 0 ? 'destructive' : 'default'} + /> + + + {formatMessage({ id: 'terminalDashboard.page.title' })} + +
+ ); +} diff --git a/ccw/frontend/src/components/terminal-dashboard/IssuePanel.tsx b/ccw/frontend/src/components/terminal-dashboard/IssuePanel.tsx new file mode 100644 index 00000000..fcd65414 --- /dev/null +++ b/ccw/frontend/src/components/terminal-dashboard/IssuePanel.tsx @@ -0,0 +1,289 @@ +// ======================================== +// IssuePanel Component +// ======================================== +// Issue list panel for the terminal dashboard middle column. +// Consumes existing useIssues() React Query hook for data fetching. +// Integrates with issueQueueIntegrationStore for selection state +// and association chain highlighting. + +import { useMemo, useCallback } from 'react'; +import { useIntl } from 'react-intl'; +import { + AlertCircle, + ArrowRightToLine, + Loader2, + AlertTriangle, + CircleDot, +} from 'lucide-react'; +import { Badge } from '@/components/ui/Badge'; +import { cn } from '@/lib/utils'; +import { useIssues } from '@/hooks/useIssues'; +import { + useIssueQueueIntegrationStore, + selectSelectedIssueId, + selectAssociationChain, +} from '@/stores/issueQueueIntegrationStore'; +import type { Issue } from '@/lib/api'; + +// ========== Priority Badge ========== + +const PRIORITY_STYLES: Record = { + critical: { variant: 'destructive', label: 'Critical' }, + high: { variant: 'warning', label: 'High' }, + medium: { variant: 'info', label: 'Medium' }, + low: { variant: 'secondary', label: 'Low' }, +}; + +function PriorityBadge({ priority }: { priority: Issue['priority'] }) { + const style = PRIORITY_STYLES[priority] ?? PRIORITY_STYLES.medium; + return ( + + {style.label} + + ); +} + +// ========== Status Indicator ========== + +function StatusDot({ status }: { status: Issue['status'] }) { + const colorMap: Record = { + open: 'text-info', + in_progress: 'text-warning', + resolved: 'text-success', + closed: 'text-muted-foreground', + completed: 'text-success', + }; + return ; +} + +// ========== Issue Item ========== + +function IssueItem({ + issue, + isSelected, + isHighlighted, + onSelect, + onSendToQueue, +}: { + issue: Issue; + isSelected: boolean; + isHighlighted: boolean; + onSelect: () => void; + onSendToQueue: () => void; +}) { + const { formatMessage } = useIntl(); + + const handleSendToQueue = useCallback( + (e: React.MouseEvent) => { + e.stopPropagation(); + onSendToQueue(); + }, + [onSendToQueue] + ); + + return ( + +
+
+ {issue.context && ( +

+ {issue.context} +

+ )} +
+ {issue.id} + {issue.labels && issue.labels.length > 0 && ( + <> + | + {issue.labels.slice(0, 2).join(', ')} + + )} +
+ + ); +} + +// ========== Empty State ========== + +function IssueEmptyState() { + const { formatMessage } = useIntl(); + return ( +
+
+ +

{formatMessage({ id: 'terminalDashboard.issuePanel.noIssues' })}

+

+ {formatMessage({ id: 'terminalDashboard.issuePanel.noIssuesDesc' })} +

+
+
+ ); +} + +// ========== Error State ========== + +function IssueErrorState({ error }: { error: Error }) { + const { formatMessage } = useIntl(); + return ( +
+
+ +

{formatMessage({ id: 'terminalDashboard.issuePanel.error' })}

+

{error.message}

+
+
+ ); +} + +// ========== Main Component ========== + +export function IssuePanel() { + const { formatMessage } = useIntl(); + const { issues, isLoading, error, openCount } = useIssues(); + + const selectedIssueId = useIssueQueueIntegrationStore(selectSelectedIssueId); + const associationChain = useIssueQueueIntegrationStore(selectAssociationChain); + const setSelectedIssue = useIssueQueueIntegrationStore((s) => s.setSelectedIssue); + const buildAssociationChain = useIssueQueueIntegrationStore((s) => s.buildAssociationChain); + + // Sort: open/in_progress first, then by priority (critical > high > medium > low) + const sortedIssues = useMemo(() => { + const priorityOrder: Record = { + critical: 0, + high: 1, + medium: 2, + low: 3, + }; + const statusOrder: Record = { + in_progress: 0, + open: 1, + resolved: 2, + completed: 3, + closed: 4, + }; + return [...issues].sort((a, b) => { + const sa = statusOrder[a.status] ?? 5; + const sb = statusOrder[b.status] ?? 5; + if (sa !== sb) return sa - sb; + const pa = priorityOrder[a.priority] ?? 3; + const pb = priorityOrder[b.priority] ?? 3; + return pa - pb; + }); + }, [issues]); + + const handleSelect = useCallback( + (issueId: string) => { + if (selectedIssueId === issueId) { + setSelectedIssue(null); + } else { + buildAssociationChain(issueId, 'issue'); + } + }, + [selectedIssueId, setSelectedIssue, buildAssociationChain] + ); + + const handleSendToQueue = useCallback( + (issueId: string) => { + // Select the issue and build chain - queue creation is handled elsewhere + buildAssociationChain(issueId, 'issue'); + }, + [buildAssociationChain] + ); + + // Loading state + if (isLoading) { + return ( +
+
+

+ + {formatMessage({ id: 'terminalDashboard.issuePanel.title' })} +

+
+
+ +
+
+ ); + } + + // Error state + if (error) { + return ( +
+
+

+ + {formatMessage({ id: 'terminalDashboard.issuePanel.title' })} +

+
+ +
+ ); + } + + return ( +
+ {/* Header */} +
+

+ + {formatMessage({ id: 'terminalDashboard.issuePanel.title' })} +

+ {openCount > 0 && ( + + {openCount} + + )} +
+ + {/* Issue List */} + {sortedIssues.length === 0 ? ( + + ) : ( +
+ {sortedIssues.map((issue) => ( + handleSelect(issue.id)} + onSendToQueue={() => handleSendToQueue(issue.id)} + /> + ))} +
+ )} +
+ ); +} diff --git a/ccw/frontend/src/components/terminal-dashboard/QueuePanel.tsx b/ccw/frontend/src/components/terminal-dashboard/QueuePanel.tsx new file mode 100644 index 00000000..f261d9ef --- /dev/null +++ b/ccw/frontend/src/components/terminal-dashboard/QueuePanel.tsx @@ -0,0 +1,264 @@ +// ======================================== +// QueuePanel Component +// ======================================== +// Queue list panel for the terminal dashboard middle column. +// Consumes existing useIssueQueue() React Query hook for queue data +// and bridges queueExecutionStore for execution status per item. +// Integrates with issueQueueIntegrationStore for association chain +// highlighting and selection state. + +import { useMemo, useCallback } from 'react'; +import { useIntl } from 'react-intl'; +import { + ListChecks, + Loader2, + AlertTriangle, + ArrowDownToLine, + Clock, + CheckCircle, + XCircle, + Zap, + Ban, + Terminal, +} from 'lucide-react'; +import { Badge } from '@/components/ui/Badge'; +import { cn } from '@/lib/utils'; +import { useIssueQueue } from '@/hooks/useIssues'; +import { + useIssueQueueIntegrationStore, + selectAssociationChain, +} from '@/stores/issueQueueIntegrationStore'; +import { + useQueueExecutionStore, + selectByQueueItem, +} from '@/stores/queueExecutionStore'; +import type { QueueItem } from '@/lib/api'; + +// ========== Status Config ========== + +type QueueItemStatus = QueueItem['status']; + +const STATUS_CONFIG: Record = { + pending: { variant: 'secondary', icon: Clock, label: 'Pending' }, + ready: { variant: 'info', icon: Zap, label: 'Ready' }, + executing: { variant: 'warning', icon: Loader2, label: 'Executing' }, + completed: { variant: 'success', icon: CheckCircle, label: 'Completed' }, + failed: { variant: 'destructive', icon: XCircle, label: 'Failed' }, + blocked: { variant: 'outline', icon: Ban, label: 'Blocked' }, +}; + +// ========== Queue Item Row ========== + +function QueueItemRow({ + item, + isHighlighted, + onSelect, +}: { + item: QueueItem; + isHighlighted: boolean; + onSelect: () => void; +}) { + const { formatMessage } = useIntl(); + const config = STATUS_CONFIG[item.status] ?? STATUS_CONFIG.pending; + const StatusIcon = config.icon; + + // Bridge to queueExecutionStore for execution status + const executions = useQueueExecutionStore(selectByQueueItem(item.item_id)); + const activeExec = executions.find((e) => e.status === 'running') ?? executions[0]; + + return ( + + ); +} + +// ========== Empty State ========== + +function QueueEmptyState() { + const { formatMessage } = useIntl(); + return ( +
+
+ +

{formatMessage({ id: 'terminalDashboard.queuePanel.noItems' })}

+

+ {formatMessage({ id: 'terminalDashboard.queuePanel.noItemsDesc' })} +

+
+
+ ); +} + +// ========== Error State ========== + +function QueueErrorState({ error }: { error: Error }) { + const { formatMessage } = useIntl(); + return ( +
+
+ +

{formatMessage({ id: 'terminalDashboard.queuePanel.error' })}

+

{error.message}

+
+
+ ); +} + +// ========== Main Component ========== + +export function QueuePanel() { + const { formatMessage } = useIntl(); + const queueQuery = useIssueQueue(); + const associationChain = useIssueQueueIntegrationStore(selectAssociationChain); + const buildAssociationChain = useIssueQueueIntegrationStore((s) => s.buildAssociationChain); + + // Flatten all queue items from grouped_items + const allItems = useMemo(() => { + if (!queueQuery.data) return []; + const grouped = queueQuery.data.grouped_items ?? {}; + const items: QueueItem[] = []; + for (const group of Object.values(grouped)) { + items.push(...group); + } + // Sort by execution_order + items.sort((a, b) => a.execution_order - b.execution_order); + return items; + }, [queueQuery.data]); + + // Count active items (pending + ready + executing) + const activeCount = useMemo(() => { + return allItems.filter( + (item) => item.status === 'pending' || item.status === 'ready' || item.status === 'executing' + ).length; + }, [allItems]); + + const handleSelect = useCallback( + (queueItemId: string) => { + buildAssociationChain(queueItemId, 'queue'); + }, + [buildAssociationChain] + ); + + // Loading state + if (queueQuery.isLoading) { + return ( +
+
+

+ + {formatMessage({ id: 'terminalDashboard.queuePanel.title' })} +

+
+
+ +
+
+ ); + } + + // Error state + if (queueQuery.error) { + return ( +
+
+

+ + {formatMessage({ id: 'terminalDashboard.queuePanel.title' })} +

+
+ +
+ ); + } + + return ( +
+ {/* Header with flow indicator */} +
+

+ + + {formatMessage({ id: 'terminalDashboard.queuePanel.title' })} +

+ {activeCount > 0 && ( + + {activeCount} + + )} +
+ + {/* Queue Item List */} + {allItems.length === 0 ? ( + + ) : ( +
+ {allItems.map((item) => ( + handleSelect(item.item_id)} + /> + ))} +
+ )} +
+ ); +} diff --git a/ccw/frontend/src/components/terminal-dashboard/SessionGroupTree.tsx b/ccw/frontend/src/components/terminal-dashboard/SessionGroupTree.tsx new file mode 100644 index 00000000..469abdca --- /dev/null +++ b/ccw/frontend/src/components/terminal-dashboard/SessionGroupTree.tsx @@ -0,0 +1,218 @@ +// ======================================== +// SessionGroupTree Component +// ======================================== +// Tree view for session groups with drag-and-drop support. +// Sessions can be dragged between groups. Groups are expandable sections. +// Uses @hello-pangea/dnd for drag-and-drop, sessionManagerStore for state. + +import { useState, useCallback, useMemo } from 'react'; +import { useIntl } from 'react-intl'; +import { + DragDropContext, + Droppable, + Draggable, + type DropResult, +} from '@hello-pangea/dnd'; +import { + ChevronRight, + FolderOpen, + Folder, + Plus, + Terminal, + GripVertical, +} from 'lucide-react'; +import { cn } from '@/lib/utils'; +import { useSessionManagerStore, selectGroups, selectSessionManagerActiveTerminalId } from '@/stores'; +import { useCliSessionStore } from '@/stores/cliSessionStore'; +import { Badge } from '@/components/ui/Badge'; + +// ========== SessionGroupTree Component ========== + +export function SessionGroupTree() { + const { formatMessage } = useIntl(); + const groups = useSessionManagerStore(selectGroups); + const activeTerminalId = useSessionManagerStore(selectSessionManagerActiveTerminalId); + const createGroup = useSessionManagerStore((s) => s.createGroup); + const moveSessionToGroup = useSessionManagerStore((s) => s.moveSessionToGroup); + const setActiveTerminal = useSessionManagerStore((s) => s.setActiveTerminal); + const sessions = useCliSessionStore((s) => s.sessions); + + const [expandedGroups, setExpandedGroups] = useState>(new Set()); + + const toggleGroup = useCallback((groupId: string) => { + setExpandedGroups((prev) => { + const next = new Set(prev); + if (next.has(groupId)) { + next.delete(groupId); + } else { + next.add(groupId); + } + return next; + }); + }, []); + + const handleCreateGroup = useCallback(() => { + const name = formatMessage({ id: 'terminalDashboard.sessionTree.defaultGroupName' }); + createGroup(name); + }, [createGroup, formatMessage]); + + const handleSessionClick = useCallback( + (sessionId: string) => { + setActiveTerminal(sessionId); + }, + [setActiveTerminal] + ); + + const handleDragEnd = useCallback( + (result: DropResult) => { + const { draggableId, destination } = result; + if (!destination) return; + + // destination.droppableId is the target group ID + const targetGroupId = destination.droppableId; + moveSessionToGroup(draggableId, targetGroupId); + }, + [moveSessionToGroup] + ); + + // Build a lookup for session display names + const sessionNames = useMemo(() => { + const map: Record = {}; + for (const [key, meta] of Object.entries(sessions)) { + map[key] = meta.tool ? `${meta.tool} - ${meta.shellKind}` : meta.shellKind; + } + return map; + }, [sessions]); + + if (groups.length === 0) { + return ( +
+
+ +
+
+ +

+ {formatMessage({ id: 'terminalDashboard.sessionTree.noGroups' })} +

+
+
+ ); + } + + return ( +
+ {/* Create group button */} +
+ +
+ + {/* Groups with drag-and-drop */} +
+ + {groups.map((group) => { + const isExpanded = expandedGroups.has(group.id); + return ( +
+ {/* Group header */} + + + {/* Expanded: droppable session list */} + {isExpanded && ( + + {(provided, snapshot) => ( +
+ {group.sessionIds.length === 0 ? ( +

+ {formatMessage({ id: 'terminalDashboard.sessionTree.emptyGroup' })} +

+ ) : ( + group.sessionIds.map((sessionId, index) => ( + + {(dragProvided, dragSnapshot) => ( +
handleSessionClick(sessionId)} + > + + + + + + {sessionNames[sessionId] ?? sessionId} + +
+ )} +
+ )) + )} + {provided.placeholder} +
+ )} +
+ )} +
+ ); + })} +
+
+
+ ); +} + +export default SessionGroupTree; diff --git a/ccw/frontend/src/components/terminal-dashboard/TerminalInstance.tsx b/ccw/frontend/src/components/terminal-dashboard/TerminalInstance.tsx new file mode 100644 index 00000000..11d1cc85 --- /dev/null +++ b/ccw/frontend/src/components/terminal-dashboard/TerminalInstance.tsx @@ -0,0 +1,211 @@ +// ======================================== +// TerminalInstance Component +// ======================================== +// xterm.js terminal wrapper for the Terminal Dashboard. +// Reuses exact integration pattern from TerminalMainArea: +// XTerm instance in ref, FitAddon, ResizeObserver, batched PTY input (30ms), +// output chunk streaming from cliSessionStore. + +import { useEffect, useRef, useCallback } from 'react'; +import { Terminal as XTerm } from 'xterm'; +import { FitAddon } from 'xterm-addon-fit'; +import { useCliSessionStore } from '@/stores/cliSessionStore'; +import { useSessionManagerStore } from '@/stores/sessionManagerStore'; +import { useWorkflowStore, selectProjectPath } from '@/stores/workflowStore'; +import { + fetchCliSessionBuffer, + sendCliSessionText, + resizeCliSession, +} from '@/lib/api'; +import { cn } from '@/lib/utils'; + +// ========== Types ========== + +interface TerminalInstanceProps { + /** Session key to render terminal for */ + sessionId: string; + /** Additional CSS classes */ + className?: string; +} + +// ========== Component ========== + +export function TerminalInstance({ sessionId, className }: TerminalInstanceProps) { + const projectPath = useWorkflowStore(selectProjectPath); + + // cliSessionStore selectors + const outputChunks = useCliSessionStore((s) => s.outputChunks); + const setBuffer = useCliSessionStore((s) => s.setBuffer); + const clearOutput = useCliSessionStore((s) => s.clearOutput); + + // ========== xterm Refs ========== + + const terminalHostRef = useRef(null); + const xtermRef = useRef(null); + const fitAddonRef = useRef(null); + const lastChunkIndexRef = useRef(0); + + // PTY input batching (30ms, matching TerminalMainArea) + const pendingInputRef = useRef(''); + const flushTimerRef = useRef(null); + + // Track sessionId in a ref so xterm onData callback always has latest value + const sessionIdRef = useRef(sessionId); + sessionIdRef.current = sessionId; + + const projectPathRef = useRef(projectPath); + projectPathRef.current = projectPath; + + // ========== PTY Input Batching ========== + + const flushInput = useCallback(async () => { + const key = sessionIdRef.current; + if (!key) return; + const pending = pendingInputRef.current; + pendingInputRef.current = ''; + if (!pending) return; + try { + await sendCliSessionText( + key, + { text: pending, appendNewline: false }, + projectPathRef.current || undefined + ); + } catch { + // Ignore transient failures + } + }, []); + + const scheduleFlush = useCallback(() => { + if (flushTimerRef.current !== null) return; + flushTimerRef.current = window.setTimeout(async () => { + flushTimerRef.current = null; + await flushInput(); + }, 30); + }, [flushInput]); + + // ========== xterm Lifecycle ========== + + // Initialize xterm instance (once per mount) + useEffect(() => { + if (!terminalHostRef.current) return; + if (xtermRef.current) return; + + const term = new XTerm({ + convertEol: true, + cursorBlink: true, + fontFamily: + 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace', + fontSize: 12, + scrollback: 5000, + }); + const fitAddon = new FitAddon(); + term.loadAddon(fitAddon); + term.open(terminalHostRef.current); + fitAddon.fit(); + + // Forward keystrokes to backend (batched 30ms) + term.onData((data) => { + if (!sessionIdRef.current) return; + pendingInputRef.current += data; + scheduleFlush(); + }); + + xtermRef.current = term; + fitAddonRef.current = fitAddon; + + return () => { + // Flush any pending input before cleanup + if (flushTimerRef.current !== null) { + window.clearTimeout(flushTimerRef.current); + flushTimerRef.current = null; + } + try { + term.dispose(); + } finally { + xtermRef.current = null; + fitAddonRef.current = null; + } + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + // Attach to session: clear terminal and load buffer + useEffect(() => { + const term = xtermRef.current; + const fitAddon = fitAddonRef.current; + if (!term || !fitAddon) return; + + lastChunkIndexRef.current = 0; + term.reset(); + term.clear(); + + if (!sessionId) return; + clearOutput(sessionId); + + fetchCliSessionBuffer(sessionId, projectPath || undefined) + .then(({ buffer }) => { + setBuffer(sessionId, buffer || ''); + }) + .catch(() => { + // ignore + }) + .finally(() => { + fitAddon.fit(); + }); + }, [sessionId, projectPath, setBuffer, clearOutput]); + + // Stream new output chunks into xterm and forward to monitor worker + useEffect(() => { + const term = xtermRef.current; + if (!term || !sessionId) return; + + const chunks = outputChunks[sessionId] ?? []; + const start = lastChunkIndexRef.current; + if (start >= chunks.length) return; + + const { feedMonitor } = useSessionManagerStore.getState(); + for (let i = start; i < chunks.length; i++) { + term.write(chunks[i].data); + feedMonitor(sessionId, chunks[i].data); + } + lastChunkIndexRef.current = chunks.length; + }, [outputChunks, sessionId]); + + // ResizeObserver -> fit + resize backend + useEffect(() => { + const host = terminalHostRef.current; + const term = xtermRef.current; + const fitAddon = fitAddonRef.current; + if (!host || !term || !fitAddon) return; + + const resize = () => { + fitAddon.fit(); + if (sessionIdRef.current) { + void (async () => { + try { + await resizeCliSession( + sessionIdRef.current, + { cols: term.cols, rows: term.rows }, + projectPathRef.current || undefined + ); + } catch { + // ignore + } + })(); + } + }; + + const ro = new ResizeObserver(resize); + ro.observe(host); + return () => ro.disconnect(); + }, [sessionId, projectPath]); + + // ========== Render ========== + + return ( +
+ ); +} diff --git a/ccw/frontend/src/components/terminal-dashboard/TerminalTabBar.tsx b/ccw/frontend/src/components/terminal-dashboard/TerminalTabBar.tsx new file mode 100644 index 00000000..e702a13c --- /dev/null +++ b/ccw/frontend/src/components/terminal-dashboard/TerminalTabBar.tsx @@ -0,0 +1,93 @@ +// ======================================== +// TerminalTabBar Component +// ======================================== +// Horizontal tab strip for terminal sessions in the Terminal Dashboard. +// Renders tabs from sessionManagerStore groups with status indicators and alert badges. + +import { useIntl } from 'react-intl'; +import { Terminal } from 'lucide-react'; +import { cn } from '@/lib/utils'; +import { + useSessionManagerStore, + selectGroups, + selectSessionManagerActiveTerminalId, + selectTerminalMetas, +} from '@/stores/sessionManagerStore'; +import type { TerminalStatus } from '@/types/terminal-dashboard'; + +// ========== Status Styles ========== + +const statusDotStyles: Record = { + active: 'bg-green-500', + idle: 'bg-gray-400', + error: 'bg-red-500', +}; + +// ========== Component ========== + +export function TerminalTabBar() { + const { formatMessage } = useIntl(); + const groups = useSessionManagerStore(selectGroups); + const activeTerminalId = useSessionManagerStore(selectSessionManagerActiveTerminalId); + const terminalMetas = useSessionManagerStore(selectTerminalMetas); + const setActiveTerminal = useSessionManagerStore((s) => s.setActiveTerminal); + + // Flatten all sessionIds from all groups + const allSessionIds = groups.flatMap((g) => g.sessionIds); + + if (allSessionIds.length === 0) { + return ( +
+ + + {formatMessage({ id: 'terminalDashboard.tabBar.noTabs' })} + +
+ ); + } + + return ( +
+ {allSessionIds.map((sessionId) => { + const meta = terminalMetas[sessionId]; + const title = meta?.title ?? sessionId; + const status: TerminalStatus = meta?.status ?? 'idle'; + const alertCount = meta?.alertCount ?? 0; + const isActive = activeTerminalId === sessionId; + + return ( + + ); + })} +
+ ); +} diff --git a/ccw/frontend/src/components/terminal-dashboard/TerminalWorkbench.tsx b/ccw/frontend/src/components/terminal-dashboard/TerminalWorkbench.tsx new file mode 100644 index 00000000..816c3633 --- /dev/null +++ b/ccw/frontend/src/components/terminal-dashboard/TerminalWorkbench.tsx @@ -0,0 +1,49 @@ +// ======================================== +// TerminalWorkbench Component +// ======================================== +// Container for the right panel of the Terminal Dashboard. +// Combines TerminalTabBar (tab switching) and TerminalInstance (xterm.js) +// in a flex-col layout. MVP scope: single terminal view (1x1 grid). + +import { useIntl } from 'react-intl'; +import { Terminal } from 'lucide-react'; +import { + useSessionManagerStore, + selectSessionManagerActiveTerminalId, +} from '@/stores/sessionManagerStore'; +import { TerminalTabBar } from './TerminalTabBar'; +import { TerminalInstance } from './TerminalInstance'; + +// ========== Component ========== + +export function TerminalWorkbench() { + const { formatMessage } = useIntl(); + const activeTerminalId = useSessionManagerStore(selectSessionManagerActiveTerminalId); + + return ( +
+ {/* Tab strip (fixed height) */} + + + {/* Terminal content (flex-1, takes remaining space) */} + {activeTerminalId ? ( +
+ +
+ ) : ( + /* Empty state when no terminal is selected */ +
+
+ +

+ {formatMessage({ id: 'terminalDashboard.workbench.noTerminal' })} +

+

+ {formatMessage({ id: 'terminalDashboard.workbench.noTerminalHint' })} +

+
+
+ )} +
+ ); +} diff --git a/ccw/frontend/src/components/terminal-panel/TerminalMainArea.tsx b/ccw/frontend/src/components/terminal-panel/TerminalMainArea.tsx index 054ef7d7..9eab5784 100644 --- a/ccw/frontend/src/components/terminal-panel/TerminalMainArea.tsx +++ b/ccw/frontend/src/components/terminal-panel/TerminalMainArea.tsx @@ -9,7 +9,6 @@ import { useIntl } from 'react-intl'; import { X, Terminal as TerminalIcon, - Plus, Trash2, RotateCcw, Loader2, @@ -22,7 +21,6 @@ import { useCliSessionStore, type CliSessionMeta } from '@/stores/cliSessionStor import { useWorkflowStore, selectProjectPath } from '@/stores/workflowStore'; import { QueueExecutionListView } from './QueueExecutionListView'; import { - createCliSession, fetchCliSessionBuffer, sendCliSessionText, resizeCliSession, @@ -41,14 +39,12 @@ export function TerminalMainArea({ onClose }: TerminalMainAreaProps) { const { formatMessage } = useIntl(); const panelView = useTerminalPanelStore((s) => s.panelView); const activeTerminalId = useTerminalPanelStore((s) => s.activeTerminalId); - const openTerminal = useTerminalPanelStore((s) => s.openTerminal); const removeTerminal = useTerminalPanelStore((s) => s.removeTerminal); const sessions = useCliSessionStore((s) => s.sessions); const outputChunks = useCliSessionStore((s) => s.outputChunks); const setBuffer = useCliSessionStore((s) => s.setBuffer); const clearOutput = useCliSessionStore((s) => s.clearOutput); - const upsertSession = useCliSessionStore((s) => s.upsertSession); const removeSessionFromStore = useCliSessionStore((s) => s.removeSession); const projectPath = useWorkflowStore(selectProjectPath); @@ -69,12 +65,8 @@ export function TerminalMainArea({ onClose }: TerminalMainAreaProps) { const flushTimerRef = useRef(null); // Toolbar state - const [isCreating, setIsCreating] = useState(false); const [isClosing, setIsClosing] = useState(false); - // Available CLI tools - const CLI_TOOLS = ['claude', 'gemini', 'qwen', 'codex', 'opencode'] as const; - const flushInput = useCallback(async () => { const sessionKey = activeTerminalId; if (!sessionKey) return; @@ -204,23 +196,6 @@ export function TerminalMainArea({ onClose }: TerminalMainAreaProps) { // ========== CLI Session Actions ========== - const handleCreateSession = useCallback(async (tool: string) => { - if (!projectPath || isCreating) return; - setIsCreating(true); - try { - const created = await createCliSession( - { workingDir: projectPath, tool }, - projectPath - ); - upsertSession(created.session); - openTerminal(created.session.sessionKey); - } catch (err) { - console.error('[TerminalMainArea] createCliSession failed:', err); - } finally { - setIsCreating(false); - } - }, [projectPath, isCreating, upsertSession, openTerminal]); - const handleCloseSession = useCallback(async () => { if (!activeTerminalId || isClosing) return; setIsClosing(true); @@ -268,50 +243,30 @@ export function TerminalMainArea({ onClose }: TerminalMainAreaProps) {
{/* Toolbar */} - {panelView === 'terminal' && ( + {panelView === 'terminal' && activeTerminalId && (
- {/* New CLI session buttons */} - {CLI_TOOLS.map((tool) => ( - - ))} -
{/* Terminal actions */} - {activeTerminalId && ( - <> - - - - )} + +
)} @@ -328,29 +283,12 @@ export function TerminalMainArea({ onClose }: TerminalMainAreaProps) { />
) : ( - /* Empty State - with quick launch */ + /* Empty State */

{formatMessage({ id: 'home.terminalPanel.noTerminalSelected' })}

-

{formatMessage({ id: 'home.terminalPanel.selectTerminalHint' })}

- {projectPath && ( -
- {CLI_TOOLS.map((tool) => ( - - ))} -
- )} +

{formatMessage({ id: 'home.terminalPanel.selectTerminalHint' })}

)} diff --git a/ccw/frontend/src/components/terminal-panel/TerminalNavBar.tsx b/ccw/frontend/src/components/terminal-panel/TerminalNavBar.tsx index 3d9b2a33..ad1abb44 100644 --- a/ccw/frontend/src/components/terminal-panel/TerminalNavBar.tsx +++ b/ccw/frontend/src/components/terminal-panel/TerminalNavBar.tsx @@ -11,7 +11,7 @@ import { cn } from '@/lib/utils'; import { useTerminalPanelStore } from '@/stores/terminalPanelStore'; import { useCliSessionStore, type CliSessionMeta, type CliSessionOutputChunk } from '@/stores/cliSessionStore'; import { useWorkflowStore, selectProjectPath } from '@/stores/workflowStore'; -import { createCliSession } from '@/lib/api'; +import { createCliSession, sendCliSessionText } from '@/lib/api'; // ========== Status Badge Mapping ========== @@ -45,6 +45,16 @@ const StatusIcon: Record> = { + claude: { default: 'claude', yolo: 'claude --permission-mode bypassPermissions' }, + gemini: { default: 'gemini', yolo: 'gemini --approval-mode yolo' }, + qwen: { default: 'qwen', yolo: 'qwen --approval-mode yolo' }, + codex: { default: 'codex', yolo: 'codex --full-auto' }, + opencode: { default: 'opencode', yolo: 'opencode' }, +}; + export function TerminalNavBar() { const panelView = useTerminalPanelStore((s) => s.panelView); const activeTerminalId = useTerminalPanelStore((s) => s.activeTerminalId); @@ -61,6 +71,7 @@ export function TerminalNavBar() { const projectPath = useWorkflowStore(selectProjectPath); const [isCreating, setIsCreating] = useState(false); const [showToolMenu, setShowToolMenu] = useState(false); + const [launchMode, setLaunchMode] = useState('yolo'); const CLI_TOOLS = ['claude', 'gemini', 'qwen', 'codex', 'opencode'] as const; @@ -75,12 +86,24 @@ export function TerminalNavBar() { ); upsertSession(created.session); openTerminal(created.session.sessionKey); + + // Auto-launch CLI tool after PTY is ready + const command = LAUNCH_COMMANDS[tool]?.[launchMode] ?? tool; + setTimeout(() => { + sendCliSessionText( + created.session.sessionKey, + { text: command, appendNewline: true }, + projectPath + ).catch((err) => + console.error('[TerminalNavBar] auto-launch failed:', err) + ); + }, 300); } catch (err) { console.error('[TerminalNavBar] createCliSession failed:', err); } finally { setIsCreating(false); } - }, [projectPath, isCreating, upsertSession, openTerminal]); + }, [projectPath, isCreating, launchMode, upsertSession, openTerminal]); const handleQueueClick = () => { setPanelView('queue'); @@ -173,7 +196,25 @@ export function TerminalNavBar() { {showToolMenu && ( <>
setShowToolMenu(false)} /> -
+
+ {/* Mode Toggle */} +
+ {(['default', 'yolo'] as const).map((mode) => ( + + ))} +
+ {/* Tool List */} {CLI_TOOLS.map((tool) => (