@morphllm/morphsdk 0.2.146 → 0.2.147

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 (205) hide show
  1. package/dist/{chunk-J2HIK4GB.js → chunk-334JOOAC.js} +2 -2
  2. package/dist/{chunk-QRSWXP4K.js → chunk-3GXWZ7TI.js} +2 -2
  3. package/dist/{chunk-BDHKL3MT.js → chunk-4LZK67MS.js} +2 -2
  4. package/dist/{chunk-UVNENJ6H.js → chunk-4XNHMFVU.js} +3 -3
  5. package/dist/{chunk-HZOTLGJH.js → chunk-4Y2NM6JD.js} +42 -2
  6. package/dist/chunk-4Y2NM6JD.js.map +1 -0
  7. package/dist/{chunk-V73GO5AJ.js → chunk-7HKJUVAK.js} +2 -2
  8. package/dist/{chunk-NF2QWJDY.js → chunk-B3AKP3RA.js} +31 -2
  9. package/dist/chunk-B3AKP3RA.js.map +1 -0
  10. package/dist/{chunk-VZ6VYRQB.js → chunk-BXQYZR7O.js} +2 -2
  11. package/dist/{chunk-GJUB3ECP.js → chunk-CJD4ZFOX.js} +2 -2
  12. package/dist/chunk-CMSHXALI.js +60 -0
  13. package/dist/chunk-CMSHXALI.js.map +1 -0
  14. package/dist/{chunk-KYKRRF7E.js → chunk-DYCRGTRN.js} +2 -2
  15. package/dist/{chunk-EU7OLX4Z.js → chunk-ETKDGHOB.js} +2 -2
  16. package/dist/{chunk-SJYAKVSS.js → chunk-G4TRYATX.js} +2 -2
  17. package/dist/{chunk-SJYAKVSS.js.map → chunk-G4TRYATX.js.map} +1 -1
  18. package/dist/chunk-GK56GCLU.js +401 -0
  19. package/dist/chunk-GK56GCLU.js.map +1 -0
  20. package/dist/{chunk-I7SFRYTX.js → chunk-HWED34T3.js} +2 -2
  21. package/dist/{chunk-FIVYDIHX.js → chunk-HYRHI2UL.js} +1 -1
  22. package/dist/{chunk-DKODF3YG.js → chunk-I3J46TSB.js} +5 -4
  23. package/dist/chunk-I3J46TSB.js.map +1 -0
  24. package/dist/{chunk-E4YKEKGW.js → chunk-KV2CC4N7.js} +2 -2
  25. package/dist/{chunk-BIQ7234U.js → chunk-LSPEWVCD.js} +2 -2
  26. package/dist/{chunk-OV57JBMB.js → chunk-N7XLC7BK.js} +2 -2
  27. package/dist/{chunk-FBOJJ3UY.js → chunk-O356YR2N.js} +17 -17
  28. package/dist/{chunk-JSWNBCGS.js → chunk-PIHW2GSK.js} +2 -2
  29. package/dist/{chunk-UYPWKQKV.js → chunk-RGNP6FNH.js} +2 -2
  30. package/dist/{chunk-YIETFYCL.js → chunk-T7HF2TDQ.js} +75 -48
  31. package/dist/chunk-T7HF2TDQ.js.map +1 -0
  32. package/dist/{chunk-NKUSUSVI.js → chunk-T7VCGKXB.js} +3 -3
  33. package/dist/{chunk-Q36MNOFA.js → chunk-UZ2QUWJD.js} +2 -2
  34. package/dist/{chunk-FYO46OT6.js → chunk-VTTU7MJB.js} +2 -2
  35. package/dist/{chunk-4PBUB77N.js → chunk-XADFYB6B.js} +2 -2
  36. package/dist/{chunk-T564HFSH.js → chunk-XS4PO4FC.js} +1 -1
  37. package/dist/{chunk-E45FW5EK.js → chunk-YH3XIVF2.js} +2 -2
  38. package/dist/{chunk-MMBQKN4G.js → chunk-ZZW4B4GG.js} +2 -2
  39. package/dist/client.cjs +439 -446
  40. package/dist/client.cjs.map +1 -1
  41. package/dist/client.js +26 -27
  42. package/dist/edge.cjs +1 -1
  43. package/dist/edge.cjs.map +1 -1
  44. package/dist/edge.js +4 -4
  45. package/dist/{finish-DBKuo8yj.d.ts → finish-Ddj1MPGt.d.ts} +1 -1
  46. package/dist/index.cjs +458 -446
  47. package/dist/index.cjs.map +1 -1
  48. package/dist/index.js +29 -29
  49. package/dist/modelrouter/core.cjs +1 -1
  50. package/dist/modelrouter/core.cjs.map +1 -1
  51. package/dist/modelrouter/core.js +3 -3
  52. package/dist/modelrouter/index.cjs +1 -1
  53. package/dist/modelrouter/index.cjs.map +1 -1
  54. package/dist/modelrouter/index.js +3 -3
  55. package/dist/subagents/anthropic.cjs +435 -442
  56. package/dist/subagents/anthropic.cjs.map +1 -1
  57. package/dist/subagents/anthropic.js +8 -9
  58. package/dist/subagents/vercel.cjs +435 -442
  59. package/dist/subagents/vercel.cjs.map +1 -1
  60. package/dist/subagents/vercel.js +8 -9
  61. package/dist/tools/browser/anthropic.cjs +1 -1
  62. package/dist/tools/browser/anthropic.cjs.map +1 -1
  63. package/dist/tools/browser/anthropic.js +5 -5
  64. package/dist/tools/browser/core.cjs +1 -1
  65. package/dist/tools/browser/core.cjs.map +1 -1
  66. package/dist/tools/browser/core.js +4 -4
  67. package/dist/tools/browser/index.cjs +1 -1
  68. package/dist/tools/browser/index.cjs.map +1 -1
  69. package/dist/tools/browser/index.js +7 -7
  70. package/dist/tools/browser/openai.cjs +1 -1
  71. package/dist/tools/browser/openai.cjs.map +1 -1
  72. package/dist/tools/browser/openai.js +5 -5
  73. package/dist/tools/browser/profiles/core.cjs +1 -1
  74. package/dist/tools/browser/profiles/core.cjs.map +1 -1
  75. package/dist/tools/browser/profiles/core.js +3 -3
  76. package/dist/tools/browser/profiles/index.cjs +1 -1
  77. package/dist/tools/browser/profiles/index.cjs.map +1 -1
  78. package/dist/tools/browser/profiles/index.js +3 -3
  79. package/dist/tools/browser/vercel.cjs +1 -1
  80. package/dist/tools/browser/vercel.cjs.map +1 -1
  81. package/dist/tools/browser/vercel.js +5 -5
  82. package/dist/tools/codebase_search/anthropic.cjs +1 -1
  83. package/dist/tools/codebase_search/anthropic.cjs.map +1 -1
  84. package/dist/tools/codebase_search/anthropic.js +4 -4
  85. package/dist/tools/codebase_search/core.cjs +1 -1
  86. package/dist/tools/codebase_search/core.cjs.map +1 -1
  87. package/dist/tools/codebase_search/core.js +3 -3
  88. package/dist/tools/codebase_search/index.cjs +1 -1
  89. package/dist/tools/codebase_search/index.cjs.map +1 -1
  90. package/dist/tools/codebase_search/index.js +6 -6
  91. package/dist/tools/codebase_search/openai.cjs +1 -1
  92. package/dist/tools/codebase_search/openai.cjs.map +1 -1
  93. package/dist/tools/codebase_search/openai.js +4 -4
  94. package/dist/tools/codebase_search/vercel.cjs +1 -1
  95. package/dist/tools/codebase_search/vercel.cjs.map +1 -1
  96. package/dist/tools/codebase_search/vercel.js +4 -4
  97. package/dist/tools/fastapply/anthropic.cjs +1 -1
  98. package/dist/tools/fastapply/anthropic.cjs.map +1 -1
  99. package/dist/tools/fastapply/anthropic.js +4 -4
  100. package/dist/tools/fastapply/apply.cjs +1 -1
  101. package/dist/tools/fastapply/apply.cjs.map +1 -1
  102. package/dist/tools/fastapply/apply.js +2 -2
  103. package/dist/tools/fastapply/core.cjs +1 -1
  104. package/dist/tools/fastapply/core.cjs.map +1 -1
  105. package/dist/tools/fastapply/core.js +3 -3
  106. package/dist/tools/fastapply/index.cjs +1 -1
  107. package/dist/tools/fastapply/index.cjs.map +1 -1
  108. package/dist/tools/fastapply/index.js +6 -6
  109. package/dist/tools/fastapply/openai.cjs +1 -1
  110. package/dist/tools/fastapply/openai.cjs.map +1 -1
  111. package/dist/tools/fastapply/openai.js +4 -4
  112. package/dist/tools/fastapply/vercel.cjs +1 -1
  113. package/dist/tools/fastapply/vercel.cjs.map +1 -1
  114. package/dist/tools/fastapply/vercel.js +4 -4
  115. package/dist/tools/index.cjs +1 -1
  116. package/dist/tools/index.cjs.map +1 -1
  117. package/dist/tools/index.js +6 -6
  118. package/dist/tools/utils/resilience.cjs +1 -1
  119. package/dist/tools/utils/resilience.cjs.map +1 -1
  120. package/dist/tools/utils/resilience.js +2 -2
  121. package/dist/tools/warp_grep/agent/config.cjs +4 -3
  122. package/dist/tools/warp_grep/agent/config.cjs.map +1 -1
  123. package/dist/tools/warp_grep/agent/config.d.ts +2 -1
  124. package/dist/tools/warp_grep/agent/config.js +1 -1
  125. package/dist/tools/warp_grep/agent/parser.cjs +52 -121
  126. package/dist/tools/warp_grep/agent/parser.cjs.map +1 -1
  127. package/dist/tools/warp_grep/agent/parser.d.ts +12 -5
  128. package/dist/tools/warp_grep/agent/parser.js +7 -3
  129. package/dist/tools/warp_grep/agent/runner.cjs +348 -424
  130. package/dist/tools/warp_grep/agent/runner.cjs.map +1 -1
  131. package/dist/tools/warp_grep/agent/runner.d.ts +6 -3
  132. package/dist/tools/warp_grep/agent/runner.js +5 -6
  133. package/dist/tools/warp_grep/agent/types.cjs.map +1 -1
  134. package/dist/tools/warp_grep/agent/types.d.ts +22 -3
  135. package/dist/tools/warp_grep/anthropic.cjs +435 -442
  136. package/dist/tools/warp_grep/anthropic.cjs.map +1 -1
  137. package/dist/tools/warp_grep/anthropic.js +8 -9
  138. package/dist/tools/warp_grep/client.cjs +435 -442
  139. package/dist/tools/warp_grep/client.cjs.map +1 -1
  140. package/dist/tools/warp_grep/client.js +7 -8
  141. package/dist/tools/warp_grep/gemini.cjs +435 -442
  142. package/dist/tools/warp_grep/gemini.cjs.map +1 -1
  143. package/dist/tools/warp_grep/gemini.js +7 -8
  144. package/dist/tools/warp_grep/gemini.js.map +1 -1
  145. package/dist/tools/warp_grep/harness.cjs +168 -180
  146. package/dist/tools/warp_grep/harness.cjs.map +1 -1
  147. package/dist/tools/warp_grep/harness.d.ts +17 -38
  148. package/dist/tools/warp_grep/harness.js +15 -14
  149. package/dist/tools/warp_grep/harness.js.map +1 -1
  150. package/dist/tools/warp_grep/index.cjs +454 -442
  151. package/dist/tools/warp_grep/index.cjs.map +1 -1
  152. package/dist/tools/warp_grep/index.d.ts +1 -1
  153. package/dist/tools/warp_grep/index.js +10 -10
  154. package/dist/tools/warp_grep/openai.cjs +435 -442
  155. package/dist/tools/warp_grep/openai.cjs.map +1 -1
  156. package/dist/tools/warp_grep/openai.js +8 -9
  157. package/dist/tools/warp_grep/providers/local.cjs +43 -2
  158. package/dist/tools/warp_grep/providers/local.cjs.map +1 -1
  159. package/dist/tools/warp_grep/providers/local.d.ts +5 -1
  160. package/dist/tools/warp_grep/providers/local.js +2 -2
  161. package/dist/tools/warp_grep/providers/remote.cjs +32 -2
  162. package/dist/tools/warp_grep/providers/remote.cjs.map +1 -1
  163. package/dist/tools/warp_grep/providers/remote.d.ts +9 -1
  164. package/dist/tools/warp_grep/providers/remote.js +2 -2
  165. package/dist/tools/warp_grep/providers/types.cjs.map +1 -1
  166. package/dist/tools/warp_grep/providers/types.d.ts +14 -1
  167. package/dist/tools/warp_grep/vercel.cjs +435 -442
  168. package/dist/tools/warp_grep/vercel.cjs.map +1 -1
  169. package/dist/tools/warp_grep/vercel.js +8 -9
  170. package/dist/version.cjs +1 -1
  171. package/dist/version.cjs.map +1 -1
  172. package/dist/version.js +1 -1
  173. package/package.json +1 -1
  174. package/dist/chunk-DKODF3YG.js.map +0 -1
  175. package/dist/chunk-EUHNJMWL.js +0 -409
  176. package/dist/chunk-EUHNJMWL.js.map +0 -1
  177. package/dist/chunk-HZOTLGJH.js.map +0 -1
  178. package/dist/chunk-NF2QWJDY.js.map +0 -1
  179. package/dist/chunk-VCKJ22DX.js +0 -131
  180. package/dist/chunk-VCKJ22DX.js.map +0 -1
  181. package/dist/chunk-YIETFYCL.js.map +0 -1
  182. /package/dist/{chunk-J2HIK4GB.js.map → chunk-334JOOAC.js.map} +0 -0
  183. /package/dist/{chunk-QRSWXP4K.js.map → chunk-3GXWZ7TI.js.map} +0 -0
  184. /package/dist/{chunk-BDHKL3MT.js.map → chunk-4LZK67MS.js.map} +0 -0
  185. /package/dist/{chunk-UVNENJ6H.js.map → chunk-4XNHMFVU.js.map} +0 -0
  186. /package/dist/{chunk-V73GO5AJ.js.map → chunk-7HKJUVAK.js.map} +0 -0
  187. /package/dist/{chunk-VZ6VYRQB.js.map → chunk-BXQYZR7O.js.map} +0 -0
  188. /package/dist/{chunk-GJUB3ECP.js.map → chunk-CJD4ZFOX.js.map} +0 -0
  189. /package/dist/{chunk-KYKRRF7E.js.map → chunk-DYCRGTRN.js.map} +0 -0
  190. /package/dist/{chunk-EU7OLX4Z.js.map → chunk-ETKDGHOB.js.map} +0 -0
  191. /package/dist/{chunk-I7SFRYTX.js.map → chunk-HWED34T3.js.map} +0 -0
  192. /package/dist/{chunk-FIVYDIHX.js.map → chunk-HYRHI2UL.js.map} +0 -0
  193. /package/dist/{chunk-E4YKEKGW.js.map → chunk-KV2CC4N7.js.map} +0 -0
  194. /package/dist/{chunk-BIQ7234U.js.map → chunk-LSPEWVCD.js.map} +0 -0
  195. /package/dist/{chunk-OV57JBMB.js.map → chunk-N7XLC7BK.js.map} +0 -0
  196. /package/dist/{chunk-FBOJJ3UY.js.map → chunk-O356YR2N.js.map} +0 -0
  197. /package/dist/{chunk-JSWNBCGS.js.map → chunk-PIHW2GSK.js.map} +0 -0
  198. /package/dist/{chunk-UYPWKQKV.js.map → chunk-RGNP6FNH.js.map} +0 -0
  199. /package/dist/{chunk-NKUSUSVI.js.map → chunk-T7VCGKXB.js.map} +0 -0
  200. /package/dist/{chunk-Q36MNOFA.js.map → chunk-UZ2QUWJD.js.map} +0 -0
  201. /package/dist/{chunk-FYO46OT6.js.map → chunk-VTTU7MJB.js.map} +0 -0
  202. /package/dist/{chunk-4PBUB77N.js.map → chunk-XADFYB6B.js.map} +0 -0
  203. /package/dist/{chunk-T564HFSH.js.map → chunk-XS4PO4FC.js.map} +0 -0
  204. /package/dist/{chunk-E45FW5EK.js.map → chunk-YH3XIVF2.js.map} +0 -0
  205. /package/dist/{chunk-MMBQKN4G.js.map → chunk-ZZW4B4GG.js.map} +0 -0
