@probelabs/probe 0.6.0-rc263 → 0.6.0-rc265

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.
@@ -9553,6 +9553,11 @@ Example: <extract><targets>${displayPath}</targets></extract>`;
9553
9553
  if (!replace_all && occurrences > 1) {
9554
9554
  return `Error editing file: Multiple occurrences found - the old_string appears ${occurrences} times in ${file_path}. To fix: (1) Set replace_all=true to replace all occurrences, or (2) Include more surrounding lines in old_string to make the match unique (add the full line or adjacent lines for context).`;
9555
9555
  }
9556
+ const oldLines = matchTarget.split("\n").length;
9557
+ const newLines = new_string.split("\n").length;
9558
+ if (oldLines >= 20 && newLines < oldLines * 0.5) {
9559
+ return `Error editing file: Edit scope too large \u2014 replacing ${oldLines} lines with ${newLines} lines risks accidental content deletion. To fix: (1) Use line-targeted editing (start_line/end_line) instead to constrain scope, or (2) Split into smaller, focused edits that each target only the lines you intend to change.`;
9560
+ }
9556
9561
  let newContent;
9557
9562
  if (replace_all) {
9558
9563
  newContent = content.replaceAll(matchTarget, new_string);
@@ -12935,6 +12940,122 @@ var init_bashPermissions = __esm({
12935
12940
  import { spawn as spawn2 } from "child_process";
12936
12941
  import { resolve as resolve3, join } from "path";
12937
12942
  import { existsSync as existsSync2 } from "fs";
12943
+ function splitCommandComponents(command) {
12944
+ const parts = [];
12945
+ let current2 = "";
12946
+ let inQuote = false;
12947
+ let quoteChar = "";
12948
+ for (let i = 0; i < command.length; i++) {
12949
+ const c = command[i];
12950
+ const next = command[i + 1] || "";
12951
+ if (c === "\\" && !inQuote) {
12952
+ current2 += c + next;
12953
+ i++;
12954
+ continue;
12955
+ }
12956
+ if (inQuote && quoteChar === '"' && c === "\\" && next) {
12957
+ current2 += c + next;
12958
+ i++;
12959
+ continue;
12960
+ }
12961
+ if (!inQuote && (c === '"' || c === "'")) {
12962
+ inQuote = true;
12963
+ quoteChar = c;
12964
+ current2 += c;
12965
+ continue;
12966
+ }
12967
+ if (inQuote && c === quoteChar) {
12968
+ inQuote = false;
12969
+ current2 += c;
12970
+ continue;
12971
+ }
12972
+ if (!inQuote) {
12973
+ if (c === "&" && next === "&" || c === "|" && next === "|") {
12974
+ if (current2.trim()) parts.push(current2.trim());
12975
+ current2 = "";
12976
+ i++;
12977
+ continue;
12978
+ }
12979
+ if (c === "|" || c === ";") {
12980
+ if (current2.trim()) parts.push(current2.trim());
12981
+ current2 = "";
12982
+ continue;
12983
+ }
12984
+ }
12985
+ current2 += c;
12986
+ }
12987
+ if (current2.trim()) parts.push(current2.trim());
12988
+ return parts;
12989
+ }
12990
+ function checkSingleCommandInteractive(command) {
12991
+ let effective = command.trim();
12992
+ while (/^\w+=\S*\s/.test(effective)) {
12993
+ effective = effective.replace(/^\w+=\S*\s+/, "");
12994
+ }
12995
+ const parts = effective.split(/\s+/);
12996
+ const base2 = parts[0];
12997
+ const args = parts.slice(1);
12998
+ if (["vi", "vim", "nvim", "nano", "emacs", "pico", "joe", "mcedit"].includes(base2)) {
12999
+ return `'${base2}' is an interactive editor and cannot run without a terminal. Use non-interactive file manipulation commands instead.`;
13000
+ }
13001
+ if (["less", "more"].includes(base2)) {
13002
+ return `'${base2}' is an interactive pager. Use 'cat', 'head', or 'tail' instead.`;
13003
+ }
13004
+ if (base2 === "git") {
13005
+ const sub = args[0];
13006
+ if (sub === "commit") {
13007
+ const hasNonInteractiveFlag = args.some(
13008
+ (a) => a === "-m" || a.startsWith("--message") || a === "-C" || a === "-c" || a.startsWith("--fixup") || a.startsWith("--squash") || a === "--allow-empty-message" || a === "--no-edit"
13009
+ );
13010
+ if (!hasNonInteractiveFlag) {
13011
+ return `Interactive command: 'git commit' opens an editor for the commit message. Use 'git commit -m "your message"' instead.`;
13012
+ }
13013
+ }
13014
+ if (sub === "rebase" && (args.includes("--continue") || args.includes("--skip"))) {
13015
+ return "Interactive command: 'git rebase --continue' opens an editor. Set environment variable GIT_EDITOR=true to accept default messages, e.g. pass env: {GIT_EDITOR: 'true'} or prepend GIT_EDITOR=true to the command.";
13016
+ }
13017
+ if (sub === "rebase" && (args.includes("-i") || args.includes("--interactive"))) {
13018
+ return "Interactive command: 'git rebase -i' requires an interactive editor. Interactive rebase cannot run without a terminal.";
13019
+ }
13020
+ if (sub === "merge" && !args.includes("--no-edit") && !args.includes("--no-commit") && !args.includes("--ff-only")) {
13021
+ return "Interactive command: 'git merge' may open an editor for the merge commit message. Add '--no-edit' to accept the default message.";
13022
+ }
13023
+ if (sub === "cherry-pick" && !args.includes("--no-edit")) {
13024
+ return "Interactive command: 'git cherry-pick' may open an editor. Add '--no-edit' to accept the default message.";
13025
+ }
13026
+ if (sub === "revert" && !args.includes("--no-edit")) {
13027
+ return "Interactive command: 'git revert' opens an editor. Add '--no-edit' to accept the default message.";
13028
+ }
13029
+ if (sub === "tag" && args.includes("-a") && !args.some((a) => a === "-m" || a.startsWith("--message"))) {
13030
+ return `Interactive command: 'git tag -a' opens an editor for the tag message. Use 'git tag -a <name> -m "message"' instead.`;
13031
+ }
13032
+ if (sub === "add" && (args.includes("-i") || args.includes("--interactive") || args.includes("-p") || args.includes("--patch"))) {
13033
+ return "Interactive command: 'git add -i/-p' requires interactive input. Use 'git add <files>' to stage specific files instead.";
13034
+ }
13035
+ }
13036
+ if (["python", "python3", "node", "irb", "ghci", "lua", "R", "ruby"].includes(base2) && args.length === 0) {
13037
+ return `Interactive command: '${base2}' without arguments starts an interactive REPL. Provide a script file or use '-c'/'--eval' for inline code.`;
13038
+ }
13039
+ if (base2 === "mysql" && !args.some((a) => a === "-e" || a.startsWith("--execute"))) {
13040
+ return `Interactive command: 'mysql' without -e flag starts an interactive session. Use 'mysql -e "SQL QUERY"' instead.`;
13041
+ }
13042
+ if (base2 === "psql" && !args.some((a) => a === "-c" || a.startsWith("--command") || a === "-f" || a.startsWith("--file"))) {
13043
+ return `Interactive command: 'psql' without -c flag starts an interactive session. Use 'psql -c "SQL QUERY"' instead.`;
13044
+ }
13045
+ if (["top", "htop", "btop", "nmon"].includes(base2)) {
13046
+ return `Interactive command: '${base2}' is an interactive TUI tool. Use 'ps aux' or 'top -b -n 1' for non-interactive process listing.`;
13047
+ }
13048
+ return null;
13049
+ }
13050
+ function checkInteractiveCommand(command) {
13051
+ if (!command || typeof command !== "string") return null;
13052
+ const components = splitCommandComponents(command.trim());
13053
+ for (const component of components) {
13054
+ const result = checkSingleCommandInteractive(component);
13055
+ if (result) return result;
13056
+ }
13057
+ return null;
13058
+ }
12938
13059
  async function executeBashCommand(command, options = {}) {
12939
13060
  const {
12940
13061
  workingDirectory = process.cwd(),
@@ -12964,6 +13085,24 @@ async function executeBashCommand(command, options = {}) {
12964
13085
  };
12965
13086
  }
12966
13087
  const startTime = Date.now();
13088
+ const interactiveError = checkInteractiveCommand(command);
13089
+ if (interactiveError) {
13090
+ if (debug) {
13091
+ console.log(`[BashExecutor] Blocked interactive command: "${command}"`);
13092
+ console.log(`[BashExecutor] Reason: ${interactiveError}`);
13093
+ }
13094
+ return {
13095
+ success: false,
13096
+ error: interactiveError,
13097
+ stdout: "",
13098
+ stderr: interactiveError,
13099
+ exitCode: 1,
13100
+ command,
13101
+ workingDirectory: cwd,
13102
+ duration: 0,
13103
+ interactive: true
13104
+ };
13105
+ }
12967
13106
  if (debug) {
12968
13107
  console.log(`[BashExecutor] Executing command: "${command}"`);
12969
13108
  console.log(`[BashExecutor] Working directory: "${cwd}"`);
@@ -12974,6 +13113,8 @@ async function executeBashCommand(command, options = {}) {
12974
13113
  ...process.env,
12975
13114
  ...env
12976
13115
  };
13116
+ if (!processEnv.GIT_EDITOR) processEnv.GIT_EDITOR = "true";
13117
+ if (!processEnv.GIT_TERMINAL_PROMPT) processEnv.GIT_TERMINAL_PROMPT = "0";
12977
13118
  const isComplex = isComplexCommand(command);
12978
13119
  let cmd, cmdArgs, useShell;
12979
13120
  if (isComplex) {
@@ -13008,20 +13149,32 @@ async function executeBashCommand(command, options = {}) {
13008
13149
  // stdin ignored, capture stdout/stderr
13009
13150
  shell: useShell,
13010
13151
  // false for security
13152
+ detached: true,
13153
+ // new session — no controlling terminal
13011
13154
  windowsHide: true
13012
13155
  });
13013
13156
  let stdout = "";
13014
13157
  let stderr = "";
13015
13158
  let killed = false;
13016
13159
  let timeoutHandle;
13160
+ const killProcessGroup = (signal) => {
13161
+ try {
13162
+ if (child.pid) process.kill(-child.pid, signal);
13163
+ } catch {
13164
+ try {
13165
+ child.kill(signal);
13166
+ } catch {
13167
+ }
13168
+ }
13169
+ };
13017
13170
  if (timeout > 0) {
13018
13171
  timeoutHandle = setTimeout(() => {
13019
13172
  if (!killed) {
13020
13173
  killed = true;
13021
- child.kill("SIGTERM");
13174
+ killProcessGroup("SIGTERM");
13022
13175
  setTimeout(() => {
13023
13176
  if (child.exitCode === null) {
13024
- child.kill("SIGKILL");
13177
+ killProcessGroup("SIGKILL");
13025
13178
  }
13026
13179
  }, 5e3);
13027
13180
  }
@@ -13034,7 +13187,7 @@ async function executeBashCommand(command, options = {}) {
13034
13187
  } else {
13035
13188
  if (!killed) {
13036
13189
  killed = true;
13037
- child.kill("SIGTERM");
13190
+ killProcessGroup("SIGTERM");
13038
13191
  }
13039
13192
  }
13040
13193
  });
@@ -13045,7 +13198,7 @@ async function executeBashCommand(command, options = {}) {
13045
13198
  } else {
13046
13199
  if (!killed) {
13047
13200
  killed = true;
13048
- child.kill("SIGTERM");
13201
+ killProcessGroup("SIGTERM");
13049
13202
  }
13050
13203
  }
13051
13204
  });
@@ -39381,7 +39534,6 @@ var init_reg_exp = __esm({
39381
39534
  // node_modules/chevrotain/lib/src/scan/lexer.js
39382
39535
  function analyzeTokenTypes(tokenTypes, options) {
39383
39536
  options = defaults_default(options, {
39384
- useSticky: SUPPORT_STICKY,
39385
39537
  debug: false,
39386
39538
  safeMode: false,
39387
39539
  positionTracking: "full",
@@ -39430,7 +39582,7 @@ function analyzeTokenTypes(tokenTypes, options) {
39430
39582
  ], regExpSource[1])) {
39431
39583
  return regExpSource[1];
39432
39584
  } else {
39433
- return options.useSticky ? addStickyFlag(currPattern) : addStartOfInput(currPattern);
39585
+ return addStickyFlag(currPattern);
39434
39586
  }
39435
39587
  } else if (isFunction_default(currPattern)) {
39436
39588
  hasCustom = true;
@@ -39444,7 +39596,7 @@ function analyzeTokenTypes(tokenTypes, options) {
39444
39596
  } else {
39445
39597
  const escapedRegExpString = currPattern.replace(/[\\^$.*+?()[\]{}|]/g, "\\$&");
39446
39598
  const wrappedRegExp = new RegExp(escapedRegExpString);
39447
- return options.useSticky ? addStickyFlag(wrappedRegExp) : addStartOfInput(wrappedRegExp);
39599
+ return addStickyFlag(wrappedRegExp);
39448
39600
  }
39449
39601
  } else {
39450
39602
  throw Error("non exhaustive match");
@@ -39848,10 +40000,6 @@ function noMetaChar(regExp) {
39848
40000
  function usesLookAheadOrBehind(regExp) {
39849
40001
  return /(\(\?=)|(\(\?!)|(\(\?<=)|(\(\?<!)/.test(regExp.source);
39850
40002
  }
39851
- function addStartOfInput(pattern) {
39852
- const flags = pattern.ignoreCase ? "i" : "";
39853
- return new RegExp(`^(?:${pattern.source})`, flags);
39854
- }
39855
40003
  function addStickyFlag(pattern) {
39856
40004
  const flags = pattern.ignoreCase ? "iy" : "y";
39857
40005
  return new RegExp(`${pattern.source}`, flags);
@@ -40040,7 +40188,7 @@ function initCharCodeToOptimizedIndexMap() {
40040
40188
  }
40041
40189
  }
40042
40190
  }
40043
- var PATTERN, DEFAULT_MODE, MODES, SUPPORT_STICKY, end_of_input, start_of_input, LineTerminatorOptimizedTester, minOptimizationVal, charCodeToOptimizedIdxMap;
40191
+ var PATTERN, DEFAULT_MODE, MODES, end_of_input, start_of_input, LineTerminatorOptimizedTester, minOptimizationVal, charCodeToOptimizedIdxMap;
40044
40192
  var init_lexer = __esm({
40045
40193
  "node_modules/chevrotain/lib/src/scan/lexer.js"() {
40046
40194
  init_api3();
@@ -40052,7 +40200,6 @@ var init_lexer = __esm({
40052
40200
  PATTERN = "PATTERN";
40053
40201
  DEFAULT_MODE = "defaultMode";
40054
40202
  MODES = "modes";
40055
- SUPPORT_STICKY = typeof new RegExp("(?:)").sticky === "boolean";
40056
40203
  end_of_input = /[^\\][$]/;
40057
40204
  start_of_input = /[^\\[][\^]|^\^/;
40058
40205
  LineTerminatorOptimizedTester = {
@@ -40368,13 +40515,6 @@ var init_lexer_public = __esm({
40368
40515
  PRINT_WARNING(warningDescriptor.message);
40369
40516
  });
40370
40517
  this.TRACE_INIT("Choosing sub-methods implementations", () => {
40371
- if (SUPPORT_STICKY) {
40372
- this.chopInput = identity_default;
40373
- this.match = this.matchWithTest;
40374
- } else {
40375
- this.updateLastIndex = noop_default;
40376
- this.match = this.matchWithExec;
40377
- }
40378
40518
  if (hasOnlySingleMode) {
40379
40519
  this.handleModes = noop_default;
40380
40520
  }
@@ -40437,7 +40577,7 @@ var init_lexer_public = __esm({
40437
40577
  // this method also used quite a bit of `!` none null assertions because it is too optimized
40438
40578
  // for `tsc` to always understand it is "safe"
40439
40579
  tokenizeInternal(text, initialMode) {
40440
- let i, j, k, matchAltImage, longerAlt, matchedImage, payload, altPayload, imageLength, group, tokType, newToken, errLength, droppedChar, msg, match2;
40580
+ let i, j, k, matchAltImage, longerAlt, matchedImage, payload, altPayload, imageLength, group, tokType, newToken, errLength, msg, match2;
40441
40581
  const orgText = text;
40442
40582
  const orgLength = orgText.length;
40443
40583
  let offset2 = 0;
@@ -40456,19 +40596,7 @@ var init_lexer_public = __esm({
40456
40596
  const modeStack = [];
40457
40597
  const emptyArray = [];
40458
40598
  Object.freeze(emptyArray);
40459
- let getPossiblePatterns;
40460
- function getPossiblePatternsSlow() {
40461
- return patternIdxToConfig;
40462
- }
40463
- function getPossiblePatternsOptimized(charCode) {
40464
- const optimizedCharIdx = charCodeToOptimizedIndex(charCode);
40465
- const possiblePatterns = currCharCodeToPatternIdxToConfig[optimizedCharIdx];
40466
- if (possiblePatterns === void 0) {
40467
- return emptyArray;
40468
- } else {
40469
- return possiblePatterns;
40470
- }
40471
- }
40599
+ let isOptimizedMode = false;
40472
40600
  const pop_mode = (popToken) => {
40473
40601
  if (modeStack.length === 1 && // if we have both a POP_MODE and a PUSH_MODE this is in-fact a "transition"
40474
40602
  // So no error should occur.
@@ -40489,9 +40617,9 @@ var init_lexer_public = __esm({
40489
40617
  currModePatternsLength = patternIdxToConfig.length;
40490
40618
  const modeCanBeOptimized = this.canModeBeOptimized[newMode] && this.config.safeMode === false;
40491
40619
  if (currCharCodeToPatternIdxToConfig && modeCanBeOptimized) {
40492
- getPossiblePatterns = getPossiblePatternsOptimized;
40620
+ isOptimizedMode = true;
40493
40621
  } else {
40494
- getPossiblePatterns = getPossiblePatternsSlow;
40622
+ isOptimizedMode = false;
40495
40623
  }
40496
40624
  }
40497
40625
  };
@@ -40503,9 +40631,9 @@ var init_lexer_public = __esm({
40503
40631
  currModePatternsLength = patternIdxToConfig.length;
40504
40632
  const modeCanBeOptimized = this.canModeBeOptimized[newMode] && this.config.safeMode === false;
40505
40633
  if (currCharCodeToPatternIdxToConfig && modeCanBeOptimized) {
40506
- getPossiblePatterns = getPossiblePatternsOptimized;
40634
+ isOptimizedMode = true;
40507
40635
  } else {
40508
- getPossiblePatterns = getPossiblePatternsSlow;
40636
+ isOptimizedMode = false;
40509
40637
  }
40510
40638
  }
40511
40639
  push_mode.call(this, initialMode);
@@ -40513,8 +40641,16 @@ var init_lexer_public = __esm({
40513
40641
  const recoveryEnabled = this.config.recoveryEnabled;
40514
40642
  while (offset2 < orgLength) {
40515
40643
  matchedImage = null;
40644
+ imageLength = -1;
40516
40645
  const nextCharCode = orgText.charCodeAt(offset2);
40517
- const chosenPatternIdxToConfig = getPossiblePatterns(nextCharCode);
40646
+ let chosenPatternIdxToConfig;
40647
+ if (isOptimizedMode) {
40648
+ const optimizedCharIdx = charCodeToOptimizedIndex(nextCharCode);
40649
+ const possiblePatterns = currCharCodeToPatternIdxToConfig[optimizedCharIdx];
40650
+ chosenPatternIdxToConfig = possiblePatterns !== void 0 ? possiblePatterns : emptyArray;
40651
+ } else {
40652
+ chosenPatternIdxToConfig = patternIdxToConfig;
40653
+ }
40518
40654
  const chosenPatternsLength = chosenPatternIdxToConfig.length;
40519
40655
  for (i = 0; i < chosenPatternsLength; i++) {
40520
40656
  currConfig = chosenPatternIdxToConfig[i];
@@ -40523,12 +40659,14 @@ var init_lexer_public = __esm({
40523
40659
  const singleCharCode = currConfig.short;
40524
40660
  if (singleCharCode !== false) {
40525
40661
  if (nextCharCode === singleCharCode) {
40662
+ imageLength = 1;
40526
40663
  matchedImage = currPattern;
40527
40664
  }
40528
40665
  } else if (currConfig.isCustom === true) {
40529
40666
  match2 = currPattern.exec(orgText, offset2, matchedTokens, groups);
40530
40667
  if (match2 !== null) {
40531
40668
  matchedImage = match2[0];
40669
+ imageLength = matchedImage.length;
40532
40670
  if (match2.payload !== void 0) {
40533
40671
  payload = match2.payload;
40534
40672
  }
@@ -40536,12 +40674,13 @@ var init_lexer_public = __esm({
40536
40674
  matchedImage = null;
40537
40675
  }
40538
40676
  } else {
40539
- this.updateLastIndex(currPattern, offset2);
40540
- matchedImage = this.match(currPattern, text, offset2);
40677
+ currPattern.lastIndex = offset2;
40678
+ imageLength = this.matchLength(currPattern, text, offset2);
40541
40679
  }
40542
- if (matchedImage !== null) {
40680
+ if (imageLength !== -1) {
40543
40681
  longerAlt = currConfig.longerAlt;
40544
40682
  if (longerAlt !== void 0) {
40683
+ matchedImage = text.substring(offset2, offset2 + imageLength);
40545
40684
  const longerAltLength = longerAlt.length;
40546
40685
  for (k = 0; k < longerAltLength; k++) {
40547
40686
  const longerAltConfig = patternIdxToConfig[longerAlt[k]];
@@ -40558,11 +40697,12 @@ var init_lexer_public = __esm({
40558
40697
  matchAltImage = null;
40559
40698
  }
40560
40699
  } else {
40561
- this.updateLastIndex(longerAltPattern, offset2);
40700
+ longerAltPattern.lastIndex = offset2;
40562
40701
  matchAltImage = this.match(longerAltPattern, text, offset2);
40563
40702
  }
40564
40703
  if (matchAltImage && matchAltImage.length > matchedImage.length) {
40565
40704
  matchedImage = matchAltImage;
40705
+ imageLength = matchAltImage.length;
40566
40706
  payload = altPayload;
40567
40707
  currConfig = longerAltConfig;
40568
40708
  break;
@@ -40572,10 +40712,10 @@ var init_lexer_public = __esm({
40572
40712
  break;
40573
40713
  }
40574
40714
  }
40575
- if (matchedImage !== null) {
40576
- imageLength = matchedImage.length;
40715
+ if (imageLength !== -1) {
40577
40716
  group = currConfig.group;
40578
40717
  if (group !== void 0) {
40718
+ matchedImage = matchedImage !== null ? matchedImage : text.substring(offset2, offset2 + imageLength);
40579
40719
  tokType = currConfig.tokenTypeIdx;
40580
40720
  newToken = this.createTokenInstance(matchedImage, offset2, tokType, currConfig.tokenType, line, column, imageLength);
40581
40721
  this.handlePayload(newToken, payload);
@@ -40585,15 +40725,13 @@ var init_lexer_public = __esm({
40585
40725
  groups[group].push(newToken);
40586
40726
  }
40587
40727
  }
40588
- text = this.chopInput(text, imageLength);
40589
- offset2 = offset2 + imageLength;
40590
- column = this.computeNewColumn(column, imageLength);
40591
40728
  if (trackLines === true && currConfig.canLineTerminator === true) {
40592
40729
  let numOfLTsInMatch = 0;
40593
40730
  let foundTerminator;
40594
40731
  let lastLTEndOffset;
40595
40732
  lineTerminatorPattern.lastIndex = 0;
40596
40733
  do {
40734
+ matchedImage = matchedImage !== null ? matchedImage : text.substring(offset2, offset2 + imageLength);
40597
40735
  foundTerminator = lineTerminatorPattern.test(matchedImage);
40598
40736
  if (foundTerminator === true) {
40599
40737
  lastLTEndOffset = lineTerminatorPattern.lastIndex - 1;
@@ -40604,8 +40742,13 @@ var init_lexer_public = __esm({
40604
40742
  line = line + numOfLTsInMatch;
40605
40743
  column = imageLength - lastLTEndOffset;
40606
40744
  this.updateTokenEndLineColumnLocation(newToken, group, lastLTEndOffset, numOfLTsInMatch, line, column, imageLength);
40745
+ } else {
40746
+ column = this.computeNewColumn(column, imageLength);
40607
40747
  }
40748
+ } else {
40749
+ column = this.computeNewColumn(column, imageLength);
40608
40750
  }
40751
+ offset2 = offset2 + imageLength;
40609
40752
  this.handleModes(currConfig, pop_mode, push_mode, newToken);
40610
40753
  } else {
40611
40754
  const errorStartOffset = offset2;
@@ -40613,7 +40756,6 @@ var init_lexer_public = __esm({
40613
40756
  const errorColumn = column;
40614
40757
  let foundResyncPoint = recoveryEnabled === false;
40615
40758
  while (foundResyncPoint === false && offset2 < orgLength) {
40616
- text = this.chopInput(text, 1);
40617
40759
  offset2++;
40618
40760
  for (j = 0; j < currModePatternsLength; j++) {
40619
40761
  const currConfig2 = patternIdxToConfig[j];
@@ -40626,7 +40768,7 @@ var init_lexer_public = __esm({
40626
40768
  } else if (currConfig2.isCustom === true) {
40627
40769
  foundResyncPoint = currPattern.exec(orgText, offset2, matchedTokens, groups) !== null;
40628
40770
  } else {
40629
- this.updateLastIndex(currPattern, offset2);
40771
+ currPattern.lastIndex = offset2;
40630
40772
  foundResyncPoint = currPattern.exec(text) !== null;
40631
40773
  }
40632
40774
  if (foundResyncPoint === true) {
@@ -40669,12 +40811,6 @@ var init_lexer_public = __esm({
40669
40811
  push_mode.call(this, config.push);
40670
40812
  }
40671
40813
  }
40672
- chopInput(text, length) {
40673
- return text.substring(length);
40674
- }
40675
- updateLastIndex(regExp, newLastIndex) {
40676
- regExp.lastIndex = newLastIndex;
40677
- }
40678
40814
  // TODO: decrease this under 600 characters? inspect stripping comments option in TSC compiler
40679
40815
  updateTokenEndLineColumnLocation(newToken, group, lastLTIdx, numOfLTsInMatch, line, column, imageLength) {
40680
40816
  let lastCharIsLT, fixForEndingInLT;
@@ -40737,16 +40873,19 @@ var init_lexer_public = __esm({
40737
40873
  token.payload = payload;
40738
40874
  }
40739
40875
  }
40740
- matchWithTest(pattern, text, offset2) {
40876
+ match(pattern, text, offset2) {
40741
40877
  const found = pattern.test(text);
40742
40878
  if (found === true) {
40743
40879
  return text.substring(offset2, pattern.lastIndex);
40744
40880
  }
40745
40881
  return null;
40746
40882
  }
40747
- matchWithExec(pattern, text) {
40748
- const regExpArray = pattern.exec(text);
40749
- return regExpArray !== null ? regExpArray[0] : null;
40883
+ matchLength(pattern, text, offset2) {
40884
+ const found = pattern.test(text);
40885
+ if (found === true) {
40886
+ return pattern.lastIndex - offset2;
40887
+ }
40888
+ return -1;
40750
40889
  }
40751
40890
  };
40752
40891
  Lexer.SKIPPED = "This marks a skipped Token pattern, this means each token identified by it will be consumed and then thrown into oblivion, this can be used to for example to completely ignore whitespace.";
@@ -40938,12 +41077,20 @@ For Further details.`;
40938
41077
  return errMsg;
