pi-readseek 0.3.3 → 0.3.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/README.md +6 -0
- package/package.json +4 -4
- package/src/confusable-hyphens.ts +6 -0
- package/src/edit-classify.ts +0 -2
- package/src/edit-diff.ts +3 -6
- package/src/edit.ts +0 -2
- package/src/hashline.ts +1 -10
- package/src/readseek-settings.ts +6 -134
- package/src/tool-prompt-metadata.ts +2 -8
- package/prompts/find.md +0 -18
- package/prompts/ls.md +0 -11
package/README.md
CHANGED
|
@@ -37,6 +37,12 @@ npm install --save-dev @jarkkojs/readseek
|
|
|
37
37
|
- **write** — creates or overwrites whole files and returns anchors for
|
|
38
38
|
immediate follow-up edits.
|
|
39
39
|
|
|
40
|
+
## Related
|
|
41
|
+
|
|
42
|
+
- [readseek.vim](https://github.com/jarkkojs/readseek.vim) — Vim 9 plugin
|
|
43
|
+
frontend for the readseek CLI. Provides go-to-definition, references,
|
|
44
|
+
rename, hover, and structural search from within Vim.
|
|
45
|
+
|
|
40
46
|
## Licensing
|
|
41
47
|
|
|
42
48
|
`pi-readseek` is licensed under `MIT`. See [LICENSE](LICENSE) for more
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-readseek",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.5",
|
|
4
4
|
"description": "Pi extension for readseek-backed hash-anchored read/edit/grep, structural code maps, structural search, and file exploration",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
],
|
|
16
16
|
"repository": {
|
|
17
17
|
"type": "git",
|
|
18
|
-
"url": "git+https://github.com/
|
|
18
|
+
"url": "git+https://github.com/jarkkojs/pi-readseek.git"
|
|
19
19
|
},
|
|
20
20
|
"author": "Maxwell Newman",
|
|
21
21
|
"license": "MIT",
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
"test": "tests"
|
|
68
68
|
},
|
|
69
69
|
"bugs": {
|
|
70
|
-
"url": "https://github.com/
|
|
70
|
+
"url": "https://github.com/jarkkojs/pi-readseek/issues"
|
|
71
71
|
},
|
|
72
|
-
"homepage": "https://github.com/
|
|
72
|
+
"homepage": "https://github.com/jarkkojs/pi-readseek#readme"
|
|
73
73
|
}
|
package/src/edit-classify.ts
CHANGED
package/src/edit-diff.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as Diff from "diff";
|
|
2
2
|
import { computeLineHash } from "./hashline.js";
|
|
3
|
+
import { CONFUSABLE_HYPHENS_RE } from "./confusable-hyphens.js";
|
|
3
4
|
|
|
4
|
-
// ─── Line ending normalization ──────────────────────────────────────────
|
|
5
5
|
|
|
6
6
|
export function detectLineEnding(content: string): "\r\n" | "\n" {
|
|
7
7
|
const crlfIdx = content.indexOf("\r\n");
|
|
@@ -31,15 +31,13 @@ export function hasBareCarriageReturn(content: string): boolean {
|
|
|
31
31
|
return content.replace(/\r\n/g, "").includes("\r");
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
// ─── Fuzzy text matching ────────────────────────────────────────────────
|
|
35
34
|
|
|
36
35
|
const SINGLE_QUOTES_RE = /[\u2018\u2019\u201A\u201B]/g;
|
|
37
36
|
const DOUBLE_QUOTES_RE = /[\u201C\u201D\u201E\u201F]/g;
|
|
38
|
-
const HYPHENS_RE = /[\u2010\u2011\u2012\u2013\u2014\u2015\u2212]/g;
|
|
39
37
|
const UNICODE_SPACES_RE = /[\u00A0\u2002-\u200A\u202F\u205F\u3000]/g;
|
|
40
38
|
|
|
41
39
|
function normalizeFuzzyChar(ch: string): string {
|
|
42
|
-
return ch.replace(SINGLE_QUOTES_RE, "'").replace(DOUBLE_QUOTES_RE, '"').replace(
|
|
40
|
+
return ch.replace(SINGLE_QUOTES_RE, "'").replace(DOUBLE_QUOTES_RE, '"').replace(CONFUSABLE_HYPHENS_RE, "-").replace(UNICODE_SPACES_RE, " ");
|
|
43
41
|
}
|
|
44
42
|
|
|
45
43
|
function normalizeForFuzzyMatch(text: string): string {
|
|
@@ -49,7 +47,7 @@ function normalizeForFuzzyMatch(text: string): string {
|
|
|
49
47
|
.join("\n")
|
|
50
48
|
.replace(SINGLE_QUOTES_RE, "'")
|
|
51
49
|
.replace(DOUBLE_QUOTES_RE, '"')
|
|
52
|
-
.replace(
|
|
50
|
+
.replace(CONFUSABLE_HYPHENS_RE, "-")
|
|
53
51
|
.replace(UNICODE_SPACES_RE, " ");
|
|
54
52
|
}
|
|
55
53
|
|
|
@@ -199,7 +197,6 @@ export function replaceText(
|
|
|
199
197
|
};
|
|
200
198
|
}
|
|
201
199
|
|
|
202
|
-
// ─── Diff generation ────────────────────────────────────────────────────
|
|
203
200
|
|
|
204
201
|
export function generateDiffString(
|
|
205
202
|
oldContent: string,
|
package/src/edit.ts
CHANGED
|
@@ -45,7 +45,6 @@ export function isBinaryBuffer(buf: Buffer): boolean {
|
|
|
45
45
|
return buf.includes(0);
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
// ─── Schema ─────────────────────────────────────────────────────────────
|
|
49
48
|
|
|
50
49
|
const hashlineEditItemSchema = Type.Union([
|
|
51
50
|
Type.Object({ set_line: Type.Object({ anchor: Type.String(), new_text: Type.String() }) }, { additionalProperties: true }),
|
|
@@ -127,7 +126,6 @@ export interface EditToolOptions {
|
|
|
127
126
|
syntaxValidate?: SyntaxValidateOptions["syntaxValidate"];
|
|
128
127
|
}
|
|
129
128
|
|
|
130
|
-
// ─── Registration ───────────────────────────────────────────────────────
|
|
131
129
|
|
|
132
130
|
export function registerEditTool(pi: ExtensionAPI, options: EditToolOptions = {}) {
|
|
133
131
|
const toolConfig = {
|
package/src/hashline.ts
CHANGED
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
import xxhashWasm from "xxhash-wasm";
|
|
9
9
|
import { throwIfAborted } from "./runtime.js";
|
|
10
10
|
import type { ReadseekLine } from "./readseek-value.js";
|
|
11
|
+
import { CONFUSABLE_HYPHENS_RE } from "./confusable-hyphens.js";
|
|
11
12
|
|
|
12
|
-
// ─── Types ──────────────────────────────────────────────────────────────
|
|
13
13
|
|
|
14
14
|
export type HashlineEditItem =
|
|
15
15
|
| { set_line: { anchor: string; new_text: string } }
|
|
@@ -52,7 +52,6 @@ interface NoopEdit {
|
|
|
52
52
|
currentContent: string;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
// ─── Hash computation ───────────────────────────────────────────────────
|
|
56
55
|
|
|
57
56
|
const HASH_LEN = 3;
|
|
58
57
|
const RADIX = 16;
|
|
@@ -62,7 +61,6 @@ const DICT = Array.from({ length: HASH_MOD }, (_, i) => i.toString(RADIX).padSta
|
|
|
62
61
|
const HASHLINE_PREFIX_RE = /^\d+:[0-9a-zA-Z]{1,16}\|/;
|
|
63
62
|
const DIFF_PLUS_RE = /^\+(?!\+)/;
|
|
64
63
|
const HASH_ONLY_PREFIX_RE = /^[0-9a-f]{3}\|/;
|
|
65
|
-
const CONFUSABLE_HYPHENS_RE = /[\u2010\u2011\u2012\u2013\u2014\u2212\uFE63\uFF0D]/g;
|
|
66
64
|
const HASH_RELOCATION_WINDOW_BASE = 20;
|
|
67
65
|
const HASH_RELOCATION_WINDOW_CAP = 100;
|
|
68
66
|
|
|
@@ -128,7 +126,6 @@ export function hashLines(content: string): string {
|
|
|
128
126
|
.join("\n");
|
|
129
127
|
}
|
|
130
128
|
|
|
131
|
-
// ─── Parsing ────────────────────────────────────────────────────────────
|
|
132
129
|
|
|
133
130
|
export function parseLineRef(ref: string): { line: number; hash: string; content?: string } {
|
|
134
131
|
const contentMatch = ref.match(/^[^|]*\|(.*)$/);
|
|
@@ -142,7 +139,6 @@ export function parseLineRef(ref: string): { line: number; hash: string; content
|
|
|
142
139
|
return { line, hash: match[2], content: contentAfterPipe };
|
|
143
140
|
}
|
|
144
141
|
|
|
145
|
-
// ─── Mismatch formatting ────────────────────────────────────────────────
|
|
146
142
|
|
|
147
143
|
function tokenSimilarity(a: string, b: string): number {
|
|
148
144
|
const tokA = new Set(a.trim().split(/\s+/));
|
|
@@ -241,7 +237,6 @@ function formatMismatchError(
|
|
|
241
237
|
return { message: out.join("\n"), updatedAnchors };
|
|
242
238
|
}
|
|
243
239
|
|
|
244
|
-
// ─── DST preprocessing helpers ──────────────────────────────────────────
|
|
245
240
|
|
|
246
241
|
function splitDst(dst: string): string[] {
|
|
247
242
|
if (dst === "") return [];
|
|
@@ -280,7 +275,6 @@ function stripNewLinePrefixes(lines: string[]): string[] {
|
|
|
280
275
|
);
|
|
281
276
|
}
|
|
282
277
|
|
|
283
|
-
// ─── Whitespace / format helpers ────────────────────────────────────────
|
|
284
278
|
|
|
285
279
|
function stripAllWhitespace(s: string): string {
|
|
286
280
|
return s.replace(/\s+/g, "");
|
|
@@ -362,7 +356,6 @@ function restoreOldWrappedLines(oldLines: string[], newLines: string[]): string[
|
|
|
362
356
|
return out;
|
|
363
357
|
}
|
|
364
358
|
|
|
365
|
-
// ─── Echo stripping ─────────────────────────────────────────────────────
|
|
366
359
|
|
|
367
360
|
function stripInsertAnchorEcho(anchorLine: string, dst: string[]): string[] {
|
|
368
361
|
if (dst.length > 1 && wsEq(dst[0], anchorLine)) return dst.slice(1);
|
|
@@ -378,7 +371,6 @@ function stripRangeBoundaryEcho(fileLines: string[], start: number, end: number,
|
|
|
378
371
|
return out;
|
|
379
372
|
}
|
|
380
373
|
|
|
381
|
-
// ─── Edit parser ────────────────────────────────────────────────────────
|
|
382
374
|
|
|
383
375
|
function parseHashlineEditItem(edit: HashlineEditItem): ParsedEdit {
|
|
384
376
|
if ("set_line" in edit) {
|
|
@@ -404,7 +396,6 @@ function parseHashlineEditItem(edit: HashlineEditItem): ParsedEdit {
|
|
|
404
396
|
throw new Error("replace edits are applied separately");
|
|
405
397
|
}
|
|
406
398
|
|
|
407
|
-
// ─── Main edit engine ───────────────────────────────────────────────────
|
|
408
399
|
|
|
409
400
|
export function applyHashlineEdits(
|
|
410
401
|
content: string,
|
package/src/readseek-settings.ts
CHANGED
|
@@ -48,144 +48,16 @@ function invalid(source: string, path: string): ReadseekSettingsWarning {
|
|
|
48
48
|
return { source, path, message: `Invalid readseek setting at ${path}` };
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
function readJsonObjectEnd(text: string, open: number): number {
|
|
52
|
-
let depth = 0;
|
|
53
|
-
let inString = false;
|
|
54
|
-
let escaped = false;
|
|
55
|
-
|
|
56
|
-
for (let i = open; i < text.length; i += 1) {
|
|
57
|
-
const char = text[i];
|
|
58
|
-
if (inString) {
|
|
59
|
-
if (escaped) escaped = false;
|
|
60
|
-
else if (char === "\\") escaped = true;
|
|
61
|
-
else if (char === '"') inString = false;
|
|
62
|
-
continue;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (char === '"') {
|
|
66
|
-
inString = true;
|
|
67
|
-
} else if (char === "{") {
|
|
68
|
-
depth += 1;
|
|
69
|
-
} else if (char === "}") {
|
|
70
|
-
depth -= 1;
|
|
71
|
-
if (depth === 0) return i;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
return -1;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function readJsonStringEnd(text: string, quote: number): number {
|
|
79
|
-
let escaped = false;
|
|
80
|
-
for (let i = quote + 1; i < text.length; i += 1) {
|
|
81
|
-
const char = text[i];
|
|
82
|
-
if (escaped) escaped = false;
|
|
83
|
-
else if (char === "\\") escaped = true;
|
|
84
|
-
else if (char === '"') return i;
|
|
85
|
-
}
|
|
86
|
-
return -1;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
function readTopLevelObjectBodies(rawText: string, section: string): string[] {
|
|
90
|
-
const bodies: string[] = [];
|
|
91
|
-
let depth = 0;
|
|
92
|
-
|
|
93
|
-
for (let i = 0; i < rawText.length; i += 1) {
|
|
94
|
-
const char = rawText[i];
|
|
95
|
-
if (char === '"') {
|
|
96
|
-
const end = readJsonStringEnd(rawText, i);
|
|
97
|
-
if (end < 0) return bodies;
|
|
98
|
-
|
|
99
|
-
if (depth === 1) {
|
|
100
|
-
const fieldName = rawText.slice(i + 1, end);
|
|
101
|
-
let cursor = end + 1;
|
|
102
|
-
while (/\s/.test(rawText[cursor] ?? "")) cursor += 1;
|
|
103
|
-
|
|
104
|
-
if (rawText[cursor] === ":") {
|
|
105
|
-
cursor += 1;
|
|
106
|
-
while (/\s/.test(rawText[cursor] ?? "")) cursor += 1;
|
|
107
|
-
if (fieldName === section && rawText[cursor] === "{") {
|
|
108
|
-
const objectEnd = readJsonObjectEnd(rawText, cursor);
|
|
109
|
-
if (objectEnd < 0) return bodies;
|
|
110
|
-
bodies.push(rawText.slice(cursor + 1, objectEnd));
|
|
111
|
-
i = objectEnd;
|
|
112
|
-
continue;
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
i = end;
|
|
117
|
-
} else if (char === "{") {
|
|
118
|
-
depth += 1;
|
|
119
|
-
} else if (char === "}") {
|
|
120
|
-
depth = Math.max(0, depth - 1);
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
return bodies;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
function rawFieldTokens(rawText: string, path: string): string[] {
|
|
128
|
-
const [section, key] = path.split(".");
|
|
129
|
-
const bodies = readTopLevelObjectBodies(rawText, section);
|
|
130
|
-
if (bodies.length !== 1) return [];
|
|
131
|
-
|
|
132
|
-
const body = bodies[0];
|
|
133
|
-
const tokens: string[] = [];
|
|
134
|
-
let depth = 0;
|
|
135
|
-
|
|
136
|
-
for (let i = 0; i < body.length; i += 1) {
|
|
137
|
-
const char = body[i];
|
|
138
|
-
if (char === '"') {
|
|
139
|
-
const end = readJsonStringEnd(body, i);
|
|
140
|
-
if (end < 0) return tokens;
|
|
141
|
-
|
|
142
|
-
if (depth === 0) {
|
|
143
|
-
const fieldName = body.slice(i + 1, end);
|
|
144
|
-
let cursor = end + 1;
|
|
145
|
-
while (/\s/.test(body[cursor] ?? "")) cursor += 1;
|
|
146
|
-
|
|
147
|
-
if (body[cursor] === ":") {
|
|
148
|
-
cursor += 1;
|
|
149
|
-
while (/\s/.test(body[cursor] ?? "")) cursor += 1;
|
|
150
|
-
if (fieldName === key) {
|
|
151
|
-
const valueStart = cursor;
|
|
152
|
-
while (cursor < body.length && !/[,}\s]/.test(body[cursor])) cursor += 1;
|
|
153
|
-
tokens.push(body.slice(valueStart, cursor));
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
i = end;
|
|
158
|
-
} else if (char === "{" || char === "[") {
|
|
159
|
-
depth += 1;
|
|
160
|
-
} else if (char === "}" || char === "]") {
|
|
161
|
-
depth = Math.max(0, depth - 1);
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
return tokens;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
function isStrictJsonPositiveInteger(rawText: string, path: string, value: unknown): value is number {
|
|
169
|
-
const tokens = rawFieldTokens(rawText, path);
|
|
170
|
-
return (
|
|
171
|
-
typeof value === "number" &&
|
|
172
|
-
Number.isSafeInteger(value) &&
|
|
173
|
-
value > 0 &&
|
|
174
|
-
tokens.length === 1 &&
|
|
175
|
-
/^[1-9][0-9]*$/.test(tokens[0])
|
|
176
|
-
);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
51
|
function readPositive(
|
|
180
52
|
raw: Record<string, unknown>,
|
|
181
53
|
key: string,
|
|
182
54
|
path: string,
|
|
183
55
|
source: string,
|
|
184
|
-
rawText: string,
|
|
185
56
|
warnings: ReadseekSettingsWarning[],
|
|
186
57
|
): number | undefined {
|
|
187
58
|
if (!(key in raw)) return undefined;
|
|
188
|
-
|
|
59
|
+
const val = raw[key];
|
|
60
|
+
if (typeof val === "number" && Number.isSafeInteger(val) && val > 0) return val;
|
|
189
61
|
warnings.push(invalid(source, path));
|
|
190
62
|
return undefined;
|
|
191
63
|
}
|
|
@@ -203,16 +75,16 @@ function readBoolean(
|
|
|
203
75
|
return undefined;
|
|
204
76
|
}
|
|
205
77
|
|
|
206
|
-
function validateSettings(raw: unknown, source: string
|
|
78
|
+
function validateSettings(raw: unknown, source: string): ReadseekSettingsResult {
|
|
207
79
|
const settings: ReadseekJsonSettings = {};
|
|
208
80
|
const warnings: ReadseekSettingsWarning[] = [];
|
|
209
81
|
if (!isRecord(raw)) return { settings, warnings };
|
|
210
82
|
|
|
211
83
|
if (isRecord(raw.grep)) {
|
|
212
84
|
const grep: NonNullable<ReadseekJsonSettings["grep"]> = {};
|
|
213
|
-
const maxLines = readPositive(raw.grep, "maxLines", "grep.maxLines", source,
|
|
85
|
+
const maxLines = readPositive(raw.grep, "maxLines", "grep.maxLines", source, warnings);
|
|
214
86
|
if (maxLines !== undefined) grep.maxLines = maxLines;
|
|
215
|
-
const maxBytes = readPositive(raw.grep, "maxBytes", "grep.maxBytes", source,
|
|
87
|
+
const maxBytes = readPositive(raw.grep, "maxBytes", "grep.maxBytes", source, warnings);
|
|
216
88
|
if (maxBytes !== undefined) grep.maxBytes = maxBytes;
|
|
217
89
|
if (Object.keys(grep).length > 0) settings.grep = grep;
|
|
218
90
|
}
|
|
@@ -246,7 +118,7 @@ function readSettingsFile(path: string): ReadseekSettingsResult {
|
|
|
246
118
|
|
|
247
119
|
try {
|
|
248
120
|
const text = readFileSync(path, "utf8");
|
|
249
|
-
return validateSettings(JSON.parse(text) as unknown, path
|
|
121
|
+
return validateSettings(JSON.parse(text) as unknown, path);
|
|
250
122
|
} catch (error) {
|
|
251
123
|
const message = error instanceof Error ? error.message : String(error);
|
|
252
124
|
return { settings: {}, warnings: [{ source: path, message: `Invalid JSON: ${message}` }] };
|
|
@@ -5,8 +5,7 @@ const COMPACT_DESCRIPTIONS: Record<string, string> = {
|
|
|
5
5
|
"read.md": "Read text files/images by path; text has LINE:HASH anchors, images return attachments.",
|
|
6
6
|
"edit.md": "Edit existing text files using fresh LINE:HASH anchors from read, grep, search, or write.",
|
|
7
7
|
"grep.md": "Search file contents; non-summary results include LINE:HASH anchors for edits.",
|
|
8
|
-
|
|
9
|
-
"ls.md": "List one directory with directories first and dotfiles included.",
|
|
8
|
+
|
|
10
9
|
"write.md": "Create or overwrite a complete file and return anchors.",
|
|
11
10
|
"sg.md": "Search code by AST pattern and return anchored matches.",
|
|
12
11
|
};
|
|
@@ -25,12 +24,7 @@ const COMPACT_GUIDELINES: Record<string, string[]> = {
|
|
|
25
24
|
"Use grep for text search and edit-ready matching anchors.",
|
|
26
25
|
"Use grep summary mode for broad count/file discovery before narrowing.",
|
|
27
26
|
],
|
|
28
|
-
|
|
29
|
-
"Use find for recursive file discovery by basename glob.",
|
|
30
|
-
],
|
|
31
|
-
"ls.md": [
|
|
32
|
-
"Use ls to inspect one directory; use find for recursion.",
|
|
33
|
-
],
|
|
27
|
+
|
|
34
28
|
"write.md": [
|
|
35
29
|
"Use write to create files or intentionally overwrite whole files.",
|
|
36
30
|
"Use edit rather than write for small changes or appends to existing files.",
|
package/prompts/find.md
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
Find files or directories recursively by basename. Uses glob patterns by default, respects nested `.gitignore`, includes hidden entries, and returns relative paths.
|
|
2
|
-
|
|
3
|
-
## Parameters
|
|
4
|
-
|
|
5
|
-
- `pattern` — required. Glob by default; with `regex: true`, JavaScript regex against each basename.
|
|
6
|
-
- `path` — directory to search, default cwd.
|
|
7
|
-
- `type` — `"file"` default, `"dir"`, or `"any"`.
|
|
8
|
-
- `limit` — max returned entries after filtering/sorting, default 1000.
|
|
9
|
-
- `maxDepth` — non-negative directory depth limit.
|
|
10
|
-
- `sortBy` — `"name"` default, `"mtime"`, or `"size"`; use `reverse: true` for descending/newest/largest first.
|
|
11
|
-
- `modifiedSince` — keep entries modified strictly after an ISO date/time or relative age like `30m`, `1h`, `24h`, `7d`.
|
|
12
|
-
- `minSize` / `maxSize` — inclusive file-size filters; numbers are bytes, strings accept 1024-based `KB`, `MB`, `GB`, etc. Directories are not removed by size filters.
|
|
13
|
-
|
|
14
|
-
## Output and usage
|
|
15
|
-
|
|
16
|
-
Output is one relative path per line. Directories end with `/`. Filtering and sorting happen before `limit`, so newest/largest queries work as expected.
|
|
17
|
-
|
|
18
|
-
Use `find` for recursive name discovery, `ls` for one directory, `grep` or `search` for contents, and `read` for file content. Remember: `pattern` matches basenames, not full paths.
|
package/prompts/ls.md
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
List one directory. Output is directories first (with `/`), then files, sorted alphabetically; dotfiles are included.
|
|
2
|
-
|
|
3
|
-
## Parameters
|
|
4
|
-
|
|
5
|
-
- `path` — directory to list, default cwd.
|
|
6
|
-
- `limit` — max entries, default 500; must be positive.
|
|
7
|
-
- `glob` — optional entry-name filter such as `*.ts`, `.env*`, or `test-*`.
|
|
8
|
-
|
|
9
|
-
## Usage
|
|
10
|
-
|
|
11
|
-
Use `ls` to inspect one known directory. Use `find` for recursive discovery, `grep` or `search` for contents, and `read` for file content. If output exceeds `limit` or 50 KB, narrow with `glob` or switch to `find`.
|