@prestyj/boss 4.10.1 → 4.12.0

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.
@@ -3225,8 +3225,8 @@ var require_utils = __commonJS({
3225
3225
  }
3226
3226
  return ind;
3227
3227
  }
3228
- function removeDotSegments(path46) {
3229
- let input = path46;
3228
+ function removeDotSegments(path49) {
3229
+ let input = path49;
3230
3230
  const output = [];
3231
3231
  let nextSlash = -1;
3232
3232
  let len = 0;
@@ -3426,8 +3426,8 @@ var require_schemes = __commonJS({
3426
3426
  wsComponent.secure = void 0;
3427
3427
  }
3428
3428
  if (wsComponent.resourceName) {
3429
- const [path46, query] = wsComponent.resourceName.split("?");
3430
- wsComponent.path = path46 && path46 !== "/" ? path46 : void 0;
3429
+ const [path49, query] = wsComponent.resourceName.split("?");
3430
+ wsComponent.path = path49 && path49 !== "/" ? path49 : void 0;
3431
3431
  wsComponent.query = query;
3432
3432
  wsComponent.resourceName = void 0;
3433
3433
  }
@@ -3486,7 +3486,7 @@ var require_schemes = __commonJS({
3486
3486
  urnComponent.nss = (uuidComponent.uuid || "").toLowerCase();
3487
3487
  return urnComponent;
3488
3488
  }
3489
- var http = (
3489
+ var http2 = (
3490
3490
  /** @type {SchemeHandler} */
3491
3491
  {
3492
3492
  scheme: "http",
@@ -3499,7 +3499,7 @@ var require_schemes = __commonJS({
3499
3499
  /** @type {SchemeHandler} */
3500
3500
  {
3501
3501
  scheme: "https",
3502
- domainHost: http.domainHost,
3502
+ domainHost: http2.domainHost,
3503
3503
  parse: httpParse,
3504
3504
  serialize: httpSerialize
3505
3505
  }
@@ -3543,7 +3543,7 @@ var require_schemes = __commonJS({
3543
3543
  var SCHEMES = (
3544
3544
  /** @type {Record<SchemeName, SchemeHandler>} */
3545
3545
  {
3546
- http,
3546
+ http: http2,
3547
3547
  https,
3548
3548
  ws,
3549
3549
  wss,
@@ -6835,12 +6835,12 @@ var require_dist = __commonJS({
6835
6835
  throw new Error(`Unknown format "${name}"`);
6836
6836
  return f;
6837
6837
  };
6838
- function addFormats(ajv, list, fs38, exportName) {
6838
+ function addFormats(ajv, list, fs40, exportName) {
6839
6839
  var _a6;
6840
6840
  var _b;
6841
6841
  (_a6 = (_b = ajv.opts.code).formats) !== null && _a6 !== void 0 ? _a6 : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
6842
6842
  for (const f of list)
6843
- ajv.addFormat(f, fs38[f]);
6843
+ ajv.addFormat(f, fs40[f]);
6844
6844
  }
6845
6845
  module.exports = exports = formatsPlugin;
6846
6846
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -6855,8 +6855,8 @@ var require_windows = __commonJS({
6855
6855
  init_esm_shims();
6856
6856
  module.exports = isexe;
6857
6857
  isexe.sync = sync;
6858
- var fs38 = __require("fs");
6859
- function checkPathExt(path46, options) {
6858
+ var fs40 = __require("fs");
6859
+ function checkPathExt(path49, options) {
6860
6860
  var pathext = options.pathExt !== void 0 ? options.pathExt : process.env.PATHEXT;
6861
6861
  if (!pathext) {
6862
6862
  return true;
@@ -6867,25 +6867,25 @@ var require_windows = __commonJS({
6867
6867
  }
6868
6868
  for (var i = 0; i < pathext.length; i++) {
6869
6869
  var p = pathext[i].toLowerCase();
6870
- if (p && path46.substr(-p.length).toLowerCase() === p) {
6870
+ if (p && path49.substr(-p.length).toLowerCase() === p) {
6871
6871
  return true;
6872
6872
  }
6873
6873
  }
6874
6874
  return false;
6875
6875
  }
6876
- function checkStat(stat, path46, options) {
6876
+ function checkStat(stat, path49, options) {
6877
6877
  if (!stat.isSymbolicLink() && !stat.isFile()) {
6878
6878
  return false;
6879
6879
  }
6880
- return checkPathExt(path46, options);
6880
+ return checkPathExt(path49, options);
6881
6881
  }
6882
- function isexe(path46, options, cb) {
6883
- fs38.stat(path46, function(er, stat) {
6884
- cb(er, er ? false : checkStat(stat, path46, options));
6882
+ function isexe(path49, options, cb) {
6883
+ fs40.stat(path49, function(er, stat) {
6884
+ cb(er, er ? false : checkStat(stat, path49, options));
6885
6885
  });
6886
6886
  }
6887
- function sync(path46, options) {
6888
- return checkStat(fs38.statSync(path46), path46, options);
6887
+ function sync(path49, options) {
6888
+ return checkStat(fs40.statSync(path49), path49, options);
6889
6889
  }
6890
6890
  }
6891
6891
  });
@@ -6897,14 +6897,14 @@ var require_mode = __commonJS({
6897
6897
  init_esm_shims();
6898
6898
  module.exports = isexe;
6899
6899
  isexe.sync = sync;
6900
- var fs38 = __require("fs");
6901
- function isexe(path46, options, cb) {
6902
- fs38.stat(path46, function(er, stat) {
6900
+ var fs40 = __require("fs");
6901
+ function isexe(path49, options, cb) {
6902
+ fs40.stat(path49, function(er, stat) {
6903
6903
  cb(er, er ? false : checkStat(stat, options));
6904
6904
  });
6905
6905
  }
6906
- function sync(path46, options) {
6907
- return checkStat(fs38.statSync(path46), options);
6906
+ function sync(path49, options) {
6907
+ return checkStat(fs40.statSync(path49), options);
6908
6908
  }
6909
6909
  function checkStat(stat, options) {
6910
6910
  return stat.isFile() && checkMode(stat, options);
@@ -6930,7 +6930,7 @@ var require_isexe = __commonJS({
6930
6930
  "../../node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/index.js"(exports, module) {
6931
6931
  "use strict";
6932
6932
  init_esm_shims();
6933
- var fs38 = __require("fs");
6933
+ var fs40 = __require("fs");
6934
6934
  var core;
6935
6935
  if (process.platform === "win32" || global.TESTING_WINDOWS) {
6936
6936
  core = require_windows();
@@ -6939,7 +6939,7 @@ var require_isexe = __commonJS({
6939
6939
  }
6940
6940
  module.exports = isexe;
6941
6941
  isexe.sync = sync;
6942
- function isexe(path46, options, cb) {
6942
+ function isexe(path49, options, cb) {
6943
6943
  if (typeof options === "function") {
6944
6944
  cb = options;
6945
6945
  options = {};
@@ -6949,7 +6949,7 @@ var require_isexe = __commonJS({
6949
6949
  throw new TypeError("callback not provided");
6950
6950
  }
6951
6951
  return new Promise(function(resolve3, reject) {
6952
- isexe(path46, options || {}, function(er, is) {
6952
+ isexe(path49, options || {}, function(er, is) {
6953
6953
  if (er) {
6954
6954
  reject(er);
6955
6955
  } else {
@@ -6958,7 +6958,7 @@ var require_isexe = __commonJS({
6958
6958
  });
6959
6959
  });
6960
6960
  }
6961
- core(path46, options || {}, function(er, is) {
6961
+ core(path49, options || {}, function(er, is) {
6962
6962
  if (er) {
6963
6963
  if (er.code === "EACCES" || options && options.ignoreErrors) {
6964
6964
  er = null;
@@ -6968,9 +6968,9 @@ var require_isexe = __commonJS({
6968
6968
  cb(er, is);
6969
6969
  });
6970
6970
  }
6971
- function sync(path46, options) {
6971
+ function sync(path49, options) {
6972
6972
  try {
6973
- return core.sync(path46, options || {});
6973
+ return core.sync(path49, options || {});
6974
6974
  } catch (er) {
6975
6975
  if (options && options.ignoreErrors || er.code === "EACCES") {
6976
6976
  return false;
@@ -6988,7 +6988,7 @@ var require_which = __commonJS({
6988
6988
  "use strict";
6989
6989
  init_esm_shims();
6990
6990
  var isWindows3 = process.platform === "win32" || process.env.OSTYPE === "cygwin" || process.env.OSTYPE === "msys";
6991
- var path46 = __require("path");
6991
+ var path49 = __require("path");
6992
6992
  var COLON = isWindows3 ? ";" : ":";
6993
6993
  var isexe = require_isexe();
6994
6994
  var getNotFoundError = (cmd) => Object.assign(new Error(`not found: ${cmd}`), { code: "ENOENT" });
@@ -7026,7 +7026,7 @@ var require_which = __commonJS({
7026
7026
  return opt.all && found.length ? resolve3(found) : reject(getNotFoundError(cmd));
7027
7027
  const ppRaw = pathEnv[i];
7028
7028
  const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
7029
- const pCmd = path46.join(pathPart, cmd);
7029
+ const pCmd = path49.join(pathPart, cmd);
7030
7030
  const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
7031
7031
  resolve3(subStep(p, i, 0));
7032
7032
  });
@@ -7053,7 +7053,7 @@ var require_which = __commonJS({
7053
7053
  for (let i = 0; i < pathEnv.length; i++) {
7054
7054
  const ppRaw = pathEnv[i];
7055
7055
  const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
7056
- const pCmd = path46.join(pathPart, cmd);
7056
+ const pCmd = path49.join(pathPart, cmd);
7057
7057
  const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
7058
7058
  for (let j = 0; j < pathExt.length; j++) {
7059
7059
  const cur = p + pathExt[j];
@@ -7103,7 +7103,7 @@ var require_resolveCommand = __commonJS({
7103
7103
  "../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/resolveCommand.js"(exports, module) {
7104
7104
  "use strict";
7105
7105
  init_esm_shims();
7106
- var path46 = __require("path");
7106
+ var path49 = __require("path");
7107
7107
  var which = require_which();
7108
7108
  var getPathKey = require_path_key();
7109
7109
  function resolveCommandAttempt(parsed, withoutPathExt) {
@@ -7121,7 +7121,7 @@ var require_resolveCommand = __commonJS({
7121
7121
  try {
7122
7122
  resolved = which.sync(parsed.command, {
7123
7123
  path: env2[getPathKey({ env: env2 })],
7124
- pathExt: withoutPathExt ? path46.delimiter : void 0
7124
+ pathExt: withoutPathExt ? path49.delimiter : void 0
7125
7125
  });
7126
7126
  } catch (e) {
7127
7127
  } finally {
@@ -7130,7 +7130,7 @@ var require_resolveCommand = __commonJS({
7130
7130
  }
7131
7131
  }
7132
7132
  if (resolved) {
7133
- resolved = path46.resolve(hasCustomCwd ? parsed.options.cwd : "", resolved);
7133
+ resolved = path49.resolve(hasCustomCwd ? parsed.options.cwd : "", resolved);
7134
7134
  }
7135
7135
  return resolved;
7136
7136
  }
@@ -7187,8 +7187,8 @@ var require_shebang_command = __commonJS({
7187
7187
  if (!match) {
7188
7188
  return null;
7189
7189
  }
7190
- const [path46, argument] = match[0].replace(/#! ?/, "").split(" ");
7191
- const binary = path46.split("/").pop();
7190
+ const [path49, argument] = match[0].replace(/#! ?/, "").split(" ");
7191
+ const binary = path49.split("/").pop();
7192
7192
  if (binary === "env") {
7193
7193
  return argument;
7194
7194
  }
@@ -7202,16 +7202,16 @@ var require_readShebang = __commonJS({
7202
7202
  "../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/readShebang.js"(exports, module) {
7203
7203
  "use strict";
7204
7204
  init_esm_shims();
7205
- var fs38 = __require("fs");
7205
+ var fs40 = __require("fs");
7206
7206
  var shebangCommand = require_shebang_command();
7207
7207
  function readShebang(command) {
7208
7208
  const size = 150;
7209
7209
  const buffer = Buffer.alloc(size);
7210
7210
  let fd2;
7211
7211
  try {
7212
- fd2 = fs38.openSync(command, "r");
7213
- fs38.readSync(fd2, buffer, 0, size, 0);
7214
- fs38.closeSync(fd2);
7212
+ fd2 = fs40.openSync(command, "r");
7213
+ fs40.readSync(fd2, buffer, 0, size, 0);
7214
+ fs40.closeSync(fd2);
7215
7215
  } catch (e) {
7216
7216
  }
7217
7217
  return shebangCommand(buffer.toString());
@@ -7225,7 +7225,7 @@ var require_parse = __commonJS({
7225
7225
  "../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/parse.js"(exports, module) {
7226
7226
  "use strict";
7227
7227
  init_esm_shims();
7228
- var path46 = __require("path");
7228
+ var path49 = __require("path");
7229
7229
  var resolveCommand = require_resolveCommand();
7230
7230
  var escape4 = require_escape();
7231
7231
  var readShebang = require_readShebang();
@@ -7250,7 +7250,7 @@ var require_parse = __commonJS({
7250
7250
  const needsShell = !isExecutableRegExp.test(commandFile);
7251
7251
  if (parsed.options.forceShell || needsShell) {
7252
7252
  const needsDoubleEscapeMetaChars = isCmdShimRegExp.test(commandFile);
7253
- parsed.command = path46.normalize(parsed.command);
7253
+ parsed.command = path49.normalize(parsed.command);
7254
7254
  parsed.command = escape4.command(parsed.command);
7255
7255
  parsed.args = parsed.args.map((arg) => escape4.argument(arg, needsDoubleEscapeMetaChars));
7256
7256
  const shellCommand = [parsed.command].concat(parsed.args).join(" ");
@@ -17765,10 +17765,10 @@ var require_react_reconciler_development = __commonJS({
17765
17765
  fiber = fiber.next, id2--;
17766
17766
  return fiber;
17767
17767
  }
17768
- function copyWithSetImpl(obj, path46, index, value) {
17769
- if (index >= path46.length) return value;
17770
- var key = path46[index], updated = isArrayImpl(obj) ? obj.slice() : assign({}, obj);
17771
- updated[key] = copyWithSetImpl(obj[key], path46, index + 1, value);
17768
+ function copyWithSetImpl(obj, path49, index, value) {
17769
+ if (index >= path49.length) return value;
17770
+ var key = path49[index], updated = isArrayImpl(obj) ? obj.slice() : assign({}, obj);
17771
+ updated[key] = copyWithSetImpl(obj[key], path49, index + 1, value);
17772
17772
  return updated;
17773
17773
  }
17774
17774
  function copyWithRename(obj, oldPath, newPath) {
@@ -17795,11 +17795,11 @@ var require_react_reconciler_development = __commonJS({
17795
17795
  );
17796
17796
  return updated;
17797
17797
  }
17798
- function copyWithDeleteImpl(obj, path46, index) {
17799
- var key = path46[index], updated = isArrayImpl(obj) ? obj.slice() : assign({}, obj);
17800
- if (index + 1 === path46.length)
17798
+ function copyWithDeleteImpl(obj, path49, index) {
17799
+ var key = path49[index], updated = isArrayImpl(obj) ? obj.slice() : assign({}, obj);
17800
+ if (index + 1 === path49.length)
17801
17801
  return isArrayImpl(updated) ? updated.splice(key, 1) : delete updated[key], updated;
17802
- updated[key] = copyWithDeleteImpl(obj[key], path46, index + 1);
17802
+ updated[key] = copyWithDeleteImpl(obj[key], path49, index + 1);
17803
17803
  return updated;
17804
17804
  }
17805
17805
  function shouldSuspendImpl() {
@@ -31076,29 +31076,29 @@ var require_react_reconciler_development = __commonJS({
31076
31076
  var didWarnAboutNestedUpdates = false;
31077
31077
  var didWarnAboutFindNodeInStrictMode = {};
31078
31078
  var overrideHookState = null, overrideHookStateDeletePath = null, overrideHookStateRenamePath = null, overrideProps = null, overridePropsDeletePath = null, overridePropsRenamePath = null, scheduleUpdate = null, scheduleRetry = null, setErrorHandler = null, setSuspenseHandler = null;
31079
- overrideHookState = function(fiber, id2, path46, value) {
31079
+ overrideHookState = function(fiber, id2, path49, value) {
31080
31080
  id2 = findHook(fiber, id2);
31081
- null !== id2 && (path46 = copyWithSetImpl(id2.memoizedState, path46, 0, value), id2.memoizedState = path46, id2.baseState = path46, fiber.memoizedProps = assign({}, fiber.memoizedProps), path46 = enqueueConcurrentRenderForLane(fiber, 2), null !== path46 && scheduleUpdateOnFiber(path46, fiber, 2));
31081
+ null !== id2 && (path49 = copyWithSetImpl(id2.memoizedState, path49, 0, value), id2.memoizedState = path49, id2.baseState = path49, fiber.memoizedProps = assign({}, fiber.memoizedProps), path49 = enqueueConcurrentRenderForLane(fiber, 2), null !== path49 && scheduleUpdateOnFiber(path49, fiber, 2));
31082
31082
  };
31083
- overrideHookStateDeletePath = function(fiber, id2, path46) {
31083
+ overrideHookStateDeletePath = function(fiber, id2, path49) {
31084
31084
  id2 = findHook(fiber, id2);
31085
- null !== id2 && (path46 = copyWithDeleteImpl(id2.memoizedState, path46, 0), id2.memoizedState = path46, id2.baseState = path46, fiber.memoizedProps = assign({}, fiber.memoizedProps), path46 = enqueueConcurrentRenderForLane(fiber, 2), null !== path46 && scheduleUpdateOnFiber(path46, fiber, 2));
31085
+ null !== id2 && (path49 = copyWithDeleteImpl(id2.memoizedState, path49, 0), id2.memoizedState = path49, id2.baseState = path49, fiber.memoizedProps = assign({}, fiber.memoizedProps), path49 = enqueueConcurrentRenderForLane(fiber, 2), null !== path49 && scheduleUpdateOnFiber(path49, fiber, 2));
31086
31086
  };
31087
31087
  overrideHookStateRenamePath = function(fiber, id2, oldPath, newPath) {
31088
31088
  id2 = findHook(fiber, id2);
31089
31089
  null !== id2 && (oldPath = copyWithRename(id2.memoizedState, oldPath, newPath), id2.memoizedState = oldPath, id2.baseState = oldPath, fiber.memoizedProps = assign({}, fiber.memoizedProps), oldPath = enqueueConcurrentRenderForLane(fiber, 2), null !== oldPath && scheduleUpdateOnFiber(oldPath, fiber, 2));
31090
31090
  };
31091
- overrideProps = function(fiber, path46, value) {
31092
- fiber.pendingProps = copyWithSetImpl(fiber.memoizedProps, path46, 0, value);
31091
+ overrideProps = function(fiber, path49, value) {
31092
+ fiber.pendingProps = copyWithSetImpl(fiber.memoizedProps, path49, 0, value);
31093
31093
  fiber.alternate && (fiber.alternate.pendingProps = fiber.pendingProps);
31094
- path46 = enqueueConcurrentRenderForLane(fiber, 2);
31095
- null !== path46 && scheduleUpdateOnFiber(path46, fiber, 2);
31094
+ path49 = enqueueConcurrentRenderForLane(fiber, 2);
31095
+ null !== path49 && scheduleUpdateOnFiber(path49, fiber, 2);
31096
31096
  };
31097
- overridePropsDeletePath = function(fiber, path46) {
31098
- fiber.pendingProps = copyWithDeleteImpl(fiber.memoizedProps, path46, 0);
31097
+ overridePropsDeletePath = function(fiber, path49) {
31098
+ fiber.pendingProps = copyWithDeleteImpl(fiber.memoizedProps, path49, 0);
31099
31099
  fiber.alternate && (fiber.alternate.pendingProps = fiber.pendingProps);
31100
- path46 = enqueueConcurrentRenderForLane(fiber, 2);
31101
- null !== path46 && scheduleUpdateOnFiber(path46, fiber, 2);
31100
+ path49 = enqueueConcurrentRenderForLane(fiber, 2);
31101
+ null !== path49 && scheduleUpdateOnFiber(path49, fiber, 2);
31102
31102
  };
31103
31103
  overridePropsRenamePath = function(fiber, oldPath, newPath) {
31104
31104
  fiber.pendingProps = copyWithRename(
@@ -33840,13 +33840,13 @@ function __classPrivateFieldGet(receiver, state3, kind, f) {
33840
33840
  // ../../node_modules/.pnpm/@anthropic-ai+sdk@0.94.0_zod@4.4.3/node_modules/@anthropic-ai/sdk/internal/utils/uuid.mjs
33841
33841
  init_esm_shims();
33842
33842
  var uuid4 = function() {
33843
- const { crypto: crypto12 } = globalThis;
33844
- if (crypto12?.randomUUID) {
33845
- uuid4 = crypto12.randomUUID.bind(crypto12);
33846
- return crypto12.randomUUID();
33843
+ const { crypto: crypto13 } = globalThis;
33844
+ if (crypto13?.randomUUID) {
33845
+ uuid4 = crypto13.randomUUID.bind(crypto13);
33846
+ return crypto13.randomUUID();
33847
33847
  }
33848
33848
  const u8 = new Uint8Array(1);
33849
- const randomByte = crypto12 ? () => crypto12.getRandomValues(u8)[0] : () => Math.random() * 255 & 255;
33849
+ const randomByte = crypto13 ? () => crypto13.getRandomValues(u8)[0] : () => Math.random() * 255 & 255;
33850
33850
  return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, (c2) => (+c2 ^ randomByte() & 15 >> +c2 / 4).toString(16));
33851
33851
  };
33852
33852
 
@@ -34333,15 +34333,15 @@ function redactSensitive(body) {
34333
34333
  }
34334
34334
  return null;
34335
34335
  }
34336
- async function checkCredentialsFileSafety(path46, onWarn = (m) => console.warn(`anthropic-sdk: ${m}`)) {
34336
+ async function checkCredentialsFileSafety(path49, onWarn = (m) => console.warn(`anthropic-sdk: ${m}`)) {
34337
34337
  if (typeof process === "undefined" || process.platform === "win32")
34338
34338
  return;
34339
- const fs38 = await import("fs");
34340
- let resolved = path46;
34339
+ const fs40 = await import("fs");
34340
+ let resolved = path49;
34341
34341
  let st;
34342
34342
  try {
34343
- resolved = await fs38.promises.realpath(path46);
34344
- st = await fs38.promises.stat(resolved);
34343
+ resolved = await fs40.promises.realpath(path49);
34344
+ st = await fs40.promises.stat(resolved);
34345
34345
  } catch {
34346
34346
  return;
34347
34347
  }
@@ -34357,27 +34357,27 @@ async function checkCredentialsFileSafety(path46, onWarn = (m) => console.warn(`
34357
34357
  }
34358
34358
  }
34359
34359
  async function writeCredentialsFileAtomic(targetPath, data) {
34360
- const fs38 = await import("fs");
34361
- const path46 = await import("path");
34362
- const dir = path46.dirname(targetPath);
34363
- await fs38.promises.mkdir(dir, { recursive: true, mode: 448 });
34360
+ const fs40 = await import("fs");
34361
+ const path49 = await import("path");
34362
+ const dir = path49.dirname(targetPath);
34363
+ await fs40.promises.mkdir(dir, { recursive: true, mode: 448 });
34364
34364
  const tmpPath = `${targetPath}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`;
34365
34365
  try {
34366
- const fh = await fs38.promises.open(tmpPath, "w", 384);
34366
+ const fh = await fs40.promises.open(tmpPath, "w", 384);
34367
34367
  try {
34368
34368
  await fh.writeFile(JSON.stringify(data, null, 2));
34369
34369
  await fh.sync();
34370
34370
  } finally {
34371
34371
  await fh.close();
34372
34372
  }
34373
- await fs38.promises.rename(tmpPath, targetPath);
34373
+ await fs40.promises.rename(tmpPath, targetPath);
34374
34374
  } catch (err) {
34375
- await fs38.promises.unlink(tmpPath).catch(() => {
34375
+ await fs40.promises.unlink(tmpPath).catch(() => {
34376
34376
  });
34377
34377
  throw err;
34378
34378
  }
34379
34379
  try {
34380
- const dirFh = await fs38.promises.open(dir, "r");
34380
+ const dirFh = await fs40.promises.open(dir, "r");
34381
34381
  try {
34382
34382
  await dirFh.sync();
34383
34383
  } finally {
@@ -34679,12 +34679,12 @@ var loadConfigWithSource = async (profile) => {
34679
34679
  return null;
34680
34680
  }
34681
34681
  validateProfileName(profileName);
34682
- const fs38 = await import("fs");
34683
- const path46 = await import("path");
34684
- const configPath = path46.join(rootConfigPath, "configs", `${profileName}.json`);
34682
+ const fs40 = await import("fs");
34683
+ const path49 = await import("path");
34684
+ const configPath = path49.join(rootConfigPath, "configs", `${profileName}.json`);
34685
34685
  let configRaw;
34686
34686
  try {
34687
- configRaw = await fs38.promises.readFile(configPath, "utf-8");
34687
+ configRaw = await fs40.promises.readFile(configPath, "utf-8");
34688
34688
  } catch (err) {
34689
34689
  if (err?.code !== "ENOENT") {
34690
34690
  throw new Error(`failed to read config file ${configPath}: ${err}`);
@@ -34765,37 +34765,37 @@ var getCredentialsPath = async (config2, profile) => {
34765
34765
  return null;
34766
34766
  }
34767
34767
  validateProfileName(profileName);
34768
- const path46 = await import("path");
34769
- return path46.join(rootConfigPath, "credentials", `${profileName}.json`);
34768
+ const path49 = await import("path");
34769
+ return path49.join(rootConfigPath, "credentials", `${profileName}.json`);
34770
34770
  };
34771
34771
  var getRootConfigPath = async () => {
34772
34772
  if (!supportsLocalConfigFiles()) {
34773
34773
  return null;
34774
34774
  }
34775
- const path46 = await import("path");
34775
+ const path49 = await import("path");
34776
34776
  const configDir = readEnv("ANTHROPIC_CONFIG_DIR");
34777
34777
  if (configDir) {
34778
34778
  return configDir;
34779
34779
  }
34780
- const os12 = getPlatformHeaders()["X-Stainless-OS"];
34781
- if (os12 === "Windows") {
34780
+ const os13 = getPlatformHeaders()["X-Stainless-OS"];
34781
+ if (os13 === "Windows") {
34782
34782
  const appData = readEnv("APPDATA");
34783
34783
  if (appData) {
34784
- return path46.join(appData, "Anthropic");
34784
+ return path49.join(appData, "Anthropic");
34785
34785
  }
34786
34786
  const userProfile = readEnv("USERPROFILE");
34787
34787
  if (userProfile) {
34788
- return path46.join(userProfile, "AppData", "Roaming", "Anthropic");
34788
+ return path49.join(userProfile, "AppData", "Roaming", "Anthropic");
34789
34789
  }
34790
34790
  return null;
34791
34791
  }
34792
34792
  const xdgConfigHome = readEnv("XDG_CONFIG_HOME");
34793
34793
  if (xdgConfigHome) {
34794
- return path46.join(xdgConfigHome, "anthropic");
34794
+ return path49.join(xdgConfigHome, "anthropic");
34795
34795
  }
34796
34796
  const home = readEnv("HOME");
34797
34797
  if (home) {
34798
- return path46.join(home, ".config", "anthropic");
34798
+ return path49.join(home, ".config", "anthropic");
34799
34799
  }
34800
34800
  return null;
34801
34801
  };
@@ -34812,11 +34812,11 @@ var getActiveProfileName = async () => {
34812
34812
  if (profileName) {
34813
34813
  return profileName;
34814
34814
  }
34815
- const fs38 = await import("fs");
34816
- const path46 = await import("path");
34817
- const filePath = path46.join(rootConfigPath, "active_config");
34815
+ const fs40 = await import("fs");
34816
+ const path49 = await import("path");
34817
+ const filePath = path49.join(rootConfigPath, "active_config");
34818
34818
  try {
34819
- return (await fs38.promises.readFile(filePath, "utf-8")).trim() || "default";
34819
+ return (await fs40.promises.readFile(filePath, "utf-8")).trim() || "default";
34820
34820
  } catch (err) {
34821
34821
  if (err?.code !== "ENOENT") {
34822
34822
  throw new Error(`failed to read ${filePath}: ${err}`);
@@ -34827,21 +34827,21 @@ var getActiveProfileName = async () => {
34827
34827
 
34828
34828
  // ../../node_modules/.pnpm/@anthropic-ai+sdk@0.94.0_zod@4.4.3/node_modules/@anthropic-ai/sdk/lib/credentials/identity-token.mjs
34829
34829
  init_esm_shims();
34830
- function identityTokenFromFile(path46) {
34831
- if (!path46) {
34830
+ function identityTokenFromFile(path49) {
34831
+ if (!path49) {
34832
34832
  throw new AnthropicError("Identity token file path is empty");
34833
34833
  }
34834
34834
  return async () => {
34835
- const fs38 = await import("fs");
34835
+ const fs40 = await import("fs");
34836
34836
  let content;
34837
34837
  try {
34838
- content = await fs38.promises.readFile(path46, "utf-8");
34838
+ content = await fs40.promises.readFile(path49, "utf-8");
34839
34839
  } catch (err) {
34840
- throw new AnthropicError(`Failed to read identity token file at ${path46}: ${err}`);
34840
+ throw new AnthropicError(`Failed to read identity token file at ${path49}: ${err}`);
34841
34841
  }
34842
34842
  const token = content.trim();
34843
34843
  if (!token) {
34844
- throw new AnthropicError(`Identity token file at ${path46} is empty`);
34844
+ throw new AnthropicError(`Identity token file at ${path49} is empty`);
34845
34845
  }
34846
34846
  return token;
34847
34847
  };
@@ -34916,11 +34916,11 @@ function oidcFederationProvider(config2) {
34916
34916
  init_esm_shims();
34917
34917
  function userOAuthProvider(config2) {
34918
34918
  return async (opts) => {
34919
- const fs38 = await import("fs");
34919
+ const fs40 = await import("fs");
34920
34920
  await checkCredentialsFileSafety(config2.credentialsPath, config2.onSafetyWarning);
34921
34921
  let raw;
34922
34922
  try {
34923
- raw = await fs38.promises.readFile(config2.credentialsPath, "utf-8");
34923
+ raw = await fs40.promises.readFile(config2.credentialsPath, "utf-8");
34924
34924
  } catch (err) {
34925
34925
  throw new WorkloadIdentityError(`Credentials file not found at ${config2.credentialsPath}: ${err}`);
34926
34926
  }
@@ -35084,11 +35084,11 @@ function resolveIdentityTokenProvider(auth2) {
35084
35084
  }
35085
35085
  function cachedExchangeProvider(exchange, credentialsPath, onCacheWriteError, onSafetyWarning) {
35086
35086
  return async (opts) => {
35087
- const fs38 = await import("fs");
35087
+ const fs40 = await import("fs");
35088
35088
  await checkCredentialsFileSafety(credentialsPath, onSafetyWarning);
35089
35089
  let existing;
35090
35090
  try {
35091
- const raw = await fs38.promises.readFile(credentialsPath, "utf-8");
35091
+ const raw = await fs40.promises.readFile(credentialsPath, "utf-8");
35092
35092
  existing = JSON.parse(raw);
35093
35093
  const token = existing?.["access_token"];
35094
35094
  if (token && !opts?.forceRefresh) {
@@ -35927,12 +35927,12 @@ function encodeURIPath(str2) {
35927
35927
  return str2.replace(/[^A-Za-z0-9\-._~!$&'()*+,;=:@]+/g, encodeURIComponent);
35928
35928
  }
35929
35929
  var EMPTY = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.create(null));
35930
- var createPathTagFunction = (pathEncoder = encodeURIPath) => function path46(statics, ...params) {
35930
+ var createPathTagFunction = (pathEncoder = encodeURIPath) => function path49(statics, ...params) {
35931
35931
  if (statics.length === 1)
35932
35932
  return statics[0];
35933
35933
  let postPath = false;
35934
35934
  const invalidSegments = [];
35935
- const path47 = statics.reduce((previousValue, currentValue, index) => {
35935
+ const path50 = statics.reduce((previousValue, currentValue, index) => {
35936
35936
  if (/[?#]/.test(currentValue)) {
35937
35937
  postPath = true;
35938
35938
  }
@@ -35949,7 +35949,7 @@ var createPathTagFunction = (pathEncoder = encodeURIPath) => function path46(sta
35949
35949
  }
35950
35950
  return previousValue + currentValue + (index === params.length ? "" : encoded);
35951
35951
  }, "");
35952
- const pathOnly = path47.split(/[?#]/, 1)[0];
35952
+ const pathOnly = path50.split(/[?#]/, 1)[0];
35953
35953
  const invalidSegmentPattern = /(?<=^|\/)(?:\.|%2e){1,2}(?=\/|$)/gi;
35954
35954
  let match;
35955
35955
  while ((match = invalidSegmentPattern.exec(pathOnly)) !== null) {
@@ -35970,10 +35970,10 @@ var createPathTagFunction = (pathEncoder = encodeURIPath) => function path46(sta
35970
35970
  }, "");
35971
35971
  throw new AnthropicError(`Path parameters result in path with invalid segments:
35972
35972
  ${invalidSegments.map((e) => e.error).join("\n")}
35973
- ${path47}
35973
+ ${path50}
35974
35974
  ${underline}`);
35975
35975
  }
35976
- return path47;
35976
+ return path50;
35977
35977
  };
35978
35978
  var path = /* @__PURE__ */ createPathTagFunction(encodeURIPath);
35979
35979
 
@@ -40734,9 +40734,9 @@ var BaseAnthropic = class {
40734
40734
  makeStatusError(status, error51, message, headers) {
40735
40735
  return APIError.generate(status, error51, message, headers);
40736
40736
  }
40737
- buildURL(path46, query, defaultBaseURL) {
40737
+ buildURL(path49, query, defaultBaseURL) {
40738
40738
  const baseURL = !__classPrivateFieldGet(this, _BaseAnthropic_instances, "m", _BaseAnthropic_baseURLOverridden).call(this) && defaultBaseURL || this.baseURL;
40739
- const url2 = isAbsoluteURL(path46) ? new URL(path46) : new URL(baseURL + (baseURL.endsWith("/") && path46.startsWith("/") ? path46.slice(1) : path46));
40739
+ const url2 = isAbsoluteURL(path49) ? new URL(path49) : new URL(baseURL + (baseURL.endsWith("/") && path49.startsWith("/") ? path49.slice(1) : path49));
40740
40740
  const defaultQuery = this.defaultQuery();
40741
40741
  const pathQuery = Object.fromEntries(url2.searchParams);
40742
40742
  if (!isEmptyObj(defaultQuery) || !isEmptyObj(pathQuery)) {
@@ -40780,24 +40780,24 @@ var BaseAnthropic = class {
40780
40780
  request.headers = headers;
40781
40781
  }
40782
40782
  }
40783
- get(path46, opts) {
40784
- return this.methodRequest("get", path46, opts);
40783
+ get(path49, opts) {
40784
+ return this.methodRequest("get", path49, opts);
40785
40785
  }
40786
- post(path46, opts) {
40787
- return this.methodRequest("post", path46, opts);
40786
+ post(path49, opts) {
40787
+ return this.methodRequest("post", path49, opts);
40788
40788
  }
40789
- patch(path46, opts) {
40790
- return this.methodRequest("patch", path46, opts);
40789
+ patch(path49, opts) {
40790
+ return this.methodRequest("patch", path49, opts);
40791
40791
  }
40792
- put(path46, opts) {
40793
- return this.methodRequest("put", path46, opts);
40792
+ put(path49, opts) {
40793
+ return this.methodRequest("put", path49, opts);
40794
40794
  }
40795
- delete(path46, opts) {
40796
- return this.methodRequest("delete", path46, opts);
40795
+ delete(path49, opts) {
40796
+ return this.methodRequest("delete", path49, opts);
40797
40797
  }
40798
- methodRequest(method, path46, opts) {
40798
+ methodRequest(method, path49, opts) {
40799
40799
  return this.request(Promise.resolve(opts).then((opts2) => {
40800
- return { method, path: path46, ...opts2 };
40800
+ return { method, path: path49, ...opts2 };
40801
40801
  }));
40802
40802
  }
40803
40803
  request(options, remainingRetries = null) {
@@ -40902,8 +40902,8 @@ var BaseAnthropic = class {
40902
40902
  }));
40903
40903
  return { response, options, controller, requestLogID, retryOfRequestLogID, startTime };
40904
40904
  }
40905
- getAPIList(path46, Page3, opts) {
40906
- return this.requestAPIList(Page3, opts && "then" in opts ? opts.then((opts2) => ({ method: "get", path: path46, ...opts2 })) : { method: "get", path: path46, ...opts });
40905
+ getAPIList(path49, Page3, opts) {
40906
+ return this.requestAPIList(Page3, opts && "then" in opts ? opts.then((opts2) => ({ method: "get", path: path49, ...opts2 })) : { method: "get", path: path49, ...opts });
40907
40907
  }
40908
40908
  requestAPIList(Page3, options) {
40909
40909
  const request = this.makeRequest(options, null, void 0);
@@ -40997,14 +40997,14 @@ var BaseAnthropic = class {
40997
40997
  }
40998
40998
  async buildRequest(inputOptions, { retryCount = 0 } = {}) {
40999
40999
  const options = { ...inputOptions };
41000
- const { method, path: path46, query, defaultBaseURL } = options;
41000
+ const { method, path: path49, query, defaultBaseURL } = options;
41001
41001
  if (this._authState.resolution) {
41002
41002
  await this._authState.resolution;
41003
41003
  }
41004
41004
  if (!this._baseURLIsExplicit && this._authState.baseURL && this.baseURL !== this._authState.baseURL) {
41005
41005
  this.baseURL = this._authState.baseURL;
41006
41006
  }
41007
- const url2 = this.buildURL(path46, query, defaultBaseURL);
41007
+ const url2 = this.buildURL(path49, query, defaultBaseURL);
41008
41008
  if ("timeout" in options)
41009
41009
  validatePositiveInteger("timeout", options.timeout);
41010
41010
  options.timeout = options.timeout ?? this.timeout;
@@ -41891,10 +41891,10 @@ function mergeDefs(...defs) {
41891
41891
  function cloneDef(schema) {
41892
41892
  return mergeDefs(schema._zod.def);
41893
41893
  }
41894
- function getElementAtPath(obj, path46) {
41895
- if (!path46)
41894
+ function getElementAtPath(obj, path49) {
41895
+ if (!path49)
41896
41896
  return obj;
41897
- return path46.reduce((acc, key) => acc?.[key], obj);
41897
+ return path49.reduce((acc, key) => acc?.[key], obj);
41898
41898
  }
41899
41899
  function promiseAllObject(promisesObj) {
41900
41900
  const keys = Object.keys(promisesObj);
@@ -42303,11 +42303,11 @@ function explicitlyAborted(x, startIndex = 0) {
42303
42303
  }
42304
42304
  return false;
42305
42305
  }
42306
- function prefixIssues(path46, issues) {
42306
+ function prefixIssues(path49, issues) {
42307
42307
  return issues.map((iss) => {
42308
42308
  var _a6;
42309
42309
  (_a6 = iss).path ?? (_a6.path = []);
42310
- iss.path.unshift(path46);
42310
+ iss.path.unshift(path49);
42311
42311
  return iss;
42312
42312
  });
42313
42313
  }
@@ -42454,16 +42454,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
42454
42454
  }
42455
42455
  function formatError(error51, mapper = (issue2) => issue2.message) {
42456
42456
  const fieldErrors = { _errors: [] };
42457
- const processError = (error52, path46 = []) => {
42457
+ const processError = (error52, path49 = []) => {
42458
42458
  for (const issue2 of error52.issues) {
42459
42459
  if (issue2.code === "invalid_union" && issue2.errors.length) {
42460
- issue2.errors.map((issues) => processError({ issues }, [...path46, ...issue2.path]));
42460
+ issue2.errors.map((issues) => processError({ issues }, [...path49, ...issue2.path]));
42461
42461
  } else if (issue2.code === "invalid_key") {
42462
- processError({ issues: issue2.issues }, [...path46, ...issue2.path]);
42462
+ processError({ issues: issue2.issues }, [...path49, ...issue2.path]);
42463
42463
  } else if (issue2.code === "invalid_element") {
42464
- processError({ issues: issue2.issues }, [...path46, ...issue2.path]);
42464
+ processError({ issues: issue2.issues }, [...path49, ...issue2.path]);
42465
42465
  } else {
42466
- const fullpath = [...path46, ...issue2.path];
42466
+ const fullpath = [...path49, ...issue2.path];
42467
42467
  if (fullpath.length === 0) {
42468
42468
  fieldErrors._errors.push(mapper(issue2));
42469
42469
  } else {
@@ -42490,17 +42490,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
42490
42490
  }
42491
42491
  function treeifyError(error51, mapper = (issue2) => issue2.message) {
42492
42492
  const result = { errors: [] };
42493
- const processError = (error52, path46 = []) => {
42493
+ const processError = (error52, path49 = []) => {
42494
42494
  var _a6, _b;
42495
42495
  for (const issue2 of error52.issues) {
42496
42496
  if (issue2.code === "invalid_union" && issue2.errors.length) {
42497
- issue2.errors.map((issues) => processError({ issues }, [...path46, ...issue2.path]));
42497
+ issue2.errors.map((issues) => processError({ issues }, [...path49, ...issue2.path]));
42498
42498
  } else if (issue2.code === "invalid_key") {
42499
- processError({ issues: issue2.issues }, [...path46, ...issue2.path]);
42499
+ processError({ issues: issue2.issues }, [...path49, ...issue2.path]);
42500
42500
  } else if (issue2.code === "invalid_element") {
42501
- processError({ issues: issue2.issues }, [...path46, ...issue2.path]);
42501
+ processError({ issues: issue2.issues }, [...path49, ...issue2.path]);
42502
42502
  } else {
42503
- const fullpath = [...path46, ...issue2.path];
42503
+ const fullpath = [...path49, ...issue2.path];
42504
42504
  if (fullpath.length === 0) {
42505
42505
  result.errors.push(mapper(issue2));
42506
42506
  continue;
@@ -42532,8 +42532,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
42532
42532
  }
42533
42533
  function toDotPath(_path) {
42534
42534
  const segs = [];
42535
- const path46 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
42536
- for (const seg of path46) {
42535
+ const path49 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
42536
+ for (const seg of path49) {
42537
42537
  if (typeof seg === "number")
42538
42538
  segs.push(`[${seg}]`);
42539
42539
  else if (typeof seg === "symbol")
@@ -55306,13 +55306,13 @@ function resolveRef(ref, ctx) {
55306
55306
  if (!ref.startsWith("#")) {
55307
55307
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
55308
55308
  }
55309
- const path46 = ref.slice(1).split("/").filter(Boolean);
55310
- if (path46.length === 0) {
55309
+ const path49 = ref.slice(1).split("/").filter(Boolean);
55310
+ if (path49.length === 0) {
55311
55311
  return ctx.rootSchema;
55312
55312
  }
55313
55313
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
55314
- if (path46[0] === defsKey) {
55315
- const key = path46[1];
55314
+ if (path49[0] === defsKey) {
55315
+ const key = path49[1];
55316
55316
  if (!key || !ctx.defs[key]) {
55317
55317
  throw new Error(`Reference not found: ${ref}`);
55318
55318
  }
@@ -55749,13 +55749,13 @@ function __classPrivateFieldGet2(receiver, state3, kind, f) {
55749
55749
  // ../../node_modules/.pnpm/openai@6.34.0_ws@8.20.0_zod@4.4.3/node_modules/openai/internal/utils/uuid.mjs
55750
55750
  init_esm_shims();
55751
55751
  var uuid43 = function() {
55752
- const { crypto: crypto12 } = globalThis;
55753
- if (crypto12?.randomUUID) {
55754
- uuid43 = crypto12.randomUUID.bind(crypto12);
55755
- return crypto12.randomUUID();
55752
+ const { crypto: crypto13 } = globalThis;
55753
+ if (crypto13?.randomUUID) {
55754
+ uuid43 = crypto13.randomUUID.bind(crypto13);
55755
+ return crypto13.randomUUID();
55756
55756
  }
55757
55757
  const u8 = new Uint8Array(1);
55758
- const randomByte = crypto12 ? () => crypto12.getRandomValues(u8)[0] : () => Math.random() * 255 & 255;
55758
+ const randomByte = crypto13 ? () => crypto13.getRandomValues(u8)[0] : () => Math.random() * 255 & 255;
55759
55759
  return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, (c2) => (+c2 ^ randomByte() & 15 >> +c2 / 4).toString(16));
55760
55760
  };
55761
55761
 
@@ -57541,12 +57541,12 @@ function encodeURIPath2(str2) {
57541
57541
  return str2.replace(/[^A-Za-z0-9\-._~!$&'()*+,;=:@]+/g, encodeURIComponent);
57542
57542
  }
57543
57543
  var EMPTY2 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.create(null));
57544
- var createPathTagFunction2 = (pathEncoder = encodeURIPath2) => function path46(statics, ...params) {
57544
+ var createPathTagFunction2 = (pathEncoder = encodeURIPath2) => function path49(statics, ...params) {
57545
57545
  if (statics.length === 1)
57546
57546
  return statics[0];
57547
57547
  let postPath = false;
57548
57548
  const invalidSegments = [];
57549
- const path47 = statics.reduce((previousValue, currentValue, index) => {
57549
+ const path50 = statics.reduce((previousValue, currentValue, index) => {
57550
57550
  if (/[?#]/.test(currentValue)) {
57551
57551
  postPath = true;
57552
57552
  }
@@ -57563,7 +57563,7 @@ var createPathTagFunction2 = (pathEncoder = encodeURIPath2) => function path46(s
57563
57563
  }
57564
57564
  return previousValue + currentValue + (index === params.length ? "" : encoded);
57565
57565
  }, "");
57566
- const pathOnly = path47.split(/[?#]/, 1)[0];
57566
+ const pathOnly = path50.split(/[?#]/, 1)[0];
57567
57567
  const invalidSegmentPattern = /(?<=^|\/)(?:\.|%2e){1,2}(?=\/|$)/gi;
57568
57568
  let match;
57569
57569
  while ((match = invalidSegmentPattern.exec(pathOnly)) !== null) {
@@ -57584,10 +57584,10 @@ var createPathTagFunction2 = (pathEncoder = encodeURIPath2) => function path46(s
57584
57584
  }, "");
57585
57585
  throw new OpenAIError(`Path parameters result in path with invalid segments:
57586
57586
  ${invalidSegments.map((e) => e.error).join("\n")}
57587
- ${path47}
57587
+ ${path50}
57588
57588
  ${underline}`);
57589
57589
  }
57590
- return path47;
57590
+ return path50;
57591
57591
  };
57592
57592
  var path2 = /* @__PURE__ */ createPathTagFunction2(encodeURIPath2);
57593
57593
 
@@ -62713,9 +62713,9 @@ var OpenAI = class {
62713
62713
  this.apiKey = token;
62714
62714
  return true;
62715
62715
  }
62716
- buildURL(path46, query, defaultBaseURL) {
62716
+ buildURL(path49, query, defaultBaseURL) {
62717
62717
  const baseURL = !__classPrivateFieldGet2(this, _OpenAI_instances, "m", _OpenAI_baseURLOverridden).call(this) && defaultBaseURL || this.baseURL;
62718
- const url2 = isAbsoluteURL2(path46) ? new URL(path46) : new URL(baseURL + (baseURL.endsWith("/") && path46.startsWith("/") ? path46.slice(1) : path46));
62718
+ const url2 = isAbsoluteURL2(path49) ? new URL(path49) : new URL(baseURL + (baseURL.endsWith("/") && path49.startsWith("/") ? path49.slice(1) : path49));
62719
62719
  const defaultQuery = this.defaultQuery();
62720
62720
  const pathQuery = Object.fromEntries(url2.searchParams);
62721
62721
  if (!isEmptyObj2(defaultQuery) || !isEmptyObj2(pathQuery)) {
@@ -62740,24 +62740,24 @@ var OpenAI = class {
62740
62740
  */
62741
62741
  async prepareRequest(request, { url: url2, options }) {
62742
62742
  }
62743
- get(path46, opts) {
62744
- return this.methodRequest("get", path46, opts);
62743
+ get(path49, opts) {
62744
+ return this.methodRequest("get", path49, opts);
62745
62745
  }
62746
- post(path46, opts) {
62747
- return this.methodRequest("post", path46, opts);
62746
+ post(path49, opts) {
62747
+ return this.methodRequest("post", path49, opts);
62748
62748
  }
62749
- patch(path46, opts) {
62750
- return this.methodRequest("patch", path46, opts);
62749
+ patch(path49, opts) {
62750
+ return this.methodRequest("patch", path49, opts);
62751
62751
  }
62752
- put(path46, opts) {
62753
- return this.methodRequest("put", path46, opts);
62752
+ put(path49, opts) {
62753
+ return this.methodRequest("put", path49, opts);
62754
62754
  }
62755
- delete(path46, opts) {
62756
- return this.methodRequest("delete", path46, opts);
62755
+ delete(path49, opts) {
62756
+ return this.methodRequest("delete", path49, opts);
62757
62757
  }
62758
- methodRequest(method, path46, opts) {
62758
+ methodRequest(method, path49, opts) {
62759
62759
  return this.request(Promise.resolve(opts).then((opts2) => {
62760
- return { method, path: path46, ...opts2 };
62760
+ return { method, path: path49, ...opts2 };
62761
62761
  }));
62762
62762
  }
62763
62763
  request(options, remainingRetries = null) {
@@ -62875,8 +62875,8 @@ var OpenAI = class {
62875
62875
  }));
62876
62876
  return { response, options, controller, requestLogID, retryOfRequestLogID, startTime };
62877
62877
  }
62878
- getAPIList(path46, Page3, opts) {
62879
- return this.requestAPIList(Page3, opts && "then" in opts ? opts.then((opts2) => ({ method: "get", path: path46, ...opts2 })) : { method: "get", path: path46, ...opts });
62878
+ getAPIList(path49, Page3, opts) {
62879
+ return this.requestAPIList(Page3, opts && "then" in opts ? opts.then((opts2) => ({ method: "get", path: path49, ...opts2 })) : { method: "get", path: path49, ...opts });
62880
62880
  }
62881
62881
  requestAPIList(Page3, options) {
62882
62882
  const request = this.makeRequest(options, null, void 0);
@@ -62967,8 +62967,8 @@ var OpenAI = class {
62967
62967
  }
62968
62968
  async buildRequest(inputOptions, { retryCount = 0 } = {}) {
62969
62969
  const options = { ...inputOptions };
62970
- const { method, path: path46, query, defaultBaseURL } = options;
62971
- const url2 = this.buildURL(path46, query, defaultBaseURL);
62970
+ const { method, path: path49, query, defaultBaseURL } = options;
62971
+ const url2 = this.buildURL(path49, query, defaultBaseURL);
62972
62972
  if ("timeout" in options)
62973
62973
  validatePositiveInteger2("timeout", options.timeout);
62974
62974
  options.timeout = options.timeout ?? this.timeout;
@@ -63452,10 +63452,15 @@ var StreamResult = class {
63452
63452
  return this.response.then(onfulfilled, onrejected);
63453
63453
  }
63454
63454
  };
63455
+ var schemaCache = /* @__PURE__ */ new WeakMap();
63455
63456
  function zodToJsonSchema(schema) {
63457
+ const cached4 = schemaCache.get(schema);
63458
+ if (cached4) return cached4;
63456
63459
  const jsonSchema = external_exports.toJSONSchema(schema);
63457
63460
  const { $schema: _schema, ...rest } = jsonSchema;
63458
- return normalizeRootForAnthropic(rest);
63461
+ const normalized = normalizeRootForAnthropic(rest);
63462
+ schemaCache.set(schema, normalized);
63463
+ return normalized;
63459
63464
  }
63460
63465
  function resolveToolSchema(tool) {
63461
63466
  return tool.rawInputSchema ?? zodToJsonSchema(tool.parameters);
@@ -63845,16 +63850,17 @@ function toAnthropicThinking(level, maxTokens, model) {
63845
63850
  outputConfig: { effort }
63846
63851
  };
63847
63852
  }
63853
+ const VISIBLE_FLOOR = 1024;
63848
63854
  const effectiveLevel = level === "xhigh" || level === "max" ? "high" : level;
63849
63855
  const budgetMap = {
63850
- low: Math.max(1024, Math.floor(maxTokens * 0.25)),
63851
- medium: Math.max(2048, Math.floor(maxTokens * 0.5)),
63852
- high: Math.max(4096, maxTokens)
63856
+ low: Math.max(1024, Math.floor(maxTokens * 0.2)),
63857
+ medium: Math.max(2048, Math.floor(maxTokens * 0.45)),
63858
+ high: Math.max(4096, Math.floor(maxTokens * 0.8))
63853
63859
  };
63854
- const budget = budgetMap[effectiveLevel];
63860
+ const budget = Math.max(0, Math.min(budgetMap[effectiveLevel], maxTokens - VISIBLE_FLOOR));
63855
63861
  return {
63856
63862
  thinking: { type: "enabled", budget_tokens: budget },
63857
- maxTokens: maxTokens + budget
63863
+ maxTokens
63858
63864
  };
63859
63865
  }
63860
63866
  function remapToolCallId(id2, idMap) {
@@ -64056,26 +64062,86 @@ function parseToolArguments(argsJson) {
64056
64062
  return {};
64057
64063
  }
64058
64064
  }
64065
+ var anthropicClientCache = /* @__PURE__ */ new Map();
64059
64066
  function createClient(options) {
64060
64067
  const isOAuth = options.apiKey?.startsWith("sk-ant-oat");
64061
- return new Anthropic({
64068
+ const userAgent = isOAuth ? options.userAgent ?? "claude-cli/2.1.75 (external, cli)" : "";
64069
+ const cacheKey = `${options.apiKey ?? ""}|${options.baseUrl ?? ""}|${userAgent}`;
64070
+ if (!options.fetch) {
64071
+ const cached4 = anthropicClientCache.get(cacheKey);
64072
+ if (cached4) return cached4;
64073
+ }
64074
+ const client = new Anthropic({
64062
64075
  ...isOAuth ? { apiKey: null, authToken: options.apiKey } : { apiKey: options.apiKey },
64063
64076
  ...options.baseUrl ? { baseURL: options.baseUrl } : {},
64064
64077
  ...options.fetch ? { fetch: options.fetch } : {},
64065
- // Disable SDK retries — the agent loop has its own stall/overload retry
64066
- // logic that surfaces errors properly. SDK retries on 429s can cause
64067
- // multi-minute hangs when the provider stops responding mid-retry.
64068
64078
  maxRetries: 0,
64069
64079
  ...isOAuth ? {
64070
64080
  defaultHeaders: {
64071
64081
  // Anthropic's OAuth edge validates the claude-cli version. Callers
64072
64082
  // (ezcoder) resolve the live version at runtime; the literal here
64073
- // is the offline fallback for direct gg-ai consumers.
64074
- "user-agent": options.userAgent ?? "claude-cli/2.1.75 (external, cli)",
64083
+ // is the offline fallback for direct ai consumers.
64084
+ "user-agent": userAgent,
64075
64085
  "x-app": "cli"
64076
64086
  }
64077
64087
  } : {}
64078
64088
  });
64089
+ if (!options.fetch) {
64090
+ if (anthropicClientCache.size >= 8) {
64091
+ const oldest = anthropicClientCache.keys().next().value;
64092
+ if (oldest) anthropicClientCache.delete(oldest);
64093
+ }
64094
+ anthropicClientCache.set(cacheKey, client);
64095
+ }
64096
+ return client;
64097
+ }
64098
+ async function prewarmAnthropicCache(options) {
64099
+ try {
64100
+ const client = createClient({
64101
+ apiKey: options.apiKey,
64102
+ baseUrl: options.baseUrl,
64103
+ userAgent: options.userAgent
64104
+ });
64105
+ const cacheControl = toAnthropicCacheControl(options.cacheRetention ?? "long", options.baseUrl);
64106
+ const { system, messages } = toAnthropicMessages(
64107
+ [
64108
+ { role: "system", content: options.system },
64109
+ { role: "user", content: "." }
64110
+ ],
64111
+ cacheControl
64112
+ );
64113
+ const isOAuth = options.apiKey.startsWith("sk-ant-oat");
64114
+ const fullSystem = isOAuth ? [
64115
+ {
64116
+ type: "text",
64117
+ text: "You are Claude Code, Anthropic's official CLI for Claude."
64118
+ },
64119
+ ...system ?? []
64120
+ ] : system;
64121
+ const tools = options.tools?.length ? toAnthropicTools(options.tools, {
64122
+ cacheControl,
64123
+ enableFineGrainedToolStreaming: true
64124
+ }) : void 0;
64125
+ await client.messages.create(
64126
+ {
64127
+ model: options.model,
64128
+ max_tokens: 1,
64129
+ messages,
64130
+ ...fullSystem ? { system: fullSystem } : {},
64131
+ ...tools ? {
64132
+ tools: [
64133
+ ...tools,
64134
+ ...options.serverTools ?? []
64135
+ ]
64136
+ } : {}
64137
+ },
64138
+ {
64139
+ signal: options.signal ?? void 0,
64140
+ ...isOAuth ? { headers: { "anthropic-beta": "claude-code-20250219,oauth-2025-04-20" } } : {}
64141
+ }
64142
+ );
64143
+ } catch {
64144
+ }
64079
64145
  }
64080
64146
  function streamAnthropic(options) {
64081
64147
  return new StreamResult(runStream(options), options.signal);
@@ -64639,13 +64705,27 @@ function extractOpenAIUsage(usage) {
64639
64705
  cacheRead
64640
64706
  };
64641
64707
  }
64708
+ var openaiClientCache = /* @__PURE__ */ new Map();
64642
64709
  function createClient2(options) {
64643
- return new OpenAI({
64710
+ const cacheKey = `${options.apiKey ?? ""}|${options.baseUrl ?? ""}|${JSON.stringify(options.defaultHeaders ?? {})}`;
64711
+ if (!options.fetch) {
64712
+ const cached4 = openaiClientCache.get(cacheKey);
64713
+ if (cached4) return cached4;
64714
+ }
64715
+ const client = new OpenAI({
64644
64716
  apiKey: options.apiKey,
64645
64717
  ...options.baseUrl ? { baseURL: options.baseUrl } : {},
64646
64718
  ...options.fetch ? { fetch: options.fetch } : {},
64647
64719
  ...options.defaultHeaders ? { defaultHeaders: options.defaultHeaders } : {}
64648
64720
  });
64721
+ if (!options.fetch) {
64722
+ if (openaiClientCache.size >= 8) {
64723
+ const oldest = openaiClientCache.keys().next().value;
64724
+ if (oldest) openaiClientCache.delete(oldest);
64725
+ }
64726
+ openaiClientCache.set(cacheKey, client);
64727
+ }
64728
+ return client;
64649
64729
  }
64650
64730
  function streamOpenAI(options) {
64651
64731
  return new StreamResult(runStream2(options), options.signal);
@@ -64703,11 +64783,11 @@ async function* runStream2(options) {
64703
64783
  }
64704
64784
  }
64705
64785
  if (getEnvironment()?.GGAI_DUMP_REQUEST) {
64706
- const fs38 = await import("fs");
64786
+ const fs40 = await import("fs");
64707
64787
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
64708
64788
  const dumpPath = `/tmp/ggai-request-${ts}.json`;
64709
- fs38.writeFileSync(dumpPath, JSON.stringify(params, null, 2));
64710
- fs38.appendFileSync(
64789
+ fs40.writeFileSync(dumpPath, JSON.stringify(params, null, 2));
64790
+ fs40.appendFileSync(
64711
64791
  "/tmp/ggai-requests.log",
64712
64792
  `[${ts}] ${dumpPath} messages=${params.messages.length}
64713
64793
  `
@@ -65051,9 +65131,6 @@ async function* runStream3(options) {
65051
65131
  body.tools = toCodexTools(options.tools);
65052
65132
  }
65053
65133
  body.prompt_cache_key = normalizePromptCacheKey(options.promptCacheKey ?? "ezcoder");
65054
- if (options.cacheRetention === "long") {
65055
- body.prompt_cache_retention = "24h";
65056
- }
65057
65134
  if (options.temperature != null && !options.thinking) {
65058
65135
  body.temperature = options.temperature;
65059
65136
  }
@@ -67501,7 +67578,7 @@ var Agent = class {
67501
67578
  }
67502
67579
  };
67503
67580
 
67504
- // ../core/dist/chunk-LN5L2S5G.js
67581
+ // ../core/dist/chunk-RHNQ3WBA.js
67505
67582
  init_esm_shims();
67506
67583
  var MODELS = [
67507
67584
  // ── Anthropic ──────────────────────────────────────────
@@ -67665,6 +67742,20 @@ var MODELS = [
67665
67742
  maxThinkingLevel: "high"
67666
67743
  },
67667
67744
  // ── Z.AI (GLM) ─────────────────────────────────────────
67745
+ // GLM-5.2: coding-first flagship with a usable 1M-token context window
67746
+ // (5x jump over GLM-5.1's ~200K) and 131K max output. Released 2026-06-13.
67747
+ {
67748
+ id: "glm-5.2",
67749
+ name: "GLM-5.2",
67750
+ provider: "glm",
67751
+ contextWindow: 1e6,
67752
+ maxOutputTokens: 131072,
67753
+ supportsThinking: true,
67754
+ supportsImages: false,
67755
+ supportsVideo: false,
67756
+ costTier: "medium",
67757
+ maxThinkingLevel: "high"
67758
+ },
67668
67759
  {
67669
67760
  id: "glm-5.1",
67670
67761
  name: "GLM-5.1",
@@ -67802,7 +67893,7 @@ function getDefaultModel(provider) {
67802
67893
  if (provider === "xiaomi") return MODELS.find((m) => m.id === "mimo-v2.5-pro");
67803
67894
  if (provider === "openai") return MODELS.find((m) => m.id === "gpt-5.5");
67804
67895
  if (provider === "gemini") return MODELS.find((m) => m.id === "gemini-3.1-flash-lite-preview");
67805
- if (provider === "glm") return MODELS.find((m) => m.id === "glm-5.1");
67896
+ if (provider === "glm") return MODELS.find((m) => m.id === "glm-5.2");
67806
67897
  if (provider === "moonshot") return MODELS.find((m) => m.id === "kimi-k2.7-code");
67807
67898
  if (provider === "minimax") return MODELS.find((m) => m.id === "MiniMax-M3");
67808
67899
  if (provider === "deepseek") return MODELS.find((m) => m.id === "deepseek-v4-pro");
@@ -67837,7 +67928,7 @@ function getSummaryModel(provider, currentModelId) {
67837
67928
  // ../core/dist/index.js
67838
67929
  init_esm_shims();
67839
67930
 
67840
- // ../core/dist/chunk-2MH5WQIW.js
67931
+ // ../core/dist/chunk-WQFTKHPJ.js
67841
67932
  init_esm_shims();
67842
67933
  import path3 from "path";
67843
67934
  import os2 from "os";
@@ -67851,6 +67942,7 @@ function getAppPaths() {
67851
67942
  telegramFile: path3.join(agentDir, "telegram.json"),
67852
67943
  agentHomeFile: path3.join(agentDir, "agent-home.json"),
67853
67944
  mcpFile: path3.join(agentDir, "mcp.json"),
67945
+ mcpAuthFile: path3.join(agentDir, "mcp-auth.json"),
67854
67946
  logFile: path3.join(agentDir, "debug.log"),
67855
67947
  skillsDir: path3.join(agentDir, "skills"),
67856
67948
  extensionsDir: path3.join(agentDir, "extensions"),
@@ -68303,12 +68395,12 @@ function macOsProductVersion() {
68303
68395
  }
68304
68396
  }
68305
68397
  function deviceModel() {
68306
- const os12 = type();
68398
+ const os13 = type();
68307
68399
  const version2 = release();
68308
68400
  const osArch = arch();
68309
- if (os12 === "Darwin") return `macOS ${macOsProductVersion() ?? version2} ${osArch}`;
68310
- if (os12 === "Windows_NT") return `Windows ${version2} ${osArch}`;
68311
- return `${os12} ${version2} ${osArch}`.trim();
68401
+ if (os13 === "Darwin") return `macOS ${macOsProductVersion() ?? version2} ${osArch}`;
68402
+ if (os13 === "Windows_NT") return `Windows ${version2} ${osArch}`;
68403
+ return `${os13} ${version2} ${osArch}`.trim();
68312
68404
  }
68313
68405
  function deviceId() {
68314
68406
  const idPath = path32.join(getAppPaths().agentDir, "kimi_device_id");
@@ -69123,7 +69215,7 @@ init_esm_shims();
69123
69215
  import { spawn as spawn2, spawnSync } from "child_process";
69124
69216
  import fs6 from "fs";
69125
69217
  import fsp from "fs/promises";
69126
- import path6 from "path";
69218
+ import path7 from "path";
69127
69219
  import os3 from "os";
69128
69220
  import crypto2 from "crypto";
69129
69221
 
@@ -69181,7 +69273,34 @@ var ENV_ALLOWLIST = /* @__PURE__ */ new Set([
69181
69273
  "ANDROID_SDK_ROOT",
69182
69274
  "RUBY_VERSION",
69183
69275
  "GEM_HOME",
69184
- "RBENV_ROOT"
69276
+ "RBENV_ROOT",
69277
+ // Windows essentials. Without these, child processes (cmd.exe, Git Bash,
69278
+ // node, npm, MCP stdio servers) misbehave or fail to spawn: SystemRoot +
69279
+ // PATHEXT are required by the Windows loader/resolver, ComSpec is the
69280
+ // cmd.exe path, and the USERPROFILE/APPDATA/TEMP family is where toolchains
69281
+ // read and write. Stripping them was a silent cause of broken shell calls.
69282
+ "SystemRoot",
69283
+ "SystemDrive",
69284
+ "windir",
69285
+ "PATHEXT",
69286
+ "ComSpec",
69287
+ "COMSPEC",
69288
+ "USERPROFILE",
69289
+ "HOMEDRIVE",
69290
+ "HOMEPATH",
69291
+ "APPDATA",
69292
+ "LOCALAPPDATA",
69293
+ "PROGRAMDATA",
69294
+ "ProgramData",
69295
+ "ProgramFiles",
69296
+ "ProgramFiles(x86)",
69297
+ "ProgramW6432",
69298
+ "TEMP",
69299
+ "TMP",
69300
+ "NUMBER_OF_PROCESSORS",
69301
+ "PROCESSOR_ARCHITECTURE",
69302
+ // Git Bash override for the agent shell (see core/shell.ts).
69303
+ "GG_BASH"
69185
69304
  ]);
69186
69305
  function getSafeToolEnv(sourceEnv = process.env) {
69187
69306
  const env2 = { TERM: "dumb", EZ_CODER: "true" };
@@ -69193,8 +69312,68 @@ function getSafeToolEnv(sourceEnv = process.env) {
69193
69312
  return env2;
69194
69313
  }
69195
69314
 
69315
+ // ../cli/dist/core/shell.js
69316
+ init_esm_shims();
69317
+ import { existsSync as existsSync2 } from "fs";
69318
+ import path6 from "path";
69319
+ function gitBashFixedCandidates(env2) {
69320
+ const programFiles = env2.ProgramFiles ?? "C:\\Program Files";
69321
+ const programFilesX86 = env2["ProgramFiles(x86)"] ?? "C:\\Program Files (x86)";
69322
+ const localAppData = env2.LOCALAPPDATA;
69323
+ const candidates = [
69324
+ path6.win32.join(programFiles, "Git", "bin", "bash.exe"),
69325
+ path6.win32.join(programFilesX86, "Git", "bin", "bash.exe")
69326
+ ];
69327
+ if (localAppData) {
69328
+ candidates.push(path6.win32.join(localAppData, "Programs", "Git", "bin", "bash.exe"));
69329
+ }
69330
+ return candidates;
69331
+ }
69332
+ function gitBashFromPath(env2, exists) {
69333
+ const rawPath = env2.PATH ?? env2.Path ?? "";
69334
+ if (!rawPath)
69335
+ return null;
69336
+ for (const dir of rawPath.split(";")) {
69337
+ if (!dir)
69338
+ continue;
69339
+ const gitExe = path6.win32.join(dir, "git.exe");
69340
+ if (!exists(gitExe))
69341
+ continue;
69342
+ const gitRoot = path6.win32.dirname(path6.win32.dirname(gitExe));
69343
+ const bash2 = path6.win32.join(gitRoot, "bin", "bash.exe");
69344
+ if (exists(bash2))
69345
+ return bash2;
69346
+ }
69347
+ return null;
69348
+ }
69349
+ function findGitBash(env2, exists) {
69350
+ for (const candidate of gitBashFixedCandidates(env2)) {
69351
+ if (exists(candidate))
69352
+ return candidate;
69353
+ }
69354
+ return gitBashFromPath(env2, exists);
69355
+ }
69356
+ function resolveShell(command, opts = {}) {
69357
+ const platform2 = opts.platform ?? process.platform;
69358
+ const env2 = opts.env ?? process.env;
69359
+ const exists = opts.exists ?? existsSync2;
69360
+ const override = env2.GG_BASH?.trim();
69361
+ if (override) {
69362
+ return { file: override, args: ["-c", command], isCmdFallback: false };
69363
+ }
69364
+ if (platform2 !== "win32") {
69365
+ return { file: "bash", args: ["-c", command], isCmdFallback: false };
69366
+ }
69367
+ const gitBash = findGitBash(env2, exists);
69368
+ if (gitBash) {
69369
+ return { file: gitBash, args: ["-c", command], isCmdFallback: false };
69370
+ }
69371
+ const comspec = env2.ComSpec ?? env2.COMSPEC ?? "C:\\Windows\\System32\\cmd.exe";
69372
+ return { file: comspec, args: ["/d", "/s", "/c", command], isCmdFallback: true };
69373
+ }
69374
+
69196
69375
  // ../cli/dist/core/process-manager.js
69197
- var BG_DIR = path6.join(os3.homedir(), ".ezcoder", "bg");
69376
+ var BG_DIR = path7.join(os3.homedir(), ".ezcoder", "bg");
69198
69377
  function stopProcessTree(pid, ops = {}) {
69199
69378
  if ((ops.platform ?? process.platform) === "win32") {
69200
69379
  (ops.spawnSync ?? spawnSync)("taskkill", ["/pid", String(pid), "/T", "/F"], {
@@ -69214,9 +69393,10 @@ var ProcessManager = class {
69214
69393
  async start(command, cwd2) {
69215
69394
  await fsp.mkdir(BG_DIR, { recursive: true });
69216
69395
  const id2 = crypto2.randomUUID().slice(0, 8);
69217
- const logFile = path6.join(BG_DIR, `${id2}.log`);
69396
+ const logFile = path7.join(BG_DIR, `${id2}.log`);
69218
69397
  const fd2 = fs6.openSync(logFile, "w");
69219
- const child = spawn2("bash", ["-c", command], {
69398
+ const shell2 = resolveShell(command);
69399
+ const child = spawn2(shell2.file, shell2.args, {
69220
69400
  cwd: cwd2,
69221
69401
  detached: true,
69222
69402
  // stdin is a pipe so callers can drive interactive processes (REPLs,
@@ -69359,7 +69539,7 @@ var ProcessManager = class {
69359
69539
 
69360
69540
  // ../cli/dist/core/lsp/manager.js
69361
69541
  init_esm_shims();
69362
- import path8 from "path";
69542
+ import path9 from "path";
69363
69543
 
69364
69544
  // ../cli/dist/core/logger.js
69365
69545
  init_esm_shims();
@@ -69728,7 +69908,7 @@ Diagnostics in ${relPath} (informational \u2014 may resolve after related edits)
69728
69908
  // ../cli/dist/core/lsp/servers.js
69729
69909
  init_esm_shims();
69730
69910
  import fs7 from "fs";
69731
- import path7 from "path";
69911
+ import path8 from "path";
69732
69912
  import { fileURLToPath } from "url";
69733
69913
  var WINDOWS_SUFFIXES = [".cmd", ".exe", ".bat"];
69734
69914
  function isExecutableFile(candidate) {
@@ -69744,13 +69924,13 @@ function candidateNames(name) {
69744
69924
  return [name];
69745
69925
  return [name, ...WINDOWS_SUFFIXES.map((suffix) => `${name}${suffix}`)];
69746
69926
  }
69747
- var MODULE_DIR = path7.dirname(fileURLToPath(import.meta.url));
69927
+ var MODULE_DIR = path8.dirname(fileURLToPath(import.meta.url));
69748
69928
  function binDirsUpFrom(start) {
69749
69929
  const dirs = [];
69750
69930
  let dir = start;
69751
69931
  for (; ; ) {
69752
- dirs.push(path7.join(dir, "node_modules", ".bin"));
69753
- const parent = path7.dirname(dir);
69932
+ dirs.push(path8.join(dir, "node_modules", ".bin"));
69933
+ const parent = path8.dirname(dir);
69754
69934
  if (parent === dir)
69755
69935
  break;
69756
69936
  dir = parent;
@@ -69762,17 +69942,17 @@ function findExecutable(name, projectRoot) {
69762
69942
  const binDirs = [...binDirsUpFrom(projectRoot), ...binDirsUpFrom(MODULE_DIR)];
69763
69943
  for (const binDir of binDirs) {
69764
69944
  for (const candidate of names) {
69765
- const binPath = path7.join(binDir, candidate);
69945
+ const binPath = path8.join(binDir, candidate);
69766
69946
  if (isExecutableFile(binPath))
69767
69947
  return binPath;
69768
69948
  }
69769
69949
  }
69770
69950
  const pathEnv = process.env.PATH ?? "";
69771
- for (const pathDir of pathEnv.split(path7.delimiter)) {
69951
+ for (const pathDir of pathEnv.split(path8.delimiter)) {
69772
69952
  if (!pathDir)
69773
69953
  continue;
69774
69954
  for (const candidate of names) {
69775
- const binPath = path7.join(pathDir, candidate);
69955
+ const binPath = path8.join(pathDir, candidate);
69776
69956
  if (isExecutableFile(binPath))
69777
69957
  return binPath;
69778
69958
  }
@@ -69782,17 +69962,17 @@ function findExecutable(name, projectRoot) {
69782
69962
  function findInNodeModulesUp(relPath, start) {
69783
69963
  let dir = start;
69784
69964
  for (; ; ) {
69785
- const candidate = path7.join(dir, "node_modules", relPath);
69965
+ const candidate = path8.join(dir, "node_modules", relPath);
69786
69966
  if (fs7.existsSync(candidate))
69787
69967
  return candidate;
69788
- const parent = path7.dirname(dir);
69968
+ const parent = path8.dirname(dir);
69789
69969
  if (parent === dir)
69790
69970
  return null;
69791
69971
  dir = parent;
69792
69972
  }
69793
69973
  }
69794
69974
  function findPackageBinScript(pkgName, binName, start) {
69795
- const pkgJsonPath = findInNodeModulesUp(path7.join(pkgName, "package.json"), start);
69975
+ const pkgJsonPath = findInNodeModulesUp(path8.join(pkgName, "package.json"), start);
69796
69976
  if (!pkgJsonPath)
69797
69977
  return null;
69798
69978
  try {
@@ -69800,7 +69980,7 @@ function findPackageBinScript(pkgName, binName, start) {
69800
69980
  const bin = typeof pkg.bin === "string" ? pkg.bin : pkg.bin?.[binName];
69801
69981
  if (!bin)
69802
69982
  return null;
69803
- const script = path7.join(path7.dirname(pkgJsonPath), bin);
69983
+ const script = path8.join(path8.dirname(pkgJsonPath), bin);
69804
69984
  return fs7.existsSync(script) ? script : null;
69805
69985
  } catch {
69806
69986
  return null;
@@ -69813,7 +69993,7 @@ function resolveNodeServer(pkgName, binName, projectRoot, args) {
69813
69993
  const bin = findExecutable(binName, projectRoot);
69814
69994
  return bin ? { command: bin, args } : null;
69815
69995
  }
69816
- var TSSERVER_REL_PATH = path7.join("typescript", "lib", "tsserver.js");
69996
+ var TSSERVER_REL_PATH = path8.join("typescript", "lib", "tsserver.js");
69817
69997
  function projectTsserverPath(projectRoot) {
69818
69998
  return findInNodeModulesUp(TSSERVER_REL_PATH, projectRoot);
69819
69999
  }
@@ -69903,27 +70083,27 @@ var LSP_SERVER_CATALOG = [
69903
70083
  }
69904
70084
  ];
69905
70085
  function serverForFile(filePath, catalog = LSP_SERVER_CATALOG) {
69906
- const extension = path7.extname(filePath).toLowerCase();
70086
+ const extension = path8.extname(filePath).toLowerCase();
69907
70087
  if (!extension)
69908
70088
  return null;
69909
70089
  return catalog.find((spec) => spec.extensions.includes(extension)) ?? null;
69910
70090
  }
69911
70091
  function findProjectRoot(filePath, markers, ceiling) {
69912
- const fileDir = path7.dirname(path7.resolve(filePath));
69913
- const cap = path7.resolve(ceiling);
69914
- const underCeiling = fileDir === cap || fileDir.startsWith(cap + path7.sep);
70092
+ const fileDir = path8.dirname(path8.resolve(filePath));
70093
+ const cap = path8.resolve(ceiling);
70094
+ const underCeiling = fileDir === cap || fileDir.startsWith(cap + path8.sep);
69915
70095
  let dir = fileDir;
69916
70096
  for (; ; ) {
69917
70097
  for (const marker of markers) {
69918
70098
  try {
69919
- fs7.statSync(path7.join(dir, marker));
70099
+ fs7.statSync(path8.join(dir, marker));
69920
70100
  return dir;
69921
70101
  } catch {
69922
70102
  }
69923
70103
  }
69924
70104
  if (underCeiling && dir === cap)
69925
70105
  break;
69926
- const parent = path7.dirname(dir);
70106
+ const parent = path8.dirname(dir);
69927
70107
  if (parent === dir)
69928
70108
  break;
69929
70109
  dir = parent;
@@ -69994,12 +70174,12 @@ var LspManager = class {
69994
70174
  log("WARN", "lsp", `${spec.id} server died`, { root });
69995
70175
  return "";
69996
70176
  }
69997
- const uri = client.syncDocument(path8.resolve(this.cwd, filePath), content);
70177
+ const uri = client.syncDocument(path9.resolve(this.cwd, filePath), content);
69998
70178
  const diagnostics = await client.collectDiagnostics(uri, budgetMs);
69999
70179
  this.warmKeys.add(key);
70000
70180
  if (diagnostics === null)
70001
70181
  return "";
70002
- const relPath = path8.relative(this.cwd, path8.resolve(this.cwd, filePath));
70182
+ const relPath = path9.relative(this.cwd, path9.resolve(this.cwd, filePath));
70003
70183
  return formatDiagnostics(relPath, diagnostics);
70004
70184
  }
70005
70185
  ensureClient(key, spec, root) {
@@ -70050,18 +70230,18 @@ function withBudget(work, budgetMs) {
70050
70230
  // ../cli/dist/tools/read.js
70051
70231
  init_esm_shims();
70052
70232
  import fs12 from "fs/promises";
70053
- import path12 from "path";
70233
+ import path13 from "path";
70054
70234
 
70055
70235
  // ../cli/dist/tools/path-utils.js
70056
70236
  init_esm_shims();
70057
70237
  import fs8 from "fs/promises";
70058
- import path9 from "path";
70238
+ import path10 from "path";
70059
70239
  import os4 from "os";
70060
70240
  function resolvePath(cwd2, filePath) {
70061
70241
  if (filePath.startsWith("~")) {
70062
- filePath = path9.join(os4.homedir(), filePath.slice(1));
70242
+ filePath = path10.join(os4.homedir(), filePath.slice(1));
70063
70243
  }
70064
- return path9.resolve(cwd2, filePath);
70244
+ return path10.resolve(cwd2, filePath);
70065
70245
  }
70066
70246
  async function rejectSymlink(resolved) {
70067
70247
  try {
@@ -70128,9 +70308,9 @@ function truncateTail(content, maxLines = MAX_LINES, maxBytes = MAX_BYTES2) {
70128
70308
  init_esm_shims();
70129
70309
  import fs9 from "fs/promises";
70130
70310
  import os5 from "os";
70131
- import path10 from "path";
70311
+ import path11 from "path";
70132
70312
  async function writeOverflow(content, prefix) {
70133
- const filePath = path10.join(os5.tmpdir(), `ezcoder-${prefix}-${Date.now()}.txt`);
70313
+ const filePath = path11.join(os5.tmpdir(), `ezcoder-${prefix}-${Date.now()}.txt`);
70134
70314
  await fs9.writeFile(filePath, content, { encoding: "utf-8", mode: 384 });
70135
70315
  return filePath;
70136
70316
  }
@@ -70141,18 +70321,18 @@ import fs10 from "fs/promises";
70141
70321
  import { spawn as spawn4 } from "child_process";
70142
70322
  import { createReadStream } from "fs";
70143
70323
  var localOperations = {
70144
- readFile: (path46) => fs10.readFile(path46, "utf-8"),
70145
- writeFile: async (path46, content) => {
70324
+ readFile: (path49) => fs10.readFile(path49, "utf-8"),
70325
+ writeFile: async (path49, content) => {
70146
70326
  const { dirname: dirname3 } = await import("path");
70147
- await fs10.mkdir(dirname3(path46), { recursive: true });
70148
- await fs10.writeFile(path46, content, "utf-8");
70327
+ await fs10.mkdir(dirname3(path49), { recursive: true });
70328
+ await fs10.writeFile(path49, content, "utf-8");
70149
70329
  },
70150
- stat: (path46) => fs10.stat(path46),
70151
- lstat: (path46) => fs10.lstat(path46),
70152
- readdir: (path46, options) => fs10.readdir(path46, options),
70153
- mkdir: (path46) => fs10.mkdir(path46, { recursive: true }).then(() => {
70330
+ stat: (path49) => fs10.stat(path49),
70331
+ lstat: (path49) => fs10.lstat(path49),
70332
+ readdir: (path49, options) => fs10.readdir(path49, options),
70333
+ mkdir: (path49) => fs10.mkdir(path49, { recursive: true }).then(() => {
70154
70334
  }),
70155
- createReadStream: (path46, encoding) => createReadStream(path46, { encoding }),
70335
+ createReadStream: (path49, encoding) => createReadStream(path49, { encoding }),
70156
70336
  spawn: (command, args, options) => spawn4(command, args, {
70157
70337
  cwd: options.cwd,
70158
70338
  env: options.env,
@@ -70198,7 +70378,7 @@ async function assertFresh(tracker, resolvedPath, ops) {
70198
70378
  init_esm_shims();
70199
70379
  import fs11 from "fs/promises";
70200
70380
  import os6 from "os";
70201
- import path11 from "path";
70381
+ import path12 from "path";
70202
70382
  import { execFile } from "child_process";
70203
70383
  import { promisify } from "util";
70204
70384
  var execFileAsync = promisify(execFile);
@@ -70246,7 +70426,7 @@ async function compressVideoToFit(inputPath, targetBytes = COMPRESS_TARGET_BYTES
70246
70426
  }
70247
70427
  const totalKbps = Math.floor(targetBytes * 8 / durationSec / 1e3 * 0.9);
70248
70428
  const videoKbps = Math.max(COMPRESS_MIN_VIDEO_KBPS, totalKbps - COMPRESS_AUDIO_KBPS);
70249
- const outPath = path11.join(os6.tmpdir(), `ezcoder-compressed-${Date.now()}.mp4`);
70429
+ const outPath = path12.join(os6.tmpdir(), `ezcoder-compressed-${Date.now()}.mp4`);
70250
70430
  try {
70251
70431
  await execFileAsync("ffmpeg", [
70252
70432
  "-y",
@@ -70318,7 +70498,7 @@ var VIDEO_MEDIA_TYPES = {
70318
70498
  };
70319
70499
  var MEDIA_TYPES = IMAGE_MEDIA_TYPES;
70320
70500
  function isAttachablePath(filePath) {
70321
- const ext = path11.extname(filePath).toLowerCase();
70501
+ const ext = path12.extname(filePath).toLowerCase();
70322
70502
  return ATTACHABLE_EXTENSIONS.has(ext);
70323
70503
  }
70324
70504
  function resolvePath2(filePath, cwd2) {
@@ -70331,9 +70511,9 @@ function resolvePath2(filePath, cwd2) {
70331
70511
  }
70332
70512
  resolved = resolved.replace(/\\(.)/g, "$1");
70333
70513
  if (resolved.startsWith("~/")) {
70334
- resolved = path11.join(process.env.HOME ?? "/", resolved.slice(2));
70335
- } else if (!path11.isAbsolute(resolved)) {
70336
- resolved = path11.join(cwd2, resolved);
70514
+ resolved = path12.join(process.env.HOME ?? "/", resolved.slice(2));
70515
+ } else if (!path12.isAbsolute(resolved)) {
70516
+ resolved = path12.join(cwd2, resolved);
70337
70517
  }
70338
70518
  return resolved;
70339
70519
  }
@@ -70446,8 +70626,8 @@ async function downscaleForPreview(buffer) {
70446
70626
  }
70447
70627
  }
70448
70628
  async function readImageFile(filePath) {
70449
- const ext = path11.extname(filePath).toLowerCase();
70450
- const fileName = path11.basename(filePath);
70629
+ const ext = path12.extname(filePath).toLowerCase();
70630
+ const fileName = path12.basename(filePath);
70451
70631
  if (VIDEO_EXTENSIONS.has(ext)) {
70452
70632
  try {
70453
70633
  const mediaType = VIDEO_MEDIA_TYPES[ext] ?? "video/mp4";
@@ -70612,7 +70792,7 @@ function createReadTool(cwd2, readFiles, ops = localOperations, onFileRead, vide
70612
70792
  async execute({ file_path, offset, limit: limit2 }, context) {
70613
70793
  const resolved = resolvePath(cwd2, file_path);
70614
70794
  await rejectSymlink(resolved);
70615
- const ext = path12.extname(resolved).toLowerCase();
70795
+ const ext = path13.extname(resolved).toLowerCase();
70616
70796
  if (IMAGE_EXTENSIONS.has(ext)) {
70617
70797
  try {
70618
70798
  const rawBuffer = await fs12.readFile(resolved);
@@ -70739,7 +70919,7 @@ init_esm_shims();
70739
70919
  // ../cli/dist/tools/write.js
70740
70920
  init_esm_shims();
70741
70921
  import fs13 from "fs/promises";
70742
- import path13 from "path";
70922
+ import path14 from "path";
70743
70923
 
70744
70924
  // ../cli/dist/core/runtime-mode.js
70745
70925
  init_esm_shims();
@@ -70801,9 +70981,9 @@ function createWriteTool(cwd2, readFiles, ops = localOperations, planModeRefOrOn
70801
70981
  return goalModeMutationRestriction("write", goalMode);
70802
70982
  }
70803
70983
  if (isPlanModeActive(planModeRef)) {
70804
- const plansDir = path13.join(cwd2, ".ezcoder", "plans");
70805
- const relative = path13.relative(plansDir, resolved);
70806
- if (relative.startsWith("..") || path13.isAbsolute(relative)) {
70984
+ const plansDir = path14.join(cwd2, ".ezcoder", "plans");
70985
+ const relative = path14.relative(plansDir, resolved);
70986
+ if (relative.startsWith("..") || path14.isAbsolute(relative)) {
70807
70987
  return `Error: write is restricted in plan mode. You can only write to .ezcoder/plans/. Got: ${file_path}`;
70808
70988
  }
70809
70989
  await fs13.mkdir(plansDir, { recursive: true });
@@ -70833,7 +71013,7 @@ function createWriteTool(cwd2, readFiles, ops = localOperations, planModeRefOrOn
70833
71013
 
70834
71014
  // ../cli/dist/tools/edit.js
70835
71015
  init_esm_shims();
70836
- import path14 from "path";
71016
+ import path15 from "path";
70837
71017
 
70838
71018
  // ../cli/dist/tools/edit-diff.js
70839
71019
  init_esm_shims();
@@ -70942,16 +71122,16 @@ var Diff = class {
70942
71122
  }
70943
71123
  }
70944
71124
  }
70945
- addToPath(path46, added, removed, oldPosInc, options) {
70946
- const last = path46.lastComponent;
71125
+ addToPath(path49, added, removed, oldPosInc, options) {
71126
+ const last = path49.lastComponent;
70947
71127
  if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
70948
71128
  return {
70949
- oldPos: path46.oldPos + oldPosInc,
71129
+ oldPos: path49.oldPos + oldPosInc,
70950
71130
  lastComponent: { count: last.count + 1, added, removed, previousComponent: last.previousComponent }
70951
71131
  };
70952
71132
  } else {
70953
71133
  return {
70954
- oldPos: path46.oldPos + oldPosInc,
71134
+ oldPos: path49.oldPos + oldPosInc,
70955
71135
  lastComponent: { count: 1, added, removed, previousComponent: last }
70956
71136
  };
70957
71137
  }
@@ -71726,7 +71906,7 @@ function createEditTool(cwd2, readFiles, ops = localOperations, planModeRefOrOnF
71726
71906
  const hasCRLF = original.includes("\r\n");
71727
71907
  const originalNormalized = hasCRLF ? original.replace(/\r\n/g, "\n") : original;
71728
71908
  let working = originalNormalized;
71729
- const fileName = path14.basename(resolved);
71909
+ const fileName = path15.basename(resolved);
71730
71910
  const outcomes = new Array(edits.length);
71731
71911
  for (let i = 0; i < edits.length; i++) {
71732
71912
  const { old_text, new_text, replace_all } = edits[i];
@@ -71828,7 +72008,7 @@ ${f.closestSnippet}`;
71828
72008
  ` : "";
71829
72009
  throw new Error(header + formatFailures());
71830
72010
  }
71831
- const relPath = path14.relative(cwd2, resolved);
72011
+ const relPath = path15.relative(cwd2, resolved);
71832
72012
  const diff3 = generateDiff(originalNormalized, working, relPath);
71833
72013
  const changed = working !== originalNormalized;
71834
72014
  let diagnosticsNote = "";
@@ -72037,7 +72217,8 @@ Use task_output with id="${result.id}" to read output, task_send to type input/a
72037
72217
  }
72038
72218
  const effectiveTimeout = timeoutMs ?? DEFAULT_TIMEOUT;
72039
72219
  return new Promise((resolve3) => {
72040
- const child = ops.spawn("bash", ["-c", command], {
72220
+ const shell2 = resolveShell(command);
72221
+ const child = ops.spawn(shell2.file, shell2.args, {
72041
72222
  cwd: cwd2,
72042
72223
  detached: true,
72043
72224
  stdio: ["ignore", "pipe", "pipe"],
@@ -72095,6 +72276,9 @@ ${output}`;
72095
72276
  output = `[Truncated: showing last ${result.keptLines} of ${result.totalLines} lines.${overflowNotice}]
72096
72277
  ${output}`;
72097
72278
  }
72279
+ if (shell2.isCmdFallback) {
72280
+ output = "[Ran under Windows cmd.exe \u2014 bash is unavailable. Use cmd syntax (dir, findstr, type); POSIX commands and quoting will fail. Install Git for Windows to get bash.]\n" + output;
72281
+ }
72098
72282
  const exitCode = timedOut ? `TIMEOUT (${effectiveTimeout}ms)` : killed ? "KILLED" : String(code ?? 1);
72099
72283
  resolve3(`Exit code: ${exitCode}
72100
72284
  ${output}`);
@@ -72113,7 +72297,7 @@ Failed to spawn: ${err.message}`);
72113
72297
  // ../cli/dist/tools/find.js
72114
72298
  init_esm_shims();
72115
72299
  import fs14 from "fs/promises";
72116
- import path15 from "path";
72300
+ import path16 from "path";
72117
72301
  var FindParams = external_exports.object({
72118
72302
  pattern: external_exports.string().describe("Glob pattern to match files (e.g. '**/*.ts', 'src/**/*.tsx')"),
72119
72303
  path: external_exports.string().optional().describe("Directory to search in (defaults to cwd)")
@@ -72159,7 +72343,7 @@ ${filtered.length} file(s) found`;
72159
72343
  }
72160
72344
  async function loadGitignore(dir) {
72161
72345
  try {
72162
- const content = await fs14.readFile(path15.join(dir, ".gitignore"), "utf-8");
72346
+ const content = await fs14.readFile(path16.join(dir, ".gitignore"), "utf-8");
72163
72347
  return content.split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
72164
72348
  } catch {
72165
72349
  return [];
@@ -72169,7 +72353,7 @@ async function loadGitignore(dir) {
72169
72353
  // ../cli/dist/tools/grep.js
72170
72354
  init_esm_shims();
72171
72355
  import readline from "readline";
72172
- import path16 from "path";
72356
+ import path17 from "path";
72173
72357
  var GrepParams = external_exports.object({
72174
72358
  pattern: external_exports.string().describe("Search pattern (regex supported)"),
72175
72359
  path: external_exports.string().optional().describe("File or directory to search (defaults to cwd)"),
@@ -72225,10 +72409,10 @@ function createGrepTool(cwd2, ops = localOperations) {
72225
72409
  }
72226
72410
  scannedCandidates += 1;
72227
72411
  const entry = typeof item === "string" ? item : item.path;
72228
- const ext = path16.extname(entry).toLowerCase();
72412
+ const ext = path17.extname(entry).toLowerCase();
72229
72413
  if (BINARY_EXTENSIONS.has(ext))
72230
72414
  continue;
72231
- const filePath = path16.join(dir, entry);
72415
+ const filePath = path17.join(dir, entry);
72232
72416
  const fileResults = await searchFile(filePath, regex2, cwd2, maxResults - results.length, ops);
72233
72417
  results.push(...fileResults);
72234
72418
  }
@@ -72238,7 +72422,7 @@ function createGrepTool(cwd2, ops = localOperations) {
72238
72422
  }
72239
72423
  async function searchFile(filePath, regex2, cwd2, maxResults, ops) {
72240
72424
  const results = [];
72241
- const relPath = path16.relative(cwd2, filePath);
72425
+ const relPath = path17.relative(cwd2, filePath);
72242
72426
  try {
72243
72427
  const fileStat = await ops.stat(filePath);
72244
72428
  if (fileStat.size > MAX_FILE_SIZE)
@@ -72300,7 +72484,7 @@ ${results.length} match(es) found`;
72300
72484
 
72301
72485
  // ../cli/dist/tools/ls.js
72302
72486
  init_esm_shims();
72303
- import path17 from "path";
72487
+ import path18 from "path";
72304
72488
  var LsParams = external_exports.object({
72305
72489
  path: external_exports.string().optional().describe("Directory path (defaults to cwd)"),
72306
72490
  all: external_exports.boolean().optional().describe("Show hidden files (default: false)")
@@ -72322,7 +72506,7 @@ function createLsTool(cwd2, ops = localOperations) {
72322
72506
  }
72323
72507
  for (const file2 of files) {
72324
72508
  try {
72325
- const stat = await ops.stat(path17.join(resolved, file2.name));
72509
+ const stat = await ops.stat(path18.join(resolved, file2.name));
72326
72510
  const size = formatSize(stat.size);
72327
72511
  const type2 = file2.isSymbolicLink() ? "l" : "f";
72328
72512
  lines.push(`${type2} ${size.padStart(8)} ${file2.name}`);
@@ -72350,25 +72534,22 @@ function formatSize(bytes) {
72350
72534
  init_esm_shims();
72351
72535
  import { spawn as spawn5 } from "child_process";
72352
72536
  import { createInterface } from "readline";
72537
+ import { existsSync as existsSync3 } from "fs";
72538
+ import { fileURLToPath as fileURLToPath2 } from "url";
72353
72539
  var SUB_AGENT_MAX_TURNS = 10;
72354
72540
  var SUB_AGENT_MAX_OUTPUT_CHARS = 1e5;
72355
72541
  var SUB_AGENT_MAX_OUTPUT_LINES = 500;
72356
72542
  var SUB_AGENT_MAX_STDERR_CHARS = 1e4;
72357
72543
  var SUB_AGENT_TIMEOUT_MS = 10 * 60 * 1e3;
72358
- function isPlanModeRef4(value) {
72359
- return typeof value === "object" && value !== null && typeof value.current === "boolean";
72360
- }
72361
- function isGoalModeRef4(value) {
72362
- return typeof value === "object" && value !== null && typeof value.current === "string";
72544
+ function resolveCliEntry() {
72545
+ const cliPath = fileURLToPath2(new URL("../cli.js", import.meta.url));
72546
+ return existsSync3(cliPath) ? cliPath : process.argv[1];
72363
72547
  }
72364
72548
  var SubAgentParams = external_exports.object({
72365
72549
  task: external_exports.string().describe("The task to delegate to the sub-agent"),
72366
72550
  agent: external_exports.string().optional().describe("Named agent definition to use (from ~/.ezcoder/agents/ or .ezcoder/agents/)")
72367
72551
  });
72368
- function createSubAgentTool(cwd2, agents, parentProvider, parentModel, getParentCacheKeyOrGoalModeRef, planModeRefArg, goalModeRefArg) {
72369
- const getParentCacheKey = typeof getParentCacheKeyOrGoalModeRef === "function" ? getParentCacheKeyOrGoalModeRef : void 0;
72370
- const goalModeRef = isGoalModeRef4(getParentCacheKeyOrGoalModeRef) ? getParentCacheKeyOrGoalModeRef : goalModeRefArg;
72371
- const planModeRef = isPlanModeRef4(planModeRefArg) ? planModeRefArg : void 0;
72552
+ function createSubAgentTool(cwd2, agents, getParentProvider, getParentModel, getParentCacheKey, planModeRef, goalModeRef) {
72372
72553
  const agentList = agents.map((a) => `- ${a.name}: ${a.description}`).join("\n");
72373
72554
  const agentDesc = agentList ? `
72374
72555
 
@@ -72402,13 +72583,14 @@ ${agentList}` : "\n\nNo named agents configured.";
72402
72583
  };
72403
72584
  }
72404
72585
  }
72405
- const useProvider = parentProvider;
72586
+ const useProvider = getParentProvider();
72587
+ const useModel = getParentModel();
72406
72588
  const cliArgs = [
72407
72589
  "--json",
72408
72590
  "--provider",
72409
72591
  useProvider,
72410
72592
  "--model",
72411
- parentModel,
72593
+ useModel,
72412
72594
  "--max-turns",
72413
72595
  String(SUB_AGENT_MAX_TURNS)
72414
72596
  ];
@@ -72420,8 +72602,7 @@ ${agentList}` : "\n\nNo named agents configured.";
72420
72602
  cliArgs.push("--system-prompt", agentDef.systemPrompt);
72421
72603
  }
72422
72604
  cliArgs.push(args.task);
72423
- const binPath = process.argv[1];
72424
- const child = spawn5(process.execPath, [binPath, ...cliArgs], {
72605
+ const child = spawn5(process.execPath, [resolveCliEntry(), ...cliArgs], {
72425
72606
  cwd: cwd2,
72426
72607
  stdio: ["ignore", "pipe", "pipe"],
72427
72608
  env: { ...process.env }
@@ -72436,7 +72617,7 @@ ${agentList}` : "\n\nNo named agents configured.";
72436
72617
  log("INFO", "subagent", "Sub-agent spawn", {
72437
72618
  cacheKey: subCacheKey,
72438
72619
  provider: useProvider,
72439
- model: parentModel,
72620
+ model: useModel,
72440
72621
  agent: agentDef?.name ?? "(default)"
72441
72622
  });
72442
72623
  let childExited = false;
@@ -73815,8 +73996,8 @@ function createWebSearchTool() {
73815
73996
  // ../cli/dist/tools/source-path.js
73816
73997
  init_esm_shims();
73817
73998
  import { spawn as spawn6 } from "child_process";
73818
- import path18 from "path";
73819
- import { fileURLToPath as fileURLToPath2 } from "url";
73999
+ import path19 from "path";
74000
+ import { fileURLToPath as fileURLToPath3 } from "url";
73820
74001
  var SOURCE_PATH_TIMEOUT_MS = 12e4;
73821
74002
  var MAX_STDERR_CHARS = 1e4;
73822
74003
  var OPENSRC_BIN_ENV = "EZ_CODER_OPENSRC_BIN";
@@ -73916,8 +74097,8 @@ function getBundledOpenSrcBinPath() {
73916
74097
  const override = process.env[OPENSRC_BIN_ENV]?.trim() ?? process.env[LEGACY_OPENSRC_BIN_ENV]?.trim();
73917
74098
  if (override)
73918
74099
  return override;
73919
- const currentDir = path18.dirname(fileURLToPath2(import.meta.url));
73920
- return path18.resolve(currentDir, "../../node_modules/opensrc/bin/opensrc.js");
74100
+ const currentDir = path19.dirname(fileURLToPath3(import.meta.url));
74101
+ return path19.resolve(currentDir, "../../node_modules/opensrc/bin/opensrc.js");
73921
74102
  }
73922
74103
  function getOpenSrcEnv() {
73923
74104
  return {
@@ -74001,7 +74182,7 @@ import { randomUUID as randomUUID2 } from "crypto";
74001
74182
  init_esm_shims();
74002
74183
  import { createHash } from "crypto";
74003
74184
  import { mkdir, readFile, writeFile } from "fs/promises";
74004
- import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
74185
+ import { existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
74005
74186
  import { homedir } from "os";
74006
74187
  import { basename, join } from "path";
74007
74188
  var DEFAULT_TASKS_BASE = join(homedir(), ".ezcoder", "tasks", "projects");
@@ -74068,7 +74249,7 @@ async function migrateLegacyTasksIfNeeded(cwd2) {
74068
74249
  if (!legacyBase)
74069
74250
  return null;
74070
74251
  const targetFile = tasksFilePath(cwd2);
74071
- if (existsSync2(targetFile))
74252
+ if (existsSync4(targetFile))
74072
74253
  return null;
74073
74254
  const legacyTasks = await readTasksFromBase(cwd2, legacyBase);
74074
74255
  if (!legacyTasks)
@@ -74208,7 +74389,7 @@ ${list}`;
74208
74389
 
74209
74390
  // ../cli/dist/tools/screenshot.js
74210
74391
  init_esm_shims();
74211
- import path19 from "path";
74392
+ import path20 from "path";
74212
74393
  import { mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
74213
74394
  var INSTALL_HINT = "Browser engine not installed. Add the optional dependency and download Chromium:\n pnpm add -w playwright && npx playwright install chromium\nThen retry the screenshot.";
74214
74395
  var ActionInput = external_exports.object({
@@ -74246,7 +74427,7 @@ function isBrowserBinaryMissing(err) {
74246
74427
  }
74247
74428
  function defaultOutPath(cwd2) {
74248
74429
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
74249
- return path19.join(cwd2, ".ezcoder", "screenshots", `${stamp}.png`);
74430
+ return path20.join(cwd2, ".ezcoder", "screenshots", `${stamp}.png`);
74250
74431
  }
74251
74432
  async function runActions(page, actions) {
74252
74433
  for (const action of actions ?? []) {
@@ -74297,7 +74478,7 @@ function createScreenshotTool(cwd2) {
74297
74478
  await runActions(page, args.actions);
74298
74479
  const raw = await page.screenshot({ fullPage: args.full_page ?? false });
74299
74480
  context.signal.removeEventListener("abort", onAbort);
74300
- await mkdir2(path19.dirname(outPath), { recursive: true });
74481
+ await mkdir2(path20.dirname(outPath), { recursive: true });
74301
74482
  await writeFile2(outPath, raw);
74302
74483
  const { buffer, mediaType } = await shrinkToFit(raw, "image/png");
74303
74484
  const previewBuffer = await downscaleForPreview(buffer);
@@ -74329,6 +74510,215 @@ function createScreenshotTool(cwd2) {
74329
74510
  };
74330
74511
  }
74331
74512
 
74513
+ // ../cli/dist/tools/generate-image.js
74514
+ init_esm_shims();
74515
+ import path21 from "path";
74516
+ import { mkdir as mkdir3, writeFile as writeFile3, readFile as readFile2 } from "fs/promises";
74517
+ var CODEX_ENDPOINT = "https://chatgpt.com/backend-api/codex/responses";
74518
+ var IMAGE_GEN_MODEL = "gpt-5.5";
74519
+ var GenerateImageParams = external_exports.object({
74520
+ prompt: external_exports.string().describe("Text description of the image to generate or the edit to apply"),
74521
+ image: external_exports.string().optional().describe("Path to an existing image file to edit (use the path returned by a previous generate_image call, or a user-attached image path). When omitted, a new image is generated from scratch."),
74522
+ size: external_exports.string().optional().describe("Output resolution. gpt-image-2 accepts any size where both edges are multiples of 16px, max edge \u22643840px, long:short ratio \u22643:1, total pixels 655,360\u20138,294,400. Popular: 1024x1024, 1536x1024, 1024x1536, 2048x2048. Default: auto."),
74523
+ quality: external_exports.enum(["low", "medium", "high", "auto"]).optional().describe("Rendering quality. Use 'low' for fast drafts, 'high' for final assets. Default: auto."),
74524
+ n: external_exports.number().int().min(1).max(4).optional().describe("Number of images to generate (1\u20134, default 1)"),
74525
+ out_path: external_exports.string().optional().describe("Where to save the generated image (relative to cwd or absolute). Defaults to .gg/generated/<timestamp>.png"),
74526
+ output_format: external_exports.enum(["png", "jpeg", "webp"]).optional().describe("Output file format (default png)"),
74527
+ background: external_exports.enum(["opaque", "auto"]).optional().describe("Background type (default auto; gpt-image-2 does not support transparent)")
74528
+ });
74529
+ function defaultOutPath2(cwd2, format) {
74530
+ const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
74531
+ const ext = format === "png" ? "png" : format === "jpeg" ? "jpg" : "webp";
74532
+ return path21.join(cwd2, ".ezcoder", "generated", `${stamp}.${ext}`);
74533
+ }
74534
+ function mediaTypeFor(format) {
74535
+ if (format === "jpeg")
74536
+ return "image/jpeg";
74537
+ if (format === "webp")
74538
+ return "image/webp";
74539
+ return "image/png";
74540
+ }
74541
+ function createGenerateImageTool(cwd2, auth2) {
74542
+ return {
74543
+ name: "generate_image",
74544
+ description: "Generate or edit images using OpenAI's gpt-image-2 model. Works even when a different chat provider is active \u2014 only requires OpenAI to be connected. Only use this tool when the user explicitly asks to create, generate, or edit an image. Pass `image` with a file path to edit an existing image (e.g. a previously generated one or a user attachment). Use `out_path` to save to a specific location (defaults to .gg/generated/).",
74545
+ parameters: GenerateImageParams,
74546
+ async execute(args, context) {
74547
+ if (context.signal.aborted)
74548
+ return "Image generation aborted before start.";
74549
+ let token;
74550
+ let accountId;
74551
+ try {
74552
+ const creds = await auth2.resolveCredentials("openai");
74553
+ token = creds.accessToken;
74554
+ accountId = creds.accountId;
74555
+ } catch {
74556
+ return "OpenAI is not connected. The user needs to connect their OpenAI account to use image generation.";
74557
+ }
74558
+ const outputFormat = args.output_format ?? "png";
74559
+ const mediaType = mediaTypeFor(outputFormat);
74560
+ const outPath = args.out_path ? resolvePath(cwd2, args.out_path) : defaultOutPath2(cwd2, outputFormat);
74561
+ try {
74562
+ const imageTool = {
74563
+ type: "image_generation",
74564
+ output_format: outputFormat
74565
+ };
74566
+ if (args.size)
74567
+ imageTool.size = args.size;
74568
+ if (args.quality)
74569
+ imageTool.quality = args.quality;
74570
+ if (args.n)
74571
+ imageTool.n = args.n;
74572
+ if (args.background)
74573
+ imageTool.background = args.background;
74574
+ const inputContent = [
74575
+ { type: "input_text", text: args.prompt }
74576
+ ];
74577
+ if (args.image) {
74578
+ const imagePath = resolvePath(cwd2, args.image);
74579
+ let fileBuffer;
74580
+ try {
74581
+ fileBuffer = await readFile2(imagePath);
74582
+ } catch {
74583
+ return `Could not read the image at ${args.image}. Check the path is correct.`;
74584
+ }
74585
+ const refMediaType = imagePath.toLowerCase().endsWith(".jpg") || imagePath.toLowerCase().endsWith(".jpeg") ? "image/jpeg" : imagePath.toLowerCase().endsWith(".webp") ? "image/webp" : "image/png";
74586
+ inputContent.push({
74587
+ type: "input_image",
74588
+ image_url: `data:${refMediaType};base64,${fileBuffer.toString("base64")}`
74589
+ });
74590
+ imageTool.action = "edit";
74591
+ } else {
74592
+ imageTool.action = "generate";
74593
+ }
74594
+ const imageBuffers = await callImageGeneration(inputContent, imageTool, token, accountId, context.signal);
74595
+ if (imageBuffers.length === 0) {
74596
+ return "Image generation returned no results. The prompt may have been blocked by content moderation.";
74597
+ }
74598
+ const savedPaths = [];
74599
+ for (let i = 0; i < imageBuffers.length; i++) {
74600
+ const buf = imageBuffers[i];
74601
+ const savePath = imageBuffers.length === 1 ? outPath : insertIndex(outPath, i);
74602
+ await mkdir3(path21.dirname(savePath), { recursive: true });
74603
+ await writeFile3(savePath, buf);
74604
+ savedPaths.push(savePath);
74605
+ }
74606
+ const primary = imageBuffers[0];
74607
+ const primaryPath = savedPaths[0];
74608
+ const { buffer: shrunk, mediaType: detectedType } = await shrinkToFit(primary, mediaType);
74609
+ const previewBuffer = await downscaleForPreview(shrunk);
74610
+ const imagePreviews = [
74611
+ {
74612
+ base64: previewBuffer.toString("base64"),
74613
+ mediaType: detectedType,
74614
+ path: primaryPath
74615
+ }
74616
+ ];
74617
+ for (let i = 1; i < imageBuffers.length; i++) {
74618
+ const extraBuf = imageBuffers[i];
74619
+ const extraPath = savedPaths[i];
74620
+ const extraShrunk = await shrinkToFit(extraBuf, mediaType);
74621
+ const extraPreview = await downscaleForPreview(extraShrunk.buffer);
74622
+ imagePreviews.push({
74623
+ base64: extraPreview.toString("base64"),
74624
+ mediaType: extraShrunk.mediaType,
74625
+ path: extraPath
74626
+ });
74627
+ }
74628
+ const summary = savedPaths.length === 1 ? `Generated image \u2192 ${primaryPath}` : `Generated ${savedPaths.length} images \u2192 ${savedPaths.join(", ")}`;
74629
+ const allContent = [
74630
+ { type: "text", text: summary },
74631
+ {
74632
+ type: "image",
74633
+ mediaType: detectedType,
74634
+ data: shrunk.toString("base64")
74635
+ }
74636
+ ];
74637
+ return {
74638
+ content: allContent,
74639
+ details: { imagePreviews }
74640
+ };
74641
+ } catch (err) {
74642
+ if (context.signal.aborted)
74643
+ return "Image generation aborted.";
74644
+ const reason = err instanceof Error ? err.message : String(err);
74645
+ return `Image generation failed: ${reason}`;
74646
+ }
74647
+ }
74648
+ };
74649
+ }
74650
+ function insertIndex(filePath, index) {
74651
+ const ext = path21.extname(filePath);
74652
+ const base = filePath.slice(0, filePath.length - ext.length);
74653
+ return `${base}_${index}${ext}`;
74654
+ }
74655
+ async function callImageGeneration(inputContent, imageTool, token, accountId, signal) {
74656
+ const body = {
74657
+ model: IMAGE_GEN_MODEL,
74658
+ store: false,
74659
+ stream: true,
74660
+ instructions: "Generate the image the user requested.",
74661
+ input: [{ role: "user", content: inputContent }],
74662
+ tools: [imageTool],
74663
+ tool_choice: "auto",
74664
+ reasoning: { effort: "low" }
74665
+ };
74666
+ const response = await fetch(CODEX_ENDPOINT, {
74667
+ method: "POST",
74668
+ headers: {
74669
+ "Content-Type": "application/json",
74670
+ Authorization: `Bearer ${token}`,
74671
+ ...accountId ? { "chatgpt-account-id": accountId } : {},
74672
+ originator: "ezcoder"
74673
+ },
74674
+ body: JSON.stringify(body),
74675
+ signal
74676
+ });
74677
+ if (!response.ok) {
74678
+ const text = await response.text();
74679
+ let detail = text;
74680
+ try {
74681
+ const parsed = JSON.parse(text);
74682
+ if (parsed.detail)
74683
+ detail = parsed.detail;
74684
+ else if (parsed.error?.message)
74685
+ detail = parsed.error.message;
74686
+ } catch {
74687
+ }
74688
+ throw new Error(`OpenAI Image API (${response.status}): ${detail}`);
74689
+ }
74690
+ if (!response.body) {
74691
+ throw new Error("OpenAI Image API returned no response body.");
74692
+ }
74693
+ const reader = response.body.getReader();
74694
+ const decoder = new TextDecoder();
74695
+ let buffer = "";
74696
+ const imageBuffers = [];
74697
+ while (true) {
74698
+ const { done, value } = await reader.read();
74699
+ if (done)
74700
+ break;
74701
+ buffer += decoder.decode(value, { stream: true });
74702
+ const lines = buffer.split("\n");
74703
+ buffer = lines.pop() ?? "";
74704
+ for (const line of lines) {
74705
+ if (!line.startsWith("data: "))
74706
+ continue;
74707
+ const data = line.slice(6);
74708
+ if (data === "[DONE]")
74709
+ continue;
74710
+ try {
74711
+ const evt = JSON.parse(data);
74712
+ if (evt.type === "response.output_item.done" && evt.item?.type === "image_generation_call" && evt.item.result) {
74713
+ imageBuffers.push(Buffer.from(evt.item.result, "base64"));
74714
+ }
74715
+ } catch {
74716
+ }
74717
+ }
74718
+ }
74719
+ return imageBuffers;
74720
+ }
74721
+
74332
74722
  // ../cli/dist/tools/enter-plan.js
74333
74723
  init_esm_shims();
74334
74724
  var EnterPlanParams = external_exports.object({
@@ -74353,7 +74743,7 @@ function createEnterPlanTool(onEnterPlan) {
74353
74743
  // ../cli/dist/tools/exit-plan.js
74354
74744
  init_esm_shims();
74355
74745
  import fs15 from "fs/promises";
74356
- import path20 from "path";
74746
+ import path23 from "path";
74357
74747
  var ExitPlanParams = external_exports.object({
74358
74748
  plan_path: external_exports.string().describe("Path to the plan markdown file; must be under .ezcoder/plans/")
74359
74749
  });
@@ -74365,9 +74755,9 @@ function createExitPlanTool(cwd2, onExitPlan) {
74365
74755
  executionMode: "sequential",
74366
74756
  async execute({ plan_path }) {
74367
74757
  const resolved = resolvePath(cwd2, plan_path);
74368
- const plansDir = path20.join(cwd2, ".ezcoder", "plans");
74369
- const relative = path20.relative(plansDir, resolved);
74370
- if (relative.startsWith("..") || path20.isAbsolute(relative)) {
74758
+ const plansDir = path23.join(cwd2, ".ezcoder", "plans");
74759
+ const relative = path23.relative(plansDir, resolved);
74760
+ if (relative.startsWith("..") || path23.isAbsolute(relative)) {
74371
74761
  return `Error: plan_path must be under .ezcoder/plans/. Got: ${plan_path}`;
74372
74762
  }
74373
74763
  try {
@@ -74393,7 +74783,7 @@ init_esm_shims();
74393
74783
  // ../cli/dist/core/goal-store.js
74394
74784
  init_esm_shims();
74395
74785
  import { createHash as createHash2, randomUUID as randomUUID3 } from "crypto";
74396
- import { mkdir as mkdir3, open, readdir, readFile as readFile2, rename, rm, writeFile as writeFile3 } from "fs/promises";
74786
+ import { mkdir as mkdir4, open, readdir, readFile as readFile3, rename, rm, writeFile as writeFile4 } from "fs/promises";
74397
74787
  import { homedir as homedir2 } from "os";
74398
74788
  import { basename as basename2, join as join2, resolve } from "path";
74399
74789
  var GOALS_BASE_ENV = "GG_GOALS_BASE";
@@ -74644,7 +75034,7 @@ async function writeGoalRunsFile(cwd2, runs) {
74644
75034
  const normalizedCwd = normalizeProjectPath(cwd2);
74645
75035
  const dir = projectDir(normalizedCwd);
74646
75036
  await withGoalStoreLock(dir, async () => {
74647
- await mkdir3(dir, { recursive: true });
75037
+ await mkdir4(dir, { recursive: true });
74648
75038
  const goalsPath = join2(dir, "goals.json");
74649
75039
  const existingRuns = await readGoalRunsFile(normalizedCwd);
74650
75040
  const omittedActive = omittedActiveGoalRuns(existingRuns, runs);
@@ -74678,7 +75068,7 @@ async function writeGoalRunsFile(cwd2, runs) {
74678
75068
  });
74679
75069
  }
74680
75070
  async function withGoalStoreLock(dir, fn) {
74681
- await mkdir3(dir, { recursive: true });
75071
+ await mkdir4(dir, { recursive: true });
74682
75072
  const lockPath = join2(dir, "goals.lock");
74683
75073
  const deadline = Date.now() + 1e4;
74684
75074
  for (; ; ) {
@@ -74702,15 +75092,15 @@ ${(/* @__PURE__ */ new Date()).toISOString()}
74702
75092
  }
74703
75093
  }
74704
75094
  }
74705
- async function atomicWriteJson(path46, value) {
74706
- const tmpPath = `${path46}.${process.pid}.${Date.now()}.tmp`;
74707
- await writeFile3(tmpPath, JSON.stringify(value, null, 2) + "\n", "utf-8");
74708
- await rename(tmpPath, path46);
75095
+ async function atomicWriteJson(path49, value) {
75096
+ const tmpPath = `${path49}.${process.pid}.${Date.now()}.tmp`;
75097
+ await writeFile4(tmpPath, JSON.stringify(value, null, 2) + "\n", "utf-8");
75098
+ await rename(tmpPath, path49);
74709
75099
  }
74710
75100
  async function readGoalRunsFile(cwd2) {
74711
75101
  const normalizedCwd = normalizeProjectPath(cwd2);
74712
75102
  try {
74713
- const data = await readFile2(join2(projectDir(normalizedCwd), "goals.json"), "utf-8");
75103
+ const data = await readFile3(join2(projectDir(normalizedCwd), "goals.json"), "utf-8");
74714
75104
  const parsed = JSON.parse(data);
74715
75105
  if (!Array.isArray(parsed))
74716
75106
  return [];
@@ -74736,7 +75126,7 @@ async function discoverGoalRunsById(id2) {
74736
75126
  const dir = join2(goalsBaseDir(), entry.name);
74737
75127
  const meta3 = await readProjectMeta(dir);
74738
75128
  const fallbackProjectPath = meta3?.path ?? dir;
74739
- const data = await readFile2(join2(dir, "goals.json"), "utf-8");
75129
+ const data = await readFile3(join2(dir, "goals.json"), "utf-8");
74740
75130
  const parsed = JSON.parse(data);
74741
75131
  if (!Array.isArray(parsed))
74742
75132
  continue;
@@ -74756,7 +75146,7 @@ async function discoverGoalRunsById(id2) {
74756
75146
  }
74757
75147
  async function readProjectMeta(dir) {
74758
75148
  try {
74759
- const parsed = JSON.parse(await readFile2(join2(dir, "meta.json"), "utf-8"));
75149
+ const parsed = JSON.parse(await readFile3(join2(dir, "meta.json"), "utf-8"));
74760
75150
  return isObject2(parsed) && typeof parsed.path === "string" ? { path: parsed.path } : null;
74761
75151
  } catch {
74762
75152
  return null;
@@ -74966,8 +75356,8 @@ function formatGoalBlockingPrerequisites(run) {
74966
75356
  }
74967
75357
  async function writeGoalProgressJournalFromRun(cwd2, run) {
74968
75358
  const dir = join2(projectDir(cwd2), "journals");
74969
- await mkdir3(dir, { recursive: true });
74970
- const path46 = join2(dir, `${run.id}.md`);
75359
+ await mkdir4(dir, { recursive: true });
75360
+ const path49 = join2(dir, `${run.id}.md`);
74971
75361
  const lines = [
74972
75362
  `# ${run.title}`,
74973
75363
  "",
@@ -74996,8 +75386,8 @@ async function writeGoalProgressJournalFromRun(cwd2, run) {
74996
75386
  ...run.evidence.slice(-10).map((item) => `- ${item.createdAt} [${item.kind}] ${item.label}${item.path ? ` (${item.path})` : ""}${item.content ? ` \u2014 ${item.content}` : ""}`),
74997
75387
  ""
74998
75388
  ];
74999
- await writeFile3(path46, lines.join("\n"), "utf-8");
75000
- return path46;
75389
+ await writeFile4(path49, lines.join("\n"), "utf-8");
75390
+ return path49;
75001
75391
  }
75002
75392
 
75003
75393
  // ../cli/dist/core/goal-controller.js
@@ -76135,7 +76525,7 @@ function createGoalsTool(cwd2, goalModeRef) {
76135
76525
  }
76136
76526
 
76137
76527
  // ../cli/dist/tools/index.js
76138
- function createTools(cwd2, opts) {
76528
+ async function createTools(cwd2, opts) {
76139
76529
  const readFiles = /* @__PURE__ */ new Map();
76140
76530
  const processManager = new ProcessManager();
76141
76531
  const ops = opts?.operations ?? localOperations;
@@ -76166,7 +76556,7 @@ function createTools(cwd2, opts) {
76166
76556
  tools.push(createWebSearchTool());
76167
76557
  }
76168
76558
  if (opts?.agents && opts.agents.length > 0 && opts.provider && opts.model) {
76169
- tools.push(createSubAgentTool(cwd2, opts.agents, opts.provider, opts.model, opts.getCacheKey, planModeRef, goalModeRef));
76559
+ tools.push(createSubAgentTool(cwd2, opts.agents, () => opts.getProvider?.() ?? opts.provider, () => opts.getModel?.() ?? opts.model, opts.getCacheKey, planModeRef, goalModeRef));
76170
76560
  }
76171
76561
  if (opts?.skills && opts.skills.length > 0) {
76172
76562
  tools.push(createSkillTool(opts.skills));
@@ -76177,6 +76567,14 @@ function createTools(cwd2, opts) {
76177
76567
  if (opts?.onExitPlan) {
76178
76568
  tools.push(createExitPlanTool(cwd2, opts.onExitPlan));
76179
76569
  }
76570
+ if (opts?.authStorage) {
76571
+ try {
76572
+ if (await opts.authStorage.hasProviderAuth("openai")) {
76573
+ tools.push(createGenerateImageTool(cwd2, opts.authStorage));
76574
+ }
76575
+ } catch {
76576
+ }
76577
+ }
76180
76578
  const rebuildReadTool = (model) => createReadTool(cwd2, readFiles, ops, opts?.onFileRead, getVideoByteLimit(model));
76181
76579
  return { tools, processManager, rebuildReadTool, lspManager };
76182
76580
  }
@@ -76184,18 +76582,18 @@ function createTools(cwd2, opts) {
76184
76582
  // ../cli/dist/system-prompt.js
76185
76583
  init_esm_shims();
76186
76584
  import fs20 from "fs/promises";
76187
- import path26 from "path";
76585
+ import path28 from "path";
76188
76586
 
76189
76587
  // ../cli/dist/core/skills.js
76190
76588
  init_esm_shims();
76191
76589
  import fs16 from "fs/promises";
76192
- import path21 from "path";
76590
+ import path24 from "path";
76193
76591
  async function discoverSkills(options) {
76194
76592
  const skills = [];
76195
76593
  const globalSkills = await loadSkillsFromDir(options.globalSkillsDir, "global");
76196
76594
  skills.push(...globalSkills);
76197
76595
  if (options.projectDir) {
76198
- const projectSkillsDir = path21.join(options.projectDir, ".ezcoder", "skills");
76596
+ const projectSkillsDir = path24.join(options.projectDir, ".ezcoder", "skills");
76199
76597
  const projectSkills = await loadSkillsFromDir(projectSkillsDir, "project");
76200
76598
  skills.push(...projectSkills);
76201
76599
  }
@@ -76210,20 +76608,20 @@ async function loadSkillsFromDir(dir, source2) {
76210
76608
  return skills;
76211
76609
  }
76212
76610
  for (const entry of dirents) {
76213
- const entryPath = path21.join(dir, entry.name);
76611
+ const entryPath = path24.join(dir, entry.name);
76214
76612
  if (entry.isFile() && entry.name.endsWith(".md")) {
76215
76613
  try {
76216
76614
  const content = await fs16.readFile(entryPath, "utf-8");
76217
76615
  const skill = parseSkillFile(content, source2);
76218
76616
  if (!skill.name)
76219
- skill.name = path21.basename(entry.name, ".md");
76617
+ skill.name = path24.basename(entry.name, ".md");
76220
76618
  skills.push(skill);
76221
76619
  } catch {
76222
76620
  }
76223
76621
  continue;
76224
76622
  }
76225
76623
  if (entry.isDirectory()) {
76226
- const skillFile = path21.join(entryPath, "SKILL.md");
76624
+ const skillFile = path24.join(entryPath, "SKILL.md");
76227
76625
  try {
76228
76626
  const content = await fs16.readFile(skillFile, "utf-8");
76229
76627
  const skill = parseSkillFile(content, source2);
@@ -76284,6 +76682,7 @@ var TOOL_PROMPT_HINTS = {
76284
76682
  exit_plan: "Submit a .ezcoder/plans/ markdown plan for user approval and leave plan mode.",
76285
76683
  subagent: "Delegate focused, isolated subtasks (research, parallel exploration).",
76286
76684
  skill: "Invoke a named skill for specialized instructions.",
76685
+ generate_image: "Generate or edit images using OpenAI's gpt-image-2 model. Only use when the user explicitly asks to create or edit an image \u2014 never generate images proactively. Requires OpenAI to be connected. Pass `image` with a file path to edit an existing image. Save with `out_path`.",
76287
76686
  "mcp__kencode-search__referenceSources": "Get curated, categorized reference repos for examples, inspiration, architecture, UI, agents, SaaS, workflows, and domain patterns. Repo-only starting points; fetch docs/source, then verify code with searchCode.",
76288
76687
  "mcp__kencode-search__discoverRepos": "Search GitHub repos live by keyword/language/topic/stars/recency. Use for current/top repos or long-tail discovery; returns metadata, not snippets. Follow with docs/source and searchCode.",
76289
76688
  "mcp__kencode-search__searchCode": "Verify public GitHub code by literal text or RE2 regex; NOT semantic. Put code/import/API tokens in `query`; `path` is a literal file-path substring, not a concept. Start broad/peek, then narrow by repo/path. RE2 multi-line needs `(?s)`."
@@ -76318,6 +76717,7 @@ var DEFAULT_TOOL_NAMES = [
76318
76717
  "exit_plan",
76319
76718
  "subagent",
76320
76719
  "skill",
76720
+ "generate_image",
76321
76721
  "mcp__kencode-search__referenceSources",
76322
76722
  "mcp__kencode-search__discoverRepos",
76323
76723
  "mcp__kencode-search__searchCode"
@@ -76326,12 +76726,12 @@ var DEFAULT_TOOL_NAMES = [
76326
76726
  // ../cli/dist/core/style-packs/index.js
76327
76727
  init_esm_shims();
76328
76728
  import fs18 from "fs";
76329
- import path24 from "path";
76729
+ import path26 from "path";
76330
76730
 
76331
76731
  // ../cli/dist/core/language-detector.js
76332
76732
  init_esm_shims();
76333
76733
  import fs17 from "fs";
76334
- import path23 from "path";
76734
+ import path25 from "path";
76335
76735
  var MARKERS = {
76336
76736
  typescript: { manifests: ["tsconfig.json"], extensions: [".ts", ".tsx", ".mts", ".cts"] },
76337
76737
  // JS is only flagged when there's a package.json AND no tsconfig — pure JS projects.
@@ -76619,7 +77019,7 @@ var PACKS = {
76619
77019
 
76620
77020
  // ../cli/dist/core/style-packs/index.js
76621
77021
  function loadPack(id2, cwd2) {
76622
- const overridePath = path24.join(cwd2, ".ezcoder", "styles", `${id2}.md`);
77022
+ const overridePath = path26.join(cwd2, ".ezcoder", "styles", `${id2}.md`);
76623
77023
  try {
76624
77024
  const stat = fs18.statSync(overridePath);
76625
77025
  if (stat.isFile()) {
@@ -76663,7 +77063,7 @@ Universal rules for agent-written code:
76663
77063
  // ../cli/dist/core/verify-commands.js
76664
77064
  init_esm_shims();
76665
77065
  import fs19 from "fs";
76666
- import path25 from "path";
77066
+ import path27 from "path";
76667
77067
  function detectVerifyCommands(cwd2, active) {
76668
77068
  const cmds = [];
76669
77069
  if (active.has("typescript") || active.has("javascript")) {
@@ -76690,12 +77090,12 @@ function detectVerifyCommands(cwd2, active) {
76690
77090
  const testScript = pick2("test", "test:unit");
76691
77091
  if (testScript)
76692
77092
  cmds.push({ label: "test", command: `${runner} ${testScript}`, language: lang });
76693
- } else if (active.has("typescript") && fileExists2(path25.join(cwd2, "tsconfig.json"))) {
77093
+ } else if (active.has("typescript") && fileExists2(path27.join(cwd2, "tsconfig.json"))) {
76694
77094
  cmds.push({ label: "typecheck", command: "tsc --noEmit", language: "typescript" });
76695
77095
  }
76696
77096
  }
76697
77097
  if (active.has("python")) {
76698
- const pyproject = readFileSafe(path25.join(cwd2, "pyproject.toml"));
77098
+ const pyproject = readFileSafe(path27.join(cwd2, "pyproject.toml"));
76699
77099
  if (pyproject) {
76700
77100
  if (/\[tool\.ruff/.test(pyproject)) {
76701
77101
  cmds.push({ label: "lint", command: "ruff check .", language: "python" });
@@ -76727,10 +77127,10 @@ function detectVerifyCommands(cwd2, active) {
76727
77127
  }
76728
77128
  if (active.has("java") || active.has("kotlin")) {
76729
77129
  const lang = active.has("kotlin") ? "kotlin" : "java";
76730
- if (fileExists2(path25.join(cwd2, "gradlew"))) {
77130
+ if (fileExists2(path27.join(cwd2, "gradlew"))) {
76731
77131
  cmds.push({ label: "build", command: "./gradlew build", language: lang });
76732
77132
  cmds.push({ label: "test", command: "./gradlew test", language: lang });
76733
- } else if (fileExists2(path25.join(cwd2, "pom.xml"))) {
77133
+ } else if (fileExists2(path27.join(cwd2, "pom.xml"))) {
76734
77134
  cmds.push({ label: "verify", command: "mvn verify", language: lang });
76735
77135
  }
76736
77136
  }
@@ -76744,7 +77144,7 @@ function detectVerifyCommands(cwd2, active) {
76744
77144
  cmds.push({ label: "test", command: "dotnet test", language: "csharp" });
76745
77145
  }
76746
77146
  if (active.has("ruby")) {
76747
- if (fileExists2(path25.join(cwd2, "Gemfile"))) {
77147
+ if (fileExists2(path27.join(cwd2, "Gemfile"))) {
76748
77148
  cmds.push({ label: "lint", command: "bundle exec rubocop", language: "ruby" });
76749
77149
  cmds.push({ label: "test", command: "bundle exec rspec", language: "ruby" });
76750
77150
  }
@@ -76754,7 +77154,7 @@ function detectVerifyCommands(cwd2, active) {
76754
77154
  cmds.push({ label: "test", command: "mix test", language: "elixir" });
76755
77155
  }
76756
77156
  if (active.has("php")) {
76757
- if (fileExists2(path25.join(cwd2, "composer.json"))) {
77157
+ if (fileExists2(path27.join(cwd2, "composer.json"))) {
76758
77158
  cmds.push({ label: "test", command: "composer test", language: "php" });
76759
77159
  }
76760
77160
  }
@@ -76786,7 +77186,7 @@ function readFileSafe(p) {
76786
77186
  }
76787
77187
  }
76788
77188
  function readPackageJsonScripts(cwd2) {
76789
- const raw = readFileSafe(path25.join(cwd2, "package.json"));
77189
+ const raw = readFileSafe(path27.join(cwd2, "package.json"));
76790
77190
  if (!raw)
76791
77191
  return null;
76792
77192
  try {
@@ -76797,11 +77197,11 @@ function readPackageJsonScripts(cwd2) {
76797
77197
  }
76798
77198
  }
76799
77199
  function detectNodeRunner(cwd2) {
76800
- if (fileExists2(path25.join(cwd2, "pnpm-lock.yaml")))
77200
+ if (fileExists2(path27.join(cwd2, "pnpm-lock.yaml")))
76801
77201
  return "pnpm";
76802
- if (fileExists2(path25.join(cwd2, "yarn.lock")))
77202
+ if (fileExists2(path27.join(cwd2, "yarn.lock")))
76803
77203
  return "yarn";
76804
- if (fileExists2(path25.join(cwd2, "bun.lockb")))
77204
+ if (fileExists2(path27.join(cwd2, "bun.lockb")))
76805
77205
  return "bun";
76806
77206
  return "npm run";
76807
77207
  }
@@ -77009,17 +77409,17 @@ async function collectProjectContext(cwd2) {
77009
77409
  while (!visited.has(dir)) {
77010
77410
  visited.add(dir);
77011
77411
  for (const name of CONTEXT_FILES) {
77012
- const filePath = path26.join(dir, name);
77412
+ const filePath = path28.join(dir, name);
77013
77413
  try {
77014
77414
  const content = await fs20.readFile(filePath, "utf-8");
77015
- const relPath = path26.relative(cwd2, filePath) || name;
77415
+ const relPath = path28.relative(cwd2, filePath) || name;
77016
77416
  contextParts.push(`### ${relPath}
77017
77417
 
77018
77418
  ${content.trim()}`);
77019
77419
  } catch {
77020
77420
  }
77021
77421
  }
77022
- const parent = path26.dirname(dir);
77422
+ const parent = path28.dirname(dir);
77023
77423
  if (parent === dir)
77024
77424
  break;
77025
77425
  dir = parent;
@@ -77093,10 +77493,10 @@ async function buildSystemPrompt(cwd2, skills, planMode, approvedPlanPath, toolN
77093
77493
  // ../cli/dist/session.js
77094
77494
  init_esm_shims();
77095
77495
  import fs21 from "fs/promises";
77096
- import path27 from "path";
77496
+ import path29 from "path";
77097
77497
  import os7 from "os";
77098
77498
  import crypto4 from "crypto";
77099
- var SESSION_DIR = path27.join(os7.homedir(), ".ezcoder", "sessions");
77499
+ var SESSION_DIR = path29.join(os7.homedir(), ".ezcoder", "sessions");
77100
77500
 
77101
77501
  // ../cli/dist/core/index.js
77102
77502
  init_esm_shims();
@@ -77164,7 +77564,8 @@ var EventBus = class {
77164
77564
  toolCallId: event.toolCallId,
77165
77565
  result: event.result,
77166
77566
  isError: event.isError,
77167
- durationMs: event.durationMs
77567
+ durationMs: event.durationMs,
77568
+ details: event.details
77168
77569
  });
77169
77570
  break;
77170
77571
  case "turn_end":
@@ -77213,7 +77614,7 @@ import fs23 from "fs/promises";
77213
77614
 
77214
77615
  // ../cli/dist/config.js
77215
77616
  init_esm_shims();
77216
- import path28 from "path";
77617
+ import path30 from "path";
77217
77618
  import fs22 from "fs/promises";
77218
77619
  import fsSync from "fs";
77219
77620
  async function ensureAppDirs() {
@@ -77279,7 +77680,7 @@ Rules:
77279
77680
  `
77280
77681
  };
77281
77682
  for (const [filename, content] of Object.entries(defaults2)) {
77282
- const filePath = path28.join(agentsDir, filename);
77683
+ const filePath = path30.join(agentsDir, filename);
77283
77684
  try {
77284
77685
  await fs22.access(filePath);
77285
77686
  } catch {
@@ -77292,7 +77693,7 @@ async function seedDefaultSkills(skillsDir) {
77292
77693
  "find-skills.md": FIND_SKILLS_MD
77293
77694
  };
77294
77695
  for (const [filename, content] of Object.entries(defaults2)) {
77295
- const filePath = path28.join(skillsDir, filename);
77696
+ const filePath = path30.join(skillsDir, filename);
77296
77697
  try {
77297
77698
  await fs22.access(filePath);
77298
77699
  } catch {
@@ -77420,7 +77821,11 @@ var SettingsSchema = external_exports.object({
77420
77821
  lspDiagnostics: external_exports.boolean().default(true),
77421
77822
  enabledTools: external_exports.array(external_exports.string()).optional(),
77422
77823
  /** Delete session transcripts older than this many days at startup. 0 disables pruning. */
77423
- sessionRetentionDays: external_exports.number().int().min(0).default(30)
77824
+ sessionRetentionDays: external_exports.number().int().min(0).default(30),
77825
+ /** Speed optimization profile.
77826
+ * - "baseline": 5-min cache TTL, no pre-warm
77827
+ * - "optimized": 1-h cache TTL, cache pre-warming on first prompt (default) */
77828
+ speedProfile: external_exports.enum(["baseline", "optimized"]).default("optimized")
77424
77829
  });
77425
77830
  var DEFAULT_SETTINGS = {
77426
77831
  autoCompact: true,
@@ -77433,7 +77838,8 @@ var DEFAULT_SETTINGS = {
77433
77838
  idealReviewEnabled: true,
77434
77839
  autoApprovePlans: true,
77435
77840
  lspDiagnostics: true,
77436
- sessionRetentionDays: 30
77841
+ sessionRetentionDays: 30,
77842
+ speedProfile: "optimized"
77437
77843
  };
77438
77844
  var SettingsManager = class {
77439
77845
  settings = { ...DEFAULT_SETTINGS };
@@ -77474,7 +77880,7 @@ init_esm_shims();
77474
77880
  import fs24 from "fs/promises";
77475
77881
  import { createReadStream as createReadStream2 } from "fs";
77476
77882
  import { createInterface as createInterface2 } from "readline";
77477
- import path29 from "path";
77883
+ import path31 from "path";
77478
77884
  import crypto6 from "crypto";
77479
77885
  var DISPLAY_ITEM_CUSTOM_KIND = "display_item";
77480
77886
  function isCompletedItemLike(value) {
@@ -77509,7 +77915,7 @@ var SessionManager = class _SessionManager {
77509
77915
  this.onPersistError?.(err);
77510
77916
  }
77511
77917
  dirForCwd(cwd2) {
77512
- return path29.join(this.sessionsDir, encodeCwd(cwd2));
77918
+ return path31.join(this.sessionsDir, encodeCwd(cwd2));
77513
77919
  }
77514
77920
  async create(cwd2, provider, model) {
77515
77921
  const id2 = crypto6.randomUUID();
@@ -77517,7 +77923,7 @@ var SessionManager = class _SessionManager {
77517
77923
  const dir = this.dirForCwd(cwd2);
77518
77924
  await fs24.mkdir(dir, { recursive: true });
77519
77925
  const fileName = `${timestamp.replace(/[:.]/g, "-")}_${id2.slice(0, 8)}.jsonl`;
77520
- const filePath = path29.join(dir, fileName);
77926
+ const filePath = path31.join(dir, fileName);
77521
77927
  const header = {
77522
77928
  type: "session",
77523
77929
  version: 2,
@@ -77589,7 +77995,7 @@ var SessionManager = class _SessionManager {
77589
77995
  for (const file2 of files) {
77590
77996
  if (!file2.endsWith(".jsonl"))
77591
77997
  continue;
77592
- const filePath = path29.join(dir, file2);
77998
+ const filePath = path31.join(dir, file2);
77593
77999
  try {
77594
78000
  const rl = createInterface2({
77595
78001
  input: createReadStream2(filePath, { encoding: "utf-8" }),
@@ -77652,7 +78058,7 @@ var SessionManager = class _SessionManager {
77652
78058
  if (options.maxAgeDays <= 0)
77653
78059
  return result;
77654
78060
  const cutoffMs = Date.now() - options.maxAgeDays * 864e5;
77655
- const keep = new Set((options.keepPaths ?? []).map((p) => path29.resolve(p)));
78061
+ const keep = new Set((options.keepPaths ?? []).map((p) => path31.resolve(p)));
77656
78062
  let cwdDirs;
77657
78063
  try {
77658
78064
  cwdDirs = await fs24.readdir(this.sessionsDir);
@@ -77660,7 +78066,7 @@ var SessionManager = class _SessionManager {
77660
78066
  return result;
77661
78067
  }
77662
78068
  for (const dirName of cwdDirs) {
77663
- const dir = path29.join(this.sessionsDir, dirName);
78069
+ const dir = path31.join(this.sessionsDir, dirName);
77664
78070
  let files;
77665
78071
  try {
77666
78072
  const stat = await fs24.stat(dir);
@@ -77674,8 +78080,8 @@ var SessionManager = class _SessionManager {
77674
78080
  for (const file2 of files) {
77675
78081
  if (!file2.endsWith(".jsonl"))
77676
78082
  continue;
77677
- const filePath = path29.join(dir, file2);
77678
- if (keep.has(path29.resolve(filePath)))
78083
+ const filePath = path31.join(dir, file2);
78084
+ if (keep.has(path31.resolve(filePath)))
77679
78085
  continue;
77680
78086
  try {
77681
78087
  const stat = await fs24.stat(filePath);
@@ -77928,25 +78334,25 @@ function createBuiltinCommands() {
77928
78334
  async execute(args) {
77929
78335
  const { execSync } = await import("child_process");
77930
78336
  const { createRequire: createRequire2 } = await import("module");
77931
- const path46 = await import("path");
77932
- const fs38 = await import("fs");
78337
+ const path49 = await import("path");
78338
+ const fs40 = await import("fs");
77933
78339
  const _require = createRequire2(import.meta.url);
77934
- const pkgPath = path46.default.resolve(path46.default.dirname(_require.resolve("../package.json")));
78340
+ const pkgPath = path49.default.resolve(path49.default.dirname(_require.resolve("../package.json")));
77935
78341
  let repoRoot = process.cwd();
77936
- let scriptPath = path46.default.join(repoRoot, "scripts", "sync-upstream.sh");
77937
- if (!fs38.existsSync(scriptPath)) {
78342
+ let scriptPath = path49.default.join(repoRoot, "scripts", "sync-upstream.sh");
78343
+ if (!fs40.existsSync(scriptPath)) {
77938
78344
  let dir = pkgPath;
77939
78345
  for (let i = 0; i < 5; i++) {
77940
- dir = path46.default.dirname(dir);
77941
- const candidate = path46.default.join(dir, "scripts", "sync-upstream.sh");
77942
- if (fs38.existsSync(candidate)) {
78346
+ dir = path49.default.dirname(dir);
78347
+ const candidate = path49.default.join(dir, "scripts", "sync-upstream.sh");
78348
+ if (fs40.existsSync(candidate)) {
77943
78349
  scriptPath = candidate;
77944
78350
  repoRoot = dir;
77945
78351
  break;
77946
78352
  }
77947
78353
  }
77948
78354
  }
77949
- if (!fs38.existsSync(scriptPath)) {
78355
+ if (!fs40.existsSync(scriptPath)) {
77950
78356
  return "sync-upstream.sh not found. Make sure you're in the ezcoder repo root,\nor that scripts/sync-upstream.sh exists.\n\nYou can create it by checking the repo: https://github.com/Gahroot/ezcoder";
77951
78357
  }
77952
78358
  const dryRun = args.trim() === "--dry-run";
@@ -78044,6 +78450,16 @@ function createBuiltinCommands() {
78044
78450
  return "New session created.";
78045
78451
  }
78046
78452
  },
78453
+ {
78454
+ name: "clear",
78455
+ aliases: [],
78456
+ description: "Clear the conversation (start a new session)",
78457
+ usage: "/clear",
78458
+ async execute(_args, ctx) {
78459
+ await ctx.newSession();
78460
+ return "Session cleared.";
78461
+ }
78462
+ },
78047
78463
  {
78048
78464
  name: "branch",
78049
78465
  aliases: ["b"],
@@ -78289,6 +78705,97 @@ If the user chooses D, stop after the report.
78289
78705
  - **No finding without a concrete, code-grounded first-run scenario.** No "could be polished" nudges.
78290
78706
  - **Report-first.** No edits, installs, or commits until the user picks an option.
78291
78707
  - **Every generated task must end with the exact line:** use kencode to reference working code. /commit when done.`
78708
+ },
78709
+ {
78710
+ name: "test-drive",
78711
+ aliases: ["qa", "td"],
78712
+ description: "Actually run the app, click around, screenshot, file bugs as tasks",
78713
+ prompt: `# /test-drive: Empirically Test the App and File Bugs as Tasks
78714
+
78715
+ You are a hands-on QA agent. Your job is to ACTUALLY RUN this app and use it like a real user \u2014 launch it, click around, type into it, navigate every reachable surface, and LOOK at the result with your own eyes (screenshots / captured output / logs). This is empirical, not a code review: you must drive the running app, not just read source. Every bug you find is recorded so it can be fixed later by another agent working through the task list \u2014 except bugs that block YOU from testing further, which you fix immediately so you can keep going.
78716
+
78717
+ This command is **project-agnostic**. Profile what THIS app is and how it runs before testing. If the user passed arguments to /test-drive, treat them as the area/flow to focus the test pass on, but still sanity-check the rest of the app.
78718
+
78719
+ ## Phase 0: Figure out how to run it
78720
+
78721
+ Inspect the project (manifests, scripts, README, entry points) and determine how a user actually runs this app, then start it:
78722
+
78723
+ - **Web app / dev server** \u2014 find the dev/start script (e.g. \`pnpm dev\`, \`npm start\`, \`vite\`). Launch it with bash as a **background process** (\`run_in_background: true\`), wait for it to be ready, and read its output with task_output to learn the local URL (e.g. http://localhost:3000).
78724
+ - **CLI / TUI** \u2014 run the binary/entry command. For interactive programs, launch as a background process and drive it with task_send (type input / answer prompts) + task_output (read what it printed). Use task_stop to end it.
78725
+ - **Desktop app (Tauri/Electron/etc.)** \u2014 start it the way the project documents. If it exposes a local webview URL or dev server, point the screenshot tool at that; otherwise launch it and rely on captured logs/output for evidence.
78726
+ - **Library / no runnable surface** \u2014 there's nothing to "click around." Run its examples/tests/demo instead, or report that there is no interactive surface to test and stop.
78727
+
78728
+ If you cannot get the app to start at all, that is itself the first blocking bug \u2014 fix it (Phase 2, blocking path) so you have something to test, then continue.
78729
+
78730
+ ## Phase 1: Drive it and LOOK \u2014 use your eyes
78731
+
78732
+ Exercise the app like a real user, surface by surface. Use the real perception tools available to you:
78733
+
78734
+ - **screenshot tool** \u2014 your eyes for anything with a UI. Open each URL/screen, run \`actions\` (click / type / wait) to walk real flows, and CAPTURE the result so you actually see what rendered. Vary viewport for responsive surfaces and use \`full_page\` for long pages. Don't assume a screen works \u2014 look at it.
78735
+ - **task_output / task_send** \u2014 your eyes and hands for CLIs, TUIs, and dev-server logs: read what the process emitted, type input to drive it, watch for errors/stack traces/warnings in the output.
78736
+ - **bash** \u2014 hit health/API endpoints, trigger flows, and inspect logs the app writes.
78737
+
78738
+ Walk the real journeys, not just the happy path that's easy to reach. For each surface, exercise:
78739
+
78740
+ 1. **Primary flows** \u2014 the main things a user comes here to do, start to finish.
78741
+ 2. **Inputs & forms** \u2014 submit valid input, empty input, and obviously wrong input; check validation and error messages.
78742
+ 3. **Navigation** \u2014 every reachable link/button/route/tab/command; look for dead ends, broken links, blank screens, 404s, console/stderr errors.
78743
+ 4. **States** \u2014 empty, loading, error, offline/slow, and "no data yet" states. These are where apps break most.
78744
+ 5. **Visual integrity** \u2014 overlapping/cut-off/misaligned elements, unstyled flashes, illegible text, broken images \u2014 things only visible by actually looking at a screenshot.
78745
+
78746
+ As you go, keep a running list of every bug with: what you did, what you expected, what actually happened, the evidence (screenshot path / captured output / log line), and the file/area it most likely lives in.
78747
+
78748
+ ## Phase 2: Triage each bug \u2014 blocking vs deferrable
78749
+
78750
+ For every bug, decide one of two paths:
78751
+
78752
+ **A) BLOCKING \u2014 it stops you from testing further.** The app won't start, a screen crashes, a flow can't be completed, or a broken gate hides everything behind it. You cannot meaningfully continue the test pass until it's fixed. **Fix these immediately**, right now, so you can keep testing:
78753
+
78754
+ 1. Reproduce it and find the root cause in the code.
78755
+ 2. Use the \`mcp__kencode-search__searchCode\` tool to reference how real projects implement the same pattern correctly, and base your fix on that working code. (If the kencode-search MCP tool isn't connected, note that and fix using project conventions + authoritative docs.)
78756
+ 3. Implement the fix, then re-run the app and CONFIRM with your eyes (re-screenshot / re-read output) that the bug is actually gone.
78757
+ 4. Commit the fix by running the \`/commit\` command, so each fix lands on working, committed code before you continue.
78758
+ 5. Resume the test pass from where you were blocked.
78759
+
78760
+ **B) DEFERRABLE \u2014 it's a real bug but you can keep testing around it.** Cosmetic issues, non-blocking errors, secondary-flow breakage, edge-case mishandling. **Do NOT fix these now.** Record them and move on \u2014 they'll be handed off as tasks for another agent to fix in a later session.
78761
+
78762
+ When unsure, prefer DEFER: only fix inline what genuinely blocks the test pass. The point is to keep driving the app and cataloguing bugs, not to stop and fix everything.
78763
+
78764
+ ## Phase 3: File deferrable bugs as tasks
78765
+
78766
+ For every deferrable bug (or a tightly-coupled group), add one task with the \`tasks\` tool (action=add). Running /test-drive is the user's explicit request to populate the task list, so this is expected \u2014 but only file REAL, reproduced bugs, not speculation. **Before filing, trace each bug to its root cause and confirm it's an actual code defect \u2014 not bad seed/test/mock data, a misconfig, or expected behavior.** This app is full of synthetic data, so "these numbers look insane" is very often just the data, not a bug. Reading the code/data/DB to establish cause is REQUIRED here, not an "assumption" \u2014 the no-assumptions rule means don't claim a screen works without looking, it does not mean skip root-cause analysis. For any numeric/calculation bug, reproduce the arithmetic from the underlying inputs before filing. Order tasks by user impact and severity. Each task needs a short title and a standalone prompt (the next agent has NO context from this session) that includes:
78767
+
78768
+ - **The bug**: what you did, what you expected, what actually happened.
78769
+ - **Reproduction steps**: the exact flow to trigger it (URL/screen/command + clicks/inputs).
78770
+ - **Evidence**: the screenshot path / captured output / log line you saw.
78771
+ - **Root cause**: the traced reason it's a code defect (not data/config/expected behavior) \u2014 for numeric bugs, the inputs and the arithmetic you reproduced.
78772
+ - **Where to look**: the file(s)/area the bug most likely lives in.
78773
+
78774
+ End EVERY task's standalone prompt with this exact line, verbatim, on its own line:
78775
+
78776
+ use kencode to reference working code. /commit when done.
78777
+
78778
+ That line guarantees the next agent bases its fix on real working code (via the kencode MCP) and commits it.
78779
+
78780
+ ## Phase 4: Report
78781
+
78782
+ When the test pass is done (or you've covered the focus area), summarize:
78783
+
78784
+ - What you ran and which surfaces/flows you actually drove (with screenshot/output evidence).
78785
+ - **Blocking bugs you fixed inline** \u2014 each with its root cause and the commit.
78786
+ - **Deferrable bugs filed as tasks** \u2014 a short list of titles.
78787
+
78788
+ Then tell the user exactly: "Tasks added. Press Ctrl+T to open the task list and run them." Do not start executing those deferred tasks unless the user explicitly says so.
78789
+
78790
+ ## Rules
78791
+
78792
+ - **Actually run the app and look.** Don't claim a screen works without observing it \u2014 a screenshot, captured output, or log line. No "this should work." But observation alone is not a filed bug: confirming a defect requires tracing the cause, which means reading the code/data/inputs.
78793
+ - **Trace cause before filing.** A symptom is not a bug until you've traced it to a code defect and ruled out bad seed/test/mock data, misconfig, and expected behavior. For numeric/calculation bugs, reproduce the arithmetic from the underlying inputs.
78794
+ - **An AI/agent (or the model itself) noticing something looks wrong is NOT evidence** \u2014 a model flags "big number vs small position" the same way whether the cause is data or logic. Only reproduced behavior plus a traced cause counts.
78795
+ - **Only fix what blocks you.** Blocking bugs get fixed inline (kencode-referenced + \`/commit\`); everything else becomes a task. When in doubt, defer.
78796
+ - **Every fix is on working, committed code** \u2014 reference real code via kencode, verify the fix by re-running, then \`/commit\`.
78797
+ - **Every filed task ends with the exact line:** use kencode to reference working code. /commit when done.
78798
+ - **File only reproduced bugs with a traced root cause.** No speculative or "could be improved" tasks, and no symptoms with an unverified cause \u2014 this is a bug hunt, not a polish wishlist.`
78292
78799
  },
78293
78800
  {
78294
78801
  name: "elon",
@@ -78400,6 +78907,118 @@ If the user chooses D, stop after the report.
78400
78907
  - **App-wide first, specific areas second** \u2014 in both the hunt and the ledger.
78401
78908
  - **No deletion without code-grounded evidence** that the thing is dead weight (no callers / write-only / unreachable / redundant). No "feels bloated" nudges.
78402
78909
  - **Report-first. No deletions, edits, installs, or commits until the user picks an option.**
78910
+ - **Every generated task must end with the exact line:** use kencode to reference working code. /commit when done.`
78911
+ },
78912
+ {
78913
+ name: "elon-2",
78914
+ aliases: ["step-2", "add-back"],
78915
+ description: "Finish the Elon algorithm: add back the ~10%, then simplify/accelerate/automate",
78916
+ prompt: `# /elon-2: The Add-Back & Optimize Pass
78917
+
78918
+ This is the SECOND HALF of /elon, and it only makes sense AFTER deletions have landed. /elon runs steps 1\u20132 of Elon Musk's algorithm \u2014 make the requirement less dumb, then delete the part/process \u2014 and it deletes aggressively, on purpose, until things break. /elon-2 runs the rest of the same algorithm, IN ORDER:
78919
+
78920
+ 1. ~~Make the requirement less dumb~~ \u2014 done by /elon.
78921
+ 2. ~~Delete the part or process~~ \u2014 done by /elon.
78922
+ 3. **Simplify** \u2014 only what survived deletion.
78923
+ 4. **Accelerate** \u2014 only what survived simplification.
78924
+ 5. **Automate** \u2014 last, never first.
78925
+
78926
+ Before step 3, this command does the move /elon deliberately leaves undone \u2014 the famous Musk rule: **"if you're not adding ~10% back, you didn't delete enough."** Aggressive deletion overshoots; some small piece you cut was actually load-bearing and has to come back. **Phase 1 recovers that ~10%.** Only then do steps 3\u20135 run, on what survived.
78927
+
78928
+ This command is **project-agnostic** and **report-first**: the only deliverable is a single ranked ledger, after which you hand the work off as tasks. **Do not edit, install, or implement anything until the user confirms by choosing an option at the end.**
78929
+
78930
+ If the user passed arguments to /elon-2, treat them as a focus area: narrow the pass to that feature/surface, but still run the full algorithm within it.
78931
+
78932
+ **Hard scope rules:**
78933
+ - **Add-backs are strictly the minimal load-bearing piece that broke.** Restoring functionality the deletions removed is NOT re-adding scope. If an "add-back" is really a net-new capability or a scope re-expansion, that is /expand \u2014 drop it here.
78934
+ - **Steps 3\u20135 operate ONLY on survivors.** Never simplify, accelerate, or automate something that should have been deleted \u2014 /elon already made those calls. Do not re-litigate deletions (revert-the-whole-deletion is the one exception, see Phase 1).
78935
+ - **Order is law.** Add-back \u2192 simplify \u2192 accelerate \u2192 automate. Never accelerate or automate something before it has been simplified.
78936
+
78937
+ ## Phase 0: Establish what changed + a baseline oracle (main agent)
78938
+
78939
+ You cannot add back what broke without knowing what was cut. Build two maps from real evidence, not memory:
78940
+
78941
+ - **Deletion map** \u2014 what /elon actually removed. Derive it from \`git log\`/\`git diff\` over the relevant range, completed deletion tasks, and removed files/symbols/flags/dependencies. For each deletion, note its predicted add-back (zero / fold-in / seam) from the /elon ledger if available.
78942
+ - **Survivor map** \u2014 the user-facing surfaces, flows, and internal pieces that remain after the deletions.
78943
+
78944
+ Then run the project's own **build / typecheck / test / lint** (whatever it has) to capture a baseline oracle: what is broken right now, after the deletions. Note dangling imports, broken routes, failing tests, dead references, and any flow that no longer completes.
78945
+
78946
+ ## Phase 1: Add-back recovery (the ~10%)
78947
+
78948
+ Empirically find what the deletions broke or over-cut. Spawn subagents in parallel using the subagent tool (call the subagent tool multiple times in a single response), one per high-risk deletion cluster from the deletion map (cap at 6).
78949
+
78950
+ Each subagent must:
78951
+
78952
+ 1. Walk the deletion and find **breakage evidence** grounded in code: failing build/typecheck/test output, dangling references to removed symbols, routes/commands that no longer resolve, a real user flow that now dead-ends, behavior that callers still expect.
78953
+ 2. For every breakage, identify the **minimal add-back** \u2014 the smallest piece of the deleted thing that must return so dependents work again (mirror the zero / fold-in / seam shapes from /elon). Cite the file:line that proves the breakage and what the restore touches.
78954
+ 3. **Right-size the add-back.** If the minimal restore is large, vague, or "we'd basically rebuild the deleted thing," that is the signal the deletion itself was wrong \u2014 flag it as **REVERT** (undo the whole deletion) rather than a partial add-back. A small, well-scoped add-back is a true ~10%; a large one means the cut went too far.
78955
+
78956
+ A deletion that broke nothing needs no add-back \u2014 that is a clean cut, leave it. The goal is to restore the minimum, not to undo the diet.
78957
+
78958
+ ## Phase 2: Steps 3\u20135 on survivors (in order)
78959
+
78960
+ For the survivor map only, spawn subagents in parallel (cap at 6 total across the three steps) to find optimization candidates, strictly in algorithm order:
78961
+
78962
+ - **Step 3 \u2014 Simplify.** Indirection, layers, branches, or config that only existed to serve now-deleted things and can be collapsed or inlined; survivors that can be merged; flows that can be flattened. This is where most leverage lives post-deletion.
78963
+ - **Step 4 \u2014 Accelerate.** Only what survived simplification: hot paths, redundant work, slow startup, repeated computation that can be sped up. A candidate may not be accelerated until it has been simplified first.
78964
+ - **Step 5 \u2014 Automate.** Last: manual steps in surviving flows that the system should do for the user. Never propose automating something that should instead be simplified away.
78965
+
78966
+ Each subagent must cite file:line anchors, name which step it belongs to, and estimate effort (small / medium / large) and leverage.
78967
+
78968
+ ## Phase 3: Validate against the repo (main agent)
78969
+
78970
+ For every candidate:
78971
+
78972
+ 1. **Add-backs:** confirm the breakage is real against the baseline oracle and that the restore is genuinely minimal. If the restore turns out large, reclassify as REVERT or drop it.
78973
+ 2. **Simplify/accelerate/automate:** confirm the candidate is a survivor (not something that should have been deleted), and that the step order holds (nothing accelerated/automated before being simplified).
78974
+ 3. Confirm scope: add-backs restore removed behavior only \u2014 anything that is net-new capability is /expand, make-it-work polish is /raise-floor, security is /bullet-proof. Drop out-of-scope items.
78975
+ 4. Merge duplicates. Rank by **completion leverage = (breakage severity or surface improved) \xF7 effort**, with all add-backs ahead of all step 3\u20135 work.
78976
+
78977
+ ## Phase 4: The completion ledger (report)
78978
+
78979
+ Output the report. **Add-back (recover) rows first, then simplify, then accelerate, then automate** \u2014 algorithm order. Start with one line: project name + a one-sentence summary of how far the deletions overshot and where the biggest post-deletion wins are. Then a single table:
78980
+
78981
+ | ID | Step | Candidate | Evidence (file:line) | What it restores / improves | Effort | Leverage |
78982
+ |---|---|---|---|---|---|---|
78983
+ | E2-001 | add-back | re-add the one default the deleted settings screen applied | flow X dead-ends after delete (path:line) | onboarding applies the default inline; nothing else returns | small | high |
78984
+ | E2-002 | simplify | inline the adapter layer that only wrapped the deleted backend | single caller left (path:line) | one fewer indirection; survivors merge | small | high |
78985
+
78986
+ Use IDs like E2-001. Add-back rows lead, then step 3, then 4, then 5. Mark any deletion that overshot as **REVERT** with the reason. The ledger is structured so a later empirical mode can run each row against the project's build/check/test as the "is it fixed / still green?" oracle. Do not run that loop now \u2014 this is report-only.
78987
+
78988
+ After the table, ask exactly:
78989
+
78990
+ What should I do?
78991
+ A) Add tasks for everything (add-backs first, then simplify/accelerate/automate)
78992
+ B) Add tasks for the add-backs only (just recover what broke)
78993
+ C) Add tasks for specific rows (give IDs, e.g. "E2-001, E2-004")
78994
+ D) None \u2014 report only
78995
+
78996
+ Do not start implementing until the user chooses.
78997
+
78998
+ ## Phase 5: Hand off as tasks
78999
+
79000
+ If the user chooses A, B, or C, do not implement directly. Add one task per selected row (or tightly coupled group) using the \`tasks\` tool (action=add), ordered by algorithm step then leverage \u2014 **add-backs first, then simplify, then accelerate, then automate**. Each task needs a short title and a standalone prompt that includes:
79001
+
79002
+ - the row ID, its step, and exactly what to restore or change (files/symbols/flags + anchors),
79003
+ - for add-backs: the breakage it fixes and the minimal restore (never re-expand scope),
79004
+ - the blast radius to touch (call sites, imports, tests, docs, config),
79005
+ - the project's verification commands to prove the build/tests are green again after the change.
79006
+
79007
+ End EVERY task's standalone prompt with this exact line, verbatim, on its own line:
79008
+
79009
+ use kencode to reference working code. /commit when done.
79010
+
79011
+ After adding the tasks, tell the user exactly: "Tasks added. Press Ctrl+T to open the task list and run them." Do not begin executing them unless the user explicitly says so.
79012
+
79013
+ If the user chooses D, stop after the report.
79014
+
79015
+ ## Rules
79016
+
79017
+ - **Runs after /elon.** This pass assumes deletions already landed; Phase 0 derives them from git history and completed tasks.
79018
+ - **Add back the ~10%, no more.** Restore only the minimal load-bearing piece that broke. A large add-back means the deletion overshot \u2014 mark it REVERT, don't quietly rebuild.
79019
+ - **Algorithm order is law.** Add-back \u2192 simplify \u2192 accelerate \u2192 automate. Never accelerate or automate before simplifying.
79020
+ - **Survivors only for steps 3\u20135.** Don't optimize something that should have been deleted; don't re-add scope (that's /expand).
79021
+ - **Report-first. No edits, installs, or commits until the user picks an option.**
78403
79022
  - **Every generated task must end with the exact line:** use kencode to reference working code. /commit when done.`
78404
79023
  },
78405
79024
  {
@@ -78943,9 +79562,9 @@ function getPromptCommand(name) {
78943
79562
  // ../cli/dist/core/custom-commands.js
78944
79563
  init_esm_shims();
78945
79564
  import fs25 from "fs/promises";
78946
- import path30 from "path";
79565
+ import path33 from "path";
78947
79566
  async function loadCustomCommands(cwd2) {
78948
- const commandsDir = path30.join(cwd2, ".ezcoder", "commands");
79567
+ const commandsDir = path33.join(cwd2, ".ezcoder", "commands");
78949
79568
  const commands = [];
78950
79569
  let files;
78951
79570
  try {
@@ -78956,11 +79575,11 @@ async function loadCustomCommands(cwd2) {
78956
79575
  for (const file2 of files) {
78957
79576
  if (!file2.endsWith(".md"))
78958
79577
  continue;
78959
- const filePath = path30.join(commandsDir, file2);
79578
+ const filePath = path33.join(commandsDir, file2);
78960
79579
  try {
78961
79580
  const raw = await fs25.readFile(filePath, "utf-8");
78962
79581
  const parsed = parseSkillFile(raw, "project");
78963
- const name = parsed.name || path30.basename(file2, ".md");
79582
+ const name = parsed.name || path33.basename(file2, ".md");
78964
79583
  commands.push({
78965
79584
  name,
78966
79585
  description: parsed.description || `Custom command from .ezcoder/commands/${file2}`,
@@ -78982,7 +79601,7 @@ init_esm_shims();
78982
79601
  // ../cli/dist/core/extensions/loader.js
78983
79602
  init_esm_shims();
78984
79603
  import fs26 from "fs/promises";
78985
- import path31 from "path";
79604
+ import path34 from "path";
78986
79605
  var ExtensionLoader = class {
78987
79606
  loaded = [];
78988
79607
  async loadAll(extensionsDir, context) {
@@ -78995,7 +79614,7 @@ var ExtensionLoader = class {
78995
79614
  for (const file2 of files) {
78996
79615
  if (!file2.endsWith(".js"))
78997
79616
  continue;
78998
- const filePath = path31.join(extensionsDir, file2);
79617
+ const filePath = path34.join(extensionsDir, file2);
78999
79618
  try {
79000
79619
  const mod = await import(filePath);
79001
79620
  const factory = typeof mod.default === "function" ? mod.default : mod.createExtension;
@@ -85229,7 +85848,138 @@ var StdioClientTransport = class {
85229
85848
  };
85230
85849
 
85231
85850
  // ../cli/dist/core/mcp/client.js
85851
+ import http from "http";
85232
85852
  import os8 from "os";
85853
+
85854
+ // ../cli/dist/core/mcp/oauth-provider.js
85855
+ init_esm_shims();
85856
+ import crypto8 from "crypto";
85857
+
85858
+ // ../cli/dist/core/mcp/oauth-store.js
85859
+ init_esm_shims();
85860
+ import fs27 from "fs/promises";
85861
+ var McpOAuthStore = class {
85862
+ filePath;
85863
+ constructor(filePath = getAppPaths().mcpAuthFile) {
85864
+ this.filePath = filePath;
85865
+ }
85866
+ async readAll() {
85867
+ try {
85868
+ const raw = await fs27.readFile(this.filePath, "utf-8");
85869
+ const parsed = JSON.parse(raw);
85870
+ return { version: 1, servers: parsed.servers ?? {} };
85871
+ } catch {
85872
+ return { version: 1, servers: {} };
85873
+ }
85874
+ }
85875
+ async writeAll(data) {
85876
+ try {
85877
+ await fs27.writeFile(this.filePath, JSON.stringify(data, null, 2), {
85878
+ encoding: "utf-8",
85879
+ mode: 384
85880
+ });
85881
+ } catch (err) {
85882
+ log("WARN", "mcp", "failed to persist MCP OAuth store", {
85883
+ message: err instanceof Error ? err.message : String(err)
85884
+ });
85885
+ }
85886
+ }
85887
+ async get(name) {
85888
+ const all = await this.readAll();
85889
+ return all.servers[name] ?? {};
85890
+ }
85891
+ /** Merge a partial entry into the server's record (read-modify-write). */
85892
+ async patch(name, patch) {
85893
+ const all = await this.readAll();
85894
+ all.servers[name] = { ...all.servers[name] ?? {}, ...patch };
85895
+ await this.writeAll(all);
85896
+ }
85897
+ /** Drop a server's whole OAuth record (used on logout / removal). */
85898
+ async clear(name) {
85899
+ const all = await this.readAll();
85900
+ if (all.servers[name]) {
85901
+ delete all.servers[name];
85902
+ await this.writeAll(all);
85903
+ }
85904
+ }
85905
+ /** Whether this server has saved tokens (i.e. has completed login at least once). */
85906
+ async hasTokens(name) {
85907
+ const entry = await this.get(name);
85908
+ return !!entry.tokens?.access_token;
85909
+ }
85910
+ };
85911
+
85912
+ // ../cli/dist/core/mcp/oauth-provider.js
85913
+ var MCP_OAUTH_CALLBACK_PORT = 41999;
85914
+ var MCP_OAUTH_CALLBACK_PATH = "/oauth/callback";
85915
+ function mcpOAuthRedirectUrl() {
85916
+ return `http://localhost:${MCP_OAUTH_CALLBACK_PORT}${MCP_OAUTH_CALLBACK_PATH}`;
85917
+ }
85918
+ var McpOAuthProvider = class {
85919
+ store;
85920
+ serverName;
85921
+ onRedirect;
85922
+ scope;
85923
+ constructor(opts) {
85924
+ this.serverName = opts.serverName;
85925
+ this.store = opts.store ?? new McpOAuthStore();
85926
+ this.onRedirect = opts.onRedirect;
85927
+ this.scope = opts.scope;
85928
+ }
85929
+ get redirectUrl() {
85930
+ return mcpOAuthRedirectUrl();
85931
+ }
85932
+ get clientMetadata() {
85933
+ return {
85934
+ client_name: "EZ Coder",
85935
+ client_uri: "https://github.com/kenkaiii/ezcoder",
85936
+ redirect_uris: [this.redirectUrl],
85937
+ grant_types: ["authorization_code", "refresh_token"],
85938
+ response_types: ["code"],
85939
+ token_endpoint_auth_method: "none",
85940
+ ...this.scope ? { scope: this.scope } : {}
85941
+ };
85942
+ }
85943
+ async state() {
85944
+ const entry = await this.store.get(this.serverName);
85945
+ if (entry.state)
85946
+ return entry.state;
85947
+ const fresh = crypto8.randomBytes(16).toString("hex");
85948
+ await this.store.patch(this.serverName, { state: fresh });
85949
+ return fresh;
85950
+ }
85951
+ async clientInformation() {
85952
+ const entry = await this.store.get(this.serverName);
85953
+ return entry.clientInformation;
85954
+ }
85955
+ async saveClientInformation(info) {
85956
+ await this.store.patch(this.serverName, {
85957
+ clientInformation: info
85958
+ });
85959
+ }
85960
+ async tokens() {
85961
+ const entry = await this.store.get(this.serverName);
85962
+ return entry.tokens;
85963
+ }
85964
+ async saveTokens(tokens2) {
85965
+ await this.store.patch(this.serverName, { tokens: tokens2 });
85966
+ }
85967
+ redirectToAuthorization(authorizationUrl) {
85968
+ this.onRedirect?.(authorizationUrl);
85969
+ }
85970
+ async saveCodeVerifier(codeVerifier) {
85971
+ await this.store.patch(this.serverName, { codeVerifier });
85972
+ }
85973
+ async codeVerifier() {
85974
+ const entry = await this.store.get(this.serverName);
85975
+ if (!entry.codeVerifier) {
85976
+ throw new Error("No PKCE code verifier saved for this MCP server.");
85977
+ }
85978
+ return entry.codeVerifier;
85979
+ }
85980
+ };
85981
+
85982
+ // ../cli/dist/core/mcp/client.js
85233
85983
  var MCPClientManager = class {
85234
85984
  servers = [];
85235
85985
  async connectAll(configs) {
@@ -85251,9 +86001,10 @@ var MCPClientManager = class {
85251
86001
  if (result.status === "fulfilled") {
85252
86002
  return { name, ok: true, toolCount: result.value.length, tools: result.value };
85253
86003
  }
85254
- const error51 = formatConnectError(result.reason);
86004
+ const requiresAuth = isUnauthorized(result.reason);
86005
+ const error51 = requiresAuth ? "Requires login." : formatConnectError(result.reason);
85255
86006
  log("WARN", "mcp", `Failed to connect to MCP server "${name}"`, { error: error51 });
85256
- return { name, ok: false, toolCount: 0, tools: [], error: error51 };
86007
+ return { name, ok: false, toolCount: 0, tools: [], error: error51, requiresAuth };
85257
86008
  });
85258
86009
  const connected = results.filter((r2) => r2.ok).length;
85259
86010
  const toolCount = results.reduce((sum, r2) => sum + r2.toolCount, 0);
@@ -85278,8 +86029,120 @@ var MCPClientManager = class {
85278
86029
  }
85279
86030
  return { name: config2.name, ok: true, toolCount: tools.length, tools };
85280
86031
  } catch (err) {
85281
- const error51 = formatConnectError(err);
85282
- return { name: config2.name, ok: false, toolCount: 0, tools: [], error: error51 };
86032
+ const requiresAuth = isUnauthorized(err);
86033
+ const error51 = requiresAuth ? "Requires login." : formatConnectError(err);
86034
+ return { name: config2.name, ok: false, toolCount: 0, tools: [], error: error51, requiresAuth };
86035
+ }
86036
+ }
86037
+ /**
86038
+ * Run the interactive OAuth login for one remote MCP server end-to-end:
86039
+ * start a loopback callback server, let the SDK open the browser via
86040
+ * `onAuthorizationUrl`, capture the redirect, exchange the code, then verify
86041
+ * the authorized connection by listing tools. Tokens are persisted by the
86042
+ * provider so later (non-interactive) connects succeed silently.
86043
+ *
86044
+ * `onAuthorizationUrl` is invoked with the authorize URL so the host can open
86045
+ * it (the ezcoder-app broadcasts it to the webview, which opens the system
86046
+ * browser; the CLI prints it). Never throws — returns `{ ok:false, error }`.
86047
+ */
86048
+ async login(config2, onAuthorizationUrl, timeoutMs = 18e4) {
86049
+ if (!config2.url) {
86050
+ return { ok: false, toolCount: 0, error: "Login is only supported for HTTP MCP servers." };
86051
+ }
86052
+ const url2 = new URL(config2.url);
86053
+ const store2 = new McpOAuthStore();
86054
+ await store2.patch(config2.name, { codeVerifier: void 0, state: void 0 });
86055
+ let codeResolve;
86056
+ let codeReject;
86057
+ const codePromise = new Promise((resolve3, reject) => {
86058
+ codeResolve = resolve3;
86059
+ codeReject = reject;
86060
+ });
86061
+ const provider = new McpOAuthProvider({
86062
+ serverName: config2.name,
86063
+ store: store2,
86064
+ onRedirect: (authUrl) => onAuthorizationUrl(authUrl.toString())
86065
+ });
86066
+ const expectedState = await provider.state();
86067
+ const server = http.createServer((req, res) => {
86068
+ const reqUrl = new URL(req.url || "", `http://localhost:${MCP_OAUTH_CALLBACK_PORT}`);
86069
+ if (reqUrl.pathname !== MCP_OAUTH_CALLBACK_PATH) {
86070
+ res.statusCode = 404;
86071
+ res.end("Not found");
86072
+ return;
86073
+ }
86074
+ const err = reqUrl.searchParams.get("error");
86075
+ const code = reqUrl.searchParams.get("code");
86076
+ const state3 = reqUrl.searchParams.get("state");
86077
+ res.writeHead(200, { "Content-Type": "text/html" });
86078
+ if (err) {
86079
+ res.end(`<html><body><h1>Login failed</h1><p>${escapeHtml(err)}</p></body></html>`);
86080
+ codeReject?.(new Error(`Authorization failed: ${err}`));
86081
+ return;
86082
+ }
86083
+ if (!code) {
86084
+ res.end("<html><body><h1>Login failed</h1><p>No authorization code.</p></body></html>");
86085
+ codeReject?.(new Error("No authorization code in callback."));
86086
+ return;
86087
+ }
86088
+ if (state3 !== expectedState) {
86089
+ res.end("<html><body><h1>Login failed</h1><p>State mismatch.</p></body></html>");
86090
+ codeReject?.(new Error("OAuth state mismatch."));
86091
+ return;
86092
+ }
86093
+ res.end("<html><body><h1>Login successful!</h1><p>You can close this tab and return to EZ Coder.</p></body></html>");
86094
+ codeResolve?.(code);
86095
+ });
86096
+ try {
86097
+ await new Promise((resolve3, reject) => {
86098
+ server.once("error", reject);
86099
+ server.listen(MCP_OAUTH_CALLBACK_PORT, "127.0.0.1", () => resolve3());
86100
+ });
86101
+ } catch (err) {
86102
+ const msg = err instanceof Error ? err.message : String(err);
86103
+ const hint = msg.includes("EADDRINUSE") || msg.includes("in use") ? `Port ${MCP_OAUTH_CALLBACK_PORT} is in use \u2014 close whatever is using it and retry.` : msg;
86104
+ return { ok: false, toolCount: 0, error: `Could not start login callback server: ${hint}` };
86105
+ }
86106
+ const overallTimeout = setTimeout(() => {
86107
+ codeReject?.(new Error("Login timed out waiting for the browser callback."));
86108
+ }, timeoutMs);
86109
+ overallTimeout.unref();
86110
+ try {
86111
+ const loginTransport = new StreamableHTTPClientTransport(url2, {
86112
+ requestInit: config2.headers ? { headers: config2.headers } : void 0,
86113
+ authProvider: provider
86114
+ });
86115
+ const loginClient = new Client({ name: "ezcoder", version: "1.0.0" });
86116
+ try {
86117
+ await loginClient.connect(loginTransport);
86118
+ const { tools: tools2 } = await loginClient.listTools();
86119
+ await loginClient.close().catch(() => {
86120
+ });
86121
+ return { ok: true, toolCount: tools2.length };
86122
+ } catch (err) {
86123
+ if (!isUnauthorized(err))
86124
+ throw err;
86125
+ }
86126
+ const code = await codePromise;
86127
+ await loginTransport.finishAuth(code);
86128
+ await loginClient.close().catch(() => {
86129
+ });
86130
+ const verifyTransport = new StreamableHTTPClientTransport(url2, {
86131
+ requestInit: config2.headers ? { headers: config2.headers } : void 0,
86132
+ authProvider: provider
86133
+ });
86134
+ const verifyClient = new Client({ name: "ezcoder", version: "1.0.0" });
86135
+ await verifyClient.connect(verifyTransport);
86136
+ const { tools } = await verifyClient.listTools();
86137
+ await verifyClient.close().catch(() => {
86138
+ });
86139
+ return { ok: true, toolCount: tools.length };
86140
+ } catch (err) {
86141
+ return { ok: false, toolCount: 0, error: formatConnectError(err) };
86142
+ } finally {
86143
+ clearTimeout(overallTimeout);
86144
+ server.close();
86145
+ await store2.patch(config2.name, { codeVerifier: void 0, state: void 0 });
85283
86146
  }
85284
86147
  }
85285
86148
  async connectServer(config2) {
@@ -85311,19 +86174,24 @@ var MCPClientManager = class {
85311
86174
  } else {
85312
86175
  const url2 = new URL(config2.url);
85313
86176
  const reqInit = config2.headers ? { headers: config2.headers } : void 0;
86177
+ const authProvider = new McpOAuthProvider({ serverName: config2.name });
85314
86178
  try {
85315
86179
  transport = new StreamableHTTPClientTransport(url2, {
85316
- requestInit: reqInit
86180
+ requestInit: reqInit,
86181
+ authProvider
85317
86182
  });
85318
86183
  client = new Client({ name: "ezcoder", version: "1.0.0" });
85319
86184
  await client.connect(transport, { timeout });
85320
86185
  } catch (streamableErr) {
86186
+ if (isUnauthorized(streamableErr))
86187
+ throw streamableErr;
85321
86188
  log("INFO", "mcp", `StreamableHTTP failed for "${config2.name}", trying SSE fallback`, {
85322
86189
  error: String(streamableErr)
85323
86190
  });
85324
86191
  transport = new SSEClientTransport(url2, {
85325
86192
  eventSourceInit: config2.headers ? { fetch: createHeaderFetch(config2.headers) } : void 0,
85326
- requestInit: reqInit
86193
+ requestInit: reqInit,
86194
+ authProvider
85327
86195
  });
85328
86196
  client = new Client({ name: "ezcoder", version: "1.0.0" });
85329
86197
  await client.connect(transport, { timeout });
@@ -85388,6 +86256,15 @@ function formatConnectError(reason) {
85388
86256
  }
85389
86257
  return msg;
85390
86258
  }
86259
+ function isUnauthorized(reason) {
86260
+ if (reason instanceof UnauthorizedError)
86261
+ return true;
86262
+ const msg = reason instanceof Error ? reason.message : String(reason);
86263
+ return msg.includes("Unauthorized") || msg.includes("401") || msg.toLowerCase().includes("invalid_token");
86264
+ }
86265
+ function escapeHtml(value) {
86266
+ return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
86267
+ }
85391
86268
  function createHeaderFetch(extraHeaders) {
85392
86269
  return (url2, init) => {
85393
86270
  const existing = init?.headers ?? {};
@@ -85400,8 +86277,8 @@ init_esm_shims();
85400
86277
 
85401
86278
  // ../cli/dist/core/mcp/store.js
85402
86279
  init_esm_shims();
85403
- import path33 from "path";
85404
- import fs27 from "fs/promises";
86280
+ import path35 from "path";
86281
+ import fs28 from "fs/promises";
85405
86282
  var StoredServerEntrySchema = external_exports.object({
85406
86283
  type: external_exports.enum(["stdio", "http", "streamable-http", "sse"]).optional(),
85407
86284
  url: external_exports.string().optional(),
@@ -85419,12 +86296,12 @@ function globalMcpPath() {
85419
86296
  return getAppPaths().mcpFile;
85420
86297
  }
85421
86298
  function projectMcpPath(cwd2) {
85422
- return path33.join(cwd2, ".ezcoder", "mcp.json");
86299
+ return path35.join(cwd2, ".ezcoder", "mcp.json");
85423
86300
  }
85424
86301
  async function readMcpFile(filePath) {
85425
86302
  let content;
85426
86303
  try {
85427
- content = await fs27.readFile(filePath, "utf-8");
86304
+ content = await fs28.readFile(filePath, "utf-8");
85428
86305
  } catch {
85429
86306
  return { mcpServers: {} };
85430
86307
  }
@@ -85477,8 +86354,8 @@ async function loadServers(cwd2) {
85477
86354
 
85478
86355
  // ../cli/dist/core/mcp/defaults.js
85479
86356
  import { createRequire } from "module";
85480
- import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
85481
- import path34 from "path";
86357
+ import { existsSync as existsSync5, readFileSync as readFileSync3 } from "fs";
86358
+ import path36 from "path";
85482
86359
  var KENCODE_PACKAGE = "@kenkaiiii/kencode-search";
85483
86360
  function resolveKencodeServer() {
85484
86361
  try {
@@ -85487,8 +86364,8 @@ function resolveKencodeServer() {
85487
86364
  const pkg = JSON.parse(readFileSync3(pkgJsonPath, "utf8"));
85488
86365
  const binRel = typeof pkg.bin === "string" ? pkg.bin : pkg.bin?.["kencode-search"] ?? Object.values(pkg.bin ?? {})[0] ?? pkg.main;
85489
86366
  if (binRel) {
85490
- const binPath = path34.join(path34.dirname(pkgJsonPath), binRel);
85491
- if (existsSync3(binPath)) {
86367
+ const binPath = path36.join(path36.dirname(pkgJsonPath), binRel);
86368
+ if (existsSync5(binPath)) {
85492
86369
  return { name: "kencode-search", command: process.execPath, args: [binPath] };
85493
86370
  }
85494
86371
  }
@@ -85545,12 +86422,12 @@ init_esm_shims();
85545
86422
 
85546
86423
  // ../cli/dist/core/agents.js
85547
86424
  init_esm_shims();
85548
- import fs28 from "fs/promises";
85549
- import path35 from "path";
86425
+ import fs29 from "fs/promises";
86426
+ import path37 from "path";
85550
86427
  async function discoverAgents(options) {
85551
86428
  const agents = [];
85552
86429
  if (options.projectDir) {
85553
- const projectAgentsDir = path35.join(options.projectDir, ".ezcoder", "agents");
86430
+ const projectAgentsDir = path37.join(options.projectDir, ".ezcoder", "agents");
85554
86431
  const projectAgents = await loadAgentsFromDir(projectAgentsDir, "project");
85555
86432
  agents.push(...projectAgents);
85556
86433
  }
@@ -85568,19 +86445,19 @@ async function loadAgentsFromDir(dir, source2) {
85568
86445
  const agents = [];
85569
86446
  let files;
85570
86447
  try {
85571
- files = await fs28.readdir(dir);
86448
+ files = await fs29.readdir(dir);
85572
86449
  } catch {
85573
86450
  return agents;
85574
86451
  }
85575
86452
  for (const file2 of files) {
85576
86453
  if (!file2.endsWith(".md"))
85577
86454
  continue;
85578
- const filePath = path35.join(dir, file2);
86455
+ const filePath = path37.join(dir, file2);
85579
86456
  try {
85580
- const content = await fs28.readFile(filePath, "utf-8");
86457
+ const content = await fs29.readFile(filePath, "utf-8");
85581
86458
  const agent = parseAgentFile(content, source2);
85582
86459
  if (!agent.name) {
85583
- agent.name = path35.basename(file2, ".md");
86460
+ agent.name = path37.basename(file2, ".md");
85584
86461
  }
85585
86462
  agents.push(agent);
85586
86463
  } catch {
@@ -85711,10 +86588,197 @@ var BUNDLED_AGENTS = [
85711
86588
  }
85712
86589
  ];
85713
86590
 
86591
+ // ../cli/dist/utils/session-title.js
86592
+ init_esm_shims();
86593
+ var TITLE_PROMPT = `Generate an extremely short title (3-7 words) summarizing what the user is asking for. Just the title, nothing else. No quotes, no punctuation at the end.`;
86594
+ async function generateSessionTitle(opts) {
86595
+ let apiKey = opts.apiKey;
86596
+ let accountId = opts.accountId;
86597
+ if (opts.resolveCredentials) {
86598
+ const creds = await opts.resolveCredentials();
86599
+ apiKey = creds.apiKey;
86600
+ accountId = creds.accountId;
86601
+ }
86602
+ const model = opts.provider === "anthropic" ? "claude-haiku-4-5-20251001" : opts.provider === "openai" ? "gpt-5.1-codex-mini" : opts.provider === "glm" ? "glm-4.7-flash" : opts.provider === "moonshot" ? "kimi-k2.7-code" : "claude-haiku-4-5-20251001";
86603
+ const messages = [
86604
+ { role: "system", content: TITLE_PROMPT },
86605
+ {
86606
+ role: "user",
86607
+ content: `User asked: "${truncate2(opts.userMessage, 300)}"
86608
+
86609
+ Assistant began: "${truncate2(opts.assistantPreview, 200)}"`
86610
+ }
86611
+ ];
86612
+ try {
86613
+ const result = stream({
86614
+ provider: opts.provider,
86615
+ model,
86616
+ messages,
86617
+ maxTokens: 30,
86618
+ temperature: 0,
86619
+ apiKey,
86620
+ baseUrl: opts.baseUrl,
86621
+ accountId
86622
+ });
86623
+ result.response.catch(() => {
86624
+ });
86625
+ const response = await result;
86626
+ const msg = response.message;
86627
+ const text = typeof msg.content === "string" ? msg.content : msg.content.filter((c2) => c2.type === "text").map((c2) => c2.text).join("");
86628
+ return text.trim().replace(/[."]+$/, "") || "New conversation";
86629
+ } catch {
86630
+ return fallbackTitle(opts.userMessage);
86631
+ }
86632
+ }
86633
+ function truncate2(s, max) {
86634
+ if (s.length <= max)
86635
+ return s;
86636
+ return s.slice(0, max) + "\u2026";
86637
+ }
86638
+ function fallbackTitle(userMessage) {
86639
+ if (!userMessage)
86640
+ return "New conversation";
86641
+ const cleaned = userMessage.replace(/^\/\S+\s*/, "").replace(/\s+/g, " ").trim();
86642
+ const first = cleaned.split(/[.\n]/)[0]?.trim() ?? cleaned;
86643
+ if (first.length <= 50)
86644
+ return first;
86645
+ const t = first.slice(0, 50);
86646
+ const sp = t.lastIndexOf(" ");
86647
+ return (sp > 20 ? t.slice(0, sp) : t) + "\u2026";
86648
+ }
86649
+
86650
+ // ../cli/dist/core/ideal-review.js
86651
+ init_esm_shims();
86652
+ var IDEAL_REVIEW_PROMPT = "Ideal? Review the actual work against the user's request before the final response. Is it simple, focused, correct, and aligned? Did you over-edit, leave TODOs, miss an obvious case the request called for, or introduce risk? Judge this by reading the code you changed \u2014 do NOT run builds, typechecks, linters, or test suites now; that happens at commit time via /commit. If anything is wrong, fix it now. If everything is good, respond with the final answer only; do not mention this ideal review unless it changed the work.";
86653
+ function evaluateIdealReview(stats) {
86654
+ const reasons = [];
86655
+ let score = 0;
86656
+ if (stats.changedLines >= 120) {
86657
+ score += 2;
86658
+ reasons.push(`${stats.changedLines} changed lines`);
86659
+ } else if (stats.changedLines >= 60) {
86660
+ score += 1;
86661
+ reasons.push(`${stats.changedLines} changed lines`);
86662
+ }
86663
+ if (stats.toolCalls >= 8) {
86664
+ score += 1;
86665
+ reasons.push(`${stats.toolCalls} tool calls`);
86666
+ }
86667
+ if (stats.writeCalls + stats.editCalls >= 4) {
86668
+ score += 2;
86669
+ reasons.push(`${stats.writeCalls + stats.editCalls} file mutation calls`);
86670
+ } else if (stats.writeCalls + stats.editCalls >= 2) {
86671
+ score += 1;
86672
+ reasons.push(`${stats.writeCalls + stats.editCalls} file mutation calls`);
86673
+ }
86674
+ if (stats.bashCalls > 0 && stats.writeCalls + stats.editCalls > 0) {
86675
+ score += 1;
86676
+ reasons.push("shell command plus file mutation");
86677
+ }
86678
+ if (stats.toolFailures > 0) {
86679
+ score += 2;
86680
+ reasons.push(`${stats.toolFailures} failed tool calls`);
86681
+ }
86682
+ if (stats.turns >= 6) {
86683
+ score += 1;
86684
+ reasons.push(`${stats.turns} agent turns`);
86685
+ }
86686
+ return { shouldReview: score >= 4, score, reasons };
86687
+ }
86688
+ function buildIdealReviewMessage(reasons) {
86689
+ const reasonText = reasons.length > 0 ? ` Triggered because: ${reasons.join(", ")}.` : "";
86690
+ return {
86691
+ role: "user",
86692
+ content: `${IDEAL_REVIEW_PROMPT}${reasonText}`
86693
+ };
86694
+ }
86695
+
86696
+ // ../cli/dist/core/loop-breaker.js
86697
+ init_esm_shims();
86698
+ var CONSECUTIVE_FAILURE_LIMIT = 3;
86699
+ var SIGNATURE_REPEAT_LIMIT = 3;
86700
+ var SAME_FILE_EDIT_LIMIT = 5;
86701
+ var LOOP_BREAK_PROMPT = "Stuck? You've repeated essentially the same action and it keeps failing or not advancing. Stop and break the pattern. Read the latest error or result literally \u2014 not what you expected it to say. Then question the assumption underneath your approach: the file, path, API, command, or premise you've been treating as true may be wrong. Either try a fundamentally different approach or, if you genuinely cannot make progress, stop and tell the user what's blocking you and what you need. Do NOT repeat the previous attempt with minor tweaks. Do not mention this note unless it changed your approach.";
86702
+ function toolCallSignature(name, args) {
86703
+ return `${name}\0${canonicalize(args)}`;
86704
+ }
86705
+ function canonicalize(value) {
86706
+ if (value === null || typeof value !== "object") {
86707
+ return JSON.stringify(value) ?? "null";
86708
+ }
86709
+ if (Array.isArray(value)) {
86710
+ return `[${value.map(canonicalize).join(",")}]`;
86711
+ }
86712
+ const entries = Object.entries(value).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0);
86713
+ return `{${entries.map(([k, v]) => `${JSON.stringify(k)}:${canonicalize(v)}`).join(",")}}`;
86714
+ }
86715
+ var TEXT_REPETITION_MIN_LENGTH = 40;
86716
+ var TEXT_REPETITION_MIN_REPEATS = 3;
86717
+ var TEXT_REPETITION_TAIL = 4096;
86718
+ function detectTextRepetition(text) {
86719
+ if (text.length < TEXT_REPETITION_MIN_LENGTH * TEXT_REPETITION_MIN_REPEATS) {
86720
+ return false;
86721
+ }
86722
+ const tail = text.slice(-TEXT_REPETITION_TAIL);
86723
+ const maxBlock = Math.floor(tail.length / TEXT_REPETITION_MIN_REPEATS);
86724
+ for (let block2 = TEXT_REPETITION_MIN_LENGTH; block2 <= maxBlock; block2++) {
86725
+ const unit = tail.slice(tail.length - block2);
86726
+ let repeats = 1;
86727
+ let offset = tail.length - block2 * 2;
86728
+ while (offset >= 0 && tail.slice(offset, offset + block2) === unit) {
86729
+ repeats++;
86730
+ offset -= block2;
86731
+ }
86732
+ if (repeats >= TEXT_REPETITION_MIN_REPEATS)
86733
+ return true;
86734
+ }
86735
+ return false;
86736
+ }
86737
+ function evaluateLoopBreak(stats) {
86738
+ const reasons = [];
86739
+ if (stats.consecutiveFailures >= CONSECUTIVE_FAILURE_LIMIT) {
86740
+ reasons.push(`${stats.consecutiveFailures} consecutive failed tool calls`);
86741
+ }
86742
+ if (stats.maxSignatureRepeats >= SIGNATURE_REPEAT_LIMIT) {
86743
+ reasons.push(`identical tool call repeated ${stats.maxSignatureRepeats}x`);
86744
+ }
86745
+ if (stats.maxSameFileEdits >= SAME_FILE_EDIT_LIMIT) {
86746
+ reasons.push(`${stats.maxSameFileEdits} edits to the same file`);
86747
+ }
86748
+ if (stats.textRepetitionDetected) {
86749
+ reasons.push("repeated output detected");
86750
+ }
86751
+ return { shouldBreak: reasons.length > 0, reasons };
86752
+ }
86753
+ function buildLoopBreakMessage(reasons) {
86754
+ const reasonText = reasons.length > 0 ? ` Triggered because: ${reasons.join(", ")}.` : "";
86755
+ return {
86756
+ role: "user",
86757
+ content: `${LOOP_BREAK_PROMPT}${reasonText}`
86758
+ };
86759
+ }
86760
+
86761
+ // ../cli/dist/core/regrounding.js
86762
+ init_esm_shims();
86763
+ function buildRegroundingMessage(originalRequest) {
86764
+ const trimmed = originalRequest.trim();
86765
+ const pin = trimmed.length > 0 ? `
86766
+
86767
+ The user's original request was:
86768
+
86769
+ ${trimmed}
86770
+
86771
+ ` : " The original request is in the earlier messages that remain. ";
86772
+ return {
86773
+ role: "user",
86774
+ content: "Re-ground. The conversation was just compacted, so earlier detail is now a summary and easy to drift from." + pin + "Before continuing, re-anchor on two things: that original request, and the specific objective you're working on right now. Verify your next step still serves the original ask \u2014 not a reshaped or narrowed version of it. If the summary dropped a constraint, file, or requirement you were tracking, recover it from the messages that remain before acting. Then continue. Do not restate this note; just proceed correctly."
86775
+ };
86776
+ }
86777
+
85714
86778
  // ../cli/dist/core/agent-session.js
85715
- import crypto8 from "crypto";
85716
- import fs29 from "fs/promises";
85717
- import path36 from "path";
86779
+ import crypto9 from "crypto";
86780
+ import fs30 from "fs/promises";
86781
+ import path38 from "path";
85718
86782
  var AgentSession = class {
85719
86783
  eventBus = new EventBus();
85720
86784
  slashCommands = new SlashCommandRegistry();
@@ -85724,8 +86788,44 @@ var AgentSession = class {
85724
86788
  extensionLoader = new ExtensionLoader();
85725
86789
  messages = [];
85726
86790
  tools = [];
86791
+ /** Rebuilds the read tool for a new model (video byte cap is baked in at
86792
+ * creation). Called from switchModel so video-capable models get the
86793
+ * read-tool's native-video path after a mid-session model change. */
86794
+ rebuildReadTool;
85727
86795
  skills = [];
85728
86796
  cacheKeyLogged = false;
86797
+ // ── Self-correction hook state (mirrors the TUI's useAgentLoop refs) ──
86798
+ // Reset at the start of every run; observed from the event stream; read by
86799
+ // the loop-break (mid-loop) and ideal-review (pre-stop) callbacks.
86800
+ hookStats = {
86801
+ changedLines: 0,
86802
+ toolCalls: 0,
86803
+ toolFailures: 0,
86804
+ turns: 0,
86805
+ writeCalls: 0,
86806
+ editCalls: 0,
86807
+ bashCalls: 0
86808
+ };
86809
+ hookText = "";
86810
+ hookConsecutiveFailures = 0;
86811
+ hookMaxSignatureRepeats = 0;
86812
+ hookMaxSameFileEdits = 0;
86813
+ hookSignatureCounts = /* @__PURE__ */ new Map();
86814
+ hookFileEditCounts = /* @__PURE__ */ new Map();
86815
+ hookToolCalls = /* @__PURE__ */ new Map();
86816
+ idealReviewInjected = false;
86817
+ loopBreakInjected = false;
86818
+ regroundingInjected = false;
86819
+ compactionOccurred = false;
86820
+ originalRequest = "";
86821
+ /** True after the cache has been pre-warmed for this session. Ensures we only
86822
+ * fire the warm-up call once (before the first real turn). */
86823
+ cachePrewarmed = false;
86824
+ // Messages queued by the user while a run is in flight. Drained at the
86825
+ // mid-loop steering boundary (user steering wins over the hooks), mirroring
86826
+ // the TUI's getSteeringMessages. Each entry carries its own attachments so a
86827
+ // user can queue media (images/video/files) mid-run, not just plain text.
86828
+ userQueue = [];
85729
86829
  processManager;
85730
86830
  lspManager;
85731
86831
  mcpManager;
@@ -85736,6 +86836,12 @@ var AgentSession = class {
85736
86836
  maxTokens;
85737
86837
  thinkingLevel;
85738
86838
  customSystemPrompt;
86839
+ /** Shared with the tool layer so plan-mode restrictions read live state. */
86840
+ planModeRef = { current: false };
86841
+ /** Path of the approved plan currently being implemented, or undefined. When
86842
+ * set, the system prompt carries the `[DONE:n]` progress contract so the
86843
+ * model emits step-completion markers the UI's plan-progress widget reads. */
86844
+ approvedPlanPath;
85739
86845
  sessionId = "";
85740
86846
  sessionPath = "";
85741
86847
  lastPersistedIndex = 0;
@@ -85748,10 +86854,25 @@ var AgentSession = class {
85748
86854
  this.model = options.model;
85749
86855
  this.cwd = options.cwd;
85750
86856
  this.baseUrl = options.baseUrl;
85751
- this.maxTokens = options.maxTokens ?? getModel(options.model)?.maxOutputTokens ?? 16384;
86857
+ this.maxTokens = this.resolveMaxTokens(options.model);
85752
86858
  this.thinkingLevel = options.thinkingLevel;
85753
86859
  this.customSystemPrompt = options.systemPrompt;
85754
86860
  }
86861
+ /**
86862
+ * Derive the output-token cap for a model. Follows the active model's
86863
+ * `maxOutputTokens` so a session booted on a large-output model (e.g. Kimi's
86864
+ * 256K) doesn't carry that cap to a smaller one (e.g. Opus's 128K) after a
86865
+ * model switch — that mismatch surfaces from the provider as
86866
+ * `max_tokens: 262144 > 128000, which is the maximum allowed …`. An explicit
86867
+ * `maxTokens` override is honored but clamped to the model's ceiling.
86868
+ */
86869
+ resolveMaxTokens(modelId) {
86870
+ const modelInfo = getModel(modelId);
86871
+ if (this.opts.maxTokens) {
86872
+ return modelInfo ? Math.min(this.opts.maxTokens, modelInfo.maxOutputTokens) : this.opts.maxTokens;
86873
+ }
86874
+ return modelInfo?.maxOutputTokens ?? 16384;
86875
+ }
85755
86876
  async initialize() {
85756
86877
  setEstimatorModel(this.model);
85757
86878
  const paths = await ensureAppDirs();
@@ -85760,10 +86881,10 @@ var AgentSession = class {
85760
86881
  this.authStorage = new AuthStorage(paths.authFile);
85761
86882
  await this.authStorage.load();
85762
86883
  this.sessionManager = new SessionManager(paths.sessionsDir);
85763
- const localEzDir = path36.join(this.cwd, ".ezcoder");
85764
- await fs29.mkdir(path36.join(localEzDir, "skills"), { recursive: true });
85765
- await fs29.mkdir(path36.join(localEzDir, "commands"), { recursive: true });
85766
- await fs29.mkdir(path36.join(localEzDir, "agents"), { recursive: true });
86884
+ const localEzDir = path38.join(this.cwd, ".ezcoder");
86885
+ await fs30.mkdir(path38.join(localEzDir, "skills"), { recursive: true });
86886
+ await fs30.mkdir(path38.join(localEzDir, "commands"), { recursive: true });
86887
+ await fs30.mkdir(path38.join(localEzDir, "agents"), { recursive: true });
85767
86888
  this.skills = await discoverSkills({
85768
86889
  globalSkillsDir: paths.skillsDir,
85769
86890
  projectDir: this.cwd
@@ -85772,33 +86893,35 @@ var AgentSession = class {
85772
86893
  globalAgentsDir: paths.agentsDir,
85773
86894
  projectDir: this.cwd
85774
86895
  });
85775
- const { tools, processManager, lspManager } = createTools(this.cwd, {
86896
+ const { tools, processManager, rebuildReadTool, lspManager } = await createTools(this.cwd, {
85776
86897
  agents,
85777
86898
  skills: this.skills,
85778
86899
  provider: this.provider,
85779
86900
  model: this.model,
85780
86901
  lspDiagnostics: this.settingsManager.get("lspDiagnostics"),
85781
- // Lazy — sessionId isn't assigned yet when createTools() runs, so we
85782
- // must defer reading the cache key until the sub-agent actually fires.
85783
- getCacheKey: () => this.getPromptCacheKey()
86902
+ authStorage: this.authStorage,
86903
+ // Lazy sessionId/model/provider can change after createTools() runs, so
86904
+ // sub-agent spawns read the current parent state at execution time.
86905
+ getProvider: () => this.provider,
86906
+ getModel: () => this.model,
86907
+ getCacheKey: () => this.getPromptCacheKey(),
86908
+ // Plan mode: only wired when the host supplies callbacks. The ref is
86909
+ // shared so bash/edit/write enforce read-only restrictions live.
86910
+ ...this.opts.onEnterPlan || this.opts.onExitPlan ? {
86911
+ planModeRef: this.planModeRef,
86912
+ onEnterPlan: this.opts.onEnterPlan,
86913
+ onExitPlan: this.opts.onExitPlan
86914
+ } : {}
85784
86915
  });
85785
86916
  this.tools = tools;
86917
+ this.rebuildReadTool = rebuildReadTool;
85786
86918
  this.processManager = processManager;
85787
86919
  this.lspManager = lspManager;
85788
86920
  this.mcpManager = new MCPClientManager();
85789
- try {
85790
- let apiKey;
85791
- if (this.provider === "glm") {
85792
- try {
85793
- const glmCreds = await this.authStorage.resolveCredentials("glm");
85794
- apiKey = glmCreds.accessToken;
85795
- } catch {
85796
- }
85797
- }
85798
- const mcpTools = await this.mcpManager.connectAll(getMCPServers(this.provider, apiKey));
85799
- this.tools.push(...mcpTools);
85800
- } catch (err) {
85801
- log("WARN", "mcp", `MCP initialization failed: ${err instanceof Error ? err.message : String(err)}`);
86921
+ if (this.opts.backgroundMcpConnect) {
86922
+ void this.connectMcpServers();
86923
+ } else {
86924
+ await this.connectMcpServers();
85802
86925
  }
85803
86926
  const basePrompt = this.customSystemPrompt ?? await buildSystemPrompt(this.cwd, this.skills, false, void 0, this.tools.map((tool) => tool.name), void 0, this.provider);
85804
86927
  this.messages = [{ role: "system", content: basePrompt }];
@@ -85855,6 +86978,36 @@ var AgentSession = class {
85855
86978
  await this.extensionLoader.loadAll(paths.extensionsDir, extContext);
85856
86979
  this.eventBus.emit("session_start", { sessionId: this.sessionId });
85857
86980
  }
86981
+ /**
86982
+ * Connect all configured MCP servers and append their tools to `this.tools`.
86983
+ * Resolves the GLM api key first (Z.AI's bundled servers need it). Never
86984
+ * throws — a failed connect is logged and skipped — so it is safe to either
86985
+ * `await` (CLI: tools ready before the first turn) or fire-and-forget
86986
+ * (sidecar: `backgroundMcpConnect`, so a slow stdio server can't stall
86987
+ * startup). Tools are pushed onto the live array the agent loop reads each
86988
+ * turn, so background-connected servers become available on the next prompt.
86989
+ */
86990
+ async connectMcpServers() {
86991
+ if (!this.mcpManager)
86992
+ return;
86993
+ try {
86994
+ let apiKey;
86995
+ if (this.provider === "glm") {
86996
+ try {
86997
+ const glmCreds = await this.authStorage.resolveCredentials("glm");
86998
+ apiKey = glmCreds.accessToken;
86999
+ } catch {
87000
+ }
87001
+ }
87002
+ const mcpTools = await this.mcpManager.connectAll(await getAllMcpServers(this.provider, apiKey, this.cwd));
87003
+ this.tools.push(...mcpTools);
87004
+ if (this.opts.backgroundMcpConnect && mcpTools.length > 0) {
87005
+ await this.rebuildSystemPromptInPlace();
87006
+ }
87007
+ } catch (err) {
87008
+ log("WARN", "mcp", `MCP initialization failed: ${err instanceof Error ? err.message : String(err)}`);
87009
+ }
87010
+ }
85858
87011
  /**
85859
87012
  * Process user input. Handles slash commands or runs agent loop.
85860
87013
  */
@@ -85891,6 +87044,208 @@ ${parsed.args}` : promptText;
85891
87044
  this.lastPersistedIndex = this.messages.length;
85892
87045
  await this.runLoop();
85893
87046
  }
87047
+ /**
87048
+ * Prompt with multimodal attachments (images / videos) alongside optional
87049
+ * text. Images and videos become native content blocks the model can see;
87050
+ * non-media files are surfaced as a text note with their saved path so the
87051
+ * agent can open them with its tools. Slash-command parsing is skipped —
87052
+ * attachments are always a direct conversational turn.
87053
+ */
87054
+ async promptWithAttachments(text, attachments) {
87055
+ const parts = this.buildAttachmentParts(text, attachments);
87056
+ if (parts.length === 0)
87057
+ return;
87058
+ const userMessage = { role: "user", content: parts };
87059
+ this.messages.push(userMessage);
87060
+ await this.persistMessage(userMessage);
87061
+ this.lastPersistedIndex = this.messages.length;
87062
+ await this.runLoop();
87063
+ }
87064
+ /**
87065
+ * Build the native content blocks (text + image/video notes + file notes) for
87066
+ * a user message with attachments. Shared by {@link promptWithAttachments} and
87067
+ * the mid-run steering drain so queued media is delivered identically.
87068
+ */
87069
+ buildAttachmentParts(text, attachments) {
87070
+ const parts = [];
87071
+ const fileNotes = [];
87072
+ const modelSupportsVideo = getModel(this.model)?.supportsVideo ?? false;
87073
+ for (const a of attachments) {
87074
+ if (a.kind === "image") {
87075
+ parts.push({ type: "image", mediaType: a.mediaType, data: a.data });
87076
+ if (a.path) {
87077
+ parts.push({ type: "text", text: `[Image saved at ${a.path}]` });
87078
+ }
87079
+ } else if (a.kind === "video") {
87080
+ if (modelSupportsVideo && a.path) {
87081
+ parts.push({
87082
+ type: "text",
87083
+ text: `The user attached a video at ${a.path}. You CAN watch it: call the read tool on this exact path now, then answer based on what you see. Do not say you cannot watch video \u2014 reading the file lets you analyze it.`
87084
+ });
87085
+ } else if (a.path) {
87086
+ parts.push({
87087
+ type: "text",
87088
+ text: `[User attached a video file at ${a.path}. You cannot watch video directly; if needed, use ffmpeg to extract frames or audio.]`
87089
+ });
87090
+ } else {
87091
+ parts.push({
87092
+ type: "text",
87093
+ text: `[User attached a video file but it could not be saved for analysis.]`
87094
+ });
87095
+ }
87096
+ } else if (a.path) {
87097
+ fileNotes.push(`- ${a.name} (saved at ${a.path})`);
87098
+ }
87099
+ }
87100
+ const textParts = [];
87101
+ if (text.trim())
87102
+ textParts.push(text.trim());
87103
+ if (fileNotes.length > 0) {
87104
+ textParts.push(`Attached files (inspect with your tools):
87105
+ ${fileNotes.join("\n")}`);
87106
+ }
87107
+ if (textParts.length > 0)
87108
+ parts.unshift({ type: "text", text: textParts.join("\n\n") });
87109
+ return parts;
87110
+ }
87111
+ /**
87112
+ * Reset per-run self-correction hook state. Mirrors the TUI's run_start
87113
+ * resets so each run evaluates the hooks from a clean slate. `originalRequest`
87114
+ * is the verbatim user ask, pinned for post-compaction re-grounding.
87115
+ */
87116
+ resetHookState(originalRequest) {
87117
+ this.hookStats = {
87118
+ changedLines: 0,
87119
+ toolCalls: 0,
87120
+ toolFailures: 0,
87121
+ turns: 0,
87122
+ writeCalls: 0,
87123
+ editCalls: 0,
87124
+ bashCalls: 0
87125
+ };
87126
+ this.hookText = "";
87127
+ this.hookConsecutiveFailures = 0;
87128
+ this.hookMaxSignatureRepeats = 0;
87129
+ this.hookMaxSameFileEdits = 0;
87130
+ this.hookSignatureCounts.clear();
87131
+ this.hookFileEditCounts.clear();
87132
+ this.hookToolCalls.clear();
87133
+ this.idealReviewInjected = false;
87134
+ this.loopBreakInjected = false;
87135
+ this.regroundingInjected = false;
87136
+ this.compactionOccurred = false;
87137
+ this.originalRequest = originalRequest;
87138
+ }
87139
+ /**
87140
+ * Fold one agent event into the hook stat accumulators. Pure bookkeeping —
87141
+ * the same signals the TUI's useAgentLoop collects, so the loop-break and
87142
+ * ideal-review decisions match across the CLI and the app.
87143
+ */
87144
+ trackHookEvent(event) {
87145
+ switch (event.type) {
87146
+ case "text_delta":
87147
+ this.hookText += event.text;
87148
+ break;
87149
+ case "tool_call_start":
87150
+ this.hookToolCalls.set(event.toolCallId, { name: event.name, args: event.args ?? {} });
87151
+ break;
87152
+ case "tool_call_end": {
87153
+ const call = this.hookToolCalls.get(event.toolCallId);
87154
+ const name = call?.name ?? "";
87155
+ const args = call?.args;
87156
+ this.hookStats.toolCalls += 1;
87157
+ if (event.isError)
87158
+ this.hookStats.toolFailures += 1;
87159
+ if (name === "write")
87160
+ this.hookStats.writeCalls += 1;
87161
+ if (name === "edit")
87162
+ this.hookStats.editCalls += 1;
87163
+ if (name === "bash")
87164
+ this.hookStats.bashCalls += 1;
87165
+ this.hookConsecutiveFailures = event.isError ? this.hookConsecutiveFailures + 1 : 0;
87166
+ const sig = toolCallSignature(name, args);
87167
+ const sigNext = (this.hookSignatureCounts.get(sig) ?? 0) + 1;
87168
+ this.hookSignatureCounts.set(sig, sigNext);
87169
+ if (sigNext > this.hookMaxSignatureRepeats)
87170
+ this.hookMaxSignatureRepeats = sigNext;
87171
+ if ((name === "edit" || name === "write") && args) {
87172
+ const filePath = args.file_path;
87173
+ if (typeof filePath === "string") {
87174
+ const fileNext = (this.hookFileEditCounts.get(filePath) ?? 0) + 1;
87175
+ this.hookFileEditCounts.set(filePath, fileNext);
87176
+ if (fileNext > this.hookMaxSameFileEdits)
87177
+ this.hookMaxSameFileEdits = fileNext;
87178
+ }
87179
+ }
87180
+ if (name === "edit" && !event.isError) {
87181
+ const diff3 = event.details?.diff ?? event.result;
87182
+ const added = (diff3.match(/^\+[^+]/gm) ?? []).length;
87183
+ const removed = (diff3.match(/^-[^-]/gm) ?? []).length;
87184
+ this.hookStats.changedLines += added + removed;
87185
+ }
87186
+ break;
87187
+ }
87188
+ case "turn_end":
87189
+ this.hookStats.turns = event.turn;
87190
+ break;
87191
+ }
87192
+ }
87193
+ /**
87194
+ * Mid-loop steering hook: fires the loop-breaker when the agent looks stuck,
87195
+ * then post-compaction re-grounding. At most one of each per run. Mirrors the
87196
+ * TUI's getSteeringMessages ordering (minus user steering, which the app
87197
+ * delivers as normal prompts).
87198
+ */
87199
+ getHookSteeringMessages() {
87200
+ if (this.userQueue.length > 0) {
87201
+ const queued = this.userQueue.splice(0);
87202
+ if (queued.every((m) => m.attachments.length === 0)) {
87203
+ const merged = queued.map((m) => m.text).join("\n\n");
87204
+ return [{ role: "user", content: merged }];
87205
+ }
87206
+ const parts = [];
87207
+ for (const m of queued)
87208
+ parts.push(...this.buildAttachmentParts(m.text, m.attachments));
87209
+ return [{ role: "user", content: parts }];
87210
+ }
87211
+ if (!this.settingsManager.get("idealReviewEnabled"))
87212
+ return null;
87213
+ if (!this.loopBreakInjected) {
87214
+ const decision = evaluateLoopBreak({
87215
+ consecutiveFailures: this.hookConsecutiveFailures,
87216
+ maxSignatureRepeats: this.hookMaxSignatureRepeats,
87217
+ maxSameFileEdits: this.hookMaxSameFileEdits,
87218
+ textRepetitionDetected: detectTextRepetition(this.hookText)
87219
+ });
87220
+ if (decision.shouldBreak) {
87221
+ this.loopBreakInjected = true;
87222
+ this.eventBus.emit("hook", { kind: "loop_break" });
87223
+ return [buildLoopBreakMessage(decision.reasons)];
87224
+ }
87225
+ }
87226
+ if (!this.regroundingInjected && this.compactionOccurred) {
87227
+ this.regroundingInjected = true;
87228
+ this.eventBus.emit("hook", { kind: "regrounding" });
87229
+ return [buildRegroundingMessage(this.originalRequest)];
87230
+ }
87231
+ return null;
87232
+ }
87233
+ /**
87234
+ * Pre-stop follow-up hook: runs the ideal review once, when the agent would
87235
+ * otherwise finish and the change set is substantial enough to warrant it.
87236
+ */
87237
+ getHookFollowUpMessages() {
87238
+ if (!this.settingsManager.get("idealReviewEnabled"))
87239
+ return null;
87240
+ if (this.idealReviewInjected)
87241
+ return null;
87242
+ const decision = evaluateIdealReview(this.hookStats);
87243
+ if (!decision.shouldReview)
87244
+ return null;
87245
+ this.idealReviewInjected = true;
87246
+ this.eventBus.emit("hook", { kind: "ideal" });
87247
+ return [buildIdealReviewMessage(decision.reasons)];
87248
+ }
85894
87249
  /** Auto-compact if needed, run agent loop with auth retry, and persist messages. */
85895
87250
  async runLoop() {
85896
87251
  if (!this.cacheKeyLogged) {
@@ -85902,6 +87257,9 @@ ${parsed.args}` : promptText;
85902
87257
  transient: String(!!this.opts.transient)
85903
87258
  });
85904
87259
  }
87260
+ const lastUser = [...this.messages].reverse().find((m) => m.role === "user");
87261
+ const originalRequest = typeof lastUser?.content === "string" ? lastUser.content : "";
87262
+ this.resetHookState(originalRequest);
85905
87263
  let creds = await this.authStorage.resolveCredentials(this.provider);
85906
87264
  if (this.settingsManager.get("autoCompact")) {
85907
87265
  const contextWindow = getContextWindow(this.model, {
@@ -85911,6 +87269,7 @@ ${parsed.args}` : promptText;
85911
87269
  const threshold = this.settingsManager.get("compactThreshold");
85912
87270
  if (shouldCompact(this.messages, contextWindow, threshold)) {
85913
87271
  await this.compact(creds);
87272
+ this.compactionOccurred = true;
85914
87273
  }
85915
87274
  }
85916
87275
  const userAgent = this.provider === "anthropic" ? await getClaudeCliUserAgent() : void 0;
@@ -85933,20 +87292,28 @@ ${parsed.args}` : promptText;
85933
87292
  // Kimi For Coding gates the managed endpoint on coding-agent identity
85934
87293
  // headers; attach them only when the Kimi OAuth token is in use.
85935
87294
  defaultHeaders: this.provider === "moonshot" && isKimiCodingEndpoint(effectiveBaseUrl) ? kimiCodingHeaders() : void 0,
85936
- cacheRetention: "short",
87295
+ // speedProfile "optimized": 1-h cache TTL (survives turns >5 min apart)
87296
+ // + pre-warm before the first turn. "baseline": current 5-min default.
87297
+ cacheRetention: this.isSpeedOptimized() ? "long" : "short",
85937
87298
  promptCacheKey: this.getPromptCacheKey(),
85938
87299
  supportsImages: modelInfo?.supportsImages,
85939
87300
  supportsVideo: modelInfo?.supportsVideo,
85940
87301
  userAgent,
85941
87302
  // clearToolUses disabled — causes model to output unsolicited context summaries
85942
87303
  // Single tool result shouldn't exceed 30% of context window (in chars)
85943
- maxToolResultChars: Math.floor(getContextWindow(this.model, { provider: this.provider, accountId }) * 3.5 * 0.3)
87304
+ maxToolResultChars: Math.floor(getContextWindow(this.model, { provider: this.provider, accountId }) * 3.5 * 0.3),
87305
+ // Self-correction hooks (same as the TUI): loop-break + re-grounding are
87306
+ // polled mid-loop; the ideal review is polled when the agent would stop.
87307
+ getSteeringMessages: () => this.getHookSteeringMessages(),
87308
+ getFollowUpMessages: () => this.getHookFollowUpMessages()
85944
87309
  });
85945
87310
  for await (const event of generator) {
87311
+ this.trackHookEvent(event);
85946
87312
  this.eventBus.forwardAgentEvent(event);
85947
87313
  }
85948
87314
  };
85949
87315
  try {
87316
+ await this.maybePrewarmCache(creds);
85950
87317
  await runAgentLoop(creds.accessToken, creds.accountId, creds.projectId);
85951
87318
  } catch (err) {
85952
87319
  if (isAbortError4(err) || this.opts.signal?.aborted) {
@@ -85977,7 +87344,16 @@ ${parsed.args}` : promptText;
85977
87344
  this.provider = provider;
85978
87345
  this.model = model;
85979
87346
  setEstimatorModel(model);
85980
- this.eventBus.emit("model_change", { provider: this.provider, model: this.model });
87347
+ this.maxTokens = this.resolveMaxTokens(model);
87348
+ this.eventBus.emit("model_change", {
87349
+ provider: this.provider,
87350
+ model: this.model,
87351
+ supportsVideo: getModel(this.model)?.supportsVideo ?? false
87352
+ });
87353
+ if (this.rebuildReadTool) {
87354
+ const newReadTool = this.rebuildReadTool(model);
87355
+ this.tools = this.tools.map((t) => t.name === "read" ? newReadTool : t);
87356
+ }
85981
87357
  if (provider && provider !== prevProvider) {
85982
87358
  const hasWebSearch = this.tools.some((t) => t.name === "web_search");
85983
87359
  if (this.provider === "anthropic" && hasWebSearch) {
@@ -86040,6 +87416,8 @@ ${parsed.args}` : promptText;
86040
87416
  });
86041
87417
  }
86042
87418
  async newSession() {
87419
+ this.planModeRef.current = false;
87420
+ this.approvedPlanPath = void 0;
86043
87421
  const basePrompt = this.customSystemPrompt ?? await buildSystemPrompt(this.cwd, this.skills, false, void 0, this.tools.map((tool) => tool.name), void 0, this.provider);
86044
87422
  this.messages = [{ role: "system", content: basePrompt }];
86045
87423
  await this.createNewSession();
@@ -86094,16 +87472,151 @@ ${parsed.args}` : promptText;
86094
87472
  cwd: this.cwd,
86095
87473
  sessionId: this.sessionId,
86096
87474
  sessionPath: this.sessionPath,
86097
- messageCount: this.messages.length
87475
+ messageCount: this.messages.length,
87476
+ planMode: this.planModeRef.current
86098
87477
  };
86099
87478
  }
87479
+ getPlanMode() {
87480
+ return this.planModeRef.current;
87481
+ }
87482
+ /** Queue a user message (optionally with attachments) to be injected mid-run
87483
+ * as steering. Returns the new queue length. No-op semantics are the caller's
87484
+ * concern. */
87485
+ queueMessage(text, attachments = []) {
87486
+ this.userQueue.push({ text, attachments });
87487
+ return this.userQueue.length;
87488
+ }
87489
+ /** Number of messages currently queued. */
87490
+ getQueuedCount() {
87491
+ return this.userQueue.length;
87492
+ }
87493
+ /** Clear the queue, returning the combined text (to restore to the composer).
87494
+ * Queued attachments are dropped on cancel — the composer only restores text. */
87495
+ drainQueue() {
87496
+ return this.userQueue.splice(0).map((m) => m.text).join("\n\n");
87497
+ }
87498
+ /** Snapshot of background processes (bash run_in_background), newest-state. */
87499
+ listBackgroundProcesses() {
87500
+ return this.processManager?.list() ?? [];
87501
+ }
87502
+ /** Stop a background process by id. Returns a human-readable status string. */
87503
+ async killBackgroundProcess(id2) {
87504
+ if (!this.processManager)
87505
+ return `No background process with id "${id2}"`;
87506
+ return this.processManager.stop(id2);
87507
+ }
87508
+ /**
87509
+ * Toggle plan mode: flips the shared ref (so tools enforce read-only
87510
+ * restrictions) and rebuilds the system prompt in place so the model is told
87511
+ * about the mode change on its next turn. No-op when a custom system prompt
87512
+ * is in force (the host owns the prompt then).
87513
+ */
87514
+ async setPlanMode(active) {
87515
+ this.planModeRef.current = active;
87516
+ if (active)
87517
+ this.approvedPlanPath = void 0;
87518
+ await this.rebuildSystemPromptInPlace();
87519
+ }
87520
+ /**
87521
+ * Bake an approved plan into the system prompt so the model is told to emit
87522
+ * `[DONE:n]` markers as it completes each step (the contract the UI's
87523
+ * plan-progress widget reads). Pass `undefined` to clear it. No-op when a
87524
+ * custom system prompt is in force (the host owns the prompt then).
87525
+ */
87526
+ async setApprovedPlan(approvedPlanPath) {
87527
+ this.approvedPlanPath = approvedPlanPath;
87528
+ await this.rebuildSystemPromptInPlace();
87529
+ }
87530
+ /** Rebuild messages[0] from current plan-mode + approved-plan state. */
87531
+ async rebuildSystemPromptInPlace() {
87532
+ if (this.customSystemPrompt)
87533
+ return;
87534
+ const rebuilt = await buildSystemPrompt(this.cwd, this.skills, this.planModeRef.current, this.approvedPlanPath, this.tools.map((tool) => tool.name), void 0, this.provider);
87535
+ if (this.messages[0]?.role === "system") {
87536
+ this.messages[0] = { role: "system", content: rebuilt };
87537
+ } else {
87538
+ this.messages.unshift({ role: "system", content: rebuilt });
87539
+ }
87540
+ }
86100
87541
  getMessages() {
86101
87542
  return this.messages;
86102
87543
  }
87544
+ /**
87545
+ * Generate a short LLM session title from the conversation so far (first user
87546
+ * message + first assistant reply). Best-effort; returns null on failure or
87547
+ * when there's no user message yet. Uses the cheapest model for the provider.
87548
+ */
87549
+ async generateTitle() {
87550
+ const extractText = (content) => typeof content === "string" ? content : content.map((c2) => c2.type === "text" && "text" in c2 && typeof c2.text === "string" ? c2.text : "").join(" ");
87551
+ const userMsg = this.messages.find((m) => m.role === "user");
87552
+ const assistantMsg = this.messages.find((m) => m.role === "assistant");
87553
+ const userText = userMsg ? extractText(userMsg.content) : "";
87554
+ if (!userText.trim())
87555
+ return null;
87556
+ try {
87557
+ const creds = await this.authStorage.resolveCredentials(this.provider);
87558
+ const title = await generateSessionTitle({
87559
+ provider: this.provider,
87560
+ userMessage: userText,
87561
+ assistantPreview: assistantMsg ? extractText(assistantMsg.content).slice(0, 200) : "",
87562
+ apiKey: creds.accessToken,
87563
+ baseUrl: this.baseUrl ?? creds.baseUrl,
87564
+ accountId: creds.accountId
87565
+ });
87566
+ return title || null;
87567
+ } catch {
87568
+ return null;
87569
+ }
87570
+ }
87571
+ /** Current reasoning/thinking level, or undefined when thinking is off. */
87572
+ getThinkingLevel() {
87573
+ return this.thinkingLevel;
87574
+ }
87575
+ /** Set the reasoning/thinking level (undefined turns thinking off). Takes
87576
+ * effect on the next prompt, since the in-flight loop reads it at start. */
87577
+ setThinkingLevel(level) {
87578
+ this.thinkingLevel = level;
87579
+ }
86103
87580
  /** Replace the abort signal (e.g. after cancellation). */
86104
87581
  setSignal(signal) {
86105
87582
  this.opts = { ...this.opts, signal };
86106
87583
  }
87584
+ /** True when speedProfile is "optimized" (1-h cache TTL + pre-warm). */
87585
+ isSpeedOptimized() {
87586
+ return this.settingsManager?.get("speedProfile") === "optimized";
87587
+ }
87588
+ /** Fire a cache pre-warm request for Anthropic so the first real turn is a
87589
+ * cache read instead of a cold write. No-op for other providers and when
87590
+ * speedProfile is not "optimized". Entirely best-effort — any failure is
87591
+ * swallowed so prewarm never blocks or aborts the real prompt. */
87592
+ async maybePrewarmCache(creds) {
87593
+ if (this.cachePrewarmed || !this.isSpeedOptimized() || this.provider !== "anthropic") {
87594
+ return;
87595
+ }
87596
+ this.cachePrewarmed = true;
87597
+ try {
87598
+ const userAgent = await getClaudeCliUserAgent();
87599
+ const systemText = typeof this.messages[0]?.content === "string" ? this.messages[0].content : "";
87600
+ if (!systemText)
87601
+ return;
87602
+ await prewarmAnthropicCache({
87603
+ apiKey: creds.accessToken,
87604
+ model: this.model,
87605
+ system: systemText,
87606
+ tools: this.tools.map((t) => ({
87607
+ name: t.name,
87608
+ description: t.description,
87609
+ parameters: t.parameters,
87610
+ ...t.rawInputSchema ? { rawInputSchema: t.rawInputSchema } : {}
87611
+ })),
87612
+ baseUrl: this.baseUrl ?? creds.baseUrl,
87613
+ userAgent,
87614
+ cacheRetention: "long",
87615
+ signal: this.opts.signal
87616
+ });
87617
+ } catch {
87618
+ }
87619
+ }
86107
87620
  getPromptCacheKey() {
86108
87621
  if (this.opts.promptCacheKey)
86109
87622
  return this.opts.promptCacheKey;
@@ -86176,7 +87689,7 @@ ${parsed.args}` : promptText;
86176
87689
  async persistMessage(message) {
86177
87690
  if (!this.sessionPath)
86178
87691
  return;
86179
- const entryId = crypto8.randomUUID();
87692
+ const entryId = crypto9.randomUUID();
86180
87693
  const entry = {
86181
87694
  type: "message",
86182
87695
  id: entryId,
@@ -87045,7 +88558,7 @@ import process14 from "process";
87045
88558
  init_esm_shims();
87046
88559
  var import_react15 = __toESM(require_react(), 1);
87047
88560
  import process13 from "process";
87048
- import fs32 from "fs";
88561
+ import fs33 from "fs";
87049
88562
 
87050
88563
  // ../../node_modules/.pnpm/es-toolkit@1.46.1/node_modules/es-toolkit/dist/compat/index.mjs
87051
88564
  init_esm_shims();
@@ -89238,7 +90751,7 @@ function wrapAnsi2(string4, columns, options) {
89238
90751
  init_esm_shims();
89239
90752
  import process5 from "process";
89240
90753
  import { execFileSync as execFileSync2 } from "child_process";
89241
- import fs30 from "fs";
90754
+ import fs31 from "fs";
89242
90755
  import tty from "tty";
89243
90756
  var defaultColumns = 80;
89244
90757
  var defaultRows = 24;
@@ -89268,7 +90781,7 @@ var isForegroundProcess = () => {
89268
90781
  return true;
89269
90782
  }
89270
90783
  try {
89271
- const statContents = fs30.readFileSync("/proc/self/stat", "utf8");
90784
+ const statContents = fs31.readFileSync("/proc/self/stat", "utf8");
89272
90785
  const closingParenthesisIndex = statContents.lastIndexOf(") ");
89273
90786
  if (closingParenthesisIndex === -1) {
89274
90787
  return false;
@@ -89312,8 +90825,8 @@ function terminalSize() {
89312
90825
  }
89313
90826
  var devTty = () => {
89314
90827
  try {
89315
- const flags = process5.platform === "darwin" ? fs30.constants.O_EVTONLY | fs30.constants.O_NONBLOCK : fs30.constants.O_NONBLOCK;
89316
- const { columns, rows } = tty.WriteStream(fs30.openSync("/dev/tty", flags));
90828
+ const flags = process5.platform === "darwin" ? fs31.constants.O_EVTONLY | fs31.constants.O_NONBLOCK : fs31.constants.O_NONBLOCK;
90829
+ const { columns, rows } = tty.WriteStream(fs31.openSync("/dev/tty", flags));
89317
90830
  return { columns, rows };
89318
90831
  } catch {
89319
90832
  }
@@ -91125,8 +92638,8 @@ var cleanupYogaNode = (node) => {
91125
92638
  var currentUpdatePriority = import_constants3.NoEventPriority;
91126
92639
  var currentRootNode;
91127
92640
  async function loadPackageJson() {
91128
- const fs38 = await import("fs");
91129
- const content = fs38.readFileSync(new URL("../package.json", import.meta.url), "utf8");
92641
+ const fs40 = await import("fs");
92642
+ const content = fs40.readFileSync(new URL("../package.json", import.meta.url), "utf8");
91130
92643
  return JSON.parse(content);
91131
92644
  }
91132
92645
  var packageJson = isDev() ? await loadPackageJson() : { name: void 0, version: void 0 };
@@ -92688,7 +94201,7 @@ var import_react13 = __toESM(require_react(), 1);
92688
94201
  init_esm_shims();
92689
94202
  var import_react12 = __toESM(require_react(), 1);
92690
94203
  var import_stack_utils = __toESM(require_stack_utils(), 1);
92691
- import * as fs31 from "fs";
94204
+ import * as fs32 from "fs";
92692
94205
  import { cwd } from "process";
92693
94206
 
92694
94207
  // ../../node_modules/.pnpm/code-excerpt@4.0.0/node_modules/code-excerpt/dist/index.js
@@ -92816,8 +94329,8 @@ function Text({ color: color2, backgroundColor, dimColor = false, bold = false,
92816
94329
  }
92817
94330
 
92818
94331
  // ../../node_modules/.pnpm/ink@6.8.0_patch_hash=6c70099ec5b01a8329f3b7bd932ceef28779e4c7f5795e7ff44fa28c2f9d6782_@types+react@19.2.15_react@19.2.6/node_modules/ink/build/components/ErrorOverview.js
92819
- var cleanupPath = (path46) => {
92820
- return path46?.replace(`file://${cwd()}/`, "");
94332
+ var cleanupPath = (path49) => {
94333
+ return path49?.replace(`file://${cwd()}/`, "");
92821
94334
  };
92822
94335
  var stackUtils = new import_stack_utils.default({
92823
94336
  cwd: cwd(),
@@ -92829,8 +94342,8 @@ function ErrorOverview({ error: error51 }) {
92829
94342
  const filePath = cleanupPath(origin?.file);
92830
94343
  let excerpt;
92831
94344
  let lineWidth = 0;
92832
- if (filePath && origin?.line && fs31.existsSync(filePath)) {
92833
- const sourceCode = fs31.readFileSync(filePath, "utf8");
94345
+ if (filePath && origin?.line && fs32.existsSync(filePath)) {
94346
+ const sourceCode = fs32.readFileSync(filePath, "utf8");
92834
94347
  excerpt = dist_default3(sourceCode, origin.line);
92835
94348
  if (excerpt) {
92836
94349
  for (const { line } of excerpt) {
@@ -93649,7 +95162,7 @@ var Ink = class {
93649
95162
  }
93650
95163
  if (process13.env["GG_INK_DEBUG"] === "1" && (delta !== 0 || this.framePadDebt > 0)) {
93651
95164
  try {
93652
- fs32.appendFileSync("/tmp/gg-ink-debug.log", JSON.stringify({
95165
+ fs33.appendFileSync("/tmp/gg-ink-debug.log", JSON.stringify({
93653
95166
  t: Date.now() % 1e5,
93654
95167
  delta,
93655
95168
  ins: insertLineCount,
@@ -95371,7 +96884,7 @@ var import_react37 = __toESM(require_react(), 1);
95371
96884
 
95372
96885
  // ../cli/dist/core/session-compaction.js
95373
96886
  init_esm_shims();
95374
- import crypto9 from "crypto";
96887
+ import crypto10 from "crypto";
95375
96888
 
95376
96889
  // ../cli/dist/ui/hooks/useContextCompaction.js
95377
96890
  init_esm_shims();
@@ -95485,18 +96998,15 @@ var taskBarStore = createStore({
95485
96998
  // ../cli/dist/utils/sound.js
95486
96999
  init_esm_shims();
95487
97000
  import { execFile as execFile2 } from "child_process";
95488
- import { fileURLToPath as fileURLToPath3 } from "url";
97001
+ import { fileURLToPath as fileURLToPath4 } from "url";
95489
97002
  import { resolve as resolve2, dirname } from "path";
95490
- var __dirname2 = dirname(fileURLToPath3(import.meta.url));
97003
+ var __dirname2 = dirname(fileURLToPath4(import.meta.url));
95491
97004
  var notificationPath = resolve2(__dirname2, "../../assets/end-notification.mp3");
95492
97005
 
95493
97006
  // ../cli/dist/ui/hooks/useAgentLoop.js
95494
97007
  init_esm_shims();
95495
97008
  var import_react43 = __toESM(require_react(), 1);
95496
97009
 
95497
- // ../cli/dist/core/loop-breaker.js
95498
- init_esm_shims();
95499
-
95500
97010
  // ../cli/dist/ui/hooks/useTranscriptHistory.js
95501
97011
  init_esm_shims();
95502
97012
  var import_react44 = __toESM(require_react(), 1);
@@ -96105,8 +97615,8 @@ function shortenValue(value, maxLength = MAX_DETAIL_LENGTH) {
96105
97615
  const tailLength = maxLength - 1 - headLength;
96106
97616
  return `${normalized.slice(0, headLength)}\u2026${normalized.slice(-tailLength)}`;
96107
97617
  }
96108
- function basename3(path46) {
96109
- const trimmed = path46.replace(/\/+$/u, "");
97618
+ function basename3(path49) {
97619
+ const trimmed = path49.replace(/\/+$/u, "");
96110
97620
  return trimmed.split("/").filter(Boolean).at(-1) ?? trimmed;
96111
97621
  }
96112
97622
  function uniqueValues(values) {
@@ -109900,8 +111410,8 @@ function ok() {
109900
111410
 
109901
111411
  // ../../node_modules/.pnpm/highlight.js@11.11.1/node_modules/highlight.js/es/core.js
109902
111412
  init_esm_shims();
109903
- var import_core19 = __toESM(require_core3(), 1);
109904
- var core_default = import_core19.default;
111413
+ var import_core20 = __toESM(require_core3(), 1);
111414
+ var core_default = import_core20.default;
109905
111415
 
109906
111416
  // ../../node_modules/.pnpm/lowlight@3.3.0/node_modules/lowlight/lib/index.js
109907
111417
  var emptyOptions = {};
@@ -111089,7 +112599,7 @@ function collapseSubmittedUserText(text) {
111089
112599
  }
111090
112600
 
111091
112601
  // ../cli/dist/ui/terminal-history.js
111092
- import path37 from "path";
112602
+ import path39 from "path";
111093
112603
  import { pathToFileURL as pathToFileURL2 } from "url";
111094
112604
 
111095
112605
  // ../cli/dist/ui/utils/terminal-graphics.js
@@ -112135,7 +113645,7 @@ function TaskPickerMenu({ tasks, selectedIndex, width }) {
112135
113645
  // ../cli/dist/ui/components/InputArea.js
112136
113646
  import { homedir as homedir3 } from "os";
112137
113647
  import { join as join3 } from "path";
112138
- import { readFileSync as readFileSync5, writeFileSync as writeFileSync3, appendFileSync, mkdirSync as mkdirSync3, renameSync, unlinkSync, existsSync as existsSync5 } from "fs";
113648
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync3, appendFileSync, mkdirSync as mkdirSync3, renameSync, unlinkSync, existsSync as existsSync7 } from "fs";
112139
113649
  var MAX_VISIBLE_LINES = 12;
112140
113650
  var PROMPT = "> ";
112141
113651
  var PLACEHOLDER = " Type your message or / to run a command";
@@ -112275,7 +113785,7 @@ function compactHistory2() {
112275
113785
  lineCountEstimate = trimmed.length;
112276
113786
  } catch {
112277
113787
  try {
112278
- if (existsSync5(tempPath))
113788
+ if (existsSync7(tempPath))
112279
113789
  unlinkSync(tempPath);
112280
113790
  } catch {
112281
113791
  }
@@ -113414,7 +114924,7 @@ var import_react69 = __toESM(require_react(), 1);
113414
114924
 
113415
114925
  // ../cli/dist/ui/pixel.js
113416
114926
  init_esm_shims();
113417
- import { existsSync as existsSync6, readFileSync as readFileSync7 } from "fs";
114927
+ import { existsSync as existsSync8, readFileSync as readFileSync7 } from "fs";
113418
114928
  import { homedir as homedir4 } from "os";
113419
114929
  import { join as join5 } from "path";
113420
114930
 
@@ -113423,9 +114933,9 @@ init_esm_shims();
113423
114933
  import { execFile as execFile3 } from "child_process";
113424
114934
  import { readFileSync as readFileSync6 } from "fs";
113425
114935
  import { dirname as dirname2, join as join4 } from "path";
113426
- import { fileURLToPath as fileURLToPath4 } from "url";
114936
+ import { fileURLToPath as fileURLToPath5 } from "url";
113427
114937
  function resolveCliVersion() {
113428
- let dir = dirname2(fileURLToPath4(import.meta.url));
114938
+ let dir = dirname2(fileURLToPath5(import.meta.url));
113429
114939
  for (let i = 0; i < 6; i++) {
113430
114940
  try {
113431
114941
  const manifest = JSON.parse(readFileSync6(join4(dir, "package.json"), "utf8"));
@@ -113454,7 +114964,7 @@ function visualWidth2(str2) {
113454
114964
  }
113455
114965
 
113456
114966
  // ../cli/dist/ui/components/PlanOverlay.js
113457
- import { readdir as readdir2, readFile as readFile3, unlink } from "fs/promises";
114967
+ import { readdir as readdir2, readFile as readFile4, unlink } from "fs/promises";
113458
114968
  import { join as join6 } from "path";
113459
114969
  var PLAN_LOGO = [
113460
114970
  " \u2588\u2580\u2580\u2580 \u2580\u2580\u2580\u2588",
@@ -113491,26 +115001,23 @@ import { execFile as execFile4 } from "child_process";
113491
115001
 
113492
115002
  // ../cli/dist/core/auto-update.js
113493
115003
  init_esm_shims();
113494
- import path38 from "path";
115004
+ import path40 from "path";
113495
115005
  import os10 from "os";
113496
115006
  var updater = createAutoUpdater({
113497
115007
  packageName: "@prestyj/cli",
113498
- stateFilePath: () => path38.join(os10.homedir(), ".ezcoder", "update-state.json")
115008
+ stateFilePath: () => path40.join(os10.homedir(), ".ezcoder", "update-state.json")
113499
115009
  });
113500
115010
  var checkAndAutoUpdate = updater.checkAndAutoUpdate;
113501
115011
  var getPendingUpdate = updater.getPendingUpdate;
113502
115012
  var startPeriodicUpdateCheck = updater.startPeriodicUpdateCheck;
113503
115013
  var stopPeriodicUpdateCheck = updater.stopPeriodicUpdateCheck;
113504
115014
 
113505
- // ../cli/dist/utils/session-title.js
113506
- init_esm_shims();
113507
-
113508
115015
  // ../cli/dist/core/setup-history.js
113509
115016
  init_esm_shims();
113510
- import fs33 from "fs";
113511
- import path39 from "path";
115017
+ import fs34 from "fs";
115018
+ import path41 from "path";
113512
115019
  import os11 from "os";
113513
- var HISTORY_PATH = path39.join(os11.homedir(), ".ezcoder", "setup-history.json");
115020
+ var HISTORY_PATH = path41.join(os11.homedir(), ".ezcoder", "setup-history.json");
113514
115021
 
113515
115022
  // ../cli/dist/ui/components/RewindOverlay.js
113516
115023
  init_esm_shims();
@@ -113535,12 +115042,6 @@ init_esm_shims();
113535
115042
  // ../cli/dist/ui/submit-slash-commands.js
113536
115043
  init_esm_shims();
113537
115044
 
113538
- // ../cli/dist/core/ideal-review.js
113539
- init_esm_shims();
113540
-
113541
- // ../cli/dist/core/regrounding.js
113542
- init_esm_shims();
113543
-
113544
115045
  // ../cli/dist/ui/thinking-level.js
113545
115046
  init_esm_shims();
113546
115047
 
@@ -113760,7 +115261,7 @@ function MessageResponse({ children, height, accentColor }) {
113760
115261
 
113761
115262
  // ../cli/dist/ui/utils/highlight.js
113762
115263
  init_esm_shims();
113763
- import path40 from "path";
115264
+ import path43 from "path";
113764
115265
  var EXT_TO_LANG = {
113765
115266
  ts: "typescript",
113766
115267
  tsx: "typescript",
@@ -113788,7 +115289,7 @@ var EXT_TO_LANG = {
113788
115289
  dockerfile: "dockerfile"
113789
115290
  };
113790
115291
  function langFromPath(filePath) {
113791
- const ext = path40.extname(filePath).replace(/^\./, "").toLowerCase();
115292
+ const ext = path43.extname(filePath).replace(/^\./, "").toLowerCase();
113792
115293
  return EXT_TO_LANG[ext];
113793
115294
  }
113794
115295
  var hlModule;
@@ -114588,7 +116089,7 @@ init_esm_shims();
114588
116089
  // ../cli/dist/core/goal-verifier.js
114589
116090
  init_esm_shims();
114590
116091
  import { spawn as spawn9 } from "child_process";
114591
- import { mkdir as mkdir4, writeFile as writeFile4 } from "fs/promises";
116092
+ import { mkdir as mkdir5, writeFile as writeFile5 } from "fs/promises";
114592
116093
  import { join as join7 } from "path";
114593
116094
  var DEFAULT_GOAL_VERIFIER_TIMEOUT_MS = 10 * 60 * 1e3;
114594
116095
 
@@ -114596,8 +116097,8 @@ var DEFAULT_GOAL_VERIFIER_TIMEOUT_MS = 10 * 60 * 1e3;
114596
116097
  init_esm_shims();
114597
116098
  import { spawn as spawn10 } from "child_process";
114598
116099
  import { createInterface as createInterface3 } from "readline";
114599
- import { createWriteStream, existsSync as existsSync7 } from "fs";
114600
- import { mkdir as mkdir5 } from "fs/promises";
116100
+ import { createWriteStream, existsSync as existsSync9 } from "fs";
116101
+ import { mkdir as mkdir6 } from "fs/promises";
114601
116102
  import { join as join8 } from "path";
114602
116103
  import { randomUUID as randomUUID5 } from "crypto";
114603
116104
  var DEFAULT_GOAL_WORKER_TIMEOUT_MS = 30 * 60 * 1e3;
@@ -114654,6 +116155,276 @@ var DISABLE_MODIFY_OTHER_KEYS = "\x1B[>4;0m";
114654
116155
  var SCREEN_CLEAR = DISABLE_MODIFY_OTHER_KEYS + "\x1B[2J\x1B[3J\x1B[H";
114655
116156
  var VIEWPORT_CLEAR = DISABLE_MODIFY_OTHER_KEYS + "\x1B[2J\x1B[H";
114656
116157
 
116158
+ // ../cli/dist/core/project-discovery.js
116159
+ init_esm_shims();
116160
+ import fs35 from "fs/promises";
116161
+ import { createReadStream as createReadStream3 } from "fs";
116162
+ import readline3 from "readline";
116163
+ import os12 from "os";
116164
+ import path44 from "path";
116165
+ async function discoverProjects() {
116166
+ const [gg, cc, cx] = await Promise.all([
116167
+ discoverGgcoderProjects(),
116168
+ discoverClaudeProjects(),
116169
+ discoverCodexProjects()
116170
+ ]);
116171
+ const byPath = /* @__PURE__ */ new Map();
116172
+ for (const p of [...gg, ...cc, ...cx]) {
116173
+ const existing = byPath.get(p.path);
116174
+ if (!existing) {
116175
+ byPath.set(p.path, p);
116176
+ continue;
116177
+ }
116178
+ byPath.set(p.path, {
116179
+ name: existing.name,
116180
+ path: existing.path,
116181
+ lastActiveMs: Math.max(existing.lastActiveMs, p.lastActiveMs),
116182
+ lastActiveDisplay: "",
116183
+ // recomputed below
116184
+ sources: mergeSources(existing.sources, p.sources)
116185
+ });
116186
+ }
116187
+ const merged = Array.from(byPath.values()).map((p) => ({
116188
+ ...p,
116189
+ lastActiveDisplay: formatRelativeTime(p.lastActiveMs)
116190
+ }));
116191
+ merged.sort((a, b) => b.lastActiveMs - a.lastActiveMs);
116192
+ return merged;
116193
+ }
116194
+ var SOURCE_ORDER = {
116195
+ ezcoder: 0,
116196
+ "claude-code": 1,
116197
+ codex: 2
116198
+ };
116199
+ function mergeSources(a, b) {
116200
+ const set2 = /* @__PURE__ */ new Set([...a, ...b]);
116201
+ return Array.from(set2).sort((x, y) => SOURCE_ORDER[x] - SOURCE_ORDER[y]);
116202
+ }
116203
+ async function discoverGgcoderProjects() {
116204
+ const sessionsDir = getAppPaths().sessionsDir;
116205
+ let entries;
116206
+ try {
116207
+ entries = await fs35.readdir(sessionsDir);
116208
+ } catch {
116209
+ return [];
116210
+ }
116211
+ const results = [];
116212
+ for (const entry of entries) {
116213
+ const dir = path44.join(sessionsDir, entry);
116214
+ const mtime = await maxJsonlMtime(dir);
116215
+ if (mtime === null)
116216
+ continue;
116217
+ const decoded = path44.resolve("/" + entry.replace(/_/g, "/"));
116218
+ if (!await isDirectory(decoded))
116219
+ continue;
116220
+ results.push({
116221
+ name: path44.basename(decoded),
116222
+ path: decoded,
116223
+ lastActiveMs: mtime,
116224
+ lastActiveDisplay: formatRelativeTime(mtime),
116225
+ sources: ["ezcoder"]
116226
+ });
116227
+ }
116228
+ return results;
116229
+ }
116230
+ async function discoverClaudeProjects() {
116231
+ const projectsDir = path44.join(os12.homedir(), ".claude", "projects");
116232
+ let entries;
116233
+ try {
116234
+ entries = await fs35.readdir(projectsDir);
116235
+ } catch {
116236
+ return [];
116237
+ }
116238
+ const results = await Promise.all(entries.map(async (entry) => {
116239
+ const dir = path44.join(projectsDir, entry);
116240
+ const mtime = await maxJsonlMtime(dir);
116241
+ if (mtime === null)
116242
+ return null;
116243
+ const cwd2 = await readFirstFromJsonlDir(dir, claudeCwdExtractor) ?? fallbackDashDecode(entry);
116244
+ if (!cwd2)
116245
+ return null;
116246
+ if (!await isDirectory(cwd2))
116247
+ return null;
116248
+ return {
116249
+ name: path44.basename(cwd2),
116250
+ path: cwd2,
116251
+ lastActiveMs: mtime,
116252
+ lastActiveDisplay: formatRelativeTime(mtime),
116253
+ sources: ["claude-code"]
116254
+ };
116255
+ }));
116256
+ return results.filter((p) => p !== null);
116257
+ }
116258
+ async function discoverCodexProjects() {
116259
+ const sessionsDir = path44.join(os12.homedir(), ".codex", "sessions");
116260
+ if (!await isDirectory(sessionsDir))
116261
+ return [];
116262
+ const files = await collectJsonlFiles(sessionsDir, 4);
116263
+ if (files.length === 0)
116264
+ return [];
116265
+ files.sort((a, b) => b.mtime - a.mtime);
116266
+ const byCwd = /* @__PURE__ */ new Map();
116267
+ for (const f of files) {
116268
+ const cwd2 = await readFirstFromFile(f.path, codexCwdExtractor);
116269
+ if (!cwd2)
116270
+ continue;
116271
+ const prev = byCwd.get(cwd2);
116272
+ if (prev === void 0 || f.mtime > prev)
116273
+ byCwd.set(cwd2, f.mtime);
116274
+ }
116275
+ const results = [];
116276
+ for (const [cwd2, mtime] of byCwd) {
116277
+ if (!await isDirectory(cwd2))
116278
+ continue;
116279
+ results.push({
116280
+ name: path44.basename(cwd2),
116281
+ path: cwd2,
116282
+ lastActiveMs: mtime,
116283
+ lastActiveDisplay: formatRelativeTime(mtime),
116284
+ sources: ["codex"]
116285
+ });
116286
+ }
116287
+ return results;
116288
+ }
116289
+ async function isDirectory(p) {
116290
+ try {
116291
+ const s = await fs35.stat(p);
116292
+ return s.isDirectory();
116293
+ } catch {
116294
+ return false;
116295
+ }
116296
+ }
116297
+ async function maxJsonlMtime(dir) {
116298
+ if (!await isDirectory(dir))
116299
+ return null;
116300
+ const files = await collectJsonlFiles(dir, 2);
116301
+ if (files.length === 0)
116302
+ return null;
116303
+ let max = 0;
116304
+ for (const f of files)
116305
+ if (f.mtime > max)
116306
+ max = f.mtime;
116307
+ return max > 0 ? max : null;
116308
+ }
116309
+ async function collectJsonlFiles(dir, maxDepth) {
116310
+ const out = [];
116311
+ await walk(dir, 0);
116312
+ return out;
116313
+ async function walk(current, depth) {
116314
+ let entries;
116315
+ try {
116316
+ entries = await fs35.readdir(current, { withFileTypes: true });
116317
+ } catch {
116318
+ return;
116319
+ }
116320
+ for (const e of entries) {
116321
+ const full = path44.join(current, e.name);
116322
+ if (e.isFile() && e.name.endsWith(".jsonl")) {
116323
+ try {
116324
+ const s = await fs35.stat(full);
116325
+ out.push({ path: full, mtime: s.mtimeMs });
116326
+ } catch {
116327
+ }
116328
+ } else if (e.isDirectory() && depth < maxDepth) {
116329
+ await walk(full, depth + 1);
116330
+ }
116331
+ }
116332
+ }
116333
+ }
116334
+ var claudeCwdExtractor = (line) => {
116335
+ try {
116336
+ const parsed = JSON.parse(line);
116337
+ if (typeof parsed.cwd === "string" && parsed.cwd.startsWith("/"))
116338
+ return parsed.cwd;
116339
+ } catch {
116340
+ }
116341
+ return null;
116342
+ };
116343
+ var CODEX_CWD_RE = /<cwd>([^<]+)<\/cwd>/;
116344
+ var codexCwdExtractor = (line) => {
116345
+ try {
116346
+ const parsed = JSON.parse(line);
116347
+ const cwd2 = parsed.payload?.cwd;
116348
+ if (typeof cwd2 === "string" && cwd2.startsWith("/"))
116349
+ return cwd2;
116350
+ } catch {
116351
+ }
116352
+ const m = CODEX_CWD_RE.exec(line);
116353
+ if (m && m[1] && m[1].startsWith("/"))
116354
+ return m[1];
116355
+ return null;
116356
+ };
116357
+ async function readFirstFromJsonlDir(dir, extractor) {
116358
+ const files = await collectJsonlFiles(dir, 2);
116359
+ if (files.length === 0)
116360
+ return null;
116361
+ files.sort((a, b) => b.mtime - a.mtime);
116362
+ for (const f of files) {
116363
+ const v = await readFirstFromFile(f.path, extractor);
116364
+ if (v)
116365
+ return v;
116366
+ }
116367
+ return null;
116368
+ }
116369
+ async function readFirstFromFile(file2, extractor) {
116370
+ return new Promise((resolve3) => {
116371
+ const stream2 = createReadStream3(file2, { encoding: "utf-8" });
116372
+ const rl = readline3.createInterface({ input: stream2, crlfDelay: Infinity });
116373
+ let lines = 0;
116374
+ let done = false;
116375
+ const MAX_LINES2 = 200;
116376
+ const finish = (value) => {
116377
+ if (done)
116378
+ return;
116379
+ done = true;
116380
+ resolve3(value);
116381
+ rl.close();
116382
+ stream2.destroy();
116383
+ };
116384
+ rl.on("line", (line) => {
116385
+ if (done)
116386
+ return;
116387
+ lines++;
116388
+ if (lines > MAX_LINES2) {
116389
+ finish(null);
116390
+ return;
116391
+ }
116392
+ const v = extractor(line);
116393
+ if (v)
116394
+ finish(v);
116395
+ });
116396
+ rl.on("close", () => finish(null));
116397
+ rl.on("error", () => finish(null));
116398
+ stream2.on("error", () => finish(null));
116399
+ });
116400
+ }
116401
+ function fallbackDashDecode(entry) {
116402
+ if (!entry.startsWith("-"))
116403
+ return null;
116404
+ return "/" + entry.slice(1).replace(/-/g, "/");
116405
+ }
116406
+ function formatRelativeTime(ms) {
116407
+ if (ms === 0)
116408
+ return "\u2014";
116409
+ const diff3 = Date.now() - ms;
116410
+ if (diff3 < 6e4)
116411
+ return "just now";
116412
+ const min = 6e4;
116413
+ const hour = 60 * min;
116414
+ const day = 24 * hour;
116415
+ const week = 7 * day;
116416
+ const month = 30 * day;
116417
+ if (diff3 < hour)
116418
+ return `${Math.floor(diff3 / min)}m ago`;
116419
+ if (diff3 < day)
116420
+ return `${Math.floor(diff3 / hour)}h ago`;
116421
+ if (diff3 < week)
116422
+ return `${Math.floor(diff3 / day)}d ago`;
116423
+ if (diff3 < month)
116424
+ return `${Math.floor(diff3 / week)}w ago`;
116425
+ return `${Math.floor(diff3 / month)}mo ago`;
116426
+ }
116427
+
114657
116428
  // src/boss-store.ts
114658
116429
  init_esm_shims();
114659
116430
  var import_react99 = __toESM(require_react(), 1);
@@ -115918,17 +117689,17 @@ var EventQueue = class {
115918
117689
 
115919
117690
  // src/settings.ts
115920
117691
  init_esm_shims();
115921
- import fs34 from "fs/promises";
115922
- import path41 from "path";
117692
+ import fs36 from "fs/promises";
117693
+ import path45 from "path";
115923
117694
  function settingsPath() {
115924
- return path41.join(getAppPaths().agentDir, "boss", "settings.json");
117695
+ return path45.join(getAppPaths().agentDir, "boss", "settings.json");
115925
117696
  }
115926
117697
  async function ensureDir() {
115927
- await fs34.mkdir(path41.dirname(settingsPath()), { recursive: true, mode: 448 });
117698
+ await fs36.mkdir(path45.dirname(settingsPath()), { recursive: true, mode: 448 });
115928
117699
  }
115929
117700
  async function loadSettings() {
115930
117701
  try {
115931
- const content = await fs34.readFile(settingsPath(), "utf-8");
117702
+ const content = await fs36.readFile(settingsPath(), "utf-8");
115932
117703
  const parsed = JSON.parse(content);
115933
117704
  if (!parsed || typeof parsed !== "object") return {};
115934
117705
  return parsed;
@@ -115943,8 +117714,8 @@ async function saveSettings(patch) {
115943
117714
  const merged = { ...current, ...patch };
115944
117715
  await ensureDir();
115945
117716
  const tmp = `${settingsPath()}.${process.pid}.tmp`;
115946
- await fs34.writeFile(tmp, JSON.stringify(merged, null, 2) + "\n", "utf-8");
115947
- await fs34.rename(tmp, settingsPath());
117717
+ await fs36.writeFile(tmp, JSON.stringify(merged, null, 2) + "\n", "utf-8");
117718
+ await fs36.rename(tmp, settingsPath());
115948
117719
  });
115949
117720
  writeChain = next.catch(() => void 0);
115950
117721
  await next;
@@ -116336,18 +118107,18 @@ init_esm_shims();
116336
118107
  // src/tasks-store.ts
116337
118108
  init_esm_shims();
116338
118109
  var import_react100 = __toESM(require_react(), 1);
116339
- import fs35 from "fs/promises";
116340
- import path43 from "path";
116341
- import crypto10 from "crypto";
118110
+ import fs37 from "fs/promises";
118111
+ import path46 from "path";
118112
+ import crypto11 from "crypto";
116342
118113
  function getPlanPath() {
116343
- return path43.join(getAppPaths().agentDir, "boss", "plan.json");
118114
+ return path46.join(getAppPaths().agentDir, "boss", "plan.json");
116344
118115
  }
116345
118116
  async function ensureDir2() {
116346
- await fs35.mkdir(path43.dirname(getPlanPath()), { recursive: true, mode: 448 });
118117
+ await fs37.mkdir(path46.dirname(getPlanPath()), { recursive: true, mode: 448 });
116347
118118
  }
116348
118119
  async function loadPlan() {
116349
118120
  try {
116350
- const content = await fs35.readFile(getPlanPath(), "utf-8");
118121
+ const content = await fs37.readFile(getPlanPath(), "utf-8");
116351
118122
  const parsed = JSON.parse(content);
116352
118123
  return Array.isArray(parsed.tasks) ? parsed.tasks : [];
116353
118124
  } catch {
@@ -116361,8 +118132,8 @@ async function persist(tasks) {
116361
118132
  await ensureDir2();
116362
118133
  const finalPath = getPlanPath();
116363
118134
  const tmpPath = `${finalPath}.${process.pid}.tmp`;
116364
- await fs35.writeFile(tmpPath, snapshot, "utf-8");
116365
- await fs35.rename(tmpPath, finalPath);
118135
+ await fs37.writeFile(tmpPath, snapshot, "utf-8");
118136
+ await fs37.rename(tmpPath, finalPath);
116366
118137
  });
116367
118138
  persistChain = next.catch(() => void 0);
116368
118139
  await next;
@@ -116385,7 +118156,7 @@ function useTasksState() {
116385
118156
  return (0, import_react100.useSyncExternalStore)(subscribe2, getSnapshot2, getSnapshot2);
116386
118157
  }
116387
118158
  function newId() {
116388
- return crypto10.randomBytes(6).toString("hex");
118159
+ return crypto11.randomBytes(6).toString("hex");
116389
118160
  }
116390
118161
  function now() {
116391
118162
  return (/* @__PURE__ */ new Date()).toISOString();
@@ -116631,12 +118402,12 @@ function createTaskTools(deps) {
116631
118402
  // src/audio.ts
116632
118403
  init_esm_shims();
116633
118404
  import { spawn as spawn11, execFileSync as execFileSync4 } from "child_process";
116634
- import { fileURLToPath as fileURLToPath5 } from "url";
116635
- import path44 from "path";
116636
- import fs36 from "fs";
118405
+ import { fileURLToPath as fileURLToPath6 } from "url";
118406
+ import path47 from "path";
118407
+ import fs38 from "fs";
116637
118408
  function readMp3DurationMs(file2) {
116638
118409
  try {
116639
- const buf = fs36.readFileSync(file2);
118410
+ const buf = fs38.readFileSync(file2);
116640
118411
  let i = 0;
116641
118412
  if (buf.length >= 10 && buf[0] === 73 && buf[1] === 68 && buf[2] === 51) {
116642
118413
  const tagSize = (buf[6] & 127) << 21 | (buf[7] & 127) << 14 | (buf[8] & 127) << 7 | buf[9] & 127;
@@ -116693,10 +118464,10 @@ function getSplashAudioDurationMs() {
116693
118464
  return ms && ms > 0 ? ms : 1500;
116694
118465
  }
116695
118466
  function assetPath(name) {
116696
- const here = path44.dirname(fileURLToPath5(import.meta.url));
116697
- const dist = path44.join(here, name);
116698
- if (fs36.existsSync(dist)) return dist;
116699
- return path44.join(here, "..", "assets", name);
118467
+ const here = path47.dirname(fileURLToPath6(import.meta.url));
118468
+ const dist = path47.join(here, name);
118469
+ if (fs38.existsSync(dist)) return dist;
118470
+ return path47.join(here, "..", "assets", name);
116700
118471
  }
116701
118472
  function splashAssetPath() {
116702
118473
  return assetPath("splash.mp3");
@@ -116736,15 +118507,15 @@ function trySpawn(cmd, args) {
116736
118507
  }
116737
118508
  function isWsl() {
116738
118509
  if (process.platform !== "linux") return false;
116739
- return !!process.env.WSL_DISTRO_NAME || fs36.existsSync("/proc/sys/fs/binfmt_misc/WSLInterop");
118510
+ return !!process.env.WSL_DISTRO_NAME || fs38.existsSync("/proc/sys/fs/binfmt_misc/WSLInterop");
116740
118511
  }
116741
118512
  async function tryPlayOnWindowsHost(file2) {
116742
118513
  try {
116743
- const here = path44.dirname(fileURLToPath5(import.meta.url));
116744
- const devAssets = path44.resolve(here, "..", "assets");
116745
- const resolved = path44.resolve(file2);
116746
- const inDist = resolved === here || resolved.startsWith(here + path44.sep);
116747
- const inAssets = resolved === devAssets || resolved.startsWith(devAssets + path44.sep);
118514
+ const here = path47.dirname(fileURLToPath6(import.meta.url));
118515
+ const devAssets = path47.resolve(here, "..", "assets");
118516
+ const resolved = path47.resolve(file2);
118517
+ const inDist = resolved === here || resolved.startsWith(here + path47.sep);
118518
+ const inAssets = resolved === devAssets || resolved.startsWith(devAssets + path47.sep);
116748
118519
  if (!inDist && !inAssets) {
116749
118520
  return false;
116750
118521
  }
@@ -116808,7 +118579,7 @@ async function tryPlayOnWindowsHost(file2) {
116808
118579
  }
116809
118580
  }
116810
118581
  async function playFile(file2) {
116811
- if (!fs36.existsSync(file2)) return;
118582
+ if (!fs38.existsSync(file2)) return;
116812
118583
  const platform2 = process.platform;
116813
118584
  if (platform2 === "darwin") {
116814
118585
  await trySpawn("afplay", [file2]);
@@ -116906,37 +118677,37 @@ function truncateOversizedToolResults2(messages, opts = {}) {
116906
118677
 
116907
118678
  // src/sessions.ts
116908
118679
  init_esm_shims();
116909
- import fs37 from "fs/promises";
116910
- import path45 from "path";
116911
- import crypto11 from "crypto";
118680
+ import fs39 from "fs/promises";
118681
+ import path48 from "path";
118682
+ import crypto12 from "crypto";
116912
118683
  var BOSS_SUBDIR = "boss";
116913
118684
  var SESSIONS_SUBDIR = "sessions";
116914
118685
  function getBossDir() {
116915
- return path45.join(getAppPaths().agentDir, BOSS_SUBDIR);
118686
+ return path48.join(getAppPaths().agentDir, BOSS_SUBDIR);
116916
118687
  }
116917
118688
  function getSessionsDir() {
116918
- return path45.join(getBossDir(), SESSIONS_SUBDIR);
118689
+ return path48.join(getBossDir(), SESSIONS_SUBDIR);
116919
118690
  }
116920
118691
  async function ensureSessionsDir() {
116921
118692
  const dir = getSessionsDir();
116922
- await fs37.mkdir(dir, { recursive: true, mode: 448 });
118693
+ await fs39.mkdir(dir, { recursive: true, mode: 448 });
116923
118694
  return dir;
116924
118695
  }
116925
118696
  async function createSession2() {
116926
118697
  await ensureSessionsDir();
116927
- const id2 = `${Date.now()}-${crypto11.randomBytes(4).toString("hex")}`;
116928
- const filePath = path45.join(getSessionsDir(), `${id2}.jsonl`);
116929
- await fs37.writeFile(filePath, "", "utf-8");
118698
+ const id2 = `${Date.now()}-${crypto12.randomBytes(4).toString("hex")}`;
118699
+ const filePath = path48.join(getSessionsDir(), `${id2}.jsonl`);
118700
+ await fs39.writeFile(filePath, "", "utf-8");
116930
118701
  return { id: id2, filePath };
116931
118702
  }
116932
118703
  async function appendMessages(filePath, msgs) {
116933
118704
  if (msgs.length === 0) return;
116934
118705
  const lines = msgs.map((m) => JSON.stringify(m)).join("\n") + "\n";
116935
- await fs37.appendFile(filePath, lines, "utf-8");
118706
+ await fs39.appendFile(filePath, lines, "utf-8");
116936
118707
  }
116937
118708
  async function loadSession2(filePath) {
116938
118709
  try {
116939
- const content = await fs37.readFile(filePath, "utf-8");
118710
+ const content = await fs39.readFile(filePath, "utf-8");
116940
118711
  const lines = content.split("\n").filter((l) => l.length > 0);
116941
118712
  const messages = [];
116942
118713
  for (const line of lines) {
@@ -116952,8 +118723,8 @@ async function loadSession2(filePath) {
116952
118723
  }
116953
118724
  async function inspectSession(filePath, id2) {
116954
118725
  try {
116955
- const stat = await fs37.stat(filePath);
116956
- const content = await fs37.readFile(filePath, "utf-8");
118726
+ const stat = await fs39.stat(filePath);
118727
+ const content = await fs39.readFile(filePath, "utf-8");
116957
118728
  const lines = content.split("\n").filter((l) => l.length > 0);
116958
118729
  let firstUserMessage;
116959
118730
  for (const line of lines) {
@@ -116986,7 +118757,7 @@ async function listSessions2() {
116986
118757
  await ensureSessionsDir();
116987
118758
  let entries;
116988
118759
  try {
116989
- entries = await fs37.readdir(getSessionsDir());
118760
+ entries = await fs39.readdir(getSessionsDir());
116990
118761
  } catch {
116991
118762
  return [];
116992
118763
  }
@@ -116994,7 +118765,7 @@ async function listSessions2() {
116994
118765
  for (const name of entries) {
116995
118766
  if (!name.endsWith(".jsonl")) continue;
116996
118767
  const id2 = name.replace(/\.jsonl$/, "");
116997
- const info = await inspectSession(path45.join(getSessionsDir(), name), id2);
118768
+ const info = await inspectSession(path48.join(getSessionsDir(), name), id2);
116998
118769
  if (info) infos.push(info);
116999
118770
  }
117000
118771
  infos.sort((a, b) => b.lastModified - a.lastModified);
@@ -117005,7 +118776,7 @@ async function getMostRecent() {
117005
118776
  return all[0] ?? null;
117006
118777
  }
117007
118778
  async function getSessionById(id2) {
117008
- const filePath = path45.join(getSessionsDir(), `${id2}.jsonl`);
118779
+ const filePath = path48.join(getSessionsDir(), `${id2}.jsonl`);
117009
118780
  return inspectSession(filePath, id2);
117010
118781
  }
117011
118782
 
@@ -117824,6 +119595,7 @@ export {
117824
119595
  MessageResponse,
117825
119596
  ToolExecution,
117826
119597
  ToolGroupExecution,
119598
+ discoverProjects,
117827
119599
  bossToolGroupRenderers,
117828
119600
  useBossState,
117829
119601
  subscribeToBossStore,
@@ -117959,4 +119731,4 @@ react/cjs/react-jsx-runtime.development.js:
117959
119731
  * LICENSE file in the root directory of this source tree.
117960
119732
  *)
117961
119733
  */
117962
- //# sourceMappingURL=chunk-72J6ZGVA.js.map
119734
+ //# sourceMappingURL=chunk-HYXLQEZL.js.map