40939
41078
  },
40940
41079
  buildAlternationAmbiguityError(options) {
40941
- const pathMsg = map_default(options.prefixPath, (currtok) => tokenLabel2(currtok)).join(", ");
40942
41080
  const occurrence = options.alternation.idx === 0 ? "" : options.alternation.idx;
41081
+ const isEmptyPath = options.prefixPath.length === 0;
40943
41082
  let currMessage = `Ambiguous Alternatives Detected: <${options.ambiguityIndices.join(" ,")}> in <OR${occurrence}> inside <${options.topLevelRule.name}> Rule,
40944
- <${pathMsg}> may appears as a prefix path in all these alternatives.
40945
41083
  `;
40946
- currMessage = currMessage + `See: https://chevrotain.io/docs/guide/resolving_grammar_errors.html#AMBIGUOUS_ALTERNATIVES
41084
+ if (isEmptyPath) {
41085
+ currMessage += `These alternatives are all empty (match no tokens), making them indistinguishable.
41086
+ Only the last alternative may be empty.
41087
+ `;
41088
+ } else {
41089
+ const pathMsg = map_default(options.prefixPath, (currtok) => tokenLabel2(currtok)).join(", ");
41090
+ currMessage += `<${pathMsg}> may appears as a prefix path in all these alternatives.
41091
+ `;
41092
+ }
41093
+ currMessage += `See: https://chevrotain.io/docs/guide/resolving_grammar_errors.html#AMBIGUOUS_ALTERNATIVES
40947
41094
  For Further details.`;
40948
41095
  return currMessage;
40949
41096
  },
@@ -47446,7 +47593,7 @@ function validateFlowchart(text, options = {}) {
47446
47593
  const byLine = /* @__PURE__ */ new Map();
47447
47594
  const collect = (arr) => {
47448
47595
  for (const e of arr || []) {
47449
- if (e && (e.code === "FL-LABEL-PARENS-UNQUOTED" || e.code === "FL-LABEL-AT-IN-UNQUOTED" || e.code === "FL-LABEL-QUOTE-IN-UNQUOTED")) {
47596
+ if (e && (e.code === "FL-LABEL-PARENS-UNQUOTED" || e.code === "FL-LABEL-AT-IN-UNQUOTED" || e.code === "FL-LABEL-QUOTE-IN-UNQUOTED" || e.code === "FL-LABEL-SLASH-UNQUOTED")) {
47450
47597
  const ln = e.line ?? 0;
47451
47598
  const col = e.column ?? 1;
47452
47599
  const list = byLine.get(ln) || [];
@@ -47529,6 +47676,7 @@ function validateFlowchart(text, options = {}) {
47529
47676
  const hasAt = seg.includes("@");
47530
47677
  const hasQuote = seg.includes('"');
47531
47678
  const isSingleQuoted = /^'[^]*'$/.test(trimmed);
47679
+ const hasLeadingSlash = lsp === "/" || lsp === "\\";
47532
47680
  if (!covered && !isQuoted && !isParenWrapped && hasParens) {
47533
47681
  errs.push({ line: ln, column: startCol, severity: "error", code: "FL-LABEL-PARENS-UNQUOTED", message: "Parentheses inside an unquoted label are not supported by Mermaid.", hint: 'Wrap the label in quotes, e.g., A["Mark (X)"] \u2014 or replace ( and ) with HTML entities: &#40; and &#41;.' });
47534
47682
  existing.push({ start: startCol, end: endCol });
@@ -47539,6 +47687,11 @@ function validateFlowchart(text, options = {}) {
47539
47687
  existing.push({ start: startCol, end: endCol });
47540
47688
  byLine.set(ln, existing);
47541
47689
  }
47690
+ if (!covered && !isQuoted && !isSlashPair && hasLeadingSlash) {
47691
+ errs.push({ line: ln, column: startCol, severity: "error", code: "FL-LABEL-SLASH-UNQUOTED", message: "Leading / or \\ inside an unquoted label is treated as a shape marker by Mermaid.", hint: 'Wrap the label in quotes, e.g., F["/dev/tty unavailable"], or use &#47; / &#92; for literal slashes.' });
47692
+ existing.push({ start: startCol, end: endCol });
47693
+ byLine.set(ln, existing);
47694
+ }
47542
47695
  if (!covered && !isQuoted && !isSlashPair && hasQuote && !isSingleQuoted) {
47543
47696
  errs.push({ line: ln, column: startCol, severity: "error", code: "FL-LABEL-QUOTE-IN-UNQUOTED", message: "Quotes are not allowed inside unquoted node labels. Use &quot; for quotes or wrap the entire label in quotes.", hint: 'Example: C["HTML Output: data-trigger-visibility=&quot;true&quot;"]' });
47544
47697
  existing.push({ start: startCol, end: endCol });
@@ -50547,7 +50700,7 @@ function computeFixes(text, errors, level = "safe") {
50547
50700
  }
50548
50701
  continue;
50549
50702
  }
50550
- if (is("FL-LABEL-PARENS-UNQUOTED", e) || is("FL-LABEL-AT-IN-UNQUOTED", e)) {
50703
+ if (is("FL-LABEL-PARENS-UNQUOTED", e) || is("FL-LABEL-AT-IN-UNQUOTED", e) || is("FL-LABEL-SLASH-UNQUOTED", e)) {
50551
50704
  if (level === "safe" || level === "all") {
50552
50705
  if (patchedLines.has(e.line))
50553
50706
  continue;
@@ -71842,6 +71995,7 @@ If the solution is clear, you can jump to implementation right away. If not, ask
71842
71995
  - Avoid implementing special cases when a general approach works
71843
71996
  - Never expose secrets, API keys, or credentials in generated code. Never log sensitive information.
71844
71997
  - 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.
71998
+ - 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.
71845
71999
  - After every significant change, verify the project still builds and passes linting. Do not wait until the end to discover breakage.
71846
72000
 
71847
72001
  # After Implementation
@@ -71852,11 +72006,33 @@ If the solution is clear, you can jump to implementation right away. If not, ask
71852
72006
 
71853
72007
  # GitHub Integration
71854
72008
  - Use the \`gh\` CLI for all GitHub operations: issues, pull requests, checks, releases.
71855
- - To create a pull request: commit your changes, push the branch, then use \`gh pr create --title "..." --body "..."\`.
71856
72009
  - To view issues or PRs: \`gh issue view <number>\`, \`gh pr view <number>\`.
71857
72010
  - If given a GitHub URL, use \`gh\` to fetch the relevant information rather than guessing.
71858
72011
  - Always return the pull request URL to the user after creating one.
71859
- - When checking GitHub Actions, only read logs of failed jobs \u2014 do not waste time on successful ones. Use \`gh run view <run-id> --log-failed\` to fetch only the relevant output.`,
72012
+ - When checking GitHub Actions, only read logs of failed jobs \u2014 do not waste time on successful ones. Use \`gh run view <run-id> --log-failed\` to fetch only the relevant output.
72013
+
72014
+ # Pull Request Creation
72015
+ - Commit your changes, push the branch, then use \`gh pr create --title "..." --body "..."\`.
72016
+ - **PR title**: Keep it short (under 72 characters). Use imperative mood describing the change (e.g. "Add retry logic for API calls", "Fix race condition in cache invalidation"). Prefix with the type of change when useful: \`fix:\`, \`feat:\`, \`refactor:\`, \`docs:\`, \`test:\`, \`chore:\`.
72017
+ - **PR body**: MUST follow this structure:
72018
+
72019
+ \`\`\`
72020
+ ## Problem / Task
72021
+ <What problem is being solved or what task was requested. If there is a linked issue, reference it with #number. Be specific about the root cause or motivation.>
72022
+
72023
+ ## Changes
72024
+ <Concise list of what was actually changed. Describe each meaningful change \u2014 files modified, logic added/removed, and why. Do NOT just list filenames; explain what each change does.>
72025
+
72026
+ ## Testing
72027
+ <What tests were added, modified, or run. Include:
72028
+ - New test names and what they verify
72029
+ - Whether existing tests still pass
72030
+ - Manual verification steps if applicable
72031
+ - Commands used to validate (e.g. \`make test\`, \`npm test\`)>
72032
+ \`\`\`
72033
+
72034
+ - If the task originated from a GitHub issue, always reference it in the PR body (e.g. "Fixes #123" or "Closes #123") so the issue is automatically closed on merge. If it originated from an external ticket system (Jira, Linear, etc.), include the ticket ID and link in the Problem / Task section (e.g. "Resolves PROJ-456").
72035
+ - Do not leave the PR body empty or vague. Every PR must clearly communicate what was done and why so reviewers can understand the change without reading every line of diff.`,
71860
72036
  "support": `You are ProbeChat Support, a specialized AI assistant focused on helping developers troubleshoot issues and solve problems. Your primary function is to help users diagnose errors, understand unexpected behaviors, and find solutions using the provided code analysis tools.
71861
72037
 
71862
72038
  When troubleshooting:
@@ -85122,6 +85298,7 @@ Follow these instructions carefully:
85122
85298
  * For rewriting entire functions/classes/methods, use the symbol parameter instead (no exact text matching needed).
85123
85299
  * For editing specific lines from search/extract output, use start_line (and optionally end_line) with the line numbers shown in the output.${this.hashLines ? ' Line references include content hashes (e.g. "42:ab") for integrity verification.' : ""}
85124
85300
  * 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.
85301
+ * IMPORTANT: Keep old_string as small as possible \u2014 include only the lines you need to change plus minimal context for uniqueness. For replacing large blocks (10+ lines), prefer line-targeted editing with start_line/end_line to constrain scope.
85125
85302
  - Use 'create' for new files or complete file rewrites.
85126
85303
  - If an edit fails, read the error message \u2014 it tells you exactly how to fix the call and retry.
85127
85304
  - The system tracks which files you've seen via search/extract. If you try to edit a file you haven't read, or one that changed since you last read it, the edit will fail with instructions to re-read first. Always use extract before editing to ensure you have current file content.` : ""}
