@evalops/maestro 0.10.30 → 0.10.31
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/agent/compaction/cut-points.d.ts +157 -0
- package/dist/agent/compaction/cut-points.d.ts.map +1 -0
- package/dist/agent/compaction/cut-points.js +341 -0
- package/dist/agent/compaction/cut-points.js.map +1 -0
- package/dist/agent/compaction.d.ts +4 -144
- package/dist/agent/compaction.d.ts.map +1 -1
- package/dist/agent/compaction.js +5 -340
- package/dist/agent/compaction.js.map +1 -1
- package/dist/cli.js +117 -113
- package/dist/node_modules/@evalops/contracts/package.json +1 -1
- package/dist/node_modules/@evalops/tui/package.json +1 -1
- package/dist/tools/parallel-ripgrep.d.ts.map +1 -1
- package/dist/tools/parallel-ripgrep.js +1 -10
- package/dist/tools/parallel-ripgrep.js.map +1 -1
- package/dist/tools/ripgrep-utils.d.ts +1 -0
- package/dist/tools/ripgrep-utils.d.ts.map +1 -1
- package/dist/tools/ripgrep-utils.js +9 -0
- package/dist/tools/ripgrep-utils.js.map +1 -1
- package/dist/tools/search.d.ts.map +1 -1
- package/dist/tools/search.js +4 -4
- package/dist/tools/search.js.map +1 -1
- package/dist/version.json +2 -2
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -94854,7 +94854,6 @@ var init_compaction_cleanup = __esm2(() => {
|
|
|
94854
94854
|
logger89 = createLogger("compaction-cleanup");
|
|
94855
94855
|
cleanupHandlers = /* @__PURE__ */ new Map();
|
|
94856
94856
|
});
|
|
94857
|
-
var SESSION_START_INITIAL_USER_METADATA_KIND = "session_start_initial_user";
|
|
94858
94857
|
function calculateContextTokens(usage4) {
|
|
94859
94858
|
return usage4.input + usage4.output + usage4.cacheRead + usage4.cacheWrite;
|
|
94860
94859
|
}
|
|
@@ -94867,6 +94866,107 @@ function getAssistantUsage(msg) {
|
|
|
94867
94866
|
}
|
|
94868
94867
|
return null;
|
|
94869
94868
|
}
|
|
94869
|
+
function getLastAssistantUsage(messages) {
|
|
94870
|
+
for (let i2 = messages.length - 1; i2 >= 0; i2--) {
|
|
94871
|
+
const usage4 = getAssistantUsage(messages[i2]);
|
|
94872
|
+
if (usage4)
|
|
94873
|
+
return usage4;
|
|
94874
|
+
}
|
|
94875
|
+
return null;
|
|
94876
|
+
}
|
|
94877
|
+
function findTurnBoundaries(messages, startIndex, endIndex) {
|
|
94878
|
+
const boundaries = [];
|
|
94879
|
+
for (let i2 = startIndex; i2 < endIndex; i2++) {
|
|
94880
|
+
if (messages[i2].role === "user") {
|
|
94881
|
+
boundaries.push(i2);
|
|
94882
|
+
}
|
|
94883
|
+
}
|
|
94884
|
+
return boundaries;
|
|
94885
|
+
}
|
|
94886
|
+
function findCutPoint(messages, startIndex, endIndex, keepRecentTokens) {
|
|
94887
|
+
const boundaries = findTurnBoundaries(messages, startIndex, endIndex);
|
|
94888
|
+
if (boundaries.length === 0) {
|
|
94889
|
+
return startIndex;
|
|
94890
|
+
}
|
|
94891
|
+
const assistantUsages = [];
|
|
94892
|
+
for (let i2 = endIndex - 1; i2 >= startIndex; i2--) {
|
|
94893
|
+
const usage4 = getAssistantUsage(messages[i2]);
|
|
94894
|
+
if (usage4) {
|
|
94895
|
+
assistantUsages.push({
|
|
94896
|
+
index: i2,
|
|
94897
|
+
tokens: calculateContextTokens(usage4)
|
|
94898
|
+
});
|
|
94899
|
+
}
|
|
94900
|
+
}
|
|
94901
|
+
if (assistantUsages.length === 0) {
|
|
94902
|
+
return boundaries[boundaries.length - 1];
|
|
94903
|
+
}
|
|
94904
|
+
const newestTokens = assistantUsages[0].tokens;
|
|
94905
|
+
let cutIndex = startIndex;
|
|
94906
|
+
for (let i2 = 1; i2 < assistantUsages.length; i2++) {
|
|
94907
|
+
const tokenDiff = newestTokens - assistantUsages[i2].tokens;
|
|
94908
|
+
if (tokenDiff >= keepRecentTokens) {
|
|
94909
|
+
const lastKeptAssistantIndex = assistantUsages[i2 - 1].index;
|
|
94910
|
+
for (let b = boundaries.length - 1; b >= 0; b--) {
|
|
94911
|
+
const boundary = boundaries[b];
|
|
94912
|
+
if (boundary !== void 0 && boundary <= lastKeptAssistantIndex) {
|
|
94913
|
+
cutIndex = boundary;
|
|
94914
|
+
break;
|
|
94915
|
+
}
|
|
94916
|
+
}
|
|
94917
|
+
break;
|
|
94918
|
+
}
|
|
94919
|
+
}
|
|
94920
|
+
return cutIndex;
|
|
94921
|
+
}
|
|
94922
|
+
function adjustBoundaryForToolResults(messages, boundary) {
|
|
94923
|
+
let adjusted = boundary;
|
|
94924
|
+
const seenToolCalls = /* @__PURE__ */ new Set();
|
|
94925
|
+
const missingToolCalls = /* @__PURE__ */ new Set();
|
|
94926
|
+
const processAssistantMessage = (message) => {
|
|
94927
|
+
if (message.role !== "assistant")
|
|
94928
|
+
return;
|
|
94929
|
+
const content = message.content;
|
|
94930
|
+
if (!content)
|
|
94931
|
+
return;
|
|
94932
|
+
for (const part of content) {
|
|
94933
|
+
if (part?.type === "toolCall") {
|
|
94934
|
+
seenToolCalls.add(part.id);
|
|
94935
|
+
if (missingToolCalls.has(part.id)) {
|
|
94936
|
+
missingToolCalls.delete(part.id);
|
|
94937
|
+
}
|
|
94938
|
+
}
|
|
94939
|
+
}
|
|
94940
|
+
};
|
|
94941
|
+
const processToolResultMessage = (message) => {
|
|
94942
|
+
if (message.role !== "toolResult")
|
|
94943
|
+
return;
|
|
94944
|
+
const toolCallId2 = message.toolCallId;
|
|
94945
|
+
if (!seenToolCalls.has(toolCallId2)) {
|
|
94946
|
+
missingToolCalls.add(toolCallId2);
|
|
94947
|
+
}
|
|
94948
|
+
};
|
|
94949
|
+
for (const message of messages.slice(adjusted)) {
|
|
94950
|
+
processAssistantMessage(message);
|
|
94951
|
+
processToolResultMessage(message);
|
|
94952
|
+
}
|
|
94953
|
+
while (missingToolCalls.size > 0 && adjusted > 0) {
|
|
94954
|
+
adjusted -= 1;
|
|
94955
|
+
const candidate = messages[adjusted];
|
|
94956
|
+
processAssistantMessage(candidate);
|
|
94957
|
+
processToolResultMessage(candidate);
|
|
94958
|
+
}
|
|
94959
|
+
return adjusted;
|
|
94960
|
+
}
|
|
94961
|
+
var DEFAULT_COMPACTION_SETTINGS;
|
|
94962
|
+
var init_cut_points = __esm2(() => {
|
|
94963
|
+
DEFAULT_COMPACTION_SETTINGS = {
|
|
94964
|
+
enabled: true,
|
|
94965
|
+
reserveTokens: 16384,
|
|
94966
|
+
keepRecentTokens: 2e4
|
|
94967
|
+
};
|
|
94968
|
+
});
|
|
94969
|
+
var SESSION_START_INITIAL_USER_METADATA_KIND = "session_start_initial_user";
|
|
94870
94970
|
function shouldSkipAssistantCompactionMessage(message) {
|
|
94871
94971
|
return message.role === "assistant" && (message.stopReason === "aborted" || message.stopReason === "error");
|
|
94872
94972
|
}
|
|
@@ -95563,98 +95663,6 @@ function truncateSummaryInputForOverflowRetry(messages, overflowErrorMessage) {
|
|
|
95563
95663
|
};
|
|
95564
95664
|
return preamble ? [preamble, markerMessage, ...truncatedBody] : [markerMessage, ...truncatedBody];
|
|
95565
95665
|
}
|
|
95566
|
-
function getLastAssistantUsage(messages) {
|
|
95567
|
-
for (let i2 = messages.length - 1; i2 >= 0; i2--) {
|
|
95568
|
-
const usage4 = getAssistantUsage(messages[i2]);
|
|
95569
|
-
if (usage4)
|
|
95570
|
-
return usage4;
|
|
95571
|
-
}
|
|
95572
|
-
return null;
|
|
95573
|
-
}
|
|
95574
|
-
function findTurnBoundaries(messages, startIndex, endIndex) {
|
|
95575
|
-
const boundaries = [];
|
|
95576
|
-
for (let i2 = startIndex; i2 < endIndex; i2++) {
|
|
95577
|
-
if (messages[i2].role === "user") {
|
|
95578
|
-
boundaries.push(i2);
|
|
95579
|
-
}
|
|
95580
|
-
}
|
|
95581
|
-
return boundaries;
|
|
95582
|
-
}
|
|
95583
|
-
function findCutPoint(messages, startIndex, endIndex, keepRecentTokens) {
|
|
95584
|
-
const boundaries = findTurnBoundaries(messages, startIndex, endIndex);
|
|
95585
|
-
if (boundaries.length === 0) {
|
|
95586
|
-
return startIndex;
|
|
95587
|
-
}
|
|
95588
|
-
const assistantUsages = [];
|
|
95589
|
-
for (let i2 = endIndex - 1; i2 >= startIndex; i2--) {
|
|
95590
|
-
const usage4 = getAssistantUsage(messages[i2]);
|
|
95591
|
-
if (usage4) {
|
|
95592
|
-
assistantUsages.push({
|
|
95593
|
-
index: i2,
|
|
95594
|
-
tokens: calculateContextTokens(usage4)
|
|
95595
|
-
});
|
|
95596
|
-
}
|
|
95597
|
-
}
|
|
95598
|
-
if (assistantUsages.length === 0) {
|
|
95599
|
-
return boundaries[boundaries.length - 1];
|
|
95600
|
-
}
|
|
95601
|
-
const newestTokens = assistantUsages[0].tokens;
|
|
95602
|
-
let cutIndex = startIndex;
|
|
95603
|
-
for (let i2 = 1; i2 < assistantUsages.length; i2++) {
|
|
95604
|
-
const tokenDiff = newestTokens - assistantUsages[i2].tokens;
|
|
95605
|
-
if (tokenDiff >= keepRecentTokens) {
|
|
95606
|
-
const lastKeptAssistantIndex = assistantUsages[i2 - 1].index;
|
|
95607
|
-
for (let b = boundaries.length - 1; b >= 0; b--) {
|
|
95608
|
-
const boundary = boundaries[b];
|
|
95609
|
-
if (boundary !== void 0 && boundary <= lastKeptAssistantIndex) {
|
|
95610
|
-
cutIndex = boundary;
|
|
95611
|
-
break;
|
|
95612
|
-
}
|
|
95613
|
-
}
|
|
95614
|
-
break;
|
|
95615
|
-
}
|
|
95616
|
-
}
|
|
95617
|
-
return cutIndex;
|
|
95618
|
-
}
|
|
95619
|
-
function adjustBoundaryForToolResults(messages, boundary) {
|
|
95620
|
-
let adjusted = boundary;
|
|
95621
|
-
const seenToolCalls = /* @__PURE__ */ new Set();
|
|
95622
|
-
const missingToolCalls = /* @__PURE__ */ new Set();
|
|
95623
|
-
const processAssistantMessage = (message) => {
|
|
95624
|
-
if (message.role !== "assistant")
|
|
95625
|
-
return;
|
|
95626
|
-
const content = message.content;
|
|
95627
|
-
if (!content)
|
|
95628
|
-
return;
|
|
95629
|
-
for (const part of content) {
|
|
95630
|
-
if (part?.type === "toolCall") {
|
|
95631
|
-
seenToolCalls.add(part.id);
|
|
95632
|
-
if (missingToolCalls.has(part.id)) {
|
|
95633
|
-
missingToolCalls.delete(part.id);
|
|
95634
|
-
}
|
|
95635
|
-
}
|
|
95636
|
-
}
|
|
95637
|
-
};
|
|
95638
|
-
const processToolResultMessage = (message) => {
|
|
95639
|
-
if (message.role !== "toolResult")
|
|
95640
|
-
return;
|
|
95641
|
-
const toolCallId2 = message.toolCallId;
|
|
95642
|
-
if (!seenToolCalls.has(toolCallId2)) {
|
|
95643
|
-
missingToolCalls.add(toolCallId2);
|
|
95644
|
-
}
|
|
95645
|
-
};
|
|
95646
|
-
for (const message of messages.slice(adjusted)) {
|
|
95647
|
-
processAssistantMessage(message);
|
|
95648
|
-
processToolResultMessage(message);
|
|
95649
|
-
}
|
|
95650
|
-
while (missingToolCalls.size > 0 && adjusted > 0) {
|
|
95651
|
-
adjusted -= 1;
|
|
95652
|
-
const candidate = messages[adjusted];
|
|
95653
|
-
processAssistantMessage(candidate);
|
|
95654
|
-
processToolResultMessage(candidate);
|
|
95655
|
-
}
|
|
95656
|
-
return adjusted;
|
|
95657
|
-
}
|
|
95658
95666
|
function buildSummarizationPrompt(customInstructions) {
|
|
95659
95667
|
if (customInstructions) {
|
|
95660
95668
|
return `${SUMMARIZATION_PROMPT}
|
|
@@ -96006,7 +96014,6 @@ ${previousSummary}`,
|
|
|
96006
96014
|
};
|
|
96007
96015
|
}
|
|
96008
96016
|
var logger90;
|
|
96009
|
-
var DEFAULT_COMPACTION_SETTINGS;
|
|
96010
96017
|
var COMPACTION_RESUME_PROMPT = "Use the above summary to resume the plan from where we left off.";
|
|
96011
96018
|
var MAX_COMPACTION_OVERFLOW_RETRIES = 3;
|
|
96012
96019
|
var PREVIOUS_SUMMARY_PREFIX = `Previous session summary:
|
|
@@ -96038,15 +96045,12 @@ var init_compaction = __esm2(() => {
|
|
|
96038
96045
|
init_path_validation();
|
|
96039
96046
|
init_compaction_cleanup();
|
|
96040
96047
|
init_compaction_hooks();
|
|
96048
|
+
init_cut_points();
|
|
96049
|
+
init_cut_points();
|
|
96041
96050
|
init_compaction_restoration();
|
|
96042
96051
|
init_context_overflow();
|
|
96043
96052
|
init_plan_mode();
|
|
96044
96053
|
logger90 = createLogger("agent:compaction");
|
|
96045
|
-
DEFAULT_COMPACTION_SETTINGS = {
|
|
96046
|
-
enabled: true,
|
|
96047
|
-
reserveTokens: 16384,
|
|
96048
|
-
keepRecentTokens: 2e4
|
|
96049
|
-
};
|
|
96050
96054
|
});
|
|
96051
96055
|
var exports_task_budget_access = {};
|
|
96052
96056
|
__export2(exports_task_budget_access, {
|
|
@@ -142455,8 +142459,8 @@ ${renderCard([
|
|
|
142455
142459
|
const summary2 = buildDiffSummary(diffValue);
|
|
142456
142460
|
sections.push(summary2);
|
|
142457
142461
|
const diffLines22 = highlightCodeLines(diffValue, "diff");
|
|
142458
|
-
const
|
|
142459
|
-
const renderedLines =
|
|
142462
|
+
const shouldCompact2 = diffStyle === "auto" && terminalWidth < 90;
|
|
142463
|
+
const renderedLines = shouldCompact2 ? clampAnsiLines(diffLines22.slice(0, 80).concat(diffLines22.length > 80 ? [`${theme.fg("dim", "... truncated ...")}`] : []), maxDiffWidth) : clampAnsiLines(diffLines22, maxDiffWidth);
|
|
142460
142464
|
sections.push(renderedLines.join(`
|
|
142461
142465
|
`));
|
|
142462
142466
|
} else if (typeof context2.args?.before === "string" && typeof context2.args?.after === "string") {
|
|
@@ -160148,6 +160152,15 @@ function toArray(value) {
|
|
|
160148
160152
|
}
|
|
160149
160153
|
return Array.isArray(value) ? value : [value];
|
|
160150
160154
|
}
|
|
160155
|
+
function shellQuoteArg(value) {
|
|
160156
|
+
if (/^[A-Za-z0-9_/:=.,@%+-]+$/.test(value)) {
|
|
160157
|
+
return value;
|
|
160158
|
+
}
|
|
160159
|
+
return `'${value.replace(/'/g, "'\\''")}'`;
|
|
160160
|
+
}
|
|
160161
|
+
function formatRipgrepCommand(args) {
|
|
160162
|
+
return ["rg", ...args].map(shellQuoteArg).join(" ");
|
|
160163
|
+
}
|
|
160151
160164
|
async function runRipgrep(args, signal, cwd) {
|
|
160152
160165
|
const child = spawn17("rg", args, {
|
|
160153
160166
|
cwd: cwd ?? process.cwd(),
|
|
@@ -160238,15 +160251,6 @@ var init_ripgrep_utils = __esm2(() => {
|
|
|
160238
160251
|
}), { minItems: 1 })
|
|
160239
160252
|
]));
|
|
160240
160253
|
});
|
|
160241
|
-
function shellQuoteArg(value) {
|
|
160242
|
-
if (/^[A-Za-z0-9_/:=.,@%+-]+$/.test(value)) {
|
|
160243
|
-
return value;
|
|
160244
|
-
}
|
|
160245
|
-
return `'${value.replace(/'/g, "'\\''")}'`;
|
|
160246
|
-
}
|
|
160247
|
-
function formatRipgrepCommand(args) {
|
|
160248
|
-
return ["rg", ...args].map(shellQuoteArg).join(" ");
|
|
160249
|
-
}
|
|
160250
160254
|
function mergeRanges(ranges) {
|
|
160251
160255
|
const sorted = [...ranges].sort((a, b) => a.start - b.start);
|
|
160252
160256
|
const merged = [];
|
|
@@ -160745,20 +160749,20 @@ Examples:
|
|
|
160745
160749
|
} else {
|
|
160746
160750
|
args.push(".");
|
|
160747
160751
|
}
|
|
160752
|
+
const command = formatRipgrepCommand(args);
|
|
160748
160753
|
let result2;
|
|
160749
160754
|
try {
|
|
160750
160755
|
result2 = await runRipgrep(args, signal, commandCwd);
|
|
160751
160756
|
} catch (error) {
|
|
160752
160757
|
const reason = error instanceof Error ? error.message : `Unknown error: ${String(error)}`;
|
|
160753
|
-
return respond.
|
|
160758
|
+
return respond.error(`ripgrep failed
|
|
160754
160759
|
|
|
160755
|
-
${reason}`).detail({ command
|
|
160760
|
+
${reason}`).detail({ command, cwd: commandCwd });
|
|
160756
160761
|
}
|
|
160757
160762
|
if (result2.exitCode === 2) {
|
|
160758
160763
|
const message = result2.stderr.trim() || result2.stdout.trim();
|
|
160759
160764
|
throw new Error(message.length > 0 ? message : "ripgrep exited with an error");
|
|
160760
160765
|
}
|
|
160761
|
-
const command = ["rg", ...args].join(" ");
|
|
160762
160766
|
if (result2.exitCode === 1 || result2.stdout.trim().length === 0) {
|
|
160763
160767
|
const detailFormat = outputMode === "files" ? "files" : outputMode === "count" ? "count" : format;
|
|
160764
160768
|
return respond.text("No matches found.").detail({ command, cwd: commandCwd, format: detailFormat });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parallel-ripgrep.d.ts","sourceRoot":"","sources":["../../src/tools/parallel-ripgrep.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;
|
|
1
|
+
{"version":3,"file":"parallel-ripgrep.d.ts","sourceRoot":"","sources":["../../src/tools/parallel-ripgrep.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AA6GH;;;GAGG;AACH,KAAK,WAAW,GAAG;IAClB,gCAAgC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,kCAAkC;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,4CAA4C;IAC5C,GAAG,EAAE,MAAM,CAAC;IACZ,sDAAsD;IACtD,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,kCAAkC;IAClC,OAAO,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF;;;GAGG;AACH,KAAK,sBAAsB,GAAG;IAC7B,8CAA8C;IAC9C,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,uCAAuC;IACvC,GAAG,EAAE,MAAM,CAAC;IACZ,6DAA6D;IAC7D,UAAU,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,UAAU,EAAE,MAAM,CAAC;IACnB,8CAA8C;IAC9C,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,iDAAiD;IACjD,SAAS,EAAE,OAAO,CAAC;CACnB,CAAC;AA+HF,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4N9B,CAAC"}
|
|
@@ -22,21 +22,12 @@
|
|
|
22
22
|
import { promises as fs } from "node:fs";
|
|
23
23
|
import { resolve as resolvePath } from "node:path";
|
|
24
24
|
import { Type } from "@sinclair/typebox";
|
|
25
|
-
import { globSchema, parseRipgrepJson, pathSchema, runRipgrep, toArray, } from "./ripgrep-utils.js";
|
|
25
|
+
import { formatRipgrepCommand, globSchema, parseRipgrepJson, pathSchema, runRipgrep, toArray, } from "./ripgrep-utils.js";
|
|
26
26
|
import { createTool, expandUserPath } from "./tool-dsl.js";
|
|
27
27
|
/** Maximum number of line ranges to include in detailed output */
|
|
28
28
|
const RANGE_DETAIL_LIMIT = 200;
|
|
29
29
|
/** Default max matches per pattern (prevents runaway searches) */
|
|
30
30
|
const DEFAULT_MAX_RESULTS = 500;
|
|
31
|
-
function shellQuoteArg(value) {
|
|
32
|
-
if (/^[A-Za-z0-9_/:=.,@%+-]+$/.test(value)) {
|
|
33
|
-
return value;
|
|
34
|
-
}
|
|
35
|
-
return `'${value.replace(/'/g, "'\\''")}'`;
|
|
36
|
-
}
|
|
37
|
-
function formatRipgrepCommand(args) {
|
|
38
|
-
return ["rg", ...args].map(shellQuoteArg).join(" ");
|
|
39
|
-
}
|
|
40
31
|
const parallelRipgrepSchema = Type.Object({
|
|
41
32
|
patterns: Type.Array(Type.String({ minLength: 1 }), {
|
|
42
33
|
minItems: 1,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parallel-ripgrep.js","sourceRoot":"","sources":["../../src/tools/parallel-ripgrep.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Parallel Ripgrep Tool\n *\n * This tool enables searching for multiple regex patterns simultaneously\n * across a codebase. Unlike running separate ripgrep searches, this tool:\n *\n * 1. Runs all pattern searches in parallel for performance\n * 2. Merges overlapping line ranges to avoid duplicate context\n * 3. Returns consolidated results with per-pattern attribution\n *\n * Use cases:\n * - Finding function definitions AND their usages\n * - Searching for multiple related patterns (e.g., import + export)\n * - Finding all occurrences of related symbols\n *\n * The merging algorithm:\n * 1. Each pattern search returns line matches with context\n * 2. Matches are grouped by file\n * 3. Overlapping/adjacent ranges within a file are merged\n * 4. Final output shows which patterns matched each range\n */\n\nimport { promises as fs } from \"node:fs\";\nimport { resolve as resolvePath } from \"node:path\";\nimport { Type } from \"@sinclair/typebox\";\nimport {\n\tglobSchema,\n\tparseRipgrepJson,\n\tpathSchema,\n\trunRipgrep,\n\ttoArray,\n} from \"./ripgrep-utils.js\";\nimport { createTool, expandUserPath } from \"./tool-dsl.js\";\n\n/** Maximum number of line ranges to include in detailed output */\nconst RANGE_DETAIL_LIMIT = 200;\n/** Default max matches per pattern (prevents runaway searches) */\nconst DEFAULT_MAX_RESULTS = 500;\n\nfunction shellQuoteArg(value: string): string {\n\tif (/^[A-Za-z0-9_/:=.,@%+-]+$/.test(value)) {\n\t\treturn value;\n\t}\n\treturn `'${value.replace(/'/g, \"'\\\\''\")}'`;\n}\n\nfunction formatRipgrepCommand(args: string[]): string {\n\treturn [\"rg\", ...args].map(shellQuoteArg).join(\" \");\n}\n\nconst parallelRipgrepSchema = Type.Object({\n\tpatterns: Type.Array(Type.String({ minLength: 1 }), {\n\t\tminItems: 1,\n\t\tmaxItems: 10,\n\t\tdescription:\n\t\t\t\"Regex patterns to search for in parallel (1-10). Results are merged when matches overlap.\",\n\t}),\n\tpaths: pathSchema,\n\tglob: globSchema,\n\tignoreCase: Type.Optional(\n\t\tType.Boolean({\n\t\t\tdescription: \"Case-insensitive search (-i) for all patterns\",\n\t\t\tdefault: false,\n\t\t}),\n\t),\n\tliteral: Type.Optional(\n\t\tType.Boolean({\n\t\t\tdescription:\n\t\t\t\t\"Treat patterns as literal strings, not regex (--fixed-strings)\",\n\t\t\tdefault: false,\n\t\t}),\n\t),\n\tword: Type.Optional(\n\t\tType.Boolean({\n\t\t\tdescription: \"Match whole words only (-w)\",\n\t\t\tdefault: false,\n\t\t}),\n\t),\n\tmultiline: Type.Optional(\n\t\tType.Boolean({\n\t\t\tdescription: \"Enable multiline matching (--multiline)\",\n\t\t\tdefault: false,\n\t\t}),\n\t),\n\tmaxResults: Type.Optional(\n\t\tType.Integer({\n\t\t\tdescription: \"Max matches per pattern (-m)\",\n\t\t\tminimum: 1,\n\t\t\tmaximum: 1000,\n\t\t}),\n\t),\n\tcontext: Type.Optional(\n\t\tType.Integer({\n\t\t\tdescription: \"Lines of context before and after each match (-C)\",\n\t\t\tminimum: 0,\n\t\t\tmaximum: 20,\n\t\t}),\n\t),\n\tbeforeContext: Type.Optional(\n\t\tType.Integer({\n\t\t\tdescription: \"Lines of context before each match (-B)\",\n\t\t\tminimum: 0,\n\t\t\tmaximum: 20,\n\t\t}),\n\t),\n\tafterContext: Type.Optional(\n\t\tType.Integer({\n\t\t\tdescription: \"Lines of context after each match (-A)\",\n\t\t\tminimum: 0,\n\t\t\tmaximum: 20,\n\t\t}),\n\t),\n\tcwd: Type.Optional(\n\t\tType.String({\n\t\t\tdescription: \"Working directory for ripgrep\",\n\t\t\tminLength: 1,\n\t\t}),\n\t),\n\tincludeHidden: Type.Optional(\n\t\tType.Boolean({\n\t\t\tdescription: \"Include hidden files (--hidden)\",\n\t\t\tdefault: false,\n\t\t}),\n\t),\n\tuseGitIgnore: Type.Optional(\n\t\tType.Boolean({\n\t\t\tdescription: \"Respect .gitignore (false to pass --no-ignore)\",\n\t\t\tdefault: true,\n\t\t}),\n\t),\n\theadLimit: Type.Optional(\n\t\tType.Integer({\n\t\t\tdescription: \"Max number of merged line ranges to return\",\n\t\t\tminimum: 1,\n\t\t\tmaximum: RANGE_DETAIL_LIMIT,\n\t\t}),\n\t),\n});\n\n/**\n * A single merged line range with its content.\n * Represents a contiguous block of lines that matched one or more patterns.\n */\ntype RangeDetail = {\n\t/** Relative path to the file */\n\tfile: string;\n\t/** First line number (1-based) */\n\tstart: number;\n\t/** Last line number (1-based, inclusive) */\n\tend: number;\n\t/** List of patterns that matched within this range */\n\tpatterns: string[];\n\t/** Actual content of the lines */\n\tcontent: string;\n};\n\n/**\n * Detailed output from the parallel ripgrep tool.\n * Includes both summary statistics and the full range details.\n */\ntype ParallelRipgrepDetails = {\n\t/** The ripgrep commands that were executed */\n\tcommands: string[];\n\t/** Working directory for the search */\n\tcwd: string;\n\t/** Total number of individual matches across all patterns */\n\tmatchCount: number;\n\t/** Number of merged line ranges in output */\n\trangeCount: number;\n\t/** The merged and deduplicated line ranges */\n\tranges: RangeDetail[];\n\t/** Whether output was truncated due to limits */\n\ttruncated: boolean;\n};\n\n/**\n * Merge overlapping or adjacent line ranges within a single file.\n *\n * This is the core deduplication logic. Given ranges like:\n * [1-5, 3-8, 10-12]\n * It produces:\n * [1-8, 10-12]\n *\n * Ranges are considered mergeable if they overlap or are exactly adjacent\n * (e.g., 1-5 and 6-10 merge to 1-10).\n *\n * Pattern sets are unioned when ranges merge.\n */\nfunction mergeRanges(\n\tranges: Array<{ start: number; end: number; patterns: Set<string> }>,\n): Array<{\n\tstart: number;\n\tend: number;\n\tpatterns: Set<string>;\n}> {\n\t// Sort by start line to enable single-pass merging\n\tconst sorted = [...ranges].sort((a, b) => a.start - b.start);\n\tconst merged: Array<{ start: number; end: number; patterns: Set<string> }> =\n\t\t[];\n\n\tfor (const range of sorted) {\n\t\tconst last = merged.at(-1);\n\t\t// Check if this range overlaps or is adjacent to the previous one\n\t\t// (start <= end + 1 allows for adjacent ranges to merge)\n\t\tif (last && range.start <= last.end + 1) {\n\t\t\t// Extend the previous range and merge patterns\n\t\t\tlast.end = Math.max(last.end, range.end);\n\t\t\tfor (const pattern of range.patterns) {\n\t\t\t\tlast.patterns.add(pattern);\n\t\t\t}\n\t\t} else {\n\t\t\t// Start a new merged range\n\t\t\tmerged.push({\n\t\t\t\tstart: range.start,\n\t\t\t\tend: range.end,\n\t\t\t\tpatterns: new Set(range.patterns),\n\t\t\t});\n\t\t}\n\t}\n\n\treturn merged;\n}\n\n/**\n * Read file contents for each merged range and build detailed output.\n *\n * This function:\n * 1. Sorts ranges by file then line number for consistent output\n * 2. Reads file contents (with caching to avoid re-reading)\n * 3. Extracts the actual line content for each range\n * 4. Applies the limit to avoid excessive output\n *\n * @param commandCwd - Working directory to resolve relative paths\n * @param ranges - The merged ranges to populate with content\n * @param limit - Maximum number of ranges to include\n */\nasync function buildRangeContent(\n\tcommandCwd: string,\n\tranges: Array<{\n\t\tfile: string;\n\t\tstart: number;\n\t\tend: number;\n\t\tpatterns: Set<string>;\n\t}>,\n\tlimit: number,\n): Promise<{ ranges: RangeDetail[]; truncated: boolean }> {\n\t// Sort for deterministic output: by file, then by line number\n\tconst mergedRanges = ranges.sort((a, b) => {\n\t\tif (a.file === b.file) {\n\t\t\treturn a.start - b.start;\n\t\t}\n\t\treturn a.file.localeCompare(b.file);\n\t});\n\n\tconst truncated = mergedRanges.length > limit;\n\tconst selected = mergedRanges.slice(0, limit);\n\n\t// Cache file contents to avoid re-reading the same file multiple times\n\tconst fileCache = new Map<string, string[]>();\n\tconst results: RangeDetail[] = [];\n\n\tfor (const range of selected) {\n\t\tconst absolutePath = resolvePath(commandCwd, range.file);\n\t\tlet lines: string[];\n\n\t\t// Check cache first\n\t\tif (fileCache.has(absolutePath)) {\n\t\t\tlines = fileCache.get(absolutePath) as string[];\n\t\t} else {\n\t\t\ttry {\n\t\t\t\tconst content = await fs.readFile(absolutePath, \"utf-8\");\n\t\t\t\tlines = content.split(/\\r?\\n/);\n\t\t\t\tfileCache.set(absolutePath, lines);\n\t\t\t} catch {\n\t\t\t\t// Skip files that can't be read (deleted, permissions, etc.)\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\t// Clamp range to actual file bounds\n\t\tconst start = Math.max(1, range.start);\n\t\tconst end = Math.min(range.end, lines.length);\n\t\tif (end < start) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Extract the content (lines array is 0-indexed, our ranges are 1-indexed)\n\t\tconst snippet = lines.slice(start - 1, end).join(\"\\n\");\n\t\tresults.push({\n\t\t\tfile: range.file,\n\t\t\tstart,\n\t\t\tend,\n\t\t\tpatterns: Array.from(range.patterns).sort(),\n\t\t\tcontent: snippet,\n\t\t});\n\t}\n\n\treturn { ranges: results, truncated };\n}\n\nexport const parallelRipgrepTool = createTool<\n\ttypeof parallelRipgrepSchema,\n\tParallelRipgrepDetails\n>({\n\tname: \"parallel_ripgrep\",\n\tlabel: \"parallel_ripgrep\",\n\tdescription:\n\t\t\"Search for multiple patterns simultaneously. Runs ripgrep queries in parallel, automatically merges overlapping line ranges, and returns consolidated content. Ideal for finding related code (e.g., function definitions AND usages) or multiple related patterns without duplicate context.\",\n\tschema: parallelRipgrepSchema,\n\tasync run(params, { signal, respond }) {\n\t\tconst {\n\t\t\tpatterns,\n\t\t\tpaths,\n\t\t\tglob,\n\t\t\tignoreCase,\n\t\t\tliteral,\n\t\t\tword,\n\t\t\tmultiline,\n\t\t\tmaxResults,\n\t\t\tcontext,\n\t\t\tbeforeContext,\n\t\t\tafterContext,\n\t\t\tcwd,\n\t\t\tincludeHidden,\n\t\t\tuseGitIgnore = true,\n\t\t\theadLimit,\n\t\t} = params;\n\n\t\tif (\n\t\t\tcontext !== undefined &&\n\t\t\t(beforeContext !== undefined || afterContext !== undefined)\n\t\t) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Use either context or before/after context options, not both.\",\n\t\t\t);\n\t\t}\n\n\t\tconst pathArgs = toArray(paths);\n\t\tconst globArgs = toArray(glob);\n\t\tconst commandCwd = cwd ? resolvePath(expandUserPath(cwd)) : process.cwd();\n\t\tconst before = beforeContext ?? context ?? 0;\n\t\tconst after = afterContext ?? context ?? 0;\n\n\t\tconst baseArgs: string[] = [\n\t\t\t\"--color=never\",\n\t\t\t\"--json\",\n\t\t\t\"-n\",\n\t\t\t\"--with-filename\",\n\t\t];\n\n\t\tif (ignoreCase) {\n\t\t\tbaseArgs.push(\"-i\");\n\t\t}\n\n\t\tif (literal) {\n\t\t\tbaseArgs.push(\"--fixed-strings\");\n\t\t}\n\n\t\tif (word) {\n\t\t\tbaseArgs.push(\"-w\");\n\t\t}\n\n\t\tif (multiline) {\n\t\t\tbaseArgs.push(\"--multiline\");\n\t\t}\n\n\t\tif (includeHidden) {\n\t\t\tbaseArgs.push(\"--hidden\");\n\t\t}\n\n\t\tif (!useGitIgnore) {\n\t\t\tbaseArgs.push(\"--no-ignore\");\n\t\t}\n\n\t\tconst effectiveMaxResults = maxResults ?? DEFAULT_MAX_RESULTS;\n\t\tbaseArgs.push(\"-m\", String(effectiveMaxResults));\n\n\t\tif (context !== undefined) {\n\t\t\tbaseArgs.push(`-C${context}`);\n\t\t}\n\n\t\tif (beforeContext !== undefined) {\n\t\t\tbaseArgs.push(`-B${beforeContext}`);\n\t\t}\n\n\t\tif (afterContext !== undefined) {\n\t\t\tbaseArgs.push(`-A${afterContext}`);\n\t\t}\n\n\t\tfor (const globPattern of globArgs) {\n\t\t\tbaseArgs.push(\"--glob\", globPattern);\n\t\t}\n\n\t\tif (pathArgs.length === 0) {\n\t\t\tpathArgs.push(\".\");\n\t\t}\n\n\t\tconst commands: string[] = [];\n\t\tlet truncatedByBytes = false;\n\t\tconst ripgrepCalls = patterns.map(async (pattern) => {\n\t\t\tconst args = [...baseArgs, \"--\", pattern, ...pathArgs];\n\t\t\tcommands.push(formatRipgrepCommand(args));\n\t\t\tconst result = await runRipgrep(args, signal, commandCwd);\n\t\t\ttruncatedByBytes ||= result.truncated;\n\t\t\treturn { pattern, result };\n\t\t});\n\n\t\tlet results: Array<{\n\t\t\tpattern: string;\n\t\t\tresult: Awaited<ReturnType<typeof runRipgrep>>;\n\t\t}>;\n\t\ttry {\n\t\t\tresults = await Promise.all(ripgrepCalls);\n\t\t} catch (error) {\n\t\t\tconst reason =\n\t\t\t\terror instanceof Error\n\t\t\t\t\t? error.message\n\t\t\t\t\t: `Unknown error: ${String(error)}`;\n\t\t\treturn respond.error(`ripgrep failed\\n\\n${reason}`).detail({\n\t\t\t\tcommands,\n\t\t\t\tcwd: commandCwd,\n\t\t\t\tmatchCount: 0,\n\t\t\t\trangeCount: 0,\n\t\t\t\tranges: [],\n\t\t\t\ttruncated: false,\n\t\t\t});\n\t\t}\n\n\t\tlet matchCount = 0;\n\t\tconst rangesByFile = new Map<\n\t\t\tstring,\n\t\t\tArray<{ start: number; end: number; patterns: Set<string> }>\n\t\t>();\n\n\t\tfor (const { pattern, result } of results) {\n\t\t\tif (result.exitCode === 2) {\n\t\t\t\tconst message = result.stderr.trim() || result.stdout.trim();\n\t\t\t\tthrow new Error(\n\t\t\t\t\tmessage.length > 0 ? message : \"ripgrep exited with an error\",\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (result.exitCode === 1 || result.stdout.trim().length === 0) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst matches = parseRipgrepJson(result.stdout);\n\t\t\tmatchCount += matches.length;\n\n\t\t\tfor (const match of matches) {\n\t\t\t\tconst start = Math.max(1, match.line - before);\n\t\t\t\tconst end = match.line + after;\n\t\t\t\tconst ranges = rangesByFile.get(match.file) ?? [];\n\t\t\t\tranges.push({ start, end, patterns: new Set([pattern]) });\n\t\t\t\trangesByFile.set(match.file, ranges);\n\t\t\t}\n\t\t}\n\n\t\tif (matchCount === 0) {\n\t\t\treturn respond.text(\"No matches found.\").detail({\n\t\t\t\tcommands,\n\t\t\t\tcwd: commandCwd,\n\t\t\t\tmatchCount,\n\t\t\t\trangeCount: 0,\n\t\t\t\tranges: [],\n\t\t\t\ttruncated: false,\n\t\t\t});\n\t\t}\n\n\t\tconst mergedRanges: Array<{\n\t\t\tfile: string;\n\t\t\tstart: number;\n\t\t\tend: number;\n\t\t\tpatterns: Set<string>;\n\t\t}> = [];\n\t\tfor (const [file, ranges] of rangesByFile.entries()) {\n\t\t\tfor (const range of mergeRanges(ranges)) {\n\t\t\t\tmergedRanges.push({\n\t\t\t\t\tfile,\n\t\t\t\t\tstart: range.start,\n\t\t\t\t\tend: range.end,\n\t\t\t\t\tpatterns: range.patterns,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tconst rangeLimit = headLimit ?? RANGE_DETAIL_LIMIT;\n\t\tconst { ranges, truncated } = await buildRangeContent(\n\t\t\tcommandCwd,\n\t\t\tmergedRanges,\n\t\t\trangeLimit,\n\t\t);\n\n\t\tconst fileCount = new Set(ranges.map((range) => range.file)).size;\n\t\tconst summaryLines = ranges\n\t\t\t.map((range) => {\n\t\t\t\tconst header = `${range.file}:${range.start}-${range.end} [${range.patterns.join(\", \")}]:`;\n\t\t\t\treturn `${header}\\n${range.content}`;\n\t\t\t})\n\t\t\t.join(\"\\n\\n\");\n\n\t\tconst truncatedNote = truncated\n\t\t\t? `\\n\\n... (showing ${ranges.length} of ${mergedRanges.length} ranges)`\n\t\t\t: truncatedByBytes\n\t\t\t\t? \"\\n\\n... (output truncated due to size limit)\"\n\t\t\t\t: \"\";\n\n\t\treturn respond\n\t\t\t.text(\n\t\t\t\t`Found ${matchCount} match(es) across ${fileCount} file(s) for ${patterns.length} pattern(s). Extracted ${mergedRanges.length} line range(s).\\n\\n${summaryLines}${truncatedNote}`,\n\t\t\t)\n\t\t\t.detail({\n\t\t\t\tcommands,\n\t\t\t\tcwd: commandCwd,\n\t\t\t\tmatchCount,\n\t\t\t\trangeCount: mergedRanges.length,\n\t\t\t\tranges,\n\t\t\t\ttruncated: truncated || truncatedByBytes,\n\t\t\t});\n\t},\n});\n"]}
|
|
1
|
+
{"version":3,"file":"parallel-ripgrep.js","sourceRoot":"","sources":["../../src/tools/parallel-ripgrep.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Parallel Ripgrep Tool\n *\n * This tool enables searching for multiple regex patterns simultaneously\n * across a codebase. Unlike running separate ripgrep searches, this tool:\n *\n * 1. Runs all pattern searches in parallel for performance\n * 2. Merges overlapping line ranges to avoid duplicate context\n * 3. Returns consolidated results with per-pattern attribution\n *\n * Use cases:\n * - Finding function definitions AND their usages\n * - Searching for multiple related patterns (e.g., import + export)\n * - Finding all occurrences of related symbols\n *\n * The merging algorithm:\n * 1. Each pattern search returns line matches with context\n * 2. Matches are grouped by file\n * 3. Overlapping/adjacent ranges within a file are merged\n * 4. Final output shows which patterns matched each range\n */\n\nimport { promises as fs } from \"node:fs\";\nimport { resolve as resolvePath } from \"node:path\";\nimport { Type } from \"@sinclair/typebox\";\nimport {\n\tformatRipgrepCommand,\n\tglobSchema,\n\tparseRipgrepJson,\n\tpathSchema,\n\trunRipgrep,\n\ttoArray,\n} from \"./ripgrep-utils.js\";\nimport { createTool, expandUserPath } from \"./tool-dsl.js\";\n\n/** Maximum number of line ranges to include in detailed output */\nconst RANGE_DETAIL_LIMIT = 200;\n/** Default max matches per pattern (prevents runaway searches) */\nconst DEFAULT_MAX_RESULTS = 500;\n\nconst parallelRipgrepSchema = Type.Object({\n\tpatterns: Type.Array(Type.String({ minLength: 1 }), {\n\t\tminItems: 1,\n\t\tmaxItems: 10,\n\t\tdescription:\n\t\t\t\"Regex patterns to search for in parallel (1-10). Results are merged when matches overlap.\",\n\t}),\n\tpaths: pathSchema,\n\tglob: globSchema,\n\tignoreCase: Type.Optional(\n\t\tType.Boolean({\n\t\t\tdescription: \"Case-insensitive search (-i) for all patterns\",\n\t\t\tdefault: false,\n\t\t}),\n\t),\n\tliteral: Type.Optional(\n\t\tType.Boolean({\n\t\t\tdescription:\n\t\t\t\t\"Treat patterns as literal strings, not regex (--fixed-strings)\",\n\t\t\tdefault: false,\n\t\t}),\n\t),\n\tword: Type.Optional(\n\t\tType.Boolean({\n\t\t\tdescription: \"Match whole words only (-w)\",\n\t\t\tdefault: false,\n\t\t}),\n\t),\n\tmultiline: Type.Optional(\n\t\tType.Boolean({\n\t\t\tdescription: \"Enable multiline matching (--multiline)\",\n\t\t\tdefault: false,\n\t\t}),\n\t),\n\tmaxResults: Type.Optional(\n\t\tType.Integer({\n\t\t\tdescription: \"Max matches per pattern (-m)\",\n\t\t\tminimum: 1,\n\t\t\tmaximum: 1000,\n\t\t}),\n\t),\n\tcontext: Type.Optional(\n\t\tType.Integer({\n\t\t\tdescription: \"Lines of context before and after each match (-C)\",\n\t\t\tminimum: 0,\n\t\t\tmaximum: 20,\n\t\t}),\n\t),\n\tbeforeContext: Type.Optional(\n\t\tType.Integer({\n\t\t\tdescription: \"Lines of context before each match (-B)\",\n\t\t\tminimum: 0,\n\t\t\tmaximum: 20,\n\t\t}),\n\t),\n\tafterContext: Type.Optional(\n\t\tType.Integer({\n\t\t\tdescription: \"Lines of context after each match (-A)\",\n\t\t\tminimum: 0,\n\t\t\tmaximum: 20,\n\t\t}),\n\t),\n\tcwd: Type.Optional(\n\t\tType.String({\n\t\t\tdescription: \"Working directory for ripgrep\",\n\t\t\tminLength: 1,\n\t\t}),\n\t),\n\tincludeHidden: Type.Optional(\n\t\tType.Boolean({\n\t\t\tdescription: \"Include hidden files (--hidden)\",\n\t\t\tdefault: false,\n\t\t}),\n\t),\n\tuseGitIgnore: Type.Optional(\n\t\tType.Boolean({\n\t\t\tdescription: \"Respect .gitignore (false to pass --no-ignore)\",\n\t\t\tdefault: true,\n\t\t}),\n\t),\n\theadLimit: Type.Optional(\n\t\tType.Integer({\n\t\t\tdescription: \"Max number of merged line ranges to return\",\n\t\t\tminimum: 1,\n\t\t\tmaximum: RANGE_DETAIL_LIMIT,\n\t\t}),\n\t),\n});\n\n/**\n * A single merged line range with its content.\n * Represents a contiguous block of lines that matched one or more patterns.\n */\ntype RangeDetail = {\n\t/** Relative path to the file */\n\tfile: string;\n\t/** First line number (1-based) */\n\tstart: number;\n\t/** Last line number (1-based, inclusive) */\n\tend: number;\n\t/** List of patterns that matched within this range */\n\tpatterns: string[];\n\t/** Actual content of the lines */\n\tcontent: string;\n};\n\n/**\n * Detailed output from the parallel ripgrep tool.\n * Includes both summary statistics and the full range details.\n */\ntype ParallelRipgrepDetails = {\n\t/** The ripgrep commands that were executed */\n\tcommands: string[];\n\t/** Working directory for the search */\n\tcwd: string;\n\t/** Total number of individual matches across all patterns */\n\tmatchCount: number;\n\t/** Number of merged line ranges in output */\n\trangeCount: number;\n\t/** The merged and deduplicated line ranges */\n\tranges: RangeDetail[];\n\t/** Whether output was truncated due to limits */\n\ttruncated: boolean;\n};\n\n/**\n * Merge overlapping or adjacent line ranges within a single file.\n *\n * This is the core deduplication logic. Given ranges like:\n * [1-5, 3-8, 10-12]\n * It produces:\n * [1-8, 10-12]\n *\n * Ranges are considered mergeable if they overlap or are exactly adjacent\n * (e.g., 1-5 and 6-10 merge to 1-10).\n *\n * Pattern sets are unioned when ranges merge.\n */\nfunction mergeRanges(\n\tranges: Array<{ start: number; end: number; patterns: Set<string> }>,\n): Array<{\n\tstart: number;\n\tend: number;\n\tpatterns: Set<string>;\n}> {\n\t// Sort by start line to enable single-pass merging\n\tconst sorted = [...ranges].sort((a, b) => a.start - b.start);\n\tconst merged: Array<{ start: number; end: number; patterns: Set<string> }> =\n\t\t[];\n\n\tfor (const range of sorted) {\n\t\tconst last = merged.at(-1);\n\t\t// Check if this range overlaps or is adjacent to the previous one\n\t\t// (start <= end + 1 allows for adjacent ranges to merge)\n\t\tif (last && range.start <= last.end + 1) {\n\t\t\t// Extend the previous range and merge patterns\n\t\t\tlast.end = Math.max(last.end, range.end);\n\t\t\tfor (const pattern of range.patterns) {\n\t\t\t\tlast.patterns.add(pattern);\n\t\t\t}\n\t\t} else {\n\t\t\t// Start a new merged range\n\t\t\tmerged.push({\n\t\t\t\tstart: range.start,\n\t\t\t\tend: range.end,\n\t\t\t\tpatterns: new Set(range.patterns),\n\t\t\t});\n\t\t}\n\t}\n\n\treturn merged;\n}\n\n/**\n * Read file contents for each merged range and build detailed output.\n *\n * This function:\n * 1. Sorts ranges by file then line number for consistent output\n * 2. Reads file contents (with caching to avoid re-reading)\n * 3. Extracts the actual line content for each range\n * 4. Applies the limit to avoid excessive output\n *\n * @param commandCwd - Working directory to resolve relative paths\n * @param ranges - The merged ranges to populate with content\n * @param limit - Maximum number of ranges to include\n */\nasync function buildRangeContent(\n\tcommandCwd: string,\n\tranges: Array<{\n\t\tfile: string;\n\t\tstart: number;\n\t\tend: number;\n\t\tpatterns: Set<string>;\n\t}>,\n\tlimit: number,\n): Promise<{ ranges: RangeDetail[]; truncated: boolean }> {\n\t// Sort for deterministic output: by file, then by line number\n\tconst mergedRanges = ranges.sort((a, b) => {\n\t\tif (a.file === b.file) {\n\t\t\treturn a.start - b.start;\n\t\t}\n\t\treturn a.file.localeCompare(b.file);\n\t});\n\n\tconst truncated = mergedRanges.length > limit;\n\tconst selected = mergedRanges.slice(0, limit);\n\n\t// Cache file contents to avoid re-reading the same file multiple times\n\tconst fileCache = new Map<string, string[]>();\n\tconst results: RangeDetail[] = [];\n\n\tfor (const range of selected) {\n\t\tconst absolutePath = resolvePath(commandCwd, range.file);\n\t\tlet lines: string[];\n\n\t\t// Check cache first\n\t\tif (fileCache.has(absolutePath)) {\n\t\t\tlines = fileCache.get(absolutePath) as string[];\n\t\t} else {\n\t\t\ttry {\n\t\t\t\tconst content = await fs.readFile(absolutePath, \"utf-8\");\n\t\t\t\tlines = content.split(/\\r?\\n/);\n\t\t\t\tfileCache.set(absolutePath, lines);\n\t\t\t} catch {\n\t\t\t\t// Skip files that can't be read (deleted, permissions, etc.)\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\t// Clamp range to actual file bounds\n\t\tconst start = Math.max(1, range.start);\n\t\tconst end = Math.min(range.end, lines.length);\n\t\tif (end < start) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Extract the content (lines array is 0-indexed, our ranges are 1-indexed)\n\t\tconst snippet = lines.slice(start - 1, end).join(\"\\n\");\n\t\tresults.push({\n\t\t\tfile: range.file,\n\t\t\tstart,\n\t\t\tend,\n\t\t\tpatterns: Array.from(range.patterns).sort(),\n\t\t\tcontent: snippet,\n\t\t});\n\t}\n\n\treturn { ranges: results, truncated };\n}\n\nexport const parallelRipgrepTool = createTool<\n\ttypeof parallelRipgrepSchema,\n\tParallelRipgrepDetails\n>({\n\tname: \"parallel_ripgrep\",\n\tlabel: \"parallel_ripgrep\",\n\tdescription:\n\t\t\"Search for multiple patterns simultaneously. Runs ripgrep queries in parallel, automatically merges overlapping line ranges, and returns consolidated content. Ideal for finding related code (e.g., function definitions AND usages) or multiple related patterns without duplicate context.\",\n\tschema: parallelRipgrepSchema,\n\tasync run(params, { signal, respond }) {\n\t\tconst {\n\t\t\tpatterns,\n\t\t\tpaths,\n\t\t\tglob,\n\t\t\tignoreCase,\n\t\t\tliteral,\n\t\t\tword,\n\t\t\tmultiline,\n\t\t\tmaxResults,\n\t\t\tcontext,\n\t\t\tbeforeContext,\n\t\t\tafterContext,\n\t\t\tcwd,\n\t\t\tincludeHidden,\n\t\t\tuseGitIgnore = true,\n\t\t\theadLimit,\n\t\t} = params;\n\n\t\tif (\n\t\t\tcontext !== undefined &&\n\t\t\t(beforeContext !== undefined || afterContext !== undefined)\n\t\t) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Use either context or before/after context options, not both.\",\n\t\t\t);\n\t\t}\n\n\t\tconst pathArgs = toArray(paths);\n\t\tconst globArgs = toArray(glob);\n\t\tconst commandCwd = cwd ? resolvePath(expandUserPath(cwd)) : process.cwd();\n\t\tconst before = beforeContext ?? context ?? 0;\n\t\tconst after = afterContext ?? context ?? 0;\n\n\t\tconst baseArgs: string[] = [\n\t\t\t\"--color=never\",\n\t\t\t\"--json\",\n\t\t\t\"-n\",\n\t\t\t\"--with-filename\",\n\t\t];\n\n\t\tif (ignoreCase) {\n\t\t\tbaseArgs.push(\"-i\");\n\t\t}\n\n\t\tif (literal) {\n\t\t\tbaseArgs.push(\"--fixed-strings\");\n\t\t}\n\n\t\tif (word) {\n\t\t\tbaseArgs.push(\"-w\");\n\t\t}\n\n\t\tif (multiline) {\n\t\t\tbaseArgs.push(\"--multiline\");\n\t\t}\n\n\t\tif (includeHidden) {\n\t\t\tbaseArgs.push(\"--hidden\");\n\t\t}\n\n\t\tif (!useGitIgnore) {\n\t\t\tbaseArgs.push(\"--no-ignore\");\n\t\t}\n\n\t\tconst effectiveMaxResults = maxResults ?? DEFAULT_MAX_RESULTS;\n\t\tbaseArgs.push(\"-m\", String(effectiveMaxResults));\n\n\t\tif (context !== undefined) {\n\t\t\tbaseArgs.push(`-C${context}`);\n\t\t}\n\n\t\tif (beforeContext !== undefined) {\n\t\t\tbaseArgs.push(`-B${beforeContext}`);\n\t\t}\n\n\t\tif (afterContext !== undefined) {\n\t\t\tbaseArgs.push(`-A${afterContext}`);\n\t\t}\n\n\t\tfor (const globPattern of globArgs) {\n\t\t\tbaseArgs.push(\"--glob\", globPattern);\n\t\t}\n\n\t\tif (pathArgs.length === 0) {\n\t\t\tpathArgs.push(\".\");\n\t\t}\n\n\t\tconst commands: string[] = [];\n\t\tlet truncatedByBytes = false;\n\t\tconst ripgrepCalls = patterns.map(async (pattern) => {\n\t\t\tconst args = [...baseArgs, \"--\", pattern, ...pathArgs];\n\t\t\tcommands.push(formatRipgrepCommand(args));\n\t\t\tconst result = await runRipgrep(args, signal, commandCwd);\n\t\t\ttruncatedByBytes ||= result.truncated;\n\t\t\treturn { pattern, result };\n\t\t});\n\n\t\tlet results: Array<{\n\t\t\tpattern: string;\n\t\t\tresult: Awaited<ReturnType<typeof runRipgrep>>;\n\t\t}>;\n\t\ttry {\n\t\t\tresults = await Promise.all(ripgrepCalls);\n\t\t} catch (error) {\n\t\t\tconst reason =\n\t\t\t\terror instanceof Error\n\t\t\t\t\t? error.message\n\t\t\t\t\t: `Unknown error: ${String(error)}`;\n\t\t\treturn respond.error(`ripgrep failed\\n\\n${reason}`).detail({\n\t\t\t\tcommands,\n\t\t\t\tcwd: commandCwd,\n\t\t\t\tmatchCount: 0,\n\t\t\t\trangeCount: 0,\n\t\t\t\tranges: [],\n\t\t\t\ttruncated: false,\n\t\t\t});\n\t\t}\n\n\t\tlet matchCount = 0;\n\t\tconst rangesByFile = new Map<\n\t\t\tstring,\n\t\t\tArray<{ start: number; end: number; patterns: Set<string> }>\n\t\t>();\n\n\t\tfor (const { pattern, result } of results) {\n\t\t\tif (result.exitCode === 2) {\n\t\t\t\tconst message = result.stderr.trim() || result.stdout.trim();\n\t\t\t\tthrow new Error(\n\t\t\t\t\tmessage.length > 0 ? message : \"ripgrep exited with an error\",\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (result.exitCode === 1 || result.stdout.trim().length === 0) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst matches = parseRipgrepJson(result.stdout);\n\t\t\tmatchCount += matches.length;\n\n\t\t\tfor (const match of matches) {\n\t\t\t\tconst start = Math.max(1, match.line - before);\n\t\t\t\tconst end = match.line + after;\n\t\t\t\tconst ranges = rangesByFile.get(match.file) ?? [];\n\t\t\t\tranges.push({ start, end, patterns: new Set([pattern]) });\n\t\t\t\trangesByFile.set(match.file, ranges);\n\t\t\t}\n\t\t}\n\n\t\tif (matchCount === 0) {\n\t\t\treturn respond.text(\"No matches found.\").detail({\n\t\t\t\tcommands,\n\t\t\t\tcwd: commandCwd,\n\t\t\t\tmatchCount,\n\t\t\t\trangeCount: 0,\n\t\t\t\tranges: [],\n\t\t\t\ttruncated: false,\n\t\t\t});\n\t\t}\n\n\t\tconst mergedRanges: Array<{\n\t\t\tfile: string;\n\t\t\tstart: number;\n\t\t\tend: number;\n\t\t\tpatterns: Set<string>;\n\t\t}> = [];\n\t\tfor (const [file, ranges] of rangesByFile.entries()) {\n\t\t\tfor (const range of mergeRanges(ranges)) {\n\t\t\t\tmergedRanges.push({\n\t\t\t\t\tfile,\n\t\t\t\t\tstart: range.start,\n\t\t\t\t\tend: range.end,\n\t\t\t\t\tpatterns: range.patterns,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tconst rangeLimit = headLimit ?? RANGE_DETAIL_LIMIT;\n\t\tconst { ranges, truncated } = await buildRangeContent(\n\t\t\tcommandCwd,\n\t\t\tmergedRanges,\n\t\t\trangeLimit,\n\t\t);\n\n\t\tconst fileCount = new Set(ranges.map((range) => range.file)).size;\n\t\tconst summaryLines = ranges\n\t\t\t.map((range) => {\n\t\t\t\tconst header = `${range.file}:${range.start}-${range.end} [${range.patterns.join(\", \")}]:`;\n\t\t\t\treturn `${header}\\n${range.content}`;\n\t\t\t})\n\t\t\t.join(\"\\n\\n\");\n\n\t\tconst truncatedNote = truncated\n\t\t\t? `\\n\\n... (showing ${ranges.length} of ${mergedRanges.length} ranges)`\n\t\t\t: truncatedByBytes\n\t\t\t\t? \"\\n\\n... (output truncated due to size limit)\"\n\t\t\t\t: \"\";\n\n\t\treturn respond\n\t\t\t.text(\n\t\t\t\t`Found ${matchCount} match(es) across ${fileCount} file(s) for ${patterns.length} pattern(s). Extracted ${mergedRanges.length} line range(s).\\n\\n${summaryLines}${truncatedNote}`,\n\t\t\t)\n\t\t\t.detail({\n\t\t\t\tcommands,\n\t\t\t\tcwd: commandCwd,\n\t\t\t\tmatchCount,\n\t\t\t\trangeCount: mergedRanges.length,\n\t\t\t\tranges,\n\t\t\t\ttruncated: truncated || truncatedByBytes,\n\t\t\t});\n\t},\n});\n"]}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export declare const pathSchema: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TString, import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>]>>;
|
|
2
2
|
export declare const globSchema: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TString, import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>]>>;
|
|
3
3
|
export declare function toArray<T>(value: T | T[] | undefined): T[];
|
|
4
|
+
export declare function formatRipgrepCommand(args: string[]): string;
|
|
4
5
|
export declare function runRipgrep(args: string[], signal?: AbortSignal, cwd?: string): Promise<{
|
|
5
6
|
stdout: string;
|
|
6
7
|
stderr: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ripgrep-utils.d.ts","sourceRoot":"","sources":["../../src/tools/ripgrep-utils.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,UAAU,2LActB,CAAC;AAEF,eAAO,MAAM,UAAU,2LActB,CAAC;AAEF,wBAAgB,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,GAAG,SAAS,GAAG,CAAC,EAAE,CAK1D;
|
|
1
|
+
{"version":3,"file":"ripgrep-utils.d.ts","sourceRoot":"","sources":["../../src/tools/ripgrep-utils.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,UAAU,2LActB,CAAC;AAEF,eAAO,MAAM,UAAU,2LActB,CAAC;AAEF,wBAAgB,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,GAAG,SAAS,GAAG,CAAC,EAAE,CAK1D;AAWD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,CAE3D;AAED,wBAAsB,UAAU,CAC/B,IAAI,EAAE,MAAM,EAAE,EACd,MAAM,CAAC,EAAE,WAAW,EACpB,GAAG,CAAC,EAAE,MAAM,GACV,OAAO,CAAC;IACV,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;CACnB,CAAC,CAkDD;AAED,MAAM,MAAM,YAAY,GAAG;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,EAAE,CAmC/D"}
|
|
@@ -28,6 +28,15 @@ export function toArray(value) {
|
|
|
28
28
|
return Array.isArray(value) ? value : [value];
|
|
29
29
|
}
|
|
30
30
|
const MAX_RIPGREP_OUTPUT_BYTES = 2_000_000; // ~2MB safeguard
|
|
31
|
+
function shellQuoteArg(value) {
|
|
32
|
+
if (/^[A-Za-z0-9_/:=.,@%+-]+$/.test(value)) {
|
|
33
|
+
return value;
|
|
34
|
+
}
|
|
35
|
+
return `'${value.replace(/'/g, "'\\''")}'`;
|
|
36
|
+
}
|
|
37
|
+
export function formatRipgrepCommand(args) {
|
|
38
|
+
return ["rg", ...args].map(shellQuoteArg).join(" ");
|
|
39
|
+
}
|
|
31
40
|
export async function runRipgrep(args, signal, cwd) {
|
|
32
41
|
const child = spawn("rg", args, {
|
|
33
42
|
cwd: cwd ?? process.cwd(),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ripgrep-utils.js","sourceRoot":"","sources":["../../src/tools/ripgrep-utils.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn } from \"node:child_process\";\nimport { Type } from \"@sinclair/typebox\";\nimport { safeJsonParse } from \"../utils/json.js\";\n\nexport const pathSchema = Type.Optional(\n\tType.Union([\n\t\tType.String({\n\t\t\tdescription: \"Directory or file to search\",\n\t\t\tminLength: 1,\n\t\t}),\n\t\tType.Array(\n\t\t\tType.String({\n\t\t\t\tdescription: \"Multiple directories or files to search\",\n\t\t\t\tminLength: 1,\n\t\t\t}),\n\t\t\t{ minItems: 1 },\n\t\t),\n\t]),\n);\n\nexport const globSchema = Type.Optional(\n\tType.Union([\n\t\tType.String({\n\t\t\tdescription: \"Glob pattern passed to ripgrep\",\n\t\t\tminLength: 1,\n\t\t}),\n\t\tType.Array(\n\t\t\tType.String({\n\t\t\t\tdescription: \"Multiple glob patterns\",\n\t\t\t\tminLength: 1,\n\t\t\t}),\n\t\t\t{ minItems: 1 },\n\t\t),\n\t]),\n);\n\nexport function toArray<T>(value: T | T[] | undefined): T[] {\n\tif (value === undefined) {\n\t\treturn [];\n\t}\n\treturn Array.isArray(value) ? value : [value];\n}\n\nconst MAX_RIPGREP_OUTPUT_BYTES = 2_000_000; // ~2MB safeguard\n\nexport async function runRipgrep(\n\targs: string[],\n\tsignal?: AbortSignal,\n\tcwd?: string,\n): Promise<{\n\tstdout: string;\n\tstderr: string;\n\texitCode: number;\n\ttruncated: boolean;\n}> {\n\tconst child = spawn(\"rg\", args, {\n\t\tcwd: cwd ?? process.cwd(),\n\t\tstdio: [\"ignore\", \"pipe\", \"pipe\"],\n\t\tsignal,\n\t});\n\n\treturn await new Promise((resolve, reject) => {\n\t\tlet stdout = \"\";\n\t\tlet stderr = \"\";\n\t\tlet truncated = false;\n\n\t\tchild.stdout.setEncoding(\"utf-8\");\n\t\tchild.stdout.on(\"data\", (chunk) => {\n\t\t\tif (stdout.length + chunk.length > MAX_RIPGREP_OUTPUT_BYTES) {\n\t\t\t\ttruncated = true;\n\t\t\t\tstdout += chunk\n\t\t\t\t\t.slice(0, Math.max(0, MAX_RIPGREP_OUTPUT_BYTES - stdout.length))\n\t\t\t\t\t.toString();\n\t\t\t\tchild.kill(\"SIGTERM\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tstdout += chunk;\n\t\t});\n\n\t\tchild.stderr.setEncoding(\"utf-8\");\n\t\tchild.stderr.on(\"data\", (chunk) => {\n\t\t\tif (stderr.length + chunk.length > MAX_RIPGREP_OUTPUT_BYTES) {\n\t\t\t\ttruncated = true;\n\t\t\t\tstderr += chunk\n\t\t\t\t\t.slice(0, Math.max(0, MAX_RIPGREP_OUTPUT_BYTES - stderr.length))\n\t\t\t\t\t.toString();\n\t\t\t\tchild.kill(\"SIGTERM\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tstderr += chunk;\n\t\t});\n\n\t\tchild.once(\"error\", (error) => {\n\t\t\treject(\n\t\t\t\terror instanceof Error\n\t\t\t\t\t? new Error(`Failed to start ripgrep: ${error.message}`)\n\t\t\t\t\t: new Error(`Failed to start ripgrep: ${String(error)}`),\n\t\t\t);\n\t\t});\n\n\t\tchild.once(\"close\", (code) => {\n\t\t\tresolve({ stdout, stderr, exitCode: code ?? 0, truncated });\n\t\t});\n\t});\n}\n\nexport type RipgrepMatch = {\n\tfile: string;\n\tline: number;\n\tcolumn: number;\n\tmatch: string;\n\tlines: string;\n};\n\nexport function parseRipgrepJson(output: string): RipgrepMatch[] {\n\tconst matches: RipgrepMatch[] = [];\n\tfor (const line of output.split(/\\r?\\n/)) {\n\t\tif (!line.trim()) continue;\n\t\tconst parsed = safeJsonParse<unknown>(line, \"ripgrep output\");\n\t\tif (!parsed.success) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst event = parsed.data as {\n\t\t\ttype?: string;\n\t\t\tdata?: {\n\t\t\t\tpath?: { text?: string };\n\t\t\t\tline_number?: number;\n\t\t\t\tlines?: { text?: string };\n\t\t\t\tsubmatches?: Array<{\n\t\t\t\t\tstart?: number;\n\t\t\t\t\tmatch?: { text?: string };\n\t\t\t\t}>;\n\t\t\t};\n\t\t};\n\t\tif (event.type !== \"match\") {\n\t\t\tcontinue;\n\t\t}\n\t\tconst pathText = event.data?.path?.text ?? \"\";\n\t\tfor (const submatch of event.data?.submatches ?? []) {\n\t\t\tmatches.push({\n\t\t\t\tfile: pathText,\n\t\t\t\tline: event.data?.line_number ?? 0,\n\t\t\t\tcolumn: submatch.start ?? 0,\n\t\t\t\tmatch: submatch.match?.text ?? \"\",\n\t\t\t\tlines: event.data?.lines?.text ?? \"\",\n\t\t\t});\n\t\t}\n\t}\n\treturn matches;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ripgrep-utils.js","sourceRoot":"","sources":["../../src/tools/ripgrep-utils.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn } from \"node:child_process\";\nimport { Type } from \"@sinclair/typebox\";\nimport { safeJsonParse } from \"../utils/json.js\";\n\nexport const pathSchema = Type.Optional(\n\tType.Union([\n\t\tType.String({\n\t\t\tdescription: \"Directory or file to search\",\n\t\t\tminLength: 1,\n\t\t}),\n\t\tType.Array(\n\t\t\tType.String({\n\t\t\t\tdescription: \"Multiple directories or files to search\",\n\t\t\t\tminLength: 1,\n\t\t\t}),\n\t\t\t{ minItems: 1 },\n\t\t),\n\t]),\n);\n\nexport const globSchema = Type.Optional(\n\tType.Union([\n\t\tType.String({\n\t\t\tdescription: \"Glob pattern passed to ripgrep\",\n\t\t\tminLength: 1,\n\t\t}),\n\t\tType.Array(\n\t\t\tType.String({\n\t\t\t\tdescription: \"Multiple glob patterns\",\n\t\t\t\tminLength: 1,\n\t\t\t}),\n\t\t\t{ minItems: 1 },\n\t\t),\n\t]),\n);\n\nexport function toArray<T>(value: T | T[] | undefined): T[] {\n\tif (value === undefined) {\n\t\treturn [];\n\t}\n\treturn Array.isArray(value) ? value : [value];\n}\n\nconst MAX_RIPGREP_OUTPUT_BYTES = 2_000_000; // ~2MB safeguard\n\nfunction shellQuoteArg(value: string): string {\n\tif (/^[A-Za-z0-9_/:=.,@%+-]+$/.test(value)) {\n\t\treturn value;\n\t}\n\treturn `'${value.replace(/'/g, \"'\\\\''\")}'`;\n}\n\nexport function formatRipgrepCommand(args: string[]): string {\n\treturn [\"rg\", ...args].map(shellQuoteArg).join(\" \");\n}\n\nexport async function runRipgrep(\n\targs: string[],\n\tsignal?: AbortSignal,\n\tcwd?: string,\n): Promise<{\n\tstdout: string;\n\tstderr: string;\n\texitCode: number;\n\ttruncated: boolean;\n}> {\n\tconst child = spawn(\"rg\", args, {\n\t\tcwd: cwd ?? process.cwd(),\n\t\tstdio: [\"ignore\", \"pipe\", \"pipe\"],\n\t\tsignal,\n\t});\n\n\treturn await new Promise((resolve, reject) => {\n\t\tlet stdout = \"\";\n\t\tlet stderr = \"\";\n\t\tlet truncated = false;\n\n\t\tchild.stdout.setEncoding(\"utf-8\");\n\t\tchild.stdout.on(\"data\", (chunk) => {\n\t\t\tif (stdout.length + chunk.length > MAX_RIPGREP_OUTPUT_BYTES) {\n\t\t\t\ttruncated = true;\n\t\t\t\tstdout += chunk\n\t\t\t\t\t.slice(0, Math.max(0, MAX_RIPGREP_OUTPUT_BYTES - stdout.length))\n\t\t\t\t\t.toString();\n\t\t\t\tchild.kill(\"SIGTERM\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tstdout += chunk;\n\t\t});\n\n\t\tchild.stderr.setEncoding(\"utf-8\");\n\t\tchild.stderr.on(\"data\", (chunk) => {\n\t\t\tif (stderr.length + chunk.length > MAX_RIPGREP_OUTPUT_BYTES) {\n\t\t\t\ttruncated = true;\n\t\t\t\tstderr += chunk\n\t\t\t\t\t.slice(0, Math.max(0, MAX_RIPGREP_OUTPUT_BYTES - stderr.length))\n\t\t\t\t\t.toString();\n\t\t\t\tchild.kill(\"SIGTERM\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tstderr += chunk;\n\t\t});\n\n\t\tchild.once(\"error\", (error) => {\n\t\t\treject(\n\t\t\t\terror instanceof Error\n\t\t\t\t\t? new Error(`Failed to start ripgrep: ${error.message}`)\n\t\t\t\t\t: new Error(`Failed to start ripgrep: ${String(error)}`),\n\t\t\t);\n\t\t});\n\n\t\tchild.once(\"close\", (code) => {\n\t\t\tresolve({ stdout, stderr, exitCode: code ?? 0, truncated });\n\t\t});\n\t});\n}\n\nexport type RipgrepMatch = {\n\tfile: string;\n\tline: number;\n\tcolumn: number;\n\tmatch: string;\n\tlines: string;\n};\n\nexport function parseRipgrepJson(output: string): RipgrepMatch[] {\n\tconst matches: RipgrepMatch[] = [];\n\tfor (const line of output.split(/\\r?\\n/)) {\n\t\tif (!line.trim()) continue;\n\t\tconst parsed = safeJsonParse<unknown>(line, \"ripgrep output\");\n\t\tif (!parsed.success) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst event = parsed.data as {\n\t\t\ttype?: string;\n\t\t\tdata?: {\n\t\t\t\tpath?: { text?: string };\n\t\t\t\tline_number?: number;\n\t\t\t\tlines?: { text?: string };\n\t\t\t\tsubmatches?: Array<{\n\t\t\t\t\tstart?: number;\n\t\t\t\t\tmatch?: { text?: string };\n\t\t\t\t}>;\n\t\t\t};\n\t\t};\n\t\tif (event.type !== \"match\") {\n\t\t\tcontinue;\n\t\t}\n\t\tconst pathText = event.data?.path?.text ?? \"\";\n\t\tfor (const submatch of event.data?.submatches ?? []) {\n\t\t\tmatches.push({\n\t\t\t\tfile: pathText,\n\t\t\t\tline: event.data?.line_number ?? 0,\n\t\t\t\tcolumn: submatch.start ?? 0,\n\t\t\t\tmatch: submatch.match?.text ?? \"\",\n\t\t\t\tlines: event.data?.lines?.text ?? \"\",\n\t\t\t});\n\t\t}\n\t}\n\treturn matches;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AAIH,OAAO,EACN,KAAK,YAAY,
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AAIH,OAAO,EACN,KAAK,YAAY,EAOjB,MAAM,oBAAoB,CAAC;AAkI5B,KAAK,iBAAiB,GAAG;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;IAC7C,OAAO,CAAC,EAAE,YAAY,EAAE,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChD,SAAS,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqUrB,CAAC"}
|
package/dist/tools/search.js
CHANGED
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
*/
|
|
52
52
|
import { resolve as resolvePath } from "node:path";
|
|
53
53
|
import { Type } from "@sinclair/typebox";
|
|
54
|
-
import { globSchema, parseRipgrepJson, pathSchema, runRipgrep, toArray, } from "./ripgrep-utils.js";
|
|
54
|
+
import { formatRipgrepCommand, globSchema, parseRipgrepJson, pathSchema, runRipgrep, toArray, } from "./ripgrep-utils.js";
|
|
55
55
|
import { createTool, expandUserPath } from "./tool-dsl.js";
|
|
56
56
|
const searchSchema = Type.Object({
|
|
57
57
|
pattern: Type.String({
|
|
@@ -240,6 +240,7 @@ Examples:
|
|
|
240
240
|
else {
|
|
241
241
|
args.push(".");
|
|
242
242
|
}
|
|
243
|
+
const command = formatRipgrepCommand(args);
|
|
243
244
|
let result;
|
|
244
245
|
try {
|
|
245
246
|
result = await runRipgrep(args, signal, commandCwd);
|
|
@@ -249,14 +250,13 @@ Examples:
|
|
|
249
250
|
? error.message
|
|
250
251
|
: `Unknown error: ${String(error)}`;
|
|
251
252
|
return respond
|
|
252
|
-
.
|
|
253
|
-
.detail({ command
|
|
253
|
+
.error(`ripgrep failed\n\n${reason}`)
|
|
254
|
+
.detail({ command, cwd: commandCwd });
|
|
254
255
|
}
|
|
255
256
|
if (result.exitCode === 2) {
|
|
256
257
|
const message = result.stderr.trim() || result.stdout.trim();
|
|
257
258
|
throw new Error(message.length > 0 ? message : "ripgrep exited with an error");
|
|
258
259
|
}
|
|
259
|
-
const command = ["rg", ...args].join(" ");
|
|
260
260
|
if (result.exitCode === 1 || result.stdout.trim().length === 0) {
|
|
261
261
|
// Use correct format in detail based on mode
|
|
262
262
|
const detailFormat = outputMode === "files"
|