@mastra/code-sdk 1.15.0-alpha.1 → 1.15.0-alpha.11
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/acp/agent.d.ts.map +1 -1
- package/dist/acp/agent.js +1 -1
- package/dist/acp/agent.js.map +1 -1
- package/dist/acp/event-mapper.d.ts.map +1 -1
- package/dist/acp/event-mapper.js +1 -1
- package/dist/acp/event-mapper.js.map +1 -1
- package/dist/agent-connections/signal-provider.d.ts +1 -1
- package/dist/agent-connections/signal-provider.d.ts.map +1 -1
- package/dist/agent-connections/signal-provider.js.map +1 -1
- package/dist/agent-connections/state-processor.d.ts +2 -2
- package/dist/agent-connections/state-processor.d.ts.map +1 -1
- package/dist/agent-connections/state-processor.js.map +1 -1
- package/dist/agent-connections/thread-state.d.ts +1 -1
- package/dist/agent-connections/thread-state.d.ts.map +1 -1
- package/dist/agent-connections/thread-state.js.map +1 -1
- package/dist/agent-connections/tools.d.ts.map +1 -1
- package/dist/agent-connections/tools.js +1 -1
- package/dist/agent-connections/tools.js.map +1 -1
- package/dist/agents/background-completion.d.ts +15 -2
- package/dist/agents/background-completion.d.ts.map +1 -1
- package/dist/agents/background-completion.js +19 -2
- package/dist/agents/background-completion.js.map +1 -1
- package/dist/agents/credential-resolver.d.ts +6 -0
- package/dist/agents/credential-resolver.d.ts.map +1 -1
- package/dist/agents/credential-resolver.js +13 -4
- package/dist/agents/credential-resolver.js.map +1 -1
- package/dist/agents/memory.d.ts.map +1 -1
- package/dist/agents/memory.js +1 -1
- package/dist/agents/memory.js.map +1 -1
- package/dist/agents/sandbox-filesystem.d.ts +32 -10
- package/dist/agents/sandbox-filesystem.d.ts.map +1 -1
- package/dist/agents/sandbox-filesystem.js +208 -66
- package/dist/agents/sandbox-filesystem.js.map +1 -1
- package/dist/agents/workspace.d.ts.map +1 -1
- package/dist/agents/workspace.js +1 -0
- package/dist/agents/workspace.js.map +1 -1
- package/dist/experimental-agent.d.ts +1 -1
- package/dist/experimental-agent.d.ts.map +1 -1
- package/dist/experimental-agent.js.map +1 -1
- package/dist/factory/client.d.ts +41 -0
- package/dist/factory/client.d.ts.map +1 -0
- package/dist/factory/client.js +98 -0
- package/dist/factory/client.js.map +1 -0
- package/dist/factory/remote-controller.d.ts +34 -0
- package/dist/factory/remote-controller.d.ts.map +1 -0
- package/dist/factory/remote-controller.js +43 -0
- package/dist/factory/remote-controller.js.map +1 -0
- package/dist/factory/remote-session.d.ts +210 -0
- package/dist/factory/remote-session.d.ts.map +1 -0
- package/dist/factory/remote-session.js +420 -0
- package/dist/factory/remote-session.js.map +1 -0
- package/dist/headless/cli.d.ts +7 -0
- package/dist/headless/cli.d.ts.map +1 -1
- package/dist/headless/cli.js +19 -3
- package/dist/headless/cli.js.map +1 -1
- package/dist/headless/flags.d.ts.map +1 -1
- package/dist/headless/flags.js +2 -1
- package/dist/headless/flags.js.map +1 -1
- package/dist/headless/format.d.ts +2 -0
- package/dist/headless/format.d.ts.map +1 -1
- package/dist/headless/format.js +13 -1
- package/dist/headless/format.js.map +1 -1
- package/dist/headless/run-mc.d.ts.map +1 -1
- package/dist/headless/run-mc.js +48 -20
- package/dist/headless/run-mc.js.map +1 -1
- package/dist/index.d.ts +22 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +69 -25
- package/dist/index.js.map +1 -1
- package/dist/onboarding/pack-activation.d.ts +2 -11
- package/dist/onboarding/pack-activation.d.ts.map +1 -1
- package/dist/onboarding/pack-activation.js.map +1 -1
- package/dist/onboarding/settings.d.ts +18 -0
- package/dist/onboarding/settings.d.ts.map +1 -1
- package/dist/onboarding/settings.js +28 -3
- package/dist/onboarding/settings.js.map +1 -1
- package/dist/platform/index.d.ts +74 -0
- package/dist/platform/index.d.ts.map +1 -0
- package/dist/platform/index.js +200 -0
- package/dist/platform/index.js.map +1 -0
- package/dist/process-memory-diagnostics.d.ts +2 -1
- package/dist/process-memory-diagnostics.d.ts.map +1 -1
- package/dist/process-memory-diagnostics.js.map +1 -1
- package/dist/providers/model-ids.d.ts +1 -0
- package/dist/providers/model-ids.d.ts.map +1 -1
- package/dist/providers/model-ids.js +6 -4
- package/dist/providers/model-ids.js.map +1 -1
- package/dist/tools/web-search.d.ts +1 -1
- package/dist/tools/web-search.d.ts.map +1 -1
- package/dist/tools/web-search.js.map +1 -1
- package/dist/tools/workflows/create-workflow.d.ts.map +1 -1
- package/dist/tools/workflows/create-workflow.js +5 -1
- package/dist/tools/workflows/create-workflow.js.map +1 -1
- package/dist/utils/local-observability.d.ts +19 -0
- package/dist/utils/local-observability.d.ts.map +1 -0
- package/dist/utils/local-observability.js +57 -0
- package/dist/utils/local-observability.js.map +1 -0
- package/dist/utils/notification-dispatch.d.ts +27 -12
- package/dist/utils/notification-dispatch.d.ts.map +1 -1
- package/dist/utils/notification-dispatch.js +46 -24
- package/dist/utils/notification-dispatch.js.map +1 -1
- package/dist/utils/signals-pubsub.d.ts +5 -3
- package/dist/utils/signals-pubsub.d.ts.map +1 -1
- package/dist/utils/signals-pubsub.js +8 -6
- package/dist/utils/signals-pubsub.js.map +1 -1
- package/dist/utils/wake-session.d.ts +44 -0
- package/dist/utils/wake-session.d.ts.map +1 -0
- package/dist/utils/wake-session.js +86 -0
- package/dist/utils/wake-session.js.map +1 -0
- package/dist/workflows/register-primitives.js +4 -1
- package/dist/workflows/register-primitives.js.map +1 -1
- package/package.json +23 -23
|
@@ -116,19 +116,20 @@ export declare class SandboxFilesystem implements WorkspaceFilesystem {
|
|
|
116
116
|
*/
|
|
117
117
|
walk(path: string, options?: WalkOptions): Promise<WalkEntry[]>;
|
|
118
118
|
/**
|
|
119
|
-
* Content search executed inside the sandbox in one command
|
|
120
|
-
* ripgrep
|
|
121
|
-
* `grep -rnE`. Patterns the
|
|
122
|
-
* word boundaries, lookarounds,
|
|
123
|
-
* {@link UnsupportedGrepPatternError} so
|
|
119
|
+
* Content search executed inside the sandbox in one command, using the best
|
|
120
|
+
* engine the sandbox has: ripgrep, then GNU grep (with git choosing files
|
|
121
|
+
* inside repositories), then POSIX `grep -rnE`. Patterns the grep engines
|
|
122
|
+
* can't express (PCRE-style classes, word boundaries, lookarounds,
|
|
123
|
+
* non-greedy quantifiers) throw {@link UnsupportedGrepPatternError} so
|
|
124
|
+
* callers use their host-side walk.
|
|
124
125
|
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
*
|
|
126
|
+
* ripgrep and GNU grep apply every `.gitignore` in the tree, relative to the
|
|
127
|
+
* directory that holds it, and skip `node_modules` unless the search path
|
|
128
|
+
* is inside one. Callers still apply their own hidden/glob filtering.
|
|
128
129
|
*/
|
|
129
130
|
grep(options: FilesystemGrepOptions): Promise<FilesystemGrepResult[]>;
|
|
130
|
-
private
|
|
131
|
-
private
|
|
131
|
+
private toolsCheck;
|
|
132
|
+
private searchTools;
|
|
132
133
|
private grepWithRipgrep;
|
|
133
134
|
private parseRipgrepJson;
|
|
134
135
|
/**
|
|
@@ -138,6 +139,27 @@ export declare class SandboxFilesystem implements WorkspaceFilesystem {
|
|
|
138
139
|
* POSIX bracket classes, GNU word anchors) must fall back to the host walk.
|
|
139
140
|
*/
|
|
140
141
|
private static readonly ERE_UNSUPPORTED;
|
|
142
|
+
/**
|
|
143
|
+
* Escapes that `grep -P` (PCRE) and JS RegExp (without the `u` flag) both
|
|
144
|
+
* accept but read differently, e.g. `\A` is "start of subject" in PCRE and
|
|
145
|
+
* a literal `A` in JS, plus POSIX bracket classes. PCRE-only syntax that JS
|
|
146
|
+
* rejects (inline flags, possessive quantifiers, atomic groups) already
|
|
147
|
+
* fails the JS compile below.
|
|
148
|
+
*/
|
|
149
|
+
private static readonly PCRE_UNSUPPORTED;
|
|
150
|
+
/** Reject patterns grep can't run with the same meaning as JS; return the JS regex used for columns. */
|
|
151
|
+
private static grepRegex;
|
|
152
|
+
/**
|
|
153
|
+
* GNU grep without ripgrep. Inside a git checkout, `git grep` picks the
|
|
154
|
+
* files (tracked plus untracked, every `.gitignore` applied) and GNU grep
|
|
155
|
+
* prints them with context. Outside a checkout (e.g. a multi-repo root),
|
|
156
|
+
* each child repository is searched the same way and plain grep covers the
|
|
157
|
+
* remaining files, skipping `node_modules`. `--null` ends each file name
|
|
158
|
+
* with NUL, so match (`N:`) and context (`N-`) lines parse unambiguously.
|
|
159
|
+
* When grep and git support it, patterns run as PCRE (`-P`), so `\d`,
|
|
160
|
+
* `\w`, `\s`, `\b`, and lookarounds don't need the host walk.
|
|
161
|
+
*/
|
|
162
|
+
private grepWithGnuGrep;
|
|
141
163
|
private grepWithPosixGrep;
|
|
142
164
|
private applyTotalCap;
|
|
143
165
|
exists(path: string): Promise<boolean>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sandbox-filesystem.d.ts","sourceRoot":"","sources":["../../src/agents/sandbox-filesystem.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EACV,WAAW,EACX,WAAW,EACX,SAAS,EACT,QAAQ,EAER,qBAAqB,EACrB,oBAAoB,EACpB,cAAc,EACd,WAAW,EACX,cAAc,EACd,WAAW,EACX,aAAa,EACb,SAAS,EACT,WAAW,EACX,mBAAmB,EACnB,YAAY,EACb,MAAM,wBAAwB,CAAC;AAmBhC,iDAAiD;AACjD,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,oDAAoD;AACpD,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,cAAc,CACZ,OAAO,EAAE,MAAM,EACf,IAAI,CAAC,EAAE,MAAM,EAAE,EACf,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;KAAE,GACxD,OAAO,CAAC,oBAAoB,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,wBAAwB;IACvC,uCAAuC;IACvC,OAAO,EAAE,WAAW,CAAC;IACrB;;;;;;OAMG;IACH,OAAO,EAAE,MAAM,GAAG,CAAC,MAAM,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC;IACnD,4DAA4D;IAC5D,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;
|
|
1
|
+
{"version":3,"file":"sandbox-filesystem.d.ts","sourceRoot":"","sources":["../../src/agents/sandbox-filesystem.ts"],"names":[],"mappings":"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"}
|
|
@@ -25,10 +25,69 @@ const EXIT_EXISTS = 22;
|
|
|
25
25
|
const EXIT_NOT_DIRECTORY = 23;
|
|
26
26
|
/** Default per-command deadline so a hung sandbox can't block file tools forever. */
|
|
27
27
|
const COMMAND_TIMEOUT_MS = 3e4;
|
|
28
|
+
/**
|
|
29
|
+
* Explain why a native grep command failed so callers can tell a timeout or
|
|
30
|
+
* broken toolchain apart from a pattern the engine cannot express.
|
|
31
|
+
*/
|
|
32
|
+
function describeGrepFailure(result) {
|
|
33
|
+
if (result.exitCode === 124) return `timed out after ${COMMAND_TIMEOUT_MS / 1e3}s`;
|
|
34
|
+
const stderrLine = result.stderr.split("\n").map((line) => line.trim()).find(Boolean);
|
|
35
|
+
const detail = stderrLine ? `: ${stderrLine.length > 200 ? `${stderrLine.slice(0, 200)}…` : stderrLine}` : "";
|
|
36
|
+
return `exit code ${result.exitCode}${detail}`;
|
|
37
|
+
}
|
|
28
38
|
/** Single-quote a string for safe POSIX shell interpolation. */
|
|
29
39
|
function shellQuote(value) {
|
|
30
40
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
31
41
|
}
|
|
42
|
+
/** One command that reports which search tools the sandbox has, one name per line. */
|
|
43
|
+
const SEARCH_TOOLS_PROBE = "command -v rg >/dev/null 2>&1 && echo rg; grep --version 2>/dev/null | head -n 1 | grep -q 'GNU grep' && echo gnu-grep; printf 'a1\\n' | grep -qP '\\d(?=)' 2>/dev/null && echo grep-pcre; if command -v git >/dev/null 2>&1; then echo git; d=$(mktemp -d 2>/dev/null) && { (cd \"$d\" && git init -q && printf 'a1\\n' >f && git grep -q --untracked -P -e '\\d(?=)') >/dev/null 2>&1 && echo git-pcre; rm -rf \"$d\"; }; fi; true";
|
|
44
|
+
function isInsideNodeModules(path) {
|
|
45
|
+
return path.split("/").includes("node_modules");
|
|
46
|
+
}
|
|
47
|
+
function fileLines(files, filePath) {
|
|
48
|
+
let state = files.get(filePath);
|
|
49
|
+
if (!state) {
|
|
50
|
+
state = {
|
|
51
|
+
matches: [],
|
|
52
|
+
linesByNumber: /* @__PURE__ */ new Map()
|
|
53
|
+
};
|
|
54
|
+
files.set(filePath, state);
|
|
55
|
+
}
|
|
56
|
+
return state;
|
|
57
|
+
}
|
|
58
|
+
/** Turn per-file lines into results relative to `abs`, attaching before/after context. */
|
|
59
|
+
function toGrepResults(files, abs, contextLines) {
|
|
60
|
+
const results = [];
|
|
61
|
+
for (const [filePath, state] of files) {
|
|
62
|
+
if (state.matches.length === 0) continue;
|
|
63
|
+
const rel = posix.relative(abs, filePath) || posix.basename(filePath);
|
|
64
|
+
const matches = state.matches.map((match) => {
|
|
65
|
+
if (contextLines <= 0) return match;
|
|
66
|
+
const before = [];
|
|
67
|
+
for (let n = match.line - 1; n >= Math.max(1, match.line - contextLines); n--) {
|
|
68
|
+
const text = state.linesByNumber.get(n);
|
|
69
|
+
if (text === void 0) break;
|
|
70
|
+
before.unshift(text);
|
|
71
|
+
}
|
|
72
|
+
const after = [];
|
|
73
|
+
for (let n = match.line + 1; n <= match.line + contextLines; n++) {
|
|
74
|
+
const text = state.linesByNumber.get(n);
|
|
75
|
+
if (text === void 0) break;
|
|
76
|
+
after.push(text);
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
...match,
|
|
80
|
+
before,
|
|
81
|
+
after
|
|
82
|
+
};
|
|
83
|
+
});
|
|
84
|
+
results.push({
|
|
85
|
+
path: rel,
|
|
86
|
+
matches
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
return results;
|
|
90
|
+
}
|
|
32
91
|
function isFileContentString(content) {
|
|
33
92
|
return typeof content === "string";
|
|
34
93
|
}
|
|
@@ -319,8 +378,11 @@ var SandboxFilesystem = class SandboxFilesystem {
|
|
|
319
378
|
const abs = await this.resolveAsync(path);
|
|
320
379
|
await this.assertContainedRealpath(abs, path);
|
|
321
380
|
const maxDepth = options?.maxDepth !== void 0 && Number.isFinite(options.maxDepth) ? `-maxdepth ${Math.max(0, Math.floor(options.maxDepth))} ` : "";
|
|
322
|
-
const
|
|
323
|
-
const
|
|
381
|
+
const keepGitignore = options?.includeGitignoreFiles ? `! \\( -type f -name .gitignore \\) ` : "";
|
|
382
|
+
const hiddenPrune = options?.includeHidden ? "" : `\\( -name '.*' ${keepGitignore}\\) -prune -o `;
|
|
383
|
+
const skipNames = options?.skipDirectoryNames?.filter(Boolean) ?? [];
|
|
384
|
+
const skipPrune = skipNames.length ? `\\( -type d \\( ${skipNames.map((name) => `-name ${shellQuote(name)}`).join(" -o ")} \\) \\) -prune -o ` : "";
|
|
385
|
+
const script = `root=${shellQuote(abs)}\n[ -e "$root" ] || [ -L "$root" ] || exit ${EXIT_NOT_FOUND}\n[ -d "$root" ] || exit ${EXIT_NOT_DIRECTORY}\nfind "$root" -mindepth 1 ${maxDepth}${hiddenPrune}${skipPrune}-print 2>/dev/null | while IFS= read -r f; do if [ -L "$f" ]; then if [ -d "$f" ]; then t=D; else t=F; fi; printf '%s\\t%s\\t%s\\n' "$t" "$f" "$(readlink "$f")"; elif [ -d "$f" ]; then printf 'd\\t%s\\n' "$f"; else printf 'f\\t%s\\n' "$f"; fi; done`;
|
|
324
386
|
const result = await this.exec(script);
|
|
325
387
|
if (result.exitCode === EXIT_NOT_FOUND) throw new DirectoryNotFoundError(path);
|
|
326
388
|
if (result.exitCode === EXIT_NOT_DIRECTORY) throw new NotDirectoryError(path);
|
|
@@ -356,31 +418,53 @@ var SandboxFilesystem = class SandboxFilesystem {
|
|
|
356
418
|
return entries;
|
|
357
419
|
}
|
|
358
420
|
/**
|
|
359
|
-
* Content search executed inside the sandbox in one command
|
|
360
|
-
* ripgrep
|
|
361
|
-
* `grep -rnE`. Patterns the
|
|
362
|
-
* word boundaries, lookarounds,
|
|
363
|
-
* {@link UnsupportedGrepPatternError} so
|
|
421
|
+
* Content search executed inside the sandbox in one command, using the best
|
|
422
|
+
* engine the sandbox has: ripgrep, then GNU grep (with git choosing files
|
|
423
|
+
* inside repositories), then POSIX `grep -rnE`. Patterns the grep engines
|
|
424
|
+
* can't express (PCRE-style classes, word boundaries, lookarounds,
|
|
425
|
+
* non-greedy quantifiers) throw {@link UnsupportedGrepPatternError} so
|
|
426
|
+
* callers use their host-side walk.
|
|
364
427
|
*
|
|
365
|
-
*
|
|
366
|
-
*
|
|
367
|
-
*
|
|
428
|
+
* ripgrep and GNU grep apply every `.gitignore` in the tree, relative to the
|
|
429
|
+
* directory that holds it, and skip `node_modules` unless the search path
|
|
430
|
+
* is inside one. Callers still apply their own hidden/glob filtering.
|
|
368
431
|
*/
|
|
369
432
|
async grep(options) {
|
|
370
433
|
const abs = await this.resolveAsync(options.path);
|
|
371
434
|
await this.assertContainedRealpath(abs, options.path);
|
|
372
|
-
|
|
435
|
+
const tools = await this.searchTools();
|
|
436
|
+
if (tools.rg) return this.grepWithRipgrep(abs, options);
|
|
437
|
+
if (tools.gnuGrep) return this.grepWithGnuGrep(abs, options, tools);
|
|
373
438
|
return this.grepWithPosixGrep(abs, options);
|
|
374
439
|
}
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
this.
|
|
378
|
-
|
|
440
|
+
toolsCheck;
|
|
441
|
+
searchTools() {
|
|
442
|
+
const check = this.toolsCheck ??= this.exec(SEARCH_TOOLS_PROBE).then((result) => {
|
|
443
|
+
if (result.exitCode !== 0) throw new Error(`search tool probe exited with ${result.exitCode}`);
|
|
444
|
+
const found = new Set(result.stdout.split("\n").map((line) => line.trim()));
|
|
445
|
+
const git = found.has("git");
|
|
446
|
+
return {
|
|
447
|
+
rg: found.has("rg"),
|
|
448
|
+
gnuGrep: found.has("gnu-grep"),
|
|
449
|
+
git,
|
|
450
|
+
pcre: found.has("grep-pcre") && (!git || found.has("git-pcre"))
|
|
451
|
+
};
|
|
452
|
+
});
|
|
453
|
+
return check.catch(() => {
|
|
454
|
+
if (this.toolsCheck === check) this.toolsCheck = void 0;
|
|
455
|
+
return {
|
|
456
|
+
rg: false,
|
|
457
|
+
gnuGrep: false,
|
|
458
|
+
git: false,
|
|
459
|
+
pcre: false
|
|
460
|
+
};
|
|
461
|
+
});
|
|
379
462
|
}
|
|
380
463
|
async grepWithRipgrep(abs, options) {
|
|
381
464
|
const args = [
|
|
382
|
-
"rg --json --no-
|
|
465
|
+
"rg --json --hidden --no-require-git",
|
|
383
466
|
`-g ${shellQuote("!.git/**")}`,
|
|
467
|
+
isInsideNodeModules(abs) ? "" : `-g ${shellQuote("!**/node_modules/**")}`,
|
|
384
468
|
options.caseSensitive ? "" : "-i",
|
|
385
469
|
options.maxCountPerFile !== void 0 ? `-m ${Math.max(1, Math.floor(options.maxCountPerFile))}` : "",
|
|
386
470
|
options.contextLines ? `-C ${Math.max(0, Math.floor(options.contextLines))}` : "",
|
|
@@ -390,7 +474,7 @@ var SandboxFilesystem = class SandboxFilesystem {
|
|
|
390
474
|
const result = await this.exec(args);
|
|
391
475
|
if (result.exitCode === 1) return [];
|
|
392
476
|
const results = this.parseRipgrepJson(result.stdout, abs, options);
|
|
393
|
-
if (result.exitCode !== 0 && results.length === 0) throw new UnsupportedGrepPatternError(options.pattern);
|
|
477
|
+
if (result.exitCode !== 0 && results.length === 0) throw new UnsupportedGrepPatternError(options.pattern, describeGrepFailure(result));
|
|
394
478
|
return results;
|
|
395
479
|
}
|
|
396
480
|
parseRipgrepJson(stdout, abs, options) {
|
|
@@ -407,14 +491,7 @@ var SandboxFilesystem = class SandboxFilesystem {
|
|
|
407
491
|
const filePath = event.data?.path?.text;
|
|
408
492
|
const lineNumber = event.data?.line_number;
|
|
409
493
|
if (!filePath || !lineNumber) continue;
|
|
410
|
-
|
|
411
|
-
if (!state) {
|
|
412
|
-
state = {
|
|
413
|
-
matches: [],
|
|
414
|
-
linesByNumber: /* @__PURE__ */ new Map()
|
|
415
|
-
};
|
|
416
|
-
files.set(filePath, state);
|
|
417
|
-
}
|
|
494
|
+
const state = fileLines(files, filePath);
|
|
418
495
|
const text = (event.data?.lines?.text ?? "").replace(/\r?\n$/, "");
|
|
419
496
|
state.linesByNumber.set(lineNumber, text);
|
|
420
497
|
if (event.type === "match") {
|
|
@@ -423,42 +500,11 @@ var SandboxFilesystem = class SandboxFilesystem {
|
|
|
423
500
|
state.matches.push({
|
|
424
501
|
line: lineNumber,
|
|
425
502
|
column,
|
|
426
|
-
text
|
|
427
|
-
lineNumber
|
|
503
|
+
text
|
|
428
504
|
});
|
|
429
505
|
}
|
|
430
506
|
}
|
|
431
|
-
|
|
432
|
-
const results = [];
|
|
433
|
-
for (const [filePath, state] of files) {
|
|
434
|
-
if (state.matches.length === 0) continue;
|
|
435
|
-
const rel = posix.relative(abs, filePath) || posix.basename(filePath);
|
|
436
|
-
const matches = state.matches.map(({ lineNumber, ...match }) => {
|
|
437
|
-
if (contextLines <= 0) return match;
|
|
438
|
-
const before = [];
|
|
439
|
-
for (let n = lineNumber - 1; n >= Math.max(1, lineNumber - contextLines); n--) {
|
|
440
|
-
const t = state.linesByNumber.get(n);
|
|
441
|
-
if (t === void 0) break;
|
|
442
|
-
before.unshift(t);
|
|
443
|
-
}
|
|
444
|
-
const after = [];
|
|
445
|
-
for (let n = lineNumber + 1; n <= lineNumber + contextLines; n++) {
|
|
446
|
-
const t = state.linesByNumber.get(n);
|
|
447
|
-
if (t === void 0) break;
|
|
448
|
-
after.push(t);
|
|
449
|
-
}
|
|
450
|
-
return {
|
|
451
|
-
...match,
|
|
452
|
-
before,
|
|
453
|
-
after
|
|
454
|
-
};
|
|
455
|
-
});
|
|
456
|
-
results.push({
|
|
457
|
-
path: rel,
|
|
458
|
-
matches
|
|
459
|
-
});
|
|
460
|
-
}
|
|
461
|
-
return this.applyTotalCap(results, options.maxTotalMatches);
|
|
507
|
+
return this.applyTotalCap(toGrepResults(files, abs, options.contextLines ?? 0), options.maxTotalMatches);
|
|
462
508
|
}
|
|
463
509
|
/**
|
|
464
510
|
* Patterns whose meaning differs between POSIX ERE and JS RegExp. The grep
|
|
@@ -467,17 +513,113 @@ var SandboxFilesystem = class SandboxFilesystem {
|
|
|
467
513
|
* POSIX bracket classes, GNU word anchors) must fall back to the host walk.
|
|
468
514
|
*/
|
|
469
515
|
static ERE_UNSUPPORTED = /\\[dDwWsSbB<>]|\(\?|[*+?}]\?|\[:[a-z]+:\]/;
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
516
|
+
/**
|
|
517
|
+
* Escapes that `grep -P` (PCRE) and JS RegExp (without the `u` flag) both
|
|
518
|
+
* accept but read differently, e.g. `\A` is "start of subject" in PCRE and
|
|
519
|
+
* a literal `A` in JS, plus POSIX bracket classes. PCRE-only syntax that JS
|
|
520
|
+
* rejects (inline flags, possessive quantifiers, atomic groups) already
|
|
521
|
+
* fails the JS compile below.
|
|
522
|
+
*/
|
|
523
|
+
static PCRE_UNSUPPORTED = /\\[AzZGKQEhHvVRXNCpPe]|\[:[a-z]+:\]/;
|
|
524
|
+
/** Reject patterns grep can't run with the same meaning as JS; return the JS regex used for columns. */
|
|
525
|
+
static grepRegex(options, pcre = false) {
|
|
526
|
+
if (pcre ? SandboxFilesystem.PCRE_UNSUPPORTED.test(options.pattern) : SandboxFilesystem.ERE_UNSUPPORTED.test(options.pattern)) throw new UnsupportedGrepPatternError(options.pattern, pcre ? "grep -P reads this syntax differently from JavaScript" : "POSIX ERE cannot express this syntax");
|
|
473
527
|
try {
|
|
474
|
-
|
|
528
|
+
return new RegExp(options.pattern, options.caseSensitive ? "" : "i");
|
|
475
529
|
} catch {
|
|
476
|
-
throw new UnsupportedGrepPatternError(options.pattern);
|
|
530
|
+
throw new UnsupportedGrepPatternError(options.pattern, "invalid regular expression");
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
/**
|
|
534
|
+
* GNU grep without ripgrep. Inside a git checkout, `git grep` picks the
|
|
535
|
+
* files (tracked plus untracked, every `.gitignore` applied) and GNU grep
|
|
536
|
+
* prints them with context. Outside a checkout (e.g. a multi-repo root),
|
|
537
|
+
* each child repository is searched the same way and plain grep covers the
|
|
538
|
+
* remaining files, skipping `node_modules`. `--null` ends each file name
|
|
539
|
+
* with NUL, so match (`N:`) and context (`N-`) lines parse unambiguously.
|
|
540
|
+
* When grep and git support it, patterns run as PCRE (`-P`), so `\d`,
|
|
541
|
+
* `\w`, `\s`, `\b`, and lookarounds don't need the host walk.
|
|
542
|
+
*/
|
|
543
|
+
async grepWithGnuGrep(abs, options, tools) {
|
|
544
|
+
const hasGit = tools.git;
|
|
545
|
+
const mode = tools.pcre ? "-P" : "-E";
|
|
546
|
+
const jsRegex = SandboxFilesystem.grepRegex(options, tools.pcre);
|
|
547
|
+
const contextLines = Math.max(0, Math.floor(options.contextLines ?? 0));
|
|
548
|
+
const grepFlags = [
|
|
549
|
+
`-HnI${mode.slice(1)} --null`,
|
|
550
|
+
options.caseSensitive ? "" : "-i",
|
|
551
|
+
options.maxCountPerFile !== void 0 ? `-m ${Math.max(1, Math.floor(options.maxCountPerFile))}` : "",
|
|
552
|
+
contextLines > 0 ? `-C ${contextLines}` : ""
|
|
553
|
+
].filter(Boolean).join(" ");
|
|
554
|
+
const skipNodeModules = !isInsideNodeModules(abs);
|
|
555
|
+
const nodeModulesPathspec = skipNodeModules ? ` ${shellQuote(":(exclude,glob)**/node_modules/**")}` : "";
|
|
556
|
+
const pruneNames = skipNodeModules ? "-name .git -o -name node_modules" : "-name .git";
|
|
557
|
+
const script = [
|
|
558
|
+
`pat=${shellQuote(options.pattern)}`,
|
|
559
|
+
`root=${shellQuote(abs)}`,
|
|
560
|
+
`grep ${mode} -e "$pat" </dev/null >/dev/null 2>&1`,
|
|
561
|
+
"if [ $? -eq 2 ]; then echo \"grep: invalid regular expression\" >&2; exit 2; fi",
|
|
562
|
+
"tmp=$(mktemp -d) || exit 1",
|
|
563
|
+
`trap 'rm -rf "$tmp"' EXIT`,
|
|
564
|
+
`search_files() { xargs -0 -r grep ${grepFlags} -e "$pat" -- 2>/dev/null; }`,
|
|
565
|
+
"search_repo() {",
|
|
566
|
+
` git -C "$1" grep -l -z -I --untracked ${options.caseSensitive ? "" : "-i "}${mode} -e "$pat" -- .${nodeModulesPathspec} >"$tmp/files" 2>/dev/null`,
|
|
567
|
+
" [ $? -gt 1 ] && return 1",
|
|
568
|
+
` printf '\\0%s\\n' "$1"`,
|
|
569
|
+
" (cd \"$1\" && search_files) <\"$tmp/files\"",
|
|
570
|
+
"}",
|
|
571
|
+
...hasGit ? [
|
|
572
|
+
"if git -C \"$root\" rev-parse --is-inside-work-tree >/dev/null 2>&1 && ! git -C \"$root\" check-ignore -q . 2>/dev/null; then",
|
|
573
|
+
" search_repo \"$root\" && exit 0",
|
|
574
|
+
"fi",
|
|
575
|
+
`find "$root" -mindepth 1 -maxdepth 3 \\( ${skipNodeModules ? "-name node_modules -prune" : "-false"} \\) -o \\( -name .git -prune -print \\) >"$tmp/repos" 2>/dev/null`,
|
|
576
|
+
": >\"$tmp/done\"",
|
|
577
|
+
"while IFS= read -r g; do",
|
|
578
|
+
" d=${g%/.git}",
|
|
579
|
+
" search_repo \"$d\" && printf '%s\\n' \"$d\" >>\"$tmp/done\"",
|
|
580
|
+
"done <\"$tmp/repos\"",
|
|
581
|
+
"set --",
|
|
582
|
+
"while IFS= read -r d; do set -- \"$@\" -o -path \"$d\"; done <\"$tmp/done\""
|
|
583
|
+
] : ["set --"],
|
|
584
|
+
`printf '\\0%s\\n' "$root"`,
|
|
585
|
+
`find "$root" -mindepth 1 \\( ${pruneNames} "$@" \\) -prune -o -type f -print0 2>/dev/null | search_files`,
|
|
586
|
+
"exit 0"
|
|
587
|
+
].join("\n");
|
|
588
|
+
const result = await this.exec(script);
|
|
589
|
+
if (result.exitCode !== 0) throw new UnsupportedGrepPatternError(options.pattern, describeGrepFailure(result));
|
|
590
|
+
const files = /* @__PURE__ */ new Map();
|
|
591
|
+
let base = abs;
|
|
592
|
+
for (const line of result.stdout.split("\n")) {
|
|
593
|
+
if (!line || line === "--") continue;
|
|
594
|
+
if (line.startsWith("\0")) {
|
|
595
|
+
base = line.slice(1);
|
|
596
|
+
continue;
|
|
597
|
+
}
|
|
598
|
+
const nul = line.indexOf("\0");
|
|
599
|
+
if (nul <= 0) continue;
|
|
600
|
+
const parsed = /^(\d+)([:-])(.*)$/s.exec(line.slice(nul + 1));
|
|
601
|
+
if (!parsed) continue;
|
|
602
|
+
const lineNumber = Number(parsed[1]);
|
|
603
|
+
const text = parsed[3];
|
|
604
|
+
const state = fileLines(files, posix.resolve(base, line.slice(0, nul)));
|
|
605
|
+
state.linesByNumber.set(lineNumber, text);
|
|
606
|
+
if (parsed[2] !== ":") continue;
|
|
607
|
+
const column = jsRegex.exec(text)?.index;
|
|
608
|
+
if (column === void 0) throw new UnsupportedGrepPatternError(options.pattern, "POSIX ERE and JS RegExp disagree on this pattern");
|
|
609
|
+
state.matches.push({
|
|
610
|
+
line: lineNumber,
|
|
611
|
+
column,
|
|
612
|
+
text
|
|
613
|
+
});
|
|
477
614
|
}
|
|
478
|
-
|
|
615
|
+
return this.applyTotalCap(toGrepResults(files, abs, contextLines), options.maxTotalMatches);
|
|
616
|
+
}
|
|
617
|
+
async grepWithPosixGrep(abs, options) {
|
|
618
|
+
const jsRegex = SandboxFilesystem.grepRegex(options);
|
|
619
|
+
if (options.contextLines) throw new UnsupportedGrepPatternError(options.pattern, "context lines are not supported by POSIX grep");
|
|
479
620
|
const args = [
|
|
480
621
|
"grep -rnIE",
|
|
622
|
+
"--exclude-dir=.git",
|
|
481
623
|
options.caseSensitive ? "" : "-i",
|
|
482
624
|
options.maxCountPerFile !== void 0 ? `-m ${Math.max(1, Math.floor(options.maxCountPerFile))}` : "",
|
|
483
625
|
"--",
|
|
@@ -486,7 +628,7 @@ var SandboxFilesystem = class SandboxFilesystem {
|
|
|
486
628
|
].filter(Boolean).join(" ");
|
|
487
629
|
const result = await this.exec(args);
|
|
488
630
|
if (result.exitCode === 1) return [];
|
|
489
|
-
if (result.exitCode !== 0) throw new UnsupportedGrepPatternError(options.pattern);
|
|
631
|
+
if (result.exitCode !== 0 && !(result.exitCode === 2 && result.stdout.trim())) throw new UnsupportedGrepPatternError(options.pattern, describeGrepFailure(result));
|
|
490
632
|
const byFile = /* @__PURE__ */ new Map();
|
|
491
633
|
for (const line of result.stdout.split("\n")) {
|
|
492
634
|
if (!line) continue;
|
|
@@ -495,7 +637,7 @@ var SandboxFilesystem = class SandboxFilesystem {
|
|
|
495
637
|
const rel = posix.relative(abs, parsed[1]) || posix.basename(parsed[1]);
|
|
496
638
|
const text = parsed[3];
|
|
497
639
|
const column = jsRegex.exec(text)?.index;
|
|
498
|
-
if (column === void 0) throw new UnsupportedGrepPatternError(options.pattern);
|
|
640
|
+
if (column === void 0) throw new UnsupportedGrepPatternError(options.pattern, "POSIX ERE and JS RegExp disagree on this pattern");
|
|
499
641
|
let matches = byFile.get(rel);
|
|
500
642
|
if (!matches) {
|
|
501
643
|
matches = [];
|