feat: Enhance search functionality with quality tiers and scoped indexing

- Updated `search_code` function to include a `quality` parameter for search quality tiers: "fast", "balanced", "thorough", and "auto".
- Introduced `search_scope` function to limit search results to a specific directory scope.
- Added `index_scope` function for indexing a specific directory without re-indexing the entire project.
- Refactored `SearchPipeline` to support quality-based routing in the `search` method.
- Implemented `Shard` and `ShardManager` classes to manage multiple index shards with LRU eviction and efficient file routing.
- Added debounce functionality in `IncrementalIndexer` to batch file events and reduce redundant processing.
- Enhanced `FileWatcher` to integrate with `IncrementalIndexer` for improved event handling.
This commit is contained in:
catlog22
2026-03-19 17:47:53 +08:00
parent 54071473fc
commit 18aff260a0
46 changed files with 1537 additions and 658 deletions

View File

@@ -40,18 +40,28 @@ MAX_ROUNDS = pipeline_mode === 'deep' ? 5
Triggered when a worker sends completion message (via SendMessage callback).
1. Parse message to identify role and task ID:
1. Parse message to identify role, then resolve completed tasks:
| Message Pattern | Role Detection |
|----------------|---------------|
| `[explorer]` or task ID `EXPLORE-*` | explorer |
| `[analyst]` or task ID `ANALYZE-*` | analyst |
| `[discussant]` or task ID `DISCUSS-*` | discussant |
| `[synthesizer]` or task ID `SYNTH-*` | synthesizer |
**Role detection** (from message tag at start of body):
2. Mark task as completed:
| Message starts with | Role | Handler |
|---------------------|------|---------|
| `[explorer]` | explorer | handleCallback |
| `[analyst]` | analyst | handleCallback |
| `[discussant]` | discussant | handleCallback |
| `[synthesizer]` | synthesizer | handleCallback |
| `[supervisor]` | supervisor | Log checkpoint result, verify CHECKPOINT task completed, proceed to handleSpawnNext |
**Task ID resolution** (do NOT parse from message — use TaskList):
- Call `TaskList()` and find tasks matching the detected role's prefix
- Tasks with status `completed` that were not previously tracked = newly completed tasks
- This is reliable even when a worker reports multiple tasks (inner_loop) or when message format varies
2. Verify task completion (worker already marks completed in Phase 5):
```
TaskGet({ taskId: "<task-id>" })
// If still "in_progress" (worker failed to mark) → fallback:
TaskUpdate({ taskId: "<task-id>", status: "completed" })
```
@@ -112,7 +122,7 @@ ELSE:
|----------|--------|
| "Continue deeper" | Create new DISCUSS-`<N+1>` task (pending, no blockedBy). Record decision in discussion.md. Proceed to handleSpawnNext |
| "Adjust direction" | AskUserQuestion for new focus. Create ANALYZE-fix-`<N>` task (pending). Create DISCUSS-`<N+1>` task (pending, blockedBy ANALYZE-fix-`<N>`). Record direction change in discussion.md. Proceed to handleSpawnNext |
| "Done" | Create SYNTH-001 task (pending, blockedBy last DISCUSS). Record decision in discussion.md. Proceed to handleSpawnNext |
| "Done" | Check if SYNTH-001 already exists (from dispatch): if yes, ensure blockedBy is updated to reference last DISCUSS task; if no, create SYNTH-001 (pending, blockedBy last DISCUSS). Record decision in discussion.md. Proceed to handleSpawnNext |
**Dynamic task creation templates**:
@@ -160,8 +170,11 @@ InnerLoop: false"
TaskUpdate({ taskId: "ANALYZE-fix-<N>", owner: "analyst" })
```
SYNTH-001 (created dynamically in deep mode):
SYNTH-001 (created dynamically — check existence first):
```
// Guard: only create if SYNTH-001 doesn't exist yet (dispatch may have pre-created it)
const existingSynth = TaskList().find(t => t.subject === 'SYNTH-001')
if (!existingSynth) {
TaskCreate({
subject: "SYNTH-001",
description: "PURPOSE: Integrate all analysis into final conclusions | Success: Executive summary with recommendations
@@ -179,6 +192,8 @@ CONSTRAINTS: Pure integration, no new exploration
---
InnerLoop: false"
})
}
// Always update blockedBy to reference the last DISCUSS task (whether pre-existing or newly created)
TaskUpdate({ taskId: "SYNTH-001", addBlockedBy: ["<last-DISCUSS-task-id>"], owner: "synthesizer" })
```
@@ -211,10 +226,10 @@ Find and spawn the next ready tasks.
| Task Prefix | Role | Role Spec |
|-------------|------|-----------|
| `EXPLORE-*` | explorer | `~ or <project>/.claude/skills/team-ultra-analyze/role-specs/explorer.md` |
| `ANALYZE-*` | analyst | `~ or <project>/.claude/skills/team-ultra-analyze/role-specs/analyst.md` |
| `DISCUSS-*` | discussant | `~ or <project>/.claude/skills/team-ultra-analyze/role-specs/discussant.md` |
| `SYNTH-*` | synthesizer | `~ or <project>/.claude/skills/team-ultra-analyze/role-specs/synthesizer.md` |
| `EXPLORE-*` | explorer | `<skill_root>/roles/explorer/role.md` |
| `ANALYZE-*` | analyst | `<skill_root>/roles/analyst/role.md` |
| `DISCUSS-*` | discussant | `<skill_root>/roles/discussant/role.md` |
| `SYNTH-*` | synthesizer | `<skill_root>/roles/synthesizer/role.md` |
3. Spawn team-worker for each ready task:
@@ -227,7 +242,7 @@ Agent({
run_in_background: true,
prompt: `## Role Assignment
role: <role>
role_spec: ~ or <project>/.claude/skills/team-ultra-analyze/role-specs/<role>.md
role_spec: <skill_root>/roles/<role>/role.md
session: <session-folder>
session_id: <session-id>
team_name: ultra-analyze
@@ -298,11 +313,11 @@ Triggered when all pipeline tasks are completed.
| deep | All EXPLORE + ANALYZE + all DISCUSS-N + SYNTH-001 completed |
1. Verify all tasks completed. If any not completed, return to handleSpawnNext
2. If all completed, transition to coordinator Phase 5
2. If all completed, **inline-execute coordinator Phase 5** (shutdown workers → report → completion action). Do NOT STOP here — continue directly into Phase 5 within the same turn.
## Phase 4: State Persistence
After every handler execution:
After every handler execution **except handleComplete**:
1. Update session.json with current state:
- `discussion_round`: current round count
@@ -311,6 +326,8 @@ After every handler execution:
2. Verify task list consistency (no orphan tasks, no broken dependencies)
3. **STOP** and wait for next event
> **handleComplete exception**: handleComplete does NOT STOP — it transitions directly to coordinator Phase 5.
## Error Handling
| Scenario | Resolution |

