@wrongstack/tools 0.310.1 → 0.313.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.
Files changed (135) hide show
  1. package/dist/_shell-pick.d.ts +5 -10
  2. package/dist/audit.js +10 -4055
  3. package/dist/bash.js +9 -2332
  4. package/dist/batch-tool-use.js +2 -187
  5. package/dist/browser/index.js +25 -1339
  6. package/dist/builtin.js +69 -33985
  7. package/dist/chunk-2CTB3UK5.js +197 -0
  8. package/dist/chunk-2ME7ZWDD.js +1272 -0
  9. package/dist/chunk-2TFQDEPU.js +113 -0
  10. package/dist/chunk-2ZCJNKFE.js +315 -0
  11. package/dist/chunk-3PVYQFRQ.js +472 -0
  12. package/dist/chunk-3QMQBO5Z.js +89 -0
  13. package/dist/chunk-42AKKX7O.js +385 -0
  14. package/dist/chunk-42SKEETB.js +113 -0
  15. package/dist/chunk-4BHUSMNL.js +104 -0
  16. package/dist/chunk-4I4LWFOO.js +431 -0
  17. package/dist/chunk-553IQUMO.js +478 -0
  18. package/dist/chunk-55KF77OK.js +1944 -0
  19. package/dist/chunk-6HLZK37X.js +359 -0
  20. package/dist/chunk-6RNIFLG4.js +305 -0
  21. package/dist/chunk-A6BRWIXN.js +317 -0
  22. package/dist/chunk-AHHDWNXC.js +200 -0
  23. package/dist/chunk-B2CIOKWP.js +899 -0
  24. package/dist/chunk-BTSFTGIL.js +7 -0
  25. package/dist/chunk-D33S4RQG.js +222 -0
  26. package/dist/chunk-DIJKHSUO.js +134 -0
  27. package/dist/chunk-DPL47QGS.js +3515 -0
  28. package/dist/chunk-EMRGN4KM.js +170 -0
  29. package/dist/chunk-FGOABE4Z.js +955 -0
  30. package/dist/chunk-FW65TP4G.js +520 -0
  31. package/dist/chunk-GOIZNNOA.js +221 -0
  32. package/dist/chunk-H5MJUAA6.js +295 -0
  33. package/dist/chunk-H5OHH6F4.js +223 -0
  34. package/dist/chunk-HC5RM4WY.js +199 -0
  35. package/dist/chunk-HEQFMLZ7.js +190 -0
  36. package/dist/chunk-HFXSNKCV.js +196 -0
  37. package/dist/chunk-HXSBQ2SE.js +1723 -0
  38. package/dist/chunk-ILESNGNM.js +163 -0
  39. package/dist/chunk-INF5CGAO.js +137 -0
  40. package/dist/chunk-IWDFZ6XR.js +337 -0
  41. package/dist/chunk-IXMNTNW5.js +238 -0
  42. package/dist/chunk-J4SRJKBW.js +428 -0
  43. package/dist/chunk-J5SKD6LN.js +235 -0
  44. package/dist/chunk-JRJJX3L5.js +424 -0
  45. package/dist/chunk-KXNDHMUB.js +366 -0
  46. package/dist/chunk-LIJQMYYX.js +59 -0
  47. package/dist/chunk-MAN26PZ5.js +260 -0
  48. package/dist/chunk-MKRQMLZA.js +474 -0
  49. package/dist/chunk-NBDZMMG2.js +169 -0
  50. package/dist/chunk-NHA6BEIH.js +101 -0
  51. package/dist/chunk-OA6YJIWL.js +4412 -0
  52. package/dist/chunk-OZC255IC.js +2830 -0
  53. package/dist/chunk-PUR6WU2B.js +154 -0
  54. package/dist/chunk-Q5JPPCZC.js +12 -0
  55. package/dist/chunk-QBV725YG.js +128 -0
  56. package/dist/chunk-QHVW4AAM.js +892 -0
  57. package/dist/chunk-QNJ7AQ4B.js +1000 -0
  58. package/dist/chunk-RGISBZBD.js +231 -0
  59. package/dist/chunk-RJZQWEMS.js +84 -0
  60. package/dist/chunk-RP2ZA47V.js +15 -0
  61. package/dist/chunk-RXISBFR5.js +315 -0
  62. package/dist/chunk-S5CCLZL3.js +99 -0
  63. package/dist/chunk-TVTCSBJF.js +122 -0
  64. package/dist/chunk-U4D5S3VQ.js +21 -0
  65. package/dist/chunk-U4VAATKP.js +193 -0
  66. package/dist/chunk-UKU2ZX4C.js +203 -0
  67. package/dist/chunk-UNSKG6DC.js +159 -0
  68. package/dist/chunk-URFKEIHM.js +1091 -0
  69. package/dist/chunk-UTV7YAW7.js +178 -0
  70. package/dist/chunk-V43EQ6VR.js +68 -0
  71. package/dist/chunk-VB3MJGCV.js +610 -0
  72. package/dist/chunk-WHIIIREL.js +223 -0
  73. package/dist/chunk-XMIFYKUT.js +1371 -0
  74. package/dist/chunk-YF2RSV34.js +54 -0
  75. package/dist/chunk-Z6DAKQ3U.js +1 -0
  76. package/dist/chunk-ZIGAZFWE.js +522 -0
  77. package/dist/circuit-breaker.js +3 -191
  78. package/dist/codebase-index/index.js +84 -13688
  79. package/dist/codebase-index/parser-worker-script.js +8 -3995
  80. package/dist/codebase-index/project-server.js +60 -8548
  81. package/dist/codebase-index/worker.js +20 -8416
  82. package/dist/design.js +2 -299
  83. package/dist/diff.js +4 -256
  84. package/dist/document.js +4 -222
  85. package/dist/e2e.js +5 -476
  86. package/dist/edit.js +14 -10200
  87. package/dist/exec.js +16 -3131
  88. package/dist/fetch.js +8 -398
  89. package/dist/format.js +10 -3750
  90. package/dist/generic-parser-VUXDIAOZ.js +13 -0
  91. package/dist/git.js +4 -380
  92. package/dist/glob.js +6 -280
  93. package/dist/go-parser-6CA77WZ4.js +469 -0
  94. package/dist/grep.js +7 -604
  95. package/dist/index.js +318 -35423
  96. package/dist/install.js +10 -4091
  97. package/dist/json-parser-7YMDJSBJ.js +213 -0
  98. package/dist/json.js +4 -665
  99. package/dist/kanban.js +3 -2096
  100. package/dist/languages/index.js +23 -4664
  101. package/dist/legacy-bridge-7UKZT46G.js +18 -0
  102. package/dist/lint.js +10 -3706
  103. package/dist/logs.js +4 -287
  104. package/dist/memory.js +6 -215
  105. package/dist/mode.js +3 -99
  106. package/dist/outdated.js +4 -5170
  107. package/dist/pack.js +65 -33933
  108. package/dist/parser-dispatch-VPOFDO2U.js +14 -0
  109. package/dist/patch.js +13 -9935
  110. package/dist/plan.js +5 -3286
  111. package/dist/process-registry.js +8 -651
  112. package/dist/ps-slash.js +12 -1439
  113. package/dist/py-parser-GPM5VYRG.js +16 -0
  114. package/dist/read.js +13 -9816
  115. package/dist/replace.js +15 -10014
  116. package/dist/rs-parser-WVQ4KYCX.js +81 -0
  117. package/dist/scaffold.js +4 -253
  118. package/dist/search.js +5 -585
  119. package/dist/session-kanban.js +30 -972
  120. package/dist/skill.js +2 -215
  121. package/dist/task.js +5 -3410
  122. package/dist/test.js +10 -3773
  123. package/dist/todo.js +4 -2891
  124. package/dist/tool-help.js +3 -123
  125. package/dist/tool-search.js +3 -79
  126. package/dist/tool-tier.js +68 -34020
  127. package/dist/tool-use.js +2 -93
  128. package/dist/tree-sitter-parser-YCILHGZD.js +17 -0
  129. package/dist/tree.js +4 -288
  130. package/dist/ts-parser-YH4ZMWMH.js +232 -0
  131. package/dist/typecheck.js +10 -3753
  132. package/dist/win32.js +6 -60
  133. package/dist/write.js +14 -9882
  134. package/dist/yaml-parser-GFAOKV53.js +157 -0
  135. package/package.json +5 -5
