wave-agent-sdk 0.4.0 → 0.5.0
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 +59 -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 +8 -3
- package/dist/managers/aiManager.d.ts.map +1 -1
- package/dist/managers/aiManager.js +35 -9
- 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 +141 -35
- 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 +52 -174
- 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 +79 -45
- package/src/constants/tools.ts +2 -2
- package/src/managers/MemoryRuleManager.ts +1 -1
- package/src/managers/aiManager.ts +50 -17
- 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 +171 -31
- 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 +73 -200
- 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
|
@@ -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,125 @@ export class SubagentManager {
|
|
|
269
282
|
status: "active",
|
|
270
283
|
});
|
|
271
284
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
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;
|
|
329
|
+
}
|
|
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
|
+
// Only update status if it's NOT a background task
|
|
386
|
+
if (!instance.backgroundTaskId) {
|
|
278
387
|
this.updateInstanceStatus(instance.subagentId, "aborted");
|
|
279
388
|
this.parentMessageManager.updateSubagentBlock(instance.subagentId, {
|
|
280
389
|
status: "aborted",
|
|
281
390
|
});
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
|
|
391
|
+
}
|
|
392
|
+
},
|
|
393
|
+
() => {
|
|
394
|
+
// Abort the AI execution
|
|
395
|
+
// Only abort if it's NOT a background task
|
|
396
|
+
if (!instance.backgroundTaskId) {
|
|
285
397
|
instance.aiManager.abortAIMessage();
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
|
|
398
|
+
}
|
|
399
|
+
},
|
|
400
|
+
]);
|
|
401
|
+
}
|
|
289
402
|
|
|
403
|
+
try {
|
|
290
404
|
// Add the user's prompt as a message
|
|
291
405
|
instance.messageManager.addUserMessage({ content: prompt });
|
|
292
406
|
|
|
@@ -326,21 +440,16 @@ export class SubagentManager {
|
|
|
326
440
|
model: resolvedModel,
|
|
327
441
|
});
|
|
328
442
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
} finally {
|
|
340
|
-
// Clean up abort listeners to prevent memory leaks
|
|
341
|
-
if (abortCleanup) {
|
|
342
|
-
abortCleanup();
|
|
343
|
-
}
|
|
443
|
+
// If we have an abort signal, race against it using utilities to prevent listener accumulation
|
|
444
|
+
// BUT: If this is a background task, we DON'T want to race against the abort signal
|
|
445
|
+
// because the abort signal (Esc) should only stop the tool watching the task, not the task itself.
|
|
446
|
+
if (abortSignal && !instance.backgroundTaskId) {
|
|
447
|
+
await Promise.race([
|
|
448
|
+
executeAI,
|
|
449
|
+
createAbortPromise(abortSignal, "Task was aborted"),
|
|
450
|
+
]);
|
|
451
|
+
} else {
|
|
452
|
+
await executeAI;
|
|
344
453
|
}
|
|
345
454
|
|
|
346
455
|
// Get the latest messages to extract the response
|
|
@@ -365,13 +474,43 @@ export class SubagentManager {
|
|
|
365
474
|
status: "completed",
|
|
366
475
|
});
|
|
367
476
|
|
|
477
|
+
// If this was transitioned to background, update the background task
|
|
478
|
+
if (instance.backgroundTaskId && this.backgroundTaskManager) {
|
|
479
|
+
const task = this.backgroundTaskManager.getTask(
|
|
480
|
+
instance.backgroundTaskId,
|
|
481
|
+
);
|
|
482
|
+
if (task) {
|
|
483
|
+
task.status = "completed";
|
|
484
|
+
task.stdout = response || "Task completed with no text response";
|
|
485
|
+
task.endTime = Date.now();
|
|
486
|
+
if (task.startTime) {
|
|
487
|
+
task.runtime = task.endTime - task.startTime;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
|
|
368
492
|
return response || "Task completed with no text response";
|
|
369
493
|
} catch (error) {
|
|
370
|
-
this
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
494
|
+
// If this was transitioned to background, update the background task with error
|
|
495
|
+
if (instance.backgroundTaskId && this.backgroundTaskManager) {
|
|
496
|
+
const task = this.backgroundTaskManager.getTask(
|
|
497
|
+
instance.backgroundTaskId,
|
|
498
|
+
);
|
|
499
|
+
if (task) {
|
|
500
|
+
task.status = "failed";
|
|
501
|
+
task.stderr = error instanceof Error ? error.message : String(error);
|
|
502
|
+
task.endTime = Date.now();
|
|
503
|
+
if (task.startTime) {
|
|
504
|
+
task.runtime = task.endTime - task.startTime;
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
}
|
|
374
508
|
throw error;
|
|
509
|
+
} finally {
|
|
510
|
+
// Clean up abort listeners to prevent memory leaks
|
|
511
|
+
if (abortCleanup) {
|
|
512
|
+
abortCleanup();
|
|
513
|
+
}
|
|
375
514
|
}
|
|
376
515
|
}
|
|
377
516
|
|
|
@@ -462,6 +601,7 @@ export class SubagentManager {
|
|
|
462
601
|
logger: this.logger,
|
|
463
602
|
sessionType: "subagent",
|
|
464
603
|
subagentType: configuration.name, // Use configuration name for restored sessions
|
|
604
|
+
memoryRuleManager: this.memoryRuleManager,
|
|
465
605
|
});
|
|
466
606
|
|
|
467
607
|
// 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
|
/**
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { minimatch } from "minimatch";
|
|
2
|
+
import * as path from "node:path";
|
|
2
3
|
import { parseFrontmatter } from "../utils/markdownParser.js";
|
|
3
4
|
import type { MemoryRule, MemoryRuleMetadata } from "../types/memoryRule.js";
|
|
4
5
|
|
|
@@ -45,15 +46,26 @@ export class MemoryRuleService {
|
|
|
45
46
|
/**
|
|
46
47
|
* Determines if a rule matches any of the given file paths using minimatch.
|
|
47
48
|
*/
|
|
48
|
-
isRuleActive(
|
|
49
|
+
isRuleActive(
|
|
50
|
+
rule: MemoryRule,
|
|
51
|
+
filesInContext: string[],
|
|
52
|
+
workdir?: string,
|
|
53
|
+
): boolean {
|
|
49
54
|
if (!rule.metadata.paths || rule.metadata.paths.length === 0) {
|
|
50
55
|
return true;
|
|
51
56
|
}
|
|
52
57
|
|
|
53
|
-
return filesInContext.some((filePath) =>
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
)
|
|
57
|
-
|
|
58
|
+
return filesInContext.some((filePath) => {
|
|
59
|
+
// Normalize path relative to workdir if it's an absolute path
|
|
60
|
+
let normalizedPath = filePath;
|
|
61
|
+
if (workdir && path.isAbsolute(filePath)) {
|
|
62
|
+
normalizedPath = path.relative(workdir, filePath);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return rule.metadata.paths!.some((pattern) => {
|
|
66
|
+
const isMatch = minimatch(normalizedPath, pattern, { dot: true });
|
|
67
|
+
return isMatch;
|
|
68
|
+
});
|
|
69
|
+
});
|
|
58
70
|
}
|
|
59
71
|
}
|
package/src/services/memory.ts
CHANGED