mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-05 01:50:27 +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 { randomBytes } from 'crypto';
|
||||
import * as os from 'os';
|
||||
import type { RouteContext } from './types.js';
|
||||
import { LoopStatus } 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 { executeCliTool } from '../../tools/cli-executor.js';
|
||||
import { loadClaudeCliTools } from '../../tools/claude-cli-tools.js';
|
||||
|
||||
/**
|
||||
* 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 };
|
||||
}
|
||||
|
||||
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)) {
|
||||
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') {
|
||||
@@ -1303,12 +1313,23 @@ function isValidId(id: string): boolean {
|
||||
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
|
||||
*/
|
||||
function mapIssueToolToLoopTool(tool: any): 'bash' | 'gemini' | 'codex' | 'qwen' | 'claude' | null {
|
||||
const validTools = ['bash', 'gemini', 'codex', 'qwen', 'claude'];
|
||||
if (validTools.includes(tool)) return tool as any;
|
||||
function mapIssueToolToLoopTool(tool: any): string | null {
|
||||
const validTools = getEnabledToolsList();
|
||||
if (validTools.includes(tool)) return tool;
|
||||
// Map aliases
|
||||
if (tool === 'ccw') return 'gemini';
|
||||
if (tool === 'ai') return 'gemini';
|
||||
@@ -1343,7 +1364,7 @@ function mapIssueOnError(onError: any): 'continue' | 'pause' | 'fail_fast' | und
|
||||
* Validate tool value
|
||||
*/
|
||||
function validateTool(tool: any): boolean {
|
||||
const validTools = ['bash', 'gemini', 'codex', 'qwen', 'claude'];
|
||||
const validTools = getEnabledToolsList();
|
||||
return validTools.includes(tool);
|
||||
}
|
||||
|
||||
|
||||
@@ -2202,6 +2202,9 @@ const i18n = {
|
||||
'loop.kanban.noBoardData': 'No tasks to display',
|
||||
'loop.listView': 'List View',
|
||||
'loop.addTask': 'Add Task',
|
||||
'loop.add': 'Add',
|
||||
'loop.save': 'Save',
|
||||
'loop.cancel': 'Cancel',
|
||||
|
||||
// Navigation & Grouping
|
||||
'loop.nav.groupBy': 'Group By',
|
||||
@@ -4796,6 +4799,9 @@ const i18n = {
|
||||
'loop.kanban.noBoardData': '没有要显示的任务',
|
||||
'loop.listView': '列表视图',
|
||||
'loop.addTask': '添加任务',
|
||||
'loop.add': '添加',
|
||||
'loop.save': '保存',
|
||||
'loop.cancel': '取消',
|
||||
|
||||
// Navigation & Grouping
|
||||
'loop.nav.groupBy': '分组',
|
||||
|
||||
@@ -22,8 +22,8 @@ export interface LoopTask {
|
||||
/** Task description (what to do) */
|
||||
description: string;
|
||||
|
||||
/** CLI tool to use */
|
||||
tool: 'bash' | 'gemini' | 'codex' | 'qwen' | 'claude';
|
||||
/** CLI tool to use (bash, builtin tools, cli-wrapper, api-endpoint) */
|
||||
tool: string;
|
||||
|
||||
/** Execution mode */
|
||||
mode: 'analysis' | 'write' | 'review';
|
||||
|
||||
Reference in New Issue
Block a user