wave-agent-sdk 0.8.3 → 0.9.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.map +1 -1
- package/dist/agent.js +7 -10
- package/dist/constants/tools.d.ts +1 -2
- package/dist/constants/tools.d.ts.map +1 -1
- package/dist/constants/tools.js +1 -2
- package/dist/managers/aiManager.d.ts +6 -10
- package/dist/managers/aiManager.d.ts.map +1 -1
- package/dist/managers/aiManager.js +38 -13
- package/dist/managers/hookManager.d.ts.map +1 -1
- package/dist/managers/hookManager.js +15 -1
- package/dist/managers/messageManager.d.ts +1 -0
- package/dist/managers/messageManager.d.ts.map +1 -1
- package/dist/managers/messageManager.js +8 -2
- package/dist/managers/permissionManager.d.ts.map +1 -1
- package/dist/managers/permissionManager.js +2 -7
- package/dist/managers/subagentManager.d.ts +5 -14
- package/dist/managers/subagentManager.d.ts.map +1 -1
- package/dist/managers/subagentManager.js +17 -65
- package/dist/managers/toolManager.d.ts +2 -2
- package/dist/managers/toolManager.d.ts.map +1 -1
- package/dist/managers/toolManager.js +4 -6
- package/dist/prompts/autoMemory.d.ts +2 -0
- package/dist/prompts/autoMemory.d.ts.map +1 -0
- package/dist/prompts/autoMemory.js +33 -0
- package/dist/prompts/index.d.ts +4 -0
- package/dist/prompts/index.d.ts.map +1 -1
- package/dist/prompts/index.js +10 -3
- package/dist/services/aiService.js +6 -7
- package/dist/services/configurationService.d.ts +28 -16
- package/dist/services/configurationService.d.ts.map +1 -1
- package/dist/services/configurationService.js +87 -28
- package/dist/services/hook.js +2 -2
- package/dist/services/initializationService.d.ts.map +1 -1
- package/dist/services/initializationService.js +20 -9
- package/dist/services/memory.d.ts +22 -4
- package/dist/services/memory.d.ts.map +1 -1
- package/dist/services/memory.js +132 -73
- package/dist/tools/agentTool.d.ts +6 -0
- package/dist/tools/agentTool.d.ts.map +1 -0
- package/dist/tools/{taskTool.js → agentTool.js} +42 -30
- package/dist/tools/grepTool.js +2 -2
- package/dist/tools/skillTool.js +2 -2
- package/dist/tools/types.d.ts +1 -1
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/types/configuration.d.ts +2 -0
- package/dist/types/configuration.d.ts.map +1 -1
- package/dist/types/hooks.d.ts +2 -0
- package/dist/types/hooks.d.ts.map +1 -1
- package/dist/types/hooks.js +17 -7
- package/dist/utils/builtinSubagents.d.ts.map +1 -1
- package/dist/utils/builtinSubagents.js +1 -3
- package/dist/utils/containerSetup.d.ts +0 -5
- package/dist/utils/containerSetup.d.ts.map +1 -1
- package/dist/utils/containerSetup.js +8 -11
- package/dist/utils/fileSearch.d.ts +1 -6
- package/dist/utils/fileSearch.d.ts.map +1 -1
- package/dist/utils/fileSearch.js +104 -75
- package/dist/utils/gitUtils.d.ts +6 -0
- package/dist/utils/gitUtils.d.ts.map +1 -1
- package/dist/utils/gitUtils.js +65 -1
- package/dist/utils/path.d.ts +0 -10
- package/dist/utils/path.d.ts.map +1 -1
- package/dist/utils/path.js +0 -61
- package/package.json +2 -1
- package/src/agent.ts +9 -20
- package/src/constants/tools.ts +1 -2
- package/src/managers/aiManager.ts +73 -28
- package/src/managers/hookManager.ts +22 -1
- package/src/managers/messageManager.ts +12 -2
- package/src/managers/permissionManager.ts +1 -7
- package/src/managers/subagentManager.ts +20 -81
- package/src/managers/toolManager.ts +4 -6
- package/src/prompts/autoMemory.ts +33 -0
- package/src/prompts/index.ts +15 -2
- package/src/services/aiService.ts +8 -8
- package/src/services/configurationService.ts +100 -28
- package/src/services/hook.ts +2 -2
- package/src/services/initializationService.ts +24 -12
- package/src/services/memory.ts +144 -82
- package/src/tools/{taskTool.ts → agentTool.ts} +42 -30
- package/src/tools/grepTool.ts +2 -2
- package/src/tools/skillTool.ts +2 -2
- package/src/tools/types.ts +1 -1
- package/src/types/configuration.ts +2 -0
- package/src/types/hooks.ts +25 -9
- package/src/utils/builtinSubagents.ts +0 -3
- package/src/utils/containerSetup.ts +8 -21
- package/src/utils/fileSearch.ts +112 -80
- package/src/utils/gitUtils.ts +66 -1
- package/src/utils/path.ts +0 -62
- package/dist/tools/lsTool.d.ts +0 -6
- package/dist/tools/lsTool.d.ts.map +0 -1
- package/dist/tools/lsTool.js +0 -175
- package/dist/tools/taskTool.d.ts +0 -6
- package/dist/tools/taskTool.d.ts.map +0 -1
- package/src/tools/lsTool.ts +0 -212
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ToolPlugin, ToolResult, ToolContext } from "./types.js";
|
|
2
2
|
import { EXPLORE_SUBAGENT_TYPE } from "../constants/subagents.js";
|
|
3
|
-
import {
|
|
3
|
+
import { AGENT_TOOL_NAME } from "../constants/tools.js";
|
|
4
4
|
import type { SubagentConfiguration } from "../utils/subagentParser.js";
|
|
5
5
|
import {
|
|
6
6
|
countToolBlocks,
|
|
@@ -8,16 +8,16 @@ import {
|
|
|
8
8
|
} from "../utils/messageOperations.js";
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
*
|
|
11
|
+
* Agent tool plugin for launching specialized agents to handle complex tasks
|
|
12
12
|
*/
|
|
13
|
-
export const
|
|
14
|
-
name:
|
|
13
|
+
export const agentTool: ToolPlugin = {
|
|
14
|
+
name: AGENT_TOOL_NAME,
|
|
15
15
|
config: {
|
|
16
16
|
type: "function" as const,
|
|
17
17
|
function: {
|
|
18
|
-
name:
|
|
18
|
+
name: AGENT_TOOL_NAME,
|
|
19
19
|
description:
|
|
20
|
-
"
|
|
20
|
+
"Launch a new agent to handle complex, multi-step tasks autonomously.",
|
|
21
21
|
parameters: {
|
|
22
22
|
type: "object",
|
|
23
23
|
properties: {
|
|
@@ -47,19 +47,31 @@ export const taskTool: ToolPlugin = {
|
|
|
47
47
|
prompt: (args?: { availableSubagents?: SubagentConfiguration[] }) => {
|
|
48
48
|
const subagentList = args?.availableSubagents
|
|
49
49
|
? args.availableSubagents
|
|
50
|
-
.map((config) =>
|
|
50
|
+
.map((config) => {
|
|
51
|
+
let toolsStr = "";
|
|
52
|
+
if (config.tools && config.tools.length > 0) {
|
|
53
|
+
toolsStr = ` (Tools: ${config.tools.join(", ")})`;
|
|
54
|
+
} else {
|
|
55
|
+
toolsStr = " (Tools: *)";
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return `- ${config.name}: ${config.description}${toolsStr}`;
|
|
59
|
+
})
|
|
51
60
|
.join("\n")
|
|
52
61
|
: "";
|
|
53
62
|
|
|
54
|
-
return `
|
|
55
|
-
|
|
63
|
+
return `Launch a new agent to handle complex, multi-step tasks autonomously.
|
|
64
|
+
|
|
65
|
+
The Agent tool launches specialized agents (subprocesses) that autonomously handle complex tasks. Each agent type has specific capabilities and tools available to it.
|
|
66
|
+
|
|
67
|
+
Available agent types and the tools they have access to:
|
|
68
|
+
${subagentList || "No agents configured"}
|
|
56
69
|
|
|
57
|
-
|
|
58
|
-
${subagentList || "No subagents configured"}
|
|
70
|
+
When using the Agent tool, you must specify a subagent_type parameter to select which agent type to use.
|
|
59
71
|
|
|
60
|
-
- When doing file search, prefer to use the ${
|
|
61
|
-
- You should proactively use the ${
|
|
62
|
-
- VERY IMPORTANT: When exploring the codebase to gather context or to answer a question that is not a needle query for a specific file/class/function, it is CRITICAL that you use the ${
|
|
72
|
+
- When doing file search, prefer to use the ${AGENT_TOOL_NAME} tool in order to reduce context usage.
|
|
73
|
+
- You should proactively use the ${AGENT_TOOL_NAME} tool with specialized agents when the task at hand matches the agent's description.
|
|
74
|
+
- VERY IMPORTANT: When exploring the codebase to gather context or to answer a question that is not a needle query for a specific file/class/function, it is CRITICAL that you use the ${AGENT_TOOL_NAME} tool with subagent_type=${EXPLORE_SUBAGENT_TYPE} instead of running search commands directly.`;
|
|
63
75
|
},
|
|
64
76
|
|
|
65
77
|
execute: async (
|
|
@@ -72,7 +84,7 @@ ${subagentList || "No subagents configured"}
|
|
|
72
84
|
success: false,
|
|
73
85
|
content: "",
|
|
74
86
|
error: "Subagent manager not available in tool context",
|
|
75
|
-
shortResult: "
|
|
87
|
+
shortResult: "Agent delegation failed",
|
|
76
88
|
};
|
|
77
89
|
}
|
|
78
90
|
|
|
@@ -87,7 +99,7 @@ ${subagentList || "No subagents configured"}
|
|
|
87
99
|
success: false,
|
|
88
100
|
content: "",
|
|
89
101
|
error: "description parameter is required and must be a string",
|
|
90
|
-
shortResult: "
|
|
102
|
+
shortResult: "Agent delegation failed",
|
|
91
103
|
};
|
|
92
104
|
}
|
|
93
105
|
|
|
@@ -96,7 +108,7 @@ ${subagentList || "No subagents configured"}
|
|
|
96
108
|
success: false,
|
|
97
109
|
content: "",
|
|
98
110
|
error: "prompt parameter is required and must be a string",
|
|
99
|
-
shortResult: "
|
|
111
|
+
shortResult: "Agent delegation failed",
|
|
100
112
|
};
|
|
101
113
|
}
|
|
102
114
|
|
|
@@ -105,7 +117,7 @@ ${subagentList || "No subagents configured"}
|
|
|
105
117
|
success: false,
|
|
106
118
|
content: "",
|
|
107
119
|
error: "subagent_type parameter is required and must be a string",
|
|
108
|
-
shortResult: "
|
|
120
|
+
shortResult: "Agent delegation failed",
|
|
109
121
|
};
|
|
110
122
|
}
|
|
111
123
|
|
|
@@ -121,14 +133,14 @@ ${subagentList || "No subagents configured"}
|
|
|
121
133
|
return {
|
|
122
134
|
success: false,
|
|
123
135
|
content: "",
|
|
124
|
-
error: `No
|
|
125
|
-
shortResult: "
|
|
136
|
+
error: `No agent found matching "${subagent_type}". Available agents: ${availableNames || "none"}`,
|
|
137
|
+
shortResult: "Agent not found",
|
|
126
138
|
};
|
|
127
139
|
}
|
|
128
140
|
|
|
129
141
|
let isBackgrounded = false;
|
|
130
142
|
|
|
131
|
-
// Create subagent instance and execute
|
|
143
|
+
// Create subagent instance and execute agent
|
|
132
144
|
const instance = await subagentManager.createInstance(
|
|
133
145
|
configuration,
|
|
134
146
|
{
|
|
@@ -173,8 +185,8 @@ ${subagentList || "No subagents configured"}
|
|
|
173
185
|
await subagentManager.backgroundInstance(instance.subagentId);
|
|
174
186
|
resolve({
|
|
175
187
|
success: true,
|
|
176
|
-
content: "
|
|
177
|
-
shortResult: "
|
|
188
|
+
content: "Agent backgrounded",
|
|
189
|
+
shortResult: "Agent backgrounded",
|
|
178
190
|
isManuallyBackgrounded: true,
|
|
179
191
|
});
|
|
180
192
|
},
|
|
@@ -182,7 +194,7 @@ ${subagentList || "No subagents configured"}
|
|
|
182
194
|
}
|
|
183
195
|
|
|
184
196
|
try {
|
|
185
|
-
const result = await subagentManager.
|
|
197
|
+
const result = await subagentManager.executeAgent(
|
|
186
198
|
instance,
|
|
187
199
|
prompt,
|
|
188
200
|
context.abortSignal,
|
|
@@ -196,13 +208,13 @@ ${subagentList || "No subagents configured"}
|
|
|
196
208
|
if (run_in_background) {
|
|
197
209
|
resolve({
|
|
198
210
|
success: true,
|
|
199
|
-
content: `
|
|
200
|
-
shortResult: `
|
|
211
|
+
content: `Agent started in background with ID: ${result}`,
|
|
212
|
+
shortResult: `Agent started in background: ${result}`,
|
|
201
213
|
});
|
|
202
214
|
return;
|
|
203
215
|
}
|
|
204
216
|
|
|
205
|
-
// Cleanup subagent instance after
|
|
217
|
+
// Cleanup subagent instance after agent completion
|
|
206
218
|
subagentManager.cleanupInstance(instance.subagentId);
|
|
207
219
|
|
|
208
220
|
const messages = instance.messageManager.getMessages();
|
|
@@ -213,14 +225,14 @@ ${subagentList || "No subagents configured"}
|
|
|
213
225
|
resolve({
|
|
214
226
|
success: true,
|
|
215
227
|
content: result,
|
|
216
|
-
shortResult: `
|
|
228
|
+
shortResult: `Agent completed${summary ? ` ${summary}` : ""}`,
|
|
217
229
|
});
|
|
218
230
|
} catch (error) {
|
|
219
231
|
if (!isBackgrounded) {
|
|
220
232
|
resolve({
|
|
221
233
|
success: false,
|
|
222
234
|
content: "",
|
|
223
|
-
error: `
|
|
235
|
+
error: `Agent delegation failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
224
236
|
shortResult: "Delegation error",
|
|
225
237
|
});
|
|
226
238
|
}
|
|
@@ -237,7 +249,7 @@ ${subagentList || "No subagents configured"}
|
|
|
237
249
|
return {
|
|
238
250
|
success: false,
|
|
239
251
|
content: "",
|
|
240
|
-
error: `
|
|
252
|
+
error: `Agent delegation failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
241
253
|
shortResult: "Delegation error",
|
|
242
254
|
};
|
|
243
255
|
}
|
package/src/tools/grepTool.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { getDisplayPath } from "../utils/path.js";
|
|
|
6
6
|
import {
|
|
7
7
|
GREP_TOOL_NAME,
|
|
8
8
|
BASH_TOOL_NAME,
|
|
9
|
-
|
|
9
|
+
AGENT_TOOL_NAME,
|
|
10
10
|
} from "../constants/tools.js";
|
|
11
11
|
|
|
12
12
|
/**
|
|
@@ -94,7 +94,7 @@ export const grepTool: ToolPlugin = {
|
|
|
94
94
|
- Supports full regex syntax (e.g., "log.*Error", "function\\s+\\w+")
|
|
95
95
|
- Filter files with glob parameter (e.g., "*.js", "**/*.tsx") or type parameter (e.g., "js", "py", "rust")
|
|
96
96
|
- Output modes: "content" shows matching lines, "files_with_matches" shows only file paths (default), "count" shows match counts
|
|
97
|
-
- Use ${
|
|
97
|
+
- Use ${AGENT_TOOL_NAME} tool for open-ended searches requiring multiple rounds
|
|
98
98
|
- Pattern syntax: Uses ripgrep (not grep) - literal braces need escaping (use \`interface\\{\\}\` to find \`interface{}\` in Go code)
|
|
99
99
|
- Multiline matching: By default patterns match within single lines only. For cross-line patterns like \`struct \\{[\\s\\S]*?field\`, use \`multiline: true\`
|
|
100
100
|
`,
|
package/src/tools/skillTool.ts
CHANGED
|
@@ -155,14 +155,14 @@ export const skillTool: ToolPlugin = {
|
|
|
155
155
|
);
|
|
156
156
|
|
|
157
157
|
try {
|
|
158
|
-
const result = await subagentManager.
|
|
158
|
+
const result = await subagentManager.executeAgent(
|
|
159
159
|
instance,
|
|
160
160
|
skillResult.content,
|
|
161
161
|
context.abortSignal,
|
|
162
162
|
false,
|
|
163
163
|
);
|
|
164
164
|
|
|
165
|
-
// Cleanup subagent instance after
|
|
165
|
+
// Cleanup subagent instance after agent completion
|
|
166
166
|
subagentManager.cleanupInstance(instance.subagentId);
|
|
167
167
|
|
|
168
168
|
const messages = instance.messageManager.getMessages();
|
package/src/tools/types.ts
CHANGED
|
@@ -73,7 +73,7 @@ export interface ToolContext {
|
|
|
73
73
|
foregroundTaskManager?: import("../types/processes.js").IForegroundTaskManager;
|
|
74
74
|
/** Task manager instance for task management */
|
|
75
75
|
taskManager: import("../services/taskManager.js").TaskManager;
|
|
76
|
-
/** Subagent manager instance for
|
|
76
|
+
/** Subagent manager instance for agent delegation */
|
|
77
77
|
subagentManager?: import("../managers/subagentManager.js").SubagentManager;
|
|
78
78
|
/** Skill manager instance for skill invocation */
|
|
79
79
|
skillManager?: import("../managers/skillManager.js").SkillManager;
|
package/src/types/hooks.ts
CHANGED
|
@@ -26,6 +26,8 @@ export type HookEvent =
|
|
|
26
26
|
export interface HookCommand {
|
|
27
27
|
type: "command";
|
|
28
28
|
command: string;
|
|
29
|
+
async?: boolean;
|
|
30
|
+
timeout?: number; // seconds
|
|
29
31
|
}
|
|
30
32
|
|
|
31
33
|
// Hook event configuration with optional pattern matching
|
|
@@ -104,15 +106,29 @@ export function isValidHookEvent(event: string): event is HookEvent {
|
|
|
104
106
|
}
|
|
105
107
|
|
|
106
108
|
export function isValidHookCommand(cmd: unknown): cmd is HookCommand {
|
|
107
|
-
|
|
108
|
-
typeof cmd
|
|
109
|
-
cmd
|
|
110
|
-
"type" in cmd
|
|
111
|
-
cmd.type
|
|
112
|
-
"command" in cmd
|
|
113
|
-
typeof cmd.command
|
|
114
|
-
cmd.command.length
|
|
115
|
-
)
|
|
109
|
+
if (
|
|
110
|
+
typeof cmd !== "object" ||
|
|
111
|
+
cmd === null ||
|
|
112
|
+
!("type" in cmd) ||
|
|
113
|
+
cmd.type !== "command" ||
|
|
114
|
+
!("command" in cmd) ||
|
|
115
|
+
typeof cmd.command !== "string" ||
|
|
116
|
+
cmd.command.length === 0
|
|
117
|
+
) {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const hookCmd = cmd as Record<string, unknown>;
|
|
122
|
+
|
|
123
|
+
if ("async" in hookCmd && typeof hookCmd.async !== "boolean") {
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if ("timeout" in hookCmd && typeof hookCmd.timeout !== "number") {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return true;
|
|
116
132
|
}
|
|
117
133
|
|
|
118
134
|
export function isValidHookEventConfig(
|
|
@@ -15,7 +15,6 @@ import {
|
|
|
15
15
|
GLOB_TOOL_NAME,
|
|
16
16
|
GREP_TOOL_NAME,
|
|
17
17
|
READ_TOOL_NAME,
|
|
18
|
-
LS_TOOL_NAME,
|
|
19
18
|
LSP_TOOL_NAME,
|
|
20
19
|
} from "../constants/tools.js";
|
|
21
20
|
import type { SubagentConfiguration } from "./subagentParser.js";
|
|
@@ -79,7 +78,6 @@ function createExploreSubagent(): SubagentConfiguration {
|
|
|
79
78
|
GREP_TOOL_NAME,
|
|
80
79
|
READ_TOOL_NAME,
|
|
81
80
|
BASH_TOOL_NAME,
|
|
82
|
-
LS_TOOL_NAME,
|
|
83
81
|
LSP_TOOL_NAME,
|
|
84
82
|
];
|
|
85
83
|
|
|
@@ -107,7 +105,6 @@ function createPlanSubagent(): SubagentConfiguration {
|
|
|
107
105
|
GREP_TOOL_NAME,
|
|
108
106
|
READ_TOOL_NAME,
|
|
109
107
|
BASH_TOOL_NAME,
|
|
110
|
-
LS_TOOL_NAME,
|
|
111
108
|
LSP_TOOL_NAME,
|
|
112
109
|
];
|
|
113
110
|
|
|
@@ -21,6 +21,7 @@ import { SubagentManager } from "../managers/subagentManager.js";
|
|
|
21
21
|
import { LiveConfigManager } from "../managers/liveConfigManager.js";
|
|
22
22
|
import { ConfigurationService } from "../services/configurationService.js";
|
|
23
23
|
import { ReversionService } from "../services/reversionService.js";
|
|
24
|
+
import { MemoryService } from "../services/memory.js";
|
|
24
25
|
import type { AgentOptions } from "../types/index.js";
|
|
25
26
|
import type {
|
|
26
27
|
PermissionMode,
|
|
@@ -29,7 +30,6 @@ import type {
|
|
|
29
30
|
BackgroundTask,
|
|
30
31
|
ToolPermissionContext,
|
|
31
32
|
} from "../types/index.js";
|
|
32
|
-
import type { GatewayConfig, ModelConfig } from "../types/config.js";
|
|
33
33
|
|
|
34
34
|
import { logger } from "./globalLogger.js";
|
|
35
35
|
|
|
@@ -48,12 +48,6 @@ export interface AgentContainerSetupOptions {
|
|
|
48
48
|
setPermissionMode: (mode: PermissionMode) => void;
|
|
49
49
|
addPermissionRule: (rule: string) => Promise<void>;
|
|
50
50
|
addUsage: (usage: Usage) => void;
|
|
51
|
-
|
|
52
|
-
// Getters
|
|
53
|
-
getGatewayConfig: () => GatewayConfig;
|
|
54
|
-
getModelConfig: () => ModelConfig;
|
|
55
|
-
getMaxInputTokens: () => number;
|
|
56
|
-
getLanguage: () => string | undefined;
|
|
57
51
|
}
|
|
58
52
|
|
|
59
53
|
export function setupAgentContainer(
|
|
@@ -72,10 +66,6 @@ export function setupAgentContainer(
|
|
|
72
66
|
setPermissionMode,
|
|
73
67
|
addPermissionRule,
|
|
74
68
|
addUsage,
|
|
75
|
-
getGatewayConfig,
|
|
76
|
-
getModelConfig,
|
|
77
|
-
getMaxInputTokens,
|
|
78
|
-
getLanguage,
|
|
79
69
|
} = setupOptions;
|
|
80
70
|
|
|
81
71
|
const callbacks = options.callbacks || {};
|
|
@@ -85,6 +75,9 @@ export function setupAgentContainer(
|
|
|
85
75
|
container.register("ForegroundTaskManager", foregroundTaskManager);
|
|
86
76
|
container.register("ConfigurationService", configurationService);
|
|
87
77
|
|
|
78
|
+
const memoryService = new MemoryService(container);
|
|
79
|
+
container.register("MemoryService", memoryService);
|
|
80
|
+
|
|
88
81
|
const memoryRuleManager = new MemoryRuleManager(container, { workdir });
|
|
89
82
|
container.register("MemoryRuleManager", memoryRuleManager);
|
|
90
83
|
|
|
@@ -139,6 +132,10 @@ export function setupAgentContainer(
|
|
|
139
132
|
container.register("LspManager", lspManager);
|
|
140
133
|
|
|
141
134
|
const permissionManager = new PermissionManager(container, { workdir });
|
|
135
|
+
if (configurationService.resolveAutoMemoryEnabled()) {
|
|
136
|
+
const autoMemoryDir = memoryService.getAutoMemoryDirectory(workdir);
|
|
137
|
+
permissionManager.updateAdditionalDirectories([autoMemoryDir]);
|
|
138
|
+
}
|
|
142
139
|
container.register("PermissionManager", permissionManager);
|
|
143
140
|
permissionManager.setOnConfiguredDefaultModeChange((mode) => {
|
|
144
141
|
handlePlanModeTransition(mode);
|
|
@@ -246,11 +243,6 @@ export function setupAgentContainer(
|
|
|
246
243
|
onSubagentLatestTotalTokensChange:
|
|
247
244
|
callbacks.onSubagentLatestTotalTokensChange,
|
|
248
245
|
},
|
|
249
|
-
getGatewayConfig,
|
|
250
|
-
getModelConfig,
|
|
251
|
-
getMaxInputTokens,
|
|
252
|
-
getLanguage,
|
|
253
|
-
getEnvironmentVars: () => configurationService.getEnvironmentVars(),
|
|
254
246
|
onUsageAdded: (usage: Usage) => addUsage(usage),
|
|
255
247
|
});
|
|
256
248
|
container.register("SubagentManager", subagentManager);
|
|
@@ -263,11 +255,6 @@ export function setupAgentContainer(
|
|
|
263
255
|
workdir,
|
|
264
256
|
systemPrompt,
|
|
265
257
|
stream,
|
|
266
|
-
getGatewayConfig,
|
|
267
|
-
getModelConfig,
|
|
268
|
-
getMaxInputTokens,
|
|
269
|
-
getLanguage,
|
|
270
|
-
getEnvironmentVars: () => configurationService.getEnvironmentVars(),
|
|
271
258
|
});
|
|
272
259
|
container.register("AIManager", aiManager);
|
|
273
260
|
|
package/src/utils/fileSearch.ts
CHANGED
|
@@ -1,26 +1,78 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { spawn } from "child_process";
|
|
2
|
+
import { rgPath } from "@vscode/ripgrep";
|
|
3
|
+
import fuzzysort from "fuzzysort";
|
|
2
4
|
import { getGlobIgnorePatterns } from "./fileFilter.js";
|
|
3
5
|
import type { FileItem } from "../types/fileSearch.js";
|
|
6
|
+
import { logger } from "./globalLogger.js";
|
|
4
7
|
|
|
5
8
|
/**
|
|
6
|
-
*
|
|
9
|
+
* Execute ripgrep to get all file paths
|
|
7
10
|
*/
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
11
|
+
async function getAllFiles(workingDirectory: string): Promise<string[]> {
|
|
12
|
+
if (!rgPath) {
|
|
13
|
+
throw new Error("ripgrep is not available");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const ignorePatterns = getGlobIgnorePatterns(workingDirectory);
|
|
17
|
+
const rgArgs = ["--files", "--color=never", "--hidden"];
|
|
18
|
+
for (const pattern of ignorePatterns) {
|
|
19
|
+
rgArgs.push("--glob", `!${pattern}`);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return new Promise((resolve, reject) => {
|
|
23
|
+
const child = spawn(rgPath, rgArgs, {
|
|
24
|
+
cwd: workingDirectory,
|
|
25
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
let stdout = "";
|
|
29
|
+
let stderr = "";
|
|
30
|
+
|
|
31
|
+
child.stdout?.on("data", (data) => {
|
|
32
|
+
stdout += data.toString();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
child.stderr?.on("data", (data) => {
|
|
36
|
+
stderr += data.toString();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
child.on("close", (code) => {
|
|
40
|
+
if (code !== 0 && code !== 1) {
|
|
41
|
+
reject(new Error(`ripgrep failed: ${stderr}`));
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const files = stdout
|
|
45
|
+
.trim()
|
|
46
|
+
.split("\n")
|
|
47
|
+
.filter((f) => f.length > 0)
|
|
48
|
+
.map((f) => f.replace(/\\/g, "/")); // Normalize to forward slashes
|
|
49
|
+
resolve(files);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
child.on("error", (err) => {
|
|
53
|
+
reject(err);
|
|
54
|
+
});
|
|
19
55
|
});
|
|
20
|
-
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Derive directory paths from file paths
|
|
60
|
+
*/
|
|
61
|
+
function deriveDirectories(files: string[]): string[] {
|
|
62
|
+
const dirs = new Set<string>();
|
|
63
|
+
for (const file of files) {
|
|
64
|
+
const parts = file.split("/");
|
|
65
|
+
// Add all parent directories
|
|
66
|
+
for (let i = 1; i < parts.length; i++) {
|
|
67
|
+
const dir = parts.slice(0, i).join("/") + "/";
|
|
68
|
+
dirs.add(dir);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return Array.from(dirs);
|
|
72
|
+
}
|
|
21
73
|
|
|
22
74
|
/**
|
|
23
|
-
* Search files and directories using
|
|
75
|
+
* Search files and directories using fuzzy matching
|
|
24
76
|
*/
|
|
25
77
|
export const searchFiles = async (
|
|
26
78
|
query: string,
|
|
@@ -32,83 +84,63 @@ export const searchFiles = async (
|
|
|
32
84
|
const { maxResults = 10, workingDirectory = process.cwd() } = options || {};
|
|
33
85
|
|
|
34
86
|
try {
|
|
35
|
-
const
|
|
36
|
-
ignore: getGlobIgnorePatterns(workingDirectory),
|
|
37
|
-
maxDepth: 10,
|
|
38
|
-
nocase: true, // Case insensitive
|
|
39
|
-
dot: true, // Include hidden files and directories
|
|
40
|
-
cwd: workingDirectory, // Specify search root directory
|
|
41
|
-
withFileTypes: true, // Get Path objects instead of strings
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
// Build glob patterns based on query
|
|
45
|
-
let patterns: string[] = [];
|
|
87
|
+
const files = await getAllFiles(workingDirectory);
|
|
46
88
|
|
|
47
89
|
if (!query.trim()) {
|
|
48
|
-
// When query is empty, show some common file types and directories
|
|
49
|
-
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
// Match directory names containing query
|
|
61
|
-
`**/*${query}*/`,
|
|
62
|
-
// Match directories containing query in path
|
|
63
|
-
`**/${query}*/`,
|
|
64
|
-
];
|
|
65
|
-
}
|
|
90
|
+
// When query is empty, show some common file types and top-level directories
|
|
91
|
+
const commonExtensions = new Set([
|
|
92
|
+
"ts",
|
|
93
|
+
"tsx",
|
|
94
|
+
"js",
|
|
95
|
+
"jsx",
|
|
96
|
+
"json",
|
|
97
|
+
"py",
|
|
98
|
+
"java",
|
|
99
|
+
]);
|
|
100
|
+
const results: FileItem[] = [];
|
|
101
|
+
const seenDirs = new Set<string>();
|
|
66
102
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// Use globIterate to get results one by one
|
|
78
|
-
const iterator = globIterate(pattern, globOptions) as AsyncGenerator<
|
|
79
|
-
Path,
|
|
80
|
-
void,
|
|
81
|
-
void
|
|
82
|
-
>;
|
|
83
|
-
|
|
84
|
-
for await (const pathObj of iterator) {
|
|
85
|
-
if (collectedPaths.length >= maxResults) {
|
|
86
|
-
// Stop the iterator when we have enough results
|
|
87
|
-
break;
|
|
103
|
+
for (const file of files) {
|
|
104
|
+
const parts = file.split("/");
|
|
105
|
+
if (parts.length > 1) {
|
|
106
|
+
const topDir = parts[0] + "/";
|
|
107
|
+
if (!seenDirs.has(topDir)) {
|
|
108
|
+
seenDirs.add(topDir);
|
|
109
|
+
results.push({ path: topDir, type: "directory" });
|
|
110
|
+
}
|
|
88
111
|
}
|
|
89
112
|
|
|
90
|
-
const
|
|
91
|
-
if (
|
|
92
|
-
|
|
93
|
-
collectedPaths.push(pathObj);
|
|
113
|
+
const ext = file.split(".").pop();
|
|
114
|
+
if (ext && commonExtensions.has(ext)) {
|
|
115
|
+
results.push({ path: file, type: "file" });
|
|
94
116
|
}
|
|
95
117
|
}
|
|
118
|
+
|
|
119
|
+
// Sort: directories first, then files, then alphabetically
|
|
120
|
+
return results
|
|
121
|
+
.sort((a, b) => {
|
|
122
|
+
if (a.type === "directory" && b.type === "file") return -1;
|
|
123
|
+
if (a.type === "file" && b.type === "directory") return 1;
|
|
124
|
+
return a.path.localeCompare(b.path);
|
|
125
|
+
})
|
|
126
|
+
.slice(0, maxResults);
|
|
96
127
|
}
|
|
97
128
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
129
|
+
const directories = deriveDirectories(files);
|
|
130
|
+
const allItems: FileItem[] = [
|
|
131
|
+
...files.map((f) => ({ path: f, type: "file" as const })),
|
|
132
|
+
...directories.map((d) => ({ path: d, type: "directory" as const })),
|
|
133
|
+
];
|
|
134
|
+
|
|
135
|
+
const fuzzyResults = fuzzysort.go(query, allItems, {
|
|
136
|
+
key: "path",
|
|
137
|
+
limit: maxResults,
|
|
138
|
+
threshold: 0,
|
|
105
139
|
});
|
|
106
140
|
|
|
107
|
-
|
|
108
|
-
const fileItems = convertPathsToFileItems(collectedPaths);
|
|
109
|
-
return fileItems;
|
|
141
|
+
return fuzzyResults.map((res) => res.obj);
|
|
110
142
|
} catch (error) {
|
|
111
|
-
|
|
143
|
+
logger.error("Fuzzy search error:", error);
|
|
112
144
|
return [];
|
|
113
145
|
}
|
|
114
146
|
};
|