@probelabs/probe 0.6.0-rc309 → 0.6.0-rc311

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.
@@ -3179,6 +3179,8 @@ Follow these instructions carefully:
3179
3179
  7. When modifying files, choose the appropriate tool:
3180
3180
  - Use 'edit' for all code modifications:
3181
3181
  * PREFERRED: Use start_line (and optionally end_line) for line-targeted editing — this is the safest and most precise approach.${this.hashLines ? ' Use the line:hash references from extract/search output (e.g. "42:ab") for integrity verification.' : ''} Always use extract first to see line numbers${this.hashLines ? ' and hashes' : ''}, then edit by line reference.
3182
+ * In line-targeted mode, omitting position means replace/update the addressed lines. To insert new code near a line, you MUST set position="before" or position="after". Never express insertion as end_line < start_line.
3183
+ * To delete lines in line-targeted mode, target the exact start_line/end_line range and set new_string to the empty string "".
3182
3184
  * For editing inside large functions: first use extract with the symbol target (e.g. "file.js#myFunction") to see the function with line numbers${this.hashLines ? ' and hashes' : ''}, then use start_line/end_line to surgically edit specific lines within it.
3183
3185
  * For rewriting entire functions/classes/methods, use the symbol parameter instead (no exact text matching needed).
3184
3186
  * FALLBACK ONLY: Use old_string + new_string for simple single-line changes where the text is unique. Copy old_string verbatim from the file. Keep old_string as small as possible.
@@ -141,6 +141,8 @@ Bash is fine for: formatters (gofmt, prettier, black), build/test/lint commands,
141
141
  - Never expose secrets, API keys, or credentials in generated code. Never log sensitive information.
142
142
  - Do not surprise the user with unrequested changes. Do what was asked, including reasonable follow-up actions, but do not refactor surrounding code or add features that were not requested.
143
143
  - When editing files, keep edits focused and minimal. For changes spanning more than a few lines, prefer line-targeted editing (start_line/end_line) over text replacement (old_string) — it constrains scope and prevents accidental removal of adjacent content. Never include unrelated sections in an edit operation.
144
+ - In line-targeted mode, omitting position means replace/update the addressed lines. To insert code near an existing line, you MUST use position="before" or position="after". Never express insertion as end_line < start_line.
145
+ - To remove lines with line-targeted mode, target the exact start_line/end_line range and set new_string to the empty string "".
144
146
  - After every significant change, verify the project still builds and passes linting. Do not wait until the end to discover breakage.
145
147
 
146
148
  # Writing Tests
@@ -186,6 +186,13 @@ function buildLineEditResponse(file_path, startLine, endLine, newLineCount, upda
186
186
  return msg;
187
187
  }
188
188
 
