@letta-ai/letta-code 0.14.7 → 0.14.9

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.
package/letta.js CHANGED
@@ -166,20 +166,39 @@ var init_error = __esm(() => {
166
166
  });
167
167
 
168
168
  // src/utils/debug.ts
169
+ import { appendFileSync } from "node:fs";
170
+ import { format } from "node:util";
169
171
  function isDebugEnabled() {
170
172
  const debug = process.env.LETTA_DEBUG;
171
173
  return debug === "1" || debug === "true";
172
174
  }
175
+ function getDebugFile() {
176
+ const path = process.env.LETTA_DEBUG_FILE;
177
+ return path && path.trim().length > 0 ? path : null;
178
+ }
179
+ function writeDebugLine(prefix, message, args) {
180
+ const debugFile = getDebugFile();
181
+ const line = `${format(`[${prefix}] ${message}`, ...args)}
182
+ `;
183
+ if (debugFile) {
184
+ try {
185
+ appendFileSync(debugFile, line, { encoding: "utf8" });
186
+ return;
187
+ } catch {}
188
+ }
189
+ console.log(line.trimEnd());
190
+ }
173
191
  function debugLog(prefix, message, ...args) {
174
192
  if (isDebugEnabled()) {
175
- console.log(`[${prefix}] ${message}`, ...args);
193
+ writeDebugLine(prefix, message, args);
176
194
  }
177
195
  }
178
196
  function debugWarn(prefix, message, ...args) {
179
197
  if (isDebugEnabled()) {
180
- console.warn(`[${prefix}] ${message}`, ...args);
198
+ writeDebugLine(prefix, `WARN: ${message}`, args);
181
199
  }
182
200
  }
201
+ var init_debug = () => {};
183
202
 
184
203
  // node_modules/@letta-ai/letta-client/internal/tslib.mjs
185
204
  function __classPrivateFieldSet(receiver, state, value, kind, f) {
@@ -493,7 +512,7 @@ function maybe_map(val, fn) {
493
512
  }
494
513
  return fn(val);
495
514
  }
