@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
package/cjs/index.cjs CHANGED
@@ -720,7 +720,7 @@ async function waitForFileLock(lockPath, binaryPath) {
720
720
  }
721
721
  } catch {
722
722
  }
723
- await new Promise((resolve7) => setTimeout(resolve7, LOCK_POLL_INTERVAL_MS));
723
+ await new Promise((resolve8) => setTimeout(resolve8, LOCK_POLL_INTERVAL_MS));
724
724
  }
725
725
  if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
726
726
  console.log(`Timeout waiting for file lock`);
@@ -2075,7 +2075,7 @@ Cwd: ${cwd}`;
2075
2075
  }
2076
2076
  }
2077
2077
  function extractWithStdin(binaryPath, cliArgs, content, options, cwd) {
2078
- return new Promise((resolve7, reject2) => {
2078
+ return new Promise((resolve8, reject2) => {
2079
2079
  const childProcess = (0, import_child_process4.spawn)(binaryPath, ["extract", ...cliArgs], {
2080
2080
  stdio: ["pipe", "pipe", "pipe"],
2081
2081
  cwd
@@ -2098,7 +2098,7 @@ function extractWithStdin(binaryPath, cliArgs, content, options, cwd) {
2098
2098
  }
2099
2099
  try {
2100
2100
  const result = processExtractOutput(stdout, options);
2101
- resolve7(result);
2101
+ resolve8(result);
2102
2102
  } catch (error2) {
2103
2103
  reject2(error2);
2104
2104
  }
@@ -3701,6 +3701,7 @@ var require_ChecksumStream = __commonJS({
3701
3701
  checksum;
3702
3702
  source;
3703
3703
  base64Encoder;
3704
+ pendingCallback = null;
3704
3705
  constructor({ expectedChecksum, checksum, source, checksumSourceLocation, base64Encoder }) {
3705
3706
  super();
3706
3707
  if (typeof source.pipe === "function") {
@@ -3715,11 +3716,20 @@ var require_ChecksumStream = __commonJS({
3715
3716
  this.source.pipe(this);
3716
3717
  }
3717
3718
  _read(size) {
3719
+ if (this.pendingCallback) {
3720
+ const callback = this.pendingCallback;
3721
+ this.pendingCallback = null;
3722
+ callback();
3723
+ }
3718
3724
  }
3719
3725
  _write(chunk, encoding, callback) {
3720
3726
  try {
3721
3727
  this.checksum.update(chunk);
3722
- this.push(chunk);
3728
+ const canPushMore = this.push(chunk);
3729
+ if (!canPushMore) {
3730
+ this.pendingCallback = callback;
3731
+ return;
3732
+ }
3723
3733
  } catch (e5) {
3724
3734
  return callback(e5);
3725
3735
  }
@@ -4186,7 +4196,7 @@ var require_headStream = __commonJS({
4186
4196
  if ((0, stream_type_check_1.isReadableStream)(stream2)) {
4187
4197
  return (0, headStream_browser_1.headStream)(stream2, bytes);
4188
4198
  }
4189
- return new Promise((resolve7, reject2) => {
4199
+ return new Promise((resolve8, reject2) => {
4190
4200
  const collector = new Collector();
4191
4201
  collector.limit = bytes;
4192
4202
  stream2.pipe(collector);
@@ -4197,7 +4207,7 @@ var require_headStream = __commonJS({
4197
4207
  collector.on("error", reject2);
4198
4208
  collector.on("finish", function() {
4199
4209
  const bytes2 = new Uint8Array(Buffer.concat(this.buffers));
4200
- resolve7(bytes2);
4210
+ resolve8(bytes2);
4201
4211
  });
4202
4212
  });
4203
4213
  };
@@ -4385,21 +4395,21 @@ var require_dist_cjs15 = __commonJS({
4385
4395
  let sendBody = true;
4386
4396
  if (!externalAgent && expect === "100-continue") {
4387
4397
  sendBody = await Promise.race([
4388
- new Promise((resolve7) => {
4389
- timeoutId = Number(timing.setTimeout(() => resolve7(true), Math.max(MIN_WAIT_TIME, maxContinueTimeoutMs)));
4398
+ new Promise((resolve8) => {
4399
+ timeoutId = Number(timing.setTimeout(() => resolve8(true), Math.max(MIN_WAIT_TIME, maxContinueTimeoutMs)));
4390
4400
  }),
4391
- new Promise((resolve7) => {
4401
+ new Promise((resolve8) => {
4392
4402
  httpRequest.on("continue", () => {
4393
4403
  timing.clearTimeout(timeoutId);
4394
- resolve7(true);
4404
+ resolve8(true);
4395
4405
  });
4396
4406
  httpRequest.on("response", () => {
4397
4407
  timing.clearTimeout(timeoutId);
4398
- resolve7(false);
4408
+ resolve8(false);
4399
4409
  });
4400
4410
  httpRequest.on("error", () => {
4401
4411
  timing.clearTimeout(timeoutId);
4402
- resolve7(false);
4412
+ resolve8(false);
4403
4413
  });
4404
4414
  })
4405
4415
  ]);
@@ -4471,13 +4481,13 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
4471
4481
  return socketWarningTimestamp;
4472
4482
  }
4473
4483
  constructor(options) {
4474
- this.configProvider = new Promise((resolve7, reject2) => {
4484
+ this.configProvider = new Promise((resolve8, reject2) => {
4475
4485
  if (typeof options === "function") {
4476
4486
  options().then((_options) => {
4477
- resolve7(this.resolveDefaultConfig(_options));
4487
+ resolve8(this.resolveDefaultConfig(_options));
4478
4488
  }).catch(reject2);
4479
4489
  } else {
4480
- resolve7(this.resolveDefaultConfig(options));
4490
+ resolve8(this.resolveDefaultConfig(options));
4481
4491
  }
4482
4492
  });
4483
4493
  }
@@ -4520,7 +4530,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
4520
4530
  const config = this.config;
4521
4531
  let writeRequestBodyPromise = void 0;
4522
4532
  const timeouts = [];
4523
- const resolve7 = async (arg) => {
4533
+ const resolve8 = async (arg) => {
4524
4534
  await writeRequestBodyPromise;
4525
4535
  timeouts.forEach(timing.clearTimeout);
4526
4536
  _resolve(arg);
@@ -4586,7 +4596,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
4586
4596
  headers: getTransformedHeaders(res.headers),
4587
4597
  body: res
4588
4598
  });
4589
- resolve7({ response: httpResponse });
4599
+ resolve8({ response: httpResponse });
4590
4600
  });
4591
4601
  req.on("error", (err) => {
4592
4602
  if (NODEJS_TIMEOUT_ERROR_CODES.includes(err.code)) {
@@ -4766,13 +4776,13 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
4766
4776
  return new _NodeHttp2Handler(instanceOrOptions);
4767
4777
  }
4768
4778
  constructor(options) {
4769
- this.configProvider = new Promise((resolve7, reject2) => {
4779
+ this.configProvider = new Promise((resolve8, reject2) => {
4770
4780
  if (typeof options === "function") {
4771
4781
  options().then((opts) => {
4772
- resolve7(opts || {});
4782
+ resolve8(opts || {});
4773
4783
  }).catch(reject2);
4774
4784
  } else {
4775
- resolve7(options || {});
4785
+ resolve8(options || {});
4776
4786
  }
4777
4787
  });
4778
4788
  }
@@ -4792,7 +4802,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
4792
4802
  return new Promise((_resolve, _reject) => {
4793
4803
  let fulfilled = false;
4794
4804
  let writeRequestBodyPromise = void 0;
4795
- const resolve7 = async (arg) => {
4805
+ const resolve8 = async (arg) => {
4796
4806
  await writeRequestBodyPromise;
4797
4807
  _resolve(arg);
4798
4808
  };
@@ -4848,7 +4858,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
4848
4858
  body: req
4849
4859
  });
4850
4860
  fulfilled = true;
4851
- resolve7({ response: httpResponse });
4861
+ resolve8({ response: httpResponse });
4852
4862
  if (disableConcurrentStreams) {
4853
4863
  session.close();
4854
4864
  this.connectionManager.deleteSession(authority, session);
@@ -4925,7 +4935,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
4925
4935
  if (isReadableStreamInstance(stream3)) {
4926
4936
  return collectReadableStream(stream3);
4927
4937
  }
4928
- return new Promise((resolve7, reject2) => {
4938
+ return new Promise((resolve8, reject2) => {
4929
4939
  const collector = new Collector();
4930
4940
  stream3.pipe(collector);
4931
4941
  stream3.on("error", (err) => {
@@ -4935,7 +4945,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
4935
4945
  collector.on("error", reject2);
4936
4946
  collector.on("finish", function() {
4937
4947
  const bytes = new Uint8Array(Buffer.concat(this.bufferedBytes));
4938
- resolve7(bytes);
4948
+ resolve8(bytes);
4939
4949
  });
4940
4950
  });
4941
4951
  };
@@ -4979,7 +4989,7 @@ var require_dist_cjs16 = __commonJS({
4979
4989
  return new Request(url, requestOptions);
4980
4990
  }
4981
4991
  function requestTimeout(timeoutInMs = 0) {
4982
- return new Promise((resolve7, reject2) => {
4992
+ return new Promise((resolve8, reject2) => {
4983
4993
  if (timeoutInMs) {
4984
4994
  setTimeout(() => {
4985
4995
  const timeoutError = new Error(`Request did not complete within ${timeoutInMs} ms`);
@@ -5097,7 +5107,7 @@ var require_dist_cjs16 = __commonJS({
5097
5107
  requestTimeout(requestTimeoutInMs)
5098
5108
  ];
5099
5109
  if (abortSignal) {
5100
- raceOfPromises.push(new Promise((resolve7, reject2) => {
5110
+ raceOfPromises.push(new Promise((resolve8, reject2) => {
5101
5111
  const onAbort = () => {
5102
5112
  const abortError = new Error("Request aborted");
5103
5113
  abortError.name = "AbortError";
@@ -5161,7 +5171,7 @@ var require_dist_cjs16 = __commonJS({
5161
5171
  return collected;
5162
5172
  }
5163
5173
  function readToBase64(blob) {
5164
- return new Promise((resolve7, reject2) => {
5174
+ return new Promise((resolve8, reject2) => {
5165
5175
  const reader = new FileReader();
5166
5176
  reader.onloadend = () => {
5167
5177
  if (reader.readyState !== 2) {
@@ -5170,7 +5180,7 @@ var require_dist_cjs16 = __commonJS({
5170
5180
  const result = reader.result ?? "";
5171
5181
  const commaIndex = result.indexOf(",");
5172
5182
  const dataOffset = commaIndex > -1 ? commaIndex + 1 : result.length;
5173
- resolve7(result.substring(dataOffset));
5183
+ resolve8(result.substring(dataOffset));
5174
5184
  };
5175
5185
  reader.onabort = () => reject2(new Error("Read aborted"));
5176
5186
  reader.onerror = () => reject2(reader.error);
@@ -6838,11 +6848,11 @@ function __metadata(metadataKey, metadataValue) {
6838
6848
  }
6839
6849
  function __awaiter(thisArg, _arguments, P, generator) {
6840
6850
  function adopt(value) {
6841
- return value instanceof P ? value : new P(function(resolve7) {
6842
- resolve7(value);
6851
+ return value instanceof P ? value : new P(function(resolve8) {
6852
+ resolve8(value);
6843
6853
  });
6844
6854
  }
6845
- return new (P || (P = Promise))(function(resolve7, reject2) {
6855
+ return new (P || (P = Promise))(function(resolve8, reject2) {
6846
6856
  function fulfilled(value) {
6847
6857
  try {
6848
6858
  step(generator.next(value));
@@ -6858,7 +6868,7 @@ function __awaiter(thisArg, _arguments, P, generator) {
6858
6868
  }
6859
6869
  }
6860
6870
  function step(result) {
6861
- result.done ? resolve7(result.value) : adopt(result.value).then(fulfilled, rejected);
6871
+ result.done ? resolve8(result.value) : adopt(result.value).then(fulfilled, rejected);
6862
6872
  }
6863
6873
  step((generator = generator.apply(thisArg, _arguments || [])).next());
6864
6874
  });
@@ -7049,14 +7059,14 @@ function __asyncValues(o5) {
7049
7059
  }, i5);
7050
7060
  function verb(n5) {
7051
7061
  i5[n5] = o5[n5] && function(v5) {
7052
- return new Promise(function(resolve7, reject2) {
7053
- v5 = o5[n5](v5), settle(resolve7, reject2, v5.done, v5.value);
7062
+ return new Promise(function(resolve8, reject2) {
7063
+ v5 = o5[n5](v5), settle(resolve8, reject2, v5.done, v5.value);
7054
7064
  });
7055
7065
  };
7056
7066
  }
7057
- function settle(resolve7, reject2, d5, v5) {
7067
+ function settle(resolve8, reject2, d5, v5) {
7058
7068
  Promise.resolve(v5).then(function(v6) {
7059
- resolve7({ value: v6, done: d5 });
7069
+ resolve8({ value: v6, done: d5 });
7060
7070
  }, reject2);
7061
7071
  }
7062
7072
  }
@@ -17457,7 +17467,7 @@ var require_dist_cjs37 = __commonJS({
17457
17467
  this.sockets[url] = (this.sockets[url] ?? []).filter((socket) => ![WebSocket.CLOSING, WebSocket.CLOSED].includes(socket.readyState));
17458
17468
  }
17459
17469
  waitForReady(socket, connectionTimeout) {
17460
- return new Promise((resolve7, reject2) => {
17470
+ return new Promise((resolve8, reject2) => {
17461
17471
  const timeout = setTimeout(() => {
17462
17472
  this.removeNotUsableSockets(socket.url);
17463
17473
  reject2({
@@ -17469,7 +17479,7 @@ var require_dist_cjs37 = __commonJS({
17469
17479
  }, connectionTimeout);
17470
17480
  socket.onopen = () => {
17471
17481
  clearTimeout(timeout);
17472
- resolve7();
17482
+ resolve8();
17473
17483
  };
17474
17484
  });
17475
17485
  }
@@ -17522,8 +17532,8 @@ var require_dist_cjs37 = __commonJS({
17522
17532
  }
17523
17533
  return { done: item.done, value: item.value };
17524
17534
  }
17525
- return new Promise((resolve7, reject2) => {
17526
- pendingResolve = resolve7;
17535
+ return new Promise((resolve8, reject2) => {
17536
+ pendingResolve = resolve8;
17527
17537
  pendingReject = reject2;
17528
17538
  });
17529
17539
  }
@@ -18736,7 +18746,7 @@ var require_dist_cjs46 = __commonJS({
18736
18746
  this.refillTokenBucket();
18737
18747
  if (amount > this.currentCapacity) {
18738
18748
  const delay = (amount - this.currentCapacity) / this.fillRate * 1e3;
18739
- await new Promise((resolve7) => _DefaultRateLimiter.setTimeoutFn(resolve7, delay));
18749
+ await new Promise((resolve8) => _DefaultRateLimiter.setTimeoutFn(resolve8, delay));
18740
18750
  }
18741
18751
  this.currentCapacity = this.currentCapacity - amount;
18742
18752
  }
@@ -19071,7 +19081,7 @@ var require_dist_cjs47 = __commonJS({
19071
19081
  const delayFromResponse = getDelayFromRetryAfterHeader(err.$response);
19072
19082
  const delay = Math.max(delayFromResponse || 0, delayFromDecider);
19073
19083
  totalDelay += delay;
19074
- await new Promise((resolve7) => setTimeout(resolve7, delay));
19084
+ await new Promise((resolve8) => setTimeout(resolve8, delay));
19075
19085
  continue;
19076
19086
  }
19077
19087
  if (!err.$metadata) {
@@ -19229,7 +19239,7 @@ var require_dist_cjs47 = __commonJS({
19229
19239
  attempts = retryToken.getRetryCount();
19230
19240
  const delay = retryToken.getRetryDelay();
19231
19241
  totalRetryDelay += delay;
19232
- await new Promise((resolve7) => setTimeout(resolve7, delay));
19242
+ await new Promise((resolve8) => setTimeout(resolve8, delay));
19233
19243
  }
19234
19244
  }
19235
19245
  } else {
@@ -19381,7 +19391,7 @@ var require_package2 = __commonJS({
19381
19391
  module2.exports = {
19382
19392
  name: "@aws-sdk/client-bedrock-runtime",
19383
19393
  description: "AWS SDK for JavaScript Bedrock Runtime Client for Node.js, Browser and React Native",
19384
- version: "3.994.0",
19394
+ version: "3.995.0",
19385
19395
  scripts: {
19386
19396
  build: "concurrently 'yarn:build:types' 'yarn:build:es' && yarn build:cjs",
19387
19397
  "build:cjs": "node ../../scripts/compilation/inline client-bedrock-runtime",
@@ -19411,11 +19421,11 @@ var require_package2 = __commonJS({
19411
19421
  "@aws-sdk/middleware-user-agent": "^3.972.11",
19412
19422
  "@aws-sdk/middleware-websocket": "^3.972.6",
19413
19423
  "@aws-sdk/region-config-resolver": "^3.972.3",
19414
- "@aws-sdk/token-providers": "3.994.0",
19424
+ "@aws-sdk/token-providers": "3.995.0",
19415
19425
  "@aws-sdk/types": "^3.973.1",
19416
- "@aws-sdk/util-endpoints": "3.994.0",
19426
+ "@aws-sdk/util-endpoints": "3.995.0",
19417
19427
  "@aws-sdk/util-user-agent-browser": "^3.972.3",
19418
- "@aws-sdk/util-user-agent-node": "^3.972.9",
19428
+ "@aws-sdk/util-user-agent-node": "^3.972.10",
19419
19429
  "@smithy/config-resolver": "^4.4.6",
19420
19430
  "@smithy/core": "^3.23.2",
19421
19431
  "@smithy/eventstream-serde-browser": "^4.2.8",
@@ -19544,7 +19554,7 @@ var require_dist_cjs49 = __commonJS({
19544
19554
  var nodeConfigProvider = require_dist_cjs43();
19545
19555
  var urlParser = require_dist_cjs22();
19546
19556
  function httpRequest(options) {
19547
- return new Promise((resolve7, reject2) => {
19557
+ return new Promise((resolve8, reject2) => {
19548
19558
  const req = http.request({
19549
19559
  method: "GET",
19550
19560
  ...options,
@@ -19569,7 +19579,7 @@ var require_dist_cjs49 = __commonJS({
19569
19579
  chunks.push(chunk);
19570
19580
  });
19571
19581
  res.on("end", () => {
19572
- resolve7(buffer.Buffer.concat(chunks));
19582
+ resolve8(buffer.Buffer.concat(chunks));
19573
19583
  req.destroy();
19574
19584
  });
19575
19585
  });
@@ -19989,7 +19999,7 @@ var require_retry_wrapper = __commonJS({
19989
19999
  try {
19990
20000
  return await toRetry();
19991
20001
  } catch (e5) {
19992
- await new Promise((resolve7) => setTimeout(resolve7, delayMs));
20002
+ await new Promise((resolve8) => setTimeout(resolve8, delayMs));
19993
20003
  }
19994
20004
  }
19995
20005
  return await toRetry();
@@ -20297,6 +20307,15 @@ var require_dist_cjs51 = __commonJS({
20297
20307
  var os4 = require("os");
20298
20308
  var process2 = require("process");
20299
20309
  var middlewareUserAgent = require_dist_cjs29();
20310
+ var getRuntimeUserAgentPair = () => {
20311
+ const runtimesToCheck = ["deno", "bun", "llrt"];
20312
+ for (const runtime of runtimesToCheck) {
20313
+ if (process2.versions[runtime]) {
20314
+ return [`md/${runtime}`, process2.versions[runtime]];
20315
+ }
20316
+ }
20317
+ return ["md/nodejs", process2.versions.node];
20318
+ };
20300
20319
  var crtAvailability = {
20301
20320
  isCrtAvailable: false
20302
20321
  };
@@ -20307,13 +20326,14 @@ var require_dist_cjs51 = __commonJS({
20307
20326
  return null;
20308
20327
  };
20309
20328
  var createDefaultUserAgentProvider5 = ({ serviceId, clientVersion }) => {
20329
+ const runtimeUserAgentPair = getRuntimeUserAgentPair();
20310
20330
  return async (config) => {
20311
20331
  const sections = [
20312
20332
  ["aws-sdk-js", clientVersion],
20313
20333
  ["ua", "2.1"],
20314
20334
  [`os/${os4.platform()}`, os4.release()],
20315
20335
  ["lang/js"],
20316
- ["md/nodejs", `${process2.versions.node}`]
20336
+ runtimeUserAgentPair
20317
20337
  ];
20318
20338
  const crtAvailable = isCrtAvailable();
20319
20339
  if (crtAvailable) {
@@ -25876,8 +25896,8 @@ var require_dist_cjs66 = __commonJS({
25876
25896
  systemClockOffsetProvider: this.systemClockOffsetProvider
25877
25897
  });
25878
25898
  let resolvePipeline;
25879
- const pipelineError = new Promise((resolve7, reject2) => {
25880
- resolvePipeline = () => resolve7(void 0);
25899
+ const pipelineError = new Promise((resolve8, reject2) => {
25900
+ resolvePipeline = () => resolve8(void 0);
25881
25901
  node_stream.pipeline(payloadStream, signingStream, request.body, (err) => {
25882
25902
  if (err) {
25883
25903
  reject2(new Error(`Pipeline error in @aws-sdk/eventstream-handler-node: ${err.message}`, { cause: err }));
@@ -25983,7 +26003,7 @@ var init_package2 = __esm({
25983
26003
  "node_modules/@aws-sdk/token-providers/node_modules/@aws-sdk/nested-clients/package.json"() {
25984
26004
  package_default2 = {
25985
26005
  name: "@aws-sdk/nested-clients",
25986
- version: "3.994.0",
26006
+ version: "3.995.0",
25987
26007
  description: "Nested clients for AWS SDK packages.",
25988
26008
  main: "./dist-cjs/index.js",
25989
26009
  module: "./dist-es/index.js",
@@ -26019,9 +26039,9 @@ var init_package2 = __esm({
26019
26039
  "@aws-sdk/middleware-user-agent": "^3.972.11",
26020
26040
  "@aws-sdk/region-config-resolver": "^3.972.3",
26021
26041
  "@aws-sdk/types": "^3.973.1",
26022
- "@aws-sdk/util-endpoints": "3.994.0",
26042
+ "@aws-sdk/util-endpoints": "3.995.0",
26023
26043
  "@aws-sdk/util-user-agent-browser": "^3.972.3",
26024
- "@aws-sdk/util-user-agent-node": "^3.972.9",
26044
+ "@aws-sdk/util-user-agent-node": "^3.972.10",
26025
26045
  "@smithy/config-resolver": "^4.4.6",
26026
26046
  "@smithy/core": "^3.23.2",
26027
26047
  "@smithy/fetch-http-handler": "^5.3.9",
@@ -27431,7 +27451,7 @@ var require_dist_cjs69 = __commonJS({
27431
27451
  streamEnded = true;
27432
27452
  });
27433
27453
  while (!generationEnded) {
27434
- const value = await new Promise((resolve7) => setTimeout(() => resolve7(records.shift()), 0));
27454
+ const value = await new Promise((resolve8) => setTimeout(() => resolve8(records.shift()), 0));
27435
27455
  if (value) {
27436
27456
  yield value;
27437
27457
  }
@@ -37471,6 +37491,400 @@ var init_zod = __esm({
37471
37491
  }
37472
37492
  });
37473
37493
 
37494
+ // src/tools/fuzzyMatch.js
37495
+ function findFuzzyMatch(content, searchString) {
37496
+ if (!searchString || searchString.trim().length === 0) {
37497
+ return null;
37498
+ }
37499
+ const normalizedContent = content.replace(/\r\n/g, "\n");
37500
+ const normalizedSearch = searchString.replace(/\r\n/g, "\n");
37501
+ const contentLines = normalizedContent.split("\n");
37502
+ const searchLines = normalizedSearch.split("\n");
37503
+ const trimmed = lineTrimmedMatch(contentLines, searchLines);
37504
+ if (trimmed) return { ...trimmed, strategy: "line-trimmed" };
37505
+ const normalized = whitespaceNormalizedMatch(normalizedContent, normalizedSearch);
37506
+ if (normalized) return { ...normalized, strategy: "whitespace-normalized" };
37507
+ const indentFlex = indentFlexibleMatch(contentLines, searchLines);
37508
+ if (indentFlex) return { ...indentFlex, strategy: "indent-flexible" };
37509
+ return null;
37510
+ }
37511
+ function lineTrimmedMatch(contentLines, searchLines) {
37512
+ if (searchLines.length === 0) return null;
37513
+ const trimmedSearchLines = searchLines.map((line) => line.trim());
37514
+ if (trimmedSearchLines.every((line) => line === "")) return null;
37515
+ const windowSize = searchLines.length;
37516
+ const matches = [];
37517
+ for (let i5 = 0; i5 <= contentLines.length - windowSize; i5++) {
37518
+ let allMatch = true;
37519
+ for (let j5 = 0; j5 < windowSize; j5++) {
37520
+ if (contentLines[i5 + j5].trim() !== trimmedSearchLines[j5]) {
37521
+ allMatch = false;
37522
+ break;
37523
+ }
37524
+ }
37525
+ if (allMatch) {
37526
+ const matchedText = contentLines.slice(i5, i5 + windowSize).join("\n");
37527
+ matches.push(matchedText);
37528
+ }
37529
+ }
37530
+ if (matches.length === 0) return null;
37531
+ return {
37532
+ matchedText: matches[0],
37533
+ count: matches.length
37534
+ };
37535
+ }
37536
+ function whitespaceNormalizedMatch(content, search2) {
37537
+ if (!search2 || search2.trim().length === 0) return null;
37538
+ const { normalized: normContent, indexMap: contentMap } = buildNormalizedMap(content);
37539
+ const { normalized: normSearch } = buildNormalizedMap(search2);
37540
+ if (normSearch.length === 0) return null;
37541
+ const matches = [];
37542
+ let searchStart = 0;
37543
+ while (searchStart <= normContent.length - normSearch.length) {
37544
+ const idx = normContent.indexOf(normSearch, searchStart);
37545
+ if (idx === -1) break;
37546
+ const originalStart = contentMap[idx];
37547
+ const originalEnd = contentMap[idx + normSearch.length - 1];
37548
+ let actualEnd = originalEnd + 1;
37549
+ while (actualEnd < content.length && /[ \t]/.test(content[actualEnd]) && (actualEnd === originalEnd + 1 || /[ \t]/.test(content[actualEnd - 1]))) {
37550
+ if (contentMap.indexOf(actualEnd) > idx + normSearch.length - 1 || contentMap.indexOf(actualEnd) === -1) {
37551
+ break;
37552
+ }
37553
+ actualEnd++;
37554
+ }
37555
+ const matchedText = content.substring(originalStart, actualEnd);
37556
+ matches.push(matchedText);
37557
+ searchStart = idx + 1;
37558
+ }
37559
+ if (matches.length === 0) return null;
37560
+ return {
37561
+ matchedText: matches[0],
37562
+ count: matches.length
37563
+ };
37564
+ }
37565
+ function buildNormalizedMap(str) {
37566
+ const normalized = [];
37567
+ const indexMap = [];
37568
+ let i5 = 0;
37569
+ while (i5 < str.length) {
37570
+ const ch = str[i5];
37571
+ if (ch === " " || ch === " ") {
37572
+ normalized.push(" ");
37573
+ indexMap.push(i5);
37574
+ while (i5 < str.length && (str[i5] === " " || str[i5] === " ")) {
37575
+ i5++;
37576
+ }
37577
+ } else {
37578
+ normalized.push(ch);
37579
+ indexMap.push(i5);
37580
+ i5++;
37581
+ }
37582
+ }
37583
+ return {
37584
+ normalized: normalized.join(""),
37585
+ indexMap
37586
+ };
37587
+ }
37588
+ function indentFlexibleMatch(contentLines, searchLines) {
37589
+ if (searchLines.length === 0) return null;
37590
+ if (searchLines.every((line) => line.trim() === "")) return null;
37591
+ const searchMinIndent = getMinIndent(searchLines);
37592
+ const strippedSearch = searchLines.map((line) => stripIndent(line, searchMinIndent));
37593
+ const windowSize = searchLines.length;
37594
+ const matches = [];
37595
+ for (let i5 = 0; i5 <= contentLines.length - windowSize; i5++) {
37596
+ const windowLines = contentLines.slice(i5, i5 + windowSize);
37597
+ const windowMinIndent = getMinIndent(windowLines);
37598
+ const strippedWindow = windowLines.map((line) => stripIndent(line, windowMinIndent));
37599
+ let allMatch = true;
37600
+ for (let j5 = 0; j5 < windowSize; j5++) {
37601
+ if (strippedWindow[j5] !== strippedSearch[j5]) {
37602
+ allMatch = false;
37603
+ break;
37604
+ }
37605
+ }
37606
+ if (allMatch) {
37607
+ const matchedText = windowLines.join("\n");
37608
+ matches.push(matchedText);
37609
+ }
37610
+ }
37611
+ if (matches.length === 0) return null;
37612
+ return {
37613
+ matchedText: matches[0],
37614
+ count: matches.length
37615
+ };
37616
+ }
37617
+ function getMinIndent(lines) {
37618
+ let min = Infinity;
37619
+ for (const line of lines) {
37620
+ if (line.trim() === "") continue;
37621
+ const match2 = line.match(/^([ \t]*)/);
37622
+ if (match2) {
37623
+ min = Math.min(min, match2[1].length);
37624
+ }
37625
+ }
37626
+ return min === Infinity ? 0 : min;
37627
+ }
37628
+ function stripIndent(line, amount) {
37629
+ if (line.trim() === "") return "";
37630
+ if (amount <= 0) return line;
37631
+ return line.substring(Math.min(amount, line.length));
37632
+ }
37633
+ var init_fuzzyMatch = __esm({
37634
+ "src/tools/fuzzyMatch.js"() {
37635
+ "use strict";
37636
+ }
37637
+ });
37638
+
37639
+ // src/tools/symbolEdit.js
37640
+ async function findSymbol(filePath, symbolName, cwd) {
37641
+ try {
37642
+ const result = await extract({
37643
+ files: [`${filePath}#${symbolName}`],
37644
+ format: "json",
37645
+ json: true,
37646
+ cwd
37647
+ });
37648
+ if (!result || !result.results || result.results.length === 0) {
37649
+ return null;
37650
+ }
37651
+ const match2 = result.results[0];
37652
+ return {
37653
+ startLine: match2.lines[0],
37654
+ // 1-indexed
37655
+ endLine: match2.lines[1],
37656
+ // 1-indexed
37657
+ code: match2.code,
37658
+ nodeType: match2.node_type,
37659
+ file: match2.file
37660
+ };
37661
+ } catch (error2) {
37662
+ if (process.env.DEBUG === "1") {
37663
+ console.error(`[SymbolEdit] findSymbol error for "${symbolName}" in ${filePath}: ${error2.message}`);
37664
+ }
37665
+ return null;
37666
+ }
37667
+ }
37668
+ async function findAllSymbols(filePath, symbolName, cwd) {
37669
+ try {
37670
+ const result = await extract({
37671
+ files: [`${filePath}#${symbolName}`],
37672
+ format: "json",
37673
+ json: true,
37674
+ cwd
37675
+ });
37676
+ if (!result || !result.results || result.results.length === 0) {
37677
+ return [];
37678
+ }
37679
+ return result.results.map((match2) => ({
37680
+ startLine: match2.lines[0],
37681
+ endLine: match2.lines[1],
37682
+ code: match2.code,
37683
+ nodeType: match2.node_type,
37684
+ file: match2.file,
37685
+ qualifiedName: match2.symbol_signature || symbolName
37686
+ }));
37687
+ } catch (error2) {
37688
+ if (process.env.DEBUG === "1") {
37689
+ console.error(`[SymbolEdit] findAllSymbols error for "${symbolName}" in ${filePath}: ${error2.message}`);
37690
+ }
37691
+ return [];
37692
+ }
37693
+ }
37694
+ function detectBaseIndent(code) {
37695
+ const lines = code.split("\n");
37696
+ for (const line of lines) {
37697
+ if (line.trim().length > 0) {
37698
+ const match2 = line.match(/^(\s*)/);
37699
+ return match2 ? match2[1] : "";
37700
+ }
37701
+ }
37702
+ return "";
37703
+ }
37704
+ function reindent(newContent, targetIndent) {
37705
+ const lines = newContent.split("\n");
37706
+ const sourceIndent = detectBaseIndent(newContent);
37707
+ return lines.map((line) => {
37708
+ if (line.trim().length === 0) {
37709
+ return "";
37710
+ }
37711
+ if (line.startsWith(sourceIndent)) {
37712
+ return targetIndent + line.slice(sourceIndent.length);
37713
+ }
37714
+ return line;
37715
+ }).join("\n");
37716
+ }
37717
+ var init_symbolEdit = __esm({
37718
+ "src/tools/symbolEdit.js"() {
37719
+ "use strict";
37720
+ init_extract();
37721
+ }
37722
+ });
37723
+
37724
+ // src/tools/hashline.js
37725
+ function computeLineHash(line) {
37726
+ const stripped = (line || "").replace(/\s+/g, "");
37727
+ let h5 = 5381;
37728
+ for (let i5 = 0; i5 < stripped.length; i5++) {
37729
+ h5 = (h5 << 5) + h5 + stripped.charCodeAt(i5) & 4294967295;
37730
+ }
37731
+ return ((h5 >>> 0) % 256).toString(16).padStart(2, "0");
37732
+ }
37733
+ function parseLineRef(ref2) {
37734
+ if (ref2 === void 0 || ref2 === null) return null;
37735
+ const str = String(ref2).trim();
37736
+ if (!str) return null;
37737
+ const hashMatch = str.match(/^(\d+):([0-9a-fA-F]{2})$/);
37738
+ if (hashMatch) {
37739
+ const line = parseInt(hashMatch[1], 10);
37740
+ if (line < 1 || !isFinite(line)) return null;
37741
+ return { line, hash: hashMatch[2].toLowerCase() };
37742
+ }
37743
+ const lineMatch = str.match(/^(\d+)$/);
37744
+ if (lineMatch) {
37745
+ const line = parseInt(lineMatch[1], 10);
37746
+ if (line < 1 || !isFinite(line)) return null;
37747
+ return { line, hash: null };
37748
+ }
37749
+ return null;
37750
+ }
37751
+ function validateLineHash(lineNum, hash, fileLines) {
37752
+ const idx = lineNum - 1;
37753
+ if (idx < 0 || idx >= fileLines.length) {
37754
+ return { valid: false, actualHash: "", actualContent: "" };
37755
+ }
37756
+ const actualContent = fileLines[idx];
37757
+ const actualHash = computeLineHash(actualContent);
37758
+ return {
37759
+ valid: actualHash === hash.toLowerCase(),
37760
+ actualHash,
37761
+ actualContent
37762
+ };
37763
+ }
37764
+ function annotateOutputWithHashes(output) {
37765
+ if (!output || typeof output !== "string") return output;
37766
+ return output.split("\n").map((line) => {
37767
+ const cleanLine = line.endsWith("\r") ? line.slice(0, -1) : line;
37768
+ const match2 = cleanLine.match(/^(\s*)(\d+)(\s*\|)(.*)$/);
37769
+ if (!match2) return line;
37770
+ const [, prefix, lineNum, pipeSection, content] = match2;
37771
+ const hash = computeLineHash(content);
37772
+ const cr = line.endsWith("\r") ? "\r" : "";
37773
+ return `${prefix}${lineNum}:${hash}${pipeSection}${content}${cr}`;
37774
+ }).join("\n");
37775
+ }
37776
+ function stripHashlinePrefixes(text) {
37777
+ if (!text || typeof text !== "string") return { cleaned: text || "", stripped: false };
37778
+ const lines = text.split("\n");
37779
+ if (lines.length === 0) return { cleaned: "", stripped: false };
37780
+ const nonEmptyLines = lines.filter((l5) => l5.trim().length > 0);
37781
+ if (nonEmptyLines.length === 0) return { cleaned: text, stripped: false };
37782
+ const prefixPattern = /^\s*\d+(?::[0-9a-fA-F]{2})?\s*\|\s?/;
37783
+ const matchCount = nonEmptyLines.filter((l5) => prefixPattern.test(l5)).length;
37784
+ if (matchCount / nonEmptyLines.length <= 0.5) {
37785
+ return { cleaned: text, stripped: false };
37786
+ }
37787
+ const cleaned = lines.map((line) => {
37788
+ if (line.trim().length === 0) return line;
37789
+ return line.replace(prefixPattern, "");
37790
+ }).join("\n");
37791
+ return { cleaned, stripped: true };
37792
+ }
37793
+ var init_hashline = __esm({
37794
+ "src/tools/hashline.js"() {
37795
+ "use strict";
37796
+ }
37797
+ });
37798
+
37799
+ // src/tools/lineEditHeuristics.js
37800
+ function stripEchoedBoundaries(newStr, fileLines, startLine, endLine, position) {
37801
+ const modifications = [];
37802
+ let lines = newStr.split("\n");
37803
+ if (lines.length === 0) return { result: newStr, modifications };
37804
+ if (position === "after") {
37805
+ const anchorIdx = startLine - 1;
37806
+ if (anchorIdx >= 0 && anchorIdx < fileLines.length) {
37807
+ const anchorTrimmed = fileLines[anchorIdx].trim();
37808
+ if (anchorTrimmed.length > 0 && lines.length > 0 && lines[0].trim() === anchorTrimmed) {
37809
+ lines = lines.slice(1);
37810
+ modifications.push("stripped echoed anchor line (insert-after)");
37811
+ }
37812
+ }
37813
+ } else if (position === "before") {
37814
+ const anchorIdx = startLine - 1;
37815
+ if (anchorIdx >= 0 && anchorIdx < fileLines.length) {
37816
+ const anchorTrimmed = fileLines[anchorIdx].trim();
37817
+ if (anchorTrimmed.length > 0 && lines.length > 0 && lines[lines.length - 1].trim() === anchorTrimmed) {
37818
+ lines = lines.slice(0, -1);
37819
+ modifications.push("stripped echoed anchor line (insert-before)");
37820
+ }
37821
+ }
37822
+ } else {
37823
+ const beforeIdx = startLine - 2;
37824
+ if (beforeIdx >= 0 && beforeIdx < fileLines.length) {
37825
+ const beforeTrimmed = fileLines[beforeIdx].trim();
37826
+ if (beforeTrimmed.length > 0 && lines.length > 0 && lines[0].trim() === beforeTrimmed) {
37827
+ lines = lines.slice(1);
37828
+ modifications.push("stripped echoed line before range");
37829
+ }
37830
+ }
37831
+ const afterIdx = endLine;
37832
+ if (afterIdx >= 0 && afterIdx < fileLines.length) {
37833
+ const afterTrimmed = fileLines[afterIdx].trim();
37834
+ if (afterTrimmed.length > 0 && lines.length > 0 && lines[lines.length - 1].trim() === afterTrimmed) {
37835
+ lines = lines.slice(0, -1);
37836
+ modifications.push("stripped echoed line after range");
37837
+ }
37838
+ }
37839
+ }
37840
+ return { result: lines.join("\n"), modifications };
37841
+ }
37842
+ function restoreIndentation(newStr, originalLines) {
37843
+ const modifications = [];
37844
+ if (!newStr || !originalLines || originalLines.length === 0) {
37845
+ return { result: newStr || "", modifications };
37846
+ }
37847
+ const originalCode = originalLines.join("\n");
37848
+ const targetIndent = detectBaseIndent(originalCode);
37849
+ const newIndent = detectBaseIndent(newStr);
37850
+ if (targetIndent !== newIndent) {
37851
+ const reindented = reindent(newStr, targetIndent);
37852
+ if (reindented !== newStr) {
37853
+ modifications.push(`reindented from "${newIndent}" to "${targetIndent}"`);
37854
+ return { result: reindented, modifications };
37855
+ }
37856
+ }
37857
+ return { result: newStr, modifications };
37858
+ }
37859
+ function cleanNewString(newStr, fileLines, startLine, endLine, position) {
37860
+ const modifications = [];
37861
+ if (!newStr && newStr !== "") return { cleaned: "", modifications };
37862
+ const { cleaned: afterPrefixes, stripped } = stripHashlinePrefixes(newStr);
37863
+ if (stripped) modifications.push("stripped line-number prefixes");
37864
+ const { result: afterEchoes, modifications: echoMods } = stripEchoedBoundaries(
37865
+ afterPrefixes,
37866
+ fileLines,
37867
+ startLine,
37868
+ endLine,
37869
+ position
37870
+ );
37871
+ modifications.push(...echoMods);
37872
+ if (!position) {
37873
+ const originalLines = fileLines.slice(startLine - 1, endLine);
37874
+ const { result: afterIndent, modifications: indentMods } = restoreIndentation(afterEchoes, originalLines);
37875
+ modifications.push(...indentMods);
37876
+ return { cleaned: afterIndent, modifications };
37877
+ }
37878
+ return { cleaned: afterEchoes, modifications };
37879
+ }
37880
+ var init_lineEditHeuristics = __esm({
37881
+ "src/tools/lineEditHeuristics.js"() {
37882
+ "use strict";
37883
+ init_symbolEdit();
37884
+ init_hashline();
37885
+ }
37886
+ });
37887
+
37474
37888
  // src/tools/edit.js
37475
37889
  function isPathAllowed(filePath, allowedFolders) {
37476
37890
  if (!allowedFolders || allowedFolders.length === 0) {
@@ -37494,6 +37908,174 @@ function parseFileToolOptions(options = {}) {
37494
37908
  workspaceRoot: options.workspaceRoot || options.cwd || allowedFolders.length > 0 && allowedFolders[0] || process.cwd()
37495
37909
  };
37496
37910
  }
37911
+ async function handleSymbolEdit({ resolvedPath: resolvedPath2, file_path, symbol: symbol15, new_string, position, debug, cwd, fileTracker }) {
37912
+ if (typeof symbol15 !== "string" || symbol15.trim() === "") {
37913
+ 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.';
37914
+ }
37915
+ if (position !== void 0 && position !== null && position !== "before" && position !== "after") {
37916
+ 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.';
37917
+ }
37918
+ const allMatches = await findAllSymbols(resolvedPath2, symbol15, cwd || process.cwd());
37919
+ if (allMatches.length === 0) {
37920
+ 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.`;
37921
+ }
37922
+ if (allMatches.length > 1) {
37923
+ const suggestions = allMatches.map(
37924
+ (m5) => ` - ${m5.qualifiedName} (${m5.nodeType}, line ${m5.startLine})`
37925
+ ).join("\n");
37926
+ return `Error editing ${file_path}: Found ${allMatches.length} symbols named "${symbol15}". Use a qualified name to specify which one:
37927
+ ${suggestions}
37928
+
37929
+ Example: <edit><file_path>${file_path}</file_path><symbol>${allMatches[0].qualifiedName}</symbol><new_string>...</new_string></edit>`;
37930
+ }
37931
+ const symbolInfo = allMatches[0];
37932
+ if (fileTracker) {
37933
+ const check = fileTracker.checkSymbolContent(resolvedPath2, symbol15, symbolInfo.code);
37934
+ if (!check.ok && check.reason === "stale") {
37935
+ return `Error editing ${file_path}: Symbol "${symbol15}" has changed since you last read it. Use extract to re-read the current content, then retry.
37936
+
37937
+ Example: <extract><targets>${file_path}#${symbol15}</targets></extract>`;
37938
+ }
37939
+ }
37940
+ const content = await import_fs4.promises.readFile(resolvedPath2, "utf-8");
37941
+ const lines = content.split("\n");
37942
+ if (position) {
37943
+ const refIndent = detectBaseIndent(symbolInfo.code);
37944
+ const reindented = reindent(new_string, refIndent);
37945
+ const newLines = reindented.split("\n");
37946
+ if (position === "after") {
37947
+ lines.splice(symbolInfo.endLine, 0, "", ...newLines);
37948
+ } else {
37949
+ lines.splice(symbolInfo.startLine - 1, 0, ...newLines, "");
37950
+ }
37951
+ await import_fs4.promises.writeFile(resolvedPath2, lines.join("\n"), "utf-8");
37952
+ if (fileTracker) {
37953
+ const updated = await findSymbol(resolvedPath2, symbol15, cwd || process.cwd());
37954
+ if (updated) {
37955
+ fileTracker.trackSymbolAfterWrite(resolvedPath2, symbol15, updated.code, updated.startLine, updated.endLine);
37956
+ }
37957
+ fileTracker.markFileSeen(resolvedPath2);
37958
+ }
37959
+ const insertLine = position === "after" ? symbolInfo.endLine + 1 : symbolInfo.startLine;
37960
+ if (debug) {
37961
+ console.error(`[Edit] Successfully inserted ${newLines.length} lines ${position} "${symbol15}" at line ${insertLine} in ${resolvedPath2}`);
37962
+ }
37963
+ return `Successfully inserted ${newLines.length} lines ${position} symbol "${symbol15}" in ${file_path} (at line ${insertLine})`;
37964
+ } else {
37965
+ const originalIndent = detectBaseIndent(symbolInfo.code);
37966
+ const reindented = reindent(new_string, originalIndent);
37967
+ const newLines = reindented.split("\n");
37968
+ lines.splice(symbolInfo.startLine - 1, symbolInfo.endLine - symbolInfo.startLine + 1, ...newLines);
37969
+ await import_fs4.promises.writeFile(resolvedPath2, lines.join("\n"), "utf-8");
37970
+ if (fileTracker) {
37971
+ const updated = await findSymbol(resolvedPath2, symbol15, cwd || process.cwd());
37972
+ if (updated) {
37973
+ fileTracker.trackSymbolAfterWrite(resolvedPath2, symbol15, updated.code, updated.startLine, updated.endLine);
37974
+ }
37975
+ fileTracker.markFileSeen(resolvedPath2);
37976
+ }
37977
+ if (debug) {
37978
+ console.error(`[Edit] Successfully replaced symbol "${symbol15}" in ${resolvedPath2} (lines ${symbolInfo.startLine}-${symbolInfo.endLine})`);
37979
+ }
37980
+ return `Successfully replaced symbol "${symbol15}" in ${file_path} (was lines ${symbolInfo.startLine}-${symbolInfo.endLine}, now ${newLines.length} lines)`;
37981
+ }
37982
+ }
37983
+ function buildLineEditResponse(file_path, startLine, endLine, newLineCount, updatedLines, insertOffset, action, heuristicMods) {
37984
+ const contextBefore = 1;
37985
+ const contextAfter = 1;
37986
+ const contextStart = Math.max(0, insertOffset - contextBefore);
37987
+ const contextEnd = Math.min(updatedLines.length, insertOffset + newLineCount + contextAfter);
37988
+ let context = "Context:\n";
37989
+ for (let i5 = contextStart; i5 < contextEnd; i5++) {
37990
+ const lineNum = i5 + 1;
37991
+ const hash = computeLineHash(updatedLines[i5]);
37992
+ const isNew = i5 >= insertOffset && i5 < insertOffset + newLineCount;
37993
+ const marker15 = isNew ? ">" : " ";
37994
+ context += `${marker15} ${lineNum}:${hash} | ${updatedLines[i5]}
37995
+ `;
37996
+ }
37997
+ let msg = `Successfully edited ${file_path} (${action})`;
37998
+ if (heuristicMods.length > 0) {
37999
+ msg += ` [auto-corrected: ${heuristicMods.join(", ")}]`;
38000
+ }
38001
+ msg += "\n" + context;
38002
+ return msg;
38003
+ }
38004
+ async function handleLineEdit({ resolvedPath: resolvedPath2, file_path, start_line, end_line, new_string, position, debug, fileTracker }) {
38005
+ const startRef = parseLineRef(start_line);
38006
+ if (!startRef) {
38007
+ 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.`;
38008
+ }
38009
+ let endRef = null;
38010
+ if (end_line !== void 0 && end_line !== null) {
38011
+ endRef = parseLineRef(end_line);
38012
+ if (!endRef) {
38013
+ 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.`;
38014
+ }
38015
+ }
38016
+ const startLine = startRef.line;
38017
+ const endLine = endRef ? endRef.line : startLine;
38018
+ if (endLine < startLine) {
38019
+ return `Error editing file: end_line (${endLine}) must be >= start_line (${startLine}).`;
38020
+ }
38021
+ if (position !== void 0 && position !== null && position !== "before" && position !== "after") {
38022
+ 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.';
38023
+ }
38024
+ const content = await import_fs4.promises.readFile(resolvedPath2, "utf-8");
38025
+ const fileLines = content.split("\n");
38026
+ if (startLine > fileLines.length) {
38027
+ return `Error editing file: Line ${startLine} is beyond file length (${fileLines.length} lines). Use 'extract' to read the current file content.`;
38028
+ }
38029
+ if (endLine > fileLines.length) {
38030
+ return `Error editing file: Line ${endLine} is beyond file length (${fileLines.length} lines). Use 'extract' to read the current file content.`;
38031
+ }
38032
+ if (startRef.hash) {
38033
+ const validation = validateLineHash(startLine, startRef.hash, fileLines);
38034
+ if (!validation.valid) {
38035
+ 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.`;
38036
+ }
38037
+ }
38038
+ if (endRef && endRef.hash) {
38039
+ const validation = validateLineHash(endLine, endRef.hash, fileLines);
38040
+ if (!validation.valid) {
38041
+ 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.`;
38042
+ }
38043
+ }
38044
+ const { cleaned, modifications } = cleanNewString(new_string, fileLines, startLine, endLine, position);
38045
+ if (debug) {
38046
+ if (modifications.length > 0) {
38047
+ console.error(`[Edit] Heuristic corrections: ${modifications.join(", ")}`);
38048
+ }
38049
+ }
38050
+ const newLines = cleaned === "" ? [] : cleaned.split("\n");
38051
+ if (position === "after") {
38052
+ fileLines.splice(startLine, 0, ...newLines);
38053
+ await import_fs4.promises.writeFile(resolvedPath2, fileLines.join("\n"), "utf-8");
38054
+ if (fileTracker) await fileTracker.trackFileAfterWrite(resolvedPath2);
38055
+ const action = `${newLines.length} line${newLines.length !== 1 ? "s" : ""} inserted after line ${startLine}`;
38056
+ return buildLineEditResponse(file_path, startLine, startLine, newLines.length, fileLines, startLine, action, modifications);
38057
+ } else if (position === "before") {
38058
+ fileLines.splice(startLine - 1, 0, ...newLines);
38059
+ await import_fs4.promises.writeFile(resolvedPath2, fileLines.join("\n"), "utf-8");
38060
+ if (fileTracker) await fileTracker.trackFileAfterWrite(resolvedPath2);
38061
+ const action = `${newLines.length} line${newLines.length !== 1 ? "s" : ""} inserted before line ${startLine}`;
38062
+ return buildLineEditResponse(file_path, startLine, startLine, newLines.length, fileLines, startLine - 1, action, modifications);
38063
+ } else {
38064
+ const replacedCount = endLine - startLine + 1;
38065
+ fileLines.splice(startLine - 1, replacedCount, ...newLines);
38066
+ await import_fs4.promises.writeFile(resolvedPath2, fileLines.join("\n"), "utf-8");
38067
+ if (fileTracker) await fileTracker.trackFileAfterWrite(resolvedPath2);
38068
+ let action;
38069
+ if (newLines.length === 0) {
38070
+ action = `${replacedCount} line${replacedCount !== 1 ? "s" : ""} deleted (lines ${startLine}-${endLine})`;
38071
+ } else if (startLine === endLine) {
38072
+ action = `line ${startLine} replaced with ${newLines.length} line${newLines.length !== 1 ? "s" : ""}`;
38073
+ } else {
38074
+ action = `lines ${startLine}-${endLine} replaced with ${newLines.length} line${newLines.length !== 1 ? "s" : ""}`;
38075
+ }
38076
+ return buildLineEditResponse(file_path, startLine, endLine, newLines.length, fileLines, startLine - 1, action, modifications);
38077
+ }
38078
+ }
37497
38079
  var import_ai, import_fs4, import_path5, import_fs5, editTool, createTool, editSchema, createSchema, editDescription, createDescription, editToolDefinition, createToolDefinition;
37498
38080
  var init_edit = __esm({
37499
38081
  "src/tools/edit.js"() {
@@ -37503,24 +38085,31 @@ var init_edit = __esm({
37503
38085
  import_path5 = require("path");
37504
38086
  import_fs5 = require("fs");
37505
38087
  init_path_validation();
38088
+ init_fuzzyMatch();
38089
+ init_symbolEdit();
38090
+ init_hashline();
38091
+ init_lineEditHeuristics();
37506
38092
  editTool = (options = {}) => {
37507
38093
  const { debug, allowedFolders, cwd, workspaceRoot } = parseFileToolOptions(options);
37508
38094
  return (0, import_ai.tool)({
37509
38095
  name: "edit",
37510
- description: `Edit files using exact string replacement (Claude Code style).
38096
+ description: `Edit files using text replacement, AST-aware symbol operations, or line-targeted editing.
37511
38097
 
37512
- 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.
38098
+ Modes:
38099
+ 1. Text edit: Provide old_string + new_string to find and replace text (with fuzzy matching fallback)
38100
+ 2. Symbol replace: Provide symbol + new_string to replace an entire function/class/method by name
38101
+ 3. Symbol insert: Provide symbol + new_string + position to insert code before/after a symbol
38102
+ 4. Line-targeted edit: Provide start_line + new_string to edit by line number (from extract/search output)
37513
38103
 
37514
38104
  Parameters:
37515
38105
  - file_path: Path to the file to edit (absolute or relative)
37516
- - old_string: Exact text to find and replace (must be unique in the file unless replace_all is true)
37517
- - new_string: Text to replace with
37518
- - replace_all: (optional) Replace all occurrences instead of requiring uniqueness
37519
-
37520
- Important:
37521
- - The old_string must match EXACTLY including whitespace
37522
- - If old_string appears multiple times and replace_all is false, the edit will fail
37523
- - Use larger context around the string to ensure uniqueness when needed`,
38106
+ - new_string: Replacement text or new code content
38107
+ - old_string: (optional) Text to find and replace. If omitted, symbol or start_line must be provided.
38108
+ - replace_all: (optional) Replace all occurrences (text mode only)
38109
+ - symbol: (optional) Symbol name for AST-aware editing (e.g. "myFunction", "MyClass.myMethod")
38110
+ - position: (optional) "before" or "after" \u2014 insert code near a symbol or line instead of replacing it
38111
+ - start_line: (optional) Line reference (e.g. "42" or "42:ab") for line-targeted editing
38112
+ - end_line: (optional) End of line range, inclusive (e.g. "55" or "55:cd")`,
37524
38113
  inputSchema: {
37525
38114
  type: "object",
37526
38115
  properties: {
@@ -37530,30 +38119,44 @@ Important:
37530
38119
  },
37531
38120
  old_string: {
37532
38121
  type: "string",
37533
- description: "Exact text to find and replace"
38122
+ description: "Text to find and replace (for text-based editing)"
37534
38123
  },
37535
38124
  new_string: {
37536
38125
  type: "string",
37537
- description: "Text to replace with"
38126
+ description: "Replacement text or new code content"
37538
38127
  },
37539
38128
  replace_all: {
37540
38129
  type: "boolean",
37541
- description: "Replace all occurrences (default: false)",
38130
+ description: "Replace all occurrences (default: false, text mode only)",
37542
38131
  default: false
38132
+ },
38133
+ symbol: {
38134
+ type: "string",
38135
+ description: 'Symbol name for AST-aware editing (e.g. "myFunction", "MyClass.myMethod")'
38136
+ },
38137
+ position: {
38138
+ type: "string",
38139
+ enum: ["before", "after"],
38140
+ description: "Insert before/after symbol or line (requires symbol or start_line, omit to replace)"
38141
+ },
38142
+ start_line: {
38143
+ type: "string",
38144
+ description: 'Line reference for line-targeted editing (e.g. "42" or "42:ab" with hash)'
38145
+ },
38146
+ end_line: {
38147
+ type: "string",
38148
+ description: 'End of line range, inclusive (e.g. "55" or "55:cd"). Defaults to start_line.'
37543
38149
  }
37544
38150
  },
37545
- required: ["file_path", "old_string", "new_string"]
38151
+ required: ["file_path", "new_string"]
37546
38152
  },
37547
- execute: async ({ file_path, old_string, new_string, replace_all = false }) => {
38153
+ execute: async ({ file_path, old_string, new_string, replace_all = false, symbol: symbol15, position, start_line, end_line }) => {
37548
38154
  try {
37549
38155
  if (!file_path || typeof file_path !== "string" || file_path.trim() === "") {
37550
- return `Error editing file: Invalid file_path - must be a non-empty string`;
37551
- }
37552
- if (old_string === void 0 || old_string === null || typeof old_string !== "string") {
37553
- return `Error editing file: Invalid old_string - must be a string`;
38156
+ 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").`;
37554
38157
  }
37555
38158
  if (new_string === void 0 || new_string === null || typeof new_string !== "string") {
37556
- return `Error editing file: Invalid new_string - must be a string`;
38159
+ 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).`;
37557
38160
  }
37558
38161
  const resolvedPath2 = (0, import_path5.isAbsolute)(file_path) ? file_path : (0, import_path5.resolve)(cwd || process.cwd(), file_path);
37559
38162
  if (debug) {
@@ -37561,34 +38164,64 @@ Important:
37561
38164
  }
37562
38165
  if (!isPathAllowed(resolvedPath2, allowedFolders)) {
37563
38166
  const relativePath = toRelativePath(resolvedPath2, workspaceRoot);
37564
- return `Error editing file: Permission denied - ${relativePath} is outside allowed directories`;
38167
+ return `Error editing file: Permission denied - ${relativePath} is outside allowed directories. Use a file path within the project workspace.`;
37565
38168
  }
37566
38169
  if (!(0, import_fs5.existsSync)(resolvedPath2)) {
37567
- return `Error editing file: File not found - ${file_path}`;
38170
+ 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.`;
38171
+ }
38172
+ if (options.fileTracker && !options.fileTracker.isFileSeen(resolvedPath2)) {
38173
+ const displayPath = toRelativePath(resolvedPath2, workspaceRoot);
38174
+ 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.
38175
+
38176
+ Example: <extract><targets>${displayPath}</targets></extract>`;
38177
+ }
38178
+ if (symbol15 !== void 0 && symbol15 !== null) {
38179
+ return await handleSymbolEdit({ resolvedPath: resolvedPath2, file_path, symbol: symbol15, new_string, position, debug, cwd, fileTracker: options.fileTracker });
38180
+ }
38181
+ if (start_line !== void 0 && start_line !== null) {
38182
+ return await handleLineEdit({ resolvedPath: resolvedPath2, file_path, start_line, end_line, new_string, position, debug, fileTracker: options.fileTracker });
38183
+ }
38184
+ if (old_string === void 0 || old_string === null) {
38185
+ 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").';
38186
+ }
38187
+ if (typeof old_string !== "string") {
38188
+ 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.`;
37568
38189
  }
37569
38190
  const content = await import_fs4.promises.readFile(resolvedPath2, "utf-8");
38191
+ let matchTarget = old_string;
38192
+ let matchStrategy = "exact";
37570
38193
  if (!content.includes(old_string)) {
37571
- return `Error editing file: String not found - the specified old_string was not found in ${file_path}`;
38194
+ const fuzzy = findFuzzyMatch(content, old_string);
38195
+ if (!fuzzy) {
38196
+ 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.`;
38197
+ }
38198
+ matchTarget = fuzzy.matchedText;
38199
+ matchStrategy = fuzzy.strategy;
38200
+ if (debug) {
38201
+ console.error(`[Edit] Exact match failed, used ${matchStrategy} matching`);
38202
+ }
37572
38203
  }
37573
- const occurrences = content.split(old_string).length - 1;
38204
+ const occurrences = content.split(matchTarget).length - 1;
37574
38205
  if (!replace_all && occurrences > 1) {
37575
- 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.`;
38206
+ 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).`;
37576
38207
  }
37577
38208
  let newContent;
37578
38209
  if (replace_all) {
37579
- newContent = content.replaceAll(old_string, new_string);
38210
+ newContent = content.replaceAll(matchTarget, new_string);
37580
38211
  } else {
37581
- newContent = content.replace(old_string, new_string);
38212
+ newContent = content.replace(matchTarget, new_string);
37582
38213
  }
37583
38214
  if (newContent === content) {
37584
- return `Error editing file: No changes made - old_string and new_string might be the same`;
38215
+ 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.`;
37585
38216
  }
37586
38217
  await import_fs4.promises.writeFile(resolvedPath2, newContent, "utf-8");
38218
+ if (options.fileTracker) await options.fileTracker.trackFileAfterWrite(resolvedPath2);
37587
38219
  const replacedCount = replace_all ? occurrences : 1;
37588
38220
  if (debug) {
37589
38221
  console.error(`[Edit] Successfully edited ${resolvedPath2}, replaced ${replacedCount} occurrence(s)`);
37590
38222
  }
37591
- return `Successfully edited ${file_path} (${replacedCount} replacement${replacedCount !== 1 ? "s" : ""})`;
38223
+ const strategyNote = matchStrategy !== "exact" ? `, matched via ${matchStrategy}` : "";
38224
+ return `Successfully edited ${file_path} (${replacedCount} replacement${replacedCount !== 1 ? "s" : ""}${strategyNote})`;
37592
38225
  } catch (error2) {
37593
38226
  console.error("[Edit] Error:", error2);
37594
38227
  return `Error editing file: ${error2.message}`;
@@ -37635,10 +38268,10 @@ Important:
37635
38268
  execute: async ({ file_path, content, overwrite = false }) => {
37636
38269
  try {
37637
38270
  if (!file_path || typeof file_path !== "string" || file_path.trim() === "") {
37638
- return `Error creating file: Invalid file_path - must be a non-empty string`;
38271
+ 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").`;
37639
38272
  }
37640
38273
  if (content === void 0 || content === null || typeof content !== "string") {
37641
- return `Error creating file: Invalid content - must be a string`;
38274
+ 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).`;
37642
38275
  }
37643
38276
  const resolvedPath2 = (0, import_path5.isAbsolute)(file_path) ? file_path : (0, import_path5.resolve)(cwd || process.cwd(), file_path);
37644
38277
  if (debug) {
@@ -37646,15 +38279,17 @@ Important:
37646
38279
  }
37647
38280
  if (!isPathAllowed(resolvedPath2, allowedFolders)) {
37648
38281
  const relativePath = toRelativePath(resolvedPath2, workspaceRoot);
37649
- return `Error creating file: Permission denied - ${relativePath} is outside allowed directories`;
38282
+ return `Error creating file: Permission denied - ${relativePath} is outside allowed directories. Use a file path within the project workspace.`;
37650
38283
  }
37651
38284
  if ((0, import_fs5.existsSync)(resolvedPath2) && !overwrite) {
37652
38285
  return `Error creating file: File already exists - ${file_path}. Use overwrite: true to replace it.`;
37653
38286
  }
38287
+ const existed = (0, import_fs5.existsSync)(resolvedPath2);
37654
38288
  const dir = (0, import_path5.dirname)(resolvedPath2);
37655
38289
  await import_fs4.promises.mkdir(dir, { recursive: true });
37656
38290
  await import_fs4.promises.writeFile(resolvedPath2, content, "utf-8");
37657
- const action = (0, import_fs5.existsSync)(resolvedPath2) && overwrite ? "overwrote" : "created";
38291
+ if (options.fileTracker) await options.fileTracker.trackFileAfterWrite(resolvedPath2);
38292
+ const action = existed && overwrite ? "overwrote" : "created";
37658
38293
  const bytes = Buffer.byteLength(content, "utf-8");
37659
38294
  if (debug) {
37660
38295
  console.error(`[Create] Successfully ${action} ${resolvedPath2}`);
@@ -37676,18 +38311,35 @@ Important:
37676
38311
  },
37677
38312
  old_string: {
37678
38313
  type: "string",
37679
- description: "Exact text to find and replace"
38314
+ description: "Text to find and replace (for text-based editing)"
37680
38315
  },
37681
38316
  new_string: {
37682
38317
  type: "string",
37683
- description: "Text to replace with"
38318
+ description: "Replacement text or new code content"
37684
38319
  },
37685
38320
  replace_all: {
37686
38321
  type: "boolean",
37687
- description: "Replace all occurrences (default: false)"
38322
+ description: "Replace all occurrences (default: false, text mode only)"
38323
+ },
38324
+ symbol: {
38325
+ type: "string",
38326
+ description: 'Symbol name for AST-aware editing (e.g. "myFunction", "MyClass.myMethod")'
38327
+ },
38328
+ position: {
38329
+ type: "string",
38330
+ enum: ["before", "after"],
38331
+ description: "Insert before/after symbol or line (requires symbol or start_line, omit to replace)"
38332
+ },
38333
+ start_line: {
38334
+ type: "string",
38335
+ description: 'Line reference for line-targeted editing (e.g. "42" or "42:ab" with hash)'
38336
+ },
38337
+ end_line: {
38338
+ type: "string",
38339
+ description: 'End of line range, inclusive (e.g. "55" or "55:cd"). Defaults to start_line.'
37688
38340
  }
37689
38341
  },
37690
- required: ["file_path", "old_string", "new_string"]
38342
+ required: ["file_path", "new_string"]
37691
38343
  };
37692
38344
  createSchema = {
37693
38345
  type: "object",
@@ -37707,50 +38359,123 @@ Important:
37707
38359
  },
37708
38360
  required: ["file_path", "content"]
37709
38361
  };
37710
- editDescription = "Edit files using exact string replacement. Requires exact match including whitespace.";
38362
+ 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.";
37711
38363
  createDescription = "Create new files with specified content. Will create parent directories if needed.";
37712
38364
  editToolDefinition = `
37713
38365
  ## edit
37714
38366
  Description: ${editDescription}
37715
38367
 
37716
- When to use:
37717
- - For precise, surgical edits to existing files
37718
- - When you need to change specific lines or blocks of code
37719
- - For renaming functions, variables, or updating configuration values
37720
- - When the exact text to replace is known and unique (or use replace_all for multiple occurrences)
38368
+ Four editing modes \u2014 choose based on the scope of your change:
37721
38369
 
37722
- When NOT to use:
37723
- - For creating new files (use 'create' tool instead)
37724
- - When you cannot determine the exact text to replace
37725
- - When changes span multiple locations that would be better handled together
38370
+ 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.
38371
+
38372
+ 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.
38373
+
38374
+ 3. **Symbol insert** (symbol + new_string + position): For adding new code before or after an existing symbol. Set position to "before" or "after".
38375
+
38376
+ 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.
37726
38377
 
37727
38378
  Parameters:
37728
38379
  - file_path: (required) Path to the file to edit
37729
- - old_string: (required) Exact text to find and replace (must match including whitespace, newlines, and indentation)
37730
- - new_string: (required) Text to replace with
37731
- - replace_all: (optional, default: false) Replace all occurrences if the string appears multiple times
37732
-
37733
- Important notes:
37734
- - The old_string MUST match EXACTLY, including all whitespace, indentation, and line breaks
37735
- - If old_string appears multiple times and replace_all is false, the tool will fail
37736
- - Always verify the exact formatting of the text you want to replace
38380
+ - new_string: (required) Replacement text or new code content
38381
+ - old_string: (optional) Text to find and replace \u2014 copy verbatim from the file, do not paraphrase or reformat
38382
+ - replace_all: (optional, default: false) Replace all occurrences of old_string (text mode only)
38383
+ - symbol: (optional) Name of a code symbol (e.g. "myFunction", "MyClass.myMethod") \u2014 must match a function, class, or method definition
38384
+ - position: (optional) "before" or "after" \u2014 insert new_string near the symbol or line instead of replacing it
38385
+ - start_line: (optional) Line reference for line-targeted editing (e.g. "42" or "42:ab")
38386
+ - end_line: (optional) End of line range, inclusive (e.g. "55" or "55:cd"). Defaults to start_line.
38387
+
38388
+ Mode selection rules (priority order):
38389
+ - If symbol is provided, symbol mode is used (old_string and start_line are ignored)
38390
+ - If start_line is provided (without symbol), line-targeted mode is used
38391
+ - If old_string is provided (without symbol or start_line), text mode is used
38392
+ - If none are provided, the tool returns an error with guidance
38393
+
38394
+ When to use each mode:
38395
+ - Small edits (a line or a few lines): use text mode with old_string
38396
+ - Replacing entire functions/classes/methods: use symbol mode \u2014 no exact text matching needed
38397
+ - Editing specific lines from extract/search output: use line-targeted mode with start_line
38398
+ - 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
38399
+
38400
+ Error handling:
38401
+ - If an edit fails, read the error message carefully \u2014 it contains specific instructions for how to fix the call and retry
38402
+ - Common fixes: use 'search'/'extract' to get exact file content, add more context to old_string, switch between text and symbol modes
38403
+ - Line-targeted hash mismatch: the file changed since last read; the error provides updated line:hash references
37737
38404
 
37738
38405
  Examples:
38406
+
38407
+ Text edit (find and replace):
37739
38408
  <edit>
37740
38409
  <file_path>src/main.js</file_path>
37741
- <old_string>function oldName() {
37742
- return 42;
37743
- }</old_string>
37744
- <new_string>function newName() {
37745
- return 42;
37746
- }</new_string>
38410
+ <old_string>return false;</old_string>
38411
+ <new_string>return true;</new_string>
37747
38412
  </edit>
37748
38413
 
38414
+ Text edit with replace_all:
37749
38415
  <edit>
37750
38416
  <file_path>config.json</file_path>
37751
38417
  <old_string>"debug": false</old_string>
37752
38418
  <new_string>"debug": true</new_string>
37753
38419
  <replace_all>true</replace_all>
38420
+ </edit>
38421
+
38422
+ Symbol replace (rewrite entire function by name):
38423
+ <edit>
38424
+ <file_path>src/utils.js</file_path>
38425
+ <symbol>calculateTotal</symbol>
38426
+ <new_string>function calculateTotal(items) {
38427
+ return items.reduce((sum, item) => sum + item.price * item.quantity, 0);
38428
+ }</new_string>
38429
+ </edit>
38430
+
38431
+ Symbol insert (add new function after existing one):
38432
+ <edit>
38433
+ <file_path>src/utils.js</file_path>
38434
+ <symbol>calculateTotal</symbol>
38435
+ <position>after</position>
38436
+ <new_string>function calculateTax(total, rate) {
38437
+ return total * rate;
38438
+ }</new_string>
38439
+ </edit>
38440
+
38441
+ Line-targeted edit (replace a line):
38442
+ <edit>
38443
+ <file_path>src/main.js</file_path>
38444
+ <start_line>42</start_line>
38445
+ <new_string> return processItems(order.items);</new_string>
38446
+ </edit>
38447
+
38448
+ Line-targeted edit (replace a range of lines):
38449
+ <edit>
38450
+ <file_path>src/main.js</file_path>
38451
+ <start_line>42</start_line>
38452
+ <end_line>55</end_line>
38453
+ <new_string> // simplified implementation
38454
+ return processItems(order.items);</new_string>
38455
+ </edit>
38456
+
38457
+ Line-targeted edit with hash verification:
38458
+ <edit>
38459
+ <file_path>src/main.js</file_path>
38460
+ <start_line>42:ab</start_line>
38461
+ <end_line>55:cd</end_line>
38462
+ <new_string> return processItems(order.items);</new_string>
38463
+ </edit>
38464
+
38465
+ Line-targeted insert (add code after a line):
38466
+ <edit>
38467
+ <file_path>src/main.js</file_path>
38468
+ <start_line>42</start_line>
38469
+ <position>after</position>
38470
+ <new_string> const validated = validate(input);</new_string>
38471
+ </edit>
38472
+
38473
+ Line-targeted delete (remove lines):
38474
+ <edit>
38475
+ <file_path>src/main.js</file_path>
38476
+ <start_line>42</start_line>
38477
+ <end_line>45</end_line>
38478
+ <new_string></new_string>
37754
38479
  </edit>`;
37755
38480
  createToolDefinition = `
37756
38481
  ## create
@@ -38287,7 +39012,7 @@ function getValidParamsForTool(toolName) {
38287
39012
  };
38288
39013
  const schema = schemaMap[toolName];
38289
39014
  if (!schema) {
38290
- return ["path", "directory", "pattern", "recursive", "includeHidden", "task", "files", "autoCommits", "result"];
39015
+ return ["path", "directory", "pattern", "recursive", "includeHidden", "task", "files", "result"];
38291
39016
  }
38292
39017
  if (toolName === "attempt_completion") {
38293
39018
  return ["result"];
@@ -38300,6 +39025,10 @@ function getValidParamsForTool(toolName) {
38300
39025
  }
38301
39026
  return [];
38302
39027
  }
39028
+ function unescapeXmlEntities(str) {
39029
+ if (typeof str !== "string") return str;
39030
+ return str.replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&apos;/g, "'").replace(/&amp;/g, "&");
39031
+ }
38303
39032
  function parseXmlToolCall(xmlString, validTools = DEFAULT_VALID_TOOLS) {
38304
39033
  let earliestToolName = null;
38305
39034
  let earliestOpenIndex = Infinity;
@@ -38356,10 +39085,10 @@ function parseXmlToolCall(xmlString, validTools = DEFAULT_VALID_TOOLS) {
38356
39085
  }
38357
39086
  paramCloseIndex = nextTagIndex;
38358
39087
  }
38359
- let paramValue = innerContent.substring(
39088
+ let paramValue = unescapeXmlEntities(innerContent.substring(
38360
39089
  paramOpenIndex + paramOpenTag.length,
38361
39090
  paramCloseIndex
38362
- ).trim();
39091
+ ).trim());
38363
39092
  if (paramValue.toLowerCase() === "true") {
38364
39093
  paramValue = true;
38365
39094
  } else if (paramValue.toLowerCase() === "false") {
@@ -38373,7 +39102,7 @@ function parseXmlToolCall(xmlString, validTools = DEFAULT_VALID_TOOLS) {
38373
39102
  params[paramName] = paramValue;
38374
39103
  }
38375
39104
  if (toolName === "attempt_completion") {
38376
- params["result"] = innerContent.trim();
39105
+ params["result"] = unescapeXmlEntities(innerContent.trim());
38377
39106
  if (params.command) {
38378
39107
  delete params.command;
38379
39108
  }
@@ -38408,7 +39137,6 @@ function detectUnrecognizedToolCall(xmlString, validTools) {
38408
39137
  "listSkills",
38409
39138
  "useSkill",
38410
39139
  "readImage",
38411
- "implement",
38412
39140
  "edit",
38413
39141
  "create",
38414
39142
  "delegate",
@@ -38783,6 +39511,8 @@ User: Read file inside the dependency
38783
39511
  </extract>
38784
39512
 
38785
39513
  </examples>
39514
+
39515
+ **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.
38786
39516
  `;
38787
39517
  delegateToolDefinition = `
38788
39518
  ## delegate
@@ -38938,7 +39668,7 @@ Capabilities:
38938
39668
  `;
38939
39669
  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.";
38940
39670
  queryDescription = "Search code using ast-grep structural pattern matching. Use this tool to find specific code structures like functions, classes, or methods.";
38941
- 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.";
39671
+ 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.";
38942
39672
  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.";
38943
39673
  bashDescription = "Execute bash commands for system exploration and development tasks. Secure by default with built-in allow/deny lists.";
38944
39674
  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.';
@@ -38954,7 +39684,6 @@ Capabilities:
38954
39684
  "useSkill",
38955
39685
  "listFiles",
38956
39686
  "searchFiles",
38957
- "implement",
38958
39687
  "bash",
38959
39688
  "task",
38960
39689
  "attempt_completion"
@@ -39634,7 +40363,7 @@ function parseXmlToolCallWithThinking(xmlString, validTools) {
39634
40363
  const toolCall = parseXmlToolCall(cleanedXmlString, validTools);
39635
40364
  return toolCall ? { ...toolCall, thinkingContent } : null;
39636
40365
  }
39637
- var import_crypto2, implementToolDefinition, listFilesToolDefinition, searchFilesToolDefinition, listSkillsToolDefinition, useSkillToolDefinition, readImageToolDefinition;
40366
+ var import_crypto2, listFilesToolDefinition, searchFilesToolDefinition, listSkillsToolDefinition, useSkillToolDefinition, readImageToolDefinition;
39638
40367
  var init_tools = __esm({
39639
40368
  "src/agent/tools.js"() {
39640
40369
  "use strict";
@@ -39642,31 +40371,6 @@ var init_tools = __esm({
39642
40371
  import_crypto2 = require("crypto");
39643
40372
  init_xmlParsingUtils();
39644
40373
  init_tasks();
39645
- implementToolDefinition = `
39646
- ## implement
39647
- Description: Implement a given task. Can modify files. Can be used ONLY if task explicitly stated that something requires modification or implementation.
39648
-
39649
- Parameters:
39650
- - task: (required) The task description. Should be as detailed as possible, ideally pointing to exact files which needs be modified or created.
39651
- - autoCommits: (optional) Whether to enable auto-commits in aider. Default is false.
39652
-
39653
- Usage Example:
39654
-
39655
- <examples>
39656
-
39657
- User: Can you implement a function to calculate Fibonacci numbers in main.js?
39658
- <implement>
39659
- <task>Implement a recursive function to calculate the nth Fibonacci number in main.js</task>
39660
- </implement>
39661
-
39662
- User: Can you implement a function to calculate Fibonacci numbers in main.js with auto-commits?
39663
- <implement>
39664
- <task>Implement a recursive function to calculate the nth Fibonacci number in main.js</task>
39665
- <autoCommits>true</autoCommits>
39666
- </implement>
39667
-
39668
- </examples>
39669
- `;
39670
40374
  listFilesToolDefinition = `
39671
40375
  ## listFiles
39672
40376
  Description: List files and directories in a specified location.
@@ -39782,33 +40486,289 @@ User: Analyze the diagram in docs/architecture.svg
39782
40486
  }
39783
40487
  });
39784
40488
 
39785
- // node_modules/balanced-match/index.js
39786
- var require_balanced_match = __commonJS({
39787
- "node_modules/balanced-match/index.js"(exports2, module2) {
40489
+ // src/tools/fileTracker.js
40490
+ function computeContentHash(content) {
40491
+ const normalized = (content || "").split("\n").map((l5) => l5.trimEnd()).join("\n");
40492
+ return (0, import_crypto3.createHash)("sha256").update(normalized).digest("hex").slice(0, 16);
40493
+ }
40494
+ function extractFilePath(target) {
40495
+ const hashIdx = target.indexOf("#");
40496
+ if (hashIdx !== -1) {
40497
+ return target.slice(0, hashIdx);
40498
+ }
40499
+ const colonIdx = target.lastIndexOf(":");
40500
+ if (colonIdx !== -1) {
40501
+ const after = target.slice(colonIdx + 1);
40502
+ if (/^\d+(-\d+)?$/.test(after)) {
40503
+ return target.slice(0, colonIdx);
40504
+ }
40505
+ }
40506
+ return target;
40507
+ }
40508
+ function extractSymbolName(target) {
40509
+ const hashIdx = target.indexOf("#");
40510
+ if (hashIdx !== -1) {
40511
+ const symbol15 = target.slice(hashIdx + 1);
40512
+ return symbol15 || null;
40513
+ }
40514
+ return null;
40515
+ }
40516
+ function parseFilePathsFromOutput(output) {
40517
+ const paths = [];
40518
+ const regex = /^(?:File:\s+|---\s+)([^\s].*?)(?:\s+---)?$/gm;
40519
+ let match2;
40520
+ while ((match2 = regex.exec(output)) !== null) {
40521
+ const path9 = match2[1].trim();
40522
+ if (path9 && !path9.startsWith("Results") && !path9.startsWith("Page") && (path9.includes("/") || path9.includes(".") || path9.includes("\\"))) {
40523
+ paths.push(path9);
40524
+ }
40525
+ }
40526
+ return paths;
40527
+ }
40528
+ var import_crypto3, import_path7, FileTracker;
40529
+ var init_fileTracker = __esm({
40530
+ "src/tools/fileTracker.js"() {
39788
40531
  "use strict";
39789
- module2.exports = balanced;
39790
- function balanced(a5, b5, str) {
39791
- if (a5 instanceof RegExp) a5 = maybeMatch(a5, str);
39792
- if (b5 instanceof RegExp) b5 = maybeMatch(b5, str);
39793
- var r5 = range2(a5, b5, str);
40532
+ import_crypto3 = require("crypto");
40533
+ import_path7 = require("path");
40534
+ init_symbolEdit();
40535
+ FileTracker = class {
40536
+ /**
40537
+ * @param {Object} [options]
40538
+ * @param {boolean} [options.debug=false] - Enable debug logging
40539
+ */
40540
+ constructor(options = {}) {
40541
+ this.debug = options.debug || false;
40542
+ this._seenFiles = /* @__PURE__ */ new Set();
40543
+ this._contentRecords = /* @__PURE__ */ new Map();
40544
+ }
40545
+ /**
40546
+ * Mark a file as "seen" — the LLM has read its content.
40547
+ * @param {string} resolvedPath - Absolute path to the file
40548
+ */
40549
+ markFileSeen(resolvedPath2) {
40550
+ this._seenFiles.add(resolvedPath2);
40551
+ if (this.debug) {
40552
+ console.error(`[FileTracker] Marked as seen: ${resolvedPath2}`);
40553
+ }
40554
+ }
40555
+ /**
40556
+ * Check if a file has been seen in this session.
40557
+ * @param {string} resolvedPath - Absolute path to the file
40558
+ * @returns {boolean}
40559
+ */
40560
+ isFileSeen(resolvedPath2) {
40561
+ return this._seenFiles.has(resolvedPath2);
40562
+ }
40563
+ /**
40564
+ * Store a content hash for a symbol in a file.
40565
+ * @param {string} resolvedPath - Absolute path to the file
40566
+ * @param {string} symbolName - Symbol name (e.g. "calculateTotal")
40567
+ * @param {string} code - The symbol's source code
40568
+ * @param {number} startLine - 1-indexed start line
40569
+ * @param {number} endLine - 1-indexed end line
40570
+ * @param {string} [source='extract'] - How the content was obtained
40571
+ */
40572
+ trackSymbolContent(resolvedPath2, symbolName, code, startLine, endLine, source = "extract") {
40573
+ const key = `${resolvedPath2}#${symbolName}`;
40574
+ const contentHash = computeContentHash(code);
40575
+ this._contentRecords.set(key, {
40576
+ contentHash,
40577
+ startLine,
40578
+ endLine,
40579
+ symbolName,
40580
+ source,
40581
+ timestamp: Date.now()
40582
+ });
40583
+ if (this.debug) {
40584
+ console.error(`[FileTracker] Tracked symbol ${key} (hash: ${contentHash}, lines ${startLine}-${endLine})`);
40585
+ }
40586
+ }
40587
+ /**
40588
+ * Look up a stored content record for a symbol.
40589
+ * @param {string} resolvedPath - Absolute path to the file
40590
+ * @param {string} symbolName - Symbol name
40591
+ * @returns {Object|null} The stored record or null
40592
+ */
40593
+ getSymbolRecord(resolvedPath2, symbolName) {
40594
+ return this._contentRecords.get(`${resolvedPath2}#${symbolName}`) || null;
40595
+ }
40596
+ /**
40597
+ * Check if a symbol's current content matches what was stored.
40598
+ * @param {string} resolvedPath - Absolute path to the file
40599
+ * @param {string} symbolName - Symbol name
40600
+ * @param {string} currentCode - The symbol's current source code (from findSymbol)
40601
+ * @returns {{ok: boolean, reason?: string, message?: string}}
40602
+ */
40603
+ checkSymbolContent(resolvedPath2, symbolName, currentCode) {
40604
+ const key = `${resolvedPath2}#${symbolName}`;
40605
+ const record = this._contentRecords.get(key);
40606
+ if (!record) {
40607
+ return { ok: true };
40608
+ }
40609
+ const currentHash = computeContentHash(currentCode);
40610
+ if (currentHash === record.contentHash) {
40611
+ return { ok: true };
40612
+ }
40613
+ return {
40614
+ ok: false,
40615
+ reason: "stale",
40616
+ message: `Symbol "${symbolName}" has changed since you last read it (hash: ${record.contentHash} \u2192 ${currentHash}).`
40617
+ };
40618
+ }
40619
+ /**
40620
+ * Track files from extract target strings.
40621
+ * Marks each file as seen. For #symbol targets, calls findSymbol to get and hash the code.
40622
+ * @param {string[]} targets - Array of extract targets (e.g. ["file.js#fn", "file.js:10-20"])
40623
+ * @param {string} cwd - Working directory for resolving relative paths
40624
+ */
40625
+ async trackFilesFromExtract(targets, cwd) {
40626
+ const seenPaths = /* @__PURE__ */ new Set();
40627
+ const symbolPromises = [];
40628
+ for (const target of targets) {
40629
+ const filePath = extractFilePath(target);
40630
+ const resolved = (0, import_path7.isAbsolute)(filePath) ? filePath : (0, import_path7.resolve)(cwd, filePath);
40631
+ if (!seenPaths.has(resolved)) {
40632
+ seenPaths.add(resolved);
40633
+ this.markFileSeen(resolved);
40634
+ }
40635
+ const symbolName = extractSymbolName(target);
40636
+ if (symbolName) {
40637
+ symbolPromises.push(
40638
+ findSymbol(resolved, symbolName, cwd).then((symbolInfo) => {
40639
+ if (symbolInfo) {
40640
+ this.trackSymbolContent(
40641
+ resolved,
40642
+ symbolName,
40643
+ symbolInfo.code,
40644
+ symbolInfo.startLine,
40645
+ symbolInfo.endLine,
40646
+ "extract"
40647
+ );
40648
+ }
40649
+ }).catch((err) => {
40650
+ if (this.debug) {
40651
+ console.error(`[FileTracker] Failed to track symbol "${symbolName}" in ${resolved}: ${err.message}`);
40652
+ }
40653
+ })
40654
+ );
40655
+ }
40656
+ }
40657
+ if (symbolPromises.length > 0) {
40658
+ await Promise.all(symbolPromises);
40659
+ }
40660
+ }
40661
+ /**
40662
+ * Track files discovered in probe search/extract output.
40663
+ * Parses "File: path" headers and "--- path ---" separators, marks each as "seen".
40664
+ * @param {string} output - Probe output text
40665
+ * @param {string} cwd - Working directory for resolving relative paths
40666
+ */
40667
+ async trackFilesFromOutput(output, cwd) {
40668
+ const paths = parseFilePathsFromOutput(output);
40669
+ for (const filePath of paths) {
40670
+ const resolved = (0, import_path7.isAbsolute)(filePath) ? filePath : (0, import_path7.resolve)(cwd, filePath);
40671
+ this.markFileSeen(resolved);
40672
+ }
40673
+ }
40674
+ /**
40675
+ * Check if a file is safe to edit (seen-check only).
40676
+ * Mode-specific content verification happens in edit handlers.
40677
+ * @param {string} resolvedPath - Absolute path to the file
40678
+ * @returns {{ok: boolean, reason?: string, message?: string}}
40679
+ */
40680
+ checkBeforeEdit(resolvedPath2) {
40681
+ if (!this._seenFiles.has(resolvedPath2)) {
40682
+ return {
40683
+ ok: false,
40684
+ reason: "untracked",
40685
+ message: "This file has not been read yet in this session. Use extract or search to read the file first."
40686
+ };
40687
+ }
40688
+ return { ok: true };
40689
+ }
40690
+ /**
40691
+ * Mark a file as seen after a successful write (backward compat).
40692
+ * Also invalidates content records for the file since its content changed.
40693
+ * @param {string} resolvedPath - Absolute path to the file
40694
+ */
40695
+ async trackFileAfterWrite(resolvedPath2) {
40696
+ this.markFileSeen(resolvedPath2);
40697
+ this.invalidateFileRecords(resolvedPath2);
40698
+ }
40699
+ /**
40700
+ * Update the stored hash for a symbol after a successful write.
40701
+ * Enables chained edits to the same symbol.
40702
+ * @param {string} resolvedPath - Absolute path to the file
40703
+ * @param {string} symbolName - Symbol name
40704
+ * @param {string} code - The symbol's new source code
40705
+ * @param {number} startLine - 1-indexed start line (new position)
40706
+ * @param {number} endLine - 1-indexed end line (new position)
40707
+ */
40708
+ trackSymbolAfterWrite(resolvedPath2, symbolName, code, startLine, endLine) {
40709
+ this.trackSymbolContent(resolvedPath2, symbolName, code, startLine, endLine, "edit");
40710
+ }
40711
+ /**
40712
+ * Remove all content records for a file.
40713
+ * Called after non-symbol edits (text/line mode) since those change content
40714
+ * without providing a symbol-level update.
40715
+ * @param {string} resolvedPath - Absolute path to the file
40716
+ */
40717
+ invalidateFileRecords(resolvedPath2) {
40718
+ const prefix = resolvedPath2 + "#";
40719
+ for (const key of this._contentRecords.keys()) {
40720
+ if (key.startsWith(prefix)) {
40721
+ this._contentRecords.delete(key);
40722
+ }
40723
+ }
40724
+ if (this.debug) {
40725
+ console.error(`[FileTracker] Invalidated content records for ${resolvedPath2}`);
40726
+ }
40727
+ }
40728
+ /**
40729
+ * Quick sync check if a file is being tracked (alias for isFileSeen).
40730
+ * @param {string} resolvedPath - Absolute path to the file
40731
+ * @returns {boolean}
40732
+ */
40733
+ isTracked(resolvedPath2) {
40734
+ return this.isFileSeen(resolvedPath2);
40735
+ }
40736
+ /**
40737
+ * Clear all tracking state.
40738
+ */
40739
+ clear() {
40740
+ this._seenFiles.clear();
40741
+ this._contentRecords.clear();
40742
+ }
40743
+ };
40744
+ }
40745
+ });
40746
+
40747
+ // node_modules/balanced-match/dist/esm/index.js
40748
+ var balanced, maybeMatch, range2;
40749
+ var init_esm = __esm({
40750
+ "node_modules/balanced-match/dist/esm/index.js"() {
40751
+ balanced = (a5, b5, str) => {
40752
+ const ma = a5 instanceof RegExp ? maybeMatch(a5, str) : a5;
40753
+ const mb = b5 instanceof RegExp ? maybeMatch(b5, str) : b5;
40754
+ const r5 = ma !== null && mb != null && range2(ma, mb, str);
39794
40755
  return r5 && {
39795
40756
  start: r5[0],
39796
40757
  end: r5[1],
39797
40758
  pre: str.slice(0, r5[0]),
39798
- body: str.slice(r5[0] + a5.length, r5[1]),
39799
- post: str.slice(r5[1] + b5.length)
40759
+ body: str.slice(r5[0] + ma.length, r5[1]),
40760
+ post: str.slice(r5[1] + mb.length)
39800
40761
  };
39801
- }
39802
- function maybeMatch(reg, str) {
39803
- var m5 = str.match(reg);
40762
+ };
40763
+ maybeMatch = (reg, str) => {
40764
+ const m5 = str.match(reg);
39804
40765
  return m5 ? m5[0] : null;
39805
- }
39806
- balanced.range = range2;
39807
- function range2(a5, b5, str) {
39808
- var begs, beg, left, right, result;
39809
- var ai = str.indexOf(a5);
39810
- var bi = str.indexOf(b5, ai + 1);
39811
- var i5 = ai;
40766
+ };
40767
+ range2 = (a5, b5, str) => {
40768
+ let begs, beg, left, right = void 0, result;
40769
+ let ai = str.indexOf(a5);
40770
+ let bi = str.indexOf(b5, ai + 1);
40771
+ let i5 = ai;
39812
40772
  if (ai >= 0 && bi > 0) {
39813
40773
  if (a5 === b5) {
39814
40774
  return [ai, bi];
@@ -39816,14 +40776,16 @@ var require_balanced_match = __commonJS({
39816
40776
  begs = [];
39817
40777
  left = str.length;
39818
40778
  while (i5 >= 0 && !result) {
39819
- if (i5 == ai) {
40779
+ if (i5 === ai) {
39820
40780
  begs.push(i5);
39821
40781
  ai = str.indexOf(a5, i5 + 1);
39822
- } else if (begs.length == 1) {
39823
- result = [begs.pop(), bi];
40782
+ } else if (begs.length === 1) {
40783
+ const r5 = begs.pop();
40784
+ if (r5 !== void 0)
40785
+ result = [r5, bi];
39824
40786
  } else {
39825
40787
  beg = begs.pop();
39826
- if (beg < left) {
40788
+ if (beg !== void 0 && beg < left) {
39827
40789
  left = beg;
39828
40790
  right = bi;
39829
40791
  }
@@ -39831,163 +40793,179 @@ var require_balanced_match = __commonJS({
39831
40793
  }
39832
40794
  i5 = ai < bi && ai >= 0 ? ai : bi;
39833
40795
  }
39834
- if (begs.length) {
40796
+ if (begs.length && right !== void 0) {
39835
40797
  result = [left, right];
39836
40798
  }
39837
40799
  }
39838
40800
  return result;
39839
- }
40801
+ };
39840
40802
  }
39841
40803
  });
39842
40804
 
39843
- // node_modules/brace-expansion/index.js
39844
- var require_brace_expansion = __commonJS({
39845
- "node_modules/brace-expansion/index.js"(exports2, module2) {
39846
- var balanced = require_balanced_match();
39847
- module2.exports = expandTop;
39848
- var escSlash = "\0SLASH" + Math.random() + "\0";
39849
- var escOpen = "\0OPEN" + Math.random() + "\0";
39850
- var escClose = "\0CLOSE" + Math.random() + "\0";
39851
- var escComma = "\0COMMA" + Math.random() + "\0";
39852
- var escPeriod = "\0PERIOD" + Math.random() + "\0";
39853
- function numeric(str) {
39854
- return parseInt(str, 10) == str ? parseInt(str, 10) : str.charCodeAt(0);
39855
- }
39856
- function escapeBraces(str) {
39857
- return str.split("\\\\").join(escSlash).split("\\{").join(escOpen).split("\\}").join(escClose).split("\\,").join(escComma).split("\\.").join(escPeriod);
39858
- }
39859
- function unescapeBraces(str) {
39860
- return str.split(escSlash).join("\\").split(escOpen).join("{").split(escClose).join("}").split(escComma).join(",").split(escPeriod).join(".");
39861
- }
39862
- function parseCommaParts(str) {
39863
- if (!str)
39864
- return [""];
39865
- var parts = [];
39866
- var m5 = balanced("{", "}", str);
39867
- if (!m5)
39868
- return str.split(",");
39869
- var pre = m5.pre;
39870
- var body = m5.body;
39871
- var post = m5.post;
39872
- var p5 = pre.split(",");
39873
- p5[p5.length - 1] += "{" + body + "}";
39874
- var postParts = parseCommaParts(post);
39875
- if (post.length) {
39876
- p5[p5.length - 1] += postParts.shift();
39877
- p5.push.apply(p5, postParts);
39878
- }
39879
- parts.push.apply(parts, p5);
39880
- return parts;
39881
- }
39882
- function expandTop(str) {
39883
- if (!str)
39884
- return [];
39885
- if (str.substr(0, 2) === "{}") {
39886
- str = "\\{\\}" + str.substr(2);
39887
- }
39888
- return expand2(escapeBraces(str), true).map(unescapeBraces);
39889
- }
39890
- function embrace(str) {
39891
- return "{" + str + "}";
39892
- }
39893
- function isPadded(el) {
39894
- return /^-?0\d/.test(el);
39895
- }
39896
- function lte(i5, y2) {
39897
- return i5 <= y2;
39898
- }
39899
- function gte(i5, y2) {
39900
- return i5 >= y2;
40805
+ // node_modules/brace-expansion/dist/esm/index.js
40806
+ function numeric(str) {
40807
+ return !isNaN(str) ? parseInt(str, 10) : str.charCodeAt(0);
40808
+ }
40809
+ function escapeBraces(str) {
40810
+ return str.replace(slashPattern, escSlash).replace(openPattern, escOpen).replace(closePattern, escClose).replace(commaPattern, escComma).replace(periodPattern, escPeriod);
40811
+ }
40812
+ function unescapeBraces(str) {
40813
+ return str.replace(escSlashPattern, "\\").replace(escOpenPattern, "{").replace(escClosePattern, "}").replace(escCommaPattern, ",").replace(escPeriodPattern, ".");
40814
+ }
40815
+ function parseCommaParts(str) {
40816
+ if (!str) {
40817
+ return [""];
40818
+ }
40819
+ const parts = [];
40820
+ const m5 = balanced("{", "}", str);
40821
+ if (!m5) {
40822
+ return str.split(",");
40823
+ }
40824
+ const { pre, body, post } = m5;
40825
+ const p5 = pre.split(",");
40826
+ p5[p5.length - 1] += "{" + body + "}";
40827
+ const postParts = parseCommaParts(post);
40828
+ if (post.length) {
40829
+ ;
40830
+ p5[p5.length - 1] += postParts.shift();
40831
+ p5.push.apply(p5, postParts);
40832
+ }
40833
+ parts.push.apply(parts, p5);
40834
+ return parts;
40835
+ }
40836
+ function expand(str, options = {}) {
40837
+ if (!str) {
40838
+ return [];
40839
+ }
40840
+ const { max = EXPANSION_MAX } = options;
40841
+ if (str.slice(0, 2) === "{}") {
40842
+ str = "\\{\\}" + str.slice(2);
40843
+ }
40844
+ return expand_(escapeBraces(str), max, true).map(unescapeBraces);
40845
+ }
40846
+ function embrace(str) {
40847
+ return "{" + str + "}";
40848
+ }
40849
+ function isPadded(el) {
40850
+ return /^-?0\d/.test(el);
40851
+ }
40852
+ function lte(i5, y2) {
40853
+ return i5 <= y2;
40854
+ }
40855
+ function gte(i5, y2) {
40856
+ return i5 >= y2;
40857
+ }
40858
+ function expand_(str, max, isTop) {
40859
+ const expansions = [];
40860
+ const m5 = balanced("{", "}", str);
40861
+ if (!m5)
40862
+ return [str];
40863
+ const pre = m5.pre;
40864
+ const post = m5.post.length ? expand_(m5.post, max, false) : [""];
40865
+ if (/\$$/.test(m5.pre)) {
40866
+ for (let k5 = 0; k5 < post.length && k5 < max; k5++) {
40867
+ const expansion = pre + "{" + m5.body + "}" + post[k5];
40868
+ expansions.push(expansion);
39901
40869
  }
39902
- function expand2(str, isTop) {
39903
- var expansions = [];
39904
- var m5 = balanced("{", "}", str);
39905
- if (!m5) return [str];
39906
- var pre = m5.pre;
39907
- var post = m5.post.length ? expand2(m5.post, false) : [""];
39908
- if (/\$$/.test(m5.pre)) {
39909
- for (var k5 = 0; k5 < post.length; k5++) {
39910
- var expansion = pre + "{" + m5.body + "}" + post[k5];
39911
- expansions.push(expansion);
39912
- }
39913
- } else {
39914
- var isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m5.body);
39915
- var isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m5.body);
39916
- var isSequence = isNumericSequence || isAlphaSequence;
39917
- var isOptions = m5.body.indexOf(",") >= 0;
39918
- if (!isSequence && !isOptions) {
39919
- if (m5.post.match(/,(?!,).*\}/)) {
39920
- str = m5.pre + "{" + m5.body + escClose + m5.post;
39921
- return expand2(str);
39922
- }
39923
- return [str];
39924
- }
39925
- var n5;
39926
- if (isSequence) {
39927
- n5 = m5.body.split(/\.\./);
39928
- } else {
39929
- n5 = parseCommaParts(m5.body);
39930
- if (n5.length === 1) {
39931
- n5 = expand2(n5[0], false).map(embrace);
39932
- if (n5.length === 1) {
39933
- return post.map(function(p5) {
39934
- return m5.pre + n5[0] + p5;
39935
- });
39936
- }
40870
+ } else {
40871
+ const isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m5.body);
40872
+ const isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m5.body);
40873
+ const isSequence = isNumericSequence || isAlphaSequence;
40874
+ const isOptions = m5.body.indexOf(",") >= 0;
40875
+ if (!isSequence && !isOptions) {
40876
+ if (m5.post.match(/,(?!,).*\}/)) {
40877
+ str = m5.pre + "{" + m5.body + escClose + m5.post;
40878
+ return expand_(str, max, true);
40879
+ }
40880
+ return [str];
40881
+ }
40882
+ let n5;
40883
+ if (isSequence) {
40884
+ n5 = m5.body.split(/\.\./);
40885
+ } else {
40886
+ n5 = parseCommaParts(m5.body);
40887
+ if (n5.length === 1 && n5[0] !== void 0) {
40888
+ n5 = expand_(n5[0], max, false).map(embrace);
40889
+ if (n5.length === 1) {
40890
+ return post.map((p5) => m5.pre + n5[0] + p5);
40891
+ }
40892
+ }
40893
+ }
40894
+ let N;
40895
+ if (isSequence && n5[0] !== void 0 && n5[1] !== void 0) {
40896
+ const x5 = numeric(n5[0]);
40897
+ const y2 = numeric(n5[1]);
40898
+ const width = Math.max(n5[0].length, n5[1].length);
40899
+ let incr = n5.length === 3 && n5[2] !== void 0 ? Math.abs(numeric(n5[2])) : 1;
40900
+ let test = lte;
40901
+ const reverse = y2 < x5;
40902
+ if (reverse) {
40903
+ incr *= -1;
40904
+ test = gte;
40905
+ }
40906
+ const pad = n5.some(isPadded);
40907
+ N = [];
40908
+ for (let i5 = x5; test(i5, y2); i5 += incr) {
40909
+ let c5;
40910
+ if (isAlphaSequence) {
40911
+ c5 = String.fromCharCode(i5);
40912
+ if (c5 === "\\") {
40913
+ c5 = "";
39937
40914
  }
39938
- }
39939
- var N;
39940
- if (isSequence) {
39941
- var x5 = numeric(n5[0]);
39942
- var y2 = numeric(n5[1]);
39943
- var width = Math.max(n5[0].length, n5[1].length);
39944
- var incr = n5.length == 3 ? Math.abs(numeric(n5[2])) : 1;
39945
- var test = lte;
39946
- var reverse = y2 < x5;
39947
- if (reverse) {
39948
- incr *= -1;
39949
- test = gte;
39950
- }
39951
- var pad = n5.some(isPadded);
39952
- N = [];
39953
- for (var i5 = x5; test(i5, y2); i5 += incr) {
39954
- var c5;
39955
- if (isAlphaSequence) {
39956
- c5 = String.fromCharCode(i5);
39957
- if (c5 === "\\")
39958
- c5 = "";
39959
- } else {
39960
- c5 = String(i5);
39961
- if (pad) {
39962
- var need = width - c5.length;
39963
- if (need > 0) {
39964
- var z2 = new Array(need + 1).join("0");
39965
- if (i5 < 0)
39966
- c5 = "-" + z2 + c5.slice(1);
39967
- else
39968
- c5 = z2 + c5;
39969
- }
40915
+ } else {
40916
+ c5 = String(i5);
40917
+ if (pad) {
40918
+ const need = width - c5.length;
40919
+ if (need > 0) {
40920
+ const z2 = new Array(need + 1).join("0");
40921
+ if (i5 < 0) {
40922
+ c5 = "-" + z2 + c5.slice(1);
40923
+ } else {
40924
+ c5 = z2 + c5;
39970
40925
  }
39971
40926
  }
39972
- N.push(c5);
39973
- }
39974
- } else {
39975
- N = [];
39976
- for (var j5 = 0; j5 < n5.length; j5++) {
39977
- N.push.apply(N, expand2(n5[j5], false));
39978
40927
  }
39979
40928
  }
39980
- for (var j5 = 0; j5 < N.length; j5++) {
39981
- for (var k5 = 0; k5 < post.length; k5++) {
39982
- var expansion = pre + N[j5] + post[k5];
39983
- if (!isTop || isSequence || expansion)
39984
- expansions.push(expansion);
39985
- }
40929
+ N.push(c5);
40930
+ }
40931
+ } else {
40932
+ N = [];
40933
+ for (let j5 = 0; j5 < n5.length; j5++) {
40934
+ N.push.apply(N, expand_(n5[j5], max, false));
40935
+ }
40936
+ }
40937
+ for (let j5 = 0; j5 < N.length; j5++) {
40938
+ for (let k5 = 0; k5 < post.length && expansions.length < max; k5++) {
40939
+ const expansion = pre + N[j5] + post[k5];
40940
+ if (!isTop || isSequence || expansion) {
40941
+ expansions.push(expansion);
39986
40942
  }
39987
40943
  }
39988
- return expansions;
39989
40944
  }
39990
40945
  }
40946
+ return expansions;
40947
+ }
40948
+ var escSlash, escOpen, escClose, escComma, escPeriod, escSlashPattern, escOpenPattern, escClosePattern, escCommaPattern, escPeriodPattern, slashPattern, openPattern, closePattern, commaPattern, periodPattern, EXPANSION_MAX;
40949
+ var init_esm2 = __esm({
40950
+ "node_modules/brace-expansion/dist/esm/index.js"() {
40951
+ init_esm();
40952
+ escSlash = "\0SLASH" + Math.random() + "\0";
40953
+ escOpen = "\0OPEN" + Math.random() + "\0";
40954
+ escClose = "\0CLOSE" + Math.random() + "\0";
40955
+ escComma = "\0COMMA" + Math.random() + "\0";
40956
+ escPeriod = "\0PERIOD" + Math.random() + "\0";
40957
+ escSlashPattern = new RegExp(escSlash, "g");
40958
+ escOpenPattern = new RegExp(escOpen, "g");
40959
+ escClosePattern = new RegExp(escClose, "g");
40960
+ escCommaPattern = new RegExp(escComma, "g");
40961
+ escPeriodPattern = new RegExp(escPeriod, "g");
40962
+ slashPattern = /\\\\/g;
40963
+ openPattern = /\\{/g;
40964
+ closePattern = /\\}/g;
40965
+ commaPattern = /\\,/g;
40966
+ periodPattern = /\\./g;
40967
+ EXPANSION_MAX = 1e5;
40968
+ }
39991
40969
  });
39992
40970
 
39993
40971
  // node_modules/minimatch/dist/esm/assert-valid-pattern.js
@@ -40570,11 +41548,13 @@ var init_ast = __esm({
40570
41548
  let escaping = false;
40571
41549
  let re = "";
40572
41550
  let uflag = false;
41551
+ let inStar = false;
40573
41552
  for (let i5 = 0; i5 < glob2.length; i5++) {
40574
41553
  const c5 = glob2.charAt(i5);
40575
41554
  if (escaping) {
40576
41555
  escaping = false;
40577
41556
  re += (reSpecials.has(c5) ? "\\" : "") + c5;
41557
+ inStar = false;
40578
41558
  continue;
40579
41559
  }
40580
41560
  if (c5 === "\\") {
@@ -40592,16 +41572,19 @@ var init_ast = __esm({
40592
41572
  uflag = uflag || needUflag;
40593
41573
  i5 += consumed - 1;
40594
41574
  hasMagic2 = hasMagic2 || magic;
41575
+ inStar = false;
40595
41576
  continue;
40596
41577
  }
40597
41578
  }
40598
41579
  if (c5 === "*") {
40599
- if (noEmpty && glob2 === "*")
40600
- re += starNoEmpty;
40601
- else
40602
- re += star;
41580
+ if (inStar)
41581
+ continue;
41582
+ inStar = true;
41583
+ re += noEmpty && /^[*]+$/.test(glob2) ? starNoEmpty : star;
40603
41584
  hasMagic2 = true;
40604
41585
  continue;
41586
+ } else {
41587
+ inStar = false;
40605
41588
  }
40606
41589
  if (c5 === "?") {
40607
41590
  re += qmark;
@@ -40627,10 +41610,10 @@ var init_escape = __esm({
40627
41610
  });
40628
41611
 
40629
41612
  // node_modules/minimatch/dist/esm/index.js
40630
- 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, sep2, GLOBSTAR, qmark2, star2, twoStarDot, twoStarNoDot, filter, ext, defaults, braceExpand, makeRe, match, globMagic, regExpEscape2, Minimatch;
40631
- var init_esm = __esm({
41613
+ var minimatch, starDotExtRE, starDotExtTest, starDotExtTestDot, starDotExtTestNocase, starDotExtTestNocaseDot, starDotStarRE, starDotStarTest, starDotStarTestDot, dotStarRE, dotStarTest, starRE, starTest, starTestDot, qmarksRE, qmarksTestNocase, qmarksTestNocaseDot, qmarksTestDot, qmarksTest, qmarksTestNoExt, qmarksTestNoExtDot, defaultPlatform, path5, sep2, GLOBSTAR, qmark2, star2, twoStarDot, twoStarNoDot, filter, ext, defaults, braceExpand, makeRe, match, globMagic, regExpEscape2, Minimatch;
41614
+ var init_esm3 = __esm({
40632
41615
  "node_modules/minimatch/dist/esm/index.js"() {
40633
- import_brace_expansion = __toESM(require_brace_expansion(), 1);
41616
+ init_esm2();
40634
41617
  init_assert_valid_pattern();
40635
41618
  init_ast();
40636
41619
  init_escape();
@@ -40753,7 +41736,7 @@ var init_esm = __esm({
40753
41736
  if (options.nobrace || !/\{(?:(?!\{).)*\}/.test(pattern)) {
40754
41737
  return [pattern];
40755
41738
  }
40756
- return (0, import_brace_expansion.default)(pattern);
41739
+ return expand(pattern);
40757
41740
  };
40758
41741
  minimatch.braceExpand = braceExpand;
40759
41742
  makeRe = (pattern, options = {}) => new Minimatch(pattern, options).makeRe();
@@ -41359,7 +42342,7 @@ var init_esm = __esm({
41359
42342
 
41360
42343
  // node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.js
41361
42344
  var perf, warned, PROCESS, emitWarning, AC, AS, shouldWarn, TYPE, isPosInt, getUintArray, ZeroArray, Stack, LRUCache;
41362
- var init_esm2 = __esm({
42345
+ var init_esm4 = __esm({
41363
42346
  "node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.js"() {
41364
42347
  perf = typeof performance === "object" && performance && typeof performance.now === "function" ? performance : Date;
41365
42348
  warned = /* @__PURE__ */ new Set();
@@ -42733,7 +43716,7 @@ var init_esm2 = __esm({
42733
43716
 
42734
43717
  // node_modules/minipass/dist/esm/index.js
42735
43718
  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;
42736
- var init_esm3 = __esm({
43719
+ var init_esm5 = __esm({
42737
43720
  "node_modules/minipass/dist/esm/index.js"() {
42738
43721
  import_node_events = require("node:events");
42739
43722
  import_node_stream = __toESM(require("node:stream"), 1);
@@ -43463,10 +44446,10 @@ var init_esm3 = __esm({
43463
44446
  * Return a void Promise that resolves once the stream ends.
43464
44447
  */
43465
44448
  async promise() {
43466
- return new Promise((resolve7, reject2) => {
44449
+ return new Promise((resolve8, reject2) => {
43467
44450
  this.on(DESTROYED, () => reject2(new Error("stream destroyed")));
43468
44451
  this.on("error", (er) => reject2(er));
43469
- this.on("end", () => resolve7());
44452
+ this.on("end", () => resolve8());
43470
44453
  });
43471
44454
  }
43472
44455
  /**
@@ -43490,7 +44473,7 @@ var init_esm3 = __esm({
43490
44473
  return Promise.resolve({ done: false, value: res });
43491
44474
  if (this[EOF])
43492
44475
  return stop();
43493
- let resolve7;
44476
+ let resolve8;
43494
44477
  let reject2;
43495
44478
  const onerr = (er) => {
43496
44479
  this.off("data", ondata);
@@ -43504,19 +44487,19 @@ var init_esm3 = __esm({
43504
44487
  this.off("end", onend);
43505
44488
  this.off(DESTROYED, ondestroy);
43506
44489
  this.pause();
43507
- resolve7({ value, done: !!this[EOF] });
44490
+ resolve8({ value, done: !!this[EOF] });
43508
44491
  };
43509
44492
  const onend = () => {
43510
44493
  this.off("error", onerr);
43511
44494
  this.off("data", ondata);
43512
44495
  this.off(DESTROYED, ondestroy);
43513
44496
  stop();
43514
- resolve7({ done: true, value: void 0 });
44497
+ resolve8({ done: true, value: void 0 });
43515
44498
  };
43516
44499
  const ondestroy = () => onerr(new Error("stream destroyed"));
43517
44500
  return new Promise((res2, rej) => {
43518
44501
  reject2 = rej;
43519
- resolve7 = res2;
44502
+ resolve8 = res2;
43520
44503
  this.once(DESTROYED, ondestroy);
43521
44504
  this.once("error", onerr);
43522
44505
  this.once("end", onend);
@@ -43620,15 +44603,15 @@ var init_esm3 = __esm({
43620
44603
 
43621
44604
  // node_modules/path-scurry/dist/esm/index.js
43622
44605
  var import_node_path, import_node_url, import_fs6, 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;
43623
- var init_esm4 = __esm({
44606
+ var init_esm6 = __esm({
43624
44607
  "node_modules/path-scurry/dist/esm/index.js"() {
43625
- init_esm2();
44608
+ init_esm4();
43626
44609
  import_node_path = require("node:path");
43627
44610
  import_node_url = require("node:url");
43628
44611
  import_fs6 = require("fs");
43629
44612
  actualFS = __toESM(require("node:fs"), 1);
43630
44613
  import_promises = require("node:fs/promises");
43631
- init_esm3();
44614
+ init_esm5();
43632
44615
  realpathSync2 = import_fs6.realpathSync.native;
43633
44616
  defaultFS = {
43634
44617
  lstatSync: import_fs6.lstatSync,
@@ -44500,9 +45483,9 @@ var init_esm4 = __esm({
44500
45483
  if (this.#asyncReaddirInFlight) {
44501
45484
  await this.#asyncReaddirInFlight;
44502
45485
  } else {
44503
- let resolve7 = () => {
45486
+ let resolve8 = () => {
44504
45487
  };
44505
- this.#asyncReaddirInFlight = new Promise((res) => resolve7 = res);
45488
+ this.#asyncReaddirInFlight = new Promise((res) => resolve8 = res);
44506
45489
  try {
44507
45490
  for (const e5 of await this.#fs.promises.readdir(fullpath, {
44508
45491
  withFileTypes: true
@@ -44515,7 +45498,7 @@ var init_esm4 = __esm({
44515
45498
  children.provisional = 0;
44516
45499
  }
44517
45500
  this.#asyncReaddirInFlight = void 0;
44518
- resolve7();
45501
+ resolve8();
44519
45502
  }
44520
45503
  return children.slice(0, children.provisional);
44521
45504
  }
@@ -45358,7 +46341,7 @@ var init_esm4 = __esm({
45358
46341
  var isPatternList, isGlobList, Pattern;
45359
46342
  var init_pattern = __esm({
45360
46343
  "node_modules/glob/dist/esm/pattern.js"() {
45361
- init_esm();
46344
+ init_esm3();
45362
46345
  isPatternList = (pl) => pl.length >= 1;
45363
46346
  isGlobList = (gl) => gl.length >= 1;
45364
46347
  Pattern = class _Pattern {
@@ -45529,7 +46512,7 @@ var init_pattern = __esm({
45529
46512
  var defaultPlatform2, Ignore;
45530
46513
  var init_ignore = __esm({
45531
46514
  "node_modules/glob/dist/esm/ignore.js"() {
45532
- init_esm();
46515
+ init_esm3();
45533
46516
  init_pattern();
45534
46517
  defaultPlatform2 = typeof process === "object" && process && typeof process.platform === "string" ? process.platform : "linux";
45535
46518
  Ignore = class {
@@ -45623,7 +46606,7 @@ var init_ignore = __esm({
45623
46606
  var HasWalkedCache, MatchRecord, SubWalks, Processor;
45624
46607
  var init_processor = __esm({
45625
46608
  "node_modules/glob/dist/esm/processor.js"() {
45626
- init_esm();
46609
+ init_esm3();
45627
46610
  HasWalkedCache = class _HasWalkedCache {
45628
46611
  store;
45629
46612
  constructor(store = /* @__PURE__ */ new Map()) {
@@ -45850,7 +46833,7 @@ var init_processor = __esm({
45850
46833
  var makeIgnore, GlobUtil, GlobWalker, GlobStream;
45851
46834
  var init_walker = __esm({
45852
46835
  "node_modules/glob/dist/esm/walker.js"() {
45853
- init_esm3();
46836
+ init_esm5();
45854
46837
  init_ignore();
45855
46838
  init_processor();
45856
46839
  makeIgnore = (ignore2, opts) => typeof ignore2 === "string" ? new Ignore([ignore2], opts) : Array.isArray(ignore2) ? new Ignore(ignore2, opts) : ignore2;
@@ -46185,9 +47168,9 @@ var init_walker = __esm({
46185
47168
  var import_node_url2, defaultPlatform3, Glob;
46186
47169
  var init_glob = __esm({
46187
47170
  "node_modules/glob/dist/esm/glob.js"() {
46188
- init_esm();
47171
+ init_esm3();
46189
47172
  import_node_url2 = require("node:url");
46190
- init_esm4();
47173
+ init_esm6();
46191
47174
  init_pattern();
46192
47175
  init_walker();
46193
47176
  defaultPlatform3 = typeof process === "object" && process && typeof process.platform === "string" ? process.platform : "linux";
@@ -46395,7 +47378,7 @@ var init_glob = __esm({
46395
47378
  var hasMagic;
46396
47379
  var init_has_magic = __esm({
46397
47380
  "node_modules/glob/dist/esm/has-magic.js"() {
46398
- init_esm();
47381
+ init_esm3();
46399
47382
  hasMagic = (pattern, options = {}) => {
46400
47383
  if (!Array.isArray(pattern)) {
46401
47384
  pattern = [pattern];
@@ -46429,12 +47412,12 @@ function globIterate(pattern, options = {}) {
46429
47412
  return new Glob(pattern, options).iterate();
46430
47413
  }
46431
47414
  var streamSync, stream, iterateSync, iterate, sync, glob;
46432
- var init_esm5 = __esm({
47415
+ var init_esm7 = __esm({
46433
47416
  "node_modules/glob/dist/esm/index.js"() {
46434
- init_esm();
47417
+ init_esm3();
46435
47418
  init_glob();
46436
47419
  init_has_magic();
46437
- init_esm();
47420
+ init_esm3();
46438
47421
  init_glob();
46439
47422
  init_has_magic();
46440
47423
  init_ignore();
@@ -46564,19 +47547,19 @@ function createWrappedTools(baseTools) {
46564
47547
  }
46565
47548
  return wrappedTools;
46566
47549
  }
46567
- var import_child_process6, import_util11, import_crypto3, import_events, import_fs7, import_fs8, import_path7, toolCallEmitter, activeToolExecutions, wrapToolWithEmitter, listFilesTool, searchFilesTool, listFilesToolInstance, searchFilesToolInstance;
47550
+ var import_child_process6, import_util11, import_crypto4, import_events, import_fs7, import_fs8, import_path8, toolCallEmitter, activeToolExecutions, wrapToolWithEmitter, listFilesTool, searchFilesTool, listFilesToolInstance, searchFilesToolInstance;
46568
47551
  var init_probeTool = __esm({
46569
47552
  "src/agent/probeTool.js"() {
46570
47553
  "use strict";
46571
47554
  init_index();
46572
47555
  import_child_process6 = require("child_process");
46573
47556
  import_util11 = require("util");
46574
- import_crypto3 = require("crypto");
47557
+ import_crypto4 = require("crypto");
46575
47558
  import_events = require("events");
46576
47559
  import_fs7 = __toESM(require("fs"), 1);
46577
47560
  import_fs8 = require("fs");
46578
- import_path7 = __toESM(require("path"), 1);
46579
- init_esm5();
47561
+ import_path8 = __toESM(require("path"), 1);
47562
+ init_esm7();
46580
47563
  init_symlink_utils();
46581
47564
  toolCallEmitter = new import_events.EventEmitter();
46582
47565
  activeToolExecutions = /* @__PURE__ */ new Map();
@@ -46586,7 +47569,7 @@ var init_probeTool = __esm({
46586
47569
  // Spread schema, description etc.
46587
47570
  execute: async (params) => {
46588
47571
  const debug = process.env.DEBUG === "1";
46589
- const toolSessionId = params.sessionId || (0, import_crypto3.randomUUID)();
47572
+ const toolSessionId = params.sessionId || (0, import_crypto4.randomUUID)();
46590
47573
  if (debug) {
46591
47574
  console.log(`[DEBUG] probeTool: Executing ${toolName} for session ${toolSessionId}`);
46592
47575
  }
@@ -46664,17 +47647,17 @@ var init_probeTool = __esm({
46664
47647
  execute: async (params) => {
46665
47648
  const { directory = ".", workingDirectory } = params;
46666
47649
  const baseCwd = workingDirectory || process.cwd();
46667
- const secureBaseDir = import_path7.default.resolve(baseCwd);
47650
+ const secureBaseDir = import_path8.default.resolve(baseCwd);
46668
47651
  const isDependencyPath = directory.startsWith("/dep/") || directory.startsWith("go:") || directory.startsWith("js:") || directory.startsWith("rust:");
46669
47652
  let targetDir;
46670
- if (import_path7.default.isAbsolute(directory)) {
46671
- targetDir = import_path7.default.resolve(directory);
46672
- if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + import_path7.default.sep) && targetDir !== secureBaseDir) {
47653
+ if (import_path8.default.isAbsolute(directory)) {
47654
+ targetDir = import_path8.default.resolve(directory);
47655
+ if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + import_path8.default.sep) && targetDir !== secureBaseDir) {
46673
47656
  throw new Error(`Path traversal attempt detected. Cannot access directory outside workspace: ${directory}`);
46674
47657
  }
46675
47658
  } else {
46676
- targetDir = import_path7.default.resolve(secureBaseDir, directory);
46677
- if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + import_path7.default.sep) && targetDir !== secureBaseDir) {
47659
+ targetDir = import_path8.default.resolve(secureBaseDir, directory);
47660
+ if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + import_path8.default.sep) && targetDir !== secureBaseDir) {
46678
47661
  throw new Error(`Path traversal attempt detected. Access denied: ${directory}`);
46679
47662
  }
46680
47663
  }
@@ -46691,7 +47674,7 @@ var init_probeTool = __esm({
46691
47674
  return `${(size / (1024 * 1024 * 1024)).toFixed(1)}G`;
46692
47675
  };
46693
47676
  const entries = await Promise.all(files.map(async (file) => {
46694
- const fullPath = import_path7.default.join(targetDir, file.name);
47677
+ const fullPath = import_path8.default.join(targetDir, file.name);
46695
47678
  const entryType = await getEntryType(file, fullPath);
46696
47679
  return {
46697
47680
  name: file.name,
@@ -46728,17 +47711,17 @@ var init_probeTool = __esm({
46728
47711
  throw new Error("Pattern is required for file search");
46729
47712
  }
46730
47713
  const baseCwd = workingDirectory || process.cwd();
46731
- const secureBaseDir = import_path7.default.resolve(baseCwd);
47714
+ const secureBaseDir = import_path8.default.resolve(baseCwd);
46732
47715
  const isDependencyPath = directory.startsWith("/dep/") || directory.startsWith("go:") || directory.startsWith("js:") || directory.startsWith("rust:");
46733
47716
  let targetDir;
46734
- if (import_path7.default.isAbsolute(directory)) {
46735
- targetDir = import_path7.default.resolve(directory);
46736
- if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + import_path7.default.sep) && targetDir !== secureBaseDir) {
47717
+ if (import_path8.default.isAbsolute(directory)) {
47718
+ targetDir = import_path8.default.resolve(directory);
47719
+ if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + import_path8.default.sep) && targetDir !== secureBaseDir) {
46737
47720
  throw new Error(`Path traversal attempt detected. Cannot access directory outside workspace: ${directory}`);
46738
47721
  }
46739
47722
  } else {
46740
- targetDir = import_path7.default.resolve(secureBaseDir, directory);
46741
- if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + import_path7.default.sep) && targetDir !== secureBaseDir) {
47723
+ targetDir = import_path8.default.resolve(secureBaseDir, directory);
47724
+ if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + import_path8.default.sep) && targetDir !== secureBaseDir) {
46742
47725
  throw new Error(`Path traversal attempt detected. Access denied: ${directory}`);
46743
47726
  }
46744
47727
  }
@@ -46784,7 +47767,7 @@ function createMockProvider() {
46784
47767
  provider: "mock",
46785
47768
  // Mock the doGenerate method used by Vercel AI SDK
46786
47769
  doGenerate: async ({ messages, tools: tools2 }) => {
46787
- await new Promise((resolve7) => setTimeout(resolve7, 10));
47770
+ await new Promise((resolve8) => setTimeout(resolve8, 10));
46788
47771
  return {
46789
47772
  text: "This is a mock response for testing",
46790
47773
  toolCalls: [],
@@ -51987,23 +52970,23 @@ var init_regexp_parser = __esm({
51987
52970
  return ASSERT_NEVER_REACH_HERE();
51988
52971
  }
51989
52972
  quantifier(isBacktracking = false) {
51990
- let range2 = void 0;
52973
+ let range3 = void 0;
51991
52974
  const begin = this.idx;
51992
52975
  switch (this.popChar()) {
51993
52976
  case "*":
51994
- range2 = {
52977
+ range3 = {
51995
52978
  atLeast: 0,
51996
52979
  atMost: Infinity
51997
52980
  };
51998
52981
  break;
51999
52982
  case "+":
52000
- range2 = {
52983
+ range3 = {
52001
52984
  atLeast: 1,
52002
52985
  atMost: Infinity
52003
52986
  };
52004
52987
  break;
52005
52988
  case "?":
52006
- range2 = {
52989
+ range3 = {
52007
52990
  atLeast: 0,
52008
52991
  atMost: 1
52009
52992
  };
@@ -52012,7 +52995,7 @@ var init_regexp_parser = __esm({
52012
52995
  const atLeast = this.integerIncludingZero();
52013
52996
  switch (this.popChar()) {
52014
52997
  case "}":
52015
- range2 = {
52998
+ range3 = {
52016
52999
  atLeast,
52017
53000
  atMost: atLeast
52018
53001
  };
@@ -52021,12 +53004,12 @@ var init_regexp_parser = __esm({
52021
53004
  let atMost;
52022
53005
  if (this.isDigit()) {
52023
53006
  atMost = this.integerIncludingZero();
52024
- range2 = {
53007
+ range3 = {
52025
53008
  atLeast,
52026
53009
  atMost
52027
53010
  };
52028
53011
  } else {
52029
- range2 = {
53012
+ range3 = {
52030
53013
  atLeast,
52031
53014
  atMost: Infinity
52032
53015
  };
@@ -52034,25 +53017,25 @@ var init_regexp_parser = __esm({
52034
53017
  this.consumeChar("}");
52035
53018
  break;
52036
53019
  }
52037
- if (isBacktracking === true && range2 === void 0) {
53020
+ if (isBacktracking === true && range3 === void 0) {
52038
53021
  return void 0;
52039
53022
  }
52040
- ASSERT_EXISTS(range2);
53023
+ ASSERT_EXISTS(range3);
52041
53024
  break;
52042
53025
  }
52043
- if (isBacktracking === true && range2 === void 0) {
53026
+ if (isBacktracking === true && range3 === void 0) {
52044
53027
  return void 0;
52045
53028
  }
52046
- if (ASSERT_EXISTS(range2)) {
53029
+ if (ASSERT_EXISTS(range3)) {
52047
53030
  if (this.peekChar(0) === "?") {
52048
53031
  this.consumeChar("?");
52049
- range2.greedy = false;
53032
+ range3.greedy = false;
52050
53033
  } else {
52051
- range2.greedy = true;
53034
+ range3.greedy = true;
52052
53035
  }
52053
- range2.type = "Quantifier";
52054
- range2.loc = this.loc(begin);
52055
- return range2;
53036
+ range3.type = "Quantifier";
53037
+ range3.loc = this.loc(begin);
53038
+ return range3;
52056
53039
  }
52057
53040
  }
52058
53041
  atom() {
@@ -52754,18 +53737,18 @@ function firstCharOptimizedIndices(ast, result, ignoreCase) {
52754
53737
  if (typeof code === "number") {
52755
53738
  addOptimizedIdxToResult(code, result, ignoreCase);
52756
53739
  } else {
52757
- const range2 = code;
53740
+ const range3 = code;
52758
53741
  if (ignoreCase === true) {
52759
- for (let rangeCode = range2.from; rangeCode <= range2.to; rangeCode++) {
53742
+ for (let rangeCode = range3.from; rangeCode <= range3.to; rangeCode++) {
52760
53743
  addOptimizedIdxToResult(rangeCode, result, ignoreCase);
52761
53744
  }
52762
53745
  } else {
52763
- for (let rangeCode = range2.from; rangeCode <= range2.to && rangeCode < minOptimizationVal; rangeCode++) {
53746
+ for (let rangeCode = range3.from; rangeCode <= range3.to && rangeCode < minOptimizationVal; rangeCode++) {
52764
53747
  addOptimizedIdxToResult(rangeCode, result, ignoreCase);
52765
53748
  }
52766
- if (range2.to >= minOptimizationVal) {
52767
- const minUnOptVal = range2.from >= minOptimizationVal ? range2.from : minOptimizationVal;
52768
- const maxUnOptVal = range2.to;
53749
+ if (range3.to >= minOptimizationVal) {
53750
+ const minUnOptVal = range3.from >= minOptimizationVal ? range3.from : minOptimizationVal;
53751
+ const maxUnOptVal = range3.to;
52769
53752
  const minOptIdx = charCodeToOptimizedIndex(minUnOptVal);
52770
53753
  const maxOptIdx = charCodeToOptimizedIndex(maxUnOptVal);
52771
53754
  for (let currOptIdx = minOptIdx; currOptIdx <= maxOptIdx; currOptIdx++) {
@@ -52826,8 +53809,8 @@ function findCode(setNode, targetCharCodes) {
52826
53809
  if (typeof codeOrRange === "number") {
52827
53810
  return includes_default(targetCharCodes, codeOrRange);
52828
53811
  } else {
52829
- const range2 = codeOrRange;
52830
- return find_default(targetCharCodes, (targetCode) => range2.from <= targetCode && targetCode <= range2.to) !== void 0;
53812
+ const range3 = codeOrRange;
53813
+ return find_default(targetCharCodes, (targetCode) => range3.from <= targetCode && targetCode <= range3.to) !== void 0;
52831
53814
  }
52832
53815
  });
52833
53816
  }
@@ -70732,8 +71715,8 @@ var require_createRange = __commonJS({
70732
71715
  var require_range = __commonJS({
70733
71716
  "node_modules/lodash/range.js"(exports2, module2) {
70734
71717
  var createRange = require_createRange();
70735
- var range2 = createRange();
70736
- module2.exports = range2;
71718
+ var range3 = createRange();
71719
+ module2.exports = range3;
70737
71720
  }
70738
71721
  });
70739
71722
 
@@ -79974,7 +80957,7 @@ var require_compile = __commonJS({
79974
80957
  const schOrFunc = root2.refs[ref2];
79975
80958
  if (schOrFunc)
79976
80959
  return schOrFunc;
79977
- let _sch = resolve7.call(this, root2, ref2);
80960
+ let _sch = resolve8.call(this, root2, ref2);
79978
80961
  if (_sch === void 0) {
79979
80962
  const schema = (_a16 = root2.localRefs) === null || _a16 === void 0 ? void 0 : _a16[ref2];
79980
80963
  const { schemaId } = this.opts;
@@ -80001,7 +80984,7 @@ var require_compile = __commonJS({
80001
80984
  function sameSchemaEnv(s1, s22) {
80002
80985
  return s1.schema === s22.schema && s1.root === s22.root && s1.baseId === s22.baseId;
80003
80986
  }
80004
- function resolve7(root2, ref2) {
80987
+ function resolve8(root2, ref2) {
80005
80988
  let sch;
80006
80989
  while (typeof (sch = this.refs[ref2]) == "string")
80007
80990
  ref2 = sch;
@@ -80576,7 +81559,7 @@ var require_fast_uri = __commonJS({
80576
81559
  }
80577
81560
  return uri;
80578
81561
  }
80579
- function resolve7(baseURI, relativeURI, options) {
81562
+ function resolve8(baseURI, relativeURI, options) {
80580
81563
  const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
80581
81564
  const resolved = resolveComponent(parse9(baseURI, schemelessOptions), parse9(relativeURI, schemelessOptions), schemelessOptions, true);
80582
81565
  schemelessOptions.skipEscape = true;
@@ -80803,7 +81786,7 @@ var require_fast_uri = __commonJS({
80803
81786
  var fastUri = {
80804
81787
  SCHEMES,
80805
81788
  normalize: normalize3,
80806
- resolve: resolve7,
81789
+ resolve: resolve8,
80807
81790
  resolveComponent,
80808
81791
  equal,
80809
81792
  serialize,
@@ -83498,6 +84481,7 @@ __export(schemaUtils_exports, {
83498
84481
  replaceMermaidDiagramsInMarkdown: () => replaceMermaidDiagramsInMarkdown,
83499
84482
  sanitizeMarkdownEscapesInJson: () => sanitizeMarkdownEscapesInJson,
83500
84483
  tryAutoWrapForSimpleSchema: () => tryAutoWrapForSimpleSchema,
84484
+ tryExtractValidJsonPrefix: () => tryExtractValidJsonPrefix,
83501
84485
  tryMaidAutoFix: () => tryMaidAutoFix,
83502
84486
  validateAndFixMermaidResponse: () => validateAndFixMermaidResponse,
83503
84487
  validateJsonResponse: () => validateJsonResponse,
@@ -83884,6 +84868,13 @@ function validateJsonResponse(response, options = {}) {
83884
84868
  errorPosition = response.indexOf(problematicToken);
83885
84869
  }
83886
84870
  }
84871
+ const prefixResult = tryExtractValidJsonPrefix(responseToValidate, { schema, debug });
84872
+ if (prefixResult && prefixResult.isValid) {
84873
+ if (debug) {
84874
+ console.log(`[DEBUG] JSON validation: Recovered valid JSON prefix (${prefixResult.extracted.length} chars) from response with trailing content`);
84875
+ }
84876
+ return { isValid: true, parsed: prefixResult.parsed };
84877
+ }
83887
84878
  let enhancedError = error2.message;
83888
84879
  let errorContext = null;
83889
84880
  if (errorPosition !== null && errorPosition >= 0 && response && response.length > 0) {
@@ -83934,6 +84925,84 @@ ${errorContext.pointer}`);
83934
84925
  };
83935
84926
  }
83936
84927
  }
84928
+ function tryExtractValidJsonPrefix(response, options = {}) {
84929
+ const { schema = null, debug = false } = options;
84930
+ if (!response || typeof response !== "string") {
84931
+ return null;
84932
+ }
84933
+ const trimmed = response.trim();
84934
+ if (trimmed.length === 0) {
84935
+ return null;
84936
+ }
84937
+ const firstChar = trimmed[0];
84938
+ if (firstChar !== "{" && firstChar !== "[") {
84939
+ return null;
84940
+ }
84941
+ try {
84942
+ JSON.parse(trimmed);
84943
+ return null;
84944
+ } catch {
84945
+ }
84946
+ const openChar = firstChar;
84947
+ const closeChar = openChar === "{" ? "}" : "]";
84948
+ let depth = 0;
84949
+ let inString = false;
84950
+ let escapeNext = false;
84951
+ let endPos = -1;
84952
+ for (let i5 = 0; i5 < trimmed.length; i5++) {
84953
+ const char = trimmed[i5];
84954
+ if (escapeNext) {
84955
+ escapeNext = false;
84956
+ continue;
84957
+ }
84958
+ if (char === "\\" && inString) {
84959
+ escapeNext = true;
84960
+ continue;
84961
+ }
84962
+ if (char === '"') {
84963
+ inString = !inString;
84964
+ continue;
84965
+ }
84966
+ if (inString) {
84967
+ continue;
84968
+ }
84969
+ if (char === openChar) {
84970
+ depth++;
84971
+ } else if (char === closeChar) {
84972
+ depth--;
84973
+ if (depth === 0) {
84974
+ endPos = i5 + 1;
84975
+ break;
84976
+ }
84977
+ }
84978
+ }
84979
+ if (endPos <= 0 || endPos >= trimmed.length) {
84980
+ return null;
84981
+ }
84982
+ const remainder = trimmed.substring(endPos).trim();
84983
+ if (remainder.length === 0) {
84984
+ return null;
84985
+ }
84986
+ const prefix = trimmed.substring(0, endPos);
84987
+ try {
84988
+ const parsed = JSON.parse(prefix);
84989
+ if (debug) {
84990
+ console.log(`[DEBUG] tryExtractValidJsonPrefix: Extracted valid JSON prefix (${prefix.length} chars), stripped trailing content (${remainder.length} chars)`);
84991
+ }
84992
+ if (schema) {
84993
+ const schemaValidation = validateJsonResponse(prefix, { debug, schema });
84994
+ if (!schemaValidation.isValid) {
84995
+ if (debug) {
84996
+ console.log(`[DEBUG] tryExtractValidJsonPrefix: Prefix is valid JSON but fails schema validation: ${schemaValidation.error}`);
84997
+ }
84998
+ return null;
84999
+ }
85000
+ }
85001
+ return { isValid: true, parsed, extracted: prefix };
85002
+ } catch {
85003
+ return null;
85004
+ }
85005
+ }
83937
85006
  function validateXmlResponse(response) {
83938
85007
  const xmlPattern = /<\/?[\w\s="'.-]+>/g;
83939
85008
  const tags = response.match(xmlPattern);
@@ -85326,13 +86395,13 @@ function loadMCPConfiguration() {
85326
86395
  // Environment variable path
85327
86396
  process.env.MCP_CONFIG_PATH,
85328
86397
  // Local project paths
85329
- (0, import_path8.join)(process.cwd(), ".mcp", "config.json"),
85330
- (0, import_path8.join)(process.cwd(), "mcp.config.json"),
86398
+ (0, import_path9.join)(process.cwd(), ".mcp", "config.json"),
86399
+ (0, import_path9.join)(process.cwd(), "mcp.config.json"),
85331
86400
  // Home directory paths
85332
- (0, import_path8.join)((0, import_os3.homedir)(), ".config", "probe", "mcp.json"),
85333
- (0, import_path8.join)((0, import_os3.homedir)(), ".mcp", "config.json"),
86401
+ (0, import_path9.join)((0, import_os3.homedir)(), ".config", "probe", "mcp.json"),
86402
+ (0, import_path9.join)((0, import_os3.homedir)(), ".mcp", "config.json"),
85334
86403
  // Claude-style config location
85335
- (0, import_path8.join)((0, import_os3.homedir)(), "Library", "Application Support", "Claude", "mcp_config.json")
86404
+ (0, import_path9.join)((0, import_os3.homedir)(), "Library", "Application Support", "Claude", "mcp_config.json")
85336
86405
  ].filter(Boolean);
85337
86406
  let config = null;
85338
86407
  for (const configPath of configPaths) {
@@ -85459,16 +86528,16 @@ function parseEnabledServers(config) {
85459
86528
  }
85460
86529
  return servers;
85461
86530
  }
85462
- var import_fs9, import_path8, import_os3, import_url4, __filename4, __dirname4, DEFAULT_TIMEOUT, MAX_TIMEOUT, DEFAULT_CONFIG;
86531
+ var import_fs9, import_path9, import_os3, import_url4, __filename4, __dirname4, DEFAULT_TIMEOUT, MAX_TIMEOUT, DEFAULT_CONFIG;
85463
86532
  var init_config = __esm({
85464
86533
  "src/agent/mcp/config.js"() {
85465
86534
  "use strict";
85466
86535
  import_fs9 = require("fs");
85467
- import_path8 = require("path");
86536
+ import_path9 = require("path");
85468
86537
  import_os3 = require("os");
85469
86538
  import_url4 = require("url");
85470
86539
  __filename4 = (0, import_url4.fileURLToPath)("file:///");
85471
- __dirname4 = (0, import_path8.dirname)(__filename4);
86540
+ __dirname4 = (0, import_path9.dirname)(__filename4);
85472
86541
  DEFAULT_TIMEOUT = 3e4;
85473
86542
  MAX_TIMEOUT = (() => {
85474
86543
  if (process.env.MCP_MAX_TIMEOUT) {
@@ -85482,7 +86551,7 @@ var init_config = __esm({
85482
86551
  // Example probe server configuration
85483
86552
  "probe-local": {
85484
86553
  command: "node",
85485
- args: [(0, import_path8.join)(__dirname4, "../../../examples/chat/mcpServer.js")],
86554
+ args: [(0, import_path9.join)(__dirname4, "../../../examples/chat/mcpServer.js")],
85486
86555
  transport: "stdio",
85487
86556
  enabled: false
85488
86557
  },
@@ -86035,7 +87104,7 @@ function parseXmlMcpToolCall(xmlString, mcpToolNames = []) {
86035
87104
  let match2;
86036
87105
  while ((match2 = paramPattern.exec(content)) !== null) {
86037
87106
  const [, paramName, paramValue] = match2;
86038
- params[paramName] = paramValue.trim();
87107
+ params[paramName] = unescapeXmlEntities(paramValue.trim());
86039
87108
  }
86040
87109
  }
86041
87110
  return { toolName, params };
@@ -86085,7 +87154,7 @@ function parseNativeXmlTool(xmlString, toolName) {
86085
87154
  while ((match2 = paramPattern.exec(content)) !== null) {
86086
87155
  const [, paramName, paramValue] = match2;
86087
87156
  if (paramName !== "params") {
86088
- params[paramName] = paramValue.trim();
87157
+ params[paramName] = unescapeXmlEntities(paramValue.trim());
86089
87158
  }
86090
87159
  }
86091
87160
  if (Object.keys(params).length > 0) {
@@ -86100,6 +87169,7 @@ var init_xmlBridge = __esm({
86100
87169
  init_client2();
86101
87170
  init_config();
86102
87171
  init_xmlParsingUtils();
87172
+ init_common2();
86103
87173
  MCPXmlBridge = class {
86104
87174
  constructor(options = {}) {
86105
87175
  this.debug = options.debug || false;
@@ -91065,7 +92135,7 @@ var require_compose_scalar = __commonJS({
91065
92135
  var resolveBlockScalar = require_resolve_block_scalar();
91066
92136
  var resolveFlowScalar = require_resolve_flow_scalar();
91067
92137
  function composeScalar(ctx, token, tagToken, onError) {
91068
- const { value, type, comment, range: range2 } = token.type === "block-scalar" ? resolveBlockScalar.resolveBlockScalar(ctx, token, onError) : resolveFlowScalar.resolveFlowScalar(token, ctx.options.strict, onError);
92138
+ const { value, type, comment, range: range3 } = token.type === "block-scalar" ? resolveBlockScalar.resolveBlockScalar(ctx, token, onError) : resolveFlowScalar.resolveFlowScalar(token, ctx.options.strict, onError);
91069
92139
  const tagName = tagToken ? ctx.directives.tagName(tagToken.source, (msg) => onError(tagToken, "TAG_RESOLVE_FAILED", msg)) : null;
91070
92140
  let tag2;
91071
92141
  if (ctx.options.stringKeys && ctx.atKey) {
@@ -91085,7 +92155,7 @@ var require_compose_scalar = __commonJS({
91085
92155
  onError(tagToken ?? token, "TAG_RESOLVE_FAILED", msg);
91086
92156
  scalar = new Scalar.Scalar(value);
91087
92157
  }
91088
- scalar.range = range2;
92158
+ scalar.range = range3;
91089
92159
  scalar.source = value;
91090
92160
  if (type)
91091
92161
  scalar.type = type;
@@ -93676,17 +94746,17 @@ async function parseSkillFile(skillFilePath, directoryName) {
93676
94746
  description,
93677
94747
  skillFilePath,
93678
94748
  directoryName,
93679
- sourceDir: (0, import_path9.dirname)(skillFilePath)
94749
+ sourceDir: (0, import_path10.dirname)(skillFilePath)
93680
94750
  },
93681
94751
  error: null
93682
94752
  };
93683
94753
  }
93684
- var import_promises2, import_path9, import_yaml, SKILL_NAME_REGEX, MAX_SKILL_NAME_LENGTH, MAX_DESCRIPTION_CHARS;
94754
+ var import_promises2, import_path10, import_yaml, SKILL_NAME_REGEX, MAX_SKILL_NAME_LENGTH, MAX_DESCRIPTION_CHARS;
93685
94755
  var init_parser7 = __esm({
93686
94756
  "src/agent/skills/parser.js"() {
93687
94757
  "use strict";
93688
94758
  import_promises2 = require("fs/promises");
93689
- import_path9 = require("path");
94759
+ import_path10 = require("path");
93690
94760
  import_yaml = __toESM(require_dist(), 1);
93691
94761
  SKILL_NAME_REGEX = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
93692
94762
  MAX_SKILL_NAME_LENGTH = 64;
@@ -93696,12 +94766,12 @@ var init_parser7 = __esm({
93696
94766
 
93697
94767
  // src/agent/skills/registry.js
93698
94768
  function isPathInside(basePath, targetPath) {
93699
- const base2 = (0, import_path10.resolve)(basePath);
93700
- const target = (0, import_path10.resolve)(targetPath);
93701
- const rel = (0, import_path10.relative)(base2, target);
94769
+ const base2 = (0, import_path11.resolve)(basePath);
94770
+ const target = (0, import_path11.resolve)(targetPath);
94771
+ const rel = (0, import_path11.relative)(base2, target);
93702
94772
  if (rel === "") return true;
93703
- if (rel === ".." || rel.startsWith(`..${import_path10.sep}`)) return false;
93704
- if ((0, import_path10.isAbsolute)(rel)) return false;
94773
+ if (rel === ".." || rel.startsWith(`..${import_path11.sep}`)) return false;
94774
+ if ((0, import_path11.isAbsolute)(rel)) return false;
93705
94775
  return true;
93706
94776
  }
93707
94777
  function isSafeEntryName(name14) {
@@ -93709,19 +94779,19 @@ function isSafeEntryName(name14) {
93709
94779
  if (name14.includes("\0")) return false;
93710
94780
  return !name14.includes("/") && !name14.includes("\\");
93711
94781
  }
93712
- var import_fs10, import_promises3, import_path10, DEFAULT_SKILL_DIRS, SKILL_FILE_NAME, SkillRegistry;
94782
+ var import_fs10, import_promises3, import_path11, DEFAULT_SKILL_DIRS, SKILL_FILE_NAME, SkillRegistry;
93713
94783
  var init_registry = __esm({
93714
94784
  "src/agent/skills/registry.js"() {
93715
94785
  "use strict";
93716
94786
  import_fs10 = require("fs");
93717
94787
  import_promises3 = require("fs/promises");
93718
- import_path10 = require("path");
94788
+ import_path11 = require("path");
93719
94789
  init_parser7();
93720
94790
  DEFAULT_SKILL_DIRS = [".claude/skills", ".codex/skills", "skills", ".skills"];
93721
94791
  SKILL_FILE_NAME = "SKILL.md";
93722
94792
  SkillRegistry = class {
93723
94793
  constructor({ repoRoot, skillDirs = DEFAULT_SKILL_DIRS, debug = false } = {}) {
93724
- this.repoRoot = repoRoot ? (0, import_path10.resolve)(repoRoot) : process.cwd();
94794
+ this.repoRoot = repoRoot ? (0, import_path11.resolve)(repoRoot) : process.cwd();
93725
94795
  this.repoRootReal = null;
93726
94796
  this.skillDirs = Array.isArray(skillDirs) && skillDirs.length > 0 ? skillDirs : DEFAULT_SKILL_DIRS;
93727
94797
  this.debug = debug;
@@ -93775,8 +94845,8 @@ var init_registry = __esm({
93775
94845
  }
93776
94846
  }
93777
94847
  async _resolveSkillDir(skillDir) {
93778
- const resolved = (0, import_path10.isAbsolute)(skillDir) ? (0, import_path10.resolve)(skillDir) : (0, import_path10.resolve)(this.repoRoot, skillDir);
93779
- const repoRoot = this.repoRootReal || (0, import_path10.resolve)(this.repoRoot);
94848
+ const resolved = (0, import_path11.isAbsolute)(skillDir) ? (0, import_path11.resolve)(skillDir) : (0, import_path11.resolve)(this.repoRoot, skillDir);
94849
+ const repoRoot = this.repoRootReal || (0, import_path11.resolve)(this.repoRoot);
93780
94850
  const resolvedReal = await this._resolveRealPath(resolved);
93781
94851
  if (!resolvedReal) return null;
93782
94852
  if (!isPathInside(repoRoot, resolvedReal)) {
@@ -93807,8 +94877,8 @@ var init_registry = __esm({
93807
94877
  }
93808
94878
  continue;
93809
94879
  }
93810
- const skillFolder = (0, import_path10.join)(dirPath, entry.name);
93811
- const skillFilePath = (0, import_path10.join)(skillFolder, SKILL_FILE_NAME);
94880
+ const skillFolder = (0, import_path11.join)(dirPath, entry.name);
94881
+ const skillFilePath = (0, import_path11.join)(skillFolder, SKILL_FILE_NAME);
93812
94882
  let skillStat;
93813
94883
  try {
93814
94884
  skillStat = await (0, import_promises3.lstat)(skillFilePath);
@@ -93966,7 +95036,7 @@ function extractErrorInfo(error2) {
93966
95036
  };
93967
95037
  }
93968
95038
  function sleep(ms) {
93969
- return new Promise((resolve7) => setTimeout(resolve7, ms));
95039
+ return new Promise((resolve8) => setTimeout(resolve8, ms));
93970
95040
  }
93971
95041
  var DEFAULT_RETRYABLE_ERRORS, RetryManager;
93972
95042
  var init_RetryManager = __esm({
@@ -94746,9 +95816,9 @@ async function truncateIfNeeded(content, tokenCounter, sessionId, maxTokens) {
94746
95816
  let tempFilePath = null;
94747
95817
  let fileError = null;
94748
95818
  try {
94749
- const tempDir = (0, import_path11.join)((0, import_os4.tmpdir)(), "probe-output");
95819
+ const tempDir = (0, import_path12.join)((0, import_os4.tmpdir)(), "probe-output");
94750
95820
  await (0, import_promises4.mkdir)(tempDir, { recursive: true });
94751
- tempFilePath = (0, import_path11.join)(tempDir, `tool-output-${sessionId || "unknown"}-${(0, import_crypto4.randomUUID)()}.txt`);
95821
+ tempFilePath = (0, import_path12.join)(tempDir, `tool-output-${sessionId || "unknown"}-${(0, import_crypto5.randomUUID)()}.txt`);
94752
95822
  await (0, import_promises4.writeFile)(tempFilePath, content, "utf8");
94753
95823
  } catch (err) {
94754
95824
  fileError = err.message || "Unknown file system error";
@@ -94796,14 +95866,14 @@ ${truncatedBody}
94796
95866
  error: fileError || void 0
94797
95867
  };
94798
95868
  }
94799
- var import_promises4, import_os4, import_path11, import_crypto4, DEFAULT_MAX_OUTPUT_TOKENS, CHARS_PER_TOKEN, TAIL_TOKENS, MIN_LIMIT_FOR_TAIL;
95869
+ var import_promises4, import_os4, import_path12, import_crypto5, DEFAULT_MAX_OUTPUT_TOKENS, CHARS_PER_TOKEN, TAIL_TOKENS, MIN_LIMIT_FOR_TAIL;
94800
95870
  var init_outputTruncator = __esm({
94801
95871
  "src/agent/outputTruncator.js"() {
94802
95872
  "use strict";
94803
95873
  import_promises4 = require("fs/promises");
94804
95874
  import_os4 = require("os");
94805
- import_path11 = require("path");
94806
- import_crypto4 = require("crypto");
95875
+ import_path12 = require("path");
95876
+ import_crypto5 = require("crypto");
94807
95877
  DEFAULT_MAX_OUTPUT_TOKENS = 2e4;
94808
95878
  CHARS_PER_TOKEN = 4;
94809
95879
  TAIL_TOKENS = 1e3;
@@ -95925,14 +96995,14 @@ var require_executor = __commonJS({
95925
96995
  function asyncDone(callback) {
95926
96996
  let isInstant = false;
95927
96997
  let instant;
95928
- const p5 = new Promise((resolve7, reject2) => {
96998
+ const p5 = new Promise((resolve8, reject2) => {
95929
96999
  callback((err, result) => {
95930
97000
  if (err)
95931
97001
  reject2(err);
95932
97002
  else {
95933
97003
  isInstant = true;
95934
97004
  instant = result;
95935
- resolve7({ result });
97005
+ resolve8({ result });
95936
97006
  }
95937
97007
  });
95938
97008
  });
@@ -95955,10 +97025,10 @@ var require_executor = __commonJS({
95955
97025
  }
95956
97026
  async function execAsync4(ticks, tree, scope, context, doneOriginal, inLoopOrSwitch) {
95957
97027
  let done = doneOriginal;
95958
- const p5 = new Promise((resolve7) => {
97028
+ const p5 = new Promise((resolve8) => {
95959
97029
  done = (e5, r5) => {
95960
97030
  doneOriginal(e5, r5);
95961
- resolve7();
97031
+ resolve8();
95962
97032
  };
95963
97033
  });
95964
97034
  if (!_execNoneRecurse(ticks, tree, scope, context, done, true, inLoopOrSwitch) && utils.isLisp(tree)) {
@@ -104796,6 +105866,7 @@ var init_bashDefaults = __esm({
104796
105866
  "tree:*",
104797
105867
  // Git read-only operations
104798
105868
  "git:status",
105869
+ "git:status:*",
104799
105870
  "git:log",
104800
105871
  "git:log:*",
104801
105872
  "git:diff",
@@ -104814,14 +105885,109 @@ var init_bashDefaults = __esm({
104814
105885
  "git:blame",
104815
105886
  "git:blame:*",
104816
105887
  "git:shortlog",
105888
+ "git:shortlog:*",
104817
105889
  "git:reflog",
105890
+ "git:reflog:*",
104818
105891
  "git:ls-files",
105892
+ "git:ls-files:*",
104819
105893
  "git:ls-tree",
105894
+ "git:ls-tree:*",
105895
+ "git:ls-remote",
105896
+ "git:ls-remote:*",
104820
105897
  "git:rev-parse",
105898
+ "git:rev-parse:*",
104821
105899
  "git:rev-list",
105900
+ "git:rev-list:*",
105901
+ "git:cat-file",
105902
+ "git:cat-file:*",
105903
+ "git:diff-tree",
105904
+ "git:diff-tree:*",
105905
+ "git:diff-files",
105906
+ "git:diff-files:*",
105907
+ "git:diff-index",
105908
+ "git:diff-index:*",
105909
+ "git:for-each-ref",
105910
+ "git:for-each-ref:*",
105911
+ "git:merge-base",
105912
+ "git:merge-base:*",
105913
+ "git:name-rev",
105914
+ "git:name-rev:*",
105915
+ "git:count-objects",
105916
+ "git:count-objects:*",
105917
+ "git:verify-commit",
105918
+ "git:verify-commit:*",
105919
+ "git:verify-tag",
105920
+ "git:verify-tag:*",
105921
+ "git:check-ignore",
105922
+ "git:check-ignore:*",
105923
+ "git:check-attr",
105924
+ "git:check-attr:*",
105925
+ "git:stash:list",
105926
+ "git:stash:show",
105927
+ "git:stash:show:*",
105928
+ "git:worktree:list",
105929
+ "git:worktree:list:*",
105930
+ "git:notes:list",
105931
+ "git:notes:show",
105932
+ "git:notes:show:*",
104822
105933
  "git:--version",
104823
105934
  "git:help",
104824
105935
  "git:help:*",
105936
+ // GitHub CLI (gh) read-only operations
105937
+ "gh:--version",
105938
+ "gh:help",
105939
+ "gh:help:*",
105940
+ "gh:status",
105941
+ "gh:auth:status",
105942
+ "gh:auth:status:*",
105943
+ "gh:issue:list",
105944
+ "gh:issue:list:*",
105945
+ "gh:issue:view",
105946
+ "gh:issue:view:*",
105947
+ "gh:issue:status",
105948
+ "gh:issue:status:*",
105949
+ "gh:pr:list",
105950
+ "gh:pr:list:*",
105951
+ "gh:pr:view",
105952
+ "gh:pr:view:*",
105953
+ "gh:pr:status",
105954
+ "gh:pr:status:*",
105955
+ "gh:pr:diff",
105956
+ "gh:pr:diff:*",
105957
+ "gh:pr:checks",
105958
+ "gh:pr:checks:*",
105959
+ "gh:repo:list",
105960
+ "gh:repo:list:*",
105961
+ "gh:repo:view",
105962
+ "gh:repo:view:*",
105963
+ "gh:release:list",
105964
+ "gh:release:list:*",
105965
+ "gh:release:view",
105966
+ "gh:release:view:*",
105967
+ "gh:run:list",
105968
+ "gh:run:list:*",
105969
+ "gh:run:view",
105970
+ "gh:run:view:*",
105971
+ "gh:workflow:list",
105972
+ "gh:workflow:list:*",
105973
+ "gh:workflow:view",
105974
+ "gh:workflow:view:*",
105975
+ "gh:gist:list",
105976
+ "gh:gist:list:*",
105977
+ "gh:gist:view",
105978
+ "gh:gist:view:*",
105979
+ "gh:search:issues",
105980
+ "gh:search:issues:*",
105981
+ "gh:search:prs",
105982
+ "gh:search:prs:*",
105983
+ "gh:search:repos",
105984
+ "gh:search:repos:*",
105985
+ "gh:search:code",
105986
+ "gh:search:code:*",
105987
+ "gh:search:commits",
105988
+ "gh:search:commits:*",
105989
+ "gh:api",
105990
+ "gh:api:*",
104825
105991
  // Package managers (information only)
104826
105992
  "npm:list",
104827
105993
  "npm:ls",
@@ -105132,14 +106298,132 @@ var init_bashDefaults = __esm({
105132
106298
  "git:push",
105133
106299
  "git:push:*",
105134
106300
  "git:force",
105135
- "git:reset:--hard:*",
105136
- "git:clean:-fd",
106301
+ "git:reset",
106302
+ "git:reset:*",
106303
+ "git:clean",
106304
+ "git:clean:*",
106305
+ "git:rm",
105137
106306
  "git:rm:*",
105138
106307
  "git:commit",
106308
+ "git:commit:*",
105139
106309
  "git:merge",
106310
+ "git:merge:*",
105140
106311
  "git:rebase",
106312
+ "git:rebase:*",
105141
106313
  "git:cherry-pick",
106314
+ "git:cherry-pick:*",
105142
106315
  "git:stash:drop",
106316
+ "git:stash:drop:*",
106317
+ "git:stash:pop",
106318
+ "git:stash:pop:*",
106319
+ "git:stash:push",
106320
+ "git:stash:push:*",
106321
+ "git:stash:clear",
106322
+ "git:branch:-d",
106323
+ "git:branch:-d:*",
106324
+ "git:branch:-D",
106325
+ "git:branch:-D:*",
106326
+ "git:branch:--delete",
106327
+ "git:branch:--delete:*",
106328
+ "git:tag:-d",
106329
+ "git:tag:-d:*",
106330
+ "git:tag:--delete",
106331
+ "git:tag:--delete:*",
106332
+ "git:remote:remove",
106333
+ "git:remote:remove:*",
106334
+ "git:remote:rm",
106335
+ "git:remote:rm:*",
106336
+ "git:checkout:--force",
106337
+ "git:checkout:--force:*",
106338
+ "git:checkout:-f",
106339
+ "git:checkout:-f:*",
106340
+ "git:submodule:deinit",
106341
+ "git:submodule:deinit:*",
106342
+ "git:notes:add",
106343
+ "git:notes:add:*",
106344
+ "git:notes:remove",
106345
+ "git:notes:remove:*",
106346
+ "git:worktree:add",
106347
+ "git:worktree:add:*",
106348
+ "git:worktree:remove",
106349
+ "git:worktree:remove:*",
106350
+ // Dangerous GitHub CLI (gh) write operations
106351
+ "gh:issue:create",
106352
+ "gh:issue:create:*",
106353
+ "gh:issue:close",
106354
+ "gh:issue:close:*",
106355
+ "gh:issue:delete",
106356
+ "gh:issue:delete:*",
106357
+ "gh:issue:edit",
106358
+ "gh:issue:edit:*",
106359
+ "gh:issue:reopen",
106360
+ "gh:issue:reopen:*",
106361
+ "gh:issue:comment",
106362
+ "gh:issue:comment:*",
106363
+ "gh:pr:create",
106364
+ "gh:pr:create:*",
106365
+ "gh:pr:close",
106366
+ "gh:pr:close:*",
106367
+ "gh:pr:merge",
106368
+ "gh:pr:merge:*",
106369
+ "gh:pr:edit",
106370
+ "gh:pr:edit:*",
106371
+ "gh:pr:reopen",
106372
+ "gh:pr:reopen:*",
106373
+ "gh:pr:review",
106374
+ "gh:pr:review:*",
106375
+ "gh:pr:comment",
106376
+ "gh:pr:comment:*",
106377
+ "gh:repo:create",
106378
+ "gh:repo:create:*",
106379
+ "gh:repo:delete",
106380
+ "gh:repo:delete:*",
106381
+ "gh:repo:fork",
106382
+ "gh:repo:fork:*",
106383
+ "gh:repo:rename",
106384
+ "gh:repo:rename:*",
106385
+ "gh:repo:archive",
106386
+ "gh:repo:archive:*",
106387
+ "gh:repo:clone",
106388
+ "gh:repo:clone:*",
106389
+ "gh:release:create",
106390
+ "gh:release:create:*",
106391
+ "gh:release:delete",
106392
+ "gh:release:delete:*",
106393
+ "gh:release:edit",
106394
+ "gh:release:edit:*",
106395
+ "gh:run:cancel",
106396
+ "gh:run:cancel:*",
106397
+ "gh:run:rerun",
106398
+ "gh:run:rerun:*",
106399
+ "gh:workflow:run",
106400
+ "gh:workflow:run:*",
106401
+ "gh:workflow:enable",
106402
+ "gh:workflow:enable:*",
106403
+ "gh:workflow:disable",
106404
+ "gh:workflow:disable:*",
106405
+ "gh:gist:create",
106406
+ "gh:gist:create:*",
106407
+ "gh:gist:delete",
106408
+ "gh:gist:delete:*",
106409
+ "gh:gist:edit",
106410
+ "gh:gist:edit:*",
106411
+ "gh:secret:set",
106412
+ "gh:secret:set:*",
106413
+ "gh:secret:delete",
106414
+ "gh:secret:delete:*",
106415
+ "gh:variable:set",
106416
+ "gh:variable:set:*",
106417
+ "gh:variable:delete",
106418
+ "gh:variable:delete:*",
106419
+ "gh:label:create",
106420
+ "gh:label:create:*",
106421
+ "gh:label:delete",
106422
+ "gh:label:delete:*",
106423
+ "gh:ssh-key:add",
106424
+ "gh:ssh-key:add:*",
106425
+ "gh:ssh-key:delete",
106426
+ "gh:ssh-key:delete:*",
105143
106427
  // File system mounting and partitioning
105144
106428
  "mount",
105145
106429
  "mount:*",
@@ -105922,7 +107206,7 @@ async function executeBashCommand(command, options = {}) {
105922
107206
  } = options;
105923
107207
  let cwd = workingDirectory;
105924
107208
  try {
105925
- cwd = (0, import_path12.resolve)(cwd);
107209
+ cwd = (0, import_path13.resolve)(cwd);
105926
107210
  if (!(0, import_fs11.existsSync)(cwd)) {
105927
107211
  throw new Error(`Working directory does not exist: ${cwd}`);
105928
107212
  }
@@ -105944,7 +107228,7 @@ async function executeBashCommand(command, options = {}) {
105944
107228
  console.log(`[BashExecutor] Working directory: "${cwd}"`);
105945
107229
  console.log(`[BashExecutor] Timeout: ${timeout}ms`);
105946
107230
  }
105947
- return new Promise((resolve7, reject2) => {
107231
+ return new Promise((resolve8, reject2) => {
105948
107232
  const processEnv = {
105949
107233
  ...process.env,
105950
107234
  ...env
@@ -105961,7 +107245,7 @@ async function executeBashCommand(command, options = {}) {
105961
107245
  } else {
105962
107246
  const args = parseCommandForExecution(command);
105963
107247
  if (!args || args.length === 0) {
105964
- resolve7({
107248
+ resolve8({
105965
107249
  success: false,
105966
107250
  error: "Failed to parse command",
105967
107251
  stdout: "",
@@ -106046,7 +107330,7 @@ async function executeBashCommand(command, options = {}) {
106046
107330
  success = false;
106047
107331
  error2 = `Command exited with code ${code}`;
106048
107332
  }
106049
- resolve7({
107333
+ resolve8({
106050
107334
  success,
106051
107335
  error: error2,
106052
107336
  stdout: stdout.trim(),
@@ -106066,7 +107350,7 @@ async function executeBashCommand(command, options = {}) {
106066
107350
  if (debug) {
106067
107351
  console.log(`[BashExecutor] Spawn error:`, error2);
106068
107352
  }
106069
- resolve7({
107353
+ resolve8({
106070
107354
  success: false,
106071
107355
  error: `Failed to execute command: ${error2.message}`,
106072
107356
  stdout: "",
@@ -106160,24 +107444,24 @@ function validateExecutionOptions(options = {}) {
106160
107444
  warnings
106161
107445
  };
106162
107446
  }
106163
- var import_child_process7, import_path12, import_fs11;
107447
+ var import_child_process7, import_path13, import_fs11;
106164
107448
  var init_bashExecutor = __esm({
106165
107449
  "src/agent/bashExecutor.js"() {
106166
107450
  "use strict";
106167
107451
  import_child_process7 = require("child_process");
106168
- import_path12 = require("path");
107452
+ import_path13 = require("path");
106169
107453
  import_fs11 = require("fs");
106170
107454
  init_bashCommandUtils();
106171
107455
  }
106172
107456
  });
106173
107457
 
106174
107458
  // src/tools/bash.js
106175
- var import_ai2, import_path13, bashTool;
107459
+ var import_ai2, import_path14, bashTool;
106176
107460
  var init_bash = __esm({
106177
107461
  "src/tools/bash.js"() {
106178
107462
  "use strict";
106179
107463
  import_ai2 = require("ai");
106180
- import_path13 = require("path");
107464
+ import_path14 = require("path");
106181
107465
  init_bashPermissions();
106182
107466
  init_bashExecutor();
106183
107467
  init_path_validation();
@@ -106294,12 +107578,12 @@ For code exploration, try these safe alternatives:
106294
107578
  - npm list, pip list for package information`;
106295
107579
  }
106296
107580
  const defaultDir = getDefaultWorkingDirectory();
106297
- const workingDir = workingDirectory ? (0, import_path13.isAbsolute)(workingDirectory) ? (0, import_path13.resolve)(workingDirectory) : (0, import_path13.resolve)(defaultDir, workingDirectory) : defaultDir;
107581
+ const workingDir = workingDirectory ? (0, import_path14.isAbsolute)(workingDirectory) ? (0, import_path14.resolve)(workingDirectory) : (0, import_path14.resolve)(defaultDir, workingDirectory) : defaultDir;
106298
107582
  if (allowedFolders && allowedFolders.length > 0) {
106299
107583
  const resolvedWorkingDir = safeRealpath(workingDir);
106300
107584
  const isAllowed = allowedFolders.some((folder) => {
106301
107585
  const resolvedFolder = safeRealpath(folder);
106302
- return resolvedWorkingDir === resolvedFolder || resolvedWorkingDir.startsWith(resolvedFolder + import_path13.sep);
107586
+ return resolvedWorkingDir === resolvedFolder || resolvedWorkingDir.startsWith(resolvedFolder + import_path14.sep);
106303
107587
  });
106304
107588
  if (!isAllowed) {
106305
107589
  const relativeDir = toRelativePath(workingDir, workspaceRoot);
@@ -107278,7 +108562,7 @@ var init_executePlan = __esm({
107278
108562
  init_query();
107279
108563
  init_extract();
107280
108564
  init_delegate();
107281
- init_esm5();
108565
+ init_esm7();
107282
108566
  init_bash();
107283
108567
  RAW_OUTPUT_START = "<<<RAW_OUTPUT>>>";
107284
108568
  RAW_OUTPUT_END = "<<<END_RAW_OUTPUT>>>";
@@ -107286,13 +108570,13 @@ var init_executePlan = __esm({
107286
108570
  });
107287
108571
 
107288
108572
  // src/agent/mcp/built-in-server.js
107289
- var import_http, import_events2, import_crypto5, import_server, import_sse2, import_streamableHttp, import_types3, InMemoryEventStore, BuiltInMCPServer;
108573
+ var import_http, import_events2, import_crypto6, import_server, import_sse2, import_streamableHttp, import_types3, InMemoryEventStore, BuiltInMCPServer;
107290
108574
  var init_built_in_server = __esm({
107291
108575
  "src/agent/mcp/built-in-server.js"() {
107292
108576
  "use strict";
107293
108577
  import_http = require("http");
107294
108578
  import_events2 = require("events");
107295
- import_crypto5 = require("crypto");
108579
+ import_crypto6 = require("crypto");
107296
108580
  import_server = require("@modelcontextprotocol/sdk/server/index.js");
107297
108581
  import_sse2 = require("@modelcontextprotocol/sdk/server/sse.js");
107298
108582
  import_streamableHttp = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
@@ -107368,7 +108652,7 @@ var init_built_in_server = __esm({
107368
108652
  }
107369
108653
  });
107370
108654
  this.registerHandlers();
107371
- return new Promise((resolve7, reject2) => {
108655
+ return new Promise((resolve8, reject2) => {
107372
108656
  this.httpServer.listen(this.port, this.host, async () => {
107373
108657
  const address = this.httpServer.address();
107374
108658
  this.port = address.port;
@@ -107378,7 +108662,7 @@ var init_built_in_server = __esm({
107378
108662
  console.log(`[MCP] Messages endpoint: http://${this.host}:${this.port}/messages`);
107379
108663
  }
107380
108664
  this.emit("ready", { host: this.host, port: this.port });
107381
- resolve7({ host: this.host, port: this.port });
108665
+ resolve8({ host: this.host, port: this.port });
107382
108666
  });
107383
108667
  this.httpServer.on("error", reject2);
107384
108668
  });
@@ -107536,7 +108820,7 @@ var init_built_in_server = __esm({
107536
108820
  }
107537
108821
  const eventStore = new InMemoryEventStore();
107538
108822
  transport = new import_streamableHttp.StreamableHTTPServerTransport({
107539
- sessionIdGenerator: () => (0, import_crypto5.randomUUID)(),
108823
+ sessionIdGenerator: () => (0, import_crypto6.randomUUID)(),
107540
108824
  eventStore,
107541
108825
  // Enable resumability
107542
108826
  onsessioninitialized: (newSessionId) => {
@@ -107597,7 +108881,7 @@ var init_built_in_server = __esm({
107597
108881
  * Parse request body as JSON
107598
108882
  */
107599
108883
  async parseRequestBody(req) {
107600
- return new Promise((resolve7, reject2) => {
108884
+ return new Promise((resolve8, reject2) => {
107601
108885
  let body = "";
107602
108886
  req.on("data", (chunk) => {
107603
108887
  body += chunk.toString();
@@ -107605,7 +108889,7 @@ var init_built_in_server = __esm({
107605
108889
  req.on("end", () => {
107606
108890
  try {
107607
108891
  const parsed = body ? JSON.parse(body) : null;
107608
- resolve7(parsed);
108892
+ resolve8(parsed);
107609
108893
  } catch (error2) {
107610
108894
  reject2(error2);
107611
108895
  }
@@ -107912,12 +109196,12 @@ data: ${JSON.stringify(data3)}
107912
109196
  }
107913
109197
  this.connections.clear();
107914
109198
  if (this.httpServer) {
107915
- return new Promise((resolve7) => {
109199
+ return new Promise((resolve8) => {
107916
109200
  this.httpServer.close(() => {
107917
109201
  if (this.debug) {
107918
109202
  console.log("[MCP] Built-in server stopped");
107919
109203
  }
107920
- resolve7();
109204
+ resolve8();
107921
109205
  });
107922
109206
  });
107923
109207
  }
@@ -107999,7 +109283,7 @@ __export(enhanced_claude_code_exports, {
107999
109283
  async function createEnhancedClaudeCLIEngine(options = {}) {
108000
109284
  const { agent, systemPrompt, customPrompt, debug, sessionId, allowedTools, timeout = 12e4 } = options;
108001
109285
  const session = new Session(
108002
- sessionId || (0, import_crypto6.randomBytes)(8).toString("hex"),
109286
+ sessionId || (0, import_crypto7.randomBytes)(8).toString("hex"),
108003
109287
  debug
108004
109288
  );
108005
109289
  let mcpServer = null;
@@ -108016,12 +109300,12 @@ async function createEnhancedClaudeCLIEngine(options = {}) {
108016
109300
  console.log("[DEBUG] Built-in MCP server started");
108017
109301
  console.log("[DEBUG] MCP URL:", `http://${host}:${port}/mcp`);
108018
109302
  }
108019
- mcpConfigPath = import_path14.default.join(import_os5.default.tmpdir(), `probe-mcp-${session.id}.json`);
109303
+ mcpConfigPath = import_path15.default.join(import_os5.default.tmpdir(), `probe-mcp-${session.id}.json`);
108020
109304
  const mcpConfig = {
108021
109305
  mcpServers: {
108022
109306
  probe: {
108023
109307
  command: "node",
108024
- args: [import_path14.default.join(process.cwd(), "mcp-probe-server.js")],
109308
+ args: [import_path15.default.join(process.cwd(), "mcp-probe-server.js")],
108025
109309
  env: {
108026
109310
  PROBE_WORKSPACE: process.cwd(),
108027
109311
  DEBUG: debug ? "true" : "false"
@@ -108246,8 +109530,8 @@ ${opts.schema}`;
108246
109530
  break;
108247
109531
  }
108248
109532
  } else if (!processEnded) {
108249
- await new Promise((resolve7) => {
108250
- resolver = resolve7;
109533
+ await new Promise((resolve8) => {
109534
+ resolver = resolve8;
108251
109535
  });
108252
109536
  }
108253
109537
  }
@@ -108446,14 +109730,14 @@ function combinePrompts(systemPrompt, customPrompt, agent) {
108446
109730
  }
108447
109731
  return systemPrompt || "";
108448
109732
  }
108449
- var import_child_process8, import_crypto6, import_promises5, import_path14, import_os5, import_events3;
109733
+ var import_child_process8, import_crypto7, import_promises5, import_path15, import_os5, import_events3;
108450
109734
  var init_enhanced_claude_code = __esm({
108451
109735
  "src/agent/engines/enhanced-claude-code.js"() {
108452
109736
  "use strict";
108453
109737
  import_child_process8 = require("child_process");
108454
- import_crypto6 = require("crypto");
109738
+ import_crypto7 = require("crypto");
108455
109739
  import_promises5 = __toESM(require("fs/promises"), 1);
108456
- import_path14 = __toESM(require("path"), 1);
109740
+ import_path15 = __toESM(require("path"), 1);
108457
109741
  import_os5 = __toESM(require("os"), 1);
108458
109742
  import_events3 = require("events");
108459
109743
  init_built_in_server();
@@ -108469,7 +109753,7 @@ __export(codex_exports, {
108469
109753
  async function createCodexEngine(options = {}) {
108470
109754
  const { agent, systemPrompt, customPrompt, debug, sessionId, allowedTools, model } = options;
108471
109755
  const session = new Session(
108472
- sessionId || (0, import_crypto7.randomBytes)(8).toString("hex"),
109756
+ sessionId || (0, import_crypto8.randomBytes)(8).toString("hex"),
108473
109757
  debug
108474
109758
  );
108475
109759
  let mcpServer = null;
@@ -108511,12 +109795,12 @@ async function createCodexEngine(options = {}) {
108511
109795
  }
108512
109796
  }
108513
109797
  if (message.id !== void 0 && pendingRequests.has(message.id)) {
108514
- const { resolve: resolve7, reject: reject2 } = pendingRequests.get(message.id);
109798
+ const { resolve: resolve8, reject: reject2 } = pendingRequests.get(message.id);
108515
109799
  pendingRequests.delete(message.id);
108516
109800
  if (message.error) {
108517
109801
  reject2(new Error(message.error.message || JSON.stringify(message.error)));
108518
109802
  } else {
108519
- resolve7(message.result);
109803
+ resolve8(message.result);
108520
109804
  }
108521
109805
  }
108522
109806
  if (message.method === "codex/event" && message.params) {
@@ -108537,7 +109821,7 @@ async function createCodexEngine(options = {}) {
108537
109821
  });
108538
109822
  }
108539
109823
  function sendRequest(method, params = {}) {
108540
- return new Promise((resolve7, reject2) => {
109824
+ return new Promise((resolve8, reject2) => {
108541
109825
  const id = ++requestId;
108542
109826
  const request = {
108543
109827
  jsonrpc: "2.0",
@@ -108545,7 +109829,7 @@ async function createCodexEngine(options = {}) {
108545
109829
  method,
108546
109830
  params
108547
109831
  };
108548
- pendingRequests.set(id, { resolve: resolve7, reject: reject2 });
109832
+ pendingRequests.set(id, { resolve: resolve8, reject: reject2 });
108549
109833
  setTimeout(() => {
108550
109834
  if (pendingRequests.has(id)) {
108551
109835
  pendingRequests.delete(id);
@@ -108608,7 +109892,7 @@ ${prompt}`;
108608
109892
  const reqId = requestId + 1;
108609
109893
  let fullResponse = "";
108610
109894
  let gotSessionId = false;
108611
- const eventPromise = new Promise((resolve7) => {
109895
+ const eventPromise = new Promise((resolve8) => {
108612
109896
  eventHandlers.set(reqId, (eventParams) => {
108613
109897
  const msg = eventParams.msg;
108614
109898
  if (msg.type === "session_configured" && msg.session_id && !gotSessionId) {
@@ -108628,7 +109912,7 @@ ${prompt}`;
108628
109912
  });
108629
109913
  setTimeout(() => {
108630
109914
  eventHandlers.delete(reqId);
108631
- resolve7();
109915
+ resolve8();
108632
109916
  }, 6e5);
108633
109917
  });
108634
109918
  const resultPromise = sendRequest("tools/call", {
@@ -108724,12 +110008,12 @@ function combinePrompts2(systemPrompt, customPrompt, agent) {
108724
110008
  }
108725
110009
  return systemPrompt || "";
108726
110010
  }
108727
- var import_child_process9, import_crypto7, import_readline;
110011
+ var import_child_process9, import_crypto8, import_readline;
108728
110012
  var init_codex = __esm({
108729
110013
  "src/agent/engines/codex.js"() {
108730
110014
  "use strict";
108731
110015
  import_child_process9 = require("child_process");
108732
- import_crypto7 = require("crypto");
110016
+ import_crypto8 = require("crypto");
108733
110017
  import_readline = require("readline");
108734
110018
  init_built_in_server();
108735
110019
  init_Session();
@@ -108834,7 +110118,7 @@ Your content here
108834
110118
 
108835
110119
  Do NOT wrap in other tags like <api_call>, <tool_name>, <function>, etc.`;
108836
110120
  }
108837
- var import_dotenv, import_anthropic2, import_openai2, import_google2, import_ai5, import_crypto8, import_events4, import_fs12, import_promises6, import_path15, ENGINE_ACTIVITY_TIMEOUT_DEFAULT, ENGINE_ACTIVITY_TIMEOUT_MIN, ENGINE_ACTIVITY_TIMEOUT_MAX, MAX_TOOL_ITERATIONS, MAX_HISTORY_MESSAGES, MAX_IMAGE_FILE_SIZE, ProbeAgent;
110121
+ var import_dotenv, import_anthropic2, import_openai2, import_google2, import_ai5, import_crypto9, import_events4, import_fs12, import_promises6, import_path16, ENGINE_ACTIVITY_TIMEOUT_DEFAULT, ENGINE_ACTIVITY_TIMEOUT_MIN, ENGINE_ACTIVITY_TIMEOUT_MAX, MAX_TOOL_ITERATIONS, MAX_HISTORY_MESSAGES, MAX_IMAGE_FILE_SIZE, ProbeAgent;
108838
110122
  var init_ProbeAgent = __esm({
108839
110123
  "src/agent/ProbeAgent.js"() {
108840
110124
  "use strict";
@@ -108844,17 +110128,18 @@ var init_ProbeAgent = __esm({
108844
110128
  import_google2 = require("@ai-sdk/google");
108845
110129
  init_dist3();
108846
110130
  import_ai5 = require("ai");
108847
- import_crypto8 = require("crypto");
110131
+ import_crypto9 = require("crypto");
108848
110132
  import_events4 = require("events");
108849
110133
  import_fs12 = require("fs");
108850
110134
  import_promises6 = require("fs/promises");
108851
- import_path15 = require("path");
110135
+ import_path16 = require("path");
108852
110136
  init_tokenCounter();
108853
110137
  init_InMemoryStorageAdapter();
108854
110138
  init_HookManager();
108855
110139
  init_imageConfig();
108856
110140
  init_tools();
108857
110141
  init_common2();
110142
+ init_fileTracker();
108858
110143
  init_probeTool();
108859
110144
  init_mockProvider();
108860
110145
  init_index();
@@ -108896,7 +110181,7 @@ var init_ProbeAgent = __esm({
108896
110181
  * @param {string} [options.customPrompt] - Custom prompt to replace the default system message
108897
110182
  * @param {string} [options.systemPrompt] - Alias for customPrompt; takes precedence when both are provided
108898
110183
  * @param {string} [options.promptType] - Predefined prompt type (code-explorer, code-searcher, architect, code-review, support)
108899
- * @param {boolean} [options.allowEdit=false] - Allow the use of the 'implement' tool
110184
+ * @param {boolean} [options.allowEdit=false] - Allow the use of the 'edit' and 'create' tools
108900
110185
  * @param {boolean} [options.enableDelegate=false] - Enable the delegate tool for task distribution to subagents
108901
110186
  * @param {boolean} [options.enableExecutePlan=false] - Enable the execute_plan DSL orchestration tool
108902
110187
  * @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)
@@ -108941,10 +110226,11 @@ var init_ProbeAgent = __esm({
108941
110226
  * @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.
108942
110227
  */
108943
110228
  constructor(options = {}) {
108944
- this.sessionId = options.sessionId || (0, import_crypto8.randomUUID)();
110229
+ this.sessionId = options.sessionId || (0, import_crypto9.randomUUID)();
108945
110230
  this.customPrompt = options.systemPrompt || options.customPrompt || null;
108946
110231
  this.promptType = options.promptType || "code-explorer";
108947
110232
  this.allowEdit = !!options.allowEdit;
110233
+ this.hashLines = options.hashLines !== void 0 ? !!options.hashLines : this.allowEdit;
108948
110234
  this.enableDelegate = !!options.enableDelegate;
108949
110235
  this.enableExecutePlan = !!options.enableExecutePlan;
108950
110236
  this.debug = options.debug || process.env.DEBUG === "1";
@@ -109006,7 +110292,8 @@ var init_ProbeAgent = __esm({
109006
110292
  if (this.debug) {
109007
110293
  console.log(`[DEBUG] Generated session ID for agent: ${this.sessionId}`);
109008
110294
  console.log(`[DEBUG] Maximum tool iterations configured: ${MAX_TOOL_ITERATIONS}`);
109009
- console.log(`[DEBUG] Allow Edit (implement tool): ${this.allowEdit}`);
110295
+ console.log(`[DEBUG] Allow Edit: ${this.allowEdit}`);
110296
+ console.log(`[DEBUG] Hash Lines: ${this.hashLines}`);
109010
110297
  console.log(`[DEBUG] Search delegation enabled: ${this.searchDelegate}`);
109011
110298
  console.log(`[DEBUG] Workspace root: ${this.workspaceRoot}`);
109012
110299
  console.log(`[DEBUG] Working directory (cwd): ${this.cwd}`);
@@ -109391,9 +110678,12 @@ var init_ProbeAgent = __esm({
109391
110678
  cwd: this.cwd,
109392
110679
  workspaceRoot: this.workspaceRoot,
109393
110680
  allowedFolders: this.allowedFolders,
110681
+ // File state tracking for safe multi-edit workflows (only when editing is enabled)
110682
+ fileTracker: this.allowEdit ? new FileTracker({ debug: this.debug }) : null,
109394
110683
  outline: this.outline,
109395
110684
  searchDelegate: this.searchDelegate,
109396
110685
  allowEdit: this.allowEdit,
110686
+ hashLines: this.hashLines,
109397
110687
  enableDelegate: this.enableDelegate,
109398
110688
  enableExecutePlan: this.enableExecutePlan,
109399
110689
  enableBash: this.enableBash,
@@ -109464,7 +110754,7 @@ var init_ProbeAgent = __esm({
109464
110754
  if (!imagePath) {
109465
110755
  throw new Error("Image path is required");
109466
110756
  }
109467
- const filename = (0, import_path15.basename)(imagePath);
110757
+ const filename = (0, import_path16.basename)(imagePath);
109468
110758
  const extension = filename.toLowerCase().split(".").pop();
109469
110759
  if (!extension || !SUPPORTED_IMAGE_EXTENSIONS.includes(extension)) {
109470
110760
  throw new Error(`Invalid or unsupported image extension: ${extension}. Supported formats: ${SUPPORTED_IMAGE_EXTENSIONS.join(", ")}`);
@@ -110178,7 +111468,7 @@ var init_ProbeAgent = __esm({
110178
111468
  let resolvedPath2 = imagePath;
110179
111469
  if (!imagePath.includes("/") && !imagePath.includes("\\")) {
110180
111470
  for (const dir of listFilesDirectories) {
110181
- const potentialPath = (0, import_path15.resolve)(dir, imagePath);
111471
+ const potentialPath = (0, import_path16.resolve)(dir, imagePath);
110182
111472
  const loaded = await this.loadImageIfValid(potentialPath);
110183
111473
  if (loaded) {
110184
111474
  if (this.debug) {
@@ -110203,7 +111493,7 @@ var init_ProbeAgent = __esm({
110203
111493
  let match2;
110204
111494
  while ((match2 = fileHeaderPattern.exec(content)) !== null) {
110205
111495
  const filePath = match2[1].trim();
110206
- const dir = (0, import_path15.dirname)(filePath);
111496
+ const dir = (0, import_path16.dirname)(filePath);
110207
111497
  if (dir && dir !== ".") {
110208
111498
  directories.push(dir);
110209
111499
  if (this.debug) {
@@ -110248,17 +111538,17 @@ var init_ProbeAgent = __esm({
110248
111538
  const allowedDirs = this.allowedFolders && this.allowedFolders.length > 0 ? this.allowedFolders : [process.cwd()];
110249
111539
  let absolutePath;
110250
111540
  let isPathAllowed2 = false;
110251
- if ((0, import_path15.isAbsolute)(imagePath)) {
110252
- absolutePath = safeRealpath((0, import_path15.resolve)(imagePath));
111541
+ if ((0, import_path16.isAbsolute)(imagePath)) {
111542
+ absolutePath = safeRealpath((0, import_path16.resolve)(imagePath));
110253
111543
  isPathAllowed2 = allowedDirs.some((dir) => {
110254
111544
  const resolvedDir = safeRealpath(dir);
110255
- return absolutePath === resolvedDir || absolutePath.startsWith(resolvedDir + import_path15.sep);
111545
+ return absolutePath === resolvedDir || absolutePath.startsWith(resolvedDir + import_path16.sep);
110256
111546
  });
110257
111547
  } else {
110258
111548
  for (const dir of allowedDirs) {
110259
111549
  const resolvedDir = safeRealpath(dir);
110260
- const resolvedPath2 = safeRealpath((0, import_path15.resolve)(dir, imagePath));
110261
- if (resolvedPath2 === resolvedDir || resolvedPath2.startsWith(resolvedDir + import_path15.sep)) {
111550
+ const resolvedPath2 = safeRealpath((0, import_path16.resolve)(dir, imagePath));
111551
+ if (resolvedPath2 === resolvedDir || resolvedPath2.startsWith(resolvedDir + import_path16.sep)) {
110262
111552
  absolutePath = resolvedPath2;
110263
111553
  isPathAllowed2 = true;
110264
111554
  break;
@@ -110446,8 +111736,8 @@ var init_ProbeAgent = __esm({
110446
111736
  const hasConfiguredName = !!configuredName;
110447
111737
  let guidanceCandidates = [];
110448
111738
  if (hasConfiguredName) {
110449
- const targetName = (0, import_path15.basename)(configuredName);
110450
- if (configuredName !== targetName || configuredName.includes("/") || configuredName.includes("\\") || configuredName.includes("..") || (0, import_path15.isAbsolute)(configuredName)) {
111739
+ const targetName = (0, import_path16.basename)(configuredName);
111740
+ if (configuredName !== targetName || configuredName.includes("/") || configuredName.includes("\\") || configuredName.includes("..") || (0, import_path16.isAbsolute)(configuredName)) {
110451
111741
  console.warn(`[WARN] Invalid architectureFileName (must be a simple filename): ${configuredName}`);
110452
111742
  } else if (targetName) {
110453
111743
  const targetLower = targetName.toLowerCase();
@@ -110514,7 +111804,7 @@ var init_ProbeAgent = __esm({
110514
111804
  pushEntry(architectureMatch);
110515
111805
  const contexts = [];
110516
111806
  for (const entry of uniqueEntries) {
110517
- const filePath = (0, import_path15.resolve)(rootDirectory, entry.name);
111807
+ const filePath = (0, import_path16.resolve)(rootDirectory, entry.name);
110518
111808
  try {
110519
111809
  const content = await (0, import_promises6.readFile)(filePath, "utf8");
110520
111810
  let kind = "other";
@@ -110579,10 +111869,10 @@ ${this.architectureContext.content}
110579
111869
  }
110580
111870
  _getSkillsRepoRoot() {
110581
111871
  if (this.workspaceRoot) {
110582
- return (0, import_path15.resolve)(this.workspaceRoot);
111872
+ return (0, import_path16.resolve)(this.workspaceRoot);
110583
111873
  }
110584
111874
  if (this.allowedFolders && this.allowedFolders.length > 0) {
110585
- return (0, import_path15.resolve)(this.allowedFolders[0]);
111875
+ return (0, import_path16.resolve)(this.allowedFolders[0]);
110586
111876
  }
110587
111877
  return process.cwd();
110588
111878
  }
@@ -110771,10 +112061,6 @@ Workspace: ${this.allowedFolders.join(", ")}`;
110771
112061
  }
110772
112062
  if (isToolAllowed("readImage")) {
110773
112063
  toolDefinitions += `${readImageToolDefinition}
110774
- `;
110775
- }
110776
- if (this.allowEdit && isToolAllowed("implement")) {
110777
- toolDefinitions += `${implementToolDefinition}
110778
112064
  `;
110779
112065
  }
110780
112066
  if (this.allowEdit && isToolAllowed("edit")) {
@@ -110856,7 +112142,7 @@ The configuration is loaded from src/config.js lines 15-25 which contains the da
110856
112142
  availableToolsList += "- query: Search code using structural AST patterns.\n";
110857
112143
  }
110858
112144
  if (isToolAllowed("extract")) {
110859
- availableToolsList += "- extract: Extract specific code blocks or lines from files.\n";
112145
+ 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';
110860
112146
  }
110861
112147
  if (isToolAllowed("listFiles")) {
110862
112148
  availableToolsList += "- listFiles: List files and directories in a specified location.\n";
@@ -110873,11 +112159,8 @@ The configuration is loaded from src/config.js lines 15-25 which contains the da
110873
112159
  if (isToolAllowed("readImage")) {
110874
112160
  availableToolsList += "- readImage: Read and load an image file for AI analysis.\n";
110875
112161
  }
110876
- if (this.allowEdit && isToolAllowed("implement")) {
110877
- availableToolsList += "- implement: Implement a feature or fix a bug using aider.\n";
110878
- }
110879
112162
  if (this.allowEdit && isToolAllowed("edit")) {
110880
- availableToolsList += "- edit: Edit files using exact string replacement.\n";
112163
+ availableToolsList += "- edit: Edit files using text replacement, AST-aware symbol operations, or line-targeted editing.\n";
110881
112164
  }
110882
112165
  if (this.allowEdit && isToolAllowed("create")) {
110883
112166
  availableToolsList += "- create: Create new files with specified content.\n";
@@ -110965,8 +112248,14 @@ Follow these instructions carefully:
110965
112248
  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.
110966
112249
  9. Prefer concise and focused search queries. Use specific keywords and phrases to narrow down results.${this.allowEdit ? `
110967
112250
  10. When modifying files, choose the appropriate tool:
110968
- - Use 'edit' for precise changes to existing files (requires exact string match)
110969
- - Use 'create' for new files or complete file rewrites` : ""}
112251
+ - Use 'edit' for all code modifications:
112252
+ * For small changes (a line or a few lines), use old_string + new_string \u2014 copy old_string verbatim from the file.
112253
+ * For rewriting entire functions/classes/methods, use the symbol parameter instead (no exact text matching needed).
112254
+ * 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.' : ""}
112255
+ * 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.
112256
+ - Use 'create' for new files or complete file rewrites.
112257
+ - If an edit fails, read the error message \u2014 it tells you exactly how to fix the call and retry.
112258
+ - 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.` : ""}
110970
112259
  </instructions>
110971
112260
  `;
110972
112261
  let systemMessage = "";
@@ -111192,8 +112481,8 @@ You are working with a workspace. Available paths: ${workspaceDesc}
111192
112481
  let currentIteration = 0;
111193
112482
  let completionAttempted = false;
111194
112483
  let finalResult = "I was unable to complete your request due to reaching the maximum number of tool iterations.";
111195
- const baseMaxIterations = this.maxIterations || MAX_TOOL_ITERATIONS;
111196
- const maxIterations = options.schema ? baseMaxIterations + 4 : baseMaxIterations;
112484
+ const baseMaxIterations = options._maxIterationsOverride || this.maxIterations || MAX_TOOL_ITERATIONS;
112485
+ const maxIterations = options._maxIterationsOverride ? baseMaxIterations : options.schema ? baseMaxIterations + 4 : baseMaxIterations;
111197
112486
  const isClaudeCode = this.clientApiProvider === "claude-code" || process.env.USE_CLAUDE_CODE === "true";
111198
112487
  const isCodex = this.clientApiProvider === "codex" || process.env.USE_CODEX === "true";
111199
112488
  if (isClaudeCode) {
@@ -111466,8 +112755,11 @@ You are working with a workspace. Available paths: ${workspaceDesc}
111466
112755
  if (this.enableSkills && this.allowedTools.isEnabled("useSkill")) validTools.push("useSkill");
111467
112756
  if (this.allowedTools.isEnabled("readImage")) validTools.push("readImage");
111468
112757
  validTools.push("attempt_completion");
111469
- if (this.allowEdit && this.allowedTools.isEnabled("implement")) {
111470
- validTools.push("implement", "edit", "create");
112758
+ if (this.allowEdit && this.allowedTools.isEnabled("edit")) {
112759
+ validTools.push("edit");
112760
+ }
112761
+ if (this.allowEdit && this.allowedTools.isEnabled("create")) {
112762
+ validTools.push("create");
111471
112763
  }
111472
112764
  if (this.enableBash && this.allowedTools.isEnabled("bash")) {
111473
112765
  validTools.push("bash");
@@ -111689,10 +112981,10 @@ ${errorXml}
111689
112981
  try {
111690
112982
  let resolvedWorkingDirectory = this.workspaceRoot || this.cwd || this.allowedFolders && this.allowedFolders[0] || process.cwd();
111691
112983
  if (params.workingDirectory) {
111692
- const requestedDir = safeRealpath((0, import_path15.isAbsolute)(params.workingDirectory) ? (0, import_path15.resolve)(params.workingDirectory) : (0, import_path15.resolve)(resolvedWorkingDirectory, params.workingDirectory));
112984
+ const requestedDir = safeRealpath((0, import_path16.isAbsolute)(params.workingDirectory) ? (0, import_path16.resolve)(params.workingDirectory) : (0, import_path16.resolve)(resolvedWorkingDirectory, params.workingDirectory));
111693
112985
  const isWithinAllowed = !this.allowedFolders || this.allowedFolders.length === 0 || this.allowedFolders.some((folder) => {
111694
112986
  const resolvedFolder = safeRealpath(folder);
111695
- return requestedDir === resolvedFolder || requestedDir.startsWith(resolvedFolder + import_path15.sep);
112987
+ return requestedDir === resolvedFolder || requestedDir.startsWith(resolvedFolder + import_path16.sep);
111696
112988
  });
111697
112989
  if (isWithinAllowed) {
111698
112990
  resolvedWorkingDirectory = requestedDir;
@@ -111760,6 +113052,8 @@ ${errorXml}
111760
113052
  // Inherit bash enablement
111761
113053
  bashConfig: this.bashConfig,
111762
113054
  // Inherit bash configuration
113055
+ allowEdit: this.allowEdit,
113056
+ // Inherit edit/create permission
111763
113057
  allowedTools: allowedToolsForDelegate,
111764
113058
  // Inherit allowed tools from parent
111765
113059
  debug: this.debug,
@@ -111832,7 +113126,7 @@ ${errorXml}
111832
113126
  currentMessages.push({ role: "assistant", content: assistantResponseContent });
111833
113127
  let toolResultContent = typeof toolResult === "string" ? toolResult : JSON.stringify(toolResult, null, 2);
111834
113128
  if (this.workspaceRoot && toolResultContent) {
111835
- const wsPrefix = this.workspaceRoot.endsWith(import_path15.sep) ? this.workspaceRoot : this.workspaceRoot + import_path15.sep;
113129
+ const wsPrefix = this.workspaceRoot.endsWith(import_path16.sep) ? this.workspaceRoot : this.workspaceRoot + import_path16.sep;
111836
113130
  toolResultContent = toolResultContent.split(wsPrefix).join("");
111837
113131
  }
111838
113132
  const { cleanedContent, extractedBlocks } = extractRawOutputBlocks(toolResultContent);
@@ -112425,13 +113719,16 @@ Convert your previous response content into actual JSON data that follows this s
112425
113719
  options.schema,
112426
113720
  0
112427
113721
  );
113722
+ const { schema: _unusedSchema1, ...schemaDefCorrectionOptions } = options;
112428
113723
  finalResult = await this.answer(schemaDefinitionPrompt, [], {
112429
- ...options,
113724
+ ...schemaDefCorrectionOptions,
112430
113725
  _schemaFormatted: true,
112431
113726
  _skipValidation: true,
112432
113727
  // Skip validation in recursive correction calls to prevent loops
112433
- _completionPromptProcessed: true
113728
+ _completionPromptProcessed: true,
112434
113729
  // Prevent cascading completion prompts in retry calls
113730
+ _maxIterationsOverride: 3
113731
+ // Correction should complete in 1-2 iterations (issue #447)
112435
113732
  });
112436
113733
  finalResult = cleanSchemaResponse(finalResult);
112437
113734
  validation = validateJsonResponse(finalResult);
@@ -112479,15 +113776,18 @@ Convert your previous response content into actual JSON data that follows this s
112479
113776
  retryCount
112480
113777
  );
112481
113778
  }
113779
+ const { schema: _unusedSchema2, ...correctionOptions } = options;
112482
113780
  finalResult = await this.answer(correctionPrompt, [], {
112483
- ...options,
113781
+ ...correctionOptions,
112484
113782
  _schemaFormatted: true,
112485
113783
  _skipValidation: true,
112486
113784
  // Skip validation in recursive correction calls to prevent loops
112487
113785
  _disableTools: true,
112488
113786
  // Only allow attempt_completion - prevent AI from using search/query tools
112489
- _completionPromptProcessed: true
113787
+ _completionPromptProcessed: true,
112490
113788
  // Prevent cascading completion prompts in retry calls
113789
+ _maxIterationsOverride: 3
113790
+ // Correction should complete in 1-2 iterations (issue #447)
112491
113791
  });
112492
113792
  finalResult = cleanSchemaResponse(finalResult);
112493
113793
  validation = validateJsonResponse(finalResult, { debug: this.debug });
@@ -112682,7 +113982,7 @@ Convert your previous response content into actual JSON data that follows this s
112682
113982
  */
112683
113983
  clone(options = {}) {
112684
113984
  const {
112685
- sessionId = (0, import_crypto8.randomUUID)(),
113985
+ sessionId = (0, import_crypto9.randomUUID)(),
112686
113986
  stripInternalMessages = true,
112687
113987
  keepSystemMessage = true,
112688
113988
  deepCopy = true,
@@ -112915,6 +114215,7 @@ async function delegate({
112915
114215
  model = null,
112916
114216
  enableBash = false,
112917
114217
  bashConfig = null,
114218
+ allowEdit = false,
112918
114219
  architectureFileName = null,
112919
114220
  promptType = "code-researcher",
112920
114221
  allowedTools = null,
@@ -112947,7 +114248,7 @@ async function delegate({
112947
114248
  }
112948
114249
  }
112949
114250
  const manager = delegationManager || defaultDelegationManager;
112950
- const sessionId = (0, import_crypto9.randomUUID)();
114251
+ const sessionId = (0, import_crypto10.randomUUID)();
112951
114252
  const startTime = Date.now();
112952
114253
  const remainingIterations = Math.max(1, maxIterations - currentIteration);
112953
114254
  const delegationSpan = typeof tracer?.createDelegationSpan === "function" ? tracer.createDelegationSpan(sessionId, task) : null;
@@ -112994,6 +114295,8 @@ async function delegate({
112994
114295
  // Inherit from parent
112995
114296
  bashConfig,
112996
114297
  // Inherit from parent
114298
+ allowEdit,
114299
+ // Inherit from parent
112997
114300
  architectureFileName,
112998
114301
  allowedTools,
112999
114302
  disableTools,
@@ -113098,11 +114401,11 @@ async function delegate({
113098
114401
  throw new Error(`Delegation failed: ${error2.message}`);
113099
114402
  }
113100
114403
  }
113101
- var import_crypto9, DelegationManager, defaultDelegationManager, DEFAULT_DELEGATE_TIMEOUT;
114404
+ var import_crypto10, DelegationManager, defaultDelegationManager, DEFAULT_DELEGATE_TIMEOUT;
113102
114405
  var init_delegate = __esm({
113103
114406
  "src/delegate.js"() {
113104
114407
  "use strict";
113105
- import_crypto9 = require("crypto");
114408
+ import_crypto10 = require("crypto");
113106
114409
  init_ProbeAgent();
113107
114410
  DelegationManager = class {
113108
114411
  constructor(options = {}) {
@@ -113179,7 +114482,7 @@ var init_delegate = __esm({
113179
114482
  if (debug) {
113180
114483
  console.error(`[DelegationManager] Slot unavailable (${this.globalActive}/${this.maxConcurrent}), queuing... (queue size: ${this.waitQueue.length}, timeout: ${effectiveTimeout}ms)`);
113181
114484
  }
113182
- return new Promise((resolve7, reject2) => {
114485
+ return new Promise((resolve8, reject2) => {
113183
114486
  const entry = {
113184
114487
  resolve: null,
113185
114488
  // Will be wrapped below
@@ -113195,7 +114498,7 @@ var init_delegate = __esm({
113195
114498
  if (settled) return;
113196
114499
  settled = true;
113197
114500
  if (entry.timeoutId) clearTimeout(entry.timeoutId);
113198
- resolve7(value);
114501
+ resolve8(value);
113199
114502
  };
113200
114503
  entry.reject = (error2) => {
113201
114504
  if (settled) return;
@@ -113245,7 +114548,7 @@ var init_delegate = __esm({
113245
114548
  while (this.waitQueue.length > 0 && this.globalActive < this.maxConcurrent) {
113246
114549
  const next = this.waitQueue.shift();
113247
114550
  if (!next) break;
113248
- const { resolve: resolve7, reject: reject2, parentSessionId, queuedAt } = next;
114551
+ const { resolve: resolve8, reject: reject2, parentSessionId, queuedAt } = next;
113249
114552
  if (parentSessionId) {
113250
114553
  const sessionData = this.sessionDelegations.get(parentSessionId);
113251
114554
  const sessionCount = sessionData?.count || 0;
@@ -113262,12 +114565,12 @@ var init_delegate = __esm({
113262
114565
  const waitTime = Date.now() - queuedAt;
113263
114566
  console.error(`[DelegationManager] Granted slot from queue (waited ${waitTime}ms). Active: ${this.globalActive}/${this.maxConcurrent}`);
113264
114567
  }
113265
- toResolve.push(resolve7);
114568
+ toResolve.push(resolve8);
113266
114569
  }
113267
114570
  if (toResolve.length > 0 || toReject.length > 0) {
113268
114571
  setImmediate(() => {
113269
- for (const resolve7 of toResolve) {
113270
- resolve7(true);
114572
+ for (const resolve8 of toResolve) {
114573
+ resolve8(true);
113271
114574
  }
113272
114575
  for (const { reject: reject2, error: error2 } of toReject) {
113273
114576
  reject2(error2);
@@ -113913,6 +115216,7 @@ var init_vercel = __esm({
113913
115216
  init_analyzeAll();
113914
115217
  init_common2();
113915
115218
  init_error_types();
115219
+ init_hashline();
113916
115220
  CODE_SEARCH_SCHEMA = {
113917
115221
  type: "object",
113918
115222
  properties: {
@@ -113931,8 +115235,15 @@ var init_vercel = __esm({
113931
115235
  maxTokens = 2e4,
113932
115236
  debug = false,
113933
115237
  outline = false,
113934
- searchDelegate = false
115238
+ searchDelegate = false,
115239
+ hashLines = false
113935
115240
  } = options;
115241
+ const maybeAnnotate = (result) => {
115242
+ if (hashLines && typeof result === "string") {
115243
+ return annotateOutputWithHashes(result);
115244
+ }
115245
+ return result;
115246
+ };
113936
115247
  return (0, import_ai6.tool)({
113937
115248
  name: "search",
113938
115249
  description: searchDelegate ? `${searchDescription} (delegates code search to a subagent and returns extracted code blocks)` : searchDescription,
@@ -113974,7 +115285,12 @@ var init_vercel = __esm({
113974
115285
  };
113975
115286
  if (!searchDelegate) {
113976
115287
  try {
113977
- return await runRawSearch();
115288
+ const result = maybeAnnotate(await runRawSearch());
115289
+ if (options.fileTracker && typeof result === "string") {
115290
+ options.fileTracker.trackFilesFromOutput(result, options.cwd || ".").catch(() => {
115291
+ });
115292
+ }
115293
+ return result;
113978
115294
  } catch (error2) {
113979
115295
  console.error("Error executing search command:", error2);
113980
115296
  return formatErrorForAI(error2);
@@ -114017,7 +115333,12 @@ var init_vercel = __esm({
114017
115333
  if (debug) {
114018
115334
  console.error("Delegated search returned no targets; falling back to raw search");
114019
115335
  }
114020
- return await runRawSearch();
115336
+ const fallbackResult = maybeAnnotate(await runRawSearch());
115337
+ if (options.fileTracker && typeof fallbackResult === "string") {
115338
+ options.fileTracker.trackFilesFromOutput(fallbackResult, options.cwd || ".").catch(() => {
115339
+ });
115340
+ }
115341
+ return fallbackResult;
114021
115342
  }
114022
115343
  const resolutionBase = searchPaths[0] || options.cwd || ".";
114023
115344
  const resolvedTargets = targets.map((target) => resolveTargetPath(target, resolutionBase));
@@ -114032,13 +115353,18 @@ var init_vercel = __esm({
114032
115353
  const extractResult = await extract(extractOptions);
114033
115354
  if (resolutionBase && typeof extractResult === "string") {
114034
115355
  const wsPrefix = resolutionBase.endsWith("/") ? resolutionBase : resolutionBase + "/";
114035
- return extractResult.split(wsPrefix).join("");
115356
+ return maybeAnnotate(extractResult.split(wsPrefix).join(""));
114036
115357
  }
114037
- return extractResult;
115358
+ return maybeAnnotate(extractResult);
114038
115359
  } catch (error2) {
114039
115360
  console.error("Delegated search failed, falling back to raw search:", error2);
114040
115361
  try {
114041
- return await runRawSearch();
115362
+ const fallbackResult2 = maybeAnnotate(await runRawSearch());
115363
+ if (options.fileTracker && typeof fallbackResult2 === "string") {
115364
+ options.fileTracker.trackFilesFromOutput(fallbackResult2, options.cwd || ".").catch(() => {
115365
+ });
115366
+ }
115367
+ return fallbackResult2;
114042
115368
  } catch (fallbackError) {
114043
115369
  console.error("Error executing search command:", fallbackError);
114044
115370
  return formatErrorForAI(fallbackError);
@@ -114084,7 +115410,7 @@ var init_vercel = __esm({
114084
115410
  });
114085
115411
  };
114086
115412
  extractTool = (options = {}) => {
114087
- const { debug = false, outline = false } = options;
115413
+ const { debug = false, outline = false, hashLines = false } = options;
114088
115414
  return (0, import_ai6.tool)({
114089
115415
  name: "extract",
114090
115416
  description: extractDescription,
@@ -114101,6 +115427,7 @@ var init_vercel = __esm({
114101
115427
  }
114102
115428
  let tempFilePath = null;
114103
115429
  let extractOptions = { cwd: effectiveCwd };
115430
+ let extractFiles = null;
114104
115431
  if (input_content) {
114105
115432
  const { writeFileSync: writeFileSync2, unlinkSync } = await import("fs");
114106
115433
  const { join: join5 } = await import("path");
@@ -114124,13 +115451,13 @@ var init_vercel = __esm({
114124
115451
  };
114125
115452
  } else if (targets) {
114126
115453
  const parsedTargets = parseTargets(targets);
114127
- const files = parsedTargets.map((target) => resolveTargetPath(target, effectiveCwd));
115454
+ extractFiles = parsedTargets.map((target) => resolveTargetPath(target, effectiveCwd));
114128
115455
  let effectiveFormat = format2;
114129
115456
  if (outline && format2 === "outline-xml") {
114130
115457
  effectiveFormat = "xml";
114131
115458
  }
114132
115459
  extractOptions = {
114133
- files,
115460
+ files: extractFiles,
114134
115461
  cwd: effectiveCwd,
114135
115462
  allowTests: allow_tests ?? true,
114136
115463
  contextLines: context_lines,
@@ -114140,6 +115467,10 @@ var init_vercel = __esm({
114140
115467
  throw new Error("Either targets or input_content must be provided");
114141
115468
  }
114142
115469
  const results = await extract(extractOptions);
115470
+ if (options.fileTracker && extractFiles && extractFiles.length > 0) {
115471
+ options.fileTracker.trackFilesFromExtract(extractFiles, effectiveCwd).catch(() => {
115472
+ });
115473
+ }
114143
115474
  if (tempFilePath) {
114144
115475
  const { unlinkSync } = await import("fs");
114145
115476
  try {
@@ -114151,6 +115482,9 @@ var init_vercel = __esm({
114151
115482
  console.error(`Warning: Failed to remove temporary file: ${cleanupError.message}`);
114152
115483
  }
114153
115484
  }
115485
+ if (hashLines && typeof results === "string") {
115486
+ return annotateOutputWithHashes(results);
115487
+ }
114154
115488
  return results;
114155
115489
  } catch (error2) {
114156
115490
  console.error("Error executing extract command:", error2);
@@ -114577,7 +115911,7 @@ async function listFilesByLevel(options) {
114577
115911
  if (!import_fs13.default.existsSync(directory)) {
114578
115912
  throw new Error(`Directory does not exist: ${directory}`);
114579
115913
  }
114580
- const gitDirExists = import_fs13.default.existsSync(import_path16.default.join(directory, ".git"));
115914
+ const gitDirExists = import_fs13.default.existsSync(import_path17.default.join(directory, ".git"));
114581
115915
  if (gitDirExists && respectGitignore) {
114582
115916
  try {
114583
115917
  return await listFilesUsingGit(directory, maxFiles);
@@ -114592,8 +115926,8 @@ async function listFilesUsingGit(directory, maxFiles) {
114592
115926
  const { stdout } = await execAsync3("git ls-files", { cwd: directory });
114593
115927
  const files = stdout.split("\n").filter(Boolean);
114594
115928
  const sortedFiles = files.sort((a5, b5) => {
114595
- const depthA = a5.split(import_path16.default.sep).length;
114596
- const depthB = b5.split(import_path16.default.sep).length;
115929
+ const depthA = a5.split(import_path17.default.sep).length;
115930
+ const depthB = b5.split(import_path17.default.sep).length;
114597
115931
  return depthA - depthB;
114598
115932
  });
114599
115933
  return sortedFiles.slice(0, maxFiles);
@@ -114610,23 +115944,23 @@ async function listFilesByLevelManually(directory, maxFiles, respectGitignore) {
114610
115944
  try {
114611
115945
  const entries = import_fs13.default.readdirSync(dir, { withFileTypes: true });
114612
115946
  const files = entries.filter((entry) => {
114613
- const fullPath = import_path16.default.join(dir, entry.name);
115947
+ const fullPath = import_path17.default.join(dir, entry.name);
114614
115948
  return getEntryTypeSync(entry, fullPath).isFile;
114615
115949
  });
114616
115950
  for (const file of files) {
114617
115951
  if (result.length >= maxFiles) break;
114618
- const filePath = import_path16.default.join(dir, file.name);
114619
- const relativePath = import_path16.default.relative(directory, filePath);
115952
+ const filePath = import_path17.default.join(dir, file.name);
115953
+ const relativePath = import_path17.default.relative(directory, filePath);
114620
115954
  if (shouldIgnore(relativePath, ignorePatterns)) continue;
114621
115955
  result.push(relativePath);
114622
115956
  }
114623
115957
  const dirs = entries.filter((entry) => {
114624
- const fullPath = import_path16.default.join(dir, entry.name);
115958
+ const fullPath = import_path17.default.join(dir, entry.name);
114625
115959
  return getEntryTypeSync(entry, fullPath).isDirectory;
114626
115960
  });
114627
115961
  for (const subdir of dirs) {
114628
- const subdirPath = import_path16.default.join(dir, subdir.name);
114629
- const relativeSubdirPath = import_path16.default.relative(directory, subdirPath);
115962
+ const subdirPath = import_path17.default.join(dir, subdir.name);
115963
+ const relativeSubdirPath = import_path17.default.relative(directory, subdirPath);
114630
115964
  if (shouldIgnore(relativeSubdirPath, ignorePatterns)) continue;
114631
115965
  if (subdir.name === "node_modules" || subdir.name === ".git") continue;
114632
115966
  queue.push({ dir: subdirPath, level: level + 1 });
@@ -114638,7 +115972,7 @@ async function listFilesByLevelManually(directory, maxFiles, respectGitignore) {
114638
115972
  return result;
114639
115973
  }
114640
115974
  function loadGitignorePatterns(directory) {
114641
- const gitignorePath = import_path16.default.join(directory, ".gitignore");
115975
+ const gitignorePath = import_path17.default.join(directory, ".gitignore");
114642
115976
  if (!import_fs13.default.existsSync(gitignorePath)) {
114643
115977
  return [];
114644
115978
  }
@@ -114661,12 +115995,12 @@ function shouldIgnore(filePath, ignorePatterns) {
114661
115995
  }
114662
115996
  return false;
114663
115997
  }
114664
- var import_fs13, import_path16, import_util12, import_child_process10, execAsync3;
115998
+ var import_fs13, import_path17, import_util12, import_child_process10, execAsync3;
114665
115999
  var init_file_lister = __esm({
114666
116000
  "src/utils/file-lister.js"() {
114667
116001
  "use strict";
114668
116002
  import_fs13 = __toESM(require("fs"), 1);
114669
- import_path16 = __toESM(require("path"), 1);
116003
+ import_path17 = __toESM(require("path"), 1);
114670
116004
  import_util12 = require("util");
114671
116005
  import_child_process10 = require("child_process");
114672
116006
  init_symlink_utils();
@@ -114684,12 +116018,12 @@ function initializeSimpleTelemetryFromOptions(options) {
114684
116018
  });
114685
116019
  return telemetry;
114686
116020
  }
114687
- var import_fs14, import_path17, SimpleTelemetry, SimpleAppTracer;
116021
+ var import_fs14, import_path18, SimpleTelemetry, SimpleAppTracer;
114688
116022
  var init_simpleTelemetry = __esm({
114689
116023
  "src/agent/simpleTelemetry.js"() {
114690
116024
  "use strict";
114691
116025
  import_fs14 = require("fs");
114692
- import_path17 = require("path");
116026
+ import_path18 = require("path");
114693
116027
  SimpleTelemetry = class {
114694
116028
  constructor(options = {}) {
114695
116029
  this.serviceName = options.serviceName || "probe-agent";
@@ -114703,7 +116037,7 @@ var init_simpleTelemetry = __esm({
114703
116037
  }
114704
116038
  initializeFileExporter() {
114705
116039
  try {
114706
- const dir = (0, import_path17.dirname)(this.filePath);
116040
+ const dir = (0, import_path18.dirname)(this.filePath);
114707
116041
  if (!(0, import_fs14.existsSync)(dir)) {
114708
116042
  (0, import_fs14.mkdirSync)(dir, { recursive: true });
114709
116043
  }
@@ -114768,20 +116102,20 @@ var init_simpleTelemetry = __esm({
114768
116102
  }
114769
116103
  async flush() {
114770
116104
  if (this.stream) {
114771
- return new Promise((resolve7) => {
114772
- this.stream.once("drain", resolve7);
116105
+ return new Promise((resolve8) => {
116106
+ this.stream.once("drain", resolve8);
114773
116107
  if (!this.stream.writableNeedDrain) {
114774
- resolve7();
116108
+ resolve8();
114775
116109
  }
114776
116110
  });
114777
116111
  }
114778
116112
  }
114779
116113
  async shutdown() {
114780
116114
  if (this.stream) {
114781
- return new Promise((resolve7) => {
116115
+ return new Promise((resolve8) => {
114782
116116
  this.stream.end(() => {
114783
116117
  console.log(`[SimpleTelemetry] File stream closed: ${this.filePath}`);
114784
- resolve7();
116118
+ resolve8();
114785
116119
  });
114786
116120
  });
114787
116121
  }
@@ -115140,6 +116474,7 @@ var init_hooks = __esm({
115140
116474
  var index_exports = {};
115141
116475
  __export(index_exports, {
115142
116476
  DEFAULT_SYSTEM_MESSAGE: () => DEFAULT_SYSTEM_MESSAGE,
116477
+ FileTracker: () => FileTracker,
115143
116478
  HOOK_TYPES: () => HOOK_TYPES,
115144
116479
  HookManager: () => HookManager,
115145
116480
  InMemoryStorageAdapter: () => InMemoryStorageAdapter,
@@ -115220,6 +116555,7 @@ var init_index = __esm({
115220
116555
  init_executePlan();
115221
116556
  init_bash();
115222
116557
  init_edit();
116558
+ init_fileTracker();
115223
116559
  init_ProbeAgent();
115224
116560
  init_simpleTelemetry();
115225
116561
  init_probeTool();
@@ -115233,6 +116569,7 @@ init_index();
115233
116569
  // Annotate the CommonJS export names for ESM import in node:
115234
116570
  0 && (module.exports = {
115235
116571
  DEFAULT_SYSTEM_MESSAGE,
116572
+ FileTracker,
115236
116573
  HOOK_TYPES,
115237
116574
  HookManager,
115238
116575
  InMemoryStorageAdapter,