189
+ const lineTargetedModeGuidance = `Line-targeted mode has three explicit behaviors:
190
+ - Replace/update lines: provide start_line and optionally end_line, and omit position
191
+ - Insert near a line: provide start_line and set position to "before" or "after"
192
+ - Delete lines: provide start_line/end_line for the exact range and set new_string to empty string ""
193
+
194
+ Inverted ranges (end_line < start_line) are always invalid and are never treated as insertion.`;
195
+
189
196
  /**
190
197
  * Handle line-targeted editing (replace, insert, delete by line numbers)
191
198
  * @param {Object} params - Parameters
@@ -211,12 +218,15 @@ async function handleLineEdit({ resolvedPath, file_path, start_line, end_line, n
211
218
  const endLine = endRef ? endRef.line : startLine;
212
219
 
213
220
  if (endLine < startLine) {
214
- return `Error editing file: end_line (${endLine}) must be >= start_line (${startLine}).`;
221
+ const insertionHint = endLine === startLine - 1
222
+ ? ` This looks like an insertion between lines ${endLine} and ${startLine}. To insert there without replacing existing code, use start_line="${startLine}" with position="before" or start_line="${endLine}" with position="after".`
223
+ : ' To insert new code, choose a single anchor line in start_line and set position to "before" or "after" instead of using an inverted range.';
224
+ return `Error editing file: end_line (${endLine}) must be >= start_line (${startLine}). Omitting position means replace/update the addressed lines, not insert.${insertionHint} To delete lines, use new_string as the empty string "" with a valid non-inverted range.`;
215
225
  }
216
226
 
217
227
  // Validate position if provided
218
228
  if (position !== undefined && position !== null && position !== 'before' && position !== 'after') {
219
- return 'Error editing file: Invalid position - must be "before" or "after". Use position="before" to insert before the line, or position="after" to insert after it.';
229
+ return 'Error editing file: Invalid position - must be "before" or "after". Use position="before" to insert before start_line, position="after" to insert after start_line, or omit position to replace/update the addressed lines.';
220
230
  }
221
231
 
222
232
  // Read the file
@@ -304,23 +314,25 @@ export const editTool = (options = {}) => {
304
314
 
305
315
  return tool({
306
316
  name: 'edit',
307
- description: `Edit files using text replacement, AST-aware symbol operations, or line-targeted editing.
317
+ description: `Edit files using text replacement, AST-aware symbol operations, or line-targeted line replacement/insertion/deletion.
308
318
 
309
319
  Modes:
310
320
  1. Text edit: Provide old_string + new_string to find and replace text (with fuzzy matching fallback)
311
321
  2. Symbol replace: Provide symbol + new_string to replace an entire function/class/method by name
312
322
  3. Symbol insert: Provide symbol + new_string + position to insert code before/after a symbol
313
- 4. Line-targeted edit: Provide start_line + new_string to edit by line number (from extract/search output)
323
+ 4. Line-targeted edit: Provide start_line + new_string to replace/update, insert, or delete lines by line number (from extract/search output)
324
+
325
+ ${lineTargetedModeGuidance}
314
326
 
315
327
  Parameters:
316
328
  - file_path: Path to the file to edit (absolute or relative)
317
- - new_string: Replacement text or new code content
329
+ - new_string: Replacement text or new code content. Use empty string "" to delete the targeted line range.
318
330
  - old_string: (optional) Text to find and replace. If omitted, symbol or start_line must be provided.
319
331
  - replace_all: (optional) Replace all occurrences (text mode only)
320
332
  - symbol: (optional) Symbol name for AST-aware editing (e.g. "myFunction", "MyClass.myMethod")
321
- - position: (optional) "before" or "after" — insert code near a symbol or line instead of replacing it
322
- - start_line: (optional) Line reference (e.g. "42" or "42:ab") for line-targeted editing
323
- - end_line: (optional) End of line range, inclusive (e.g. "55" or "55:cd")`,
333
+ - position: (optional) "before" or "after" — insert code near a symbol or line instead of replacing it. Omit position to replace/update.
334
+ - start_line: (optional) Line reference (e.g. "42" or "42:ab") for line-targeted editing. With position, this is the insertion anchor. Without position, this is the first line to replace/update/delete.
335
+ - end_line: (optional) End of line range, inclusive (e.g. "55" or "55:cd"). Must be >= start_line. Omit for single-line updates. Do not use inverted ranges for insertion.`,
324
336
 
325
337
  inputSchema: {
326
338
  type: 'object',
@@ -335,7 +347,7 @@ Parameters:
335
347
  },
336
348
  new_string: {
337
349
  type: 'string',
338
- description: 'Replacement text or new code content'
350
+ description: 'Replacement text or new code content. Use empty string "" to delete the targeted line range.'
339
351
  },
340
352
  replace_all: {
341
353
  type: 'boolean',
@@ -349,15 +361,15 @@ Parameters:
349
361
  position: {
350
362
  type: 'string',
351
363
  enum: ['before', 'after'],
352
- description: 'Insert before/after symbol or line (requires symbol or start_line, omit to replace)'
364
+ description: 'Insert before/after the target symbol or start_line anchor. Omit position to replace/update the addressed symbol or line range.'
353
365
  },
354
366
  start_line: {
355
367
  type: 'string',
356
- description: 'Line reference for line-targeted editing (e.g. "42" or "42:ab" with hash)'
368
+ description: 'Line reference for line-targeted editing (e.g. "42" or "42:ab" with hash). With position, this is the insertion anchor. Without position, this is the first line to replace/update/delete.'
357
369
  },
358
370
  end_line: {
359
371
  type: 'string',
360
- description: 'End of line range, inclusive (e.g. "55" or "55:cd"). Defaults to start_line.'
372
+ description: 'Inclusive end of the line range to replace/delete (e.g. "55" or "55:cd"). Must be >= start_line. Defaults to start_line.'
361
373
  }
362
374
  },
363
375
  required: ['file_path', 'new_string']
@@ -702,7 +714,7 @@ export const editSchema = {
702
714
  },
703
715
  new_string: {
704
716
  type: 'string',
705
- description: 'Replacement text or new code content'
717
+ description: 'Replacement text or new code content. Use empty string "" to delete the targeted line range.'
706
718
  },
707
719
  replace_all: {
708
720
  type: 'boolean',
@@ -715,15 +727,15 @@ export const editSchema = {
715
727
  position: {
716
728
  type: 'string',
717
729
  enum: ['before', 'after'],
718
- description: 'Insert before/after symbol or line (requires symbol or start_line, omit to replace)'
730
+ description: 'Insert before/after the target symbol or start_line anchor. Omit position to replace/update the addressed symbol or line range.'
719
731
  },
720
732
  start_line: {
721
733
  type: 'string',
722
- description: 'Line reference for line-targeted editing (e.g. "42" or "42:ab" with hash)'
734
+ description: 'Line reference for line-targeted editing (e.g. "42" or "42:ab" with hash). With position, this is the insertion anchor. Without position, this is the first line to replace/update/delete.'
723
735
  },
724
736
  end_line: {
725
737
  type: 'string',
726
- description: 'End of line range, inclusive (e.g. "55" or "55:cd"). Defaults to start_line.'
738
+ description: 'Inclusive end of the line range to replace/delete (e.g. "55" or "55:cd"). Must be >= start_line. Defaults to start_line.'
727
739
  }
728
740
  },
729
741
  required: ['file_path', 'new_string']
@@ -760,7 +772,7 @@ export const multiEditSchema = {
760
772
  };
761
773
 
762
774
  // Tool descriptions for XML definitions
763
- export const editDescription = 'Edit files using text replacement, AST-aware symbol operations, or line-targeted editing. Supports fuzzy matching for text edits and optional hash-based integrity verification for line edits.';
775
+ export const editDescription = 'Edit files using text replacement, AST-aware symbol operations, or line-targeted replacement/insertion/deletion. Supports fuzzy matching for text edits and optional hash-based integrity verification for line edits.';
764
776
  export const createDescription = 'Create new files with specified content. Will create parent directories if needed.';
765
777
  export const multiEditDescription = 'Apply multiple file edits in a single tool call. Accepts a JSON array of edit operations, each supporting the same modes as the edit tool.';
766
778
 
@@ -779,15 +791,21 @@ Four editing modes — choose based on the scope of your change:
779
791
 
780
792
  4. **Line-targeted edit** (start_line + new_string): For precise edits using line numbers from extract/search output. Use start_line with a line number (e.g. "42") or line:hash (e.g. "42:ab") for integrity verification. Add end_line for multi-line ranges. Use position="before" or "after" to insert instead of replace.
781
793
 
794
+ How line-targeted mode behaves:
795
+ - Replace/update lines: provide start_line and optionally end_line, and omit position
796
+ - Insert near a line: provide start_line and set position to "before" or "after"
797
+ - Delete lines: provide start_line/end_line for the exact range and set new_string to empty string ""
798
+ - Inverted ranges are invalid: end_line must be >= start_line and is never treated as insertion
799
+
782
800
  Parameters:
783
801
  - file_path: (required) Path to the file to edit
784
- - new_string: (required) Replacement text or new code content
802
+ - new_string: (required) Replacement text or new code content. Use empty string "" to delete the targeted line range.
785
803
  - old_string: (optional) Text to find and replace — copy verbatim from the file, do not paraphrase or reformat
786
804
  - replace_all: (optional, default: false) Replace all occurrences of old_string (text mode only)
787
805
  - symbol: (optional) Name of a code symbol (e.g. "myFunction", "MyClass.myMethod") — must match a function, class, or method definition
788
- - position: (optional) "before" or "after" — insert new_string near the symbol or line instead of replacing it
789
- - start_line: (optional) Line reference for line-targeted editing (e.g. "42" or "42:ab")
790
- - end_line: (optional) End of line range, inclusive (e.g. "55" or "55:cd"). Defaults to start_line.
806
+ - position: (optional) "before" or "after" — insert new_string near the symbol or line instead of replacing it. Omit position to replace/update.
807
+ - start_line: (optional) Line reference for line-targeted editing (e.g. "42" or "42:ab"). With position, this is the insertion anchor. Without position, this is the first line to replace/update/delete.
808
+ - end_line: (optional) End of line range, inclusive (e.g. "55" or "55:cd"). Defaults to start_line. Must be >= start_line. Use it for replace/update/delete ranges, not insertion.
791
809
 
792
810
  Mode selection rules (priority order):
793
811
  - If symbol is provided, symbol mode is used (old_string and start_line are ignored)
@@ -799,12 +817,15 @@ When to use each mode:
799
817
  - Small edits (a line or a few lines): use text mode with old_string
800
818
  - Replacing entire functions/classes/methods: use symbol mode — no exact text matching needed
801
819
  - Editing specific lines from extract/search output: use line-targeted mode with start_line
820
+ - Adding a new block near an existing line: use line-targeted mode with start_line plus position="before" or position="after"
821
+ - Removing lines entirely: use line-targeted mode with start_line/end_line and new_string=""
802
822
  - Editing inside large functions without rewriting them entirely: first use extract with the symbol target (e.g. "file.js#myFunction") to see the function with line numbers, then use start_line/end_line to edit specific lines within it
803
823
 
804
824
  Error handling:
805
825
  - If an edit fails, read the error message carefully — it contains specific instructions for how to fix the call and retry
806
826
  - Common fixes: use 'search'/'extract' to get exact file content, add more context to old_string, switch between text and symbol modes
807
827
  - Line-targeted hash mismatch: the file changed since last read; the error provides updated line:hash references
828
+ - Inverted line ranges are invalid; the error explains how to express insertion with position="before"/"after"
808
829
 
809
830
  Examples:
810
831
 
@@ -858,6 +879,22 @@ Line-targeted edit (replace a range of lines):
858
879
  return processItems(order.items);</new_string>
859
880
  </edit>
860
881
 
882
+ Line-targeted edit (insert before a line without replacing it):
883
+ <edit>
884
+ <file_path>src/main.js</file_path>
885
+ <start_line>42</start_line>
886
+ <position>before</position>
887
+ <new_string> logger.debug("starting process");</new_string>
888
+ </edit>
889
+
890
+ Line-targeted edit (delete a range of lines):
891
+ <edit>
892
+ <file_path>src/main.js</file_path>
893
+ <start_line>42</start_line>
894
+ <end_line>45</end_line>
895
+ <new_string></new_string>
896
+ </edit>
897
+
861
898
  Line-targeted edit with hash verification:
862
899
  <edit>
863
900
  <file_path>src/main.js</file_path>
@@ -31560,10 +31560,11 @@ async function handleLineEdit({ resolvedPath, file_path, start_line, end_line, n
31560
31560
  const startLine = startRef.line;
31561
31561
  const endLine = endRef ? endRef.line : startLine;
31562
31562
  if (endLine < startLine) {
31563
- return `Error editing file: end_line (${endLine}) must be >= start_line (${startLine}).`;
31563
+ const insertionHint = endLine === startLine - 1 ? ` This looks like an insertion between lines ${endLine} and ${startLine}. To insert there without replacing existing code, use start_line="${startLine}" with position="before" or start_line="${endLine}" with position="after".` : ' To insert new code, choose a single anchor line in start_line and set position to "before" or "after" instead of using an inverted range.';
31564
+ return `Error editing file: end_line (${endLine}) must be >= start_line (${startLine}). Omitting position means replace/update the addressed lines, not insert.${insertionHint} To delete lines, use new_string as the empty string "" with a valid non-inverted range.`;
31564
31565
  }
31565
31566
  if (position !== void 0 && position !== null && position !== "before" && position !== "after") {
31566
- return 'Error editing file: Invalid position - must be "before" or "after". Use position="before" to insert before the line, or position="after" to insert after it.';
31567
+ return 'Error editing file: Invalid position - must be "before" or "after". Use position="before" to insert before start_line, position="after" to insert after start_line, or omit position to replace/update the addressed lines.';
31567
31568
  }
31568
31569
  const content = await import_fs7.promises.readFile(resolvedPath, "utf-8");
31569
31570
  const fileLines = content.split("\n");
@@ -31620,7 +31621,7 @@ async function handleLineEdit({ resolvedPath, file_path, start_line, end_line, n
31620
31621
  return buildLineEditResponse(file_path, startLine, endLine, newLines.length, fileLines, startLine - 1, action, modifications);
31621
31622
  }
31622
31623
  }
31623
- var import_ai3, import_fs7, import_path9, import_fs8, editTool, createTool, multiEditTool, editSchema, createSchema, multiEditSchema, editDescription, createDescription, multiEditDescription, editToolDefinition, createToolDefinition, multiEditToolDefinition;
31624
+ var import_ai3, import_fs7, import_path9, import_fs8, lineTargetedModeGuidance, editTool, createTool, multiEditTool, editSchema, createSchema, multiEditSchema, editDescription, createDescription, multiEditDescription, editToolDefinition, createToolDefinition, multiEditToolDefinition;
31624
31625
  var init_edit = __esm({
31625
31626
  "src/tools/edit.js"() {
31626
31627
  "use strict";
@@ -31633,27 +31634,35 @@ var init_edit = __esm({
31633
31634
  init_symbolEdit();
31634
31635
  init_hashline();
31635
31636
  init_lineEditHeuristics();
31637
+ lineTargetedModeGuidance = `Line-targeted mode has three explicit behaviors:
31638
+ - Replace/update lines: provide start_line and optionally end_line, and omit position
31639
+ - Insert near a line: provide start_line and set position to "before" or "after"
31640
+ - Delete lines: provide start_line/end_line for the exact range and set new_string to empty string ""
31641
+
31642
+ Inverted ranges (end_line < start_line) are always invalid and are never treated as insertion.`;
31636
31643
  editTool = (options = {}) => {
31637
31644
  const { debug, allowedFolders, cwd, workspaceRoot } = parseFileToolOptions(options);
31638
31645
  return (0, import_ai3.tool)({
31639
31646
  name: "edit",
31640
- description: `Edit files using text replacement, AST-aware symbol operations, or line-targeted editing.
31647
+ description: `Edit files using text replacement, AST-aware symbol operations, or line-targeted line replacement/insertion/deletion.
31641
31648
 
31642
31649
  Modes:
31643
31650
  1. Text edit: Provide old_string + new_string to find and replace text (with fuzzy matching fallback)
31644
31651
  2. Symbol replace: Provide symbol + new_string to replace an entire function/class/method by name
31645
31652
  3. Symbol insert: Provide symbol + new_string + position to insert code before/after a symbol
31646
- 4. Line-targeted edit: Provide start_line + new_string to edit by line number (from extract/search output)
31653
+ 4. Line-targeted edit: Provide start_line + new_string to replace/update, insert, or delete lines by line number (from extract/search output)
31654
+
31655
+ ${lineTargetedModeGuidance}
31647
31656
 
31648
31657
  Parameters:
31649
31658
  - file_path: Path to the file to edit (absolute or relative)
31650
- - new_string: Replacement text or new code content
31659
+ - new_string: Replacement text or new code content. Use empty string "" to delete the targeted line range.
31651
31660
  - old_string: (optional) Text to find and replace. If omitted, symbol or start_line must be provided.
31652
31661
  - replace_all: (optional) Replace all occurrences (text mode only)
31653
31662
  - symbol: (optional) Symbol name for AST-aware editing (e.g. "myFunction", "MyClass.myMethod")
31654
- - position: (optional) "before" or "after" \u2014 insert code near a symbol or line instead of replacing it
31655
- - start_line: (optional) Line reference (e.g. "42" or "42:ab") for line-targeted editing
31656
- - end_line: (optional) End of line range, inclusive (e.g. "55" or "55:cd")`,
31663
+ - position: (optional) "before" or "after" \u2014 insert code near a symbol or line instead of replacing it. Omit position to replace/update.
31664
+ - start_line: (optional) Line reference (e.g. "42" or "42:ab") for line-targeted editing. With position, this is the insertion anchor. Without position, this is the first line to replace/update/delete.
31665
+ - end_line: (optional) End of line range, inclusive (e.g. "55" or "55:cd"). Must be >= start_line. Omit for single-line updates. Do not use inverted ranges for insertion.`,
31657
31666
  inputSchema: {
31658
31667
  type: "object",
31659
31668
  properties: {
@@ -31667,7 +31676,7 @@ Parameters:
31667
31676
  },
31668
31677
  new_string: {
31669
31678
  type: "string",
31670
- description: "Replacement text or new code content"
31679
+ description: 'Replacement text or new code content. Use empty string "" to delete the targeted line range.'
31671
31680
  },
31672
31681
  replace_all: {
31673
31682
  type: "boolean",
@@ -31681,15 +31690,15 @@ Parameters:
31681
31690
  position: {
31682
31691
  type: "string",
31683
31692
  enum: ["before", "after"],
31684
- description: "Insert before/after symbol or line (requires symbol or start_line, omit to replace)"
31693
+ description: "Insert before/after the target symbol or start_line anchor. Omit position to replace/update the addressed symbol or line range."
31685
31694
  },
31686
31695
  start_line: {
31687
31696
  type: "string",
31688
- description: 'Line reference for line-targeted editing (e.g. "42" or "42:ab" with hash)'
31697
+ description: 'Line reference for line-targeted editing (e.g. "42" or "42:ab" with hash). With position, this is the insertion anchor. Without position, this is the first line to replace/update/delete.'
31689
31698
  },
31690
31699
  end_line: {
31691
31700
  type: "string",
31692
- description: 'End of line range, inclusive (e.g. "55" or "55:cd"). Defaults to start_line.'
31701
+ description: 'Inclusive end of the line range to replace/delete (e.g. "55" or "55:cd"). Must be >= start_line. Defaults to start_line.'
31693
31702
  }
31694
31703
  },
31695
31704
  required: ["file_path", "new_string"]
@@ -31940,7 +31949,7 @@ Important:
31940
31949
  },
31941
31950
  new_string: {
31942
31951
  type: "string",
31943
- description: "Replacement text or new code content"
31952
+ description: 'Replacement text or new code content. Use empty string "" to delete the targeted line range.'
31944
31953
  },
31945
31954
  replace_all: {
31946
31955
  type: "boolean",
@@ -31953,15 +31962,15 @@ Important:
31953
31962
  position: {
31954
31963
  type: "string",
31955
31964
  enum: ["before", "after"],
31956
- description: "Insert before/after symbol or line (requires symbol or start_line, omit to replace)"
31965
+ description: "Insert before/after the target symbol or start_line anchor. Omit position to replace/update the addressed symbol or line range."
31957
31966
  },
31958
31967
  start_line: {
31959
31968
  type: "string",
31960
- description: 'Line reference for line-targeted editing (e.g. "42" or "42:ab" with hash)'
31969
+ description: 'Line reference for line-targeted editing (e.g. "42" or "42:ab" with hash). With position, this is the insertion anchor. Without position, this is the first line to replace/update/delete.'
31961
31970
  },
31962
31971
  end_line: {
31963
31972
  type: "string",
31964
- description: 'End of line range, inclusive (e.g. "55" or "55:cd"). Defaults to start_line.'
31973
+ description: 'Inclusive end of the line range to replace/delete (e.g. "55" or "55:cd"). Must be >= start_line. Defaults to start_line.'
31965
31974
  }
31966
31975
  },
31967
31976
  required: ["file_path", "new_string"]
@@ -31994,7 +32003,7 @@ Important:
31994
32003
  },
31995
32004
  required: ["edits"]
31996
32005
  };
31997
- editDescription = "Edit files using text replacement, AST-aware symbol operations, or line-targeted editing. Supports fuzzy matching for text edits and optional hash-based integrity verification for line edits.";
32006
+ editDescription = "Edit files using text replacement, AST-aware symbol operations, or line-targeted replacement/insertion/deletion. Supports fuzzy matching for text edits and optional hash-based integrity verification for line edits.";
31998
32007
  createDescription = "Create new files with specified content. Will create parent directories if needed.";
31999
32008
  multiEditDescription = "Apply multiple file edits in a single tool call. Accepts a JSON array of edit operations, each supporting the same modes as the edit tool.";
32000
32009
  editToolDefinition = `
@@ -32011,15 +32020,21 @@ Four editing modes \u2014 choose based on the scope of your change:
32011
32020
 
32012
32021
  4. **Line-targeted edit** (start_line + new_string): For precise edits using line numbers from extract/search output. Use start_line with a line number (e.g. "42") or line:hash (e.g. "42:ab") for integrity verification. Add end_line for multi-line ranges. Use position="before" or "after" to insert instead of replace.
32013
32022
 
32023
+ How line-targeted mode behaves:
32024
+ - Replace/update lines: provide start_line and optionally end_line, and omit position
32025
+ - Insert near a line: provide start_line and set position to "before" or "after"
32026
+ - Delete lines: provide start_line/end_line for the exact range and set new_string to empty string ""
32027
+ - Inverted ranges are invalid: end_line must be >= start_line and is never treated as insertion
32028
+
32014
32029
  Parameters:
32015
32030
  - file_path: (required) Path to the file to edit
32016
- - new_string: (required) Replacement text or new code content
32031
+ - new_string: (required) Replacement text or new code content. Use empty string "" to delete the targeted line range.
32017
32032
  - old_string: (optional) Text to find and replace \u2014 copy verbatim from the file, do not paraphrase or reformat
32018
32033
  - replace_all: (optional, default: false) Replace all occurrences of old_string (text mode only)
32019
32034
  - symbol: (optional) Name of a code symbol (e.g. "myFunction", "MyClass.myMethod") \u2014 must match a function, class, or method definition
32020
- - position: (optional) "before" or "after" \u2014 insert new_string near the symbol or line instead of replacing it
32021
- - start_line: (optional) Line reference for line-targeted editing (e.g. "42" or "42:ab")
32022
- - end_line: (optional) End of line range, inclusive (e.g. "55" or "55:cd"). Defaults to start_line.
32035
+ - position: (optional) "before" or "after" \u2014 insert new_string near the symbol or line instead of replacing it. Omit position to replace/update.
32036
+ - start_line: (optional) Line reference for line-targeted editing (e.g. "42" or "42:ab"). With position, this is the insertion anchor. Without position, this is the first line to replace/update/delete.
32037
+ - end_line: (optional) End of line range, inclusive (e.g. "55" or "55:cd"). Defaults to start_line. Must be >= start_line. Use it for replace/update/delete ranges, not insertion.
32023
32038
 
32024
32039
  Mode selection rules (priority order):
32025
32040
  - If symbol is provided, symbol mode is used (old_string and start_line are ignored)
@@ -32031,12 +32046,15 @@ When to use each mode:
32031
32046
  - Small edits (a line or a few lines): use text mode with old_string
32032
32047
  - Replacing entire functions/classes/methods: use symbol mode \u2014 no exact text matching needed
32033
32048
  - Editing specific lines from extract/search output: use line-targeted mode with start_line
32049
+ - Adding a new block near an existing line: use line-targeted mode with start_line plus position="before" or position="after"
32050
+ - Removing lines entirely: use line-targeted mode with start_line/end_line and new_string=""
32034
32051
  - Editing inside large functions without rewriting them entirely: first use extract with the symbol target (e.g. "file.js#myFunction") to see the function with line numbers, then use start_line/end_line to edit specific lines within it
32035
32052
 
32036
32053
  Error handling:
32037
32054
  - If an edit fails, read the error message carefully \u2014 it contains specific instructions for how to fix the call and retry
32038
32055
  - Common fixes: use 'search'/'extract' to get exact file content, add more context to old_string, switch between text and symbol modes
32039
32056
  - Line-targeted hash mismatch: the file changed since last read; the error provides updated line:hash references
32057
+ - Inverted line ranges are invalid; the error explains how to express insertion with position="before"/"after"
32040
32058
 
32041
32059
  Examples:
32042
32060
 
@@ -32090,6 +32108,22 @@ Line-targeted edit (replace a range of lines):
32090
32108
  return processItems(order.items);</new_string>
32091
32109
  </edit>
32092
32110
 
32111
+ Line-targeted edit (insert before a line without replacing it):
32112
+ <edit>
32113
+ <file_path>src/main.js</file_path>
32114
+ <start_line>42</start_line>
32115
+ <position>before</position>
32116
+ <new_string> logger.debug("starting process");</new_string>
32117
+ </edit>
32118
+
32119
+ Line-targeted edit (delete a range of lines):
32120
+ <edit>
32121
+ <file_path>src/main.js</file_path>
32122
+ <start_line>42</start_line>
32123
+ <end_line>45</end_line>
32124
+ <new_string></new_string>
32125
+ </edit>
32126
+
32093
32127
  Line-targeted edit with hash verification:
32094
32128
  <edit>
32095
32129
  <file_path>src/main.js</file_path>
@@ -89942,6 +89976,8 @@ Bash is fine for: formatters (gofmt, prettier, black), build/test/lint commands,
89942
89976
  - Never expose secrets, API keys, or credentials in generated code. Never log sensitive information.
89943
89977
  - Do not surprise the user with unrequested changes. Do what was asked, including reasonable follow-up actions, but do not refactor surrounding code or add features that were not requested.
89944
89978
  - When editing files, keep edits focused and minimal. For changes spanning more than a few lines, prefer line-targeted editing (start_line/end_line) over text replacement (old_string) \u2014 it constrains scope and prevents accidental removal of adjacent content. Never include unrelated sections in an edit operation.
89979
+ - In line-targeted mode, omitting position means replace/update the addressed lines. To insert code near an existing line, you MUST use position="before" or position="after". Never express insertion as end_line < start_line.
89980
+ - To remove lines with line-targeted mode, target the exact start_line/end_line range and set new_string to the empty string "".
89945
89981
  - After every significant change, verify the project still builds and passes linting. Do not wait until the end to discover breakage.
89946
89982
 
89947
89983
  # Writing Tests
@@ -103538,6 +103574,8 @@ Follow these instructions carefully:
103538
103574
  7. When modifying files, choose the appropriate tool:
103539
103575
  - Use 'edit' for all code modifications:
103540
103576
  * PREFERRED: Use start_line (and optionally end_line) for line-targeted editing \u2014 this is the safest and most precise approach.${this.hashLines ? ' Use the line:hash references from extract/search output (e.g. "42:ab") for integrity verification.' : ""} Always use extract first to see line numbers${this.hashLines ? " and hashes" : ""}, then edit by line reference.
103577
+ * In line-targeted mode, omitting position means replace/update the addressed lines. To insert new code near a line, you MUST set position="before" or position="after". Never express insertion as end_line < start_line.
103578
+ * To delete lines in line-targeted mode, target the exact start_line/end_line range and set new_string to the empty string "".
103541
103579
  * For editing inside large functions: first use extract with the symbol target (e.g. "file.js#myFunction") to see the function with line numbers${this.hashLines ? " and hashes" : ""}, then use start_line/end_line to surgically edit specific lines within it.
103542
103580
  * For rewriting entire functions/classes/methods, use the symbol parameter instead (no exact text matching needed).
103543
103581
  * FALLBACK ONLY: Use old_string + new_string for simple single-line changes where the text is unique. Copy old_string verbatim from the file. Keep old_string as small as possible.
package/cjs/index.cjs CHANGED
@@ -74139,6 +74139,8 @@ Bash is fine for: formatters (gofmt, prettier, black), build/test/lint commands,
74139
74139
  - Never expose secrets, API keys, or credentials in generated code. Never log sensitive information.
74140
74140
  - Do not surprise the user with unrequested changes. Do what was asked, including reasonable follow-up actions, but do not refactor surrounding code or add features that were not requested.
74141
74141
  - When editing files, keep edits focused and minimal. For changes spanning more than a few lines, prefer line-targeted editing (start_line/end_line) over text replacement (old_string) \u2014 it constrains scope and prevents accidental removal of adjacent content. Never include unrelated sections in an edit operation.
74142
+ - In line-targeted mode, omitting position means replace/update the addressed lines. To insert code near an existing line, you MUST use position="before" or position="after". Never express insertion as end_line < start_line.
74143
+ - To remove lines with line-targeted mode, target the exact start_line/end_line range and set new_string to the empty string "".
74142
74144
  - After every significant change, verify the project still builds and passes linting. Do not wait until the end to discover breakage.
74143
74145
 
74144
74146
  # Writing Tests
@@ -100082,6 +100084,8 @@ Follow these instructions carefully:
100082
100084
  7. When modifying files, choose the appropriate tool:
100083
100085
  - Use 'edit' for all code modifications:
100084
100086
  * PREFERRED: Use start_line (and optionally end_line) for line-targeted editing \u2014 this is the safest and most precise approach.${this.hashLines ? ' Use the line:hash references from extract/search output (e.g. "42:ab") for integrity verification.' : ""} Always use extract first to see line numbers${this.hashLines ? " and hashes" : ""}, then edit by line reference.
100087
+ * In line-targeted mode, omitting position means replace/update the addressed lines. To insert new code near a line, you MUST set position="before" or position="after". Never express insertion as end_line < start_line.
100088
+ * To delete lines in line-targeted mode, target the exact start_line/end_line range and set new_string to the empty string "".
100085
100089
  * For editing inside large functions: first use extract with the symbol target (e.g. "file.js#myFunction") to see the function with line numbers${this.hashLines ? " and hashes" : ""}, then use start_line/end_line to surgically edit specific lines within it.
100086
100090
  * For rewriting entire functions/classes/methods, use the symbol parameter instead (no exact text matching needed).
100087
100091
  * FALLBACK ONLY: Use old_string + new_string for simple single-line changes where the text is unique. Copy old_string verbatim from the file. Keep old_string as small as possible.
@@ -104614,10 +104618,11 @@ async function handleLineEdit({ resolvedPath, file_path, start_line, end_line, n
104614
104618
  const startLine = startRef.line;
104615
104619
  const endLine = endRef ? endRef.line : startLine;
104616
104620
  if (endLine < startLine) {
104617
- return `Error editing file: end_line (${endLine}) must be >= start_line (${startLine}).`;
104621
+ const insertionHint = endLine === startLine - 1 ? ` This looks like an insertion between lines ${endLine} and ${startLine}. To insert there without replacing existing code, use start_line="${startLine}" with position="before" or start_line="${endLine}" with position="after".` : ' To insert new code, choose a single anchor line in start_line and set position to "before" or "after" instead of using an inverted range.';
104622
+ return `Error editing file: end_line (${endLine}) must be >= start_line (${startLine}). Omitting position means replace/update the addressed lines, not insert.${insertionHint} To delete lines, use new_string as the empty string "" with a valid non-inverted range.`;
104618
104623
  }
104619
104624
  if (position !== void 0 && position !== null && position !== "before" && position !== "after") {
104620
- return 'Error editing file: Invalid position - must be "before" or "after". Use position="before" to insert before the line, or position="after" to insert after it.';
104625
+ return 'Error editing file: Invalid position - must be "before" or "after". Use position="before" to insert before start_line, position="after" to insert after start_line, or omit position to replace/update the addressed lines.';
104621
104626
  }
104622
104627
  const content = await import_fs13.promises.readFile(resolvedPath, "utf-8");
104623
104628
  const fileLines = content.split("\n");
@@ -104674,7 +104679,7 @@ async function handleLineEdit({ resolvedPath, file_path, start_line, end_line, n
104674
104679
  return buildLineEditResponse(file_path, startLine, endLine, newLines.length, fileLines, startLine - 1, action, modifications);
104675
104680
  }
104676
104681
  }
104677
- var import_ai6, import_fs13, import_path17, import_fs14, editTool, createTool, multiEditTool, editSchema, createSchema, multiEditSchema, editDescription, createDescription, multiEditDescription, editToolDefinition, createToolDefinition, multiEditToolDefinition;
104682
+ var import_ai6, import_fs13, import_path17, import_fs14, lineTargetedModeGuidance, editTool, createTool, multiEditTool, editSchema, createSchema, multiEditSchema, editDescription, createDescription, multiEditDescription, editToolDefinition, createToolDefinition, multiEditToolDefinition;
104678
104683
  var init_edit = __esm({
104679
104684
  "src/tools/edit.js"() {
104680
104685
  "use strict";
@@ -104687,27 +104692,35 @@ var init_edit = __esm({
104687
104692
  init_symbolEdit();
104688
104693
  init_hashline();
104689
104694
  init_lineEditHeuristics();
104695
+ lineTargetedModeGuidance = `Line-targeted mode has three explicit behaviors:
104696
+ - Replace/update lines: provide start_line and optionally end_line, and omit position
104697
+ - Insert near a line: provide start_line and set position to "before" or "after"
104698
+ - Delete lines: provide start_line/end_line for the exact range and set new_string to empty string ""
104699
+
104700
+ Inverted ranges (end_line < start_line) are always invalid and are never treated as insertion.`;
104690
104701
  editTool = (options = {}) => {
104691
104702
  const { debug, allowedFolders, cwd, workspaceRoot } = parseFileToolOptions(options);
104692
104703
  return (0, import_ai6.tool)({
104693
104704
  name: "edit",
104694
- description: `Edit files using text replacement, AST-aware symbol operations, or line-targeted editing.
104705
+ description: `Edit files using text replacement, AST-aware symbol operations, or line-targeted line replacement/insertion/deletion.
104695
104706
 
104696
104707
  Modes:
104697
104708
  1. Text edit: Provide old_string + new_string to find and replace text (with fuzzy matching fallback)
104698
104709
  2. Symbol replace: Provide symbol + new_string to replace an entire function/class/method by name
104699
104710
  3. Symbol insert: Provide symbol + new_string + position to insert code before/after a symbol
104700
- 4. Line-targeted edit: Provide start_line + new_string to edit by line number (from extract/search output)
104711
+ 4. Line-targeted edit: Provide start_line + new_string to replace/update, insert, or delete lines by line number (from extract/search output)
104712
+
104713
+ ${lineTargetedModeGuidance}
104701
104714
 
104702
104715
  Parameters:
104703
104716
  - file_path: Path to the file to edit (absolute or relative)
104704
- - new_string: Replacement text or new code content
104717
+ - new_string: Replacement text or new code content. Use empty string "" to delete the targeted line range.
104705
104718
  - old_string: (optional) Text to find and replace. If omitted, symbol or start_line must be provided.
104706
104719
  - replace_all: (optional) Replace all occurrences (text mode only)
104707
104720
  - symbol: (optional) Symbol name for AST-aware editing (e.g. "myFunction", "MyClass.myMethod")
104708
- - position: (optional) "before" or "after" \u2014 insert code near a symbol or line instead of replacing it
104709
- - start_line: (optional) Line reference (e.g. "42" or "42:ab") for line-targeted editing
104710
- - end_line: (optional) End of line range, inclusive (e.g. "55" or "55:cd")`,
104721
+ - position: (optional) "before" or "after" \u2014 insert code near a symbol or line instead of replacing it. Omit position to replace/update.
104722
+ - start_line: (optional) Line reference (e.g. "42" or "42:ab") for line-targeted editing. With position, this is the insertion anchor. Without position, this is the first line to replace/update/delete.
104723
+ - end_line: (optional) End of line range, inclusive (e.g. "55" or "55:cd"). Must be >= start_line. Omit for single-line updates. Do not use inverted ranges for insertion.`,
104711
104724
  inputSchema: {
104712
104725
  type: "object",
104713
104726
  properties: {
@@ -104721,7 +104734,7 @@ Parameters:
104721
104734
  },
104722
104735
  new_string: {
104723
104736
  type: "string",
104724
- description: "Replacement text or new code content"
104737
+ description: 'Replacement text or new code content. Use empty string "" to delete the targeted line range.'
104725
104738
  },
104726
104739
  replace_all: {
104727
104740
  type: "boolean",
@@ -104735,15 +104748,15 @@ Parameters:
104735
104748
  position: {
104736
104749
  type: "string",
104737
104750
  enum: ["before", "after"],
104738
- description: "Insert before/after symbol or line (requires symbol or start_line, omit to replace)"
104751
+ description: "Insert before/after the target symbol or start_line anchor. Omit position to replace/update the addressed symbol or line range."
104739
104752
  },
104740
104753
  start_line: {
104741
104754
  type: "string",
104742
- description: 'Line reference for line-targeted editing (e.g. "42" or "42:ab" with hash)'
104755
+ description: 'Line reference for line-targeted editing (e.g. "42" or "42:ab" with hash). With position, this is the insertion anchor. Without position, this is the first line to replace/update/delete.'
104743
104756
  },
104744
104757
  end_line: {
104745
104758
  type: "string",
104746
- description: 'End of line range, inclusive (e.g. "55" or "55:cd"). Defaults to start_line.'
104759
+ description: 'Inclusive end of the line range to replace/delete (e.g. "55" or "55:cd"). Must be >= start_line. Defaults to start_line.'
104747
104760
  }
104748
104761
  },
104749
104762
  required: ["file_path", "new_string"]
@@ -104994,7 +105007,7 @@ Important:
104994
105007
  },
104995
105008
  new_string: {
104996
105009
  type: "string",
104997
- description: "Replacement text or new code content"
105010
+ description: 'Replacement text or new code content. Use empty string "" to delete the targeted line range.'
104998
105011
  },
104999
105012
  replace_all: {
105000
105013
  type: "boolean",
@@ -105007,15 +105020,15 @@ Important:
105007
105020
  position: {
105008
105021
  type: "string",
105009
105022
  enum: ["before", "after"],
105010
- description: "Insert before/after symbol or line (requires symbol or start_line, omit to replace)"
105023
+ description: "Insert before/after the target symbol or start_line anchor. Omit position to replace/update the addressed symbol or line range."
105011
105024
  },
105012
105025
  start_line: {
105013
105026
  type: "string",
105014
- description: 'Line reference for line-targeted editing (e.g. "42" or "42:ab" with hash)'
105027
+ description: 'Line reference for line-targeted editing (e.g. "42" or "42:ab" with hash). With position, this is the insertion anchor. Without position, this is the first line to replace/update/delete.'
105015
105028
  },
105016
105029
  end_line: {
105017
105030
  type: "string",
105018
- description: 'End of line range, inclusive (e.g. "55" or "55:cd"). Defaults to start_line.'
105031
+ description: 'Inclusive end of the line range to replace/delete (e.g. "55" or "55:cd"). Must be >= start_line. Defaults to start_line.'
105019
105032
  }
105020
105033
  },
105021
105034
  required: ["file_path", "new_string"]
@@ -105048,7 +105061,7 @@ Important:
105048
105061
  },
105049
105062
  required: ["edits"]
105050
105063
  };
105051
- editDescription = "Edit files using text replacement, AST-aware symbol operations, or line-targeted editing. Supports fuzzy matching for text edits and optional hash-based integrity verification for line edits.";
105064
+ editDescription = "Edit files using text replacement, AST-aware symbol operations, or line-targeted replacement/insertion/deletion. Supports fuzzy matching for text edits and optional hash-based integrity verification for line edits.";
105052
105065
  createDescription = "Create new files with specified content. Will create parent directories if needed.";
105053
105066
  multiEditDescription = "Apply multiple file edits in a single tool call. Accepts a JSON array of edit operations, each supporting the same modes as the edit tool.";
105054
105067
  editToolDefinition = `
@@ -105065,15 +105078,21 @@ Four editing modes \u2014 choose based on the scope of your change:
105065
105078
 
105066
105079
  4. **Line-targeted edit** (start_line + new_string): For precise edits using line numbers from extract/search output. Use start_line with a line number (e.g. "42") or line:hash (e.g. "42:ab") for integrity verification. Add end_line for multi-line ranges. Use position="before" or "after" to insert instead of replace.
105067
105080
 
105081
+ How line-targeted mode behaves:
105082
+ - Replace/update lines: provide start_line and optionally end_line, and omit position
105083
+ - Insert near a line: provide start_line and set position to "before" or "after"
105084
+ - Delete lines: provide start_line/end_line for the exact range and set new_string to empty string ""
105085
+ - Inverted ranges are invalid: end_line must be >= start_line and is never treated as insertion
105086
+
105068
105087
  Parameters:
105069
105088
  - file_path: (required) Path to the file to edit
105070
- - new_string: (required) Replacement text or new code content
105089
+ - new_string: (required) Replacement text or new code content. Use empty string "" to delete the targeted line range.
105071
105090
  - old_string: (optional) Text to find and replace \u2014 copy verbatim from the file, do not paraphrase or reformat
105072
105091
  - replace_all: (optional, default: false) Replace all occurrences of old_string (text mode only)
105073
105092
  - symbol: (optional) Name of a code symbol (e.g. "myFunction", "MyClass.myMethod") \u2014 must match a function, class, or method definition
105074
- - position: (optional) "before" or "after" \u2014 insert new_string near the symbol or line instead of replacing it
105075
- - start_line: (optional) Line reference for line-targeted editing (e.g. "42" or "42:ab")
105076
- - end_line: (optional) End of line range, inclusive (e.g. "55" or "55:cd"). Defaults to start_line.
105093
+ - position: (optional) "before" or "after" \u2014 insert new_string near the symbol or line instead of replacing it. Omit position to replace/update.
105094
+ - start_line: (optional) Line reference for line-targeted editing (e.g. "42" or "42:ab"). With position, this is the insertion anchor. Without position, this is the first line to replace/update/delete.
105095
+ - end_line: (optional) End of line range, inclusive (e.g. "55" or "55:cd"). Defaults to start_line. Must be >= start_line. Use it for replace/update/delete ranges, not insertion.
105077
105096
 
105078
105097
  Mode selection rules (priority order):
105079
105098
  - If symbol is provided, symbol mode is used (old_string and start_line are ignored)
@@ -105085,12 +105104,15 @@ When to use each mode:
105085
105104
  - Small edits (a line or a few lines): use text mode with old_string
105086
105105
  - Replacing entire functions/classes/methods: use symbol mode \u2014 no exact text matching needed
105087
105106
  - Editing specific lines from extract/search output: use line-targeted mode with start_line
105107
+ - Adding a new block near an existing line: use line-targeted mode with start_line plus position="before" or position="after"
105108
+ - Removing lines entirely: use line-targeted mode with start_line/end_line and new_string=""
105088
105109
  - Editing inside large functions without rewriting them entirely: first use extract with the symbol target (e.g. "file.js#myFunction") to see the function with line numbers, then use start_line/end_line to edit specific lines within it
105089
105110
 
105090
105111
  Error handling:
105091
105112
  - If an edit fails, read the error message carefully \u2014 it contains specific instructions for how to fix the call and retry
105092
105113
  - Common fixes: use 'search'/'extract' to get exact file content, add more context to old_string, switch between text and symbol modes
105093
105114
  - Line-targeted hash mismatch: the file changed since last read; the error provides updated line:hash references
105115
+ - Inverted line ranges are invalid; the error explains how to express insertion with position="before"/"after"
105094
105116
 
105095
105117
  Examples:
105096
105118
 
@@ -105144,6 +105166,22 @@ Line-targeted edit (replace a range of lines):
105144
105166
  return processItems(order.items);</new_string>
105145
105167
  </edit>
105146
105168
 
105169
+ Line-targeted edit (insert before a line without replacing it):
105170
+ <edit>
105171
+ <file_path>src/main.js</file_path>
105172
+ <start_line>42</start_line>
105173
+ <position>before</position>
105174
+ <new_string> logger.debug("starting process");</new_string>
105175
+ </edit>
105176
+
105177
+ Line-targeted edit (delete a range of lines):
105178
+ <edit>
105179
+ <file_path>src/main.js</file_path>
105180
+ <start_line>42</start_line>
105181
+ <end_line>45</end_line>
105182
+ <new_string></new_string>
105183
+ </edit>
105184
+
105147
105185
  Line-targeted edit with hash verification:
105148
105186
  <edit>
105149
105187
  <file_path>src/main.js</file_path>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@probelabs/probe",
3
- "version": "0.6.0-rc309",
3
+ "version": "0.6.0-rc311",
4
4
  "description": "Node.js wrapper for the probe code search tool",
5
5
  "main": "src/index.js",
6
6
  "module": "src/index.js",
@@ -3179,6 +3179,8 @@ Follow these instructions carefully:
3179
3179
  7. When modifying files, choose the appropriate tool:
3180
3180
  - Use 'edit' for all code modifications:
3181
3181
  * PREFERRED: Use start_line (and optionally end_line) for line-targeted editing — this is the safest and most precise approach.${this.hashLines ? ' Use the line:hash references from extract/search output (e.g. "42:ab") for integrity verification.' : ''} Always use extract first to see line numbers${this.hashLines ? ' and hashes' : ''}, then edit by line reference.
3182
+ * In line-targeted mode, omitting position means replace/update the addressed lines. To insert new code near a line, you MUST set position="before" or position="after". Never express insertion as end_line < start_line.
3183
+ * To delete lines in line-targeted mode, target the exact start_line/end_line range and set new_string to the empty string "".
3182
3184
  * For editing inside large functions: first use extract with the symbol target (e.g. "file.js#myFunction") to see the function with line numbers${this.hashLines ? ' and hashes' : ''}, then use start_line/end_line to surgically edit specific lines within it.
3183
3185
  * For rewriting entire functions/classes/methods, use the symbol parameter instead (no exact text matching needed).
3184
3186
  * FALLBACK ONLY: Use old_string + new_string for simple single-line changes where the text is unique. Copy old_string verbatim from the file. Keep old_string as small as possible.
@@ -141,6 +141,8 @@ Bash is fine for: formatters (gofmt, prettier, black), build/test/lint commands,
141
141
  - Never expose secrets, API keys, or credentials in generated code. Never log sensitive information.
142
142
  - Do not surprise the user with unrequested changes. Do what was asked, including reasonable follow-up actions, but do not refactor surrounding code or add features that were not requested.
143
143
  - When editing files, keep edits focused and minimal. For changes spanning more than a few lines, prefer line-targeted editing (start_line/end_line) over text replacement (old_string) — it constrains scope and prevents accidental removal of adjacent content. Never include unrelated sections in an edit operation.
144
+ - In line-targeted mode, omitting position means replace/update the addressed lines. To insert code near an existing line, you MUST use position="before" or position="after". Never express insertion as end_line < start_line.
145
+ - To remove lines with line-targeted mode, target the exact start_line/end_line range and set new_string to the empty string "".
144
146
  - After every significant change, verify the project still builds and passes linting. Do not wait until the end to discover breakage.
145
147
 
146
148
  # Writing Tests
package/src/tools/edit.js CHANGED
@@ -186,6 +186,13 @@ function buildLineEditResponse(file_path, startLine, endLine, newLineCount, upda
186
186
  return msg;
187
187
  }
188
188
 
189
+ const lineTargetedModeGuidance = `Line-targeted mode has three explicit behaviors:
190
+ - Replace/update lines: provide start_line and optionally end_line, and omit position
191
+ - Insert near a line: provide start_line and set position to "before" or "after"
192
+ - Delete lines: provide start_line/end_line for the exact range and set new_string to empty string ""
193
+
194
+ Inverted ranges (end_line < start_line) are always invalid and are never treated as insertion.`;
195
+
189
196
  /**
190
197
  * Handle line-targeted editing (replace, insert, delete by line numbers)
191
198
  * @param {Object} params - Parameters
@@ -211,12 +218,15 @@ async function handleLineEdit({ resolvedPath, file_path, start_line, end_line, n
211
218
  const endLine = endRef ? endRef.line : startLine;
212
219
 
213
220
  if (endLine < startLine) {
214
- return `Error editing file: end_line (${endLine}) must be >= start_line (${startLine}).`;
221
+ const insertionHint = endLine === startLine - 1
222
+ ? ` This looks like an insertion between lines ${endLine} and ${startLine}. To insert there without replacing existing code, use start_line="${startLine}" with position="before" or start_line="${endLine}" with position="after".`
223
+ : ' To insert new code, choose a single anchor line in start_line and set position to "before" or "after" instead of using an inverted range.';
224
+ return `Error editing file: end_line (${endLine}) must be >= start_line (${startLine}). Omitting position means replace/update the addressed lines, not insert.${insertionHint} To delete lines, use new_string as the empty string "" with a valid non-inverted range.`;
215
225
  }
216
226
 
217
227
  // Validate position if provided
218
228
  if (position !== undefined && position !== null && position !== 'before' && position !== 'after') {
219
- return 'Error editing file: Invalid position - must be "before" or "after". Use position="before" to insert before the line, or position="after" to insert after it.';
229
+ return 'Error editing file: Invalid position - must be "before" or "after". Use position="before" to insert before start_line, position="after" to insert after start_line, or omit position to replace/update the addressed lines.';
220
230
  }
221
231
 
222
232
  // Read the file
@@ -304,23 +314,25 @@ export const editTool = (options = {}) => {
304
314
 
305
315
  return tool({
306
316
  name: 'edit',
307
- description: `Edit files using text replacement, AST-aware symbol operations, or line-targeted editing.
317
+ description: `Edit files using text replacement, AST-aware symbol operations, or line-targeted line replacement/insertion/deletion.
308
318
 
309
319
  Modes:
310
320
  1. Text edit: Provide old_string + new_string to find and replace text (with fuzzy matching fallback)
311
321
  2. Symbol replace: Provide symbol + new_string to replace an entire function/class/method by name
312
322
  3. Symbol insert: Provide symbol + new_string + position to insert code before/after a symbol
313
- 4. Line-targeted edit: Provide start_line + new_string to edit by line number (from extract/search output)
323
+ 4. Line-targeted edit: Provide start_line + new_string to replace/update, insert, or delete lines by line number (from extract/search output)
324
+
325
+ ${lineTargetedModeGuidance}
314
326
 
315
327
  Parameters:
316
328
  - file_path: Path to the file to edit (absolute or relative)
317
- - new_string: Replacement text or new code content
329
+ - new_string: Replacement text or new code content. Use empty string "" to delete the targeted line range.
318
330
  - old_string: (optional) Text to find and replace. If omitted, symbol or start_line must be provided.
319
331
  - replace_all: (optional) Replace all occurrences (text mode only)
320
332
  - symbol: (optional) Symbol name for AST-aware editing (e.g. "myFunction", "MyClass.myMethod")
321
- - position: (optional) "before" or "after" — insert code near a symbol or line instead of replacing it
322
- - start_line: (optional) Line reference (e.g. "42" or "42:ab") for line-targeted editing
323
- - end_line: (optional) End of line range, inclusive (e.g. "55" or "55:cd")`,
333
+ - position: (optional) "before" or "after" — insert code near a symbol or line instead of replacing it. Omit position to replace/update.
334
+ - start_line: (optional) Line reference (e.g. "42" or "42:ab") for line-targeted editing. With position, this is the insertion anchor. Without position, this is the first line to replace/update/delete.
335
+ - end_line: (optional) End of line range, inclusive (e.g. "55" or "55:cd"). Must be >= start_line. Omit for single-line updates. Do not use inverted ranges for insertion.`,
324
336
 
325
337
  inputSchema: {
326
338
  type: 'object',
@@ -335,7 +347,7 @@ Parameters:
335
347
  },
336
348
  new_string: {
337
349
  type: 'string',
338
- description: 'Replacement text or new code content'
350
+ description: 'Replacement text or new code content. Use empty string "" to delete the targeted line range.'
339
351
  },
340
352
  replace_all: {
341
353
  type: 'boolean',
@@ -349,15 +361,15 @@ Parameters:
349
361
  position: {
350
362
  type: 'string',
351
363
  enum: ['before', 'after'],
352
- description: 'Insert before/after symbol or line (requires symbol or start_line, omit to replace)'
364
+ description: 'Insert before/after the target symbol or start_line anchor. Omit position to replace/update the addressed symbol or line range.'
353
365
  },
354
366
  start_line: {
355
367
  type: 'string',
356
- description: 'Line reference for line-targeted editing (e.g. "42" or "42:ab" with hash)'
368
+ description: 'Line reference for line-targeted editing (e.g. "42" or "42:ab" with hash). With position, this is the insertion anchor. Without position, this is the first line to replace/update/delete.'
357
369
  },
358
370
  end_line: {
359
371
  type: 'string',
360
- description: 'End of line range, inclusive (e.g. "55" or "55:cd"). Defaults to start_line.'
372
+ description: 'Inclusive end of the line range to replace/delete (e.g. "55" or "55:cd"). Must be >= start_line. Defaults to start_line.'
361
373
  }
362
374
  },
363
375
  required: ['file_path', 'new_string']
@@ -702,7 +714,7 @@ export const editSchema = {
702
714
  },
703
715
  new_string: {
704
716
  type: 'string',
705
- description: 'Replacement text or new code content'
717
+ description: 'Replacement text or new code content. Use empty string "" to delete the targeted line range.'
706
718
  },
707
719
  replace_all: {
708
720
  type: 'boolean',
@@ -715,15 +727,15 @@ export const editSchema = {
715
727
  position: {
716
728
  type: 'string',
717
729
  enum: ['before', 'after'],
718
- description: 'Insert before/after symbol or line (requires symbol or start_line, omit to replace)'
730
+ description: 'Insert before/after the target symbol or start_line anchor. Omit position to replace/update the addressed symbol or line range.'
719
731
  },
720
732
  start_line: {
721
733
  type: 'string',
722
- description: 'Line reference for line-targeted editing (e.g. "42" or "42:ab" with hash)'
734
+ description: 'Line reference for line-targeted editing (e.g. "42" or "42:ab" with hash). With position, this is the insertion anchor. Without position, this is the first line to replace/update/delete.'
723
735
  },
724
736
  end_line: {
725
737
  type: 'string',
726
- description: 'End of line range, inclusive (e.g. "55" or "55:cd"). Defaults to start_line.'
738
+ description: 'Inclusive end of the line range to replace/delete (e.g. "55" or "55:cd"). Must be >= start_line. Defaults to start_line.'
727
739
  }
728
740
  },
729
741
  required: ['file_path', 'new_string']
@@ -760,7 +772,7 @@ export const multiEditSchema = {
760
772
  };
761
773
 
762
774
  // Tool descriptions for XML definitions
763
- export const editDescription = 'Edit files using text replacement, AST-aware symbol operations, or line-targeted editing. Supports fuzzy matching for text edits and optional hash-based integrity verification for line edits.';
775
+ export const editDescription = 'Edit files using text replacement, AST-aware symbol operations, or line-targeted replacement/insertion/deletion. Supports fuzzy matching for text edits and optional hash-based integrity verification for line edits.';
764
776
  export const createDescription = 'Create new files with specified content. Will create parent directories if needed.';
765
777
  export const multiEditDescription = 'Apply multiple file edits in a single tool call. Accepts a JSON array of edit operations, each supporting the same modes as the edit tool.';
766
778
 
@@ -779,15 +791,21 @@ Four editing modes — choose based on the scope of your change:
779
791
 
780
792
  4. **Line-targeted edit** (start_line + new_string): For precise edits using line numbers from extract/search output. Use start_line with a line number (e.g. "42") or line:hash (e.g. "42:ab") for integrity verification. Add end_line for multi-line ranges. Use position="before" or "after" to insert instead of replace.
781
793
 
794
+ How line-targeted mode behaves:
795
+ - Replace/update lines: provide start_line and optionally end_line, and omit position
796
+ - Insert near a line: provide start_line and set position to "before" or "after"
797
+ - Delete lines: provide start_line/end_line for the exact range and set new_string to empty string ""
798
+ - Inverted ranges are invalid: end_line must be >= start_line and is never treated as insertion
799
+
782
800
  Parameters:
783
801
  - file_path: (required) Path to the file to edit
784
- - new_string: (required) Replacement text or new code content
802
+ - new_string: (required) Replacement text or new code content. Use empty string "" to delete the targeted line range.
785
803
  - old_string: (optional) Text to find and replace — copy verbatim from the file, do not paraphrase or reformat
786
804
  - replace_all: (optional, default: false) Replace all occurrences of old_string (text mode only)
787
805
  - symbol: (optional) Name of a code symbol (e.g. "myFunction", "MyClass.myMethod") — must match a function, class, or method definition
788
- - position: (optional) "before" or "after" — insert new_string near the symbol or line instead of replacing it
789
- - start_line: (optional) Line reference for line-targeted editing (e.g. "42" or "42:ab")
790
- - end_line: (optional) End of line range, inclusive (e.g. "55" or "55:cd"). Defaults to start_line.
806
+ - position: (optional) "before" or "after" — insert new_string near the symbol or line instead of replacing it. Omit position to replace/update.
807
+ - start_line: (optional) Line reference for line-targeted editing (e.g. "42" or "42:ab"). With position, this is the insertion anchor. Without position, this is the first line to replace/update/delete.
808
+ - end_line: (optional) End of line range, inclusive (e.g. "55" or "55:cd"). Defaults to start_line. Must be >= start_line. Use it for replace/update/delete ranges, not insertion.
791
809
 
792
810
  Mode selection rules (priority order):
793
811
  - If symbol is provided, symbol mode is used (old_string and start_line are ignored)
@@ -799,12 +817,15 @@ When to use each mode:
799
817
  - Small edits (a line or a few lines): use text mode with old_string
800
818
  - Replacing entire functions/classes/methods: use symbol mode — no exact text matching needed
801
819
  - Editing specific lines from extract/search output: use line-targeted mode with start_line
820
+ - Adding a new block near an existing line: use line-targeted mode with start_line plus position="before" or position="after"
821
+ - Removing lines entirely: use line-targeted mode with start_line/end_line and new_string=""
802
822
  - Editing inside large functions without rewriting them entirely: first use extract with the symbol target (e.g. "file.js#myFunction") to see the function with line numbers, then use start_line/end_line to edit specific lines within it
803
823
 
804
824
  Error handling:
805
825
  - If an edit fails, read the error message carefully — it contains specific instructions for how to fix the call and retry
806
826
  - Common fixes: use 'search'/'extract' to get exact file content, add more context to old_string, switch between text and symbol modes
807
827
  - Line-targeted hash mismatch: the file changed since last read; the error provides updated line:hash references
828
+ - Inverted line ranges are invalid; the error explains how to express insertion with position="before"/"after"
808
829
 
809
830
  Examples:
810
831
 
@@ -858,6 +879,22 @@ Line-targeted edit (replace a range of lines):
858
879
  return processItems(order.items);</new_string>
859
880
  </edit>
860
881
 
882
+ Line-targeted edit (insert before a line without replacing it):
883
+ <edit>
884
+ <file_path>src/main.js</file_path>
885
+ <start_line>42</start_line>
886
+ <position>before</position>
887
+ <new_string> logger.debug("starting process");</new_string>
888
+ </edit>
889
+
890
+ Line-targeted edit (delete a range of lines):
891
+ <edit>
892
+ <file_path>src/main.js</file_path>
893
+ <start_line>42</start_line>
894
+ <end_line>45</end_line>
895
+ <new_string></new_string>
896
+ </edit>
897
+
861
898
  Line-targeted edit with hash verification:
862
899
  <edit>
863
900
  <file_path>src/main.js</file_path>