@evalops/maestro 0.10.41 → 0.10.43

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dist/cli/commands/operating-plane.d.ts.map +1 -1
  2. package/dist/cli/commands/operating-plane.js +3 -2
  3. package/dist/cli/commands/operating-plane.js.map +1 -1
  4. package/dist/cli/help.js +8 -6
  5. package/dist/cli/help.js.map +1 -1
  6. package/dist/cli.js +209 -97
  7. package/dist/codex/subagent-dispatch-table.d.ts +1 -1
  8. package/dist/codex/subagent-dispatch-table.js +1 -1
  9. package/dist/codex/subagent-dispatch-table.js.map +1 -1
  10. package/dist/node_modules/@evalops/contracts/package.json +1 -1
  11. package/dist/node_modules/@evalops/tui/package.json +1 -1
  12. package/dist/platform/a2a-completion-audit.d.ts +12 -6
  13. package/dist/platform/a2a-completion-audit.d.ts.map +1 -1
  14. package/dist/platform/a2a-completion-audit.js +28 -20
  15. package/dist/platform/a2a-completion-audit.js.map +1 -1
  16. package/dist/platform/a2a-maestro-peer.js +8 -7
  17. package/dist/platform/a2a-maestro-peer.js.map +1 -1
  18. package/dist/platform/a2a-telemetry-inspect.d.ts +2 -2
  19. package/dist/platform/a2a-telemetry-inspect.d.ts.map +1 -1
  20. package/dist/platform/a2a-telemetry-inspect.js +3 -3
  21. package/dist/platform/a2a-telemetry-inspect.js.map +1 -1
  22. package/dist/platform/operating-plane-client.d.ts +2 -2
  23. package/dist/platform/operating-plane-client.d.ts.map +1 -1
  24. package/dist/platform/operating-plane-client.js.map +1 -1
  25. package/dist/platform/operating-plane-summary.d.ts +4 -4
  26. package/dist/platform/operating-plane-summary.d.ts.map +1 -1
  27. package/dist/platform/operating-plane-summary.js +39 -27
  28. package/dist/platform/operating-plane-summary.js.map +1 -1
  29. package/dist/server/session-timeline.d.ts.map +1 -1
  30. package/dist/server/session-timeline.js +112 -2
  31. package/dist/server/session-timeline.js.map +1 -1
  32. package/dist/tools/background/resource-monitor.d.ts.map +1 -1
  33. package/dist/tools/background/resource-monitor.js +8 -6
  34. package/dist/tools/background/resource-monitor.js.map +1 -1
  35. package/dist/tools/parallel-ripgrep.d.ts.map +1 -1
  36. package/dist/tools/parallel-ripgrep.js +2 -2
  37. package/dist/tools/parallel-ripgrep.js.map +1 -1
  38. package/dist/tools/ripgrep-utils.d.ts +1 -0
  39. package/dist/tools/ripgrep-utils.d.ts.map +1 -1
  40. package/dist/tools/ripgrep-utils.js +4 -0
  41. package/dist/tools/ripgrep-utils.js.map +1 -1
  42. package/dist/tools/search.d.ts.map +1 -1
  43. package/dist/tools/search.js +2 -2
  44. package/dist/tools/search.js.map +1 -1
  45. package/dist/utils/document-extractor.d.ts.map +1 -1
  46. package/dist/utils/document-extractor.js +8 -1
  47. package/dist/utils/document-extractor.js.map +1 -1
  48. package/dist/version.json +2 -2
  49. package/package.json +2 -2
