@bdsqqq/pi 0.0.1
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/chunk-DsIazq42.js +26 -0
- package/dist/command-palette-B97yKqne.js +406 -0
- package/dist/core/agents-md.d.ts +22 -0
- package/dist/core/agents-md.js +174 -0
- package/dist/core/box-chrome.d.ts +56 -0
- package/dist/core/box-chrome.js +207 -0
- package/dist/core/box-format.d.ts +82 -0
- package/dist/core/box-format.js +381 -0
- package/dist/core/config.d.ts +14 -0
- package/dist/core/config.js +201 -0
- package/dist/core/file-tracker.d.ts +65 -0
- package/dist/core/file-tracker.js +439 -0
- package/dist/core/github-api.d.ts +45 -0
- package/dist/core/github-api.js +101 -0
- package/dist/core/html-to-md.d.ts +5 -0
- package/dist/core/html-to-md.js +289 -0
- package/dist/core/interpolate.d.ts +44 -0
- package/dist/core/interpolate.js +475 -0
- package/dist/core/mutex.d.ts +8 -0
- package/dist/core/mutex.js +142 -0
- package/dist/core/output-buffer.d.ts +80 -0
- package/dist/core/output-buffer.js +517 -0
- package/dist/core/permissions.d.ts +19 -0
- package/dist/core/permissions.js +140 -0
- package/dist/core/pi-spawn.d.ts +62 -0
- package/dist/core/pi-spawn.js +244 -0
- package/dist/core/prompt-patch.d.ts +11 -0
- package/dist/core/prompt-patch.js +16 -0
- package/dist/core/show-renderer.d.ts +10 -0
- package/dist/core/show-renderer.js +39 -0
- package/dist/core/show.d.ts +29 -0
- package/dist/core/show.js +288 -0
- package/dist/core/sub-agent-render.d.ts +56 -0
- package/dist/core/sub-agent-render.js +579 -0
- package/dist/core/tool-cost.d.ts +17 -0
- package/dist/core/tool-cost.js +58 -0
- package/dist/core/tui.d.ts +9 -0
- package/dist/core/tui.js +33 -0
- package/dist/editor-BljciPdx.js +537 -0
- package/dist/extensions/bash.d.ts +12 -0
- package/dist/extensions/bash.js +261 -0
- package/dist/extensions/code-review.d.ts +14 -0
- package/dist/extensions/code-review.js +175 -0
- package/dist/extensions/command-palette.d.ts +6 -0
- package/dist/extensions/command-palette.js +2 -0
- package/dist/extensions/create-file.d.ts +7 -0
- package/dist/extensions/create-file.js +88 -0
- package/dist/extensions/edit-file.d.ts +7 -0
- package/dist/extensions/edit-file.js +395 -0
- package/dist/extensions/editor.d.ts +6 -0
- package/dist/extensions/editor.js +2 -0
- package/dist/extensions/finder.d.ts +13 -0
- package/dist/extensions/finder.js +108 -0
- package/dist/extensions/format-file.d.ts +11 -0
- package/dist/extensions/format-file.js +145 -0
- package/dist/extensions/github.d.ts +13 -0
- package/dist/extensions/github.js +527 -0
- package/dist/extensions/glob.d.ts +10 -0
- package/dist/extensions/glob.js +163 -0
- package/dist/extensions/grep.d.ts +13 -0
- package/dist/extensions/grep.js +356 -0
- package/dist/extensions/handoff.d.ts +6 -0
- package/dist/extensions/handoff.js +277 -0
- package/dist/extensions/librarian.d.ts +13 -0
- package/dist/extensions/librarian.js +113 -0
- package/dist/extensions/look-at.d.ts +13 -0
- package/dist/extensions/look-at.js +121 -0
- package/dist/extensions/ls.d.ts +8 -0
- package/dist/extensions/ls.js +87 -0
- package/dist/extensions/mermaid.d.ts +20 -0
- package/dist/extensions/mermaid.js +2 -0
- package/dist/extensions/oracle.d.ts +13 -0
- package/dist/extensions/oracle.js +143 -0
- package/dist/extensions/read-session.d.ts +13 -0
- package/dist/extensions/read-session.js +265 -0
- package/dist/extensions/read-web-page.d.ts +11 -0
- package/dist/extensions/read-web-page.js +234 -0
- package/dist/extensions/read.d.ts +23 -0
- package/dist/extensions/read.js +323 -0
- package/dist/extensions/search-sessions.d.ts +29 -0
- package/dist/extensions/search-sessions.js +426 -0
- package/dist/extensions/session-name.d.ts +6 -0
- package/dist/extensions/session-name.js +54 -0
- package/dist/extensions/skill.d.ts +7 -0
- package/dist/extensions/skill.js +232 -0
- package/dist/extensions/system-prompt.d.ts +6 -0
- package/dist/extensions/system-prompt.js +31 -0
- package/dist/extensions/task.d.ts +11 -0
- package/dist/extensions/task.js +114 -0
- package/dist/extensions/tool-harness.d.ts +6 -0
- package/dist/extensions/tool-harness.js +37 -0
- package/dist/extensions/undo-edit.d.ts +7 -0
- package/dist/extensions/undo-edit.js +127 -0
- package/dist/extensions/web-search.d.ts +12 -0
- package/dist/extensions/web-search.js +254 -0
- package/dist/extensions.d.ts +29 -0
- package/dist/extensions.js +29 -0
- package/dist/mermaid-C7xCVBrw.js +95296 -0
- package/package.json +67 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ExtensionAPI, ToolDefinition } from "@mariozechner/pi-coding-agent";
|
|
2
|
+
|
|
3
|
+
//#region packages/extensions/read/index.d.ts
|
|
4
|
+
interface ReadLimits {
|
|
5
|
+
maxLines: number;
|
|
6
|
+
maxFileBytes: number;
|
|
7
|
+
maxLineBytes: number;
|
|
8
|
+
maxDirEntries: number;
|
|
9
|
+
}
|
|
10
|
+
declare const NORMAL_LIMITS: ReadLimits;
|
|
11
|
+
declare function expandPath(filePath: string): string;
|
|
12
|
+
declare function resolveToAbsolute(filePath: string, cwd: string): string;
|
|
13
|
+
/**
|
|
14
|
+
* try macOS filesystem variants when file doesn't exist at resolved path.
|
|
15
|
+
* covers NFD normalization and narrow no-break space in AM/PM timestamps.
|
|
16
|
+
*/
|
|
17
|
+
declare function resolveWithVariants(filePath: string, cwd: string): string;
|
|
18
|
+
declare function isSecretFile(filePath: string): boolean;
|
|
19
|
+
declare function listDirectory(dirPath: string, maxEntries: number): string;
|
|
20
|
+
declare function createReadTool(limits: ReadLimits): ToolDefinition;
|
|
21
|
+
declare function export_default(pi: ExtensionAPI): void;
|
|
22
|
+
//#endregion
|
|
23
|
+
export { NORMAL_LIMITS, ReadLimits, createReadTool, export_default as default, expandPath, isSecretFile, listDirectory, resolveToAbsolute, resolveWithVariants };
|
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
import { withPromptPatch } from "../core/prompt-patch.js";
|
|
2
|
+
import { boxRendererWindowed, osc8Link } from "../core/box-format.js";
|
|
3
|
+
import { formatHeadTail } from "../core/output-buffer.js";
|
|
4
|
+
import { getExtensionConfig } from "../core/config.js";
|
|
5
|
+
import * as fs from "node:fs";
|
|
6
|
+
import * as path from "node:path";
|
|
7
|
+
import { Text } from "@mariozechner/pi-tui";
|
|
8
|
+
import { Type } from "@sinclair/typebox";
|
|
9
|
+
import * as os from "node:os";
|
|
10
|
+
//#region packages/extensions/read/index.ts
|
|
11
|
+
/**
|
|
12
|
+
* read tool — replaces pi's built-in with enhanced file reading.
|
|
13
|
+
*
|
|
14
|
+
* differences from pi's built-in:
|
|
15
|
+
* - line-numbered output (`1: content`)
|
|
16
|
+
* - directory listing integrated (no separate ls tool needed)
|
|
17
|
+
* - secret file blocking (.env etc.)
|
|
18
|
+
* - `~` expansion and `@` prefix stripping
|
|
19
|
+
* - image support via base64
|
|
20
|
+
*
|
|
21
|
+
* uses `path` + optional `read_range` [start, end] interface.
|
|
22
|
+
*/
|
|
23
|
+
const NORMAL_LIMITS = {
|
|
24
|
+
maxLines: 500,
|
|
25
|
+
maxFileBytes: 64 * 1024,
|
|
26
|
+
maxLineBytes: 4096,
|
|
27
|
+
maxDirEntries: 1e3
|
|
28
|
+
};
|
|
29
|
+
const CONFIG_DEFAULTS = {
|
|
30
|
+
maxLines: 500,
|
|
31
|
+
maxFileBytes: 65536,
|
|
32
|
+
maxLineBytes: 4096,
|
|
33
|
+
maxDirEntries: 1e3
|
|
34
|
+
};
|
|
35
|
+
const SECRET_PATTERNS = [/^\.env$/, /^\.env\..+$/];
|
|
36
|
+
const SECRET_EXCEPTIONS = new Set([
|
|
37
|
+
".env.example",
|
|
38
|
+
".env.sample",
|
|
39
|
+
".env.template"
|
|
40
|
+
]);
|
|
41
|
+
const IMAGE_MIME = {
|
|
42
|
+
".jpg": "image/jpeg",
|
|
43
|
+
".jpeg": "image/jpeg",
|
|
44
|
+
".png": "image/png",
|
|
45
|
+
".gif": "image/gif",
|
|
46
|
+
".webp": "image/webp"
|
|
47
|
+
};
|
|
48
|
+
function expandPath(filePath) {
|
|
49
|
+
const stripped = filePath.startsWith("@") ? filePath.slice(1) : filePath;
|
|
50
|
+
if (stripped === "~") return os.homedir();
|
|
51
|
+
if (stripped.startsWith("~/")) return os.homedir() + stripped.slice(1);
|
|
52
|
+
return stripped;
|
|
53
|
+
}
|
|
54
|
+
function resolveToAbsolute(filePath, cwd) {
|
|
55
|
+
const expanded = expandPath(filePath);
|
|
56
|
+
return path.isAbsolute(expanded) ? expanded : path.resolve(cwd, expanded);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* try macOS filesystem variants when file doesn't exist at resolved path.
|
|
60
|
+
* covers NFD normalization and narrow no-break space in AM/PM timestamps.
|
|
61
|
+
*/
|
|
62
|
+
function resolveWithVariants(filePath, cwd) {
|
|
63
|
+
const resolved = resolveToAbsolute(filePath, cwd);
|
|
64
|
+
if (fs.existsSync(resolved)) return resolved;
|
|
65
|
+
const amPm = resolved.replace(/ (AM|PM)\./g, `\u202F$1.`);
|
|
66
|
+
if (amPm !== resolved && fs.existsSync(amPm)) return amPm;
|
|
67
|
+
const nfd = resolved.normalize("NFD");
|
|
68
|
+
if (nfd !== resolved && fs.existsSync(nfd)) return nfd;
|
|
69
|
+
return resolved;
|
|
70
|
+
}
|
|
71
|
+
function isSecretFile(filePath) {
|
|
72
|
+
const basename = path.basename(filePath);
|
|
73
|
+
if (SECRET_EXCEPTIONS.has(basename)) return false;
|
|
74
|
+
return SECRET_PATTERNS.some((p) => p.test(basename));
|
|
75
|
+
}
|
|
76
|
+
function getImageMime(filePath) {
|
|
77
|
+
return IMAGE_MIME[path.extname(filePath).toLowerCase()];
|
|
78
|
+
}
|
|
79
|
+
function listDirectory(dirPath, maxEntries) {
|
|
80
|
+
let entries;
|
|
81
|
+
try {
|
|
82
|
+
entries = fs.readdirSync(dirPath, { withFileTypes: true });
|
|
83
|
+
} catch (err) {
|
|
84
|
+
throw new Error(`cannot list directory: ${err.message}`);
|
|
85
|
+
}
|
|
86
|
+
return formatHeadTail(entries.map((e) => e.isDirectory() ? `${e.name}/` : e.name).sort((a, b) => a.localeCompare(b)), maxEntries, (n) => `... [${n} more entries] ...`);
|
|
87
|
+
}
|
|
88
|
+
function readFileContent(filePath, limits, readRange) {
|
|
89
|
+
const allLines = fs.readFileSync(filePath, "utf-8").split("\n");
|
|
90
|
+
const totalLines = allLines.length;
|
|
91
|
+
const start = Math.max(1, readRange?.[0] ?? 1);
|
|
92
|
+
const end = Math.min(totalLines, readRange?.[1] ?? start + limits.maxLines - 1);
|
|
93
|
+
end - start + 1;
|
|
94
|
+
const numbered = [];
|
|
95
|
+
for (let i = start - 1; i < end; i++) {
|
|
96
|
+
let line = allLines[i];
|
|
97
|
+
if (line === void 0) continue;
|
|
98
|
+
if (Buffer.byteLength(line, "utf-8") > limits.maxLineBytes) {
|
|
99
|
+
while (Buffer.byteLength(line, "utf-8") > limits.maxLineBytes) line = line.slice(0, Math.max(1, line.length - 100));
|
|
100
|
+
line += "... (line truncated)";
|
|
101
|
+
}
|
|
102
|
+
numbered.push(`${i + 1}: ${line}`);
|
|
103
|
+
}
|
|
104
|
+
if (numbered.reduce((sum, l) => sum + Buffer.byteLength(l, "utf-8") + 1, 0) <= limits.maxFileBytes) return {
|
|
105
|
+
text: numbered.join("\n"),
|
|
106
|
+
totalLines,
|
|
107
|
+
shownStart: start,
|
|
108
|
+
shownEnd: end
|
|
109
|
+
};
|
|
110
|
+
return {
|
|
111
|
+
text: formatHeadTail(numbered, limits.maxLines, (n) => `... [${n} lines truncated, ${limits.maxFileBytes / 1024}KB limit reached] ...`),
|
|
112
|
+
totalLines,
|
|
113
|
+
shownStart: start,
|
|
114
|
+
shownEnd: end
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
function createReadTool(limits) {
|
|
118
|
+
return {
|
|
119
|
+
name: "read",
|
|
120
|
+
label: "Read",
|
|
121
|
+
description: `Read a file or list a directory from the file system. If the path is a directory, it returns a list of entries. If the file or directory doesn't exist, an error is returned.
|
|
122
|
+
|
|
123
|
+
- The path parameter MUST be an absolute path.
|
|
124
|
+
- By default, this tool returns the first ${limits.maxLines} lines. To read more, call it multiple times with different read_ranges.\n- Use the Grep tool to find specific content in large files or files with long lines.
|
|
125
|
+
- If you are unsure of the correct file path, use the glob tool to look up filenames by glob pattern.
|
|
126
|
+
- The contents are returned with each line prefixed by its line number. For example, if a file has contents "abc\\n", you will receive "1: abc\\n". For directories, entries are returned one per line (without line numbers) with a trailing "/" for subdirectories.
|
|
127
|
+
- This tool can read images (such as PNG, JPEG, and GIF files) and present them to the model visually.
|
|
128
|
+
- When possible, call this tool in parallel for all files you will want to read.
|
|
129
|
+
- Avoid tiny repeated slices (e.g., 50‑line chunks). If you need more context from the same file, read a larger range or the full default window instead.`,
|
|
130
|
+
parameters: Type.Object({
|
|
131
|
+
path: Type.String({ description: "The absolute path to the file or directory (MUST be absolute, not relative)." }),
|
|
132
|
+
read_range: Type.Optional(Type.Array(Type.Number(), {
|
|
133
|
+
description: `An array of two integers specifying the start and end line numbers to view. Line numbers are 1-indexed. If not provided, defaults to [1, ${limits.maxLines}]. Examples: [500, 700], [700, 1400]`,
|
|
134
|
+
minItems: 2,
|
|
135
|
+
maxItems: 2
|
|
136
|
+
}))
|
|
137
|
+
}),
|
|
138
|
+
renderCall(args, theme) {
|
|
139
|
+
const filePath = args.path || "...";
|
|
140
|
+
const home = os.homedir();
|
|
141
|
+
const shortened = filePath.startsWith(home) ? `~${filePath.slice(home.length)}` : filePath;
|
|
142
|
+
const readRange = args.read_range;
|
|
143
|
+
let context = shortened;
|
|
144
|
+
if (Array.isArray(readRange) && readRange.length === 2) context += `:${readRange[0]}-${readRange[1]}`;
|
|
145
|
+
const linked = filePath.startsWith("/") ? osc8Link(`file://${filePath}`, context) : context;
|
|
146
|
+
return new Text(theme.fg("toolTitle", theme.bold("Read ")) + theme.fg("dim", linked), 0, 0);
|
|
147
|
+
},
|
|
148
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
149
|
+
const p = params;
|
|
150
|
+
const resolved = resolveWithVariants(p.path, ctx.cwd);
|
|
151
|
+
if (isSecretFile(resolved)) return {
|
|
152
|
+
content: [{
|
|
153
|
+
type: "text",
|
|
154
|
+
text: `refused to read ${path.basename(resolved)}: file may contain secrets. ask the user to share relevant values.`
|
|
155
|
+
}],
|
|
156
|
+
isError: true
|
|
157
|
+
};
|
|
158
|
+
if (!fs.existsSync(resolved)) return {
|
|
159
|
+
content: [{
|
|
160
|
+
type: "text",
|
|
161
|
+
text: `file not found: ${resolved}`
|
|
162
|
+
}],
|
|
163
|
+
isError: true
|
|
164
|
+
};
|
|
165
|
+
if (fs.statSync(resolved).isDirectory()) try {
|
|
166
|
+
return {
|
|
167
|
+
content: [{
|
|
168
|
+
type: "text",
|
|
169
|
+
text: listDirectory(resolved, limits.maxDirEntries)
|
|
170
|
+
}],
|
|
171
|
+
details: {
|
|
172
|
+
filePath: resolved,
|
|
173
|
+
isDirectory: true
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
} catch (err) {
|
|
177
|
+
return {
|
|
178
|
+
content: [{
|
|
179
|
+
type: "text",
|
|
180
|
+
text: err.message
|
|
181
|
+
}],
|
|
182
|
+
isError: true
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
const mime = getImageMime(resolved);
|
|
186
|
+
if (mime) try {
|
|
187
|
+
return { content: [{
|
|
188
|
+
type: "image",
|
|
189
|
+
data: fs.readFileSync(resolved).toString("base64"),
|
|
190
|
+
mimeType: mime
|
|
191
|
+
}] };
|
|
192
|
+
} catch (err) {
|
|
193
|
+
return {
|
|
194
|
+
content: [{
|
|
195
|
+
type: "text",
|
|
196
|
+
text: `failed to read image: ${err.message}`
|
|
197
|
+
}],
|
|
198
|
+
isError: true
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
try {
|
|
202
|
+
const readRange = p.read_range;
|
|
203
|
+
const { text, totalLines, shownStart, shownEnd } = readFileContent(resolved, limits, readRange);
|
|
204
|
+
let output = text;
|
|
205
|
+
let notice;
|
|
206
|
+
if (shownEnd < totalLines) {
|
|
207
|
+
notice = `showing lines ${shownStart}-${shownEnd} of ${totalLines}`;
|
|
208
|
+
output += `\n\n(${notice}. use read_range to see more.)`;
|
|
209
|
+
}
|
|
210
|
+
return {
|
|
211
|
+
content: [{
|
|
212
|
+
type: "text",
|
|
213
|
+
text: output
|
|
214
|
+
}],
|
|
215
|
+
details: {
|
|
216
|
+
filePath: resolved,
|
|
217
|
+
notice
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
} catch (err) {
|
|
221
|
+
return {
|
|
222
|
+
content: [{
|
|
223
|
+
type: "text",
|
|
224
|
+
text: `failed to read file: ${err.message}`
|
|
225
|
+
}],
|
|
226
|
+
isError: true
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
},
|
|
230
|
+
renderResult(result, _options, _theme) {
|
|
231
|
+
const text = result.content?.[0];
|
|
232
|
+
if (text?.type !== "text") return new Text("(no output)", 0, 0);
|
|
233
|
+
result.details?.filePath;
|
|
234
|
+
result.details?.isDirectory;
|
|
235
|
+
const notice = result.details?.notice;
|
|
236
|
+
const parsed = text.text.split("\n").map((line) => {
|
|
237
|
+
const m = line.match(/^(\s*\d+): (.*)$/);
|
|
238
|
+
if (m && m[1] && m[2]) return {
|
|
239
|
+
gutter: m[1].trim(),
|
|
240
|
+
text: m[2],
|
|
241
|
+
highlight: true
|
|
242
|
+
};
|
|
243
|
+
return {
|
|
244
|
+
text: line,
|
|
245
|
+
highlight: true
|
|
246
|
+
};
|
|
247
|
+
});
|
|
248
|
+
if (notice && parsed.length > 0) {
|
|
249
|
+
const last = parsed[parsed.length - 1];
|
|
250
|
+
if (last && last.text.startsWith(`(${notice}`)) {
|
|
251
|
+
parsed.pop();
|
|
252
|
+
const newLast = parsed[parsed.length - 1];
|
|
253
|
+
if (parsed.length && newLast && newLast.text === "") parsed.pop();
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
const notices = notice ? [notice] : void 0;
|
|
257
|
+
/** collapsed: head 3 + tail 5 visual lines */
|
|
258
|
+
const COLLAPSED_EXCERPTS = [{
|
|
259
|
+
focus: "head",
|
|
260
|
+
context: 3
|
|
261
|
+
}, {
|
|
262
|
+
focus: "tail",
|
|
263
|
+
context: 5
|
|
264
|
+
}];
|
|
265
|
+
const section = { blocks: [{ lines: parsed }] };
|
|
266
|
+
return boxRendererWindowed(() => [section], {
|
|
267
|
+
collapsed: { excerpts: COLLAPSED_EXCERPTS },
|
|
268
|
+
expanded: {}
|
|
269
|
+
}, notices, _options.expanded);
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
if (import.meta.vitest) {
|
|
274
|
+
const { describe, it, expect } = import.meta.vitest;
|
|
275
|
+
describe("expandPath", () => {
|
|
276
|
+
it("strips @ prefix", () => {
|
|
277
|
+
expect(expandPath("@/foo/bar")).toBe("/foo/bar");
|
|
278
|
+
});
|
|
279
|
+
it("expands ~ to homedir", () => {
|
|
280
|
+
expect(expandPath("~")).toBe(os.homedir());
|
|
281
|
+
});
|
|
282
|
+
it("expands ~/ to homedir + path", () => {
|
|
283
|
+
expect(expandPath("~/foo")).toBe(os.homedir() + "/foo");
|
|
284
|
+
});
|
|
285
|
+
it("returns unchanged path without prefix", () => {
|
|
286
|
+
expect(expandPath("/absolute/path")).toBe("/absolute/path");
|
|
287
|
+
expect(expandPath("relative/path")).toBe("relative/path");
|
|
288
|
+
});
|
|
289
|
+
});
|
|
290
|
+
describe("resolveToAbsolute", () => {
|
|
291
|
+
it("returns absolute paths unchanged", () => {
|
|
292
|
+
expect(resolveToAbsolute("/foo/bar", "/cwd")).toBe("/foo/bar");
|
|
293
|
+
});
|
|
294
|
+
it("resolves relative paths against cwd", () => {
|
|
295
|
+
expect(resolveToAbsolute("foo/bar", "/cwd")).toBe("/cwd/foo/bar");
|
|
296
|
+
});
|
|
297
|
+
it("expands ~ before resolving", () => {
|
|
298
|
+
expect(resolveToAbsolute("~/foo", "/cwd")).toBe(os.homedir() + "/foo");
|
|
299
|
+
});
|
|
300
|
+
});
|
|
301
|
+
describe("isSecretFile", () => {
|
|
302
|
+
it("blocks .env files", () => {
|
|
303
|
+
expect(isSecretFile("/home/user/.env")).toBe(true);
|
|
304
|
+
expect(isSecretFile("/home/user/.env.local")).toBe(true);
|
|
305
|
+
expect(isSecretFile("/home/user/.env.production")).toBe(true);
|
|
306
|
+
});
|
|
307
|
+
it("allows .env.example and friends", () => {
|
|
308
|
+
expect(isSecretFile("/home/user/.env.example")).toBe(false);
|
|
309
|
+
expect(isSecretFile("/home/user/.env.sample")).toBe(false);
|
|
310
|
+
expect(isSecretFile("/home/user/.env.template")).toBe(false);
|
|
311
|
+
});
|
|
312
|
+
it("allows other files", () => {
|
|
313
|
+
expect(isSecretFile("/home/user/config.json")).toBe(false);
|
|
314
|
+
expect(isSecretFile("/home/user/README.md")).toBe(false);
|
|
315
|
+
});
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
function read_default(pi) {
|
|
319
|
+
const cfg = getExtensionConfig("@bds_pi/read", CONFIG_DEFAULTS);
|
|
320
|
+
pi.registerTool(withPromptPatch(createReadTool(cfg)));
|
|
321
|
+
}
|
|
322
|
+
//#endregion
|
|
323
|
+
export { NORMAL_LIMITS, createReadTool, read_default as default, expandPath, isSecretFile, listDirectory, resolveToAbsolute, resolveWithVariants };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { ExtensionAPI, ToolDefinition } from "@mariozechner/pi-coding-agent";
|
|
2
|
+
|
|
3
|
+
//#region packages/extensions/search-sessions/index.d.ts
|
|
4
|
+
type SearchSessionsExtConfig = {
|
|
5
|
+
maxResults: number;
|
|
6
|
+
sessionsDir: string;
|
|
7
|
+
rgTimeoutMs: number;
|
|
8
|
+
};
|
|
9
|
+
interface BranchResult {
|
|
10
|
+
sessionId: string;
|
|
11
|
+
sessionName: string;
|
|
12
|
+
leafId: string;
|
|
13
|
+
workspace: string;
|
|
14
|
+
filePath: string;
|
|
15
|
+
timestampStart: string;
|
|
16
|
+
timestampEnd: string;
|
|
17
|
+
filesTouched: string[];
|
|
18
|
+
models: string[];
|
|
19
|
+
messageCount: number;
|
|
20
|
+
firstUserMessage: string;
|
|
21
|
+
/** concatenated user + assistant text for keyword search (not displayed) */
|
|
22
|
+
searchableText: string;
|
|
23
|
+
/** path to parent session file if this session was forked */
|
|
24
|
+
parentSessionPath?: string;
|
|
25
|
+
}
|
|
26
|
+
declare function createSearchSessionsTool(config?: SearchSessionsExtConfig): ToolDefinition;
|
|
27
|
+
declare function export_default(pi: ExtensionAPI): void;
|
|
28
|
+
//#endregion
|
|
29
|
+
export { BranchResult, createSearchSessionsTool, export_default as default };
|