@probelabs/probe 0.6.0-rc253 → 0.6.0-rc255

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-rc255-aarch64-apple-darwin.tar.gz +0 -0
  3. package/bin/binaries/probe-v0.6.0-rc255-aarch64-unknown-linux-musl.tar.gz +0 -0
  4. package/bin/binaries/probe-v0.6.0-rc255-x86_64-apple-darwin.tar.gz +0 -0
  5. package/bin/binaries/probe-v0.6.0-rc255-x86_64-pc-windows-msvc.zip +0 -0
  6. package/bin/binaries/probe-v0.6.0-rc255-x86_64-unknown-linux-musl.tar.gz +0 -0
  7. package/build/agent/ProbeAgent.d.ts +1 -1
  8. package/build/agent/ProbeAgent.js +51 -16
  9. package/build/agent/acp/tools.js +2 -1
  10. package/build/agent/acp/tools.test.js +2 -1
  11. package/build/agent/dsl/environment.js +19 -0
  12. package/build/agent/index.js +1512 -413
  13. package/build/agent/schemaUtils.js +91 -2
  14. package/build/agent/tools.js +0 -28
  15. package/build/delegate.js +3 -0
  16. package/build/index.js +2 -0
  17. package/build/tools/common.js +6 -5
  18. package/build/tools/edit.js +457 -65
  19. package/build/tools/executePlan.js +3 -1
  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 +1615 -517
  27. package/cjs/index.cjs +1643 -543
  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 +51 -16
  32. package/src/agent/acp/tools.js +2 -1
  33. package/src/agent/acp/tools.test.js +2 -1
  34. package/src/agent/dsl/environment.js +19 -0
  35. package/src/agent/index.js +14 -3
  36. package/src/agent/schemaUtils.js +91 -2
  37. package/src/agent/tools.js +0 -28
  38. package/src/delegate.js +3 -0
  39. package/src/index.js +2 -0
  40. package/src/tools/common.js +6 -5
  41. package/src/tools/edit.js +457 -65
  42. package/src/tools/executePlan.js +3 -1
  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-rc253-aarch64-apple-darwin.tar.gz +0 -0
  50. package/bin/binaries/probe-v0.6.0-rc253-aarch64-unknown-linux-musl.tar.gz +0 -0
  51. package/bin/binaries/probe-v0.6.0-rc253-x86_64-apple-darwin.tar.gz +0 -0
  52. package/bin/binaries/probe-v0.6.0-rc253-x86_64-pc-windows-msvc.zip +0 -0
  53. package/bin/binaries/probe-v0.6.0-rc253-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
  }
