mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-13 02:41:50 +08:00
feat(loop): support external CLI tools (cli-wrapper) in task management
- Fix missing i18n translations: loop.add, loop.save, loop.cancel - Replace hardcoded validTools with dynamic tool loading from cli-tools.json - Support external CLI wrappers (like doubao) in task creation and updates - Add getEnabledToolsList() helper to fetch enabled tools dynamically - Update mapIssueToolToLoopTool() to accept any string tool name - Update validateTool() to use dynamic tool list - Change LoopTask.tool type from specific strings to string (accepts any tool) This allows tasks to use any enabled CLI tool from configuration, including builtin tools, cli-wrappers, and api-endpoints, not just the hardcoded ['bash', 'gemini', 'codex', 'qwen', 'claude'].
This commit is contained in:
@@ -29,11 +29,13 @@
|
|||||||
|
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
import { randomBytes } from 'crypto';
|
import { randomBytes } from 'crypto';
|
||||||
|
import * as os from 'os';
|
||||||
import type { RouteContext } from './types.js';
|
import type { RouteContext } from './types.js';
|
||||||
import { LoopStatus } from '../../types/loop.js';
|
import { LoopStatus } from '../../types/loop.js';
|
||||||
import type { LoopState } from '../../types/loop.js';
|
import type { LoopState } from '../../types/loop.js';
|
||||||
import { TaskStorageManager, type TaskCreateRequest, type TaskUpdateRequest, type TaskReorderRequest } from '../../tools/loop-task-manager.js';
|
import { TaskStorageManager, type TaskCreateRequest, type TaskUpdateRequest, type TaskReorderRequest } from '../../tools/loop-task-manager.js';
|
||||||
import { executeCliTool } from '../../tools/cli-executor.js';
|
import { executeCliTool } from '../../tools/cli-executor.js';
|
||||||
|
import { loadClaudeCliTools } from '../../tools/claude-cli-tools.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* V2 Loop Create Request
|
* V2 Loop Create Request
|
||||||
@@ -710,9 +712,17 @@ export async function handleLoopV2Routes(ctx: RouteContext): Promise<boolean> {
|
|||||||
return { success: false, error: 'tool is required', status: 400 };
|
return { success: false, error: 'tool is required', status: 400 };
|
||||||
}
|
}
|
||||||
|
|
||||||
const validTools = ['bash', 'gemini', 'codex', 'qwen', 'claude'];
|
// Get enabled tools from cli-tools.json dynamically
|
||||||
|
const cliToolsConfig = loadClaudeCliTools(os.homedir());
|
||||||
|
const enabledTools = Object.entries(cliToolsConfig.tools || {})
|
||||||
|
.filter(([_, config]) => config.enabled === true)
|
||||||
|
.map(([name]) => name);
|
||||||
|
|
||||||
|
// Also allow 'bash' as a special case (built-in tool)
|
||||||
|
const validTools = ['bash', ...enabledTools];
|
||||||
|
|
||||||
if (!validTools.includes(tool)) {
|
if (!validTools.includes(tool)) {
|
||||||
return { success: false, error: `tool must be one of: ${validTools.join(', ')}`, status: 400 };
|
return { success: false, error: `tool must be one of enabled tools: ${validTools.join(', ')}`, status: 400 };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mode || typeof mode !== 'string') {
|
if (!mode || typeof mode !== 'string') {
|
||||||
@@ -1303,12 +1313,23 @@ function isValidId(id: string): boolean {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get enabled tools list
|
||||||
|
*/
|
||||||
|
function getEnabledToolsList(): string[] {
|
||||||
|
const cliToolsConfig = loadClaudeCliTools(os.homedir());
|
||||||
|
const enabledTools = Object.entries(cliToolsConfig.tools || {})
|
||||||
|
.filter(([_, config]) => config.enabled === true)
|
||||||
|
.map(([name]) => name);
|
||||||
|
return ['bash', ...enabledTools];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map issue tool to loop tool
|
* Map issue tool to loop tool
|
||||||
*/
|
*/
|
||||||
function mapIssueToolToLoopTool(tool: any): 'bash' | 'gemini' | 'codex' | 'qwen' | 'claude' | null {
|
function mapIssueToolToLoopTool(tool: any): string | null {
|
||||||
const validTools = ['bash', 'gemini', 'codex', 'qwen', 'claude'];
|
const validTools = getEnabledToolsList();
|
||||||
if (validTools.includes(tool)) return tool as any;
|
if (validTools.includes(tool)) return tool;
|
||||||
// Map aliases
|
// Map aliases
|
||||||
if (tool === 'ccw') return 'gemini';
|
if (tool === 'ccw') return 'gemini';
|
||||||
if (tool === 'ai') return 'gemini';
|
if (tool === 'ai') return 'gemini';
|
||||||
@@ -1343,7 +1364,7 @@ function mapIssueOnError(onError: any): 'continue' | 'pause' | 'fail_fast' | und
|
|||||||
* Validate tool value
|
* Validate tool value
|
||||||
*/
|
*/
|
||||||
function validateTool(tool: any): boolean {
|
function validateTool(tool: any): boolean {
|
||||||
const validTools = ['bash', 'gemini', 'codex', 'qwen', 'claude'];
|
const validTools = getEnabledToolsList();
|
||||||
return validTools.includes(tool);
|
return validTools.includes(tool);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2202,6 +2202,9 @@ const i18n = {
|
|||||||
'loop.kanban.noBoardData': 'No tasks to display',
|
'loop.kanban.noBoardData': 'No tasks to display',
|
||||||
'loop.listView': 'List View',
|
'loop.listView': 'List View',
|
||||||
'loop.addTask': 'Add Task',
|
'loop.addTask': 'Add Task',
|
||||||
|
'loop.add': 'Add',
|
||||||
|
'loop.save': 'Save',
|
||||||
|
'loop.cancel': 'Cancel',
|
||||||
|
|
||||||
// Navigation & Grouping
|
// Navigation & Grouping
|
||||||
'loop.nav.groupBy': 'Group By',
|
'loop.nav.groupBy': 'Group By',
|
||||||
@@ -4796,6 +4799,9 @@ const i18n = {
|
|||||||
'loop.kanban.noBoardData': '没有要显示的任务',
|
'loop.kanban.noBoardData': '没有要显示的任务',
|
||||||
'loop.listView': '列表视图',
|
'loop.listView': '列表视图',
|
||||||
'loop.addTask': '添加任务',
|
'loop.addTask': '添加任务',
|
||||||
|
'loop.add': '添加',
|
||||||
|
'loop.save': '保存',
|
||||||
|
'loop.cancel': '取消',
|
||||||
|
|
||||||
// Navigation & Grouping
|
// Navigation & Grouping
|
||||||
'loop.nav.groupBy': '分组',
|
'loop.nav.groupBy': '分组',
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ export interface LoopTask {
|
|||||||
/** Task description (what to do) */
|
/** Task description (what to do) */
|
||||||
description: string;
|
description: string;
|
||||||
|
|
||||||
/** CLI tool to use */
|
/** CLI tool to use (bash, builtin tools, cli-wrapper, api-endpoint) */
|
||||||
tool: 'bash' | 'gemini' | 'codex' | 'qwen' | 'claude';
|
tool: string;
|
||||||
|
|
||||||
/** Execution mode */
|
/** Execution mode */
|
||||||
mode: 'analysis' | 'write' | 'review';
|
mode: 'analysis' | 'write' | 'review';
|
||||||
|
|||||||
Reference in New Issue
Block a user