@morphllm/morphsdk 0.2.50 → 0.2.52

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 (62) hide show
  1. package/dist/{chunk-4MELBN55.js → chunk-FYQUSDOE.js} +4 -4
  2. package/dist/{chunk-Z2FBMSNE.js → chunk-HQO45BAJ.js} +5 -1
  3. package/dist/chunk-HQO45BAJ.js.map +1 -0
  4. package/dist/{chunk-NRWVMX4O.js → chunk-L5BMGLLQ.js} +29 -22
  5. package/dist/chunk-L5BMGLLQ.js.map +1 -0
  6. package/dist/{chunk-SWQPIKPY.js → chunk-LVPVVLTI.js} +70 -49
  7. package/dist/chunk-LVPVVLTI.js.map +1 -0
  8. package/dist/{chunk-2TXLSKGU.js → chunk-MZT6HVGD.js} +3 -3
  9. package/dist/{chunk-DZRBTNQR.js → chunk-PZDR5ZZ2.js} +5 -5
  10. package/dist/{chunk-KH3RKPPO.js → chunk-UU6XCZG3.js} +4 -4
  11. package/dist/{chunk-5ASRBH5I.js → chunk-YR53PPVM.js} +4 -4
  12. package/dist/{chunk-MLDK7SCW.js → chunk-ZJIIICRA.js} +29 -7
  13. package/dist/chunk-ZJIIICRA.js.map +1 -0
  14. package/dist/client.cjs +116 -68
  15. package/dist/client.cjs.map +1 -1
  16. package/dist/client.js +13 -13
  17. package/dist/index.cjs +116 -68
  18. package/dist/index.cjs.map +1 -1
  19. package/dist/index.js +13 -13
  20. package/dist/tools/warp_grep/agent/parser.cjs +69 -48
  21. package/dist/tools/warp_grep/agent/parser.cjs.map +1 -1
  22. package/dist/tools/warp_grep/agent/parser.d.ts +2 -0
  23. package/dist/tools/warp_grep/agent/parser.js +1 -1
  24. package/dist/tools/warp_grep/agent/runner.cjs +88 -62
  25. package/dist/tools/warp_grep/agent/runner.cjs.map +1 -1
  26. package/dist/tools/warp_grep/agent/runner.js +7 -7
  27. package/dist/tools/warp_grep/agent/types.cjs.map +1 -1
  28. package/dist/tools/warp_grep/agent/types.d.ts +1 -1
  29. package/dist/tools/warp_grep/anthropic.cjs +116 -68
  30. package/dist/tools/warp_grep/anthropic.cjs.map +1 -1
  31. package/dist/tools/warp_grep/anthropic.js +10 -10
  32. package/dist/tools/warp_grep/index.cjs +116 -68
  33. package/dist/tools/warp_grep/index.cjs.map +1 -1
  34. package/dist/tools/warp_grep/index.js +12 -12
  35. package/dist/tools/warp_grep/openai.cjs +116 -68
  36. package/dist/tools/warp_grep/openai.cjs.map +1 -1
  37. package/dist/tools/warp_grep/openai.js +10 -10
  38. package/dist/tools/warp_grep/providers/local.cjs +28 -6
  39. package/dist/tools/warp_grep/providers/local.cjs.map +1 -1
  40. package/dist/tools/warp_grep/providers/local.js +1 -1
  41. package/dist/tools/warp_grep/providers/types.cjs.map +1 -1
  42. package/dist/tools/warp_grep/providers/types.d.ts +2 -0
  43. package/dist/tools/warp_grep/tools/grep.cjs +3 -0
  44. package/dist/tools/warp_grep/tools/grep.cjs.map +1 -1
  45. package/dist/tools/warp_grep/tools/grep.js +3 -0
  46. package/dist/tools/warp_grep/tools/grep.js.map +1 -1
  47. package/dist/tools/warp_grep/tools/read.cjs +4 -0
  48. package/dist/tools/warp_grep/tools/read.cjs.map +1 -1
  49. package/dist/tools/warp_grep/tools/read.js +1 -1
  50. package/dist/tools/warp_grep/vercel.cjs +116 -68
  51. package/dist/tools/warp_grep/vercel.cjs.map +1 -1
  52. package/dist/tools/warp_grep/vercel.js +10 -10
  53. package/package.json +1 -1
  54. package/dist/chunk-MLDK7SCW.js.map +0 -1
  55. package/dist/chunk-NRWVMX4O.js.map +0 -1
  56. package/dist/chunk-SWQPIKPY.js.map +0 -1
  57. package/dist/chunk-Z2FBMSNE.js.map +0 -1
  58. /package/dist/{chunk-4MELBN55.js.map → chunk-FYQUSDOE.js.map} +0 -0
  59. /package/dist/{chunk-2TXLSKGU.js.map → chunk-MZT6HVGD.js.map} +0 -0
  60. /package/dist/{chunk-DZRBTNQR.js.map → chunk-PZDR5ZZ2.js.map} +0 -0
  61. /package/dist/{chunk-KH3RKPPO.js.map → chunk-UU6XCZG3.js.map} +0 -0
  62. /package/dist/{chunk-5ASRBH5I.js.map → chunk-YR53PPVM.js.map} +0 -0