@@ -4186,7 +4186,7 @@ var require_headStream = __commonJS({
4186
4186
  if ((0, stream_type_check_1.isReadableStream)(stream2)) {
4187
4187
  return (0, headStream_browser_1.headStream)(stream2, bytes);
4188
4188
  }
4189
- return new Promise((resolve7, reject2) => {
4189
+ return new Promise((resolve8, reject2) => {
4190
4190
  const collector = new Collector();
4191
4191
  collector.limit = bytes;
4192
4192
  stream2.pipe(collector);
@@ -4197,7 +4197,7 @@ var require_headStream = __commonJS({
4197
4197
  collector.on("error", reject2);
4198
4198
  collector.on("finish", function() {
4199
4199
  const bytes2 = new Uint8Array(Buffer.concat(this.buffers));
4200
- resolve7(bytes2);
4200
+ resolve8(bytes2);
4201
4201
  });
4202
4202
  });
4203
4203
  };
@@ -4385,21 +4385,21 @@ var require_dist_cjs15 = __commonJS({
4385
4385
  let sendBody = true;
4386
4386
  if (!externalAgent && expect === "100-continue") {
4387
4387
  sendBody = await Promise.race([
4388
- new Promise((resolve7) => {
4389
- timeoutId = Number(timing.setTimeout(() => resolve7(true), Math.max(MIN_WAIT_TIME, maxContinueTimeoutMs)));
4388
+ new Promise((resolve8) => {
4389
+ timeoutId = Number(timing.setTimeout(() => resolve8(true), Math.max(MIN_WAIT_TIME, maxContinueTimeoutMs)));
4390
4390
  }),
4391
- new Promise((resolve7) => {
4391
+ new Promise((resolve8) => {
4392
4392
  httpRequest.on("continue", () => {
4393
4393
  timing.clearTimeout(timeoutId);
4394
- resolve7(true);
4394
+ resolve8(true);
4395
4395
  });
4396
4396
  httpRequest.on("response", () => {
4397
4397
  timing.clearTimeout(timeoutId);
4398
- resolve7(false);
4398
+ resolve8(false);
4399
4399
  });
4400
4400
  httpRequest.on("error", () => {
4401
4401
  timing.clearTimeout(timeoutId);
4402
- resolve7(false);
4402
+ resolve8(false);
4403
4403
  });
4404
4404
  })
4405
4405
  ]);
@@ -4471,13 +4471,13 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
4471
4471
  return socketWarningTimestamp;
4472
4472
  }
4473
4473
  constructor(options) {
4474
- this.configProvider = new Promise((resolve7, reject2) => {
4474
+ this.configProvider = new Promise((resolve8, reject2) => {
4475
4475
  if (typeof options === "function") {
4476
4476
  options().then((_options) => {
4477
- resolve7(this.resolveDefaultConfig(_options));
4477
+ resolve8(this.resolveDefaultConfig(_options));
4478
4478
  }).catch(reject2);
4479
4479
  } else {
4480
- resolve7(this.resolveDefaultConfig(options));
4480
+ resolve8(this.resolveDefaultConfig(options));
4481
4481
  }
4482
4482
  });
4483
4483
  }
@@ -4520,7 +4520,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
4520
4520
  const config = this.config;
4521
4521
  let writeRequestBodyPromise = void 0;
4522
4522
  const timeouts = [];
4523
- const resolve7 = async (arg) => {
4523
+ const resolve8 = async (arg) => {
4524
4524
  await writeRequestBodyPromise;
4525
4525
  timeouts.forEach(timing.clearTimeout);
4526
4526
  _resolve(arg);
@@ -4586,7 +4586,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
4586
4586
  headers: getTransformedHeaders(res.headers),
4587
4587
  body: res
4588
4588
  });
4589
- resolve7({ response: httpResponse });
4589
+ resolve8({ response: httpResponse });
4590
4590
  });
4591
4591
  req.on("error", (err) => {
4592
4592
  if (NODEJS_TIMEOUT_ERROR_CODES.includes(err.code)) {
@@ -4766,13 +4766,13 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
4766
4766
  return new _NodeHttp2Handler(instanceOrOptions);
4767
4767
  }
4768
4768
  constructor(options) {
4769
- this.configProvider = new Promise((resolve7, reject2) => {
4769
+ this.configProvider = new Promise((resolve8, reject2) => {
4770
4770
  if (typeof options === "function") {
4771
4771
  options().then((opts) => {
4772
- resolve7(opts || {});
4772
+ resolve8(opts || {});
4773
4773
  }).catch(reject2);
4774
4774
  } else {
4775
- resolve7(options || {});
4775
+ resolve8(options || {});
4776
4776
  }
4777
4777
  });
4778
4778
  }
@@ -4792,7 +4792,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
4792
4792
  return new Promise((_resolve, _reject) => {
4793
4793
  let fulfilled = false;
4794
4794
  let writeRequestBodyPromise = void 0;
4795
- const resolve7 = async (arg) => {
4795
+ const resolve8 = async (arg) => {
4796
4796
  await writeRequestBodyPromise;
4797
4797
  _resolve(arg);
4798
4798
  };
@@ -4848,7 +4848,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
4848
4848
  body: req
4849
4849
  });
4850
4850
  fulfilled = true;
4851
- resolve7({ response: httpResponse });
4851
+ resolve8({ response: httpResponse });
4852
4852
  if (disableConcurrentStreams) {
4853
4853
  session.close();
4854
4854
  this.connectionManager.deleteSession(authority, session);
@@ -4925,7 +4925,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
4925
4925
  if (isReadableStreamInstance(stream3)) {
4926
4926
  return collectReadableStream(stream3);
4927
4927
  }
4928
- return new Promise((resolve7, reject2) => {
4928
+ return new Promise((resolve8, reject2) => {
4929
4929
  const collector = new Collector();
4930
4930
  stream3.pipe(collector);
4931
4931
  stream3.on("error", (err) => {
@@ -4935,7 +4935,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
4935
4935
  collector.on("error", reject2);
4936
4936
  collector.on("finish", function() {
4937
4937
  const bytes = new Uint8Array(Buffer.concat(this.bufferedBytes));
4938
- resolve7(bytes);
4938
+ resolve8(bytes);
4939
4939
  });
4940
4940
  });
4941
4941
  };
@@ -4979,7 +4979,7 @@ var require_dist_cjs16 = __commonJS({
4979
4979
  return new Request(url, requestOptions);
4980
4980
  }
4981
4981
  function requestTimeout(timeoutInMs = 0) {
4982
- return new Promise((resolve7, reject2) => {
4982
+ return new Promise((resolve8, reject2) => {
4983
4983
  if (timeoutInMs) {
4984
4984
  setTimeout(() => {
4985
4985
  const timeoutError = new Error(`Request did not complete within ${timeoutInMs} ms`);
@@ -5097,7 +5097,7 @@ var require_dist_cjs16 = __commonJS({
5097
5097
  requestTimeout(requestTimeoutInMs)
5098
5098
  ];
5099
5099
  if (abortSignal) {
5100
- raceOfPromises.push(new Promise((resolve7, reject2) => {
5100
+ raceOfPromises.push(new Promise((resolve8, reject2) => {
5101
5101
  const onAbort = () => {
5102
5102
  const abortError = new Error("Request aborted");
5103
5103
  abortError.name = "AbortError";
@@ -5161,7 +5161,7 @@ var require_dist_cjs16 = __commonJS({
5161
5161
  return collected;
5162
5162
  }
5163
5163
  function readToBase64(blob) {
5164
- return new Promise((resolve7, reject2) => {
5164
+ return new Promise((resolve8, reject2) => {
5165
5165
  const reader = new FileReader();
5166
5166
  reader.onloadend = () => {
5167
5167
  if (reader.readyState !== 2) {
@@ -5170,7 +5170,7 @@ var require_dist_cjs16 = __commonJS({
5170
5170
  const result = reader.result ?? "";
5171
5171
  const commaIndex = result.indexOf(",");
5172
5172
  const dataOffset = commaIndex > -1 ? commaIndex + 1 : result.length;
5173
- resolve7(result.substring(dataOffset));
5173
+ resolve8(result.substring(dataOffset));
5174
5174
  };
5175
5175
  reader.onabort = () => reject2(new Error("Read aborted"));
5176
5176
  reader.onerror = () => reject2(reader.error);
@@ -6838,11 +6838,11 @@ function __metadata(metadataKey, metadataValue) {
6838
6838
  }
6839
6839
  function __awaiter(thisArg, _arguments, P, generator) {
6840
6840
  function adopt(value) {
6841
- return value instanceof P ? value : new P(function(resolve7) {
6842
- resolve7(value);
6841
+ return value instanceof P ? value : new P(function(resolve8) {
6842
+ resolve8(value);
6843
6843
  });
6844
6844
  }
6845
- return new (P || (P = Promise))(function(resolve7, reject2) {
6845
+ return new (P || (P = Promise))(function(resolve8, reject2) {
6846
6846
  function fulfilled(value) {
6847
6847
  try {
6848
6848
  step(generator.next(value));
@@ -6858,7 +6858,7 @@ function __awaiter(thisArg, _arguments, P, generator) {
6858
6858
  }
6859
6859
  }
6860
6860
  function step(result) {
6861
- result.done ? resolve7(result.value) : adopt(result.value).then(fulfilled, rejected);
6861
+ result.done ? resolve8(result.value) : adopt(result.value).then(fulfilled, rejected);
6862
6862
  }
6863
6863
  step((generator = generator.apply(thisArg, _arguments || [])).next());
6864
6864
  });
@@ -7049,14 +7049,14 @@ function __asyncValues(o5) {
7049
7049
  }, i5);
7050
7050
  function verb(n5) {
7051
7051
  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);
7052
+ return new Promise(function(resolve8, reject2) {
7053
+ v5 = o5[n5](v5), settle(resolve8, reject2, v5.done, v5.value);
7054
7054
  });
7055
7055
  };
7056
7056
  }
7057
- function settle(resolve7, reject2, d5, v5) {
7057
+ function settle(resolve8, reject2, d5, v5) {
7058
7058
  Promise.resolve(v5).then(function(v6) {
7059
- resolve7({ value: v6, done: d5 });
7059
+ resolve8({ value: v6, done: d5 });
7060
7060
  }, reject2);
7061
7061
  }
7062
7062
  }
@@ -17457,7 +17457,7 @@ var require_dist_cjs37 = __commonJS({
17457
17457
  this.sockets[url] = (this.sockets[url] ?? []).filter((socket) => ![WebSocket.CLOSING, WebSocket.CLOSED].includes(socket.readyState));
17458
17458
  }
17459
17459
  waitForReady(socket, connectionTimeout) {
17460
- return new Promise((resolve7, reject2) => {
17460
+ return new Promise((resolve8, reject2) => {
17461
17461
  const timeout = setTimeout(() => {
17462
17462
  this.removeNotUsableSockets(socket.url);
17463
17463
  reject2({
@@ -17469,7 +17469,7 @@ var require_dist_cjs37 = __commonJS({
17469
17469
  }, connectionTimeout);
17470
17470
  socket.onopen = () => {
17471
17471
  clearTimeout(timeout);
17472
- resolve7();
17472
+ resolve8();
17473
17473
  };
17474
17474
  });
17475
17475
  }
@@ -17522,8 +17522,8 @@ var require_dist_cjs37 = __commonJS({
17522
17522
  }
17523
17523
  return { done: item.done, value: item.value };
17524
17524
  }
17525
- return new Promise((resolve7, reject2) => {
17526
- pendingResolve = resolve7;
17525
+ return new Promise((resolve8, reject2) => {
17526
+ pendingResolve = resolve8;
17527
17527
  pendingReject = reject2;
17528
17528
  });
17529
17529
  }
@@ -18736,7 +18736,7 @@ var require_dist_cjs46 = __commonJS({
18736
18736
  this.refillTokenBucket();
18737
18737
  if (amount > this.currentCapacity) {
18738
18738
  const delay = (amount - this.currentCapacity) / this.fillRate * 1e3;
18739
- await new Promise((resolve7) => _DefaultRateLimiter.setTimeoutFn(resolve7, delay));
18739
+ await new Promise((resolve8) => _DefaultRateLimiter.setTimeoutFn(resolve8, delay));
18740
18740
  }
18741
18741
  this.currentCapacity = this.currentCapacity - amount;
18742
18742
  }
@@ -19071,7 +19071,7 @@ var require_dist_cjs47 = __commonJS({
19071
19071
  const delayFromResponse = getDelayFromRetryAfterHeader(err.$response);
19072
19072
  const delay = Math.max(delayFromResponse || 0, delayFromDecider);
19073
19073
  totalDelay += delay;
19074
- await new Promise((resolve7) => setTimeout(resolve7, delay));
19074
+ await new Promise((resolve8) => setTimeout(resolve8, delay));
19075
19075
  continue;
19076
19076
  }
19077
19077
  if (!err.$metadata) {
@@ -19229,7 +19229,7 @@ var require_dist_cjs47 = __commonJS({
19229
19229
  attempts = retryToken.getRetryCount();
19230
19230
  const delay = retryToken.getRetryDelay();
19231
19231
  totalRetryDelay += delay;
19232
- await new Promise((resolve7) => setTimeout(resolve7, delay));
19232
+ await new Promise((resolve8) => setTimeout(resolve8, delay));
19233
19233
  }
19234
19234
  }
19235
19235
  } else {
@@ -19381,7 +19381,7 @@ var require_package2 = __commonJS({
19381
19381
  module2.exports = {
19382
19382
  name: "@aws-sdk/client-bedrock-runtime",
19383
19383
  description: "AWS SDK for JavaScript Bedrock Runtime Client for Node.js, Browser and React Native",
19384
- version: "3.994.0",
19384
+ version: "3.995.0",
19385
19385
  scripts: {
19386
19386
  build: "concurrently 'yarn:build:types' 'yarn:build:es' && yarn build:cjs",
19387
19387
  "build:cjs": "node ../../scripts/compilation/inline client-bedrock-runtime",
@@ -19411,11 +19411,11 @@ var require_package2 = __commonJS({
19411
19411
  "@aws-sdk/middleware-user-agent": "^3.972.11",
19412
19412
  "@aws-sdk/middleware-websocket": "^3.972.6",
19413
19413
  "@aws-sdk/region-config-resolver": "^3.972.3",
19414
- "@aws-sdk/token-providers": "3.994.0",
19414
+ "@aws-sdk/token-providers": "3.995.0",
19415
19415
  "@aws-sdk/types": "^3.973.1",
19416
- "@aws-sdk/util-endpoints": "3.994.0",
19416
+ "@aws-sdk/util-endpoints": "3.995.0",
19417
19417
  "@aws-sdk/util-user-agent-browser": "^3.972.3",
19418
- "@aws-sdk/util-user-agent-node": "^3.972.9",
19418
+ "@aws-sdk/util-user-agent-node": "^3.972.10",
19419
19419
  "@smithy/config-resolver": "^4.4.6",
19420
19420
  "@smithy/core": "^3.23.2",
19421
19421
  "@smithy/eventstream-serde-browser": "^4.2.8",
@@ -19544,7 +19544,7 @@ var require_dist_cjs49 = __commonJS({
19544
19544
  var nodeConfigProvider = require_dist_cjs43();
19545
19545
  var urlParser = require_dist_cjs22();
19546
19546
  function httpRequest(options) {
19547
- return new Promise((resolve7, reject2) => {
19547
+ return new Promise((resolve8, reject2) => {
19548
19548
  const req = http.request({
19549
19549
  method: "GET",
19550
19550
  ...options,
@@ -19569,7 +19569,7 @@ var require_dist_cjs49 = __commonJS({
19569
19569
  chunks.push(chunk);
19570
19570
  });
19571
19571
  res.on("end", () => {
19572
- resolve7(buffer.Buffer.concat(chunks));
19572
+ resolve8(buffer.Buffer.concat(chunks));
19573
19573
  req.destroy();
19574
19574
  });
19575
19575
  });
@@ -19989,7 +19989,7 @@ var require_retry_wrapper = __commonJS({
19989
19989
  try {
19990
19990
  return await toRetry();
19991
19991
  } catch (e5) {
19992
- await new Promise((resolve7) => setTimeout(resolve7, delayMs));
19992
+ await new Promise((resolve8) => setTimeout(resolve8, delayMs));
19993
19993
  }
19994
19994
  }
19995
19995
  return await toRetry();
@@ -20297,6 +20297,15 @@ var require_dist_cjs51 = __commonJS({
20297
20297
  var os4 = require("os");
20298
20298
  var process2 = require("process");
20299
20299
  var middlewareUserAgent = require_dist_cjs29();
20300
+ var getRuntimeUserAgentPair = () => {
20301
+ const runtimesToCheck = ["deno", "bun", "llrt"];
20302
+ for (const runtime of runtimesToCheck) {
20303
+ if (process2.versions[runtime]) {
20304
+ return [`md/${runtime}`, process2.versions[runtime]];
20305
+ }
20306
+ }
20307
+ return ["md/nodejs", process2.versions.node];
20308
+ };
20300
20309
  var crtAvailability = {
20301
20310
  isCrtAvailable: false
20302
20311
  };
@@ -20307,13 +20316,14 @@ var require_dist_cjs51 = __commonJS({
20307
20316
  return null;
20308
20317
  };
20309
20318
  var createDefaultUserAgentProvider5 = ({ serviceId, clientVersion }) => {
20319
+ const runtimeUserAgentPair = getRuntimeUserAgentPair();
20310
20320
  return async (config) => {
20311
20321
  const sections = [
20312
20322
  ["aws-sdk-js", clientVersion],
20313
20323
  ["ua", "2.1"],
20314
20324
  [`os/${os4.platform()}`, os4.release()],
20315
20325
  ["lang/js"],
20316
- ["md/nodejs", `${process2.versions.node}`]
20326
+ runtimeUserAgentPair
20317
20327
  ];
20318
20328
  const crtAvailable = isCrtAvailable();
20319
20329
  if (crtAvailable) {
@@ -25876,8 +25886,8 @@ var require_dist_cjs66 = __commonJS({
25876
25886
  systemClockOffsetProvider: this.systemClockOffsetProvider
25877
25887
  });
25878
25888
  let resolvePipeline;
25879
- const pipelineError = new Promise((resolve7, reject2) => {
25880
- resolvePipeline = () => resolve7(void 0);
25889
+ const pipelineError = new Promise((resolve8, reject2) => {
25890
+ resolvePipeline = () => resolve8(void 0);
25881
25891
  node_stream.pipeline(payloadStream, signingStream, request.body, (err) => {
25882
25892
  if (err) {
25883
25893
  reject2(new Error(`Pipeline error in @aws-sdk/eventstream-handler-node: ${err.message}`, { cause: err }));
@@ -25983,7 +25993,7 @@ var init_package2 = __esm({
25983
25993
  "node_modules/@aws-sdk/token-providers/node_modules/@aws-sdk/nested-clients/package.json"() {
25984
25994
  package_default2 = {
25985
25995
  name: "@aws-sdk/nested-clients",
25986
- version: "3.994.0",
25996
+ version: "3.995.0",
25987
25997
  description: "Nested clients for AWS SDK packages.",
25988
25998
  main: "./dist-cjs/index.js",
25989
25999
  module: "./dist-es/index.js",
@@ -26019,9 +26029,9 @@ var init_package2 = __esm({
26019
26029
  "@aws-sdk/middleware-user-agent": "^3.972.11",
26020
26030
  "@aws-sdk/region-config-resolver": "^3.972.3",
26021
26031
  "@aws-sdk/types": "^3.973.1",
26022
- "@aws-sdk/util-endpoints": "3.994.0",
26032
+ "@aws-sdk/util-endpoints": "3.995.0",
26023
26033
  "@aws-sdk/util-user-agent-browser": "^3.972.3",
26024
- "@aws-sdk/util-user-agent-node": "^3.972.9",
26034
+ "@aws-sdk/util-user-agent-node": "^3.972.10",
26025
26035
  "@smithy/config-resolver": "^4.4.6",
26026
26036
  "@smithy/core": "^3.23.2",
26027
26037
  "@smithy/fetch-http-handler": "^5.3.9",
@@ -27431,7 +27441,7 @@ var require_dist_cjs69 = __commonJS({
27431
27441
  streamEnded = true;
27432
27442
  });
27433
27443
  while (!generationEnded) {
27434
- const value = await new Promise((resolve7) => setTimeout(() => resolve7(records.shift()), 0));
27444
+ const value = await new Promise((resolve8) => setTimeout(() => resolve8(records.shift()), 0));
27435
27445
  if (value) {
27436
27446
  yield value;
27437
27447
  }
@@ -37471,6 +37481,400 @@ var init_zod = __esm({
37471
37481
  }
37472
37482
  });
37473
37483
 
37484
+ // src/tools/fuzzyMatch.js
37485
+ function findFuzzyMatch(content, searchString) {
37486
+ if (!searchString || searchString.trim().length === 0) {
37487
+ return null;
37488
+ }
37489
+ const normalizedContent = content.replace(/\r\n/g, "\n");
37490
+ const normalizedSearch = searchString.replace(/\r\n/g, "\n");
37491
+ const contentLines = normalizedContent.split("\n");
37492
+ const searchLines = normalizedSearch.split("\n");
37493
+ const trimmed = lineTrimmedMatch(contentLines, searchLines);
37494
+ if (trimmed) return { ...trimmed, strategy: "line-trimmed" };
37495
+ const normalized = whitespaceNormalizedMatch(normalizedContent, normalizedSearch);
37496
+ if (normalized) return { ...normalized, strategy: "whitespace-normalized" };
37497
+ const indentFlex = indentFlexibleMatch(contentLines, searchLines);
37498
+ if (indentFlex) return { ...indentFlex, strategy: "indent-flexible" };
37499
+ return null;
37500
+ }
37501
+ function lineTrimmedMatch(contentLines, searchLines) {
37502
+ if (searchLines.length === 0) return null;
37503
+ const trimmedSearchLines = searchLines.map((line) => line.trim());
37504
+ if (trimmedSearchLines.every((line) => line === "")) return null;
37505
+ const windowSize = searchLines.length;
37506
+ const matches = [];
37507
+ for (let i5 = 0; i5 <= contentLines.length - windowSize; i5++) {
37508
+ let allMatch = true;
37509
+ for (let j5 = 0; j5 < windowSize; j5++) {
37510
+ if (contentLines[i5 + j5].trim() !== trimmedSearchLines[j5]) {
37511
+ allMatch = false;
37512
+ break;
37513
+ }
37514
+ }
37515
+ if (allMatch) {
37516
+ const matchedText = contentLines.slice(i5, i5 + windowSize).join("\n");
37517
+ matches.push(matchedText);
37518
+ }
37519
+ }
37520
+ if (matches.length === 0) return null;
37521
+ return {
37522
+ matchedText: matches[0],
37523
+ count: matches.length
37524
+ };
37525
+ }
37526
+ function whitespaceNormalizedMatch(content, search2) {
37527
+ if (!search2 || search2.trim().length === 0) return null;
37528
+ const { normalized: normContent, indexMap: contentMap } = buildNormalizedMap(content);
37529
+ const { normalized: normSearch } = buildNormalizedMap(search2);
37530
+ if (normSearch.length === 0) return null;
37531
+ const matches = [];
37532
+ let searchStart = 0;
37533
+ while (searchStart <= normContent.length - normSearch.length) {
37534
+ const idx = normContent.indexOf(normSearch, searchStart);
37535
+ if (idx === -1) break;
37536
+ const originalStart = contentMap[idx];
37537
+ const originalEnd = contentMap[idx + normSearch.length - 1];
37538
+ let actualEnd = originalEnd + 1;
37539
+ while (actualEnd < content.length && /[ \t]/.test(content[actualEnd]) && (actualEnd === originalEnd + 1 || /[ \t]/.test(content[actualEnd - 1]))) {
37540
+ if (contentMap.indexOf(actualEnd) > idx + normSearch.length - 1 || contentMap.indexOf(actualEnd) === -1) {
37541
+ break;
37542
+ }
37543
+ actualEnd++;
37544
+ }
37545
+ const matchedText = content.substring(originalStart, actualEnd);
37546
+ matches.push(matchedText);
37547
+ searchStart = idx + 1;
37548
+ }
37549
+ if (matches.length === 0) return null;
37550
+ return {
37551
+ matchedText: matches[0],
37552
+ count: matches.length
37553
+ };
37554
+ }
37555
+ function buildNormalizedMap(str) {
37556
+ const normalized = [];
37557
+ const indexMap = [];
37558
+ let i5 = 0;
37559
+ while (i5 < str.length) {
37560
+ const ch = str[i5];
37561
+ if (ch === " " || ch === " ") {
37562
+ normalized.push(" ");
37563
+ indexMap.push(i5);
37564
+ while (i5 < str.length && (str[i5] === " " || str[i5] === " ")) {
37565
+ i5++;
37566
+ }
37567
+ } else {
37568
+ normalized.push(ch);
37569
+ indexMap.push(i5);
37570
+ i5++;
37571
+ }
37572
+ }
37573
+ return {
37574
+ normalized: normalized.join(""),
37575
+ indexMap
37576
+ };
37577
+ }
37578
+ function indentFlexibleMatch(contentLines, searchLines) {
37579
+ if (searchLines.length === 0) return null;
37580
+ if (searchLines.every((line) => line.trim() === "")) return null;
37581
+ const searchMinIndent = getMinIndent(searchLines);
37582
+ const strippedSearch = searchLines.map((line) => stripIndent(line, searchMinIndent));
37583
+ const windowSize = searchLines.length;
37584
+ const matches = [];
37585
+ for (let i5 = 0; i5 <= contentLines.length - windowSize; i5++) {
37586
+ const windowLines = contentLines.slice(i5, i5 + windowSize);
37587
+ const windowMinIndent = getMinIndent(windowLines);
37588
+ const strippedWindow = windowLines.map((line) => stripIndent(line, windowMinIndent));
37589
+ let allMatch = true;
37590
+ for (let j5 = 0; j5 < windowSize; j5++) {
37591
+ if (strippedWindow[j5] !== strippedSearch[j5]) {
37592
+ allMatch = false;
37593
+ break;
37594
+ }
37595
+ }
37596
+ if (allMatch) {
37597
+ const matchedText = windowLines.join("\n");
37598
+ matches.push(matchedText);
37599
+ }
37600
+ }
37601
+ if (matches.length === 0) return null;
37602
+ return {
37603
+ matchedText: matches[0],
37604
+ count: matches.length
37605
+ };
37606
+ }
37607
+ function getMinIndent(lines) {
37608
+ let min = Infinity;
37609
+ for (const line of lines) {
37610
+ if (line.trim() === "") continue;
37611
+ const match2 = line.match(/^([ \t]*)/);
37612
+ if (match2) {
37613
+ min = Math.min(min, match2[1].length);
37614
+ }
37615
+ }
37616
+ return min === Infinity ? 0 : min;
37617
+ }
37618
+ function stripIndent(line, amount) {
37619
+ if (line.trim() === "") return "";
37620
+ if (amount <= 0) return line;
37621
+ return line.substring(Math.min(amount, line.length));
37622
+ }
37623
+ var init_fuzzyMatch = __esm({
37624
+ "src/tools/fuzzyMatch.js"() {
37625
+ "use strict";
37626
+ }
37627
+ });
37628
+
37629
+ // src/tools/symbolEdit.js
37630
+ async function findSymbol(filePath, symbolName, cwd) {
37631
+ try {
37632
+ const result = await extract({
37633
+ files: [`${filePath}#${symbolName}`],
37634
+ format: "json",
37635
+ json: true,
37636
+ cwd
37637
+ });
37638
+ if (!result || !result.results || result.results.length === 0) {
37639
+ return null;
37640
+ }
37641
+ const match2 = result.results[0];
37642
+ return {
37643
+ startLine: match2.lines[0],
37644
+ // 1-indexed
37645
+ endLine: match2.lines[1],
37646
+ // 1-indexed
37647
+ code: match2.code,
37648
+ nodeType: match2.node_type,
37649
+ file: match2.file
37650
+ };
37651
+ } catch (error2) {
37652
+ if (process.env.DEBUG === "1") {
37653
+ console.error(`[SymbolEdit] findSymbol error for "${symbolName}" in ${filePath}: ${error2.message}`);
37654
+ }
37655
+ return null;
37656
+ }
37657
+ }
37658
+ async function findAllSymbols(filePath, symbolName, cwd) {
37659
+ try {
37660
+ const result = await extract({
37661
+ files: [`${filePath}#${symbolName}`],
37662
+ format: "json",
37663
+ json: true,
37664
+ cwd
37665
+ });
37666
+ if (!result || !result.results || result.results.length === 0) {
37667
+ return [];
37668
+ }
37669
+ return result.results.map((match2) => ({
37670
+ startLine: match2.lines[0],
37671
+ endLine: match2.lines[1],
37672
+ code: match2.code,
37673
+ nodeType: match2.node_type,
37674
+ file: match2.file,
37675
+ qualifiedName: match2.symbol_signature || symbolName
37676
+ }));
37677
+ } catch (error2) {
37678
+ if (process.env.DEBUG === "1") {
37679
+ console.error(`[SymbolEdit] findAllSymbols error for "${symbolName}" in ${filePath}: ${error2.message}`);
37680
+ }
37681
+ return [];
37682
+ }
37683
+ }
37684
+ function detectBaseIndent(code) {
37685
+ const lines = code.split("\n");
37686
+ for (const line of lines) {
37687
+ if (line.trim().length > 0) {
37688
+ const match2 = line.match(/^(\s*)/);
37689
+ return match2 ? match2[1] : "";
37690
+ }
37691
+ }
37692
+ return "";
37693
+ }
37694
+ function reindent(newContent, targetIndent) {
37695
+ const lines = newContent.split("\n");
37696
+ const sourceIndent = detectBaseIndent(newContent);
37697
+ return lines.map((line) => {
37698
+ if (line.trim().length === 0) {
37699
+ return "";
37700
+ }
37701
+ if (line.startsWith(sourceIndent)) {
37702
+ return targetIndent + line.slice(sourceIndent.length);
37703
+ }
37704
+ return line;
37705
+ }).join("\n");
37706
+ }
37707
+ var init_symbolEdit = __esm({
37708
+ "src/tools/symbolEdit.js"() {
37709
+ "use strict";
37710
+ init_extract();
37711
+ }
37712
+ });
37713
+
37714
+ // src/tools/hashline.js
37715
+ function computeLineHash(line) {
37716
+ const stripped = (line || "").replace(/\s+/g, "");
37717
+ let h5 = 5381;
37718
+ for (let i5 = 0; i5 < stripped.length; i5++) {
37719
+ h5 = (h5 << 5) + h5 + stripped.charCodeAt(i5) & 4294967295;
37720
+ }
37721
+ return ((h5 >>> 0) % 256).toString(16).padStart(2, "0");
37722
+ }
37723
+ function parseLineRef(ref2) {
37724
+ if (ref2 === void 0 || ref2 === null) return null;
37725
+ const str = String(ref2).trim();
37726
+ if (!str) return null;
37727
+ const hashMatch = str.match(/^(\d+):([0-9a-fA-F]{2})$/);
37728
+ if (hashMatch) {
37729
+ const line = parseInt(hashMatch[1], 10);
37730
+ if (line < 1 || !isFinite(line)) return null;
37731
+ return { line, hash: hashMatch[2].toLowerCase() };
37732
+ }
37733
+ const lineMatch = str.match(/^(\d+)$/);
37734
+ if (lineMatch) {
37735
+ const line = parseInt(lineMatch[1], 10);
37736
+ if (line < 1 || !isFinite(line)) return null;
37737
+ return { line, hash: null };
37738
+ }
37739
+ return null;
37740
+ }
37741
+ function validateLineHash(lineNum, hash, fileLines) {
37742
+ const idx = lineNum - 1;
37743
+ if (idx < 0 || idx >= fileLines.length) {
37744
+ return { valid: false, actualHash: "", actualContent: "" };
37745
+ }
37746
+ const actualContent = fileLines[idx];
37747
+ const actualHash = computeLineHash(actualContent);
37748
+ return {
37749
+ valid: actualHash === hash.toLowerCase(),
37750
+ actualHash,
37751
+ actualContent
37752
+ };
37753
+ }
37754
+ function annotateOutputWithHashes(output) {
37755
+ if (!output || typeof output !== "string") return output;
37756
+ return output.split("\n").map((line) => {
37757
+ const cleanLine = line.endsWith("\r") ? line.slice(0, -1) : line;
37758
+ const match2 = cleanLine.match(/^(\s*)(\d+)(\s*\|)(.*)$/);
37759
+ if (!match2) return line;
37760
+ const [, prefix, lineNum, pipeSection, content] = match2;
37761
+ const hash = computeLineHash(content);
37762
+ const cr = line.endsWith("\r") ? "\r" : "";
37763
+ return `${prefix}${lineNum}:${hash}${pipeSection}${content}${cr}`;
37764
+ }).join("\n");
37765
+ }
37766
+ function stripHashlinePrefixes(text) {
37767
+ if (!text || typeof text !== "string") return { cleaned: text || "", stripped: false };
37768
+ const lines = text.split("\n");
37769
+ if (lines.length === 0) return { cleaned: "", stripped: false };
37770
+ const nonEmptyLines = lines.filter((l5) => l5.trim().length > 0);
37771
+ if (nonEmptyLines.length === 0) return { cleaned: text, stripped: false };
37772
+ const prefixPattern = /^\s*\d+(?::[0-9a-fA-F]{2})?\s*\|\s?/;
37773
+ const matchCount = nonEmptyLines.filter((l5) => prefixPattern.test(l5)).length;
37774
+ if (matchCount / nonEmptyLines.length <= 0.5) {
37775
+ return { cleaned: text, stripped: false };
37776
+ }
37777
+ const cleaned = lines.map((line) => {
37778
+ if (line.trim().length === 0) return line;
37779
+ return line.replace(prefixPattern, "");
37780
+ }).join("\n");
37781
+ return { cleaned, stripped: true };
37782
+ }
37783
+ var init_hashline = __esm({
37784
+ "src/tools/hashline.js"() {
37785
+ "use strict";
37786
+ }
37787
+ });
37788
+
37789
+ // src/tools/lineEditHeuristics.js
37790
+ function stripEchoedBoundaries(newStr, fileLines, startLine, endLine, position) {
37791
+ const modifications = [];
37792
+ let lines = newStr.split("\n");
37793
+ if (lines.length === 0) return { result: newStr, modifications };
37794
+ if (position === "after") {
37795
+ const anchorIdx = startLine - 1;
37796
+ if (anchorIdx >= 0 && anchorIdx < fileLines.length) {
37797
+ const anchorTrimmed = fileLines[anchorIdx].trim();
37798
+ if (anchorTrimmed.length > 0 && lines.length > 0 && lines[0].trim() === anchorTrimmed) {
37799
+ lines = lines.slice(1);
37800
+ modifications.push("stripped echoed anchor line (insert-after)");
37801
+ }
37802
+ }
37803
+ } else if (position === "before") {
37804
+ const anchorIdx = startLine - 1;
37805
+ if (anchorIdx >= 0 && anchorIdx < fileLines.length) {
37806
+ const anchorTrimmed = fileLines[anchorIdx].trim();
37807
+ if (anchorTrimmed.length > 0 && lines.length > 0 && lines[lines.length - 1].trim() === anchorTrimmed) {
37808
+ lines = lines.slice(0, -1);
37809
+ modifications.push("stripped echoed anchor line (insert-before)");
37810
+ }
37811
+ }
37812
+ } else {
37813
+ const beforeIdx = startLine - 2;
37814
+ if (beforeIdx >= 0 && beforeIdx < fileLines.length) {
37815
+ const beforeTrimmed = fileLines[beforeIdx].trim();
37816
+ if (beforeTrimmed.length > 0 && lines.length > 0 && lines[0].trim() === beforeTrimmed) {
37817
+ lines = lines.slice(1);
37818
+ modifications.push("stripped echoed line before range");
37819
+ }
37820
+ }
37821
+ const afterIdx = endLine;
37822
+ if (afterIdx >= 0 && afterIdx < fileLines.length) {
37823
+ const afterTrimmed = fileLines[afterIdx].trim();
37824
+ if (afterTrimmed.length > 0 && lines.length > 0 && lines[lines.length - 1].trim() === afterTrimmed) {
37825
+ lines = lines.slice(0, -1);
37826
+ modifications.push("stripped echoed line after range");
37827
+ }
37828
+ }
37829
+ }
37830
+ return { result: lines.join("\n"), modifications };
37831
+ }
37832
+ function restoreIndentation(newStr, originalLines) {
37833
+ const modifications = [];
37834
+ if (!newStr || !originalLines || originalLines.length === 0) {
37835
+ return { result: newStr || "", modifications };
37836
+ }
37837
+ const originalCode = originalLines.join("\n");
37838
+ const targetIndent = detectBaseIndent(originalCode);
37839
+ const newIndent = detectBaseIndent(newStr);
37840
+ if (targetIndent !== newIndent) {
37841
+ const reindented = reindent(newStr, targetIndent);
37842
+ if (reindented !== newStr) {
37843
+ modifications.push(`reindented from "${newIndent}" to "${targetIndent}"`);
37844
+ return { result: reindented, modifications };
37845
+ }
37846
+ }
37847
+ return { result: newStr, modifications };
37848
+ }
37849
+ function cleanNewString(newStr, fileLines, startLine, endLine, position) {
37850
+ const modifications = [];
37851
+ if (!newStr && newStr !== "") return { cleaned: "", modifications };
37852
+ const { cleaned: afterPrefixes, stripped } = stripHashlinePrefixes(newStr);
37853
+ if (stripped) modifications.push("stripped line-number prefixes");
37854
+ const { result: afterEchoes, modifications: echoMods } = stripEchoedBoundaries(
37855
+ afterPrefixes,
37856
+ fileLines,
37857
+ startLine,
37858
+ endLine,
37859
+ position
37860
+ );
37861
+ modifications.push(...echoMods);
37862
+ if (!position) {
37863
+ const originalLines = fileLines.slice(startLine - 1, endLine);
37864
+ const { result: afterIndent, modifications: indentMods } = restoreIndentation(afterEchoes, originalLines);
37865
+ modifications.push(...indentMods);
37866
+ return { cleaned: afterIndent, modifications };
37867
+ }
37868
+ return { cleaned: afterEchoes, modifications };
37869
+ }
37870
+ var init_lineEditHeuristics = __esm({
37871
+ "src/tools/lineEditHeuristics.js"() {
37872
+ "use strict";
37873
+ init_symbolEdit();
37874
+ init_hashline();
37875
+ }
37876
+ });
37877
+
37474
37878
  // src/tools/edit.js
37475
37879
  function isPathAllowed(filePath, allowedFolders) {
37476
37880
  if (!allowedFolders || allowedFolders.length === 0) {
@@ -37494,6 +37898,174 @@ function parseFileToolOptions(options = {}) {
37494
37898
  workspaceRoot: options.workspaceRoot || options.cwd || allowedFolders.length > 0 && allowedFolders[0] || process.cwd()
37495
37899
  };
37496
37900
  }
37901
+ async function handleSymbolEdit({ resolvedPath: resolvedPath2, file_path, symbol: symbol15, new_string, position, debug, cwd, fileTracker }) {
37902
+ if (typeof symbol15 !== "string" || symbol15.trim() === "") {
37903
+ 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.';
37904
+ }
37905
+ if (position !== void 0 && position !== null && position !== "before" && position !== "after") {
37906
+ 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.';
37907
+ }
37908
+ const allMatches = await findAllSymbols(resolvedPath2, symbol15, cwd || process.cwd());
37909
+ if (allMatches.length === 0) {
37910
+ 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.`;
37911
+ }
37912
+ if (allMatches.length > 1) {
37913
+ const suggestions = allMatches.map(
37914
+ (m5) => ` - ${m5.qualifiedName} (${m5.nodeType}, line ${m5.startLine})`
37915
+ ).join("\n");
37916
+ return `Error editing ${file_path}: Found ${allMatches.length} symbols named "${symbol15}". Use a qualified name to specify which one:
37917
+ ${suggestions}
37918
+
37919
+ Example: <edit><file_path>${file_path}</file_path><symbol>${allMatches[0].qualifiedName}</symbol><new_string>...</new_string></edit>`;
37920
+ }
37921
+ const symbolInfo = allMatches[0];
37922
+ if (fileTracker) {
37923
+ const check = fileTracker.checkSymbolContent(resolvedPath2, symbol15, symbolInfo.code);
37924
+ if (!check.ok && check.reason === "stale") {
37925
+ return `Error editing ${file_path}: Symbol "${symbol15}" has changed since you last read it. Use extract to re-read the current content, then retry.
37926
+
37927
+ Example: <extract><targets>${file_path}#${symbol15}</targets></extract>`;
37928
+ }
37929
+ }
37930
+ const content = await import_fs4.promises.readFile(resolvedPath2, "utf-8");
37931
+ const lines = content.split("\n");
37932
+ if (position) {
37933
+ const refIndent = detectBaseIndent(symbolInfo.code);
37934
+ const reindented = reindent(new_string, refIndent);
37935
+ const newLines = reindented.split("\n");
37936
+ if (position === "after") {
37937
+ lines.splice(symbolInfo.endLine, 0, "", ...newLines);
37938
+ } else {
37939
+ lines.splice(symbolInfo.startLine - 1, 0, ...newLines, "");
37940
+ }
37941
+ await import_fs4.promises.writeFile(resolvedPath2, lines.join("\n"), "utf-8");
37942
+ if (fileTracker) {
37943
+ const updated = await findSymbol(resolvedPath2, symbol15, cwd || process.cwd());
37944
+ if (updated) {
37945
+ fileTracker.trackSymbolAfterWrite(resolvedPath2, symbol15, updated.code, updated.startLine, updated.endLine);
37946
+ }
37947
+ fileTracker.markFileSeen(resolvedPath2);
37948
+ }
37949
+ const insertLine = position === "after" ? symbolInfo.endLine + 1 : symbolInfo.startLine;
37950
+ if (debug) {
37951
+ console.error(`[Edit] Successfully inserted ${newLines.length} lines ${position} "${symbol15}" at line ${insertLine} in ${resolvedPath2}`);
37952
+ }
37953
+ return `Successfully inserted ${newLines.length} lines ${position} symbol "${symbol15}" in ${file_path} (at line ${insertLine})`;
37954
+ } else {
37955
+ const originalIndent = detectBaseIndent(symbolInfo.code);
37956
+ const reindented = reindent(new_string, originalIndent);
37957
+ const newLines = reindented.split("\n");
37958
+ lines.splice(symbolInfo.startLine - 1, symbolInfo.endLine - symbolInfo.startLine + 1, ...newLines);
37959
+ await import_fs4.promises.writeFile(resolvedPath2, lines.join("\n"), "utf-8");
37960
+ if (fileTracker) {
37961
+ const updated = await findSymbol(resolvedPath2, symbol15, cwd || process.cwd());
37962
+ if (updated) {
37963
+ fileTracker.trackSymbolAfterWrite(resolvedPath2, symbol15, updated.code, updated.startLine, updated.endLine);
37964
+ }
37965
+ fileTracker.markFileSeen(resolvedPath2);
37966
+ }
37967
+ if (debug) {
37968
+ console.error(`[Edit] Successfully replaced symbol "${symbol15}" in ${resolvedPath2} (lines ${symbolInfo.startLine}-${symbolInfo.endLine})`);
37969
+ }
37970
+ return `Successfully replaced symbol "${symbol15}" in ${file_path} (was lines ${symbolInfo.startLine}-${symbolInfo.endLine}, now ${newLines.length} lines)`;
37971
+ }
37972
+ }
37973
+ function buildLineEditResponse(file_path, startLine, endLine, newLineCount, updatedLines, insertOffset, action, heuristicMods) {
37974
+ const contextBefore = 1;
37975
+ const contextAfter = 1;
37976
+ const contextStart = Math.max(0, insertOffset - contextBefore);
37977
+ const contextEnd = Math.min(updatedLines.length, insertOffset + newLineCount + contextAfter);
37978
+ let context = "Context:\n";
37979
+ for (let i5 = contextStart; i5 < contextEnd; i5++) {
37980
+ const lineNum = i5 + 1;
37981
+ const hash = computeLineHash(updatedLines[i5]);
37982
+ const isNew = i5 >= insertOffset && i5 < insertOffset + newLineCount;
37983
+ const marker15 = isNew ? ">" : " ";
37984
+ context += `${marker15} ${lineNum}:${hash} | ${updatedLines[i5]}
37985
+ `;
37986
+ }
37987
+ let msg = `Successfully edited ${file_path} (${action})`;
37988
+ if (heuristicMods.length > 0) {
37989
+ msg += ` [auto-corrected: ${heuristicMods.join(", ")}]`;
37990
+ }
37991
+ msg += "\n" + context;
37992
+ return msg;
37993
+ }
37994
+ async function handleLineEdit({ resolvedPath: resolvedPath2, file_path, start_line, end_line, new_string, position, debug, fileTracker }) {
37995
+ const startRef = parseLineRef(start_line);
37996
+ if (!startRef) {
37997
+ 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.`;
37998
+ }
37999
+ let endRef = null;
38000
+ if (end_line !== void 0 && end_line !== null) {
38001
+ endRef = parseLineRef(end_line);
38002
+ if (!endRef) {
38003
+ 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.`;
38004
+ }
38005
+ }
38006
+ const startLine = startRef.line;
38007
+ const endLine = endRef ? endRef.line : startLine;
38008
+ if (endLine < startLine) {
38009
+ return `Error editing file: end_line (${endLine}) must be >= start_line (${startLine}).`;
38010
+ }
38011
+ if (position !== void 0 && position !== null && position !== "before" && position !== "after") {
38012
+ 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.';
38013
+ }
38014
+ const content = await import_fs4.promises.readFile(resolvedPath2, "utf-8");
38015
+ const fileLines = content.split("\n");
38016
+ if (startLine > fileLines.length) {
38017
+ return `Error editing file: Line ${startLine} is beyond file length (${fileLines.length} lines). Use 'extract' to read the current file content.`;
38018
+ }
38019
+ if (endLine > fileLines.length) {
38020
+ return `Error editing file: Line ${endLine} is beyond file length (${fileLines.length} lines). Use 'extract' to read the current file content.`;
38021
+ }
38022
+ if (startRef.hash) {
38023
+ const validation = validateLineHash(startLine, startRef.hash, fileLines);
38024
+ if (!validation.valid) {
38025
+ 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.`;
38026
+ }
38027
+ }
38028
+ if (endRef && endRef.hash) {
38029
+ const validation = validateLineHash(endLine, endRef.hash, fileLines);
38030
+ if (!validation.valid) {
38031
+ 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.`;
38032
+ }
38033
+ }
38034
+ const { cleaned, modifications } = cleanNewString(new_string, fileLines, startLine, endLine, position);
38035
+ if (debug) {
38036
+ if (modifications.length > 0) {
38037
+ console.error(`[Edit] Heuristic corrections: ${modifications.join(", ")}`);
38038
+ }
38039
+ }
38040
+ const newLines = cleaned === "" ? [] : cleaned.split("\n");
38041
+ if (position === "after") {
38042
+ fileLines.splice(startLine, 0, ...newLines);
38043
+ await import_fs4.promises.writeFile(resolvedPath2, fileLines.join("\n"), "utf-8");
38044
+ if (fileTracker) await fileTracker.trackFileAfterWrite(resolvedPath2);
38045
+ const action = `${newLines.length} line${newLines.length !== 1 ? "s" : ""} inserted after line ${startLine}`;
38046
+ return buildLineEditResponse(file_path, startLine, startLine, newLines.length, fileLines, startLine, action, modifications);
38047
+ } else if (position === "before") {
38048
+ fileLines.splice(startLine - 1, 0, ...newLines);
38049
+ await import_fs4.promises.writeFile(resolvedPath2, fileLines.join("\n"), "utf-8");
38050
+ if (fileTracker) await fileTracker.trackFileAfterWrite(resolvedPath2);
38051
+ const action = `${newLines.length} line${newLines.length !== 1 ? "s" : ""} inserted before line ${startLine}`;
38052
+ return buildLineEditResponse(file_path, startLine, startLine, newLines.length, fileLines, startLine - 1, action, modifications);
38053
+ } else {
38054
+ const replacedCount = endLine - startLine + 1;
38055
+ fileLines.splice(startLine - 1, replacedCount, ...newLines);
38056
+ await import_fs4.promises.writeFile(resolvedPath2, fileLines.join("\n"), "utf-8");
38057
+ if (fileTracker) await fileTracker.trackFileAfterWrite(resolvedPath2);
38058
+ let action;
38059
+ if (newLines.length === 0) {
38060
+ action = `${replacedCount} line${replacedCount !== 1 ? "s" : ""} deleted (lines ${startLine}-${endLine})`;
38061
+ } else if (startLine === endLine) {
38062
+ action = `line ${startLine} replaced with ${newLines.length} line${newLines.length !== 1 ? "s" : ""}`;
38063
+ } else {
38064
+ action = `lines ${startLine}-${endLine} replaced with ${newLines.length} line${newLines.length !== 1 ? "s" : ""}`;
38065
+ }
38066
+ return buildLineEditResponse(file_path, startLine, endLine, newLines.length, fileLines, startLine - 1, action, modifications);
38067
+ }
38068
+ }
37497
38069
  var import_ai, import_fs4, import_path5, import_fs5, editTool, createTool, editSchema, createSchema, editDescription, createDescription, editToolDefinition, createToolDefinition;
37498
38070
  var init_edit = __esm({
37499
38071
  "src/tools/edit.js"() {
@@ -37503,24 +38075,31 @@ var init_edit = __esm({
37503
38075
  import_path5 = require("path");
37504
38076
  import_fs5 = require("fs");
37505
38077
  init_path_validation();
38078
+ init_fuzzyMatch();
38079
+ init_symbolEdit();
38080
+ init_hashline();
38081
+ init_lineEditHeuristics();
37506
38082
  editTool = (options = {}) => {
37507
38083
  const { debug, allowedFolders, cwd, workspaceRoot } = parseFileToolOptions(options);
37508
38084
  return (0, import_ai.tool)({
37509
38085
  name: "edit",
37510
- description: `Edit files using exact string replacement (Claude Code style).
38086
+ description: `Edit files using text replacement, AST-aware symbol operations, or line-targeted editing.
37511
38087
 
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.
38088
+ Modes:
38089
+ 1. Text edit: Provide old_string + new_string to find and replace text (with fuzzy matching fallback)
38090
+ 2. Symbol replace: Provide symbol + new_string to replace an entire function/class/method by name
38091
+ 3. Symbol insert: Provide symbol + new_string + position to insert code before/after a symbol
38092
+ 4. Line-targeted edit: Provide start_line + new_string to edit by line number (from extract/search output)
37513
38093
 
37514
38094
  Parameters:
37515
38095
  - 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`,
38096
+ - new_string: Replacement text or new code content
38097
+ - old_string: (optional) Text to find and replace. If omitted, symbol or start_line must be provided.
38098
+ - replace_all: (optional) Replace all occurrences (text mode only)
38099
+ - symbol: (optional) Symbol name for AST-aware editing (e.g. "myFunction", "MyClass.myMethod")
38100
+ - position: (optional) "before" or "after" \u2014 insert code near a symbol or line instead of replacing it
38101
+ - start_line: (optional) Line reference (e.g. "42" or "42:ab") for line-targeted editing
38102
+ - end_line: (optional) End of line range, inclusive (e.g. "55" or "55:cd")`,
37524
38103
  inputSchema: {
37525
38104
  type: "object",
37526
38105
  properties: {
@@ -37530,30 +38109,44 @@ Important:
37530
38109
  },
37531
38110
  old_string: {
37532
38111
  type: "string",
37533
- description: "Exact text to find and replace"
38112
+ description: "Text to find and replace (for text-based editing)"
37534
38113
  },
37535
38114
  new_string: {
37536
38115
  type: "string",
37537
- description: "Text to replace with"
38116
+ description: "Replacement text or new code content"
37538
38117
  },
37539
38118
  replace_all: {
37540
38119
  type: "boolean",
37541
- description: "Replace all occurrences (default: false)",
38120
+ description: "Replace all occurrences (default: false, text mode only)",
37542
38121
  default: false
38122
+ },
38123
+ symbol: {
38124
+ type: "string",
38125
+ description: 'Symbol name for AST-aware editing (e.g. "myFunction", "MyClass.myMethod")'
38126
+ },
38127
+ position: {
38128
+ type: "string",
38129
+ enum: ["before", "after"],
38130
+ description: "Insert before/after symbol or line (requires symbol or start_line, omit to replace)"
38131
+ },
38132
+ start_line: {
38133
+ type: "string",
38134
+ description: 'Line reference for line-targeted editing (e.g. "42" or "42:ab" with hash)'
38135
+ },
38136
+ end_line: {
38137
+ type: "string",
38138
+ description: 'End of line range, inclusive (e.g. "55" or "55:cd"). Defaults to start_line.'
37543
38139
  }
37544
38140
  },
37545
- required: ["file_path", "old_string", "new_string"]
38141
+ required: ["file_path", "new_string"]
37546
38142
  },
37547
- execute: async ({ file_path, old_string, new_string, replace_all = false }) => {
38143
+ execute: async ({ file_path, old_string, new_string, replace_all = false, symbol: symbol15, position, start_line, end_line }) => {
37548
38144
  try {
37549
38145
  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`;
38146
+ 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
38147
  }
37555
38148
  if (new_string === void 0 || new_string === null || typeof new_string !== "string") {
37556
- return `Error editing file: Invalid new_string - must be a string`;
38149
+ 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
38150
  }
37558
38151
  const resolvedPath2 = (0, import_path5.isAbsolute)(file_path) ? file_path : (0, import_path5.resolve)(cwd || process.cwd(), file_path);
37559
38152
  if (debug) {
@@ -37561,34 +38154,64 @@ Important:
37561
38154
  }
37562
38155
  if (!isPathAllowed(resolvedPath2, allowedFolders)) {
37563
38156
  const relativePath = toRelativePath(resolvedPath2, workspaceRoot);
37564
- return `Error editing file: Permission denied - ${relativePath} is outside allowed directories`;
38157
+ return `Error editing file: Permission denied - ${relativePath} is outside allowed directories. Use a file path within the project workspace.`;
37565
38158
  }
37566
38159
  if (!(0, import_fs5.existsSync)(resolvedPath2)) {
37567
- return `Error editing file: File not found - ${file_path}`;
38160
+ 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.`;
38161
+ }
38162
+ if (options.fileTracker && !options.fileTracker.isFileSeen(resolvedPath2)) {
38163
+ const displayPath = toRelativePath(resolvedPath2, workspaceRoot);
38164
+ 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.
38165
+
38166
+ Example: <extract><targets>${displayPath}</targets></extract>`;
38167
+ }
38168
+ if (symbol15 !== void 0 && symbol15 !== null) {
38169
+ return await handleSymbolEdit({ resolvedPath: resolvedPath2, file_path, symbol: symbol15, new_string, position, debug, cwd, fileTracker: options.fileTracker });
38170
+ }
38171
+ if (start_line !== void 0 && start_line !== null) {
38172
+ return await handleLineEdit({ resolvedPath: resolvedPath2, file_path, start_line, end_line, new_string, position, debug, fileTracker: options.fileTracker });
38173
+ }
38174
+ if (old_string === void 0 || old_string === null) {
38175
+ 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").';
38176
+ }
38177
+ if (typeof old_string !== "string") {
38178
+ 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
38179
  }
37569
38180
  const content = await import_fs4.promises.readFile(resolvedPath2, "utf-8");
38181
+ let matchTarget = old_string;
38182
+ let matchStrategy = "exact";
37570
38183
  if (!content.includes(old_string)) {
37571
- return `Error editing file: String not found - the specified old_string was not found in ${file_path}`;
38184
+ const fuzzy = findFuzzyMatch(content, old_string);
38185
+ if (!fuzzy) {
38186
+ 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.`;
38187
+ }
38188
+ matchTarget = fuzzy.matchedText;
38189
+ matchStrategy = fuzzy.strategy;
38190
+ if (debug) {
38191
+ console.error(`[Edit] Exact match failed, used ${matchStrategy} matching`);
38192
+ }
37572
38193
  }
37573
- const occurrences = content.split(old_string).length - 1;
38194
+ const occurrences = content.split(matchTarget).length - 1;
37574
38195
  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.`;
38196
+ 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
38197
  }
37577
38198
  let newContent;
37578
38199
  if (replace_all) {
37579
- newContent = content.replaceAll(old_string, new_string);
38200
+ newContent = content.replaceAll(matchTarget, new_string);
37580
38201
  } else {
37581
- newContent = content.replace(old_string, new_string);
38202
+ newContent = content.replace(matchTarget, new_string);
37582
38203
  }
37583
38204
  if (newContent === content) {
37584
- return `Error editing file: No changes made - old_string and new_string might be the same`;
38205
+ 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
38206
  }
37586
38207
  await import_fs4.promises.writeFile(resolvedPath2, newContent, "utf-8");
38208
+ if (options.fileTracker) await options.fileTracker.trackFileAfterWrite(resolvedPath2);
37587
38209
  const replacedCount = replace_all ? occurrences : 1;
37588
38210
  if (debug) {
37589
38211
  console.error(`[Edit] Successfully edited ${resolvedPath2}, replaced ${replacedCount} occurrence(s)`);
37590
38212
  }
37591
- return `Successfully edited ${file_path} (${replacedCount} replacement${replacedCount !== 1 ? "s" : ""})`;
38213
+ const strategyNote = matchStrategy !== "exact" ? `, matched via ${matchStrategy}` : "";
38214
+ return `Successfully edited ${file_path} (${replacedCount} replacement${replacedCount !== 1 ? "s" : ""}${strategyNote})`;
37592
38215
  } catch (error2) {
37593
38216
  console.error("[Edit] Error:", error2);
37594
38217
  return `Error editing file: ${error2.message}`;
@@ -37635,10 +38258,10 @@ Important:
37635
38258
  execute: async ({ file_path, content, overwrite = false }) => {
37636
38259
  try {
37637
38260
  if (!file_path || typeof file_path !== "string" || file_path.trim() === "") {
37638
- return `Error creating file: Invalid file_path - must be a non-empty string`;
38261
+ 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
38262
  }
37640
38263
  if (content === void 0 || content === null || typeof content !== "string") {
37641
- return `Error creating file: Invalid content - must be a string`;
38264
+ 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
38265
  }
37643
38266
  const resolvedPath2 = (0, import_path5.isAbsolute)(file_path) ? file_path : (0, import_path5.resolve)(cwd || process.cwd(), file_path);
37644
38267
  if (debug) {
@@ -37646,15 +38269,17 @@ Important:
37646
38269
  }
37647
38270
  if (!isPathAllowed(resolvedPath2, allowedFolders)) {
37648
38271
  const relativePath = toRelativePath(resolvedPath2, workspaceRoot);
37649
- return `Error creating file: Permission denied - ${relativePath} is outside allowed directories`;
38272
+ return `Error creating file: Permission denied - ${relativePath} is outside allowed directories. Use a file path within the project workspace.`;
37650
38273
  }
37651
38274
  if ((0, import_fs5.existsSync)(resolvedPath2) && !overwrite) {
37652
38275
  return `Error creating file: File already exists - ${file_path}. Use overwrite: true to replace it.`;
37653
38276
  }
38277
+ const existed = (0, import_fs5.existsSync)(resolvedPath2);
37654
38278
  const dir = (0, import_path5.dirname)(resolvedPath2);
37655
38279
  await import_fs4.promises.mkdir(dir, { recursive: true });
37656
38280
  await import_fs4.promises.writeFile(resolvedPath2, content, "utf-8");
37657
- const action = (0, import_fs5.existsSync)(resolvedPath2) && overwrite ? "overwrote" : "created";
38281
+ if (options.fileTracker) await options.fileTracker.trackFileAfterWrite(resolvedPath2);
38282
+ const action = existed && overwrite ? "overwrote" : "created";
37658
38283
  const bytes = Buffer.byteLength(content, "utf-8");
37659
38284
  if (debug) {
37660
38285
  console.error(`[Create] Successfully ${action} ${resolvedPath2}`);
@@ -37676,18 +38301,35 @@ Important:
37676
38301
  },
37677
38302
  old_string: {
37678
38303
  type: "string",
37679
- description: "Exact text to find and replace"
38304
+ description: "Text to find and replace (for text-based editing)"
37680
38305
  },
37681
38306
  new_string: {
37682
38307
  type: "string",
37683
- description: "Text to replace with"
38308
+ description: "Replacement text or new code content"
37684
38309
  },
37685
38310
  replace_all: {
37686
38311
  type: "boolean",
37687
- description: "Replace all occurrences (default: false)"
38312
+ description: "Replace all occurrences (default: false, text mode only)"
38313
+ },
38314
+ symbol: {
38315
+ type: "string",
38316
+ description: 'Symbol name for AST-aware editing (e.g. "myFunction", "MyClass.myMethod")'
38317
+ },
38318
+ position: {
38319
+ type: "string",
38320
+ enum: ["before", "after"],
38321
+ description: "Insert before/after symbol or line (requires symbol or start_line, omit to replace)"
38322
+ },
38323
+ start_line: {
38324
+ type: "string",
38325
+ description: 'Line reference for line-targeted editing (e.g. "42" or "42:ab" with hash)'
38326
+ },
38327
+ end_line: {
38328
+ type: "string",
38329
+ description: 'End of line range, inclusive (e.g. "55" or "55:cd"). Defaults to start_line.'
37688
38330
  }
37689
38331
  },
37690
- required: ["file_path", "old_string", "new_string"]
38332
+ required: ["file_path", "new_string"]
37691
38333
  };
37692
38334
  createSchema = {
37693
38335
  type: "object",
@@ -37707,50 +38349,123 @@ Important:
37707
38349
  },
37708
38350
  required: ["file_path", "content"]
37709
38351
  };
37710
- editDescription = "Edit files using exact string replacement. Requires exact match including whitespace.";
38352
+ 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
38353
  createDescription = "Create new files with specified content. Will create parent directories if needed.";
37712
38354
  editToolDefinition = `
37713
38355
  ## edit
37714
38356
  Description: ${editDescription}
37715
38357
 
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)
38358
+ Four editing modes \u2014 choose based on the scope of your change:
37721
38359
 
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
38360
+ 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.
38361
+
38362
+ 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.
38363
+
38364
+ 3. **Symbol insert** (symbol + new_string + position): For adding new code before or after an existing symbol. Set position to "before" or "after".
38365
+
38366
+ 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
38367
 
37727
38368
  Parameters:
37728
38369
  - 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
38370
+ - new_string: (required) Replacement text or new code content
38371
+ - old_string: (optional) Text to find and replace \u2014 copy verbatim from the file, do not paraphrase or reformat
38372
+ - replace_all: (optional, default: false) Replace all occurrences of old_string (text mode only)
38373
+ - symbol: (optional) Name of a code symbol (e.g. "myFunction", "MyClass.myMethod") \u2014 must match a function, class, or method definition
38374
+ - position: (optional) "before" or "after" \u2014 insert new_string near the symbol or line instead of replacing it
38375
+ - start_line: (optional) Line reference for line-targeted editing (e.g. "42" or "42:ab")
38376
+ - end_line: (optional) End of line range, inclusive (e.g. "55" or "55:cd"). Defaults to start_line.
38377
+
38378
+ Mode selection rules (priority order):
38379
+ - If symbol is provided, symbol mode is used (old_string and start_line are ignored)
38380
+ - If start_line is provided (without symbol), line-targeted mode is used
38381
+ - If old_string is provided (without symbol or start_line), text mode is used
38382
+ - If none are provided, the tool returns an error with guidance
38383
+
38384
+ When to use each mode:
38385
+ - Small edits (a line or a few lines): use text mode with old_string
38386
+ - Replacing entire functions/classes/methods: use symbol mode \u2014 no exact text matching needed
38387
+ - Editing specific lines from extract/search output: use line-targeted mode with start_line
38388
+ - 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
38389
+
38390
+ Error handling:
38391
+ - If an edit fails, read the error message carefully \u2014 it contains specific instructions for how to fix the call and retry
38392
+ - Common fixes: use 'search'/'extract' to get exact file content, add more context to old_string, switch between text and symbol modes
38393
+ - Line-targeted hash mismatch: the file changed since last read; the error provides updated line:hash references
37737
38394
 
37738
38395
  Examples:
38396
+
38397
+ Text edit (find and replace):
37739
38398
  <edit>
37740
38399
  <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>
38400
+ <old_string>return false;</old_string>
38401
+ <new_string>return true;</new_string>
37747
38402
  </edit>
37748
38403
 
38404
+ Text edit with replace_all:
37749
38405
  <edit>
37750
38406
  <file_path>config.json</file_path>
37751
38407
  <old_string>"debug": false</old_string>
37752
38408
  <new_string>"debug": true</new_string>
37753
38409
  <replace_all>true</replace_all>
38410
+ </edit>
38411
+
38412
+ Symbol replace (rewrite entire function by name):
38413
+ <edit>
38414
+ <file_path>src/utils.js</file_path>
38415
+ <symbol>calculateTotal</symbol>
38416
+ <new_string>function calculateTotal(items) {
38417
+ return items.reduce((sum, item) => sum + item.price * item.quantity, 0);
38418
+ }</new_string>
38419
+ </edit>
38420
+
38421
+ Symbol insert (add new function after existing one):
38422
+ <edit>
38423
+ <file_path>src/utils.js</file_path>
38424
+ <symbol>calculateTotal</symbol>
38425
+ <position>after</position>
38426
+ <new_string>function calculateTax(total, rate) {
38427
+ return total * rate;
38428
+ }</new_string>
38429
+ </edit>
38430
+
38431
+ Line-targeted edit (replace a line):
38432
+ <edit>
38433
+ <file_path>src/main.js</file_path>
38434
+ <start_line>42</start_line>
38435
+ <new_string> return processItems(order.items);</new_string>
38436
+ </edit>
38437
+
38438
+ Line-targeted edit (replace a range of lines):
38439
+ <edit>
38440
+ <file_path>src/main.js</file_path>
38441
+ <start_line>42</start_line>
38442
+ <end_line>55</end_line>
38443
+ <new_string> // simplified implementation
38444
+ return processItems(order.items);</new_string>
38445
+ </edit>
38446
+
38447
+ Line-targeted edit with hash verification:
38448
+ <edit>
38449
+ <file_path>src/main.js</file_path>
38450
+ <start_line>42:ab</start_line>
38451
+ <end_line>55:cd</end_line>
38452
+ <new_string> return processItems(order.items);</new_string>
38453
+ </edit>
38454
+
38455
+ Line-targeted insert (add code after a line):
38456
+ <edit>
38457
+ <file_path>src/main.js</file_path>
38458
+ <start_line>42</start_line>
38459
+ <position>after</position>
38460
+ <new_string> const validated = validate(input);</new_string>
38461
+ </edit>
38462
+
38463
+ Line-targeted delete (remove lines):
38464
+ <edit>
38465
+ <file_path>src/main.js</file_path>
38466
+ <start_line>42</start_line>
38467
+ <end_line>45</end_line>
38468
+ <new_string></new_string>
37754
38469
  </edit>`;
37755
38470
  createToolDefinition = `
37756
38471
  ## create
@@ -38287,7 +39002,7 @@ function getValidParamsForTool(toolName) {
38287
39002
  };
38288
39003
  const schema = schemaMap[toolName];
38289
39004
  if (!schema) {
38290
- return ["path", "directory", "pattern", "recursive", "includeHidden", "task", "files", "autoCommits", "result"];
39005
+ return ["path", "directory", "pattern", "recursive", "includeHidden", "task", "files", "result"];
38291
39006
  }
38292
39007
  if (toolName === "attempt_completion") {
38293
39008
  return ["result"];
@@ -38408,7 +39123,6 @@ function detectUnrecognizedToolCall(xmlString, validTools) {
38408
39123
  "listSkills",
38409
39124
  "useSkill",
38410
39125
  "readImage",
38411
- "implement",
38412
39126
  "edit",
38413
39127
  "create",
38414
39128
  "delegate",
@@ -38783,6 +39497,8 @@ User: Read file inside the dependency
38783
39497
  </extract>
38784
39498
 
38785
39499
  </examples>
39500
+
39501
+ **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
39502
  `;
38787
39503
  delegateToolDefinition = `
38788
39504
  ## delegate
@@ -38938,7 +39654,7 @@ Capabilities:
38938
39654
  `;
38939
39655
  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
39656
  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.";
39657
+ 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
39658
  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
39659
  bashDescription = "Execute bash commands for system exploration and development tasks. Secure by default with built-in allow/deny lists.";
38944
39660
  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 +39670,6 @@ Capabilities:
38954
39670
  "useSkill",
38955
39671
  "listFiles",
38956
39672
  "searchFiles",
38957
- "implement",
38958
39673
  "bash",
38959
39674
  "task",
38960
39675
  "attempt_completion"
@@ -39634,7 +40349,7 @@ function parseXmlToolCallWithThinking(xmlString, validTools) {
39634
40349
  const toolCall = parseXmlToolCall(cleanedXmlString, validTools);
39635
40350
  return toolCall ? { ...toolCall, thinkingContent } : null;
39636
40351
  }
39637
- var import_crypto2, implementToolDefinition, listFilesToolDefinition, searchFilesToolDefinition, listSkillsToolDefinition, useSkillToolDefinition, readImageToolDefinition;
40352
+ var import_crypto2, listFilesToolDefinition, searchFilesToolDefinition, listSkillsToolDefinition, useSkillToolDefinition, readImageToolDefinition;
39638
40353
  var init_tools = __esm({
39639
40354
  "src/agent/tools.js"() {
39640
40355
  "use strict";
@@ -39642,31 +40357,6 @@ var init_tools = __esm({
39642
40357
  import_crypto2 = require("crypto");
39643
40358
  init_xmlParsingUtils();
39644
40359
  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
40360
  listFilesToolDefinition = `
39671
40361
  ## listFiles
39672
40362
  Description: List files and directories in a specified location.
@@ -39782,33 +40472,289 @@ User: Analyze the diagram in docs/architecture.svg
39782
40472
  }
39783
40473
  });
39784
40474
 
39785
- // node_modules/balanced-match/index.js
39786
- var require_balanced_match = __commonJS({
39787
- "node_modules/balanced-match/index.js"(exports2, module2) {
40475
+ // src/tools/fileTracker.js
40476
+ function computeContentHash(content) {
40477
+ const normalized = (content || "").split("\n").map((l5) => l5.trimEnd()).join("\n");
40478
+ return (0, import_crypto3.createHash)("sha256").update(normalized).digest("hex").slice(0, 16);
40479
+ }
40480
+ function extractFilePath(target) {
40481
+ const hashIdx = target.indexOf("#");
40482
+ if (hashIdx !== -1) {
40483
+ return target.slice(0, hashIdx);
40484
+ }
40485
+ const colonIdx = target.lastIndexOf(":");
40486
+ if (colonIdx !== -1) {
40487
+ const after = target.slice(colonIdx + 1);
40488
+ if (/^\d+(-\d+)?$/.test(after)) {
40489
+ return target.slice(0, colonIdx);
40490
+ }
40491
+ }
40492
+ return target;
40493
+ }
40494
+ function extractSymbolName(target) {
40495
+ const hashIdx = target.indexOf("#");
40496
+ if (hashIdx !== -1) {
40497
+ const symbol15 = target.slice(hashIdx + 1);
40498
+ return symbol15 || null;
40499
+ }
40500
+ return null;
40501
+ }
40502
+ function parseFilePathsFromOutput(output) {
40503
+ const paths = [];
40504
+ const regex = /^(?:File:\s+|---\s+)([^\s].*?)(?:\s+---)?$/gm;
40505
+ let match2;
40506
+ while ((match2 = regex.exec(output)) !== null) {
40507
+ const path9 = match2[1].trim();
40508
+ if (path9 && !path9.startsWith("Results") && !path9.startsWith("Page") && (path9.includes("/") || path9.includes(".") || path9.includes("\\"))) {
40509
+ paths.push(path9);
40510
+ }
40511
+ }
40512
+ return paths;
40513
+ }
40514
+ var import_crypto3, import_path7, FileTracker;
40515
+ var init_fileTracker = __esm({
40516
+ "src/tools/fileTracker.js"() {
39788
40517
  "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);
40518
+ import_crypto3 = require("crypto");
40519
+ import_path7 = require("path");
40520
+ init_symbolEdit();
40521
+ FileTracker = class {
40522
+ /**
40523
+ * @param {Object} [options]
40524
+ * @param {boolean} [options.debug=false] - Enable debug logging
40525
+ */
40526
+ constructor(options = {}) {
40527
+ this.debug = options.debug || false;
40528
+ this._seenFiles = /* @__PURE__ */ new Set();
40529
+ this._contentRecords = /* @__PURE__ */ new Map();
40530
+ }
40531
+ /**
40532
+ * Mark a file as "seen" — the LLM has read its content.
40533
+ * @param {string} resolvedPath - Absolute path to the file
40534
+ */
40535
+ markFileSeen(resolvedPath2) {
40536
+ this._seenFiles.add(resolvedPath2);
40537
+ if (this.debug) {
40538
+ console.error(`[FileTracker] Marked as seen: ${resolvedPath2}`);
40539
+ }
40540
+ }
40541
+ /**
40542
+ * Check if a file has been seen in this session.
40543
+ * @param {string} resolvedPath - Absolute path to the file
40544
+ * @returns {boolean}
40545
+ */
40546
+ isFileSeen(resolvedPath2) {
40547
+ return this._seenFiles.has(resolvedPath2);
40548
+ }
40549
+ /**
40550
+ * Store a content hash for a symbol in a file.
40551
+ * @param {string} resolvedPath - Absolute path to the file
40552
+ * @param {string} symbolName - Symbol name (e.g. "calculateTotal")
40553
+ * @param {string} code - The symbol's source code
40554
+ * @param {number} startLine - 1-indexed start line
40555
+ * @param {number} endLine - 1-indexed end line
40556
+ * @param {string} [source='extract'] - How the content was obtained
40557
+ */
40558
+ trackSymbolContent(resolvedPath2, symbolName, code, startLine, endLine, source = "extract") {
40559
+ const key = `${resolvedPath2}#${symbolName}`;
40560
+ const contentHash = computeContentHash(code);
40561
+ this._contentRecords.set(key, {
40562
+ contentHash,
40563
+ startLine,
40564
+ endLine,
40565
+ symbolName,
40566
+ source,
40567
+ timestamp: Date.now()
40568
+ });
40569
+ if (this.debug) {
40570
+ console.error(`[FileTracker] Tracked symbol ${key} (hash: ${contentHash}, lines ${startLine}-${endLine})`);
40571
+ }
40572
+ }
40573
+ /**
40574
+ * Look up a stored content record for a symbol.
40575
+ * @param {string} resolvedPath - Absolute path to the file
40576
+ * @param {string} symbolName - Symbol name
40577
+ * @returns {Object|null} The stored record or null
40578
+ */
40579
+ getSymbolRecord(resolvedPath2, symbolName) {
40580
+ return this._contentRecords.get(`${resolvedPath2}#${symbolName}`) || null;
40581
+ }
40582
+ /**
40583
+ * Check if a symbol's current content matches what was stored.
40584
+ * @param {string} resolvedPath - Absolute path to the file
40585
+ * @param {string} symbolName - Symbol name
40586
+ * @param {string} currentCode - The symbol's current source code (from findSymbol)
40587
+ * @returns {{ok: boolean, reason?: string, message?: string}}
40588
+ */
40589
+ checkSymbolContent(resolvedPath2, symbolName, currentCode) {
40590
+ const key = `${resolvedPath2}#${symbolName}`;
40591
+ const record = this._contentRecords.get(key);
40592
+ if (!record) {
40593
+ return { ok: true };
40594
+ }
40595
+ const currentHash = computeContentHash(currentCode);
40596
+ if (currentHash === record.contentHash) {
40597
+ return { ok: true };
40598
+ }
40599
+ return {
40600
+ ok: false,
40601
+ reason: "stale",
40602
+ message: `Symbol "${symbolName}" has changed since you last read it (hash: ${record.contentHash} \u2192 ${currentHash}).`
40603
+ };
40604
+ }
40605
+ /**
40606
+ * Track files from extract target strings.
40607
+ * Marks each file as seen. For #symbol targets, calls findSymbol to get and hash the code.
40608
+ * @param {string[]} targets - Array of extract targets (e.g. ["file.js#fn", "file.js:10-20"])
40609
+ * @param {string} cwd - Working directory for resolving relative paths
40610
+ */
40611
+ async trackFilesFromExtract(targets, cwd) {
40612
+ const seenPaths = /* @__PURE__ */ new Set();
40613
+ const symbolPromises = [];
40614
+ for (const target of targets) {
40615
+ const filePath = extractFilePath(target);
40616
+ const resolved = (0, import_path7.isAbsolute)(filePath) ? filePath : (0, import_path7.resolve)(cwd, filePath);
40617
+ if (!seenPaths.has(resolved)) {
40618
+ seenPaths.add(resolved);
40619
+ this.markFileSeen(resolved);
40620
+ }
40621
+ const symbolName = extractSymbolName(target);
40622
+ if (symbolName) {
40623
+ symbolPromises.push(
40624
+ findSymbol(resolved, symbolName, cwd).then((symbolInfo) => {
40625
+ if (symbolInfo) {
40626
+ this.trackSymbolContent(
40627
+ resolved,
40628
+ symbolName,
40629
+ symbolInfo.code,
40630
+ symbolInfo.startLine,
40631
+ symbolInfo.endLine,
40632
+ "extract"
40633
+ );
40634
+ }
40635
+ }).catch((err) => {
40636
+ if (this.debug) {
40637
+ console.error(`[FileTracker] Failed to track symbol "${symbolName}" in ${resolved}: ${err.message}`);
40638
+ }
40639
+ })
40640
+ );
40641
+ }
40642
+ }
40643
+ if (symbolPromises.length > 0) {
40644
+ await Promise.all(symbolPromises);
40645
+ }
40646
+ }
40647
+ /**
40648
+ * Track files discovered in probe search/extract output.
40649
+ * Parses "File: path" headers and "--- path ---" separators, marks each as "seen".
40650
+ * @param {string} output - Probe output text
40651
+ * @param {string} cwd - Working directory for resolving relative paths
40652
+ */
40653
+ async trackFilesFromOutput(output, cwd) {
40654
+ const paths = parseFilePathsFromOutput(output);
40655
+ for (const filePath of paths) {
40656
+ const resolved = (0, import_path7.isAbsolute)(filePath) ? filePath : (0, import_path7.resolve)(cwd, filePath);
40657
+ this.markFileSeen(resolved);
40658
+ }
40659
+ }
40660
+ /**
40661
+ * Check if a file is safe to edit (seen-check only).
40662
+ * Mode-specific content verification happens in edit handlers.
40663
+ * @param {string} resolvedPath - Absolute path to the file
40664
+ * @returns {{ok: boolean, reason?: string, message?: string}}
40665
+ */
40666
+ checkBeforeEdit(resolvedPath2) {
40667
+ if (!this._seenFiles.has(resolvedPath2)) {
40668
+ return {
40669
+ ok: false,
40670
+ reason: "untracked",
40671
+ message: "This file has not been read yet in this session. Use extract or search to read the file first."
40672
+ };
40673
+ }
40674
+ return { ok: true };
40675
+ }
40676
+ /**
40677
+ * Mark a file as seen after a successful write (backward compat).
40678
+ * Also invalidates content records for the file since its content changed.
40679
+ * @param {string} resolvedPath - Absolute path to the file
40680
+ */
40681
+ async trackFileAfterWrite(resolvedPath2) {
40682
+ this.markFileSeen(resolvedPath2);
40683
+ this.invalidateFileRecords(resolvedPath2);
40684
+ }
40685
+ /**
40686
+ * Update the stored hash for a symbol after a successful write.
40687
+ * Enables chained edits to the same symbol.
40688
+ * @param {string} resolvedPath - Absolute path to the file
40689
+ * @param {string} symbolName - Symbol name
40690
+ * @param {string} code - The symbol's new source code
40691
+ * @param {number} startLine - 1-indexed start line (new position)
40692
+ * @param {number} endLine - 1-indexed end line (new position)
40693
+ */
40694
+ trackSymbolAfterWrite(resolvedPath2, symbolName, code, startLine, endLine) {
40695
+ this.trackSymbolContent(resolvedPath2, symbolName, code, startLine, endLine, "edit");
40696
+ }
40697
+ /**
40698
+ * Remove all content records for a file.
40699
+ * Called after non-symbol edits (text/line mode) since those change content
40700
+ * without providing a symbol-level update.
40701
+ * @param {string} resolvedPath - Absolute path to the file
40702
+ */
40703
+ invalidateFileRecords(resolvedPath2) {
40704
+ const prefix = resolvedPath2 + "#";
40705
+ for (const key of this._contentRecords.keys()) {
40706
+ if (key.startsWith(prefix)) {
40707
+ this._contentRecords.delete(key);
40708
+ }
40709
+ }
40710
+ if (this.debug) {
40711
+ console.error(`[FileTracker] Invalidated content records for ${resolvedPath2}`);
40712
+ }
40713
+ }
40714
+ /**
40715
+ * Quick sync check if a file is being tracked (alias for isFileSeen).
40716
+ * @param {string} resolvedPath - Absolute path to the file
40717
+ * @returns {boolean}
40718
+ */
40719
+ isTracked(resolvedPath2) {
40720
+ return this.isFileSeen(resolvedPath2);
40721
+ }
40722
+ /**
40723
+ * Clear all tracking state.
40724
+ */
40725
+ clear() {
40726
+ this._seenFiles.clear();
40727
+ this._contentRecords.clear();
40728
+ }
40729
+ };
40730
+ }
40731
+ });
40732
+
40733
+ // node_modules/balanced-match/dist/esm/index.js
40734
+ var balanced, maybeMatch, range2;
40735
+ var init_esm = __esm({
40736
+ "node_modules/balanced-match/dist/esm/index.js"() {
40737
+ balanced = (a5, b5, str) => {
40738
+ const ma = a5 instanceof RegExp ? maybeMatch(a5, str) : a5;
40739
+ const mb = b5 instanceof RegExp ? maybeMatch(b5, str) : b5;
40740
+ const r5 = ma !== null && mb != null && range2(ma, mb, str);
39794
40741
  return r5 && {
39795
40742
  start: r5[0],
39796
40743
  end: r5[1],
39797
40744
  pre: str.slice(0, r5[0]),
39798
- body: str.slice(r5[0] + a5.length, r5[1]),
39799
- post: str.slice(r5[1] + b5.length)
40745
+ body: str.slice(r5[0] + ma.length, r5[1]),
40746
+ post: str.slice(r5[1] + mb.length)
39800
40747
  };
39801
- }
39802
- function maybeMatch(reg, str) {
39803
- var m5 = str.match(reg);
40748
+ };
40749
+ maybeMatch = (reg, str) => {
40750
+ const m5 = str.match(reg);
39804
40751
  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;
40752
+ };
40753
+ range2 = (a5, b5, str) => {
40754
+ let begs, beg, left, right = void 0, result;
40755
+ let ai = str.indexOf(a5);
40756
+ let bi = str.indexOf(b5, ai + 1);
40757
+ let i5 = ai;
39812
40758
  if (ai >= 0 && bi > 0) {
39813
40759
  if (a5 === b5) {
39814
40760
  return [ai, bi];
@@ -39816,14 +40762,16 @@ var require_balanced_match = __commonJS({
39816
40762
  begs = [];
39817
40763
  left = str.length;
39818
40764
  while (i5 >= 0 && !result) {
39819
- if (i5 == ai) {
40765
+ if (i5 === ai) {
39820
40766
  begs.push(i5);
39821
40767
  ai = str.indexOf(a5, i5 + 1);
39822
- } else if (begs.length == 1) {
39823
- result = [begs.pop(), bi];
40768
+ } else if (begs.length === 1) {
40769
+ const r5 = begs.pop();
40770
+ if (r5 !== void 0)
40771
+ result = [r5, bi];
39824
40772
  } else {
39825
40773
  beg = begs.pop();
39826
- if (beg < left) {
40774
+ if (beg !== void 0 && beg < left) {
39827
40775
  left = beg;
39828
40776
  right = bi;
39829
40777
  }
@@ -39831,163 +40779,179 @@ var require_balanced_match = __commonJS({
39831
40779
  }
39832
40780
  i5 = ai < bi && ai >= 0 ? ai : bi;
39833
40781
  }
39834
- if (begs.length) {
40782
+ if (begs.length && right !== void 0) {
39835
40783
  result = [left, right];
39836
40784
  }
39837
40785
  }
39838
40786
  return result;
39839
- }
40787
+ };
39840
40788
  }
39841
40789
  });
39842
40790
 
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;
40791
+ // node_modules/brace-expansion/dist/esm/index.js
40792
+ function numeric(str) {
40793
+ return !isNaN(str) ? parseInt(str, 10) : str.charCodeAt(0);
40794
+ }
40795
+ function escapeBraces(str) {
40796
+ return str.replace(slashPattern, escSlash).replace(openPattern, escOpen).replace(closePattern, escClose).replace(commaPattern, escComma).replace(periodPattern, escPeriod);
40797
+ }
40798
+ function unescapeBraces(str) {
40799
+ return str.replace(escSlashPattern, "\\").replace(escOpenPattern, "{").replace(escClosePattern, "}").replace(escCommaPattern, ",").replace(escPeriodPattern, ".");
40800
+ }
40801
+ function parseCommaParts(str) {
40802
+ if (!str) {
40803
+ return [""];
40804
+ }
40805
+ const parts = [];
40806
+ const m5 = balanced("{", "}", str);
40807
+ if (!m5) {
40808
+ return str.split(",");
40809
+ }
40810
+ const { pre, body, post } = m5;
40811
+ const p5 = pre.split(",");
40812
+ p5[p5.length - 1] += "{" + body + "}";
40813
+ const postParts = parseCommaParts(post);
40814
+ if (post.length) {
40815
+ ;
40816
+ p5[p5.length - 1] += postParts.shift();
40817
+ p5.push.apply(p5, postParts);
40818
+ }
40819
+ parts.push.apply(parts, p5);
40820
+ return parts;
40821
+ }
40822
+ function expand(str, options = {}) {
40823
+ if (!str) {
40824
+ return [];
40825
+ }
40826
+ const { max = EXPANSION_MAX } = options;
40827
+ if (str.slice(0, 2) === "{}") {
40828
+ str = "\\{\\}" + str.slice(2);
40829
+ }
40830
+ return expand_(escapeBraces(str), max, true).map(unescapeBraces);
40831
+ }
40832
+ function embrace(str) {
40833
+ return "{" + str + "}";
40834
+ }
40835
+ function isPadded(el) {
40836
+ return /^-?0\d/.test(el);
40837
+ }
40838
+ function lte(i5, y2) {
40839
+ return i5 <= y2;
40840
+ }
40841
+ function gte(i5, y2) {
40842
+ return i5 >= y2;
40843
+ }
40844
+ function expand_(str, max, isTop) {
40845
+ const expansions = [];
40846
+ const m5 = balanced("{", "}", str);
40847
+ if (!m5)
40848
+ return [str];
40849
+ const pre = m5.pre;
40850
+ const post = m5.post.length ? expand_(m5.post, max, false) : [""];
40851
+ if (/\$$/.test(m5.pre)) {
40852
+ for (let k5 = 0; k5 < post.length && k5 < max; k5++) {
40853
+ const expansion = pre + "{" + m5.body + "}" + post[k5];
40854
+ expansions.push(expansion);
39901
40855
  }
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
- }
40856
+ } else {
40857
+ const isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m5.body);
40858
+ const isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m5.body);
40859
+ const isSequence = isNumericSequence || isAlphaSequence;
40860
+ const isOptions = m5.body.indexOf(",") >= 0;
40861
+ if (!isSequence && !isOptions) {
40862
+ if (m5.post.match(/,(?!,).*\}/)) {
40863
+ str = m5.pre + "{" + m5.body + escClose + m5.post;
40864
+ return expand_(str, max, true);
40865
+ }
40866
+ return [str];
40867
+ }
40868
+ let n5;
40869
+ if (isSequence) {
40870
+ n5 = m5.body.split(/\.\./);
40871
+ } else {
40872
+ n5 = parseCommaParts(m5.body);
40873
+ if (n5.length === 1 && n5[0] !== void 0) {
40874
+ n5 = expand_(n5[0], max, false).map(embrace);
40875
+ if (n5.length === 1) {
40876
+ return post.map((p5) => m5.pre + n5[0] + p5);
40877
+ }
40878
+ }
40879
+ }
40880
+ let N;
40881
+ if (isSequence && n5[0] !== void 0 && n5[1] !== void 0) {
40882
+ const x5 = numeric(n5[0]);
40883
+ const y2 = numeric(n5[1]);
40884
+ const width = Math.max(n5[0].length, n5[1].length);
40885
+ let incr = n5.length === 3 && n5[2] !== void 0 ? Math.abs(numeric(n5[2])) : 1;
40886
+ let test = lte;
40887
+ const reverse = y2 < x5;
40888
+ if (reverse) {
40889
+ incr *= -1;
40890
+ test = gte;
40891
+ }
40892
+ const pad = n5.some(isPadded);
40893
+ N = [];
40894
+ for (let i5 = x5; test(i5, y2); i5 += incr) {
40895
+ let c5;
40896
+ if (isAlphaSequence) {
40897
+ c5 = String.fromCharCode(i5);
40898
+ if (c5 === "\\") {
40899
+ c5 = "";
39937
40900
  }
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
- }
40901
+ } else {
40902
+ c5 = String(i5);
40903
+ if (pad) {
40904
+ const need = width - c5.length;
40905
+ if (need > 0) {
40906
+ const z2 = new Array(need + 1).join("0");
40907
+ if (i5 < 0) {
40908
+ c5 = "-" + z2 + c5.slice(1);
40909
+ } else {
40910
+ c5 = z2 + c5;
39970
40911
  }
39971
40912
  }
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
40913
  }
39979
40914
  }
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
- }
40915
+ N.push(c5);
40916
+ }
40917
+ } else {
40918
+ N = [];
40919
+ for (let j5 = 0; j5 < n5.length; j5++) {
40920
+ N.push.apply(N, expand_(n5[j5], max, false));
40921
+ }
40922
+ }
40923
+ for (let j5 = 0; j5 < N.length; j5++) {
40924
+ for (let k5 = 0; k5 < post.length && expansions.length < max; k5++) {
40925
+ const expansion = pre + N[j5] + post[k5];
40926
+ if (!isTop || isSequence || expansion) {
40927
+ expansions.push(expansion);
39986
40928
  }
39987
40929
  }
39988
- return expansions;
39989
40930
  }
39990
40931
  }
40932
+ return expansions;
40933
+ }
40934
+ var escSlash, escOpen, escClose, escComma, escPeriod, escSlashPattern, escOpenPattern, escClosePattern, escCommaPattern, escPeriodPattern, slashPattern, openPattern, closePattern, commaPattern, periodPattern, EXPANSION_MAX;
40935
+ var init_esm2 = __esm({
40936
+ "node_modules/brace-expansion/dist/esm/index.js"() {
40937
+ init_esm();
40938
+ escSlash = "\0SLASH" + Math.random() + "\0";
40939
+ escOpen = "\0OPEN" + Math.random() + "\0";
40940
+ escClose = "\0CLOSE" + Math.random() + "\0";
40941
+ escComma = "\0COMMA" + Math.random() + "\0";
40942
+ escPeriod = "\0PERIOD" + Math.random() + "\0";
40943
+ escSlashPattern = new RegExp(escSlash, "g");
40944
+ escOpenPattern = new RegExp(escOpen, "g");
40945
+ escClosePattern = new RegExp(escClose, "g");
40946
+ escCommaPattern = new RegExp(escComma, "g");
40947
+ escPeriodPattern = new RegExp(escPeriod, "g");
40948
+ slashPattern = /\\\\/g;
40949
+ openPattern = /\\{/g;
40950
+ closePattern = /\\}/g;
40951
+ commaPattern = /\\,/g;
40952
+ periodPattern = /\\./g;
40953
+ EXPANSION_MAX = 1e5;
40954
+ }
39991
40955
  });
39992
40956
 
39993
40957
  // node_modules/minimatch/dist/esm/assert-valid-pattern.js
@@ -40570,11 +41534,13 @@ var init_ast = __esm({
40570
41534
  let escaping = false;
40571
41535
  let re = "";
40572
41536
  let uflag = false;
41537
+ let inStar = false;
40573
41538
  for (let i5 = 0; i5 < glob2.length; i5++) {
40574
41539
  const c5 = glob2.charAt(i5);
40575
41540
  if (escaping) {
40576
41541
  escaping = false;
40577
41542
  re += (reSpecials.has(c5) ? "\\" : "") + c5;
41543
+ inStar = false;
40578
41544
  continue;
40579
41545
  }
40580
41546
  if (c5 === "\\") {
@@ -40592,16 +41558,19 @@ var init_ast = __esm({
40592
41558
  uflag = uflag || needUflag;
40593
41559
  i5 += consumed - 1;
40594
41560
  hasMagic2 = hasMagic2 || magic;
41561
+ inStar = false;
40595
41562
  continue;
40596
41563
  }
40597
41564
  }
40598
41565
  if (c5 === "*") {
40599
- if (noEmpty && glob2 === "*")
40600
- re += starNoEmpty;
40601
- else
40602
- re += star;
41566
+ if (inStar)
41567
+ continue;
41568
+ inStar = true;
41569
+ re += noEmpty && /^[*]+$/.test(glob2) ? starNoEmpty : star;
40603
41570
  hasMagic2 = true;
40604
41571
  continue;
41572
+ } else {
41573
+ inStar = false;
40605
41574
  }
40606
41575
  if (c5 === "?") {
40607
41576
  re += qmark;
@@ -40627,10 +41596,10 @@ var init_escape = __esm({
40627
41596
  });
40628
41597
 
40629
41598
  // 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({
41599
+ 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;
41600
+ var init_esm3 = __esm({
40632
41601
  "node_modules/minimatch/dist/esm/index.js"() {
40633
- import_brace_expansion = __toESM(require_brace_expansion(), 1);
41602
+ init_esm2();
40634
41603
  init_assert_valid_pattern();
40635
41604
  init_ast();
40636
41605
  init_escape();
@@ -40753,7 +41722,7 @@ var init_esm = __esm({
40753
41722
  if (options.nobrace || !/\{(?:(?!\{).)*\}/.test(pattern)) {
40754
41723
  return [pattern];
40755
41724
  }
40756
- return (0, import_brace_expansion.default)(pattern);
41725
+ return expand(pattern);
40757
41726
  };
40758
41727
  minimatch.braceExpand = braceExpand;
40759
41728
  makeRe = (pattern, options = {}) => new Minimatch(pattern, options).makeRe();
@@ -41359,7 +42328,7 @@ var init_esm = __esm({
41359
42328
 
41360
42329
  // node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.js
41361
42330
  var perf, warned, PROCESS, emitWarning, AC, AS, shouldWarn, TYPE, isPosInt, getUintArray, ZeroArray, Stack, LRUCache;
41362
- var init_esm2 = __esm({
42331
+ var init_esm4 = __esm({
41363
42332
  "node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.js"() {
41364
42333
  perf = typeof performance === "object" && performance && typeof performance.now === "function" ? performance : Date;
41365
42334
  warned = /* @__PURE__ */ new Set();
@@ -42733,7 +43702,7 @@ var init_esm2 = __esm({
42733
43702
 
42734
43703
  // node_modules/minipass/dist/esm/index.js
42735
43704
  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({
43705
+ var init_esm5 = __esm({
42737
43706
  "node_modules/minipass/dist/esm/index.js"() {
42738
43707
  import_node_events = require("node:events");
42739
43708
  import_node_stream = __toESM(require("node:stream"), 1);
@@ -43463,10 +44432,10 @@ var init_esm3 = __esm({
43463
44432
  * Return a void Promise that resolves once the stream ends.
43464
44433
  */
43465
44434
  async promise() {
43466
- return new Promise((resolve7, reject2) => {
44435
+ return new Promise((resolve8, reject2) => {
43467
44436
  this.on(DESTROYED, () => reject2(new Error("stream destroyed")));
43468
44437
  this.on("error", (er) => reject2(er));
43469
- this.on("end", () => resolve7());
44438
+ this.on("end", () => resolve8());
43470
44439
  });
43471
44440
  }
43472
44441
  /**
@@ -43490,7 +44459,7 @@ var init_esm3 = __esm({
43490
44459
  return Promise.resolve({ done: false, value: res });
43491
44460
  if (this[EOF])
43492
44461
  return stop();
43493
- let resolve7;
44462
+ let resolve8;
43494
44463
  let reject2;
43495
44464
  const onerr = (er) => {
43496
44465
  this.off("data", ondata);
@@ -43504,19 +44473,19 @@ var init_esm3 = __esm({
43504
44473
  this.off("end", onend);
43505
44474
  this.off(DESTROYED, ondestroy);
43506
44475
  this.pause();
43507
- resolve7({ value, done: !!this[EOF] });
44476
+ resolve8({ value, done: !!this[EOF] });
43508
44477
  };
43509
44478
  const onend = () => {
43510
44479
  this.off("error", onerr);
43511
44480
  this.off("data", ondata);
43512
44481
  this.off(DESTROYED, ondestroy);
43513
44482
  stop();
43514
- resolve7({ done: true, value: void 0 });
44483
+ resolve8({ done: true, value: void 0 });
43515
44484
  };
43516
44485
  const ondestroy = () => onerr(new Error("stream destroyed"));
43517
44486
  return new Promise((res2, rej) => {
43518
44487
  reject2 = rej;
43519
- resolve7 = res2;
44488
+ resolve8 = res2;
43520
44489
  this.once(DESTROYED, ondestroy);
43521
44490
  this.once("error", onerr);
43522
44491
  this.once("end", onend);
@@ -43620,15 +44589,15 @@ var init_esm3 = __esm({
43620
44589
 
43621
44590
  // node_modules/path-scurry/dist/esm/index.js
43622
44591
  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({
44592
+ var init_esm6 = __esm({
43624
44593
  "node_modules/path-scurry/dist/esm/index.js"() {
43625
- init_esm2();
44594
+ init_esm4();
43626
44595
  import_node_path = require("node:path");
43627
44596
  import_node_url = require("node:url");
43628
44597
  import_fs6 = require("fs");
43629
44598
  actualFS = __toESM(require("node:fs"), 1);
43630
44599
  import_promises = require("node:fs/promises");
43631
- init_esm3();
44600
+ init_esm5();
43632
44601
  realpathSync2 = import_fs6.realpathSync.native;
43633
44602
  defaultFS = {
43634
44603
  lstatSync: import_fs6.lstatSync,
@@ -44500,9 +45469,9 @@ var init_esm4 = __esm({
44500
45469
  if (this.#asyncReaddirInFlight) {
44501
45470
  await this.#asyncReaddirInFlight;
44502
45471
  } else {
44503
- let resolve7 = () => {
45472
+ let resolve8 = () => {
44504
45473
  };
44505
- this.#asyncReaddirInFlight = new Promise((res) => resolve7 = res);
45474
+ this.#asyncReaddirInFlight = new Promise((res) => resolve8 = res);
44506
45475
  try {
44507
45476
  for (const e5 of await this.#fs.promises.readdir(fullpath, {
44508
45477
  withFileTypes: true
@@ -44515,7 +45484,7 @@ var init_esm4 = __esm({
44515
45484
  children.provisional = 0;
44516
45485
  }
44517
45486
  this.#asyncReaddirInFlight = void 0;
44518
- resolve7();
45487
+ resolve8();
44519
45488
  }
44520
45489
  return children.slice(0, children.provisional);
44521
45490
  }
@@ -45358,7 +46327,7 @@ var init_esm4 = __esm({
45358
46327
  var isPatternList, isGlobList, Pattern;
45359
46328
  var init_pattern = __esm({
45360
46329
  "node_modules/glob/dist/esm/pattern.js"() {
45361
- init_esm();
46330
+ init_esm3();
45362
46331
  isPatternList = (pl) => pl.length >= 1;
45363
46332
  isGlobList = (gl) => gl.length >= 1;
45364
46333
  Pattern = class _Pattern {
@@ -45529,7 +46498,7 @@ var init_pattern = __esm({
45529
46498
  var defaultPlatform2, Ignore;
45530
46499
  var init_ignore = __esm({
45531
46500
  "node_modules/glob/dist/esm/ignore.js"() {
45532
- init_esm();
46501
+ init_esm3();
45533
46502
  init_pattern();
45534
46503
  defaultPlatform2 = typeof process === "object" && process && typeof process.platform === "string" ? process.platform : "linux";
45535
46504
  Ignore = class {
@@ -45623,7 +46592,7 @@ var init_ignore = __esm({
45623
46592
  var HasWalkedCache, MatchRecord, SubWalks, Processor;
45624
46593
  var init_processor = __esm({
45625
46594
  "node_modules/glob/dist/esm/processor.js"() {
45626
- init_esm();
46595
+ init_esm3();
45627
46596
  HasWalkedCache = class _HasWalkedCache {
45628
46597
  store;
45629
46598
  constructor(store = /* @__PURE__ */ new Map()) {
@@ -45850,7 +46819,7 @@ var init_processor = __esm({
45850
46819
  var makeIgnore, GlobUtil, GlobWalker, GlobStream;
45851
46820
  var init_walker = __esm({
45852
46821
  "node_modules/glob/dist/esm/walker.js"() {
45853
- init_esm3();
46822
+ init_esm5();
45854
46823
  init_ignore();
45855
46824
  init_processor();
45856
46825
  makeIgnore = (ignore2, opts) => typeof ignore2 === "string" ? new Ignore([ignore2], opts) : Array.isArray(ignore2) ? new Ignore(ignore2, opts) : ignore2;
@@ -46185,9 +47154,9 @@ var init_walker = __esm({
46185
47154
  var import_node_url2, defaultPlatform3, Glob;
46186
47155
  var init_glob = __esm({
46187
47156
  "node_modules/glob/dist/esm/glob.js"() {
46188
- init_esm();
47157
+ init_esm3();
46189
47158
  import_node_url2 = require("node:url");
46190
- init_esm4();
47159
+ init_esm6();
46191
47160
  init_pattern();
46192
47161
  init_walker();
46193
47162
  defaultPlatform3 = typeof process === "object" && process && typeof process.platform === "string" ? process.platform : "linux";
@@ -46395,7 +47364,7 @@ var init_glob = __esm({
46395
47364
  var hasMagic;
46396
47365
  var init_has_magic = __esm({
46397
47366
  "node_modules/glob/dist/esm/has-magic.js"() {
46398
- init_esm();
47367
+ init_esm3();
46399
47368
  hasMagic = (pattern, options = {}) => {
46400
47369
  if (!Array.isArray(pattern)) {
46401
47370
  pattern = [pattern];
@@ -46429,12 +47398,12 @@ function globIterate(pattern, options = {}) {
46429
47398
  return new Glob(pattern, options).iterate();
46430
47399
  }
46431
47400
  var streamSync, stream, iterateSync, iterate, sync, glob;
46432
- var init_esm5 = __esm({
47401
+ var init_esm7 = __esm({
46433
47402
  "node_modules/glob/dist/esm/index.js"() {
46434
- init_esm();
47403
+ init_esm3();
46435
47404
  init_glob();
46436
47405
  init_has_magic();
46437
- init_esm();
47406
+ init_esm3();
46438
47407
  init_glob();
46439
47408
  init_has_magic();
46440
47409
  init_ignore();
@@ -46564,19 +47533,19 @@ function createWrappedTools(baseTools) {
46564
47533
  }
46565
47534
  return wrappedTools;
46566
47535
  }
46567
- var import_child_process6, import_util11, import_crypto3, import_events, import_fs7, import_fs8, import_path7, toolCallEmitter, activeToolExecutions, wrapToolWithEmitter, listFilesTool, searchFilesTool, listFilesToolInstance, searchFilesToolInstance;
47536
+ var import_child_process6, import_util11, import_crypto4, import_events, import_fs7, import_fs8, import_path8, toolCallEmitter, activeToolExecutions, wrapToolWithEmitter, listFilesTool, searchFilesTool, listFilesToolInstance, searchFilesToolInstance;
46568
47537
  var init_probeTool = __esm({
46569
47538
  "src/agent/probeTool.js"() {
46570
47539
  "use strict";
46571
47540
  init_index();
46572
47541
  import_child_process6 = require("child_process");
46573
47542
  import_util11 = require("util");
46574
- import_crypto3 = require("crypto");
47543
+ import_crypto4 = require("crypto");
46575
47544
  import_events = require("events");
46576
47545
  import_fs7 = __toESM(require("fs"), 1);
46577
47546
  import_fs8 = require("fs");
46578
- import_path7 = __toESM(require("path"), 1);
46579
- init_esm5();
47547
+ import_path8 = __toESM(require("path"), 1);
47548
+ init_esm7();
46580
47549
  init_symlink_utils();
46581
47550
  toolCallEmitter = new import_events.EventEmitter();
46582
47551
  activeToolExecutions = /* @__PURE__ */ new Map();
@@ -46586,7 +47555,7 @@ var init_probeTool = __esm({
46586
47555
  // Spread schema, description etc.
46587
47556
  execute: async (params) => {
46588
47557
  const debug = process.env.DEBUG === "1";
46589
- const toolSessionId = params.sessionId || (0, import_crypto3.randomUUID)();
47558
+ const toolSessionId = params.sessionId || (0, import_crypto4.randomUUID)();
46590
47559
  if (debug) {
46591
47560
  console.log(`[DEBUG] probeTool: Executing ${toolName} for session ${toolSessionId}`);
46592
47561
  }
@@ -46664,17 +47633,17 @@ var init_probeTool = __esm({
46664
47633
  execute: async (params) => {
46665
47634
  const { directory = ".", workingDirectory } = params;
46666
47635
  const baseCwd = workingDirectory || process.cwd();
46667
- const secureBaseDir = import_path7.default.resolve(baseCwd);
47636
+ const secureBaseDir = import_path8.default.resolve(baseCwd);
46668
47637
  const isDependencyPath = directory.startsWith("/dep/") || directory.startsWith("go:") || directory.startsWith("js:") || directory.startsWith("rust:");
46669
47638
  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) {
47639
+ if (import_path8.default.isAbsolute(directory)) {
47640
+ targetDir = import_path8.default.resolve(directory);
47641
+ if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + import_path8.default.sep) && targetDir !== secureBaseDir) {
46673
47642
  throw new Error(`Path traversal attempt detected. Cannot access directory outside workspace: ${directory}`);
46674
47643
  }
46675
47644
  } else {
46676
- targetDir = import_path7.default.resolve(secureBaseDir, directory);
46677
- if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + import_path7.default.sep) && targetDir !== secureBaseDir) {
47645
+ targetDir = import_path8.default.resolve(secureBaseDir, directory);
47646
+ if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + import_path8.default.sep) && targetDir !== secureBaseDir) {
46678
47647
  throw new Error(`Path traversal attempt detected. Access denied: ${directory}`);
46679
47648
  }
46680
47649
  }
@@ -46691,7 +47660,7 @@ var init_probeTool = __esm({
46691
47660
  return `${(size / (1024 * 1024 * 1024)).toFixed(1)}G`;
46692
47661
  };
46693
47662
  const entries = await Promise.all(files.map(async (file) => {
46694
- const fullPath = import_path7.default.join(targetDir, file.name);
47663
+ const fullPath = import_path8.default.join(targetDir, file.name);
46695
47664
  const entryType = await getEntryType(file, fullPath);
46696
47665
  return {
46697
47666
  name: file.name,
@@ -46728,17 +47697,17 @@ var init_probeTool = __esm({
46728
47697
  throw new Error("Pattern is required for file search");
46729
47698
  }
46730
47699
  const baseCwd = workingDirectory || process.cwd();
46731
- const secureBaseDir = import_path7.default.resolve(baseCwd);
47700
+ const secureBaseDir = import_path8.default.resolve(baseCwd);
46732
47701
  const isDependencyPath = directory.startsWith("/dep/") || directory.startsWith("go:") || directory.startsWith("js:") || directory.startsWith("rust:");
46733
47702
  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) {
47703
+ if (import_path8.default.isAbsolute(directory)) {
47704
+ targetDir = import_path8.default.resolve(directory);
47705
+ if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + import_path8.default.sep) && targetDir !== secureBaseDir) {
46737
47706
  throw new Error(`Path traversal attempt detected. Cannot access directory outside workspace: ${directory}`);
46738
47707
  }
46739
47708
  } else {
46740
- targetDir = import_path7.default.resolve(secureBaseDir, directory);
46741
- if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + import_path7.default.sep) && targetDir !== secureBaseDir) {
47709
+ targetDir = import_path8.default.resolve(secureBaseDir, directory);
47710
+ if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + import_path8.default.sep) && targetDir !== secureBaseDir) {
46742
47711
  throw new Error(`Path traversal attempt detected. Access denied: ${directory}`);
46743
47712
  }
46744
47713
  }
@@ -46784,7 +47753,7 @@ function createMockProvider() {
46784
47753
  provider: "mock",
46785
47754
  // Mock the doGenerate method used by Vercel AI SDK
46786
47755
  doGenerate: async ({ messages, tools: tools2 }) => {
46787
- await new Promise((resolve7) => setTimeout(resolve7, 10));
47756
+ await new Promise((resolve8) => setTimeout(resolve8, 10));
46788
47757
  return {
46789
47758
  text: "This is a mock response for testing",
46790
47759
  toolCalls: [],
@@ -51987,23 +52956,23 @@ var init_regexp_parser = __esm({
51987
52956
  return ASSERT_NEVER_REACH_HERE();
51988
52957
  }
51989
52958
  quantifier(isBacktracking = false) {
51990
- let range2 = void 0;
52959
+ let range3 = void 0;
51991
52960
  const begin = this.idx;
51992
52961
  switch (this.popChar()) {
51993
52962
  case "*":
51994
- range2 = {
52963
+ range3 = {
51995
52964
  atLeast: 0,
51996
52965
  atMost: Infinity
51997
52966
  };
51998
52967
  break;
51999
52968
  case "+":
52000
- range2 = {
52969
+ range3 = {
52001
52970
  atLeast: 1,
52002
52971
  atMost: Infinity
52003
52972
  };
52004
52973
  break;
52005
52974
  case "?":
52006
- range2 = {
52975
+ range3 = {
52007
52976
  atLeast: 0,
52008
52977
  atMost: 1
52009
52978
  };
@@ -52012,7 +52981,7 @@ var init_regexp_parser = __esm({
52012
52981
  const atLeast = this.integerIncludingZero();
52013
52982
  switch (this.popChar()) {
52014
52983
  case "}":
52015
- range2 = {
52984
+ range3 = {
52016
52985
  atLeast,
52017
52986
  atMost: atLeast
52018
52987
  };
@@ -52021,12 +52990,12 @@ var init_regexp_parser = __esm({
52021
52990
  let atMost;
52022
52991
  if (this.isDigit()) {
52023
52992
  atMost = this.integerIncludingZero();
52024
- range2 = {
52993
+ range3 = {
52025
52994
  atLeast,
52026
52995
  atMost
52027
52996
  };
52028
52997
  } else {
52029
- range2 = {
52998
+ range3 = {
52030
52999
  atLeast,
52031
53000
  atMost: Infinity
52032
53001
  };
@@ -52034,25 +53003,25 @@ var init_regexp_parser = __esm({
52034
53003
  this.consumeChar("}");
52035
53004
  break;
52036
53005
  }
52037
- if (isBacktracking === true && range2 === void 0) {
53006
+ if (isBacktracking === true && range3 === void 0) {
52038
53007
  return void 0;
52039
53008
  }
52040
- ASSERT_EXISTS(range2);
53009
+ ASSERT_EXISTS(range3);
52041
53010
  break;
52042
53011
  }
52043
- if (isBacktracking === true && range2 === void 0) {
53012
+ if (isBacktracking === true && range3 === void 0) {
52044
53013
  return void 0;
52045
53014
  }
52046
- if (ASSERT_EXISTS(range2)) {
53015
+ if (ASSERT_EXISTS(range3)) {
52047
53016
  if (this.peekChar(0) === "?") {
52048
53017
  this.consumeChar("?");
52049
- range2.greedy = false;
53018
+ range3.greedy = false;
52050
53019
  } else {
52051
- range2.greedy = true;
53020
+ range3.greedy = true;
52052
53021
  }
52053
- range2.type = "Quantifier";
52054
- range2.loc = this.loc(begin);
52055
- return range2;
53022
+ range3.type = "Quantifier";
53023
+ range3.loc = this.loc(begin);
53024
+ return range3;
52056
53025
  }
52057
53026
  }
52058
53027
  atom() {
@@ -52754,18 +53723,18 @@ function firstCharOptimizedIndices(ast, result, ignoreCase) {
52754
53723
  if (typeof code === "number") {
52755
53724
  addOptimizedIdxToResult(code, result, ignoreCase);
52756
53725
  } else {
52757
- const range2 = code;
53726
+ const range3 = code;
52758
53727
  if (ignoreCase === true) {
52759
- for (let rangeCode = range2.from; rangeCode <= range2.to; rangeCode++) {
53728
+ for (let rangeCode = range3.from; rangeCode <= range3.to; rangeCode++) {
52760
53729
  addOptimizedIdxToResult(rangeCode, result, ignoreCase);
52761
53730
  }
52762
53731
  } else {
52763
- for (let rangeCode = range2.from; rangeCode <= range2.to && rangeCode < minOptimizationVal; rangeCode++) {
53732
+ for (let rangeCode = range3.from; rangeCode <= range3.to && rangeCode < minOptimizationVal; rangeCode++) {
52764
53733
  addOptimizedIdxToResult(rangeCode, result, ignoreCase);
52765
53734
  }
52766
- if (range2.to >= minOptimizationVal) {
52767
- const minUnOptVal = range2.from >= minOptimizationVal ? range2.from : minOptimizationVal;
52768
- const maxUnOptVal = range2.to;
53735
+ if (range3.to >= minOptimizationVal) {
53736
+ const minUnOptVal = range3.from >= minOptimizationVal ? range3.from : minOptimizationVal;
53737
+ const maxUnOptVal = range3.to;
52769
53738
  const minOptIdx = charCodeToOptimizedIndex(minUnOptVal);
52770
53739
  const maxOptIdx = charCodeToOptimizedIndex(maxUnOptVal);
52771
53740
  for (let currOptIdx = minOptIdx; currOptIdx <= maxOptIdx; currOptIdx++) {
@@ -52826,8 +53795,8 @@ function findCode(setNode, targetCharCodes) {
52826
53795
  if (typeof codeOrRange === "number") {
52827
53796
  return includes_default(targetCharCodes, codeOrRange);
52828
53797
  } else {
52829
- const range2 = codeOrRange;
52830
- return find_default(targetCharCodes, (targetCode) => range2.from <= targetCode && targetCode <= range2.to) !== void 0;
53798
+ const range3 = codeOrRange;
53799
+ return find_default(targetCharCodes, (targetCode) => range3.from <= targetCode && targetCode <= range3.to) !== void 0;
52831
53800
  }
52832
53801
  });
52833
53802
  }
@@ -70732,8 +71701,8 @@ var require_createRange = __commonJS({
70732
71701
  var require_range = __commonJS({
70733
71702
  "node_modules/lodash/range.js"(exports2, module2) {
70734
71703
  var createRange = require_createRange();
70735
- var range2 = createRange();
70736
- module2.exports = range2;
71704
+ var range3 = createRange();
71705
+ module2.exports = range3;
70737
71706
  }
70738
71707
  });
70739
71708
 
@@ -79974,7 +80943,7 @@ var require_compile = __commonJS({
79974
80943
  const schOrFunc = root2.refs[ref2];
79975
80944
  if (schOrFunc)
79976
80945
  return schOrFunc;
79977
- let _sch = resolve7.call(this, root2, ref2);
80946
+ let _sch = resolve8.call(this, root2, ref2);
79978
80947
  if (_sch === void 0) {
79979
80948
  const schema = (_a16 = root2.localRefs) === null || _a16 === void 0 ? void 0 : _a16[ref2];
79980
80949
  const { schemaId } = this.opts;
@@ -80001,7 +80970,7 @@ var require_compile = __commonJS({
80001
80970
  function sameSchemaEnv(s1, s22) {
80002
80971
  return s1.schema === s22.schema && s1.root === s22.root && s1.baseId === s22.baseId;
80003
80972
  }
80004
- function resolve7(root2, ref2) {
80973
+ function resolve8(root2, ref2) {
80005
80974
  let sch;
80006
80975
  while (typeof (sch = this.refs[ref2]) == "string")
80007
80976
  ref2 = sch;
@@ -80576,7 +81545,7 @@ var require_fast_uri = __commonJS({
80576
81545
  }
80577
81546
  return uri;
80578
81547
  }
80579
- function resolve7(baseURI, relativeURI, options) {
81548
+ function resolve8(baseURI, relativeURI, options) {
80580
81549
  const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
80581
81550
  const resolved = resolveComponent(parse9(baseURI, schemelessOptions), parse9(relativeURI, schemelessOptions), schemelessOptions, true);
80582
81551
  schemelessOptions.skipEscape = true;
@@ -80803,7 +81772,7 @@ var require_fast_uri = __commonJS({
80803
81772
  var fastUri = {
80804
81773
  SCHEMES,
80805
81774
  normalize: normalize3,
80806
- resolve: resolve7,
81775
+ resolve: resolve8,
80807
81776
  resolveComponent,
80808
81777
  equal,
80809
81778
  serialize,
@@ -83496,6 +84465,7 @@ __export(schemaUtils_exports, {
83496
84465
  processSchemaResponse: () => processSchemaResponse,
83497
84466
  replaceMermaidDiagramsInJson: () => replaceMermaidDiagramsInJson,
83498
84467
  replaceMermaidDiagramsInMarkdown: () => replaceMermaidDiagramsInMarkdown,
84468
+ sanitizeMarkdownEscapesInJson: () => sanitizeMarkdownEscapesInJson,
83499
84469
  tryAutoWrapForSimpleSchema: () => tryAutoWrapForSimpleSchema,
83500
84470
  tryMaidAutoFix: () => tryMaidAutoFix,
83501
84471
  validateAndFixMermaidResponse: () => validateAndFixMermaidResponse,
@@ -83599,6 +84569,17 @@ function decodeHtmlEntities(text) {
83599
84569
  }
83600
84570
  return decoded;
83601
84571
  }
84572
+ function sanitizeMarkdownEscapesInJson(jsonString) {
84573
+ if (!jsonString || typeof jsonString !== "string") {
84574
+ return jsonString;
84575
+ }
84576
+ return jsonString.replace(/\\\\|\\([^"\\\/bfnrtu])/g, (match2, captured) => {
84577
+ if (match2 === "\\\\") {
84578
+ return "\\\\";
84579
+ }
84580
+ return captured;
84581
+ });
84582
+ }
83602
84583
  function normalizeJsonQuotes(str) {
83603
84584
  if (!str || typeof str !== "string") {
83604
84585
  return str;
@@ -83651,6 +84632,15 @@ function cleanSchemaResponse(response) {
83651
84632
  if (resultWrapperMatch) {
83652
84633
  return cleanSchemaResponse(resultWrapperMatch[1]);
83653
84634
  }
84635
+ const toolCodeMatch = trimmed.match(/<tool_code>\s*([\s\S]*?)\s*<\/tool_code>/);
84636
+ if (toolCodeMatch) {
84637
+ let innerContent = toolCodeMatch[1].trim();
84638
+ const funcCallMatch = innerContent.match(/(?:print|attempt_completion)\s*\(\s*([{\[][\s\S]*[}\]])\s*\)/);
84639
+ if (funcCallMatch) {
84640
+ return cleanSchemaResponse(funcCallMatch[1]);
84641
+ }
84642
+ return cleanSchemaResponse(innerContent);
84643
+ }
83654
84644
  const jsonBlockMatch = trimmed.match(/```json\s*\n([\s\S]*?)\n```/);
83655
84645
  if (jsonBlockMatch) {
83656
84646
  return normalizeJsonQuotes(jsonBlockMatch[1].trim());
@@ -83718,9 +84708,25 @@ function validateJsonResponse(response, options = {}) {
83718
84708
  console.log(`[DEBUG] JSON validation: Schema validation enabled`);
83719
84709
  }
83720
84710
  }
84711
+ let responseToValidate = response;
84712
+ try {
84713
+ JSON.parse(response);
84714
+ } catch (initialError) {
84715
+ if (initialError.message && initialError.message.includes("escape")) {
84716
+ const sanitized = sanitizeMarkdownEscapesInJson(response);
84717
+ try {
84718
+ JSON.parse(sanitized);
84719
+ responseToValidate = sanitized;
84720
+ if (debug) {
84721
+ console.log(`[DEBUG] JSON validation: Fixed Markdown escapes in JSON (issue #441)`);
84722
+ }
84723
+ } catch {
84724
+ }
84725
+ }
84726
+ }
83721
84727
  try {
83722
84728
  const parseStart = Date.now();
83723
- const parsed = JSON.parse(response);
84729
+ const parsed = JSON.parse(responseToValidate);
83724
84730
  const parseTime = Date.now() - parseStart;
83725
84731
  if (debug) {
83726
84732
  console.log(`[DEBUG] JSON validation: Successfully parsed in ${parseTime}ms`);
@@ -84062,7 +85068,21 @@ function tryAutoWrapForSimpleSchema(response, schema, options = {}) {
84062
85068
  console.log(`[DEBUG] Auto-wrap: Response is already valid JSON, skipping`);
84063
85069
  }
84064
85070
  return null;
84065
- } catch {
85071
+ } catch (initialError) {
85072
+ if (initialError.message && initialError.message.includes("escape")) {
85073
+ try {
85074
+ const sanitized = sanitizeMarkdownEscapesInJson(response);
85075
+ JSON.parse(sanitized);
85076
+ if (debug) {
85077
+ console.log(`[DEBUG] Auto-wrap: Fixed Markdown escapes in JSON (issue #441), returning sanitized JSON`);
85078
+ }
85079
+ return sanitized;
85080
+ } catch {
85081
+ if (debug) {
85082
+ console.log(`[DEBUG] Auto-wrap: Markdown escape sanitization didn't fix JSON, proceeding with wrapping`);
85083
+ }
85084
+ }
85085
+ }
84066
85086
  }
84067
85087
  const wrapped = JSON.stringify({ [wrapperInfo.fieldName]: response });
84068
85088
  if (debug) {
@@ -85275,13 +86295,13 @@ function loadMCPConfiguration() {
85275
86295
  // Environment variable path
85276
86296
  process.env.MCP_CONFIG_PATH,
85277
86297
  // Local project paths
85278
- (0, import_path8.join)(process.cwd(), ".mcp", "config.json"),
85279
- (0, import_path8.join)(process.cwd(), "mcp.config.json"),
86298
+ (0, import_path9.join)(process.cwd(), ".mcp", "config.json"),
86299
+ (0, import_path9.join)(process.cwd(), "mcp.config.json"),
85280
86300
  // Home directory paths
85281
- (0, import_path8.join)((0, import_os3.homedir)(), ".config", "probe", "mcp.json"),
85282
- (0, import_path8.join)((0, import_os3.homedir)(), ".mcp", "config.json"),
86301
+ (0, import_path9.join)((0, import_os3.homedir)(), ".config", "probe", "mcp.json"),
86302
+ (0, import_path9.join)((0, import_os3.homedir)(), ".mcp", "config.json"),
85283
86303
  // Claude-style config location
85284
- (0, import_path8.join)((0, import_os3.homedir)(), "Library", "Application Support", "Claude", "mcp_config.json")
86304
+ (0, import_path9.join)((0, import_os3.homedir)(), "Library", "Application Support", "Claude", "mcp_config.json")
85285
86305
  ].filter(Boolean);
85286
86306
  let config = null;
85287
86307
  for (const configPath of configPaths) {
@@ -85408,16 +86428,16 @@ function parseEnabledServers(config) {
85408
86428
  }
85409
86429
  return servers;
85410
86430
  }
85411
- var import_fs9, import_path8, import_os3, import_url4, __filename4, __dirname4, DEFAULT_TIMEOUT, MAX_TIMEOUT, DEFAULT_CONFIG;
86431
+ var import_fs9, import_path9, import_os3, import_url4, __filename4, __dirname4, DEFAULT_TIMEOUT, MAX_TIMEOUT, DEFAULT_CONFIG;
85412
86432
  var init_config = __esm({
85413
86433
  "src/agent/mcp/config.js"() {
85414
86434
  "use strict";
85415
86435
  import_fs9 = require("fs");
85416
- import_path8 = require("path");
86436
+ import_path9 = require("path");
85417
86437
  import_os3 = require("os");
85418
86438
  import_url4 = require("url");
85419
86439
  __filename4 = (0, import_url4.fileURLToPath)("file:///");
85420
- __dirname4 = (0, import_path8.dirname)(__filename4);
86440
+ __dirname4 = (0, import_path9.dirname)(__filename4);
85421
86441
  DEFAULT_TIMEOUT = 3e4;
85422
86442
  MAX_TIMEOUT = (() => {
85423
86443
  if (process.env.MCP_MAX_TIMEOUT) {
@@ -85431,7 +86451,7 @@ var init_config = __esm({
85431
86451
  // Example probe server configuration
85432
86452
  "probe-local": {
85433
86453
  command: "node",
85434
- args: [(0, import_path8.join)(__dirname4, "../../../examples/chat/mcpServer.js")],
86454
+ args: [(0, import_path9.join)(__dirname4, "../../../examples/chat/mcpServer.js")],
85435
86455
  transport: "stdio",
85436
86456
  enabled: false
85437
86457
  },
@@ -91014,7 +92034,7 @@ var require_compose_scalar = __commonJS({
91014
92034
  var resolveBlockScalar = require_resolve_block_scalar();
91015
92035
  var resolveFlowScalar = require_resolve_flow_scalar();
91016
92036
  function composeScalar(ctx, token, tagToken, onError) {
91017
- const { value, type, comment, range: range2 } = token.type === "block-scalar" ? resolveBlockScalar.resolveBlockScalar(ctx, token, onError) : resolveFlowScalar.resolveFlowScalar(token, ctx.options.strict, onError);
92037
+ const { value, type, comment, range: range3 } = token.type === "block-scalar" ? resolveBlockScalar.resolveBlockScalar(ctx, token, onError) : resolveFlowScalar.resolveFlowScalar(token, ctx.options.strict, onError);
91018
92038
  const tagName = tagToken ? ctx.directives.tagName(tagToken.source, (msg) => onError(tagToken, "TAG_RESOLVE_FAILED", msg)) : null;
91019
92039
  let tag2;
91020
92040
  if (ctx.options.stringKeys && ctx.atKey) {
@@ -91034,7 +92054,7 @@ var require_compose_scalar = __commonJS({
91034
92054
  onError(tagToken ?? token, "TAG_RESOLVE_FAILED", msg);
91035
92055
  scalar = new Scalar.Scalar(value);
91036
92056
  }
91037
- scalar.range = range2;
92057
+ scalar.range = range3;
91038
92058
  scalar.source = value;
91039
92059
  if (type)
91040
92060
  scalar.type = type;
@@ -93625,17 +94645,17 @@ async function parseSkillFile(skillFilePath, directoryName) {
93625
94645
  description,
93626
94646
  skillFilePath,
93627
94647
  directoryName,
93628
- sourceDir: (0, import_path9.dirname)(skillFilePath)
94648
+ sourceDir: (0, import_path10.dirname)(skillFilePath)
93629
94649
  },
93630
94650
  error: null
93631
94651
  };
93632
94652
  }
93633
- var import_promises2, import_path9, import_yaml, SKILL_NAME_REGEX, MAX_SKILL_NAME_LENGTH, MAX_DESCRIPTION_CHARS;
94653
+ var import_promises2, import_path10, import_yaml, SKILL_NAME_REGEX, MAX_SKILL_NAME_LENGTH, MAX_DESCRIPTION_CHARS;
93634
94654
  var init_parser7 = __esm({
93635
94655
  "src/agent/skills/parser.js"() {
93636
94656
  "use strict";
93637
94657
  import_promises2 = require("fs/promises");
93638
- import_path9 = require("path");
94658
+ import_path10 = require("path");
93639
94659
  import_yaml = __toESM(require_dist(), 1);
93640
94660
  SKILL_NAME_REGEX = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
93641
94661
  MAX_SKILL_NAME_LENGTH = 64;
@@ -93645,12 +94665,12 @@ var init_parser7 = __esm({
93645
94665
 
93646
94666
  // src/agent/skills/registry.js
93647
94667
  function isPathInside(basePath, targetPath) {
93648
- const base2 = (0, import_path10.resolve)(basePath);
93649
- const target = (0, import_path10.resolve)(targetPath);
93650
- const rel = (0, import_path10.relative)(base2, target);
94668
+ const base2 = (0, import_path11.resolve)(basePath);
94669
+ const target = (0, import_path11.resolve)(targetPath);
94670
+ const rel = (0, import_path11.relative)(base2, target);
93651
94671
  if (rel === "") return true;
93652
- if (rel === ".." || rel.startsWith(`..${import_path10.sep}`)) return false;
93653
- if ((0, import_path10.isAbsolute)(rel)) return false;
94672
+ if (rel === ".." || rel.startsWith(`..${import_path11.sep}`)) return false;
94673
+ if ((0, import_path11.isAbsolute)(rel)) return false;
93654
94674
  return true;
93655
94675
  }
93656
94676
  function isSafeEntryName(name14) {
@@ -93658,19 +94678,19 @@ function isSafeEntryName(name14) {
93658
94678
  if (name14.includes("\0")) return false;
93659
94679
  return !name14.includes("/") && !name14.includes("\\");
93660
94680
  }
93661
- var import_fs10, import_promises3, import_path10, DEFAULT_SKILL_DIRS, SKILL_FILE_NAME, SkillRegistry;
94681
+ var import_fs10, import_promises3, import_path11, DEFAULT_SKILL_DIRS, SKILL_FILE_NAME, SkillRegistry;
93662
94682
  var init_registry = __esm({
93663
94683
  "src/agent/skills/registry.js"() {
93664
94684
  "use strict";
93665
94685
  import_fs10 = require("fs");
93666
94686
  import_promises3 = require("fs/promises");
93667
- import_path10 = require("path");
94687
+ import_path11 = require("path");
93668
94688
  init_parser7();
93669
94689
  DEFAULT_SKILL_DIRS = [".claude/skills", ".codex/skills", "skills", ".skills"];
93670
94690
  SKILL_FILE_NAME = "SKILL.md";
93671
94691
  SkillRegistry = class {
93672
94692
  constructor({ repoRoot, skillDirs = DEFAULT_SKILL_DIRS, debug = false } = {}) {
93673
- this.repoRoot = repoRoot ? (0, import_path10.resolve)(repoRoot) : process.cwd();
94693
+ this.repoRoot = repoRoot ? (0, import_path11.resolve)(repoRoot) : process.cwd();
93674
94694
  this.repoRootReal = null;
93675
94695
  this.skillDirs = Array.isArray(skillDirs) && skillDirs.length > 0 ? skillDirs : DEFAULT_SKILL_DIRS;
93676
94696
  this.debug = debug;
@@ -93724,8 +94744,8 @@ var init_registry = __esm({
93724
94744
  }
93725
94745
  }
93726
94746
  async _resolveSkillDir(skillDir) {
93727
- const resolved = (0, import_path10.isAbsolute)(skillDir) ? (0, import_path10.resolve)(skillDir) : (0, import_path10.resolve)(this.repoRoot, skillDir);
93728
- const repoRoot = this.repoRootReal || (0, import_path10.resolve)(this.repoRoot);
94747
+ const resolved = (0, import_path11.isAbsolute)(skillDir) ? (0, import_path11.resolve)(skillDir) : (0, import_path11.resolve)(this.repoRoot, skillDir);
94748
+ const repoRoot = this.repoRootReal || (0, import_path11.resolve)(this.repoRoot);
93729
94749
  const resolvedReal = await this._resolveRealPath(resolved);
93730
94750
  if (!resolvedReal) return null;
93731
94751
  if (!isPathInside(repoRoot, resolvedReal)) {
@@ -93756,8 +94776,8 @@ var init_registry = __esm({
93756
94776
  }
93757
94777
  continue;
93758
94778
  }
93759
- const skillFolder = (0, import_path10.join)(dirPath, entry.name);
93760
- const skillFilePath = (0, import_path10.join)(skillFolder, SKILL_FILE_NAME);
94779
+ const skillFolder = (0, import_path11.join)(dirPath, entry.name);
94780
+ const skillFilePath = (0, import_path11.join)(skillFolder, SKILL_FILE_NAME);
93761
94781
  let skillStat;
93762
94782
  try {
93763
94783
  skillStat = await (0, import_promises3.lstat)(skillFilePath);
@@ -93915,7 +94935,7 @@ function extractErrorInfo(error2) {
93915
94935
  };
93916
94936
  }
93917
94937
  function sleep(ms) {
93918
- return new Promise((resolve7) => setTimeout(resolve7, ms));
94938
+ return new Promise((resolve8) => setTimeout(resolve8, ms));
93919
94939
  }
93920
94940
  var DEFAULT_RETRYABLE_ERRORS, RetryManager;
93921
94941
  var init_RetryManager = __esm({
@@ -94695,9 +95715,9 @@ async function truncateIfNeeded(content, tokenCounter, sessionId, maxTokens) {
94695
95715
  let tempFilePath = null;
94696
95716
  let fileError = null;
94697
95717
  try {
94698
- const tempDir = (0, import_path11.join)((0, import_os4.tmpdir)(), "probe-output");
95718
+ const tempDir = (0, import_path12.join)((0, import_os4.tmpdir)(), "probe-output");
94699
95719
  await (0, import_promises4.mkdir)(tempDir, { recursive: true });
94700
- tempFilePath = (0, import_path11.join)(tempDir, `tool-output-${sessionId || "unknown"}-${(0, import_crypto4.randomUUID)()}.txt`);
95720
+ tempFilePath = (0, import_path12.join)(tempDir, `tool-output-${sessionId || "unknown"}-${(0, import_crypto5.randomUUID)()}.txt`);
94701
95721
  await (0, import_promises4.writeFile)(tempFilePath, content, "utf8");
94702
95722
  } catch (err) {
94703
95723
  fileError = err.message || "Unknown file system error";
@@ -94745,14 +95765,14 @@ ${truncatedBody}
94745
95765
  error: fileError || void 0
94746
95766
  };
94747
95767
  }
94748
- var import_promises4, import_os4, import_path11, import_crypto4, DEFAULT_MAX_OUTPUT_TOKENS, CHARS_PER_TOKEN, TAIL_TOKENS, MIN_LIMIT_FOR_TAIL;
95768
+ var import_promises4, import_os4, import_path12, import_crypto5, DEFAULT_MAX_OUTPUT_TOKENS, CHARS_PER_TOKEN, TAIL_TOKENS, MIN_LIMIT_FOR_TAIL;
94749
95769
  var init_outputTruncator = __esm({
94750
95770
  "src/agent/outputTruncator.js"() {
94751
95771
  "use strict";
94752
95772
  import_promises4 = require("fs/promises");
94753
95773
  import_os4 = require("os");
94754
- import_path11 = require("path");
94755
- import_crypto4 = require("crypto");
95774
+ import_path12 = require("path");
95775
+ import_crypto5 = require("crypto");
94756
95776
  DEFAULT_MAX_OUTPUT_TOKENS = 2e4;
94757
95777
  CHARS_PER_TOKEN = 4;
94758
95778
  TAIL_TOKENS = 1e3;
@@ -95874,14 +96894,14 @@ var require_executor = __commonJS({
95874
96894
  function asyncDone(callback) {
95875
96895
  let isInstant = false;
95876
96896
  let instant;
95877
- const p5 = new Promise((resolve7, reject2) => {
96897
+ const p5 = new Promise((resolve8, reject2) => {
95878
96898
  callback((err, result) => {
95879
96899
  if (err)
95880
96900
  reject2(err);
95881
96901
  else {
95882
96902
  isInstant = true;
95883
96903
  instant = result;
95884
- resolve7({ result });
96904
+ resolve8({ result });
95885
96905
  }
95886
96906
  });
95887
96907
  });
@@ -95904,10 +96924,10 @@ var require_executor = __commonJS({
95904
96924
  }
95905
96925
  async function execAsync4(ticks, tree, scope, context, doneOriginal, inLoopOrSwitch) {
95906
96926
  let done = doneOriginal;
95907
- const p5 = new Promise((resolve7) => {
96927
+ const p5 = new Promise((resolve8) => {
95908
96928
  done = (e5, r5) => {
95909
96929
  doneOriginal(e5, r5);
95910
- resolve7();
96930
+ resolve8();
95911
96931
  };
95912
96932
  });
95913
96933
  if (!_execNoneRecurse(ticks, tree, scope, context, done, true, inLoopOrSwitch) && utils.isLisp(tree)) {
@@ -104258,6 +105278,13 @@ function generateSandboxGlobals(options) {
104258
105278
  if (i5 < keys2.length) params[keys2[i5]] = arg;
104259
105279
  });
104260
105280
  }
105281
+ if (params.path && typeof params.path === "object") {
105282
+ const coercedPath = params.path.file_path || params.path.path || params.path.directory || params.path.filename;
105283
+ if (coercedPath && typeof coercedPath === "string") {
105284
+ logFn?.(`[${name14}] Warning: Coerced object path to string "${coercedPath}" (issue #444)`);
105285
+ params.path = coercedPath;
105286
+ }
105287
+ }
104261
105288
  const validated = schema.safeParse(params);
104262
105289
  if (!validated.success) {
104263
105290
  throw new Error(`Invalid parameters for ${name14}: ${validated.error.message}`);
@@ -104294,6 +105321,11 @@ function generateSandboxGlobals(options) {
104294
105321
  }
104295
105322
  if (llmCall) {
104296
105323
  const rawLLM = async (instruction, data3, opts = {}) => {
105324
+ const dataStr = typeof data3 === "string" ? data3 : JSON.stringify(data3);
105325
+ if (dataStr && dataStr.startsWith("ERROR:")) {
105326
+ logFn?.("[LLM] Blocked: data contains error from previous tool call");
105327
+ return "ERROR: Previous tool call failed - " + dataStr.substring(0, 200);
105328
+ }
104297
105329
  const result = await llmCall(instruction, data3, opts);
104298
105330
  if (opts.schema && typeof result === "string") {
104299
105331
  try {
@@ -105859,7 +106891,7 @@ async function executeBashCommand(command, options = {}) {
105859
106891
  } = options;
105860
106892
  let cwd = workingDirectory;
105861
106893
  try {
105862
- cwd = (0, import_path12.resolve)(cwd);
106894
+ cwd = (0, import_path13.resolve)(cwd);
105863
106895
  if (!(0, import_fs11.existsSync)(cwd)) {
105864
106896
  throw new Error(`Working directory does not exist: ${cwd}`);
105865
106897
  }
@@ -105881,7 +106913,7 @@ async function executeBashCommand(command, options = {}) {
105881
106913
  console.log(`[BashExecutor] Working directory: "${cwd}"`);
105882
106914
  console.log(`[BashExecutor] Timeout: ${timeout}ms`);
105883
106915
  }
105884
- return new Promise((resolve7, reject2) => {
106916
+ return new Promise((resolve8, reject2) => {
105885
106917
  const processEnv = {
105886
106918
  ...process.env,
105887
106919
  ...env
@@ -105898,7 +106930,7 @@ async function executeBashCommand(command, options = {}) {
105898
106930
  } else {
105899
106931
  const args = parseCommandForExecution(command);
105900
106932
  if (!args || args.length === 0) {
105901
- resolve7({
106933
+ resolve8({
105902
106934
  success: false,
105903
106935
  error: "Failed to parse command",
105904
106936
  stdout: "",
@@ -105983,7 +107015,7 @@ async function executeBashCommand(command, options = {}) {
105983
107015
  success = false;
105984
107016
  error2 = `Command exited with code ${code}`;
105985
107017
  }
105986
- resolve7({
107018
+ resolve8({
105987
107019
  success,
105988
107020
  error: error2,
105989
107021
  stdout: stdout.trim(),
@@ -106003,7 +107035,7 @@ async function executeBashCommand(command, options = {}) {
106003
107035
  if (debug) {
106004
107036
  console.log(`[BashExecutor] Spawn error:`, error2);
106005
107037
  }
106006
- resolve7({
107038
+ resolve8({
106007
107039
  success: false,
106008
107040
  error: `Failed to execute command: ${error2.message}`,
106009
107041
  stdout: "",
@@ -106097,24 +107129,24 @@ function validateExecutionOptions(options = {}) {
106097
107129
  warnings
106098
107130
  };
106099
107131
  }
106100
- var import_child_process7, import_path12, import_fs11;
107132
+ var import_child_process7, import_path13, import_fs11;
106101
107133
  var init_bashExecutor = __esm({
106102
107134
  "src/agent/bashExecutor.js"() {
106103
107135
  "use strict";
106104
107136
  import_child_process7 = require("child_process");
106105
- import_path12 = require("path");
107137
+ import_path13 = require("path");
106106
107138
  import_fs11 = require("fs");
106107
107139
  init_bashCommandUtils();
106108
107140
  }
106109
107141
  });
106110
107142
 
106111
107143
  // src/tools/bash.js
106112
- var import_ai2, import_path13, bashTool;
107144
+ var import_ai2, import_path14, bashTool;
106113
107145
  var init_bash = __esm({
106114
107146
  "src/tools/bash.js"() {
106115
107147
  "use strict";
106116
107148
  import_ai2 = require("ai");
106117
- import_path13 = require("path");
107149
+ import_path14 = require("path");
106118
107150
  init_bashPermissions();
106119
107151
  init_bashExecutor();
106120
107152
  init_path_validation();
@@ -106231,12 +107263,12 @@ For code exploration, try these safe alternatives:
106231
107263
  - npm list, pip list for package information`;
106232
107264
  }
106233
107265
  const defaultDir = getDefaultWorkingDirectory();
106234
- const workingDir = workingDirectory ? (0, import_path13.isAbsolute)(workingDirectory) ? (0, import_path13.resolve)(workingDirectory) : (0, import_path13.resolve)(defaultDir, workingDirectory) : defaultDir;
107266
+ const workingDir = workingDirectory ? (0, import_path14.isAbsolute)(workingDirectory) ? (0, import_path14.resolve)(workingDirectory) : (0, import_path14.resolve)(defaultDir, workingDirectory) : defaultDir;
106235
107267
  if (allowedFolders && allowedFolders.length > 0) {
106236
107268
  const resolvedWorkingDir = safeRealpath(workingDir);
106237
107269
  const isAllowed = allowedFolders.some((folder) => {
106238
107270
  const resolvedFolder = safeRealpath(folder);
106239
- return resolvedWorkingDir === resolvedFolder || resolvedWorkingDir.startsWith(resolvedFolder + import_path13.sep);
107271
+ return resolvedWorkingDir === resolvedFolder || resolvedWorkingDir.startsWith(resolvedFolder + import_path14.sep);
106240
107272
  });
106241
107273
  if (!isAllowed) {
106242
107274
  const relativeDir = toRelativePath(workingDir, workspaceRoot);
@@ -106591,6 +107623,7 @@ ${lastError}
106591
107623
 
106592
107624
  RULES REMINDER:
106593
107625
  - search(query) is KEYWORD SEARCH \u2014 pass a search query, NOT a filename. Use extract(filepath) to read file contents.
107626
+ - search(query, path) \u2014 the path argument must be a STRING, not an object. Use field.file_path, not field.
106594
107627
  - search() returns up to 20K tokens by default. Use search(query, path, {maxTokens: null}) for unlimited, or searchAll(query) to auto-paginate ALL results.
106595
107628
  - search(), searchAll(), query(), extract(), listFiles(), bash() all return STRINGS, not arrays.
106596
107629
  - Use chunk(stringData) to split a string into an array of chunks.
@@ -106599,7 +107632,8 @@ RULES REMINDER:
106599
107632
  - Do NOT define helper functions that call tools \u2014 write logic inline.
106600
107633
  - Do NOT use async/await, template literals, or shorthand properties.
106601
107634
  - Do NOT use regex literals (/pattern/) \u2014 use String methods like indexOf, includes, startsWith instead.
106602
- - String concatenation with +, not template literals.`;
107635
+ - String concatenation with +, not template literals.
107636
+ - IMPORTANT: If a tool returns "ERROR: ...", do NOT pass that error string to LLM() \u2014 handle or skip it.`;
106603
107637
  const fixedCode = await llmCallFn(fixPrompt, "", { maxTokens: 4e3, temperature: 0.2 });
106604
107638
  currentCode = stripCodeWrapping(fixedCode);
106605
107639
  planSpan?.addEvent?.("dsl.self_heal_complete", {
@@ -107213,7 +108247,7 @@ var init_executePlan = __esm({
107213
108247
  init_query();
107214
108248
  init_extract();
107215
108249
  init_delegate();
107216
- init_esm5();
108250
+ init_esm7();
107217
108251
  init_bash();
107218
108252
  RAW_OUTPUT_START = "<<<RAW_OUTPUT>>>";
107219
108253
  RAW_OUTPUT_END = "<<<END_RAW_OUTPUT>>>";
@@ -107221,13 +108255,13 @@ var init_executePlan = __esm({
107221
108255
  });
107222
108256
 
107223
108257
  // src/agent/mcp/built-in-server.js
107224
- var import_http, import_events2, import_crypto5, import_server, import_sse2, import_streamableHttp, import_types3, InMemoryEventStore, BuiltInMCPServer;
108258
+ var import_http, import_events2, import_crypto6, import_server, import_sse2, import_streamableHttp, import_types3, InMemoryEventStore, BuiltInMCPServer;
107225
108259
  var init_built_in_server = __esm({
107226
108260
  "src/agent/mcp/built-in-server.js"() {
107227
108261
  "use strict";
107228
108262
  import_http = require("http");
107229
108263
  import_events2 = require("events");
107230
- import_crypto5 = require("crypto");
108264
+ import_crypto6 = require("crypto");
107231
108265
  import_server = require("@modelcontextprotocol/sdk/server/index.js");
107232
108266
  import_sse2 = require("@modelcontextprotocol/sdk/server/sse.js");
107233
108267
  import_streamableHttp = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
@@ -107303,7 +108337,7 @@ var init_built_in_server = __esm({
107303
108337
  }
107304
108338
  });
107305
108339
  this.registerHandlers();
107306
- return new Promise((resolve7, reject2) => {
108340
+ return new Promise((resolve8, reject2) => {
107307
108341
  this.httpServer.listen(this.port, this.host, async () => {
107308
108342
  const address = this.httpServer.address();
107309
108343
  this.port = address.port;
@@ -107313,7 +108347,7 @@ var init_built_in_server = __esm({
107313
108347
  console.log(`[MCP] Messages endpoint: http://${this.host}:${this.port}/messages`);
107314
108348
  }
107315
108349
  this.emit("ready", { host: this.host, port: this.port });
107316
- resolve7({ host: this.host, port: this.port });
108350
+ resolve8({ host: this.host, port: this.port });
107317
108351
  });
107318
108352
  this.httpServer.on("error", reject2);
107319
108353
  });
@@ -107471,7 +108505,7 @@ var init_built_in_server = __esm({
107471
108505
  }
107472
108506
  const eventStore = new InMemoryEventStore();
107473
108507
  transport = new import_streamableHttp.StreamableHTTPServerTransport({
107474
- sessionIdGenerator: () => (0, import_crypto5.randomUUID)(),
108508
+ sessionIdGenerator: () => (0, import_crypto6.randomUUID)(),
107475
108509
  eventStore,
107476
108510
  // Enable resumability
107477
108511
  onsessioninitialized: (newSessionId) => {
@@ -107532,7 +108566,7 @@ var init_built_in_server = __esm({
107532
108566
  * Parse request body as JSON
107533
108567
  */
107534
108568
  async parseRequestBody(req) {
107535
- return new Promise((resolve7, reject2) => {
108569
+ return new Promise((resolve8, reject2) => {
107536
108570
  let body = "";
107537
108571
  req.on("data", (chunk) => {
107538
108572
  body += chunk.toString();
@@ -107540,7 +108574,7 @@ var init_built_in_server = __esm({
107540
108574
  req.on("end", () => {
107541
108575
  try {
107542
108576
  const parsed = body ? JSON.parse(body) : null;
107543
- resolve7(parsed);
108577
+ resolve8(parsed);
107544
108578
  } catch (error2) {
107545
108579
  reject2(error2);
107546
108580
  }
@@ -107847,12 +108881,12 @@ data: ${JSON.stringify(data3)}
107847
108881
  }
107848
108882
  this.connections.clear();
107849
108883
  if (this.httpServer) {
107850
- return new Promise((resolve7) => {
108884
+ return new Promise((resolve8) => {
107851
108885
  this.httpServer.close(() => {
107852
108886
  if (this.debug) {
107853
108887
  console.log("[MCP] Built-in server stopped");
107854
108888
  }
107855
- resolve7();
108889
+ resolve8();
107856
108890
  });
107857
108891
  });
107858
108892
  }
@@ -107934,7 +108968,7 @@ __export(enhanced_claude_code_exports, {
107934
108968
  async function createEnhancedClaudeCLIEngine(options = {}) {
107935
108969
  const { agent, systemPrompt, customPrompt, debug, sessionId, allowedTools, timeout = 12e4 } = options;
107936
108970
  const session = new Session(
107937
- sessionId || (0, import_crypto6.randomBytes)(8).toString("hex"),
108971
+ sessionId || (0, import_crypto7.randomBytes)(8).toString("hex"),
107938
108972
  debug
107939
108973
  );
107940
108974
  let mcpServer = null;
@@ -107951,12 +108985,12 @@ async function createEnhancedClaudeCLIEngine(options = {}) {
107951
108985
  console.log("[DEBUG] Built-in MCP server started");
107952
108986
  console.log("[DEBUG] MCP URL:", `http://${host}:${port}/mcp`);
107953
108987
  }
107954
- mcpConfigPath = import_path14.default.join(import_os5.default.tmpdir(), `probe-mcp-${session.id}.json`);
108988
+ mcpConfigPath = import_path15.default.join(import_os5.default.tmpdir(), `probe-mcp-${session.id}.json`);
107955
108989
  const mcpConfig = {
107956
108990
  mcpServers: {
107957
108991
  probe: {
107958
108992
  command: "node",
107959
- args: [import_path14.default.join(process.cwd(), "mcp-probe-server.js")],
108993
+ args: [import_path15.default.join(process.cwd(), "mcp-probe-server.js")],
107960
108994
  env: {
107961
108995
  PROBE_WORKSPACE: process.cwd(),
107962
108996
  DEBUG: debug ? "true" : "false"
@@ -108181,8 +109215,8 @@ ${opts.schema}`;
108181
109215
  break;
108182
109216
  }
108183
109217
  } else if (!processEnded) {
108184
- await new Promise((resolve7) => {
108185
- resolver = resolve7;
109218
+ await new Promise((resolve8) => {
109219
+ resolver = resolve8;
108186
109220
  });
108187
109221
  }
108188
109222
  }
@@ -108381,14 +109415,14 @@ function combinePrompts(systemPrompt, customPrompt, agent) {
108381
109415
  }
108382
109416
  return systemPrompt || "";
108383
109417
  }
108384
- var import_child_process8, import_crypto6, import_promises5, import_path14, import_os5, import_events3;
109418
+ var import_child_process8, import_crypto7, import_promises5, import_path15, import_os5, import_events3;
108385
109419
  var init_enhanced_claude_code = __esm({
108386
109420
  "src/agent/engines/enhanced-claude-code.js"() {
108387
109421
  "use strict";
108388
109422
  import_child_process8 = require("child_process");
108389
- import_crypto6 = require("crypto");
109423
+ import_crypto7 = require("crypto");
108390
109424
  import_promises5 = __toESM(require("fs/promises"), 1);
108391
- import_path14 = __toESM(require("path"), 1);
109425
+ import_path15 = __toESM(require("path"), 1);
108392
109426
  import_os5 = __toESM(require("os"), 1);
108393
109427
  import_events3 = require("events");
108394
109428
  init_built_in_server();
@@ -108404,7 +109438,7 @@ __export(codex_exports, {
108404
109438
  async function createCodexEngine(options = {}) {
108405
109439
  const { agent, systemPrompt, customPrompt, debug, sessionId, allowedTools, model } = options;
108406
109440
  const session = new Session(
108407
- sessionId || (0, import_crypto7.randomBytes)(8).toString("hex"),
109441
+ sessionId || (0, import_crypto8.randomBytes)(8).toString("hex"),
108408
109442
  debug
108409
109443
  );
108410
109444
  let mcpServer = null;
@@ -108446,12 +109480,12 @@ async function createCodexEngine(options = {}) {
108446
109480
  }
108447
109481
  }
108448
109482
  if (message.id !== void 0 && pendingRequests.has(message.id)) {
108449
- const { resolve: resolve7, reject: reject2 } = pendingRequests.get(message.id);
109483
+ const { resolve: resolve8, reject: reject2 } = pendingRequests.get(message.id);
108450
109484
  pendingRequests.delete(message.id);
108451
109485
  if (message.error) {
108452
109486
  reject2(new Error(message.error.message || JSON.stringify(message.error)));
108453
109487
  } else {
108454
- resolve7(message.result);
109488
+ resolve8(message.result);
108455
109489
  }
108456
109490
  }
108457
109491
  if (message.method === "codex/event" && message.params) {
@@ -108472,7 +109506,7 @@ async function createCodexEngine(options = {}) {
108472
109506
  });
108473
109507
  }
108474
109508
  function sendRequest(method, params = {}) {
108475
- return new Promise((resolve7, reject2) => {
109509
+ return new Promise((resolve8, reject2) => {
108476
109510
  const id = ++requestId;
108477
109511
  const request = {
108478
109512
  jsonrpc: "2.0",
@@ -108480,7 +109514,7 @@ async function createCodexEngine(options = {}) {
108480
109514
  method,
108481
109515
  params
108482
109516
  };
108483
- pendingRequests.set(id, { resolve: resolve7, reject: reject2 });
109517
+ pendingRequests.set(id, { resolve: resolve8, reject: reject2 });
108484
109518
  setTimeout(() => {
108485
109519
  if (pendingRequests.has(id)) {
108486
109520
  pendingRequests.delete(id);
@@ -108543,7 +109577,7 @@ ${prompt}`;
108543
109577
  const reqId = requestId + 1;
108544
109578
  let fullResponse = "";
108545
109579
  let gotSessionId = false;
108546
- const eventPromise = new Promise((resolve7) => {
109580
+ const eventPromise = new Promise((resolve8) => {
108547
109581
  eventHandlers.set(reqId, (eventParams) => {
108548
109582
  const msg = eventParams.msg;
108549
109583
  if (msg.type === "session_configured" && msg.session_id && !gotSessionId) {
@@ -108563,7 +109597,7 @@ ${prompt}`;
108563
109597
  });
108564
109598
  setTimeout(() => {
108565
109599
  eventHandlers.delete(reqId);
108566
- resolve7();
109600
+ resolve8();
108567
109601
  }, 6e5);
108568
109602
  });
108569
109603
  const resultPromise = sendRequest("tools/call", {
@@ -108659,12 +109693,12 @@ function combinePrompts2(systemPrompt, customPrompt, agent) {
108659
109693
  }
108660
109694
  return systemPrompt || "";
108661
109695
  }
108662
- var import_child_process9, import_crypto7, import_readline;
109696
+ var import_child_process9, import_crypto8, import_readline;
108663
109697
  var init_codex = __esm({
108664
109698
  "src/agent/engines/codex.js"() {
108665
109699
  "use strict";
108666
109700
  import_child_process9 = require("child_process");
108667
- import_crypto7 = require("crypto");
109701
+ import_crypto8 = require("crypto");
108668
109702
  import_readline = require("readline");
108669
109703
  init_built_in_server();
108670
109704
  init_Session();
@@ -108769,7 +109803,7 @@ Your content here
108769
109803
 
108770
109804
  Do NOT wrap in other tags like <api_call>, <tool_name>, <function>, etc.`;
108771
109805
  }
108772
- 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;
109806
+ 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;
108773
109807
  var init_ProbeAgent = __esm({
108774
109808
  "src/agent/ProbeAgent.js"() {
108775
109809
  "use strict";
@@ -108779,17 +109813,18 @@ var init_ProbeAgent = __esm({
108779
109813
  import_google2 = require("@ai-sdk/google");
108780
109814
  init_dist3();
108781
109815
  import_ai5 = require("ai");
108782
- import_crypto8 = require("crypto");
109816
+ import_crypto9 = require("crypto");
108783
109817
  import_events4 = require("events");
108784
109818
  import_fs12 = require("fs");
108785
109819
  import_promises6 = require("fs/promises");
108786
- import_path15 = require("path");
109820
+ import_path16 = require("path");
108787
109821
  init_tokenCounter();
108788
109822
  init_InMemoryStorageAdapter();
108789
109823
  init_HookManager();
108790
109824
  init_imageConfig();
108791
109825
  init_tools();
108792
109826
  init_common2();
109827
+ init_fileTracker();
108793
109828
  init_probeTool();
108794
109829
  init_mockProvider();
108795
109830
  init_index();
@@ -108831,7 +109866,7 @@ var init_ProbeAgent = __esm({
108831
109866
  * @param {string} [options.customPrompt] - Custom prompt to replace the default system message
108832
109867
  * @param {string} [options.systemPrompt] - Alias for customPrompt; takes precedence when both are provided
108833
109868
  * @param {string} [options.promptType] - Predefined prompt type (code-explorer, code-searcher, architect, code-review, support)
108834
- * @param {boolean} [options.allowEdit=false] - Allow the use of the 'implement' tool
109869
+ * @param {boolean} [options.allowEdit=false] - Allow the use of the 'edit' and 'create' tools
108835
109870
  * @param {boolean} [options.enableDelegate=false] - Enable the delegate tool for task distribution to subagents
108836
109871
  * @param {boolean} [options.enableExecutePlan=false] - Enable the execute_plan DSL orchestration tool
108837
109872
  * @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)
@@ -108876,10 +109911,11 @@ var init_ProbeAgent = __esm({
108876
109911
  * @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.
108877
109912
  */
108878
109913
  constructor(options = {}) {
108879
- this.sessionId = options.sessionId || (0, import_crypto8.randomUUID)();
109914
+ this.sessionId = options.sessionId || (0, import_crypto9.randomUUID)();
108880
109915
  this.customPrompt = options.systemPrompt || options.customPrompt || null;
108881
109916
  this.promptType = options.promptType || "code-explorer";
108882
109917
  this.allowEdit = !!options.allowEdit;
109918
+ this.hashLines = options.hashLines !== void 0 ? !!options.hashLines : this.allowEdit;
108883
109919
  this.enableDelegate = !!options.enableDelegate;
108884
109920
  this.enableExecutePlan = !!options.enableExecutePlan;
108885
109921
  this.debug = options.debug || process.env.DEBUG === "1";
@@ -108941,7 +109977,8 @@ var init_ProbeAgent = __esm({
108941
109977
  if (this.debug) {
108942
109978
  console.log(`[DEBUG] Generated session ID for agent: ${this.sessionId}`);
108943
109979
  console.log(`[DEBUG] Maximum tool iterations configured: ${MAX_TOOL_ITERATIONS}`);
108944
- console.log(`[DEBUG] Allow Edit (implement tool): ${this.allowEdit}`);
109980
+ console.log(`[DEBUG] Allow Edit: ${this.allowEdit}`);
109981
+ console.log(`[DEBUG] Hash Lines: ${this.hashLines}`);
108945
109982
  console.log(`[DEBUG] Search delegation enabled: ${this.searchDelegate}`);
108946
109983
  console.log(`[DEBUG] Workspace root: ${this.workspaceRoot}`);
108947
109984
  console.log(`[DEBUG] Working directory (cwd): ${this.cwd}`);
@@ -109326,9 +110363,12 @@ var init_ProbeAgent = __esm({
109326
110363
  cwd: this.cwd,
109327
110364
  workspaceRoot: this.workspaceRoot,
109328
110365
  allowedFolders: this.allowedFolders,
110366
+ // File state tracking for safe multi-edit workflows (only when editing is enabled)
110367
+ fileTracker: this.allowEdit ? new FileTracker({ debug: this.debug }) : null,
109329
110368
  outline: this.outline,
109330
110369
  searchDelegate: this.searchDelegate,
109331
110370
  allowEdit: this.allowEdit,
110371
+ hashLines: this.hashLines,
109332
110372
  enableDelegate: this.enableDelegate,
109333
110373
  enableExecutePlan: this.enableExecutePlan,
109334
110374
  enableBash: this.enableBash,
@@ -109399,7 +110439,7 @@ var init_ProbeAgent = __esm({
109399
110439
  if (!imagePath) {
109400
110440
  throw new Error("Image path is required");
109401
110441
  }
109402
- const filename = (0, import_path15.basename)(imagePath);
110442
+ const filename = (0, import_path16.basename)(imagePath);
109403
110443
  const extension = filename.toLowerCase().split(".").pop();
109404
110444
  if (!extension || !SUPPORTED_IMAGE_EXTENSIONS.includes(extension)) {
109405
110445
  throw new Error(`Invalid or unsupported image extension: ${extension}. Supported formats: ${SUPPORTED_IMAGE_EXTENSIONS.join(", ")}`);
@@ -110113,7 +111153,7 @@ var init_ProbeAgent = __esm({
110113
111153
  let resolvedPath2 = imagePath;
110114
111154
  if (!imagePath.includes("/") && !imagePath.includes("\\")) {
110115
111155
  for (const dir of listFilesDirectories) {
110116
- const potentialPath = (0, import_path15.resolve)(dir, imagePath);
111156
+ const potentialPath = (0, import_path16.resolve)(dir, imagePath);
110117
111157
  const loaded = await this.loadImageIfValid(potentialPath);
110118
111158
  if (loaded) {
110119
111159
  if (this.debug) {
@@ -110138,7 +111178,7 @@ var init_ProbeAgent = __esm({
110138
111178
  let match2;
110139
111179
  while ((match2 = fileHeaderPattern.exec(content)) !== null) {
110140
111180
  const filePath = match2[1].trim();
110141
- const dir = (0, import_path15.dirname)(filePath);
111181
+ const dir = (0, import_path16.dirname)(filePath);
110142
111182
  if (dir && dir !== ".") {
110143
111183
  directories.push(dir);
110144
111184
  if (this.debug) {
@@ -110183,17 +111223,17 @@ var init_ProbeAgent = __esm({
110183
111223
  const allowedDirs = this.allowedFolders && this.allowedFolders.length > 0 ? this.allowedFolders : [process.cwd()];
110184
111224
  let absolutePath;
110185
111225
  let isPathAllowed2 = false;
110186
- if ((0, import_path15.isAbsolute)(imagePath)) {
110187
- absolutePath = safeRealpath((0, import_path15.resolve)(imagePath));
111226
+ if ((0, import_path16.isAbsolute)(imagePath)) {
111227
+ absolutePath = safeRealpath((0, import_path16.resolve)(imagePath));
110188
111228
  isPathAllowed2 = allowedDirs.some((dir) => {
110189
111229
  const resolvedDir = safeRealpath(dir);
110190
- return absolutePath === resolvedDir || absolutePath.startsWith(resolvedDir + import_path15.sep);
111230
+ return absolutePath === resolvedDir || absolutePath.startsWith(resolvedDir + import_path16.sep);
110191
111231
  });
110192
111232
  } else {
110193
111233
  for (const dir of allowedDirs) {
110194
111234
  const resolvedDir = safeRealpath(dir);
110195
- const resolvedPath2 = safeRealpath((0, import_path15.resolve)(dir, imagePath));
110196
- if (resolvedPath2 === resolvedDir || resolvedPath2.startsWith(resolvedDir + import_path15.sep)) {
111235
+ const resolvedPath2 = safeRealpath((0, import_path16.resolve)(dir, imagePath));
111236
+ if (resolvedPath2 === resolvedDir || resolvedPath2.startsWith(resolvedDir + import_path16.sep)) {
110197
111237
  absolutePath = resolvedPath2;
110198
111238
  isPathAllowed2 = true;
110199
111239
  break;
@@ -110381,8 +111421,8 @@ var init_ProbeAgent = __esm({
110381
111421
  const hasConfiguredName = !!configuredName;
110382
111422
  let guidanceCandidates = [];
110383
111423
  if (hasConfiguredName) {
110384
- const targetName = (0, import_path15.basename)(configuredName);
110385
- if (configuredName !== targetName || configuredName.includes("/") || configuredName.includes("\\") || configuredName.includes("..") || (0, import_path15.isAbsolute)(configuredName)) {
111424
+ const targetName = (0, import_path16.basename)(configuredName);
111425
+ if (configuredName !== targetName || configuredName.includes("/") || configuredName.includes("\\") || configuredName.includes("..") || (0, import_path16.isAbsolute)(configuredName)) {
110386
111426
  console.warn(`[WARN] Invalid architectureFileName (must be a simple filename): ${configuredName}`);
110387
111427
  } else if (targetName) {
110388
111428
  const targetLower = targetName.toLowerCase();
@@ -110449,7 +111489,7 @@ var init_ProbeAgent = __esm({
110449
111489
  pushEntry(architectureMatch);
110450
111490
  const contexts = [];
110451
111491
  for (const entry of uniqueEntries) {
110452
- const filePath = (0, import_path15.resolve)(rootDirectory, entry.name);
111492
+ const filePath = (0, import_path16.resolve)(rootDirectory, entry.name);
110453
111493
  try {
110454
111494
  const content = await (0, import_promises6.readFile)(filePath, "utf8");
110455
111495
  let kind = "other";
@@ -110514,10 +111554,10 @@ ${this.architectureContext.content}
110514
111554
  }
110515
111555
  _getSkillsRepoRoot() {
110516
111556
  if (this.workspaceRoot) {
110517
- return (0, import_path15.resolve)(this.workspaceRoot);
111557
+ return (0, import_path16.resolve)(this.workspaceRoot);
110518
111558
  }
110519
111559
  if (this.allowedFolders && this.allowedFolders.length > 0) {
110520
- return (0, import_path15.resolve)(this.allowedFolders[0]);
111560
+ return (0, import_path16.resolve)(this.allowedFolders[0]);
110521
111561
  }
110522
111562
  return process.cwd();
110523
111563
  }
@@ -110706,10 +111746,6 @@ Workspace: ${this.allowedFolders.join(", ")}`;
110706
111746
  }
110707
111747
  if (isToolAllowed("readImage")) {
110708
111748
  toolDefinitions += `${readImageToolDefinition}
110709
- `;
110710
- }
110711
- if (this.allowEdit && isToolAllowed("implement")) {
110712
- toolDefinitions += `${implementToolDefinition}
110713
111749
  `;
110714
111750
  }
110715
111751
  if (this.allowEdit && isToolAllowed("edit")) {
@@ -110791,7 +111827,7 @@ The configuration is loaded from src/config.js lines 15-25 which contains the da
110791
111827
  availableToolsList += "- query: Search code using structural AST patterns.\n";
110792
111828
  }
110793
111829
  if (isToolAllowed("extract")) {
110794
- availableToolsList += "- extract: Extract specific code blocks or lines from files.\n";
111830
+ 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';
110795
111831
  }
110796
111832
  if (isToolAllowed("listFiles")) {
110797
111833
  availableToolsList += "- listFiles: List files and directories in a specified location.\n";
@@ -110808,11 +111844,8 @@ The configuration is loaded from src/config.js lines 15-25 which contains the da
110808
111844
  if (isToolAllowed("readImage")) {
110809
111845
  availableToolsList += "- readImage: Read and load an image file for AI analysis.\n";
110810
111846
  }
110811
- if (this.allowEdit && isToolAllowed("implement")) {
110812
- availableToolsList += "- implement: Implement a feature or fix a bug using aider.\n";
110813
- }
110814
111847
  if (this.allowEdit && isToolAllowed("edit")) {
110815
- availableToolsList += "- edit: Edit files using exact string replacement.\n";
111848
+ availableToolsList += "- edit: Edit files using text replacement, AST-aware symbol operations, or line-targeted editing.\n";
110816
111849
  }
110817
111850
  if (this.allowEdit && isToolAllowed("create")) {
110818
111851
  availableToolsList += "- create: Create new files with specified content.\n";
@@ -110900,8 +111933,14 @@ Follow these instructions carefully:
110900
111933
  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.
110901
111934
  9. Prefer concise and focused search queries. Use specific keywords and phrases to narrow down results.${this.allowEdit ? `
110902
111935
  10. When modifying files, choose the appropriate tool:
110903
- - Use 'edit' for precise changes to existing files (requires exact string match)
110904
- - Use 'create' for new files or complete file rewrites` : ""}
111936
+ - Use 'edit' for all code modifications:
111937
+ * For small changes (a line or a few lines), use old_string + new_string \u2014 copy old_string verbatim from the file.
111938
+ * For rewriting entire functions/classes/methods, use the symbol parameter instead (no exact text matching needed).
111939
+ * 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.' : ""}
111940
+ * 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.
111941
+ - Use 'create' for new files or complete file rewrites.
111942
+ - If an edit fails, read the error message \u2014 it tells you exactly how to fix the call and retry.
111943
+ - 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.` : ""}
110905
111944
  </instructions>
110906
111945
  `;
110907
111946
  let systemMessage = "";
@@ -111401,8 +112440,11 @@ You are working with a workspace. Available paths: ${workspaceDesc}
111401
112440
  if (this.enableSkills && this.allowedTools.isEnabled("useSkill")) validTools.push("useSkill");
111402
112441
  if (this.allowedTools.isEnabled("readImage")) validTools.push("readImage");
111403
112442
  validTools.push("attempt_completion");
111404
- if (this.allowEdit && this.allowedTools.isEnabled("implement")) {
111405
- validTools.push("implement", "edit", "create");
112443
+ if (this.allowEdit && this.allowedTools.isEnabled("edit")) {
112444
+ validTools.push("edit");
112445
+ }
112446
+ if (this.allowEdit && this.allowedTools.isEnabled("create")) {
112447
+ validTools.push("create");
111406
112448
  }
111407
112449
  if (this.enableBash && this.allowedTools.isEnabled("bash")) {
111408
112450
  validTools.push("bash");
@@ -111624,10 +112666,10 @@ ${errorXml}
111624
112666
  try {
111625
112667
  let resolvedWorkingDirectory = this.workspaceRoot || this.cwd || this.allowedFolders && this.allowedFolders[0] || process.cwd();
111626
112668
  if (params.workingDirectory) {
111627
- const requestedDir = safeRealpath((0, import_path15.isAbsolute)(params.workingDirectory) ? (0, import_path15.resolve)(params.workingDirectory) : (0, import_path15.resolve)(resolvedWorkingDirectory, params.workingDirectory));
112669
+ const requestedDir = safeRealpath((0, import_path16.isAbsolute)(params.workingDirectory) ? (0, import_path16.resolve)(params.workingDirectory) : (0, import_path16.resolve)(resolvedWorkingDirectory, params.workingDirectory));
111628
112670
  const isWithinAllowed = !this.allowedFolders || this.allowedFolders.length === 0 || this.allowedFolders.some((folder) => {
111629
112671
  const resolvedFolder = safeRealpath(folder);
111630
- return requestedDir === resolvedFolder || requestedDir.startsWith(resolvedFolder + import_path15.sep);
112672
+ return requestedDir === resolvedFolder || requestedDir.startsWith(resolvedFolder + import_path16.sep);
111631
112673
  });
111632
112674
  if (isWithinAllowed) {
111633
112675
  resolvedWorkingDirectory = requestedDir;
@@ -111695,6 +112737,8 @@ ${errorXml}
111695
112737
  // Inherit bash enablement
111696
112738
  bashConfig: this.bashConfig,
111697
112739
  // Inherit bash configuration
112740
+ allowEdit: this.allowEdit,
112741
+ // Inherit edit/create permission
111698
112742
  allowedTools: allowedToolsForDelegate,
111699
112743
  // Inherit allowed tools from parent
111700
112744
  debug: this.debug,
@@ -111767,7 +112811,7 @@ ${errorXml}
111767
112811
  currentMessages.push({ role: "assistant", content: assistantResponseContent });
111768
112812
  let toolResultContent = typeof toolResult === "string" ? toolResult : JSON.stringify(toolResult, null, 2);
111769
112813
  if (this.workspaceRoot && toolResultContent) {
111770
- const wsPrefix = this.workspaceRoot.endsWith(import_path15.sep) ? this.workspaceRoot : this.workspaceRoot + import_path15.sep;
112814
+ const wsPrefix = this.workspaceRoot.endsWith(import_path16.sep) ? this.workspaceRoot : this.workspaceRoot + import_path16.sep;
111771
112815
  toolResultContent = toolResultContent.split(wsPrefix).join("");
111772
112816
  }
111773
112817
  const { cleanedContent, extractedBlocks } = extractRawOutputBlocks(toolResultContent);
@@ -111855,6 +112899,25 @@ ${errorXml}
111855
112899
  }
111856
112900
  break;
111857
112901
  }
112902
+ if (options.schema) {
112903
+ let contentToCheck = assistantResponseContent;
112904
+ contentToCheck = contentToCheck.replace(/<thinking>[\s\S]*?<\/thinking>/gi, "").trim();
112905
+ contentToCheck = contentToCheck.replace(/<thinking>[\s\S]*$/gi, "").trim();
112906
+ const cleanedJson = cleanSchemaResponse(contentToCheck);
112907
+ try {
112908
+ JSON.parse(cleanedJson);
112909
+ const validation = validateJsonResponse(cleanedJson, { debug: this.debug, schema: options.schema });
112910
+ if (validation.isValid) {
112911
+ if (this.debug) {
112912
+ console.log(`[DEBUG] Issue #443: Accepting valid JSON response without attempt_completion (${cleanedJson.length} chars)`);
112913
+ }
112914
+ finalResult = cleanedJson;
112915
+ completionAttempted = true;
112916
+ break;
112917
+ }
112918
+ } catch {
112919
+ }
112920
+ }
111858
112921
  consecutiveNoToolCount++;
111859
112922
  const isIdentical = lastNoToolResponse !== null && assistantResponseContent === lastNoToolResponse;
111860
112923
  const isSemanticallyStuck = lastNoToolResponse !== null && areBothStuckResponses(lastNoToolResponse, assistantResponseContent);
@@ -112598,7 +113661,7 @@ Convert your previous response content into actual JSON data that follows this s
112598
113661
  */
112599
113662
  clone(options = {}) {
112600
113663
  const {
112601
- sessionId = (0, import_crypto8.randomUUID)(),
113664
+ sessionId = (0, import_crypto9.randomUUID)(),
112602
113665
  stripInternalMessages = true,
112603
113666
  keepSystemMessage = true,
112604
113667
  deepCopy = true,
@@ -112831,6 +113894,7 @@ async function delegate({
112831
113894
  model = null,
112832
113895
  enableBash = false,
112833
113896
  bashConfig = null,
113897
+ allowEdit = false,
112834
113898
  architectureFileName = null,
112835
113899
  promptType = "code-researcher",
112836
113900
  allowedTools = null,
@@ -112863,7 +113927,7 @@ async function delegate({
112863
113927
  }
112864
113928
  }
112865
113929
  const manager = delegationManager || defaultDelegationManager;
112866
- const sessionId = (0, import_crypto9.randomUUID)();
113930
+ const sessionId = (0, import_crypto10.randomUUID)();
112867
113931
  const startTime = Date.now();
112868
113932
  const remainingIterations = Math.max(1, maxIterations - currentIteration);
112869
113933
  const delegationSpan = typeof tracer?.createDelegationSpan === "function" ? tracer.createDelegationSpan(sessionId, task) : null;
@@ -112910,6 +113974,8 @@ async function delegate({
112910
113974
  // Inherit from parent
112911
113975
  bashConfig,
112912
113976
  // Inherit from parent
113977
+ allowEdit,
113978
+ // Inherit from parent
112913
113979
  architectureFileName,
112914
113980
  allowedTools,
112915
113981
  disableTools,
@@ -113014,11 +114080,11 @@ async function delegate({
113014
114080
  throw new Error(`Delegation failed: ${error2.message}`);
113015
114081
  }
113016
114082
  }
113017
- var import_crypto9, DelegationManager, defaultDelegationManager, DEFAULT_DELEGATE_TIMEOUT;
114083
+ var import_crypto10, DelegationManager, defaultDelegationManager, DEFAULT_DELEGATE_TIMEOUT;
113018
114084
  var init_delegate = __esm({
113019
114085
  "src/delegate.js"() {
113020
114086
  "use strict";
113021
- import_crypto9 = require("crypto");
114087
+ import_crypto10 = require("crypto");
113022
114088
  init_ProbeAgent();
113023
114089
  DelegationManager = class {
113024
114090
  constructor(options = {}) {
@@ -113095,7 +114161,7 @@ var init_delegate = __esm({
113095
114161
  if (debug) {
113096
114162
  console.error(`[DelegationManager] Slot unavailable (${this.globalActive}/${this.maxConcurrent}), queuing... (queue size: ${this.waitQueue.length}, timeout: ${effectiveTimeout}ms)`);
113097
114163
  }
113098
- return new Promise((resolve7, reject2) => {
114164
+ return new Promise((resolve8, reject2) => {
113099
114165
  const entry = {
113100
114166
  resolve: null,
113101
114167
  // Will be wrapped below
@@ -113111,7 +114177,7 @@ var init_delegate = __esm({
113111
114177
  if (settled) return;
113112
114178
  settled = true;
113113
114179
  if (entry.timeoutId) clearTimeout(entry.timeoutId);
113114
- resolve7(value);
114180
+ resolve8(value);
113115
114181
  };
113116
114182
  entry.reject = (error2) => {
113117
114183
  if (settled) return;
@@ -113161,7 +114227,7 @@ var init_delegate = __esm({
113161
114227
  while (this.waitQueue.length > 0 && this.globalActive < this.maxConcurrent) {
113162
114228
  const next = this.waitQueue.shift();
113163
114229
  if (!next) break;
113164
- const { resolve: resolve7, reject: reject2, parentSessionId, queuedAt } = next;
114230
+ const { resolve: resolve8, reject: reject2, parentSessionId, queuedAt } = next;
113165
114231
  if (parentSessionId) {
113166
114232
  const sessionData = this.sessionDelegations.get(parentSessionId);
113167
114233
  const sessionCount = sessionData?.count || 0;
@@ -113178,12 +114244,12 @@ var init_delegate = __esm({
113178
114244
  const waitTime = Date.now() - queuedAt;
113179
114245
  console.error(`[DelegationManager] Granted slot from queue (waited ${waitTime}ms). Active: ${this.globalActive}/${this.maxConcurrent}`);
113180
114246
  }
113181
- toResolve.push(resolve7);
114247
+ toResolve.push(resolve8);
113182
114248
  }
113183
114249
  if (toResolve.length > 0 || toReject.length > 0) {
113184
114250
  setImmediate(() => {
113185
- for (const resolve7 of toResolve) {
113186
- resolve7(true);
114251
+ for (const resolve8 of toResolve) {
114252
+ resolve8(true);
113187
114253
  }
113188
114254
  for (const { reject: reject2, error: error2 } of toReject) {
113189
114255
  reject2(error2);
@@ -113829,6 +114895,7 @@ var init_vercel = __esm({
113829
114895
  init_analyzeAll();
113830
114896
  init_common2();
113831
114897
  init_error_types();
114898
+ init_hashline();
113832
114899
  CODE_SEARCH_SCHEMA = {
113833
114900
  type: "object",
113834
114901
  properties: {
@@ -113847,8 +114914,15 @@ var init_vercel = __esm({
113847
114914
  maxTokens = 2e4,
113848
114915
  debug = false,
113849
114916
  outline = false,
113850
- searchDelegate = false
114917
+ searchDelegate = false,
114918
+ hashLines = false
113851
114919
  } = options;
114920
+ const maybeAnnotate = (result) => {
114921
+ if (hashLines && typeof result === "string") {
114922
+ return annotateOutputWithHashes(result);
114923
+ }
114924
+ return result;
114925
+ };
113852
114926
  return (0, import_ai6.tool)({
113853
114927
  name: "search",
113854
114928
  description: searchDelegate ? `${searchDescription} (delegates code search to a subagent and returns extracted code blocks)` : searchDescription,
@@ -113890,7 +114964,12 @@ var init_vercel = __esm({
113890
114964
  };
113891
114965
  if (!searchDelegate) {
113892
114966
  try {
113893
- return await runRawSearch();
114967
+ const result = maybeAnnotate(await runRawSearch());
114968
+ if (options.fileTracker && typeof result === "string") {
114969
+ options.fileTracker.trackFilesFromOutput(result, options.cwd || ".").catch(() => {
114970
+ });
114971
+ }
114972
+ return result;
113894
114973
  } catch (error2) {
113895
114974
  console.error("Error executing search command:", error2);
113896
114975
  return formatErrorForAI(error2);
@@ -113933,7 +115012,12 @@ var init_vercel = __esm({
113933
115012
  if (debug) {
113934
115013
  console.error("Delegated search returned no targets; falling back to raw search");
113935
115014
  }
113936
- return await runRawSearch();
115015
+ const fallbackResult = maybeAnnotate(await runRawSearch());
115016
+ if (options.fileTracker && typeof fallbackResult === "string") {
115017
+ options.fileTracker.trackFilesFromOutput(fallbackResult, options.cwd || ".").catch(() => {
115018
+ });
115019
+ }
115020
+ return fallbackResult;
113937
115021
  }
113938
115022
  const resolutionBase = searchPaths[0] || options.cwd || ".";
113939
115023
  const resolvedTargets = targets.map((target) => resolveTargetPath(target, resolutionBase));
@@ -113948,13 +115032,18 @@ var init_vercel = __esm({
113948
115032
  const extractResult = await extract(extractOptions);
113949
115033
  if (resolutionBase && typeof extractResult === "string") {
113950
115034
  const wsPrefix = resolutionBase.endsWith("/") ? resolutionBase : resolutionBase + "/";
113951
- return extractResult.split(wsPrefix).join("");
115035
+ return maybeAnnotate(extractResult.split(wsPrefix).join(""));
113952
115036
  }
113953
- return extractResult;
115037
+ return maybeAnnotate(extractResult);
113954
115038
  } catch (error2) {
113955
115039
  console.error("Delegated search failed, falling back to raw search:", error2);
113956
115040
  try {
113957
- return await runRawSearch();
115041
+ const fallbackResult2 = maybeAnnotate(await runRawSearch());
115042
+ if (options.fileTracker && typeof fallbackResult2 === "string") {
115043
+ options.fileTracker.trackFilesFromOutput(fallbackResult2, options.cwd || ".").catch(() => {
115044
+ });
115045
+ }
115046
+ return fallbackResult2;
113958
115047
  } catch (fallbackError) {
113959
115048
  console.error("Error executing search command:", fallbackError);
113960
115049
  return formatErrorForAI(fallbackError);
@@ -114000,7 +115089,7 @@ var init_vercel = __esm({
114000
115089
  });
114001
115090
  };
114002
115091
  extractTool = (options = {}) => {
114003
- const { debug = false, outline = false } = options;
115092
+ const { debug = false, outline = false, hashLines = false } = options;
114004
115093
  return (0, import_ai6.tool)({
114005
115094
  name: "extract",
114006
115095
  description: extractDescription,
@@ -114017,6 +115106,7 @@ var init_vercel = __esm({
114017
115106
  }
114018
115107
  let tempFilePath = null;
114019
115108
  let extractOptions = { cwd: effectiveCwd };
115109
+ let extractFiles = null;
114020
115110
  if (input_content) {
114021
115111
  const { writeFileSync: writeFileSync2, unlinkSync } = await import("fs");
114022
115112
  const { join: join5 } = await import("path");
@@ -114040,13 +115130,13 @@ var init_vercel = __esm({
114040
115130
  };
114041
115131
  } else if (targets) {
114042
115132
  const parsedTargets = parseTargets(targets);
114043
- const files = parsedTargets.map((target) => resolveTargetPath(target, effectiveCwd));
115133
+ extractFiles = parsedTargets.map((target) => resolveTargetPath(target, effectiveCwd));
114044
115134
  let effectiveFormat = format2;
114045
115135
  if (outline && format2 === "outline-xml") {
114046
115136
  effectiveFormat = "xml";
114047
115137
  }
114048
115138
  extractOptions = {
114049
- files,
115139
+ files: extractFiles,
114050
115140
  cwd: effectiveCwd,
114051
115141
  allowTests: allow_tests ?? true,
114052
115142
  contextLines: context_lines,
@@ -114056,6 +115146,10 @@ var init_vercel = __esm({
114056
115146
  throw new Error("Either targets or input_content must be provided");
114057
115147
  }
114058
115148
  const results = await extract(extractOptions);
115149
+ if (options.fileTracker && extractFiles && extractFiles.length > 0) {
115150
+ options.fileTracker.trackFilesFromExtract(extractFiles, effectiveCwd).catch(() => {
115151
+ });
115152
+ }
114059
115153
  if (tempFilePath) {
114060
115154
  const { unlinkSync } = await import("fs");
114061
115155
  try {
@@ -114067,6 +115161,9 @@ var init_vercel = __esm({
114067
115161
  console.error(`Warning: Failed to remove temporary file: ${cleanupError.message}`);
114068
115162
  }
114069
115163
  }
115164
+ if (hashLines && typeof results === "string") {
115165
+ return annotateOutputWithHashes(results);
115166
+ }
114070
115167
  return results;
114071
115168
  } catch (error2) {
114072
115169
  console.error("Error executing extract command:", error2);
@@ -114493,7 +115590,7 @@ async function listFilesByLevel(options) {
114493
115590
  if (!import_fs13.default.existsSync(directory)) {
114494
115591
  throw new Error(`Directory does not exist: ${directory}`);
114495
115592
  }
114496
- const gitDirExists = import_fs13.default.existsSync(import_path16.default.join(directory, ".git"));
115593
+ const gitDirExists = import_fs13.default.existsSync(import_path17.default.join(directory, ".git"));
114497
115594
  if (gitDirExists && respectGitignore) {
114498
115595
  try {
114499
115596
  return await listFilesUsingGit(directory, maxFiles);
@@ -114508,8 +115605,8 @@ async function listFilesUsingGit(directory, maxFiles) {
114508
115605
  const { stdout } = await execAsync3("git ls-files", { cwd: directory });
114509
115606
  const files = stdout.split("\n").filter(Boolean);
114510
115607
  const sortedFiles = files.sort((a5, b5) => {
114511
- const depthA = a5.split(import_path16.default.sep).length;
114512
- const depthB = b5.split(import_path16.default.sep).length;
115608
+ const depthA = a5.split(import_path17.default.sep).length;
115609
+ const depthB = b5.split(import_path17.default.sep).length;
114513
115610
  return depthA - depthB;
114514
115611
  });
114515
115612
  return sortedFiles.slice(0, maxFiles);
@@ -114526,23 +115623,23 @@ async function listFilesByLevelManually(directory, maxFiles, respectGitignore) {
114526
115623
  try {
114527
115624
  const entries = import_fs13.default.readdirSync(dir, { withFileTypes: true });
114528
115625
  const files = entries.filter((entry) => {
114529
- const fullPath = import_path16.default.join(dir, entry.name);
115626
+ const fullPath = import_path17.default.join(dir, entry.name);
114530
115627
  return getEntryTypeSync(entry, fullPath).isFile;
114531
115628
  });
114532
115629
  for (const file of files) {
114533
115630
  if (result.length >= maxFiles) break;
114534
- const filePath = import_path16.default.join(dir, file.name);
114535
- const relativePath = import_path16.default.relative(directory, filePath);
115631
+ const filePath = import_path17.default.join(dir, file.name);
115632
+ const relativePath = import_path17.default.relative(directory, filePath);
114536
115633
  if (shouldIgnore(relativePath, ignorePatterns)) continue;
114537
115634
  result.push(relativePath);
114538
115635
  }
114539
115636
  const dirs = entries.filter((entry) => {
114540
- const fullPath = import_path16.default.join(dir, entry.name);
115637
+ const fullPath = import_path17.default.join(dir, entry.name);
114541
115638
  return getEntryTypeSync(entry, fullPath).isDirectory;
114542
115639
  });
114543
115640
  for (const subdir of dirs) {
114544
- const subdirPath = import_path16.default.join(dir, subdir.name);
114545
- const relativeSubdirPath = import_path16.default.relative(directory, subdirPath);
115641
+ const subdirPath = import_path17.default.join(dir, subdir.name);
115642
+ const relativeSubdirPath = import_path17.default.relative(directory, subdirPath);
114546
115643
  if (shouldIgnore(relativeSubdirPath, ignorePatterns)) continue;
114547
115644
  if (subdir.name === "node_modules" || subdir.name === ".git") continue;
114548
115645
  queue.push({ dir: subdirPath, level: level + 1 });
@@ -114554,7 +115651,7 @@ async function listFilesByLevelManually(directory, maxFiles, respectGitignore) {
114554
115651
  return result;
114555
115652
  }
114556
115653
  function loadGitignorePatterns(directory) {
114557
- const gitignorePath = import_path16.default.join(directory, ".gitignore");
115654
+ const gitignorePath = import_path17.default.join(directory, ".gitignore");
114558
115655
  if (!import_fs13.default.existsSync(gitignorePath)) {
114559
115656
  return [];
114560
115657
  }
@@ -114577,12 +115674,12 @@ function shouldIgnore(filePath, ignorePatterns) {
114577
115674
  }
114578
115675
  return false;
114579
115676
  }
114580
- var import_fs13, import_path16, import_util12, import_child_process10, execAsync3;
115677
+ var import_fs13, import_path17, import_util12, import_child_process10, execAsync3;
114581
115678
  var init_file_lister = __esm({
114582
115679
  "src/utils/file-lister.js"() {
114583
115680
  "use strict";
114584
115681
  import_fs13 = __toESM(require("fs"), 1);
114585
- import_path16 = __toESM(require("path"), 1);
115682
+ import_path17 = __toESM(require("path"), 1);
114586
115683
  import_util12 = require("util");
114587
115684
  import_child_process10 = require("child_process");
114588
115685
  init_symlink_utils();
@@ -114600,12 +115697,12 @@ function initializeSimpleTelemetryFromOptions(options) {
114600
115697
  });
114601
115698
  return telemetry;
114602
115699
  }
114603
- var import_fs14, import_path17, SimpleTelemetry, SimpleAppTracer;
115700
+ var import_fs14, import_path18, SimpleTelemetry, SimpleAppTracer;
114604
115701
  var init_simpleTelemetry = __esm({
114605
115702
  "src/agent/simpleTelemetry.js"() {
114606
115703
  "use strict";
114607
115704
  import_fs14 = require("fs");
114608
- import_path17 = require("path");
115705
+ import_path18 = require("path");
114609
115706
  SimpleTelemetry = class {
114610
115707
  constructor(options = {}) {
114611
115708
  this.serviceName = options.serviceName || "probe-agent";
@@ -114619,7 +115716,7 @@ var init_simpleTelemetry = __esm({
114619
115716
  }
114620
115717
  initializeFileExporter() {
114621
115718
  try {
114622
- const dir = (0, import_path17.dirname)(this.filePath);
115719
+ const dir = (0, import_path18.dirname)(this.filePath);
114623
115720
  if (!(0, import_fs14.existsSync)(dir)) {
114624
115721
  (0, import_fs14.mkdirSync)(dir, { recursive: true });
114625
115722
  }
@@ -114684,20 +115781,20 @@ var init_simpleTelemetry = __esm({
114684
115781
  }
114685
115782
  async flush() {
114686
115783
  if (this.stream) {
114687
- return new Promise((resolve7) => {
114688
- this.stream.once("drain", resolve7);
115784
+ return new Promise((resolve8) => {
115785
+ this.stream.once("drain", resolve8);
114689
115786
  if (!this.stream.writableNeedDrain) {
114690
- resolve7();
115787
+ resolve8();
114691
115788
  }
114692
115789
  });
114693
115790
  }
114694
115791
  }
114695
115792
  async shutdown() {
114696
115793
  if (this.stream) {
114697
- return new Promise((resolve7) => {
115794
+ return new Promise((resolve8) => {
114698
115795
  this.stream.end(() => {
114699
115796
  console.log(`[SimpleTelemetry] File stream closed: ${this.filePath}`);
114700
- resolve7();
115797
+ resolve8();
114701
115798
  });
114702
115799
  });
114703
115800
  }
@@ -115056,6 +116153,7 @@ var init_hooks = __esm({
115056
116153
  var index_exports = {};
115057
116154
  __export(index_exports, {
115058
116155
  DEFAULT_SYSTEM_MESSAGE: () => DEFAULT_SYSTEM_MESSAGE,
116156
+ FileTracker: () => FileTracker,
115059
116157
  HOOK_TYPES: () => HOOK_TYPES,
115060
116158
  HookManager: () => HookManager,
115061
116159
  InMemoryStorageAdapter: () => InMemoryStorageAdapter,
@@ -115136,6 +116234,7 @@ var init_index = __esm({
115136
116234
  init_executePlan();
115137
116235
  init_bash();
115138
116236
  init_edit();
116237
+ init_fileTracker();
115139
116238
  init_ProbeAgent();
115140
116239
  init_simpleTelemetry();
115141
116240
  init_probeTool();
@@ -115149,6 +116248,7 @@ init_index();
115149
116248
  // Annotate the CommonJS export names for ESM import in node:
115150
116249
  0 && (module.exports = {
115151
116250
  DEFAULT_SYSTEM_MESSAGE,
116251
+ FileTracker,
115152
116252
  HOOK_TYPES,
115153
116253
  HookManager,
115154
116254
  InMemoryStorageAdapter,