Refactor execution modes and CLI integration across agents

- Updated code-developer, tdd-developer, and test-fix-agent to streamline execution modes based on task.meta.execution_config.method.
- Removed legacy command handling and introduced CLI handoff for 'cli' execution method.
- Enhanced buildCliHandoffPrompt to include task JSON path and improved context handling.
- Updated task-generate-agent and task-generate-tdd to reflect new execution method mappings and removed command field from implementation_approach.
- Improved CLI settings validation in CliSettingsModal with format and length checks.
- Added localization for new CLI settings messages in English and Chinese.
- Enhanced GPU selector to use localized strings for GPU types.
- Introduced TypeScript LSP setup documentation for better user guidance.
This commit is contained in:
catlog22
2026-02-02 19:21:30 +08:00
parent 2305e7b8e7
commit 545679eeb9
18 changed files with 192 additions and 405 deletions

View File

@@ -1,216 +0,0 @@
# Test Generation Enhancement - Implementation Summary
## Overview
Enhanced test-task-generate workflow with two major improvements:
1. **Gemini Test Enhancement** (Phase 1.5): Comprehensive test suggestions for API, integration, and error scenarios
2. **Planning Notes Mechanism** (test-planning-notes.md): Record Gemini enhancement, context, and plan process for full transparency
---
## Changes Made
### 1. Created Gemini Prompt Template
**File**: `~/.claude/workflows/cli-templates/prompts/test/test-suggestions-enhancement.txt`
- Structured prompt for Gemini CLI to generate comprehensive test suggestions
- Covers L1-L3 test layers with focus on API, integration, and error scenarios
- Produces actionable test specifications with expected behavior and success criteria
### 2. Enhanced test-task-generate.md with Two Major Features
**Location**: `.claude/commands/workflow/tools/test-task-generate.md`
#### A. Phase 1.5: Gemini Test Enhancement
- **Invocation of cli-execution-agent** for Gemini analysis
- **Template**: test-suggestions-enhancement.txt
- **Output**: gemini-enriched-suggestions.md
- **Merge**: Appends enriched suggestions to TEST_ANALYSIS_RESULTS.md
#### B. test-planning-notes.md Mechanism (NEW - References plan.md pattern)
Similar to plan.md's planning-notes.md, this records the entire planning journey.
**Lifecycle**:
1. **Phase 1 Creation**: Initialize test-planning-notes.md with Test Intent
2. **Phase 1.5 Update**: Record Gemini Enhancement findings
3. **Phase 2 Update**: Final Task Generation findings (agent-executed)
---
## Planning Notes Architecture (Similar to plan.md)
### test-planning-notes.md Structure
```markdown
# Test Planning Notes
**Session**: WFS-test-xxx
**Source Session**: WFS-xxx
**Created**: [timestamp]
## Test Intent (Phase 1)
- **PROJECT_TYPE**: [Detected project type]
- **TEST_FRAMEWORK**: [Detected framework]
- **COVERAGE_TARGET**: [Coverage goal]
- **SOURCE_SESSION**: [Source session ID]
---
## Context Findings (Phase 1)
### Files with Coverage Gaps
[Extracted from TEST_ANALYSIS_RESULTS.md]
### Test Framework & Conventions
- Framework: [Framework]
- Coverage Target: [Target]
---
## Gemini Enhancement (Phase 1.5)
**Analysis Timestamp**: [timestamp]
**Template**: test-suggestions-enhancement.txt
**Output File**: .process/gemini-enriched-suggestions.md
### Enriched Test Suggestions (Complete Gemini Analysis)
[COMPLETE CONTENT FROM gemini-enriched-suggestions.md EMBEDDED HERE]
[All L1-L3 test suggestions, API contracts, integration patterns, error scenarios]
### Gemini Analysis Summary
- **Status**: Enrichment complete
- **Layers Covered**: L1, L2.1, L2.2, L2.4, L2.5
- **Focus Areas**: API contracts, integration patterns, error scenarios, edge cases
- **Output Stored**: Full analysis in gemini-enriched-suggestions.md
### Key Features
1. **Complete Gemini Analysis Embedded**: Full enriched suggestions content is directly embedded into test-planning-notes.md
2. **Preserved Output File**: gemini-enriched-suggestions.md still generated as artifact for reference
3. **Consolidated Context**: test-planning-notes.md becomes single source of truth for all planning context
4. **Agent Friendly**: test-action-planning-agent can read complete planning context from one file
### Use Cases for Gemini Content in planning-notes.md
| Use Case | Benefit |
|----------|---------|
| Reviewer reads planning-notes | See full Gemini suggestions without opening separate file |
| Agent reads planning-notes | Get enriched context alongside other planning metadata |
| Archive session | Complete record of analysis in one file |
| N+1 phase reference | Full history of suggestions for iterative refinement |
---
## Consolidated Test Requirements (Phase 2 Input)
1. [Context] Test framework conventions
2. [Context] Coverage target
3. [Gemini] API contract test strategies
4. [Gemini] Error scenario coverage
[... more consolidated requirements]
---
## Task Generation (Phase 2)
[Updated by test-action-planning-agent]
## N+1 Context
### Decisions
| Decision | Rationale | Revisit? |
|----------|-----------|----------|
[Decisions made during planning]
### Deferred
- [ ] Items for N+1 phase
```
### Key Benefits of Planning Notes
1. **Full Transparency**: Record Gemini enhancement findings and context
2. **Consolidated Context**: All phase inputs/outputs in one place
3. **N+1 Support**: Track decisions and deferred items for future iterations
4. **Agent Context**: test-action-planning-agent reads consolidated requirements
5. **Traceability**: How each test requirement came from which phase/source
6. **Integration Consistency**: Follows same pattern as plan.md for familiarity
---
## Complete Integration Flow
```
test-task-generate execution:
├─ Phase 1: Context Preparation
│ ├─ Load session metadata
│ ├─ Load TEST_ANALYSIS_RESULTS.md (original)
│ └─ CREATE test-planning-notes.md (Test Intent section)
├─ Phase 1.5: Gemini Test Enhancement
│ ├─ Invoke cli-execution-agent for Gemini analysis
│ ├─ Generate gemini-enriched-suggestions.md (full analysis output)
│ └─ RECORD complete enrichment to test-planning-notes.md (embed full Gemini analysis)
└─ Phase 2: Test Document Generation (Agent)
├─ Load TEST_ANALYSIS_RESULTS.md (original, unchanged)
├─ Load test-planning-notes.md (includes full Gemini enrichment)
├─ Generate task JSONs (IMPL-*.json)
└─ Create IMPL_PLAN.md + TODO_LIST.md
```
## Key Design Decisions
### Gemini Enhancement Recording Strategy
**Decision**: Record Gemini enhancement to test-planning-notes.md instead of appending to TEST_ANALYSIS_RESULTS.md
**Rationale**:
1. **Separation of Concerns**: TEST_ANALYSIS_RESULTS.md remains as original analysis output
2. **Single Source of Truth**: test-planning-notes.md consolidates ALL planning context
3. **Better Traceability**: Clear separation between base analysis and AI enrichment
4. **Follows plan.md Pattern**: Consistent with planning-notes.md mechanism
**Implementation**:
- Phase 1.5 generates gemini-enriched-suggestions.md (preserved as output file)
- Complete Gemini analysis content is embedded into test-planning-notes.md
- test-action-planning-agent reads both TEST_ANALYSIS_RESULTS.md and test-planning-notes.md
## No Breaking Changes
**Backward Compatible**:
- Phase 1.5 is optional enhancement - if Gemini analysis fails, workflow continues with original TEST_ANALYSIS_RESULTS.md
- test-action-planning-agent requires NO modifications to source code
- test-planning-notes.md consolidates context but doesn't replace existing inputs
- Existing workflows unaffected; only adds richer suggestions and traceability
**Enriched Layers**:
- **L1 (Unit)**: Edge cases, boundary conditions, error path validation
- **L2.1 (Integration)**: Module interactions, dependency injection patterns
- **L2.2 (API Contracts)**: Request/response, validation, status codes, error responses
- **L2.4 (External APIs)**: Mock strategies, failure scenarios, timeout handling
- **L2.5 (Failure Modes)**: Exception hierarchies, error propagation, recovery strategies
**Benefits**:
- ✅ Comprehensive API test specifications
- ✅ Detailed integration test strategies
- ✅ Systematic error scenario coverage
- ✅ More actionable task generation
- ✅ Reduced manual test planning effort
## How Test-Action-Planning-Agent Uses Enrichment
**Phase 1 (Context Loading)**:
- test-action-planning-agent reads complete TEST_ANALYSIS_RESULTS.md
- Includes both original analysis AND Gemini-enhanced suggestions
- Automatically leverages enriched content for task generation
**IMPL-001.json (Test Generation)**:
- Generated with reference to enriched test specifications
- Enhanced L1-L3 layer requirements from Gemini analysis
- More detailed test case descriptions
- Better integration and error scenario coverage
## Verification
To verify the enhancement is working:
1. Run `/workflow:test-fix-gen` to trigger test workflow
2. Check `.workflow/active/[session]/.process/gemini-enriched-suggestions.md` exists
3. Check TEST_ANALYSIS_RESULTS.md contains "## Gemini-Enhanced Test Suggestions" section
4. Review IMPL-001.json - should reference enriched test specifications
5. Execute `/workflow:test-cycle-execute` - generated tests should cover API, integration, and error scenarios comprehensively