@@ -252,12 +252,6 @@ function getSystemPrompt() {
252
252
  }
253
253
 
254
254
  // tools/warp_grep/agent/parser.ts
255
- var LLMResponseParseError = class extends Error {
256
- constructor(message) {
257
- super(message);
258
- this.name = "LLMResponseParseError";
259
- }
260
- };
261
255
  var VALID_COMMANDS = ["analyse", "grep", "read", "finish"];
262
256
  function preprocessText(text) {
263
257
  let processed = text.replace(/<think>[\s\S]*?<\/think>/gi, "");
@@ -308,24 +302,23 @@ var LLMResponseParser = class {
308
302
  const lines = preprocessText(text);
309
303
  const commands = [];
310
304
  let finishAccumulator = null;
311
- lines.forEach((line, idx) => {
305
+ lines.forEach((line) => {
312
306
  if (!line || line.startsWith("#")) return;
313
- const ctx = { lineNumber: idx + 1, raw: line };
314
- const parts = this.splitLine(line, ctx);
307
+ const parts = this.splitLine(line);
315
308
  if (parts.length === 0) return;
316
309
  const cmd = parts[0];
317
310
  switch (cmd) {
318
311
  case "analyse":
319
- this.handleAnalyse(parts, ctx, commands);
312
+ this.handleAnalyse(parts, line, commands);
320
313
  break;
321
314
  case "grep":
322
- this.handleGrep(parts, ctx, commands);
315
+ this.handleGrep(parts, line, commands);
323
316
  break;
324
317
  case "read":
325
- this.handleRead(parts, ctx, commands);
318
+ this.handleRead(parts, line, commands);
326
319
  break;
327
320
  case "finish":
328
- finishAccumulator = this.handleFinish(parts, ctx, finishAccumulator);
321
+ finishAccumulator = this.handleFinish(parts, line, commands, finishAccumulator);
329
322
  break;
330
323
  default:
331
324
  break;
@@ -342,53 +335,68 @@ var LLMResponseParser = class {
342
335
  }
343
336
  return commands;
344
337
  }
345
- splitLine(line, ctx) {
346
- try {
347
- const parts = [];
348
- let current = "";
349
- let inSingle = false;
350
- for (let i = 0; i < line.length; i++) {
351
- const ch = line[i];
352
- if (ch === "'" && line[i - 1] !== "\\") {
353
- inSingle = !inSingle;
354
- current += ch;
355
- } else if (!inSingle && /\s/.test(ch)) {
356
- if (current) {
357
- parts.push(current);
358
- current = "";
359
- }
360
- } else {
361
- current += ch;
338
+ splitLine(line) {
339
+ const parts = [];
340
+ let current = "";
341
+ let inSingle = false;
342
+ for (let i = 0; i < line.length; i++) {
343
+ const ch = line[i];
344
+ if (ch === "'" && line[i - 1] !== "\\") {
345
+ inSingle = !inSingle;
346
+ current += ch;
347
+ } else if (!inSingle && /\s/.test(ch)) {
348
+ if (current) {
349
+ parts.push(current);
350
+ current = "";
362
351
  }
352
+ } else {
353
+ current += ch;
363
354
  }
364
- if (current) parts.push(current);
365
- return parts;
366
- } catch {
367
- throw new LLMResponseParseError(`Line ${ctx.lineNumber}: Unable to parse line.`);
368
355
  }
356
+ if (current) parts.push(current);
357
+ return parts;
358
+ }
359
+ /** Helper to create a _skip tool call with an error message */
360
+ skip(message) {
361
+ return { name: "_skip", arguments: { message } };
369
362
  }
370
- handleAnalyse(parts, ctx, commands) {
363
+ handleAnalyse(parts, rawLine, commands) {
371
364
  if (parts.length < 2) {
372
- throw new LLMResponseParseError(`Line ${ctx.lineNumber}: analyse requires <path>`);
365
+ commands.push(this.skip(
366
+ `[SKIPPED] Your command "${rawLine}" is missing a path. Correct format: analyse <path> [pattern]. Example: analyse src/`
367
+ ));
368
+ return;
373
369
  }
374
370
  const path4 = parts[1];
375
371
  const pattern = parts[2]?.replace(/^"|"$/g, "") ?? null;
376
372
  commands.push({ name: "analyse", arguments: { path: path4, pattern } });
377
373
  }
378
374
  // no glob tool in MCP
379
- handleGrep(parts, ctx, commands) {
375
+ handleGrep(parts, rawLine, commands) {
380
376
  if (parts.length < 3) {
381
- throw new LLMResponseParseError(`Line ${ctx.lineNumber}: grep requires '<pattern>' and <path>`);
377
+ commands.push(this.skip(
378
+ `[SKIPPED] Your command "${rawLine}" is missing arguments. Correct format: grep '<pattern>' <path>. Example: grep 'TODO' src/`
379
+ ));
380
+ return;
382
381
  }
383
- const pat = parts[1];
384
- if (!pat.startsWith("'") || !pat.endsWith("'")) {
385
- throw new LLMResponseParseError(`Line ${ctx.lineNumber}: grep pattern must be single-quoted`);
382
+ let pat = parts[1];
383
+ if (pat.startsWith("'") && pat.endsWith("'")) {
384
+ pat = pat.slice(1, -1);
386
385
  }
387
- commands.push({ name: "grep", arguments: { pattern: pat.slice(1, -1), path: parts[2] } });
386
+ if (!pat) {
387
+ commands.push(this.skip(
388
+ `[SKIPPED] Your command "${rawLine}" has an empty pattern. Provide a non-empty search pattern. Example: grep 'function' src/`
389
+ ));
390
+ return;
391
+ }
392
+ commands.push({ name: "grep", arguments: { pattern: pat, path: parts[2] } });
388
393
  }
389
- handleRead(parts, ctx, commands) {
394
+ handleRead(parts, rawLine, commands) {
390
395
  if (parts.length < 2) {
391
- throw new LLMResponseParseError(`Line ${ctx.lineNumber}: read requires <path> or <path>:<start-end>`);
396
+ commands.push(this.skip(
397
+ `[SKIPPED] Your command "${rawLine}" is missing a path. Correct format: read <path> or read <path>:<start>-<end>. Example: read src/index.ts:1-50`
398
+ ));
399
+ return;
392
400
  }
393
401
  const spec = parts[1];
394
402
  const rangeIdx = spec.indexOf(":");
@@ -396,31 +404,38 @@ var LLMResponseParser = class {
396
404
  commands.push({ name: "read", arguments: { path: spec } });
397
405
  return;
398
406
  }
399
- const path4 = spec.slice(0, rangeIdx);
407
+ const filePath = spec.slice(0, rangeIdx);
400
408
  const range = spec.slice(rangeIdx + 1);
401
409
  const [s, e] = range.split("-").map((v) => parseInt(v, 10));
402
410
  if (!Number.isFinite(s) || !Number.isFinite(e)) {
403
- throw new LLMResponseParseError(`Line ${ctx.lineNumber}: invalid read range '${range}'`);
411
+ commands.push({ name: "read", arguments: { path: filePath } });
412
+ return;
404
413
  }
405
- commands.push({ name: "read", arguments: { path: path4, start: s, end: e } });
414
+ commands.push({ name: "read", arguments: { path: filePath, start: s, end: e } });
406
415
  }
407
- handleFinish(parts, ctx, acc) {
416
+ handleFinish(parts, rawLine, commands, acc) {
408
417
  const map = acc ?? /* @__PURE__ */ new Map();
409
418
  const args = parts.slice(1);
410
419
  for (const token of args) {
411
- const [path4, rangesText] = token.split(":", 2);
412
- if (!path4 || !rangesText) {
413
- throw new LLMResponseParseError(`Line ${ctx.lineNumber}: invalid finish token '${token}'`);
420
+ const [filePath, rangesText] = token.split(":", 2);
421
+ if (!filePath || !rangesText) {
422
+ commands.push(this.skip(
423
+ `[SKIPPED] Invalid finish token "${token}". Correct format: finish <path>:<start>-<end>. Example: finish src/index.ts:1-50`
424
+ ));
425
+ continue;
414
426
  }
415
427
  const rangeSpecs = rangesText.split(",").filter(Boolean);
416
428
  for (const spec of rangeSpecs) {
417
429
  const [s, e] = spec.split("-").map((v) => parseInt(v, 10));
418
430
  if (!Number.isFinite(s) || !Number.isFinite(e) || e < s) {
419
- throw new LLMResponseParseError(`Line ${ctx.lineNumber}: invalid range '${spec}'`);
431
+ commands.push(this.skip(
432
+ `[SKIPPED] Invalid range "${spec}" in "${token}". Ranges must be <start>-<end> where start <= end. Example: 1-50`
433
+ ));
434
+ continue;
420
435
  }
421
- const arr = map.get(path4) ?? [];
436
+ const arr = map.get(filePath) ?? [];
422
437
  arr.push([s, e]);
423
- map.set(path4, arr);
438
+ map.set(filePath, arr);
424
439
  }
425
440
  }
426
441
  return map;
@@ -430,6 +445,10 @@ var LLMResponseParser = class {
430
445
  // tools/warp_grep/tools/read.ts
431
446
  async function toolRead(provider, args) {
432
447
  const res = await provider.read({ path: args.path, start: args.start, end: args.end });
448
+ if (res.error) {
449
+ return res.error;
450
+ }
451
+ if (!res.lines.length) return "(empty file)";
433
452
  return res.lines.join("\n");
434
453
  }
435
454
 
@@ -815,14 +834,7 @@ async function runWarpGrep(config) {
815
834
  });
816
835
  if (!assistantContent) break;
817
836
  messages.push({ role: "assistant", content: assistantContent });
818
- let toolCalls = [];
819
- try {
820
- toolCalls = parser.parse(assistantContent);
821
- } catch (e) {
822
- errors.push({ message: e instanceof Error ? e.message : String(e) });
823
- terminationReason = "terminated";
824
- break;
825
- }
837
+ const toolCalls = parser.parse(assistantContent);
826
838
  if (toolCalls.length === 0) {
827
839
  errors.push({ message: "No tool calls produced by the model." });
828
840
  terminationReason = "terminated";
@@ -832,7 +844,12 @@ async function runWarpGrep(config) {
832
844
  const grepCalls = toolCalls.filter((c) => c.name === "grep");
833
845
  const analyseCalls = toolCalls.filter((c) => c.name === "analyse");
834
846
  const readCalls = toolCalls.filter((c) => c.name === "read");
847
+ const skipCalls = toolCalls.filter((c) => c.name === "_skip");
835
848
  const formatted = [];
849
+ for (const c of skipCalls) {
850
+ const msg = c.arguments?.message || "Command skipped due to parsing error";
851
+ formatted.push(msg);
852
+ }
836
853
  const otherPromises = [];
837
854
  for (const c of analyseCalls) {
838
855
  const args = c.arguments ?? {};
@@ -858,6 +875,15 @@ async function runWarpGrep(config) {
858
875
  const args = c.arguments ?? {};
859
876
  try {
860
877
  const grepRes = await provider.grep({ pattern: args.pattern, path: args.path });
878
+ if (grepRes.error) {
879
+ errors.push({ message: grepRes.error });
880
+ terminationReason = "terminated";
881
+ return {
882
+ terminationReason: "terminated",
883
+ messages,
884
+ errors
885
+ };
886
+ }
861
887
  const rawOutput = Array.isArray(grepRes.lines) ? grepRes.lines.join("\n") : "";
862
888
  const newMatches = parseAndFilterGrepOutput(rawOutput, grepState);
863
889
  let formattedPayload = formatTurnGrepOutput(newMatches);
@@ -1069,10 +1095,22 @@ var LocalRipgrepProvider = class {
1069
1095
  ];
1070
1096
  const res = await runRipgrep(args, { cwd: this.repoRoot });
1071
1097
  if (res.exitCode === -1) {
1072
- throw new Error(res.stderr || "ripgrep (rg) execution failed.");
1098
+ return {
1099
+ lines: [],
1100
+ error: `[RIPGREP NOT AVAILABLE] ripgrep (rg) is required but failed to execute. Please install it:
1101
+ \u2022 macOS: brew install ripgrep
1102
+ \u2022 Ubuntu/Debian: apt install ripgrep
1103
+ \u2022 Windows: choco install ripgrep
1104
+ \u2022 Or visit: https://github.com/BurntSushi/ripgrep#installation
1105
+ Exit code: ${res.exitCode}${res.stderr ? `
1106
+ Details: ${res.stderr}` : ""}`
1107
+ };
1073
1108
  }
1074
1109
  if (res.exitCode !== 0 && res.exitCode !== 1) {
1075
- throw new Error(res.stderr || `ripgrep failed with code ${res.exitCode}`);
1110
+ return {
1111
+ lines: [],
1112
+ error: `[RIPGREP ERROR] grep failed with exit code ${res.exitCode}${res.stderr ? `: ${res.stderr}` : ""}`
1113
+ };
1076
1114
  }
1077
1115
  const lines = (res.stdout || "").trim().split(/\r?\n/).filter((l) => l.length > 0);
1078
1116
  return { lines };
@@ -1090,7 +1128,8 @@ var LocalRipgrepProvider = class {
1090
1128
  ];
1091
1129
  const res = await runRipgrep(args, { cwd: this.repoRoot });
1092
1130
  if (res.exitCode === -1) {
1093
- throw new Error(res.stderr || "ripgrep (rg) execution failed.");
1131
+ console.warn(`[warp_grep] ripgrep not available for glob: ${res.stderr || "execution failed"}`);
1132
+ return { files: [] };
1094
1133
  }
1095
1134
  const files = (res.stdout || "").trim().split(/\r?\n/).filter((l) => l.length > 0);
1096
1135
  return { files };
@@ -1099,13 +1138,22 @@ var LocalRipgrepProvider = class {
1099
1138
  const abs = resolveUnderRepo(this.repoRoot, params.path);
1100
1139
  const stat = await import_promises3.default.stat(abs).catch(() => null);
1101
1140
  if (!stat || !stat.isFile()) {
1102
- throw new Error(`Path is not a file: ${params.path}`);
1141
+ return {
1142
+ lines: [],
1143
+ error: `[FILE NOT FOUND] You tried to read "${params.path}" but there is no file at this path. Double-check the path exists and is spelled correctly.`
1144
+ };
1103
1145
  }
1104
1146
  if (isSymlink(abs)) {
1105
- throw new Error(`Refusing to read symlink: ${params.path}`);
1147
+ return {
1148
+ lines: [],
1149
+ error: `[SYMLINK] You tried to read "${params.path}" but this is a symlink. Try reading the actual file it points to instead.`
1150
+ };
1106
1151
  }
1107
1152
  if (!isTextualFile(abs)) {
1108
- throw new Error(`Non-text or too-large file: ${params.path}`);
1153
+ return {
1154
+ lines: [],
1155
+ error: `[UNREADABLE FILE] You tried to read "${params.path}" but this file is either too large or not a text file, so it cannot be read. Try a different file.`
1156
+ };
1109
1157
  }
1110
1158
  const lines = await readAllLines(abs);
1111
1159
  const total = lines.length;