@@ -87,6 +87,7 @@ If the solution is clear, you can jump to implementation right away. If not, ask
87
87
  - Avoid implementing special cases when a general approach works
88
88
  - Never expose secrets, API keys, or credentials in generated code. Never log sensitive information.
89
89
  - 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.
90
+ - 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.
90
91
  - After every significant change, verify the project still builds and passes linting. Do not wait until the end to discover breakage.
91
92
 
92
93
  # After Implementation
@@ -97,11 +98,33 @@ If the solution is clear, you can jump to implementation right away. If not, ask
97
98
 
98
99
  # GitHub Integration
99
100
  - Use the \`gh\` CLI for all GitHub operations: issues, pull requests, checks, releases.
100
- - To create a pull request: commit your changes, push the branch, then use \`gh pr create --title "..." --body "..."\`.
101
101
  - To view issues or PRs: \`gh issue view <number>\`, \`gh pr view <number>\`.
102
102
  - If given a GitHub URL, use \`gh\` to fetch the relevant information rather than guessing.
103
103
  - Always return the pull request URL to the user after creating one.
104
- - When checking GitHub Actions, only read logs of failed jobs — do not waste time on successful ones. Use \`gh run view <run-id> --log-failed\` to fetch only the relevant output.`,
104
+ - When checking GitHub Actions, only read logs of failed jobs — do not waste time on successful ones. Use \`gh run view <run-id> --log-failed\` to fetch only the relevant output.
105
+
106
+ # Pull Request Creation
107
+ - Commit your changes, push the branch, then use \`gh pr create --title "..." --body "..."\`.
108
+ - **PR title**: Keep it short (under 72 characters). Use imperative mood describing the change (e.g. "Add retry logic for API calls", "Fix race condition in cache invalidation"). Prefix with the type of change when useful: \`fix:\`, \`feat:\`, \`refactor:\`, \`docs:\`, \`test:\`, \`chore:\`.
109
+ - **PR body**: MUST follow this structure:
110
+
111
+ \`\`\`
112
+ ## Problem / Task
113
+ <What problem is being solved or what task was requested. If there is a linked issue, reference it with #number. Be specific about the root cause or motivation.>
114
+
115
+ ## Changes
116
+ <Concise list of what was actually changed. Describe each meaningful change — files modified, logic added/removed, and why. Do NOT just list filenames; explain what each change does.>
117
+
118
+ ## Testing
119
+ <What tests were added, modified, or run. Include:
120
+ - New test names and what they verify
121
+ - Whether existing tests still pass
122
+ - Manual verification steps if applicable
123
+ - Commands used to validate (e.g. \`make test\`, \`npm test\`)>
124
+ \`\`\`
125
+
126
+ - If the task originated from a GitHub issue, always reference it in the PR body (e.g. "Fixes #123" or "Closes #123") so the issue is automatically closed on merge. If it originated from an external ticket system (Jira, Linear, etc.), include the ticket ID and link in the Problem / Task section (e.g. "Resolves PROJ-456").
127
+ - Do not leave the PR body empty or vague. Every PR must clearly communicate what was done and why so reviewers can understand the change without reading every line of diff.`,
105
128
 
106
129
  'support': `You are ProbeChat Support, a specialized AI assistant focused on helping developers troubleshoot issues and solve problems. Your primary function is to help users diagnose errors, understand unexpected behaviors, and find solutions using the provided code analysis tools.
107
130