stigmergy 1.3.77-beta.0 → 1.3.77-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/orchestration/core/CentralOrchestrator.js +32 -290
- package/dist/orchestration/managers/EnhancedTerminalManager.js +94 -38
- package/package.json +98 -98
- package/skills/complex-task-decomposition-with-system-engineering/DOCUMENTATION.md +316 -0
- package/skills/complex-task-decomposition-with-system-engineering/README.md +168 -0
- package/skills/complex-task-decomposition-with-system-engineering/SKILL.md +272 -0
- package/skills/complex-task-decomposition-with-system-engineering/agent_coordinator.sh +314 -0
- package/skills/complex-task-decomposition-with-system-engineering/context_manager.sh +241 -0
- package/skills/complex-task-decomposition-with-system-engineering/task_analyzer.sh +263 -0
- package/skills/resumesession/independent-resume.js +306 -8
- package/src/cli/commands/concurrent.js +142 -181
- package/src/cli/commands/stigmergy-resume.js +83 -1
- package/src/orchestration/managers/EnhancedTerminalManager.ts +14 -1
- package/dist/orchestration/config/index.js +0 -131
- package/dist/orchestration/core/CentralOrchestrator-Realtime.js +0 -286
- package/dist/orchestration/core/CentralOrchestrator-WithLock.js +0 -357
- package/dist/orchestration/events/EventBus.js +0 -190
- package/dist/orchestration/hooks/HookInstaller.js +0 -88
- package/dist/orchestration/hooks/HookSystem.js +0 -249
- package/dist/orchestration/integration/ResumeSessionIntegration.js +0 -150
- package/dist/orchestration/managers/GitWorktreeManager.js +0 -412
- package/dist/orchestration/managers/ResultAggregator.js +0 -159
- package/dist/orchestration/managers/StateLockManager.js +0 -250
- package/dist/orchestration/managers/TaskPlanningFiles.js +0 -364
- package/dist/orchestration/types/index.js +0 -2
|
@@ -1,293 +1,35 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
/**
|
|
3
|
-
* CentralOrchestrator -
|
|
4
|
-
* 负责任务规划、任务分解、CLI选择、策略确定和结果聚合
|
|
2
|
+
* Stub CentralOrchestrator - Minimal implementation for compatibility
|
|
5
3
|
*/
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
available: true,
|
|
36
|
-
capabilities: ['code', 'analysis', 'interactive']
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
name: 'claude',
|
|
40
|
-
command: 'claude',
|
|
41
|
-
params: ['-p', '', '--dangerously-skip-permissions', '--allowed-tools', 'Bash,Edit,Read,Write,RunCommand,ComputerTools'],
|
|
42
|
-
available: true,
|
|
43
|
-
capabilities: ['analysis', 'documentation', 'reasoning', 'complex']
|
|
44
|
-
},
|
|
45
|
-
{
|
|
46
|
-
name: 'gemini',
|
|
47
|
-
command: 'gemini',
|
|
48
|
-
params: ['-y'],
|
|
49
|
-
available: true,
|
|
50
|
-
capabilities: ['multilingual', 'creative', 'writing', 'design']
|
|
51
|
-
},
|
|
52
|
-
{
|
|
53
|
-
name: 'codebuddy',
|
|
54
|
-
command: 'codebuddy',
|
|
55
|
-
params: ['-p', '', '-y'],
|
|
56
|
-
available: true,
|
|
57
|
-
capabilities: ['completion', 'refactoring', 'optimization', 'quality']
|
|
58
|
-
},
|
|
59
|
-
{
|
|
60
|
-
name: 'codex',
|
|
61
|
-
command: 'codex',
|
|
62
|
-
params: ['-p', '', '-y'],
|
|
63
|
-
available: true,
|
|
64
|
-
capabilities: ['debugging', 'bug-fixing', 'error-handling']
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
name: 'copilot',
|
|
68
|
-
command: 'copilot',
|
|
69
|
-
params: ['-p', '', '--allow-all-tools'],
|
|
70
|
-
available: true,
|
|
71
|
-
capabilities: ['best-practices', 'suggestions', 'patterns', 'architecture']
|
|
72
|
-
},
|
|
73
|
-
{
|
|
74
|
-
name: 'qodercli',
|
|
75
|
-
command: 'qodercli',
|
|
76
|
-
params: ['-y'],
|
|
77
|
-
available: true,
|
|
78
|
-
capabilities: ['code', 'general']
|
|
79
|
-
}
|
|
80
|
-
];
|
|
81
|
-
clis.forEach(cli => {
|
|
82
|
-
this.cliRegistry.set(cli.name, cli);
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
/**
|
|
86
|
-
* 并发执行任务
|
|
87
|
-
*/
|
|
88
|
-
async executeConcurrent(task, options = {}) {
|
|
89
|
-
const strategy = {
|
|
90
|
-
mode: options.mode || 'parallel',
|
|
91
|
-
concurrencyLimit: options.concurrencyLimit || this.concurrency,
|
|
92
|
-
timeout: options.timeout || 0
|
|
93
|
-
};
|
|
94
|
-
this.emit('task-start', { task, strategy });
|
|
95
|
-
const startTime = Date.now();
|
|
96
|
-
try {
|
|
97
|
-
// 选择可用的 CLI
|
|
98
|
-
const availableCLIs = this._selectAvailableCLIs(strategy.concurrencyLimit || this.concurrency);
|
|
99
|
-
console.log(`\n🤖 Selected CLIs: ${availableCLIs.join(', ')}`);
|
|
100
|
-
// 并发执行
|
|
101
|
-
const promises = availableCLIs.map(cliName => this._executeWithCLI(cliName, task, strategy.timeout));
|
|
102
|
-
const results = await Promise.all(promises);
|
|
103
|
-
const endTime = Date.now();
|
|
104
|
-
// 统计结果
|
|
105
|
-
const successCount = results.filter(r => r.success).length;
|
|
106
|
-
const failedCount = results.filter(r => !r.success).length;
|
|
107
|
-
const concurrentResult = {
|
|
108
|
-
totalResults: results.length,
|
|
109
|
-
successCount,
|
|
110
|
-
failedCount,
|
|
111
|
-
totalTime: endTime - startTime,
|
|
112
|
-
results
|
|
113
|
-
};
|
|
114
|
-
this.emit('task-complete', { task, result: concurrentResult });
|
|
115
|
-
return concurrentResult;
|
|
116
|
-
}
|
|
117
|
-
catch (error) {
|
|
118
|
-
this.emit('task-error', { task, error });
|
|
119
|
-
throw error;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
/**
|
|
123
|
-
* 选择可用的 CLI
|
|
124
|
-
*/
|
|
125
|
-
_selectAvailableCLIs(count) {
|
|
126
|
-
const available = Array.from(this.cliRegistry.entries())
|
|
127
|
-
.filter(([_, config]) => config.available)
|
|
128
|
-
.map(([name, _]) => name);
|
|
129
|
-
return available.slice(0, count);
|
|
130
|
-
}
|
|
131
|
-
/**
|
|
132
|
-
* 使用指定的 CLI 执行任务
|
|
133
|
-
*/
|
|
134
|
-
async _executeWithCLI(cliName, task, timeout) {
|
|
135
|
-
const cliConfig = this.cliRegistry.get(cliName);
|
|
136
|
-
if (!cliConfig) {
|
|
137
|
-
throw new Error(`CLI ${cliName} not found in registry`);
|
|
138
|
-
}
|
|
139
|
-
console.log(`\n🚀 Executing with ${cliName}...`);
|
|
140
|
-
console.log(`📋 Task: ${task.substring(0, 100)}...`);
|
|
141
|
-
const startTime = Date.now();
|
|
142
|
-
try {
|
|
143
|
-
// 构建命令参数
|
|
144
|
-
let args;
|
|
145
|
-
if (cliName === 'qwen' || cliName === 'iflow' || cliName === 'qodercli' || cliName === 'gemini') {
|
|
146
|
-
args = [task, ...cliConfig.params];
|
|
147
|
-
}
|
|
148
|
-
else if (cliName === 'codebuddy' || cliName === 'codex') {
|
|
149
|
-
args = [...cliConfig.params.map(p => p === '' ? task : p)];
|
|
150
|
-
}
|
|
151
|
-
else if (cliName === 'copilot') {
|
|
152
|
-
args = ['-p', task, '--allow-all-tools'];
|
|
153
|
-
}
|
|
154
|
-
else if (cliName === 'claude') {
|
|
155
|
-
args = ['-p', task, '--dangerously-skip-permissions', '--allowed-tools', 'Bash,Edit,Read,Write,RunCommand,ComputerTools'];
|
|
156
|
-
}
|
|
157
|
-
else {
|
|
158
|
-
args = ['-p', task];
|
|
159
|
-
}
|
|
160
|
-
// 执行命令(传递 cliName 用于前缀)
|
|
161
|
-
const result = await this._spawnCommand(cliName, cliName, args, timeout);
|
|
162
|
-
const endTime = Date.now();
|
|
163
|
-
console.log(`✅ ${cliName} completed in ${endTime - startTime}ms`);
|
|
164
|
-
return {
|
|
165
|
-
cli: cliName,
|
|
166
|
-
success: true,
|
|
167
|
-
output: result,
|
|
168
|
-
executionTime: endTime - startTime
|
|
169
|
-
};
|
|
170
|
-
}
|
|
171
|
-
catch (error) {
|
|
172
|
-
const endTime = Date.now();
|
|
173
|
-
console.log(`❌ ${cliName} failed: ${error}`);
|
|
174
|
-
return {
|
|
175
|
-
cli: cliName,
|
|
176
|
-
success: false,
|
|
177
|
-
output: null,
|
|
178
|
-
executionTime: endTime - startTime,
|
|
179
|
-
error: error instanceof Error ? error.message : String(error)
|
|
180
|
-
};
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
/**
|
|
184
|
-
* 生成子进程执行命令(实时输出版本)
|
|
185
|
-
*/
|
|
186
|
-
_spawnCommand(cliName, command, args, timeout) {
|
|
187
|
-
return new Promise((resolve, reject) => {
|
|
188
|
-
let output = '';
|
|
189
|
-
let errorOutput = '';
|
|
190
|
-
// 使用 pipe 但添加前缀实时显示
|
|
191
|
-
const childProcess = (0, child_process_1.spawn)(command, args, {
|
|
192
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
193
|
-
shell: true,
|
|
194
|
-
cwd: this.workDir
|
|
195
|
-
});
|
|
196
|
-
// 实时显示输出(带 CLI 名称前缀)
|
|
197
|
-
childProcess.stdout?.on('data', (data) => {
|
|
198
|
-
const text = data.toString();
|
|
199
|
-
output += text;
|
|
200
|
-
// 实时显示,添加前缀
|
|
201
|
-
const lines = text.split('\n');
|
|
202
|
-
lines.forEach(line => {
|
|
203
|
-
if (line.trim()) {
|
|
204
|
-
console.log(`[${cliName}] ${line}`);
|
|
205
|
-
}
|
|
206
|
-
});
|
|
207
|
-
});
|
|
208
|
-
childProcess.stderr?.on('data', (data) => {
|
|
209
|
-
const text = data.toString();
|
|
210
|
-
errorOutput += text;
|
|
211
|
-
// 实时显示错误
|
|
212
|
-
const lines = text.split('\n');
|
|
213
|
-
lines.forEach(line => {
|
|
214
|
-
if (line.trim()) {
|
|
215
|
-
console.error(`[${cliName}] ERROR: ${line}`);
|
|
216
|
-
}
|
|
217
|
-
});
|
|
218
|
-
});
|
|
219
|
-
// 处理进程退出
|
|
220
|
-
childProcess.on('close', (code) => {
|
|
221
|
-
if (code === 0) {
|
|
222
|
-
resolve(output);
|
|
223
|
-
}
|
|
224
|
-
else {
|
|
225
|
-
reject(new Error(errorOutput || `Process exited with code ${code}`));
|
|
226
|
-
}
|
|
227
|
-
});
|
|
228
|
-
// 处理错误
|
|
229
|
-
childProcess.on('error', (error) => {
|
|
230
|
-
reject(error);
|
|
231
|
-
});
|
|
232
|
-
// 超时处理
|
|
233
|
-
if (timeout > 0) {
|
|
234
|
-
const timeoutId = setTimeout(() => {
|
|
235
|
-
childProcess.kill();
|
|
236
|
-
reject(new Error(`Command timed out after ${timeout}ms`));
|
|
237
|
-
}, timeout);
|
|
238
|
-
childProcess.on('close', () => {
|
|
239
|
-
clearTimeout(timeoutId);
|
|
240
|
-
});
|
|
241
|
-
}
|
|
242
|
-
});
|
|
243
|
-
}
|
|
244
|
-
/**
|
|
245
|
-
* 获取可用的 CLI 列表
|
|
246
|
-
*/
|
|
247
|
-
getAvailableCLIs() {
|
|
248
|
-
return Array.from(this.cliRegistry.entries())
|
|
249
|
-
.filter(([_, config]) => config.available)
|
|
250
|
-
.map(([name, _]) => name);
|
|
251
|
-
}
|
|
252
|
-
/**
|
|
253
|
-
* 检查 CLI 是否可用
|
|
254
|
-
*/
|
|
255
|
-
isCLIAvailable(cliName) {
|
|
256
|
-
const cli = this.cliRegistry.get(cliName);
|
|
257
|
-
return cli ? cli.available : false;
|
|
258
|
-
}
|
|
259
|
-
/**
|
|
260
|
-
* 设置 CLI 可用性
|
|
261
|
-
*/
|
|
262
|
-
setCLIAvailability(cliName, available) {
|
|
263
|
-
const cli = this.cliRegistry.get(cliName);
|
|
264
|
-
if (cli) {
|
|
265
|
-
cli.available = available;
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
/**
|
|
269
|
-
* 获取并发度
|
|
270
|
-
*/
|
|
271
|
-
getConcurrency() {
|
|
272
|
-
return this.concurrency;
|
|
273
|
-
}
|
|
274
|
-
/**
|
|
275
|
-
* 设置并发度
|
|
276
|
-
*/
|
|
277
|
-
setConcurrency(concurrency) {
|
|
278
|
-
this.concurrency = Math.max(1, concurrency);
|
|
279
|
-
}
|
|
280
|
-
/**
|
|
281
|
-
* 获取工作目录
|
|
282
|
-
*/
|
|
283
|
-
getWorkDir() {
|
|
284
|
-
return this.workDir;
|
|
285
|
-
}
|
|
286
|
-
/**
|
|
287
|
-
* 设置工作目录
|
|
288
|
-
*/
|
|
289
|
-
setWorkDir(workDir) {
|
|
290
|
-
this.workDir = workDir;
|
|
291
|
-
}
|
|
4
|
+
|
|
5
|
+
class CentralOrchestrator {
|
|
6
|
+
constructor(options = {}) {
|
|
7
|
+
this.concurrency = options.concurrency || 3;
|
|
8
|
+
this.workDir = options.workDir || process.cwd();
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* 选择可用的CLI工具
|
|
13
|
+
*/
|
|
14
|
+
_selectAvailableCLIs(count) {
|
|
15
|
+
const allCLIs = ['claude', 'qwen', 'gemini', 'iflow', 'qodercli', 'codebuddy'];
|
|
16
|
+
return allCLIs.slice(0, Math.min(count, allCLIs.length));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 执行并发任务
|
|
21
|
+
*/
|
|
22
|
+
async executeConcurrent(prompt, options = {}) {
|
|
23
|
+
// Stub implementation - returns empty result
|
|
24
|
+
return {
|
|
25
|
+
totalResults: 0,
|
|
26
|
+
successCount: 0,
|
|
27
|
+
failedCount: 0,
|
|
28
|
+
skippedCount: 0,
|
|
29
|
+
totalTime: 0,
|
|
30
|
+
results: []
|
|
31
|
+
};
|
|
32
|
+
}
|
|
292
33
|
}
|
|
293
|
-
|
|
34
|
+
|
|
35
|
+
module.exports = { CentralOrchestrator };
|
|
@@ -1,51 +1,71 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.EnhancedTerminalManager = void 0;
|
|
4
|
-
const child_process_1 = require("child_process");
|
|
5
|
-
const config_1 = require("../config");
|
|
1
|
+
const { spawn } = require('child_process');
|
|
2
|
+
|
|
6
3
|
class EnhancedTerminalManager {
|
|
7
4
|
constructor() {
|
|
8
5
|
this.terminals = new Map();
|
|
9
6
|
this.outputBuffers = new Map();
|
|
10
7
|
}
|
|
8
|
+
|
|
11
9
|
/**
|
|
12
10
|
* 启动多个终端
|
|
13
11
|
*/
|
|
14
12
|
async launchTerminalsForTask(task, strategy, worktrees) {
|
|
15
13
|
const results = [];
|
|
14
|
+
|
|
16
15
|
// 根据策略确定启动顺序
|
|
17
16
|
if (strategy.mode === 'parallel') {
|
|
18
17
|
// 并行启动所有终端
|
|
19
|
-
const launchPromises = task.subtasks.map((subtask) =>
|
|
18
|
+
const launchPromises = task.subtasks.map((subtask) =>
|
|
19
|
+
this.launchTerminalForSubtask(
|
|
20
|
+
subtask,
|
|
21
|
+
worktrees[subtask.id],
|
|
22
|
+
strategy
|
|
23
|
+
)
|
|
24
|
+
);
|
|
25
|
+
|
|
20
26
|
const launchResults = await Promise.all(launchPromises);
|
|
21
27
|
results.push(...launchResults);
|
|
22
|
-
}
|
|
23
|
-
else if (strategy.mode === 'sequential') {
|
|
28
|
+
} else if (strategy.mode === 'sequential') {
|
|
24
29
|
// 串行启动终端
|
|
25
30
|
for (const subtask of task.subtasks) {
|
|
26
|
-
const result = await this.launchTerminalForSubtask(
|
|
31
|
+
const result = await this.launchTerminalForSubtask(
|
|
32
|
+
subtask,
|
|
33
|
+
worktrees[subtask.id],
|
|
34
|
+
strategy
|
|
35
|
+
);
|
|
27
36
|
results.push(result);
|
|
37
|
+
|
|
28
38
|
// 等待终端完成
|
|
29
39
|
if (result.success && result.terminalId) {
|
|
30
40
|
await this.waitForTerminal(result.terminalId);
|
|
31
41
|
}
|
|
32
42
|
}
|
|
33
|
-
}
|
|
34
|
-
else if (strategy.mode === 'hybrid') {
|
|
43
|
+
} else if (strategy.mode === 'hybrid') {
|
|
35
44
|
// 混合模式:按照并行组启动
|
|
36
45
|
for (const group of strategy.parallelGroups || []) {
|
|
37
|
-
const launchPromises = group.tasks.map((subtask) =>
|
|
46
|
+
const launchPromises = group.tasks.map((subtask) =>
|
|
47
|
+
this.launchTerminalForSubtask(
|
|
48
|
+
subtask,
|
|
49
|
+
worktrees[subtask.id],
|
|
50
|
+
strategy
|
|
51
|
+
)
|
|
52
|
+
);
|
|
53
|
+
|
|
38
54
|
const launchResults = await Promise.all(launchPromises);
|
|
39
55
|
results.push(...launchResults);
|
|
56
|
+
|
|
40
57
|
// 等待组内所有终端完成
|
|
41
58
|
const terminalIds = launchResults
|
|
42
59
|
.filter(r => r.success && r.terminalId)
|
|
43
60
|
.map(r => r.terminalId);
|
|
61
|
+
|
|
44
62
|
await this.waitForAllTerminals(terminalIds);
|
|
45
63
|
}
|
|
46
64
|
}
|
|
65
|
+
|
|
47
66
|
return results;
|
|
48
67
|
}
|
|
68
|
+
|
|
49
69
|
/**
|
|
50
70
|
* 启动单个终端
|
|
51
71
|
*/
|
|
@@ -53,8 +73,9 @@ class EnhancedTerminalManager {
|
|
|
53
73
|
try {
|
|
54
74
|
// 1. 构建 CLI 命令
|
|
55
75
|
const command = this.buildCLICommand(subtask, worktree);
|
|
76
|
+
|
|
56
77
|
// 2. 启动终端进程
|
|
57
|
-
const childProcess =
|
|
78
|
+
const childProcess = spawn(command, {
|
|
58
79
|
shell: true,
|
|
59
80
|
cwd: worktree.worktreePath,
|
|
60
81
|
env: {
|
|
@@ -63,6 +84,7 @@ class EnhancedTerminalManager {
|
|
|
63
84
|
STIGMERGY_SUBTASK_ID: subtask.id
|
|
64
85
|
}
|
|
65
86
|
});
|
|
87
|
+
|
|
66
88
|
// 3. 创建终端对象
|
|
67
89
|
const terminalId = `term-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
68
90
|
const terminal = {
|
|
@@ -75,31 +97,54 @@ class EnhancedTerminalManager {
|
|
|
75
97
|
createdAt: new Date(),
|
|
76
98
|
output: ''
|
|
77
99
|
};
|
|
100
|
+
|
|
78
101
|
// 4. 存储终端信息
|
|
79
102
|
this.terminals.set(terminalId, { process: childProcess, terminal });
|
|
80
103
|
this.outputBuffers.set(terminalId, '');
|
|
104
|
+
|
|
81
105
|
// 5. 设置输出监听
|
|
106
|
+
// 🔥 新增:实时显示输出,让用户看到CLI的实时活动
|
|
107
|
+
const cliName = terminal.cliName || 'unknown';
|
|
108
|
+
|
|
82
109
|
childProcess.stdout?.on('data', (data) => {
|
|
83
110
|
const output = data.toString();
|
|
84
|
-
|
|
111
|
+
|
|
112
|
+
// 立即显示给用户(实时反馈)
|
|
113
|
+
process.stdout.write(`[${cliName}] ${output}`);
|
|
114
|
+
|
|
115
|
+
// 同时存储到缓冲区(用于最终收集)
|
|
116
|
+
this.outputBuffers.set(
|
|
117
|
+
terminalId,
|
|
118
|
+
(this.outputBuffers.get(terminalId) || '') + output
|
|
119
|
+
);
|
|
85
120
|
terminal.output += output;
|
|
86
121
|
});
|
|
122
|
+
|
|
87
123
|
childProcess.stderr?.on('data', (data) => {
|
|
88
124
|
const error = data.toString();
|
|
125
|
+
|
|
126
|
+
// 立即显示错误输出(用红色前缀)
|
|
127
|
+
process.stderr.write(`[${cliName}] ${error}`);
|
|
128
|
+
|
|
129
|
+
// 同时存储到缓冲区
|
|
89
130
|
terminal.error = (terminal.error || '') + error;
|
|
90
131
|
});
|
|
132
|
+
|
|
91
133
|
// 6. 设置进程退出监听
|
|
92
134
|
childProcess.on('close', (code) => {
|
|
93
135
|
terminal.status = code === 0 ? 'completed' : 'failed';
|
|
94
136
|
terminal.completedAt = new Date();
|
|
95
137
|
});
|
|
138
|
+
|
|
96
139
|
childProcess.on('error', (error) => {
|
|
97
140
|
terminal.status = 'crashed';
|
|
98
141
|
terminal.error = error.message;
|
|
99
142
|
terminal.completedAt = new Date();
|
|
100
143
|
});
|
|
144
|
+
|
|
101
145
|
// 7. 等待进程启动
|
|
102
146
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
147
|
+
|
|
103
148
|
// 8. 检查进程是否成功启动
|
|
104
149
|
if (childProcess.killed || childProcess.exitCode !== null) {
|
|
105
150
|
return {
|
|
@@ -107,47 +152,46 @@ class EnhancedTerminalManager {
|
|
|
107
152
|
errorMessage: 'Process failed to start'
|
|
108
153
|
};
|
|
109
154
|
}
|
|
155
|
+
|
|
110
156
|
terminal.status = 'running';
|
|
157
|
+
|
|
111
158
|
return {
|
|
112
159
|
success: true,
|
|
113
160
|
terminalId
|
|
114
161
|
};
|
|
115
|
-
|
|
116
|
-
catch (error) {
|
|
162
|
+
|
|
163
|
+
} catch (error) {
|
|
117
164
|
return {
|
|
118
165
|
success: false,
|
|
119
|
-
errorMessage: error
|
|
166
|
+
errorMessage: error.message || 'Unknown error'
|
|
120
167
|
};
|
|
121
168
|
}
|
|
122
169
|
}
|
|
170
|
+
|
|
123
171
|
/**
|
|
124
172
|
* 构建 CLI 命令
|
|
125
173
|
*/
|
|
126
174
|
buildCLICommand(subtask, worktree) {
|
|
127
175
|
const cliName = subtask.assignedCLI || 'claude';
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
throw new Error(`No CLI mappings found for ${cliName}`);
|
|
131
|
-
}
|
|
176
|
+
|
|
177
|
+
// Simplified command building - you may need to expand this
|
|
132
178
|
let command = cliName;
|
|
179
|
+
|
|
133
180
|
// 🔥 关键:添加自动模式参数(并发和路由模式必须使用自动模式)
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
if (
|
|
137
|
-
command +=
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
if (subtask.requiredSkills.length > 0) {
|
|
141
|
-
command += mappings.skills(subtask.requiredSkills);
|
|
142
|
-
}
|
|
143
|
-
// 添加 mcp 参数
|
|
144
|
-
if (subtask.mcpTools.length > 0) {
|
|
145
|
-
command += mappings.mcp(subtask.mcpTools);
|
|
181
|
+
if (cliName === 'claude') {
|
|
182
|
+
command += ' --yes';
|
|
183
|
+
} else if (cliName === 'qwen') {
|
|
184
|
+
command += ' --auto';
|
|
185
|
+
} else if (cliName === 'gemini') {
|
|
186
|
+
command += ' --auto';
|
|
146
187
|
}
|
|
188
|
+
|
|
147
189
|
// 添加 cwd 参数
|
|
148
|
-
command +=
|
|
190
|
+
command += ` --cwd "${worktree.worktreePath}"`;
|
|
191
|
+
|
|
149
192
|
return command;
|
|
150
193
|
}
|
|
194
|
+
|
|
151
195
|
/**
|
|
152
196
|
* 获取终端状态
|
|
153
197
|
*/
|
|
@@ -156,7 +200,9 @@ class EnhancedTerminalManager {
|
|
|
156
200
|
if (!terminalInfo) {
|
|
157
201
|
return null;
|
|
158
202
|
}
|
|
203
|
+
|
|
159
204
|
const { terminal } = terminalInfo;
|
|
205
|
+
|
|
160
206
|
return {
|
|
161
207
|
terminalId: terminal.id,
|
|
162
208
|
subtaskId: terminal.subtaskId,
|
|
@@ -167,6 +213,7 @@ class EnhancedTerminalManager {
|
|
|
167
213
|
completedAt: terminal.completedAt
|
|
168
214
|
};
|
|
169
215
|
}
|
|
216
|
+
|
|
170
217
|
/**
|
|
171
218
|
* 等待终端完成
|
|
172
219
|
*/
|
|
@@ -175,8 +222,10 @@ class EnhancedTerminalManager {
|
|
|
175
222
|
if (!terminalInfo) {
|
|
176
223
|
throw new Error('Terminal not found');
|
|
177
224
|
}
|
|
225
|
+
|
|
178
226
|
const { terminal, process: childProcess } = terminalInfo;
|
|
179
|
-
|
|
227
|
+
|
|
228
|
+
return new Promise((resolve) => {
|
|
180
229
|
const timer = setTimeout(() => {
|
|
181
230
|
childProcess.kill();
|
|
182
231
|
resolve({
|
|
@@ -188,6 +237,7 @@ class EnhancedTerminalManager {
|
|
|
188
237
|
duration: timeout
|
|
189
238
|
});
|
|
190
239
|
}, timeout);
|
|
240
|
+
|
|
191
241
|
childProcess.on('close', (code) => {
|
|
192
242
|
clearTimeout(timer);
|
|
193
243
|
resolve({
|
|
@@ -201,6 +251,7 @@ class EnhancedTerminalManager {
|
|
|
201
251
|
});
|
|
202
252
|
});
|
|
203
253
|
}
|
|
254
|
+
|
|
204
255
|
/**
|
|
205
256
|
* 等待所有终端完成
|
|
206
257
|
*/
|
|
@@ -208,6 +259,7 @@ class EnhancedTerminalManager {
|
|
|
208
259
|
const promises = terminalIds.map(id => this.waitForTerminal(id, timeout));
|
|
209
260
|
return Promise.all(promises);
|
|
210
261
|
}
|
|
262
|
+
|
|
211
263
|
/**
|
|
212
264
|
* 终止终端
|
|
213
265
|
*/
|
|
@@ -216,11 +268,14 @@ class EnhancedTerminalManager {
|
|
|
216
268
|
if (!terminalInfo) {
|
|
217
269
|
throw new Error('Terminal not found');
|
|
218
270
|
}
|
|
271
|
+
|
|
219
272
|
const { process: childProcess, terminal } = terminalInfo;
|
|
220
273
|
childProcess.kill();
|
|
274
|
+
|
|
221
275
|
terminal.status = 'failed';
|
|
222
276
|
terminal.completedAt = new Date();
|
|
223
277
|
}
|
|
278
|
+
|
|
224
279
|
/**
|
|
225
280
|
* 清理所有终端
|
|
226
281
|
*/
|
|
@@ -230,13 +285,14 @@ class EnhancedTerminalManager {
|
|
|
230
285
|
if (!childProcess.killed) {
|
|
231
286
|
childProcess.kill();
|
|
232
287
|
}
|
|
233
|
-
}
|
|
234
|
-
catch (error) {
|
|
288
|
+
} catch (error) {
|
|
235
289
|
// 忽略清理错误
|
|
236
290
|
}
|
|
237
291
|
}
|
|
292
|
+
|
|
238
293
|
this.terminals.clear();
|
|
239
294
|
this.outputBuffers.clear();
|
|
240
295
|
}
|
|
241
296
|
}
|
|
242
|
-
|
|
297
|
+
|
|
298
|
+
module.exports = { EnhancedTerminalManager };
|