feat: 支持模型别名(PRIMARY_MODEL, SECONDARY_MODEL)并更新CLI命令构建逻辑

This commit is contained in:
catlog22
2026-02-05 20:09:04 +08:00
parent 47c192f584
commit 6576886457
3 changed files with 50 additions and 38 deletions

View File

@@ -1496,7 +1496,7 @@ export async function cliCommand(
console.log(chalk.gray(' --tool <tool> Tool: gemini, qwen, codex (default: gemini)'));
console.log(chalk.gray(' --mode <mode> Mode: analysis, write, auto, review (default: analysis)'));
console.log(chalk.gray(' -d, --debug Enable debug logging for troubleshooting'));
console.log(chalk.gray(' --model <model> Model override'));
console.log(chalk.gray(' --model <model> Model override (supports PRIMARY_MODEL, SECONDARY_MODEL aliases)'));
console.log(chalk.gray(' --cd <path> Working directory'));
console.log(chalk.gray(' --includeDirs <dirs> Additional directories'));
// --timeout removed - controlled by external caller (bash timeout)

View File

@@ -85,7 +85,29 @@ import { findEndpointById } from '../config/litellm-api-config-manager.js';
// CLI Settings (CLI封装) integration
import { loadEndpointSettings, getSettingsFilePath, findEndpoint } from '../config/cli-settings-manager.js';
import { loadClaudeCliTools, getToolConfig, getPrimaryModel } from './claude-cli-tools.js';
import { loadClaudeCliTools, getToolConfig, getPrimaryModel, getSecondaryModel } from './claude-cli-tools.js';
/**
* Resolve model alias to actual model name
* Supports: PRIMARY_MODEL, SECONDARY_MODEL
* Returns original value if not an alias
*/
function resolveModelAlias(model: string | undefined, tool: string, workingDir: string): string | undefined {
if (!model) return model;
const upperModel = model.toUpperCase();
if (upperModel === 'PRIMARY_MODEL') {
return getPrimaryModel(workingDir, tool);
}
if (upperModel === 'SECONDARY_MODEL') {
return getSecondaryModel(workingDir, tool);
}
// Not an alias, return original
return model;
}
/**
* Parse .env file content into key-value pairs
@@ -597,8 +619,10 @@ async function executeCliTool(
// Use configured primary model if no explicit model provided
// This allows --model parameter to override the tool's primaryModel
// Resolve model aliases (PRIMARY_MODEL, SECONDARY_MODEL) before using
// Use undefined if primaryModel is empty string (endpoint.model will be used as fallback)
const apiEndpointEffectiveModel = model || (toolConfig.primaryModel || undefined);
const resolvedApiModel = resolveModelAlias(model, toolName, workingDir);
const apiEndpointEffectiveModel = resolvedApiModel || (toolConfig.primaryModel || undefined);
// Find LiteLLM endpoint configuration
const litellmEndpoint = findEndpointById(workingDir, litellmEndpointId);
@@ -851,7 +875,9 @@ async function executeCliTool(
}
// Use configured primary model if no explicit model provided
const effectiveModel = model || getPrimaryModel(workingDir, tool);
// Resolve model aliases (PRIMARY_MODEL, SECONDARY_MODEL) before using
const resolvedModel = resolveModelAlias(model, tool, workingDir);
const effectiveModel = resolvedModel || getPrimaryModel(workingDir, tool);
// Load and validate settings file for Claude tool (builtin only)
let settingsFilePath: string | undefined;

View File

@@ -15,13 +15,6 @@ const EXCLUDE_DIRS = [
'coverage', '.nyc_output', 'logs', 'tmp', 'temp'
];
// Default models for each tool
const DEFAULT_MODELS = {
gemini: 'gemini-2.5-flash',
qwen: 'coder-model',
codex: 'gpt5-codex'
};
/**
* Count files in directory
*/
@@ -159,33 +152,23 @@ function createPromptFile(prompt) {
}
/**
* Build CLI command using stdin piping for prompt (avoids shell escaping issues)
* Build ccw cli command using prompt file
*/
function buildCliCommand(tool, promptFile, model) {
// Use stdin piping: cat file | tool or Get-Content | tool
// This avoids shell escaping issues with multiline prompts
// Use ccw cli with prompt file
// ccw cli reads prompt from file when using -p @file syntax
const normalizedPath = promptFile.replace(/\\/g, '/');
const isWindows = process.platform === 'win32';
// Build the cat/read command based on platform
const catCmd = isWindows ? `Get-Content -Raw "${normalizedPath}" | ` : `cat "${normalizedPath}" | `;
switch (tool) {
case 'qwen':
return model === 'coder-model'
? `${catCmd}qwen --yolo`
: `${catCmd}qwen -m "${model}" --yolo`;
case 'codex':
// codex uses different syntax - prompt as exec argument
if (isWindows) {
return `codex --full-auto exec (Get-Content -Raw "${normalizedPath}") -m "${model}" --skip-git-repo-check -s danger-full-access`;
}
return `codex --full-auto exec "$(cat "${normalizedPath}")" -m "${model}" --skip-git-repo-check -s danger-full-access`;
case 'gemini':
default:
// gemini reads from stdin when no positional prompt is given
return `${catCmd}gemini -m "${model}" --yolo`;
}
// Read prompt content for ccw cli -p parameter
const promptContent = readFileSync(promptFile, 'utf8');
// Escape single quotes in prompt for shell
const escapedPrompt = promptContent.replace(/'/g, "'\\''");
// Build ccw cli command with --mode write
// Format: ccw cli -p 'prompt content' --tool <tool> --model <model> --mode write
return `ccw cli -p '${escapedPrompt}' --tool ${tool} --model ${model} --mode write`;
}
/**
@@ -227,8 +210,9 @@ async function execute(params) {
};
}
// Set model
const actualModel = model || DEFAULT_MODELS[tool] || DEFAULT_MODELS.gemini;
// Set model - if not provided by user, use SECONDARY_MODEL alias
// The ccw cli will resolve this to the actual secondary model from cli-tools.json
const actualModel = model || 'SECONDARY_MODEL';
// Load template
const templateContent = loadTemplate();
@@ -344,13 +328,15 @@ Instructions:
*/
export const updateModuleClaudeTool = {
name: 'update_module_claude',
description: `Generate/update CLAUDE.md module documentation using CLI tools.
description: `Generate/update CLAUDE.md module documentation using ccw cli.
Strategies:
- single-layer: Read current dir code + child CLAUDE.md, generate ./CLAUDE.md
- multi-layer: Read all files, generate CLAUDE.md for each directory
Tools: gemini (default), qwen, codex`,
Tools: gemini (default), qwen, codex
Model: Supports model aliases (PRIMARY_MODEL, SECONDARY_MODEL) or explicit model names
Default: SECONDARY_MODEL (resolved from ~/.claude/cli-tools.json)`,
parameters: {
type: 'object',
properties: {