496
- var has = (obj, key) => (has = Object.hasOwn ?? Function.prototype.call.bind(Object.prototype.hasOwnProperty), has(obj, key)), hex_table, limit = 1024, encode = (str, _defaultEncoder, charset, _kind, format) => {
515
+ var has = (obj, key) => (has = Object.hasOwn ?? Function.prototype.call.bind(Object.prototype.hasOwnProperty), has(obj, key)), hex_table, limit = 1024, encode = (str, _defaultEncoder, charset, _kind, format2) => {
497
516
  if (str.length === 0) {
498
517
  return str;
499
518
  }
@@ -514,7 +533,7 @@ var has = (obj, key) => (has = Object.hasOwn ?? Function.prototype.call.bind(Obj
514
533
  const arr = [];
515
534
  for (let i = 0;i < segment.length; ++i) {
516
535
  let c = segment.charCodeAt(i);
517
- if (c === 45 || c === 46 || c === 95 || c === 126 || c >= 48 && c <= 57 || c >= 65 && c <= 90 || c >= 97 && c <= 122 || format === RFC1738 && (c === 40 || c === 41)) {
536
+ if (c === 45 || c === 46 || c === 95 || c === 126 || c >= 48 && c <= 57 || c >= 65 && c <= 90 || c >= 97 && c <= 122 || format2 === RFC1738 && (c === 40 || c === 41)) {
518
537
  arr[arr.length] = segment.charAt(i);
519
538
  continue;
520
539
  }
@@ -554,7 +573,7 @@ var init_utils = __esm(() => {
554
573
  function is_non_nullish_primitive(v) {
555
574
  return typeof v === "string" || typeof v === "number" || typeof v === "boolean" || typeof v === "symbol" || typeof v === "bigint";
556
575
  }
557
- function inner_stringify(object, prefix, generateArrayPrefix, commaRoundTrip, allowEmptyArrays, strictNullHandling, skipNulls, encodeDotInKeys, encoder, filter, sort, allowDots, serializeDate, format, formatter, encodeValuesOnly, charset, sideChannel) {
576
+ function inner_stringify(object, prefix, generateArrayPrefix, commaRoundTrip, allowEmptyArrays, strictNullHandling, skipNulls, encodeDotInKeys, encoder, filter, sort, allowDots, serializeDate, format2, formatter, encodeValuesOnly, charset, sideChannel) {
558
577
  let obj = object;
559
578
  let tmp_sc = sideChannel;
560
579
  let step = 0;
@@ -587,15 +606,15 @@ function inner_stringify(object, prefix, generateArrayPrefix, commaRoundTrip, al
587
606
  }
588
607
  if (obj === null) {
589
608
  if (strictNullHandling) {
590
- return encoder && !encodeValuesOnly ? encoder(prefix, defaults.encoder, charset, "key", format) : prefix;
609
+ return encoder && !encodeValuesOnly ? encoder(prefix, defaults.encoder, charset, "key", format2) : prefix;
591
610
  }
592
611
  obj = "";
593
612
  }
594
613
  if (is_non_nullish_primitive(obj) || is_buffer(obj)) {
595
614
  if (encoder) {
596
- const key_value = encodeValuesOnly ? prefix : encoder(prefix, defaults.encoder, charset, "key", format);
615
+ const key_value = encodeValuesOnly ? prefix : encoder(prefix, defaults.encoder, charset, "key", format2);
597
616
  return [
598
- formatter?.(key_value) + "=" + formatter?.(encoder(obj, defaults.encoder, charset, "value", format))
617
+ formatter?.(key_value) + "=" + formatter?.(encoder(obj, defaults.encoder, charset, "value", format2))
599
618
  ];
600
619
  }
601
620
  return [formatter?.(prefix) + "=" + formatter?.(String(obj))];
@@ -632,7 +651,7 @@ function inner_stringify(object, prefix, generateArrayPrefix, commaRoundTrip, al
632
651
  sideChannel.set(object, step);
633
652
  const valueSideChannel = new WeakMap;
634
653
  valueSideChannel.set(sentinel, sideChannel);
635
- push_to_array(values, inner_stringify(value, key_prefix, generateArrayPrefix, commaRoundTrip, allowEmptyArrays, strictNullHandling, skipNulls, encodeDotInKeys, generateArrayPrefix === "comma" && encodeValuesOnly && isArray(obj) ? null : encoder, filter, sort, allowDots, serializeDate, format, formatter, encodeValuesOnly, charset, valueSideChannel));
654
+ push_to_array(values, inner_stringify(value, key_prefix, generateArrayPrefix, commaRoundTrip, allowEmptyArrays, strictNullHandling, skipNulls, encodeDotInKeys, generateArrayPrefix === "comma" && encodeValuesOnly && isArray(obj) ? null : encoder, filter, sort, allowDots, serializeDate, format2, formatter, encodeValuesOnly, charset, valueSideChannel));
636
655
  }
637
656
  return values;
638
657
  }
@@ -650,14 +669,14 @@ function normalize_stringify_options(opts = defaults) {
650
669
  if (typeof opts.charset !== "undefined" && opts.charset !== "utf-8" && opts.charset !== "iso-8859-1") {
651
670
  throw new TypeError("The charset option must be either utf-8, iso-8859-1, or undefined");
652
671
  }
653
- let format = default_format;
672
+ let format2 = default_format;
654
673
  if (typeof opts.format !== "undefined") {
655
674
  if (!has(formatters, opts.format)) {
656
675
  throw new TypeError("Unknown format option provided.");
657
676
  }
658
- format = opts.format;
677
+ format2 = opts.format;
659
678
  }
660
- const formatter = formatters[format];
679
+ const formatter = formatters[format2];
661
680
  let filter = defaults.filter;
662
681
  if (typeof opts.filter === "function" || isArray(opts.filter)) {
663
682
  filter = opts.filter;
@@ -688,7 +707,7 @@ function normalize_stringify_options(opts = defaults) {
688
707
  encoder: typeof opts.encoder === "function" ? opts.encoder : defaults.encoder,
689
708
  encodeValuesOnly: typeof opts.encodeValuesOnly === "boolean" ? opts.encodeValuesOnly : defaults.encodeValuesOnly,
690
709
  filter,
691
- format,
710
+ format: format2,
692
711
  formatter,
693
712
  serializeDate: typeof opts.serializeDate === "function" ? opts.serializeDate : defaults.serializeDate,
694
713
  skipNulls: typeof opts.skipNulls === "boolean" ? opts.skipNulls : defaults.skipNulls,
@@ -3108,7 +3127,7 @@ var package_default;
3108
3127
  var init_package = __esm(() => {
3109
3128
  package_default = {
3110
3129
  name: "@letta-ai/letta-code",
3111
- version: "0.14.7",
3130
+ version: "0.14.9",
3112
3131
  description: "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
3113
3132
  type: "module",
3114
3133
  bin: {
@@ -3170,7 +3189,7 @@ var init_package = __esm(() => {
3170
3189
  check: "bun run scripts/check.js",
3171
3190
  dev: "bun --loader:.md=text --loader:.mdx=text --loader:.txt=text run src/index.ts",
3172
3191
  build: "node scripts/postinstall-patches.js && bun run build.js",
3173
- prepare: "bun run build",
3192
+ prepublishOnly: "bun run build",
3174
3193
  postinstall: "node scripts/postinstall-patches.js"
3175
3194
  },
3176
3195
  "lint-staged": {
@@ -3570,7 +3589,7 @@ class SettingsManager {
3570
3589
  }
3571
3590
  this.settings = updatedSettings;
3572
3591
  await this.persistSettings();
3573
- console.log("Successfully migrated tokens to secrets");
3592
+ debugWarn("settings", "Successfully migrated tokens to secrets");
3574
3593
  } catch (error) {
3575
3594
  console.warn("Failed to migrate tokens to secrets:", error);
3576
3595
  console.warn("Tokens will remain in settings file for persistence");
@@ -4287,6 +4306,7 @@ class SettingsManager {
4287
4306
  }
4288
4307
  var DEFAULT_SETTINGS, DEFAULT_PROJECT_SETTINGS, DEFAULT_LOCAL_PROJECT_SETTINGS, DEFAULT_LETTA_API_URL = "https://api.letta.com", settingsManager;
4289
4308
  var init_settings_manager = __esm(async () => {
4309
+ init_debug();
4290
4310
  init_fs();
4291
4311
  await init_secrets();
4292
4312
  DEFAULT_SETTINGS = {
@@ -7367,38 +7387,38 @@ var require_react_development = __commonJS((exports, module) => {
7367
7387
  ReactSharedInternals.ReactDebugCurrentFrame = ReactDebugCurrentFrame;
7368
7388
  ReactSharedInternals.ReactCurrentActQueue = ReactCurrentActQueue;
7369
7389
  }
7370
- function warn(format) {
7390
+ function warn(format2) {
7371
7391
  {
7372
7392
  {
7373
7393
  for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1;_key < _len; _key++) {
7374
7394
  args[_key - 1] = arguments[_key];
7375
7395
  }
7376
- printWarning("warn", format, args);
7396
+ printWarning("warn", format2, args);
7377
7397
  }
7378
7398
  }
7379
7399
  }
7380
- function error(format) {
7400
+ function error(format2) {
7381
7401
  {
7382
7402
  {
7383
7403
  for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1;_key2 < _len2; _key2++) {
7384
7404
  args[_key2 - 1] = arguments[_key2];
7385
7405
  }
7386
- printWarning("error", format, args);
7406
+ printWarning("error", format2, args);
7387
7407
  }
7388
7408
  }
7389
7409
  }
7390
- function printWarning(level, format, args) {
7410
+ function printWarning(level, format2, args) {
7391
7411
  {
7392
7412
  var ReactDebugCurrentFrame2 = ReactSharedInternals.ReactDebugCurrentFrame;
7393
7413
  var stack = ReactDebugCurrentFrame2.getStackAddendum();
7394
7414
  if (stack !== "") {
7395
- format += "%s";
7415
+ format2 += "%s";
7396
7416
  args = args.concat([stack]);
7397
7417
  }
7398
7418
  var argsWithFormat = args.map(function(item) {
7399
7419
  return String(item);
7400
7420
  });
7401
- argsWithFormat.unshift("Warning: " + format);
7421
+ argsWithFormat.unshift("Warning: " + format2);
7402
7422
  Function.prototype.apply.call(console[level], console, argsWithFormat);
7403
7423
  }
7404
7424
  }
@@ -11750,38 +11770,38 @@ var require_react_reconciler_development = __commonJS((exports, module) => {
11750
11770
  suppressWarning = newSuppressWarning;
11751
11771
  }
11752
11772
  }
11753
- function warn(format) {
11773
+ function warn(format2) {
11754
11774
  {
11755
11775
  if (!suppressWarning) {
11756
11776
  for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1;_key < _len; _key++) {
11757
11777
  args[_key - 1] = arguments[_key];
11758
11778
  }
11759
- printWarning("warn", format, args);
11779
+ printWarning("warn", format2, args);
11760
11780
  }
11761
11781
  }
11762
11782
  }
11763
- function error(format) {
11783
+ function error(format2) {
11764
11784
  {
11765
11785
  if (!suppressWarning) {
11766
11786
  for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1;_key2 < _len2; _key2++) {
11767
11787
  args[_key2 - 1] = arguments[_key2];
11768
11788
  }
11769
- printWarning("error", format, args);
11789
+ printWarning("error", format2, args);
11770
11790
  }
11771
11791
  }
11772
11792
  }
11773
- function printWarning(level, format, args) {
11793
+ function printWarning(level, format2, args) {
11774
11794
  {
11775
11795
  var ReactDebugCurrentFrame2 = ReactSharedInternals.ReactDebugCurrentFrame;
11776
11796
  var stack = ReactDebugCurrentFrame2.getStackAddendum();
11777
11797
  if (stack !== "") {
11778
- format += "%s";
11798
+ format2 += "%s";
11779
11799
  args = args.concat([stack]);
11780
11800
  }
11781
11801
  var argsWithFormat = args.map(function(item) {
11782
11802
  return String(item);
11783
11803
  });
11784
- argsWithFormat.unshift("Warning: " + format);
11804
+ argsWithFormat.unshift("Warning: " + format2);
11785
11805
  Function.prototype.apply.call(console[level], console, argsWithFormat);
11786
11806
  }
11787
11807
  }
@@ -30620,11 +30640,22 @@ var import_react16, useInput = (inputHandler, options = {}) => {
30620
30640
  }
30621
30641
  let keypress = parse_keypress_default(data);
30622
30642
  if (!keypress.name && typeof data === "string") {
30643
+ let keycode = null;
30644
+ let modifier = 0;
30645
+ let event = 1;
30623
30646
  const csiUMatch = data.match(/^\x1b\[(\d+)(?:;(\d+))?(?::(\d+))?u$/);
30624
30647
  if (csiUMatch) {
30625
- const keycode = parseInt(csiUMatch[1], 10);
30626
- const modifier = parseInt(csiUMatch[2] || "1", 10) - 1;
30627
- const event = csiUMatch[3] ? parseInt(csiUMatch[3], 10) : 1;
30648
+ keycode = parseInt(csiUMatch[1], 10);
30649
+ modifier = parseInt(csiUMatch[2] || "1", 10) - 1;
30650
+ event = csiUMatch[3] ? parseInt(csiUMatch[3], 10) : 1;
30651
+ } else {
30652
+ const modifyOtherKeysMatch = data.match(/^\x1b\[27;(\d+);(\d+)~$/);
30653
+ if (modifyOtherKeysMatch) {
30654
+ modifier = parseInt(modifyOtherKeysMatch[1], 10) - 1;
30655
+ keycode = parseInt(modifyOtherKeysMatch[2], 10);
30656
+ }
30657
+ }
30658
+ if (keycode !== null) {
30628
30659
  if (event === 3) {
30629
30660
  return;
30630
30661
  }
@@ -30660,7 +30691,7 @@ var import_react16, useInput = (inputHandler, options = {}) => {
30660
30691
  rightArrow: keypress.name === "right",
30661
30692
  pageDown: keypress.name === "pagedown",
30662
30693
  pageUp: keypress.name === "pageup",
30663
- return: keypress.name === "return",
30694
+ return: keypress.name === "return" || keypress.name === "enter",
30664
30695
  escape: keypress.name === "escape",
30665
30696
  ctrl: keypress.ctrl,
30666
30697
  shift: keypress.shift,
@@ -31094,28 +31125,28 @@ var require_react_jsx_dev_runtime_development = __commonJS((exports) => {
31094
31125
  return null;
31095
31126
  }
31096
31127
  var ReactSharedInternals = React10.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
31097
- function error(format) {
31128
+ function error(format2) {
31098
31129
  {
31099
31130
  {
31100
31131
  for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1;_key2 < _len2; _key2++) {
31101
31132
  args[_key2 - 1] = arguments[_key2];
31102
31133
  }
31103
- printWarning("error", format, args);
31134
+ printWarning("error", format2, args);
31104
31135
  }
31105
31136
  }
31106
31137
  }
31107
- function printWarning(level, format, args) {
31138
+ function printWarning(level, format2, args) {
31108
31139
  {
31109
31140
  var ReactDebugCurrentFrame2 = ReactSharedInternals.ReactDebugCurrentFrame;
31110
31141
  var stack = ReactDebugCurrentFrame2.getStackAddendum();
31111
31142
  if (stack !== "") {
31112
- format += "%s";
31143
+ format2 += "%s";
31113
31144
  args = args.concat([stack]);
31114
31145
  }
31115
31146
  var argsWithFormat = args.map(function(item) {
31116
31147
  return String(item);
31117
31148
  });
31118
- argsWithFormat.unshift("Warning: " + format);
31149
+ argsWithFormat.unshift("Warning: " + format2);
31119
31150
  Function.prototype.apply.call(console[level], console, argsWithFormat);
31120
31151
  }
31121
31152
  }
@@ -33252,10 +33283,11 @@ function getSnapshot() {
33252
33283
  return tick;
33253
33284
  }
33254
33285
  function AnimatedLogo({
33255
- color = colors.welcome.accent
33286
+ color = colors.welcome.accent,
33287
+ animate = true
33256
33288
  }) {
33257
33289
  const tick2 = import_react24.useSyncExternalStore(subscribe, getSnapshot);
33258
- const frame = tick2 % logoFrames.length;
33290
+ const frame = animate ? tick2 % logoFrames.length : 0;
33259
33291
  const logoLines = logoFrames[frame]?.split(`
33260
33292
  `) ?? [];
33261
33293
  return /* @__PURE__ */ jsx_dev_runtime5.jsxDEV(jsx_dev_runtime5.Fragment, {
@@ -33409,7 +33441,8 @@ function WelcomeScreen({
33409
33441
  paddingLeft: 1,
33410
33442
  paddingRight: 2,
33411
33443
  children: /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(AnimatedLogo, {
33412
- color: colors.welcome.accent
33444
+ color: colors.welcome.accent,
33445
+ animate: loadingState !== "ready"
33413
33446
  }, undefined, false, undefined, this)
33414
33447
  }, undefined, false, undefined, this),
33415
33448
  /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Box_default, {
@@ -34598,13 +34631,19 @@ function windowsLaunchers(command) {
34598
34631
  return [];
34599
34632
  const launchers = [];
34600
34633
  const seen = new Set;
34634
+ const powerShellCommand = trimmed.startsWith("&") || trimmed.startsWith('"') || trimmed.startsWith("'") ? trimmed.startsWith("&") ? trimmed : `& ${trimmed}` : trimmed;
34601
34635
  pushUnique(launchers, seen, [
34602
34636
  "powershell.exe",
34603
34637
  "-NoProfile",
34604
34638
  "-Command",
34605
- trimmed
34639
+ powerShellCommand
34640
+ ]);
34641
+ pushUnique(launchers, seen, [
34642
+ "pwsh",
34643
+ "-NoProfile",
34644
+ "-Command",
34645
+ powerShellCommand
34606
34646
  ]);
34607
- pushUnique(launchers, seen, ["pwsh", "-NoProfile", "-Command", trimmed]);
34608
34647
  const envComSpecRaw = process.env.ComSpec || process.env.COMSPEC;
34609
34648
  const envComSpec = envComSpecRaw?.trim();
34610
34649
  if (envComSpec) {
@@ -34667,6 +34706,7 @@ var init_types = __esm(() => {
34667
34706
  TOOL_EVENTS = new Set([
34668
34707
  "PreToolUse",
34669
34708
  "PostToolUse",
34709
+ "PostToolUseFailure",
34670
34710
  "PermissionRequest"
34671
34711
  ]);
34672
34712
  });
@@ -34737,8 +34777,10 @@ function executeWithLauncher(launcher, inputJson, workingDirectory, input, timeo
34737
34777
  const safeResolve = (result) => {
34738
34778
  if (!resolved) {
34739
34779
  resolved = true;
34740
- const exitLabel = result.exitCode === 0 /* ALLOW */ ? "\x1B[32m✓ allowed\x1B[0m" : result.exitCode === 2 /* BLOCK */ ? "\x1B[31m✗ blocked\x1B[0m" : "\x1B[33m⚠ error\x1B[0m";
34741
- console.log(`\x1B[90m[hook] ${command}\x1B[0m`);
34780
+ const exitCode = result.exitCode === 0 /* ALLOW */ ? 0 : result.exitCode === 2 /* BLOCK */ ? 2 : 1;
34781
+ const exitColor = result.exitCode === 0 /* ALLOW */ ? "\x1B[32m" : result.exitCode === 2 /* BLOCK */ ? "\x1B[31m" : "\x1B[33m";
34782
+ const exitLabel = result.timedOut ? `${exitColor}timeout\x1B[0m` : `${exitColor}exit ${exitCode}\x1B[0m`;
34783
+ console.log(`\x1B[90m[hook:${input.event_type}] ${command}\x1B[0m`);
34742
34784
  console.log(`\x1B[90m ⎿ ${exitLabel} (${result.durationMs}ms)\x1B[0m`);
34743
34785
  if (result.stdout) {
34744
34786
  console.log(`\x1B[90m ⎿ (stdout)\x1B[0m`);
@@ -34908,7 +34950,8 @@ var init_executor = __esm(() => {
34908
34950
  function loadGlobalHooks() {
34909
34951
  try {
34910
34952
  return settingsManager.getSettings().hooks || {};
34911
- } catch {
34953
+ } catch (error) {
34954
+ debugLog("hooks", "loadGlobalHooks: Settings not initialized yet", error);
34912
34955
  return {};
34913
34956
  }
34914
34957
  }
@@ -34920,7 +34963,8 @@ async function loadProjectHooks(workingDirectory = process.cwd()) {
34920
34963
  await settingsManager.loadProjectSettings(workingDirectory);
34921
34964
  }
34922
34965
  return settingsManager.getProjectSettings(workingDirectory)?.hooks || {};
34923
- } catch {
34966
+ } catch (error) {
34967
+ debugLog("hooks", "loadProjectHooks: Settings not available", error);
34924
34968
  return {};
34925
34969
  }
34926
34970
  }
@@ -34932,7 +34976,8 @@ async function loadProjectLocalHooks(workingDirectory = process.cwd()) {
34932
34976
  await settingsManager.loadLocalProjectSettings(workingDirectory);
34933
34977
  }
34934
34978
  return settingsManager.getLocalProjectSettings(workingDirectory)?.hooks || {};
34935
- } catch {
34979
+ } catch (error) {
34980
+ debugLog("hooks", "loadProjectLocalHooks: Settings not available", error);
34936
34981
  return {};
34937
34982
  }
34938
34983
  }
@@ -34983,7 +35028,8 @@ function matchesTool(pattern, toolName) {
34983
35028
  try {
34984
35029
  const regex2 = new RegExp(`^(?:${pattern})$`);
34985
35030
  return regex2.test(toolName);
34986
- } catch {
35031
+ } catch (error) {
35032
+ debugLog("hooks", `matchesTool: Invalid regex pattern "${pattern}", falling back to exact match`, error);
34987
35033
  return pattern === toolName;
34988
35034
  }
34989
35035
  }
@@ -35026,15 +35072,20 @@ function areHooksDisabled(workingDirectory = process.cwd()) {
35026
35072
  if (projectDisabled === true) {
35027
35073
  return true;
35028
35074
  }
35029
- } catch {}
35075
+ } catch (error) {
35076
+ debugLog("hooks", "areHooksDisabled: Project settings not loaded, skipping", error);
35077
+ }
35030
35078
  try {
35031
35079
  const localDisabled = settingsManager.getLocalProjectSettings(workingDirectory)?.hooks?.disabled;
35032
35080
  if (localDisabled === true) {
35033
35081
  return true;
35034
35082
  }
35035
- } catch {}
35083
+ } catch (error) {
35084
+ debugLog("hooks", "areHooksDisabled: Local project settings not loaded, skipping", error);
35085
+ }
35036
35086
  return false;
35037
- } catch {
35087
+ } catch (error) {
35088
+ debugLog("hooks", "areHooksDisabled: Failed to check hooks disabled status", error);
35038
35089
  return false;
35039
35090
  }
35040
35091
  }
@@ -35046,6 +35097,7 @@ async function getHooksForEvent(event, toolName, workingDirectory = process.cwd(
35046
35097
  return getMatchingHooks(config, event, toolName);
35047
35098
  }
35048
35099
  var init_loader = __esm(async () => {
35100
+ init_debug();
35049
35101
  init_types();
35050
35102
  await init_settings_manager();
35051
35103
  });
@@ -35084,6 +35136,31 @@ async function runPostToolUseHooks(toolName, toolInput, toolResult, toolCallId,
35084
35136
  };
35085
35137
  return executeHooksParallel(hooks, input, workingDirectory);
35086
35138
  }
35139
+ async function runPostToolUseFailureHooks(toolName, toolInput, errorMessage, errorType, toolCallId, workingDirectory = process.cwd(), agentId, precedingReasoning, precedingAssistantMessage) {
35140
+ const hooks = await getHooksForEvent("PostToolUseFailure", toolName, workingDirectory);
35141
+ if (hooks.length === 0) {
35142
+ return { blocked: false, errored: false, feedback: [], results: [] };
35143
+ }
35144
+ const input = {
35145
+ event_type: "PostToolUseFailure",
35146
+ working_directory: workingDirectory,
35147
+ tool_name: toolName,
35148
+ tool_input: toolInput,
35149
+ tool_call_id: toolCallId,
35150
+ error_message: errorMessage,
35151
+ error_type: errorType,
35152
+ agent_id: agentId,
35153
+ preceding_reasoning: precedingReasoning,
35154
+ preceding_assistant_message: precedingAssistantMessage
35155
+ };
35156
+ const result = await executeHooksParallel(hooks, input, workingDirectory);
35157
+ return {
35158
+ blocked: false,
35159
+ errored: result.errored,
35160
+ feedback: result.feedback,
35161
+ results: result.results
35162
+ };
35163
+ }
35087
35164
  async function runPermissionRequestHooks(toolName, toolInput, permissionType, scope, workingDirectory = process.cwd()) {
35088
35165
  const hooks = await getHooksForEvent("PermissionRequest", toolName, workingDirectory);
35089
35166
  if (hooks.length === 0) {
@@ -35194,7 +35271,19 @@ async function runSessionStartHooks(isNewSession, agentId, agentName, conversati
35194
35271
  agent_name: agentName,
35195
35272
  conversation_id: conversationId
35196
35273
  };
35197
- return executeHooks(hooks, input, workingDirectory);
35274
+ const result = await executeHooks(hooks, input, workingDirectory);
35275
+ const feedback = [];
35276
+ for (const hookResult of result.results) {
35277
+ if (hookResult.stdout?.trim()) {
35278
+ feedback.push(hookResult.stdout.trim());
35279
+ }
35280
+ }
35281
+ return {
35282
+ blocked: false,
35283
+ errored: result.errored,
35284
+ feedback,
35285
+ results: result.results
35286
+ };
35198
35287
  }
35199
35288
  async function runSessionEndHooks(durationMs, messageCount, toolCallCount, agentId, conversationId, workingDirectory = process.cwd()) {
35200
35289
  const hooks = await getHooksForEvent("SessionEnd", undefined, workingDirectory);
@@ -36939,8 +37028,8 @@ function getShellEnv() {
36939
37028
  const env3 = { ...process.env };
36940
37029
  const rgBinDir = getRipgrepBinDir();
36941
37030
  if (rgBinDir) {
36942
- const currentPath = env3.PATH || "";
36943
- env3.PATH = `${rgBinDir}${path3.delimiter}${currentPath}`;
37031
+ const pathKey = Object.keys(env3).find((k) => k.toUpperCase() === "PATH") || "PATH";
37032
+ env3[pathKey] = `${rgBinDir}${path3.delimiter}${env3[pathKey] || ""}`;
36944
37033
  }
36945
37034
  try {
36946
37035
  env3.LETTA_AGENT_ID = getCurrentAgentId();
@@ -39701,11 +39790,11 @@ var require_picomatch = __commonJS((exports, module) => {
39701
39790
  return { isMatch: false, output: "" };
39702
39791
  }
39703
39792
  const opts = options || {};
39704
- const format = opts.format || (posix ? utils.toPosixSlashes : null);
39793
+ const format2 = opts.format || (posix ? utils.toPosixSlashes : null);
39705
39794
  let match = input === glob2;
39706
- let output = match && format ? format(input) : input;
39795
+ let output = match && format2 ? format2(input) : input;
39707
39796
  if (match === false) {
39708
- output = format ? format(input) : input;
39797
+ output = format2 ? format2(input) : input;
39709
39798
  match = output === glob2;
39710
39799
  }
39711
39800
  if (match === false || opts.capture === true) {
@@ -39979,14 +40068,14 @@ async function getImageDimensions(buffer) {
39979
40068
  const output = execSync(`magick identify -format "%w %h %m" "${tempInput}"`, {
39980
40069
  encoding: "utf-8"
39981
40070
  });
39982
- const [width, height, format] = output.trim().split(" ");
39983
- if (!width || !height || !format) {
40071
+ const [width, height, format2] = output.trim().split(" ");
40072
+ if (!width || !height || !format2) {
39984
40073
  throw new Error("Failed to get image dimensions");
39985
40074
  }
39986
40075
  return {
39987
40076
  width: parseInt(width, 10),
39988
40077
  height: parseInt(height, 10),
39989
- format: format.toLowerCase()
40078
+ format: format2.toLowerCase()
39990
40079
  };
39991
40080
  } finally {
39992
40081
  unlinkSync2(tempInput);
@@ -40055,9 +40144,9 @@ async function compressToFitByteLimit(buffer, currentWidth, currentHeight) {
40055
40144
  }
40056
40145
  }
40057
40146
  async function resizeImageIfNeeded(buffer, inputMediaType) {
40058
- const { width, height, format } = await getImageDimensions(buffer);
40147
+ const { width, height, format: format2 } = await getImageDimensions(buffer);
40059
40148
  const needsResize = width > MAX_IMAGE_WIDTH || height > MAX_IMAGE_HEIGHT;
40060
- const isPassthroughFormat = format === "png" || format === "jpeg" || format === "jpg";
40149
+ const isPassthroughFormat = format2 === "png" || format2 === "jpeg" || format2 === "jpg";
40061
40150
  if (!needsResize && isPassthroughFormat) {
40062
40151
  const compressed = await compressToFitByteLimit(buffer, width, height);
40063
40152
  if (compressed) {
@@ -40078,7 +40167,7 @@ async function resizeImageIfNeeded(buffer, inputMediaType) {
40078
40167
  const tempOutput2 = join12(tmpdir(), `resize-output-${Date.now()}-${Math.random().toString(36).slice(2)}`);
40079
40168
  let outputBuffer2;
40080
40169
  let outputMediaType;
40081
- if (format === "jpeg" || format === "jpg") {
40170
+ if (format2 === "jpeg" || format2 === "jpg") {
40082
40171
  execSync(`magick "${tempInput}" -resize ${MAX_IMAGE_WIDTH}x${MAX_IMAGE_HEIGHT}> -quality 85 "${tempOutput2}.jpg"`, {
40083
40172
  stdio: "ignore"
40084
40173
  });
@@ -45680,10 +45769,10 @@ var require_output = __commonJS((exports, module) => {
45680
45769
  }
45681
45770
  return this;
45682
45771
  }
45683
- function toFormat(format, options) {
45684
- const actualFormat = formats.get((is.object(format) && is.string(format.id) ? format.id : format).toLowerCase());
45772
+ function toFormat(format2, options) {
45773
+ const actualFormat = formats.get((is.object(format2) && is.string(format2.id) ? format2.id : format2).toLowerCase());
45685
45774
  if (!actualFormat) {
45686
- throw is.invalidParameterError("format", `one of: ${[...formats.keys()].join(", ")}`, format);
45775
+ throw is.invalidParameterError("format", `one of: ${[...formats.keys()].join(", ")}`, format2);
45687
45776
  }
45688
45777
  return this[actualFormat](options);
45689
45778
  }
@@ -46405,11 +46494,11 @@ var require_utility = __commonJS((exports, module) => {
46405
46494
  var sharp = require_sharp();
46406
46495
  var runtimePlatform = runtimePlatformArch();
46407
46496
  var libvipsVersion = sharp.libvipsVersion();
46408
- var format = sharp.format();
46409
- format.heif.output.alias = ["avif", "heic"];
46410
- format.jpeg.output.alias = ["jpe", "jpg"];
46411
- format.tiff.output.alias = ["tif"];
46412
- format.jp2k.output.alias = ["j2c", "j2k", "jp2", "jpx"];
46497
+ var format2 = sharp.format();
46498
+ format2.heif.output.alias = ["avif", "heic"];
46499
+ format2.jpeg.output.alias = ["jpe", "jpg"];
46500
+ format2.tiff.output.alias = ["tif"];
46501
+ format2.jp2k.output.alias = ["j2c", "j2k", "jp2", "jpx"];
46413
46502
  var interpolators = {
46414
46503
  nearest: "nearest",
46415
46504
  bilinear: "bilinear",
@@ -46437,9 +46526,9 @@ var require_utility = __commonJS((exports, module) => {
46437
46526
  }
46438
46527
  }
46439
46528
  versions.sharp = require_package().version;
46440
- if (versions.heif && format.heif) {
46441
- format.heif.input.fileSuffix = [".avif"];
46442
- format.heif.output.alias = ["avif"];
46529
+ if (versions.heif && format2.heif) {
46530
+ format2.heif.input.fileSuffix = [".avif"];
46531
+ format2.heif.output.alias = ["avif"];
46443
46532
  }
46444
46533
  function cache4(options) {
46445
46534
  if (is.bool(options)) {
@@ -46497,7 +46586,7 @@ var require_utility = __commonJS((exports, module) => {
46497
46586
  Sharp.concurrency = concurrency;
46498
46587
  Sharp.counters = counters;
46499
46588
  Sharp.simd = simd;
46500
- Sharp.format = format;
46589
+ Sharp.format = format2;
46501
46590
  Sharp.interpolators = interpolators;
46502
46591
  Sharp.versions = versions;
46503
46592
  Sharp.queue = queue;
@@ -46576,9 +46665,9 @@ async function resizeImageIfNeeded2(buffer, inputMediaType) {
46576
46665
  const metadata = await image2.metadata();
46577
46666
  const width = metadata.width ?? 0;
46578
46667
  const height = metadata.height ?? 0;
46579
- const format = metadata.format;
46668
+ const format2 = metadata.format;
46580
46669
  const needsResize = width > MAX_IMAGE_WIDTH2 || height > MAX_IMAGE_HEIGHT2;
46581
- const isPassthroughFormat = format === "png" || format === "jpeg";
46670
+ const isPassthroughFormat = format2 === "png" || format2 === "jpeg";
46582
46671
  if (!needsResize && isPassthroughFormat) {
46583
46672
  const compressed2 = await compressToFitByteLimit2(buffer, width, height);
46584
46673
  if (compressed2) {
@@ -46599,7 +46688,7 @@ async function resizeImageIfNeeded2(buffer, inputMediaType) {
46599
46688
  });
46600
46689
  let outputBuffer2;
46601
46690
  let outputMediaType;
46602
- if (format === "jpeg") {
46691
+ if (format2 === "jpeg") {
46603
46692
  outputBuffer2 = await resized.jpeg({ quality: 85 }).toBuffer();
46604
46693
  outputMediaType = "image/jpeg";
46605
46694
  } else {
@@ -54363,7 +54452,10 @@ async function getAvailableModelHandles(options) {
54363
54452
  function prefetchAvailableModelHandles() {
54364
54453
  getAvailableModelHandles().catch(() => {});
54365
54454
  }
54366
- function getModelContextWindow(handle) {
54455
+ async function getModelContextWindow(handle) {
54456
+ if (!cache4) {
54457
+ await getAvailableModelHandles();
54458
+ }
54367
54459
  return cache4?.contextWindows.get(handle);
54368
54460
  }
54369
54461
  var CACHE_TTL_MS, cache4 = null, inflight = null;
@@ -57621,19 +57713,22 @@ var init_esm7 = __esm(() => {
57621
57713
 
57622
57714
  // src/permissions/matcher.ts
57623
57715
  import { resolve as resolve13 } from "node:path";
57716
+ function normalizePath(p) {
57717
+ return p.replace(/\\/g, "/");
57718
+ }
57624
57719
  function matchesFilePattern(query, pattern, workingDirectory) {
57625
57720
  const queryMatch = query.match(/^([^(]+)\((.+)\)$/);
57626
57721
  if (!queryMatch || !queryMatch[1] || !queryMatch[2]) {
57627
57722
  return false;
57628
57723
  }
57629
57724
  const queryTool = queryMatch[1];
57630
- const filePath = queryMatch[2];
57725
+ const filePath = normalizePath(queryMatch[2]);
57631
57726
  const patternMatch = pattern.match(/^([^(]+)\((.+)\)$/);
57632
57727
  if (!patternMatch || !patternMatch[1] || !patternMatch[2]) {
57633
57728
  return false;
57634
57729
  }
57635
57730
  const patternTool = patternMatch[1];
57636
- let globPattern = patternMatch[2];
57731
+ let globPattern = normalizePath(patternMatch[2]);
57637
57732
  if (queryTool !== patternTool) {
57638
57733
  return false;
57639
57734
  }
@@ -57647,11 +57742,12 @@ function matchesFilePattern(query, pattern, workingDirectory) {
57647
57742
  if (globPattern.startsWith("//")) {
57648
57743
  globPattern = globPattern.slice(1);
57649
57744
  }
57650
- const absoluteFilePath = resolve13(workingDirectory, filePath);
57745
+ const absoluteFilePath = normalizePath(resolve13(workingDirectory, filePath));
57651
57746
  if (globPattern.startsWith("/")) {
57652
57747
  return minimatch2(absoluteFilePath, globPattern);
57653
57748
  }
57654
- const relativeFilePath = filePath.startsWith("/") ? absoluteFilePath.replace(`${workingDirectory}/`, "") : filePath;
57749
+ const normalizedWorkingDir = normalizePath(workingDirectory);
57750
+ const relativeFilePath = filePath.startsWith("/") ? absoluteFilePath.replace(`${normalizedWorkingDir}/`, "") : filePath;
57655
57751
  return minimatch2(relativeFilePath, globPattern) || minimatch2(absoluteFilePath, globPattern);
57656
57752
  }
57657
57753
  function extractActualCommand(command) {
@@ -58971,10 +59067,51 @@ async function executeTool(name, args, options) {
58971
59067
  const responseSize = typeof flattenedResponse === "string" ? flattenedResponse.length : JSON.stringify(flattenedResponse).length;
58972
59068
  telemetry2.trackToolUsage(internalName, toolStatus === "success", duration, responseSize, toolStatus === "error" ? "tool_error" : undefined, stderr ? stderr.join(`
58973
59069
  `) : undefined);
58974
- runPostToolUseHooks(internalName, args, {
58975
- status: toolStatus,
58976
- output: getDisplayableToolReturn(flattenedResponse)
58977
- }, options?.toolCallId, undefined, undefined, undefined, undefined).catch(() => {});
59070
+ let postToolUseFeedback = [];
59071
+ try {
59072
+ const postHookResult = await runPostToolUseHooks(internalName, args, {
59073
+ status: toolStatus,
59074
+ output: getDisplayableToolReturn(flattenedResponse)
59075
+ }, options?.toolCallId, undefined, undefined, undefined, undefined);
59076
+ postToolUseFeedback = postHookResult.feedback;
59077
+ } catch (error) {
59078
+ debugLog("hooks", "PostToolUse hook error (success path)", error);
59079
+ }
59080
+ let postToolUseFailureFeedback = [];
59081
+ if (toolStatus === "error") {
59082
+ const errorOutput = typeof flattenedResponse === "string" ? flattenedResponse : JSON.stringify(flattenedResponse);
59083
+ try {
59084
+ const failureHookResult = await runPostToolUseFailureHooks(internalName, args, errorOutput, "tool_error", options?.toolCallId, undefined, undefined, undefined, undefined);
59085
+ postToolUseFailureFeedback = failureHookResult.feedback;
59086
+ } catch (error) {
59087
+ debugLog("hooks", "PostToolUseFailure hook error (tool returned error)", error);
59088
+ }
59089
+ }
59090
+ const allFeedback = [...postToolUseFeedback, ...postToolUseFailureFeedback];
59091
+ if (allFeedback.length > 0) {
59092
+ const feedbackMessage = `
59093
+
59094
+ [Hook feedback]:
59095
+ ${allFeedback.join(`
59096
+ `)}`;
59097
+ let finalToolReturn;
59098
+ if (typeof flattenedResponse === "string") {
59099
+ finalToolReturn = flattenedResponse + feedbackMessage;
59100
+ } else if (Array.isArray(flattenedResponse)) {
59101
+ finalToolReturn = [
59102
+ ...flattenedResponse,
59103
+ { type: "text", text: feedbackMessage }
59104
+ ];
59105
+ } else {
59106
+ finalToolReturn = flattenedResponse;
59107
+ }
59108
+ return {
59109
+ toolReturn: finalToolReturn,
59110
+ status: toolStatus,
59111
+ ...stdout && { stdout },
59112
+ ...stderr && { stderr }
59113
+ };
59114
+ }
58978
59115
  return {
58979
59116
  toolReturn: flattenedResponse,
58980
59117
  status: toolStatus,
@@ -58987,9 +59124,28 @@ async function executeTool(name, args, options) {
58987
59124
  const errorType = isAbort ? "abort" : error instanceof Error ? error.name : "unknown";
58988
59125
  const errorMessage = isAbort ? INTERRUPTED_BY_USER : error instanceof Error ? error.message : String(error);
58989
59126
  telemetry2.trackToolUsage(internalName, false, duration, errorMessage.length, errorType, errorMessage);
58990
- runPostToolUseHooks(internalName, args, { status: "error", output: errorMessage }, options?.toolCallId, undefined, undefined, undefined, undefined).catch(() => {});
59127
+ let postToolUseFeedback = [];
59128
+ try {
59129
+ const postHookResult = await runPostToolUseHooks(internalName, args, { status: "error", output: errorMessage }, options?.toolCallId, undefined, undefined, undefined, undefined);
59130
+ postToolUseFeedback = postHookResult.feedback;
59131
+ } catch (error2) {
59132
+ debugLog("hooks", "PostToolUse hook error (error path)", error2);
59133
+ }
59134
+ let postToolUseFailureFeedback = [];
59135
+ try {
59136
+ const failureHookResult = await runPostToolUseFailureHooks(internalName, args, errorMessage, errorType, options?.toolCallId, undefined, undefined, undefined, undefined);
59137
+ postToolUseFailureFeedback = failureHookResult.feedback;
59138
+ } catch (error2) {
59139
+ debugLog("hooks", "PostToolUseFailure hook error (exception path)", error2);
59140
+ }
59141
+ const allFeedback = [...postToolUseFeedback, ...postToolUseFailureFeedback];
59142
+ const finalErrorMessage = allFeedback.length > 0 ? `${errorMessage}
59143
+
59144
+ [Hook feedback]:
59145
+ ${allFeedback.join(`
59146
+ `)}` : errorMessage;
58991
59147
  return {
58992
- toolReturn: errorMessage,
59148
+ toolReturn: finalErrorMessage,
58993
59149
  status: "error"
58994
59150
  };
58995
59151
  }
@@ -59025,6 +59181,7 @@ var init_manager3 = __esm(async () => {
59025
59181
  init_model();
59026
59182
  init_subagents();
59027
59183
  init_constants();
59184
+ init_debug();
59028
59185
  await __promiseAll([
59029
59186
  init_approval_execution(),
59030
59187
  init_hooks(),
@@ -61856,7 +62013,7 @@ function buildModelSettings(modelHandle, updateArgs) {
61856
62013
  async function updateAgentLLMConfig(agentId, modelHandle, updateArgs) {
61857
62014
  const client = await getClient2();
61858
62015
  const modelSettings = buildModelSettings(modelHandle, updateArgs);
61859
- const contextWindow = updateArgs?.context_window;
62016
+ const contextWindow = updateArgs?.context_window ?? await getModelContextWindow(modelHandle);
61860
62017
  const hasModelSettings = Object.keys(modelSettings).length > 0;
61861
62018
  await client.agents.update(agentId, {
61862
62019
  model: modelHandle,
@@ -61938,6 +62095,7 @@ async function updateAgentSystemPromptMemfs(agentId, enableMemfs) {
61938
62095
  var init_modify = __esm(async () => {
61939
62096
  await __promiseAll([
61940
62097
  init_openai_codex_provider(),
62098
+ init_available_models(),
61941
62099
  init_client2()
61942
62100
  ]);
61943
62101
  });
@@ -62109,7 +62267,7 @@ async function createAgent(nameOrOptions = DEFAULT_AGENT_NAME, model, embeddingM
62109
62267
  blockProvenance.push({ label: blockId, source: "shared" });
62110
62268
  }
62111
62269
  const modelUpdateArgs = getModelUpdateArgs(modelHandle);
62112
- const contextWindow = modelUpdateArgs?.context_window;
62270
+ const contextWindow = modelUpdateArgs?.context_window ?? await getModelContextWindow(modelHandle);
62113
62271
  let systemPromptContent;
62114
62272
  if (options.systemPromptCustom) {
62115
62273
  systemPromptContent = options.systemPromptCustom;
@@ -62182,6 +62340,7 @@ var init_create = __esm(async () => {
62182
62340
  init_promptAssets();
62183
62341
  init_skills2();
62184
62342
  await __promiseAll([
62343
+ init_available_models(),
62185
62344
  init_client2(),
62186
62345
  init_modify()
62187
62346
  ]);
@@ -62853,16 +63012,6 @@ function isGlobTool(name) {
62853
63012
  }
62854
63013
 
62855
63014
  // src/cli/helpers/accumulator.ts
62856
- var exports_accumulator = {};
62857
- __export(exports_accumulator, {
62858
- toLines: () => toLines,
62859
- setToolCallsRunning: () => setToolCallsRunning,
62860
- onChunk: () => onChunk,
62861
- markIncompleteToolsAsCancelled: () => markIncompleteToolsAsCancelled,
62862
- markCurrentLineAsFinished: () => markCurrentLineAsFinished,
62863
- createBuffers: () => createBuffers,
62864
- appendStreamingOutput: () => appendStreamingOutput
62865
- });
62866
63015
  function appendStreamingOutput(state, chunk, startTime, isStderr = false) {
62867
63016
  const current = state || {
62868
63017
  tailLines: [],
@@ -62963,7 +63112,7 @@ function markCurrentLineAsFinished(b) {
62963
63112
  if (!b.lastOtid) {
62964
63113
  return;
62965
63114
  }
62966
- const prev = b.byId.get(b.lastOtid) || b.byId.get(`${b.lastOtid}-tool`);
63115
+ const prev = b.byId.get(b.lastOtid);
62967
63116
  if (prev && (prev.kind === "assistant" || prev.kind === "reasoning")) {
62968
63117
  markAsFinished(b, b.lastOtid);
62969
63118
  } else {}
@@ -63109,48 +63258,33 @@ function onChunk(b, chunk) {
63109
63258
  }
63110
63259
  case "tool_call_message":
63111
63260
  case "approval_request_message": {
63112
- let id = chunk.otid;
63261
+ handleOtidTransition(b, chunk.otid ?? undefined);
63113
63262
  const toolCall = chunk.tool_call || (Array.isArray(chunk.tool_calls) && chunk.tool_calls.length > 0 ? chunk.tool_calls[0] : null);
63114
- const toolCallId = toolCall?.tool_call_id;
63115
- const name = toolCall?.name;
63116
- const argsText = toolCall?.arguments;
63117
- if (toolCallId && b.toolCallIdToLineId.has(toolCallId)) {
63118
- const existingId = b.toolCallIdToLineId.get(toolCallId);
63119
- if (existingId) {
63120
- id = existingId;
63121
- }
63122
- handleOtidTransition(b, chunk.otid ?? undefined);
63123
- } else {
63124
- if (id && b.byId.has(id)) {
63125
- const existing = b.byId.get(id);
63126
- if (existing && existing.kind === "reasoning") {
63127
- markAsFinished(b, id);
63128
- id = `${id}-tool`;
63129
- } else if (existing && existing.kind === "tool_call") {
63130
- if (toolCallId) {
63131
- id = `${id}-${toolCallId.slice(-8)}`;
63132
- } else {
63133
- id = `${id}-${Date.now().toString(36)}`;
63134
- }
63135
- }
63136
- }
63137
- handleOtidTransition(b, id ?? undefined);
63138
- if (!id) {
63139
- break;
63140
- }
63141
- if (toolCallId)
63142
- b.toolCallIdToLineId.set(toolCallId, id);
63143
- }
63144
- if (!id)
63263
+ if (!toolCall || !toolCall.tool_call_id)
63145
63264
  break;
63265
+ const toolCallId = toolCall.tool_call_id;
63266
+ const name = toolCall.name;
63267
+ const argsText = toolCall.arguments;
63268
+ const id = b.toolCallIdToLineId.get(toolCallId) ?? toolCallId;
63269
+ if (!b.toolCallIdToLineId.has(toolCallId)) {
63270
+ b.toolCallIdToLineId.set(toolCallId, id);
63271
+ }
63146
63272
  const desiredPhase = "ready";
63147
- const line = ensure(b, id, () => ({
63273
+ let line = ensure(b, id, () => ({
63148
63274
  kind: "tool_call",
63149
63275
  id,
63150
- toolCallId: toolCallId ?? undefined,
63276
+ toolCallId,
63151
63277
  name: name ?? undefined,
63152
63278
  phase: desiredPhase
63153
63279
  }));
63280
+ if (name && !line.name || line.toolCallId !== toolCallId) {
63281
+ line = {
63282
+ ...line,
63283
+ toolCallId,
63284
+ name: line.name ?? name ?? undefined
63285
+ };
63286
+ b.byId.set(id, line);
63287
+ }
63154
63288
  if (chunk.message_type === "approval_request_message" && line.phase !== "finished") {
63155
63289
  b.byId.set(id, { ...line, phase: "ready" });
63156
63290
  }
@@ -63182,7 +63316,9 @@ function onChunk(b, chunk) {
63182
63316
  parsedArgs = JSON.parse(toolInfo.toolArgs);
63183
63317
  }
63184
63318
  } catch {}
63185
- runPreToolUseHooks(toolInfo.toolName, parsedArgs, toolCallId, undefined, b.agentId).catch(() => {});
63319
+ runPreToolUseHooks(toolInfo.toolName, parsedArgs, toolCallId, undefined, b.agentId).catch((error) => {
63320
+ debugLog("hooks", "PreToolUse hook error (accumulator)", error);
63321
+ });
63186
63322
  }
63187
63323
  }
63188
63324
  break;
@@ -63231,7 +63367,9 @@ function onChunk(b, chunk) {
63231
63367
  runPostToolUseHooks(serverToolInfo.toolName, parsedArgs, {
63232
63368
  status: status === "success" ? "success" : "error",
63233
63369
  output: resultText
63234
- }, toolCallId, undefined, b.agentId, precedingReasoning, precedingAssistantMessage).catch(() => {});
63370
+ }, toolCallId, undefined, b.agentId, precedingReasoning, precedingAssistantMessage).catch((error) => {
63371
+ debugLog("hooks", "PostToolUse hook error (accumulator)", error);
63372
+ });
63235
63373
  b.serverToolCalls.delete(toolCallId);
63236
63374
  }
63237
63375
  }
@@ -63337,6 +63475,7 @@ function setToolCallsRunning(b, toolCallIds) {
63337
63475
  var MAX_TAIL_LINES = 5, MAX_BUFFER_SIZE = 1e5, CANCEL_REASON_TEXT;
63338
63476
  var init_accumulator = __esm(async () => {
63339
63477
  init_constants();
63478
+ init_debug();
63340
63479
  init_backfill();
63341
63480
  await init_hooks();
63342
63481
  CANCEL_REASON_TEXT = {
@@ -63347,6 +63486,99 @@ var init_accumulator = __esm(async () => {
63347
63486
  };
63348
63487
  });
63349
63488
 
63489
+ // src/cli/helpers/safeJsonParse.ts
63490
+ function safeJsonParse(json) {
63491
+ try {
63492
+ const data = JSON.parse(json);
63493
+ return { success: true, data };
63494
+ } catch (error) {
63495
+ return {
63496
+ success: false,
63497
+ error: error instanceof Error ? error.message : String(error)
63498
+ };
63499
+ }
63500
+ }
63501
+ function safeJsonParseOr(json, defaultValue) {
63502
+ const result = safeJsonParse(json);
63503
+ return result.success ? result.data : defaultValue;
63504
+ }
63505
+
63506
+ // src/cli/helpers/approvalClassification.ts
63507
+ async function getMissingRequiredArgs(toolName, parsedArgs) {
63508
+ const schema = getToolSchema(toolName);
63509
+ const required = schema?.input_schema?.required || [];
63510
+ return required.filter((key) => !(key in parsedArgs) || parsedArgs[key] == null);
63511
+ }
63512
+ async function classifyApprovals(approvals, opts = {}) {
63513
+ const needsUserInput = [];
63514
+ const autoAllowed = [];
63515
+ const autoDenied = [];
63516
+ const denyReasonForAsk = opts.denyReasonForAsk ?? "Tool requires approval (headless mode)";
63517
+ const missingNameReason = opts.missingNameReason ?? "Tool call incomplete - missing name";
63518
+ for (const approval of approvals) {
63519
+ const toolName = approval.toolName;
63520
+ if (!toolName) {
63521
+ autoDenied.push({
63522
+ approval,
63523
+ permission: { decision: "deny", reason: missingNameReason },
63524
+ context: null,
63525
+ parsedArgs: {},
63526
+ denyReason: missingNameReason
63527
+ });
63528
+ continue;
63529
+ }
63530
+ const parsedArgs = safeJsonParseOr(approval.toolArgs || "{}", {});
63531
+ const permission = await checkToolPermission(toolName, parsedArgs);
63532
+ const context3 = opts.getContext ? await opts.getContext(toolName, parsedArgs) : null;
63533
+ let decision = permission.decision;
63534
+ if (opts.alwaysRequiresUserInput?.(toolName) && decision === "allow") {
63535
+ decision = "ask";
63536
+ }
63537
+ if (decision === "ask" && opts.treatAskAsDeny) {
63538
+ autoDenied.push({
63539
+ approval,
63540
+ permission,
63541
+ context: context3,
63542
+ parsedArgs,
63543
+ denyReason: denyReasonForAsk
63544
+ });
63545
+ continue;
63546
+ }
63547
+ if (decision === "allow" && opts.requireArgsForAutoApprove) {
63548
+ const missingRequiredArgs = await getMissingRequiredArgs(toolName, parsedArgs);
63549
+ if (missingRequiredArgs.length > 0) {
63550
+ const denyReason = opts.missingArgsReason ? opts.missingArgsReason(missingRequiredArgs) : `Missing required parameter${missingRequiredArgs.length > 1 ? "s" : ""}: ${missingRequiredArgs.join(", ")}`;
63551
+ autoDenied.push({
63552
+ approval,
63553
+ permission,
63554
+ context: context3,
63555
+ parsedArgs,
63556
+ missingRequiredArgs,
63557
+ denyReason
63558
+ });
63559
+ continue;
63560
+ }
63561
+ }
63562
+ const entry = {
63563
+ approval,
63564
+ permission,
63565
+ context: context3,
63566
+ parsedArgs
63567
+ };
63568
+ if (decision === "ask") {
63569
+ needsUserInput.push(entry);
63570
+ } else if (decision === "deny") {
63571
+ autoDenied.push(entry);
63572
+ } else {
63573
+ autoAllowed.push(entry);
63574
+ }
63575
+ }
63576
+ return { needsUserInput, autoAllowed, autoDenied };
63577
+ }
63578
+ var init_approvalClassification = __esm(async () => {
63579
+ await init_manager3();
63580
+ });
63581
+
63350
63582
  // src/cli/helpers/errorContext.ts
63351
63583
  function setErrorContext(context3) {
63352
63584
  currentContext = { ...currentContext, ...context3 };
@@ -63543,23 +63775,6 @@ var init_errorFormatter = __esm(() => {
63543
63775
  init_errorContext();
63544
63776
  });
63545
63777
 
63546
- // src/cli/helpers/safeJsonParse.ts
63547
- function safeJsonParse(json) {
63548
- try {
63549
- const data = JSON.parse(json);
63550
- return { success: true, data };
63551
- } catch (error) {
63552
- return {
63553
- success: false,
63554
- error: error instanceof Error ? error.message : String(error)
63555
- };
63556
- }
63557
- }
63558
- function safeJsonParseOr(json, defaultValue) {
63559
- const result = safeJsonParse(json);
63560
- return result.success ? result.data : defaultValue;
63561
- }
63562
-
63563
63778
  // src/cli/helpers/streamProcessor.ts
63564
63779
  class StreamProcessor {
63565
63780
  pendingApprovals = new Map;
@@ -63567,7 +63782,6 @@ class StreamProcessor {
63567
63782
  lastRunId = null;
63568
63783
  lastSeqId = null;
63569
63784
  stopReason = null;
63570
- lastApprovalId = null;
63571
63785
  processChunk(chunk) {
63572
63786
  let errorInfo;
63573
63787
  let updatedApproval;
@@ -63607,21 +63821,13 @@ class StreamProcessor {
63607
63821
  this.pendingApprovals.delete(chunk.tool_call_id);
63608
63822
  }
63609
63823
  }
63610
- if (chunk.message_type === "approval_request_message") {
63611
- this.lastApprovalId = chunk.id;
63612
- }
63613
63824
  if (chunk.message_type === "approval_request_message") {
63614
63825
  const toolCalls = Array.isArray(chunk.tool_calls) ? chunk.tool_calls : chunk.tool_call ? [chunk.tool_call] : [];
63615
63826
  for (const toolCall of toolCalls) {
63616
- let id = toolCall?.tool_call_id ?? this.lastApprovalId;
63617
- if (!id) {
63618
- if (this.pendingApprovals.size === 1) {
63619
- id = Array.from(this.pendingApprovals.keys())[0] ?? null;
63620
- }
63621
- }
63622
- if (!id)
63827
+ const toolCallId = toolCall?.tool_call_id;
63828
+ if (!toolCallId)
63623
63829
  continue;
63624
- this.lastApprovalId = id;
63830
+ const id = toolCallId;
63625
63831
  const existing = this.pendingApprovals.get(id) || {
63626
63832
  toolCallId: id,
63627
63833
  toolName: "",
@@ -63652,7 +63858,7 @@ class StreamProcessor {
63652
63858
  }
63653
63859
 
63654
63860
  // src/cli/helpers/stream.ts
63655
- async function drainStream(stream2, buffers, refresh, abortSignal, onFirstMessage) {
63861
+ async function drainStream(stream2, buffers, refresh, abortSignal, onFirstMessage, onChunkProcessed) {
63656
63862
  const startTime = performance.now();
63657
63863
  const requestStartTime = stream2[STREAM_REQUEST_START_TIME];
63658
63864
  let hasLoggedTTFT = false;
@@ -63702,17 +63908,44 @@ async function drainStream(stream2, buffers, refresh, abortSignal, onFirstMessag
63702
63908
  const ttft = performance.now() - requestStartTime;
63703
63909
  logTiming(`TTFT: ${formatDuration(ttft)} (from POST to first content)`);
63704
63910
  }
63705
- const { shouldOutput } = streamProcessor.processChunk(chunk);
63911
+ const { shouldOutput, errorInfo, updatedApproval } = streamProcessor.processChunk(chunk);
63706
63912
  if (abortSignal?.aborted) {
63707
63913
  stopReason = "cancelled";
63708
63914
  markIncompleteToolsAsCancelled(buffers, true, "user_interrupt");
63709
63915
  queueMicrotask(refresh);
63710
63916
  break;
63711
63917
  }
63712
- if (shouldOutput) {
63918
+ let shouldOutputChunk = shouldOutput;
63919
+ let shouldAccumulate = shouldOutput;
63920
+ if (onChunkProcessed) {
63921
+ const hookResult = await onChunkProcessed({
63922
+ chunk,
63923
+ shouldOutput: shouldOutputChunk,
63924
+ errorInfo,
63925
+ updatedApproval,
63926
+ streamProcessor
63927
+ });
63928
+ if (hookResult?.shouldOutput !== undefined) {
63929
+ shouldOutputChunk = hookResult.shouldOutput;
63930
+ }
63931
+ if (hookResult?.shouldAccumulate !== undefined) {
63932
+ shouldAccumulate = hookResult.shouldAccumulate;
63933
+ } else {
63934
+ shouldAccumulate = shouldOutputChunk;
63935
+ }
63936
+ if (hookResult?.stopReason) {
63937
+ stopReason = hookResult.stopReason;
63938
+ }
63939
+ } else {
63940
+ shouldAccumulate = shouldOutputChunk;
63941
+ }
63942
+ if (shouldAccumulate) {
63713
63943
  onChunk(buffers, chunk);
63714
63944
  queueMicrotask(refresh);
63715
63945
  }
63946
+ if (stopReason) {
63947
+ break;
63948
+ }
63716
63949
  }
63717
63950
  } catch (e) {
63718
63951
  const errorMessage = e instanceof Error ? e.message : String(e);
@@ -63779,9 +64012,9 @@ async function drainStream(stream2, buffers, refresh, abortSignal, onFirstMessag
63779
64012
  fallbackError
63780
64013
  };
63781
64014
  }
63782
- async function drainStreamWithResume(stream2, buffers, refresh, abortSignal, onFirstMessage) {
64015
+ async function drainStreamWithResume(stream2, buffers, refresh, abortSignal, onFirstMessage, onChunkProcessed) {
63783
64016
  const overallStartTime = performance.now();
63784
- let result = await drainStream(stream2, buffers, refresh, abortSignal, onFirstMessage);
64017
+ let result = await drainStream(stream2, buffers, refresh, abortSignal, onFirstMessage, onChunkProcessed);
63785
64018
  if (result.stopReason === "error" && result.lastRunId && result.lastSeqId !== null && abortSignal && !abortSignal.aborted) {
63786
64019
  const originalFallbackError = result.fallbackError;
63787
64020
  try {
@@ -63792,7 +64025,7 @@ async function drainStreamWithResume(stream2, buffers, refresh, abortSignal, onF
63792
64025
  starting_after: result.lastSeqId,
63793
64026
  batch_size: 1000
63794
64027
  });
63795
- const resumeResult = await drainStream(resumeStream, buffers, refresh, abortSignal);
64028
+ const resumeResult = await drainStream(resumeStream, buffers, refresh, abortSignal, undefined, onChunkProcessed);
63796
64029
  result = resumeResult;
63797
64030
  } catch (_e) {
63798
64031
  result.fallbackError = originalFallbackError;
@@ -63803,6 +64036,7 @@ async function drainStreamWithResume(stream2, buffers, refresh, abortSignal, onF
63803
64036
  }
63804
64037
  var init_stream = __esm(async () => {
63805
64038
  init_error();
64039
+ init_debug();
63806
64040
  init_timing();
63807
64041
  await __promiseAll([
63808
64042
  init_client2(),
@@ -64227,6 +64461,7 @@ async function getResumeData2(client, agent, conversationId) {
64227
64461
  var MESSAGE_HISTORY_LIMIT2 = 15;
64228
64462
  var init_check_approval = __esm(() => {
64229
64463
  init_error();
64464
+ init_debug();
64230
64465
  });
64231
64466
 
64232
64467
  // src/headless.ts
@@ -64313,6 +64548,13 @@ async function handleHeadlessCommand(argv, model, skillsDirectory) {
64313
64548
  }
64314
64549
  const inputFormat = values["input-format"];
64315
64550
  const isBidirectionalMode = inputFormat === "stream-json";
64551
+ process.stdout.on("error", (err) => {
64552
+ const code = typeof err === "object" && err !== null && "code" in err ? err.code : undefined;
64553
+ if (code === "EPIPE") {
64554
+ process.exit(0);
64555
+ }
64556
+ throw err;
64557
+ });
64316
64558
  let prompt = positionals.slice(2).join(" ");
64317
64559
  if (!prompt && !isBidirectionalMode) {
64318
64560
  if (!process.stdin.isTTY) {
@@ -64617,10 +64859,7 @@ In headless mode, use:
64617
64859
  const noSkillsFlag = values["no-skills"];
64618
64860
  const isSubagent = process.env.LETTA_CODE_AGENT_ROLE === "subagent";
64619
64861
  if (!noSkillsFlag && !isSubagent) {
64620
- const createdBlocks = await ensureSkillsBlocks(agent.id);
64621
- if (createdBlocks.length > 0) {
64622
- console.log("Created missing skills blocks for agent compatibility");
64623
- }
64862
+ await ensureSkillsBlocks(agent.id);
64624
64863
  }
64625
64864
  if (memfsFlag) {
64626
64865
  settingsManager.setMemfsEnabled(agent.id, true);
@@ -64628,6 +64867,8 @@ In headless mode, use:
64628
64867
  settingsManager.setMemfsEnabled(agent.id, false);
64629
64868
  } else if (isNewlyCreatedAgent && !isSubagent) {
64630
64869
  settingsManager.setMemfsEnabled(agent.id, true);
64870
+ } else if (specifiedAgentId && !isSubagent) {
64871
+ settingsManager.setMemfsEnabled(agent.id, true);
64631
64872
  }
64632
64873
  if (settingsManager.isMemfsEnabled(agent.id)) {
64633
64874
  try {
@@ -64638,9 +64879,6 @@ In headless mode, use:
64638
64879
  process.exit(1);
64639
64880
  }
64640
64881
  await updateMemoryFilesystemBlock(agent.id);
64641
- if (syncResult.updatedBlocks.length > 0 || syncResult.createdBlocks.length > 0 || syncResult.deletedBlocks.length > 0 || syncResult.updatedFiles.length > 0 || syncResult.createdFiles.length > 0 || syncResult.deletedFiles.length > 0) {
64642
- console.log(formatMemorySyncSummary(syncResult));
64643
- }
64644
64882
  } catch (error) {
64645
64883
  console.error(`Memory filesystem sync failed: ${error instanceof Error ? error.message : String(error)}`);
64646
64884
  process.exit(1);
@@ -64771,39 +65009,28 @@ In headless mode, use:
64771
65009
  const pendingApprovals = resume.pendingApprovals || [];
64772
65010
  if (pendingApprovals.length === 0)
64773
65011
  break;
64774
- const decisions = [];
64775
- for (const currentApproval of pendingApprovals) {
64776
- const { toolName, toolArgs } = currentApproval;
64777
- const parsedArgs = safeJsonParseOr(toolArgs || "{}", {});
64778
- const permission = await checkToolPermission(toolName, parsedArgs);
64779
- if (permission.decision === "deny" || permission.decision === "ask") {
64780
- const denyReason = permission.decision === "ask" ? "Tool requires approval (headless mode)" : `Permission denied: ${permission.matchedRule || permission.reason}`;
64781
- decisions.push({
64782
- type: "deny",
64783
- approval: currentApproval,
64784
- reason: denyReason
64785
- });
64786
- continue;
64787
- }
64788
- const { getToolSchema: getToolSchema2 } = await init_manager3().then(() => exports_manager2);
64789
- const schema = getToolSchema2(toolName);
64790
- const required = schema?.input_schema?.required || [];
64791
- const missing = required.filter((key) => !(key in parsedArgs) || parsedArgs[key] == null);
64792
- if (missing.length > 0) {
64793
- decisions.push({
64794
- type: "deny",
64795
- approval: currentApproval,
64796
- reason: `Missing required parameter${missing.length > 1 ? "s" : ""}: ${missing.join(", ")}`
64797
- });
64798
- continue;
64799
- }
64800
- decisions.push({
65012
+ const { autoAllowed, autoDenied } = await classifyApprovals(pendingApprovals, {
65013
+ treatAskAsDeny: true,
65014
+ denyReasonForAsk: "Tool requires approval (headless mode)",
65015
+ requireArgsForAutoApprove: true,
65016
+ missingNameReason: "Tool call incomplete - missing name"
65017
+ });
65018
+ const decisions = [
65019
+ ...autoAllowed.map((ac) => ({
64801
65020
  type: "approve",
64802
- approval: currentApproval,
64803
- reason: permission.reason || "Allowed by permission rule",
64804
- matchedRule: permission.matchedRule || "auto-approved"
64805
- });
64806
- }
65021
+ approval: ac.approval,
65022
+ reason: ac.permission.reason || "Allowed by permission rule",
65023
+ matchedRule: "matchedRule" in ac.permission && ac.permission.matchedRule ? ac.permission.matchedRule : "auto-approved"
65024
+ })),
65025
+ ...autoDenied.map((ac) => {
65026
+ const fallback = "matchedRule" in ac.permission && ac.permission.matchedRule ? `Permission denied: ${ac.permission.matchedRule}` : ac.permission.reason ? `Permission denied: ${ac.permission.reason}` : "Permission denied: Unknown reason";
65027
+ return {
65028
+ type: "deny",
65029
+ approval: ac.approval,
65030
+ reason: ac.denyReason ?? fallback
65031
+ };
65032
+ })
65033
+ ];
64807
65034
  const { executeApprovalBatch: executeApprovalBatch2 } = await init_approval_execution().then(() => exports_approval_execution);
64808
65035
  if (outputFormat === "stream-json") {
64809
65036
  for (const decision of decisions) {
@@ -64923,12 +65150,16 @@ ${SYSTEM_REMINDER_CLOSE}
64923
65150
  let approvals = [];
64924
65151
  let apiDurationMs;
64925
65152
  let lastRunId = null;
65153
+ let approvalPendingRecovery = false;
64926
65154
  if (outputFormat === "stream-json") {
64927
- const startTime = performance.now();
64928
65155
  const autoApprovalEmitted = new Set;
64929
- const streamProcessor = new StreamProcessor;
64930
- for await (const chunk of stream2) {
64931
- const { shouldOutput, errorInfo, updatedApproval } = streamProcessor.processChunk(chunk);
65156
+ const streamJsonHook = async ({
65157
+ chunk,
65158
+ shouldOutput,
65159
+ errorInfo,
65160
+ updatedApproval
65161
+ }) => {
65162
+ let shouldOutputChunk = shouldOutput;
64932
65163
  if (errorInfo && shouldOutput) {
64933
65164
  const errorEvent = {
64934
65165
  type: "error",
@@ -64948,52 +65179,45 @@ ${SYSTEM_REMINDER_CLOSE}
64948
65179
  }
64949
65180
  };
64950
65181
  console.log(JSON.stringify(errorEvent));
64951
- const { onChunk: accumulatorOnChunk } = await init_accumulator().then(() => exports_accumulator);
64952
- accumulatorOnChunk(buffers, chunk);
64953
- continue;
65182
+ shouldOutputChunk = false;
64954
65183
  }
64955
65184
  if (isApprovalPendingError(errorInfo?.detail) || isApprovalPendingError(errorInfo?.message)) {
64956
- if (outputFormat === "stream-json") {
64957
- const recoveryMsg = {
64958
- type: "recovery",
64959
- recovery_type: "approval_pending",
64960
- message: "Detected pending approval conflict; auto-denying stale approval and retrying",
64961
- run_id: lastRunId ?? undefined,
65185
+ const recoveryRunId = errorInfo?.run_id;
65186
+ const recoveryMsg = {
65187
+ type: "recovery",
65188
+ recovery_type: "approval_pending",
65189
+ message: "Detected pending approval conflict; auto-denying stale approval and retrying",
65190
+ run_id: recoveryRunId ?? undefined,
65191
+ session_id: sessionId,
65192
+ uuid: `recovery-${recoveryRunId || crypto.randomUUID()}`
65193
+ };
65194
+ console.log(JSON.stringify(recoveryMsg));
65195
+ approvalPendingRecovery = true;
65196
+ return { stopReason: "error", shouldAccumulate: true };
65197
+ }
65198
+ if (updatedApproval && !autoApprovalEmitted.has(updatedApproval.toolCallId)) {
65199
+ const { autoAllowed } = await classifyApprovals([updatedApproval], {
65200
+ requireArgsForAutoApprove: true,
65201
+ missingNameReason: "Tool call incomplete - missing name"
65202
+ });
65203
+ const [approval] = autoAllowed;
65204
+ if (approval) {
65205
+ const permission = approval.permission;
65206
+ shouldOutputChunk = false;
65207
+ const autoApprovalMsg = {
65208
+ type: "auto_approval",
65209
+ tool_call: {
65210
+ name: approval.approval.toolName,
65211
+ tool_call_id: approval.approval.toolCallId,
65212
+ arguments: approval.approval.toolArgs || "{}"
65213
+ },
65214
+ reason: permission.reason || "Allowed by permission rule",
65215
+ matched_rule: "matchedRule" in permission && permission.matchedRule ? permission.matchedRule : "auto-approved",
64962
65216
  session_id: sessionId,
64963
- uuid: `recovery-${lastRunId || crypto.randomUUID()}`
65217
+ uuid: `auto-approval-${approval.approval.toolCallId}`
64964
65218
  };
64965
- console.log(JSON.stringify(recoveryMsg));
64966
- }
64967
- await resolveAllPendingApprovals();
64968
- stopReason = "error";
64969
- break;
64970
- }
64971
- let shouldOutputChunk = shouldOutput;
64972
- if (updatedApproval && !autoApprovalEmitted.has(updatedApproval.toolCallId) && updatedApproval.toolName) {
64973
- const parsedArgs = safeJsonParseOr(updatedApproval.toolArgs || "{}", null);
64974
- const permission = await checkToolPermission(updatedApproval.toolName, parsedArgs || {});
64975
- if (permission.decision === "allow" && parsedArgs) {
64976
- const { getToolSchema: getToolSchema2 } = await init_manager3().then(() => exports_manager2);
64977
- const schema = getToolSchema2(updatedApproval.toolName);
64978
- const required = schema?.input_schema?.required || [];
64979
- const missing = required.filter((key) => !(key in parsedArgs) || parsedArgs[key] == null);
64980
- if (missing.length === 0) {
64981
- shouldOutputChunk = false;
64982
- const autoApprovalMsg = {
64983
- type: "auto_approval",
64984
- tool_call: {
64985
- name: updatedApproval.toolName,
64986
- tool_call_id: updatedApproval.toolCallId,
64987
- arguments: updatedApproval.toolArgs || "{}"
64988
- },
64989
- reason: permission.reason || "Allowed by permission rule",
64990
- matched_rule: permission.matchedRule || "auto-approved",
64991
- session_id: sessionId,
64992
- uuid: `auto-approval-${updatedApproval.toolCallId}`
64993
- };
64994
- console.log(JSON.stringify(autoApprovalMsg));
64995
- autoApprovalEmitted.add(updatedApproval.toolCallId);
64996
- }
65219
+ console.log(JSON.stringify(autoApprovalMsg));
65220
+ autoApprovalEmitted.add(approval.approval.toolCallId);
64997
65221
  }
64998
65222
  }
64999
65223
  if (shouldOutputChunk) {
@@ -65017,17 +65241,15 @@ ${SYSTEM_REMINDER_CLOSE}
65017
65241
  console.log(JSON.stringify(msg));
65018
65242
  }
65019
65243
  }
65020
- const { onChunk: onChunk2 } = await init_accumulator().then(() => exports_accumulator);
65021
- onChunk2(buffers, chunk);
65022
- }
65023
- stopReason = stopReason || streamProcessor.stopReason || "error";
65024
- apiDurationMs = performance.now() - startTime;
65025
- approvals = streamProcessor.getApprovals();
65026
- lastRunId = streamProcessor.lastRunId;
65244
+ return { shouldOutput: shouldOutputChunk, shouldAccumulate: true };
65245
+ };
65246
+ const result = await drainStreamWithResume(stream2, buffers, () => {}, undefined, undefined, streamJsonHook);
65247
+ stopReason = result.stopReason;
65248
+ approvals = result.approvals || [];
65249
+ apiDurationMs = result.apiDurationMs;
65250
+ lastRunId = result.lastRunId || null;
65027
65251
  if (lastRunId)
65028
65252
  lastKnownRunId = lastRunId;
65029
- const { markCurrentLineAsFinished: markCurrentLineAsFinished2 } = await init_accumulator().then(() => exports_accumulator);
65030
- markCurrentLineAsFinished2(buffers);
65031
65253
  } else {
65032
65254
  const result = await drainStreamWithResume(stream2, buffers, () => {});
65033
65255
  stopReason = result.stopReason;
@@ -65038,6 +65260,10 @@ ${SYSTEM_REMINDER_CLOSE}
65038
65260
  lastKnownRunId = lastRunId;
65039
65261
  }
65040
65262
  sessionStats.endTurn(apiDurationMs);
65263
+ if (approvalPendingRecovery) {
65264
+ await resolveAllPendingApprovals();
65265
+ continue;
65266
+ }
65041
65267
  if (stopReason === "end_turn") {
65042
65268
  llmApiErrorRetries = 0;
65043
65269
  conversationBusyRetries = 0;
@@ -65048,45 +65274,26 @@ ${SYSTEM_REMINDER_CLOSE}
65048
65274
  console.error("Unexpected empty approvals array");
65049
65275
  process.exit(1);
65050
65276
  }
65051
- const decisions = [];
65052
- for (const currentApproval of approvals) {
65053
- const { toolName, toolArgs } = currentApproval;
65054
- const parsedArgs = safeJsonParseOr(toolArgs, {});
65055
- const permission = await checkToolPermission(toolName, parsedArgs);
65056
- if (permission.decision === "deny") {
65057
- const denyReason = `Permission denied: ${permission.matchedRule || permission.reason}`;
65058
- decisions.push({
65059
- type: "deny",
65060
- approval: currentApproval,
65061
- reason: denyReason
65062
- });
65063
- continue;
65064
- }
65065
- if (permission.decision === "ask") {
65066
- decisions.push({
65067
- type: "deny",
65068
- approval: currentApproval,
65069
- reason: "Tool requires approval (headless mode)"
65070
- });
65071
- continue;
65072
- }
65073
- const { getToolSchema: getToolSchema2 } = await init_manager3().then(() => exports_manager2);
65074
- const schema = getToolSchema2(toolName);
65075
- const required = schema?.input_schema?.required || [];
65076
- const missing = required.filter((key) => !(key in parsedArgs) || parsedArgs[key] == null);
65077
- if (missing.length > 0) {
65078
- decisions.push({
65079
- type: "deny",
65080
- approval: currentApproval,
65081
- reason: `Missing required parameter${missing.length > 1 ? "s" : ""}: ${missing.join(", ")}`
65082
- });
65083
- continue;
65084
- }
65085
- decisions.push({
65277
+ const { autoAllowed, autoDenied } = await classifyApprovals(approvals, {
65278
+ treatAskAsDeny: true,
65279
+ denyReasonForAsk: "Tool requires approval (headless mode)",
65280
+ requireArgsForAutoApprove: true,
65281
+ missingNameReason: "Tool call incomplete - missing name"
65282
+ });
65283
+ const decisions = [
65284
+ ...autoAllowed.map((ac) => ({
65086
65285
  type: "approve",
65087
- approval: currentApproval
65088
- });
65089
- }
65286
+ approval: ac.approval
65287
+ })),
65288
+ ...autoDenied.map((ac) => {
65289
+ const fallback = "matchedRule" in ac.permission && ac.permission.matchedRule ? `Permission denied: ${ac.permission.matchedRule}` : ac.permission.reason ? `Permission denied: ${ac.permission.reason}` : "Permission denied: Unknown reason";
65290
+ return {
65291
+ type: "deny",
65292
+ approval: ac.approval,
65293
+ reason: ac.denyReason ?? fallback
65294
+ };
65295
+ })
65296
+ ];
65090
65297
  const { executeApprovalBatch: executeApprovalBatch2 } = await init_approval_execution().then(() => exports_approval_execution);
65091
65298
  const executedResults = await executeApprovalBatch2(decisions);
65092
65299
  currentInput = [
@@ -65505,6 +65712,8 @@ async function runBidirectionalMode(agent, conversationId, _client, _outputForma
65505
65712
  const buffers = createBuffers(agent.id);
65506
65713
  const startTime = performance.now();
65507
65714
  let numTurns = 0;
65715
+ let lastStopReason = null;
65716
+ let sawStreamError = false;
65508
65717
  let currentInput = [
65509
65718
  { role: "user", content: userContent }
65510
65719
  ];
@@ -65516,109 +65725,138 @@ async function runBidirectionalMode(agent, conversationId, _client, _outputForma
65516
65725
  const stream2 = await sendMessageStream(conversationId, currentInput, {
65517
65726
  agentId: agent.id
65518
65727
  });
65519
- const streamProcessor = new StreamProcessor;
65520
- for await (const chunk of stream2) {
65521
- if (currentAbortController?.signal.aborted) {
65522
- break;
65728
+ const streamJsonHook = ({
65729
+ chunk,
65730
+ shouldOutput,
65731
+ errorInfo
65732
+ }) => {
65733
+ if (errorInfo && shouldOutput) {
65734
+ sawStreamError = true;
65735
+ const errorEvent = {
65736
+ type: "error",
65737
+ message: errorInfo.message,
65738
+ stop_reason: "error",
65739
+ run_id: errorInfo.run_id,
65740
+ session_id: sessionId,
65741
+ uuid: crypto.randomUUID(),
65742
+ ...errorInfo.error_type && errorInfo.run_id && {
65743
+ api_error: {
65744
+ message_type: "error_message",
65745
+ message: errorInfo.message,
65746
+ error_type: errorInfo.error_type,
65747
+ detail: errorInfo.detail,
65748
+ run_id: errorInfo.run_id
65749
+ }
65750
+ }
65751
+ };
65752
+ console.log(JSON.stringify(errorEvent));
65753
+ return { shouldAccumulate: true };
65523
65754
  }
65524
- const { shouldOutput } = streamProcessor.processChunk(chunk);
65525
- if (shouldOutput) {
65526
- const chunkWithIds = chunk;
65527
- const uuid = chunkWithIds.otid || chunkWithIds.id;
65528
- if (includePartialMessages) {
65529
- const streamEvent = {
65530
- type: "stream_event",
65531
- event: chunk,
65532
- session_id: sessionId,
65533
- uuid: uuid || crypto.randomUUID()
65534
- };
65535
- console.log(JSON.stringify(streamEvent));
65536
- } else {
65537
- const msg = {
65538
- type: "message",
65539
- ...chunk,
65540
- session_id: sessionId,
65541
- uuid: uuid || crypto.randomUUID()
65542
- };
65543
- console.log(JSON.stringify(msg));
65544
- }
65755
+ if (!shouldOutput) {
65756
+ return { shouldAccumulate: true };
65545
65757
  }
65546
- const { onChunk: onChunk2 } = await init_accumulator().then(() => exports_accumulator);
65547
- onChunk2(buffers, chunk);
65548
- }
65549
- const stopReason = streamProcessor.stopReason || "error";
65758
+ const chunkWithIds = chunk;
65759
+ const uuid = chunkWithIds.otid || chunkWithIds.id;
65760
+ if (includePartialMessages) {
65761
+ const streamEvent = {
65762
+ type: "stream_event",
65763
+ event: chunk,
65764
+ session_id: sessionId,
65765
+ uuid: uuid || crypto.randomUUID()
65766
+ };
65767
+ console.log(JSON.stringify(streamEvent));
65768
+ } else {
65769
+ const msg = {
65770
+ type: "message",
65771
+ ...chunk,
65772
+ session_id: sessionId,
65773
+ uuid: uuid || crypto.randomUUID()
65774
+ };
65775
+ console.log(JSON.stringify(msg));
65776
+ }
65777
+ return { shouldAccumulate: true };
65778
+ };
65779
+ const result = await drainStreamWithResume(stream2, buffers, () => {}, currentAbortController?.signal, undefined, streamJsonHook);
65780
+ const stopReason = result.stopReason;
65781
+ lastStopReason = stopReason;
65782
+ const approvals = result.approvals || [];
65550
65783
  if (stopReason === "end_turn") {
65551
65784
  break;
65552
65785
  }
65553
- if (currentAbortController?.signal.aborted) {
65786
+ if (currentAbortController?.signal.aborted || stopReason === "cancelled") {
65554
65787
  break;
65555
65788
  }
65556
65789
  if (stopReason === "requires_approval") {
65557
- const approvals = streamProcessor.getApprovals();
65558
65790
  if (approvals.length === 0) {
65791
+ lastStopReason = "error";
65559
65792
  break;
65560
65793
  }
65561
- const decisions = [];
65562
- for (const approval of approvals) {
65563
- const parsedArgs = safeJsonParseOr(approval.toolArgs, {});
65564
- const permission = await checkToolPermission(approval.toolName, parsedArgs);
65565
- if (permission.decision === "allow") {
65794
+ const { autoAllowed, autoDenied, needsUserInput } = await classifyApprovals(approvals, {
65795
+ requireArgsForAutoApprove: true,
65796
+ missingNameReason: "Tool call incomplete - missing name"
65797
+ });
65798
+ const decisions = [
65799
+ ...autoAllowed.map((ac) => ({
65800
+ type: "approve",
65801
+ approval: ac.approval,
65802
+ matchedRule: "matchedRule" in ac.permission && ac.permission.matchedRule ? ac.permission.matchedRule : "auto-approved"
65803
+ })),
65804
+ ...autoDenied.map((ac) => {
65805
+ const fallback = "matchedRule" in ac.permission && ac.permission.matchedRule ? `Permission denied: ${ac.permission.matchedRule}` : ac.permission.reason ? `Permission denied: ${ac.permission.reason}` : "Permission denied: Unknown reason";
65806
+ return {
65807
+ type: "deny",
65808
+ approval: ac.approval,
65809
+ reason: ac.denyReason ?? fallback
65810
+ };
65811
+ })
65812
+ ];
65813
+ for (const approvalItem of autoAllowed) {
65814
+ const permission = approvalItem.permission;
65815
+ const autoApprovalMsg = {
65816
+ type: "auto_approval",
65817
+ tool_call: {
65818
+ name: approvalItem.approval.toolName,
65819
+ tool_call_id: approvalItem.approval.toolCallId,
65820
+ arguments: approvalItem.approval.toolArgs
65821
+ },
65822
+ reason: permission.reason || "auto-approved",
65823
+ matched_rule: "matchedRule" in permission && permission.matchedRule ? permission.matchedRule : "auto-approved",
65824
+ session_id: sessionId,
65825
+ uuid: `auto-approval-${approvalItem.approval.toolCallId}`
65826
+ };
65827
+ console.log(JSON.stringify(autoApprovalMsg));
65828
+ }
65829
+ for (const ac of needsUserInput) {
65830
+ const permResponse = await requestPermission(ac.approval.toolCallId, ac.approval.toolName, ac.parsedArgs);
65831
+ if (permResponse.decision === "allow") {
65832
+ const finalApproval = permResponse.updatedInput ? {
65833
+ ...ac.approval,
65834
+ toolArgs: JSON.stringify(permResponse.updatedInput)
65835
+ } : ac.approval;
65566
65836
  decisions.push({
65567
65837
  type: "approve",
65568
- approval,
65569
- matchedRule: permission.matchedRule || "auto-approved"
65838
+ approval: finalApproval,
65839
+ matchedRule: "SDK callback approved"
65570
65840
  });
65571
65841
  const autoApprovalMsg = {
65572
65842
  type: "auto_approval",
65573
65843
  tool_call: {
65574
- name: approval.toolName,
65575
- tool_call_id: approval.toolCallId,
65576
- arguments: approval.toolArgs
65844
+ name: finalApproval.toolName,
65845
+ tool_call_id: finalApproval.toolCallId,
65846
+ arguments: finalApproval.toolArgs
65577
65847
  },
65578
- reason: permission.reason || "auto-approved",
65579
- matched_rule: permission.matchedRule || "auto-approved",
65848
+ reason: permResponse.reason || "SDK callback approved",
65849
+ matched_rule: "canUseTool callback",
65580
65850
  session_id: sessionId,
65581
- uuid: `auto-approval-${approval.toolCallId}`
65851
+ uuid: `auto-approval-${ac.approval.toolCallId}`
65582
65852
  };
65583
65853
  console.log(JSON.stringify(autoApprovalMsg));
65584
- } else if (permission.decision === "deny") {
65854
+ } else {
65585
65855
  decisions.push({
65586
65856
  type: "deny",
65587
- approval,
65588
- reason: `Permission denied: ${permission.matchedRule || permission.reason}`
65857
+ approval: ac.approval,
65858
+ reason: permResponse.reason || "Denied by SDK callback"
65589
65859
  });
65590
- } else {
65591
- const permResponse = await requestPermission(approval.toolCallId, approval.toolName, parsedArgs);
65592
- if (permResponse.decision === "allow") {
65593
- const finalApproval = permResponse.updatedInput ? {
65594
- ...approval,
65595
- toolArgs: JSON.stringify(permResponse.updatedInput)
65596
- } : approval;
65597
- decisions.push({
65598
- type: "approve",
65599
- approval: finalApproval,
65600
- matchedRule: "SDK callback approved"
65601
- });
65602
- const autoApprovalMsg = {
65603
- type: "auto_approval",
65604
- tool_call: {
65605
- name: finalApproval.toolName,
65606
- tool_call_id: finalApproval.toolCallId,
65607
- arguments: finalApproval.toolArgs
65608
- },
65609
- reason: permResponse.reason || "SDK callback approved",
65610
- matched_rule: "canUseTool callback",
65611
- session_id: sessionId,
65612
- uuid: `auto-approval-${approval.toolCallId}`
65613
- };
65614
- console.log(JSON.stringify(autoApprovalMsg));
65615
- } else {
65616
- decisions.push({
65617
- type: "deny",
65618
- approval,
65619
- reason: permResponse.reason || "Denied by SDK callback"
65620
- });
65621
- }
65622
65860
  }
65623
65861
  }
65624
65862
  const { executeApprovalBatch: executeApprovalBatch2 } = await init_approval_execution().then(() => exports_approval_execution);
@@ -65640,9 +65878,12 @@ async function runBidirectionalMode(agent, conversationId, _client, _outputForma
65640
65878
  const lastReasoning = reversed.find((line2) => line2.kind === "reasoning" && ("text" in line2) && typeof line2.text === "string" && line2.text.trim().length > 0);
65641
65879
  const lastToolResult = reversed.find((line2) => line2.kind === "tool_call" && ("resultText" in line2) && typeof line2.resultText === "string" && (line2.resultText ?? "").trim().length > 0);
65642
65880
  const resultText = lastAssistant?.text || lastReasoning?.text || lastToolResult?.resultText || "";
65881
+ const isAborted = currentAbortController?.signal.aborted;
65882
+ const isError = sawStreamError || lastStopReason && lastStopReason !== "end_turn" && lastStopReason !== "requires_approval";
65883
+ const subtype = isAborted ? "interrupted" : isError ? "error" : "success";
65643
65884
  const resultMsg = {
65644
65885
  type: "result",
65645
- subtype: currentAbortController?.signal.aborted ? "interrupted" : "success",
65886
+ subtype,
65646
65887
  session_id: sessionId,
65647
65888
  duration_ms: Math.round(durationMs),
65648
65889
  duration_api_ms: 0,
@@ -65652,18 +65893,38 @@ async function runBidirectionalMode(agent, conversationId, _client, _outputForma
65652
65893
  conversation_id: conversationId,
65653
65894
  run_ids: [],
65654
65895
  usage: null,
65655
- uuid: `result-${agent.id}-${Date.now()}`
65896
+ uuid: `result-${agent.id}-${Date.now()}`,
65897
+ ...subtype === "error" && {
65898
+ stop_reason: lastStopReason && lastStopReason !== "end_turn" ? lastStopReason : "error"
65899
+ }
65656
65900
  };
65657
65901
  console.log(JSON.stringify(resultMsg));
65658
65902
  } catch (error) {
65903
+ const errorDetails = formatErrorDetails(error, agent.id);
65659
65904
  const errorMsg2 = {
65660
65905
  type: "error",
65661
- message: error instanceof Error ? error.message : "Unknown error occurred",
65906
+ message: errorDetails,
65662
65907
  stop_reason: "error",
65663
65908
  session_id: sessionId,
65664
65909
  uuid: crypto.randomUUID()
65665
65910
  };
65666
65911
  console.log(JSON.stringify(errorMsg2));
65912
+ const errorResultMsg = {
65913
+ type: "result",
65914
+ subtype: "error",
65915
+ session_id: sessionId,
65916
+ duration_ms: 0,
65917
+ duration_api_ms: 0,
65918
+ num_turns: 0,
65919
+ result: null,
65920
+ agent_id: agent.id,
65921
+ conversation_id: conversationId,
65922
+ run_ids: [],
65923
+ usage: null,
65924
+ uuid: `result-error-${agent.id}-${Date.now()}`,
65925
+ stop_reason: "error"
65926
+ };
65927
+ console.log(JSON.stringify(errorResultMsg));
65667
65928
  } finally {
65668
65929
  currentAbortController = null;
65669
65930
  }
@@ -65696,9 +65957,9 @@ var init_headless = __esm(async () => {
65696
65957
  init_memoryFilesystem(),
65697
65958
  init_message(),
65698
65959
  init_accumulator(),
65960
+ init_approvalClassification(),
65699
65961
  init_stream(),
65700
- init_settings_manager(),
65701
- init_manager3()
65962
+ init_settings_manager()
65702
65963
  ]);
65703
65964
  });
65704
65965
 
@@ -69710,7 +69971,8 @@ var init_InlineBashApproval = __esm(async () => {
69710
69971
  onCancel,
69711
69972
  isFocused = true,
69712
69973
  approveAlwaysText,
69713
- allowPersistence = true
69974
+ allowPersistence = true,
69975
+ showPreview = true
69714
69976
  }) => {
69715
69977
  const [selectedOption, setSelectedOption] = import_react36.useState(0);
69716
69978
  const {
@@ -69768,6 +70030,15 @@ var init_InlineBashApproval = __esm(async () => {
69768
70030
  }
69769
70031
  if (key.escape) {
69770
70032
  onCancel?.();
70033
+ return;
70034
+ }
70035
+ if (input === "1") {
70036
+ onApprove();
70037
+ return;
70038
+ }
70039
+ if (input === "2" && allowPersistence) {
70040
+ onApproveAlways("project");
70041
+ return;
69771
70042
  }
69772
70043
  }, { isActive: isFocused });
69773
70044
  const solidLine = SOLID_LINE6.repeat(Math.max(columns, 10));
@@ -69801,12 +70072,13 @@ var init_InlineBashApproval = __esm(async () => {
69801
70072
  ]
69802
70073
  }, undefined, true, undefined, this), [bashInfo.command, bashInfo.description, solidLine]);
69803
70074
  const hintText = isOnCustomOption ? customReason ? "Enter to submit · Esc to clear" : "Type reason · Esc to cancel" : "Enter to select · Esc to cancel";
70075
+ const optionsMarginTop = showPreview ? 1 : 0;
69804
70076
  return /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Box_default, {
69805
70077
  flexDirection: "column",
69806
70078
  children: [
69807
- memoizedCommandContent,
70079
+ showPreview && memoizedCommandContent,
69808
70080
  /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Box_default, {
69809
- marginTop: 1,
70081
+ marginTop: optionsMarginTop,
69810
70082
  flexDirection: "column",
69811
70083
  children: [
69812
70084
  /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Box_default, {
@@ -70126,7 +70398,8 @@ var init_InlineFileEditApproval = __esm(async () => {
70126
70398
  onCancel,
70127
70399
  isFocused = true,
70128
70400
  approveAlwaysText,
70129
- allowPersistence = true
70401
+ allowPersistence = true,
70402
+ showPreview = true
70130
70403
  }) => {
70131
70404
  const [selectedOption, setSelectedOption] = import_react38.useState(0);
70132
70405
  const {
@@ -70217,6 +70490,15 @@ var init_InlineFileEditApproval = __esm(async () => {
70217
70490
  }
70218
70491
  if (key.escape) {
70219
70492
  onCancel?.();
70493
+ return;
70494
+ }
70495
+ if (input === "1") {
70496
+ onApprove(diffsToPass.size > 0 ? diffsToPass : undefined);
70497
+ return;
70498
+ }
70499
+ if (input === "2" && allowPersistence) {
70500
+ onApproveAlways("project", diffsToPass.size > 0 ? diffsToPass : undefined);
70501
+ return;
70220
70502
  }
70221
70503
  }, { isActive: isFocused });
70222
70504
  const solidLine = SOLID_LINE8.repeat(Math.max(columns, 10));
@@ -70354,12 +70636,13 @@ var init_InlineFileEditApproval = __esm(async () => {
70354
70636
  diffKind
70355
70637
  ]);
70356
70638
  const hintText = isOnCustomOption ? customReason ? "Enter to submit · Esc to clear" : "Type reason · Esc to cancel" : "Enter to select · Esc to cancel";
70639
+ const optionsMarginTop = showPreview ? 1 : 0;
70357
70640
  return /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
70358
70641
  flexDirection: "column",
70359
70642
  children: [
70360
- memoizedDiffContent,
70643
+ showPreview && memoizedDiffContent,
70361
70644
  /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
70362
- marginTop: 1,
70645
+ marginTop: optionsMarginTop,
70363
70646
  flexDirection: "column",
70364
70647
  children: [
70365
70648
  /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
@@ -70499,7 +70782,8 @@ var init_InlineGenericApproval = __esm(async () => {
70499
70782
  onCancel,
70500
70783
  isFocused = true,
70501
70784
  approveAlwaysText,
70502
- allowPersistence = true
70785
+ allowPersistence = true,
70786
+ showPreview = true
70503
70787
  }) => {
70504
70788
  const [selectedOption, setSelectedOption] = import_react39.useState(0);
70505
70789
  const {
@@ -70557,6 +70841,15 @@ var init_InlineGenericApproval = __esm(async () => {
70557
70841
  }
70558
70842
  if (key.escape) {
70559
70843
  onCancel?.();
70844
+ return;
70845
+ }
70846
+ if (input === "1") {
70847
+ onApprove();
70848
+ return;
70849
+ }
70850
+ if (input === "2" && allowPersistence) {
70851
+ onApproveAlways("project");
70852
+ return;
70560
70853
  }
70561
70854
  }, { isActive: isFocused });
70562
70855
  const solidLine = SOLID_LINE9.repeat(Math.max(columns, 10));
@@ -70590,12 +70883,13 @@ var init_InlineGenericApproval = __esm(async () => {
70590
70883
  ]
70591
70884
  }, undefined, true, undefined, this), [toolName, formattedArgs, solidLine]);
70592
70885
  const hintText = isOnCustomOption ? customReason ? "Enter to submit · Esc to clear" : "Type reason · Esc to cancel" : "Enter to select · Esc to cancel";
70886
+ const optionsMarginTop = showPreview ? 1 : 0;
70593
70887
  return /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
70594
70888
  flexDirection: "column",
70595
70889
  children: [
70596
- memoizedToolContent,
70890
+ showPreview && memoizedToolContent,
70597
70891
  /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
70598
- marginTop: 1,
70892
+ marginTop: optionsMarginTop,
70599
70893
  flexDirection: "column",
70600
70894
  children: [
70601
70895
  /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
@@ -71149,6 +71443,15 @@ var init_InlineTaskApproval = __esm(async () => {
71149
71443
  }
71150
71444
  if (key.escape) {
71151
71445
  onCancel?.();
71446
+ return;
71447
+ }
71448
+ if (input === "1") {
71449
+ onApprove();
71450
+ return;
71451
+ }
71452
+ if (input === "2" && allowPersistence) {
71453
+ onApproveAlways("session");
71454
+ return;
71152
71455
  }
71153
71456
  }, { isActive: isFocused });
71154
71457
  const solidLine = SOLID_LINE11.repeat(Math.max(columns, 10));
@@ -71453,6 +71756,15 @@ var init_StaticPlanApproval = __esm(async () => {
71453
71756
  }
71454
71757
  if (key.escape) {
71455
71758
  onKeepPlanning("User cancelled");
71759
+ return;
71760
+ }
71761
+ if (input === "1") {
71762
+ onApproveAndAcceptEdits();
71763
+ return;
71764
+ }
71765
+ if (input === "2") {
71766
+ onApprove();
71767
+ return;
71456
71768
  }
71457
71769
  }, { isActive: isFocused });
71458
71770
  const hintText = isOnCustomOption ? customReason ? "Enter to submit · Esc to clear" : "Type feedback · Esc to cancel" : "Enter to select · Esc to cancel";
@@ -71670,7 +71982,8 @@ var init_ApprovalSwitch = __esm(async () => {
71670
71982
  onEnterPlanModeApprove,
71671
71983
  onEnterPlanModeReject,
71672
71984
  precomputedDiff,
71673
- allDiffs
71985
+ allDiffs,
71986
+ showPreview = true
71674
71987
  }) => {
71675
71988
  const toolName = approval.toolName;
71676
71989
  if (toolName === "ExitPlanMode" && onPlanApprove && onPlanKeepPlanning) {
@@ -71695,7 +72008,8 @@ var init_ApprovalSwitch = __esm(async () => {
71695
72008
  onCancel,
71696
72009
  isFocused,
71697
72010
  approveAlwaysText,
71698
- allowPersistence
72011
+ allowPersistence,
72012
+ showPreview
71699
72013
  }, undefined, false, undefined, this);
71700
72014
  }
71701
72015
  }
@@ -71710,7 +72024,8 @@ var init_ApprovalSwitch = __esm(async () => {
71710
72024
  onCancel,
71711
72025
  isFocused,
71712
72026
  approveAlwaysText,
71713
- allowPersistence
72027
+ allowPersistence,
72028
+ showPreview
71714
72029
  }, undefined, false, undefined, this);
71715
72030
  }
71716
72031
  }
@@ -71723,12 +72038,14 @@ var init_ApprovalSwitch = __esm(async () => {
71723
72038
  }
71724
72039
  if (toolName === "AskUserQuestion" && onQuestionSubmit) {
71725
72040
  const questions = getQuestions(approval);
71726
- return /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(InlineQuestionApproval, {
71727
- questions,
71728
- onSubmit: onQuestionSubmit,
71729
- onCancel,
71730
- isFocused
71731
- }, undefined, false, undefined, this);
72041
+ if (questions.length > 0) {
72042
+ return /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(InlineQuestionApproval, {
72043
+ questions,
72044
+ onSubmit: onQuestionSubmit,
72045
+ onCancel,
72046
+ isFocused
72047
+ }, undefined, false, undefined, this);
72048
+ }
71732
72049
  }
71733
72050
  if (isTaskTool(toolName)) {
71734
72051
  const taskInfo = getTaskInfo(approval);
@@ -71754,7 +72071,8 @@ var init_ApprovalSwitch = __esm(async () => {
71754
72071
  onCancel,
71755
72072
  isFocused,
71756
72073
  approveAlwaysText,
71757
- allowPersistence
72074
+ allowPersistence,
72075
+ showPreview
71758
72076
  }, undefined, false, undefined, this);
71759
72077
  });
71760
72078
  ApprovalSwitch.displayName = "ApprovalSwitch";
@@ -71762,9 +72080,9 @@ var init_ApprovalSwitch = __esm(async () => {
71762
72080
 
71763
72081
  // src/cli/components/AssistantMessageRich.tsx
71764
72082
  var import_react44, jsx_dev_runtime23, normalize6 = (s) => s.replace(/\r\n/g, `
71765
- `).replace(/[ \t]+$/gm, "").replace(/\n{3,}/g, `
72083
+ `).replace(/\n{3,}/g, `
71766
72084
 
71767
- `).replace(/^\n+|\n+$/g, ""), AssistantMessage;
72085
+ `).replace(/^\n+/g, ""), AssistantMessage;
71768
72086
  var init_AssistantMessageRich = __esm(async () => {
71769
72087
  init_useTerminalWidth();
71770
72088
  await __promiseAll([
@@ -72900,14 +73218,6 @@ var init_EventMessage = __esm(async () => {
72900
73218
  color: colors.tool.completed,
72901
73219
  children: "●"
72902
73220
  }, undefined, false, undefined, this);
72903
- const formatArgs2 = () => {
72904
- const stats = line.stats;
72905
- if (stats?.messagesCountBefore !== undefined && stats?.messagesCountAfter !== undefined) {
72906
- return `${stats.messagesCountBefore} → ${stats.messagesCountAfter} messages`;
72907
- }
72908
- return "...";
72909
- };
72910
- const argsDisplay = formatArgs2();
72911
73221
  return /* @__PURE__ */ jsx_dev_runtime33.jsxDEV(Box_default, {
72912
73222
  flexDirection: "column",
72913
73223
  children: [
@@ -72924,16 +73234,12 @@ var init_EventMessage = __esm(async () => {
72924
73234
  width: rightWidth,
72925
73235
  children: isRunning ? /* @__PURE__ */ jsx_dev_runtime33.jsxDEV(CompactingAnimation, {}, undefined, false, undefined, this) : /* @__PURE__ */ jsx_dev_runtime33.jsxDEV(Text2, {
72926
73236
  bold: true,
72927
- children: [
72928
- "Compact(",
72929
- argsDisplay,
72930
- ")"
72931
- ]
72932
- }, undefined, true, undefined, this)
73237
+ children: "Conversation compacted"
73238
+ }, undefined, false, undefined, this)
72933
73239
  }, undefined, false, undefined, this)
72934
73240
  ]
72935
73241
  }, undefined, true, undefined, this),
72936
- !isRunning && line.summary && /* @__PURE__ */ jsx_dev_runtime33.jsxDEV(jsx_dev_runtime33.Fragment, {
73242
+ !isRunning && line.summary && (process.env.LETTA_DEBUG === "1" || process.env.LETTA_DEBUG === "true") && /* @__PURE__ */ jsx_dev_runtime33.jsxDEV(jsx_dev_runtime33.Fragment, {
72937
73243
  children: [
72938
73244
  /* @__PURE__ */ jsx_dev_runtime33.jsxDEV(Box_default, {
72939
73245
  flexDirection: "row",
@@ -74389,10 +74695,10 @@ var init_registry = __esm(() => {
74389
74695
  }
74390
74696
  },
74391
74697
  "/rename": {
74392
- desc: "Rename the current agent (/rename <name>)",
74698
+ desc: "Rename agent or conversation (/rename agent|convo <name>)",
74393
74699
  order: 24,
74394
74700
  handler: () => {
74395
- return "Renaming agent...";
74701
+ return "Renaming...";
74396
74702
  }
74397
74703
  },
74398
74704
  "/description": {
@@ -75052,7 +75358,8 @@ function loadHooksFromLocation(location, workingDirectory = process.cwd()) {
75052
75358
  case "project-local":
75053
75359
  return settingsManager.getLocalProjectSettings(workingDirectory)?.hooks || {};
75054
75360
  }
75055
- } catch {
75361
+ } catch (error) {
75362
+ debugLog("hooks", "loadHooksFromLocation: Settings not loaded yet", error);
75056
75363
  return {};
75057
75364
  }
75058
75365
  }
@@ -75204,7 +75511,8 @@ function countHooksForEvent(event, workingDirectory = process.cwd()) {
75204
75511
  function isUserHooksDisabled() {
75205
75512
  try {
75206
75513
  return settingsManager.getSettings().hooks?.disabled === true;
75207
- } catch {
75514
+ } catch (error) {
75515
+ debugLog("hooks", "isUserHooksDisabled: Failed to check user hooks disabled status", error);
75208
75516
  return false;
75209
75517
  }
75210
75518
  }
@@ -75218,6 +75526,7 @@ function setHooksDisabled(disabled) {
75218
75526
  });
75219
75527
  }
75220
75528
  var init_writer = __esm(async () => {
75529
+ init_debug();
75221
75530
  init_types();
75222
75531
  await init_settings_manager();
75223
75532
  });
@@ -75261,6 +75570,7 @@ var init_HooksManager = __esm(async () => {
75261
75570
  HOOK_EVENTS = [
75262
75571
  { event: "PreToolUse", description: "Before tool execution" },
75263
75572
  { event: "PostToolUse", description: "After tool execution" },
75573
+ { event: "PostToolUseFailure", description: "After tool execution fails" },
75264
75574
  { event: "PermissionRequest", description: "When permission is requested" },
75265
75575
  { event: "UserPromptSubmit", description: "When user submits a prompt" },
75266
75576
  { event: "Notification", description: "When notifications are sent" },
@@ -77738,28 +78048,28 @@ var require_react_jsx_runtime_development = __commonJS((exports) => {
77738
78048
  return null;
77739
78049
  }
77740
78050
  var ReactSharedInternals = React14.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
77741
- function error(format) {
78051
+ function error(format2) {
77742
78052
  {
77743
78053
  {
77744
78054
  for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1;_key2 < _len2; _key2++) {
77745
78055
  args[_key2 - 1] = arguments[_key2];
77746
78056
  }
77747
- printWarning("error", format, args);
78057
+ printWarning("error", format2, args);
77748
78058
  }
77749
78059
  }
77750
78060
  }
77751
- function printWarning(level, format, args) {
78061
+ function printWarning(level, format2, args) {
77752
78062
  {
77753
78063
  var ReactDebugCurrentFrame2 = ReactSharedInternals.ReactDebugCurrentFrame;
77754
78064
  var stack = ReactDebugCurrentFrame2.getStackAddendum();
77755
78065
  if (stack !== "") {
77756
- format += "%s";
78066
+ format2 += "%s";
77757
78067
  args = args.concat([stack]);
77758
78068
  }
77759
78069
  var argsWithFormat = args.map(function(item) {
77760
78070
  return String(item);
77761
78071
  });
77762
- argsWithFormat.unshift("Warning: " + format);
78072
+ argsWithFormat.unshift("Warning: " + format2);
77763
78073
  Function.prototype.apply.call(console[level], console, argsWithFormat);
77764
78074
  }
77765
78075
  }
@@ -85409,9 +85719,9 @@ var init_ProviderSelector = __esm(async () => {
85409
85719
 
85410
85720
  // src/cli/components/ReasoningMessageRich.tsx
85411
85721
  var import_react79, jsx_dev_runtime56, normalize7 = (s) => s.replace(/\r\n/g, `
85412
- `).replace(/[ \t]+$/gm, "").replace(/\n{3,}/g, `
85722
+ `).replace(/\n{3,}/g, `
85413
85723
 
85414
- `).replace(/^\n+|\n+$/g, ""), ReasoningMessage;
85724
+ `).replace(/^\n+/g, ""), ReasoningMessage;
85415
85725
  var init_ReasoningMessageRich = __esm(async () => {
85416
85726
  init_useTerminalWidth();
85417
85727
  await __promiseAll([
@@ -87386,38 +87696,21 @@ var init_ToolCallMessageRich = __esm(async () => {
87386
87696
  }
87387
87697
  }
87388
87698
  const fallback = displayName.length >= rightWidth;
87389
- const getDotElement = () => {
87699
+ const dotColor = (() => {
87390
87700
  switch (line.phase) {
87391
87701
  case "streaming":
87392
- return /* @__PURE__ */ jsx_dev_runtime65.jsxDEV(Text2, {
87393
- color: colors.tool.streaming,
87394
- children: "●"
87395
- }, undefined, false, undefined, this);
87702
+ return colors.tool.streaming;
87396
87703
  case "ready":
87397
- return /* @__PURE__ */ jsx_dev_runtime65.jsxDEV(BlinkDot, {
87398
- color: colors.tool.pending
87399
- }, undefined, false, undefined, this);
87704
+ return colors.tool.pending;
87400
87705
  case "running":
87401
- return /* @__PURE__ */ jsx_dev_runtime65.jsxDEV(BlinkDot, {
87402
- color: colors.tool.running
87403
- }, undefined, false, undefined, this);
87706
+ return colors.tool.running;
87404
87707
  case "finished":
87405
- if (line.resultOk === false) {
87406
- return /* @__PURE__ */ jsx_dev_runtime65.jsxDEV(Text2, {
87407
- color: colors.tool.error,
87408
- children: "●"
87409
- }, undefined, false, undefined, this);
87410
- }
87411
- return /* @__PURE__ */ jsx_dev_runtime65.jsxDEV(Text2, {
87412
- color: colors.tool.completed,
87413
- children: "●"
87414
- }, undefined, false, undefined, this);
87708
+ return line.resultOk === false ? colors.tool.error : colors.tool.completed;
87415
87709
  default:
87416
- return /* @__PURE__ */ jsx_dev_runtime65.jsxDEV(Text2, {
87417
- children: "●"
87418
- }, undefined, false, undefined, this);
87710
+ return;
87419
87711
  }
87420
- };
87712
+ })();
87713
+ const dotShouldAnimate = line.phase === "ready" || line.phase === "running";
87421
87714
  const getResultElement = () => {
87422
87715
  if (!line.resultText)
87423
87716
  return null;
@@ -88003,7 +88296,10 @@ var init_ToolCallMessageRich = __esm(async () => {
88003
88296
  width: 2,
88004
88297
  flexShrink: 0,
88005
88298
  children: [
88006
- getDotElement(),
88299
+ /* @__PURE__ */ jsx_dev_runtime65.jsxDEV(BlinkDot, {
88300
+ color: dotColor,
88301
+ shouldAnimate: dotShouldAnimate
88302
+ }, undefined, false, undefined, this),
88007
88303
  /* @__PURE__ */ jsx_dev_runtime65.jsxDEV(Text2, {}, undefined, false, undefined, this)
88008
88304
  ]
88009
88305
  }, undefined, true, undefined, this),
@@ -90008,12 +90304,48 @@ function isNonStateCommand(msg) {
90008
90304
  }
90009
90305
  return false;
90010
90306
  }
90307
+ function countWrappedLines(text, width) {
90308
+ if (!text)
90309
+ return 0;
90310
+ const wrapWidth = Math.max(1, width);
90311
+ return text.split(/\r?\n/).reduce((sum, line) => {
90312
+ const len = line.length;
90313
+ const wrapped = Math.max(1, Math.ceil(len / wrapWidth));
90314
+ return sum + wrapped;
90315
+ }, 0);
90316
+ }
90317
+ function countWrappedLinesFromList(lines, width) {
90318
+ if (!lines.length)
90319
+ return 0;
90320
+ const wrapWidth = Math.max(1, width);
90321
+ return lines.reduce((sum, line) => {
90322
+ const len = line.length;
90323
+ const wrapped = Math.max(1, Math.ceil(len / wrapWidth));
90324
+ return sum + wrapped;
90325
+ }, 0);
90326
+ }
90327
+ function estimateAdvancedDiffLines(diff2, width) {
90328
+ const wrapWidth = Math.max(1, width);
90329
+ let total = 0;
90330
+ for (const hunk of diff2.hunks) {
90331
+ for (const line of hunk.lines) {
90332
+ const raw = line.raw || "";
90333
+ if (raw.startsWith("\\"))
90334
+ continue;
90335
+ const text = raw.slice(1);
90336
+ total += Math.max(1, Math.ceil(text.length / wrapWidth));
90337
+ }
90338
+ }
90339
+ return total;
90340
+ }
90011
90341
  function uid4(prefix) {
90012
90342
  return `${prefix}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
90013
90343
  }
90014
90344
  function sendDesktopNotification(message = "Awaiting your input", level = "info") {
90015
90345
  process.stdout.write("\x07");
90016
- runNotificationHooks(message, level).catch(() => {});
90346
+ runNotificationHooks(message, level).catch((error) => {
90347
+ debugLog("hooks", "Notification hook error", error);
90348
+ });
90017
90349
  }
90018
90350
  async function isRetriableError(stopReason, lastRunId) {
90019
90351
  if (stopReason === "llm_api_error")
@@ -90498,18 +90830,23 @@ function App2({
90498
90830
  closeTrajectorySegment,
90499
90831
  syncTrajectoryElapsedBase
90500
90832
  ]);
90833
+ const sessionStartFeedbackRef = import_react91.useRef([]);
90501
90834
  import_react91.useEffect(() => {
90502
- if (agentId && !sessionHooksRanRef.current) {
90835
+ if (agentId && agentId !== "loading" && !sessionHooksRanRef.current) {
90503
90836
  sessionHooksRanRef.current = true;
90504
90837
  const isNewSession = !initialConversationId;
90505
- runSessionStartHooks(isNewSession, agentId, agentName ?? undefined, conversationIdRef.current ?? undefined).catch(() => {});
90838
+ runSessionStartHooks(isNewSession, agentId, agentName ?? undefined, conversationIdRef.current ?? undefined).then((result) => {
90839
+ if (result.feedback.length > 0) {
90840
+ sessionStartFeedbackRef.current = result.feedback;
90841
+ }
90842
+ }).catch(() => {});
90506
90843
  }
90507
90844
  }, [agentId, agentName, initialConversationId]);
90508
- import_react91.useEffect(() => {
90509
- return () => {
90510
- const durationMs = Date.now() - sessionStartTimeRef.current;
90511
- runSessionEndHooks(durationMs, undefined, undefined, agentIdRef.current ?? undefined, conversationIdRef.current ?? undefined).catch(() => {});
90512
- };
90845
+ const runEndHooks = import_react91.useCallback(async () => {
90846
+ const durationMs = Date.now() - sessionStartTimeRef.current;
90847
+ try {
90848
+ await runSessionEndHooks(durationMs, undefined, undefined, agentIdRef.current ?? undefined, conversationIdRef.current ?? undefined);
90849
+ } catch {}
90513
90850
  }, []);
90514
90851
  import_react91.useEffect(() => {
90515
90852
  return () => {
@@ -90652,9 +90989,34 @@ function App2({
90652
90989
  setStaticRenderEpoch((epoch) => epoch + 1);
90653
90990
  lastClearedColumnsRef.current = pendingColumns;
90654
90991
  }, [columns, streaming]);
90655
- const commitEligibleLines = import_react91.useCallback((b) => {
90992
+ const deferredToolCallCommitsRef = import_react91.useRef(new Map);
90993
+ const [deferredCommitAt, setDeferredCommitAt] = import_react91.useState(null);
90994
+ const resetDeferredToolCallCommits = import_react91.useCallback(() => {
90995
+ deferredToolCallCommitsRef.current.clear();
90996
+ setDeferredCommitAt(null);
90997
+ }, []);
90998
+ const commitEligibleLines = import_react91.useCallback((b, opts) => {
90999
+ const deferToolCalls = opts?.deferToolCalls !== false;
90656
91000
  const newlyCommitted = [];
90657
91001
  let firstTaskIndex = -1;
91002
+ const deferredCommits = deferredToolCallCommitsRef.current;
91003
+ const now = Date.now();
91004
+ let blockedByDeferred = false;
91005
+ const shouldSkipCommittedToolCall = (ln) => {
91006
+ if (ln.kind !== "tool_call")
91007
+ return false;
91008
+ if (!ln.toolCallId || !ln.name)
91009
+ return false;
91010
+ if (ln.phase !== "finished" || ln.resultOk === false)
91011
+ return false;
91012
+ if (!eagerCommittedPreviewsRef.current.has(ln.toolCallId))
91013
+ return false;
91014
+ return isFileEditTool(ln.name) || isFileWriteTool(ln.name) || isPatchTool(ln.name);
91015
+ };
91016
+ if (!deferToolCalls && deferredCommits.size > 0) {
91017
+ deferredCommits.clear();
91018
+ setDeferredCommitAt(null);
91019
+ }
90658
91020
  const hasInProgress = hasInProgressTaskToolCalls(b.order, b.byId, emittedIdsRef.current);
90659
91021
  const finishedTaskToolCalls = collectFinishedTaskToolCalls(b.order, b.byId, emittedIdsRef.current, hasInProgress);
90660
91022
  for (const id of b.order) {
@@ -90695,11 +91057,32 @@ function App2({
90695
91057
  continue;
90696
91058
  }
90697
91059
  if ("phase" in ln && ln.phase === "finished") {
91060
+ if (shouldSkipCommittedToolCall(ln)) {
91061
+ deferredCommits.delete(id);
91062
+ emittedIdsRef.current.add(id);
91063
+ continue;
91064
+ }
91065
+ if (deferToolCalls && ln.kind === "tool_call" && (!ln.name || !isTaskTool(ln.name))) {
91066
+ const commitAt = deferredCommits.get(id);
91067
+ if (commitAt === undefined) {
91068
+ const nextCommitAt = now + TOOL_CALL_COMMIT_DEFER_MS;
91069
+ deferredCommits.set(id, nextCommitAt);
91070
+ setDeferredCommitAt(nextCommitAt);
91071
+ blockedByDeferred = true;
91072
+ break;
91073
+ }
91074
+ if (commitAt > now) {
91075
+ setDeferredCommitAt(commitAt);
91076
+ blockedByDeferred = true;
91077
+ break;
91078
+ }
91079
+ deferredCommits.delete(id);
91080
+ }
90698
91081
  emittedIdsRef.current.add(id);
90699
91082
  newlyCommitted.push({ ...ln });
90700
91083
  }
90701
91084
  }
90702
- if (finishedTaskToolCalls.length > 0) {
91085
+ if (!blockedByDeferred && finishedTaskToolCalls.length > 0) {
90703
91086
  for (const tc of finishedTaskToolCalls) {
90704
91087
  emittedIdsRef.current.add(tc.lineId);
90705
91088
  }
@@ -90707,6 +91090,9 @@ function App2({
90707
91090
  newlyCommitted.splice(firstTaskIndex >= 0 ? firstTaskIndex : newlyCommitted.length, 0, groupItem);
90708
91091
  clearSubagentsByIds(groupItem.agents.map((a) => a.id));
90709
91092
  }
91093
+ if (deferredCommits.size === 0) {
91094
+ setDeferredCommitAt(null);
91095
+ }
90710
91096
  if (newlyCommitted.length > 0) {
90711
91097
  setStaticItems((prev) => [...prev, ...newlyCommitted]);
90712
91098
  }
@@ -90723,6 +91109,108 @@ function App2({
90723
91109
  const precomputedDiffsRef = import_react91.useRef(new Map);
90724
91110
  const lastPlanFilePathRef = import_react91.useRef(null);
90725
91111
  const eagerCommittedPreviewsRef = import_react91.useRef(new Set);
91112
+ const estimateApprovalPreviewLines = import_react91.useCallback((approval) => {
91113
+ const toolName = approval.toolName;
91114
+ if (!toolName)
91115
+ return 0;
91116
+ const args = safeJsonParseOr(approval.toolArgs || "{}", {});
91117
+ const wrapWidth = Math.max(MIN_WRAP_WIDTH, columns - TEXT_WRAP_GUTTER);
91118
+ const diffWrapWidth = Math.max(MIN_WRAP_WIDTH, columns - DIFF_WRAP_GUTTER);
91119
+ if (isShellTool(toolName)) {
91120
+ const t = toolName.toLowerCase();
91121
+ let command = "(no command)";
91122
+ let description = "";
91123
+ if (t === "shell") {
91124
+ const cmdVal = args.command;
91125
+ command = Array.isArray(cmdVal) ? cmdVal.join(" ") : typeof cmdVal === "string" ? cmdVal : "(no command)";
91126
+ description = typeof args.justification === "string" ? args.justification : "";
91127
+ } else {
91128
+ command = typeof args.command === "string" ? args.command : "(no command)";
91129
+ description = typeof args.description === "string" ? args.description : typeof args.justification === "string" ? args.justification : "";
91130
+ }
91131
+ let lines2 = 3;
91132
+ lines2 += countWrappedLines(command, wrapWidth);
91133
+ if (description) {
91134
+ lines2 += countWrappedLines(description, wrapWidth);
91135
+ }
91136
+ return lines2;
91137
+ }
91138
+ if (isFileEditTool(toolName) || isFileWriteTool(toolName) || isPatchTool(toolName)) {
91139
+ const headerLines = 4;
91140
+ let diffLines2 = 0;
91141
+ const toolCallId = approval.toolCallId;
91142
+ if (isPatchTool(toolName) && typeof args.input === "string") {
91143
+ const operations = parsePatchOperations(args.input);
91144
+ operations.forEach((op, idx) => {
91145
+ if (idx > 0)
91146
+ diffLines2 += 1;
91147
+ diffLines2 += 1;
91148
+ const diffKey = toolCallId ? `${toolCallId}:${op.path}` : undefined;
91149
+ const opDiff = diffKey && precomputedDiffsRef.current.has(diffKey) ? precomputedDiffsRef.current.get(diffKey) : undefined;
91150
+ if (opDiff) {
91151
+ diffLines2 += estimateAdvancedDiffLines(opDiff, diffWrapWidth);
91152
+ return;
91153
+ }
91154
+ if (op.kind === "add") {
91155
+ diffLines2 += countWrappedLines(op.content, wrapWidth);
91156
+ return;
91157
+ }
91158
+ if (op.kind === "update") {
91159
+ if (op.patchLines?.length) {
91160
+ diffLines2 += countWrappedLinesFromList(op.patchLines, wrapWidth);
91161
+ } else {
91162
+ diffLines2 += countWrappedLines(op.oldString || "", wrapWidth);
91163
+ diffLines2 += countWrappedLines(op.newString || "", wrapWidth);
91164
+ }
91165
+ return;
91166
+ }
91167
+ diffLines2 += 1;
91168
+ });
91169
+ return headerLines + diffLines2;
91170
+ }
91171
+ const diff2 = toolCallId && precomputedDiffsRef.current.has(toolCallId) ? precomputedDiffsRef.current.get(toolCallId) : undefined;
91172
+ if (diff2) {
91173
+ diffLines2 += estimateAdvancedDiffLines(diff2, diffWrapWidth);
91174
+ return headerLines + diffLines2;
91175
+ }
91176
+ if (Array.isArray(args.edits)) {
91177
+ for (const edit2 of args.edits) {
91178
+ if (!edit2 || typeof edit2 !== "object")
91179
+ continue;
91180
+ const oldString2 = typeof edit2.old_string === "string" ? edit2.old_string : "";
91181
+ const newString2 = typeof edit2.new_string === "string" ? edit2.new_string : "";
91182
+ diffLines2 += countWrappedLines(oldString2, wrapWidth);
91183
+ diffLines2 += countWrappedLines(newString2, wrapWidth);
91184
+ }
91185
+ return headerLines + diffLines2;
91186
+ }
91187
+ if (typeof args.content === "string") {
91188
+ diffLines2 += countWrappedLines(args.content, wrapWidth);
91189
+ return headerLines + diffLines2;
91190
+ }
91191
+ const oldString = typeof args.old_string === "string" ? args.old_string : "";
91192
+ const newString = typeof args.new_string === "string" ? args.new_string : "";
91193
+ diffLines2 += countWrappedLines(oldString, wrapWidth);
91194
+ diffLines2 += countWrappedLines(newString, wrapWidth);
91195
+ return headerLines + diffLines2;
91196
+ }
91197
+ return 0;
91198
+ }, [columns]);
91199
+ const shouldEagerCommitApprovalPreview = import_react91.useCallback((approval) => {
91200
+ if (!terminalRows)
91201
+ return false;
91202
+ const previewLines = estimateApprovalPreviewLines(approval);
91203
+ if (previewLines === 0)
91204
+ return false;
91205
+ return previewLines + APPROVAL_OPTIONS_HEIGHT + APPROVAL_PREVIEW_BUFFER >= terminalRows;
91206
+ }, [estimateApprovalPreviewLines, terminalRows]);
91207
+ const currentApprovalShouldCommitPreview = import_react91.useMemo(() => {
91208
+ if (!currentApproval)
91209
+ return false;
91210
+ if (currentApproval.toolName === "ExitPlanMode")
91211
+ return false;
91212
+ return shouldEagerCommitApprovalPreview(currentApproval);
91213
+ }, [currentApproval, shouldEagerCommitApprovalPreview]);
90726
91214
  const refreshDerived = import_react91.useCallback(() => {
90727
91215
  const b = buffersRef.current;
90728
91216
  setTokenCount(b.tokenCount);
@@ -90730,6 +91218,16 @@ function App2({
90730
91218
  setLines(newLines);
90731
91219
  commitEligibleLines(b);
90732
91220
  }, [commitEligibleLines]);
91221
+ import_react91.useEffect(() => {
91222
+ if (deferredCommitAt === null)
91223
+ return;
91224
+ const delay = Math.max(0, deferredCommitAt - Date.now());
91225
+ const timer = setTimeout(() => {
91226
+ setDeferredCommitAt(null);
91227
+ refreshDerived();
91228
+ }, delay);
91229
+ return () => clearTimeout(timer);
91230
+ }, [deferredCommitAt, refreshDerived]);
90733
91231
  const streamingRefreshTimeoutRef = import_react91.useRef(null);
90734
91232
  const refreshDerivedStreaming = import_react91.useCallback(() => {
90735
91233
  if (streamingRefreshTimeoutRef.current) {
@@ -90825,6 +91323,31 @@ function App2({
90825
91323
  lastPlanFilePathRef.current = planFilePath;
90826
91324
  } catch {}
90827
91325
  }, [currentApproval]);
91326
+ import_react91.useEffect(() => {
91327
+ if (!currentApproval)
91328
+ return;
91329
+ if (currentApproval.toolName === "ExitPlanMode")
91330
+ return;
91331
+ const toolCallId = currentApproval.toolCallId;
91332
+ if (!toolCallId)
91333
+ return;
91334
+ if (eagerCommittedPreviewsRef.current.has(toolCallId))
91335
+ return;
91336
+ if (!currentApprovalShouldCommitPreview)
91337
+ return;
91338
+ const previewItem = {
91339
+ kind: "approval_preview",
91340
+ id: `approval-preview-${toolCallId}`,
91341
+ toolCallId,
91342
+ toolName: currentApproval.toolName,
91343
+ toolArgs: currentApproval.toolArgs || "{}"
91344
+ };
91345
+ if ((isFileEditTool(currentApproval.toolName) || isFileWriteTool(currentApproval.toolName)) && precomputedDiffsRef.current.has(toolCallId)) {
91346
+ previewItem.precomputedDiff = precomputedDiffsRef.current.get(toolCallId);
91347
+ }
91348
+ setStaticItems((prev) => [...prev, previewItem]);
91349
+ eagerCommittedPreviewsRef.current.add(toolCallId);
91350
+ }, [currentApproval, currentApprovalShouldCommitPreview]);
90828
91351
  import_react91.useEffect(() => {
90829
91352
  if (loadingState === "ready" && messageHistory.length > 0 && !hasBackfilledRef.current) {
90830
91353
  hasBackfilledRef.current = true;
@@ -90886,7 +91409,7 @@ function App2({
90886
91409
  });
90887
91410
  buffersRef.current.order.push(statusId);
90888
91411
  refreshDerived();
90889
- commitEligibleLines(buffersRef.current);
91412
+ commitEligibleLines(buffersRef.current, { deferToolCalls: false });
90890
91413
  }
90891
91414
  }, [
90892
91415
  loadingState,
@@ -91303,6 +91826,7 @@ ${newState.originalPrompt}`
91303
91826
  }
91304
91827
  if (isConversationBusyError(errorDetail) && conversationBusyRetriesRef.current < CONVERSATION_BUSY_MAX_RETRIES2) {
91305
91828
  conversationBusyRetriesRef.current += 1;
91829
+ const retryDelayMs = CONVERSATION_BUSY_RETRY_BASE_DELAY_MS * 2 ** (conversationBusyRetriesRef.current - 1);
91306
91830
  const statusId = uid4("status");
91307
91831
  buffersRef.current.byId.set(statusId, {
91308
91832
  kind: "status",
@@ -91313,7 +91837,7 @@ ${newState.originalPrompt}`
91313
91837
  refreshDerived();
91314
91838
  let cancelled = false;
91315
91839
  const startTime = Date.now();
91316
- while (Date.now() - startTime < CONVERSATION_BUSY_RETRY_DELAY_MS2) {
91840
+ while (Date.now() - startTime < retryDelayMs) {
91317
91841
  if (abortControllerRef.current?.signal.aborted || userCancelledRef.current) {
91318
91842
  cancelled = true;
91319
91843
  break;
@@ -91616,39 +92140,11 @@ ${feedback}
91616
92140
  refreshDerived();
91617
92141
  return;
91618
92142
  }
91619
- const approvalResults2 = await Promise.all(approvalsToProcess.map(async (approvalItem) => {
91620
- if (!approvalItem.toolName) {
91621
- return {
91622
- approval: approvalItem,
91623
- permission: {
91624
- decision: "deny",
91625
- reason: "Tool call incomplete - missing name or arguments"
91626
- },
91627
- context: null
91628
- };
91629
- }
91630
- const parsedArgs = safeJsonParseOr(approvalItem.toolArgs, {});
91631
- const permission = await checkToolPermission(approvalItem.toolName, parsedArgs);
91632
- const context3 = await analyzeToolApproval(approvalItem.toolName, parsedArgs);
91633
- return { approval: approvalItem, permission, context: context3 };
91634
- }));
91635
- const needsUserInput = [];
91636
- const autoDenied = [];
91637
- const autoAllowed = [];
91638
- for (const ac of approvalResults2) {
91639
- const { approval: approval2, permission } = ac;
91640
- let decision = permission.decision;
91641
- if (alwaysRequiresUserInput(approval2.toolName) && decision === "allow") {
91642
- decision = "ask";
91643
- }
91644
- if (decision === "ask") {
91645
- needsUserInput.push(ac);
91646
- } else if (decision === "deny") {
91647
- autoDenied.push(ac);
91648
- } else {
91649
- autoAllowed.push(ac);
91650
- }
91651
- }
92143
+ const { needsUserInput, autoAllowed, autoDenied } = await classifyApprovals(approvalsToProcess, {
92144
+ getContext: analyzeToolApproval,
92145
+ alwaysRequiresUserInput,
92146
+ missingNameReason: "Tool call incomplete - missing name or arguments"
92147
+ });
91652
92148
  for (const ac of [...autoAllowed, ...needsUserInput]) {
91653
92149
  const toolName = ac.approval.toolName;
91654
92150
  const toolCallId = ac.approval.toolCallId;
@@ -92133,6 +92629,7 @@ ${feedback}
92133
92629
  ]);
92134
92630
  const handleExit = import_react91.useCallback(async () => {
92135
92631
  saveLastAgentBeforeExit();
92632
+ await runEndHooks();
92136
92633
  const stats = sessionStatsRef.current.getSnapshot();
92137
92634
  telemetry2.trackSessionEnd(stats, "exit_command");
92138
92635
  await telemetry2.flush();
@@ -92140,7 +92637,7 @@ ${feedback}
92140
92637
  setTimeout(() => {
92141
92638
  process.exit(0);
92142
92639
  }, 100);
92143
- }, []);
92640
+ }, [runEndHooks]);
92144
92641
  const handleEnterQueueEditMode = import_react91.useCallback(() => {
92145
92642
  setMessageQueue([]);
92146
92643
  }, []);
@@ -92364,6 +92861,7 @@ ${feedback}
92364
92861
  buffersRef.current.order = [];
92365
92862
  buffersRef.current.tokenCount = 0;
92366
92863
  emittedIdsRef.current.clear();
92864
+ resetDeferredToolCallCommits();
92367
92865
  setStaticItems([]);
92368
92866
  setStaticRenderEpoch((e) => e + 1);
92369
92867
  resetTrajectoryBases();
@@ -92421,6 +92919,7 @@ ${feedback}
92421
92919
  agentName,
92422
92920
  setCommandRunning,
92423
92921
  isAgentBusy,
92922
+ resetDeferredToolCallCommits,
92424
92923
  resetTrajectoryBases
92425
92924
  ]);
92426
92925
  const handleCreateNewAgent = import_react91.useCallback(async (name) => {
@@ -92444,6 +92943,7 @@ ${feedback}
92444
92943
  buffersRef.current.order = [];
92445
92944
  buffersRef.current.tokenCount = 0;
92446
92945
  emittedIdsRef.current.clear();
92946
+ resetDeferredToolCallCommits();
92447
92947
  setStaticItems([]);
92448
92948
  setStaticRenderEpoch((e) => e + 1);
92449
92949
  resetTrajectoryBases();
@@ -92487,7 +92987,13 @@ ${feedback}
92487
92987
  } finally {
92488
92988
  setCommandRunning(false);
92489
92989
  }
92490
- }, [refreshDerived, agentId, setCommandRunning, resetTrajectoryBases]);
92990
+ }, [
92991
+ refreshDerived,
92992
+ agentId,
92993
+ setCommandRunning,
92994
+ resetDeferredToolCallCommits,
92995
+ resetTrajectoryBases
92996
+ ]);
92491
92997
  const handleBashSubmit = import_react91.useCallback(async (command) => {
92492
92998
  if (bashRunning)
92493
92999
  return;
@@ -92592,39 +93098,11 @@ ${expanded.command}` : expanded.command;
92592
93098
  if (!existingApprovals || existingApprovals.length === 0) {
92593
93099
  return { blocked: false };
92594
93100
  }
92595
- const approvalResults2 = await Promise.all(existingApprovals.map(async (approvalItem) => {
92596
- if (!approvalItem.toolName) {
92597
- return {
92598
- approval: approvalItem,
92599
- permission: {
92600
- decision: "deny",
92601
- reason: "Tool call incomplete - missing name"
92602
- },
92603
- context: null
92604
- };
92605
- }
92606
- const parsedArgs = safeJsonParseOr(approvalItem.toolArgs, {});
92607
- const permission = await checkToolPermission(approvalItem.toolName, parsedArgs);
92608
- const context3 = await analyzeToolApproval(approvalItem.toolName, parsedArgs);
92609
- return { approval: approvalItem, permission, context: context3 };
92610
- }));
92611
- const needsUserInput = [];
92612
- const autoAllowed = [];
92613
- const autoDenied = [];
92614
- for (const ac of approvalResults2) {
92615
- const { approval, permission } = ac;
92616
- let decision = permission.decision;
92617
- if (alwaysRequiresUserInput(approval.toolName) && decision === "allow") {
92618
- decision = "ask";
92619
- }
92620
- if (decision === "ask") {
92621
- needsUserInput.push(ac);
92622
- } else if (decision === "deny") {
92623
- autoDenied.push(ac);
92624
- } else {
92625
- autoAllowed.push(ac);
92626
- }
92627
- }
93101
+ const { needsUserInput, autoAllowed, autoDenied } = await classifyApprovals(existingApprovals, {
93102
+ getContext: analyzeToolApproval,
93103
+ alwaysRequiresUserInput,
93104
+ missingNameReason: "Tool call incomplete - missing name"
93105
+ });
92628
93106
  if (needsUserInput.length > 0) {
92629
93107
  setPendingApprovals(needsUserInput.map((ac) => ac.approval));
92630
93108
  setApprovalContexts(needsUserInput.map((ac) => ac.context).filter((ctx) => ctx !== null));
@@ -93181,6 +93659,7 @@ Type your task to begin the loop.`,
93181
93659
  buffersRef.current.order.push(cmdId);
93182
93660
  refreshDerived();
93183
93661
  setCommandRunning(true);
93662
+ await runEndHooks();
93184
93663
  try {
93185
93664
  const client = await getClient2();
93186
93665
  const conversation = await client.conversations.create({
@@ -93194,6 +93673,13 @@ Type your task to begin the loop.`,
93194
93673
  conversationId: conversation.id
93195
93674
  });
93196
93675
  turnCountRef.current = 0;
93676
+ sessionHooksRanRef.current = false;
93677
+ runSessionStartHooks(true, agentId, agentName ?? undefined, conversation.id).then((result2) => {
93678
+ if (result2.feedback.length > 0) {
93679
+ sessionStartFeedbackRef.current = result2.feedback;
93680
+ }
93681
+ }).catch(() => {});
93682
+ sessionHooksRanRef.current = true;
93197
93683
  buffersRef.current.byId.set(cmdId, {
93198
93684
  kind: "command",
93199
93685
  id: cmdId,
@@ -93232,6 +93718,7 @@ Type your task to begin the loop.`,
93232
93718
  buffersRef.current.order.push(cmdId);
93233
93719
  refreshDerived();
93234
93720
  setCommandRunning(true);
93721
+ await runEndHooks();
93235
93722
  try {
93236
93723
  const client = await getClient2();
93237
93724
  await client.agents.messages.reset(agentId, {
@@ -93248,6 +93735,13 @@ Type your task to begin the loop.`,
93248
93735
  conversationId: conversation.id
93249
93736
  });
93250
93737
  turnCountRef.current = 0;
93738
+ sessionHooksRanRef.current = false;
93739
+ runSessionStartHooks(true, agentId, agentName ?? undefined, conversation.id).then((result2) => {
93740
+ if (result2.feedback.length > 0) {
93741
+ sessionStartFeedbackRef.current = result2.feedback;
93742
+ }
93743
+ }).catch(() => {});
93744
+ sessionHooksRanRef.current = true;
93251
93745
  buffersRef.current.byId.set(cmdId, {
93252
93746
  kind: "command",
93253
93747
  id: cmdId,
@@ -93354,14 +93848,29 @@ Type your task to begin the loop.`,
93354
93848
  }
93355
93849
  if (msg.trim().startsWith("/rename")) {
93356
93850
  const parts = msg.trim().split(/\s+/);
93357
- const newName = parts.slice(1).join(" ");
93358
- if (!newName) {
93851
+ const subcommand = parts[1]?.toLowerCase();
93852
+ if (!subcommand || subcommand !== "agent" && subcommand !== "convo") {
93853
+ const cmdId2 = uid4("cmd");
93854
+ buffersRef.current.byId.set(cmdId2, {
93855
+ kind: "command",
93856
+ id: cmdId2,
93857
+ input: msg,
93858
+ output: "Usage: /rename agent <name> or /rename convo <summary>",
93859
+ phase: "finished",
93860
+ success: false
93861
+ });
93862
+ buffersRef.current.order.push(cmdId2);
93863
+ refreshDerived();
93864
+ return { submitted: true };
93865
+ }
93866
+ const newValue = parts.slice(2).join(" ");
93867
+ if (!newValue) {
93359
93868
  const cmdId2 = uid4("cmd");
93360
93869
  buffersRef.current.byId.set(cmdId2, {
93361
93870
  kind: "command",
93362
93871
  id: cmdId2,
93363
93872
  input: msg,
93364
- output: "Please provide a new name: /rename <name>",
93873
+ output: subcommand === "convo" ? "Please provide a summary: /rename convo <summary>" : "Please provide a name: /rename agent <name>",
93365
93874
  phase: "finished",
93366
93875
  success: false
93367
93876
  });
@@ -93369,7 +93878,49 @@ Type your task to begin the loop.`,
93369
93878
  refreshDerived();
93370
93879
  return { submitted: true };
93371
93880
  }
93372
- const validationError = validateAgentName(newName);
93881
+ if (subcommand === "convo") {
93882
+ const cmdId2 = uid4("cmd");
93883
+ buffersRef.current.byId.set(cmdId2, {
93884
+ kind: "command",
93885
+ id: cmdId2,
93886
+ input: msg,
93887
+ output: `Renaming conversation to "${newValue}"...`,
93888
+ phase: "running"
93889
+ });
93890
+ buffersRef.current.order.push(cmdId2);
93891
+ refreshDerived();
93892
+ setCommandRunning(true);
93893
+ try {
93894
+ const client = await getClient2();
93895
+ await client.conversations.update(conversationId, {
93896
+ summary: newValue
93897
+ });
93898
+ buffersRef.current.byId.set(cmdId2, {
93899
+ kind: "command",
93900
+ id: cmdId2,
93901
+ input: msg,
93902
+ output: `Conversation renamed to "${newValue}"`,
93903
+ phase: "finished",
93904
+ success: true
93905
+ });
93906
+ refreshDerived();
93907
+ } catch (error) {
93908
+ const errorDetails = formatErrorDetails(error, agentId);
93909
+ buffersRef.current.byId.set(cmdId2, {
93910
+ kind: "command",
93911
+ id: cmdId2,
93912
+ input: msg,
93913
+ output: `Failed: ${errorDetails}`,
93914
+ phase: "finished",
93915
+ success: false
93916
+ });
93917
+ refreshDerived();
93918
+ } finally {
93919
+ setCommandRunning(false);
93920
+ }
93921
+ return { submitted: true };
93922
+ }
93923
+ const validationError = validateAgentName(newValue);
93373
93924
  if (validationError) {
93374
93925
  const cmdId2 = uid4("cmd");
93375
93926
  buffersRef.current.byId.set(cmdId2, {
@@ -93389,7 +93940,7 @@ Type your task to begin the loop.`,
93389
93940
  kind: "command",
93390
93941
  id: cmdId,
93391
93942
  input: msg,
93392
- output: `Renaming agent to "${newName}"...`,
93943
+ output: `Renaming agent to "${newValue}"...`,
93393
93944
  phase: "running"
93394
93945
  });
93395
93946
  buffersRef.current.order.push(cmdId);
@@ -93397,13 +93948,13 @@ Type your task to begin the loop.`,
93397
93948
  setCommandRunning(true);
93398
93949
  try {
93399
93950
  const client = await getClient2();
93400
- await client.agents.update(agentId, { name: newName });
93401
- updateAgentName(newName);
93951
+ await client.agents.update(agentId, { name: newValue });
93952
+ updateAgentName(newValue);
93402
93953
  buffersRef.current.byId.set(cmdId, {
93403
93954
  kind: "command",
93404
93955
  id: cmdId,
93405
93956
  input: msg,
93406
- output: `Agent renamed to "${newName}"`,
93957
+ output: `Agent renamed to "${newValue}"`,
93407
93958
  phase: "finished",
93408
93959
  success: true
93409
93960
  });
@@ -93529,6 +94080,7 @@ Type your task to begin the loop.`,
93529
94080
  buffersRef.current.order = [];
93530
94081
  buffersRef.current.tokenCount = 0;
93531
94082
  emittedIdsRef.current.clear();
94083
+ resetDeferredToolCallCommits();
93532
94084
  setStaticItems([]);
93533
94085
  setStaticRenderEpoch((e) => e + 1);
93534
94086
  resetTrajectoryBases();
@@ -94357,6 +94909,17 @@ ${SYSTEM_REMINDER_CLOSE}`
94357
94909
  });
94358
94910
  hasSentSessionContextRef.current = true;
94359
94911
  }
94912
+ let sessionStartHookFeedback = "";
94913
+ if (sessionStartFeedbackRef.current.length > 0) {
94914
+ sessionStartHookFeedback = `${SYSTEM_REMINDER_OPEN}
94915
+ [SessionStart hook context]:
94916
+ ${sessionStartFeedbackRef.current.join(`
94917
+ `)}
94918
+ ${SYSTEM_REMINDER_CLOSE}
94919
+
94920
+ `;
94921
+ sessionStartFeedbackRef.current = [];
94922
+ }
94360
94923
  let bashCommandPrefix = "";
94361
94924
  if (bashCommandCacheRef.current.length > 0) {
94362
94925
  bashCommandPrefix = `${SYSTEM_REMINDER_OPEN}
@@ -94419,7 +94982,7 @@ ${SYSTEM_REMINDER_CLOSE}
94419
94982
  `;
94420
94983
  lastNotifiedModeRef.current = currentMode;
94421
94984
  }
94422
- const allReminders = sessionContextReminder + permissionModeAlert + planModeReminder + ralphModeReminder + skillUnloadReminder + bashCommandPrefix + userPromptSubmitHookFeedback + memoryReminderContent + memfsConflictReminder;
94985
+ const allReminders = sessionContextReminder + sessionStartHookFeedback + permissionModeAlert + planModeReminder + ralphModeReminder + skillUnloadReminder + bashCommandPrefix + userPromptSubmitHookFeedback + memoryReminderContent + memfsConflictReminder;
94423
94986
  const messageContent = allReminders && typeof contentParts === "string" ? allReminders + contentParts : Array.isArray(contentParts) && allReminders ? [{ type: "text", text: allReminders }, ...contentParts] : contentParts;
94424
94987
  const userId = uid4("user");
94425
94988
  buffersRef.current.byId.set(userId, {
@@ -94467,22 +95030,11 @@ ${SYSTEM_REMINDER_CLOSE}
94467
95030
  return { submitted: false };
94468
95031
  }
94469
95032
  if (existingApprovals && existingApprovals.length > 0) {
94470
- const approvalResults2 = await Promise.all(existingApprovals.map(async (approvalItem) => {
94471
- if (!approvalItem.toolName) {
94472
- return {
94473
- approval: approvalItem,
94474
- permission: {
94475
- decision: "deny",
94476
- reason: "Tool call incomplete - missing name"
94477
- },
94478
- context: null
94479
- };
94480
- }
94481
- const parsedArgs = safeJsonParseOr(approvalItem.toolArgs, {});
94482
- const permission = await checkToolPermission(approvalItem.toolName, parsedArgs);
94483
- const context3 = await analyzeToolApproval(approvalItem.toolName, parsedArgs);
94484
- return { approval: approvalItem, permission, context: context3 };
94485
- }));
95033
+ const { needsUserInput, autoAllowed, autoDenied } = await classifyApprovals(existingApprovals, {
95034
+ getContext: analyzeToolApproval,
95035
+ alwaysRequiresUserInput,
95036
+ missingNameReason: "Tool call incomplete - missing name"
95037
+ });
94486
95038
  if (userCancelledRef.current || abortControllerRef.current?.signal.aborted) {
94487
95039
  buffersRef.current.byId.delete(userId);
94488
95040
  const orderIndex = buffersRef.current.order.indexOf(userId);
@@ -94493,23 +95045,6 @@ ${SYSTEM_REMINDER_CLOSE}
94493
95045
  refreshDerived();
94494
95046
  return { submitted: false };
94495
95047
  }
94496
- const needsUserInput = [];
94497
- const autoAllowed = [];
94498
- const autoDenied = [];
94499
- for (const ac of approvalResults2) {
94500
- const { approval, permission } = ac;
94501
- let decision = permission.decision;
94502
- if (alwaysRequiresUserInput(approval.toolName) && decision === "allow") {
94503
- decision = "ask";
94504
- }
94505
- if (decision === "ask") {
94506
- needsUserInput.push(ac);
94507
- } else if (decision === "deny") {
94508
- autoDenied.push(ac);
94509
- } else {
94510
- autoAllowed.push(ac);
94511
- }
94512
- }
94513
95048
  if (needsUserInput.length === 0) {
94514
95049
  for (const ac of [...autoAllowed, ...needsUserInput]) {
94515
95050
  const toolName = ac.approval.toolName;
@@ -94925,8 +95460,12 @@ ${SYSTEM_REMINDER_CLOSE}
94925
95460
  ...approvalResultsSnapshot,
94926
95461
  ...additionalDecision ? [additionalDecision] : []
94927
95462
  ];
94928
- executingToolCallIdsRef.current = allDecisions.filter((decision) => decision.type === "approve").map((decision) => decision.approval.toolCallId);
94929
- setToolCallsRunning(buffersRef.current, allDecisions.filter((d) => d.type === "approve").map((d) => d.approval.toolCallId));
95463
+ const approvedDecisions = allDecisions.filter((decision) => decision.type === "approve");
95464
+ const runningDecisions = approvedDecisions.filter((decision) => !decision.precomputedResult);
95465
+ executingToolCallIdsRef.current = runningDecisions.map((decision) => decision.approval.toolCallId);
95466
+ if (runningDecisions.length > 0) {
95467
+ setToolCallsRunning(buffersRef.current, runningDecisions.map((d) => d.approval.toolCallId));
95468
+ }
94930
95469
  refreshDerived();
94931
95470
  const { executeApprovalBatch: executeApprovalBatch2 } = await init_approval_execution().then(() => exports_approval_execution);
94932
95471
  sessionStatsRef.current.startTrajectory();
@@ -95278,7 +95817,7 @@ ${SYSTEM_REMINDER_CLOSE}
95278
95817
  let selectedModel = models2.find((m) => m.id === modelId);
95279
95818
  if (!selectedModel && modelId.includes("/")) {
95280
95819
  const { getModelContextWindow: getModelContextWindow2 } = await init_available_models().then(() => exports_available_models);
95281
- const apiContextWindow = getModelContextWindow2(modelId);
95820
+ const apiContextWindow = await getModelContextWindow2(modelId);
95282
95821
  selectedModel = {
95283
95822
  id: modelId,
95284
95823
  handle: modelId,
@@ -95942,9 +96481,6 @@ Consider switching to a different system prompt using /system to match.` : null;
95942
96481
  });
95943
96482
  setThinkingMessage(getRandomThinkingVerb());
95944
96483
  refreshDerived();
95945
- if (approval.toolCallId) {
95946
- eagerCommittedPreviewsRef.current.add(approval.toolCallId);
95947
- }
95948
96484
  const decision = {
95949
96485
  type: "approve",
95950
96486
  approval,
@@ -96031,6 +96567,8 @@ Plan file path: ${planFilePath}`;
96031
96567
  return lines.filter((ln) => {
96032
96568
  if (!("phase" in ln))
96033
96569
  return false;
96570
+ if (emittedIdsRef.current.has(ln.id))
96571
+ return false;
96034
96572
  if (ln.kind === "command" || ln.kind === "bash_command") {
96035
96573
  return ln.phase === "running";
96036
96574
  }
@@ -96038,7 +96576,7 @@ Plan file path: ${planFilePath}`;
96038
96576
  if (ln.name && isTaskTool(ln.name)) {
96039
96577
  return ln.phase === "ready" || ln.phase === "streaming";
96040
96578
  }
96041
- return ln.phase !== "finished";
96579
+ return ln.phase !== "finished" || deferredToolCallCommitsRef.current.has(ln.id);
96042
96580
  }
96043
96581
  if (ln.kind === "event") {
96044
96582
  return ln.phase === "running";
@@ -96047,7 +96585,7 @@ Plan file path: ${planFilePath}`;
96047
96585
  return false;
96048
96586
  return ln.phase === "streaming";
96049
96587
  });
96050
- }, [lines, tokenStreamingEnabled]);
96588
+ }, [lines, tokenStreamingEnabled, staticItems.length, deferredCommitAt]);
96051
96589
  const { agents: subagents } = import_react91.useSyncExternalStore(subscribe2, getSnapshot2);
96052
96590
  const shouldAnimate = import_react91.useMemo(() => {
96053
96591
  const countLines4 = (text) => {
@@ -96125,7 +96663,7 @@ Plan file path: ${planFilePath}`;
96125
96663
  });
96126
96664
  buffersRef.current.order.push(statusId);
96127
96665
  refreshDerived();
96128
- commitEligibleLines(buffersRef.current);
96666
+ commitEligibleLines(buffersRef.current, { deferToolCalls: false });
96129
96667
  }
96130
96668
  }, [
96131
96669
  loadingState,
@@ -96146,6 +96684,8 @@ Plan file path: ${planFilePath}`;
96146
96684
  const trajectoryTokenDisplay = Math.max(liveTrajectoryTokenBase + runTokenDelta, trajectoryTokenDisplayRef.current);
96147
96685
  const inputVisible = !showExitStats;
96148
96686
  const inputEnabled = !showExitStats && pendingApprovals.length === 0 && !anySelectorOpen;
96687
+ const currentApprovalPreviewCommitted = currentApproval?.toolCallId ? eagerCommittedPreviewsRef.current.has(currentApproval.toolCallId) : false;
96688
+ const showApprovalPreview = !currentApprovalShouldCommitPreview && !currentApprovalPreviewCommitted;
96149
96689
  import_react91.useEffect(() => {
96150
96690
  trajectoryTokenDisplayRef.current = trajectoryTokenDisplay;
96151
96691
  }, [trajectoryTokenDisplay]);
@@ -96155,51 +96695,53 @@ Plan file path: ${planFilePath}`;
96155
96695
  /* @__PURE__ */ jsx_dev_runtime69.jsxDEV(Static, {
96156
96696
  items: staticItems,
96157
96697
  style: { flexDirection: "column" },
96158
- children: (item, index) => /* @__PURE__ */ jsx_dev_runtime69.jsxDEV(Box_default, {
96159
- marginTop: index > 0 ? 1 : 0,
96160
- children: item.kind === "welcome" ? /* @__PURE__ */ jsx_dev_runtime69.jsxDEV(WelcomeScreen, {
96161
- loadingState: "ready",
96162
- ...item.snapshot
96163
- }, undefined, false, undefined, this) : item.kind === "user" ? /* @__PURE__ */ jsx_dev_runtime69.jsxDEV(UserMessage, {
96164
- line: item
96165
- }, undefined, false, undefined, this) : item.kind === "reasoning" ? /* @__PURE__ */ jsx_dev_runtime69.jsxDEV(ReasoningMessage, {
96166
- line: item
96167
- }, undefined, false, undefined, this) : item.kind === "assistant" ? /* @__PURE__ */ jsx_dev_runtime69.jsxDEV(AssistantMessage, {
96168
- line: item
96169
- }, undefined, false, undefined, this) : item.kind === "tool_call" ? /* @__PURE__ */ jsx_dev_runtime69.jsxDEV(ToolCallMessage, {
96170
- line: item,
96171
- precomputedDiffs: precomputedDiffsRef.current,
96172
- lastPlanFilePath: lastPlanFilePathRef.current
96173
- }, undefined, false, undefined, this) : item.kind === "subagent_group" ? /* @__PURE__ */ jsx_dev_runtime69.jsxDEV(SubagentGroupStatic, {
96174
- agents: item.agents
96175
- }, undefined, false, undefined, this) : item.kind === "error" ? /* @__PURE__ */ jsx_dev_runtime69.jsxDEV(ErrorMessage, {
96176
- line: item
96177
- }, undefined, false, undefined, this) : item.kind === "status" ? /* @__PURE__ */ jsx_dev_runtime69.jsxDEV(StatusMessage, {
96178
- line: item
96179
- }, undefined, false, undefined, this) : item.kind === "event" ? /* @__PURE__ */ jsx_dev_runtime69.jsxDEV(EventMessage, {
96180
- line: item
96181
- }, undefined, false, undefined, this) : item.kind === "separator" ? /* @__PURE__ */ jsx_dev_runtime69.jsxDEV(Box_default, {
96182
- marginTop: 1,
96183
- children: /* @__PURE__ */ jsx_dev_runtime69.jsxDEV(Text2, {
96184
- dimColor: true,
96185
- children: "─".repeat(columns)
96186
- }, undefined, false, undefined, this)
96187
- }, undefined, false, undefined, this) : item.kind === "command" ? /* @__PURE__ */ jsx_dev_runtime69.jsxDEV(CommandMessage, {
96188
- line: item
96189
- }, undefined, false, undefined, this) : item.kind === "bash_command" ? /* @__PURE__ */ jsx_dev_runtime69.jsxDEV(BashCommandMessage, {
96190
- line: item
96191
- }, undefined, false, undefined, this) : item.kind === "trajectory_summary" ? /* @__PURE__ */ jsx_dev_runtime69.jsxDEV(TrajectorySummary, {
96192
- line: item
96193
- }, undefined, false, undefined, this) : item.kind === "approval_preview" ? /* @__PURE__ */ jsx_dev_runtime69.jsxDEV(ApprovalPreview, {
96194
- toolName: item.toolName,
96195
- toolArgs: item.toolArgs,
96196
- precomputedDiff: item.precomputedDiff,
96197
- allDiffs: precomputedDiffsRef.current,
96198
- planContent: item.planContent,
96199
- planFilePath: item.planFilePath,
96200
- toolCallId: item.toolCallId
96201
- }, undefined, false, undefined, this) : null
96202
- }, item.id, false, undefined, this)
96698
+ children: (item, index) => {
96699
+ return /* @__PURE__ */ jsx_dev_runtime69.jsxDEV(Box_default, {
96700
+ marginTop: index > 0 ? 1 : 0,
96701
+ children: item.kind === "welcome" ? /* @__PURE__ */ jsx_dev_runtime69.jsxDEV(WelcomeScreen, {
96702
+ loadingState: "ready",
96703
+ ...item.snapshot
96704
+ }, undefined, false, undefined, this) : item.kind === "user" ? /* @__PURE__ */ jsx_dev_runtime69.jsxDEV(UserMessage, {
96705
+ line: item
96706
+ }, undefined, false, undefined, this) : item.kind === "reasoning" ? /* @__PURE__ */ jsx_dev_runtime69.jsxDEV(ReasoningMessage, {
96707
+ line: item
96708
+ }, undefined, false, undefined, this) : item.kind === "assistant" ? /* @__PURE__ */ jsx_dev_runtime69.jsxDEV(AssistantMessage, {
96709
+ line: item
96710
+ }, undefined, false, undefined, this) : item.kind === "tool_call" ? /* @__PURE__ */ jsx_dev_runtime69.jsxDEV(ToolCallMessage, {
96711
+ line: item,
96712
+ precomputedDiffs: precomputedDiffsRef.current,
96713
+ lastPlanFilePath: lastPlanFilePathRef.current
96714
+ }, undefined, false, undefined, this) : item.kind === "subagent_group" ? /* @__PURE__ */ jsx_dev_runtime69.jsxDEV(SubagentGroupStatic, {
96715
+ agents: item.agents
96716
+ }, undefined, false, undefined, this) : item.kind === "error" ? /* @__PURE__ */ jsx_dev_runtime69.jsxDEV(ErrorMessage, {
96717
+ line: item
96718
+ }, undefined, false, undefined, this) : item.kind === "status" ? /* @__PURE__ */ jsx_dev_runtime69.jsxDEV(StatusMessage, {
96719
+ line: item
96720
+ }, undefined, false, undefined, this) : item.kind === "event" ? /* @__PURE__ */ jsx_dev_runtime69.jsxDEV(EventMessage, {
96721
+ line: item
96722
+ }, undefined, false, undefined, this) : item.kind === "separator" ? /* @__PURE__ */ jsx_dev_runtime69.jsxDEV(Box_default, {
96723
+ marginTop: 1,
96724
+ children: /* @__PURE__ */ jsx_dev_runtime69.jsxDEV(Text2, {
96725
+ dimColor: true,
96726
+ children: "─".repeat(columns)
96727
+ }, undefined, false, undefined, this)
96728
+ }, undefined, false, undefined, this) : item.kind === "command" ? /* @__PURE__ */ jsx_dev_runtime69.jsxDEV(CommandMessage, {
96729
+ line: item
96730
+ }, undefined, false, undefined, this) : item.kind === "bash_command" ? /* @__PURE__ */ jsx_dev_runtime69.jsxDEV(BashCommandMessage, {
96731
+ line: item
96732
+ }, undefined, false, undefined, this) : item.kind === "trajectory_summary" ? /* @__PURE__ */ jsx_dev_runtime69.jsxDEV(TrajectorySummary, {
96733
+ line: item
96734
+ }, undefined, false, undefined, this) : item.kind === "approval_preview" ? /* @__PURE__ */ jsx_dev_runtime69.jsxDEV(ApprovalPreview, {
96735
+ toolName: item.toolName,
96736
+ toolArgs: item.toolArgs,
96737
+ precomputedDiff: item.precomputedDiff,
96738
+ allDiffs: precomputedDiffsRef.current,
96739
+ planContent: item.planContent,
96740
+ planFilePath: item.planFilePath,
96741
+ toolCallId: item.toolCallId
96742
+ }, undefined, false, undefined, this) : null
96743
+ }, item.id, false, undefined, this);
96744
+ }
96203
96745
  }, staticRenderEpoch, false, undefined, this),
96204
96746
  /* @__PURE__ */ jsx_dev_runtime69.jsxDEV(Box_default, {
96205
96747
  flexDirection: "column",
@@ -96217,10 +96759,12 @@ Plan file path: ${planFilePath}`;
96217
96759
  liveItems.length > 0 && /* @__PURE__ */ jsx_dev_runtime69.jsxDEV(Box_default, {
96218
96760
  flexDirection: "column",
96219
96761
  children: liveItems.map((ln) => {
96220
- if (ln.kind === "tool_call" && ln.name && isTaskTool(ln.name) && ln.toolCallId && !pendingIds.has(ln.toolCallId) && ln.toolCallId !== currentApproval?.toolCallId) {
96762
+ const isFileTool = ln.kind === "tool_call" && ln.name && (isFileEditTool(ln.name) || isFileWriteTool(ln.name) || isPatchTool(ln.name));
96763
+ const isApprovalTracked = ln.kind === "tool_call" && ln.toolCallId && (ln.toolCallId === currentApproval?.toolCallId || pendingIds.has(ln.toolCallId) || queuedIds.has(ln.toolCallId));
96764
+ if (isFileTool && !isApprovalTracked) {
96221
96765
  return null;
96222
96766
  }
96223
- if (ln.kind === "tool_call" && ln.toolCallId && eagerCommittedPreviewsRef.current.has(ln.toolCallId) && ln.toolCallId !== currentApproval?.toolCallId) {
96767
+ if (ln.kind === "tool_call" && ln.name && isTaskTool(ln.name) && ln.toolCallId && !pendingIds.has(ln.toolCallId) && ln.toolCallId !== currentApproval?.toolCallId) {
96224
96768
  return null;
96225
96769
  }
96226
96770
  const matchesCurrentApproval = ln.kind === "tool_call" && currentApproval && ln.toolCallId === currentApproval.toolCallId;
@@ -96242,7 +96786,8 @@ Plan file path: ${planFilePath}`;
96242
96786
  allDiffs: precomputedDiffsRef.current,
96243
96787
  isFocused: true,
96244
96788
  approveAlwaysText: currentApprovalContext?.approveAlwaysText,
96245
- allowPersistence: currentApprovalContext?.allowPersistence ?? true
96789
+ allowPersistence: currentApprovalContext?.allowPersistence ?? true,
96790
+ showPreview: showApprovalPreview
96246
96791
  }, undefined, false, undefined, this) : ln.kind === "user" ? /* @__PURE__ */ jsx_dev_runtime69.jsxDEV(UserMessage, {
96247
96792
  line: ln
96248
96793
  }, undefined, false, undefined, this) : ln.kind === "reasoning" ? /* @__PURE__ */ jsx_dev_runtime69.jsxDEV(ReasoningMessage, {
@@ -96291,7 +96836,8 @@ Plan file path: ${planFilePath}`;
96291
96836
  allDiffs: precomputedDiffsRef.current,
96292
96837
  isFocused: true,
96293
96838
  approveAlwaysText: currentApprovalContext?.approveAlwaysText,
96294
- allowPersistence: currentApprovalContext?.allowPersistence ?? true
96839
+ allowPersistence: currentApprovalContext?.allowPersistence ?? true,
96840
+ showPreview: showApprovalPreview
96295
96841
  }, undefined, false, undefined, this)
96296
96842
  }, undefined, false, undefined, this),
96297
96843
  /* @__PURE__ */ jsx_dev_runtime69.jsxDEV(SubagentGroupDisplay, {}, undefined, false, undefined, this)
@@ -96543,6 +97089,7 @@ Plan file path: ${planFilePath}`;
96543
97089
  buffersRef.current.order = [];
96544
97090
  buffersRef.current.tokenCount = 0;
96545
97091
  emittedIdsRef.current.clear();
97092
+ resetDeferredToolCallCommits();
96546
97093
  setStaticItems([]);
96547
97094
  setStaticRenderEpoch((e) => e + 1);
96548
97095
  resetTrajectoryBases();
@@ -96665,6 +97212,7 @@ Plan file path: ${planFilePath}`;
96665
97212
  buffersRef.current.order = [];
96666
97213
  buffersRef.current.tokenCount = 0;
96667
97214
  emittedIdsRef.current.clear();
97215
+ resetDeferredToolCallCommits();
96668
97216
  setStaticItems([]);
96669
97217
  setStaticRenderEpoch((e) => e + 1);
96670
97218
  resetTrajectoryBases();
@@ -96764,6 +97312,7 @@ Plan file path: ${planFilePath}`;
96764
97312
  buffersRef.current.order = [];
96765
97313
  buffersRef.current.tokenCount = 0;
96766
97314
  emittedIdsRef.current.clear();
97315
+ resetDeferredToolCallCommits();
96767
97316
  setStaticItems([]);
96768
97317
  setStaticRenderEpoch((e) => e + 1);
96769
97318
  resetTrajectoryBases();
@@ -96982,7 +97531,7 @@ Open /mcp to attach or detach tools for this server.`,
96982
97531
  ]
96983
97532
  }, resumeKey, true, undefined, this);
96984
97533
  }
96985
- var import_react91, jsx_dev_runtime69, CLEAR_SCREEN_AND_HOME = "\x1B[2J\x1B[H", MIN_RESIZE_DELTA = 2, EAGER_CANCEL = true, LLM_API_ERROR_MAX_RETRIES2 = 3, CONVERSATION_BUSY_MAX_RETRIES2 = 1, CONVERSATION_BUSY_RETRY_DELAY_MS2 = 2500, INTERRUPT_MESSAGE = "Interrupted – tell the agent what to do differently. Something went wrong? Use /feedback to report issues.", ERROR_FEEDBACK_HINT = "Something went wrong? Use /feedback to report issues.", OPUS_BEDROCK_FALLBACK_HINT = "Downstream provider issues? Use /model to switch to Bedrock Opus 4.5", PROVIDER_FALLBACK_HINT = "Downstream provider issues? Use /model to switch to another provider", INTERACTIVE_SLASH_COMMANDS, NON_STATE_COMMANDS;
97534
+ var import_react91, jsx_dev_runtime69, CLEAR_SCREEN_AND_HOME = "\x1B[2J\x1B[H", MIN_RESIZE_DELTA = 2, TOOL_CALL_COMMIT_DEFER_MS = 50, EAGER_CANCEL = true, LLM_API_ERROR_MAX_RETRIES2 = 3, CONVERSATION_BUSY_MAX_RETRIES2 = 3, CONVERSATION_BUSY_RETRY_BASE_DELAY_MS = 2500, INTERRUPT_MESSAGE = "Interrupted – tell the agent what to do differently. Something went wrong? Use /feedback to report issues.", ERROR_FEEDBACK_HINT = "Something went wrong? Use /feedback to report issues.", OPUS_BEDROCK_FALLBACK_HINT = "Downstream provider issues? Use /model to switch to Bedrock Opus 4.5", PROVIDER_FALLBACK_HINT = "Downstream provider issues? Use /model to switch to another provider", INTERACTIVE_SLASH_COMMANDS, NON_STATE_COMMANDS, APPROVAL_OPTIONS_HEIGHT = 8, APPROVAL_PREVIEW_BUFFER = 4, MIN_WRAP_WIDTH = 10, TEXT_WRAP_GUTTER = 6, DIFF_WRAP_GUTTER = 12;
96986
97535
  var init_App2 = __esm(async () => {
96987
97536
  init_error();
96988
97537
  init_check_approval();
@@ -96995,6 +97544,7 @@ var init_App2 = __esm(async () => {
96995
97544
  init_mode();
96996
97545
  init_mode2();
96997
97546
  init_settings();
97547
+ init_debug();
96998
97548
  init_colors();
96999
97549
  init_SessionStats();
97000
97550
  init_AnimationContext();
@@ -97062,6 +97612,7 @@ var init_App2 = __esm(async () => {
97062
97612
  init_UserMessageRich(),
97063
97613
  init_WelcomeScreen(),
97064
97614
  init_accumulator(),
97615
+ init_approvalClassification(),
97065
97616
  init_memoryReminder(),
97066
97617
  init_sessionContext(),
97067
97618
  init_stream(),
@@ -97853,7 +98404,7 @@ async function createAgent2(nameOrOptions = DEFAULT_AGENT_NAME, model, embedding
97853
98404
  blockProvenance.push({ label: blockId, source: "shared" });
97854
98405
  }
97855
98406
  const modelUpdateArgs = getModelUpdateArgs(modelHandle);
97856
- const contextWindow = modelUpdateArgs?.context_window;
98407
+ const contextWindow = modelUpdateArgs?.context_window ?? await getModelContextWindow(modelHandle);
97857
98408
  let systemPromptContent;
97858
98409
  if (options.systemPromptCustom) {
97859
98410
  systemPromptContent = options.systemPromptCustom;
@@ -97926,6 +98477,7 @@ var init_create3 = __esm(async () => {
97926
98477
  init_promptAssets();
97927
98478
  init_skills2();
97928
98479
  await __promiseAll([
98480
+ init_available_models(),
97929
98481
  init_client2(),
97930
98482
  init_modify()
97931
98483
  ]);
@@ -98069,7 +98621,7 @@ function buildModelSettings2(modelHandle, updateArgs) {
98069
98621
  async function updateAgentLLMConfig2(agentId, modelHandle, updateArgs) {
98070
98622
  const client = await getClient2();
98071
98623
  const modelSettings = buildModelSettings2(modelHandle, updateArgs);
98072
- const contextWindow = updateArgs?.context_window;
98624
+ const contextWindow = updateArgs?.context_window ?? await getModelContextWindow(modelHandle);
98073
98625
  const hasModelSettings = Object.keys(modelSettings).length > 0;
98074
98626
  await client.agents.update(agentId, {
98075
98627
  model: modelHandle,
@@ -98151,6 +98703,7 @@ async function updateAgentSystemPromptMemfs2(agentId, enableMemfs) {
98151
98703
  var init_modify2 = __esm(async () => {
98152
98704
  await __promiseAll([
98153
98705
  init_openai_codex_provider(),
98706
+ init_available_models(),
98154
98707
  init_client2()
98155
98708
  ]);
98156
98709
  });
@@ -98247,6 +98800,7 @@ class InternalServerError extends APIError {
98247
98800
 
98248
98801
  // src/agent/check-approval.ts
98249
98802
  init_error();
98803
+ init_debug();
98250
98804
  var MESSAGE_HISTORY_LIMIT = 15;
98251
98805
  function isBackfillEnabled() {
98252
98806
  const val = process.env.LETTA_BACKFILL;
@@ -100815,6 +101369,7 @@ class PermissionModeManager {
100815
101369
  var permissionMode = new PermissionModeManager;
100816
101370
 
100817
101371
  // src/settings-manager.ts
101372
+ init_debug();
100818
101373
  init_fs();
100819
101374
  await init_secrets();
100820
101375
  import { homedir as homedir6 } from "node:os";
@@ -100914,7 +101469,7 @@ class SettingsManager2 {
100914
101469
  }
100915
101470
  this.settings = updatedSettings;
100916
101471
  await this.persistSettings();
100917
- console.log("Successfully migrated tokens to secrets");
101472
+ debugWarn("settings", "Successfully migrated tokens to secrets");
100918
101473
  } catch (error) {
100919
101474
  console.warn("Failed to migrate tokens to secrets:", error);
100920
101475
  console.warn("Tokens will remain in settings file for persistence");
@@ -101843,6 +102398,7 @@ var telemetry = new TelemetryManager;
101843
102398
  init_model();
101844
102399
  init_subagents();
101845
102400
  init_constants();
102401
+ init_debug();
101846
102402
  await __promiseAll([
101847
102403
  init_approval_execution(),
101848
102404
  init_hooks(),
@@ -103415,4 +103971,4 @@ Error during initialization: ${message}`);
103415
103971
  }
103416
103972
  main();
103417
103973
 
103418
- //# debugId=ECD33F3765BB3B7864756E2164756E21
103974
+ //# debugId=E6B9011D5A418C2E64756E2164756E21