package/dist/client.cjs CHANGED
@@ -36,7 +36,7 @@ var init_package = __esm({
36
36
  "package.json"() {
37
37
  package_default = {
38
38
  name: "@morphllm/morphsdk",
39
- version: "0.2.146",
39
+ version: "0.2.147",
40
40
  description: "TypeScript SDK and CLI for Morph Fast Apply integration",
41
41
  type: "module",
42
42
  main: "./dist/index.cjs",
@@ -416,11 +416,12 @@ var init_config = __esm({
416
416
  return isNaN(parsed) || parsed <= 0 ? defaultMs : parsed;
417
417
  };
418
418
  AGENT_CONFIG = {
419
- MAX_TURNS: 4,
419
+ MAX_TURNS: 6,
420
420
  /** Default timeout for model calls. Can be overridden via MORPH_WARP_GREP_TIMEOUT env var (in ms) */
421
421
  TIMEOUT_MS: parseEnvTimeout(process.env.MORPH_WARP_GREP_TIMEOUT, 3e4),
422
- MAX_CONTEXT_CHARS: 54e4,
422
+ MAX_CONTEXT_CHARS: 321600,
423
423
  MAX_OUTPUT_LINES: 200,
424
+ MAX_LIST_RESULTS: 500,
424
425
  MAX_READ_LINES: 800,
425
426
  MAX_LIST_DEPTH: 3,
426
427
  LIST_TIMEOUT_MS: 2e3
@@ -505,7 +506,7 @@ var init_config = __esm({
505
506
  ".*"
506
507
  ];
507
508
  DEFAULT_EXCLUDES = (process.env.MORPH_WARP_GREP_EXCLUDE || "").split(",").map((s) => s.trim()).filter(Boolean).concat(BUILTIN_EXCLUDES);
508
- DEFAULT_MODEL = "morph-warp-grep-v2";
509
+ DEFAULT_MODEL = "morph-warp-grep-v2.1";
509
510
  }
510
511
  });
511
512
 
@@ -578,19 +579,19 @@ var init_ripgrep = __esm({
578
579
 
579
580
  // tools/warp_grep/utils/paths.ts
580
581
  function resolveUnderRepo(repoRoot, targetPath) {
581
- const absRoot = import_path4.default.resolve(repoRoot);
582
- const resolved = import_path4.default.resolve(absRoot, targetPath);
582
+ const absRoot = import_path5.default.resolve(repoRoot);
583
+ const resolved = import_path5.default.resolve(absRoot, targetPath);
583
584
  ensureWithinRepo(absRoot, resolved);
584
585
  return resolved;
585
586
  }
586
587
  function ensureWithinRepo(repoRoot, absTarget) {
587
- const rel = import_path4.default.relative(import_path4.default.resolve(repoRoot), import_path4.default.resolve(absTarget));
588
- if (rel.startsWith("..") || import_path4.default.isAbsolute(rel)) {
588
+ const rel = import_path5.default.relative(import_path5.default.resolve(repoRoot), import_path5.default.resolve(absTarget));
589
+ if (rel.startsWith("..") || import_path5.default.isAbsolute(rel)) {
589
590
  throw new Error(`Path outside repository root: ${absTarget}`);
590
591
  }
591
592
  }
592
593
  function toRepoRelative(repoRoot, absPath) {
593
- return import_path4.default.relative(import_path4.default.resolve(repoRoot), import_path4.default.resolve(absPath));
594
+ return import_path5.default.relative(import_path5.default.resolve(repoRoot), import_path5.default.resolve(absPath));
594
595
  }
595
596
  function isSymlink(p) {
596
597
  try {
@@ -601,7 +602,7 @@ function isSymlink(p) {
601
602
  }
602
603
  }
603
604
  function fixPathRepetition(fullPath) {
604
- const segments = fullPath.split(import_path4.default.sep).filter(Boolean);
605
+ const segments = fullPath.split(import_path5.default.sep).filter(Boolean);
605
606
  if (segments.length < 2) return null;
606
607
  for (let len = Math.floor(segments.length / 2); len >= 1; len--) {
607
608
  for (let i = 0; i <= segments.length - 2 * len; i++) {
@@ -609,7 +610,7 @@ function fixPathRepetition(fullPath) {
609
610
  const second = segments.slice(i + len, i + 2 * len);
610
611
  if (first.every((seg, idx) => seg === second[idx])) {
611
612
  const fixed = [...segments.slice(0, i), ...segments.slice(i + len)];
612
- return import_path4.default.sep + fixed.join(import_path4.default.sep);
613
+ return import_path5.default.sep + fixed.join(import_path5.default.sep);
613
614
  }
614
615
  }
615
616
  }
@@ -633,12 +634,12 @@ function isTextualFile(filePath, maxBytes = 2e6) {
633
634
  return false;
634
635
  }
635
636
  }
636
- var import_fs, import_path4;
637
+ var import_fs, import_path5;
637
638
  var init_paths = __esm({
638
639
  "tools/warp_grep/utils/paths.ts"() {
639
640
  "use strict";
640
641
  import_fs = __toESM(require("fs"), 1);
641
- import_path4 = __toESM(require("path"), 1);
642
+ import_path5 = __toESM(require("path"), 1);
642
643
  }
643
644
  });
644
645
 
@@ -669,12 +670,12 @@ function shouldSkip2(name, allowNames) {
669
670
  }
670
671
  return false;
671
672
  }
672
- var import_promises2, import_path5, SKIP_NAMES2, SKIP_EXTENSIONS2, LocalRipgrepProvider;
673
+ var import_promises2, import_path6, SKIP_NAMES2, SKIP_EXTENSIONS2, LocalRipgrepProvider;
673
674
  var init_local = __esm({
674
675
  "tools/warp_grep/providers/local.ts"() {
675
676
  "use strict";
676
677
  import_promises2 = __toESM(require("fs/promises"), 1);
677
- import_path5 = __toESM(require("path"), 1);
678
+ import_path6 = __toESM(require("path"), 1);
678
679
  init_ripgrep();
679
680
  init_paths();
680
681
  init_files();
@@ -776,7 +777,7 @@ var init_local = __esm({
776
777
  }
777
778
  const stat = await import_promises2.default.stat(abs).catch(() => null);
778
779
  if (!stat) return { lines: [] };
779
- const targetArg = abs === import_path5.default.resolve(this.repoRoot) ? "." : toRepoRelative(this.repoRoot, abs);
780
+ const targetArg = abs === import_path6.default.resolve(this.repoRoot) ? "." : toRepoRelative(this.repoRoot, abs);
780
781
  const contextLines = params.context_lines !== void 0 ? String(params.context_lines) : "1";
781
782
  const args = [
782
783
  "--no-config",
@@ -931,7 +932,7 @@ Details: ${res.stderr}` : ""}`
931
932
  if (timedOut || results.length >= maxResults) break;
932
933
  if (shouldSkip2(entry.name, allowNames)) continue;
933
934
  if (regex && !regex.test(entry.name)) continue;
934
- const full = import_path5.default.join(dir, entry.name);
935
+ const full = import_path6.default.join(dir, entry.name);
935
936
  const isDir = entry.isDirectory();
936
937
  results.push({
937
938
  name: entry.name,
@@ -947,6 +948,46 @@ Details: ${res.stderr}` : ""}`
947
948
  await walk(abs, 0);
948
949
  return results;
949
950
  }
951
+ async glob(params) {
952
+ let abs;
953
+ try {
954
+ abs = params.path ? resolveUnderRepo(this.repoRoot, params.path) : this.repoRoot;
955
+ } catch (err) {
956
+ return { files: [], searchDir: this.repoRoot, totalFound: 0, error: `[PATH ERROR] ${err instanceof Error ? err.message : String(err)}` };
957
+ }
958
+ const stat = await import_promises2.default.stat(abs).catch(() => null);
959
+ if (!stat || !stat.isDirectory()) {
960
+ return { files: [], searchDir: abs, totalFound: 0, error: `[PATH ERROR] Directory not found: ${params.path || "."}` };
961
+ }
962
+ const targetArg = abs === import_path6.default.resolve(this.repoRoot) ? "." : toRepoRelative(this.repoRoot, abs);
963
+ const args = [
964
+ "--no-config",
965
+ "--files",
966
+ "--color=never",
967
+ "-g",
968
+ params.pattern,
969
+ ...this.excludes.filter((e) => !this.allowNames?.has(e)).flatMap((e) => ["-g", `!${e}`]),
970
+ targetArg || "."
971
+ ];
972
+ const res = await runRipgrep(args, { cwd: this.repoRoot });
973
+ if (res.exitCode === -1) {
974
+ return { files: [], searchDir: abs, totalFound: 0, error: `[RIPGREP NOT AVAILABLE] ripgrep (rg) is required for glob search.` };
975
+ }
976
+ if (res.exitCode !== 0 && res.exitCode !== 1) {
977
+ return { files: [], searchDir: abs, totalFound: 0, error: `[GLOB ERROR] glob failed with exit code ${res.exitCode}${res.stderr ? `: ${res.stderr}` : ""}` };
978
+ }
979
+ const absRoot = import_path6.default.resolve(this.repoRoot);
980
+ const relFiles = (res.stdout || "").trim().split(/\r?\n/).filter((l) => l.length > 0);
981
+ const absFiles = relFiles.map((f) => import_path6.default.resolve(absRoot, f));
982
+ const withMtime = [];
983
+ for (const f of absFiles) {
984
+ const s = await import_promises2.default.stat(f).catch(() => null);
985
+ withMtime.push({ file: f, mtime: s?.mtimeMs ?? 0 });
986
+ }
987
+ withMtime.sort((a, b) => b.mtime - a.mtime);
988
+ const totalFound = withMtime.length;
989
+ return { files: withMtime.slice(0, 100).map((f) => f.file), searchDir: abs, totalFound };
990
+ }
950
991
  };
951
992
  }
952
993
  });
@@ -2493,131 +2534,58 @@ async function checkHealth(config = {}) {
2493
2534
  init_config();
2494
2535
 
2495
2536
  // tools/warp_grep/agent/parser.ts
2496
- var VALID_COMMANDS = ["list_directory", "ripgrep", "read", "finish"];
2497
- function isValidCommand(name) {
2498
- return VALID_COMMANDS.includes(name);
2537
+ function parseReadLines(linesStr) {
2538
+ const ranges = [];
2539
+ for (const rangeStr of linesStr.split(",")) {
2540
+ const trimmed = rangeStr.trim();
2541
+ if (!trimmed) continue;
2542
+ const parts = trimmed.split("-").map((v) => parseInt(v.trim(), 10));
2543
+ if (parts.length >= 2 && Number.isFinite(parts[0]) && Number.isFinite(parts[1])) {
2544
+ ranges.push([parts[0], parts[1]]);
2545
+ } else if (Number.isFinite(parts[0])) {
2546
+ ranges.push([parts[0], parts[0]]);
2547
+ }
2548
+ }
2549
+ if (ranges.length === 1) return { start: ranges[0][0], end: ranges[0][1] };
2550
+ if (ranges.length > 1) return { lines: ranges };
2551
+ return {};
2499
2552
  }
2500
- function parseQwen3ToolCalls(text) {
2501
- const tools = [];
2502
- const toolCallRegex = /<tool_call>\s*<function=([a-z_][a-z0-9_]*)>([\s\S]*?)<\/function>\s*<\/tool_call>/gi;
2503
- let match;
2504
- while ((match = toolCallRegex.exec(text)) !== null) {
2505
- const funcName = match[1].toLowerCase();
2506
- const body = match[2];
2507
- if (!isValidCommand(funcName)) continue;
2508
- const params = {};
2509
- const paramRegex = /<parameter=([a-z_][a-z0-9_]*)>([\s\S]*?)<\/parameter>/gi;
2510
- let paramMatch;
2511
- while ((paramMatch = paramRegex.exec(body)) !== null) {
2512
- params[paramMatch[1].toLowerCase()] = paramMatch[2].trim();
2513
- }
2514
- if (funcName === "ripgrep") {
2515
- const pattern = params.pattern;
2516
- if (!pattern) continue;
2517
- const args = {
2518
- pattern,
2519
- path: params.path || ".",
2520
- ...params.glob && { glob: params.glob },
2521
- ...params.context_lines && { context_lines: parseInt(params.context_lines, 10) },
2522
- ...params.case_sensitive && { case_sensitive: params.case_sensitive === "true" }
2523
- };
2524
- tools.push({ name: "grep", arguments: args });
2525
- } else if (funcName === "list_directory") {
2526
- const command = params.command;
2527
- const directPath = params.path;
2528
- let dirPath = directPath || ".";
2529
- if (!directPath && command) {
2530
- const tokens = command.trim().split(/\s+/);
2531
- const pathTokens = tokens.slice(1).filter((t) => !t.startsWith("-") && !t.startsWith("|") && !t.startsWith("\\("));
2532
- if (pathTokens.length > 0) {
2533
- dirPath = pathTokens[0];
2534
- }
2535
- }
2536
- tools.push({ name: "list_directory", arguments: { path: dirPath, pattern: params.pattern || null } });
2537
- } else if (funcName === "read") {
2538
- const filePath = params.path;
2539
- if (!filePath) continue;
2540
- const args = { path: filePath };
2541
- const linesStr = params.lines;
2542
- if (linesStr) {
2543
- const ranges = [];
2544
- for (const rangeStr of linesStr.split(",")) {
2545
- const trimmed = rangeStr.trim();
2546
- if (!trimmed) continue;
2547
- const [s, e] = trimmed.split("-").map((v) => parseInt(v.trim(), 10));
2548
- if (Number.isFinite(s) && Number.isFinite(e)) {
2549
- ranges.push([s, e]);
2550
- } else if (Number.isFinite(s)) {
2551
- ranges.push([s, s]);
2552
- }
2553
- }
2554
- if (ranges.length === 1) {
2555
- args.start = ranges[0][0];
2556
- args.end = ranges[0][1];
2557
- } else if (ranges.length > 1) {
2558
- args.lines = ranges;
2559
- }
2560
- }
2561
- tools.push({ name: "read", arguments: args });
2562
- } else if (funcName === "finish") {
2563
- if (params.result && !params.files) {
2564
- tools.push({ name: "finish", arguments: { files: [], textResult: params.result } });
2565
- continue;
2566
- }
2567
- const filesStr = params.files;
2568
- if (!filesStr) {
2569
- tools.push({ name: "finish", arguments: { files: [], textResult: "No relevant code found." } });
2570
- continue;
2571
- }
2572
- const files = [];
2573
- for (const line of filesStr.split("\n")) {
2574
- const trimmed = line.trim();
2575
- if (!trimmed) continue;
2576
- const colonIdx = trimmed.indexOf(":");
2577
- if (colonIdx === -1) {
2578
- files.push({ path: trimmed, lines: "*" });
2579
- } else {
2580
- const filePath = trimmed.slice(0, colonIdx);
2581
- const rangesPart = trimmed.slice(colonIdx + 1);
2582
- const ranges = [];
2583
- for (const rangeStr of rangesPart.split(",")) {
2584
- const rt = rangeStr.trim();
2585
- if (!rt || rt === "*") {
2586
- files.push({ path: filePath, lines: "*" });
2587
- break;
2588
- }
2589
- const [s, e] = rt.split("-").map((v) => parseInt(v.trim(), 10));
2590
- if (Number.isFinite(s) && Number.isFinite(e)) {
2591
- ranges.push([s, e]);
2592
- } else if (Number.isFinite(s)) {
2593
- ranges.push([s, s]);
2594
- }
2595
- }
2596
- if (ranges.length > 0) {
2597
- files.push({ path: filePath, lines: ranges });
2598
- } else if (!files.some((f) => f.path === filePath)) {
2599
- files.push({ path: filePath, lines: "*" });
2600
- }
2601
- }
2602
- }
2603
- if (files.length > 0) {
2604
- tools.push({ name: "finish", arguments: { files } });
2605
- } else {
2606
- tools.push({ name: "finish", arguments: { files: [], textResult: filesStr } });
2553
+ function parseFinishFiles(filesStr) {
2554
+ const files = [];
2555
+ for (const line of filesStr.trim().split(/\s+/)) {
2556
+ const trimmed = line.trim();
2557
+ if (!trimmed) continue;
2558
+ const colonIdx = trimmed.indexOf(":");
2559
+ if (colonIdx === -1) {
2560
+ files.push({ path: trimmed, lines: "*" });
2561
+ continue;
2562
+ }
2563
+ const filePath = trimmed.slice(0, colonIdx);
2564
+ const rangesPart = trimmed.slice(colonIdx + 1);
2565
+ if (!rangesPart.trim() || rangesPart.trim() === "*") {
2566
+ files.push({ path: filePath, lines: "*" });
2567
+ continue;
2568
+ }
2569
+ const ranges = [];
2570
+ for (const rangeStr of rangesPart.split(",")) {
2571
+ const rt = rangeStr.trim();
2572
+ if (!rt) continue;
2573
+ const parts = rt.split("-").map((v) => parseInt(v.trim(), 10));
2574
+ if (parts.length >= 2 && Number.isFinite(parts[0]) && Number.isFinite(parts[1])) {
2575
+ ranges.push([parts[0], parts[1]]);
2576
+ } else if (Number.isFinite(parts[0])) {
2577
+ ranges.push([parts[0], parts[0]]);
2607
2578
  }
2608
2579
  }
2580
+ files.push({ path: filePath, lines: ranges.length > 0 ? ranges : "*" });
2609
2581
  }
2610
- return tools;
2582
+ return files;
2583
+ }
2584
+ function extractPathFromCommand(command) {
2585
+ const tokens = command.trim().split(/\s+/);
2586
+ const pathTokens = tokens.slice(1).filter((t) => !t.startsWith("-") && !t.startsWith("|") && !t.startsWith("\\("));
2587
+ return pathTokens[0] || ".";
2611
2588
  }
2612
- var LLMResponseParser = class {
2613
- parse(text) {
2614
- if (typeof text !== "string") {
2615
- throw new TypeError("Command text must be a string.");
2616
- }
2617
- const withoutThink = text.replace(/<think>[\s\S]*?<\/think>/gi, "");
2618
- return parseQwen3ToolCalls(withoutThink);
2619
- }
2620
- };
2621
2589
 
2622
2590
  // tools/warp_grep/agent/tools/grep.ts
2623
2591
  async function toolGrep(provider, args) {
@@ -2668,29 +2636,42 @@ async function toolRead(provider, args) {
2668
2636
 
2669
2637
  // tools/warp_grep/agent/tools/list_directory.ts
2670
2638
  init_config();
2671
- async function toolListDirectory(provider, args) {
2672
- const maxResults = args.maxResults ?? AGENT_CONFIG.MAX_OUTPUT_LINES;
2673
- const initialDepth = args.maxDepth ?? AGENT_CONFIG.MAX_LIST_DEPTH;
2674
- async function getListRecursive(currentDepth) {
2675
- const entries = await provider.listDirectory({
2676
- path: args.path,
2677
- pattern: args.pattern ?? null,
2678
- maxResults,
2679
- maxDepth: currentDepth
2680
- });
2681
- if (entries.length >= maxResults && currentDepth > 0) {
2682
- return getListRecursive(currentDepth - 1);
2683
- }
2684
- return { entries };
2685
- }
2686
- const { entries: list } = await getListRecursive(initialDepth);
2687
- if (!list.length) return "empty";
2688
- const tree = list.map((e) => {
2689
- const indent = " ".repeat(e.depth);
2690
- const name = e.type === "dir" ? `${e.name}/` : e.name;
2691
- return `${indent}${name}`;
2692
- }).join("\n");
2693
- return tree;
2639
+ var import_path2 = __toESM(require("path"), 1);
2640
+ async function toolListDirectory(provider, args, repoRoot) {
2641
+ const maxResults = args.maxResults ?? AGENT_CONFIG.MAX_LIST_RESULTS;
2642
+ const maxDepth = args.maxDepth ?? AGENT_CONFIG.MAX_LIST_DEPTH;
2643
+ const entries = await provider.listDirectory({
2644
+ path: args.path,
2645
+ pattern: args.pattern ?? null,
2646
+ maxResults,
2647
+ maxDepth
2648
+ });
2649
+ if (!entries.length) return "empty";
2650
+ if (repoRoot) {
2651
+ const absRoot = import_path2.default.resolve(repoRoot);
2652
+ const lines = entries.map((e) => import_path2.default.join(absRoot, e.path));
2653
+ return lines.join("\n");
2654
+ }
2655
+ return entries.map((e) => e.path).join("\n");
2656
+ }
2657
+
2658
+ // tools/warp_grep/agent/tools/glob.ts
2659
+ async function toolGlob(provider, args) {
2660
+ const res = await provider.glob(args);
2661
+ if (res.error) {
2662
+ return res.error;
2663
+ }
2664
+ if (!res.files.length) {
2665
+ return "no matches";
2666
+ }
2667
+ const header = `Found ${res.totalFound} file(s) matching "${args.pattern}" within ${res.searchDir}, sorted by modification time (newest first):`;
2668
+ const body = res.files.join("\n");
2669
+ const truncated = res.totalFound > res.files.length ? `
2670
+ [${res.totalFound - res.files.length} files truncated]` : "";
2671
+ return `${header}
2672
+ ---
2673
+ ${body}
2674
+ ---${truncated}`;
2694
2675
  }
2695
2676
 
2696
2677
  // tools/warp_grep/agent/tools/finish.ts
@@ -2751,32 +2732,21 @@ function mergeRanges(ranges) {
2751
2732
  return merged;
2752
2733
  }
2753
2734
 
2754
- // tools/warp_grep/agent/formatter.ts
2755
- var ToolOutputFormatter = class {
2756
- format(toolName, _args, output, options = {}) {
2757
- const name = (toolName ?? "").trim();
2758
- if (!name) {
2759
- return "";
2760
- }
2761
- const payload = output?.toString?.()?.trim?.() ?? "";
2762
- const isError = Boolean(options.isError);
2763
- if (!payload && !isError) {
2764
- return "";
2765
- }
2766
- return `<tool_response>
2767
- ${payload}
2768
- </tool_response>`;
2769
- }
2770
- };
2771
- var sharedFormatter = new ToolOutputFormatter();
2772
- function formatAgentToolOutput(toolName, args, output, options = {}) {
2773
- return sharedFormatter.format(toolName, args, output, options);
2774
- }
2775
-
2776
2735
  // tools/warp_grep/agent/helpers.ts
2777
- var import_path2 = __toESM(require("path"), 1);
2736
+ var import_path3 = __toESM(require("path"), 1);
2778
2737
  init_config();
2779
2738
  var TRUNCATED_MARKER = "[truncated for context limit]";
2739
+ function getMessageSize(m) {
2740
+ if (m.role === "tool") return m.content.length;
2741
+ if (m.role === "assistant") {
2742
+ let size = typeof m.content === "string" ? m.content.length : 0;
2743
+ if (m.tool_calls) {
2744
+ size += m.tool_calls.reduce((s, tc) => s + tc.function.name.length + tc.function.arguments.length, 0);
2745
+ }
2746
+ return size;
2747
+ }
2748
+ return m.content.length;
2749
+ }
2780
2750
  function formatTurnMessage(turnsUsed, maxTurns) {
2781
2751
  const turnsRemaining = maxTurns - turnsUsed;
2782
2752
  if (turnsRemaining === 1) {
@@ -2787,33 +2757,30 @@ You have used ${turnsUsed} turns, you only have 1 turn remaining. You have run o
2787
2757
  You have used ${turnsUsed} turn${turnsUsed === 1 ? "" : "s"} and have ${turnsRemaining} remaining`;
2788
2758
  }
2789
2759
  function calculateContextBudget(messages) {
2790
- const totalChars = messages.reduce((sum, m) => sum + m.content.length, 0);
2760
+ const totalChars = messages.reduce((sum, m) => sum + getMessageSize(m), 0);
2791
2761
  const maxChars = AGENT_CONFIG.MAX_CONTEXT_CHARS;
2792
- const percent = Math.round(totalChars / maxChars * 100);
2793
- const usedK = Math.round(totalChars / 1e3);
2794
- const maxK = Math.round(maxChars / 1e3);
2795
- return `<context_budget>${percent}% (${usedK}K/${maxK}K chars used)</context_budget>`;
2762
+ const percent = Math.floor(totalChars / maxChars * 100);
2763
+ const usedK = Math.floor(totalChars / 1e3);
2764
+ const maxK = Math.floor(maxChars / 1e3);
2765
+ return `<context_budget>${percent}% (${usedK}K/${maxK}K chars)</context_budget>`;
2796
2766
  }
2797
2767
  async function buildInitialState(repoRoot, searchTerm, provider, options) {
2798
2768
  const budget = calculateContextBudget([]);
2799
- const turnTag = `Turn 0/${AGENT_CONFIG.MAX_TURNS}`;
2769
+ const turnTag = `You have used 0 turns and have ${AGENT_CONFIG.MAX_TURNS} remaining`;
2800
2770
  const treeDepth = options?.search_type === "node_modules" ? 1 : 2;
2771
+ const absRoot = import_path3.default.resolve(repoRoot);
2801
2772
  try {
2802
2773
  const entries = await provider.listDirectory({
2803
2774
  path: ".",
2804
2775
  maxResults: AGENT_CONFIG.MAX_OUTPUT_LINES,
2805
2776
  maxDepth: treeDepth
2806
2777
  });
2807
- const treeLines = entries.map((e) => {
2808
- const indent = " ".repeat(e.depth);
2809
- const name = e.type === "dir" ? `${e.name}/` : e.name;
2810
- return `${indent}${name}`;
2811
- });
2812
- const repoName = import_path2.default.basename(repoRoot);
2813
- const treeOutput = treeLines.length > 0 ? `${repoName}/
2814
- ${treeLines.join("\n")}` : `${repoName}/`;
2778
+ const lines = [absRoot];
2779
+ for (const e of entries) {
2780
+ lines.push(import_path3.default.join(absRoot, e.path));
2781
+ }
2815
2782
  return `<repo_structure>
2816
- ${treeOutput}
2783
+ ${lines.join("\n")}
2817
2784
  </repo_structure>
2818
2785
 
2819
2786
  <search_string>
@@ -2822,9 +2789,8 @@ ${searchTerm}
2822
2789
  ${budget}
2823
2790
  ${turnTag}`;
2824
2791
  } catch {
2825
- const repoName = import_path2.default.basename(repoRoot);
2826
2792
  return `<repo_structure>
2827
- ${repoName}/
2793
+ ${absRoot}
2828
2794
  </repo_structure>
2829
2795
 
2830
2796
  <search_string>
@@ -2835,26 +2801,32 @@ ${turnTag}`;
2835
2801
  }
2836
2802
  }
2837
2803
  function enforceContextLimit(messages, maxChars = AGENT_CONFIG.MAX_CONTEXT_CHARS) {
2838
- const getTotalChars = () => messages.reduce((sum, m) => sum + m.content.length, 0);
2804
+ const getTotalChars = () => messages.reduce((sum, m) => sum + getMessageSize(m), 0);
2839
2805
  if (getTotalChars() <= maxChars) {
2840
2806
  return messages;
2841
2807
  }
2842
- const userIndices = [];
2808
+ const truncatableIndices = [];
2843
2809
  let firstUserSkipped = false;
2844
2810
  for (let i = 0; i < messages.length; i++) {
2845
- if (messages[i].role === "user") {
2811
+ const m = messages[i];
2812
+ if (m.role === "tool") {
2813
+ truncatableIndices.push(i);
2814
+ } else if (m.role === "user") {
2846
2815
  if (!firstUserSkipped) {
2847
2816
  firstUserSkipped = true;
2848
2817
  continue;
2849
2818
  }
2850
- userIndices.push(i);
2819
+ truncatableIndices.push(i);
2851
2820
  }
2852
2821
  }
2853
- for (const idx of userIndices) {
2822
+ for (const idx of truncatableIndices) {
2854
2823
  if (getTotalChars() <= maxChars) {
2855
2824
  break;
2856
2825
  }
2857
- if (messages[idx].content !== TRUNCATED_MARKER) {
2826
+ const m = messages[idx];
2827
+ if (m.role === "tool" && m.content !== TRUNCATED_MARKER) {
2828
+ messages[idx] = { role: "tool", tool_call_id: m.tool_call_id, content: TRUNCATED_MARKER };
2829
+ } else if (m.role === "user" && m.content !== TRUNCATED_MARKER) {
2858
2830
  messages[idx] = { role: "user", content: TRUNCATED_MARKER };
2859
2831
  }
2860
2832
  }
@@ -2864,9 +2836,115 @@ function enforceContextLimit(messages, maxChars = AGENT_CONFIG.MAX_CONTEXT_CHARS
2864
2836
  // tools/warp_grep/agent/runner.ts
2865
2837
  var import_openai2 = __toESM(require("openai"), 1);
2866
2838
  init_version();
2867
- var import_path3 = __toESM(require("path"), 1);
2868
- var parser = new LLMResponseParser();
2839
+ var import_path4 = __toESM(require("path"), 1);
2869
2840
  var DEFAULT_API_URL3 = "https://api.morphllm.com";
2841
+ var TOOL_SPECS = [
2842
+ {
2843
+ type: "function",
2844
+ function: {
2845
+ name: "list_directory",
2846
+ description: "Execute ls or find commands to explore directory structure. Max 500 results. Common junk directories are excluded automatically.",
2847
+ parameters: {
2848
+ type: "object",
2849
+ properties: {
2850
+ command: {
2851
+ type: "string",
2852
+ description: "Full ls or find command (e.g. ls -la src/, find . -maxdepth 2 -type f -name '*.py', find . -type d, ls -d */)."
2853
+ }
2854
+ },
2855
+ required: ["command"]
2856
+ }
2857
+ }
2858
+ },
2859
+ {
2860
+ type: "function",
2861
+ function: {
2862
+ name: "grep_search",
2863
+ description: "Search for a regex pattern in file contents. Returns matching lines with file paths and line numbers. Case-insensitive. Respects .gitignore.",
2864
+ parameters: {
2865
+ type: "object",
2866
+ properties: {
2867
+ pattern: {
2868
+ type: "string",
2869
+ description: "Regex pattern to search for in file contents (e.g. 'class\\s+\\w+Error', 'import|require|from', 'def (get|set|update)_user')."
2870
+ },
2871
+ path: {
2872
+ type: "string",
2873
+ description: "File or directory to search in. Defaults to current working directory."
2874
+ },
2875
+ glob: {
2876
+ type: "string",
2877
+ description: "Glob pattern to filter files (e.g. '*.py', '*.{ts,tsx,js,jsx,py,go}', 'src/**/*.go', '!*.test.*')."
2878
+ },
2879
+ limit: {
2880
+ type: "integer",
2881
+ description: "Limit output to first N matching lines. Shows all matches if not specified."
2882
+ }
2883
+ },
2884
+ required: ["pattern"]
2885
+ }
2886
+ }
2887
+ },
2888
+ {
2889
+ type: "function",
2890
+ function: {
2891
+ name: "glob",
2892
+ description: "Find files by name/extension using glob patterns. Returns absolute paths sorted by modification time (newest first). Respects .gitignore. Max 100 results.",
2893
+ parameters: {
2894
+ type: "object",
2895
+ properties: {
2896
+ pattern: {
2897
+ type: "string",
2898
+ description: "Glob pattern to match files (e.g. '*.py', 'src/**/*.js', '*.{ts,tsx}', 'test_*.py')."
2899
+ },
2900
+ path: {
2901
+ type: "string",
2902
+ description: "Directory to search in. Defaults to repository root."
2903
+ }
2904
+ },
2905
+ required: ["pattern"]
2906
+ }
2907
+ }
2908
+ },
2909
+ {
2910
+ type: "function",
2911
+ function: {
2912
+ name: "read",
2913
+ description: "Read entire files or specific line ranges using absolute paths.",
2914
+ parameters: {
2915
+ type: "object",
2916
+ properties: {
2917
+ path: {
2918
+ type: "string",
2919
+ description: "File path to read, using absolute path (e.g. '/home/ubuntu/repo/src/main.py' or windows path)."
2920
+ },
2921
+ lines: {
2922
+ type: "string",
2923
+ description: "Optional line range (e.g. '1-50' or '1-20,45-80'). Omit to read entire file."
2924
+ }
2925
+ },
2926
+ required: ["path"]
2927
+ }
2928
+ }
2929
+ },
2930
+ {
2931
+ type: "function",
2932
+ function: {
2933
+ name: "finish",
2934
+ description: "Submit final answer with all relevant code locations. Include imports and over-include rather than miss context.",
2935
+ parameters: {
2936
+ type: "object",
2937
+ properties: {
2938
+ files: {
2939
+ type: "string",
2940
+ description: "One file per line as path:lines (e.g. 'src/auth.py:1-15,25-50\\nsrc/user.py'). Omit line range to include entire file."
2941
+ }
2942
+ },
2943
+ required: ["files"]
2944
+ }
2945
+ }
2946
+ }
2947
+ ];
2870
2948
  async function callModel(messages, model, options = {}) {
2871
2949
  const baseUrl = options.morphApiUrl || DEFAULT_API_URL3;
2872
2950
  const apiKey = options.morphApiKey || process.env.MORPH_API_KEY || "";
@@ -2887,8 +2965,9 @@ async function callModel(messages, model, options = {}) {
2887
2965
  data = await client.chat.completions.create({
2888
2966
  model,
2889
2967
  temperature: 0,
2890
- max_tokens: 1024,
2968
+ max_tokens: 2048,
2891
2969
  messages,
2970
+ tools: TOOL_SPECS,
2892
2971
  ...options.search_type ? { search_type: options.search_type } : {}
2893
2972
  });
2894
2973
  } catch (error) {
@@ -2900,187 +2979,87 @@ async function callModel(messages, model, options = {}) {
2900
2979
  throw error;
2901
2980
  }
2902
2981
  const choice = data?.choices?.[0];
2903
- const content = choice?.message?.content;
2904
- if (content && typeof content === "string") {
2905
- return content;
2982
+ const message = choice?.message;
2983
+ if (!message) {
2984
+ if (attempt === MAX_EMPTY_RETRIES) {
2985
+ throw new Error("Invalid response from model: no message in response");
2986
+ }
2987
+ await new Promise((resolve2) => setTimeout(resolve2, 200));
2988
+ continue;
2989
+ }
2990
+ const toolCalls = (message.tool_calls || []).map((tc) => ({
2991
+ id: tc.id,
2992
+ type: "function",
2993
+ function: { name: tc.function.name, arguments: tc.function.arguments }
2994
+ }));
2995
+ if (message.content || toolCalls.length > 0) {
2996
+ return { content: message.content ?? null, tool_calls: toolCalls };
2906
2997
  }
2907
2998
  if (attempt === MAX_EMPTY_RETRIES) {
2908
2999
  const finishReason = choice?.finish_reason ?? "unknown";
2909
- const hasToolCalls = Array.isArray(choice?.message?.tool_calls) && choice.message.tool_calls.length > 0;
2910
- const choicesLen = data?.choices?.length ?? 0;
2911
- const contentType = content === null ? "null" : content === void 0 ? "undefined" : typeof content;
2912
3000
  throw new Error(
2913
- `Invalid response from model: content=${contentType}, finish_reason=${finishReason}, has_tool_calls=${hasToolCalls}, choices_length=${choicesLen}`
3001
+ `Invalid response from model: no content and no tool_calls, finish_reason=${finishReason}`
2914
3002
  );
2915
3003
  }
2916
3004
  await new Promise((resolve2) => setTimeout(resolve2, 200));
2917
3005
  }
2918
3006
  throw new Error("Invalid response from model");
2919
3007
  }
2920
- async function runWarpGrep(config) {
2921
- const totalStart = Date.now();
2922
- const timeoutMs = config.timeout ?? AGENT_CONFIG.TIMEOUT_MS;
2923
- const timings = { turns: [], timeout_ms: timeoutMs };
2924
- const repoRoot = import_path3.default.resolve(config.repoRoot || process.cwd());
2925
- const model = config.model || DEFAULT_MODEL;
2926
- const messages = [];
2927
- const maxTurns = AGENT_CONFIG.MAX_TURNS;
2928
- const initialStateStart = Date.now();
2929
- const initialState = await buildInitialState(repoRoot, config.searchTerm, config.provider, { search_type: config.search_type });
2930
- timings.initial_state_ms = Date.now() - initialStateStart;
2931
- messages.push({ role: "user", content: initialState });
2932
- const provider = config.provider;
2933
- const errors = [];
2934
- let finishMeta;
2935
- let terminationReason = "terminated";
2936
- for (let turn = 1; turn <= maxTurns; turn += 1) {
2937
- const turnMetrics = { turn, morph_api_ms: 0, local_tools_ms: 0 };
2938
- enforceContextLimit(messages);
2939
- const modelCallStart = Date.now();
2940
- const assistantContent = await callModel(messages, model, {
2941
- morphApiKey: config.morphApiKey,
2942
- morphApiUrl: config.morphApiUrl,
2943
- retryConfig: config.retryConfig,
2944
- timeout: timeoutMs,
2945
- search_type: config.search_type
2946
- }).catch((e) => {
2947
- const errMsg = e instanceof Error ? e.message : String(e);
2948
- console.error(`[warp_grep] Morph API call failed on turn ${turn}:`, errMsg);
2949
- errors.push({ message: errMsg });
2950
- return "";
2951
- });
2952
- turnMetrics.morph_api_ms = Date.now() - modelCallStart;
2953
- if (!assistantContent) {
2954
- console.error(`[warp_grep] Empty response from Morph API on turn ${turn}. Errors so far:`, errors);
2955
- timings.turns.push(turnMetrics);
2956
- break;
2957
- }
2958
- messages.push({ role: "assistant", content: assistantContent });
2959
- const toolCalls = parser.parse(assistantContent);
2960
- if (toolCalls.length === 0) {
2961
- console.error(`[warp_grep] No tool calls parsed on turn ${turn}. Assistant content (first 500 chars):`, assistantContent.slice(0, 500));
2962
- 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" });
2963
- terminationReason = "terminated";
2964
- timings.turns.push(turnMetrics);
2965
- break;
2966
- }
2967
- const finishCalls = toolCalls.filter((c) => c.name === "finish");
2968
- const grepCalls = toolCalls.filter((c) => c.name === "grep");
2969
- const listDirCalls = toolCalls.filter((c) => c.name === "list_directory");
2970
- const readCalls = toolCalls.filter((c) => c.name === "read");
2971
- const skipCalls = toolCalls.filter((c) => c.name === "_skip");
2972
- const formatted = [];
2973
- for (const c of skipCalls) {
2974
- const msg = c.arguments?.message || "Command skipped due to parsing error";
2975
- formatted.push(msg);
2976
- }
2977
- const allPromises = [];
2978
- for (const c of grepCalls) {
2979
- const args = c.arguments ?? {};
2980
- allPromises.push(
2981
- toolGrep(provider, args).then(
2982
- ({ output }) => formatAgentToolOutput("grep", args, output),
2983
- (err) => formatAgentToolOutput("grep", args, String(err), { isError: true })
2984
- )
2985
- );
2986
- }
2987
- for (const c of listDirCalls) {
2988
- const args = c.arguments ?? {};
2989
- allPromises.push(
2990
- toolListDirectory(provider, args).then(
2991
- (p) => formatAgentToolOutput("list_directory", args, p),
2992
- (err) => formatAgentToolOutput("list_directory", args, String(err), { isError: true })
2993
- )
2994
- );
2995
- }
2996
- for (const c of readCalls) {
2997
- const args = c.arguments ?? {};
2998
- allPromises.push(
2999
- toolRead(provider, args).then(
3000
- (p) => formatAgentToolOutput("read", args, p),
3001
- (err) => formatAgentToolOutput("read", args, String(err), { isError: true })
3002
- )
3003
- );
3008
+ function safeParseJSON(s) {
3009
+ try {
3010
+ return JSON.parse(s);
3011
+ } catch {
3012
+ return {};
3013
+ }
3014
+ }
3015
+ async function executeTool(provider, name, args, repoRoot) {
3016
+ switch (name) {
3017
+ case "grep_search": {
3018
+ const grepArgs = {
3019
+ pattern: args.pattern,
3020
+ path: args.path || "."
3021
+ };
3022
+ if (args.glob) grepArgs.glob = args.glob;
3023
+ if (args.case_sensitive !== void 0) grepArgs.case_sensitive = args.case_sensitive;
3024
+ const result = await toolGrep(provider, grepArgs);
3025
+ let output = result.output;
3026
+ if (args.limit && typeof args.limit === "number") {
3027
+ const lines = output.split("\n");
3028
+ if (lines.length > args.limit) {
3029
+ output = lines.slice(0, args.limit).join("\n") + `
3030
+ ... (truncated at ${args.limit} lines)`;
3031
+ }
3032
+ }
3033
+ return output;
3004
3034
  }
3005
- const toolExecStart = Date.now();
3006
- const allResults = await Promise.all(allPromises);
3007
- turnMetrics.local_tools_ms = Date.now() - toolExecStart;
3008
- for (const result of allResults) {
3009
- formatted.push(result);
3035
+ case "glob": {
3036
+ return toolGlob(provider, {
3037
+ pattern: args.pattern,
3038
+ path: args.path
3039
+ });
3010
3040
  }
3011
- if (formatted.length > 0) {
3012
- const turnMessage = formatTurnMessage(turn, maxTurns);
3013
- const contextBudget = calculateContextBudget(messages);
3014
- messages.push({ role: "user", content: formatted.join("\n") + turnMessage + "\n" + contextBudget });
3041
+ case "list_directory": {
3042
+ const dirPath = extractPathFromCommand(args.command || ".");
3043
+ return toolListDirectory(provider, { path: dirPath }, repoRoot);
3015
3044
  }
3016
- timings.turns.push(turnMetrics);
3017
- if (finishCalls.length) {
3018
- const fc = finishCalls[0];
3019
- const files = fc.arguments?.files ?? [];
3020
- const textResult = fc.arguments?.textResult;
3021
- finishMeta = { files };
3022
- terminationReason = "completed";
3023
- if (files.length === 0) {
3024
- const payload2 = textResult || "No relevant code found.";
3025
- timings.turns.push(turnMetrics);
3026
- timings.total_ms = Date.now() - totalStart;
3027
- return {
3028
- terminationReason: "completed",
3029
- messages,
3030
- finish: { payload: payload2, metadata: finishMeta },
3031
- timings
3032
- };
3033
- }
3034
- break;
3035
- }
3036
- }
3037
- if (terminationReason !== "completed" || !finishMeta) {
3038
- timings.total_ms = Date.now() - totalStart;
3039
- return { terminationReason, messages, errors, timings };
3040
- }
3041
- const parts = ["Relevant context found:"];
3042
- for (const f of finishMeta.files) {
3043
- const ranges = f.lines === "*" ? "*" : Array.isArray(f.lines) ? f.lines.map(([s, e]) => `${s}-${e}`).join(", ") : "*";
3044
- parts.push(`- ${f.path}: ${ranges}`);
3045
- }
3046
- const payload = parts.join("\n");
3047
- const finishResolutionStart = Date.now();
3048
- const fileReadErrors = [];
3049
- const resolved = await readFinishFiles(
3050
- repoRoot,
3051
- finishMeta.files,
3052
- async (p, s, e) => {
3053
- try {
3054
- const rr = await provider.read({ path: p, start: s, end: e });
3055
- return rr.lines.map((l) => {
3056
- const idx = l.indexOf("|");
3057
- return idx >= 0 ? l.slice(idx + 1) : l;
3058
- });
3059
- } catch (err) {
3060
- const errorMsg = err instanceof Error ? err.message : String(err);
3061
- fileReadErrors.push({ path: p, error: errorMsg });
3062
- console.error(`[warp_grep] Failed to read file: ${p} - ${errorMsg}`);
3063
- return [`[couldn't find: ${p}]`];
3045
+ case "read": {
3046
+ const readArgs = {
3047
+ path: args.path
3048
+ };
3049
+ if (args.lines && typeof args.lines === "string") {
3050
+ Object.assign(readArgs, parseReadLines(args.lines));
3064
3051
  }
3052
+ return toolRead(provider, readArgs);
3065
3053
  }
3066
- );
3067
- timings.finish_resolution_ms = Date.now() - finishResolutionStart;
3068
- if (fileReadErrors.length > 0) {
3069
- errors.push(...fileReadErrors.map((e) => ({ message: `File read error: ${e.path} - ${e.error}` })));
3054
+ default:
3055
+ return `Unknown tool: ${name}`;
3070
3056
  }
3071
- timings.total_ms = Date.now() - totalStart;
3072
- return {
3073
- terminationReason: "completed",
3074
- messages,
3075
- finish: { payload, metadata: finishMeta, resolved },
3076
- timings
3077
- };
3078
3057
  }
3079
3058
  async function* runWarpGrepStreaming(config) {
3080
3059
  const totalStart = Date.now();
3081
3060
  const timeoutMs = config.timeout ?? AGENT_CONFIG.TIMEOUT_MS;
3082
3061
  const timings = { turns: [], timeout_ms: timeoutMs };
3083
- const repoRoot = import_path3.default.resolve(config.repoRoot || process.cwd());
3062
+ const repoRoot = import_path4.default.resolve(config.repoRoot || process.cwd());
3084
3063
  const model = config.model || DEFAULT_MODEL;
3085
3064
  const messages = [];
3086
3065
  const maxTurns = AGENT_CONFIG.MAX_TURNS;
@@ -3096,7 +3075,7 @@ async function* runWarpGrepStreaming(config) {
3096
3075
  const turnMetrics = { turn, morph_api_ms: 0, local_tools_ms: 0 };
3097
3076
  enforceContextLimit(messages);
3098
3077
  const modelCallStart = Date.now();
3099
- const assistantContent = await callModel(messages, model, {
3078
+ const response = await callModel(messages, model, {
3100
3079
  morphApiKey: config.morphApiKey,
3101
3080
  morphApiUrl: config.morphApiUrl,
3102
3081
  retryConfig: config.retryConfig,
@@ -3104,90 +3083,45 @@ async function* runWarpGrepStreaming(config) {
3104
3083
  search_type: config.search_type
3105
3084
  }).catch((e) => {
3106
3085
  const errMsg = e instanceof Error ? e.message : String(e);
3107
- console.error(`[warp_grep:stream] Morph API call failed on turn ${turn}:`, errMsg);
3086
+ console.error(`[warp_grep] Morph API call failed on turn ${turn}:`, errMsg);
3108
3087
  errors.push({ message: errMsg });
3109
- return "";
3088
+ return null;
3110
3089
  });
3111
3090
  turnMetrics.morph_api_ms = Date.now() - modelCallStart;
3112
- if (!assistantContent) {
3113
- console.error(`[warp_grep:stream] Empty response from Morph API on turn ${turn}. Errors so far:`, errors);
3091
+ if (!response) {
3114
3092
  timings.turns.push(turnMetrics);
3115
3093
  break;
3116
3094
  }
3117
- messages.push({ role: "assistant", content: assistantContent });
3118
- const toolCalls = parser.parse(assistantContent);
3095
+ const toolCalls = response.tool_calls;
3096
+ messages.push({
3097
+ role: "assistant",
3098
+ content: response.content,
3099
+ ...toolCalls.length > 0 ? { tool_calls: toolCalls } : {}
3100
+ });
3119
3101
  if (toolCalls.length === 0) {
3120
- console.error(`[warp_grep:stream] No tool calls parsed on turn ${turn}. Assistant content (first 500 chars):`, assistantContent.slice(0, 500));
3121
- 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" });
3102
+ console.error(`[warp_grep] No tool calls on turn ${turn}. Content: ${(response.content || "").slice(0, 500)}`);
3103
+ errors.push({ message: "No tool calls produced by the model." });
3122
3104
  terminationReason = "terminated";
3123
3105
  timings.turns.push(turnMetrics);
3124
3106
  break;
3125
3107
  }
3126
3108
  yield {
3127
3109
  turn,
3128
- toolCalls: toolCalls.map((c) => ({
3129
- name: c.name,
3130
- arguments: c.arguments ?? {}
3110
+ toolCalls: toolCalls.map((tc) => ({
3111
+ name: tc.function.name,
3112
+ arguments: safeParseJSON(tc.function.arguments)
3131
3113
  }))
3132
3114
  };
3133
- const finishCalls = toolCalls.filter((c) => c.name === "finish");
3134
- const grepCalls = toolCalls.filter((c) => c.name === "grep");
3135
- const listDirCalls = toolCalls.filter((c) => c.name === "list_directory");
3136
- const readCalls = toolCalls.filter((c) => c.name === "read");
3137
- const skipCalls = toolCalls.filter((c) => c.name === "_skip");
3138
- const formatted = [];
3139
- for (const c of skipCalls) {
3140
- const msg = c.arguments?.message || "Command skipped due to parsing error";
3141
- formatted.push(msg);
3142
- }
3143
- const allPromises = [];
3144
- for (const c of grepCalls) {
3145
- const args = c.arguments ?? {};
3146
- allPromises.push(
3147
- toolGrep(provider, args).then(
3148
- ({ output }) => formatAgentToolOutput("grep", args, output),
3149
- (err) => formatAgentToolOutput("grep", args, String(err), { isError: true })
3150
- )
3151
- );
3152
- }
3153
- for (const c of listDirCalls) {
3154
- const args = c.arguments ?? {};
3155
- allPromises.push(
3156
- toolListDirectory(provider, args).then(
3157
- (p) => formatAgentToolOutput("list_directory", args, p),
3158
- (err) => formatAgentToolOutput("list_directory", args, String(err), { isError: true })
3159
- )
3160
- );
3161
- }
3162
- for (const c of readCalls) {
3163
- const args = c.arguments ?? {};
3164
- allPromises.push(
3165
- toolRead(provider, args).then(
3166
- (p) => formatAgentToolOutput("read", args, p),
3167
- (err) => formatAgentToolOutput("read", args, String(err), { isError: true })
3168
- )
3169
- );
3170
- }
3171
- const toolExecStart = Date.now();
3172
- const allResults = await Promise.all(allPromises);
3173
- turnMetrics.local_tools_ms = Date.now() - toolExecStart;
3174
- for (const result of allResults) {
3175
- formatted.push(result);
3176
- }
3177
- if (formatted.length > 0) {
3178
- const turnMessage = formatTurnMessage(turn, maxTurns);
3179
- const contextBudget = calculateContextBudget(messages);
3180
- messages.push({ role: "user", content: formatted.join("\n") + turnMessage + "\n" + contextBudget });
3181
- }
3182
- timings.turns.push(turnMetrics);
3183
- if (finishCalls.length) {
3184
- const fc = finishCalls[0];
3185
- const files = fc.arguments?.files ?? [];
3186
- const textResult = fc.arguments?.textResult;
3115
+ const finishCall = toolCalls.find((tc) => tc.function.name === "finish");
3116
+ if (finishCall) {
3117
+ const args = safeParseJSON(finishCall.function.arguments);
3118
+ const filesStr = args.files || "";
3119
+ const files = parseFinishFiles(filesStr);
3187
3120
  finishMeta = { files };
3188
3121
  terminationReason = "completed";
3189
3122
  if (files.length === 0) {
3190
- const payload2 = textResult || "No relevant code found.";
3123
+ const payload2 = filesStr || "No relevant code found.";
3124
+ timings.turns.push(turnMetrics);
3191
3125
  timings.total_ms = Date.now() - totalStart;
3192
3126
  return {
3193
3127
  terminationReason: "completed",
@@ -3196,8 +3130,25 @@ async function* runWarpGrepStreaming(config) {
3196
3130
  timings
3197
3131
  };
3198
3132
  }
3133
+ timings.turns.push(turnMetrics);
3199
3134
  break;
3200
3135
  }
3136
+ const toolExecStart = Date.now();
3137
+ const results = await Promise.all(
3138
+ toolCalls.map(async (tc) => {
3139
+ const args = safeParseJSON(tc.function.arguments);
3140
+ const output = await executeTool(provider, tc.function.name, args, repoRoot).catch((err) => String(err));
3141
+ return { tool_call_id: tc.id, content: output };
3142
+ })
3143
+ );
3144
+ turnMetrics.local_tools_ms = Date.now() - toolExecStart;
3145
+ for (const result of results) {
3146
+ messages.push({ role: "tool", tool_call_id: result.tool_call_id, content: result.content });
3147
+ }
3148
+ const turnMsg = formatTurnMessage(turn, maxTurns);
3149
+ const budget = calculateContextBudget(messages);
3150
+ messages.push({ role: "user", content: turnMsg + "\n" + budget });
3151
+ timings.turns.push(turnMetrics);
3201
3152
  }
3202
3153
  if (terminationReason !== "completed" || !finishMeta) {
3203
3154
  timings.total_ms = Date.now() - totalStart;
@@ -3215,17 +3166,22 @@ async function* runWarpGrepStreaming(config) {
3215
3166
  repoRoot,
3216
3167
  finishMeta.files,
3217
3168
  async (p, s, e) => {
3169
+ let resolvedPath = p;
3170
+ if (!p.startsWith(repoRoot)) {
3171
+ const relative2 = p.startsWith("/") ? p.slice(1) : p;
3172
+ resolvedPath = import_path4.default.join(repoRoot, relative2);
3173
+ }
3218
3174
  try {
3219
- const rr = await provider.read({ path: p, start: s, end: e });
3175
+ const rr = await provider.read({ path: resolvedPath, start: s, end: e });
3220
3176
  return rr.lines.map((l) => {
3221
3177
  const idx = l.indexOf("|");
3222
3178
  return idx >= 0 ? l.slice(idx + 1) : l;
3223
3179
  });
3224
3180
  } catch (err) {
3225
3181
  const errorMsg = err instanceof Error ? err.message : String(err);
3226
- fileReadErrors.push({ path: p, error: errorMsg });
3227
- console.error(`[warp_grep] Failed to read file: ${p} - ${errorMsg}`);
3228
- return [`[couldn't find: ${p}]`];
3182
+ fileReadErrors.push({ path: resolvedPath, error: errorMsg });
3183
+ console.error(`[warp_grep] Failed to read file: ${resolvedPath} - ${errorMsg}`);
3184
+ return [`[couldn't find: ${resolvedPath}]`];
3229
3185
  }
3230
3186
  }
3231
3187
  );
@@ -3241,6 +3197,14 @@ async function* runWarpGrepStreaming(config) {
3241
3197
  timings
3242
3198
  };
3243
3199
  }
3200
+ async function runWarpGrep(config) {
3201
+ const gen = runWarpGrepStreaming(config);
3202
+ let result = await gen.next();
3203
+ while (!result.done) {
3204
+ result = await gen.next();
3205
+ }
3206
+ return result.value;
3207
+ }
3244
3208
 
3245
3209
  // tools/warp_grep/providers/remote.ts
3246
3210
  init_config();
@@ -3420,6 +3384,35 @@ var RemoteCommandsProvider = class {
3420
3384
  return [];
3421
3385
  }
3422
3386
  }
3387
+ /**
3388
+ * Glob search - finds files matching a pattern.
3389
+ * Falls back to a grep --files approach via the listDir command.
3390
+ */
3391
+ async glob(params) {
3392
+ const searchPath = params.path || this.repoRoot;
3393
+ try {
3394
+ const stdout = await this.commands.listDir(searchPath, 10);
3395
+ const allPaths = (stdout || "").trim().split(/\r?\n/).filter((p) => p.length > 0);
3396
+ const globToRegex = (glob) => {
3397
+ const escaped = glob.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".");
3398
+ return new RegExp(escaped);
3399
+ };
3400
+ const regex = globToRegex(params.pattern);
3401
+ const matched = allPaths.filter((p) => {
3402
+ const name = p.split("/").pop() || "";
3403
+ return regex.test(name) && !shouldSkip(name);
3404
+ });
3405
+ const totalFound = matched.length;
3406
+ return { files: matched.slice(0, 100), searchDir: searchPath, totalFound };
3407
+ } catch (error) {
3408
+ return {
3409
+ files: [],
3410
+ searchDir: searchPath,
3411
+ totalFound: 0,
3412
+ error: `[GLOB ERROR] ${error instanceof Error ? error.message : String(error)}`
3413
+ };
3414
+ }
3415
+ }
3423
3416
  };
3424
3417
 
3425
3418
  // tools/warp_grep/providers/code_storage_http.ts
@@ -3446,9 +3439,9 @@ function createCodeStorageHttpCommands(config) {
3446
3439
  const { baseUrl, repoId, branch } = config;
3447
3440
  const encodedRepoId = encodeURIComponent(repoId);
3448
3441
  return {
3449
- grep: (pattern, path5, glob) => post(`${baseUrl}/api/code-search/${encodedRepoId}/grep`, { pattern, path: path5, glob, branch }, "grep"),
3450
- read: (path5, start, end) => post(`${baseUrl}/api/code-search/${encodedRepoId}/read`, { path: path5, start, end, branch }, "read"),
3451
- listDir: (path5, maxDepth) => post(`${baseUrl}/api/code-search/${encodedRepoId}/list`, { path: path5, maxDepth, branch }, "list")
3442
+ grep: (pattern, path6, glob) => post(`${baseUrl}/api/code-search/${encodedRepoId}/grep`, { pattern, path: path6, glob, branch }, "grep"),
3443
+ read: (path6, start, end) => post(`${baseUrl}/api/code-search/${encodedRepoId}/read`, { path: path6, start, end, branch }, "read"),
3444
+ listDir: (path6, maxDepth) => post(`${baseUrl}/api/code-search/${encodedRepoId}/list`, { path: path6, maxDepth, branch }, "list")
3452
3445
  };
3453
3446
  }
3454
3447
 
@@ -3831,10 +3824,10 @@ var GitHubClient = class {
3831
3824
  /**
3832
3825
  * Make an authenticated API request
3833
3826
  */
3834
- async request(method, path5, body) {
3835
- const url = `${this.baseUrl}${path5}`;
3827
+ async request(method, path6, body) {
3828
+ const url = `${this.baseUrl}${path6}`;
3836
3829
  if (this.debug) {
3837
- console.log(`[GitHub SDK] ${method} ${path5}`, body || "");
3830
+ console.log(`[GitHub SDK] ${method} ${path6}`, body || "");
3838
3831
  }
3839
3832
  const controller = new AbortController();
3840
3833
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);