package/dist/grep.js CHANGED
@@ -1,608 +1,11 @@
1
- // src/grep.ts
2
- import { spawn } from "node:child_process";
3
- import * as fs2 from "node:fs/promises";
4
- import * as path3 from "node:path";
5
- import { ToolValidationError } from "@wrongstack/core/types";
6
1
  import {
7
- buildChildEnv,
8
- compileGlob as compileGlob2,
9
- DEFAULT_WALK_IGNORE_DIRS,
10
- expectDefined
11
- } from "@wrongstack/core/utils";
12
-
13
- // src/_concurrency.ts
14
- async function mapWithConcurrency(items, limit, fn) {
15
- if (items.length === 0) return [];
16
- const effectiveLimit = Math.max(1, Math.min(limit | 0, items.length));
17
- const results = new Array(items.length);
18
- let nextIndex = 0;
19
- const worker = async () => {
20
- while (true) {
21
- const i = nextIndex++;
22
- if (i >= items.length) return;
23
- results[i] = await fn(items[i]);
24
- }
25
- };
26
- await Promise.all(Array.from({ length: effectiveLimit }, worker));
27
- return results;
28
- }
29
-
30
- // src/_regex.ts
31
- import {
32
- capSubject,
33
- compileUserRegex,
34
- MAX_SUBJECT_LEN
35
- } from "@wrongstack/primitives";
36
-
37
- // src/_util.ts
38
- import * as fsp from "node:fs/promises";
39
- import * as path from "node:path";
40
- import * as Core from "@wrongstack/core/utils";
41
- function resolvePath(input, ctx) {
42
- return path.isAbsolute(input) ? path.normalize(input) : path.resolve(ctx.workingDir ?? ctx.cwd, input);
43
- }
44
- function allowedRoots(ctx) {
45
- return [path.resolve(ctx.projectRoot), path.resolve(Core.wstackGlobalRoot())];
46
- }
47
- function isInsideAny(target, roots) {
48
- return roots.some((root) => {
49
- const rel = path.relative(root, target);
50
- return rel === "" || !rel.startsWith("..") && !path.isAbsolute(rel);
51
- });
52
- }
53
- function ensureInsideRoot(absPath, ctx) {
54
- const target = path.resolve(absPath);
55
- if (ctx.allowOutsideProjectRoot) return target;
56
- if (isInsideAny(target, allowedRoots(ctx))) return target;
57
- throw new Error(`Path "${absPath}" is outside project root "${path.resolve(ctx.projectRoot)}"`);
58
- }
59
- function safeResolve(input, ctx) {
60
- return ensureInsideRoot(resolvePath(input, ctx), ctx);
61
- }
62
- async function resolveRealInsideRoot(absPath, ctx) {
63
- if (ctx.allowOutsideProjectRoot) return absPath;
64
- const realRoots = await Promise.all(
65
- allowedRoots(ctx).map((r) => fsp.realpath(r).catch(() => path.resolve(r)))
66
- );
67
- let probe = absPath;
68
- const pendingTail = [];
69
- for (; ; ) {
70
- let real;
71
- try {
72
- real = await fsp.realpath(probe);
73
- } catch (err) {
74
- if (err.code === "ENOENT") {
75
- const parent = path.dirname(probe);
76
- if (parent === probe) return absPath;
77
- pendingTail.unshift(path.basename(probe));
78
- probe = parent;
79
- continue;
80
- }
81
- throw err;
82
- }
83
- const candidate = pendingTail.length > 0 ? path.join(real, ...pendingTail) : real;
84
- if (isInsideAny(candidate, realRoots)) {
85
- return candidate;
86
- }
87
- throw new Error(
88
- `Path "${absPath}" resolves through a symlink outside project root "${realRoots[0]}"`
89
- );
90
- }
91
- }
92
- async function safeResolveReal(input, ctx) {
93
- const abs = safeResolve(input, ctx);
94
- return await resolveRealInsideRoot(abs, ctx);
95
- }
96
- function isBinaryBuffer(buf) {
97
- const len = Math.min(buf.length, 8192);
98
- for (let i = 0; i < len; i++) {
99
- if (buf[i] === 0) return true;
100
- }
101
- return false;
102
- }
103
-
104
- // src/codebase-index/gitignore.ts
105
- import * as fs from "node:fs/promises";
106
- import * as path2 from "node:path";
107
- import { compileGlob } from "@wrongstack/core/utils";
108
- function globBody(glob) {
109
- return compileGlob(glob).source.replace(/^\^/, "").replace(/\$$/, "");
110
- }
111
- function compileGitignore(lines) {
112
- const rules = [];
113
- for (const raw of lines) {
114
- let line = raw.replace(/\r$/, "");
115
- if (!line.trim() || line.trimStart().startsWith("#")) continue;
116
- line = line.trim();
117
- let negated = false;
118
- if (line.startsWith("!")) {
119
- negated = true;
120
- line = line.slice(1);
121
- }
122
- let dirOnly = false;
123
- if (line.endsWith("/")) {
124
- dirOnly = true;
125
- line = line.slice(0, -1);
126
- }
127
- if (!line) continue;
128
- const anchored = line.startsWith("/") || line.includes("/");
129
- if (line.startsWith("/")) line = line.slice(1);
130
- const body = globBody(line);
131
- const prefix = anchored ? "^" : "(?:^|.*/)";
132
- rules.push({
133
- eqOrUnder: new RegExp(`${prefix}${body}(?:/.*)?$`),
134
- under: new RegExp(`${prefix}${body}/.*$`),
135
- negated,
136
- dirOnly
137
- });
138
- }
139
- return (relPath, isDir) => {
140
- const p = relPath.replace(/\\/g, "/").replace(/^\/+/, "");
141
- let ignored = false;
142
- for (const r of rules) {
143
- const re = r.dirOnly && !isDir ? r.under : r.eqOrUnder;
144
- if (re.test(p)) ignored = !r.negated;
145
- }
146
- return ignored;
147
- };
148
- }
149
- async function loadGitignoreMatcher(projectRoot) {
150
- let lines = [];
151
- try {
152
- const raw = await fs.readFile(path2.join(projectRoot, ".gitignore"), "utf8");
153
- lines = raw.split("\n");
154
- } catch {
155
- }
156
- return compileGitignore(lines);
157
- }
158
-
159
- // src/grep.ts
160
- var DEFAULT_IGNORE = new Set(DEFAULT_WALK_IGNORE_DIRS);
161
- var NATIVE_SCAN_CONCURRENCY = 32;
162
- var NATIVE_READ_CHUNK_BYTES = 64 * 1024;
163
- var NATIVE_MAX_FILE_BYTES = 1e6;
164
- var RG_MAX_QUEUE_CHUNKS = 128;
165
- var RG_MAX_QUEUE_CHARS = 8 * 1024 * 1024;
166
- var grepTool = {
167
- name: "grep",
168
- category: "Search",
169
- description: "Search exact file contents using a regular expression. Use index-backed `codebase-search` first for symbol or concept discovery when it is live. Prefers ripgrep for speed and features when available.",
170
- usageHint: 'EXACT-TEXT AND REGEX SEARCH:\n\n- When `codebase-search` is live, use it first for symbols and concepts; use `grep` for exact text, regexes, unsupported content, and concrete usage sites.\n- `pattern` is a regular expression.\n- Use `output_mode: "content"` (default) to get matching lines with context.\n- Use `"files_with_matches"` when you only need the list of files.\n- Use `"count"` for quick statistics.\n- `glob` and `path` let you narrow the search scope significantly.\n- Always prefer this over `bash grep` when searching code.',
171
- selection: {
172
- doNotUseWhen: "you only need to locate files by name or path pattern.",
173
- useInstead: ["glob"]
174
- },
175
- permission: "auto",
176
- mutating: false,
177
- capabilities: ["fs.read"],
178
- icon: "search",
179
- maxOutputBytes: 131072,
180
- timeoutMs: 1e4,
181
- inputSchema: {
182
- type: "object",
183
- properties: {
184
- pattern: {
185
- type: "string",
186
- description: "Regular expression pattern to search for in file contents."
187
- },
188
- path: {
189
- type: "string",
190
- description: "Limit search to this directory or file (relative to project root)."
191
- },
192
- glob: {
193
- type: "string",
194
- description: 'Glob filter for which files to include (e.g. "**/*.ts", "src/**").'
195
- },
196
- output_mode: {
197
- type: "string",
198
- enum: ["content", "files_with_matches", "count"],
199
- description: "Return style: detailed matches, just file list, or count only."
200
- },
201
- context_lines: {
202
- type: "integer",
203
- description: "How many lines of surrounding context to include with each match."
204
- },
205
- case_insensitive: {
206
- type: "boolean",
207
- description: "Ignore case when matching."
208
- },
209
- limit: {
210
- type: "integer",
211
- description: "Maximum number of matches to return."
212
- }
213
- },
214
- required: ["pattern"]
215
- },
216
- async execute(input, ctx, opts) {
217
- let final;
218
- const executeStream = grepTool.executeStream;
219
- if (!executeStream) throw new Error("grepTool: stream execution unavailable");
220
- for await (const ev of executeStream(input, ctx, opts)) {
221
- if (ev.type === "final") final = ev.output;
222
- }
223
- if (!final) throw new Error("grep: stream ended without final event");
224
- return final;
225
- },
226
- async *executeStream(input, ctx, opts) {
227
- if (!input?.pattern) {
228
- throw new ToolValidationError({
229
- message: "grep: pattern is required",
230
- field: "pattern"
231
- });
232
- }
233
- const base = input.path ? await safeResolveReal(input.path, ctx) : ctx.cwd;
234
- const mode = input.output_mode ?? "content";
235
- const limit = Math.max(1, Math.min(input.limit ?? 200, 2e3));
236
- const validation = compileUserRegex(input.pattern, input.case_insensitive ? "i" : "");
237
- if (!validation.ok) {
238
- throw new ToolValidationError({
239
- message: `grep: ${validation.reason}`,
240
- field: "pattern"
241
- });
242
- }
243
- const rgAvailable = await detectRg();
244
- if (rgAvailable) {
245
- try {
246
- yield* runRgStream(input, base, mode, limit, opts.signal);
247
- return;
248
- } catch {
249
- }
250
- }
251
- yield { type: "log", text: "Falling back to native grep\u2026" };
252
- const out = await runNative(input, base, mode, limit, opts.signal);
253
- yield { type: "final", output: out };
254
- }
255
- };
256
- var rgAvailabilityCache;
257
- function __resetRgDetectionForTests() {
258
- rgAvailabilityCache = void 0;
259
- }
260
- function detectRg() {
261
- rgAvailabilityCache ??= new Promise((resolve2) => {
262
- try {
263
- const p = spawn("rg", ["--version"], {
264
- env: buildChildEnv(),
265
- stdio: "ignore",
266
- signal: AbortSignal.timeout(1e4),
267
- windowsHide: true
268
- });
269
- p.on("error", () => resolve2(false));
270
- p.on("close", (code) => resolve2(code === 0));
271
- } catch {
272
- resolve2(false);
273
- }
274
- });
275
- return rgAvailabilityCache;
276
- }
277
- async function* runRgStream(input, base, mode, limit, signal) {
278
- const args = ["--no-heading"];
279
- if (input.case_insensitive) args.push("-i");
280
- if (mode === "files_with_matches") args.push("-l");
281
- if (mode === "count") args.push("-c");
282
- if (mode === "content") {
283
- args.push("-n");
284
- if (input.context_lines) args.push("-C", String(input.context_lines));
285
- }
286
- for (const ignored of DEFAULT_IGNORE) {
287
- args.push("--glob", `!${ignored}/**`, "--glob", `!**/${ignored}/**`);
288
- }
289
- const gitignorePath = path3.join(base, ".gitignore");
290
- if (await fs2.access(gitignorePath).then(
291
- () => true,
292
- () => false
293
- )) {
294
- args.push("--ignore-file", gitignorePath);
295
- }
296
- if (input.glob) args.push("--glob", input.glob);
297
- args.push("--", input.pattern, base);
298
- const matches = [];
299
- let buf = "";
300
- let totalLines = 0;
301
- let totalCount = 0;
302
- let batchSinceFlush = 0;
303
- const FLUSH_AT = 16;
304
- const MAX_BUF_BYTES = 1e6;
305
- let bufOverflow = false;
306
- const child = spawn("rg", args, {
307
- signal,
308
- env: buildChildEnv(),
309
- // rg diagnostics are not part of the tool result. Ignoring stderr avoids
310
- // an unread pipe filling up and pinning the child when rg reports many
311
- // filesystem errors.
312
- stdio: ["ignore", "pipe", "ignore"],
313
- windowsHide: true
314
- });
315
- const queue = [];
316
- let queuedChars = 0;
317
- let waiter;
318
- let paused = false;
319
- const wake = () => {
320
- if (waiter) {
321
- const w = waiter;
322
- waiter = void 0;
323
- w();
324
- }
325
- };
326
- const pauseIfFlooded = () => {
327
- if (paused || queue.length < RG_MAX_QUEUE_CHUNKS && queuedChars < RG_MAX_QUEUE_CHARS) return;
328
- paused = true;
329
- child.stdout?.pause();
330
- };
331
- const resumeIfDrained = () => {
332
- if (!paused || queue.length >= RG_MAX_QUEUE_CHUNKS || queuedChars >= RG_MAX_QUEUE_CHARS) return;
333
- paused = false;
334
- child.stdout?.resume();
335
- };
336
- const onStdoutData = (c) => {
337
- const data = c.toString();
338
- queue.push({ kind: "out", data });
339
- queuedChars += data.length;
340
- wake();
341
- pauseIfFlooded();
342
- };
343
- const onError = (e) => {
344
- queue.push({ kind: "error", data: e.message });
345
- wake();
346
- };
347
- const onClose = () => {
348
- queue.push({ kind: "close", data: "" });
349
- wake();
350
- };
351
- child.stdout?.on("data", onStdoutData);
352
- child.on("error", onError);
353
- child.on("close", onClose);
354
- let pendingBatch = [];
355
- let errored = false;
356
- let closed = false;
357
- try {
358
- for (; ; ) {
359
- while (queue.length === 0) {
360
- await new Promise((r) => {
361
- waiter = r;
362
- });
363
- }
364
- const c = expectDefined(queue.shift());
365
- queuedChars = Math.max(0, queuedChars - c.data.length);
366
- resumeIfDrained();
367
- if (c.kind === "error") {
368
- errored = true;
369
- continue;
370
- }
371
- if (c.kind === "close") {
372
- closed = true;
373
- break;
374
- }
375
- buf += c.data;
376
- if (buf.length > MAX_BUF_BYTES && !bufOverflow) {
377
- bufOverflow = true;
378
- buf = buf.slice(-MAX_BUF_BYTES);
379
- try {
380
- child.kill("SIGTERM");
381
- } catch {
382
- }
383
- }
384
- const idx = buf.lastIndexOf("\n");
385
- if (idx === -1) continue;
386
- const ready = buf.slice(0, idx);
387
- buf = buf.slice(idx + 1);
388
- for (const line of ready.split("\n")) {
389
- if (!line) continue;
390
- totalLines++;
391
- if (mode === "count") totalCount += parseRgCountLine(line);
392
- if (matches.length < limit) {
393
- matches.push(line);
394
- pendingBatch.push(line);
395
- batchSinceFlush++;
396
- }
397
- }
398
- if (batchSinceFlush >= FLUSH_AT) {
399
- yield {
400
- type: "partial_output",
401
- text: pendingBatch.join("\n"),
402
- data: { matches_so_far: matches.length }
403
- };
404
- pendingBatch = [];
405
- batchSinceFlush = 0;
406
- }
407
- }
408
- if (buf.trim()) {
409
- for (const line of buf.split("\n")) {
410
- if (!line) continue;
411
- totalLines++;
412
- if (mode === "count") totalCount += parseRgCountLine(line);
413
- if (matches.length < limit) {
414
- matches.push(line);
415
- pendingBatch.push(line);
416
- }
417
- }
418
- }
419
- if (pendingBatch.length > 0) {
420
- yield {
421
- type: "partial_output",
422
- text: pendingBatch.join("\n"),
423
- data: { matches_so_far: matches.length }
424
- };
425
- }
426
- if (errored) throw new Error("rg: spawn error");
427
- yield {
428
- type: "final",
429
- output: {
430
- matches,
431
- count: mode === "count" ? totalCount : totalLines,
432
- truncated: totalLines > limit || bufOverflow,
433
- used: "rg"
434
- }
435
- };
436
- } finally {
437
- child.stdout?.off("data", onStdoutData);
438
- child.off("error", onError);
439
- child.off("close", onClose);
440
- child.stdout?.destroy();
441
- queue.length = 0;
442
- queuedChars = 0;
443
- waiter = void 0;
444
- if (!closed && child.exitCode === null) {
445
- try {
446
- child.kill("SIGTERM");
447
- } catch {
448
- }
449
- }
450
- }
451
- }
452
- function parseRgCountLine(line) {
453
- const idx = line.lastIndexOf(":");
454
- if (idx === -1) return 0;
455
- const n = Number.parseInt(line.slice(idx + 1), 10);
456
- return Number.isFinite(n) ? n : 0;
457
- }
458
- async function runNative(input, base, mode, limit, signal) {
459
- const flags = input.case_insensitive ? "i" : "";
460
- const compiled = compileUserRegex(input.pattern, flags);
461
- if (!compiled.ok) {
462
- throw new ToolValidationError({
463
- message: `grep: ${compiled.reason}`,
464
- field: "pattern"
465
- });
466
- }
467
- const re = compiled.regex;
468
- const globRe = input.glob ? compileGlob2(input.glob) : null;
469
- const isGitIgnored = await loadGitignoreMatcher(base);
470
- const matches = [];
471
- const countOnlyFirstHit = mode === "count" && limit === 1;
472
- const maxBytes = mode === "content" ? NATIVE_MAX_FILE_BYTES : Math.min(NATIVE_MAX_FILE_BYTES, 256 * 1024);
473
- let total = 0;
474
- let stopped = false;
475
- const scanFile = async (full, name) => {
476
- if (stopped || signal.aborted) return;
477
- if (globRe && !globRe.test(name) && !globRe.test(full)) return;
478
- if (globRe) globRe.lastIndex = 0;
479
- try {
480
- const stat2 = await fs2.stat(full);
481
- if (!stat2.isFile() || stat2.size > maxBytes || stopped || signal.aborted) return;
482
- const file = await fs2.open(full, "r");
483
- try {
484
- let bytesReadTotal = 0;
485
- let lineNumber = 0;
486
- let fileHits = 0;
487
- let leftover = "";
488
- let binaryChecked = false;
489
- const buffer = Buffer.allocUnsafe(Math.min(NATIVE_READ_CHUNK_BYTES, maxBytes));
490
- while (!stopped && !signal.aborted && bytesReadTotal < maxBytes) {
491
- const remaining = maxBytes - bytesReadTotal;
492
- const { bytesRead } = await file.read(
493
- buffer,
494
- 0,
495
- Math.min(buffer.length, remaining),
496
- null
497
- );
498
- if (bytesRead === 0) break;
499
- const chunk = buffer.subarray(0, bytesRead);
500
- if (!binaryChecked) {
501
- binaryChecked = true;
502
- if (isBinaryBuffer(chunk)) return;
503
- }
504
- bytesReadTotal += bytesRead;
505
- const text = leftover + chunk.toString("utf8");
506
- const lines = text.split(/\r?\n/);
507
- leftover = lines.pop() ?? "";
508
- for (const rawLine of lines) {
509
- if (stopped || signal.aborted) break;
510
- lineNumber++;
511
- const ln = capSubject(rawLine);
512
- re.lastIndex = 0;
513
- if (!re.test(ln)) continue;
514
- fileHits++;
515
- total++;
516
- if (mode === "content") {
517
- if (matches.length < limit) matches.push(`${full}:${lineNumber}:${ln}`);
518
- } else if (mode === "files_with_matches") {
519
- if (fileHits === 1 && matches.length < limit) matches.push(full);
520
- break;
521
- } else if (fileHits === 1 && matches.length < limit) {
522
- matches.push(`${full}:${countOnlyFirstHit ? 1 : 0}`);
523
- }
524
- if (countOnlyFirstHit || mode !== "content" && matches.length >= limit) {
525
- stopped = true;
526
- break;
527
- }
528
- }
529
- if (mode === "files_with_matches" && fileHits > 0) break;
530
- }
531
- if (!stopped && !signal.aborted && leftover.length > 0) {
532
- lineNumber++;
533
- const ln = capSubject(leftover);
534
- re.lastIndex = 0;
535
- if (re.test(ln)) {
536
- fileHits++;
537
- total++;
538
- if (mode === "content") {
539
- if (matches.length < limit) matches.push(`${full}:${lineNumber}:${ln}`);
540
- } else if (mode === "files_with_matches") {
541
- if (matches.length < limit) matches.push(full);
542
- } else if (matches.length < limit) {
543
- matches.push(`${full}:${countOnlyFirstHit ? 1 : fileHits}`);
544
- }
545
- }
546
- }
547
- if (fileHits > 0) {
548
- if (mode === "count") {
549
- const idx = matches.findIndex((entry) => entry.startsWith(`${full}:`));
550
- if (idx !== -1) matches[idx] = `${full}:${fileHits}`;
551
- }
552
- if (mode === "files_with_matches" && matches.length >= limit) stopped = true;
553
- }
554
- if (mode === "content" && matches.length >= limit) stopped = true;
555
- if (mode === "count" && matches.length >= limit && (countOnlyFirstHit || mode !== "count"))
556
- stopped = true;
557
- } finally {
558
- await file.close();
559
- }
560
- } catch {
561
- }
562
- };
563
- const walk = async (dir, relPrefix) => {
564
- if (stopped || signal.aborted) return;
565
- let entries;
566
- try {
567
- entries = await fs2.readdir(dir, { withFileTypes: true });
568
- } catch {
569
- return;
570
- }
571
- const files = [];
572
- const subdirs = [];
573
- for (const e of entries) {
574
- if (stopped) return;
575
- if (DEFAULT_IGNORE.has(e.name)) continue;
576
- if (e.isSymbolicLink()) continue;
577
- const rel = relPrefix ? `${relPrefix}/${e.name}` : e.name;
578
- const full = path3.join(dir, e.name);
579
- if (e.isDirectory()) {
580
- if (isGitIgnored(rel, true)) continue;
581
- subdirs.push({ full, rel });
582
- } else if (e.isFile()) {
583
- if (isGitIgnored(rel, false)) continue;
584
- files.push({ full, name: e.name });
585
- }
586
- }
587
- await mapWithConcurrency(
588
- files,
589
- NATIVE_SCAN_CONCURRENCY,
590
- ({ full, name }) => scanFile(full, name)
591
- );
592
- await mapWithConcurrency(
593
- subdirs,
594
- Math.min(16, NATIVE_SCAN_CONCURRENCY),
595
- ({ full, rel }) => walk(full, rel)
596
- );
597
- };
598
- await walk(base, "");
599
- return {
600
- matches,
601
- count: total,
602
- truncated: stopped,
603
- used: "native"
604
- };
605
- }
2
+ __resetRgDetectionForTests,
3
+ grepTool
4
+ } from "./chunk-553IQUMO.js";
5
+ import "./chunk-Q5JPPCZC.js";
6
+ import "./chunk-U4D5S3VQ.js";
7
+ import "./chunk-LIJQMYYX.js";
8
+ import "./chunk-D33S4RQG.js";
606
9
  export {
607
10
  __resetRgDetectionForTests,
608
11
  grepTool