@fleetagent/pi-coding-agent 0.0.10 → 0.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/core/agent-session.d.ts +1 -0
  3. package/dist/core/agent-session.d.ts.map +1 -1
  4. package/dist/core/agent-session.js +16 -3
  5. package/dist/core/agent-session.js.map +1 -1
  6. package/dist/core/bash-executor.d.ts +2 -0
  7. package/dist/core/bash-executor.d.ts.map +1 -1
  8. package/dist/core/bash-executor.js +1 -0
  9. package/dist/core/bash-executor.js.map +1 -1
  10. package/dist/core/extensions/index.d.ts +1 -1
  11. package/dist/core/extensions/index.d.ts.map +1 -1
  12. package/dist/core/extensions/index.js.map +1 -1
  13. package/dist/core/extensions/loader.d.ts.map +1 -1
  14. package/dist/core/extensions/loader.js +86 -0
  15. package/dist/core/extensions/loader.js.map +1 -1
  16. package/dist/core/extensions/runner.d.ts +3 -0
  17. package/dist/core/extensions/runner.d.ts.map +1 -1
  18. package/dist/core/extensions/runner.js +27 -0
  19. package/dist/core/extensions/runner.js.map +1 -1
  20. package/dist/core/extensions/types.d.ts +55 -2
  21. package/dist/core/extensions/types.d.ts.map +1 -1
  22. package/dist/core/extensions/types.js.map +1 -1
  23. package/dist/core/pi-agent.d.ts.map +1 -1
  24. package/dist/core/pi-agent.js +1 -0
  25. package/dist/core/pi-agent.js.map +1 -1
  26. package/dist/core/prompt-templates.d.ts +5 -0
  27. package/dist/core/prompt-templates.d.ts.map +1 -1
  28. package/dist/core/prompt-templates.js +115 -0
  29. package/dist/core/prompt-templates.js.map +1 -1
  30. package/dist/core/resource-loader.d.ts +15 -0
  31. package/dist/core/resource-loader.d.ts.map +1 -1
  32. package/dist/core/resource-loader.js +332 -40
  33. package/dist/core/resource-loader.js.map +1 -1
  34. package/dist/core/rules.d.ts +6 -0
  35. package/dist/core/rules.d.ts.map +1 -1
  36. package/dist/core/rules.js +216 -0
  37. package/dist/core/rules.js.map +1 -1
  38. package/dist/core/skills.d.ts +6 -0
  39. package/dist/core/skills.d.ts.map +1 -1
  40. package/dist/core/skills.js +216 -0
  41. package/dist/core/skills.js.map +1 -1
  42. package/dist/core/source-info.d.ts +2 -0
  43. package/dist/core/source-info.d.ts.map +1 -1
  44. package/dist/core/source-info.js +6 -0
  45. package/dist/core/source-info.js.map +1 -1
  46. package/dist/core/tools/bash.d.ts.map +1 -1
  47. package/dist/core/tools/bash.js +5 -5
  48. package/dist/core/tools/bash.js.map +1 -1
  49. package/dist/core/tools/edit.d.ts.map +1 -1
  50. package/dist/core/tools/edit.js +5 -5
  51. package/dist/core/tools/edit.js.map +1 -1
  52. package/dist/core/tools/find.d.ts.map +1 -1
  53. package/dist/core/tools/find.js +2 -2
  54. package/dist/core/tools/find.js.map +1 -1
  55. package/dist/core/tools/grep.d.ts.map +1 -1
  56. package/dist/core/tools/grep.js +2 -2
  57. package/dist/core/tools/grep.js.map +1 -1
  58. package/dist/core/tools/ls.d.ts.map +1 -1
  59. package/dist/core/tools/ls.js +2 -2
  60. package/dist/core/tools/ls.js.map +1 -1
  61. package/dist/core/tools/read.d.ts.map +1 -1
  62. package/dist/core/tools/read.js +3 -2
  63. package/dist/core/tools/read.js.map +1 -1
  64. package/dist/core/tools/render-utils.d.ts +9 -0
  65. package/dist/core/tools/render-utils.d.ts.map +1 -1
  66. package/dist/core/tools/render-utils.js +14 -0
  67. package/dist/core/tools/render-utils.js.map +1 -1
  68. package/dist/core/tools/write.d.ts.map +1 -1
  69. package/dist/core/tools/write.js +3 -2
  70. package/dist/core/tools/write.js.map +1 -1
  71. package/dist/index.d.ts +1 -1
  72. package/dist/index.d.ts.map +1 -1
  73. package/dist/index.js.map +1 -1
  74. package/dist/main.d.ts.map +1 -1
  75. package/dist/main.js +7 -5
  76. package/dist/main.js.map +1 -1
  77. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  78. package/dist/modes/interactive/interactive-mode.js +21 -9
  79. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  80. package/docs/extensions.md +82 -3
  81. package/docs/usage.md +2 -0
  82. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  83. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  84. package/examples/extensions/sandbox/package.json +1 -1
  85. package/examples/extensions/with-deps/package.json +1 -1
  86. package/npm-shrinkwrap.json +12 -12
  87. package/package.json +4 -4
