@morphllm/morphsdk 0.2.80 → 0.2.82

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 (80) hide show
  1. package/dist/{chunk-QL5SMQ73.js → chunk-24EYSWME.js} +2 -2
  2. package/dist/{chunk-ND7IFSMR.js → chunk-3ONNAQZU.js} +2 -2
  3. package/dist/{chunk-HBIDSKIQ.js → chunk-4KMBU6T3.js} +15 -7
  4. package/dist/chunk-4KMBU6T3.js.map +1 -0
  5. package/dist/{chunk-XT5ZO6ES.js → chunk-5PNMAWLC.js} +8 -2
  6. package/dist/chunk-5PNMAWLC.js.map +1 -0
  7. package/dist/{chunk-LM62QCGS.js → chunk-EK5ZEOI3.js} +5 -5
  8. package/dist/{chunk-5PGRBWJX.js → chunk-FJKPMMNQ.js} +8 -6
  9. package/dist/chunk-FJKPMMNQ.js.map +1 -0
  10. package/dist/{chunk-DCIUCDWJ.js → chunk-P2O5JKE5.js} +39 -11
  11. package/dist/chunk-P2O5JKE5.js.map +1 -0
  12. package/dist/{chunk-26QXQFLZ.js → chunk-PUGSTXLO.js} +9 -4
  13. package/dist/chunk-PUGSTXLO.js.map +1 -0
  14. package/dist/{chunk-6OII5QOW.js → chunk-WIAYUEJK.js} +8 -6
  15. package/dist/chunk-WIAYUEJK.js.map +1 -0
  16. package/dist/{chunk-4R3ALD5C.js → chunk-ZLJAODDJ.js} +2 -2
  17. package/dist/{client-CSINf0lQ.d.ts → client-CsO9LifG.d.ts} +1 -1
  18. package/dist/client.cjs +69 -17
  19. package/dist/client.cjs.map +1 -1
  20. package/dist/client.d.ts +2 -2
  21. package/dist/client.js +10 -10
  22. package/dist/index.cjs +69 -17
  23. package/dist/index.cjs.map +1 -1
  24. package/dist/index.d.ts +2 -2
  25. package/dist/index.js +10 -10
  26. package/dist/tools/warp_grep/agent/config.cjs +7 -1
  27. package/dist/tools/warp_grep/agent/config.cjs.map +1 -1
  28. package/dist/tools/warp_grep/agent/config.d.ts +1 -0
  29. package/dist/tools/warp_grep/agent/config.js +1 -1
  30. package/dist/tools/warp_grep/agent/runner.cjs +45 -8
  31. package/dist/tools/warp_grep/agent/runner.cjs.map +1 -1
  32. package/dist/tools/warp_grep/agent/runner.js +3 -3
  33. package/dist/tools/warp_grep/agent/types.cjs.map +1 -1
  34. package/dist/tools/warp_grep/agent/types.d.ts +2 -0
  35. package/dist/tools/warp_grep/anthropic.cjs +67 -16
  36. package/dist/tools/warp_grep/anthropic.cjs.map +1 -1
  37. package/dist/tools/warp_grep/anthropic.d.ts +1 -1
  38. package/dist/tools/warp_grep/anthropic.js +7 -7
  39. package/dist/tools/warp_grep/client.cjs +69 -17
  40. package/dist/tools/warp_grep/client.cjs.map +1 -1
  41. package/dist/tools/warp_grep/client.d.ts +1 -1
  42. package/dist/tools/warp_grep/client.js +6 -6
  43. package/dist/tools/warp_grep/gemini.cjs +67 -16
  44. package/dist/tools/warp_grep/gemini.cjs.map +1 -1
  45. package/dist/tools/warp_grep/gemini.d.ts +1 -1
  46. package/dist/tools/warp_grep/gemini.js +6 -6
  47. package/dist/tools/warp_grep/harness.cjs +57 -15
  48. package/dist/tools/warp_grep/harness.cjs.map +1 -1
  49. package/dist/tools/warp_grep/harness.js +3 -3
  50. package/dist/tools/warp_grep/index.cjs +73 -22
  51. package/dist/tools/warp_grep/index.cjs.map +1 -1
  52. package/dist/tools/warp_grep/index.d.ts +1 -1
  53. package/dist/tools/warp_grep/index.js +6 -6
  54. package/dist/tools/warp_grep/openai.cjs +67 -16
  55. package/dist/tools/warp_grep/openai.cjs.map +1 -1
  56. package/dist/tools/warp_grep/openai.d.ts +1 -1
  57. package/dist/tools/warp_grep/openai.js +7 -7
  58. package/dist/tools/warp_grep/providers/local.cjs +20 -6
  59. package/dist/tools/warp_grep/providers/local.cjs.map +1 -1
  60. package/dist/tools/warp_grep/providers/local.js +2 -2
  61. package/dist/tools/warp_grep/providers/remote.cjs +14 -3
  62. package/dist/tools/warp_grep/providers/remote.cjs.map +1 -1
  63. package/dist/tools/warp_grep/providers/remote.d.ts +1 -1
  64. package/dist/tools/warp_grep/providers/remote.js +2 -2
  65. package/dist/tools/warp_grep/vercel.cjs +67 -16
  66. package/dist/tools/warp_grep/vercel.cjs.map +1 -1
  67. package/dist/tools/warp_grep/vercel.d.ts +1 -1
  68. package/dist/tools/warp_grep/vercel.js +7 -7
  69. package/dist/{types-CnvVDM63.d.ts → types-Cv4LpqVl.d.ts} +2 -0
  70. package/package.json +1 -1
  71. package/dist/chunk-26QXQFLZ.js.map +0 -1
  72. package/dist/chunk-5PGRBWJX.js.map +0 -1
  73. package/dist/chunk-6OII5QOW.js.map +0 -1
  74. package/dist/chunk-DCIUCDWJ.js.map +0 -1
  75. package/dist/chunk-HBIDSKIQ.js.map +0 -1
  76. package/dist/chunk-XT5ZO6ES.js.map +0 -1
  77. /package/dist/{chunk-QL5SMQ73.js.map → chunk-24EYSWME.js.map} +0 -0
  78. /package/dist/{chunk-ND7IFSMR.js.map → chunk-3ONNAQZU.js.map} +0 -0
  79. /package/dist/{chunk-LM62QCGS.js.map → chunk-EK5ZEOI3.js.map} +0 -0
  80. /package/dist/{chunk-4R3ALD5C.js.map → chunk-ZLJAODDJ.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-QL5SMQ73.js";
6
+ } from "../../chunk-24EYSWME.js";
7
7
  import "../../chunk-KW7OEGZK.js";
