@morphllm/morphsdk 0.2.50 → 0.2.51

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-KH3RKPPO.js → chunk-2GZMA5OY.js} +4 -4
  2. package/dist/{chunk-DZRBTNQR.js → chunk-3IASMZXX.js} +5 -5
  3. package/dist/{chunk-NRWVMX4O.js → chunk-HBH4FWIZ.js} +18 -11
  4. package/dist/chunk-HBH4FWIZ.js.map +1 -0
  5. package/dist/{chunk-Z2FBMSNE.js → chunk-HQO45BAJ.js} +5 -1
  6. package/dist/chunk-HQO45BAJ.js.map +1 -0
  7. package/dist/{chunk-2TXLSKGU.js → chunk-KMWLHINT.js} +3 -3
  8. package/dist/{chunk-SWQPIKPY.js → chunk-LVPVVLTI.js} +70 -49
  9. package/dist/chunk-LVPVVLTI.js.map +1 -0
  10. package/dist/{chunk-4MELBN55.js → chunk-W3QUAOGV.js} +4 -4
  11. package/dist/{chunk-5ASRBH5I.js → chunk-X3WAPQSV.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 +9 -9
  17. package/dist/index.cjs +116 -68
  18. package/dist/index.cjs.map +1 -1
  19. package/dist/index.js +9 -9
  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 +3 -3
  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 +6 -6
  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 +8 -8
  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 +6 -6
  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 +6 -6
  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-KH3RKPPO.js.map → chunk-2GZMA5OY.js.map} +0 -0
  59. /package/dist/{chunk-DZRBTNQR.js.map → chunk-3IASMZXX.js.map} +0 -0
  60. /package/dist/{chunk-2TXLSKGU.js.map → chunk-KMWLHINT.js.map} +0 -0
  61. /package/dist/{chunk-4MELBN55.js.map → chunk-W3QUAOGV.js.map} +0 -0
  62. /package/dist/{chunk-5ASRBH5I.js.map → chunk-X3WAPQSV.js.map} +0 -0
@@ -258,12 +258,6 @@ function getSystemPrompt() {
258
258
  }
259
259
 
260
260
  // tools/warp_grep/agent/parser.ts
261
- var LLMResponseParseError = class extends Error {
262
- constructor(message) {
263
- super(message);
264
- this.name = "LLMResponseParseError";
265
- }
266
- };
267
261
  var VALID_COMMANDS = ["analyse", "grep", "read", "finish"];
