@probelabs/probe 0.6.0-rc225 → 0.6.0-rc227

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 (30) hide show
  1. package/bin/binaries/probe-v0.6.0-rc227-aarch64-apple-darwin.tar.gz +0 -0
  2. package/bin/binaries/probe-v0.6.0-rc227-aarch64-unknown-linux-musl.tar.gz +0 -0
  3. package/bin/binaries/probe-v0.6.0-rc227-x86_64-apple-darwin.tar.gz +0 -0
  4. package/bin/binaries/probe-v0.6.0-rc227-x86_64-pc-windows-msvc.zip +0 -0
  5. package/bin/binaries/probe-v0.6.0-rc227-x86_64-unknown-linux-musl.tar.gz +0 -0
  6. package/build/agent/ProbeAgent.d.ts +24 -0
  7. package/build/agent/ProbeAgent.js +310 -141
  8. package/build/agent/engines/enhanced-claude-code.js +72 -3
  9. package/build/agent/index.js +386 -129
  10. package/build/tools/analyzeAll.js +6 -1
  11. package/build/tools/bash.js +18 -3
  12. package/build/tools/edit.js +19 -10
  13. package/build/tools/vercel.js +17 -7
  14. package/build/utils/path-validation.js +148 -1
  15. package/cjs/agent/ProbeAgent.cjs +683 -389
  16. package/cjs/index.cjs +680 -389
  17. package/package.json +1 -1
  18. package/src/agent/ProbeAgent.d.ts +24 -0
  19. package/src/agent/ProbeAgent.js +310 -141
  20. package/src/agent/engines/enhanced-claude-code.js +72 -3
  21. package/src/tools/analyzeAll.js +6 -1
  22. package/src/tools/bash.js +18 -3
  23. package/src/tools/edit.js +19 -10
  24. package/src/tools/vercel.js +17 -7
  25. package/src/utils/path-validation.js +148 -1
  26. package/bin/binaries/probe-v0.6.0-rc225-aarch64-apple-darwin.tar.gz +0 -0
  27. package/bin/binaries/probe-v0.6.0-rc225-aarch64-unknown-linux-musl.tar.gz +0 -0
  28. package/bin/binaries/probe-v0.6.0-rc225-x86_64-apple-darwin.tar.gz +0 -0
  29. package/bin/binaries/probe-v0.6.0-rc225-x86_64-pc-windows-msvc.zip +0 -0
  30. package/bin/binaries/probe-v0.6.0-rc225-x86_64-unknown-linux-musl.tar.gz +0 -0
@@ -14245,8 +14245,45 @@ var require_dist_cjs29 = __commonJS({
14245
14245
  }
14246
14246
  });
14247
14247
 
