@letta-ai/letta-code 0.14.14 → 0.14.15

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
@@ -3122,7 +3122,7 @@ var package_default;
3122
3122
  var init_package = __esm(() => {
3123
3123
  package_default = {
3124
3124
  name: "@letta-ai/letta-code",
3125
- version: "0.14.14",
3125
+ version: "0.14.15",
3126
3126
  description: "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
3127
3127
  type: "module",
3128
3128
  bin: {
@@ -5649,7 +5649,6 @@ Your memory consists of memory blocks and external memory:
5649
5649
  - Memory Blocks: Stored as memory blocks, each containing a label (title), description (explaining how this block should influence your behavior), and value (the actual content). Memory blocks have size limits. Memory blocks are embedded within your system instructions and remain constantly available in-context.
5650
5650
  - External memory: Additional memory storage that is accessible and that you can bring into context with tools when needed.
5651
5651
 
5652
- Memory management tools allow you to edit existing memory blocks and query for external memories.
5653
5652
  Memory blocks are used to modulate and augment your base behavior, follow them closely, and maintain them cleanly.
5654
5653
  They are the foundation which makes you *you*.
5655
5654
 
@@ -29235,6 +29234,12 @@ var create = (stream, { showCursor = false } = {}) => {
29235
29234
  let previousLineCount = 0;
29236
29235
  let previousOutput = "";
29237
29236
  let hasHiddenCursor = false;
29237
+ const renderWithClearedLineEnds = (output) => {
29238
+ const lines = output.split(`
29239
+ `);
29240
+ return lines.map((line) => line + exports_base.eraseEndLine).join(`
29241
+ `);
29242
+ };
29238
29243
  const render = (str) => {
29239
29244
  if (!showCursor && !hasHiddenCursor) {
29240
29245
  cli_cursor_default.hide();
@@ -29245,10 +29250,17 @@ var create = (stream, { showCursor = false } = {}) => {
29245
29250
  if (output === previousOutput) {
29246
29251
  return;
29247
29252
  }
29248
- previousOutput = output;
29249
- stream.write(exports_base.eraseLines(previousLineCount) + output);
29250
- previousLineCount = output.split(`
29253
+ const nextLineCount = output.split(`
29251
29254
  `).length;
29255
+ if (previousLineCount > 1) {
29256
+ stream.write(exports_base.cursorUp(previousLineCount - 1));
29257
+ }
29258
+ stream.write(renderWithClearedLineEnds(output));
29259
+ if (nextLineCount < previousLineCount) {
29260
+ stream.write(exports_base.eraseDown);
29261
+ }
29262
+ previousOutput = output;
29263
+ previousLineCount = nextLineCount;
29252
29264
  };
29253
29265
  render.clear = () => {
29254
29266
  stream.write(exports_base.eraseLines(previousLineCount));
@@ -31103,7 +31115,7 @@ var init_colors = __esm(() => {
31103
31115
  inline: "green"
31104
31116
  },
31105
31117
  link: {
31106
- text: "cyan",
31118
+ text: brandColors.primaryAccentLight,
31107
31119
  url: brandColors.primaryAccent
31108
31120
  },
31109
31121
  heading: {
@@ -33160,7 +33172,8 @@ var init_models2 = __esm(() => {
33160
33172
  isFeatured: true,
33161
33173
  free: true,
33162
33174
  updateArgs: {
33163
- context_window: 180000
33175
+ context_window: 160000,
33176
+ max_output_tokens: 64000
33164
33177
  }
33165
33178
  },
33166
33179
  {
@@ -33169,7 +33182,8 @@ var init_models2 = __esm(() => {
33169
33182
  label: "Minimax M2",
33170
33183
  description: "Minimax's latest model",
33171
33184
  updateArgs: {
33172
- context_window: 196000
33185
+ context_window: 160000,
33186
+ max_output_tokens: 64000
33173
33187
  }
33174
33188
  },
33175
33189
  {
@@ -54856,12 +54870,14 @@ async function executeSubagent(type, config, model, userPrompt, baseURL, subagen
54856
54870
  return executeSubagent(type, config, primaryModel, userPrompt, baseURL, subagentId, true, signal, undefined, undefined, maxTurns);
54857
54871
  }
54858
54872
  }
54873
+ const propagatedError = state.finalError?.trim();
54874
+ const fallbackError = stderr || `Subagent exited with code ${exitCode}`;
54859
54875
  return {
54860
54876
  agentId: state.agentId || "",
54861
54877
  conversationId: state.conversationId || undefined,
54862
54878
  report: "",
54863
54879
  success: false,
54864
- error: stderr || `Subagent exited with code ${exitCode}`
54880
+ error: propagatedError || fallbackError
54865
54881
  };
54866
54882
  }
54867
54883
  if (state.finalResult !== null) {
@@ -55053,6 +55069,34 @@ function extractTaskNotificationsForDisplay(message) {
55053
55069
  }
55054
55070
 
55055
55071
  // src/tools/impl/Task.ts
55072
+ function buildTaskResultHeader(subagentType, result) {
55073
+ return [
55074
+ `subagent_type=${subagentType}`,
55075
+ result.agentId ? `agent_id=${result.agentId}` : undefined,
55076
+ result.conversationId ? `conversation_id=${result.conversationId}` : undefined
55077
+ ].filter(Boolean).join(" ");
55078
+ }
55079
+ function writeTaskTranscriptStart(outputFile, description, subagentType) {
55080
+ appendToOutputFile(outputFile, `[Task started: ${description}]
55081
+ [subagent_type: ${subagentType}]
55082
+
55083
+ `);
55084
+ }
55085
+ function writeTaskTranscriptResult(outputFile, result, header) {
55086
+ if (result.success) {
55087
+ appendToOutputFile(outputFile, `${header}
55088
+
55089
+ ${result.report}
55090
+
55091
+ [Task completed]
55092
+ `);
55093
+ return;
55094
+ }
55095
+ appendToOutputFile(outputFile, `[error] ${result.error || "Subagent execution failed"}
55096
+
55097
+ [Task failed]
55098
+ `);
55099
+ }
55056
55100
  async function task(args) {
55057
55101
  const { command = "run", model, toolCallId, signal } = args;
55058
55102
  if (command === "refresh") {
@@ -55091,7 +55135,7 @@ async function task(args) {
55091
55135
  registerSubagent(subagentId, subagent_type, description, toolCallId, isBackground);
55092
55136
  if (isBackground) {
55093
55137
  const taskId = getNextTaskId();
55094
- const outputFile = createBackgroundOutputFile(taskId);
55138
+ const outputFile2 = createBackgroundOutputFile(taskId);
55095
55139
  const abortController = new AbortController;
55096
55140
  const bgTask = {
55097
55141
  description,
@@ -55100,37 +55144,21 @@ async function task(args) {
55100
55144
  status: "running",
55101
55145
  output: [],
55102
55146
  startTime: new Date,
55103
- outputFile,
55147
+ outputFile: outputFile2,
55104
55148
  abortController
55105
55149
  };
55106
55150
  backgroundTasks.set(taskId, bgTask);
55107
- appendToOutputFile(outputFile, `[Task started: ${description}]
55108
- [subagent_type: ${subagent_type}]
55109
-
55110
- `);
55151
+ writeTaskTranscriptStart(outputFile2, description, subagent_type);
55111
55152
  spawnSubagent(subagent_type, prompt, model, subagentId, abortController.signal, args.agent_id, args.conversation_id, args.max_turns).then((result) => {
55112
55153
  bgTask.status = result.success ? "completed" : "failed";
55113
55154
  if (result.error) {
55114
55155
  bgTask.error = result.error;
55115
55156
  }
55116
- const header = [
55117
- `subagent_type=${subagent_type}`,
55118
- result.agentId ? `agent_id=${result.agentId}` : undefined,
55119
- result.conversationId ? `conversation_id=${result.conversationId}` : undefined
55120
- ].filter(Boolean).join(" ");
55157
+ const header = buildTaskResultHeader(subagent_type, result);
55158
+ writeTaskTranscriptResult(outputFile2, result, header);
55121
55159
  if (result.success) {
55122
- appendToOutputFile(outputFile, `${header}
55123
-
55124
- ${result.report}
55125
- `);
55126
55160
  bgTask.output.push(result.report || "");
55127
- } else {
55128
- appendToOutputFile(outputFile, `[error] ${result.error || "Subagent execution failed"}
55129
- `);
55130
55161
  }
55131
- appendToOutputFile(outputFile, `
55132
- [Task ${result.success ? "completed" : "failed"}]
55133
- `);
55134
55162
  completeSubagent(subagentId, {
55135
55163
  success: result.success,
55136
55164
  error: result.error,
@@ -55149,7 +55177,7 @@ ${result.report || ""}` : result.error || "Subagent execution failed";
55149
55177
  status: result.success ? "completed" : "failed",
55150
55178
  summary: `Agent "${description}" ${result.success ? "completed" : "failed"}`,
55151
55179
  result: truncatedResult,
55152
- outputFile,
55180
+ outputFile: outputFile2,
55153
55181
  usage: {
55154
55182
  totalTokens: result.totalTokens,
55155
55183
  toolUses,
@@ -55162,7 +55190,7 @@ ${result.report || ""}` : result.error || "Subagent execution failed";
55162
55190
  const errorMessage = error instanceof Error ? error.message : String(error);
55163
55191
  bgTask.status = "failed";
55164
55192
  bgTask.error = errorMessage;
55165
- appendToOutputFile(outputFile, `[error] ${errorMessage}
55193
+ appendToOutputFile(outputFile2, `[error] ${errorMessage}
55166
55194
  `);
55167
55195
  completeSubagent(subagentId, { success: false, error: errorMessage });
55168
55196
  const subagentSnapshot = getSnapshot2();
@@ -55173,7 +55201,7 @@ ${result.report || ""}` : result.error || "Subagent execution failed";
55173
55201
  status: "failed",
55174
55202
  summary: `Agent "${description}" failed`,
55175
55203
  result: errorMessage,
55176
- outputFile,
55204
+ outputFile: outputFile2,
55177
55205
  usage: {
55178
55206
  toolUses,
55179
55207
  durationMs
@@ -55183,8 +55211,11 @@ ${result.report || ""}` : result.error || "Subagent execution failed";
55183
55211
  runSubagentStopHooks(subagent_type, subagentId, false, errorMessage, args.agent_id, args.conversation_id).catch(() => {});
55184
55212
  });
55185
55213
  return `Task running in background with ID: ${taskId}
55186
- Output file: ${outputFile}`;
55214
+ Output file: ${outputFile2}`;
55187
55215
  }
55216
+ const foregroundTaskId = getNextTaskId();
55217
+ const outputFile = createBackgroundOutputFile(foregroundTaskId);
55218
+ writeTaskTranscriptStart(outputFile, description, subagent_type);
55188
55219
  try {
55189
55220
  const result = await spawnSubagent(subagent_type, prompt, model, subagentId, signal, args.agent_id, args.conversation_id, args.max_turns);
55190
55221
  completeSubagent(subagentId, {
@@ -55194,24 +55225,34 @@ Output file: ${outputFile}`;
55194
55225
  });
55195
55226
  runSubagentStopHooks(subagent_type, subagentId, result.success, result.error, result.agentId, result.conversationId).catch(() => {});
55196
55227
  if (!result.success) {
55197
- return `Error: ${result.error || "Subagent execution failed"}`;
55228
+ const errorMessage = result.error || "Subagent execution failed";
55229
+ const failedResult = {
55230
+ ...result,
55231
+ error: errorMessage
55232
+ };
55233
+ writeTaskTranscriptResult(outputFile, failedResult, "");
55234
+ return `Error: ${errorMessage}
55235
+ Output file: ${outputFile}`;
55198
55236
  }
55199
- const header = [
55200
- `subagent_type=${subagent_type}`,
55201
- result.agentId ? `agent_id=${result.agentId}` : undefined,
55202
- result.conversationId ? `conversation_id=${result.conversationId}` : undefined
55203
- ].filter(Boolean).join(" ");
55237
+ const header = buildTaskResultHeader(subagent_type, result);
55204
55238
  const fullOutput = `${header}
55205
55239
 
55206
55240
  ${result.report}`;
55241
+ writeTaskTranscriptResult(outputFile, result, header);
55207
55242
  const userCwd = process.env.USER_CWD || process.cwd();
55208
55243
  const { content: truncatedOutput } = truncateByChars(fullOutput, LIMITS.TASK_OUTPUT_CHARS, "Task", { workingDirectory: userCwd, toolName: "Task" });
55209
- return truncatedOutput;
55244
+ return `${truncatedOutput}
55245
+ Output file: ${outputFile}`;
55210
55246
  } catch (error) {
55211
55247
  const errorMessage = error instanceof Error ? error.message : String(error);
55212
55248
  completeSubagent(subagentId, { success: false, error: errorMessage });
55213
55249
  runSubagentStopHooks(subagent_type, subagentId, false, errorMessage, args.agent_id, args.conversation_id).catch(() => {});
55214
- return `Error: ${errorMessage}`;
55250
+ appendToOutputFile(outputFile, `[error] ${errorMessage}
55251
+
55252
+ [Task failed]
55253
+ `);
55254
+ return `Error: ${errorMessage}
55255
+ Output file: ${outputFile}`;
55215
55256
  }
55216
55257
  }
55217
55258
  var VALID_DEPLOY_TYPES;
@@ -58591,6 +58632,7 @@ var exports_analyzer = {};
58591
58632
  __export(exports_analyzer, {
58592
58633
  analyzeApprovalContext: () => analyzeApprovalContext
58593
58634
  });
58635
+ import { homedir as homedir11 } from "node:os";
58594
58636
  import { dirname as dirname8, resolve as resolve15 } from "node:path";
58595
58637
  function analyzeApprovalContext(toolName, toolArgs, workingDirectory) {
58596
58638
  const resolveFilePath = () => {
@@ -58691,7 +58733,85 @@ function containsDangerousCommand(command) {
58691
58733
  }
58692
58734
  return false;
58693
58735
  }
58694
- function analyzeBashApproval(command, _workingDir) {
58736
+ function escapeRegex(text) {
58737
+ return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
58738
+ }
58739
+ function normalizePathSeparators(path18) {
58740
+ return path18.replace(/\\/g, "/");
58741
+ }
58742
+ function parseAbsoluteCommandPaths(command) {
58743
+ const normalized = command.replace(/\\"/g, '"').replace(/\\'/g, "'");
58744
+ const candidates = [];
58745
+ const quotedRegex = /["']((?:[A-Za-z]:)?\/[^"']+)["']/g;
58746
+ let quotedMatch = quotedRegex.exec(normalized);
58747
+ while (quotedMatch) {
58748
+ if (quotedMatch[1]) {
58749
+ candidates.push(normalizePathSeparators(quotedMatch[1]));
58750
+ }
58751
+ quotedMatch = quotedRegex.exec(normalized);
58752
+ }
58753
+ const tokens = normalized.split(/\s+/);
58754
+ for (const token of tokens) {
58755
+ const cleaned = token.replace(/^["'`([{]+/, "").replace(/["'`),;|\]}]+$/g, "");
58756
+ if (/^(?:[A-Za-z]:)?\//.test(cleaned)) {
58757
+ candidates.push(normalizePathSeparators(cleaned));
58758
+ }
58759
+ }
58760
+ return Array.from(new Set(candidates));
58761
+ }
58762
+ function detectSkillScript(command, workingDir) {
58763
+ const pathCandidates = parseAbsoluteCommandPaths(command);
58764
+ if (pathCandidates.length === 0) {
58765
+ return null;
58766
+ }
58767
+ const normalizedWorkingDir = normalizePathSeparators(workingDir).replace(/\/$/, "");
58768
+ const normalizedHomeDir = normalizePathSeparators(homedir11()).replace(/\/$/, "");
58769
+ const detect = (source, regex2) => {
58770
+ for (const candidate of pathCandidates) {
58771
+ const match3 = candidate.match(regex2);
58772
+ if (!match3?.[1]) {
58773
+ continue;
58774
+ }
58775
+ const skillName = match3[1];
58776
+ const skillRootPath = match3[0].replace(/\/scripts\/$/, "");
58777
+ return { source, skillName, skillRootPath };
58778
+ }
58779
+ return null;
58780
+ };
58781
+ const projectRegex = new RegExp(`^${escapeRegex(normalizedWorkingDir)}/\\.skills/(.+?)/scripts/`);
58782
+ const projectSkill = detect("project", projectRegex);
58783
+ if (projectSkill) {
58784
+ return projectSkill;
58785
+ }
58786
+ const agentRegex = new RegExp(`^${escapeRegex(normalizedHomeDir)}/\\.letta/agents/[^/]+/skills/(.+?)/scripts/`);
58787
+ const agentSkill = detect("agent-scoped", agentRegex);
58788
+ if (agentSkill) {
58789
+ return agentSkill;
58790
+ }
58791
+ const globalRegex = new RegExp(`^${escapeRegex(normalizedHomeDir)}/\\.letta/skills/(.+?)/scripts/`);
58792
+ const globalSkill = detect("global", globalRegex);
58793
+ if (globalSkill) {
58794
+ return globalSkill;
58795
+ }
58796
+ const bundledSkill = detect("bundled", /\/skills\/builtin\/([^/]+)\/scripts\//);
58797
+ if (bundledSkill) {
58798
+ return bundledSkill;
58799
+ }
58800
+ return null;
58801
+ }
58802
+ function buildSkillScriptRule(command, skillRootPath) {
58803
+ const normalizedCommand = normalizePathSeparators(command).trim();
58804
+ const rootIndex = normalizedCommand.indexOf(skillRootPath);
58805
+ if (rootIndex === -1) {
58806
+ return `Bash(${normalizedCommand})`;
58807
+ }
58808
+ const rulePrefix = normalizedCommand.slice(0, rootIndex + skillRootPath.length);
58809
+ return `Bash(${rulePrefix}:*)`;
58810
+ }
58811
+ function getSkillApprovalText(source, skillName) {
58812
+ return `Yes, and don't ask again for scripts in ${source} skill '${skillName}'`;
58813
+ }
58814
+ function analyzeBashApproval(command, workingDir) {
58695
58815
  const parts = command.trim().split(/\s+/);
58696
58816
  const baseCommand = parts[0] || "";
58697
58817
  const firstArg = parts[1] || "";
@@ -58715,6 +58835,18 @@ function analyzeBashApproval(command, _workingDir) {
58715
58835
  safetyLevel: "dangerous"
58716
58836
  };
58717
58837
  }
58838
+ const skillScript = detectSkillScript(command, workingDir);
58839
+ if (skillScript) {
58840
+ const { source, skillName, skillRootPath } = skillScript;
58841
+ return {
58842
+ recommendedRule: buildSkillScriptRule(command, skillRootPath),
58843
+ ruleDescription: `scripts in ${source} skill '${skillName}'`,
58844
+ approveAlwaysText: getSkillApprovalText(source, skillName),
58845
+ defaultScope: "project",
58846
+ allowPersistence: true,
58847
+ safetyLevel: "moderate"
58848
+ };
58849
+ }
58718
58850
  if (baseCommand === "git") {
58719
58851
  const gitSubcommand = firstArg;
58720
58852
  const safeGitCommands = ["status", "diff", "log", "show", "branch"];
@@ -63864,6 +63996,49 @@ var init_errorContext = __esm(() => {
63864
63996
  });
63865
63997
 
63866
63998
  // src/cli/helpers/errorFormatter.ts
63999
+ function extractReasonList(value) {
64000
+ if (!Array.isArray(value))
64001
+ return [];
64002
+ return value.filter((reason) => typeof reason === "string").map((reason) => reason.toLowerCase());
64003
+ }
64004
+ function getErrorReasons(e) {
64005
+ const reasons = new Set;
64006
+ const errorBody = e.error;
64007
+ if (errorBody && typeof errorBody === "object") {
64008
+ const body = errorBody;
64009
+ for (const reason of extractReasonList(body.reasons)) {
64010
+ reasons.add(reason);
64011
+ }
64012
+ if (body.error && typeof body.error === "object") {
64013
+ const nested = body.error;
64014
+ for (const reason of extractReasonList(nested.reasons)) {
64015
+ reasons.add(reason);
64016
+ }
64017
+ }
64018
+ }
64019
+ const message = e.message?.toLowerCase() ?? "";
64020
+ for (const knownReason of [
64021
+ "not-enough-credits",
64022
+ "model-unknown",
64023
+ "byok-not-available-on-free-tier",
64024
+ "free-usage-exceeded",
64025
+ "premium-usage-exceeded",
64026
+ "standard-usage-exceeded",
64027
+ "basic-usage-exceeded",
64028
+ "context-window-size-not-supported",
64029
+ "agents-limit-exceeded",
64030
+ "exceeded-quota"
64031
+ ]) {
64032
+ if (message.includes(knownReason)) {
64033
+ reasons.add(knownReason);
64034
+ }
64035
+ }
64036
+ return Array.from(reasons);
64037
+ }
64038
+ function hasErrorReason(e, reason, reasons) {
64039
+ const allReasons = reasons ?? getErrorReasons(e);
64040
+ return allReasons.includes(reason.toLowerCase());
64041
+ }
63867
64042
  function getRateLimitResetMs(e) {
63868
64043
  if (e.status !== 429)
63869
64044
  return;
@@ -63917,52 +64092,26 @@ function getResourceLimitMessage(e) {
63917
64092
  }
63918
64093
  return;
63919
64094
  }
63920
- function isAgentLimitError(e) {
64095
+ function isAgentLimitError(e, reasons) {
63921
64096
  if (e.status !== 429)
63922
64097
  return false;
63923
- const errorBody = e.error;
63924
- if (errorBody && typeof errorBody === "object") {
63925
- if ("reasons" in errorBody && Array.isArray(errorBody.reasons)) {
63926
- if (errorBody.reasons.includes("agents-limit-exceeded")) {
63927
- return true;
63928
- }
63929
- }
63930
- }
63931
- return false;
64098
+ return hasErrorReason(e, "agents-limit-exceeded", reasons);
63932
64099
  }
63933
- function isCreditExhaustedError(e) {
64100
+ function isCreditExhaustedError(e, reasons) {
63934
64101
  if (e.status !== 402)
63935
64102
  return false;
63936
- const errorBody = e.error;
63937
- if (errorBody && typeof errorBody === "object") {
63938
- if ("reasons" in errorBody && Array.isArray(errorBody.reasons)) {
63939
- if (errorBody.reasons.includes("not-enough-credits")) {
63940
- return true;
63941
- }
63942
- }
63943
- if ("error" in errorBody && typeof errorBody.error === "object") {
63944
- const nested = errorBody.error;
63945
- if ("reasons" in nested && Array.isArray(nested.reasons)) {
63946
- if (nested.reasons.includes("not-enough-credits")) {
63947
- return true;
63948
- }
63949
- }
63950
- }
63951
- }
63952
- if (e.message?.includes("not-enough-credits")) {
63953
- return true;
63954
- }
63955
- return false;
64103
+ return hasErrorReason(e, "not-enough-credits", reasons);
63956
64104
  }
63957
64105
  function formatErrorDetails(e, agentId, conversationId) {
63958
64106
  let runId;
63959
64107
  if (e instanceof APIError2) {
64108
+ const reasons = getErrorReasons(e);
63960
64109
  const rateLimitResetMs = getRateLimitResetMs(e);
63961
64110
  if (rateLimitResetMs !== undefined) {
63962
64111
  const resetInfo = rateLimitResetMs > 0 ? formatResetTime(rateLimitResetMs) : "Try again later";
63963
64112
  return `You've hit your usage limit. ${resetInfo}. View usage: ${LETTA_USAGE_URL}`;
63964
64113
  }
63965
- if (isAgentLimitError(e)) {
64114
+ if (isAgentLimitError(e, reasons)) {
63966
64115
  const { billingTier } = getErrorContext();
63967
64116
  if (billingTier?.toLowerCase() === "free") {
63968
64117
  return `You've reached the agent limit (3) for the Free Plan. Delete agents at: ${LETTA_AGENTS_URL}
@@ -63971,6 +64120,12 @@ Or upgrade to Pro for unlimited agents at: ${LETTA_USAGE_URL}`;
63971
64120
  return `You've reached your agent limit. Delete agents at: ${LETTA_AGENTS_URL}
63972
64121
  Or check your plan at: ${LETTA_USAGE_URL}`;
63973
64122
  }
64123
+ if (hasErrorReason(e, "model-unknown", reasons)) {
64124
+ return `The selected model is not currently available for this account or provider. Run /model and press R to refresh available models, then choose an available model or connect a provider with /connect.`;
64125
+ }
64126
+ if (hasErrorReason(e, "context-window-size-not-supported", reasons)) {
64127
+ return `The selected context window is not supported for this model. Switch models with /model or pick a model with a larger context window.`;
64128
+ }
63974
64129
  const resourceLimitMsg = getResourceLimitMessage(e);
63975
64130
  if (resourceLimitMsg) {
63976
64131
  const match3 = resourceLimitMsg.match(/limit for (\w+)/);
@@ -63979,13 +64134,19 @@ Or check your plan at: ${LETTA_USAGE_URL}`;
63979
64134
  Upgrade at: ${LETTA_USAGE_URL}
63980
64135
  Delete ${resourceType} at: ${LETTA_AGENTS_URL}`;
63981
64136
  }
63982
- if (isCreditExhaustedError(e)) {
63983
- const { billingTier, modelDisplayName } = getErrorContext();
63984
- if (billingTier?.toLowerCase() === "free") {
63985
- const modelInfo = modelDisplayName ? ` (${modelDisplayName})` : "";
63986
- return `Selected hosted model${modelInfo} not available on Free plan. Switch to a free model with /model (glm-4.7 or minimax-m2.1), upgrade your account at ${LETTA_USAGE_URL}, or connect your own API keys with /connect.`;
63987
- }
63988
- return `Your account is out of credits. Redeem additional credits or configure auto-recharge on your account page: ${LETTA_USAGE_URL}`;
64137
+ if (isCreditExhaustedError(e, reasons)) {
64138
+ return `Your account is out of credits for hosted inference. Add credits, enable auto-recharge, or upgrade at ${LETTA_USAGE_URL}. You can also connect your own provider keys with /connect.`;
64139
+ }
64140
+ if (hasErrorReason(e, "premium-usage-exceeded", reasons) || hasErrorReason(e, "standard-usage-exceeded", reasons) || hasErrorReason(e, "basic-usage-exceeded", reasons)) {
64141
+ return `You've reached your hosted model usage limit. View your plan and usage at ${LETTA_USAGE_URL}, or connect your own provider keys with /connect.`;
64142
+ }
64143
+ if (hasErrorReason(e, "byok-not-available-on-free-tier", reasons)) {
64144
+ const { modelDisplayName } = getErrorContext();
64145
+ const modelInfo = modelDisplayName ? ` (${modelDisplayName})` : "";
64146
+ return `Selected BYOK model${modelInfo} is not available on the Free plan. Switch to a free hosted model with /model (glm-4.7 or minimax-m2.1), or upgrade at ${LETTA_USAGE_URL}.`;
64147
+ }
64148
+ if (hasErrorReason(e, "free-usage-exceeded", reasons)) {
64149
+ return `You've reached the Free plan hosted model usage limit. Switch to free hosted models with /model (glm-4.7 or minimax-m2.1), upgrade at ${LETTA_USAGE_URL}, or connect your own provider keys with /connect.`;
63989
64150
  }
63990
64151
  if (e.error && typeof e.error === "object" && "error" in e.error) {
63991
64152
  const errorData = e.error.error;
@@ -66720,10 +66881,10 @@ __export(exports_settings, {
66720
66881
  loadProjectSettings: () => loadProjectSettings,
66721
66882
  getSetting: () => getSetting
66722
66883
  });
66723
- import { homedir as homedir12 } from "node:os";
66884
+ import { homedir as homedir13 } from "node:os";
66724
66885
  import { join as join20 } from "node:path";
66725
66886
  function getSettingsPath() {
66726
- return join20(homedir12(), ".letta", "settings.json");
66887
+ return join20(homedir13(), ".letta", "settings.json");
66727
66888
  }
66728
66889
  async function loadSettings() {
66729
66890
  const settingsPath = getSettingsPath();
@@ -72717,8 +72878,9 @@ function AnimationProvider({
72717
72878
  children,
72718
72879
  shouldAnimate
72719
72880
  }) {
72881
+ const contextValue = import_react45.useMemo(() => ({ shouldAnimate }), [shouldAnimate]);
72720
72882
  return /* @__PURE__ */ jsx_dev_runtime24.jsxDEV(AnimationContext.Provider, {
72721
- value: { shouldAnimate },
72883
+ value: contextValue,
72722
72884
  children
72723
72885
  }, undefined, false, undefined, this);
72724
72886
  }
@@ -72774,11 +72936,18 @@ var init_CollapsedOutputDisplay = __esm(async () => {
72774
72936
  jsx_dev_runtime26 = __toESM(require_jsx_dev_runtime(), 1);
72775
72937
  CollapsedOutputDisplay = import_react47.memo(({
72776
72938
  output,
72777
- maxLines = DEFAULT_COLLAPSED_LINES
72939
+ maxLines = DEFAULT_COLLAPSED_LINES,
72940
+ maxChars
72778
72941
  }) => {
72779
72942
  const columns = useTerminalWidth();
72780
72943
  const contentWidth = Math.max(0, columns - PREFIX_WIDTH);
72781
- const lines = output.split(`
72944
+ let displayOutput = output;
72945
+ let clippedByChars = false;
72946
+ if (typeof maxChars === "number" && maxChars > 0 && output.length > maxChars) {
72947
+ displayOutput = `${output.slice(0, maxChars)}…`;
72948
+ clippedByChars = true;
72949
+ }
72950
+ const lines = displayOutput.split(`
72782
72951
  `);
72783
72952
  if (lines.length > 0 && lines[lines.length - 1] === "") {
72784
72953
  lines.pop();
@@ -72853,6 +73022,26 @@ var init_CollapsedOutputDisplay = __esm(async () => {
72853
73022
  }, undefined, true, undefined, this)
72854
73023
  }, undefined, false, undefined, this)
72855
73024
  ]
73025
+ }, undefined, true, undefined, this),
73026
+ clippedByChars && /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(Box_default, {
73027
+ flexDirection: "row",
73028
+ children: [
73029
+ /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(Box_default, {
73030
+ width: PREFIX_WIDTH,
73031
+ flexShrink: 0,
73032
+ children: /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(Text2, {
73033
+ children: " "
73034
+ }, undefined, false, undefined, this)
73035
+ }, undefined, false, undefined, this),
73036
+ /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(Box_default, {
73037
+ flexGrow: 1,
73038
+ width: contentWidth,
73039
+ children: /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(Text2, {
73040
+ dimColor: true,
73041
+ children: "… output clipped"
73042
+ }, undefined, false, undefined, this)
73043
+ }, undefined, false, undefined, this)
73044
+ ]
72856
73045
  }, undefined, true, undefined, this)
72857
73046
  ]
72858
73047
  }, undefined, true, undefined, this);
@@ -74896,7 +75085,7 @@ import {
74896
75085
  readFileSync as readFileSync6,
74897
75086
  writeFileSync as writeFileSync5
74898
75087
  } from "node:fs";
74899
- import { homedir as homedir13, platform as platform3 } from "node:os";
75088
+ import { homedir as homedir14, platform as platform3 } from "node:os";
74900
75089
  import { dirname as dirname12, join as join22 } from "node:path";
74901
75090
  function detectTerminalType() {
74902
75091
  if (process.env.CURSOR_TRACE_ID || process.env.CURSOR_CHANNEL) {
@@ -74929,7 +75118,7 @@ function getKeybindingsPath(terminal) {
74929
75118
  }[terminal];
74930
75119
  const os5 = platform3();
74931
75120
  if (os5 === "darwin") {
74932
- return join22(homedir13(), "Library", "Application Support", appName, "User", "keybindings.json");
75121
+ return join22(homedir14(), "Library", "Application Support", appName, "User", "keybindings.json");
74933
75122
  }
74934
75123
  if (os5 === "win32") {
74935
75124
  const appData = process.env.APPDATA;
@@ -74938,7 +75127,7 @@ function getKeybindingsPath(terminal) {
74938
75127
  return join22(appData, appName, "User", "keybindings.json");
74939
75128
  }
74940
75129
  if (os5 === "linux") {
74941
- return join22(homedir13(), ".config", appName, "User", "keybindings.json");
75130
+ return join22(homedir14(), ".config", appName, "User", "keybindings.json");
74942
75131
  }
74943
75132
  return null;
74944
75133
  }
@@ -75095,10 +75284,10 @@ function getWezTermConfigPath() {
75095
75284
  if (existsSync13(xdgPath))
75096
75285
  return xdgPath;
75097
75286
  }
75098
- const configPath = join22(homedir13(), ".config", "wezterm", "wezterm.lua");
75287
+ const configPath = join22(homedir14(), ".config", "wezterm", "wezterm.lua");
75099
75288
  if (existsSync13(configPath))
75100
75289
  return configPath;
75101
- return join22(homedir13(), ".wezterm.lua");
75290
+ return join22(homedir14(), ".wezterm.lua");
75102
75291
  }
75103
75292
  function wezTermDeleteFixExists(configPath) {
75104
75293
  if (!existsSync13(configPath))
@@ -80725,7 +80914,8 @@ var init_ShimmerText = __esm(async () => {
80725
80914
  color = colors.status.processing,
80726
80915
  boldPrefix,
80727
80916
  message,
80728
- shimmerOffset
80917
+ shimmerOffset,
80918
+ wrap
80729
80919
  }) {
80730
80920
  const fullText = `${boldPrefix ? `${boldPrefix} ` : ""}${message}…`;
80731
80921
  const prefixLength = boldPrefix ? boldPrefix.length + 1 : 0;
@@ -80740,6 +80930,7 @@ var init_ShimmerText = __esm(async () => {
80740
80930
  return isInPrefix ? source_default.bold(styledChar) : styledChar;
80741
80931
  }).join("");
80742
80932
  return /* @__PURE__ */ jsx_dev_runtime44.jsxDEV(Text2, {
80933
+ wrap,
80743
80934
  children: shimmerText
80744
80935
  }, undefined, false, undefined, this);
80745
80936
  });
@@ -80748,6 +80939,15 @@ var init_ShimmerText = __esm(async () => {
80748
80939
  // src/cli/components/InputRich.tsx
80749
80940
  import { EventEmitter as EventEmitter5 } from "node:events";
80750
80941
  import { stdin } from "node:process";
80942
+ function truncateEnd(value, maxChars) {
80943
+ if (maxChars <= 0)
80944
+ return "";
80945
+ if (value.length <= maxChars)
80946
+ return value;
80947
+ if (maxChars <= 3)
80948
+ return value.slice(0, maxChars);
80949
+ return `${value.slice(0, maxChars - 3)}...`;
80950
+ }
80751
80951
  function getVisualLines(text, lineWidth) {
80752
80952
  const lines = [];
80753
80953
  let lineStart = 0;
@@ -80813,7 +81013,9 @@ function Input({
80813
81013
  onPasteError,
80814
81014
  restoredInput,
80815
81015
  onRestoredInputConsumed,
80816
- networkPhase = null
81016
+ networkPhase = null,
81017
+ terminalWidth,
81018
+ shouldAnimate = true
80817
81019
  }) {
80818
81020
  const [value, setValue] = import_react68.useState("");
80819
81021
  const [escapePressed, setEscapePressed] = import_react68.useState(false);
@@ -80825,7 +81027,7 @@ function Input({
80825
81027
  const [isAutocompleteActive, setIsAutocompleteActive] = import_react68.useState(false);
80826
81028
  const [cursorPos, setCursorPos] = import_react68.useState(undefined);
80827
81029
  const [currentCursorPosition, setCurrentCursorPosition] = import_react68.useState(0);
80828
- const columns = useTerminalWidth();
81030
+ const columns = terminalWidth;
80829
81031
  const contentWidth = Math.max(0, columns - 2);
80830
81032
  const interactionEnabled = visible && inputEnabled;
80831
81033
  const reserveInputSpace = !collapseInputWhenDisabled;
@@ -80834,6 +81036,38 @@ function Input({
80834
81036
  return Math.max(1, getVisualLines(value, contentWidth).length);
80835
81037
  }, [value, contentWidth]);
80836
81038
  const inputChromeHeight = inputRowLines + 3;
81039
+ const computedFooterRightColumnWidth = import_react68.useMemo(() => Math.max(28, Math.min(72, Math.floor(columns * 0.45))), [columns]);
81040
+ const [footerRightColumnWidth, setFooterRightColumnWidth] = import_react68.useState(computedFooterRightColumnWidth);
81041
+ const debugFlicker = process.env.LETTA_DEBUG_FLICKER === "1";
81042
+ import_react68.useEffect(() => {
81043
+ if (!streaming) {
81044
+ setFooterRightColumnWidth(computedFooterRightColumnWidth);
81045
+ return;
81046
+ }
81047
+ if (computedFooterRightColumnWidth >= footerRightColumnWidth) {
81048
+ const growthDelta = computedFooterRightColumnWidth - footerRightColumnWidth;
81049
+ if (debugFlicker && growthDelta >= FOOTER_WIDTH_STREAMING_DELTA) {
81050
+ console.error(`[debug:flicker:footer-width] defer growth ${footerRightColumnWidth} -> ${computedFooterRightColumnWidth} (delta=${growthDelta})`);
81051
+ }
81052
+ return;
81053
+ }
81054
+ const shrinkDelta = footerRightColumnWidth - computedFooterRightColumnWidth;
81055
+ if (shrinkDelta < FOOTER_WIDTH_STREAMING_DELTA) {
81056
+ if (debugFlicker && shrinkDelta > 0) {
81057
+ console.error(`[debug:flicker:footer-width] ignore minor shrink ${footerRightColumnWidth} -> ${computedFooterRightColumnWidth} (delta=${shrinkDelta})`);
81058
+ }
81059
+ return;
81060
+ }
81061
+ if (debugFlicker) {
81062
+ console.error(`[debug:flicker:footer-width] shrink ${footerRightColumnWidth} -> ${computedFooterRightColumnWidth} (delta=${shrinkDelta})`);
81063
+ }
81064
+ setFooterRightColumnWidth(computedFooterRightColumnWidth);
81065
+ }, [
81066
+ streaming,
81067
+ computedFooterRightColumnWidth,
81068
+ footerRightColumnWidth,
81069
+ debugFlicker
81070
+ ]);
80837
81071
  const [history, setHistory] = import_react68.useState([]);
80838
81072
  const [historyIndex, setHistoryIndex] = import_react68.useState(-1);
80839
81073
  const [temporaryInput, setTemporaryInput] = import_react68.useState("");
@@ -80849,18 +81083,18 @@ function Input({
80849
81083
  onRestoredInputConsumed?.();
80850
81084
  }
80851
81085
  }, [restoredInput, value, onRestoredInputConsumed]);
80852
- const handleBangAtEmpty = () => {
81086
+ const handleBangAtEmpty = import_react68.useCallback(() => {
80853
81087
  if (isBashMode)
80854
81088
  return false;
80855
81089
  setIsBashMode(true);
80856
81090
  return true;
80857
- };
80858
- const handleBackspaceAtEmpty = () => {
81091
+ }, [isBashMode]);
81092
+ const handleBackspaceAtEmpty = import_react68.useCallback(() => {
80859
81093
  if (!isBashMode)
80860
81094
  return false;
80861
81095
  setIsBashMode(false);
80862
81096
  return true;
80863
- };
81097
+ }, [isBashMode]);
80864
81098
  import_react68.useEffect(() => {
80865
81099
  if (cursorPos !== undefined) {
80866
81100
  const timer = setTimeout(() => setCursorPos(undefined), 0);
@@ -80881,9 +81115,6 @@ function Input({
80881
81115
  setCurrentMode(externalMode);
80882
81116
  }
80883
81117
  }, [externalMode]);
80884
- const [shimmerOffset, setShimmerOffset] = import_react68.useState(-3);
80885
- const [elapsedMs, setElapsedMs] = import_react68.useState(0);
80886
- const streamStartRef = import_react68.useRef(null);
80887
81118
  import_react68.useEffect(() => {
80888
81119
  if (!interactionEnabled) {
80889
81120
  setIsAutocompleteActive(false);
@@ -81102,35 +81333,7 @@ function Input({
81102
81333
  clearTimeout(ctrlCTimerRef.current);
81103
81334
  };
81104
81335
  }, []);
81105
- import_react68.useEffect(() => {
81106
- if (!streaming || !visible)
81107
- return;
81108
- const id = setInterval(() => {
81109
- setShimmerOffset((prev) => {
81110
- const prefixLen = agentName ? agentName.length + 1 : 0;
81111
- const len = prefixLen + thinkingMessage.length;
81112
- const next = prev + 1;
81113
- return next > len + 3 ? -3 : next;
81114
- });
81115
- }, 120);
81116
- return () => clearInterval(id);
81117
- }, [streaming, thinkingMessage, visible, agentName]);
81118
- import_react68.useEffect(() => {
81119
- if (streaming && visible) {
81120
- if (streamStartRef.current === null) {
81121
- streamStartRef.current = performance.now();
81122
- }
81123
- const id = setInterval(() => {
81124
- if (streamStartRef.current !== null) {
81125
- setElapsedMs(performance.now() - streamStartRef.current);
81126
- }
81127
- }, 1000);
81128
- return () => clearInterval(id);
81129
- }
81130
- streamStartRef.current = null;
81131
- setElapsedMs(0);
81132
- }, [streaming, visible]);
81133
- const handleSubmit = async () => {
81336
+ const handleSubmit = import_react68.useCallback(async () => {
81134
81337
  if (isAutocompleteActive) {
81135
81338
  return;
81136
81339
  }
@@ -81140,9 +81343,11 @@ function Input({
81140
81343
  return;
81141
81344
  if (bashRunning)
81142
81345
  return;
81143
- if (previousValue.trim() !== history[history.length - 1]) {
81144
- setHistory([...history, previousValue]);
81145
- }
81346
+ setHistory((prev) => {
81347
+ if (previousValue.trim() === prev[prev.length - 1])
81348
+ return prev;
81349
+ return [...prev, previousValue];
81350
+ });
81146
81351
  setHistoryIndex(-1);
81147
81352
  setTemporaryInput("");
81148
81353
  setValue("");
@@ -81151,8 +81356,12 @@ function Input({
81151
81356
  }
81152
81357
  return;
81153
81358
  }
81154
- if (previousValue.trim() && previousValue !== history[history.length - 1]) {
81155
- setHistory([...history, previousValue]);
81359
+ if (previousValue.trim()) {
81360
+ setHistory((prev) => {
81361
+ if (previousValue === prev[prev.length - 1])
81362
+ return prev;
81363
+ return [...prev, previousValue];
81364
+ });
81156
81365
  }
81157
81366
  setHistoryIndex(-1);
81158
81367
  setTemporaryInput("");
@@ -81161,8 +81370,15 @@ function Input({
81161
81370
  if (!result.submitted) {
81162
81371
  setValue(previousValue);
81163
81372
  }
81164
- };
81165
- const handleFileSelect = (selectedPath) => {
81373
+ }, [
81374
+ isAutocompleteActive,
81375
+ value,
81376
+ isBashMode,
81377
+ bashRunning,
81378
+ onBashSubmit,
81379
+ onSubmit
81380
+ ]);
81381
+ const handleFileSelect = import_react68.useCallback((selectedPath) => {
81166
81382
  const atIndex = value.lastIndexOf("@");
81167
81383
  if (atIndex === -1)
81168
81384
  return;
@@ -81181,21 +81397,25 @@ function Input({
81181
81397
  }
81182
81398
  setValue(newValue);
81183
81399
  setCursorPos(newCursorPos);
81184
- };
81185
- const handleCommandSelect = async (selectedCommand) => {
81400
+ }, [value]);
81401
+ const handleCommandSelect = import_react68.useCallback(async (selectedCommand) => {
81186
81402
  const commandToSubmit = selectedCommand.trim();
81187
- if (commandToSubmit && commandToSubmit !== history[history.length - 1]) {
81188
- setHistory([...history, commandToSubmit]);
81403
+ if (commandToSubmit) {
81404
+ setHistory((prev) => {
81405
+ if (commandToSubmit === prev[prev.length - 1])
81406
+ return prev;
81407
+ return [...prev, commandToSubmit];
81408
+ });
81189
81409
  }
81190
81410
  setHistoryIndex(-1);
81191
81411
  setTemporaryInput("");
81192
81412
  setValue("");
81193
81413
  await onSubmit(commandToSubmit);
81194
- };
81195
- const handleCommandAutocomplete = (selectedCommand) => {
81414
+ }, [onSubmit]);
81415
+ const handleCommandAutocomplete = import_react68.useCallback((selectedCommand) => {
81196
81416
  setValue(selectedCommand);
81197
81417
  setCursorPos(selectedCommand.length);
81198
- };
81418
+ }, []);
81199
81419
  const modeInfo = import_react68.useMemo(() => {
81200
81420
  if (ralphPending) {
81201
81421
  if (ralphPendingYolo) {
@@ -81237,164 +81457,145 @@ function Input({
81237
81457
  return null;
81238
81458
  }
81239
81459
  }, [ralphPending, ralphPendingYolo, ralphActive, currentMode]);
81240
- const estimatedTokens = charsToTokens(tokenCount);
81241
- const totalElapsedMs = elapsedBaseMs + elapsedMs;
81242
- const shouldShowTokenCount = streaming && estimatedTokens > TOKEN_DISPLAY_THRESHOLD;
81243
- const shouldShowElapsed = streaming && totalElapsedMs > ELAPSED_DISPLAY_THRESHOLD_MS;
81244
- const elapsedLabel = formatElapsedLabel(totalElapsedMs);
81245
- const networkArrow = import_react68.useMemo(() => {
81246
- if (!networkPhase)
81247
- return "";
81248
- if (networkPhase === "upload")
81249
- return "↑";
81250
- if (networkPhase === "download")
81251
- return "↑";
81252
- return "↑̸";
81253
- }, [networkPhase]);
81254
- const showErrorArrow = networkArrow === "↑̸";
81255
- const statusHintText = import_react68.useMemo(() => {
81256
- const hintColor = source_default.hex(colors.subagent.hint);
81257
- const hintBold = hintColor.bold;
81258
- const parts = [];
81259
- if (shouldShowElapsed) {
81260
- parts.push(elapsedLabel);
81261
- }
81262
- if (shouldShowTokenCount) {
81263
- parts.push(`${formatCompact(estimatedTokens)}${networkArrow ? ` ${networkArrow}` : ""}`);
81264
- } else if (showErrorArrow) {
81265
- parts.push(networkArrow);
81266
- }
81267
- const suffix = `${parts.length > 0 ? ` · ${parts.join(" · ")}` : ""})`;
81268
- if (interruptRequested) {
81269
- return hintColor(` (interrupting${suffix}`);
81270
- }
81271
- return hintColor(" (") + hintBold("esc") + hintColor(` to interrupt${suffix}`);
81460
+ const horizontalLine = import_react68.useMemo(() => "─".repeat(columns), [columns]);
81461
+ const lowerPane = import_react68.useMemo(() => {
81462
+ return /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(jsx_dev_runtime45.Fragment, {
81463
+ children: [
81464
+ messageQueue && messageQueue.length > 0 && /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(QueuedMessages, {
81465
+ messages: messageQueue
81466
+ }, undefined, false, undefined, this),
81467
+ interactionEnabled ? /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Box_default, {
81468
+ flexDirection: "column",
81469
+ children: [
81470
+ /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Text2, {
81471
+ dimColor: !isBashMode,
81472
+ color: isBashMode ? colors.bash.border : undefined,
81473
+ children: horizontalLine
81474
+ }, undefined, false, undefined, this),
81475
+ /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Box_default, {
81476
+ flexDirection: "row",
81477
+ children: [
81478
+ /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Box_default, {
81479
+ width: 2,
81480
+ flexShrink: 0,
81481
+ children: [
81482
+ /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Text2, {
81483
+ color: isBashMode ? colors.bash.prompt : colors.input.prompt,
81484
+ children: isBashMode ? "!" : ">"
81485
+ }, undefined, false, undefined, this),
81486
+ /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Text2, {
81487
+ children: " "
81488
+ }, undefined, false, undefined, this)
81489
+ ]
81490
+ }, undefined, true, undefined, this),
81491
+ /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Box_default, {
81492
+ flexGrow: 1,
81493
+ width: contentWidth,
81494
+ children: /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(PasteAwareTextInput, {
81495
+ value,
81496
+ onChange: setValue,
81497
+ onSubmit: handleSubmit,
81498
+ cursorPosition: cursorPos,
81499
+ onCursorMove: setCurrentCursorPosition,
81500
+ focus: interactionEnabled && !onEscapeCancel,
81501
+ onBangAtEmpty: handleBangAtEmpty,
81502
+ onBackspaceAtEmpty: handleBackspaceAtEmpty,
81503
+ onPasteError
81504
+ }, undefined, false, undefined, this)
81505
+ }, undefined, false, undefined, this)
81506
+ ]
81507
+ }, undefined, true, undefined, this),
81508
+ /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Text2, {
81509
+ dimColor: !isBashMode,
81510
+ color: isBashMode ? colors.bash.border : undefined,
81511
+ children: horizontalLine
81512
+ }, undefined, false, undefined, this),
81513
+ /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(InputAssist, {
81514
+ currentInput: value,
81515
+ cursorPosition: currentCursorPosition,
81516
+ onFileSelect: handleFileSelect,
81517
+ onCommandSelect: handleCommandSelect,
81518
+ onCommandAutocomplete: handleCommandAutocomplete,
81519
+ onAutocompleteActiveChange: setIsAutocompleteActive,
81520
+ agentId,
81521
+ agentName,
81522
+ serverUrl,
81523
+ workingDirectory: process.cwd(),
81524
+ conversationId
81525
+ }, undefined, false, undefined, this),
81526
+ /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(InputFooter, {
81527
+ ctrlCPressed,
81528
+ escapePressed,
81529
+ isBashMode,
81530
+ modeName: modeInfo?.name ?? null,
81531
+ modeColor: modeInfo?.color ?? null,
81532
+ showExitHint: ralphActive || ralphPending,
81533
+ agentName,
81534
+ currentModel,
81535
+ isOpenAICodexProvider: currentModelProvider === OPENAI_CODEX_PROVIDER_NAME,
81536
+ isByokProvider: currentModelProvider?.startsWith("lc-") || currentModelProvider === OPENAI_CODEX_PROVIDER_NAME,
81537
+ hideFooter,
81538
+ rightColumnWidth: footerRightColumnWidth
81539
+ }, undefined, false, undefined, this)
81540
+ ]
81541
+ }, undefined, true, undefined, this) : reserveInputSpace ? /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Box_default, {
81542
+ height: inputChromeHeight
81543
+ }, undefined, false, undefined, this) : null
81544
+ ]
81545
+ }, undefined, true, undefined, this);
81272
81546
  }, [
81273
- shouldShowElapsed,
81274
- elapsedLabel,
81275
- shouldShowTokenCount,
81276
- estimatedTokens,
81277
- interruptRequested,
81278
- networkArrow,
81279
- showErrorArrow
81547
+ messageQueue,
81548
+ interactionEnabled,
81549
+ isBashMode,
81550
+ horizontalLine,
81551
+ contentWidth,
81552
+ value,
81553
+ handleSubmit,
81554
+ cursorPos,
81555
+ onEscapeCancel,
81556
+ handleBangAtEmpty,
81557
+ handleBackspaceAtEmpty,
81558
+ onPasteError,
81559
+ currentCursorPosition,
81560
+ handleFileSelect,
81561
+ handleCommandSelect,
81562
+ handleCommandAutocomplete,
81563
+ agentId,
81564
+ agentName,
81565
+ serverUrl,
81566
+ conversationId,
81567
+ ctrlCPressed,
81568
+ escapePressed,
81569
+ modeInfo?.name,
81570
+ modeInfo?.color,
81571
+ ralphActive,
81572
+ ralphPending,
81573
+ currentModel,
81574
+ currentModelProvider,
81575
+ hideFooter,
81576
+ footerRightColumnWidth,
81577
+ reserveInputSpace,
81578
+ inputChromeHeight
81280
81579
  ]);
81281
- const horizontalLine = import_react68.useMemo(() => "─".repeat(columns), [columns]);
81282
81580
  if (!visible) {
81283
81581
  return null;
81284
81582
  }
81285
81583
  return /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Box_default, {
81286
81584
  flexDirection: "column",
81287
81585
  children: [
81288
- streaming && /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Box_default, {
81289
- flexDirection: "row",
81290
- marginBottom: 1,
81291
- children: [
81292
- /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Box_default, {
81293
- width: 2,
81294
- flexShrink: 0,
81295
- children: /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Text2, {
81296
- color: colors.status.processing,
81297
- children: /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Spinner2, {
81298
- type: "layer"
81299
- }, undefined, false, undefined, this)
81300
- }, undefined, false, undefined, this)
81301
- }, undefined, false, undefined, this),
81302
- /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Box_default, {
81303
- flexGrow: 1,
81304
- flexDirection: "row",
81305
- children: [
81306
- /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(ShimmerText, {
81307
- boldPrefix: agentName || undefined,
81308
- message: thinkingMessage,
81309
- shimmerOffset
81310
- }, undefined, false, undefined, this),
81311
- /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Text2, {
81312
- children: statusHintText
81313
- }, undefined, false, undefined, this)
81314
- ]
81315
- }, undefined, true, undefined, this)
81316
- ]
81317
- }, undefined, true, undefined, this),
81318
- messageQueue && messageQueue.length > 0 && /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(QueuedMessages, {
81319
- messages: messageQueue
81586
+ /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(StreamingStatus, {
81587
+ streaming,
81588
+ visible,
81589
+ tokenCount,
81590
+ elapsedBaseMs,
81591
+ thinkingMessage,
81592
+ agentName,
81593
+ interruptRequested,
81594
+ networkPhase,
81595
+ terminalWidth: columns,
81596
+ shouldAnimate
81320
81597
  }, undefined, false, undefined, this),
81321
- interactionEnabled ? /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Box_default, {
81322
- flexDirection: "column",
81323
- children: [
81324
- /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Text2, {
81325
- dimColor: !isBashMode,
81326
- color: isBashMode ? colors.bash.border : undefined,
81327
- children: horizontalLine
81328
- }, undefined, false, undefined, this),
81329
- /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Box_default, {
81330
- flexDirection: "row",
81331
- children: [
81332
- /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Box_default, {
81333
- width: 2,
81334
- flexShrink: 0,
81335
- children: [
81336
- /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Text2, {
81337
- color: isBashMode ? colors.bash.prompt : colors.input.prompt,
81338
- children: isBashMode ? "!" : ">"
81339
- }, undefined, false, undefined, this),
81340
- /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Text2, {
81341
- children: " "
81342
- }, undefined, false, undefined, this)
81343
- ]
81344
- }, undefined, true, undefined, this),
81345
- /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Box_default, {
81346
- flexGrow: 1,
81347
- width: contentWidth,
81348
- children: /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(PasteAwareTextInput, {
81349
- value,
81350
- onChange: setValue,
81351
- onSubmit: handleSubmit,
81352
- cursorPosition: cursorPos,
81353
- onCursorMove: setCurrentCursorPosition,
81354
- focus: interactionEnabled && !onEscapeCancel,
81355
- onBangAtEmpty: handleBangAtEmpty,
81356
- onBackspaceAtEmpty: handleBackspaceAtEmpty,
81357
- onPasteError
81358
- }, undefined, false, undefined, this)
81359
- }, undefined, false, undefined, this)
81360
- ]
81361
- }, undefined, true, undefined, this),
81362
- /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Text2, {
81363
- dimColor: !isBashMode,
81364
- color: isBashMode ? colors.bash.border : undefined,
81365
- children: horizontalLine
81366
- }, undefined, false, undefined, this),
81367
- /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(InputAssist, {
81368
- currentInput: value,
81369
- cursorPosition: currentCursorPosition,
81370
- onFileSelect: handleFileSelect,
81371
- onCommandSelect: handleCommandSelect,
81372
- onCommandAutocomplete: handleCommandAutocomplete,
81373
- onAutocompleteActiveChange: setIsAutocompleteActive,
81374
- agentId,
81375
- agentName,
81376
- serverUrl,
81377
- workingDirectory: process.cwd(),
81378
- conversationId
81379
- }, undefined, false, undefined, this),
81380
- /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(InputFooter, {
81381
- ctrlCPressed,
81382
- escapePressed,
81383
- isBashMode,
81384
- modeName: modeInfo?.name ?? null,
81385
- modeColor: modeInfo?.color ?? null,
81386
- showExitHint: ralphActive || ralphPending,
81387
- agentName,
81388
- currentModel,
81389
- isOpenAICodexProvider: currentModelProvider === OPENAI_CODEX_PROVIDER_NAME,
81390
- isByokProvider: currentModelProvider?.startsWith("lc-") || currentModelProvider === OPENAI_CODEX_PROVIDER_NAME,
81391
- isAutocompleteActive,
81392
- hideFooter
81393
- }, undefined, false, undefined, this)
81394
- ]
81395
- }, undefined, true, undefined, this) : reserveInputSpace ? /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Box_default, {
81396
- height: inputChromeHeight
81397
- }, undefined, false, undefined, this) : null
81598
+ lowerPane
81398
81599
  ]
81399
81600
  }, undefined, true, undefined, this);
81400
81601
  }
@@ -81417,14 +81618,13 @@ function formatElapsedLabel(ms) {
81417
81618
  }
81418
81619
  return seconds > 0 ? `${minutes}m ${seconds}s` : `${minutes}m`;
81419
81620
  }
81420
- var import_react68, jsx_dev_runtime45, Spinner2, ESC_CLEAR_WINDOW_MS = 2500, InputFooter;
81621
+ var import_react68, jsx_dev_runtime45, Spinner2, ESC_CLEAR_WINDOW_MS = 2500, FOOTER_WIDTH_STREAMING_DELTA = 2, InputFooter, StreamingStatus;
81421
81622
  var init_InputRich = __esm(async () => {
81422
81623
  init_source();
81423
81624
  init_oauth();
81424
81625
  init_constants();
81425
81626
  init_mode();
81426
81627
  init_mode2();
81427
- init_useTerminalWidth();
81428
81628
  init_colors();
81429
81629
  await __promiseAll([
81430
81630
  init_build2(),
@@ -81451,78 +81651,249 @@ var init_InputRich = __esm(async () => {
81451
81651
  currentModel,
81452
81652
  isOpenAICodexProvider,
81453
81653
  isByokProvider,
81454
- isAutocompleteActive,
81455
- hideFooter
81654
+ hideFooter,
81655
+ rightColumnWidth
81456
81656
  }) {
81457
- if (hideFooter || isAutocompleteActive) {
81657
+ const hideFooterContent = hideFooter;
81658
+ const maxAgentChars = Math.max(10, Math.floor(rightColumnWidth * 0.45));
81659
+ const displayAgentName = truncateEnd(agentName || "Unnamed", maxAgentChars);
81660
+ const byokExtraChars = isByokProvider ? 2 : 0;
81661
+ const reservedChars = displayAgentName.length + byokExtraChars + 4;
81662
+ const maxModelChars = Math.max(8, rightColumnWidth - reservedChars);
81663
+ const displayModel = truncateEnd(currentModel ?? "unknown", maxModelChars);
81664
+ const rightTextLength = displayAgentName.length + displayModel.length + byokExtraChars + 3;
81665
+ const rightPrefixSpaces = Math.max(0, rightColumnWidth - rightTextLength);
81666
+ const rightLabel = import_react68.useMemo(() => {
81667
+ const parts = [];
81668
+ parts.push(" ".repeat(rightPrefixSpaces));
81669
+ parts.push(source_default.hex(colors.footer.agentName)(displayAgentName));
81670
+ parts.push(source_default.dim(" ["));
81671
+ parts.push(source_default.dim(displayModel));
81672
+ if (isByokProvider) {
81673
+ parts.push(source_default.dim(" "));
81674
+ parts.push(isOpenAICodexProvider ? source_default.hex("#74AA9C")("▲") : source_default.yellow("▲"));
81675
+ }
81676
+ parts.push(source_default.dim("]"));
81677
+ return parts.join("");
81678
+ }, [
81679
+ rightPrefixSpaces,
81680
+ displayAgentName,
81681
+ displayModel,
81682
+ isByokProvider,
81683
+ isOpenAICodexProvider
81684
+ ]);
81685
+ return /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Box_default, {
81686
+ flexDirection: "row",
81687
+ marginBottom: 1,
81688
+ children: [
81689
+ /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Box_default, {
81690
+ flexGrow: 1,
81691
+ paddingRight: 1,
81692
+ children: hideFooterContent ? /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Text2, {
81693
+ children: " "
81694
+ }, undefined, false, undefined, this) : ctrlCPressed ? /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Text2, {
81695
+ dimColor: true,
81696
+ children: "Press CTRL-C again to exit"
81697
+ }, undefined, false, undefined, this) : escapePressed ? /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Text2, {
81698
+ dimColor: true,
81699
+ children: "Press Esc again to clear"
81700
+ }, undefined, false, undefined, this) : isBashMode ? /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Text2, {
81701
+ children: [
81702
+ /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Text2, {
81703
+ color: colors.bash.prompt,
81704
+ children: "⏵⏵ bash mode"
81705
+ }, undefined, false, undefined, this),
81706
+ /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Text2, {
81707
+ color: colors.bash.prompt,
81708
+ dimColor: true,
81709
+ children: [
81710
+ " ",
81711
+ "(backspace to exit)"
81712
+ ]
81713
+ }, undefined, true, undefined, this)
81714
+ ]
81715
+ }, undefined, true, undefined, this) : modeName && modeColor ? /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Text2, {
81716
+ children: [
81717
+ /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Text2, {
81718
+ color: modeColor,
81719
+ children: [
81720
+ "⏵⏵ ",
81721
+ modeName
81722
+ ]
81723
+ }, undefined, true, undefined, this),
81724
+ /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Text2, {
81725
+ color: modeColor,
81726
+ dimColor: true,
81727
+ children: [
81728
+ " ",
81729
+ "(shift+tab to ",
81730
+ showExitHint ? "exit" : "cycle",
81731
+ ")"
81732
+ ]
81733
+ }, undefined, true, undefined, this)
81734
+ ]
81735
+ }, undefined, true, undefined, this) : /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Text2, {
81736
+ dimColor: true,
81737
+ children: "Press / for commands"
81738
+ }, undefined, false, undefined, this)
81739
+ }, undefined, false, undefined, this),
81740
+ /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Box_default, {
81741
+ width: rightColumnWidth,
81742
+ flexShrink: 0,
81743
+ children: hideFooterContent ? /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Text2, {
81744
+ children: " ".repeat(rightColumnWidth)
81745
+ }, undefined, false, undefined, this) : /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Text2, {
81746
+ children: rightLabel
81747
+ }, undefined, false, undefined, this)
81748
+ }, undefined, false, undefined, this)
81749
+ ]
81750
+ }, undefined, true, undefined, this);
81751
+ });
81752
+ StreamingStatus = import_react68.memo(function StreamingStatus2({
81753
+ streaming,
81754
+ visible,
81755
+ tokenCount,
81756
+ elapsedBaseMs,
81757
+ thinkingMessage,
81758
+ agentName,
81759
+ interruptRequested,
81760
+ networkPhase,
81761
+ terminalWidth,
81762
+ shouldAnimate
81763
+ }) {
81764
+ const [shimmerOffset, setShimmerOffset] = import_react68.useState(-3);
81765
+ const [elapsedMs, setElapsedMs] = import_react68.useState(0);
81766
+ const streamStartRef = import_react68.useRef(null);
81767
+ import_react68.useEffect(() => {
81768
+ if (!streaming || !visible || !shouldAnimate)
81769
+ return;
81770
+ const id = setInterval(() => {
81771
+ setShimmerOffset((prev) => {
81772
+ const prefixLen = agentName ? agentName.length + 1 : 0;
81773
+ const len = prefixLen + thinkingMessage.length;
81774
+ const next = prev + 1;
81775
+ return next > len + 3 ? -3 : next;
81776
+ });
81777
+ }, 120);
81778
+ return () => clearInterval(id);
81779
+ }, [streaming, thinkingMessage, visible, agentName, shouldAnimate]);
81780
+ import_react68.useEffect(() => {
81781
+ if (!shouldAnimate) {
81782
+ setShimmerOffset(-3);
81783
+ }
81784
+ }, [shouldAnimate]);
81785
+ import_react68.useEffect(() => {
81786
+ if (streaming && visible) {
81787
+ if (streamStartRef.current === null) {
81788
+ streamStartRef.current = performance.now();
81789
+ }
81790
+ const id = setInterval(() => {
81791
+ if (streamStartRef.current !== null) {
81792
+ setElapsedMs(performance.now() - streamStartRef.current);
81793
+ }
81794
+ }, 1000);
81795
+ return () => clearInterval(id);
81796
+ }
81797
+ streamStartRef.current = null;
81798
+ setElapsedMs(0);
81799
+ }, [streaming, visible]);
81800
+ const estimatedTokens = charsToTokens(tokenCount);
81801
+ const totalElapsedMs = elapsedBaseMs + elapsedMs;
81802
+ const shouldShowTokenCount = streaming && estimatedTokens > TOKEN_DISPLAY_THRESHOLD;
81803
+ const shouldShowElapsed = streaming && totalElapsedMs > ELAPSED_DISPLAY_THRESHOLD_MS;
81804
+ const elapsedLabel = formatElapsedLabel(totalElapsedMs);
81805
+ const networkArrow = import_react68.useMemo(() => {
81806
+ if (!networkPhase)
81807
+ return "";
81808
+ if (networkPhase === "upload")
81809
+ return "↑";
81810
+ if (networkPhase === "download")
81811
+ return "↑";
81812
+ return "↑̸";
81813
+ }, [networkPhase]);
81814
+ const showErrorArrow = networkArrow === "↑̸";
81815
+ const statusContentWidth = Math.max(0, terminalWidth - 2);
81816
+ const minMessageWidth = 12;
81817
+ const statusHintParts = import_react68.useMemo(() => {
81818
+ const parts = [];
81819
+ if (shouldShowElapsed) {
81820
+ parts.push(elapsedLabel);
81821
+ }
81822
+ if (shouldShowTokenCount) {
81823
+ parts.push(`${formatCompact(estimatedTokens)}${networkArrow ? ` ${networkArrow}` : ""}`);
81824
+ } else if (showErrorArrow) {
81825
+ parts.push(networkArrow);
81826
+ }
81827
+ return parts;
81828
+ }, [
81829
+ shouldShowElapsed,
81830
+ elapsedLabel,
81831
+ shouldShowTokenCount,
81832
+ estimatedTokens,
81833
+ networkArrow,
81834
+ showErrorArrow
81835
+ ]);
81836
+ const statusHintSuffix = statusHintParts.length ? ` · ${statusHintParts.join(" · ")}` : "";
81837
+ const statusHintPlain = interruptRequested ? ` (interrupting${statusHintSuffix})` : ` (esc to interrupt${statusHintSuffix})`;
81838
+ const statusHintWidth = Array.from(statusHintPlain).length;
81839
+ const maxHintWidth = Math.max(0, statusContentWidth - minMessageWidth);
81840
+ const hintColumnWidth = Math.max(0, Math.min(statusHintWidth, maxHintWidth));
81841
+ const maxMessageWidth = Math.max(0, statusContentWidth - hintColumnWidth);
81842
+ const statusLabel = `${agentName ? `${agentName} ` : ""}${thinkingMessage}…`;
81843
+ const statusLabelWidth = Array.from(statusLabel).length;
81844
+ const messageColumnWidth = Math.max(0, Math.min(maxMessageWidth, Math.max(minMessageWidth, statusLabelWidth)));
81845
+ const statusHintText = import_react68.useMemo(() => {
81846
+ const hintColor = source_default.hex(colors.subagent.hint);
81847
+ const hintBold = hintColor.bold;
81848
+ const suffix = `${statusHintSuffix})`;
81849
+ if (interruptRequested) {
81850
+ return hintColor(` (interrupting${suffix}`);
81851
+ }
81852
+ return hintColor(" (") + hintBold("esc") + hintColor(` to interrupt${suffix}`);
81853
+ }, [interruptRequested, statusHintSuffix]);
81854
+ if (!streaming || !visible) {
81458
81855
  return null;
81459
81856
  }
81460
81857
  return /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Box_default, {
81461
- justifyContent: "space-between",
81858
+ flexDirection: "row",
81462
81859
  marginBottom: 1,
81463
81860
  children: [
81464
- ctrlCPressed ? /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Text2, {
81465
- dimColor: true,
81466
- children: "Press CTRL-C again to exit"
81467
- }, undefined, false, undefined, this) : escapePressed ? /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Text2, {
81468
- dimColor: true,
81469
- children: "Press Esc again to clear"
81470
- }, undefined, false, undefined, this) : isBashMode ? /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Text2, {
81471
- children: [
81472
- /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Text2, {
81473
- color: colors.bash.prompt,
81474
- children: "⏵⏵ bash mode"
81475
- }, undefined, false, undefined, this),
81476
- /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Text2, {
81477
- color: colors.bash.prompt,
81478
- dimColor: true,
81479
- children: [
81480
- " ",
81481
- "(backspace to exit)"
81482
- ]
81483
- }, undefined, true, undefined, this)
81484
- ]
81485
- }, undefined, true, undefined, this) : modeName && modeColor ? /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Text2, {
81486
- children: [
81487
- /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Text2, {
81488
- color: modeColor,
81489
- children: [
81490
- "⏵⏵ ",
81491
- modeName
81492
- ]
81493
- }, undefined, true, undefined, this),
81494
- /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Text2, {
81495
- color: modeColor,
81496
- dimColor: true,
81497
- children: [
81498
- " ",
81499
- "(shift+tab to ",
81500
- showExitHint ? "exit" : "cycle",
81501
- ")"
81502
- ]
81503
- }, undefined, true, undefined, this)
81504
- ]
81505
- }, undefined, true, undefined, this) : /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Text2, {
81506
- dimColor: true,
81507
- children: "Press / for commands"
81861
+ /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Box_default, {
81862
+ width: 2,
81863
+ flexShrink: 0,
81864
+ children: /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Text2, {
81865
+ color: colors.status.processing,
81866
+ children: shouldAnimate ? /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Spinner2, {
81867
+ type: "layer"
81868
+ }, undefined, false, undefined, this) : "●"
81869
+ }, undefined, false, undefined, this)
81508
81870
  }, undefined, false, undefined, this),
81509
- /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Text2, {
81871
+ /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Box_default, {
81872
+ width: statusContentWidth,
81873
+ flexShrink: 0,
81874
+ flexDirection: "row",
81510
81875
  children: [
81511
- /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Text2, {
81512
- color: colors.footer.agentName,
81513
- children: agentName || "Unnamed"
81876
+ /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Box_default, {
81877
+ width: messageColumnWidth,
81878
+ flexShrink: 0,
81879
+ children: /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(ShimmerText, {
81880
+ boldPrefix: agentName || undefined,
81881
+ message: thinkingMessage,
81882
+ shimmerOffset: shouldAnimate ? shimmerOffset : -3,
81883
+ wrap: "truncate-end"
81884
+ }, undefined, false, undefined, this)
81514
81885
  }, undefined, false, undefined, this),
81515
- /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Text2, {
81516
- dimColor: true,
81517
- children: [
81518
- ` [${currentModel ?? "unknown"}`,
81519
- isByokProvider && /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Text2, {
81520
- color: isOpenAICodexProvider ? "#74AA9C" : "yellow",
81521
- children: " ▲"
81522
- }, undefined, false, undefined, this),
81523
- "]"
81524
- ]
81525
- }, undefined, true, undefined, this)
81886
+ hintColumnWidth > 0 && /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Box_default, {
81887
+ width: hintColumnWidth,
81888
+ flexShrink: 0,
81889
+ children: /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Text2, {
81890
+ wrap: "truncate-end",
81891
+ children: statusHintText
81892
+ }, undefined, false, undefined, this)
81893
+ }, undefined, false, undefined, this),
81894
+ /* @__PURE__ */ jsx_dev_runtime45.jsxDEV(Box_default, {
81895
+ flexGrow: 1
81896
+ }, undefined, false, undefined, this)
81526
81897
  ]
81527
81898
  }, undefined, true, undefined, this)
81528
81899
  ]
@@ -84640,22 +85011,22 @@ function ModelSelector({
84640
85011
  };
84641
85012
  const getCategoryDescription = (cat) => {
84642
85013
  if (cat === "server-recommended") {
84643
- return "Recommended models on the server";
85014
+ return "Recommended models currently available for this account";
84644
85015
  }
84645
85016
  if (cat === "server-all") {
84646
- return "All models on the server";
85017
+ return "All models currently available for this account";
84647
85018
  }
84648
85019
  if (cat === "supported") {
84649
- return isFreeTier ? "Upgrade your account to access more models" : "Recommended models on the Letta API";
85020
+ return isFreeTier ? "Upgrade your account to access more models" : "Recommended Letta API models currently available for this account";
84650
85021
  }
84651
85022
  if (cat === "byok")
84652
- return "Recommended models via your API keys (use /connect to add more)";
85023
+ return "Recommended models via your connected API keys (use /connect to add more)";
84653
85024
  if (cat === "byok-all")
84654
- return "All models via your API keys (use /connect to add more)";
85025
+ return "All models via your connected API keys (use /connect to add more)";
84655
85026
  if (cat === "all") {
84656
- return isFreeTier ? "Upgrade your account to access more models" : "All models on the Letta API";
85027
+ return isFreeTier ? "Upgrade your account to access more models" : "All Letta API models currently available for this account";
84657
85028
  }
84658
- return "All models on the Letta API";
85029
+ return "All Letta API models currently available for this account";
84659
85030
  };
84660
85031
  const renderTabBar = () => /* @__PURE__ */ jsx_dev_runtime51.jsxDEV(Box_default, {
84661
85032
  flexDirection: "row",
@@ -84815,7 +85186,7 @@ function ModelSelector({
84815
85186
  currentList.length,
84816
85187
  " models",
84817
85188
  isCached ? " · cached" : "",
84818
- " · R to refresh"
85189
+ " · R to refresh availability"
84819
85190
  ]
84820
85191
  }, undefined, true, undefined, this),
84821
85192
  /* @__PURE__ */ jsx_dev_runtime51.jsxDEV(Text2, {
@@ -85431,11 +85802,11 @@ var init_byok_providers = __esm(async () => {
85431
85802
 
85432
85803
  // src/utils/aws-credentials.ts
85433
85804
  import { readFile as readFile12 } from "node:fs/promises";
85434
- import { homedir as homedir14 } from "node:os";
85805
+ import { homedir as homedir15 } from "node:os";
85435
85806
  import { join as join26 } from "node:path";
85436
85807
  async function parseAwsCredentials() {
85437
- const credentialsPath = join26(homedir14(), ".aws", "credentials");
85438
- const configPath = join26(homedir14(), ".aws", "config");
85808
+ const credentialsPath = join26(homedir15(), ".aws", "credentials");
85809
+ const configPath = join26(homedir15(), ".aws", "config");
85439
85810
  const profiles = new Map;
85440
85811
  try {
85441
85812
  const content = await readFile12(credentialsPath, "utf-8");
@@ -89153,7 +89524,8 @@ var init_ToolCallMessageRich = __esm(async () => {
89153
89524
  streaming: line.streaming
89154
89525
  }, undefined, false, undefined, this),
89155
89526
  isShellTool2(rawName) && line.phase === "finished" && line.resultText && line.resultOk !== false && /* @__PURE__ */ jsx_dev_runtime65.jsxDEV(CollapsedOutputDisplay, {
89156
- output: line.resultText
89527
+ output: line.resultText,
89528
+ maxChars: 300
89157
89529
  }, undefined, false, undefined, this),
89158
89530
  (() => {
89159
89531
  const showDefaultResult = !isShellTool2(rawName) || line.phase === "finished" && line.resultOk === false || line.phase !== "running" && line.phase !== "finished";
@@ -90414,7 +90786,7 @@ __export(exports_shellAliases, {
90414
90786
  clearAliasCache: () => clearAliasCache
90415
90787
  });
90416
90788
  import { existsSync as existsSync16, readFileSync as readFileSync8 } from "node:fs";
90417
- import { homedir as homedir15 } from "node:os";
90789
+ import { homedir as homedir16 } from "node:os";
90418
90790
  import { join as join27 } from "node:path";
90419
90791
  function parseAliasesFromFile(filePath) {
90420
90792
  const aliases = new Map;
@@ -90484,7 +90856,7 @@ function loadAliases(forceReload = false) {
90484
90856
  if (aliasCache && !forceReload) {
90485
90857
  return aliasCache;
90486
90858
  }
90487
- const home = homedir15();
90859
+ const home = homedir16();
90488
90860
  const allAliases = new Map;
90489
90861
  for (const file of ALIAS_FILES) {
90490
90862
  const filePath = join27(home, file);
@@ -91105,21 +91477,6 @@ Use /disconnect codex to remove the current connection first.`, false);
91105
91477
  ctx.setCommandRunning(true);
91106
91478
  const cmdId = addCommandResult3(ctx.buffersRef, ctx.refreshDerived, msg, "Checking account eligibility...", true, "running");
91107
91479
  try {
91108
- const eligibility = await checkOpenAICodexEligibility();
91109
- if (!eligibility.eligible) {
91110
- updateCommandResult3(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, `✗ ChatGPT OAuth requires a Pro or Enterprise plan
91111
-
91112
- ` + `This feature is only available for Letta Pro or Enterprise customers.
91113
- ` + `Current plan: ${eligibility.billing_tier}
91114
-
91115
- ` + `To upgrade your plan, visit:
91116
-
91117
- ` + ` https://app.letta.com/settings/organization/usage
91118
-
91119
- ` + `If you have an OpenAI API key, you can use it directly by setting:
91120
- ` + ` export OPENAI_API_KEY=your-key`, false, "finished");
91121
- return;
91122
- }
91123
91480
  updateCommandResult3(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, `Starting OAuth flow...
91124
91481
  A browser window will open for authorization.`, true, "running");
91125
91482
  const { authorizationUrl, state, codeVerifier, redirectUri } = await startOpenAIOAuth(OPENAI_OAUTH_CONFIG.defaultPort);
@@ -91173,20 +91530,7 @@ Your ChatGPT Plus/Pro subscription is now linked.`, true, "finished");
91173
91530
  } catch (error) {
91174
91531
  settingsManager.clearOAuthState();
91175
91532
  const errorMessage = getErrorMessage2(error);
91176
- let displayMessage;
91177
- if (errorMessage === "PLAN_UPGRADE_REQUIRED") {
91178
- displayMessage = `✗ ChatGPT OAuth requires a Pro or Enterprise plan
91179
-
91180
- ` + `This feature is only available for Letta Pro or Enterprise customers.
91181
- To upgrade your plan, visit:
91182
-
91183
- https://app.letta.com/settings/organization/usage
91184
-
91185
- If you have an OpenAI API key, you can use it directly by setting:
91186
- export OPENAI_API_KEY=your-key`;
91187
- } else {
91188
- displayMessage = `✗ Failed to connect: ${errorMessage}`;
91189
- }
91533
+ const displayMessage = `✗ Failed to connect: ${errorMessage}`;
91190
91534
  updateCommandResult3(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, displayMessage, false, "finished");
91191
91535
  } finally {
91192
91536
  ctx.setCommandRunning(false);
@@ -91495,7 +91839,7 @@ async function packageSkills(agentId, skillsDir) {
91495
91839
  console.warn(`Skipping invalid skill ${entry.name}: missing SKILL.md`);
91496
91840
  continue;
91497
91841
  }
91498
- const sourceUrl = await findSkillSourceUrl(entry.name);
91842
+ const sourceUrl = skillsDir ? null : await findSkillSourceUrl(entry.name);
91499
91843
  const skill2 = { name: entry.name };
91500
91844
  if (sourceUrl) {
91501
91845
  skill2.source_url = sourceUrl;
@@ -91571,7 +91915,7 @@ __export(exports_App, {
91571
91915
  default: () => App2
91572
91916
  });
91573
91917
  import { existsSync as existsSync17, readFileSync as readFileSync9, renameSync, writeFileSync as writeFileSync6 } from "node:fs";
91574
- import { homedir as homedir16, tmpdir as tmpdir3 } from "node:os";
91918
+ import { homedir as homedir17, tmpdir as tmpdir3 } from "node:os";
91575
91919
  import { join as join28 } from "node:path";
91576
91920
  function getErrorHintForStopReason(stopReason, currentModelId) {
91577
91921
  if (currentModelId === "opus" && stopReason === "llm_api_error" && getModelInfo("bedrock-opus")) {
@@ -92228,18 +92572,93 @@ function App2({
92228
92572
  setCommandRunning(false);
92229
92573
  }
92230
92574
  }, [setCommandRunning]);
92231
- const columns = useTerminalWidth();
92575
+ const rawColumns = useTerminalWidth();
92232
92576
  const terminalRows = useTerminalRows();
92233
- const prevColumnsRef = import_react91.useRef(columns);
92234
- const lastClearedColumnsRef = import_react91.useRef(columns);
92577
+ const [stableColumns, setStableColumns] = import_react91.useState(rawColumns);
92578
+ const stableColumnsTimeoutRef = import_react91.useRef(null);
92579
+ const prevColumnsRef = import_react91.useRef(rawColumns);
92580
+ const lastClearedColumnsRef = import_react91.useRef(rawColumns);
92235
92581
  const pendingResizeRef = import_react91.useRef(false);
92236
92582
  const pendingResizeColumnsRef = import_react91.useRef(null);
92237
92583
  const [staticRenderEpoch, setStaticRenderEpoch] = import_react91.useState(0);
92238
92584
  const resizeClearTimeout = import_react91.useRef(null);
92585
+ const lastClearAtRef = import_react91.useRef(0);
92239
92586
  const isInitialResizeRef = import_react91.useRef(true);
92587
+ const columns = stableColumns;
92588
+ const debugFlicker = process.env.LETTA_DEBUG_FLICKER === "1";
92589
+ import_react91.useEffect(() => {
92590
+ if (rawColumns === stableColumns) {
92591
+ if (stableColumnsTimeoutRef.current) {
92592
+ clearTimeout(stableColumnsTimeoutRef.current);
92593
+ stableColumnsTimeoutRef.current = null;
92594
+ }
92595
+ return;
92596
+ }
92597
+ const delta = Math.abs(rawColumns - stableColumns);
92598
+ if (delta >= MIN_RESIZE_DELTA) {
92599
+ if (stableColumnsTimeoutRef.current) {
92600
+ clearTimeout(stableColumnsTimeoutRef.current);
92601
+ stableColumnsTimeoutRef.current = null;
92602
+ }
92603
+ setStableColumns(rawColumns);
92604
+ return;
92605
+ }
92606
+ if (stableColumnsTimeoutRef.current) {
92607
+ clearTimeout(stableColumnsTimeoutRef.current);
92608
+ }
92609
+ stableColumnsTimeoutRef.current = setTimeout(() => {
92610
+ stableColumnsTimeoutRef.current = null;
92611
+ setStableColumns(rawColumns);
92612
+ }, STABLE_WIDTH_SETTLE_MS);
92613
+ }, [rawColumns, stableColumns]);
92614
+ const clearAndRemount = import_react91.useCallback((targetColumns) => {
92615
+ if (debugFlicker) {
92616
+ console.error(`[debug:flicker:clear-remount] target=${targetColumns} previousCleared=${lastClearedColumnsRef.current} raw=${prevColumnsRef.current}`);
92617
+ }
92618
+ if (typeof process !== "undefined" && process.stdout && "write" in process.stdout && process.stdout.isTTY) {
92619
+ process.stdout.write(CLEAR_SCREEN_AND_HOME);
92620
+ }
92621
+ setStaticRenderEpoch((epoch) => epoch + 1);
92622
+ lastClearedColumnsRef.current = targetColumns;
92623
+ lastClearAtRef.current = Date.now();
92624
+ }, [debugFlicker]);
92625
+ const scheduleResizeClear = import_react91.useCallback((targetColumns) => {
92626
+ if (targetColumns === lastClearedColumnsRef.current) {
92627
+ return;
92628
+ }
92629
+ if (resizeClearTimeout.current) {
92630
+ clearTimeout(resizeClearTimeout.current);
92631
+ resizeClearTimeout.current = null;
92632
+ }
92633
+ const elapsedSinceClear = Date.now() - lastClearAtRef.current;
92634
+ const rateLimitDelay = elapsedSinceClear >= MIN_CLEAR_INTERVAL_MS ? 0 : MIN_CLEAR_INTERVAL_MS - elapsedSinceClear;
92635
+ const delay = Math.max(RESIZE_SETTLE_MS, rateLimitDelay);
92636
+ if (debugFlicker) {
92637
+ console.error(`[debug:flicker:resize-schedule] target=${targetColumns} delay=${delay}ms elapsedSinceClear=${elapsedSinceClear}ms`);
92638
+ }
92639
+ resizeClearTimeout.current = setTimeout(() => {
92640
+ resizeClearTimeout.current = null;
92641
+ if (prevColumnsRef.current !== targetColumns) {
92642
+ if (debugFlicker) {
92643
+ console.error(`[debug:flicker:resize-skip] stale target=${targetColumns} currentRaw=${prevColumnsRef.current}`);
92644
+ }
92645
+ return;
92646
+ }
92647
+ if (targetColumns === lastClearedColumnsRef.current) {
92648
+ if (debugFlicker) {
92649
+ console.error(`[debug:flicker:resize-skip] already-cleared target=${targetColumns}`);
92650
+ }
92651
+ return;
92652
+ }
92653
+ if (debugFlicker) {
92654
+ console.error(`[debug:flicker:resize-fire] clear target=${targetColumns}`);
92655
+ }
92656
+ clearAndRemount(targetColumns);
92657
+ }, delay);
92658
+ }, [clearAndRemount, debugFlicker]);
92240
92659
  import_react91.useEffect(() => {
92241
92660
  const prev = prevColumnsRef.current;
92242
- if (columns === prev)
92661
+ if (rawColumns === prev)
92243
92662
  return;
92244
92663
  if (resizeClearTimeout.current) {
92245
92664
  clearTimeout(resizeClearTimeout.current);
@@ -92247,52 +92666,38 @@ function App2({
92247
92666
  }
92248
92667
  if (isInitialResizeRef.current) {
92249
92668
  isInitialResizeRef.current = false;
92250
- prevColumnsRef.current = columns;
92251
- lastClearedColumnsRef.current = columns;
92669
+ prevColumnsRef.current = rawColumns;
92670
+ lastClearedColumnsRef.current = rawColumns;
92252
92671
  return;
92253
92672
  }
92254
- const delta = Math.abs(columns - prev);
92673
+ const delta = Math.abs(rawColumns - prev);
92255
92674
  const isMinorJitter = delta > 0 && delta < MIN_RESIZE_DELTA;
92675
+ if (isMinorJitter) {
92676
+ prevColumnsRef.current = rawColumns;
92677
+ return;
92678
+ }
92256
92679
  if (streaming) {
92257
- if (isMinorJitter) {
92258
- prevColumnsRef.current = columns;
92259
- return;
92260
- }
92261
92680
  pendingResizeRef.current = true;
92262
- pendingResizeColumnsRef.current = columns;
92263
- prevColumnsRef.current = columns;
92681
+ pendingResizeColumnsRef.current = rawColumns;
92682
+ prevColumnsRef.current = rawColumns;
92264
92683
  return;
92265
92684
  }
92266
- if (columns === lastClearedColumnsRef.current) {
92685
+ if (rawColumns === lastClearedColumnsRef.current) {
92267
92686
  pendingResizeRef.current = false;
92268
92687
  pendingResizeColumnsRef.current = null;
92269
- prevColumnsRef.current = columns;
92688
+ prevColumnsRef.current = rawColumns;
92270
92689
  return;
92271
92690
  }
92272
- const scheduledColumns = columns;
92273
- resizeClearTimeout.current = setTimeout(() => {
92274
- resizeClearTimeout.current = null;
92275
- if (typeof process !== "undefined" && process.stdout && "write" in process.stdout && process.stdout.isTTY) {
92276
- process.stdout.write(CLEAR_SCREEN_AND_HOME);
92277
- }
92278
- setStaticRenderEpoch((epoch) => epoch + 1);
92279
- lastClearedColumnsRef.current = scheduledColumns;
92280
- }, 150);
92281
- prevColumnsRef.current = columns;
92282
- return () => {
92283
- if (resizeClearTimeout.current) {
92284
- clearTimeout(resizeClearTimeout.current);
92285
- resizeClearTimeout.current = null;
92286
- }
92287
- };
92288
- }, [columns, streaming]);
92691
+ scheduleResizeClear(rawColumns);
92692
+ prevColumnsRef.current = rawColumns;
92693
+ }, [rawColumns, streaming, scheduleResizeClear]);
92289
92694
  import_react91.useEffect(() => {
92290
92695
  if (streaming) {
92291
92696
  if (resizeClearTimeout.current) {
92292
92697
  clearTimeout(resizeClearTimeout.current);
92293
92698
  resizeClearTimeout.current = null;
92294
92699
  pendingResizeRef.current = true;
92295
- pendingResizeColumnsRef.current = columns;
92700
+ pendingResizeColumnsRef.current = rawColumns;
92296
92701
  }
92297
92702
  return;
92298
92703
  }
@@ -92305,12 +92710,20 @@ function App2({
92305
92710
  return;
92306
92711
  if (pendingColumns === lastClearedColumnsRef.current)
92307
92712
  return;
92308
- if (typeof process !== "undefined" && process.stdout && "write" in process.stdout && process.stdout.isTTY) {
92309
- process.stdout.write(CLEAR_SCREEN_AND_HOME);
92310
- }
92311
- setStaticRenderEpoch((epoch) => epoch + 1);
92312
- lastClearedColumnsRef.current = pendingColumns;
92313
- }, [columns, streaming]);
92713
+ scheduleResizeClear(pendingColumns);
92714
+ }, [rawColumns, streaming, scheduleResizeClear]);
92715
+ import_react91.useEffect(() => {
92716
+ return () => {
92717
+ if (resizeClearTimeout.current) {
92718
+ clearTimeout(resizeClearTimeout.current);
92719
+ resizeClearTimeout.current = null;
92720
+ }
92721
+ if (stableColumnsTimeoutRef.current) {
92722
+ clearTimeout(stableColumnsTimeoutRef.current);
92723
+ stableColumnsTimeoutRef.current = null;
92724
+ }
92725
+ };
92726
+ }, []);
92314
92727
  const deferredToolCallCommitsRef = import_react91.useRef(new Map);
92315
92728
  const [deferredCommitAt, setDeferredCommitAt] = import_react91.useState(null);
92316
92729
  const resetDeferredToolCallCommits = import_react91.useCallback(() => {
@@ -96852,8 +97265,9 @@ ${SYSTEM_REMINDER_CLOSE}
96852
97265
  };
96853
97266
  }
96854
97267
  if (!selectedModel) {
96855
- const cmd = overlayCommand ?? commandRunner.start("/model", `Model not found: ${modelId}`);
96856
- cmd.fail(`Model not found: ${modelId}`);
97268
+ const output = `Model not found: ${modelId}. Run /model and press R to refresh available models.`;
97269
+ const cmd = overlayCommand ?? commandRunner.start("/model", output);
97270
+ cmd.fail(output);
96857
97271
  return;
96858
97272
  }
96859
97273
  const model = selectedModel;
@@ -96902,8 +97316,11 @@ Consider switching to a different system prompt using /system to match.` : null;
96902
97316
  });
96903
97317
  } catch (error) {
96904
97318
  const errorDetails = formatErrorDetails(error, agentId);
96905
- const cmd = overlayCommand ?? commandRunner.start("/model", "Failed to switch model.");
96906
- cmd.fail(`Failed to switch model: ${errorDetails}`);
97319
+ const modelLabel = selectedModel?.label ?? modelId;
97320
+ const guidance = "Run /model and press R to refresh available models. If the model is still unavailable, choose another model or connect a provider with /connect.";
97321
+ const cmd = overlayCommand ?? commandRunner.start("/model", `Failed to switch model to ${modelLabel}.`);
97322
+ cmd.fail(`Failed to switch model to ${modelLabel}: ${errorDetails}
97323
+ ${guidance}`);
96907
97324
  }
96908
97325
  }, [
96909
97326
  agentId,
@@ -97070,9 +97487,9 @@ Consider switching to a different system prompt using /system to match.` : null;
97070
97487
  commandRunner.start
97071
97488
  ]);
97072
97489
  const handleFeedbackSubmit = import_react91.useCallback(async (message) => {
97490
+ const overlayCommand = consumeOverlayCommand("feedback");
97073
97491
  closeOverlay();
97074
97492
  await withCommandLock(async () => {
97075
- const overlayCommand = consumeOverlayCommand("feedback");
97076
97493
  const cmd = overlayCommand ?? commandRunner.start("/feedback", "Sending feedback...");
97077
97494
  try {
97078
97495
  const resolvedMessage = resolvePlaceholders(message);
@@ -97279,7 +97696,7 @@ Consider switching to a different system prompt using /system to match.` : null;
97279
97696
  }
97280
97697
  if (!planFileExists()) {
97281
97698
  const planFilePath = permissionMode2.getPlanFilePath();
97282
- const plansDir = join28(homedir16(), ".letta", "plans");
97699
+ const plansDir = join28(homedir17(), ".letta", "plans");
97283
97700
  handlePlanKeepPlanning(`You must write your plan to a plan file before exiting plan mode.
97284
97701
  ` + (planFilePath ? `Plan file path: ${planFilePath}
97285
97702
  ` : "") + `Use a write tool to create your plan in ${plansDir}, then use ExitPlanMode to present the plan to the user.`);
@@ -97435,7 +97852,7 @@ Plan file path: ${planFilePath}`;
97435
97852
  deferredCommitAt
97436
97853
  ]);
97437
97854
  const { agents: subagents } = import_react91.useSyncExternalStore(subscribe2, getSnapshot2);
97438
- const shouldAnimate = import_react91.useMemo(() => {
97855
+ const estimatedLiveHeight = import_react91.useMemo(() => {
97439
97856
  const countLines4 = (text) => {
97440
97857
  if (!text)
97441
97858
  return 0;
@@ -97459,8 +97876,23 @@ Plan file path: ${planFilePath}`;
97459
97876
  const subagentsHeight = subagents.length * LINES_PER_SUBAGENT;
97460
97877
  const FIXED_BUFFER = 20;
97461
97878
  const estimatedHeight = liveItemsHeight + subagentsHeight + FIXED_BUFFER;
97462
- return estimatedHeight < terminalRows;
97463
- }, [liveItems, terminalRows, subagents.length]);
97879
+ return estimatedHeight;
97880
+ }, [liveItems, subagents.length]);
97881
+ const [shouldAnimate, setShouldAnimate] = import_react91.useState(() => estimatedLiveHeight < terminalRows);
97882
+ import_react91.useEffect(() => {
97883
+ if (terminalRows <= 0) {
97884
+ setShouldAnimate(false);
97885
+ return;
97886
+ }
97887
+ const disableThreshold = terminalRows;
97888
+ const resumeThreshold = Math.max(0, terminalRows - ANIMATION_RESUME_HYSTERESIS_ROWS);
97889
+ setShouldAnimate((prev) => {
97890
+ if (prev) {
97891
+ return estimatedLiveHeight < disableThreshold;
97892
+ }
97893
+ return estimatedLiveHeight < resumeThreshold;
97894
+ });
97895
+ }, [estimatedLiveHeight, terminalRows]);
97464
97896
  import_react91.useEffect(() => {
97465
97897
  if (loadingState === "ready" && !welcomeCommittedRef.current && messageHistory.length === 0) {
97466
97898
  if (!continueSession && !agentProvenance) {
@@ -97813,7 +98245,9 @@ Plan file path: ${planFilePath}`;
97813
98245
  onPasteError: handlePasteError,
97814
98246
  restoredInput,
97815
98247
  onRestoredInputConsumed: () => setRestoredInput(null),
97816
- networkPhase
98248
+ networkPhase,
98249
+ terminalWidth: columns,
98250
+ shouldAnimate
97817
98251
  }, undefined, false, undefined, this)
97818
98252
  }, undefined, false, undefined, this),
97819
98253
  activeOverlay === "model" && /* @__PURE__ */ jsx_dev_runtime69.jsxDEV(ModelSelector, {
@@ -98319,7 +98753,7 @@ Open /mcp to attach or detach tools for this server.`, true);
98319
98753
  ]
98320
98754
  }, resumeKey, true, undefined, this);
98321
98755
  }
98322
- 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;
98756
+ var import_react91, jsx_dev_runtime69, CLEAR_SCREEN_AND_HOME = "\x1B[2J\x1B[H", MIN_RESIZE_DELTA = 2, RESIZE_SETTLE_MS = 250, MIN_CLEAR_INTERVAL_MS = 750, STABLE_WIDTH_SETTLE_MS = 180, TOOL_CALL_COMMIT_DEFER_MS = 50, ANIMATION_RESUME_HYSTERESIS_ROWS = 2, 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;
98323
98757
  var init_App2 = __esm(async () => {
98324
98758
  init_error();
98325
98759
  init_check_approval();
@@ -98466,7 +98900,7 @@ import {
98466
98900
  readFileSync as readFileSync10,
98467
98901
  writeFileSync as writeFileSync7
98468
98902
  } from "node:fs";
98469
- import { homedir as homedir17, platform as platform5 } from "node:os";
98903
+ import { homedir as homedir18, platform as platform5 } from "node:os";
98470
98904
  import { dirname as dirname14, join as join29 } from "node:path";
98471
98905
  function detectTerminalType2() {
98472
98906
  if (process.env.CURSOR_TRACE_ID || process.env.CURSOR_CHANNEL) {
@@ -98499,7 +98933,7 @@ function getKeybindingsPath2(terminal) {
98499
98933
  }[terminal];
98500
98934
  const os6 = platform5();
98501
98935
  if (os6 === "darwin") {
98502
- return join29(homedir17(), "Library", "Application Support", appName, "User", "keybindings.json");
98936
+ return join29(homedir18(), "Library", "Application Support", appName, "User", "keybindings.json");
98503
98937
  }
98504
98938
  if (os6 === "win32") {
98505
98939
  const appData = process.env.APPDATA;
@@ -98508,7 +98942,7 @@ function getKeybindingsPath2(terminal) {
98508
98942
  return join29(appData, appName, "User", "keybindings.json");
98509
98943
  }
98510
98944
  if (os6 === "linux") {
98511
- return join29(homedir17(), ".config", appName, "User", "keybindings.json");
98945
+ return join29(homedir18(), ".config", appName, "User", "keybindings.json");
98512
98946
  }
98513
98947
  return null;
98514
98948
  }
@@ -98665,10 +99099,10 @@ function getWezTermConfigPath2() {
98665
99099
  if (existsSync18(xdgPath))
98666
99100
  return xdgPath;
98667
99101
  }
98668
- const configPath = join29(homedir17(), ".config", "wezterm", "wezterm.lua");
99102
+ const configPath = join29(homedir18(), ".config", "wezterm", "wezterm.lua");
98669
99103
  if (existsSync18(configPath))
98670
99104
  return configPath;
98671
- return join29(homedir17(), ".wezterm.lua");
99105
+ return join29(homedir18(), ".wezterm.lua");
98672
99106
  }
98673
99107
  function wezTermDeleteFixExists2(configPath) {
98674
99108
  if (!existsSync18(configPath))
@@ -98766,10 +99200,10 @@ __export(exports_settings2, {
98766
99200
  loadProjectSettings: () => loadProjectSettings2,
98767
99201
  getSetting: () => getSetting2
98768
99202
  });
98769
- import { homedir as homedir18 } from "node:os";
99203
+ import { homedir as homedir19 } from "node:os";
98770
99204
  import { join as join30 } from "node:path";
98771
99205
  function getSettingsPath2() {
98772
- return join30(homedir18(), ".letta", "settings.json");
99206
+ return join30(homedir19(), ".letta", "settings.json");
98773
99207
  }
98774
99208
  async function loadSettings2() {
98775
99209
  const settingsPath = getSettingsPath2();
@@ -104809,4 +105243,4 @@ Error during initialization: ${message}`);
104809
105243
  }
104810
105244
  main();
104811
105245
 
104812
- //# debugId=8B604F61633624E964756E2164756E21
105246
+ //# debugId=F0DE08B3E2B6D4FD64756E2164756E21