@prbe.ai/electron-sdk 0.1.3 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +332 -0
- package/dist/index.d.ts +331 -20
- package/dist/index.js +2471 -69
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2402 -0
- package/dist/index.mjs.map +1 -0
- package/dist/types-DHT-JxMT.d.mts +401 -0
- package/dist/types-DHT-JxMT.d.ts +401 -0
- package/dist/types.d.mts +2 -0
- package/dist/types.d.ts +2 -14
- package/dist/types.js +160 -30
- package/dist/types.js.map +1 -1
- package/dist/types.mjs +125 -0
- package/dist/types.mjs.map +1 -0
- package/package.json +22 -12
- package/dist/agent.d.ts +0 -106
- package/dist/agent.d.ts.map +0 -1
- package/dist/agent.js +0 -878
- package/dist/agent.js.map +0 -1
- package/dist/assets/index.d.ts +0 -6
- package/dist/assets/index.d.ts.map +0 -1
- package/dist/assets/index.js +0 -13
- package/dist/assets/index.js.map +0 -1
- package/dist/electron/channels.d.ts +0 -21
- package/dist/electron/channels.d.ts.map +0 -1
- package/dist/electron/channels.js +0 -25
- package/dist/electron/channels.js.map +0 -1
- package/dist/electron/index.d.ts +0 -12
- package/dist/electron/index.d.ts.map +0 -1
- package/dist/electron/index.js +0 -22
- package/dist/electron/index.js.map +0 -1
- package/dist/electron/ipc-interaction-handler.d.ts +0 -21
- package/dist/electron/ipc-interaction-handler.d.ts.map +0 -1
- package/dist/electron/ipc-interaction-handler.js +0 -48
- package/dist/electron/ipc-interaction-handler.js.map +0 -1
- package/dist/electron/preload.d.ts +0 -20
- package/dist/electron/preload.d.ts.map +0 -1
- package/dist/electron/preload.js +0 -72
- package/dist/electron/preload.js.map +0 -1
- package/dist/electron/setup-handlers.d.ts +0 -30
- package/dist/electron/setup-handlers.d.ts.map +0 -1
- package/dist/electron/setup-handlers.js +0 -111
- package/dist/electron/setup-handlers.js.map +0 -1
- package/dist/electron/types.d.ts +0 -56
- package/dist/electron/types.d.ts.map +0 -1
- package/dist/electron/types.js +0 -9
- package/dist/electron/types.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/interactions.d.ts +0 -63
- package/dist/interactions.d.ts.map +0 -1
- package/dist/interactions.js +0 -27
- package/dist/interactions.js.map +0 -1
- package/dist/models.d.ts +0 -218
- package/dist/models.d.ts.map +0 -1
- package/dist/models.js +0 -121
- package/dist/models.js.map +0 -1
- package/dist/serialization.d.ts +0 -51
- package/dist/serialization.d.ts.map +0 -1
- package/dist/serialization.js +0 -72
- package/dist/serialization.js.map +0 -1
- package/dist/state.d.ts +0 -70
- package/dist/state.d.ts.map +0 -1
- package/dist/state.js +0 -303
- package/dist/state.js.map +0 -1
- package/dist/tools/bash.d.ts +0 -30
- package/dist/tools/bash.d.ts.map +0 -1
- package/dist/tools/bash.js +0 -248
- package/dist/tools/bash.js.map +0 -1
- package/dist/tools/filesystem.d.ts +0 -63
- package/dist/tools/filesystem.d.ts.map +0 -1
- package/dist/tools/filesystem.js +0 -573
- package/dist/tools/filesystem.js.map +0 -1
- package/dist/tools/index.d.ts +0 -46
- package/dist/tools/index.d.ts.map +0 -1
- package/dist/tools/index.js +0 -171
- package/dist/tools/index.js.map +0 -1
- package/dist/tools/interactive.d.ts +0 -15
- package/dist/tools/interactive.d.ts.map +0 -1
- package/dist/tools/interactive.js +0 -58
- package/dist/tools/interactive.js.map +0 -1
- package/dist/tools/logs.d.ts +0 -72
- package/dist/tools/logs.d.ts.map +0 -1
- package/dist/tools/logs.js +0 -366
- package/dist/tools/logs.js.map +0 -1
- package/dist/types.d.ts.map +0 -1
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* tools/filesystem.ts — Built-in filesystem tools
|
|
3
|
-
*
|
|
4
|
-
* Implements: client_list_directory, client_read_file, client_search_content,
|
|
5
|
-
* client_find_files, client_flag_file
|
|
6
|
-
*
|
|
7
|
-
* Mirrors PRBEAgentTools.swift filesystem tool implementations.
|
|
8
|
-
*/
|
|
9
|
-
import type { PRBEToolDeclaration, FlaggedFileIn } from "../models";
|
|
10
|
-
import type { PRBEInteractionRequester } from "../interactions";
|
|
11
|
-
import type { PRBETool } from "./index";
|
|
12
|
-
export declare class ListDirectoryTool implements PRBETool {
|
|
13
|
-
private readonly autoApprovedDirs;
|
|
14
|
-
private readonly requester?;
|
|
15
|
-
private readonly grantedPaths?;
|
|
16
|
-
constructor(autoApprovedDirs: string[], requester?: PRBEInteractionRequester, grantedPaths?: Set<string>);
|
|
17
|
-
get declaration(): PRBEToolDeclaration;
|
|
18
|
-
execute(args: Record<string, unknown>): Promise<string>;
|
|
19
|
-
private static readonly MAX_ENTRIES;
|
|
20
|
-
private listDir;
|
|
21
|
-
}
|
|
22
|
-
export declare class ReadFileTool implements PRBETool {
|
|
23
|
-
private readonly autoApprovedDirs;
|
|
24
|
-
private readonly requester?;
|
|
25
|
-
private readonly grantedPaths?;
|
|
26
|
-
constructor(autoApprovedDirs: string[], requester?: PRBEInteractionRequester, grantedPaths?: Set<string>);
|
|
27
|
-
get declaration(): PRBEToolDeclaration;
|
|
28
|
-
execute(args: Record<string, unknown>): Promise<string>;
|
|
29
|
-
}
|
|
30
|
-
export declare class SearchContentTool implements PRBETool {
|
|
31
|
-
private readonly autoApprovedDirs;
|
|
32
|
-
private readonly requester?;
|
|
33
|
-
private readonly grantedPaths?;
|
|
34
|
-
constructor(autoApprovedDirs: string[], requester?: PRBEInteractionRequester, grantedPaths?: Set<string>);
|
|
35
|
-
get declaration(): PRBEToolDeclaration;
|
|
36
|
-
execute(args: Record<string, unknown>): Promise<string>;
|
|
37
|
-
private collectFiles;
|
|
38
|
-
}
|
|
39
|
-
export declare class FindFilesTool implements PRBETool {
|
|
40
|
-
private readonly autoApprovedDirs;
|
|
41
|
-
private readonly requester?;
|
|
42
|
-
private readonly grantedPaths?;
|
|
43
|
-
constructor(autoApprovedDirs: string[], requester?: PRBEInteractionRequester, grantedPaths?: Set<string>);
|
|
44
|
-
get declaration(): PRBEToolDeclaration;
|
|
45
|
-
execute(args: Record<string, unknown>): Promise<string>;
|
|
46
|
-
private walkAndMatch;
|
|
47
|
-
/**
|
|
48
|
-
* Simple glob matching: supports *, ?, and character classes [...].
|
|
49
|
-
* Converts glob to regex and tests against the filename.
|
|
50
|
-
*/
|
|
51
|
-
private globMatch;
|
|
52
|
-
}
|
|
53
|
-
export declare class FlagFileTool implements PRBETool {
|
|
54
|
-
private readonly autoApprovedDirs;
|
|
55
|
-
private readonly onFlag;
|
|
56
|
-
private readonly requester?;
|
|
57
|
-
private readonly grantedPaths?;
|
|
58
|
-
private static readonly MAX_BINARY_SIZE;
|
|
59
|
-
constructor(autoApprovedDirs: string[], onFlag: (file: FlaggedFileIn) => void, requester?: PRBEInteractionRequester, grantedPaths?: Set<string>);
|
|
60
|
-
get declaration(): PRBEToolDeclaration;
|
|
61
|
-
execute(args: Record<string, unknown>): Promise<string>;
|
|
62
|
-
}
|
|
63
|
-
//# sourceMappingURL=filesystem.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"filesystem.d.ts","sourceRoot":"","sources":["../../src/tools/filesystem.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/filesystem.js
DELETED
|
@@ -1,573 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* tools/filesystem.ts — Built-in filesystem tools
|
|
4
|
-
*
|
|
5
|
-
* Implements: client_list_directory, client_read_file, client_search_content,
|
|
6
|
-
* client_find_files, client_flag_file
|
|
7
|
-
*
|
|
8
|
-
* Mirrors PRBEAgentTools.swift filesystem tool implementations.
|
|
9
|
-
*/
|
|
10
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
11
|
-
if (k2 === undefined) k2 = k;
|
|
12
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
13
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
14
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
15
|
-
}
|
|
16
|
-
Object.defineProperty(o, k2, desc);
|
|
17
|
-
}) : (function(o, m, k, k2) {
|
|
18
|
-
if (k2 === undefined) k2 = k;
|
|
19
|
-
o[k2] = m[k];
|
|
20
|
-
}));
|
|
21
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
22
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
23
|
-
}) : function(o, v) {
|
|
24
|
-
o["default"] = v;
|
|
25
|
-
});
|
|
26
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
27
|
-
var ownKeys = function(o) {
|
|
28
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
29
|
-
var ar = [];
|
|
30
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
31
|
-
return ar;
|
|
32
|
-
};
|
|
33
|
-
return ownKeys(o);
|
|
34
|
-
};
|
|
35
|
-
return function (mod) {
|
|
36
|
-
if (mod && mod.__esModule) return mod;
|
|
37
|
-
var result = {};
|
|
38
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
39
|
-
__setModuleDefault(result, mod);
|
|
40
|
-
return result;
|
|
41
|
-
};
|
|
42
|
-
})();
|
|
43
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
44
|
-
exports.FlagFileTool = exports.FindFilesTool = exports.SearchContentTool = exports.ReadFileTool = exports.ListDirectoryTool = void 0;
|
|
45
|
-
const fs = __importStar(require("fs"));
|
|
46
|
-
const path = __importStar(require("path"));
|
|
47
|
-
const models_1 = require("../models");
|
|
48
|
-
const index_1 = require("./index");
|
|
49
|
-
/** Resolve a path using access request if available, else basic validation. Returns [resolved, error]. */
|
|
50
|
-
async function resolvePath(pathStr, autoApprovedDirs, requester, grantedPaths) {
|
|
51
|
-
if (requester && grantedPaths) {
|
|
52
|
-
const result = await (0, index_1.resolveWithAccessRequest)(pathStr, autoApprovedDirs, grantedPaths, requester);
|
|
53
|
-
if (result && "error" in result)
|
|
54
|
-
return [null, result.error];
|
|
55
|
-
if (result && "path" in result)
|
|
56
|
-
return [result.path, null];
|
|
57
|
-
}
|
|
58
|
-
const resolved = (0, index_1.resolveAndValidate)(pathStr, autoApprovedDirs);
|
|
59
|
-
return [resolved, resolved ? null : "path is outside auto-approved directories"];
|
|
60
|
-
}
|
|
61
|
-
// ---------------------------------------------------------------------------
|
|
62
|
-
// ListDirectoryTool
|
|
63
|
-
// ---------------------------------------------------------------------------
|
|
64
|
-
class ListDirectoryTool {
|
|
65
|
-
autoApprovedDirs;
|
|
66
|
-
requester;
|
|
67
|
-
grantedPaths;
|
|
68
|
-
constructor(autoApprovedDirs, requester, grantedPaths) {
|
|
69
|
-
this.autoApprovedDirs = autoApprovedDirs;
|
|
70
|
-
this.requester = requester;
|
|
71
|
-
this.grantedPaths = grantedPaths;
|
|
72
|
-
}
|
|
73
|
-
get declaration() {
|
|
74
|
-
return {
|
|
75
|
-
name: models_1.ToolName.CLIENT_LIST_DIRECTORY,
|
|
76
|
-
description: "List directory contents",
|
|
77
|
-
parameters: [
|
|
78
|
-
{ name: "path", type: models_1.ToolParamType.STRING, description: "Directory path", required: true },
|
|
79
|
-
{ name: "recursive", type: models_1.ToolParamType.BOOLEAN, description: "List recursively", required: false },
|
|
80
|
-
{ name: "max_depth", type: models_1.ToolParamType.INTEGER, description: "Max depth (default 3)", required: false },
|
|
81
|
-
],
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
async execute(args) {
|
|
85
|
-
const pathStr = args["path"];
|
|
86
|
-
if (!pathStr)
|
|
87
|
-
return "Error: 'path' parameter is required";
|
|
88
|
-
const [resolved, resolveErr] = await resolvePath(pathStr, this.autoApprovedDirs, this.requester, this.grantedPaths);
|
|
89
|
-
if (!resolved)
|
|
90
|
-
return `Error: ${resolveErr}`;
|
|
91
|
-
try {
|
|
92
|
-
const stat = fs.statSync(resolved);
|
|
93
|
-
if (!stat.isDirectory())
|
|
94
|
-
return `Error: '${pathStr}' is not a directory`;
|
|
95
|
-
}
|
|
96
|
-
catch {
|
|
97
|
-
return `Error: '${pathStr}' does not exist or is not accessible`;
|
|
98
|
-
}
|
|
99
|
-
const recursive = args["recursive"] === true;
|
|
100
|
-
const maxDepth = typeof args["max_depth"] === "number" ? args["max_depth"] : 3;
|
|
101
|
-
const lines = [];
|
|
102
|
-
this.listDir(resolved, 0, recursive ? maxDepth : 1, lines);
|
|
103
|
-
if (lines.length >= ListDirectoryTool.MAX_ENTRIES) {
|
|
104
|
-
lines.push(`\n(truncated at ${ListDirectoryTool.MAX_ENTRIES} entries — use a more specific path)`);
|
|
105
|
-
}
|
|
106
|
-
return lines.join("\n") || "(empty directory)";
|
|
107
|
-
}
|
|
108
|
-
static MAX_ENTRIES = 1000;
|
|
109
|
-
listDir(dirPath, depth, maxDepth, lines) {
|
|
110
|
-
if (depth >= maxDepth)
|
|
111
|
-
return;
|
|
112
|
-
if (lines.length >= ListDirectoryTool.MAX_ENTRIES)
|
|
113
|
-
return;
|
|
114
|
-
const indent = " ".repeat(depth);
|
|
115
|
-
let entries;
|
|
116
|
-
try {
|
|
117
|
-
entries = fs.readdirSync(dirPath, { withFileTypes: true });
|
|
118
|
-
}
|
|
119
|
-
catch {
|
|
120
|
-
lines.push(`${indent}(access denied)`);
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
// Sort entries alphabetically, skip hidden files
|
|
124
|
-
const sorted = entries
|
|
125
|
-
.filter((e) => !e.name.startsWith("."))
|
|
126
|
-
.sort((a, b) => a.name.localeCompare(b.name));
|
|
127
|
-
for (const entry of sorted) {
|
|
128
|
-
const fullPath = path.join(dirPath, entry.name);
|
|
129
|
-
if (entry.isDirectory()) {
|
|
130
|
-
lines.push(`${indent}${entry.name}/`);
|
|
131
|
-
this.listDir(fullPath, depth + 1, maxDepth, lines);
|
|
132
|
-
}
|
|
133
|
-
else {
|
|
134
|
-
try {
|
|
135
|
-
const stat = fs.statSync(fullPath);
|
|
136
|
-
lines.push(`${indent}${entry.name} (${(0, index_1.humanReadableSize)(stat.size)})`);
|
|
137
|
-
}
|
|
138
|
-
catch {
|
|
139
|
-
lines.push(`${indent}${entry.name} (unknown size)`);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
exports.ListDirectoryTool = ListDirectoryTool;
|
|
146
|
-
// ---------------------------------------------------------------------------
|
|
147
|
-
// ReadFileTool
|
|
148
|
-
// ---------------------------------------------------------------------------
|
|
149
|
-
class ReadFileTool {
|
|
150
|
-
autoApprovedDirs;
|
|
151
|
-
requester;
|
|
152
|
-
grantedPaths;
|
|
153
|
-
constructor(autoApprovedDirs, requester, grantedPaths) {
|
|
154
|
-
this.autoApprovedDirs = autoApprovedDirs;
|
|
155
|
-
this.requester = requester;
|
|
156
|
-
this.grantedPaths = grantedPaths;
|
|
157
|
-
}
|
|
158
|
-
get declaration() {
|
|
159
|
-
return {
|
|
160
|
-
name: models_1.ToolName.CLIENT_READ_FILE,
|
|
161
|
-
description: "Read file contents",
|
|
162
|
-
parameters: [
|
|
163
|
-
{ name: "path", type: models_1.ToolParamType.STRING, description: "File path", required: true },
|
|
164
|
-
{ name: "offset", type: models_1.ToolParamType.INTEGER, description: "Line offset", required: false },
|
|
165
|
-
{ name: "limit", type: models_1.ToolParamType.INTEGER, description: "Max lines (default 200)", required: false },
|
|
166
|
-
],
|
|
167
|
-
};
|
|
168
|
-
}
|
|
169
|
-
async execute(args) {
|
|
170
|
-
const pathStr = args["path"];
|
|
171
|
-
if (!pathStr)
|
|
172
|
-
return "Error: 'path' parameter is required";
|
|
173
|
-
const [resolved, resolveErr] = await resolvePath(pathStr, this.autoApprovedDirs, this.requester, this.grantedPaths);
|
|
174
|
-
if (!resolved)
|
|
175
|
-
return `Error: ${resolveErr}`;
|
|
176
|
-
let content;
|
|
177
|
-
try {
|
|
178
|
-
content = fs.readFileSync(resolved, "utf-8");
|
|
179
|
-
}
|
|
180
|
-
catch {
|
|
181
|
-
return `Error: could not read file at '${pathStr}'`;
|
|
182
|
-
}
|
|
183
|
-
const allLines = content.split(/\r?\n/);
|
|
184
|
-
const totalLines = allLines.length;
|
|
185
|
-
const limit = typeof args["limit"] === "number" ? args["limit"] : 200;
|
|
186
|
-
const rawOffset = typeof args["offset"] === "number" ? args["offset"] : 0;
|
|
187
|
-
let startIndex;
|
|
188
|
-
if (rawOffset < 0) {
|
|
189
|
-
startIndex = Math.max(0, totalLines + rawOffset);
|
|
190
|
-
}
|
|
191
|
-
else {
|
|
192
|
-
startIndex = rawOffset;
|
|
193
|
-
}
|
|
194
|
-
const endIndex = Math.min(startIndex + limit, totalLines);
|
|
195
|
-
if (startIndex >= totalLines) {
|
|
196
|
-
return `File has ${totalLines} lines; offset ${rawOffset} is out of range.`;
|
|
197
|
-
}
|
|
198
|
-
let stat;
|
|
199
|
-
try {
|
|
200
|
-
stat = fs.statSync(resolved);
|
|
201
|
-
}
|
|
202
|
-
catch {
|
|
203
|
-
stat = { size: 0 };
|
|
204
|
-
}
|
|
205
|
-
const sizeStr = (0, index_1.humanReadableSize)(stat.size);
|
|
206
|
-
let result = `File: ${pathStr} (${totalLines} lines, ${sizeStr}, showing ${startIndex + 1}-${endIndex})\n`;
|
|
207
|
-
for (let i = startIndex; i < endIndex; i++) {
|
|
208
|
-
const lineNum = String(i + 1).padStart(4, " ");
|
|
209
|
-
result += `${lineNum} | ${allLines[i]}\n`;
|
|
210
|
-
}
|
|
211
|
-
return result;
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
exports.ReadFileTool = ReadFileTool;
|
|
215
|
-
// ---------------------------------------------------------------------------
|
|
216
|
-
// SearchContentTool
|
|
217
|
-
// ---------------------------------------------------------------------------
|
|
218
|
-
class SearchContentTool {
|
|
219
|
-
autoApprovedDirs;
|
|
220
|
-
requester;
|
|
221
|
-
grantedPaths;
|
|
222
|
-
constructor(autoApprovedDirs, requester, grantedPaths) {
|
|
223
|
-
this.autoApprovedDirs = autoApprovedDirs;
|
|
224
|
-
this.requester = requester;
|
|
225
|
-
this.grantedPaths = grantedPaths;
|
|
226
|
-
}
|
|
227
|
-
get declaration() {
|
|
228
|
-
return {
|
|
229
|
-
name: models_1.ToolName.CLIENT_SEARCH_CONTENT,
|
|
230
|
-
description: "Search file contents",
|
|
231
|
-
parameters: [
|
|
232
|
-
{ name: "pattern", type: models_1.ToolParamType.STRING, description: "Regex pattern", required: true },
|
|
233
|
-
{ name: "path", type: models_1.ToolParamType.STRING, description: "File or directory to search", required: true },
|
|
234
|
-
{ name: "context_lines", type: models_1.ToolParamType.INTEGER, description: "Context lines (default 2)", required: false },
|
|
235
|
-
{ name: "max_results", type: models_1.ToolParamType.INTEGER, description: "Max results (default 50)", required: false },
|
|
236
|
-
],
|
|
237
|
-
};
|
|
238
|
-
}
|
|
239
|
-
async execute(args) {
|
|
240
|
-
const pattern = args["pattern"];
|
|
241
|
-
if (!pattern)
|
|
242
|
-
return "Error: 'pattern' parameter is required";
|
|
243
|
-
const pathStr = args["path"];
|
|
244
|
-
if (!pathStr)
|
|
245
|
-
return "Error: 'path' parameter is required";
|
|
246
|
-
const [resolved, resolveErr] = await resolvePath(pathStr, this.autoApprovedDirs, this.requester, this.grantedPaths);
|
|
247
|
-
if (!resolved)
|
|
248
|
-
return `Error: ${resolveErr}`;
|
|
249
|
-
const contextLines = typeof args["context_lines"] === "number" ? args["context_lines"] : 2;
|
|
250
|
-
const maxResults = typeof args["max_results"] === "number" ? args["max_results"] : 50;
|
|
251
|
-
let regex;
|
|
252
|
-
try {
|
|
253
|
-
regex = new RegExp(pattern);
|
|
254
|
-
}
|
|
255
|
-
catch {
|
|
256
|
-
return `Error: invalid regex pattern '${pattern}'`;
|
|
257
|
-
}
|
|
258
|
-
// Collect file paths to search
|
|
259
|
-
const fileURLs = [];
|
|
260
|
-
let isDirectory = false;
|
|
261
|
-
try {
|
|
262
|
-
const stat = fs.statSync(resolved);
|
|
263
|
-
if (stat.isDirectory()) {
|
|
264
|
-
isDirectory = true;
|
|
265
|
-
this.collectFiles(resolved, fileURLs);
|
|
266
|
-
}
|
|
267
|
-
else {
|
|
268
|
-
fileURLs.push(resolved);
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
catch {
|
|
272
|
-
return `Error: could not access '${pathStr}'`;
|
|
273
|
-
}
|
|
274
|
-
const results = [];
|
|
275
|
-
for (const filePath of fileURLs) {
|
|
276
|
-
if (results.length >= maxResults)
|
|
277
|
-
break;
|
|
278
|
-
let content;
|
|
279
|
-
try {
|
|
280
|
-
content = fs.readFileSync(filePath, "utf-8");
|
|
281
|
-
}
|
|
282
|
-
catch {
|
|
283
|
-
continue;
|
|
284
|
-
}
|
|
285
|
-
const lines = content.split(/\r?\n/);
|
|
286
|
-
const relativePath = isDirectory
|
|
287
|
-
? path.relative(resolved, filePath)
|
|
288
|
-
: path.basename(filePath);
|
|
289
|
-
for (let idx = 0; idx < lines.length; idx++) {
|
|
290
|
-
if (results.length >= maxResults)
|
|
291
|
-
break;
|
|
292
|
-
if (!regex.test(lines[idx]))
|
|
293
|
-
continue;
|
|
294
|
-
let snippet;
|
|
295
|
-
if (contextLines > 0) {
|
|
296
|
-
const start = Math.max(0, idx - contextLines);
|
|
297
|
-
const end = Math.min(lines.length - 1, idx + contextLines);
|
|
298
|
-
snippet = "";
|
|
299
|
-
for (let ci = start; ci <= end; ci++) {
|
|
300
|
-
const marker = ci === idx ? ">" : " ";
|
|
301
|
-
snippet += `${relativePath}:${ci + 1}:${marker} ${lines[ci]}\n`;
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
else {
|
|
305
|
-
snippet = `${relativePath}:${idx + 1}: ${lines[idx]}`;
|
|
306
|
-
}
|
|
307
|
-
results.push(snippet);
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
if (results.length === 0) {
|
|
311
|
-
return `No matches found for '${pattern}' in '${pathStr}'`;
|
|
312
|
-
}
|
|
313
|
-
return `Found ${results.length} match(es):\n\n${results.join("\n---\n")}`;
|
|
314
|
-
}
|
|
315
|
-
collectFiles(dirPath, fileURLs) {
|
|
316
|
-
let entries;
|
|
317
|
-
try {
|
|
318
|
-
entries = fs.readdirSync(dirPath, { withFileTypes: true });
|
|
319
|
-
}
|
|
320
|
-
catch {
|
|
321
|
-
return;
|
|
322
|
-
}
|
|
323
|
-
for (const entry of entries) {
|
|
324
|
-
if (entry.name.startsWith("."))
|
|
325
|
-
continue;
|
|
326
|
-
const fullPath = path.join(dirPath, entry.name);
|
|
327
|
-
if (entry.isDirectory()) {
|
|
328
|
-
this.collectFiles(fullPath, fileURLs);
|
|
329
|
-
}
|
|
330
|
-
else if (entry.isFile()) {
|
|
331
|
-
fileURLs.push(fullPath);
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
exports.SearchContentTool = SearchContentTool;
|
|
337
|
-
// ---------------------------------------------------------------------------
|
|
338
|
-
// FindFilesTool
|
|
339
|
-
// ---------------------------------------------------------------------------
|
|
340
|
-
class FindFilesTool {
|
|
341
|
-
autoApprovedDirs;
|
|
342
|
-
requester;
|
|
343
|
-
grantedPaths;
|
|
344
|
-
constructor(autoApprovedDirs, requester, grantedPaths) {
|
|
345
|
-
this.autoApprovedDirs = autoApprovedDirs;
|
|
346
|
-
this.requester = requester;
|
|
347
|
-
this.grantedPaths = grantedPaths;
|
|
348
|
-
}
|
|
349
|
-
get declaration() {
|
|
350
|
-
return {
|
|
351
|
-
name: models_1.ToolName.CLIENT_FIND_FILES,
|
|
352
|
-
description: "Find files by name",
|
|
353
|
-
parameters: [
|
|
354
|
-
{ name: "pattern", type: models_1.ToolParamType.STRING, description: "Glob pattern", required: true },
|
|
355
|
-
{ name: "path", type: models_1.ToolParamType.STRING, description: "Directory to search", required: true },
|
|
356
|
-
{ name: "max_results", type: models_1.ToolParamType.INTEGER, description: "Max results (default 50)", required: false },
|
|
357
|
-
],
|
|
358
|
-
};
|
|
359
|
-
}
|
|
360
|
-
async execute(args) {
|
|
361
|
-
const pattern = args["pattern"];
|
|
362
|
-
if (!pattern)
|
|
363
|
-
return "Error: 'pattern' parameter is required";
|
|
364
|
-
const pathStr = args["path"];
|
|
365
|
-
if (!pathStr)
|
|
366
|
-
return "Error: 'path' parameter is required";
|
|
367
|
-
const [resolved, resolveErr] = await resolvePath(pathStr, this.autoApprovedDirs, this.requester, this.grantedPaths);
|
|
368
|
-
if (!resolved)
|
|
369
|
-
return `Error: ${resolveErr}`;
|
|
370
|
-
const maxResults = typeof args["max_results"] === "number" ? args["max_results"] : 50;
|
|
371
|
-
const matches = [];
|
|
372
|
-
this.walkAndMatch(resolved, pattern, matches);
|
|
373
|
-
// Sort newest-first
|
|
374
|
-
matches.sort((a, b) => b.modified.getTime() - a.modified.getTime());
|
|
375
|
-
const limited = matches.slice(0, maxResults);
|
|
376
|
-
if (limited.length === 0) {
|
|
377
|
-
return `No files matching '${pattern}' found in '${pathStr}'`;
|
|
378
|
-
}
|
|
379
|
-
let result = `Found ${matches.length} file(s) matching '${pattern}':\n\n`;
|
|
380
|
-
for (const m of limited) {
|
|
381
|
-
const sizeStr = (0, index_1.humanReadableSize)(m.size);
|
|
382
|
-
const dateStr = m.modified.toISOString();
|
|
383
|
-
result += `${m.path} (${sizeStr}, ${dateStr})\n`;
|
|
384
|
-
}
|
|
385
|
-
return result;
|
|
386
|
-
}
|
|
387
|
-
walkAndMatch(dirPath, pattern, matches) {
|
|
388
|
-
let entries;
|
|
389
|
-
try {
|
|
390
|
-
entries = fs.readdirSync(dirPath, { withFileTypes: true });
|
|
391
|
-
}
|
|
392
|
-
catch {
|
|
393
|
-
return;
|
|
394
|
-
}
|
|
395
|
-
for (const entry of entries) {
|
|
396
|
-
if (entry.name.startsWith("."))
|
|
397
|
-
continue;
|
|
398
|
-
const fullPath = path.join(dirPath, entry.name);
|
|
399
|
-
if (entry.isDirectory()) {
|
|
400
|
-
this.walkAndMatch(fullPath, pattern, matches);
|
|
401
|
-
}
|
|
402
|
-
else if (entry.isFile()) {
|
|
403
|
-
if (this.globMatch(entry.name, pattern)) {
|
|
404
|
-
try {
|
|
405
|
-
const stat = fs.statSync(fullPath);
|
|
406
|
-
matches.push({
|
|
407
|
-
path: fullPath,
|
|
408
|
-
size: stat.size,
|
|
409
|
-
modified: stat.mtime,
|
|
410
|
-
});
|
|
411
|
-
}
|
|
412
|
-
catch {
|
|
413
|
-
// Skip files we can't stat
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
/**
|
|
420
|
-
* Simple glob matching: supports *, ?, and character classes [...].
|
|
421
|
-
* Converts glob to regex and tests against the filename.
|
|
422
|
-
*/
|
|
423
|
-
globMatch(filename, pattern) {
|
|
424
|
-
// Convert glob pattern to regex
|
|
425
|
-
let regexStr = "^";
|
|
426
|
-
for (let i = 0; i < pattern.length; i++) {
|
|
427
|
-
const c = pattern[i];
|
|
428
|
-
switch (c) {
|
|
429
|
-
case "*":
|
|
430
|
-
regexStr += ".*";
|
|
431
|
-
break;
|
|
432
|
-
case "?":
|
|
433
|
-
regexStr += ".";
|
|
434
|
-
break;
|
|
435
|
-
case "[":
|
|
436
|
-
// Find closing bracket
|
|
437
|
-
const closeBracket = pattern.indexOf("]", i + 1);
|
|
438
|
-
if (closeBracket === -1) {
|
|
439
|
-
regexStr += "\\[";
|
|
440
|
-
}
|
|
441
|
-
else {
|
|
442
|
-
regexStr += pattern.substring(i, closeBracket + 1);
|
|
443
|
-
i = closeBracket;
|
|
444
|
-
}
|
|
445
|
-
break;
|
|
446
|
-
case ".":
|
|
447
|
-
case "(":
|
|
448
|
-
case ")":
|
|
449
|
-
case "+":
|
|
450
|
-
case "^":
|
|
451
|
-
case "$":
|
|
452
|
-
case "|":
|
|
453
|
-
case "{":
|
|
454
|
-
case "}":
|
|
455
|
-
case "\\":
|
|
456
|
-
regexStr += `\\${c}`;
|
|
457
|
-
break;
|
|
458
|
-
default:
|
|
459
|
-
regexStr += c;
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
regexStr += "$";
|
|
463
|
-
try {
|
|
464
|
-
return new RegExp(regexStr).test(filename);
|
|
465
|
-
}
|
|
466
|
-
catch {
|
|
467
|
-
return false;
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
exports.FindFilesTool = FindFilesTool;
|
|
472
|
-
// ---------------------------------------------------------------------------
|
|
473
|
-
// FlagFileTool
|
|
474
|
-
// ---------------------------------------------------------------------------
|
|
475
|
-
class FlagFileTool {
|
|
476
|
-
autoApprovedDirs;
|
|
477
|
-
onFlag;
|
|
478
|
-
requester;
|
|
479
|
-
grantedPaths;
|
|
480
|
-
static MAX_BINARY_SIZE = 100 * 1024 * 1024; // 100MB
|
|
481
|
-
constructor(autoApprovedDirs, onFlag, requester, grantedPaths) {
|
|
482
|
-
this.autoApprovedDirs = autoApprovedDirs;
|
|
483
|
-
this.onFlag = onFlag;
|
|
484
|
-
this.requester = requester;
|
|
485
|
-
this.grantedPaths = grantedPaths;
|
|
486
|
-
}
|
|
487
|
-
get declaration() {
|
|
488
|
-
return {
|
|
489
|
-
name: models_1.ToolName.CLIENT_FLAG_FILE,
|
|
490
|
-
description: "Flag a file (or part of a text file) as evidence. For large text files, use offset and limit to flag only the relevant section. Binary files are flagged in full (up to 100MB).",
|
|
491
|
-
parameters: [
|
|
492
|
-
{ name: "path", type: models_1.ToolParamType.STRING, description: "File path", required: true },
|
|
493
|
-
{ name: "reason", type: models_1.ToolParamType.STRING, description: "Reason for flagging", required: true },
|
|
494
|
-
{ name: "offset", type: models_1.ToolParamType.INTEGER, description: "Starting line number (1-based, text files only). Negative = from end.", required: false },
|
|
495
|
-
{ name: "limit", type: models_1.ToolParamType.INTEGER, description: "Max number of lines to include (text files only).", required: false },
|
|
496
|
-
],
|
|
497
|
-
};
|
|
498
|
-
}
|
|
499
|
-
async execute(args) {
|
|
500
|
-
const pathStr = args["path"];
|
|
501
|
-
if (!pathStr)
|
|
502
|
-
return "Error: 'path' parameter is required";
|
|
503
|
-
const reason = args["reason"];
|
|
504
|
-
if (!reason)
|
|
505
|
-
return "Error: 'reason' parameter is required";
|
|
506
|
-
const [resolved, resolveErr] = await resolvePath(pathStr, this.autoApprovedDirs, this.requester, this.grantedPaths);
|
|
507
|
-
if (!resolved)
|
|
508
|
-
return `Error: ${resolveErr}`;
|
|
509
|
-
if (!fs.existsSync(resolved)) {
|
|
510
|
-
return `Error: file does not exist at '${pathStr}'`;
|
|
511
|
-
}
|
|
512
|
-
const offset = typeof args["offset"] === "number" ? args["offset"] : undefined;
|
|
513
|
-
const limit = typeof args["limit"] === "number" ? args["limit"] : undefined;
|
|
514
|
-
// Try reading as text first
|
|
515
|
-
let textContent = null;
|
|
516
|
-
try {
|
|
517
|
-
textContent = fs.readFileSync(resolved, "utf-8");
|
|
518
|
-
}
|
|
519
|
-
catch {
|
|
520
|
-
// Not readable as text
|
|
521
|
-
}
|
|
522
|
-
if (textContent !== null) {
|
|
523
|
-
let content = textContent;
|
|
524
|
-
if (offset !== undefined || limit !== undefined) {
|
|
525
|
-
let lines = content.split(/\r?\n/);
|
|
526
|
-
const totalLines = lines.length;
|
|
527
|
-
let startIdx = 0;
|
|
528
|
-
if (offset !== undefined) {
|
|
529
|
-
startIdx = offset < 0 ? Math.max(0, totalLines + offset) : Math.max(0, offset - 1);
|
|
530
|
-
}
|
|
531
|
-
lines = lines.slice(startIdx);
|
|
532
|
-
if (limit !== undefined && limit > 0) {
|
|
533
|
-
lines = lines.slice(0, limit);
|
|
534
|
-
}
|
|
535
|
-
const rangeDesc = `lines ${startIdx + 1}-${startIdx + lines.length} of ${totalLines}`;
|
|
536
|
-
content = `[${rangeDesc}]\n${lines.join("\n")}`;
|
|
537
|
-
}
|
|
538
|
-
const redacted = (0, models_1.redactPII)(content);
|
|
539
|
-
this.onFlag({
|
|
540
|
-
originalPath: resolved,
|
|
541
|
-
reason,
|
|
542
|
-
data: Buffer.from(redacted, "utf-8"),
|
|
543
|
-
isText: true,
|
|
544
|
-
});
|
|
545
|
-
const sizeDesc = offset !== undefined || limit !== undefined ? " (partial)" : "";
|
|
546
|
-
return `Flagged '${pathStr}'${sizeDesc} — reason: ${reason}`;
|
|
547
|
-
}
|
|
548
|
-
// Binary file — flag in full, no partial support
|
|
549
|
-
if (offset !== undefined || limit !== undefined) {
|
|
550
|
-
return "Error: offset/limit not supported for binary files. Flag the full file instead.";
|
|
551
|
-
}
|
|
552
|
-
let data;
|
|
553
|
-
try {
|
|
554
|
-
data = fs.readFileSync(resolved);
|
|
555
|
-
}
|
|
556
|
-
catch {
|
|
557
|
-
return `Error: could not read file at '${pathStr}'`;
|
|
558
|
-
}
|
|
559
|
-
if (data.length > FlagFileTool.MAX_BINARY_SIZE) {
|
|
560
|
-
const sizeMB = Math.floor(data.length / (1024 * 1024));
|
|
561
|
-
return `Error: file is ${sizeMB}MB — exceeds 100MB limit`;
|
|
562
|
-
}
|
|
563
|
-
this.onFlag({
|
|
564
|
-
originalPath: resolved,
|
|
565
|
-
reason,
|
|
566
|
-
data,
|
|
567
|
-
isText: false,
|
|
568
|
-
});
|
|
569
|
-
return `Flagged '${pathStr}' (binary, ${data.length} bytes) — reason: ${reason}`;
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
exports.FlagFileTool = FlagFileTool;
|
|
573
|
-
//# sourceMappingURL=filesystem.js.map
|