diff --git a/.claude/commands/workflow/review.md b/.claude/commands/workflow/review.md deleted file mode 100644 index 2f7d6440..00000000 --- a/.claude/commands/workflow/review.md +++ /dev/null @@ -1,322 +0,0 @@ ---- -name: review -description: Post-implementation review with specialized types (security/architecture/action-items/quality) using analysis agents and Gemini -argument-hint: "[--type=security|architecture|action-items|quality] [--archived] [optional: session-id]" ---- - -## Command Overview: /workflow:review - -**Optional specialized review** for completed implementations. In the standard workflow, **passing tests = approved code**. Use this command only when specialized review is required (security, architecture, compliance, docs). - -## Philosophy: "Tests Are the Review" - -- **Default**: All tests pass -> Code approved -- **Optional**: Specialized reviews for: - - Security audits (vulnerabilities, auth/authz) - - Architecture compliance (patterns, technical debt) - - Action items verification (requirements met, acceptance criteria) - -## Review Types - -| Type | Focus | Use Case | -|------|-------|----------| -| `quality` | Code quality, best practices, maintainability | Default general review | -| `security` | Security vulnerabilities, data handling, access control | Security audits | -| `architecture` | Architectural patterns, technical debt, design decisions | Architecture compliance | -| `action-items` | Requirements met, acceptance criteria verified, action items completed | Pre-deployment verification | - -**Notes**: -- For documentation generation, use `/workflow:tools:docs` -- For CLAUDE.md updates, use `/update-memory-related` - -## Execution Process - -``` -Input Parsing: - ├─ Parse --type flag (default: quality) - ├─ Parse --archived flag (search in archives) - └─ Parse session-id argument (optional) - -Step 1: Session Resolution - └─ Decision: - ├─ session-id provided + --archived → Search .workflow/archives/ - ├─ session-id provided → Search .workflow/active/ first, then archives - └─ Not provided → Auto-detect from .workflow/active/ - -Step 2: Validation - ├─ Check session directory exists (active or archived) - └─ Check for completed implementation (.summaries/IMPL-*.md exists) - -Step 3: Type Check - └─ Decision: - ├─ type=docs → Redirect to /workflow:tools:docs - └─ Other types → Continue to analysis - -Step 4: Model Analysis Phase - ├─ Load context (summaries, test results, changed files) - └─ Perform specialized review by type: - ├─ security → Security patterns + Gemini analysis - ├─ architecture → Qwen architecture analysis - ├─ quality → Gemini code quality analysis - └─ action-items → Requirements verification - -Step 5: Generate Report - └─ Output: REVIEW-{type}.md -``` - -## Execution Template - -```bash -#!/bin/bash -# Optional specialized review for completed implementation - -# Step 1: Session ID resolution and location detection -if [ -n "$SESSION_ARG" ]; then - sessionId="$SESSION_ARG" -else - sessionId=$(find .workflow/active/ -name "WFS-*" -type d | head -1 | xargs basename) -fi - -# Step 2: Resolve session path (active or archived) -# Priority: --archived flag → active → archives -if [ -n "$ARCHIVED_FLAG" ]; then - sessionPath=".workflow/archives/${sessionId}" -elif [ -d ".workflow/active/${sessionId}" ]; then - sessionPath=".workflow/active/${sessionId}" -elif [ -d ".workflow/archives/${sessionId}" ]; then - sessionPath=".workflow/archives/${sessionId}" - echo "Note: Session found in archives, running review on archived session" -else - echo "Session ${sessionId} not found in active or archives" - exit 1 -fi - -# Check for completed tasks -if [ ! -d "${sessionPath}/.summaries" ] || [ -z "$(find ${sessionPath}/.summaries/ -name "IMPL-*.md" -type f 2>/dev/null)" ]; then - echo "No completed implementation found. Complete implementation first" - exit 1 -fi - -# Step 3: Determine review type (default: quality) -review_type="${TYPE_ARG:-quality}" - -# Redirect docs review to specialized command -if [ "$review_type" = "docs" ]; then - echo "For documentation generation, please use:" - echo " /workflow:tools:docs" - echo "" - echo "The docs command provides:" - echo " - Hierarchical architecture documentation" - echo " - API documentation generation" - echo " - Documentation structure analysis" - exit 0 -fi - -# Step 4: Analysis handover → Model takes control -# BASH_EXECUTION_STOPS → MODEL_ANALYSIS_BEGINS -``` - -### Model Analysis Phase - -After bash validation, the model takes control to: - -1. **Load Context**: Read completed task summaries and changed files - ```bash - # Load implementation summaries (iterate through .summaries/ directory) - for summary in ${sessionPath}/.summaries/*.md; do - cat "$summary" - done - - # Load test results (if available) - for test_summary in ${sessionPath}/.summaries/TEST-FIX-*.md 2>/dev/null; do - cat "$test_summary" - done - - # Get changed files - git log --since="$(cat ${sessionPath}/workflow-session.json | jq -r .created_at)" --name-only --pretty=format: | sort -u - ``` - -2. **Perform Specialized Review**: Based on `review_type` - - **Security Review** (`--type=security`): - - Use ripgrep for security patterns: - ```bash - rg "password|token|secret|auth" -g "*.{ts,js,py}" - rg "eval|exec|innerHTML|dangerouslySetInnerHTML" -g "*.{ts,js,tsx}" - ``` - - Use Gemini for security analysis: - ```bash - ccw cli -p " - PURPOSE: Security audit of completed implementation - TASK: Review code for security vulnerabilities, insecure patterns, auth/authz issues - CONTEXT: @.summaries/IMPL-*.md,../.. @../../project-tech.json @../../project-guidelines.json - EXPECTED: Security findings report with severity levels - RULES: Focus on OWASP Top 10, authentication, authorization, data validation, injection risks - " --tool gemini --mode write --cd ${sessionPath} - ``` - - **Architecture Review** (`--type=architecture`): - - Use Qwen for architecture analysis: - ```bash - ccw cli -p " - PURPOSE: Architecture compliance review - TASK: Evaluate adherence to architectural patterns, identify technical debt, review design decisions - CONTEXT: @.summaries/IMPL-*.md,../.. @../../project-tech.json @../../project-guidelines.json - EXPECTED: Architecture assessment with recommendations - RULES: Check for patterns, separation of concerns, modularity, scalability - " --tool qwen --mode write --cd ${sessionPath} - ``` - - **Quality Review** (`--type=quality`): - - Use Gemini for code quality: - ```bash - ccw cli -p " - PURPOSE: Code quality and best practices review - TASK: Assess code readability, maintainability, adherence to best practices - CONTEXT: @.summaries/IMPL-*.md,../.. @../../project-tech.json @../../project-guidelines.json - EXPECTED: Quality assessment with improvement suggestions - RULES: Check for code smells, duplication, complexity, naming conventions - " --tool gemini --mode write --cd ${sessionPath} - ``` - - **Action Items Review** (`--type=action-items`): - - Verify all requirements and acceptance criteria met: - ```bash - # Load task requirements and acceptance criteria - for task_file in ${sessionPath}/.task/*.json; do - cat "$task_file" | jq -r ' - "Task: " + .id + "\n" + - "Requirements: " + .description + "\n" + - "Acceptance: " + (.convergence.criteria | join(", ")) - ' - done - - # Check implementation summaries against requirements - ccw cli -p " - PURPOSE: Verify all requirements and acceptance criteria are met - TASK: Cross-check implementation summaries against original requirements - CONTEXT: @.task/IMPL-*.json,.summaries/IMPL-*.md,../.. @../../project-tech.json @../../project-guidelines.json - EXPECTED: - - Requirements coverage matrix - - Acceptance criteria verification - - Missing/incomplete action items - - Pre-deployment readiness assessment - RULES: - - Check each requirement has corresponding implementation - - Verify all acceptance criteria are met - - Flag any incomplete or missing action items - - Assess deployment readiness - " --tool gemini --mode write --cd ${sessionPath} - ``` - - -3. **Generate Review Report**: Create structured report - ```markdown - # Review Report: ${review_type} - - **Session**: ${sessionId} - **Date**: $(date) - **Type**: ${review_type} - - ## Summary - - Tasks Reviewed: [count IMPL tasks] - - Files Changed: [count files] - - Severity: [High/Medium/Low] - - ## Findings - - ### Critical Issues - - [Issue 1 with file:line reference] - - [Issue 2 with file:line reference] - - ### Recommendations - - [Recommendation 1] - - [Recommendation 2] - - ### Positive Observations - - [Good pattern observed] - - ## Action Items - - [ ] [Action 1] - - [ ] [Action 2] - ``` - -4. **Output Files**: - ```bash - # Save review report - Write(${sessionPath}/REVIEW-${review_type}.md) - - # Update session metadata - # (optional) Update workflow-session.json with review status - ``` - -5. **Optional: Update Memory** (if docs review or significant findings): - ```bash - # If architecture or quality issues found, suggest memory update - if [ "$review_type" = "architecture" ] || [ "$review_type" = "quality" ]; then - echo "Consider updating project documentation:" - echo " /update-memory-related" - fi - ``` - -## Usage Examples - -```bash -# General quality review after implementation -/workflow:review - -# Security audit before deployment -/workflow:review --type=security - -# Architecture review for specific session -/workflow:review --type=architecture WFS-payment-integration - -# Review an archived session (auto-detects if not in active) -/workflow:review --type=security WFS-old-feature - -# Explicitly review archived session -/workflow:review --archived --type=quality WFS-completed-feature - -# Documentation review -/workflow:review --type=docs -``` - -## Features - -- **Simple Validation**: Check session exists and has completed tasks -- **No Complex Orchestration**: Direct analysis, no multi-phase pipeline -- **Specialized Reviews**: Different prompts and tools for different review types -- **Archived Session Support**: Review archived sessions with `--archived` flag or auto-detection -- **MCP Integration**: Fast code search for security and architecture patterns -- **CLI Tool Integration**: Gemini for analysis, Qwen for architecture -- **Structured Output**: Markdown reports with severity levels and action items -- **Optional Memory Update**: Suggests documentation updates for significant findings - -## Integration with Workflow - -``` -Standard Workflow: - plan -> execute -> test-gen -> execute (complete) - -Optional Review (when needed): - plan -> execute -> test-gen -> execute -> review (security/architecture/docs) -``` - -**When to Use**: -- Before production deployment (security review + action-items review) -- After major feature (architecture review) -- Before code freeze (quality review) -- Pre-deployment verification (action-items review) - -**When NOT to Use**: -- Regular development (tests are sufficient) -- Simple bug fixes (test-fix-agent handles it) -- Minor changes (update-memory-related is enough) - -## Post-Review Action - -After review completion, prompt user: -``` -Review complete. Would you like to complete and archive this session? -→ Run /workflow:session:complete to archive with lessons learned -``` diff --git a/.claude/skills/workflow-execute/SKILL.md b/.claude/skills/workflow-execute/SKILL.md index cdeb4556..a8ddb016 100644 --- a/.claude/skills/workflow-execute/SKILL.md +++ b/.claude/skills/workflow-execute/SKILL.md @@ -116,14 +116,21 @@ Phase 5: Completion ├─ Update task statuses in JSON files ├─ Generate summaries └─ AskUserQuestion: Choose next step - ├─ "Enter Review" → /workflow:review + ├─ "Enter Review" → Phase 6 └─ "Complete Session" → /workflow:session:complete +Phase 6: Post-Implementation Review (Optional) + └─ Ref: phases/06-review.md + ├─ Select review type (quality/security/architecture/action-items) + ├─ CLI-assisted analysis (Gemini/Qwen) + ├─ Generate REVIEW-{type}.md report + └─ Post-review: another review or complete session + Resume Mode (--resume-session): ├─ Skip Phase 1 & Phase 2 └─ Entry Point: Phase 3 (TodoWrite Generation) ├─ Update session status to "active" (if not already) - └─ Continue: Phase 4 → Phase 5 + └─ Continue: Phase 4 → Phase 5 → [Phase 6] ``` ## Execution Lifecycle @@ -346,7 +353,7 @@ if (autoYes) { ``` **Based on user selection**: -- **"Enter Review"**: Execute `/workflow:review` +- **"Enter Review"**: Execute Phase 6 → `Ref: phases/06-review.md` - **"Complete Session"**: Execute `/workflow:session:complete` ### Post-Completion Expansion @@ -532,6 +539,12 @@ meta.agent missing → Infer from meta.type: - "docs" → @doc-generator ``` +## Phase Reference Documents + +| Phase | Document | Purpose | +|-------|----------|---------| +| 6 | [phases/06-review.md](phases/06-review.md) | Post-implementation specialized review (security/architecture/quality/action-items) | + ## Workflow File Structure Reference ``` .workflow/active/WFS-[topic-slug]/ diff --git a/.claude/skills/workflow-execute/phases/06-review.md b/.claude/skills/workflow-execute/phases/06-review.md new file mode 100644 index 00000000..f64d1392 --- /dev/null +++ b/.claude/skills/workflow-execute/phases/06-review.md @@ -0,0 +1,212 @@ +# Phase 6: Post-Implementation Review + +Optional specialized review for completed implementations. In the standard workflow, **passing tests = approved code**. This phase executes only when user selects "Enter Review" in Phase 5 completion. + +## Objective + +- Perform specialized review (security/architecture/quality/action-items) on completed implementation +- Generate structured review report with severity levels and action items +- Provide CLI-assisted analysis using Gemini/Qwen for deep review + +## Philosophy: "Tests Are the Review" + +- **Default**: All tests pass → Code approved +- **Optional**: This phase for specialized reviews: + - Security audits (vulnerabilities, auth/authz) + - Architecture compliance (patterns, technical debt) + - Action items verification (requirements met, acceptance criteria) + - Code quality assessment (best practices, maintainability) + +## Review Types + +| Type | Focus | Use Case | +|------|-------|----------| +| `quality` | Code quality, best practices, maintainability | Default general review | +| `security` | Security vulnerabilities, data handling, access control | Security audits | +| `architecture` | Architectural patterns, technical debt, design decisions | Architecture compliance | +| `action-items` | Requirements met, acceptance criteria verified | Pre-deployment verification | + +**Notes**: +- For documentation generation, use `/workflow:tools:docs` +- For CLAUDE.md updates, use `/update-memory-related` + +## Execution + +### Step 6.1: Review Type Selection + +Prompt user to select review type: + +```javascript +AskUserQuestion({ + questions: [{ + question: "Select review type:", + header: "Review Type", + multiSelect: false, + options: [ + { label: "Quality (Recommended)", description: "Code quality, best practices, maintainability" }, + { label: "Security", description: "Security vulnerabilities, data handling, access control" }, + { label: "Architecture", description: "Architectural patterns, technical debt, design decisions" }, + { label: "Action Items", description: "Requirements met, acceptance criteria verified" } + ] + }] +}) +``` + +**Auto Mode** (`--yes`): Skip selection, default to `quality`. + +### Step 6.2: Validation + +```bash +# Verify completed implementation exists +sessionPath=".workflow/active/${sessionId}" + +if [ ! -d "${sessionPath}/.summaries" ] || [ -z "$(find ${sessionPath}/.summaries/ -name "IMPL-*.md" -type f 2>/dev/null)" ]; then + echo "No completed implementation found. Complete implementation first." + exit 1 +fi +``` + +### Step 6.3: Context Loading + +```bash +# Load implementation summaries +for summary in ${sessionPath}/.summaries/*.md; do + cat "$summary" +done + +# Load test results (if available) +for test_summary in ${sessionPath}/.summaries/TEST-FIX-*.md 2>/dev/null; do + cat "$test_summary" +done + +# Get changed files +git log --since="$(cat ${sessionPath}/workflow-session.json | jq -r .created_at)" --name-only --pretty=format: | sort -u +``` + +### Step 6.4: Specialized Review Analysis + +Based on `review_type`, execute the corresponding analysis: + +**Security Review** (`security`): +```bash +# Pattern scan +rg "password|token|secret|auth" -g "*.{ts,js,py}" +rg "eval|exec|innerHTML|dangerouslySetInnerHTML" -g "*.{ts,js,tsx}" + +# Gemini security analysis +ccw cli -p " +PURPOSE: Security audit of completed implementation +TASK: Review code for security vulnerabilities, insecure patterns, auth/authz issues +CONTEXT: @.summaries/IMPL-*.md,../.. @../../project-tech.json @../../project-guidelines.json +EXPECTED: Security findings report with severity levels +RULES: Focus on OWASP Top 10, authentication, authorization, data validation, injection risks +" --tool gemini --mode write --cd ${sessionPath} +``` + +**Architecture Review** (`architecture`): +```bash +ccw cli -p " +PURPOSE: Architecture compliance review +TASK: Evaluate adherence to architectural patterns, identify technical debt, review design decisions +CONTEXT: @.summaries/IMPL-*.md,../.. @../../project-tech.json @../../project-guidelines.json +EXPECTED: Architecture assessment with recommendations +RULES: Check for patterns, separation of concerns, modularity, scalability +" --tool qwen --mode write --cd ${sessionPath} +``` + +**Quality Review** (`quality`): +```bash +ccw cli -p " +PURPOSE: Code quality and best practices review +TASK: Assess code readability, maintainability, adherence to best practices +CONTEXT: @.summaries/IMPL-*.md,../.. @../../project-tech.json @../../project-guidelines.json +EXPECTED: Quality assessment with improvement suggestions +RULES: Check for code smells, duplication, complexity, naming conventions +" --tool gemini --mode write --cd ${sessionPath} +``` + +**Action Items Review** (`action-items`): +```bash +# Load task requirements and acceptance criteria +for task_file in ${sessionPath}/.task/*.json; do + cat "$task_file" | jq -r ' + "Task: " + .id + "\n" + + "Requirements: " + .description + "\n" + + "Acceptance: " + (.convergence.criteria | join(", ")) + ' +done + +# Cross-check implementation against requirements +ccw cli -p " +PURPOSE: Verify all requirements and acceptance criteria are met +TASK: Cross-check implementation summaries against original requirements +CONTEXT: @.task/IMPL-*.json,.summaries/IMPL-*.md,../.. @../../project-tech.json @../../project-guidelines.json +EXPECTED: +- Requirements coverage matrix +- Acceptance criteria verification +- Missing/incomplete action items +- Pre-deployment readiness assessment +RULES: +- Check each requirement has corresponding implementation +- Verify all acceptance criteria are met +- Flag any incomplete or missing action items +- Assess deployment readiness +" --tool gemini --mode write --cd ${sessionPath} +``` + +### Step 6.5: Generate Review Report + +Write structured report to session directory: + +```markdown +# Review Report: ${review_type} + +**Session**: ${sessionId} +**Date**: $(date) +**Type**: ${review_type} + +## Summary +- Tasks Reviewed: [count IMPL tasks] +- Files Changed: [count files] +- Severity: [High/Medium/Low] + +## Findings + +### Critical Issues +- [Issue 1 with file:line reference] + +### Recommendations +- [Recommendation 1] + +### Positive Observations +- [Good pattern observed] + +## Action Items +- [ ] [Action 1] +- [ ] [Action 2] +``` + +**Output**: `${sessionPath}/REVIEW-${review_type}.md` + +### Step 6.6: Post-Review Prompt + +``` +Review complete. Would you like to: +→ Run another review type +→ Complete session: /workflow:session:complete +``` + +If architecture or quality issues found, suggest: +``` +Consider updating project documentation: +→ /update-memory-related +``` + +## Output + +- **File**: `${sessionPath}/REVIEW-${review_type}.md` +- **TodoWrite**: Mark Phase 6 completed + +## Next Phase + +Return to orchestrator for session completion or additional review cycles. diff --git a/ccw/frontend/src/components/shared/Flowchart.tsx b/ccw/frontend/src/components/shared/Flowchart.tsx index 377b0c27..a9fd1f47 100644 --- a/ccw/frontend/src/components/shared/Flowchart.tsx +++ b/ccw/frontend/src/components/shared/Flowchart.tsx @@ -54,8 +54,9 @@ const StatusIcon: React.FC<{ status?: string; className?: string }> = ({ status, const CustomNode: React.FC<{ data: FlowchartNodeData }> = ({ data }) => { const isPreAnalysis = data.type === 'pre-analysis'; const isSection = data.type === 'section'; - const isCompleted = data.status === 'completed'; - const isInProgress = data.status === 'in_progress'; + const showStatus = data.showStepStatus !== false; + const isCompleted = showStatus && data.status === 'completed'; + const isInProgress = showStatus && data.status === 'in_progress'; if (isSection) { return ( @@ -101,14 +102,14 @@ const CustomNode: React.FC<{ data: FlowchartNodeData }> = ({ data }) => { - {isCompleted ? : data.step} + {isCompleted && showStatus ? : data.step}
{data.label} - {data.status && data.status !== 'pending' && ( + {showStatus && data.status && data.status !== 'pending' && ( )}
@@ -141,12 +142,13 @@ const nodeTypes: NodeTypes = { export interface FlowchartProps { flowControl: FlowControl; className?: string; + showStepStatus?: boolean; } /** * Flowchart component for visualizing implementation approach */ -export function Flowchart({ flowControl, className = '' }: FlowchartProps) { +export function Flowchart({ flowControl, className = '', showStepStatus = true }: FlowchartProps) { const preAnalysis = flowControl.pre_analysis || []; const implSteps = flowControl.implementation_approach || []; @@ -185,6 +187,7 @@ export function Flowchart({ flowControl, className = '' }: FlowchartProps) { step: `P${idx + 1}`, output: step.output_to, type: 'pre-analysis' as const, + showStepStatus, }, }); @@ -308,6 +311,7 @@ export function Flowchart({ flowControl, className = '' }: FlowchartProps) { type: 'implementation' as const, dependsOn, status: stepStatus, + showStepStatus, }, }); @@ -411,10 +415,12 @@ export function Flowchart({ flowControl, className = '' }: FlowchartProps) { nodeColor={(node) => { const data = node.data as FlowchartNodeData; if (data.type === 'section') return '#9ca3af'; - // Status-based colors - if (data.status === 'completed') return '#22c55e'; // green-500 - if (data.status === 'in_progress') return '#f59e0b'; // amber-500 - if (data.status === 'blocked') return '#ef4444'; // red-500 + // Status-based colors (only when status tracking is enabled) + if (data.showStepStatus !== false) { + if (data.status === 'completed') return '#22c55e'; // green-500 + if (data.status === 'in_progress') return '#f59e0b'; // amber-500 + if (data.status === 'blocked') return '#ef4444'; // red-500 + } if (data.type === 'pre-analysis') return '#f59e0b'; return '#3b82f6'; }} diff --git a/ccw/frontend/src/components/shared/TaskDrawer.tsx b/ccw/frontend/src/components/shared/TaskDrawer.tsx index 21627023..a70693b7 100644 --- a/ccw/frontend/src/components/shared/TaskDrawer.tsx +++ b/ccw/frontend/src/components/shared/TaskDrawer.tsx @@ -382,7 +382,7 @@ export function TaskDrawer({ task, isOpen, onClose }: TaskDrawerProps) { {/* Flowchart Tab */} {hasFlowchart && ( - + )} diff --git a/ccw/frontend/src/components/terminal-dashboard/AgentList.tsx b/ccw/frontend/src/components/terminal-dashboard/AgentList.tsx index 07c4a421..6b9dd441 100644 --- a/ccw/frontend/src/components/terminal-dashboard/AgentList.tsx +++ b/ccw/frontend/src/components/terminal-dashboard/AgentList.tsx @@ -95,8 +95,8 @@ export function AgentList() { return (
- {/* Section header */} -
+ {/* Section header with visual separation */} +

{formatMessage({ id: 'terminalDashboard.agentList.title' })} @@ -110,8 +110,8 @@ export function AgentList() { {/* Plan list or empty state */} {planEntries.length === 0 ? ( -
-

+

+

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

diff --git a/ccw/frontend/src/components/terminal-dashboard/GlobalKpiBar.tsx b/ccw/frontend/src/components/terminal-dashboard/GlobalKpiBar.tsx deleted file mode 100644 index 9661f21e..00000000 --- a/ccw/frontend/src/components/terminal-dashboard/GlobalKpiBar.tsx +++ /dev/null @@ -1,138 +0,0 @@ -// ======================================== -// GlobalKpiBar Component -// ======================================== -// Top bar showing 3 KPI metrics spanning the full page width. -// Metrics: -// 1. Active Sessions - count from sessionManagerStore (wraps cliSessionStore) -// 2. Queue Size - pending/ready items count from useIssueQueue React Query hook -// 3. Alert Count - total alerts from all terminalMetas -// -// Per design spec (V-001): consumes sessionManagerStore, NOT cliSessionStore directly. - -import { useMemo } from 'react'; -import { useIntl } from 'react-intl'; -import { Activity, ListChecks, AlertTriangle } from 'lucide-react'; -import { cn } from '@/lib/utils'; -import { - useSessionManagerStore, - selectGroups, - selectTerminalMetas, -} from '@/stores/sessionManagerStore'; -import { useIssueQueue } from '@/hooks/useIssues'; -import type { TerminalStatus } from '@/types/terminal-dashboard'; - -// ========== KPI Item ========== - -function KpiItem({ - icon: Icon, - label, - value, - variant = 'default', -}: { - icon: React.ComponentType<{ className?: string }>; - label: string; - value: number; - variant?: 'default' | 'primary' | 'warning' | 'destructive'; -}) { - const variantStyles = { - default: 'text-muted-foreground', - primary: 'text-primary', - warning: 'text-warning', - destructive: 'text-destructive', - }; - - return ( -
- - {label} - - {value} - -
- ); -} - -// ========== Main Component ========== - -export function GlobalKpiBar() { - const { formatMessage } = useIntl(); - const groups = useSessionManagerStore(selectGroups); - const terminalMetas = useSessionManagerStore(selectTerminalMetas); - const queueQuery = useIssueQueue(); - - // Derive active session count from sessionManagerStore groups - const sessionCount = useMemo(() => { - const allSessionIds = groups.flatMap((g) => g.sessionIds); - // Count sessions that have 'active' status in terminalMetas - let activeCount = 0; - for (const sid of allSessionIds) { - const meta = terminalMetas[sid]; - const status: TerminalStatus = meta?.status ?? 'idle'; - if (status === 'active') { - activeCount++; - } - } - // If no sessions are managed in groups, return total unique session IDs - // This ensures the KPI shows meaningful data even before grouping - return activeCount > 0 ? activeCount : allSessionIds.length; - }, [groups, terminalMetas]); - - // Derive queue pending count from useIssueQueue data - const queuePendingCount = useMemo(() => { - const queue = queueQuery.data; - if (!queue) return 0; - // Count all items across grouped_items - let count = 0; - if (queue.grouped_items) { - for (const items of Object.values(queue.grouped_items)) { - count += items.length; - } - } - // Also count ungrouped tasks and solutions - if (queue.tasks) count += queue.tasks.length; - if (queue.solutions) count += queue.solutions.length; - return count; - }, [queueQuery.data]); - - // Derive total alert count from all terminalMetas - const totalAlerts = useMemo(() => { - let count = 0; - for (const meta of Object.values(terminalMetas)) { - count += meta.alertCount; - } - return count; - }, [terminalMetas]); - - return ( -
- - -
- - 0 ? 'warning' : 'default'} - /> - -
- - 0 ? 'destructive' : 'default'} - /> - - - {formatMessage({ id: 'terminalDashboard.page.title' })} - -
- ); -} diff --git a/ccw/frontend/src/components/terminal-dashboard/IssuePanel.tsx b/ccw/frontend/src/components/terminal-dashboard/IssuePanel.tsx index fcd65414..9061975c 100644 --- a/ccw/frontend/src/components/terminal-dashboard/IssuePanel.tsx +++ b/ccw/frontend/src/components/terminal-dashboard/IssuePanel.tsx @@ -85,7 +85,7 @@ function IssueItem({
-
- +
+

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

diff --git a/ccw/frontend/src/components/terminal-dashboard/TerminalTabBar.tsx b/ccw/frontend/src/components/terminal-dashboard/TerminalTabBar.tsx index e702a13c..0e98b85b 100644 --- a/ccw/frontend/src/components/terminal-dashboard/TerminalTabBar.tsx +++ b/ccw/frontend/src/components/terminal-dashboard/TerminalTabBar.tsx @@ -4,8 +4,9 @@ // Horizontal tab strip for terminal sessions in the Terminal Dashboard. // Renders tabs from sessionManagerStore groups with status indicators and alert badges. +import { useMemo } from 'react'; import { useIntl } from 'react-intl'; -import { Terminal } from 'lucide-react'; +import { Terminal, AlertTriangle } from 'lucide-react'; import { cn } from '@/lib/utils'; import { useSessionManagerStore, @@ -35,6 +36,15 @@ export function TerminalTabBar() { // Flatten all sessionIds from all groups const allSessionIds = groups.flatMap((g) => g.sessionIds); + // Total alerts across all terminals + const totalAlerts = useMemo(() => { + let count = 0; + for (const meta of Object.values(terminalMetas)) { + count += meta.alertCount; + } + return count; + }, [terminalMetas]); + if (allSessionIds.length === 0) { return (
@@ -88,6 +98,16 @@ export function TerminalTabBar() { ); })} + + {/* Total alerts indicator at right end */} + {totalAlerts > 0 && ( +
+ + + {totalAlerts > 99 ? '99+' : totalAlerts} + +
+ )}
); } diff --git a/ccw/frontend/src/components/terminal-dashboard/TerminalWorkbench.tsx b/ccw/frontend/src/components/terminal-dashboard/TerminalWorkbench.tsx index 816c3633..b34c5508 100644 --- a/ccw/frontend/src/components/terminal-dashboard/TerminalWorkbench.tsx +++ b/ccw/frontend/src/components/terminal-dashboard/TerminalWorkbench.tsx @@ -2,23 +2,139 @@ // TerminalWorkbench Component // ======================================== // Container for the right panel of the Terminal Dashboard. -// Combines TerminalTabBar (tab switching) and TerminalInstance (xterm.js) -// in a flex-col layout. MVP scope: single terminal view (1x1 grid). +// Combines TerminalTabBar (tab switching) and TerminalInstance (xterm.js). +// When no terminal is active, shows selected issue detail preview +// or a compact empty state with action hints. +import { useMemo } from 'react'; import { useIntl } from 'react-intl'; -import { Terminal } from 'lucide-react'; +import { + Terminal, + CircleDot, + Tag, + Clock, + User, +} from 'lucide-react'; +import { Badge } from '@/components/ui/Badge'; +import { cn } from '@/lib/utils'; import { useSessionManagerStore, selectSessionManagerActiveTerminalId, } from '@/stores/sessionManagerStore'; +import { + useIssueQueueIntegrationStore, + selectSelectedIssueId, +} from '@/stores/issueQueueIntegrationStore'; +import { useIssues } from '@/hooks/useIssues'; +import type { Issue } from '@/lib/api'; import { TerminalTabBar } from './TerminalTabBar'; import { TerminalInstance } from './TerminalInstance'; +// ========== Priority Styles ========== + +const PRIORITY_VARIANT: Record = { + critical: 'destructive', + high: 'warning', + medium: 'info', + low: 'secondary', +}; + +const STATUS_COLORS: Record = { + open: 'text-info', + in_progress: 'text-warning', + resolved: 'text-success', + closed: 'text-muted-foreground', + completed: 'text-success', +}; + +// ========== Issue Detail Preview ========== + +function IssueDetailPreview({ issue }: { issue: Issue }) { + const { formatMessage } = useIntl(); + + return ( +
+
+ {/* Header hint */} +

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