8
8
  import {
9
9
  formatResult
10
- } from "../../chunk-5PGRBWJX.js";
11
- import "../../chunk-6OII5QOW.js";
12
- import "../../chunk-26QXQFLZ.js";
13
- import "../../chunk-DCIUCDWJ.js";
10
+ } from "../../chunk-FJKPMMNQ.js";
11
+ import "../../chunk-WIAYUEJK.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-HBIDSKIQ.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,
@@ -450,11 +456,19 @@ Details: ${res.stderr}` : ""}`
450
456
  };
451
457
  }
452
458
  const total = lines.length;
453
- let s = params.start ?? 1;
454
- let e = Math.min(params.end ?? total, total);
455
- if (s > total && total > 0) {
456
- s = 1;
457
- e = total;
459
+ const rawStart = params.start;
460
+ const rawEnd = params.end;
461
+ let s = 1;
462
+ let e = total;
463
+ const startValid = rawStart === void 0 || Number.isFinite(rawStart) && rawStart > 0;
464
+ const endValid = rawEnd === void 0 || Number.isFinite(rawEnd) && rawEnd > 0;
465
+ if (startValid && endValid) {
466
+ s = rawStart ?? 1;
467
+ e = Math.min(rawEnd ?? total, total);
468
+ if (s > total && total > 0 || s > e) {
469
+ s = 1;
470
+ e = total;
471
+ }
458
472
  }
459
473
  const out = [];
460
474
  for (let i = s; i <= e; i += 1) {
@@ -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 let s = params.start ?? 1;\n let e = Math.min(params.end ?? total, total);\n if (s > total && total > 0) {\n // Model hallucinated range - fallback to full file\n s = 1;\n e = total;\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-HBIDSKIQ.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,
@@ -230,8 +236,13 @@ var RemoteCommandsProvider = class {
230
236
  * Read file and add line numbers
231
237
  */
232
238
  async read(params) {
233
- const start = params.start ?? 1;
234
- const end = params.end ?? 1e6;
239
+ const rawStart = params.start;
240
+ const rawEnd = params.end;
241
+ const startValid = rawStart === void 0 || Number.isFinite(rawStart) && rawStart > 0;
242
+ const endValid = rawEnd === void 0 || Number.isFinite(rawEnd) && rawEnd > 0;
243
+ const rangeValid = startValid && endValid && (rawStart === void 0 || rawEnd === void 0 || rawStart <= rawEnd);
244
+ const start = rangeValid && rawStart !== void 0 ? rawStart : 1;
245
+ const end = rangeValid && rawEnd !== void 0 ? rawEnd : 1e6;
235
246
  try {
236
247
  const stdout = await this.commands.read(params.path, start, end);
237
248
  const contentLines = (stdout || "").split("\n");
@@ -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 start = params.start ?? 1;\n const end = params.end ?? 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-26QXQFLZ.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,
@@ -609,10 +615,25 @@ async function toolGrep(provider, args) {
609
615
  }
610
616
 
611
617
  // tools/warp_grep/agent/tools/read.ts
618
+ function isValidRange(start, end) {
619
+ return typeof start === "number" && typeof end === "number" && Number.isFinite(start) && Number.isFinite(end) && start > 0 && end >= start;
620
+ }
612
621
  async function toolRead(provider, args) {
613
- if (args.lines && args.lines.length > 0) {
622
+ if (args.lines && Array.isArray(args.lines) && args.lines.length > 0) {
623
+ const validRanges = [];
624
+ for (const range of args.lines) {
625
+ if (Array.isArray(range) && range.length >= 2 && isValidRange(range[0], range[1])) {
626
+ validRanges.push([range[0], range[1]]);
627
+ }
628
+ }
629
+ if (validRanges.length === 0) {
630
+ const res2 = await provider.read({ path: args.path });
631
+ if (res2.error) return res2.error;
632
+ if (!res2.lines.length) return "(empty file)";
633
+ return res2.lines.join("\n");
634
+ }
614
635
  const chunks = [];
615
- for (const [start, end] of args.lines) {
636
+ for (const [start, end] of validRanges) {
616
637
  const res2 = await provider.read({ path: args.path, start, end });
617
638
  if (res2.error) return res2.error;
618
639
  chunks.push(res2.lines.join("\n"));
@@ -648,14 +669,28 @@ async function toolListDirectory(provider, args) {
648
669
  }
649
670
 
650
671
  // tools/warp_grep/agent/tools/finish.ts
672
+ function isValidRange2(range) {
673
+ return Array.isArray(range) && range.length >= 2 && typeof range[0] === "number" && typeof range[1] === "number" && Number.isFinite(range[0]) && Number.isFinite(range[1]) && range[0] > 0 && range[1] >= range[0];
674
+ }
675
+ function extractValidRanges(lines) {
676
+ if (!Array.isArray(lines)) return null;
677
+ const valid = [];
678
+ for (const range of lines) {
679
+ if (isValidRange2(range)) {
680
+ valid.push([range[0], range[1]]);
681
+ }
682
+ }
683
+ return valid.length > 0 ? valid : null;
684
+ }
651
685
  async function readFinishFiles(repoRoot, files, reader) {
652
686
  const out = [];
653
687
  for (const f of files) {
654
- if (f.lines === "*") {
688
+ const validRanges = f.lines === "*" ? null : extractValidRanges(f.lines);
689
+ if (f.lines === "*" || !validRanges) {
655
690
  const lines = await reader(f.path);
656
691
  out.push({ path: f.path, ranges: "*", content: lines.join("\n") });
657
692
  } else {
658
- const ranges = mergeRanges(f.lines);
693
+ const ranges = mergeRanges(validRanges);
659
694
  const chunks = [];
660
695
  for (const [s, e] of ranges) {
661
696
  const lines = await reader(f.path, s, e);
@@ -956,7 +991,8 @@ async function callModel(messages, model, options = {}) {
956
991
  },
957
992
  options.retryConfig
958
993
  );
959
- 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");
960
996
  if (!resp.ok) {
961
997
  if (resp.status === 404) {
962
998
  throw new Error(
@@ -990,7 +1026,8 @@ async function runWarpGrep(config) {
990
1026
  const assistantContent = await callModel(messages, model, {
991
1027
  morphApiKey: config.morphApiKey,
992
1028
  morphApiUrl: config.morphApiUrl,
993
- retryConfig: config.retryConfig
1029
+ retryConfig: config.retryConfig,
1030
+ timeout: config.timeout
994
1031
  }).catch((e) => {
995
1032
  errors.push({ message: e instanceof Error ? e.message : String(e) });
996
1033
  return "";
@@ -1063,7 +1100,7 @@ async function runWarpGrep(config) {
1063
1100
  }
1064
1101
  const parts = ["Relevant context found:"];
1065
1102
  for (const f of finishMeta.files) {
1066
- const ranges = f.lines === "*" ? "*" : f.lines.map(([s, e]) => `${s}-${e}`).join(", ");
1103
+ const ranges = f.lines === "*" ? "*" : Array.isArray(f.lines) ? f.lines.map(([s, e]) => `${s}-${e}`).join(", ") : "*";
1067
1104
  parts.push(`- ${f.path}: ${ranges}`);
1068
1105
  }
1069
1106
  const payload = parts.join("\n");
@@ -1423,11 +1460,19 @@ Details: ${res.stderr}` : ""}`
1423
1460
  };
1424
1461
  }
1425
1462
  const total = lines.length;
1426
- let s = params.start ?? 1;
1427
- let e = Math.min(params.end ?? total, total);
1428
- if (s > total && total > 0) {
1429
- s = 1;
1430
- e = total;
1463
+ const rawStart = params.start;
1464
+ const rawEnd = params.end;
1465
+ let s = 1;
1466
+ let e = total;
1467
+ const startValid = rawStart === void 0 || Number.isFinite(rawStart) && rawStart > 0;
1468
+ const endValid = rawEnd === void 0 || Number.isFinite(rawEnd) && rawEnd > 0;
1469
+ if (startValid && endValid) {
1470
+ s = rawStart ?? 1;
1471
+ e = Math.min(rawEnd ?? total, total);
1472
+ if (s > total && total > 0 || s > e) {
1473
+ s = 1;
1474
+ e = total;
1475
+ }
1431
1476
  }
1432
1477
  const out = [];
1433
1478
  for (let i = s; i <= e; i += 1) {
@@ -1603,8 +1648,13 @@ var RemoteCommandsProvider = class {
1603
1648
  * Read file and add line numbers
1604
1649
  */
1605
1650
  async read(params) {
1606
- const start = params.start ?? 1;
1607
- const end = params.end ?? 1e6;
1651
+ const rawStart = params.start;
1652
+ const rawEnd = params.end;
1653
+ const startValid = rawStart === void 0 || Number.isFinite(rawStart) && rawStart > 0;
1654
+ const endValid = rawEnd === void 0 || Number.isFinite(rawEnd) && rawEnd > 0;
1655
+ const rangeValid = startValid && endValid && (rawStart === void 0 || rawEnd === void 0 || rawStart <= rawEnd);
1656
+ const start = rangeValid && rawStart !== void 0 ? rawStart : 1;
1657
+ const end = rangeValid && rawEnd !== void 0 ? rawEnd : 1e6;
1608
1658
  try {
1609
1659
  const stdout = await this.commands.read(params.path, start, end);
1610
1660
  const contentLines = (stdout || "").split("\n");
@@ -1676,7 +1726,8 @@ async function executeToolCall(input, config) {
1676
1726
  debug: config.debug ?? false,
1677
1727
  morphApiKey: config.morphApiKey,
1678
1728
  morphApiUrl: config.morphApiUrl,
1679
- retryConfig: config.retryConfig
1729
+ retryConfig: config.retryConfig,
1730
+ timeout: config.timeout
1680
1731
  });
1681
1732
  const finish = result.finish;
1682
1733
  if (result.terminationReason !== "completed" || !finish?.metadata) {