From cff1e16441e2152978da1c3247ead40384f8a2c8 Mon Sep 17 00:00:00 2001 From: catlog22 Date: Thu, 5 Mar 2026 20:02:46 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=9B=B4=E6=96=B0A2UIButton=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=E4=BB=A5=E6=94=AF=E6=8C=81A2UI=E5=BF=AB=E9=80=9F?= =?UTF-8?q?=E6=93=8D=E4=BD=9C=E5=92=8C=E5=8F=AF=E7=94=A8=E6=80=A7=E6=A3=80?= =?UTF-8?q?=E6=9F=A5=EF=BC=9B=E5=A2=9E=E5=BC=BAInjectionControlTab?= =?UTF-8?q?=E5=92=8CQueueExecutionListView=E7=BB=84=E4=BB=B6=E7=9A=84?= =?UTF-8?q?=E9=94=99=E8=AF=AF=E5=A4=84=E7=90=86=E5=92=8C=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../skills/workflow-multi-cli-plan/SKILL.md | 13 + .../phases/01-multi-cli-plan.md | 11 +- .../phases/02-lite-execute.md | 779 ------------------ .../src/components/layout/A2UIButton.tsx | 26 +- .../components/specs/InjectionControlTab.tsx | 6 +- .../terminal-panel/QueueExecutionListView.tsx | 25 +- 6 files changed, 68 insertions(+), 792 deletions(-) delete mode 100644 .claude/skills/workflow-multi-cli-plan/phases/02-lite-execute.md diff --git a/.claude/skills/workflow-multi-cli-plan/SKILL.md b/.claude/skills/workflow-multi-cli-plan/SKILL.md index e69de29b..07baee40 100644 --- a/.claude/skills/workflow-multi-cli-plan/SKILL.md +++ b/.claude/skills/workflow-multi-cli-plan/SKILL.md @@ -0,0 +1,13 @@ +--- +name: workflow-multi-cli-plan +description: Multi-CLI collaborative planning with ACE context gathering, iterative cross-verification, and execution handoff +allowed-tools: Skill, Agent, AskUserQuestion, TodoWrite, Read, Write, Edit, Bash, Glob, Grep +--- + +# Workflow-Multi-CLI-Plan + +Multi-CLI collaborative planning with ACE context gathering and iterative cross-verification. + +## Execution + +Execute Phase 1 directly: [phases/01-multi-cli-plan.md](phases/01-multi-cli-plan.md) diff --git a/.claude/skills/workflow-multi-cli-plan/phases/01-multi-cli-plan.md b/.claude/skills/workflow-multi-cli-plan/phases/01-multi-cli-plan.md index 92850270..40d9b269 100644 --- a/.claude/skills/workflow-multi-cli-plan/phases/01-multi-cli-plan.md +++ b/.claude/skills/workflow-multi-cli-plan/phases/01-multi-cli-plan.md @@ -459,9 +459,12 @@ executionContext = { **Step 4: Hand off to Execution**: ```javascript -// Direct phase handoff: Read and execute Phase 2 (lite-execute) with in-memory context -Read("phases/02-lite-execute.md") -// Execute Phase 2 with executionContext (Mode 1: In-Memory Plan) +// Skill handoff: Invoke workflow-lite-execute with in-memory context +Skill({ + skill: "workflow-lite-execute", + args: "--in-memory" +}) +// executionContext is passed via global variable to workflow-lite-execute (Mode 1: In-Memory Plan) ``` ## Output File Structure @@ -614,4 +617,4 @@ cat .workflow/.multi-cli-plan/{session-id}/context-package.json ## Next Phase -Return to orchestrator, then auto-continue to [Phase 2: Lite Execute](02-lite-execute.md) via Skill handoff. +Return to orchestrator, then auto-continue via `Skill({ skill: "workflow-lite-execute", args: "--in-memory" })` with executionContext. diff --git a/.claude/skills/workflow-multi-cli-plan/phases/02-lite-execute.md b/.claude/skills/workflow-multi-cli-plan/phases/02-lite-execute.md deleted file mode 100644 index 009445e2..00000000 --- a/.claude/skills/workflow-multi-cli-plan/phases/02-lite-execute.md +++ /dev/null @@ -1,779 +0,0 @@ -# Phase 2: Lite Execute - -> **📌 COMPACT SENTINEL [Phase 2: Lite-Execute]** -> This phase contains 6 execution steps (Step 1 — 6). -> If you can read this sentinel but cannot find the full Step protocol below, context has been compressed. -> Recovery: `Read("phases/02-lite-execute.md")` - -Complete execution engine supporting multiple input modes: in-memory plan, prompt description, or file content. - -## Objective - -- Execute implementation tasks from in-memory plan, prompt description, or file content -- Support batch execution with grouped tasks and code review - -## 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 - -> **Note**: This is an internal phase, not a standalone command. It is called by Phase 1 (multi-cli-plan) after plan approval, or by lite-plan after Phase 4 approval. - -## Input Modes - -### Mode 1: In-Memory Plan - -**Trigger**: Called by multi-cli-plan Phase 5 after plan approval, or by lite-plan after Phase 4 approval - -**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 -// Reference workflowPreferences (set by SKILL.md via AskUserQuestion) -const autoYes = workflowPreferences.autoYes - -let userSelection - -if (autoYes) { - // Auto mode: Use defaults - console.log(`[Auto] 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 → per-executor parallel batches (one CLI per batch) - │ ├─ Group: dependent tasks → sequential phases (respect dependencies) - │ └─ Create TodoWrite list for batches - ├─ Step 3: Launch execution - │ ├─ Phase 1: Independent tasks (⚡ per-executor batches, multi-CLI 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 } - }) -} - -// Executor Resolution (used by task grouping below) -// 获取任务的 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 -} - -// Group into batches: per-executor parallel batches (one CLI per batch) -function createExecutionCalls(tasks, executionMethod) { - const tasksWithDeps = extractDependencies(tasks) - const processed = new Set() - const calls = [] - - // Phase 1: Independent tasks → per-executor batches (multi-CLI concurrent) - const independentTasks = tasksWithDeps.filter(t => t.dependencies.length === 0) - if (independentTasks.length > 0) { - const executorGroups = groupTasksByExecutor(independentTasks) - let parallelIndex = 1 - - for (const [executor, tasks] of Object.entries(executorGroups)) { - if (tasks.length === 0) continue - tasks.forEach(t => processed.add(t.taskIndex)) - calls.push({ - method: executionMethod, - executor: executor, // 明确指定 executor - executionType: "parallel", - groupId: `P${parallelIndex++}`, - taskSummary: tasks.map(t => t.title).join(' | '), - tasks: tasks - }) - } - } - - // Phase 2: Dependent tasks → sequential/parallel 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) - } - - if (ready.length > 1) { - // Multiple ready tasks → per-executor batches (parallel within this phase) - const executorGroups = groupTasksByExecutor(ready) - for (const [executor, tasks] of Object.entries(executorGroups)) { - if (tasks.length === 0) continue - tasks.forEach(t => processed.add(t.taskIndex)) - calls.push({ - method: executionMethod, - executor: executor, - executionType: "parallel", - groupId: `P${calls.length + 1}`, - taskSummary: tasks.map(t => t.title).join(' | '), - tasks: tasks - }) - } - } else { - // Single ready task → sequential batch - ready.forEach(t => processed.add(t.taskIndex)) - calls.push({ - method: executionMethod, - executor: getTaskExecutor(ready[0]), - executionType: "sequential", - groupId: `S${sequentialIndex++}`, - taskSummary: ready[0].title, - 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.executor}] (${c.tasks.length} tasks)`, - status: "pending", - activeForm: `Executing ${c.id} [${c.executor}]` - })) -}) -``` - -### Step 3: Launch Execution - -**Executor Resolution**: `getTaskExecutor()` and `groupTasksByExecutor()` defined in Step 2 (Task Grouping). - -**Batch Execution Routing** (根据 batch.executor 字段路由): -```javascript -// executeBatch 根据 batch 自身的 executor 字段决定调用哪个 CLI -function executeBatch(batch) { - const executor = batch.executor || getTaskExecutor(batch.tasks[0]) - const sessionId = executionContext?.session?.id || 'standalone' - const fixedId = `${sessionId}-${batch.groupId}` - - if (executor === 'agent') { - // Agent execution (synchronous) - return Agent({ - subagent_type: "code-developer", - run_in_background: false, - description: batch.taskSummary, - prompt: buildExecutionPrompt(batch) - }) - } else if (executor === 'codex') { - // Codex CLI (background) - return Bash(`ccw cli -p "${buildExecutionPrompt(batch)}" --tool codex --mode write --id ${fixedId}`, { run_in_background: true }) - } else if (executor === 'gemini') { - // Gemini CLI (background) - return Bash(`ccw cli -p "${buildExecutionPrompt(batch)}" --tool gemini --mode write --id ${fixedId}`, { run_in_background: true }) - } -} -``` - -**并行执行原则**: -- 每个 batch 对应一个独立的 CLI 实例或 Agent 调用 -- 并行 = 多个 Bash(run_in_background=true) 或多个 Task() 同时发出 -- 绝不将多个独立任务合并到同一个 CLI prompt 中 -- Agent 任务不可后台执行(run_in_background=false),但多个 Agent 任务可通过单条消息中的多个 Task() 调用并发 - -**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/specs/*.md`) - 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: Auto-Sync Project State - -**Trigger**: After all executions complete (regardless of code review) - -**Operation**: Execute `/workflow:session:sync -y "{summary}"` to update both `specs/*.md` and `project-tech.json` in one shot. - -Summary 取值优先级:`originalUserInput` → `planObject.summary` → git log 自动推断。 - -## Best Practices - -**Input Modes**: In-memory (lite-plan), prompt (standalone), file (JSON/text) -**Task Grouping**: Based on explicit depends_on only; independent tasks split by executor, each batch runs as separate CLI instance -**Execution**: Independent task batches launch concurrently via single Claude message with multiple tool calls (one tool call per batch) - -## 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 - -**Auto-sync**: 执行 `/workflow:session:sync -y "{summary}"` 更新 specs/*.md + project-tech(Step 6 已触发,此处不重复)。 - -完成后询问用户是否扩展为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/ccw/frontend/src/components/layout/A2UIButton.tsx b/ccw/frontend/src/components/layout/A2UIButton.tsx index 3fafc062..366c5d52 100644 --- a/ccw/frontend/src/components/layout/A2UIButton.tsx +++ b/ccw/frontend/src/components/layout/A2UIButton.tsx @@ -8,15 +8,20 @@ import { MessageSquare } from 'lucide-react'; import { Button } from '@/components/ui/Button'; import { useDialogStyleContext } from '@/contexts/DialogStyleContext'; import { cn } from '@/lib/utils'; +import { useNotificationStore } from '@/stores'; interface A2UIButtonProps { className?: string; compact?: boolean; } + + export function A2UIButton({ className, compact = false }: A2UIButtonProps) { const { formatMessage } = useIntl(); const { preferences } = useDialogStyleContext(); + const a2uiSurfaces = useNotificationStore((state) => state.a2uiSurfaces); + const isA2UIAvailable = Object.keys(a2uiSurfaces).length > 0; // Don't render if hidden in preferences if (!preferences.showA2UIButtonInToolbar) { @@ -24,21 +29,36 @@ export function A2UIButton({ className, compact = false }: A2UIButtonProps) { } const handleClick = () => { - // Trigger A2UI quick action - this would typically open a dialog + // This would typically open the most relevant A2UI dialog // For now, we'll just log the action - console.log('[A2UIButton] Quick action triggered'); + if (isA2UIAvailable) { + console.log('[A2UIButton] Quick action triggered'); + // Example: find the first popup surface and handle it + const firstPopupId = Object.keys(a2uiSurfaces).find(id => a2uiSurfaces[id].displayMode === 'popup'); + if(firstPopupId) { + // In a real implementation, you might open a dialog here + // using the surface data. + console.log(`[A2UIButton] Would open dialog for surface: ${firstPopupId}`); + } + } }; + const buttonTitle = isA2UIAvailable + ? formatMessage({ id: 'navigation.toolbar.a2ui.quickAction', defaultMessage: 'A2UI Quick Action' }) + : formatMessage({ id: 'navigation.toolbar.a2ui.unavailable', defaultMessage: 'No A2UI action available' }); + return ( - );