Skip to content

Commit 6576886

Browse files
author
catlog22
committed
feat: 支持模型别名(PRIMARY_MODEL, SECONDARY_MODEL)并更新CLI命令构建逻辑
1 parent 47c192f commit 6576886

3 files changed

Lines changed: 50 additions & 38 deletions

File tree

ccw/src/commands/cli.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1496,7 +1496,7 @@ export async function cliCommand(
14961496
console.log(chalk.gray(' --tool <tool> Tool: gemini, qwen, codex (default: gemini)'));
14971497
console.log(chalk.gray(' --mode <mode> Mode: analysis, write, auto, review (default: analysis)'));
14981498
console.log(chalk.gray(' -d, --debug Enable debug logging for troubleshooting'));
1499-
console.log(chalk.gray(' --model <model> Model override'));
1499+
console.log(chalk.gray(' --model <model> Model override (supports PRIMARY_MODEL, SECONDARY_MODEL aliases)'));
15001500
console.log(chalk.gray(' --cd <path> Working directory'));
15011501
console.log(chalk.gray(' --includeDirs <dirs> Additional directories'));
15021502
// --timeout removed - controlled by external caller (bash timeout)

ccw/src/tools/cli-executor-core.ts

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,29 @@ import { findEndpointById } from '../config/litellm-api-config-manager.js';
8585

8686
// CLI Settings (CLI封装) integration
8787
import { loadEndpointSettings, getSettingsFilePath, findEndpoint } from '../config/cli-settings-manager.js';
88-
import { loadClaudeCliTools, getToolConfig, getPrimaryModel } from './claude-cli-tools.js';
88+
import { loadClaudeCliTools, getToolConfig, getPrimaryModel, getSecondaryModel } from './claude-cli-tools.js';
89+
90+
/**
91+
* Resolve model alias to actual model name
92+
* Supports: PRIMARY_MODEL, SECONDARY_MODEL
93+
* Returns original value if not an alias
94+
*/
95+
function resolveModelAlias(model: string | undefined, tool: string, workingDir: string): string | undefined {
96+
if (!model) return model;
97+
98+
const upperModel = model.toUpperCase();
99+
100+
if (upperModel === 'PRIMARY_MODEL') {
101+
return getPrimaryModel(workingDir, tool);
102+
}
103+
104+
if (upperModel === 'SECONDARY_MODEL') {
105+
return getSecondaryModel(workingDir, tool);
106+
}
107+
108+
// Not an alias, return original
109+
return model;
110+
}
89111

90112
/**
91113
* Parse .env file content into key-value pairs
@@ -597,8 +619,10 @@ async function executeCliTool(
597619

598620
// Use configured primary model if no explicit model provided
599621
// This allows --model parameter to override the tool's primaryModel
622+
// Resolve model aliases (PRIMARY_MODEL, SECONDARY_MODEL) before using
600623
// Use undefined if primaryModel is empty string (endpoint.model will be used as fallback)
601-
const apiEndpointEffectiveModel = model || (toolConfig.primaryModel || undefined);
624+
const resolvedApiModel = resolveModelAlias(model, toolName, workingDir);
625+
const apiEndpointEffectiveModel = resolvedApiModel || (toolConfig.primaryModel || undefined);
602626

603627
// Find LiteLLM endpoint configuration
604628
const litellmEndpoint = findEndpointById(workingDir, litellmEndpointId);
@@ -851,7 +875,9 @@ async function executeCliTool(
851875
}
852876

853877
// Use configured primary model if no explicit model provided
854-
const effectiveModel = model || getPrimaryModel(workingDir, tool);
878+
// Resolve model aliases (PRIMARY_MODEL, SECONDARY_MODEL) before using
879+
const resolvedModel = resolveModelAlias(model, tool, workingDir);
880+
const effectiveModel = resolvedModel || getPrimaryModel(workingDir, tool);
855881

856882
// Load and validate settings file for Claude tool (builtin only)
857883
let settingsFilePath: string | undefined;

ccw/src/tools/update-module-claude.js

Lines changed: 20 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,6 @@ const EXCLUDE_DIRS = [
1515
'coverage', '.nyc_output', 'logs', 'tmp', 'temp'
1616
];
1717

18-
// Default models for each tool
19-
const DEFAULT_MODELS = {
20-
gemini: 'gemini-2.5-flash',
21-
qwen: 'coder-model',
22-
codex: 'gpt5-codex'
23-
};
24-
2518
/**
2619
* Count files in directory
2720
*/
@@ -159,33 +152,23 @@ function createPromptFile(prompt) {
159152
}
160153

161154
/**
162-
* Build CLI command using stdin piping for prompt (avoids shell escaping issues)
155+
* Build ccw cli command using prompt file
163156
*/
164157
function buildCliCommand(tool, promptFile, model) {
165-
// Use stdin piping: cat file | tool or Get-Content | tool
166-
// This avoids shell escaping issues with multiline prompts
158+
// Use ccw cli with prompt file
159+
// ccw cli reads prompt from file when using -p @file syntax
167160
const normalizedPath = promptFile.replace(/\\/g, '/');
168161
const isWindows = process.platform === 'win32';
169-
170-
// Build the cat/read command based on platform
171-
const catCmd = isWindows ? `Get-Content -Raw "${normalizedPath}" | ` : `cat "${normalizedPath}" | `;
172-
173-
switch (tool) {
174-
case 'qwen':
175-
return model === 'coder-model'
176-
? `${catCmd}qwen --yolo`
177-
: `${catCmd}qwen -m "${model}" --yolo`;
178-
case 'codex':
179-
// codex uses different syntax - prompt as exec argument
180-
if (isWindows) {
181-
return `codex --full-auto exec (Get-Content -Raw "${normalizedPath}") -m "${model}" --skip-git-repo-check -s danger-full-access`;
182-
}
183-
return `codex --full-auto exec "$(cat "${normalizedPath}")" -m "${model}" --skip-git-repo-check -s danger-full-access`;
184-
case 'gemini':
185-
default:
186-
// gemini reads from stdin when no positional prompt is given
187-
return `${catCmd}gemini -m "${model}" --yolo`;
188-
}
162+
163+
// Read prompt content for ccw cli -p parameter
164+
const promptContent = readFileSync(promptFile, 'utf8');
165+
166+
// Escape single quotes in prompt for shell
167+
const escapedPrompt = promptContent.replace(/'/g, "'\\''");
168+
169+
// Build ccw cli command with --mode write
170+
// Format: ccw cli -p 'prompt content' --tool <tool> --model <model> --mode write
171+
return `ccw cli -p '${escapedPrompt}' --tool ${tool} --model ${model} --mode write`;
189172
}
190173

191174
/**
@@ -227,8 +210,9 @@ async function execute(params) {
227210
};
228211
}
229212

230-
// Set model
231-
const actualModel = model || DEFAULT_MODELS[tool] || DEFAULT_MODELS.gemini;
213+
// Set model - if not provided by user, use SECONDARY_MODEL alias
214+
// The ccw cli will resolve this to the actual secondary model from cli-tools.json
215+
const actualModel = model || 'SECONDARY_MODEL';
232216

233217
// Load template
234218
const templateContent = loadTemplate();
@@ -344,13 +328,15 @@ Instructions:
344328
*/
345329
export const updateModuleClaudeTool = {
346330
name: 'update_module_claude',
347-
description: `Generate/update CLAUDE.md module documentation using CLI tools.
331+
description: `Generate/update CLAUDE.md module documentation using ccw cli.
348332
349333
Strategies:
350334
- single-layer: Read current dir code + child CLAUDE.md, generate ./CLAUDE.md
351335
- multi-layer: Read all files, generate CLAUDE.md for each directory
352336
353-
Tools: gemini (default), qwen, codex`,
337+
Tools: gemini (default), qwen, codex
338+
Model: Supports model aliases (PRIMARY_MODEL, SECONDARY_MODEL) or explicit model names
339+
Default: SECONDARY_MODEL (resolved from ~/.claude/cli-tools.json)`,
354340
parameters: {
355341
type: 'object',
356342
properties: {

0 commit comments

Comments
 (0)