@@ -1 +1 @@
1
- {"version":3,"file":"find.js","sourceRoot":"","sources":["../../../src/core/tools/find.ts"],"names":[],"mappings":"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","sourcesContent":["import { createInterface } from \"node:readline\";\nimport type { AgentTool } from \"@fleetagent/pi-agent-core\";\nimport { Text } from \"@fleetagent/pi-tui\";\nimport { spawn } from \"child_process\";\nimport path from \"path\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport { ensureTool } from \"../../utils/tools-manager.ts\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../extensions/types.ts\";\nimport type { ToolOperations } from \"./operations.ts\";\nimport { resolveToCwd } from \"./path-utils.ts\";\nimport { getTextOutput, invalidArgText, shortenPath, str } from \"./render-utils.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\nimport { DEFAULT_MAX_BYTES, formatSize, type TruncationResult, truncateHead } from \"./truncate.ts\";\n\nfunction toPosixPath(value: string): string {\n\treturn value.split(path.sep).join(\"/\");\n}\n\nconst findSchema = Type.Object({\n\tpattern: Type.String({\n\t\tdescription: \"Glob pattern to match files, e.g. '*.ts', '**/*.json', or 'src/**/*.spec.ts'\",\n\t}),\n\tpath: Type.Optional(Type.String({ description: \"Directory to search in (default: current directory)\" })),\n\tlimit: Type.Optional(Type.Number({ description: \"Maximum number of results (default: 1000)\" })),\n});\n\nexport type FindToolInput = Static<typeof findSchema>;\n\nconst DEFAULT_LIMIT = 1000;\n\nexport interface FindToolDetails {\n\ttruncation?: TruncationResult;\n\tresultLimitReached?: number;\n}\n\nexport interface FindToolOptions {}\n\nfunction formatFindCall(\n\targs: { pattern: string; path?: string; limit?: number } | undefined,\n\ttheme: typeof import(\"../../modes/interactive/theme/theme.ts\").theme,\n): string {\n\tconst pattern = str(args?.pattern);\n\tconst rawPath = str(args?.path);\n\tconst path = rawPath !== null ? shortenPath(rawPath || \".\") : null;\n\tconst limit = args?.limit;\n\tconst invalidArg = invalidArgText(theme);\n\tlet text =\n\t\ttheme.fg(\"toolTitle\", theme.bold(\"find\")) +\n\t\t\" \" +\n\t\t(pattern === null ? invalidArg : theme.fg(\"accent\", pattern || \"\")) +\n\t\ttheme.fg(\"toolOutput\", ` in ${path === null ? invalidArg : path}`);\n\tif (limit !== undefined) {\n\t\ttext += theme.fg(\"toolOutput\", ` (limit ${limit})`);\n\t}\n\treturn text;\n}\n\nfunction formatFindResult(\n\tresult: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tdetails?: FindToolDetails;\n\t},\n\toptions: ToolRenderResultOptions,\n\ttheme: typeof import(\"../../modes/interactive/theme/theme.ts\").theme,\n\tshowImages: boolean,\n): string {\n\tconst output = getTextOutput(result, showImages).trim();\n\tlet text = \"\";\n\tif (output) {\n\t\tconst lines = output.split(\"\\n\");\n\t\tconst maxLines = options.expanded ? lines.length : 20;\n\t\tconst displayLines = lines.slice(0, maxLines);\n\t\tconst remaining = lines.length - maxLines;\n\t\ttext += `\\n${displayLines.map((line) => theme.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n\t\tif (remaining > 0) {\n\t\t\ttext += `${theme.fg(\"muted\", `\\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")})`;\n\t\t}\n\t}\n\n\tconst resultLimit = result.details?.resultLimitReached;\n\tconst truncation = result.details?.truncation;\n\tif (resultLimit || truncation?.truncated) {\n\t\tconst warnings: string[] = [];\n\t\tif (resultLimit) warnings.push(`${resultLimit} results limit`);\n\t\tif (truncation?.truncated) warnings.push(`${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);\n\t\ttext += `\\n${theme.fg(\"warning\", `[Truncated: ${warnings.join(\", \")}]`)}`;\n\t}\n\treturn text;\n}\n\nexport function createFindToolDefinition(\n\toperations: ToolOperations,\n\t_options?: FindToolOptions,\n): ToolDefinition<typeof findSchema, FindToolDetails | undefined> {\n\tconst ops = operations;\n\tconst cwd = operations.cwd;\n\treturn {\n\t\tname: \"find\",\n\t\tlabel: \"find\",\n\t\tdescription: `Search for files by glob pattern. Returns matching file paths relative to the search directory. Respects .gitignore. Output is truncated to ${DEFAULT_LIMIT} results or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first).`,\n\t\tpromptSnippet: \"Find files by glob pattern (respects .gitignore)\",\n\t\tparameters: findSchema,\n\t\tasync execute(\n\t\t\t_toolCallId,\n\t\t\t{ pattern, path: searchDir, limit }: { pattern: string; path?: string; limit?: number },\n\t\t\tsignal?: AbortSignal,\n\t\t\t_onUpdate?,\n\t\t\t_ctx?,\n\t\t) {\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\treject(new Error(\"Operation aborted\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tlet settled = false;\n\t\t\t\tlet stopChild: (() => void) | undefined;\n\t\t\t\tconst settle = (fn: () => void) => {\n\t\t\t\t\tif (settled) return;\n\t\t\t\t\tsettled = true;\n\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\tstopChild = undefined;\n\t\t\t\t\tfn();\n\t\t\t\t};\n\t\t\t\tconst onAbort = () => {\n\t\t\t\t\tstopChild?.();\n\t\t\t\t\tsettle(() => reject(new Error(\"Operation aborted\")));\n\t\t\t\t};\n\t\t\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\n\t\t\t\t(async () => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst searchPath = resolveToCwd(searchDir || \".\", cwd);\n\t\t\t\t\t\tconst effectiveLimit = limit ?? DEFAULT_LIMIT;\n\t\t\t\t\t\t// If operations provide glob(), use that instead of fd.\n\t\t\t\t\t\tif (ops.glob) {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tawait ops.access(searchPath, \"exists\");\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\tsettle(() => reject(new Error(`Path not found: ${searchPath}`)));\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\t\t\t\tsettle(() => reject(new Error(\"Operation aborted\")));\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst results = await ops.glob(pattern, searchPath, {\n\t\t\t\t\t\t\t\tignore: [\"**/node_modules/**\", \"**/.git/**\"],\n\t\t\t\t\t\t\t\tlimit: effectiveLimit,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\t\t\t\tsettle(() => reject(new Error(\"Operation aborted\")));\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (results.length === 0) {\n\t\t\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: \"No files found matching pattern\" }],\n\t\t\t\t\t\t\t\t\t\tdetails: undefined,\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Relativize paths against the search root for stable output.\n\t\t\t\t\t\t\tconst relativized = results.map((p) => {\n\t\t\t\t\t\t\t\tif (p.startsWith(searchPath)) return toPosixPath(p.slice(searchPath.length + 1));\n\t\t\t\t\t\t\t\treturn toPosixPath(path.relative(searchPath, p));\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tconst resultLimitReached = relativized.length >= effectiveLimit;\n\t\t\t\t\t\t\tconst rawOutput = relativized.join(\"\\n\");\n\t\t\t\t\t\t\tconst truncation = truncateHead(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER });\n\t\t\t\t\t\t\tlet resultOutput = truncation.content;\n\t\t\t\t\t\t\tconst details: FindToolDetails = {};\n\t\t\t\t\t\t\tconst notices: string[] = [];\n\t\t\t\t\t\t\tif (resultLimitReached) {\n\t\t\t\t\t\t\t\tnotices.push(`${effectiveLimit} results limit reached`);\n\t\t\t\t\t\t\t\tdetails.resultLimitReached = effectiveLimit;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (truncation.truncated) {\n\t\t\t\t\t\t\t\tnotices.push(`${formatSize(DEFAULT_MAX_BYTES)} limit reached`);\n\t\t\t\t\t\t\t\tdetails.truncation = truncation;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (notices.length > 0) {\n\t\t\t\t\t\t\t\tresultOutput += `\\n\\n[${notices.join(\". \")}]`;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: resultOutput }],\n\t\t\t\t\t\t\t\t\tdetails: Object.keys(details).length > 0 ? details : undefined,\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Default implementation uses fd.\n\t\t\t\t\t\tconst fdPath = await ensureTool(\"fd\", true);\n\t\t\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\t\t\tsettle(() => reject(new Error(\"Operation aborted\")));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (!fdPath) {\n\t\t\t\t\t\t\tsettle(() => reject(new Error(\"fd is not available and could not be downloaded\")));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Build fd arguments. --no-require-git makes fd apply hierarchical .gitignore\n\t\t\t\t\t\t// semantics whether or not the search path is inside a git repository, without\n\t\t\t\t\t\t// leaking sibling-directory rules the way --ignore-file (a global source) would.\n\t\t\t\t\t\tconst args: string[] = [\n\t\t\t\t\t\t\t\"--glob\",\n\t\t\t\t\t\t\t\"--color=never\",\n\t\t\t\t\t\t\t\"--hidden\",\n\t\t\t\t\t\t\t\"--no-require-git\",\n\t\t\t\t\t\t\t\"--max-results\",\n\t\t\t\t\t\t\tString(effectiveLimit),\n\t\t\t\t\t\t];\n\n\t\t\t\t\t\t// fd --glob matches against the basename unless --full-path is set; in --full-path\n\t\t\t\t\t\t// mode it matches against the absolute candidate path, so a path-containing\n\t\t\t\t\t\t// pattern like 'src/**/*.spec.ts' needs a leading '**/' to match anything.\n\t\t\t\t\t\tlet effectivePattern = pattern;\n\t\t\t\t\t\tif (pattern.includes(\"/\")) {\n\t\t\t\t\t\t\targs.push(\"--full-path\");\n\t\t\t\t\t\t\tif (!pattern.startsWith(\"/\") && !pattern.startsWith(\"**/\") && pattern !== \"**\") {\n\t\t\t\t\t\t\t\teffectivePattern = `**/${pattern}`;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\targs.push(\"--\", effectivePattern, searchPath);\n\n\t\t\t\t\t\tconst child = spawn(fdPath, args, { stdio: [\"ignore\", \"pipe\", \"pipe\"] });\n\t\t\t\t\t\tconst rl = createInterface({ input: child.stdout });\n\t\t\t\t\t\tlet stderr = \"\";\n\t\t\t\t\t\tconst lines: string[] = [];\n\n\t\t\t\t\t\tstopChild = () => {\n\t\t\t\t\t\t\tif (!child.killed) {\n\t\t\t\t\t\t\t\tchild.kill();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tconst cleanup = () => {\n\t\t\t\t\t\t\trl.close();\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tchild.stderr?.on(\"data\", (chunk) => {\n\t\t\t\t\t\t\tstderr += chunk.toString();\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\trl.on(\"line\", (line) => {\n\t\t\t\t\t\t\tlines.push(line);\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tchild.on(\"error\", (error) => {\n\t\t\t\t\t\t\tcleanup();\n\t\t\t\t\t\t\tsettle(() => reject(new Error(`Failed to run fd: ${error.message}`)));\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tchild.on(\"close\", (code) => {\n\t\t\t\t\t\t\tcleanup();\n\t\t\t\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\t\t\t\tsettle(() => reject(new Error(\"Operation aborted\")));\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst output = lines.join(\"\\n\");\n\t\t\t\t\t\t\tif (code !== 0) {\n\t\t\t\t\t\t\t\tconst errorMsg = stderr.trim() || `fd exited with code ${code}`;\n\t\t\t\t\t\t\t\tif (!output) {\n\t\t\t\t\t\t\t\t\tsettle(() => reject(new Error(errorMsg)));\n\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (!output) {\n\t\t\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: \"No files found matching pattern\" }],\n\t\t\t\t\t\t\t\t\t\tdetails: undefined,\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tconst relativized: string[] = [];\n\t\t\t\t\t\t\tfor (const rawLine of lines) {\n\t\t\t\t\t\t\t\tconst line = rawLine.replace(/\\r$/, \"\").trim();\n\t\t\t\t\t\t\t\tif (!line) continue;\n\t\t\t\t\t\t\t\tconst hadTrailingSlash = line.endsWith(\"/\") || line.endsWith(\"\\\\\");\n\t\t\t\t\t\t\t\tlet relativePath = line;\n\t\t\t\t\t\t\t\tif (line.startsWith(searchPath)) {\n\t\t\t\t\t\t\t\t\trelativePath = line.slice(searchPath.length + 1);\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\trelativePath = path.relative(searchPath, line);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (hadTrailingSlash && !relativePath.endsWith(\"/\")) relativePath += \"/\";\n\t\t\t\t\t\t\t\trelativized.push(toPosixPath(relativePath));\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tconst resultLimitReached = relativized.length >= effectiveLimit;\n\t\t\t\t\t\t\tconst rawOutput = relativized.join(\"\\n\");\n\t\t\t\t\t\t\tconst truncation = truncateHead(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER });\n\t\t\t\t\t\t\tlet resultOutput = truncation.content;\n\t\t\t\t\t\t\tconst details: FindToolDetails = {};\n\t\t\t\t\t\t\tconst notices: string[] = [];\n\t\t\t\t\t\t\tif (resultLimitReached) {\n\t\t\t\t\t\t\t\tnotices.push(\n\t\t\t\t\t\t\t\t\t`${effectiveLimit} results limit reached. Use limit=${effectiveLimit * 2} for more, or refine pattern`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tdetails.resultLimitReached = effectiveLimit;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (truncation.truncated) {\n\t\t\t\t\t\t\t\tnotices.push(`${formatSize(DEFAULT_MAX_BYTES)} limit reached`);\n\t\t\t\t\t\t\t\tdetails.truncation = truncation;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (notices.length > 0) {\n\t\t\t\t\t\t\t\tresultOutput += `\\n\\n[${notices.join(\". \")}]`;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: resultOutput }],\n\t\t\t\t\t\t\t\t\tdetails: Object.keys(details).length > 0 ? details : undefined,\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t});\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\t\t\tsettle(() => reject(new Error(\"Operation aborted\")));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst error = e instanceof Error ? e : new Error(String(e));\n\t\t\t\t\t\tsettle(() => reject(error));\n\t\t\t\t\t}\n\t\t\t\t})();\n\t\t\t});\n\t\t},\n\t\trenderCall(args, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatFindCall(args, theme));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatFindResult(result as any, options, theme, context.showImages));\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createFindTool(operations: ToolOperations, options?: FindToolOptions): AgentTool<typeof findSchema> {\n\treturn wrapToolDefinition(createFindToolDefinition(operations, options));\n}\n"]}
1
+ {"version":3,"file":"find.js","sourceRoot":"","sources":["../../../src/core/tools/find.ts"],"names":[],"mappings":"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","sourcesContent":["import { createInterface } from \"node:readline\";\nimport type { AgentTool } from \"@fleetagent/pi-agent-core\";\nimport { Text } from \"@fleetagent/pi-tui\";\nimport { spawn } from \"child_process\";\nimport path from \"path\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport { ensureTool } from \"../../utils/tools-manager.ts\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../extensions/types.ts\";\nimport type { ToolOperations } from \"./operations.ts\";\nimport { resolveToCwd } from \"./path-utils.ts\";\nimport { formatBackendIcon, getTextOutput, invalidArgText, shortenPath, str } from \"./render-utils.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\nimport { DEFAULT_MAX_BYTES, formatSize, type TruncationResult, truncateHead } from \"./truncate.ts\";\n\nfunction toPosixPath(value: string): string {\n\treturn value.split(path.sep).join(\"/\");\n}\n\nconst findSchema = Type.Object({\n\tpattern: Type.String({\n\t\tdescription: \"Glob pattern to match files, e.g. '*.ts', '**/*.json', or 'src/**/*.spec.ts'\",\n\t}),\n\tpath: Type.Optional(Type.String({ description: \"Directory to search in (default: current directory)\" })),\n\tlimit: Type.Optional(Type.Number({ description: \"Maximum number of results (default: 1000)\" })),\n});\n\nexport type FindToolInput = Static<typeof findSchema>;\n\nconst DEFAULT_LIMIT = 1000;\n\nexport interface FindToolDetails {\n\ttruncation?: TruncationResult;\n\tresultLimitReached?: number;\n}\n\nexport interface FindToolOptions {}\n\nfunction formatFindCall(\n\targs: { pattern: string; path?: string; limit?: number } | undefined,\n\ttheme: typeof import(\"../../modes/interactive/theme/theme.ts\").theme,\n): string {\n\tconst pattern = str(args?.pattern);\n\tconst rawPath = str(args?.path);\n\tconst path = rawPath !== null ? shortenPath(rawPath || \".\") : null;\n\tconst limit = args?.limit;\n\tconst invalidArg = invalidArgText(theme);\n\tlet text =\n\t\ttheme.fg(\"toolTitle\", theme.bold(\"find\")) +\n\t\t\" \" +\n\t\t(pattern === null ? invalidArg : theme.fg(\"accent\", pattern || \"\")) +\n\t\ttheme.fg(\"toolOutput\", ` in ${path === null ? invalidArg : path}`);\n\tif (limit !== undefined) {\n\t\ttext += theme.fg(\"toolOutput\", ` (limit ${limit})`);\n\t}\n\treturn text;\n}\n\nfunction formatFindResult(\n\tresult: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tdetails?: FindToolDetails;\n\t},\n\toptions: ToolRenderResultOptions,\n\ttheme: typeof import(\"../../modes/interactive/theme/theme.ts\").theme,\n\tshowImages: boolean,\n): string {\n\tconst output = getTextOutput(result, showImages).trim();\n\tlet text = \"\";\n\tif (output) {\n\t\tconst lines = output.split(\"\\n\");\n\t\tconst maxLines = options.expanded ? lines.length : 20;\n\t\tconst displayLines = lines.slice(0, maxLines);\n\t\tconst remaining = lines.length - maxLines;\n\t\ttext += `\\n${displayLines.map((line) => theme.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n\t\tif (remaining > 0) {\n\t\t\ttext += `${theme.fg(\"muted\", `\\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")})`;\n\t\t}\n\t}\n\n\tconst resultLimit = result.details?.resultLimitReached;\n\tconst truncation = result.details?.truncation;\n\tif (resultLimit || truncation?.truncated) {\n\t\tconst warnings: string[] = [];\n\t\tif (resultLimit) warnings.push(`${resultLimit} results limit`);\n\t\tif (truncation?.truncated) warnings.push(`${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);\n\t\ttext += `\\n${theme.fg(\"warning\", `[Truncated: ${warnings.join(\", \")}]`)}`;\n\t}\n\treturn text;\n}\n\nexport function createFindToolDefinition(\n\toperations: ToolOperations,\n\t_options?: FindToolOptions,\n): ToolDefinition<typeof findSchema, FindToolDetails | undefined> {\n\tconst ops = operations;\n\tconst cwd = operations.cwd;\n\treturn {\n\t\tname: \"find\",\n\t\tlabel: \"find\",\n\t\tdescription: `Search for files by glob pattern. Returns matching file paths relative to the search directory. Respects .gitignore. Output is truncated to ${DEFAULT_LIMIT} results or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first).`,\n\t\tpromptSnippet: \"Find files by glob pattern (respects .gitignore)\",\n\t\tparameters: findSchema,\n\t\tasync execute(\n\t\t\t_toolCallId,\n\t\t\t{ pattern, path: searchDir, limit }: { pattern: string; path?: string; limit?: number },\n\t\t\tsignal?: AbortSignal,\n\t\t\t_onUpdate?,\n\t\t\t_ctx?,\n\t\t) {\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\treject(new Error(\"Operation aborted\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tlet settled = false;\n\t\t\t\tlet stopChild: (() => void) | undefined;\n\t\t\t\tconst settle = (fn: () => void) => {\n\t\t\t\t\tif (settled) return;\n\t\t\t\t\tsettled = true;\n\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\tstopChild = undefined;\n\t\t\t\t\tfn();\n\t\t\t\t};\n\t\t\t\tconst onAbort = () => {\n\t\t\t\t\tstopChild?.();\n\t\t\t\t\tsettle(() => reject(new Error(\"Operation aborted\")));\n\t\t\t\t};\n\t\t\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\n\t\t\t\t(async () => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst searchPath = resolveToCwd(searchDir || \".\", cwd);\n\t\t\t\t\t\tconst effectiveLimit = limit ?? DEFAULT_LIMIT;\n\t\t\t\t\t\t// If operations provide glob(), use that instead of fd.\n\t\t\t\t\t\tif (ops.glob) {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tawait ops.access(searchPath, \"exists\");\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\tsettle(() => reject(new Error(`Path not found: ${searchPath}`)));\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\t\t\t\tsettle(() => reject(new Error(\"Operation aborted\")));\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst results = await ops.glob(pattern, searchPath, {\n\t\t\t\t\t\t\t\tignore: [\"**/node_modules/**\", \"**/.git/**\"],\n\t\t\t\t\t\t\t\tlimit: effectiveLimit,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\t\t\t\tsettle(() => reject(new Error(\"Operation aborted\")));\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (results.length === 0) {\n\t\t\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: \"No files found matching pattern\" }],\n\t\t\t\t\t\t\t\t\t\tdetails: undefined,\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Relativize paths against the search root for stable output.\n\t\t\t\t\t\t\tconst relativized = results.map((p) => {\n\t\t\t\t\t\t\t\tif (p.startsWith(searchPath)) return toPosixPath(p.slice(searchPath.length + 1));\n\t\t\t\t\t\t\t\treturn toPosixPath(path.relative(searchPath, p));\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tconst resultLimitReached = relativized.length >= effectiveLimit;\n\t\t\t\t\t\t\tconst rawOutput = relativized.join(\"\\n\");\n\t\t\t\t\t\t\tconst truncation = truncateHead(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER });\n\t\t\t\t\t\t\tlet resultOutput = truncation.content;\n\t\t\t\t\t\t\tconst details: FindToolDetails = {};\n\t\t\t\t\t\t\tconst notices: string[] = [];\n\t\t\t\t\t\t\tif (resultLimitReached) {\n\t\t\t\t\t\t\t\tnotices.push(`${effectiveLimit} results limit reached`);\n\t\t\t\t\t\t\t\tdetails.resultLimitReached = effectiveLimit;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (truncation.truncated) {\n\t\t\t\t\t\t\t\tnotices.push(`${formatSize(DEFAULT_MAX_BYTES)} limit reached`);\n\t\t\t\t\t\t\t\tdetails.truncation = truncation;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (notices.length > 0) {\n\t\t\t\t\t\t\t\tresultOutput += `\\n\\n[${notices.join(\". \")}]`;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: resultOutput }],\n\t\t\t\t\t\t\t\t\tdetails: Object.keys(details).length > 0 ? details : undefined,\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Default implementation uses fd.\n\t\t\t\t\t\tconst fdPath = await ensureTool(\"fd\", true);\n\t\t\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\t\t\tsettle(() => reject(new Error(\"Operation aborted\")));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (!fdPath) {\n\t\t\t\t\t\t\tsettle(() => reject(new Error(\"fd is not available and could not be downloaded\")));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Build fd arguments. --no-require-git makes fd apply hierarchical .gitignore\n\t\t\t\t\t\t// semantics whether or not the search path is inside a git repository, without\n\t\t\t\t\t\t// leaking sibling-directory rules the way --ignore-file (a global source) would.\n\t\t\t\t\t\tconst args: string[] = [\n\t\t\t\t\t\t\t\"--glob\",\n\t\t\t\t\t\t\t\"--color=never\",\n\t\t\t\t\t\t\t\"--hidden\",\n\t\t\t\t\t\t\t\"--no-require-git\",\n\t\t\t\t\t\t\t\"--max-results\",\n\t\t\t\t\t\t\tString(effectiveLimit),\n\t\t\t\t\t\t];\n\n\t\t\t\t\t\t// fd --glob matches against the basename unless --full-path is set; in --full-path\n\t\t\t\t\t\t// mode it matches against the absolute candidate path, so a path-containing\n\t\t\t\t\t\t// pattern like 'src/**/*.spec.ts' needs a leading '**/' to match anything.\n\t\t\t\t\t\tlet effectivePattern = pattern;\n\t\t\t\t\t\tif (pattern.includes(\"/\")) {\n\t\t\t\t\t\t\targs.push(\"--full-path\");\n\t\t\t\t\t\t\tif (!pattern.startsWith(\"/\") && !pattern.startsWith(\"**/\") && pattern !== \"**\") {\n\t\t\t\t\t\t\t\teffectivePattern = `**/${pattern}`;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\targs.push(\"--\", effectivePattern, searchPath);\n\n\t\t\t\t\t\tconst child = spawn(fdPath, args, { stdio: [\"ignore\", \"pipe\", \"pipe\"] });\n\t\t\t\t\t\tconst rl = createInterface({ input: child.stdout });\n\t\t\t\t\t\tlet stderr = \"\";\n\t\t\t\t\t\tconst lines: string[] = [];\n\n\t\t\t\t\t\tstopChild = () => {\n\t\t\t\t\t\t\tif (!child.killed) {\n\t\t\t\t\t\t\t\tchild.kill();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tconst cleanup = () => {\n\t\t\t\t\t\t\trl.close();\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tchild.stderr?.on(\"data\", (chunk) => {\n\t\t\t\t\t\t\tstderr += chunk.toString();\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\trl.on(\"line\", (line) => {\n\t\t\t\t\t\t\tlines.push(line);\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tchild.on(\"error\", (error) => {\n\t\t\t\t\t\t\tcleanup();\n\t\t\t\t\t\t\tsettle(() => reject(new Error(`Failed to run fd: ${error.message}`)));\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tchild.on(\"close\", (code) => {\n\t\t\t\t\t\t\tcleanup();\n\t\t\t\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\t\t\t\tsettle(() => reject(new Error(\"Operation aborted\")));\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst output = lines.join(\"\\n\");\n\t\t\t\t\t\t\tif (code !== 0) {\n\t\t\t\t\t\t\t\tconst errorMsg = stderr.trim() || `fd exited with code ${code}`;\n\t\t\t\t\t\t\t\tif (!output) {\n\t\t\t\t\t\t\t\t\tsettle(() => reject(new Error(errorMsg)));\n\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (!output) {\n\t\t\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: \"No files found matching pattern\" }],\n\t\t\t\t\t\t\t\t\t\tdetails: undefined,\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tconst relativized: string[] = [];\n\t\t\t\t\t\t\tfor (const rawLine of lines) {\n\t\t\t\t\t\t\t\tconst line = rawLine.replace(/\\r$/, \"\").trim();\n\t\t\t\t\t\t\t\tif (!line) continue;\n\t\t\t\t\t\t\t\tconst hadTrailingSlash = line.endsWith(\"/\") || line.endsWith(\"\\\\\");\n\t\t\t\t\t\t\t\tlet relativePath = line;\n\t\t\t\t\t\t\t\tif (line.startsWith(searchPath)) {\n\t\t\t\t\t\t\t\t\trelativePath = line.slice(searchPath.length + 1);\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\trelativePath = path.relative(searchPath, line);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (hadTrailingSlash && !relativePath.endsWith(\"/\")) relativePath += \"/\";\n\t\t\t\t\t\t\t\trelativized.push(toPosixPath(relativePath));\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tconst resultLimitReached = relativized.length >= effectiveLimit;\n\t\t\t\t\t\t\tconst rawOutput = relativized.join(\"\\n\");\n\t\t\t\t\t\t\tconst truncation = truncateHead(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER });\n\t\t\t\t\t\t\tlet resultOutput = truncation.content;\n\t\t\t\t\t\t\tconst details: FindToolDetails = {};\n\t\t\t\t\t\t\tconst notices: string[] = [];\n\t\t\t\t\t\t\tif (resultLimitReached) {\n\t\t\t\t\t\t\t\tnotices.push(\n\t\t\t\t\t\t\t\t\t`${effectiveLimit} results limit reached. Use limit=${effectiveLimit * 2} for more, or refine pattern`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tdetails.resultLimitReached = effectiveLimit;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (truncation.truncated) {\n\t\t\t\t\t\t\t\tnotices.push(`${formatSize(DEFAULT_MAX_BYTES)} limit reached`);\n\t\t\t\t\t\t\t\tdetails.truncation = truncation;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (notices.length > 0) {\n\t\t\t\t\t\t\t\tresultOutput += `\\n\\n[${notices.join(\". \")}]`;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: resultOutput }],\n\t\t\t\t\t\t\t\t\tdetails: Object.keys(details).length > 0 ? details : undefined,\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t});\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\t\t\tsettle(() => reject(new Error(\"Operation aborted\")));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst error = e instanceof Error ? e : new Error(String(e));\n\t\t\t\t\t\tsettle(() => reject(error));\n\t\t\t\t\t}\n\t\t\t\t})();\n\t\t\t});\n\t\t},\n\t\trenderCall(args, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatBackendIcon(ops.getBackendInfo?.(), theme) + formatFindCall(args, theme));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatFindResult(result as any, options, theme, context.showImages));\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createFindTool(operations: ToolOperations, options?: FindToolOptions): AgentTool<typeof findSchema> {\n\treturn wrapToolDefinition(createFindToolDefinition(operations, options));\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"grep.d.ts","sourceRoot":"","sources":["../../../src/core/tools/grep.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAI3D,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAG5C,OAAO,KAAK,EAAE,cAAc,EAA2B,MAAM,wBAAwB,CAAC;AACtF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAItD,OAAO,EAIN,KAAK,gBAAgB,EAGrB,MAAM,eAAe,CAAC;AAEvB,QAAA,MAAM,UAAU;;;;;;;;EAYd,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AAGtD,MAAM,WAAW,eAAe;IAC/B,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,eAAe;CAAG;AAyDnC,wBAAgB,wBAAwB,CACvC,UAAU,EAAE,cAAc,EAC1B,QAAQ,CAAC,EAAE,eAAe,GACxB,cAAc,CAAC,OAAO,UAAU,EAAE,eAAe,GAAG,SAAS,CAAC,CA8ThE;AAED,wBAAgB,cAAc,CAAC,UAAU,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC,OAAO,UAAU,CAAC,CAElH","sourcesContent":["import { createInterface } from \"node:readline\";\nimport type { AgentTool } from \"@fleetagent/pi-agent-core\";\nimport { Text } from \"@fleetagent/pi-tui\";\nimport { spawn } from \"child_process\";\nimport path from \"path\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport { ensureTool } from \"../../utils/tools-manager.ts\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../extensions/types.ts\";\nimport type { ToolOperations } from \"./operations.ts\";\nimport { resolveToCwd } from \"./path-utils.ts\";\nimport { getTextOutput, invalidArgText, shortenPath, str } from \"./render-utils.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\nimport {\n\tDEFAULT_MAX_BYTES,\n\tformatSize,\n\tGREP_MAX_LINE_LENGTH,\n\ttype TruncationResult,\n\ttruncateHead,\n\ttruncateLine,\n} from \"./truncate.ts\";\n\nconst grepSchema = Type.Object({\n\tpattern: Type.String({ description: \"Search pattern (regex or literal string)\" }),\n\tpath: Type.Optional(Type.String({ description: \"Directory or file to search (default: current directory)\" })),\n\tglob: Type.Optional(Type.String({ description: \"Filter files by glob pattern, e.g. '*.ts' or '**/*.spec.ts'\" })),\n\tignoreCase: Type.Optional(Type.Boolean({ description: \"Case-insensitive search (default: false)\" })),\n\tliteral: Type.Optional(\n\t\tType.Boolean({ description: \"Treat pattern as literal string instead of regex (default: false)\" }),\n\t),\n\tcontext: Type.Optional(\n\t\tType.Number({ description: \"Number of lines to show before and after each match (default: 0)\" }),\n\t),\n\tlimit: Type.Optional(Type.Number({ description: \"Maximum number of matches to return (default: 100)\" })),\n});\n\nexport type GrepToolInput = Static<typeof grepSchema>;\nconst DEFAULT_LIMIT = 100;\n\nexport interface GrepToolDetails {\n\ttruncation?: TruncationResult;\n\tmatchLimitReached?: number;\n\tlinesTruncated?: boolean;\n}\n\nexport interface GrepToolOptions {}\n\nfunction formatGrepCall(\n\targs: { pattern: string; path?: string; glob?: string; limit?: number } | undefined,\n\ttheme: typeof import(\"../../modes/interactive/theme/theme.ts\").theme,\n): string {\n\tconst pattern = str(args?.pattern);\n\tconst rawPath = str(args?.path);\n\tconst path = rawPath !== null ? shortenPath(rawPath || \".\") : null;\n\tconst glob = str(args?.glob);\n\tconst limit = args?.limit;\n\tconst invalidArg = invalidArgText(theme);\n\tlet text =\n\t\ttheme.fg(\"toolTitle\", theme.bold(\"grep\")) +\n\t\t\" \" +\n\t\t(pattern === null ? invalidArg : theme.fg(\"accent\", `/${pattern || \"\"}/`)) +\n\t\ttheme.fg(\"toolOutput\", ` in ${path === null ? invalidArg : path}`);\n\tif (glob) text += theme.fg(\"toolOutput\", ` (${glob})`);\n\tif (limit !== undefined) text += theme.fg(\"toolOutput\", ` limit ${limit}`);\n\treturn text;\n}\n\nfunction formatGrepResult(\n\tresult: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tdetails?: GrepToolDetails;\n\t},\n\toptions: ToolRenderResultOptions,\n\ttheme: typeof import(\"../../modes/interactive/theme/theme.ts\").theme,\n\tshowImages: boolean,\n): string {\n\tconst output = getTextOutput(result, showImages).trim();\n\tlet text = \"\";\n\tif (output) {\n\t\tconst lines = output.split(\"\\n\");\n\t\tconst maxLines = options.expanded ? lines.length : 15;\n\t\tconst displayLines = lines.slice(0, maxLines);\n\t\tconst remaining = lines.length - maxLines;\n\t\ttext += `\\n${displayLines.map((line) => theme.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n\t\tif (remaining > 0) {\n\t\t\ttext += `${theme.fg(\"muted\", `\\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")})`;\n\t\t}\n\t}\n\n\tconst matchLimit = result.details?.matchLimitReached;\n\tconst truncation = result.details?.truncation;\n\tconst linesTruncated = result.details?.linesTruncated;\n\tif (matchLimit || truncation?.truncated || linesTruncated) {\n\t\tconst warnings: string[] = [];\n\t\tif (matchLimit) warnings.push(`${matchLimit} matches limit`);\n\t\tif (truncation?.truncated) warnings.push(`${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);\n\t\tif (linesTruncated) warnings.push(\"some lines truncated\");\n\t\ttext += `\\n${theme.fg(\"warning\", `[Truncated: ${warnings.join(\", \")}]`)}`;\n\t}\n\treturn text;\n}\n\nexport function createGrepToolDefinition(\n\toperations: ToolOperations,\n\t_options?: GrepToolOptions,\n): ToolDefinition<typeof grepSchema, GrepToolDetails | undefined> {\n\tconst ops = operations;\n\tconst cwd = operations.cwd;\n\treturn {\n\t\tname: \"grep\",\n\t\tlabel: \"grep\",\n\t\tdescription: `Search file contents for a pattern. Returns matching lines with file paths and line numbers. Respects .gitignore. Output is truncated to ${DEFAULT_LIMIT} matches or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). Long lines are truncated to ${GREP_MAX_LINE_LENGTH} chars.`,\n\t\tpromptSnippet: \"Search file contents for patterns (respects .gitignore)\",\n\t\tparameters: grepSchema,\n\t\tasync execute(\n\t\t\t_toolCallId,\n\t\t\t{\n\t\t\t\tpattern,\n\t\t\t\tpath: searchDir,\n\t\t\t\tglob,\n\t\t\t\tignoreCase,\n\t\t\t\tliteral,\n\t\t\t\tcontext,\n\t\t\t\tlimit,\n\t\t\t}: {\n\t\t\t\tpattern: string;\n\t\t\t\tpath?: string;\n\t\t\t\tglob?: string;\n\t\t\t\tignoreCase?: boolean;\n\t\t\t\tliteral?: boolean;\n\t\t\t\tcontext?: number;\n\t\t\t\tlimit?: number;\n\t\t\t},\n\t\t\tsignal?: AbortSignal,\n\t\t\t_onUpdate?,\n\t\t\t_ctx?,\n\t\t) {\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\treject(new Error(\"Operation aborted\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tlet settled = false;\n\t\t\t\tconst settle = (fn: () => void) => {\n\t\t\t\t\tif (!settled) {\n\t\t\t\t\t\tsettled = true;\n\t\t\t\t\t\tfn();\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\t(async () => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst searchPath = resolveToCwd(searchDir || \".\", cwd);\n\t\t\t\t\t\tlet isDirectory: boolean;\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tisDirectory = (await ops.stat(searchPath)).isDirectory();\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\tsettle(() => reject(new Error(`Path not found: ${searchPath}`)));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst contextValue = context && context > 0 ? context : 0;\n\t\t\t\t\t\tconst effectiveLimit = Math.max(1, limit ?? DEFAULT_LIMIT);\n\t\t\t\t\t\tconst formatPath = (filePath: string): string => {\n\t\t\t\t\t\t\tif (isDirectory) {\n\t\t\t\t\t\t\t\tconst relative = path.relative(searchPath, filePath);\n\t\t\t\t\t\t\t\tif (relative && !relative.startsWith(\"..\")) {\n\t\t\t\t\t\t\t\t\treturn relative.replace(/\\\\/g, \"/\");\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn path.basename(filePath);\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tconst fileCache = new Map<string, string[]>();\n\t\t\t\t\t\tconst getFileLines = async (filePath: string): Promise<string[]> => {\n\t\t\t\t\t\t\tlet lines = fileCache.get(filePath);\n\t\t\t\t\t\t\tif (!lines) {\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tconst content = (await ops.readFile(filePath)).toString(\"utf-8\");\n\t\t\t\t\t\t\t\t\tlines = content.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\").split(\"\\n\");\n\t\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t\tlines = [];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tfileCache.set(filePath, lines);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn lines;\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tlet linesTruncated = false;\n\t\t\t\t\t\tconst formatBlock = async (filePath: string, lineNumber: number): Promise<string[]> => {\n\t\t\t\t\t\t\tconst relativePath = formatPath(filePath);\n\t\t\t\t\t\t\tconst lines = await getFileLines(filePath);\n\t\t\t\t\t\t\tif (!lines.length) return [`${relativePath}:${lineNumber}: (unable to read file)`];\n\t\t\t\t\t\t\tconst block: string[] = [];\n\t\t\t\t\t\t\tconst start = contextValue > 0 ? Math.max(1, lineNumber - contextValue) : lineNumber;\n\t\t\t\t\t\t\tconst end = contextValue > 0 ? Math.min(lines.length, lineNumber + contextValue) : lineNumber;\n\t\t\t\t\t\t\tfor (let current = start; current <= end; current++) {\n\t\t\t\t\t\t\t\tconst lineText = lines[current - 1] ?? \"\";\n\t\t\t\t\t\t\t\tconst sanitized = lineText.replace(/\\r/g, \"\");\n\t\t\t\t\t\t\t\tconst isMatchLine = current === lineNumber;\n\t\t\t\t\t\t\t\t// Truncate long lines so grep output stays compact.\n\t\t\t\t\t\t\t\tconst { text: truncatedText, wasTruncated } = truncateLine(sanitized);\n\t\t\t\t\t\t\t\tif (wasTruncated) linesTruncated = true;\n\t\t\t\t\t\t\t\tif (isMatchLine) block.push(`${relativePath}:${current}: ${truncatedText}`);\n\t\t\t\t\t\t\t\telse block.push(`${relativePath}-${current}- ${truncatedText}`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn block;\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tif (ops.grep) {\n\t\t\t\t\t\t\tconst grepResult = await ops.grep({\n\t\t\t\t\t\t\t\tpattern,\n\t\t\t\t\t\t\t\tpath: searchPath,\n\t\t\t\t\t\t\t\tglob,\n\t\t\t\t\t\t\t\tignoreCase,\n\t\t\t\t\t\t\t\tliteral,\n\t\t\t\t\t\t\t\tlimit: effectiveLimit,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tisDirectory = grepResult.isDirectory;\n\t\t\t\t\t\t\tif (grepResult.matches.length === 0) {\n\t\t\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\t\t\tresolve({ content: [{ type: \"text\", text: \"No matches found\" }], details: undefined }),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst outputLines: string[] = [];\n\t\t\t\t\t\t\tfor (const match of grepResult.matches) {\n\t\t\t\t\t\t\t\tif (contextValue === 0 && match.lineText !== undefined) {\n\t\t\t\t\t\t\t\t\tconst relativePath = formatPath(match.filePath);\n\t\t\t\t\t\t\t\t\tconst sanitized = match.lineText\n\t\t\t\t\t\t\t\t\t\t.replace(/\\r\\n/g, \"\\n\")\n\t\t\t\t\t\t\t\t\t\t.replace(/\\r/g, \"\")\n\t\t\t\t\t\t\t\t\t\t.replace(/\\n$/, \"\");\n\t\t\t\t\t\t\t\t\tconst { text: truncatedText, wasTruncated } = truncateLine(sanitized);\n\t\t\t\t\t\t\t\t\tif (wasTruncated) linesTruncated = true;\n\t\t\t\t\t\t\t\t\toutputLines.push(`${relativePath}:${match.lineNumber}: ${truncatedText}`);\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tconst block = await formatBlock(match.filePath, match.lineNumber);\n\t\t\t\t\t\t\t\t\toutputLines.push(...block);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst rawOutput = outputLines.join(\"\\n\");\n\t\t\t\t\t\t\tconst truncation = truncateHead(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER });\n\t\t\t\t\t\t\tlet output = truncation.content;\n\t\t\t\t\t\t\tconst details: GrepToolDetails = {};\n\t\t\t\t\t\t\tconst notices: string[] = [];\n\t\t\t\t\t\t\tif (grepResult.matches.length >= effectiveLimit) {\n\t\t\t\t\t\t\t\tnotices.push(\n\t\t\t\t\t\t\t\t\t`${effectiveLimit} matches limit reached. Use limit=${effectiveLimit * 2} for more, or refine pattern`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tdetails.matchLimitReached = effectiveLimit;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (truncation.truncated) {\n\t\t\t\t\t\t\t\tnotices.push(`${formatSize(DEFAULT_MAX_BYTES)} limit reached`);\n\t\t\t\t\t\t\t\tdetails.truncation = truncation;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (linesTruncated) {\n\t\t\t\t\t\t\t\tnotices.push(\n\t\t\t\t\t\t\t\t\t`Some lines truncated to ${GREP_MAX_LINE_LENGTH} chars. Use read tool to see full lines`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tdetails.linesTruncated = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (notices.length > 0) output += `\\n\\n[${notices.join(\". \")}]`;\n\t\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: output }],\n\t\t\t\t\t\t\t\t\tdetails: Object.keys(details).length > 0 ? details : undefined,\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst rgPath = await ensureTool(\"rg\", true);\n\t\t\t\t\t\tif (!rgPath) {\n\t\t\t\t\t\t\tsettle(() => reject(new Error(\"ripgrep (rg) is not available and could not be downloaded\")));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst args: string[] = [\"--json\", \"--line-number\", \"--color=never\", \"--hidden\"];\n\t\t\t\t\t\tif (ignoreCase) args.push(\"--ignore-case\");\n\t\t\t\t\t\tif (literal) args.push(\"--fixed-strings\");\n\t\t\t\t\t\tif (glob) args.push(\"--glob\", glob);\n\t\t\t\t\t\targs.push(\"--\", pattern, searchPath);\n\n\t\t\t\t\t\tconst child = spawn(rgPath, args, { stdio: [\"ignore\", \"pipe\", \"pipe\"] });\n\t\t\t\t\t\tconst rl = createInterface({ input: child.stdout });\n\t\t\t\t\t\tlet stderr = \"\";\n\t\t\t\t\t\tlet matchCount = 0;\n\t\t\t\t\t\tlet matchLimitReached = false;\n\t\t\t\t\t\tlet aborted = false;\n\t\t\t\t\t\tlet killedDueToLimit = false;\n\t\t\t\t\t\tconst outputLines: string[] = [];\n\n\t\t\t\t\t\tconst cleanup = () => {\n\t\t\t\t\t\t\trl.close();\n\t\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\t};\n\t\t\t\t\t\tconst stopChild = (dueToLimit = false) => {\n\t\t\t\t\t\t\tif (!child.killed) {\n\t\t\t\t\t\t\t\tkilledDueToLimit = dueToLimit;\n\t\t\t\t\t\t\t\tchild.kill();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t};\n\t\t\t\t\t\tconst onAbort = () => {\n\t\t\t\t\t\t\taborted = true;\n\t\t\t\t\t\t\tstopChild();\n\t\t\t\t\t\t};\n\t\t\t\t\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t\t\t\tchild.stderr?.on(\"data\", (chunk) => {\n\t\t\t\t\t\t\tstderr += chunk.toString();\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\t// Collect matches during streaming, then format them after rg exits.\n\t\t\t\t\t\tconst matches: Array<{ filePath: string; lineNumber: number; lineText?: string }> = [];\n\t\t\t\t\t\trl.on(\"line\", (line) => {\n\t\t\t\t\t\t\tif (!line.trim() || matchCount >= effectiveLimit) return;\n\t\t\t\t\t\t\tlet event: any;\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tevent = JSON.parse(line);\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (event.type === \"match\") {\n\t\t\t\t\t\t\t\tmatchCount++;\n\t\t\t\t\t\t\t\tconst filePath = event.data?.path?.text;\n\t\t\t\t\t\t\t\tconst lineNumber = event.data?.line_number;\n\t\t\t\t\t\t\t\tconst lineText = event.data?.lines?.text;\n\t\t\t\t\t\t\t\tif (filePath && typeof lineNumber === \"number\")\n\t\t\t\t\t\t\t\t\tmatches.push({ filePath, lineNumber, lineText });\n\t\t\t\t\t\t\t\tif (matchCount >= effectiveLimit) {\n\t\t\t\t\t\t\t\t\tmatchLimitReached = true;\n\t\t\t\t\t\t\t\t\tstopChild(true);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tchild.on(\"error\", (error) => {\n\t\t\t\t\t\t\tcleanup();\n\t\t\t\t\t\t\tsettle(() => reject(new Error(`Failed to run ripgrep: ${error.message}`)));\n\t\t\t\t\t\t});\n\t\t\t\t\t\tchild.on(\"close\", async (code) => {\n\t\t\t\t\t\t\tcleanup();\n\t\t\t\t\t\t\tif (aborted) {\n\t\t\t\t\t\t\t\tsettle(() => reject(new Error(\"Operation aborted\")));\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (!killedDueToLimit && code !== 0 && code !== 1) {\n\t\t\t\t\t\t\t\tconst errorMsg = stderr.trim() || `ripgrep exited with code ${code}`;\n\t\t\t\t\t\t\t\tsettle(() => reject(new Error(errorMsg)));\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (matchCount === 0) {\n\t\t\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\t\t\tresolve({ content: [{ type: \"text\", text: \"No matches found\" }], details: undefined }),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Format matches after streaming finishes so custom readFile() backends can be async.\n\t\t\t\t\t\t\tfor (const match of matches) {\n\t\t\t\t\t\t\t\tif (contextValue === 0 && match.lineText !== undefined) {\n\t\t\t\t\t\t\t\t\tconst relativePath = formatPath(match.filePath);\n\t\t\t\t\t\t\t\t\tconst sanitized = match.lineText\n\t\t\t\t\t\t\t\t\t\t.replace(/\\r\\n/g, \"\\n\")\n\t\t\t\t\t\t\t\t\t\t.replace(/\\r/g, \"\")\n\t\t\t\t\t\t\t\t\t\t.replace(/\\n$/, \"\");\n\t\t\t\t\t\t\t\t\tconst { text: truncatedText, wasTruncated } = truncateLine(sanitized);\n\t\t\t\t\t\t\t\t\tif (wasTruncated) linesTruncated = true;\n\t\t\t\t\t\t\t\t\toutputLines.push(`${relativePath}:${match.lineNumber}: ${truncatedText}`);\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tconst block = await formatBlock(match.filePath, match.lineNumber);\n\t\t\t\t\t\t\t\t\toutputLines.push(...block);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tconst rawOutput = outputLines.join(\"\\n\");\n\t\t\t\t\t\t\t// Apply byte truncation. There is no line limit here because the match limit already capped rows.\n\t\t\t\t\t\t\tconst truncation = truncateHead(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER });\n\t\t\t\t\t\t\tlet output = truncation.content;\n\t\t\t\t\t\t\tconst details: GrepToolDetails = {};\n\t\t\t\t\t\t\t// Build actionable notices for truncation and match limits.\n\t\t\t\t\t\t\tconst notices: string[] = [];\n\t\t\t\t\t\t\tif (matchLimitReached) {\n\t\t\t\t\t\t\t\tnotices.push(\n\t\t\t\t\t\t\t\t\t`${effectiveLimit} matches limit reached. Use limit=${effectiveLimit * 2} for more, or refine pattern`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tdetails.matchLimitReached = effectiveLimit;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (truncation.truncated) {\n\t\t\t\t\t\t\t\tnotices.push(`${formatSize(DEFAULT_MAX_BYTES)} limit reached`);\n\t\t\t\t\t\t\t\tdetails.truncation = truncation;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (linesTruncated) {\n\t\t\t\t\t\t\t\tnotices.push(\n\t\t\t\t\t\t\t\t\t`Some lines truncated to ${GREP_MAX_LINE_LENGTH} chars. Use read tool to see full lines`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tdetails.linesTruncated = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (notices.length > 0) output += `\\n\\n[${notices.join(\". \")}]`;\n\t\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: output }],\n\t\t\t\t\t\t\t\t\tdetails: Object.keys(details).length > 0 ? details : undefined,\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t});\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tsettle(() => reject(err as Error));\n\t\t\t\t\t}\n\t\t\t\t})();\n\t\t\t});\n\t\t},\n\t\trenderCall(args, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatGrepCall(args, theme));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatGrepResult(result as any, options, theme, context.showImages));\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createGrepTool(operations: ToolOperations, options?: GrepToolOptions): AgentTool<typeof grepSchema> {\n\treturn wrapToolDefinition(createGrepToolDefinition(operations, options));\n}\n"]}
1
+ {"version":3,"file":"grep.d.ts","sourceRoot":"","sources":["../../../src/core/tools/grep.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAI3D,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAG5C,OAAO,KAAK,EAAE,cAAc,EAA2B,MAAM,wBAAwB,CAAC;AACtF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAItD,OAAO,EAIN,KAAK,gBAAgB,EAGrB,MAAM,eAAe,CAAC;AAEvB,QAAA,MAAM,UAAU;;;;;;;;EAYd,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AAGtD,MAAM,WAAW,eAAe;IAC/B,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,eAAe;CAAG;AAyDnC,wBAAgB,wBAAwB,CACvC,UAAU,EAAE,cAAc,EAC1B,QAAQ,CAAC,EAAE,eAAe,GACxB,cAAc,CAAC,OAAO,UAAU,EAAE,eAAe,GAAG,SAAS,CAAC,CA8ThE;AAED,wBAAgB,cAAc,CAAC,UAAU,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC,OAAO,UAAU,CAAC,CAElH","sourcesContent":["import { createInterface } from \"node:readline\";\nimport type { AgentTool } from \"@fleetagent/pi-agent-core\";\nimport { Text } from \"@fleetagent/pi-tui\";\nimport { spawn } from \"child_process\";\nimport path from \"path\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport { ensureTool } from \"../../utils/tools-manager.ts\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../extensions/types.ts\";\nimport type { ToolOperations } from \"./operations.ts\";\nimport { resolveToCwd } from \"./path-utils.ts\";\nimport { formatBackendIcon, getTextOutput, invalidArgText, shortenPath, str } from \"./render-utils.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\nimport {\n\tDEFAULT_MAX_BYTES,\n\tformatSize,\n\tGREP_MAX_LINE_LENGTH,\n\ttype TruncationResult,\n\ttruncateHead,\n\ttruncateLine,\n} from \"./truncate.ts\";\n\nconst grepSchema = Type.Object({\n\tpattern: Type.String({ description: \"Search pattern (regex or literal string)\" }),\n\tpath: Type.Optional(Type.String({ description: \"Directory or file to search (default: current directory)\" })),\n\tglob: Type.Optional(Type.String({ description: \"Filter files by glob pattern, e.g. '*.ts' or '**/*.spec.ts'\" })),\n\tignoreCase: Type.Optional(Type.Boolean({ description: \"Case-insensitive search (default: false)\" })),\n\tliteral: Type.Optional(\n\t\tType.Boolean({ description: \"Treat pattern as literal string instead of regex (default: false)\" }),\n\t),\n\tcontext: Type.Optional(\n\t\tType.Number({ description: \"Number of lines to show before and after each match (default: 0)\" }),\n\t),\n\tlimit: Type.Optional(Type.Number({ description: \"Maximum number of matches to return (default: 100)\" })),\n});\n\nexport type GrepToolInput = Static<typeof grepSchema>;\nconst DEFAULT_LIMIT = 100;\n\nexport interface GrepToolDetails {\n\ttruncation?: TruncationResult;\n\tmatchLimitReached?: number;\n\tlinesTruncated?: boolean;\n}\n\nexport interface GrepToolOptions {}\n\nfunction formatGrepCall(\n\targs: { pattern: string; path?: string; glob?: string; limit?: number } | undefined,\n\ttheme: typeof import(\"../../modes/interactive/theme/theme.ts\").theme,\n): string {\n\tconst pattern = str(args?.pattern);\n\tconst rawPath = str(args?.path);\n\tconst path = rawPath !== null ? shortenPath(rawPath || \".\") : null;\n\tconst glob = str(args?.glob);\n\tconst limit = args?.limit;\n\tconst invalidArg = invalidArgText(theme);\n\tlet text =\n\t\ttheme.fg(\"toolTitle\", theme.bold(\"grep\")) +\n\t\t\" \" +\n\t\t(pattern === null ? invalidArg : theme.fg(\"accent\", `/${pattern || \"\"}/`)) +\n\t\ttheme.fg(\"toolOutput\", ` in ${path === null ? invalidArg : path}`);\n\tif (glob) text += theme.fg(\"toolOutput\", ` (${glob})`);\n\tif (limit !== undefined) text += theme.fg(\"toolOutput\", ` limit ${limit}`);\n\treturn text;\n}\n\nfunction formatGrepResult(\n\tresult: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tdetails?: GrepToolDetails;\n\t},\n\toptions: ToolRenderResultOptions,\n\ttheme: typeof import(\"../../modes/interactive/theme/theme.ts\").theme,\n\tshowImages: boolean,\n): string {\n\tconst output = getTextOutput(result, showImages).trim();\n\tlet text = \"\";\n\tif (output) {\n\t\tconst lines = output.split(\"\\n\");\n\t\tconst maxLines = options.expanded ? lines.length : 15;\n\t\tconst displayLines = lines.slice(0, maxLines);\n\t\tconst remaining = lines.length - maxLines;\n\t\ttext += `\\n${displayLines.map((line) => theme.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n\t\tif (remaining > 0) {\n\t\t\ttext += `${theme.fg(\"muted\", `\\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")})`;\n\t\t}\n\t}\n\n\tconst matchLimit = result.details?.matchLimitReached;\n\tconst truncation = result.details?.truncation;\n\tconst linesTruncated = result.details?.linesTruncated;\n\tif (matchLimit || truncation?.truncated || linesTruncated) {\n\t\tconst warnings: string[] = [];\n\t\tif (matchLimit) warnings.push(`${matchLimit} matches limit`);\n\t\tif (truncation?.truncated) warnings.push(`${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);\n\t\tif (linesTruncated) warnings.push(\"some lines truncated\");\n\t\ttext += `\\n${theme.fg(\"warning\", `[Truncated: ${warnings.join(\", \")}]`)}`;\n\t}\n\treturn text;\n}\n\nexport function createGrepToolDefinition(\n\toperations: ToolOperations,\n\t_options?: GrepToolOptions,\n): ToolDefinition<typeof grepSchema, GrepToolDetails | undefined> {\n\tconst ops = operations;\n\tconst cwd = operations.cwd;\n\treturn {\n\t\tname: \"grep\",\n\t\tlabel: \"grep\",\n\t\tdescription: `Search file contents for a pattern. Returns matching lines with file paths and line numbers. Respects .gitignore. Output is truncated to ${DEFAULT_LIMIT} matches or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). Long lines are truncated to ${GREP_MAX_LINE_LENGTH} chars.`,\n\t\tpromptSnippet: \"Search file contents for patterns (respects .gitignore)\",\n\t\tparameters: grepSchema,\n\t\tasync execute(\n\t\t\t_toolCallId,\n\t\t\t{\n\t\t\t\tpattern,\n\t\t\t\tpath: searchDir,\n\t\t\t\tglob,\n\t\t\t\tignoreCase,\n\t\t\t\tliteral,\n\t\t\t\tcontext,\n\t\t\t\tlimit,\n\t\t\t}: {\n\t\t\t\tpattern: string;\n\t\t\t\tpath?: string;\n\t\t\t\tglob?: string;\n\t\t\t\tignoreCase?: boolean;\n\t\t\t\tliteral?: boolean;\n\t\t\t\tcontext?: number;\n\t\t\t\tlimit?: number;\n\t\t\t},\n\t\t\tsignal?: AbortSignal,\n\t\t\t_onUpdate?,\n\t\t\t_ctx?,\n\t\t) {\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\treject(new Error(\"Operation aborted\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tlet settled = false;\n\t\t\t\tconst settle = (fn: () => void) => {\n\t\t\t\t\tif (!settled) {\n\t\t\t\t\t\tsettled = true;\n\t\t\t\t\t\tfn();\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\t(async () => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst searchPath = resolveToCwd(searchDir || \".\", cwd);\n\t\t\t\t\t\tlet isDirectory: boolean;\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tisDirectory = (await ops.stat(searchPath)).isDirectory();\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\tsettle(() => reject(new Error(`Path not found: ${searchPath}`)));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst contextValue = context && context > 0 ? context : 0;\n\t\t\t\t\t\tconst effectiveLimit = Math.max(1, limit ?? DEFAULT_LIMIT);\n\t\t\t\t\t\tconst formatPath = (filePath: string): string => {\n\t\t\t\t\t\t\tif (isDirectory) {\n\t\t\t\t\t\t\t\tconst relative = path.relative(searchPath, filePath);\n\t\t\t\t\t\t\t\tif (relative && !relative.startsWith(\"..\")) {\n\t\t\t\t\t\t\t\t\treturn relative.replace(/\\\\/g, \"/\");\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn path.basename(filePath);\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tconst fileCache = new Map<string, string[]>();\n\t\t\t\t\t\tconst getFileLines = async (filePath: string): Promise<string[]> => {\n\t\t\t\t\t\t\tlet lines = fileCache.get(filePath);\n\t\t\t\t\t\t\tif (!lines) {\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tconst content = (await ops.readFile(filePath)).toString(\"utf-8\");\n\t\t\t\t\t\t\t\t\tlines = content.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\").split(\"\\n\");\n\t\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t\tlines = [];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tfileCache.set(filePath, lines);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn lines;\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tlet linesTruncated = false;\n\t\t\t\t\t\tconst formatBlock = async (filePath: string, lineNumber: number): Promise<string[]> => {\n\t\t\t\t\t\t\tconst relativePath = formatPath(filePath);\n\t\t\t\t\t\t\tconst lines = await getFileLines(filePath);\n\t\t\t\t\t\t\tif (!lines.length) return [`${relativePath}:${lineNumber}: (unable to read file)`];\n\t\t\t\t\t\t\tconst block: string[] = [];\n\t\t\t\t\t\t\tconst start = contextValue > 0 ? Math.max(1, lineNumber - contextValue) : lineNumber;\n\t\t\t\t\t\t\tconst end = contextValue > 0 ? Math.min(lines.length, lineNumber + contextValue) : lineNumber;\n\t\t\t\t\t\t\tfor (let current = start; current <= end; current++) {\n\t\t\t\t\t\t\t\tconst lineText = lines[current - 1] ?? \"\";\n\t\t\t\t\t\t\t\tconst sanitized = lineText.replace(/\\r/g, \"\");\n\t\t\t\t\t\t\t\tconst isMatchLine = current === lineNumber;\n\t\t\t\t\t\t\t\t// Truncate long lines so grep output stays compact.\n\t\t\t\t\t\t\t\tconst { text: truncatedText, wasTruncated } = truncateLine(sanitized);\n\t\t\t\t\t\t\t\tif (wasTruncated) linesTruncated = true;\n\t\t\t\t\t\t\t\tif (isMatchLine) block.push(`${relativePath}:${current}: ${truncatedText}`);\n\t\t\t\t\t\t\t\telse block.push(`${relativePath}-${current}- ${truncatedText}`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn block;\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tif (ops.grep) {\n\t\t\t\t\t\t\tconst grepResult = await ops.grep({\n\t\t\t\t\t\t\t\tpattern,\n\t\t\t\t\t\t\t\tpath: searchPath,\n\t\t\t\t\t\t\t\tglob,\n\t\t\t\t\t\t\t\tignoreCase,\n\t\t\t\t\t\t\t\tliteral,\n\t\t\t\t\t\t\t\tlimit: effectiveLimit,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tisDirectory = grepResult.isDirectory;\n\t\t\t\t\t\t\tif (grepResult.matches.length === 0) {\n\t\t\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\t\t\tresolve({ content: [{ type: \"text\", text: \"No matches found\" }], details: undefined }),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst outputLines: string[] = [];\n\t\t\t\t\t\t\tfor (const match of grepResult.matches) {\n\t\t\t\t\t\t\t\tif (contextValue === 0 && match.lineText !== undefined) {\n\t\t\t\t\t\t\t\t\tconst relativePath = formatPath(match.filePath);\n\t\t\t\t\t\t\t\t\tconst sanitized = match.lineText\n\t\t\t\t\t\t\t\t\t\t.replace(/\\r\\n/g, \"\\n\")\n\t\t\t\t\t\t\t\t\t\t.replace(/\\r/g, \"\")\n\t\t\t\t\t\t\t\t\t\t.replace(/\\n$/, \"\");\n\t\t\t\t\t\t\t\t\tconst { text: truncatedText, wasTruncated } = truncateLine(sanitized);\n\t\t\t\t\t\t\t\t\tif (wasTruncated) linesTruncated = true;\n\t\t\t\t\t\t\t\t\toutputLines.push(`${relativePath}:${match.lineNumber}: ${truncatedText}`);\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tconst block = await formatBlock(match.filePath, match.lineNumber);\n\t\t\t\t\t\t\t\t\toutputLines.push(...block);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst rawOutput = outputLines.join(\"\\n\");\n\t\t\t\t\t\t\tconst truncation = truncateHead(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER });\n\t\t\t\t\t\t\tlet output = truncation.content;\n\t\t\t\t\t\t\tconst details: GrepToolDetails = {};\n\t\t\t\t\t\t\tconst notices: string[] = [];\n\t\t\t\t\t\t\tif (grepResult.matches.length >= effectiveLimit) {\n\t\t\t\t\t\t\t\tnotices.push(\n\t\t\t\t\t\t\t\t\t`${effectiveLimit} matches limit reached. Use limit=${effectiveLimit * 2} for more, or refine pattern`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tdetails.matchLimitReached = effectiveLimit;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (truncation.truncated) {\n\t\t\t\t\t\t\t\tnotices.push(`${formatSize(DEFAULT_MAX_BYTES)} limit reached`);\n\t\t\t\t\t\t\t\tdetails.truncation = truncation;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (linesTruncated) {\n\t\t\t\t\t\t\t\tnotices.push(\n\t\t\t\t\t\t\t\t\t`Some lines truncated to ${GREP_MAX_LINE_LENGTH} chars. Use read tool to see full lines`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tdetails.linesTruncated = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (notices.length > 0) output += `\\n\\n[${notices.join(\". \")}]`;\n\t\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: output }],\n\t\t\t\t\t\t\t\t\tdetails: Object.keys(details).length > 0 ? details : undefined,\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst rgPath = await ensureTool(\"rg\", true);\n\t\t\t\t\t\tif (!rgPath) {\n\t\t\t\t\t\t\tsettle(() => reject(new Error(\"ripgrep (rg) is not available and could not be downloaded\")));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst args: string[] = [\"--json\", \"--line-number\", \"--color=never\", \"--hidden\"];\n\t\t\t\t\t\tif (ignoreCase) args.push(\"--ignore-case\");\n\t\t\t\t\t\tif (literal) args.push(\"--fixed-strings\");\n\t\t\t\t\t\tif (glob) args.push(\"--glob\", glob);\n\t\t\t\t\t\targs.push(\"--\", pattern, searchPath);\n\n\t\t\t\t\t\tconst child = spawn(rgPath, args, { stdio: [\"ignore\", \"pipe\", \"pipe\"] });\n\t\t\t\t\t\tconst rl = createInterface({ input: child.stdout });\n\t\t\t\t\t\tlet stderr = \"\";\n\t\t\t\t\t\tlet matchCount = 0;\n\t\t\t\t\t\tlet matchLimitReached = false;\n\t\t\t\t\t\tlet aborted = false;\n\t\t\t\t\t\tlet killedDueToLimit = false;\n\t\t\t\t\t\tconst outputLines: string[] = [];\n\n\t\t\t\t\t\tconst cleanup = () => {\n\t\t\t\t\t\t\trl.close();\n\t\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\t};\n\t\t\t\t\t\tconst stopChild = (dueToLimit = false) => {\n\t\t\t\t\t\t\tif (!child.killed) {\n\t\t\t\t\t\t\t\tkilledDueToLimit = dueToLimit;\n\t\t\t\t\t\t\t\tchild.kill();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t};\n\t\t\t\t\t\tconst onAbort = () => {\n\t\t\t\t\t\t\taborted = true;\n\t\t\t\t\t\t\tstopChild();\n\t\t\t\t\t\t};\n\t\t\t\t\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t\t\t\tchild.stderr?.on(\"data\", (chunk) => {\n\t\t\t\t\t\t\tstderr += chunk.toString();\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\t// Collect matches during streaming, then format them after rg exits.\n\t\t\t\t\t\tconst matches: Array<{ filePath: string; lineNumber: number; lineText?: string }> = [];\n\t\t\t\t\t\trl.on(\"line\", (line) => {\n\t\t\t\t\t\t\tif (!line.trim() || matchCount >= effectiveLimit) return;\n\t\t\t\t\t\t\tlet event: any;\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tevent = JSON.parse(line);\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (event.type === \"match\") {\n\t\t\t\t\t\t\t\tmatchCount++;\n\t\t\t\t\t\t\t\tconst filePath = event.data?.path?.text;\n\t\t\t\t\t\t\t\tconst lineNumber = event.data?.line_number;\n\t\t\t\t\t\t\t\tconst lineText = event.data?.lines?.text;\n\t\t\t\t\t\t\t\tif (filePath && typeof lineNumber === \"number\")\n\t\t\t\t\t\t\t\t\tmatches.push({ filePath, lineNumber, lineText });\n\t\t\t\t\t\t\t\tif (matchCount >= effectiveLimit) {\n\t\t\t\t\t\t\t\t\tmatchLimitReached = true;\n\t\t\t\t\t\t\t\t\tstopChild(true);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tchild.on(\"error\", (error) => {\n\t\t\t\t\t\t\tcleanup();\n\t\t\t\t\t\t\tsettle(() => reject(new Error(`Failed to run ripgrep: ${error.message}`)));\n\t\t\t\t\t\t});\n\t\t\t\t\t\tchild.on(\"close\", async (code) => {\n\t\t\t\t\t\t\tcleanup();\n\t\t\t\t\t\t\tif (aborted) {\n\t\t\t\t\t\t\t\tsettle(() => reject(new Error(\"Operation aborted\")));\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (!killedDueToLimit && code !== 0 && code !== 1) {\n\t\t\t\t\t\t\t\tconst errorMsg = stderr.trim() || `ripgrep exited with code ${code}`;\n\t\t\t\t\t\t\t\tsettle(() => reject(new Error(errorMsg)));\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (matchCount === 0) {\n\t\t\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\t\t\tresolve({ content: [{ type: \"text\", text: \"No matches found\" }], details: undefined }),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Format matches after streaming finishes so custom readFile() backends can be async.\n\t\t\t\t\t\t\tfor (const match of matches) {\n\t\t\t\t\t\t\t\tif (contextValue === 0 && match.lineText !== undefined) {\n\t\t\t\t\t\t\t\t\tconst relativePath = formatPath(match.filePath);\n\t\t\t\t\t\t\t\t\tconst sanitized = match.lineText\n\t\t\t\t\t\t\t\t\t\t.replace(/\\r\\n/g, \"\\n\")\n\t\t\t\t\t\t\t\t\t\t.replace(/\\r/g, \"\")\n\t\t\t\t\t\t\t\t\t\t.replace(/\\n$/, \"\");\n\t\t\t\t\t\t\t\t\tconst { text: truncatedText, wasTruncated } = truncateLine(sanitized);\n\t\t\t\t\t\t\t\t\tif (wasTruncated) linesTruncated = true;\n\t\t\t\t\t\t\t\t\toutputLines.push(`${relativePath}:${match.lineNumber}: ${truncatedText}`);\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tconst block = await formatBlock(match.filePath, match.lineNumber);\n\t\t\t\t\t\t\t\t\toutputLines.push(...block);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tconst rawOutput = outputLines.join(\"\\n\");\n\t\t\t\t\t\t\t// Apply byte truncation. There is no line limit here because the match limit already capped rows.\n\t\t\t\t\t\t\tconst truncation = truncateHead(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER });\n\t\t\t\t\t\t\tlet output = truncation.content;\n\t\t\t\t\t\t\tconst details: GrepToolDetails = {};\n\t\t\t\t\t\t\t// Build actionable notices for truncation and match limits.\n\t\t\t\t\t\t\tconst notices: string[] = [];\n\t\t\t\t\t\t\tif (matchLimitReached) {\n\t\t\t\t\t\t\t\tnotices.push(\n\t\t\t\t\t\t\t\t\t`${effectiveLimit} matches limit reached. Use limit=${effectiveLimit * 2} for more, or refine pattern`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tdetails.matchLimitReached = effectiveLimit;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (truncation.truncated) {\n\t\t\t\t\t\t\t\tnotices.push(`${formatSize(DEFAULT_MAX_BYTES)} limit reached`);\n\t\t\t\t\t\t\t\tdetails.truncation = truncation;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (linesTruncated) {\n\t\t\t\t\t\t\t\tnotices.push(\n\t\t\t\t\t\t\t\t\t`Some lines truncated to ${GREP_MAX_LINE_LENGTH} chars. Use read tool to see full lines`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tdetails.linesTruncated = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (notices.length > 0) output += `\\n\\n[${notices.join(\". \")}]`;\n\t\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: output }],\n\t\t\t\t\t\t\t\t\tdetails: Object.keys(details).length > 0 ? details : undefined,\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t});\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tsettle(() => reject(err as Error));\n\t\t\t\t\t}\n\t\t\t\t})();\n\t\t\t});\n\t\t},\n\t\trenderCall(args, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatBackendIcon(ops.getBackendInfo?.(), theme) + formatGrepCall(args, theme));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatGrepResult(result as any, options, theme, context.showImages));\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createGrepTool(operations: ToolOperations, options?: GrepToolOptions): AgentTool<typeof grepSchema> {\n\treturn wrapToolDefinition(createGrepToolDefinition(operations, options));\n}\n"]}
@@ -6,7 +6,7 @@ import { Type } from "typebox";
6
6
  import { keyHint } from "../../modes/interactive/components/keybinding-hints.js";