14248
- // node_modules/@aws-crypto/util/node_modules/@smithy/is-array-buffer/dist-cjs/index.js
14248
+ // node_modules/@aws-sdk/util-format-url/dist-cjs/index.js
14249
14249
  var require_dist_cjs30 = __commonJS({
14250
+ "node_modules/@aws-sdk/util-format-url/dist-cjs/index.js"(exports2) {
14251
+ "use strict";
14252
+ var querystringBuilder = require_dist_cjs14();
14253
+ function formatUrl(request) {
14254
+ const { port, query: query2 } = request;
14255
+ let { protocol, path: path9, hostname } = request;
14256
+ if (protocol && protocol.slice(-1) !== ":") {
14257
+ protocol += ":";
14258
+ }
14259
+ if (port) {
14260
+ hostname += `:${port}`;
14261
+ }
14262
+ if (path9 && path9.charAt(0) !== "/") {
14263
+ path9 = `/${path9}`;
14264
+ }
14265
+ let queryString = query2 ? querystringBuilder.buildQueryString(query2) : "";
14266
+ if (queryString && queryString[0] !== "?") {
14267
+ queryString = `?${queryString}`;
14268
+ }
14269
+ let auth = "";
14270
+ if (request.username != null || request.password != null) {
14271
+ const username = request.username ?? "";
14272
+ const password = request.password ?? "";
14273
+ auth = `${username}:${password}@`;
14274
+ }
14275
+ let fragment = "";
14276
+ if (request.fragment) {
14277
+ fragment = `#${request.fragment}`;
14278
+ }
14279
+ return `${protocol}//${auth}${hostname}${path9}${queryString}${fragment}`;
14280
+ }
14281
+ exports2.formatUrl = formatUrl;
14282
+ }
14283
+ });
14284
+
14285
+ // node_modules/@aws-crypto/util/node_modules/@smithy/is-array-buffer/dist-cjs/index.js
14286
+ var require_dist_cjs31 = __commonJS({
14250
14287
  "node_modules/@aws-crypto/util/node_modules/@smithy/is-array-buffer/dist-cjs/index.js"(exports2, module2) {
14251
14288
  var __defProp2 = Object.defineProperty;
14252
14289
  var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
@@ -14276,7 +14313,7 @@ var require_dist_cjs30 = __commonJS({
14276
14313
  });
14277
14314
 
14278
14315
  // node_modules/@aws-crypto/util/node_modules/@smithy/util-buffer-from/dist-cjs/index.js
14279
- var require_dist_cjs31 = __commonJS({
14316
+ var require_dist_cjs32 = __commonJS({
14280
14317
  "node_modules/@aws-crypto/util/node_modules/@smithy/util-buffer-from/dist-cjs/index.js"(exports2, module2) {
14281
14318
  var __defProp2 = Object.defineProperty;
14282
14319
  var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
@@ -14302,7 +14339,7 @@ var require_dist_cjs31 = __commonJS({
14302
14339
  fromString: () => fromString
14303
14340
  });
14304
14341
  module2.exports = __toCommonJS2(src_exports);
14305
- var import_is_array_buffer = require_dist_cjs30();
14342
+ var import_is_array_buffer = require_dist_cjs31();
14306
14343
  var import_buffer = require("buffer");
14307
14344
  var fromArrayBuffer = /* @__PURE__ */ __name((input, offset = 0, length = input.byteLength - offset) => {
14308
14345
  if (!(0, import_is_array_buffer.isArrayBuffer)(input)) {
@@ -14320,7 +14357,7 @@ var require_dist_cjs31 = __commonJS({
14320
14357
  });
14321
14358
 
14322
14359
  // node_modules/@aws-crypto/util/node_modules/@smithy/util-utf8/dist-cjs/index.js
14323
- var require_dist_cjs32 = __commonJS({
14360
+ var require_dist_cjs33 = __commonJS({
14324
14361
  "node_modules/@aws-crypto/util/node_modules/@smithy/util-utf8/dist-cjs/index.js"(exports2, module2) {
14325
14362
  var __defProp2 = Object.defineProperty;
14326
14363
  var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
@@ -14347,7 +14384,7 @@ var require_dist_cjs32 = __commonJS({
14347
14384
  toUtf8: () => toUtf811
14348
14385
  });
14349
14386
  module2.exports = __toCommonJS2(src_exports);
14350
- var import_util_buffer_from = require_dist_cjs31();
14387
+ var import_util_buffer_from = require_dist_cjs32();
14351
14388
  var fromUtf88 = /* @__PURE__ */ __name((input) => {
14352
14389
  const buf = (0, import_util_buffer_from.fromString)(input, "utf8");
14353
14390
  return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength / Uint8Array.BYTES_PER_ELEMENT);
@@ -14379,7 +14416,7 @@ var require_convertToBuffer = __commonJS({
14379
14416
  "use strict";
14380
14417
  Object.defineProperty(exports2, "__esModule", { value: true });
14381
14418
  exports2.convertToBuffer = void 0;
14382
- var util_utf8_1 = require_dist_cjs32();
14419
+ var util_utf8_1 = require_dist_cjs33();
14383
14420
  var fromUtf88 = typeof Buffer !== "undefined" && Buffer.from ? function(input) {
14384
14421
  return Buffer.from(input, "utf8");
14385
14422
  } : util_utf8_1.fromUtf8;
@@ -14826,7 +14863,7 @@ var require_main3 = __commonJS({
14826
14863
  });
14827
14864
 
14828
14865
  // node_modules/@smithy/eventstream-codec/dist-cjs/index.js
14829
- var require_dist_cjs33 = __commonJS({
14866
+ var require_dist_cjs34 = __commonJS({
14830
14867
  "node_modules/@smithy/eventstream-codec/dist-cjs/index.js"(exports2) {
14831
14868
  "use strict";
14832
14869
  var crc32 = require_main3();
@@ -15209,48 +15246,11 @@ var require_dist_cjs33 = __commonJS({
15209
15246
  }
15210
15247
  });
15211
15248
 
15212
- // node_modules/@aws-sdk/util-format-url/dist-cjs/index.js
15213
- var require_dist_cjs34 = __commonJS({
15214
- "node_modules/@aws-sdk/util-format-url/dist-cjs/index.js"(exports2) {
15215
- "use strict";
15216
- var querystringBuilder = require_dist_cjs14();
15217
- function formatUrl(request) {
15218
- const { port, query: query2 } = request;
15219
- let { protocol, path: path9, hostname } = request;
15220
- if (protocol && protocol.slice(-1) !== ":") {
15221
- protocol += ":";
15222
- }
15223
- if (port) {
15224
- hostname += `:${port}`;
15225
- }
15226
- if (path9 && path9.charAt(0) !== "/") {
15227
- path9 = `/${path9}`;
15228
- }
15229
- let queryString = query2 ? querystringBuilder.buildQueryString(query2) : "";
15230
- if (queryString && queryString[0] !== "?") {
15231
- queryString = `?${queryString}`;
15232
- }
15233
- let auth = "";
15234
- if (request.username != null || request.password != null) {
15235
- const username = request.username ?? "";
15236
- const password = request.password ?? "";
15237
- auth = `${username}:${password}@`;
15238
- }
15239
- let fragment = "";
15240
- if (request.fragment) {
15241
- fragment = `#${request.fragment}`;
15242
- }
15243
- return `${protocol}//${auth}${hostname}${path9}${queryString}${fragment}`;
15244
- }
15245
- exports2.formatUrl = formatUrl;
15246
- }
15247
- });
15248
-
15249
15249
  // node_modules/@smithy/eventstream-serde-universal/dist-cjs/index.js
15250
15250
  var require_dist_cjs35 = __commonJS({
15251
15251
  "node_modules/@smithy/eventstream-serde-universal/dist-cjs/index.js"(exports2) {
15252
15252
  "use strict";
15253
- var eventstreamCodec = require_dist_cjs33();
15253
+ var eventstreamCodec = require_dist_cjs34();
15254
15254
  function getChunkedStream(source) {
15255
15255
  let currentMessageTotalLength = 0;
15256
15256
  let currentMessagePendingLength = 0;
@@ -15435,183 +15435,20 @@ var require_dist_cjs36 = __commonJS({
15435
15435
  var require_dist_cjs37 = __commonJS({
15436
15436
  "node_modules/@aws-sdk/middleware-websocket/dist-cjs/index.js"(exports2) {
15437
15437
  "use strict";
15438
- var eventstreamCodec = require_dist_cjs33();
15439
- var utilHexEncoding = require_dist_cjs17();
15440
- var protocolHttp = require_dist_cjs2();
15441
- var utilFormatUrl = require_dist_cjs34();
15438
+ var utilFormatUrl = require_dist_cjs30();
15442
15439
  var eventstreamSerdeBrowser = require_dist_cjs36();
15443
15440
  var fetchHttpHandler = require_dist_cjs16();
15444
- var getEventSigningTransformStream = (initialSignature, messageSigner, eventStreamCodec, systemClockOffsetProvider) => {
15445
- let priorSignature = initialSignature;
15446
- const transformer = {
15447
- start() {
15448
- },
15449
- async transform(chunk, controller) {
15450
- try {
15451
- const now = new Date(Date.now() + await systemClockOffsetProvider());
15452
- const dateHeader = {
15453
- ":date": { type: "timestamp", value: now }
15454
- };
15455
- const signedMessage = await messageSigner.sign({
15456
- message: {
15457
- body: chunk,
15458
- headers: dateHeader
15459
- },
15460
- priorSignature
15461
- }, {
15462
- signingDate: now
15463
- });
15464
- priorSignature = signedMessage.signature;
15465
- const serializedSigned = eventStreamCodec.encode({
15466
- headers: {
15467
- ...dateHeader,
15468
- ":chunk-signature": {
15469
- type: "binary",
15470
- value: utilHexEncoding.fromHex(signedMessage.signature)
15471
- }
15472
- },
15473
- body: chunk
15474
- });
15475
- controller.enqueue(serializedSigned);
15476
- } catch (error2) {
15477
- controller.error(error2);
15478
- }
15479
- }
15480
- };
15481
- return new TransformStream({ ...transformer });
15482
- };
15483
- var EventStreamPayloadHandler = class {
15484
- messageSigner;
15485
- eventStreamCodec;
15486
- systemClockOffsetProvider;
15487
- constructor(options) {
15488
- this.messageSigner = options.messageSigner;
15489
- this.eventStreamCodec = new eventstreamCodec.EventStreamCodec(options.utf8Encoder, options.utf8Decoder);
15490
- this.systemClockOffsetProvider = async () => options.systemClockOffset ?? 0;
15491
- }
15492
- async handle(next, args, context = {}) {
15493
- const request = args.request;
15494
- const { body: payload2, headers, query: query2 } = request;
15495
- if (!(payload2 instanceof ReadableStream)) {
15496
- throw new Error("Eventstream payload must be a ReadableStream.");
15497
- }
15498
- const placeHolderStream = new TransformStream();
15499
- request.body = placeHolderStream.readable;
15500
- const match2 = (headers?.authorization ?? "").match(/Signature=(\w+)$/);
15501
- const priorSignature = (match2 ?? [])[1] ?? (query2 && query2["X-Amz-Signature"]) ?? "";
15502
- const signingStream = getEventSigningTransformStream(priorSignature, await this.messageSigner(), this.eventStreamCodec, this.systemClockOffsetProvider);
15503
- payload2.pipeThrough(signingStream).pipeThrough(placeHolderStream);
15504
- let result;
15505
- try {
15506
- result = await next(args);
15507
- } catch (e5) {
15508
- const p5 = payload2.cancel?.();
15509
- if (p5 instanceof Promise) {
15510
- p5.catch(() => {
15511
- });
15512
- }
15513
- throw e5;
15514
- }
15515
- return result;
15516
- }
15517
- };
15518
- var eventStreamPayloadHandlerProvider = (options) => new EventStreamPayloadHandler(options);
15519
- var injectSessionIdMiddleware = () => (next) => async (args) => {
15520
- const requestParams = {
15521
- ...args.input
15522
- };
15523
- const response = await next(args);
15524
- const output = response.output;
15525
- if (requestParams.SessionId && output.SessionId == null) {
15526
- output.SessionId = requestParams.SessionId;
15527
- }
15528
- return response;
15529
- };
15530
- var injectSessionIdMiddlewareOptions = {
15531
- step: "initialize",
15532
- name: "injectSessionIdMiddleware",
15533
- tags: ["WEBSOCKET", "EVENT_STREAM"],
15534
- override: true
15535
- };
15536
- var websocketEndpointMiddleware = (config, options) => (next) => (args) => {
15537
- const { request } = args;
15538
- if (protocolHttp.HttpRequest.isInstance(request) && config.requestHandler.metadata?.handlerProtocol?.toLowerCase().includes("websocket")) {
15539
- request.protocol = "wss:";
15540
- request.method = "GET";
15541
- request.path = `${request.path}-websocket`;
15542
- const { headers } = request;
15543
- delete headers["content-type"];
15544
- delete headers["x-amz-content-sha256"];
15545
- for (const name14 of Object.keys(headers)) {
15546
- if (name14.indexOf(options.headerPrefix) === 0) {
15547
- const chunkedName = name14.replace(options.headerPrefix, "");
15548
- request.query[chunkedName] = headers[name14];
15549
- }
15550
- }
15551
- if (headers["x-amz-user-agent"]) {
15552
- request.query["user-agent"] = headers["x-amz-user-agent"];
15553
- }
15554
- request.headers = { host: headers.host ?? request.hostname };
15555
- }
15556
- return next(args);
15557
- };
15558
- var websocketEndpointMiddlewareOptions = {
15559
- name: "websocketEndpointMiddleware",
15560
- tags: ["WEBSOCKET", "EVENT_STREAM"],
15561
- relation: "after",
15562
- toMiddleware: "eventStreamHeaderMiddleware",
15563
- override: true
15564
- };
15565
- var getWebSocketPlugin = (config, options) => ({
15566
- applyToStack: (clientStack) => {
15567
- clientStack.addRelativeTo(websocketEndpointMiddleware(config, options), websocketEndpointMiddlewareOptions);
15568
- clientStack.add(injectSessionIdMiddleware(), injectSessionIdMiddlewareOptions);
15569
- }
15570
- });
15441
+ var protocolHttp = require_dist_cjs2();
15442
+ var utilBase64 = require_dist_cjs12();
15443
+ var eventstreamCodec = require_dist_cjs34();
15444
+ var utilHexEncoding = require_dist_cjs17();
15571
15445
  var isWebSocketRequest = (request) => request.protocol === "ws:" || request.protocol === "wss:";
15572
- var WebsocketSignatureV4 = class {
15573
- signer;
15574
- constructor(options) {
15575
- this.signer = options.signer;
15576
- }
15577
- presign(originalRequest, options = {}) {
15578
- return this.signer.presign(originalRequest, options);
15579
- }
15580
- async sign(toSign, options) {
15581
- if (protocolHttp.HttpRequest.isInstance(toSign) && isWebSocketRequest(toSign)) {
15582
- const signedRequest = await this.signer.presign({ ...toSign, body: "" }, {
15583
- ...options,
15584
- expiresIn: 60,
15585
- unsignableHeaders: new Set(Object.keys(toSign.headers).filter((header) => header !== "host"))
15586
- });
15587
- return {
15588
- ...signedRequest,
15589
- body: toSign.body
15590
- };
15591
- } else {
15592
- return this.signer.sign(toSign, options);
15593
- }
15594
- }
15595
- };
15596
- var resolveWebSocketConfig = (input) => {
15597
- const { signer } = input;
15598
- return Object.assign(input, {
15599
- signer: async (authScheme) => {
15600
- const signerObj = await signer(authScheme);
15601
- if (validateSigner(signerObj)) {
15602
- return new WebsocketSignatureV4({ signer: signerObj });
15603
- }
15604
- throw new Error("Expected WebsocketSignatureV4 signer, please check the client constructor.");
15605
- }
15606
- });
15607
- };
15608
- var validateSigner = (signer) => !!signer;
15609
- var DEFAULT_WS_CONNECTION_TIMEOUT_MS = 2e3;
15446
+ var DEFAULT_WS_CONNECTION_TIMEOUT_MS = 3e3;
15610
15447
  var WebSocketFetchHandler = class _WebSocketFetchHandler {
15611
15448
  metadata = {
15612
15449
  handlerProtocol: "websocket/h1.1"
15613
15450
  };
15614
- config;
15451
+ config = {};
15615
15452
  configPromise;
15616
15453
  httpHandler;
15617
15454
  sockets = {};
@@ -15623,12 +15460,19 @@ var require_dist_cjs37 = __commonJS({
15623
15460
  }
15624
15461
  constructor(options, httpHandler = new fetchHttpHandler.FetchHttpHandler()) {
15625
15462
  this.httpHandler = httpHandler;
15463
+ const setConfig = (opts) => {
15464
+ this.config = {
15465
+ ...opts ?? {}
15466
+ };
15467
+ return this.config;
15468
+ };
15626
15469
  if (typeof options === "function") {
15627
15470
  this.config = {};
15628
- this.configPromise = options().then((opts) => this.config = opts ?? {});
15471
+ this.configPromise = options().then((opts) => {
15472
+ return setConfig(opts);
15473
+ });
15629
15474
  } else {
15630
- this.config = options ?? {};
15631
- this.configPromise = Promise.resolve(this.config);
15475
+ this.configPromise = Promise.resolve(setConfig(options));
15632
15476
  }
15633
15477
  }
15634
15478
  destroy() {
@@ -15640,17 +15484,20 @@ var require_dist_cjs37 = __commonJS({
15640
15484
  }
15641
15485
  }
15642
15486
  async handle(request) {
15487
+ this.config = await this.configPromise;
15488
+ const { logger: logger2 } = this.config;
15643
15489
  if (!isWebSocketRequest(request)) {
15490
+ logger2?.debug?.(`@aws-sdk - ws fetching ${request.protocol}${request.hostname}${request.path}`);
15644
15491
  return this.httpHandler.handle(request);
15645
15492
  }
15646
15493
  const url = utilFormatUrl.formatUrl(request);
15494
+ logger2?.debug?.(`@aws-sdk - ws connecting ${url.split("?")[0]}`);
15647
15495
  const socket = new WebSocket(url);
15648
15496
  if (!this.sockets[url]) {
15649
15497
  this.sockets[url] = [];
15650
15498
  }
15651
15499
  this.sockets[url].push(socket);
15652
15500
  socket.binaryType = "arraybuffer";
15653
- this.config = await this.configPromise;
15654
15501
  const { connectionTimeout = DEFAULT_WS_CONNECTION_TIMEOUT_MS } = this.config;
15655
15502
  await this.waitForReady(socket, connectionTimeout);
15656
15503
  const { body } = request;
@@ -15682,7 +15529,8 @@ var require_dist_cjs37 = __commonJS({
15682
15529
  this.removeNotUsableSockets(socket.url);
15683
15530
  reject2({
15684
15531
  $metadata: {
15685
- httpStatusCode: 500
15532
+ httpStatusCode: 500,
15533
+ websocketSynthetic500Error: true
15686
15534
  }
15687
15535
  });
15688
15536
  }, connectionTimeout);
@@ -15693,42 +15541,57 @@ var require_dist_cjs37 = __commonJS({
15693
15541
  });
15694
15542
  }
15695
15543
  connect(socket, data2) {
15696
- let streamError = void 0;
15697
- let socketErrorOccurred = false;
15698
- let reject2 = () => {
15699
- };
15700
- let resolve7 = () => {
15544
+ const messageQueue = [];
15545
+ let pendingResolve = null;
15546
+ let pendingReject = null;
15547
+ const push = (item) => {
15548
+ if (pendingResolve) {
15549
+ if (item.error) {
15550
+ pendingReject(item.error);
15551
+ } else {
15552
+ pendingResolve({ done: item.done, value: item.value });
15553
+ }
15554
+ pendingResolve = null;
15555
+ pendingReject = null;
15556
+ } else {
15557
+ messageQueue.push(item);
15558
+ }
15701
15559
  };
15702
15560
  socket.onmessage = (event) => {
15703
- resolve7({
15704
- done: false,
15705
- value: new Uint8Array(event.data)
15706
- });
15561
+ const { data: data3 } = event;
15562
+ if (typeof data3 === "string") {
15563
+ push({
15564
+ done: false,
15565
+ value: utilBase64.fromBase64(data3)
15566
+ });
15567
+ } else {
15568
+ push({
15569
+ done: false,
15570
+ value: new Uint8Array(data3)
15571
+ });
15572
+ }
15707
15573
  };
15708
- socket.onerror = (error2) => {
15709
- socketErrorOccurred = true;
15574
+ socket.onerror = (event) => {
15710
15575
  socket.close();
15711
- reject2(error2);
15576
+ push({ done: true, error: event });
15712
15577
  };
15713
15578
  socket.onclose = () => {
15714
15579
  this.removeNotUsableSockets(socket.url);
15715
- if (socketErrorOccurred)
15716
- return;
15717
- if (streamError) {
15718
- reject2(streamError);
15719
- } else {
15720
- resolve7({
15721
- done: true,
15722
- value: void 0
15723
- });
15724
- }
15580
+ push({ done: true });
15725
15581
  };
15726
15582
  const outputStream = {
15727
15583
  [Symbol.asyncIterator]: () => ({
15728
- next: () => {
15729
- return new Promise((_resolve, _reject) => {
15730
- resolve7 = _resolve;
15731
- reject2 = _reject;
15584
+ async next() {
15585
+ if (messageQueue.length > 0) {
15586
+ const item = messageQueue.shift();
15587
+ if (item.error) {
15588
+ throw item.error;
15589
+ }
15590
+ return { done: item.done, value: item.value };
15591
+ }
15592
+ return new Promise((resolve7, reject2) => {
15593
+ pendingResolve = resolve7;
15594
+ pendingReject = reject2;
15732
15595
  });
15733
15596
  }
15734
15597
  })
@@ -15743,7 +15606,10 @@ var require_dist_cjs37 = __commonJS({
15743
15606
  }
15744
15607
  }
15745
15608
  } catch (err) {
15746
- streamError = err;
15609
+ push({
15610
+ done: true,
15611
+ error: err
15612
+ });
15747
15613
  } finally {
15748
15614
  socket.close(1e3);
15749
15615
  }
@@ -15767,6 +15633,174 @@ var require_dist_cjs37 = __commonJS({
15767
15633
  };
15768
15634
  var toReadableStream = (asyncIterable) => typeof ReadableStream === "function" ? eventstreamSerdeBrowser.iterableToReadableStream(asyncIterable) : asyncIterable;
15769
15635
  var isReadableStream = (payload2) => typeof ReadableStream === "function" && payload2 instanceof ReadableStream;
15636
+ var websocketEndpointMiddleware = (config, options) => (next) => (args) => {
15637
+ const { request } = args;
15638
+ if (protocolHttp.HttpRequest.isInstance(request) && config.requestHandler.metadata?.handlerProtocol?.toLowerCase().includes("websocket")) {
15639
+ request.protocol = "wss:";
15640
+ request.method = "GET";
15641
+ request.path = `${request.path}-websocket`;
15642
+ const { headers } = request;
15643
+ delete headers["content-type"];
15644
+ delete headers["x-amz-content-sha256"];
15645
+ for (const name14 of Object.keys(headers)) {
15646
+ if (name14.indexOf(options.headerPrefix) === 0) {
15647
+ const chunkedName = name14.replace(options.headerPrefix, "");
15648
+ request.query[chunkedName] = headers[name14];
15649
+ }
15650
+ }
15651
+ if (headers["x-amz-user-agent"]) {
15652
+ request.query["user-agent"] = headers["x-amz-user-agent"];
15653
+ }
15654
+ request.headers = { host: headers.host ?? request.hostname };
15655
+ }
15656
+ return next(args);
15657
+ };
15658
+ var websocketEndpointMiddlewareOptions = {
15659
+ name: "websocketEndpointMiddleware",
15660
+ tags: ["WEBSOCKET", "EVENT_STREAM"],
15661
+ relation: "after",
15662
+ toMiddleware: "eventStreamHeaderMiddleware",
15663
+ override: true
15664
+ };
15665
+ var injectSessionIdMiddleware = () => (next) => async (args) => {
15666
+ const requestParams = {
15667
+ ...args.input
15668
+ };
15669
+ const response = await next(args);
15670
+ const output = response.output;
15671
+ if (requestParams.SessionId && output.SessionId == null) {
15672
+ output.SessionId = requestParams.SessionId;
15673
+ }
15674
+ return response;
15675
+ };
15676
+ var injectSessionIdMiddlewareOptions = {
15677
+ step: "initialize",
15678
+ name: "injectSessionIdMiddleware",
15679
+ tags: ["WEBSOCKET", "EVENT_STREAM"],
15680
+ override: true
15681
+ };
15682
+ var getWebSocketPlugin = (config, options) => ({
15683
+ applyToStack: (clientStack) => {
15684
+ clientStack.addRelativeTo(websocketEndpointMiddleware(config, options), websocketEndpointMiddlewareOptions);
15685
+ clientStack.add(injectSessionIdMiddleware(), injectSessionIdMiddlewareOptions);
15686
+ }
15687
+ });
15688
+ var WebsocketSignatureV4 = class {
15689
+ signer;
15690
+ constructor(options) {
15691
+ this.signer = options.signer;
15692
+ }
15693
+ presign(originalRequest, options = {}) {
15694
+ return this.signer.presign(originalRequest, options);
15695
+ }
15696
+ async sign(toSign, options) {
15697
+ if (protocolHttp.HttpRequest.isInstance(toSign) && isWebSocketRequest(toSign)) {
15698
+ const signedRequest = await this.signer.presign({ ...toSign, body: "" }, {
15699
+ ...options,
15700
+ expiresIn: 60,
15701
+ unsignableHeaders: new Set(Object.keys(toSign.headers).filter((header) => header !== "host"))
15702
+ });
15703
+ return {
15704
+ ...signedRequest,
15705
+ body: toSign.body
15706
+ };
15707
+ } else {
15708
+ return this.signer.sign(toSign, options);
15709
+ }
15710
+ }
15711
+ signMessage(message, args) {
15712
+ return this.signer.signMessage(message, args);
15713
+ }
15714
+ };
15715
+ var resolveWebSocketConfig = (input) => {
15716
+ const { signer } = input;
15717
+ return Object.assign(input, {
15718
+ signer: async (authScheme) => {
15719
+ const signerObj = await signer(authScheme);
15720
+ if (validateSigner(signerObj)) {
15721
+ return new WebsocketSignatureV4({ signer: signerObj });
15722
+ }
15723
+ throw new Error("Expected WebsocketSignatureV4 signer, please check the client constructor.");
15724
+ }
15725
+ });
15726
+ };
15727
+ var validateSigner = (signer) => !!signer;
15728
+ var EventSigningTransformStream = class extends TransformStream {
15729
+ constructor(initialSignature, messageSigner, eventStreamCodec, systemClockOffsetProvider) {
15730
+ let priorSignature = initialSignature;
15731
+ super({
15732
+ start() {
15733
+ },
15734
+ async transform(chunk, controller) {
15735
+ try {
15736
+ const now = new Date(Date.now() + await systemClockOffsetProvider());
15737
+ const dateHeader = {
15738
+ ":date": { type: "timestamp", value: now }
15739
+ };
15740
+ const signedMessage = await messageSigner.sign({
15741
+ message: {
15742
+ body: chunk,
15743
+ headers: dateHeader
15744
+ },
15745
+ priorSignature
15746
+ }, {
15747
+ signingDate: now
15748
+ });
15749
+ priorSignature = signedMessage.signature;
15750
+ const serializedSigned = eventStreamCodec.encode({
15751
+ headers: {
15752
+ ...dateHeader,
15753
+ ":chunk-signature": {
15754
+ type: "binary",
15755
+ value: utilHexEncoding.fromHex(signedMessage.signature)
15756
+ }
15757
+ },
15758
+ body: chunk
15759
+ });
15760
+ controller.enqueue(serializedSigned);
15761
+ } catch (error2) {
15762
+ controller.error(error2);
15763
+ }
15764
+ }
15765
+ });
15766
+ }
15767
+ };
15768
+ var EventStreamPayloadHandler = class {
15769
+ messageSigner;
15770
+ eventStreamCodec;
15771
+ systemClockOffsetProvider;
15772
+ constructor(options) {
15773
+ this.messageSigner = options.messageSigner;
15774
+ this.eventStreamCodec = new eventstreamCodec.EventStreamCodec(options.utf8Encoder, options.utf8Decoder);
15775
+ this.systemClockOffsetProvider = async () => options.systemClockOffset ?? 0;
15776
+ }
15777
+ async handle(next, args, context = {}) {
15778
+ const request = args.request;
15779
+ const { body: payload2, headers, query: query2 } = request;
15780
+ if (!(payload2 instanceof ReadableStream)) {
15781
+ throw new Error("Eventstream payload must be a ReadableStream.");
15782
+ }
15783
+ const placeHolderStream = new TransformStream();
15784
+ request.body = placeHolderStream.readable;
15785
+ const match2 = (headers?.authorization ?? "").match(/Signature=(\w+)$/);
15786
+ const priorSignature = (match2 ?? [])[1] ?? (query2 && query2["X-Amz-Signature"]) ?? "";
15787
+ const signingStream = new EventSigningTransformStream(priorSignature, await this.messageSigner(), this.eventStreamCodec, this.systemClockOffsetProvider);
15788
+ payload2.pipeThrough(signingStream).pipeThrough(placeHolderStream);
15789
+ let result;
15790
+ try {
15791
+ result = await next(args);
15792
+ } catch (e5) {
15793
+ const p5 = payload2.cancel?.();
15794
+ if (p5 instanceof Promise) {
15795
+ p5.catch(() => {
15796
+ });
15797
+ }
15798
+ throw e5;
15799
+ }
15800
+ return result;
15801
+ }
15802
+ };
15803
+ var eventStreamPayloadHandlerProvider = (options) => new EventStreamPayloadHandler(options);
15770
15804
  exports2.WebSocketFetchHandler = WebSocketFetchHandler;
15771
15805
  exports2.eventStreamPayloadHandlerProvider = eventStreamPayloadHandlerProvider;
15772
15806
  exports2.getWebSocketPlugin = getWebSocketPlugin;
@@ -17414,7 +17448,7 @@ var require_package2 = __commonJS({
17414
17448
  module2.exports = {
17415
17449
  name: "@aws-sdk/client-bedrock-runtime",
17416
17450
  description: "AWS SDK for JavaScript Bedrock Runtime Client for Node.js, Browser and React Native",
17417
- version: "3.983.0",
17451
+ version: "3.984.0",
17418
17452
  scripts: {
17419
17453
  build: "concurrently 'yarn:build:types' 'yarn:build:es' && yarn build:cjs",
17420
17454
  "build:cjs": "node ../../scripts/compilation/inline client-bedrock-runtime",
@@ -17436,17 +17470,17 @@ var require_package2 = __commonJS({
17436
17470
  "@aws-crypto/sha256-js": "5.2.0",
17437
17471
  "@aws-sdk/core": "^3.973.6",
17438
17472
  "@aws-sdk/credential-provider-node": "^3.972.5",
17439
- "@aws-sdk/eventstream-handler-node": "^3.972.4",
17473
+ "@aws-sdk/eventstream-handler-node": "^3.972.5",
17440
17474
  "@aws-sdk/middleware-eventstream": "^3.972.3",
17441
17475
  "@aws-sdk/middleware-host-header": "^3.972.3",
17442
17476
  "@aws-sdk/middleware-logger": "^3.972.3",
17443
17477
  "@aws-sdk/middleware-recursion-detection": "^3.972.3",
17444
17478
  "@aws-sdk/middleware-user-agent": "^3.972.6",
17445
- "@aws-sdk/middleware-websocket": "^3.972.4",
17479
+ "@aws-sdk/middleware-websocket": "^3.972.5",
17446
17480
  "@aws-sdk/region-config-resolver": "^3.972.3",
17447
- "@aws-sdk/token-providers": "3.983.0",
17481
+ "@aws-sdk/token-providers": "3.984.0",
17448
17482
  "@aws-sdk/types": "^3.973.1",
17449
- "@aws-sdk/util-endpoints": "3.983.0",
17483
+ "@aws-sdk/util-endpoints": "3.984.0",
17450
17484
  "@aws-sdk/util-user-agent-browser": "^3.972.3",
17451
17485
  "@aws-sdk/util-user-agent-node": "^3.972.4",
17452
17486
  "@smithy/config-resolver": "^4.4.6",
@@ -23758,9 +23792,9 @@ var require_dist_cjs65 = __commonJS({
23758
23792
  var require_dist_cjs66 = __commonJS({
23759
23793
  "node_modules/@aws-sdk/eventstream-handler-node/dist-cjs/index.js"(exports2) {
23760
23794
  "use strict";
23761
- var eventstreamCodec = require_dist_cjs33();
23762
- var stream2 = require("stream");
23763
- var EventSigningStream = class extends stream2.Transform {
23795
+ var eventstreamCodec = require_dist_cjs34();
23796
+ var node_stream = require("node:stream");
23797
+ var EventSigningTransformStream = class extends node_stream.Transform {
23764
23798
  priorSignature;
23765
23799
  messageSigner;
23766
23800
  eventStreamCodec;
@@ -23826,16 +23860,16 @@ var require_dist_cjs66 = __commonJS({
23826
23860
  async handle(next, args, context = {}) {
23827
23861
  const request = args.request;
23828
23862
  const { body: payload2, query: query2 } = request;
23829
- if (!(payload2 instanceof stream2.Readable)) {
23863
+ if (!(payload2 instanceof node_stream.Readable)) {
23830
23864
  throw new Error("Eventstream payload must be a Readable stream.");
23831
23865
  }
23832
23866
  const payloadStream = payload2;
23833
- request.body = new stream2.PassThrough({
23867
+ request.body = new node_stream.PassThrough({
23834
23868
  objectMode: true
23835
23869
  });
23836
23870
  const match2 = request.headers?.authorization?.match(/Signature=([\w]+)$/);
23837
23871
  const priorSignature = match2?.[1] ?? query2?.["X-Amz-Signature"] ?? "";
23838
- const signingStream = new EventSigningStream({
23872
+ const signingStream = new EventSigningTransformStream({
23839
23873
  priorSignature,
23840
23874
  eventStreamCodec: this.eventStreamCodec,
23841
23875
  messageSigner: await this.messageSigner(),
@@ -23844,7 +23878,7 @@ var require_dist_cjs66 = __commonJS({
23844
23878
  let resolvePipeline;
23845
23879
  const pipelineError = new Promise((resolve7, reject2) => {
23846
23880
  resolvePipeline = () => resolve7(void 0);
23847
- stream2.pipeline(payloadStream, signingStream, request.body, (err) => {
23881
+ node_stream.pipeline(payloadStream, signingStream, request.body, (err) => {
23848
23882
  if (err) {
23849
23883
  reject2(new Error(`Pipeline error in @aws-sdk/eventstream-handler-node: ${err.message}`, { cause: err }));
23850
23884
  }
@@ -23949,7 +23983,7 @@ var init_package2 = __esm({
23949
23983
  "node_modules/@aws-sdk/token-providers/node_modules/@aws-sdk/nested-clients/package.json"() {
23950
23984
  package_default2 = {
23951
23985
  name: "@aws-sdk/nested-clients",
23952
- version: "3.983.0",
23986
+ version: "3.984.0",
23953
23987
  description: "Nested clients for AWS SDK packages.",
23954
23988
  main: "./dist-cjs/index.js",
23955
23989
  module: "./dist-es/index.js",
@@ -23985,7 +24019,7 @@ var init_package2 = __esm({
23985
24019
  "@aws-sdk/middleware-user-agent": "^3.972.6",
23986
24020
  "@aws-sdk/region-config-resolver": "^3.972.3",
23987
24021
  "@aws-sdk/types": "^3.973.1",
23988
- "@aws-sdk/util-endpoints": "3.983.0",
24022
+ "@aws-sdk/util-endpoints": "3.984.0",
23989
24023
  "@aws-sdk/util-user-agent-browser": "^3.972.3",
23990
24024
  "@aws-sdk/util-user-agent-node": "^3.972.4",
23991
24025
  "@smithy/config-resolver": "^4.4.6",
@@ -32675,6 +32709,25 @@ var init_error_types = __esm({
32675
32709
  });
32676
32710
 
32677
32711
  // src/utils/path-validation.js
32712
+ function safeRealpath(inputPath) {
32713
+ try {
32714
+ return (0, import_fs3.realpathSync)(inputPath);
32715
+ } catch (error2) {
32716
+ const normalized = import_path4.default.normalize(inputPath);
32717
+ const parts = normalized.split(import_path4.default.sep);
32718
+ for (let i5 = parts.length - 1; i5 >= 0; i5--) {
32719
+ const ancestorPath = parts.slice(0, i5).join(import_path4.default.sep) || import_path4.default.sep;
32720
+ try {
32721
+ const resolvedAncestor = (0, import_fs3.realpathSync)(ancestorPath);
32722
+ const remainingParts = parts.slice(i5);
32723
+ return import_path4.default.join(resolvedAncestor, ...remainingParts);
32724
+ } catch (ancestorError) {
32725
+ continue;
32726
+ }
32727
+ }
32728
+ return normalized;
32729
+ }
32730
+ }
32678
32731
  async function validateCwdPath(inputPath, defaultPath = process.cwd()) {
32679
32732
  const targetPath = inputPath || defaultPath;
32680
32733
  const normalizedPath = import_path4.default.normalize(import_path4.default.resolve(targetPath));
@@ -32707,6 +32760,53 @@ async function validateCwdPath(inputPath, defaultPath = process.cwd()) {
32707
32760
  }
32708
32761
  return normalizedPath;
32709
32762
  }
32763
+ function getCommonPrefix(folders) {
32764
+ if (!folders || folders.length === 0) {
32765
+ return process.cwd();
32766
+ }
32767
+ if (folders.length === 1) {
32768
+ return safeRealpath(folders[0]);
32769
+ }
32770
+ const normalized = folders.map((f5) => safeRealpath(f5));
32771
+ const segments = normalized.map((f5) => f5.split(import_path4.default.sep));
32772
+ const minLen = Math.min(...segments.map((s5) => s5.length));
32773
+ const commonSegments = [];
32774
+ for (let i5 = 0; i5 < minLen; i5++) {
32775
+ const segment = segments[0][i5];
32776
+ if (segments.every((s5) => s5[i5] === segment)) {
32777
+ commonSegments.push(segment);
32778
+ } else {
32779
+ break;
32780
+ }
32781
+ }
32782
+ if (commonSegments.length === 0) {
32783
+ return normalized[0];
32784
+ }
32785
+ if (commonSegments.length === 1 && /^[a-zA-Z]:$/.test(commonSegments[0])) {
32786
+ return normalized[0];
32787
+ }
32788
+ if (commonSegments.length === 1 && commonSegments[0] === "") {
32789
+ return normalized[0];
32790
+ }
32791
+ return commonSegments.join(import_path4.default.sep);
32792
+ }
32793
+ function toRelativePath(absolutePath, workspaceRoot) {
32794
+ if (!absolutePath || !workspaceRoot) {
32795
+ return absolutePath;
32796
+ }
32797
+ let normalized = safeRealpath(absolutePath);
32798
+ let normalizedRoot = safeRealpath(workspaceRoot);
32799
+ while (normalizedRoot.length > 1 && normalizedRoot.endsWith(import_path4.default.sep)) {
32800
+ normalizedRoot = normalizedRoot.slice(0, -1);
32801
+ }
32802
+ if (normalized === normalizedRoot) {
32803
+ return ".";
32804
+ }
32805
+ if (normalized.startsWith(normalizedRoot + import_path4.default.sep)) {
32806
+ return import_path4.default.relative(normalizedRoot, normalized);
32807
+ }
32808
+ return absolutePath;
32809
+ }
32710
32810
  var import_path4, import_fs3;
32711
32811
  var init_path_validation = __esm({
32712
32812
  "src/utils/path-validation.js"() {
@@ -33904,6 +34004,7 @@ async function analyzeAll(options) {
33904
34004
  sessionId,
33905
34005
  debug = false,
33906
34006
  cwd,
34007
+ workspaceRoot,
33907
34008
  allowedFolders,
33908
34009
  provider,
33909
34010
  model,
@@ -33916,10 +34017,11 @@ async function analyzeAll(options) {
33916
34017
  if (!question) {
33917
34018
  throw new Error('The "question" parameter is required.');
33918
34019
  }
34020
+ const effectiveWorkspaceRoot = workspaceRoot || cwd || allowedFolders?.[0] || path9;
33919
34021
  const delegateOptions = {
33920
34022
  debug,
33921
34023
  sessionId,
33922
- path: allowedFolders?.[0] || cwd || path9,
34024
+ path: effectiveWorkspaceRoot,
33923
34025
  allowedFolders,
33924
34026
  provider,
33925
34027
  model,
@@ -38132,21 +38234,24 @@ var init_zod = __esm({
38132
38234
  // src/tools/edit.js
38133
38235
  function isPathAllowed(filePath, allowedFolders) {
38134
38236
  if (!allowedFolders || allowedFolders.length === 0) {
38135
- const resolvedPath3 = (0, import_path5.resolve)(filePath);
38136
- const cwd = (0, import_path5.resolve)(process.cwd());
38237
+ const resolvedPath3 = safeRealpath(filePath);
38238
+ const cwd = safeRealpath(process.cwd());
38137
38239
  return resolvedPath3 === cwd || resolvedPath3.startsWith(cwd + import_path5.sep);
38138
38240
  }
38139
- const resolvedPath2 = (0, import_path5.resolve)(filePath);
38241
+ const resolvedPath2 = safeRealpath(filePath);
38140
38242
  return allowedFolders.some((folder) => {
38141
- const allowedPath = (0, import_path5.resolve)(folder);
38243
+ const allowedPath = safeRealpath(folder);
38142
38244
  return resolvedPath2 === allowedPath || resolvedPath2.startsWith(allowedPath + import_path5.sep);
38143
38245
  });
38144
38246
  }
38145
38247
  function parseFileToolOptions(options = {}) {
38248
+ const allowedFolders = options.allowedFolders || [];
38146
38249
  return {
38147
38250
  debug: options.debug || false,
38148
- allowedFolders: options.allowedFolders || [],
38149
- cwd: options.cwd
38251
+ allowedFolders,
38252
+ cwd: options.cwd,
38253
+ // Consistent fallback chain: workspaceRoot > cwd > allowedFolders[0] > process.cwd()
38254
+ workspaceRoot: options.workspaceRoot || options.cwd || allowedFolders.length > 0 && allowedFolders[0] || process.cwd()
38150
38255
  };
38151
38256
  }
38152
38257
  var import_ai, import_fs4, import_path5, import_fs5, editTool, createTool, editSchema, createSchema, editDescription, createDescription, editToolDefinition, createToolDefinition;
@@ -38157,8 +38262,9 @@ var init_edit = __esm({
38157
38262
  import_fs4 = require("fs");
38158
38263
  import_path5 = require("path");
38159
38264
  import_fs5 = require("fs");
38265
+ init_path_validation();
38160
38266
  editTool = (options = {}) => {
38161
- const { debug, allowedFolders, cwd } = parseFileToolOptions(options);
38267
+ const { debug, allowedFolders, cwd, workspaceRoot } = parseFileToolOptions(options);
38162
38268
  return (0, import_ai.tool)({
38163
38269
  name: "edit",
38164
38270
  description: `Edit files using exact string replacement (Claude Code style).
@@ -38214,7 +38320,8 @@ Important:
38214
38320
  console.error(`[Edit] Attempting to edit file: ${resolvedPath2}`);
38215
38321
  }
38216
38322
  if (!isPathAllowed(resolvedPath2, allowedFolders)) {
38217
- return `Error editing file: Permission denied - ${file_path} is outside allowed directories`;
38323
+ const relativePath = toRelativePath(resolvedPath2, workspaceRoot);
38324
+ return `Error editing file: Permission denied - ${relativePath} is outside allowed directories`;
38218
38325
  }
38219
38326
  if (!(0, import_fs5.existsSync)(resolvedPath2)) {
38220
38327
  return `Error editing file: File not found - ${file_path}`;
@@ -38250,7 +38357,7 @@ Important:
38250
38357
  });
38251
38358
  };
38252
38359
  createTool = (options = {}) => {
38253
- const { debug, allowedFolders, cwd } = parseFileToolOptions(options);
38360
+ const { debug, allowedFolders, cwd, workspaceRoot } = parseFileToolOptions(options);
38254
38361
  return (0, import_ai.tool)({
38255
38362
  name: "create",
38256
38363
  description: `Create new files with specified content.
@@ -38298,7 +38405,8 @@ Important:
38298
38405
  console.error(`[Create] Attempting to create file: ${resolvedPath2}`);
38299
38406
  }
38300
38407
  if (!isPathAllowed(resolvedPath2, allowedFolders)) {
38301
- return `Error creating file: Permission denied - ${file_path} is outside allowed directories`;
38408
+ const relativePath = toRelativePath(resolvedPath2, workspaceRoot);
38409
+ return `Error creating file: Permission denied - ${relativePath} is outside allowed directories`;
38302
38410
  }
38303
38411
  if ((0, import_fs5.existsSync)(resolvedPath2) && !overwrite) {
38304
38412
  return `Error creating file: File already exists - ${file_path}. Use overwrite: true to replace it.`;
@@ -39860,7 +39968,7 @@ var init_vercel = __esm({
39860
39968
  });
39861
39969
  };
39862
39970
  delegateTool = (options = {}) => {
39863
- const { debug = false, timeout = 300, cwd, allowedFolders, enableBash = false, bashConfig, architectureFileName, enableMcp = false, mcpConfig = null, mcpConfigPath = null, delegationManager = null } = options;
39971
+ const { debug = false, timeout = 300, cwd, allowedFolders, workspaceRoot, enableBash = false, bashConfig, architectureFileName, enableMcp = false, mcpConfig = null, mcpConfigPath = null, delegationManager = null } = options;
39864
39972
  return (0, import_ai2.tool)({
39865
39973
  name: "delegate",
39866
39974
  description: delegateDescription,
@@ -39893,8 +40001,8 @@ var init_vercel = __esm({
39893
40001
  if (searchDelegate !== void 0 && typeof searchDelegate !== "boolean") {
39894
40002
  throw new TypeError("searchDelegate must be a boolean if provided");
39895
40003
  }
39896
- const workspaceRoot = allowedFolders && allowedFolders[0];
39897
- const effectivePath = path9 || workspaceRoot || cwd;
40004
+ const effectiveWorkspaceRoot = workspaceRoot || allowedFolders && allowedFolders[0];
40005
+ const effectivePath = path9 || effectiveWorkspaceRoot || cwd;
39898
40006
  if (debug) {
39899
40007
  console.error(`Executing delegate with task: "${task.substring(0, 100)}${task.length > 100 ? "..." : ""}"`);
39900
40008
  if (parentSessionId) {
@@ -39931,7 +40039,7 @@ var init_vercel = __esm({
39931
40039
  });
39932
40040
  };
39933
40041
  analyzeAllTool = (options = {}) => {
39934
- const { sessionId, debug = false, delegationManager = null } = options;
40042
+ const { sessionId, debug = false, delegationManager = null, workspaceRoot } = options;
39935
40043
  return (0, import_ai2.tool)({
39936
40044
  name: "analyze_all",
39937
40045
  description: analyzeAllDescription,
@@ -39950,12 +40058,14 @@ var init_vercel = __esm({
39950
40058
  console.error(`[analyze_all] Question: ${question}`);
39951
40059
  console.error(`[analyze_all] Path: ${searchPath}`);
39952
40060
  }
40061
+ const effectiveWorkspaceRoot = workspaceRoot || options.cwd || options.allowedFolders && options.allowedFolders[0];
39953
40062
  const result = await analyzeAll({
39954
40063
  question,
39955
40064
  path: searchPath,
39956
40065
  sessionId,
39957
40066
  debug,
39958
40067
  cwd: options.cwd,
40068
+ workspaceRoot: effectiveWorkspaceRoot,
39959
40069
  allowedFolders: options.allowedFolders,
39960
40070
  provider: options.provider,
39961
40071
  model: options.model,
@@ -41432,14 +41542,17 @@ var init_bash = __esm({
41432
41542
  import_path8 = require("path");
41433
41543
  init_bashPermissions();
41434
41544
  init_bashExecutor();
41545
+ init_path_validation();
41435
41546
  bashTool = (options = {}) => {
41436
41547
  const {
41437
41548
  bashConfig = {},
41438
41549
  debug = false,
41439
41550
  cwd,
41440
41551
  allowedFolders = [],
41552
+ workspaceRoot: providedWorkspaceRoot,
41441
41553
  tracer = null
41442
41554
  } = options;
41555
+ const workspaceRoot = providedWorkspaceRoot || cwd || allowedFolders.length > 0 && allowedFolders[0] || process.cwd();
41443
41556
  const permissionChecker = new BashPermissionChecker({
41444
41557
  allow: bashConfig.allow,
41445
41558
  deny: bashConfig.deny,
@@ -41455,6 +41568,9 @@ var init_bash = __esm({
41455
41568
  if (cwd) {
41456
41569
  return cwd;
41457
41570
  }
41571
+ if (workspaceRoot) {
41572
+ return workspaceRoot;
41573
+ }
41458
41574
  if (allowedFolders && allowedFolders.length > 0) {
41459
41575
  return allowedFolders[0];
41460
41576
  }
@@ -41542,13 +41658,15 @@ For code exploration, try these safe alternatives:
41542
41658
  const defaultDir = getDefaultWorkingDirectory();
41543
41659
  const workingDir = workingDirectory ? (0, import_path8.isAbsolute)(workingDirectory) ? (0, import_path8.resolve)(workingDirectory) : (0, import_path8.resolve)(defaultDir, workingDirectory) : defaultDir;
41544
41660
  if (allowedFolders && allowedFolders.length > 0) {
41545
- const resolvedWorkingDir = (0, import_path8.resolve)(workingDir);
41661
+ const resolvedWorkingDir = safeRealpath(workingDir);
41546
41662
  const isAllowed = allowedFolders.some((folder) => {
41547
- const resolvedFolder = (0, import_path8.resolve)(folder);
41663
+ const resolvedFolder = safeRealpath(folder);
41548
41664
  return resolvedWorkingDir === resolvedFolder || resolvedWorkingDir.startsWith(resolvedFolder + import_path8.sep);
41549
41665
  });
41550
41666
  if (!isAllowed) {
41551
- return `Error: Working directory "${workingDir}" is not within allowed folders: ${allowedFolders.join(", ")}`;
41667
+ const relativeDir = toRelativePath(workingDir, workspaceRoot);
41668
+ const relativeAllowed = allowedFolders.map((f5) => toRelativePath(f5, workspaceRoot));
41669
+ return `Error: Working directory "${relativeDir}" is not within allowed folders: ${relativeAllowed.join(", ")}`;
41552
41670
  }
41553
41671
  }
41554
41672
  const executionOptions = {
@@ -45715,7 +45833,7 @@ var init_esm3 = __esm({
45715
45833
  });
45716
45834
 
45717
45835
  // node_modules/path-scurry/dist/esm/index.js
45718
- var import_node_path, import_node_url, import_fs9, actualFS, import_promises, realpathSync, 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;
45836
+ var import_node_path, import_node_url, import_fs9, 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;
45719
45837
  var init_esm4 = __esm({
45720
45838
  "node_modules/path-scurry/dist/esm/index.js"() {
45721
45839
  init_esm2();
@@ -45725,13 +45843,13 @@ var init_esm4 = __esm({
45725
45843
  actualFS = __toESM(require("node:fs"), 1);
45726
45844
  import_promises = require("node:fs/promises");
45727
45845
  init_esm3();
45728
- realpathSync = import_fs9.realpathSync.native;
45846
+ realpathSync2 = import_fs9.realpathSync.native;
45729
45847
  defaultFS = {
45730
45848
  lstatSync: import_fs9.lstatSync,
45731
45849
  readdir: import_fs9.readdir,
45732
45850
  readdirSync: import_fs9.readdirSync,
45733
45851
  readlinkSync: import_fs9.readlinkSync,
45734
- realpathSync,
45852
+ realpathSync: realpathSync2,
45735
45853
  promises: {
45736
45854
  lstat: import_promises.lstat,
45737
45855
  readdir: import_promises.readdir,
@@ -98313,7 +98431,7 @@ __export(enhanced_claude_code_exports, {
98313
98431
  createEnhancedClaudeCLIEngine: () => createEnhancedClaudeCLIEngine
98314
98432
  });
98315
98433
  async function createEnhancedClaudeCLIEngine(options = {}) {
98316
- const { agent, systemPrompt, customPrompt, debug, sessionId, allowedTools } = options;
98434
+ const { agent, systemPrompt, customPrompt, debug, sessionId, allowedTools, timeout = 12e4 } = options;
98317
98435
  const session = new Session(
98318
98436
  sessionId || (0, import_crypto7.randomBytes)(8).toString("hex"),
98319
98437
  debug
@@ -98412,6 +98530,30 @@ ${opts.schema}`;
98412
98530
  stdio: ["ignore", "pipe", "pipe"]
98413
98531
  // Ignore stdin since echo handles it
98414
98532
  });
98533
+ let killed = false;
98534
+ let timeoutHandle;
98535
+ let sigkillHandle;
98536
+ if (timeout > 0) {
98537
+ timeoutHandle = setTimeout(() => {
98538
+ if (!killed) {
98539
+ killed = true;
98540
+ processEnded = true;
98541
+ proc2.kill("SIGTERM");
98542
+ if (debug) {
98543
+ console.log(`[DEBUG] Process timed out after ${timeout}ms, sending SIGTERM`);
98544
+ }
98545
+ sigkillHandle = setTimeout(() => {
98546
+ if (proc2.exitCode === null) {
98547
+ proc2.kill("SIGKILL");
98548
+ if (debug) {
98549
+ console.log("[DEBUG] Process did not exit, sending SIGKILL");
98550
+ }
98551
+ }
98552
+ }, 5e3);
98553
+ emitter.emit("error", new Error(`Claude CLI process timed out after ${timeout}ms`));
98554
+ }
98555
+ }, timeout);
98556
+ }
98415
98557
  proc2.stdout.on("data", (data2) => {
98416
98558
  buffer += data2.toString();
98417
98559
  processJsonBuffer(buffer, emitter, session, debug, toolCollector);
@@ -98428,10 +98570,20 @@ ${opts.schema}`;
98428
98570
  }
98429
98571
  });
98430
98572
  proc2.on("close", (code) => {
98573
+ if (timeoutHandle) {
98574
+ clearTimeout(timeoutHandle);
98575
+ }
98576
+ if (sigkillHandle) {
98577
+ clearTimeout(sigkillHandle);
98578
+ }
98431
98579
  processEnded = true;
98432
98580
  if (code !== 0 && debug) {
98433
98581
  console.log(`[DEBUG] Process exited with code ${code}`);
98434
98582
  }
98583
+ if (killed) {
98584
+ emitter.emit("end");
98585
+ return;
98586
+ }
98435
98587
  if (buffer.trim()) {
98436
98588
  processJsonBuffer(buffer, emitter, session, debug, toolCollector);
98437
98589
  }
@@ -98447,6 +98599,13 @@ ${opts.schema}`;
98447
98599
  emitter.emit("end");
98448
98600
  });
98449
98601
  proc2.on("error", (error2) => {
98602
+ if (timeoutHandle) {
98603
+ clearTimeout(timeoutHandle);
98604
+ }
98605
+ if (sigkillHandle) {
98606
+ clearTimeout(sigkillHandle);
98607
+ }
98608
+ processEnded = true;
98450
98609
  emitter.emit("error", error2);
98451
98610
  });
98452
98611
  const messageQueue = [];
@@ -98492,7 +98651,22 @@ ${opts.schema}`;
98492
98651
  \u{1F527} Using ${msg.name}: ${JSON.stringify(msg.input)}
98493
98652
  `
98494
98653
  };
98495
- const result = await executeProbleTool(agent, msg.name, msg.input);
98654
+ const toolTimeout = 3e4;
98655
+ let toolTimeoutId;
98656
+ const timeoutPromise = new Promise((_, reject2) => {
98657
+ toolTimeoutId = setTimeout(() => reject2(new Error(`Tool ${msg.name} timed out after ${toolTimeout}ms`)), toolTimeout);
98658
+ });
98659
+ let result;
98660
+ try {
98661
+ result = await Promise.race([
98662
+ executeProbleTool(agent, msg.name, msg.input),
98663
+ timeoutPromise
98664
+ ]);
98665
+ } catch (error2) {
98666
+ result = `Tool error: ${error2.message}`;
98667
+ } finally {
98668
+ clearTimeout(toolTimeoutId);
98669
+ }
98496
98670
  yield { type: "text", content: `${result}
98497
98671
  ` };
98498
98672
  } else if (msg.type === "toolBatch") {
@@ -99068,6 +99242,9 @@ var init_enhanced_vercel = __esm({
99068
99242
  // src/agent/ProbeAgent.js
99069
99243
  var ProbeAgent_exports = {};
99070
99244
  __export(ProbeAgent_exports, {
99245
+ ENGINE_ACTIVITY_TIMEOUT_DEFAULT: () => ENGINE_ACTIVITY_TIMEOUT_DEFAULT,
99246
+ ENGINE_ACTIVITY_TIMEOUT_MAX: () => ENGINE_ACTIVITY_TIMEOUT_MAX,
99247
+ ENGINE_ACTIVITY_TIMEOUT_MIN: () => ENGINE_ACTIVITY_TIMEOUT_MIN,
99071
99248
  ProbeAgent: () => ProbeAgent
99072
99249
  });
99073
99250
  module.exports = __toCommonJS(ProbeAgent_exports);
@@ -99092,7 +99269,7 @@ Your content here
99092
99269
 
99093
99270
  Do NOT wrap in other tags like <api_call>, <tool_name>, <function>, etc.`;
99094
99271
  }
99095
- var import_dotenv2, import_anthropic2, import_openai2, import_google2, import_ai5, import_crypto9, import_events4, import_fs14, import_promises6, import_path17, MAX_TOOL_ITERATIONS, MAX_HISTORY_MESSAGES, MAX_IMAGE_FILE_SIZE, ProbeAgent;
99272
+ var import_dotenv2, import_anthropic2, import_openai2, import_google2, import_ai5, 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;
99096
99273
  var init_ProbeAgent = __esm({
99097
99274
  "src/agent/ProbeAgent.js"() {
99098
99275
  import_dotenv2 = __toESM(require_main(), 1);
@@ -99126,10 +99303,14 @@ var init_ProbeAgent = __esm({
99126
99303
  init_FallbackManager();
99127
99304
  init_contextCompactor();
99128
99305
  init_error_types();
99306
+ init_path_validation();
99129
99307
  init_outputTruncator();
99130
99308
  init_delegate();
99131
99309
  init_tasks();
99132
99310
  import_dotenv2.default.config();
99311
+ ENGINE_ACTIVITY_TIMEOUT_DEFAULT = 18e4;
99312
+ ENGINE_ACTIVITY_TIMEOUT_MIN = 5e3;
99313
+ ENGINE_ACTIVITY_TIMEOUT_MAX = 6e5;
99133
99314
  MAX_TOOL_ITERATIONS = (() => {
99134
99315
  const val = parseInt(process.env.MAX_TOOL_ITERATIONS || "30", 10);
99135
99316
  if (isNaN(val) || val < 1 || val > 200) {
@@ -99188,6 +99369,8 @@ var init_ProbeAgent = __esm({
99188
99369
  * @param {number} [options.fallback.maxTotalAttempts=10] - Maximum total attempts across all providers
99189
99370
  * @param {string} [options.completionPrompt] - Custom prompt to run after attempt_completion for validation/review (runs before mermaid/JSON validation)
99190
99371
  * @param {number} [options.maxOutputTokens] - Maximum tokens for tool output before truncation (default: 20000, can also be set via PROBE_MAX_OUTPUT_TOKENS env var)
99372
+ * @param {number} [options.requestTimeout] - Timeout in ms for AI requests (default: 120000 or REQUEST_TIMEOUT env var). Used to abort hung requests.
99373
+ * @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.
99191
99374
  */
99192
99375
  constructor(options = {}) {
99193
99376
  this.sessionId = options.sessionId || (0, import_crypto9.randomUUID)();
@@ -99243,7 +99426,8 @@ var init_ProbeAgent = __esm({
99243
99426
  } else {
99244
99427
  this.allowedFolders = [process.cwd()];
99245
99428
  }
99246
- this.cwd = options.cwd || null;
99429
+ this.workspaceRoot = getCommonPrefix(this.allowedFolders);
99430
+ this.cwd = options.cwd || this.workspaceRoot;
99247
99431
  this.clientApiProvider = options.provider || null;
99248
99432
  this.clientApiModel = options.model || null;
99249
99433
  this.clientApiKey = null;
@@ -99255,6 +99439,8 @@ var init_ProbeAgent = __esm({
99255
99439
  console.log(`[DEBUG] Maximum tool iterations configured: ${MAX_TOOL_ITERATIONS}`);
99256
99440
  console.log(`[DEBUG] Allow Edit (implement tool): ${this.allowEdit}`);
99257
99441
  console.log(`[DEBUG] Search delegation enabled: ${this.searchDelegate}`);
99442
+ console.log(`[DEBUG] Workspace root: ${this.workspaceRoot}`);
99443
+ console.log(`[DEBUG] Working directory (cwd): ${this.cwd}`);
99258
99444
  }
99259
99445
  this.initializeTools();
99260
99446
  this.history = [];
@@ -99270,6 +99456,32 @@ var init_ProbeAgent = __esm({
99270
99456
  this.enableTasks = !!options.enableTasks;
99271
99457
  this.taskManager = null;
99272
99458
  this.delegationManager = new DelegationManager();
99459
+ this.requestTimeout = options.requestTimeout ?? (() => {
99460
+ if (process.env.REQUEST_TIMEOUT) {
99461
+ const parsed = parseInt(process.env.REQUEST_TIMEOUT, 10);
99462
+ if (isNaN(parsed) || parsed < 1e3 || parsed > 36e5) {
99463
+ return 12e4;
99464
+ }
99465
+ return parsed;
99466
+ }
99467
+ return 12e4;
99468
+ })();
99469
+ if (this.debug) {
99470
+ console.log(`[DEBUG] Request timeout: ${this.requestTimeout}ms`);
99471
+ }
99472
+ this.maxOperationTimeout = options.maxOperationTimeout ?? (() => {
99473
+ if (process.env.MAX_OPERATION_TIMEOUT) {
99474
+ const parsed = parseInt(process.env.MAX_OPERATION_TIMEOUT, 10);
99475
+ if (isNaN(parsed) || parsed < 1e3 || parsed > 72e5) {
99476
+ return 3e5;
99477
+ }
99478
+ return parsed;
99479
+ }
99480
+ return 3e5;
99481
+ })();
99482
+ if (this.debug) {
99483
+ console.log(`[DEBUG] Max operation timeout: ${this.maxOperationTimeout}ms`);
99484
+ }
99273
99485
  this.retryConfig = options.retry || {};
99274
99486
  this.retryManager = null;
99275
99487
  this.fallbackConfig = options.fallback || null;
@@ -99602,8 +99814,9 @@ var init_ProbeAgent = __esm({
99602
99814
  const configOptions = {
99603
99815
  sessionId: this.sessionId,
99604
99816
  debug: this.debug,
99605
- // Use explicit cwd if set, otherwise fall back to first allowed folder
99606
- cwd: this.cwd || (this.allowedFolders.length > 0 ? this.allowedFolders[0] : process.cwd()),
99817
+ // Use cwd (which defaults to workspaceRoot in constructor)
99818
+ cwd: this.cwd,
99819
+ workspaceRoot: this.workspaceRoot,
99607
99820
  allowedFolders: this.allowedFolders,
99608
99821
  outline: this.outline,
99609
99822
  searchDelegate: this.searchDelegate,
@@ -99888,88 +100101,98 @@ var init_ProbeAgent = __esm({
99888
100101
  }
99889
100102
  }
99890
100103
  /**
99891
- * Execute streamText with retry and fallback support
99892
- * @param {Object} options - streamText options
99893
- * @returns {Promise<Object>} - streamText result
100104
+ * Create a streamText-compatible result from an engine stream with timeout handling
100105
+ * @param {AsyncGenerator} engineStream - The engine's query result
100106
+ * @param {AbortSignal} abortSignal - Signal for aborting the operation
100107
+ * @param {number} requestTimeout - Per-request timeout in ms
100108
+ * @param {Object} timeoutState - Object with timeoutId property (mutable for cleanup)
100109
+ * @returns {Object} - streamText-compatible result with textStream
99894
100110
  * @private
99895
100111
  */
99896
- async streamTextWithRetryAndFallback(options) {
99897
- if (this.clientApiProvider === "claude-code" || process.env.USE_CLAUDE_CODE === "true") {
100112
+ _createEngineTextStreamResult(engineStream, abortSignal, requestTimeout, timeoutState) {
100113
+ const activityTimeout = (() => {
100114
+ const parsed = parseInt(process.env.ENGINE_ACTIVITY_TIMEOUT, 10);
100115
+ return isNaN(parsed) || parsed < ENGINE_ACTIVITY_TIMEOUT_MIN || parsed > ENGINE_ACTIVITY_TIMEOUT_MAX ? ENGINE_ACTIVITY_TIMEOUT_DEFAULT : parsed;
100116
+ })();
100117
+ const startTime = Date.now();
100118
+ async function* createTextStream() {
100119
+ let lastActivity = Date.now();
99898
100120
  try {
99899
- const engine = await this.getEngine();
99900
- if (engine && engine.query) {
99901
- const userMessages = options.messages.filter(
99902
- (m5) => m5.role === "user" && !m5.content.includes("WARNING: You have reached the maximum tool iterations limit")
99903
- );
99904
- const lastUserMessage = userMessages[userMessages.length - 1];
99905
- const prompt = lastUserMessage ? lastUserMessage.content : "";
99906
- const engineOptions = {
99907
- maxTokens: options.maxTokens,
99908
- temperature: options.temperature,
99909
- messages: options.messages,
99910
- systemPrompt: options.messages.find((m5) => m5.role === "system")?.content
99911
- };
99912
- const engineStream = engine.query(prompt, engineOptions);
99913
- async function* createTextStream() {
99914
- for await (const message of engineStream) {
99915
- if (message.type === "text" && message.content) {
99916
- yield message.content;
99917
- } else if (typeof message === "string") {
99918
- yield message;
99919
- }
99920
- }
100121
+ for await (const message of engineStream) {
100122
+ if (abortSignal.aborted) {
100123
+ const abortError = new Error("Operation aborted");
100124
+ abortError.name = "AbortError";
100125
+ throw abortError;
99921
100126
  }
99922
- return {
99923
- textStream: createTextStream(),
99924
- usage: Promise.resolve({})
99925
- // Engine should handle its own usage tracking
99926
- // Add other streamText-compatible properties as needed
99927
- };
99928
- }
99929
- } catch (error2) {
99930
- if (this.debug) {
99931
- console.log(`[DEBUG] Failed to use Claude Code engine, falling back to Vercel:`, error2.message);
99932
- }
99933
- }
99934
- }
99935
- if (this.clientApiProvider === "codex" || process.env.USE_CODEX === "true") {
99936
- try {
99937
- const engine = await this.getEngine();
99938
- if (engine && engine.query) {
99939
- const userMessages = options.messages.filter(
99940
- (m5) => m5.role === "user" && !m5.content.includes("WARNING: You have reached the maximum tool iterations limit")
99941
- );
99942
- const lastUserMessage = userMessages[userMessages.length - 1];
99943
- const prompt = lastUserMessage ? lastUserMessage.content : "";
99944
- const engineOptions = {
99945
- maxTokens: options.maxTokens,
99946
- temperature: options.temperature,
99947
- messages: options.messages,
99948
- systemPrompt: options.messages.find((m5) => m5.role === "system")?.content
99949
- };
99950
- const engineStream = engine.query(prompt, engineOptions);
99951
- async function* createTextStream() {
99952
- for await (const message of engineStream) {
99953
- if (message.type === "text" && message.content) {
99954
- yield message.content;
99955
- } else if (typeof message === "string") {
99956
- yield message;
99957
- }
99958
- }
100127
+ const now = Date.now();
100128
+ if (now - lastActivity > activityTimeout) {
100129
+ throw new Error(`Engine stream timeout - no activity for ${activityTimeout}ms`);
100130
+ }
100131
+ if (requestTimeout > 0 && now - startTime > requestTimeout) {
100132
+ throw new Error(`Engine stream timeout - request exceeded ${requestTimeout}ms`);
100133
+ }
100134
+ lastActivity = now;
100135
+ if (message.type === "text" && message.content) {
100136
+ yield message.content;
100137
+ } else if (typeof message === "string") {
100138
+ yield message;
99959
100139
  }
99960
- return {
99961
- textStream: createTextStream(),
99962
- usage: Promise.resolve({})
99963
- // Engine should handle its own usage tracking
99964
- // Add other streamText-compatible properties as needed
99965
- };
99966
100140
  }
99967
- } catch (error2) {
99968
- if (this.debug) {
99969
- console.log(`[DEBUG] Failed to use Codex engine, falling back to Vercel:`, error2.message);
100141
+ } finally {
100142
+ if (timeoutState.timeoutId) {
100143
+ clearTimeout(timeoutState.timeoutId);
100144
+ timeoutState.timeoutId = null;
99970
100145
  }
99971
100146
  }
99972
100147
  }
100148
+ return {
100149
+ textStream: createTextStream(),
100150
+ usage: Promise.resolve({})
100151
+ // Engine should handle its own usage tracking
100152
+ // Add other streamText-compatible properties as needed
100153
+ };
100154
+ }
100155
+ /**
100156
+ * Try to use an engine (claude-code or codex) for streaming
100157
+ * @param {Object} options - streamText options
100158
+ * @param {AbortController} controller - Abort controller for the operation
100159
+ * @param {Object} timeoutState - Mutable timeout state for cleanup
100160
+ * @returns {Promise<Object|null>} - Stream result or null if engine unavailable
100161
+ * @private
100162
+ */
100163
+ async _tryEngineStreamPath(options, controller, timeoutState) {
100164
+ const engine = await this.getEngine();
100165
+ if (!engine || !engine.query) {
100166
+ return null;
100167
+ }
100168
+ const userMessages = options.messages.filter(
100169
+ (m5) => m5.role === "user" && !m5.content.includes("WARNING: You have reached the maximum tool iterations limit")
100170
+ );
100171
+ const lastUserMessage = userMessages[userMessages.length - 1];
100172
+ const prompt = lastUserMessage ? lastUserMessage.content : "";
100173
+ const engineOptions = {
100174
+ maxTokens: options.maxTokens,
100175
+ temperature: options.temperature,
100176
+ messages: options.messages,
100177
+ systemPrompt: options.messages.find((m5) => m5.role === "system")?.content,
100178
+ abortSignal: controller.signal
100179
+ };
100180
+ const engineStream = engine.query(prompt, engineOptions);
100181
+ return this._createEngineTextStreamResult(
100182
+ engineStream,
100183
+ controller.signal,
100184
+ this.requestTimeout,
100185
+ timeoutState
100186
+ );
100187
+ }
100188
+ /**
100189
+ * Execute streamText with Vercel AI SDK using retry/fallback logic
100190
+ * @param {Object} options - streamText options
100191
+ * @param {AbortController} controller - Abort controller for the operation
100192
+ * @returns {Promise<Object>} - Stream result
100193
+ * @private
100194
+ */
100195
+ async _executeWithVercelProvider(options, controller) {
99973
100196
  if (!this.retryManager) {
99974
100197
  this.retryManager = new RetryManager({
99975
100198
  maxRetries: this.retryConfig.maxRetries ?? 3,
@@ -99982,10 +100205,11 @@ var init_ProbeAgent = __esm({
99982
100205
  }
99983
100206
  if (!this.fallbackManager) {
99984
100207
  return await this.retryManager.executeWithRetry(
99985
- () => (0, import_ai5.streamText)(options),
100208
+ () => (0, import_ai5.streamText)({ ...options, abortSignal: controller.signal }),
99986
100209
  {
99987
100210
  provider: this.apiType,
99988
- model: this.model
100211
+ model: this.model,
100212
+ signal: controller.signal
99989
100213
  }
99990
100214
  );
99991
100215
  }
@@ -99993,7 +100217,8 @@ var init_ProbeAgent = __esm({
99993
100217
  async (provider, model, config) => {
99994
100218
  const fallbackOptions = {
99995
100219
  ...options,
99996
- model: provider(model)
100220
+ model: provider(model),
100221
+ abortSignal: controller.signal
99997
100222
  };
99998
100223
  const providerRetryManager = new RetryManager({
99999
100224
  maxRetries: config.maxRetries ?? this.retryConfig.maxRetries ?? 3,
@@ -100007,12 +100232,54 @@ var init_ProbeAgent = __esm({
100007
100232
  () => (0, import_ai5.streamText)(fallbackOptions),
100008
100233
  {
100009
100234
  provider: config.provider,
100010
- model
100235
+ model,
100236
+ signal: controller.signal
100011
100237
  }
100012
100238
  );
100013
100239
  }
100014
100240
  );
100015
100241
  }
100242
+ /**
100243
+ * Execute streamText with retry and fallback support
100244
+ * @param {Object} options - streamText options
100245
+ * @returns {Promise<Object>} - streamText result
100246
+ * @private
100247
+ */
100248
+ async streamTextWithRetryAndFallback(options) {
100249
+ const controller = new AbortController();
100250
+ const timeoutState = { timeoutId: null };
100251
+ if (this.maxOperationTimeout && this.maxOperationTimeout > 0) {
100252
+ timeoutState.timeoutId = setTimeout(() => {
100253
+ controller.abort();
100254
+ if (this.debug) {
100255
+ console.log(`[DEBUG] Operation timed out after ${this.maxOperationTimeout}ms (max operation timeout)`);
100256
+ }
100257
+ }, this.maxOperationTimeout);
100258
+ }
100259
+ try {
100260
+ const useClaudeCode = this.clientApiProvider === "claude-code" || process.env.USE_CLAUDE_CODE === "true";
100261
+ const useCodex = this.clientApiProvider === "codex" || process.env.USE_CODEX === "true";
100262
+ if (useClaudeCode || useCodex) {
100263
+ try {
100264
+ const result = await this._tryEngineStreamPath(options, controller, timeoutState);
100265
+ if (result) {
100266
+ return result;
100267
+ }
100268
+ } catch (error2) {
100269
+ if (this.debug) {
100270
+ const engineType = useClaudeCode ? "Claude Code" : "Codex";
100271
+ console.log(`[DEBUG] Failed to use ${engineType} engine, falling back to Vercel:`, error2.message);
100272
+ }
100273
+ }
100274
+ }
100275
+ return await this._executeWithVercelProvider(options, controller);
100276
+ } finally {
100277
+ if (timeoutState.timeoutId) {
100278
+ clearTimeout(timeoutState.timeoutId);
100279
+ timeoutState.timeoutId = null;
100280
+ }
100281
+ }
100282
+ }
100016
100283
  /**
100017
100284
  * Initialize Anthropic model
100018
100285
  */
@@ -100290,16 +100557,16 @@ var init_ProbeAgent = __esm({
100290
100557
  let absolutePath;
100291
100558
  let isPathAllowed2 = false;
100292
100559
  if ((0, import_path17.isAbsolute)(imagePath)) {
100293
- absolutePath = (0, import_path17.normalize)((0, import_path17.resolve)(imagePath));
100560
+ absolutePath = safeRealpath((0, import_path17.resolve)(imagePath));
100294
100561
  isPathAllowed2 = allowedDirs.some((dir) => {
100295
- const normalizedDir = (0, import_path17.normalize)((0, import_path17.resolve)(dir));
100296
- return absolutePath === normalizedDir || absolutePath.startsWith(normalizedDir + import_path17.sep);
100562
+ const resolvedDir = safeRealpath(dir);
100563
+ return absolutePath === resolvedDir || absolutePath.startsWith(resolvedDir + import_path17.sep);
100297
100564
  });
100298
100565
  } else {
100299
100566
  for (const dir of allowedDirs) {
100300
- const normalizedDir = (0, import_path17.normalize)((0, import_path17.resolve)(dir));
100301
- const resolvedPath2 = (0, import_path17.normalize)((0, import_path17.resolve)(dir, imagePath));
100302
- if (resolvedPath2 === normalizedDir || resolvedPath2.startsWith(normalizedDir + import_path17.sep)) {
100567
+ const resolvedDir = safeRealpath(dir);
100568
+ const resolvedPath2 = safeRealpath((0, import_path17.resolve)(dir, imagePath));
100569
+ if (resolvedPath2 === resolvedDir || resolvedPath2.startsWith(resolvedDir + import_path17.sep)) {
100303
100570
  absolutePath = resolvedPath2;
100304
100571
  isPathAllowed2 = true;
100305
100572
  break;
@@ -100482,7 +100749,7 @@ var init_ProbeAgent = __esm({
100482
100749
  if (this._architectureContextLoaded) {
100483
100750
  return this.architectureContext;
100484
100751
  }
100485
- const rootDirectory = this.allowedFolders.length > 0 ? this.allowedFolders[0] : process.cwd();
100752
+ const rootDirectory = this.workspaceRoot || (this.allowedFolders.length > 0 ? this.allowedFolders[0] : process.cwd());
100486
100753
  const configuredName = typeof this.architectureFileName === "string" ? this.architectureFileName.trim() : "";
100487
100754
  const hasConfiguredName = !!configuredName;
100488
100755
  let guidanceCandidates = [];
@@ -100619,6 +100886,9 @@ ${this.architectureContext.content}
100619
100886
  `;
100620
100887
  }
100621
100888
  _getSkillsRepoRoot() {
100889
+ if (this.workspaceRoot) {
100890
+ return (0, import_path17.resolve)(this.workspaceRoot);
100891
+ }
100622
100892
  if (this.allowedFolders && this.allowedFolders.length > 0) {
100623
100893
  return (0, import_path17.resolve)(this.allowedFolders[0]);
100624
100894
  }
@@ -100686,7 +100956,7 @@ Workspace: ${this.allowedFolders.join(", ")}`;
100686
100956
 
100687
100957
  # Repository Structure
100688
100958
  `;
100689
- systemPrompt += `You are working with a repository located at: ${this.allowedFolders[0]}
100959
+ systemPrompt += `You are working with a repository located at: ${this.workspaceRoot}
100690
100960
 
100691
100961
  `;
100692
100962
  systemPrompt += `Here's an overview of the repository structure (showing up to 100 most relevant files):
@@ -100739,7 +101009,7 @@ Workspace: ${this.allowedFolders.join(", ")}`;
100739
101009
 
100740
101010
  # Repository Structure
100741
101011
  `;
100742
- systemPrompt += `You are working with a repository located at: ${this.allowedFolders[0]}
101012
+ systemPrompt += `You are working with a repository located at: ${this.workspaceRoot}
100743
101013
 
100744
101014
  `;
100745
101015
  systemPrompt += `Here's an overview of the repository structure (showing up to 100 most relevant files):
@@ -101038,21 +101308,34 @@ For MCP tools, use JSON format within the params tag, e.g.:
101038
101308
  `;
101039
101309
  }
101040
101310
  }
101041
- const searchDirectory = this.allowedFolders.length > 0 ? this.allowedFolders[0] : process.cwd();
101311
+ const searchDirectory = this.workspaceRoot;
101042
101312
  if (this.debug) {
101043
- console.log(`[DEBUG] Generating file list for base directory: ${searchDirectory}...`);
101313
+ console.log(`[DEBUG] Generating file list for workspace root: ${searchDirectory}...`);
101314
+ }
101315
+ const relativeWorkspaces = this.allowedFolders.map((f5) => {
101316
+ const rel = toRelativePath(f5, this.workspaceRoot);
101317
+ if (rel && rel !== "." && !rel.startsWith(".") && !rel.startsWith("/")) {
101318
+ return "./" + rel;
101319
+ }
101320
+ return rel;
101321
+ }).filter((f5) => f5 && f5 !== ".");
101322
+ let workspaceDesc;
101323
+ if (relativeWorkspaces.length === 0) {
101324
+ workspaceDesc = ". (current directory)";
101325
+ } else {
101326
+ workspaceDesc = relativeWorkspaces.join(", ");
101044
101327
  }
101045
101328
  try {
101046
101329
  const files = await listFilesByLevel({
101047
101330
  directory: searchDirectory,
101048
101331
  maxFiles: 100,
101049
101332
  respectGitignore: !process.env.PROBE_NO_GITIGNORE || process.env.PROBE_NO_GITIGNORE === "",
101050
- cwd: process.cwd()
101333
+ cwd: this.workspaceRoot
101051
101334
  });
101052
101335
  systemMessage += `
101053
101336
  # Repository Structure
101054
101337
 
101055
- You are working with a repository located at: ${searchDirectory}
101338
+ You are working with a workspace. Available paths: ${workspaceDesc}
101056
101339
 
101057
101340
  Here's an overview of the repository structure (showing up to 100 most relevant files):
101058
101341
 
@@ -101068,15 +101351,22 @@ ${files}
101068
101351
  systemMessage += `
101069
101352
  # Repository Structure
101070
101353
 
101071
- You are working with a repository located at: ${searchDirectory}
101354
+ You are working with a workspace. Available paths: ${workspaceDesc}
101072
101355
 
101073
101356
  `;
101074
101357
  }
101075
101358
  await this.loadArchitectureContext();
101076
101359
  systemMessage += this.getArchitectureSection();
101077
101360
  if (this.allowedFolders.length > 0) {
101361
+ const relativeAllowed = this.allowedFolders.map((f5) => {
101362
+ const rel = toRelativePath(f5, this.workspaceRoot);
101363
+ if (rel && rel !== "." && !rel.startsWith(".") && !rel.startsWith("/")) {
101364
+ return "./" + rel;
101365
+ }
101366
+ return rel;
101367
+ });
101078
101368
  systemMessage += `
101079
- **Important**: For security reasons, you can only search within these allowed folders: ${this.allowedFolders.join(", ")}
101369
+ **Important**: For security reasons, you can only access these paths: ${relativeAllowed.join(", ")}
101080
101370
 
101081
101371
  `;
101082
101372
  }
@@ -101590,6 +101880,7 @@ You are working with a repository located at: ${searchDirectory}
101590
101880
  console.error(`[DEBUG] ========================================
101591
101881
  `);
101592
101882
  }
101883
+ currentMessages.push({ role: "assistant", content: assistantResponseContent });
101593
101884
  currentMessages.push({ role: "user", content: `<tool_result>
101594
101885
  ${toolResultContent}
101595
101886
  </tool_result>` });
@@ -101610,17 +101901,18 @@ ${toolResultContent}
101610
101901
  `);
101611
101902
  }
101612
101903
  const errorXml = formatErrorForAI(error2);
101904
+ currentMessages.push({ role: "assistant", content: assistantResponseContent });
101613
101905
  currentMessages.push({ role: "user", content: `<tool_result>
101614
101906
  ${errorXml}
101615
101907
  </tool_result>` });
101616
101908
  }
101617
101909
  } else if (this.toolImplementations[toolName]) {
101618
101910
  try {
101619
- let resolvedWorkingDirectory = this.cwd || this.allowedFolders && this.allowedFolders[0] || process.cwd();
101911
+ let resolvedWorkingDirectory = this.workspaceRoot || this.cwd || this.allowedFolders && this.allowedFolders[0] || process.cwd();
101620
101912
  if (params.workingDirectory) {
101621
- const requestedDir = (0, import_path17.isAbsolute)(params.workingDirectory) ? (0, import_path17.resolve)(params.workingDirectory) : (0, import_path17.resolve)(resolvedWorkingDirectory, params.workingDirectory);
101913
+ const requestedDir = safeRealpath((0, import_path17.isAbsolute)(params.workingDirectory) ? (0, import_path17.resolve)(params.workingDirectory) : (0, import_path17.resolve)(resolvedWorkingDirectory, params.workingDirectory));
101622
101914
  const isWithinAllowed = !this.allowedFolders || this.allowedFolders.length === 0 || this.allowedFolders.some((folder) => {
101623
- const resolvedFolder = (0, import_path17.resolve)(folder);
101915
+ const resolvedFolder = safeRealpath(folder);
101624
101916
  return requestedDir === resolvedFolder || requestedDir.startsWith(resolvedFolder + import_path17.sep);
101625
101917
  });
101626
101918
  if (isWithinAllowed) {
@@ -102089,7 +102381,7 @@ Convert your previous response content into actual JSON data that follows this s
102089
102381
  }
102090
102382
  const mermaidValidation = await validateAndFixMermaidResponse(finalResult, {
102091
102383
  debug: this.debug,
102092
- path: this.allowedFolders[0],
102384
+ path: this.workspaceRoot || this.allowedFolders[0],
102093
102385
  provider: this.clientApiProvider,
102094
102386
  model: this.model,
102095
102387
  tracer: this.tracer
@@ -102162,7 +102454,7 @@ Convert your previous response content into actual JSON data that follows this s
102162
102454
  }
102163
102455
  const { JsonFixingAgent: JsonFixingAgent2 } = await Promise.resolve().then(() => (init_schemaUtils(), schemaUtils_exports));
102164
102456
  const jsonFixer = new JsonFixingAgent2({
102165
- path: this.allowedFolders[0],
102457
+ path: this.workspaceRoot || this.allowedFolders[0],
102166
102458
  provider: this.clientApiProvider,
102167
102459
  model: this.model,
102168
102460
  debug: this.debug,
@@ -102231,7 +102523,7 @@ Convert your previous response content into actual JSON data that follows this s
102231
102523
  }
102232
102524
  const mermaidValidation = await validateAndFixMermaidResponse(finalResult, {
102233
102525
  debug: this.debug,
102234
- path: this.allowedFolders[0],
102526
+ path: this.workspaceRoot || this.allowedFolders[0],
102235
102527
  provider: this.clientApiProvider,
102236
102528
  model: this.model,
102237
102529
  tracer: this.tracer
@@ -102363,7 +102655,7 @@ Convert your previous response content into actual JSON data that follows this s
102363
102655
  }
102364
102656
  const finalMermaidValidation = await validateAndFixMermaidResponse(finalResult, {
102365
102657
  debug: this.debug,
102366
- path: this.allowedFolders[0],
102658
+ path: this.workspaceRoot || this.allowedFolders[0],
102367
102659
  provider: this.clientApiProvider,
102368
102660
  model: this.model,
102369
102661
  tracer: this.tracer
@@ -102513,8 +102805,7 @@ Convert your previous response content into actual JSON data that follows this s
102513
102805
  allowEdit: this.allowEdit,
102514
102806
  enableDelegate: this.enableDelegate,
102515
102807
  architectureFileName: this.architectureFileName,
102516
- path: this.allowedFolders[0],
102517
- // Use first allowed folder as primary path
102808
+ // Pass allowedFolders which will recompute workspaceRoot correctly
102518
102809
  allowedFolders: [...this.allowedFolders],
102519
102810
  cwd: this.cwd,
102520
102811
  // Preserve explicit working directory
@@ -102708,6 +102999,9 @@ Convert your previous response content into actual JSON data that follows this s
102708
102999
  init_ProbeAgent();
102709
103000
  // Annotate the CommonJS export names for ESM import in node:
102710
103001
  0 && (module.exports = {
103002
+ ENGINE_ACTIVITY_TIMEOUT_DEFAULT,
103003
+ ENGINE_ACTIVITY_TIMEOUT_MAX,
103004
+ ENGINE_ACTIVITY_TIMEOUT_MIN,
102711
103005
  ProbeAgent
102712
103006
  });
102713
103007
  /*! Bundled license information: