@probelabs/probe 0.6.0-rc254 → 0.6.0-rc256

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/README.md +166 -3
  2. package/bin/binaries/probe-v0.6.0-rc256-aarch64-apple-darwin.tar.gz +0 -0
  3. package/bin/binaries/probe-v0.6.0-rc256-aarch64-unknown-linux-musl.tar.gz +0 -0
  4. package/bin/binaries/probe-v0.6.0-rc256-x86_64-apple-darwin.tar.gz +0 -0
  5. package/bin/binaries/probe-v0.6.0-rc256-x86_64-pc-windows-msvc.zip +0 -0
  6. package/bin/binaries/probe-v0.6.0-rc256-x86_64-unknown-linux-musl.tar.gz +0 -0
  7. package/build/agent/ProbeAgent.d.ts +1 -1
  8. package/build/agent/ProbeAgent.js +39 -23
  9. package/build/agent/acp/tools.js +2 -1
  10. package/build/agent/acp/tools.test.js +2 -1
  11. package/build/agent/bashDefaults.js +75 -6
  12. package/build/agent/index.js +1752 -426
  13. package/build/agent/mcp/xmlBridge.js +3 -2
  14. package/build/agent/schemaUtils.js +127 -0
  15. package/build/agent/tools.js +0 -28
  16. package/build/delegate.js +3 -0
  17. package/build/index.js +2 -0
  18. package/build/tools/common.js +26 -8
  19. package/build/tools/edit.js +457 -65
  20. package/build/tools/fileTracker.js +318 -0
  21. package/build/tools/fuzzyMatch.js +271 -0
  22. package/build/tools/hashline.js +131 -0
  23. package/build/tools/lineEditHeuristics.js +138 -0
  24. package/build/tools/symbolEdit.js +119 -0
  25. package/build/tools/vercel.js +40 -9
  26. package/cjs/agent/ProbeAgent.cjs +1863 -528
  27. package/cjs/index.cjs +1891 -554
  28. package/index.d.ts +189 -1
  29. package/package.json +1 -1
  30. package/src/agent/ProbeAgent.d.ts +1 -1
  31. package/src/agent/ProbeAgent.js +39 -23
  32. package/src/agent/acp/tools.js +2 -1
  33. package/src/agent/acp/tools.test.js +2 -1
  34. package/src/agent/bashDefaults.js +75 -6
  35. package/src/agent/index.js +18 -7
  36. package/src/agent/mcp/xmlBridge.js +3 -2
  37. package/src/agent/schemaUtils.js +127 -0
  38. package/src/agent/tools.js +0 -28
  39. package/src/delegate.js +3 -0
  40. package/src/index.js +2 -0
  41. package/src/tools/common.js +26 -8
  42. package/src/tools/edit.js +457 -65
  43. package/src/tools/fileTracker.js +318 -0
  44. package/src/tools/fuzzyMatch.js +271 -0
  45. package/src/tools/hashline.js +131 -0
  46. package/src/tools/lineEditHeuristics.js +138 -0
  47. package/src/tools/symbolEdit.js +119 -0
  48. package/src/tools/vercel.js +40 -9
  49. package/bin/binaries/probe-v0.6.0-rc254-aarch64-apple-darwin.tar.gz +0 -0
  50. package/bin/binaries/probe-v0.6.0-rc254-aarch64-unknown-linux-musl.tar.gz +0 -0
  51. package/bin/binaries/probe-v0.6.0-rc254-x86_64-apple-darwin.tar.gz +0 -0
  52. package/bin/binaries/probe-v0.6.0-rc254-x86_64-pc-windows-msvc.zip +0 -0
  53. package/bin/binaries/probe-v0.6.0-rc254-x86_64-unknown-linux-musl.tar.gz +0 -0