7
7
  import { ensureTool } from "../../utils/tools-manager.js";
8
8
  import { resolveToCwd } from "./path-utils.js";
9
- import { getTextOutput, invalidArgText, shortenPath, str } from "./render-utils.js";
9
+ import { formatBackendIcon, getTextOutput, invalidArgText, shortenPath, str } from "./render-utils.js";
10
10
  import { wrapToolDefinition } from "./tool-definition-wrapper.js";
11
11
  import { DEFAULT_MAX_BYTES, formatSize, GREP_MAX_LINE_LENGTH, truncateHead, truncateLine, } from "./truncate.js";
12
12
  const grepSchema = Type.Object({
@@ -340,7 +340,7 @@ export function createGrepToolDefinition(operations, _options) {
340
340
  },
341
341
  renderCall(args, theme, context) {
342
342
  const text = context.lastComponent ?? new Text("", 0, 0);
343
- text.setText(formatGrepCall(args, theme));
343
+ text.setText(formatBackendIcon(ops.getBackendInfo?.(), theme) + formatGrepCall(args, theme));
344
344
  return text;
345
345
  },
346
346
  renderResult(result, options, theme, context) {
@@ -1 +1 @@
1
- {"version":3,"file":"grep.js","sourceRoot":"","sources":["../../../src/core/tools/grep.ts"],"names":[],"mappings":"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","sourcesContent":["import { createInterface } from \"node:readline\";\nimport type { AgentTool } from \"@fleetagent/pi-agent-core\";\nimport { Text } from \"@fleetagent/pi-tui\";\nimport { spawn } from \"child_process\";\nimport path from \"path\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport { ensureTool } from \"../../utils/tools-manager.ts\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../extensions/types.ts\";\nimport type { ToolOperations } from \"./operations.ts\";\nimport { resolveToCwd } from \"./path-utils.ts\";\nimport { getTextOutput, invalidArgText, shortenPath, str } from \"./render-utils.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\nimport {\n\tDEFAULT_MAX_BYTES,\n\tformatSize,\n\tGREP_MAX_LINE_LENGTH,\n\ttype TruncationResult,\n\ttruncateHead,\n\ttruncateLine,\n} from \"./truncate.ts\";\n\nconst grepSchema = Type.Object({\n\tpattern: Type.String({ description: \"Search pattern (regex or literal string)\" }),\n\tpath: Type.Optional(Type.String({ description: \"Directory or file to search (default: current directory)\" })),\n\tglob: Type.Optional(Type.String({ description: \"Filter files by glob pattern, e.g. '*.ts' or '**/*.spec.ts'\" })),\n\tignoreCase: Type.Optional(Type.Boolean({ description: \"Case-insensitive search (default: false)\" })),\n\tliteral: Type.Optional(\n\t\tType.Boolean({ description: \"Treat pattern as literal string instead of regex (default: false)\" }),\n\t),\n\tcontext: Type.Optional(\n\t\tType.Number({ description: \"Number of lines to show before and after each match (default: 0)\" }),\n\t),\n\tlimit: Type.Optional(Type.Number({ description: \"Maximum number of matches to return (default: 100)\" })),\n});\n\nexport type GrepToolInput = Static<typeof grepSchema>;\nconst DEFAULT_LIMIT = 100;\n\nexport interface GrepToolDetails {\n\ttruncation?: TruncationResult;\n\tmatchLimitReached?: number;\n\tlinesTruncated?: boolean;\n}\n\nexport interface GrepToolOptions {}\n\nfunction formatGrepCall(\n\targs: { pattern: string; path?: string; glob?: string; limit?: number } | undefined,\n\ttheme: typeof import(\"../../modes/interactive/theme/theme.ts\").theme,\n): string {\n\tconst pattern = str(args?.pattern);\n\tconst rawPath = str(args?.path);\n\tconst path = rawPath !== null ? shortenPath(rawPath || \".\") : null;\n\tconst glob = str(args?.glob);\n\tconst limit = args?.limit;\n\tconst invalidArg = invalidArgText(theme);\n\tlet text =\n\t\ttheme.fg(\"toolTitle\", theme.bold(\"grep\")) +\n\t\t\" \" +\n\t\t(pattern === null ? invalidArg : theme.fg(\"accent\", `/${pattern || \"\"}/`)) +\n\t\ttheme.fg(\"toolOutput\", ` in ${path === null ? invalidArg : path}`);\n\tif (glob) text += theme.fg(\"toolOutput\", ` (${glob})`);\n\tif (limit !== undefined) text += theme.fg(\"toolOutput\", ` limit ${limit}`);\n\treturn text;\n}\n\nfunction formatGrepResult(\n\tresult: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tdetails?: GrepToolDetails;\n\t},\n\toptions: ToolRenderResultOptions,\n\ttheme: typeof import(\"../../modes/interactive/theme/theme.ts\").theme,\n\tshowImages: boolean,\n): string {\n\tconst output = getTextOutput(result, showImages).trim();\n\tlet text = \"\";\n\tif (output) {\n\t\tconst lines = output.split(\"\\n\");\n\t\tconst maxLines = options.expanded ? lines.length : 15;\n\t\tconst displayLines = lines.slice(0, maxLines);\n\t\tconst remaining = lines.length - maxLines;\n\t\ttext += `\\n${displayLines.map((line) => theme.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n\t\tif (remaining > 0) {\n\t\t\ttext += `${theme.fg(\"muted\", `\\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")})`;\n\t\t}\n\t}\n\n\tconst matchLimit = result.details?.matchLimitReached;\n\tconst truncation = result.details?.truncation;\n\tconst linesTruncated = result.details?.linesTruncated;\n\tif (matchLimit || truncation?.truncated || linesTruncated) {\n\t\tconst warnings: string[] = [];\n\t\tif (matchLimit) warnings.push(`${matchLimit} matches limit`);\n\t\tif (truncation?.truncated) warnings.push(`${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);\n\t\tif (linesTruncated) warnings.push(\"some lines truncated\");\n\t\ttext += `\\n${theme.fg(\"warning\", `[Truncated: ${warnings.join(\", \")}]`)}`;\n\t}\n\treturn text;\n}\n\nexport function createGrepToolDefinition(\n\toperations: ToolOperations,\n\t_options?: GrepToolOptions,\n): ToolDefinition<typeof grepSchema, GrepToolDetails | undefined> {\n\tconst ops = operations;\n\tconst cwd = operations.cwd;\n\treturn {\n\t\tname: \"grep\",\n\t\tlabel: \"grep\",\n\t\tdescription: `Search file contents for a pattern. Returns matching lines with file paths and line numbers. Respects .gitignore. Output is truncated to ${DEFAULT_LIMIT} matches or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). Long lines are truncated to ${GREP_MAX_LINE_LENGTH} chars.`,\n\t\tpromptSnippet: \"Search file contents for patterns (respects .gitignore)\",\n\t\tparameters: grepSchema,\n\t\tasync execute(\n\t\t\t_toolCallId,\n\t\t\t{\n\t\t\t\tpattern,\n\t\t\t\tpath: searchDir,\n\t\t\t\tglob,\n\t\t\t\tignoreCase,\n\t\t\t\tliteral,\n\t\t\t\tcontext,\n\t\t\t\tlimit,\n\t\t\t}: {\n\t\t\t\tpattern: string;\n\t\t\t\tpath?: string;\n\t\t\t\tglob?: string;\n\t\t\t\tignoreCase?: boolean;\n\t\t\t\tliteral?: boolean;\n\t\t\t\tcontext?: number;\n\t\t\t\tlimit?: number;\n\t\t\t},\n\t\t\tsignal?: AbortSignal,\n\t\t\t_onUpdate?,\n\t\t\t_ctx?,\n\t\t) {\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\treject(new Error(\"Operation aborted\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tlet settled = false;\n\t\t\t\tconst settle = (fn: () => void) => {\n\t\t\t\t\tif (!settled) {\n\t\t\t\t\t\tsettled = true;\n\t\t\t\t\t\tfn();\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\t(async () => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst searchPath = resolveToCwd(searchDir || \".\", cwd);\n\t\t\t\t\t\tlet isDirectory: boolean;\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tisDirectory = (await ops.stat(searchPath)).isDirectory();\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\tsettle(() => reject(new Error(`Path not found: ${searchPath}`)));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst contextValue = context && context > 0 ? context : 0;\n\t\t\t\t\t\tconst effectiveLimit = Math.max(1, limit ?? DEFAULT_LIMIT);\n\t\t\t\t\t\tconst formatPath = (filePath: string): string => {\n\t\t\t\t\t\t\tif (isDirectory) {\n\t\t\t\t\t\t\t\tconst relative = path.relative(searchPath, filePath);\n\t\t\t\t\t\t\t\tif (relative && !relative.startsWith(\"..\")) {\n\t\t\t\t\t\t\t\t\treturn relative.replace(/\\\\/g, \"/\");\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn path.basename(filePath);\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tconst fileCache = new Map<string, string[]>();\n\t\t\t\t\t\tconst getFileLines = async (filePath: string): Promise<string[]> => {\n\t\t\t\t\t\t\tlet lines = fileCache.get(filePath);\n\t\t\t\t\t\t\tif (!lines) {\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tconst content = (await ops.readFile(filePath)).toString(\"utf-8\");\n\t\t\t\t\t\t\t\t\tlines = content.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\").split(\"\\n\");\n\t\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t\tlines = [];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tfileCache.set(filePath, lines);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn lines;\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tlet linesTruncated = false;\n\t\t\t\t\t\tconst formatBlock = async (filePath: string, lineNumber: number): Promise<string[]> => {\n\t\t\t\t\t\t\tconst relativePath = formatPath(filePath);\n\t\t\t\t\t\t\tconst lines = await getFileLines(filePath);\n\t\t\t\t\t\t\tif (!lines.length) return [`${relativePath}:${lineNumber}: (unable to read file)`];\n\t\t\t\t\t\t\tconst block: string[] = [];\n\t\t\t\t\t\t\tconst start = contextValue > 0 ? Math.max(1, lineNumber - contextValue) : lineNumber;\n\t\t\t\t\t\t\tconst end = contextValue > 0 ? Math.min(lines.length, lineNumber + contextValue) : lineNumber;\n\t\t\t\t\t\t\tfor (let current = start; current <= end; current++) {\n\t\t\t\t\t\t\t\tconst lineText = lines[current - 1] ?? \"\";\n\t\t\t\t\t\t\t\tconst sanitized = lineText.replace(/\\r/g, \"\");\n\t\t\t\t\t\t\t\tconst isMatchLine = current === lineNumber;\n\t\t\t\t\t\t\t\t// Truncate long lines so grep output stays compact.\n\t\t\t\t\t\t\t\tconst { text: truncatedText, wasTruncated } = truncateLine(sanitized);\n\t\t\t\t\t\t\t\tif (wasTruncated) linesTruncated = true;\n\t\t\t\t\t\t\t\tif (isMatchLine) block.push(`${relativePath}:${current}: ${truncatedText}`);\n\t\t\t\t\t\t\t\telse block.push(`${relativePath}-${current}- ${truncatedText}`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn block;\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tif (ops.grep) {\n\t\t\t\t\t\t\tconst grepResult = await ops.grep({\n\t\t\t\t\t\t\t\tpattern,\n\t\t\t\t\t\t\t\tpath: searchPath,\n\t\t\t\t\t\t\t\tglob,\n\t\t\t\t\t\t\t\tignoreCase,\n\t\t\t\t\t\t\t\tliteral,\n\t\t\t\t\t\t\t\tlimit: effectiveLimit,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tisDirectory = grepResult.isDirectory;\n\t\t\t\t\t\t\tif (grepResult.matches.length === 0) {\n\t\t\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\t\t\tresolve({ content: [{ type: \"text\", text: \"No matches found\" }], details: undefined }),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst outputLines: string[] = [];\n\t\t\t\t\t\t\tfor (const match of grepResult.matches) {\n\t\t\t\t\t\t\t\tif (contextValue === 0 && match.lineText !== undefined) {\n\t\t\t\t\t\t\t\t\tconst relativePath = formatPath(match.filePath);\n\t\t\t\t\t\t\t\t\tconst sanitized = match.lineText\n\t\t\t\t\t\t\t\t\t\t.replace(/\\r\\n/g, \"\\n\")\n\t\t\t\t\t\t\t\t\t\t.replace(/\\r/g, \"\")\n\t\t\t\t\t\t\t\t\t\t.replace(/\\n$/, \"\");\n\t\t\t\t\t\t\t\t\tconst { text: truncatedText, wasTruncated } = truncateLine(sanitized);\n\t\t\t\t\t\t\t\t\tif (wasTruncated) linesTruncated = true;\n\t\t\t\t\t\t\t\t\toutputLines.push(`${relativePath}:${match.lineNumber}: ${truncatedText}`);\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tconst block = await formatBlock(match.filePath, match.lineNumber);\n\t\t\t\t\t\t\t\t\toutputLines.push(...block);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst rawOutput = outputLines.join(\"\\n\");\n\t\t\t\t\t\t\tconst truncation = truncateHead(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER });\n\t\t\t\t\t\t\tlet output = truncation.content;\n\t\t\t\t\t\t\tconst details: GrepToolDetails = {};\n\t\t\t\t\t\t\tconst notices: string[] = [];\n\t\t\t\t\t\t\tif (grepResult.matches.length >= effectiveLimit) {\n\t\t\t\t\t\t\t\tnotices.push(\n\t\t\t\t\t\t\t\t\t`${effectiveLimit} matches limit reached. Use limit=${effectiveLimit * 2} for more, or refine pattern`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tdetails.matchLimitReached = effectiveLimit;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (truncation.truncated) {\n\t\t\t\t\t\t\t\tnotices.push(`${formatSize(DEFAULT_MAX_BYTES)} limit reached`);\n\t\t\t\t\t\t\t\tdetails.truncation = truncation;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (linesTruncated) {\n\t\t\t\t\t\t\t\tnotices.push(\n\t\t\t\t\t\t\t\t\t`Some lines truncated to ${GREP_MAX_LINE_LENGTH} chars. Use read tool to see full lines`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tdetails.linesTruncated = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (notices.length > 0) output += `\\n\\n[${notices.join(\". \")}]`;\n\t\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: output }],\n\t\t\t\t\t\t\t\t\tdetails: Object.keys(details).length > 0 ? details : undefined,\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst rgPath = await ensureTool(\"rg\", true);\n\t\t\t\t\t\tif (!rgPath) {\n\t\t\t\t\t\t\tsettle(() => reject(new Error(\"ripgrep (rg) is not available and could not be downloaded\")));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst args: string[] = [\"--json\", \"--line-number\", \"--color=never\", \"--hidden\"];\n\t\t\t\t\t\tif (ignoreCase) args.push(\"--ignore-case\");\n\t\t\t\t\t\tif (literal) args.push(\"--fixed-strings\");\n\t\t\t\t\t\tif (glob) args.push(\"--glob\", glob);\n\t\t\t\t\t\targs.push(\"--\", pattern, searchPath);\n\n\t\t\t\t\t\tconst child = spawn(rgPath, args, { stdio: [\"ignore\", \"pipe\", \"pipe\"] });\n\t\t\t\t\t\tconst rl = createInterface({ input: child.stdout });\n\t\t\t\t\t\tlet stderr = \"\";\n\t\t\t\t\t\tlet matchCount = 0;\n\t\t\t\t\t\tlet matchLimitReached = false;\n\t\t\t\t\t\tlet aborted = false;\n\t\t\t\t\t\tlet killedDueToLimit = false;\n\t\t\t\t\t\tconst outputLines: string[] = [];\n\n\t\t\t\t\t\tconst cleanup = () => {\n\t\t\t\t\t\t\trl.close();\n\t\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\t};\n\t\t\t\t\t\tconst stopChild = (dueToLimit = false) => {\n\t\t\t\t\t\t\tif (!child.killed) {\n\t\t\t\t\t\t\t\tkilledDueToLimit = dueToLimit;\n\t\t\t\t\t\t\t\tchild.kill();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t};\n\t\t\t\t\t\tconst onAbort = () => {\n\t\t\t\t\t\t\taborted = true;\n\t\t\t\t\t\t\tstopChild();\n\t\t\t\t\t\t};\n\t\t\t\t\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t\t\t\tchild.stderr?.on(\"data\", (chunk) => {\n\t\t\t\t\t\t\tstderr += chunk.toString();\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\t// Collect matches during streaming, then format them after rg exits.\n\t\t\t\t\t\tconst matches: Array<{ filePath: string; lineNumber: number; lineText?: string }> = [];\n\t\t\t\t\t\trl.on(\"line\", (line) => {\n\t\t\t\t\t\t\tif (!line.trim() || matchCount >= effectiveLimit) return;\n\t\t\t\t\t\t\tlet event: any;\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tevent = JSON.parse(line);\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (event.type === \"match\") {\n\t\t\t\t\t\t\t\tmatchCount++;\n\t\t\t\t\t\t\t\tconst filePath = event.data?.path?.text;\n\t\t\t\t\t\t\t\tconst lineNumber = event.data?.line_number;\n\t\t\t\t\t\t\t\tconst lineText = event.data?.lines?.text;\n\t\t\t\t\t\t\t\tif (filePath && typeof lineNumber === \"number\")\n\t\t\t\t\t\t\t\t\tmatches.push({ filePath, lineNumber, lineText });\n\t\t\t\t\t\t\t\tif (matchCount >= effectiveLimit) {\n\t\t\t\t\t\t\t\t\tmatchLimitReached = true;\n\t\t\t\t\t\t\t\t\tstopChild(true);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tchild.on(\"error\", (error) => {\n\t\t\t\t\t\t\tcleanup();\n\t\t\t\t\t\t\tsettle(() => reject(new Error(`Failed to run ripgrep: ${error.message}`)));\n\t\t\t\t\t\t});\n\t\t\t\t\t\tchild.on(\"close\", async (code) => {\n\t\t\t\t\t\t\tcleanup();\n\t\t\t\t\t\t\tif (aborted) {\n\t\t\t\t\t\t\t\tsettle(() => reject(new Error(\"Operation aborted\")));\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (!killedDueToLimit && code !== 0 && code !== 1) {\n\t\t\t\t\t\t\t\tconst errorMsg = stderr.trim() || `ripgrep exited with code ${code}`;\n\t\t\t\t\t\t\t\tsettle(() => reject(new Error(errorMsg)));\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (matchCount === 0) {\n\t\t\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\t\t\tresolve({ content: [{ type: \"text\", text: \"No matches found\" }], details: undefined }),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Format matches after streaming finishes so custom readFile() backends can be async.\n\t\t\t\t\t\t\tfor (const match of matches) {\n\t\t\t\t\t\t\t\tif (contextValue === 0 && match.lineText !== undefined) {\n\t\t\t\t\t\t\t\t\tconst relativePath = formatPath(match.filePath);\n\t\t\t\t\t\t\t\t\tconst sanitized = match.lineText\n\t\t\t\t\t\t\t\t\t\t.replace(/\\r\\n/g, \"\\n\")\n\t\t\t\t\t\t\t\t\t\t.replace(/\\r/g, \"\")\n\t\t\t\t\t\t\t\t\t\t.replace(/\\n$/, \"\");\n\t\t\t\t\t\t\t\t\tconst { text: truncatedText, wasTruncated } = truncateLine(sanitized);\n\t\t\t\t\t\t\t\t\tif (wasTruncated) linesTruncated = true;\n\t\t\t\t\t\t\t\t\toutputLines.push(`${relativePath}:${match.lineNumber}: ${truncatedText}`);\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tconst block = await formatBlock(match.filePath, match.lineNumber);\n\t\t\t\t\t\t\t\t\toutputLines.push(...block);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tconst rawOutput = outputLines.join(\"\\n\");\n\t\t\t\t\t\t\t// Apply byte truncation. There is no line limit here because the match limit already capped rows.\n\t\t\t\t\t\t\tconst truncation = truncateHead(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER });\n\t\t\t\t\t\t\tlet output = truncation.content;\n\t\t\t\t\t\t\tconst details: GrepToolDetails = {};\n\t\t\t\t\t\t\t// Build actionable notices for truncation and match limits.\n\t\t\t\t\t\t\tconst notices: string[] = [];\n\t\t\t\t\t\t\tif (matchLimitReached) {\n\t\t\t\t\t\t\t\tnotices.push(\n\t\t\t\t\t\t\t\t\t`${effectiveLimit} matches limit reached. Use limit=${effectiveLimit * 2} for more, or refine pattern`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tdetails.matchLimitReached = effectiveLimit;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (truncation.truncated) {\n\t\t\t\t\t\t\t\tnotices.push(`${formatSize(DEFAULT_MAX_BYTES)} limit reached`);\n\t\t\t\t\t\t\t\tdetails.truncation = truncation;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (linesTruncated) {\n\t\t\t\t\t\t\t\tnotices.push(\n\t\t\t\t\t\t\t\t\t`Some lines truncated to ${GREP_MAX_LINE_LENGTH} chars. Use read tool to see full lines`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tdetails.linesTruncated = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (notices.length > 0) output += `\\n\\n[${notices.join(\". \")}]`;\n\t\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: output }],\n\t\t\t\t\t\t\t\t\tdetails: Object.keys(details).length > 0 ? details : undefined,\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t});\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tsettle(() => reject(err as Error));\n\t\t\t\t\t}\n\t\t\t\t})();\n\t\t\t});\n\t\t},\n\t\trenderCall(args, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatGrepCall(args, theme));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatGrepResult(result as any, options, theme, context.showImages));\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createGrepTool(operations: ToolOperations, options?: GrepToolOptions): AgentTool<typeof grepSchema> {\n\treturn wrapToolDefinition(createGrepToolDefinition(operations, options));\n}\n"]}
1
+ {"version":3,"file":"grep.js","sourceRoot":"","sources":["../../../src/core/tools/grep.ts"],"names":[],"mappings":"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","sourcesContent":["import { createInterface } from \"node:readline\";\nimport type { AgentTool } from \"@fleetagent/pi-agent-core\";\nimport { Text } from \"@fleetagent/pi-tui\";\nimport { spawn } from \"child_process\";\nimport path from \"path\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport { ensureTool } from \"../../utils/tools-manager.ts\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../extensions/types.ts\";\nimport type { ToolOperations } from \"./operations.ts\";\nimport { resolveToCwd } from \"./path-utils.ts\";\nimport { formatBackendIcon, getTextOutput, invalidArgText, shortenPath, str } from \"./render-utils.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\nimport {\n\tDEFAULT_MAX_BYTES,\n\tformatSize,\n\tGREP_MAX_LINE_LENGTH,\n\ttype TruncationResult,\n\ttruncateHead,\n\ttruncateLine,\n} from \"./truncate.ts\";\n\nconst grepSchema = Type.Object({\n\tpattern: Type.String({ description: \"Search pattern (regex or literal string)\" }),\n\tpath: Type.Optional(Type.String({ description: \"Directory or file to search (default: current directory)\" })),\n\tglob: Type.Optional(Type.String({ description: \"Filter files by glob pattern, e.g. '*.ts' or '**/*.spec.ts'\" })),\n\tignoreCase: Type.Optional(Type.Boolean({ description: \"Case-insensitive search (default: false)\" })),\n\tliteral: Type.Optional(\n\t\tType.Boolean({ description: \"Treat pattern as literal string instead of regex (default: false)\" }),\n\t),\n\tcontext: Type.Optional(\n\t\tType.Number({ description: \"Number of lines to show before and after each match (default: 0)\" }),\n\t),\n\tlimit: Type.Optional(Type.Number({ description: \"Maximum number of matches to return (default: 100)\" })),\n});\n\nexport type GrepToolInput = Static<typeof grepSchema>;\nconst DEFAULT_LIMIT = 100;\n\nexport interface GrepToolDetails {\n\ttruncation?: TruncationResult;\n\tmatchLimitReached?: number;\n\tlinesTruncated?: boolean;\n}\n\nexport interface GrepToolOptions {}\n\nfunction formatGrepCall(\n\targs: { pattern: string; path?: string; glob?: string; limit?: number } | undefined,\n\ttheme: typeof import(\"../../modes/interactive/theme/theme.ts\").theme,\n): string {\n\tconst pattern = str(args?.pattern);\n\tconst rawPath = str(args?.path);\n\tconst path = rawPath !== null ? shortenPath(rawPath || \".\") : null;\n\tconst glob = str(args?.glob);\n\tconst limit = args?.limit;\n\tconst invalidArg = invalidArgText(theme);\n\tlet text =\n\t\ttheme.fg(\"toolTitle\", theme.bold(\"grep\")) +\n\t\t\" \" +\n\t\t(pattern === null ? invalidArg : theme.fg(\"accent\", `/${pattern || \"\"}/`)) +\n\t\ttheme.fg(\"toolOutput\", ` in ${path === null ? invalidArg : path}`);\n\tif (glob) text += theme.fg(\"toolOutput\", ` (${glob})`);\n\tif (limit !== undefined) text += theme.fg(\"toolOutput\", ` limit ${limit}`);\n\treturn text;\n}\n\nfunction formatGrepResult(\n\tresult: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tdetails?: GrepToolDetails;\n\t},\n\toptions: ToolRenderResultOptions,\n\ttheme: typeof import(\"../../modes/interactive/theme/theme.ts\").theme,\n\tshowImages: boolean,\n): string {\n\tconst output = getTextOutput(result, showImages).trim();\n\tlet text = \"\";\n\tif (output) {\n\t\tconst lines = output.split(\"\\n\");\n\t\tconst maxLines = options.expanded ? lines.length : 15;\n\t\tconst displayLines = lines.slice(0, maxLines);\n\t\tconst remaining = lines.length - maxLines;\n\t\ttext += `\\n${displayLines.map((line) => theme.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n\t\tif (remaining > 0) {\n\t\t\ttext += `${theme.fg(\"muted\", `\\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")})`;\n\t\t}\n\t}\n\n\tconst matchLimit = result.details?.matchLimitReached;\n\tconst truncation = result.details?.truncation;\n\tconst linesTruncated = result.details?.linesTruncated;\n\tif (matchLimit || truncation?.truncated || linesTruncated) {\n\t\tconst warnings: string[] = [];\n\t\tif (matchLimit) warnings.push(`${matchLimit} matches limit`);\n\t\tif (truncation?.truncated) warnings.push(`${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);\n\t\tif (linesTruncated) warnings.push(\"some lines truncated\");\n\t\ttext += `\\n${theme.fg(\"warning\", `[Truncated: ${warnings.join(\", \")}]`)}`;\n\t}\n\treturn text;\n}\n\nexport function createGrepToolDefinition(\n\toperations: ToolOperations,\n\t_options?: GrepToolOptions,\n): ToolDefinition<typeof grepSchema, GrepToolDetails | undefined> {\n\tconst ops = operations;\n\tconst cwd = operations.cwd;\n\treturn {\n\t\tname: \"grep\",\n\t\tlabel: \"grep\",\n\t\tdescription: `Search file contents for a pattern. Returns matching lines with file paths and line numbers. Respects .gitignore. Output is truncated to ${DEFAULT_LIMIT} matches or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). Long lines are truncated to ${GREP_MAX_LINE_LENGTH} chars.`,\n\t\tpromptSnippet: \"Search file contents for patterns (respects .gitignore)\",\n\t\tparameters: grepSchema,\n\t\tasync execute(\n\t\t\t_toolCallId,\n\t\t\t{\n\t\t\t\tpattern,\n\t\t\t\tpath: searchDir,\n\t\t\t\tglob,\n\t\t\t\tignoreCase,\n\t\t\t\tliteral,\n\t\t\t\tcontext,\n\t\t\t\tlimit,\n\t\t\t}: {\n\t\t\t\tpattern: string;\n\t\t\t\tpath?: string;\n\t\t\t\tglob?: string;\n\t\t\t\tignoreCase?: boolean;\n\t\t\t\tliteral?: boolean;\n\t\t\t\tcontext?: number;\n\t\t\t\tlimit?: number;\n\t\t\t},\n\t\t\tsignal?: AbortSignal,\n\t\t\t_onUpdate?,\n\t\t\t_ctx?,\n\t\t) {\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\treject(new Error(\"Operation aborted\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tlet settled = false;\n\t\t\t\tconst settle = (fn: () => void) => {\n\t\t\t\t\tif (!settled) {\n\t\t\t\t\t\tsettled = true;\n\t\t\t\t\t\tfn();\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\t(async () => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst searchPath = resolveToCwd(searchDir || \".\", cwd);\n\t\t\t\t\t\tlet isDirectory: boolean;\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tisDirectory = (await ops.stat(searchPath)).isDirectory();\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\tsettle(() => reject(new Error(`Path not found: ${searchPath}`)));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst contextValue = context && context > 0 ? context : 0;\n\t\t\t\t\t\tconst effectiveLimit = Math.max(1, limit ?? DEFAULT_LIMIT);\n\t\t\t\t\t\tconst formatPath = (filePath: string): string => {\n\t\t\t\t\t\t\tif (isDirectory) {\n\t\t\t\t\t\t\t\tconst relative = path.relative(searchPath, filePath);\n\t\t\t\t\t\t\t\tif (relative && !relative.startsWith(\"..\")) {\n\t\t\t\t\t\t\t\t\treturn relative.replace(/\\\\/g, \"/\");\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn path.basename(filePath);\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tconst fileCache = new Map<string, string[]>();\n\t\t\t\t\t\tconst getFileLines = async (filePath: string): Promise<string[]> => {\n\t\t\t\t\t\t\tlet lines = fileCache.get(filePath);\n\t\t\t\t\t\t\tif (!lines) {\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tconst content = (await ops.readFile(filePath)).toString(\"utf-8\");\n\t\t\t\t\t\t\t\t\tlines = content.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\").split(\"\\n\");\n\t\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t\tlines = [];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tfileCache.set(filePath, lines);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn lines;\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tlet linesTruncated = false;\n\t\t\t\t\t\tconst formatBlock = async (filePath: string, lineNumber: number): Promise<string[]> => {\n\t\t\t\t\t\t\tconst relativePath = formatPath(filePath);\n\t\t\t\t\t\t\tconst lines = await getFileLines(filePath);\n\t\t\t\t\t\t\tif (!lines.length) return [`${relativePath}:${lineNumber}: (unable to read file)`];\n\t\t\t\t\t\t\tconst block: string[] = [];\n\t\t\t\t\t\t\tconst start = contextValue > 0 ? Math.max(1, lineNumber - contextValue) : lineNumber;\n\t\t\t\t\t\t\tconst end = contextValue > 0 ? Math.min(lines.length, lineNumber + contextValue) : lineNumber;\n\t\t\t\t\t\t\tfor (let current = start; current <= end; current++) {\n\t\t\t\t\t\t\t\tconst lineText = lines[current - 1] ?? \"\";\n\t\t\t\t\t\t\t\tconst sanitized = lineText.replace(/\\r/g, \"\");\n\t\t\t\t\t\t\t\tconst isMatchLine = current === lineNumber;\n\t\t\t\t\t\t\t\t// Truncate long lines so grep output stays compact.\n\t\t\t\t\t\t\t\tconst { text: truncatedText, wasTruncated } = truncateLine(sanitized);\n\t\t\t\t\t\t\t\tif (wasTruncated) linesTruncated = true;\n\t\t\t\t\t\t\t\tif (isMatchLine) block.push(`${relativePath}:${current}: ${truncatedText}`);\n\t\t\t\t\t\t\t\telse block.push(`${relativePath}-${current}- ${truncatedText}`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn block;\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tif (ops.grep) {\n\t\t\t\t\t\t\tconst grepResult = await ops.grep({\n\t\t\t\t\t\t\t\tpattern,\n\t\t\t\t\t\t\t\tpath: searchPath,\n\t\t\t\t\t\t\t\tglob,\n\t\t\t\t\t\t\t\tignoreCase,\n\t\t\t\t\t\t\t\tliteral,\n\t\t\t\t\t\t\t\tlimit: effectiveLimit,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tisDirectory = grepResult.isDirectory;\n\t\t\t\t\t\t\tif (grepResult.matches.length === 0) {\n\t\t\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\t\t\tresolve({ content: [{ type: \"text\", text: \"No matches found\" }], details: undefined }),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst outputLines: string[] = [];\n\t\t\t\t\t\t\tfor (const match of grepResult.matches) {\n\t\t\t\t\t\t\t\tif (contextValue === 0 && match.lineText !== undefined) {\n\t\t\t\t\t\t\t\t\tconst relativePath = formatPath(match.filePath);\n\t\t\t\t\t\t\t\t\tconst sanitized = match.lineText\n\t\t\t\t\t\t\t\t\t\t.replace(/\\r\\n/g, \"\\n\")\n\t\t\t\t\t\t\t\t\t\t.replace(/\\r/g, \"\")\n\t\t\t\t\t\t\t\t\t\t.replace(/\\n$/, \"\");\n\t\t\t\t\t\t\t\t\tconst { text: truncatedText, wasTruncated } = truncateLine(sanitized);\n\t\t\t\t\t\t\t\t\tif (wasTruncated) linesTruncated = true;\n\t\t\t\t\t\t\t\t\toutputLines.push(`${relativePath}:${match.lineNumber}: ${truncatedText}`);\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tconst block = await formatBlock(match.filePath, match.lineNumber);\n\t\t\t\t\t\t\t\t\toutputLines.push(...block);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst rawOutput = outputLines.join(\"\\n\");\n\t\t\t\t\t\t\tconst truncation = truncateHead(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER });\n\t\t\t\t\t\t\tlet output = truncation.content;\n\t\t\t\t\t\t\tconst details: GrepToolDetails = {};\n\t\t\t\t\t\t\tconst notices: string[] = [];\n\t\t\t\t\t\t\tif (grepResult.matches.length >= effectiveLimit) {\n\t\t\t\t\t\t\t\tnotices.push(\n\t\t\t\t\t\t\t\t\t`${effectiveLimit} matches limit reached. Use limit=${effectiveLimit * 2} for more, or refine pattern`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tdetails.matchLimitReached = effectiveLimit;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (truncation.truncated) {\n\t\t\t\t\t\t\t\tnotices.push(`${formatSize(DEFAULT_MAX_BYTES)} limit reached`);\n\t\t\t\t\t\t\t\tdetails.truncation = truncation;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (linesTruncated) {\n\t\t\t\t\t\t\t\tnotices.push(\n\t\t\t\t\t\t\t\t\t`Some lines truncated to ${GREP_MAX_LINE_LENGTH} chars. Use read tool to see full lines`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tdetails.linesTruncated = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (notices.length > 0) output += `\\n\\n[${notices.join(\". \")}]`;\n\t\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: output }],\n\t\t\t\t\t\t\t\t\tdetails: Object.keys(details).length > 0 ? details : undefined,\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst rgPath = await ensureTool(\"rg\", true);\n\t\t\t\t\t\tif (!rgPath) {\n\t\t\t\t\t\t\tsettle(() => reject(new Error(\"ripgrep (rg) is not available and could not be downloaded\")));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst args: string[] = [\"--json\", \"--line-number\", \"--color=never\", \"--hidden\"];\n\t\t\t\t\t\tif (ignoreCase) args.push(\"--ignore-case\");\n\t\t\t\t\t\tif (literal) args.push(\"--fixed-strings\");\n\t\t\t\t\t\tif (glob) args.push(\"--glob\", glob);\n\t\t\t\t\t\targs.push(\"--\", pattern, searchPath);\n\n\t\t\t\t\t\tconst child = spawn(rgPath, args, { stdio: [\"ignore\", \"pipe\", \"pipe\"] });\n\t\t\t\t\t\tconst rl = createInterface({ input: child.stdout });\n\t\t\t\t\t\tlet stderr = \"\";\n\t\t\t\t\t\tlet matchCount = 0;\n\t\t\t\t\t\tlet matchLimitReached = false;\n\t\t\t\t\t\tlet aborted = false;\n\t\t\t\t\t\tlet killedDueToLimit = false;\n\t\t\t\t\t\tconst outputLines: string[] = [];\n\n\t\t\t\t\t\tconst cleanup = () => {\n\t\t\t\t\t\t\trl.close();\n\t\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\t};\n\t\t\t\t\t\tconst stopChild = (dueToLimit = false) => {\n\t\t\t\t\t\t\tif (!child.killed) {\n\t\t\t\t\t\t\t\tkilledDueToLimit = dueToLimit;\n\t\t\t\t\t\t\t\tchild.kill();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t};\n\t\t\t\t\t\tconst onAbort = () => {\n\t\t\t\t\t\t\taborted = true;\n\t\t\t\t\t\t\tstopChild();\n\t\t\t\t\t\t};\n\t\t\t\t\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t\t\t\tchild.stderr?.on(\"data\", (chunk) => {\n\t\t\t\t\t\t\tstderr += chunk.toString();\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\t// Collect matches during streaming, then format them after rg exits.\n\t\t\t\t\t\tconst matches: Array<{ filePath: string; lineNumber: number; lineText?: string }> = [];\n\t\t\t\t\t\trl.on(\"line\", (line) => {\n\t\t\t\t\t\t\tif (!line.trim() || matchCount >= effectiveLimit) return;\n\t\t\t\t\t\t\tlet event: any;\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tevent = JSON.parse(line);\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (event.type === \"match\") {\n\t\t\t\t\t\t\t\tmatchCount++;\n\t\t\t\t\t\t\t\tconst filePath = event.data?.path?.text;\n\t\t\t\t\t\t\t\tconst lineNumber = event.data?.line_number;\n\t\t\t\t\t\t\t\tconst lineText = event.data?.lines?.text;\n\t\t\t\t\t\t\t\tif (filePath && typeof lineNumber === \"number\")\n\t\t\t\t\t\t\t\t\tmatches.push({ filePath, lineNumber, lineText });\n\t\t\t\t\t\t\t\tif (matchCount >= effectiveLimit) {\n\t\t\t\t\t\t\t\t\tmatchLimitReached = true;\n\t\t\t\t\t\t\t\t\tstopChild(true);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tchild.on(\"error\", (error) => {\n\t\t\t\t\t\t\tcleanup();\n\t\t\t\t\t\t\tsettle(() => reject(new Error(`Failed to run ripgrep: ${error.message}`)));\n\t\t\t\t\t\t});\n\t\t\t\t\t\tchild.on(\"close\", async (code) => {\n\t\t\t\t\t\t\tcleanup();\n\t\t\t\t\t\t\tif (aborted) {\n\t\t\t\t\t\t\t\tsettle(() => reject(new Error(\"Operation aborted\")));\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (!killedDueToLimit && code !== 0 && code !== 1) {\n\t\t\t\t\t\t\t\tconst errorMsg = stderr.trim() || `ripgrep exited with code ${code}`;\n\t\t\t\t\t\t\t\tsettle(() => reject(new Error(errorMsg)));\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (matchCount === 0) {\n\t\t\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\t\t\tresolve({ content: [{ type: \"text\", text: \"No matches found\" }], details: undefined }),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Format matches after streaming finishes so custom readFile() backends can be async.\n\t\t\t\t\t\t\tfor (const match of matches) {\n\t\t\t\t\t\t\t\tif (contextValue === 0 && match.lineText !== undefined) {\n\t\t\t\t\t\t\t\t\tconst relativePath = formatPath(match.filePath);\n\t\t\t\t\t\t\t\t\tconst sanitized = match.lineText\n\t\t\t\t\t\t\t\t\t\t.replace(/\\r\\n/g, \"\\n\")\n\t\t\t\t\t\t\t\t\t\t.replace(/\\r/g, \"\")\n\t\t\t\t\t\t\t\t\t\t.replace(/\\n$/, \"\");\n\t\t\t\t\t\t\t\t\tconst { text: truncatedText, wasTruncated } = truncateLine(sanitized);\n\t\t\t\t\t\t\t\t\tif (wasTruncated) linesTruncated = true;\n\t\t\t\t\t\t\t\t\toutputLines.push(`${relativePath}:${match.lineNumber}: ${truncatedText}`);\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tconst block = await formatBlock(match.filePath, match.lineNumber);\n\t\t\t\t\t\t\t\t\toutputLines.push(...block);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tconst rawOutput = outputLines.join(\"\\n\");\n\t\t\t\t\t\t\t// Apply byte truncation. There is no line limit here because the match limit already capped rows.\n\t\t\t\t\t\t\tconst truncation = truncateHead(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER });\n\t\t\t\t\t\t\tlet output = truncation.content;\n\t\t\t\t\t\t\tconst details: GrepToolDetails = {};\n\t\t\t\t\t\t\t// Build actionable notices for truncation and match limits.\n\t\t\t\t\t\t\tconst notices: string[] = [];\n\t\t\t\t\t\t\tif (matchLimitReached) {\n\t\t\t\t\t\t\t\tnotices.push(\n\t\t\t\t\t\t\t\t\t`${effectiveLimit} matches limit reached. Use limit=${effectiveLimit * 2} for more, or refine pattern`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tdetails.matchLimitReached = effectiveLimit;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (truncation.truncated) {\n\t\t\t\t\t\t\t\tnotices.push(`${formatSize(DEFAULT_MAX_BYTES)} limit reached`);\n\t\t\t\t\t\t\t\tdetails.truncation = truncation;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (linesTruncated) {\n\t\t\t\t\t\t\t\tnotices.push(\n\t\t\t\t\t\t\t\t\t`Some lines truncated to ${GREP_MAX_LINE_LENGTH} chars. Use read tool to see full lines`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tdetails.linesTruncated = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (notices.length > 0) output += `\\n\\n[${notices.join(\". \")}]`;\n\t\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: output }],\n\t\t\t\t\t\t\t\t\tdetails: Object.keys(details).length > 0 ? details : undefined,\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t});\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tsettle(() => reject(err as Error));\n\t\t\t\t\t}\n\t\t\t\t})();\n\t\t\t});\n\t\t},\n\t\trenderCall(args, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatBackendIcon(ops.getBackendInfo?.(), theme) + formatGrepCall(args, theme));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatGrepResult(result as any, options, theme, context.showImages));\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createGrepTool(operations: ToolOperations, options?: GrepToolOptions): AgentTool<typeof grepSchema> {\n\treturn wrapToolDefinition(createGrepToolDefinition(operations, options));\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"ls.d.ts","sourceRoot":"","sources":["../../../src/core/tools/ls.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAG3D,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE5C,OAAO,KAAK,EAAE,cAAc,EAA2B,MAAM,wBAAwB,CAAC;AACtF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAItD,OAAO,EAAiC,KAAK,gBAAgB,EAAgB,MAAM,eAAe,CAAC;AAEnG,QAAA,MAAM,QAAQ;;;EAGZ,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,QAAQ,CAAC,CAAC;AAIlD,MAAM,WAAW,aAAa;IAC7B,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,aAAa;CAAG;AAkDjC,wBAAgB,sBAAsB,CACrC,UAAU,EAAE,cAAc,EAC1B,QAAQ,CAAC,EAAE,aAAa,GACtB,cAAc,CAAC,OAAO,QAAQ,EAAE,aAAa,GAAG,SAAS,CAAC,CA8H5D;AAED,wBAAgB,YAAY,CAAC,UAAU,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,SAAS,CAAC,OAAO,QAAQ,CAAC,CAE5G","sourcesContent":["import type { AgentTool } from \"@fleetagent/pi-agent-core\";\nimport { Text } from \"@fleetagent/pi-tui\";\nimport nodePath from \"path\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../extensions/types.ts\";\nimport type { ToolOperations } from \"./operations.ts\";\nimport { resolveToCwd } from \"./path-utils.ts\";\nimport { getTextOutput, invalidArgText, shortenPath, str } from \"./render-utils.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\nimport { DEFAULT_MAX_BYTES, formatSize, type TruncationResult, truncateHead } from \"./truncate.ts\";\n\nconst lsSchema = Type.Object({\n\tpath: Type.Optional(Type.String({ description: \"Directory to list (default: current directory)\" })),\n\tlimit: Type.Optional(Type.Number({ description: \"Maximum number of entries to return (default: 500)\" })),\n});\n\nexport type LsToolInput = Static<typeof lsSchema>;\n\nconst DEFAULT_LIMIT = 500;\n\nexport interface LsToolDetails {\n\ttruncation?: TruncationResult;\n\tentryLimitReached?: number;\n}\n\nexport interface LsToolOptions {}\n\nfunction formatLsCall(\n\targs: { path?: string; limit?: number } | undefined,\n\ttheme: typeof import(\"../../modes/interactive/theme/theme.ts\").theme,\n): string {\n\tconst rawPath = str(args?.path);\n\tconst path = rawPath !== null ? shortenPath(rawPath || \".\") : null;\n\tconst limit = args?.limit;\n\tconst invalidArg = invalidArgText(theme);\n\tlet text = `${theme.fg(\"toolTitle\", theme.bold(\"ls\"))} ${path === null ? invalidArg : theme.fg(\"accent\", path)}`;\n\tif (limit !== undefined) {\n\t\ttext += theme.fg(\"toolOutput\", ` (limit ${limit})`);\n\t}\n\treturn text;\n}\n\nfunction formatLsResult(\n\tresult: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tdetails?: LsToolDetails;\n\t},\n\toptions: ToolRenderResultOptions,\n\ttheme: typeof import(\"../../modes/interactive/theme/theme.ts\").theme,\n\tshowImages: boolean,\n): string {\n\tconst output = getTextOutput(result, showImages).trim();\n\tlet text = \"\";\n\tif (output) {\n\t\tconst lines = output.split(\"\\n\");\n\t\tconst maxLines = options.expanded ? lines.length : 20;\n\t\tconst displayLines = lines.slice(0, maxLines);\n\t\tconst remaining = lines.length - maxLines;\n\t\ttext += `\\n${displayLines.map((line) => theme.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n\t\tif (remaining > 0) {\n\t\t\ttext += `${theme.fg(\"muted\", `\\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")})`;\n\t\t}\n\t}\n\n\tconst entryLimit = result.details?.entryLimitReached;\n\tconst truncation = result.details?.truncation;\n\tif (entryLimit || truncation?.truncated) {\n\t\tconst warnings: string[] = [];\n\t\tif (entryLimit) warnings.push(`${entryLimit} entries limit`);\n\t\tif (truncation?.truncated) warnings.push(`${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);\n\t\ttext += `\\n${theme.fg(\"warning\", `[Truncated: ${warnings.join(\", \")}]`)}`;\n\t}\n\treturn text;\n}\n\nexport function createLsToolDefinition(\n\toperations: ToolOperations,\n\t_options?: LsToolOptions,\n): ToolDefinition<typeof lsSchema, LsToolDetails | undefined> {\n\tconst ops = operations;\n\tconst cwd = operations.cwd;\n\treturn {\n\t\tname: \"ls\",\n\t\tlabel: \"ls\",\n\t\tdescription: `List directory contents. Returns entries sorted alphabetically, with '/' suffix for directories. Includes dotfiles. Output is truncated to ${DEFAULT_LIMIT} entries or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first).`,\n\t\tpromptSnippet: \"List directory contents\",\n\t\tparameters: lsSchema,\n\t\tasync execute(\n\t\t\t_toolCallId,\n\t\t\t{ path, limit }: { path?: string; limit?: number },\n\t\t\tsignal?: AbortSignal,\n\t\t\t_onUpdate?,\n\t\t\t_ctx?,\n\t\t) {\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\treject(new Error(\"Operation aborted\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst onAbort = () => reject(new Error(\"Operation aborted\"));\n\t\t\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\n\t\t\t\t(async () => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst dirPath = resolveToCwd(path || \".\", cwd);\n\t\t\t\t\t\tconst effectiveLimit = limit ?? DEFAULT_LIMIT;\n\n\t\t\t\t\t\t// Check if path exists.\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tawait ops.access(dirPath, \"exists\");\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\treject(new Error(`Path not found: ${dirPath}`));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Check if path is a directory.\n\t\t\t\t\t\tconst stat = await ops.stat(dirPath);\n\t\t\t\t\t\tif (!stat.isDirectory()) {\n\t\t\t\t\t\t\treject(new Error(`Not a directory: ${dirPath}`));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Read directory entries.\n\t\t\t\t\t\tlet entries: string[];\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tentries = await ops.readdir(dirPath);\n\t\t\t\t\t\t} catch (e: any) {\n\t\t\t\t\t\t\treject(new Error(`Cannot read directory: ${e.message}`));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Sort alphabetically, case-insensitive.\n\t\t\t\t\t\tentries.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));\n\n\t\t\t\t\t\t// Format entries with directory indicators.\n\t\t\t\t\t\tconst results: string[] = [];\n\t\t\t\t\t\tlet entryLimitReached = false;\n\t\t\t\t\t\tfor (const entry of entries) {\n\t\t\t\t\t\t\tif (results.length >= effectiveLimit) {\n\t\t\t\t\t\t\t\tentryLimitReached = true;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tconst fullPath = nodePath.join(dirPath, entry);\n\t\t\t\t\t\t\tlet suffix = \"\";\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tconst entryStat = await ops.stat(fullPath);\n\t\t\t\t\t\t\t\tif (entryStat.isDirectory()) suffix = \"/\";\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t// Skip entries we cannot stat.\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tresults.push(entry + suffix);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\n\t\t\t\t\t\tif (results.length === 0) {\n\t\t\t\t\t\t\tresolve({ content: [{ type: \"text\", text: \"(empty directory)\" }], details: undefined });\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst rawOutput = results.join(\"\\n\");\n\t\t\t\t\t\t// Apply byte truncation. There is no separate line limit because entry count is already capped.\n\t\t\t\t\t\tconst truncation = truncateHead(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER });\n\t\t\t\t\t\tlet output = truncation.content;\n\t\t\t\t\t\tconst details: LsToolDetails = {};\n\t\t\t\t\t\t// Build actionable notices for truncation and entry limits.\n\t\t\t\t\t\tconst notices: string[] = [];\n\t\t\t\t\t\tif (entryLimitReached) {\n\t\t\t\t\t\t\tnotices.push(`${effectiveLimit} entries limit reached. Use limit=${effectiveLimit * 2} for more`);\n\t\t\t\t\t\t\tdetails.entryLimitReached = effectiveLimit;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (truncation.truncated) {\n\t\t\t\t\t\t\tnotices.push(`${formatSize(DEFAULT_MAX_BYTES)} limit reached`);\n\t\t\t\t\t\t\tdetails.truncation = truncation;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (notices.length > 0) {\n\t\t\t\t\t\t\toutput += `\\n\\n[${notices.join(\". \")}]`;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: output }],\n\t\t\t\t\t\t\tdetails: Object.keys(details).length > 0 ? details : undefined,\n\t\t\t\t\t\t});\n\t\t\t\t\t} catch (e: any) {\n\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\treject(e);\n\t\t\t\t\t}\n\t\t\t\t})();\n\t\t\t});\n\t\t},\n\t\trenderCall(args, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatLsCall(args, theme));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatLsResult(result as any, options, theme, context.showImages));\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createLsTool(operations: ToolOperations, options?: LsToolOptions): AgentTool<typeof lsSchema> {\n\treturn wrapToolDefinition(createLsToolDefinition(operations, options));\n}\n"]}
1
+ {"version":3,"file":"ls.d.ts","sourceRoot":"","sources":["../../../src/core/tools/ls.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAG3D,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE5C,OAAO,KAAK,EAAE,cAAc,EAA2B,MAAM,wBAAwB,CAAC;AACtF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAItD,OAAO,EAAiC,KAAK,gBAAgB,EAAgB,MAAM,eAAe,CAAC;AAEnG,QAAA,MAAM,QAAQ;;;EAGZ,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,QAAQ,CAAC,CAAC;AAIlD,MAAM,WAAW,aAAa;IAC7B,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,aAAa;CAAG;AAkDjC,wBAAgB,sBAAsB,CACrC,UAAU,EAAE,cAAc,EAC1B,QAAQ,CAAC,EAAE,aAAa,GACtB,cAAc,CAAC,OAAO,QAAQ,EAAE,aAAa,GAAG,SAAS,CAAC,CA8H5D;AAED,wBAAgB,YAAY,CAAC,UAAU,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,SAAS,CAAC,OAAO,QAAQ,CAAC,CAE5G","sourcesContent":["import type { AgentTool } from \"@fleetagent/pi-agent-core\";\nimport { Text } from \"@fleetagent/pi-tui\";\nimport nodePath from \"path\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../extensions/types.ts\";\nimport type { ToolOperations } from \"./operations.ts\";\nimport { resolveToCwd } from \"./path-utils.ts\";\nimport { formatBackendIcon, getTextOutput, invalidArgText, shortenPath, str } from \"./render-utils.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\nimport { DEFAULT_MAX_BYTES, formatSize, type TruncationResult, truncateHead } from \"./truncate.ts\";\n\nconst lsSchema = Type.Object({\n\tpath: Type.Optional(Type.String({ description: \"Directory to list (default: current directory)\" })),\n\tlimit: Type.Optional(Type.Number({ description: \"Maximum number of entries to return (default: 500)\" })),\n});\n\nexport type LsToolInput = Static<typeof lsSchema>;\n\nconst DEFAULT_LIMIT = 500;\n\nexport interface LsToolDetails {\n\ttruncation?: TruncationResult;\n\tentryLimitReached?: number;\n}\n\nexport interface LsToolOptions {}\n\nfunction formatLsCall(\n\targs: { path?: string; limit?: number } | undefined,\n\ttheme: typeof import(\"../../modes/interactive/theme/theme.ts\").theme,\n): string {\n\tconst rawPath = str(args?.path);\n\tconst path = rawPath !== null ? shortenPath(rawPath || \".\") : null;\n\tconst limit = args?.limit;\n\tconst invalidArg = invalidArgText(theme);\n\tlet text = `${theme.fg(\"toolTitle\", theme.bold(\"ls\"))} ${path === null ? invalidArg : theme.fg(\"accent\", path)}`;\n\tif (limit !== undefined) {\n\t\ttext += theme.fg(\"toolOutput\", ` (limit ${limit})`);\n\t}\n\treturn text;\n}\n\nfunction formatLsResult(\n\tresult: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tdetails?: LsToolDetails;\n\t},\n\toptions: ToolRenderResultOptions,\n\ttheme: typeof import(\"../../modes/interactive/theme/theme.ts\").theme,\n\tshowImages: boolean,\n): string {\n\tconst output = getTextOutput(result, showImages).trim();\n\tlet text = \"\";\n\tif (output) {\n\t\tconst lines = output.split(\"\\n\");\n\t\tconst maxLines = options.expanded ? lines.length : 20;\n\t\tconst displayLines = lines.slice(0, maxLines);\n\t\tconst remaining = lines.length - maxLines;\n\t\ttext += `\\n${displayLines.map((line) => theme.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n\t\tif (remaining > 0) {\n\t\t\ttext += `${theme.fg(\"muted\", `\\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")})`;\n\t\t}\n\t}\n\n\tconst entryLimit = result.details?.entryLimitReached;\n\tconst truncation = result.details?.truncation;\n\tif (entryLimit || truncation?.truncated) {\n\t\tconst warnings: string[] = [];\n\t\tif (entryLimit) warnings.push(`${entryLimit} entries limit`);\n\t\tif (truncation?.truncated) warnings.push(`${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);\n\t\ttext += `\\n${theme.fg(\"warning\", `[Truncated: ${warnings.join(\", \")}]`)}`;\n\t}\n\treturn text;\n}\n\nexport function createLsToolDefinition(\n\toperations: ToolOperations,\n\t_options?: LsToolOptions,\n): ToolDefinition<typeof lsSchema, LsToolDetails | undefined> {\n\tconst ops = operations;\n\tconst cwd = operations.cwd;\n\treturn {\n\t\tname: \"ls\",\n\t\tlabel: \"ls\",\n\t\tdescription: `List directory contents. Returns entries sorted alphabetically, with '/' suffix for directories. Includes dotfiles. Output is truncated to ${DEFAULT_LIMIT} entries or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first).`,\n\t\tpromptSnippet: \"List directory contents\",\n\t\tparameters: lsSchema,\n\t\tasync execute(\n\t\t\t_toolCallId,\n\t\t\t{ path, limit }: { path?: string; limit?: number },\n\t\t\tsignal?: AbortSignal,\n\t\t\t_onUpdate?,\n\t\t\t_ctx?,\n\t\t) {\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\treject(new Error(\"Operation aborted\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst onAbort = () => reject(new Error(\"Operation aborted\"));\n\t\t\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\n\t\t\t\t(async () => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst dirPath = resolveToCwd(path || \".\", cwd);\n\t\t\t\t\t\tconst effectiveLimit = limit ?? DEFAULT_LIMIT;\n\n\t\t\t\t\t\t// Check if path exists.\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tawait ops.access(dirPath, \"exists\");\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\treject(new Error(`Path not found: ${dirPath}`));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Check if path is a directory.\n\t\t\t\t\t\tconst stat = await ops.stat(dirPath);\n\t\t\t\t\t\tif (!stat.isDirectory()) {\n\t\t\t\t\t\t\treject(new Error(`Not a directory: ${dirPath}`));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Read directory entries.\n\t\t\t\t\t\tlet entries: string[];\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tentries = await ops.readdir(dirPath);\n\t\t\t\t\t\t} catch (e: any) {\n\t\t\t\t\t\t\treject(new Error(`Cannot read directory: ${e.message}`));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Sort alphabetically, case-insensitive.\n\t\t\t\t\t\tentries.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));\n\n\t\t\t\t\t\t// Format entries with directory indicators.\n\t\t\t\t\t\tconst results: string[] = [];\n\t\t\t\t\t\tlet entryLimitReached = false;\n\t\t\t\t\t\tfor (const entry of entries) {\n\t\t\t\t\t\t\tif (results.length >= effectiveLimit) {\n\t\t\t\t\t\t\t\tentryLimitReached = true;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tconst fullPath = nodePath.join(dirPath, entry);\n\t\t\t\t\t\t\tlet suffix = \"\";\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tconst entryStat = await ops.stat(fullPath);\n\t\t\t\t\t\t\t\tif (entryStat.isDirectory()) suffix = \"/\";\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t// Skip entries we cannot stat.\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tresults.push(entry + suffix);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\n\t\t\t\t\t\tif (results.length === 0) {\n\t\t\t\t\t\t\tresolve({ content: [{ type: \"text\", text: \"(empty directory)\" }], details: undefined });\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst rawOutput = results.join(\"\\n\");\n\t\t\t\t\t\t// Apply byte truncation. There is no separate line limit because entry count is already capped.\n\t\t\t\t\t\tconst truncation = truncateHead(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER });\n\t\t\t\t\t\tlet output = truncation.content;\n\t\t\t\t\t\tconst details: LsToolDetails = {};\n\t\t\t\t\t\t// Build actionable notices for truncation and entry limits.\n\t\t\t\t\t\tconst notices: string[] = [];\n\t\t\t\t\t\tif (entryLimitReached) {\n\t\t\t\t\t\t\tnotices.push(`${effectiveLimit} entries limit reached. Use limit=${effectiveLimit * 2} for more`);\n\t\t\t\t\t\t\tdetails.entryLimitReached = effectiveLimit;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (truncation.truncated) {\n\t\t\t\t\t\t\tnotices.push(`${formatSize(DEFAULT_MAX_BYTES)} limit reached`);\n\t\t\t\t\t\t\tdetails.truncation = truncation;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (notices.length > 0) {\n\t\t\t\t\t\t\toutput += `\\n\\n[${notices.join(\". \")}]`;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: output }],\n\t\t\t\t\t\t\tdetails: Object.keys(details).length > 0 ? details : undefined,\n\t\t\t\t\t\t});\n\t\t\t\t\t} catch (e: any) {\n\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\treject(e);\n\t\t\t\t\t}\n\t\t\t\t})();\n\t\t\t});\n\t\t},\n\t\trenderCall(args, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatBackendIcon(ops.getBackendInfo?.(), theme) + formatLsCall(args, theme));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatLsResult(result as any, options, theme, context.showImages));\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createLsTool(operations: ToolOperations, options?: LsToolOptions): AgentTool<typeof lsSchema> {\n\treturn wrapToolDefinition(createLsToolDefinition(operations, options));\n}\n"]}
@@ -3,7 +3,7 @@ import nodePath from "path";
3
3
  import { Type } from "typebox";
4
4
  import { keyHint } from "../../modes/interactive/components/keybinding-hints.js";
5
5
  import { resolveToCwd } from "./path-utils.js";
6
- import { getTextOutput, invalidArgText, shortenPath, str } from "./render-utils.js";
6
+ import { formatBackendIcon, getTextOutput, invalidArgText, shortenPath, str } from "./render-utils.js";
7
7
  import { wrapToolDefinition } from "./tool-definition-wrapper.js";
8
8
  import { DEFAULT_MAX_BYTES, formatSize, truncateHead } from "./truncate.js";
9
9
  const lsSchema = Type.Object({
@@ -151,7 +151,7 @@ export function createLsToolDefinition(operations, _options) {
151
151
  },
152
152
  renderCall(args, theme, context) {
153
153
  const text = context.lastComponent ?? new Text("", 0, 0);
154
- text.setText(formatLsCall(args, theme));
154
+ text.setText(formatBackendIcon(ops.getBackendInfo?.(), theme) + formatLsCall(args, theme));
155
155
  return text;
156
156
  },
157
157
  renderResult(result, options, theme, context) {
@@ -1 +1 @@
1
- {"version":3,"file":"ls.js","sourceRoot":"","sources":["../../../src/core/tools/ls.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAC1C,OAAO,QAAQ,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAe,IAAI,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,wDAAwD,CAAC;AAGjF,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AACpF,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAyB,YAAY,EAAE,MAAM,eAAe,CAAC;AAEnG,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC;IAC5B,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,gDAAgD,EAAE,CAAC,CAAC;IACnG,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,oDAAoD,EAAE,CAAC,CAAC;CACxG,CAAC,CAAC;AAIH,MAAM,aAAa,GAAG,GAAG,CAAC;AAS1B,SAAS,YAAY,CACpB,IAAmD,EACnD,KAAoE,EAC3D;IACT,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAChC,MAAM,IAAI,GAAG,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,OAAO,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACnE,MAAM,KAAK,GAAG,IAAI,EAAE,KAAK,CAAC;IAC1B,MAAM,UAAU,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;IACzC,IAAI,IAAI,GAAG,GAAG,KAAK,CAAC,EAAE,CAAC,WAAW,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,CAAC;IACjH,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACzB,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC,YAAY,EAAE,WAAW,KAAK,GAAG,CAAC,CAAC;IACrD,CAAC;IACD,OAAO,IAAI,CAAC;AAAA,CACZ;AAED,SAAS,cAAc,CACtB,MAGC,EACD,OAAgC,EAChC,KAAoE,EACpE,UAAmB,EACV;IACT,MAAM,MAAM,GAAG,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,IAAI,EAAE,CAAC;IACxD,IAAI,IAAI,GAAG,EAAE,CAAC;IACd,IAAI,MAAM,EAAE,CAAC;QACZ,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACjC,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;QACtD,MAAM,YAAY,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;QAC9C,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,GAAG,QAAQ,CAAC;QAC1C,IAAI,IAAI,KAAK,YAAY,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACnF,IAAI,SAAS,GAAG,CAAC,EAAE,CAAC;YACnB,IAAI,IAAI,GAAG,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,UAAU,SAAS,cAAc,CAAC,IAAI,OAAO,CAAC,kBAAkB,EAAE,WAAW,CAAC,GAAG,CAAC;QAChH,CAAC;IACF,CAAC;IAED,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,EAAE,iBAAiB,CAAC;IACrD,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC;IAC9C,IAAI,UAAU,IAAI,UAAU,EAAE,SAAS,EAAE,CAAC;QACzC,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,IAAI,UAAU;YAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,UAAU,gBAAgB,CAAC,CAAC;QAC7D,IAAI,UAAU,EAAE,SAAS;YAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,UAAU,CAAC,QAAQ,IAAI,iBAAiB,CAAC,QAAQ,CAAC,CAAC;QAC1G,IAAI,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC,SAAS,EAAE,eAAe,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;IAC3E,CAAC;IACD,OAAO,IAAI,CAAC;AAAA,CACZ;AAED,MAAM,UAAU,sBAAsB,CACrC,UAA0B,EAC1B,QAAwB,EACqC;IAC7D,MAAM,GAAG,GAAG,UAAU,CAAC;IACvB,MAAM,GAAG,GAAG,UAAU,CAAC,GAAG,CAAC;IAC3B,OAAO;QACN,IAAI,EAAE,IAAI;QACV,KAAK,EAAE,IAAI;QACX,WAAW,EAAE,8IAA8I,aAAa,eAAe,iBAAiB,GAAG,IAAI,8BAA8B;QAC7O,aAAa,EAAE,yBAAyB;QACxC,UAAU,EAAE,QAAQ;QACpB,KAAK,CAAC,OAAO,CACZ,WAAW,EACX,EAAE,IAAI,EAAE,KAAK,EAAqC,EAClD,MAAoB,EACpB,SAAU,EACV,IAAK,EACJ;YACD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC;gBACvC,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC;oBACrB,MAAM,CAAC,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC,CAAC;oBACvC,OAAO;gBACR,CAAC;gBAED,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC,CAAC;gBAC7D,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;gBAE3D,CAAC,KAAK,IAAI,EAAE,CAAC;oBACZ,IAAI,CAAC;wBACJ,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,IAAI,GAAG,EAAE,GAAG,CAAC,CAAC;wBAC/C,MAAM,cAAc,GAAG,KAAK,IAAI,aAAa,CAAC;wBAE9C,wBAAwB;wBACxB,IAAI,CAAC;4BACJ,MAAM,GAAG,CAAC,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;wBACrC,CAAC;wBAAC,MAAM,CAAC;4BACR,MAAM,CAAC,IAAI,KAAK,CAAC,mBAAmB,OAAO,EAAE,CAAC,CAAC,CAAC;4BAChD,OAAO;wBACR,CAAC;wBAED,gCAAgC;wBAChC,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;wBACrC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;4BACzB,MAAM,CAAC,IAAI,KAAK,CAAC,oBAAoB,OAAO,EAAE,CAAC,CAAC,CAAC;4BACjD,OAAO;wBACR,CAAC;wBAED,0BAA0B;wBAC1B,IAAI,OAAiB,CAAC;wBACtB,IAAI,CAAC;4BACJ,OAAO,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;wBACtC,CAAC;wBAAC,OAAO,CAAM,EAAE,CAAC;4BACjB,MAAM,CAAC,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;4BACzD,OAAO;wBACR,CAAC;wBAED,yCAAyC;wBACzC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;wBAEvE,4CAA4C;wBAC5C,MAAM,OAAO,GAAa,EAAE,CAAC;wBAC7B,IAAI,iBAAiB,GAAG,KAAK,CAAC;wBAC9B,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;4BAC7B,IAAI,OAAO,CAAC,MAAM,IAAI,cAAc,EAAE,CAAC;gCACtC,iBAAiB,GAAG,IAAI,CAAC;gCACzB,MAAM;4BACP,CAAC;4BAED,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;4BAC/C,IAAI,MAAM,GAAG,EAAE,CAAC;4BAChB,IAAI,CAAC;gCACJ,MAAM,SAAS,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;gCAC3C,IAAI,SAAS,CAAC,WAAW,EAAE;oCAAE,MAAM,GAAG,GAAG,CAAC;4BAC3C,CAAC;4BAAC,MAAM,CAAC;gCACR,+BAA+B;gCAC/B,SAAS;4BACV,CAAC;4BACD,OAAO,CAAC,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,CAAC;wBAC9B,CAAC;wBAED,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;wBAE9C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;4BAC1B,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB,EAAE,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC;4BACxF,OAAO;wBACR,CAAC;wBAED,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;wBACrC,gGAAgG;wBAChG,MAAM,UAAU,GAAG,YAAY,CAAC,SAAS,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,gBAAgB,EAAE,CAAC,CAAC;wBAClF,IAAI,MAAM,GAAG,UAAU,CAAC,OAAO,CAAC;wBAChC,MAAM,OAAO,GAAkB,EAAE,CAAC;wBAClC,4DAA4D;wBAC5D,MAAM,OAAO,GAAa,EAAE,CAAC;wBAC7B,IAAI,iBAAiB,EAAE,CAAC;4BACvB,OAAO,CAAC,IAAI,CAAC,GAAG,cAAc,qCAAqC,cAAc,GAAG,CAAC,WAAW,CAAC,CAAC;4BAClG,OAAO,CAAC,iBAAiB,GAAG,cAAc,CAAC;wBAC5C,CAAC;wBACD,IAAI,UAAU,CAAC,SAAS,EAAE,CAAC;4BAC1B,OAAO,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,iBAAiB,CAAC,gBAAgB,CAAC,CAAC;4BAC/D,OAAO,CAAC,UAAU,GAAG,UAAU,CAAC;wBACjC,CAAC;wBACD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;4BACxB,MAAM,IAAI,QAAQ,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;wBACzC,CAAC;wBAED,OAAO,CAAC;4BACP,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;4BACzC,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS;yBAC9D,CAAC,CAAC;oBACJ,CAAC;oBAAC,OAAO,CAAM,EAAE,CAAC;wBACjB,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;wBAC9C,MAAM,CAAC,CAAC,CAAC,CAAC;oBACX,CAAC;gBAAA,CACD,CAAC,EAAE,CAAC;YAAA,CACL,CAAC,CAAC;QAAA,CACH;QACD,UAAU,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE;YAChC,MAAM,IAAI,GAAI,OAAO,CAAC,aAAkC,IAAI,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;YAC/E,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;YACxC,OAAO,IAAI,CAAC;QAAA,CACZ;QACD,YAAY,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE;YAC7C,MAAM,IAAI,GAAI,OAAO,CAAC,aAAkC,IAAI,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;YAC/E,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,MAAa,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC;YAChF,OAAO,IAAI,CAAC;QAAA,CACZ;KACD,CAAC;AAAA,CACF;AAED,MAAM,UAAU,YAAY,CAAC,UAA0B,EAAE,OAAuB,EAA8B;IAC7G,OAAO,kBAAkB,CAAC,sBAAsB,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;AAAA,CACvE","sourcesContent":["import type { AgentTool } from \"@fleetagent/pi-agent-core\";\nimport { Text } from \"@fleetagent/pi-tui\";\nimport nodePath from \"path\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../extensions/types.ts\";\nimport type { ToolOperations } from \"./operations.ts\";\nimport { resolveToCwd } from \"./path-utils.ts\";\nimport { getTextOutput, invalidArgText, shortenPath, str } from \"./render-utils.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\nimport { DEFAULT_MAX_BYTES, formatSize, type TruncationResult, truncateHead } from \"./truncate.ts\";\n\nconst lsSchema = Type.Object({\n\tpath: Type.Optional(Type.String({ description: \"Directory to list (default: current directory)\" })),\n\tlimit: Type.Optional(Type.Number({ description: \"Maximum number of entries to return (default: 500)\" })),\n});\n\nexport type LsToolInput = Static<typeof lsSchema>;\n\nconst DEFAULT_LIMIT = 500;\n\nexport interface LsToolDetails {\n\ttruncation?: TruncationResult;\n\tentryLimitReached?: number;\n}\n\nexport interface LsToolOptions {}\n\nfunction formatLsCall(\n\targs: { path?: string; limit?: number } | undefined,\n\ttheme: typeof import(\"../../modes/interactive/theme/theme.ts\").theme,\n): string {\n\tconst rawPath = str(args?.path);\n\tconst path = rawPath !== null ? shortenPath(rawPath || \".\") : null;\n\tconst limit = args?.limit;\n\tconst invalidArg = invalidArgText(theme);\n\tlet text = `${theme.fg(\"toolTitle\", theme.bold(\"ls\"))} ${path === null ? invalidArg : theme.fg(\"accent\", path)}`;\n\tif (limit !== undefined) {\n\t\ttext += theme.fg(\"toolOutput\", ` (limit ${limit})`);\n\t}\n\treturn text;\n}\n\nfunction formatLsResult(\n\tresult: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tdetails?: LsToolDetails;\n\t},\n\toptions: ToolRenderResultOptions,\n\ttheme: typeof import(\"../../modes/interactive/theme/theme.ts\").theme,\n\tshowImages: boolean,\n): string {\n\tconst output = getTextOutput(result, showImages).trim();\n\tlet text = \"\";\n\tif (output) {\n\t\tconst lines = output.split(\"\\n\");\n\t\tconst maxLines = options.expanded ? lines.length : 20;\n\t\tconst displayLines = lines.slice(0, maxLines);\n\t\tconst remaining = lines.length - maxLines;\n\t\ttext += `\\n${displayLines.map((line) => theme.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n\t\tif (remaining > 0) {\n\t\t\ttext += `${theme.fg(\"muted\", `\\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")})`;\n\t\t}\n\t}\n\n\tconst entryLimit = result.details?.entryLimitReached;\n\tconst truncation = result.details?.truncation;\n\tif (entryLimit || truncation?.truncated) {\n\t\tconst warnings: string[] = [];\n\t\tif (entryLimit) warnings.push(`${entryLimit} entries limit`);\n\t\tif (truncation?.truncated) warnings.push(`${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);\n\t\ttext += `\\n${theme.fg(\"warning\", `[Truncated: ${warnings.join(\", \")}]`)}`;\n\t}\n\treturn text;\n}\n\nexport function createLsToolDefinition(\n\toperations: ToolOperations,\n\t_options?: LsToolOptions,\n): ToolDefinition<typeof lsSchema, LsToolDetails | undefined> {\n\tconst ops = operations;\n\tconst cwd = operations.cwd;\n\treturn {\n\t\tname: \"ls\",\n\t\tlabel: \"ls\",\n\t\tdescription: `List directory contents. Returns entries sorted alphabetically, with '/' suffix for directories. Includes dotfiles. Output is truncated to ${DEFAULT_LIMIT} entries or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first).`,\n\t\tpromptSnippet: \"List directory contents\",\n\t\tparameters: lsSchema,\n\t\tasync execute(\n\t\t\t_toolCallId,\n\t\t\t{ path, limit }: { path?: string; limit?: number },\n\t\t\tsignal?: AbortSignal,\n\t\t\t_onUpdate?,\n\t\t\t_ctx?,\n\t\t) {\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\treject(new Error(\"Operation aborted\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst onAbort = () => reject(new Error(\"Operation aborted\"));\n\t\t\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\n\t\t\t\t(async () => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst dirPath = resolveToCwd(path || \".\", cwd);\n\t\t\t\t\t\tconst effectiveLimit = limit ?? DEFAULT_LIMIT;\n\n\t\t\t\t\t\t// Check if path exists.\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tawait ops.access(dirPath, \"exists\");\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\treject(new Error(`Path not found: ${dirPath}`));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Check if path is a directory.\n\t\t\t\t\t\tconst stat = await ops.stat(dirPath);\n\t\t\t\t\t\tif (!stat.isDirectory()) {\n\t\t\t\t\t\t\treject(new Error(`Not a directory: ${dirPath}`));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Read directory entries.\n\t\t\t\t\t\tlet entries: string[];\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tentries = await ops.readdir(dirPath);\n\t\t\t\t\t\t} catch (e: any) {\n\t\t\t\t\t\t\treject(new Error(`Cannot read directory: ${e.message}`));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Sort alphabetically, case-insensitive.\n\t\t\t\t\t\tentries.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));\n\n\t\t\t\t\t\t// Format entries with directory indicators.\n\t\t\t\t\t\tconst results: string[] = [];\n\t\t\t\t\t\tlet entryLimitReached = false;\n\t\t\t\t\t\tfor (const entry of entries) {\n\t\t\t\t\t\t\tif (results.length >= effectiveLimit) {\n\t\t\t\t\t\t\t\tentryLimitReached = true;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tconst fullPath = nodePath.join(dirPath, entry);\n\t\t\t\t\t\t\tlet suffix = \"\";\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tconst entryStat = await ops.stat(fullPath);\n\t\t\t\t\t\t\t\tif (entryStat.isDirectory()) suffix = \"/\";\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t// Skip entries we cannot stat.\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tresults.push(entry + suffix);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\n\t\t\t\t\t\tif (results.length === 0) {\n\t\t\t\t\t\t\tresolve({ content: [{ type: \"text\", text: \"(empty directory)\" }], details: undefined });\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst rawOutput = results.join(\"\\n\");\n\t\t\t\t\t\t// Apply byte truncation. There is no separate line limit because entry count is already capped.\n\t\t\t\t\t\tconst truncation = truncateHead(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER });\n\t\t\t\t\t\tlet output = truncation.content;\n\t\t\t\t\t\tconst details: LsToolDetails = {};\n\t\t\t\t\t\t// Build actionable notices for truncation and entry limits.\n\t\t\t\t\t\tconst notices: string[] = [];\n\t\t\t\t\t\tif (entryLimitReached) {\n\t\t\t\t\t\t\tnotices.push(`${effectiveLimit} entries limit reached. Use limit=${effectiveLimit * 2} for more`);\n\t\t\t\t\t\t\tdetails.entryLimitReached = effectiveLimit;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (truncation.truncated) {\n\t\t\t\t\t\t\tnotices.push(`${formatSize(DEFAULT_MAX_BYTES)} limit reached`);\n\t\t\t\t\t\t\tdetails.truncation = truncation;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (notices.length > 0) {\n\t\t\t\t\t\t\toutput += `\\n\\n[${notices.join(\". \")}]`;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: output }],\n\t\t\t\t\t\t\tdetails: Object.keys(details).length > 0 ? details : undefined,\n\t\t\t\t\t\t});\n\t\t\t\t\t} catch (e: any) {\n\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\treject(e);\n\t\t\t\t\t}\n\t\t\t\t})();\n\t\t\t});\n\t\t},\n\t\trenderCall(args, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatLsCall(args, theme));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatLsResult(result as any, options, theme, context.showImages));\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createLsTool(operations: ToolOperations, options?: LsToolOptions): AgentTool<typeof lsSchema> {\n\treturn wrapToolDefinition(createLsToolDefinition(operations, options));\n}\n"]}
1
+ {"version":3,"file":"ls.js","sourceRoot":"","sources":["../../../src/core/tools/ls.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAC1C,OAAO,QAAQ,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAe,IAAI,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,wDAAwD,CAAC;AAGjF,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,cAAc,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AACvG,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAyB,YAAY,EAAE,MAAM,eAAe,CAAC;AAEnG,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC;IAC5B,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,gDAAgD,EAAE,CAAC,CAAC;IACnG,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,oDAAoD,EAAE,CAAC,CAAC;CACxG,CAAC,CAAC;AAIH,MAAM,aAAa,GAAG,GAAG,CAAC;AAS1B,SAAS,YAAY,CACpB,IAAmD,EACnD,KAAoE,EAC3D;IACT,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAChC,MAAM,IAAI,GAAG,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,OAAO,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACnE,MAAM,KAAK,GAAG,IAAI,EAAE,KAAK,CAAC;IAC1B,MAAM,UAAU,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;IACzC,IAAI,IAAI,GAAG,GAAG,KAAK,CAAC,EAAE,CAAC,WAAW,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,CAAC;IACjH,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACzB,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC,YAAY,EAAE,WAAW,KAAK,GAAG,CAAC,CAAC;IACrD,CAAC;IACD,OAAO,IAAI,CAAC;AAAA,CACZ;AAED,SAAS,cAAc,CACtB,MAGC,EACD,OAAgC,EAChC,KAAoE,EACpE,UAAmB,EACV;IACT,MAAM,MAAM,GAAG,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,IAAI,EAAE,CAAC;IACxD,IAAI,IAAI,GAAG,EAAE,CAAC;IACd,IAAI,MAAM,EAAE,CAAC;QACZ,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACjC,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;QACtD,MAAM,YAAY,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;QAC9C,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,GAAG,QAAQ,CAAC;QAC1C,IAAI,IAAI,KAAK,YAAY,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACnF,IAAI,SAAS,GAAG,CAAC,EAAE,CAAC;YACnB,IAAI,IAAI,GAAG,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,UAAU,SAAS,cAAc,CAAC,IAAI,OAAO,CAAC,kBAAkB,EAAE,WAAW,CAAC,GAAG,CAAC;QAChH,CAAC;IACF,CAAC;IAED,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,EAAE,iBAAiB,CAAC;IACrD,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC;IAC9C,IAAI,UAAU,IAAI,UAAU,EAAE,SAAS,EAAE,CAAC;QACzC,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,IAAI,UAAU;YAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,UAAU,gBAAgB,CAAC,CAAC;QAC7D,IAAI,UAAU,EAAE,SAAS;YAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,UAAU,CAAC,QAAQ,IAAI,iBAAiB,CAAC,QAAQ,CAAC,CAAC;QAC1G,IAAI,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC,SAAS,EAAE,eAAe,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;IAC3E,CAAC;IACD,OAAO,IAAI,CAAC;AAAA,CACZ;AAED,MAAM,UAAU,sBAAsB,CACrC,UAA0B,EAC1B,QAAwB,EACqC;IAC7D,MAAM,GAAG,GAAG,UAAU,CAAC;IACvB,MAAM,GAAG,GAAG,UAAU,CAAC,GAAG,CAAC;IAC3B,OAAO;QACN,IAAI,EAAE,IAAI;QACV,KAAK,EAAE,IAAI;QACX,WAAW,EAAE,8IAA8I,aAAa,eAAe,iBAAiB,GAAG,IAAI,8BAA8B;QAC7O,aAAa,EAAE,yBAAyB;QACxC,UAAU,EAAE,QAAQ;QACpB,KAAK,CAAC,OAAO,CACZ,WAAW,EACX,EAAE,IAAI,EAAE,KAAK,EAAqC,EAClD,MAAoB,EACpB,SAAU,EACV,IAAK,EACJ;YACD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC;gBACvC,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC;oBACrB,MAAM,CAAC,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC,CAAC;oBACvC,OAAO;gBACR,CAAC;gBAED,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC,CAAC;gBAC7D,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;gBAE3D,CAAC,KAAK,IAAI,EAAE,CAAC;oBACZ,IAAI,CAAC;wBACJ,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,IAAI,GAAG,EAAE,GAAG,CAAC,CAAC;wBAC/C,MAAM,cAAc,GAAG,KAAK,IAAI,aAAa,CAAC;wBAE9C,wBAAwB;wBACxB,IAAI,CAAC;4BACJ,MAAM,GAAG,CAAC,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;wBACrC,CAAC;wBAAC,MAAM,CAAC;4BACR,MAAM,CAAC,IAAI,KAAK,CAAC,mBAAmB,OAAO,EAAE,CAAC,CAAC,CAAC;4BAChD,OAAO;wBACR,CAAC;wBAED,gCAAgC;wBAChC,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;wBACrC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;4BACzB,MAAM,CAAC,IAAI,KAAK,CAAC,oBAAoB,OAAO,EAAE,CAAC,CAAC,CAAC;4BACjD,OAAO;wBACR,CAAC;wBAED,0BAA0B;wBAC1B,IAAI,OAAiB,CAAC;wBACtB,IAAI,CAAC;4BACJ,OAAO,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;wBACtC,CAAC;wBAAC,OAAO,CAAM,EAAE,CAAC;4BACjB,MAAM,CAAC,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;4BACzD,OAAO;wBACR,CAAC;wBAED,yCAAyC;wBACzC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;wBAEvE,4CAA4C;wBAC5C,MAAM,OAAO,GAAa,EAAE,CAAC;wBAC7B,IAAI,iBAAiB,GAAG,KAAK,CAAC;wBAC9B,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;4BAC7B,IAAI,OAAO,CAAC,MAAM,IAAI,cAAc,EAAE,CAAC;gCACtC,iBAAiB,GAAG,IAAI,CAAC;gCACzB,MAAM;4BACP,CAAC;4BAED,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;4BAC/C,IAAI,MAAM,GAAG,EAAE,CAAC;4BAChB,IAAI,CAAC;gCACJ,MAAM,SAAS,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;gCAC3C,IAAI,SAAS,CAAC,WAAW,EAAE;oCAAE,MAAM,GAAG,GAAG,CAAC;4BAC3C,CAAC;4BAAC,MAAM,CAAC;gCACR,+BAA+B;gCAC/B,SAAS;4BACV,CAAC;4BACD,OAAO,CAAC,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,CAAC;wBAC9B,CAAC;wBAED,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;wBAE9C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;4BAC1B,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB,EAAE,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC;4BACxF,OAAO;wBACR,CAAC;wBAED,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;wBACrC,gGAAgG;wBAChG,MAAM,UAAU,GAAG,YAAY,CAAC,SAAS,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,gBAAgB,EAAE,CAAC,CAAC;wBAClF,IAAI,MAAM,GAAG,UAAU,CAAC,OAAO,CAAC;wBAChC,MAAM,OAAO,GAAkB,EAAE,CAAC;wBAClC,4DAA4D;wBAC5D,MAAM,OAAO,GAAa,EAAE,CAAC;wBAC7B,IAAI,iBAAiB,EAAE,CAAC;4BACvB,OAAO,CAAC,IAAI,CAAC,GAAG,cAAc,qCAAqC,cAAc,GAAG,CAAC,WAAW,CAAC,CAAC;4BAClG,OAAO,CAAC,iBAAiB,GAAG,cAAc,CAAC;wBAC5C,CAAC;wBACD,IAAI,UAAU,CAAC,SAAS,EAAE,CAAC;4BAC1B,OAAO,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,iBAAiB,CAAC,gBAAgB,CAAC,CAAC;4BAC/D,OAAO,CAAC,UAAU,GAAG,UAAU,CAAC;wBACjC,CAAC;wBACD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;4BACxB,MAAM,IAAI,QAAQ,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;wBACzC,CAAC;wBAED,OAAO,CAAC;4BACP,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;4BACzC,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS;yBAC9D,CAAC,CAAC;oBACJ,CAAC;oBAAC,OAAO,CAAM,EAAE,CAAC;wBACjB,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;wBAC9C,MAAM,CAAC,CAAC,CAAC,CAAC;oBACX,CAAC;gBAAA,CACD,CAAC,EAAE,CAAC;YAAA,CACL,CAAC,CAAC;QAAA,CACH;QACD,UAAU,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE;YAChC,MAAM,IAAI,GAAI,OAAO,CAAC,aAAkC,IAAI,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;YAC/E,IAAI,CAAC,OAAO,CAAC,iBAAiB,CAAC,GAAG,CAAC,cAAc,EAAE,EAAE,EAAE,KAAK,CAAC,GAAG,YAAY,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;YAC3F,OAAO,IAAI,CAAC;QAAA,CACZ;QACD,YAAY,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE;YAC7C,MAAM,IAAI,GAAI,OAAO,CAAC,aAAkC,IAAI,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;YAC/E,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,MAAa,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC;YAChF,OAAO,IAAI,CAAC;QAAA,CACZ;KACD,CAAC;AAAA,CACF;AAED,MAAM,UAAU,YAAY,CAAC,UAA0B,EAAE,OAAuB,EAA8B;IAC7G,OAAO,kBAAkB,CAAC,sBAAsB,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;AAAA,CACvE","sourcesContent":["import type { AgentTool } from \"@fleetagent/pi-agent-core\";\nimport { Text } from \"@fleetagent/pi-tui\";\nimport nodePath from \"path\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../extensions/types.ts\";\nimport type { ToolOperations } from \"./operations.ts\";\nimport { resolveToCwd } from \"./path-utils.ts\";\nimport { formatBackendIcon, getTextOutput, invalidArgText, shortenPath, str } from \"./render-utils.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\nimport { DEFAULT_MAX_BYTES, formatSize, type TruncationResult, truncateHead } from \"./truncate.ts\";\n\nconst lsSchema = Type.Object({\n\tpath: Type.Optional(Type.String({ description: \"Directory to list (default: current directory)\" })),\n\tlimit: Type.Optional(Type.Number({ description: \"Maximum number of entries to return (default: 500)\" })),\n});\n\nexport type LsToolInput = Static<typeof lsSchema>;\n\nconst DEFAULT_LIMIT = 500;\n\nexport interface LsToolDetails {\n\ttruncation?: TruncationResult;\n\tentryLimitReached?: number;\n}\n\nexport interface LsToolOptions {}\n\nfunction formatLsCall(\n\targs: { path?: string; limit?: number } | undefined,\n\ttheme: typeof import(\"../../modes/interactive/theme/theme.ts\").theme,\n): string {\n\tconst rawPath = str(args?.path);\n\tconst path = rawPath !== null ? shortenPath(rawPath || \".\") : null;\n\tconst limit = args?.limit;\n\tconst invalidArg = invalidArgText(theme);\n\tlet text = `${theme.fg(\"toolTitle\", theme.bold(\"ls\"))} ${path === null ? invalidArg : theme.fg(\"accent\", path)}`;\n\tif (limit !== undefined) {\n\t\ttext += theme.fg(\"toolOutput\", ` (limit ${limit})`);\n\t}\n\treturn text;\n}\n\nfunction formatLsResult(\n\tresult: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tdetails?: LsToolDetails;\n\t},\n\toptions: ToolRenderResultOptions,\n\ttheme: typeof import(\"../../modes/interactive/theme/theme.ts\").theme,\n\tshowImages: boolean,\n): string {\n\tconst output = getTextOutput(result, showImages).trim();\n\tlet text = \"\";\n\tif (output) {\n\t\tconst lines = output.split(\"\\n\");\n\t\tconst maxLines = options.expanded ? lines.length : 20;\n\t\tconst displayLines = lines.slice(0, maxLines);\n\t\tconst remaining = lines.length - maxLines;\n\t\ttext += `\\n${displayLines.map((line) => theme.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n\t\tif (remaining > 0) {\n\t\t\ttext += `${theme.fg(\"muted\", `\\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")})`;\n\t\t}\n\t}\n\n\tconst entryLimit = result.details?.entryLimitReached;\n\tconst truncation = result.details?.truncation;\n\tif (entryLimit || truncation?.truncated) {\n\t\tconst warnings: string[] = [];\n\t\tif (entryLimit) warnings.push(`${entryLimit} entries limit`);\n\t\tif (truncation?.truncated) warnings.push(`${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);\n\t\ttext += `\\n${theme.fg(\"warning\", `[Truncated: ${warnings.join(\", \")}]`)}`;\n\t}\n\treturn text;\n}\n\nexport function createLsToolDefinition(\n\toperations: ToolOperations,\n\t_options?: LsToolOptions,\n): ToolDefinition<typeof lsSchema, LsToolDetails | undefined> {\n\tconst ops = operations;\n\tconst cwd = operations.cwd;\n\treturn {\n\t\tname: \"ls\",\n\t\tlabel: \"ls\",\n\t\tdescription: `List directory contents. Returns entries sorted alphabetically, with '/' suffix for directories. Includes dotfiles. Output is truncated to ${DEFAULT_LIMIT} entries or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first).`,\n\t\tpromptSnippet: \"List directory contents\",\n\t\tparameters: lsSchema,\n\t\tasync execute(\n\t\t\t_toolCallId,\n\t\t\t{ path, limit }: { path?: string; limit?: number },\n\t\t\tsignal?: AbortSignal,\n\t\t\t_onUpdate?,\n\t\t\t_ctx?,\n\t\t) {\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\treject(new Error(\"Operation aborted\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst onAbort = () => reject(new Error(\"Operation aborted\"));\n\t\t\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\n\t\t\t\t(async () => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst dirPath = resolveToCwd(path || \".\", cwd);\n\t\t\t\t\t\tconst effectiveLimit = limit ?? DEFAULT_LIMIT;\n\n\t\t\t\t\t\t// Check if path exists.\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tawait ops.access(dirPath, \"exists\");\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\treject(new Error(`Path not found: ${dirPath}`));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Check if path is a directory.\n\t\t\t\t\t\tconst stat = await ops.stat(dirPath);\n\t\t\t\t\t\tif (!stat.isDirectory()) {\n\t\t\t\t\t\t\treject(new Error(`Not a directory: ${dirPath}`));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Read directory entries.\n\t\t\t\t\t\tlet entries: string[];\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tentries = await ops.readdir(dirPath);\n\t\t\t\t\t\t} catch (e: any) {\n\t\t\t\t\t\t\treject(new Error(`Cannot read directory: ${e.message}`));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Sort alphabetically, case-insensitive.\n\t\t\t\t\t\tentries.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));\n\n\t\t\t\t\t\t// Format entries with directory indicators.\n\t\t\t\t\t\tconst results: string[] = [];\n\t\t\t\t\t\tlet entryLimitReached = false;\n\t\t\t\t\t\tfor (const entry of entries) {\n\t\t\t\t\t\t\tif (results.length >= effectiveLimit) {\n\t\t\t\t\t\t\t\tentryLimitReached = true;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tconst fullPath = nodePath.join(dirPath, entry);\n\t\t\t\t\t\t\tlet suffix = \"\";\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tconst entryStat = await ops.stat(fullPath);\n\t\t\t\t\t\t\t\tif (entryStat.isDirectory()) suffix = \"/\";\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t// Skip entries we cannot stat.\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tresults.push(entry + suffix);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\n\t\t\t\t\t\tif (results.length === 0) {\n\t\t\t\t\t\t\tresolve({ content: [{ type: \"text\", text: \"(empty directory)\" }], details: undefined });\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst rawOutput = results.join(\"\\n\");\n\t\t\t\t\t\t// Apply byte truncation. There is no separate line limit because entry count is already capped.\n\t\t\t\t\t\tconst truncation = truncateHead(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER });\n\t\t\t\t\t\tlet output = truncation.content;\n\t\t\t\t\t\tconst details: LsToolDetails = {};\n\t\t\t\t\t\t// Build actionable notices for truncation and entry limits.\n\t\t\t\t\t\tconst notices: string[] = [];\n\t\t\t\t\t\tif (entryLimitReached) {\n\t\t\t\t\t\t\tnotices.push(`${effectiveLimit} entries limit reached. Use limit=${effectiveLimit * 2} for more`);\n\t\t\t\t\t\t\tdetails.entryLimitReached = effectiveLimit;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (truncation.truncated) {\n\t\t\t\t\t\t\tnotices.push(`${formatSize(DEFAULT_MAX_BYTES)} limit reached`);\n\t\t\t\t\t\t\tdetails.truncation = truncation;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (notices.length > 0) {\n\t\t\t\t\t\t\toutput += `\\n\\n[${notices.join(\". \")}]`;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: output }],\n\t\t\t\t\t\t\tdetails: Object.keys(details).length > 0 ? details : undefined,\n\t\t\t\t\t\t});\n\t\t\t\t\t} catch (e: any) {\n\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\treject(e);\n\t\t\t\t\t}\n\t\t\t\t})();\n\t\t\t});\n\t\t},\n\t\trenderCall(args, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatBackendIcon(ops.getBackendInfo?.(), theme) + formatLsCall(args, theme));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatLsResult(result as any, options, theme, context.showImages));\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createLsTool(operations: ToolOperations, options?: LsToolOptions): AgentTool<typeof lsSchema> {\n\treturn wrapToolDefinition(createLsToolDefinition(operations, options));\n}\n"]}