@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 +36 -7
- package/dist/index.d.ts +36 -7
- package/dist/index.js +228 -9
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +228 -9
- package/dist/index.mjs.map +1 -1
- package/dist/runtime/nodeRuntime.d.mts +3 -3
- package/dist/runtime/nodeRuntime.d.ts +3 -3
- package/dist/runtime/nodeRuntime.js +256 -19
- package/dist/runtime/nodeRuntime.js.map +1 -1
- package/dist/runtime/nodeRuntime.mjs +255 -18
- package/dist/runtime/nodeRuntime.mjs.map +1 -1
- package/dist/runtime/webRuntime.d.mts +3 -2
- package/dist/runtime/webRuntime.d.ts +3 -2
- package/dist/runtime/webRuntime.js +247 -13
- package/dist/runtime/webRuntime.js.map +1 -1
- package/dist/runtime/webRuntime.mjs +247 -13
- package/dist/runtime/webRuntime.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -47,6 +47,7 @@ declare class WebPromptManager implements IPromptManager {
|
|
|
47
47
|
customTools?: any[];
|
|
48
48
|
}): string;
|
|
49
49
|
getNoUseToolInstructions(context: any): string;
|
|
50
|
+
getUsedToolResultInstructions(): string;
|
|
50
51
|
}
|
|
51
52
|
|
|
52
53
|
declare class WebMcpManager implements IMcpManager {
|
|
@@ -66,12 +67,12 @@ declare class DefaultWebRuntime implements IAgentRuntime {
|
|
|
66
67
|
private vol;
|
|
67
68
|
private memfs;
|
|
68
69
|
fs: {
|
|
69
|
-
readFile: (filepath: string) => Promise<string>;
|
|
70
|
+
readFile: (filepath: string, options?: any) => Promise<string>;
|
|
70
71
|
writeFile: (filepath: string, content: string) => Promise<void>;
|
|
71
72
|
deleteFile: (filepath: string) => Promise<void>;
|
|
72
73
|
deleteDirectory: (dirpath: string) => Promise<void>;
|
|
73
74
|
fileExists: (filepath: string) => Promise<boolean>;
|
|
74
|
-
readDir: (dirpath: string) => any;
|
|
75
|
+
readDir: (dirpath: string, options: any) => any;
|
|
75
76
|
mkdir: (dirpath: string) => Promise<void>;
|
|
76
77
|
};
|
|
77
78
|
path: {
|
|
@@ -47,6 +47,7 @@ declare class WebPromptManager implements IPromptManager {
|
|
|
47
47
|
customTools?: any[];
|
|
48
48
|
}): string;
|
|
49
49
|
getNoUseToolInstructions(context: any): string;
|
|
50
|
+
getUsedToolResultInstructions(): string;
|
|
50
51
|
}
|
|
51
52
|
|
|
52
53
|
declare class WebMcpManager implements IMcpManager {
|
|
@@ -66,12 +67,12 @@ declare class DefaultWebRuntime implements IAgentRuntime {
|
|
|
66
67
|
private vol;
|
|
67
68
|
private memfs;
|
|
68
69
|
fs: {
|
|
69
|
-
readFile: (filepath: string) => Promise<string>;
|
|
70
|
+
readFile: (filepath: string, options?: any) => Promise<string>;
|
|
70
71
|
writeFile: (filepath: string, content: string) => Promise<void>;
|
|
71
72
|
deleteFile: (filepath: string) => Promise<void>;
|
|
72
73
|
deleteDirectory: (dirpath: string) => Promise<void>;
|
|
73
74
|
fileExists: (filepath: string) => Promise<boolean>;
|
|
74
|
-
readDir: (dirpath: string) => any;
|
|
75
|
+
readDir: (dirpath: string, options: any) => any;
|
|
75
76
|
mkdir: (dirpath: string) => Promise<void>;
|
|
76
77
|
};
|
|
77
78
|
path: {
|
|
@@ -24,6 +24,7 @@ var AgentDefaultTool = /* @__PURE__ */ ((AgentDefaultTool2) => {
|
|
|
24
24
|
AgentDefaultTool2["FILE_DELETE"] = "agent_delete_file";
|
|
25
25
|
AgentDefaultTool2["DIR_DELETE"] = "agent_delete_directory";
|
|
26
26
|
AgentDefaultTool2["SEARCH"] = "agent_search_files";
|
|
27
|
+
AgentDefaultTool2["SEARCH_CONTENT"] = "agent_search_file_content";
|
|
27
28
|
AgentDefaultTool2["LIST_FILES"] = "agent_list_files";
|
|
28
29
|
AgentDefaultTool2["LIST_CODE_DEF"] = "agent_list_code_definition_names";
|
|
29
30
|
AgentDefaultTool2["BROWSER"] = "agent_browser_action";
|
|
@@ -197,11 +198,22 @@ return (
|
|
|
197
198
|
},
|
|
198
199
|
{
|
|
199
200
|
name: "agent_search_files" /* SEARCH */,
|
|
200
|
-
description: "Search for files in a directory
|
|
201
|
+
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.",
|
|
201
202
|
params: {
|
|
202
203
|
path: "(required) The absolute or relative directory path to search.",
|
|
203
|
-
regex: "(required) The regex pattern to match
|
|
204
|
-
file_pattern: "(optional) glob pattern like *.ts."
|
|
204
|
+
regex: "(required) The regex pattern to match file or directory names against.",
|
|
205
|
+
file_pattern: "(optional) glob pattern like *.ts.",
|
|
206
|
+
include_node_modules: "(optional) set to true to include node_modules in the search. Defaults to false, so node_modules is skipped."
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
name: "agent_search_file_content" /* SEARCH_CONTENT */,
|
|
211
|
+
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.",
|
|
212
|
+
params: {
|
|
213
|
+
path: "(required) The absolute or relative directory path to search.",
|
|
214
|
+
regex: "(required) The regex pattern to match file content against.",
|
|
215
|
+
file_pattern: "(optional) glob pattern like *.ts to limit which files are searched.",
|
|
216
|
+
include_node_modules: "(optional) set to true to include node_modules in the search. Defaults to false, so node_modules is skipped."
|
|
205
217
|
}
|
|
206
218
|
},
|
|
207
219
|
{
|
|
@@ -270,6 +282,7 @@ var READ_ONLY_TOOLS = [
|
|
|
270
282
|
"agent_list_files" /* LIST_FILES */,
|
|
271
283
|
"agent_read_file" /* FILE_READ */,
|
|
272
284
|
"agent_search_files" /* SEARCH */,
|
|
285
|
+
"agent_search_file_content" /* SEARCH_CONTENT */,
|
|
273
286
|
"agent_list_code_definition_names" /* LIST_CODE_DEF */,
|
|
274
287
|
"agent_browser_action" /* BROWSER */,
|
|
275
288
|
"agent_ask_followup_question" /* ASK */,
|
|
@@ -439,6 +452,7 @@ var toolParamNames = [
|
|
|
439
452
|
"diff",
|
|
440
453
|
"regex",
|
|
441
454
|
"file_pattern",
|
|
455
|
+
"include_node_modules",
|
|
442
456
|
"recursive",
|
|
443
457
|
"action",
|
|
444
458
|
"url",
|
|
@@ -477,6 +491,66 @@ var toolParamNames = [
|
|
|
477
491
|
"start_line",
|
|
478
492
|
"end_line"
|
|
479
493
|
];
|
|
494
|
+
var TEXT_FILE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
495
|
+
"txt",
|
|
496
|
+
"md",
|
|
497
|
+
"markdown",
|
|
498
|
+
"json",
|
|
499
|
+
"js",
|
|
500
|
+
"mjs",
|
|
501
|
+
"cjs",
|
|
502
|
+
"ts",
|
|
503
|
+
"tsx",
|
|
504
|
+
"jsx",
|
|
505
|
+
"html",
|
|
506
|
+
"htm",
|
|
507
|
+
"css",
|
|
508
|
+
"scss",
|
|
509
|
+
"sass",
|
|
510
|
+
"less",
|
|
511
|
+
"py",
|
|
512
|
+
"java",
|
|
513
|
+
"c",
|
|
514
|
+
"cpp",
|
|
515
|
+
"cc",
|
|
516
|
+
"cxx",
|
|
517
|
+
"h",
|
|
518
|
+
"hpp",
|
|
519
|
+
"cs",
|
|
520
|
+
"go",
|
|
521
|
+
"rs",
|
|
522
|
+
"rb",
|
|
523
|
+
"php",
|
|
524
|
+
"sh",
|
|
525
|
+
"bash",
|
|
526
|
+
"zsh",
|
|
527
|
+
"bat",
|
|
528
|
+
"cmd",
|
|
529
|
+
"ps1",
|
|
530
|
+
"yaml",
|
|
531
|
+
"yml",
|
|
532
|
+
"toml",
|
|
533
|
+
"ini",
|
|
534
|
+
"cfg",
|
|
535
|
+
"conf",
|
|
536
|
+
"xml",
|
|
537
|
+
"svg",
|
|
538
|
+
"csv",
|
|
539
|
+
"log",
|
|
540
|
+
"sql",
|
|
541
|
+
"vue",
|
|
542
|
+
"svelte",
|
|
543
|
+
"astro",
|
|
544
|
+
"graphql",
|
|
545
|
+
"gql",
|
|
546
|
+
"prisma",
|
|
547
|
+
"env",
|
|
548
|
+
"gitignore",
|
|
549
|
+
"dockerfile",
|
|
550
|
+
"makefile",
|
|
551
|
+
"properties",
|
|
552
|
+
"lock"
|
|
553
|
+
]);
|
|
480
554
|
var AgentState = /* @__PURE__ */ ((AgentState2) => {
|
|
481
555
|
AgentState2["IDLE"] = "idle";
|
|
482
556
|
AgentState2["THINKING"] = "thinking";
|
|
@@ -557,7 +631,7 @@ var ClineAgent = class {
|
|
|
557
631
|
}
|
|
558
632
|
}
|
|
559
633
|
/**
|
|
560
|
-
* 获取当前 Agent 的系统提示词
|
|
634
|
+
* 获取当前 Agent 的系统提示词
|
|
561
635
|
* 如果 force 为 true,则强制重新获取系统提示词
|
|
562
636
|
*/
|
|
563
637
|
async getPrompt(force = false) {
|
|
@@ -832,15 +906,41 @@ STDERR: ${result.stderr}` });
|
|
|
832
906
|
const path2 = tool.params.path || this.runtime.env.cwd();
|
|
833
907
|
const regexStr = tool.params.regex;
|
|
834
908
|
const filePattern = tool.params.file_pattern;
|
|
835
|
-
|
|
909
|
+
const includeNodeModules = tool.params.include_node_modules === "true";
|
|
910
|
+
if (regexStr && path2) {
|
|
836
911
|
try {
|
|
837
|
-
|
|
838
|
-
|
|
912
|
+
let result;
|
|
913
|
+
if (typeof this.runtime.fs.searchFiles === "function") {
|
|
914
|
+
result = await this.runtime.fs.searchFiles(path2, regexStr, filePattern);
|
|
915
|
+
} else {
|
|
916
|
+
result = await this.searchFiles(path2, regexStr, filePattern, includeNodeModules);
|
|
917
|
+
}
|
|
918
|
+
toolResults.push({ tool, result });
|
|
839
919
|
} catch (e) {
|
|
840
920
|
toolResults.push({ tool, result: `Error: ${e.message}` });
|
|
841
921
|
}
|
|
842
922
|
} else {
|
|
843
|
-
toolResults.push({ tool, result: `Error:
|
|
923
|
+
toolResults.push({ tool, result: `Error: miss path or regex params` });
|
|
924
|
+
}
|
|
925
|
+
} else if (tool.name === "agent_search_file_content" /* SEARCH_CONTENT */) {
|
|
926
|
+
const path2 = tool.params.path || this.runtime.env.cwd();
|
|
927
|
+
const regexStr = tool.params.regex;
|
|
928
|
+
const filePattern = tool.params.file_pattern;
|
|
929
|
+
const includeNodeModules = tool.params.include_node_modules === "true";
|
|
930
|
+
if (regexStr && path2) {
|
|
931
|
+
try {
|
|
932
|
+
let result;
|
|
933
|
+
if (typeof this.runtime.fs.searchFileContent === "function") {
|
|
934
|
+
result = await this.runtime.fs.searchFileContent(path2, regexStr, filePattern);
|
|
935
|
+
} else {
|
|
936
|
+
result = await this.searchFileContent(path2, regexStr, filePattern, includeNodeModules);
|
|
937
|
+
}
|
|
938
|
+
toolResults.push({ tool, result });
|
|
939
|
+
} catch (e) {
|
|
940
|
+
toolResults.push({ tool, result: `Error: ${e.message}` });
|
|
941
|
+
}
|
|
942
|
+
} else {
|
|
943
|
+
toolResults.push({ tool, result: `Error: miss path or regex params` });
|
|
844
944
|
}
|
|
845
945
|
} else if (tool.name === "agent_use_mcp_tool" /* MCP_USE */) {
|
|
846
946
|
const serverName = tool.params.server_name;
|
|
@@ -945,9 +1045,14 @@ IMPORTANT: The skill is now loaded. Do NOT call agent_load_skill again for this
|
|
|
945
1045
|
}
|
|
946
1046
|
}
|
|
947
1047
|
if (this.state === "thinking" /* THINKING */ && toolResults.length > 0) {
|
|
948
|
-
|
|
1048
|
+
let toolResultsContext = toolResults.map((tr) => `<${TOOL_RESULT_BLOCK} tool_name="${tr.tool.name}">
|
|
949
1049
|
${typeof tr.result === "string" ? tr.result.trim() : JSON.stringify(tr.result)}
|
|
950
1050
|
</${TOOL_RESULT_BLOCK}>`).join("\n\n");
|
|
1051
|
+
const lastResult = toolResults[toolResults.length - 1];
|
|
1052
|
+
if (lastResult && lastResult.tool.name !== "agent_attempt_completion" /* ATTEMPT */) {
|
|
1053
|
+
toolResultsContext += `
|
|
1054
|
+
${this.promptManager.getUsedToolResultInstructions()}`;
|
|
1055
|
+
}
|
|
951
1056
|
if (this.onStreamChunk) {
|
|
952
1057
|
this.onStreamChunk({ type: "text", text: toolResultsContext });
|
|
953
1058
|
}
|
|
@@ -1005,6 +1110,120 @@ ${searchBlock.substring(0, 100)}...`);
|
|
|
1005
1110
|
async getHistory() {
|
|
1006
1111
|
return this.memory.getHistory();
|
|
1007
1112
|
}
|
|
1113
|
+
/**
|
|
1114
|
+
* 判断文件是否为可进行内容搜索的文本类文件
|
|
1115
|
+
*/
|
|
1116
|
+
isTextFile(name) {
|
|
1117
|
+
const ext = name.includes(".") ? String(name.split(".").pop()).toLowerCase() : "";
|
|
1118
|
+
if (!ext) {
|
|
1119
|
+
return true;
|
|
1120
|
+
}
|
|
1121
|
+
return TEXT_FILE_EXTENSIONS.has(ext);
|
|
1122
|
+
}
|
|
1123
|
+
/**
|
|
1124
|
+
* 按文件名/目录名搜索,层级优先(BFS):
|
|
1125
|
+
* 每一层先匹配完当前层级的所有条目,再进入更深的子目录。
|
|
1126
|
+
*/
|
|
1127
|
+
async searchFiles(dirpath, regex, filePattern, includeNodeModules = false) {
|
|
1128
|
+
const matches = [];
|
|
1129
|
+
const MAX_RESULTS = 100;
|
|
1130
|
+
const MAX_DEPTH = 8;
|
|
1131
|
+
const SKIP_DIRS = /* @__PURE__ */ new Set([".git", "dist", ".agent", ".turbopack"]);
|
|
1132
|
+
const shouldSkipDir = (name) => SKIP_DIRS.has(name) || name === "node_modules" && !includeNodeModules;
|
|
1133
|
+
const nameRe = new RegExp(regex);
|
|
1134
|
+
const globRe = filePattern ? new RegExp(filePattern.replace(/\./g, "\\.").replace(/\*/g, ".*")) : null;
|
|
1135
|
+
const queue = [{ dir: dirpath, depth: 0 }];
|
|
1136
|
+
while (queue.length > 0 && matches.length < MAX_RESULTS) {
|
|
1137
|
+
const { dir, depth } = queue.shift();
|
|
1138
|
+
if (depth > MAX_DEPTH) {
|
|
1139
|
+
continue;
|
|
1140
|
+
}
|
|
1141
|
+
let entries;
|
|
1142
|
+
try {
|
|
1143
|
+
entries = await this.runtime.fs.readDir(dir, { recursive: false });
|
|
1144
|
+
} catch {
|
|
1145
|
+
continue;
|
|
1146
|
+
}
|
|
1147
|
+
for (const entry of entries) {
|
|
1148
|
+
if (matches.length >= MAX_RESULTS) {
|
|
1149
|
+
break;
|
|
1150
|
+
}
|
|
1151
|
+
const child = dir === "." ? entry.name : `${dir}/${entry.name}`;
|
|
1152
|
+
if (entry.isDirectory()) {
|
|
1153
|
+
if (!shouldSkipDir(entry.name)) {
|
|
1154
|
+
if (nameRe.test(entry.name)) {
|
|
1155
|
+
matches.push(`${child}/`);
|
|
1156
|
+
}
|
|
1157
|
+
queue.push({ dir: child, depth: depth + 1 });
|
|
1158
|
+
}
|
|
1159
|
+
} else if (entry.isFile()) {
|
|
1160
|
+
if (globRe && !globRe.test(entry.name)) {
|
|
1161
|
+
continue;
|
|
1162
|
+
}
|
|
1163
|
+
if (nameRe.test(entry.name)) {
|
|
1164
|
+
matches.push(child);
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
if (matches.length === 0) {
|
|
1170
|
+
return "No files found.";
|
|
1171
|
+
}
|
|
1172
|
+
return matches.join("\n");
|
|
1173
|
+
}
|
|
1174
|
+
/**
|
|
1175
|
+
* 按文件内容搜索:正则匹配文件内容,返回匹配文件路径。
|
|
1176
|
+
*/
|
|
1177
|
+
async searchFileContent(dirpath, regex, filePattern, includeNodeModules = false) {
|
|
1178
|
+
const matches = [];
|
|
1179
|
+
const MAX_RESULTS = 100;
|
|
1180
|
+
const MAX_DEPTH = 8;
|
|
1181
|
+
const SKIP_DIRS = /* @__PURE__ */ new Set([".git", "dist", ".agent", ".turbopack"]);
|
|
1182
|
+
const shouldSkipDir = (name) => SKIP_DIRS.has(name) || name === "node_modules" && !includeNodeModules;
|
|
1183
|
+
const contentRe = new RegExp(regex);
|
|
1184
|
+
const globRe = filePattern ? new RegExp(filePattern.replace(/\./g, "\\.").replace(/\*/g, ".*")) : null;
|
|
1185
|
+
const walk = async (dir, depth) => {
|
|
1186
|
+
if (depth > MAX_DEPTH || matches.length >= MAX_RESULTS) {
|
|
1187
|
+
return;
|
|
1188
|
+
}
|
|
1189
|
+
let entries;
|
|
1190
|
+
try {
|
|
1191
|
+
entries = await this.runtime.fs.readDir(dir, { recursive: false });
|
|
1192
|
+
} catch {
|
|
1193
|
+
return;
|
|
1194
|
+
}
|
|
1195
|
+
for (const entry of entries) {
|
|
1196
|
+
if (matches.length >= MAX_RESULTS) {
|
|
1197
|
+
break;
|
|
1198
|
+
}
|
|
1199
|
+
const child = dir === "." ? entry.name : `${dir}/${entry.name}`;
|
|
1200
|
+
if (entry.isDirectory()) {
|
|
1201
|
+
if (!shouldSkipDir(entry.name)) {
|
|
1202
|
+
await walk(child, depth + 1);
|
|
1203
|
+
}
|
|
1204
|
+
} else if (entry.isFile()) {
|
|
1205
|
+
if (!this.isTextFile(entry.name)) {
|
|
1206
|
+
continue;
|
|
1207
|
+
}
|
|
1208
|
+
if (globRe && !globRe.test(entry.name)) {
|
|
1209
|
+
continue;
|
|
1210
|
+
}
|
|
1211
|
+
try {
|
|
1212
|
+
const content = await this.runtime.fs.readFile(child);
|
|
1213
|
+
if (typeof content === "string" && contentRe.test(content)) {
|
|
1214
|
+
matches.push(child);
|
|
1215
|
+
}
|
|
1216
|
+
} catch {
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
};
|
|
1221
|
+
await walk(dirpath, 0);
|
|
1222
|
+
if (matches.length === 0) {
|
|
1223
|
+
return "No files found with matching content.";
|
|
1224
|
+
}
|
|
1225
|
+
return matches.join("\n");
|
|
1226
|
+
}
|
|
1008
1227
|
};
|
|
1009
1228
|
var WebApiHandler = class {
|
|
1010
1229
|
config;
|
|
@@ -1379,6 +1598,21 @@ Otherwise, if you have not completed the task and do not need additional informa
|
|
|
1379
1598
|
(This is an automated message, so do not respond to it conversationally.)
|
|
1380
1599
|
${this?.getEnvironmentInfoPrompt?.(context)}`;
|
|
1381
1600
|
}
|
|
1601
|
+
getUsedToolResultInstructions() {
|
|
1602
|
+
return `The above are the results of the tool call. Please continue to complete the remaining tasks.
|
|
1603
|
+
|
|
1604
|
+
# TODO LIST UPDATE REQUIRED - You MUST include the task_progress parameter in your NEXT tool call.
|
|
1605
|
+
|
|
1606
|
+
1. To create or update a todo list, include the task_progress parameter in the next tool call
|
|
1607
|
+
2. Review each item and update its status:
|
|
1608
|
+
- Mark completed items with: - [x]
|
|
1609
|
+
- Keep incomplete items as: - [ ]
|
|
1610
|
+
- Add new items if you discover additional steps
|
|
1611
|
+
3. Modify the list as needed:
|
|
1612
|
+
- Add any new steps you've discovered
|
|
1613
|
+
- Reorder if the sequence has changed
|
|
1614
|
+
4. Ensure the list accurately reflects the current state`;
|
|
1615
|
+
}
|
|
1382
1616
|
};
|
|
1383
1617
|
|
|
1384
1618
|
// src/memory/WebMemoryManager.ts
|
|
@@ -1484,8 +1718,8 @@ var DefaultWebRuntime = class {
|
|
|
1484
1718
|
vol = new memfs.Volume();
|
|
1485
1719
|
memfs = memfs.createFsFromVolume(this.vol).promises;
|
|
1486
1720
|
fs = {
|
|
1487
|
-
readFile: async (filepath) => {
|
|
1488
|
-
const content = await this.memfs.readFile(filepath,
|
|
1721
|
+
readFile: async (filepath, options = "utf8") => {
|
|
1722
|
+
const content = await this.memfs.readFile(filepath, options);
|
|
1489
1723
|
return content.toString();
|
|
1490
1724
|
},
|
|
1491
1725
|
writeFile: async (filepath, content) => {
|
|
@@ -1505,8 +1739,8 @@ var DefaultWebRuntime = class {
|
|
|
1505
1739
|
return false;
|
|
1506
1740
|
}
|
|
1507
1741
|
},
|
|
1508
|
-
readDir: (dirpath) => {
|
|
1509
|
-
return this.memfs.readdir(dirpath, { withFileTypes: true });
|
|
1742
|
+
readDir: (dirpath, options) => {
|
|
1743
|
+
return this.memfs.readdir(dirpath, { withFileTypes: true, ...options || {} });
|
|
1510
1744
|
},
|
|
1511
1745
|
mkdir: async (dirpath) => {
|
|
1512
1746
|
await this.memfs.mkdir(dirpath, { recursive: true });
|