View File

@@ -288,8 +288,8 @@ function computeCliStrategy(task, allTasks) {
"execution_group": "parallel-abc123|null", "execution_group": "parallel-abc123|null",
"module": "frontend|backend|shared|null", "module": "frontend|backend|shared|null",
"execution_config": { "execution_config": {
"method": "agent|hybrid|cli", "method": "agent|cli",
"cli_tool": "codex|gemini|qwen|auto", "cli_tool": "codex|gemini|qwen|auto|null",
"enable_resume": true, "enable_resume": true,
"previous_cli_id": "string|null" "previous_cli_id": "string|null"
} }
@@ -303,7 +303,7 @@ function computeCliStrategy(task, allTasks) {
- `execution_group`: Parallelization group ID (tasks with same ID can run concurrently) or `null` for sequential tasks - `execution_group`: Parallelization group ID (tasks with same ID can run concurrently) or `null` for sequential tasks
- `module`: Module identifier for multi-module projects (e.g., `frontend`, `backend`, `shared`) or `null` for single-module - `module`: Module identifier for multi-module projects (e.g., `frontend`, `backend`, `shared`) or `null` for single-module
- `execution_config`: CLI execution settings (MUST align with userConfig from task-generate-agent) - `execution_config`: CLI execution settings (MUST align with userConfig from task-generate-agent)
- `method`: Execution method - `agent` (direct), `hybrid` (agent + CLI), `cli` (CLI only) - `method`: Execution method - `agent` (direct) or `cli` (CLI only). Only two values in final task JSON.
- `cli_tool`: Preferred CLI tool - `codex`, `gemini`, `qwen`, `auto`, or `null` (for agent-only) - `cli_tool`: Preferred CLI tool - `codex`, `gemini`, `qwen`, `auto`, or `null` (for agent-only)
- `enable_resume`: Whether to use `--resume` for CLI continuity (default: true) - `enable_resume`: Whether to use `--resume` for CLI continuity (default: true)
- `previous_cli_id`: Previous task's CLI execution ID for resume (populated at runtime) - `previous_cli_id`: Previous task's CLI execution ID for resume (populated at runtime)
@@ -318,14 +318,16 @@ userConfig.executionMethod → meta.execution_config
"cli" → "cli" →
meta.execution_config = { method: "cli", cli_tool: userConfig.preferredCliTool, enable_resume: true } meta.execution_config = { method: "cli", cli_tool: userConfig.preferredCliTool, enable_resume: true }
Execution: Agent executes pre_analysis, then hands off context + implementation_approach to CLI Execution: Agent executes pre_analysis, then hands off full context to CLI via buildCliHandoffPrompt()
"hybrid" → "hybrid" →
meta.execution_config = { method: "hybrid", cli_tool: userConfig.preferredCliTool, enable_resume: true } Per-task decision: set method to "agent" OR "cli" per task based on complexity
Execution: Agent decides which tasks to handoff to CLI based on complexity - Simple tasks (≤3 files, straightforward logic) → { method: "agent", cli_tool: null, enable_resume: false }
- Complex tasks (>3 files, complex logic, refactoring) → { method: "cli", cli_tool: userConfig.preferredCliTool, enable_resume: true }
Final task JSON always has method = "agent" or "cli", never "hybrid"
``` ```
**Note**: implementation_approach steps NO LONGER contain `command` fields. CLI execution is controlled by task-level `meta.execution_config` only. **IMPORTANT**: implementation_approach steps do NOT contain `command` fields. Execution routing is controlled by task-level `meta.execution_config.method` only.
**Test Task Extensions** (for type="test-gen" or type="test-fix"): **Test Task Extensions** (for type="test-gen" or type="test-fix"):
@@ -344,7 +346,7 @@ userConfig.executionMethod → meta.execution_config
- `test_framework`: Existing test framework from project (required for test tasks) - `test_framework`: Existing test framework from project (required for test tasks)
- `coverage_target`: Target code coverage percentage (optional) - `coverage_target`: Target code coverage percentage (optional)
**Note**: CLI tool usage for test-fix tasks is now controlled via `flow_control.implementation_approach` steps with `command` fields, not via `meta.use_codex`. **Note**: CLI tool usage for test-fix tasks is now controlled via task-level `meta.execution_config.method`, not via `meta.use_codex`.
#### Context Object #### Context Object
@@ -555,59 +557,45 @@ The examples above demonstrate **patterns**, not fixed requirements. Agent MUST:
##### Implementation Approach ##### Implementation Approach
**Execution Modes**: **Execution Control**:
The `implementation_approach` supports **two execution modes** based on the presence of the `command` field: The `implementation_approach` defines sequential implementation steps. Execution routing is controlled by **task-level `meta.execution_config.method`**, NOT by step-level `command` fields.
1. **Default Mode (Agent Execution)** - `command` field **omitted**: **Two Execution Modes**:
1. **Agent Mode** (`meta.execution_config.method = "agent"`):
- Agent interprets `modification_points` and `logic_flow` autonomously - Agent interprets `modification_points` and `logic_flow` autonomously
- Direct agent execution with full context awareness - Direct agent execution with full context awareness
- No external tool overhead - No external tool overhead
- **Use for**: Standard implementation tasks where agent capability is sufficient - **Use for**: Standard implementation tasks where agent capability is sufficient
- **Required fields**: `step`, `title`, `description`, `modification_points`, `logic_flow`, `depends_on`, `output`
2. **CLI Mode (Command Execution)** - `command` field **included**: 2. **CLI Mode** (`meta.execution_config.method = "cli"`):
- Specified command executes the step directly - Agent executes `pre_analysis`, then hands off full context to CLI via `buildCliHandoffPrompt()`
- Leverages specialized CLI tools (codex/gemini/qwen) for complex reasoning - CLI tool specified in `meta.execution_config.cli_tool` (codex/gemini/qwen)
- **Use for**: Large-scale features, complex refactoring, or when user explicitly requests CLI tool usage - Leverages specialized CLI tools for complex reasoning
- **Required fields**: Same as default mode **PLUS** `command`, `resume_from` (optional) - **Use for**: Large-scale features, complex refactoring, or when userConfig.executionMethod = "cli"
- **Command patterns** (with resume support):
- `ccw cli -p '[prompt]' --tool codex --mode write --cd [path]`
- `ccw cli -p '[prompt]' --resume ${previousCliId} --tool codex --mode write` (resume from previous)
- `ccw cli -p '[prompt]' --tool gemini --mode write --cd [path]` (write mode)
- **Resume mechanism**: When step depends on previous CLI execution, include `--resume` with previous execution ID
**Semantic CLI Tool Selection**: **Step Schema** (same for both modes):
```json
{
"step": 1,
"title": "Step title",
"description": "What to implement (may use [variable] placeholders from pre_analysis)",
"modification_points": ["Quantified changes: [list with counts]"],
"logic_flow": ["Implementation sequence"],
"depends_on": [0],
"output": "variable_name"
}
```
Agent determines CLI tool usage per-step based on user semantics and task nature. **Required fields**: `step`, `title`, `description`, `modification_points`, `logic_flow`, `depends_on`, `output`
**Source**: Scan `metadata.task_description` from context-package.json for CLI tool preferences. **IMPORTANT**: Do NOT add `command` field to implementation_approach steps. Execution routing is determined by task-level `meta.execution_config.method` only.
**User Semantic Triggers** (patterns to detect in task_description): **Example**:
- "use Codex/codex" → Add `command` field with Codex CLI
- "use Gemini/gemini" → Add `command` field with Gemini CLI
- "use Qwen/qwen" → Add `command` field with Qwen CLI
- "CLI execution" / "automated" → Infer appropriate CLI tool
**Task-Based Selection** (when no explicit user preference):
- **Implementation/coding**: Codex preferred for autonomous development
- **Analysis/exploration**: Gemini preferred for large context analysis
- **Documentation**: Gemini/Qwen with write mode (`--mode write`)
- **Testing**: Depends on complexity - simple=agent, complex=Codex
**Default Behavior**: Agent always executes the workflow. CLI commands are embedded in `implementation_approach` steps:
- Agent orchestrates task execution
- When step has `command` field, agent executes it via CCW CLI
- When step has no `command` field, agent implements directly
- This maintains agent control while leveraging CLI tool power
**Key Principle**: The `command` field is **optional**. Agent decides based on user semantics and task complexity.
**Examples**:
```json ```json
[ [
// === DEFAULT MODE: Agent Execution (no command field) ===
{ {
"step": 1, "step": 1,
"title": "Load and analyze role analyses", "title": "Load and analyze role analyses",
@@ -644,8 +632,7 @@ Agent determines CLI tool usage per-step based on user semantics and task nature
], ],
"depends_on": [1], "depends_on": [1],
"output": "implementation" "output": "implementation"
}, }
] ]
``` ```