@@ -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\tformatRipgrepCommand,\n\tglobSchema,\n\tisRipgrepPathError,\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\tif (isRipgrepPathError(message)) {\n\t\t\t\t\treturn respond\n\t\t\t\t\t\t.error(\n\t\t\t\t\t\t\t`ripgrep failed\\n\\n${message.length > 0 ? message : \"ripgrep path lookup failed\"}`,\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.detail({\n\t\t\t\t\t\t\tcommands,\n\t\t\t\t\t\t\tcwd: commandCwd,\n\t\t\t\t\t\t\tmatchCount: 0,\n\t\t\t\t\t\t\trangeCount: 0,\n\t\t\t\t\t\t\tranges: [],\n\t\t\t\t\t\t\ttruncated: false,\n\t\t\t\t\t\t});\n\t\t\t\t}\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":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AACzC,OAAO,EACN,oBAAoB,EACpB,UAAU,EACV,kBAAkB,EAClB,wBAAwB,EACxB,gBAAgB,EAChB,UAAU,EACV,UAAU,EACV,OAAO,GACP,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE3D,kEAAkE;AAClE,MAAM,kBAAkB,GAAG,GAAG,CAAC;AAC/B,kEAAkE;AAClE,MAAM,mBAAmB,GAAG,GAAG,CAAC;AAEhC,MAAM,qBAAqB,GAAG,IAAI,CAAC,MAAM,CAAC;IACzC,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC,EAAE;QACnD,QAAQ,EAAE,CAAC;QACX,QAAQ,EAAE,EAAE;QACZ,WAAW,EACV,2FAA2F;KAC5F,CAAC;IACF,KAAK,EAAE,UAAU;IACjB,IAAI,EAAE,UAAU;IAChB,UAAU,EAAE,IAAI,CAAC,QAAQ,CACxB,IAAI,CAAC,OAAO,CAAC;QACZ,WAAW,EAAE,+CAA+C;QAC5D,OAAO,EAAE,KAAK;KACd,CAAC,CACF;IACD,OAAO,EAAE,IAAI,CAAC,QAAQ,CACrB,IAAI,CAAC,OAAO,CAAC;QACZ,WAAW,EACV,gEAAgE;QACjE,OAAO,EAAE,KAAK;KACd,CAAC,CACF;IACD,IAAI,EAAE,IAAI,CAAC,QAAQ,CAClB,IAAI,CAAC,OAAO,CAAC;QACZ,WAAW,EAAE,6BAA6B;QAC1C,OAAO,EAAE,KAAK;KACd,CAAC,CACF;IACD,SAAS,EAAE,IAAI,CAAC,QAAQ,CACvB,IAAI,CAAC,OAAO,CAAC;QACZ,WAAW,EAAE,yCAAyC;QACtD,OAAO,EAAE,KAAK;KACd,CAAC,CACF;IACD,UAAU,EAAE,IAAI,CAAC,QAAQ,CACxB,IAAI,CAAC,OAAO,CAAC;QACZ,WAAW,EAAE,8BAA8B;QAC3C,OAAO,EAAE,CAAC;QACV,OAAO,EAAE,IAAI;KACb,CAAC,CACF;IACD,OAAO,EAAE,IAAI,CAAC,QAAQ,CACrB,IAAI,CAAC,OAAO,CAAC;QACZ,WAAW,EAAE,mDAAmD;QAChE,OAAO,EAAE,CAAC;QACV,OAAO,EAAE,EAAE;KACX,CAAC,CACF;IACD,aAAa,EAAE,IAAI,CAAC,QAAQ,CAC3B,IAAI,CAAC,OAAO,CAAC;QACZ,WAAW,EAAE,yCAAyC;QACtD,OAAO,EAAE,CAAC;QACV,OAAO,EAAE,EAAE;KACX,CAAC,CACF;IACD,YAAY,EAAE,IAAI,CAAC,QAAQ,CAC1B,IAAI,CAAC,OAAO,CAAC;QACZ,WAAW,EAAE,wCAAwC;QACrD,OAAO,EAAE,CAAC;QACV,OAAO,EAAE,EAAE;KACX,CAAC,CACF;IACD,GAAG,EAAE,IAAI,CAAC,QAAQ,CACjB,IAAI,CAAC,MAAM,CAAC;QACX,WAAW,EAAE,+BAA+B;QAC5C,SAAS,EAAE,CAAC;KACZ,CAAC,CACF;IACD,aAAa,EAAE,IAAI,CAAC,QAAQ,CAC3B,IAAI,CAAC,OAAO,CAAC;QACZ,WAAW,EAAE,iCAAiC;QAC9C,OAAO,EAAE,KAAK;KACd,CAAC,CACF;IACD,YAAY,EAAE,IAAI,CAAC,QAAQ,CAC1B,IAAI,CAAC,OAAO,CAAC;QACZ,WAAW,EAAE,gDAAgD;QAC7D,OAAO,EAAE,IAAI;KACb,CAAC,CACF;IACD,SAAS,EAAE,IAAI,CAAC,QAAQ,CACvB,IAAI,CAAC,OAAO,CAAC;QACZ,WAAW,EAAE,4CAA4C;QACzD,OAAO,EAAE,CAAC;QACV,OAAO,EAAE,kBAAkB;KAC3B,CAAC,CACF;CACD,CAAC,CAAC;AAsCH;;;;;;;;;;;;GAYG;AACH,SAAS,WAAW,CACnB,MAAoE;IAMpE,mDAAmD;IACnD,MAAM,MAAM,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;IAC7D,MAAM,MAAM,GACX,EAAE,CAAC;IAEJ,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC5B,MAAM,IAAI,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3B,kEAAkE;QAClE,yDAAyD;QACzD,IAAI,IAAI,IAAI,KAAK,CAAC,KAAK,IAAI,IAAI,CAAC,GAAG,GAAG,CAAC,EAAE,CAAC;YACzC,+CAA+C;YAC/C,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;YACzC,KAAK,MAAM,OAAO,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;gBACtC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YAC5B,CAAC;QACF,CAAC;aAAM,CAAC;YACP,2BAA2B;YAC3B,MAAM,CAAC,IAAI,CAAC;gBACX,KAAK,EAAE,KAAK,CAAC,KAAK;gBAClB,GAAG,EAAE,KAAK,CAAC,GAAG;gBACd,QAAQ,EAAE,IAAI,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC;aACjC,CAAC,CAAC;QACJ,CAAC;IACF,CAAC;IAED,OAAO,MAAM,CAAC;AACf,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,KAAK,UAAU,iBAAiB,CAC/B,UAAkB,EAClB,MAKE,EACF,KAAa;IAEb,8DAA8D;IAC9D,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACzC,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;YACvB,OAAO,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC;QAC1B,CAAC;QACD,OAAO,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,MAAM,SAAS,GAAG,YAAY,CAAC,MAAM,GAAG,KAAK,CAAC;IAC9C,MAAM,QAAQ,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IAE9C,uEAAuE;IACvE,MAAM,SAAS,GAAG,IAAI,GAAG,EAAoB,CAAC;IAC9C,MAAM,OAAO,GAAkB,EAAE,CAAC;IAElC,KAAK,MAAM,KAAK,IAAI,QAAQ,EAAE,CAAC;QAC9B,MAAM,YAAY,GAAG,WAAW,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QACzD,IAAI,KAAe,CAAC;QAEpB,oBAAoB;QACpB,IAAI,SAAS,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC;YACjC,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,YAAY,CAAa,CAAC;QACjD,CAAC;aAAM,CAAC;YACP,IAAI,CAAC;gBACJ,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;gBACzD,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;gBAC/B,SAAS,CAAC,GAAG,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;YACpC,CAAC;YAAC,MAAM,CAAC;gBACR,6DAA6D;gBAC7D,SAAS;YACV,CAAC;QACF,CAAC;QAED,oCAAoC;QACpC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;QACvC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;QAC9C,IAAI,GAAG,GAAG,KAAK,EAAE,CAAC;YACjB,SAAS;QACV,CAAC;QAED,2EAA2E;QAC3E,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACvD,OAAO,CAAC,IAAI,CAAC;YACZ,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,KAAK;YACL,GAAG;YACH,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE;YAC3C,OAAO,EAAE,OAAO;SAChB,CAAC,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;AACvC,CAAC;AAED,MAAM,CAAC,MAAM,mBAAmB,GAAG,UAAU,CAG3C;IACD,IAAI,EAAE,kBAAkB;IACxB,KAAK,EAAE,kBAAkB;IACzB,WAAW,EACV,+RAA+R;IAChS,MAAM,EAAE,qBAAqB;IAC7B,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE;QACpC,MAAM,EACL,QAAQ,EACR,KAAK,EACL,IAAI,EACJ,UAAU,EACV,OAAO,EACP,IAAI,EACJ,SAAS,EACT,UAAU,EACV,OAAO,EACP,aAAa,EACb,YAAY,EACZ,GAAG,EACH,aAAa,EACb,YAAY,GAAG,IAAI,EACnB,SAAS,GACT,GAAG,MAAM,CAAC;QAEX,IACC,OAAO,KAAK,SAAS;YACrB,CAAC,aAAa,KAAK,SAAS,IAAI,YAAY,KAAK,SAAS,CAAC,EAC1D,CAAC;YACF,MAAM,IAAI,KAAK,CACd,+DAA+D,CAC/D,CAAC;QACH,CAAC;QAED,MAAM,QAAQ,GAAG,wBAAwB,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;QAC1D,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QAC/B,MAAM,UAAU,GAAG,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;QAC1E,MAAM,MAAM,GAAG,aAAa,IAAI,OAAO,IAAI,CAAC,CAAC;QAC7C,MAAM,KAAK,GAAG,YAAY,IAAI,OAAO,IAAI,CAAC,CAAC;QAE3C,MAAM,QAAQ,GAAa;YAC1B,eAAe;YACf,QAAQ;YACR,IAAI;YACJ,iBAAiB;SACjB,CAAC;QAEF,IAAI,UAAU,EAAE,CAAC;YAChB,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrB,CAAC;QAED,IAAI,OAAO,EAAE,CAAC;YACb,QAAQ,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QAClC,CAAC;QAED,IAAI,IAAI,EAAE,CAAC;YACV,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrB,CAAC;QAED,IAAI,SAAS,EAAE,CAAC;YACf,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAC9B,CAAC;QAED,IAAI,aAAa,EAAE,CAAC;YACnB,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC3B,CAAC;QAED,IAAI,CAAC,YAAY,EAAE,CAAC;YACnB,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAC9B,CAAC;QAED,MAAM,mBAAmB,GAAG,UAAU,IAAI,mBAAmB,CAAC;QAC9D,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,mBAAmB,CAAC,CAAC,CAAC;QAEjD,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC3B,QAAQ,CAAC,IAAI,CAAC,KAAK,OAAO,EAAE,CAAC,CAAC;QAC/B,CAAC;QAED,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;YACjC,QAAQ,CAAC,IAAI,CAAC,KAAK,aAAa,EAAE,CAAC,CAAC;QACrC,CAAC;QAED,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;YAChC,QAAQ,CAAC,IAAI,CAAC,KAAK,YAAY,EAAE,CAAC,CAAC;QACpC,CAAC;QAED,KAAK,MAAM,WAAW,IAAI,QAAQ,EAAE,CAAC;YACpC,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;QACtC,CAAC;QAED,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3B,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACpB,CAAC;QAED,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,IAAI,gBAAgB,GAAG,KAAK,CAAC;QAC7B,MAAM,YAAY,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;YACnD,MAAM,IAAI,GAAG,CAAC,GAAG,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,QAAQ,CAAC,CAAC;YACvD,QAAQ,CAAC,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAAC,CAAC;YAC1C,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC;YAC1D,gBAAgB,KAAK,MAAM,CAAC,SAAS,CAAC;YACtC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;QAC5B,CAAC,CAAC,CAAC;QAEH,IAAI,OAGF,CAAC;QACH,IAAI,CAAC;YACJ,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QAC3C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,MAAM,MAAM,GACX,KAAK,YAAY,KAAK;gBACrB,CAAC,CAAC,KAAK,CAAC,OAAO;gBACf,CAAC,CAAC,kBAAkB,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;YACtC,OAAO,OAAO,CAAC,KAAK,CAAC,qBAAqB,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;gBAC1D,QAAQ;gBACR,GAAG,EAAE,UAAU;gBACf,UAAU,EAAE,CAAC;gBACb,UAAU,EAAE,CAAC;gBACb,MAAM,EAAE,EAAE;gBACV,SAAS,EAAE,KAAK;aAChB,CAAC,CAAC;QACJ,CAAC;QAED,IAAI,UAAU,GAAG,CAAC,CAAC;QACnB,MAAM,YAAY,GAAG,IAAI,GAAG,EAGzB,CAAC;QAEJ,KAAK,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,OAAO,EAAE,CAAC;YAC3C,IAAI,MAAM,CAAC,QAAQ,KAAK,CAAC,EAAE,CAAC;gBAC3B,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;gBAC7D,IAAI,kBAAkB,CAAC,OAAO,CAAC,EAAE,CAAC;oBACjC,OAAO,OAAO;yBACZ,KAAK,CACL,qBAAqB,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,4BAA4B,EAAE,CAClF;yBACA,MAAM,CAAC;wBACP,QAAQ;wBACR,GAAG,EAAE,UAAU;wBACf,UAAU,EAAE,CAAC;wBACb,UAAU,EAAE,CAAC;wBACb,MAAM,EAAE,EAAE;wBACV,SAAS,EAAE,KAAK;qBAChB,CAAC,CAAC;gBACL,CAAC;gBACD,MAAM,IAAI,KAAK,CACd,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,8BAA8B,CAC7D,CAAC;YACH,CAAC;YAED,IAAI,MAAM,CAAC,QAAQ,KAAK,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAChE,SAAS;YACV,CAAC;YAED,MAAM,OAAO,GAAG,gBAAgB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAChD,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;YAE7B,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;gBAC7B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;gBAC/C,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC;gBAC/B,MAAM,MAAM,GAAG,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;gBAClD,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;gBAC1D,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YACtC,CAAC;QACF,CAAC;QAED,IAAI,UAAU,KAAK,CAAC,EAAE,CAAC;YACtB,OAAO,OAAO,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,MAAM,CAAC;gBAC/C,QAAQ;gBACR,GAAG,EAAE,UAAU;gBACf,UAAU;gBACV,UAAU,EAAE,CAAC;gBACb,MAAM,EAAE,EAAE;gBACV,SAAS,EAAE,KAAK;aAChB,CAAC,CAAC;QACJ,CAAC;QAED,MAAM,YAAY,GAKb,EAAE,CAAC;QACR,KAAK,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,YAAY,CAAC,OAAO,EAAE,EAAE,CAAC;YACrD,KAAK,MAAM,KAAK,IAAI,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC;gBACzC,YAAY,CAAC,IAAI,CAAC;oBACjB,IAAI;oBACJ,KAAK,EAAE,KAAK,CAAC,KAAK;oBAClB,GAAG,EAAE,KAAK,CAAC,GAAG;oBACd,QAAQ,EAAE,KAAK,CAAC,QAAQ;iBACxB,CAAC,CAAC;YACJ,CAAC;QACF,CAAC;QAED,MAAM,UAAU,GAAG,SAAS,IAAI,kBAAkB,CAAC;QACnD,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,iBAAiB,CACpD,UAAU,EACV,YAAY,EACZ,UAAU,CACV,CAAC;QAEF,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;QAClE,MAAM,YAAY,GAAG,MAAM;aACzB,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;YACd,MAAM,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,GAAG,KAAK,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;YAC3F,OAAO,GAAG,MAAM,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC;QACtC,CAAC,CAAC;aACD,IAAI,CAAC,MAAM,CAAC,CAAC;QAEf,MAAM,aAAa,GAAG,SAAS;YAC9B,CAAC,CAAC,oBAAoB,MAAM,CAAC,MAAM,OAAO,YAAY,CAAC,MAAM,UAAU;YACvE,CAAC,CAAC,gBAAgB;gBACjB,CAAC,CAAC,8CAA8C;gBAChD,CAAC,CAAC,EAAE,CAAC;QAEP,OAAO,OAAO;aACZ,IAAI,CACJ,SAAS,UAAU,qBAAqB,SAAS,gBAAgB,QAAQ,CAAC,MAAM,0BAA0B,YAAY,CAAC,MAAM,sBAAsB,YAAY,GAAG,aAAa,EAAE,CACjL;aACA,MAAM,CAAC;YACP,QAAQ;YACR,GAAG,EAAE,UAAU;YACf,UAAU;YACV,UAAU,EAAE,YAAY,CAAC,MAAM;YAC/B,MAAM;YACN,SAAS,EAAE,SAAS,IAAI,gBAAgB;SACxC,CAAC,CAAC;IACL,CAAC;CACD,CAAC,CAAC","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\tisRipgrepPathError,\n\tnormalizeRipgrepPathArgs,\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 = normalizeRipgrepPathArgs(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\tif (isRipgrepPathError(message)) {\n\t\t\t\t\treturn respond\n\t\t\t\t\t\t.error(\n\t\t\t\t\t\t\t`ripgrep failed\\n\\n${message.length > 0 ? message : \"ripgrep path lookup failed\"}`,\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.detail({\n\t\t\t\t\t\t\tcommands,\n\t\t\t\t\t\t\tcwd: commandCwd,\n\t\t\t\t\t\t\tmatchCount: 0,\n\t\t\t\t\t\t\trangeCount: 0,\n\t\t\t\t\t\t\tranges: [],\n\t\t\t\t\t\t\ttruncated: false,\n\t\t\t\t\t\t});\n\t\t\t\t}\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 normalizeRipgrepPathArgs(paths: string[]): string[];
4
5
  export declare function formatRipgrepCommand(args: string[]): string;
5
6
  export declare function isRipgrepPathError(message: string): boolean;
6
7
  export declare function runRipgrep(args: string[], signal?: AbortSignal, cwd?: string): Promise<{
@@ -1 +1 @@
1
- {"version":3,"file":"ripgrep-utils.d.ts","sourceRoot":"","sources":["../../src/tools/ripgrep-utils.ts"],"names":[],"mappings":"AAKA,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;AAgHD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,CAE3D;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAI3D;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,CAoDD;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"}
1
+ {"version":3,"file":"ripgrep-utils.d.ts","sourceRoot":"","sources":["../../src/tools/ripgrep-utils.ts"],"names":[],"mappings":"AAMA,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;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAElE;AAgHD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,CAE3D;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAI3D;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,CAoDD;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"}
@@ -1,6 +1,7 @@
1
1
  import { spawn } from "node:child_process";
2
2
  import { Type } from "@sinclair/typebox";
3
3
  import { safeJsonParse } from "../utils/json.js";
4
+ import { expandTildePath } from "../utils/path-expansion.js";
4
5
  import { ensureTool } from "./tools-manager.js";
5
6
  export const pathSchema = Type.Optional(Type.Union([
6
7
  Type.String({
@@ -28,6 +29,9 @@ export function toArray(value) {
28
29
  }
29
30
  return Array.isArray(value) ? value : [value];
30
31
  }
32
+ export function normalizeRipgrepPathArgs(paths) {
33
+ return paths.map((path) => expandTildePath(path));
34
+ }
31
35
  const MAX_RIPGREP_OUTPUT_BYTES = 2_000_000; // ~2MB safeguard
32
36
  let ripgrepExecutablePromise = null;
33
37
  let ripgrepInstallController = null;
@@ -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\";\nimport { ensureTool } from \"./tools-manager.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\nlet ripgrepExecutablePromise: Promise<string | null> | null = null;\nlet ripgrepInstallController: AbortController | null = null;\nlet ripgrepExecutableWaiters = 0;\n\nfunction ripgrepAbortError(): Error {\n\treturn new Error(\"ripgrep search aborted before start\");\n}\n\nfunction resetRipgrepExecutablePromise(): void {\n\tripgrepExecutablePromise = null;\n\tripgrepInstallController = null;\n}\n\nfunction getRipgrepExecutablePromise(): Promise<string | null> {\n\tif (!ripgrepExecutablePromise) {\n\t\tconst controller = new AbortController();\n\t\tripgrepInstallController = controller;\n\t\tconst promise = ensureTool(\"rg\", true, controller.signal).then(\n\t\t\t(executable) => {\n\t\t\t\tif (ripgrepInstallController === controller) {\n\t\t\t\t\tripgrepInstallController = null;\n\t\t\t\t}\n\t\t\t\tif (ripgrepExecutablePromise === promise && !executable) {\n\t\t\t\t\tripgrepExecutablePromise = null;\n\t\t\t\t}\n\t\t\t\treturn executable;\n\t\t\t},\n\t\t\t(error) => {\n\t\t\t\tif (ripgrepInstallController === controller) {\n\t\t\t\t\tripgrepInstallController = null;\n\t\t\t\t}\n\t\t\t\tif (ripgrepExecutablePromise === promise) {\n\t\t\t\t\tripgrepExecutablePromise = null;\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t},\n\t\t);\n\t\tripgrepExecutablePromise = promise;\n\t}\n\treturn ripgrepExecutablePromise;\n}\n\nfunction releaseRipgrepExecutableWaiter(signal?: AbortSignal): void {\n\tripgrepExecutableWaiters = Math.max(0, ripgrepExecutableWaiters - 1);\n\tif (signal?.aborted && ripgrepExecutableWaiters === 0) {\n\t\tconst controller = ripgrepInstallController;\n\t\tresetRipgrepExecutablePromise();\n\t\tcontroller?.abort(signal.reason);\n\t}\n}\n\nasync function waitForRipgrepExecutableWithAbort(\n\tpromise: Promise<string | null>,\n\tsignal: AbortSignal,\n): Promise<string | null> {\n\tthrowIfRipgrepAborted(signal);\n\treturn await new Promise<string | null>((resolve, reject) => {\n\t\tconst onAbort = (): void => {\n\t\t\tsignal.removeEventListener(\"abort\", onAbort);\n\t\t\treject(ripgrepAbortError());\n\t\t};\n\n\t\tsignal.addEventListener(\"abort\", onAbort, { once: true });\n\t\tpromise.then(resolve, reject).finally(() => {\n\t\t\tsignal.removeEventListener(\"abort\", onAbort);\n\t\t});\n\t});\n}\n\nasync function resolveRipgrepExecutable(signal?: AbortSignal): Promise<string> {\n\tripgrepExecutableWaiters += 1;\n\ttry {\n\t\tconst promise = getRipgrepExecutablePromise();\n\t\tconst executable = signal\n\t\t\t? await waitForRipgrepExecutableWithAbort(promise, signal)\n\t\t\t: await promise;\n\t\tif (!executable) {\n\t\t\tthrow new Error(\"ripgrep is not available and could not be downloaded\");\n\t\t}\n\t\treturn executable;\n\t} finally {\n\t\treleaseRipgrepExecutableWaiter(signal);\n\t}\n}\n\nfunction throwIfRipgrepAborted(signal?: AbortSignal): void {\n\tif (signal?.aborted) {\n\t\tthrow ripgrepAbortError();\n\t}\n}\n\nasync function resolveRipgrepExecutableWithAbort(\n\tsignal?: AbortSignal,\n): Promise<string> {\n\tthrowIfRipgrepAborted(signal);\n\tif (!signal) {\n\t\treturn await resolveRipgrepExecutable();\n\t}\n\n\treturn await resolveRipgrepExecutable(signal);\n}\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 function isRipgrepPathError(message: string): boolean {\n\treturn /No such file or directory|IO error|os error 2|system cannot find the path/i.test(\n\t\tmessage,\n\t);\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 executable = await resolveRipgrepExecutableWithAbort(signal);\n\tthrowIfRipgrepAborted(signal);\n\tconst child = spawn(executable, 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\";\nimport { expandTildePath } from \"../utils/path-expansion.js\";\nimport { ensureTool } from \"./tools-manager.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\nexport function normalizeRipgrepPathArgs(paths: string[]): string[] {\n\treturn paths.map((path) => expandTildePath(path));\n}\n\nconst MAX_RIPGREP_OUTPUT_BYTES = 2_000_000; // ~2MB safeguard\nlet ripgrepExecutablePromise: Promise<string | null> | null = null;\nlet ripgrepInstallController: AbortController | null = null;\nlet ripgrepExecutableWaiters = 0;\n\nfunction ripgrepAbortError(): Error {\n\treturn new Error(\"ripgrep search aborted before start\");\n}\n\nfunction resetRipgrepExecutablePromise(): void {\n\tripgrepExecutablePromise = null;\n\tripgrepInstallController = null;\n}\n\nfunction getRipgrepExecutablePromise(): Promise<string | null> {\n\tif (!ripgrepExecutablePromise) {\n\t\tconst controller = new AbortController();\n\t\tripgrepInstallController = controller;\n\t\tconst promise = ensureTool(\"rg\", true, controller.signal).then(\n\t\t\t(executable) => {\n\t\t\t\tif (ripgrepInstallController === controller) {\n\t\t\t\t\tripgrepInstallController = null;\n\t\t\t\t}\n\t\t\t\tif (ripgrepExecutablePromise === promise && !executable) {\n\t\t\t\t\tripgrepExecutablePromise = null;\n\t\t\t\t}\n\t\t\t\treturn executable;\n\t\t\t},\n\t\t\t(error) => {\n\t\t\t\tif (ripgrepInstallController === controller) {\n\t\t\t\t\tripgrepInstallController = null;\n\t\t\t\t}\n\t\t\t\tif (ripgrepExecutablePromise === promise) {\n\t\t\t\t\tripgrepExecutablePromise = null;\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t},\n\t\t);\n\t\tripgrepExecutablePromise = promise;\n\t}\n\treturn ripgrepExecutablePromise;\n}\n\nfunction releaseRipgrepExecutableWaiter(signal?: AbortSignal): void {\n\tripgrepExecutableWaiters = Math.max(0, ripgrepExecutableWaiters - 1);\n\tif (signal?.aborted && ripgrepExecutableWaiters === 0) {\n\t\tconst controller = ripgrepInstallController;\n\t\tresetRipgrepExecutablePromise();\n\t\tcontroller?.abort(signal.reason);\n\t}\n}\n\nasync function waitForRipgrepExecutableWithAbort(\n\tpromise: Promise<string | null>,\n\tsignal: AbortSignal,\n): Promise<string | null> {\n\tthrowIfRipgrepAborted(signal);\n\treturn await new Promise<string | null>((resolve, reject) => {\n\t\tconst onAbort = (): void => {\n\t\t\tsignal.removeEventListener(\"abort\", onAbort);\n\t\t\treject(ripgrepAbortError());\n\t\t};\n\n\t\tsignal.addEventListener(\"abort\", onAbort, { once: true });\n\t\tpromise.then(resolve, reject).finally(() => {\n\t\t\tsignal.removeEventListener(\"abort\", onAbort);\n\t\t});\n\t});\n}\n\nasync function resolveRipgrepExecutable(signal?: AbortSignal): Promise<string> {\n\tripgrepExecutableWaiters += 1;\n\ttry {\n\t\tconst promise = getRipgrepExecutablePromise();\n\t\tconst executable = signal\n\t\t\t? await waitForRipgrepExecutableWithAbort(promise, signal)\n\t\t\t: await promise;\n\t\tif (!executable) {\n\t\t\tthrow new Error(\"ripgrep is not available and could not be downloaded\");\n\t\t}\n\t\treturn executable;\n\t} finally {\n\t\treleaseRipgrepExecutableWaiter(signal);\n\t}\n}\n\nfunction throwIfRipgrepAborted(signal?: AbortSignal): void {\n\tif (signal?.aborted) {\n\t\tthrow ripgrepAbortError();\n\t}\n}\n\nasync function resolveRipgrepExecutableWithAbort(\n\tsignal?: AbortSignal,\n): Promise<string> {\n\tthrowIfRipgrepAborted(signal);\n\tif (!signal) {\n\t\treturn await resolveRipgrepExecutable();\n\t}\n\n\treturn await resolveRipgrepExecutable(signal);\n}\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 function isRipgrepPathError(message: string): boolean {\n\treturn /No such file or directory|IO error|os error 2|system cannot find the path/i.test(\n\t\tmessage,\n\t);\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 executable = await resolveRipgrepExecutableWithAbort(signal);\n\tthrowIfRipgrepAborted(signal);\n\tconst child = spawn(executable, 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,EAQjB,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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4UrB,CAAC"}
1
+ {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AAIH,OAAO,EACN,KAAK,YAAY,EASjB,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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4UrB,CAAC"}
@@ -51,7 +51,7 @@
51
51
  */
52
52
  import { resolve as resolvePath } from "node:path";
53
53
  import { Type } from "@sinclair/typebox";
54
- import { formatRipgrepCommand, globSchema, isRipgrepPathError, parseRipgrepJson, pathSchema, runRipgrep, toArray, } from "./ripgrep-utils.js";
54
+ import { formatRipgrepCommand, globSchema, isRipgrepPathError, normalizeRipgrepPathArgs, 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({
@@ -173,7 +173,7 @@ Examples:
173
173
  if (format === "json" && outputMode !== "content") {
174
174
  throw new Error("JSON format is not supported with outputMode: 'files' or 'count'. Use format: 'text' or omit the format parameter.");
175
175
  }
176
- const pathArgs = toArray(paths);
176
+ const pathArgs = normalizeRipgrepPathArgs(toArray(paths));
177
177
  const globArgs = toArray(glob);
178
178
  const commandCwd = cwd ? resolvePath(expandUserPath(cwd)) : process.cwd();
179
179
  const args = ["--color=never"];
@@ -1 +1 @@
1
- {"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Search Tool - Ripgrep-Powered Code Search\n *\n * This module provides a powerful search tool that wraps ripgrep (rg) for\n * fast, regex-capable searching across codebases. It supports multiple\n * output modes, context controls, and filtering options.\n *\n * ## Output Modes\n *\n * | Mode | Description | Use Case |\n * |-----------|------------------------------------|-----------------------------|\n * | content | Show matching lines with context | Reading code matches |\n * | files | List only file paths | Finding which files match |\n * | count | Show match counts per file | Gauging search scope |\n *\n * ## Features\n *\n * - **Regex support**: Full regex patterns or literal string matching\n * - **Case handling**: Case-sensitive or insensitive searches\n * - **Context lines**: Show surrounding lines for context (-B, -A, -C)\n * - **Glob filtering**: Target specific file patterns\n * - **Git-aware**: Respects .gitignore by default\n * - **Multiline**: Optional multiline pattern matching\n * - **JSON output**: Structured results for programmatic use\n *\n * ## Example\n *\n * ```typescript\n * // Find all TODO comments in TypeScript files\n * searchTool.execute('call-id', {\n * pattern: 'TODO',\n * glob: '*.ts',\n * outputMode: 'files',\n * });\n *\n * // Search with context\n * searchTool.execute('call-id', {\n * pattern: 'function\\\\s+\\\\w+',\n * context: 3,\n * ignoreCase: true,\n * });\n * ```\n *\n * ## Performance\n *\n * - Default max results: 500 (configurable up to 1000)\n * - Head limit for sampling large result sets\n * - Truncation indicators when limits are hit\n *\n * @module tools/search\n */\n\nimport { resolve as resolvePath } from \"node:path\";\nimport { Type } from \"@sinclair/typebox\";\nimport {\n\ttype RipgrepMatch,\n\tformatRipgrepCommand,\n\tglobSchema,\n\tisRipgrepPathError,\n\tparseRipgrepJson,\n\tpathSchema,\n\trunRipgrep,\n\ttoArray,\n} from \"./ripgrep-utils.js\";\nimport { createTool, expandUserPath } from \"./tool-dsl.js\";\n\nconst searchSchema = Type.Object(\n\t{\n\t\tpattern: Type.String({\n\t\t\tdescription: \"Regex pattern (or literal when literal=true)\",\n\t\t\tminLength: 1,\n\t\t}),\n\t\tpaths: pathSchema,\n\t\tglob: globSchema,\n\t\tignoreCase: Type.Optional(\n\t\t\tType.Boolean({\n\t\t\t\tdescription: \"Perform case-insensitive search (-i).\",\n\t\t\t\tdefault: false,\n\t\t\t}),\n\t\t),\n\t\tliteral: Type.Optional(\n\t\t\tType.Boolean({\n\t\t\t\tdescription: \"Treat the pattern as a literal string (--fixed-strings).\",\n\t\t\t\tdefault: false,\n\t\t\t}),\n\t\t),\n\t\tword: Type.Optional(\n\t\t\tType.Boolean({\n\t\t\t\tdescription: \"Match only whole words (-w).\",\n\t\t\t\tdefault: false,\n\t\t\t}),\n\t\t),\n\t\tmultiline: Type.Optional(\n\t\t\tType.Boolean({\n\t\t\t\tdescription: \"Enable multiline matching (--multiline).\",\n\t\t\t\tdefault: false,\n\t\t\t}),\n\t\t),\n\t\tmaxResults: Type.Optional(\n\t\t\tType.Integer({\n\t\t\t\tdescription: \"Stop after this many matches (-m).\",\n\t\t\t\tminimum: 1,\n\t\t\t\tmaximum: 1000,\n\t\t\t}),\n\t\t),\n\t\tcontext: Type.Optional(\n\t\t\tType.Integer({\n\t\t\t\tdescription: \"Show this many lines of context before and after (-C).\",\n\t\t\t\tminimum: 0,\n\t\t\t\tmaximum: 20,\n\t\t\t}),\n\t\t),\n\t\tbeforeContext: Type.Optional(\n\t\t\tType.Integer({\n\t\t\t\tdescription: \"Show this many lines of context before each match (-B).\",\n\t\t\t\tminimum: 0,\n\t\t\t\tmaximum: 20,\n\t\t\t}),\n\t\t),\n\t\tafterContext: Type.Optional(\n\t\t\tType.Integer({\n\t\t\t\tdescription: \"Show this many lines of context after each match (-A).\",\n\t\t\t\tminimum: 0,\n\t\t\t\tmaximum: 20,\n\t\t\t}),\n\t\t),\n\t\tcwd: Type.Optional(\n\t\t\tType.String({\n\t\t\t\tdescription: \"Working directory to run ripgrep from\",\n\t\t\t\tminLength: 1,\n\t\t\t}),\n\t\t),\n\t\tincludeHidden: Type.Optional(\n\t\t\tType.Boolean({\n\t\t\t\tdescription: \"Include hidden files (--hidden)\",\n\t\t\t\tdefault: false,\n\t\t\t}),\n\t\t),\n\t\tuseGitIgnore: Type.Optional(\n\t\t\tType.Boolean({\n\t\t\t\tdescription: \"Respect .gitignore (set false to pass --no-ignore)\",\n\t\t\t\tdefault: true,\n\t\t\t}),\n\t\t),\n\t\toutputMode: Type.Optional(\n\t\t\tType.Union(\n\t\t\t\t[Type.Literal(\"content\"), Type.Literal(\"files\"), Type.Literal(\"count\")],\n\t\t\t\t{\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"Output mode: 'content' shows matching lines (default), 'files' lists only file paths, 'count' shows match counts per file.\",\n\t\t\t\t\tdefault: \"content\",\n\t\t\t\t},\n\t\t\t),\n\t\t),\n\t\tformat: Type.Optional(\n\t\t\tType.Union([Type.Literal(\"text\"), Type.Literal(\"json\")], {\n\t\t\t\tdescription:\n\t\t\t\t\t\"Output format for content mode. JSON not supported with files/count modes.\",\n\t\t\t\tdefault: \"text\",\n\t\t\t}),\n\t\t),\n\t\tinvertMatch: Type.Optional(\n\t\t\tType.Boolean({\n\t\t\t\tdescription:\n\t\t\t\t\t\"Show lines that do NOT match the pattern (--invert-match).\",\n\t\t\t\tdefault: false,\n\t\t\t}),\n\t\t),\n\t\tonlyMatching: Type.Optional(\n\t\t\tType.Boolean({\n\t\t\t\tdescription:\n\t\t\t\t\t\"Only show the matched text, not the entire line (--only-matching). Only works with content mode.\",\n\t\t\t\tdefault: false,\n\t\t\t}),\n\t\t),\n\t\theadLimit: Type.Optional(\n\t\t\tType.Integer({\n\t\t\t\tdescription:\n\t\t\t\t\t\"Limit output to first N lines/entries. Useful for sampling large result sets.\",\n\t\t\t\tminimum: 1,\n\t\t\t\tmaximum: 10000,\n\t\t\t}),\n\t\t),\n\t},\n\t{\n\t\tdescription:\n\t\t\t\"Use either context or before/after context options, not both.\",\n\t},\n);\n\nconst JSON_DETAIL_LIMIT = 200;\nconst DEFAULT_MAX_RESULTS = 500;\n\ntype SearchToolDetails = {\n\tcommand: string;\n\tcwd: string;\n\tformat?: \"text\" | \"json\" | \"files\" | \"count\";\n\tmatches?: RipgrepMatch[];\n\tfileCount?: number;\n\tfiles?: string[];\n\ttotalMatches?: number;\n\tcounts?: Array<{ file: string; count: number }>;\n\ttruncated?: boolean;\n};\n\nexport const searchTool = createTool<typeof searchSchema, SearchToolDetails>({\n\tname: \"search\",\n\tlabel: \"search\",\n\tdescription: `Find text across files using ripgrep with optional globbing and context controls.\n\nOutput modes (outputMode parameter):\n- \"content\": Show matching lines with file:line:content format (default)\n- \"files\": List only file paths containing matches (fast for finding files)\n- \"count\": Show match counts per file (useful for gauging scope)\n\nModifiers:\n- invertMatch: Show lines that do NOT match\n- onlyMatching: Show only the matched text (content mode only)\n- headLimit: Limit output to first N entries (useful for sampling)\n\nExamples:\n {pattern: \"TODO\", outputMode: \"files\"} → list files containing TODO\n {pattern: \"function\", outputMode: \"count\"} → count functions per file\n {pattern: \"^#\", invertMatch: true} → lines not starting with #`,\n\tschema: searchSchema,\n\tasync run(params, { signal, respond }) {\n\t\tconst {\n\t\t\tpattern,\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\toutputMode = \"content\",\n\t\t\tformat = \"text\",\n\t\t\tinvertMatch = false,\n\t\t\tonlyMatching = false,\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\t// Validate options incompatible with files/count modes\n\t\tif (outputMode !== \"content\" && onlyMatching) {\n\t\t\tthrow new Error(\n\t\t\t\t\"onlyMatching can only be used with outputMode: 'content'.\",\n\t\t\t);\n\t\t}\n\n\t\tif (\n\t\t\toutputMode !== \"content\" &&\n\t\t\t(context !== undefined ||\n\t\t\t\tbeforeContext !== undefined ||\n\t\t\t\tafterContext !== undefined)\n\t\t) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Context options can only be used with outputMode: 'content'.\",\n\t\t\t);\n\t\t}\n\n\t\tif (format === \"json\" && outputMode !== \"content\") {\n\t\t\tthrow new Error(\n\t\t\t\t\"JSON format is not supported with outputMode: 'files' or 'count'. Use format: 'text' or omit the format parameter.\",\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\n\t\tconst args: string[] = [\"--color=never\"];\n\n\t\t// Output mode flags\n\t\tif (outputMode === \"files\") {\n\t\t\targs.push(\"--files-with-matches\");\n\t\t} else if (outputMode === \"count\") {\n\t\t\t// Use --count-matches for actual match counts, -H to always show filename\n\t\t\targs.push(\"--count-matches\", \"-H\");\n\t\t} else {\n\t\t\t// content mode: show line numbers and filenames\n\t\t\targs.push(\"-n\", \"--with-filename\");\n\t\t}\n\n\t\tif (ignoreCase) {\n\t\t\targs.push(\"-i\");\n\t\t}\n\n\t\tif (literal) {\n\t\t\targs.push(\"--fixed-strings\");\n\t\t}\n\n\t\tif (word) {\n\t\t\targs.push(\"-w\");\n\t\t}\n\n\t\tif (multiline) {\n\t\t\targs.push(\"--multiline\");\n\t\t}\n\n\t\tif (includeHidden) {\n\t\t\targs.push(\"--hidden\");\n\t\t}\n\n\t\tif (!useGitIgnore) {\n\t\t\targs.push(\"--no-ignore\");\n\t\t}\n\n\t\tif (invertMatch) {\n\t\t\targs.push(\"--invert-match\");\n\t\t}\n\n\t\tif (onlyMatching) {\n\t\t\targs.push(\"--only-matching\");\n\t\t}\n\n\t\tconst shouldApplyMaxResults =\n\t\t\toutputMode === \"content\" || maxResults !== undefined;\n\t\tif (shouldApplyMaxResults) {\n\t\t\tconst effectiveMaxResults = maxResults ?? DEFAULT_MAX_RESULTS;\n\t\t\targs.push(\"-m\", String(effectiveMaxResults));\n\t\t}\n\n\t\tif (context !== undefined) {\n\t\t\targs.push(`-C${context}`);\n\t\t}\n\n\t\tif (beforeContext !== undefined) {\n\t\t\targs.push(`-B${beforeContext}`);\n\t\t}\n\n\t\tif (afterContext !== undefined) {\n\t\t\targs.push(`-A${afterContext}`);\n\t\t}\n\n\t\tfor (const globPattern of globArgs) {\n\t\t\targs.push(\"--glob\", globPattern);\n\t\t}\n\n\t\tif (format === \"json\" && outputMode === \"content\") {\n\t\t\targs.push(\"--json\");\n\t\t}\n\n\t\targs.push(\"--\", pattern);\n\n\t\tif (pathArgs.length > 0) {\n\t\t\targs.push(...pathArgs);\n\t\t} else {\n\t\t\targs.push(\".\");\n\t\t}\n\n\t\tconst command = formatRipgrepCommand(args);\n\t\tlet result: {\n\t\t\tstdout: string;\n\t\t\tstderr: string;\n\t\t\texitCode: number;\n\t\t\ttruncated: boolean;\n\t\t};\n\t\ttry {\n\t\t\tresult = await runRipgrep(args, signal, commandCwd);\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\n\t\t\t\t.error(`ripgrep failed\\n\\n${reason}`)\n\t\t\t\t.detail({ command, cwd: commandCwd });\n\t\t}\n\n\t\tif (result.exitCode === 2) {\n\t\t\tconst message = result.stderr.trim() || result.stdout.trim();\n\t\t\tif (isRipgrepPathError(message)) {\n\t\t\t\treturn respond\n\t\t\t\t\t.error(\n\t\t\t\t\t\t`ripgrep failed\\n\\n${message.length > 0 ? message : \"ripgrep path lookup failed\"}`,\n\t\t\t\t\t)\n\t\t\t\t\t.detail({ command, cwd: commandCwd });\n\t\t\t}\n\t\t\tthrow new Error(\n\t\t\t\tmessage.length > 0 ? message : \"ripgrep exited with an error\",\n\t\t\t);\n\t\t}\n\n\t\tif (result.exitCode === 1 || result.stdout.trim().length === 0) {\n\t\t\t// Use correct format in detail based on mode\n\t\t\tconst detailFormat =\n\t\t\t\toutputMode === \"files\"\n\t\t\t\t\t? \"files\"\n\t\t\t\t\t: outputMode === \"count\"\n\t\t\t\t\t\t? \"count\"\n\t\t\t\t\t\t: format;\n\t\t\treturn respond\n\t\t\t\t.text(\"No matches found.\")\n\t\t\t\t.detail({ command, cwd: commandCwd, format: detailFormat });\n\t\t}\n\n\t\tconst truncatedByBytes = result.truncated ?? false;\n\n\t\t// Handle files mode output\n\t\tif (outputMode === \"files\") {\n\t\t\tconst allFiles = result.stdout\n\t\t\t\t.trim()\n\t\t\t\t.split(\"\\n\")\n\t\t\t\t.filter((f) => f.length > 0);\n\t\t\tconst files =\n\t\t\t\theadLimit !== undefined ? allFiles.slice(0, headLimit) : allFiles;\n\t\t\tconst truncated = headLimit !== undefined && allFiles.length > headLimit;\n\t\t\tconst fileList = files.join(\"\\n\");\n\t\t\tconst truncatedNote = truncated\n\t\t\t\t? `\\n\\n... (showing ${files.length} of ${allFiles.length} files)`\n\t\t\t\t: truncatedByBytes\n\t\t\t\t\t? \"\\n\\n... (output truncated due to size limit)\"\n\t\t\t\t\t: \"\";\n\t\t\treturn respond\n\t\t\t\t.text(\n\t\t\t\t\t`Found ${allFiles.length} file(s) matching \"${pattern}\":\\n\\n${fileList}${truncatedNote}`,\n\t\t\t\t)\n\t\t\t\t.detail({\n\t\t\t\t\tcommand,\n\t\t\t\t\tcwd: commandCwd,\n\t\t\t\t\tformat: \"files\",\n\t\t\t\t\tfileCount: allFiles.length,\n\t\t\t\t\tfiles,\n\t\t\t\t\ttruncated: truncated || truncatedByBytes,\n\t\t\t\t});\n\t\t}\n\n\t\t// Handle count mode output\n\t\tif (outputMode === \"count\") {\n\t\t\tconst lines = result.stdout\n\t\t\t\t.trim()\n\t\t\t\t.split(\"\\n\")\n\t\t\t\t.filter((l) => l.length > 0);\n\t\t\tconst allCounts: Array<{ file: string; count: number }> = [];\n\t\t\tlet totalMatches = 0;\n\t\t\t// Use regex to parse \"filename:count\" format robustly\n\t\t\t// This handles Windows paths (C:\\path\\file.txt:5) and colons in filenames\n\t\t\tconst countLineRegex = /^(.+):(\\d+)$/;\n\t\t\tfor (const line of lines) {\n\t\t\t\tconst match = line.match(countLineRegex);\n\t\t\t\tif (match) {\n\t\t\t\t\tconst file = match[1]!;\n\t\t\t\t\tconst matchCount = Number.parseInt(match[2]!, 10);\n\t\t\t\t\tallCounts.push({ file, count: matchCount });\n\t\t\t\t\ttotalMatches += matchCount;\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst counts =\n\t\t\t\theadLimit !== undefined ? allCounts.slice(0, headLimit) : allCounts;\n\t\t\tconst truncated = headLimit !== undefined && allCounts.length > headLimit;\n\t\t\tconst summary = counts.map((c) => `${c.file}: ${c.count}`).join(\"\\n\");\n\t\t\tconst truncatedNote = truncated\n\t\t\t\t? `\\n\\n... (showing ${counts.length} of ${allCounts.length} files)`\n\t\t\t\t: truncatedByBytes\n\t\t\t\t\t? \"\\n\\n... (output truncated due to size limit)\"\n\t\t\t\t\t: \"\";\n\t\t\treturn respond\n\t\t\t\t.text(\n\t\t\t\t\t`Found ${totalMatches} match(es) across ${allCounts.length} file(s):\\n\\n${summary}${truncatedNote}`,\n\t\t\t\t)\n\t\t\t\t.detail({\n\t\t\t\t\tcommand,\n\t\t\t\t\tcwd: commandCwd,\n\t\t\t\t\tformat: \"count\",\n\t\t\t\t\ttotalMatches,\n\t\t\t\t\tfileCount: allCounts.length,\n\t\t\t\t\tcounts,\n\t\t\t\t\ttruncated: truncated || truncatedByBytes,\n\t\t\t\t});\n\t\t}\n\n\t\t// Handle JSON format\n\t\tif (format === \"json\") {\n\t\t\tconst allMatches = parseRipgrepJson(result.stdout);\n\t\t\tconst matches =\n\t\t\t\theadLimit !== undefined ? allMatches.slice(0, headLimit) : allMatches;\n\t\t\tconst headLimitTruncated =\n\t\t\t\theadLimit !== undefined && allMatches.length > headLimit;\n\t\t\tconst detailLimitTruncated = matches.length > JSON_DETAIL_LIMIT;\n\t\t\tconst truncated =\n\t\t\t\theadLimitTruncated || detailLimitTruncated || truncatedByBytes;\n\t\t\tconst preview = matches\n\t\t\t\t.slice(0, 5)\n\t\t\t\t.map(\n\t\t\t\t\t(match) =>\n\t\t\t\t\t\t`${match.file}:${match.line}:${match.column} ${match.match.trim()}`,\n\t\t\t\t)\n\t\t\t\t.join(\"\\n\");\n\t\t\tconst suffix =\n\t\t\t\tmatches.length > 5 ? `\\n... (${matches.length - 5} more matches)` : \"\";\n\t\t\tconst truncatedNote = headLimitTruncated\n\t\t\t\t? `\\n(showing ${matches.length} of ${allMatches.length} total matches)`\n\t\t\t\t: \"\";\n\t\t\tconst text = matches.length\n\t\t\t\t? `Found ${allMatches.length} match(es).${truncatedNote}\\n\\n${preview}${suffix}`\n\t\t\t\t: \"No matches found.\";\n\t\t\treturn respond.text(text).detail({\n\t\t\t\tcommand,\n\t\t\t\tcwd: commandCwd,\n\t\t\t\tformat,\n\t\t\t\tmatches: matches.slice(0, JSON_DETAIL_LIMIT),\n\t\t\t\ttruncated,\n\t\t\t});\n\t\t}\n\n\t\t// Handle text format (content mode)\n\t\tconst lines = result.stdout.trimEnd().split(\"\\n\");\n\t\tconst outputLines =\n\t\t\theadLimit !== undefined ? lines.slice(0, headLimit) : lines;\n\t\tconst truncated = headLimit !== undefined && lines.length > headLimit;\n\t\tconst truncatedNote = truncated\n\t\t\t? `\\n\\n... (showing ${outputLines.length} of ${lines.length} lines)`\n\t\t\t: truncatedByBytes\n\t\t\t\t? \"\\n\\n... (output truncated due to size limit)\"\n\t\t\t\t: \"\";\n\t\treturn respond.text(outputLines.join(\"\\n\") + truncatedNote).detail({\n\t\t\tcommand,\n\t\t\tcwd: commandCwd,\n\t\t\tformat,\n\t\t\ttruncated: truncated || truncatedByBytes,\n\t\t});\n\t},\n});\n"]}
1
+ {"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Search Tool - Ripgrep-Powered Code Search\n *\n * This module provides a powerful search tool that wraps ripgrep (rg) for\n * fast, regex-capable searching across codebases. It supports multiple\n * output modes, context controls, and filtering options.\n *\n * ## Output Modes\n *\n * | Mode | Description | Use Case |\n * |-----------|------------------------------------|-----------------------------|\n * | content | Show matching lines with context | Reading code matches |\n * | files | List only file paths | Finding which files match |\n * | count | Show match counts per file | Gauging search scope |\n *\n * ## Features\n *\n * - **Regex support**: Full regex patterns or literal string matching\n * - **Case handling**: Case-sensitive or insensitive searches\n * - **Context lines**: Show surrounding lines for context (-B, -A, -C)\n * - **Glob filtering**: Target specific file patterns\n * - **Git-aware**: Respects .gitignore by default\n * - **Multiline**: Optional multiline pattern matching\n * - **JSON output**: Structured results for programmatic use\n *\n * ## Example\n *\n * ```typescript\n * // Find all TODO comments in TypeScript files\n * searchTool.execute('call-id', {\n * pattern: 'TODO',\n * glob: '*.ts',\n * outputMode: 'files',\n * });\n *\n * // Search with context\n * searchTool.execute('call-id', {\n * pattern: 'function\\\\s+\\\\w+',\n * context: 3,\n * ignoreCase: true,\n * });\n * ```\n *\n * ## Performance\n *\n * - Default max results: 500 (configurable up to 1000)\n * - Head limit for sampling large result sets\n * - Truncation indicators when limits are hit\n *\n * @module tools/search\n */\n\nimport { resolve as resolvePath } from \"node:path\";\nimport { Type } from \"@sinclair/typebox\";\nimport {\n\ttype RipgrepMatch,\n\tformatRipgrepCommand,\n\tglobSchema,\n\tisRipgrepPathError,\n\tnormalizeRipgrepPathArgs,\n\tparseRipgrepJson,\n\tpathSchema,\n\trunRipgrep,\n\ttoArray,\n} from \"./ripgrep-utils.js\";\nimport { createTool, expandUserPath } from \"./tool-dsl.js\";\n\nconst searchSchema = Type.Object(\n\t{\n\t\tpattern: Type.String({\n\t\t\tdescription: \"Regex pattern (or literal when literal=true)\",\n\t\t\tminLength: 1,\n\t\t}),\n\t\tpaths: pathSchema,\n\t\tglob: globSchema,\n\t\tignoreCase: Type.Optional(\n\t\t\tType.Boolean({\n\t\t\t\tdescription: \"Perform case-insensitive search (-i).\",\n\t\t\t\tdefault: false,\n\t\t\t}),\n\t\t),\n\t\tliteral: Type.Optional(\n\t\t\tType.Boolean({\n\t\t\t\tdescription: \"Treat the pattern as a literal string (--fixed-strings).\",\n\t\t\t\tdefault: false,\n\t\t\t}),\n\t\t),\n\t\tword: Type.Optional(\n\t\t\tType.Boolean({\n\t\t\t\tdescription: \"Match only whole words (-w).\",\n\t\t\t\tdefault: false,\n\t\t\t}),\n\t\t),\n\t\tmultiline: Type.Optional(\n\t\t\tType.Boolean({\n\t\t\t\tdescription: \"Enable multiline matching (--multiline).\",\n\t\t\t\tdefault: false,\n\t\t\t}),\n\t\t),\n\t\tmaxResults: Type.Optional(\n\t\t\tType.Integer({\n\t\t\t\tdescription: \"Stop after this many matches (-m).\",\n\t\t\t\tminimum: 1,\n\t\t\t\tmaximum: 1000,\n\t\t\t}),\n\t\t),\n\t\tcontext: Type.Optional(\n\t\t\tType.Integer({\n\t\t\t\tdescription: \"Show this many lines of context before and after (-C).\",\n\t\t\t\tminimum: 0,\n\t\t\t\tmaximum: 20,\n\t\t\t}),\n\t\t),\n\t\tbeforeContext: Type.Optional(\n\t\t\tType.Integer({\n\t\t\t\tdescription: \"Show this many lines of context before each match (-B).\",\n\t\t\t\tminimum: 0,\n\t\t\t\tmaximum: 20,\n\t\t\t}),\n\t\t),\n\t\tafterContext: Type.Optional(\n\t\t\tType.Integer({\n\t\t\t\tdescription: \"Show this many lines of context after each match (-A).\",\n\t\t\t\tminimum: 0,\n\t\t\t\tmaximum: 20,\n\t\t\t}),\n\t\t),\n\t\tcwd: Type.Optional(\n\t\t\tType.String({\n\t\t\t\tdescription: \"Working directory to run ripgrep from\",\n\t\t\t\tminLength: 1,\n\t\t\t}),\n\t\t),\n\t\tincludeHidden: Type.Optional(\n\t\t\tType.Boolean({\n\t\t\t\tdescription: \"Include hidden files (--hidden)\",\n\t\t\t\tdefault: false,\n\t\t\t}),\n\t\t),\n\t\tuseGitIgnore: Type.Optional(\n\t\t\tType.Boolean({\n\t\t\t\tdescription: \"Respect .gitignore (set false to pass --no-ignore)\",\n\t\t\t\tdefault: true,\n\t\t\t}),\n\t\t),\n\t\toutputMode: Type.Optional(\n\t\t\tType.Union(\n\t\t\t\t[Type.Literal(\"content\"), Type.Literal(\"files\"), Type.Literal(\"count\")],\n\t\t\t\t{\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"Output mode: 'content' shows matching lines (default), 'files' lists only file paths, 'count' shows match counts per file.\",\n\t\t\t\t\tdefault: \"content\",\n\t\t\t\t},\n\t\t\t),\n\t\t),\n\t\tformat: Type.Optional(\n\t\t\tType.Union([Type.Literal(\"text\"), Type.Literal(\"json\")], {\n\t\t\t\tdescription:\n\t\t\t\t\t\"Output format for content mode. JSON not supported with files/count modes.\",\n\t\t\t\tdefault: \"text\",\n\t\t\t}),\n\t\t),\n\t\tinvertMatch: Type.Optional(\n\t\t\tType.Boolean({\n\t\t\t\tdescription:\n\t\t\t\t\t\"Show lines that do NOT match the pattern (--invert-match).\",\n\t\t\t\tdefault: false,\n\t\t\t}),\n\t\t),\n\t\tonlyMatching: Type.Optional(\n\t\t\tType.Boolean({\n\t\t\t\tdescription:\n\t\t\t\t\t\"Only show the matched text, not the entire line (--only-matching). Only works with content mode.\",\n\t\t\t\tdefault: false,\n\t\t\t}),\n\t\t),\n\t\theadLimit: Type.Optional(\n\t\t\tType.Integer({\n\t\t\t\tdescription:\n\t\t\t\t\t\"Limit output to first N lines/entries. Useful for sampling large result sets.\",\n\t\t\t\tminimum: 1,\n\t\t\t\tmaximum: 10000,\n\t\t\t}),\n\t\t),\n\t},\n\t{\n\t\tdescription:\n\t\t\t\"Use either context or before/after context options, not both.\",\n\t},\n);\n\nconst JSON_DETAIL_LIMIT = 200;\nconst DEFAULT_MAX_RESULTS = 500;\n\ntype SearchToolDetails = {\n\tcommand: string;\n\tcwd: string;\n\tformat?: \"text\" | \"json\" | \"files\" | \"count\";\n\tmatches?: RipgrepMatch[];\n\tfileCount?: number;\n\tfiles?: string[];\n\ttotalMatches?: number;\n\tcounts?: Array<{ file: string; count: number }>;\n\ttruncated?: boolean;\n};\n\nexport const searchTool = createTool<typeof searchSchema, SearchToolDetails>({\n\tname: \"search\",\n\tlabel: \"search\",\n\tdescription: `Find text across files using ripgrep with optional globbing and context controls.\n\nOutput modes (outputMode parameter):\n- \"content\": Show matching lines with file:line:content format (default)\n- \"files\": List only file paths containing matches (fast for finding files)\n- \"count\": Show match counts per file (useful for gauging scope)\n\nModifiers:\n- invertMatch: Show lines that do NOT match\n- onlyMatching: Show only the matched text (content mode only)\n- headLimit: Limit output to first N entries (useful for sampling)\n\nExamples:\n {pattern: \"TODO\", outputMode: \"files\"} → list files containing TODO\n {pattern: \"function\", outputMode: \"count\"} → count functions per file\n {pattern: \"^#\", invertMatch: true} → lines not starting with #`,\n\tschema: searchSchema,\n\tasync run(params, { signal, respond }) {\n\t\tconst {\n\t\t\tpattern,\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\toutputMode = \"content\",\n\t\t\tformat = \"text\",\n\t\t\tinvertMatch = false,\n\t\t\tonlyMatching = false,\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\t// Validate options incompatible with files/count modes\n\t\tif (outputMode !== \"content\" && onlyMatching) {\n\t\t\tthrow new Error(\n\t\t\t\t\"onlyMatching can only be used with outputMode: 'content'.\",\n\t\t\t);\n\t\t}\n\n\t\tif (\n\t\t\toutputMode !== \"content\" &&\n\t\t\t(context !== undefined ||\n\t\t\t\tbeforeContext !== undefined ||\n\t\t\t\tafterContext !== undefined)\n\t\t) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Context options can only be used with outputMode: 'content'.\",\n\t\t\t);\n\t\t}\n\n\t\tif (format === \"json\" && outputMode !== \"content\") {\n\t\t\tthrow new Error(\n\t\t\t\t\"JSON format is not supported with outputMode: 'files' or 'count'. Use format: 'text' or omit the format parameter.\",\n\t\t\t);\n\t\t}\n\n\t\tconst pathArgs = normalizeRipgrepPathArgs(toArray(paths));\n\t\tconst globArgs = toArray(glob);\n\t\tconst commandCwd = cwd ? resolvePath(expandUserPath(cwd)) : process.cwd();\n\n\t\tconst args: string[] = [\"--color=never\"];\n\n\t\t// Output mode flags\n\t\tif (outputMode === \"files\") {\n\t\t\targs.push(\"--files-with-matches\");\n\t\t} else if (outputMode === \"count\") {\n\t\t\t// Use --count-matches for actual match counts, -H to always show filename\n\t\t\targs.push(\"--count-matches\", \"-H\");\n\t\t} else {\n\t\t\t// content mode: show line numbers and filenames\n\t\t\targs.push(\"-n\", \"--with-filename\");\n\t\t}\n\n\t\tif (ignoreCase) {\n\t\t\targs.push(\"-i\");\n\t\t}\n\n\t\tif (literal) {\n\t\t\targs.push(\"--fixed-strings\");\n\t\t}\n\n\t\tif (word) {\n\t\t\targs.push(\"-w\");\n\t\t}\n\n\t\tif (multiline) {\n\t\t\targs.push(\"--multiline\");\n\t\t}\n\n\t\tif (includeHidden) {\n\t\t\targs.push(\"--hidden\");\n\t\t}\n\n\t\tif (!useGitIgnore) {\n\t\t\targs.push(\"--no-ignore\");\n\t\t}\n\n\t\tif (invertMatch) {\n\t\t\targs.push(\"--invert-match\");\n\t\t}\n\n\t\tif (onlyMatching) {\n\t\t\targs.push(\"--only-matching\");\n\t\t}\n\n\t\tconst shouldApplyMaxResults =\n\t\t\toutputMode === \"content\" || maxResults !== undefined;\n\t\tif (shouldApplyMaxResults) {\n\t\t\tconst effectiveMaxResults = maxResults ?? DEFAULT_MAX_RESULTS;\n\t\t\targs.push(\"-m\", String(effectiveMaxResults));\n\t\t}\n\n\t\tif (context !== undefined) {\n\t\t\targs.push(`-C${context}`);\n\t\t}\n\n\t\tif (beforeContext !== undefined) {\n\t\t\targs.push(`-B${beforeContext}`);\n\t\t}\n\n\t\tif (afterContext !== undefined) {\n\t\t\targs.push(`-A${afterContext}`);\n\t\t}\n\n\t\tfor (const globPattern of globArgs) {\n\t\t\targs.push(\"--glob\", globPattern);\n\t\t}\n\n\t\tif (format === \"json\" && outputMode === \"content\") {\n\t\t\targs.push(\"--json\");\n\t\t}\n\n\t\targs.push(\"--\", pattern);\n\n\t\tif (pathArgs.length > 0) {\n\t\t\targs.push(...pathArgs);\n\t\t} else {\n\t\t\targs.push(\".\");\n\t\t}\n\n\t\tconst command = formatRipgrepCommand(args);\n\t\tlet result: {\n\t\t\tstdout: string;\n\t\t\tstderr: string;\n\t\t\texitCode: number;\n\t\t\ttruncated: boolean;\n\t\t};\n\t\ttry {\n\t\t\tresult = await runRipgrep(args, signal, commandCwd);\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\n\t\t\t\t.error(`ripgrep failed\\n\\n${reason}`)\n\t\t\t\t.detail({ command, cwd: commandCwd });\n\t\t}\n\n\t\tif (result.exitCode === 2) {\n\t\t\tconst message = result.stderr.trim() || result.stdout.trim();\n\t\t\tif (isRipgrepPathError(message)) {\n\t\t\t\treturn respond\n\t\t\t\t\t.error(\n\t\t\t\t\t\t`ripgrep failed\\n\\n${message.length > 0 ? message : \"ripgrep path lookup failed\"}`,\n\t\t\t\t\t)\n\t\t\t\t\t.detail({ command, cwd: commandCwd });\n\t\t\t}\n\t\t\tthrow new Error(\n\t\t\t\tmessage.length > 0 ? message : \"ripgrep exited with an error\",\n\t\t\t);\n\t\t}\n\n\t\tif (result.exitCode === 1 || result.stdout.trim().length === 0) {\n\t\t\t// Use correct format in detail based on mode\n\t\t\tconst detailFormat =\n\t\t\t\toutputMode === \"files\"\n\t\t\t\t\t? \"files\"\n\t\t\t\t\t: outputMode === \"count\"\n\t\t\t\t\t\t? \"count\"\n\t\t\t\t\t\t: format;\n\t\t\treturn respond\n\t\t\t\t.text(\"No matches found.\")\n\t\t\t\t.detail({ command, cwd: commandCwd, format: detailFormat });\n\t\t}\n\n\t\tconst truncatedByBytes = result.truncated ?? false;\n\n\t\t// Handle files mode output\n\t\tif (outputMode === \"files\") {\n\t\t\tconst allFiles = result.stdout\n\t\t\t\t.trim()\n\t\t\t\t.split(\"\\n\")\n\t\t\t\t.filter((f) => f.length > 0);\n\t\t\tconst files =\n\t\t\t\theadLimit !== undefined ? allFiles.slice(0, headLimit) : allFiles;\n\t\t\tconst truncated = headLimit !== undefined && allFiles.length > headLimit;\n\t\t\tconst fileList = files.join(\"\\n\");\n\t\t\tconst truncatedNote = truncated\n\t\t\t\t? `\\n\\n... (showing ${files.length} of ${allFiles.length} files)`\n\t\t\t\t: truncatedByBytes\n\t\t\t\t\t? \"\\n\\n... (output truncated due to size limit)\"\n\t\t\t\t\t: \"\";\n\t\t\treturn respond\n\t\t\t\t.text(\n\t\t\t\t\t`Found ${allFiles.length} file(s) matching \"${pattern}\":\\n\\n${fileList}${truncatedNote}`,\n\t\t\t\t)\n\t\t\t\t.detail({\n\t\t\t\t\tcommand,\n\t\t\t\t\tcwd: commandCwd,\n\t\t\t\t\tformat: \"files\",\n\t\t\t\t\tfileCount: allFiles.length,\n\t\t\t\t\tfiles,\n\t\t\t\t\ttruncated: truncated || truncatedByBytes,\n\t\t\t\t});\n\t\t}\n\n\t\t// Handle count mode output\n\t\tif (outputMode === \"count\") {\n\t\t\tconst lines = result.stdout\n\t\t\t\t.trim()\n\t\t\t\t.split(\"\\n\")\n\t\t\t\t.filter((l) => l.length > 0);\n\t\t\tconst allCounts: Array<{ file: string; count: number }> = [];\n\t\t\tlet totalMatches = 0;\n\t\t\t// Use regex to parse \"filename:count\" format robustly\n\t\t\t// This handles Windows paths (C:\\path\\file.txt:5) and colons in filenames\n\t\t\tconst countLineRegex = /^(.+):(\\d+)$/;\n\t\t\tfor (const line of lines) {\n\t\t\t\tconst match = line.match(countLineRegex);\n\t\t\t\tif (match) {\n\t\t\t\t\tconst file = match[1]!;\n\t\t\t\t\tconst matchCount = Number.parseInt(match[2]!, 10);\n\t\t\t\t\tallCounts.push({ file, count: matchCount });\n\t\t\t\t\ttotalMatches += matchCount;\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst counts =\n\t\t\t\theadLimit !== undefined ? allCounts.slice(0, headLimit) : allCounts;\n\t\t\tconst truncated = headLimit !== undefined && allCounts.length > headLimit;\n\t\t\tconst summary = counts.map((c) => `${c.file}: ${c.count}`).join(\"\\n\");\n\t\t\tconst truncatedNote = truncated\n\t\t\t\t? `\\n\\n... (showing ${counts.length} of ${allCounts.length} files)`\n\t\t\t\t: truncatedByBytes\n\t\t\t\t\t? \"\\n\\n... (output truncated due to size limit)\"\n\t\t\t\t\t: \"\";\n\t\t\treturn respond\n\t\t\t\t.text(\n\t\t\t\t\t`Found ${totalMatches} match(es) across ${allCounts.length} file(s):\\n\\n${summary}${truncatedNote}`,\n\t\t\t\t)\n\t\t\t\t.detail({\n\t\t\t\t\tcommand,\n\t\t\t\t\tcwd: commandCwd,\n\t\t\t\t\tformat: \"count\",\n\t\t\t\t\ttotalMatches,\n\t\t\t\t\tfileCount: allCounts.length,\n\t\t\t\t\tcounts,\n\t\t\t\t\ttruncated: truncated || truncatedByBytes,\n\t\t\t\t});\n\t\t}\n\n\t\t// Handle JSON format\n\t\tif (format === \"json\") {\n\t\t\tconst allMatches = parseRipgrepJson(result.stdout);\n\t\t\tconst matches =\n\t\t\t\theadLimit !== undefined ? allMatches.slice(0, headLimit) : allMatches;\n\t\t\tconst headLimitTruncated =\n\t\t\t\theadLimit !== undefined && allMatches.length > headLimit;\n\t\t\tconst detailLimitTruncated = matches.length > JSON_DETAIL_LIMIT;\n\t\t\tconst truncated =\n\t\t\t\theadLimitTruncated || detailLimitTruncated || truncatedByBytes;\n\t\t\tconst preview = matches\n\t\t\t\t.slice(0, 5)\n\t\t\t\t.map(\n\t\t\t\t\t(match) =>\n\t\t\t\t\t\t`${match.file}:${match.line}:${match.column} ${match.match.trim()}`,\n\t\t\t\t)\n\t\t\t\t.join(\"\\n\");\n\t\t\tconst suffix =\n\t\t\t\tmatches.length > 5 ? `\\n... (${matches.length - 5} more matches)` : \"\";\n\t\t\tconst truncatedNote = headLimitTruncated\n\t\t\t\t? `\\n(showing ${matches.length} of ${allMatches.length} total matches)`\n\t\t\t\t: \"\";\n\t\t\tconst text = matches.length\n\t\t\t\t? `Found ${allMatches.length} match(es).${truncatedNote}\\n\\n${preview}${suffix}`\n\t\t\t\t: \"No matches found.\";\n\t\t\treturn respond.text(text).detail({\n\t\t\t\tcommand,\n\t\t\t\tcwd: commandCwd,\n\t\t\t\tformat,\n\t\t\t\tmatches: matches.slice(0, JSON_DETAIL_LIMIT),\n\t\t\t\ttruncated,\n\t\t\t});\n\t\t}\n\n\t\t// Handle text format (content mode)\n\t\tconst lines = result.stdout.trimEnd().split(\"\\n\");\n\t\tconst outputLines =\n\t\t\theadLimit !== undefined ? lines.slice(0, headLimit) : lines;\n\t\tconst truncated = headLimit !== undefined && lines.length > headLimit;\n\t\tconst truncatedNote = truncated\n\t\t\t? `\\n\\n... (showing ${outputLines.length} of ${lines.length} lines)`\n\t\t\t: truncatedByBytes\n\t\t\t\t? \"\\n\\n... (output truncated due to size limit)\"\n\t\t\t\t: \"\";\n\t\treturn respond.text(outputLines.join(\"\\n\") + truncatedNote).detail({\n\t\t\tcommand,\n\t\t\tcwd: commandCwd,\n\t\t\tformat,\n\t\t\ttruncated: truncated || truncatedByBytes,\n\t\t});\n\t},\n});\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"document-extractor.d.ts","sourceRoot":"","sources":["../../src/utils/document-extractor.ts"],"names":[],"mappings":"AASA,MAAM,MAAM,uBAAuB,GAChC,KAAK,GACL,MAAM,GACN,MAAM,GACN,MAAM,GACN,MAAM,GACN,SAAS,CAAC;AAEb,MAAM,WAAW,oBAAoB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,qBAAqB;IACrC,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,uBAAuB,CAAC;IAChC,SAAS,EAAE,QAAQ,GAAG,YAAY,CAAC;IACnC,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CAClB;AA0ZD,wBAAsB,mBAAmB,CACxC,KAAK,EAAE,oBAAoB,GACzB,OAAO,CAAC,qBAAqB,CAAC,CAsGhC"}
1
+ {"version":3,"file":"document-extractor.d.ts","sourceRoot":"","sources":["../../src/utils/document-extractor.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,uBAAuB,GAChC,KAAK,GACL,MAAM,GACN,MAAM,GACN,MAAM,GACN,MAAM,GACN,SAAS,CAAC;AAEb,MAAM,WAAW,oBAAoB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,qBAAqB;IACrC,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,uBAAuB,CAAC;IAChC,SAAS,EAAE,QAAQ,GAAG,YAAY,CAAC;IACnC,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CAClB;AAoaD,wBAAsB,mBAAmB,CACxC,KAAK,EAAE,oBAAoB,GACzB,OAAO,CAAC,qBAAqB,CAAC,CAuGhC"}
@@ -5,7 +5,6 @@ import { extname, join } from "node:path";
5
5
  import ExcelJS from "exceljs";
6
6
  import JSZip from "jszip";
7
7
  import mammoth from "mammoth";
8
- import { PDFParse } from "pdf-parse";
9
8
  const DEFAULT_MAX_CHARS = 200_000;
10
9
  const MAX_INPUT_BYTES = 50 * 1024 * 1024;
11
10
  const MARKITDOWN_TIMEOUT_MS = 20_000;
@@ -13,6 +12,13 @@ const MARKITDOWN_TIMEOUT_KILL_GRACE_MS = 500;
13
12
  const MARKITDOWN_TIMEOUT_CLOSE_GRACE_MS = 1_000;
14
13
  const NODE_TIMER_MAX_MS = 2_147_483_647;
15
14
  const XLSX_MIME = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
15
+ let cachedPDFParse;
16
+ async function loadPDFParse() {
17
+ if (!cachedPDFParse) {
18
+ ({ PDFParse: cachedPDFParse } = await import("pdf-parse"));
19
+ }
20
+ return cachedPDFParse;
21
+ }
16
22
  function clampText(text, maxChars) {
17
23
  if (text.length <= maxChars)
18
24
  return { text, truncated: false };
@@ -373,6 +379,7 @@ export async function extractDocumentText(input) {
373
379
  if (!extractedText) {
374
380
  switch (format) {
375
381
  case "pdf": {
382
+ const PDFParse = await loadPDFParse();
376
383
  const parser = new PDFParse({ data: buffer });
377
384
  try {
378
385
  const result = await parser.getText();
@@ -1 +1 @@
1
- {"version":3,"file":"document-extractor.js","sourceRoot":"","sources":["../../src/utils/document-extractor.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn } from \"node:child_process\";\nimport { mkdtemp, rm, writeFile } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { extname, join } from \"node:path\";\nimport ExcelJS from \"exceljs\";\nimport JSZip from \"jszip\";\nimport mammoth from \"mammoth\";\nimport { PDFParse } from \"pdf-parse\";\n\nexport type ExtractedDocumentFormat =\n\t| \"pdf\"\n\t| \"docx\"\n\t| \"xlsx\"\n\t| \"pptx\"\n\t| \"text\"\n\t| \"unknown\";\n\nexport interface ExtractDocumentInput {\n\tbuffer: Buffer;\n\tfileName: string;\n\tmimeType?: string;\n\tmaxChars?: number;\n}\n\nexport interface ExtractDocumentOutput {\n\textractedText: string;\n\tformat: ExtractedDocumentFormat;\n\textractor: \"native\" | \"markitdown\";\n\ttruncated: boolean;\n\tsizeBytes: number;\n}\n\ntype ExcelWorkbookLoadInput = Parameters<ExcelJS.Workbook[\"xlsx\"][\"load\"]>[0];\n\nconst DEFAULT_MAX_CHARS = 200_000;\nconst MAX_INPUT_BYTES = 50 * 1024 * 1024;\nconst MARKITDOWN_TIMEOUT_MS = 20_000;\nconst MARKITDOWN_TIMEOUT_KILL_GRACE_MS = 500;\nconst MARKITDOWN_TIMEOUT_CLOSE_GRACE_MS = 1_000;\nconst NODE_TIMER_MAX_MS = 2_147_483_647;\nconst XLSX_MIME =\n\t\"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\";\n\nfunction clampText(\n\ttext: string,\n\tmaxChars: number,\n): { text: string; truncated: boolean } {\n\tif (text.length <= maxChars) return { text, truncated: false };\n\treturn { text: text.slice(0, maxChars), truncated: true };\n}\n\nfunction detectFormat(\n\tfileName: string,\n\tmimeType?: string,\n): ExtractedDocumentFormat {\n\tconst lowerName = fileName.toLowerCase();\n\tconst type = (mimeType || \"\").toLowerCase();\n\n\tif (type === \"application/pdf\" || lowerName.endsWith(\".pdf\")) return \"pdf\";\n\tif (\n\t\ttype ===\n\t\t\t\"application/vnd.openxmlformats-officedocument.wordprocessingml.document\" ||\n\t\tlowerName.endsWith(\".docx\")\n\t)\n\t\treturn \"docx\";\n\tif (type === XLSX_MIME || lowerName.endsWith(\".xlsx\")) return \"xlsx\";\n\tif (\n\t\ttype ===\n\t\t\t\"application/vnd.openxmlformats-officedocument.presentationml.presentation\" ||\n\t\tlowerName.endsWith(\".pptx\")\n\t)\n\t\treturn \"pptx\";\n\tif (type.startsWith(\"text/\")) return \"text\";\n\n\tconst textExtensions = [\n\t\t\".txt\",\n\t\t\".md\",\n\t\t\".markdown\",\n\t\t\".json\",\n\t\t\".yaml\",\n\t\t\".yml\",\n\t\t\".csv\",\n\t\t\".ts\",\n\t\t\".tsx\",\n\t\t\".js\",\n\t\t\".jsx\",\n\t\t\".html\",\n\t\t\".css\",\n\t\t\".xml\",\n\t];\n\tif (textExtensions.some((ext) => lowerName.endsWith(ext))) return \"text\";\n\n\treturn \"unknown\";\n}\n\nfunction splitCommandArgs(value: string | undefined): string[] {\n\tconst input = value?.trim() ?? \"\";\n\tif (!input) return [];\n\n\tconst args: string[] = [];\n\tlet current = \"\";\n\tlet quote: \"'\" | '\"' | null = null;\n\tlet tokenStarted = false;\n\n\tfor (let index = 0; index < input.length; index += 1) {\n\t\tconst char = input.charAt(index);\n\n\t\tif (quote === \"'\") {\n\t\t\tif (char === \"'\") {\n\t\t\t\tquote = null;\n\t\t\t} else {\n\t\t\t\tcurrent += char;\n\t\t\t}\n\t\t\ttokenStarted = true;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (quote === '\"') {\n\t\t\tif (char === '\"') {\n\t\t\t\tquote = null;\n\t\t\t\ttokenStarted = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (char === \"\\\\\") {\n\t\t\t\tconst next = input[index + 1];\n\t\t\t\tif (next && ['\"', \"\\\\\", \"$\", \"`\", \"\\n\"].includes(next)) {\n\t\t\t\t\tcurrent += next;\n\t\t\t\t\tindex += 1;\n\t\t\t\t} else {\n\t\t\t\t\tcurrent += char;\n\t\t\t\t}\n\t\t\t\ttokenStarted = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tcurrent += char;\n\t\t\ttokenStarted = true;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (char === \"\\\\\") {\n\t\t\tconst next = input[index + 1];\n\t\t\tif (next && (/\\s/u.test(next) || [\"'\", '\"', \"\\\\\"].includes(next))) {\n\t\t\t\tcurrent += next;\n\t\t\t\tindex += 1;\n\t\t\t} else {\n\t\t\t\tcurrent += char;\n\t\t\t}\n\t\t\ttokenStarted = true;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (char === \"'\" || char === '\"') {\n\t\t\tquote = char;\n\t\t\ttokenStarted = true;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (/\\s/u.test(char)) {\n\t\t\tif (tokenStarted) {\n\t\t\t\targs.push(current);\n\t\t\t\tcurrent = \"\";\n\t\t\t\ttokenStarted = false;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tcurrent += char;\n\t\ttokenStarted = true;\n\t}\n\n\tif (quote) {\n\t\tthrow new Error(\"Unterminated quote in MAESTRO_MARKITDOWN_ARGS\");\n\t}\n\tif (tokenStarted) {\n\t\targs.push(current);\n\t}\n\treturn args;\n}\n\nfunction isMarkitdownDisabled(): boolean {\n\treturn /^(0|false|off|no)$/i.test(process.env.MAESTRO_MARKITDOWN ?? \"\");\n}\n\nfunction markitdownCandidates(): Array<{\n\tcommand: string;\n\targsPrefix: string[];\n}> {\n\tconst configured = process.env.MAESTRO_MARKITDOWN_CMD?.trim();\n\tif (configured) {\n\t\treturn [\n\t\t\t{\n\t\t\t\tcommand: configured,\n\t\t\t\targsPrefix: splitCommandArgs(process.env.MAESTRO_MARKITDOWN_ARGS),\n\t\t\t},\n\t\t];\n\t}\n\treturn [\n\t\t{ command: \"markitdown\", argsPrefix: [] },\n\t\t{ command: \"uvx\", argsPrefix: [\"markitdown\"] },\n\t];\n}\n\nfunction shouldTryMarkitdown(\n\tformat: ExtractedDocumentFormat,\n\tfileName: string,\n\tmimeType?: string,\n): boolean {\n\tif (isMarkitdownDisabled()) return false;\n\tif (/^(1|true|on|yes)$/i.test(process.env.MAESTRO_MARKITDOWN_PREFER ?? \"\")) {\n\t\treturn true;\n\t}\n\tconst lowerName = fileName.toLowerCase();\n\tconst type = (mimeType ?? \"\").toLowerCase();\n\tif (format === \"unknown\") return true;\n\tif (lowerName.endsWith(\".html\") || lowerName.endsWith(\".htm\")) return true;\n\tif (type.includes(\"text/html\")) return true;\n\treturn false;\n}\n\nfunction readPositiveIntegerEnv(name: string, fallback: number): number {\n\tconst value = process.env[name]?.trim();\n\tif (!value) return fallback;\n\tconst parsed = Number(value);\n\tif (!Number.isFinite(parsed) || !Number.isInteger(parsed) || parsed <= 0) {\n\t\treturn fallback;\n\t}\n\treturn Math.min(parsed, NODE_TIMER_MAX_MS);\n}\n\nfunction signalMarkitdownProcessTree(\n\tchild: ReturnType<typeof spawn>,\n\tsignal: NodeJS.Signals,\n): void {\n\tif (process.platform !== \"win32\" && child.pid) {\n\t\ttry {\n\t\t\tprocess.kill(-child.pid, signal);\n\t\t\treturn;\n\t\t} catch (error) {\n\t\t\tif ((error as NodeJS.ErrnoException).code === \"ESRCH\") {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\ttry {\n\t\tchild.kill(signal);\n\t} catch {\n\t\t// The process may have exited between timeout handling and signal delivery.\n\t}\n}\n\nfunction runMarkitdownCandidate(\n\tcandidate: { command: string; argsPrefix: string[] },\n\targs: string[],\n): Promise<string> {\n\treturn new Promise((resolve, reject) => {\n\t\tconst child = spawn(candidate.command, [...candidate.argsPrefix, ...args], {\n\t\t\tdetached: process.platform !== \"win32\",\n\t\t\tstdio: [\"ignore\", \"pipe\", \"pipe\"],\n\t\t});\n\t\tlet stdout = \"\";\n\t\tlet stderr = \"\";\n\t\tlet timedOut = false;\n\t\tlet settled = false;\n\t\tlet killTimer: NodeJS.Timeout | undefined;\n\t\tlet closeGraceTimer: NodeJS.Timeout | undefined;\n\t\tconst timer = setTimeout(\n\t\t\t() => {\n\t\t\t\ttimedOut = true;\n\t\t\t\tsignalMarkitdownProcessTree(child, \"SIGTERM\");\n\t\t\t\tkillTimer = setTimeout(\n\t\t\t\t\t() => {\n\t\t\t\t\t\tsignalMarkitdownProcessTree(child, \"SIGKILL\");\n\t\t\t\t\t\tcloseGraceTimer = setTimeout(\n\t\t\t\t\t\t\t() => {\n\t\t\t\t\t\t\t\tchild.stdout.destroy();\n\t\t\t\t\t\t\t\tchild.stderr.destroy();\n\t\t\t\t\t\t\t\tchild.unref();\n\t\t\t\t\t\t\t\tfinish(new Error(\"MarkItDown conversion timed out\"));\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\treadPositiveIntegerEnv(\n\t\t\t\t\t\t\t\t\"MAESTRO_MARKITDOWN_CLOSE_GRACE_MS\",\n\t\t\t\t\t\t\t\tMARKITDOWN_TIMEOUT_CLOSE_GRACE_MS,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t);\n\t\t\t\t\t},\n\t\t\t\t\treadPositiveIntegerEnv(\n\t\t\t\t\t\t\"MAESTRO_MARKITDOWN_KILL_GRACE_MS\",\n\t\t\t\t\t\tMARKITDOWN_TIMEOUT_KILL_GRACE_MS,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t},\n\t\t\treadPositiveIntegerEnv(\n\t\t\t\t\"MAESTRO_MARKITDOWN_TIMEOUT_MS\",\n\t\t\t\tMARKITDOWN_TIMEOUT_MS,\n\t\t\t),\n\t\t);\n\n\t\tfunction finish(error: Error | null, output?: string) {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tclearTimeout(timer);\n\t\t\tif (killTimer) clearTimeout(killTimer);\n\t\t\tif (closeGraceTimer) clearTimeout(closeGraceTimer);\n\t\t\tif (error) {\n\t\t\t\treject(error);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tresolve(output ?? \"\");\n\t\t}\n\n\t\tchild.stdout.setEncoding(\"utf8\");\n\t\tchild.stderr.setEncoding(\"utf8\");\n\t\tchild.stdout.on(\"data\", (chunk) => {\n\t\t\tstdout += chunk;\n\t\t});\n\t\tchild.stderr.on(\"data\", (chunk) => {\n\t\t\tstderr += chunk;\n\t\t});\n\t\tchild.on(\"error\", (error) => {\n\t\t\tif (timedOut) {\n\t\t\t\tfinish(new Error(\"MarkItDown conversion timed out\"));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tfinish(error);\n\t\t});\n\t\tchild.on(\"close\", (code) => {\n\t\t\tif (timedOut) {\n\t\t\t\tfinish(new Error(\"MarkItDown conversion timed out\"));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (code === 0) {\n\t\t\t\tfinish(null, stdout);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tfinish(\n\t\t\t\tnew Error(\n\t\t\t\t\t`MarkItDown exited with ${code}${stderr ? `: ${stderr.slice(0, 500)}` : \"\"}`,\n\t\t\t\t),\n\t\t\t);\n\t\t});\n\t});\n}\n\nasync function extractWithMarkitdown(input: {\n\tbuffer: Buffer;\n\tfileName: string;\n\tmimeType?: string;\n}): Promise<string | null> {\n\tconst tempDir = await mkdtemp(join(tmpdir(), \"maestro-markitdown-\"));\n\tconst extension = extname(input.fileName) || \".bin\";\n\tconst tempPath = join(tempDir, `input${extension}`);\n\ttry {\n\t\tawait writeFile(tempPath, input.buffer);\n\t\tconst args = [tempPath];\n\t\tif (input.mimeType) {\n\t\t\targs.push(\"--mime-type\", input.mimeType);\n\t\t}\n\n\t\tlet lastError: unknown;\n\t\tfor (const candidate of markitdownCandidates()) {\n\t\t\ttry {\n\t\t\t\tconst output = await runMarkitdownCandidate(candidate, args);\n\t\t\t\tconst text = output.trim();\n\t\t\t\tif (text) return text;\n\t\t\t} catch (error) {\n\t\t\t\tlastError = error;\n\t\t\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") continue;\n\t\t\t}\n\t\t}\n\n\t\tif (process.env.MAESTRO_MARKITDOWN_CMD) {\n\t\t\tconst message =\n\t\t\t\tlastError instanceof Error ? lastError.message : String(lastError);\n\t\t\tthrow new Error(`MarkItDown extraction failed: ${message}`);\n\t\t}\n\t\treturn null;\n\t} finally {\n\t\tawait rm(tempDir, { force: true, recursive: true });\n\t}\n}\n\nfunction worksheetToRows(worksheet: ExcelJS.Worksheet): string[][] {\n\tconst rows: string[][] = [];\n\tworksheet.eachRow({ includeEmpty: false }, (row) => {\n\t\tconst cells: string[] = [];\n\t\tfor (let column = 1; column <= row.cellCount; column++) {\n\t\t\tcells.push((row.getCell(column).text || \"\").trim());\n\t\t}\n\t\twhile (cells.length > 0 && cells[cells.length - 1] === \"\") {\n\t\t\tcells.pop();\n\t\t}\n\t\tif (cells.some((value) => value !== \"\")) {\n\t\t\trows.push(cells);\n\t\t}\n\t});\n\treturn rows;\n}\n\nasync function extractPptxText(buffer: Buffer): Promise<string> {\n\tconst zip = await JSZip.loadAsync(buffer);\n\n\tconst slidePaths = Object.keys(zip.files)\n\t\t.filter((p) => /^ppt\\/slides\\/slide\\d+\\.xml$/i.test(p))\n\t\t.sort((a, b) => {\n\t\t\tconst an = Number.parseInt(a.match(/slide(\\d+)\\.xml/i)?.[1] || \"0\", 10);\n\t\t\tconst bn = Number.parseInt(b.match(/slide(\\d+)\\.xml/i)?.[1] || \"0\", 10);\n\t\t\treturn an - bn;\n\t\t});\n\n\tif (slidePaths.length === 0) {\n\t\treturn \"\";\n\t}\n\n\tconst parts: string[] = [];\n\tfor (const slidePath of slidePaths) {\n\t\tconst slideNumber = slidePath.match(/slide(\\d+)\\.xml/i)?.[1] || \"?\";\n\t\tconst xml = await zip.file(slidePath)?.async(\"string\");\n\t\tif (!xml) continue;\n\n\t\tconst texts = Array.from(xml.matchAll(/<a:t>(.*?)<\\/a:t>/g))\n\t\t\t.map((m) => m[1] || \"\")\n\t\t\t.map((s) =>\n\t\t\t\ts\n\t\t\t\t\t.replaceAll(\"&lt;\", \"<\")\n\t\t\t\t\t.replaceAll(\"&gt;\", \">\")\n\t\t\t\t\t.replaceAll(\"&amp;\", \"&\")\n\t\t\t\t\t.replaceAll(\"&quot;\", '\"')\n\t\t\t\t\t.replaceAll(\"&apos;\", \"'\"),\n\t\t\t)\n\t\t\t.map((s) => s.trim())\n\t\t\t.filter(Boolean);\n\n\t\tif (texts.length === 0) continue;\n\t\tparts.push(`# Slide ${slideNumber}\\n${texts.join(\" \")}`);\n\t}\n\n\treturn parts.join(\"\\n\\n\");\n}\n\nexport async function extractDocumentText(\n\tinput: ExtractDocumentInput,\n): Promise<ExtractDocumentOutput> {\n\tconst { buffer, fileName } = input;\n\tconst maxChars = Math.max(1, input.maxChars ?? DEFAULT_MAX_CHARS);\n\n\tif (buffer.byteLength > MAX_INPUT_BYTES) {\n\t\tthrow new Error(\n\t\t\t`Document is too large (${(buffer.byteLength / 1024 / 1024).toFixed(1)}MB). Maximum supported size is 50MB.`,\n\t\t);\n\t}\n\n\tconst format = detectFormat(fileName, input.mimeType);\n\tconst markitdownFirst =\n\t\t/^(1|true|on|yes)$/i.test(process.env.MAESTRO_MARKITDOWN_PREFER ?? \"\") &&\n\t\t!isMarkitdownDisabled();\n\n\tlet extractedText = \"\";\n\tlet extractor: ExtractDocumentOutput[\"extractor\"] = \"native\";\n\tif (markitdownFirst) {\n\t\tconst markitdownText = await extractWithMarkitdown({\n\t\t\tbuffer,\n\t\t\tfileName,\n\t\t\tmimeType: input.mimeType,\n\t\t});\n\t\tif (markitdownText) {\n\t\t\textractedText = markitdownText;\n\t\t\textractor = \"markitdown\";\n\t\t}\n\t}\n\n\tif (!extractedText) {\n\t\tswitch (format) {\n\t\t\tcase \"pdf\": {\n\t\t\t\tconst parser = new PDFParse({ data: buffer });\n\t\t\t\ttry {\n\t\t\t\t\tconst result = await parser.getText();\n\t\t\t\t\textractedText = result.text || \"\";\n\t\t\t\t} finally {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait parser.destroy();\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// ignore\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"docx\": {\n\t\t\t\tconst result = await mammoth.extractRawText({ buffer });\n\t\t\t\textractedText = result.value || \"\";\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"xlsx\": {\n\t\t\t\tconst workbook = new ExcelJS.Workbook();\n\t\t\t\tawait workbook.xlsx.load(buffer as unknown as ExcelWorkbookLoadInput);\n\t\t\t\tconst parts: string[] = [];\n\t\t\t\tfor (const worksheet of workbook.worksheets) {\n\t\t\t\t\tconst rows = worksheetToRows(worksheet);\n\t\t\t\t\tif (rows.length === 0) continue;\n\t\t\t\t\tparts.push(\n\t\t\t\t\t\t`# Sheet: ${worksheet.name}\\n${rows.map((row) => row.join(\"\\t\")).join(\"\\n\")}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\textractedText = parts.join(\"\\n\\n\");\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"pptx\": {\n\t\t\t\textractedText = await extractPptxText(buffer);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"text\": {\n\t\t\t\textractedText = buffer.toString(\"utf8\");\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault: {\n\t\t\t\textractedText = \"\";\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (\n\t\textractor !== \"markitdown\" &&\n\t\tshouldTryMarkitdown(format, fileName, input.mimeType)\n\t) {\n\t\tconst markitdownText = await extractWithMarkitdown({\n\t\t\tbuffer,\n\t\t\tfileName,\n\t\t\tmimeType: input.mimeType,\n\t\t});\n\t\tif (markitdownText) {\n\t\t\textractedText = markitdownText;\n\t\t\textractor = \"markitdown\";\n\t\t}\n\t}\n\n\tconst { text, truncated } = clampText(extractedText, maxChars);\n\treturn {\n\t\textractedText: text,\n\t\tformat,\n\t\textractor,\n\t\ttruncated,\n\t\tsizeBytes: buffer.byteLength,\n\t};\n}\n"]}
1
+ {"version":3,"file":"document-extractor.js","sourceRoot":"","sources":["../../src/utils/document-extractor.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn } from \"node:child_process\";\nimport { mkdtemp, rm, writeFile } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { extname, join } from \"node:path\";\nimport ExcelJS from \"exceljs\";\nimport JSZip from \"jszip\";\nimport mammoth from \"mammoth\";\n\nexport type ExtractedDocumentFormat =\n\t| \"pdf\"\n\t| \"docx\"\n\t| \"xlsx\"\n\t| \"pptx\"\n\t| \"text\"\n\t| \"unknown\";\n\nexport interface ExtractDocumentInput {\n\tbuffer: Buffer;\n\tfileName: string;\n\tmimeType?: string;\n\tmaxChars?: number;\n}\n\nexport interface ExtractDocumentOutput {\n\textractedText: string;\n\tformat: ExtractedDocumentFormat;\n\textractor: \"native\" | \"markitdown\";\n\ttruncated: boolean;\n\tsizeBytes: number;\n}\n\ntype ExcelWorkbookLoadInput = Parameters<ExcelJS.Workbook[\"xlsx\"][\"load\"]>[0];\ntype PDFParseConstructor = typeof import(\"pdf-parse\").PDFParse;\n\nconst DEFAULT_MAX_CHARS = 200_000;\nconst MAX_INPUT_BYTES = 50 * 1024 * 1024;\nconst MARKITDOWN_TIMEOUT_MS = 20_000;\nconst MARKITDOWN_TIMEOUT_KILL_GRACE_MS = 500;\nconst MARKITDOWN_TIMEOUT_CLOSE_GRACE_MS = 1_000;\nconst NODE_TIMER_MAX_MS = 2_147_483_647;\nconst XLSX_MIME =\n\t\"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\";\n\nlet cachedPDFParse: PDFParseConstructor | undefined;\n\nasync function loadPDFParse(): Promise<PDFParseConstructor> {\n\tif (!cachedPDFParse) {\n\t\t({ PDFParse: cachedPDFParse } = await import(\"pdf-parse\"));\n\t}\n\treturn cachedPDFParse;\n}\n\nfunction clampText(\n\ttext: string,\n\tmaxChars: number,\n): { text: string; truncated: boolean } {\n\tif (text.length <= maxChars) return { text, truncated: false };\n\treturn { text: text.slice(0, maxChars), truncated: true };\n}\n\nfunction detectFormat(\n\tfileName: string,\n\tmimeType?: string,\n): ExtractedDocumentFormat {\n\tconst lowerName = fileName.toLowerCase();\n\tconst type = (mimeType || \"\").toLowerCase();\n\n\tif (type === \"application/pdf\" || lowerName.endsWith(\".pdf\")) return \"pdf\";\n\tif (\n\t\ttype ===\n\t\t\t\"application/vnd.openxmlformats-officedocument.wordprocessingml.document\" ||\n\t\tlowerName.endsWith(\".docx\")\n\t)\n\t\treturn \"docx\";\n\tif (type === XLSX_MIME || lowerName.endsWith(\".xlsx\")) return \"xlsx\";\n\tif (\n\t\ttype ===\n\t\t\t\"application/vnd.openxmlformats-officedocument.presentationml.presentation\" ||\n\t\tlowerName.endsWith(\".pptx\")\n\t)\n\t\treturn \"pptx\";\n\tif (type.startsWith(\"text/\")) return \"text\";\n\n\tconst textExtensions = [\n\t\t\".txt\",\n\t\t\".md\",\n\t\t\".markdown\",\n\t\t\".json\",\n\t\t\".yaml\",\n\t\t\".yml\",\n\t\t\".csv\",\n\t\t\".ts\",\n\t\t\".tsx\",\n\t\t\".js\",\n\t\t\".jsx\",\n\t\t\".html\",\n\t\t\".css\",\n\t\t\".xml\",\n\t];\n\tif (textExtensions.some((ext) => lowerName.endsWith(ext))) return \"text\";\n\n\treturn \"unknown\";\n}\n\nfunction splitCommandArgs(value: string | undefined): string[] {\n\tconst input = value?.trim() ?? \"\";\n\tif (!input) return [];\n\n\tconst args: string[] = [];\n\tlet current = \"\";\n\tlet quote: \"'\" | '\"' | null = null;\n\tlet tokenStarted = false;\n\n\tfor (let index = 0; index < input.length; index += 1) {\n\t\tconst char = input.charAt(index);\n\n\t\tif (quote === \"'\") {\n\t\t\tif (char === \"'\") {\n\t\t\t\tquote = null;\n\t\t\t} else {\n\t\t\t\tcurrent += char;\n\t\t\t}\n\t\t\ttokenStarted = true;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (quote === '\"') {\n\t\t\tif (char === '\"') {\n\t\t\t\tquote = null;\n\t\t\t\ttokenStarted = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (char === \"\\\\\") {\n\t\t\t\tconst next = input[index + 1];\n\t\t\t\tif (next && ['\"', \"\\\\\", \"$\", \"`\", \"\\n\"].includes(next)) {\n\t\t\t\t\tcurrent += next;\n\t\t\t\t\tindex += 1;\n\t\t\t\t} else {\n\t\t\t\t\tcurrent += char;\n\t\t\t\t}\n\t\t\t\ttokenStarted = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tcurrent += char;\n\t\t\ttokenStarted = true;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (char === \"\\\\\") {\n\t\t\tconst next = input[index + 1];\n\t\t\tif (next && (/\\s/u.test(next) || [\"'\", '\"', \"\\\\\"].includes(next))) {\n\t\t\t\tcurrent += next;\n\t\t\t\tindex += 1;\n\t\t\t} else {\n\t\t\t\tcurrent += char;\n\t\t\t}\n\t\t\ttokenStarted = true;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (char === \"'\" || char === '\"') {\n\t\t\tquote = char;\n\t\t\ttokenStarted = true;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (/\\s/u.test(char)) {\n\t\t\tif (tokenStarted) {\n\t\t\t\targs.push(current);\n\t\t\t\tcurrent = \"\";\n\t\t\t\ttokenStarted = false;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tcurrent += char;\n\t\ttokenStarted = true;\n\t}\n\n\tif (quote) {\n\t\tthrow new Error(\"Unterminated quote in MAESTRO_MARKITDOWN_ARGS\");\n\t}\n\tif (tokenStarted) {\n\t\targs.push(current);\n\t}\n\treturn args;\n}\n\nfunction isMarkitdownDisabled(): boolean {\n\treturn /^(0|false|off|no)$/i.test(process.env.MAESTRO_MARKITDOWN ?? \"\");\n}\n\nfunction markitdownCandidates(): Array<{\n\tcommand: string;\n\targsPrefix: string[];\n}> {\n\tconst configured = process.env.MAESTRO_MARKITDOWN_CMD?.trim();\n\tif (configured) {\n\t\treturn [\n\t\t\t{\n\t\t\t\tcommand: configured,\n\t\t\t\targsPrefix: splitCommandArgs(process.env.MAESTRO_MARKITDOWN_ARGS),\n\t\t\t},\n\t\t];\n\t}\n\treturn [\n\t\t{ command: \"markitdown\", argsPrefix: [] },\n\t\t{ command: \"uvx\", argsPrefix: [\"markitdown\"] },\n\t];\n}\n\nfunction shouldTryMarkitdown(\n\tformat: ExtractedDocumentFormat,\n\tfileName: string,\n\tmimeType?: string,\n): boolean {\n\tif (isMarkitdownDisabled()) return false;\n\tif (/^(1|true|on|yes)$/i.test(process.env.MAESTRO_MARKITDOWN_PREFER ?? \"\")) {\n\t\treturn true;\n\t}\n\tconst lowerName = fileName.toLowerCase();\n\tconst type = (mimeType ?? \"\").toLowerCase();\n\tif (format === \"unknown\") return true;\n\tif (lowerName.endsWith(\".html\") || lowerName.endsWith(\".htm\")) return true;\n\tif (type.includes(\"text/html\")) return true;\n\treturn false;\n}\n\nfunction readPositiveIntegerEnv(name: string, fallback: number): number {\n\tconst value = process.env[name]?.trim();\n\tif (!value) return fallback;\n\tconst parsed = Number(value);\n\tif (!Number.isFinite(parsed) || !Number.isInteger(parsed) || parsed <= 0) {\n\t\treturn fallback;\n\t}\n\treturn Math.min(parsed, NODE_TIMER_MAX_MS);\n}\n\nfunction signalMarkitdownProcessTree(\n\tchild: ReturnType<typeof spawn>,\n\tsignal: NodeJS.Signals,\n): void {\n\tif (process.platform !== \"win32\" && child.pid) {\n\t\ttry {\n\t\t\tprocess.kill(-child.pid, signal);\n\t\t\treturn;\n\t\t} catch (error) {\n\t\t\tif ((error as NodeJS.ErrnoException).code === \"ESRCH\") {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\ttry {\n\t\tchild.kill(signal);\n\t} catch {\n\t\t// The process may have exited between timeout handling and signal delivery.\n\t}\n}\n\nfunction runMarkitdownCandidate(\n\tcandidate: { command: string; argsPrefix: string[] },\n\targs: string[],\n): Promise<string> {\n\treturn new Promise((resolve, reject) => {\n\t\tconst child = spawn(candidate.command, [...candidate.argsPrefix, ...args], {\n\t\t\tdetached: process.platform !== \"win32\",\n\t\t\tstdio: [\"ignore\", \"pipe\", \"pipe\"],\n\t\t});\n\t\tlet stdout = \"\";\n\t\tlet stderr = \"\";\n\t\tlet timedOut = false;\n\t\tlet settled = false;\n\t\tlet killTimer: NodeJS.Timeout | undefined;\n\t\tlet closeGraceTimer: NodeJS.Timeout | undefined;\n\t\tconst timer = setTimeout(\n\t\t\t() => {\n\t\t\t\ttimedOut = true;\n\t\t\t\tsignalMarkitdownProcessTree(child, \"SIGTERM\");\n\t\t\t\tkillTimer = setTimeout(\n\t\t\t\t\t() => {\n\t\t\t\t\t\tsignalMarkitdownProcessTree(child, \"SIGKILL\");\n\t\t\t\t\t\tcloseGraceTimer = setTimeout(\n\t\t\t\t\t\t\t() => {\n\t\t\t\t\t\t\t\tchild.stdout.destroy();\n\t\t\t\t\t\t\t\tchild.stderr.destroy();\n\t\t\t\t\t\t\t\tchild.unref();\n\t\t\t\t\t\t\t\tfinish(new Error(\"MarkItDown conversion timed out\"));\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\treadPositiveIntegerEnv(\n\t\t\t\t\t\t\t\t\"MAESTRO_MARKITDOWN_CLOSE_GRACE_MS\",\n\t\t\t\t\t\t\t\tMARKITDOWN_TIMEOUT_CLOSE_GRACE_MS,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t);\n\t\t\t\t\t},\n\t\t\t\t\treadPositiveIntegerEnv(\n\t\t\t\t\t\t\"MAESTRO_MARKITDOWN_KILL_GRACE_MS\",\n\t\t\t\t\t\tMARKITDOWN_TIMEOUT_KILL_GRACE_MS,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t},\n\t\t\treadPositiveIntegerEnv(\n\t\t\t\t\"MAESTRO_MARKITDOWN_TIMEOUT_MS\",\n\t\t\t\tMARKITDOWN_TIMEOUT_MS,\n\t\t\t),\n\t\t);\n\n\t\tfunction finish(error: Error | null, output?: string) {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tclearTimeout(timer);\n\t\t\tif (killTimer) clearTimeout(killTimer);\n\t\t\tif (closeGraceTimer) clearTimeout(closeGraceTimer);\n\t\t\tif (error) {\n\t\t\t\treject(error);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tresolve(output ?? \"\");\n\t\t}\n\n\t\tchild.stdout.setEncoding(\"utf8\");\n\t\tchild.stderr.setEncoding(\"utf8\");\n\t\tchild.stdout.on(\"data\", (chunk) => {\n\t\t\tstdout += chunk;\n\t\t});\n\t\tchild.stderr.on(\"data\", (chunk) => {\n\t\t\tstderr += chunk;\n\t\t});\n\t\tchild.on(\"error\", (error) => {\n\t\t\tif (timedOut) {\n\t\t\t\tfinish(new Error(\"MarkItDown conversion timed out\"));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tfinish(error);\n\t\t});\n\t\tchild.on(\"close\", (code) => {\n\t\t\tif (timedOut) {\n\t\t\t\tfinish(new Error(\"MarkItDown conversion timed out\"));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (code === 0) {\n\t\t\t\tfinish(null, stdout);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tfinish(\n\t\t\t\tnew Error(\n\t\t\t\t\t`MarkItDown exited with ${code}${stderr ? `: ${stderr.slice(0, 500)}` : \"\"}`,\n\t\t\t\t),\n\t\t\t);\n\t\t});\n\t});\n}\n\nasync function extractWithMarkitdown(input: {\n\tbuffer: Buffer;\n\tfileName: string;\n\tmimeType?: string;\n}): Promise<string | null> {\n\tconst tempDir = await mkdtemp(join(tmpdir(), \"maestro-markitdown-\"));\n\tconst extension = extname(input.fileName) || \".bin\";\n\tconst tempPath = join(tempDir, `input${extension}`);\n\ttry {\n\t\tawait writeFile(tempPath, input.buffer);\n\t\tconst args = [tempPath];\n\t\tif (input.mimeType) {\n\t\t\targs.push(\"--mime-type\", input.mimeType);\n\t\t}\n\n\t\tlet lastError: unknown;\n\t\tfor (const candidate of markitdownCandidates()) {\n\t\t\ttry {\n\t\t\t\tconst output = await runMarkitdownCandidate(candidate, args);\n\t\t\t\tconst text = output.trim();\n\t\t\t\tif (text) return text;\n\t\t\t} catch (error) {\n\t\t\t\tlastError = error;\n\t\t\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") continue;\n\t\t\t}\n\t\t}\n\n\t\tif (process.env.MAESTRO_MARKITDOWN_CMD) {\n\t\t\tconst message =\n\t\t\t\tlastError instanceof Error ? lastError.message : String(lastError);\n\t\t\tthrow new Error(`MarkItDown extraction failed: ${message}`);\n\t\t}\n\t\treturn null;\n\t} finally {\n\t\tawait rm(tempDir, { force: true, recursive: true });\n\t}\n}\n\nfunction worksheetToRows(worksheet: ExcelJS.Worksheet): string[][] {\n\tconst rows: string[][] = [];\n\tworksheet.eachRow({ includeEmpty: false }, (row) => {\n\t\tconst cells: string[] = [];\n\t\tfor (let column = 1; column <= row.cellCount; column++) {\n\t\t\tcells.push((row.getCell(column).text || \"\").trim());\n\t\t}\n\t\twhile (cells.length > 0 && cells[cells.length - 1] === \"\") {\n\t\t\tcells.pop();\n\t\t}\n\t\tif (cells.some((value) => value !== \"\")) {\n\t\t\trows.push(cells);\n\t\t}\n\t});\n\treturn rows;\n}\n\nasync function extractPptxText(buffer: Buffer): Promise<string> {\n\tconst zip = await JSZip.loadAsync(buffer);\n\n\tconst slidePaths = Object.keys(zip.files)\n\t\t.filter((p) => /^ppt\\/slides\\/slide\\d+\\.xml$/i.test(p))\n\t\t.sort((a, b) => {\n\t\t\tconst an = Number.parseInt(a.match(/slide(\\d+)\\.xml/i)?.[1] || \"0\", 10);\n\t\t\tconst bn = Number.parseInt(b.match(/slide(\\d+)\\.xml/i)?.[1] || \"0\", 10);\n\t\t\treturn an - bn;\n\t\t});\n\n\tif (slidePaths.length === 0) {\n\t\treturn \"\";\n\t}\n\n\tconst parts: string[] = [];\n\tfor (const slidePath of slidePaths) {\n\t\tconst slideNumber = slidePath.match(/slide(\\d+)\\.xml/i)?.[1] || \"?\";\n\t\tconst xml = await zip.file(slidePath)?.async(\"string\");\n\t\tif (!xml) continue;\n\n\t\tconst texts = Array.from(xml.matchAll(/<a:t>(.*?)<\\/a:t>/g))\n\t\t\t.map((m) => m[1] || \"\")\n\t\t\t.map((s) =>\n\t\t\t\ts\n\t\t\t\t\t.replaceAll(\"&lt;\", \"<\")\n\t\t\t\t\t.replaceAll(\"&gt;\", \">\")\n\t\t\t\t\t.replaceAll(\"&amp;\", \"&\")\n\t\t\t\t\t.replaceAll(\"&quot;\", '\"')\n\t\t\t\t\t.replaceAll(\"&apos;\", \"'\"),\n\t\t\t)\n\t\t\t.map((s) => s.trim())\n\t\t\t.filter(Boolean);\n\n\t\tif (texts.length === 0) continue;\n\t\tparts.push(`# Slide ${slideNumber}\\n${texts.join(\" \")}`);\n\t}\n\n\treturn parts.join(\"\\n\\n\");\n}\n\nexport async function extractDocumentText(\n\tinput: ExtractDocumentInput,\n): Promise<ExtractDocumentOutput> {\n\tconst { buffer, fileName } = input;\n\tconst maxChars = Math.max(1, input.maxChars ?? DEFAULT_MAX_CHARS);\n\n\tif (buffer.byteLength > MAX_INPUT_BYTES) {\n\t\tthrow new Error(\n\t\t\t`Document is too large (${(buffer.byteLength / 1024 / 1024).toFixed(1)}MB). Maximum supported size is 50MB.`,\n\t\t);\n\t}\n\n\tconst format = detectFormat(fileName, input.mimeType);\n\tconst markitdownFirst =\n\t\t/^(1|true|on|yes)$/i.test(process.env.MAESTRO_MARKITDOWN_PREFER ?? \"\") &&\n\t\t!isMarkitdownDisabled();\n\n\tlet extractedText = \"\";\n\tlet extractor: ExtractDocumentOutput[\"extractor\"] = \"native\";\n\tif (markitdownFirst) {\n\t\tconst markitdownText = await extractWithMarkitdown({\n\t\t\tbuffer,\n\t\t\tfileName,\n\t\t\tmimeType: input.mimeType,\n\t\t});\n\t\tif (markitdownText) {\n\t\t\textractedText = markitdownText;\n\t\t\textractor = \"markitdown\";\n\t\t}\n\t}\n\n\tif (!extractedText) {\n\t\tswitch (format) {\n\t\t\tcase \"pdf\": {\n\t\t\t\tconst PDFParse = await loadPDFParse();\n\t\t\t\tconst parser = new PDFParse({ data: buffer });\n\t\t\t\ttry {\n\t\t\t\t\tconst result = await parser.getText();\n\t\t\t\t\textractedText = result.text || \"\";\n\t\t\t\t} finally {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait parser.destroy();\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// ignore\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"docx\": {\n\t\t\t\tconst result = await mammoth.extractRawText({ buffer });\n\t\t\t\textractedText = result.value || \"\";\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"xlsx\": {\n\t\t\t\tconst workbook = new ExcelJS.Workbook();\n\t\t\t\tawait workbook.xlsx.load(buffer as unknown as ExcelWorkbookLoadInput);\n\t\t\t\tconst parts: string[] = [];\n\t\t\t\tfor (const worksheet of workbook.worksheets) {\n\t\t\t\t\tconst rows = worksheetToRows(worksheet);\n\t\t\t\t\tif (rows.length === 0) continue;\n\t\t\t\t\tparts.push(\n\t\t\t\t\t\t`# Sheet: ${worksheet.name}\\n${rows.map((row) => row.join(\"\\t\")).join(\"\\n\")}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\textractedText = parts.join(\"\\n\\n\");\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"pptx\": {\n\t\t\t\textractedText = await extractPptxText(buffer);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"text\": {\n\t\t\t\textractedText = buffer.toString(\"utf8\");\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault: {\n\t\t\t\textractedText = \"\";\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (\n\t\textractor !== \"markitdown\" &&\n\t\tshouldTryMarkitdown(format, fileName, input.mimeType)\n\t) {\n\t\tconst markitdownText = await extractWithMarkitdown({\n\t\t\tbuffer,\n\t\t\tfileName,\n\t\t\tmimeType: input.mimeType,\n\t\t});\n\t\tif (markitdownText) {\n\t\t\textractedText = markitdownText;\n\t\t\textractor = \"markitdown\";\n\t\t}\n\t}\n\n\tconst { text, truncated } = clampText(extractedText, maxChars);\n\treturn {\n\t\textractedText: text,\n\t\tformat,\n\t\textractor,\n\t\ttruncated,\n\t\tsizeBytes: buffer.byteLength,\n\t};\n}\n"]}