mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-05 01:50:27 +08:00
feat(issue): Enhance queue management with solution-level granularity and improved item identification
This commit is contained in:
@@ -76,18 +76,23 @@ chcp 65001 > $null
|
||||
|
||||
**For task context gathering and analysis, ALWAYS prefer MCP tools**:
|
||||
|
||||
1. **smart_search** - First choice for code discovery
|
||||
- Use `smart_search(query="...")` for semantic/keyword search
|
||||
1. **mcp__ace-tool__search_context** - HIGHEST PRIORITY for code discovery
|
||||
- Semantic search with real-time codebase index
|
||||
- Use for: finding implementations, understanding architecture, locating patterns
|
||||
- Example: `mcp__ace-tool__search_context(project_root_path="/path", query="authentication logic")`
|
||||
|
||||
2. **smart_search** - Fallback for structured search
|
||||
- Use `smart_search(query="...")` for keyword/regex search
|
||||
- Use `smart_search(action="find_files", pattern="*.ts")` for file discovery
|
||||
- Supports modes: `auto`, `hybrid`, `exact`, `ripgrep`
|
||||
|
||||
2. **read_file** - Batch file reading
|
||||
3. **read_file** - Batch file reading
|
||||
- Read multiple files in parallel: `read_file(path="file1.ts")`, `read_file(path="file2.ts")`
|
||||
- Supports glob patterns: `read_file(path="src/**/*.config.ts")`
|
||||
|
||||
**Priority Order**:
|
||||
```
|
||||
smart_search (discovery) → read_file (batch read) → shell commands (fallback)
|
||||
ACE search_context (semantic) → smart_search (structured) → read_file (batch read) → shell commands (fallback)
|
||||
```
|
||||
|
||||
**NEVER** use shell commands (`cat`, `find`, `grep`) when MCP tools are available.
|
||||
@@ -96,7 +101,7 @@ smart_search (discovery) → read_file (batch read) → shell commands (fallback
|
||||
|
||||
**Before**:
|
||||
- [ ] Understand PURPOSE and TASK clearly
|
||||
- [ ] Use smart_search to discover relevant files
|
||||
- [ ] Use ACE search_context first, fallback to smart_search for discovery
|
||||
- [ ] Use read_file to batch read context files, find 3+ patterns
|
||||
- [ ] Check RULES templates and constraints
|
||||
|
||||
|
||||
@@ -389,12 +389,16 @@ function writeQueue(queue: Queue): void {
|
||||
writeQueueIndex(index);
|
||||
}
|
||||
|
||||
function generateQueueItemId(queue: Queue): string {
|
||||
const maxNum = queue.tasks.reduce((max, q) => {
|
||||
const match = q.item_id.match(/^T-(\d+)$/);
|
||||
function generateQueueItemId(queue: Queue, level: 'solution' | 'task' = 'solution'): string {
|
||||
const prefix = level === 'solution' ? 'S' : 'T';
|
||||
const items = level === 'solution' ? (queue.solutions || []) : (queue.tasks || []);
|
||||
const pattern = new RegExp(`^${prefix}-(\\d+)$`);
|
||||
|
||||
const maxNum = items.reduce((max, q) => {
|
||||
const match = q.item_id.match(pattern);
|
||||
return match ? Math.max(max, parseInt(match[1])) : max;
|
||||
}, 0);
|
||||
return `T-${maxNum + 1}`;
|
||||
return `${prefix}-${maxNum + 1}`;
|
||||
}
|
||||
|
||||
// ============ Commands ============
|
||||
@@ -1003,7 +1007,7 @@ async function queueAction(subAction: string | undefined, issueId: string | unde
|
||||
return;
|
||||
}
|
||||
|
||||
// Add issue tasks to queue
|
||||
// Add issue solution to queue (solution-level granularity)
|
||||
if (subAction === 'add' && issueId) {
|
||||
const issue = findIssue(issueId);
|
||||
if (!issue) {
|
||||
@@ -1020,48 +1024,61 @@ async function queueAction(subAction: string | undefined, issueId: string | unde
|
||||
|
||||
// Get or create active queue (create new if current is completed/archived)
|
||||
let queue = readActiveQueue();
|
||||
const isNewQueue = queue.tasks.length === 0 || queue.status !== 'active';
|
||||
const items = queue.solutions || [];
|
||||
const isNewQueue = items.length === 0 || queue.status !== 'active';
|
||||
|
||||
if (queue.status !== 'active') {
|
||||
// Create new queue if current is not active
|
||||
queue = createEmptyQueue();
|
||||
}
|
||||
|
||||
// Ensure solutions array exists
|
||||
if (!queue.solutions) {
|
||||
queue.solutions = [];
|
||||
}
|
||||
|
||||
// Check if solution already in queue
|
||||
const exists = queue.solutions.some(q => q.issue_id === issueId && q.solution_id === solution.id);
|
||||
if (exists) {
|
||||
console.log(chalk.yellow(`Solution ${solution.id} already in queue`));
|
||||
return;
|
||||
}
|
||||
|
||||
// Add issue to queue's issue list
|
||||
if (!queue.issue_ids.includes(issueId)) {
|
||||
queue.issue_ids.push(issueId);
|
||||
}
|
||||
|
||||
let added = 0;
|
||||
for (const task of solution.tasks) {
|
||||
const exists = queue.tasks.some(q => q.issue_id === issueId && q.task_id === task.id);
|
||||
if (exists) continue;
|
||||
|
||||
queue.tasks.push({
|
||||
item_id: generateQueueItemId(queue),
|
||||
issue_id: issueId,
|
||||
solution_id: solution.id,
|
||||
task_id: task.id,
|
||||
status: 'pending',
|
||||
execution_order: queue.tasks.length + 1,
|
||||
execution_group: 'P1',
|
||||
depends_on: task.depends_on.map(dep => {
|
||||
const depItem = queue.tasks.find(q => q.task_id === dep && q.issue_id === issueId);
|
||||
return depItem?.item_id || dep;
|
||||
}),
|
||||
semantic_priority: 0.5,
|
||||
assigned_executor: 'codex'
|
||||
});
|
||||
added++;
|
||||
// Collect all files touched by this solution
|
||||
const filesTouched = new Set<string>();
|
||||
for (const task of solution.tasks || []) {
|
||||
for (const mp of task.modification_points || []) {
|
||||
filesTouched.add(mp.file);
|
||||
}
|
||||
}
|
||||
|
||||
// Create solution-level queue item (S-N)
|
||||
queue.solutions.push({
|
||||
item_id: generateQueueItemId(queue, 'solution'),
|
||||
issue_id: issueId,
|
||||
solution_id: solution.id,
|
||||
status: 'pending',
|
||||
execution_order: queue.solutions.length + 1,
|
||||
execution_group: 'P1',
|
||||
depends_on: [],
|
||||
semantic_priority: 0.5,
|
||||
assigned_executor: 'codex',
|
||||
task_count: solution.tasks?.length || 0,
|
||||
files_touched: Array.from(filesTouched)
|
||||
});
|
||||
|
||||
writeQueue(queue);
|
||||
updateIssue(issueId, { status: 'queued', queued_at: new Date().toISOString() });
|
||||
|
||||
if (isNewQueue) {
|
||||
console.log(chalk.green(`✓ Created queue ${queue.id}`));
|
||||
}
|
||||
console.log(chalk.green(`✓ Added ${added} tasks from ${solution.id}`));
|
||||
console.log(chalk.green(`✓ Added solution ${solution.id} (${solution.tasks?.length || 0} tasks) to queue`));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1075,7 +1092,11 @@ async function queueAction(subAction: string | undefined, issueId: string | unde
|
||||
|
||||
console.log(chalk.bold.cyan('\nActive Queue\n'));
|
||||
|
||||
if (!queue.id || queue.tasks.length === 0) {
|
||||
// Support both solution-level and task-level queues
|
||||
const items = queue.solutions || queue.tasks || [];
|
||||
const isSolutionLevel = !!(queue.solutions && queue.solutions.length > 0);
|
||||
|
||||
if (!queue.id || items.length === 0) {
|
||||
console.log(chalk.yellow('No active queue'));
|
||||
console.log(chalk.gray('Create one: ccw issue queue add <issue-id>'));
|
||||
console.log(chalk.gray('Or list history: ccw issue queue list'));
|
||||
@@ -1084,13 +1105,17 @@ async function queueAction(subAction: string | undefined, issueId: string | unde
|
||||
|
||||
console.log(chalk.gray(`Queue: ${queue.id}`));
|
||||
console.log(chalk.gray(`Issues: ${queue.issue_ids.join(', ')}`));
|
||||
console.log(chalk.gray(`Total: ${queue._metadata.total_tasks} | Pending: ${queue._metadata.pending_count} | Executing: ${queue._metadata.executing_count} | Completed: ${queue._metadata.completed_count}`));
|
||||
console.log(chalk.gray(`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}`));
|
||||
console.log();
|
||||
|
||||
console.log(chalk.gray('QueueID'.padEnd(10) + 'Issue'.padEnd(15) + 'Task'.padEnd(8) + 'Status'.padEnd(12) + 'Executor'));
|
||||
if (isSolutionLevel) {
|
||||
console.log(chalk.gray('ItemID'.padEnd(10) + 'Issue'.padEnd(15) + 'Tasks'.padEnd(8) + 'Status'.padEnd(12) + 'Executor'));
|
||||
} else {
|
||||
console.log(chalk.gray('ItemID'.padEnd(10) + 'Issue'.padEnd(15) + 'Task'.padEnd(8) + 'Status'.padEnd(12) + 'Executor'));
|
||||
}
|
||||
console.log(chalk.gray('-'.repeat(60)));
|
||||
|
||||
for (const item of queue.tasks) {
|
||||
for (const item of items) {
|
||||
const statusColor = {
|
||||
'pending': chalk.gray,
|
||||
'ready': chalk.cyan,
|
||||
@@ -1100,10 +1125,14 @@ async function queueAction(subAction: string | undefined, issueId: string | unde
|
||||
'blocked': chalk.magenta
|
||||
}[item.status] || chalk.white;
|
||||
|
||||
const thirdCol = isSolutionLevel
|
||||
? String(item.task_count || 0).padEnd(8)
|
||||
: (item.task_id || '-').padEnd(8);
|
||||
|
||||
console.log(
|
||||
item.item_id.padEnd(10) +
|
||||
item.issue_id.substring(0, 13).padEnd(15) +
|
||||
(item.task_id || '-').padEnd(8) +
|
||||
thirdCol +
|
||||
statusColor(item.status.padEnd(12)) +
|
||||
item.assigned_executor
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user