@@ -1844,6 +1844,7 @@ var require_ChecksumStream = __commonJS({
1844
1844
  checksum;
1845
1845
  source;
1846
1846
  base64Encoder;
1847
+ pendingCallback = null;
1847
1848
  constructor({ expectedChecksum, checksum, source, checksumSourceLocation, base64Encoder }) {
1848
1849
  super();
1849
1850
  if (typeof source.pipe === "function") {
@@ -1858,11 +1859,20 @@ var require_ChecksumStream = __commonJS({
1858
1859
  this.source.pipe(this);
1859
1860
  }
1860
1861
  _read(size) {
1862
+ if (this.pendingCallback) {
1863
+ const callback = this.pendingCallback;
1864
+ this.pendingCallback = null;
1865
+ callback();
1866
+ }
1861
1867
  }
1862
1868
  _write(chunk, encoding, callback) {
1863
1869
  try {
1864
1870
  this.checksum.update(chunk);
1865
- this.push(chunk);
1871
+ const canPushMore = this.push(chunk);
1872
+ if (!canPushMore) {
1873
+ this.pendingCallback = callback;
1874
+ return;
1875
+ }
1866
1876
  } catch (e5) {
1867
1877
  return callback(e5);
1868
1878
  }
@@ -2329,7 +2339,7 @@ var require_headStream = __commonJS({
2329
2339
  if ((0, stream_type_check_1.isReadableStream)(stream2)) {
2330
2340
  return (0, headStream_browser_1.headStream)(stream2, bytes);
2331
2341
  }
2332
- return new Promise((resolve7, reject2) => {
2342
+ return new Promise((resolve8, reject2) => {
2333
2343
  const collector = new Collector();
2334
2344
  collector.limit = bytes;
2335
2345
  stream2.pipe(collector);
@@ -2340,7 +2350,7 @@ var require_headStream = __commonJS({
2340
2350
  collector.on("error", reject2);
2341
2351
  collector.on("finish", function() {
2342
2352
  const bytes2 = new Uint8Array(Buffer.concat(this.buffers));
2343
- resolve7(bytes2);
2353
+ resolve8(bytes2);
2344
2354
  });
2345
2355
  });
2346
2356
  };
@@ -2528,21 +2538,21 @@ var require_dist_cjs15 = __commonJS({
2528
2538
  let sendBody = true;
2529
2539
  if (!externalAgent && expect === "100-continue") {
2530
2540
  sendBody = await Promise.race([
2531
- new Promise((resolve7) => {
2532
- timeoutId = Number(timing.setTimeout(() => resolve7(true), Math.max(MIN_WAIT_TIME, maxContinueTimeoutMs)));
2541
+ new Promise((resolve8) => {
2542
+ timeoutId = Number(timing.setTimeout(() => resolve8(true), Math.max(MIN_WAIT_TIME, maxContinueTimeoutMs)));
2533
2543
  }),
2534
- new Promise((resolve7) => {
2544
+ new Promise((resolve8) => {
2535
2545
  httpRequest.on("continue", () => {
2536
2546
  timing.clearTimeout(timeoutId);
2537
- resolve7(true);
2547
+ resolve8(true);
2538
2548
  });
2539
2549
  httpRequest.on("response", () => {
2540
2550
  timing.clearTimeout(timeoutId);
2541
- resolve7(false);
2551
+ resolve8(false);
2542
2552
  });
2543
2553
  httpRequest.on("error", () => {
2544
2554
  timing.clearTimeout(timeoutId);
2545
- resolve7(false);
2555
+ resolve8(false);
2546
2556
  });
2547
2557
  })
2548
2558
  ]);
@@ -2614,13 +2624,13 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
2614
2624
  return socketWarningTimestamp;
2615
2625
  }
2616
2626
  constructor(options) {
2617
- this.configProvider = new Promise((resolve7, reject2) => {
2627
+ this.configProvider = new Promise((resolve8, reject2) => {
2618
2628
  if (typeof options === "function") {
2619
2629
  options().then((_options) => {
2620
- resolve7(this.resolveDefaultConfig(_options));
2630
+ resolve8(this.resolveDefaultConfig(_options));
2621
2631
  }).catch(reject2);
2622
2632
  } else {
2623
- resolve7(this.resolveDefaultConfig(options));
2633
+ resolve8(this.resolveDefaultConfig(options));
2624
2634
  }
2625
2635
  });
2626
2636
  }
@@ -2663,7 +2673,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
2663
2673
  const config = this.config;
2664
2674
  let writeRequestBodyPromise = void 0;
2665
2675
  const timeouts = [];
2666
- const resolve7 = async (arg) => {
2676
+ const resolve8 = async (arg) => {
2667
2677
  await writeRequestBodyPromise;
2668
2678
  timeouts.forEach(timing.clearTimeout);
2669
2679
  _resolve(arg);
@@ -2729,7 +2739,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
2729
2739
  headers: getTransformedHeaders(res.headers),
2730
2740
  body: res
2731
2741
  });
2732
- resolve7({ response: httpResponse });
2742
+ resolve8({ response: httpResponse });
2733
2743
  });
2734
2744
  req.on("error", (err) => {
2735
2745
  if (NODEJS_TIMEOUT_ERROR_CODES.includes(err.code)) {
@@ -2909,13 +2919,13 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
2909
2919
  return new _NodeHttp2Handler(instanceOrOptions);
2910
2920
  }
2911
2921
  constructor(options) {
2912
- this.configProvider = new Promise((resolve7, reject2) => {
2922
+ this.configProvider = new Promise((resolve8, reject2) => {
2913
2923
  if (typeof options === "function") {
2914
2924
  options().then((opts) => {
2915
- resolve7(opts || {});
2925
+ resolve8(opts || {});
2916
2926
  }).catch(reject2);
2917
2927
  } else {
2918
- resolve7(options || {});
2928
+ resolve8(options || {});
2919
2929
  }
2920
2930
  });
2921
2931
  }
@@ -2935,7 +2945,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
2935
2945
  return new Promise((_resolve, _reject) => {
2936
2946
  let fulfilled = false;
2937
2947
  let writeRequestBodyPromise = void 0;
2938
- const resolve7 = async (arg) => {
2948
+ const resolve8 = async (arg) => {
2939
2949
  await writeRequestBodyPromise;
2940
2950
  _resolve(arg);
2941
2951
  };
@@ -2991,7 +3001,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
2991
3001
  body: req
2992
3002
  });
2993
3003
  fulfilled = true;
2994
- resolve7({ response: httpResponse });
3004
+ resolve8({ response: httpResponse });
2995
3005
  if (disableConcurrentStreams) {
2996
3006
  session.close();
2997
3007
  this.connectionManager.deleteSession(authority, session);
@@ -3068,7 +3078,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
3068
3078
  if (isReadableStreamInstance(stream3)) {
3069
3079
  return collectReadableStream(stream3);
3070
3080
  }
3071
- return new Promise((resolve7, reject2) => {
3081
+ return new Promise((resolve8, reject2) => {
3072
3082
  const collector = new Collector();
3073
3083
  stream3.pipe(collector);
3074
3084
  stream3.on("error", (err) => {
@@ -3078,7 +3088,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
3078
3088
  collector.on("error", reject2);
3079
3089
  collector.on("finish", function() {
3080
3090
  const bytes = new Uint8Array(Buffer.concat(this.bufferedBytes));
3081
- resolve7(bytes);
3091
+ resolve8(bytes);
3082
3092
  });
3083
3093
  });
3084
3094
  };
@@ -3122,7 +3132,7 @@ var require_dist_cjs16 = __commonJS({
3122
3132
  return new Request(url, requestOptions);
3123
3133
  }
3124
3134
  function requestTimeout(timeoutInMs = 0) {
3125
- return new Promise((resolve7, reject2) => {
3135
+ return new Promise((resolve8, reject2) => {
3126
3136
  if (timeoutInMs) {
3127
3137
  setTimeout(() => {
3128
3138
  const timeoutError = new Error(`Request did not complete within ${timeoutInMs} ms`);
@@ -3240,7 +3250,7 @@ var require_dist_cjs16 = __commonJS({
3240
3250
  requestTimeout(requestTimeoutInMs)
3241
3251
  ];
3242
3252
  if (abortSignal) {
3243
- raceOfPromises.push(new Promise((resolve7, reject2) => {
3253
+ raceOfPromises.push(new Promise((resolve8, reject2) => {
3244
3254
  const onAbort = () => {
3245
3255
  const abortError = new Error("Request aborted");
3246
3256
  abortError.name = "AbortError";
@@ -3304,7 +3314,7 @@ var require_dist_cjs16 = __commonJS({
3304
3314
  return collected;
3305
3315
  }
3306
3316
  function readToBase64(blob) {
3307
- return new Promise((resolve7, reject2) => {
3317
+ return new Promise((resolve8, reject2) => {
3308
3318
  const reader = new FileReader();
3309
3319
  reader.onloadend = () => {
3310
3320
  if (reader.readyState !== 2) {
@@ -3313,7 +3323,7 @@ var require_dist_cjs16 = __commonJS({
3313
3323
  const result = reader.result ?? "";
3314
3324
  const commaIndex = result.indexOf(",");
3315
3325
  const dataOffset = commaIndex > -1 ? commaIndex + 1 : result.length;
3316
- resolve7(result.substring(dataOffset));
3326
+ resolve8(result.substring(dataOffset));
3317
3327
  };
3318
3328
  reader.onabort = () => reject2(new Error("Read aborted"));
3319
3329
  reader.onerror = () => reject2(reader.error);
@@ -4981,11 +4991,11 @@ function __metadata(metadataKey, metadataValue) {
4981
4991
  }
4982
4992
  function __awaiter(thisArg, _arguments, P, generator) {
4983
4993
  function adopt(value) {
4984
- return value instanceof P ? value : new P(function(resolve7) {
4985
- resolve7(value);
4994
+ return value instanceof P ? value : new P(function(resolve8) {
4995
+ resolve8(value);
4986
4996
  });
4987
4997
  }
4988
- return new (P || (P = Promise))(function(resolve7, reject2) {
4998
+ return new (P || (P = Promise))(function(resolve8, reject2) {
4989
4999
  function fulfilled(value) {
4990
5000
  try {
4991
5001
  step(generator.next(value));
@@ -5001,7 +5011,7 @@ function __awaiter(thisArg, _arguments, P, generator) {
5001
5011
  }
5002
5012
  }
5003
5013
  function step(result) {
5004
- result.done ? resolve7(result.value) : adopt(result.value).then(fulfilled, rejected);
5014
+ result.done ? resolve8(result.value) : adopt(result.value).then(fulfilled, rejected);
5005
5015
  }
5006
5016
  step((generator = generator.apply(thisArg, _arguments || [])).next());
5007
5017
  });
@@ -5192,14 +5202,14 @@ function __asyncValues(o5) {
5192
5202
  }, i5);
5193
5203
  function verb(n5) {
5194
5204
  i5[n5] = o5[n5] && function(v5) {
5195
- return new Promise(function(resolve7, reject2) {
5196
- v5 = o5[n5](v5), settle(resolve7, reject2, v5.done, v5.value);
5205
+ return new Promise(function(resolve8, reject2) {
5206
+ v5 = o5[n5](v5), settle(resolve8, reject2, v5.done, v5.value);
5197
5207
  });
5198
5208
  };
5199
5209
  }
5200
- function settle(resolve7, reject2, d5, v5) {
5210
+ function settle(resolve8, reject2, d5, v5) {
5201
5211
  Promise.resolve(v5).then(function(v6) {
5202
- resolve7({ value: v6, done: d5 });
5212
+ resolve8({ value: v6, done: d5 });
5203
5213
  }, reject2);
5204
5214
  }
5205
5215
  }
@@ -15600,7 +15610,7 @@ var require_dist_cjs37 = __commonJS({
15600
15610
  this.sockets[url] = (this.sockets[url] ?? []).filter((socket) => ![WebSocket.CLOSING, WebSocket.CLOSED].includes(socket.readyState));
15601
15611
  }
15602
15612
  waitForReady(socket, connectionTimeout) {
15603
- return new Promise((resolve7, reject2) => {
15613
+ return new Promise((resolve8, reject2) => {
15604
15614
  const timeout = setTimeout(() => {
15605
15615
  this.removeNotUsableSockets(socket.url);
15606
15616
  reject2({
@@ -15612,7 +15622,7 @@ var require_dist_cjs37 = __commonJS({
15612
15622
  }, connectionTimeout);
15613
15623
  socket.onopen = () => {
15614
15624
  clearTimeout(timeout);
15615
- resolve7();
15625
+ resolve8();
15616
15626
  };
15617
15627
  });
15618
15628
  }
@@ -15665,8 +15675,8 @@ var require_dist_cjs37 = __commonJS({
15665
15675
  }
15666
15676
  return { done: item.done, value: item.value };
15667
15677
  }
15668
- return new Promise((resolve7, reject2) => {
15669
- pendingResolve = resolve7;
15678
+ return new Promise((resolve8, reject2) => {
15679
+ pendingResolve = resolve8;
15670
15680
  pendingReject = reject2;
15671
15681
  });
15672
15682
  }
@@ -16879,7 +16889,7 @@ var require_dist_cjs46 = __commonJS({
16879
16889
  this.refillTokenBucket();
16880
16890
  if (amount > this.currentCapacity) {
16881
16891
  const delay = (amount - this.currentCapacity) / this.fillRate * 1e3;
16882
- await new Promise((resolve7) => _DefaultRateLimiter.setTimeoutFn(resolve7, delay));
16892
+ await new Promise((resolve8) => _DefaultRateLimiter.setTimeoutFn(resolve8, delay));
16883
16893
  }
16884
16894
  this.currentCapacity = this.currentCapacity - amount;
16885
16895
  }
@@ -17214,7 +17224,7 @@ var require_dist_cjs47 = __commonJS({
17214
17224
  const delayFromResponse = getDelayFromRetryAfterHeader(err.$response);
17215
17225
  const delay = Math.max(delayFromResponse || 0, delayFromDecider);
17216
17226
  totalDelay += delay;
17217
- await new Promise((resolve7) => setTimeout(resolve7, delay));
17227
+ await new Promise((resolve8) => setTimeout(resolve8, delay));
17218
17228
  continue;
17219
17229
  }
17220
17230
  if (!err.$metadata) {
@@ -17372,7 +17382,7 @@ var require_dist_cjs47 = __commonJS({
17372
17382
  attempts = retryToken.getRetryCount();
17373
17383
  const delay = retryToken.getRetryDelay();
17374
17384
  totalRetryDelay += delay;
17375
- await new Promise((resolve7) => setTimeout(resolve7, delay));
17385
+ await new Promise((resolve8) => setTimeout(resolve8, delay));
17376
17386
  }
17377
17387
  }
17378
17388
  } else {
@@ -17524,7 +17534,7 @@ var require_package2 = __commonJS({
17524
17534
  module2.exports = {
17525
17535
  name: "@aws-sdk/client-bedrock-runtime",
17526
17536
  description: "AWS SDK for JavaScript Bedrock Runtime Client for Node.js, Browser and React Native",
17527
- version: "3.994.0",
17537
+ version: "3.995.0",
17528
17538
  scripts: {
17529
17539
  build: "concurrently 'yarn:build:types' 'yarn:build:es' && yarn build:cjs",
17530
17540
  "build:cjs": "node ../../scripts/compilation/inline client-bedrock-runtime",
@@ -17554,11 +17564,11 @@ var require_package2 = __commonJS({
17554
17564
  "@aws-sdk/middleware-user-agent": "^3.972.11",
17555
17565
  "@aws-sdk/middleware-websocket": "^3.972.6",
17556
17566
  "@aws-sdk/region-config-resolver": "^3.972.3",
17557
- "@aws-sdk/token-providers": "3.994.0",
17567
+ "@aws-sdk/token-providers": "3.995.0",
17558
17568
  "@aws-sdk/types": "^3.973.1",
17559
- "@aws-sdk/util-endpoints": "3.994.0",
17569
+ "@aws-sdk/util-endpoints": "3.995.0",
17560
17570
  "@aws-sdk/util-user-agent-browser": "^3.972.3",
17561
- "@aws-sdk/util-user-agent-node": "^3.972.9",
17571
+ "@aws-sdk/util-user-agent-node": "^3.972.10",
17562
17572
  "@smithy/config-resolver": "^4.4.6",
17563
17573
  "@smithy/core": "^3.23.2",
17564
17574
  "@smithy/eventstream-serde-browser": "^4.2.8",
@@ -17687,7 +17697,7 @@ var require_dist_cjs49 = __commonJS({
17687
17697
  var nodeConfigProvider = require_dist_cjs43();
17688
17698
  var urlParser = require_dist_cjs22();
17689
17699
  function httpRequest(options) {
17690
- return new Promise((resolve7, reject2) => {
17700
+ return new Promise((resolve8, reject2) => {
17691
17701
  const req = http.request({
17692
17702
  method: "GET",
17693
17703
  ...options,
@@ -17712,7 +17722,7 @@ var require_dist_cjs49 = __commonJS({
17712
17722
  chunks.push(chunk);
17713
17723
  });
17714
17724
  res.on("end", () => {
17715
- resolve7(buffer.Buffer.concat(chunks));
17725
+ resolve8(buffer.Buffer.concat(chunks));
17716
17726
  req.destroy();
17717
17727
  });
17718
17728
  });
@@ -18132,7 +18142,7 @@ var require_retry_wrapper = __commonJS({
18132
18142
  try {
18133
18143
  return await toRetry();
18134
18144
  } catch (e5) {
18135
- await new Promise((resolve7) => setTimeout(resolve7, delayMs));
18145
+ await new Promise((resolve8) => setTimeout(resolve8, delayMs));
18136
18146
  }
18137
18147
  }
18138
18148
  return await toRetry();
@@ -18440,6 +18450,15 @@ var require_dist_cjs51 = __commonJS({
18440
18450
  var os4 = require("os");
18441
18451
  var process2 = require("process");
18442
18452
  var middlewareUserAgent = require_dist_cjs29();
18453
+ var getRuntimeUserAgentPair = () => {
18454
+ const runtimesToCheck = ["deno", "bun", "llrt"];
18455
+ for (const runtime of runtimesToCheck) {
18456
+ if (process2.versions[runtime]) {
18457
+ return [`md/${runtime}`, process2.versions[runtime]];
18458
+ }
18459
+ }
18460
+ return ["md/nodejs", process2.versions.node];
18461
+ };
18443
18462
  var crtAvailability = {
18444
18463
  isCrtAvailable: false
18445
18464
  };
@@ -18450,13 +18469,14 @@ var require_dist_cjs51 = __commonJS({
18450
18469
  return null;
18451
18470
  };
18452
18471
  var createDefaultUserAgentProvider5 = ({ serviceId, clientVersion }) => {
18472
+ const runtimeUserAgentPair = getRuntimeUserAgentPair();
18453
18473
  return async (config) => {
18454
18474
  const sections = [
18455
18475
  ["aws-sdk-js", clientVersion],
18456
18476
  ["ua", "2.1"],
18457
18477
  [`os/${os4.platform()}`, os4.release()],
18458
18478
  ["lang/js"],
18459
- ["md/nodejs", `${process2.versions.node}`]
18479
+ runtimeUserAgentPair
18460
18480
  ];
18461
18481
  const crtAvailable = isCrtAvailable();
18462
18482
  if (crtAvailable) {
@@ -24019,8 +24039,8 @@ var require_dist_cjs66 = __commonJS({
24019
24039
  systemClockOffsetProvider: this.systemClockOffsetProvider
24020
24040
  });
24021
24041
  let resolvePipeline;
24022
- const pipelineError = new Promise((resolve7, reject2) => {
24023
- resolvePipeline = () => resolve7(void 0);
24042
+ const pipelineError = new Promise((resolve8, reject2) => {
24043
+ resolvePipeline = () => resolve8(void 0);
24024
24044
  node_stream.pipeline(payloadStream, signingStream, request.body, (err) => {
24025
24045
  if (err) {
24026
24046
  reject2(new Error(`Pipeline error in @aws-sdk/eventstream-handler-node: ${err.message}`, { cause: err }));
@@ -24126,7 +24146,7 @@ var init_package2 = __esm({
24126
24146
  "node_modules/@aws-sdk/token-providers/node_modules/@aws-sdk/nested-clients/package.json"() {
24127
24147
  package_default2 = {
24128
24148
  name: "@aws-sdk/nested-clients",
24129
- version: "3.994.0",
24149
+ version: "3.995.0",
24130
24150
  description: "Nested clients for AWS SDK packages.",
24131
24151
  main: "./dist-cjs/index.js",
24132
24152
  module: "./dist-es/index.js",
@@ -24162,9 +24182,9 @@ var init_package2 = __esm({
24162
24182
  "@aws-sdk/middleware-user-agent": "^3.972.11",
24163
24183
  "@aws-sdk/region-config-resolver": "^3.972.3",
24164
24184
  "@aws-sdk/types": "^3.973.1",
24165
- "@aws-sdk/util-endpoints": "3.994.0",
24185
+ "@aws-sdk/util-endpoints": "3.995.0",
24166
24186
  "@aws-sdk/util-user-agent-browser": "^3.972.3",
24167
- "@aws-sdk/util-user-agent-node": "^3.972.9",
24187
+ "@aws-sdk/util-user-agent-node": "^3.972.10",
24168
24188
  "@smithy/config-resolver": "^4.4.6",
24169
24189
  "@smithy/core": "^3.23.2",
24170
24190
  "@smithy/fetch-http-handler": "^5.3.9",
@@ -25574,7 +25594,7 @@ var require_dist_cjs69 = __commonJS({
25574
25594
  streamEnded = true;
25575
25595
  });
25576
25596
  while (!generationEnded) {
25577
- const value = await new Promise((resolve7) => setTimeout(() => resolve7(records.shift()), 0));
25597
+ const value = await new Promise((resolve8) => setTimeout(() => resolve8(records.shift()), 0));
25578
25598
  if (value) {
25579
25599
  yield value;
25580
25600
  }
@@ -31837,7 +31857,7 @@ async function waitForFileLock(lockPath, binaryPath) {
31837
31857
  }
31838
31858
  } catch {
31839
31859
  }
31840
- await new Promise((resolve7) => setTimeout(resolve7, LOCK_POLL_INTERVAL_MS));
31860
+ await new Promise((resolve8) => setTimeout(resolve8, LOCK_POLL_INTERVAL_MS));
31841
31861
  }
31842
31862
  if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
31843
31863
  console.log(`Timeout waiting for file lock`);
@@ -33186,7 +33206,7 @@ Cwd: ${cwd}`;
33186
33206
  }
33187
33207
  }
33188
33208
  function extractWithStdin(binaryPath, cliArgs, content, options, cwd) {
33189
- return new Promise((resolve7, reject2) => {
33209
+ return new Promise((resolve8, reject2) => {
33190
33210
  const childProcess = (0, import_child_process4.spawn)(binaryPath, ["extract", ...cliArgs], {
33191
33211
  stdio: ["pipe", "pipe", "pipe"],
33192
33212
  cwd
@@ -33209,7 +33229,7 @@ function extractWithStdin(binaryPath, cliArgs, content, options, cwd) {
33209
33229
  }
33210
33230
  try {
33211
33231
  const result = processExtractOutput(stdout, options);
33212
- resolve7(result);
33232
+ resolve8(result);
33213
33233
  } catch (error2) {
33214
33234
  reject2(error2);
33215
33235
  }
@@ -33318,6 +33338,7 @@ async function delegate({
33318
33338
  model = null,
33319
33339
  enableBash = false,
33320
33340
  bashConfig = null,
33341
+ allowEdit = false,
33321
33342
  architectureFileName = null,
33322
33343
  promptType = "code-researcher",
33323
33344
  allowedTools = null,
@@ -33397,6 +33418,8 @@ async function delegate({
33397
33418
  // Inherit from parent
33398
33419
  bashConfig,
33399
33420
  // Inherit from parent
33421
+ allowEdit,
33422
+ // Inherit from parent
33400
33423
  architectureFileName,
33401
33424
  allowedTools,
33402
33425
  disableTools,
@@ -33582,7 +33605,7 @@ var init_delegate = __esm({
33582
33605
  if (debug) {
33583
33606
  console.error(`[DelegationManager] Slot unavailable (${this.globalActive}/${this.maxConcurrent}), queuing... (queue size: ${this.waitQueue.length}, timeout: ${effectiveTimeout}ms)`);
33584
33607
  }
33585
- return new Promise((resolve7, reject2) => {
33608
+ return new Promise((resolve8, reject2) => {
33586
33609
  const entry = {
33587
33610
  resolve: null,
33588
33611
  // Will be wrapped below
@@ -33598,7 +33621,7 @@ var init_delegate = __esm({
33598
33621
  if (settled) return;
33599
33622
  settled = true;
33600
33623
  if (entry.timeoutId) clearTimeout(entry.timeoutId);
33601
- resolve7(value);
33624
+ resolve8(value);
33602
33625
  };
33603
33626
  entry.reject = (error2) => {
33604
33627
  if (settled) return;
@@ -33648,7 +33671,7 @@ var init_delegate = __esm({
33648
33671
  while (this.waitQueue.length > 0 && this.globalActive < this.maxConcurrent) {
33649
33672
  const next = this.waitQueue.shift();
33650
33673
  if (!next) break;
33651
- const { resolve: resolve7, reject: reject2, parentSessionId, queuedAt } = next;
33674
+ const { resolve: resolve8, reject: reject2, parentSessionId, queuedAt } = next;
33652
33675
  if (parentSessionId) {
33653
33676
  const sessionData = this.sessionDelegations.get(parentSessionId);
33654
33677
  const sessionCount = sessionData?.count || 0;
@@ -33665,12 +33688,12 @@ var init_delegate = __esm({
33665
33688
  const waitTime = Date.now() - queuedAt;
33666
33689
  console.error(`[DelegationManager] Granted slot from queue (waited ${waitTime}ms). Active: ${this.globalActive}/${this.maxConcurrent}`);
33667
33690
  }
33668
- toResolve.push(resolve7);
33691
+ toResolve.push(resolve8);
33669
33692
  }
33670
33693
  if (toResolve.length > 0 || toReject.length > 0) {
33671
33694
  setImmediate(() => {
33672
- for (const resolve7 of toResolve) {
33673
- resolve7(true);
33695
+ for (const resolve8 of toResolve) {
33696
+ resolve8(true);
33674
33697
  }
33675
33698
  for (const { reject: reject2, error: error2 } of toReject) {
33676
33699
  reject2(error2);
@@ -38305,6 +38328,400 @@ var init_zod = __esm({
38305
38328
  }
38306
38329
  });
38307
38330
 
38331
+ // src/tools/fuzzyMatch.js
38332
+ function findFuzzyMatch(content, searchString) {
38333
+ if (!searchString || searchString.trim().length === 0) {
38334
+ return null;
38335
+ }
38336
+ const normalizedContent = content.replace(/\r\n/g, "\n");
38337
+ const normalizedSearch = searchString.replace(/\r\n/g, "\n");
38338
+ const contentLines = normalizedContent.split("\n");
38339
+ const searchLines = normalizedSearch.split("\n");
38340
+ const trimmed = lineTrimmedMatch(contentLines, searchLines);
38341
+ if (trimmed) return { ...trimmed, strategy: "line-trimmed" };
38342
+ const normalized = whitespaceNormalizedMatch(normalizedContent, normalizedSearch);
38343
+ if (normalized) return { ...normalized, strategy: "whitespace-normalized" };
38344
+ const indentFlex = indentFlexibleMatch(contentLines, searchLines);
38345
+ if (indentFlex) return { ...indentFlex, strategy: "indent-flexible" };
38346
+ return null;
38347
+ }
38348
+ function lineTrimmedMatch(contentLines, searchLines) {
38349
+ if (searchLines.length === 0) return null;
38350
+ const trimmedSearchLines = searchLines.map((line) => line.trim());
38351
+ if (trimmedSearchLines.every((line) => line === "")) return null;
38352
+ const windowSize = searchLines.length;
38353
+ const matches = [];
38354
+ for (let i5 = 0; i5 <= contentLines.length - windowSize; i5++) {
38355
+ let allMatch = true;
38356
+ for (let j5 = 0; j5 < windowSize; j5++) {
38357
+ if (contentLines[i5 + j5].trim() !== trimmedSearchLines[j5]) {
38358
+ allMatch = false;
38359
+ break;
38360
+ }
38361
+ }
38362
+ if (allMatch) {
38363
+ const matchedText = contentLines.slice(i5, i5 + windowSize).join("\n");
38364
+ matches.push(matchedText);
38365
+ }
38366
+ }
38367
+ if (matches.length === 0) return null;
38368
+ return {
38369
+ matchedText: matches[0],
38370
+ count: matches.length
38371
+ };
38372
+ }
38373
+ function whitespaceNormalizedMatch(content, search2) {
38374
+ if (!search2 || search2.trim().length === 0) return null;
38375
+ const { normalized: normContent, indexMap: contentMap } = buildNormalizedMap(content);
38376
+ const { normalized: normSearch } = buildNormalizedMap(search2);
38377
+ if (normSearch.length === 0) return null;
38378
+ const matches = [];
38379
+ let searchStart = 0;
38380
+ while (searchStart <= normContent.length - normSearch.length) {
38381
+ const idx = normContent.indexOf(normSearch, searchStart);
38382
+ if (idx === -1) break;
38383
+ const originalStart = contentMap[idx];
38384
+ const originalEnd = contentMap[idx + normSearch.length - 1];
38385
+ let actualEnd = originalEnd + 1;
38386
+ while (actualEnd < content.length && /[ \t]/.test(content[actualEnd]) && (actualEnd === originalEnd + 1 || /[ \t]/.test(content[actualEnd - 1]))) {
38387
+ if (contentMap.indexOf(actualEnd) > idx + normSearch.length - 1 || contentMap.indexOf(actualEnd) === -1) {
38388
+ break;
38389
+ }
38390
+ actualEnd++;
38391
+ }
38392
+ const matchedText = content.substring(originalStart, actualEnd);
38393
+ matches.push(matchedText);
38394
+ searchStart = idx + 1;
38395
+ }
38396
+ if (matches.length === 0) return null;
38397
+ return {
38398
+ matchedText: matches[0],
38399
+ count: matches.length
38400
+ };
38401
+ }
38402
+ function buildNormalizedMap(str) {
38403
+ const normalized = [];
38404
+ const indexMap = [];
38405
+ let i5 = 0;
38406
+ while (i5 < str.length) {
38407
+ const ch = str[i5];
38408
+ if (ch === " " || ch === " ") {
38409
+ normalized.push(" ");
38410
+ indexMap.push(i5);
38411
+ while (i5 < str.length && (str[i5] === " " || str[i5] === " ")) {
38412
+ i5++;
38413
+ }
38414
+ } else {
38415
+ normalized.push(ch);
38416
+ indexMap.push(i5);
38417
+ i5++;
38418
+ }
38419
+ }
38420
+ return {
38421
+ normalized: normalized.join(""),
38422
+ indexMap
38423
+ };
38424
+ }
38425
+ function indentFlexibleMatch(contentLines, searchLines) {
38426
+ if (searchLines.length === 0) return null;
38427
+ if (searchLines.every((line) => line.trim() === "")) return null;
38428
+ const searchMinIndent = getMinIndent(searchLines);
38429
+ const strippedSearch = searchLines.map((line) => stripIndent(line, searchMinIndent));
38430
+ const windowSize = searchLines.length;
38431
+ const matches = [];
38432
+ for (let i5 = 0; i5 <= contentLines.length - windowSize; i5++) {
38433
+ const windowLines = contentLines.slice(i5, i5 + windowSize);
38434
+ const windowMinIndent = getMinIndent(windowLines);
38435
+ const strippedWindow = windowLines.map((line) => stripIndent(line, windowMinIndent));
38436
+ let allMatch = true;
38437
+ for (let j5 = 0; j5 < windowSize; j5++) {
38438
+ if (strippedWindow[j5] !== strippedSearch[j5]) {
38439
+ allMatch = false;
38440
+ break;
38441
+ }
38442
+ }
38443
+ if (allMatch) {
38444
+ const matchedText = windowLines.join("\n");
38445
+ matches.push(matchedText);
38446
+ }
38447
+ }
38448
+ if (matches.length === 0) return null;
38449
+ return {
38450
+ matchedText: matches[0],
38451
+ count: matches.length
38452
+ };
38453
+ }
38454
+ function getMinIndent(lines) {
38455
+ let min = Infinity;
38456
+ for (const line of lines) {
38457
+ if (line.trim() === "") continue;
38458
+ const match2 = line.match(/^([ \t]*)/);
38459
+ if (match2) {
38460
+ min = Math.min(min, match2[1].length);
38461
+ }
38462
+ }
38463
+ return min === Infinity ? 0 : min;
38464
+ }
38465
+ function stripIndent(line, amount) {
38466
+ if (line.trim() === "") return "";
38467
+ if (amount <= 0) return line;
38468
+ return line.substring(Math.min(amount, line.length));
38469
+ }
38470
+ var init_fuzzyMatch = __esm({
38471
+ "src/tools/fuzzyMatch.js"() {
38472
+ "use strict";
38473
+ }
38474
+ });
38475
+
38476
+ // src/tools/symbolEdit.js
38477
+ async function findSymbol(filePath, symbolName, cwd) {
38478
+ try {
38479
+ const result = await extract({
38480
+ files: [`${filePath}#${symbolName}`],
38481
+ format: "json",
38482
+ json: true,
38483
+ cwd
38484
+ });
38485
+ if (!result || !result.results || result.results.length === 0) {
38486
+ return null;
38487
+ }
38488
+ const match2 = result.results[0];
38489
+ return {
38490
+ startLine: match2.lines[0],
38491
+ // 1-indexed
38492
+ endLine: match2.lines[1],
38493
+ // 1-indexed
38494
+ code: match2.code,
38495
+ nodeType: match2.node_type,
38496
+ file: match2.file
38497
+ };
38498
+ } catch (error2) {
38499
+ if (process.env.DEBUG === "1") {
38500
+ console.error(`[SymbolEdit] findSymbol error for "${symbolName}" in ${filePath}: ${error2.message}`);
38501
+ }
38502
+ return null;
38503
+ }
38504
+ }
38505
+ async function findAllSymbols(filePath, symbolName, cwd) {
38506
+ try {
38507
+ const result = await extract({
38508
+ files: [`${filePath}#${symbolName}`],
38509
+ format: "json",
38510
+ json: true,
38511
+ cwd
38512
+ });
38513
+ if (!result || !result.results || result.results.length === 0) {
38514
+ return [];
38515
+ }
38516
+ return result.results.map((match2) => ({
38517
+ startLine: match2.lines[0],
38518
+ endLine: match2.lines[1],
38519
+ code: match2.code,
38520
+ nodeType: match2.node_type,
38521
+ file: match2.file,
38522
+ qualifiedName: match2.symbol_signature || symbolName
38523
+ }));
38524
+ } catch (error2) {
38525
+ if (process.env.DEBUG === "1") {
38526
+ console.error(`[SymbolEdit] findAllSymbols error for "${symbolName}" in ${filePath}: ${error2.message}`);
38527
+ }
38528
+ return [];
38529
+ }
38530
+ }
38531
+ function detectBaseIndent(code) {
38532
+ const lines = code.split("\n");
38533
+ for (const line of lines) {
38534
+ if (line.trim().length > 0) {
38535
+ const match2 = line.match(/^(\s*)/);
38536
+ return match2 ? match2[1] : "";
38537
+ }
38538
+ }
38539
+ return "";
38540
+ }
38541
+ function reindent(newContent, targetIndent) {
38542
+ const lines = newContent.split("\n");
38543
+ const sourceIndent = detectBaseIndent(newContent);
38544
+ return lines.map((line) => {
38545
+ if (line.trim().length === 0) {
38546
+ return "";
38547
+ }
38548
+ if (line.startsWith(sourceIndent)) {
38549
+ return targetIndent + line.slice(sourceIndent.length);
38550
+ }
38551
+ return line;
38552
+ }).join("\n");
38553
+ }
38554
+ var init_symbolEdit = __esm({
38555
+ "src/tools/symbolEdit.js"() {
38556
+ "use strict";
38557
+ init_extract();
38558
+ }
38559
+ });
38560
+
38561
+ // src/tools/hashline.js
38562
+ function computeLineHash(line) {
38563
+ const stripped = (line || "").replace(/\s+/g, "");
38564
+ let h5 = 5381;
38565
+ for (let i5 = 0; i5 < stripped.length; i5++) {
38566
+ h5 = (h5 << 5) + h5 + stripped.charCodeAt(i5) & 4294967295;
38567
+ }
38568
+ return ((h5 >>> 0) % 256).toString(16).padStart(2, "0");
38569
+ }
38570
+ function parseLineRef(ref2) {
38571
+ if (ref2 === void 0 || ref2 === null) return null;
38572
+ const str = String(ref2).trim();
38573
+ if (!str) return null;
38574
+ const hashMatch = str.match(/^(\d+):([0-9a-fA-F]{2})$/);
38575
+ if (hashMatch) {
38576
+ const line = parseInt(hashMatch[1], 10);
38577
+ if (line < 1 || !isFinite(line)) return null;
38578
+ return { line, hash: hashMatch[2].toLowerCase() };
38579
+ }
38580
+ const lineMatch = str.match(/^(\d+)$/);
38581
+ if (lineMatch) {
38582
+ const line = parseInt(lineMatch[1], 10);
38583
+ if (line < 1 || !isFinite(line)) return null;
38584
+ return { line, hash: null };
38585
+ }
38586
+ return null;
38587
+ }
38588
+ function validateLineHash(lineNum, hash, fileLines) {
38589
+ const idx = lineNum - 1;
38590
+ if (idx < 0 || idx >= fileLines.length) {
38591
+ return { valid: false, actualHash: "", actualContent: "" };
38592
+ }
38593
+ const actualContent = fileLines[idx];
38594
+ const actualHash = computeLineHash(actualContent);
38595
+ return {
38596
+ valid: actualHash === hash.toLowerCase(),
38597
+ actualHash,
38598
+ actualContent
38599
+ };
38600
+ }
38601
+ function annotateOutputWithHashes(output) {
38602
+ if (!output || typeof output !== "string") return output;
38603
+ return output.split("\n").map((line) => {
38604
+ const cleanLine = line.endsWith("\r") ? line.slice(0, -1) : line;
38605
+ const match2 = cleanLine.match(/^(\s*)(\d+)(\s*\|)(.*)$/);
38606
+ if (!match2) return line;
38607
+ const [, prefix, lineNum, pipeSection, content] = match2;
38608
+ const hash = computeLineHash(content);
38609
+ const cr = line.endsWith("\r") ? "\r" : "";
38610
+ return `${prefix}${lineNum}:${hash}${pipeSection}${content}${cr}`;
38611
+ }).join("\n");
38612
+ }
38613
+ function stripHashlinePrefixes(text) {
38614
+ if (!text || typeof text !== "string") return { cleaned: text || "", stripped: false };
38615
+ const lines = text.split("\n");
38616
+ if (lines.length === 0) return { cleaned: "", stripped: false };
38617
+ const nonEmptyLines = lines.filter((l5) => l5.trim().length > 0);
38618
+ if (nonEmptyLines.length === 0) return { cleaned: text, stripped: false };
38619
+ const prefixPattern = /^\s*\d+(?::[0-9a-fA-F]{2})?\s*\|\s?/;
38620
+ const matchCount = nonEmptyLines.filter((l5) => prefixPattern.test(l5)).length;
38621
+ if (matchCount / nonEmptyLines.length <= 0.5) {
38622
+ return { cleaned: text, stripped: false };
38623
+ }
38624
+ const cleaned = lines.map((line) => {
38625
+ if (line.trim().length === 0) return line;
38626
+ return line.replace(prefixPattern, "");
38627
+ }).join("\n");
38628
+ return { cleaned, stripped: true };
38629
+ }
38630
+ var init_hashline = __esm({
38631
+ "src/tools/hashline.js"() {
38632
+ "use strict";
38633
+ }
38634
+ });
38635
+
38636
+ // src/tools/lineEditHeuristics.js
38637
+ function stripEchoedBoundaries(newStr, fileLines, startLine, endLine, position) {
38638
+ const modifications = [];
38639
+ let lines = newStr.split("\n");
38640
+ if (lines.length === 0) return { result: newStr, modifications };
38641
+ if (position === "after") {
38642
+ const anchorIdx = startLine - 1;
38643
+ if (anchorIdx >= 0 && anchorIdx < fileLines.length) {
38644
+ const anchorTrimmed = fileLines[anchorIdx].trim();
38645
+ if (anchorTrimmed.length > 0 && lines.length > 0 && lines[0].trim() === anchorTrimmed) {
38646
+ lines = lines.slice(1);
38647
+ modifications.push("stripped echoed anchor line (insert-after)");
38648
+ }
38649
+ }
38650
+ } else if (position === "before") {
38651
+ const anchorIdx = startLine - 1;
38652
+ if (anchorIdx >= 0 && anchorIdx < fileLines.length) {
38653
+ const anchorTrimmed = fileLines[anchorIdx].trim();
38654
+ if (anchorTrimmed.length > 0 && lines.length > 0 && lines[lines.length - 1].trim() === anchorTrimmed) {
38655
+ lines = lines.slice(0, -1);
38656
+ modifications.push("stripped echoed anchor line (insert-before)");
38657
+ }
38658
+ }
38659
+ } else {
38660
+ const beforeIdx = startLine - 2;
38661
+ if (beforeIdx >= 0 && beforeIdx < fileLines.length) {
38662
+ const beforeTrimmed = fileLines[beforeIdx].trim();
38663
+ if (beforeTrimmed.length > 0 && lines.length > 0 && lines[0].trim() === beforeTrimmed) {
38664
+ lines = lines.slice(1);
38665
+ modifications.push("stripped echoed line before range");
38666
+ }
38667
+ }
38668
+ const afterIdx = endLine;
38669
+ if (afterIdx >= 0 && afterIdx < fileLines.length) {
38670
+ const afterTrimmed = fileLines[afterIdx].trim();
38671
+ if (afterTrimmed.length > 0 && lines.length > 0 && lines[lines.length - 1].trim() === afterTrimmed) {
38672
+ lines = lines.slice(0, -1);
38673
+ modifications.push("stripped echoed line after range");
38674
+ }
38675
+ }
38676
+ }
38677
+ return { result: lines.join("\n"), modifications };
38678
+ }
38679
+ function restoreIndentation(newStr, originalLines) {
38680
+ const modifications = [];
38681
+ if (!newStr || !originalLines || originalLines.length === 0) {
38682
+ return { result: newStr || "", modifications };
38683
+ }
38684
+ const originalCode = originalLines.join("\n");
38685
+ const targetIndent = detectBaseIndent(originalCode);
38686
+ const newIndent = detectBaseIndent(newStr);
38687
+ if (targetIndent !== newIndent) {
38688
+ const reindented = reindent(newStr, targetIndent);
38689
+ if (reindented !== newStr) {
38690
+ modifications.push(`reindented from "${newIndent}" to "${targetIndent}"`);
38691
+ return { result: reindented, modifications };
38692
+ }
38693
+ }
38694
+ return { result: newStr, modifications };
38695
+ }
38696
+ function cleanNewString(newStr, fileLines, startLine, endLine, position) {
38697
+ const modifications = [];
38698
+ if (!newStr && newStr !== "") return { cleaned: "", modifications };
38699
+ const { cleaned: afterPrefixes, stripped } = stripHashlinePrefixes(newStr);
38700
+ if (stripped) modifications.push("stripped line-number prefixes");
38701
+ const { result: afterEchoes, modifications: echoMods } = stripEchoedBoundaries(
38702
+ afterPrefixes,
38703
+ fileLines,
38704
+ startLine,
38705
+ endLine,
38706
+ position
38707
+ );
38708
+ modifications.push(...echoMods);
38709
+ if (!position) {
38710
+ const originalLines = fileLines.slice(startLine - 1, endLine);
38711
+ const { result: afterIndent, modifications: indentMods } = restoreIndentation(afterEchoes, originalLines);
38712
+ modifications.push(...indentMods);
38713
+ return { cleaned: afterIndent, modifications };
38714
+ }
38715
+ return { cleaned: afterEchoes, modifications };
38716
+ }
38717
+ var init_lineEditHeuristics = __esm({
38718
+ "src/tools/lineEditHeuristics.js"() {
38719
+ "use strict";
38720
+ init_symbolEdit();
38721
+ init_hashline();
38722
+ }
38723
+ });
38724
+
38308
38725
  // src/tools/edit.js
38309
38726
  function isPathAllowed(filePath, allowedFolders) {
38310
38727
  if (!allowedFolders || allowedFolders.length === 0) {
@@ -38328,6 +38745,174 @@ function parseFileToolOptions(options = {}) {
38328
38745
  workspaceRoot: options.workspaceRoot || options.cwd || allowedFolders.length > 0 && allowedFolders[0] || process.cwd()
38329
38746
  };
38330
38747
  }
38748
+ async function handleSymbolEdit({ resolvedPath: resolvedPath2, file_path, symbol: symbol15, new_string, position, debug, cwd, fileTracker }) {
38749
+ if (typeof symbol15 !== "string" || symbol15.trim() === "") {
38750
+ return 'Error editing file: Invalid symbol - must be a non-empty string. Provide the name of a function, class, method, or other named code definition (e.g. "myFunction" or "MyClass.myMethod"). To edit by text matching instead, use old_string + new_string.';
38751
+ }
38752
+ if (position !== void 0 && position !== null && position !== "before" && position !== "after") {
38753
+ return 'Error editing file: Invalid position - must be "before" or "after". Use position="before" to insert code above the symbol, or position="after" to insert code below it. Omit position entirely to replace the symbol with new_string.';
38754
+ }
38755
+ const allMatches = await findAllSymbols(resolvedPath2, symbol15, cwd || process.cwd());
38756
+ if (allMatches.length === 0) {
38757
+ return `Error editing file: Symbol "${symbol15}" not found in ${file_path}. Verify the symbol name matches a top-level function, class, method, or other named definition exactly as declared in the source. Use 'search' or 'extract' to inspect the file and find the correct symbol name. Alternatively, use old_string + new_string for text-based editing instead.`;
38758
+ }
38759
+ if (allMatches.length > 1) {
38760
+ const suggestions = allMatches.map(
38761
+ (m5) => ` - ${m5.qualifiedName} (${m5.nodeType}, line ${m5.startLine})`
38762
+ ).join("\n");
38763
+ return `Error editing ${file_path}: Found ${allMatches.length} symbols named "${symbol15}". Use a qualified name to specify which one:
38764
+ ${suggestions}
38765
+
38766
+ Example: <edit><file_path>${file_path}</file_path><symbol>${allMatches[0].qualifiedName}</symbol><new_string>...</new_string></edit>`;
38767
+ }
38768
+ const symbolInfo = allMatches[0];
38769
+ if (fileTracker) {
38770
+ const check = fileTracker.checkSymbolContent(resolvedPath2, symbol15, symbolInfo.code);
38771
+ if (!check.ok && check.reason === "stale") {
38772
+ return `Error editing ${file_path}: Symbol "${symbol15}" has changed since you last read it. Use extract to re-read the current content, then retry.
38773
+
38774
+ Example: <extract><targets>${file_path}#${symbol15}</targets></extract>`;
38775
+ }
38776
+ }
38777
+ const content = await import_fs4.promises.readFile(resolvedPath2, "utf-8");
38778
+ const lines = content.split("\n");
38779
+ if (position) {
38780
+ const refIndent = detectBaseIndent(symbolInfo.code);
38781
+ const reindented = reindent(new_string, refIndent);
38782
+ const newLines = reindented.split("\n");
38783
+ if (position === "after") {
38784
+ lines.splice(symbolInfo.endLine, 0, "", ...newLines);
38785
+ } else {
38786
+ lines.splice(symbolInfo.startLine - 1, 0, ...newLines, "");
38787
+ }
38788
+ await import_fs4.promises.writeFile(resolvedPath2, lines.join("\n"), "utf-8");
38789
+ if (fileTracker) {
38790
+ const updated = await findSymbol(resolvedPath2, symbol15, cwd || process.cwd());
38791
+ if (updated) {
38792
+ fileTracker.trackSymbolAfterWrite(resolvedPath2, symbol15, updated.code, updated.startLine, updated.endLine);
38793
+ }
38794
+ fileTracker.markFileSeen(resolvedPath2);
38795
+ }
38796
+ const insertLine = position === "after" ? symbolInfo.endLine + 1 : symbolInfo.startLine;
38797
+ if (debug) {
38798
+ console.error(`[Edit] Successfully inserted ${newLines.length} lines ${position} "${symbol15}" at line ${insertLine} in ${resolvedPath2}`);
38799
+ }
38800
+ return `Successfully inserted ${newLines.length} lines ${position} symbol "${symbol15}" in ${file_path} (at line ${insertLine})`;
38801
+ } else {
38802
+ const originalIndent = detectBaseIndent(symbolInfo.code);
38803
+ const reindented = reindent(new_string, originalIndent);
38804
+ const newLines = reindented.split("\n");
38805
+ lines.splice(symbolInfo.startLine - 1, symbolInfo.endLine - symbolInfo.startLine + 1, ...newLines);
38806
+ await import_fs4.promises.writeFile(resolvedPath2, lines.join("\n"), "utf-8");
38807
+ if (fileTracker) {
38808
+ const updated = await findSymbol(resolvedPath2, symbol15, cwd || process.cwd());
38809
+ if (updated) {
38810
+ fileTracker.trackSymbolAfterWrite(resolvedPath2, symbol15, updated.code, updated.startLine, updated.endLine);
38811
+ }
38812
+ fileTracker.markFileSeen(resolvedPath2);
38813
+ }
38814
+ if (debug) {
38815
+ console.error(`[Edit] Successfully replaced symbol "${symbol15}" in ${resolvedPath2} (lines ${symbolInfo.startLine}-${symbolInfo.endLine})`);
38816
+ }
38817
+ return `Successfully replaced symbol "${symbol15}" in ${file_path} (was lines ${symbolInfo.startLine}-${symbolInfo.endLine}, now ${newLines.length} lines)`;
38818
+ }
38819
+ }
38820
+ function buildLineEditResponse(file_path, startLine, endLine, newLineCount, updatedLines, insertOffset, action, heuristicMods) {
38821
+ const contextBefore = 1;
38822
+ const contextAfter = 1;
38823
+ const contextStart = Math.max(0, insertOffset - contextBefore);
38824
+ const contextEnd = Math.min(updatedLines.length, insertOffset + newLineCount + contextAfter);
38825
+ let context = "Context:\n";
38826
+ for (let i5 = contextStart; i5 < contextEnd; i5++) {
38827
+ const lineNum = i5 + 1;
38828
+ const hash = computeLineHash(updatedLines[i5]);
38829
+ const isNew = i5 >= insertOffset && i5 < insertOffset + newLineCount;
38830
+ const marker15 = isNew ? ">" : " ";
38831
+ context += `${marker15} ${lineNum}:${hash} | ${updatedLines[i5]}
38832
+ `;
38833
+ }
38834
+ let msg = `Successfully edited ${file_path} (${action})`;
38835
+ if (heuristicMods.length > 0) {
38836
+ msg += ` [auto-corrected: ${heuristicMods.join(", ")}]`;
38837
+ }
38838
+ msg += "\n" + context;
38839
+ return msg;
38840
+ }
38841
+ async function handleLineEdit({ resolvedPath: resolvedPath2, file_path, start_line, end_line, new_string, position, debug, fileTracker }) {
38842
+ const startRef = parseLineRef(start_line);
38843
+ if (!startRef) {
38844
+ return `Error editing file: Invalid start_line '${start_line}'. Use a line number (e.g. "42") or line:hash (e.g. "42:ab"). Line numbers are 1-indexed.`;
38845
+ }
38846
+ let endRef = null;
38847
+ if (end_line !== void 0 && end_line !== null) {
38848
+ endRef = parseLineRef(end_line);
38849
+ if (!endRef) {
38850
+ return `Error editing file: Invalid end_line '${end_line}'. Use a line number (e.g. "55") or line:hash (e.g. "55:cd"). Must be >= start_line.`;
38851
+ }
38852
+ }
38853
+ const startLine = startRef.line;
38854
+ const endLine = endRef ? endRef.line : startLine;
38855
+ if (endLine < startLine) {
38856
+ return `Error editing file: end_line (${endLine}) must be >= start_line (${startLine}).`;
38857
+ }
38858
+ if (position !== void 0 && position !== null && position !== "before" && position !== "after") {
38859
+ 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.';
38860
+ }
38861
+ const content = await import_fs4.promises.readFile(resolvedPath2, "utf-8");
38862
+ const fileLines = content.split("\n");
38863
+ if (startLine > fileLines.length) {
38864
+ return `Error editing file: Line ${startLine} is beyond file length (${fileLines.length} lines). Use 'extract' to read the current file content.`;
38865
+ }
38866
+ if (endLine > fileLines.length) {
38867
+ return `Error editing file: Line ${endLine} is beyond file length (${fileLines.length} lines). Use 'extract' to read the current file content.`;
38868
+ }
38869
+ if (startRef.hash) {
38870
+ const validation = validateLineHash(startLine, startRef.hash, fileLines);
38871
+ if (!validation.valid) {
38872
+ return `Error editing file: Line ${startLine} has changed since last read. Expected hash '${startRef.hash}' but content is now: ${startLine}:${validation.actualHash} | ${validation.actualContent}. Use '${startLine}:${validation.actualHash}' instead.`;
38873
+ }
38874
+ }
38875
+ if (endRef && endRef.hash) {
38876
+ const validation = validateLineHash(endLine, endRef.hash, fileLines);
38877
+ if (!validation.valid) {
38878
+ return `Error editing file: Line ${endLine} has changed since last read. Expected hash '${endRef.hash}' but content is now: ${endLine}:${validation.actualHash} | ${validation.actualContent}. Use '${endLine}:${validation.actualHash}' instead.`;
38879
+ }
38880
+ }
38881
+ const { cleaned, modifications } = cleanNewString(new_string, fileLines, startLine, endLine, position);
38882
+ if (debug) {
38883
+ if (modifications.length > 0) {
38884
+ console.error(`[Edit] Heuristic corrections: ${modifications.join(", ")}`);
38885
+ }
38886
+ }
38887
+ const newLines = cleaned === "" ? [] : cleaned.split("\n");
38888
+ if (position === "after") {
38889
+ fileLines.splice(startLine, 0, ...newLines);
38890
+ await import_fs4.promises.writeFile(resolvedPath2, fileLines.join("\n"), "utf-8");
38891
+ if (fileTracker) await fileTracker.trackFileAfterWrite(resolvedPath2);
38892
+ const action = `${newLines.length} line${newLines.length !== 1 ? "s" : ""} inserted after line ${startLine}`;
38893
+ return buildLineEditResponse(file_path, startLine, startLine, newLines.length, fileLines, startLine, action, modifications);
38894
+ } else if (position === "before") {
38895
+ fileLines.splice(startLine - 1, 0, ...newLines);
38896
+ await import_fs4.promises.writeFile(resolvedPath2, fileLines.join("\n"), "utf-8");
38897
+ if (fileTracker) await fileTracker.trackFileAfterWrite(resolvedPath2);
38898
+ const action = `${newLines.length} line${newLines.length !== 1 ? "s" : ""} inserted before line ${startLine}`;
38899
+ return buildLineEditResponse(file_path, startLine, startLine, newLines.length, fileLines, startLine - 1, action, modifications);
38900
+ } else {
38901
+ const replacedCount = endLine - startLine + 1;
38902
+ fileLines.splice(startLine - 1, replacedCount, ...newLines);
38903
+ await import_fs4.promises.writeFile(resolvedPath2, fileLines.join("\n"), "utf-8");
38904
+ if (fileTracker) await fileTracker.trackFileAfterWrite(resolvedPath2);
38905
+ let action;
38906
+ if (newLines.length === 0) {
38907
+ action = `${replacedCount} line${replacedCount !== 1 ? "s" : ""} deleted (lines ${startLine}-${endLine})`;
38908
+ } else if (startLine === endLine) {
38909
+ action = `line ${startLine} replaced with ${newLines.length} line${newLines.length !== 1 ? "s" : ""}`;
38910
+ } else {
38911
+ action = `lines ${startLine}-${endLine} replaced with ${newLines.length} line${newLines.length !== 1 ? "s" : ""}`;
38912
+ }
38913
+ return buildLineEditResponse(file_path, startLine, endLine, newLines.length, fileLines, startLine - 1, action, modifications);
38914
+ }
38915
+ }
38331
38916
  var import_ai, import_fs4, import_path5, import_fs5, editTool, createTool, editSchema, createSchema, editDescription, createDescription, editToolDefinition, createToolDefinition;
38332
38917
  var init_edit = __esm({
38333
38918
  "src/tools/edit.js"() {
@@ -38337,24 +38922,31 @@ var init_edit = __esm({
38337
38922
  import_path5 = require("path");
38338
38923
  import_fs5 = require("fs");
38339
38924
  init_path_validation();
38925
+ init_fuzzyMatch();
38926
+ init_symbolEdit();
38927
+ init_hashline();
38928
+ init_lineEditHeuristics();
38340
38929
  editTool = (options = {}) => {
38341
38930
  const { debug, allowedFolders, cwd, workspaceRoot } = parseFileToolOptions(options);
38342
38931
  return (0, import_ai.tool)({
38343
38932
  name: "edit",
38344
- description: `Edit files using exact string replacement (Claude Code style).
38933
+ description: `Edit files using text replacement, AST-aware symbol operations, or line-targeted editing.
38345
38934
 
38346
- This tool performs exact string replacements in files. It requires the old_string to match exactly what's in the file, including all whitespace and indentation.
38935
+ Modes:
38936
+ 1. Text edit: Provide old_string + new_string to find and replace text (with fuzzy matching fallback)
38937
+ 2. Symbol replace: Provide symbol + new_string to replace an entire function/class/method by name
38938
+ 3. Symbol insert: Provide symbol + new_string + position to insert code before/after a symbol
38939
+ 4. Line-targeted edit: Provide start_line + new_string to edit by line number (from extract/search output)
38347
38940
 
38348
38941
  Parameters:
38349
38942
  - file_path: Path to the file to edit (absolute or relative)
38350
- - old_string: Exact text to find and replace (must be unique in the file unless replace_all is true)
38351
- - new_string: Text to replace with
38352
- - replace_all: (optional) Replace all occurrences instead of requiring uniqueness
38353
-
38354
- Important:
38355
- - The old_string must match EXACTLY including whitespace
38356
- - If old_string appears multiple times and replace_all is false, the edit will fail
38357
- - Use larger context around the string to ensure uniqueness when needed`,
38943
+ - new_string: Replacement text or new code content
38944
+ - old_string: (optional) Text to find and replace. If omitted, symbol or start_line must be provided.
38945
+ - replace_all: (optional) Replace all occurrences (text mode only)
38946
+ - symbol: (optional) Symbol name for AST-aware editing (e.g. "myFunction", "MyClass.myMethod")
38947
+ - position: (optional) "before" or "after" \u2014 insert code near a symbol or line instead of replacing it
38948
+ - start_line: (optional) Line reference (e.g. "42" or "42:ab") for line-targeted editing
38949
+ - end_line: (optional) End of line range, inclusive (e.g. "55" or "55:cd")`,
38358
38950
  inputSchema: {
38359
38951
  type: "object",
38360
38952
  properties: {
@@ -38364,30 +38956,44 @@ Important:
38364
38956
  },
38365
38957
  old_string: {
38366
38958
  type: "string",
38367
- description: "Exact text to find and replace"
38959
+ description: "Text to find and replace (for text-based editing)"
38368
38960
  },
38369
38961
  new_string: {
38370
38962
  type: "string",
38371
- description: "Text to replace with"
38963
+ description: "Replacement text or new code content"
38372
38964
  },
38373
38965
  replace_all: {
38374
38966
  type: "boolean",
38375
- description: "Replace all occurrences (default: false)",
38967
+ description: "Replace all occurrences (default: false, text mode only)",
38376
38968
  default: false
38969
+ },
38970
+ symbol: {
38971
+ type: "string",
38972
+ description: 'Symbol name for AST-aware editing (e.g. "myFunction", "MyClass.myMethod")'
38973
+ },
38974
+ position: {
38975
+ type: "string",
38976
+ enum: ["before", "after"],
38977
+ description: "Insert before/after symbol or line (requires symbol or start_line, omit to replace)"
38978
+ },
38979
+ start_line: {
38980
+ type: "string",
38981
+ description: 'Line reference for line-targeted editing (e.g. "42" or "42:ab" with hash)'
38982
+ },
38983
+ end_line: {
38984
+ type: "string",
38985
+ description: 'End of line range, inclusive (e.g. "55" or "55:cd"). Defaults to start_line.'
38377
38986
  }
38378
38987
  },
38379
- required: ["file_path", "old_string", "new_string"]
38988
+ required: ["file_path", "new_string"]
38380
38989
  },
38381
- execute: async ({ file_path, old_string, new_string, replace_all = false }) => {
38990
+ execute: async ({ file_path, old_string, new_string, replace_all = false, symbol: symbol15, position, start_line, end_line }) => {
38382
38991
  try {
38383
38992
  if (!file_path || typeof file_path !== "string" || file_path.trim() === "") {
38384
- return `Error editing file: Invalid file_path - must be a non-empty string`;
38385
- }
38386
- if (old_string === void 0 || old_string === null || typeof old_string !== "string") {
38387
- return `Error editing file: Invalid old_string - must be a string`;
38993
+ return `Error editing file: Invalid file_path - must be a non-empty string. Provide an absolute path or a path relative to the working directory (e.g. "src/main.js").`;
38388
38994
  }
38389
38995
  if (new_string === void 0 || new_string === null || typeof new_string !== "string") {
38390
- return `Error editing file: Invalid new_string - must be a string`;
38996
+ return `Error editing file: Invalid new_string - must be a string. Provide the replacement content as a string value (empty string "" is valid for deletions).`;
38391
38997
  }
38392
38998
  const resolvedPath2 = (0, import_path5.isAbsolute)(file_path) ? file_path : (0, import_path5.resolve)(cwd || process.cwd(), file_path);
38393
38999
  if (debug) {
@@ -38395,34 +39001,64 @@ Important:
38395
39001
  }
38396
39002
  if (!isPathAllowed(resolvedPath2, allowedFolders)) {
38397
39003
  const relativePath = toRelativePath(resolvedPath2, workspaceRoot);
38398
- return `Error editing file: Permission denied - ${relativePath} is outside allowed directories`;
39004
+ return `Error editing file: Permission denied - ${relativePath} is outside allowed directories. Use a file path within the project workspace.`;
38399
39005
  }
38400
39006
  if (!(0, import_fs5.existsSync)(resolvedPath2)) {
38401
- return `Error editing file: File not found - ${file_path}`;
39007
+ return `Error editing file: File not found - ${file_path}. Verify the path is correct and the file exists. Use 'search' to find files by name, or 'create' to make a new file.`;
39008
+ }
39009
+ if (options.fileTracker && !options.fileTracker.isFileSeen(resolvedPath2)) {
39010
+ const displayPath = toRelativePath(resolvedPath2, workspaceRoot);
39011
+ return `Error editing ${displayPath}: This file has not been read yet in this session. Use 'extract' to read the file first, then retry your edit. This ensures you are working with the current file content.
39012
+
39013
+ Example: <extract><targets>${displayPath}</targets></extract>`;
39014
+ }
39015
+ if (symbol15 !== void 0 && symbol15 !== null) {
39016
+ return await handleSymbolEdit({ resolvedPath: resolvedPath2, file_path, symbol: symbol15, new_string, position, debug, cwd, fileTracker: options.fileTracker });
39017
+ }
39018
+ if (start_line !== void 0 && start_line !== null) {
39019
+ return await handleLineEdit({ resolvedPath: resolvedPath2, file_path, start_line, end_line, new_string, position, debug, fileTracker: options.fileTracker });
39020
+ }
39021
+ if (old_string === void 0 || old_string === null) {
39022
+ return 'Error editing file: Must provide either old_string (for text edit), symbol (for AST-aware edit), or start_line (for line-targeted edit). For text editing: set old_string to the exact text to find and new_string to its replacement. For symbol editing: set symbol to a function/class/method name (e.g. "myFunction"). For line-targeted editing: set start_line to a line number from extract/search output (e.g. "42" or "42:ab").';
39023
+ }
39024
+ if (typeof old_string !== "string") {
39025
+ return `Error editing file: Invalid old_string - must be a string. Provide the exact text to find in the file, or use the symbol parameter instead for AST-aware editing by name.`;
38402
39026
  }
38403
39027
  const content = await import_fs4.promises.readFile(resolvedPath2, "utf-8");
39028
+ let matchTarget = old_string;
39029
+ let matchStrategy = "exact";
38404
39030
  if (!content.includes(old_string)) {
38405
- return `Error editing file: String not found - the specified old_string was not found in ${file_path}`;
39031
+ const fuzzy = findFuzzyMatch(content, old_string);
39032
+ if (!fuzzy) {
39033
+ return `Error editing file: String not found - the specified old_string was not found in ${file_path}. The text may have changed or differ from what you expected. Try: (1) Use 'search' or 'extract' to read the current file content and copy the exact text. (2) Use the symbol parameter to edit by function/class name instead. (3) Verify the file_path is correct.`;
39034
+ }
39035
+ matchTarget = fuzzy.matchedText;
39036
+ matchStrategy = fuzzy.strategy;
39037
+ if (debug) {
39038
+ console.error(`[Edit] Exact match failed, used ${matchStrategy} matching`);
39039
+ }
38406
39040
  }
38407
- const occurrences = content.split(old_string).length - 1;
39041
+ const occurrences = content.split(matchTarget).length - 1;
38408
39042
  if (!replace_all && occurrences > 1) {
38409
- return `Error editing file: Multiple occurrences found - the old_string appears ${occurrences} times. Use replace_all: true to replace all occurrences, or provide more context to make the string unique.`;
39043
+ 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).`;
38410
39044
  }
38411
39045
  let newContent;
38412
39046
  if (replace_all) {
38413
- newContent = content.replaceAll(old_string, new_string);
39047
+ newContent = content.replaceAll(matchTarget, new_string);
38414
39048
  } else {
38415
- newContent = content.replace(old_string, new_string);
39049
+ newContent = content.replace(matchTarget, new_string);
38416
39050
  }
38417
39051
  if (newContent === content) {
38418
- return `Error editing file: No changes made - old_string and new_string might be the same`;
39052
+ return `Error editing file: No changes made - the replacement result is identical to the original. Verify that old_string and new_string are actually different. If fuzzy matching was used, the matched text may already equal new_string.`;
38419
39053
  }
38420
39054
  await import_fs4.promises.writeFile(resolvedPath2, newContent, "utf-8");
39055
+ if (options.fileTracker) await options.fileTracker.trackFileAfterWrite(resolvedPath2);
38421
39056
  const replacedCount = replace_all ? occurrences : 1;
38422
39057
  if (debug) {
38423
39058
  console.error(`[Edit] Successfully edited ${resolvedPath2}, replaced ${replacedCount} occurrence(s)`);
38424
39059
  }
38425
- return `Successfully edited ${file_path} (${replacedCount} replacement${replacedCount !== 1 ? "s" : ""})`;
39060
+ const strategyNote = matchStrategy !== "exact" ? `, matched via ${matchStrategy}` : "";
39061
+ return `Successfully edited ${file_path} (${replacedCount} replacement${replacedCount !== 1 ? "s" : ""}${strategyNote})`;
38426
39062
  } catch (error2) {
38427
39063
  console.error("[Edit] Error:", error2);
38428
39064
  return `Error editing file: ${error2.message}`;
@@ -38469,10 +39105,10 @@ Important:
38469
39105
  execute: async ({ file_path, content, overwrite = false }) => {
38470
39106
  try {
38471
39107
  if (!file_path || typeof file_path !== "string" || file_path.trim() === "") {
38472
- return `Error creating file: Invalid file_path - must be a non-empty string`;
39108
+ return `Error creating file: Invalid file_path - must be a non-empty string. Provide an absolute path or a path relative to the working directory (e.g. "src/newFile.js").`;
38473
39109
  }
38474
39110
  if (content === void 0 || content === null || typeof content !== "string") {
38475
- return `Error creating file: Invalid content - must be a string`;
39111
+ return `Error creating file: Invalid content - must be a string. Provide the file content as a string value (empty string "" is valid for an empty file).`;
38476
39112
  }
38477
39113
  const resolvedPath2 = (0, import_path5.isAbsolute)(file_path) ? file_path : (0, import_path5.resolve)(cwd || process.cwd(), file_path);
38478
39114
  if (debug) {
@@ -38480,15 +39116,17 @@ Important:
38480
39116
  }
38481
39117
  if (!isPathAllowed(resolvedPath2, allowedFolders)) {
38482
39118
  const relativePath = toRelativePath(resolvedPath2, workspaceRoot);
38483
- return `Error creating file: Permission denied - ${relativePath} is outside allowed directories`;
39119
+ return `Error creating file: Permission denied - ${relativePath} is outside allowed directories. Use a file path within the project workspace.`;
38484
39120
  }
38485
39121
  if ((0, import_fs5.existsSync)(resolvedPath2) && !overwrite) {
38486
39122
  return `Error creating file: File already exists - ${file_path}. Use overwrite: true to replace it.`;
38487
39123
  }
39124
+ const existed = (0, import_fs5.existsSync)(resolvedPath2);
38488
39125
  const dir = (0, import_path5.dirname)(resolvedPath2);
38489
39126
  await import_fs4.promises.mkdir(dir, { recursive: true });
38490
39127
  await import_fs4.promises.writeFile(resolvedPath2, content, "utf-8");
38491
- const action = (0, import_fs5.existsSync)(resolvedPath2) && overwrite ? "overwrote" : "created";
39128
+ if (options.fileTracker) await options.fileTracker.trackFileAfterWrite(resolvedPath2);
39129
+ const action = existed && overwrite ? "overwrote" : "created";
38492
39130
  const bytes = Buffer.byteLength(content, "utf-8");
38493
39131
  if (debug) {
38494
39132
  console.error(`[Create] Successfully ${action} ${resolvedPath2}`);
@@ -38510,18 +39148,35 @@ Important:
38510
39148
  },
38511
39149
  old_string: {
38512
39150
  type: "string",
38513
- description: "Exact text to find and replace"
39151
+ description: "Text to find and replace (for text-based editing)"
38514
39152
  },
38515
39153
  new_string: {
38516
39154
  type: "string",
38517
- description: "Text to replace with"
39155
+ description: "Replacement text or new code content"
38518
39156
  },
38519
39157
  replace_all: {
38520
39158
  type: "boolean",
38521
- description: "Replace all occurrences (default: false)"
39159
+ description: "Replace all occurrences (default: false, text mode only)"
39160
+ },
39161
+ symbol: {
39162
+ type: "string",
39163
+ description: 'Symbol name for AST-aware editing (e.g. "myFunction", "MyClass.myMethod")'
39164
+ },
39165
+ position: {
39166
+ type: "string",
39167
+ enum: ["before", "after"],
39168
+ description: "Insert before/after symbol or line (requires symbol or start_line, omit to replace)"
39169
+ },
39170
+ start_line: {
39171
+ type: "string",
39172
+ description: 'Line reference for line-targeted editing (e.g. "42" or "42:ab" with hash)'
39173
+ },
39174
+ end_line: {
39175
+ type: "string",
39176
+ description: 'End of line range, inclusive (e.g. "55" or "55:cd"). Defaults to start_line.'
38522
39177
  }
38523
39178
  },
38524
- required: ["file_path", "old_string", "new_string"]
39179
+ required: ["file_path", "new_string"]
38525
39180
  };
38526
39181
  createSchema = {
38527
39182
  type: "object",
@@ -38541,50 +39196,123 @@ Important:
38541
39196
  },
38542
39197
  required: ["file_path", "content"]
38543
39198
  };
38544
- editDescription = "Edit files using exact string replacement. Requires exact match including whitespace.";
39199
+ 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.";
38545
39200
  createDescription = "Create new files with specified content. Will create parent directories if needed.";
38546
39201
  editToolDefinition = `
38547
39202
  ## edit
38548
39203
  Description: ${editDescription}
38549
39204
 
38550
- When to use:
38551
- - For precise, surgical edits to existing files
38552
- - When you need to change specific lines or blocks of code
38553
- - For renaming functions, variables, or updating configuration values
38554
- - When the exact text to replace is known and unique (or use replace_all for multiple occurrences)
39205
+ Four editing modes \u2014 choose based on the scope of your change:
38555
39206
 
38556
- When NOT to use:
38557
- - For creating new files (use 'create' tool instead)
38558
- - When you cannot determine the exact text to replace
38559
- - When changes span multiple locations that would be better handled together
39207
+ 1. **Text edit** (old_string + new_string): For small, precise changes \u2014 fix a condition, rename a variable, update a value. Provide old_string copied verbatim from the file and new_string with the replacement. Fuzzy matching handles minor whitespace/indentation differences automatically, but always try to copy the exact text.
39208
+
39209
+ 2. **Symbol replace** (symbol + new_string): For replacing an entire function, class, or method by name. No need to quote the old code \u2014 just provide the symbol name and the full new implementation. Indentation is automatically adjusted to match the original. Prefer this mode when rewriting whole definitions.
39210
+
39211
+ 3. **Symbol insert** (symbol + new_string + position): For adding new code before or after an existing symbol. Set position to "before" or "after".
39212
+
39213
+ 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.
38560
39214
 
38561
39215
  Parameters:
38562
39216
  - file_path: (required) Path to the file to edit
38563
- - old_string: (required) Exact text to find and replace (must match including whitespace, newlines, and indentation)
38564
- - new_string: (required) Text to replace with
38565
- - replace_all: (optional, default: false) Replace all occurrences if the string appears multiple times
38566
-
38567
- Important notes:
38568
- - The old_string MUST match EXACTLY, including all whitespace, indentation, and line breaks
38569
- - If old_string appears multiple times and replace_all is false, the tool will fail
38570
- - Always verify the exact formatting of the text you want to replace
39217
+ - new_string: (required) Replacement text or new code content
39218
+ - old_string: (optional) Text to find and replace \u2014 copy verbatim from the file, do not paraphrase or reformat
39219
+ - replace_all: (optional, default: false) Replace all occurrences of old_string (text mode only)
39220
+ - symbol: (optional) Name of a code symbol (e.g. "myFunction", "MyClass.myMethod") \u2014 must match a function, class, or method definition
39221
+ - position: (optional) "before" or "after" \u2014 insert new_string near the symbol or line instead of replacing it
39222
+ - start_line: (optional) Line reference for line-targeted editing (e.g. "42" or "42:ab")
39223
+ - end_line: (optional) End of line range, inclusive (e.g. "55" or "55:cd"). Defaults to start_line.
39224
+
39225
+ Mode selection rules (priority order):
39226
+ - If symbol is provided, symbol mode is used (old_string and start_line are ignored)
39227
+ - If start_line is provided (without symbol), line-targeted mode is used
39228
+ - If old_string is provided (without symbol or start_line), text mode is used
39229
+ - If none are provided, the tool returns an error with guidance
39230
+
39231
+ When to use each mode:
39232
+ - Small edits (a line or a few lines): use text mode with old_string
39233
+ - Replacing entire functions/classes/methods: use symbol mode \u2014 no exact text matching needed
39234
+ - Editing specific lines from extract/search output: use line-targeted mode with start_line
39235
+ - 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
39236
+
39237
+ Error handling:
39238
+ - If an edit fails, read the error message carefully \u2014 it contains specific instructions for how to fix the call and retry
39239
+ - Common fixes: use 'search'/'extract' to get exact file content, add more context to old_string, switch between text and symbol modes
39240
+ - Line-targeted hash mismatch: the file changed since last read; the error provides updated line:hash references
38571
39241
 
38572
39242
  Examples:
39243
+
39244
+ Text edit (find and replace):
38573
39245
  <edit>
38574
39246
  <file_path>src/main.js</file_path>
38575
- <old_string>function oldName() {
38576
- return 42;
38577
- }</old_string>
38578
- <new_string>function newName() {
38579
- return 42;
38580
- }</new_string>
39247
+ <old_string>return false;</old_string>
39248
+ <new_string>return true;</new_string>
38581
39249
  </edit>
38582
39250
 
39251
+ Text edit with replace_all:
38583
39252
  <edit>
38584
39253
  <file_path>config.json</file_path>
38585
39254
  <old_string>"debug": false</old_string>
38586
39255
  <new_string>"debug": true</new_string>
38587
39256
  <replace_all>true</replace_all>
39257
+ </edit>
39258
+
39259
+ Symbol replace (rewrite entire function by name):
39260
+ <edit>
39261
+ <file_path>src/utils.js</file_path>
39262
+ <symbol>calculateTotal</symbol>
39263
+ <new_string>function calculateTotal(items) {
39264
+ return items.reduce((sum, item) => sum + item.price * item.quantity, 0);
39265
+ }</new_string>
39266
+ </edit>
39267
+
39268
+ Symbol insert (add new function after existing one):
39269
+ <edit>
39270
+ <file_path>src/utils.js</file_path>
39271
+ <symbol>calculateTotal</symbol>
39272
+ <position>after</position>
39273
+ <new_string>function calculateTax(total, rate) {
39274
+ return total * rate;
39275
+ }</new_string>
39276
+ </edit>
39277
+
39278
+ Line-targeted edit (replace a line):
39279
+ <edit>
39280
+ <file_path>src/main.js</file_path>
39281
+ <start_line>42</start_line>
39282
+ <new_string> return processItems(order.items);</new_string>
39283
+ </edit>
39284
+
39285
+ Line-targeted edit (replace a range of lines):
39286
+ <edit>
39287
+ <file_path>src/main.js</file_path>
39288
+ <start_line>42</start_line>
39289
+ <end_line>55</end_line>
39290
+ <new_string> // simplified implementation
39291
+ return processItems(order.items);</new_string>
39292
+ </edit>
39293
+
39294
+ Line-targeted edit with hash verification:
39295
+ <edit>
39296
+ <file_path>src/main.js</file_path>
39297
+ <start_line>42:ab</start_line>
39298
+ <end_line>55:cd</end_line>
39299
+ <new_string> return processItems(order.items);</new_string>
39300
+ </edit>
39301
+
39302
+ Line-targeted insert (add code after a line):
39303
+ <edit>
39304
+ <file_path>src/main.js</file_path>
39305
+ <start_line>42</start_line>
39306
+ <position>after</position>
39307
+ <new_string> const validated = validate(input);</new_string>
39308
+ </edit>
39309
+
39310
+ Line-targeted delete (remove lines):
39311
+ <edit>
39312
+ <file_path>src/main.js</file_path>
39313
+ <start_line>42</start_line>
39314
+ <end_line>45</end_line>
39315
+ <new_string></new_string>
38588
39316
  </edit>`;
38589
39317
  createToolDefinition = `
38590
39318
  ## create
@@ -39121,7 +39849,7 @@ function getValidParamsForTool(toolName) {
39121
39849
  };
39122
39850
  const schema = schemaMap[toolName];
39123
39851
  if (!schema) {
39124
- return ["path", "directory", "pattern", "recursive", "includeHidden", "task", "files", "autoCommits", "result"];
39852
+ return ["path", "directory", "pattern", "recursive", "includeHidden", "task", "files", "result"];
39125
39853
  }
39126
39854
  if (toolName === "attempt_completion") {
39127
39855
  return ["result"];
@@ -39134,6 +39862,10 @@ function getValidParamsForTool(toolName) {
39134
39862
  }
39135
39863
  return [];
39136
39864
  }
39865
+ function unescapeXmlEntities(str) {
39866
+ if (typeof str !== "string") return str;
39867
+ return str.replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&apos;/g, "'").replace(/&amp;/g, "&");
39868
+ }
39137
39869
  function parseXmlToolCall(xmlString, validTools = DEFAULT_VALID_TOOLS) {
39138
39870
  let earliestToolName = null;
39139
39871
  let earliestOpenIndex = Infinity;
@@ -39190,10 +39922,10 @@ function parseXmlToolCall(xmlString, validTools = DEFAULT_VALID_TOOLS) {
39190
39922
  }
39191
39923
  paramCloseIndex = nextTagIndex;
39192
39924
  }
39193
- let paramValue = innerContent.substring(
39925
+ let paramValue = unescapeXmlEntities(innerContent.substring(
39194
39926
  paramOpenIndex + paramOpenTag.length,
39195
39927
  paramCloseIndex
39196
- ).trim();
39928
+ ).trim());
39197
39929
  if (paramValue.toLowerCase() === "true") {
39198
39930
  paramValue = true;
39199
39931
  } else if (paramValue.toLowerCase() === "false") {
@@ -39207,7 +39939,7 @@ function parseXmlToolCall(xmlString, validTools = DEFAULT_VALID_TOOLS) {
39207
39939
  params[paramName] = paramValue;
39208
39940
  }
39209
39941
  if (toolName === "attempt_completion") {
39210
- params["result"] = innerContent.trim();
39942
+ params["result"] = unescapeXmlEntities(innerContent.trim());
39211
39943
  if (params.command) {
39212
39944
  delete params.command;
39213
39945
  }
@@ -39242,7 +39974,6 @@ function detectUnrecognizedToolCall(xmlString, validTools) {
39242
39974
  "listSkills",
39243
39975
  "useSkill",
39244
39976
  "readImage",
39245
- "implement",
39246
39977
  "edit",
39247
39978
  "create",
39248
39979
  "delegate",
@@ -39617,6 +40348,8 @@ User: Read file inside the dependency
39617
40348
  </extract>
39618
40349
 
39619
40350
  </examples>
40351
+
40352
+ **Edit Integration:** The line numbers shown in extract output (e.g. "42 | code") can be used directly with the edit tool's start_line/end_line parameters for precise line-targeted editing. To edit inside a large function: extract it by symbol name first (e.g. "file.js#myFunction"), then use the line numbers from the output to make surgical edits with start_line/end_line.
39620
40353
  `;
39621
40354
  delegateToolDefinition = `
39622
40355
  ## delegate
@@ -39772,7 +40505,7 @@ Capabilities:
39772
40505
  `;
39773
40506
  searchDescription = "Search code in the repository. Free-form questions are accepted, but Elasticsearch-style keyword queries work best. Use this tool first for any code-related questions.";
39774
40507
  queryDescription = "Search code using ast-grep structural pattern matching. Use this tool to find specific code structures like functions, classes, or methods.";
39775
- extractDescription = "Extract code blocks from files based on file paths and optional line numbers. Use this tool to see complete context after finding relevant files.";
40508
+ extractDescription = "Extract code blocks from files based on file paths and optional line numbers. Use this tool to see complete context after finding relevant files. Line numbers from output can be used with edit start_line/end_line for precise editing.";
39776
40509
  delegateDescription = "Automatically delegate big distinct tasks to specialized probe subagents within the agentic loop. Used by AI agents to break down complex requests into focused, parallel tasks.";
39777
40510
  analyzeAllDescription = 'Answer questions that require analyzing ALL matching data in the codebase. Use for aggregate questions like "What features exist?", "List all API endpoints", "Count TODO comments". The AI automatically plans the search strategy, processes all results via map-reduce, and synthesizes a comprehensive answer. WARNING: Slower than search - only use when you need complete coverage.';
39778
40511
  DEFAULT_VALID_TOOLS = [
@@ -39787,7 +40520,6 @@ Capabilities:
39787
40520
  "useSkill",
39788
40521
  "listFiles",
39789
40522
  "searchFiles",
39790
- "implement",
39791
40523
  "bash",
39792
40524
  "task",
39793
40525
  "attempt_completion"
@@ -39912,6 +40644,7 @@ var init_vercel = __esm({
39912
40644
  init_analyzeAll();
39913
40645
  init_common2();
39914
40646
  init_error_types();
40647
+ init_hashline();
39915
40648
  CODE_SEARCH_SCHEMA = {
39916
40649
  type: "object",
39917
40650
  properties: {
@@ -39930,8 +40663,15 @@ var init_vercel = __esm({
39930
40663
  maxTokens = 2e4,
39931
40664
  debug = false,
39932
40665
  outline = false,
39933
- searchDelegate = false
40666
+ searchDelegate = false,
40667
+ hashLines = false
39934
40668
  } = options;
40669
+ const maybeAnnotate = (result) => {
40670
+ if (hashLines && typeof result === "string") {
40671
+ return annotateOutputWithHashes(result);
40672
+ }
40673
+ return result;
40674
+ };
39935
40675
  return (0, import_ai2.tool)({
39936
40676
  name: "search",
39937
40677
  description: searchDelegate ? `${searchDescription} (delegates code search to a subagent and returns extracted code blocks)` : searchDescription,
@@ -39973,7 +40713,12 @@ var init_vercel = __esm({
39973
40713
  };
39974
40714
  if (!searchDelegate) {
39975
40715
  try {
39976
- return await runRawSearch();
40716
+ const result = maybeAnnotate(await runRawSearch());
40717
+ if (options.fileTracker && typeof result === "string") {
40718
+ options.fileTracker.trackFilesFromOutput(result, options.cwd || ".").catch(() => {
40719
+ });
40720
+ }
40721
+ return result;
39977
40722
  } catch (error2) {
39978
40723
  console.error("Error executing search command:", error2);
39979
40724
  return formatErrorForAI(error2);
@@ -40016,7 +40761,12 @@ var init_vercel = __esm({
40016
40761
  if (debug) {
40017
40762
  console.error("Delegated search returned no targets; falling back to raw search");
40018
40763
  }
40019
- return await runRawSearch();
40764
+ const fallbackResult = maybeAnnotate(await runRawSearch());
40765
+ if (options.fileTracker && typeof fallbackResult === "string") {
40766
+ options.fileTracker.trackFilesFromOutput(fallbackResult, options.cwd || ".").catch(() => {
40767
+ });
40768
+ }
40769
+ return fallbackResult;
40020
40770
  }
40021
40771
  const resolutionBase = searchPaths[0] || options.cwd || ".";
40022
40772
  const resolvedTargets = targets.map((target) => resolveTargetPath(target, resolutionBase));
@@ -40031,13 +40781,18 @@ var init_vercel = __esm({
40031
40781
  const extractResult = await extract(extractOptions);
40032
40782
  if (resolutionBase && typeof extractResult === "string") {
40033
40783
  const wsPrefix = resolutionBase.endsWith("/") ? resolutionBase : resolutionBase + "/";
40034
- return extractResult.split(wsPrefix).join("");
40784
+ return maybeAnnotate(extractResult.split(wsPrefix).join(""));
40035
40785
  }
40036
- return extractResult;
40786
+ return maybeAnnotate(extractResult);
40037
40787
  } catch (error2) {
40038
40788
  console.error("Delegated search failed, falling back to raw search:", error2);
40039
40789
  try {
40040
- return await runRawSearch();
40790
+ const fallbackResult2 = maybeAnnotate(await runRawSearch());
40791
+ if (options.fileTracker && typeof fallbackResult2 === "string") {
40792
+ options.fileTracker.trackFilesFromOutput(fallbackResult2, options.cwd || ".").catch(() => {
40793
+ });
40794
+ }
40795
+ return fallbackResult2;
40041
40796
  } catch (fallbackError) {
40042
40797
  console.error("Error executing search command:", fallbackError);
40043
40798
  return formatErrorForAI(fallbackError);
@@ -40083,7 +40838,7 @@ var init_vercel = __esm({
40083
40838
  });
40084
40839
  };
40085
40840
  extractTool = (options = {}) => {
40086
- const { debug = false, outline = false } = options;
40841
+ const { debug = false, outline = false, hashLines = false } = options;
40087
40842
  return (0, import_ai2.tool)({
40088
40843
  name: "extract",
40089
40844
  description: extractDescription,
@@ -40100,6 +40855,7 @@ var init_vercel = __esm({
40100
40855
  }
40101
40856
  let tempFilePath = null;
40102
40857
  let extractOptions = { cwd: effectiveCwd };
40858
+ let extractFiles = null;
40103
40859
  if (input_content) {
40104
40860
  const { writeFileSync: writeFileSync2, unlinkSync } = await import("fs");
40105
40861
  const { join: join5 } = await import("path");
@@ -40123,13 +40879,13 @@ var init_vercel = __esm({
40123
40879
  };
40124
40880
  } else if (targets) {
40125
40881
  const parsedTargets = parseTargets(targets);
40126
- const files = parsedTargets.map((target) => resolveTargetPath(target, effectiveCwd));
40882
+ extractFiles = parsedTargets.map((target) => resolveTargetPath(target, effectiveCwd));
40127
40883
  let effectiveFormat = format2;
40128
40884
  if (outline && format2 === "outline-xml") {
40129
40885
  effectiveFormat = "xml";
40130
40886
  }
40131
40887
  extractOptions = {
40132
- files,
40888
+ files: extractFiles,
40133
40889
  cwd: effectiveCwd,
40134
40890
  allowTests: allow_tests ?? true,
40135
40891
  contextLines: context_lines,
@@ -40139,6 +40895,10 @@ var init_vercel = __esm({
40139
40895
  throw new Error("Either targets or input_content must be provided");
40140
40896
  }
40141
40897
  const results = await extract(extractOptions);
40898
+ if (options.fileTracker && extractFiles && extractFiles.length > 0) {
40899
+ options.fileTracker.trackFilesFromExtract(extractFiles, effectiveCwd).catch(() => {
40900
+ });
40901
+ }
40142
40902
  if (tempFilePath) {
40143
40903
  const { unlinkSync } = await import("fs");
40144
40904
  try {
@@ -40150,6 +40910,9 @@ var init_vercel = __esm({
40150
40910
  console.error(`Warning: Failed to remove temporary file: ${cleanupError.message}`);
40151
40911
  }
40152
40912
  }
40913
+ if (hashLines && typeof results === "string") {
40914
+ return annotateOutputWithHashes(results);
40915
+ }
40153
40916
  return results;
40154
40917
  } catch (error2) {
40155
40918
  console.error("Error executing extract command:", error2);
@@ -40349,6 +41112,7 @@ var init_bashDefaults = __esm({
40349
41112
  "tree:*",
40350
41113
  // Git read-only operations
40351
41114
  "git:status",
41115
+ "git:status:*",
40352
41116
  "git:log",
40353
41117
  "git:log:*",
40354
41118
  "git:diff",
@@ -40367,14 +41131,109 @@ var init_bashDefaults = __esm({
40367
41131
  "git:blame",
40368
41132
  "git:blame:*",
40369
41133
  "git:shortlog",
41134
+ "git:shortlog:*",
40370
41135
  "git:reflog",
41136
+ "git:reflog:*",
40371
41137
  "git:ls-files",
41138
+ "git:ls-files:*",
40372
41139
  "git:ls-tree",
41140
+ "git:ls-tree:*",
41141
+ "git:ls-remote",
41142
+ "git:ls-remote:*",
40373
41143
  "git:rev-parse",
41144
+ "git:rev-parse:*",
40374
41145
  "git:rev-list",
41146
+ "git:rev-list:*",
41147
+ "git:cat-file",
41148
+ "git:cat-file:*",
41149
+ "git:diff-tree",
41150
+ "git:diff-tree:*",
41151
+ "git:diff-files",
41152
+ "git:diff-files:*",
41153
+ "git:diff-index",
41154
+ "git:diff-index:*",
41155
+ "git:for-each-ref",
41156
+ "git:for-each-ref:*",
41157
+ "git:merge-base",
41158
+ "git:merge-base:*",
41159
+ "git:name-rev",
41160
+ "git:name-rev:*",
41161
+ "git:count-objects",
41162
+ "git:count-objects:*",
41163
+ "git:verify-commit",
41164
+ "git:verify-commit:*",
41165
+ "git:verify-tag",
41166
+ "git:verify-tag:*",
41167
+ "git:check-ignore",
41168
+ "git:check-ignore:*",
41169
+ "git:check-attr",
41170
+ "git:check-attr:*",
41171
+ "git:stash:list",
41172
+ "git:stash:show",
41173
+ "git:stash:show:*",
41174
+ "git:worktree:list",
41175
+ "git:worktree:list:*",
41176
+ "git:notes:list",
41177
+ "git:notes:show",
41178
+ "git:notes:show:*",
40375
41179
  "git:--version",
40376
41180
  "git:help",
40377
41181
  "git:help:*",
41182
+ // GitHub CLI (gh) read-only operations
41183
+ "gh:--version",
41184
+ "gh:help",
41185
+ "gh:help:*",
41186
+ "gh:status",
41187
+ "gh:auth:status",
41188
+ "gh:auth:status:*",
41189
+ "gh:issue:list",
41190
+ "gh:issue:list:*",
41191
+ "gh:issue:view",
41192
+ "gh:issue:view:*",
41193
+ "gh:issue:status",
41194
+ "gh:issue:status:*",
41195
+ "gh:pr:list",
41196
+ "gh:pr:list:*",
41197
+ "gh:pr:view",
41198
+ "gh:pr:view:*",
41199
+ "gh:pr:status",
41200
+ "gh:pr:status:*",
41201
+ "gh:pr:diff",
41202
+ "gh:pr:diff:*",
41203
+ "gh:pr:checks",
41204
+ "gh:pr:checks:*",
41205
+ "gh:repo:list",
41206
+ "gh:repo:list:*",
41207
+ "gh:repo:view",
41208
+ "gh:repo:view:*",
41209
+ "gh:release:list",
41210
+ "gh:release:list:*",
41211
+ "gh:release:view",
41212
+ "gh:release:view:*",
41213
+ "gh:run:list",
41214
+ "gh:run:list:*",
41215
+ "gh:run:view",
41216
+ "gh:run:view:*",
41217
+ "gh:workflow:list",
41218
+ "gh:workflow:list:*",
41219
+ "gh:workflow:view",
41220
+ "gh:workflow:view:*",
41221
+ "gh:gist:list",
41222
+ "gh:gist:list:*",
41223
+ "gh:gist:view",
41224
+ "gh:gist:view:*",
41225
+ "gh:search:issues",
41226
+ "gh:search:issues:*",
41227
+ "gh:search:prs",
41228
+ "gh:search:prs:*",
41229
+ "gh:search:repos",
41230
+ "gh:search:repos:*",
41231
+ "gh:search:code",
41232
+ "gh:search:code:*",
41233
+ "gh:search:commits",
41234
+ "gh:search:commits:*",
41235
+ "gh:api",
41236
+ "gh:api:*",
40378
41237
  // Package managers (information only)
40379
41238
  "npm:list",
40380
41239
  "npm:ls",
@@ -40685,14 +41544,132 @@ var init_bashDefaults = __esm({
40685
41544
  "git:push",
40686
41545
  "git:push:*",
40687
41546
  "git:force",
40688
- "git:reset:--hard:*",
40689
- "git:clean:-fd",
41547
+ "git:reset",
41548
+ "git:reset:*",
41549
+ "git:clean",
41550
+ "git:clean:*",
41551
+ "git:rm",
40690
41552
  "git:rm:*",
40691
41553
  "git:commit",
41554
+ "git:commit:*",
40692
41555
  "git:merge",
41556
+ "git:merge:*",
40693
41557
  "git:rebase",
41558
+ "git:rebase:*",
40694
41559
  "git:cherry-pick",
41560
+ "git:cherry-pick:*",
40695
41561
  "git:stash:drop",
41562
+ "git:stash:drop:*",
41563
+ "git:stash:pop",
41564
+ "git:stash:pop:*",
41565
+ "git:stash:push",
41566
+ "git:stash:push:*",
41567
+ "git:stash:clear",
41568
+ "git:branch:-d",
41569
+ "git:branch:-d:*",
41570
+ "git:branch:-D",
41571
+ "git:branch:-D:*",
41572
+ "git:branch:--delete",
41573
+ "git:branch:--delete:*",
41574
+ "git:tag:-d",
41575
+ "git:tag:-d:*",
41576
+ "git:tag:--delete",
41577
+ "git:tag:--delete:*",
41578
+ "git:remote:remove",
41579
+ "git:remote:remove:*",
41580
+ "git:remote:rm",
41581
+ "git:remote:rm:*",
41582
+ "git:checkout:--force",
41583
+ "git:checkout:--force:*",
41584
+ "git:checkout:-f",
41585
+ "git:checkout:-f:*",
41586
+ "git:submodule:deinit",
41587
+ "git:submodule:deinit:*",
41588
+ "git:notes:add",
41589
+ "git:notes:add:*",
41590
+ "git:notes:remove",
41591
+ "git:notes:remove:*",
41592
+ "git:worktree:add",
41593
+ "git:worktree:add:*",
41594
+ "git:worktree:remove",
41595
+ "git:worktree:remove:*",
41596
+ // Dangerous GitHub CLI (gh) write operations
41597
+ "gh:issue:create",
41598
+ "gh:issue:create:*",
41599
+ "gh:issue:close",
41600
+ "gh:issue:close:*",
41601
+ "gh:issue:delete",
41602
+ "gh:issue:delete:*",
41603
+ "gh:issue:edit",
41604
+ "gh:issue:edit:*",
41605
+ "gh:issue:reopen",
41606
+ "gh:issue:reopen:*",
41607
+ "gh:issue:comment",
41608
+ "gh:issue:comment:*",
41609
+ "gh:pr:create",
41610
+ "gh:pr:create:*",
41611
+ "gh:pr:close",
41612
+ "gh:pr:close:*",
41613
+ "gh:pr:merge",
41614
+ "gh:pr:merge:*",
41615
+ "gh:pr:edit",
41616
+ "gh:pr:edit:*",
41617
+ "gh:pr:reopen",
41618
+ "gh:pr:reopen:*",
41619
+ "gh:pr:review",
41620
+ "gh:pr:review:*",
41621
+ "gh:pr:comment",
41622
+ "gh:pr:comment:*",
41623
+ "gh:repo:create",
41624
+ "gh:repo:create:*",
41625
+ "gh:repo:delete",
41626
+ "gh:repo:delete:*",
41627
+ "gh:repo:fork",
41628
+ "gh:repo:fork:*",
41629
+ "gh:repo:rename",
41630
+ "gh:repo:rename:*",
41631
+ "gh:repo:archive",
41632
+ "gh:repo:archive:*",
41633
+ "gh:repo:clone",
41634
+ "gh:repo:clone:*",
41635
+ "gh:release:create",
41636
+ "gh:release:create:*",
41637
+ "gh:release:delete",
41638
+ "gh:release:delete:*",
41639
+ "gh:release:edit",
41640
+ "gh:release:edit:*",
41641
+ "gh:run:cancel",
41642
+ "gh:run:cancel:*",
41643
+ "gh:run:rerun",
41644
+ "gh:run:rerun:*",
41645
+ "gh:workflow:run",
41646
+ "gh:workflow:run:*",
41647
+ "gh:workflow:enable",
41648
+ "gh:workflow:enable:*",
41649
+ "gh:workflow:disable",
41650
+ "gh:workflow:disable:*",
41651
+ "gh:gist:create",
41652
+ "gh:gist:create:*",
41653
+ "gh:gist:delete",
41654
+ "gh:gist:delete:*",
41655
+ "gh:gist:edit",
41656
+ "gh:gist:edit:*",
41657
+ "gh:secret:set",
41658
+ "gh:secret:set:*",
41659
+ "gh:secret:delete",
41660
+ "gh:secret:delete:*",
41661
+ "gh:variable:set",
41662
+ "gh:variable:set:*",
41663
+ "gh:variable:delete",
41664
+ "gh:variable:delete:*",
41665
+ "gh:label:create",
41666
+ "gh:label:create:*",
41667
+ "gh:label:delete",
41668
+ "gh:label:delete:*",
41669
+ "gh:ssh-key:add",
41670
+ "gh:ssh-key:add:*",
41671
+ "gh:ssh-key:delete",
41672
+ "gh:ssh-key:delete:*",
40696
41673
  // File system mounting and partitioning
40697
41674
  "mount",
40698
41675
  "mount:*",
@@ -41497,7 +42474,7 @@ async function executeBashCommand(command, options = {}) {
41497
42474
  console.log(`[BashExecutor] Working directory: "${cwd}"`);
41498
42475
  console.log(`[BashExecutor] Timeout: ${timeout}ms`);
41499
42476
  }
41500
- return new Promise((resolve7, reject2) => {
42477
+ return new Promise((resolve8, reject2) => {
41501
42478
  const processEnv = {
41502
42479
  ...process.env,
41503
42480
  ...env
@@ -41514,7 +42491,7 @@ async function executeBashCommand(command, options = {}) {
41514
42491
  } else {
41515
42492
  const args = parseCommandForExecution(command);
41516
42493
  if (!args || args.length === 0) {
41517
- resolve7({
42494
+ resolve8({
41518
42495
  success: false,
41519
42496
  error: "Failed to parse command",
41520
42497
  stdout: "",
@@ -41599,7 +42576,7 @@ async function executeBashCommand(command, options = {}) {
41599
42576
  success = false;
41600
42577
  error2 = `Command exited with code ${code}`;
41601
42578
  }
41602
- resolve7({
42579
+ resolve8({
41603
42580
  success,
41604
42581
  error: error2,
41605
42582
  stdout: stdout.trim(),
@@ -41619,7 +42596,7 @@ async function executeBashCommand(command, options = {}) {
41619
42596
  if (debug) {
41620
42597
  console.log(`[BashExecutor] Spawn error:`, error2);
41621
42598
  }
41622
- resolve7({
42599
+ resolve8({
41623
42600
  success: false,
41624
42601
  error: `Failed to execute command: ${error2.message}`,
41625
42602
  stdout: "",
@@ -43031,14 +44008,14 @@ var require_executor = __commonJS({
43031
44008
  function asyncDone(callback) {
43032
44009
  let isInstant = false;
43033
44010
  let instant;
43034
- const p5 = new Promise((resolve7, reject2) => {
44011
+ const p5 = new Promise((resolve8, reject2) => {
43035
44012
  callback((err, result) => {
43036
44013
  if (err)
43037
44014
  reject2(err);
43038
44015
  else {
43039
44016
  isInstant = true;
43040
44017
  instant = result;
43041
- resolve7({ result });
44018
+ resolve8({ result });
43042
44019
  }
43043
44020
  });
43044
44021
  });
@@ -43061,10 +44038,10 @@ var require_executor = __commonJS({
43061
44038
  }
43062
44039
  async function execAsync4(ticks, tree, scope, context, doneOriginal, inLoopOrSwitch) {
43063
44040
  let done = doneOriginal;
43064
- const p5 = new Promise((resolve7) => {
44041
+ const p5 = new Promise((resolve8) => {
43065
44042
  done = (e5, r5) => {
43066
44043
  doneOriginal(e5, r5);
43067
- resolve7();
44044
+ resolve8();
43068
44045
  };
43069
44046
  });
43070
44047
  if (!_execNoneRecurse(ticks, tree, scope, context, done, true, inLoopOrSwitch) && utils.isLisp(tree)) {
@@ -51828,33 +52805,31 @@ var init_runtime = __esm({
51828
52805
  }
51829
52806
  });
51830
52807
 
51831
- // node_modules/balanced-match/index.js
51832
- var require_balanced_match = __commonJS({
51833
- "node_modules/balanced-match/index.js"(exports2, module2) {
51834
- "use strict";
51835
- module2.exports = balanced;
51836
- function balanced(a5, b5, str) {
51837
- if (a5 instanceof RegExp) a5 = maybeMatch(a5, str);
51838
- if (b5 instanceof RegExp) b5 = maybeMatch(b5, str);
51839
- var r5 = range2(a5, b5, str);
52808
+ // node_modules/balanced-match/dist/esm/index.js
52809
+ var balanced, maybeMatch, range2;
52810
+ var init_esm = __esm({
52811
+ "node_modules/balanced-match/dist/esm/index.js"() {
52812
+ balanced = (a5, b5, str) => {
52813
+ const ma = a5 instanceof RegExp ? maybeMatch(a5, str) : a5;
52814
+ const mb = b5 instanceof RegExp ? maybeMatch(b5, str) : b5;
52815
+ const r5 = ma !== null && mb != null && range2(ma, mb, str);
51840
52816
  return r5 && {
51841
52817
  start: r5[0],
51842
52818
  end: r5[1],
51843
52819
  pre: str.slice(0, r5[0]),
51844
- body: str.slice(r5[0] + a5.length, r5[1]),
51845
- post: str.slice(r5[1] + b5.length)
52820
+ body: str.slice(r5[0] + ma.length, r5[1]),
52821
+ post: str.slice(r5[1] + mb.length)
51846
52822
  };
51847
- }
51848
- function maybeMatch(reg, str) {
51849
- var m5 = str.match(reg);
52823
+ };
52824
+ maybeMatch = (reg, str) => {
52825
+ const m5 = str.match(reg);
51850
52826
  return m5 ? m5[0] : null;
51851
- }
51852
- balanced.range = range2;
51853
- function range2(a5, b5, str) {
51854
- var begs, beg, left, right, result;
51855
- var ai = str.indexOf(a5);
51856
- var bi = str.indexOf(b5, ai + 1);
51857
- var i5 = ai;
52827
+ };
52828
+ range2 = (a5, b5, str) => {
52829
+ let begs, beg, left, right = void 0, result;
52830
+ let ai = str.indexOf(a5);
52831
+ let bi = str.indexOf(b5, ai + 1);
52832
+ let i5 = ai;
51858
52833
  if (ai >= 0 && bi > 0) {
51859
52834
  if (a5 === b5) {
51860
52835
  return [ai, bi];
@@ -51862,14 +52837,16 @@ var require_balanced_match = __commonJS({
51862
52837
  begs = [];
51863
52838
  left = str.length;
51864
52839
  while (i5 >= 0 && !result) {
51865
- if (i5 == ai) {
52840
+ if (i5 === ai) {
51866
52841
  begs.push(i5);
51867
52842
  ai = str.indexOf(a5, i5 + 1);
51868
- } else if (begs.length == 1) {
51869
- result = [begs.pop(), bi];
52843
+ } else if (begs.length === 1) {
52844
+ const r5 = begs.pop();
52845
+ if (r5 !== void 0)
52846
+ result = [r5, bi];
51870
52847
  } else {
51871
52848
  beg = begs.pop();
51872
- if (beg < left) {
52849
+ if (beg !== void 0 && beg < left) {
51873
52850
  left = beg;
51874
52851
  right = bi;
51875
52852
  }
@@ -51877,163 +52854,179 @@ var require_balanced_match = __commonJS({
51877
52854
  }
51878
52855
  i5 = ai < bi && ai >= 0 ? ai : bi;
51879
52856
  }
51880
- if (begs.length) {
52857
+ if (begs.length && right !== void 0) {
51881
52858
  result = [left, right];
51882
52859
  }
51883
52860
  }
51884
52861
  return result;
51885
- }
52862
+ };
51886
52863
  }
51887
52864
  });
51888
52865
 
51889
- // node_modules/brace-expansion/index.js
51890
- var require_brace_expansion = __commonJS({
51891
- "node_modules/brace-expansion/index.js"(exports2, module2) {
51892
- var balanced = require_balanced_match();
51893
- module2.exports = expandTop;
51894
- var escSlash = "\0SLASH" + Math.random() + "\0";
51895
- var escOpen = "\0OPEN" + Math.random() + "\0";
51896
- var escClose = "\0CLOSE" + Math.random() + "\0";
51897
- var escComma = "\0COMMA" + Math.random() + "\0";
51898
- var escPeriod = "\0PERIOD" + Math.random() + "\0";
51899
- function numeric(str) {
51900
- return parseInt(str, 10) == str ? parseInt(str, 10) : str.charCodeAt(0);
51901
- }
51902
- function escapeBraces(str) {
51903
- return str.split("\\\\").join(escSlash).split("\\{").join(escOpen).split("\\}").join(escClose).split("\\,").join(escComma).split("\\.").join(escPeriod);
51904
- }
51905
- function unescapeBraces(str) {
51906
- return str.split(escSlash).join("\\").split(escOpen).join("{").split(escClose).join("}").split(escComma).join(",").split(escPeriod).join(".");
51907
- }
51908
- function parseCommaParts(str) {
51909
- if (!str)
51910
- return [""];
51911
- var parts = [];
51912
- var m5 = balanced("{", "}", str);
51913
- if (!m5)
51914
- return str.split(",");
51915
- var pre = m5.pre;
51916
- var body = m5.body;
51917
- var post = m5.post;
51918
- var p5 = pre.split(",");
51919
- p5[p5.length - 1] += "{" + body + "}";
51920
- var postParts = parseCommaParts(post);
51921
- if (post.length) {
51922
- p5[p5.length - 1] += postParts.shift();
51923
- p5.push.apply(p5, postParts);
51924
- }
51925
- parts.push.apply(parts, p5);
51926
- return parts;
51927
- }
51928
- function expandTop(str) {
51929
- if (!str)
51930
- return [];
51931
- if (str.substr(0, 2) === "{}") {
51932
- str = "\\{\\}" + str.substr(2);
51933
- }
51934
- return expand2(escapeBraces(str), true).map(unescapeBraces);
51935
- }
51936
- function embrace(str) {
51937
- return "{" + str + "}";
51938
- }
51939
- function isPadded(el) {
51940
- return /^-?0\d/.test(el);
51941
- }
51942
- function lte(i5, y2) {
51943
- return i5 <= y2;
51944
- }
51945
- function gte(i5, y2) {
51946
- return i5 >= y2;
52866
+ // node_modules/brace-expansion/dist/esm/index.js
52867
+ function numeric(str) {
52868
+ return !isNaN(str) ? parseInt(str, 10) : str.charCodeAt(0);
52869
+ }
52870
+ function escapeBraces(str) {
52871
+ return str.replace(slashPattern, escSlash).replace(openPattern, escOpen).replace(closePattern, escClose).replace(commaPattern, escComma).replace(periodPattern, escPeriod);
52872
+ }
52873
+ function unescapeBraces(str) {
52874
+ return str.replace(escSlashPattern, "\\").replace(escOpenPattern, "{").replace(escClosePattern, "}").replace(escCommaPattern, ",").replace(escPeriodPattern, ".");
52875
+ }
52876
+ function parseCommaParts(str) {
52877
+ if (!str) {
52878
+ return [""];
52879
+ }
52880
+ const parts = [];
52881
+ const m5 = balanced("{", "}", str);
52882
+ if (!m5) {
52883
+ return str.split(",");
52884
+ }
52885
+ const { pre, body, post } = m5;
52886
+ const p5 = pre.split(",");
52887
+ p5[p5.length - 1] += "{" + body + "}";
52888
+ const postParts = parseCommaParts(post);
52889
+ if (post.length) {
52890
+ ;
52891
+ p5[p5.length - 1] += postParts.shift();
52892
+ p5.push.apply(p5, postParts);
52893
+ }
52894
+ parts.push.apply(parts, p5);
52895
+ return parts;
52896
+ }
52897
+ function expand(str, options = {}) {
52898
+ if (!str) {
52899
+ return [];
52900
+ }
52901
+ const { max = EXPANSION_MAX } = options;
52902
+ if (str.slice(0, 2) === "{}") {
52903
+ str = "\\{\\}" + str.slice(2);
52904
+ }
52905
+ return expand_(escapeBraces(str), max, true).map(unescapeBraces);
52906
+ }
52907
+ function embrace(str) {
52908
+ return "{" + str + "}";
52909
+ }
52910
+ function isPadded(el) {
52911
+ return /^-?0\d/.test(el);
52912
+ }
52913
+ function lte(i5, y2) {
52914
+ return i5 <= y2;
52915
+ }
52916
+ function gte(i5, y2) {
52917
+ return i5 >= y2;
52918
+ }
52919
+ function expand_(str, max, isTop) {
52920
+ const expansions = [];
52921
+ const m5 = balanced("{", "}", str);
52922
+ if (!m5)
52923
+ return [str];
52924
+ const pre = m5.pre;
52925
+ const post = m5.post.length ? expand_(m5.post, max, false) : [""];
52926
+ if (/\$$/.test(m5.pre)) {
52927
+ for (let k5 = 0; k5 < post.length && k5 < max; k5++) {
52928
+ const expansion = pre + "{" + m5.body + "}" + post[k5];
52929
+ expansions.push(expansion);
51947
52930
  }
51948
- function expand2(str, isTop) {
51949
- var expansions = [];
51950
- var m5 = balanced("{", "}", str);
51951
- if (!m5) return [str];
51952
- var pre = m5.pre;
51953
- var post = m5.post.length ? expand2(m5.post, false) : [""];
51954
- if (/\$$/.test(m5.pre)) {
51955
- for (var k5 = 0; k5 < post.length; k5++) {
51956
- var expansion = pre + "{" + m5.body + "}" + post[k5];
51957
- expansions.push(expansion);
51958
- }
51959
- } else {
51960
- var isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m5.body);
51961
- var isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m5.body);
51962
- var isSequence = isNumericSequence || isAlphaSequence;
51963
- var isOptions = m5.body.indexOf(",") >= 0;
51964
- if (!isSequence && !isOptions) {
51965
- if (m5.post.match(/,(?!,).*\}/)) {
51966
- str = m5.pre + "{" + m5.body + escClose + m5.post;
51967
- return expand2(str);
51968
- }
51969
- return [str];
51970
- }
51971
- var n5;
51972
- if (isSequence) {
51973
- n5 = m5.body.split(/\.\./);
51974
- } else {
51975
- n5 = parseCommaParts(m5.body);
51976
- if (n5.length === 1) {
51977
- n5 = expand2(n5[0], false).map(embrace);
51978
- if (n5.length === 1) {
51979
- return post.map(function(p5) {
51980
- return m5.pre + n5[0] + p5;
51981
- });
51982
- }
52931
+ } else {
52932
+ const isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m5.body);
52933
+ const isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m5.body);
52934
+ const isSequence = isNumericSequence || isAlphaSequence;
52935
+ const isOptions = m5.body.indexOf(",") >= 0;
52936
+ if (!isSequence && !isOptions) {
52937
+ if (m5.post.match(/,(?!,).*\}/)) {
52938
+ str = m5.pre + "{" + m5.body + escClose + m5.post;
52939
+ return expand_(str, max, true);
52940
+ }
52941
+ return [str];
52942
+ }
52943
+ let n5;
52944
+ if (isSequence) {
52945
+ n5 = m5.body.split(/\.\./);
52946
+ } else {
52947
+ n5 = parseCommaParts(m5.body);
52948
+ if (n5.length === 1 && n5[0] !== void 0) {
52949
+ n5 = expand_(n5[0], max, false).map(embrace);
52950
+ if (n5.length === 1) {
52951
+ return post.map((p5) => m5.pre + n5[0] + p5);
52952
+ }
52953
+ }
52954
+ }
52955
+ let N;
52956
+ if (isSequence && n5[0] !== void 0 && n5[1] !== void 0) {
52957
+ const x5 = numeric(n5[0]);
52958
+ const y2 = numeric(n5[1]);
52959
+ const width = Math.max(n5[0].length, n5[1].length);
52960
+ let incr = n5.length === 3 && n5[2] !== void 0 ? Math.abs(numeric(n5[2])) : 1;
52961
+ let test = lte;
52962
+ const reverse = y2 < x5;
52963
+ if (reverse) {
52964
+ incr *= -1;
52965
+ test = gte;
52966
+ }
52967
+ const pad = n5.some(isPadded);
52968
+ N = [];
52969
+ for (let i5 = x5; test(i5, y2); i5 += incr) {
52970
+ let c5;
52971
+ if (isAlphaSequence) {
52972
+ c5 = String.fromCharCode(i5);
52973
+ if (c5 === "\\") {
52974
+ c5 = "";
51983
52975
  }
51984
- }
51985
- var N;
51986
- if (isSequence) {
51987
- var x5 = numeric(n5[0]);
51988
- var y2 = numeric(n5[1]);
51989
- var width = Math.max(n5[0].length, n5[1].length);
51990
- var incr = n5.length == 3 ? Math.abs(numeric(n5[2])) : 1;
51991
- var test = lte;
51992
- var reverse = y2 < x5;
51993
- if (reverse) {
51994
- incr *= -1;
51995
- test = gte;
51996
- }
51997
- var pad = n5.some(isPadded);
51998
- N = [];
51999
- for (var i5 = x5; test(i5, y2); i5 += incr) {
52000
- var c5;
52001
- if (isAlphaSequence) {
52002
- c5 = String.fromCharCode(i5);
52003
- if (c5 === "\\")
52004
- c5 = "";
52005
- } else {
52006
- c5 = String(i5);
52007
- if (pad) {
52008
- var need = width - c5.length;
52009
- if (need > 0) {
52010
- var z2 = new Array(need + 1).join("0");
52011
- if (i5 < 0)
52012
- c5 = "-" + z2 + c5.slice(1);
52013
- else
52014
- c5 = z2 + c5;
52015
- }
52976
+ } else {
52977
+ c5 = String(i5);
52978
+ if (pad) {
52979
+ const need = width - c5.length;
52980
+ if (need > 0) {
52981
+ const z2 = new Array(need + 1).join("0");
52982
+ if (i5 < 0) {
52983
+ c5 = "-" + z2 + c5.slice(1);
52984
+ } else {
52985
+ c5 = z2 + c5;
52016
52986
  }
52017
52987
  }
52018
- N.push(c5);
52019
- }
52020
- } else {
52021
- N = [];
52022
- for (var j5 = 0; j5 < n5.length; j5++) {
52023
- N.push.apply(N, expand2(n5[j5], false));
52024
52988
  }
52025
52989
  }
52026
- for (var j5 = 0; j5 < N.length; j5++) {
52027
- for (var k5 = 0; k5 < post.length; k5++) {
52028
- var expansion = pre + N[j5] + post[k5];
52029
- if (!isTop || isSequence || expansion)
52030
- expansions.push(expansion);
52031
- }
52990
+ N.push(c5);
52991
+ }
52992
+ } else {
52993
+ N = [];
52994
+ for (let j5 = 0; j5 < n5.length; j5++) {
52995
+ N.push.apply(N, expand_(n5[j5], max, false));
52996
+ }
52997
+ }
52998
+ for (let j5 = 0; j5 < N.length; j5++) {
52999
+ for (let k5 = 0; k5 < post.length && expansions.length < max; k5++) {
53000
+ const expansion = pre + N[j5] + post[k5];
53001
+ if (!isTop || isSequence || expansion) {
53002
+ expansions.push(expansion);
52032
53003
  }
52033
53004
  }
52034
- return expansions;
52035
53005
  }
52036
53006
  }
53007
+ return expansions;
53008
+ }
53009
+ var escSlash, escOpen, escClose, escComma, escPeriod, escSlashPattern, escOpenPattern, escClosePattern, escCommaPattern, escPeriodPattern, slashPattern, openPattern, closePattern, commaPattern, periodPattern, EXPANSION_MAX;
53010
+ var init_esm2 = __esm({
53011
+ "node_modules/brace-expansion/dist/esm/index.js"() {
53012
+ init_esm();
53013
+ escSlash = "\0SLASH" + Math.random() + "\0";
53014
+ escOpen = "\0OPEN" + Math.random() + "\0";
53015
+ escClose = "\0CLOSE" + Math.random() + "\0";
53016
+ escComma = "\0COMMA" + Math.random() + "\0";
53017
+ escPeriod = "\0PERIOD" + Math.random() + "\0";
53018
+ escSlashPattern = new RegExp(escSlash, "g");
53019
+ escOpenPattern = new RegExp(escOpen, "g");
53020
+ escClosePattern = new RegExp(escClose, "g");
53021
+ escCommaPattern = new RegExp(escComma, "g");
53022
+ escPeriodPattern = new RegExp(escPeriod, "g");
53023
+ slashPattern = /\\\\/g;
53024
+ openPattern = /\\{/g;
53025
+ closePattern = /\\}/g;
53026
+ commaPattern = /\\,/g;
53027
+ periodPattern = /\\./g;
53028
+ EXPANSION_MAX = 1e5;
53029
+ }
52037
53030
  });
52038
53031
 
52039
53032
  // node_modules/minimatch/dist/esm/assert-valid-pattern.js
@@ -52616,11 +53609,13 @@ var init_ast = __esm({
52616
53609
  let escaping = false;
52617
53610
  let re = "";
52618
53611
  let uflag = false;
53612
+ let inStar = false;
52619
53613
  for (let i5 = 0; i5 < glob2.length; i5++) {
52620
53614
  const c5 = glob2.charAt(i5);
52621
53615
  if (escaping) {
52622
53616
  escaping = false;
52623
53617
  re += (reSpecials.has(c5) ? "\\" : "") + c5;
53618
+ inStar = false;
52624
53619
  continue;
52625
53620
  }
52626
53621
  if (c5 === "\\") {
@@ -52638,16 +53633,19 @@ var init_ast = __esm({
52638
53633
  uflag = uflag || needUflag;
52639
53634
  i5 += consumed - 1;
52640
53635
  hasMagic2 = hasMagic2 || magic;
53636
+ inStar = false;
52641
53637
  continue;
52642
53638
  }
52643
53639
  }
52644
53640
  if (c5 === "*") {
52645
- if (noEmpty && glob2 === "*")
52646
- re += starNoEmpty;
52647
- else
52648
- re += star;
53641
+ if (inStar)
53642
+ continue;
53643
+ inStar = true;
53644
+ re += noEmpty && /^[*]+$/.test(glob2) ? starNoEmpty : star;
52649
53645
  hasMagic2 = true;
52650
53646
  continue;
53647
+ } else {
53648
+ inStar = false;
52651
53649
  }
52652
53650
  if (c5 === "?") {
52653
53651
  re += qmark;
@@ -52673,10 +53671,10 @@ var init_escape = __esm({
52673
53671
  });
52674
53672
 
52675
53673
  // node_modules/minimatch/dist/esm/index.js
52676
- var import_brace_expansion, minimatch, starDotExtRE, starDotExtTest, starDotExtTestDot, starDotExtTestNocase, starDotExtTestNocaseDot, starDotStarRE, starDotStarTest, starDotStarTestDot, dotStarRE, dotStarTest, starRE, starTest, starTestDot, qmarksRE, qmarksTestNocase, qmarksTestNocaseDot, qmarksTestDot, qmarksTest, qmarksTestNoExt, qmarksTestNoExtDot, defaultPlatform, path5, sep3, GLOBSTAR, qmark2, star2, twoStarDot, twoStarNoDot, filter, ext, defaults, braceExpand, makeRe, match, globMagic, regExpEscape2, Minimatch;
52677
- var init_esm = __esm({
53674
+ var minimatch, starDotExtRE, starDotExtTest, starDotExtTestDot, starDotExtTestNocase, starDotExtTestNocaseDot, starDotStarRE, starDotStarTest, starDotStarTestDot, dotStarRE, dotStarTest, starRE, starTest, starTestDot, qmarksRE, qmarksTestNocase, qmarksTestNocaseDot, qmarksTestDot, qmarksTest, qmarksTestNoExt, qmarksTestNoExtDot, defaultPlatform, path5, sep3, GLOBSTAR, qmark2, star2, twoStarDot, twoStarNoDot, filter, ext, defaults, braceExpand, makeRe, match, globMagic, regExpEscape2, Minimatch;
53675
+ var init_esm3 = __esm({
52678
53676
  "node_modules/minimatch/dist/esm/index.js"() {
52679
- import_brace_expansion = __toESM(require_brace_expansion(), 1);
53677
+ init_esm2();
52680
53678
  init_assert_valid_pattern();
52681
53679
  init_ast();
52682
53680
  init_escape();
@@ -52799,7 +53797,7 @@ var init_esm = __esm({
52799
53797
  if (options.nobrace || !/\{(?:(?!\{).)*\}/.test(pattern)) {
52800
53798
  return [pattern];
52801
53799
  }
52802
- return (0, import_brace_expansion.default)(pattern);
53800
+ return expand(pattern);
52803
53801
  };
52804
53802
  minimatch.braceExpand = braceExpand;
52805
53803
  makeRe = (pattern, options = {}) => new Minimatch(pattern, options).makeRe();
@@ -53405,7 +54403,7 @@ var init_esm = __esm({
53405
54403
 
53406
54404
  // node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.js
53407
54405
  var perf, warned, PROCESS, emitWarning, AC, AS, shouldWarn, TYPE, isPosInt, getUintArray, ZeroArray, Stack, LRUCache;
53408
- var init_esm2 = __esm({
54406
+ var init_esm4 = __esm({
53409
54407
  "node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.js"() {
53410
54408
  perf = typeof performance === "object" && performance && typeof performance.now === "function" ? performance : Date;
53411
54409
  warned = /* @__PURE__ */ new Set();
@@ -54779,7 +55777,7 @@ var init_esm2 = __esm({
54779
55777
 
54780
55778
  // node_modules/minipass/dist/esm/index.js
54781
55779
  var import_node_events, import_node_stream, import_node_string_decoder, proc, isStream, isReadable, isWritable, EOF, MAYBE_EMIT_END, EMITTED_END, EMITTING_END, EMITTED_ERROR, CLOSED, READ, FLUSH, FLUSHCHUNK, ENCODING, DECODER, FLOWING, PAUSED, RESUME, BUFFER, PIPES, BUFFERLENGTH, BUFFERPUSH, BUFFERSHIFT, OBJECTMODE, DESTROYED, ERROR, EMITDATA, EMITEND, EMITEND2, ASYNC, ABORT, ABORTED, SIGNAL, DATALISTENERS, DISCARDED, defer, nodefer, isEndish, isArrayBufferLike, isArrayBufferView, Pipe, PipeProxyErrors, isObjectModeOptions, isEncodingOptions, Minipass;
54782
- var init_esm3 = __esm({
55780
+ var init_esm5 = __esm({
54783
55781
  "node_modules/minipass/dist/esm/index.js"() {
54784
55782
  import_node_events = require("node:events");
54785
55783
  import_node_stream = __toESM(require("node:stream"), 1);
@@ -55509,10 +56507,10 @@ var init_esm3 = __esm({
55509
56507
  * Return a void Promise that resolves once the stream ends.
55510
56508
  */
55511
56509
  async promise() {
55512
- return new Promise((resolve7, reject2) => {
56510
+ return new Promise((resolve8, reject2) => {
55513
56511
  this.on(DESTROYED, () => reject2(new Error("stream destroyed")));
55514
56512
  this.on("error", (er) => reject2(er));
55515
- this.on("end", () => resolve7());
56513
+ this.on("end", () => resolve8());
55516
56514
  });
55517
56515
  }
55518
56516
  /**
@@ -55536,7 +56534,7 @@ var init_esm3 = __esm({
55536
56534
  return Promise.resolve({ done: false, value: res });
55537
56535
  if (this[EOF])
55538
56536
  return stop();
55539
- let resolve7;
56537
+ let resolve8;
55540
56538
  let reject2;
55541
56539
  const onerr = (er) => {
55542
56540
  this.off("data", ondata);
@@ -55550,19 +56548,19 @@ var init_esm3 = __esm({
55550
56548
  this.off("end", onend);
55551
56549
  this.off(DESTROYED, ondestroy);
55552
56550
  this.pause();
55553
- resolve7({ value, done: !!this[EOF] });
56551
+ resolve8({ value, done: !!this[EOF] });
55554
56552
  };
55555
56553
  const onend = () => {
55556
56554
  this.off("error", onerr);
55557
56555
  this.off("data", ondata);
55558
56556
  this.off(DESTROYED, ondestroy);
55559
56557
  stop();
55560
- resolve7({ done: true, value: void 0 });
56558
+ resolve8({ done: true, value: void 0 });
55561
56559
  };
55562
56560
  const ondestroy = () => onerr(new Error("stream destroyed"));
55563
56561
  return new Promise((res2, rej) => {
55564
56562
  reject2 = rej;
55565
- resolve7 = res2;
56563
+ resolve8 = res2;
55566
56564
  this.once(DESTROYED, ondestroy);
55567
56565
  this.once("error", onerr);
55568
56566
  this.once("end", onend);
@@ -55666,15 +56664,15 @@ var init_esm3 = __esm({
55666
56664
 
55667
56665
  // node_modules/path-scurry/dist/esm/index.js
55668
56666
  var import_node_path, import_node_url, import_fs7, actualFS, import_promises, realpathSync2, defaultFS, fsFromOption, uncDriveRegexp, uncToDrive, eitherSep, UNKNOWN, IFIFO, IFCHR, IFDIR, IFBLK, IFREG, IFLNK, IFSOCK, IFMT, IFMT_UNKNOWN, READDIR_CALLED, LSTAT_CALLED, ENOTDIR, ENOENT, ENOREADLINK, ENOREALPATH, ENOCHILD, TYPEMASK, entToType, normalizeCache, normalize, normalizeNocaseCache, normalizeNocase, ResolveCache, ChildrenCache, setAsCwd, PathBase, PathWin32, PathPosix, PathScurryBase, PathScurryWin32, PathScurryPosix, PathScurryDarwin, Path, PathScurry;
55669
- var init_esm4 = __esm({
56667
+ var init_esm6 = __esm({
55670
56668
  "node_modules/path-scurry/dist/esm/index.js"() {
55671
- init_esm2();
56669
+ init_esm4();
55672
56670
  import_node_path = require("node:path");
55673
56671
  import_node_url = require("node:url");
55674
56672
  import_fs7 = require("fs");
55675
56673
  actualFS = __toESM(require("node:fs"), 1);
55676
56674
  import_promises = require("node:fs/promises");
55677
- init_esm3();
56675
+ init_esm5();
55678
56676
  realpathSync2 = import_fs7.realpathSync.native;
55679
56677
  defaultFS = {
55680
56678
  lstatSync: import_fs7.lstatSync,
@@ -56546,9 +57544,9 @@ var init_esm4 = __esm({
56546
57544
  if (this.#asyncReaddirInFlight) {
56547
57545
  await this.#asyncReaddirInFlight;
56548
57546
  } else {
56549
- let resolve7 = () => {
57547
+ let resolve8 = () => {
56550
57548
  };
56551
- this.#asyncReaddirInFlight = new Promise((res) => resolve7 = res);
57549
+ this.#asyncReaddirInFlight = new Promise((res) => resolve8 = res);
56552
57550
  try {
56553
57551
  for (const e5 of await this.#fs.promises.readdir(fullpath, {
56554
57552
  withFileTypes: true
@@ -56561,7 +57559,7 @@ var init_esm4 = __esm({
56561
57559
  children.provisional = 0;
56562
57560
  }
56563
57561
  this.#asyncReaddirInFlight = void 0;
56564
- resolve7();
57562
+ resolve8();
56565
57563
  }
56566
57564
  return children.slice(0, children.provisional);
56567
57565
  }
@@ -57404,7 +58402,7 @@ var init_esm4 = __esm({
57404
58402
  var isPatternList, isGlobList, Pattern;
57405
58403
  var init_pattern = __esm({
57406
58404
  "node_modules/glob/dist/esm/pattern.js"() {
57407
- init_esm();
58405
+ init_esm3();
57408
58406
  isPatternList = (pl) => pl.length >= 1;
57409
58407
  isGlobList = (gl) => gl.length >= 1;
57410
58408
  Pattern = class _Pattern {
@@ -57575,7 +58573,7 @@ var init_pattern = __esm({
57575
58573
  var defaultPlatform2, Ignore;
57576
58574
  var init_ignore = __esm({
57577
58575
  "node_modules/glob/dist/esm/ignore.js"() {
57578
- init_esm();
58576
+ init_esm3();
57579
58577
  init_pattern();
57580
58578
  defaultPlatform2 = typeof process === "object" && process && typeof process.platform === "string" ? process.platform : "linux";
57581
58579
  Ignore = class {
@@ -57669,7 +58667,7 @@ var init_ignore = __esm({
57669
58667
  var HasWalkedCache, MatchRecord, SubWalks, Processor;
57670
58668
  var init_processor = __esm({
57671
58669
  "node_modules/glob/dist/esm/processor.js"() {
57672
- init_esm();
58670
+ init_esm3();
57673
58671
  HasWalkedCache = class _HasWalkedCache {
57674
58672
  store;
57675
58673
  constructor(store = /* @__PURE__ */ new Map()) {
@@ -57896,7 +58894,7 @@ var init_processor = __esm({
57896
58894
  var makeIgnore, GlobUtil, GlobWalker, GlobStream;
57897
58895
  var init_walker = __esm({
57898
58896
  "node_modules/glob/dist/esm/walker.js"() {
57899
- init_esm3();
58897
+ init_esm5();
57900
58898
  init_ignore();
57901
58899
  init_processor();
57902
58900
  makeIgnore = (ignore2, opts) => typeof ignore2 === "string" ? new Ignore([ignore2], opts) : Array.isArray(ignore2) ? new Ignore(ignore2, opts) : ignore2;
@@ -58231,9 +59229,9 @@ var init_walker = __esm({
58231
59229
  var import_node_url2, defaultPlatform3, Glob;
58232
59230
  var init_glob = __esm({
58233
59231
  "node_modules/glob/dist/esm/glob.js"() {
58234
- init_esm();
59232
+ init_esm3();
58235
59233
  import_node_url2 = require("node:url");
58236
- init_esm4();
59234
+ init_esm6();
58237
59235
  init_pattern();
58238
59236
  init_walker();
58239
59237
  defaultPlatform3 = typeof process === "object" && process && typeof process.platform === "string" ? process.platform : "linux";
@@ -58441,7 +59439,7 @@ var init_glob = __esm({
58441
59439
  var hasMagic;
58442
59440
  var init_has_magic = __esm({
58443
59441
  "node_modules/glob/dist/esm/has-magic.js"() {
58444
- init_esm();
59442
+ init_esm3();
58445
59443
  hasMagic = (pattern, options = {}) => {
58446
59444
  if (!Array.isArray(pattern)) {
58447
59445
  pattern = [pattern];
@@ -58475,12 +59473,12 @@ function globIterate(pattern, options = {}) {
58475
59473
  return new Glob(pattern, options).iterate();
58476
59474
  }
58477
59475
  var streamSync, stream, iterateSync, iterate, sync, glob;
58478
- var init_esm5 = __esm({
59476
+ var init_esm7 = __esm({
58479
59477
  "node_modules/glob/dist/esm/index.js"() {
58480
- init_esm();
59478
+ init_esm3();
58481
59479
  init_glob();
58482
59480
  init_has_magic();
58483
- init_esm();
59481
+ init_esm3();
58484
59482
  init_glob();
58485
59483
  init_has_magic();
58486
59484
  init_ignore();
@@ -59440,7 +60438,7 @@ var init_executePlan = __esm({
59440
60438
  init_query();
59441
60439
  init_extract();
59442
60440
  init_delegate();
59443
- init_esm5();
60441
+ init_esm7();
59444
60442
  init_bash();
59445
60443
  RAW_OUTPUT_START = "<<<RAW_OUTPUT>>>";
59446
60444
  RAW_OUTPUT_END = "<<<END_RAW_OUTPUT>>>";
@@ -59712,13 +60710,271 @@ var init_file_lister = __esm({
59712
60710
  }
59713
60711
  });
59714
60712
 
60713
+ // src/tools/fileTracker.js
60714
+ function computeContentHash(content) {
60715
+ const normalized = (content || "").split("\n").map((l5) => l5.trimEnd()).join("\n");
60716
+ return (0, import_crypto3.createHash)("sha256").update(normalized).digest("hex").slice(0, 16);
60717
+ }
60718
+ function extractFilePath(target) {
60719
+ const hashIdx = target.indexOf("#");
60720
+ if (hashIdx !== -1) {
60721
+ return target.slice(0, hashIdx);
60722
+ }
60723
+ const colonIdx = target.lastIndexOf(":");
60724
+ if (colonIdx !== -1) {
60725
+ const after = target.slice(colonIdx + 1);
60726
+ if (/^\d+(-\d+)?$/.test(after)) {
60727
+ return target.slice(0, colonIdx);
60728
+ }
60729
+ }
60730
+ return target;
60731
+ }
60732
+ function extractSymbolName(target) {
60733
+ const hashIdx = target.indexOf("#");
60734
+ if (hashIdx !== -1) {
60735
+ const symbol15 = target.slice(hashIdx + 1);
60736
+ return symbol15 || null;
60737
+ }
60738
+ return null;
60739
+ }
60740
+ function parseFilePathsFromOutput(output) {
60741
+ const paths = [];
60742
+ const regex = /^(?:File:\s+|---\s+)([^\s].*?)(?:\s+---)?$/gm;
60743
+ let match2;
60744
+ while ((match2 = regex.exec(output)) !== null) {
60745
+ const path9 = match2[1].trim();
60746
+ if (path9 && !path9.startsWith("Results") && !path9.startsWith("Page") && (path9.includes("/") || path9.includes(".") || path9.includes("\\"))) {
60747
+ paths.push(path9);
60748
+ }
60749
+ }
60750
+ return paths;
60751
+ }
60752
+ var import_crypto3, import_path10, FileTracker;
60753
+ var init_fileTracker = __esm({
60754
+ "src/tools/fileTracker.js"() {
60755
+ "use strict";
60756
+ import_crypto3 = require("crypto");
60757
+ import_path10 = require("path");
60758
+ init_symbolEdit();
60759
+ FileTracker = class {
60760
+ /**
60761
+ * @param {Object} [options]
60762
+ * @param {boolean} [options.debug=false] - Enable debug logging
60763
+ */
60764
+ constructor(options = {}) {
60765
+ this.debug = options.debug || false;
60766
+ this._seenFiles = /* @__PURE__ */ new Set();
60767
+ this._contentRecords = /* @__PURE__ */ new Map();
60768
+ }
60769
+ /**
60770
+ * Mark a file as "seen" — the LLM has read its content.
60771
+ * @param {string} resolvedPath - Absolute path to the file
60772
+ */
60773
+ markFileSeen(resolvedPath2) {
60774
+ this._seenFiles.add(resolvedPath2);
60775
+ if (this.debug) {
60776
+ console.error(`[FileTracker] Marked as seen: ${resolvedPath2}`);
60777
+ }
60778
+ }
60779
+ /**
60780
+ * Check if a file has been seen in this session.
60781
+ * @param {string} resolvedPath - Absolute path to the file
60782
+ * @returns {boolean}
60783
+ */
60784
+ isFileSeen(resolvedPath2) {
60785
+ return this._seenFiles.has(resolvedPath2);
60786
+ }
60787
+ /**
60788
+ * Store a content hash for a symbol in a file.
60789
+ * @param {string} resolvedPath - Absolute path to the file
60790
+ * @param {string} symbolName - Symbol name (e.g. "calculateTotal")
60791
+ * @param {string} code - The symbol's source code
60792
+ * @param {number} startLine - 1-indexed start line
60793
+ * @param {number} endLine - 1-indexed end line
60794
+ * @param {string} [source='extract'] - How the content was obtained
60795
+ */
60796
+ trackSymbolContent(resolvedPath2, symbolName, code, startLine, endLine, source = "extract") {
60797
+ const key = `${resolvedPath2}#${symbolName}`;
60798
+ const contentHash = computeContentHash(code);
60799
+ this._contentRecords.set(key, {
60800
+ contentHash,
60801
+ startLine,
60802
+ endLine,
60803
+ symbolName,
60804
+ source,
60805
+ timestamp: Date.now()
60806
+ });
60807
+ if (this.debug) {
60808
+ console.error(`[FileTracker] Tracked symbol ${key} (hash: ${contentHash}, lines ${startLine}-${endLine})`);
60809
+ }
60810
+ }
60811
+ /**
60812
+ * Look up a stored content record for a symbol.
60813
+ * @param {string} resolvedPath - Absolute path to the file
60814
+ * @param {string} symbolName - Symbol name
60815
+ * @returns {Object|null} The stored record or null
60816
+ */
60817
+ getSymbolRecord(resolvedPath2, symbolName) {
60818
+ return this._contentRecords.get(`${resolvedPath2}#${symbolName}`) || null;
60819
+ }
60820
+ /**
60821
+ * Check if a symbol's current content matches what was stored.
60822
+ * @param {string} resolvedPath - Absolute path to the file
60823
+ * @param {string} symbolName - Symbol name
60824
+ * @param {string} currentCode - The symbol's current source code (from findSymbol)
60825
+ * @returns {{ok: boolean, reason?: string, message?: string}}
60826
+ */
60827
+ checkSymbolContent(resolvedPath2, symbolName, currentCode) {
60828
+ const key = `${resolvedPath2}#${symbolName}`;
60829
+ const record = this._contentRecords.get(key);
60830
+ if (!record) {
60831
+ return { ok: true };
60832
+ }
60833
+ const currentHash = computeContentHash(currentCode);
60834
+ if (currentHash === record.contentHash) {
60835
+ return { ok: true };
60836
+ }
60837
+ return {
60838
+ ok: false,
60839
+ reason: "stale",
60840
+ message: `Symbol "${symbolName}" has changed since you last read it (hash: ${record.contentHash} \u2192 ${currentHash}).`
60841
+ };
60842
+ }
60843
+ /**
60844
+ * Track files from extract target strings.
60845
+ * Marks each file as seen. For #symbol targets, calls findSymbol to get and hash the code.
60846
+ * @param {string[]} targets - Array of extract targets (e.g. ["file.js#fn", "file.js:10-20"])
60847
+ * @param {string} cwd - Working directory for resolving relative paths
60848
+ */
60849
+ async trackFilesFromExtract(targets, cwd) {
60850
+ const seenPaths = /* @__PURE__ */ new Set();
60851
+ const symbolPromises = [];
60852
+ for (const target of targets) {
60853
+ const filePath = extractFilePath(target);
60854
+ const resolved = (0, import_path10.isAbsolute)(filePath) ? filePath : (0, import_path10.resolve)(cwd, filePath);
60855
+ if (!seenPaths.has(resolved)) {
60856
+ seenPaths.add(resolved);
60857
+ this.markFileSeen(resolved);
60858
+ }
60859
+ const symbolName = extractSymbolName(target);
60860
+ if (symbolName) {
60861
+ symbolPromises.push(
60862
+ findSymbol(resolved, symbolName, cwd).then((symbolInfo) => {
60863
+ if (symbolInfo) {
60864
+ this.trackSymbolContent(
60865
+ resolved,
60866
+ symbolName,
60867
+ symbolInfo.code,
60868
+ symbolInfo.startLine,
60869
+ symbolInfo.endLine,
60870
+ "extract"
60871
+ );
60872
+ }
60873
+ }).catch((err) => {
60874
+ if (this.debug) {
60875
+ console.error(`[FileTracker] Failed to track symbol "${symbolName}" in ${resolved}: ${err.message}`);
60876
+ }
60877
+ })
60878
+ );
60879
+ }
60880
+ }
60881
+ if (symbolPromises.length > 0) {
60882
+ await Promise.all(symbolPromises);
60883
+ }
60884
+ }
60885
+ /**
60886
+ * Track files discovered in probe search/extract output.
60887
+ * Parses "File: path" headers and "--- path ---" separators, marks each as "seen".
60888
+ * @param {string} output - Probe output text
60889
+ * @param {string} cwd - Working directory for resolving relative paths
60890
+ */
60891
+ async trackFilesFromOutput(output, cwd) {
60892
+ const paths = parseFilePathsFromOutput(output);
60893
+ for (const filePath of paths) {
60894
+ const resolved = (0, import_path10.isAbsolute)(filePath) ? filePath : (0, import_path10.resolve)(cwd, filePath);
60895
+ this.markFileSeen(resolved);
60896
+ }
60897
+ }
60898
+ /**
60899
+ * Check if a file is safe to edit (seen-check only).
60900
+ * Mode-specific content verification happens in edit handlers.
60901
+ * @param {string} resolvedPath - Absolute path to the file
60902
+ * @returns {{ok: boolean, reason?: string, message?: string}}
60903
+ */
60904
+ checkBeforeEdit(resolvedPath2) {
60905
+ if (!this._seenFiles.has(resolvedPath2)) {
60906
+ return {
60907
+ ok: false,
60908
+ reason: "untracked",
60909
+ message: "This file has not been read yet in this session. Use extract or search to read the file first."
60910
+ };
60911
+ }
60912
+ return { ok: true };
60913
+ }
60914
+ /**
60915
+ * Mark a file as seen after a successful write (backward compat).
60916
+ * Also invalidates content records for the file since its content changed.
60917
+ * @param {string} resolvedPath - Absolute path to the file
60918
+ */
60919
+ async trackFileAfterWrite(resolvedPath2) {
60920
+ this.markFileSeen(resolvedPath2);
60921
+ this.invalidateFileRecords(resolvedPath2);
60922
+ }
60923
+ /**
60924
+ * Update the stored hash for a symbol after a successful write.
60925
+ * Enables chained edits to the same symbol.
60926
+ * @param {string} resolvedPath - Absolute path to the file
60927
+ * @param {string} symbolName - Symbol name
60928
+ * @param {string} code - The symbol's new source code
60929
+ * @param {number} startLine - 1-indexed start line (new position)
60930
+ * @param {number} endLine - 1-indexed end line (new position)
60931
+ */
60932
+ trackSymbolAfterWrite(resolvedPath2, symbolName, code, startLine, endLine) {
60933
+ this.trackSymbolContent(resolvedPath2, symbolName, code, startLine, endLine, "edit");
60934
+ }
60935
+ /**
60936
+ * Remove all content records for a file.
60937
+ * Called after non-symbol edits (text/line mode) since those change content
60938
+ * without providing a symbol-level update.
60939
+ * @param {string} resolvedPath - Absolute path to the file
60940
+ */
60941
+ invalidateFileRecords(resolvedPath2) {
60942
+ const prefix = resolvedPath2 + "#";
60943
+ for (const key of this._contentRecords.keys()) {
60944
+ if (key.startsWith(prefix)) {
60945
+ this._contentRecords.delete(key);
60946
+ }
60947
+ }
60948
+ if (this.debug) {
60949
+ console.error(`[FileTracker] Invalidated content records for ${resolvedPath2}`);
60950
+ }
60951
+ }
60952
+ /**
60953
+ * Quick sync check if a file is being tracked (alias for isFileSeen).
60954
+ * @param {string} resolvedPath - Absolute path to the file
60955
+ * @returns {boolean}
60956
+ */
60957
+ isTracked(resolvedPath2) {
60958
+ return this.isFileSeen(resolvedPath2);
60959
+ }
60960
+ /**
60961
+ * Clear all tracking state.
60962
+ */
60963
+ clear() {
60964
+ this._seenFiles.clear();
60965
+ this._contentRecords.clear();
60966
+ }
60967
+ };
60968
+ }
60969
+ });
60970
+
59715
60971
  // src/agent/simpleTelemetry.js
59716
- var import_fs9, import_path10;
60972
+ var import_fs9, import_path11;
59717
60973
  var init_simpleTelemetry = __esm({
59718
60974
  "src/agent/simpleTelemetry.js"() {
59719
60975
  "use strict";
59720
60976
  import_fs9 = require("fs");
59721
- import_path10 = require("path");
60977
+ import_path11 = require("path");
59722
60978
  }
59723
60979
  });
59724
60980
 
@@ -59817,19 +61073,19 @@ function createWrappedTools(baseTools) {
59817
61073
  }
59818
61074
  return wrappedTools;
59819
61075
  }
59820
- var import_child_process8, import_util12, import_crypto3, import_events, import_fs10, import_fs11, import_path11, toolCallEmitter, activeToolExecutions, wrapToolWithEmitter, listFilesTool, searchFilesTool, listFilesToolInstance, searchFilesToolInstance;
61076
+ var import_child_process8, import_util12, import_crypto4, import_events, import_fs10, import_fs11, import_path12, toolCallEmitter, activeToolExecutions, wrapToolWithEmitter, listFilesTool, searchFilesTool, listFilesToolInstance, searchFilesToolInstance;
59821
61077
  var init_probeTool = __esm({
59822
61078
  "src/agent/probeTool.js"() {
59823
61079
  "use strict";
59824
61080
  init_index();
59825
61081
  import_child_process8 = require("child_process");
59826
61082
  import_util12 = require("util");
59827
- import_crypto3 = require("crypto");
61083
+ import_crypto4 = require("crypto");
59828
61084
  import_events = require("events");
59829
61085
  import_fs10 = __toESM(require("fs"), 1);
59830
61086
  import_fs11 = require("fs");
59831
- import_path11 = __toESM(require("path"), 1);
59832
- init_esm5();
61087
+ import_path12 = __toESM(require("path"), 1);
61088
+ init_esm7();
59833
61089
  init_symlink_utils();
59834
61090
  toolCallEmitter = new import_events.EventEmitter();
59835
61091
  activeToolExecutions = /* @__PURE__ */ new Map();
@@ -59839,7 +61095,7 @@ var init_probeTool = __esm({
59839
61095
  // Spread schema, description etc.
59840
61096
  execute: async (params) => {
59841
61097
  const debug = process.env.DEBUG === "1";
59842
- const toolSessionId = params.sessionId || (0, import_crypto3.randomUUID)();
61098
+ const toolSessionId = params.sessionId || (0, import_crypto4.randomUUID)();
59843
61099
  if (debug) {
59844
61100
  console.log(`[DEBUG] probeTool: Executing ${toolName} for session ${toolSessionId}`);
59845
61101
  }
@@ -59917,17 +61173,17 @@ var init_probeTool = __esm({
59917
61173
  execute: async (params) => {
59918
61174
  const { directory = ".", workingDirectory } = params;
59919
61175
  const baseCwd = workingDirectory || process.cwd();
59920
- const secureBaseDir = import_path11.default.resolve(baseCwd);
61176
+ const secureBaseDir = import_path12.default.resolve(baseCwd);
59921
61177
  const isDependencyPath = directory.startsWith("/dep/") || directory.startsWith("go:") || directory.startsWith("js:") || directory.startsWith("rust:");
59922
61178
  let targetDir;
59923
- if (import_path11.default.isAbsolute(directory)) {
59924
- targetDir = import_path11.default.resolve(directory);
59925
- if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + import_path11.default.sep) && targetDir !== secureBaseDir) {
61179
+ if (import_path12.default.isAbsolute(directory)) {
61180
+ targetDir = import_path12.default.resolve(directory);
61181
+ if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + import_path12.default.sep) && targetDir !== secureBaseDir) {
59926
61182
  throw new Error(`Path traversal attempt detected. Cannot access directory outside workspace: ${directory}`);
59927
61183
  }
59928
61184
  } else {
59929
- targetDir = import_path11.default.resolve(secureBaseDir, directory);
59930
- if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + import_path11.default.sep) && targetDir !== secureBaseDir) {
61185
+ targetDir = import_path12.default.resolve(secureBaseDir, directory);
61186
+ if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + import_path12.default.sep) && targetDir !== secureBaseDir) {
59931
61187
  throw new Error(`Path traversal attempt detected. Access denied: ${directory}`);
59932
61188
  }
59933
61189
  }
@@ -59944,7 +61200,7 @@ var init_probeTool = __esm({
59944
61200
  return `${(size / (1024 * 1024 * 1024)).toFixed(1)}G`;
59945
61201
  };
59946
61202
  const entries = await Promise.all(files.map(async (file) => {
59947
- const fullPath = import_path11.default.join(targetDir, file.name);
61203
+ const fullPath = import_path12.default.join(targetDir, file.name);
59948
61204
  const entryType = await getEntryType(file, fullPath);
59949
61205
  return {
59950
61206
  name: file.name,
@@ -59981,17 +61237,17 @@ var init_probeTool = __esm({
59981
61237
  throw new Error("Pattern is required for file search");
59982
61238
  }
59983
61239
  const baseCwd = workingDirectory || process.cwd();
59984
- const secureBaseDir = import_path11.default.resolve(baseCwd);
61240
+ const secureBaseDir = import_path12.default.resolve(baseCwd);
59985
61241
  const isDependencyPath = directory.startsWith("/dep/") || directory.startsWith("go:") || directory.startsWith("js:") || directory.startsWith("rust:");
59986
61242
  let targetDir;
59987
- if (import_path11.default.isAbsolute(directory)) {
59988
- targetDir = import_path11.default.resolve(directory);
59989
- if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + import_path11.default.sep) && targetDir !== secureBaseDir) {
61243
+ if (import_path12.default.isAbsolute(directory)) {
61244
+ targetDir = import_path12.default.resolve(directory);
61245
+ if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + import_path12.default.sep) && targetDir !== secureBaseDir) {
59990
61246
  throw new Error(`Path traversal attempt detected. Cannot access directory outside workspace: ${directory}`);
59991
61247
  }
59992
61248
  } else {
59993
- targetDir = import_path11.default.resolve(secureBaseDir, directory);
59994
- if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + import_path11.default.sep) && targetDir !== secureBaseDir) {
61249
+ targetDir = import_path12.default.resolve(secureBaseDir, directory);
61250
+ if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + import_path12.default.sep) && targetDir !== secureBaseDir) {
59995
61251
  throw new Error(`Path traversal attempt detected. Access denied: ${directory}`);
59996
61252
  }
59997
61253
  }
@@ -60568,6 +61824,7 @@ var init_index = __esm({
60568
61824
  init_executePlan();
60569
61825
  init_bash();
60570
61826
  init_edit();
61827
+ init_fileTracker();
60571
61828
  init_ProbeAgent();
60572
61829
  init_simpleTelemetry();
60573
61830
  init_probeTool();
@@ -60749,39 +62006,14 @@ function parseXmlToolCallWithThinking(xmlString, validTools) {
60749
62006
  const toolCall = parseXmlToolCall(cleanedXmlString, validTools);
60750
62007
  return toolCall ? { ...toolCall, thinkingContent } : null;
60751
62008
  }
60752
- var import_crypto4, implementToolDefinition, listFilesToolDefinition, searchFilesToolDefinition, listSkillsToolDefinition, useSkillToolDefinition, readImageToolDefinition;
62009
+ var import_crypto5, listFilesToolDefinition, searchFilesToolDefinition, listSkillsToolDefinition, useSkillToolDefinition, readImageToolDefinition;
60753
62010
  var init_tools2 = __esm({
60754
62011
  "src/agent/tools.js"() {
60755
62012
  "use strict";
60756
62013
  init_index();
60757
- import_crypto4 = require("crypto");
62014
+ import_crypto5 = require("crypto");
60758
62015
  init_xmlParsingUtils();
60759
62016
  init_tasks();
60760
- implementToolDefinition = `
60761
- ## implement
60762
- Description: Implement a given task. Can modify files. Can be used ONLY if task explicitly stated that something requires modification or implementation.
60763
-
60764
- Parameters:
60765
- - task: (required) The task description. Should be as detailed as possible, ideally pointing to exact files which needs be modified or created.
60766
- - autoCommits: (optional) Whether to enable auto-commits in aider. Default is false.
60767
-
60768
- Usage Example:
60769
-
60770
- <examples>
60771
-
60772
- User: Can you implement a function to calculate Fibonacci numbers in main.js?
60773
- <implement>
60774
- <task>Implement a recursive function to calculate the nth Fibonacci number in main.js</task>
60775
- </implement>
60776
-
60777
- User: Can you implement a function to calculate Fibonacci numbers in main.js with auto-commits?
60778
- <implement>
60779
- <task>Implement a recursive function to calculate the nth Fibonacci number in main.js</task>
60780
- <autoCommits>true</autoCommits>
60781
- </implement>
60782
-
60783
- </examples>
60784
- `;
60785
62017
  listFilesToolDefinition = `
60786
62018
  ## listFiles
60787
62019
  Description: List files and directories in a specified location.
@@ -60905,7 +62137,7 @@ function createMockProvider() {
60905
62137
  provider: "mock",
60906
62138
  // Mock the doGenerate method used by Vercel AI SDK
60907
62139
  doGenerate: async ({ messages, tools: tools2 }) => {
60908
- await new Promise((resolve7) => setTimeout(resolve7, 10));
62140
+ await new Promise((resolve8) => setTimeout(resolve8, 10));
60909
62141
  return {
60910
62142
  text: "This is a mock response for testing",
60911
62143
  toolCalls: [],
@@ -66108,23 +67340,23 @@ var init_regexp_parser = __esm({
66108
67340
  return ASSERT_NEVER_REACH_HERE();
66109
67341
  }
66110
67342
  quantifier(isBacktracking = false) {
66111
- let range2 = void 0;
67343
+ let range3 = void 0;
66112
67344
  const begin = this.idx;
66113
67345
  switch (this.popChar()) {
66114
67346
  case "*":
66115
- range2 = {
67347
+ range3 = {
66116
67348
  atLeast: 0,
66117
67349
  atMost: Infinity
66118
67350
  };
66119
67351
  break;
66120
67352
  case "+":
66121
- range2 = {
67353
+ range3 = {
66122
67354
  atLeast: 1,
66123
67355
  atMost: Infinity
66124
67356
  };
66125
67357
  break;
66126
67358
  case "?":
66127
- range2 = {
67359
+ range3 = {
66128
67360
  atLeast: 0,
66129
67361
  atMost: 1
66130
67362
  };
@@ -66133,7 +67365,7 @@ var init_regexp_parser = __esm({
66133
67365
  const atLeast = this.integerIncludingZero();
66134
67366
  switch (this.popChar()) {
66135
67367
  case "}":
66136
- range2 = {
67368
+ range3 = {
66137
67369
  atLeast,
66138
67370
  atMost: atLeast
66139
67371
  };
@@ -66142,12 +67374,12 @@ var init_regexp_parser = __esm({
66142
67374
  let atMost;
66143
67375
  if (this.isDigit()) {
66144
67376
  atMost = this.integerIncludingZero();
66145
- range2 = {
67377
+ range3 = {
66146
67378
  atLeast,
66147
67379
  atMost
66148
67380
  };
66149
67381
  } else {
66150
- range2 = {
67382
+ range3 = {
66151
67383
  atLeast,
66152
67384
  atMost: Infinity
66153
67385
  };
@@ -66155,25 +67387,25 @@ var init_regexp_parser = __esm({
66155
67387
  this.consumeChar("}");
66156
67388
  break;
66157
67389
  }
66158
- if (isBacktracking === true && range2 === void 0) {
67390
+ if (isBacktracking === true && range3 === void 0) {
66159
67391
  return void 0;
66160
67392
  }
66161
- ASSERT_EXISTS(range2);
67393
+ ASSERT_EXISTS(range3);
66162
67394
  break;
66163
67395
  }
66164
- if (isBacktracking === true && range2 === void 0) {
67396
+ if (isBacktracking === true && range3 === void 0) {
66165
67397
  return void 0;
66166
67398
  }
66167
- if (ASSERT_EXISTS(range2)) {
67399
+ if (ASSERT_EXISTS(range3)) {
66168
67400
  if (this.peekChar(0) === "?") {
66169
67401
  this.consumeChar("?");
66170
- range2.greedy = false;
67402
+ range3.greedy = false;
66171
67403
  } else {
66172
- range2.greedy = true;
67404
+ range3.greedy = true;
66173
67405
  }
66174
- range2.type = "Quantifier";
66175
- range2.loc = this.loc(begin);
66176
- return range2;
67406
+ range3.type = "Quantifier";
67407
+ range3.loc = this.loc(begin);
67408
+ return range3;
66177
67409
  }
66178
67410
  }
66179
67411
  atom() {
@@ -66875,18 +68107,18 @@ function firstCharOptimizedIndices(ast, result, ignoreCase) {
66875
68107
  if (typeof code === "number") {
66876
68108
  addOptimizedIdxToResult(code, result, ignoreCase);
66877
68109
  } else {
66878
- const range2 = code;
68110
+ const range3 = code;
66879
68111
  if (ignoreCase === true) {
66880
- for (let rangeCode = range2.from; rangeCode <= range2.to; rangeCode++) {
68112
+ for (let rangeCode = range3.from; rangeCode <= range3.to; rangeCode++) {
66881
68113
  addOptimizedIdxToResult(rangeCode, result, ignoreCase);
66882
68114
  }
66883
68115
  } else {
66884
- for (let rangeCode = range2.from; rangeCode <= range2.to && rangeCode < minOptimizationVal; rangeCode++) {
68116
+ for (let rangeCode = range3.from; rangeCode <= range3.to && rangeCode < minOptimizationVal; rangeCode++) {
66885
68117
  addOptimizedIdxToResult(rangeCode, result, ignoreCase);
66886
68118
  }
66887
- if (range2.to >= minOptimizationVal) {
66888
- const minUnOptVal = range2.from >= minOptimizationVal ? range2.from : minOptimizationVal;
66889
- const maxUnOptVal = range2.to;
68119
+ if (range3.to >= minOptimizationVal) {
68120
+ const minUnOptVal = range3.from >= minOptimizationVal ? range3.from : minOptimizationVal;
68121
+ const maxUnOptVal = range3.to;
66890
68122
  const minOptIdx = charCodeToOptimizedIndex(minUnOptVal);
66891
68123
  const maxOptIdx = charCodeToOptimizedIndex(maxUnOptVal);
66892
68124
  for (let currOptIdx = minOptIdx; currOptIdx <= maxOptIdx; currOptIdx++) {
@@ -66947,8 +68179,8 @@ function findCode(setNode, targetCharCodes) {
66947
68179
  if (typeof codeOrRange === "number") {
66948
68180
  return includes_default(targetCharCodes, codeOrRange);
66949
68181
  } else {
66950
- const range2 = codeOrRange;
66951
- return find_default(targetCharCodes, (targetCode) => range2.from <= targetCode && targetCode <= range2.to) !== void 0;
68182
+ const range3 = codeOrRange;
68183
+ return find_default(targetCharCodes, (targetCode) => range3.from <= targetCode && targetCode <= range3.to) !== void 0;
66952
68184
  }
66953
68185
  });
66954
68186
  }
@@ -84853,8 +86085,8 @@ var require_createRange = __commonJS({
84853
86085
  var require_range = __commonJS({
84854
86086
  "node_modules/lodash/range.js"(exports2, module2) {
84855
86087
  var createRange = require_createRange();
84856
- var range2 = createRange();
84857
- module2.exports = range2;
86088
+ var range3 = createRange();
86089
+ module2.exports = range3;
84858
86090
  }
84859
86091
  });
84860
86092
 
@@ -94095,7 +95327,7 @@ var require_compile = __commonJS({
94095
95327
  const schOrFunc = root2.refs[ref2];
94096
95328
  if (schOrFunc)
94097
95329
  return schOrFunc;
94098
- let _sch = resolve7.call(this, root2, ref2);
95330
+ let _sch = resolve8.call(this, root2, ref2);
94099
95331
  if (_sch === void 0) {
94100
95332
  const schema = (_a16 = root2.localRefs) === null || _a16 === void 0 ? void 0 : _a16[ref2];
94101
95333
  const { schemaId } = this.opts;
@@ -94122,7 +95354,7 @@ var require_compile = __commonJS({
94122
95354
  function sameSchemaEnv(s1, s22) {
94123
95355
  return s1.schema === s22.schema && s1.root === s22.root && s1.baseId === s22.baseId;
94124
95356
  }
94125
- function resolve7(root2, ref2) {
95357
+ function resolve8(root2, ref2) {
94126
95358
  let sch;
94127
95359
  while (typeof (sch = this.refs[ref2]) == "string")
94128
95360
  ref2 = sch;
@@ -94697,7 +95929,7 @@ var require_fast_uri = __commonJS({
94697
95929
  }
94698
95930
  return uri;
94699
95931
  }
94700
- function resolve7(baseURI, relativeURI, options) {
95932
+ function resolve8(baseURI, relativeURI, options) {
94701
95933
  const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
94702
95934
  const resolved = resolveComponent(parse9(baseURI, schemelessOptions), parse9(relativeURI, schemelessOptions), schemelessOptions, true);
94703
95935
  schemelessOptions.skipEscape = true;
@@ -94924,7 +96156,7 @@ var require_fast_uri = __commonJS({
94924
96156
  var fastUri = {
94925
96157
  SCHEMES,
94926
96158
  normalize: normalize3,
94927
- resolve: resolve7,
96159
+ resolve: resolve8,
94928
96160
  resolveComponent,
94929
96161
  equal,
94930
96162
  serialize,
@@ -97619,6 +98851,7 @@ __export(schemaUtils_exports, {
97619
98851
  replaceMermaidDiagramsInMarkdown: () => replaceMermaidDiagramsInMarkdown,
97620
98852
  sanitizeMarkdownEscapesInJson: () => sanitizeMarkdownEscapesInJson,
97621
98853
  tryAutoWrapForSimpleSchema: () => tryAutoWrapForSimpleSchema,
98854
+ tryExtractValidJsonPrefix: () => tryExtractValidJsonPrefix,
97622
98855
  tryMaidAutoFix: () => tryMaidAutoFix,
97623
98856
  validateAndFixMermaidResponse: () => validateAndFixMermaidResponse,
97624
98857
  validateJsonResponse: () => validateJsonResponse,
@@ -98005,6 +99238,13 @@ function validateJsonResponse(response, options = {}) {
98005
99238
  errorPosition = response.indexOf(problematicToken);
98006
99239
  }
98007
99240
  }
99241
+ const prefixResult = tryExtractValidJsonPrefix(responseToValidate, { schema, debug });
99242
+ if (prefixResult && prefixResult.isValid) {
99243
+ if (debug) {
99244
+ console.log(`[DEBUG] JSON validation: Recovered valid JSON prefix (${prefixResult.extracted.length} chars) from response with trailing content`);
99245
+ }
99246
+ return { isValid: true, parsed: prefixResult.parsed };
99247
+ }
98008
99248
  let enhancedError = error2.message;
98009
99249
  let errorContext = null;
98010
99250
  if (errorPosition !== null && errorPosition >= 0 && response && response.length > 0) {
@@ -98055,6 +99295,84 @@ ${errorContext.pointer}`);
98055
99295
  };
98056
99296
  }
98057
99297
  }
99298
+ function tryExtractValidJsonPrefix(response, options = {}) {
99299
+ const { schema = null, debug = false } = options;
99300
+ if (!response || typeof response !== "string") {
99301
+ return null;
99302
+ }
99303
+ const trimmed = response.trim();
99304
+ if (trimmed.length === 0) {
99305
+ return null;
99306
+ }
99307
+ const firstChar = trimmed[0];
99308
+ if (firstChar !== "{" && firstChar !== "[") {
99309
+ return null;
99310
+ }
99311
+ try {
99312
+ JSON.parse(trimmed);
99313
+ return null;
99314
+ } catch {
99315
+ }
99316
+ const openChar = firstChar;
99317
+ const closeChar = openChar === "{" ? "}" : "]";
99318
+ let depth = 0;
99319
+ let inString = false;
99320
+ let escapeNext = false;
99321
+ let endPos = -1;
99322
+ for (let i5 = 0; i5 < trimmed.length; i5++) {
99323
+ const char = trimmed[i5];
99324
+ if (escapeNext) {
99325
+ escapeNext = false;
99326
+ continue;
99327
+ }
99328
+ if (char === "\\" && inString) {
99329
+ escapeNext = true;
99330
+ continue;
99331
+ }
99332
+ if (char === '"') {
99333
+ inString = !inString;
99334
+ continue;
99335
+ }
99336
+ if (inString) {
99337
+ continue;
99338
+ }
99339
+ if (char === openChar) {
99340
+ depth++;
99341
+ } else if (char === closeChar) {
99342
+ depth--;
99343
+ if (depth === 0) {
99344
+ endPos = i5 + 1;
99345
+ break;
99346
+ }
99347
+ }
99348
+ }
99349
+ if (endPos <= 0 || endPos >= trimmed.length) {
99350
+ return null;
99351
+ }
99352
+ const remainder = trimmed.substring(endPos).trim();
99353
+ if (remainder.length === 0) {
99354
+ return null;
99355
+ }
99356
+ const prefix = trimmed.substring(0, endPos);
99357
+ try {
99358
+ const parsed = JSON.parse(prefix);
99359
+ if (debug) {
99360
+ console.log(`[DEBUG] tryExtractValidJsonPrefix: Extracted valid JSON prefix (${prefix.length} chars), stripped trailing content (${remainder.length} chars)`);
99361
+ }
99362
+ if (schema) {
99363
+ const schemaValidation = validateJsonResponse(prefix, { debug, schema });
99364
+ if (!schemaValidation.isValid) {
99365
+ if (debug) {
99366
+ console.log(`[DEBUG] tryExtractValidJsonPrefix: Prefix is valid JSON but fails schema validation: ${schemaValidation.error}`);
99367
+ }
99368
+ return null;
99369
+ }
99370
+ }
99371
+ return { isValid: true, parsed, extracted: prefix };
99372
+ } catch {
99373
+ return null;
99374
+ }
99375
+ }
98058
99376
  function validateXmlResponse(response) {
98059
99377
  const xmlPattern = /<\/?[\w\s="'.-]+>/g;
98060
99378
  const tags = response.match(xmlPattern);
@@ -99447,13 +100765,13 @@ function loadMCPConfiguration() {
99447
100765
  // Environment variable path
99448
100766
  process.env.MCP_CONFIG_PATH,
99449
100767
  // Local project paths
99450
- (0, import_path12.join)(process.cwd(), ".mcp", "config.json"),
99451
- (0, import_path12.join)(process.cwd(), "mcp.config.json"),
100768
+ (0, import_path13.join)(process.cwd(), ".mcp", "config.json"),
100769
+ (0, import_path13.join)(process.cwd(), "mcp.config.json"),
99452
100770
  // Home directory paths
99453
- (0, import_path12.join)((0, import_os3.homedir)(), ".config", "probe", "mcp.json"),
99454
- (0, import_path12.join)((0, import_os3.homedir)(), ".mcp", "config.json"),
100771
+ (0, import_path13.join)((0, import_os3.homedir)(), ".config", "probe", "mcp.json"),
100772
+ (0, import_path13.join)((0, import_os3.homedir)(), ".mcp", "config.json"),
99455
100773
  // Claude-style config location
99456
- (0, import_path12.join)((0, import_os3.homedir)(), "Library", "Application Support", "Claude", "mcp_config.json")
100774
+ (0, import_path13.join)((0, import_os3.homedir)(), "Library", "Application Support", "Claude", "mcp_config.json")
99457
100775
  ].filter(Boolean);
99458
100776
  let config = null;
99459
100777
  for (const configPath of configPaths) {
@@ -99580,16 +100898,16 @@ function parseEnabledServers(config) {
99580
100898
  }
99581
100899
  return servers;
99582
100900
  }
99583
- var import_fs12, import_path12, import_os3, import_url4, __filename4, __dirname4, DEFAULT_TIMEOUT, MAX_TIMEOUT, DEFAULT_CONFIG;
100901
+ var import_fs12, import_path13, import_os3, import_url4, __filename4, __dirname4, DEFAULT_TIMEOUT, MAX_TIMEOUT, DEFAULT_CONFIG;
99584
100902
  var init_config = __esm({
99585
100903
  "src/agent/mcp/config.js"() {
99586
100904
  "use strict";
99587
100905
  import_fs12 = require("fs");
99588
- import_path12 = require("path");
100906
+ import_path13 = require("path");
99589
100907
  import_os3 = require("os");
99590
100908
  import_url4 = require("url");
99591
100909
  __filename4 = (0, import_url4.fileURLToPath)("file:///");
99592
- __dirname4 = (0, import_path12.dirname)(__filename4);
100910
+ __dirname4 = (0, import_path13.dirname)(__filename4);
99593
100911
  DEFAULT_TIMEOUT = 3e4;
99594
100912
  MAX_TIMEOUT = (() => {
99595
100913
  if (process.env.MCP_MAX_TIMEOUT) {
@@ -99603,7 +100921,7 @@ var init_config = __esm({
99603
100921
  // Example probe server configuration
99604
100922
  "probe-local": {
99605
100923
  command: "node",
99606
- args: [(0, import_path12.join)(__dirname4, "../../../examples/chat/mcpServer.js")],
100924
+ args: [(0, import_path13.join)(__dirname4, "../../../examples/chat/mcpServer.js")],
99607
100925
  transport: "stdio",
99608
100926
  enabled: false
99609
100927
  },
@@ -100156,7 +101474,7 @@ function parseXmlMcpToolCall(xmlString, mcpToolNames = []) {
100156
101474
  let match2;
100157
101475
  while ((match2 = paramPattern.exec(content)) !== null) {
100158
101476
  const [, paramName, paramValue] = match2;
100159
- params[paramName] = paramValue.trim();
101477
+ params[paramName] = unescapeXmlEntities(paramValue.trim());
100160
101478
  }
100161
101479
  }
100162
101480
  return { toolName, params };
@@ -100206,7 +101524,7 @@ function parseNativeXmlTool(xmlString, toolName) {
100206
101524
  while ((match2 = paramPattern.exec(content)) !== null) {
100207
101525
  const [, paramName, paramValue] = match2;
100208
101526
  if (paramName !== "params") {
100209
- params[paramName] = paramValue.trim();
101527
+ params[paramName] = unescapeXmlEntities(paramValue.trim());
100210
101528
  }
100211
101529
  }
100212
101530
  if (Object.keys(params).length > 0) {
@@ -100221,6 +101539,7 @@ var init_xmlBridge = __esm({
100221
101539
  init_client2();
100222
101540
  init_config();
100223
101541
  init_xmlParsingUtils();
101542
+ init_common2();
100224
101543
  MCPXmlBridge = class {
100225
101544
  constructor(options = {}) {
100226
101545
  this.debug = options.debug || false;
@@ -105186,7 +106505,7 @@ var require_compose_scalar = __commonJS({
105186
106505
  var resolveBlockScalar = require_resolve_block_scalar();
105187
106506
  var resolveFlowScalar = require_resolve_flow_scalar();
105188
106507
  function composeScalar(ctx, token, tagToken, onError) {
105189
- const { value, type, comment, range: range2 } = token.type === "block-scalar" ? resolveBlockScalar.resolveBlockScalar(ctx, token, onError) : resolveFlowScalar.resolveFlowScalar(token, ctx.options.strict, onError);
106508
+ const { value, type, comment, range: range3 } = token.type === "block-scalar" ? resolveBlockScalar.resolveBlockScalar(ctx, token, onError) : resolveFlowScalar.resolveFlowScalar(token, ctx.options.strict, onError);
105190
106509
  const tagName = tagToken ? ctx.directives.tagName(tagToken.source, (msg) => onError(tagToken, "TAG_RESOLVE_FAILED", msg)) : null;
105191
106510
  let tag2;
105192
106511
  if (ctx.options.stringKeys && ctx.atKey) {
@@ -105206,7 +106525,7 @@ var require_compose_scalar = __commonJS({
105206
106525
  onError(tagToken ?? token, "TAG_RESOLVE_FAILED", msg);
105207
106526
  scalar = new Scalar.Scalar(value);
105208
106527
  }
105209
- scalar.range = range2;
106528
+ scalar.range = range3;
105210
106529
  scalar.source = value;
105211
106530
  if (type)
105212
106531
  scalar.type = type;
@@ -107797,17 +109116,17 @@ async function parseSkillFile(skillFilePath, directoryName) {
107797
109116
  description,
107798
109117
  skillFilePath,
107799
109118
  directoryName,
107800
- sourceDir: (0, import_path13.dirname)(skillFilePath)
109119
+ sourceDir: (0, import_path14.dirname)(skillFilePath)
107801
109120
  },
107802
109121
  error: null
107803
109122
  };
107804
109123
  }
107805
- var import_promises2, import_path13, import_yaml, SKILL_NAME_REGEX, MAX_SKILL_NAME_LENGTH, MAX_DESCRIPTION_CHARS;
109124
+ var import_promises2, import_path14, import_yaml, SKILL_NAME_REGEX, MAX_SKILL_NAME_LENGTH, MAX_DESCRIPTION_CHARS;
107806
109125
  var init_parser7 = __esm({
107807
109126
  "src/agent/skills/parser.js"() {
107808
109127
  "use strict";
107809
109128
  import_promises2 = require("fs/promises");
107810
- import_path13 = require("path");
109129
+ import_path14 = require("path");
107811
109130
  import_yaml = __toESM(require_dist(), 1);
107812
109131
  SKILL_NAME_REGEX = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
107813
109132
  MAX_SKILL_NAME_LENGTH = 64;
@@ -107817,12 +109136,12 @@ var init_parser7 = __esm({
107817
109136
 
107818
109137
  // src/agent/skills/registry.js
107819
109138
  function isPathInside(basePath, targetPath) {
107820
- const base2 = (0, import_path14.resolve)(basePath);
107821
- const target = (0, import_path14.resolve)(targetPath);
107822
- const rel = (0, import_path14.relative)(base2, target);
109139
+ const base2 = (0, import_path15.resolve)(basePath);
109140
+ const target = (0, import_path15.resolve)(targetPath);
109141
+ const rel = (0, import_path15.relative)(base2, target);
107823
109142
  if (rel === "") return true;
107824
- if (rel === ".." || rel.startsWith(`..${import_path14.sep}`)) return false;
107825
- if ((0, import_path14.isAbsolute)(rel)) return false;
109143
+ if (rel === ".." || rel.startsWith(`..${import_path15.sep}`)) return false;
109144
+ if ((0, import_path15.isAbsolute)(rel)) return false;
107826
109145
  return true;
107827
109146
  }
107828
109147
  function isSafeEntryName(name14) {
@@ -107830,19 +109149,19 @@ function isSafeEntryName(name14) {
107830
109149
  if (name14.includes("\0")) return false;
107831
109150
  return !name14.includes("/") && !name14.includes("\\");
107832
109151
  }
107833
- var import_fs13, import_promises3, import_path14, DEFAULT_SKILL_DIRS, SKILL_FILE_NAME, SkillRegistry;
109152
+ var import_fs13, import_promises3, import_path15, DEFAULT_SKILL_DIRS, SKILL_FILE_NAME, SkillRegistry;
107834
109153
  var init_registry = __esm({
107835
109154
  "src/agent/skills/registry.js"() {
107836
109155
  "use strict";
107837
109156
  import_fs13 = require("fs");
107838
109157
  import_promises3 = require("fs/promises");
107839
- import_path14 = require("path");
109158
+ import_path15 = require("path");
107840
109159
  init_parser7();
107841
109160
  DEFAULT_SKILL_DIRS = [".claude/skills", ".codex/skills", "skills", ".skills"];
107842
109161
  SKILL_FILE_NAME = "SKILL.md";
107843
109162
  SkillRegistry = class {
107844
109163
  constructor({ repoRoot, skillDirs = DEFAULT_SKILL_DIRS, debug = false } = {}) {
107845
- this.repoRoot = repoRoot ? (0, import_path14.resolve)(repoRoot) : process.cwd();
109164
+ this.repoRoot = repoRoot ? (0, import_path15.resolve)(repoRoot) : process.cwd();
107846
109165
  this.repoRootReal = null;
107847
109166
  this.skillDirs = Array.isArray(skillDirs) && skillDirs.length > 0 ? skillDirs : DEFAULT_SKILL_DIRS;
107848
109167
  this.debug = debug;
@@ -107896,8 +109215,8 @@ var init_registry = __esm({
107896
109215
  }
107897
109216
  }
107898
109217
  async _resolveSkillDir(skillDir) {
107899
- const resolved = (0, import_path14.isAbsolute)(skillDir) ? (0, import_path14.resolve)(skillDir) : (0, import_path14.resolve)(this.repoRoot, skillDir);
107900
- const repoRoot = this.repoRootReal || (0, import_path14.resolve)(this.repoRoot);
109218
+ const resolved = (0, import_path15.isAbsolute)(skillDir) ? (0, import_path15.resolve)(skillDir) : (0, import_path15.resolve)(this.repoRoot, skillDir);
109219
+ const repoRoot = this.repoRootReal || (0, import_path15.resolve)(this.repoRoot);
107901
109220
  const resolvedReal = await this._resolveRealPath(resolved);
107902
109221
  if (!resolvedReal) return null;
107903
109222
  if (!isPathInside(repoRoot, resolvedReal)) {
@@ -107928,8 +109247,8 @@ var init_registry = __esm({
107928
109247
  }
107929
109248
  continue;
107930
109249
  }
107931
- const skillFolder = (0, import_path14.join)(dirPath, entry.name);
107932
- const skillFilePath = (0, import_path14.join)(skillFolder, SKILL_FILE_NAME);
109250
+ const skillFolder = (0, import_path15.join)(dirPath, entry.name);
109251
+ const skillFilePath = (0, import_path15.join)(skillFolder, SKILL_FILE_NAME);
107933
109252
  let skillStat;
107934
109253
  try {
107935
109254
  skillStat = await (0, import_promises3.lstat)(skillFilePath);
@@ -108087,7 +109406,7 @@ function extractErrorInfo(error2) {
108087
109406
  };
108088
109407
  }
108089
109408
  function sleep(ms) {
108090
- return new Promise((resolve7) => setTimeout(resolve7, ms));
109409
+ return new Promise((resolve8) => setTimeout(resolve8, ms));
108091
109410
  }
108092
109411
  var DEFAULT_RETRYABLE_ERRORS, RetryManager;
108093
109412
  var init_RetryManager = __esm({
@@ -108867,9 +110186,9 @@ async function truncateIfNeeded(content, tokenCounter, sessionId, maxTokens) {
108867
110186
  let tempFilePath = null;
108868
110187
  let fileError = null;
108869
110188
  try {
108870
- const tempDir = (0, import_path15.join)((0, import_os4.tmpdir)(), "probe-output");
110189
+ const tempDir = (0, import_path16.join)((0, import_os4.tmpdir)(), "probe-output");
108871
110190
  await (0, import_promises4.mkdir)(tempDir, { recursive: true });
108872
- tempFilePath = (0, import_path15.join)(tempDir, `tool-output-${sessionId || "unknown"}-${(0, import_crypto5.randomUUID)()}.txt`);
110191
+ tempFilePath = (0, import_path16.join)(tempDir, `tool-output-${sessionId || "unknown"}-${(0, import_crypto6.randomUUID)()}.txt`);
108873
110192
  await (0, import_promises4.writeFile)(tempFilePath, content, "utf8");
108874
110193
  } catch (err) {
108875
110194
  fileError = err.message || "Unknown file system error";
@@ -108917,14 +110236,14 @@ ${truncatedBody}
108917
110236
  error: fileError || void 0
108918
110237
  };
108919
110238
  }
108920
- var import_promises4, import_os4, import_path15, import_crypto5, DEFAULT_MAX_OUTPUT_TOKENS, CHARS_PER_TOKEN2, TAIL_TOKENS, MIN_LIMIT_FOR_TAIL;
110239
+ var import_promises4, import_os4, import_path16, import_crypto6, DEFAULT_MAX_OUTPUT_TOKENS, CHARS_PER_TOKEN2, TAIL_TOKENS, MIN_LIMIT_FOR_TAIL;
108921
110240
  var init_outputTruncator = __esm({
108922
110241
  "src/agent/outputTruncator.js"() {
108923
110242
  "use strict";
108924
110243
  import_promises4 = require("fs/promises");
108925
110244
  import_os4 = require("os");
108926
- import_path15 = require("path");
108927
- import_crypto5 = require("crypto");
110245
+ import_path16 = require("path");
110246
+ import_crypto6 = require("crypto");
108928
110247
  DEFAULT_MAX_OUTPUT_TOKENS = 2e4;
108929
110248
  CHARS_PER_TOKEN2 = 4;
108930
110249
  TAIL_TOKENS = 1e3;
@@ -108933,13 +110252,13 @@ var init_outputTruncator = __esm({
108933
110252
  });
108934
110253
 
108935
110254
  // src/agent/mcp/built-in-server.js
108936
- var import_http, import_events2, import_crypto6, import_server, import_sse2, import_streamableHttp, import_types3, InMemoryEventStore, BuiltInMCPServer;
110255
+ var import_http, import_events2, import_crypto7, import_server, import_sse2, import_streamableHttp, import_types3, InMemoryEventStore, BuiltInMCPServer;
108937
110256
  var init_built_in_server = __esm({
108938
110257
  "src/agent/mcp/built-in-server.js"() {
108939
110258
  "use strict";
108940
110259
  import_http = require("http");
108941
110260
  import_events2 = require("events");
108942
- import_crypto6 = require("crypto");
110261
+ import_crypto7 = require("crypto");
108943
110262
  import_server = require("@modelcontextprotocol/sdk/server/index.js");
108944
110263
  import_sse2 = require("@modelcontextprotocol/sdk/server/sse.js");
108945
110264
  import_streamableHttp = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
@@ -109015,7 +110334,7 @@ var init_built_in_server = __esm({
109015
110334
  }
109016
110335
  });
109017
110336
  this.registerHandlers();
109018
- return new Promise((resolve7, reject2) => {
110337
+ return new Promise((resolve8, reject2) => {
109019
110338
  this.httpServer.listen(this.port, this.host, async () => {
109020
110339
  const address = this.httpServer.address();
109021
110340
  this.port = address.port;
@@ -109025,7 +110344,7 @@ var init_built_in_server = __esm({
109025
110344
  console.log(`[MCP] Messages endpoint: http://${this.host}:${this.port}/messages`);
109026
110345
  }
109027
110346
  this.emit("ready", { host: this.host, port: this.port });
109028
- resolve7({ host: this.host, port: this.port });
110347
+ resolve8({ host: this.host, port: this.port });
109029
110348
  });
109030
110349
  this.httpServer.on("error", reject2);
109031
110350
  });
@@ -109183,7 +110502,7 @@ var init_built_in_server = __esm({
109183
110502
  }
109184
110503
  const eventStore = new InMemoryEventStore();
109185
110504
  transport = new import_streamableHttp.StreamableHTTPServerTransport({
109186
- sessionIdGenerator: () => (0, import_crypto6.randomUUID)(),
110505
+ sessionIdGenerator: () => (0, import_crypto7.randomUUID)(),
109187
110506
  eventStore,
109188
110507
  // Enable resumability
109189
110508
  onsessioninitialized: (newSessionId) => {
@@ -109244,7 +110563,7 @@ var init_built_in_server = __esm({
109244
110563
  * Parse request body as JSON
109245
110564
  */
109246
110565
  async parseRequestBody(req) {
109247
- return new Promise((resolve7, reject2) => {
110566
+ return new Promise((resolve8, reject2) => {
109248
110567
  let body = "";
109249
110568
  req.on("data", (chunk) => {
109250
110569
  body += chunk.toString();
@@ -109252,7 +110571,7 @@ var init_built_in_server = __esm({
109252
110571
  req.on("end", () => {
109253
110572
  try {
109254
110573
  const parsed = body ? JSON.parse(body) : null;
109255
- resolve7(parsed);
110574
+ resolve8(parsed);
109256
110575
  } catch (error2) {
109257
110576
  reject2(error2);
109258
110577
  }
@@ -109559,12 +110878,12 @@ data: ${JSON.stringify(data3)}
109559
110878
  }
109560
110879
  this.connections.clear();
109561
110880
  if (this.httpServer) {
109562
- return new Promise((resolve7) => {
110881
+ return new Promise((resolve8) => {
109563
110882
  this.httpServer.close(() => {
109564
110883
  if (this.debug) {
109565
110884
  console.log("[MCP] Built-in server stopped");
109566
110885
  }
109567
- resolve7();
110886
+ resolve8();
109568
110887
  });
109569
110888
  });
109570
110889
  }
@@ -109646,7 +110965,7 @@ __export(enhanced_claude_code_exports, {
109646
110965
  async function createEnhancedClaudeCLIEngine(options = {}) {
109647
110966
  const { agent, systemPrompt, customPrompt, debug, sessionId, allowedTools, timeout = 12e4 } = options;
109648
110967
  const session = new Session(
109649
- sessionId || (0, import_crypto7.randomBytes)(8).toString("hex"),
110968
+ sessionId || (0, import_crypto8.randomBytes)(8).toString("hex"),
109650
110969
  debug
109651
110970
  );
109652
110971
  let mcpServer = null;
@@ -109663,12 +110982,12 @@ async function createEnhancedClaudeCLIEngine(options = {}) {
109663
110982
  console.log("[DEBUG] Built-in MCP server started");
109664
110983
  console.log("[DEBUG] MCP URL:", `http://${host}:${port}/mcp`);
109665
110984
  }
109666
- mcpConfigPath = import_path16.default.join(import_os5.default.tmpdir(), `probe-mcp-${session.id}.json`);
110985
+ mcpConfigPath = import_path17.default.join(import_os5.default.tmpdir(), `probe-mcp-${session.id}.json`);
109667
110986
  const mcpConfig = {
109668
110987
  mcpServers: {
109669
110988
  probe: {
109670
110989
  command: "node",
109671
- args: [import_path16.default.join(process.cwd(), "mcp-probe-server.js")],
110990
+ args: [import_path17.default.join(process.cwd(), "mcp-probe-server.js")],
109672
110991
  env: {
109673
110992
  PROBE_WORKSPACE: process.cwd(),
109674
110993
  DEBUG: debug ? "true" : "false"
@@ -109893,8 +111212,8 @@ ${opts.schema}`;
109893
111212
  break;
109894
111213
  }
109895
111214
  } else if (!processEnded) {
109896
- await new Promise((resolve7) => {
109897
- resolver = resolve7;
111215
+ await new Promise((resolve8) => {
111216
+ resolver = resolve8;
109898
111217
  });
109899
111218
  }
109900
111219
  }
@@ -110093,14 +111412,14 @@ function combinePrompts(systemPrompt, customPrompt, agent) {
110093
111412
  }
110094
111413
  return systemPrompt || "";
110095
111414
  }
110096
- var import_child_process9, import_crypto7, import_promises5, import_path16, import_os5, import_events3;
111415
+ var import_child_process9, import_crypto8, import_promises5, import_path17, import_os5, import_events3;
110097
111416
  var init_enhanced_claude_code = __esm({
110098
111417
  "src/agent/engines/enhanced-claude-code.js"() {
110099
111418
  "use strict";
110100
111419
  import_child_process9 = require("child_process");
110101
- import_crypto7 = require("crypto");
111420
+ import_crypto8 = require("crypto");
110102
111421
  import_promises5 = __toESM(require("fs/promises"), 1);
110103
- import_path16 = __toESM(require("path"), 1);
111422
+ import_path17 = __toESM(require("path"), 1);
110104
111423
  import_os5 = __toESM(require("os"), 1);
110105
111424
  import_events3 = require("events");
110106
111425
  init_built_in_server();
@@ -110116,7 +111435,7 @@ __export(codex_exports, {
110116
111435
  async function createCodexEngine(options = {}) {
110117
111436
  const { agent, systemPrompt, customPrompt, debug, sessionId, allowedTools, model } = options;
110118
111437
  const session = new Session(
110119
- sessionId || (0, import_crypto8.randomBytes)(8).toString("hex"),
111438
+ sessionId || (0, import_crypto9.randomBytes)(8).toString("hex"),
110120
111439
  debug
110121
111440
  );
110122
111441
  let mcpServer = null;
@@ -110158,12 +111477,12 @@ async function createCodexEngine(options = {}) {
110158
111477
  }
110159
111478
  }
110160
111479
  if (message.id !== void 0 && pendingRequests.has(message.id)) {
110161
- const { resolve: resolve7, reject: reject2 } = pendingRequests.get(message.id);
111480
+ const { resolve: resolve8, reject: reject2 } = pendingRequests.get(message.id);
110162
111481
  pendingRequests.delete(message.id);
110163
111482
  if (message.error) {
110164
111483
  reject2(new Error(message.error.message || JSON.stringify(message.error)));
110165
111484
  } else {
110166
- resolve7(message.result);
111485
+ resolve8(message.result);
110167
111486
  }
110168
111487
  }
110169
111488
  if (message.method === "codex/event" && message.params) {
@@ -110184,7 +111503,7 @@ async function createCodexEngine(options = {}) {
110184
111503
  });
110185
111504
  }
110186
111505
  function sendRequest(method, params = {}) {
110187
- return new Promise((resolve7, reject2) => {
111506
+ return new Promise((resolve8, reject2) => {
110188
111507
  const id = ++requestId;
110189
111508
  const request = {
110190
111509
  jsonrpc: "2.0",
@@ -110192,7 +111511,7 @@ async function createCodexEngine(options = {}) {
110192
111511
  method,
110193
111512
  params
110194
111513
  };
110195
- pendingRequests.set(id, { resolve: resolve7, reject: reject2 });
111514
+ pendingRequests.set(id, { resolve: resolve8, reject: reject2 });
110196
111515
  setTimeout(() => {
110197
111516
  if (pendingRequests.has(id)) {
110198
111517
  pendingRequests.delete(id);
@@ -110255,7 +111574,7 @@ ${prompt}`;
110255
111574
  const reqId = requestId + 1;
110256
111575
  let fullResponse = "";
110257
111576
  let gotSessionId = false;
110258
- const eventPromise = new Promise((resolve7) => {
111577
+ const eventPromise = new Promise((resolve8) => {
110259
111578
  eventHandlers.set(reqId, (eventParams) => {
110260
111579
  const msg = eventParams.msg;
110261
111580
  if (msg.type === "session_configured" && msg.session_id && !gotSessionId) {
@@ -110275,7 +111594,7 @@ ${prompt}`;
110275
111594
  });
110276
111595
  setTimeout(() => {
110277
111596
  eventHandlers.delete(reqId);
110278
- resolve7();
111597
+ resolve8();
110279
111598
  }, 6e5);
110280
111599
  });
110281
111600
  const resultPromise = sendRequest("tools/call", {
@@ -110371,12 +111690,12 @@ function combinePrompts2(systemPrompt, customPrompt, agent) {
110371
111690
  }
110372
111691
  return systemPrompt || "";
110373
111692
  }
110374
- var import_child_process10, import_crypto8, import_readline;
111693
+ var import_child_process10, import_crypto9, import_readline;
110375
111694
  var init_codex = __esm({
110376
111695
  "src/agent/engines/codex.js"() {
110377
111696
  "use strict";
110378
111697
  import_child_process10 = require("child_process");
110379
- import_crypto8 = require("crypto");
111698
+ import_crypto9 = require("crypto");
110380
111699
  import_readline = require("readline");
110381
111700
  init_built_in_server();
110382
111701
  init_Session();
@@ -110482,7 +111801,7 @@ Your content here
110482
111801
 
110483
111802
  Do NOT wrap in other tags like <api_call>, <tool_name>, <function>, etc.`;
110484
111803
  }
110485
- var import_dotenv2, import_anthropic2, import_openai2, import_google2, import_ai6, import_crypto9, import_events4, import_fs14, import_promises6, import_path17, ENGINE_ACTIVITY_TIMEOUT_DEFAULT, ENGINE_ACTIVITY_TIMEOUT_MIN, ENGINE_ACTIVITY_TIMEOUT_MAX, MAX_TOOL_ITERATIONS, MAX_HISTORY_MESSAGES, MAX_IMAGE_FILE_SIZE, ProbeAgent;
111804
+ var import_dotenv2, import_anthropic2, import_openai2, import_google2, import_ai6, import_crypto10, import_events4, import_fs14, import_promises6, import_path18, ENGINE_ACTIVITY_TIMEOUT_DEFAULT, ENGINE_ACTIVITY_TIMEOUT_MIN, ENGINE_ACTIVITY_TIMEOUT_MAX, MAX_TOOL_ITERATIONS, MAX_HISTORY_MESSAGES, MAX_IMAGE_FILE_SIZE, ProbeAgent;
110486
111805
  var init_ProbeAgent = __esm({
110487
111806
  "src/agent/ProbeAgent.js"() {
110488
111807
  import_dotenv2 = __toESM(require_main(), 1);
@@ -110491,17 +111810,18 @@ var init_ProbeAgent = __esm({
110491
111810
  import_google2 = require("@ai-sdk/google");
110492
111811
  init_dist3();
110493
111812
  import_ai6 = require("ai");
110494
- import_crypto9 = require("crypto");
111813
+ import_crypto10 = require("crypto");
110495
111814
  import_events4 = require("events");
110496
111815
  import_fs14 = require("fs");
110497
111816
  import_promises6 = require("fs/promises");
110498
- import_path17 = require("path");
111817
+ import_path18 = require("path");
110499
111818
  init_tokenCounter();
110500
111819
  init_InMemoryStorageAdapter();
110501
111820
  init_HookManager();
110502
111821
  init_imageConfig();
110503
111822
  init_tools2();
110504
111823
  init_common2();
111824
+ init_fileTracker();
110505
111825
  init_probeTool();
110506
111826
  init_mockProvider();
110507
111827
  init_index();
@@ -110543,7 +111863,7 @@ var init_ProbeAgent = __esm({
110543
111863
  * @param {string} [options.customPrompt] - Custom prompt to replace the default system message
110544
111864
  * @param {string} [options.systemPrompt] - Alias for customPrompt; takes precedence when both are provided
110545
111865
  * @param {string} [options.promptType] - Predefined prompt type (code-explorer, code-searcher, architect, code-review, support)
110546
- * @param {boolean} [options.allowEdit=false] - Allow the use of the 'implement' tool
111866
+ * @param {boolean} [options.allowEdit=false] - Allow the use of the 'edit' and 'create' tools
110547
111867
  * @param {boolean} [options.enableDelegate=false] - Enable the delegate tool for task distribution to subagents
110548
111868
  * @param {boolean} [options.enableExecutePlan=false] - Enable the execute_plan DSL orchestration tool
110549
111869
  * @param {string} [options.architectureFileName] - Architecture context filename to embed from repo root (defaults to AGENTS.md with CLAUDE.md fallback; ARCHITECTURE.md is always included when present)
@@ -110588,10 +111908,11 @@ var init_ProbeAgent = __esm({
110588
111908
  * @param {number} [options.maxOperationTimeout] - Maximum timeout in ms for the entire operation including all retries and fallbacks (default: 300000 or MAX_OPERATION_TIMEOUT env var). This is the absolute maximum time for streamTextWithRetryAndFallback.
110589
111909
  */
110590
111910
  constructor(options = {}) {
110591
- this.sessionId = options.sessionId || (0, import_crypto9.randomUUID)();
111911
+ this.sessionId = options.sessionId || (0, import_crypto10.randomUUID)();
110592
111912
  this.customPrompt = options.systemPrompt || options.customPrompt || null;
110593
111913
  this.promptType = options.promptType || "code-explorer";
110594
111914
  this.allowEdit = !!options.allowEdit;
111915
+ this.hashLines = options.hashLines !== void 0 ? !!options.hashLines : this.allowEdit;
110595
111916
  this.enableDelegate = !!options.enableDelegate;
110596
111917
  this.enableExecutePlan = !!options.enableExecutePlan;
110597
111918
  this.debug = options.debug || process.env.DEBUG === "1";
@@ -110653,7 +111974,8 @@ var init_ProbeAgent = __esm({
110653
111974
  if (this.debug) {
110654
111975
  console.log(`[DEBUG] Generated session ID for agent: ${this.sessionId}`);
110655
111976
  console.log(`[DEBUG] Maximum tool iterations configured: ${MAX_TOOL_ITERATIONS}`);
110656
- console.log(`[DEBUG] Allow Edit (implement tool): ${this.allowEdit}`);
111977
+ console.log(`[DEBUG] Allow Edit: ${this.allowEdit}`);
111978
+ console.log(`[DEBUG] Hash Lines: ${this.hashLines}`);
110657
111979
  console.log(`[DEBUG] Search delegation enabled: ${this.searchDelegate}`);
110658
111980
  console.log(`[DEBUG] Workspace root: ${this.workspaceRoot}`);
110659
111981
  console.log(`[DEBUG] Working directory (cwd): ${this.cwd}`);
@@ -111038,9 +112360,12 @@ var init_ProbeAgent = __esm({
111038
112360
  cwd: this.cwd,
111039
112361
  workspaceRoot: this.workspaceRoot,
111040
112362
  allowedFolders: this.allowedFolders,
112363
+ // File state tracking for safe multi-edit workflows (only when editing is enabled)
112364
+ fileTracker: this.allowEdit ? new FileTracker({ debug: this.debug }) : null,
111041
112365
  outline: this.outline,
111042
112366
  searchDelegate: this.searchDelegate,
111043
112367
  allowEdit: this.allowEdit,
112368
+ hashLines: this.hashLines,
111044
112369
  enableDelegate: this.enableDelegate,
111045
112370
  enableExecutePlan: this.enableExecutePlan,
111046
112371
  enableBash: this.enableBash,
@@ -111111,7 +112436,7 @@ var init_ProbeAgent = __esm({
111111
112436
  if (!imagePath) {
111112
112437
  throw new Error("Image path is required");
111113
112438
  }
111114
- const filename = (0, import_path17.basename)(imagePath);
112439
+ const filename = (0, import_path18.basename)(imagePath);
111115
112440
  const extension = filename.toLowerCase().split(".").pop();
111116
112441
  if (!extension || !SUPPORTED_IMAGE_EXTENSIONS.includes(extension)) {
111117
112442
  throw new Error(`Invalid or unsupported image extension: ${extension}. Supported formats: ${SUPPORTED_IMAGE_EXTENSIONS.join(", ")}`);
@@ -111825,7 +113150,7 @@ var init_ProbeAgent = __esm({
111825
113150
  let resolvedPath2 = imagePath;
111826
113151
  if (!imagePath.includes("/") && !imagePath.includes("\\")) {
111827
113152
  for (const dir of listFilesDirectories) {
111828
- const potentialPath = (0, import_path17.resolve)(dir, imagePath);
113153
+ const potentialPath = (0, import_path18.resolve)(dir, imagePath);
111829
113154
  const loaded = await this.loadImageIfValid(potentialPath);
111830
113155
  if (loaded) {
111831
113156
  if (this.debug) {
@@ -111850,7 +113175,7 @@ var init_ProbeAgent = __esm({
111850
113175
  let match2;
111851
113176
  while ((match2 = fileHeaderPattern.exec(content)) !== null) {
111852
113177
  const filePath = match2[1].trim();
111853
- const dir = (0, import_path17.dirname)(filePath);
113178
+ const dir = (0, import_path18.dirname)(filePath);
111854
113179
  if (dir && dir !== ".") {
111855
113180
  directories.push(dir);
111856
113181
  if (this.debug) {
@@ -111895,17 +113220,17 @@ var init_ProbeAgent = __esm({
111895
113220
  const allowedDirs = this.allowedFolders && this.allowedFolders.length > 0 ? this.allowedFolders : [process.cwd()];
111896
113221
  let absolutePath;
111897
113222
  let isPathAllowed2 = false;
111898
- if ((0, import_path17.isAbsolute)(imagePath)) {
111899
- absolutePath = safeRealpath((0, import_path17.resolve)(imagePath));
113223
+ if ((0, import_path18.isAbsolute)(imagePath)) {
113224
+ absolutePath = safeRealpath((0, import_path18.resolve)(imagePath));
111900
113225
  isPathAllowed2 = allowedDirs.some((dir) => {
111901
113226
  const resolvedDir = safeRealpath(dir);
111902
- return absolutePath === resolvedDir || absolutePath.startsWith(resolvedDir + import_path17.sep);
113227
+ return absolutePath === resolvedDir || absolutePath.startsWith(resolvedDir + import_path18.sep);
111903
113228
  });
111904
113229
  } else {
111905
113230
  for (const dir of allowedDirs) {
111906
113231
  const resolvedDir = safeRealpath(dir);
111907
- const resolvedPath2 = safeRealpath((0, import_path17.resolve)(dir, imagePath));
111908
- if (resolvedPath2 === resolvedDir || resolvedPath2.startsWith(resolvedDir + import_path17.sep)) {
113232
+ const resolvedPath2 = safeRealpath((0, import_path18.resolve)(dir, imagePath));
113233
+ if (resolvedPath2 === resolvedDir || resolvedPath2.startsWith(resolvedDir + import_path18.sep)) {
111909
113234
  absolutePath = resolvedPath2;
111910
113235
  isPathAllowed2 = true;
111911
113236
  break;
@@ -112093,8 +113418,8 @@ var init_ProbeAgent = __esm({
112093
113418
  const hasConfiguredName = !!configuredName;
112094
113419
  let guidanceCandidates = [];
112095
113420
  if (hasConfiguredName) {
112096
- const targetName = (0, import_path17.basename)(configuredName);
112097
- if (configuredName !== targetName || configuredName.includes("/") || configuredName.includes("\\") || configuredName.includes("..") || (0, import_path17.isAbsolute)(configuredName)) {
113421
+ const targetName = (0, import_path18.basename)(configuredName);
113422
+ if (configuredName !== targetName || configuredName.includes("/") || configuredName.includes("\\") || configuredName.includes("..") || (0, import_path18.isAbsolute)(configuredName)) {
112098
113423
  console.warn(`[WARN] Invalid architectureFileName (must be a simple filename): ${configuredName}`);
112099
113424
  } else if (targetName) {
112100
113425
  const targetLower = targetName.toLowerCase();
@@ -112161,7 +113486,7 @@ var init_ProbeAgent = __esm({
112161
113486
  pushEntry(architectureMatch);
112162
113487
  const contexts = [];
112163
113488
  for (const entry of uniqueEntries) {
112164
- const filePath = (0, import_path17.resolve)(rootDirectory, entry.name);
113489
+ const filePath = (0, import_path18.resolve)(rootDirectory, entry.name);
112165
113490
  try {
112166
113491
  const content = await (0, import_promises6.readFile)(filePath, "utf8");
112167
113492
  let kind = "other";
@@ -112226,10 +113551,10 @@ ${this.architectureContext.content}
112226
113551
  }
112227
113552
  _getSkillsRepoRoot() {
112228
113553
  if (this.workspaceRoot) {
112229
- return (0, import_path17.resolve)(this.workspaceRoot);
113554
+ return (0, import_path18.resolve)(this.workspaceRoot);
112230
113555
  }
112231
113556
  if (this.allowedFolders && this.allowedFolders.length > 0) {
112232
- return (0, import_path17.resolve)(this.allowedFolders[0]);
113557
+ return (0, import_path18.resolve)(this.allowedFolders[0]);
112233
113558
  }
112234
113559
  return process.cwd();
112235
113560
  }
@@ -112418,10 +113743,6 @@ Workspace: ${this.allowedFolders.join(", ")}`;
112418
113743
  }
112419
113744
  if (isToolAllowed("readImage")) {
112420
113745
  toolDefinitions += `${readImageToolDefinition}
112421
- `;
112422
- }
112423
- if (this.allowEdit && isToolAllowed("implement")) {
112424
- toolDefinitions += `${implementToolDefinition}
112425
113746
  `;
112426
113747
  }
112427
113748
  if (this.allowEdit && isToolAllowed("edit")) {
@@ -112503,7 +113824,7 @@ The configuration is loaded from src/config.js lines 15-25 which contains the da
112503
113824
  availableToolsList += "- query: Search code using structural AST patterns.\n";
112504
113825
  }
112505
113826
  if (isToolAllowed("extract")) {
112506
- availableToolsList += "- extract: Extract specific code blocks or lines from files.\n";
113827
+ availableToolsList += '- extract: Extract specific code blocks or lines from files. Use with symbol targets (e.g. "file.js#funcName") to get line numbers for line-targeted editing.\n';
112507
113828
  }
112508
113829
  if (isToolAllowed("listFiles")) {
112509
113830
  availableToolsList += "- listFiles: List files and directories in a specified location.\n";
@@ -112520,11 +113841,8 @@ The configuration is loaded from src/config.js lines 15-25 which contains the da
112520
113841
  if (isToolAllowed("readImage")) {
112521
113842
  availableToolsList += "- readImage: Read and load an image file for AI analysis.\n";
112522
113843
  }
112523
- if (this.allowEdit && isToolAllowed("implement")) {
112524
- availableToolsList += "- implement: Implement a feature or fix a bug using aider.\n";
112525
- }
112526
113844
  if (this.allowEdit && isToolAllowed("edit")) {
112527
- availableToolsList += "- edit: Edit files using exact string replacement.\n";
113845
+ availableToolsList += "- edit: Edit files using text replacement, AST-aware symbol operations, or line-targeted editing.\n";
112528
113846
  }
112529
113847
  if (this.allowEdit && isToolAllowed("create")) {
112530
113848
  availableToolsList += "- create: Create new files with specified content.\n";
@@ -112612,8 +113930,14 @@ Follow these instructions carefully:
112612
113930
  8. Once the task is fully completed, use the '<attempt_completion>' tool to provide the final result. This is the ONLY way to signal completion.
112613
113931
  9. Prefer concise and focused search queries. Use specific keywords and phrases to narrow down results.${this.allowEdit ? `
112614
113932
  10. When modifying files, choose the appropriate tool:
112615
- - Use 'edit' for precise changes to existing files (requires exact string match)
112616
- - Use 'create' for new files or complete file rewrites` : ""}
113933
+ - Use 'edit' for all code modifications:
113934
+ * For small changes (a line or a few lines), use old_string + new_string \u2014 copy old_string verbatim from the file.
113935
+ * For rewriting entire functions/classes/methods, use the symbol parameter instead (no exact text matching needed).
113936
+ * 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.' : ""}
113937
+ * 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.
113938
+ - Use 'create' for new files or complete file rewrites.
113939
+ - If an edit fails, read the error message \u2014 it tells you exactly how to fix the call and retry.
113940
+ - 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.` : ""}
112617
113941
  </instructions>
112618
113942
  `;
112619
113943
  let systemMessage = "";
@@ -112839,8 +114163,8 @@ You are working with a workspace. Available paths: ${workspaceDesc}
112839
114163
  let currentIteration = 0;
112840
114164
  let completionAttempted = false;
112841
114165
  let finalResult = "I was unable to complete your request due to reaching the maximum number of tool iterations.";
112842
- const baseMaxIterations = this.maxIterations || MAX_TOOL_ITERATIONS;
112843
- const maxIterations = options.schema ? baseMaxIterations + 4 : baseMaxIterations;
114166
+ const baseMaxIterations = options._maxIterationsOverride || this.maxIterations || MAX_TOOL_ITERATIONS;
114167
+ const maxIterations = options._maxIterationsOverride ? baseMaxIterations : options.schema ? baseMaxIterations + 4 : baseMaxIterations;
112844
114168
  const isClaudeCode = this.clientApiProvider === "claude-code" || process.env.USE_CLAUDE_CODE === "true";
112845
114169
  const isCodex = this.clientApiProvider === "codex" || process.env.USE_CODEX === "true";
112846
114170
  if (isClaudeCode) {
@@ -113113,8 +114437,11 @@ You are working with a workspace. Available paths: ${workspaceDesc}
113113
114437
  if (this.enableSkills && this.allowedTools.isEnabled("useSkill")) validTools.push("useSkill");
113114
114438
  if (this.allowedTools.isEnabled("readImage")) validTools.push("readImage");
113115
114439
  validTools.push("attempt_completion");
113116
- if (this.allowEdit && this.allowedTools.isEnabled("implement")) {
113117
- validTools.push("implement", "edit", "create");
114440
+ if (this.allowEdit && this.allowedTools.isEnabled("edit")) {
114441
+ validTools.push("edit");
114442
+ }
114443
+ if (this.allowEdit && this.allowedTools.isEnabled("create")) {
114444
+ validTools.push("create");
113118
114445
  }
113119
114446
  if (this.enableBash && this.allowedTools.isEnabled("bash")) {
113120
114447
  validTools.push("bash");
@@ -113336,10 +114663,10 @@ ${errorXml}
113336
114663
  try {
113337
114664
  let resolvedWorkingDirectory = this.workspaceRoot || this.cwd || this.allowedFolders && this.allowedFolders[0] || process.cwd();
113338
114665
  if (params.workingDirectory) {
113339
- const requestedDir = safeRealpath((0, import_path17.isAbsolute)(params.workingDirectory) ? (0, import_path17.resolve)(params.workingDirectory) : (0, import_path17.resolve)(resolvedWorkingDirectory, params.workingDirectory));
114666
+ const requestedDir = safeRealpath((0, import_path18.isAbsolute)(params.workingDirectory) ? (0, import_path18.resolve)(params.workingDirectory) : (0, import_path18.resolve)(resolvedWorkingDirectory, params.workingDirectory));
113340
114667
  const isWithinAllowed = !this.allowedFolders || this.allowedFolders.length === 0 || this.allowedFolders.some((folder) => {
113341
114668
  const resolvedFolder = safeRealpath(folder);
113342
- return requestedDir === resolvedFolder || requestedDir.startsWith(resolvedFolder + import_path17.sep);
114669
+ return requestedDir === resolvedFolder || requestedDir.startsWith(resolvedFolder + import_path18.sep);
113343
114670
  });
113344
114671
  if (isWithinAllowed) {
113345
114672
  resolvedWorkingDirectory = requestedDir;
@@ -113407,6 +114734,8 @@ ${errorXml}
113407
114734
  // Inherit bash enablement
113408
114735
  bashConfig: this.bashConfig,
113409
114736
  // Inherit bash configuration
114737
+ allowEdit: this.allowEdit,
114738
+ // Inherit edit/create permission
113410
114739
  allowedTools: allowedToolsForDelegate,
113411
114740
  // Inherit allowed tools from parent
113412
114741
  debug: this.debug,
@@ -113479,7 +114808,7 @@ ${errorXml}
113479
114808
  currentMessages.push({ role: "assistant", content: assistantResponseContent });
113480
114809
  let toolResultContent = typeof toolResult === "string" ? toolResult : JSON.stringify(toolResult, null, 2);
113481
114810
  if (this.workspaceRoot && toolResultContent) {
113482
- const wsPrefix = this.workspaceRoot.endsWith(import_path17.sep) ? this.workspaceRoot : this.workspaceRoot + import_path17.sep;
114811
+ const wsPrefix = this.workspaceRoot.endsWith(import_path18.sep) ? this.workspaceRoot : this.workspaceRoot + import_path18.sep;
113483
114812
  toolResultContent = toolResultContent.split(wsPrefix).join("");
113484
114813
  }
113485
114814
  const { cleanedContent, extractedBlocks } = extractRawOutputBlocks(toolResultContent);
@@ -114072,13 +115401,16 @@ Convert your previous response content into actual JSON data that follows this s
114072
115401
  options.schema,
114073
115402
  0
114074
115403
  );
115404
+ const { schema: _unusedSchema1, ...schemaDefCorrectionOptions } = options;
114075
115405
  finalResult = await this.answer(schemaDefinitionPrompt, [], {
114076
- ...options,
115406
+ ...schemaDefCorrectionOptions,
114077
115407
  _schemaFormatted: true,
114078
115408
  _skipValidation: true,
114079
115409
  // Skip validation in recursive correction calls to prevent loops
114080
- _completionPromptProcessed: true
115410
+ _completionPromptProcessed: true,
114081
115411
  // Prevent cascading completion prompts in retry calls
115412
+ _maxIterationsOverride: 3
115413
+ // Correction should complete in 1-2 iterations (issue #447)
114082
115414
  });
114083
115415
  finalResult = cleanSchemaResponse(finalResult);
114084
115416
  validation = validateJsonResponse(finalResult);
@@ -114126,15 +115458,18 @@ Convert your previous response content into actual JSON data that follows this s
114126
115458
  retryCount
114127
115459
  );
114128
115460
  }
115461
+ const { schema: _unusedSchema2, ...correctionOptions } = options;
114129
115462
  finalResult = await this.answer(correctionPrompt, [], {
114130
- ...options,
115463
+ ...correctionOptions,
114131
115464
  _schemaFormatted: true,
114132
115465
  _skipValidation: true,
114133
115466
  // Skip validation in recursive correction calls to prevent loops
114134
115467
  _disableTools: true,
114135
115468
  // Only allow attempt_completion - prevent AI from using search/query tools
114136
- _completionPromptProcessed: true
115469
+ _completionPromptProcessed: true,
114137
115470
  // Prevent cascading completion prompts in retry calls
115471
+ _maxIterationsOverride: 3
115472
+ // Correction should complete in 1-2 iterations (issue #447)
114138
115473
  });
114139
115474
  finalResult = cleanSchemaResponse(finalResult);
114140
115475
  validation = validateJsonResponse(finalResult, { debug: this.debug });
@@ -114329,7 +115664,7 @@ Convert your previous response content into actual JSON data that follows this s
114329
115664
  */
114330
115665
  clone(options = {}) {
114331
115666
  const {
114332
- sessionId = (0, import_crypto9.randomUUID)(),
115667
+ sessionId = (0, import_crypto10.randomUUID)(),
114333
115668
  stripInternalMessages = true,
114334
115669
  keepSystemMessage = true,
114335
115670
  deepCopy = true,