wave-agent-sdk 0.9.7 → 0.10.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.
Files changed (40) hide show
  1. package/dist/index.d.ts +0 -1
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +0 -1
  4. package/dist/managers/backgroundTaskManager.d.ts.map +1 -1
  5. package/dist/managers/backgroundTaskManager.js +59 -6
  6. package/dist/managers/skillManager.d.ts.map +1 -1
  7. package/dist/managers/skillManager.js +13 -1
  8. package/dist/managers/subagentManager.d.ts +2 -0
  9. package/dist/managers/subagentManager.d.ts.map +1 -1
  10. package/dist/managers/subagentManager.js +22 -0
  11. package/dist/tools/agentTool.d.ts.map +1 -1
  12. package/dist/tools/agentTool.js +7 -3
  13. package/dist/tools/bashTool.d.ts.map +1 -1
  14. package/dist/tools/bashTool.js +6 -2
  15. package/dist/tools/globTool.d.ts.map +1 -1
  16. package/dist/tools/globTool.js +9 -48
  17. package/dist/tools/grepTool.d.ts.map +1 -1
  18. package/dist/tools/grepTool.js +0 -6
  19. package/dist/types/processes.d.ts +4 -0
  20. package/dist/types/processes.d.ts.map +1 -1
  21. package/dist/utils/fileSearch.d.ts.map +1 -1
  22. package/dist/utils/fileSearch.js +0 -5
  23. package/dist/utils/openaiClient.d.ts.map +1 -1
  24. package/dist/utils/openaiClient.js +24 -7
  25. package/package.json +1 -1
  26. package/src/index.ts +0 -1
  27. package/src/managers/backgroundTaskManager.ts +62 -6
  28. package/src/managers/skillManager.ts +11 -1
  29. package/src/managers/subagentManager.ts +31 -0
  30. package/src/tools/agentTool.ts +9 -3
  31. package/src/tools/bashTool.ts +6 -2
  32. package/src/tools/globTool.ts +9 -61
  33. package/src/tools/grepTool.ts +0 -7
  34. package/src/types/processes.ts +4 -0
  35. package/src/utils/fileSearch.ts +0 -5
  36. package/src/utils/openaiClient.ts +23 -7
  37. package/dist/utils/fileFilter.d.ts +0 -15
  38. package/dist/utils/fileFilter.d.ts.map +0 -1
  39. package/dist/utils/fileFilter.js +0 -35
  40. package/src/utils/fileFilter.ts +0 -39
package/dist/index.d.ts CHANGED
@@ -4,7 +4,6 @@ export * from "./agent.js";
4
4
  export * from "./core/plugin.js";
5
5
  export * from "./utils/bashParser.js";
6
6
  export * from "./utils/convertMessagesForAPI.js";
7
- export * from "./utils/fileFilter.js";
8
7
  export * from "./utils/fileSearch.js";
9
8
  export * from "./utils/globalLogger.js";
10
9
  export * from "./utils/mcpUtils.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,mBAAmB,CAAC;AAGlC,cAAc,sBAAsB,CAAC;AAGrC,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC;AAGjC,cAAc,uBAAuB,CAAC;AACtC,cAAc,kCAAkC,CAAC;AACjD,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,iBAAiB,CAAC;AAChC,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,wBAAwB,CAAC;AACvC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,qBAAqB,CAAC;AACpC,cAAc,0BAA0B,CAAC;AACzC,cAAc,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,mBAAmB,CAAC;AAGlC,cAAc,sBAAsB,CAAC;AAGrC,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC;AAGjC,cAAc,uBAAuB,CAAC;AACtC,cAAc,kCAAkC,CAAC;AACjD,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,iBAAiB,CAAC;AAChC,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,wBAAwB,CAAC;AACvC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,qBAAqB,CAAC;AACpC,cAAc,0BAA0B,CAAC;AACzC,cAAc,kBAAkB,CAAC"}
package/dist/index.js CHANGED
@@ -8,7 +8,6 @@ export * from "./core/plugin.js";
8
8
  // Export all utilities
9
9
  export * from "./utils/bashParser.js";
10
10
  export * from "./utils/convertMessagesForAPI.js";
11
- export * from "./utils/fileFilter.js";
12
11
  export * from "./utils/fileSearch.js";
13
12
  export * from "./utils/globalLogger.js";
14
13
  export * from "./utils/mcpUtils.js";
