From 603bc00bca35c6081452ad04d27a96b2acbac185 Mon Sep 17 00:00:00 2001 From: catlog22 Date: Mon, 29 Dec 2025 22:41:10 +0800 Subject: [PATCH] refactor(issue): enhance documentation and add core guidelines for data access --- .claude/commands/issue/new.md | 2 +- .claude/commands/issue/plan.md | 48 +++++++++++++++++++++------- .claude/commands/issue/queue.md | 36 ++++++++++++++++++--- ccw/src/cli.ts | 2 +- ccw/src/commands/issue.ts | 56 ++++++++++++++++++++++++++++++--- 5 files changed, 122 insertions(+), 22 deletions(-) diff --git a/.claude/commands/issue/new.md b/.claude/commands/issue/new.md index 06887f81..4c27d36f 100644 --- a/.claude/commands/issue/new.md +++ b/.claude/commands/issue/new.md @@ -16,7 +16,7 @@ Clear Input (GitHub URL, structured text) → Direct creation Unclear Input (vague description) → Minimal clarifying questions ``` -## Issue Structure (Simplified) +## Issue Structure ```typescript interface Issue { diff --git a/.claude/commands/issue/plan.md b/.claude/commands/issue/plan.md index f990362f..ad557f80 100644 --- a/.claude/commands/issue/plan.md +++ b/.claude/commands/issue/plan.md @@ -14,17 +14,39 @@ Unified planning command using **issue-plan-agent** that combines exploration an **Behavior:** - Single solution per issue → auto-bind - Multiple solutions → return for user selection -- Agent handles file generation +- Agent handles file generation + +## Core Guidelines + +**⚠️ Data Access Principle**: Issues and solutions files can grow very large. To avoid context overflow: + +| Operation | Correct | Incorrect | +|-----------|---------|-----------| +| List issues (brief) | `ccw issue list --status pending --brief` | `Read('issues.jsonl')` | +| Read issue details | `ccw issue status --json` | `Read('issues.jsonl')` | +| Update status | `ccw issue update --status ...` | Direct file edit | +| Bind solution | `ccw issue bind ` | Direct file edit | + +**Output Options**: +- `--brief`: JSON with minimal fields (id, title, status, priority, tags) +- `--json`: Full JSON (agent use only) + +**Orchestration vs Execution**: +- **Command (orchestrator)**: Use `--brief` for minimal context +- **Agent (executor)**: Fetch full details → `ccw issue status --json` + +**ALWAYS** use CLI commands for CRUD operations. **NEVER** read entire `issues.jsonl` or `solutions/*.jsonl` directly. ## Usage ```bash -/issue:plan [,,...] [FLAGS] +/issue:plan [[,,...]] [FLAGS] # Examples +/issue:plan # Default: --all-pending /issue:plan GH-123 # Single issue /issue:plan GH-123,GH-124,GH-125 # Batch (up to 3) -/issue:plan --all-pending # All pending issues +/issue:plan --all-pending # All pending issues (explicit) # Flags --batch-size Max issues per agent batch (default: 3) @@ -62,14 +84,17 @@ Phase 4: Summary ## Implementation -### Phase 1: Issue Loading (ID + Title + Tags) +### Phase 1: Issue Loading (Brief Info Only) ```javascript const batchSize = flags.batchSize || 3; -let issues = []; // {id, title, tags} +let issues = []; // {id, title, tags} - brief info for grouping only -if (flags.allPending) { - // Get pending issues with metadata via CLI (JSON output) +// Default to --all-pending if no input provided +const useAllPending = flags.allPending || !userInput || userInput.trim() === ''; + +if (useAllPending) { + // Get pending issues with brief metadata via CLI const result = Bash(`ccw issue list --status pending,registered --json`).trim(); const parsed = result ? JSON.parse(result) : []; issues = parsed.map(i => ({ id: i.id, title: i.title || '', tags: i.tags || [] })); @@ -80,7 +105,7 @@ if (flags.allPending) { } console.log(`Found ${issues.length} pending issues`); } else { - // Parse comma-separated issue IDs, fetch metadata + // Parse comma-separated issue IDs, fetch brief metadata const ids = userInput.includes(',') ? userInput.split(',').map(s => s.trim()) : [userInput.trim()]; @@ -92,6 +117,7 @@ if (flags.allPending) { issues.push({ id, title: parsed.title || '', tags: parsed.tags || [] }); } } +// Note: Agent fetches full issue content via `ccw issue status --json` // Semantic grouping via Gemini CLI (max 4 issues per group) async function groupBySimilarityGemini(issues) { @@ -172,7 +198,7 @@ ${issueList} 2. Load project context files 3. Explore codebase (ACE semantic search) 4. Plan solution with tasks (schema: solution-schema.json) -5. Create solution: ccw issue solution --data '{...}' +5. Write solution to: .workflow/issues/solutions/{issue-id}.jsonl 6. Single solution → auto-bind; Multiple → return for selection ### Rules @@ -258,8 +284,8 @@ for (let i = 0; i < agentTasks.length; i += MAX_PARALLEL) { ```javascript // Count planned issues via CLI -const plannedIds = Bash(`ccw issue list --status planned --ids`).trim(); -const plannedCount = plannedIds ? plannedIds.split('\n').length : 0; +const planned = JSON.parse(Bash(`ccw issue list --status planned --brief`) || '[]'); +const plannedCount = planned.length; console.log(` ## Done: ${issues.length} issues → ${plannedCount} planned diff --git a/.claude/commands/issue/queue.md b/.claude/commands/issue/queue.md index fc77b026..524e6cf9 100644 --- a/.claude/commands/issue/queue.md +++ b/.claude/commands/issue/queue.md @@ -21,6 +21,29 @@ Queue formation command using **issue-queue-agent** that analyzes all bound solu - Semantic priority calculation per solution (0.0-1.0) - Parallel/Sequential group assignment for solutions +## Core Guidelines + +**⚠️ Data Access Principle**: Issues and queue files can grow very large. To avoid context overflow: + +| Operation | Correct | Incorrect | +|-----------|---------|-----------| +| List issues (brief) | `ccw issue list --status planned --brief` | `Read('issues.jsonl')` | +| List queue (brief) | `ccw issue queue --brief` | `Read('queues/*.json')` | +| Read issue details | `ccw issue status --json` | `Read('issues.jsonl')` | +| Get next item | `ccw issue next --json` | `Read('queues/*.json')` | +| Update status | `ccw issue update --status ...` | Direct file edit | +| Sync from queue | `ccw issue update --from-queue` | Direct file edit | + +**Output Options**: +- `--brief`: JSON with minimal fields (id, status, counts) +- `--json`: Full JSON (agent use only) + +**Orchestration vs Execution**: +- **Command (orchestrator)**: Use `--brief` for minimal context +- **Agent (executor)**: Fetch full details → `ccw issue status --json` + +**ALWAYS** use CLI commands for CRUD operations. **NEVER** read entire `issues.jsonl` or `queues/*.json` directly. + ## Usage @@ -203,15 +226,20 @@ if (result.clarifications?.length > 0) { ### Phase 6: Status Update & Summary -**Status Update** (single command): -```bash -ccw issue update --from-queue [queue-id] --json +**Status Update** (MUST use CLI command, NOT direct file operations): -# Examples +```bash +# Option 1: Batch update from queue (recommended) +ccw issue update --from-queue [queue-id] --json ccw issue update --from-queue --json # Use active queue ccw issue update --from-queue QUE-xxx --json # Use specific queue + +# Option 2: Individual issue update +ccw issue update --status queued ``` +**⚠️ IMPORTANT**: Do NOT directly modify `issues.jsonl`. Always use CLI command to ensure proper validation and history tracking. + **Output** (JSON): ```json { diff --git a/ccw/src/cli.ts b/ccw/src/cli.ts index 789a76f5..343bb288 100644 --- a/ccw/src/cli.ts +++ b/ccw/src/cli.ts @@ -277,7 +277,7 @@ export function run(argv: string[]): void { .option('--priority ', 'Task priority (1-5)') .option('--format ', 'Output format: json, markdown') .option('--json', 'Output as JSON') - .option('--ids', 'List only IDs (one per line, for scripting)') + .option('--brief', 'Brief JSON output (minimal fields)') .option('--force', 'Force operation') // New options for solution/queue management .option('--solution ', 'Solution JSON file path') diff --git a/ccw/src/commands/issue.ts b/ccw/src/commands/issue.ts index 53e3f1f0..6160c933 100644 --- a/ccw/src/commands/issue.ts +++ b/ccw/src/commands/issue.ts @@ -194,7 +194,7 @@ interface IssueOptions { json?: boolean; force?: boolean; fail?: boolean; - ids?: boolean; // List only IDs (one per line) + brief?: boolean; // List brief info only (id, title, status, priority, tags) - JSON format data?: string; // JSON data for create fromQueue?: boolean | string; // Sync statuses from queue (true=active, string=specific queue ID) } @@ -714,9 +714,17 @@ async function listAction(issueId: string | undefined, options: IssueOptions): P issues = issues.filter(i => statuses.includes(i.status)); } - // IDs only mode (one per line, for scripting) - if (options.ids) { - issues.forEach(i => console.log(i.id)); + // Brief mode: minimal fields only (id, title, status, priority, tags, bound_solution_id) + if (options.brief) { + const briefIssues = issues.map(i => ({ + id: i.id, + title: i.title, + status: i.status, + priority: i.priority, + tags: i.tags || [], + bound_solution_id: i.bound_solution_id + })); + console.log(JSON.stringify(briefIssues, null, 2)); return; } @@ -1216,6 +1224,22 @@ async function queueAction(subAction: string | undefined, issueId: string | unde if (subAction === 'list' || subAction === 'history') { const index = readQueueIndex(); + // Brief mode: minimal queue index info + if (options.brief) { + const briefIndex = { + active_queue_id: index.active_queue_id, + queues: index.queues.map(q => ({ + id: q.id, + status: q.status, + issue_ids: q.issue_ids, + total_solutions: q.total_solutions, + completed_solutions: q.completed_solutions + })) + }; + console.log(JSON.stringify(briefIndex, null, 2)); + return; + } + if (options.json) { console.log(JSON.stringify(index, null, 2)); return; @@ -1525,6 +1549,28 @@ async function queueAction(subAction: string | undefined, issueId: string | unde // Show current queue const queue = readActiveQueue(); + // Brief mode: minimal queue info (id, issue_ids, item summaries) + if (options.brief) { + const items = queue.solutions || queue.tasks || []; + const briefQueue = { + id: queue.id, + issue_ids: queue.issue_ids || [], + total: items.length, + pending: items.filter(i => i.status === 'pending').length, + executing: items.filter(i => i.status === 'executing').length, + completed: items.filter(i => i.status === 'completed').length, + items: items.map(i => ({ + item_id: i.item_id, + issue_id: i.issue_id, + solution_id: i.solution_id, + status: i.status, + task_count: i.task_count + })) + }; + console.log(JSON.stringify(briefQueue, null, 2)); + return; + } + if (options.json) { console.log(JSON.stringify(queue, null, 2)); return; @@ -1960,7 +2006,7 @@ export async function issueCommand( console.log(chalk.bold('Options:')); console.log(chalk.gray(' --title Issue/task title')); console.log(chalk.gray(' --status <status> Filter by status (comma-separated)')); - console.log(chalk.gray(' --ids List only IDs (one per line)')); + console.log(chalk.gray(' --brief Brief JSON output (minimal fields)')); console.log(chalk.gray(' --solution <path> Solution JSON file')); console.log(chalk.gray(' --result <json> Execution result')); console.log(chalk.gray(' --reason <text> Failure reason'));