View File

@@ -202,33 +202,17 @@ for (const step of task.flow_control.pre_analysis || []) {
preAnalysisResults[step.output_to] = result; preAnalysisResults[step.output_to] = result;
} }
// Phase 2: Determine execution mode // Phase 2: Determine execution mode (based on task.meta.execution_config.method)
const hasLegacyCommands = task.flow_control.implementation_approach // Two modes: 'cli' (call CLI tool) or 'agent' (execute directly)
.some(step => step.command);
IF hasLegacyCommands: IF executionMethod === 'cli':
// Backward compatibility: Old mode with step.command fields // CLI Handoff: Full context passed to CLI via buildCliHandoffPrompt
FOR each step in implementation_approach[]: → const cliPrompt = buildCliHandoffPrompt(preAnalysisResults, task, taskJsonPath)
IF step.command exists:
→ Execute via Bash: Bash({ command: step.command, timeout: 3600000 })
ELSE:
→ Agent direct implementation
ELSE IF executionMethod === 'cli':
// New mode: CLI Handoff
→ const cliPrompt = buildCliHandoffPrompt(preAnalysisResults, task)
→ const cliCommand = buildCliCommand(task, cliTool, cliPrompt) → const cliCommand = buildCliCommand(task, cliTool, cliPrompt)
→ Bash({ command: cliCommand, run_in_background: false, timeout: 3600000 }) → Bash({ command: cliCommand, run_in_background: false, timeout: 3600000 })
ELSE IF executionMethod === 'hybrid':
// Hybrid mode: Agent decides based on task complexity
→ IF task is complex (multiple files, complex logic):
Use CLI Handoff (same as cli mode)
ELSE:
Use Agent direct implementation
ELSE (executionMethod === 'agent'): ELSE (executionMethod === 'agent'):
// Default: Agent direct implementation // Execute implementation steps directly
FOR each step in implementation_approach[]: FOR each step in implementation_approach[]:
1. Variable Substitution: Replace [variable_name] with preAnalysisResults 1. Variable Substitution: Replace [variable_name] with preAnalysisResults
2. Read modification_points[] as files to create/modify 2. Read modification_points[] as files to create/modify
@@ -253,26 +237,23 @@ function getDefaultCliTool() {
} }
// Build CLI prompt from pre-analysis results and task // Build CLI prompt from pre-analysis results and task
function buildCliHandoffPrompt(preAnalysisResults, task) { function buildCliHandoffPrompt(preAnalysisResults, task, taskJsonPath) {
const contextSection = Object.entries(preAnalysisResults) const contextSection = Object.entries(preAnalysisResults)
.map(([key, value]) => `### ${key}\n${value}`) .map(([key, value]) => `### ${key}\n${value}`)
.join('\n\n'); .join('\n\n');
const approachSection = task.flow_control.implementation_approach const conventions = task.context.shared_context?.conventions?.join(' | ') || '';
.map((step, i) => ` const constraints = `Follow existing patterns | No breaking changes${conventions ? ' | ' + conventions : ''}`;
### Step ${step.step}: ${step.title}
${step.description}
**Modification Points**:
${step.modification_points?.map(m => `- ${m}`).join('\n') || 'N/A'}
**Logic Flow**:
${step.logic_flow?.map((l, j) => `${j + 1}. ${l}`).join('\n') || 'Follow modification points'}
`).join('\n');
return ` return `
PURPOSE: ${task.title} PURPOSE: ${task.title}
Complete implementation based on pre-analyzed context. Complete implementation based on pre-analyzed context and task JSON.
## TASK JSON
Read full task definition: ${taskJsonPath}
## TECH STACK
${task.context.shared_context?.tech_stack?.map(t => `- ${t}`).join('\n') || 'Auto-detect from project files'}
## PRE-ANALYSIS CONTEXT ## PRE-ANALYSIS CONTEXT
${contextSection} ${contextSection}
@@ -280,17 +261,17 @@ ${contextSection}
## REQUIREMENTS ## REQUIREMENTS
${task.context.requirements?.map(r => `- ${r}`).join('\n') || task.context.requirements} ${task.context.requirements?.map(r => `- ${r}`).join('\n') || task.context.requirements}
## IMPLEMENTATION APPROACH
${approachSection}
## ACCEPTANCE CRITERIA ## ACCEPTANCE CRITERIA
${task.context.acceptance?.map(a => `- ${a}`).join('\n') || task.context.acceptance} ${task.context.acceptance?.map(a => `- ${a}`).join('\n') || task.context.acceptance}
## TARGET FILES ## TARGET FILES
${task.flow_control.target_files?.map(f => `- ${f}`).join('\n') || 'See modification points above'} ${task.flow_control.target_files?.map(f => `- ${f}`).join('\n') || 'See task JSON modification_points'}
## FOCUS PATHS
${task.context.focus_paths?.map(p => `- ${p}`).join('\n') || 'See task JSON'}
MODE: write MODE: write
CONSTRAINTS: Follow existing patterns | No breaking changes CONSTRAINTS: ${constraints}
`.trim(); `.trim();
} }
@@ -319,7 +300,7 @@ function buildCliCommand(task, cliTool, cliPrompt) {
**Execution Config Reference** (from task.meta.execution_config): **Execution Config Reference** (from task.meta.execution_config):
| Field | Values | Description | | Field | Values | Description |
|-------|--------|-------------| |-------|--------|-------------|
| `method` | `agent` / `cli` / `hybrid` | Execution mode (default: agent) | | `method` | `agent` / `cli` | Execution mode (default: agent) |
| `cli_tool` | See `~/.claude/cli-tools.json` | CLI tool preference (first enabled tool as default) | | `cli_tool` | See `~/.claude/cli-tools.json` | CLI tool preference (first enabled tool as default) |
| `enable_resume` | `true` / `false` | Enable CLI session resume | | `enable_resume` | `true` / `false` | Enable CLI session resume |

View File

@@ -154,11 +154,15 @@ STEP 1: Parse Red Phase Requirements
→ Load existing test patterns from focus_paths → Load existing test patterns from focus_paths
STEP 2: Execute Red Phase Implementation STEP 2: Execute Red Phase Implementation
IF step.command exists: const executionMethod = task.meta?.execution_config?.method || 'agent';
→ Execute CLI command with session resume
→ Build CLI command: ccw cli -p "..." --resume {resume_from} --tool {tool} --mode write IF executionMethod === 'cli':
// CLI Handoff: Full context passed via buildCliHandoffPrompt
→ const cliPrompt = buildCliHandoffPrompt(preAnalysisResults, task, taskJsonPath)
→ const cliCommand = buildCliCommand(task, cliTool, cliPrompt)
→ Bash({ command: cliCommand, run_in_background: false, timeout: 3600000 })
ELSE: ELSE:
→ Direct agent implementation // Execute directly
→ Create test files in modification_points → Create test files in modification_points
→ Write test cases following test_cases enumeration → Write test cases following test_cases enumeration
→ Use context.shared_context.conventions for test style → Use context.shared_context.conventions for test style
@@ -195,11 +199,16 @@ STEP 1: Parse Green Phase Requirements
→ Set max_iterations from meta.max_iterations (default: 3) → Set max_iterations from meta.max_iterations (default: 3)
STEP 2: Initial Implementation STEP 2: Initial Implementation
IF step.command exists: const executionMethod = task.meta?.execution_config?.method || 'agent';
→ Execute CLI command with session resume
→ Build CLI command: ccw cli -p "..." --resume {resume_from} --tool {tool} --mode write IF executionMethod === 'cli':
// CLI Handoff: Full context passed via buildCliHandoffPrompt
→ const cliPrompt = buildCliHandoffPrompt(preAnalysisResults, task, taskJsonPath)
→ const cliCommand = buildCliCommand(task, cliTool, cliPrompt)
→ Bash({ command: cliCommand, run_in_background: false, timeout: 3600000 })
ELSE: ELSE:
→ Direct agent implementation // Execute implementation steps directly
→ Implement functions in modification_points → Implement functions in modification_points
→ Follow logic_flow sequence → Follow logic_flow sequence
→ Use minimal code to pass tests (no over-engineering) → Use minimal code to pass tests (no over-engineering)
@@ -293,10 +302,15 @@ STEP 1: Parse Refactor Phase Requirements
→ Load refactoring scope from modification_points → Load refactoring scope from modification_points
STEP 2: Execute Refactor Implementation STEP 2: Execute Refactor Implementation
IF step.command exists: const executionMethod = task.meta?.execution_config?.method || 'agent';
→ Execute CLI command with session resume
IF executionMethod === 'cli':
// CLI Handoff: Full context passed via buildCliHandoffPrompt
→ const cliPrompt = buildCliHandoffPrompt(preAnalysisResults, task, taskJsonPath)
→ const cliCommand = buildCliCommand(task, cliTool, cliPrompt)
→ Bash({ command: cliCommand, run_in_background: false, timeout: 3600000 })
ELSE: ELSE:
→ Direct agent refactoring // Execute directly
→ Apply refactorings from logic_flow → Apply refactorings from logic_flow
→ Follow refactoring best practices: → Follow refactoring best practices:
• Extract functions for clarity • Extract functions for clarity
@@ -326,47 +340,15 @@ STEP 3: Regression Testing (REQUIRED)
### 3. CLI Execution Integration ### 3. CLI Execution Integration
**CLI Session Resumption** (when step.command exists): **CLI Functions** (inherited from code-developer):
- `buildCliHandoffPrompt(preAnalysisResults, task, taskJsonPath)` - Assembles CLI prompt with full context
**Build CLI Command with Resume Strategy**: - `buildCliCommand(task, cliTool, cliPrompt)` - Builds CLI command with resume strategy
```javascript
function buildCliCommand(step, tddConfig) {
const baseCommand = step.command // From task JSON
// Parse cli_execution strategy
switch (tddConfig.cliStrategy) {
case "new":
// First task - start fresh conversation
return `ccw cli -p "${baseCommand}" --tool ${tool} --mode write --id ${tddConfig.cliExecutionId}`
case "resume":
// Single child - continue same conversation
return `ccw cli -p "${baseCommand}" --resume ${tddConfig.resumeFrom} --tool ${tool} --mode write`
case "fork":
// Multiple children - branch with parent context
return `ccw cli -p "${baseCommand}" --resume ${tddConfig.resumeFrom} --id ${tddConfig.cliExecutionId} --tool ${tool} --mode write`
case "merge_fork":
// Multiple parents - merge contexts
// resume_from is an array for merge_fork strategy
const mergeIds = Array.isArray(tddConfig.resumeFrom)
? tddConfig.resumeFrom.join(',')
: tddConfig.resumeFrom
return `ccw cli -p "${baseCommand}" --resume ${mergeIds} --id ${tddConfig.cliExecutionId} --tool ${tool} --mode write`
default:
// Fallback - no resume
return `ccw cli -p "${baseCommand}" --tool ${tool} --mode write`
}
}
```
**Execute CLI Command**: **Execute CLI Command**:
```javascript ```javascript
// TDD agent runs in foreground - can receive hook callbacks // TDD agent runs in foreground - can receive hook callbacks
Bash( Bash(
command=buildCliCommand(step, tddConfig), command=buildCliCommand(task, cliTool, cliPrompt),
timeout=3600000, // 60 min for CLI execution timeout=3600000, // 60 min for CLI execution
run_in_background=false // Agent can receive task completion hooks run_in_background=false // Agent can receive task completion hooks
) )
@@ -504,7 +486,7 @@ Before completing any TDD task, verify:
- Use test-fix cycle in Green phase - Use test-fix cycle in Green phase
- Auto-revert on max iterations failure - Auto-revert on max iterations failure
- Generate TDD-enhanced summaries - Generate TDD-enhanced summaries
- Use CLI resume strategies when step.command exists - Use CLI resume strategies when meta.execution_config.method is "cli"
- Log all test-fix iterations to .process/ - Log all test-fix iterations to .process/
**Bash Tool (CLI Execution in TDD Agent)**: **Bash Tool (CLI Execution in TDD Agent)**:

View File

@@ -83,15 +83,15 @@ When task JSON contains implementation_approach array:
- `description`: Detailed description with variable references - `description`: Detailed description with variable references
- `modification_points`: Test and code modification targets - `modification_points`: Test and code modification targets
- `logic_flow`: Test-fix iteration sequence - `logic_flow`: Test-fix iteration sequence
- `command`: Optional CLI command (only when explicitly specified)
- `depends_on`: Array of step numbers that must complete first - `depends_on`: Array of step numbers that must complete first
- `output`: Variable name for this step's output - `output`: Variable name for this step's output
5. **Execution Mode Selection**: 5. **Execution Mode Selection**:
- IF `command` field exists → Execute CLI command via Bash tool - Based on `meta.execution_config.method`:
- ELSE (no command) → Agent direct execution: - `"cli"` → Build CLI command via buildCliHandoffPrompt() and execute via Bash tool
- Parse `modification_points` as files to modify - `"agent"` (default) → Agent direct execution:
- Follow `logic_flow` for test-fix iteration - Parse `modification_points` as files to modify
- Use test_commands from flow_control for test execution - Follow `logic_flow` for test-fix iteration
- Use test_commands from flow_control for test execution
### 1. Context Assessment & Test Discovery ### 1. Context Assessment & Test Discovery

View File

@@ -284,16 +284,24 @@ Execution Method: ${userConfig.executionMethod} // agent|hybrid|cli
Preferred CLI Tool: ${userConfig.preferredCliTool} // codex|gemini|qwen|auto Preferred CLI Tool: ${userConfig.preferredCliTool} // codex|gemini|qwen|auto
Supplementary Materials: ${userConfig.supplementaryMaterials} Supplementary Materials: ${userConfig.supplementaryMaterials}
## CLI TOOL SELECTION ## EXECUTION METHOD MAPPING
Based on userConfig.executionMethod: Based on userConfig.executionMethod, set task-level meta.execution_config:
- "agent": No command field in implementation_approach steps
- "hybrid": Add command field to complex steps only (agent handles simple steps)
- "cli": Add command field to ALL implementation_approach steps
CLI Resume Support (MANDATORY for all CLI commands): "agent" →
- Use --resume parameter to continue from previous task execution meta.execution_config = { method: "agent", cli_tool: null, enable_resume: false }
- Read previous task's cliExecutionId from session state Agent executes implementation_approach steps directly
- Format: ccw cli -p "[prompt]" --resume ${previousCliId} --tool ${tool} --mode write
"cli" →
meta.execution_config = { method: "cli", cli_tool: userConfig.preferredCliTool, enable_resume: true }
Agent executes pre_analysis, then hands off full context to CLI via buildCliHandoffPrompt()
"hybrid" →
Per-task decision: Analyze task complexity, set method to "agent" OR "cli" per task
- Simple tasks (≤3 files, straightforward logic) → method: "agent"
- Complex tasks (>3 files, complex logic, refactoring) → method: "cli"
CLI tool: userConfig.preferredCliTool, enable_resume: true
IMPORTANT: Do NOT add command field to implementation_approach steps. Execution routing is controlled by task-level meta.execution_config.method only.
## PRIORITIZED CONTEXT (from context-package.prioritized_context) - ALREADY SORTED ## PRIORITIZED CONTEXT (from context-package.prioritized_context) - ALREADY SORTED
Context sorting is ALREADY COMPLETED in context-gather Phase 2/3. DO NOT re-sort. Context sorting is ALREADY COMPLETED in context-gather Phase 2/3. DO NOT re-sort.
@@ -458,16 +466,24 @@ Execution Method: ${userConfig.executionMethod} // agent|hybrid|cli
Preferred CLI Tool: ${userConfig.preferredCliTool} // codex|gemini|qwen|auto Preferred CLI Tool: ${userConfig.preferredCliTool} // codex|gemini|qwen|auto
Supplementary Materials: ${userConfig.supplementaryMaterials} Supplementary Materials: ${userConfig.supplementaryMaterials}
## CLI TOOL SELECTION ## EXECUTION METHOD MAPPING
Based on userConfig.executionMethod: Based on userConfig.executionMethod, set task-level meta.execution_config:
- "agent": No command field in implementation_approach steps
- "hybrid": Add command field to complex steps only (agent handles simple steps)
- "cli": Add command field to ALL implementation_approach steps
CLI Resume Support (MANDATORY for all CLI commands): "agent" →
- Use --resume parameter to continue from previous task execution meta.execution_config = { method: "agent", cli_tool: null, enable_resume: false }
- Read previous task's cliExecutionId from session state Agent executes implementation_approach steps directly
- Format: ccw cli -p "[prompt]" --resume ${previousCliId} --tool ${tool} --mode write
"cli" →
meta.execution_config = { method: "cli", cli_tool: userConfig.preferredCliTool, enable_resume: true }
Agent executes pre_analysis, then hands off full context to CLI via buildCliHandoffPrompt()
"hybrid" →
Per-task decision: Analyze task complexity, set method to "agent" OR "cli" per task
- Simple tasks (≤3 files, straightforward logic) → method: "agent"
- Complex tasks (>3 files, complex logic, refactoring) → method: "cli"
CLI tool: userConfig.preferredCliTool, enable_resume: true
IMPORTANT: Do NOT add command field to implementation_approach steps. Execution routing is controlled by task-level meta.execution_config.method only.
## PRIORITIZED CONTEXT (from context-package.prioritized_context) - ALREADY SORTED ## PRIORITIZED CONTEXT (from context-package.prioritized_context) - ALREADY SORTED
Context sorting is ALREADY COMPLETED in context-gather Phase 2/3. DO NOT re-sort. Context sorting is ALREADY COMPLETED in context-gather Phase 2/3. DO NOT re-sort.

View File

@@ -359,16 +359,24 @@ Execution Method: ${userConfig.executionMethod} // agent|hybrid|cli
Preferred CLI Tool: ${userConfig.preferredCliTool} // codex|gemini|qwen|auto Preferred CLI Tool: ${userConfig.preferredCliTool} // codex|gemini|qwen|auto
Supplementary Materials: ${userConfig.supplementaryMaterials} Supplementary Materials: ${userConfig.supplementaryMaterials}
## CLI TOOL SELECTION ## EXECUTION METHOD MAPPING
Based on userConfig.executionMethod: Based on userConfig.executionMethod, set task-level meta.execution_config:
- "agent": No command field in implementation_approach steps
- "hybrid": Add command field to complex steps only (Red/Green phases recommended for CLI)
- "cli": Add command field to ALL Red-Green-Refactor steps
CLI Resume Support (MANDATORY for all CLI commands): "agent" →
- Use --resume parameter to continue from previous task execution meta.execution_config = { method: "agent", cli_tool: null, enable_resume: false }
- Read previous task's cliExecutionId from session state Agent executes Red-Green-Refactor phases directly
- Format: ccw cli -p "[prompt]" --resume [previousCliId] --tool [tool] --mode write
"cli" →
meta.execution_config = { method: "cli", cli_tool: userConfig.preferredCliTool, enable_resume: true }
Agent executes pre_analysis, then hands off full context to CLI via buildCliHandoffPrompt()
"hybrid" →
Per-task decision: Analyze TDD cycle complexity, set method to "agent" OR "cli" per task
- Simple cycles (≤5 test cases, ≤3 files) → method: "agent"
- Complex cycles (>5 test cases, >3 files, integration tests) → method: "cli"
CLI tool: userConfig.preferredCliTool, enable_resume: true
IMPORTANT: Do NOT add command field to implementation_approach steps. Execution routing is controlled by task-level meta.execution_config.method only.
## EXPLORATION CONTEXT (from context-package.exploration_results) ## EXPLORATION CONTEXT (from context-package.exploration_results)
- Load exploration_results from context-package.json - Load exploration_results from context-package.json
@@ -426,7 +434,7 @@ CLI Resume Support (MANDATORY for all CLI commands):
2. Green Phase (`tdd_phase: "green"`): Implement to pass tests 2. Green Phase (`tdd_phase: "green"`): Implement to pass tests
3. Refactor Phase (`tdd_phase: "refactor"`): Improve code quality 3. Refactor Phase (`tdd_phase: "refactor"`): Improve code quality
- `flow_control.pre_analysis`: Include exploration integration_points analysis - `flow_control.pre_analysis`: Include exploration integration_points analysis
- CLI tool usage based on userConfig (add `command` field per executionMethod) - **meta.execution_config**: Set per userConfig.executionMethod (agent/cli/hybrid)
- **Details**: See action-planning-agent.md § TDD Task JSON Generation - **Details**: See action-planning-agent.md § TDD Task JSON Generation
##### 2. IMPL_PLAN.md (TDD Variant) ##### 2. IMPL_PLAN.md (TDD Variant)
@@ -623,7 +631,7 @@ This section provides quick reference for TDD task JSON structure. For complete
- Context: `focus_paths` use absolute or clear relative paths - Context: `focus_paths` use absolute or clear relative paths
- Flow control: Exactly 3 steps with `tdd_phase` field ("red", "green", "refactor") - Flow control: Exactly 3 steps with `tdd_phase` field ("red", "green", "refactor")
- Flow control: `pre_analysis` includes exploration integration_points analysis - Flow control: `pre_analysis` includes exploration integration_points analysis
- Command field: Added per `userConfig.executionMethod` (agent/hybrid/cli) - **meta.execution_config**: Set per `userConfig.executionMethod` (agent/cli/hybrid)
- See Phase 2 agent prompt for full schema and requirements - See Phase 2 agent prompt for full schema and requirements
## Output Files Structure ## Output Files Structure
@@ -736,7 +744,7 @@ IMPL (Green phase) tasks include automatic test-fix cycle:
3. **Success Path**: Tests pass → Complete task 3. **Success Path**: Tests pass → Complete task
4. **Failure Path**: Tests fail → Enter iterative fix cycle: 4. **Failure Path**: Tests fail → Enter iterative fix cycle:
- **Gemini Diagnosis**: Analyze failures with bug-fix template - **Gemini Diagnosis**: Analyze failures with bug-fix template
- **Fix Application**: Agent (default) or CLI (if `command` field present) - **Fix Application**: Agent executes fixes directly
- **Retest**: Verify fix resolves failures - **Retest**: Verify fix resolves failures
- **Repeat**: Up to max_iterations (default: 3) - **Repeat**: Up to max_iterations (default: 3)
5. **Safety Net**: Auto-revert all changes if max iterations reached 5. **Safety Net**: Auto-revert all changes if max iterations reached
@@ -745,5 +753,5 @@ IMPL (Green phase) tasks include automatic test-fix cycle:
## Configuration Options ## Configuration Options
- **meta.max_iterations**: Number of fix attempts in Green phase (default: 3) - **meta.max_iterations**: Number of fix attempts in Green phase (default: 3)
- **CLI tool usage**: Determined semantically from user's task description via `command` field in implementation_approach - **meta.execution_config.method**: Execution routing (agent/cli) determined from userConfig.executionMethod

View File

@@ -116,6 +116,16 @@ export function CliSettingsModal({ open, onClose, cliSettings }: CliSettingsModa
if (!name.trim()) { if (!name.trim()) {
newErrors.name = formatMessage({ id: 'apiSettings.validation.nameRequired' }); newErrors.name = formatMessage({ id: 'apiSettings.validation.nameRequired' });
} else {
// Validate name format: must start with letter, followed by letters/numbers/hyphens/underscores
const namePattern = /^[a-zA-Z][a-zA-Z0-9_-]*$/;
if (!namePattern.test(name.trim())) {
newErrors.name = formatMessage({ id: 'apiSettings.cliSettings.nameFormatHint' });
}
// Validate name length
if (name.trim().length > 32) {
newErrors.name = formatMessage({ id: 'apiSettings.cliSettings.nameTooLong' }, { max: 32 });
}
} }
if (mode === 'provider-based') { if (mode === 'provider-based') {
@@ -219,7 +229,11 @@ export function CliSettingsModal({ open, onClose, cliSettings }: CliSettingsModa
onChange={(e) => setName(e.target.value)} onChange={(e) => setName(e.target.value)}
placeholder={formatMessage({ id: 'apiSettings.cliSettings.namePlaceholder' })} placeholder={formatMessage({ id: 'apiSettings.cliSettings.namePlaceholder' })}
className={errors.name ? 'border-destructive' : ''} className={errors.name ? 'border-destructive' : ''}
maxLength={32}
/> />
<p className="text-xs text-muted-foreground">
{formatMessage({ id: 'apiSettings.cliSettings.nameFormatHint' })}
</p>
{errors.name && <p className="text-sm text-destructive">{errors.name}</p>} {errors.name && <p className="text-sm text-destructive">{errors.name}</p>}
</div> </div>

View File

@@ -266,7 +266,7 @@ function DeviceCard({ device, isSelected, onSelect, isSelecting }: DeviceCardPro
)} )}
</div> </div>
<p className="text-xs text-muted-foreground"> <p className="text-xs text-muted-foreground">
{formatMessage({ id: 'codexlens.gpu.type' })}: {device.type === 'discrete' ? '独立显卡' : '集成显卡'} {formatMessage({ id: 'codexlens.gpu.type' })}: {formatMessage({ id: device.type === 'discrete' ? 'codexlens.gpu.discrete' : 'codexlens.gpu.integrated' })}
</p> </p>
{device.memory?.total && ( {device.memory?.total && (
<p className="text-xs text-muted-foreground"> <p className="text-xs text-muted-foreground">

View File

@@ -289,6 +289,8 @@
"descriptionPlaceholder": "Optional description for this configuration", "descriptionPlaceholder": "Optional description for this configuration",
"selectProvider": "Select a provider", "selectProvider": "Select a provider",
"includeCoAuthoredBy": "Include co-authored-by in commits", "includeCoAuthoredBy": "Include co-authored-by in commits",
"nameFormatHint": "Letters, numbers, hyphens, underscores only. Used as: ccw cli --tool [name]",
"nameTooLong": "Name must be {max} characters or less",
"validation": { "validation": {
"providerRequired": "Please select a provider", "providerRequired": "Please select a provider",
"authOrBaseUrlRequired": "Please enter auth token or base URL" "authOrBaseUrlRequired": "Please enter auth token or base URL"

View File

@@ -142,6 +142,8 @@
"notAvailable": "GPU functionality not available", "notAvailable": "GPU functionality not available",
"unknownDevice": "Unknown device", "unknownDevice": "Unknown device",
"type": "Type", "type": "Type",
"discrete": "Discrete GPU",
"integrated": "Integrated GPU",
"driver": "Driver Version", "driver": "Driver Version",
"memory": "Memory" "memory": "Memory"
}, },

View File

@@ -289,6 +289,8 @@
"descriptionPlaceholder": "此配置的可选描述", "descriptionPlaceholder": "此配置的可选描述",
"selectProvider": "选择提供商", "selectProvider": "选择提供商",
"includeCoAuthoredBy": "在提交中包含 co-authored-by", "includeCoAuthoredBy": "在提交中包含 co-authored-by",
"nameFormatHint": "仅限字母、数字、连字符和下划线。用作ccw cli --tool [名称]",
"nameTooLong": "名称必须在 {max} 个字符以内",
"validation": { "validation": {
"providerRequired": "请选择提供商", "providerRequired": "请选择提供商",
"authOrBaseUrlRequired": "请输入认证令牌或基础 URL" "authOrBaseUrlRequired": "请输入认证令牌或基础 URL"

View File

@@ -142,6 +142,8 @@
"notAvailable": "GPU 功能不可用", "notAvailable": "GPU 功能不可用",
"unknownDevice": "未知设备", "unknownDevice": "未知设备",
"type": "类型", "type": "类型",
"discrete": "独立显卡",
"integrated": "集成显卡",
"driver": "驱动版本", "driver": "驱动版本",
"memory": "显存" "memory": "显存"
}, },

View File

@@ -446,9 +446,9 @@ export function SettingsPage() {
{/* System Theme Toggle (Backward Compatibility) */} {/* System Theme Toggle (Backward Compatibility) */}
<div className="flex items-center justify-between pt-4 border-t border-border"> <div className="flex items-center justify-between pt-4 border-t border-border">
<div> <div>
<p className="font-medium text-foreground"></p> <p className="font-medium text-foreground">{formatMessage({ id: 'settings.appearance.systemFollow' })}</p>
<p className="text-sm text-muted-foreground"> <p className="text-sm text-muted-foreground">
使/ {formatMessage({ id: 'settings.appearance.systemFollowDesc' })}
</p> </p>
</div> </div>
<Button <Button

View File

@@ -421,7 +421,7 @@ async function showToolConfigModal(toolName) {
var status = cliToolStatus[toolName] || {}; var status = cliToolStatus[toolName] || {};
if (!toolConfig) { if (!toolConfig) {
toolConfig = { enabled: true, primaryModel: '', secondaryModel: '' }; toolConfig = { enabled: true, primaryModel: '', secondaryModel: '', type: 'builtin' };
} }
var content = buildToolConfigModalContent(toolName, toolConfig, models, status); var content = buildToolConfigModalContent(toolName, toolConfig, models, status);
@@ -1163,7 +1163,7 @@ function initToolConfigModalEvents(tool, currentConfig, models) {
} }
// Only include settingsFile for builtin claude tool // Only include settingsFile for builtin claude tool
if (tool === 'claude' && config.type === 'builtin') { if (tool === 'claude' && currentConfig.type === 'builtin') {
updateData.settingsFile = settingsFile || null; updateData.settingsFile = settingsFile || null;
} }

View File

@@ -228,10 +228,13 @@ function getGlobalSettingsPath(): string {
*/ */
function resolveConfigPath(projectDir: string): { path: string; source: 'project' | 'global' | 'default' } { function resolveConfigPath(projectDir: string): { path: string; source: 'project' | 'global' | 'default' } {
const globalPath = getGlobalConfigPath(); const globalPath = getGlobalConfigPath();
debugLog(`[HYPOTHESIS-1] Checking for global config at: ${globalPath}`);
if (fs.existsSync(globalPath)) { if (fs.existsSync(globalPath)) {
debugLog(`[HYPOTHESIS-1] Global config found. Using source: 'global'`);
return { path: globalPath, source: 'global' }; return { path: globalPath, source: 'global' };
} }
debugLog(`[HYPOTHESIS-1] Global config NOT found. Using source: 'default'`);
// Return global path for default (will be created there) // Return global path for default (will be created there)
return { path: globalPath, source: 'default' }; return { path: globalPath, source: 'default' };
} }
@@ -278,15 +281,13 @@ function backupConfigFile(filePath: string): string {
/** /**
* Ensure tool has required fields (for backward compatibility) * Ensure tool has required fields (for backward compatibility)
* Preserves ALL fields from original tool object
*/ */
function ensureToolTags(tool: Partial<ClaudeCliTool>): ClaudeCliTool { function ensureToolTags(tool: Partial<ClaudeCliTool>): ClaudeCliTool {
return { return {
...tool, // Preserve all original fields (including availableModels, type, id, etc.)
enabled: tool.enabled ?? true, enabled: tool.enabled ?? true,
primaryModel: tool.primaryModel, tags: tool.tags ?? []
secondaryModel: tool.secondaryModel,
tags: tool.tags ?? [],
envFile: tool.envFile,
settingsFile: tool.settingsFile
}; };
} }
@@ -509,10 +510,12 @@ export async function ensureClaudeCliToolsAsync(projectDir: string, createInProj
* Automatically migrates older config versions to v3.2.0 * Automatically migrates older config versions to v3.2.0
*/ */
export function loadClaudeCliTools(projectDir: string): ClaudeCliToolsConfig & { _source?: string } { export function loadClaudeCliTools(projectDir: string): ClaudeCliToolsConfig & { _source?: string } {
debugLog(`[DIAGNOSIS] Starting to load claude cli tools for projectDir: ${projectDir}`);
const resolved = resolveConfigPath(projectDir); const resolved = resolveConfigPath(projectDir);
try { try {
if (resolved.source === 'default') { if (resolved.source === 'default') {
debugLog('[DIAGNOSIS] Resolved source is "default", returning default config.');
return { ...DEFAULT_TOOLS_CONFIG, _source: 'default' }; return { ...DEFAULT_TOOLS_CONFIG, _source: 'default' };
} }
@@ -526,9 +529,8 @@ export function loadClaudeCliTools(projectDir: string): ClaudeCliToolsConfig & {
const mergedTools: Record<string, ClaudeCliTool> = {}; const mergedTools: Record<string, ClaudeCliTool> = {};
for (const [key, tool] of Object.entries(migrated.tools || {})) { for (const [key, tool] of Object.entries(migrated.tools || {})) {
mergedTools[key] = { mergedTools[key] = {
...ensureToolTags(tool), ...ensureToolTags(tool), // Now preserves all fields including availableModels, type, id
type: tool.type ?? 'builtin', type: tool.type ?? 'builtin' // Ensure type has default value
id: tool.id // Preserve id for api-endpoint type
}; };
} }
@@ -554,6 +556,7 @@ export function loadClaudeCliTools(projectDir: string): ClaudeCliToolsConfig & {
debugLog(`[claude-cli-tools] Loaded tools config from ${resolved.source}: ${resolved.path}`); debugLog(`[claude-cli-tools] Loaded tools config from ${resolved.source}: ${resolved.path}`);
return config; return config;
} catch (err) { } catch (err) {
console.error('[HYPOTHESIS-2] Error loading or parsing tools config. Falling back to default. Error:', err);
console.error('[claude-cli-tools] Error loading tools config:', err); console.error('[claude-cli-tools] Error loading tools config:', err);
return { ...DEFAULT_TOOLS_CONFIG, _source: 'default' }; return { ...DEFAULT_TOOLS_CONFIG, _source: 'default' };
} }

View File

@@ -28,6 +28,8 @@ export interface CliToolConfig {
secondaryModel: string; secondaryModel: string;
tags?: string[]; tags?: string[];
envFile?: string | null; envFile?: string | null;
type?: 'builtin' | 'cli-wrapper' | 'api-endpoint'; // Tool type for frontend routing
settingsFile?: string | null; // Claude CLI settings file path
} }
export interface CliConfig { export interface CliConfig {
@@ -156,7 +158,9 @@ export function getFullConfigResponse(baseDir: string): {
primaryModel: tool.primaryModel ?? '', primaryModel: tool.primaryModel ?? '',
secondaryModel: tool.secondaryModel ?? '', secondaryModel: tool.secondaryModel ?? '',
tags: tool.tags, tags: tool.tags,
envFile: tool.envFile envFile: tool.envFile,
type: tool.type, // Preserve type field for frontend routing
settingsFile: tool.settingsFile // Preserve settingsFile for Claude CLI
}; };
} }