mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-05 01:50:27 +08:00
feat: 添加规划笔记功能以支持任务生成和约束管理
This commit is contained in:
@@ -55,6 +55,17 @@ color: yellow
|
||||
**Step-by-step execution**:
|
||||
|
||||
```
|
||||
0. Load planning notes → Extract phase-level constraints (NEW)
|
||||
Commands: Read('.workflow/active/{session-id}/planning-notes.md')
|
||||
Output: Consolidated constraints from all workflow phases
|
||||
Structure:
|
||||
- User Intent: Original GOAL, KEY_CONSTRAINTS
|
||||
- Context Findings: Critical files, architecture notes, constraints
|
||||
- Conflict Decisions: Resolved conflicts, modified artifacts
|
||||
- Consolidated Constraints: Numbered list of ALL constraints (Phase 1-3)
|
||||
|
||||
USAGE: This is the PRIMARY source of constraints. All task generation MUST respect these constraints.
|
||||
|
||||
1. Load session metadata → Extract user input
|
||||
- User description: Original task/feature requirements
|
||||
- Project scope: User-specified boundaries and goals
|
||||
@@ -826,6 +837,7 @@ Use `analysis_results.complexity` or task count to determine structure:
|
||||
### 3.3 Guidelines Checklist
|
||||
|
||||
**ALWAYS:**
|
||||
- **Load planning-notes.md FIRST**: Read planning-notes.md before context-package.json. Use its Consolidated Constraints as primary constraint source for all task generation
|
||||
- **Search Tool Priority**: ACE (`mcp__ace-tool__search_context`) → CCW (`mcp__ccw-tools__smart_search`) / Built-in (`Grep`, `Glob`, `Read`)
|
||||
- Apply Quantification Requirements to all requirements, acceptance criteria, and modification points
|
||||
- Load IMPL_PLAN template: `Read(~/.claude/workflows/cli-templates/prompts/workflow/impl-plan-template.txt)` before generating IMPL_PLAN.md
|
||||
|
||||
@@ -19,7 +19,7 @@ Interactive brainstorming workflow with **multi-CLI collaboration** and **docume
|
||||
|
||||
**Key features**:
|
||||
- **brainstorm.md**: Complete thought evolution timeline
|
||||
- **Multi-CLI collaboration**: Gemini (creative), Codex (pragmatic), Qwen (systematic) perspectives
|
||||
- **Multi-CLI collaboration**: Gemini (creative), Codex (pragmatic), Claude (systematic) perspectives
|
||||
- **Idea expansion**: Progressive questioning and exploration
|
||||
- **Diverge-Converge cycles**: Generate options then focus on best paths
|
||||
- **Synthesis**: Merge multiple perspectives into coherent solutions
|
||||
@@ -61,8 +61,8 @@ Phase 1: Seed Understanding
|
||||
|
||||
Phase 2: Divergent Exploration (Multi-CLI Parallel)
|
||||
├─ Gemini CLI: Creative/innovative perspectives
|
||||
├─ Codex CLI: Pragmatic/implementation perspectives
|
||||
├─ Qwen CLI: Systematic/architectural perspectives
|
||||
├─ Codex CLI: Pragmatic/implementation perspectives
|
||||
├─ Claude CLI: Systematic/architectural perspectives
|
||||
└─ Aggregate diverse viewpoints
|
||||
|
||||
Phase 3: Interactive Refinement (Multi-Round)
|
||||
@@ -375,7 +375,7 @@ CONSTRAINTS: Focus on what can actually be built with current tech stack
|
||||
})
|
||||
)
|
||||
|
||||
// 3. Qwen: Systematic/Architectural Perspective
|
||||
// 3. Claude: Systematic/Architectural Perspective
|
||||
cliPromises.push(
|
||||
Bash({
|
||||
command: `ccw cli -p "
|
||||
@@ -404,7 +404,7 @@ EXPECTED:
|
||||
- Risk matrix
|
||||
|
||||
CONSTRAINTS: Consider existing system architecture
|
||||
" --tool qwen --mode analysis`,
|
||||
" --tool claude --mode analysis`,
|
||||
run_in_background: true
|
||||
})
|
||||
)
|
||||
@@ -436,7 +436,7 @@ const perspectives = {
|
||||
},
|
||||
|
||||
systematic: {
|
||||
source: 'qwen',
|
||||
source: 'claude',
|
||||
decomposition: [...],
|
||||
patterns: [...],
|
||||
tradeoffs: [...]
|
||||
@@ -488,7 +488,7 @@ ${blockers.map(b => `- ⚠️ ${b}`).join('\n')}
|
||||
|
||||
---
|
||||
|
||||
#### Systematic Perspective (Qwen)
|
||||
#### Systematic Perspective (Claude)
|
||||
|
||||
**Problem Decomposition**:
|
||||
${decomposition}
|
||||
@@ -956,7 +956,7 @@ ${decisionFramework}
|
||||
- **Total Rounds**: ${totalRounds}
|
||||
- **Ideas Generated**: ${totalIdeas}
|
||||
- **Ideas Survived**: ${survivedIdeas}
|
||||
- **Perspectives Used**: Gemini (creative), Codex (pragmatic), Qwen (systematic)
|
||||
- **Perspectives Used**: Gemini (creative), Codex (pragmatic), Claude (systematic)
|
||||
- **Duration**: ${duration}
|
||||
- **Artifacts**: brainstorm.md, perspectives.json, synthesis.json, ${ideaFiles.length} idea deep-dives
|
||||
```
|
||||
@@ -1056,7 +1056,7 @@ if (selection.includes("导出分享")) {
|
||||
#### Pragmatic Perspective (Codex)
|
||||
...
|
||||
|
||||
#### Systematic Perspective (Qwen)
|
||||
#### Systematic Perspective (Claude)
|
||||
...
|
||||
|
||||
#### Perspective Synthesis
|
||||
@@ -1105,7 +1105,7 @@ if (selection.includes("导出分享")) {
|
||||
|-----|------|-------|----------|
|
||||
| Gemini | Creative | Innovation, cross-domain | Generating novel ideas |
|
||||
| Codex | Pragmatic | Implementation, feasibility | Reality-checking ideas |
|
||||
| Qwen | Systematic | Architecture, structure | Organizing solutions |
|
||||
| Claude | Systematic | Architecture, structure | Organizing solutions |
|
||||
|
||||
### Collaboration Patterns
|
||||
|
||||
|
||||
@@ -115,7 +115,38 @@ CONTEXT: Existing user database schema, REST API endpoints
|
||||
|
||||
**TodoWrite**: Mark phase 1 completed, phase 2 in_progress
|
||||
|
||||
**After Phase 1**: Return to user showing Phase 1 results, then auto-continue to Phase 2
|
||||
**After Phase 1**: Initialize planning-notes.md with user intent
|
||||
|
||||
```javascript
|
||||
// Create minimal planning notes document
|
||||
const planningNotesPath = `.workflow/active/${sessionId}/planning-notes.md`
|
||||
const userGoal = structuredDescription.goal
|
||||
const userConstraints = structuredDescription.context || "None specified"
|
||||
|
||||
Write(planningNotesPath, `# Planning Notes
|
||||
|
||||
**Session**: ${sessionId}
|
||||
**Created**: ${new Date().toISOString()}
|
||||
|
||||
## User Intent (Phase 1)
|
||||
|
||||
- **GOAL**: ${userGoal}
|
||||
- **KEY_CONSTRAINTS**: ${userConstraints}
|
||||
|
||||
---
|
||||
|
||||
## Context Findings (Phase 2)
|
||||
(To be filled by context-gather)
|
||||
|
||||
## Conflict Decisions (Phase 3)
|
||||
(To be filled if conflicts detected)
|
||||
|
||||
## Consolidated Constraints (Phase 4 Input)
|
||||
1. ${userConstraints}
|
||||
`)
|
||||
```
|
||||
|
||||
Return to user showing Phase 1 results, then auto-continue to Phase 2
|
||||
|
||||
---
|
||||
|
||||
@@ -168,7 +199,37 @@ SlashCommand(command="/workflow:tools:context-gather --session [sessionId] \"[st
|
||||
|
||||
**Note**: Phase 2 tasks completed and collapsed to summary.
|
||||
|
||||
**After Phase 2**: Return to user showing Phase 2 results, then auto-continue to Phase 3/4 (depending on conflict_risk)
|
||||
**After Phase 2**: Update planning-notes.md with context findings, then auto-continue
|
||||
|
||||
```javascript
|
||||
// Read context-package to extract key findings
|
||||
const contextPackage = JSON.parse(Read(contextPath))
|
||||
const conflictRisk = contextPackage.conflict_detection?.risk_level || 'low'
|
||||
const criticalFiles = (contextPackage.exploration_results?.aggregated_insights?.critical_files || [])
|
||||
.slice(0, 5).map(f => f.path)
|
||||
const archPatterns = contextPackage.project_context?.architecture_patterns || []
|
||||
const constraints = contextPackage.exploration_results?.aggregated_insights?.constraints || []
|
||||
|
||||
// Append Phase 2 findings to planning-notes.md
|
||||
Edit(planningNotesPath, {
|
||||
old: '## Context Findings (Phase 2)\n(To be filled by context-gather)',
|
||||
new: `## Context Findings (Phase 2)
|
||||
|
||||
- **CRITICAL_FILES**: ${criticalFiles.join(', ') || 'None identified'}
|
||||
- **ARCHITECTURE**: ${archPatterns.join(', ') || 'Not detected'}
|
||||
- **CONFLICT_RISK**: ${conflictRisk}
|
||||
- **CONSTRAINTS**: ${constraints.length > 0 ? constraints.join('; ') : 'None'}`
|
||||
})
|
||||
|
||||
// Append Phase 2 constraints to consolidated list
|
||||
Edit(planningNotesPath, {
|
||||
old: '## Consolidated Constraints (Phase 4 Input)',
|
||||
new: `## Consolidated Constraints (Phase 4 Input)
|
||||
${constraints.map((c, i) => `${i + 2}. [Context] ${c}`).join('\n')}`
|
||||
})
|
||||
```
|
||||
|
||||
Return to user showing Phase 2 results, then auto-continue to Phase 3/4 (depending on conflict_risk)
|
||||
|
||||
---
|
||||
|
||||
@@ -229,7 +290,45 @@ SlashCommand(command="/workflow:tools:conflict-resolution --session [sessionId]
|
||||
|
||||
**Note**: Phase 3 tasks completed and collapsed to summary.
|
||||
|
||||
**After Phase 3**: Return to user showing conflict resolution results (if executed) and selected strategies, then auto-continue to Phase 3.5
|
||||
**After Phase 3**: Update planning-notes.md with conflict decisions (if executed), then auto-continue
|
||||
|
||||
```javascript
|
||||
// If Phase 3 was executed, update planning-notes.md
|
||||
if (conflictRisk >= 'medium') {
|
||||
const conflictResPath = `.workflow/active/${sessionId}/.process/conflict-resolution.json`
|
||||
|
||||
if (fs.existsSync(conflictResPath)) {
|
||||
const conflictRes = JSON.parse(Read(conflictResPath))
|
||||
const resolved = conflictRes.resolved_conflicts || []
|
||||
const modifiedArtifacts = conflictRes.modified_artifacts || []
|
||||
const planningConstraints = conflictRes.planning_constraints || []
|
||||
|
||||
// Update Phase 3 section
|
||||
Edit(planningNotesPath, {
|
||||
old: '## Conflict Decisions (Phase 3)\n(To be filled if conflicts detected)',
|
||||
new: `## Conflict Decisions (Phase 3)
|
||||
|
||||
- **RESOLVED**: ${resolved.map(r => `${r.type} → ${r.strategy}`).join('; ') || 'None'}
|
||||
- **MODIFIED_ARTIFACTS**: ${modifiedArtifacts.join(', ') || 'None'}
|
||||
- **CONSTRAINTS**: ${planningConstraints.join('; ') || 'None'}`
|
||||
})
|
||||
|
||||
// Append Phase 3 constraints to consolidated list
|
||||
if (planningConstraints.length > 0) {
|
||||
const currentNotes = Read(planningNotesPath)
|
||||
const constraintCount = (currentNotes.match(/^\d+\./gm) || []).length
|
||||
|
||||
Edit(planningNotesPath, {
|
||||
old: '## Consolidated Constraints (Phase 4 Input)',
|
||||
new: `## Consolidated Constraints (Phase 4 Input)
|
||||
${planningConstraints.map((c, i) => `${constraintCount + i + 1}. [Conflict] ${c}`).join('\n')}`
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Return to user showing conflict resolution results (if executed) and selected strategies, then auto-continue to Phase 3.5
|
||||
|
||||
**Memory State Check**:
|
||||
- Evaluate current context window usage and memory state
|
||||
@@ -282,7 +381,12 @@ SlashCommand(command="/workflow:tools:task-generate-agent --session [sessionId]"
|
||||
|
||||
**CLI Execution Note**: CLI tool usage is now determined semantically by action-planning-agent based on user's task description. If user specifies "use Codex/Gemini/Qwen for X", the agent embeds `command` fields in relevant `implementation_approach` steps.
|
||||
|
||||
**Input**: `sessionId` from Phase 1
|
||||
**Input**:
|
||||
- `sessionId` from Phase 1
|
||||
- **planning-notes.md**: Consolidated constraints from all phases (Phase 1-3)
|
||||
- Path: `.workflow/active/[sessionId]/planning-notes.md`
|
||||
- Contains: User intent, context findings, conflict decisions, consolidated constraints
|
||||
- **Purpose**: Provides structured, minimal context summary to action-planning-agent
|
||||
|
||||
**Validation**:
|
||||
- `.workflow/active/[sessionId]/IMPL_PLAN.md` exists
|
||||
@@ -404,26 +508,22 @@ User Input (task description)
|
||||
↓
|
||||
Phase 1: session:start --auto "structured-description"
|
||||
↓ Output: sessionId
|
||||
↓ Session Memory: Previous tasks, context, artifacts
|
||||
↓ Write: planning-notes.md (User Intent section)
|
||||
↓
|
||||
Phase 2: context-gather --session sessionId "structured-description"
|
||||
↓ Input: sessionId + session memory + structured description
|
||||
↓ Input: sessionId + structured description
|
||||
↓ Output: contextPath (context-package.json) + conflict_risk
|
||||
↓ Update: planning-notes.md (Context Findings + Consolidated Constraints)
|
||||
↓
|
||||
Phase 3: conflict-resolution [AUTO-TRIGGERED if conflict_risk ≥ medium]
|
||||
↓ Input: sessionId + contextPath + conflict_risk
|
||||
↓ CLI-powered conflict detection (JSON output)
|
||||
↓ AskUserQuestion: Present conflicts + resolution strategies
|
||||
↓ User selects strategies (or skip)
|
||||
↓ Apply modifications via Edit tool:
|
||||
↓ - Update guidance-specification.md
|
||||
↓ - Update role analyses (*.md)
|
||||
↓ - Mark context-package.json as "resolved"
|
||||
↓ Output: Modified brainstorm artifacts (NO report file)
|
||||
↓ Output: Modified brainstorm artifacts
|
||||
↓ Update: planning-notes.md (Conflict Decisions + Consolidated Constraints)
|
||||
↓ Skip if conflict_risk is none/low → proceed directly to Phase 4
|
||||
↓
|
||||
Phase 4: task-generate-agent --session sessionId
|
||||
↓ Input: sessionId + resolved brainstorm artifacts + session memory
|
||||
↓ Input: sessionId + planning-notes.md + context-package.json + brainstorm artifacts
|
||||
↓ planning-notes.md provides: User Intent, Context Findings, Constraints
|
||||
↓ Output: IMPL_PLAN.md, task JSONs, TODO_LIST.md
|
||||
↓
|
||||
Return summary to user
|
||||
|
||||
@@ -161,12 +161,13 @@ const userConfig = {
|
||||
|
||||
### Phase 1: Context Preparation & Module Detection (Command Responsibility)
|
||||
|
||||
**Command prepares session paths, metadata, and detects module structure.**
|
||||
**Command prepares session paths, metadata, detects module structure, and loads planning-notes.md.**
|
||||
|
||||
**Session Path Structure**:
|
||||
```
|
||||
.workflow/active/WFS-{session-id}/
|
||||
├── workflow-session.json # Session metadata
|
||||
├── planning-notes.md # Consolidated planning notes (NEW)
|
||||
├── .process/
|
||||
│ └── context-package.json # Context package with artifact catalog
|
||||
├── .task/ # Output: Task JSON files
|
||||
@@ -248,9 +249,21 @@ IMPORTANT: This is PLANNING ONLY - you are generating planning documents, NOT im
|
||||
|
||||
CRITICAL: Follow the progressive loading strategy defined in agent specification (load analysis.md files incrementally due to file size)
|
||||
|
||||
## PLANNING NOTES (PHASE 1-3 CONTEXT)
|
||||
Load: .workflow/active/{session-id}/planning-notes.md
|
||||
|
||||
This document contains:
|
||||
- User Intent: Original GOAL and KEY_CONSTRAINTS from Phase 1
|
||||
- Context Findings: Critical files, architecture, and constraints from Phase 2
|
||||
- Conflict Decisions: Resolved conflicts and planning constraints from Phase 3
|
||||
- Consolidated Constraints: All constraints from all phases
|
||||
|
||||
**USAGE**: Read planning-notes.md FIRST. Use Consolidated Constraints list to guide task sequencing and dependencies.
|
||||
|
||||
## SESSION PATHS
|
||||
Input:
|
||||
- Session Metadata: .workflow/active/{session-id}/workflow-session.json
|
||||
- Planning Notes: .workflow/active/{session-id}/planning-notes.md (NEW)
|
||||
- Context Package: .workflow/active/{session-id}/.process/context-package.json
|
||||
|
||||
Output:
|
||||
@@ -376,6 +389,11 @@ IMPORTANT: Generate Task JSONs ONLY. IMPL_PLAN.md and TODO_LIST.md by Phase 3 Co
|
||||
|
||||
CRITICAL: Follow the progressive loading strategy defined in agent specification (load analysis.md files incrementally due to file size)
|
||||
|
||||
## PLANNING NOTES (PHASE 1-3 CONTEXT)
|
||||
Load: .workflow/active/{session-id}/planning-notes.md
|
||||
|
||||
This document contains consolidated constraints and user intent to guide module-scoped task generation.
|
||||
|
||||
## MODULE SCOPE
|
||||
- Module: ${module.name} (${module.type})
|
||||
- Focus Paths: ${module.paths.join(', ')}
|
||||
@@ -386,6 +404,7 @@ CRITICAL: Follow the progressive loading strategy defined in agent specification
|
||||
## SESSION PATHS
|
||||
Input:
|
||||
- Session Metadata: .workflow/active/{session-id}/workflow-session.json
|
||||
- Planning Notes: .workflow/active/{session-id}/planning-notes.md (NEW)
|
||||
- Context Package: .workflow/active/{session-id}/.process/context-package.json
|
||||
|
||||
Output:
|
||||
|
||||
@@ -302,7 +302,7 @@ export async function handleCliRoutes(ctx: RouteContext): Promise<boolean> {
|
||||
if (req.method === 'PUT') {
|
||||
handlePostRequest(req, res, async (body: unknown) => {
|
||||
try {
|
||||
const updates = body as { enabled?: boolean; primaryModel?: string; secondaryModel?: string; tags?: string[]; envFile?: string | null };
|
||||
const updates = body as { enabled?: boolean; primaryModel?: string; secondaryModel?: string; availableModels?: string[]; tags?: string[]; envFile?: string | null };
|
||||
const updated = updateToolConfig(initialPath, tool, updates);
|
||||
|
||||
// Broadcast config updated event
|
||||
|
||||
@@ -482,6 +482,18 @@ function buildToolConfigModalContent(tool, config, models, status) {
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
|
||||
// Available Models Section - Unified input with inline models
|
||||
'<div class="tool-config-section">' +
|
||||
'<h4>Available Models <span class="text-muted">(shown in dropdowns below)</span></h4>' +
|
||||
'<div class="tags-unified-input" id="modelsUnifiedInput">' +
|
||||
(config.availableModels || models).map(function(model) {
|
||||
return '<span class="tag-item tag-model">' + escapeHtml(model) + '<button type="button" class="tag-remove" data-model="' + escapeHtml(model) + '">×</button></span>';
|
||||
}).join('') +
|
||||
'<input type="text" id="modelInput" class="tag-inline-input" placeholder="Enter model name and press Enter" />' +
|
||||
'</div>' +
|
||||
'<p class="text-muted text-xs mt-1"><i data-lucide="info" class="w-3 h-3"></i> Click × to remove, type to add new models</p>' +
|
||||
'</div>' +
|
||||
|
||||
// Primary Model Section
|
||||
'<div class="tool-config-section">' +
|
||||
'<h4>Primary Model <span class="text-muted">(CLI endpoint calls)</span></h4>' +
|
||||
@@ -855,6 +867,8 @@ function closeFileBrowserModal(selectedPath) {
|
||||
function initToolConfigModalEvents(tool, currentConfig, models) {
|
||||
// Local tags state (copy from config)
|
||||
var currentTags = (currentConfig.tags || []).slice();
|
||||
// Local available models state (copy from config or use defaults)
|
||||
var currentModels = (currentConfig.availableModels || models).slice();
|
||||
|
||||
// Helper to render tags inline with input
|
||||
function renderTags() {
|
||||
@@ -896,6 +910,58 @@ function initToolConfigModalEvents(tool, currentConfig, models) {
|
||||
});
|
||||
}
|
||||
|
||||
// Helper to render available models inline with input
|
||||
function renderModels() {
|
||||
var container = document.getElementById('modelsUnifiedInput');
|
||||
var input = document.getElementById('modelInput');
|
||||
if (!container) return;
|
||||
|
||||
// Remove existing model items but keep the input
|
||||
container.querySelectorAll('.tag-item').forEach(function(el) { el.remove(); });
|
||||
|
||||
// Insert models before the input
|
||||
currentModels.forEach(function(model) {
|
||||
var modelEl = document.createElement('span');
|
||||
modelEl.className = 'tag-item tag-model';
|
||||
modelEl.innerHTML = escapeHtml(model) + '<button type="button" class="tag-remove" data-model="' + escapeHtml(model) + '">×</button>';
|
||||
container.insertBefore(modelEl, input);
|
||||
});
|
||||
|
||||
// Re-attach remove handlers
|
||||
container.querySelectorAll('.tag-remove').forEach(function(btn) {
|
||||
btn.onclick = function(e) {
|
||||
e.stopPropagation();
|
||||
var modelToRemove = this.getAttribute('data-model');
|
||||
currentModels = currentModels.filter(function(m) { return m !== modelToRemove; });
|
||||
renderModels();
|
||||
updateModelSelects();
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
// Helper to update model select dropdowns with current model list
|
||||
function updateModelSelects() {
|
||||
var primarySelect = document.getElementById('primaryModelSelect');
|
||||
var secondarySelect = document.getElementById('secondaryModelSelect');
|
||||
if (!primarySelect || !secondarySelect) return;
|
||||
|
||||
var primaryValue = primarySelect.value;
|
||||
var secondaryValue = secondarySelect.value;
|
||||
|
||||
// Rebuild options
|
||||
var buildOptions = function(selectedValue) {
|
||||
var html = '';
|
||||
currentModels.forEach(function(m) {
|
||||
html += '<option value="' + escapeHtml(m) + '"' + (m === selectedValue ? ' selected' : '') + '>' + escapeHtml(m) + '</option>';
|
||||
});
|
||||
html += '<option value="__custom__"' + (selectedValue === '__custom__' ? ' selected' : '') + '>Custom...</option>';
|
||||
return html;
|
||||
};
|
||||
|
||||
primarySelect.innerHTML = buildOptions(primaryValue);
|
||||
secondarySelect.innerHTML = buildOptions(secondaryValue);
|
||||
}
|
||||
|
||||
// Click on unified input container focuses the input
|
||||
var unifiedInput = document.getElementById('tagsUnifiedInput');
|
||||
if (unifiedInput) {
|
||||
@@ -906,6 +972,16 @@ function initToolConfigModalEvents(tool, currentConfig, models) {
|
||||
};
|
||||
}
|
||||
|
||||
// Click on models unified input container focuses the input
|
||||
var modelsUnifiedInput = document.getElementById('modelsUnifiedInput');
|
||||
if (modelsUnifiedInput) {
|
||||
modelsUnifiedInput.onclick = function(e) {
|
||||
if (e.target === this) {
|
||||
document.getElementById('modelInput').focus();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Tag input handler
|
||||
var tagInput = document.getElementById('tagInput');
|
||||
if (tagInput) {
|
||||
@@ -933,8 +1009,27 @@ function initToolConfigModalEvents(tool, currentConfig, models) {
|
||||
};
|
||||
});
|
||||
|
||||
// Model input handler
|
||||
var modelInput = document.getElementById('modelInput');
|
||||
if (modelInput) {
|
||||
modelInput.onkeydown = function(e) {
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
var newModel = this.value.trim();
|
||||
if (newModel && currentModels.indexOf(newModel) === -1) {
|
||||
currentModels.push(newModel);
|
||||
renderModels();
|
||||
updateModelSelects();
|
||||
}
|
||||
this.value = '';
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Initialize tags display
|
||||
renderTags();
|
||||
// Initialize models display
|
||||
renderModels();
|
||||
// Initialize lucide icons for predefined buttons
|
||||
if (window.lucide) lucide.createIcons();
|
||||
|
||||
@@ -1020,6 +1115,11 @@ function initToolConfigModalEvents(tool, currentConfig, models) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentModels.length === 0) {
|
||||
showRefreshToast('At least one available model is required', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
// Get envFile value (only for gemini/qwen)
|
||||
var envFileInput = document.getElementById('envFileInput');
|
||||
var envFile = envFileInput ? envFileInput.value.trim() : '';
|
||||
@@ -1028,6 +1128,7 @@ function initToolConfigModalEvents(tool, currentConfig, models) {
|
||||
var updateData = {
|
||||
primaryModel: primaryModel,
|
||||
secondaryModel: secondaryModel,
|
||||
availableModels: currentModels,
|
||||
tags: currentTags
|
||||
};
|
||||
|
||||
|
||||
@@ -33,6 +33,11 @@ export interface ClaudeCliTool {
|
||||
enabled: boolean;
|
||||
primaryModel?: string;
|
||||
secondaryModel?: string;
|
||||
/**
|
||||
* Available models for this tool (shown in UI dropdown)
|
||||
* If not provided, defaults will be used based on tool type
|
||||
*/
|
||||
availableModels?: string[];
|
||||
tags: string[];
|
||||
/**
|
||||
* Tool type determines routing:
|
||||
@@ -122,12 +127,13 @@ export interface ClaudeCliCombinedConfig extends ClaudeCliToolsConfig {
|
||||
// ========== Default Config ==========
|
||||
|
||||
const DEFAULT_TOOLS_CONFIG: ClaudeCliToolsConfig = {
|
||||
version: '3.3.0',
|
||||
version: '3.4.0',
|
||||
tools: {
|
||||
gemini: {
|
||||
enabled: true,
|
||||
primaryModel: 'gemini-2.5-pro',
|
||||
secondaryModel: 'gemini-2.5-flash',
|
||||
availableModels: ['gemini-2.5-pro', 'gemini-2.5-flash', 'gemini-2.0-flash', 'gemini-2.0-flash-thinking', 'gemini-1.5-pro'],
|
||||
tags: [],
|
||||
type: 'builtin'
|
||||
},
|
||||
@@ -135,6 +141,7 @@ const DEFAULT_TOOLS_CONFIG: ClaudeCliToolsConfig = {
|
||||
enabled: true,
|
||||
primaryModel: 'coder-model',
|
||||
secondaryModel: 'coder-model',
|
||||
availableModels: ['coder-model', 'vision-model', 'qwen-2.5-coder', 'qwen-2.5-72b'],
|
||||
tags: [],
|
||||
type: 'builtin'
|
||||
},
|
||||
@@ -142,6 +149,7 @@ const DEFAULT_TOOLS_CONFIG: ClaudeCliToolsConfig = {
|
||||
enabled: true,
|
||||
primaryModel: 'gpt-5.2',
|
||||
secondaryModel: 'gpt-5.2',
|
||||
availableModels: ['gpt-5.2', 'gpt-5', 'gpt5-codex', 'o3', 'o1'],
|
||||
tags: [],
|
||||
type: 'builtin'
|
||||
},
|
||||
@@ -149,6 +157,7 @@ const DEFAULT_TOOLS_CONFIG: ClaudeCliToolsConfig = {
|
||||
enabled: true,
|
||||
primaryModel: 'sonnet',
|
||||
secondaryModel: 'haiku',
|
||||
availableModels: ['opus', 'sonnet', 'haiku'],
|
||||
tags: [],
|
||||
type: 'builtin'
|
||||
},
|
||||
@@ -156,6 +165,7 @@ const DEFAULT_TOOLS_CONFIG: ClaudeCliToolsConfig = {
|
||||
enabled: true,
|
||||
primaryModel: 'opencode/glm-4.7-free',
|
||||
secondaryModel: 'opencode/glm-4.7-free',
|
||||
availableModels: ['opencode/glm-4.7-free', 'opencode/deepseek-v3-free'],
|
||||
tags: [],
|
||||
type: 'builtin'
|
||||
}
|
||||
@@ -1098,6 +1108,7 @@ export function updateToolConfig(
|
||||
enabled: boolean;
|
||||
primaryModel: string;
|
||||
secondaryModel: string;
|
||||
availableModels: string[];
|
||||
tags: string[];
|
||||
envFile: string | null;
|
||||
}>
|
||||
@@ -1114,6 +1125,9 @@ export function updateToolConfig(
|
||||
if (updates.secondaryModel !== undefined) {
|
||||
config.tools[tool].secondaryModel = updates.secondaryModel;
|
||||
}
|
||||
if (updates.availableModels !== undefined) {
|
||||
config.tools[tool].availableModels = updates.availableModels;
|
||||
}
|
||||
if (updates.tags !== undefined) {
|
||||
config.tools[tool].tags = updates.tags;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user