wave-agent-sdk 0.4.0 → 0.5.1
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/agent.d.ts +28 -5
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +54 -37
- package/dist/constants/tools.d.ts +2 -2
- package/dist/constants/tools.js +2 -2
- package/dist/managers/MemoryRuleManager.js +1 -1
- package/dist/managers/aiManager.d.ts +3 -3
- package/dist/managers/aiManager.d.ts.map +1 -1
- package/dist/managers/aiManager.js +3 -4
- package/dist/managers/backgroundBashManager.d.ts.map +1 -1
- package/dist/managers/backgroundBashManager.js +1 -0
- package/dist/managers/backgroundTaskManager.d.ts +35 -0
- package/dist/managers/backgroundTaskManager.d.ts.map +1 -0
- package/dist/managers/backgroundTaskManager.js +249 -0
- package/dist/managers/foregroundTaskManager.d.ts +9 -0
- package/dist/managers/foregroundTaskManager.d.ts.map +1 -0
- package/dist/managers/foregroundTaskManager.js +20 -0
- package/dist/managers/liveConfigManager.d.ts +1 -1
- package/dist/managers/lspManager.d.ts.map +1 -1
- package/dist/managers/lspManager.js +3 -1
- package/dist/managers/messageManager.d.ts +12 -2
- package/dist/managers/messageManager.d.ts.map +1 -1
- package/dist/managers/messageManager.js +36 -2
- package/dist/managers/permissionManager.d.ts.map +1 -1
- package/dist/managers/permissionManager.js +1 -7
- package/dist/managers/pluginManager.d.ts.map +1 -1
- package/dist/managers/pluginManager.js +3 -2
- package/dist/managers/slashCommandManager.d.ts +3 -0
- package/dist/managers/slashCommandManager.d.ts.map +1 -1
- package/dist/managers/slashCommandManager.js +1 -0
- package/dist/managers/subagentManager.d.ts +11 -2
- package/dist/managers/subagentManager.d.ts.map +1 -1
- package/dist/managers/subagentManager.js +137 -39
- package/dist/managers/toolManager.d.ts +7 -1
- package/dist/managers/toolManager.d.ts.map +1 -1
- package/dist/managers/toolManager.js +9 -3
- package/dist/services/GitService.d.ts.map +1 -1
- package/dist/services/GitService.js +6 -2
- package/dist/services/MarketplaceService.d.ts +2 -2
- package/dist/services/MarketplaceService.d.ts.map +1 -1
- package/dist/services/MarketplaceService.js +18 -11
- package/dist/services/MemoryRuleService.d.ts +1 -1
- package/dist/services/MemoryRuleService.d.ts.map +1 -1
- package/dist/services/MemoryRuleService.js +13 -2
- package/dist/services/memory.js +1 -1
- package/dist/tools/bashTool.d.ts +0 -8
- package/dist/tools/bashTool.d.ts.map +1 -1
- package/dist/tools/bashTool.js +44 -172
- package/dist/tools/editTool.d.ts.map +1 -1
- package/dist/tools/editTool.js +6 -5
- package/dist/tools/multiEditTool.d.ts.map +1 -1
- package/dist/tools/multiEditTool.js +7 -6
- package/dist/tools/taskOutputTool.d.ts +3 -0
- package/dist/tools/taskOutputTool.d.ts.map +1 -0
- package/dist/tools/taskOutputTool.js +149 -0
- package/dist/tools/taskStopTool.d.ts +3 -0
- package/dist/tools/taskStopTool.d.ts.map +1 -0
- package/dist/tools/taskStopTool.js +65 -0
- package/dist/tools/taskTool.d.ts.map +1 -1
- package/dist/tools/taskTool.js +105 -63
- package/dist/tools/types.d.ts +3 -0
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/types/marketplace.d.ts +1 -0
- package/dist/types/marketplace.d.ts.map +1 -1
- package/dist/types/messaging.d.ts +1 -0
- package/dist/types/messaging.d.ts.map +1 -1
- package/dist/types/processes.d.ts +24 -4
- package/dist/types/processes.d.ts.map +1 -1
- package/dist/utils/editUtils.d.ts +2 -11
- package/dist/utils/editUtils.d.ts.map +1 -1
- package/dist/utils/editUtils.js +52 -79
- package/dist/utils/messageOperations.d.ts +3 -1
- package/dist/utils/messageOperations.d.ts.map +1 -1
- package/dist/utils/messageOperations.js +5 -1
- package/package.json +5 -5
- package/src/agent.ts +73 -45
- package/src/constants/tools.ts +2 -2
- package/src/managers/MemoryRuleManager.ts +1 -1
- package/src/managers/aiManager.ts +6 -9
- package/src/managers/backgroundBashManager.ts +1 -0
- package/src/managers/backgroundTaskManager.ts +306 -0
- package/src/managers/foregroundTaskManager.ts +26 -0
- package/src/managers/lspManager.ts +3 -1
- package/src/managers/messageManager.ts +48 -2
- package/src/managers/permissionManager.ts +1 -7
- package/src/managers/pluginManager.ts +4 -3
- package/src/managers/slashCommandManager.ts +4 -0
- package/src/managers/subagentManager.ts +167 -35
- package/src/managers/toolManager.ts +16 -4
- package/src/services/GitService.ts +6 -2
- package/src/services/MarketplaceService.ts +30 -12
- package/src/services/MemoryRuleService.ts +18 -6
- package/src/services/memory.ts +1 -1
- package/src/tools/bashTool.ts +59 -196
- package/src/tools/editTool.ts +6 -17
- package/src/tools/multiEditTool.ts +7 -18
- package/src/tools/taskOutputTool.ts +174 -0
- package/src/tools/taskStopTool.ts +72 -0
- package/src/tools/taskTool.ts +130 -74
- package/src/tools/types.ts +3 -0
- package/src/types/marketplace.ts +1 -0
- package/src/types/messaging.ts +1 -0
- package/src/types/processes.ts +33 -4
- package/src/utils/editUtils.ts +65 -103
- package/src/utils/messageOperations.ts +7 -0
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
SESSION_DIR,
|
|
27
27
|
} from "../services/session.js";
|
|
28
28
|
import { ChatCompletionMessageFunctionToolCall } from "openai/resources.js";
|
|
29
|
+
import type { MemoryRuleManager } from "./MemoryRuleManager.js";
|
|
29
30
|
import { pathEncoder } from "../utils/pathEncoder.js";
|
|
30
31
|
|
|
31
32
|
export interface MessageManagerCallbacks {
|
|
@@ -57,6 +58,7 @@ export interface MessageManagerCallbacks {
|
|
|
57
58
|
onUpdateCommandOutputMessage?: (command: string, output: string) => void;
|
|
58
59
|
onCompleteCommandMessage?: (command: string, exitCode: number) => void;
|
|
59
60
|
onSlashCommandsChange?: (commands: SlashCommand[]) => void;
|
|
61
|
+
onInfoBlockAdded?: (content: string) => void;
|
|
60
62
|
// Rewind callbacks
|
|
61
63
|
onShowRewind?: () => void;
|
|
62
64
|
// Subagent callbacks
|
|
@@ -80,6 +82,7 @@ export interface MessageManagerOptions {
|
|
|
80
82
|
logger?: Logger;
|
|
81
83
|
sessionType?: "main" | "subagent";
|
|
82
84
|
subagentType?: string;
|
|
85
|
+
memoryRuleManager?: MemoryRuleManager;
|
|
83
86
|
}
|
|
84
87
|
|
|
85
88
|
export class MessageManager {
|
|
@@ -95,6 +98,7 @@ export class MessageManager {
|
|
|
95
98
|
private transcriptPath: string; // Cached transcript path
|
|
96
99
|
private savedMessageCount: number; // Track how many messages have been saved to prevent duplication
|
|
97
100
|
private filesInContext: Set<string> = new Set(); // Track files mentioned in the conversation
|
|
101
|
+
private memoryRuleManager?: MemoryRuleManager;
|
|
98
102
|
private sessionType: "main" | "subagent";
|
|
99
103
|
private subagentType?: string;
|
|
100
104
|
|
|
@@ -110,6 +114,7 @@ export class MessageManager {
|
|
|
110
114
|
this.savedMessageCount = 0; // Initialize saved message count tracker
|
|
111
115
|
this.sessionType = options.sessionType || "main";
|
|
112
116
|
this.subagentType = options.subagentType;
|
|
117
|
+
this.memoryRuleManager = options.memoryRuleManager;
|
|
113
118
|
|
|
114
119
|
// Compute and cache the transcript path
|
|
115
120
|
this.transcriptPath = this.computeTranscriptPath();
|
|
@@ -151,6 +156,30 @@ export class MessageManager {
|
|
|
151
156
|
return this.transcriptPath;
|
|
152
157
|
}
|
|
153
158
|
|
|
159
|
+
/**
|
|
160
|
+
* Get combined memory content (project memory + user memory + modular rules)
|
|
161
|
+
*/
|
|
162
|
+
public async getCombinedMemory(): Promise<string> {
|
|
163
|
+
const memory = await import("../services/memory.js");
|
|
164
|
+
let combined = await memory.getCombinedMemoryContent(this.workdir);
|
|
165
|
+
|
|
166
|
+
if (this.memoryRuleManager) {
|
|
167
|
+
const filesInContext = this.getFilesInContext();
|
|
168
|
+
const activeRules = this.memoryRuleManager.getActiveRules(filesInContext);
|
|
169
|
+
if (activeRules.length > 0) {
|
|
170
|
+
this.logger?.debug(
|
|
171
|
+
`Active modular rules (${activeRules.length}): ${activeRules.map((r) => r.id).join(", ")}`,
|
|
172
|
+
);
|
|
173
|
+
if (combined) {
|
|
174
|
+
combined += "\n\n";
|
|
175
|
+
}
|
|
176
|
+
combined += activeRules.map((r) => r.content).join("\n\n");
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return combined;
|
|
181
|
+
}
|
|
182
|
+
|
|
154
183
|
/**
|
|
155
184
|
* Compute the transcript path using cached encoded workdir
|
|
156
185
|
* Called during construction and when sessionId changes
|
|
@@ -400,6 +429,18 @@ export class MessageManager {
|
|
|
400
429
|
this.callbacks.onErrorBlockAdded?.(error);
|
|
401
430
|
}
|
|
402
431
|
|
|
432
|
+
public addInfoBlock(content: string): void {
|
|
433
|
+
const lastMessage = this.messages[this.messages.length - 1];
|
|
434
|
+
if (lastMessage && lastMessage.role === "assistant") {
|
|
435
|
+
lastMessage.blocks.push({
|
|
436
|
+
type: "info",
|
|
437
|
+
content,
|
|
438
|
+
} as unknown as import("../types/index.js").MessageBlock);
|
|
439
|
+
this.setMessages([...this.messages]);
|
|
440
|
+
this.callbacks.onInfoBlockAdded?.(content);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
|
|
403
444
|
/**
|
|
404
445
|
* Compress messages and update session, delete compressed messages, only keep compressed messages and subsequent messages
|
|
405
446
|
*/
|
|
@@ -494,12 +535,13 @@ export class MessageManager {
|
|
|
494
535
|
subagentName: string,
|
|
495
536
|
sessionId: string,
|
|
496
537
|
configuration: SubagentConfiguration,
|
|
497
|
-
status: "active" | "completed" | "error" = "active",
|
|
538
|
+
status: "active" | "completed" | "error" | "aborted" = "active",
|
|
498
539
|
parameters: {
|
|
499
540
|
description: string;
|
|
500
541
|
prompt: string;
|
|
501
542
|
subagent_type: string;
|
|
502
543
|
},
|
|
544
|
+
runInBackground?: boolean,
|
|
503
545
|
): void {
|
|
504
546
|
const params: AddSubagentBlockParams = {
|
|
505
547
|
messages: this.messages,
|
|
@@ -508,6 +550,7 @@ export class MessageManager {
|
|
|
508
550
|
sessionId,
|
|
509
551
|
status,
|
|
510
552
|
configuration,
|
|
553
|
+
runInBackground,
|
|
511
554
|
};
|
|
512
555
|
const updatedMessages = addSubagentBlockToMessage(params);
|
|
513
556
|
this.setMessages(updatedMessages);
|
|
@@ -519,6 +562,7 @@ export class MessageManager {
|
|
|
519
562
|
updates: Partial<{
|
|
520
563
|
status: "active" | "completed" | "error" | "aborted";
|
|
521
564
|
sessionId: string;
|
|
565
|
+
runInBackground: boolean;
|
|
522
566
|
}>,
|
|
523
567
|
): void {
|
|
524
568
|
const updatedMessages = updateSubagentBlockInMessage(
|
|
@@ -532,7 +576,9 @@ export class MessageManager {
|
|
|
532
576
|
subagentId,
|
|
533
577
|
status: updates.status || "active",
|
|
534
578
|
};
|
|
535
|
-
|
|
579
|
+
if (updates.status) {
|
|
580
|
+
this.callbacks.onSubAgentBlockUpdated?.(params.subagentId, params.status);
|
|
581
|
+
}
|
|
536
582
|
}
|
|
537
583
|
|
|
538
584
|
/**
|
|
@@ -237,13 +237,7 @@ export class PermissionManager {
|
|
|
237
237
|
* Get the current effective permission mode for tool execution context
|
|
238
238
|
*/
|
|
239
239
|
getCurrentEffectiveMode(cliPermissionMode?: PermissionMode): PermissionMode {
|
|
240
|
-
|
|
241
|
-
this.logger?.debug("getCurrentEffectiveMode", {
|
|
242
|
-
cliPermissionMode,
|
|
243
|
-
configuredDefaultMode: this.configuredDefaultMode,
|
|
244
|
-
resolvedMode: mode,
|
|
245
|
-
});
|
|
246
|
-
return mode;
|
|
240
|
+
return this.resolveEffectivePermissionMode(cliPermissionMode);
|
|
247
241
|
}
|
|
248
242
|
|
|
249
243
|
/**
|
|
@@ -149,9 +149,7 @@ export class PluginManager {
|
|
|
149
149
|
* @param configs Array of plugin configurations
|
|
150
150
|
*/
|
|
151
151
|
async loadPlugins(configs: PluginConfig[]): Promise<void> {
|
|
152
|
-
// Load
|
|
153
|
-
await this.loadInstalledPlugins();
|
|
154
|
-
|
|
152
|
+
// Load plugins from configuration (e.g. --plugin-dir) first to give them higher priority
|
|
155
153
|
for (const config of configs) {
|
|
156
154
|
if (config.type !== "local") {
|
|
157
155
|
this.logger?.warn(`Unsupported plugin type: ${config.type}`);
|
|
@@ -164,6 +162,9 @@ export class PluginManager {
|
|
|
164
162
|
|
|
165
163
|
await this.loadSinglePlugin(absolutePath);
|
|
166
164
|
}
|
|
165
|
+
|
|
166
|
+
// Load installed plugins from marketplace
|
|
167
|
+
await this.loadInstalledPlugins();
|
|
167
168
|
}
|
|
168
169
|
|
|
169
170
|
/**
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { MessageManager } from "./messageManager.js";
|
|
2
2
|
import type { AIManager } from "./aiManager.js";
|
|
3
|
+
import type { BackgroundTaskManager } from "./backgroundTaskManager.js";
|
|
3
4
|
import type {
|
|
4
5
|
SlashCommand,
|
|
5
6
|
CustomSlashCommand,
|
|
@@ -26,6 +27,7 @@ const execAsync = promisify(exec);
|
|
|
26
27
|
export interface SlashCommandManagerOptions {
|
|
27
28
|
messageManager: MessageManager;
|
|
28
29
|
aiManager: AIManager;
|
|
30
|
+
backgroundTaskManager: BackgroundTaskManager;
|
|
29
31
|
workdir: string;
|
|
30
32
|
logger?: Logger;
|
|
31
33
|
}
|
|
@@ -35,12 +37,14 @@ export class SlashCommandManager {
|
|
|
35
37
|
private customCommands = new Map<string, CustomSlashCommand>();
|
|
36
38
|
private messageManager: MessageManager;
|
|
37
39
|
private aiManager: AIManager;
|
|
40
|
+
private backgroundTaskManager: BackgroundTaskManager;
|
|
38
41
|
private workdir: string;
|
|
39
42
|
private logger?: Logger;
|
|
40
43
|
|
|
41
44
|
constructor(options: SlashCommandManagerOptions) {
|
|
42
45
|
this.messageManager = options.messageManager;
|
|
43
46
|
this.aiManager = options.aiManager;
|
|
47
|
+
this.backgroundTaskManager = options.backgroundTaskManager;
|
|
44
48
|
this.workdir = options.workdir;
|
|
45
49
|
this.logger = options.logger;
|
|
46
50
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { randomUUID } from "crypto";
|
|
2
|
+
import type { MemoryRuleManager } from "./MemoryRuleManager.js";
|
|
2
3
|
import type { SubagentConfiguration } from "../utils/subagentParser.js";
|
|
3
4
|
import type {
|
|
4
5
|
Message,
|
|
@@ -20,6 +21,7 @@ import {
|
|
|
20
21
|
addConsolidatedAbortListener,
|
|
21
22
|
createAbortPromise,
|
|
22
23
|
} from "../utils/abortUtils.js";
|
|
24
|
+
import { BackgroundTaskManager } from "./backgroundTaskManager.js";
|
|
23
25
|
|
|
24
26
|
export interface SubagentManagerCallbacks {
|
|
25
27
|
// Granular subagent message callbacks (015-subagent-message-callbacks)
|
|
@@ -60,6 +62,7 @@ export interface SubagentInstance {
|
|
|
60
62
|
status: "initializing" | "active" | "completed" | "error" | "aborted";
|
|
61
63
|
messages: Message[];
|
|
62
64
|
subagentType: string; // Store the subagent type for hook context
|
|
65
|
+
backgroundTaskId?: string; // ID of the background task if transitioned
|
|
63
66
|
}
|
|
64
67
|
|
|
65
68
|
export interface SubagentManagerOptions {
|
|
@@ -74,6 +77,8 @@ export interface SubagentManagerOptions {
|
|
|
74
77
|
getLanguage: () => string | undefined;
|
|
75
78
|
hookManager?: HookManager;
|
|
76
79
|
onUsageAdded?: (usage: Usage) => void;
|
|
80
|
+
backgroundTaskManager?: BackgroundTaskManager;
|
|
81
|
+
memoryRuleManager?: MemoryRuleManager;
|
|
77
82
|
}
|
|
78
83
|
|
|
79
84
|
export class SubagentManager {
|
|
@@ -91,6 +96,8 @@ export class SubagentManager {
|
|
|
91
96
|
private getLanguage: () => string | undefined;
|
|
92
97
|
private hookManager?: HookManager;
|
|
93
98
|
private onUsageAdded?: (usage: Usage) => void;
|
|
99
|
+
private backgroundTaskManager?: BackgroundTaskManager;
|
|
100
|
+
private memoryRuleManager?: MemoryRuleManager;
|
|
94
101
|
|
|
95
102
|
constructor(options: SubagentManagerOptions) {
|
|
96
103
|
this.workdir = options.workdir;
|
|
@@ -104,6 +111,8 @@ export class SubagentManager {
|
|
|
104
111
|
this.getLanguage = options.getLanguage;
|
|
105
112
|
this.hookManager = options.hookManager;
|
|
106
113
|
this.onUsageAdded = options.onUsageAdded;
|
|
114
|
+
this.backgroundTaskManager = options.backgroundTaskManager;
|
|
115
|
+
this.memoryRuleManager = options.memoryRuleManager;
|
|
107
116
|
}
|
|
108
117
|
|
|
109
118
|
/**
|
|
@@ -158,6 +167,7 @@ export class SubagentManager {
|
|
|
158
167
|
prompt: string;
|
|
159
168
|
subagent_type: string;
|
|
160
169
|
},
|
|
170
|
+
runInBackground?: boolean,
|
|
161
171
|
): Promise<SubagentInstance> {
|
|
162
172
|
if (!this.parentToolManager) {
|
|
163
173
|
throw new Error(
|
|
@@ -176,6 +186,7 @@ export class SubagentManager {
|
|
|
176
186
|
logger: this.logger,
|
|
177
187
|
sessionType: "subagent",
|
|
178
188
|
subagentType: parameters.subagent_type,
|
|
189
|
+
memoryRuleManager: this.memoryRuleManager,
|
|
179
190
|
});
|
|
180
191
|
|
|
181
192
|
// Use the parent tool manager directly - tool restrictions will be handled by allowedTools parameter
|
|
@@ -241,6 +252,7 @@ export class SubagentManager {
|
|
|
241
252
|
configuration,
|
|
242
253
|
"active",
|
|
243
254
|
parameters,
|
|
255
|
+
runInBackground,
|
|
244
256
|
);
|
|
245
257
|
|
|
246
258
|
return instance;
|
|
@@ -256,6 +268,7 @@ export class SubagentManager {
|
|
|
256
268
|
instance: SubagentInstance,
|
|
257
269
|
prompt: string,
|
|
258
270
|
abortSignal?: AbortSignal,
|
|
271
|
+
runInBackground?: boolean,
|
|
259
272
|
): Promise<string> {
|
|
260
273
|
try {
|
|
261
274
|
// Check if already aborted before starting
|
|
@@ -269,24 +282,119 @@ export class SubagentManager {
|
|
|
269
282
|
status: "active",
|
|
270
283
|
});
|
|
271
284
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
285
|
+
if (runInBackground && this.backgroundTaskManager) {
|
|
286
|
+
const taskId = this.backgroundTaskManager.generateId();
|
|
287
|
+
const startTime = Date.now();
|
|
288
|
+
|
|
289
|
+
this.backgroundTaskManager.addTask({
|
|
290
|
+
id: taskId,
|
|
291
|
+
type: "subagent",
|
|
292
|
+
status: "running",
|
|
293
|
+
startTime,
|
|
294
|
+
description: instance.configuration.description,
|
|
295
|
+
stdout: "",
|
|
296
|
+
stderr: "",
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
instance.backgroundTaskId = taskId;
|
|
300
|
+
|
|
301
|
+
// Execute in background
|
|
302
|
+
(async () => {
|
|
303
|
+
try {
|
|
304
|
+
const result = await this.internalExecute(
|
|
305
|
+
instance,
|
|
306
|
+
prompt,
|
|
307
|
+
abortSignal,
|
|
308
|
+
);
|
|
309
|
+
const task = this.backgroundTaskManager?.getTask(taskId);
|
|
310
|
+
if (task) {
|
|
311
|
+
task.status = "completed";
|
|
312
|
+
task.stdout = result;
|
|
313
|
+
task.endTime = Date.now();
|
|
314
|
+
task.runtime = task.endTime - startTime;
|
|
315
|
+
}
|
|
316
|
+
} catch (error) {
|
|
317
|
+
const task = this.backgroundTaskManager?.getTask(taskId);
|
|
318
|
+
if (task) {
|
|
319
|
+
task.status = "failed";
|
|
320
|
+
task.stderr =
|
|
321
|
+
error instanceof Error ? error.message : String(error);
|
|
322
|
+
task.endTime = Date.now();
|
|
323
|
+
task.runtime = task.endTime - startTime;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
})();
|
|
327
|
+
|
|
328
|
+
return taskId;
|
|
288
329
|
}
|
|
289
330
|
|
|
331
|
+
return await this.internalExecute(instance, prompt, abortSignal);
|
|
332
|
+
} catch (error) {
|
|
333
|
+
this.updateInstanceStatus(instance.subagentId, "error");
|
|
334
|
+
this.parentMessageManager.updateSubagentBlock(instance.subagentId, {
|
|
335
|
+
status: "error",
|
|
336
|
+
});
|
|
337
|
+
throw error;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
async backgroundInstance(subagentId: string): Promise<string> {
|
|
342
|
+
const instance = this.instances.get(subagentId);
|
|
343
|
+
if (!instance) {
|
|
344
|
+
throw new Error(`Subagent instance ${subagentId} not found`);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
if (!this.backgroundTaskManager) {
|
|
348
|
+
throw new Error("BackgroundTaskManager not available");
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
const taskId = this.backgroundTaskManager.generateId();
|
|
352
|
+
const startTime = Date.now();
|
|
353
|
+
|
|
354
|
+
this.backgroundTaskManager.addTask({
|
|
355
|
+
id: taskId,
|
|
356
|
+
type: "subagent",
|
|
357
|
+
status: "running",
|
|
358
|
+
startTime,
|
|
359
|
+
description: instance.configuration.description,
|
|
360
|
+
stdout: "",
|
|
361
|
+
stderr: "",
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
instance.backgroundTaskId = taskId;
|
|
365
|
+
|
|
366
|
+
// Update parent message manager to reflect background status
|
|
367
|
+
this.parentMessageManager.updateSubagentBlock(subagentId, {
|
|
368
|
+
runInBackground: true,
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
return taskId;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
private async internalExecute(
|
|
375
|
+
instance: SubagentInstance,
|
|
376
|
+
prompt: string,
|
|
377
|
+
abortSignal?: AbortSignal,
|
|
378
|
+
): Promise<string> {
|
|
379
|
+
// Set up consolidated abort handler to prevent listener accumulation
|
|
380
|
+
let abortCleanup: (() => void) | undefined;
|
|
381
|
+
if (abortSignal) {
|
|
382
|
+
abortCleanup = addConsolidatedAbortListener(abortSignal, [
|
|
383
|
+
() => {
|
|
384
|
+
// Update status to aborted
|
|
385
|
+
this.updateInstanceStatus(instance.subagentId, "aborted");
|
|
386
|
+
this.parentMessageManager.updateSubagentBlock(instance.subagentId, {
|
|
387
|
+
status: "aborted",
|
|
388
|
+
});
|
|
389
|
+
},
|
|
390
|
+
() => {
|
|
391
|
+
// Abort the AI execution
|
|
392
|
+
instance.aiManager.abortAIMessage();
|
|
393
|
+
},
|
|
394
|
+
]);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
try {
|
|
290
398
|
// Add the user's prompt as a message
|
|
291
399
|
instance.messageManager.addUserMessage({ content: prompt });
|
|
292
400
|
|
|
@@ -326,21 +434,14 @@ export class SubagentManager {
|
|
|
326
434
|
model: resolvedModel,
|
|
327
435
|
});
|
|
328
436
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
await executeAI;
|
|
338
|
-
}
|
|
339
|
-
} finally {
|
|
340
|
-
// Clean up abort listeners to prevent memory leaks
|
|
341
|
-
if (abortCleanup) {
|
|
342
|
-
abortCleanup();
|
|
343
|
-
}
|
|
437
|
+
// If we have an abort signal, race against it using utilities to prevent listener accumulation
|
|
438
|
+
if (abortSignal) {
|
|
439
|
+
await Promise.race([
|
|
440
|
+
executeAI,
|
|
441
|
+
createAbortPromise(abortSignal, "Task was aborted"),
|
|
442
|
+
]);
|
|
443
|
+
} else {
|
|
444
|
+
await executeAI;
|
|
344
445
|
}
|
|
345
446
|
|
|
346
447
|
// Get the latest messages to extract the response
|
|
@@ -365,13 +466,43 @@ export class SubagentManager {
|
|
|
365
466
|
status: "completed",
|
|
366
467
|
});
|
|
367
468
|
|
|
469
|
+
// If this was transitioned to background, update the background task
|
|
470
|
+
if (instance.backgroundTaskId && this.backgroundTaskManager) {
|
|
471
|
+
const task = this.backgroundTaskManager.getTask(
|
|
472
|
+
instance.backgroundTaskId,
|
|
473
|
+
);
|
|
474
|
+
if (task) {
|
|
475
|
+
task.status = "completed";
|
|
476
|
+
task.stdout = response || "Task completed with no text response";
|
|
477
|
+
task.endTime = Date.now();
|
|
478
|
+
if (task.startTime) {
|
|
479
|
+
task.runtime = task.endTime - task.startTime;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
368
484
|
return response || "Task completed with no text response";
|
|
369
485
|
} catch (error) {
|
|
370
|
-
this
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
486
|
+
// If this was transitioned to background, update the background task with error
|
|
487
|
+
if (instance.backgroundTaskId && this.backgroundTaskManager) {
|
|
488
|
+
const task = this.backgroundTaskManager.getTask(
|
|
489
|
+
instance.backgroundTaskId,
|
|
490
|
+
);
|
|
491
|
+
if (task) {
|
|
492
|
+
task.status = "failed";
|
|
493
|
+
task.stderr = error instanceof Error ? error.message : String(error);
|
|
494
|
+
task.endTime = Date.now();
|
|
495
|
+
if (task.startTime) {
|
|
496
|
+
task.runtime = task.endTime - task.startTime;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
}
|
|
374
500
|
throw error;
|
|
501
|
+
} finally {
|
|
502
|
+
// Clean up abort listeners to prevent memory leaks
|
|
503
|
+
if (abortCleanup) {
|
|
504
|
+
abortCleanup();
|
|
505
|
+
}
|
|
375
506
|
}
|
|
376
507
|
}
|
|
377
508
|
|
|
@@ -462,6 +593,7 @@ export class SubagentManager {
|
|
|
462
593
|
logger: this.logger,
|
|
463
594
|
sessionType: "subagent",
|
|
464
595
|
subagentType: configuration.name, // Use configuration name for restored sessions
|
|
596
|
+
memoryRuleManager: this.memoryRuleManager,
|
|
465
597
|
});
|
|
466
598
|
|
|
467
599
|
// Use the parent tool manager
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { ToolContext, ToolPlugin, ToolResult } from "../tools/types.js";
|
|
2
|
-
import { bashTool
|
|
2
|
+
import { bashTool } from "../tools/bashTool.js";
|
|
3
|
+
import { taskOutputTool } from "../tools/taskOutputTool.js";
|
|
4
|
+
import { taskStopTool } from "../tools/taskStopTool.js";
|
|
3
5
|
import { deleteFileTool } from "../tools/deleteFileTool.js";
|
|
4
6
|
import { editTool } from "../tools/editTool.js";
|
|
5
7
|
import { multiEditTool } from "../tools/multiEditTool.js";
|
|
@@ -33,10 +35,14 @@ export interface ToolManagerOptions {
|
|
|
33
35
|
mcpManager: McpManager;
|
|
34
36
|
lspManager?: ILspManager;
|
|
35
37
|
logger?: Logger;
|
|
36
|
-
/**
|
|
38
|
+
/** Permission manager for handling tool permission checks */
|
|
37
39
|
permissionManager?: PermissionManager;
|
|
40
|
+
/** Foreground task manager for backgrounding tasks */
|
|
41
|
+
foregroundTaskManager?: import("../types/processes.js").IForegroundTaskManager;
|
|
38
42
|
/** Reversion manager for file snapshots */
|
|
39
43
|
reversionManager?: ReversionManager;
|
|
44
|
+
/** Background task manager for background execution */
|
|
45
|
+
backgroundTaskManager?: import("./backgroundTaskManager.js").BackgroundTaskManager;
|
|
40
46
|
/** Permission mode for tool execution (defaults to "default") */
|
|
41
47
|
permissionMode?: PermissionMode;
|
|
42
48
|
/** Custom permission callback for tool usage */
|
|
@@ -55,7 +61,9 @@ class ToolManager {
|
|
|
55
61
|
private lspManager?: ILspManager;
|
|
56
62
|
private logger?: Logger;
|
|
57
63
|
private permissionManager?: PermissionManager;
|
|
64
|
+
private foregroundTaskManager?: import("../types/processes.js").IForegroundTaskManager;
|
|
58
65
|
private reversionManager?: ReversionManager;
|
|
66
|
+
private backgroundTaskManager?: import("./backgroundTaskManager.js").BackgroundTaskManager;
|
|
59
67
|
private permissionMode?: PermissionMode;
|
|
60
68
|
private canUseToolCallback?: PermissionCallback;
|
|
61
69
|
|
|
@@ -64,7 +72,9 @@ class ToolManager {
|
|
|
64
72
|
this.lspManager = options.lspManager;
|
|
65
73
|
this.logger = options.logger;
|
|
66
74
|
this.permissionManager = options.permissionManager;
|
|
75
|
+
this.foregroundTaskManager = options.foregroundTaskManager;
|
|
67
76
|
this.reversionManager = options.reversionManager;
|
|
77
|
+
this.backgroundTaskManager = options.backgroundTaskManager;
|
|
68
78
|
// Store CLI permission mode, let PermissionManager resolve effective mode
|
|
69
79
|
this.permissionMode = options.permissionMode;
|
|
70
80
|
this.canUseToolCallback = options.canUseToolCallback;
|
|
@@ -106,8 +116,8 @@ class ToolManager {
|
|
|
106
116
|
}): void {
|
|
107
117
|
const builtInTools = [
|
|
108
118
|
bashTool,
|
|
109
|
-
|
|
110
|
-
|
|
119
|
+
taskOutputTool,
|
|
120
|
+
taskStopTool,
|
|
111
121
|
deleteFileTool,
|
|
112
122
|
editTool,
|
|
113
123
|
multiEditTool,
|
|
@@ -168,6 +178,8 @@ class ToolManager {
|
|
|
168
178
|
canUseToolCallback: this.canUseToolCallback,
|
|
169
179
|
permissionManager: this.permissionManager,
|
|
170
180
|
reversionManager: this.reversionManager,
|
|
181
|
+
backgroundTaskManager: this.backgroundTaskManager,
|
|
182
|
+
foregroundTaskManager: this.foregroundTaskManager,
|
|
171
183
|
mcpManager: this.mcpManager,
|
|
172
184
|
lspManager: this.lspManager,
|
|
173
185
|
};
|
|
@@ -43,7 +43,9 @@ export class GitService {
|
|
|
43
43
|
|
|
44
44
|
try {
|
|
45
45
|
const refArgs = ref ? `-b "${ref}"` : "--depth 1";
|
|
46
|
-
await execAsync(`
|
|
46
|
+
await execAsync(`git clone ${refArgs} "${url}" "${targetPath}"`, {
|
|
47
|
+
env: { ...process.env, LC_ALL: "C" },
|
|
48
|
+
});
|
|
47
49
|
} catch (error) {
|
|
48
50
|
throw this.handleGitError(urlOrRepo, error);
|
|
49
51
|
}
|
|
@@ -59,7 +61,9 @@ export class GitService {
|
|
|
59
61
|
);
|
|
60
62
|
}
|
|
61
63
|
try {
|
|
62
|
-
await execAsync(`
|
|
64
|
+
await execAsync(`git -C "${targetPath}" pull`, {
|
|
65
|
+
env: { ...process.env, LC_ALL: "C" },
|
|
66
|
+
});
|
|
63
67
|
} catch (error) {
|
|
64
68
|
throw this.handleGitError(targetPath, error);
|
|
65
69
|
}
|
|
@@ -346,7 +346,10 @@ export class MarketplaceService {
|
|
|
346
346
|
/**
|
|
347
347
|
* Installs a plugin from a marketplace
|
|
348
348
|
*/
|
|
349
|
-
async installPlugin(
|
|
349
|
+
async installPlugin(
|
|
350
|
+
pluginAtMarketplace: string,
|
|
351
|
+
projectPath?: string,
|
|
352
|
+
): Promise<InstalledPlugin> {
|
|
350
353
|
const [pluginName, marketplaceName] = pluginAtMarketplace.split("@");
|
|
351
354
|
if (!pluginName || !marketplaceName) {
|
|
352
355
|
throw new Error("Invalid plugin format. Use name@marketplace");
|
|
@@ -432,7 +435,10 @@ export class MarketplaceService {
|
|
|
432
435
|
|
|
433
436
|
const installedRegistry = await this.getInstalledPlugins();
|
|
434
437
|
const existingIndex = installedRegistry.plugins.findIndex(
|
|
435
|
-
(p) =>
|
|
438
|
+
(p) =>
|
|
439
|
+
p.name === pluginName &&
|
|
440
|
+
p.marketplace === marketplaceName &&
|
|
441
|
+
p.projectPath === projectPath,
|
|
436
442
|
);
|
|
437
443
|
|
|
438
444
|
const installedPlugin: InstalledPlugin = {
|
|
@@ -440,6 +446,7 @@ export class MarketplaceService {
|
|
|
440
446
|
marketplace: marketplaceName,
|
|
441
447
|
version,
|
|
442
448
|
cachePath,
|
|
449
|
+
projectPath,
|
|
443
450
|
};
|
|
444
451
|
|
|
445
452
|
if (existingIndex >= 0) {
|
|
@@ -467,7 +474,10 @@ export class MarketplaceService {
|
|
|
467
474
|
/**
|
|
468
475
|
* Uninstalls a plugin
|
|
469
476
|
*/
|
|
470
|
-
async uninstallPlugin(
|
|
477
|
+
async uninstallPlugin(
|
|
478
|
+
pluginAtMarketplace: string,
|
|
479
|
+
projectPath?: string,
|
|
480
|
+
): Promise<void> {
|
|
471
481
|
const [pluginName, marketplaceName] = pluginAtMarketplace.split("@");
|
|
472
482
|
if (!pluginName || !marketplaceName) {
|
|
473
483
|
throw new Error("Invalid plugin format. Use name@marketplace");
|
|
@@ -475,25 +485,33 @@ export class MarketplaceService {
|
|
|
475
485
|
|
|
476
486
|
const installedRegistry = await this.getInstalledPlugins();
|
|
477
487
|
const pluginIndex = installedRegistry.plugins.findIndex(
|
|
478
|
-
(p) =>
|
|
488
|
+
(p) =>
|
|
489
|
+
p.name === pluginName &&
|
|
490
|
+
p.marketplace === marketplaceName &&
|
|
491
|
+
p.projectPath === projectPath,
|
|
479
492
|
);
|
|
480
493
|
|
|
481
494
|
if (pluginIndex === -1) {
|
|
482
495
|
throw new Error(
|
|
483
|
-
`Plugin ${pluginName}@${marketplaceName} is not installed`,
|
|
496
|
+
`Plugin ${pluginName}@${marketplaceName} is not installed${projectPath ? ` for project ${projectPath}` : ""}`,
|
|
484
497
|
);
|
|
485
498
|
}
|
|
486
499
|
|
|
487
|
-
const
|
|
488
|
-
|
|
489
|
-
// Remove cached files
|
|
490
|
-
if (existsSync(plugin.cachePath)) {
|
|
491
|
-
await fs.rm(plugin.cachePath, { recursive: true, force: true });
|
|
492
|
-
}
|
|
500
|
+
const pluginToRemove = installedRegistry.plugins[pluginIndex];
|
|
493
501
|
|
|
494
|
-
// Remove from registry
|
|
502
|
+
// Remove from registry first
|
|
495
503
|
installedRegistry.plugins.splice(pluginIndex, 1);
|
|
496
504
|
await this.saveInstalledPlugins(installedRegistry);
|
|
505
|
+
|
|
506
|
+
// Check if any other project is still using this same cache path
|
|
507
|
+
const isStillReferenced = installedRegistry.plugins.some(
|
|
508
|
+
(p) => p.cachePath === pluginToRemove.cachePath,
|
|
509
|
+
);
|
|
510
|
+
|
|
511
|
+
// Only remove cached files if no other references exist
|
|
512
|
+
if (!isStillReferenced && existsSync(pluginToRemove.cachePath)) {
|
|
513
|
+
await fs.rm(pluginToRemove.cachePath, { recursive: true, force: true });
|
|
514
|
+
}
|
|
497
515
|
}
|
|
498
516
|
|
|
499
517
|
/**
|