@morphllm/morphsdk 0.2.81 → 0.2.83

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 (77) hide show
  1. package/dist/{chunk-4NI25AKV.js → chunk-4KMBU6T3.js} +2 -2
  2. package/dist/{chunk-XT5ZO6ES.js → chunk-5PNMAWLC.js} +8 -2
  3. package/dist/chunk-5PNMAWLC.js.map +1 -0
  4. package/dist/{chunk-X6A64F2F.js → chunk-HPR6BJA7.js} +5 -5
  5. package/dist/{chunk-4VMIPD4G.js → chunk-HRK53IKL.js} +8 -6
  6. package/dist/chunk-HRK53IKL.js.map +1 -0
  7. package/dist/{chunk-NTTQJM6O.js → chunk-LXG37353.js} +2 -2
  8. package/dist/{chunk-467MCW5R.js → chunk-P2O5JKE5.js} +2 -2
  9. package/dist/{chunk-PHJQ4N3T.js → chunk-PUGSTXLO.js} +2 -2
  10. package/dist/{chunk-B3UC7UVA.js → chunk-QOYI77CN.js} +30 -8
  11. package/dist/chunk-QOYI77CN.js.map +1 -0
  12. package/dist/{chunk-Z2HDXUH7.js → chunk-RL4JBZ3T.js} +2 -2
  13. package/dist/{chunk-OFMDENAQ.js → chunk-S27A4NQM.js} +2 -2
  14. package/dist/{client-CSINf0lQ.d.ts → client-CsO9LifG.d.ts} +1 -1
  15. package/dist/client.cjs +38 -8
  16. package/dist/client.cjs.map +1 -1
  17. package/dist/client.d.ts +2 -2
  18. package/dist/client.js +10 -10
  19. package/dist/index.cjs +38 -8
  20. package/dist/index.cjs.map +1 -1
  21. package/dist/index.d.ts +2 -2
  22. package/dist/index.js +10 -10
  23. package/dist/tools/warp_grep/agent/config.cjs +7 -1
  24. package/dist/tools/warp_grep/agent/config.cjs.map +1 -1
  25. package/dist/tools/warp_grep/agent/config.d.ts +1 -0
  26. package/dist/tools/warp_grep/agent/config.js +1 -1
  27. package/dist/tools/warp_grep/agent/runner.cjs +34 -6
  28. package/dist/tools/warp_grep/agent/runner.cjs.map +1 -1
  29. package/dist/tools/warp_grep/agent/runner.js +3 -3
  30. package/dist/tools/warp_grep/agent/types.cjs.map +1 -1
  31. package/dist/tools/warp_grep/agent/types.d.ts +16 -1
  32. package/dist/tools/warp_grep/anthropic.cjs +36 -7
  33. package/dist/tools/warp_grep/anthropic.cjs.map +1 -1
  34. package/dist/tools/warp_grep/anthropic.d.ts +1 -1
  35. package/dist/tools/warp_grep/anthropic.js +7 -7
  36. package/dist/tools/warp_grep/client.cjs +38 -8
  37. package/dist/tools/warp_grep/client.cjs.map +1 -1
  38. package/dist/tools/warp_grep/client.d.ts +1 -1
  39. package/dist/tools/warp_grep/client.js +6 -6
  40. package/dist/tools/warp_grep/gemini.cjs +36 -7
  41. package/dist/tools/warp_grep/gemini.cjs.map +1 -1
  42. package/dist/tools/warp_grep/gemini.d.ts +1 -1
  43. package/dist/tools/warp_grep/gemini.js +6 -6
  44. package/dist/tools/warp_grep/harness.cjs +7 -1
  45. package/dist/tools/warp_grep/harness.cjs.map +1 -1
  46. package/dist/tools/warp_grep/harness.js +3 -3
  47. package/dist/tools/warp_grep/index.cjs +38 -8
  48. package/dist/tools/warp_grep/index.cjs.map +1 -1
  49. package/dist/tools/warp_grep/index.d.ts +1 -1
  50. package/dist/tools/warp_grep/index.js +6 -6
  51. package/dist/tools/warp_grep/openai.cjs +36 -7
  52. package/dist/tools/warp_grep/openai.cjs.map +1 -1
  53. package/dist/tools/warp_grep/openai.d.ts +1 -1
  54. package/dist/tools/warp_grep/openai.js +7 -7
  55. package/dist/tools/warp_grep/providers/local.cjs +7 -1
  56. package/dist/tools/warp_grep/providers/local.cjs.map +1 -1
  57. package/dist/tools/warp_grep/providers/local.js +2 -2
  58. package/dist/tools/warp_grep/providers/remote.cjs +7 -1
  59. package/dist/tools/warp_grep/providers/remote.cjs.map +1 -1
  60. package/dist/tools/warp_grep/providers/remote.d.ts +1 -1
  61. package/dist/tools/warp_grep/providers/remote.js +2 -2
  62. package/dist/tools/warp_grep/vercel.cjs +36 -7
  63. package/dist/tools/warp_grep/vercel.cjs.map +1 -1
  64. package/dist/tools/warp_grep/vercel.d.ts +1 -1
  65. package/dist/tools/warp_grep/vercel.js +7 -7
  66. package/dist/{types-CnvVDM63.d.ts → types-Cv4LpqVl.d.ts} +2 -0
  67. package/package.json +1 -1
  68. package/dist/chunk-4VMIPD4G.js.map +0 -1
  69. package/dist/chunk-B3UC7UVA.js.map +0 -1
  70. package/dist/chunk-XT5ZO6ES.js.map +0 -1
  71. /package/dist/{chunk-4NI25AKV.js.map → chunk-4KMBU6T3.js.map} +0 -0
  72. /package/dist/{chunk-X6A64F2F.js.map → chunk-HPR6BJA7.js.map} +0 -0
  73. /package/dist/{chunk-NTTQJM6O.js.map → chunk-LXG37353.js.map} +0 -0
  74. /package/dist/{chunk-467MCW5R.js.map → chunk-P2O5JKE5.js.map} +0 -0
  75. /package/dist/{chunk-PHJQ4N3T.js.map → chunk-PUGSTXLO.js.map} +0 -0
  76. /package/dist/{chunk-Z2HDXUH7.js.map → chunk-RL4JBZ3T.js.map} +0 -0
  77. /package/dist/{chunk-OFMDENAQ.js.map → chunk-S27A4NQM.js.map} +0 -0
@@ -1,7 +1,7 @@
1
1
  import { ChatCompletionTool } from 'openai/resources/chat/completions';
2
2
  export { formatResult } from './client.js';
3
3
  export { getSystemPrompt } from './agent/prompt.js';
4
- import { d as WarpGrepToolConfig, b as WarpGrepResult } from '../../types-CnvVDM63.js';
4
+ import { d as WarpGrepToolConfig, b as WarpGrepResult } from '../../types-Cv4LpqVl.js';
5
5
  import './providers/types.js';
6
6
  import '../utils/resilience.js';
7
7
 
@@ -3,24 +3,24 @@ import {
3
3
  execute,
4
4
  openai_default,
5
5
  warpGrepTool
6
- } from "../../chunk-NTTQJM6O.js";
6
+ } from "../../chunk-LXG37353.js";
7
7
  import "../../chunk-KW7OEGZK.js";
8
8
  import {
9
9
  formatResult
10
- } from "../../chunk-4VMIPD4G.js";
11
- import "../../chunk-B3UC7UVA.js";
12
- import "../../chunk-PHJQ4N3T.js";
13
- import "../../chunk-467MCW5R.js";
10
+ } from "../../chunk-HRK53IKL.js";
11
+ import "../../chunk-QOYI77CN.js";
12
+ import "../../chunk-PUGSTXLO.js";
13
+ import "../../chunk-P2O5JKE5.js";
14
14
  import "../../chunk-APP75CBN.js";
15
15
  import "../../chunk-5QRN3JNB.js";
16
16
  import {
17
17
  getSystemPrompt
18
18
  } from "../../chunk-FMLHRJDF.js";
19
- import "../../chunk-4NI25AKV.js";
19
+ import "../../chunk-4KMBU6T3.js";
20
20
  import "../../chunk-G2RSY56Q.js";
21
21
  import "../../chunk-YPKNMYD4.js";
22
22
  import "../../chunk-TPP2UGQP.js";
23
- import "../../chunk-XT5ZO6ES.js";
23
+ import "../../chunk-5PNMAWLC.js";
24
24
  import "../../chunk-4VWJFZVS.js";
25
25
  import "../../chunk-PZ5AY32C.js";
