Skip to content

Commit 48a6a1f

Browse files
author
catlog22
committed
Add comprehensive tests for ast-grep and tree-sitter relationship extraction
- Introduced test suite for AstGrepPythonProcessor covering pattern definitions, parsing, and relationship extraction. - Added comparison tests between tree-sitter and ast-grep for consistency in relationship extraction. - Implemented tests for ast-grep binding module to verify functionality and availability. - Ensured tests cover various scenarios including inheritance, function calls, and imports.
1 parent 126a357 commit 48a6a1f

56 files changed

Lines changed: 10622 additions & 374 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude/skills/workflow-lite-plan/phases/02-lite-execute.md

Lines changed: 103 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -184,11 +184,11 @@ Execution:
184184
├─ Step 1: Initialize result tracking (previousExecutionResults = [])
185185
├─ Step 2: Task grouping & batch creation
186186
│ ├─ Extract explicit depends_on (no file/keyword inference)
187-
│ ├─ Group: independent tasks → single parallel batch (maximize utilization)
187+
│ ├─ Group: independent tasks → per-executor parallel batches (one CLI per batch)
188188
│ ├─ Group: dependent tasks → sequential phases (respect dependencies)
189189
│ └─ Create TodoWrite list for batches
190190
├─ Step 3: Launch execution
191-
│ ├─ Phase 1: All independent tasks (⚡ single batch, concurrent)
191+
│ ├─ Phase 1: Independent tasks (⚡ per-executor batches, multi-CLI concurrent)
192192
│ └─ Phase 2+: Dependent tasks by dependency order
193193
├─ Step 4: Track progress (TodoWrite updates per batch)
194194
└─ Step 5: Code review (if codeReviewTool ≠ "Skip")
@@ -241,26 +241,58 @@ function extractDependencies(tasks) {
241241
})
242242
}
243243

