mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-11 02:33:51 +08:00
feat(cli-manager): add CLI wrapper endpoints management and UI integration
- Introduced functions to load and toggle CLI wrapper endpoints from the API. - Updated the CLI manager UI to display and manage CLI wrapper endpoints. - Removed CodexLens and Semantic Search from the tools section, now managed in their dedicated pages. feat(codexlens-manager): move File Watcher card to the CodexLens Manager page - Relocated the File Watcher card from the right column to the main content area of the CodexLens Manager page. refactor(claude-cli-tools): enhance CLI tools configuration and migration - Added support for new tool types: 'cli-wrapper' and 'api-endpoint'. - Updated migration logic to handle new tool types and preserve endpoint IDs. - Deprecated previous custom endpoint handling in favor of the new structure. feat(cli-executor-core): integrate CLI settings for custom endpoint execution - Implemented execution logic for custom CLI封装 endpoints using settings files. - Enhanced error handling and output logging for CLI executions. - Updated tool identification logic to support both built-in tools and custom endpoints.
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
|
||||
import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync, readdirSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
import * as os from 'os';
|
||||
import { getCCWHome, ensureStorageDir } from './storage-paths.js';
|
||||
import {
|
||||
ClaudeCliSettings,
|
||||
@@ -17,6 +18,10 @@ import {
|
||||
validateSettings,
|
||||
createDefaultSettings
|
||||
} from '../types/cli-settings.js';
|
||||
import {
|
||||
addClaudeCustomEndpoint,
|
||||
removeClaudeCustomEndpoint
|
||||
} from '../tools/claude-cli-tools.js';
|
||||
|
||||
/**
|
||||
* Get CLI settings directory path
|
||||
@@ -116,6 +121,23 @@ export function saveEndpointSettings(request: SaveEndpointRequest): SettingsOper
|
||||
index.set(endpointId, metadata);
|
||||
saveIndex(index);
|
||||
|
||||
// Sync with cli-tools.json for ccw cli --tool integration
|
||||
// API endpoints are added as tools with type: 'api-endpoint'
|
||||
// Usage: ccw cli -p "..." --tool custom --model <endpoint-id> --mode analysis
|
||||
try {
|
||||
const projectDir = os.homedir(); // Use home dir as base for global config
|
||||
addClaudeCustomEndpoint(projectDir, {
|
||||
id: endpointId,
|
||||
name: request.name,
|
||||
enabled: request.enabled ?? true
|
||||
// No cli-wrapper tag -> registers as type: 'api-endpoint'
|
||||
});
|
||||
console.log(`[CliSettings] Synced endpoint ${endpointId} to cli-tools.json tools`);
|
||||
} catch (syncError) {
|
||||
console.warn(`[CliSettings] Failed to sync with cli-tools.json: ${syncError}`);
|
||||
// Non-fatal: continue even if sync fails
|
||||
}
|
||||
|
||||
// Return full endpoint settings
|
||||
const endpoint: EndpointSettings = {
|
||||
...metadata,
|
||||
@@ -195,6 +217,16 @@ export function deleteEndpointSettings(endpointId: string): SettingsOperationRes
|
||||
index.delete(endpointId);
|
||||
saveIndex(index);
|
||||
|
||||
// Step 3: Remove from cli-tools.json tools (api-endpoint type)
|
||||
try {
|
||||
const projectDir = os.homedir();
|
||||
removeClaudeCustomEndpoint(projectDir, endpointId);
|
||||
console.log(`[CliSettings] Removed endpoint ${endpointId} from cli-tools.json tools`);
|
||||
} catch (syncError) {
|
||||
console.warn(`[CliSettings] Failed to remove from cli-tools.json: ${syncError}`);
|
||||
// Non-fatal: continue even if sync fails
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: 'Endpoint deleted'
|
||||
@@ -271,6 +303,20 @@ export function toggleEndpointEnabled(endpointId: string, enabled: boolean): Set
|
||||
index.set(endpointId, metadata);
|
||||
saveIndex(index);
|
||||
|
||||
// Sync enabled status with cli-tools.json tools (api-endpoint type)
|
||||
try {
|
||||
const projectDir = os.homedir();
|
||||
addClaudeCustomEndpoint(projectDir, {
|
||||
id: endpointId,
|
||||
name: metadata.name,
|
||||
enabled: enabled
|
||||
// No cli-wrapper tag -> updates as type: 'api-endpoint'
|
||||
});
|
||||
console.log(`[CliSettings] Synced endpoint ${endpointId} enabled=${enabled} to cli-tools.json tools`);
|
||||
} catch (syncError) {
|
||||
console.warn(`[CliSettings] Failed to sync enabled status to cli-tools.json: ${syncError}`);
|
||||
}
|
||||
|
||||
// Load full settings for response
|
||||
const endpoint = loadEndpointSettings(endpointId);
|
||||
|
||||
@@ -357,3 +403,58 @@ export function getEnabledEndpoints(): EndpointSettings[] {
|
||||
const { endpoints } = listAllSettings();
|
||||
return endpoints.filter(ep => ep.enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find endpoint by name (case-insensitive)
|
||||
* Useful for CLI where user types --tool doubao instead of --tool ep-xxx
|
||||
*/
|
||||
export function findEndpointByName(name: string): EndpointSettings | null {
|
||||
const { endpoints } = listAllSettings();
|
||||
const lowerName = name.toLowerCase();
|
||||
return endpoints.find(ep => ep.name.toLowerCase() === lowerName) || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find endpoint by ID or name
|
||||
* First tries exact ID match, then falls back to name match
|
||||
*/
|
||||
export function findEndpoint(idOrName: string): EndpointSettings | null {
|
||||
// Try by ID first
|
||||
const byId = loadEndpointSettings(idOrName);
|
||||
if (byId) return byId;
|
||||
|
||||
// Try by name
|
||||
return findEndpointByName(idOrName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate endpoint name for CLI compatibility
|
||||
* Name must be: lowercase, alphanumeric, hyphens allowed, no spaces or special chars
|
||||
*/
|
||||
export function validateEndpointName(name: string): { valid: boolean; error?: string } {
|
||||
if (!name || name.trim().length === 0) {
|
||||
return { valid: false, error: 'Name is required' };
|
||||
}
|
||||
|
||||
// Check for valid characters: a-z, 0-9, hyphen, underscore
|
||||
const validPattern = /^[a-z][a-z0-9_-]*$/;
|
||||
if (!validPattern.test(name.toLowerCase())) {
|
||||
return {
|
||||
valid: false,
|
||||
error: 'Name must start with a letter and contain only letters, numbers, hyphens, and underscores'
|
||||
};
|
||||
}
|
||||
|
||||
// Check length
|
||||
if (name.length > 32) {
|
||||
return { valid: false, error: 'Name must be 32 characters or less' };
|
||||
}
|
||||
|
||||
// Check if name conflicts with built-in tools
|
||||
const builtinTools = ['gemini', 'qwen', 'codex', 'claude', 'opencode', 'litellm'];
|
||||
if (builtinTools.includes(name.toLowerCase())) {
|
||||
return { valid: false, error: `Name "${name}" conflicts with a built-in tool` };
|
||||
}
|
||||
|
||||
return { valid: true };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user