mind-palace-graph 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/INSTALL.md +387 -0
- package/README.md +602 -0
- package/dist/api.d.ts +682 -0
- package/dist/api.js +660 -0
- package/dist/api.js.map +1 -0
- package/dist/cli.d.ts +95 -0
- package/dist/cli.js +856 -0
- package/dist/cli.js.map +1 -0
- package/dist/format.d.ts +16 -0
- package/dist/format.js +199 -0
- package/dist/format.js.map +1 -0
- package/dist/fuzzy.d.ts +45 -0
- package/dist/fuzzy.js +150 -0
- package/dist/fuzzy.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +528 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-server.d.ts +24 -0
- package/dist/mcp-server.js +187 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/mind-palace.d.ts +148 -0
- package/dist/mind-palace.js +780 -0
- package/dist/mind-palace.js.map +1 -0
- package/dist/nodes.d.ts +57 -0
- package/dist/nodes.js +220 -0
- package/dist/nodes.js.map +1 -0
- package/dist/pagination.d.ts +41 -0
- package/dist/pagination.js +63 -0
- package/dist/pagination.js.map +1 -0
- package/dist/palace-format.d.ts +30 -0
- package/dist/palace-format.js +146 -0
- package/dist/palace-format.js.map +1 -0
- package/dist/rg.d.ts +34 -0
- package/dist/rg.js +288 -0
- package/dist/rg.js.map +1 -0
- package/dist/sources.d.ts +87 -0
- package/dist/sources.js +457 -0
- package/dist/sources.js.map +1 -0
- package/dist/tokens.d.ts +35 -0
- package/dist/tokens.js +95 -0
- package/dist/tokens.js.map +1 -0
- package/dist/types.d.ts +236 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/package.json +67 -0
- package/skills/mpg-context/SKILL.md +556 -0
- package/skills/mpg-context/references/anti-patterns.md +133 -0
- package/skills/mpg-context/references/integration.md +123 -0
- package/skills/mpg-context/references/mind-palace.md +217 -0
- package/skills/mpg-context/references/multi-agent.md +147 -0
- package/skills/mpg-context/references/sources.md +120 -0
package/dist/rg.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thin wrapper over ripgrep's --json output.
|
|
3
|
+
*
|
|
4
|
+
* We don't reimplement grep. rg is the fastest, most correct regex
|
|
5
|
+
* engine available, and `--json` gives us structured matches we can
|
|
6
|
+
* build context nodes from. This module is the only place that
|
|
7
|
+
* knows about rg's CLI.
|
|
8
|
+
*
|
|
9
|
+
* Defensive posture against pathological input:
|
|
10
|
+
* - Pass `--max-columns` so rg refuses to emit megabyte-long
|
|
11
|
+
* `lines.text` payloads (minified assets, generated blobs).
|
|
12
|
+
* A preview marker still tells us a match existed.
|
|
13
|
+
* - Cap the in-memory line buffer. If rg emits a single JSON line
|
|
14
|
+
* longer than the cap, we kill the process and throw rather than
|
|
15
|
+
* letting V8 string-concat blow up O(n^2).
|
|
16
|
+
* - Clip per-Match `text` so a single oversized match line can't
|
|
17
|
+
* pin many megabytes into `pendingMatches` once per submatch.
|
|
18
|
+
* - Surface JSON parse failures via `MPG_DEBUG` instead of silently
|
|
19
|
+
* swallowing them — otherwise a truncated tail line looks like a
|
|
20
|
+
* clean "no matches" result.
|
|
21
|
+
*/
|
|
22
|
+
import type { Match, RgOptions, Source } from "./types.js";
|
|
23
|
+
export declare class RgError extends Error {
|
|
24
|
+
readonly code: number | null;
|
|
25
|
+
readonly stderr: string;
|
|
26
|
+
constructor(message: string, code: number | null, stderr: string);
|
|
27
|
+
}
|
|
28
|
+
export declare class RgNotFoundError extends Error {
|
|
29
|
+
constructor();
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Run ripgrep and yield structured matches as they arrive (streaming).
|
|
33
|
+
*/
|
|
34
|
+
export declare function runRg(pattern: string, source: Source, sourceContent: string | null, options?: RgOptions): AsyncGenerator<Match>;
|
package/dist/rg.js
ADDED
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thin wrapper over ripgrep's --json output.
|
|
3
|
+
*
|
|
4
|
+
* We don't reimplement grep. rg is the fastest, most correct regex
|
|
5
|
+
* engine available, and `--json` gives us structured matches we can
|
|
6
|
+
* build context nodes from. This module is the only place that
|
|
7
|
+
* knows about rg's CLI.
|
|
8
|
+
*
|
|
9
|
+
* Defensive posture against pathological input:
|
|
10
|
+
* - Pass `--max-columns` so rg refuses to emit megabyte-long
|
|
11
|
+
* `lines.text` payloads (minified assets, generated blobs).
|
|
12
|
+
* A preview marker still tells us a match existed.
|
|
13
|
+
* - Cap the in-memory line buffer. If rg emits a single JSON line
|
|
14
|
+
* longer than the cap, we kill the process and throw rather than
|
|
15
|
+
* letting V8 string-concat blow up O(n^2).
|
|
16
|
+
* - Clip per-Match `text` so a single oversized match line can't
|
|
17
|
+
* pin many megabytes into `pendingMatches` once per submatch.
|
|
18
|
+
* - Surface JSON parse failures via `MPG_DEBUG` instead of silently
|
|
19
|
+
* swallowing them — otherwise a truncated tail line looks like a
|
|
20
|
+
* clean "no matches" result.
|
|
21
|
+
*/
|
|
22
|
+
import { spawn } from "node:child_process";
|
|
23
|
+
import { randomBytes } from "node:crypto";
|
|
24
|
+
import { resolve as resolvePath } from "node:path";
|
|
25
|
+
export class RgError extends Error {
|
|
26
|
+
code;
|
|
27
|
+
stderr;
|
|
28
|
+
constructor(message, code, stderr) {
|
|
29
|
+
super(message);
|
|
30
|
+
this.code = code;
|
|
31
|
+
this.stderr = stderr;
|
|
32
|
+
this.name = "RgError";
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export class RgNotFoundError extends Error {
|
|
36
|
+
constructor() {
|
|
37
|
+
super("ripgrep (rg) is not installed or not on PATH. Install it from https://github.com/BurntSushi/ripgrep");
|
|
38
|
+
this.name = "RgNotFoundError";
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/** Hard cap on per-line size we will buffer before bailing out. */
|
|
42
|
+
const MAX_LINE_BUFFER_BYTES = 16 * 1024 * 1024; // 16 MB
|
|
43
|
+
/** Default cap on per-line columns rg will emit. */
|
|
44
|
+
const DEFAULT_MAX_COLUMNS = 1_000_000;
|
|
45
|
+
/** Hard cap on per-Match.text size we push downstream. */
|
|
46
|
+
const MAX_MATCH_TEXT_CHARS = 16 * 1024; // 16 KB per node's match line
|
|
47
|
+
function debugLog(msg) {
|
|
48
|
+
if (process.env.MPG_DEBUG) {
|
|
49
|
+
try {
|
|
50
|
+
process.stderr.write(`mpg[rg]: ${msg}\n`);
|
|
51
|
+
}
|
|
52
|
+
catch { /* ignore */ }
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Run ripgrep and yield structured matches as they arrive (streaming).
|
|
57
|
+
*/
|
|
58
|
+
export async function* runRg(pattern, source, sourceContent, options = {}) {
|
|
59
|
+
const args = ["--json", "--no-heading", "--no-messages"];
|
|
60
|
+
// Always cap per-line size. rg emits the preview form (still flags
|
|
61
|
+
// the match, just doesn't ship the body) for oversized lines.
|
|
62
|
+
const maxColumns = options.max_columns ?? DEFAULT_MAX_COLUMNS;
|
|
63
|
+
args.push("--max-columns", String(maxColumns));
|
|
64
|
+
args.push("--max-columns-preview");
|
|
65
|
+
if (options.case_insensitive)
|
|
66
|
+
args.push("-i");
|
|
67
|
+
if (options.word_match)
|
|
68
|
+
args.push("-w");
|
|
69
|
+
if (options.fixed_strings)
|
|
70
|
+
args.push("-F");
|
|
71
|
+
if (options.multiline)
|
|
72
|
+
args.push("-U", "--multiline-dotall");
|
|
73
|
+
if (options.hidden)
|
|
74
|
+
args.push("--hidden");
|
|
75
|
+
if (options.no_ignore)
|
|
76
|
+
args.push("-u");
|
|
77
|
+
if (options.include_globs) {
|
|
78
|
+
for (const g of options.include_globs)
|
|
79
|
+
args.push("--glob", g);
|
|
80
|
+
}
|
|
81
|
+
if (options.exclude_globs) {
|
|
82
|
+
for (const g of options.exclude_globs)
|
|
83
|
+
args.push("--glob", `!${g}`);
|
|
84
|
+
}
|
|
85
|
+
if (options.type)
|
|
86
|
+
args.push("--type", options.type);
|
|
87
|
+
if (options.glob_case_insensitive)
|
|
88
|
+
args.push("--glob-case-insensitive");
|
|
89
|
+
// Search target. Non-file sources go to a temp file with a random
|
|
90
|
+
// suffix — pid+ms is not enough when callers spawn many rg processes
|
|
91
|
+
// in the same millisecond.
|
|
92
|
+
let searchTarget;
|
|
93
|
+
let cleanup = null;
|
|
94
|
+
if (sourceContent !== null) {
|
|
95
|
+
const tmpDir = process.env.TMPDIR || process.env.TMP || process.env.TEMP || "/tmp";
|
|
96
|
+
const safeId = source.id.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 80);
|
|
97
|
+
const rand = randomBytes(6).toString("hex");
|
|
98
|
+
const tmpPath = resolvePath(tmpDir, `mpg-${process.pid}-${Date.now()}-${rand}-${safeId}`);
|
|
99
|
+
const { writeFileSync, unlinkSync } = await import("node:fs");
|
|
100
|
+
writeFileSync(tmpPath, sourceContent, "utf8");
|
|
101
|
+
cleanup = () => {
|
|
102
|
+
try {
|
|
103
|
+
unlinkSync(tmpPath);
|
|
104
|
+
}
|
|
105
|
+
catch { /* ignore */ }
|
|
106
|
+
};
|
|
107
|
+
searchTarget = tmpPath;
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
searchTarget = source.id;
|
|
111
|
+
}
|
|
112
|
+
args.push("--", pattern, searchTarget);
|
|
113
|
+
// Spawn rg.
|
|
114
|
+
let proc;
|
|
115
|
+
try {
|
|
116
|
+
proc = spawn("rg", args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
117
|
+
}
|
|
118
|
+
catch (err) {
|
|
119
|
+
if (cleanup)
|
|
120
|
+
cleanup();
|
|
121
|
+
if (err.code === "ENOENT") {
|
|
122
|
+
throw new RgNotFoundError();
|
|
123
|
+
}
|
|
124
|
+
throw err;
|
|
125
|
+
}
|
|
126
|
+
// Stream-parse: accumulate chunks, split by newline, process complete
|
|
127
|
+
// lines as they arrive. We track the buffer size so a pathological
|
|
128
|
+
// single line (e.g. minified asset containing many alternation hits)
|
|
129
|
+
// can't grow V8's string-concat path into O(n^2) memory.
|
|
130
|
+
let stderr = "";
|
|
131
|
+
if (proc.stderr) {
|
|
132
|
+
proc.stderr.setEncoding("utf8");
|
|
133
|
+
proc.stderr.on("data", (chunk) => { stderr += chunk; });
|
|
134
|
+
}
|
|
135
|
+
let lineBuffer = "";
|
|
136
|
+
let bufferOverflow = false;
|
|
137
|
+
let parseErrors = 0;
|
|
138
|
+
let pendingResolve = null;
|
|
139
|
+
const pendingMatches = [];
|
|
140
|
+
let streamEnded = false;
|
|
141
|
+
let aborted = false;
|
|
142
|
+
function clipMatchText(s) {
|
|
143
|
+
if (s.length <= MAX_MATCH_TEXT_CHARS)
|
|
144
|
+
return s;
|
|
145
|
+
const head = MAX_MATCH_TEXT_CHARS - 16;
|
|
146
|
+
return s.slice(0, head) + "…[clipped]";
|
|
147
|
+
}
|
|
148
|
+
function processLine(line) {
|
|
149
|
+
if (!line)
|
|
150
|
+
return;
|
|
151
|
+
let parsed;
|
|
152
|
+
try {
|
|
153
|
+
parsed = JSON.parse(line);
|
|
154
|
+
}
|
|
155
|
+
catch (err) {
|
|
156
|
+
parseErrors++;
|
|
157
|
+
debugLog(`JSON.parse failed on line of length ${line.length}: ${err.message}`);
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
if (parsed.type !== "match")
|
|
161
|
+
return;
|
|
162
|
+
const m = parsed;
|
|
163
|
+
// rg emits `lines.text` as a string when the line fits under
|
|
164
|
+
// --max-columns. With --max-columns-preview, oversized lines get a
|
|
165
|
+
// truncated preview but the field is still a string.
|
|
166
|
+
const rawText = m.data?.lines?.text;
|
|
167
|
+
if (typeof rawText !== "string") {
|
|
168
|
+
debugLog(`match record missing lines.text at line ${m.data?.line_number}`);
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
const txt = clipMatchText(stripTrailingNewline(rawText));
|
|
172
|
+
let matchSource;
|
|
173
|
+
if (sourceContent !== null) {
|
|
174
|
+
matchSource = source;
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
const filePath = resolvePath(m.data.path.text);
|
|
178
|
+
matchSource = { id: filePath, type: "file" };
|
|
179
|
+
}
|
|
180
|
+
for (const sub of m.data.submatches) {
|
|
181
|
+
pendingMatches.push({
|
|
182
|
+
source: matchSource,
|
|
183
|
+
line: m.data.line_number,
|
|
184
|
+
text: txt,
|
|
185
|
+
match_start: sub.start,
|
|
186
|
+
match_end: sub.end,
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
function abortProc(reason) {
|
|
191
|
+
if (aborted)
|
|
192
|
+
return;
|
|
193
|
+
aborted = true;
|
|
194
|
+
debugLog(`aborting rg: ${reason}`);
|
|
195
|
+
try {
|
|
196
|
+
proc.kill("SIGTERM");
|
|
197
|
+
}
|
|
198
|
+
catch { /* ignore */ }
|
|
199
|
+
}
|
|
200
|
+
proc.stdout.setEncoding("utf8");
|
|
201
|
+
proc.stdout.on("data", (chunk) => {
|
|
202
|
+
if (aborted)
|
|
203
|
+
return;
|
|
204
|
+
// Guard before any string-concat. If a single line is already
|
|
205
|
+
// bigger than our cap, kill rg and let the generator surface the
|
|
206
|
+
// error on close — we never want O(n^2) string-concat growth.
|
|
207
|
+
if (lineBuffer.length + chunk.length > MAX_LINE_BUFFER_BYTES) {
|
|
208
|
+
bufferOverflow = true;
|
|
209
|
+
abortProc(`single line exceeded ${MAX_LINE_BUFFER_BYTES} bytes`);
|
|
210
|
+
if (pendingResolve) {
|
|
211
|
+
pendingResolve();
|
|
212
|
+
pendingResolve = null;
|
|
213
|
+
}
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
lineBuffer += chunk;
|
|
217
|
+
const lines = lineBuffer.split("\n");
|
|
218
|
+
lineBuffer = lines.pop(); // keep incomplete last line
|
|
219
|
+
for (const line of lines)
|
|
220
|
+
processLine(line);
|
|
221
|
+
if (pendingMatches.length > 0 && pendingResolve) {
|
|
222
|
+
pendingResolve();
|
|
223
|
+
pendingResolve = null;
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
proc.stdout.on("end", () => {
|
|
227
|
+
// Process any trailing partial line — if we aborted because of
|
|
228
|
+
// overflow, skip this so we don't try to parse a multi-MB
|
|
229
|
+
// mid-line buffer.
|
|
230
|
+
if (!bufferOverflow && lineBuffer.trim())
|
|
231
|
+
processLine(lineBuffer);
|
|
232
|
+
streamEnded = true;
|
|
233
|
+
if (pendingResolve) {
|
|
234
|
+
pendingResolve();
|
|
235
|
+
pendingResolve = null;
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
const closePromise = new Promise((resolve, reject) => {
|
|
239
|
+
proc.on("error", reject);
|
|
240
|
+
proc.on("close", (code) => resolve({ code }));
|
|
241
|
+
});
|
|
242
|
+
// Async generator loop: drain pending matches, wait for more, repeat.
|
|
243
|
+
try {
|
|
244
|
+
let allEmitted = false;
|
|
245
|
+
while (!allEmitted) {
|
|
246
|
+
while (pendingMatches.length > 0) {
|
|
247
|
+
yield pendingMatches.shift();
|
|
248
|
+
}
|
|
249
|
+
if (streamEnded || bufferOverflow) {
|
|
250
|
+
allEmitted = true;
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
await new Promise((resolve) => {
|
|
254
|
+
pendingResolve = resolve;
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
finally {
|
|
260
|
+
const { code } = await closePromise;
|
|
261
|
+
if (cleanup)
|
|
262
|
+
cleanup();
|
|
263
|
+
if (parseErrors > 0) {
|
|
264
|
+
debugLog(`${parseErrors} JSON line(s) failed to parse during this scan`);
|
|
265
|
+
}
|
|
266
|
+
if (bufferOverflow) {
|
|
267
|
+
throw new RgError(`mpg: a single match line exceeded ${MAX_LINE_BUFFER_BYTES} bytes ` +
|
|
268
|
+
`for source ${source.id}. This usually means a minified asset or ` +
|
|
269
|
+
`generated blob — exclude it with --glob '!path' or pass a more ` +
|
|
270
|
+
`restrictive pattern.`, code, stderr);
|
|
271
|
+
}
|
|
272
|
+
// rg exit codes: 0 = matches, 1 = no matches, 2+ = error.
|
|
273
|
+
// We treat SIGTERM (null code on POSIX, sometimes propagated as
|
|
274
|
+
// exit 143 / signal name) as our own abort signal and don't
|
|
275
|
+
// surface it as a separate error.
|
|
276
|
+
if (!aborted && code !== null && code > 1) {
|
|
277
|
+
throw new RgError(`ripgrep exited with code ${code}: ${stderr.trim() || "unknown error"}`, code, stderr);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
function stripTrailingNewline(s) {
|
|
282
|
+
if (s.endsWith("\r\n"))
|
|
283
|
+
return s.slice(0, -2);
|
|
284
|
+
if (s.endsWith("\n"))
|
|
285
|
+
return s.slice(0, -1);
|
|
286
|
+
return s;
|
|
287
|
+
}
|
|
288
|
+
//# sourceMappingURL=rg.js.map
|
package/dist/rg.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rg.js","sourceRoot":"","sources":["../src/rg.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Source resolution.
|
|
3
|
+
*
|
|
4
|
+
* A "source" is a stream of text we can search. mpg supports four kinds:
|
|
5
|
+
*
|
|
6
|
+
* - file/glob: read from disk
|
|
7
|
+
* - command: exec a shell command, search its stdout
|
|
8
|
+
* - stdin: read piped input
|
|
9
|
+
* - url: fetch with HTTP GET
|
|
10
|
+
*
|
|
11
|
+
* For non-file sources we capture the content into memory and feed it
|
|
12
|
+
* to rg via a temp file (see rg.ts). This keeps rg as the single
|
|
13
|
+
* search engine while supporting arbitrary content types.
|
|
14
|
+
*/
|
|
15
|
+
import type { Source } from "./types.js";
|
|
16
|
+
/** Read stdin once and cache it. Returns cached value on subsequent calls. */
|
|
17
|
+
export declare function getStdin(): Promise<string>;
|
|
18
|
+
/** Reset the cached stdin (e.g. in test teardown). */
|
|
19
|
+
export declare function resetStdinCache(): void;
|
|
20
|
+
export interface ResolvedSource {
|
|
21
|
+
source: Source;
|
|
22
|
+
/** Inline content if we have it (stdin, command, url, or small files). */
|
|
23
|
+
content: string | null;
|
|
24
|
+
}
|
|
25
|
+
/** Expand globs into individual file paths using Node's built-in fs.glob. */
|
|
26
|
+
export declare function expandGlobs(patterns: string[]): Promise<string[]>;
|
|
27
|
+
/** Heuristic: if a path exists as a file/dir, classify it. */
|
|
28
|
+
export declare function classifyPath(p: string): "file" | "glob";
|
|
29
|
+
/**
|
|
30
|
+
* Resolve a list of path specs to actual file paths.
|
|
31
|
+
*
|
|
32
|
+
* If `stdinContent` is provided, it is used as the content when
|
|
33
|
+
* resolving `@-` specs instead of reading process.stdin again.
|
|
34
|
+
* This avoids double-reading stdin when both content-from-stdin and
|
|
35
|
+
* path-list-from-stdin are used in the same invocation.
|
|
36
|
+
*
|
|
37
|
+
* A spec can be:
|
|
38
|
+
* - `@-` read paths from stdin, one per line
|
|
39
|
+
* - `@<file>` read paths from a file, one per line
|
|
40
|
+
* - `path` a literal file or directory path
|
|
41
|
+
* - `glob` a glob pattern; expanded via fs.glob
|
|
42
|
+
*
|
|
43
|
+
* Directories are recursed into. Empty lines and `#` comments are
|
|
44
|
+
* ignored when reading from a file.
|
|
45
|
+
*/
|
|
46
|
+
export declare function resolvePathSpecs(specs: string[], stdinContent?: string | null): Promise<string[]>;
|
|
47
|
+
/**
|
|
48
|
+
* Split path specs into two buckets without expanding directories:
|
|
49
|
+
*
|
|
50
|
+
* - `files`: literal file paths the caller asked for. Each becomes
|
|
51
|
+
* a separate `runRg` invocation so they can be searched
|
|
52
|
+
* in parallel and their per-file content cache is hot.
|
|
53
|
+
* - `bulk`: directories and glob patterns. These get passed to
|
|
54
|
+
* rg as-is — rg walks them itself in parallel, much
|
|
55
|
+
* faster than fan-out-per-file from Node. Each bulk
|
|
56
|
+
* entry becomes one `runRg` invocation that may emit
|
|
57
|
+
* matches from many files.
|
|
58
|
+
*
|
|
59
|
+
* `@file` / `@-` are still expanded inline (the caller asked for an
|
|
60
|
+
* explicit list, so we respect that).
|
|
61
|
+
*
|
|
62
|
+
* Returns absolute paths so deduplication is stable across cwd-relative
|
|
63
|
+
* vs absolute inputs.
|
|
64
|
+
*/
|
|
65
|
+
export declare function classifyPathSpecs(specs: string[], stdinContent?: string | null): Promise<{
|
|
66
|
+
files: string[];
|
|
67
|
+
bulk: string[];
|
|
68
|
+
}>;
|
|
69
|
+
export declare function resolveFileSource(p: string): ResolvedSource;
|
|
70
|
+
export declare function resolveGlobSource(pattern: string): Promise<ResolvedSource[]>;
|
|
71
|
+
export declare function resolveCommandSource(cmd: string): ResolvedSource;
|
|
72
|
+
/**
|
|
73
|
+
* Capture a shell command's stdout for searching.
|
|
74
|
+
*
|
|
75
|
+
* Quoting handled correctly: the command runs through the platform
|
|
76
|
+
* shell (`bash -c` on POSIX, `cmd /c` on Windows), so `git log
|
|
77
|
+
* --grep="fix bug"` parses the way the user typed it.
|
|
78
|
+
*
|
|
79
|
+
* Output is capped at COMMAND_OUTPUT_MAX_BYTES and the command is
|
|
80
|
+
* killed after COMMAND_TIMEOUT_MS so a hanging or runaway command
|
|
81
|
+
* can't lock up the agent harness.
|
|
82
|
+
*/
|
|
83
|
+
export declare function captureCommand(cmd: string): Promise<string>;
|
|
84
|
+
/** Deprecated: use getStdin() instead to avoid double-reads. */
|
|
85
|
+
export declare function captureStdin(): Promise<string>;
|
|
86
|
+
export declare function captureUrl(url: string): Promise<string>;
|
|
87
|
+
export declare function resolveUrlSource(url: string): ResolvedSource;
|