26
26
  export {
@@ -165,9 +165,15 @@ async function readAllLines(filePath) {
165
165
  }
166
166
 
167
167
  // tools/warp_grep/agent/config.ts
168
+ var parseEnvTimeout = (envValue, defaultMs) => {
169
+ if (!envValue) return defaultMs;
170
+ const parsed = parseInt(envValue, 10);
171
+ return isNaN(parsed) || parsed <= 0 ? defaultMs : parsed;
172
+ };
168
173
  var AGENT_CONFIG = {
169
174
  MAX_TURNS: 4,
170
- TIMEOUT_MS: 3e4,
175
+ /** Default timeout for model calls. Can be overridden via MORPH_WARP_GREP_TIMEOUT env var (in ms) */
176
+ TIMEOUT_MS: parseEnvTimeout(process.env.MORPH_WARP_GREP_TIMEOUT, 3e4),
171
177
  MAX_CONTEXT_CHARS: 54e4,
172
178
  MAX_OUTPUT_LINES: 200,
173
179
  MAX_READ_LINES: 800,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../tools/warp_grep/providers/local.ts","../../../../tools/warp_grep/utils/ripgrep.ts","../../../../tools/warp_grep/utils/paths.ts","../../../../tools/warp_grep/utils/files.ts","../../../../tools/warp_grep/agent/config.ts"],"sourcesContent":["import fs from 'fs/promises';\nimport fssync from 'fs';\nimport path from 'path';\nimport { runRipgrep } from '../utils/ripgrep.js';\nimport { ensureWithinRepo, resolveUnderRepo, toRepoRelative, isSymlink, isTextualFile, fixPathRepetition } from '../utils/paths.js';\nimport type { WarpGrepProvider, GrepResult, ReadResult, ListDirectoryEntry } from './types.js';\nimport { readAllLines } from '../utils/files.js';\nimport { DEFAULT_EXCLUDES, AGENT_CONFIG } from '../agent/config.js';\n\n/**\n * Directories/files to always skip (exact name match)\n */\nconst SKIP_NAMES = new Set([\n // Version control\n '.git', '.svn', '.hg', '.bzr',\n // Dependencies\n 'node_modules', 'bower_components', '.pnpm', '.yarn',\n 'vendor', 'Pods', '.bundle',\n // Python\n '__pycache__', '.pytest_cache', '.mypy_cache', '.ruff_cache',\n '.venv', 'venv', '.tox', '.nox', '.eggs',\n // Build outputs\n 'dist', 'build', 'out', 'output', 'target', '_build',\n '.next', '.nuxt', '.output', '.vercel', '.netlify',\n // Cache\n '.cache', '.parcel-cache', '.turbo', '.nx', '.gradle',\n // IDE\n '.idea', '.vscode', '.vs',\n // Coverage\n 'coverage', '.coverage', 'htmlcov', '.nyc_output',\n // Temp\n 'tmp', 'temp', '.tmp', '.temp',\n // Lock files\n 'package-lock.json', 'yarn.lock', 'pnpm-lock.yaml', 'bun.lockb',\n 'Cargo.lock', 'Gemfile.lock', 'poetry.lock',\n]);\n\n/**\n * File extensions to skip\n */\nconst SKIP_EXTENSIONS = new Set([\n '.min.js', '.min.css', '.bundle.js',\n '.wasm', '.so', '.dll', '.pyc',\n '.map', '.js.map',\n]);\n\n/**\n * Check if a filename should be skipped\n */\nfunction shouldSkip(name: string): boolean {\n // Skip exact name matches\n if (SKIP_NAMES.has(name)) return true;\n \n // Skip hidden files/directories (start with .)\n if (name.startsWith('.')) return true;\n \n // Skip files with certain extensions\n for (const ext of SKIP_EXTENSIONS) {\n if (name.endsWith(ext)) return true;\n }\n \n return false;\n}\n\nexport class LocalRipgrepProvider implements WarpGrepProvider {\n constructor(private readonly repoRoot: string, private readonly excludes: string[] = DEFAULT_EXCLUDES) {}\n\n async grep(params: { pattern: string; path: string; glob?: string }): Promise<GrepResult> {\n let abs: string;\n try {\n abs = resolveUnderRepo(this.repoRoot, params.path);\n } catch (err) {\n return {\n lines: [],\n error: `[PATH ERROR] ${err instanceof Error ? err.message : String(err)}`,\n };\n }\n const stat = await fs.stat(abs).catch(() => null);\n if (!stat) return { lines: [] };\n const targetArg = abs === path.resolve(this.repoRoot) ? '.' : toRepoRelative(this.repoRoot, abs);\n const args = [\n '--no-config',\n '--no-heading',\n '--with-filename',\n '--line-number',\n '--color=never',\n '--trim',\n '--max-columns=400',\n '-C', '1',\n ...(params.glob ? ['--glob', params.glob] : []),\n ...this.excludes.flatMap((e) => ['-g', `!${e}`]),\n params.pattern,\n targetArg || '.',\n ];\n const res = await runRipgrep(args, { cwd: this.repoRoot });\n \n // Gracefully handle ripgrep not being available\n if (res.exitCode === -1) {\n return {\n lines: [],\n error: `[RIPGREP NOT AVAILABLE] ripgrep (rg) is required but failed to execute. Please install it:\\n` +\n ` • macOS: brew install ripgrep\\n` +\n ` • Ubuntu/Debian: apt install ripgrep\\n` +\n ` • Windows: choco install ripgrep\\n` +\n ` • Or visit: https://github.com/BurntSushi/ripgrep#installation\\n` +\n `Exit code: ${res.exitCode}${res.stderr ? `\\nDetails: ${res.stderr}` : ''}`,\n };\n }\n \n // Handle other ripgrep errors gracefully\n if (res.exitCode !== 0 && res.exitCode !== 1) {\n return {\n lines: [],\n error: `[RIPGREP ERROR] grep failed with exit code ${res.exitCode}${res.stderr ? `: ${res.stderr}` : ''}`,\n };\n }\n \n const lines = (res.stdout || '')\n .trim()\n .split(/\\r?\\n/)\n .filter((l) => l.length > 0);\n if (lines.length > AGENT_CONFIG.MAX_OUTPUT_LINES) {\n return {\n lines: [],\n error: 'query not specific enough, tool tried to return too much context and failed',\n };\n }\n \n return { lines };\n }\n\n async read(params: { path: string; start?: number; end?: number }): Promise<ReadResult> {\n let abs: string;\n try {\n abs = resolveUnderRepo(this.repoRoot, params.path);\n } catch (err) {\n return {\n lines: [],\n error: `[PATH ERROR] ${err instanceof Error ? err.message : String(err)}`,\n };\n }\n let stat = await fs.stat(abs).catch(() => null);\n\n // Handle duplicate path segments from model predictions\n if (!stat || !stat.isFile()) {\n const fixedPath = fixPathRepetition(abs);\n if (fixedPath) {\n const fixedStat = await fs.stat(fixedPath).catch(() => null);\n if (fixedStat?.isFile()) {\n abs = fixedPath;\n stat = fixedStat;\n }\n }\n }\n\n // Gracefully handle file not found / not a file\n if (!stat || !stat.isFile()) {\n return {\n lines: [],\n error: `[FILE NOT FOUND] You tried to read \"${params.path}\" but there is no file at this path. ` +\n `Double-check the path exists and is spelled correctly.`,\n };\n }\n \n // Gracefully handle symlinks\n if (isSymlink(abs)) {\n return {\n lines: [],\n error: `[SYMLINK] You tried to read \"${params.path}\" but this is a symlink. ` +\n `Try reading the actual file it points to instead.`,\n };\n }\n \n // Gracefully handle non-text or too-large files\n if (!isTextualFile(abs)) {\n return {\n lines: [],\n error: `[UNREADABLE FILE] You tried to read \"${params.path}\" but this file is either too large ` +\n `or not a text file, so it cannot be read. Try a different file.`,\n };\n }\n \n let lines: string[];\n try {\n lines = await readAllLines(abs);\n } catch (err) {\n return {\n lines: [],\n error: `[READ ERROR] Failed to read \"${params.path}\": ${err instanceof Error ? err.message : String(err)}`,\n };\n }\n const total = lines.length;\n const rawStart = params.start;\n const rawEnd = params.end;\n \n let s = 1;\n let e = total;\n \n const startValid = rawStart === undefined || (Number.isFinite(rawStart) && rawStart > 0);\n const endValid = rawEnd === undefined || (Number.isFinite(rawEnd) && rawEnd > 0);\n \n if (startValid && endValid) {\n s = rawStart ?? 1;\n e = Math.min(rawEnd ?? total, total);\n if ((s > total && total > 0) || (s > e)) {\n s = 1;\n e = total;\n }\n }\n const out: string[] = [];\n for (let i = s; i <= e; i += 1) {\n const content = lines[i - 1] ?? '';\n out.push(`${i}|${content}`);\n }\n if (out.length > AGENT_CONFIG.MAX_READ_LINES) {\n const truncated = out.slice(0, AGENT_CONFIG.MAX_READ_LINES);\n truncated.push(`... [truncated: showing ${AGENT_CONFIG.MAX_READ_LINES} of ${out.length} lines]`);\n return { lines: truncated };\n }\n \n return { lines: out };\n }\n\n async listDirectory(params: { path: string; pattern?: string | null; maxResults?: number; maxDepth?: number }): Promise<ListDirectoryEntry[]> {\n let abs: string;\n try {\n abs = resolveUnderRepo(this.repoRoot, params.path);\n } catch {\n // Path outside repo - return empty (graceful failure)\n return [];\n }\n const stat = await fs.stat(abs).catch(() => null);\n if (!stat || !stat.isDirectory()) {\n return [];\n }\n const maxResults = params.maxResults ?? AGENT_CONFIG.MAX_OUTPUT_LINES;\n const maxDepth = params.maxDepth ?? AGENT_CONFIG.MAX_LIST_DEPTH;\n const regex = params.pattern ? new RegExp(params.pattern) : null;\n const repoRoot = this.repoRoot;\n\n const results: ListDirectoryEntry[] = [];\n let timedOut = false;\n const startTime = Date.now();\n \n async function walk(dir: string, depth: number) {\n if (Date.now() - startTime > AGENT_CONFIG.LIST_TIMEOUT_MS) {\n timedOut = true;\n return;\n }\n if (depth > maxDepth || results.length >= maxResults) return;\n const entries = await fs.readdir(dir, { withFileTypes: true });\n for (const entry of entries) {\n if (timedOut || results.length >= maxResults) break;\n \n // Simple name-based filtering - skip junk dirs/files\n if (shouldSkip(entry.name)) continue;\n \n // Apply user-provided pattern filter\n if (regex && !regex.test(entry.name)) continue;\n \n const full = path.join(dir, entry.name);\n const isDir = entry.isDirectory();\n \n results.push({\n name: entry.name,\n path: toRepoRelative(repoRoot, full),\n type: isDir ? 'dir' : 'file',\n depth,\n });\n if (isDir) {\n await walk(full, depth + 1);\n }\n }\n }\n await walk(abs, 0);\n return results;\n }\n}\n\n\n","import { spawn } from 'child_process';\nimport { rgPath } from '@vscode/ripgrep';\n\nexport type ExecResult = { stdout: string; stderr: string; exitCode: number };\n\n// Cache the working ripgrep path to avoid repeated fallback checks\nlet resolvedRgPath: string | null = null;\nlet rgPathChecked = false;\n\nfunction spawnRg(rgBinary: string, args: string[], opts?: { cwd?: string; env?: NodeJS.ProcessEnv }): Promise<ExecResult> {\n return new Promise((resolve) => {\n const child = spawn(rgBinary, args, {\n cwd: opts?.cwd,\n env: { ...process.env, ...(opts?.env || {}) },\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n let stdout = '';\n let stderr = '';\n child.stdout.on('data', (d) => (stdout += d.toString()));\n child.stderr.on('data', (d) => (stderr += d.toString()));\n child.on('close', (code) => {\n resolve({ stdout, stderr, exitCode: typeof code === 'number' ? code : -1 });\n });\n child.on('error', () => {\n resolve({ stdout: '', stderr: 'Failed to spawn ripgrep.', exitCode: -1 });\n });\n });\n}\n\n// Check if a result indicates a binary compatibility failure (not a normal rg error)\nfunction isBinaryFailure(result: ExecResult): boolean {\n // Spawn error\n if (result.exitCode === -1) return true;\n // jemalloc page size issue (common on ARM64 with non-standard page sizes)\n if (result.stderr.includes('jemalloc') || result.stderr.includes('Unsupported system page size')) return true;\n // SIGABRT (134 = 128 + 6)\n if (result.exitCode === 134) return true;\n return false;\n}\n\nexport async function runRipgrep(args: string[], opts?: { cwd?: string; env?: NodeJS.ProcessEnv }): Promise<ExecResult> {\n // If we've already determined the working path, use it\n if (rgPathChecked && resolvedRgPath) {\n return spawnRg(resolvedRgPath, args, opts);\n }\n\n // First attempt: bundled ripgrep\n if (!rgPathChecked) {\n const result = await spawnRg(rgPath, args, opts);\n \n if (!isBinaryFailure(result)) {\n // Bundled binary works, cache it\n resolvedRgPath = rgPath;\n rgPathChecked = true;\n return result;\n }\n\n // Bundled binary failed, try system rg\n const fallbackResult = await spawnRg('rg', args, opts);\n \n if (!isBinaryFailure(fallbackResult)) {\n // System rg works, cache it\n resolvedRgPath = 'rg';\n rgPathChecked = true;\n return fallbackResult;\n }\n\n // Neither works, mark as checked and return the original error\n rgPathChecked = true;\n return { \n stdout: '', \n stderr: 'Failed to spawn ripgrep. Neither bundled nor system rg is available.', \n exitCode: -1 \n };\n }\n\n // rgPathChecked is true but resolvedRgPath is null - no working rg found\n return { \n stdout: '', \n stderr: 'Failed to spawn ripgrep. Neither bundled nor system rg is available.', \n exitCode: -1 \n };\n}\n\n\n","import fs from 'fs';\nimport path from 'path';\n\nexport function resolveUnderRepo(repoRoot: string, targetPath: string): string {\n const absRoot = path.resolve(repoRoot);\n const resolved = path.resolve(absRoot, targetPath);\n ensureWithinRepo(absRoot, resolved);\n return resolved;\n}\n\nexport function ensureWithinRepo(repoRoot: string, absTarget: string): void {\n const rel = path.relative(path.resolve(repoRoot), path.resolve(absTarget));\n if (rel.startsWith('..') || path.isAbsolute(rel)) {\n throw new Error(`Path outside repository root: ${absTarget}`);\n }\n}\n\nexport function toRepoRelative(repoRoot: string, absPath: string): string {\n return path.relative(path.resolve(repoRoot), path.resolve(absPath));\n}\n\nexport function isSymlink(p: string): boolean {\n try {\n const st = fs.lstatSync(p);\n return st.isSymbolicLink();\n } catch {\n return false;\n }\n}\n\n/**\n * Detects and removes consecutive duplicate path segments.\n *\n * When the model predicts a path that includes the repo directory name,\n * joining with repoRoot creates duplication:\n * repoRoot=\"/Users/dhruv/repo\" + predicted=\"repo/src/file.ts\"\n * → \"/Users/dhruv/repo/repo/src/file.ts\"\n *\n * This function detects such patterns and returns the corrected path,\n * or null if no duplication is found.\n */\nexport function fixPathRepetition(fullPath: string): string | null {\n const segments = fullPath.split(path.sep).filter(Boolean);\n if (segments.length < 2) return null;\n\n for (let len = Math.floor(segments.length / 2); len >= 1; len--) {\n for (let i = 0; i <= segments.length - 2 * len; i++) {\n const first = segments.slice(i, i + len);\n const second = segments.slice(i + len, i + 2 * len);\n\n if (first.every((seg, idx) => seg === second[idx])) {\n const fixed = [...segments.slice(0, i), ...segments.slice(i + len)];\n return path.sep + fixed.join(path.sep);\n }\n }\n }\n\n return null;\n}\n\nexport function isTextualFile(filePath: string, maxBytes = 2_000_000): boolean {\n try {\n const st = fs.statSync(filePath);\n if (!st.isFile()) return false;\n if (st.size > maxBytes) return false;\n const fd = fs.openSync(filePath, 'r');\n const buf = Buffer.alloc(512);\n const read = fs.readSync(fd, buf, 0, buf.length, 0);\n fs.closeSync(fd);\n for (let i = 0; i < read; i++) {\n const c = buf[i];\n if (c === 0) return false; // binary heuristic\n }\n return true;\n } catch {\n return false;\n }\n}\n\n\n","import fs from 'fs/promises';\n\nexport async function readAllLines(filePath: string): Promise<string[]> {\n const content = await fs.readFile(filePath, 'utf8');\n // Preserve newlines; split keeping consistency\n return content.split(/\\r?\\n/);\n}\n\n\n","export const AGENT_CONFIG = {\n MAX_TURNS: 4,\n TIMEOUT_MS: 30_000,\n MAX_CONTEXT_CHARS: 540_000,\n MAX_OUTPUT_LINES: 200,\n MAX_READ_LINES: 800,\n MAX_LIST_DEPTH: 3,\n LIST_TIMEOUT_MS: 2_000,\n};\n\n/**\n * Comprehensive exclusion list for directories and files\n * These patterns are used with ripgrep's -g flag\n */\nconst BUILTIN_EXCLUDES = [\n // Version control\n '.git', '.svn', '.hg', '.bzr',\n \n // Dependencies\n 'node_modules', 'bower_components', '.pnpm', '.yarn',\n 'vendor', 'packages', 'Pods', '.bundle',\n \n // Python\n '__pycache__', '.pytest_cache', '.mypy_cache', '.ruff_cache',\n '.venv', 'venv', '.tox', '.nox', '.eggs', '*.egg-info',\n \n // Build outputs\n 'dist', 'build', 'out', 'output', 'target', '_build',\n '.next', '.nuxt', '.output', '.vercel', '.netlify',\n \n // Cache directories\n '.cache', '.parcel-cache', '.turbo', '.nx', '.gradle',\n \n // IDE/Editor\n '.idea', '.vscode', '.vs',\n \n // Coverage\n 'coverage', '.coverage', 'htmlcov', '.nyc_output',\n \n // Temporary\n 'tmp', 'temp', '.tmp', '.temp',\n \n // Lock files\n 'package-lock.json', 'yarn.lock', 'pnpm-lock.yaml', 'bun.lockb',\n 'Cargo.lock', 'Gemfile.lock', 'poetry.lock',\n \n // Binary/minified\n '*.min.js', '*.min.css', '*.bundle.js',\n '*.wasm', '*.so', '*.dll', '*.pyc',\n '*.map', '*.js.map',\n \n // Hidden directories catch-all\n '.*',\n];\n\nexport const DEFAULT_EXCLUDES = (process.env.MORPH_WARP_GREP_EXCLUDE || '')\n .split(',')\n .map(s => s.trim())\n .filter(Boolean)\n .concat(BUILTIN_EXCLUDES);\n\nexport const DEFAULT_MODEL = 'morph-warp-grep-v1';\n\n\n"],"mappings":"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","names":["import_promises","import_path","path","fs","fs","fs","path"]}
1
+ {"version":3,"sources":["../../../../tools/warp_grep/providers/local.ts","../../../../tools/warp_grep/utils/ripgrep.ts","../../../../tools/warp_grep/utils/paths.ts","../../../../tools/warp_grep/utils/files.ts","../../../../tools/warp_grep/agent/config.ts"],"sourcesContent":["import fs from 'fs/promises';\nimport fssync from 'fs';\nimport path from 'path';\nimport { runRipgrep } from '../utils/ripgrep.js';\nimport { ensureWithinRepo, resolveUnderRepo, toRepoRelative, isSymlink, isTextualFile, fixPathRepetition } from '../utils/paths.js';\nimport type { WarpGrepProvider, GrepResult, ReadResult, ListDirectoryEntry } from './types.js';\nimport { readAllLines } from '../utils/files.js';\nimport { DEFAULT_EXCLUDES, AGENT_CONFIG } from '../agent/config.js';\n\n/**\n * Directories/files to always skip (exact name match)\n */\nconst SKIP_NAMES = new Set([\n // Version control\n '.git', '.svn', '.hg', '.bzr',\n // Dependencies\n 'node_modules', 'bower_components', '.pnpm', '.yarn',\n 'vendor', 'Pods', '.bundle',\n // Python\n '__pycache__', '.pytest_cache', '.mypy_cache', '.ruff_cache',\n '.venv', 'venv', '.tox', '.nox', '.eggs',\n // Build outputs\n 'dist', 'build', 'out', 'output', 'target', '_build',\n '.next', '.nuxt', '.output', '.vercel', '.netlify',\n // Cache\n '.cache', '.parcel-cache', '.turbo', '.nx', '.gradle',\n // IDE\n '.idea', '.vscode', '.vs',\n // Coverage\n 'coverage', '.coverage', 'htmlcov', '.nyc_output',\n // Temp\n 'tmp', 'temp', '.tmp', '.temp',\n // Lock files\n 'package-lock.json', 'yarn.lock', 'pnpm-lock.yaml', 'bun.lockb',\n 'Cargo.lock', 'Gemfile.lock', 'poetry.lock',\n]);\n\n/**\n * File extensions to skip\n */\nconst SKIP_EXTENSIONS = new Set([\n '.min.js', '.min.css', '.bundle.js',\n '.wasm', '.so', '.dll', '.pyc',\n '.map', '.js.map',\n]);\n\n/**\n * Check if a filename should be skipped\n */\nfunction shouldSkip(name: string): boolean {\n // Skip exact name matches\n if (SKIP_NAMES.has(name)) return true;\n \n // Skip hidden files/directories (start with .)\n if (name.startsWith('.')) return true;\n \n // Skip files with certain extensions\n for (const ext of SKIP_EXTENSIONS) {\n if (name.endsWith(ext)) return true;\n }\n \n return false;\n}\n\nexport class LocalRipgrepProvider implements WarpGrepProvider {\n constructor(private readonly repoRoot: string, private readonly excludes: string[] = DEFAULT_EXCLUDES) {}\n\n async grep(params: { pattern: string; path: string; glob?: string }): Promise<GrepResult> {\n let abs: string;\n try {\n abs = resolveUnderRepo(this.repoRoot, params.path);\n } catch (err) {\n return {\n lines: [],\n error: `[PATH ERROR] ${err instanceof Error ? err.message : String(err)}`,\n };\n }\n const stat = await fs.stat(abs).catch(() => null);\n if (!stat) return { lines: [] };\n const targetArg = abs === path.resolve(this.repoRoot) ? '.' : toRepoRelative(this.repoRoot, abs);\n const args = [\n '--no-config',\n '--no-heading',\n '--with-filename',\n '--line-number',\n '--color=never',\n '--trim',\n '--max-columns=400',\n '-C', '1',\n ...(params.glob ? ['--glob', params.glob] : []),\n ...this.excludes.flatMap((e) => ['-g', `!${e}`]),\n params.pattern,\n targetArg || '.',\n ];\n const res = await runRipgrep(args, { cwd: this.repoRoot });\n \n // Gracefully handle ripgrep not being available\n if (res.exitCode === -1) {\n return {\n lines: [],\n error: `[RIPGREP NOT AVAILABLE] ripgrep (rg) is required but failed to execute. Please install it:\\n` +\n ` • macOS: brew install ripgrep\\n` +\n ` • Ubuntu/Debian: apt install ripgrep\\n` +\n ` • Windows: choco install ripgrep\\n` +\n ` • Or visit: https://github.com/BurntSushi/ripgrep#installation\\n` +\n `Exit code: ${res.exitCode}${res.stderr ? `\\nDetails: ${res.stderr}` : ''}`,\n };\n }\n \n // Handle other ripgrep errors gracefully\n if (res.exitCode !== 0 && res.exitCode !== 1) {\n return {\n lines: [],\n error: `[RIPGREP ERROR] grep failed with exit code ${res.exitCode}${res.stderr ? `: ${res.stderr}` : ''}`,\n };\n }\n \n const lines = (res.stdout || '')\n .trim()\n .split(/\\r?\\n/)\n .filter((l) => l.length > 0);\n if (lines.length > AGENT_CONFIG.MAX_OUTPUT_LINES) {\n return {\n lines: [],\n error: 'query not specific enough, tool tried to return too much context and failed',\n };\n }\n \n return { lines };\n }\n\n async read(params: { path: string; start?: number; end?: number }): Promise<ReadResult> {\n let abs: string;\n try {\n abs = resolveUnderRepo(this.repoRoot, params.path);\n } catch (err) {\n return {\n lines: [],\n error: `[PATH ERROR] ${err instanceof Error ? err.message : String(err)}`,\n };\n }\n let stat = await fs.stat(abs).catch(() => null);\n\n // Handle duplicate path segments from model predictions\n if (!stat || !stat.isFile()) {\n const fixedPath = fixPathRepetition(abs);\n if (fixedPath) {\n const fixedStat = await fs.stat(fixedPath).catch(() => null);\n if (fixedStat?.isFile()) {\n abs = fixedPath;\n stat = fixedStat;\n }\n }\n }\n\n // Gracefully handle file not found / not a file\n if (!stat || !stat.isFile()) {\n return {\n lines: [],\n error: `[FILE NOT FOUND] You tried to read \"${params.path}\" but there is no file at this path. ` +\n `Double-check the path exists and is spelled correctly.`,\n };\n }\n \n // Gracefully handle symlinks\n if (isSymlink(abs)) {\n return {\n lines: [],\n error: `[SYMLINK] You tried to read \"${params.path}\" but this is a symlink. ` +\n `Try reading the actual file it points to instead.`,\n };\n }\n \n // Gracefully handle non-text or too-large files\n if (!isTextualFile(abs)) {\n return {\n lines: [],\n error: `[UNREADABLE FILE] You tried to read \"${params.path}\" but this file is either too large ` +\n `or not a text file, so it cannot be read. Try a different file.`,\n };\n }\n \n let lines: string[];\n try {\n lines = await readAllLines(abs);\n } catch (err) {\n return {\n lines: [],\n error: `[READ ERROR] Failed to read \"${params.path}\": ${err instanceof Error ? err.message : String(err)}`,\n };\n }\n const total = lines.length;\n const rawStart = params.start;\n const rawEnd = params.end;\n \n let s = 1;\n let e = total;\n \n const startValid = rawStart === undefined || (Number.isFinite(rawStart) && rawStart > 0);\n const endValid = rawEnd === undefined || (Number.isFinite(rawEnd) && rawEnd > 0);\n \n if (startValid && endValid) {\n s = rawStart ?? 1;\n e = Math.min(rawEnd ?? total, total);\n if ((s > total && total > 0) || (s > e)) {\n s = 1;\n e = total;\n }\n }\n const out: string[] = [];\n for (let i = s; i <= e; i += 1) {\n const content = lines[i - 1] ?? '';\n out.push(`${i}|${content}`);\n }\n if (out.length > AGENT_CONFIG.MAX_READ_LINES) {\n const truncated = out.slice(0, AGENT_CONFIG.MAX_READ_LINES);\n truncated.push(`... [truncated: showing ${AGENT_CONFIG.MAX_READ_LINES} of ${out.length} lines]`);\n return { lines: truncated };\n }\n \n return { lines: out };\n }\n\n async listDirectory(params: { path: string; pattern?: string | null; maxResults?: number; maxDepth?: number }): Promise<ListDirectoryEntry[]> {\n let abs: string;\n try {\n abs = resolveUnderRepo(this.repoRoot, params.path);\n } catch {\n // Path outside repo - return empty (graceful failure)\n return [];\n }\n const stat = await fs.stat(abs).catch(() => null);\n if (!stat || !stat.isDirectory()) {\n return [];\n }\n const maxResults = params.maxResults ?? AGENT_CONFIG.MAX_OUTPUT_LINES;\n const maxDepth = params.maxDepth ?? AGENT_CONFIG.MAX_LIST_DEPTH;\n const regex = params.pattern ? new RegExp(params.pattern) : null;\n const repoRoot = this.repoRoot;\n\n const results: ListDirectoryEntry[] = [];\n let timedOut = false;\n const startTime = Date.now();\n \n async function walk(dir: string, depth: number) {\n if (Date.now() - startTime > AGENT_CONFIG.LIST_TIMEOUT_MS) {\n timedOut = true;\n return;\n }\n if (depth > maxDepth || results.length >= maxResults) return;\n const entries = await fs.readdir(dir, { withFileTypes: true });\n for (const entry of entries) {\n if (timedOut || results.length >= maxResults) break;\n \n // Simple name-based filtering - skip junk dirs/files\n if (shouldSkip(entry.name)) continue;\n \n // Apply user-provided pattern filter\n if (regex && !regex.test(entry.name)) continue;\n \n const full = path.join(dir, entry.name);\n const isDir = entry.isDirectory();\n \n results.push({\n name: entry.name,\n path: toRepoRelative(repoRoot, full),\n type: isDir ? 'dir' : 'file',\n depth,\n });\n if (isDir) {\n await walk(full, depth + 1);\n }\n }\n }\n await walk(abs, 0);\n return results;\n }\n}\n\n\n","import { spawn } from 'child_process';\nimport { rgPath } from '@vscode/ripgrep';\n\nexport type ExecResult = { stdout: string; stderr: string; exitCode: number };\n\n// Cache the working ripgrep path to avoid repeated fallback checks\nlet resolvedRgPath: string | null = null;\nlet rgPathChecked = false;\n\nfunction spawnRg(rgBinary: string, args: string[], opts?: { cwd?: string; env?: NodeJS.ProcessEnv }): Promise<ExecResult> {\n return new Promise((resolve) => {\n const child = spawn(rgBinary, args, {\n cwd: opts?.cwd,\n env: { ...process.env, ...(opts?.env || {}) },\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n let stdout = '';\n let stderr = '';\n child.stdout.on('data', (d) => (stdout += d.toString()));\n child.stderr.on('data', (d) => (stderr += d.toString()));\n child.on('close', (code) => {\n resolve({ stdout, stderr, exitCode: typeof code === 'number' ? code : -1 });\n });\n child.on('error', () => {\n resolve({ stdout: '', stderr: 'Failed to spawn ripgrep.', exitCode: -1 });\n });\n });\n}\n\n// Check if a result indicates a binary compatibility failure (not a normal rg error)\nfunction isBinaryFailure(result: ExecResult): boolean {\n // Spawn error\n if (result.exitCode === -1) return true;\n // jemalloc page size issue (common on ARM64 with non-standard page sizes)\n if (result.stderr.includes('jemalloc') || result.stderr.includes('Unsupported system page size')) return true;\n // SIGABRT (134 = 128 + 6)\n if (result.exitCode === 134) return true;\n return false;\n}\n\nexport async function runRipgrep(args: string[], opts?: { cwd?: string; env?: NodeJS.ProcessEnv }): Promise<ExecResult> {\n // If we've already determined the working path, use it\n if (rgPathChecked && resolvedRgPath) {\n return spawnRg(resolvedRgPath, args, opts);\n }\n\n // First attempt: bundled ripgrep\n if (!rgPathChecked) {\n const result = await spawnRg(rgPath, args, opts);\n \n if (!isBinaryFailure(result)) {\n // Bundled binary works, cache it\n resolvedRgPath = rgPath;\n rgPathChecked = true;\n return result;\n }\n\n // Bundled binary failed, try system rg\n const fallbackResult = await spawnRg('rg', args, opts);\n \n if (!isBinaryFailure(fallbackResult)) {\n // System rg works, cache it\n resolvedRgPath = 'rg';\n rgPathChecked = true;\n return fallbackResult;\n }\n\n // Neither works, mark as checked and return the original error\n rgPathChecked = true;\n return { \n stdout: '', \n stderr: 'Failed to spawn ripgrep. Neither bundled nor system rg is available.', \n exitCode: -1 \n };\n }\n\n // rgPathChecked is true but resolvedRgPath is null - no working rg found\n return { \n stdout: '', \n stderr: 'Failed to spawn ripgrep. Neither bundled nor system rg is available.', \n exitCode: -1 \n };\n}\n\n\n","import fs from 'fs';\nimport path from 'path';\n\nexport function resolveUnderRepo(repoRoot: string, targetPath: string): string {\n const absRoot = path.resolve(repoRoot);\n const resolved = path.resolve(absRoot, targetPath);\n ensureWithinRepo(absRoot, resolved);\n return resolved;\n}\n\nexport function ensureWithinRepo(repoRoot: string, absTarget: string): void {\n const rel = path.relative(path.resolve(repoRoot), path.resolve(absTarget));\n if (rel.startsWith('..') || path.isAbsolute(rel)) {\n throw new Error(`Path outside repository root: ${absTarget}`);\n }\n}\n\nexport function toRepoRelative(repoRoot: string, absPath: string): string {\n return path.relative(path.resolve(repoRoot), path.resolve(absPath));\n}\n\nexport function isSymlink(p: string): boolean {\n try {\n const st = fs.lstatSync(p);\n return st.isSymbolicLink();\n } catch {\n return false;\n }\n}\n\n/**\n * Detects and removes consecutive duplicate path segments.\n *\n * When the model predicts a path that includes the repo directory name,\n * joining with repoRoot creates duplication:\n * repoRoot=\"/Users/dhruv/repo\" + predicted=\"repo/src/file.ts\"\n * → \"/Users/dhruv/repo/repo/src/file.ts\"\n *\n * This function detects such patterns and returns the corrected path,\n * or null if no duplication is found.\n */\nexport function fixPathRepetition(fullPath: string): string | null {\n const segments = fullPath.split(path.sep).filter(Boolean);\n if (segments.length < 2) return null;\n\n for (let len = Math.floor(segments.length / 2); len >= 1; len--) {\n for (let i = 0; i <= segments.length - 2 * len; i++) {\n const first = segments.slice(i, i + len);\n const second = segments.slice(i + len, i + 2 * len);\n\n if (first.every((seg, idx) => seg === second[idx])) {\n const fixed = [...segments.slice(0, i), ...segments.slice(i + len)];\n return path.sep + fixed.join(path.sep);\n }\n }\n }\n\n return null;\n}\n\nexport function isTextualFile(filePath: string, maxBytes = 2_000_000): boolean {\n try {\n const st = fs.statSync(filePath);\n if (!st.isFile()) return false;\n if (st.size > maxBytes) return false;\n const fd = fs.openSync(filePath, 'r');\n const buf = Buffer.alloc(512);\n const read = fs.readSync(fd, buf, 0, buf.length, 0);\n fs.closeSync(fd);\n for (let i = 0; i < read; i++) {\n const c = buf[i];\n if (c === 0) return false; // binary heuristic\n }\n return true;\n } catch {\n return false;\n }\n}\n\n\n","import fs from 'fs/promises';\n\nexport async function readAllLines(filePath: string): Promise<string[]> {\n const content = await fs.readFile(filePath, 'utf8');\n // Preserve newlines; split keeping consistency\n return content.split(/\\r?\\n/);\n}\n\n\n","// Parse timeout from env, defaulting to 30 seconds\nconst parseEnvTimeout = (envValue: string | undefined, defaultMs: number): number => {\n if (!envValue) return defaultMs;\n const parsed = parseInt(envValue, 10);\n return isNaN(parsed) || parsed <= 0 ? defaultMs : parsed;\n};\n\nexport const AGENT_CONFIG = {\n MAX_TURNS: 4,\n /** Default timeout for model calls. Can be overridden via MORPH_WARP_GREP_TIMEOUT env var (in ms) */\n TIMEOUT_MS: parseEnvTimeout(process.env.MORPH_WARP_GREP_TIMEOUT, 30_000),\n MAX_CONTEXT_CHARS: 540_000,\n MAX_OUTPUT_LINES: 200,\n MAX_READ_LINES: 800,\n MAX_LIST_DEPTH: 3,\n LIST_TIMEOUT_MS: 2_000,\n};\n\n/**\n * Comprehensive exclusion list for directories and files\n * These patterns are used with ripgrep's -g flag\n */\nconst BUILTIN_EXCLUDES = [\n // Version control\n '.git', '.svn', '.hg', '.bzr',\n \n // Dependencies\n 'node_modules', 'bower_components', '.pnpm', '.yarn',\n 'vendor', 'packages', 'Pods', '.bundle',\n \n // Python\n '__pycache__', '.pytest_cache', '.mypy_cache', '.ruff_cache',\n '.venv', 'venv', '.tox', '.nox', '.eggs', '*.egg-info',\n \n // Build outputs\n 'dist', 'build', 'out', 'output', 'target', '_build',\n '.next', '.nuxt', '.output', '.vercel', '.netlify',\n \n // Cache directories\n '.cache', '.parcel-cache', '.turbo', '.nx', '.gradle',\n \n // IDE/Editor\n '.idea', '.vscode', '.vs',\n \n // Coverage\n 'coverage', '.coverage', 'htmlcov', '.nyc_output',\n \n // Temporary\n 'tmp', 'temp', '.tmp', '.temp',\n \n // Lock files\n 'package-lock.json', 'yarn.lock', 'pnpm-lock.yaml', 'bun.lockb',\n 'Cargo.lock', 'Gemfile.lock', 'poetry.lock',\n \n // Binary/minified\n '*.min.js', '*.min.css', '*.bundle.js',\n '*.wasm', '*.so', '*.dll', '*.pyc',\n '*.map', '*.js.map',\n \n // Hidden directories catch-all\n '.*',\n];\n\nexport const DEFAULT_EXCLUDES = (process.env.MORPH_WARP_GREP_EXCLUDE || '')\n .split(',')\n .map(s => s.trim())\n .filter(Boolean)\n .concat(BUILTIN_EXCLUDES);\n\nexport const DEFAULT_MODEL = 'morph-warp-grep-v1';\n\n\n"],"mappings":"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","names":["import_promises","import_path","path","fs","fs","fs","path"]}
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  LocalRipgrepProvider
3
- } from "../../../chunk-4NI25AKV.js";
3
+ } from "../../../chunk-4KMBU6T3.js";
4
4
  import "../../../chunk-G2RSY56Q.js";
5
5
  import "../../../chunk-YPKNMYD4.js";
6
6
  import "../../../chunk-TPP2UGQP.js";
7
- import "../../../chunk-XT5ZO6ES.js";
7
+ import "../../../chunk-5PNMAWLC.js";
8
8
  import "../../../chunk-PZ5AY32C.js";
9
9
  export {
10
10
  LocalRipgrepProvider
@@ -25,9 +25,15 @@ __export(remote_exports, {
25
25
  module.exports = __toCommonJS(remote_exports);
26
26
 
27
27
  // tools/warp_grep/agent/config.ts
28
+ var parseEnvTimeout = (envValue, defaultMs) => {
29
+ if (!envValue) return defaultMs;
30
+ const parsed = parseInt(envValue, 10);
31
+ return isNaN(parsed) || parsed <= 0 ? defaultMs : parsed;
32
+ };
28
33
  var AGENT_CONFIG = {
29
34
  MAX_TURNS: 4,
30
- TIMEOUT_MS: 3e4,
35
+ /** Default timeout for model calls. Can be overridden via MORPH_WARP_GREP_TIMEOUT env var (in ms) */
36
+ TIMEOUT_MS: parseEnvTimeout(process.env.MORPH_WARP_GREP_TIMEOUT, 3e4),
31
37
  MAX_CONTEXT_CHARS: 54e4,
32
38
  MAX_OUTPUT_LINES: 200,
33
39
  MAX_READ_LINES: 800,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../tools/warp_grep/providers/remote.ts","../../../../tools/warp_grep/agent/config.ts"],"sourcesContent":["/**\n * RemoteCommandsProvider - wraps simple RemoteCommands into WarpGrepProvider\n * \n * Handles parsing of raw stdout from grep/read/listDir commands.\n * Users just return stdout, SDK handles all format conversion.\n */\n\nimport type { WarpGrepProvider, GrepResult, ReadResult, ListDirectoryEntry } from './types.js';\nimport type { RemoteCommands } from '../types.js';\nimport { AGENT_CONFIG } from '../agent/config.js';\n\n/**\n * Directories/files to always skip (exact name match)\n */\nconst SKIP_NAMES = new Set([\n // Version control\n '.git', '.svn', '.hg', '.bzr',\n // Dependencies\n 'node_modules', 'bower_components', '.pnpm', '.yarn',\n 'vendor', 'Pods', '.bundle',\n // Python\n '__pycache__', '.pytest_cache', '.mypy_cache', '.ruff_cache',\n '.venv', 'venv', '.tox', '.nox', '.eggs',\n // Build outputs\n 'dist', 'build', 'out', 'output', 'target', '_build',\n '.next', '.nuxt', '.output', '.vercel', '.netlify',\n // Cache\n '.cache', '.parcel-cache', '.turbo', '.nx', '.gradle',\n // IDE\n '.idea', '.vscode', '.vs',\n // Coverage\n 'coverage', '.coverage', 'htmlcov', '.nyc_output',\n // Temp\n 'tmp', 'temp', '.tmp', '.temp',\n // Lock files\n 'package-lock.json', 'yarn.lock', 'pnpm-lock.yaml', 'bun.lockb',\n 'Cargo.lock', 'Gemfile.lock', 'poetry.lock',\n]);\n\n/**\n * File extensions to skip\n */\nconst SKIP_EXTENSIONS = new Set([\n '.min.js', '.min.css', '.bundle.js',\n '.wasm', '.so', '.dll', '.pyc',\n '.map', '.js.map',\n]);\n\n/**\n * Check if a filename should be skipped\n */\nfunction shouldSkip(name: string): boolean {\n // Skip exact name matches\n if (SKIP_NAMES.has(name)) return true;\n \n // Skip hidden files/directories (start with .)\n if (name.startsWith('.')) return true;\n \n // Skip files with certain extensions\n for (const ext of SKIP_EXTENSIONS) {\n if (name.endsWith(ext)) return true;\n }\n \n return false;\n}\n\n/**\n * Wraps simple RemoteCommands functions into a full WarpGrepProvider.\n * \n * This allows users to provide three simple functions that return raw stdout,\n * and the SDK handles all parsing internally.\n * \n * @example\n * ```typescript\n * const provider = new RemoteCommandsProvider('/home/repo', {\n * grep: async (pattern, path) => {\n * const r = await sandbox.run(`rg '${pattern}' '${path}'`);\n * return r.stdout;\n * },\n * read: async (path, start, end) => {\n * const r = await sandbox.run(`sed -n '${start},${end}p' '${path}'`);\n * return r.stdout;\n * },\n * listDir: async (path, maxDepth) => {\n * const r = await sandbox.run(`find '${path}' -maxdepth ${maxDepth}`);\n * return r.stdout;\n * },\n * });\n * ```\n */\nexport class RemoteCommandsProvider implements WarpGrepProvider {\n constructor(\n private readonly repoRoot: string,\n private readonly commands: RemoteCommands\n ) {}\n\n /**\n * Run grep command and parse ripgrep output\n */\n async grep(params: { pattern: string; path: string; glob?: string }): Promise<GrepResult> {\n try {\n const stdout = await this.commands.grep(params.pattern, params.path, params.glob);\n \n // Parse ripgrep output: each line is \"path:line:content\" or \"path-line-content\" for context\n const lines = (stdout || '')\n .trim()\n .split(/\\r?\\n/)\n .filter((l) => l.length > 0);\n \n // Check if output is too large\n if (lines.length > AGENT_CONFIG.MAX_OUTPUT_LINES) {\n return {\n lines: [],\n error: 'Query not specific enough - too many results returned. Try a more specific pattern.',\n };\n }\n \n return { lines };\n } catch (error) {\n return {\n lines: [],\n error: `[GREP ERROR] ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n }\n\n /**\n * Read file and add line numbers\n */\n async read(params: { path: string; start?: number; end?: number }): Promise<ReadResult> {\n const rawStart = params.start;\n const rawEnd = params.end;\n \n const startValid = rawStart === undefined || (Number.isFinite(rawStart) && rawStart > 0);\n const endValid = rawEnd === undefined || (Number.isFinite(rawEnd) && rawEnd > 0);\n const rangeValid = startValid && endValid && \n (rawStart === undefined || rawEnd === undefined || rawStart <= rawEnd);\n \n const start = rangeValid && rawStart !== undefined ? rawStart : 1;\n const end = rangeValid && rawEnd !== undefined ? rawEnd : 1_000_000;\n \n try {\n const stdout = await this.commands.read(params.path, start, end);\n \n // Split content into lines and add line numbers\n const contentLines = (stdout || '').split('\\n');\n \n // Remove trailing empty line if present (common with sed output)\n if (contentLines.length > 0 && contentLines[contentLines.length - 1] === '') {\n contentLines.pop();\n }\n \n // Format as \"lineNumber|content\"\n const lines = contentLines.map((content, idx) => `${start + idx}|${content}`);\n \n // Check if output is too large\n if (lines.length > AGENT_CONFIG.MAX_READ_LINES) {\n const truncated = lines.slice(0, AGENT_CONFIG.MAX_READ_LINES);\n truncated.push(`... [truncated: showing ${AGENT_CONFIG.MAX_READ_LINES} of ${lines.length} lines]`);\n return { lines: truncated };\n }\n \n return { lines };\n } catch (error) {\n return {\n lines: [],\n error: `[READ ERROR] ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n }\n\n /**\n * List directory and parse find output\n */\n async listDirectory(params: { \n path: string; \n pattern?: string | null; \n maxResults?: number; \n maxDepth?: number;\n }): Promise<ListDirectoryEntry[]> {\n const maxDepth = params.maxDepth ?? AGENT_CONFIG.MAX_LIST_DEPTH;\n const maxResults = params.maxResults ?? AGENT_CONFIG.MAX_OUTPUT_LINES;\n \n try {\n const stdout = await this.commands.listDir(params.path, maxDepth);\n \n // Parse find output: one path per line\n const paths = (stdout || '')\n .trim()\n .split(/\\r?\\n/)\n .filter((p) => p.length > 0);\n \n const regex = params.pattern ? new RegExp(params.pattern) : null;\n const entries: ListDirectoryEntry[] = [];\n \n for (const fullPath of paths) {\n // Skip the root path itself\n if (fullPath === params.path || fullPath === this.repoRoot) continue;\n \n const name = fullPath.split('/').pop() || '';\n \n // Simple name-based filtering - skip junk dirs/files\n if (shouldSkip(name)) continue;\n \n // Apply pattern filter if provided\n if (regex && !regex.test(name)) continue;\n \n // Determine relative path\n let relativePath = fullPath;\n if (fullPath.startsWith(this.repoRoot)) {\n relativePath = fullPath.slice(this.repoRoot.length).replace(/^\\//, '');\n }\n \n // Calculate depth based on path separators\n const depth = relativePath.split('/').filter(Boolean).length - 1;\n \n // Determine if it's a directory (ends with / or infer from path structure)\n // Note: Most sandbox find commands don't indicate type, so we guess based on extension\n const hasExtension = name.includes('.') && !name.startsWith('.');\n const type: 'file' | 'dir' = hasExtension ? 'file' : 'dir';\n \n entries.push({\n name,\n path: relativePath,\n type,\n depth: Math.max(0, depth),\n });\n \n if (entries.length >= maxResults) break;\n }\n \n return entries;\n } catch (error) {\n // Return empty array on error (consistent with LocalRipgrepProvider)\n return [];\n }\n }\n}\n\n\n\n\n","export const AGENT_CONFIG = {\n MAX_TURNS: 4,\n TIMEOUT_MS: 30_000,\n MAX_CONTEXT_CHARS: 540_000,\n MAX_OUTPUT_LINES: 200,\n MAX_READ_LINES: 800,\n MAX_LIST_DEPTH: 3,\n LIST_TIMEOUT_MS: 2_000,\n};\n\n/**\n * Comprehensive exclusion list for directories and files\n * These patterns are used with ripgrep's -g flag\n */\nconst BUILTIN_EXCLUDES = [\n // Version control\n '.git', '.svn', '.hg', '.bzr',\n \n // Dependencies\n 'node_modules', 'bower_components', '.pnpm', '.yarn',\n 'vendor', 'packages', 'Pods', '.bundle',\n \n // Python\n '__pycache__', '.pytest_cache', '.mypy_cache', '.ruff_cache',\n '.venv', 'venv', '.tox', '.nox', '.eggs', '*.egg-info',\n \n // Build outputs\n 'dist', 'build', 'out', 'output', 'target', '_build',\n '.next', '.nuxt', '.output', '.vercel', '.netlify',\n \n // Cache directories\n '.cache', '.parcel-cache', '.turbo', '.nx', '.gradle',\n \n // IDE/Editor\n '.idea', '.vscode', '.vs',\n \n // Coverage\n 'coverage', '.coverage', 'htmlcov', '.nyc_output',\n \n // Temporary\n 'tmp', 'temp', '.tmp', '.temp',\n \n // Lock files\n 'package-lock.json', 'yarn.lock', 'pnpm-lock.yaml', 'bun.lockb',\n 'Cargo.lock', 'Gemfile.lock', 'poetry.lock',\n \n // Binary/minified\n '*.min.js', '*.min.css', '*.bundle.js',\n '*.wasm', '*.so', '*.dll', '*.pyc',\n '*.map', '*.js.map',\n \n // Hidden directories catch-all\n '.*',\n];\n\nexport const DEFAULT_EXCLUDES = (process.env.MORPH_WARP_GREP_EXCLUDE || '')\n .split(',')\n .map(s => s.trim())\n .filter(Boolean)\n .concat(BUILTIN_EXCLUDES);\n\nexport const DEFAULT_MODEL = 'morph-warp-grep-v1';\n\n\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../tools/warp_grep/providers/remote.ts","../../../../tools/warp_grep/agent/config.ts"],"sourcesContent":["/**\n * RemoteCommandsProvider - wraps simple RemoteCommands into WarpGrepProvider\n * \n * Handles parsing of raw stdout from grep/read/listDir commands.\n * Users just return stdout, SDK handles all format conversion.\n */\n\nimport type { WarpGrepProvider, GrepResult, ReadResult, ListDirectoryEntry } from './types.js';\nimport type { RemoteCommands } from '../types.js';\nimport { AGENT_CONFIG } from '../agent/config.js';\n\n/**\n * Directories/files to always skip (exact name match)\n */\nconst SKIP_NAMES = new Set([\n // Version control\n '.git', '.svn', '.hg', '.bzr',\n // Dependencies\n 'node_modules', 'bower_components', '.pnpm', '.yarn',\n 'vendor', 'Pods', '.bundle',\n // Python\n '__pycache__', '.pytest_cache', '.mypy_cache', '.ruff_cache',\n '.venv', 'venv', '.tox', '.nox', '.eggs',\n // Build outputs\n 'dist', 'build', 'out', 'output', 'target', '_build',\n '.next', '.nuxt', '.output', '.vercel', '.netlify',\n // Cache\n '.cache', '.parcel-cache', '.turbo', '.nx', '.gradle',\n // IDE\n '.idea', '.vscode', '.vs',\n // Coverage\n 'coverage', '.coverage', 'htmlcov', '.nyc_output',\n // Temp\n 'tmp', 'temp', '.tmp', '.temp',\n // Lock files\n 'package-lock.json', 'yarn.lock', 'pnpm-lock.yaml', 'bun.lockb',\n 'Cargo.lock', 'Gemfile.lock', 'poetry.lock',\n]);\n\n/**\n * File extensions to skip\n */\nconst SKIP_EXTENSIONS = new Set([\n '.min.js', '.min.css', '.bundle.js',\n '.wasm', '.so', '.dll', '.pyc',\n '.map', '.js.map',\n]);\n\n/**\n * Check if a filename should be skipped\n */\nfunction shouldSkip(name: string): boolean {\n // Skip exact name matches\n if (SKIP_NAMES.has(name)) return true;\n \n // Skip hidden files/directories (start with .)\n if (name.startsWith('.')) return true;\n \n // Skip files with certain extensions\n for (const ext of SKIP_EXTENSIONS) {\n if (name.endsWith(ext)) return true;\n }\n \n return false;\n}\n\n/**\n * Wraps simple RemoteCommands functions into a full WarpGrepProvider.\n * \n * This allows users to provide three simple functions that return raw stdout,\n * and the SDK handles all parsing internally.\n * \n * @example\n * ```typescript\n * const provider = new RemoteCommandsProvider('/home/repo', {\n * grep: async (pattern, path) => {\n * const r = await sandbox.run(`rg '${pattern}' '${path}'`);\n * return r.stdout;\n * },\n * read: async (path, start, end) => {\n * const r = await sandbox.run(`sed -n '${start},${end}p' '${path}'`);\n * return r.stdout;\n * },\n * listDir: async (path, maxDepth) => {\n * const r = await sandbox.run(`find '${path}' -maxdepth ${maxDepth}`);\n * return r.stdout;\n * },\n * });\n * ```\n */\nexport class RemoteCommandsProvider implements WarpGrepProvider {\n constructor(\n private readonly repoRoot: string,\n private readonly commands: RemoteCommands\n ) {}\n\n /**\n * Run grep command and parse ripgrep output\n */\n async grep(params: { pattern: string; path: string; glob?: string }): Promise<GrepResult> {\n try {\n const stdout = await this.commands.grep(params.pattern, params.path, params.glob);\n \n // Parse ripgrep output: each line is \"path:line:content\" or \"path-line-content\" for context\n const lines = (stdout || '')\n .trim()\n .split(/\\r?\\n/)\n .filter((l) => l.length > 0);\n \n // Check if output is too large\n if (lines.length > AGENT_CONFIG.MAX_OUTPUT_LINES) {\n return {\n lines: [],\n error: 'Query not specific enough - too many results returned. Try a more specific pattern.',\n };\n }\n \n return { lines };\n } catch (error) {\n return {\n lines: [],\n error: `[GREP ERROR] ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n }\n\n /**\n * Read file and add line numbers\n */\n async read(params: { path: string; start?: number; end?: number }): Promise<ReadResult> {\n const rawStart = params.start;\n const rawEnd = params.end;\n \n const startValid = rawStart === undefined || (Number.isFinite(rawStart) && rawStart > 0);\n const endValid = rawEnd === undefined || (Number.isFinite(rawEnd) && rawEnd > 0);\n const rangeValid = startValid && endValid && \n (rawStart === undefined || rawEnd === undefined || rawStart <= rawEnd);\n \n const start = rangeValid && rawStart !== undefined ? rawStart : 1;\n const end = rangeValid && rawEnd !== undefined ? rawEnd : 1_000_000;\n \n try {\n const stdout = await this.commands.read(params.path, start, end);\n \n // Split content into lines and add line numbers\n const contentLines = (stdout || '').split('\\n');\n \n // Remove trailing empty line if present (common with sed output)\n if (contentLines.length > 0 && contentLines[contentLines.length - 1] === '') {\n contentLines.pop();\n }\n \n // Format as \"lineNumber|content\"\n const lines = contentLines.map((content, idx) => `${start + idx}|${content}`);\n \n // Check if output is too large\n if (lines.length > AGENT_CONFIG.MAX_READ_LINES) {\n const truncated = lines.slice(0, AGENT_CONFIG.MAX_READ_LINES);\n truncated.push(`... [truncated: showing ${AGENT_CONFIG.MAX_READ_LINES} of ${lines.length} lines]`);\n return { lines: truncated };\n }\n \n return { lines };\n } catch (error) {\n return {\n lines: [],\n error: `[READ ERROR] ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n }\n\n /**\n * List directory and parse find output\n */\n async listDirectory(params: { \n path: string; \n pattern?: string | null; \n maxResults?: number; \n maxDepth?: number;\n }): Promise<ListDirectoryEntry[]> {\n const maxDepth = params.maxDepth ?? AGENT_CONFIG.MAX_LIST_DEPTH;\n const maxResults = params.maxResults ?? AGENT_CONFIG.MAX_OUTPUT_LINES;\n \n try {\n const stdout = await this.commands.listDir(params.path, maxDepth);\n \n // Parse find output: one path per line\n const paths = (stdout || '')\n .trim()\n .split(/\\r?\\n/)\n .filter((p) => p.length > 0);\n \n const regex = params.pattern ? new RegExp(params.pattern) : null;\n const entries: ListDirectoryEntry[] = [];\n \n for (const fullPath of paths) {\n // Skip the root path itself\n if (fullPath === params.path || fullPath === this.repoRoot) continue;\n \n const name = fullPath.split('/').pop() || '';\n \n // Simple name-based filtering - skip junk dirs/files\n if (shouldSkip(name)) continue;\n \n // Apply pattern filter if provided\n if (regex && !regex.test(name)) continue;\n \n // Determine relative path\n let relativePath = fullPath;\n if (fullPath.startsWith(this.repoRoot)) {\n relativePath = fullPath.slice(this.repoRoot.length).replace(/^\\//, '');\n }\n \n // Calculate depth based on path separators\n const depth = relativePath.split('/').filter(Boolean).length - 1;\n \n // Determine if it's a directory (ends with / or infer from path structure)\n // Note: Most sandbox find commands don't indicate type, so we guess based on extension\n const hasExtension = name.includes('.') && !name.startsWith('.');\n const type: 'file' | 'dir' = hasExtension ? 'file' : 'dir';\n \n entries.push({\n name,\n path: relativePath,\n type,\n depth: Math.max(0, depth),\n });\n \n if (entries.length >= maxResults) break;\n }\n \n return entries;\n } catch (error) {\n // Return empty array on error (consistent with LocalRipgrepProvider)\n return [];\n }\n }\n}\n\n\n\n\n","// Parse timeout from env, defaulting to 30 seconds\nconst parseEnvTimeout = (envValue: string | undefined, defaultMs: number): number => {\n if (!envValue) return defaultMs;\n const parsed = parseInt(envValue, 10);\n return isNaN(parsed) || parsed <= 0 ? defaultMs : parsed;\n};\n\nexport const AGENT_CONFIG = {\n MAX_TURNS: 4,\n /** Default timeout for model calls. Can be overridden via MORPH_WARP_GREP_TIMEOUT env var (in ms) */\n TIMEOUT_MS: parseEnvTimeout(process.env.MORPH_WARP_GREP_TIMEOUT, 30_000),\n MAX_CONTEXT_CHARS: 540_000,\n MAX_OUTPUT_LINES: 200,\n MAX_READ_LINES: 800,\n MAX_LIST_DEPTH: 3,\n LIST_TIMEOUT_MS: 2_000,\n};\n\n/**\n * Comprehensive exclusion list for directories and files\n * These patterns are used with ripgrep's -g flag\n */\nconst BUILTIN_EXCLUDES = [\n // Version control\n '.git', '.svn', '.hg', '.bzr',\n \n // Dependencies\n 'node_modules', 'bower_components', '.pnpm', '.yarn',\n 'vendor', 'packages', 'Pods', '.bundle',\n \n // Python\n '__pycache__', '.pytest_cache', '.mypy_cache', '.ruff_cache',\n '.venv', 'venv', '.tox', '.nox', '.eggs', '*.egg-info',\n \n // Build outputs\n 'dist', 'build', 'out', 'output', 'target', '_build',\n '.next', '.nuxt', '.output', '.vercel', '.netlify',\n \n // Cache directories\n '.cache', '.parcel-cache', '.turbo', '.nx', '.gradle',\n \n // IDE/Editor\n '.idea', '.vscode', '.vs',\n \n // Coverage\n 'coverage', '.coverage', 'htmlcov', '.nyc_output',\n \n // Temporary\n 'tmp', 'temp', '.tmp', '.temp',\n \n // Lock files\n 'package-lock.json', 'yarn.lock', 'pnpm-lock.yaml', 'bun.lockb',\n 'Cargo.lock', 'Gemfile.lock', 'poetry.lock',\n \n // Binary/minified\n '*.min.js', '*.min.css', '*.bundle.js',\n '*.wasm', '*.so', '*.dll', '*.pyc',\n '*.map', '*.js.map',\n \n // Hidden directories catch-all\n '.*',\n];\n\nexport const DEFAULT_EXCLUDES = (process.env.MORPH_WARP_GREP_EXCLUDE || '')\n .split(',')\n .map(s => s.trim())\n .filter(Boolean)\n .concat(BUILTIN_EXCLUDES);\n\nexport const DEFAULT_MODEL = 'morph-warp-grep-v1';\n\n\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACCA,IAAM,kBAAkB,CAAC,UAA8B,cAA8B;AACnF,MAAI,CAAC,SAAU,QAAO;AACtB,QAAM,SAAS,SAAS,UAAU,EAAE;AACpC,SAAO,MAAM,MAAM,KAAK,UAAU,IAAI,YAAY;AACpD;AAEO,IAAM,eAAe;AAAA,EAC1B,WAAW;AAAA;AAAA,EAEX,YAAY,gBAAgB,QAAQ,IAAI,yBAAyB,GAAM;AAAA,EACvE,mBAAmB;AAAA,EACnB,kBAAkB;AAAA,EAClB,gBAAgB;AAAA,EAChB,gBAAgB;AAAA,EAChB,iBAAiB;AACnB;AAMA,IAAM,mBAAmB;AAAA;AAAA,EAEvB;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAO;AAAA;AAAA,EAGvB;AAAA,EAAgB;AAAA,EAAoB;AAAA,EAAS;AAAA,EAC7C;AAAA,EAAU;AAAA,EAAY;AAAA,EAAQ;AAAA;AAAA,EAG9B;AAAA,EAAe;AAAA,EAAiB;AAAA,EAAe;AAAA,EAC/C;AAAA,EAAS;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAS;AAAA;AAAA,EAG1C;AAAA,EAAQ;AAAA,EAAS;AAAA,EAAO;AAAA,EAAU;AAAA,EAAU;AAAA,EAC5C;AAAA,EAAS;AAAA,EAAS;AAAA,EAAW;AAAA,EAAW;AAAA;AAAA,EAGxC;AAAA,EAAU;AAAA,EAAiB;AAAA,EAAU;AAAA,EAAO;AAAA;AAAA,EAG5C;AAAA,EAAS;AAAA,EAAW;AAAA;AAAA,EAGpB;AAAA,EAAY;AAAA,EAAa;AAAA,EAAW;AAAA;AAAA,EAGpC;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAQ;AAAA;AAAA,EAGvB;AAAA,EAAqB;AAAA,EAAa;AAAA,EAAkB;AAAA,EACpD;AAAA,EAAc;AAAA,EAAgB;AAAA;AAAA,EAG9B;AAAA,EAAY;AAAA,EAAa;AAAA,EACzB;AAAA,EAAU;AAAA,EAAQ;AAAA,EAAS;AAAA,EAC3B;AAAA,EAAS;AAAA;AAAA,EAGT;AACF;AAEO,IAAM,oBAAoB,QAAQ,IAAI,2BAA2B,IACrE,MAAM,GAAG,EACT,IAAI,OAAK,EAAE,KAAK,CAAC,EACjB,OAAO,OAAO,EACd,OAAO,gBAAgB;;;ADrD1B,IAAM,aAAa,oBAAI,IAAI;AAAA;AAAA,EAEzB;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAO;AAAA;AAAA,EAEvB;AAAA,EAAgB;AAAA,EAAoB;AAAA,EAAS;AAAA,EAC7C;AAAA,EAAU;AAAA,EAAQ;AAAA;AAAA,EAElB;AAAA,EAAe;AAAA,EAAiB;AAAA,EAAe;AAAA,EAC/C;AAAA,EAAS;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAQ;AAAA;AAAA,EAEjC;AAAA,EAAQ;AAAA,EAAS;AAAA,EAAO;AAAA,EAAU;AAAA,EAAU;AAAA,EAC5C;AAAA,EAAS;AAAA,EAAS;AAAA,EAAW;AAAA,EAAW;AAAA;AAAA,EAExC;AAAA,EAAU;AAAA,EAAiB;AAAA,EAAU;AAAA,EAAO;AAAA;AAAA,EAE5C;AAAA,EAAS;AAAA,EAAW;AAAA;AAAA,EAEpB;AAAA,EAAY;AAAA,EAAa;AAAA,EAAW;AAAA;AAAA,EAEpC;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAQ;AAAA;AAAA,EAEvB;AAAA,EAAqB;AAAA,EAAa;AAAA,EAAkB;AAAA,EACpD;AAAA,EAAc;AAAA,EAAgB;AAChC,CAAC;AAKD,IAAM,kBAAkB,oBAAI,IAAI;AAAA,EAC9B;AAAA,EAAW;AAAA,EAAY;AAAA,EACvB;AAAA,EAAS;AAAA,EAAO;AAAA,EAAQ;AAAA,EACxB;AAAA,EAAQ;AACV,CAAC;AAKD,SAAS,WAAW,MAAuB;AAEzC,MAAI,WAAW,IAAI,IAAI,EAAG,QAAO;AAGjC,MAAI,KAAK,WAAW,GAAG,EAAG,QAAO;AAGjC,aAAW,OAAO,iBAAiB;AACjC,QAAI,KAAK,SAAS,GAAG,EAAG,QAAO;AAAA,EACjC;AAEA,SAAO;AACT;AA0BO,IAAM,yBAAN,MAAyD;AAAA,EAC9D,YACmB,UACA,UACjB;AAFiB;AACA;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA,EAKH,MAAM,KAAK,QAA+E;AACxF,QAAI;AACF,YAAM,SAAS,MAAM,KAAK,SAAS,KAAK,OAAO,SAAS,OAAO,MAAM,OAAO,IAAI;AAGhF,YAAM,SAAS,UAAU,IACtB,KAAK,EACL,MAAM,OAAO,EACb,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC;AAG7B,UAAI,MAAM,SAAS,aAAa,kBAAkB;AAChD,eAAO;AAAA,UACL,OAAO,CAAC;AAAA,UACR,OAAO;AAAA,QACT;AAAA,MACF;AAEA,aAAO,EAAE,MAAM;AAAA,IACjB,SAAS,OAAO;AACd,aAAO;AAAA,QACL,OAAO,CAAC;AAAA,QACR,OAAO,gBAAgB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,MAC/E;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,KAAK,QAA6E;AACtF,UAAM,WAAW,OAAO;AACxB,UAAM,SAAS,OAAO;AAEtB,UAAM,aAAa,aAAa,UAAc,OAAO,SAAS,QAAQ,KAAK,WAAW;AACtF,UAAM,WAAW,WAAW,UAAc,OAAO,SAAS,MAAM,KAAK,SAAS;AAC9E,UAAM,aAAa,cAAc,aAC9B,aAAa,UAAa,WAAW,UAAa,YAAY;AAEjE,UAAM,QAAQ,cAAc,aAAa,SAAY,WAAW;AAChE,UAAM,MAAM,cAAc,WAAW,SAAY,SAAS;AAE1D,QAAI;AACF,YAAM,SAAS,MAAM,KAAK,SAAS,KAAK,OAAO,MAAM,OAAO,GAAG;AAG/D,YAAM,gBAAgB,UAAU,IAAI,MAAM,IAAI;AAG9C,UAAI,aAAa,SAAS,KAAK,aAAa,aAAa,SAAS,CAAC,MAAM,IAAI;AAC3E,qBAAa,IAAI;AAAA,MACnB;AAGA,YAAM,QAAQ,aAAa,IAAI,CAAC,SAAS,QAAQ,GAAG,QAAQ,GAAG,IAAI,OAAO,EAAE;AAG5E,UAAI,MAAM,SAAS,aAAa,gBAAgB;AAC9C,cAAM,YAAY,MAAM,MAAM,GAAG,aAAa,cAAc;AAC5D,kBAAU,KAAK,2BAA2B,aAAa,cAAc,OAAO,MAAM,MAAM,SAAS;AACjG,eAAO,EAAE,OAAO,UAAU;AAAA,MAC5B;AAEA,aAAO,EAAE,MAAM;AAAA,IACjB,SAAS,OAAO;AACd,aAAO;AAAA,QACL,OAAO,CAAC;AAAA,QACR,OAAO,gBAAgB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,MAC/E;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,cAAc,QAKc;AAChC,UAAM,WAAW,OAAO,YAAY,aAAa;AACjD,UAAM,aAAa,OAAO,cAAc,aAAa;AAErD,QAAI;AACF,YAAM,SAAS,MAAM,KAAK,SAAS,QAAQ,OAAO,MAAM,QAAQ;AAGhE,YAAM,SAAS,UAAU,IACtB,KAAK,EACL,MAAM,OAAO,EACb,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC;AAE7B,YAAM,QAAQ,OAAO,UAAU,IAAI,OAAO,OAAO,OAAO,IAAI;AAC5D,YAAM,UAAgC,CAAC;AAEvC,iBAAW,YAAY,OAAO;AAE5B,YAAI,aAAa,OAAO,QAAQ,aAAa,KAAK,SAAU;AAE5D,cAAM,OAAO,SAAS,MAAM,GAAG,EAAE,IAAI,KAAK;AAG1C,YAAI,WAAW,IAAI,EAAG;AAGtB,YAAI,SAAS,CAAC,MAAM,KAAK,IAAI,EAAG;AAGhC,YAAI,eAAe;AACnB,YAAI,SAAS,WAAW,KAAK,QAAQ,GAAG;AACtC,yBAAe,SAAS,MAAM,KAAK,SAAS,MAAM,EAAE,QAAQ,OAAO,EAAE;AAAA,QACvE;AAGA,cAAM,QAAQ,aAAa,MAAM,GAAG,EAAE,OAAO,OAAO,EAAE,SAAS;AAI/D,cAAM,eAAe,KAAK,SAAS,GAAG,KAAK,CAAC,KAAK,WAAW,GAAG;AAC/D,cAAM,OAAuB,eAAe,SAAS;AAErD,gBAAQ,KAAK;AAAA,UACX;AAAA,UACA,MAAM;AAAA,UACN;AAAA,UACA,OAAO,KAAK,IAAI,GAAG,KAAK;AAAA,QAC1B,CAAC;AAED,YAAI,QAAQ,UAAU,WAAY;AAAA,MACpC;AAEA,aAAO;AAAA,IACT,SAAS,OAAO;AAEd,aAAO,CAAC;AAAA,IACV;AAAA,EACF;AACF;","names":[]}
@@ -1,5 +1,5 @@
1
1
  import { WarpGrepProvider, GrepResult, ReadResult, ListDirectoryEntry } from './types.js';
2
- import { R as RemoteCommands } from '../../../types-CnvVDM63.js';
2
+ import { R as RemoteCommands } from '../../../types-Cv4LpqVl.js';
3
3
  import '../../utils/resilience.js';
4
4
 
5
5
  /**
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  RemoteCommandsProvider
3
- } from "../../../chunk-PHJQ4N3T.js";
4
- import "../../../chunk-XT5ZO6ES.js";
3
+ } from "../../../chunk-PUGSTXLO.js";
4
+ import "../../../chunk-5PNMAWLC.js";
5
5
  import "../../../chunk-PZ5AY32C.js";
6
6
  export {
7
7
  RemoteCommandsProvider
@@ -41,9 +41,15 @@ var import_ai = require("ai");
41
41
  var import_zod = require("zod");
42
42
 
43
43
  // tools/warp_grep/agent/config.ts
44
+ var parseEnvTimeout = (envValue, defaultMs) => {
45
+ if (!envValue) return defaultMs;
46
+ const parsed = parseInt(envValue, 10);
47
+ return isNaN(parsed) || parsed <= 0 ? defaultMs : parsed;
48
+ };
44
49
  var AGENT_CONFIG = {
45
50
  MAX_TURNS: 4,
46
- TIMEOUT_MS: 3e4,
51
+ /** Default timeout for model calls. Can be overridden via MORPH_WARP_GREP_TIMEOUT env var (in ms) */
52
+ TIMEOUT_MS: parseEnvTimeout(process.env.MORPH_WARP_GREP_TIMEOUT, 3e4),
47
53
  MAX_CONTEXT_CHARS: 54e4,
48
54
  MAX_OUTPUT_LINES: 200,
49
55
  MAX_READ_LINES: 800,
@@ -985,7 +991,8 @@ async function callModel(messages, model, options = {}) {
985
991
  },
986
992
  options.retryConfig
987
993
  );
988
- const resp = await withTimeout(fetchPromise, AGENT_CONFIG.TIMEOUT_MS, "morph-warp-grep request timed out");
994
+ const timeoutMs = options.timeout ?? AGENT_CONFIG.TIMEOUT_MS;
995
+ const resp = await withTimeout(fetchPromise, timeoutMs, "morph-warp-grep request timed out");
989
996
  if (!resp.ok) {
990
997
  if (resp.status === 404) {
991
998
  throw new Error(
@@ -1003,10 +1010,15 @@ async function callModel(messages, model, options = {}) {
1003
1010
  return content;
1004
1011
  }
1005
1012
  async function runWarpGrep(config) {
1013
+ const totalStart = Date.now();
1014
+ const timeoutMs = config.timeout ?? AGENT_CONFIG.TIMEOUT_MS;
1015
+ const timings = { turns: [], timeout_ms: timeoutMs };
1006
1016
  const repoRoot = import_path2.default.resolve(config.repoRoot || process.cwd());
1007
1017
  const messages = [];
1008
1018
  messages.push({ role: "system", content: getSystemPrompt() });
1019
+ const initialStateStart = Date.now();
1009
1020
  const initialState = await buildInitialState(repoRoot, config.query, config.provider);
1021
+ timings.initial_state_ms = Date.now() - initialStateStart;
1010
1022
  messages.push({ role: "user", content: initialState });
1011
1023
  const maxTurns = AGENT_CONFIG.MAX_TURNS;
1012
1024
  const model = config.model || DEFAULT_MODEL;
@@ -1015,21 +1027,29 @@ async function runWarpGrep(config) {
1015
1027
  let finishMeta;
1016
1028
  let terminationReason = "terminated";
1017
1029
  for (let turn = 1; turn <= maxTurns; turn += 1) {
1030
+ const turnMetrics = { turn, morph_api_ms: 0, local_tools_ms: 0 };
1018
1031
  enforceContextLimit(messages);
1032
+ const modelCallStart = Date.now();
1019
1033
  const assistantContent = await callModel(messages, model, {
1020
1034
  morphApiKey: config.morphApiKey,
1021
1035
  morphApiUrl: config.morphApiUrl,
1022
- retryConfig: config.retryConfig
1036
+ retryConfig: config.retryConfig,
1037
+ timeout: timeoutMs
1023
1038
  }).catch((e) => {
1024
1039
  errors.push({ message: e instanceof Error ? e.message : String(e) });
1025
1040
  return "";
1026
1041
  });
1027
- if (!assistantContent) break;
1042
+ turnMetrics.morph_api_ms = Date.now() - modelCallStart;
1043
+ if (!assistantContent) {
1044
+ timings.turns.push(turnMetrics);
1045
+ break;
1046
+ }
1028
1047
  messages.push({ role: "assistant", content: assistantContent });
1029
1048
  const toolCalls = parser.parse(assistantContent);
1030
1049
  if (toolCalls.length === 0) {
1031
1050
  errors.push({ message: "No tool calls produced by the model. Your MCP is likely out of date! Update it by running: rm -rf ~/.npm/_npx && npm cache clean --force && npx -y @morphllm/morphmcp@latest" });
1032
1051
  terminationReason = "terminated";
1052
+ timings.turns.push(turnMetrics);
1033
1053
  break;
1034
1054
  }
1035
1055
  const finishCalls = toolCalls.filter((c) => c.name === "finish");
@@ -1070,7 +1090,9 @@ async function runWarpGrep(config) {
1070
1090
  )
1071
1091
  );
1072
1092
  }
1093
+ const toolExecStart = Date.now();
1073
1094
  const allResults = await Promise.all(allPromises);
1095
+ turnMetrics.local_tools_ms = Date.now() - toolExecStart;
1074
1096
  for (const result of allResults) {
1075
1097
  formatted.push(result);
1076
1098
  }
@@ -1079,6 +1101,7 @@ async function runWarpGrep(config) {
1079
1101
  const contextBudget = calculateContextBudget(messages);
1080
1102
  messages.push({ role: "user", content: formatted.join("\n") + turnMessage + "\n" + contextBudget });
1081
1103
  }
1104
+ timings.turns.push(turnMetrics);
1082
1105
  if (finishCalls.length) {
1083
1106
  const fc = finishCalls[0];
1084
1107
  const files = fc.arguments?.files ?? [];
@@ -1088,7 +1111,8 @@ async function runWarpGrep(config) {
1088
1111
  }
1089
1112
  }
1090
1113
  if (terminationReason !== "completed" || !finishMeta) {
1091
- return { terminationReason, messages, errors };
1114
+ timings.total_ms = Date.now() - totalStart;
1115
+ return { terminationReason, messages, errors, timings };
1092
1116
  }
1093
1117
  const parts = ["Relevant context found:"];
1094
1118
  for (const f of finishMeta.files) {
@@ -1096,6 +1120,7 @@ async function runWarpGrep(config) {
1096
1120
  parts.push(`- ${f.path}: ${ranges}`);
1097
1121
  }
1098
1122
  const payload = parts.join("\n");
1123
+ const finishResolutionStart = Date.now();
1099
1124
  const fileReadErrors = [];
1100
1125
  const resolved = await readFinishFiles(
1101
1126
  repoRoot,
@@ -1115,13 +1140,16 @@ async function runWarpGrep(config) {
1115
1140
  }
1116
1141
  }
1117
1142
  );
1143
+ timings.finish_resolution_ms = Date.now() - finishResolutionStart;
1118
1144
  if (fileReadErrors.length > 0) {
1119
1145
  errors.push(...fileReadErrors.map((e) => ({ message: `File read error: ${e.path} - ${e.error}` })));
1120
1146
  }
1147
+ timings.total_ms = Date.now() - totalStart;
1121
1148
  return {
1122
1149
  terminationReason: "completed",
1123
1150
  messages,
1124
- finish: { payload, metadata: finishMeta, resolved }
1151
+ finish: { payload, metadata: finishMeta, resolved },
1152
+ timings
1125
1153
  };
1126
1154
  }
1127
1155
 
@@ -1718,7 +1746,8 @@ async function executeToolCall(input, config) {
1718
1746
  debug: config.debug ?? false,
1719
1747
  morphApiKey: config.morphApiKey,
1720
1748
  morphApiUrl: config.morphApiUrl,
1721
- retryConfig: config.retryConfig
1749
+ retryConfig: config.retryConfig,
1750
+ timeout: config.timeout
1722
1751
  });
1723
1752
  const finish = result.finish;
1724
1753
  if (result.terminationReason !== "completed" || !finish?.metadata) {