+ + {/* Title + Status */} +
+
+ +

+ {issue.title} +

+
+
+ + {issue.priority} + + {issue.id} +
+
+ + {/* Context / Description */} + {issue.context && ( +
+

+ {issue.context} +

+
+ )} + + {/* Metadata rows */} +
+ {issue.labels && issue.labels.length > 0 && ( +
+ +
+ {issue.labels.map((label) => ( + + {label} + + ))} +
+
+ )} + {issue.assignee && ( +
+ + {issue.assignee} +
+ )} + {issue.createdAt && ( +
+ + {new Date(issue.createdAt).toLocaleString()} +
+ )} +
+ + {/* Hint */} +

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

+
+
+ ); +} + // ========== Component ========== export function TerminalWorkbench() { const { formatMessage } = useIntl(); const activeTerminalId = useSessionManagerStore(selectSessionManagerActiveTerminalId); + const selectedIssueId = useIssueQueueIntegrationStore(selectSelectedIssueId); + const { issues } = useIssues(); + + // Find selected issue for preview + const selectedIssue = useMemo(() => { + if (!selectedIssueId) return null; + return issues.find((i) => i.id === selectedIssueId) ?? null; + }, [selectedIssueId, issues]); return (
@@ -30,11 +146,14 @@ export function TerminalWorkbench() {
+ ) : selectedIssue ? ( + /* Issue detail preview when no terminal but issue is selected */ + ) : ( - /* Empty state when no terminal is selected */ + /* Compact empty state */
- +

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

diff --git a/ccw/frontend/src/locales/en/terminal-dashboard.json b/ccw/frontend/src/locales/en/terminal-dashboard.json index 8ad7eba5..ff531c9b 100644 --- a/ccw/frontend/src/locales/en/terminal-dashboard.json +++ b/ccw/frontend/src/locales/en/terminal-dashboard.json @@ -20,6 +20,12 @@ "noSelection": "Select an item to view details", "associationChain": "Association Chain" }, + "bottomPanel": { + "queueTab": "Queue", + "inspectorTab": "Inspector", + "collapse": "Collapse panel", + "expand": "Expand panel" + }, "sessionTree": { "createGroup": "New Group", "groupNamePrompt": "Enter group name", @@ -67,7 +73,9 @@ }, "workbench": { "noTerminal": "No terminal selected", - "noTerminalHint": "Select a session from the tab bar or create a new one" + "noTerminalHint": "Select a session from the tab bar or create a new one", + "issuePreview": "Issue Preview", + "issuePreviewHint": "Select a terminal session or send this issue to the queue to begin work" }, "placeholder": { "sessionTree": "Session groups will appear here", diff --git a/ccw/frontend/src/locales/zh/terminal-dashboard.json b/ccw/frontend/src/locales/zh/terminal-dashboard.json index 2682ed5c..95e58416 100644 --- a/ccw/frontend/src/locales/zh/terminal-dashboard.json +++ b/ccw/frontend/src/locales/zh/terminal-dashboard.json @@ -20,6 +20,12 @@ "noSelection": "选择一个项目以查看详情", "associationChain": "关联链路" }, + "bottomPanel": { + "queueTab": "队列", + "inspectorTab": "检查器", + "collapse": "折叠面板", + "expand": "展开面板" + }, "sessionTree": { "createGroup": "新建分组", "groupNamePrompt": "输入分组名称", @@ -67,7 +73,9 @@ }, "workbench": { "noTerminal": "未选择终端", - "noTerminalHint": "从标签栏选择会话或创建新会话" + "noTerminalHint": "从标签栏选择会话或创建新会话", + "issuePreview": "问题预览", + "issuePreviewHint": "选择终端会话或将此问题发送到队列以开始工作" }, "placeholder": { "sessionTree": "会话分组将在此显示", diff --git a/ccw/frontend/src/pages/session-detail/TaskListTab.tsx b/ccw/frontend/src/pages/session-detail/TaskListTab.tsx index 04a67274..05509c00 100644 --- a/ccw/frontend/src/pages/session-detail/TaskListTab.tsx +++ b/ccw/frontend/src/pages/session-detail/TaskListTab.tsx @@ -44,6 +44,14 @@ export function TaskListTab({ session, onTaskClick }: TaskListTabProps) { const { formatMessage } = useIntl(); const tasks = session.tasks || []; + + // Detect if session tasks support status tracking (new format has explicit status/status_history in raw data) + const hasStatusTracking = tasks.some((t) => { + const raw = (t as unknown as Record)._raw as Record | undefined; + const source = (raw?._raw as Record) || raw; + return source ? (source.status !== undefined || source.status_history !== undefined) : false; + }); + const completed = tasks.filter((t) => t.status === 'completed').length; const inProgress = tasks.filter((t) => t.status === 'in_progress').length; const pending = tasks.filter((t) => t.status === 'pending').length; @@ -165,18 +173,20 @@ export function TaskListTab({ session, onTaskClick }: TaskListTabProps) { return (
- {/* Stats Bar with Bulk Actions */} - + {/* Stats Bar with Bulk Actions (only for tasks with status tracking) */} + {hasStatusTracking && ( + + )} {/* Tasks List */} {localTasks.length === 0 ? ( @@ -236,12 +246,14 @@ export function TaskListTab({ session, onTaskClick }: TaskListTabProps) { {/* Right: Status and Meta info */}
- {/* Row 1: Status dropdown */} - handleTaskStatusChange(task.task_id, newStatus)} - size="sm" - /> + {/* Row 1: Status dropdown (only for tasks with status tracking) */} + {hasStatusTracking && ( + handleTaskStatusChange(task.task_id, newStatus)} + size="sm" + /> + )} {/* Row 2: Meta info */}