244-
// Group into batches: maximize parallel execution
244+
// Executor Resolution (used by task grouping below)
245+
// 获取任务的 executor(优先使用 executorAssignments,fallback 到全局 executionMethod)
246+
function getTaskExecutor(task) {
247+
const assignments = executionContext?.executorAssignments || {}
248+
if (assignments[task.id]) {
249+
return assignments[task.id].executor // 'gemini' | 'codex' | 'agent'
250+
}
251+
// Fallback: 全局 executionMethod 映射
252+
const method = executionContext?.executionMethod || 'Auto'
253+
if (method === 'Agent') return 'agent'
254+
if (method === 'Codex') return 'codex'
255+
// Auto: 根据复杂度
256+
return planObject.complexity === 'Low' ? 'agent' : 'codex'
257+
}
258+
259+
// 按 executor 分组任务(核心分组组件)
260+
function groupTasksByExecutor(tasks) {
261+
const groups = { gemini: [], codex: [], agent: [] }
262+
tasks.forEach(task => {
263+
const executor = getTaskExecutor(task)
264+
groups[executor].push(task)
265+
})
266+
return groups
267+
}
268+
269+
// Group into batches: per-executor parallel batches (one CLI per batch)
245270
function createExecutionCalls(tasks, executionMethod) {
246271
const tasksWithDeps = extractDependencies(tasks)
247272
const processed = new Set()
248273
const calls = []
249274

250-
// Phase 1: All independent tasks → single parallel batch (maximize utilization)
275+
// Phase 1: Independent tasks → per-executor batches (multi-CLI concurrent)
251276
const independentTasks = tasksWithDeps.filter(t => t.dependencies.length === 0)
252277
if (independentTasks.length > 0) {
253-
independentTasks.forEach(t => processed.add(t.taskIndex))
254-
calls.push({
255-
method: executionMethod,
256-
executionType: "parallel",
257-
groupId: "P1",
258-
taskSummary: independentTasks.map(t => t.title).join(' | '),
259-
tasks: independentTasks
260-
})
278+
const executorGroups = groupTasksByExecutor(independentTasks)
279+
let parallelIndex = 1
280+
281+
for (const [executor, tasks] of Object.entries(executorGroups)) {
282+
if (tasks.length === 0) continue
283+
tasks.forEach(t => processed.add(t.taskIndex))
284+
calls.push({
285+
method: executionMethod,
286+
executor: executor, // 明确指定 executor
287+
executionType: "parallel",
288+
groupId: `P${parallelIndex++}`,
289+
taskSummary: tasks.map(t => t.title).join(' | '),
290+
tasks: tasks
291+
})
292+
}
261293
}
262294

263-
// Phase 2: Dependent tasks → sequential batches (respect dependencies)
295+
// Phase 2: Dependent tasks → sequential/parallel batches (respect dependencies)
264296
let sequentialIndex = 1
265297
let remaining = tasksWithDeps.filter(t => !processed.has(t.taskIndex))
266298

@@ -275,15 +307,33 @@ function createExecutionCalls(tasks, executionMethod) {
275307
ready.push(...remaining)
276308
}
277309

278-
// Group ready tasks (can run in parallel within this phase)
279-
ready.forEach(t => processed.add(t.taskIndex))
280-
calls.push({
281-
method: executionMethod,
282-
executionType: ready.length > 1 ? "parallel" : "sequential",
283-
groupId: ready.length > 1 ? `P${calls.length + 1}` : `S${sequentialIndex++}`,
284-
taskSummary: ready.map(t => t.title).join(ready.length > 1 ? ' | ' : ''),
285-
tasks: ready
286-
})
310+
if (ready.length > 1) {
311+
// Multiple ready tasks → per-executor batches (parallel within this phase)
312+
const executorGroups = groupTasksByExecutor(ready)
313+
for (const [executor, tasks] of Object.entries(executorGroups)) {
314+
if (tasks.length === 0) continue
315+
tasks.forEach(t => processed.add(t.taskIndex))
316+
calls.push({
317+
method: executionMethod,
318+
executor: executor,
319+
executionType: "parallel",
320+
groupId: `P${calls.length + 1}`,
321+
taskSummary: tasks.map(t => t.title).join(' | '),
322+
tasks: tasks
323+
})
324+
}
325+
} else {
326+
// Single ready task → sequential batch
327+
ready.forEach(t => processed.add(t.taskIndex))
328+
calls.push({
329+
method: executionMethod,
330+
executor: getTaskExecutor(ready[0]),
331+
executionType: "sequential",
332+
groupId: `S${sequentialIndex++}`,
333+
taskSummary: ready[0].title,
334+
tasks: ready
335+
})
336+
}
287337

288338
remaining = remaining.filter(t => !processed.has(t.taskIndex))
289339
}
@@ -304,33 +354,40 @@ TodoWrite({
304354
305355
### Step 3: Launch Execution
306356
307-
**Executor Resolution** (任务级 executor 优先于全局设置):
357+
**Executor Resolution**: `getTaskExecutor()` and `groupTasksByExecutor()` defined in Step 2 (Task Grouping).
358+
359+
**Batch Execution Routing** (根据 batch.executor 字段路由):
308360
```javascript
309-
// 获取任务的 executor(优先使用 executorAssignments,fallback 到全局 executionMethod)
310-
function getTaskExecutor(task) {
311-
const assignments = executionContext?.executorAssignments || {}
312-
if (assignments[task.id]) {
313-
return assignments[task.id].executor // 'gemini' | 'codex' | 'agent'
361+
// executeBatch 根据 batch 自身的 executor 字段决定调用哪个 CLI
362+
function executeBatch(batch) {
363+
const executor = batch.executor || getTaskExecutor(batch.tasks[0])
364+
const sessionId = executionContext?.session?.id || 'standalone'
365+
const fixedId = `${sessionId}-${batch.groupId}`
366+
367+
if (executor === 'agent') {
368+
// Agent execution (synchronous)
369+
return Task({
370+
subagent_type: "code-developer",
371+
run_in_background: false,
372+
description: batch.taskSummary,
373+
prompt: buildExecutionPrompt(batch)
374+
})
375+
} else if (executor === 'codex') {
376+
// Codex CLI (background)
377+
return Bash(`ccw cli -p "${buildExecutionPrompt(batch)}" --tool codex --mode write --id ${fixedId}`, { run_in_background: true })
378+
} else if (executor === 'gemini') {
379+
// Gemini CLI (background)
380+
return Bash(`ccw cli -p "${buildExecutionPrompt(batch)}" --tool gemini --mode write --id ${fixedId}`, { run_in_background: true })
314381
}
315-
// Fallback: 全局 executionMethod 映射
316-
const method = executionContext?.executionMethod || 'Auto'
317-
if (method === 'Agent') return 'agent'
318-
if (method === 'Codex') return 'codex'
319-
// Auto: 根据复杂度
320-
return planObject.complexity === 'Low' ? 'agent' : 'codex'
321-
}
322-
323-
// 按 executor 分组任务
324-
function groupTasksByExecutor(tasks) {
325-
const groups = { gemini: [], codex: [], agent: [] }
326-
tasks.forEach(task => {
327-
const executor = getTaskExecutor(task)
328-
groups[executor].push(task)
329-
})
330-
return groups
331382
}
332383
```
333384
385+
**并行执行原则**:
386+
- 每个 batch 对应一个独立的 CLI 实例或 Agent 调用
387+
- 并行 = 多个 Bash(run_in_background=true) 或多个 Task() 同时发出
388+
- 绝不将多个独立任务合并到同一个 CLI prompt 中
389+
- Agent 任务不可后台执行(run_in_background=false),但多个 Agent 任务可通过单条消息中的多个 Task() 调用并发
390+
334391
**Execution Flow**: Parallel batches concurrently → Sequential batches in order
335392
```javascript
336393
const parallel = executionCalls.filter(c => c.executionType === "parallel")
@@ -659,8 +716,8 @@ console.log(`✓ Development index: [${category}] ${entry.title}`)
659716
## Best Practices
660717
661718
**Input Modes**: In-memory (lite-plan), prompt (standalone), file (JSON/text)
662-
**Task Grouping**: Based on explicit depends_on only; independent tasks run in single parallel batch
663-
**Execution**: All independent tasks launch concurrently via single Claude message with multiple tool calls
719+
**Task Grouping**: Based on explicit depends_on only; independent tasks split by executor, each batch runs as separate CLI instance
720+
**Execution**: Independent task batches launch concurrently via single Claude message with multiple tool calls (one tool call per batch)
664721
665722
## Error Handling
666723

0 commit comments

Comments
 (0)