@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
@@ -2329,7 +2329,7 @@ var require_headStream = __commonJS({
2329
2329
  if ((0, stream_type_check_1.isReadableStream)(stream2)) {
2330
2330
  return (0, headStream_browser_1.headStream)(stream2, bytes);
2331
2331
  }
2332
- return new Promise((resolve7, reject2) => {
2332
+ return new Promise((resolve8, reject2) => {
2333
2333
  const collector = new Collector();
2334
2334
  collector.limit = bytes;
2335
2335
  stream2.pipe(collector);
@@ -2340,7 +2340,7 @@ var require_headStream = __commonJS({
2340
2340
  collector.on("error", reject2);
2341
2341
  collector.on("finish", function() {
2342
2342
  const bytes2 = new Uint8Array(Buffer.concat(this.buffers));
2343
- resolve7(bytes2);
2343
+ resolve8(bytes2);
2344
2344
  });
2345
2345
  });
2346
2346
  };
@@ -2528,21 +2528,21 @@ var require_dist_cjs15 = __commonJS({
2528
2528
  let sendBody = true;
2529
2529
  if (!externalAgent && expect === "100-continue") {
2530
2530
  sendBody = await Promise.race([
2531
- new Promise((resolve7) => {
2532
- timeoutId = Number(timing.setTimeout(() => resolve7(true), Math.max(MIN_WAIT_TIME, maxContinueTimeoutMs)));
2531
+ new Promise((resolve8) => {
2532
+ timeoutId = Number(timing.setTimeout(() => resolve8(true), Math.max(MIN_WAIT_TIME, maxContinueTimeoutMs)));
2533
2533
  }),
2534
- new Promise((resolve7) => {
2534
+ new Promise((resolve8) => {
2535
2535
  httpRequest.on("continue", () => {
2536
2536
  timing.clearTimeout(timeoutId);
2537
- resolve7(true);
2537
+ resolve8(true);
2538
2538
  });
2539
2539
  httpRequest.on("response", () => {
2540
2540
  timing.clearTimeout(timeoutId);
2541
- resolve7(false);
2541
+ resolve8(false);
2542
2542
  });
2543
2543
  httpRequest.on("error", () => {
2544
2544
  timing.clearTimeout(timeoutId);
2545
- resolve7(false);
2545
+ resolve8(false);
2546
2546
  });
2547
2547
  })
2548
2548
  ]);
@@ -2614,13 +2614,13 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
2614
2614
  return socketWarningTimestamp;
2615
2615
  }
2616
2616
  constructor(options) {
2617
- this.configProvider = new Promise((resolve7, reject2) => {
2617
+ this.configProvider = new Promise((resolve8, reject2) => {
2618
2618
  if (typeof options === "function") {
2619
2619
  options().then((_options) => {
2620
- resolve7(this.resolveDefaultConfig(_options));
2620
+ resolve8(this.resolveDefaultConfig(_options));
2621
2621
  }).catch(reject2);
2622
2622
  } else {
2623
- resolve7(this.resolveDefaultConfig(options));
2623
+ resolve8(this.resolveDefaultConfig(options));
2624
2624
  }
2625
2625
  });
2626
2626
  }
@@ -2663,7 +2663,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
2663
2663
  const config = this.config;
2664
2664
  let writeRequestBodyPromise = void 0;
2665
2665
  const timeouts = [];
2666
- const resolve7 = async (arg) => {
2666
+ const resolve8 = async (arg) => {
2667
2667
  await writeRequestBodyPromise;
2668
2668
  timeouts.forEach(timing.clearTimeout);
2669
2669
  _resolve(arg);
@@ -2729,7 +2729,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
2729
2729
  headers: getTransformedHeaders(res.headers),
2730
2730
  body: res
2731
2731
  });
2732
- resolve7({ response: httpResponse });
2732
+ resolve8({ response: httpResponse });
2733
2733
  });
2734
2734
  req.on("error", (err) => {
2735
2735
  if (NODEJS_TIMEOUT_ERROR_CODES.includes(err.code)) {
@@ -2909,13 +2909,13 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
2909
2909
  return new _NodeHttp2Handler(instanceOrOptions);
2910
2910
  }
2911
2911
  constructor(options) {
2912
- this.configProvider = new Promise((resolve7, reject2) => {
2912
+ this.configProvider = new Promise((resolve8, reject2) => {
2913
2913
  if (typeof options === "function") {
2914
2914
  options().then((opts) => {
2915
- resolve7(opts || {});
2915
+ resolve8(opts || {});
2916
2916
  }).catch(reject2);
2917
2917
  } else {
2918
- resolve7(options || {});
2918
+ resolve8(options || {});
2919
2919
  }
2920
2920
  });
2921
2921
  }
@@ -2935,7 +2935,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
2935
2935
  return new Promise((_resolve, _reject) => {
2936
2936
  let fulfilled = false;
2937
2937
  let writeRequestBodyPromise = void 0;
2938
- const resolve7 = async (arg) => {
2938
+ const resolve8 = async (arg) => {
2939
2939
  await writeRequestBodyPromise;
2940
2940
  _resolve(arg);
2941
2941
  };
@@ -2991,7 +2991,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
2991
2991
  body: req
2992
2992
  });
2993
2993
  fulfilled = true;
2994
- resolve7({ response: httpResponse });
2994
+ resolve8({ response: httpResponse });
2995
2995
  if (disableConcurrentStreams) {
2996
2996
  session.close();
2997
2997
  this.connectionManager.deleteSession(authority, session);
@@ -3068,7 +3068,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
3068
3068
  if (isReadableStreamInstance(stream3)) {
3069
3069
  return collectReadableStream(stream3);
3070
3070
  }
3071
- return new Promise((resolve7, reject2) => {
3071
+ return new Promise((resolve8, reject2) => {
3072
3072
  const collector = new Collector();
3073
3073
  stream3.pipe(collector);
3074
3074
  stream3.on("error", (err) => {
@@ -3078,7 +3078,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
3078
3078
  collector.on("error", reject2);
3079
3079
  collector.on("finish", function() {
3080
3080
  const bytes = new Uint8Array(Buffer.concat(this.bufferedBytes));
3081
- resolve7(bytes);
3081
+ resolve8(bytes);
3082
3082
  });
3083
3083
  });
3084
3084
  };
@@ -3122,7 +3122,7 @@ var require_dist_cjs16 = __commonJS({
3122
3122
  return new Request(url, requestOptions);
3123
3123
  }
3124
3124
  function requestTimeout(timeoutInMs = 0) {
3125
- return new Promise((resolve7, reject2) => {
3125
+ return new Promise((resolve8, reject2) => {
3126
3126
  if (timeoutInMs) {
3127
3127
  setTimeout(() => {
3128
3128
  const timeoutError = new Error(`Request did not complete within ${timeoutInMs} ms`);
@@ -3240,7 +3240,7 @@ var require_dist_cjs16 = __commonJS({
3240
3240
  requestTimeout(requestTimeoutInMs)
3241
3241
  ];
3242
3242
  if (abortSignal) {
3243
- raceOfPromises.push(new Promise((resolve7, reject2) => {
3243
+ raceOfPromises.push(new Promise((resolve8, reject2) => {
3244
3244
  const onAbort = () => {
3245
3245
  const abortError = new Error("Request aborted");
3246
3246
  abortError.name = "AbortError";
@@ -3304,7 +3304,7 @@ var require_dist_cjs16 = __commonJS({
3304
3304
  return collected;
3305
3305
  }
3306
3306
  function readToBase64(blob) {
3307
- return new Promise((resolve7, reject2) => {
3307
+ return new Promise((resolve8, reject2) => {
3308
3308
  const reader = new FileReader();
3309
3309
  reader.onloadend = () => {
3310
3310
  if (reader.readyState !== 2) {
@@ -3313,7 +3313,7 @@ var require_dist_cjs16 = __commonJS({
3313
3313
  const result = reader.result ?? "";
3314
3314
  const commaIndex = result.indexOf(",");
3315
3315
  const dataOffset = commaIndex > -1 ? commaIndex + 1 : result.length;
3316
- resolve7(result.substring(dataOffset));
3316
+ resolve8(result.substring(dataOffset));
3317
3317
  };
3318
3318
  reader.onabort = () => reject2(new Error("Read aborted"));
3319
3319
  reader.onerror = () => reject2(reader.error);
@@ -4981,11 +4981,11 @@ function __metadata(metadataKey, metadataValue) {
4981
4981
  }
4982
4982
  function __awaiter(thisArg, _arguments, P, generator) {
4983
4983
  function adopt(value) {
4984
- return value instanceof P ? value : new P(function(resolve7) {
4985
- resolve7(value);
4984
+ return value instanceof P ? value : new P(function(resolve8) {
4985
+ resolve8(value);
4986
4986
  });
4987
4987
  }
4988
- return new (P || (P = Promise))(function(resolve7, reject2) {
4988
+ return new (P || (P = Promise))(function(resolve8, reject2) {
4989
4989
  function fulfilled(value) {
4990
4990
  try {
4991
4991
  step(generator.next(value));
@@ -5001,7 +5001,7 @@ function __awaiter(thisArg, _arguments, P, generator) {
5001
5001
  }
5002
5002
  }
5003
5003
  function step(result) {
5004
- result.done ? resolve7(result.value) : adopt(result.value).then(fulfilled, rejected);
5004
+ result.done ? resolve8(result.value) : adopt(result.value).then(fulfilled, rejected);
5005
5005
  }
5006
5006
  step((generator = generator.apply(thisArg, _arguments || [])).next());
5007
5007
  });
@@ -5192,14 +5192,14 @@ function __asyncValues(o5) {
5192
5192
  }, i5);
5193
5193
  function verb(n5) {
5194
5194
  i5[n5] = o5[n5] && function(v5) {
5195
- return new Promise(function(resolve7, reject2) {
5196
- v5 = o5[n5](v5), settle(resolve7, reject2, v5.done, v5.value);
5195
+ return new Promise(function(resolve8, reject2) {
5196
+ v5 = o5[n5](v5), settle(resolve8, reject2, v5.done, v5.value);
5197
5197
  });
5198
5198
  };
5199
5199
  }
5200
- function settle(resolve7, reject2, d5, v5) {
5200
+ function settle(resolve8, reject2, d5, v5) {
5201
5201
  Promise.resolve(v5).then(function(v6) {
5202
- resolve7({ value: v6, done: d5 });
5202
+ resolve8({ value: v6, done: d5 });
5203
5203
  }, reject2);
5204
5204
  }
5205
5205
  }
@@ -15600,7 +15600,7 @@ var require_dist_cjs37 = __commonJS({
15600
15600
  this.sockets[url] = (this.sockets[url] ?? []).filter((socket) => ![WebSocket.CLOSING, WebSocket.CLOSED].includes(socket.readyState));
15601
15601
  }
15602
15602
  waitForReady(socket, connectionTimeout) {
15603
- return new Promise((resolve7, reject2) => {
15603
+ return new Promise((resolve8, reject2) => {
15604
15604
  const timeout = setTimeout(() => {
15605
15605
  this.removeNotUsableSockets(socket.url);
15606
15606
  reject2({
@@ -15612,7 +15612,7 @@ var require_dist_cjs37 = __commonJS({
15612
15612
  }, connectionTimeout);
15613
15613
  socket.onopen = () => {
15614
15614
  clearTimeout(timeout);
15615
- resolve7();
15615
+ resolve8();
15616
15616
  };
15617
15617
  });
15618
15618
  }
@@ -15665,8 +15665,8 @@ var require_dist_cjs37 = __commonJS({
15665
15665
  }
15666
15666
  return { done: item.done, value: item.value };
15667
15667
  }
15668
- return new Promise((resolve7, reject2) => {
15669
- pendingResolve = resolve7;
15668
+ return new Promise((resolve8, reject2) => {
15669
+ pendingResolve = resolve8;
15670
15670
  pendingReject = reject2;
15671
15671
  });
15672
15672
  }
@@ -16879,7 +16879,7 @@ var require_dist_cjs46 = __commonJS({
16879
16879
  this.refillTokenBucket();
16880
16880
  if (amount > this.currentCapacity) {
16881
16881
  const delay = (amount - this.currentCapacity) / this.fillRate * 1e3;
16882
- await new Promise((resolve7) => _DefaultRateLimiter.setTimeoutFn(resolve7, delay));
16882
+ await new Promise((resolve8) => _DefaultRateLimiter.setTimeoutFn(resolve8, delay));
16883
16883
  }
16884
16884
  this.currentCapacity = this.currentCapacity - amount;
16885
16885
  }
@@ -17214,7 +17214,7 @@ var require_dist_cjs47 = __commonJS({
17214
17214
  const delayFromResponse = getDelayFromRetryAfterHeader(err.$response);
17215
17215
  const delay = Math.max(delayFromResponse || 0, delayFromDecider);
17216
17216
  totalDelay += delay;
17217
- await new Promise((resolve7) => setTimeout(resolve7, delay));
17217
+ await new Promise((resolve8) => setTimeout(resolve8, delay));
17218
17218
  continue;
17219
17219
  }
17220
17220
  if (!err.$metadata) {
@@ -17372,7 +17372,7 @@ var require_dist_cjs47 = __commonJS({
17372
17372
  attempts = retryToken.getRetryCount();
17373
17373
  const delay = retryToken.getRetryDelay();
17374
17374
  totalRetryDelay += delay;
17375
- await new Promise((resolve7) => setTimeout(resolve7, delay));
17375
+ await new Promise((resolve8) => setTimeout(resolve8, delay));
17376
17376
  }
17377
17377
  }
17378
17378
  } else {
@@ -17524,7 +17524,7 @@ var require_package2 = __commonJS({
17524
17524
  module2.exports = {
17525
17525
  name: "@aws-sdk/client-bedrock-runtime",
17526
17526
  description: "AWS SDK for JavaScript Bedrock Runtime Client for Node.js, Browser and React Native",
17527
- version: "3.994.0",
17527
+ version: "3.995.0",
17528
17528
  scripts: {
17529
17529
  build: "concurrently 'yarn:build:types' 'yarn:build:es' && yarn build:cjs",
17530
17530
  "build:cjs": "node ../../scripts/compilation/inline client-bedrock-runtime",
@@ -17554,11 +17554,11 @@ var require_package2 = __commonJS({
17554
17554
  "@aws-sdk/middleware-user-agent": "^3.972.11",
17555
17555
  "@aws-sdk/middleware-websocket": "^3.972.6",
17556
17556
  "@aws-sdk/region-config-resolver": "^3.972.3",
17557
- "@aws-sdk/token-providers": "3.994.0",
17557
+ "@aws-sdk/token-providers": "3.995.0",
17558
17558
  "@aws-sdk/types": "^3.973.1",
17559
- "@aws-sdk/util-endpoints": "3.994.0",
17559
+ "@aws-sdk/util-endpoints": "3.995.0",
17560
17560
  "@aws-sdk/util-user-agent-browser": "^3.972.3",
17561
- "@aws-sdk/util-user-agent-node": "^3.972.9",
17561
+ "@aws-sdk/util-user-agent-node": "^3.972.10",
17562
17562
  "@smithy/config-resolver": "^4.4.6",
17563
17563
  "@smithy/core": "^3.23.2",
17564
17564
  "@smithy/eventstream-serde-browser": "^4.2.8",
@@ -17687,7 +17687,7 @@ var require_dist_cjs49 = __commonJS({
17687
17687
  var nodeConfigProvider = require_dist_cjs43();
17688
17688
  var urlParser = require_dist_cjs22();
17689
17689
  function httpRequest(options) {
17690
- return new Promise((resolve7, reject2) => {
17690
+ return new Promise((resolve8, reject2) => {
17691
17691
  const req = http.request({
17692
17692
  method: "GET",
17693
17693
  ...options,
@@ -17712,7 +17712,7 @@ var require_dist_cjs49 = __commonJS({
17712
17712
  chunks.push(chunk);
17713
17713
  });
17714
17714
  res.on("end", () => {
17715
- resolve7(buffer.Buffer.concat(chunks));
17715
+ resolve8(buffer.Buffer.concat(chunks));
17716
17716
  req.destroy();
17717
17717
  });
17718
17718
  });
@@ -18132,7 +18132,7 @@ var require_retry_wrapper = __commonJS({
18132
18132
  try {
18133
18133
  return await toRetry();
18134
18134
  } catch (e5) {
18135
- await new Promise((resolve7) => setTimeout(resolve7, delayMs));
18135
+ await new Promise((resolve8) => setTimeout(resolve8, delayMs));
18136
18136
  }
18137
18137
  }
18138
18138
  return await toRetry();
@@ -18440,6 +18440,15 @@ var require_dist_cjs51 = __commonJS({
18440
18440
  var os4 = require("os");
18441
18441
  var process2 = require("process");
18442
18442
  var middlewareUserAgent = require_dist_cjs29();
18443
+ var getRuntimeUserAgentPair = () => {
18444
+ const runtimesToCheck = ["deno", "bun", "llrt"];
18445
+ for (const runtime of runtimesToCheck) {
18446
+ if (process2.versions[runtime]) {
18447
+ return [`md/${runtime}`, process2.versions[runtime]];
18448
+ }
18449
+ }
18450
+ return ["md/nodejs", process2.versions.node];
18451
+ };
18443
18452
  var crtAvailability = {
18444
18453
  isCrtAvailable: false
18445
18454
  };
@@ -18450,13 +18459,14 @@ var require_dist_cjs51 = __commonJS({
18450
18459
  return null;
18451
18460
  };
18452
18461
  var createDefaultUserAgentProvider5 = ({ serviceId, clientVersion }) => {
18462
+ const runtimeUserAgentPair = getRuntimeUserAgentPair();
18453
18463
  return async (config) => {
18454
18464
  const sections = [
18455
18465
  ["aws-sdk-js", clientVersion],
18456
18466
  ["ua", "2.1"],
18457
18467
  [`os/${os4.platform()}`, os4.release()],
18458
18468
  ["lang/js"],
18459
- ["md/nodejs", `${process2.versions.node}`]
18469
+ runtimeUserAgentPair
18460
18470
  ];
18461
18471
  const crtAvailable = isCrtAvailable();
18462
18472
  if (crtAvailable) {
@@ -24019,8 +24029,8 @@ var require_dist_cjs66 = __commonJS({
24019
24029
  systemClockOffsetProvider: this.systemClockOffsetProvider
24020
24030
  });
24021
24031
  let resolvePipeline;
24022
- const pipelineError = new Promise((resolve7, reject2) => {
24023
- resolvePipeline = () => resolve7(void 0);
24032
+ const pipelineError = new Promise((resolve8, reject2) => {
24033
+ resolvePipeline = () => resolve8(void 0);
24024
24034
  node_stream.pipeline(payloadStream, signingStream, request.body, (err) => {
24025
24035
  if (err) {
24026
24036
  reject2(new Error(`Pipeline error in @aws-sdk/eventstream-handler-node: ${err.message}`, { cause: err }));
@@ -24126,7 +24136,7 @@ var init_package2 = __esm({
24126
24136
  "node_modules/@aws-sdk/token-providers/node_modules/@aws-sdk/nested-clients/package.json"() {
24127
24137
  package_default2 = {
24128
24138
  name: "@aws-sdk/nested-clients",
24129
- version: "3.994.0",
24139
+ version: "3.995.0",
24130
24140
  description: "Nested clients for AWS SDK packages.",
24131
24141
  main: "./dist-cjs/index.js",
24132
24142
  module: "./dist-es/index.js",
@@ -24162,9 +24172,9 @@ var init_package2 = __esm({
24162
24172
  "@aws-sdk/middleware-user-agent": "^3.972.11",
24163
24173
  "@aws-sdk/region-config-resolver": "^3.972.3",
24164
24174
  "@aws-sdk/types": "^3.973.1",
24165
- "@aws-sdk/util-endpoints": "3.994.0",
24175
+ "@aws-sdk/util-endpoints": "3.995.0",
24166
24176
  "@aws-sdk/util-user-agent-browser": "^3.972.3",
24167
- "@aws-sdk/util-user-agent-node": "^3.972.9",
24177
+ "@aws-sdk/util-user-agent-node": "^3.972.10",
24168
24178
  "@smithy/config-resolver": "^4.4.6",
24169
24179
  "@smithy/core": "^3.23.2",
24170
24180
  "@smithy/fetch-http-handler": "^5.3.9",
@@ -25574,7 +25584,7 @@ var require_dist_cjs69 = __commonJS({
25574
25584
  streamEnded = true;
25575
25585
  });
25576
25586
  while (!generationEnded) {
25577
- const value = await new Promise((resolve7) => setTimeout(() => resolve7(records.shift()), 0));
25587
+ const value = await new Promise((resolve8) => setTimeout(() => resolve8(records.shift()), 0));
25578
25588
  if (value) {
25579
25589
  yield value;
25580
25590
  }
@@ -31837,7 +31847,7 @@ async function waitForFileLock(lockPath, binaryPath) {
31837
31847
  }
31838
31848
  } catch {
31839
31849
  }
31840
- await new Promise((resolve7) => setTimeout(resolve7, LOCK_POLL_INTERVAL_MS));
31850
+ await new Promise((resolve8) => setTimeout(resolve8, LOCK_POLL_INTERVAL_MS));
31841
31851
  }
31842
31852
  if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
31843
31853
  console.log(`Timeout waiting for file lock`);
@@ -33186,7 +33196,7 @@ Cwd: ${cwd}`;
33186
33196
  }
33187
33197
  }
33188
33198
  function extractWithStdin(binaryPath, cliArgs, content, options, cwd) {
33189
- return new Promise((resolve7, reject2) => {
33199
+ return new Promise((resolve8, reject2) => {
33190
33200
  const childProcess = (0, import_child_process4.spawn)(binaryPath, ["extract", ...cliArgs], {
33191
33201
  stdio: ["pipe", "pipe", "pipe"],
33192
33202
  cwd
@@ -33209,7 +33219,7 @@ function extractWithStdin(binaryPath, cliArgs, content, options, cwd) {
33209
33219
  }
33210
33220
  try {
33211
33221
  const result = processExtractOutput(stdout, options);
33212
- resolve7(result);
33222
+ resolve8(result);
33213
33223
  } catch (error2) {
33214
33224
  reject2(error2);
33215
33225
  }
@@ -33318,6 +33328,7 @@ async function delegate({
33318
33328
  model = null,
33319
33329
  enableBash = false,
33320
33330
  bashConfig = null,
33331
+ allowEdit = false,
33321
33332
  architectureFileName = null,
33322
33333
  promptType = "code-researcher",
33323
33334
  allowedTools = null,
@@ -33397,6 +33408,8 @@ async function delegate({
33397
33408
  // Inherit from parent
33398
33409
  bashConfig,
33399
33410
  // Inherit from parent
33411
+ allowEdit,
33412
+ // Inherit from parent
33400
33413
  architectureFileName,
33401
33414
  allowedTools,
33402
33415
  disableTools,
@@ -33582,7 +33595,7 @@ var init_delegate = __esm({
33582
33595
  if (debug) {
33583
33596
  console.error(`[DelegationManager] Slot unavailable (${this.globalActive}/${this.maxConcurrent}), queuing... (queue size: ${this.waitQueue.length}, timeout: ${effectiveTimeout}ms)`);
33584
33597
  }
33585
- return new Promise((resolve7, reject2) => {
33598
+ return new Promise((resolve8, reject2) => {
33586
33599
  const entry = {
33587
33600
  resolve: null,
33588
33601
  // Will be wrapped below
@@ -33598,7 +33611,7 @@ var init_delegate = __esm({
33598
33611
  if (settled) return;
33599
33612
  settled = true;
33600
33613
  if (entry.timeoutId) clearTimeout(entry.timeoutId);
33601
- resolve7(value);
33614
+ resolve8(value);
33602
33615
  };
33603
33616
  entry.reject = (error2) => {
33604
33617
  if (settled) return;
@@ -33648,7 +33661,7 @@ var init_delegate = __esm({
33648
33661
  while (this.waitQueue.length > 0 && this.globalActive < this.maxConcurrent) {
33649
33662
  const next = this.waitQueue.shift();
33650
33663
  if (!next) break;
33651
- const { resolve: resolve7, reject: reject2, parentSessionId, queuedAt } = next;
33664
+ const { resolve: resolve8, reject: reject2, parentSessionId, queuedAt } = next;
33652
33665
  if (parentSessionId) {
33653
33666
  const sessionData = this.sessionDelegations.get(parentSessionId);
33654
33667
  const sessionCount = sessionData?.count || 0;
@@ -33665,12 +33678,12 @@ var init_delegate = __esm({
33665
33678
  const waitTime = Date.now() - queuedAt;
33666
33679
  console.error(`[DelegationManager] Granted slot from queue (waited ${waitTime}ms). Active: ${this.globalActive}/${this.maxConcurrent}`);
33667
33680
  }
33668
- toResolve.push(resolve7);
33681
+ toResolve.push(resolve8);
33669
33682
  }
33670
33683
  if (toResolve.length > 0 || toReject.length > 0) {
33671
33684
  setImmediate(() => {
33672
- for (const resolve7 of toResolve) {
33673
- resolve7(true);
33685
+ for (const resolve8 of toResolve) {
33686
+ resolve8(true);
33674
33687
  }
33675
33688
  for (const { reject: reject2, error: error2 } of toReject) {
33676
33689
  reject2(error2);
@@ -38305,6 +38318,400 @@ var init_zod = __esm({
38305
38318
  }
38306
38319
  });
38307
38320
 
38321
+ // src/tools/fuzzyMatch.js
38322
+ function findFuzzyMatch(content, searchString) {
38323
+ if (!searchString || searchString.trim().length === 0) {
38324
+ return null;
38325
+ }
38326
+ const normalizedContent = content.replace(/\r\n/g, "\n");
38327
+ const normalizedSearch = searchString.replace(/\r\n/g, "\n");
38328
+ const contentLines = normalizedContent.split("\n");
38329
+ const searchLines = normalizedSearch.split("\n");
38330
+ const trimmed = lineTrimmedMatch(contentLines, searchLines);
38331
+ if (trimmed) return { ...trimmed, strategy: "line-trimmed" };
38332
+ const normalized = whitespaceNormalizedMatch(normalizedContent, normalizedSearch);
38333
+ if (normalized) return { ...normalized, strategy: "whitespace-normalized" };
38334
+ const indentFlex = indentFlexibleMatch(contentLines, searchLines);
38335
+ if (indentFlex) return { ...indentFlex, strategy: "indent-flexible" };
38336
+ return null;
38337
+ }
38338
+ function lineTrimmedMatch(contentLines, searchLines) {
38339
+ if (searchLines.length === 0) return null;
38340
+ const trimmedSearchLines = searchLines.map((line) => line.trim());
38341
+ if (trimmedSearchLines.every((line) => line === "")) return null;
38342
+ const windowSize = searchLines.length;
38343
+ const matches = [];
38344
+ for (let i5 = 0; i5 <= contentLines.length - windowSize; i5++) {
38345
+ let allMatch = true;
38346
+ for (let j5 = 0; j5 < windowSize; j5++) {
38347
+ if (contentLines[i5 + j5].trim() !== trimmedSearchLines[j5]) {
38348
+ allMatch = false;
38349
+ break;
38350
+ }
38351
+ }
38352
+ if (allMatch) {
38353
+ const matchedText = contentLines.slice(i5, i5 + windowSize).join("\n");
38354
+ matches.push(matchedText);
38355
+ }
38356
+ }
38357
+ if (matches.length === 0) return null;
38358
+ return {
38359
+ matchedText: matches[0],
38360
+ count: matches.length
38361
+ };
38362
+ }
38363
+ function whitespaceNormalizedMatch(content, search2) {
38364
+ if (!search2 || search2.trim().length === 0) return null;
38365
+ const { normalized: normContent, indexMap: contentMap } = buildNormalizedMap(content);
38366
+ const { normalized: normSearch } = buildNormalizedMap(search2);
38367
+ if (normSearch.length === 0) return null;
38368
+ const matches = [];
38369
+ let searchStart = 0;
38370
+ while (searchStart <= normContent.length - normSearch.length) {
38371
+ const idx = normContent.indexOf(normSearch, searchStart);
38372
+ if (idx === -1) break;
38373
+ const originalStart = contentMap[idx];
38374
+ const originalEnd = contentMap[idx + normSearch.length - 1];
38375
+ let actualEnd = originalEnd + 1;
38376
+ while (actualEnd < content.length && /[ \t]/.test(content[actualEnd]) && (actualEnd === originalEnd + 1 || /[ \t]/.test(content[actualEnd - 1]))) {
38377
+ if (contentMap.indexOf(actualEnd) > idx + normSearch.length - 1 || contentMap.indexOf(actualEnd) === -1) {
38378
+ break;
38379
+ }
38380
+ actualEnd++;
38381
+ }
38382
+ const matchedText = content.substring(originalStart, actualEnd);
38383
+ matches.push(matchedText);
38384
+ searchStart = idx + 1;
38385
+ }
38386
+ if (matches.length === 0) return null;
38387
+ return {
38388
+ matchedText: matches[0],
38389
+ count: matches.length
38390
+ };
38391
+ }
38392
+ function buildNormalizedMap(str) {
38393
+ const normalized = [];
38394
+ const indexMap = [];
38395
+ let i5 = 0;
38396
+ while (i5 < str.length) {
38397
+ const ch = str[i5];
38398
+ if (ch === " " || ch === " ") {
38399
+ normalized.push(" ");
38400
+ indexMap.push(i5);
38401
+ while (i5 < str.length && (str[i5] === " " || str[i5] === " ")) {
38402
+ i5++;
38403
+ }
38404
+ } else {
38405
+ normalized.push(ch);
38406
+ indexMap.push(i5);
38407
+ i5++;
38408
+ }
38409
+ }
38410
+ return {
38411
+ normalized: normalized.join(""),
38412
+ indexMap
38413
+ };
38414
+ }
38415
+ function indentFlexibleMatch(contentLines, searchLines) {
38416
+ if (searchLines.length === 0) return null;
38417
+ if (searchLines.every((line) => line.trim() === "")) return null;
38418
+ const searchMinIndent = getMinIndent(searchLines);
38419
+ const strippedSearch = searchLines.map((line) => stripIndent(line, searchMinIndent));
38420
+ const windowSize = searchLines.length;
38421
+ const matches = [];
38422
+ for (let i5 = 0; i5 <= contentLines.length - windowSize; i5++) {
38423
+ const windowLines = contentLines.slice(i5, i5 + windowSize);
38424
+ const windowMinIndent = getMinIndent(windowLines);
38425
+ const strippedWindow = windowLines.map((line) => stripIndent(line, windowMinIndent));
38426
+ let allMatch = true;
38427
+ for (let j5 = 0; j5 < windowSize; j5++) {
38428
+ if (strippedWindow[j5] !== strippedSearch[j5]) {
38429
+ allMatch = false;
38430
+ break;
38431
+ }
38432
+ }
38433
+ if (allMatch) {
38434
+ const matchedText = windowLines.join("\n");
38435
+ matches.push(matchedText);
38436
+ }
38437
+ }
38438
+ if (matches.length === 0) return null;
38439
+ return {
38440
+ matchedText: matches[0],
38441
+ count: matches.length
38442
+ };
38443
+ }
38444
+ function getMinIndent(lines) {
38445
+ let min = Infinity;
38446
+ for (const line of lines) {
38447
+ if (line.trim() === "") continue;
38448
+ const match2 = line.match(/^([ \t]*)/);
38449
+ if (match2) {
38450
+ min = Math.min(min, match2[1].length);
38451
+ }
38452
+ }
38453
+ return min === Infinity ? 0 : min;
38454
+ }
38455
+ function stripIndent(line, amount) {
38456
+ if (line.trim() === "") return "";
38457
+ if (amount <= 0) return line;
38458
+ return line.substring(Math.min(amount, line.length));
38459
+ }
38460
+ var init_fuzzyMatch = __esm({
38461
+ "src/tools/fuzzyMatch.js"() {
38462
+ "use strict";
38463
+ }
38464
+ });
38465
+
38466
+ // src/tools/symbolEdit.js
38467
+ async function findSymbol(filePath, symbolName, cwd) {
38468
+ try {
38469
+ const result = await extract({
38470
+ files: [`${filePath}#${symbolName}`],
38471
+ format: "json",
38472
+ json: true,
38473
+ cwd
38474
+ });
38475
+ if (!result || !result.results || result.results.length === 0) {
38476
+ return null;
38477
+ }
38478
+ const match2 = result.results[0];
38479
+ return {
38480
+ startLine: match2.lines[0],
38481
+ // 1-indexed
38482
+ endLine: match2.lines[1],
38483
+ // 1-indexed
38484
+ code: match2.code,
38485
+ nodeType: match2.node_type,
38486
+ file: match2.file
38487
+ };
38488
+ } catch (error2) {
38489
+ if (process.env.DEBUG === "1") {
38490
+ console.error(`[SymbolEdit] findSymbol error for "${symbolName}" in ${filePath}: ${error2.message}`);
38491
+ }
38492
+ return null;
38493
+ }
38494
+ }
38495
+ async function findAllSymbols(filePath, symbolName, cwd) {
38496
+ try {
38497
+ const result = await extract({
38498
+ files: [`${filePath}#${symbolName}`],
38499
+ format: "json",
38500
+ json: true,
38501
+ cwd
38502
+ });
38503
+ if (!result || !result.results || result.results.length === 0) {
38504
+ return [];
38505
+ }
38506
+ return result.results.map((match2) => ({
38507
+ startLine: match2.lines[0],
38508
+ endLine: match2.lines[1],
38509
+ code: match2.code,
38510
+ nodeType: match2.node_type,
38511
+ file: match2.file,
38512
+ qualifiedName: match2.symbol_signature || symbolName
38513
+ }));
38514
+ } catch (error2) {
38515
+ if (process.env.DEBUG === "1") {
38516
+ console.error(`[SymbolEdit] findAllSymbols error for "${symbolName}" in ${filePath}: ${error2.message}`);
38517
+ }
38518
+ return [];
38519
+ }
38520
+ }
38521
+ function detectBaseIndent(code) {
38522
+ const lines = code.split("\n");
38523
+ for (const line of lines) {
38524
+ if (line.trim().length > 0) {
38525
+ const match2 = line.match(/^(\s*)/);
38526
+ return match2 ? match2[1] : "";
38527
+ }
38528
+ }
38529
+ return "";
38530
+ }
38531
+ function reindent(newContent, targetIndent) {
38532
+ const lines = newContent.split("\n");
38533
+ const sourceIndent = detectBaseIndent(newContent);
38534
+ return lines.map((line) => {
38535
+ if (line.trim().length === 0) {
38536
+ return "";
38537
+ }
38538
+ if (line.startsWith(sourceIndent)) {
38539
+ return targetIndent + line.slice(sourceIndent.length);
38540
+ }
38541
+ return line;
38542
+ }).join("\n");
38543
+ }
38544
+ var init_symbolEdit = __esm({
38545
+ "src/tools/symbolEdit.js"() {
38546
+ "use strict";
38547
+ init_extract();
38548
+ }
38549
+ });
38550
+
38551
+ // src/tools/hashline.js
38552
+ function computeLineHash(line) {
38553
+ const stripped = (line || "").replace(/\s+/g, "");
38554
+ let h5 = 5381;
38555
+ for (let i5 = 0; i5 < stripped.length; i5++) {
38556
+ h5 = (h5 << 5) + h5 + stripped.charCodeAt(i5) & 4294967295;
38557
+ }
38558
+ return ((h5 >>> 0) % 256).toString(16).padStart(2, "0");
38559
+ }
38560
+ function parseLineRef(ref2) {
38561
+ if (ref2 === void 0 || ref2 === null) return null;
38562
+ const str = String(ref2).trim();
38563
+ if (!str) return null;
38564
+ const hashMatch = str.match(/^(\d+):([0-9a-fA-F]{2})$/);
38565
+ if (hashMatch) {
38566
+ const line = parseInt(hashMatch[1], 10);
38567
+ if (line < 1 || !isFinite(line)) return null;
38568
+ return { line, hash: hashMatch[2].toLowerCase() };
38569
+ }
38570
+ const lineMatch = str.match(/^(\d+)$/);
38571
+ if (lineMatch) {
38572
+ const line = parseInt(lineMatch[1], 10);
38573
+ if (line < 1 || !isFinite(line)) return null;
38574
+ return { line, hash: null };
38575
+ }
38576
+ return null;
38577
+ }
38578
+ function validateLineHash(lineNum, hash, fileLines) {
38579
+ const idx = lineNum - 1;
38580
+ if (idx < 0 || idx >= fileLines.length) {
38581
+ return { valid: false, actualHash: "", actualContent: "" };
38582
+ }
38583
+ const actualContent = fileLines[idx];
38584
+ const actualHash = computeLineHash(actualContent);
38585
+ return {
38586
+ valid: actualHash === hash.toLowerCase(),
38587
+ actualHash,
38588
+ actualContent
38589
+ };
38590
+ }
38591
+ function annotateOutputWithHashes(output) {
38592
+ if (!output || typeof output !== "string") return output;
38593
+ return output.split("\n").map((line) => {
38594
+ const cleanLine = line.endsWith("\r") ? line.slice(0, -1) : line;
38595
+ const match2 = cleanLine.match(/^(\s*)(\d+)(\s*\|)(.*)$/);
38596
+ if (!match2) return line;
38597
+ const [, prefix, lineNum, pipeSection, content] = match2;
38598
+ const hash = computeLineHash(content);
38599
+ const cr = line.endsWith("\r") ? "\r" : "";
38600
+ return `${prefix}${lineNum}:${hash}${pipeSection}${content}${cr}`;
38601
+ }).join("\n");
38602
+ }
38603
+ function stripHashlinePrefixes(text) {
38604
+ if (!text || typeof text !== "string") return { cleaned: text || "", stripped: false };
38605
+ const lines = text.split("\n");
38606
+ if (lines.length === 0) return { cleaned: "", stripped: false };
38607
+ const nonEmptyLines = lines.filter((l5) => l5.trim().length > 0);
38608
+ if (nonEmptyLines.length === 0) return { cleaned: text, stripped: false };
38609
+ const prefixPattern = /^\s*\d+(?::[0-9a-fA-F]{2})?\s*\|\s?/;
38610
+ const matchCount = nonEmptyLines.filter((l5) => prefixPattern.test(l5)).length;
38611
+ if (matchCount / nonEmptyLines.length <= 0.5) {
38612
+ return { cleaned: text, stripped: false };
38613
+ }
38614
+ const cleaned = lines.map((line) => {
38615
+ if (line.trim().length === 0) return line;
38616
+ return line.replace(prefixPattern, "");
38617
+ }).join("\n");
38618
+ return { cleaned, stripped: true };
38619
+ }
38620
+ var init_hashline = __esm({
38621
+ "src/tools/hashline.js"() {
38622
+ "use strict";
38623
+ }
38624
+ });
38625
+
38626
+ // src/tools/lineEditHeuristics.js
38627
+ function stripEchoedBoundaries(newStr, fileLines, startLine, endLine, position) {
38628
+ const modifications = [];
38629
+ let lines = newStr.split("\n");
38630
+ if (lines.length === 0) return { result: newStr, modifications };
38631
+ if (position === "after") {
38632
+ const anchorIdx = startLine - 1;
38633
+ if (anchorIdx >= 0 && anchorIdx < fileLines.length) {
38634
+ const anchorTrimmed = fileLines[anchorIdx].trim();
38635
+ if (anchorTrimmed.length > 0 && lines.length > 0 && lines[0].trim() === anchorTrimmed) {
38636
+ lines = lines.slice(1);
38637
+ modifications.push("stripped echoed anchor line (insert-after)");
38638
+ }
38639
+ }
38640
+ } else if (position === "before") {
38641
+ const anchorIdx = startLine - 1;
38642
+ if (anchorIdx >= 0 && anchorIdx < fileLines.length) {
38643
+ const anchorTrimmed = fileLines[anchorIdx].trim();
38644
+ if (anchorTrimmed.length > 0 && lines.length > 0 && lines[lines.length - 1].trim() === anchorTrimmed) {
38645
+ lines = lines.slice(0, -1);
38646
+ modifications.push("stripped echoed anchor line (insert-before)");
38647
+ }
38648
+ }
38649
+ } else {
38650
+ const beforeIdx = startLine - 2;
38651
+ if (beforeIdx >= 0 && beforeIdx < fileLines.length) {
38652
+ const beforeTrimmed = fileLines[beforeIdx].trim();
38653
+ if (beforeTrimmed.length > 0 && lines.length > 0 && lines[0].trim() === beforeTrimmed) {
38654
+ lines = lines.slice(1);
38655
+ modifications.push("stripped echoed line before range");
38656
+ }
38657
+ }
38658
+ const afterIdx = endLine;
38659
+ if (afterIdx >= 0 && afterIdx < fileLines.length) {
38660
+ const afterTrimmed = fileLines[afterIdx].trim();
38661
+ if (afterTrimmed.length > 0 && lines.length > 0 && lines[lines.length - 1].trim() === afterTrimmed) {
38662
+ lines = lines.slice(0, -1);
38663
+ modifications.push("stripped echoed line after range");
38664
+ }
38665
+ }
38666
+ }
38667
+ return { result: lines.join("\n"), modifications };
38668
+ }
38669
+ function restoreIndentation(newStr, originalLines) {
38670
+ const modifications = [];
38671
+ if (!newStr || !originalLines || originalLines.length === 0) {
38672
+ return { result: newStr || "", modifications };
38673
+ }
38674
+ const originalCode = originalLines.join("\n");
38675
+ const targetIndent = detectBaseIndent(originalCode);
38676
+ const newIndent = detectBaseIndent(newStr);
38677
+ if (targetIndent !== newIndent) {
38678
+ const reindented = reindent(newStr, targetIndent);
38679
+ if (reindented !== newStr) {
38680
+ modifications.push(`reindented from "${newIndent}" to "${targetIndent}"`);
38681
+ return { result: reindented, modifications };
38682
+ }
38683
+ }
38684
+ return { result: newStr, modifications };
38685
+ }
38686
+ function cleanNewString(newStr, fileLines, startLine, endLine, position) {
38687
+ const modifications = [];
38688
+ if (!newStr && newStr !== "") return { cleaned: "", modifications };
38689
+ const { cleaned: afterPrefixes, stripped } = stripHashlinePrefixes(newStr);
38690
+ if (stripped) modifications.push("stripped line-number prefixes");
38691
+ const { result: afterEchoes, modifications: echoMods } = stripEchoedBoundaries(
38692
+ afterPrefixes,
38693
+ fileLines,
38694
+ startLine,
38695
+ endLine,
38696
+ position
38697
+ );
38698
+ modifications.push(...echoMods);
38699
+ if (!position) {
38700
+ const originalLines = fileLines.slice(startLine - 1, endLine);
38701
+ const { result: afterIndent, modifications: indentMods } = restoreIndentation(afterEchoes, originalLines);
38702
+ modifications.push(...indentMods);
38703
+ return { cleaned: afterIndent, modifications };
38704
+ }
38705
+ return { cleaned: afterEchoes, modifications };
38706
+ }
38707
+ var init_lineEditHeuristics = __esm({
38708
+ "src/tools/lineEditHeuristics.js"() {
38709
+ "use strict";
38710
+ init_symbolEdit();
38711
+ init_hashline();
38712
+ }
38713
+ });
38714
+
38308
38715
  // src/tools/edit.js
38309
38716
  function isPathAllowed(filePath, allowedFolders) {
38310
38717
  if (!allowedFolders || allowedFolders.length === 0) {
@@ -38328,6 +38735,174 @@ function parseFileToolOptions(options = {}) {
38328
38735
  workspaceRoot: options.workspaceRoot || options.cwd || allowedFolders.length > 0 && allowedFolders[0] || process.cwd()
38329
38736
  };
38330
38737
  }
38738
+ async function handleSymbolEdit({ resolvedPath: resolvedPath2, file_path, symbol: symbol15, new_string, position, debug, cwd, fileTracker }) {
38739
+ if (typeof symbol15 !== "string" || symbol15.trim() === "") {
38740
+ 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.';
38741
+ }
38742
+ if (position !== void 0 && position !== null && position !== "before" && position !== "after") {
38743
+ 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.';
38744
+ }
38745
+ const allMatches = await findAllSymbols(resolvedPath2, symbol15, cwd || process.cwd());
38746
+ if (allMatches.length === 0) {
38747
+ 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.`;
38748
+ }
38749
+ if (allMatches.length > 1) {
38750
+ const suggestions = allMatches.map(
38751
+ (m5) => ` - ${m5.qualifiedName} (${m5.nodeType}, line ${m5.startLine})`
38752
+ ).join("\n");
38753
+ return `Error editing ${file_path}: Found ${allMatches.length} symbols named "${symbol15}". Use a qualified name to specify which one:
38754
+ ${suggestions}
38755
+
38756
+ Example: <edit><file_path>${file_path}</file_path><symbol>${allMatches[0].qualifiedName}</symbol><new_string>...</new_string></edit>`;
38757
+ }
38758
+ const symbolInfo = allMatches[0];
38759
+ if (fileTracker) {
38760
+ const check = fileTracker.checkSymbolContent(resolvedPath2, symbol15, symbolInfo.code);
38761
+ if (!check.ok && check.reason === "stale") {
38762
+ return `Error editing ${file_path}: Symbol "${symbol15}" has changed since you last read it. Use extract to re-read the current content, then retry.
38763
+
38764
+ Example: <extract><targets>${file_path}#${symbol15}</targets></extract>`;
38765
+ }
38766
+ }
38767
+ const content = await import_fs4.promises.readFile(resolvedPath2, "utf-8");
38768
+ const lines = content.split("\n");
38769
+ if (position) {
38770
+ const refIndent = detectBaseIndent(symbolInfo.code);
38771
+ const reindented = reindent(new_string, refIndent);
38772
+ const newLines = reindented.split("\n");
38773
+ if (position === "after") {
38774
+ lines.splice(symbolInfo.endLine, 0, "", ...newLines);
38775
+ } else {
38776
+ lines.splice(symbolInfo.startLine - 1, 0, ...newLines, "");
38777
+ }
38778
+ await import_fs4.promises.writeFile(resolvedPath2, lines.join("\n"), "utf-8");
38779
+ if (fileTracker) {
38780
+ const updated = await findSymbol(resolvedPath2, symbol15, cwd || process.cwd());
38781
+ if (updated) {
38782
+ fileTracker.trackSymbolAfterWrite(resolvedPath2, symbol15, updated.code, updated.startLine, updated.endLine);
38783
+ }
38784
+ fileTracker.markFileSeen(resolvedPath2);
38785
+ }
38786
+ const insertLine = position === "after" ? symbolInfo.endLine + 1 : symbolInfo.startLine;
38787
+ if (debug) {
38788
+ console.error(`[Edit] Successfully inserted ${newLines.length} lines ${position} "${symbol15}" at line ${insertLine} in ${resolvedPath2}`);
38789
+ }
38790
+ return `Successfully inserted ${newLines.length} lines ${position} symbol "${symbol15}" in ${file_path} (at line ${insertLine})`;
38791
+ } else {
38792
+ const originalIndent = detectBaseIndent(symbolInfo.code);
38793
+ const reindented = reindent(new_string, originalIndent);
38794
+ const newLines = reindented.split("\n");
38795
+ lines.splice(symbolInfo.startLine - 1, symbolInfo.endLine - symbolInfo.startLine + 1, ...newLines);
38796
+ await import_fs4.promises.writeFile(resolvedPath2, lines.join("\n"), "utf-8");
38797
+ if (fileTracker) {
38798
+ const updated = await findSymbol(resolvedPath2, symbol15, cwd || process.cwd());
38799
+ if (updated) {
38800
+ fileTracker.trackSymbolAfterWrite(resolvedPath2, symbol15, updated.code, updated.startLine, updated.endLine);
38801
+ }
38802
+ fileTracker.markFileSeen(resolvedPath2);
38803
+ }
38804
+ if (debug) {
38805
+ console.error(`[Edit] Successfully replaced symbol "${symbol15}" in ${resolvedPath2} (lines ${symbolInfo.startLine}-${symbolInfo.endLine})`);
38806
+ }
38807
+ return `Successfully replaced symbol "${symbol15}" in ${file_path} (was lines ${symbolInfo.startLine}-${symbolInfo.endLine}, now ${newLines.length} lines)`;
38808
+ }
38809
+ }
38810
+ function buildLineEditResponse(file_path, startLine, endLine, newLineCount, updatedLines, insertOffset, action, heuristicMods) {
38811
+ const contextBefore = 1;
38812
+ const contextAfter = 1;
38813
+ const contextStart = Math.max(0, insertOffset - contextBefore);
38814
+ const contextEnd = Math.min(updatedLines.length, insertOffset + newLineCount + contextAfter);
38815
+ let context = "Context:\n";
38816
+ for (let i5 = contextStart; i5 < contextEnd; i5++) {
38817
+ const lineNum = i5 + 1;
38818
+ const hash = computeLineHash(updatedLines[i5]);
38819
+ const isNew = i5 >= insertOffset && i5 < insertOffset + newLineCount;
38820
+ const marker15 = isNew ? ">" : " ";
38821
+ context += `${marker15} ${lineNum}:${hash} | ${updatedLines[i5]}
38822
+ `;
38823
+ }
38824
+ let msg = `Successfully edited ${file_path} (${action})`;
38825
+ if (heuristicMods.length > 0) {
38826
+ msg += ` [auto-corrected: ${heuristicMods.join(", ")}]`;
38827
+ }
38828
+ msg += "\n" + context;
38829
+ return msg;
38830
+ }
38831
+ async function handleLineEdit({ resolvedPath: resolvedPath2, file_path, start_line, end_line, new_string, position, debug, fileTracker }) {
38832
+ const startRef = parseLineRef(start_line);
38833
+ if (!startRef) {
38834
+ 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.`;
38835
+ }
38836
+ let endRef = null;
38837
+ if (end_line !== void 0 && end_line !== null) {
38838
+ endRef = parseLineRef(end_line);
38839
+ if (!endRef) {
38840
+ 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.`;
38841
+ }
38842
+ }
38843
+ const startLine = startRef.line;
38844
+ const endLine = endRef ? endRef.line : startLine;
38845
+ if (endLine < startLine) {
38846
+ return `Error editing file: end_line (${endLine}) must be >= start_line (${startLine}).`;
38847
+ }
38848
+ if (position !== void 0 && position !== null && position !== "before" && position !== "after") {
38849
+ 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.';
38850
+ }
38851
+ const content = await import_fs4.promises.readFile(resolvedPath2, "utf-8");
38852
+ const fileLines = content.split("\n");
38853
+ if (startLine > fileLines.length) {
38854
+ return `Error editing file: Line ${startLine} is beyond file length (${fileLines.length} lines). Use 'extract' to read the current file content.`;
38855
+ }
38856
+ if (endLine > fileLines.length) {
38857
+ return `Error editing file: Line ${endLine} is beyond file length (${fileLines.length} lines). Use 'extract' to read the current file content.`;
38858
+ }
38859
+ if (startRef.hash) {
38860
+ const validation = validateLineHash(startLine, startRef.hash, fileLines);
38861
+ if (!validation.valid) {
38862
+ 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.`;
38863
+ }
38864
+ }
38865
+ if (endRef && endRef.hash) {
38866
+ const validation = validateLineHash(endLine, endRef.hash, fileLines);
38867
+ if (!validation.valid) {
38868
+ 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.`;
38869
+ }
38870
+ }
38871
+ const { cleaned, modifications } = cleanNewString(new_string, fileLines, startLine, endLine, position);
38872
+ if (debug) {
38873
+ if (modifications.length > 0) {
38874
+ console.error(`[Edit] Heuristic corrections: ${modifications.join(", ")}`);
38875
+ }
38876
+ }
38877
+ const newLines = cleaned === "" ? [] : cleaned.split("\n");
38878
+ if (position === "after") {
38879
+ fileLines.splice(startLine, 0, ...newLines);
38880
+ await import_fs4.promises.writeFile(resolvedPath2, fileLines.join("\n"), "utf-8");
38881
+ if (fileTracker) await fileTracker.trackFileAfterWrite(resolvedPath2);
38882
+ const action = `${newLines.length} line${newLines.length !== 1 ? "s" : ""} inserted after line ${startLine}`;
38883
+ return buildLineEditResponse(file_path, startLine, startLine, newLines.length, fileLines, startLine, action, modifications);
38884
+ } else if (position === "before") {
38885
+ fileLines.splice(startLine - 1, 0, ...newLines);
38886
+ await import_fs4.promises.writeFile(resolvedPath2, fileLines.join("\n"), "utf-8");
38887
+ if (fileTracker) await fileTracker.trackFileAfterWrite(resolvedPath2);
38888
+ const action = `${newLines.length} line${newLines.length !== 1 ? "s" : ""} inserted before line ${startLine}`;
38889
+ return buildLineEditResponse(file_path, startLine, startLine, newLines.length, fileLines, startLine - 1, action, modifications);
38890
+ } else {
38891
+ const replacedCount = endLine - startLine + 1;
38892
+ fileLines.splice(startLine - 1, replacedCount, ...newLines);
38893
+ await import_fs4.promises.writeFile(resolvedPath2, fileLines.join("\n"), "utf-8");
38894
+ if (fileTracker) await fileTracker.trackFileAfterWrite(resolvedPath2);
38895
+ let action;
38896
+ if (newLines.length === 0) {
38897
+ action = `${replacedCount} line${replacedCount !== 1 ? "s" : ""} deleted (lines ${startLine}-${endLine})`;
38898
+ } else if (startLine === endLine) {
38899
+ action = `line ${startLine} replaced with ${newLines.length} line${newLines.length !== 1 ? "s" : ""}`;
38900
+ } else {
38901
+ action = `lines ${startLine}-${endLine} replaced with ${newLines.length} line${newLines.length !== 1 ? "s" : ""}`;
38902
+ }
38903
+ return buildLineEditResponse(file_path, startLine, endLine, newLines.length, fileLines, startLine - 1, action, modifications);
38904
+ }
38905
+ }
38331
38906
  var import_ai, import_fs4, import_path5, import_fs5, editTool, createTool, editSchema, createSchema, editDescription, createDescription, editToolDefinition, createToolDefinition;
38332
38907
  var init_edit = __esm({
38333
38908
  "src/tools/edit.js"() {
@@ -38337,24 +38912,31 @@ var init_edit = __esm({
38337
38912
  import_path5 = require("path");
38338
38913
  import_fs5 = require("fs");
38339
38914
  init_path_validation();
38915
+ init_fuzzyMatch();
38916
+ init_symbolEdit();
38917
+ init_hashline();
38918
+ init_lineEditHeuristics();
38340
38919
  editTool = (options = {}) => {
38341
38920
  const { debug, allowedFolders, cwd, workspaceRoot } = parseFileToolOptions(options);
38342
38921
  return (0, import_ai.tool)({
38343
38922
  name: "edit",
38344
- description: `Edit files using exact string replacement (Claude Code style).
38923
+ description: `Edit files using text replacement, AST-aware symbol operations, or line-targeted editing.
38345
38924
 
38346
- This tool performs exact string replacements in files. It requires the old_string to match exactly what's in the file, including all whitespace and indentation.
38925
+ Modes:
38926
+ 1. Text edit: Provide old_string + new_string to find and replace text (with fuzzy matching fallback)
38927
+ 2. Symbol replace: Provide symbol + new_string to replace an entire function/class/method by name
38928
+ 3. Symbol insert: Provide symbol + new_string + position to insert code before/after a symbol
38929
+ 4. Line-targeted edit: Provide start_line + new_string to edit by line number (from extract/search output)
38347
38930
 
38348
38931
  Parameters:
38349
38932
  - file_path: Path to the file to edit (absolute or relative)
38350
- - old_string: Exact text to find and replace (must be unique in the file unless replace_all is true)
38351
- - new_string: Text to replace with
38352
- - replace_all: (optional) Replace all occurrences instead of requiring uniqueness
38353
-
38354
- Important:
38355
- - The old_string must match EXACTLY including whitespace
38356
- - If old_string appears multiple times and replace_all is false, the edit will fail
38357
- - Use larger context around the string to ensure uniqueness when needed`,
38933
+ - new_string: Replacement text or new code content
38934
+ - old_string: (optional) Text to find and replace. If omitted, symbol or start_line must be provided.
38935
+ - replace_all: (optional) Replace all occurrences (text mode only)
38936
+ - symbol: (optional) Symbol name for AST-aware editing (e.g. "myFunction", "MyClass.myMethod")
38937
+ - position: (optional) "before" or "after" \u2014 insert code near a symbol or line instead of replacing it
38938
+ - start_line: (optional) Line reference (e.g. "42" or "42:ab") for line-targeted editing
38939
+ - end_line: (optional) End of line range, inclusive (e.g. "55" or "55:cd")`,
38358
38940
  inputSchema: {
38359
38941
  type: "object",
38360
38942
  properties: {
@@ -38364,30 +38946,44 @@ Important:
38364
38946
  },
38365
38947
  old_string: {
38366
38948
  type: "string",
38367
- description: "Exact text to find and replace"
38949
+ description: "Text to find and replace (for text-based editing)"
38368
38950
  },
38369
38951
  new_string: {
38370
38952
  type: "string",
38371
- description: "Text to replace with"
38953
+ description: "Replacement text or new code content"
38372
38954
  },
38373
38955
  replace_all: {
38374
38956
  type: "boolean",
38375
- description: "Replace all occurrences (default: false)",
38957
+ description: "Replace all occurrences (default: false, text mode only)",
38376
38958
  default: false
38959
+ },
38960
+ symbol: {
38961
+ type: "string",
38962
+ description: 'Symbol name for AST-aware editing (e.g. "myFunction", "MyClass.myMethod")'
38963
+ },
38964
+ position: {
38965
+ type: "string",
38966
+ enum: ["before", "after"],
38967
+ description: "Insert before/after symbol or line (requires symbol or start_line, omit to replace)"
38968
+ },
38969
+ start_line: {
38970
+ type: "string",
38971
+ description: 'Line reference for line-targeted editing (e.g. "42" or "42:ab" with hash)'
38972
+ },
38973
+ end_line: {
38974
+ type: "string",
38975
+ description: 'End of line range, inclusive (e.g. "55" or "55:cd"). Defaults to start_line.'
38377
38976
  }
38378
38977
  },
38379
- required: ["file_path", "old_string", "new_string"]
38978
+ required: ["file_path", "new_string"]
38380
38979
  },
38381
- execute: async ({ file_path, old_string, new_string, replace_all = false }) => {
38980
+ execute: async ({ file_path, old_string, new_string, replace_all = false, symbol: symbol15, position, start_line, end_line }) => {
38382
38981
  try {
38383
38982
  if (!file_path || typeof file_path !== "string" || file_path.trim() === "") {
38384
- return `Error editing file: Invalid file_path - must be a non-empty string`;
38385
- }
38386
- if (old_string === void 0 || old_string === null || typeof old_string !== "string") {
38387
- return `Error editing file: Invalid old_string - must be a string`;
38983
+ return `Error editing file: Invalid file_path - must be a non-empty string. Provide an absolute path or a path relative to the working directory (e.g. "src/main.js").`;
38388
38984
  }
38389
38985
  if (new_string === void 0 || new_string === null || typeof new_string !== "string") {
38390
- return `Error editing file: Invalid new_string - must be a string`;
38986
+ return `Error editing file: Invalid new_string - must be a string. Provide the replacement content as a string value (empty string "" is valid for deletions).`;
38391
38987
  }
38392
38988
  const resolvedPath2 = (0, import_path5.isAbsolute)(file_path) ? file_path : (0, import_path5.resolve)(cwd || process.cwd(), file_path);
38393
38989
  if (debug) {
@@ -38395,34 +38991,64 @@ Important:
38395
38991
  }
38396
38992
  if (!isPathAllowed(resolvedPath2, allowedFolders)) {
38397
38993
  const relativePath = toRelativePath(resolvedPath2, workspaceRoot);
38398
- return `Error editing file: Permission denied - ${relativePath} is outside allowed directories`;
38994
+ return `Error editing file: Permission denied - ${relativePath} is outside allowed directories. Use a file path within the project workspace.`;
38399
38995
  }
38400
38996
  if (!(0, import_fs5.existsSync)(resolvedPath2)) {
38401
- return `Error editing file: File not found - ${file_path}`;
38997
+ 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.`;
38998
+ }
38999
+ if (options.fileTracker && !options.fileTracker.isFileSeen(resolvedPath2)) {
39000
+ const displayPath = toRelativePath(resolvedPath2, workspaceRoot);
39001
+ 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.
39002
+
39003
+ Example: <extract><targets>${displayPath}</targets></extract>`;
39004
+ }
39005
+ if (symbol15 !== void 0 && symbol15 !== null) {
39006
+ return await handleSymbolEdit({ resolvedPath: resolvedPath2, file_path, symbol: symbol15, new_string, position, debug, cwd, fileTracker: options.fileTracker });
39007
+ }
39008
+ if (start_line !== void 0 && start_line !== null) {
39009
+ return await handleLineEdit({ resolvedPath: resolvedPath2, file_path, start_line, end_line, new_string, position, debug, fileTracker: options.fileTracker });
39010
+ }
39011
+ if (old_string === void 0 || old_string === null) {
39012
+ 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").';
39013
+ }
39014
+ if (typeof old_string !== "string") {
39015
+ return `Error editing file: Invalid old_string - must be a string. Provide the exact text to find in the file, or use the symbol parameter instead for AST-aware editing by name.`;
38402
39016
  }
38403
39017
  const content = await import_fs4.promises.readFile(resolvedPath2, "utf-8");
39018
+ let matchTarget = old_string;
39019
+ let matchStrategy = "exact";
38404
39020
  if (!content.includes(old_string)) {
38405
- return `Error editing file: String not found - the specified old_string was not found in ${file_path}`;
39021
+ const fuzzy = findFuzzyMatch(content, old_string);
39022
+ if (!fuzzy) {
39023
+ 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.`;
39024
+ }
39025
+ matchTarget = fuzzy.matchedText;
39026
+ matchStrategy = fuzzy.strategy;
39027
+ if (debug) {
39028
+ console.error(`[Edit] Exact match failed, used ${matchStrategy} matching`);
39029
+ }
38406
39030
  }
38407
- const occurrences = content.split(old_string).length - 1;
39031
+ const occurrences = content.split(matchTarget).length - 1;
38408
39032
  if (!replace_all && occurrences > 1) {
38409
- return `Error editing file: Multiple occurrences found - the old_string appears ${occurrences} times. Use replace_all: true to replace all occurrences, or provide more context to make the string unique.`;
39033
+ return `Error editing file: Multiple occurrences found - the old_string appears ${occurrences} times in ${file_path}. To fix: (1) Set replace_all=true to replace all occurrences, or (2) Include more surrounding lines in old_string to make the match unique (add the full line or adjacent lines for context).`;
38410
39034
  }
38411
39035
  let newContent;
38412
39036
  if (replace_all) {
38413
- newContent = content.replaceAll(old_string, new_string);
39037
+ newContent = content.replaceAll(matchTarget, new_string);
38414
39038
  } else {
38415
- newContent = content.replace(old_string, new_string);
39039
+ newContent = content.replace(matchTarget, new_string);
38416
39040
  }
38417
39041
  if (newContent === content) {
38418
- return `Error editing file: No changes made - old_string and new_string might be the same`;
39042
+ return `Error editing file: No changes made - the replacement result is identical to the original. Verify that old_string and new_string are actually different. If fuzzy matching was used, the matched text may already equal new_string.`;
38419
39043
  }
38420
39044
  await import_fs4.promises.writeFile(resolvedPath2, newContent, "utf-8");
39045
+ if (options.fileTracker) await options.fileTracker.trackFileAfterWrite(resolvedPath2);
38421
39046
  const replacedCount = replace_all ? occurrences : 1;
38422
39047
  if (debug) {
38423
39048
  console.error(`[Edit] Successfully edited ${resolvedPath2}, replaced ${replacedCount} occurrence(s)`);
38424
39049
  }
38425
- return `Successfully edited ${file_path} (${replacedCount} replacement${replacedCount !== 1 ? "s" : ""})`;
39050
+ const strategyNote = matchStrategy !== "exact" ? `, matched via ${matchStrategy}` : "";
39051
+ return `Successfully edited ${file_path} (${replacedCount} replacement${replacedCount !== 1 ? "s" : ""}${strategyNote})`;
38426
39052
  } catch (error2) {
38427
39053
  console.error("[Edit] Error:", error2);
38428
39054
  return `Error editing file: ${error2.message}`;
@@ -38469,10 +39095,10 @@ Important:
38469
39095
  execute: async ({ file_path, content, overwrite = false }) => {
38470
39096
  try {
38471
39097
  if (!file_path || typeof file_path !== "string" || file_path.trim() === "") {
38472
- return `Error creating file: Invalid file_path - must be a non-empty string`;
39098
+ return `Error creating file: Invalid file_path - must be a non-empty string. Provide an absolute path or a path relative to the working directory (e.g. "src/newFile.js").`;
38473
39099
  }
38474
39100
  if (content === void 0 || content === null || typeof content !== "string") {
38475
- return `Error creating file: Invalid content - must be a string`;
39101
+ return `Error creating file: Invalid content - must be a string. Provide the file content as a string value (empty string "" is valid for an empty file).`;
38476
39102
  }
38477
39103
  const resolvedPath2 = (0, import_path5.isAbsolute)(file_path) ? file_path : (0, import_path5.resolve)(cwd || process.cwd(), file_path);
38478
39104
  if (debug) {
@@ -38480,15 +39106,17 @@ Important:
38480
39106
  }
38481
39107
  if (!isPathAllowed(resolvedPath2, allowedFolders)) {
38482
39108
  const relativePath = toRelativePath(resolvedPath2, workspaceRoot);
38483
- return `Error creating file: Permission denied - ${relativePath} is outside allowed directories`;
39109
+ return `Error creating file: Permission denied - ${relativePath} is outside allowed directories. Use a file path within the project workspace.`;
38484
39110
  }
38485
39111
  if ((0, import_fs5.existsSync)(resolvedPath2) && !overwrite) {
38486
39112
  return `Error creating file: File already exists - ${file_path}. Use overwrite: true to replace it.`;
38487
39113
  }
39114
+ const existed = (0, import_fs5.existsSync)(resolvedPath2);
38488
39115
  const dir = (0, import_path5.dirname)(resolvedPath2);
38489
39116
  await import_fs4.promises.mkdir(dir, { recursive: true });
38490
39117
  await import_fs4.promises.writeFile(resolvedPath2, content, "utf-8");
38491
- const action = (0, import_fs5.existsSync)(resolvedPath2) && overwrite ? "overwrote" : "created";
39118
+ if (options.fileTracker) await options.fileTracker.trackFileAfterWrite(resolvedPath2);
39119
+ const action = existed && overwrite ? "overwrote" : "created";
38492
39120
  const bytes = Buffer.byteLength(content, "utf-8");
38493
39121
  if (debug) {
38494
39122
  console.error(`[Create] Successfully ${action} ${resolvedPath2}`);
@@ -38510,18 +39138,35 @@ Important:
38510
39138
  },
38511
39139
  old_string: {
38512
39140
  type: "string",
38513
- description: "Exact text to find and replace"
39141
+ description: "Text to find and replace (for text-based editing)"
38514
39142
  },
38515
39143
  new_string: {
38516
39144
  type: "string",
38517
- description: "Text to replace with"
39145
+ description: "Replacement text or new code content"
38518
39146
  },
38519
39147
  replace_all: {
38520
39148
  type: "boolean",
38521
- description: "Replace all occurrences (default: false)"
39149
+ description: "Replace all occurrences (default: false, text mode only)"
39150
+ },
39151
+ symbol: {
39152
+ type: "string",
39153
+ description: 'Symbol name for AST-aware editing (e.g. "myFunction", "MyClass.myMethod")'
39154
+ },
39155
+ position: {
39156
+ type: "string",
39157
+ enum: ["before", "after"],
39158
+ description: "Insert before/after symbol or line (requires symbol or start_line, omit to replace)"
39159
+ },
39160
+ start_line: {
39161
+ type: "string",
39162
+ description: 'Line reference for line-targeted editing (e.g. "42" or "42:ab" with hash)'
39163
+ },
39164
+ end_line: {
39165
+ type: "string",
39166
+ description: 'End of line range, inclusive (e.g. "55" or "55:cd"). Defaults to start_line.'
38522
39167
  }
38523
39168
  },
38524
- required: ["file_path", "old_string", "new_string"]
39169
+ required: ["file_path", "new_string"]
38525
39170
  };
38526
39171
  createSchema = {
38527
39172
  type: "object",
@@ -38541,50 +39186,123 @@ Important:
38541
39186
  },
38542
39187
  required: ["file_path", "content"]
38543
39188
  };
38544
- editDescription = "Edit files using exact string replacement. Requires exact match including whitespace.";
39189
+ editDescription = "Edit files using text replacement, AST-aware symbol operations, or line-targeted editing. Supports fuzzy matching for text edits and optional hash-based integrity verification for line edits.";
38545
39190
  createDescription = "Create new files with specified content. Will create parent directories if needed.";
38546
39191
  editToolDefinition = `
38547
39192
  ## edit
38548
39193
  Description: ${editDescription}
38549
39194
 
38550
- When to use:
38551
- - For precise, surgical edits to existing files
38552
- - When you need to change specific lines or blocks of code
38553
- - For renaming functions, variables, or updating configuration values
38554
- - When the exact text to replace is known and unique (or use replace_all for multiple occurrences)
39195
+ Four editing modes \u2014 choose based on the scope of your change:
38555
39196
 
38556
- When NOT to use:
38557
- - For creating new files (use 'create' tool instead)
38558
- - When you cannot determine the exact text to replace
38559
- - When changes span multiple locations that would be better handled together
39197
+ 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.
39198
+
39199
+ 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.
39200
+
39201
+ 3. **Symbol insert** (symbol + new_string + position): For adding new code before or after an existing symbol. Set position to "before" or "after".
39202
+
39203
+ 4. **Line-targeted edit** (start_line + new_string): For precise edits using line numbers from extract/search output. Use start_line with a line number (e.g. "42") or line:hash (e.g. "42:ab") for integrity verification. Add end_line for multi-line ranges. Use position="before" or "after" to insert instead of replace.
38560
39204
 
38561
39205
  Parameters:
38562
39206
  - file_path: (required) Path to the file to edit
38563
- - old_string: (required) Exact text to find and replace (must match including whitespace, newlines, and indentation)
38564
- - new_string: (required) Text to replace with
38565
- - replace_all: (optional, default: false) Replace all occurrences if the string appears multiple times
38566
-
38567
- Important notes:
38568
- - The old_string MUST match EXACTLY, including all whitespace, indentation, and line breaks
38569
- - If old_string appears multiple times and replace_all is false, the tool will fail
38570
- - Always verify the exact formatting of the text you want to replace
39207
+ - new_string: (required) Replacement text or new code content
39208
+ - old_string: (optional) Text to find and replace \u2014 copy verbatim from the file, do not paraphrase or reformat
39209
+ - replace_all: (optional, default: false) Replace all occurrences of old_string (text mode only)
39210
+ - symbol: (optional) Name of a code symbol (e.g. "myFunction", "MyClass.myMethod") \u2014 must match a function, class, or method definition
39211
+ - position: (optional) "before" or "after" \u2014 insert new_string near the symbol or line instead of replacing it
39212
+ - start_line: (optional) Line reference for line-targeted editing (e.g. "42" or "42:ab")
39213
+ - end_line: (optional) End of line range, inclusive (e.g. "55" or "55:cd"). Defaults to start_line.
39214
+
39215
+ Mode selection rules (priority order):
39216
+ - If symbol is provided, symbol mode is used (old_string and start_line are ignored)
39217
+ - If start_line is provided (without symbol), line-targeted mode is used
39218
+ - If old_string is provided (without symbol or start_line), text mode is used
39219
+ - If none are provided, the tool returns an error with guidance
39220
+
39221
+ When to use each mode:
39222
+ - Small edits (a line or a few lines): use text mode with old_string
39223
+ - Replacing entire functions/classes/methods: use symbol mode \u2014 no exact text matching needed
39224
+ - Editing specific lines from extract/search output: use line-targeted mode with start_line
39225
+ - 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
39226
+
39227
+ Error handling:
39228
+ - If an edit fails, read the error message carefully \u2014 it contains specific instructions for how to fix the call and retry
39229
+ - Common fixes: use 'search'/'extract' to get exact file content, add more context to old_string, switch between text and symbol modes
39230
+ - Line-targeted hash mismatch: the file changed since last read; the error provides updated line:hash references
38571
39231
 
38572
39232
  Examples:
39233
+
39234
+ Text edit (find and replace):
38573
39235
  <edit>
38574
39236
  <file_path>src/main.js</file_path>
38575
- <old_string>function oldName() {
38576
- return 42;
38577
- }</old_string>
38578
- <new_string>function newName() {
38579
- return 42;
38580
- }</new_string>
39237
+ <old_string>return false;</old_string>
39238
+ <new_string>return true;</new_string>
38581
39239
  </edit>
38582
39240
 
39241
+ Text edit with replace_all:
38583
39242
  <edit>
38584
39243
  <file_path>config.json</file_path>
38585
39244
  <old_string>"debug": false</old_string>
38586
39245
  <new_string>"debug": true</new_string>
38587
39246
  <replace_all>true</replace_all>
39247
+ </edit>
39248
+
39249
+ Symbol replace (rewrite entire function by name):
39250
+ <edit>
39251
+ <file_path>src/utils.js</file_path>
39252
+ <symbol>calculateTotal</symbol>
39253
+ <new_string>function calculateTotal(items) {
39254
+ return items.reduce((sum, item) => sum + item.price * item.quantity, 0);
39255
+ }</new_string>
39256
+ </edit>
39257
+
39258
+ Symbol insert (add new function after existing one):
39259
+ <edit>
39260
+ <file_path>src/utils.js</file_path>
39261
+ <symbol>calculateTotal</symbol>
39262
+ <position>after</position>
39263
+ <new_string>function calculateTax(total, rate) {
39264
+ return total * rate;
39265
+ }</new_string>
39266
+ </edit>
39267
+
39268
+ Line-targeted edit (replace a line):
39269
+ <edit>
39270
+ <file_path>src/main.js</file_path>
39271
+ <start_line>42</start_line>
39272
+ <new_string> return processItems(order.items);</new_string>
39273
+ </edit>
39274
+
39275
+ Line-targeted edit (replace a range of lines):
39276
+ <edit>
39277
+ <file_path>src/main.js</file_path>
39278
+ <start_line>42</start_line>
39279
+ <end_line>55</end_line>
39280
+ <new_string> // simplified implementation
39281
+ return processItems(order.items);</new_string>
39282
+ </edit>
39283
+
39284
+ Line-targeted edit with hash verification:
39285
+ <edit>
39286
+ <file_path>src/main.js</file_path>
39287
+ <start_line>42:ab</start_line>
39288
+ <end_line>55:cd</end_line>
39289
+ <new_string> return processItems(order.items);</new_string>
39290
+ </edit>
39291
+
39292
+ Line-targeted insert (add code after a line):
39293
+ <edit>
39294
+ <file_path>src/main.js</file_path>
39295
+ <start_line>42</start_line>
39296
+ <position>after</position>
39297
+ <new_string> const validated = validate(input);</new_string>
39298
+ </edit>
39299
+
39300
+ Line-targeted delete (remove lines):
39301
+ <edit>
39302
+ <file_path>src/main.js</file_path>
39303
+ <start_line>42</start_line>
39304
+ <end_line>45</end_line>
39305
+ <new_string></new_string>
38588
39306
  </edit>`;
38589
39307
  createToolDefinition = `
38590
39308
  ## create
@@ -39121,7 +39839,7 @@ function getValidParamsForTool(toolName) {
39121
39839
  };
39122
39840
  const schema = schemaMap[toolName];
39123
39841
  if (!schema) {
39124
- return ["path", "directory", "pattern", "recursive", "includeHidden", "task", "files", "autoCommits", "result"];
39842
+ return ["path", "directory", "pattern", "recursive", "includeHidden", "task", "files", "result"];
39125
39843
  }
39126
39844
  if (toolName === "attempt_completion") {
39127
39845
  return ["result"];
@@ -39242,7 +39960,6 @@ function detectUnrecognizedToolCall(xmlString, validTools) {
39242
39960
  "listSkills",
39243
39961
  "useSkill",
39244
39962
  "readImage",
39245
- "implement",
39246
39963
  "edit",
39247
39964
  "create",
39248
39965
  "delegate",
@@ -39617,6 +40334,8 @@ User: Read file inside the dependency
39617
40334
  </extract>
39618
40335
 
39619
40336
  </examples>
40337
+
40338
+ **Edit Integration:** The line numbers shown in extract output (e.g. "42 | code") can be used directly with the edit tool's start_line/end_line parameters for precise line-targeted editing. To edit inside a large function: extract it by symbol name first (e.g. "file.js#myFunction"), then use the line numbers from the output to make surgical edits with start_line/end_line.
39620
40339
  `;
39621
40340
  delegateToolDefinition = `
39622
40341
  ## delegate
@@ -39772,7 +40491,7 @@ Capabilities:
39772
40491
  `;
39773
40492
  searchDescription = "Search code in the repository. Free-form questions are accepted, but Elasticsearch-style keyword queries work best. Use this tool first for any code-related questions.";
39774
40493
  queryDescription = "Search code using ast-grep structural pattern matching. Use this tool to find specific code structures like functions, classes, or methods.";
39775
- extractDescription = "Extract code blocks from files based on file paths and optional line numbers. Use this tool to see complete context after finding relevant files.";
40494
+ extractDescription = "Extract code blocks from files based on file paths and optional line numbers. Use this tool to see complete context after finding relevant files. Line numbers from output can be used with edit start_line/end_line for precise editing.";
39776
40495
  delegateDescription = "Automatically delegate big distinct tasks to specialized probe subagents within the agentic loop. Used by AI agents to break down complex requests into focused, parallel tasks.";
39777
40496
  analyzeAllDescription = 'Answer questions that require analyzing ALL matching data in the codebase. Use for aggregate questions like "What features exist?", "List all API endpoints", "Count TODO comments". The AI automatically plans the search strategy, processes all results via map-reduce, and synthesizes a comprehensive answer. WARNING: Slower than search - only use when you need complete coverage.';
39778
40497
  DEFAULT_VALID_TOOLS = [
@@ -39787,7 +40506,6 @@ Capabilities:
39787
40506
  "useSkill",
39788
40507
  "listFiles",
39789
40508
  "searchFiles",
39790
- "implement",
39791
40509
  "bash",
39792
40510
  "task",
39793
40511
  "attempt_completion"
@@ -39912,6 +40630,7 @@ var init_vercel = __esm({
39912
40630
  init_analyzeAll();
39913
40631
  init_common2();
39914
40632
  init_error_types();
40633
+ init_hashline();
39915
40634
  CODE_SEARCH_SCHEMA = {
39916
40635
  type: "object",
39917
40636
  properties: {
@@ -39930,8 +40649,15 @@ var init_vercel = __esm({
39930
40649
  maxTokens = 2e4,
39931
40650
  debug = false,
39932
40651
  outline = false,
39933
- searchDelegate = false
40652
+ searchDelegate = false,
40653
+ hashLines = false
39934
40654
  } = options;
40655
+ const maybeAnnotate = (result) => {
40656
+ if (hashLines && typeof result === "string") {
40657
+ return annotateOutputWithHashes(result);
40658
+ }
40659
+ return result;
40660
+ };
39935
40661
  return (0, import_ai2.tool)({
39936
40662
  name: "search",
39937
40663
  description: searchDelegate ? `${searchDescription} (delegates code search to a subagent and returns extracted code blocks)` : searchDescription,
@@ -39973,7 +40699,12 @@ var init_vercel = __esm({
39973
40699
  };
39974
40700
  if (!searchDelegate) {
39975
40701
  try {
39976
- return await runRawSearch();
40702
+ const result = maybeAnnotate(await runRawSearch());
40703
+ if (options.fileTracker && typeof result === "string") {
40704
+ options.fileTracker.trackFilesFromOutput(result, options.cwd || ".").catch(() => {
40705
+ });
40706
+ }
40707
+ return result;
39977
40708
  } catch (error2) {
39978
40709
  console.error("Error executing search command:", error2);
39979
40710
  return formatErrorForAI(error2);
@@ -40016,7 +40747,12 @@ var init_vercel = __esm({
40016
40747
  if (debug) {
40017
40748
  console.error("Delegated search returned no targets; falling back to raw search");
40018
40749
  }
40019
- return await runRawSearch();
40750
+ const fallbackResult = maybeAnnotate(await runRawSearch());
40751
+ if (options.fileTracker && typeof fallbackResult === "string") {
40752
+ options.fileTracker.trackFilesFromOutput(fallbackResult, options.cwd || ".").catch(() => {
40753
+ });
40754
+ }
40755
+ return fallbackResult;
40020
40756
  }
40021
40757
  const resolutionBase = searchPaths[0] || options.cwd || ".";
40022
40758
  const resolvedTargets = targets.map((target) => resolveTargetPath(target, resolutionBase));
@@ -40031,13 +40767,18 @@ var init_vercel = __esm({
40031
40767
  const extractResult = await extract(extractOptions);
40032
40768
  if (resolutionBase && typeof extractResult === "string") {
40033
40769
  const wsPrefix = resolutionBase.endsWith("/") ? resolutionBase : resolutionBase + "/";
40034
- return extractResult.split(wsPrefix).join("");
40770
+ return maybeAnnotate(extractResult.split(wsPrefix).join(""));
40035
40771
  }
40036
- return extractResult;
40772
+ return maybeAnnotate(extractResult);
40037
40773
  } catch (error2) {
40038
40774
  console.error("Delegated search failed, falling back to raw search:", error2);
40039
40775
  try {
40040
- return await runRawSearch();
40776
+ const fallbackResult2 = maybeAnnotate(await runRawSearch());
40777
+ if (options.fileTracker && typeof fallbackResult2 === "string") {
40778
+ options.fileTracker.trackFilesFromOutput(fallbackResult2, options.cwd || ".").catch(() => {
40779
+ });
40780
+ }
40781
+ return fallbackResult2;
40041
40782
  } catch (fallbackError) {
40042
40783
  console.error("Error executing search command:", fallbackError);
40043
40784
  return formatErrorForAI(fallbackError);
@@ -40083,7 +40824,7 @@ var init_vercel = __esm({
40083
40824
  });
40084
40825
  };
40085
40826
  extractTool = (options = {}) => {
40086
- const { debug = false, outline = false } = options;
40827
+ const { debug = false, outline = false, hashLines = false } = options;
40087
40828
  return (0, import_ai2.tool)({
40088
40829
  name: "extract",
40089
40830
  description: extractDescription,
@@ -40100,6 +40841,7 @@ var init_vercel = __esm({
40100
40841
  }
40101
40842
  let tempFilePath = null;
40102
40843
  let extractOptions = { cwd: effectiveCwd };
40844
+ let extractFiles = null;
40103
40845
  if (input_content) {
40104
40846
  const { writeFileSync: writeFileSync2, unlinkSync } = await import("fs");
40105
40847
  const { join: join5 } = await import("path");
@@ -40123,13 +40865,13 @@ var init_vercel = __esm({
40123
40865
  };
40124
40866
  } else if (targets) {
40125
40867
  const parsedTargets = parseTargets(targets);
40126
- const files = parsedTargets.map((target) => resolveTargetPath(target, effectiveCwd));
40868
+ extractFiles = parsedTargets.map((target) => resolveTargetPath(target, effectiveCwd));
40127
40869
  let effectiveFormat = format2;
40128
40870
  if (outline && format2 === "outline-xml") {
40129
40871
  effectiveFormat = "xml";
40130
40872
  }
40131
40873
  extractOptions = {
40132
- files,
40874
+ files: extractFiles,
40133
40875
  cwd: effectiveCwd,
40134
40876
  allowTests: allow_tests ?? true,
40135
40877
  contextLines: context_lines,
@@ -40139,6 +40881,10 @@ var init_vercel = __esm({
40139
40881
  throw new Error("Either targets or input_content must be provided");
40140
40882
  }
40141
40883
  const results = await extract(extractOptions);
40884
+ if (options.fileTracker && extractFiles && extractFiles.length > 0) {
40885
+ options.fileTracker.trackFilesFromExtract(extractFiles, effectiveCwd).catch(() => {
40886
+ });
40887
+ }
40142
40888
  if (tempFilePath) {
40143
40889
  const { unlinkSync } = await import("fs");
40144
40890
  try {
@@ -40150,6 +40896,9 @@ var init_vercel = __esm({
40150
40896
  console.error(`Warning: Failed to remove temporary file: ${cleanupError.message}`);
40151
40897
  }
40152
40898
  }
40899
+ if (hashLines && typeof results === "string") {
40900
+ return annotateOutputWithHashes(results);
40901
+ }
40153
40902
  return results;
40154
40903
  } catch (error2) {
40155
40904
  console.error("Error executing extract command:", error2);
@@ -41497,7 +42246,7 @@ async function executeBashCommand(command, options = {}) {
41497
42246
  console.log(`[BashExecutor] Working directory: "${cwd}"`);
41498
42247
  console.log(`[BashExecutor] Timeout: ${timeout}ms`);
41499
42248
  }
41500
- return new Promise((resolve7, reject2) => {
42249
+ return new Promise((resolve8, reject2) => {
41501
42250
  const processEnv = {
41502
42251
  ...process.env,
41503
42252
  ...env
@@ -41514,7 +42263,7 @@ async function executeBashCommand(command, options = {}) {
41514
42263
  } else {
41515
42264
  const args = parseCommandForExecution(command);
41516
42265
  if (!args || args.length === 0) {
41517
- resolve7({
42266
+ resolve8({
41518
42267
  success: false,
41519
42268
  error: "Failed to parse command",
41520
42269
  stdout: "",
@@ -41599,7 +42348,7 @@ async function executeBashCommand(command, options = {}) {
41599
42348
  success = false;
41600
42349
  error2 = `Command exited with code ${code}`;
41601
42350
  }
41602
- resolve7({
42351
+ resolve8({
41603
42352
  success,
41604
42353
  error: error2,
41605
42354
  stdout: stdout.trim(),
@@ -41619,7 +42368,7 @@ async function executeBashCommand(command, options = {}) {
41619
42368
  if (debug) {
41620
42369
  console.log(`[BashExecutor] Spawn error:`, error2);
41621
42370
  }
41622
- resolve7({
42371
+ resolve8({
41623
42372
  success: false,
41624
42373
  error: `Failed to execute command: ${error2.message}`,
41625
42374
  stdout: "",
@@ -43031,14 +43780,14 @@ var require_executor = __commonJS({
43031
43780
  function asyncDone(callback) {
43032
43781
  let isInstant = false;
43033
43782
  let instant;
43034
- const p5 = new Promise((resolve7, reject2) => {
43783
+ const p5 = new Promise((resolve8, reject2) => {
43035
43784
  callback((err, result) => {
43036
43785
  if (err)
43037
43786
  reject2(err);
43038
43787
  else {
43039
43788
  isInstant = true;
43040
43789
  instant = result;
43041
- resolve7({ result });
43790
+ resolve8({ result });
43042
43791
  }
43043
43792
  });
43044
43793
  });
@@ -43061,10 +43810,10 @@ var require_executor = __commonJS({
43061
43810
  }
43062
43811
  async function execAsync4(ticks, tree, scope, context, doneOriginal, inLoopOrSwitch) {
43063
43812
  let done = doneOriginal;
43064
- const p5 = new Promise((resolve7) => {
43813
+ const p5 = new Promise((resolve8) => {
43065
43814
  done = (e5, r5) => {
43066
43815
  doneOriginal(e5, r5);
43067
- resolve7();
43816
+ resolve8();
43068
43817
  };
43069
43818
  });
43070
43819
  if (!_execNoneRecurse(ticks, tree, scope, context, done, true, inLoopOrSwitch) && utils.isLisp(tree)) {
@@ -51415,6 +52164,13 @@ function generateSandboxGlobals(options) {
51415
52164
  if (i5 < keys2.length) params[keys2[i5]] = arg;
51416
52165
  });
51417
52166
  }
52167
+ if (params.path && typeof params.path === "object") {
52168
+ const coercedPath = params.path.file_path || params.path.path || params.path.directory || params.path.filename;
52169
+ if (coercedPath && typeof coercedPath === "string") {
52170
+ logFn?.(`[${name14}] Warning: Coerced object path to string "${coercedPath}" (issue #444)`);
52171
+ params.path = coercedPath;
52172
+ }
52173
+ }
51418
52174
  const validated = schema.safeParse(params);
51419
52175
  if (!validated.success) {
51420
52176
  throw new Error(`Invalid parameters for ${name14}: ${validated.error.message}`);
@@ -51451,6 +52207,11 @@ function generateSandboxGlobals(options) {
51451
52207
  }
51452
52208
  if (llmCall) {
51453
52209
  const rawLLM = async (instruction, data3, opts = {}) => {
52210
+ const dataStr = typeof data3 === "string" ? data3 : JSON.stringify(data3);
52211
+ if (dataStr && dataStr.startsWith("ERROR:")) {
52212
+ logFn?.("[LLM] Blocked: data contains error from previous tool call");
52213
+ return "ERROR: Previous tool call failed - " + dataStr.substring(0, 200);
52214
+ }
51454
52215
  const result = await llmCall(instruction, data3, opts);
51455
52216
  if (opts.schema && typeof result === "string") {
51456
52217
  try {
@@ -51816,33 +52577,31 @@ var init_runtime = __esm({
51816
52577
  }
51817
52578
  });
51818
52579
 
51819
- // node_modules/balanced-match/index.js
51820
- var require_balanced_match = __commonJS({
51821
- "node_modules/balanced-match/index.js"(exports2, module2) {
51822
- "use strict";
51823
- module2.exports = balanced;
51824
- function balanced(a5, b5, str) {
51825
- if (a5 instanceof RegExp) a5 = maybeMatch(a5, str);
51826
- if (b5 instanceof RegExp) b5 = maybeMatch(b5, str);
51827
- var r5 = range2(a5, b5, str);
52580
+ // node_modules/balanced-match/dist/esm/index.js
52581
+ var balanced, maybeMatch, range2;
52582
+ var init_esm = __esm({
52583
+ "node_modules/balanced-match/dist/esm/index.js"() {
52584
+ balanced = (a5, b5, str) => {
52585
+ const ma = a5 instanceof RegExp ? maybeMatch(a5, str) : a5;
52586
+ const mb = b5 instanceof RegExp ? maybeMatch(b5, str) : b5;
52587
+ const r5 = ma !== null && mb != null && range2(ma, mb, str);
51828
52588
  return r5 && {
51829
52589
  start: r5[0],
51830
52590
  end: r5[1],
51831
52591
  pre: str.slice(0, r5[0]),
51832
- body: str.slice(r5[0] + a5.length, r5[1]),
51833
- post: str.slice(r5[1] + b5.length)
52592
+ body: str.slice(r5[0] + ma.length, r5[1]),
52593
+ post: str.slice(r5[1] + mb.length)
51834
52594
  };
51835
- }
51836
- function maybeMatch(reg, str) {
51837
- var m5 = str.match(reg);
52595
+ };
52596
+ maybeMatch = (reg, str) => {
52597
+ const m5 = str.match(reg);
51838
52598
  return m5 ? m5[0] : null;
51839
- }
51840
- balanced.range = range2;
51841
- function range2(a5, b5, str) {
51842
- var begs, beg, left, right, result;
51843
- var ai = str.indexOf(a5);
51844
- var bi = str.indexOf(b5, ai + 1);
51845
- var i5 = ai;
52599
+ };
52600
+ range2 = (a5, b5, str) => {
52601
+ let begs, beg, left, right = void 0, result;
52602
+ let ai = str.indexOf(a5);
52603
+ let bi = str.indexOf(b5, ai + 1);
52604
+ let i5 = ai;
51846
52605
  if (ai >= 0 && bi > 0) {
51847
52606
  if (a5 === b5) {
51848
52607
  return [ai, bi];
@@ -51850,14 +52609,16 @@ var require_balanced_match = __commonJS({
51850
52609
  begs = [];
51851
52610
  left = str.length;
51852
52611
  while (i5 >= 0 && !result) {
51853
- if (i5 == ai) {
52612
+ if (i5 === ai) {
51854
52613
  begs.push(i5);
51855
52614
  ai = str.indexOf(a5, i5 + 1);
51856
- } else if (begs.length == 1) {
51857
- result = [begs.pop(), bi];
52615
+ } else if (begs.length === 1) {
52616
+ const r5 = begs.pop();
52617
+ if (r5 !== void 0)
52618
+ result = [r5, bi];
51858
52619
  } else {
51859
52620
  beg = begs.pop();
51860
- if (beg < left) {
52621
+ if (beg !== void 0 && beg < left) {
51861
52622
  left = beg;
51862
52623
  right = bi;
51863
52624
  }
@@ -51865,163 +52626,179 @@ var require_balanced_match = __commonJS({
51865
52626
  }
51866
52627
  i5 = ai < bi && ai >= 0 ? ai : bi;
51867
52628
  }
51868
- if (begs.length) {
52629
+ if (begs.length && right !== void 0) {
51869
52630
  result = [left, right];
51870
52631
  }
51871
52632
  }
51872
52633
  return result;
51873
- }
52634
+ };
51874
52635
  }
51875
52636
  });
51876
52637
 
51877
- // node_modules/brace-expansion/index.js
51878
- var require_brace_expansion = __commonJS({
51879
- "node_modules/brace-expansion/index.js"(exports2, module2) {
51880
- var balanced = require_balanced_match();
51881
- module2.exports = expandTop;
51882
- var escSlash = "\0SLASH" + Math.random() + "\0";
51883
- var escOpen = "\0OPEN" + Math.random() + "\0";
51884
- var escClose = "\0CLOSE" + Math.random() + "\0";
51885
- var escComma = "\0COMMA" + Math.random() + "\0";
51886
- var escPeriod = "\0PERIOD" + Math.random() + "\0";
51887
- function numeric(str) {
51888
- return parseInt(str, 10) == str ? parseInt(str, 10) : str.charCodeAt(0);
51889
- }
51890
- function escapeBraces(str) {
51891
- return str.split("\\\\").join(escSlash).split("\\{").join(escOpen).split("\\}").join(escClose).split("\\,").join(escComma).split("\\.").join(escPeriod);
51892
- }
51893
- function unescapeBraces(str) {
51894
- return str.split(escSlash).join("\\").split(escOpen).join("{").split(escClose).join("}").split(escComma).join(",").split(escPeriod).join(".");
51895
- }
51896
- function parseCommaParts(str) {
51897
- if (!str)
51898
- return [""];
51899
- var parts = [];
51900
- var m5 = balanced("{", "}", str);
51901
- if (!m5)
51902
- return str.split(",");
51903
- var pre = m5.pre;
51904
- var body = m5.body;
51905
- var post = m5.post;
51906
- var p5 = pre.split(",");
51907
- p5[p5.length - 1] += "{" + body + "}";
51908
- var postParts = parseCommaParts(post);
51909
- if (post.length) {
51910
- p5[p5.length - 1] += postParts.shift();
51911
- p5.push.apply(p5, postParts);
51912
- }
51913
- parts.push.apply(parts, p5);
51914
- return parts;
51915
- }
51916
- function expandTop(str) {
51917
- if (!str)
51918
- return [];
51919
- if (str.substr(0, 2) === "{}") {
51920
- str = "\\{\\}" + str.substr(2);
51921
- }
51922
- return expand2(escapeBraces(str), true).map(unescapeBraces);
51923
- }
51924
- function embrace(str) {
51925
- return "{" + str + "}";
51926
- }
51927
- function isPadded(el) {
51928
- return /^-?0\d/.test(el);
51929
- }
51930
- function lte(i5, y2) {
51931
- return i5 <= y2;
51932
- }
51933
- function gte(i5, y2) {
51934
- return i5 >= y2;
52638
+ // node_modules/brace-expansion/dist/esm/index.js
52639
+ function numeric(str) {
52640
+ return !isNaN(str) ? parseInt(str, 10) : str.charCodeAt(0);
52641
+ }
52642
+ function escapeBraces(str) {
52643
+ return str.replace(slashPattern, escSlash).replace(openPattern, escOpen).replace(closePattern, escClose).replace(commaPattern, escComma).replace(periodPattern, escPeriod);
52644
+ }
52645
+ function unescapeBraces(str) {
52646
+ return str.replace(escSlashPattern, "\\").replace(escOpenPattern, "{").replace(escClosePattern, "}").replace(escCommaPattern, ",").replace(escPeriodPattern, ".");
52647
+ }
52648
+ function parseCommaParts(str) {
52649
+ if (!str) {
52650
+ return [""];
52651
+ }
52652
+ const parts = [];
52653
+ const m5 = balanced("{", "}", str);
52654
+ if (!m5) {
52655
+ return str.split(",");
52656
+ }
52657
+ const { pre, body, post } = m5;
52658
+ const p5 = pre.split(",");
52659
+ p5[p5.length - 1] += "{" + body + "}";
52660
+ const postParts = parseCommaParts(post);
52661
+ if (post.length) {
52662
+ ;
52663
+ p5[p5.length - 1] += postParts.shift();
52664
+ p5.push.apply(p5, postParts);
52665
+ }
52666
+ parts.push.apply(parts, p5);
52667
+ return parts;
52668
+ }
52669
+ function expand(str, options = {}) {
52670
+ if (!str) {
52671
+ return [];
52672
+ }
52673
+ const { max = EXPANSION_MAX } = options;
52674
+ if (str.slice(0, 2) === "{}") {
52675
+ str = "\\{\\}" + str.slice(2);
52676
+ }
52677
+ return expand_(escapeBraces(str), max, true).map(unescapeBraces);
52678
+ }
52679
+ function embrace(str) {
52680
+ return "{" + str + "}";
52681
+ }
52682
+ function isPadded(el) {
52683
+ return /^-?0\d/.test(el);
52684
+ }
52685
+ function lte(i5, y2) {
52686
+ return i5 <= y2;
52687
+ }
52688
+ function gte(i5, y2) {
52689
+ return i5 >= y2;
52690
+ }
52691
+ function expand_(str, max, isTop) {
52692
+ const expansions = [];
52693
+ const m5 = balanced("{", "}", str);
52694
+ if (!m5)
52695
+ return [str];
52696
+ const pre = m5.pre;
52697
+ const post = m5.post.length ? expand_(m5.post, max, false) : [""];
52698
+ if (/\$$/.test(m5.pre)) {
52699
+ for (let k5 = 0; k5 < post.length && k5 < max; k5++) {
52700
+ const expansion = pre + "{" + m5.body + "}" + post[k5];
52701
+ expansions.push(expansion);
51935
52702
  }
51936
- function expand2(str, isTop) {
51937
- var expansions = [];
51938
- var m5 = balanced("{", "}", str);
51939
- if (!m5) return [str];
51940
- var pre = m5.pre;
51941
- var post = m5.post.length ? expand2(m5.post, false) : [""];
51942
- if (/\$$/.test(m5.pre)) {
51943
- for (var k5 = 0; k5 < post.length; k5++) {
51944
- var expansion = pre + "{" + m5.body + "}" + post[k5];
51945
- expansions.push(expansion);
51946
- }
51947
- } else {
51948
- var isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m5.body);
51949
- var isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m5.body);
51950
- var isSequence = isNumericSequence || isAlphaSequence;
51951
- var isOptions = m5.body.indexOf(",") >= 0;
51952
- if (!isSequence && !isOptions) {
51953
- if (m5.post.match(/,(?!,).*\}/)) {
51954
- str = m5.pre + "{" + m5.body + escClose + m5.post;
51955
- return expand2(str);
51956
- }
51957
- return [str];
51958
- }
51959
- var n5;
51960
- if (isSequence) {
51961
- n5 = m5.body.split(/\.\./);
51962
- } else {
51963
- n5 = parseCommaParts(m5.body);
51964
- if (n5.length === 1) {
51965
- n5 = expand2(n5[0], false).map(embrace);
51966
- if (n5.length === 1) {
51967
- return post.map(function(p5) {
51968
- return m5.pre + n5[0] + p5;
51969
- });
51970
- }
52703
+ } else {
52704
+ const isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m5.body);
52705
+ const isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m5.body);
52706
+ const isSequence = isNumericSequence || isAlphaSequence;
52707
+ const isOptions = m5.body.indexOf(",") >= 0;
52708
+ if (!isSequence && !isOptions) {
52709
+ if (m5.post.match(/,(?!,).*\}/)) {
52710
+ str = m5.pre + "{" + m5.body + escClose + m5.post;
52711
+ return expand_(str, max, true);
52712
+ }
52713
+ return [str];
52714
+ }
52715
+ let n5;
52716
+ if (isSequence) {
52717
+ n5 = m5.body.split(/\.\./);
52718
+ } else {
52719
+ n5 = parseCommaParts(m5.body);
52720
+ if (n5.length === 1 && n5[0] !== void 0) {
52721
+ n5 = expand_(n5[0], max, false).map(embrace);
52722
+ if (n5.length === 1) {
52723
+ return post.map((p5) => m5.pre + n5[0] + p5);
52724
+ }
52725
+ }
52726
+ }
52727
+ let N;
52728
+ if (isSequence && n5[0] !== void 0 && n5[1] !== void 0) {
52729
+ const x5 = numeric(n5[0]);
52730
+ const y2 = numeric(n5[1]);
52731
+ const width = Math.max(n5[0].length, n5[1].length);
52732
+ let incr = n5.length === 3 && n5[2] !== void 0 ? Math.abs(numeric(n5[2])) : 1;
52733
+ let test = lte;
52734
+ const reverse = y2 < x5;
52735
+ if (reverse) {
52736
+ incr *= -1;
52737
+ test = gte;
52738
+ }
52739
+ const pad = n5.some(isPadded);
52740
+ N = [];
52741
+ for (let i5 = x5; test(i5, y2); i5 += incr) {
52742
+ let c5;
52743
+ if (isAlphaSequence) {
52744
+ c5 = String.fromCharCode(i5);
52745
+ if (c5 === "\\") {
52746
+ c5 = "";
51971
52747
  }
51972
- }
51973
- var N;
51974
- if (isSequence) {
51975
- var x5 = numeric(n5[0]);
51976
- var y2 = numeric(n5[1]);
51977
- var width = Math.max(n5[0].length, n5[1].length);
51978
- var incr = n5.length == 3 ? Math.abs(numeric(n5[2])) : 1;
51979
- var test = lte;
51980
- var reverse = y2 < x5;
51981
- if (reverse) {
51982
- incr *= -1;
51983
- test = gte;
51984
- }
51985
- var pad = n5.some(isPadded);
51986
- N = [];
51987
- for (var i5 = x5; test(i5, y2); i5 += incr) {
51988
- var c5;
51989
- if (isAlphaSequence) {
51990
- c5 = String.fromCharCode(i5);
51991
- if (c5 === "\\")
51992
- c5 = "";
51993
- } else {
51994
- c5 = String(i5);
51995
- if (pad) {
51996
- var need = width - c5.length;
51997
- if (need > 0) {
51998
- var z2 = new Array(need + 1).join("0");
51999
- if (i5 < 0)
52000
- c5 = "-" + z2 + c5.slice(1);
52001
- else
52002
- c5 = z2 + c5;
52003
- }
52748
+ } else {
52749
+ c5 = String(i5);
52750
+ if (pad) {
52751
+ const need = width - c5.length;
52752
+ if (need > 0) {
52753
+ const z2 = new Array(need + 1).join("0");
52754
+ if (i5 < 0) {
52755
+ c5 = "-" + z2 + c5.slice(1);
52756
+ } else {
52757
+ c5 = z2 + c5;
52004
52758
  }
52005
52759
  }
52006
- N.push(c5);
52007
- }
52008
- } else {
52009
- N = [];
52010
- for (var j5 = 0; j5 < n5.length; j5++) {
52011
- N.push.apply(N, expand2(n5[j5], false));
52012
52760
  }
52013
52761
  }
52014
- for (var j5 = 0; j5 < N.length; j5++) {
52015
- for (var k5 = 0; k5 < post.length; k5++) {
52016
- var expansion = pre + N[j5] + post[k5];
52017
- if (!isTop || isSequence || expansion)
52018
- expansions.push(expansion);
52019
- }
52762
+ N.push(c5);
52763
+ }
52764
+ } else {
52765
+ N = [];
52766
+ for (let j5 = 0; j5 < n5.length; j5++) {
52767
+ N.push.apply(N, expand_(n5[j5], max, false));
52768
+ }
52769
+ }
52770
+ for (let j5 = 0; j5 < N.length; j5++) {
52771
+ for (let k5 = 0; k5 < post.length && expansions.length < max; k5++) {
52772
+ const expansion = pre + N[j5] + post[k5];
52773
+ if (!isTop || isSequence || expansion) {
52774
+ expansions.push(expansion);
52020
52775
  }
52021
52776
  }
52022
- return expansions;
52023
52777
  }
52024
52778
  }
52779
+ return expansions;
52780
+ }
52781
+ var escSlash, escOpen, escClose, escComma, escPeriod, escSlashPattern, escOpenPattern, escClosePattern, escCommaPattern, escPeriodPattern, slashPattern, openPattern, closePattern, commaPattern, periodPattern, EXPANSION_MAX;
52782
+ var init_esm2 = __esm({
52783
+ "node_modules/brace-expansion/dist/esm/index.js"() {
52784
+ init_esm();
52785
+ escSlash = "\0SLASH" + Math.random() + "\0";
52786
+ escOpen = "\0OPEN" + Math.random() + "\0";
52787
+ escClose = "\0CLOSE" + Math.random() + "\0";
52788
+ escComma = "\0COMMA" + Math.random() + "\0";
52789
+ escPeriod = "\0PERIOD" + Math.random() + "\0";
52790
+ escSlashPattern = new RegExp(escSlash, "g");
52791
+ escOpenPattern = new RegExp(escOpen, "g");
52792
+ escClosePattern = new RegExp(escClose, "g");
52793
+ escCommaPattern = new RegExp(escComma, "g");
52794
+ escPeriodPattern = new RegExp(escPeriod, "g");
52795
+ slashPattern = /\\\\/g;
52796
+ openPattern = /\\{/g;
52797
+ closePattern = /\\}/g;
52798
+ commaPattern = /\\,/g;
52799
+ periodPattern = /\\./g;
52800
+ EXPANSION_MAX = 1e5;
52801
+ }
52025
52802
  });
52026
52803
 
52027
52804
  // node_modules/minimatch/dist/esm/assert-valid-pattern.js
@@ -52604,11 +53381,13 @@ var init_ast = __esm({
52604
53381
  let escaping = false;
52605
53382
  let re = "";
52606
53383
  let uflag = false;
53384
+ let inStar = false;
52607
53385
  for (let i5 = 0; i5 < glob2.length; i5++) {
52608
53386
  const c5 = glob2.charAt(i5);
52609
53387
  if (escaping) {
52610
53388
  escaping = false;
52611
53389
  re += (reSpecials.has(c5) ? "\\" : "") + c5;
53390
+ inStar = false;
52612
53391
  continue;
52613
53392
  }
52614
53393
  if (c5 === "\\") {
@@ -52626,16 +53405,19 @@ var init_ast = __esm({
52626
53405
  uflag = uflag || needUflag;
52627
53406
  i5 += consumed - 1;
52628
53407
  hasMagic2 = hasMagic2 || magic;
53408
+ inStar = false;
52629
53409
  continue;
52630
53410
  }
52631
53411
  }
52632
53412
  if (c5 === "*") {
52633
- if (noEmpty && glob2 === "*")
52634
- re += starNoEmpty;
52635
- else
52636
- re += star;
53413
+ if (inStar)
53414
+ continue;
53415
+ inStar = true;
53416
+ re += noEmpty && /^[*]+$/.test(glob2) ? starNoEmpty : star;
52637
53417
  hasMagic2 = true;
52638
53418
  continue;
53419
+ } else {
53420
+ inStar = false;
52639
53421
  }
52640
53422
  if (c5 === "?") {
52641
53423
  re += qmark;
@@ -52661,10 +53443,10 @@ var init_escape = __esm({
52661
53443
  });
52662
53444
 
52663
53445
  // node_modules/minimatch/dist/esm/index.js
52664
- var import_brace_expansion, minimatch, starDotExtRE, starDotExtTest, starDotExtTestDot, starDotExtTestNocase, starDotExtTestNocaseDot, starDotStarRE, starDotStarTest, starDotStarTestDot, dotStarRE, dotStarTest, starRE, starTest, starTestDot, qmarksRE, qmarksTestNocase, qmarksTestNocaseDot, qmarksTestDot, qmarksTest, qmarksTestNoExt, qmarksTestNoExtDot, defaultPlatform, path5, sep3, GLOBSTAR, qmark2, star2, twoStarDot, twoStarNoDot, filter, ext, defaults, braceExpand, makeRe, match, globMagic, regExpEscape2, Minimatch;
52665
- var init_esm = __esm({
53446
+ var minimatch, starDotExtRE, starDotExtTest, starDotExtTestDot, starDotExtTestNocase, starDotExtTestNocaseDot, starDotStarRE, starDotStarTest, starDotStarTestDot, dotStarRE, dotStarTest, starRE, starTest, starTestDot, qmarksRE, qmarksTestNocase, qmarksTestNocaseDot, qmarksTestDot, qmarksTest, qmarksTestNoExt, qmarksTestNoExtDot, defaultPlatform, path5, sep3, GLOBSTAR, qmark2, star2, twoStarDot, twoStarNoDot, filter, ext, defaults, braceExpand, makeRe, match, globMagic, regExpEscape2, Minimatch;
53447
+ var init_esm3 = __esm({
52666
53448
  "node_modules/minimatch/dist/esm/index.js"() {
52667
- import_brace_expansion = __toESM(require_brace_expansion(), 1);
53449
+ init_esm2();
52668
53450
  init_assert_valid_pattern();
52669
53451
  init_ast();
52670
53452
  init_escape();
@@ -52787,7 +53569,7 @@ var init_esm = __esm({
52787
53569
  if (options.nobrace || !/\{(?:(?!\{).)*\}/.test(pattern)) {
52788
53570
  return [pattern];
52789
53571
  }
52790
- return (0, import_brace_expansion.default)(pattern);
53572
+ return expand(pattern);
52791
53573
  };
52792
53574
  minimatch.braceExpand = braceExpand;
52793
53575
  makeRe = (pattern, options = {}) => new Minimatch(pattern, options).makeRe();
@@ -53393,7 +54175,7 @@ var init_esm = __esm({
53393
54175
 
53394
54176
  // node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.js
53395
54177
  var perf, warned, PROCESS, emitWarning, AC, AS, shouldWarn, TYPE, isPosInt, getUintArray, ZeroArray, Stack, LRUCache;
53396
- var init_esm2 = __esm({
54178
+ var init_esm4 = __esm({
53397
54179
  "node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.js"() {
53398
54180
  perf = typeof performance === "object" && performance && typeof performance.now === "function" ? performance : Date;
53399
54181
  warned = /* @__PURE__ */ new Set();
@@ -54767,7 +55549,7 @@ var init_esm2 = __esm({
54767
55549
 
54768
55550
  // node_modules/minipass/dist/esm/index.js
54769
55551
  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;
54770
- var init_esm3 = __esm({
55552
+ var init_esm5 = __esm({
54771
55553
  "node_modules/minipass/dist/esm/index.js"() {
54772
55554
  import_node_events = require("node:events");
54773
55555
  import_node_stream = __toESM(require("node:stream"), 1);
@@ -55497,10 +56279,10 @@ var init_esm3 = __esm({
55497
56279
  * Return a void Promise that resolves once the stream ends.
55498
56280
  */
55499
56281
  async promise() {
55500
- return new Promise((resolve7, reject2) => {
56282
+ return new Promise((resolve8, reject2) => {
55501
56283
  this.on(DESTROYED, () => reject2(new Error("stream destroyed")));
55502
56284
  this.on("error", (er) => reject2(er));
55503
- this.on("end", () => resolve7());
56285
+ this.on("end", () => resolve8());
55504
56286
  });
55505
56287
  }
55506
56288
  /**
@@ -55524,7 +56306,7 @@ var init_esm3 = __esm({
55524
56306
  return Promise.resolve({ done: false, value: res });
55525
56307
  if (this[EOF])
55526
56308
  return stop();
55527
- let resolve7;
56309
+ let resolve8;
55528
56310
  let reject2;
55529
56311
  const onerr = (er) => {
55530
56312
  this.off("data", ondata);
@@ -55538,19 +56320,19 @@ var init_esm3 = __esm({
55538
56320
  this.off("end", onend);
55539
56321
  this.off(DESTROYED, ondestroy);
55540
56322
  this.pause();
55541
- resolve7({ value, done: !!this[EOF] });
56323
+ resolve8({ value, done: !!this[EOF] });
55542
56324
  };
55543
56325
  const onend = () => {
55544
56326
  this.off("error", onerr);
55545
56327
  this.off("data", ondata);
55546
56328
  this.off(DESTROYED, ondestroy);
55547
56329
  stop();
55548
- resolve7({ done: true, value: void 0 });
56330
+ resolve8({ done: true, value: void 0 });
55549
56331
  };
55550
56332
  const ondestroy = () => onerr(new Error("stream destroyed"));
55551
56333
  return new Promise((res2, rej) => {
55552
56334
  reject2 = rej;
55553
- resolve7 = res2;
56335
+ resolve8 = res2;
55554
56336
  this.once(DESTROYED, ondestroy);
55555
56337
  this.once("error", onerr);
55556
56338
  this.once("end", onend);
@@ -55654,15 +56436,15 @@ var init_esm3 = __esm({
55654
56436
 
55655
56437
  // node_modules/path-scurry/dist/esm/index.js
55656
56438
  var import_node_path, import_node_url, import_fs7, actualFS, import_promises, realpathSync2, defaultFS, fsFromOption, uncDriveRegexp, uncToDrive, eitherSep, UNKNOWN, IFIFO, IFCHR, IFDIR, IFBLK, IFREG, IFLNK, IFSOCK, IFMT, IFMT_UNKNOWN, READDIR_CALLED, LSTAT_CALLED, ENOTDIR, ENOENT, ENOREADLINK, ENOREALPATH, ENOCHILD, TYPEMASK, entToType, normalizeCache, normalize, normalizeNocaseCache, normalizeNocase, ResolveCache, ChildrenCache, setAsCwd, PathBase, PathWin32, PathPosix, PathScurryBase, PathScurryWin32, PathScurryPosix, PathScurryDarwin, Path, PathScurry;
55657
- var init_esm4 = __esm({
56439
+ var init_esm6 = __esm({
55658
56440
  "node_modules/path-scurry/dist/esm/index.js"() {
55659
- init_esm2();
56441
+ init_esm4();
55660
56442
  import_node_path = require("node:path");
55661
56443
  import_node_url = require("node:url");
55662
56444
  import_fs7 = require("fs");
55663
56445
  actualFS = __toESM(require("node:fs"), 1);
55664
56446
  import_promises = require("node:fs/promises");
55665
- init_esm3();
56447
+ init_esm5();
55666
56448
  realpathSync2 = import_fs7.realpathSync.native;
55667
56449
  defaultFS = {
55668
56450
  lstatSync: import_fs7.lstatSync,
@@ -56534,9 +57316,9 @@ var init_esm4 = __esm({
56534
57316
  if (this.#asyncReaddirInFlight) {
56535
57317
  await this.#asyncReaddirInFlight;
56536
57318
  } else {
56537
- let resolve7 = () => {
57319
+ let resolve8 = () => {
56538
57320
  };
56539
- this.#asyncReaddirInFlight = new Promise((res) => resolve7 = res);
57321
+ this.#asyncReaddirInFlight = new Promise((res) => resolve8 = res);
56540
57322
  try {
56541
57323
  for (const e5 of await this.#fs.promises.readdir(fullpath, {
56542
57324
  withFileTypes: true
@@ -56549,7 +57331,7 @@ var init_esm4 = __esm({
56549
57331
  children.provisional = 0;
56550
57332
  }
56551
57333
  this.#asyncReaddirInFlight = void 0;
56552
- resolve7();
57334
+ resolve8();
56553
57335
  }
56554
57336
  return children.slice(0, children.provisional);
56555
57337
  }
@@ -57392,7 +58174,7 @@ var init_esm4 = __esm({
57392
58174
  var isPatternList, isGlobList, Pattern;
57393
58175
  var init_pattern = __esm({
57394
58176
  "node_modules/glob/dist/esm/pattern.js"() {
57395
- init_esm();
58177
+ init_esm3();
57396
58178
  isPatternList = (pl) => pl.length >= 1;
57397
58179
  isGlobList = (gl) => gl.length >= 1;
57398
58180
  Pattern = class _Pattern {
@@ -57563,7 +58345,7 @@ var init_pattern = __esm({
57563
58345
  var defaultPlatform2, Ignore;
57564
58346
  var init_ignore = __esm({
57565
58347
  "node_modules/glob/dist/esm/ignore.js"() {
57566
- init_esm();
58348
+ init_esm3();
57567
58349
  init_pattern();
57568
58350
  defaultPlatform2 = typeof process === "object" && process && typeof process.platform === "string" ? process.platform : "linux";
57569
58351
  Ignore = class {
@@ -57657,7 +58439,7 @@ var init_ignore = __esm({
57657
58439
  var HasWalkedCache, MatchRecord, SubWalks, Processor;
57658
58440
  var init_processor = __esm({
57659
58441
  "node_modules/glob/dist/esm/processor.js"() {
57660
- init_esm();
58442
+ init_esm3();
57661
58443
  HasWalkedCache = class _HasWalkedCache {
57662
58444
  store;
57663
58445
  constructor(store = /* @__PURE__ */ new Map()) {
@@ -57884,7 +58666,7 @@ var init_processor = __esm({
57884
58666
  var makeIgnore, GlobUtil, GlobWalker, GlobStream;
57885
58667
  var init_walker = __esm({
57886
58668
  "node_modules/glob/dist/esm/walker.js"() {
57887
- init_esm3();
58669
+ init_esm5();
57888
58670
  init_ignore();
57889
58671
  init_processor();
57890
58672
  makeIgnore = (ignore2, opts) => typeof ignore2 === "string" ? new Ignore([ignore2], opts) : Array.isArray(ignore2) ? new Ignore(ignore2, opts) : ignore2;
@@ -58219,9 +59001,9 @@ var init_walker = __esm({
58219
59001
  var import_node_url2, defaultPlatform3, Glob;
58220
59002
  var init_glob = __esm({
58221
59003
  "node_modules/glob/dist/esm/glob.js"() {
58222
- init_esm();
59004
+ init_esm3();
58223
59005
  import_node_url2 = require("node:url");
58224
- init_esm4();
59006
+ init_esm6();
58225
59007
  init_pattern();
58226
59008
  init_walker();
58227
59009
  defaultPlatform3 = typeof process === "object" && process && typeof process.platform === "string" ? process.platform : "linux";
@@ -58429,7 +59211,7 @@ var init_glob = __esm({
58429
59211
  var hasMagic;
58430
59212
  var init_has_magic = __esm({
58431
59213
  "node_modules/glob/dist/esm/has-magic.js"() {
58432
- init_esm();
59214
+ init_esm3();
58433
59215
  hasMagic = (pattern, options = {}) => {
58434
59216
  if (!Array.isArray(pattern)) {
58435
59217
  pattern = [pattern];
@@ -58463,12 +59245,12 @@ function globIterate(pattern, options = {}) {
58463
59245
  return new Glob(pattern, options).iterate();
58464
59246
  }
58465
59247
  var streamSync, stream, iterateSync, iterate, sync, glob;
58466
- var init_esm5 = __esm({
59248
+ var init_esm7 = __esm({
58467
59249
  "node_modules/glob/dist/esm/index.js"() {
58468
- init_esm();
59250
+ init_esm3();
58469
59251
  init_glob();
58470
59252
  init_has_magic();
58471
- init_esm();
59253
+ init_esm3();
58472
59254
  init_glob();
58473
59255
  init_has_magic();
58474
59256
  init_ignore();
@@ -58804,6 +59586,7 @@ ${lastError}
58804
59586
 
58805
59587
  RULES REMINDER:
58806
59588
  - search(query) is KEYWORD SEARCH \u2014 pass a search query, NOT a filename. Use extract(filepath) to read file contents.
59589
+ - search(query, path) \u2014 the path argument must be a STRING, not an object. Use field.file_path, not field.
58807
59590
  - search() returns up to 20K tokens by default. Use search(query, path, {maxTokens: null}) for unlimited, or searchAll(query) to auto-paginate ALL results.
58808
59591
  - search(), searchAll(), query(), extract(), listFiles(), bash() all return STRINGS, not arrays.
58809
59592
  - Use chunk(stringData) to split a string into an array of chunks.
@@ -58812,7 +59595,8 @@ RULES REMINDER:
58812
59595
  - Do NOT define helper functions that call tools \u2014 write logic inline.
58813
59596
  - Do NOT use async/await, template literals, or shorthand properties.
58814
59597
  - Do NOT use regex literals (/pattern/) \u2014 use String methods like indexOf, includes, startsWith instead.
58815
- - String concatenation with +, not template literals.`;
59598
+ - String concatenation with +, not template literals.
59599
+ - IMPORTANT: If a tool returns "ERROR: ...", do NOT pass that error string to LLM() \u2014 handle or skip it.`;
58816
59600
  const fixedCode = await llmCallFn(fixPrompt, "", { maxTokens: 4e3, temperature: 0.2 });
58817
59601
  currentCode = stripCodeWrapping(fixedCode);
58818
59602
  planSpan?.addEvent?.("dsl.self_heal_complete", {
@@ -59426,7 +60210,7 @@ var init_executePlan = __esm({
59426
60210
  init_query();
59427
60211
  init_extract();
59428
60212
  init_delegate();
59429
- init_esm5();
60213
+ init_esm7();
59430
60214
  init_bash();
59431
60215
  RAW_OUTPUT_START = "<<<RAW_OUTPUT>>>";
59432
60216
  RAW_OUTPUT_END = "<<<END_RAW_OUTPUT>>>";
@@ -59698,13 +60482,271 @@ var init_file_lister = __esm({
59698
60482
  }
59699
60483
  });
59700
60484
 
60485
+ // src/tools/fileTracker.js
60486
+ function computeContentHash(content) {
60487
+ const normalized = (content || "").split("\n").map((l5) => l5.trimEnd()).join("\n");
60488
+ return (0, import_crypto3.createHash)("sha256").update(normalized).digest("hex").slice(0, 16);
60489
+ }
60490
+ function extractFilePath(target) {
60491
+ const hashIdx = target.indexOf("#");
60492
+ if (hashIdx !== -1) {
60493
+ return target.slice(0, hashIdx);
60494
+ }
60495
+ const colonIdx = target.lastIndexOf(":");
60496
+ if (colonIdx !== -1) {
60497
+ const after = target.slice(colonIdx + 1);
60498
+ if (/^\d+(-\d+)?$/.test(after)) {
60499
+ return target.slice(0, colonIdx);
60500
+ }
60501
+ }
60502
+ return target;
60503
+ }
60504
+ function extractSymbolName(target) {
60505
+ const hashIdx = target.indexOf("#");
60506
+ if (hashIdx !== -1) {
60507
+ const symbol15 = target.slice(hashIdx + 1);
60508
+ return symbol15 || null;
60509
+ }
60510
+ return null;
60511
+ }
60512
+ function parseFilePathsFromOutput(output) {
60513
+ const paths = [];
60514
+ const regex = /^(?:File:\s+|---\s+)([^\s].*?)(?:\s+---)?$/gm;
60515
+ let match2;
60516
+ while ((match2 = regex.exec(output)) !== null) {
60517
+ const path9 = match2[1].trim();
60518
+ if (path9 && !path9.startsWith("Results") && !path9.startsWith("Page") && (path9.includes("/") || path9.includes(".") || path9.includes("\\"))) {
60519
+ paths.push(path9);
60520
+ }
60521
+ }
60522
+ return paths;
60523
+ }
60524
+ var import_crypto3, import_path10, FileTracker;
60525
+ var init_fileTracker = __esm({
60526
+ "src/tools/fileTracker.js"() {
60527
+ "use strict";
60528
+ import_crypto3 = require("crypto");
60529
+ import_path10 = require("path");
60530
+ init_symbolEdit();
60531
+ FileTracker = class {
60532
+ /**
60533
+ * @param {Object} [options]
60534
+ * @param {boolean} [options.debug=false] - Enable debug logging
60535
+ */
60536
+ constructor(options = {}) {
60537
+ this.debug = options.debug || false;
60538
+ this._seenFiles = /* @__PURE__ */ new Set();
60539
+ this._contentRecords = /* @__PURE__ */ new Map();
60540
+ }
60541
+ /**
60542
+ * Mark a file as "seen" — the LLM has read its content.
60543
+ * @param {string} resolvedPath - Absolute path to the file
60544
+ */
60545
+ markFileSeen(resolvedPath2) {
60546
+ this._seenFiles.add(resolvedPath2);
60547
+ if (this.debug) {
60548
+ console.error(`[FileTracker] Marked as seen: ${resolvedPath2}`);
60549
+ }
60550
+ }
60551
+ /**
60552
+ * Check if a file has been seen in this session.
60553
+ * @param {string} resolvedPath - Absolute path to the file
60554
+ * @returns {boolean}
60555
+ */
60556
+ isFileSeen(resolvedPath2) {
60557
+ return this._seenFiles.has(resolvedPath2);
60558
+ }
60559
+ /**
60560
+ * Store a content hash for a symbol in a file.
60561
+ * @param {string} resolvedPath - Absolute path to the file
60562
+ * @param {string} symbolName - Symbol name (e.g. "calculateTotal")
60563
+ * @param {string} code - The symbol's source code
60564
+ * @param {number} startLine - 1-indexed start line
60565
+ * @param {number} endLine - 1-indexed end line
60566
+ * @param {string} [source='extract'] - How the content was obtained
60567
+ */
60568
+ trackSymbolContent(resolvedPath2, symbolName, code, startLine, endLine, source = "extract") {
60569
+ const key = `${resolvedPath2}#${symbolName}`;
60570
+ const contentHash = computeContentHash(code);
60571
+ this._contentRecords.set(key, {
60572
+ contentHash,
60573
+ startLine,
60574
+ endLine,
60575
+ symbolName,
60576
+ source,
60577
+ timestamp: Date.now()
60578
+ });
60579
+ if (this.debug) {
60580
+ console.error(`[FileTracker] Tracked symbol ${key} (hash: ${contentHash}, lines ${startLine}-${endLine})`);
60581
+ }
60582
+ }
60583
+ /**
60584
+ * Look up a stored content record for a symbol.
60585
+ * @param {string} resolvedPath - Absolute path to the file
60586
+ * @param {string} symbolName - Symbol name
60587
+ * @returns {Object|null} The stored record or null
60588
+ */
60589
+ getSymbolRecord(resolvedPath2, symbolName) {
60590
+ return this._contentRecords.get(`${resolvedPath2}#${symbolName}`) || null;
60591
+ }
60592
+ /**
60593
+ * Check if a symbol's current content matches what was stored.
60594
+ * @param {string} resolvedPath - Absolute path to the file
60595
+ * @param {string} symbolName - Symbol name
60596
+ * @param {string} currentCode - The symbol's current source code (from findSymbol)
60597
+ * @returns {{ok: boolean, reason?: string, message?: string}}
60598
+ */
60599
+ checkSymbolContent(resolvedPath2, symbolName, currentCode) {
60600
+ const key = `${resolvedPath2}#${symbolName}`;
60601
+ const record = this._contentRecords.get(key);
60602
+ if (!record) {
60603
+ return { ok: true };
60604
+ }
60605
+ const currentHash = computeContentHash(currentCode);
60606
+ if (currentHash === record.contentHash) {
60607
+ return { ok: true };
60608
+ }
60609
+ return {
60610
+ ok: false,
60611
+ reason: "stale",
60612
+ message: `Symbol "${symbolName}" has changed since you last read it (hash: ${record.contentHash} \u2192 ${currentHash}).`
60613
+ };
60614
+ }
60615
+ /**
60616
+ * Track files from extract target strings.
60617
+ * Marks each file as seen. For #symbol targets, calls findSymbol to get and hash the code.
60618
+ * @param {string[]} targets - Array of extract targets (e.g. ["file.js#fn", "file.js:10-20"])
60619
+ * @param {string} cwd - Working directory for resolving relative paths
60620
+ */
60621
+ async trackFilesFromExtract(targets, cwd) {
60622
+ const seenPaths = /* @__PURE__ */ new Set();
60623
+ const symbolPromises = [];
60624
+ for (const target of targets) {
60625
+ const filePath = extractFilePath(target);
60626
+ const resolved = (0, import_path10.isAbsolute)(filePath) ? filePath : (0, import_path10.resolve)(cwd, filePath);
60627
+ if (!seenPaths.has(resolved)) {
60628
+ seenPaths.add(resolved);
60629
+ this.markFileSeen(resolved);
60630
+ }
60631
+ const symbolName = extractSymbolName(target);
60632
+ if (symbolName) {
60633
+ symbolPromises.push(
60634
+ findSymbol(resolved, symbolName, cwd).then((symbolInfo) => {
60635
+ if (symbolInfo) {
60636
+ this.trackSymbolContent(
60637
+ resolved,
60638
+ symbolName,
60639
+ symbolInfo.code,
60640
+ symbolInfo.startLine,
60641
+ symbolInfo.endLine,
60642
+ "extract"
60643
+ );
60644
+ }
60645
+ }).catch((err) => {
60646
+ if (this.debug) {
60647
+ console.error(`[FileTracker] Failed to track symbol "${symbolName}" in ${resolved}: ${err.message}`);
60648
+ }
60649
+ })
60650
+ );
60651
+ }
60652
+ }
60653
+ if (symbolPromises.length > 0) {
60654
+ await Promise.all(symbolPromises);
60655
+ }
60656
+ }
60657
+ /**
60658
+ * Track files discovered in probe search/extract output.
60659
+ * Parses "File: path" headers and "--- path ---" separators, marks each as "seen".
60660
+ * @param {string} output - Probe output text
60661
+ * @param {string} cwd - Working directory for resolving relative paths
60662
+ */
60663
+ async trackFilesFromOutput(output, cwd) {
60664
+ const paths = parseFilePathsFromOutput(output);
60665
+ for (const filePath of paths) {
60666
+ const resolved = (0, import_path10.isAbsolute)(filePath) ? filePath : (0, import_path10.resolve)(cwd, filePath);
60667
+ this.markFileSeen(resolved);
60668
+ }
60669
+ }
60670
+ /**
60671
+ * Check if a file is safe to edit (seen-check only).
60672
+ * Mode-specific content verification happens in edit handlers.
60673
+ * @param {string} resolvedPath - Absolute path to the file
60674
+ * @returns {{ok: boolean, reason?: string, message?: string}}
60675
+ */
60676
+ checkBeforeEdit(resolvedPath2) {
60677
+ if (!this._seenFiles.has(resolvedPath2)) {
60678
+ return {
60679
+ ok: false,
60680
+ reason: "untracked",
60681
+ message: "This file has not been read yet in this session. Use extract or search to read the file first."
60682
+ };
60683
+ }
60684
+ return { ok: true };
60685
+ }
60686
+ /**
60687
+ * Mark a file as seen after a successful write (backward compat).
60688
+ * Also invalidates content records for the file since its content changed.
60689
+ * @param {string} resolvedPath - Absolute path to the file
60690
+ */
60691
+ async trackFileAfterWrite(resolvedPath2) {
60692
+ this.markFileSeen(resolvedPath2);
60693
+ this.invalidateFileRecords(resolvedPath2);
60694
+ }
60695
+ /**
60696
+ * Update the stored hash for a symbol after a successful write.
60697
+ * Enables chained edits to the same symbol.
60698
+ * @param {string} resolvedPath - Absolute path to the file
60699
+ * @param {string} symbolName - Symbol name
60700
+ * @param {string} code - The symbol's new source code
60701
+ * @param {number} startLine - 1-indexed start line (new position)
60702
+ * @param {number} endLine - 1-indexed end line (new position)
60703
+ */
60704
+ trackSymbolAfterWrite(resolvedPath2, symbolName, code, startLine, endLine) {
60705
+ this.trackSymbolContent(resolvedPath2, symbolName, code, startLine, endLine, "edit");
60706
+ }
60707
+ /**
60708
+ * Remove all content records for a file.
60709
+ * Called after non-symbol edits (text/line mode) since those change content
60710
+ * without providing a symbol-level update.
60711
+ * @param {string} resolvedPath - Absolute path to the file
60712
+ */
60713
+ invalidateFileRecords(resolvedPath2) {
60714
+ const prefix = resolvedPath2 + "#";
60715
+ for (const key of this._contentRecords.keys()) {
60716
+ if (key.startsWith(prefix)) {
60717
+ this._contentRecords.delete(key);
60718
+ }
60719
+ }
60720
+ if (this.debug) {
60721
+ console.error(`[FileTracker] Invalidated content records for ${resolvedPath2}`);
60722
+ }
60723
+ }
60724
+ /**
60725
+ * Quick sync check if a file is being tracked (alias for isFileSeen).
60726
+ * @param {string} resolvedPath - Absolute path to the file
60727
+ * @returns {boolean}
60728
+ */
60729
+ isTracked(resolvedPath2) {
60730
+ return this.isFileSeen(resolvedPath2);
60731
+ }
60732
+ /**
60733
+ * Clear all tracking state.
60734
+ */
60735
+ clear() {
60736
+ this._seenFiles.clear();
60737
+ this._contentRecords.clear();
60738
+ }
60739
+ };
60740
+ }
60741
+ });
60742
+
59701
60743
  // src/agent/simpleTelemetry.js
59702
- var import_fs9, import_path10;
60744
+ var import_fs9, import_path11;
59703
60745
  var init_simpleTelemetry = __esm({
59704
60746
  "src/agent/simpleTelemetry.js"() {
59705
60747
  "use strict";
59706
60748
  import_fs9 = require("fs");
59707
- import_path10 = require("path");
60749
+ import_path11 = require("path");
59708
60750
  }
59709
60751
  });
59710
60752
 
@@ -59803,19 +60845,19 @@ function createWrappedTools(baseTools) {
59803
60845
  }
59804
60846
  return wrappedTools;
59805
60847
  }
59806
- var import_child_process8, import_util12, import_crypto3, import_events, import_fs10, import_fs11, import_path11, toolCallEmitter, activeToolExecutions, wrapToolWithEmitter, listFilesTool, searchFilesTool, listFilesToolInstance, searchFilesToolInstance;
60848
+ var import_child_process8, import_util12, import_crypto4, import_events, import_fs10, import_fs11, import_path12, toolCallEmitter, activeToolExecutions, wrapToolWithEmitter, listFilesTool, searchFilesTool, listFilesToolInstance, searchFilesToolInstance;
59807
60849
  var init_probeTool = __esm({
59808
60850
  "src/agent/probeTool.js"() {
59809
60851
  "use strict";
59810
60852
  init_index();
59811
60853
  import_child_process8 = require("child_process");
59812
60854
  import_util12 = require("util");
59813
- import_crypto3 = require("crypto");
60855
+ import_crypto4 = require("crypto");
59814
60856
  import_events = require("events");
59815
60857
  import_fs10 = __toESM(require("fs"), 1);
59816
60858
  import_fs11 = require("fs");
59817
- import_path11 = __toESM(require("path"), 1);
59818
- init_esm5();
60859
+ import_path12 = __toESM(require("path"), 1);
60860
+ init_esm7();
59819
60861
  init_symlink_utils();
59820
60862
  toolCallEmitter = new import_events.EventEmitter();
59821
60863
  activeToolExecutions = /* @__PURE__ */ new Map();
@@ -59825,7 +60867,7 @@ var init_probeTool = __esm({
59825
60867
  // Spread schema, description etc.
59826
60868
  execute: async (params) => {
59827
60869
  const debug = process.env.DEBUG === "1";
59828
- const toolSessionId = params.sessionId || (0, import_crypto3.randomUUID)();
60870
+ const toolSessionId = params.sessionId || (0, import_crypto4.randomUUID)();
59829
60871
  if (debug) {
59830
60872
  console.log(`[DEBUG] probeTool: Executing ${toolName} for session ${toolSessionId}`);
59831
60873
  }
@@ -59903,17 +60945,17 @@ var init_probeTool = __esm({
59903
60945
  execute: async (params) => {
59904
60946
  const { directory = ".", workingDirectory } = params;
59905
60947
  const baseCwd = workingDirectory || process.cwd();
59906
- const secureBaseDir = import_path11.default.resolve(baseCwd);
60948
+ const secureBaseDir = import_path12.default.resolve(baseCwd);
59907
60949
  const isDependencyPath = directory.startsWith("/dep/") || directory.startsWith("go:") || directory.startsWith("js:") || directory.startsWith("rust:");
59908
60950
  let targetDir;
59909
- if (import_path11.default.isAbsolute(directory)) {
59910
- targetDir = import_path11.default.resolve(directory);
59911
- if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + import_path11.default.sep) && targetDir !== secureBaseDir) {
60951
+ if (import_path12.default.isAbsolute(directory)) {
60952
+ targetDir = import_path12.default.resolve(directory);
60953
+ if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + import_path12.default.sep) && targetDir !== secureBaseDir) {
59912
60954
  throw new Error(`Path traversal attempt detected. Cannot access directory outside workspace: ${directory}`);
59913
60955
  }
59914
60956
  } else {
59915
- targetDir = import_path11.default.resolve(secureBaseDir, directory);
59916
- if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + import_path11.default.sep) && targetDir !== secureBaseDir) {
60957
+ targetDir = import_path12.default.resolve(secureBaseDir, directory);
60958
+ if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + import_path12.default.sep) && targetDir !== secureBaseDir) {
59917
60959
  throw new Error(`Path traversal attempt detected. Access denied: ${directory}`);
59918
60960
  }
59919
60961
  }
@@ -59930,7 +60972,7 @@ var init_probeTool = __esm({
59930
60972
  return `${(size / (1024 * 1024 * 1024)).toFixed(1)}G`;
59931
60973
  };
59932
60974
  const entries = await Promise.all(files.map(async (file) => {
59933
- const fullPath = import_path11.default.join(targetDir, file.name);
60975
+ const fullPath = import_path12.default.join(targetDir, file.name);
59934
60976
  const entryType = await getEntryType(file, fullPath);
59935
60977
  return {
59936
60978
  name: file.name,
@@ -59967,17 +61009,17 @@ var init_probeTool = __esm({
59967
61009
  throw new Error("Pattern is required for file search");
59968
61010
  }
59969
61011
  const baseCwd = workingDirectory || process.cwd();
59970
- const secureBaseDir = import_path11.default.resolve(baseCwd);
61012
+ const secureBaseDir = import_path12.default.resolve(baseCwd);
59971
61013
  const isDependencyPath = directory.startsWith("/dep/") || directory.startsWith("go:") || directory.startsWith("js:") || directory.startsWith("rust:");
59972
61014
  let targetDir;
59973
- if (import_path11.default.isAbsolute(directory)) {
59974
- targetDir = import_path11.default.resolve(directory);
59975
- if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + import_path11.default.sep) && targetDir !== secureBaseDir) {
61015
+ if (import_path12.default.isAbsolute(directory)) {
61016
+ targetDir = import_path12.default.resolve(directory);
61017
+ if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + import_path12.default.sep) && targetDir !== secureBaseDir) {
59976
61018
  throw new Error(`Path traversal attempt detected. Cannot access directory outside workspace: ${directory}`);
59977
61019
  }
59978
61020
  } else {
59979
- targetDir = import_path11.default.resolve(secureBaseDir, directory);
59980
- if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + import_path11.default.sep) && targetDir !== secureBaseDir) {
61021
+ targetDir = import_path12.default.resolve(secureBaseDir, directory);
61022
+ if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + import_path12.default.sep) && targetDir !== secureBaseDir) {
59981
61023
  throw new Error(`Path traversal attempt detected. Access denied: ${directory}`);
59982
61024
  }
59983
61025
  }
@@ -60554,6 +61596,7 @@ var init_index = __esm({
60554
61596
  init_executePlan();
60555
61597
  init_bash();
60556
61598
  init_edit();
61599
+ init_fileTracker();
60557
61600
  init_ProbeAgent();
60558
61601
  init_simpleTelemetry();
60559
61602
  init_probeTool();
@@ -60735,39 +61778,14 @@ function parseXmlToolCallWithThinking(xmlString, validTools) {
60735
61778
  const toolCall = parseXmlToolCall(cleanedXmlString, validTools);
60736
61779
  return toolCall ? { ...toolCall, thinkingContent } : null;
60737
61780
  }
60738
- var import_crypto4, implementToolDefinition, listFilesToolDefinition, searchFilesToolDefinition, listSkillsToolDefinition, useSkillToolDefinition, readImageToolDefinition;
61781
+ var import_crypto5, listFilesToolDefinition, searchFilesToolDefinition, listSkillsToolDefinition, useSkillToolDefinition, readImageToolDefinition;
60739
61782
  var init_tools2 = __esm({
60740
61783
  "src/agent/tools.js"() {
60741
61784
  "use strict";
60742
61785
  init_index();
60743
- import_crypto4 = require("crypto");
61786
+ import_crypto5 = require("crypto");
60744
61787
  init_xmlParsingUtils();
60745
61788
  init_tasks();
60746
- implementToolDefinition = `
60747
- ## implement
60748
- Description: Implement a given task. Can modify files. Can be used ONLY if task explicitly stated that something requires modification or implementation.
60749
-
60750
- Parameters:
60751
- - task: (required) The task description. Should be as detailed as possible, ideally pointing to exact files which needs be modified or created.
60752
- - autoCommits: (optional) Whether to enable auto-commits in aider. Default is false.
60753
-
60754
- Usage Example:
60755
-
60756
- <examples>
60757
-
60758
- User: Can you implement a function to calculate Fibonacci numbers in main.js?
60759
- <implement>
60760
- <task>Implement a recursive function to calculate the nth Fibonacci number in main.js</task>
60761
- </implement>
60762
-
60763
- User: Can you implement a function to calculate Fibonacci numbers in main.js with auto-commits?
60764
- <implement>
60765
- <task>Implement a recursive function to calculate the nth Fibonacci number in main.js</task>
60766
- <autoCommits>true</autoCommits>
60767
- </implement>
60768
-
60769
- </examples>
60770
- `;
60771
61789
  listFilesToolDefinition = `
60772
61790
  ## listFiles
60773
61791
  Description: List files and directories in a specified location.
@@ -60891,7 +61909,7 @@ function createMockProvider() {
60891
61909
  provider: "mock",
60892
61910
  // Mock the doGenerate method used by Vercel AI SDK
60893
61911
  doGenerate: async ({ messages, tools: tools2 }) => {
60894
- await new Promise((resolve7) => setTimeout(resolve7, 10));
61912
+ await new Promise((resolve8) => setTimeout(resolve8, 10));
60895
61913
  return {
60896
61914
  text: "This is a mock response for testing",
60897
61915
  toolCalls: [],
@@ -66094,23 +67112,23 @@ var init_regexp_parser = __esm({
66094
67112
  return ASSERT_NEVER_REACH_HERE();
66095
67113
  }
66096
67114
  quantifier(isBacktracking = false) {
66097
- let range2 = void 0;
67115
+ let range3 = void 0;
66098
67116
  const begin = this.idx;
66099
67117
  switch (this.popChar()) {
66100
67118
  case "*":
66101
- range2 = {
67119
+ range3 = {
66102
67120
  atLeast: 0,
66103
67121
  atMost: Infinity
66104
67122
  };
66105
67123
  break;
66106
67124
  case "+":
66107
- range2 = {
67125
+ range3 = {
66108
67126
  atLeast: 1,
66109
67127
  atMost: Infinity
66110
67128
  };
66111
67129
  break;
66112
67130
  case "?":
66113
- range2 = {
67131
+ range3 = {
66114
67132
  atLeast: 0,
66115
67133
  atMost: 1
66116
67134
  };
@@ -66119,7 +67137,7 @@ var init_regexp_parser = __esm({
66119
67137
  const atLeast = this.integerIncludingZero();
66120
67138
  switch (this.popChar()) {
66121
67139
  case "}":
66122
- range2 = {
67140
+ range3 = {
66123
67141
  atLeast,
66124
67142
  atMost: atLeast
66125
67143
  };
@@ -66128,12 +67146,12 @@ var init_regexp_parser = __esm({
66128
67146
  let atMost;
66129
67147
  if (this.isDigit()) {
66130
67148
  atMost = this.integerIncludingZero();
66131
- range2 = {
67149
+ range3 = {
66132
67150
  atLeast,
66133
67151
  atMost
66134
67152
  };
66135
67153
  } else {
66136
- range2 = {
67154
+ range3 = {
66137
67155
  atLeast,
66138
67156
  atMost: Infinity
66139
67157
  };
@@ -66141,25 +67159,25 @@ var init_regexp_parser = __esm({
66141
67159
  this.consumeChar("}");
66142
67160
  break;
66143
67161
  }
66144
- if (isBacktracking === true && range2 === void 0) {
67162
+ if (isBacktracking === true && range3 === void 0) {
66145
67163
  return void 0;
66146
67164
  }
66147
- ASSERT_EXISTS(range2);
67165
+ ASSERT_EXISTS(range3);
66148
67166
  break;
66149
67167
  }
66150
- if (isBacktracking === true && range2 === void 0) {
67168
+ if (isBacktracking === true && range3 === void 0) {
66151
67169
  return void 0;
66152
67170
  }
66153
- if (ASSERT_EXISTS(range2)) {
67171
+ if (ASSERT_EXISTS(range3)) {
66154
67172
  if (this.peekChar(0) === "?") {
66155
67173
  this.consumeChar("?");
66156
- range2.greedy = false;
67174
+ range3.greedy = false;
66157
67175
  } else {
66158
- range2.greedy = true;
67176
+ range3.greedy = true;
66159
67177
  }
66160
- range2.type = "Quantifier";
66161
- range2.loc = this.loc(begin);
66162
- return range2;
67178
+ range3.type = "Quantifier";
67179
+ range3.loc = this.loc(begin);
67180
+ return range3;
66163
67181
  }
66164
67182
  }
66165
67183
  atom() {
@@ -66861,18 +67879,18 @@ function firstCharOptimizedIndices(ast, result, ignoreCase) {
66861
67879
  if (typeof code === "number") {
66862
67880
  addOptimizedIdxToResult(code, result, ignoreCase);
66863
67881
  } else {
66864
- const range2 = code;
67882
+ const range3 = code;
66865
67883
  if (ignoreCase === true) {
66866
- for (let rangeCode = range2.from; rangeCode <= range2.to; rangeCode++) {
67884
+ for (let rangeCode = range3.from; rangeCode <= range3.to; rangeCode++) {
66867
67885
  addOptimizedIdxToResult(rangeCode, result, ignoreCase);
66868
67886
  }
66869
67887
  } else {
66870
- for (let rangeCode = range2.from; rangeCode <= range2.to && rangeCode < minOptimizationVal; rangeCode++) {
67888
+ for (let rangeCode = range3.from; rangeCode <= range3.to && rangeCode < minOptimizationVal; rangeCode++) {
66871
67889
  addOptimizedIdxToResult(rangeCode, result, ignoreCase);
66872
67890
  }
66873
- if (range2.to >= minOptimizationVal) {
66874
- const minUnOptVal = range2.from >= minOptimizationVal ? range2.from : minOptimizationVal;
66875
- const maxUnOptVal = range2.to;
67891
+ if (range3.to >= minOptimizationVal) {
67892
+ const minUnOptVal = range3.from >= minOptimizationVal ? range3.from : minOptimizationVal;
67893
+ const maxUnOptVal = range3.to;
66876
67894
  const minOptIdx = charCodeToOptimizedIndex(minUnOptVal);
66877
67895
  const maxOptIdx = charCodeToOptimizedIndex(maxUnOptVal);
66878
67896
  for (let currOptIdx = minOptIdx; currOptIdx <= maxOptIdx; currOptIdx++) {
@@ -66933,8 +67951,8 @@ function findCode(setNode, targetCharCodes) {
66933
67951
  if (typeof codeOrRange === "number") {
66934
67952
  return includes_default(targetCharCodes, codeOrRange);
66935
67953
  } else {
66936
- const range2 = codeOrRange;
66937
- return find_default(targetCharCodes, (targetCode) => range2.from <= targetCode && targetCode <= range2.to) !== void 0;
67954
+ const range3 = codeOrRange;
67955
+ return find_default(targetCharCodes, (targetCode) => range3.from <= targetCode && targetCode <= range3.to) !== void 0;
66938
67956
  }
66939
67957
  });
66940
67958
  }
@@ -84839,8 +85857,8 @@ var require_createRange = __commonJS({
84839
85857
  var require_range = __commonJS({
84840
85858
  "node_modules/lodash/range.js"(exports2, module2) {
84841
85859
  var createRange = require_createRange();
84842
- var range2 = createRange();
84843
- module2.exports = range2;
85860
+ var range3 = createRange();
85861
+ module2.exports = range3;
84844
85862
  }
84845
85863
  });
84846
85864
 
@@ -94081,7 +95099,7 @@ var require_compile = __commonJS({
94081
95099
  const schOrFunc = root2.refs[ref2];
94082
95100
  if (schOrFunc)
94083
95101
  return schOrFunc;
94084
- let _sch = resolve7.call(this, root2, ref2);
95102
+ let _sch = resolve8.call(this, root2, ref2);
94085
95103
  if (_sch === void 0) {
94086
95104
  const schema = (_a16 = root2.localRefs) === null || _a16 === void 0 ? void 0 : _a16[ref2];
94087
95105
  const { schemaId } = this.opts;
@@ -94108,7 +95126,7 @@ var require_compile = __commonJS({
94108
95126
  function sameSchemaEnv(s1, s22) {
94109
95127
  return s1.schema === s22.schema && s1.root === s22.root && s1.baseId === s22.baseId;
94110
95128
  }
94111
- function resolve7(root2, ref2) {
95129
+ function resolve8(root2, ref2) {
94112
95130
  let sch;
94113
95131
  while (typeof (sch = this.refs[ref2]) == "string")
94114
95132
  ref2 = sch;
@@ -94683,7 +95701,7 @@ var require_fast_uri = __commonJS({
94683
95701
  }
94684
95702
  return uri;
94685
95703
  }
94686
- function resolve7(baseURI, relativeURI, options) {
95704
+ function resolve8(baseURI, relativeURI, options) {
94687
95705
  const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
94688
95706
  const resolved = resolveComponent(parse9(baseURI, schemelessOptions), parse9(relativeURI, schemelessOptions), schemelessOptions, true);
94689
95707
  schemelessOptions.skipEscape = true;
@@ -94910,7 +95928,7 @@ var require_fast_uri = __commonJS({
94910
95928
  var fastUri = {
94911
95929
  SCHEMES,
94912
95930
  normalize: normalize3,
94913
- resolve: resolve7,
95931
+ resolve: resolve8,
94914
95932
  resolveComponent,
94915
95933
  equal,
94916
95934
  serialize,
@@ -97603,6 +98621,7 @@ __export(schemaUtils_exports, {
97603
98621
  processSchemaResponse: () => processSchemaResponse,
97604
98622
  replaceMermaidDiagramsInJson: () => replaceMermaidDiagramsInJson,
97605
98623
  replaceMermaidDiagramsInMarkdown: () => replaceMermaidDiagramsInMarkdown,
98624
+ sanitizeMarkdownEscapesInJson: () => sanitizeMarkdownEscapesInJson,
97606
98625
  tryAutoWrapForSimpleSchema: () => tryAutoWrapForSimpleSchema,
97607
98626
  tryMaidAutoFix: () => tryMaidAutoFix,
97608
98627
  validateAndFixMermaidResponse: () => validateAndFixMermaidResponse,
@@ -97706,6 +98725,17 @@ function decodeHtmlEntities2(text) {
97706
98725
  }
97707
98726
  return decoded;
97708
98727
  }
98728
+ function sanitizeMarkdownEscapesInJson(jsonString) {
98729
+ if (!jsonString || typeof jsonString !== "string") {
98730
+ return jsonString;
98731
+ }
98732
+ return jsonString.replace(/\\\\|\\([^"\\\/bfnrtu])/g, (match2, captured) => {
98733
+ if (match2 === "\\\\") {
98734
+ return "\\\\";
98735
+ }
98736
+ return captured;
98737
+ });
98738
+ }
97709
98739
  function normalizeJsonQuotes(str) {
97710
98740
  if (!str || typeof str !== "string") {
97711
98741
  return str;
@@ -97758,6 +98788,15 @@ function cleanSchemaResponse(response) {
97758
98788
  if (resultWrapperMatch) {
97759
98789
  return cleanSchemaResponse(resultWrapperMatch[1]);
97760
98790
  }
98791
+ const toolCodeMatch = trimmed.match(/<tool_code>\s*([\s\S]*?)\s*<\/tool_code>/);
98792
+ if (toolCodeMatch) {
98793
+ let innerContent = toolCodeMatch[1].trim();
98794
+ const funcCallMatch = innerContent.match(/(?:print|attempt_completion)\s*\(\s*([{\[][\s\S]*[}\]])\s*\)/);
98795
+ if (funcCallMatch) {
98796
+ return cleanSchemaResponse(funcCallMatch[1]);
98797
+ }
98798
+ return cleanSchemaResponse(innerContent);
98799
+ }
97761
98800
  const jsonBlockMatch = trimmed.match(/```json\s*\n([\s\S]*?)\n```/);
97762
98801
  if (jsonBlockMatch) {
97763
98802
  return normalizeJsonQuotes(jsonBlockMatch[1].trim());
@@ -97825,9 +98864,25 @@ function validateJsonResponse(response, options = {}) {
97825
98864
  console.log(`[DEBUG] JSON validation: Schema validation enabled`);
97826
98865
  }
97827
98866
  }
98867
+ let responseToValidate = response;
98868
+ try {
98869
+ JSON.parse(response);
98870
+ } catch (initialError) {
98871
+ if (initialError.message && initialError.message.includes("escape")) {
98872
+ const sanitized = sanitizeMarkdownEscapesInJson(response);
98873
+ try {
98874
+ JSON.parse(sanitized);
98875
+ responseToValidate = sanitized;
98876
+ if (debug) {
98877
+ console.log(`[DEBUG] JSON validation: Fixed Markdown escapes in JSON (issue #441)`);
98878
+ }
98879
+ } catch {
98880
+ }
98881
+ }
98882
+ }
97828
98883
  try {
97829
98884
  const parseStart = Date.now();
97830
- const parsed = JSON.parse(response);
98885
+ const parsed = JSON.parse(responseToValidate);
97831
98886
  const parseTime = Date.now() - parseStart;
97832
98887
  if (debug) {
97833
98888
  console.log(`[DEBUG] JSON validation: Successfully parsed in ${parseTime}ms`);
@@ -98169,7 +99224,21 @@ function tryAutoWrapForSimpleSchema(response, schema, options = {}) {
98169
99224
  console.log(`[DEBUG] Auto-wrap: Response is already valid JSON, skipping`);
98170
99225
  }
98171
99226
  return null;
98172
- } catch {
99227
+ } catch (initialError) {
99228
+ if (initialError.message && initialError.message.includes("escape")) {
99229
+ try {
99230
+ const sanitized = sanitizeMarkdownEscapesInJson(response);
99231
+ JSON.parse(sanitized);
99232
+ if (debug) {
99233
+ console.log(`[DEBUG] Auto-wrap: Fixed Markdown escapes in JSON (issue #441), returning sanitized JSON`);
99234
+ }
99235
+ return sanitized;
99236
+ } catch {
99237
+ if (debug) {
99238
+ console.log(`[DEBUG] Auto-wrap: Markdown escape sanitization didn't fix JSON, proceeding with wrapping`);
99239
+ }
99240
+ }
99241
+ }
98173
99242
  }
98174
99243
  const wrapped = JSON.stringify({ [wrapperInfo.fieldName]: response });
98175
99244
  if (debug) {
@@ -99382,13 +100451,13 @@ function loadMCPConfiguration() {
99382
100451
  // Environment variable path
99383
100452
  process.env.MCP_CONFIG_PATH,
99384
100453
  // Local project paths
99385
- (0, import_path12.join)(process.cwd(), ".mcp", "config.json"),
99386
- (0, import_path12.join)(process.cwd(), "mcp.config.json"),
100454
+ (0, import_path13.join)(process.cwd(), ".mcp", "config.json"),
100455
+ (0, import_path13.join)(process.cwd(), "mcp.config.json"),
99387
100456
  // Home directory paths
99388
- (0, import_path12.join)((0, import_os3.homedir)(), ".config", "probe", "mcp.json"),
99389
- (0, import_path12.join)((0, import_os3.homedir)(), ".mcp", "config.json"),
100457
+ (0, import_path13.join)((0, import_os3.homedir)(), ".config", "probe", "mcp.json"),
100458
+ (0, import_path13.join)((0, import_os3.homedir)(), ".mcp", "config.json"),
99390
100459
  // Claude-style config location
99391
- (0, import_path12.join)((0, import_os3.homedir)(), "Library", "Application Support", "Claude", "mcp_config.json")
100460
+ (0, import_path13.join)((0, import_os3.homedir)(), "Library", "Application Support", "Claude", "mcp_config.json")
99392
100461
  ].filter(Boolean);
99393
100462
  let config = null;
99394
100463
  for (const configPath of configPaths) {
@@ -99515,16 +100584,16 @@ function parseEnabledServers(config) {
99515
100584
  }
99516
100585
  return servers;
99517
100586
  }
99518
- var import_fs12, import_path12, import_os3, import_url4, __filename4, __dirname4, DEFAULT_TIMEOUT, MAX_TIMEOUT, DEFAULT_CONFIG;
100587
+ var import_fs12, import_path13, import_os3, import_url4, __filename4, __dirname4, DEFAULT_TIMEOUT, MAX_TIMEOUT, DEFAULT_CONFIG;
99519
100588
  var init_config = __esm({
99520
100589
  "src/agent/mcp/config.js"() {
99521
100590
  "use strict";
99522
100591
  import_fs12 = require("fs");
99523
- import_path12 = require("path");
100592
+ import_path13 = require("path");
99524
100593
  import_os3 = require("os");
99525
100594
  import_url4 = require("url");
99526
100595
  __filename4 = (0, import_url4.fileURLToPath)("file:///");
99527
- __dirname4 = (0, import_path12.dirname)(__filename4);
100596
+ __dirname4 = (0, import_path13.dirname)(__filename4);
99528
100597
  DEFAULT_TIMEOUT = 3e4;
99529
100598
  MAX_TIMEOUT = (() => {
99530
100599
  if (process.env.MCP_MAX_TIMEOUT) {
@@ -99538,7 +100607,7 @@ var init_config = __esm({
99538
100607
  // Example probe server configuration
99539
100608
  "probe-local": {
99540
100609
  command: "node",
99541
- args: [(0, import_path12.join)(__dirname4, "../../../examples/chat/mcpServer.js")],
100610
+ args: [(0, import_path13.join)(__dirname4, "../../../examples/chat/mcpServer.js")],
99542
100611
  transport: "stdio",
99543
100612
  enabled: false
99544
100613
  },
@@ -105121,7 +106190,7 @@ var require_compose_scalar = __commonJS({
105121
106190
  var resolveBlockScalar = require_resolve_block_scalar();
105122
106191
  var resolveFlowScalar = require_resolve_flow_scalar();
105123
106192
  function composeScalar(ctx, token, tagToken, onError) {
105124
- const { value, type, comment, range: range2 } = token.type === "block-scalar" ? resolveBlockScalar.resolveBlockScalar(ctx, token, onError) : resolveFlowScalar.resolveFlowScalar(token, ctx.options.strict, onError);
106193
+ const { value, type, comment, range: range3 } = token.type === "block-scalar" ? resolveBlockScalar.resolveBlockScalar(ctx, token, onError) : resolveFlowScalar.resolveFlowScalar(token, ctx.options.strict, onError);
105125
106194
  const tagName = tagToken ? ctx.directives.tagName(tagToken.source, (msg) => onError(tagToken, "TAG_RESOLVE_FAILED", msg)) : null;
105126
106195
  let tag2;
105127
106196
  if (ctx.options.stringKeys && ctx.atKey) {
@@ -105141,7 +106210,7 @@ var require_compose_scalar = __commonJS({
105141
106210
  onError(tagToken ?? token, "TAG_RESOLVE_FAILED", msg);
105142
106211
  scalar = new Scalar.Scalar(value);
105143
106212
  }
105144
- scalar.range = range2;
106213
+ scalar.range = range3;
105145
106214
  scalar.source = value;
105146
106215
  if (type)
105147
106216
  scalar.type = type;
@@ -107732,17 +108801,17 @@ async function parseSkillFile(skillFilePath, directoryName) {
107732
108801
  description,
107733
108802
  skillFilePath,
107734
108803
  directoryName,
107735
- sourceDir: (0, import_path13.dirname)(skillFilePath)
108804
+ sourceDir: (0, import_path14.dirname)(skillFilePath)
107736
108805
  },
107737
108806
  error: null
107738
108807
  };
107739
108808
  }
107740
- var import_promises2, import_path13, import_yaml, SKILL_NAME_REGEX, MAX_SKILL_NAME_LENGTH, MAX_DESCRIPTION_CHARS;
108809
+ var import_promises2, import_path14, import_yaml, SKILL_NAME_REGEX, MAX_SKILL_NAME_LENGTH, MAX_DESCRIPTION_CHARS;
107741
108810
  var init_parser7 = __esm({
107742
108811
  "src/agent/skills/parser.js"() {
107743
108812
  "use strict";
107744
108813
  import_promises2 = require("fs/promises");
107745
- import_path13 = require("path");
108814
+ import_path14 = require("path");
107746
108815
  import_yaml = __toESM(require_dist(), 1);
107747
108816
  SKILL_NAME_REGEX = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
107748
108817
  MAX_SKILL_NAME_LENGTH = 64;
@@ -107752,12 +108821,12 @@ var init_parser7 = __esm({
107752
108821
 
107753
108822
  // src/agent/skills/registry.js
107754
108823
  function isPathInside(basePath, targetPath) {
107755
- const base2 = (0, import_path14.resolve)(basePath);
107756
- const target = (0, import_path14.resolve)(targetPath);
107757
- const rel = (0, import_path14.relative)(base2, target);
108824
+ const base2 = (0, import_path15.resolve)(basePath);
108825
+ const target = (0, import_path15.resolve)(targetPath);
108826
+ const rel = (0, import_path15.relative)(base2, target);
107758
108827
  if (rel === "") return true;
107759
- if (rel === ".." || rel.startsWith(`..${import_path14.sep}`)) return false;
107760
- if ((0, import_path14.isAbsolute)(rel)) return false;
108828
+ if (rel === ".." || rel.startsWith(`..${import_path15.sep}`)) return false;
108829
+ if ((0, import_path15.isAbsolute)(rel)) return false;
107761
108830
  return true;
107762
108831
  }
107763
108832
  function isSafeEntryName(name14) {
@@ -107765,19 +108834,19 @@ function isSafeEntryName(name14) {
107765
108834
  if (name14.includes("\0")) return false;
107766
108835
  return !name14.includes("/") && !name14.includes("\\");
107767
108836
  }
107768
- var import_fs13, import_promises3, import_path14, DEFAULT_SKILL_DIRS, SKILL_FILE_NAME, SkillRegistry;
108837
+ var import_fs13, import_promises3, import_path15, DEFAULT_SKILL_DIRS, SKILL_FILE_NAME, SkillRegistry;
107769
108838
  var init_registry = __esm({
107770
108839
  "src/agent/skills/registry.js"() {
107771
108840
  "use strict";
107772
108841
  import_fs13 = require("fs");
107773
108842
  import_promises3 = require("fs/promises");
107774
- import_path14 = require("path");
108843
+ import_path15 = require("path");
107775
108844
  init_parser7();
107776
108845
  DEFAULT_SKILL_DIRS = [".claude/skills", ".codex/skills", "skills", ".skills"];
107777
108846
  SKILL_FILE_NAME = "SKILL.md";
107778
108847
  SkillRegistry = class {
107779
108848
  constructor({ repoRoot, skillDirs = DEFAULT_SKILL_DIRS, debug = false } = {}) {
107780
- this.repoRoot = repoRoot ? (0, import_path14.resolve)(repoRoot) : process.cwd();
108849
+ this.repoRoot = repoRoot ? (0, import_path15.resolve)(repoRoot) : process.cwd();
107781
108850
  this.repoRootReal = null;
107782
108851
  this.skillDirs = Array.isArray(skillDirs) && skillDirs.length > 0 ? skillDirs : DEFAULT_SKILL_DIRS;
107783
108852
  this.debug = debug;
@@ -107831,8 +108900,8 @@ var init_registry = __esm({
107831
108900
  }
107832
108901
  }
107833
108902
  async _resolveSkillDir(skillDir) {
107834
- const resolved = (0, import_path14.isAbsolute)(skillDir) ? (0, import_path14.resolve)(skillDir) : (0, import_path14.resolve)(this.repoRoot, skillDir);
107835
- const repoRoot = this.repoRootReal || (0, import_path14.resolve)(this.repoRoot);
108903
+ const resolved = (0, import_path15.isAbsolute)(skillDir) ? (0, import_path15.resolve)(skillDir) : (0, import_path15.resolve)(this.repoRoot, skillDir);
108904
+ const repoRoot = this.repoRootReal || (0, import_path15.resolve)(this.repoRoot);
107836
108905
  const resolvedReal = await this._resolveRealPath(resolved);
107837
108906
  if (!resolvedReal) return null;
107838
108907
  if (!isPathInside(repoRoot, resolvedReal)) {
@@ -107863,8 +108932,8 @@ var init_registry = __esm({
107863
108932
  }
107864
108933
  continue;
107865
108934
  }
107866
- const skillFolder = (0, import_path14.join)(dirPath, entry.name);
107867
- const skillFilePath = (0, import_path14.join)(skillFolder, SKILL_FILE_NAME);
108935
+ const skillFolder = (0, import_path15.join)(dirPath, entry.name);
108936
+ const skillFilePath = (0, import_path15.join)(skillFolder, SKILL_FILE_NAME);
107868
108937
  let skillStat;
107869
108938
  try {
107870
108939
  skillStat = await (0, import_promises3.lstat)(skillFilePath);
@@ -108022,7 +109091,7 @@ function extractErrorInfo(error2) {
108022
109091
  };
108023
109092
  }
108024
109093
  function sleep(ms) {
108025
- return new Promise((resolve7) => setTimeout(resolve7, ms));
109094
+ return new Promise((resolve8) => setTimeout(resolve8, ms));
108026
109095
  }
108027
109096
  var DEFAULT_RETRYABLE_ERRORS, RetryManager;
108028
109097
  var init_RetryManager = __esm({
@@ -108802,9 +109871,9 @@ async function truncateIfNeeded(content, tokenCounter, sessionId, maxTokens) {
108802
109871
  let tempFilePath = null;
108803
109872
  let fileError = null;
108804
109873
  try {
108805
- const tempDir = (0, import_path15.join)((0, import_os4.tmpdir)(), "probe-output");
109874
+ const tempDir = (0, import_path16.join)((0, import_os4.tmpdir)(), "probe-output");
108806
109875
  await (0, import_promises4.mkdir)(tempDir, { recursive: true });
108807
- tempFilePath = (0, import_path15.join)(tempDir, `tool-output-${sessionId || "unknown"}-${(0, import_crypto5.randomUUID)()}.txt`);
109876
+ tempFilePath = (0, import_path16.join)(tempDir, `tool-output-${sessionId || "unknown"}-${(0, import_crypto6.randomUUID)()}.txt`);
108808
109877
  await (0, import_promises4.writeFile)(tempFilePath, content, "utf8");
108809
109878
  } catch (err) {
108810
109879
  fileError = err.message || "Unknown file system error";
@@ -108852,14 +109921,14 @@ ${truncatedBody}
108852
109921
  error: fileError || void 0
108853
109922
  };
108854
109923
  }
108855
- var import_promises4, import_os4, import_path15, import_crypto5, DEFAULT_MAX_OUTPUT_TOKENS, CHARS_PER_TOKEN2, TAIL_TOKENS, MIN_LIMIT_FOR_TAIL;
109924
+ var import_promises4, import_os4, import_path16, import_crypto6, DEFAULT_MAX_OUTPUT_TOKENS, CHARS_PER_TOKEN2, TAIL_TOKENS, MIN_LIMIT_FOR_TAIL;
108856
109925
  var init_outputTruncator = __esm({
108857
109926
  "src/agent/outputTruncator.js"() {
108858
109927
  "use strict";
108859
109928
  import_promises4 = require("fs/promises");
108860
109929
  import_os4 = require("os");
108861
- import_path15 = require("path");
108862
- import_crypto5 = require("crypto");
109930
+ import_path16 = require("path");
109931
+ import_crypto6 = require("crypto");
108863
109932
  DEFAULT_MAX_OUTPUT_TOKENS = 2e4;
108864
109933
  CHARS_PER_TOKEN2 = 4;
108865
109934
  TAIL_TOKENS = 1e3;
@@ -108868,13 +109937,13 @@ var init_outputTruncator = __esm({
108868
109937
  });
108869
109938
 
108870
109939
  // src/agent/mcp/built-in-server.js
108871
- var import_http, import_events2, import_crypto6, import_server, import_sse2, import_streamableHttp, import_types3, InMemoryEventStore, BuiltInMCPServer;
109940
+ var import_http, import_events2, import_crypto7, import_server, import_sse2, import_streamableHttp, import_types3, InMemoryEventStore, BuiltInMCPServer;
108872
109941
  var init_built_in_server = __esm({
108873
109942
  "src/agent/mcp/built-in-server.js"() {
108874
109943
  "use strict";
108875
109944
  import_http = require("http");
108876
109945
  import_events2 = require("events");
108877
- import_crypto6 = require("crypto");
109946
+ import_crypto7 = require("crypto");
108878
109947
  import_server = require("@modelcontextprotocol/sdk/server/index.js");
108879
109948
  import_sse2 = require("@modelcontextprotocol/sdk/server/sse.js");
108880
109949
  import_streamableHttp = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
@@ -108950,7 +110019,7 @@ var init_built_in_server = __esm({
108950
110019
  }
108951
110020
  });
108952
110021
  this.registerHandlers();
108953
- return new Promise((resolve7, reject2) => {
110022
+ return new Promise((resolve8, reject2) => {
108954
110023
  this.httpServer.listen(this.port, this.host, async () => {
108955
110024
  const address = this.httpServer.address();
108956
110025
  this.port = address.port;
@@ -108960,7 +110029,7 @@ var init_built_in_server = __esm({
108960
110029
  console.log(`[MCP] Messages endpoint: http://${this.host}:${this.port}/messages`);
108961
110030
  }
108962
110031
  this.emit("ready", { host: this.host, port: this.port });
108963
- resolve7({ host: this.host, port: this.port });
110032
+ resolve8({ host: this.host, port: this.port });
108964
110033
  });
108965
110034
  this.httpServer.on("error", reject2);
108966
110035
  });
@@ -109118,7 +110187,7 @@ var init_built_in_server = __esm({
109118
110187
  }
109119
110188
  const eventStore = new InMemoryEventStore();
109120
110189
  transport = new import_streamableHttp.StreamableHTTPServerTransport({
109121
- sessionIdGenerator: () => (0, import_crypto6.randomUUID)(),
110190
+ sessionIdGenerator: () => (0, import_crypto7.randomUUID)(),
109122
110191
  eventStore,
109123
110192
  // Enable resumability
109124
110193
  onsessioninitialized: (newSessionId) => {
@@ -109179,7 +110248,7 @@ var init_built_in_server = __esm({
109179
110248
  * Parse request body as JSON
109180
110249
  */
109181
110250
  async parseRequestBody(req) {
109182
- return new Promise((resolve7, reject2) => {
110251
+ return new Promise((resolve8, reject2) => {
109183
110252
  let body = "";
109184
110253
  req.on("data", (chunk) => {
109185
110254
  body += chunk.toString();
@@ -109187,7 +110256,7 @@ var init_built_in_server = __esm({
109187
110256
  req.on("end", () => {
109188
110257
  try {
109189
110258
  const parsed = body ? JSON.parse(body) : null;
109190
- resolve7(parsed);
110259
+ resolve8(parsed);
109191
110260
  } catch (error2) {
109192
110261
  reject2(error2);
109193
110262
  }
@@ -109494,12 +110563,12 @@ data: ${JSON.stringify(data3)}
109494
110563
  }
109495
110564
  this.connections.clear();
109496
110565
  if (this.httpServer) {
109497
- return new Promise((resolve7) => {
110566
+ return new Promise((resolve8) => {
109498
110567
  this.httpServer.close(() => {
109499
110568
  if (this.debug) {
109500
110569
  console.log("[MCP] Built-in server stopped");
109501
110570
  }
109502
- resolve7();
110571
+ resolve8();
109503
110572
  });
109504
110573
  });
109505
110574
  }
@@ -109581,7 +110650,7 @@ __export(enhanced_claude_code_exports, {
109581
110650
  async function createEnhancedClaudeCLIEngine(options = {}) {
109582
110651
  const { agent, systemPrompt, customPrompt, debug, sessionId, allowedTools, timeout = 12e4 } = options;
109583
110652
  const session = new Session(
109584
- sessionId || (0, import_crypto7.randomBytes)(8).toString("hex"),
110653
+ sessionId || (0, import_crypto8.randomBytes)(8).toString("hex"),
109585
110654
  debug
109586
110655
  );
109587
110656
  let mcpServer = null;
@@ -109598,12 +110667,12 @@ async function createEnhancedClaudeCLIEngine(options = {}) {
109598
110667
  console.log("[DEBUG] Built-in MCP server started");
109599
110668
  console.log("[DEBUG] MCP URL:", `http://${host}:${port}/mcp`);
109600
110669
  }
109601
- mcpConfigPath = import_path16.default.join(import_os5.default.tmpdir(), `probe-mcp-${session.id}.json`);
110670
+ mcpConfigPath = import_path17.default.join(import_os5.default.tmpdir(), `probe-mcp-${session.id}.json`);
109602
110671
  const mcpConfig = {
109603
110672
  mcpServers: {
109604
110673
  probe: {
109605
110674
  command: "node",
109606
- args: [import_path16.default.join(process.cwd(), "mcp-probe-server.js")],
110675
+ args: [import_path17.default.join(process.cwd(), "mcp-probe-server.js")],
109607
110676
  env: {
109608
110677
  PROBE_WORKSPACE: process.cwd(),
109609
110678
  DEBUG: debug ? "true" : "false"
@@ -109828,8 +110897,8 @@ ${opts.schema}`;
109828
110897
  break;
109829
110898
  }
109830
110899
  } else if (!processEnded) {
109831
- await new Promise((resolve7) => {
109832
- resolver = resolve7;
110900
+ await new Promise((resolve8) => {
110901
+ resolver = resolve8;
109833
110902
  });
109834
110903
  }
109835
110904
  }
@@ -110028,14 +111097,14 @@ function combinePrompts(systemPrompt, customPrompt, agent) {
110028
111097
  }
110029
111098
  return systemPrompt || "";
110030
111099
  }
110031
- var import_child_process9, import_crypto7, import_promises5, import_path16, import_os5, import_events3;
111100
+ var import_child_process9, import_crypto8, import_promises5, import_path17, import_os5, import_events3;
110032
111101
  var init_enhanced_claude_code = __esm({
110033
111102
  "src/agent/engines/enhanced-claude-code.js"() {
110034
111103
  "use strict";
110035
111104
  import_child_process9 = require("child_process");
110036
- import_crypto7 = require("crypto");
111105
+ import_crypto8 = require("crypto");
110037
111106
  import_promises5 = __toESM(require("fs/promises"), 1);
110038
- import_path16 = __toESM(require("path"), 1);
111107
+ import_path17 = __toESM(require("path"), 1);
110039
111108
  import_os5 = __toESM(require("os"), 1);
110040
111109
  import_events3 = require("events");
110041
111110
  init_built_in_server();
@@ -110051,7 +111120,7 @@ __export(codex_exports, {
110051
111120
  async function createCodexEngine(options = {}) {
110052
111121
  const { agent, systemPrompt, customPrompt, debug, sessionId, allowedTools, model } = options;
110053
111122
  const session = new Session(
110054
- sessionId || (0, import_crypto8.randomBytes)(8).toString("hex"),
111123
+ sessionId || (0, import_crypto9.randomBytes)(8).toString("hex"),
110055
111124
  debug
110056
111125
  );
110057
111126
  let mcpServer = null;
@@ -110093,12 +111162,12 @@ async function createCodexEngine(options = {}) {
110093
111162
  }
110094
111163
  }
110095
111164
  if (message.id !== void 0 && pendingRequests.has(message.id)) {
110096
- const { resolve: resolve7, reject: reject2 } = pendingRequests.get(message.id);
111165
+ const { resolve: resolve8, reject: reject2 } = pendingRequests.get(message.id);
110097
111166
  pendingRequests.delete(message.id);
110098
111167
  if (message.error) {
110099
111168
  reject2(new Error(message.error.message || JSON.stringify(message.error)));
110100
111169
  } else {
110101
- resolve7(message.result);
111170
+ resolve8(message.result);
110102
111171
  }
110103
111172
  }
110104
111173
  if (message.method === "codex/event" && message.params) {
@@ -110119,7 +111188,7 @@ async function createCodexEngine(options = {}) {
110119
111188
  });
110120
111189
  }
110121
111190
  function sendRequest(method, params = {}) {
110122
- return new Promise((resolve7, reject2) => {
111191
+ return new Promise((resolve8, reject2) => {
110123
111192
  const id = ++requestId;
110124
111193
  const request = {
110125
111194
  jsonrpc: "2.0",
@@ -110127,7 +111196,7 @@ async function createCodexEngine(options = {}) {
110127
111196
  method,
110128
111197
  params
110129
111198
  };
110130
- pendingRequests.set(id, { resolve: resolve7, reject: reject2 });
111199
+ pendingRequests.set(id, { resolve: resolve8, reject: reject2 });
110131
111200
  setTimeout(() => {
110132
111201
  if (pendingRequests.has(id)) {
110133
111202
  pendingRequests.delete(id);
@@ -110190,7 +111259,7 @@ ${prompt}`;
110190
111259
  const reqId = requestId + 1;
110191
111260
  let fullResponse = "";
110192
111261
  let gotSessionId = false;
110193
- const eventPromise = new Promise((resolve7) => {
111262
+ const eventPromise = new Promise((resolve8) => {
110194
111263
  eventHandlers.set(reqId, (eventParams) => {
110195
111264
  const msg = eventParams.msg;
110196
111265
  if (msg.type === "session_configured" && msg.session_id && !gotSessionId) {
@@ -110210,7 +111279,7 @@ ${prompt}`;
110210
111279
  });
110211
111280
  setTimeout(() => {
110212
111281
  eventHandlers.delete(reqId);
110213
- resolve7();
111282
+ resolve8();
110214
111283
  }, 6e5);
110215
111284
  });
110216
111285
  const resultPromise = sendRequest("tools/call", {
@@ -110306,12 +111375,12 @@ function combinePrompts2(systemPrompt, customPrompt, agent) {
110306
111375
  }
110307
111376
  return systemPrompt || "";
110308
111377
  }
110309
- var import_child_process10, import_crypto8, import_readline;
111378
+ var import_child_process10, import_crypto9, import_readline;
110310
111379
  var init_codex = __esm({
110311
111380
  "src/agent/engines/codex.js"() {
110312
111381
  "use strict";
110313
111382
  import_child_process10 = require("child_process");
110314
- import_crypto8 = require("crypto");
111383
+ import_crypto9 = require("crypto");
110315
111384
  import_readline = require("readline");
110316
111385
  init_built_in_server();
110317
111386
  init_Session();
@@ -110417,7 +111486,7 @@ Your content here
110417
111486
 
110418
111487
  Do NOT wrap in other tags like <api_call>, <tool_name>, <function>, etc.`;
110419
111488
  }
110420
- var import_dotenv2, import_anthropic2, import_openai2, import_google2, import_ai6, import_crypto9, import_events4, import_fs14, import_promises6, import_path17, ENGINE_ACTIVITY_TIMEOUT_DEFAULT, ENGINE_ACTIVITY_TIMEOUT_MIN, ENGINE_ACTIVITY_TIMEOUT_MAX, MAX_TOOL_ITERATIONS, MAX_HISTORY_MESSAGES, MAX_IMAGE_FILE_SIZE, ProbeAgent;
111489
+ var import_dotenv2, import_anthropic2, import_openai2, import_google2, import_ai6, import_crypto10, import_events4, import_fs14, import_promises6, import_path18, ENGINE_ACTIVITY_TIMEOUT_DEFAULT, ENGINE_ACTIVITY_TIMEOUT_MIN, ENGINE_ACTIVITY_TIMEOUT_MAX, MAX_TOOL_ITERATIONS, MAX_HISTORY_MESSAGES, MAX_IMAGE_FILE_SIZE, ProbeAgent;
110421
111490
  var init_ProbeAgent = __esm({
110422
111491
  "src/agent/ProbeAgent.js"() {
110423
111492
  import_dotenv2 = __toESM(require_main(), 1);
@@ -110426,17 +111495,18 @@ var init_ProbeAgent = __esm({
110426
111495
  import_google2 = require("@ai-sdk/google");
110427
111496
  init_dist3();
110428
111497
  import_ai6 = require("ai");
110429
- import_crypto9 = require("crypto");
111498
+ import_crypto10 = require("crypto");
110430
111499
  import_events4 = require("events");
110431
111500
  import_fs14 = require("fs");
110432
111501
  import_promises6 = require("fs/promises");
110433
- import_path17 = require("path");
111502
+ import_path18 = require("path");
110434
111503
  init_tokenCounter();
110435
111504
  init_InMemoryStorageAdapter();
110436
111505
  init_HookManager();
110437
111506
  init_imageConfig();
110438
111507
  init_tools2();
110439
111508
  init_common2();
111509
+ init_fileTracker();
110440
111510
  init_probeTool();
110441
111511
  init_mockProvider();
110442
111512
  init_index();
@@ -110478,7 +111548,7 @@ var init_ProbeAgent = __esm({
110478
111548
  * @param {string} [options.customPrompt] - Custom prompt to replace the default system message
110479
111549
  * @param {string} [options.systemPrompt] - Alias for customPrompt; takes precedence when both are provided
110480
111550
  * @param {string} [options.promptType] - Predefined prompt type (code-explorer, code-searcher, architect, code-review, support)
110481
- * @param {boolean} [options.allowEdit=false] - Allow the use of the 'implement' tool
111551
+ * @param {boolean} [options.allowEdit=false] - Allow the use of the 'edit' and 'create' tools
110482
111552
  * @param {boolean} [options.enableDelegate=false] - Enable the delegate tool for task distribution to subagents
110483
111553
  * @param {boolean} [options.enableExecutePlan=false] - Enable the execute_plan DSL orchestration tool
110484
111554
  * @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)
@@ -110523,10 +111593,11 @@ var init_ProbeAgent = __esm({
110523
111593
  * @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.
110524
111594
  */
110525
111595
  constructor(options = {}) {
110526
- this.sessionId = options.sessionId || (0, import_crypto9.randomUUID)();
111596
+ this.sessionId = options.sessionId || (0, import_crypto10.randomUUID)();
110527
111597
  this.customPrompt = options.systemPrompt || options.customPrompt || null;
110528
111598
  this.promptType = options.promptType || "code-explorer";
110529
111599
  this.allowEdit = !!options.allowEdit;
111600
+ this.hashLines = options.hashLines !== void 0 ? !!options.hashLines : this.allowEdit;
110530
111601
  this.enableDelegate = !!options.enableDelegate;
110531
111602
  this.enableExecutePlan = !!options.enableExecutePlan;
110532
111603
  this.debug = options.debug || process.env.DEBUG === "1";
@@ -110588,7 +111659,8 @@ var init_ProbeAgent = __esm({
110588
111659
  if (this.debug) {
110589
111660
  console.log(`[DEBUG] Generated session ID for agent: ${this.sessionId}`);
110590
111661
  console.log(`[DEBUG] Maximum tool iterations configured: ${MAX_TOOL_ITERATIONS}`);
110591
- console.log(`[DEBUG] Allow Edit (implement tool): ${this.allowEdit}`);
111662
+ console.log(`[DEBUG] Allow Edit: ${this.allowEdit}`);
111663
+ console.log(`[DEBUG] Hash Lines: ${this.hashLines}`);
110592
111664
  console.log(`[DEBUG] Search delegation enabled: ${this.searchDelegate}`);
110593
111665
  console.log(`[DEBUG] Workspace root: ${this.workspaceRoot}`);
110594
111666
  console.log(`[DEBUG] Working directory (cwd): ${this.cwd}`);
@@ -110973,9 +112045,12 @@ var init_ProbeAgent = __esm({
110973
112045
  cwd: this.cwd,
110974
112046
  workspaceRoot: this.workspaceRoot,
110975
112047
  allowedFolders: this.allowedFolders,
112048
+ // File state tracking for safe multi-edit workflows (only when editing is enabled)
112049
+ fileTracker: this.allowEdit ? new FileTracker({ debug: this.debug }) : null,
110976
112050
  outline: this.outline,
110977
112051
  searchDelegate: this.searchDelegate,
110978
112052
  allowEdit: this.allowEdit,
112053
+ hashLines: this.hashLines,
110979
112054
  enableDelegate: this.enableDelegate,
110980
112055
  enableExecutePlan: this.enableExecutePlan,
110981
112056
  enableBash: this.enableBash,
@@ -111046,7 +112121,7 @@ var init_ProbeAgent = __esm({
111046
112121
  if (!imagePath) {
111047
112122
  throw new Error("Image path is required");
111048
112123
  }
111049
- const filename = (0, import_path17.basename)(imagePath);
112124
+ const filename = (0, import_path18.basename)(imagePath);
111050
112125
  const extension = filename.toLowerCase().split(".").pop();
111051
112126
  if (!extension || !SUPPORTED_IMAGE_EXTENSIONS.includes(extension)) {
111052
112127
  throw new Error(`Invalid or unsupported image extension: ${extension}. Supported formats: ${SUPPORTED_IMAGE_EXTENSIONS.join(", ")}`);
@@ -111760,7 +112835,7 @@ var init_ProbeAgent = __esm({
111760
112835
  let resolvedPath2 = imagePath;
111761
112836
  if (!imagePath.includes("/") && !imagePath.includes("\\")) {
111762
112837
  for (const dir of listFilesDirectories) {
111763
- const potentialPath = (0, import_path17.resolve)(dir, imagePath);
112838
+ const potentialPath = (0, import_path18.resolve)(dir, imagePath);
111764
112839
  const loaded = await this.loadImageIfValid(potentialPath);
111765
112840
  if (loaded) {
111766
112841
  if (this.debug) {
@@ -111785,7 +112860,7 @@ var init_ProbeAgent = __esm({
111785
112860
  let match2;
111786
112861
  while ((match2 = fileHeaderPattern.exec(content)) !== null) {
111787
112862
  const filePath = match2[1].trim();
111788
- const dir = (0, import_path17.dirname)(filePath);
112863
+ const dir = (0, import_path18.dirname)(filePath);
111789
112864
  if (dir && dir !== ".") {
111790
112865
  directories.push(dir);
111791
112866
  if (this.debug) {
@@ -111830,17 +112905,17 @@ var init_ProbeAgent = __esm({
111830
112905
  const allowedDirs = this.allowedFolders && this.allowedFolders.length > 0 ? this.allowedFolders : [process.cwd()];
111831
112906
  let absolutePath;
111832
112907
  let isPathAllowed2 = false;
111833
- if ((0, import_path17.isAbsolute)(imagePath)) {
111834
- absolutePath = safeRealpath((0, import_path17.resolve)(imagePath));
112908
+ if ((0, import_path18.isAbsolute)(imagePath)) {
112909
+ absolutePath = safeRealpath((0, import_path18.resolve)(imagePath));
111835
112910
  isPathAllowed2 = allowedDirs.some((dir) => {
111836
112911
  const resolvedDir = safeRealpath(dir);
111837
- return absolutePath === resolvedDir || absolutePath.startsWith(resolvedDir + import_path17.sep);
112912
+ return absolutePath === resolvedDir || absolutePath.startsWith(resolvedDir + import_path18.sep);
111838
112913
  });
111839
112914
  } else {
111840
112915
  for (const dir of allowedDirs) {
111841
112916
  const resolvedDir = safeRealpath(dir);
111842
- const resolvedPath2 = safeRealpath((0, import_path17.resolve)(dir, imagePath));
111843
- if (resolvedPath2 === resolvedDir || resolvedPath2.startsWith(resolvedDir + import_path17.sep)) {
112917
+ const resolvedPath2 = safeRealpath((0, import_path18.resolve)(dir, imagePath));
112918
+ if (resolvedPath2 === resolvedDir || resolvedPath2.startsWith(resolvedDir + import_path18.sep)) {
111844
112919
  absolutePath = resolvedPath2;
111845
112920
  isPathAllowed2 = true;
111846
112921
  break;
@@ -112028,8 +113103,8 @@ var init_ProbeAgent = __esm({
112028
113103
  const hasConfiguredName = !!configuredName;
112029
113104
  let guidanceCandidates = [];
112030
113105
  if (hasConfiguredName) {
112031
- const targetName = (0, import_path17.basename)(configuredName);
112032
- if (configuredName !== targetName || configuredName.includes("/") || configuredName.includes("\\") || configuredName.includes("..") || (0, import_path17.isAbsolute)(configuredName)) {
113106
+ const targetName = (0, import_path18.basename)(configuredName);
113107
+ if (configuredName !== targetName || configuredName.includes("/") || configuredName.includes("\\") || configuredName.includes("..") || (0, import_path18.isAbsolute)(configuredName)) {
112033
113108
  console.warn(`[WARN] Invalid architectureFileName (must be a simple filename): ${configuredName}`);
112034
113109
  } else if (targetName) {
112035
113110
  const targetLower = targetName.toLowerCase();
@@ -112096,7 +113171,7 @@ var init_ProbeAgent = __esm({
112096
113171
  pushEntry(architectureMatch);
112097
113172
  const contexts = [];
112098
113173
  for (const entry of uniqueEntries) {
112099
- const filePath = (0, import_path17.resolve)(rootDirectory, entry.name);
113174
+ const filePath = (0, import_path18.resolve)(rootDirectory, entry.name);
112100
113175
  try {
112101
113176
  const content = await (0, import_promises6.readFile)(filePath, "utf8");
112102
113177
  let kind = "other";
@@ -112161,10 +113236,10 @@ ${this.architectureContext.content}
112161
113236
  }
112162
113237
  _getSkillsRepoRoot() {
112163
113238
  if (this.workspaceRoot) {
112164
- return (0, import_path17.resolve)(this.workspaceRoot);
113239
+ return (0, import_path18.resolve)(this.workspaceRoot);
112165
113240
  }
112166
113241
  if (this.allowedFolders && this.allowedFolders.length > 0) {
112167
- return (0, import_path17.resolve)(this.allowedFolders[0]);
113242
+ return (0, import_path18.resolve)(this.allowedFolders[0]);
112168
113243
  }
112169
113244
  return process.cwd();
112170
113245
  }
@@ -112353,10 +113428,6 @@ Workspace: ${this.allowedFolders.join(", ")}`;
112353
113428
  }
112354
113429
  if (isToolAllowed("readImage")) {
112355
113430
  toolDefinitions += `${readImageToolDefinition}
112356
- `;
112357
- }
112358
- if (this.allowEdit && isToolAllowed("implement")) {
112359
- toolDefinitions += `${implementToolDefinition}
112360
113431
  `;
112361
113432
  }
112362
113433
  if (this.allowEdit && isToolAllowed("edit")) {
@@ -112438,7 +113509,7 @@ The configuration is loaded from src/config.js lines 15-25 which contains the da
112438
113509
  availableToolsList += "- query: Search code using structural AST patterns.\n";
112439
113510
  }
112440
113511
  if (isToolAllowed("extract")) {
112441
- availableToolsList += "- extract: Extract specific code blocks or lines from files.\n";
113512
+ 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';
112442
113513
  }
112443
113514
  if (isToolAllowed("listFiles")) {
112444
113515
  availableToolsList += "- listFiles: List files and directories in a specified location.\n";
@@ -112455,11 +113526,8 @@ The configuration is loaded from src/config.js lines 15-25 which contains the da
112455
113526
  if (isToolAllowed("readImage")) {
112456
113527
  availableToolsList += "- readImage: Read and load an image file for AI analysis.\n";
112457
113528
  }
112458
- if (this.allowEdit && isToolAllowed("implement")) {
112459
- availableToolsList += "- implement: Implement a feature or fix a bug using aider.\n";
112460
- }
112461
113529
  if (this.allowEdit && isToolAllowed("edit")) {
112462
- availableToolsList += "- edit: Edit files using exact string replacement.\n";
113530
+ availableToolsList += "- edit: Edit files using text replacement, AST-aware symbol operations, or line-targeted editing.\n";
112463
113531
  }
112464
113532
  if (this.allowEdit && isToolAllowed("create")) {
112465
113533
  availableToolsList += "- create: Create new files with specified content.\n";
@@ -112547,8 +113615,14 @@ Follow these instructions carefully:
112547
113615
  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.
112548
113616
  9. Prefer concise and focused search queries. Use specific keywords and phrases to narrow down results.${this.allowEdit ? `
112549
113617
  10. When modifying files, choose the appropriate tool:
112550
- - Use 'edit' for precise changes to existing files (requires exact string match)
112551
- - Use 'create' for new files or complete file rewrites` : ""}
113618
+ - Use 'edit' for all code modifications:
113619
+ * For small changes (a line or a few lines), use old_string + new_string \u2014 copy old_string verbatim from the file.
113620
+ * For rewriting entire functions/classes/methods, use the symbol parameter instead (no exact text matching needed).
113621
+ * 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.' : ""}
113622
+ * 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.
113623
+ - Use 'create' for new files or complete file rewrites.
113624
+ - If an edit fails, read the error message \u2014 it tells you exactly how to fix the call and retry.
113625
+ - 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.` : ""}
112552
113626
  </instructions>
112553
113627
  `;
112554
113628
  let systemMessage = "";
@@ -113048,8 +114122,11 @@ You are working with a workspace. Available paths: ${workspaceDesc}
113048
114122
  if (this.enableSkills && this.allowedTools.isEnabled("useSkill")) validTools.push("useSkill");
113049
114123
  if (this.allowedTools.isEnabled("readImage")) validTools.push("readImage");
113050
114124
  validTools.push("attempt_completion");
113051
- if (this.allowEdit && this.allowedTools.isEnabled("implement")) {
113052
- validTools.push("implement", "edit", "create");
114125
+ if (this.allowEdit && this.allowedTools.isEnabled("edit")) {
114126
+ validTools.push("edit");
114127
+ }
114128
+ if (this.allowEdit && this.allowedTools.isEnabled("create")) {
114129
+ validTools.push("create");
113053
114130
  }
113054
114131
  if (this.enableBash && this.allowedTools.isEnabled("bash")) {
113055
114132
  validTools.push("bash");
@@ -113271,10 +114348,10 @@ ${errorXml}
113271
114348
  try {
113272
114349
  let resolvedWorkingDirectory = this.workspaceRoot || this.cwd || this.allowedFolders && this.allowedFolders[0] || process.cwd();
113273
114350
  if (params.workingDirectory) {
113274
- const requestedDir = safeRealpath((0, import_path17.isAbsolute)(params.workingDirectory) ? (0, import_path17.resolve)(params.workingDirectory) : (0, import_path17.resolve)(resolvedWorkingDirectory, params.workingDirectory));
114351
+ const requestedDir = safeRealpath((0, import_path18.isAbsolute)(params.workingDirectory) ? (0, import_path18.resolve)(params.workingDirectory) : (0, import_path18.resolve)(resolvedWorkingDirectory, params.workingDirectory));
113275
114352
  const isWithinAllowed = !this.allowedFolders || this.allowedFolders.length === 0 || this.allowedFolders.some((folder) => {
113276
114353
  const resolvedFolder = safeRealpath(folder);
113277
- return requestedDir === resolvedFolder || requestedDir.startsWith(resolvedFolder + import_path17.sep);
114354
+ return requestedDir === resolvedFolder || requestedDir.startsWith(resolvedFolder + import_path18.sep);
113278
114355
  });
113279
114356
  if (isWithinAllowed) {
113280
114357
  resolvedWorkingDirectory = requestedDir;
@@ -113342,6 +114419,8 @@ ${errorXml}
113342
114419
  // Inherit bash enablement
113343
114420
  bashConfig: this.bashConfig,
113344
114421
  // Inherit bash configuration
114422
+ allowEdit: this.allowEdit,
114423
+ // Inherit edit/create permission
113345
114424
  allowedTools: allowedToolsForDelegate,
113346
114425
  // Inherit allowed tools from parent
113347
114426
  debug: this.debug,
@@ -113414,7 +114493,7 @@ ${errorXml}
113414
114493
  currentMessages.push({ role: "assistant", content: assistantResponseContent });
113415
114494
  let toolResultContent = typeof toolResult === "string" ? toolResult : JSON.stringify(toolResult, null, 2);
113416
114495
  if (this.workspaceRoot && toolResultContent) {
113417
- const wsPrefix = this.workspaceRoot.endsWith(import_path17.sep) ? this.workspaceRoot : this.workspaceRoot + import_path17.sep;
114496
+ const wsPrefix = this.workspaceRoot.endsWith(import_path18.sep) ? this.workspaceRoot : this.workspaceRoot + import_path18.sep;
113418
114497
  toolResultContent = toolResultContent.split(wsPrefix).join("");
113419
114498
  }
113420
114499
  const { cleanedContent, extractedBlocks } = extractRawOutputBlocks(toolResultContent);
@@ -113502,6 +114581,25 @@ ${errorXml}
113502
114581
  }
113503
114582
  break;
113504
114583
  }
114584
+ if (options.schema) {
114585
+ let contentToCheck = assistantResponseContent;
114586
+ contentToCheck = contentToCheck.replace(/<thinking>[\s\S]*?<\/thinking>/gi, "").trim();
114587
+ contentToCheck = contentToCheck.replace(/<thinking>[\s\S]*$/gi, "").trim();
114588
+ const cleanedJson = cleanSchemaResponse(contentToCheck);
114589
+ try {
114590
+ JSON.parse(cleanedJson);
114591
+ const validation = validateJsonResponse(cleanedJson, { debug: this.debug, schema: options.schema });
114592
+ if (validation.isValid) {
114593
+ if (this.debug) {
114594
+ console.log(`[DEBUG] Issue #443: Accepting valid JSON response without attempt_completion (${cleanedJson.length} chars)`);
114595
+ }
114596
+ finalResult = cleanedJson;
114597
+ completionAttempted = true;
114598
+ break;
114599
+ }
114600
+ } catch {
114601
+ }
114602
+ }
113505
114603
  consecutiveNoToolCount++;
113506
114604
  const isIdentical = lastNoToolResponse !== null && assistantResponseContent === lastNoToolResponse;
113507
114605
  const isSemanticallyStuck = lastNoToolResponse !== null && areBothStuckResponses(lastNoToolResponse, assistantResponseContent);
@@ -114245,7 +115343,7 @@ Convert your previous response content into actual JSON data that follows this s
114245
115343
  */
114246
115344
  clone(options = {}) {
114247
115345
  const {
114248
- sessionId = (0, import_crypto9.randomUUID)(),
115346
+ sessionId = (0, import_crypto10.randomUUID)(),
114249
115347
  stripInternalMessages = true,
114250
115348
  keepSystemMessage = true,
114251
115349
  deepCopy = true,