mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-05 01:50:27 +08:00
feat(cli): add settings file support for builtin Claude
- Enhance CLI status rendering to display settings file information for builtin Claude. - Introduce settings file input in CLI manager for configuring the path to settings.json. - Update Claude CLI tool interface to include settingsFile property. - Implement settings file resolution and validation in CLI executor. - Create a new collaborative planning workflow command with detailed documentation. - Add test scripts for debugging tool configuration and command building.
This commit is contained in:
@@ -525,6 +525,33 @@ function renderCliStatus() {
|
||||
const enabledCliSettings = isClaude ? cliSettingsEndpoints.filter(ep => ep.enabled) : [];
|
||||
const hasCliSettings = enabledCliSettings.length > 0;
|
||||
|
||||
// Build Settings File info for builtin Claude
|
||||
let settingsFileInfo = '';
|
||||
if (isClaude && config.type === 'builtin' && config.settingsFile) {
|
||||
const settingsFile = config.settingsFile;
|
||||
// Simple path resolution attempt for display (no actual filesystem access)
|
||||
const resolvedPath = settingsFile.startsWith('~')
|
||||
? settingsFile.replace('~', (typeof os !== 'undefined' && os.homedir) ? os.homedir() : '~')
|
||||
: settingsFile;
|
||||
|
||||
settingsFileInfo = `
|
||||
<div class="cli-settings-info mt-2 p-2 rounded bg-muted/50 text-xs">
|
||||
<div class="flex items-center gap-1 text-muted-foreground mb-1">
|
||||
<i data-lucide="file-key" class="w-3 h-3"></i>
|
||||
<span>Settings File:</span>
|
||||
</div>
|
||||
<div class="text-foreground font-mono text-[10px] break-all" title="${resolvedPath}">
|
||||
${settingsFile}
|
||||
</div>
|
||||
${settingsFile !== resolvedPath ? `
|
||||
<div class="text-muted-foreground mt-1 font-mono text-[10px] break-all">
|
||||
→ ${resolvedPath}
|
||||
</div>
|
||||
` : ''}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
// Build CLI Settings badge for Claude
|
||||
let cliSettingsBadge = '';
|
||||
if (isClaude && hasCliSettings) {
|
||||
@@ -588,6 +615,7 @@ function renderCliStatus() {
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
${settingsFileInfo}
|
||||
${cliSettingsInfo}
|
||||
<div class="cli-tool-actions mt-3 flex gap-2">
|
||||
${isAvailable ? (isEnabled
|
||||
|
||||
@@ -562,6 +562,27 @@ function buildToolConfigModalContent(tool, config, models, status) {
|
||||
'</div>'
|
||||
) : '') +
|
||||
|
||||
// Claude Settings File Section (only for builtin claude type)
|
||||
(tool === 'claude' && config.type === 'builtin' ? (
|
||||
'<div class="tool-config-section">' +
|
||||
'<h4><i data-lucide="file-key" class="w-3.5 h-3.5"></i> Settings File <span class="text-muted">(optional)</span></h4>' +
|
||||
'<div class="env-file-input-group">' +
|
||||
'<div class="env-file-input-row">' +
|
||||
'<input type="text" id="claudeSettingsFileInput" class="tool-config-input" ' +
|
||||
'placeholder="~/path/to/settings.json or D:\\path\\to\\settings.json" ' +
|
||||
'value="' + (config.settingsFile ? escapeHtml(config.settingsFile) : '') + '" />' +
|
||||
'<button type="button" class="btn-sm btn-outline" id="claudeSettingsFileBrowseBtn">' +
|
||||
'<i data-lucide="folder-open" class="w-3.5 h-3.5"></i> Browse' +
|
||||
'</button>' +
|
||||
'</div>' +
|
||||
'<p class="env-file-hint">' +
|
||||
'<i data-lucide="info" class="w-3 h-3"></i> ' +
|
||||
'Path to Claude CLI settings.json file (supports ~, absolute, and Windows paths)' +
|
||||
'</p>' +
|
||||
'</div>' +
|
||||
'</div>'
|
||||
) : '') +
|
||||
|
||||
// Footer
|
||||
'<div class="tool-config-footer">' +
|
||||
'<button class="btn btn-outline" onclick="closeModal()">' + t('common.cancel') + '</button>' +
|
||||
@@ -1124,6 +1145,10 @@ function initToolConfigModalEvents(tool, currentConfig, models) {
|
||||
var envFileInput = document.getElementById('envFileInput');
|
||||
var envFile = envFileInput ? envFileInput.value.trim() : '';
|
||||
|
||||
// Get settingsFile value (only for builtin claude)
|
||||
var claudeSettingsFileInput = document.getElementById('claudeSettingsFileInput');
|
||||
var settingsFile = claudeSettingsFileInput ? claudeSettingsFileInput.value.trim() : '';
|
||||
|
||||
try {
|
||||
var updateData = {
|
||||
primaryModel: primaryModel,
|
||||
@@ -1137,6 +1162,11 @@ function initToolConfigModalEvents(tool, currentConfig, models) {
|
||||
updateData.envFile = envFile || null;
|
||||
}
|
||||
|
||||
// Only include settingsFile for builtin claude tool
|
||||
if (tool === 'claude' && config.type === 'builtin') {
|
||||
updateData.settingsFile = settingsFile || null;
|
||||
}
|
||||
|
||||
await updateCliToolConfig(tool, updateData);
|
||||
// Reload config to reflect changes
|
||||
await loadCliToolConfig();
|
||||
@@ -1164,6 +1194,20 @@ function initToolConfigModalEvents(tool, currentConfig, models) {
|
||||
};
|
||||
}
|
||||
|
||||
// Claude Settings File browse button (only for builtin claude)
|
||||
var claudeSettingsFileBrowseBtn = document.getElementById('claudeSettingsFileBrowseBtn');
|
||||
if (claudeSettingsFileBrowseBtn) {
|
||||
claudeSettingsFileBrowseBtn.onclick = function() {
|
||||
showFileBrowserModal(function(selectedPath) {
|
||||
var claudeSettingsFileInput = document.getElementById('claudeSettingsFileInput');
|
||||
if (claudeSettingsFileInput && selectedPath) {
|
||||
claudeSettingsFileInput.value = selectedPath;
|
||||
claudeSettingsFileInput.focus();
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
// Initialize lucide icons in modal
|
||||
if (window.lucide) lucide.createIcons();
|
||||
}
|
||||
|
||||
@@ -56,6 +56,12 @@ export interface ClaudeCliTool {
|
||||
* Supports both absolute paths and paths relative to home directory (e.g., ~/.my-env)
|
||||
*/
|
||||
envFile?: string;
|
||||
/**
|
||||
* Path to Claude CLI settings.json file (builtin claude only)
|
||||
* Passed to Claude CLI via --settings parameter
|
||||
* Supports ~, absolute, relative, and Windows paths
|
||||
*/
|
||||
settingsFile?: string;
|
||||
}
|
||||
|
||||
export type CliToolName = 'gemini' | 'qwen' | 'codex' | 'claude' | 'opencode' | string;
|
||||
@@ -279,7 +285,8 @@ function ensureToolTags(tool: Partial<ClaudeCliTool>): ClaudeCliTool {
|
||||
primaryModel: tool.primaryModel,
|
||||
secondaryModel: tool.secondaryModel,
|
||||
tags: tool.tags ?? [],
|
||||
envFile: tool.envFile
|
||||
envFile: tool.envFile,
|
||||
settingsFile: tool.settingsFile
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1015,6 +1022,7 @@ export function getToolConfig(projectDir: string, tool: string): {
|
||||
secondaryModel: string;
|
||||
tags?: string[];
|
||||
envFile?: string;
|
||||
settingsFile?: string;
|
||||
} {
|
||||
const config = loadClaudeCliTools(projectDir);
|
||||
const toolConfig = config.tools[tool];
|
||||
@@ -1034,7 +1042,8 @@ export function getToolConfig(projectDir: string, tool: string): {
|
||||
primaryModel: toolConfig.primaryModel ?? '',
|
||||
secondaryModel: toolConfig.secondaryModel ?? '',
|
||||
tags: toolConfig.tags,
|
||||
envFile: toolConfig.envFile
|
||||
envFile: toolConfig.envFile,
|
||||
settingsFile: toolConfig.settingsFile
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1051,6 +1060,7 @@ export function updateToolConfig(
|
||||
availableModels: string[];
|
||||
tags: string[];
|
||||
envFile: string | null;
|
||||
settingsFile: string | null;
|
||||
}>
|
||||
): ClaudeCliToolsConfig {
|
||||
const config = loadClaudeCliTools(projectDir);
|
||||
@@ -1079,6 +1089,14 @@ export function updateToolConfig(
|
||||
config.tools[tool].envFile = updates.envFile;
|
||||
}
|
||||
}
|
||||
// Handle settingsFile: set to undefined if null/empty, otherwise set value
|
||||
if (updates.settingsFile !== undefined) {
|
||||
if (updates.settingsFile === null || updates.settingsFile === '') {
|
||||
delete config.tools[tool].settingsFile;
|
||||
} else {
|
||||
config.tools[tool].settingsFile = updates.settingsFile;
|
||||
}
|
||||
}
|
||||
saveClaudeCliTools(projectDir, config);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import { spawn, ChildProcess } from 'child_process';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as os from 'os';
|
||||
import { validatePath } from '../utils/path-resolver.js';
|
||||
import { validatePath, resolvePath } from '../utils/path-resolver.js';
|
||||
import { escapeWindowsArg } from '../utils/shell-escape.js';
|
||||
import { buildCommand, checkToolAvailability, clearToolCache, debugLog, errorLog, type NativeResumeConfig, type ToolAvailability } from './cli-executor-utils.js';
|
||||
import type { ConversationRecord, ConversationTurn, ExecutionOutput, ExecutionRecord } from './cli-executor-state.js';
|
||||
@@ -85,7 +85,7 @@ 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 } from './claude-cli-tools.js';
|
||||
import { loadClaudeCliTools, getToolConfig, getPrimaryModel } from './claude-cli-tools.js';
|
||||
|
||||
/**
|
||||
* Parse .env file content into key-value pairs
|
||||
@@ -338,8 +338,7 @@ import {
|
||||
import {
|
||||
isToolEnabled as isToolEnabledFromConfig,
|
||||
enableTool as enableToolFromConfig,
|
||||
disableTool as disableToolFromConfig,
|
||||
getPrimaryModel
|
||||
disableTool as disableToolFromConfig
|
||||
} from './cli-config-manager.js';
|
||||
|
||||
// Built-in CLI tools
|
||||
@@ -794,6 +793,25 @@ async function executeCliTool(
|
||||
// Use configured primary model if no explicit model provided
|
||||
const effectiveModel = model || getPrimaryModel(workingDir, tool);
|
||||
|
||||
// Load and validate settings file for Claude tool (builtin only)
|
||||
let settingsFilePath: string | undefined;
|
||||
if (tool === 'claude') {
|
||||
const toolConfig = getToolConfig(workingDir, tool);
|
||||
if (toolConfig.settingsFile) {
|
||||
try {
|
||||
const resolved = resolvePath(toolConfig.settingsFile);
|
||||
if (fs.existsSync(resolved)) {
|
||||
settingsFilePath = resolved;
|
||||
debugLog('SETTINGS_FILE', `Resolved Claude settings file`, { configured: toolConfig.settingsFile, resolved });
|
||||
} else {
|
||||
errorLog('SETTINGS_FILE', `Claude settings file not found, skipping`, { configured: toolConfig.settingsFile, resolved });
|
||||
}
|
||||
} catch (err) {
|
||||
errorLog('SETTINGS_FILE', `Failed to resolve Claude settings file`, { configured: toolConfig.settingsFile, error: (err as Error).message });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Build command
|
||||
const { command, args, useStdin, outputFormat: autoDetectedFormat } = buildCommand({
|
||||
tool,
|
||||
@@ -803,6 +821,7 @@ async function executeCliTool(
|
||||
dir: cd,
|
||||
include: includeDirs,
|
||||
nativeResume: nativeResumeConfig,
|
||||
settingsFile: settingsFilePath,
|
||||
reviewOptions: mode === 'review' ? { uncommitted, base, commit, title } : undefined
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user