diff --git a/.claude/commands/view.md b/.claude/commands/view.md deleted file mode 100644 index 3105c925..00000000 --- a/.claude/commands/view.md +++ /dev/null @@ -1,367 +0,0 @@ ---- -name: ccw view -description: Dashboard - Open CCW workflow dashboard for managing tasks and sessions -category: general ---- - -# CCW View Command - -Open the CCW workflow dashboard for visualizing and managing project tasks, sessions, and workflow execution status. - -## Description - -`ccw view` launches an interactive web dashboard that provides: -- **Workflow Overview**: Visualize current workflow status and command chain execution -- **Session Management**: View and manage active workflow sessions -- **Task Tracking**: Monitor TODO items and task progress -- **Workspace Switching**: Switch between different project workspaces -- **Real-time Updates**: Live updates of command execution and status - -## Usage - -```bash -# Open dashboard for current workspace -ccw view - -# Specify workspace path -ccw view --path /path/to/workspace - -# Custom port (default: 3456) -ccw view --port 3000 - -# Bind to specific host -ccw view --host 0.0.0.0 --port 3456 - -# Open without launching browser -ccw view --no-browser - -# Show URL without opening browser -ccw view --no-browser -``` - -## Options - -| Option | Default | Description | -|--------|---------|-------------| -| `--path ` | Current directory | Workspace path to display | -| `--port ` | 3456 | Server port for dashboard | -| `--host ` | 127.0.0.1 | Server host/bind address | -| `--no-browser` | false | Don't launch browser automatically | -| `-h, --help` | - | Show help message | - -## Features - -### Dashboard Sections - -#### 1. **Workflow Overview** -- Current workflow status -- Command chain visualization (with Minimum Execution Units marked) -- Live progress tracking -- Error alerts - -#### 2. **Session Management** -- List active sessions by type (workflow, review, tdd) -- Session details (created time, last activity, session ID) -- Quick actions (resume, pause, complete) -- Session logs/history - -#### 3. **Task Tracking** -- TODO list with status indicators -- Progress percentage -- Task grouping by workflow stage -- Quick inline task updates - -#### 4. **Workspace Switcher** -- Browse available workspaces -- Switch context with one click -- Recent workspaces list - -#### 5. **Command History** -- Recent commands executed -- Execution time and status -- Quick re-run options - -### Keyboard Shortcuts - -| Shortcut | Action | -|----------|--------| -| `R` | Refresh dashboard | -| `Cmd/Ctrl + J` | Jump to session search | -| `Cmd/Ctrl + K` | Open command palette | -| `?` | Show help | - -## Multi-Instance Support - -The dashboard supports multiple concurrent instances: - -```bash -# Terminal 1: Workspace A on port 3456 -ccw view --path ~/projects/workspace-a - -# Terminal 2: Workspace B on port 3457 -ccw view --path ~/projects/workspace-b --port 3457 - -# Switching workspaces on the same port -ccw view --path ~/projects/workspace-c # Auto-switches existing server -``` - -When the server is already running and you execute `ccw view` with a different path: -1. Detects running server on the port -2. Sends workspace switch request -3. Updates dashboard to new workspace -4. Opens browser with updated context - -## Server Lifecycle - -### Startup - -``` -ccw view - ├─ Check if server running on port - │ ├─ If yes: Send switch-path request - │ └─ If no: Start new server - ├─ Launch browser (unless --no-browser) - └─ Display dashboard URL -``` - -### Running - -The dashboard server continues running until: -- User explicitly stops it (Ctrl+C) -- All connections close after timeout -- System shutdown - -### Multiple Workspaces - -Switching to a different workspace keeps the same server instance: -``` -Server State Before: workspace-a on port 3456 -ccw view --path ~/projects/workspace-b -Server State After: workspace-b on port 3456 (same instance) -``` - -## Environment Variables - -```bash -# Set default port -export CCW_VIEW_PORT=4000 -ccw view # Uses port 4000 - -# Set default host -export CCW_VIEW_HOST=localhost -ccw view --port 3456 # Binds to localhost:3456 - -# Disable browser launch by default -export CCW_VIEW_NO_BROWSER=true -ccw view # Won't auto-launch browser -``` - -## Integration with CCW Workflows - -The dashboard is fully integrated with CCW commands: - -### Viewing Workflow Progress - -```bash -# Start a workflow -ccw "Add user authentication" - -# In another terminal, view progress -ccw view # Shows execution progress in real-time -``` - -### Session Management from Dashboard - -- Start new session: Click "New Session" button -- Resume paused session: Sessions list → Resume button -- View session logs: Click session name -- Complete session: Sessions list → Complete button - -### Real-time Command Execution - -- View active command chain execution -- Watch command transition through Minimum Execution Units -- See error alerts and recovery options -- View command output logs - -## Troubleshooting - -### Port Already in Use - -```bash -# Use different port -ccw view --port 3457 - -# Or kill existing server -lsof -i :3456 # Find process -kill -9 # Kill it -ccw view # Start fresh -``` - -### Dashboard Not Loading - -```bash -# Try without browser -ccw view --no-browser - -# Check server logs -tail -f ~/.ccw/logs/dashboard.log - -# Verify network access -curl http://localhost:3456/api/health -``` - -### Workspace Path Not Found - -```bash -# Use full absolute path -ccw view --path "$(pwd)" - -# Or specify explicit path -ccw view --path ~/projects/my-project -``` - -## Related Commands - -- **`/ccw`** - Main workflow orchestrator -- **`/workflow:session:list`** - List workflow sessions -- **`/workflow:session:resume`** - Resume paused session -- **`/memory:compact`** - Compact session memory for dashboard display - -## Examples - -### Basic Dashboard View - -```bash -cd ~/projects/my-app -ccw view -# → Launches http://localhost:3456 in browser -``` - -### Network-Accessible Dashboard - -```bash -# Allow remote access -ccw view --host 0.0.0.0 --port 3000 -# → Dashboard accessible at http://machine-ip:3000 -``` - -### Multiple Workspaces on Different Ports - -```bash -# Terminal 1: Main project -ccw view --path ~/projects/main --port 3456 - -# Terminal 2: Side project -ccw view --path ~/projects/side --port 3457 - -# View both simultaneously -# → http://localhost:3456 (main) -# → http://localhost:3457 (side) -``` - -### Headless Dashboard - -```bash -# Run dashboard without browser -ccw view --port 3000 --no-browser -echo "Dashboard available at http://localhost:3000" - -# Share URL with team -# Can be proxied through nginx/port forwarding -``` - -### Environment-Based Configuration - -```bash -# Script for CI/CD -export CCW_VIEW_HOST=0.0.0.0 -export CCW_VIEW_PORT=8080 -ccw view --path /workspace - -# → Dashboard accessible on port 8080 to all interfaces -``` - -## Dashboard Pages - -### Overview Page (`/`) -- Current workflow status -- Active sessions summary -- Recent commands -- System health indicators - -### Sessions Page (`/sessions`) -- All sessions (grouped by type) -- Session details and metadata -- Session logs viewer -- Quick actions (resume/complete) - -### Tasks Page (`/tasks`) -- Current TODO items -- Progress tracking -- Inline task editing -- Workflow history - -### Workspace Page (`/workspace`) -- Current workspace info -- Available workspaces -- Workspace switcher -- Workspace settings - -### Settings Page (`/settings`) -- Port configuration -- Theme preferences -- Auto-refresh settings -- Export settings - -## Server Health Monitoring - -The dashboard includes health monitoring: - -```bash -# Check health endpoint -curl http://localhost:3456/api/health -# → { "status": "ok", "uptime": 12345 } - -# Monitor metrics -curl http://localhost:3456/api/metrics -# → { "sessions": 3, "tasks": 15, "lastUpdate": "2025-01-29T10:30:00Z" } -``` - -## Advanced Usage - -### Custom Port with Dynamic Discovery - -```bash -# Find next available port -available_port=$(find-available-port 3456) -ccw view --port $available_port - -# Display in CI/CD -echo "Dashboard: http://localhost:$available_port" -``` - -### Dashboard Behind Proxy - -```bash -# Configure nginx reverse proxy -# Proxy http://proxy.example.com/dashboard → http://localhost:3456 - -ccw view --host 127.0.0.1 --port 3456 - -# Access via proxy -# http://proxy.example.com/dashboard -``` - -### Session Export from Dashboard - -- View → Sessions → Export JSON -- Exports session metadata and progress -- Useful for record-keeping and reporting - -## See Also - -- **CCW Commands**: `/ccw` - Auto workflow orchestration -- **Session Management**: `/workflow:session:start`, `/workflow:session:list` -- **Task Tracking**: `TodoWrite` tool for programmatic task management -- **Workflow Status**: `/workflow:status` for CLI-based status view diff --git a/.claude/commands/workflow/analyze-with-file.md b/.claude/commands/workflow/analyze-with-file.md index c690177b..ef6a0d0c 100644 --- a/.claude/commands/workflow/analyze-with-file.md +++ b/.claude/commands/workflow/analyze-with-file.md @@ -613,7 +613,13 @@ User agrees with current direction, wants deeper code analysis - Current design allows horizontal scaling without session affinity ``` -## Usage Recommendations (Requires User Confirmation) +## Usage Recommendations(Requires User Confirmation) + +**When to Execute Directly :** +- Short, focused analysis tasks (single module/component) +- Clear, well-defined topics with limited scope +- Quick information gathering without multi-round iteration +- Follow-up analysis building on existing session **Use `Skill(skill="workflow:analyze-with-file", args="\"topic\"")` when:** - Exploring a complex topic collaboratively diff --git a/.claude/commands/workflow/lite-lite-lite.md b/.claude/commands/workflow/lite-lite-lite.md deleted file mode 100644 index 6467a986..00000000 --- a/.claude/commands/workflow/lite-lite-lite.md +++ /dev/null @@ -1,465 +0,0 @@ ---- -name: workflow:lite-lite-lite -description: Ultra-lightweight multi-tool analysis and direct execution. No artifacts for simple tasks; auto-creates planning docs in .workflow/.scratchpad/ for complex tasks. Auto tool selection based on task analysis, user-driven iteration via AskUser. -argument-hint: "[-y|--yes] " -allowed-tools: TodoWrite(*), Task(*), AskUserQuestion(*), Read(*), Bash(*), Write(*), mcp__ace-tool__search_context(*), mcp__ccw-tools__write_file(*) ---- - -## Auto Mode - -When `--yes` or `-y`: Skip clarification questions, auto-select tools, execute directly with recommended settings. - -# Ultra-Lite Multi-Tool Workflow - -## Quick Start - -```bash -/workflow:lite-lite-lite "Fix the login bug" -/workflow:lite-lite-lite "Refactor payment module for multi-gateway support" -``` - -**Core Philosophy**: Minimal friction, maximum velocity. Simple tasks = no artifacts. Complex tasks = lightweight planning doc in `.workflow/.scratchpad/`. - -## Overview - -**Complexity-aware workflow**: Clarify → Assess Complexity → Select Tools → Multi-Mode Analysis → Decision → Direct Execution - -**vs multi-cli-plan**: No IMPL_PLAN.md, plan.json, synthesis.json - state in memory or lightweight scratchpad doc for complex tasks. - -## Execution Flow - -``` -Phase 1: Clarify Requirements → AskUser for missing details -Phase 1.5: Assess Complexity → Determine if planning doc needed -Phase 2: Select Tools (CLI → Mode → Agent) → 3-step selection -Phase 3: Multi-Mode Analysis → Execute with --resume chaining -Phase 4: User Decision → Execute / Refine / Change / Cancel -Phase 5: Direct Execution → No plan files (simple) or scratchpad doc (complex) -``` - -## Phase 1: Clarify Requirements - -```javascript -const taskDescription = $ARGUMENTS - -if (taskDescription.length < 20 || isAmbiguous(taskDescription)) { - AskUserQuestion({ - questions: [{ - question: "Please provide more details: target files/modules, expected behavior, constraints?", - header: "Details", - options: [ - { label: "I'll provide more", description: "Add more context" }, - { label: "Continue analysis", description: "Let tools explore autonomously" } - ], - multiSelect: false - }] - }) -} - -// Optional: Quick ACE Context for complex tasks -mcp__ace-tool__search_context({ - project_root_path: process.cwd(), - query: `${taskDescription} implementation patterns` -}) -``` - -## Phase 1.5: Assess Complexity - -| Level | Creates Plan Doc | Trigger Keywords | -|-------|------------------|------------------| -| **simple** | ❌ | (default) | -| **moderate** | ✅ | module, system, service, integration, multiple | -| **complex** | ✅ | refactor, migrate, security, auth, payment, database | - -```javascript -// Complexity detection (after ACE query) -const isComplex = /refactor|migrate|security|auth|payment|database/i.test(taskDescription) -const isModerate = /module|system|service|integration|multiple/i.test(taskDescription) || aceContext?.relevant_files?.length > 2 - -if (isComplex || isModerate) { - const planPath = `.workflow/.scratchpad/lite3-${taskSlug}-${dateStr}.md` - // Create planning doc with: Task, Status, Complexity, Analysis Summary, Execution Plan, Progress Log -} -``` - -## Phase 2: Select Tools - -### Tool Definitions - -**CLI Tools** (from cli-tools.json): -```javascript -const cliConfig = JSON.parse(Read("~/.claude/cli-tools.json")) -const cliTools = Object.entries(cliConfig.tools) - .filter(([_, config]) => config.enabled) - .map(([name, config]) => ({ - name, type: 'cli', - tags: config.tags || [], - model: config.primaryModel, - toolType: config.type // builtin, cli-wrapper, api-endpoint - })) -``` - -**Sub Agents**: - -| Agent | Strengths | canExecute | -|-------|-----------|------------| -| **code-developer** | Code implementation, test writing | ✅ | -| **Explore** | Fast code exploration, pattern discovery | ❌ | -| **cli-explore-agent** | Dual-source analysis (Bash+CLI) | ❌ | -| **cli-discuss-agent** | Multi-CLI collaboration, cross-verification | ❌ | -| **debug-explore-agent** | Hypothesis-driven debugging | ❌ | -| **context-search-agent** | Multi-layer file discovery, dependency analysis | ❌ | -| **test-fix-agent** | Test execution, failure diagnosis, code fixing | ✅ | -| **universal-executor** | General execution, multi-domain adaptation | ✅ | - -**Analysis Modes**: - -| Mode | Pattern | Use Case | minCLIs | -|------|---------|----------|---------| -| **Parallel** | `A \|\| B \|\| C → Aggregate` | Fast multi-perspective | 1+ | -| **Sequential** | `A → B(resume) → C(resume)` | Incremental deepening | 2+ | -| **Collaborative** | `A → B → A → B → Synthesize` | Multi-round refinement | 2+ | -| **Debate** | `A(propose) → B(challenge) → A(defend)` | Adversarial validation | 2 | -| **Challenge** | `A(analyze) → B(challenge)` | Find flaws and risks | 2 | - -### Three-Step Selection Flow - -```javascript -// Step 1: Select CLIs (multiSelect) -AskUserQuestion({ - questions: [{ - question: "Select CLI tools for analysis (1-3 for collaboration modes)", - header: "CLI Tools", - options: cliTools.map(cli => ({ - label: cli.name, - description: cli.tags.length > 0 ? cli.tags.join(', ') : cli.model || 'general' - })), - multiSelect: true - }] -}) - -// Step 2: Select Mode (filtered by CLI count) -const availableModes = analysisModes.filter(m => selectedCLIs.length >= m.minCLIs) -AskUserQuestion({ - questions: [{ - question: "Select analysis mode", - header: "Mode", - options: availableModes.map(m => ({ - label: m.label, - description: `${m.description} [${m.pattern}]` - })), - multiSelect: false - }] -}) - -// Step 3: Select Agent for execution -AskUserQuestion({ - questions: [{ - question: "Select Sub Agent for execution", - header: "Agent", - options: agents.map(a => ({ label: a.name, description: a.strength })), - multiSelect: false - }] -}) - -// Confirm selection -AskUserQuestion({ - questions: [{ - question: "Confirm selection?", - header: "Confirm", - options: [ - { label: "Confirm and continue", description: `${selectedMode.label} with ${selectedCLIs.length} CLIs` }, - { label: "Re-select CLIs", description: "Choose different CLI tools" }, - { label: "Re-select Mode", description: "Choose different analysis mode" }, - { label: "Re-select Agent", description: "Choose different Sub Agent" } - ], - multiSelect: false - }] -}) -``` - -## Phase 3: Multi-Mode Analysis - -### Universal CLI Prompt Template - -```javascript -// Unified prompt builder - used by all modes -function buildPrompt({ purpose, tasks, expected, rules, taskDescription }) { - return ` -PURPOSE: ${purpose}: ${taskDescription} -TASK: ${tasks.map(t => `• ${t}`).join(' ')} -MODE: analysis -CONTEXT: @**/* -EXPECTED: ${expected} -CONSTRAINTS: ${rules} -` -} - -// Execute CLI with prompt -function execCLI(cli, prompt, options = {}) { - const { resume, background = false } = options - const resumeFlag = resume ? `--resume ${resume}` : '' - return Bash({ - command: `ccw cli -p "${prompt}" --tool ${cli.name} --mode analysis ${resumeFlag}`, - run_in_background: background - }) -} -``` - -### Prompt Presets by Role - -| Role | PURPOSE | TASKS | EXPECTED | RULES | -|------|---------|-------|----------|-------| -| **initial** | Initial analysis | Identify files, Analyze approach, List changes | Root cause, files, changes, risks | Focus on actionable insights | -| **extend** | Build on previous | Review previous, Extend, Add insights | Extended analysis building on findings | Build incrementally, avoid repetition | -| **synthesize** | Refine and synthesize | Review, Identify gaps, Synthesize | Refined synthesis with new perspectives | Add value not repetition | -| **propose** | Propose comprehensive analysis | Analyze thoroughly, Propose solution, State assumptions | Well-reasoned proposal with trade-offs | Be clear about assumptions | -| **challenge** | Challenge and stress-test | Identify weaknesses, Question assumptions, Suggest alternatives | Critique with counter-arguments | Be adversarial but constructive | -| **defend** | Respond to challenges | Address challenges, Defend valid aspects, Propose refined solution | Refined proposal incorporating feedback | Be open to criticism, synthesize | -| **criticize** | Find flaws ruthlessly | Find logical flaws, Identify edge cases, Rate criticisms | Critique with severity: [CRITICAL]/[HIGH]/[MEDIUM]/[LOW] | Be ruthlessly critical | - -```javascript -const PROMPTS = { - initial: { purpose: 'Initial analysis', tasks: ['Identify affected files', 'Analyze implementation approach', 'List specific changes'], expected: 'Root cause, files to modify, key changes, risks', rules: 'Focus on actionable insights' }, - extend: { purpose: 'Build on previous analysis', tasks: ['Review previous findings', 'Extend analysis', 'Add new insights'], expected: 'Extended analysis building on previous', rules: 'Build incrementally, avoid repetition' }, - synthesize: { purpose: 'Refine and synthesize', tasks: ['Review previous', 'Identify gaps', 'Add insights', 'Synthesize findings'], expected: 'Refined synthesis with new perspectives', rules: 'Build collaboratively, add value' }, - propose: { purpose: 'Propose comprehensive analysis', tasks: ['Analyze thoroughly', 'Propose solution', 'State assumptions clearly'], expected: 'Well-reasoned proposal with trade-offs', rules: 'Be clear about assumptions' }, - challenge: { purpose: 'Challenge and stress-test', tasks: ['Identify weaknesses', 'Question assumptions', 'Suggest alternatives', 'Highlight overlooked risks'], expected: 'Constructive critique with counter-arguments', rules: 'Be adversarial but constructive' }, - defend: { purpose: 'Respond to challenges', tasks: ['Address each challenge', 'Defend valid aspects', 'Acknowledge valid criticisms', 'Propose refined solution'], expected: 'Refined proposal incorporating alternatives', rules: 'Be open to criticism, synthesize best ideas' }, - criticize: { purpose: 'Stress-test and find weaknesses', tasks: ['Find logical flaws', 'Identify missed edge cases', 'Propose alternatives', 'Rate criticisms (High/Medium/Low)'], expected: 'Detailed critique with severity ratings', rules: 'Be ruthlessly critical, find every flaw' } -} -``` - -### Mode Implementations - -```javascript -// Parallel: All CLIs run simultaneously -async function executeParallel(clis, task) { - return await Promise.all(clis.map(cli => - execCLI(cli, buildPrompt({ ...PROMPTS.initial, taskDescription: task }), { background: true }) - )) -} - -// Sequential: Each CLI builds on previous via --resume -async function executeSequential(clis, task) { - const results = [] - let prevId = null - for (const cli of clis) { - const preset = prevId ? PROMPTS.extend : PROMPTS.initial - const result = await execCLI(cli, buildPrompt({ ...preset, taskDescription: task }), { resume: prevId }) - results.push(result) - prevId = extractSessionId(result) - } - return results -} - -// Collaborative: Multi-round synthesis -async function executeCollaborative(clis, task, rounds = 2) { - const results = [] - let prevId = null - for (let r = 0; r < rounds; r++) { - for (const cli of clis) { - const preset = !prevId ? PROMPTS.initial : PROMPTS.synthesize - const result = await execCLI(cli, buildPrompt({ ...preset, taskDescription: task }), { resume: prevId }) - results.push({ cli: cli.name, round: r, result }) - prevId = extractSessionId(result) - } - } - return results -} - -// Debate: Propose → Challenge → Defend -async function executeDebate(clis, task) { - const [cliA, cliB] = clis - const results = [] - - const propose = await execCLI(cliA, buildPrompt({ ...PROMPTS.propose, taskDescription: task })) - results.push({ phase: 'propose', cli: cliA.name, result: propose }) - - const challenge = await execCLI(cliB, buildPrompt({ ...PROMPTS.challenge, taskDescription: task }), { resume: extractSessionId(propose) }) - results.push({ phase: 'challenge', cli: cliB.name, result: challenge }) - - const defend = await execCLI(cliA, buildPrompt({ ...PROMPTS.defend, taskDescription: task }), { resume: extractSessionId(challenge) }) - results.push({ phase: 'defend', cli: cliA.name, result: defend }) - - return results -} - -// Challenge: Analyze → Criticize -async function executeChallenge(clis, task) { - const [cliA, cliB] = clis - const results = [] - - const analyze = await execCLI(cliA, buildPrompt({ ...PROMPTS.initial, taskDescription: task })) - results.push({ phase: 'analyze', cli: cliA.name, result: analyze }) - - const criticize = await execCLI(cliB, buildPrompt({ ...PROMPTS.criticize, taskDescription: task }), { resume: extractSessionId(analyze) }) - results.push({ phase: 'challenge', cli: cliB.name, result: criticize }) - - return results -} -``` - -### Mode Router & Result Aggregation - -```javascript -async function executeAnalysis(mode, clis, taskDescription) { - switch (mode.name) { - case 'parallel': return await executeParallel(clis, taskDescription) - case 'sequential': return await executeSequential(clis, taskDescription) - case 'collaborative': return await executeCollaborative(clis, taskDescription) - case 'debate': return await executeDebate(clis, taskDescription) - case 'challenge': return await executeChallenge(clis, taskDescription) - } -} - -function aggregateResults(mode, results) { - const base = { mode: mode.name, pattern: mode.pattern, tools_used: results.map(r => r.cli || 'unknown') } - - switch (mode.name) { - case 'parallel': - return { ...base, findings: results.map(parseOutput), consensus: findCommonPoints(results), divergences: findDifferences(results) } - case 'sequential': - return { ...base, evolution: results.map((r, i) => ({ step: i + 1, analysis: parseOutput(r) })), finalAnalysis: parseOutput(results.at(-1)) } - case 'collaborative': - return { ...base, rounds: groupByRound(results), synthesis: extractSynthesis(results.at(-1)) } - case 'debate': - return { ...base, proposal: parseOutput(results.find(r => r.phase === 'propose')?.result), - challenges: parseOutput(results.find(r => r.phase === 'challenge')?.result), - resolution: parseOutput(results.find(r => r.phase === 'defend')?.result), confidence: calculateDebateConfidence(results) } - case 'challenge': - return { ...base, originalAnalysis: parseOutput(results.find(r => r.phase === 'analyze')?.result), - critiques: parseCritiques(results.find(r => r.phase === 'challenge')?.result), riskScore: calculateRiskScore(results) } - } -} - -// If planPath exists: update Analysis Summary & Execution Plan sections -``` - -## Phase 4: User Decision - -```javascript -function presentSummary(analysis) { - console.log(`## Analysis Result\n**Mode**: ${analysis.mode} (${analysis.pattern})\n**Tools**: ${analysis.tools_used.join(' → ')}`) - - switch (analysis.mode) { - case 'parallel': - console.log(`### Consensus\n${analysis.consensus.map(c => `- ${c}`).join('\n')}\n### Divergences\n${analysis.divergences.map(d => `- ${d}`).join('\n')}`) - break - case 'sequential': - console.log(`### Evolution\n${analysis.evolution.map(e => `**Step ${e.step}**: ${e.analysis.summary}`).join('\n')}\n### Final\n${analysis.finalAnalysis.summary}`) - break - case 'collaborative': - console.log(`### Rounds\n${Object.entries(analysis.rounds).map(([r, a]) => `**Round ${r}**: ${a.map(x => x.cli).join(' + ')}`).join('\n')}\n### Synthesis\n${analysis.synthesis}`) - break - case 'debate': - console.log(`### Debate\n**Proposal**: ${analysis.proposal.summary}\n**Challenges**: ${analysis.challenges.points?.length || 0} points\n**Resolution**: ${analysis.resolution.summary}\n**Confidence**: ${analysis.confidence}%`) - break - case 'challenge': - console.log(`### Challenge\n**Original**: ${analysis.originalAnalysis.summary}\n**Critiques**: ${analysis.critiques.length} issues\n${analysis.critiques.map(c => `- [${c.severity}] ${c.description}`).join('\n')}\n**Risk Score**: ${analysis.riskScore}/100`) - break - } -} - -AskUserQuestion({ - questions: [{ - question: "How to proceed?", - header: "Next Step", - options: [ - { label: "Execute directly", description: "Implement immediately" }, - { label: "Refine analysis", description: "Add constraints, re-analyze" }, - { label: "Change tools", description: "Different tool combination" }, - { label: "Cancel", description: "End workflow" } - ], - multiSelect: false - }] -}) -// If planPath exists: record decision to Decisions Made table -// Routing: Execute → Phase 5 | Refine → Phase 3 | Change → Phase 2 | Cancel → End -``` - -## Phase 5: Direct Execution - -```javascript -// Simple tasks: No artifacts | Complex tasks: Update scratchpad doc -const executionAgents = agents.filter(a => a.canExecute) -const executionTool = selectedAgent.canExecute ? selectedAgent : selectedCLIs[0] - -if (executionTool.type === 'agent') { - Task({ - subagent_type: executionTool.name, - run_in_background: false, - description: `Execute: ${taskDescription.slice(0, 30)}`, - prompt: `## Task\n${taskDescription}\n\n## Analysis Results\n${JSON.stringify(aggregatedAnalysis, null, 2)}\n\n## Instructions\n1. Apply changes to identified files\n2. Follow recommended approach\n3. Handle identified risks\n4. Verify changes work correctly` - }) -} else { - Bash({ - command: `ccw cli -p " -PURPOSE: Implement solution: ${taskDescription} -TASK: ${extractedTasks.join(' • ')} -MODE: write -CONTEXT: @${affectedFiles.join(' @')} -EXPECTED: Working implementation with all changes applied -CONSTRAINTS: Follow existing patterns -" --tool ${executionTool.name} --mode write`, - run_in_background: false - }) -} -// If planPath exists: update Status to completed/failed, append to Progress Log -``` - -## TodoWrite Structure - -```javascript -TodoWrite({ todos: [ - { content: "Phase 1: Clarify requirements", status: "in_progress", activeForm: "Clarifying requirements" }, - { content: "Phase 1.5: Assess complexity", status: "pending", activeForm: "Assessing complexity" }, - { content: "Phase 2: Select tools", status: "pending", activeForm: "Selecting tools" }, - { content: "Phase 3: Multi-mode analysis", status: "pending", activeForm: "Running analysis" }, - { content: "Phase 4: User decision", status: "pending", activeForm: "Awaiting decision" }, - { content: "Phase 5: Direct execution", status: "pending", activeForm: "Executing" } -]}) -``` - -## Iteration Patterns - -| Pattern | Flow | -|---------|------| -| **Direct** | Phase 1 → 2 → 3 → 4(execute) → 5 | -| **Refinement** | Phase 3 → 4(refine) → 3 → 4 → 5 | -| **Tool Adjust** | Phase 2(adjust) → 3 → 4 → 5 | - -## Error Handling - -| Error | Resolution | -|-------|------------| -| CLI timeout | Retry with secondary model | -| No enabled tools | Ask user to enable tools in cli-tools.json | -| Task unclear | Default to first CLI + code-developer | -| Ambiguous task | Force clarification via AskUser | -| Execution fails | Present error, ask user for direction | -| Plan doc write fails | Continue without doc (degrade to zero-artifact mode) | -| Scratchpad dir missing | Auto-create `.workflow/.scratchpad/` | - -## Comparison with multi-cli-plan - -| Aspect | lite-lite-lite | multi-cli-plan | -|--------|----------------|----------------| -| **Artifacts** | Conditional (scratchpad doc for complex tasks) | Always (IMPL_PLAN.md, plan.json, synthesis.json) | -| **Session** | Stateless (--resume chaining) | Persistent session folder | -| **Tool Selection** | 3-step (CLI → Mode → Agent) | Config-driven fixed tools | -| **Analysis Modes** | 5 modes with --resume | Fixed synthesis rounds | -| **Complexity** | Auto-detected (simple/moderate/complex) | Assumed complex | -| **Best For** | Quick analysis, simple-to-moderate tasks | Complex multi-step implementations | - -## Post-Completion Expansion - -完成后询问用户是否扩展为issue(test/enhance/refactor/doc),选中项调用 `/issue:new "{summary} - {dimension}"` - -## Related Commands - -```bash -/workflow:multi-cli-plan "complex task" # Full planning workflow -/workflow:lite-plan "task" # Single CLI planning -/workflow:lite-execute --in-memory # Direct execution -``` diff --git a/.claude/skills/ccw-loop/SKILL.md b/.claude/skills/ccw-loop/SKILL.md deleted file mode 100644 index 2a58cf4a..00000000 --- a/.claude/skills/ccw-loop/SKILL.md +++ /dev/null @@ -1,259 +0,0 @@ ---- -name: ccw-loop -description: Stateless iterative development loop workflow with documented progress. Supports develop, debug, and validate phases with file-based state tracking. Triggers on "ccw-loop", "dev loop", "development loop", "开发循环", "迭代开发". -allowed-tools: Task(*), AskUserQuestion(*), Read(*), Grep(*), Glob(*), Bash(*), Edit(*), Write(*), TodoWrite(*) ---- - -# CCW Loop - Stateless Iterative Development Workflow - -无状态迭代开发循环工作流,支持开发 (develop)、调试 (debug)、验证 (validate) 三个阶段,每个阶段都有独立的文件记录进展。 - -## Arguments - -| Arg | Required | Description | -|-----|----------|-------------| -| task | No | Task description (for new loop, mutually exclusive with --loop-id) | -| --loop-id | No | Existing loop ID to continue (from API or previous session) | -| --auto | No | Auto-cycle mode (develop → debug → validate → complete) | - -## Unified Architecture (API + Skill Integration) - -``` -┌─────────────────────────────────────────────────────────────────┐ -│ Dashboard (UI) │ -│ [Create] [Start] [Pause] [Resume] [Stop] [View Progress] │ -└─────────────────────────────────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────────────────┐ -│ loop-v2-routes.ts (Control Plane) │ -│ │ -│ State: .loop/{loopId}.json (MASTER) │ -│ Tasks: .loop/{loopId}.tasks.jsonl │ -│ │ -│ /start → Trigger ccw-loop skill with --loop-id │ -│ /pause → Set status='paused' (skill checks before action) │ -│ /stop → Set status='failed' (skill terminates) │ -│ /resume → Set status='running' (skill continues) │ -└─────────────────────────────────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────────────────┐ -│ ccw-loop Skill (Execution Plane) │ -│ │ -│ Reads/Writes: .loop/{loopId}.json (unified state) │ -│ Writes: .loop/{loopId}.progress/* (progress files) │ -│ │ -│ BEFORE each action: │ -│ → Check status: paused/stopped → exit gracefully │ -│ → running → continue with action │ -│ │ -│ Actions: init → develop → debug → validate → complete │ -└─────────────────────────────────────────────────────────────────┘ -``` - -## Key Design Principles - -1. **统一状态**: API 和 Skill 共享 `.loop/{loopId}.json` 状态文件 -2. **控制信号**: Skill 每个 Action 前检查 status 字段 (paused/stopped) -3. **文件驱动**: 所有进度、理解、结果都记录在 `.loop/{loopId}.progress/` -4. **可恢复**: 任何时候可以继续之前的循环 (`--loop-id`) -5. **双触发**: 支持 API 触发 (`--loop-id`) 和直接调用 (task description) -6. **Gemini 辅助**: 使用 CLI 工具进行深度分析和假设验证 - -## Execution Modes - -### Mode 1: Interactive (交互式) - -用户手动选择每个动作,适合复杂任务。 - -``` -用户 → 选择动作 → 执行 → 查看结果 → 选择下一动作 -``` - -### Mode 2: Auto-Loop (自动循环) - -按预设顺序自动执行,适合标准开发流程。 - -``` -Develop → Debug → Validate → (如有问题) → Develop → ... -``` - -## Session Structure (Unified Location) - -``` -.loop/ -├── {loopId}.json # 主状态文件 (API + Skill 共享) -├── {loopId}.tasks.jsonl # 任务列表 (API 管理) -└── {loopId}.progress/ # Skill 进度文件 - ├── develop.md # 开发进度记录 - ├── debug.md # 理解演变文档 - ├── validate.md # 验证报告 - ├── changes.log # 代码变更日志 (NDJSON) - └── debug.log # 调试日志 (NDJSON) -``` - -## Directory Setup - -```javascript -// loopId 来源: -// 1. API 触发时: 从 --loop-id 参数获取 -// 2. 直接调用时: 生成新的 loop-v2-{timestamp}-{random} - -const loopId = args['--loop-id'] || generateLoopId() -const loopFile = `.loop/${loopId}.json` -const progressDir = `.loop/${loopId}.progress` - -// 创建进度目录 -Bash(`mkdir -p "${progressDir}"`) -``` - -## Action Catalog - -| Action | Purpose | Output Files | CLI Integration | -|--------|---------|--------------|-----------------| -| [action-init](phases/actions/action-init.md) | 初始化循环会话 | meta.json, state.json | - | -| [action-develop-with-file](phases/actions/action-develop-with-file.md) | 开发任务执行 | progress.md, tasks.json | gemini --mode write | -| [action-debug-with-file](phases/actions/action-debug-with-file.md) | 假设驱动调试 | understanding.md, hypotheses.json | gemini --mode analysis | -| [action-validate-with-file](phases/actions/action-validate-with-file.md) | 测试与验证 | validation.md, test-results.json | gemini --mode analysis | -| [action-complete](phases/actions/action-complete.md) | 完成循环 | summary.md | - | -| [action-menu](phases/actions/action-menu.md) | 显示操作菜单 | - | - | - -## Usage - -```bash -# 启动新循环 (直接调用) -/ccw-loop "实现用户认证功能" - -# 继续现有循环 (API 触发或手动恢复) -/ccw-loop --loop-id loop-v2-20260122-abc123 - -# 自动循环模式 -/ccw-loop --auto "修复登录bug并添加测试" - -# API 触发自动循环 -/ccw-loop --loop-id loop-v2-20260122-abc123 --auto -``` - -## Execution Flow - -``` -┌─────────────────────────────────────────────────────────────────┐ -│ /ccw-loop [ | --loop-id ] [--auto] │ -├─────────────────────────────────────────────────────────────────┤ -│ │ -│ 1. Parameter Detection: │ -│ ├─ IF --loop-id provided: │ -│ │ ├─ Read .loop/{loopId}.json │ -│ │ ├─ Validate status === 'running' │ -│ │ └─ Continue from skill_state.current_action │ -│ └─ ELSE (task description): │ -│ ├─ Generate new loopId │ -│ ├─ Create .loop/{loopId}.json │ -│ └─ Initialize with action-init │ -│ │ -│ 2. Orchestrator Loop: │ -│ ├─ Read state from .loop/{loopId}.json │ -│ ├─ Check control signals: │ -│ │ ├─ status === 'paused' → Exit (wait for resume) │ -│ │ ├─ status === 'failed' → Exit with error │ -│ │ └─ status === 'running' → Continue │ -│ ├─ Show menu / auto-select next action │ -│ ├─ Execute action │ -│ ├─ Update .loop/{loopId}.progress/{action}.md │ -│ ├─ Update .loop/{loopId}.json (skill_state) │ -│ └─ Loop or exit based on user choice / completion │ -│ │ -│ 3. Action Execution: │ -│ ├─ BEFORE: checkControlSignals() → exit if paused/stopped │ -│ ├─ Develop: Plan → Implement → Document progress │ -│ ├─ Debug: Hypothesize → Instrument → Analyze → Fix │ -│ ├─ Validate: Test → Check → Report │ -│ └─ AFTER: Update skill_state in .loop/{loopId}.json │ -│ │ -│ 4. Termination: │ -│ ├─ Control signal: paused (graceful exit, wait resume) │ -│ ├─ Control signal: stopped (failed state) │ -│ ├─ User exits (interactive mode) │ -│ ├─ All tasks completed (status → completed) │ -│ └─ Max iterations reached │ -│ │ -└─────────────────────────────────────────────────────────────────┘ -``` - -## Reference Documents - -| Document | Purpose | -|----------|---------| -| [phases/orchestrator.md](phases/orchestrator.md) | 编排器:状态读取 + 动作选择 | -| [phases/state-schema.md](phases/state-schema.md) | 状态结构定义 | -| [specs/loop-requirements.md](specs/loop-requirements.md) | 循环需求规范 | -| [specs/action-catalog.md](specs/action-catalog.md) | 动作目录 | -| [templates/progress-template.md](templates/progress-template.md) | 进度文档模板 | -| [templates/understanding-template.md](templates/understanding-template.md) | 理解文档模板 | - -## Integration with Loop Monitor (Dashboard) - -此 Skill 与 CCW Dashboard 的 Loop Monitor 实现 **控制平面 + 执行平面** 分离架构: - -### Control Plane (Dashboard/API → loop-v2-routes.ts) - -1. **创建循环**: `POST /api/loops/v2` → 创建 `.loop/{loopId}.json` -2. **启动执行**: `POST /api/loops/v2/:loopId/start` → 触发 `/ccw-loop --loop-id {loopId} --auto` -3. **暂停执行**: `POST /api/loops/v2/:loopId/pause` → 设置 `status='paused'` (Skill 下次检查时退出) -4. **恢复执行**: `POST /api/loops/v2/:loopId/resume` → 设置 `status='running'` → 重新触发 Skill -5. **停止执行**: `POST /api/loops/v2/:loopId/stop` → 设置 `status='failed'` - -### Execution Plane (ccw-loop Skill) - -1. **读取状态**: 从 `.loop/{loopId}.json` 读取 API 设置的状态 -2. **检查控制**: 每个 Action 前检查 `status` 字段 -3. **执行动作**: develop → debug → validate → complete -4. **更新进度**: 写入 `.loop/{loopId}.progress/*.md` 和更新 `skill_state` -5. **状态同步**: Dashboard 通过读取 `.loop/{loopId}.json` 获取进度 - -## CLI Integration Points - -### Develop Phase -```bash -ccw cli -p "PURPOSE: Implement {task}... -TASK: • Analyze requirements • Write code • Update progress -MODE: write -CONTEXT: @progress.md @tasks.json -EXPECTED: Implementation + updated progress.md -" --tool gemini --mode write --rule development-implement-feature -``` - -### Debug Phase -```bash -ccw cli -p "PURPOSE: Generate debugging hypotheses... -TASK: • Analyze error • Generate hypotheses • Add instrumentation -MODE: analysis -CONTEXT: @understanding.md @debug.log -EXPECTED: Hypotheses + instrumentation plan -" --tool gemini --mode analysis --rule analysis-diagnose-bug-root-cause -``` - -### Validate Phase -```bash -ccw cli -p "PURPOSE: Validate implementation... -TASK: • Run tests • Check coverage • Verify requirements -MODE: analysis -CONTEXT: @validation.md @test-results.json -EXPECTED: Validation report -" --tool gemini --mode analysis --rule analysis-review-code-quality -``` - -## Error Handling - -| Situation | Action | -|-----------|--------| -| Session not found | Create new session | -| State file corrupted | Rebuild from file contents | -| CLI tool fails | Fallback to manual analysis | -| Tests fail | Loop back to develop/debug | -| >10 iterations | Warn user, suggest break | - -## Post-Completion Expansion - -完成后询问用户是否扩展为 issue (test/enhance/refactor/doc),选中项调用 `/issue:new "{summary} - {dimension}"` diff --git a/.claude/skills/ccw-loop/phases/actions/action-complete.md b/.claude/skills/ccw-loop/phases/actions/action-complete.md deleted file mode 100644 index 5fe12829..00000000 --- a/.claude/skills/ccw-loop/phases/actions/action-complete.md +++ /dev/null @@ -1,320 +0,0 @@ -# Action: Complete - -完成 CCW Loop 会话,生成总结报告。 - -## Purpose - -- 生成完成报告 -- 汇总所有阶段成果 -- 提供后续建议 -- 询问是否扩展为 Issue - -## Preconditions - -- [ ] state.initialized === true -- [ ] state.status === 'running' - -## Execution - -### Step 1: 汇总统计 - -```javascript -const getUtc8ISOString = () => new Date(Date.now() + 8 * 60 * 60 * 1000).toISOString() - -const sessionFolder = `.workflow/.loop/${state.session_id}` - -const stats = { - // 时间统计 - duration: Date.now() - new Date(state.created_at).getTime(), - iterations: state.iteration_count, - - // 开发统计 - develop: { - total_tasks: state.develop.total_count, - completed_tasks: state.develop.completed_count, - completion_rate: state.develop.total_count > 0 - ? (state.develop.completed_count / state.develop.total_count * 100).toFixed(1) - : 0 - }, - - // 调试统计 - debug: { - iterations: state.debug.iteration, - hypotheses_tested: state.debug.hypotheses.length, - root_cause_found: state.debug.confirmed_hypothesis !== null - }, - - // 验证统计 - validate: { - runs: state.validate.test_results.length, - passed: state.validate.passed, - coverage: state.validate.coverage, - failed_tests: state.validate.failed_tests.length - } -} - -console.log('\n生成完成报告...') -``` - -### Step 2: 生成总结报告 - -```javascript -const summaryReport = `# CCW Loop Session Summary - -**Session ID**: ${state.session_id} -**Task**: ${state.task_description} -**Started**: ${state.created_at} -**Completed**: ${getUtc8ISOString()} -**Duration**: ${formatDuration(stats.duration)} - ---- - -## Executive Summary - -${state.validate.passed - ? '✅ **任务成功完成** - 所有测试通过,验证成功' - : state.develop.completed_count === state.develop.total_count - ? '⚠️ **开发完成,验证未通过** - 需要进一步调试' - : '⏸️ **任务部分完成** - 仍有待处理项'} - ---- - -## Development Phase - -| Metric | Value | -|--------|-------| -| Total Tasks | ${stats.develop.total_tasks} | -| Completed | ${stats.develop.completed_tasks} | -| Completion Rate | ${stats.develop.completion_rate}% | - -### Completed Tasks - -${state.develop.tasks.filter(t => t.status === 'completed').map(t => ` -- ✅ ${t.description} - - Files: ${t.files_changed?.join(', ') || 'N/A'} - - Completed: ${t.completed_at} -`).join('\n')} - -### Pending Tasks - -${state.develop.tasks.filter(t => t.status !== 'completed').map(t => ` -- ⏳ ${t.description} -`).join('\n') || '_None_'} - ---- - -## Debug Phase - -| Metric | Value | -|--------|-------| -| Iterations | ${stats.debug.iterations} | -| Hypotheses Tested | ${stats.debug.hypotheses_tested} | -| Root Cause Found | ${stats.debug.root_cause_found ? 'Yes' : 'No'} | - -${stats.debug.root_cause_found ? ` -### Confirmed Root Cause - -**${state.debug.confirmed_hypothesis}**: ${state.debug.hypotheses.find(h => h.id === state.debug.confirmed_hypothesis)?.description || 'N/A'} -` : ''} - -### Hypothesis Summary - -${state.debug.hypotheses.map(h => ` -- **${h.id}**: ${h.status.toUpperCase()} - - ${h.description} -`).join('\n') || '_No hypotheses tested_'} - ---- - -## Validation Phase - -| Metric | Value | -|--------|-------| -| Test Runs | ${stats.validate.runs} | -| Status | ${stats.validate.passed ? 'PASSED' : 'FAILED'} | -| Coverage | ${stats.validate.coverage || 'N/A'}% | -| Failed Tests | ${stats.validate.failed_tests} | - -${stats.validate.failed_tests > 0 ? ` -### Failed Tests - -${state.validate.failed_tests.map(t => `- ❌ ${t}`).join('\n')} -` : ''} - ---- - -## Files Modified - -${listModifiedFiles(sessionFolder)} - ---- - -## Key Learnings - -${state.debug.iteration > 0 ? ` -### From Debugging - -${extractLearnings(state.debug.hypotheses)} -` : ''} - ---- - -## Recommendations - -${generateRecommendations(stats, state)} - ---- - -## Session Artifacts - -| File | Description | -|------|-------------| -| \`develop/progress.md\` | Development progress timeline | -| \`develop/tasks.json\` | Task list with status | -| \`debug/understanding.md\` | Debug exploration and learnings | -| \`debug/hypotheses.json\` | Hypothesis history | -| \`validate/validation.md\` | Validation report | -| \`validate/test-results.json\` | Test execution results | - ---- - -*Generated by CCW Loop at ${getUtc8ISOString()}* -` - -Write(`${sessionFolder}/summary.md`, summaryReport) -console.log(`\n报告已保存: ${sessionFolder}/summary.md`) -``` - -### Step 3: 询问后续扩展 - -```javascript -console.log('\n' + '═'.repeat(60)) -console.log(' 任务已完成') -console.log('═'.repeat(60)) - -const expansionResponse = await AskUserQuestion({ - questions: [{ - question: "是否将发现扩展为 Issue?", - header: "扩展选项", - multiSelect: true, - options: [ - { label: "测试 (Test)", description: "添加更多测试用例" }, - { label: "增强 (Enhance)", description: "功能增强建议" }, - { label: "重构 (Refactor)", description: "代码重构建议" }, - { label: "文档 (Doc)", description: "文档更新需求" }, - { label: "否,直接完成", description: "不创建 Issue" } - ] - }] -}) - -const selectedExpansions = expansionResponse["扩展选项"] - -if (selectedExpansions && !selectedExpansions.includes("否,直接完成")) { - for (const expansion of selectedExpansions) { - const dimension = expansion.split(' ')[0].toLowerCase() - const issueSummary = `${state.task_description} - ${dimension}` - - console.log(`\n创建 Issue: ${issueSummary}`) - - // 调用 /issue:new 创建 issue - await Bash({ - command: `/issue:new "${issueSummary}"`, - run_in_background: false - }) - } -} -``` - -### Step 4: 最终输出 - -```javascript -console.log(` -═══════════════════════════════════════════════════════════ - ✅ CCW Loop 会话完成 -═══════════════════════════════════════════════════════════ - - 会话 ID: ${state.session_id} - 用时: ${formatDuration(stats.duration)} - 迭代: ${stats.iterations} - - 开发: ${stats.develop.completed_tasks}/${stats.develop.total_tasks} 任务完成 - 调试: ${stats.debug.iterations} 次迭代 - 验证: ${stats.validate.passed ? '通过 ✅' : '未通过 ❌'} - - 报告: ${sessionFolder}/summary.md - -═══════════════════════════════════════════════════════════ -`) -``` - -## State Updates - -```javascript -return { - stateUpdates: { - status: 'completed', - completed_at: getUtc8ISOString(), - summary: stats - }, - continue: false, - message: `会话 ${state.session_id} 已完成` -} -``` - -## Helper Functions - -```javascript -function formatDuration(ms) { - const seconds = Math.floor(ms / 1000) - const minutes = Math.floor(seconds / 60) - const hours = Math.floor(minutes / 60) - - if (hours > 0) { - return `${hours}h ${minutes % 60}m` - } else if (minutes > 0) { - return `${minutes}m ${seconds % 60}s` - } else { - return `${seconds}s` - } -} - -function generateRecommendations(stats, state) { - const recommendations = [] - - if (stats.develop.completion_rate < 100) { - recommendations.push('- 完成剩余开发任务') - } - - if (!stats.validate.passed) { - recommendations.push('- 修复失败的测试') - } - - if (stats.validate.coverage && stats.validate.coverage < 80) { - recommendations.push(`- 提高测试覆盖率 (当前: ${stats.validate.coverage}%)`) - } - - if (stats.debug.iterations > 3 && !stats.debug.root_cause_found) { - recommendations.push('- 考虑代码重构以简化调试') - } - - if (recommendations.length === 0) { - recommendations.push('- 考虑代码审查') - recommendations.push('- 更新相关文档') - recommendations.push('- 准备部署') - } - - return recommendations.join('\n') -} -``` - -## Error Handling - -| Error Type | Recovery | -|------------|----------| -| 报告生成失败 | 显示基本统计,跳过文件写入 | -| Issue 创建失败 | 记录错误,继续完成 | - -## Next Actions - -- 无 (终止状态) -- 如需继续: 使用 `ccw-loop --resume {session-id}` 重新打开会话 diff --git a/.claude/skills/ccw-loop/phases/actions/action-debug-with-file.md b/.claude/skills/ccw-loop/phases/actions/action-debug-with-file.md deleted file mode 100644 index 0e7ae626..00000000 --- a/.claude/skills/ccw-loop/phases/actions/action-debug-with-file.md +++ /dev/null @@ -1,485 +0,0 @@ -# Action: Debug With File - -假设驱动调试,记录理解演变到 understanding.md,支持 Gemini 辅助分析和假设生成。 - -## Purpose - -执行假设驱动的调试流程,包括: -- 定位错误源 -- 生成可测试假设 -- 添加 NDJSON 日志 -- 分析日志证据 -- 纠正错误理解 -- 应用修复 - -## Preconditions - -- [ ] state.initialized === true -- [ ] state.status === 'running' - -## Session Setup - -```javascript -const getUtc8ISOString = () => new Date(Date.now() + 8 * 60 * 60 * 1000).toISOString() - -const sessionFolder = `.workflow/.loop/${state.session_id}` -const debugFolder = `${sessionFolder}/debug` -const understandingPath = `${debugFolder}/understanding.md` -const hypothesesPath = `${debugFolder}/hypotheses.json` -const debugLogPath = `${debugFolder}/debug.log` -``` - ---- - -## Mode Detection - -```javascript -// 自动检测模式 -const understandingExists = fs.existsSync(understandingPath) -const logHasContent = fs.existsSync(debugLogPath) && fs.statSync(debugLogPath).size > 0 - -const debugMode = logHasContent ? 'analyze' : (understandingExists ? 'continue' : 'explore') - -console.log(`Debug mode: ${debugMode}`) -``` - ---- - -## Explore Mode (首次调试) - -### Step 1.1: 定位错误源 - -```javascript -if (debugMode === 'explore') { - // 询问用户 bug 描述 - const bugInput = await AskUserQuestion({ - questions: [{ - question: "请描述遇到的 bug 或错误信息:", - header: "Bug 描述", - multiSelect: false, - options: [ - { label: "手动输入", description: "输入错误描述或堆栈" }, - { label: "从测试失败", description: "从验证阶段的失败测试中获取" } - ] - }] - }) - - const bugDescription = bugInput["Bug 描述"] - - // 提取关键词并搜索 - const searchResults = await Task({ - subagent_type: 'Explore', - run_in_background: false, - prompt: `Search codebase for error patterns related to: ${bugDescription}` - }) - - // 分析搜索结果,识别受影响的位置 - const affectedLocations = analyzeSearchResults(searchResults) -} -``` - -### Step 1.2: 记录初始理解 - -```javascript -// 创建 understanding.md -const initialUnderstanding = `# Understanding Document - -**Session ID**: ${state.session_id} -**Bug Description**: ${bugDescription} -**Started**: ${getUtc8ISOString()} - ---- - -## Exploration Timeline - -### Iteration 1 - Initial Exploration (${getUtc8ISOString()}) - -#### Current Understanding - -Based on bug description and initial code search: - -- Error pattern: ${errorPattern} -- Affected areas: ${affectedLocations.map(l => l.file).join(', ')} -- Initial hypothesis: ${initialThoughts} - -#### Evidence from Code Search - -${searchResults.map(r => ` -**Keyword: "${r.keyword}"** -- Found in: ${r.files.join(', ')} -- Key findings: ${r.insights} -`).join('\n')} - -#### Next Steps - -- Generate testable hypotheses -- Add instrumentation -- Await reproduction - ---- - -## Current Consolidated Understanding - -${initialConsolidatedUnderstanding} -` - -Write(understandingPath, initialUnderstanding) -``` - -### Step 1.3: Gemini 辅助假设生成 - -```bash -ccw cli -p " -PURPOSE: Generate debugging hypotheses for: ${bugDescription} -Success criteria: Testable hypotheses with clear evidence criteria - -TASK: -• Analyze error pattern and code search results -• Identify 3-5 most likely root causes -• For each hypothesis, specify: - - What might be wrong - - What evidence would confirm/reject it - - Where to add instrumentation -• Rank by likelihood - -MODE: analysis - -CONTEXT: @${understandingPath} | Search results in understanding.md - -EXPECTED: -- Structured hypothesis list (JSON format) -- Each hypothesis with: id, description, testable_condition, logging_point, evidence_criteria -- Likelihood ranking (1=most likely) - -CONSTRAINTS: Focus on testable conditions -" --tool gemini --mode analysis --rule analysis-diagnose-bug-root-cause -``` - -### Step 1.4: 保存假设 - -```javascript -const hypotheses = { - iteration: 1, - timestamp: getUtc8ISOString(), - bug_description: bugDescription, - hypotheses: [ - { - id: "H1", - description: "...", - testable_condition: "...", - logging_point: "file.ts:func:42", - evidence_criteria: { - confirm: "...", - reject: "..." - }, - likelihood: 1, - status: "pending" - } - // ... - ], - gemini_insights: "...", - corrected_assumptions: [] -} - -Write(hypothesesPath, JSON.stringify(hypotheses, null, 2)) -``` - -### Step 1.5: 添加 NDJSON 日志 - -```javascript -// 为每个假设添加日志点 -for (const hypothesis of hypotheses.hypotheses) { - const [file, func, line] = hypothesis.logging_point.split(':') - - const logStatement = `console.log(JSON.stringify({ - hid: "${hypothesis.id}", - ts: Date.now(), - func: "${func}", - data: { /* 相关数据 */ } - }))` - - // 使用 Edit 工具添加日志 - // ... -} -``` - ---- - -## Analyze Mode (有日志后) - -### Step 2.1: 解析调试日志 - -```javascript -if (debugMode === 'analyze') { - // 读取 NDJSON 日志 - const logContent = Read(debugLogPath) - const entries = logContent.split('\n') - .filter(l => l.trim()) - .map(l => JSON.parse(l)) - - // 按假设分组 - const byHypothesis = groupBy(entries, 'hid') -} -``` - -### Step 2.2: Gemini 辅助证据分析 - -```bash -ccw cli -p " -PURPOSE: Analyze debug log evidence to validate/correct hypotheses for: ${bugDescription} -Success criteria: Clear verdict per hypothesis + corrected understanding - -TASK: -• Parse log entries by hypothesis -• Evaluate evidence against expected criteria -• Determine verdict: confirmed | rejected | inconclusive -• Identify incorrect assumptions from previous understanding -• Suggest corrections to understanding - -MODE: analysis - -CONTEXT: -@${debugLogPath} -@${understandingPath} -@${hypothesesPath} - -EXPECTED: -- Per-hypothesis verdict with reasoning -- Evidence summary -- List of incorrect assumptions with corrections -- Updated consolidated understanding -- Root cause if confirmed, or next investigation steps - -CONSTRAINTS: Evidence-based reasoning only, no speculation -" --tool gemini --mode analysis --rule analysis-diagnose-bug-root-cause -``` - -### Step 2.3: 更新理解文档 - -```javascript -// 追加新迭代到 understanding.md -const iteration = state.debug.iteration + 1 - -const analysisEntry = ` -### Iteration ${iteration} - Evidence Analysis (${getUtc8ISOString()}) - -#### Log Analysis Results - -${results.map(r => ` -**${r.id}**: ${r.verdict.toUpperCase()} -- Evidence: ${JSON.stringify(r.evidence)} -- Reasoning: ${r.reason} -`).join('\n')} - -#### Corrected Understanding - -Previous misunderstandings identified and corrected: - -${corrections.map(c => ` -- ~~${c.wrong}~~ → ${c.corrected} - - Why wrong: ${c.reason} - - Evidence: ${c.evidence} -`).join('\n')} - -#### New Insights - -${newInsights.join('\n- ')} - -#### Gemini Analysis - -${geminiAnalysis} - -${confirmedHypothesis ? ` -#### Root Cause Identified - -**${confirmedHypothesis.id}**: ${confirmedHypothesis.description} - -Evidence supporting this conclusion: -${confirmedHypothesis.supportingEvidence} -` : ` -#### Next Steps - -${nextSteps} -`} - ---- - -## Current Consolidated Understanding (Updated) - -### What We Know - -- ${validUnderstanding1} -- ${validUnderstanding2} - -### What Was Disproven - -- ~~${wrongAssumption}~~ (Evidence: ${disproofEvidence}) - -### Current Investigation Focus - -${currentFocus} - -### Remaining Questions - -- ${openQuestion1} -- ${openQuestion2} -` - -const existingContent = Read(understandingPath) -Write(understandingPath, existingContent + analysisEntry) -``` - -### Step 2.4: 更新假设状态 - -```javascript -const hypothesesData = JSON.parse(Read(hypothesesPath)) - -// 更新假设状态 -hypothesesData.hypotheses = hypothesesData.hypotheses.map(h => ({ - ...h, - status: results.find(r => r.id === h.id)?.verdict || h.status, - evidence: results.find(r => r.id === h.id)?.evidence || h.evidence, - verdict_reason: results.find(r => r.id === h.id)?.reason || h.verdict_reason -})) - -hypothesesData.iteration++ -hypothesesData.timestamp = getUtc8ISOString() - -Write(hypothesesPath, JSON.stringify(hypothesesData, null, 2)) -``` - ---- - -## Fix & Verification - -### Step 3.1: 应用修复 - -```javascript -if (confirmedHypothesis) { - console.log(`\n根因确认: ${confirmedHypothesis.description}`) - console.log('准备应用修复...') - - // 使用 Gemini 生成修复代码 - const fixPrompt = ` -PURPOSE: Fix the identified root cause -Root Cause: ${confirmedHypothesis.description} -Evidence: ${confirmedHypothesis.supportingEvidence} - -TASK: -• Generate fix code -• Ensure backward compatibility -• Add tests if needed - -MODE: write - -CONTEXT: @${confirmedHypothesis.logging_point.split(':')[0]} - -EXPECTED: Fixed code + verification steps -` - - await Bash({ - command: `ccw cli -p "${fixPrompt}" --tool gemini --mode write --rule development-debug-runtime-issues`, - run_in_background: false - }) -} -``` - -### Step 3.2: 记录解决方案 - -```javascript -const resolutionEntry = ` -### Resolution (${getUtc8ISOString()}) - -#### Fix Applied - -- Modified files: ${modifiedFiles.join(', ')} -- Fix description: ${fixDescription} -- Root cause addressed: ${rootCause} - -#### Verification Results - -${verificationResults} - -#### Lessons Learned - -1. ${lesson1} -2. ${lesson2} - -#### Key Insights for Future - -- ${insight1} -- ${insight2} -` - -const existingContent = Read(understandingPath) -Write(understandingPath, existingContent + resolutionEntry) -``` - -### Step 3.3: 清理日志 - -```javascript -// 移除调试日志 -// (可选,根据用户选择) -``` - ---- - -## State Updates - -```javascript -return { - stateUpdates: { - debug: { - current_bug: bugDescription, - hypotheses: hypothesesData.hypotheses, - confirmed_hypothesis: confirmedHypothesis?.id || null, - iteration: hypothesesData.iteration, - last_analysis_at: getUtc8ISOString(), - understanding_updated: true - }, - last_action: 'action-debug-with-file' - }, - continue: true, - message: confirmedHypothesis - ? `根因确认: ${confirmedHypothesis.description}\n修复已应用,请验证` - : `分析完成,需要更多证据\n请复现 bug 后再次执行` -} -``` - -## Error Handling - -| Error Type | Recovery | -|------------|----------| -| 空 debug.log | 提示用户复现 bug | -| 所有假设被否定 | 使用 Gemini 生成新假设 | -| 修复无效 | 记录失败尝试,迭代 | -| >5 迭代 | 建议升级到 /workflow:lite-fix | -| Gemini 不可用 | 回退到手动分析 | - -## Understanding Document Template - -参考 [templates/understanding-template.md](../../templates/understanding-template.md) - -## CLI Integration - -### 假设生成 -```bash -ccw cli -p "PURPOSE: Generate debugging hypotheses..." --tool gemini --mode analysis --rule analysis-diagnose-bug-root-cause -``` - -### 证据分析 -```bash -ccw cli -p "PURPOSE: Analyze debug log evidence..." --tool gemini --mode analysis --rule analysis-diagnose-bug-root-cause -``` - -### 生成修复 -```bash -ccw cli -p "PURPOSE: Fix the identified root cause..." --tool gemini --mode write --rule development-debug-runtime-issues -``` - -## Next Actions (Hints) - -- 根因确认: `action-validate-with-file` (验证修复) -- 需要更多证据: 等待用户复现,再次执行此动作 -- 所有假设否定: 重新执行此动作生成新假设 -- 用户选择: `action-menu` (返回菜单) diff --git a/.claude/skills/ccw-loop/phases/actions/action-develop-with-file.md b/.claude/skills/ccw-loop/phases/actions/action-develop-with-file.md deleted file mode 100644 index 0846a0fb..00000000 --- a/.claude/skills/ccw-loop/phases/actions/action-develop-with-file.md +++ /dev/null @@ -1,365 +0,0 @@ -# Action: Develop With File - -增量开发任务执行,记录进度到 progress.md,支持 Gemini 辅助实现。 - -## Purpose - -执行开发任务并记录进度,包括: -- 分析任务需求 -- 使用 Gemini/CLI 实现代码 -- 记录代码变更 -- 更新进度文档 - -## Preconditions - -- [ ] state.status === 'running' -- [ ] state.skill_state !== null -- [ ] state.skill_state.develop.tasks.some(t => t.status === 'pending') - -## Session Setup (Unified Location) - -```javascript -const getUtc8ISOString = () => new Date(Date.now() + 8 * 60 * 60 * 1000).toISOString() - -// 统一位置: .loop/{loopId} -const loopId = state.loop_id -const loopFile = `.loop/${loopId}.json` -const progressDir = `.loop/${loopId}.progress` -const progressPath = `${progressDir}/develop.md` -const changesLogPath = `${progressDir}/changes.log` -``` - ---- - -## Execution - -### Step 0: Check Control Signals (CRITICAL) - -```javascript -/** - * CRITICAL: 每个 Action 必须在开始时检查控制信号 - * 如果 API 设置了 paused/stopped,Skill 应立即退出 - */ -function checkControlSignals(loopId) { - const state = JSON.parse(Read(`.loop/${loopId}.json`)) - - switch (state.status) { - case 'paused': - console.log('⏸️ Loop paused by API. Exiting action.') - return { continue: false, reason: 'paused' } - - case 'failed': - console.log('⏹️ Loop stopped by API. Exiting action.') - return { continue: false, reason: 'stopped' } - - case 'running': - return { continue: true, reason: 'running' } - - default: - return { continue: false, reason: 'unknown_status' } - } -} - -// Execute check -const control = checkControlSignals(loopId) -if (!control.continue) { - return { - skillStateUpdates: { current_action: null }, - continue: false, - message: `Action terminated: ${control.reason}` - } -} -``` - -### Step 1: 加载任务列表 - -```javascript -// 读取任务列表 (从 skill_state) -let tasks = state.skill_state?.develop?.tasks || [] - -// 如果任务列表为空,询问用户创建 -if (tasks.length === 0) { - // 使用 Gemini 分析任务描述,生成任务列表 - const analysisPrompt = ` -PURPOSE: 分析开发任务并分解为可执行步骤 -Success: 生成 3-7 个具体、可验证的子任务 - -TASK: -• 分析任务描述: ${state.task_description} -• 识别关键功能点 -• 分解为独立子任务 -• 为每个子任务指定工具和模式 - -MODE: analysis - -CONTEXT: @package.json @src/**/*.ts | Memory: 项目结构 - -EXPECTED: -JSON 格式: -{ - "tasks": [ - { - "id": "task-001", - "description": "任务描述", - "tool": "gemini", - "mode": "write", - "files": ["src/xxx.ts"] - } - ] -} -` - - const result = await Task({ - subagent_type: 'cli-execution-agent', - run_in_background: false, - prompt: `Execute Gemini CLI with prompt: ${analysisPrompt}` - }) - - tasks = JSON.parse(result).tasks -} - -// 找到第一个待处理任务 -const currentTask = tasks.find(t => t.status === 'pending') - -if (!currentTask) { - return { - skillStateUpdates: { - develop: { ...state.skill_state.develop, current_task: null } - }, - continue: true, - message: '所有开发任务已完成' - } -} -``` - -### Step 2: 执行开发任务 - -```javascript -console.log(`\n执行任务: ${currentTask.description}`) - -// 更新任务状态 -currentTask.status = 'in_progress' - -// 使用 Gemini 实现 -const implementPrompt = ` -PURPOSE: 实现开发任务 -Task: ${currentTask.description} -Success criteria: 代码实现完成,测试通过 - -TASK: -• 分析现有代码结构 -• 实现功能代码 -• 添加必要的类型定义 -• 确保代码风格一致 - -MODE: write - -CONTEXT: @${currentTask.files?.join(' @') || 'src/**/*.ts'} - -EXPECTED: -- 完整的代码实现 -- 代码变更列表 -- 简要实现说明 - -CONSTRAINTS: 遵循现有代码风格 | 不破坏现有功能 -` - -const implementResult = await Bash({ - command: `ccw cli -p "${implementPrompt}" --tool gemini --mode write --rule development-implement-feature`, - run_in_background: false -}) - -// 记录代码变更 -const timestamp = getUtc8ISOString() -const changeEntry = { - timestamp, - task_id: currentTask.id, - description: currentTask.description, - files_changed: currentTask.files || [], - result: 'success' -} - -// 追加到 changes.log (NDJSON 格式) -const changesContent = Read(changesLogPath) || '' -Write(changesLogPath, changesContent + JSON.stringify(changeEntry) + '\n') -``` - -### Step 3: 更新进度文档 - -```javascript -const timestamp = getUtc8ISOString() -const iteration = state.develop.completed_count + 1 - -// 读取现有进度文档 -let progressContent = Read(progressPath) || '' - -// 如果是新文档,添加头部 -if (!progressContent) { - progressContent = `# Development Progress - -**Session ID**: ${state.session_id} -**Task**: ${state.task_description} -**Started**: ${timestamp} - ---- - -## Progress Timeline - -` -} - -// 追加本次进度 -const progressEntry = ` -### Iteration ${iteration} - ${currentTask.description} (${timestamp}) - -#### Task Details - -- **ID**: ${currentTask.id} -- **Tool**: ${currentTask.tool} -- **Mode**: ${currentTask.mode} - -#### Implementation Summary - -${implementResult.summary || '实现完成'} - -#### Files Changed - -${currentTask.files?.map(f => `- \`${f}\``).join('\n') || '- No files specified'} - -#### Status: COMPLETED - ---- - -` - -Write(progressPath, progressContent + progressEntry) - -// 更新任务状态 -currentTask.status = 'completed' -currentTask.completed_at = timestamp -``` - -### Step 4: 更新任务列表文件 - -```javascript -// 更新 tasks.json -const updatedTasks = tasks.map(t => - t.id === currentTask.id ? currentTask : t -) - -Write(tasksPath, JSON.stringify(updatedTasks, null, 2)) -``` - -## State Updates - -```javascript -return { - stateUpdates: { - develop: { - tasks: updatedTasks, - current_task_id: null, - completed_count: state.develop.completed_count + 1, - total_count: updatedTasks.length, - last_progress_at: getUtc8ISOString() - }, - last_action: 'action-develop-with-file' - }, - continue: true, - message: `任务完成: ${currentTask.description}\n进度: ${state.develop.completed_count + 1}/${updatedTasks.length}` -} -``` - -## Error Handling - -| Error Type | Recovery | -|------------|----------| -| Gemini CLI 失败 | 提示用户手动实现,记录到 progress.md | -| 文件写入失败 | 重试一次,失败则记录错误 | -| 任务解析失败 | 询问用户手动输入任务 | - -## Progress Document Template - -```markdown -# Development Progress - -**Session ID**: LOOP-xxx-2026-01-22 -**Task**: 实现用户认证功能 -**Started**: 2026-01-22T10:00:00+08:00 - ---- - -## Progress Timeline - -### Iteration 1 - 分析登录组件 (2026-01-22T10:05:00+08:00) - -#### Task Details - -- **ID**: task-001 -- **Tool**: gemini -- **Mode**: analysis - -#### Implementation Summary - -分析了现有登录组件结构,识别了需要修改的文件和依赖关系。 - -#### Files Changed - -- `src/components/Login.tsx` -- `src/hooks/useAuth.ts` - -#### Status: COMPLETED - ---- - -### Iteration 2 - 实现登录 API (2026-01-22T10:15:00+08:00) - -... - ---- - -## Current Statistics - -| Metric | Value | -|--------|-------| -| Total Tasks | 5 | -| Completed | 2 | -| In Progress | 1 | -| Pending | 2 | -| Progress | 40% | - ---- - -## Next Steps - -- [ ] 完成剩余任务 -- [ ] 运行测试 -- [ ] 代码审查 -``` - -## CLI Integration - -### 任务分析 -```bash -ccw cli -p "PURPOSE: 分解开发任务为子任务 -TASK: • 分析任务描述 • 识别功能点 • 生成任务列表 -MODE: analysis -CONTEXT: @package.json @src/**/* -EXPECTED: JSON 任务列表 -" --tool gemini --mode analysis --rule planning-breakdown-task-steps -``` - -### 代码实现 -```bash -ccw cli -p "PURPOSE: 实现功能代码 -TASK: • 分析需求 • 编写代码 • 添加类型 -MODE: write -CONTEXT: @src/xxx.ts -EXPECTED: 完整实现 -" --tool gemini --mode write --rule development-implement-feature -``` - -## Next Actions (Hints) - -- 所有任务完成: `action-debug-with-file` (开始调试) -- 任务失败: `action-develop-with-file` (重试或下一个任务) -- 用户选择: `action-menu` (返回菜单) diff --git a/.claude/skills/ccw-loop/phases/actions/action-init.md b/.claude/skills/ccw-loop/phases/actions/action-init.md deleted file mode 100644 index ac847942..00000000 --- a/.claude/skills/ccw-loop/phases/actions/action-init.md +++ /dev/null @@ -1,200 +0,0 @@ -# Action: Initialize - -初始化 CCW Loop 会话,创建目录结构和初始状态。 - -## Purpose - -- 创建会话目录结构 -- 初始化状态文件 -- 分析任务描述生成初始任务列表 -- 准备执行环境 - -## Preconditions - -- [ ] state.status === 'pending' -- [ ] state.initialized === false - -## Execution - -### Step 1: 创建目录结构 - -```javascript -const getUtc8ISOString = () => new Date(Date.now() + 8 * 60 * 60 * 1000).toISOString() - -const taskSlug = state.task_description.toLowerCase().replace(/[^a-z0-9]+/g, '-').substring(0, 30) -const dateStr = getUtc8ISOString().substring(0, 10) -const sessionId = `LOOP-${taskSlug}-${dateStr}` -const sessionFolder = `.workflow/.loop/${sessionId}` - -Bash(`mkdir -p "${sessionFolder}/develop"`) -Bash(`mkdir -p "${sessionFolder}/debug"`) -Bash(`mkdir -p "${sessionFolder}/validate"`) - -console.log(`Session created: ${sessionId}`) -console.log(`Location: ${sessionFolder}`) -``` - -### Step 2: 创建元数据文件 - -```javascript -const meta = { - session_id: sessionId, - task_description: state.task_description, - created_at: getUtc8ISOString(), - mode: state.mode || 'interactive' -} - -Write(`${sessionFolder}/meta.json`, JSON.stringify(meta, null, 2)) -``` - -### Step 3: 分析任务生成开发任务列表 - -```javascript -// 使用 Gemini 分析任务描述 -console.log('\n分析任务描述...') - -const analysisPrompt = ` -PURPOSE: 分析开发任务并分解为可执行步骤 -Success: 生成 3-7 个具体、可验证的子任务 - -TASK: -• 分析任务描述: ${state.task_description} -• 识别关键功能点 -• 分解为独立子任务 -• 为每个子任务指定工具和模式 - -MODE: analysis - -CONTEXT: @package.json @src/**/*.ts (如存在) - -EXPECTED: -JSON 格式: -{ - "tasks": [ - { - "id": "task-001", - "description": "任务描述", - "tool": "gemini", - "mode": "write", - "priority": 1 - } - ], - "estimated_complexity": "low|medium|high", - "key_files": ["file1.ts", "file2.ts"] -} - -CONSTRAINTS: 生成实际可执行的任务 -` - -const result = await Bash({ - command: `ccw cli -p "${analysisPrompt}" --tool gemini --mode analysis --rule planning-breakdown-task-steps`, - run_in_background: false -}) - -const analysis = JSON.parse(result.stdout) -const tasks = analysis.tasks.map((t, i) => ({ - ...t, - id: t.id || `task-${String(i + 1).padStart(3, '0')}`, - status: 'pending', - created_at: getUtc8ISOString(), - completed_at: null, - files_changed: [] -})) - -// 保存任务列表 -Write(`${sessionFolder}/develop/tasks.json`, JSON.stringify(tasks, null, 2)) -``` - -### Step 4: 初始化进度文档 - -```javascript -const progressInitial = `# Development Progress - -**Session ID**: ${sessionId} -**Task**: ${state.task_description} -**Started**: ${getUtc8ISOString()} -**Estimated Complexity**: ${analysis.estimated_complexity} - ---- - -## Task List - -${tasks.map((t, i) => `${i + 1}. [ ] ${t.description}`).join('\n')} - -## Key Files - -${analysis.key_files?.map(f => `- \`${f}\``).join('\n') || '- To be determined'} - ---- - -## Progress Timeline - -` - -Write(`${sessionFolder}/develop/progress.md`, progressInitial) -``` - -### Step 5: 显示初始化结果 - -```javascript -console.log(`\n✅ 会话初始化完成`) -console.log(`\n任务列表 (${tasks.length} 项):`) -tasks.forEach((t, i) => { - console.log(` ${i + 1}. ${t.description} [${t.tool}/${t.mode}]`) -}) -console.log(`\n预估复杂度: ${analysis.estimated_complexity}`) -console.log(`\n执行 'develop' 开始开发,或 'menu' 查看更多选项`) -``` - -## State Updates - -```javascript -return { - stateUpdates: { - session_id: sessionId, - status: 'running', - initialized: true, - develop: { - tasks: tasks, - current_task_id: null, - completed_count: 0, - total_count: tasks.length, - last_progress_at: null - }, - debug: { - current_bug: null, - hypotheses: [], - confirmed_hypothesis: null, - iteration: 0, - last_analysis_at: null, - understanding_updated: false - }, - validate: { - test_results: [], - coverage: null, - passed: false, - failed_tests: [], - last_run_at: null - }, - context: { - estimated_complexity: analysis.estimated_complexity, - key_files: analysis.key_files - } - }, - continue: true, - message: `会话 ${sessionId} 已初始化\n${tasks.length} 个开发任务待执行` -} -``` - -## Error Handling - -| Error Type | Recovery | -|------------|----------| -| 目录创建失败 | 检查权限,重试 | -| Gemini 分析失败 | 提示用户手动输入任务 | -| 任务解析失败 | 使用默认任务列表 | - -## Next Actions - -- 成功: `action-menu` (显示操作菜单) 或 `action-develop-with-file` (直接开始开发) -- 失败: 报错退出 diff --git a/.claude/skills/ccw-loop/phases/actions/action-menu.md b/.claude/skills/ccw-loop/phases/actions/action-menu.md deleted file mode 100644 index 40e01dad..00000000 --- a/.claude/skills/ccw-loop/phases/actions/action-menu.md +++ /dev/null @@ -1,192 +0,0 @@ -# Action: Menu - -显示交互式操作菜单,让用户选择下一步操作。 - -## Purpose - -- 显示当前状态摘要 -- 提供操作选项 -- 接收用户选择 -- 返回下一个动作 - -## Preconditions - -- [ ] state.initialized === true -- [ ] state.status === 'running' - -## Execution - -### Step 1: 生成状态摘要 - -```javascript -const getUtc8ISOString = () => new Date(Date.now() + 8 * 60 * 60 * 1000).toISOString() - -// 开发进度 -const developProgress = state.develop.total_count > 0 - ? `${state.develop.completed_count}/${state.develop.total_count} (${(state.develop.completed_count / state.develop.total_count * 100).toFixed(0)}%)` - : '未开始' - -// 调试状态 -const debugStatus = state.debug.confirmed_hypothesis - ? `✅ 已确认根因` - : state.debug.iteration > 0 - ? `🔍 迭代 ${state.debug.iteration}` - : '未开始' - -// 验证状态 -const validateStatus = state.validate.passed - ? `✅ 通过` - : state.validate.test_results.length > 0 - ? `❌ ${state.validate.failed_tests.length} 个失败` - : '未运行' - -const statusSummary = ` -═══════════════════════════════════════════════════════════ - CCW Loop - ${state.session_id} -═══════════════════════════════════════════════════════════ - - 任务: ${state.task_description} - 迭代: ${state.iteration_count} - - ┌─────────────────────────────────────────────────────┐ - │ 开发 (Develop) │ ${developProgress.padEnd(20)} │ - │ 调试 (Debug) │ ${debugStatus.padEnd(20)} │ - │ 验证 (Validate) │ ${validateStatus.padEnd(20)} │ - └─────────────────────────────────────────────────────┘ - -═══════════════════════════════════════════════════════════ -` - -console.log(statusSummary) -``` - -### Step 2: 显示操作选项 - -```javascript -const options = [ - { - label: "📝 继续开发 (Develop)", - description: state.develop.completed_count < state.develop.total_count - ? `执行下一个开发任务` - : "所有任务已完成,可添加新任务", - action: "action-develop-with-file" - }, - { - label: "🔍 开始调试 (Debug)", - description: state.debug.iteration > 0 - ? "继续假设驱动调试" - : "开始新的调试会话", - action: "action-debug-with-file" - }, - { - label: "✅ 运行验证 (Validate)", - description: "运行测试并检查覆盖率", - action: "action-validate-with-file" - }, - { - label: "📊 查看详情 (Status)", - description: "查看详细进度和文件", - action: "action-status" - }, - { - label: "🏁 完成循环 (Complete)", - description: "结束当前循环", - action: "action-complete" - }, - { - label: "🚪 退出 (Exit)", - description: "保存状态并退出", - action: "exit" - } -] - -const response = await AskUserQuestion({ - questions: [{ - question: "选择下一步操作:", - header: "操作", - multiSelect: false, - options: options.map(o => ({ - label: o.label, - description: o.description - })) - }] -}) - -const selectedLabel = response["操作"] -const selectedOption = options.find(o => o.label === selectedLabel) -const nextAction = selectedOption?.action || 'action-menu' -``` - -### Step 3: 处理特殊选项 - -```javascript -if (nextAction === 'exit') { - console.log('\n保存状态并退出...') - return { - stateUpdates: { - status: 'user_exit' - }, - continue: false, - message: '会话已保存,使用 --resume 可继续' - } -} - -if (nextAction === 'action-status') { - // 显示详细状态 - const sessionFolder = `.workflow/.loop/${state.session_id}` - - console.log('\n=== 开发进度 ===') - const progress = Read(`${sessionFolder}/develop/progress.md`) - console.log(progress?.substring(0, 500) + '...') - - console.log('\n=== 调试状态 ===') - if (state.debug.hypotheses.length > 0) { - state.debug.hypotheses.forEach(h => { - console.log(` ${h.id}: ${h.status} - ${h.description.substring(0, 50)}...`) - }) - } else { - console.log(' 尚未开始调试') - } - - console.log('\n=== 验证结果 ===') - if (state.validate.test_results.length > 0) { - const latest = state.validate.test_results[state.validate.test_results.length - 1] - console.log(` 最近运行: ${latest.timestamp}`) - console.log(` 通过率: ${latest.summary.pass_rate}%`) - } else { - console.log(' 尚未运行验证') - } - - // 返回菜单 - return { - stateUpdates: {}, - continue: true, - nextAction: 'action-menu', - message: '' - } -} -``` - -## State Updates - -```javascript -return { - stateUpdates: { - // 不更新状态,仅返回下一个动作 - }, - continue: true, - nextAction: nextAction, - message: `执行: ${selectedOption?.label || nextAction}` -} -``` - -## Error Handling - -| Error Type | Recovery | -|------------|----------| -| 用户取消 | 返回菜单 | -| 无效选择 | 重新显示菜单 | - -## Next Actions - -根据用户选择动态决定下一个动作。 diff --git a/.claude/skills/ccw-loop/phases/actions/action-validate-with-file.md b/.claude/skills/ccw-loop/phases/actions/action-validate-with-file.md deleted file mode 100644 index 0705b8bb..00000000 --- a/.claude/skills/ccw-loop/phases/actions/action-validate-with-file.md +++ /dev/null @@ -1,307 +0,0 @@ -# Action: Validate With File - -运行测试并验证实现,记录结果到 validation.md,支持 Gemini 辅助分析测试覆盖率和质量。 - -## Purpose - -执行测试验证流程,包括: -- 运行单元测试 -- 运行集成测试 -- 检查代码覆盖率 -- 生成验证报告 -- 分析失败原因 - -## Preconditions - -- [ ] state.initialized === true -- [ ] state.status === 'running' -- [ ] state.develop.completed_count > 0 || state.debug.confirmed_hypothesis !== null - -## Session Setup - -```javascript -const getUtc8ISOString = () => new Date(Date.now() + 8 * 60 * 60 * 1000).toISOString() - -const sessionFolder = `.workflow/.loop/${state.session_id}` -const validateFolder = `${sessionFolder}/validate` -const validationPath = `${validateFolder}/validation.md` -const testResultsPath = `${validateFolder}/test-results.json` -const coveragePath = `${validateFolder}/coverage.json` -``` - ---- - -## Execution - -### Step 1: 运行测试 - -```javascript -console.log('\n运行测试...') - -// 检测测试框架 -const packageJson = JSON.parse(Read('package.json')) -const testScript = packageJson.scripts?.test || 'npm test' - -// 运行测试并捕获输出 -const testResult = await Bash({ - command: testScript, - timeout: 300000 // 5分钟 -}) - -// 解析测试输出 -const testResults = parseTestOutput(testResult.stdout) -``` - -### Step 2: 检查覆盖率 - -```javascript -// 运行覆盖率检查 -let coverageData = null - -if (packageJson.scripts?.['test:coverage']) { - const coverageResult = await Bash({ - command: 'npm run test:coverage', - timeout: 300000 - }) - - // 解析覆盖率报告 - coverageData = parseCoverageReport(coverageResult.stdout) - - Write(coveragePath, JSON.stringify(coverageData, null, 2)) -} -``` - -### Step 3: Gemini 辅助分析 - -```bash -ccw cli -p " -PURPOSE: Analyze test results and coverage -Success criteria: Identify quality issues and suggest improvements - -TASK: -• Analyze test execution results -• Review code coverage metrics -• Identify missing test cases -• Suggest quality improvements -• Verify requirements coverage - -MODE: analysis - -CONTEXT: -@${testResultsPath} -@${coveragePath} -@${sessionFolder}/develop/progress.md - -EXPECTED: -- Quality assessment report -- Failed tests analysis -- Coverage gaps identification -- Improvement recommendations -- Pass/Fail decision with rationale - -CONSTRAINTS: Evidence-based quality assessment -" --tool gemini --mode analysis --rule analysis-review-code-quality -``` - -### Step 4: 生成验证报告 - -```javascript -const timestamp = getUtc8ISOString() -const iteration = (state.validate.test_results?.length || 0) + 1 - -const validationReport = `# Validation Report - -**Session ID**: ${state.session_id} -**Task**: ${state.task_description} -**Validated**: ${timestamp} - ---- - -## Iteration ${iteration} - Validation Run - -### Test Execution Summary - -| Metric | Value | -|--------|-------| -| Total Tests | ${testResults.total} | -| Passed | ${testResults.passed} | -| Failed | ${testResults.failed} | -| Skipped | ${testResults.skipped} | -| Duration | ${testResults.duration_ms}ms | -| **Pass Rate** | **${(testResults.passed / testResults.total * 100).toFixed(1)}%** | - -### Coverage Report - -${coverageData ? ` -| File | Statements | Branches | Functions | Lines | -|------|------------|----------|-----------|-------| -${coverageData.files.map(f => `| ${f.path} | ${f.statements}% | ${f.branches}% | ${f.functions}% | ${f.lines}% |`).join('\n')} - -**Overall Coverage**: ${coverageData.overall.statements}% -` : '_No coverage data available_'} - -### Failed Tests - -${testResults.failed > 0 ? ` -${testResults.failures.map(f => ` -#### ${f.test_name} - -- **Suite**: ${f.suite} -- **Error**: ${f.error_message} -- **Stack**: -\`\`\` -${f.stack_trace} -\`\`\` -`).join('\n')} -` : '_All tests passed_'} - -### Gemini Quality Analysis - -${geminiAnalysis} - -### Recommendations - -${recommendations.map(r => `- ${r}`).join('\n')} - ---- - -## Validation Decision - -**Result**: ${testResults.passed === testResults.total ? '✅ PASS' : '❌ FAIL'} - -**Rationale**: ${validationDecision} - -${testResults.passed !== testResults.total ? ` -### Next Actions - -1. Review failed tests -2. Debug failures using action-debug-with-file -3. Fix issues and re-run validation -` : ` -### Next Actions - -1. Consider code review -2. Prepare for deployment -3. Update documentation -`} -` - -// 写入验证报告 -Write(validationPath, validationReport) -``` - -### Step 5: 保存测试结果 - -```javascript -const testResultsData = { - iteration, - timestamp, - summary: { - total: testResults.total, - passed: testResults.passed, - failed: testResults.failed, - skipped: testResults.skipped, - pass_rate: (testResults.passed / testResults.total * 100).toFixed(1), - duration_ms: testResults.duration_ms - }, - tests: testResults.tests, - failures: testResults.failures, - coverage: coverageData?.overall || null -} - -Write(testResultsPath, JSON.stringify(testResultsData, null, 2)) -``` - ---- - -## State Updates - -```javascript -const validationPassed = testResults.failed === 0 && testResults.passed > 0 - -return { - stateUpdates: { - validate: { - test_results: [...(state.validate.test_results || []), testResultsData], - coverage: coverageData?.overall.statements || null, - passed: validationPassed, - failed_tests: testResults.failures.map(f => f.test_name), - last_run_at: getUtc8ISOString() - }, - last_action: 'action-validate-with-file' - }, - continue: true, - message: validationPassed - ? `验证通过 ✅\n测试: ${testResults.passed}/${testResults.total}\n覆盖率: ${coverageData?.overall.statements || 'N/A'}%` - : `验证失败 ❌\n失败: ${testResults.failed}/${testResults.total}\n建议进入调试模式` -} -``` - -## Test Output Parsers - -### Jest/Vitest Parser - -```javascript -function parseJestOutput(stdout) { - const testPattern = /Tests:\s+(\d+) passed.*?(\d+) failed.*?(\d+) total/ - const match = stdout.match(testPattern) - - return { - total: parseInt(match[3]), - passed: parseInt(match[1]), - failed: parseInt(match[2]), - // ... parse individual test results - } -} -``` - -### Pytest Parser - -```javascript -function parsePytestOutput(stdout) { - const summaryPattern = /(\d+) passed.*?(\d+) failed.*?(\d+) error/ - // ... implementation -} -``` - -## Error Handling - -| Error Type | Recovery | -|------------|----------| -| Tests don't run | 检查测试脚本配置,提示用户 | -| All tests fail | 建议进入 debug 模式 | -| Coverage tool missing | 跳过覆盖率检查,仅运行测试 | -| Timeout | 增加超时时间或拆分测试 | - -## Validation Report Template - -参考 [templates/validation-template.md](../../templates/validation-template.md) - -## CLI Integration - -### 质量分析 -```bash -ccw cli -p "PURPOSE: Analyze test results and coverage... -TASK: • Review results • Identify gaps • Suggest improvements -MODE: analysis -CONTEXT: @test-results.json @coverage.json -EXPECTED: Quality assessment -" --tool gemini --mode analysis --rule analysis-review-code-quality -``` - -### 测试生成 (如覆盖率低) -```bash -ccw cli -p "PURPOSE: Generate missing test cases... -TASK: • Analyze uncovered code • Write tests -MODE: write -CONTEXT: @coverage.json @src/**/* -EXPECTED: Test code -" --tool gemini --mode write --rule development-generate-tests -``` - -## Next Actions (Hints) - -- 验证通过: `action-complete` (完成循环) -- 验证失败: `action-debug-with-file` (调试失败测试) -- 覆盖率低: `action-develop-with-file` (添加测试) -- 用户选择: `action-menu` (返回菜单) diff --git a/.claude/skills/ccw-loop/phases/orchestrator.md b/.claude/skills/ccw-loop/phases/orchestrator.md deleted file mode 100644 index decf5ee9..00000000 --- a/.claude/skills/ccw-loop/phases/orchestrator.md +++ /dev/null @@ -1,486 +0,0 @@ -# Orchestrator - -根据当前状态选择并执行下一个动作,实现无状态循环工作流。与 API (loop-v2-routes.ts) 协作实现控制平面/执行平面分离。 - -## Role - -检查控制信号 → 读取文件状态 → 选择动作 → 执行 → 更新文件 → 循环,直到完成或被外部暂停/停止。 - -## State Management (Unified Location) - -### 读取状态 - -```javascript -const getUtc8ISOString = () => new Date(Date.now() + 8 * 60 * 60 * 1000).toISOString() - -/** - * 读取循环状态 (统一位置) - * @param loopId - Loop ID (e.g., "loop-v2-20260122-abc123") - */ -function readLoopState(loopId) { - const stateFile = `.loop/${loopId}.json` - - if (!fs.existsSync(stateFile)) { - return null - } - - const state = JSON.parse(Read(stateFile)) - return state -} -``` - -### 更新状态 - -```javascript -/** - * 更新循环状态 (只更新 skill_state 部分,不修改 API 字段) - * @param loopId - Loop ID - * @param updates - 更新内容 (skill_state 字段) - */ -function updateLoopState(loopId, updates) { - const stateFile = `.loop/${loopId}.json` - const currentState = readLoopState(loopId) - - if (!currentState) { - throw new Error(`Loop state not found: ${loopId}`) - } - - // 只更新 skill_state 和 updated_at - const newState = { - ...currentState, - updated_at: getUtc8ISOString(), - skill_state: { - ...currentState.skill_state, - ...updates - } - } - - Write(stateFile, JSON.stringify(newState, null, 2)) - return newState -} -``` - -### 创建新循环状态 (直接调用时) - -```javascript -/** - * 创建新的循环状态 (仅在直接调用时使用,API 触发时状态已存在) - */ -function createLoopState(loopId, taskDescription) { - const stateFile = `.loop/${loopId}.json` - const now = getUtc8ISOString() - - const state = { - // API 兼容字段 - loop_id: loopId, - title: taskDescription.substring(0, 100), - description: taskDescription, - max_iterations: 10, - status: 'running', // 直接调用时设为 running - current_iteration: 0, - created_at: now, - updated_at: now, - - // Skill 扩展字段 - skill_state: null // 由 action-init 初始化 - } - - // 确保目录存在 - Bash(`mkdir -p ".loop"`) - Bash(`mkdir -p ".loop/${loopId}.progress"`) - - Write(stateFile, JSON.stringify(state, null, 2)) - return state -} -``` - -## Control Signal Checking - -```javascript -/** - * 检查 API 控制信号 - * 必须在每个 Action 开始前调用 - * @returns { continue: boolean, reason: string } - */ -function checkControlSignals(loopId) { - const state = readLoopState(loopId) - - if (!state) { - return { continue: false, reason: 'state_not_found' } - } - - switch (state.status) { - case 'paused': - // API 暂停了循环,Skill 应退出等待 resume - console.log(`⏸️ Loop paused by API. Waiting for resume...`) - return { continue: false, reason: 'paused' } - - case 'failed': - // API 停止了循环 (用户手动停止) - console.log(`⏹️ Loop stopped by API.`) - return { continue: false, reason: 'stopped' } - - case 'completed': - // 已完成 - console.log(`✅ Loop already completed.`) - return { continue: false, reason: 'completed' } - - case 'created': - // API 创建但未启动 (不应该走到这里) - console.log(`⚠️ Loop not started by API.`) - return { continue: false, reason: 'not_started' } - - case 'running': - // 正常继续 - return { continue: true, reason: 'running' } - - default: - console.log(`⚠️ Unknown status: ${state.status}`) - return { continue: false, reason: 'unknown_status' } - } -} -``` - -## Decision Logic - -```javascript -/** - * 选择下一个 Action (基于 skill_state) - */ -function selectNextAction(state, mode = 'interactive') { - const skillState = state.skill_state - - // 1. 终止条件检查 (API status) - if (state.status === 'completed') return null - if (state.status === 'failed') return null - if (state.current_iteration >= state.max_iterations) { - console.warn(`已达到最大迭代次数 (${state.max_iterations})`) - return 'action-complete' - } - - // 2. 初始化检查 - if (!skillState || !skillState.current_action) { - return 'action-init' - } - - // 3. 模式判断 - if (mode === 'interactive') { - return 'action-menu' // 显示菜单让用户选择 - } - - // 4. 自动模式:基于状态自动选择 - if (mode === 'auto') { - // 按优先级:develop → debug → validate - - // 如果有待开发任务 - const hasPendingDevelop = skillState.develop?.tasks?.some(t => t.status === 'pending') - if (hasPendingDevelop) { - return 'action-develop-with-file' - } - - // 如果开发完成但未调试 - if (skillState.last_action === 'action-develop-with-file') { - const needsDebug = skillState.develop?.completed < skillState.develop?.total - if (needsDebug) { - return 'action-debug-with-file' - } - } - - // 如果调试完成但未验证 - if (skillState.last_action === 'action-debug-with-file' || - skillState.debug?.confirmed_hypothesis) { - return 'action-validate-with-file' - } - - // 如果验证失败,回到开发 - if (skillState.last_action === 'action-validate-with-file') { - if (!skillState.validate?.passed) { - return 'action-develop-with-file' - } - } - - // 全部通过,完成 - if (skillState.validate?.passed && !hasPendingDevelop) { - return 'action-complete' - } - - // 默认:开发 - return 'action-develop-with-file' - } - - // 5. 默认完成 - return 'action-complete' -} -``` - -## Execution Loop - -```javascript -/** - * 运行编排器 - * @param options.loopId - 现有 Loop ID (API 触发时) - * @param options.task - 任务描述 (直接调用时) - * @param options.mode - 'interactive' | 'auto' - */ -async function runOrchestrator(options = {}) { - const { loopId: existingLoopId, task, mode = 'interactive' } = options - - console.log('=== CCW Loop Orchestrator Started ===') - - // 1. 确定 loopId - let loopId - let state - - if (existingLoopId) { - // API 触发:使用现有 loopId - loopId = existingLoopId - state = readLoopState(loopId) - - if (!state) { - console.error(`Loop not found: ${loopId}`) - return { status: 'error', message: 'Loop not found' } - } - - console.log(`Resuming loop: ${loopId}`) - console.log(`Status: ${state.status}`) - - } else if (task) { - // 直接调用:创建新 loopId - const timestamp = getUtc8ISOString().replace(/[-:]/g, '').split('.')[0] - const random = Math.random().toString(36).substring(2, 10) - loopId = `loop-v2-${timestamp}-${random}` - - console.log(`Creating new loop: ${loopId}`) - console.log(`Task: ${task}`) - - state = createLoopState(loopId, task) - - } else { - console.error('Either --loop-id or task description is required') - return { status: 'error', message: 'Missing loopId or task' } - } - - const progressDir = `.loop/${loopId}.progress` - - // 2. 主循环 - let iteration = state.current_iteration || 0 - - while (iteration < state.max_iterations) { - iteration++ - - // ======================================== - // CRITICAL: Check control signals first - // ======================================== - const control = checkControlSignals(loopId) - if (!control.continue) { - console.log(`\n🛑 Loop terminated: ${control.reason}`) - break - } - - // 重新读取状态 (可能被 API 更新) - state = readLoopState(loopId) - - console.log(`\n[Iteration ${iteration}] Status: ${state.status}`) - - // 选择下一个动作 - const actionId = selectNextAction(state, mode) - - if (!actionId) { - console.log('No action selected, terminating.') - break - } - - console.log(`[Iteration ${iteration}] Executing: ${actionId}`) - - // 更新 current_iteration - state = { - ...state, - current_iteration: iteration, - updated_at: getUtc8ISOString() - } - Write(`.loop/${loopId}.json`, JSON.stringify(state, null, 2)) - - // 执行动作 - try { - const actionPromptFile = `.claude/skills/ccw-loop/phases/actions/${actionId}.md` - - if (!fs.existsSync(actionPromptFile)) { - console.error(`Action file not found: ${actionPromptFile}`) - continue - } - - const actionPrompt = Read(actionPromptFile) - - // 构建 Agent 提示 - const agentPrompt = ` -[LOOP CONTEXT] -Loop ID: ${loopId} -State File: .loop/${loopId}.json -Progress Dir: ${progressDir} - -[CURRENT STATE] -${JSON.stringify(state, null, 2)} - -[ACTION INSTRUCTIONS] -${actionPrompt} - -[TASK] -You are executing ${actionId} for loop: ${state.title || state.description} - -[CONTROL SIGNALS] -Before executing, check if status is still 'running'. -If status is 'paused' or 'failed', exit gracefully. - -[RETURN] -Return JSON with: -- skillStateUpdates: Object with skill_state fields to update -- continue: Boolean indicating if loop should continue -- message: String with user message -` - - const result = await Task({ - subagent_type: 'universal-executor', - run_in_background: false, - description: `Execute ${actionId}`, - prompt: agentPrompt - }) - - // 解析结果 - const actionResult = JSON.parse(result) - - // 更新状态 (只更新 skill_state) - updateLoopState(loopId, { - current_action: null, - last_action: actionId, - completed_actions: [ - ...(state.skill_state?.completed_actions || []), - actionId - ], - ...actionResult.skillStateUpdates - }) - - // 显示消息 - if (actionResult.message) { - console.log(`\n${actionResult.message}`) - } - - // 检查是否继续 - if (actionResult.continue === false) { - console.log('Action requested termination.') - break - } - - } catch (error) { - console.error(`Error executing ${actionId}: ${error.message}`) - - // 错误处理 - updateLoopState(loopId, { - current_action: null, - errors: [ - ...(state.skill_state?.errors || []), - { - action: actionId, - message: error.message, - timestamp: getUtc8ISOString() - } - ] - }) - } - } - - if (iteration >= state.max_iterations) { - console.log(`\n⚠️ Reached maximum iterations (${state.max_iterations})`) - console.log('Consider breaking down the task or taking a break.') - } - - console.log('\n=== CCW Loop Orchestrator Finished ===') - - // 返回最终状态 - const finalState = readLoopState(loopId) - return { - status: finalState.status, - loop_id: loopId, - iterations: iteration, - final_state: finalState - } -} -``` - -## Action Catalog - -| Action | Purpose | Preconditions | Effects | -|--------|---------|---------------|---------| -| [action-init](actions/action-init.md) | 初始化会话 | status=pending | initialized=true | -| [action-menu](actions/action-menu.md) | 显示操作菜单 | initialized=true | 用户选择下一动作 | -| [action-develop-with-file](actions/action-develop-with-file.md) | 开发任务 | initialized=true | 更新 progress.md | -| [action-debug-with-file](actions/action-debug-with-file.md) | 假设调试 | initialized=true | 更新 understanding.md | -| [action-validate-with-file](actions/action-validate-with-file.md) | 测试验证 | initialized=true | 更新 validation.md | -| [action-complete](actions/action-complete.md) | 完成循环 | validation_passed=true | status=completed | - -## Termination Conditions - -1. **API 暂停**: `state.status === 'paused'` (Skill 退出,等待 resume) -2. **API 停止**: `state.status === 'failed'` (Skill 终止) -3. **任务完成**: `state.status === 'completed'` -4. **迭代限制**: `state.current_iteration >= state.max_iterations` -5. **Action 请求终止**: `actionResult.continue === false` - -## Error Recovery - -| Error Type | Recovery Strategy | -|------------|-------------------| -| 动作执行失败 | 记录错误,增加 error_count,继续下一动作 | -| 状态文件损坏 | 从其他文件重建状态 (progress.md, understanding.md 等) | -| 用户中止 | 保存当前状态,允许 --resume 恢复 | -| CLI 工具失败 | 回退到手动分析模式 | - -## Mode Strategies - -### Interactive Mode (默认) - -每次显示菜单,让用户选择动作: - -``` -当前状态: 开发中 -可用操作: - 1. 继续开发 (develop) - 2. 开始调试 (debug) - 3. 运行验证 (validate) - 4. 查看进度 (status) - 5. 退出 (exit) - -请选择: -``` - -### Auto Mode (自动循环) - -按预设流程自动执行: - -``` -Develop → Debug → Validate → - ↓ (如验证失败) -Develop (修复) → Debug → Validate → 完成 -``` - -## State Machine (API Status) - -```mermaid -stateDiagram-v2 - [*] --> created: API creates loop - created --> running: API /start → Trigger Skill - running --> paused: API /pause → Set status - running --> completed: action-complete - running --> failed: API /stop OR error - paused --> running: API /resume → Re-trigger Skill - completed --> [*] - failed --> [*] - - note right of paused - Skill checks status before each action - If paused, Skill exits gracefully - end note - - note right of running - Skill executes: init → develop → debug → validate - end note -``` diff --git a/.claude/skills/ccw-loop/phases/state-schema.md b/.claude/skills/ccw-loop/phases/state-schema.md deleted file mode 100644 index 94c46cff..00000000 --- a/.claude/skills/ccw-loop/phases/state-schema.md +++ /dev/null @@ -1,474 +0,0 @@ -# State Schema - -CCW Loop 的状态结构定义(统一版本)。 - -## 状态文件 - -**位置**: `.loop/{loopId}.json` (统一位置,API + Skill 共享) - -**旧版本位置** (仅向后兼容): `.workflow/.loop/{session-id}/state.json` - -## 结构定义 - -### 统一状态接口 (Unified Loop State) - -```typescript -/** - * Unified Loop State - API 和 Skill 共享的状态结构 - * API (loop-v2-routes.ts) 拥有状态的主控权 - * Skill (ccw-loop) 读取和更新此状态 - */ -interface LoopState { - // ===================================================== - // API FIELDS (from loop-v2-routes.ts) - // 这些字段由 API 管理,Skill 只读 - // ===================================================== - - loop_id: string // Loop ID, e.g., "loop-v2-20260122-abc123" - title: string // Loop 标题 - description: string // Loop 描述 - max_iterations: number // 最大迭代次数 - status: 'created' | 'running' | 'paused' | 'completed' | 'failed' - current_iteration: number // 当前迭代次数 - created_at: string // 创建时间 (ISO8601) - updated_at: string // 最后更新时间 (ISO8601) - completed_at?: string // 完成时间 (ISO8601) - failure_reason?: string // 失败原因 - - // ===================================================== - // SKILL EXTENSION FIELDS - // 这些字段由 Skill 管理,API 只读 - // ===================================================== - - skill_state?: { - // 当前执行动作 - current_action: 'init' | 'develop' | 'debug' | 'validate' | 'complete' | null - last_action: string | null - completed_actions: string[] - mode: 'interactive' | 'auto' - - // === 开发阶段 === - develop: { - total: number - completed: number - current_task?: string - tasks: DevelopTask[] - last_progress_at: string | null - } - - // === 调试阶段 === - debug: { - active_bug?: string - hypotheses_count: number - hypotheses: Hypothesis[] - confirmed_hypothesis: string | null - iteration: number - last_analysis_at: string | null - } - - // === 验证阶段 === - validate: { - pass_rate: number // 测试通过率 (0-100) - coverage: number // 覆盖率 (0-100) - test_results: TestResult[] - passed: boolean - failed_tests: string[] - last_run_at: string | null - } - - // === 错误追踪 === - errors: Array<{ - action: string - message: string - timestamp: string - }> - } -} - -interface DevelopTask { - id: string - description: string - tool: 'gemini' | 'qwen' | 'codex' | 'bash' - mode: 'analysis' | 'write' - status: 'pending' | 'in_progress' | 'completed' | 'failed' - files_changed: string[] - created_at: string - completed_at: string | null -} - -interface Hypothesis { - id: string // H1, H2, ... - description: string - testable_condition: string - logging_point: string - evidence_criteria: { - confirm: string - reject: string - } - likelihood: number // 1 = 最可能 - status: 'pending' | 'confirmed' | 'rejected' | 'inconclusive' - evidence: Record | null - verdict_reason: string | null -} - -interface TestResult { - test_name: string - suite: string - status: 'passed' | 'failed' | 'skipped' - duration_ms: number - error_message: string | null - stack_trace: string | null -} -``` - -## 初始状态 - -### 由 API 创建时 (Dashboard 触发) - -```json -{ - "loop_id": "loop-v2-20260122-abc123", - "title": "Implement user authentication", - "description": "Add login/logout functionality", - "max_iterations": 10, - "status": "created", - "current_iteration": 0, - "created_at": "2026-01-22T10:00:00+08:00", - "updated_at": "2026-01-22T10:00:00+08:00" -} -``` - -### 由 Skill 初始化后 (action-init) - -```json -{ - "loop_id": "loop-v2-20260122-abc123", - "title": "Implement user authentication", - "description": "Add login/logout functionality", - "max_iterations": 10, - "status": "running", - "current_iteration": 0, - "created_at": "2026-01-22T10:00:00+08:00", - "updated_at": "2026-01-22T10:00:05+08:00", - - "skill_state": { - "current_action": "init", - "last_action": null, - "completed_actions": [], - "mode": "auto", - - "develop": { - "total": 3, - "completed": 0, - "current_task": null, - "tasks": [ - { "id": "task-001", "description": "Create auth component", "status": "pending" } - ], - "last_progress_at": null - }, - - "debug": { - "active_bug": null, - "hypotheses_count": 0, - "hypotheses": [], - "confirmed_hypothesis": null, - "iteration": 0, - "last_analysis_at": null - }, - - "validate": { - "pass_rate": 0, - "coverage": 0, - "test_results": [], - "passed": false, - "failed_tests": [], - "last_run_at": null - }, - - "errors": [] - } -} -``` - -## 控制信号检查 (Control Signals) - -Skill 在每个 Action 开始前必须检查控制信号: - -```javascript -/** - * 检查 API 控制信号 - * @returns { continue: boolean, action: 'pause_exit' | 'stop_exit' | 'continue' } - */ -function checkControlSignals(loopId) { - const state = JSON.parse(Read(`.loop/${loopId}.json`)) - - switch (state.status) { - case 'paused': - // API 暂停了循环,Skill 应退出等待 resume - return { continue: false, action: 'pause_exit' } - - case 'failed': - // API 停止了循环 (用户手动停止) - return { continue: false, action: 'stop_exit' } - - case 'running': - // 正常继续 - return { continue: true, action: 'continue' } - - default: - // 异常状态 - return { continue: false, action: 'stop_exit' } - } -} -``` - -### 在 Action 中使用 - -```markdown -## Execution - -### Step 1: Check Control Signals - -\`\`\`javascript -const control = checkControlSignals(loopId) -if (!control.continue) { - // 输出退出原因 - console.log(`Loop ${control.action}: status = ${state.status}`) - - // 如果是 pause_exit,保存当前进度 - if (control.action === 'pause_exit') { - updateSkillState(loopId, { current_action: 'paused' }) - } - - return // 退出 Action -} -\`\`\` - -### Step 2: Execute Action Logic -... -``` - -## 状态转换规则 - -### 1. 初始化 (action-init) - -```javascript -// Skill 初始化后 -{ - // API 字段更新 - status: 'created' → 'running', // 或保持 'running' 如果 API 已设置 - updated_at: timestamp, - - // Skill 字段初始化 - skill_state: { - current_action: 'init', - mode: 'auto', - develop: { - tasks: [...parsed_tasks], - total: N, - completed: 0 - } - } -} -``` - -### 2. 开发进行中 (action-develop-with-file) - -```javascript -// 开发任务执行后 -{ - updated_at: timestamp, - current_iteration: state.current_iteration + 1, - - skill_state: { - current_action: 'develop', - last_action: 'action-develop-with-file', - completed_actions: [...state.skill_state.completed_actions, 'action-develop-with-file'], - develop: { - current_task: 'task-xxx', - completed: N+1, - last_progress_at: timestamp - } - } -} -``` - -### 3. 调试进行中 (action-debug-with-file) - -```javascript -// 调试执行后 -{ - updated_at: timestamp, - current_iteration: state.current_iteration + 1, - - skill_state: { - current_action: 'debug', - last_action: 'action-debug-with-file', - debug: { - active_bug: '...', - hypotheses_count: N, - hypotheses: [...new_hypotheses], - iteration: N+1, - last_analysis_at: timestamp - } - } -} -``` - -### 4. 验证完成 (action-validate-with-file) - -```javascript -// 验证执行后 -{ - updated_at: timestamp, - current_iteration: state.current_iteration + 1, - - skill_state: { - current_action: 'validate', - last_action: 'action-validate-with-file', - validate: { - test_results: [...results], - pass_rate: 95.5, - coverage: 85.0, - passed: true | false, - failed_tests: ['test1', 'test2'], - last_run_at: timestamp - } - } -} -``` - -### 5. 完成 (action-complete) - -```javascript -// 循环完成后 -{ - status: 'running' → 'completed', - completed_at: timestamp, - updated_at: timestamp, - - skill_state: { - current_action: 'complete', - last_action: 'action-complete' - } -} -``` - -## 状态派生字段 - -以下字段可从状态计算得出,不需要存储: - -```javascript -// 开发完成度 -const developProgress = state.develop.total_count > 0 - ? (state.develop.completed_count / state.develop.total_count) * 100 - : 0 - -// 是否有待开发任务 -const hasPendingDevelop = state.develop.tasks.some(t => t.status === 'pending') - -// 调试是否完成 -const debugCompleted = state.debug.confirmed_hypothesis !== null - -// 验证是否通过 -const validationPassed = state.validate.passed && state.validate.test_results.length > 0 - -// 整体进度 -const overallProgress = ( - (developProgress * 0.5) + - (debugCompleted ? 25 : 0) + - (validationPassed ? 25 : 0) -) -``` - -## 文件同步 - -### 统一位置 (Unified Location) - -状态与文件的对应关系: - -| 状态字段 | 同步文件 | 同步时机 | -|----------|----------|----------| -| 整个 LoopState | `.loop/{loopId}.json` | 每次状态变更 (主文件) | -| `skill_state.develop` | `.loop/{loopId}.progress/develop.md` | 每次开发操作后 | -| `skill_state.debug` | `.loop/{loopId}.progress/debug.md` | 每次调试操作后 | -| `skill_state.validate` | `.loop/{loopId}.progress/validate.md` | 每次验证操作后 | -| 代码变更日志 | `.loop/{loopId}.progress/changes.log` | 每次文件修改 (NDJSON) | -| 调试日志 | `.loop/{loopId}.progress/debug.log` | 每次调试日志 (NDJSON) | - -### 文件结构示例 - -``` -.loop/ -├── loop-v2-20260122-abc123.json # 主状态文件 (API + Skill) -├── loop-v2-20260122-abc123.tasks.jsonl # 任务列表 (API 管理) -└── loop-v2-20260122-abc123.progress/ # Skill 进度文件 - ├── develop.md # 开发进度 - ├── debug.md # 调试理解 - ├── validate.md # 验证报告 - ├── changes.log # 代码变更 (NDJSON) - └── debug.log # 调试日志 (NDJSON) -``` - -## 状态恢复 - -如果主状态文件 `.loop/{loopId}.json` 损坏,可以从进度文件重建 skill_state: - -```javascript -function rebuildSkillStateFromProgress(loopId) { - const progressDir = `.loop/${loopId}.progress` - - // 尝试从进度文件解析状态 - const skill_state = { - develop: parseProgressFile(`${progressDir}/develop.md`), - debug: parseProgressFile(`${progressDir}/debug.md`), - validate: parseProgressFile(`${progressDir}/validate.md`) - } - - return skill_state -} - -// 解析进度 Markdown 文件 -function parseProgressFile(filePath) { - const content = Read(filePath) - if (!content) return null - - // 从 Markdown 表格和结构中提取数据 - // ... implementation -} -``` - -### 恢复策略 - -1. **API 字段**: 无法恢复 - 需要从 API 重新获取或用户手动输入 -2. **skill_state 字段**: 可以从 `.progress/` 目录的 Markdown 文件解析 -3. **任务列表**: 从 `.loop/{loopId}.tasks.jsonl` 恢复 - -## 状态验证 - -```javascript -function validateState(state) { - const errors = [] - - // 必需字段 - if (!state.session_id) errors.push('Missing session_id') - if (!state.task_description) errors.push('Missing task_description') - - // 状态一致性 - if (state.initialized && state.status === 'pending') { - errors.push('Inconsistent: initialized but status is pending') - } - - if (state.status === 'completed' && !state.validate.passed) { - errors.push('Inconsistent: completed but validation not passed') - } - - // 开发任务一致性 - const completedTasks = state.develop.tasks.filter(t => t.status === 'completed').length - if (completedTasks !== state.develop.completed_count) { - errors.push('Inconsistent: completed_count mismatch') - } - - return { valid: errors.length === 0, errors } -} -``` diff --git a/.claude/skills/ccw-loop/specs/action-catalog.md b/.claude/skills/ccw-loop/specs/action-catalog.md deleted file mode 100644 index cc1e5ffc..00000000 --- a/.claude/skills/ccw-loop/specs/action-catalog.md +++ /dev/null @@ -1,300 +0,0 @@ -# Action Catalog - -CCW Loop 所有可用动作的目录和说明。 - -## Available Actions - -| Action | Purpose | Preconditions | Effects | CLI Integration | -|--------|---------|---------------|---------|-----------------| -| [action-init](../phases/actions/action-init.md) | 初始化会话 | status=pending, initialized=false | status→running, initialized→true, 创建目录和任务列表 | Gemini 任务分解 | -| [action-menu](../phases/actions/action-menu.md) | 显示操作菜单 | initialized=true, status=running | 返回用户选择的动作 | - | -| [action-develop-with-file](../phases/actions/action-develop-with-file.md) | 执行开发任务 | initialized=true, pending tasks > 0 | 更新 progress.md, 完成一个任务 | Gemini 代码实现 | -| [action-debug-with-file](../phases/actions/action-debug-with-file.md) | 假设驱动调试 | initialized=true | 更新 understanding.md, hypotheses.json | Gemini 假设生成和证据分析 | -| [action-validate-with-file](../phases/actions/action-validate-with-file.md) | 运行测试验证 | initialized=true, develop > 0 or debug confirmed | 更新 validation.md, test-results.json | Gemini 质量分析 | -| [action-complete](../phases/actions/action-complete.md) | 完成循环 | initialized=true | status→completed, 生成 summary.md | - | - -## Action Dependencies Graph - -```mermaid -graph TD - START([用户启动 /ccw-loop]) --> INIT[action-init] - INIT --> MENU[action-menu] - - MENU --> DEVELOP[action-develop-with-file] - MENU --> DEBUG[action-debug-with-file] - MENU --> VALIDATE[action-validate-with-file] - MENU --> STATUS[action-status] - MENU --> COMPLETE[action-complete] - MENU --> EXIT([退出]) - - DEVELOP --> MENU - DEBUG --> MENU - VALIDATE --> MENU - STATUS --> MENU - COMPLETE --> END([结束]) - EXIT --> END - - style INIT fill:#e1f5fe - style MENU fill:#fff3e0 - style DEVELOP fill:#e8f5e9 - style DEBUG fill:#fce4ec - style VALIDATE fill:#f3e5f5 - style COMPLETE fill:#c8e6c9 -``` - -## Action Execution Matrix - -### Interactive Mode - -| State | Auto-Selected Action | User Options | -|-------|---------------------|--------------| -| pending | action-init | - | -| running, !initialized | action-init | - | -| running, initialized | action-menu | All actions | - -### Auto Mode - -| Condition | Selected Action | -|-----------|----------------| -| pending_develop_tasks > 0 | action-develop-with-file | -| last_action=develop, !debug_completed | action-debug-with-file | -| last_action=debug, !validation_completed | action-validate-with-file | -| validation_failed | action-develop-with-file (fix) | -| validation_passed, no pending | action-complete | - -## Action Inputs/Outputs - -### action-init - -**Inputs**: -- state.task_description -- User input (optional) - -**Outputs**: -- meta.json -- state.json (初始化) -- develop/tasks.json -- develop/progress.md - -**State Changes**: -```javascript -{ - status: 'pending' → 'running', - initialized: false → true, - develop.tasks: [] → [task1, task2, ...] -} -``` - -### action-develop-with-file - -**Inputs**: -- state.develop.tasks -- User selection (如有多个待处理任务) - -**Outputs**: -- develop/progress.md (追加) -- develop/tasks.json (更新) -- develop/changes.log (追加) - -**State Changes**: -```javascript -{ - develop.current_task_id: null → 'task-xxx' → null, - develop.completed_count: N → N+1, - last_action: X → 'action-develop-with-file' -} -``` - -### action-debug-with-file - -**Inputs**: -- Bug description (用户输入或从测试失败获取) -- debug.log (如已有) - -**Outputs**: -- debug/understanding.md (追加) -- debug/hypotheses.json (更新) -- Code changes (添加日志或修复) - -**State Changes**: -```javascript -{ - debug.current_bug: null → 'bug description', - debug.hypotheses: [...updated], - debug.iteration: N → N+1, - debug.confirmed_hypothesis: null → 'H1' (如确认) -} -``` - -### action-validate-with-file - -**Inputs**: -- 测试脚本 (从 package.json) -- 覆盖率工具 (可选) - -**Outputs**: -- validate/validation.md (追加) -- validate/test-results.json (更新) -- validate/coverage.json (更新) - -**State Changes**: -```javascript -{ - validate.test_results: [...new results], - validate.coverage: null → 85.5, - validate.passed: false → true, - validate.failed_tests: ['test1', 'test2'] → [] -} -``` - -### action-complete - -**Inputs**: -- state (完整状态) -- User choices (扩展选项) - -**Outputs**: -- summary.md -- Issues (如选择扩展) - -**State Changes**: -```javascript -{ - status: 'running' → 'completed', - completed_at: null → timestamp -} -``` - -## Action Sequences - -### Typical Happy Path - -``` -action-init - → action-develop-with-file (task 1) - → action-develop-with-file (task 2) - → action-develop-with-file (task 3) - → action-validate-with-file - → PASS - → action-complete -``` - -### Debug Iteration Path - -``` -action-init - → action-develop-with-file (task 1) - → action-validate-with-file - → FAIL - → action-debug-with-file (探索) - → action-debug-with-file (分析) - → Root cause found - → action-validate-with-file - → PASS - → action-complete -``` - -### Multi-Iteration Path - -``` -action-init - → action-develop-with-file (task 1) - → action-debug-with-file - → action-develop-with-file (task 2) - → action-validate-with-file - → FAIL - → action-debug-with-file - → action-validate-with-file - → PASS - → action-complete -``` - -## Error Scenarios - -### CLI Tool Failure - -``` -action-develop-with-file - → Gemini CLI fails - → Fallback to manual implementation - → Prompt user for code - → Continue -``` - -### Test Failure - -``` -action-validate-with-file - → Tests fail - → Record failed tests - → Suggest action-debug-with-file - → User chooses debug or manual fix -``` - -### Max Iterations Reached - -``` -state.iteration_count >= 10 - → Warning message - → Suggest break or task split - → Allow continue or exit -``` - -## Action Extensions - -### Adding New Actions - -To add a new action: - -1. Create `phases/actions/action-{name}.md` -2. Define preconditions, execution, state updates -3. Add to this catalog -4. Update orchestrator.md decision logic -5. Add to action-menu.md options - -### Action Template - -```markdown -# Action: {Name} - -{Brief description} - -## Purpose - -{Detailed purpose} - -## Preconditions - -- [ ] condition1 -- [ ] condition2 - -## Execution - -### Step 1: {Step Name} - -\`\`\`javascript -// code -\`\`\` - -## State Updates - -\`\`\`javascript -return { - stateUpdates: { - // updates - }, - continue: true, - message: "..." -} -\`\`\` - -## Error Handling - -| Error Type | Recovery | -|------------|----------| -| ... | ... | - -## Next Actions (Hints) - -- condition: next_action -``` diff --git a/.claude/skills/ccw-loop/specs/loop-requirements.md b/.claude/skills/ccw-loop/specs/loop-requirements.md deleted file mode 100644 index 90719be5..00000000 --- a/.claude/skills/ccw-loop/specs/loop-requirements.md +++ /dev/null @@ -1,192 +0,0 @@ -# Loop Requirements Specification - -CCW Loop 的核心需求和约束定义。 - -## Core Requirements - -### 1. 无状态循环 - -**Requirement**: 每次执行从文件读取状态,执行后写回文件,不依赖内存状态。 - -**Rationale**: 支持随时中断和恢复,状态持久化。 - -**Validation**: -- [ ] 每个 action 开始时从文件读取状态 -- [ ] 每个 action 结束时将状态写回文件 -- [ ] 无全局变量或内存状态依赖 - -### 2. 文件驱动进度 - -**Requirement**: 所有进度、理解、验证结果都记录在专用 Markdown 文件中。 - -**Rationale**: 可审计、可回顾、团队可见。 - -**Validation**: -- [ ] develop/progress.md 记录开发进度 -- [ ] debug/understanding.md 记录理解演变 -- [ ] validate/validation.md 记录验证结果 -- [ ] 所有文件使用 Markdown 格式,易读 - -### 3. CLI 工具集成 - -**Requirement**: 关键决策点使用 Gemini/CLI 进行深度分析。 - -**Rationale**: 利用 LLM 能力提高质量。 - -**Validation**: -- [ ] 任务分解使用 Gemini -- [ ] 假设生成使用 Gemini -- [ ] 证据分析使用 Gemini -- [ ] 质量评估使用 Gemini - -### 4. 用户控制循环 - -**Requirement**: 支持交互式和自动循环两种模式,用户可随时介入。 - -**Rationale**: 灵活性,适应不同场景。 - -**Validation**: -- [ ] 交互模式:每步显示菜单 -- [ ] 自动模式:按预设流程执行 -- [ ] 用户可随时退出 -- [ ] 状态可恢复 - -### 5. 可恢复性 - -**Requirement**: 任何时候中断后,可以从上次位置继续。 - -**Rationale**: 长时间任务支持,意外中断恢复。 - -**Validation**: -- [ ] 状态保存在 state.json -- [ ] 使用 --resume 可继续 -- [ ] 历史记录完整保留 - -## Quality Standards - -### Completeness - -| Dimension | Threshold | -|-----------|-----------| -| 进度文档完整性 | 每个任务都有记录 | -| 理解文档演变 | 每次迭代都有更新 | -| 验证报告详尽 | 包含所有测试结果 | - -### Consistency - -| Dimension | Threshold | -|-----------|-----------| -| 文件格式一致 | 所有 Markdown 文件使用相同模板 | -| 状态同步一致 | state.json 与文件内容匹配 | -| 时间戳格式 | 统一使用 ISO8601 格式 | - -### Usability - -| Dimension | Threshold | -|-----------|-----------| -| 菜单易用性 | 选项清晰,描述准确 | -| 进度可见性 | 随时可查看当前状态 | -| 错误提示 | 错误消息清晰,提供恢复建议 | - -## Constraints - -### 1. 文件结构约束 - -``` -.workflow/.loop/{session-id}/ -├── meta.json # 只写一次,不再修改 -├── state.json # 每次 action 后更新 -├── develop/ -│ ├── progress.md # 只追加,不删除 -│ ├── tasks.json # 任务状态更新 -│ └── changes.log # NDJSON 格式,只追加 -├── debug/ -│ ├── understanding.md # 只追加,记录时间线 -│ ├── hypotheses.json # 更新假设状态 -│ └── debug.log # NDJSON 格式 -└── validate/ - ├── validation.md # 每次验证追加 - ├── test-results.json # 累积测试结果 - └── coverage.json # 最新覆盖率 -``` - -### 2. 命名约束 - -- Session ID: `LOOP-{slug}-{YYYY-MM-DD}` -- Task ID: `task-{NNN}` (三位数字) -- Hypothesis ID: `H{N}` (单字母+数字) - -### 3. 状态转换约束 - -``` -pending → running → completed - ↓ - user_exit - ↓ - failed -``` - -Only allow: `pending→running`, `running→completed/user_exit/failed` - -### 4. 错误限制约束 - -- 最大错误次数: 3 -- 超过 3 次错误 → 自动终止 -- 每次错误 → 记录到 state.errors[] - -### 5. 迭代限制约束 - -- 最大迭代次数: 10 (警告) -- 超过 10 次 → 警告用户,但不强制停止 -- 建议拆分任务或休息 - -## Integration Requirements - -### 1. Dashboard 集成 - -**Requirement**: 与 CCW Dashboard Loop Monitor 无缝集成。 - -**Specification**: -- Dashboard 创建 Loop → 调用此 Skill -- state.json → Dashboard 实时显示 -- 任务列表双向同步 -- 状态控制按钮映射到 actions - -### 2. Issue 系统集成 - -**Requirement**: 完成后可扩展为 Issue。 - -**Specification**: -- 支持维度: test, enhance, refactor, doc -- 调用 `/issue:new "{summary} - {dimension}"` -- 自动填充上下文 - -### 3. CLI 工具集成 - -**Requirement**: 使用 CCW CLI 工具进行分析和实现。 - -**Specification**: -- 任务分解: `--rule planning-breakdown-task-steps` -- 代码实现: `--rule development-implement-feature` -- 根因分析: `--rule analysis-diagnose-bug-root-cause` -- 质量评估: `--rule analysis-review-code-quality` - -## Non-Functional Requirements - -### Performance - -- Session 初始化: < 5s -- Action 执行: < 30s (不含 CLI 调用) -- 状态读写: < 1s - -### Reliability - -- 状态文件损坏恢复: 支持从其他文件重建 -- CLI 工具失败降级: 回退到手动模式 -- 错误重试: 支持一次自动重试 - -### Maintainability - -- 文档化: 所有 action 都有清晰说明 -- 模块化: 每个 action 独立可测 -- 可扩展: 易于添加新 action diff --git a/.claude/skills/ccw-loop/templates/progress-template.md b/.claude/skills/ccw-loop/templates/progress-template.md deleted file mode 100644 index 5f3b9682..00000000 --- a/.claude/skills/ccw-loop/templates/progress-template.md +++ /dev/null @@ -1,175 +0,0 @@ -# Progress Document Template - -开发进度文档的标准模板。 - -## Template Structure - -```markdown -# Development Progress - -**Session ID**: {{session_id}} -**Task**: {{task_description}} -**Started**: {{started_at}} -**Estimated Complexity**: {{complexity}} - ---- - -## Task List - -{{#each tasks}} -{{@index}}. [{{#if completed}}x{{else}} {{/if}}] {{description}} -{{/each}} - -## Key Files - -{{#each key_files}} -- `{{this}}` -{{/each}} - ---- - -## Progress Timeline - -{{#each iterations}} -### Iteration {{@index}} - {{task_name}} ({{timestamp}}) - -#### Task Details - -- **ID**: {{task_id}} -- **Tool**: {{tool}} -- **Mode**: {{mode}} - -#### Implementation Summary - -{{summary}} - -#### Files Changed - -{{#each files_changed}} -- `{{this}}` -{{/each}} - -#### Status: {{status}} - ---- -{{/each}} - -## Current Statistics - -| Metric | Value | -|--------|-------| -| Total Tasks | {{total_tasks}} | -| Completed | {{completed_tasks}} | -| In Progress | {{in_progress_tasks}} | -| Pending | {{pending_tasks}} | -| Progress | {{progress_percentage}}% | - ---- - -## Next Steps - -{{#each next_steps}} -- [ ] {{this}} -{{/each}} -``` - -## Template Variables - -| Variable | Type | Source | Description | -|----------|------|--------|-------------| -| `session_id` | string | state.session_id | 会话 ID | -| `task_description` | string | state.task_description | 任务描述 | -| `started_at` | string | state.created_at | 开始时间 | -| `complexity` | string | state.context.estimated_complexity | 预估复杂度 | -| `tasks` | array | state.develop.tasks | 任务列表 | -| `key_files` | array | state.context.key_files | 关键文件 | -| `iterations` | array | 从文件解析 | 迭代历史 | -| `total_tasks` | number | state.develop.total_count | 总任务数 | -| `completed_tasks` | number | state.develop.completed_count | 已完成数 | - -## Usage Example - -```javascript -const progressTemplate = Read('.claude/skills/ccw-loop/templates/progress-template.md') - -function renderProgress(state) { - let content = progressTemplate - - // 替换简单变量 - content = content.replace('{{session_id}}', state.session_id) - content = content.replace('{{task_description}}', state.task_description) - content = content.replace('{{started_at}}', state.created_at) - content = content.replace('{{complexity}}', state.context?.estimated_complexity || 'unknown') - - // 替换任务列表 - const taskList = state.develop.tasks.map((t, i) => { - const checkbox = t.status === 'completed' ? 'x' : ' ' - return `${i + 1}. [${checkbox}] ${t.description}` - }).join('\n') - content = content.replace('{{#each tasks}}...{{/each}}', taskList) - - // 替换统计 - content = content.replace('{{total_tasks}}', state.develop.total_count) - content = content.replace('{{completed_tasks}}', state.develop.completed_count) - // ... - - return content -} -``` - -## Section Templates - -### Task Entry - -```markdown -### Iteration {{N}} - {{task_name}} ({{timestamp}}) - -#### Task Details - -- **ID**: {{task_id}} -- **Tool**: {{tool}} -- **Mode**: {{mode}} - -#### Implementation Summary - -{{summary}} - -#### Files Changed - -{{#each files}} -- `{{this}}` -{{/each}} - -#### Status: COMPLETED - ---- -``` - -### Statistics Table - -```markdown -## Current Statistics - -| Metric | Value | -|--------|-------| -| Total Tasks | {{total}} | -| Completed | {{completed}} | -| In Progress | {{in_progress}} | -| Pending | {{pending}} | -| Progress | {{percentage}}% | -``` - -### Next Steps - -```markdown -## Next Steps - -{{#if all_completed}} -- [ ] Run validation tests -- [ ] Code review -- [ ] Update documentation -{{else}} -- [ ] Complete remaining {{pending}} tasks -- [ ] Review completed work -{{/if}} -``` diff --git a/.claude/skills/ccw-loop/templates/understanding-template.md b/.claude/skills/ccw-loop/templates/understanding-template.md deleted file mode 100644 index c1069597..00000000 --- a/.claude/skills/ccw-loop/templates/understanding-template.md +++ /dev/null @@ -1,303 +0,0 @@ -# Understanding Document Template - -调试理解演变文档的标准模板。 - -## Template Structure - -```markdown -# Understanding Document - -**Session ID**: {{session_id}} -**Bug Description**: {{bug_description}} -**Started**: {{started_at}} - ---- - -## Exploration Timeline - -{{#each iterations}} -### Iteration {{number}} - {{title}} ({{timestamp}}) - -{{#if is_exploration}} -#### Current Understanding - -Based on bug description and initial code search: - -- Error pattern: {{error_pattern}} -- Affected areas: {{affected_areas}} -- Initial hypothesis: {{initial_thoughts}} - -#### Evidence from Code Search - -{{#each search_results}} -**Keyword: "{{keyword}}"** -- Found in: {{files}} -- Key findings: {{insights}} -{{/each}} -{{/if}} - -{{#if has_hypotheses}} -#### Hypotheses Generated (Gemini-Assisted) - -{{#each hypotheses}} -**{{id}}** (Likelihood: {{likelihood}}): {{description}} -- Logging at: {{logging_point}} -- Testing: {{testable_condition}} -- Evidence to confirm: {{confirm_criteria}} -- Evidence to reject: {{reject_criteria}} -{{/each}} - -**Gemini Insights**: {{gemini_insights}} -{{/if}} - -{{#if is_analysis}} -#### Log Analysis Results - -{{#each results}} -**{{id}}**: {{verdict}} -- Evidence: {{evidence}} -- Reasoning: {{reason}} -{{/each}} - -#### Corrected Understanding - -Previous misunderstandings identified and corrected: - -{{#each corrections}} -- ~~{{wrong}}~~ → {{corrected}} - - Why wrong: {{reason}} - - Evidence: {{evidence}} -{{/each}} - -#### New Insights - -{{#each insights}} -- {{this}} -{{/each}} - -#### Gemini Analysis - -{{gemini_analysis}} -{{/if}} - -{{#if root_cause_found}} -#### Root Cause Identified - -**{{hypothesis_id}}**: {{description}} - -Evidence supporting this conclusion: -{{supporting_evidence}} -{{else}} -#### Next Steps - -{{next_steps}} -{{/if}} - ---- -{{/each}} - -## Current Consolidated Understanding - -### What We Know - -{{#each valid_understandings}} -- {{this}} -{{/each}} - -### What Was Disproven - -{{#each disproven}} -- ~~{{assumption}}~~ (Evidence: {{evidence}}) -{{/each}} - -### Current Investigation Focus - -{{current_focus}} - -### Remaining Questions - -{{#each questions}} -- {{this}} -{{/each}} -``` - -## Template Variables - -| Variable | Type | Source | Description | -|----------|------|--------|-------------| -| `session_id` | string | state.session_id | 会话 ID | -| `bug_description` | string | state.debug.current_bug | Bug 描述 | -| `iterations` | array | 从文件解析 | 迭代历史 | -| `hypotheses` | array | state.debug.hypotheses | 假设列表 | -| `valid_understandings` | array | 从 Gemini 分析 | 有效理解 | -| `disproven` | array | 从假设状态 | 被否定的假设 | - -## Section Templates - -### Exploration Section - -```markdown -### Iteration {{N}} - Initial Exploration ({{timestamp}}) - -#### Current Understanding - -Based on bug description and initial code search: - -- Error pattern: {{pattern}} -- Affected areas: {{areas}} -- Initial hypothesis: {{thoughts}} - -#### Evidence from Code Search - -{{#each search_results}} -**Keyword: "{{keyword}}"** -- Found in: {{files}} -- Key findings: {{insights}} -{{/each}} - -#### Next Steps - -- Generate testable hypotheses -- Add instrumentation -- Await reproduction -``` - -### Hypothesis Section - -```markdown -#### Hypotheses Generated (Gemini-Assisted) - -| ID | Description | Likelihood | Status | -|----|-------------|------------|--------| -{{#each hypotheses}} -| {{id}} | {{description}} | {{likelihood}} | {{status}} | -{{/each}} - -**Details:** - -{{#each hypotheses}} -**{{id}}**: {{description}} -- Logging at: `{{logging_point}}` -- Testing: {{testable_condition}} -- Confirm: {{evidence_criteria.confirm}} -- Reject: {{evidence_criteria.reject}} -{{/each}} -``` - -### Analysis Section - -```markdown -### Iteration {{N}} - Evidence Analysis ({{timestamp}}) - -#### Log Analysis Results - -{{#each results}} -**{{id}}**: **{{verdict}}** -- Evidence: \`{{evidence}}\` -- Reasoning: {{reason}} -{{/each}} - -#### Corrected Understanding - -| Previous Assumption | Corrected To | Reason | -|---------------------|--------------|--------| -{{#each corrections}} -| ~~{{wrong}}~~ | {{corrected}} | {{reason}} | -{{/each}} - -#### Gemini Analysis - -{{gemini_analysis}} -``` - -### Consolidated Understanding Section - -```markdown -## Current Consolidated Understanding - -### What We Know - -{{#each valid}} -- {{this}} -{{/each}} - -### What Was Disproven - -{{#each disproven}} -- ~~{{this.assumption}}~~ (Evidence: {{this.evidence}}) -{{/each}} - -### Current Investigation Focus - -{{focus}} - -### Remaining Questions - -{{#each questions}} -- {{this}} -{{/each}} -``` - -### Resolution Section - -```markdown -### Resolution ({{timestamp}}) - -#### Fix Applied - -- Modified files: {{files}} -- Fix description: {{description}} -- Root cause addressed: {{root_cause}} - -#### Verification Results - -{{verification}} - -#### Lessons Learned - -{{#each lessons}} -{{@index}}. {{this}} -{{/each}} - -#### Key Insights for Future - -{{#each insights}} -- {{this}} -{{/each}} -``` - -## Consolidation Rules - -更新 "Current Consolidated Understanding" 时遵循以下规则: - -1. **简化被否定项**: 移到 "What Was Disproven",只保留单行摘要 -2. **保留有效见解**: 将确认的发现提升到 "What We Know" -3. **避免重复**: 不在合并部分重复时间线细节 -4. **关注当前状态**: 描述现在知道什么,而不是过程 -5. **保留关键纠正**: 保留重要的 wrong→right 转换供学习 - -## Anti-Patterns - -**错误示例 (冗余)**: -```markdown -## Current Consolidated Understanding - -In iteration 1 we thought X, but in iteration 2 we found Y, then in iteration 3... -Also we checked A and found B, and then we checked C... -``` - -**正确示例 (精简)**: -```markdown -## Current Consolidated Understanding - -### What We Know -- Error occurs during runtime update, not initialization -- Config value is None (not missing key) - -### What Was Disproven -- ~~Initialization error~~ (Timing evidence) -- ~~Missing key hypothesis~~ (Key exists) - -### Current Investigation Focus -Why is config value None during update? -``` diff --git a/.claude/skills/ccw-loop/templates/validation-template.md b/.claude/skills/ccw-loop/templates/validation-template.md deleted file mode 100644 index 8c06e6e1..00000000 --- a/.claude/skills/ccw-loop/templates/validation-template.md +++ /dev/null @@ -1,258 +0,0 @@ -# Validation Report Template - -验证报告的标准模板。 - -## Template Structure - -```markdown -# Validation Report - -**Session ID**: {{session_id}} -**Task**: {{task_description}} -**Validated**: {{timestamp}} - ---- - -## Iteration {{iteration}} - Validation Run - -### Test Execution Summary - -| Metric | Value | -|--------|-------| -| Total Tests | {{total_tests}} | -| Passed | {{passed_tests}} | -| Failed | {{failed_tests}} | -| Skipped | {{skipped_tests}} | -| Duration | {{duration}}ms | -| **Pass Rate** | **{{pass_rate}}%** | - -### Coverage Report - -{{#if has_coverage}} -| File | Statements | Branches | Functions | Lines | -|------|------------|----------|-----------|-------| -{{#each coverage_files}} -| {{path}} | {{statements}}% | {{branches}}% | {{functions}}% | {{lines}}% | -{{/each}} - -**Overall Coverage**: {{overall_coverage}}% -{{else}} -_No coverage data available_ -{{/if}} - -### Failed Tests - -{{#if has_failures}} -{{#each failures}} -#### {{test_name}} - -- **Suite**: {{suite}} -- **Error**: {{error_message}} -- **Stack**: -\`\`\` -{{stack_trace}} -\`\`\` -{{/each}} -{{else}} -_All tests passed_ -{{/if}} - -### Gemini Quality Analysis - -{{gemini_analysis}} - -### Recommendations - -{{#each recommendations}} -- {{this}} -{{/each}} - ---- - -## Validation Decision - -**Result**: {{#if passed}}✅ PASS{{else}}❌ FAIL{{/if}} - -**Rationale**: {{rationale}} - -{{#if not_passed}} -### Next Actions - -1. Review failed tests -2. Debug failures using action-debug-with-file -3. Fix issues and re-run validation -{{else}} -### Next Actions - -1. Consider code review -2. Prepare for deployment -3. Update documentation -{{/if}} -``` - -## Template Variables - -| Variable | Type | Source | Description | -|----------|------|--------|-------------| -| `session_id` | string | state.session_id | 会话 ID | -| `task_description` | string | state.task_description | 任务描述 | -| `timestamp` | string | 当前时间 | 验证时间 | -| `iteration` | number | 从文件计算 | 验证迭代次数 | -| `total_tests` | number | 测试输出 | 总测试数 | -| `passed_tests` | number | 测试输出 | 通过数 | -| `failed_tests` | number | 测试输出 | 失败数 | -| `pass_rate` | number | 计算得出 | 通过率 | -| `coverage_files` | array | 覆盖率报告 | 文件覆盖率 | -| `failures` | array | 测试输出 | 失败测试详情 | -| `gemini_analysis` | string | Gemini CLI | 质量分析 | -| `recommendations` | array | Gemini CLI | 建议列表 | - -## Section Templates - -### Test Summary - -```markdown -### Test Execution Summary - -| Metric | Value | -|--------|-------| -| Total Tests | {{total}} | -| Passed | {{passed}} | -| Failed | {{failed}} | -| Skipped | {{skipped}} | -| Duration | {{duration}}ms | -| **Pass Rate** | **{{rate}}%** | -``` - -### Coverage Table - -```markdown -### Coverage Report - -| File | Statements | Branches | Functions | Lines | -|------|------------|----------|-----------|-------| -{{#each files}} -| `{{path}}` | {{statements}}% | {{branches}}% | {{functions}}% | {{lines}}% | -{{/each}} - -**Overall Coverage**: {{overall}}% - -**Coverage Thresholds**: -- ✅ Good: ≥ 80% -- ⚠️ Warning: 60-79% -- ❌ Poor: < 60% -``` - -### Failed Test Details - -```markdown -### Failed Tests - -{{#each failures}} -#### ❌ {{test_name}} - -| Field | Value | -|-------|-------| -| Suite | {{suite}} | -| Error | {{error_message}} | -| Duration | {{duration}}ms | - -**Stack Trace**: -\`\`\` -{{stack_trace}} -\`\`\` - -**Possible Causes**: -{{#each possible_causes}} -- {{this}} -{{/each}} - ---- -{{/each}} -``` - -### Quality Analysis - -```markdown -### Gemini Quality Analysis - -#### Code Quality Assessment - -| Dimension | Score | Status | -|-----------|-------|--------| -| Correctness | {{correctness}}/10 | {{correctness_status}} | -| Completeness | {{completeness}}/10 | {{completeness_status}} | -| Reliability | {{reliability}}/10 | {{reliability_status}} | -| Maintainability | {{maintainability}}/10 | {{maintainability_status}} | - -#### Key Findings - -{{#each findings}} -- **{{severity}}**: {{description}} -{{/each}} - -#### Recommendations - -{{#each recommendations}} -{{@index}}. {{this}} -{{/each}} -``` - -### Decision Section - -```markdown -## Validation Decision - -**Result**: {{#if passed}}✅ PASS{{else}}❌ FAIL{{/if}} - -**Rationale**: -{{rationale}} - -**Confidence Level**: {{confidence}} - -### Decision Matrix - -| Criteria | Status | Weight | Score | -|----------|--------|--------|-------| -| All tests pass | {{tests_pass}} | 40% | {{tests_score}} | -| Coverage ≥ 80% | {{coverage_pass}} | 30% | {{coverage_score}} | -| No critical issues | {{no_critical}} | 20% | {{critical_score}} | -| Quality analysis pass | {{quality_pass}} | 10% | {{quality_score}} | -| **Total** | | 100% | **{{total_score}}** | - -**Threshold**: 70% to pass - -### Next Actions - -{{#if passed}} -1. ✅ Code review (recommended) -2. ✅ Update documentation -3. ✅ Prepare for deployment -{{else}} -1. ❌ Review failed tests -2. ❌ Debug failures -3. ❌ Fix issues and re-run -{{/if}} -``` - -## Historical Comparison - -```markdown -## Validation History - -| Iteration | Date | Pass Rate | Coverage | Status | -|-----------|------|-----------|----------|--------| -{{#each history}} -| {{iteration}} | {{date}} | {{pass_rate}}% | {{coverage}}% | {{status}} | -{{/each}} - -### Trend Analysis - -{{#if improving}} -📈 **Improving**: Pass rate increased from {{previous_rate}}% to {{current_rate}}% -{{else if declining}} -📉 **Declining**: Pass rate decreased from {{previous_rate}}% to {{current_rate}}% -{{else}} -➡️ **Stable**: Pass rate remains at {{current_rate}}% -{{/if}} -``` diff --git a/.claude/skills/prompt-enhancer/SKILL.md b/.claude/skills/prompt-enhancer/SKILL.md deleted file mode 100644 index 348515ce..00000000 --- a/.claude/skills/prompt-enhancer/SKILL.md +++ /dev/null @@ -1,124 +0,0 @@ ---- -name: Prompt Enhancer -description: Transform vague prompts into actionable specs using intelligent analysis and session memory. Use when user input contains -e or --enhance flag. -allowed-tools: (none) ---- - -# Prompt Enhancer - -**Transform**: Vague intent → Structured specification (Memory-based, Direct Output) - -**Languages**: English + Chinese (中英文语义识别) - -## Process (Internal → Direct Output) - -**Internal Analysis**: Intelligently extract session context, identify tech stack, and structure into actionable format. - -**Output**: Direct structured prompt (no intermediate steps shown) - -## Output Format - -**Dynamic Structure**: Adapt fields based on task type and context needs. Not all fields are required. - -**Core Fields** (always present): -- **INTENT**: One-sentence technical goal -- **ACTION**: Concrete steps with technical details - -**Optional Fields** (include when relevant): -- **TECH STACK**: Relevant technologies (when tech-specific) -- **CONTEXT**: Session memory findings (when context matters) -- **ATTENTION**: Critical constraints (when risks/requirements exist) -- **SCOPE**: Affected modules/files (for multi-module tasks) -- **METRICS**: Success criteria (for optimization/performance tasks) -- **DEPENDENCIES**: Related components (for integration tasks) - -**Example (Simple Task)**: -``` -📋 ENHANCED PROMPT - -INTENT: Fix authentication token validation in JWT middleware - -ACTION: -1. Review token expiration logic in auth middleware -2. Add proper error handling for expired tokens -3. Test with valid/expired/malformed tokens -``` - -**Example (Complex Task)**: -``` -📋 ENHANCED PROMPT - -INTENT: Optimize API performance with caching and database indexing - -TECH STACK: -- Redis: Response caching -- PostgreSQL: Query optimization - -CONTEXT: -- API response times >2s mentioned in previous conversation -- PostgreSQL slow query logs show N+1 problems - -ACTION: -1. Profile endpoints to identify slow queries -2. Add PostgreSQL indexes on frequently queried columns -3. Implement Redis caching for read-heavy endpoints -4. Add cache invalidation on data updates - -METRICS: -- Target: <500ms API response time -- Cache hit ratio: >80% - -ATTENTION: -- Maintain backward compatibility with existing API contracts -- Handle cache invalidation correctly to avoid stale data -``` -## Workflow - -``` -Trigger (-e/--enhance) → Internal Analysis → Dynamic Output - ↓ ↓ ↓ - User Input Assess Task Type Select Fields - Extract Memory Context Structure Prompt -``` - -1. **Detect**: User input contains `-e` or `--enhance` -2. **Analyze**: - - Determine task type (fix/optimize/implement/refactor) - - Extract relevant session context - - Identify tech stack and constraints -3. **Structure**: - - Always include: INTENT + ACTION - - Conditionally add: TECH STACK, CONTEXT, ATTENTION, METRICS, etc. -4. **Output**: Present dynamically structured prompt - -## Enhancement Guidelines (Internal) - -**Always Include**: -- Clear, actionable INTENT -- Concrete ACTION steps with technical details - -**Add When Relevant**: -- TECH STACK: Task involves specific technologies -- CONTEXT: Session memory provides useful background -- ATTENTION: Security/compatibility/performance concerns exist -- SCOPE: Multi-module or cross-component changes -- METRICS: Performance/optimization goals need measurement -- DEPENDENCIES: Integration points matter - -**Quality Checks**: -- Make vague intent explicit -- Resolve ambiguous references -- Add testing/validation steps -- Include constraints from memory - -## Best Practices - -- ✅ Trigger only on `-e`/`--enhance` flags -- ✅ Use **dynamic field selection** based on task type -- ✅ Extract **memory context ONLY** (no file reading) -- ✅ Always include INTENT + ACTION as core fields -- ✅ Add optional fields only when relevant to task -- ✅ Direct output (no intermediate steps shown) -- ❌ NO tool calls -- ❌ NO file operations (Bash, Read, Glob, Grep) -- ❌ NO fixed template - adapt to task needs diff --git a/.claude/skills/text-formatter/SKILL.md b/.claude/skills/text-formatter/SKILL.md deleted file mode 100644 index a346b9fc..00000000 --- a/.claude/skills/text-formatter/SKILL.md +++ /dev/null @@ -1,196 +0,0 @@ ---- -name: text-formatter -description: Transform and optimize text content with intelligent formatting. Output BBCode + Markdown hybrid format optimized for forums. Triggers on "format text", "text formatter", "排版", "格式化文本", "BBCode". -allowed-tools: Task, AskUserQuestion, Read, Write, Bash, Glob ---- - -# Text Formatter - -Transform and optimize text content with intelligent structure analysis. Output format: **BBCode + Markdown hybrid** optimized for forum publishing. - -## Architecture Overview - -``` -┌─────────────────────────────────────────────────────────────────┐ -│ Text Formatter Architecture (BBCode + MD Mode) │ -├─────────────────────────────────────────────────────────────────┤ -│ │ -│ Phase 1: Input Collection → 接收文本/文件 │ -│ ↓ │ -│ Phase 2: Content Analysis → 分析结构、识别 Callout/Admonition │ -│ ↓ │ -│ Phase 3: Format Transform → 转换为 BBCode+MD 格式 │ -│ ↓ │ -│ Phase 4: Output & Preview → 保存文件 + 预览 │ -│ │ -└─────────────────────────────────────────────────────────────────┘ -``` - -## Key Design Principles - -1. **Single Format Output**: BBCode + Markdown hybrid (forum optimized) -2. **Pixel-Based Sizing**: size=150/120/100/80 (not 1-7 levels) -3. **Forum Compatibility**: Only use widely-supported BBCode tags -4. **Markdown Separators**: Use `---` for horizontal rules (not `[hr]`) -5. **No Alignment Tags**: `[align]` not supported, avoid usage - ---- - -## Format Specification - -### Supported BBCode Tags - -| Tag | Usage | Example | -|-----|-------|---------| -| `[size=N]` | Font size (pixels) | `[size=120]Title[/size]` | -| `[color=X]` | Text color (hex/name) | `[color=#2196F3]Blue[/color]` 或 `[color=blue]` | -| `[b]` | Bold | `[b]Bold text[/b]` | -| `[i]` | Italic | `[i]Italic[/i]` | -| `[s]` | Strikethrough | `[s]deleted[/s]` | -| `[u]` | Underline | `[u]underlined[/u]` | -| `[quote]` | Quote block | `[quote]Content[/quote]` | -| `[code]` | Code block | `[code]code[/code]` | -| `[img]` | Image | `[img]url[/img]` | -| `[url]` | Link | `[url=link]text[/url]` | -| `[list]` | List container | `[list][*]item[/list]` | -| `[spoiler]` | Collapsible content | `[spoiler=标题]隐藏内容[/spoiler]` | - -### HTML to BBCode Conversion - -| HTML Input | BBCode Output | -|------------|---------------| -| `高亮` | `[color=yellow]高亮[/color]` | -| `下划线` | `[u]下划线[/u]` | -| `
标题内容
` | `[spoiler=标题]内容[/spoiler]` | - -### Unsupported Tags (Avoid!) - -| Tag | Reason | Alternative | -|-----|--------|-------------| -| `[align]` | Not rendered | Remove or use default left | -| `[hr]` | Shows as text | Use Markdown `---` | -| `
` | HTML not supported | Use BBCode only | -| `[table]` | Limited support | Use list or code block | - -### Size Hierarchy (Pixels) - -| Element | Size | Color | Usage | -|---------|------|-------|-------| -| **Main Title** | 150 | #2196F3 | Document title | -| **Section Title** | 120 | #2196F3 | Major sections (## H2) | -| **Subsection** | 100 | #333 | Sub-sections (### H3) | -| **Normal Text** | (default) | - | Body content | -| **Notes/Gray** | 80 | gray | Footnotes, metadata | - -### Color Palette - -| Color | Hex | Semantic Usage | -|-------|-----|----------------| -| **Blue** | #2196F3 | Titles, links, info | -| **Green** | #4CAF50 | Success, tips, features | -| **Orange** | #FF9800 | Warnings, caution | -| **Red** | #F44336 | Errors, danger, important | -| **Purple** | #9C27B0 | Examples, code | -| **Gray** | gray | Notes, metadata | - ---- - -## Mandatory Prerequisites - -> Read before execution: - -| Document | Purpose | Priority | -|----------|---------|----------| -| [specs/format-rules.md](specs/format-rules.md) | Format conversion rules | **P0** | -| [specs/element-mapping.md](specs/element-mapping.md) | Element type mappings | P1 | -| [specs/callout-types.md](specs/callout-types.md) | Callout/Admonition types | P1 | - ---- - -## Execution Flow - -``` -┌────────────────────────────────────────────────────────────────┐ -│ Phase 1: Input Collection │ -│ - Ask: paste text OR file path │ -│ - Output: input-config.json │ -├────────────────────────────────────────────────────────────────┤ -│ Phase 2: Content Analysis │ -│ - Detect structure: headings, lists, code blocks, tables │ -│ - Identify Callouts/Admonitions (>[!type]) │ -│ - Output: analysis.json │ -├────────────────────────────────────────────────────────────────┤ -│ Phase 3: Format Transform │ -│ - Apply BBCode + MD rules from specs/format-rules.md │ -│ - Convert elements with pixel-based sizes │ -│ - Use Markdown --- for separators │ -│ - Output: formatted content │ -├────────────────────────────────────────────────────────────────┤ -│ Phase 4: Output & Preview │ -│ - Save to .bbcode.txt file │ -│ - Display preview │ -│ - Output: final file │ -└────────────────────────────────────────────────────────────────┘ -``` - -## Callout/Admonition Support - -支持 Obsidian 风格的 Callout 语法,转换为 BBCode quote: - -```markdown -> [!NOTE] -> 这是一个提示信息 - -> [!WARNING] -> 这是一个警告信息 -``` - -转换结果: - -```bbcode -[quote] -[size=100][color=#2196F3][b]📝 注意[/b][/color][/size] - -这是一个提示信息 -[/quote] -``` - -| Type | Color | Icon | -|------|-------|------| -| NOTE/INFO | #2196F3 | 📝 | -| TIP/HINT | #4CAF50 | 💡 | -| SUCCESS | #4CAF50 | ✅ | -| WARNING/CAUTION | #FF9800 | ⚠️ | -| DANGER/ERROR | #F44336 | ❌ | -| EXAMPLE | #9C27B0 | 📋 | - -## Directory Setup - -```javascript -const timestamp = new Date().toISOString().slice(0,10).replace(/-/g, ''); -const workDir = `.workflow/.scratchpad/text-formatter-${timestamp}`; - -Bash(`mkdir -p "${workDir}"`); -``` - -## Output Structure - -``` -.workflow/.scratchpad/text-formatter-{date}/ -├── input-config.json # 输入配置 -├── analysis.json # 内容分析结果 -└── output.bbcode.txt # BBCode+MD 输出 -``` - -## Reference Documents - -| Document | Purpose | -|----------|---------| -| [phases/01-input-collection.md](phases/01-input-collection.md) | 收集输入内容 | -| [phases/02-content-analysis.md](phases/02-content-analysis.md) | 分析内容结构 | -| [phases/03-format-transform.md](phases/03-format-transform.md) | 格式转换 | -| [phases/04-output-preview.md](phases/04-output-preview.md) | 输出和预览 | -| [specs/format-rules.md](specs/format-rules.md) | 格式转换规则 | -| [specs/element-mapping.md](specs/element-mapping.md) | 元素映射表 | -| [specs/callout-types.md](specs/callout-types.md) | Callout 类型定义 | -| [templates/bbcode-template.md](templates/bbcode-template.md) | BBCode 模板 | diff --git a/.claude/skills/text-formatter/phases/01-input-collection.md b/.claude/skills/text-formatter/phases/01-input-collection.md deleted file mode 100644 index 2b48c8da..00000000 --- a/.claude/skills/text-formatter/phases/01-input-collection.md +++ /dev/null @@ -1,111 +0,0 @@ -# Phase 1: Input Collection - -收集用户输入的文本内容。 - -## Objective - -- 获取用户输入内容(直接粘贴或文件路径) -- 生成输入配置文件 - -**注意**: 输出格式固定为 BBCode + Markdown 混合格式(论坛优化),无需选择。 - -## Input - -- 来源: 用户交互 -- 配置: 无前置依赖 - -## Execution Steps - -### Step 1: 询问输入方式 - -```javascript -const inputMethod = await AskUserQuestion({ - questions: [ - { - question: "请选择输入方式", - header: "输入方式", - multiSelect: false, - options: [ - { label: "直接粘贴文本", description: "在对话中粘贴要格式化的内容" }, - { label: "指定文件路径", description: "读取指定文件的内容" } - ] - } - ] -}); -``` - -### Step 2: 获取内容 - -```javascript -let content = ''; - -if (inputMethod["输入方式"] === "直接粘贴文本") { - // 提示用户粘贴内容 - const textInput = await AskUserQuestion({ - questions: [ - { - question: "请粘贴要格式化的文本内容(粘贴后选择确认)", - header: "文本内容", - multiSelect: false, - options: [ - { label: "已粘贴完成", description: "确认已在上方粘贴内容" } - ] - } - ] - }); - // 从用户消息中提取文本内容 - content = extractUserText(); -} else { - // 询问文件路径 - const filePath = await AskUserQuestion({ - questions: [ - { - question: "请输入文件路径", - header: "文件路径", - multiSelect: false, - options: [ - { label: "已输入路径", description: "确认路径已在上方输入" } - ] - } - ] - }); - content = Read(extractedFilePath); -} -``` - -### Step 3: 保存配置 - -```javascript -const config = { - input_method: inputMethod["输入方式"], - target_format: "BBCode+MD", // 固定格式 - original_content: content, - timestamp: new Date().toISOString() -}; - -Write(`${workDir}/input-config.json`, JSON.stringify(config, null, 2)); -``` - -## Output - -- **File**: `input-config.json` -- **Format**: JSON - -```json -{ - "input_method": "直接粘贴文本", - "target_format": "BBCode+MD", - "original_content": "...", - "timestamp": "2026-01-13T..." -} -``` - -## Quality Checklist - -- [ ] 成功获取用户输入内容 -- [ ] 内容非空且有效 -- [ ] 配置文件已保存 - -## Next Phase - -→ [Phase 2: Content Analysis](02-content-analysis.md) diff --git a/.claude/skills/text-formatter/phases/02-content-analysis.md b/.claude/skills/text-formatter/phases/02-content-analysis.md deleted file mode 100644 index 34d86729..00000000 --- a/.claude/skills/text-formatter/phases/02-content-analysis.md +++ /dev/null @@ -1,248 +0,0 @@ -# Phase 2: Content Analysis - -分析输入内容的结构和语义元素。 - -## Objective - -- 识别内容结构(标题、段落、列表等) -- 检测特殊元素(代码块、表格、链接等) -- 生成结构化分析结果 - -## Input - -- 依赖: `input-config.json` -- 配置: `{workDir}/input-config.json` - -## Execution Steps - -### Step 1: 加载输入 - -```javascript -const config = JSON.parse(Read(`${workDir}/input-config.json`)); -const content = config.original_content; -``` - -### Step 2: 结构分析 - -```javascript -function analyzeStructure(text) { - const analysis = { - elements: [], - stats: { - headings: 0, - paragraphs: 0, - lists: 0, - code_blocks: 0, - tables: 0, - links: 0, - images: 0, - quotes: 0, - callouts: 0 - } - }; - - // Callout 检测正则 (Obsidian 风格) - const CALLOUT_PATTERN = /^>\s*\[!(\w+)\](?:\s+(.+))?$/; - - const lines = text.split('\n'); - let currentElement = null; - let inCodeBlock = false; - let inList = false; - - for (let i = 0; i < lines.length; i++) { - const line = lines[i]; - - // 检测代码块 - if (line.match(/^```/)) { - inCodeBlock = !inCodeBlock; - if (inCodeBlock) { - analysis.elements.push({ - type: 'code_block', - start: i, - language: line.replace(/^```/, '').trim() - }); - analysis.stats.code_blocks++; - } - continue; - } - - if (inCodeBlock) continue; - - // 检测标题 (Markdown 或纯文本模式) - if (line.match(/^#{1,6}\s/)) { - const level = line.match(/^(#+)/)[1].length; - analysis.elements.push({ - type: 'heading', - level: level, - content: line.replace(/^#+\s*/, ''), - line: i - }); - analysis.stats.headings++; - continue; - } - - // 检测列表 - if (line.match(/^[\s]*[-*+]\s/) || line.match(/^[\s]*\d+\.\s/)) { - if (!inList) { - analysis.elements.push({ - type: 'list', - start: i, - ordered: line.match(/^\d+\./) !== null - }); - analysis.stats.lists++; - inList = true; - } - continue; - } else { - inList = false; - } - - // 检测 Callout (Obsidian 风格) - 优先于普通引用 - const calloutMatch = line.match(CALLOUT_PATTERN); - if (calloutMatch) { - const calloutType = calloutMatch[1].toLowerCase(); - const calloutTitle = calloutMatch[2] || null; - // 收集 Callout 内容行 - const calloutContent = []; - let j = i + 1; - while (j < lines.length && lines[j].startsWith('>')) { - calloutContent.push(lines[j].replace(/^>\s*/, '')); - j++; - } - analysis.elements.push({ - type: 'callout', - calloutType: calloutType, - title: calloutTitle, - content: calloutContent.join('\n'), - start: i, - end: j - 1 - }); - analysis.stats.callouts++; - i = j - 1; // 跳过已处理的行 - continue; - } - - // 检测普通引用 - if (line.match(/^>\s/)) { - analysis.elements.push({ - type: 'quote', - content: line.replace(/^>\s*/, ''), - line: i - }); - analysis.stats.quotes++; - continue; - } - - // 检测表格 - if (line.match(/^\|.*\|$/)) { - analysis.elements.push({ - type: 'table_row', - line: i - }); - if (!analysis.elements.find(e => e.type === 'table')) { - analysis.stats.tables++; - } - continue; - } - - // 检测链接 - const links = line.match(/\[([^\]]+)\]\(([^)]+)\)/g); - if (links) { - analysis.stats.links += links.length; - } - - // 检测图片 - const images = line.match(/!\[([^\]]*)\]\(([^)]+)\)/g); - if (images) { - analysis.stats.images += images.length; - } - - // 普通段落 - if (line.trim() && !line.match(/^[-=]{3,}$/)) { - analysis.elements.push({ - type: 'paragraph', - line: i, - preview: line.substring(0, 50) - }); - analysis.stats.paragraphs++; - } - } - - return analysis; -} - -const analysis = analyzeStructure(content); -``` - -### Step 3: 语义增强 - -```javascript -// 识别特殊语义 -function enhanceSemantics(text, analysis) { - const enhanced = { ...analysis }; - - // 检测关键词强调 - const boldPatterns = text.match(/\*\*[^*]+\*\*/g) || []; - const italicPatterns = text.match(/\*[^*]+\*/g) || []; - - enhanced.semantics = { - emphasis: { - bold: boldPatterns.length, - italic: italicPatterns.length - }, - estimated_reading_time: Math.ceil(text.split(/\s+/).length / 200) // 200 words/min - }; - - return enhanced; -} - -const enhancedAnalysis = enhanceSemantics(content, analysis); -``` - -### Step 4: 保存分析结果 - -```javascript -Write(`${workDir}/analysis.json`, JSON.stringify(enhancedAnalysis, null, 2)); -``` - -## Output - -- **File**: `analysis.json` -- **Format**: JSON - -```json -{ - "elements": [ - { "type": "heading", "level": 1, "content": "Title", "line": 0 }, - { "type": "paragraph", "line": 2, "preview": "..." }, - { "type": "callout", "calloutType": "warning", "title": "注意事项", "content": "...", "start": 4, "end": 6 }, - { "type": "code_block", "start": 8, "language": "javascript" } - ], - "stats": { - "headings": 3, - "paragraphs": 10, - "lists": 2, - "code_blocks": 1, - "tables": 0, - "links": 5, - "images": 0, - "quotes": 1, - "callouts": 2 - }, - "semantics": { - "emphasis": { "bold": 5, "italic": 3 }, - "estimated_reading_time": 2 - } -} -``` - -## Quality Checklist - -- [ ] 所有结构元素已识别 -- [ ] 统计信息准确 -- [ ] 语义增强完成 -- [ ] 分析文件已保存 - -## Next Phase - -→ [Phase 3: Format Transform](03-format-transform.md) diff --git a/.claude/skills/text-formatter/phases/03-format-transform.md b/.claude/skills/text-formatter/phases/03-format-transform.md deleted file mode 100644 index 3a46d8ef..00000000 --- a/.claude/skills/text-formatter/phases/03-format-transform.md +++ /dev/null @@ -1,245 +0,0 @@ -# Phase 3: Format Transform - -将内容转换为 BBCode + Markdown 混合格式(论坛优化)。 - -## Objective - -- 根据分析结果转换内容 -- 应用像素级字号规则 -- 处理 Callout/标注语法 -- 生成论坛兼容的输出 - -## Input - -- 依赖: `input-config.json`, `analysis.json` -- 规范: `specs/format-rules.md`, `specs/element-mapping.md` - -## Format Specification - -### Size Hierarchy (Pixels) - -| Element | Size | Color | Usage | -|---------|------|-------|-------| -| **H1** | 150 | #2196F3 | 文档主标题 | -| **H2** | 120 | #2196F3 | 章节标题 | -| **H3** | 100 | #333 | 子标题 | -| **H4+** | (默认) | - | 仅加粗 | -| **Notes** | 80 | gray | 备注/元数据 | - -### Unsupported Tags (禁止使用) - -| Tag | Reason | Alternative | -|-----|--------|-------------| -| `[align]` | 不渲染 | 删除,使用默认左对齐 | -| `[hr]` | 显示为文本 | 使用 Markdown `---` | -| `[table]` | 支持有限 | 转为列表或代码块 | -| HTML tags | 不支持 | 仅使用 BBCode | - -## Execution Steps - -### Step 1: 加载配置和分析 - -```javascript -const config = JSON.parse(Read(`${workDir}/input-config.json`)); -const analysis = JSON.parse(Read(`${workDir}/analysis.json`)); -const content = config.original_content; -``` - -### Step 2: Callout 配置 - -```javascript -// Callout 类型映射(像素级字号) -const CALLOUT_CONFIG = { - // 信息类 - note: { icon: '📝', color: '#2196F3', label: '注意' }, - info: { icon: 'ℹ️', color: '#2196F3', label: '信息' }, - abstract: { icon: '📄', color: '#2196F3', label: '摘要' }, - summary: { icon: '📄', color: '#2196F3', label: '摘要' }, - tldr: { icon: '📄', color: '#2196F3', label: '摘要' }, - - // 成功/提示类 - tip: { icon: '💡', color: '#4CAF50', label: '提示' }, - hint: { icon: '💡', color: '#4CAF50', label: '提示' }, - success: { icon: '✅', color: '#4CAF50', label: '成功' }, - check: { icon: '✅', color: '#4CAF50', label: '完成' }, - done: { icon: '✅', color: '#4CAF50', label: '完成' }, - - // 警告类 - warning: { icon: '⚠️', color: '#FF9800', label: '警告' }, - caution: { icon: '⚠️', color: '#FF9800', label: '注意' }, - attention: { icon: '⚠️', color: '#FF9800', label: '注意' }, - question: { icon: '❓', color: '#FF9800', label: '问题' }, - help: { icon: '❓', color: '#FF9800', label: '帮助' }, - faq: { icon: '❓', color: '#FF9800', label: 'FAQ' }, - todo: { icon: '📋', color: '#FF9800', label: '待办' }, - - // 错误/危险类 - danger: { icon: '❌', color: '#F44336', label: '危险' }, - error: { icon: '❌', color: '#F44336', label: '错误' }, - bug: { icon: '🐛', color: '#F44336', label: 'Bug' }, - important: { icon: '⭐', color: '#F44336', label: '重要' }, - - // 其他 - example: { icon: '📋', color: '#9C27B0', label: '示例' }, - quote: { icon: '💬', color: 'gray', label: '引用' }, - cite: { icon: '💬', color: 'gray', label: '引用' } -}; - -// Callout 检测正则 (支持 +/- 折叠标记) -const CALLOUT_PATTERN = /^>\s*\[!(\w+)\][+-]?(?:\s+(.+))?$/; -``` - -### Step 3: Callout 解析器 - -```javascript -function parseCallouts(text) { - const lines = text.split('\n'); - const result = []; - let i = 0; - - while (i < lines.length) { - const match = lines[i].match(CALLOUT_PATTERN); - if (match) { - const type = match[1].toLowerCase(); - const title = match[2] || null; - const content = []; - i++; - - // 收集 Callout 内容行 - while (i < lines.length && lines[i].startsWith('>')) { - content.push(lines[i].replace(/^>\s*/, '')); - i++; - } - - result.push({ - isCallout: true, - type, - title, - content: content.join('\n') - }); - } else { - result.push({ isCallout: false, line: lines[i] }); - i++; - } - } - - return result; -} -``` - -### Step 4: BBCode+MD 转换器 - -```javascript -function formatBBCodeMD(text) { - let result = text; - - // ===== 标题转换 (像素级字号) ===== - result = result.replace(/^######\s*(.+)$/gm, '[b]$1[/b]'); - result = result.replace(/^#####\s*(.+)$/gm, '[b]$1[/b]'); - result = result.replace(/^####\s*(.+)$/gm, '[b]$1[/b]'); - result = result.replace(/^###\s*(.+)$/gm, '[size=100][color=#333][b]$1[/b][/color][/size]'); - result = result.replace(/^##\s*(.+)$/gm, '[size=120][color=#2196F3][b]$1[/b][/color][/size]'); - result = result.replace(/^#\s*(.+)$/gm, '[size=150][color=#2196F3][b]$1[/b][/color][/size]'); - - // ===== 文本样式 ===== - result = result.replace(/\*\*\*(.+?)\*\*\*/g, '[b][i]$1[/i][/b]'); - result = result.replace(/\*\*(.+?)\*\*/g, '[b]$1[/b]'); - result = result.replace(/__(.+?)__/g, '[b]$1[/b]'); - result = result.replace(/\*(.+?)\*/g, '[i]$1[/i]'); - result = result.replace(/_(.+?)_/g, '[i]$1[/i]'); - result = result.replace(/~~(.+?)~~/g, '[s]$1[/s]'); - result = result.replace(/==(.+?)==/g, '[color=yellow]$1[/color]'); - - // ===== HTML 转 BBCode ===== - result = result.replace(/(.+?)<\/mark>/g, '[color=yellow]$1[/color]'); - result = result.replace(/(.+?)<\/u>/g, '[u]$1[/u]'); - result = result.replace(/
\s*(.+?)<\/summary>\s*([\s\S]*?)<\/details>/g, - '[spoiler=$1]$2[/spoiler]'); - - // ===== 代码 ===== - result = result.replace(/```(\w*)\n([\s\S]*?)```/g, '[code]$2[/code]'); - // 行内代码保持原样 (部分论坛不支持 font=monospace) - - // ===== 链接和图片 ===== - result = result.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '[url=$2]$1[/url]'); - result = result.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, '[img]$2[/img]'); - - // ===== 引用 (非 Callout) ===== - result = result.replace(/^>\s+(.+)$/gm, '[quote]$1[/quote]'); - - // ===== 列表 (使用 • 符号) ===== - result = result.replace(/^[-*+]\s+(.+)$/gm, '• $1'); - - // ===== 分隔线 (保持 Markdown 语法) ===== - // `---` 在混合格式中通常可用,不转换为 [hr] - - return result.trim(); -} -``` - -### Step 5: Callout 转换 - -```javascript -function convertCallouts(text) { - const parsed = parseCallouts(text); - - return parsed.map(item => { - if (item.isCallout) { - const cfg = CALLOUT_CONFIG[item.type] || CALLOUT_CONFIG.note; - const displayTitle = item.title || cfg.label; - - // 使用 [quote] 包裹,标题使用 size=100 - return `[quote] -[size=100][color=${cfg.color}][b]${cfg.icon} ${displayTitle}[/b][/color][/size] - -${item.content} -[/quote]`; - } - return item.line; - }).join('\n'); -} -``` - -### Step 6: 执行转换 - -```javascript -// 1. 先处理 Callouts -let formattedContent = convertCallouts(content); - -// 2. 再进行通用 BBCode+MD 转换 -formattedContent = formatBBCodeMD(formattedContent); - -// 3. 清理多余空行 -formattedContent = formattedContent.replace(/\n{3,}/g, '\n\n'); -``` - -### Step 7: 保存转换结果 - -```javascript -const outputFile = 'output.bbcode.txt'; -Write(`${workDir}/${outputFile}`, formattedContent); - -// 更新配置 -config.output_file = outputFile; -config.formatted_content = formattedContent; -Write(`${workDir}/input-config.json`, JSON.stringify(config, null, 2)); -``` - -## Output - -- **File**: `output.bbcode.txt` -- **Format**: BBCode + Markdown 混合格式 - -## Quality Checklist - -- [ ] 标题使用像素值 (150/120/100) -- [ ] 未使用 `[align]` 标签 -- [ ] 未使用 `[hr]` 标签 -- [ ] 分隔线使用 `---` -- [ ] Callout 正确转换为 [quote] -- [ ] 颜色值使用 hex 格式 -- [ ] 内容完整无丢失 - -## Next Phase - -→ [Phase 4: Output & Preview](04-output-preview.md) diff --git a/.claude/skills/text-formatter/phases/04-output-preview.md b/.claude/skills/text-formatter/phases/04-output-preview.md deleted file mode 100644 index 5a27a43f..00000000 --- a/.claude/skills/text-formatter/phases/04-output-preview.md +++ /dev/null @@ -1,183 +0,0 @@ -# Phase 4: Output & Preview - -输出最终结果并提供预览。 - -## Objective - -- 保存格式化后的内容到文件 -- 提供预览功能 -- 显示转换统计信息 - -## Input - -- 依赖: `input-config.json`, `output.*` -- 配置: `{workDir}/input-config.json` - -## Execution Steps - -### Step 1: 加载结果 - -```javascript -const config = JSON.parse(Read(`${workDir}/input-config.json`)); -const analysis = JSON.parse(Read(`${workDir}/analysis.json`)); -const outputFile = `${workDir}/${config.output_file}`; -const formattedContent = Read(outputFile); -``` - -### Step 2: 生成统计摘要 - -```javascript -const summary = { - input: { - method: config.input_method, - original_length: config.original_content.length, - word_count: config.original_content.split(/\s+/).length - }, - output: { - format: config.target_format, - file: outputFile, - length: formattedContent.length - }, - elements: analysis.stats, - reading_time: analysis.semantics?.estimated_reading_time || 1 -}; - -console.log(` -╔════════════════════════════════════════════════════════════════╗ -║ Text Formatter Summary ║ -╠════════════════════════════════════════════════════════════════╣ -║ Input: ${summary.input.word_count} words (${summary.input.original_length} chars) -║ Output: ${summary.output.format} → ${summary.output.file} -║ Elements Converted: -║ • Headings: ${summary.elements.headings} -║ • Paragraphs: ${summary.elements.paragraphs} -║ • Lists: ${summary.elements.lists} -║ • Code Blocks: ${summary.elements.code_blocks} -║ • Links: ${summary.elements.links} -║ Estimated Reading Time: ${summary.reading_time} min -╚════════════════════════════════════════════════════════════════╝ -`); -``` - -### Step 3: HTML 预览(如适用) - -```javascript -if (config.target_format === 'HTML') { - // 生成完整 HTML 文件用于预览 - const previewHtml = ` - - - - - Text Formatter Preview - - - -
- ${formattedContent} -
- -`; - - Write(`${workDir}/preview.html`, previewHtml); - - // 可选:在浏览器中打开预览 - // Bash(`start "${workDir}/preview.html"`); // Windows - // Bash(`open "${workDir}/preview.html"`); // macOS -} -``` - -### Step 4: 显示输出内容 - -```javascript -// 显示格式化后的内容 -console.log('\n=== Formatted Content ===\n'); -console.log(formattedContent); -console.log('\n=========================\n'); - -// 提示用户 -console.log(` -📁 Output saved to: ${outputFile} -${config.target_format === 'HTML' ? '🌐 Preview available: ' + workDir + '/preview.html' : ''} - -💡 Tips: -- Copy the content above for immediate use -- Or access the saved file at the path shown -`); -``` - -### Step 5: 询问后续操作 - -```javascript -const nextAction = await AskUserQuestion({ - questions: [ - { - question: "需要执行什么操作?", - header: "后续操作", - multiSelect: false, - options: [ - { label: "完成", description: "结束格式化流程" }, - { label: "转换为其他格式", description: "选择另一种输出格式" }, - { label: "重新编辑", description: "修改原始内容后重新格式化" } - ] - } - ] -}); - -if (nextAction["后续操作"] === "转换为其他格式") { - // 返回 Phase 1 选择新格式 - console.log('请重新运行 /text-formatter 选择其他格式'); -} -``` - -## Output - -- **File**: `output.{ext}` (最终输出) -- **File**: `preview.html` (HTML 预览,仅 HTML 格式) -- **Console**: 统计摘要和格式化内容 - -## Final Output Structure - -``` -{workDir}/ -├── input-config.json # 配置信息 -├── analysis.json # 分析结果 -├── output.md # Markdown 输出(如选择) -├── output.bbcode.txt # BBCode 输出(如选择) -├── output.html # HTML 输出(如选择) -└── preview.html # HTML 预览页面 -``` - -## Quality Checklist - -- [ ] 输出文件已保存 -- [ ] 统计信息正确显示 -- [ ] 预览功能可用(HTML) -- [ ] 用户可访问输出内容 - -## Completion - -此为最终阶段,格式化流程完成。 diff --git a/.claude/skills/text-formatter/specs/callout-types.md b/.claude/skills/text-formatter/specs/callout-types.md deleted file mode 100644 index 0647b2a1..00000000 --- a/.claude/skills/text-formatter/specs/callout-types.md +++ /dev/null @@ -1,293 +0,0 @@ -# Callout Types - -Obsidian 风格的 Callout/Admonition 类型定义和转换规则。 - -## When to Use - -| Phase | Usage | Section | -|-------|-------|---------| -| Phase 2 | 检测 Callout | Detection patterns | -| Phase 3 | 格式转换 | Conversion rules | - ---- - -## Callout 语法 - -### Obsidian 原生语法 - -```markdown -> [!TYPE] 可选标题 -> 内容行1 -> 内容行2 -``` - -### 支持的类型 - -| Type | Alias | Icon | Color | 用途 | -|------|-------|------|-------|------| -| `note` | - | 📝 | blue | 普通提示 | -| `info` | - | ℹ️ | blue | 信息说明 | -| `tip` | `hint` | 💡 | green | 技巧提示 | -| `success` | `check`, `done` | ✅ | green | 成功状态 | -| `warning` | `caution`, `attention` | ⚠️ | orange | 警告信息 | -| `danger` | `error` | ❌ | red | 危险/错误 | -| `bug` | - | 🐛 | red | Bug 说明 | -| `example` | - | 📋 | purple | 示例内容 | -| `quote` | `cite` | 💬 | gray | 引用内容 | -| `abstract` | `summary`, `tldr` | 📄 | cyan | 摘要 | -| `question` | `help`, `faq` | ❓ | yellow | 问题/FAQ | -| `todo` | - | 📌 | orange | 待办事项 | - ---- - -## 检测 Pattern - -```javascript -// Callout 检测正则 -const CALLOUT_PATTERN = /^>\s*\[!(\w+)\](?:\s+(.+))?$/; - -// 检测函数 -function detectCallout(line) { - const match = line.match(CALLOUT_PATTERN); - if (match) { - return { - type: match[1].toLowerCase(), - title: match[2] || null - }; - } - return null; -} - -// 解析完整 Callout 块 -function parseCalloutBlock(lines, startIndex) { - const firstLine = lines[startIndex]; - const calloutInfo = detectCallout(firstLine); - - if (!calloutInfo) return null; - - const content = []; - let i = startIndex + 1; - - while (i < lines.length && lines[i].startsWith('>')) { - content.push(lines[i].replace(/^>\s*/, '')); - i++; - } - - return { - ...calloutInfo, - content: content.join('\n'), - endIndex: i - 1 - }; -} -``` - ---- - -## 转换规则 - -### BBCode 转换 - -```javascript -const CALLOUT_BBCODE = { - note: { - icon: '📝', - color: '#2196F3', - label: '注意' - }, - info: { - icon: 'ℹ️', - color: '#2196F3', - label: '信息' - }, - tip: { - icon: '💡', - color: '#4CAF50', - label: '提示' - }, - success: { - icon: '✅', - color: '#4CAF50', - label: '成功' - }, - warning: { - icon: '⚠️', - color: '#FF9800', - label: '警告' - }, - danger: { - icon: '❌', - color: '#F44336', - label: '危险' - }, - bug: { - icon: '🐛', - color: '#F44336', - label: 'Bug' - }, - example: { - icon: '📋', - color: '#9C27B0', - label: '示例' - }, - quote: { - icon: '💬', - color: '#9E9E9E', - label: '引用' - }, - question: { - icon: '❓', - color: '#FFEB3B', - label: '问题' - } -}; - -function calloutToBBCode(type, title, content, style = 'forum') { - const config = CALLOUT_BBCODE[type] || CALLOUT_BBCODE.note; - const displayTitle = title || config.label; - - if (style === 'compact') { - return `[quote][b]${config.icon} ${displayTitle}[/b] -${content}[/quote]`; - } - - // Forum style - more visual - return `[quote] -[color=${config.color}][size=4][b]${config.icon} ${displayTitle}[/b][/size][/color] - -${content} -[/quote]`; -} -``` - -### HTML 转换 - -```javascript -function calloutToHTML(type, title, content) { - const config = CALLOUT_BBCODE[type] || CALLOUT_BBCODE.note; - const displayTitle = title || config.label; - - return `
-
- ${config.icon} - ${displayTitle} -
-
- ${content} -
-
`; -} -``` - -### Hybrid 转换 - -```javascript -function calloutToHybrid(type, title, content) { - const config = CALLOUT_BBCODE[type] || CALLOUT_BBCODE.note; - const displayTitle = title || config.label; - - // HTML container + BBCode styling + MD content - return `
- -[color=${config.color}][b]${config.icon} ${displayTitle}[/b][/color] - -${content} - -
`; -} -``` - ---- - -## Callout CSS 样式 - -```css -/* Base callout styles */ -.callout { - padding: 1rem; - margin: 1rem 0; - border-left: 4px solid; - border-radius: 4px; - background: #f8f9fa; -} - -.callout-title { - display: flex; - align-items: center; - gap: 0.5rem; - font-weight: 600; - margin-bottom: 0.5rem; -} - -.callout-icon { - font-size: 1.2em; -} - -/* Type-specific colors */ -.callout-note, .callout-info { - border-color: #2196F3; - background: #E3F2FD; -} - -.callout-tip, .callout-success { - border-color: #4CAF50; - background: #E8F5E9; -} - -.callout-warning { - border-color: #FF9800; - background: #FFF3E0; -} - -.callout-danger, .callout-bug { - border-color: #F44336; - background: #FFEBEE; -} - -.callout-example { - border-color: #9C27B0; - background: #F3E5F5; -} - -.callout-quote { - border-color: #9E9E9E; - background: #FAFAFA; -} - -.callout-question { - border-color: #FFC107; - background: #FFFDE7; -} -``` - ---- - -## 折叠 Callout - -支持可折叠的 Callout 语法: - -```markdown -> [!NOTE]+ 默认展开 -> 内容 - -> [!NOTE]- 默认折叠 -> 内容 -``` - -### BBCode 折叠 - -```bbcode -[collapse=📝 注意] -内容 -[/collapse] -``` - -### HTML 折叠 - -```html -
- 📝 注意 -
- 内容 -
-
-``` diff --git a/.claude/skills/text-formatter/specs/element-mapping.md b/.claude/skills/text-formatter/specs/element-mapping.md deleted file mode 100644 index 8bf3d51e..00000000 --- a/.claude/skills/text-formatter/specs/element-mapping.md +++ /dev/null @@ -1,226 +0,0 @@ -# Element Mapping - -内容元素到 BBCode + Markdown 混合格式的映射表。 - -## When to Use - -| Phase | Usage | Section | -|-------|-------|---------| -| Phase 2 | 元素识别 | Detection patterns | -| Phase 3 | 格式转换 | Conversion rules | - ---- - -## Element Detection Patterns - -### 标题检测 - -| 类型 | Pattern | 示例 | -|------|---------|------| -| ATX 标题 | `/^#{1,6}\s+(.+)$/` | `# Title`, `## Subtitle` | -| Setext H1 | `/^(.+)\n={3,}$/` | `Title\n====` | -| Setext H2 | `/^(.+)\n-{3,}$/` | `Subtitle\n----` | - -### 列表检测 - -| 类型 | Pattern | 示例 | -|------|---------|------| -| 无序列表 | `/^[\s]*[-*+]\s+(.+)$/` | `- item`, `* item` | -| 有序列表 | `/^[\s]*\d+\.\s+(.+)$/` | `1. item`, `2. item` | -| 任务列表 | `/^[\s]*[-*]\s+\[([ x])\]\s+(.+)$/` | `- [ ] todo`, `- [x] done` | - -### Callout 检测 - -| 类型 | Pattern | 示例 | -|------|---------|------| -| Callout 开始 | `/^>\s*\[!(\w+)\](?:\s+(.+))?$/` | `> [!NOTE] 标题` | -| Callout 内容 | `/^>\s*(.*)$/` | `> 内容行` | -| 可折叠展开 | `/^>\s*\[!(\w+)\]\+/` | `> [!NOTE]+` | -| 可折叠收起 | `/^>\s*\[!(\w+)\]-/` | `> [!NOTE]-` | - -### 代码检测 - -| 类型 | Pattern | 示例 | -|------|---------|------| -| 代码块开始 | `/^```(\w*)$/` | ` ```js ` | -| 代码块结束 | `/^```$/` | ` ``` ` | -| 行内代码 | `/`([^`]+)`/` | `` `code` `` | - -### 其他元素 - -| 类型 | Pattern | 示例 | -|------|---------|------| -| 链接 | `/\[([^\]]+)\]\(([^)]+)\)/` | `[text](url)` | -| 图片 | `/!\[([^\]]*)\]\(([^)]+)\)/` | `![alt](url)` | -| 普通引用 | `/^>\s+(.+)$/` | `> quote` | -| 分隔线 | `/^[-*_]{3,}$/` | `---`, `***` | -| 高亮 | `/==(.+?)==/` | `==highlight==` | -| 粗体 | `/\*\*(.+?)\*\*/` | `**bold**` | -| 斜体 | `/\*(.+?)\*/` | `*italic*` | -| 删除线 | `/~~(.+?)~~/` | `~~strike~~` | - -### HTML 元素检测 - -| 类型 | Pattern | 示例 | -|------|---------|------| -| 高亮 | `/(.+?)<\/mark>/` | `高亮` | -| 折叠块 | `/
\s*(.+?)<\/summary>([\s\S]*?)<\/details>/` | `
标题内容
` | -| 下划线 | `/(.+?)<\/u>/` | `下划线` | - ---- - -## Element Conversion Matrix - -### 标题映射 (Pixel-Based) - -| Element | Markdown | BBCode Output | -|---------|----------|---------------| -| **H1** | `# text` | `[size=150][color=#2196F3][b]text[/b][/color][/size]` | -| **H2** | `## text` | `[size=120][color=#2196F3][b]text[/b][/color][/size]` | -| **H3** | `### text` | `[size=100][color=#333][b]text[/b][/color][/size]` | -| **H4** | `#### text` | `[b]text[/b]` | -| **H5** | `##### text` | `[b]text[/b]` | -| **H6** | `###### text` | `[b]text[/b]` | - -### 文本样式映射 - -| Element | Markdown/HTML | BBCode | -|---------|---------------|--------| -| **Bold** | `**text**` 或 `__text__` | `[b]text[/b]` | -| **Italic** | `*text*` 或 `_text_` | `[i]text[/i]` | -| **Bold+Italic** | `***text***` | `[b][i]text[/i][/b]` | -| **Strike** | `~~text~~` | `[s]text[/s]` | -| **Underline** | `text` | `[u]text[/u]` | -| **Highlight** | `==text==` 或 `text` | `[color=yellow]text[/color]` | -| **Code (inline)** | `` `text` `` | 保持原样 | - -### HTML 转 BBCode 映射 - -| HTML | BBCode | -|------|--------| -| `text` | `[color=yellow]text[/color]` | -| `text` | `[u]text[/u]` | -| `
标题内容
` | `[spoiler=标题]内容[/spoiler]` | - -### 块级元素映射 - -| Element | Markdown | BBCode | -|---------|----------|--------| -| **Code Block** | ` ```lang\ncode\n``` ` | `[code]code[/code]` | -| **Quote** | `> text` | `[quote]text[/quote]` | -| **HR** | `---` | `---` (保持 Markdown) | -| **List Item** | `- text` | `• text` | -| **Paragraph** | `text\n\ntext` | `text\n\ntext` | - -### 链接和媒体映射 - -| Element | Markdown | BBCode | -|---------|----------|--------| -| **Link** | `[text](url)` | `[url=url]text[/url]` | -| **Image** | `![alt](url)` | `[img]url[/img]` | - ---- - -## Callout Mapping - -### 类型到样式映射 - -| Callout Type | Color | Icon | Label | -|--------------|-------|------|-------| -| note | #2196F3 | 📝 | 注意 | -| info | #2196F3 | ℹ️ | 信息 | -| tip | #4CAF50 | 💡 | 提示 | -| hint | #4CAF50 | 💡 | 提示 | -| success | #4CAF50 | ✅ | 成功 | -| check | #4CAF50 | ✅ | 完成 | -| done | #4CAF50 | ✅ | 完成 | -| warning | #FF9800 | ⚠️ | 警告 | -| caution | #FF9800 | ⚠️ | 注意 | -| attention | #FF9800 | ⚠️ | 注意 | -| danger | #F44336 | ❌ | 危险 | -| error | #F44336 | ❌ | 错误 | -| bug | #F44336 | 🐛 | Bug | -| example | #9C27B0 | 📋 | 示例 | -| question | #FF9800 | ❓ | 问题 | -| help | #FF9800 | ❓ | 帮助 | -| faq | #FF9800 | ❓ | FAQ | -| quote | gray | 💬 | 引用 | -| cite | gray | 💬 | 引用 | -| abstract | #2196F3 | 📄 | 摘要 | -| summary | #2196F3 | 📄 | 摘要 | -| tldr | #2196F3 | 📄 | 摘要 | -| todo | #FF9800 | 📋 | 待办 | -| important | #F44336 | ⭐ | 重要 | - -### Callout 输出模板 - -```bbcode -[quote] -[size=100][color={color}][b]{icon} {title}[/b][/color][/size] - -{content} -[/quote] -``` - ---- - -## Unsupported Elements - -### 不支持转换的元素 - -| 元素 | 原因 | 降级方案 | -|------|------|----------| -| 表格 | BBCode 表格支持有限 | 转为代码块或列表 | -| 脚注 | 不支持 | 转为括号注释 `(注: ...)` | -| 数学公式 | 不支持 | 保留原始文本 | -| 嵌入内容 | 不支持 | 转为链接 | -| 任务列表 | 复选框不支持 | 转为普通列表 `☐`/`☑` | - -### 降级示例 - -**表格**: -``` -| A | B | -|---|---| -| 1 | 2 | - -→ 降级为: - -A: 1 -B: 2 -``` - -**脚注**: -``` -文本[^1] - -[^1]: 脚注内容 - -→ 降级为: - -文本 (注: 脚注内容) -``` - -**任务列表**: -``` -- [ ] 待办 -- [x] 已完成 - -→ 降级为: - -☐ 待办 -☑ 已完成 -``` - ---- - -## Validation Rules - -### 转换验证 - -- [ ] 所有 H1-H3 使用像素值 size (150/120/100) -- [ ] 未使用 `[align]` 标签 -- [ ] 未使用 `[hr]` 标签 -- [ ] 分隔线保持 `---` -- [ ] Callout 正确识别并转换 -- [ ] 颜色值使用 hex 格式 diff --git a/.claude/skills/text-formatter/specs/format-rules.md b/.claude/skills/text-formatter/specs/format-rules.md deleted file mode 100644 index ca7ce47b..00000000 --- a/.claude/skills/text-formatter/specs/format-rules.md +++ /dev/null @@ -1,273 +0,0 @@ -# Format Conversion Rules - -BBCode + Markdown 混合格式转换规则(论坛优化)。 - -## When to Use - -| Phase | Usage | Section | -|-------|-------|---------| -| Phase 3 | 格式转换 | All sections | - ---- - -## Core Principles - -### 1. Pixel-Based Sizing - -**重要**: 使用像素值而非 1-7 级别 - -| 元素 | Size (px) | 说明 | -|------|-----------|------| -| 主标题 (H1) | 150 | 文档标题 | -| 章节标题 (H2) | 120 | 主要章节 | -| 子标题 (H3) | 100 | 子章节 | -| 正文 | (默认) | 不指定 size | -| 备注/灰色 | 80 | 脚注、元数据 | - -### 2. Supported Tags Only - -**支持的 BBCode 标签**: -- `[size=N]` - 字号(像素值) -- `[color=X]` - 颜色(hex 或名称,如 `[color=blue]`、`[color=#2196F3]`) -- `[b]`, `[i]`, `[s]`, `[u]` - 粗体、斜体、删除线、下划线 -- `[quote]` - 引用块 -- `[code]` - 代码块 -- `[url]`, `[img]` - 链接、图片 -- `[list]`, `[*]` - 列表 -- `[spoiler]` 或 `[spoiler=标题]` - 折叠/隐藏内容 - -**禁止使用的标签**: -- `[align]` - 不渲染,显示为文本 -- `[hr]` - 不渲染,使用 Markdown `---` -- `[table]` - 支持有限,避免使用 - -**HTML 标签转换** (输入时支持,转换为 BBCode): -- `text` → `[color=yellow]text[/color]` -- `
标题内容
` → `[spoiler=标题]内容[/spoiler]` -- 其他 HTML 标签 (`
`, ``) - 删除 - -### 3. Markdown as Separator - -分隔线使用 Markdown 语法:`---` - ---- - -## Element Conversion Rules - -### 标题转换 - -| Markdown | BBCode Output | -|----------|---------------| -| `# H1` | `[size=150][color=#2196F3][b]H1[/b][/color][/size]` | -| `## H2` | `[size=120][color=#2196F3][b]H2[/b][/color][/size]` | -| `### H3` | `[size=100][color=#333][b]H3[/b][/color][/size]` | -| `#### H4+` | `[b]H4[/b]` (不加 size) | - -### 文本样式 - -| Markdown/HTML | BBCode | -|---------------|--------| -| `**bold**` 或 `__bold__` | `[b]bold[/b]` | -| `*italic*` 或 `_italic_` | `[i]italic[/i]` | -| `***both***` | `[b][i]both[/i][/b]` | -| `~~strike~~` | `[s]strike[/s]` | -| `==highlight==` 或 `text` | `[color=yellow]highlight[/color]` | -| (无 MD 语法) | `[u]underline[/u]` | - -### 折叠内容 - -| HTML | BBCode | -|------|--------| -| `
标题内容
` | `[spoiler=标题]内容[/spoiler]` | -| (无 HTML) | `[spoiler]隐藏内容[/spoiler]` | - -### 代码 - -| Markdown | BBCode | -|----------|--------| -| `` `inline` `` | 保持原样或 `[color=#9C27B0]inline[/color]` | -| ` ```code``` ` | `[code]code[/code]` | - -### 链接和图片 - -| Markdown | BBCode | -|----------|--------| -| `[text](url)` | `[url=url]text[/url]` | -| `![alt](url)` | `[img]url[/img]` | - -### 列表 - -``` -Markdown: -- item 1 -- item 2 - - nested - -BBCode: -• item 1 -• item 2 - • nested -``` - -注意:使用 `•` 符号而非 `[list][*]`,因为部分论坛渲染有问题。 - -### 引用 - -``` -Markdown: -> quote text - -BBCode: -[quote] -quote text -[/quote] -``` - ---- - -## Callout (标注) 转换 - -### Obsidian Callout 语法 - -```markdown -> [!TYPE] 可选标题 -> 内容行 1 -> 内容行 2 -``` - -### 支持的 Callout 类型 - -| Type | Color | Icon | 中文标签 | -|------|-------|------|----------| -| note, info | #2196F3 | 📝 | 注意 / 信息 | -| tip, hint | #4CAF50 | 💡 | 提示 | -| success, check, done | #4CAF50 | ✅ | 成功 | -| warning, caution, attention | #FF9800 | ⚠️ | 警告 | -| danger, error, bug | #F44336 | ❌ | 危险 / 错误 | -| example | #9C27B0 | 📋 | 示例 | -| question, help, faq | #FF9800 | ❓ | 问题 | -| quote, cite | gray | 💬 | 引用 | -| abstract, summary, tldr | #2196F3 | 📄 | 摘要 | - -### Callout 转换模板 - -```bbcode -[quote] -[size=100][color={color}][b]{icon} {title}[/b][/color][/size] - -{content} -[/quote] -``` - -**示例**: - -```markdown -> [!WARNING] 注意事项 -> 这是警告内容 -``` - -转换为: - -```bbcode -[quote] -[size=100][color=#FF9800][b]⚠️ 注意事项[/b][/color][/size] - -这是警告内容 -[/quote] -``` - -### 可折叠 Callout - -Obsidian 支持 `> [!NOTE]+` (展开) 和 `> [!NOTE]-` (折叠)。 - -由于 BBCode 不支持折叠,统一转换为普通 quote。 - ---- - -## Color Palette - -### 语义颜色 - -| 语义 | Hex | 使用场景 | -|------|-----|----------| -| Primary | #2196F3 | 标题、链接、信息 | -| Success | #4CAF50 | 成功、提示、特性 | -| Warning | #FF9800 | 警告、注意 | -| Error | #F44336 | 错误、危险 | -| Purple | #9C27B0 | 示例、代码 | -| Gray | gray | 备注、元数据 | -| Dark | #333 | 子标题 | - -### 颜色使用规则 - -1. **标题颜色**: H1/H2 使用 #2196F3,H3 使用 #333 -2. **Callout 颜色**: 根据类型使用语义颜色 -3. **备注颜色**: 使用 gray -4. **强调颜色**: 根据语义选择(成功用绿色,警告用橙色) - ---- - -## Spacing Rules - -### 空行控制 - -| 元素 | 前空行 | 后空行 | -|------|--------|--------| -| 标题 | 1 | 1 | -| 段落 | 0 | 1 | -| 列表 | 0 | 1 | -| 代码块 | 1 | 1 | -| Callout | 1 | 1 | -| 分隔线 `---` | 1 | 1 | - -### 示例输出结构 - -```bbcode -[size=150][color=#2196F3][b]文档标题[/b][/color][/size] - -[size=80][color=gray]作者 | 日期[/color][/size] - ---- - -[size=120][color=#2196F3][b]第一章节[/b][/color][/size] - -正文内容... - -[quote] -[size=100][color=#4CAF50][b]💡 提示[/b][/color][/size] - -提示内容 -[/quote] - ---- - -[size=120][color=#2196F3][b]第二章节[/b][/color][/size] - -更多内容... - ---- - -[size=80][color=gray]— 全文完 —[/color][/size] -``` - ---- - -## Quality Checklist - -### 转换完整性 - -- [ ] 所有标题使用像素值 size -- [ ] 未使用 `[align]` 或 `[hr]` -- [ ] 分隔线使用 `---` -- [ ] Callout 正确转换为 quote -- [ ] 颜色符合语义规范 -- [ ] 空行控制正确 - -### 常见错误 - -| 错误 | 正确做法 | -|------|----------| -| `[size=5]` | `[size=120]` | -| `[align=center]` | 删除,默认左对齐 | -| `[hr]` | 使用 `---` | -| `
` | 删除 HTML 标签 | diff --git a/.claude/skills/text-formatter/templates/bbcode-template.md b/.claude/skills/text-formatter/templates/bbcode-template.md deleted file mode 100644 index d854af5e..00000000 --- a/.claude/skills/text-formatter/templates/bbcode-template.md +++ /dev/null @@ -1,350 +0,0 @@ -# BBCode Template - -论坛优化的 BBCode + Markdown 混合模板(像素级字号)。 - -## 核心规则 - -### 字号体系 (Pixels) - -| 元素 | Size | 说明 | -|------|------|------| -| 主标题 | 150 | 文档标题 | -| 章节标题 | 120 | H2 级别 | -| 子标题 | 100 | H3 级别 | -| 正文 | (默认) | 不指定 | -| 备注 | 80 | 灰色小字 | - -### 禁止使用 - -- `[align]` - 不渲染 -- `[hr]` - 不渲染,用 `---` -- `[table]` - 支持有限 -- HTML 标签 - ---- - -## 文档模板 - -### 基础文档结构 - -```bbcode -[size=150][color=#2196F3][b]{{title}}[/b][/color][/size] - -[size=80][color=gray]{{metadata}}[/color][/size] - ---- - -{{introduction}} - ---- - -[size=120][color=#2196F3][b]{{section1_title}}[/b][/color][/size] - -{{section1_content}} - ---- - -[size=120][color=#2196F3][b]{{section2_title}}[/b][/color][/size] - -{{section2_content}} - ---- - -[size=80][color=gray]— 全文完 —[/color][/size] -``` - -### 带目录的文档 - -```bbcode -[size=150][color=#2196F3][b]{{title}}[/b][/color][/size] - -[size=80][color=gray]{{author}} | {{date}}[/color][/size] - ---- - -[size=100][b]📋 目录[/b][/size] - -• {{section1_title}} -• {{section2_title}} -• {{section3_title}} - ---- - -[size=120][color=#2196F3][b]{{section1_title}}[/b][/color][/size] - -{{section1_content}} - ---- - -[size=120][color=#2196F3][b]{{section2_title}}[/b][/color][/size] - -{{section2_content}} - ---- - -[size=120][color=#2196F3][b]{{section3_title}}[/b][/color][/size] - -{{section3_content}} - ---- - -[size=80][color=gray]— 全文完 —[/color][/size] -``` - ---- - -## Callout 模板 - -### 提示 (Note/Info) - -```bbcode -[quote] -[size=100][color=#2196F3][b]📝 {{title}}[/b][/color][/size] - -{{content}} -[/quote] -``` - -### 技巧 (Tip/Hint) - -```bbcode -[quote] -[size=100][color=#4CAF50][b]💡 {{title}}[/b][/color][/size] - -{{content}} -[/quote] -``` - -### 成功 (Success) - -```bbcode -[quote] -[size=100][color=#4CAF50][b]✅ {{title}}[/b][/color][/size] - -{{content}} -[/quote] -``` - -### 警告 (Warning/Caution) - -```bbcode -[quote] -[size=100][color=#FF9800][b]⚠️ {{title}}[/b][/color][/size] - -{{content}} -[/quote] -``` - -### 危险/错误 (Danger/Error) - -```bbcode -[quote] -[size=100][color=#F44336][b]❌ {{title}}[/b][/color][/size] - -{{content}} -[/quote] -``` - -### 示例 (Example) - -```bbcode -[quote] -[size=100][color=#9C27B0][b]📋 {{title}}[/b][/color][/size] - -{{content}} -[/quote] -``` - -### 问题 (Question/FAQ) - -```bbcode -[quote] -[size=100][color=#FF9800][b]❓ {{title}}[/b][/color][/size] - -{{content}} -[/quote] -``` - -### 重要 (Important) - -```bbcode -[quote] -[size=100][color=#F44336][b]⭐ {{title}}[/b][/color][/size] - -{{content}} -[/quote] -``` - ---- - -## 代码展示模板 - -### 单代码块 - -```bbcode -[size=100][color=#9C27B0][b]代码示例[/b][/color][/size] - -[code] -{{code}} -[/code] - -[size=80][color=gray]说明: {{description}}[/color][/size] -``` - -### 带标题的代码 - -```bbcode -[size=100][b]{{code_title}}[/b][/size] - -[code] -{{code}} -[/code] -``` - ---- - -## 特性展示模板 - -### 特性列表 - -```bbcode -[size=120][color=#2196F3][b]功能特性[/b][/color][/size] - -• [color=#4CAF50][b]✨ {{feature1}}[/b][/color] — {{desc1}} -• [color=#2196F3][b]🚀 {{feature2}}[/b][/color] — {{desc2}} -• [color=#FF9800][b]⚡ {{feature3}}[/b][/color] — {{desc3}} -``` - -### 详细特性卡片 - -```bbcode -[size=120][color=#2196F3][b]功能特性[/b][/color][/size] - -[quote] -[size=100][color=#4CAF50][b]✨ {{feature1_title}}[/b][/color][/size] - -{{feature1_description}} - -[size=80][color=gray]适用场景: {{feature1_use_case}}[/color][/size] -[/quote] - -[quote] -[size=100][color=#2196F3][b]🚀 {{feature2_title}}[/b][/color][/size] - -{{feature2_description}} - -[size=80][color=gray]适用场景: {{feature2_use_case}}[/color][/size] -[/quote] -``` - ---- - -## 步骤指南模板 - -```bbcode -[size=120][color=#2196F3][b]操作步骤[/b][/color][/size] - -[size=100][color=#2196F3][b]步骤 1: {{step1_title}}[/b][/color][/size] - -{{step1_content}} - -[quote] -[size=100][color=#FF9800][b]💡 提示[/b][/color][/size] - -{{step1_tip}} -[/quote] - -[size=100][color=#2196F3][b]步骤 2: {{step2_title}}[/b][/color][/size] - -{{step2_content}} - -[size=100][color=#2196F3][b]步骤 3: {{step3_title}}[/b][/color][/size] - -{{step3_content}} - ---- - -[color=#4CAF50][b]✅ 完成![/b][/color] {{completion_message}} -``` - ---- - -## 版本更新模板 - -```bbcode -[size=150][color=#673AB7][b]🎉 版本 {{version}} 更新日志[/b][/color][/size] - ---- - -[size=120][color=#4CAF50][b]✨ 新功能[/b][/color][/size] - -• [b]{{new_feature1}}[/b]: {{new_feature1_desc}} -• [b]{{new_feature2}}[/b]: {{new_feature2_desc}} - -[size=120][color=#2196F3][b]🔧 改进[/b][/color][/size] - -• {{improvement1}} -• {{improvement2}} - -[size=120][color=#F44336][b]🐛 修复[/b][/color][/size] - -• {{bugfix1}} -• {{bugfix2}} - ---- - -[url={{download_url}}][b]📥 立即下载[/b][/url] -``` - ---- - -## FAQ 模板 - -```bbcode -[size=120][color=#2196F3][b]❓ 常见问题[/b][/color][/size] - ---- - -[size=100][color=#333][b]Q: {{question1}}[/b][/color][/size] - -[b]A:[/b] {{answer1}} - ---- - -[size=100][color=#333][b]Q: {{question2}}[/b][/color][/size] - -[b]A:[/b] {{answer2}} - ---- - -[size=100][color=#333][b]Q: {{question3}}[/b][/color][/size] - -[b]A:[/b] {{answer3}} -``` - ---- - -## 转换检查清单 - -### 必须检查 - -- [ ] 标题使用像素值 (150/120/100) -- [ ] 分隔线使用 `---` -- [ ] 未使用 `[align]` -- [ ] 未使用 `[hr]` -- [ ] 未使用 HTML 标签 -- [ ] Callout 标题 size=100 -- [ ] 灰色备注 size=80 - -### 颜色规范 - -| 用途 | 颜色 | -|------|------| -| 主标题 | #2196F3 | -| 章节标题 | #2196F3 | -| 子标题 | #333 | -| 成功/提示 | #4CAF50 | -| 警告 | #FF9800 | -| 错误/危险 | #F44336 | -| 示例 | #9C27B0 | -| 备注 | gray | diff --git a/ccw/frontend/package-lock.json b/ccw/frontend/package-lock.json index b81e8a98..d27b1ff2 100644 --- a/ccw/frontend/package-lock.json +++ b/ccw/frontend/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "@formatjs/icu-messageformat-parser": "^2.11.4", "@hello-pangea/dnd": "^18.0.1", + "@radix-ui/react-accordion": "^1.2.12", "@radix-ui/react-alert-dialog": "^1.1.15", "@radix-ui/react-checkbox": "^1.3.3", "@radix-ui/react-collapsible": "^1.1.12", @@ -1392,6 +1393,37 @@ "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==", "license": "MIT" }, + "node_modules/@radix-ui/react-accordion": { + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.2.12.tgz", + "integrity": "sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collapsible": "1.1.12", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-alert-dialog": { "version": "1.1.15", "resolved": "https://registry.npmjs.org/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.1.15.tgz", diff --git a/ccw/frontend/package.json b/ccw/frontend/package.json index 664b3fff..7e4fc9a3 100644 --- a/ccw/frontend/package.json +++ b/ccw/frontend/package.json @@ -19,6 +19,7 @@ "dependencies": { "@formatjs/icu-messageformat-parser": "^2.11.4", "@hello-pangea/dnd": "^18.0.1", + "@radix-ui/react-accordion": "^1.2.12", "@radix-ui/react-alert-dialog": "^1.1.15", "@radix-ui/react-checkbox": "^1.3.3", "@radix-ui/react-collapsible": "^1.1.12", diff --git a/ccw/frontend/src/App.tsx b/ccw/frontend/src/App.tsx index 01fff7dd..00ad5e40 100644 --- a/ccw/frontend/src/App.tsx +++ b/ccw/frontend/src/App.tsx @@ -11,6 +11,7 @@ import { router } from './router'; import queryClient from './lib/query-client'; import type { Locale } from './lib/i18n'; import { useWorkflowStore } from '@/stores/workflowStore'; +import { useActiveCliExecutions } from '@/hooks/useActiveCliExecutions'; interface AppProps { locale: Locale; @@ -26,6 +27,7 @@ function App({ locale, messages }: AppProps) { + @@ -57,4 +59,19 @@ function QueryInvalidator() { return null; } +/** + * CLI Execution Sync component + * Syncs active CLI executions in the background to keep the count updated in Header + */ +function CliExecutionSync() { + // Always sync active CLI executions with a longer polling interval + // This ensures the activeCliCount badge in Header shows correct count on initial load + useActiveCliExecutions( + true, // enabled: always sync + 15000 // refetchInterval: 15 seconds (longer than monitor's 5 seconds to reduce load) + ); + + return null; +} + export default App; diff --git a/ccw/frontend/src/components/api-settings/CliSettingsList.tsx b/ccw/frontend/src/components/api-settings/CliSettingsList.tsx index d83046fb..b27409ea 100644 --- a/ccw/frontend/src/components/api-settings/CliSettingsList.tsx +++ b/ccw/frontend/src/components/api-settings/CliSettingsList.tsx @@ -119,7 +119,7 @@ function CliSettingsCard({ )} {cliSettings.settings.includeCoAuthoredBy !== undefined && ( - Co-authored: {cliSettings.settings.includeCoAuthoredBy ? 'Yes' : 'No'} + {formatMessage({ id: 'apiSettings.cliSettings.coAuthoredBy' })}: {formatMessage({ id: cliSettings.settings.includeCoAuthoredBy ? 'common.yes' : 'common.no' })} )}
diff --git a/ccw/frontend/src/components/api-settings/CliSettingsModal.tsx b/ccw/frontend/src/components/api-settings/CliSettingsModal.tsx index 43984586..5cca11fa 100644 --- a/ccw/frontend/src/components/api-settings/CliSettingsModal.tsx +++ b/ccw/frontend/src/components/api-settings/CliSettingsModal.tsx @@ -5,7 +5,7 @@ import { useState, useEffect } from 'react'; import { useIntl } from 'react-intl'; -import { Check, Eye, EyeOff } from 'lucide-react'; +import { Check, Eye, EyeOff, X, Plus } from 'lucide-react'; import { Dialog, DialogContent, @@ -59,12 +59,21 @@ export function CliSettingsModal({ open, onClose, cliSettings }: CliSettingsModa const [providerId, setProviderId] = useState(''); const [model, setModel] = useState('sonnet'); const [includeCoAuthoredBy, setIncludeCoAuthoredBy] = useState(false); + const [settingsFile, setSettingsFile] = useState(''); // Direct mode state const [authToken, setAuthToken] = useState(''); const [baseUrl, setBaseUrl] = useState(''); const [showToken, setShowToken] = useState(false); + // Available models state + const [availableModels, setAvailableModels] = useState([]); + const [modelInput, setModelInput] = useState(''); + + // Tags state + const [tags, setTags] = useState([]); + const [tagInput, setTagInput] = useState(''); + // Validation errors const [errors, setErrors] = useState>({}); @@ -76,6 +85,9 @@ export function CliSettingsModal({ open, onClose, cliSettings }: CliSettingsModa setEnabled(cliSettings.enabled); setModel(cliSettings.settings.model || 'sonnet'); setIncludeCoAuthoredBy(cliSettings.settings.includeCoAuthoredBy || false); + setSettingsFile(cliSettings.settings.settingsFile || ''); + setAvailableModels(cliSettings.settings.availableModels || []); + setTags(cliSettings.settings.tags || []); // Determine mode based on settings const hasCustomBaseUrl = Boolean( @@ -104,8 +116,13 @@ export function CliSettingsModal({ open, onClose, cliSettings }: CliSettingsModa setProviderId(''); setModel('sonnet'); setIncludeCoAuthoredBy(false); + setSettingsFile(''); setAuthToken(''); setBaseUrl(''); + setAvailableModels([]); + setModelInput(''); + setTags([]); + setTagInput(''); setErrors({}); } }, [cliSettings, open, providers]); @@ -183,6 +200,9 @@ export function CliSettingsModal({ open, onClose, cliSettings }: CliSettingsModa env, model, includeCoAuthoredBy, + settingsFile: settingsFile.trim() || undefined, + availableModels, + tags, }, }; @@ -198,6 +218,37 @@ export function CliSettingsModal({ open, onClose, cliSettings }: CliSettingsModa } }; + // Handle add model + const handleAddModel = () => { + const newModel = modelInput.trim(); + if (newModel && !availableModels.includes(newModel)) { + setAvailableModels([...availableModels, newModel]); + setModelInput(''); + } + }; + + // Handle remove model + const handleRemoveModel = (modelToRemove: string) => { + setAvailableModels(availableModels.filter((m) => m !== modelToRemove)); + }; + + // Handle add tag + const handleAddTag = () => { + const newTag = tagInput.trim(); + if (newTag && !tags.includes(newTag)) { + setTags([...tags, newTag]); + setTagInput(''); + } + }; + + // Handle remove tag + const handleRemoveTag = (tagToRemove: string) => { + setTags(tags.filter((t) => t !== tagToRemove)); + }; + + // Predefined tags + const predefinedTags = ['分析', 'Debug', 'implementation', 'refactoring', 'testing']; + // Get selected provider info const selectedProvider = providers.find((p) => p.id === providerId); @@ -387,15 +438,154 @@ export function CliSettingsModal({ open, onClose, cliSettings }: CliSettingsModa {/* Additional Settings (both modes) */} -
- - +
+
+ + +
+ +
+ + setSettingsFile(e.target.value)} + placeholder={formatMessage({ id: 'apiSettings.cliSettings.settingsFilePlaceholder' })} + /> +

+ {formatMessage({ id: 'apiSettings.cliSettings.settingsFileHint' })} +

+
+ + {/* Available Models Section */} +
+ +
+ {availableModels.map((model) => ( + + {model} + + + ))} +
+ setModelInput(e.target.value)} + onKeyDown={(e) => { + if (e.key === 'Enter') { + e.preventDefault(); + handleAddModel(); + } + }} + placeholder={formatMessage({ id: 'apiSettings.cliSettings.availableModelsPlaceholder' })} + className="flex-1 min-w-[120px]" + /> + +
+
+

+ {formatMessage({ id: 'apiSettings.cliSettings.availableModelsHint' })} +

+
+ + {/* Tags Section */} +
+ +

+ {formatMessage({ id: 'apiSettings.cliSettings.tagsDescription' })} +

+
+ {tags.map((tag) => ( + + {tag} + + + ))} +
+ setTagInput(e.target.value)} + onKeyDown={(e) => { + if (e.key === 'Enter') { + e.preventDefault(); + handleAddTag(); + } + }} + placeholder={formatMessage({ id: 'apiSettings.cliSettings.tagInputPlaceholder' })} + className="flex-1 min-w-[120px]" + /> + +
+
+ {/* Predefined Tags */} +
+ + {formatMessage({ id: 'apiSettings.cliSettings.predefinedTags' })}: + + {predefinedTags.map((predefinedTag) => ( + + ))} +
+
diff --git a/ccw/frontend/src/components/coordinator/CoordinatorInputModal.test.tsx b/ccw/frontend/src/components/coordinator/CoordinatorInputModal.test.tsx new file mode 100644 index 00000000..79d88e37 --- /dev/null +++ b/ccw/frontend/src/components/coordinator/CoordinatorInputModal.test.tsx @@ -0,0 +1,136 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import { render, screen, fireEvent, waitFor } from '@testing-library/react'; +import { IntlProvider } from 'react-intl'; +import { CoordinatorInputModal } from './CoordinatorInputModal'; + +// Mock zustand stores +vi.mock('@/stores/coordinatorStore', () => ({ + useCoordinatorStore: () => ({ + startCoordinator: vi.fn(), + }), +})); + +vi.mock('@/hooks/useNotifications', () => ({ + useNotifications: () => ({ + success: vi.fn(), + error: vi.fn(), + }), +})); + +// Mock fetch +global.fetch = vi.fn(); + +const mockMessages = { + 'coordinator.modal.title': 'Start Coordinator', + 'coordinator.modal.description': 'Describe the task', + 'coordinator.form.taskDescription': 'Task Description', + 'coordinator.form.taskDescriptionPlaceholder': 'Enter task description', + 'coordinator.form.parameters': 'Parameters', + 'coordinator.form.parametersPlaceholder': '{"key": "value"}', + 'coordinator.form.parametersHelp': 'Optional JSON parameters', + 'coordinator.form.characterCount': '{current} / {max} characters (min: {min})', + 'coordinator.form.start': 'Start', + 'coordinator.form.starting': 'Starting...', + 'coordinator.validation.taskDescriptionRequired': 'Task description is required', + 'coordinator.validation.taskDescriptionTooShort': 'Too short', + 'coordinator.validation.taskDescriptionTooLong': 'Too long', + 'coordinator.validation.parametersInvalidJson': 'Invalid JSON', + 'common.actions.cancel': 'Cancel', +}; + +const renderWithIntl = (ui: React.ReactElement) => { + return render( + + {ui} + + ); +}; + +describe('CoordinatorInputModal', () => { + const mockOnClose = vi.fn(); + + beforeEach(() => { + vi.clearAllMocks(); + }); + + it('should render when open', () => { + renderWithIntl(); + + expect(screen.getByText('Start Coordinator')).toBeInTheDocument(); + expect(screen.getByText('Describe the task')).toBeInTheDocument(); + }); + + it('should not render when closed', () => { + renderWithIntl(); + + expect(screen.queryByText('Start Coordinator')).not.toBeInTheDocument(); + }); + + it('should show validation error for empty task description', async () => { + renderWithIntl(); + + const startButton = screen.getByText('Start'); + fireEvent.click(startButton); + + await waitFor(() => { + expect(screen.getByText('Task description is required')).toBeInTheDocument(); + }); + }); + + it('should show validation error for short task description', async () => { + renderWithIntl(); + + const textarea = screen.getByPlaceholderText('Enter task description'); + fireEvent.change(textarea, { target: { value: 'Short' } }); + + const startButton = screen.getByText('Start'); + fireEvent.click(startButton); + + await waitFor(() => { + expect(screen.getByText('Too short')).toBeInTheDocument(); + }); + }); + + it('should show validation error for invalid JSON parameters', async () => { + renderWithIntl(); + + const textarea = screen.getByPlaceholderText('Enter task description'); + fireEvent.change(textarea, { target: { value: 'Valid task description here' } }); + + const paramsInput = screen.getByPlaceholderText('{"key": "value"}'); + fireEvent.change(paramsInput, { target: { value: 'invalid json' } }); + + const startButton = screen.getByText('Start'); + fireEvent.click(startButton); + + await waitFor(() => { + expect(screen.getByText('Invalid JSON')).toBeInTheDocument(); + }); + }); + + it('should submit with valid task description', async () => { + const mockFetch = vi.fn().mockResolvedValue({ + ok: true, + json: async () => ({ success: true }), + }); + global.fetch = mockFetch; + + renderWithIntl(); + + const textarea = screen.getByPlaceholderText('Enter task description'); + fireEvent.change(textarea, { target: { value: 'Valid task description with more than 10 characters' } }); + + const startButton = screen.getByText('Start'); + fireEvent.click(startButton); + + await waitFor(() => { + expect(mockFetch).toHaveBeenCalledWith( + '/api/coordinator/start', + expect.objectContaining({ + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }) + ); + }); + }); +}); diff --git a/ccw/frontend/src/components/coordinator/CoordinatorInputModal.tsx b/ccw/frontend/src/components/coordinator/CoordinatorInputModal.tsx new file mode 100644 index 00000000..8eda0527 --- /dev/null +++ b/ccw/frontend/src/components/coordinator/CoordinatorInputModal.tsx @@ -0,0 +1,249 @@ +// ======================================== +// Coordinator Input Modal Component +// ======================================== +// Modal dialog for starting coordinator execution with task description and parameters + +import { useState, useEffect } from 'react'; +import { useIntl } from 'react-intl'; +import { Loader2 } from 'lucide-react'; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogDescription, + DialogFooter, +} from '@/components/ui/Dialog'; +import { Button } from '@/components/ui/Button'; +import { Textarea } from '@/components/ui/Textarea'; +import { Input } from '@/components/ui/Input'; +import { Label } from '@/components/ui/Label'; +import { useCoordinatorStore } from '@/stores/coordinatorStore'; +import { useNotifications } from '@/hooks/useNotifications'; + +// ========== Types ========== + +export interface CoordinatorInputModalProps { + open: boolean; + onClose: () => void; +} + +interface FormErrors { + taskDescription?: string; + parameters?: string; +} + +// ========== Validation Helper ========== + +function validateForm(taskDescription: string, parameters: string): FormErrors { + const errors: FormErrors = {}; + + // Validate task description + if (!taskDescription.trim()) { + errors.taskDescription = 'coordinator.validation.taskDescriptionRequired'; + } else { + const length = taskDescription.trim().length; + if (length < 10) { + errors.taskDescription = 'coordinator.validation.taskDescriptionTooShort'; + } else if (length > 2000) { + errors.taskDescription = 'coordinator.validation.taskDescriptionTooLong'; + } + } + + // Validate parameters if provided + if (parameters.trim()) { + try { + JSON.parse(parameters.trim()); + } catch (error) { + errors.parameters = 'coordinator.validation.parametersInvalidJson'; + } + } + + return errors; +} + +// ========== Component ========== + +export function CoordinatorInputModal({ open, onClose }: CoordinatorInputModalProps) { + const { formatMessage } = useIntl(); + const { success, error: showError } = useNotifications(); + const { startCoordinator } = useCoordinatorStore(); + + // Form state + const [taskDescription, setTaskDescription] = useState(''); + const [parameters, setParameters] = useState(''); + const [errors, setErrors] = useState({}); + const [isSubmitting, setIsSubmitting] = useState(false); + + // Reset form when modal opens/closes + useEffect(() => { + if (open) { + setTaskDescription(''); + setParameters(''); + setErrors({}); + } + }, [open]); + + // Handle field change + const handleFieldChange = ( + field: 'taskDescription' | 'parameters', + value: string + ) => { + if (field === 'taskDescription') { + setTaskDescription(value); + } else { + setParameters(value); + } + + // Clear error for this field when user starts typing + if (errors[field]) { + setErrors((prev) => ({ ...prev, [field]: undefined })); + } + }; + + // Handle submit + const handleSubmit = async () => { + // Validate form + const validationErrors = validateForm(taskDescription, parameters); + if (Object.keys(validationErrors).length > 0) { + setErrors(validationErrors); + return; + } + + setIsSubmitting(true); + try { + // Parse parameters if provided + const parsedParams = parameters.trim() ? JSON.parse(parameters.trim()) : undefined; + + // Generate execution ID + const executionId = `exec-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; + + // Call API to start coordinator + const response = await fetch('/api/coordinator/start', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + executionId, + taskDescription: taskDescription.trim(), + parameters: parsedParams, + }), + }); + + if (!response.ok) { + const error = await response.json().catch(() => ({ message: 'Unknown error' })); + throw new Error(error.message || 'Failed to start coordinator'); + } + + // Call store to update state + await startCoordinator(executionId, taskDescription.trim(), parsedParams); + + success(formatMessage({ id: 'coordinator.success.started' })); + onClose(); + } catch (error) { + const errorMessage = error instanceof Error ? error.message : 'Unknown error'; + showError('Error', errorMessage); + console.error('Failed to start coordinator:', error); + } finally { + setIsSubmitting(false); + } + }; + + return ( + + + + + {formatMessage({ id: 'coordinator.modal.title' })} + + + {formatMessage({ id: 'coordinator.modal.description' })} + + + +
+ {/* Task Description */} +
+ +