@amical/aiagent-sdk 0.1.8 → 0.1.10

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/index.d.mts CHANGED
@@ -7,12 +7,12 @@ interface IAgentRuntime {
7
7
  * 文件系统相关操作
8
8
  */
9
9
  fs: {
10
- readFile(path: string): Promise<string>;
10
+ readFile(path: string, options?: any): Promise<any>;
11
11
  writeFile(path: string, content: string): Promise<void>;
12
12
  deleteFile(path: string): Promise<void>;
13
13
  deleteDirectory(path: string): Promise<void>;
14
14
  fileExists(path: string): Promise<boolean>;
15
- readDir(path: string): Promise<any[]>;
15
+ readDir(path: string, options?: any): Promise<any[]>;
16
16
  mkdir(path: string): Promise<void>;
17
17
  /**
18
18
  * 跨文件正则搜索
@@ -21,7 +21,8 @@ interface IAgentRuntime {
21
21
  * @param filePattern (可选) 文件名匹配模式,比如 '*.ts'
22
22
  * @returns 返回格式化后的包含上下文的搜索结果字符串
23
23
  */
24
- searchFiles?(path: string, regex: string, filePattern?: string): Promise<string>;
24
+ searchFiles?(path: string, regex: string, filePattern?: string, includeNodeModules?: boolean): Promise<string>;
25
+ searchFileContent?(path: string, regex: string, filePattern?: string, includeNodeModules?: boolean): Promise<string>;
25
26
  };
26
27
  path: {
27
28
  join(...paths: string[]): string;
@@ -59,6 +60,7 @@ declare enum AgentDefaultTool {
59
60
  FILE_DELETE = "agent_delete_file",
60
61
  DIR_DELETE = "agent_delete_directory",
61
62
  SEARCH = "agent_search_files",
63
+ SEARCH_CONTENT = "agent_search_file_content",
62
64
  LIST_FILES = "agent_list_files",
63
65
  LIST_CODE_DEF = "agent_list_code_definition_names",
64
66
  BROWSER = "agent_browser_action",
@@ -137,11 +139,21 @@ declare const defaultTools: readonly [{
137
139
  };
138
140
  }, {
139
141
  readonly name: AgentDefaultTool.SEARCH;
140
- readonly description: "Search for files in a directory that match a regex pattern or glob pattern.";
142
+ readonly description: "Search for files or directories by name in a directory tree, matching the name against a regex (and optionally a glob). Directories are traversed level by level: all matches in the current level are returned before descending into deeper levels. Use this tool only to locate files/directories by name.";
141
143
  readonly params: {
142
144
  readonly path: "(required) The absolute or relative directory path to search.";
143
- readonly regex: "(required) The regex pattern to match files against.";
145
+ readonly regex: "(required) The regex pattern to match file or directory names against.";
144
146
  readonly file_pattern: "(optional) glob pattern like *.ts.";
147
+ readonly include_node_modules: "(optional) set to true to include node_modules in the search. Defaults to false, so node_modules is skipped.";
148
+ };
149
+ }, {
150
+ readonly name: AgentDefaultTool.SEARCH_CONTENT;
151
+ readonly description: "Search the contents of files in a directory tree for a regex pattern. Use this tool when you need to find text or code inside files rather than matching file or directory names.";
152
+ readonly params: {
153
+ readonly path: "(required) The absolute or relative directory path to search.";
154
+ readonly regex: "(required) The regex pattern to match file content against.";
155
+ readonly file_pattern: "(optional) glob pattern like *.ts to limit which files are searched.";
156
+ readonly include_node_modules: "(optional) set to true to include node_modules in the search. Defaults to false, so node_modules is skipped.";
145
157
  };
146
158
  }, {
147
159
  readonly name: AgentDefaultTool.LIST_FILES;
@@ -166,7 +178,7 @@ declare const defaultTools: readonly [{
166
178
  declare const toolUseNames: AgentDefaultTool[];
167
179
  declare function setDynamicToolUseNames(namespace: string, names: string[]): void;
168
180
  declare function getToolUseNames(): string[];
169
- declare const READ_ONLY_TOOLS: readonly [AgentDefaultTool.LIST_FILES, AgentDefaultTool.FILE_READ, AgentDefaultTool.SEARCH, AgentDefaultTool.LIST_CODE_DEF, AgentDefaultTool.BROWSER, AgentDefaultTool.ASK, AgentDefaultTool.WEB_SEARCH, AgentDefaultTool.WEB_FETCH, AgentDefaultTool.LOAD_SKILL, AgentDefaultTool.USE_SUBAGENTS];
181
+ declare const READ_ONLY_TOOLS: readonly [AgentDefaultTool.LIST_FILES, AgentDefaultTool.FILE_READ, AgentDefaultTool.SEARCH, AgentDefaultTool.SEARCH_CONTENT, AgentDefaultTool.LIST_CODE_DEF, AgentDefaultTool.BROWSER, AgentDefaultTool.ASK, AgentDefaultTool.WEB_SEARCH, AgentDefaultTool.WEB_FETCH, AgentDefaultTool.LOAD_SKILL, AgentDefaultTool.USE_SUBAGENTS];
170
182
 
171
183
  /**
172
184
  * @description **Version 2**
@@ -198,7 +210,7 @@ interface TextStreamContent {
198
210
  content: string;
199
211
  partial: boolean;
200
212
  }
201
- declare const toolParamNames: readonly ["command", "requires_approval", "path", "absolutePath", "content", "diff", "regex", "file_pattern", "recursive", "action", "url", "coordinate", "text", "query", "allowed_domains", "blocked_domains", "prompt", "server_name", "tool_name", "arguments", "uri", "question", "options", "response", "result", "context", "title", "what_happened", "steps_to_reproduce", "api_request_output", "additional_context", "needs_more_exploration", "task_progress", "timeout", "input", "from_ref", "to_ref", "skill_name", "prompt_1", "prompt_2", "prompt_3", "prompt_4", "prompt_5", "start_line", "end_line"];
213
+ declare const toolParamNames: readonly ["command", "requires_approval", "path", "absolutePath", "content", "diff", "regex", "file_pattern", "include_node_modules", "recursive", "action", "url", "coordinate", "text", "query", "allowed_domains", "blocked_domains", "prompt", "server_name", "tool_name", "arguments", "uri", "question", "options", "response", "result", "context", "title", "what_happened", "steps_to_reproduce", "api_request_output", "additional_context", "needs_more_exploration", "task_progress", "timeout", "input", "from_ref", "to_ref", "skill_name", "prompt_1", "prompt_2", "prompt_3", "prompt_4", "prompt_5", "start_line", "end_line"];
202
214
  type ToolParamName = (typeof toolParamNames)[number];
203
215
  interface ToolUse {
204
216
  type: "tool_use";
@@ -269,6 +281,10 @@ interface IPromptManager {
269
281
  * 获取未使用工具的错误提示词
270
282
  */
271
283
  getNoUseToolInstructions(context: any): string;
284
+ /**
285
+ * 工具调用后,提醒继续完成任务
286
+ */
287
+ getUsedToolResultInstructions(): string;
272
288
  }
273
289
 
274
290
  /**
@@ -480,6 +496,19 @@ declare class ClineAgent {
480
496
  resume(userInput?: string): Promise<void>;
481
497
  appendHistory(history: AgentMessage[]): Promise<void>;
482
498
  getHistory(): Promise<AgentMessage[]>;
499
+ /**
500
+ * 判断文件是否为可进行内容搜索的文本类文件
501
+ */
502
+ private isTextFile;
503
+ /**
504
+ * 按文件名/目录名搜索,层级优先(BFS):
505
+ * 每一层先匹配完当前层级的所有条目,再进入更深的子目录。
506
+ */
507
+ searchFiles(dirpath: string, regex: string, filePattern?: string, includeNodeModules?: boolean): Promise<string>;
508
+ /**
509
+ * 按文件内容搜索:正则匹配文件内容,返回匹配文件路径。
510
+ */
511
+ searchFileContent(dirpath: string, regex: string, filePattern?: string, includeNodeModules?: boolean): Promise<string>;
483
512
  }
484
513
 
485
514
  declare const VERSION = "0.1.0";
package/dist/index.d.ts CHANGED
@@ -7,12 +7,12 @@ interface IAgentRuntime {
7
7
  * 文件系统相关操作
8
8
  */
9
9
  fs: {
10
- readFile(path: string): Promise<string>;
10
+ readFile(path: string, options?: any): Promise<any>;
11
11
  writeFile(path: string, content: string): Promise<void>;
12
12
  deleteFile(path: string): Promise<void>;
13
13
  deleteDirectory(path: string): Promise<void>;
14
14
  fileExists(path: string): Promise<boolean>;
15
- readDir(path: string): Promise<any[]>;
15
+ readDir(path: string, options?: any): Promise<any[]>;
16
16
  mkdir(path: string): Promise<void>;
17
17
  /**
18
18
  * 跨文件正则搜索
@@ -21,7 +21,8 @@ interface IAgentRuntime {
21
21
  * @param filePattern (可选) 文件名匹配模式,比如 '*.ts'
22
22
  * @returns 返回格式化后的包含上下文的搜索结果字符串
23
23
  */
24
- searchFiles?(path: string, regex: string, filePattern?: string): Promise<string>;
24
+ searchFiles?(path: string, regex: string, filePattern?: string, includeNodeModules?: boolean): Promise<string>;
25
+ searchFileContent?(path: string, regex: string, filePattern?: string, includeNodeModules?: boolean): Promise<string>;
25
26
  };
26
27
  path: {
27
28
  join(...paths: string[]): string;
@@ -59,6 +60,7 @@ declare enum AgentDefaultTool {
59
60
  FILE_DELETE = "agent_delete_file",
60
61
  DIR_DELETE = "agent_delete_directory",
61
62
  SEARCH = "agent_search_files",
63
+ SEARCH_CONTENT = "agent_search_file_content",
62
64
  LIST_FILES = "agent_list_files",
63
65
  LIST_CODE_DEF = "agent_list_code_definition_names",
64
66
  BROWSER = "agent_browser_action",
@@ -137,11 +139,21 @@ declare const defaultTools: readonly [{
137
139
  };
138
140
  }, {
139
141
  readonly name: AgentDefaultTool.SEARCH;
140
- readonly description: "Search for files in a directory that match a regex pattern or glob pattern.";
142
+ readonly description: "Search for files or directories by name in a directory tree, matching the name against a regex (and optionally a glob). Directories are traversed level by level: all matches in the current level are returned before descending into deeper levels. Use this tool only to locate files/directories by name.";
141
143
  readonly params: {
142
144
  readonly path: "(required) The absolute or relative directory path to search.";
143
- readonly regex: "(required) The regex pattern to match files against.";
145
+ readonly regex: "(required) The regex pattern to match file or directory names against.";
144
146
  readonly file_pattern: "(optional) glob pattern like *.ts.";
147
+ readonly include_node_modules: "(optional) set to true to include node_modules in the search. Defaults to false, so node_modules is skipped.";
148
+ };
149
+ }, {
150
+ readonly name: AgentDefaultTool.SEARCH_CONTENT;
151
+ readonly description: "Search the contents of files in a directory tree for a regex pattern. Use this tool when you need to find text or code inside files rather than matching file or directory names.";
152
+ readonly params: {
153
+ readonly path: "(required) The absolute or relative directory path to search.";
154
+ readonly regex: "(required) The regex pattern to match file content against.";
155
+ readonly file_pattern: "(optional) glob pattern like *.ts to limit which files are searched.";
156
+ readonly include_node_modules: "(optional) set to true to include node_modules in the search. Defaults to false, so node_modules is skipped.";
145
157
  };
146
158
  }, {
147
159
  readonly name: AgentDefaultTool.LIST_FILES;
@@ -166,7 +178,7 @@ declare const defaultTools: readonly [{
166
178
  declare const toolUseNames: AgentDefaultTool[];
167
179
  declare function setDynamicToolUseNames(namespace: string, names: string[]): void;
168
180
  declare function getToolUseNames(): string[];
169
- declare const READ_ONLY_TOOLS: readonly [AgentDefaultTool.LIST_FILES, AgentDefaultTool.FILE_READ, AgentDefaultTool.SEARCH, AgentDefaultTool.LIST_CODE_DEF, AgentDefaultTool.BROWSER, AgentDefaultTool.ASK, AgentDefaultTool.WEB_SEARCH, AgentDefaultTool.WEB_FETCH, AgentDefaultTool.LOAD_SKILL, AgentDefaultTool.USE_SUBAGENTS];
181
+ declare const READ_ONLY_TOOLS: readonly [AgentDefaultTool.LIST_FILES, AgentDefaultTool.FILE_READ, AgentDefaultTool.SEARCH, AgentDefaultTool.SEARCH_CONTENT, AgentDefaultTool.LIST_CODE_DEF, AgentDefaultTool.BROWSER, AgentDefaultTool.ASK, AgentDefaultTool.WEB_SEARCH, AgentDefaultTool.WEB_FETCH, AgentDefaultTool.LOAD_SKILL, AgentDefaultTool.USE_SUBAGENTS];
170
182
 
171
183
  /**
172
184
  * @description **Version 2**
@@ -198,7 +210,7 @@ interface TextStreamContent {
198
210
  content: string;
199
211
  partial: boolean;
200
212
  }
201
- declare const toolParamNames: readonly ["command", "requires_approval", "path", "absolutePath", "content", "diff", "regex", "file_pattern", "recursive", "action", "url", "coordinate", "text", "query", "allowed_domains", "blocked_domains", "prompt", "server_name", "tool_name", "arguments", "uri", "question", "options", "response", "result", "context", "title", "what_happened", "steps_to_reproduce", "api_request_output", "additional_context", "needs_more_exploration", "task_progress", "timeout", "input", "from_ref", "to_ref", "skill_name", "prompt_1", "prompt_2", "prompt_3", "prompt_4", "prompt_5", "start_line", "end_line"];
213
+ declare const toolParamNames: readonly ["command", "requires_approval", "path", "absolutePath", "content", "diff", "regex", "file_pattern", "include_node_modules", "recursive", "action", "url", "coordinate", "text", "query", "allowed_domains", "blocked_domains", "prompt", "server_name", "tool_name", "arguments", "uri", "question", "options", "response", "result", "context", "title", "what_happened", "steps_to_reproduce", "api_request_output", "additional_context", "needs_more_exploration", "task_progress", "timeout", "input", "from_ref", "to_ref", "skill_name", "prompt_1", "prompt_2", "prompt_3", "prompt_4", "prompt_5", "start_line", "end_line"];
202
214
  type ToolParamName = (typeof toolParamNames)[number];
203
215
  interface ToolUse {
204
216
  type: "tool_use";
@@ -269,6 +281,10 @@ interface IPromptManager {
269
281
  * 获取未使用工具的错误提示词
270
282
  */
271
283
  getNoUseToolInstructions(context: any): string;
284
+ /**
285
+ * 工具调用后,提醒继续完成任务
286
+ */
287
+ getUsedToolResultInstructions(): string;
272
288
  }
273
289
 
274
290
  /**
@@ -480,6 +496,19 @@ declare class ClineAgent {
480
496
  resume(userInput?: string): Promise<void>;
481
497
  appendHistory(history: AgentMessage[]): Promise<void>;
482
498
  getHistory(): Promise<AgentMessage[]>;
499
+ /**
500
+ * 判断文件是否为可进行内容搜索的文本类文件
501
+ */
502
+ private isTextFile;
503
+ /**
504
+ * 按文件名/目录名搜索,层级优先(BFS):
505
+ * 每一层先匹配完当前层级的所有条目,再进入更深的子目录。
506
+ */
507
+ searchFiles(dirpath: string, regex: string, filePattern?: string, includeNodeModules?: boolean): Promise<string>;
508
+ /**
509
+ * 按文件内容搜索:正则匹配文件内容,返回匹配文件路径。
510
+ */
511
+ searchFileContent(dirpath: string, regex: string, filePattern?: string, includeNodeModules?: boolean): Promise<string>;
483
512
  }
484
513
 
485
514
  declare const VERSION = "0.1.0";
package/dist/index.js CHANGED
@@ -18,6 +18,7 @@ var AgentDefaultTool = /* @__PURE__ */ ((AgentDefaultTool2) => {
18
18
  AgentDefaultTool2["FILE_DELETE"] = "agent_delete_file";
19
19
  AgentDefaultTool2["DIR_DELETE"] = "agent_delete_directory";
20
20
  AgentDefaultTool2["SEARCH"] = "agent_search_files";
21
+ AgentDefaultTool2["SEARCH_CONTENT"] = "agent_search_file_content";
21
22
  AgentDefaultTool2["LIST_FILES"] = "agent_list_files";
22
23
  AgentDefaultTool2["LIST_CODE_DEF"] = "agent_list_code_definition_names";
23
24
  AgentDefaultTool2["BROWSER"] = "agent_browser_action";
@@ -191,11 +192,22 @@ return (
191
192
  },
192
193
  {
193
194
  name: "agent_search_files" /* SEARCH */,
194
- description: "Search for files in a directory that match a regex pattern or glob pattern.",
195
+ description: "Search for files or directories by name in a directory tree, matching the name against a regex (and optionally a glob). Directories are traversed level by level: all matches in the current level are returned before descending into deeper levels. Use this tool only to locate files/directories by name.",
195
196
  params: {
196
197
  path: "(required) The absolute or relative directory path to search.",
197
- regex: "(required) The regex pattern to match files against.",
198
- file_pattern: "(optional) glob pattern like *.ts."
198
+ regex: "(required) The regex pattern to match file or directory names against.",
199
+ file_pattern: "(optional) glob pattern like *.ts.",
200
+ include_node_modules: "(optional) set to true to include node_modules in the search. Defaults to false, so node_modules is skipped."
201
+ }
202
+ },
203
+ {
204
+ name: "agent_search_file_content" /* SEARCH_CONTENT */,
205
+ description: "Search the contents of files in a directory tree for a regex pattern. Use this tool when you need to find text or code inside files rather than matching file or directory names.",
206
+ params: {
207
+ path: "(required) The absolute or relative directory path to search.",
208
+ regex: "(required) The regex pattern to match file content against.",
209
+ file_pattern: "(optional) glob pattern like *.ts to limit which files are searched.",
210
+ include_node_modules: "(optional) set to true to include node_modules in the search. Defaults to false, so node_modules is skipped."
199
211
  }
200
212
  },
201
213
  {
@@ -264,6 +276,7 @@ var READ_ONLY_TOOLS = [
264
276
  "agent_list_files" /* LIST_FILES */,
265
277
  "agent_read_file" /* FILE_READ */,
266
278
  "agent_search_files" /* SEARCH */,
279
+ "agent_search_file_content" /* SEARCH_CONTENT */,
267
280
  "agent_list_code_definition_names" /* LIST_CODE_DEF */,
268
281
  "agent_browser_action" /* BROWSER */,
269
282
  "agent_ask_followup_question" /* ASK */,
@@ -433,6 +446,7 @@ var toolParamNames = [
433
446
  "diff",
434
447
  "regex",
435
448
  "file_pattern",
449
+ "include_node_modules",
436
450
  "recursive",
437
451
  "action",
438
452
  "url",
@@ -471,6 +485,66 @@ var toolParamNames = [
471
485
  "start_line",
472
486
  "end_line"
473
487
  ];
488
+ var TEXT_FILE_EXTENSIONS = /* @__PURE__ */ new Set([
489
+ "txt",
490
+ "md",
491
+ "markdown",
492
+ "json",
493
+ "js",
494
+ "mjs",
495
+ "cjs",
496
+ "ts",
497
+ "tsx",
498
+ "jsx",
499
+ "html",
500
+ "htm",
501
+ "css",
502
+ "scss",
503
+ "sass",
504
+ "less",
505
+ "py",
506
+ "java",
507
+ "c",
508
+ "cpp",
509
+ "cc",
510
+ "cxx",
511
+ "h",
512
+ "hpp",
513
+ "cs",
514
+ "go",
515
+ "rs",
516
+ "rb",
517
+ "php",
518
+ "sh",
519
+ "bash",
520
+ "zsh",
521
+ "bat",
522
+ "cmd",
523
+ "ps1",
524
+ "yaml",
525
+ "yml",
526
+ "toml",
527
+ "ini",
528
+ "cfg",
529
+ "conf",
530
+ "xml",
531
+ "svg",
532
+ "csv",
533
+ "log",
534
+ "sql",
535
+ "vue",
536
+ "svelte",
537
+ "astro",
538
+ "graphql",
539
+ "gql",
540
+ "prisma",
541
+ "env",
542
+ "gitignore",
543
+ "dockerfile",
544
+ "makefile",
545
+ "properties",
546
+ "lock"
547
+ ]);
474
548
  var AgentState = /* @__PURE__ */ ((AgentState2) => {
475
549
  AgentState2["IDLE"] = "idle";
476
550
  AgentState2["THINKING"] = "thinking";
@@ -551,7 +625,7 @@ var ClineAgent = class {
551
625
  }
552
626
  }
553
627
  /**
554
- * 获取当前 Agent 的系统提示词
628
+ * 获取当前 Agent 的系统提示词
555
629
  * 如果 force 为 true,则强制重新获取系统提示词
556
630
  */
557
631
  async getPrompt(force = false) {
@@ -826,15 +900,41 @@ STDERR: ${result.stderr}` });
826
900
  const path = tool.params.path || this.runtime.env.cwd();
827
901
  const regexStr = tool.params.regex;
828
902
  const filePattern = tool.params.file_pattern;
829
- if (regexStr && this.runtime.fs.searchFiles) {
903
+ const includeNodeModules = tool.params.include_node_modules === "true";
904
+ if (regexStr && path) {
830
905
  try {
831
- const result = await this.runtime.fs.searchFiles(path, regexStr, filePattern);
832
- toolResults.push({ tool, result: `${result}` });
906
+ let result;
907
+ if (typeof this.runtime.fs.searchFiles === "function") {
908
+ result = await this.runtime.fs.searchFiles(path, regexStr, filePattern);
909
+ } else {
910
+ result = await this.searchFiles(path, regexStr, filePattern, includeNodeModules);
911
+ }
912
+ toolResults.push({ tool, result });
833
913
  } catch (e) {
834
914
  toolResults.push({ tool, result: `Error: ${e.message}` });
835
915
  }
836
916
  } else {
837
- toolResults.push({ tool, result: `Error: searchFiles not supported by runtime or missing regex.` });
917
+ toolResults.push({ tool, result: `Error: miss path or regex params` });
918
+ }
919
+ } else if (tool.name === "agent_search_file_content" /* SEARCH_CONTENT */) {
920
+ const path = tool.params.path || this.runtime.env.cwd();
921
+ const regexStr = tool.params.regex;
922
+ const filePattern = tool.params.file_pattern;
923
+ const includeNodeModules = tool.params.include_node_modules === "true";
924
+ if (regexStr && path) {
925
+ try {
926
+ let result;
927
+ if (typeof this.runtime.fs.searchFileContent === "function") {
928
+ result = await this.runtime.fs.searchFileContent(path, regexStr, filePattern);
929
+ } else {
930
+ result = await this.searchFileContent(path, regexStr, filePattern, includeNodeModules);
931
+ }
932
+ toolResults.push({ tool, result });
933
+ } catch (e) {
934
+ toolResults.push({ tool, result: `Error: ${e.message}` });
935
+ }
936
+ } else {
937
+ toolResults.push({ tool, result: `Error: miss path or regex params` });
838
938
  }
839
939
  } else if (tool.name === "agent_use_mcp_tool" /* MCP_USE */) {
840
940
  const serverName = tool.params.server_name;
@@ -939,9 +1039,14 @@ IMPORTANT: The skill is now loaded. Do NOT call agent_load_skill again for this
939
1039
  }
940
1040
  }
941
1041
  if (this.state === "thinking" /* THINKING */ && toolResults.length > 0) {
942
- const toolResultsContext = toolResults.map((tr) => `<${TOOL_RESULT_BLOCK} tool_name="${tr.tool.name}">
1042
+ let toolResultsContext = toolResults.map((tr) => `<${TOOL_RESULT_BLOCK} tool_name="${tr.tool.name}">
943
1043
  ${typeof tr.result === "string" ? tr.result.trim() : JSON.stringify(tr.result)}
944
1044
  </${TOOL_RESULT_BLOCK}>`).join("\n\n");
1045
+ const lastResult = toolResults[toolResults.length - 1];
1046
+ if (lastResult && lastResult.tool.name !== "agent_attempt_completion" /* ATTEMPT */) {
1047
+ toolResultsContext += `
1048
+ ${this.promptManager.getUsedToolResultInstructions()}`;
1049
+ }
945
1050
  if (this.onStreamChunk) {
946
1051
  this.onStreamChunk({ type: "text", text: toolResultsContext });
947
1052
  }
@@ -999,6 +1104,120 @@ ${searchBlock.substring(0, 100)}...`);
999
1104
  async getHistory() {
1000
1105
  return this.memory.getHistory();
1001
1106
  }
1107
+ /**
1108
+ * 判断文件是否为可进行内容搜索的文本类文件
1109
+ */
1110
+ isTextFile(name) {
1111
+ const ext = name.includes(".") ? String(name.split(".").pop()).toLowerCase() : "";
1112
+ if (!ext) {
1113
+ return true;
1114
+ }
1115
+ return TEXT_FILE_EXTENSIONS.has(ext);
1116
+ }
1117
+ /**
1118
+ * 按文件名/目录名搜索,层级优先(BFS):
1119
+ * 每一层先匹配完当前层级的所有条目,再进入更深的子目录。
1120
+ */
1121
+ async searchFiles(dirpath, regex, filePattern, includeNodeModules = false) {
1122
+ const matches = [];
1123
+ const MAX_RESULTS = 100;
1124
+ const MAX_DEPTH = 8;
1125
+ const SKIP_DIRS = /* @__PURE__ */ new Set([".git", "dist", ".agent", ".turbopack"]);
1126
+ const shouldSkipDir = (name) => SKIP_DIRS.has(name) || name === "node_modules" && !includeNodeModules;
1127
+ const nameRe = new RegExp(regex);
1128
+ const globRe = filePattern ? new RegExp(filePattern.replace(/\./g, "\\.").replace(/\*/g, ".*")) : null;
1129
+ const queue = [{ dir: dirpath, depth: 0 }];
1130
+ while (queue.length > 0 && matches.length < MAX_RESULTS) {
1131
+ const { dir, depth } = queue.shift();
1132
+ if (depth > MAX_DEPTH) {
1133
+ continue;
1134
+ }
1135
+ let entries;
1136
+ try {
1137
+ entries = await this.runtime.fs.readDir(dir, { recursive: false });
1138
+ } catch {
1139
+ continue;
1140
+ }
1141
+ for (const entry of entries) {
1142
+ if (matches.length >= MAX_RESULTS) {
1143
+ break;
1144
+ }
1145
+ const child = dir === "." ? entry.name : `${dir}/${entry.name}`;
1146
+ if (entry.isDirectory()) {
1147
+ if (!shouldSkipDir(entry.name)) {
1148
+ if (nameRe.test(entry.name)) {
1149
+ matches.push(`${child}/`);
1150
+ }
1151
+ queue.push({ dir: child, depth: depth + 1 });
1152
+ }
1153
+ } else if (entry.isFile()) {
1154
+ if (globRe && !globRe.test(entry.name)) {
1155
+ continue;
1156
+ }
1157
+ if (nameRe.test(entry.name)) {
1158
+ matches.push(child);
1159
+ }
1160
+ }
1161
+ }
1162
+ }
1163
+ if (matches.length === 0) {
1164
+ return "No files found.";
1165
+ }
1166
+ return matches.join("\n");
1167
+ }
1168
+ /**
1169
+ * 按文件内容搜索:正则匹配文件内容,返回匹配文件路径。
1170
+ */
1171
+ async searchFileContent(dirpath, regex, filePattern, includeNodeModules = false) {
1172
+ const matches = [];
1173
+ const MAX_RESULTS = 100;
1174
+ const MAX_DEPTH = 8;
1175
+ const SKIP_DIRS = /* @__PURE__ */ new Set([".git", "dist", ".agent", ".turbopack"]);
1176
+ const shouldSkipDir = (name) => SKIP_DIRS.has(name) || name === "node_modules" && !includeNodeModules;
1177
+ const contentRe = new RegExp(regex);
1178
+ const globRe = filePattern ? new RegExp(filePattern.replace(/\./g, "\\.").replace(/\*/g, ".*")) : null;
1179
+ const walk = async (dir, depth) => {
1180
+ if (depth > MAX_DEPTH || matches.length >= MAX_RESULTS) {
1181
+ return;
1182
+ }
1183
+ let entries;
1184
+ try {
1185
+ entries = await this.runtime.fs.readDir(dir, { recursive: false });
1186
+ } catch {
1187
+ return;
1188
+ }
1189
+ for (const entry of entries) {
1190
+ if (matches.length >= MAX_RESULTS) {
1191
+ break;
1192
+ }
1193
+ const child = dir === "." ? entry.name : `${dir}/${entry.name}`;
1194
+ if (entry.isDirectory()) {
1195
+ if (!shouldSkipDir(entry.name)) {
1196
+ await walk(child, depth + 1);
1197
+ }
1198
+ } else if (entry.isFile()) {
1199
+ if (!this.isTextFile(entry.name)) {
1200
+ continue;
1201
+ }
1202
+ if (globRe && !globRe.test(entry.name)) {
1203
+ continue;
1204
+ }
1205
+ try {
1206
+ const content = await this.runtime.fs.readFile(child);
1207
+ if (typeof content === "string" && contentRe.test(content)) {
1208
+ matches.push(child);
1209
+ }
1210
+ } catch {
1211
+ }
1212
+ }
1213
+ }
1214
+ };
1215
+ await walk(dirpath, 0);
1216
+ if (matches.length === 0) {
1217
+ return "No files found with matching content.";
1218
+ }
1219
+ return matches.join("\n");
1220
+ }
1002
1221
  };
1003
1222
 
1004
1223
  // src/index.ts