@evalops/maestro 0.10.28 → 0.10.29

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/cli.js CHANGED
@@ -160235,6 +160235,15 @@ var init_ripgrep_utils = __esm2(() => {
160235
160235
  }), { minItems: 1 })
160236
160236
  ]));
160237
160237
  });
160238
+ function shellQuoteArg(value) {
160239
+ if (/^[A-Za-z0-9_/:=.,@%+-]+$/.test(value)) {
160240
+ return value;
160241
+ }
160242
+ return `'${value.replace(/'/g, "'\\''")}'`;
160243
+ }
160244
+ function formatRipgrepCommand(args) {
160245
+ return ["rg", ...args].map(shellQuoteArg).join(" ");
160246
+ }
160238
160247
  function mergeRanges(ranges) {
160239
160248
  const sorted = [...ranges].sort((a, b) => a.start - b.start);
160240
160249
  const merged = [];
@@ -160442,7 +160451,7 @@ var init_parallel_ripgrep = __esm2(() => {
160442
160451
  let truncatedByBytes = false;
160443
160452
  const ripgrepCalls = patterns.map(async (pattern) => {
160444
160453
  const args = [...baseArgs, "--", pattern, ...pathArgs];
160445
- commands.push(["rg", ...args].join(" "));
160454
+ commands.push(formatRipgrepCommand(args));
160446
160455
  const result2 = await runRipgrep(args, signal, commandCwd);
160447
160456
  truncatedByBytes ||= result2.truncated;
160448
160457
  return { pattern, result: result2 };
@@ -160452,7 +160461,7 @@ var init_parallel_ripgrep = __esm2(() => {
160452
160461
  results = await Promise.all(ripgrepCalls);
160453
160462
  } catch (error) {
160454
160463
  const reason = error instanceof Error ? error.message : `Unknown error: ${String(error)}`;
160455
- return respond.text(`ripgrep failed
160464
+ return respond.error(`ripgrep failed
160456
160465
 
160457
160466
  ${reason}`).detail({
160458
160467
  commands,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@evalops/contracts",
3
- "version": "0.10.28",
3
+ "version": "0.10.29",
4
4
  "description": "Shared Maestro contracts for frontend/backend integration",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@evalops/tui",
3
- "version": "0.10.28",
3
+ "version": "0.10.29",
4
4
  "description": "Terminal UI library with differential rendering for Maestro",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1 +1 @@
1
- {"version":3,"file":"parallel-ripgrep.d.ts","sourceRoot":"","sources":["../../src/tools/parallel-ripgrep.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AA4GH;;;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"}
1
+ {"version":3,"file":"parallel-ripgrep.d.ts","sourceRoot":"","sources":["../../src/tools/parallel-ripgrep.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAuHH;;;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"}
@@ -28,6 +28,15 @@ import { createTool, expandUserPath } from "./tool-dsl.js";
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
+ }
31
40
  const parallelRipgrepSchema = Type.Object({
32
41
  patterns: Type.Array(Type.String({ minLength: 1 }), {
33
42
  minItems: 1,
@@ -252,7 +261,7 @@ export const parallelRipgrepTool = createTool({
252
261
  let truncatedByBytes = false;
253
262
  const ripgrepCalls = patterns.map(async (pattern) => {
254
263
  const args = [...baseArgs, "--", pattern, ...pathArgs];
255
- commands.push(["rg", ...args].join(" "));
264
+ commands.push(formatRipgrepCommand(args));
256
265
  const result = await runRipgrep(args, signal, commandCwd);
257
266
  truncatedByBytes ||= result.truncated;
258
267
  return { pattern, result };
@@ -265,7 +274,7 @@ export const parallelRipgrepTool = createTool({
265
274
  const reason = error instanceof Error
266
275
  ? error.message
267
276
  : `Unknown error: ${String(error)}`;
268
- return respond.text(`ripgrep failed\n\n${reason}`).detail({
277
+ return respond.error(`ripgrep failed\n\n${reason}`).detail({
269
278
  commands,
270
279
  cwd: commandCwd,
271
280
  matchCount: 0,
@@ -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\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([\"rg\", ...args].join(\" \"));\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.text(`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\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"]}
package/dist/version.json CHANGED
@@ -1,4 +1,4 @@
1
1
  {
2
- "version": "0.10.28",
3
- "notes": "Maestro by EvalOps - Deterministic coding agent with TUI/CLI and Web UI for AI-assisted development v0.10.28 is now available."
2
+ "version": "0.10.29",
3
+ "notes": "Maestro by EvalOps - Deterministic coding agent with TUI/CLI and Web UI for AI-assisted development v0.10.29 is now available."
4
4
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@evalops/maestro",
3
3
  "description": "Maestro by EvalOps - Deterministic coding agent with TUI/CLI and Web UI for AI-assisted development",
4
- "version": "0.10.28",
4
+ "version": "0.10.29",
5
5
  "private": false,
6
6
  "type": "module",
7
7
  "workspaces": [