@@ -1 +1 @@
1
- {"version":3,"file":"backgroundTaskManager.d.ts","sourceRoot":"","sources":["../../src/managers/backgroundTaskManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EAAE,cAAc,EAAmB,MAAM,uBAAuB,CAAC;AAGxE,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD,MAAM,WAAW,8BAA8B;IAC7C,uBAAuB,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,EAAE,KAAK,IAAI,CAAC;CAC7D;AAED,MAAM,WAAW,4BAA4B;IAC3C,SAAS,CAAC,EAAE,8BAA8B,CAAC;IAC3C,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,qBAAqB;IAO9B,OAAO,CAAC,SAAS;IANnB,OAAO,CAAC,KAAK,CAAqC;IAClD,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,SAAS,CAAiC;IAClD,OAAO,CAAC,OAAO,CAAS;gBAGd,SAAS,EAAE,SAAS,EAC5B,OAAO,EAAE,4BAA4B;IAMvC,OAAO,CAAC,iBAAiB;IAIlB,UAAU,IAAI,MAAM;IAIpB,OAAO,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI;IAKnC,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAI/C,WAAW,IAAI,cAAc,EAAE;IAI/B,UAAU,CACf,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,MAAM,GACf;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,YAAY,CAAC;QAAC,MAAM,EAAE,MAAM,IAAI,CAAA;KAAE;IA8GnD,YAAY,CACjB,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,MAAM,EACf,aAAa,GAAE,MAAW,EAC1B,aAAa,GAAE,MAAW,GACzB,MAAM;IAoEF,SAAS,CACd,EAAE,EAAE,MAAM,EACV,MAAM,CAAC,EAAE,MAAM,GACd;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAiCrD,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IA+B7B,OAAO,IAAI,IAAI;CAUvB"}
1
+ {"version":3,"file":"backgroundTaskManager.d.ts","sourceRoot":"","sources":["../../src/managers/backgroundTaskManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AAIzD,OAAO,EAAE,cAAc,EAAmB,MAAM,uBAAuB,CAAC;AAGxE,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD,MAAM,WAAW,8BAA8B;IAC7C,uBAAuB,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,EAAE,KAAK,IAAI,CAAC;CAC7D;AAED,MAAM,WAAW,4BAA4B;IAC3C,SAAS,CAAC,EAAE,8BAA8B,CAAC;IAC3C,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,qBAAqB;IAO9B,OAAO,CAAC,SAAS;IANnB,OAAO,CAAC,KAAK,CAAqC;IAClD,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,SAAS,CAAiC;IAClD,OAAO,CAAC,OAAO,CAAS;gBAGd,SAAS,EAAE,SAAS,EAC5B,OAAO,EAAE,4BAA4B;IAMvC,OAAO,CAAC,iBAAiB;IAIlB,UAAU,IAAI,MAAM;IAIpB,OAAO,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI;IAKnC,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAI/C,WAAW,IAAI,cAAc,EAAE;IAI/B,UAAU,CACf,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,MAAM,GACf;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,YAAY,CAAC;QAAC,MAAM,EAAE,MAAM,IAAI,CAAA;KAAE;IAqInD,YAAY,CACjB,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,MAAM,EACf,aAAa,GAAE,MAAW,EAC1B,aAAa,GAAE,MAAW,GACzB,MAAM;IAkGF,SAAS,CACd,EAAE,EAAE,MAAM,EACV,MAAM,CAAC,EAAE,MAAM,GACd;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAiCrD,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IA+B7B,OAAO,IAAI,IAAI;CAUvB"}
@@ -1,4 +1,7 @@
1
1
  import { spawn } from "child_process";
2
+ import * as os from "os";
3
+ import * as fs from "fs";
4
+ import * as path from "path";
2
5
  import { stripAnsiColors } from "../utils/stringUtils.js";
3
6
  import { logger } from "../utils/globalLogger.js";
4
7
  export class BackgroundTaskManager {
@@ -36,6 +39,9 @@ export class BackgroundTaskManager {
36
39
  ...process.env,
37
40
  },
38
41
  });
42
+ // Create log file
43
+ const logPath = path.join(os.tmpdir(), `wave-task-${id}.log`);
44
+ const logStream = fs.createWriteStream(logPath, { flags: "a" });
39
45
  const shell = {
40
46
  id,
41
47
  type: "shell",
@@ -45,8 +51,10 @@ export class BackgroundTaskManager {
45
51
  status: "running",
46
52
  stdout: "",
47
53
  stderr: "",
54
+ outputPath: logPath,
48
55
  onStop: () => {
49
56
  try {
57
+ logStream.end();
50
58
  if (child.pid) {
51
59
  process.kill(-child.pid, "SIGTERM");
52
60
  setTimeout(() => {
@@ -81,17 +89,28 @@ export class BackgroundTaskManager {
81
89
  }, timeout);
82
90
  }
83
91
  const onStdout = (data) => {
84
- shell.stdout += stripAnsiColors(data.toString());
92
+ const stripped = stripAnsiColors(data.toString());
93
+ shell.stdout += stripped;
94
+ if (logStream.writable) {
95
+ logStream.write(stripped);
96
+ }
85
97
  this.notifyTasksChange();
86
98
  };
87
99
  const onStderr = (data) => {
88
- shell.stderr += stripAnsiColors(data.toString());
100
+ const stripped = stripAnsiColors(data.toString());
101
+ shell.stderr += stripped;
102
+ if (logStream.writable) {
103
+ logStream.write(stripped);
104
+ }
89
105
  this.notifyTasksChange();
90
106
  };
91
107
  const onExit = (code) => {
92
108
  if (timeoutHandle) {
93
109
  clearTimeout(timeoutHandle);
94
110
  }
111
+ if (logStream.writable) {
112
+ logStream.end();
113
+ }
95
114
  shell.status = code === 0 ? "completed" : "failed";
96
115
  shell.exitCode = code ?? 0;
97
116
  shell.endTime = Date.now();
@@ -102,8 +121,13 @@ export class BackgroundTaskManager {
102
121
  if (timeoutHandle) {
103
122
  clearTimeout(timeoutHandle);
104
123
  }
124
+ const stripped = `\nProcess error: ${stripAnsiColors(error.message)}`;
105
125
  shell.status = "failed";
106
- shell.stderr += `\nProcess error: ${stripAnsiColors(error.message)}`;
126
+ shell.stderr += stripped;
127
+ if (logStream.writable) {
128
+ logStream.write(stripped);
129
+ logStream.end();
130
+ }
107
131
  shell.exitCode = 1;
108
132
  shell.endTime = Date.now();
109
133
  shell.runtime = shell.endTime - startTime;
@@ -121,6 +145,7 @@ export class BackgroundTaskManager {
121
145
  if (timeoutHandle) {
122
146
  clearTimeout(timeoutHandle);
123
147
  }
148
+ logStream.end();
124
149
  this.tasks.delete(id);
125
150
  this.notifyTasksChange();
126
151
  };
@@ -129,6 +154,16 @@ export class BackgroundTaskManager {
129
154
  adoptProcess(child, command, initialStdout = "", initialStderr = "") {
130
155
  const id = this.generateId();
131
156
  const startTime = Date.now();
157
+ // Create log file
158
+ const logPath = path.join(os.tmpdir(), `wave-task-${id}.log`);
159
+ const logStream = fs.createWriteStream(logPath, { flags: "a" });
160
+ // Write initial output to log file
161
+ if (initialStdout) {
162
+ logStream.write(stripAnsiColors(initialStdout));
163
+ }
164
+ if (initialStderr) {
165
+ logStream.write(stripAnsiColors(initialStderr));
166
+ }
132
167
  const shell = {
133
168
  id,
134
169
  type: "shell",
@@ -138,8 +173,10 @@ export class BackgroundTaskManager {
138
173
  status: "running",
139
174
  stdout: initialStdout,
140
175
  stderr: initialStderr,
176
+ outputPath: logPath,
141
177
  onStop: () => {
142
178
  try {
179
+ logStream.end();
143
180
  if (child.pid) {
144
181
  process.kill(-child.pid, "SIGTERM");
145
182
  setTimeout(() => {
@@ -165,14 +202,25 @@ export class BackgroundTaskManager {
165
202
  this.tasks.set(id, shell);
166
203
  this.notifyTasksChange();
167
204
  child.stdout?.on("data", (data) => {
168
- shell.stdout += stripAnsiColors(data.toString());
205
+ const stripped = stripAnsiColors(data.toString());
206
+ shell.stdout += stripped;
207
+ if (logStream.writable) {
208
+ logStream.write(stripped);
209
+ }
169
210
  this.notifyTasksChange();
170
211
  });
171
212
  child.stderr?.on("data", (data) => {
172
- shell.stderr += stripAnsiColors(data.toString());
213
+ const stripped = stripAnsiColors(data.toString());
214
+ shell.stderr += stripped;
215
+ if (logStream.writable) {
216
+ logStream.write(stripped);
217
+ }
173
218
  this.notifyTasksChange();
174
219
  });
175
220
  child.on("exit", (code) => {
221
+ if (logStream.writable) {
222
+ logStream.end();
223
+ }
176
224
  shell.status = code === 0 ? "completed" : "failed";
177
225
  shell.exitCode = code ?? 0;
178
226
  shell.endTime = Date.now();
@@ -180,8 +228,13 @@ export class BackgroundTaskManager {
180
228
  this.notifyTasksChange();
181
229
  });
182
230
  child.on("error", (error) => {
231
+ const stripped = `\nProcess error: ${stripAnsiColors(error.message)}`;
183
232
  shell.status = "failed";
184
- shell.stderr += `\nProcess error: ${stripAnsiColors(error.message)}`;
233
+ shell.stderr += stripped;
234
+ if (logStream.writable) {
235
+ logStream.write(stripped);
236
+ logStream.end();
237
+ }
185
238
  shell.exitCode = 1;
186
239
  shell.endTime = Date.now();
187
240
  shell.runtime = shell.endTime - startTime;
@@ -1 +1 @@
1
- {"version":3,"file":"skillManager.d.ts","sourceRoot":"","sources":["../../src/managers/skillManager.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,mBAAmB,EACnB,aAAa,EACb,KAAK,EAGL,aAAa,EACb,sBAAsB,EACvB,MAAM,mBAAmB,CAAC;AAS3B,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAGlD;;GAEG;AACH,qBAAa,YAAY;IAUrB,OAAO,CAAC,SAAS;IATnB,OAAO,CAAC,kBAAkB,CAAS;IACnC,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,OAAO,CAAS;IAExB,OAAO,CAAC,aAAa,CAAoC;IACzD,OAAO,CAAC,YAAY,CAA4B;IAChD,OAAO,CAAC,WAAW,CAAS;gBAGlB,SAAS,EAAE,SAAS,EAC5B,OAAO,GAAE,mBAAwB;IAQnC;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAoCjC;;OAEG;IACH,aAAa,IAAI,OAAO;IAIxB;;OAEG;IACH,kBAAkB,IAAI,aAAa,EAAE;IAQrC;;OAEG;IACH,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAQzD;;;OAGG;IACG,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC;IAgBzD;;OAEG;YACW,cAAc;IAkB5B;;OAEG;YACW,uBAAuB;IA8ErC;;OAEG;YACW,oBAAoB;IAkBlC;;OAEG;IACG,YAAY,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC;QAC/C,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,sBAAsB,CAAC;QACjC,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;KACzB,CAAC;IA8BF;;OAEG;IACG,YAAY,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAC5C;QACE,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,EAAE,KAAK,CAAC;KACd,GACD;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,SAAS,CAAA;KAAE,CACzC;IA6BD;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAkB3B;;OAEG;YACW,yBAAyB;IASvC;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAc7B;;OAEG;IACH,oBAAoB,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI;CA0BhE"}
1
+ {"version":3,"file":"skillManager.d.ts","sourceRoot":"","sources":["../../src/managers/skillManager.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,mBAAmB,EACnB,aAAa,EACb,KAAK,EAGL,aAAa,EACb,sBAAsB,EACvB,MAAM,mBAAmB,CAAC;AAS3B,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAGlD;;GAEG;AACH,qBAAa,YAAY;IAUrB,OAAO,CAAC,SAAS;IATnB,OAAO,CAAC,kBAAkB,CAAS;IACnC,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,OAAO,CAAS;IAExB,OAAO,CAAC,aAAa,CAAoC;IACzD,OAAO,CAAC,YAAY,CAA4B;IAChD,OAAO,CAAC,WAAW,CAAS;gBAGlB,SAAS,EAAE,SAAS,EAC5B,OAAO,GAAE,mBAAwB;IAQnC;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAoCjC;;OAEG;IACH,aAAa,IAAI,OAAO;IAIxB;;OAEG;IACH,kBAAkB,IAAI,aAAa,EAAE;IAQrC;;OAEG;IACH,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAQzD;;;OAGG;IACG,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC;IAgBzD;;OAEG;YACW,cAAc;IAkB5B;;OAEG;YACW,uBAAuB;IA8ErC;;OAEG;YACW,oBAAoB;IA4BlC;;OAEG;IACG,YAAY,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC;QAC/C,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,sBAAsB,CAAC;QACjC,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;KACzB,CAAC;IA8BF;;OAEG;IACG,YAAY,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAC5C;QACE,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,EAAE,KAAK,CAAC;KACd,GACD;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,SAAS,CAAA;KAAE,CACzC;IA6BD;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAkB3B;;OAEG;YACW,yBAAyB;IASvC;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAc7B;;OAEG;IACH,oBAAoB,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI;CA0BhE"}
@@ -179,8 +179,20 @@ export class SkillManager {
179
179
  try {
180
180
  const entries = await readdir(skillsPath, { withFileTypes: true });
181
181
  for (const entry of entries) {
182
+ const fullPath = join(skillsPath, entry.name);
182
183
  if (entry.isDirectory()) {
183
- directories.push(join(skillsPath, entry.name));
184
+ directories.push(fullPath);
185
+ }
186
+ else if (entry.isSymbolicLink()) {
187
+ try {
188
+ const s = await stat(fullPath);
189
+ if (s.isDirectory()) {
190
+ directories.push(fullPath);
191
+ }
192
+ }
193
+ catch {
194
+ // Ignore broken symlinks or other errors
195
+ }
184
196
  }
185
197
  }
186
198
  }
@@ -1,3 +1,4 @@
1
+ import * as fs from "fs";
1
2
  import type { SubagentConfiguration } from "../utils/subagentParser.js";
2
3
  import type { Message, Usage } from "../types/index.js";
3
4
  import { AIManager } from "./aiManager.js";
@@ -36,6 +37,7 @@ export interface SubagentInstance {
36
37
  backgroundTaskId?: string;
37
38
  onUpdate?: () => void;
38
39
  model?: string;
40
+ logStream?: fs.WriteStream;
39
41
  }
40
42
  export interface SubagentManagerOptions {
41
43
  workdir: string;
@@ -1 +1 @@
1
- {"version":3,"file":"subagentManager.d.ts","sourceRoot":"","sources":["../../src/managers/subagentManager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"subagentManager.d.ts","sourceRoot":"","sources":["../../src/managers/subagentManager.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,7 @@
1
1
  import { randomUUID } from "crypto";
2
+ import * as os from "os";
3
+ import * as fs from "fs";
4
+ import * as path from "path";
2
5
  import { AIManager } from "./aiManager.js";
3
6
  import { MessageManager } from "./messageManager.js";
4
7
  import { ToolManager } from "./toolManager.js";
@@ -142,6 +145,10 @@ export class SubagentManager {
142
145
  if (runInBackground && backgroundTaskManager) {
143
146
  const taskId = backgroundTaskManager.generateId();
144
147
  const startTime = Date.now();
148
+ // Create log file
149
+ const logPath = path.join(os.tmpdir(), `wave-subagent-${taskId}.log`);
150
+ const logStream = fs.createWriteStream(logPath, { flags: "a" });
151
+ instance.logStream = logStream;
145
152
  backgroundTaskManager.addTask({
146
153
  id: taskId,
147
154
  type: "subagent",
@@ -150,8 +157,10 @@ export class SubagentManager {
150
157
  description: instance.description,
151
158
  stdout: "",
152
159
  stderr: "",
160
+ outputPath: logPath,
153
161
  subagentId: instance.subagentId,
154
162
  onStop: () => {
163
+ instance.logStream?.end();
155
164
  instance.aiManager.abortAIMessage();
156
165
  this.cleanupInstance(instance.subagentId);
157
166
  },
@@ -202,6 +211,10 @@ export class SubagentManager {
202
211
  }
203
212
  const taskId = backgroundTaskManager.generateId();
204
213
  const startTime = Date.now();
214
+ // Create log file
215
+ const logPath = path.join(os.tmpdir(), `wave-subagent-${taskId}.log`);
216
+ const logStream = fs.createWriteStream(logPath, { flags: "a" });
217
+ instance.logStream = logStream;
205
218
  backgroundTaskManager.addTask({
206
219
  id: taskId,
207
220
  type: "subagent",
@@ -210,8 +223,10 @@ export class SubagentManager {
210
223
  description: instance.description,
211
224
  stdout: "",
212
225
  stderr: "",
226
+ outputPath: logPath,
213
227
  subagentId: instance.subagentId,
214
228
  onStop: () => {
229
+ instance.logStream?.end();
215
230
  instance.aiManager.abortAIMessage();
216
231
  this.cleanupInstance(instance.subagentId);
217
232
  },
@@ -285,6 +300,7 @@ export class SubagentManager {
285
300
  : undefined;
286
301
  // If this was transitioned to background, update the background task
287
302
  if (instance.backgroundTaskId && backgroundTaskManager) {
303
+ instance.logStream?.end();
288
304
  const task = backgroundTaskManager.getTask(instance.backgroundTaskId);
289
305
  if (task) {
290
306
  task.status = "completed";
@@ -303,6 +319,7 @@ export class SubagentManager {
303
319
  : undefined;
304
320
  // If this was transitioned to background, update the background task with error
305
321
  if (instance.backgroundTaskId && backgroundTaskManager) {
322
+ instance.logStream?.end();
306
323
  const task = backgroundTaskManager.getTask(instance.backgroundTaskId);
307
324
  if (task) {
308
325
  task.status = "failed";
@@ -412,6 +429,11 @@ export class SubagentManager {
412
429
  instance.lastTools.shift();
413
430
  }
414
431
  instance.onUpdate?.();
432
+ // Log tool execution to file
433
+ if (instance.logStream) {
434
+ const compactParams = (params.parameters || "{}").substring(0, 100);
435
+ instance.logStream.write(`[${new Date().toISOString()}] Running tool: ${params.name} with params: ${compactParams}${compactParams.length >= 100 ? "..." : ""}\n`);
436
+ }
415
437
  }
416
438
  }
417
439
  // Forward tool block updates to parent via SubagentManager callbacks
@@ -1 +1 @@
1
- {"version":3,"file":"agentTool.d.ts","sourceRoot":"","sources":["../../src/tools/agentTool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAA2B,MAAM,YAAY,CAAC;AAStE;;GAEG;AACH,eAAO,MAAM,SAAS,EAAE,UA0PvB,CAAC"}
1
+ {"version":3,"file":"agentTool.d.ts","sourceRoot":"","sources":["../../src/tools/agentTool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAA2B,MAAM,YAAY,CAAC;AAStE;;GAEG;AACH,eAAO,MAAM,SAAS,EAAE,UAgQvB,CAAC"}
@@ -149,10 +149,12 @@ When using the Agent tool, you must specify a subagent_type parameter to select
149
149
  id: instance.subagentId,
150
150
  backgroundHandler: async () => {
151
151
  isBackgrounded = true;
152
- await subagentManager.backgroundInstance(instance.subagentId);
152
+ const taskId = await subagentManager.backgroundInstance(instance.subagentId);
153
+ const task = context.backgroundTaskManager?.getTask(taskId);
154
+ const outputPath = task?.outputPath;
153
155
  resolve({
154
156
  success: true,
155
- content: "Agent backgrounded",
157
+ content: `Agent backgrounded with ID: ${taskId}.${outputPath ? ` Real-time output: ${outputPath}` : ""}`,
156
158
  shortResult: "Agent backgrounded",
157
159
  isManuallyBackgrounded: true,
158
160
  });
@@ -165,9 +167,11 @@ When using the Agent tool, you must specify a subagent_type parameter to select
165
167
  return;
166
168
  }
167
169
  if (run_in_background) {
170
+ const task = context.backgroundTaskManager?.getTask(result);
171
+ const outputPath = task?.outputPath;
168
172
  resolve({
169
173
  success: true,
170
- content: `Agent started in background with ID: ${result}`,
174
+ content: `Agent started in background with ID: ${result}.${outputPath ? ` Real-time output: ${outputPath}` : ""}`,
171
175
  shortResult: `Agent started in background: ${result}`,
172
176
  });
173
177
  return;
@@ -1 +1 @@
1
- {"version":3,"file":"bashTool.d.ts","sourceRoot":"","sources":["../../src/tools/bashTool.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAA2B,MAAM,YAAY,CAAC;AActE;;GAEG;AACH,eAAO,MAAM,QAAQ,EAAE,UAuXtB,CAAC"}
1
+ {"version":3,"file":"bashTool.d.ts","sourceRoot":"","sources":["../../src/tools/bashTool.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAA2B,MAAM,YAAY,CAAC;AActE;;GAEG;AACH,eAAO,MAAM,QAAQ,EAAE,UA2XtB,CAAC"}
@@ -148,9 +148,11 @@ Usage notes:
148
148
  };
149
149
  }
150
150
  const { id: taskId } = backgroundTaskManager.startShell(command, timeout);
151
+ const task = backgroundTaskManager.getTask(taskId);
152
+ const outputPath = task?.outputPath;
151
153
  return {
152
154
  success: true,
153
- content: `Command started in background with ID: ${taskId}. Use TaskOutput tool with task_id="${taskId}" to monitor output.`,
155
+ content: `Command started in background with ID: ${taskId}.${outputPath ? ` Real-time output: ${outputPath}` : ` Use TaskOutput tool with task_id="${taskId}" to monitor output.`}`,
154
156
  shortResult: `Background process ${taskId} started`,
155
157
  };
156
158
  }
@@ -181,9 +183,11 @@ Usage notes:
181
183
  const backgroundTaskManager = context.backgroundTaskManager;
182
184
  if (backgroundTaskManager) {
183
185
  const taskId = backgroundTaskManager.adoptProcess(child, command, outputBuffer, errorBuffer);
186
+ const task = backgroundTaskManager.getTask(taskId);
187
+ const outputPath = task?.outputPath;
184
188
  resolve({
185
189
  success: true,
186
- content: `Command moved to background with ID: ${taskId}.`,
190
+ content: `Command moved to background with ID: ${taskId}.${outputPath ? ` Real-time output: ${outputPath}` : ""}`,
187
191
  shortResult: `Process ${taskId} backgrounded`,
188
192
  isManuallyBackgrounded: true,
189
193
  });
@@ -1 +1 @@
1
- {"version":3,"file":"globTool.d.ts","sourceRoot":"","sources":["../../src/tools/globTool.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAA2B,MAAM,YAAY,CAAC;AAiEtE;;GAEG;AACH,eAAO,MAAM,QAAQ,EAAE,UAsItB,CAAC"}
1
+ {"version":3,"file":"globTool.d.ts","sourceRoot":"","sources":["../../src/tools/globTool.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAA2B,MAAM,YAAY,CAAC;AAStE;;GAEG;AACH,eAAO,MAAM,QAAQ,EAAE,UA2ItB,CAAC"}
@@ -1,55 +1,11 @@
1
- import { spawn } from "child_process";
2
- import { rgPath } from "../utils/ripgrep.js";
1
+ import { glob } from "glob";
3
2
  import { stat } from "fs/promises";
4
3
  import { resolvePath, getDisplayPath } from "../utils/path.js";
5
- import { getAllIgnorePatterns } from "../utils/fileFilter.js";
6
4
  import { GLOB_TOOL_NAME } from "../constants/tools.js";
7
5
  /**
8
6
  * Maximum number of files returned by glob tool
9
7
  */
10
- const MAX_GLOB_RESULTS = 1000;
11
- /**
12
- * Execute ripgrep to find files matching a pattern
13
- */
14
- async function runRipgrep(pattern, workdir) {
15
- if (!rgPath) {
16
- throw new Error("ripgrep is not available");
17
- }
18
- const ignorePatterns = getAllIgnorePatterns();
19
- const rgArgs = ["--files", "--color=never", "--hidden", "--glob", pattern];
20
- for (const ignorePattern of ignorePatterns) {
21
- rgArgs.push("--glob", `!${ignorePattern}`);
22
- }
23
- return new Promise((resolve, reject) => {
24
- const child = spawn(rgPath, rgArgs, {
25
- cwd: workdir,
26
- stdio: ["ignore", "pipe", "pipe"],
27
- });
28
- let stdout = "";
29
- let stderr = "";
30
- child.stdout?.on("data", (data) => {
31
- stdout += data.toString();
32
- });
33
- child.stderr?.on("data", (data) => {
34
- stderr += data.toString();
35
- });
36
- child.on("close", (code) => {
37
- if (code !== 0 && code !== 1) {
38
- reject(new Error(`ripgrep failed with code ${code}: ${stderr || "Unknown error"}`));
39
- return;
40
- }
41
- const files = stdout
42
- .trim()
43
- .split("\n")
44
- .filter((f) => f.length > 0)
45
- .map((f) => f.replace(/\\/g, "/")); // Normalize to forward slashes
46
- resolve(files);
47
- });
48
- child.on("error", (err) => {
49
- reject(err);
50
- });
51
- });
52
- }
8
+ const MAX_GLOB_RESULTS = 100;
53
9
  /**
54
10
  * Glob Tool Plugin - Fast file pattern matching
55
11
  */
@@ -97,8 +53,13 @@ export const globTool = {
97
53
  const workdir = searchPath
98
54
  ? resolvePath(searchPath, context.workdir)
99
55
  : context.workdir;
100
- // Execute glob search using ripgrep
101
- const matches = await runRipgrep(pattern, workdir);
56
+ // Execute glob search using glob package
57
+ const matches = await glob(pattern, {
58
+ cwd: workdir,
59
+ nodir: true,
60
+ dot: true,
61
+ ignore: ["**/.git/**"],
62
+ });
102
63
  if (matches.length === 0) {
103
64
  return {
104
65
  success: true,
@@ -1 +1 @@
1
- {"version":3,"file":"grepTool.d.ts","sourceRoot":"","sources":["../../src/tools/grepTool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAA2B,MAAM,YAAY,CAAC;AAWtE;;GAEG;AACH,eAAO,MAAM,QAAQ,EAAE,UAuRtB,CAAC"}
1
+ {"version":3,"file":"grepTool.d.ts","sourceRoot":"","sources":["../../src/tools/grepTool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAA2B,MAAM,YAAY,CAAC;AAUtE;;GAEG;AACH,eAAO,MAAM,QAAQ,EAAE,UAiRtB,CAAC"}
@@ -1,5 +1,4 @@
1
1
  import { spawn } from "child_process";
2
- import { getAllIgnorePatterns } from "../utils/fileFilter.js";
3
2
  import { rgPath } from "../utils/ripgrep.js";
4
3
  import { getDisplayPath } from "../utils/path.js";
5
4
  import { GREP_TOOL_NAME, BASH_TOOL_NAME, AGENT_TOOL_NAME, } from "../constants/tools.js";
@@ -157,11 +156,6 @@ export const grepTool = {
157
156
  if (globPattern) {
158
157
  rgArgs.push("--glob", globPattern);
159
158
  }
160
- // Get common ignore rules
161
- const ignorePatterns = getAllIgnorePatterns();
162
- for (const exclude of ignorePatterns) {
163
- rgArgs.push("--glob", `!${exclude}`);
164
- }
165
159
  // Add search pattern - use -e parameter to avoid patterns starting with - being mistaken as command line options
166
160
  rgArgs.push("-e", pattern);
167
161
  // Add search path
@@ -27,6 +27,10 @@ export interface BackgroundTaskBase {
27
27
  * Used for cleanup when the task is stopped.
28
28
  */
29
29
  subagentId?: string;
30
+ /**
31
+ * Optional path to the real-time output log file.
32
+ */
33
+ outputPath?: string;
30
34
  }
31
35
  export interface BackgroundShell extends BackgroundTaskBase {
32
36
  type: "shell";
@@ -1 +1 @@
1
- {"version":3,"file":"processes.d.ts","sourceRoot":"","sources":["../../src/types/processes.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,MAAM,MAAM,oBAAoB,GAC5B,SAAS,GACT,WAAW,GACX,QAAQ,GACR,QAAQ,CAAC;AACb,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG,UAAU,CAAC;AAEtD,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,kBAAkB,CAAC;IACzB,MAAM,EAAE,oBAAoB,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,eAAgB,SAAQ,kBAAkB;IACzD,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,YAAY,CAAC;CACvB;AAED,MAAM,WAAW,kBAAmB,SAAQ,kBAAkB;IAC5D,IAAI,EAAE,UAAU,CAAC;CAClB;AAED,MAAM,MAAM,cAAc,GAAG,eAAe,GAAG,kBAAkB,CAAC;AAElE,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,iBAAiB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACxC;AAED,MAAM,WAAW,sBAAsB;IACrC,sBAAsB,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI,CAAC;IACnD,wBAAwB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5C"}
1
+ {"version":3,"file":"processes.d.ts","sourceRoot":"","sources":["../../src/types/processes.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,MAAM,MAAM,oBAAoB,GAC5B,SAAS,GACT,WAAW,GACX,QAAQ,GACR,QAAQ,CAAC;AACb,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG,UAAU,CAAC;AAEtD,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,kBAAkB,CAAC;IACzB,MAAM,EAAE,oBAAoB,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,eAAgB,SAAQ,kBAAkB;IACzD,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,YAAY,CAAC;CACvB;AAED,MAAM,WAAW,kBAAmB,SAAQ,kBAAkB;IAC5D,IAAI,EAAE,UAAU,CAAC;CAClB;AAED,MAAM,MAAM,cAAc,GAAG,eAAe,GAAG,kBAAkB,CAAC;AAElE,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,iBAAiB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACxC;AAED,MAAM,WAAW,sBAAsB;IACrC,sBAAsB,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI,CAAC;IACnD,wBAAwB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5C"}
@@ -1 +1 @@
1
- {"version":3,"file":"fileSearch.d.ts","sourceRoot":"","sources":["../../src/utils/fileSearch.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAqEvD;;GAEG;AACH,eAAO,MAAM,WAAW,GACtB,OAAO,MAAM,EACb,UAAU;IACR,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,KACA,OAAO,CAAC,QAAQ,EAAE,CA+DpB,CAAC"}
1
+ {"version":3,"file":"fileSearch.d.ts","sourceRoot":"","sources":["../../src/utils/fileSearch.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAiEvD;;GAEG;AACH,eAAO,MAAM,WAAW,GACtB,OAAO,MAAM,EACb,UAAU;IACR,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,KACA,OAAO,CAAC,QAAQ,EAAE,CA+DpB,CAAC"}
@@ -1,7 +1,6 @@
1
1
  import { spawn } from "child_process";
2
2
  import { rgPath } from "./ripgrep.js";
3
3
  import fuzzysort from "fuzzysort";
4
- import { getAllIgnorePatterns } from "./fileFilter.js";
5
4
  import { logger } from "./globalLogger.js";
6
5
  /**
7
6
  * Execute ripgrep to get all file paths
@@ -10,11 +9,7 @@ async function getAllFiles(workingDirectory) {
10
9
  if (!rgPath) {
11
10
  throw new Error("ripgrep is not available");
12
11
  }
13
- const ignorePatterns = getAllIgnorePatterns();
14
12
  const rgArgs = ["--files", "--color=never", "--hidden"];
15
- for (const pattern of ignorePatterns) {
16
- rgArgs.push("--glob", `!${pattern}`);
17
- }
18
13
  return new Promise((resolve, reject) => {
19
14
  const child = spawn(rgPath, rgArgs, {
20
15
  cwd: workingDirectory,
@@ -1 +1 @@
1
- {"version":3,"file":"openaiClient.d.ts","sourceRoot":"","sources":["../../src/utils/openaiClient.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sCAAsC,EACtC,mCAAmC,EACnC,mBAAmB,EACnB,cAAc,EACf,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGnD,KAAK,YAAY,GACb,sCAAsC,GACtC,mCAAmC,CAAC;AAExC,UAAU,WAAW,CAAC,CAAC;IACrB,IAAI,EAAE,CAAC,CAAC;IACR,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED,UAAU,UAAU,CAAC,CAAC,CAAE,SAAQ,OAAO,CAAC,CAAC,CAAC;IACxC,YAAY,IAAI,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;CACzC;AAED,qBAAa,YAAY;IACX,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,aAAa;IAEzC,IAAI,IAAI;;qBAGO,CAAC,SAAS,YAAY,UACrB,CAAC,YACC;gBAAE,MAAM,CAAC,EAAE,WAAW,CAAA;aAAE,KACjC,UAAU,CACX,CAAC,SAAS,mCAAmC,GACzC,aAAa,CAAC,mBAAmB,CAAC,GAClC,cAAc,CACnB;;MA2BN;YAEa,OAAO;YAgIN,oBAAoB;CAqCpC"}
1
+ {"version":3,"file":"openaiClient.d.ts","sourceRoot":"","sources":["../../src/utils/openaiClient.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sCAAsC,EACtC,mCAAmC,EACnC,mBAAmB,EACnB,cAAc,EACf,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGnD,KAAK,YAAY,GACb,sCAAsC,GACtC,mCAAmC,CAAC;AAExC,UAAU,WAAW,CAAC,CAAC;IACrB,IAAI,EAAE,CAAC,CAAC;IACR,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED,UAAU,UAAU,CAAC,CAAC,CAAE,SAAQ,OAAO,CAAC,CAAC,CAAC;IACxC,YAAY,IAAI,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;CACzC;AAED,qBAAa,YAAY;IACX,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,aAAa;IAEzC,IAAI,IAAI;;qBAGO,CAAC,SAAS,YAAY,UACrB,CAAC,YACC;gBAAE,MAAM,CAAC,EAAE,WAAW,CAAA;aAAE,KACjC,UAAU,CACX,CAAC,SAAS,mCAAmC,GACzC,aAAa,CAAC,mBAAmB,CAAC,GAClC,cAAc,CACnB;;MA2BN;YAEa,OAAO;YAgJN,oBAAoB;CAqCpC"}
@@ -38,13 +38,30 @@ export class OpenAIClient {
38
38
  const delay = initialDelay * Math.pow(2, attempt - 1);
39
39
  await new Promise((resolve) => setTimeout(resolve, delay));
40
40
  }
41
- const response = await fetchFn(url, {
42
- method: "POST",
43
- headers,
44
- body: JSON.stringify(params),
45
- signal: options?.signal,
46
- ...fetchOptions,
47
- });
41
+ let response;
42
+ try {
43
+ response = await fetchFn(url, {
44
+ method: "POST",
45
+ headers,
46
+ body: JSON.stringify(params),
47
+ signal: options?.signal,
48
+ ...fetchOptions,
49
+ });
50
+ }
51
+ catch (e) {
52
+ if (e instanceof Error && e.name === "AbortError") {
53
+ throw e;
54
+ }
55
+ if (attempt < maxRetries) {
56
+ logger.warn("OpenAI API network error, retrying...", {
57
+ attempt: attempt + 1,
58
+ error: e,
59
+ });
60
+ lastError = e;
61
+ continue;
62
+ }
63
+ throw e;
64
+ }
48
65
  if (response.ok) {
49
66
  if (params.stream) {
50
67
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wave-agent-sdk",
3
- "version": "0.9.7",
3
+ "version": "0.10.0",
4
4
  "description": "SDK for building AI-powered development tools and agents",
5
5
  "keywords": [
6
6
  "ai",
package/src/index.ts CHANGED
@@ -11,7 +11,6 @@ export * from "./core/plugin.js";
11
11
  // Export all utilities
12
12
  export * from "./utils/bashParser.js";
13
13
  export * from "./utils/convertMessagesForAPI.js";
14
- export * from "./utils/fileFilter.js";
15
14
  export * from "./utils/fileSearch.js";
16
15
  export * from "./utils/globalLogger.js";
17
16
  export * from "./utils/mcpUtils.js";
@@ -1,4 +1,7 @@
1
1
  import { spawn, type ChildProcess } from "child_process";
2
+ import * as os from "os";
3
+ import * as fs from "fs";
4
+ import * as path from "path";
2
5
  import { BackgroundTask, BackgroundShell } from "../types/processes.js";
3
6
  import { stripAnsiColors } from "../utils/stringUtils.js";
4
7
  import { logger } from "../utils/globalLogger.js";
@@ -64,6 +67,10 @@ export class BackgroundTaskManager {
64
67
  },
65
68
  });
66
69
 
70
+ // Create log file
71
+ const logPath = path.join(os.tmpdir(), `wave-task-${id}.log`);
72
+ const logStream = fs.createWriteStream(logPath, { flags: "a" });
73
+
67
74
  const shell: BackgroundShell = {
68
75
  id,
69
76
  type: "shell",
@@ -73,8 +80,10 @@ export class BackgroundTaskManager {
73
80
  status: "running",
74
81
  stdout: "",
75
82
  stderr: "",
83
+ outputPath: logPath,
76
84
  onStop: () => {
77
85
  try {
86
+ logStream.end();
78
87
  if (child.pid) {
79
88
  process.kill(-child.pid, "SIGTERM");
80
89
  setTimeout(() => {
@@ -109,12 +118,20 @@ export class BackgroundTaskManager {
109
118
  }
110
119
 
111
120
  const onStdout = (data: Buffer | string) => {
112
- shell.stdout += stripAnsiColors(data.toString());
121
+ const stripped = stripAnsiColors(data.toString());
122
+ shell.stdout += stripped;
123
+ if (logStream.writable) {
124
+ logStream.write(stripped);
125
+ }
113
126
  this.notifyTasksChange();
114
127
  };
115
128
 
116
129
  const onStderr = (data: Buffer | string) => {
117
- shell.stderr += stripAnsiColors(data.toString());
130
+ const stripped = stripAnsiColors(data.toString());
131
+ shell.stderr += stripped;
132
+ if (logStream.writable) {
133
+ logStream.write(stripped);
134
+ }
118
135
  this.notifyTasksChange();
119
136
  };
120
137
 
@@ -122,6 +139,9 @@ export class BackgroundTaskManager {
122
139
  if (timeoutHandle) {
123
140
  clearTimeout(timeoutHandle);
124
141
  }
142
+ if (logStream.writable) {
143
+ logStream.end();
144
+ }
125
145
  shell.status = code === 0 ? "completed" : "failed";
126
146
  shell.exitCode = code ?? 0;
127
147
  shell.endTime = Date.now();
@@ -133,8 +153,13 @@ export class BackgroundTaskManager {
133
153
  if (timeoutHandle) {
134
154
  clearTimeout(timeoutHandle);
135
155
  }
156
+ const stripped = `\nProcess error: ${stripAnsiColors(error.message)}`;
136
157
  shell.status = "failed";
137
- shell.stderr += `\nProcess error: ${stripAnsiColors(error.message)}`;
158
+ shell.stderr += stripped;
159
+ if (logStream.writable) {
160
+ logStream.write(stripped);
161
+ logStream.end();
162
+ }
138
163
  shell.exitCode = 1;
139
164
  shell.endTime = Date.now();
140
165
  shell.runtime = shell.endTime - startTime;
@@ -154,6 +179,7 @@ export class BackgroundTaskManager {
154
179
  if (timeoutHandle) {
155
180
  clearTimeout(timeoutHandle);
156
181
  }
182
+ logStream.end();
157
183
  this.tasks.delete(id);
158
184
  this.notifyTasksChange();
159
185
  };
@@ -170,6 +196,18 @@ export class BackgroundTaskManager {
170
196
  const id = this.generateId();
171
197
  const startTime = Date.now();
172
198
 
199
+ // Create log file
200
+ const logPath = path.join(os.tmpdir(), `wave-task-${id}.log`);
201
+ const logStream = fs.createWriteStream(logPath, { flags: "a" });
202
+
203
+ // Write initial output to log file
204
+ if (initialStdout) {
205
+ logStream.write(stripAnsiColors(initialStdout));
206
+ }
207
+ if (initialStderr) {
208
+ logStream.write(stripAnsiColors(initialStderr));
209
+ }
210
+
173
211
  const shell: BackgroundShell = {
174
212
  id,
175
213
  type: "shell",
@@ -179,8 +217,10 @@ export class BackgroundTaskManager {
179
217
  status: "running",
180
218
  stdout: initialStdout,
181
219
  stderr: initialStderr,
220
+ outputPath: logPath,
182
221
  onStop: () => {
183
222
  try {
223
+ logStream.end();
184
224
  if (child.pid) {
185
225
  process.kill(-child.pid, "SIGTERM");
186
226
  setTimeout(() => {
@@ -205,16 +245,27 @@ export class BackgroundTaskManager {
205
245
  this.notifyTasksChange();
206
246
 
207
247
  child.stdout?.on("data", (data) => {
208
- shell.stdout += stripAnsiColors(data.toString());
248
+ const stripped = stripAnsiColors(data.toString());
249
+ shell.stdout += stripped;
250
+ if (logStream.writable) {
251
+ logStream.write(stripped);
252
+ }
209
253
  this.notifyTasksChange();
210
254
  });
211
255
 
212
256
  child.stderr?.on("data", (data) => {
213
- shell.stderr += stripAnsiColors(data.toString());
257
+ const stripped = stripAnsiColors(data.toString());
258
+ shell.stderr += stripped;
259
+ if (logStream.writable) {
260
+ logStream.write(stripped);
261
+ }
214
262
  this.notifyTasksChange();
215
263
  });
216
264
 
217
265
  child.on("exit", (code) => {
266
+ if (logStream.writable) {
267
+ logStream.end();
268
+ }
218
269
  shell.status = code === 0 ? "completed" : "failed";
219
270
  shell.exitCode = code ?? 0;
220
271
  shell.endTime = Date.now();
@@ -223,8 +274,13 @@ export class BackgroundTaskManager {
223
274
  });
224
275
 
225
276
  child.on("error", (error) => {
277
+ const stripped = `\nProcess error: ${stripAnsiColors(error.message)}`;
226
278
  shell.status = "failed";
227
- shell.stderr += `\nProcess error: ${stripAnsiColors(error.message)}`;
279
+ shell.stderr += stripped;
280
+ if (logStream.writable) {
281
+ logStream.write(stripped);
282
+ logStream.end();
283
+ }
228
284
  shell.exitCode = 1;
229
285
  shell.endTime = Date.now();
230
286
  shell.runtime = shell.endTime - startTime;
@@ -243,8 +243,18 @@ export class SkillManager {
243
243
  const entries = await readdir(skillsPath, { withFileTypes: true });
244
244
 
245
245
  for (const entry of entries) {
246
+ const fullPath = join(skillsPath, entry.name);
246
247
  if (entry.isDirectory()) {
247
- directories.push(join(skillsPath, entry.name));
248
+ directories.push(fullPath);
249
+ } else if (entry.isSymbolicLink()) {
250
+ try {
251
+ const s = await stat(fullPath);
252
+ if (s.isDirectory()) {
253
+ directories.push(fullPath);
254
+ }
255
+ } catch {
256
+ // Ignore broken symlinks or other errors
257
+ }
248
258
  }
249
259
  }
250
260
  } catch {
@@ -1,4 +1,7 @@
1
1
  import { randomUUID } from "crypto";
2
+ import * as os from "os";
3
+ import * as fs from "fs";
4
+ import * as path from "path";
2
5
  import type { SubagentConfiguration } from "../utils/subagentParser.js";
3
6
  import type { Message, Usage } from "../types/index.js";
4
7
  import { AIManager } from "./aiManager.js";
@@ -70,6 +73,7 @@ export interface SubagentInstance {
70
73
  backgroundTaskId?: string; // ID of the background task if transitioned
71
74
  onUpdate?: () => void; // Optional callback for real-time updates
72
75
  model?: string; // Optional model override
76
+ logStream?: fs.WriteStream; // Optional log stream for background tasks
73
77
  }
74
78
 
75
79
  export interface SubagentManagerOptions {
@@ -274,6 +278,11 @@ export class SubagentManager {
274
278
  const taskId = backgroundTaskManager.generateId();
275
279
  const startTime = Date.now();
276
280
 
281
+ // Create log file
282
+ const logPath = path.join(os.tmpdir(), `wave-subagent-${taskId}.log`);
283
+ const logStream = fs.createWriteStream(logPath, { flags: "a" });
284
+ instance.logStream = logStream;
285
+
277
286
  backgroundTaskManager.addTask({
278
287
  id: taskId,
279
288
  type: "subagent",
@@ -282,8 +291,10 @@ export class SubagentManager {
282
291
  description: instance.description,
283
292
  stdout: "",
284
293
  stderr: "",
294
+ outputPath: logPath,
285
295
  subagentId: instance.subagentId,
286
296
  onStop: () => {
297
+ instance.logStream?.end();
287
298
  instance.aiManager.abortAIMessage();
288
299
  this.cleanupInstance(instance.subagentId);
289
300
  },
@@ -345,6 +356,11 @@ export class SubagentManager {
345
356
  const taskId = backgroundTaskManager.generateId();
346
357
  const startTime = Date.now();
347
358
 
359
+ // Create log file
360
+ const logPath = path.join(os.tmpdir(), `wave-subagent-${taskId}.log`);
361
+ const logStream = fs.createWriteStream(logPath, { flags: "a" });
362
+ instance.logStream = logStream;
363
+
348
364
  backgroundTaskManager.addTask({
349
365
  id: taskId,
350
366
  type: "subagent",
@@ -353,8 +369,10 @@ export class SubagentManager {
353
369
  description: instance.description,
354
370
  stdout: "",
355
371
  stderr: "",
372
+ outputPath: logPath,
356
373
  subagentId: instance.subagentId,
357
374
  onStop: () => {
375
+ instance.logStream?.end();
358
376
  instance.aiManager.abortAIMessage();
359
377
  this.cleanupInstance(instance.subagentId);
360
378
  },
@@ -446,6 +464,7 @@ export class SubagentManager {
446
464
 
447
465
  // If this was transitioned to background, update the background task
448
466
  if (instance.backgroundTaskId && backgroundTaskManager) {
467
+ instance.logStream?.end();
449
468
  const task = backgroundTaskManager.getTask(instance.backgroundTaskId);
450
469
  if (task) {
451
470
  task.status = "completed";
@@ -465,6 +484,7 @@ export class SubagentManager {
465
484
 
466
485
  // If this was transitioned to background, update the background task with error
467
486
  if (instance.backgroundTaskId && backgroundTaskManager) {
487
+ instance.logStream?.end();
468
488
  const task = backgroundTaskManager.getTask(instance.backgroundTaskId);
469
489
  if (task) {
470
490
  task.status = "failed";
@@ -599,6 +619,17 @@ export class SubagentManager {
599
619
  instance.lastTools.shift();
600
620
  }
601
621
  instance.onUpdate?.();
622
+
623
+ // Log tool execution to file
624
+ if (instance.logStream) {
625
+ const compactParams = (params.parameters || "{}").substring(
626
+ 0,
627
+ 100,
628
+ );
629
+ instance.logStream.write(
630
+ `[${new Date().toISOString()}] Running tool: ${params.name} with params: ${compactParams}${compactParams.length >= 100 ? "..." : ""}\n`,
631
+ );
632
+ }
602
633
  }
603
634
  }
604
635
 
@@ -182,10 +182,14 @@ When using the Agent tool, you must specify a subagent_type parameter to select
182
182
  id: instance.subagentId,
183
183
  backgroundHandler: async () => {
184
184
  isBackgrounded = true;
185
- await subagentManager.backgroundInstance(instance.subagentId);
185
+ const taskId = await subagentManager.backgroundInstance(
186
+ instance.subagentId,
187
+ );
188
+ const task = context.backgroundTaskManager?.getTask(taskId);
189
+ const outputPath = task?.outputPath;
186
190
  resolve({
187
191
  success: true,
188
- content: "Agent backgrounded",
192
+ content: `Agent backgrounded with ID: ${taskId}.${outputPath ? ` Real-time output: ${outputPath}` : ""}`,
189
193
  shortResult: "Agent backgrounded",
190
194
  isManuallyBackgrounded: true,
191
195
  });
@@ -206,9 +210,11 @@ When using the Agent tool, you must specify a subagent_type parameter to select
206
210
  }
207
211
 
208
212
  if (run_in_background) {
213
+ const task = context.backgroundTaskManager?.getTask(result);
214
+ const outputPath = task?.outputPath;
209
215
  resolve({
210
216
  success: true,
211
- content: `Agent started in background with ID: ${result}`,
217
+ content: `Agent started in background with ID: ${result}.${outputPath ? ` Real-time output: ${outputPath}` : ""}`,
212
218
  shortResult: `Agent started in background: ${result}`,
213
219
  });
214
220
  return;
@@ -177,9 +177,11 @@ Usage notes:
177
177
  }
178
178
 
179
179
  const { id: taskId } = backgroundTaskManager.startShell(command, timeout);
180
+ const task = backgroundTaskManager.getTask(taskId);
181
+ const outputPath = task?.outputPath;
180
182
  return {
181
183
  success: true,
182
- content: `Command started in background with ID: ${taskId}. Use TaskOutput tool with task_id="${taskId}" to monitor output.`,
184
+ content: `Command started in background with ID: ${taskId}.${outputPath ? ` Real-time output: ${outputPath}` : ` Use TaskOutput tool with task_id="${taskId}" to monitor output.`}`,
183
185
  shortResult: `Background process ${taskId} started`,
184
186
  };
185
187
  }
@@ -220,9 +222,11 @@ Usage notes:
220
222
  outputBuffer,
221
223
  errorBuffer,
222
224
  );
225
+ const task = backgroundTaskManager.getTask(taskId);
226
+ const outputPath = task?.outputPath;
223
227
  resolve({
224
228
  success: true,
225
- content: `Command moved to background with ID: ${taskId}.`,
229
+ content: `Command moved to background with ID: ${taskId}.${outputPath ? ` Real-time output: ${outputPath}` : ""}`,
226
230
  shortResult: `Process ${taskId} backgrounded`,
227
231
  isManuallyBackgrounded: true,
228
232
  });
@@ -1,70 +1,13 @@
1
- import { spawn } from "child_process";
2
- import { rgPath } from "../utils/ripgrep.js";
1
+ import { glob } from "glob";
3
2
  import { stat } from "fs/promises";
4
3
  import type { ToolPlugin, ToolResult, ToolContext } from "./types.js";
5
4
  import { resolvePath, getDisplayPath } from "../utils/path.js";
6
- import { getAllIgnorePatterns } from "../utils/fileFilter.js";
7
5
  import { GLOB_TOOL_NAME } from "../constants/tools.js";
8
6
 
9
7
  /**
10
8
  * Maximum number of files returned by glob tool
11
9
  */
12
- const MAX_GLOB_RESULTS = 1000;
13
-
14
- /**
15
- * Execute ripgrep to find files matching a pattern
16
- */
17
- async function runRipgrep(pattern: string, workdir: string): Promise<string[]> {
18
- if (!rgPath) {
19
- throw new Error("ripgrep is not available");
20
- }
21
-
22
- const ignorePatterns = getAllIgnorePatterns();
23
- const rgArgs = ["--files", "--color=never", "--hidden", "--glob", pattern];
24
-
25
- for (const ignorePattern of ignorePatterns) {
26
- rgArgs.push("--glob", `!${ignorePattern}`);
27
- }
28
-
29
- return new Promise<string[]>((resolve, reject) => {
30
- const child = spawn(rgPath, rgArgs, {
31
- cwd: workdir,
32
- stdio: ["ignore", "pipe", "pipe"],
33
- });
34
-
35
- let stdout = "";
36
- let stderr = "";
37
-
38
- child.stdout?.on("data", (data) => {
39
- stdout += data.toString();
40
- });
41
-
42
- child.stderr?.on("data", (data) => {
43
- stderr += data.toString();
44
- });
45
-
46
- child.on("close", (code) => {
47
- if (code !== 0 && code !== 1) {
48
- reject(
49
- new Error(
50
- `ripgrep failed with code ${code}: ${stderr || "Unknown error"}`,
51
- ),
52
- );
53
- return;
54
- }
55
- const files = stdout
56
- .trim()
57
- .split("\n")
58
- .filter((f) => f.length > 0)
59
- .map((f) => f.replace(/\\/g, "/")); // Normalize to forward slashes
60
- resolve(files);
61
- });
62
-
63
- child.on("error", (err) => {
64
- reject(err);
65
- });
66
- });
67
- }
10
+ const MAX_GLOB_RESULTS = 100;
68
11
 
69
12
  /**
70
13
  * Glob Tool Plugin - Fast file pattern matching
@@ -122,8 +65,13 @@ export const globTool: ToolPlugin = {
122
65
  ? resolvePath(searchPath, context.workdir)
123
66
  : context.workdir;
124
67
 
125
- // Execute glob search using ripgrep
126
- const matches = await runRipgrep(pattern, workdir);
68
+ // Execute glob search using glob package
69
+ const matches = await glob(pattern, {
70
+ cwd: workdir,
71
+ nodir: true,
72
+ dot: true,
73
+ ignore: ["**/.git/**"],
74
+ });
127
75
 
128
76
  if (matches.length === 0) {
129
77
  return {
@@ -1,6 +1,5 @@
1
1
  import type { ToolPlugin, ToolResult, ToolContext } from "./types.js";
2
2
  import { spawn } from "child_process";
3
- import { getAllIgnorePatterns } from "../utils/fileFilter.js";
4
3
  import { rgPath } from "../utils/ripgrep.js";
5
4
  import { getDisplayPath } from "../utils/path.js";
6
5
  import {
@@ -188,12 +187,6 @@ export const grepTool: ToolPlugin = {
188
187
  rgArgs.push("--glob", globPattern);
189
188
  }
190
189
 
191
- // Get common ignore rules
192
- const ignorePatterns = getAllIgnorePatterns();
193
- for (const exclude of ignorePatterns) {
194
- rgArgs.push("--glob", `!${exclude}`);
195
- }
196
-
197
190
  // Add search pattern - use -e parameter to avoid patterns starting with - being mistaken as command line options
198
191
  rgArgs.push("-e", pattern);
199
192
 
@@ -34,6 +34,10 @@ export interface BackgroundTaskBase {
34
34
  * Used for cleanup when the task is stopped.
35
35
  */
36
36
  subagentId?: string;
37
+ /**
38
+ * Optional path to the real-time output log file.
39
+ */
40
+ outputPath?: string;
37
41
  }
38
42
 
39
43
  export interface BackgroundShell extends BackgroundTaskBase {
@@ -1,7 +1,6 @@
1
1
  import { spawn } from "child_process";
2
2
  import { rgPath } from "./ripgrep.js";
3
3
  import fuzzysort from "fuzzysort";
4
- import { getAllIgnorePatterns } from "./fileFilter.js";
5
4
  import type { FileItem } from "../types/fileSearch.js";
6
5
  import { logger } from "./globalLogger.js";
7
6
 
@@ -13,11 +12,7 @@ async function getAllFiles(workingDirectory: string): Promise<string[]> {
13
12
  throw new Error("ripgrep is not available");
14
13
  }
15
14
 
16
- const ignorePatterns = getAllIgnorePatterns();
17
15
  const rgArgs = ["--files", "--color=never", "--hidden"];
18
- for (const pattern of ignorePatterns) {
19
- rgArgs.push("--glob", `!${pattern}`);
20
- }
21
16
 
22
17
  return new Promise((resolve, reject) => {
23
18
  const child = spawn(rgPath, rgArgs, {
@@ -97,13 +97,29 @@ export class OpenAIClient {
97
97
  await new Promise((resolve) => setTimeout(resolve, delay));
98
98
  }
99
99
 
100
- const response = await fetchFn(url, {
101
- method: "POST",
102
- headers,
103
- body: JSON.stringify(params),
104
- signal: options?.signal,
105
- ...(fetchOptions as RequestInit),
106
- });
100
+ let response: Response;
101
+ try {
102
+ response = await fetchFn(url, {
103
+ method: "POST",
104
+ headers,
105
+ body: JSON.stringify(params),
106
+ signal: options?.signal,
107
+ ...(fetchOptions as RequestInit),
108
+ });
109
+ } catch (e) {
110
+ if (e instanceof Error && e.name === "AbortError") {
111
+ throw e;
112
+ }
113
+ if (attempt < maxRetries) {
114
+ logger.warn("OpenAI API network error, retrying...", {
115
+ attempt: attempt + 1,
116
+ error: e,
117
+ });
118
+ lastError = e as Error;
119
+ continue;
120
+ }
121
+ throw e;
122
+ }
107
123
 
108
124
  if (response.ok) {
109
125
  if (params.stream) {
@@ -1,15 +0,0 @@
1
- /**
2
- * Common ignore directory and file patterns
3
- * Can be reused by multiple tools (glob, ripgrep, etc.)
4
- */
5
- export declare const COMMON_IGNORE_PATTERNS: {
6
- dependencies: string[];
7
- cache: string[];
8
- editor: string[];
9
- os: string[];
10
- };
11
- /**
12
- * Get flat array of all common ignore patterns
13
- */
14
- export declare const getAllIgnorePatterns: () => string[];
15
- //# sourceMappingURL=fileFilter.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"fileFilter.d.ts","sourceRoot":"","sources":["../../src/utils/fileFilter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,sBAAsB;;;;;CAsBlC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,oBAAoB,QAAO,MAAM,EAO7C,CAAC"}
@@ -1,35 +0,0 @@
1
- /**
2
- * Common ignore directory and file patterns
3
- * Can be reused by multiple tools (glob, ripgrep, etc.)
4
- */
5
- export const COMMON_IGNORE_PATTERNS = {
6
- // Dependencies and build directories
7
- dependencies: [
8
- "node_modules/**",
9
- ".git/**",
10
- "dist/**",
11
- "build/**",
12
- ".next/**",
13
- "coverage/**",
14
- ".nyc_output/**",
15
- "tmp/**",
16
- "temp/**",
17
- ],
18
- // Cache and temporary files
19
- cache: ["*.log", "*.cache", ".DS_Store", "Thumbs.db", "*~", "*.swp", "*.swo"],
20
- // Editor and IDE files
21
- editor: [".vscode/**", ".idea/**", "*.sublime-*"],
22
- // Operating system related
23
- os: [".DS_Store", "Thumbs.db", "desktop.ini"],
24
- };
25
- /**
26
- * Get flat array of all common ignore patterns
27
- */
28
- export const getAllIgnorePatterns = () => {
29
- return [
30
- ...COMMON_IGNORE_PATTERNS.dependencies,
31
- ...COMMON_IGNORE_PATTERNS.cache,
32
- ...COMMON_IGNORE_PATTERNS.editor,
33
- ...COMMON_IGNORE_PATTERNS.os,
34
- ];
35
- };
@@ -1,39 +0,0 @@
1
- /**
2
- * Common ignore directory and file patterns
3
- * Can be reused by multiple tools (glob, ripgrep, etc.)
4
- */
5
- export const COMMON_IGNORE_PATTERNS = {
6
- // Dependencies and build directories
7
- dependencies: [
8
- "node_modules/**",
9
- ".git/**",
10
- "dist/**",
11
- "build/**",
12
- ".next/**",
13
- "coverage/**",
14
- ".nyc_output/**",
15
- "tmp/**",
16
- "temp/**",
17
- ],
18
-
19
- // Cache and temporary files
20
- cache: ["*.log", "*.cache", ".DS_Store", "Thumbs.db", "*~", "*.swp", "*.swo"],
21
-
22
- // Editor and IDE files
23
- editor: [".vscode/**", ".idea/**", "*.sublime-*"],
24
-
25
- // Operating system related
26
- os: [".DS_Store", "Thumbs.db", "desktop.ini"],
27
- };
28
-
29
- /**
30
- * Get flat array of all common ignore patterns
31
- */
32
- export const getAllIgnorePatterns = (): string[] => {
33
- return [
34
- ...COMMON_IGNORE_PATTERNS.dependencies,
35
- ...COMMON_IGNORE_PATTERNS.cache,
36
- ...COMMON_IGNORE_PATTERNS.editor,
37
- ...COMMON_IGNORE_PATTERNS.os,
38
- ];
39
- };