View File

@@ -44,13 +44,21 @@ When coordinator is invoked, detect invocation type:
| Detection | Condition | Handler |
|-----------|-----------|---------|
| Worker callback | Message contains role tag [explorer], [analyst], [discussant], [synthesizer] | -> handleCallback (monitor.md) |
| Worker callback | Message content starts with `[explorer]`, `[analyst]`, `[discussant]`, or `[synthesizer]` (role tag at beginning of message body) | -> handleCallback (monitor.md) |
| Supervisor callback | Message content starts with `[supervisor]` | -> handleSupervisorReport (log checkpoint result, proceed to handleSpawnNext if tasks unblocked) |
| Idle notification | System notification that a teammate went idle (does NOT start with a role tag — typically says "Agent X is now idle") | -> **IGNORE** (do not handleCallback; idle is normal after every turn) |
| Shutdown response | Message content is a JSON object containing `shutdown_response` (parse as structured data, not string) | -> handleShutdownResponse (see Phase 5) |
| Status check | Arguments contain "check" or "status" | -> handleCheck (monitor.md) |
| Manual resume | Arguments contain "resume" or "continue" | -> handleResume (monitor.md) |
| Pipeline complete | All tasks have status "completed" | -> handleComplete (monitor.md) |
| Interrupted session | Active/paused session exists | -> Phase 0 |
| New session | None of above | -> Phase 1 |
**Message format discrimination**:
- **String messages starting with `[<role>]`**: Worker/supervisor completion reports → route to handleCallback or handleSupervisorReport
- **JSON object messages** (contain `type:` field): Structured protocol messages (shutdown_response) → route by `type` field
- **Other strings without role tags**: System idle notifications → IGNORE
For callback/check/resume/complete: load `@commands/monitor.md` and execute matched handler, then STOP.
### Router Implementation
@@ -167,7 +175,31 @@ All subsequent coordination is handled by `commands/monitor.md` handlers trigger
---
## Phase 5: Report + Completion Action
## Phase 5: Shutdown Workers + Report + Completion Action
### Shutdown All Workers
Before reporting, gracefully shut down all active teammates. This is a **multi-turn** process:
1. Read team config: `~/.claude/teams/ultra-analyze/config.json`
2. Build shutdown tracking list: `pending_shutdown = [<all member names except coordinator>]`
3. For each member in pending_shutdown, send shutdown request:
```javascript
SendMessage({
to: "<member-name>",
message: { type: "shutdown_request", reason: "Pipeline complete" }
})
```
4. **STOP** — wait for responses. Each `shutdown_response` triggers a new coordinator turn.
5. On each subsequent turn (shutdown_response received):
- Remove responder from `pending_shutdown`
- If `pending_shutdown` is empty → proceed to **Report** section below
- If not empty → **STOP** again, wait for remaining responses
6. If a member is unresponsive after 2 follow-ups, remove from tracking and proceed
**Note**: Workers that completed Phase 5-F and reached STOP may have already terminated. SendMessage to a terminated agent is silently ignored — this is safe. Only resident agents (e.g., supervisor) require explicit shutdown.
### Report
1. Load session state -> count completed tasks, calculate duration
2. List deliverables: