wave-agent-sdk 0.9.1 → 0.9.2
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/managers/permissionManager.d.ts +5 -0
- package/dist/managers/permissionManager.d.ts.map +1 -1
- package/dist/managers/permissionManager.js +18 -0
- package/dist/services/initializationService.d.ts.map +1 -1
- package/dist/services/initializationService.js +8 -0
- package/dist/services/memory.d.ts.map +1 -1
- package/dist/services/memory.js +4 -1
- package/dist/tools/globTool.d.ts.map +1 -1
- package/dist/tools/globTool.js +48 -11
- package/dist/tools/grepTool.js +2 -2
- package/dist/utils/containerSetup.js +1 -1
- package/dist/utils/fileFilter.d.ts +0 -11
- package/dist/utils/fileFilter.d.ts.map +1 -1
- package/dist/utils/fileFilter.js +0 -142
- package/dist/utils/fileSearch.js +2 -2
- package/dist/utils/messageOperations.js +4 -2
- package/package.json +1 -1
- package/src/managers/permissionManager.ts +22 -0
- package/src/services/initializationService.ts +11 -0
- package/src/services/memory.ts +5 -1
- package/src/tools/globTool.ts +61 -11
- package/src/tools/grepTool.ts +2 -2
- package/src/utils/containerSetup.ts +1 -1
- package/src/utils/fileFilter.ts +0 -163
- package/src/utils/fileSearch.ts +2 -2
- package/src/utils/messageOperations.ts +2 -2
|
@@ -31,6 +31,7 @@ export declare class PermissionManager {
|
|
|
31
31
|
private deniedRules;
|
|
32
32
|
private temporaryRules;
|
|
33
33
|
private additionalDirectories;
|
|
34
|
+
private systemAdditionalDirectories;
|
|
34
35
|
private workdir?;
|
|
35
36
|
private planFilePath?;
|
|
36
37
|
private onConfiguredDefaultModeChange?;
|
|
@@ -84,6 +85,10 @@ export declare class PermissionManager {
|
|
|
84
85
|
* Update the additional directories (e.g., when configuration reloads)
|
|
85
86
|
*/
|
|
86
87
|
updateAdditionalDirectories(directories: string[]): void;
|
|
88
|
+
/**
|
|
89
|
+
* Add a system-level additional directory that is persistent across configuration reloads
|
|
90
|
+
*/
|
|
91
|
+
addSystemAdditionalDirectory(directory: string): void;
|
|
87
92
|
/**
|
|
88
93
|
* Update the working directory
|
|
89
94
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"permissionManager.d.ts","sourceRoot":"","sources":["../../src/managers/permissionManager.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EACV,kBAAkB,EAClB,qBAAqB,EACrB,kBAAkB,EAClB,cAAc,EACf,MAAM,yBAAyB,CAAC;AAEjC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAgBhD,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AA8BlD,MAAM,WAAW,wBAAwB;IACvC,uDAAuD;IACvD,qBAAqB,CAAC,EAAE,cAAc,CAAC;IACvC,kCAAkC;IAClC,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,iCAAiC;IACjC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,8DAA8D;IAC9D,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;IACjC,iCAAiC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oCAAoC;IACpC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sBAAsB;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,iBAAiB;
|
|
1
|
+
{"version":3,"file":"permissionManager.d.ts","sourceRoot":"","sources":["../../src/managers/permissionManager.ts"],"names":[],"mappings":"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"}
|
|
@@ -42,6 +42,7 @@ export class PermissionManager {
|
|
|
42
42
|
this.deniedRules = [];
|
|
43
43
|
this.temporaryRules = [];
|
|
44
44
|
this.additionalDirectories = [];
|
|
45
|
+
this.systemAdditionalDirectories = [];
|
|
45
46
|
this.configuredDefaultMode = options.configuredDefaultMode;
|
|
46
47
|
this.allowedRules = options.allowedRules || [];
|
|
47
48
|
this.deniedRules = options.deniedRules || [];
|
|
@@ -133,6 +134,17 @@ export class PermissionManager {
|
|
|
133
134
|
return path.resolve(dir);
|
|
134
135
|
});
|
|
135
136
|
}
|
|
137
|
+
/**
|
|
138
|
+
* Add a system-level additional directory that is persistent across configuration reloads
|
|
139
|
+
*/
|
|
140
|
+
addSystemAdditionalDirectory(directory) {
|
|
141
|
+
const resolvedPath = this.workdir && !path.isAbsolute(directory)
|
|
142
|
+
? path.resolve(this.workdir, directory)
|
|
143
|
+
: path.resolve(directory);
|
|
144
|
+
if (!this.systemAdditionalDirectories.includes(resolvedPath)) {
|
|
145
|
+
this.systemAdditionalDirectories.push(resolvedPath);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
136
148
|
/**
|
|
137
149
|
* Update the working directory
|
|
138
150
|
*/
|
|
@@ -170,6 +182,12 @@ export class PermissionManager {
|
|
|
170
182
|
return { isInside: true, resolvedPath: absolutePath };
|
|
171
183
|
}
|
|
172
184
|
}
|
|
185
|
+
// Check system additional directories
|
|
186
|
+
for (const dir of this.systemAdditionalDirectories) {
|
|
187
|
+
if (isPathInside(absolutePath, dir)) {
|
|
188
|
+
return { isInside: true, resolvedPath: absolutePath };
|
|
189
|
+
}
|
|
190
|
+
}
|
|
173
191
|
return { isInside: false, resolvedPath: absolutePath };
|
|
174
192
|
}
|
|
175
193
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"initializationService.d.ts","sourceRoot":"","sources":["../../src/services/initializationService.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,OAAO,EACP,MAAM,EACN,YAAY,EACZ,WAAW,EACZ,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACtE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAC9E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACtE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AACpE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AAC1E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AAC1E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAIpD,MAAM,WAAW,qBAAqB;IACpC,YAAY,EAAE,YAAY,CAAC;IAC3B,eAAe,EAAE,eAAe,CAAC;IACjC,SAAS,EAAE,SAAS,CAAC;IACrB,WAAW,EAAE,WAAW,CAAC;IACzB,aAAa,EAAE,aAAa,CAAC;IAC7B,OAAO,EAAE,YAAY,CAAC;IACtB,mBAAmB,EAAE,mBAAmB,CAAC;IACzC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,UAAU,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,WAAW,CAAC;IACxB,oBAAoB,EAAE,oBAAoB,CAAC;IAC3C,WAAW,EAAE,WAAW,CAAC;IACzB,cAAc,EAAE,cAAc,CAAC;IAC/B,iBAAiB,EAAE,iBAAiB,CAAC;IACrC,iBAAiB,EAAE,iBAAiB,CAAC;IACrC,WAAW,EAAE,WAAW,CAAC;IACzB,gBAAgB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,wBAAwB,EAAE,MAAM,IAAI,CAAC;CACtC;AAED,qBAAa,qBAAqB;WACZ,UAAU,CAC5B,OAAO,EAAE,qBAAqB,EAC9B,OAAO,CAAC,EAAE;QACR,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,mBAAmB,CAAC,EAAE,OAAO,CAAC;QAC9B,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC;KACtB,GACA,OAAO,CAAC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"initializationService.d.ts","sourceRoot":"","sources":["../../src/services/initializationService.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,OAAO,EACP,MAAM,EACN,YAAY,EACZ,WAAW,EACZ,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACtE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAC9E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACtE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AACpE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AAC1E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AAC1E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAIpD,MAAM,WAAW,qBAAqB;IACpC,YAAY,EAAE,YAAY,CAAC;IAC3B,eAAe,EAAE,eAAe,CAAC;IACjC,SAAS,EAAE,SAAS,CAAC;IACrB,WAAW,EAAE,WAAW,CAAC;IACzB,aAAa,EAAE,aAAa,CAAC;IAC7B,OAAO,EAAE,YAAY,CAAC;IACtB,mBAAmB,EAAE,mBAAmB,CAAC;IACzC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,UAAU,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,WAAW,CAAC;IACxB,oBAAoB,EAAE,oBAAoB,CAAC;IAC3C,WAAW,EAAE,WAAW,CAAC;IACzB,cAAc,EAAE,cAAc,CAAC;IAC/B,iBAAiB,EAAE,iBAAiB,CAAC;IACrC,iBAAiB,EAAE,iBAAiB,CAAC;IACrC,WAAW,EAAE,WAAW,CAAC;IACzB,gBAAgB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,wBAAwB,EAAE,MAAM,IAAI,CAAC;CACtC;AAED,qBAAa,qBAAqB;WACZ,UAAU,CAC5B,OAAO,EAAE,qBAAqB,EAC9B,OAAO,CAAC,EAAE;QACR,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,mBAAmB,CAAC,EAAE,OAAO,CAAC;QAC9B,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC;KACtB,GACA,OAAO,CAAC,IAAI,CAAC;CAgPjB"}
|
|
@@ -57,6 +57,9 @@ export class InitializationService {
|
|
|
57
57
|
if (configResult.configuration.permissions.defaultMode) {
|
|
58
58
|
permissionManager.updateConfiguredDefaultMode(configResult.configuration.permissions.defaultMode);
|
|
59
59
|
}
|
|
60
|
+
if (configResult.configuration.permissions.additionalDirectories) {
|
|
61
|
+
permissionManager.updateAdditionalDirectories(configResult.configuration.permissions.additionalDirectories);
|
|
62
|
+
}
|
|
60
63
|
}
|
|
61
64
|
}
|
|
62
65
|
}
|
|
@@ -93,6 +96,11 @@ export class InitializationService {
|
|
|
93
96
|
const memoryService = container.get("MemoryService");
|
|
94
97
|
if (memoryService) {
|
|
95
98
|
await memoryService.ensureAutoMemoryDirectory(workdir);
|
|
99
|
+
const permissionManager = container.get("PermissionManager");
|
|
100
|
+
if (permissionManager) {
|
|
101
|
+
const autoMemoryDir = memoryService.getAutoMemoryDirectory(workdir);
|
|
102
|
+
permissionManager.addSystemAdditionalDirectory(autoMemoryDir);
|
|
103
|
+
}
|
|
96
104
|
}
|
|
97
105
|
}
|
|
98
106
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/services/memory.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAIlD,qBAAa,aAAa;IACZ,OAAO,CAAC,SAAS;gBAAT,SAAS,EAAE,SAAS;IAExC;;;OAGG;IACH,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;
|
|
1
|
+
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/services/memory.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAIlD,qBAAa,aAAa;IACZ,OAAO,CAAC,SAAS;gBAAT,SAAS,EAAE,SAAS;IAExC;;;OAGG;IACH,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAU/C;;OAEG;IACG,yBAAyB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA2B/D;;OAEG;IACG,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAiBtD,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC;IA8BrC,oBAAoB,IAAI,OAAO,CAAC,MAAM,CAAC;IAevC,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAuBhD,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAqBjE"}
|
package/dist/services/memory.js
CHANGED
|
@@ -14,7 +14,10 @@ export class MemoryService {
|
|
|
14
14
|
* Uses the git common directory to ensure worktrees share the same memory.
|
|
15
15
|
*/
|
|
16
16
|
getAutoMemoryDirectory(workdir) {
|
|
17
|
-
const
|
|
17
|
+
const commonDir = getGitCommonDir(workdir);
|
|
18
|
+
// If the common directory is a .git directory, use its parent as the project root
|
|
19
|
+
// for a cleaner encoded name while maintaining stability across worktrees.
|
|
20
|
+
const projectRoot = path.basename(commonDir) === ".git" ? path.dirname(commonDir) : commonDir;
|
|
18
21
|
const encodedName = pathEncoder.encodeSync(projectRoot);
|
|
19
22
|
return path.join(homedir(), ".wave", "projects", encodedName, "memory");
|
|
20
23
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"globTool.d.ts","sourceRoot":"","sources":["../../src/tools/globTool.ts"],"names":[],"mappings":"
|
|
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"}
|
package/dist/tools/globTool.js
CHANGED
|
@@ -1,12 +1,55 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { spawn } from "child_process";
|
|
2
|
+
import { rgPath } from "@vscode/ripgrep";
|
|
2
3
|
import { stat } from "fs/promises";
|
|
3
4
|
import { resolvePath, getDisplayPath } from "../utils/path.js";
|
|
4
|
-
import {
|
|
5
|
+
import { getAllIgnorePatterns } from "../utils/fileFilter.js";
|
|
5
6
|
import { GLOB_TOOL_NAME } from "../constants/tools.js";
|
|
6
7
|
/**
|
|
7
8
|
* Maximum number of files returned by glob tool
|
|
8
9
|
*/
|
|
9
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
|
+
}
|
|
10
53
|
/**
|
|
11
54
|
* Glob Tool Plugin - Fast file pattern matching
|
|
12
55
|
*/
|
|
@@ -54,14 +97,8 @@ export const globTool = {
|
|
|
54
97
|
const workdir = searchPath
|
|
55
98
|
? resolvePath(searchPath, context.workdir)
|
|
56
99
|
: context.workdir;
|
|
57
|
-
// Execute glob search
|
|
58
|
-
const matches = await
|
|
59
|
-
cwd: workdir,
|
|
60
|
-
ignore: getGlobIgnorePatterns(workdir),
|
|
61
|
-
dot: false,
|
|
62
|
-
absolute: false,
|
|
63
|
-
nocase: false, // Keep case sensitive
|
|
64
|
-
});
|
|
100
|
+
// Execute glob search using ripgrep
|
|
101
|
+
const matches = await runRipgrep(pattern, workdir);
|
|
65
102
|
if (matches.length === 0) {
|
|
66
103
|
return {
|
|
67
104
|
success: true,
|
|
@@ -72,7 +109,7 @@ export const globTool = {
|
|
|
72
109
|
// Get file modification time and sort
|
|
73
110
|
const filesWithStats = await Promise.allSettled(matches.map(async (file) => {
|
|
74
111
|
try {
|
|
75
|
-
const fullPath = resolvePath(file,
|
|
112
|
+
const fullPath = resolvePath(file, workdir);
|
|
76
113
|
const stats = await stat(fullPath);
|
|
77
114
|
return {
|
|
78
115
|
path: file,
|
package/dist/tools/grepTool.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { spawn } from "child_process";
|
|
2
|
-
import {
|
|
2
|
+
import { getAllIgnorePatterns } from "../utils/fileFilter.js";
|
|
3
3
|
import { rgPath } from "@vscode/ripgrep";
|
|
4
4
|
import { getDisplayPath } from "../utils/path.js";
|
|
5
5
|
import { GREP_TOOL_NAME, BASH_TOOL_NAME, AGENT_TOOL_NAME, } from "../constants/tools.js";
|
|
@@ -158,7 +158,7 @@ export const grepTool = {
|
|
|
158
158
|
rgArgs.push("--glob", globPattern);
|
|
159
159
|
}
|
|
160
160
|
// Get common ignore rules
|
|
161
|
-
const ignorePatterns =
|
|
161
|
+
const ignorePatterns = getAllIgnorePatterns();
|
|
162
162
|
for (const exclude of ignorePatterns) {
|
|
163
163
|
rgArgs.push("--glob", `!${exclude}`);
|
|
164
164
|
}
|
|
@@ -78,7 +78,7 @@ export function setupAgentContainer(setupOptions) {
|
|
|
78
78
|
const permissionManager = new PermissionManager(container, { workdir });
|
|
79
79
|
if (configurationService.resolveAutoMemoryEnabled()) {
|
|
80
80
|
const autoMemoryDir = memoryService.getAutoMemoryDirectory(workdir);
|
|
81
|
-
permissionManager.
|
|
81
|
+
permissionManager.addSystemAdditionalDirectory(autoMemoryDir);
|
|
82
82
|
}
|
|
83
83
|
container.register("PermissionManager", permissionManager);
|
|
84
84
|
permissionManager.setOnConfiguredDefaultModeChange((mode) => {
|
|
@@ -12,15 +12,4 @@ export declare const COMMON_IGNORE_PATTERNS: {
|
|
|
12
12
|
* Get flat array of all common ignore patterns
|
|
13
13
|
*/
|
|
14
14
|
export declare const getAllIgnorePatterns: () => string[];
|
|
15
|
-
/**
|
|
16
|
-
* Parse all .gitignore files in the working directory and its subdirectories and convert to glob patterns
|
|
17
|
-
* @param workdir Working directory
|
|
18
|
-
* @returns Array of glob ignore patterns
|
|
19
|
-
*/
|
|
20
|
-
export declare const parseGitignoreToGlob: (workdir: string) => string[];
|
|
21
|
-
/**
|
|
22
|
-
* Get ignore patterns for glob search
|
|
23
|
-
* @param workdir Working directory for resolving .gitignore files
|
|
24
|
-
*/
|
|
25
|
-
export declare const getGlobIgnorePatterns: (workdir?: string) => string[];
|
|
26
15
|
//# sourceMappingURL=fileFilter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fileFilter.d.ts","sourceRoot":"","sources":["../../src/utils/fileFilter.ts"],"names":[],"mappings":"
|
|
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"}
|
package/dist/utils/fileFilter.js
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import * as fs from "fs";
|
|
2
|
-
import * as path from "path";
|
|
3
1
|
/**
|
|
4
2
|
* Common ignore directory and file patterns
|
|
5
3
|
* Can be reused by multiple tools (glob, ripgrep, etc.)
|
|
@@ -35,143 +33,3 @@ export const getAllIgnorePatterns = () => {
|
|
|
35
33
|
...COMMON_IGNORE_PATTERNS.os,
|
|
36
34
|
];
|
|
37
35
|
};
|
|
38
|
-
/**
|
|
39
|
-
* Recursively find all .gitignore files in directory
|
|
40
|
-
* @param dir Directory to search
|
|
41
|
-
* @param maxDepth Maximum recursion depth to prevent too deep searches
|
|
42
|
-
* @returns Array of .gitignore file paths
|
|
43
|
-
*/
|
|
44
|
-
const findAllGitignoreFiles = (dir, maxDepth = 5) => {
|
|
45
|
-
const gitignoreFiles = [];
|
|
46
|
-
if (maxDepth <= 0)
|
|
47
|
-
return gitignoreFiles;
|
|
48
|
-
try {
|
|
49
|
-
const items = fs.readdirSync(dir, { withFileTypes: true });
|
|
50
|
-
for (const item of items) {
|
|
51
|
-
const fullPath = path.join(dir, item.name);
|
|
52
|
-
if (item.isFile() && item.name === ".gitignore") {
|
|
53
|
-
gitignoreFiles.push(fullPath);
|
|
54
|
-
}
|
|
55
|
-
else if (item.isDirectory() && !shouldSkipDirectory(item.name)) {
|
|
56
|
-
// Recursively search subdirectories, but skip some obviously unnecessary directories
|
|
57
|
-
gitignoreFiles.push(...findAllGitignoreFiles(fullPath, maxDepth - 1));
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
catch {
|
|
62
|
-
// Ignore permission errors and other issues
|
|
63
|
-
}
|
|
64
|
-
return gitignoreFiles;
|
|
65
|
-
};
|
|
66
|
-
/**
|
|
67
|
-
* Determine whether to skip searching a directory
|
|
68
|
-
*/
|
|
69
|
-
const shouldSkipDirectory = (dirName) => {
|
|
70
|
-
const skipDirs = [
|
|
71
|
-
"node_modules",
|
|
72
|
-
".git",
|
|
73
|
-
"dist",
|
|
74
|
-
"build",
|
|
75
|
-
".next",
|
|
76
|
-
"coverage",
|
|
77
|
-
".nyc_output",
|
|
78
|
-
"tmp",
|
|
79
|
-
"temp",
|
|
80
|
-
".cache",
|
|
81
|
-
];
|
|
82
|
-
return skipDirs.includes(dirName);
|
|
83
|
-
};
|
|
84
|
-
/**
|
|
85
|
-
* Parse single .gitignore file content
|
|
86
|
-
* @param gitignorePath .gitignore file path
|
|
87
|
-
* @param basePath Base path for calculating relative paths
|
|
88
|
-
* @returns Array of parsed glob patterns
|
|
89
|
-
*/
|
|
90
|
-
const parseGitignoreFile = (gitignorePath, basePath) => {
|
|
91
|
-
const patterns = [];
|
|
92
|
-
try {
|
|
93
|
-
if (fs.existsSync(gitignorePath)) {
|
|
94
|
-
const gitignoreContent = fs.readFileSync(gitignorePath, "utf8");
|
|
95
|
-
const gitignoreDir = path.dirname(gitignorePath);
|
|
96
|
-
// Calculate relative directory relative to base path
|
|
97
|
-
const relativeDirFromBase = path.relative(basePath, gitignoreDir);
|
|
98
|
-
const lines = gitignoreContent
|
|
99
|
-
.split("\n")
|
|
100
|
-
.map((line) => line.trim())
|
|
101
|
-
.filter((line) => line && !line.startsWith("#"));
|
|
102
|
-
for (const line of lines) {
|
|
103
|
-
// Skip negation rules (starting with !)
|
|
104
|
-
if (line.startsWith("!")) {
|
|
105
|
-
continue;
|
|
106
|
-
}
|
|
107
|
-
let pattern = line;
|
|
108
|
-
// Handle patterns starting with / (relative to current .gitignore file directory)
|
|
109
|
-
if (pattern.startsWith("/")) {
|
|
110
|
-
pattern = pattern.slice(1); // Remove leading /
|
|
111
|
-
}
|
|
112
|
-
// If .gitignore is in subdirectory, need to add path prefix
|
|
113
|
-
if (relativeDirFromBase && relativeDirFromBase !== ".") {
|
|
114
|
-
pattern = path.posix.join(relativeDirFromBase, pattern);
|
|
115
|
-
}
|
|
116
|
-
// If directory pattern (ending with /)
|
|
117
|
-
if (pattern.endsWith("/")) {
|
|
118
|
-
const dirName = pattern.slice(0, -1);
|
|
119
|
-
// For directory patterns, add both exact match and wildcard match
|
|
120
|
-
patterns.push(`${dirName}/**`); // Directory and all its sub-content
|
|
121
|
-
// If no path separators, it's a simple directory name, add global match
|
|
122
|
-
if (!dirName.includes("/") && !dirName.includes("*")) {
|
|
123
|
-
patterns.push(`**/${dirName}/**`); // Match directories of same name at any level
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
else {
|
|
127
|
-
// File pattern
|
|
128
|
-
patterns.push(pattern);
|
|
129
|
-
// If no wildcards and no extension, also treat as directory
|
|
130
|
-
if (!pattern.includes("*") && !pattern.includes(".")) {
|
|
131
|
-
patterns.push(`${pattern}/**`);
|
|
132
|
-
// Also add global match for simple directory names
|
|
133
|
-
if (!pattern.includes("/")) {
|
|
134
|
-
patterns.push(`**/${pattern}/**`);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
catch {
|
|
142
|
-
// Ignore errors when reading .gitignore files
|
|
143
|
-
}
|
|
144
|
-
return patterns;
|
|
145
|
-
};
|
|
146
|
-
/**
|
|
147
|
-
* Parse all .gitignore files in the working directory and its subdirectories and convert to glob patterns
|
|
148
|
-
* @param workdir Working directory
|
|
149
|
-
* @returns Array of glob ignore patterns
|
|
150
|
-
*/
|
|
151
|
-
export const parseGitignoreToGlob = (workdir) => {
|
|
152
|
-
const patterns = [];
|
|
153
|
-
try {
|
|
154
|
-
// Find all .gitignore files
|
|
155
|
-
const gitignoreFiles = findAllGitignoreFiles(workdir);
|
|
156
|
-
// Parse each .gitignore file
|
|
157
|
-
for (const gitignoreFile of gitignoreFiles) {
|
|
158
|
-
patterns.push(...parseGitignoreFile(gitignoreFile, workdir));
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
catch {
|
|
162
|
-
// Ignore errors during search process
|
|
163
|
-
}
|
|
164
|
-
return patterns;
|
|
165
|
-
};
|
|
166
|
-
/**
|
|
167
|
-
* Get ignore patterns for glob search
|
|
168
|
-
* @param workdir Working directory for resolving .gitignore files
|
|
169
|
-
*/
|
|
170
|
-
export const getGlobIgnorePatterns = (workdir) => {
|
|
171
|
-
const patterns = getAllIgnorePatterns();
|
|
172
|
-
// If working directory is provided, parse .gitignore files
|
|
173
|
-
if (workdir) {
|
|
174
|
-
patterns.push(...parseGitignoreToGlob(workdir));
|
|
175
|
-
}
|
|
176
|
-
return patterns;
|
|
177
|
-
};
|
package/dist/utils/fileSearch.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { spawn } from "child_process";
|
|
2
2
|
import { rgPath } from "@vscode/ripgrep";
|
|
3
3
|
import fuzzysort from "fuzzysort";
|
|
4
|
-
import {
|
|
4
|
+
import { getAllIgnorePatterns } from "./fileFilter.js";
|
|
5
5
|
import { logger } from "./globalLogger.js";
|
|
6
6
|
/**
|
|
7
7
|
* Execute ripgrep to get all file paths
|
|
@@ -10,7 +10,7 @@ async function getAllFiles(workingDirectory) {
|
|
|
10
10
|
if (!rgPath) {
|
|
11
11
|
throw new Error("ripgrep is not available");
|
|
12
12
|
}
|
|
13
|
-
const ignorePatterns =
|
|
13
|
+
const ignorePatterns = getAllIgnorePatterns();
|
|
14
14
|
const rgArgs = ["--files", "--color=never", "--hidden"];
|
|
15
15
|
for (const pattern of ignorePatterns) {
|
|
16
16
|
rgArgs.push("--glob", `!${pattern}`);
|
|
@@ -108,14 +108,16 @@ export const updateToolBlockInMessage = ({ messages, id, parameters, result, suc
|
|
|
108
108
|
if (toolBlockIndex !== -1) {
|
|
109
109
|
const toolBlock = newMessages[i].blocks[toolBlockIndex];
|
|
110
110
|
if (toolBlock.type === "tool") {
|
|
111
|
-
|
|
111
|
+
if (parameters !== undefined)
|
|
112
|
+
toolBlock.parameters = parameters;
|
|
112
113
|
if (result !== undefined)
|
|
113
114
|
toolBlock.result = result;
|
|
114
115
|
if (shortResult !== undefined)
|
|
115
116
|
toolBlock.shortResult = shortResult;
|
|
116
117
|
if (startLineNumber !== undefined)
|
|
117
118
|
toolBlock.startLineNumber = startLineNumber;
|
|
118
|
-
|
|
119
|
+
if (images !== undefined)
|
|
120
|
+
toolBlock.images = images; // Add image data update
|
|
119
121
|
if (success !== undefined)
|
|
120
122
|
toolBlock.success = success;
|
|
121
123
|
if (error !== undefined)
|
package/package.json
CHANGED
|
@@ -84,6 +84,7 @@ export class PermissionManager {
|
|
|
84
84
|
private deniedRules: string[] = [];
|
|
85
85
|
private temporaryRules: string[] = [];
|
|
86
86
|
private additionalDirectories: string[] = [];
|
|
87
|
+
private systemAdditionalDirectories: string[] = [];
|
|
87
88
|
private workdir?: string;
|
|
88
89
|
private planFilePath?: string;
|
|
89
90
|
private onConfiguredDefaultModeChange?: (mode: PermissionMode) => void;
|
|
@@ -203,6 +204,20 @@ export class PermissionManager {
|
|
|
203
204
|
});
|
|
204
205
|
}
|
|
205
206
|
|
|
207
|
+
/**
|
|
208
|
+
* Add a system-level additional directory that is persistent across configuration reloads
|
|
209
|
+
*/
|
|
210
|
+
public addSystemAdditionalDirectory(directory: string): void {
|
|
211
|
+
const resolvedPath =
|
|
212
|
+
this.workdir && !path.isAbsolute(directory)
|
|
213
|
+
? path.resolve(this.workdir, directory)
|
|
214
|
+
: path.resolve(directory);
|
|
215
|
+
|
|
216
|
+
if (!this.systemAdditionalDirectories.includes(resolvedPath)) {
|
|
217
|
+
this.systemAdditionalDirectories.push(resolvedPath);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
206
221
|
/**
|
|
207
222
|
* Update the working directory
|
|
208
223
|
*/
|
|
@@ -251,6 +266,13 @@ export class PermissionManager {
|
|
|
251
266
|
}
|
|
252
267
|
}
|
|
253
268
|
|
|
269
|
+
// Check system additional directories
|
|
270
|
+
for (const dir of this.systemAdditionalDirectories) {
|
|
271
|
+
if (isPathInside(absolutePath, dir)) {
|
|
272
|
+
return { isInside: true, resolvedPath: absolutePath };
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
254
276
|
return { isInside: false, resolvedPath: absolutePath };
|
|
255
277
|
}
|
|
256
278
|
|
|
@@ -151,6 +151,11 @@ export class InitializationService {
|
|
|
151
151
|
configResult.configuration.permissions.defaultMode,
|
|
152
152
|
);
|
|
153
153
|
}
|
|
154
|
+
if (configResult.configuration.permissions.additionalDirectories) {
|
|
155
|
+
permissionManager.updateAdditionalDirectories(
|
|
156
|
+
configResult.configuration.permissions.additionalDirectories,
|
|
157
|
+
);
|
|
158
|
+
}
|
|
154
159
|
}
|
|
155
160
|
}
|
|
156
161
|
} catch (error) {
|
|
@@ -196,6 +201,12 @@ export class InitializationService {
|
|
|
196
201
|
container.get<import("./memory.js").MemoryService>("MemoryService");
|
|
197
202
|
if (memoryService) {
|
|
198
203
|
await memoryService.ensureAutoMemoryDirectory(workdir);
|
|
204
|
+
const permissionManager =
|
|
205
|
+
container.get<PermissionManager>("PermissionManager");
|
|
206
|
+
if (permissionManager) {
|
|
207
|
+
const autoMemoryDir = memoryService.getAutoMemoryDirectory(workdir);
|
|
208
|
+
permissionManager.addSystemAdditionalDirectory(autoMemoryDir);
|
|
209
|
+
}
|
|
199
210
|
}
|
|
200
211
|
}
|
|
201
212
|
} catch (error) {
|
package/src/services/memory.ts
CHANGED
|
@@ -15,7 +15,11 @@ export class MemoryService {
|
|
|
15
15
|
* Uses the git common directory to ensure worktrees share the same memory.
|
|
16
16
|
*/
|
|
17
17
|
getAutoMemoryDirectory(workdir: string): string {
|
|
18
|
-
const
|
|
18
|
+
const commonDir = getGitCommonDir(workdir);
|
|
19
|
+
// If the common directory is a .git directory, use its parent as the project root
|
|
20
|
+
// for a cleaner encoded name while maintaining stability across worktrees.
|
|
21
|
+
const projectRoot =
|
|
22
|
+
path.basename(commonDir) === ".git" ? path.dirname(commonDir) : commonDir;
|
|
19
23
|
const encodedName = pathEncoder.encodeSync(projectRoot);
|
|
20
24
|
return path.join(homedir(), ".wave", "projects", encodedName, "memory");
|
|
21
25
|
}
|
package/src/tools/globTool.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { spawn } from "child_process";
|
|
2
|
+
import { rgPath } from "@vscode/ripgrep";
|
|
2
3
|
import { stat } from "fs/promises";
|
|
3
4
|
import type { ToolPlugin, ToolResult, ToolContext } from "./types.js";
|
|
4
5
|
import { resolvePath, getDisplayPath } from "../utils/path.js";
|
|
5
|
-
import {
|
|
6
|
+
import { getAllIgnorePatterns } from "../utils/fileFilter.js";
|
|
6
7
|
import { GLOB_TOOL_NAME } from "../constants/tools.js";
|
|
7
8
|
|
|
8
9
|
/**
|
|
@@ -10,6 +11,61 @@ import { GLOB_TOOL_NAME } from "../constants/tools.js";
|
|
|
10
11
|
*/
|
|
11
12
|
const MAX_GLOB_RESULTS = 1000;
|
|
12
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
|
+
}
|
|
68
|
+
|
|
13
69
|
/**
|
|
14
70
|
* Glob Tool Plugin - Fast file pattern matching
|
|
15
71
|
*/
|
|
@@ -66,14 +122,8 @@ export const globTool: ToolPlugin = {
|
|
|
66
122
|
? resolvePath(searchPath, context.workdir)
|
|
67
123
|
: context.workdir;
|
|
68
124
|
|
|
69
|
-
// Execute glob search
|
|
70
|
-
const matches = await
|
|
71
|
-
cwd: workdir,
|
|
72
|
-
ignore: getGlobIgnorePatterns(workdir),
|
|
73
|
-
dot: false,
|
|
74
|
-
absolute: false,
|
|
75
|
-
nocase: false, // Keep case sensitive
|
|
76
|
-
});
|
|
125
|
+
// Execute glob search using ripgrep
|
|
126
|
+
const matches = await runRipgrep(pattern, workdir);
|
|
77
127
|
|
|
78
128
|
if (matches.length === 0) {
|
|
79
129
|
return {
|
|
@@ -87,7 +137,7 @@ export const globTool: ToolPlugin = {
|
|
|
87
137
|
const filesWithStats = await Promise.allSettled(
|
|
88
138
|
matches.map(async (file) => {
|
|
89
139
|
try {
|
|
90
|
-
const fullPath = resolvePath(file,
|
|
140
|
+
const fullPath = resolvePath(file, workdir);
|
|
91
141
|
const stats = await stat(fullPath);
|
|
92
142
|
return {
|
|
93
143
|
path: file,
|
package/src/tools/grepTool.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ToolPlugin, ToolResult, ToolContext } from "./types.js";
|
|
2
2
|
import { spawn } from "child_process";
|
|
3
|
-
import {
|
|
3
|
+
import { getAllIgnorePatterns } from "../utils/fileFilter.js";
|
|
4
4
|
import { rgPath } from "@vscode/ripgrep";
|
|
5
5
|
import { getDisplayPath } from "../utils/path.js";
|
|
6
6
|
import {
|
|
@@ -189,7 +189,7 @@ export const grepTool: ToolPlugin = {
|
|
|
189
189
|
}
|
|
190
190
|
|
|
191
191
|
// Get common ignore rules
|
|
192
|
-
const ignorePatterns =
|
|
192
|
+
const ignorePatterns = getAllIgnorePatterns();
|
|
193
193
|
for (const exclude of ignorePatterns) {
|
|
194
194
|
rgArgs.push("--glob", `!${exclude}`);
|
|
195
195
|
}
|
|
@@ -133,7 +133,7 @@ export function setupAgentContainer(
|
|
|
133
133
|
const permissionManager = new PermissionManager(container, { workdir });
|
|
134
134
|
if (configurationService.resolveAutoMemoryEnabled()) {
|
|
135
135
|
const autoMemoryDir = memoryService.getAutoMemoryDirectory(workdir);
|
|
136
|
-
permissionManager.
|
|
136
|
+
permissionManager.addSystemAdditionalDirectory(autoMemoryDir);
|
|
137
137
|
}
|
|
138
138
|
container.register("PermissionManager", permissionManager);
|
|
139
139
|
permissionManager.setOnConfiguredDefaultModeChange((mode) => {
|
package/src/utils/fileFilter.ts
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import * as fs from "fs";
|
|
2
|
-
import * as path from "path";
|
|
3
|
-
|
|
4
1
|
/**
|
|
5
2
|
* Common ignore directory and file patterns
|
|
6
3
|
* Can be reused by multiple tools (glob, ripgrep, etc.)
|
|
@@ -40,163 +37,3 @@ export const getAllIgnorePatterns = (): string[] => {
|
|
|
40
37
|
...COMMON_IGNORE_PATTERNS.os,
|
|
41
38
|
];
|
|
42
39
|
};
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Recursively find all .gitignore files in directory
|
|
46
|
-
* @param dir Directory to search
|
|
47
|
-
* @param maxDepth Maximum recursion depth to prevent too deep searches
|
|
48
|
-
* @returns Array of .gitignore file paths
|
|
49
|
-
*/
|
|
50
|
-
const findAllGitignoreFiles = (dir: string, maxDepth: number = 5): string[] => {
|
|
51
|
-
const gitignoreFiles: string[] = [];
|
|
52
|
-
|
|
53
|
-
if (maxDepth <= 0) return gitignoreFiles;
|
|
54
|
-
|
|
55
|
-
try {
|
|
56
|
-
const items = fs.readdirSync(dir, { withFileTypes: true });
|
|
57
|
-
|
|
58
|
-
for (const item of items) {
|
|
59
|
-
const fullPath = path.join(dir, item.name);
|
|
60
|
-
|
|
61
|
-
if (item.isFile() && item.name === ".gitignore") {
|
|
62
|
-
gitignoreFiles.push(fullPath);
|
|
63
|
-
} else if (item.isDirectory() && !shouldSkipDirectory(item.name)) {
|
|
64
|
-
// Recursively search subdirectories, but skip some obviously unnecessary directories
|
|
65
|
-
gitignoreFiles.push(...findAllGitignoreFiles(fullPath, maxDepth - 1));
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
} catch {
|
|
69
|
-
// Ignore permission errors and other issues
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
return gitignoreFiles;
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Determine whether to skip searching a directory
|
|
77
|
-
*/
|
|
78
|
-
const shouldSkipDirectory = (dirName: string): boolean => {
|
|
79
|
-
const skipDirs = [
|
|
80
|
-
"node_modules",
|
|
81
|
-
".git",
|
|
82
|
-
"dist",
|
|
83
|
-
"build",
|
|
84
|
-
".next",
|
|
85
|
-
"coverage",
|
|
86
|
-
".nyc_output",
|
|
87
|
-
"tmp",
|
|
88
|
-
"temp",
|
|
89
|
-
".cache",
|
|
90
|
-
];
|
|
91
|
-
return skipDirs.includes(dirName);
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Parse single .gitignore file content
|
|
96
|
-
* @param gitignorePath .gitignore file path
|
|
97
|
-
* @param basePath Base path for calculating relative paths
|
|
98
|
-
* @returns Array of parsed glob patterns
|
|
99
|
-
*/
|
|
100
|
-
const parseGitignoreFile = (
|
|
101
|
-
gitignorePath: string,
|
|
102
|
-
basePath: string,
|
|
103
|
-
): string[] => {
|
|
104
|
-
const patterns: string[] = [];
|
|
105
|
-
|
|
106
|
-
try {
|
|
107
|
-
if (fs.existsSync(gitignorePath)) {
|
|
108
|
-
const gitignoreContent = fs.readFileSync(gitignorePath, "utf8");
|
|
109
|
-
const gitignoreDir = path.dirname(gitignorePath);
|
|
110
|
-
// Calculate relative directory relative to base path
|
|
111
|
-
const relativeDirFromBase = path.relative(basePath, gitignoreDir);
|
|
112
|
-
|
|
113
|
-
const lines = gitignoreContent
|
|
114
|
-
.split("\n")
|
|
115
|
-
.map((line) => line.trim())
|
|
116
|
-
.filter((line) => line && !line.startsWith("#"));
|
|
117
|
-
|
|
118
|
-
for (const line of lines) {
|
|
119
|
-
// Skip negation rules (starting with !)
|
|
120
|
-
if (line.startsWith("!")) {
|
|
121
|
-
continue;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
let pattern = line;
|
|
125
|
-
|
|
126
|
-
// Handle patterns starting with / (relative to current .gitignore file directory)
|
|
127
|
-
if (pattern.startsWith("/")) {
|
|
128
|
-
pattern = pattern.slice(1); // Remove leading /
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// If .gitignore is in subdirectory, need to add path prefix
|
|
132
|
-
if (relativeDirFromBase && relativeDirFromBase !== ".") {
|
|
133
|
-
pattern = path.posix.join(relativeDirFromBase, pattern);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// If directory pattern (ending with /)
|
|
137
|
-
if (pattern.endsWith("/")) {
|
|
138
|
-
const dirName = pattern.slice(0, -1);
|
|
139
|
-
// For directory patterns, add both exact match and wildcard match
|
|
140
|
-
patterns.push(`${dirName}/**`); // Directory and all its sub-content
|
|
141
|
-
// If no path separators, it's a simple directory name, add global match
|
|
142
|
-
if (!dirName.includes("/") && !dirName.includes("*")) {
|
|
143
|
-
patterns.push(`**/${dirName}/**`); // Match directories of same name at any level
|
|
144
|
-
}
|
|
145
|
-
} else {
|
|
146
|
-
// File pattern
|
|
147
|
-
patterns.push(pattern);
|
|
148
|
-
// If no wildcards and no extension, also treat as directory
|
|
149
|
-
if (!pattern.includes("*") && !pattern.includes(".")) {
|
|
150
|
-
patterns.push(`${pattern}/**`);
|
|
151
|
-
// Also add global match for simple directory names
|
|
152
|
-
if (!pattern.includes("/")) {
|
|
153
|
-
patterns.push(`**/${pattern}/**`);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
} catch {
|
|
160
|
-
// Ignore errors when reading .gitignore files
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
return patterns;
|
|
164
|
-
};
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Parse all .gitignore files in the working directory and its subdirectories and convert to glob patterns
|
|
168
|
-
* @param workdir Working directory
|
|
169
|
-
* @returns Array of glob ignore patterns
|
|
170
|
-
*/
|
|
171
|
-
export const parseGitignoreToGlob = (workdir: string): string[] => {
|
|
172
|
-
const patterns: string[] = [];
|
|
173
|
-
|
|
174
|
-
try {
|
|
175
|
-
// Find all .gitignore files
|
|
176
|
-
const gitignoreFiles = findAllGitignoreFiles(workdir);
|
|
177
|
-
|
|
178
|
-
// Parse each .gitignore file
|
|
179
|
-
for (const gitignoreFile of gitignoreFiles) {
|
|
180
|
-
patterns.push(...parseGitignoreFile(gitignoreFile, workdir));
|
|
181
|
-
}
|
|
182
|
-
} catch {
|
|
183
|
-
// Ignore errors during search process
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
return patterns;
|
|
187
|
-
};
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* Get ignore patterns for glob search
|
|
191
|
-
* @param workdir Working directory for resolving .gitignore files
|
|
192
|
-
*/
|
|
193
|
-
export const getGlobIgnorePatterns = (workdir?: string): string[] => {
|
|
194
|
-
const patterns = getAllIgnorePatterns();
|
|
195
|
-
|
|
196
|
-
// If working directory is provided, parse .gitignore files
|
|
197
|
-
if (workdir) {
|
|
198
|
-
patterns.push(...parseGitignoreToGlob(workdir));
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
return patterns;
|
|
202
|
-
};
|
package/src/utils/fileSearch.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { spawn } from "child_process";
|
|
2
2
|
import { rgPath } from "@vscode/ripgrep";
|
|
3
3
|
import fuzzysort from "fuzzysort";
|
|
4
|
-
import {
|
|
4
|
+
import { getAllIgnorePatterns } from "./fileFilter.js";
|
|
5
5
|
import type { FileItem } from "../types/fileSearch.js";
|
|
6
6
|
import { logger } from "./globalLogger.js";
|
|
7
7
|
|
|
@@ -13,7 +13,7 @@ async function getAllFiles(workingDirectory: string): Promise<string[]> {
|
|
|
13
13
|
throw new Error("ripgrep is not available");
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
const ignorePatterns =
|
|
16
|
+
const ignorePatterns = getAllIgnorePatterns();
|
|
17
17
|
const rgArgs = ["--files", "--color=never", "--hidden"];
|
|
18
18
|
for (const pattern of ignorePatterns) {
|
|
19
19
|
rgArgs.push("--glob", `!${pattern}`);
|
|
@@ -220,12 +220,12 @@ export const updateToolBlockInMessage = ({
|
|
|
220
220
|
if (toolBlockIndex !== -1) {
|
|
221
221
|
const toolBlock = newMessages[i].blocks[toolBlockIndex];
|
|
222
222
|
if (toolBlock.type === "tool") {
|
|
223
|
-
toolBlock.parameters = parameters;
|
|
223
|
+
if (parameters !== undefined) toolBlock.parameters = parameters;
|
|
224
224
|
if (result !== undefined) toolBlock.result = result;
|
|
225
225
|
if (shortResult !== undefined) toolBlock.shortResult = shortResult;
|
|
226
226
|
if (startLineNumber !== undefined)
|
|
227
227
|
toolBlock.startLineNumber = startLineNumber;
|
|
228
|
-
toolBlock.images = images; // Add image data update
|
|
228
|
+
if (images !== undefined) toolBlock.images = images; // Add image data update
|
|
229
229
|
if (success !== undefined) toolBlock.success = success;
|
|
230
230
|
if (error !== undefined) toolBlock.error = error;
|
|
231
231
|
if (stage !== undefined) toolBlock.stage = stage;
|