268
262
  function preprocessText(text) {
269
263
  let processed = text.replace(/<think>[\s\S]*?<\/think>/gi, "");
@@ -314,24 +308,23 @@ var LLMResponseParser = class {
314
308
  const lines = preprocessText(text);
315
309
  const commands = [];
316
310
  let finishAccumulator = null;
317
- lines.forEach((line, idx) => {
311
+ lines.forEach((line) => {
318
312
  if (!line || line.startsWith("#")) return;
319
- const ctx = { lineNumber: idx + 1, raw: line };
320
- const parts = this.splitLine(line, ctx);
313
+ const parts = this.splitLine(line);
321
314
  if (parts.length === 0) return;
322
315
  const cmd = parts[0];
323
316
  switch (cmd) {
324
317
  case "analyse":
325
- this.handleAnalyse(parts, ctx, commands);
318
+ this.handleAnalyse(parts, line, commands);
326
319
  break;
327
320
  case "grep":
328
- this.handleGrep(parts, ctx, commands);
321
+ this.handleGrep(parts, line, commands);
329
322
  break;
330
323
  case "read":
331
- this.handleRead(parts, ctx, commands);
324
+ this.handleRead(parts, line, commands);
332
325
  break;
333
326
  case "finish":
334
- finishAccumulator = this.handleFinish(parts, ctx, finishAccumulator);
327
+ finishAccumulator = this.handleFinish(parts, line, commands, finishAccumulator);
335
328
  break;
336
329
  default:
337
330
  break;
@@ -348,53 +341,68 @@ var LLMResponseParser = class {
348
341
  }
349
342
  return commands;
350
343
  }
351
- splitLine(line, ctx) {
352
- try {
353
- const parts = [];
354
- let current = "";
355
- let inSingle = false;
356
- for (let i = 0; i < line.length; i++) {
357
- const ch = line[i];
358
- if (ch === "'" && line[i - 1] !== "\\") {
359
- inSingle = !inSingle;
360
- current += ch;
361
- } else if (!inSingle && /\s/.test(ch)) {
362
- if (current) {
363
- parts.push(current);
364
- current = "";
365
- }
366
- } else {
367
- current += ch;
344
+ splitLine(line) {
345
+ const parts = [];
346
+ let current = "";
347
+ let inSingle = false;
348
+ for (let i = 0; i < line.length; i++) {
349
+ const ch = line[i];
350
+ if (ch === "'" && line[i - 1] !== "\\") {
351
+ inSingle = !inSingle;
352
+ current += ch;
353
+ } else if (!inSingle && /\s/.test(ch)) {
354
+ if (current) {
355
+ parts.push(current);
356
+ current = "";
368
357
  }
358
+ } else {
359
+ current += ch;
369
360
  }
370
- if (current) parts.push(current);
371
- return parts;
372
- } catch {
373
- throw new LLMResponseParseError(`Line ${ctx.lineNumber}: Unable to parse line.`);
374
361
  }
362
+ if (current) parts.push(current);
363
+ return parts;
364
+ }
365
+ /** Helper to create a _skip tool call with an error message */
366
+ skip(message) {
367
+ return { name: "_skip", arguments: { message } };
375
368
  }
376
- handleAnalyse(parts, ctx, commands) {
369
+ handleAnalyse(parts, rawLine, commands) {
377
370
  if (parts.length < 2) {
378
- throw new LLMResponseParseError(`Line ${ctx.lineNumber}: analyse requires <path>`);
371
+ commands.push(this.skip(
372
+ `[SKIPPED] Your command "${rawLine}" is missing a path. Correct format: analyse <path> [pattern]. Example: analyse src/`
373
+ ));
374
+ return;
379
375
  }
380
376
  const path4 = parts[1];
381
377
  const pattern = parts[2]?.replace(/^"|"$/g, "") ?? null;
382
378
  commands.push({ name: "analyse", arguments: { path: path4, pattern } });
383
379
  }
384
380
  // no glob tool in MCP
385
- handleGrep(parts, ctx, commands) {
381
+ handleGrep(parts, rawLine, commands) {
386
382
  if (parts.length < 3) {
387
- throw new LLMResponseParseError(`Line ${ctx.lineNumber}: grep requires '<pattern>' and <path>`);
383
+ commands.push(this.skip(
384
+ `[SKIPPED] Your command "${rawLine}" is missing arguments. Correct format: grep '<pattern>' <path>. Example: grep 'TODO' src/`
385
+ ));
386
+ return;
388
387
  }
389
- const pat = parts[1];
390
- if (!pat.startsWith("'") || !pat.endsWith("'")) {
391
- throw new LLMResponseParseError(`Line ${ctx.lineNumber}: grep pattern must be single-quoted`);
388
+ let pat = parts[1];
389
+ if (pat.startsWith("'") && pat.endsWith("'")) {
390
+ pat = pat.slice(1, -1);
392
391
  }
393
- commands.push({ name: "grep", arguments: { pattern: pat.slice(1, -1), path: parts[2] } });
392
+ if (!pat) {
393
+ commands.push(this.skip(
394
+ `[SKIPPED] Your command "${rawLine}" has an empty pattern. Provide a non-empty search pattern. Example: grep 'function' src/`
395
+ ));
396
+ return;
397
+ }
398
+ commands.push({ name: "grep", arguments: { pattern: pat, path: parts[2] } });
394
399
  }
395
- handleRead(parts, ctx, commands) {
400
+ handleRead(parts, rawLine, commands) {
396
401
  if (parts.length < 2) {
397
- throw new LLMResponseParseError(`Line ${ctx.lineNumber}: read requires <path> or <path>:<start-end>`);
402
+ commands.push(this.skip(
403
+ `[SKIPPED] Your command "${rawLine}" is missing a path. Correct format: read <path> or read <path>:<start>-<end>. Example: read src/index.ts:1-50`
404
+ ));
405
+ return;
398
406
  }
399
407
  const spec = parts[1];
400
408
  const rangeIdx = spec.indexOf(":");
@@ -402,31 +410,38 @@ var LLMResponseParser = class {
402
410
  commands.push({ name: "read", arguments: { path: spec } });
403
411
  return;
404
412
  }
405
- const path4 = spec.slice(0, rangeIdx);
413
+ const filePath = spec.slice(0, rangeIdx);
406
414
  const range = spec.slice(rangeIdx + 1);
407
415
  const [s, e] = range.split("-").map((v) => parseInt(v, 10));
408
416
  if (!Number.isFinite(s) || !Number.isFinite(e)) {
409
- throw new LLMResponseParseError(`Line ${ctx.lineNumber}: invalid read range '${range}'`);
417
+ commands.push({ name: "read", arguments: { path: filePath } });
418
+ return;
410
419
  }
411
- commands.push({ name: "read", arguments: { path: path4, start: s, end: e } });
420
+ commands.push({ name: "read", arguments: { path: filePath, start: s, end: e } });
412
421
  }
413
- handleFinish(parts, ctx, acc) {
422
+ handleFinish(parts, rawLine, commands, acc) {
414
423
  const map = acc ?? /* @__PURE__ */ new Map();
415
424
  const args = parts.slice(1);
416
425
  for (const token of args) {
417
- const [path4, rangesText] = token.split(":", 2);
418
- if (!path4 || !rangesText) {
419
- throw new LLMResponseParseError(`Line ${ctx.lineNumber}: invalid finish token '${token}'`);
426
+ const [filePath, rangesText] = token.split(":", 2);
427
+ if (!filePath || !rangesText) {
428
+ commands.push(this.skip(
429
+ `[SKIPPED] Invalid finish token "${token}". Correct format: finish <path>:<start>-<end>. Example: finish src/index.ts:1-50`
430
+ ));
431
+ continue;
420
432
  }
421
433
  const rangeSpecs = rangesText.split(",").filter(Boolean);
422
434
  for (const spec of rangeSpecs) {
423
435
  const [s, e] = spec.split("-").map((v) => parseInt(v, 10));
424
436
  if (!Number.isFinite(s) || !Number.isFinite(e) || e < s) {
425
- throw new LLMResponseParseError(`Line ${ctx.lineNumber}: invalid range '${spec}'`);
437
+ commands.push(this.skip(
438
+ `[SKIPPED] Invalid range "${spec}" in "${token}". Ranges must be <start>-<end> where start <= end. Example: 1-50`
439
+ ));
440
+ continue;
426
441
  }
427
- const arr = map.get(path4) ?? [];
442
+ const arr = map.get(filePath) ?? [];
428
443
  arr.push([s, e]);
429
- map.set(path4, arr);
444
+ map.set(filePath, arr);
430
445
  }
431
446
  }
432
447
  return map;
@@ -436,6 +451,10 @@ var LLMResponseParser = class {
436
451
  // tools/warp_grep/tools/read.ts
437
452
  async function toolRead(provider, args) {
438
453
  const res = await provider.read({ path: args.path, start: args.start, end: args.end });
454
+ if (res.error) {
455
+ return res.error;
456
+ }
457
+ if (!res.lines.length) return "(empty file)";
439
458
  return res.lines.join("\n");
440
459
  }
441
460
 
@@ -821,14 +840,7 @@ async function runWarpGrep(config) {
821
840
  });
822
841
  if (!assistantContent) break;
823
842
  messages.push({ role: "assistant", content: assistantContent });
824
- let toolCalls = [];
825
- try {
826
- toolCalls = parser.parse(assistantContent);
827
- } catch (e) {
828
- errors.push({ message: e instanceof Error ? e.message : String(e) });
829
- terminationReason = "terminated";
830
- break;
831
- }
843
+ const toolCalls = parser.parse(assistantContent);
832
844
  if (toolCalls.length === 0) {
833
845
  errors.push({ message: "No tool calls produced by the model." });
834
846
  terminationReason = "terminated";
@@ -838,7 +850,12 @@ async function runWarpGrep(config) {
838
850
  const grepCalls = toolCalls.filter((c) => c.name === "grep");
839
851
  const analyseCalls = toolCalls.filter((c) => c.name === "analyse");
840
852
  const readCalls = toolCalls.filter((c) => c.name === "read");
853
+ const skipCalls = toolCalls.filter((c) => c.name === "_skip");
841
854
  const formatted = [];
855
+ for (const c of skipCalls) {
856
+ const msg = c.arguments?.message || "Command skipped due to parsing error";
857
+ formatted.push(msg);
858
+ }
842
859
  const otherPromises = [];
843
860
  for (const c of analyseCalls) {
844
861
  const args = c.arguments ?? {};
@@ -864,6 +881,15 @@ async function runWarpGrep(config) {
864
881
  const args = c.arguments ?? {};
865
882
  try {
866
883
  const grepRes = await provider.grep({ pattern: args.pattern, path: args.path });
884
+ if (grepRes.error) {
885
+ errors.push({ message: grepRes.error });
886
+ terminationReason = "terminated";
887
+ return {
888
+ terminationReason: "terminated",
889
+ messages,
890
+ errors
891
+ };
892
+ }
867
893
  const rawOutput = Array.isArray(grepRes.lines) ? grepRes.lines.join("\n") : "";
868
894
  const newMatches = parseAndFilterGrepOutput(rawOutput, grepState);
869
895
  let formattedPayload = formatTurnGrepOutput(newMatches);
@@ -1075,10 +1101,22 @@ var LocalRipgrepProvider = class {
1075
1101
  ];
1076
1102
  const res = await runRipgrep(args, { cwd: this.repoRoot });
1077
1103
  if (res.exitCode === -1) {
1078
- throw new Error(res.stderr || "ripgrep (rg) execution failed.");
1104
+ return {
1105
+ lines: [],
1106
+ error: `[RIPGREP NOT AVAILABLE] ripgrep (rg) is required but failed to execute. Please install it:
1107
+ \u2022 macOS: brew install ripgrep
1108
+ \u2022 Ubuntu/Debian: apt install ripgrep
1109
+ \u2022 Windows: choco install ripgrep
1110
+ \u2022 Or visit: https://github.com/BurntSushi/ripgrep#installation
1111
+ Exit code: ${res.exitCode}${res.stderr ? `
1112
+ Details: ${res.stderr}` : ""}`
1113
+ };
1079
1114
  }
1080
1115
  if (res.exitCode !== 0 && res.exitCode !== 1) {
1081
- throw new Error(res.stderr || `ripgrep failed with code ${res.exitCode}`);
1116
+ return {
1117
+ lines: [],
1118
+ error: `[RIPGREP ERROR] grep failed with exit code ${res.exitCode}${res.stderr ? `: ${res.stderr}` : ""}`
1119
+ };
1082
1120
  }
1083
1121
  const lines = (res.stdout || "").trim().split(/\r?\n/).filter((l) => l.length > 0);
1084
1122
  return { lines };
@@ -1096,7 +1134,8 @@ var LocalRipgrepProvider = class {
1096
1134
  ];
1097
1135
  const res = await runRipgrep(args, { cwd: this.repoRoot });
1098
1136
  if (res.exitCode === -1) {
1099
- throw new Error(res.stderr || "ripgrep (rg) execution failed.");
1137
+ console.warn(`[warp_grep] ripgrep not available for glob: ${res.stderr || "execution failed"}`);
1138
+ return { files: [] };
1100
1139
  }
1101
1140
  const files = (res.stdout || "").trim().split(/\r?\n/).filter((l) => l.length > 0);
1102
1141
  return { files };
@@ -1105,13 +1144,22 @@ var LocalRipgrepProvider = class {
1105
1144
  const abs = resolveUnderRepo(this.repoRoot, params.path);
1106
1145
  const stat = await import_promises3.default.stat(abs).catch(() => null);
1107
1146
  if (!stat || !stat.isFile()) {
1108
- throw new Error(`Path is not a file: ${params.path}`);
1147
+ return {
1148
+ lines: [],
1149
+ 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.`
1150
+ };
1109
1151
  }
1110
1152
  if (isSymlink(abs)) {
1111
- throw new Error(`Refusing to read symlink: ${params.path}`);
1153
+ return {
1154
+ lines: [],
1155
+ error: `[SYMLINK] You tried to read "${params.path}" but this is a symlink. Try reading the actual file it points to instead.`
1156
+ };
1112
1157
  }
1113
1158
  if (!isTextualFile(abs)) {
1114
- throw new Error(`Non-text or too-large file: ${params.path}`);
1159
+ return {
1160
+ lines: [],
1161
+ 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.`
1162
+ };
1115
1163
  }
1116
1164
  const lines = await readAllLines(abs);
1117
1165
  const total = lines.length;