@letta-ai/letta-code 0.1.7 → 0.1.8

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
@@ -115467,23 +115467,32 @@ async function isBinaryFile(filePath) {
115467
115467
  const fd = await fs4.open(filePath, "r");
115468
115468
  try {
115469
115469
  const stats = await fd.stat();
115470
- const bufferSize = Math.min(4096, stats.size);
115470
+ const bufferSize = Math.min(8192, stats.size);
115471
115471
  if (bufferSize === 0)
115472
115472
  return false;
115473
115473
  const buffer = Buffer.alloc(bufferSize);
115474
115474
  const { bytesRead } = await fd.read(buffer, 0, bufferSize, 0);
115475
115475
  if (bytesRead === 0)
115476
115476
  return false;
115477
- for (let i = 0;i < bytesRead; i++)
115477
+ for (let i = 0;i < bytesRead; i++) {
115478
115478
  if (buffer[i] === 0)
115479
115479
  return true;
115480
- let nonPrintableCount = 0;
115481
- for (let i = 0;i < bytesRead; i++) {
115482
- const byte = buffer[i];
115483
- if (byte < 9 || byte > 13 && byte < 32 || byte > 126)
115484
- nonPrintableCount++;
115485
115480
  }
115486
- return nonPrintableCount / bytesRead > 0.3;
115481
+ try {
115482
+ const text = buffer.slice(0, bytesRead).toString("utf-8");
115483
+ if (text.includes("�"))
115484
+ return true;
115485
+ let controlCharCount = 0;
115486
+ for (let i = 0;i < text.length; i++) {
115487
+ const code = text.charCodeAt(i);
115488
+ if (code < 9 || code > 13 && code < 32) {
115489
+ controlCharCount++;
115490
+ }
115491
+ }
115492
+ return controlCharCount / text.length > 0.3;
115493
+ } catch {
115494
+ return true;
115495
+ }
115487
115496
  } finally {
115488
115497
  await fd.close();
115489
115498
  }
@@ -118565,10 +118574,11 @@ var init_analyzer = () => {};
118565
118574
 
118566
118575
  // src/tools/manager.ts
118567
118576
  function getRegistry2() {
118568
- if (!globalThis[REGISTRY_KEY2]) {
118569
- globalThis[REGISTRY_KEY2] = new Map;
118577
+ const global2 = globalThis;
118578
+ if (!global2[REGISTRY_KEY2]) {
118579
+ global2[REGISTRY_KEY2] = new Map;
118570
118580
  }
118571
- return globalThis[REGISTRY_KEY2];
118581
+ return global2[REGISTRY_KEY2];
118572
118582
  }
118573
118583
  async function checkToolPermission(toolName, toolArgs, workingDirectory = process.cwd()) {
118574
118584
  const { checkPermission: checkPermission2 } = await Promise.resolve().then(() => (init_checker(), exports_checker));
@@ -119175,6 +119185,52 @@ var init_message = __esm(() => {
119175
119185
  init_client();
119176
119186
  });
119177
119187
 
119188
+ // src/agent/stats.ts
119189
+ class SessionStats {
119190
+ sessionStartMs;
119191
+ totalApiMs;
119192
+ usage;
119193
+ constructor() {
119194
+ this.sessionStartMs = performance.now();
119195
+ this.totalApiMs = 0;
119196
+ this.usage = {
119197
+ promptTokens: 0,
119198
+ completionTokens: 0,
119199
+ totalTokens: 0,
119200
+ cachedTokens: 0,
119201
+ reasoningTokens: 0,
119202
+ stepCount: 0
119203
+ };
119204
+ }
119205
+ endTurn(apiDurationMs) {
119206
+ this.totalApiMs += apiDurationMs;
119207
+ }
119208
+ updateUsageFromBuffers(buffers) {
119209
+ this.usage = { ...buffers.usage };
119210
+ }
119211
+ getSnapshot() {
119212
+ const now = performance.now();
119213
+ return {
119214
+ sessionStartMs: this.sessionStartMs,
119215
+ totalWallMs: now - this.sessionStartMs,
119216
+ totalApiMs: this.totalApiMs,
119217
+ usage: { ...this.usage }
119218
+ };
119219
+ }
119220
+ reset() {
119221
+ this.sessionStartMs = performance.now();
119222
+ this.totalApiMs = 0;
119223
+ this.usage = {
119224
+ promptTokens: 0,
119225
+ completionTokens: 0,
119226
+ totalTokens: 0,
119227
+ cachedTokens: 0,
119228
+ reasoningTokens: 0,
119229
+ stepCount: 0
119230
+ };
119231
+ }
119232
+ }
119233
+
119178
119234
  // src/cli/helpers/accumulator.ts
119179
119235
  function createBuffers() {
119180
119236
  return {
@@ -119183,7 +119239,15 @@ function createBuffers() {
119183
119239
  byId: new Map,
119184
119240
  pendingToolByRun: new Map,
119185
119241
  toolCallIdToLineId: new Map,
119186
- lastOtid: null
119242
+ lastOtid: null,
119243
+ usage: {
119244
+ promptTokens: 0,
119245
+ completionTokens: 0,
119246
+ totalTokens: 0,
119247
+ cachedTokens: 0,
119248
+ reasoningTokens: 0,
119249
+ stepCount: 0
119250
+ }
119187
119251
  };
119188
119252
  }
119189
119253
  function ensure(b, id, make) {
@@ -119347,6 +119411,21 @@ function onChunk(b, chunk) {
119347
119411
  b.byId.set(id, updatedLine);
119348
119412
  break;
119349
119413
  }
119414
+ case "usage_statistics": {
119415
+ if (chunk.promptTokens !== undefined) {
119416
+ b.usage.promptTokens += chunk.promptTokens;
119417
+ }
119418
+ if (chunk.completionTokens !== undefined) {
119419
+ b.usage.completionTokens += chunk.completionTokens;
119420
+ }
119421
+ if (chunk.totalTokens !== undefined) {
119422
+ b.usage.totalTokens += chunk.totalTokens;
119423
+ }
119424
+ if (chunk.stepCount !== undefined) {
119425
+ b.usage.stepCount += chunk.stepCount;
119426
+ }
119427
+ break;
119428
+ }
119350
119429
  default:
119351
119430
  break;
119352
119431
  }
@@ -119380,6 +119459,7 @@ function safeJsonParseOr(json, defaultValue) {
119380
119459
 
119381
119460
  // src/cli/helpers/stream.ts
119382
119461
  async function drainStream(stream, buffers, refresh) {
119462
+ const startTime = performance.now();
119383
119463
  let approvalRequestId = null;
119384
119464
  let toolCallId = null;
119385
119465
  let toolName = null;
@@ -119418,9 +119498,11 @@ async function drainStream(stream, buffers, refresh) {
119418
119498
  queueMicrotask(refresh);
119419
119499
  if (chunk.messageType === "stop_reason") {
119420
119500
  stopReason = chunk.stopReason;
119421
- break;
119422
119501
  }
119423
119502
  }
119503
+ if (!stopReason) {
119504
+ stopReason = import_letta_client4.Letta.StopReasonType.Error;
119505
+ }
119424
119506
  markCurrentLineAsFinished(buffers);
119425
119507
  queueMicrotask(refresh);
119426
119508
  const approval = toolCallId && toolName && toolArgs && approvalRequestId ? {
@@ -119428,10 +119510,8 @@ async function drainStream(stream, buffers, refresh) {
119428
119510
  toolName,
119429
119511
  toolArgs
119430
119512
  } : null;
119431
- if (!stopReason) {
119432
- stopReason = import_letta_client4.Letta.StopReasonType.Error;
119433
- }
119434
- return { stopReason, approval, lastRunId, lastSeqId };
119513
+ const apiDurationMs = performance.now() - startTime;
119514
+ return { stopReason, approval, lastRunId, lastSeqId, apiDurationMs };
119435
119515
  }
119436
119516
  var import_letta_client4;
119437
119517
  var init_stream = __esm(() => {
@@ -119450,7 +119530,8 @@ async function handleHeadlessCommand(argv) {
119450
119530
  args: argv,
119451
119531
  options: {
119452
119532
  continue: { type: "boolean", short: "c" },
119453
- agent: { type: "string", short: "a" }
119533
+ agent: { type: "string", short: "a" },
119534
+ "output-format": { type: "string" }
119454
119535
  },
119455
119536
  strict: false,
119456
119537
  allowPositionals: true
@@ -119491,7 +119572,13 @@ async function handleHeadlessCommand(argv) {
119491
119572
  agent = await createAgent();
119492
119573
  await updateSettings2({ lastAgent: agent.id });
119493
119574
  }
119575
+ const outputFormat = values["output-format"] || "text";
119576
+ if (!["text", "json", "stream-json"].includes(outputFormat)) {
119577
+ console.error(`Error: Invalid output format "${outputFormat}". Valid formats: text, json, stream-json`);
119578
+ process.exit(1);
119579
+ }
119494
119580
  const buffers = createBuffers();
119581
+ const sessionStats = new SessionStats;
119495
119582
  let currentInput = [
119496
119583
  {
119497
119584
  role: import_letta_client5.Letta.MessageCreateRole.User,
@@ -119501,7 +119588,8 @@ async function handleHeadlessCommand(argv) {
119501
119588
  try {
119502
119589
  while (true) {
119503
119590
  const stream = await sendMessageStream(agent.id, currentInput);
119504
- const { stopReason, approval } = await drainStream(stream, buffers, () => {});
119591
+ const { stopReason, approval, apiDurationMs } = await drainStream(stream, buffers, () => {});
119592
+ sessionStats.endTurn(apiDurationMs);
119505
119593
  if (stopReason === import_letta_client5.Letta.StopReasonType.EndTurn) {
119506
119594
  break;
119507
119595
  }
@@ -119561,13 +119649,36 @@ async function handleHeadlessCommand(argv) {
119561
119649
  console.error(`Error: ${error}`);
119562
119650
  process.exit(1);
119563
119651
  }
119652
+ sessionStats.updateUsageFromBuffers(buffers);
119564
119653
  const lines = toLines(buffers);
119565
119654
  const lastAssistant = [...lines].reverse().find((line) => line.kind === "assistant");
119566
- if (lastAssistant && "text" in lastAssistant) {
119567
- console.log(lastAssistant.text);
119568
- } else {
119569
- console.error("No assistant response found");
119655
+ const resultText = lastAssistant && "text" in lastAssistant ? lastAssistant.text : "No assistant response found";
119656
+ if (outputFormat === "json") {
119657
+ const stats = sessionStats.getSnapshot();
119658
+ const output = {
119659
+ type: "result",
119660
+ subtype: "success",
119661
+ is_error: false,
119662
+ duration_ms: Math.round(stats.totalWallMs),
119663
+ duration_api_ms: Math.round(stats.totalApiMs),
119664
+ num_turns: stats.usage.stepCount,
119665
+ result: resultText,
119666
+ session_id: agent.id,
119667
+ usage: {
119668
+ input_tokens: stats.usage.promptTokens,
119669
+ output_tokens: stats.usage.completionTokens
119670
+ }
119671
+ };
119672
+ console.log(JSON.stringify(output, null, 2));
119673
+ } else if (outputFormat === "stream-json") {
119674
+ console.error("stream-json format not yet implemented");
119570
119675
  process.exit(1);
119676
+ } else {
119677
+ if (!lastAssistant || !("text" in lastAssistant)) {
119678
+ console.error("No assistant response found");
119679
+ process.exit(1);
119680
+ }
119681
+ console.log(lastAssistant.text);
119571
119682
  }
119572
119683
  }
119573
119684
  var import_letta_client5;
@@ -143202,12 +143313,7 @@ function TextInput({ value: originalValue, placeholder = "", focus = true, mask,
143202
143313
  nextCursorWidth = input.length;
143203
143314
  }
143204
143315
  }
143205
- if (cursorOffset < 0) {
143206
- nextCursorOffset = 0;
143207
- }
143208
- if (cursorOffset > originalValue.length) {
143209
- nextCursorOffset = originalValue.length;
143210
- }
143316
+ nextCursorOffset = Math.max(0, Math.min(nextCursorOffset, nextValue.length));
143211
143317
  setState({ cursorOffset: nextCursorOffset, cursorWidth: nextCursorWidth });
143212
143318
  if (typeof onCursorOffsetChange === "function")
143213
143319
  onCursorOffsetChange(nextCursorOffset);
@@ -144100,6 +144206,59 @@ var init_diff2 = __esm(() => {
144100
144206
  init_libesm();
144101
144207
  });
144102
144208
 
144209
+ // src/cli/hooks/useTerminalWidth.ts
144210
+ function useTerminalWidth() {
144211
+ const [columns, setColumns] = import_react23.useState(trackedColumns);
144212
+ import_react23.useEffect(() => {
144213
+ ensureResizeHandler();
144214
+ const listener = (value) => {
144215
+ setColumns(value);
144216
+ };
144217
+ listeners.add(listener);
144218
+ return () => {
144219
+ listeners.delete(listener);
144220
+ removeResizeHandlerIfIdle();
144221
+ };
144222
+ }, []);
144223
+ return columns;
144224
+ }
144225
+ var import_react23, getStdout = () => {
144226
+ if (typeof process === "undefined")
144227
+ return;
144228
+ const stdout = process.stdout;
144229
+ return stdout && typeof stdout.on === "function" ? stdout : undefined;
144230
+ }, getTerminalWidth = () => getStdout()?.columns ?? 80, listeners, resizeHandlerRegistered = false, trackedColumns, resizeHandler = () => {
144231
+ const nextColumns = getTerminalWidth();
144232
+ if (nextColumns === trackedColumns) {
144233
+ return;
144234
+ }
144235
+ trackedColumns = nextColumns;
144236
+ for (const listener of listeners) {
144237
+ listener(nextColumns);
144238
+ }
144239
+ }, ensureResizeHandler = () => {
144240
+ if (resizeHandlerRegistered)
144241
+ return;
144242
+ const stdout = getStdout();
144243
+ if (!stdout)
144244
+ return;
144245
+ stdout.on("resize", resizeHandler);
144246
+ resizeHandlerRegistered = true;
144247
+ }, removeResizeHandlerIfIdle = () => {
144248
+ if (!resizeHandlerRegistered || listeners.size > 0)
144249
+ return;
144250
+ const stdout = getStdout();
144251
+ if (!stdout)
144252
+ return;
144253
+ stdout.off("resize", resizeHandler);
144254
+ resizeHandlerRegistered = false;
144255
+ };
144256
+ var init_useTerminalWidth = __esm(() => {
144257
+ import_react23 = __toESM(require_react2(), 1);
144258
+ listeners = new Set;
144259
+ trackedColumns = getTerminalWidth();
144260
+ });
144261
+
144103
144262
  // src/cli/components/colors.ts
144104
144263
  var brandColors, colors;
144105
144264
  var init_colors = __esm(() => {
@@ -145374,7 +145533,8 @@ function Line({
145374
145533
  }, undefined, true, undefined, this);
145375
145534
  }
145376
145535
  function AdvancedDiffRenderer(props) {
145377
- const result = import_react23.useMemo(() => {
145536
+ const columns = useTerminalWidth();
145537
+ const result = import_react24.useMemo(() => {
145378
145538
  if (props.precomputed)
145379
145539
  return props.precomputed;
145380
145540
  if (props.kind === "write") {
@@ -145505,7 +145665,6 @@ function AdvancedDiffRenderer(props) {
145505
145665
  const maxDisplayNo = rows.reduce((m, r) => Math.max(m, r.displayNo), 1);
145506
145666
  const gutterWidth = String(maxDisplayNo).length;
145507
145667
  const header = props.kind === "write" ? `Wrote changes to ${relative4}` : `Updated ${relative4}`;
145508
- const columns = typeof process !== "undefined" && process.stdout && "columns" in process.stdout ? process.stdout.columns : 80;
145509
145668
  const panelInnerWidth = Math.max(20, columns - 8);
145510
145669
  return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
145511
145670
  flexDirection: "column",
@@ -145534,16 +145693,17 @@ function AdvancedDiffRenderer(props) {
145534
145693
  ]
145535
145694
  }, undefined, true, undefined, this);
145536
145695
  }
145537
- var import_react23, jsx_dev_runtime2;
145696
+ var import_react24, jsx_dev_runtime2;
145538
145697
  var init_AdvancedDiffRenderer = __esm(async () => {
145539
145698
  init_libesm();
145540
145699
  init_diff2();
145700
+ init_useTerminalWidth();
145541
145701
  init_colors();
145542
145702
  await __promiseAll([
145543
145703
  init_build3(),
145544
145704
  init_DiffRenderer()
145545
145705
  ]);
145546
- import_react23 = __toESM(require_react2(), 1);
145706
+ import_react24 = __toESM(require_react2(), 1);
145547
145707
  jsx_dev_runtime2 = __toESM(require_jsx_dev_runtime(), 1);
145548
145708
  });
145549
145709
 
@@ -145555,10 +145715,10 @@ function ApprovalDialog({
145555
145715
  onApproveAlways,
145556
145716
  onDeny
145557
145717
  }) {
145558
- const [selectedOption, setSelectedOption] = import_react24.useState(0);
145559
- const [isEnteringReason, setIsEnteringReason] = import_react24.useState(false);
145560
- const [denyReason, setDenyReason] = import_react24.useState("");
145561
- const options = import_react24.useMemo(() => {
145718
+ const [selectedOption, setSelectedOption] = import_react25.useState(0);
145719
+ const [isEnteringReason, setIsEnteringReason] = import_react25.useState(false);
145720
+ const [denyReason, setDenyReason] = import_react25.useState("");
145721
+ const options = import_react25.useMemo(() => {
145562
145722
  const opts = [{ label: "Yes, just this once", action: onApprove }];
145563
145723
  if (approvalContext?.allowPersistence) {
145564
145724
  opts.push({
@@ -145582,6 +145742,11 @@ function ApprovalDialog({
145582
145742
  }
145583
145743
  return;
145584
145744
  }
145745
+ if (key.escape) {
145746
+ setSelectedOption(options.length - 1);
145747
+ setIsEnteringReason(true);
145748
+ return;
145749
+ }
145585
145750
  if (key.upArrow) {
145586
145751
  setSelectedOption((prev) => prev > 0 ? prev - 1 : options.length - 1);
145587
145752
  } else if (key.downArrow) {
@@ -145612,7 +145777,7 @@ function ApprovalDialog({
145612
145777
  try {
145613
145778
  parsedArgs = JSON.parse(approvalRequest.toolArgs);
145614
145779
  } catch {}
145615
- const precomputedDiff = import_react24.useMemo(() => {
145780
+ const precomputedDiff = import_react25.useMemo(() => {
145616
145781
  if (!parsedArgs)
145617
145782
  return null;
145618
145783
  const toolName = approvalRequest.toolName.toLowerCase();
@@ -145752,7 +145917,7 @@ function getHeaderLabel(toolName) {
145752
145917
  return "Update Todos";
145753
145918
  return toolName;
145754
145919
  }
145755
- var import_react24, jsx_dev_runtime3, OptionsRenderer, DynamicPreview = ({
145920
+ var import_react25, jsx_dev_runtime3, OptionsRenderer, DynamicPreview = ({
145756
145921
  toolName,
145757
145922
  toolArgs,
145758
145923
  parsedArgs,
@@ -145886,9 +146051,9 @@ var init_ApprovalDialogRich = __esm(async () => {
145886
146051
  init_build4(),
145887
146052
  init_AdvancedDiffRenderer()
145888
146053
  ]);
145889
- import_react24 = __toESM(require_react2(), 1);
146054
+ import_react25 = __toESM(require_react2(), 1);
145890
146055
  jsx_dev_runtime3 = __toESM(require_jsx_dev_runtime(), 1);
145891
- OptionsRenderer = import_react24.memo(({
146056
+ OptionsRenderer = import_react25.memo(({
145892
146057
  options,
145893
146058
  selectedOption
145894
146059
  }) => {
@@ -146211,19 +146376,20 @@ var init_MarkdownDisplay = __esm(async () => {
146211
146376
  });
146212
146377
 
146213
146378
  // src/cli/components/AssistantMessageRich.tsx
146214
- var import_react25, jsx_dev_runtime6, normalize = (s) => s.replace(/\r\n/g, `
146379
+ var import_react26, jsx_dev_runtime6, normalize = (s) => s.replace(/\r\n/g, `
146215
146380
  `).replace(/[ \t]+$/gm, "").replace(/\n{3,}/g, `
146216
146381
 
146217
146382
  `).replace(/^\n+|\n+$/g, ""), AssistantMessage;
146218
146383
  var init_AssistantMessageRich = __esm(async () => {
146384
+ init_useTerminalWidth();
146219
146385
  await __promiseAll([
146220
146386
  init_build3(),
146221
146387
  init_MarkdownDisplay()
146222
146388
  ]);
146223
- import_react25 = __toESM(require_react2(), 1);
146389
+ import_react26 = __toESM(require_react2(), 1);
146224
146390
  jsx_dev_runtime6 = __toESM(require_jsx_dev_runtime(), 1);
146225
- AssistantMessage = import_react25.memo(({ line }) => {
146226
- const columns = typeof process !== "undefined" && process.stdout && "columns" in process.stdout ? process.stdout.columns ?? 80 : 80;
146391
+ AssistantMessage = import_react26.memo(({ line }) => {
146392
+ const columns = useTerminalWidth();
146227
146393
  const contentWidth = Math.max(0, columns - 2);
146228
146394
  const normalizedText = normalize(line.text);
146229
146395
  return /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Box_default, {
@@ -146251,9 +146417,9 @@ var init_AssistantMessageRich = __esm(async () => {
146251
146417
  });
146252
146418
 
146253
146419
  // src/cli/components/CommandMessage.tsx
146254
- var import_react26, jsx_dev_runtime7, BlinkDot = ({ color = "yellow" }) => {
146255
- const [on, setOn] = import_react26.useState(true);
146256
- import_react26.useEffect(() => {
146420
+ var import_react27, jsx_dev_runtime7, BlinkDot = ({ color = "yellow" }) => {
146421
+ const [on, setOn] = import_react27.useState(true);
146422
+ import_react27.useEffect(() => {
146257
146423
  const t = setInterval(() => setOn((v) => !v), 400);
146258
146424
  return () => clearInterval(t);
146259
146425
  }, []);
@@ -146263,15 +146429,16 @@ var import_react26, jsx_dev_runtime7, BlinkDot = ({ color = "yellow" }) => {
146263
146429
  }, undefined, false, undefined, this);
146264
146430
  }, CommandMessage;
146265
146431
  var init_CommandMessage = __esm(async () => {
146432
+ init_useTerminalWidth();
146266
146433
  init_colors();
146267
146434
  await __promiseAll([
146268
146435
  init_build3(),
146269
146436
  init_MarkdownDisplay()
146270
146437
  ]);
146271
- import_react26 = __toESM(require_react2(), 1);
146438
+ import_react27 = __toESM(require_react2(), 1);
146272
146439
  jsx_dev_runtime7 = __toESM(require_jsx_dev_runtime(), 1);
146273
- CommandMessage = import_react26.memo(({ line }) => {
146274
- const columns = typeof process !== "undefined" && process.stdout && "columns" in process.stdout ? process.stdout.columns ?? 80 : 80;
146440
+ CommandMessage = import_react27.memo(({ line }) => {
146441
+ const columns = useTerminalWidth();
146275
146442
  const rightWidth = Math.max(0, columns - 2);
146276
146443
  const getDotElement = () => {
146277
146444
  if (!line.phase || line.phase === "finished") {
@@ -146346,12 +146513,12 @@ var init_CommandMessage = __esm(async () => {
146346
146513
  });
146347
146514
 
146348
146515
  // src/cli/components/ErrorMessage.tsx
146349
- var import_react27, jsx_dev_runtime8, ErrorMessage;
146516
+ var import_react28, jsx_dev_runtime8, ErrorMessage;
146350
146517
  var init_ErrorMessage = __esm(async () => {
146351
146518
  await init_build3();
146352
- import_react27 = __toESM(require_react2(), 1);
146519
+ import_react28 = __toESM(require_react2(), 1);
146353
146520
  jsx_dev_runtime8 = __toESM(require_jsx_dev_runtime(), 1);
146354
- ErrorMessage = import_react27.memo(({ line }) => {
146521
+ ErrorMessage = import_react28.memo(({ line }) => {
146355
146522
  return /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Text, {
146356
146523
  children: line.text
146357
146524
  }, undefined, false, undefined, this);
@@ -148000,9 +148167,9 @@ var require_cli_spinners = __commonJS((exports, module) => {
148000
148167
 
148001
148168
  // node_modules/ink-spinner/build/index.js
148002
148169
  function Spinner({ type = "dots" }) {
148003
- const [frame, setFrame] = import_react28.useState(0);
148170
+ const [frame, setFrame] = import_react29.useState(0);
148004
148171
  const spinner = import_cli_spinners.default[type];
148005
- import_react28.useEffect(() => {
148172
+ import_react29.useEffect(() => {
148006
148173
  const timer = setInterval(() => {
148007
148174
  setFrame((previousFrame) => {
148008
148175
  const isLastFrame = previousFrame === spinner.frames.length - 1;
@@ -148013,12 +148180,12 @@ function Spinner({ type = "dots" }) {
148013
148180
  clearInterval(timer);
148014
148181
  };
148015
148182
  }, [spinner]);
148016
- return import_react28.default.createElement(Text, null, spinner.frames[frame]);
148183
+ return import_react29.default.createElement(Text, null, spinner.frames[frame]);
148017
148184
  }
148018
- var import_react28, import_cli_spinners, build_default2;
148185
+ var import_react29, import_cli_spinners, build_default2;
148019
148186
  var init_build5 = __esm(async () => {
148020
148187
  await init_build3();
148021
- import_react28 = __toESM(require_react2(), 1);
148188
+ import_react29 = __toESM(require_react2(), 1);
148022
148189
  import_cli_spinners = __toESM(require_cli_spinners(), 1);
148023
148190
  build_default2 = Spinner;
148024
148191
  });
@@ -148074,6 +148241,12 @@ var init_registry = __esm(() => {
148074
148241
  handler: () => {
148075
148242
  return "Toggling token streaming...";
148076
148243
  }
148244
+ },
148245
+ "/exit": {
148246
+ desc: "Exit and show session stats",
148247
+ handler: () => {
148248
+ return "Exiting...";
148249
+ }
148077
148250
  }
148078
148251
  };
148079
148252
  });
@@ -148378,14 +148551,14 @@ function PasteAwareTextInput({
148378
148551
  placeholder,
148379
148552
  focus = true
148380
148553
  }) {
148381
- const [displayValue, setDisplayValue] = import_react29.useState(value);
148382
- const [actualValue, setActualValue] = import_react29.useState(value);
148383
- const lastPasteDetectedAtRef = import_react29.useRef(0);
148384
- const suppressNextChangeRef = import_react29.useRef(false);
148385
- const caretOffsetRef = import_react29.useRef((value || "").length);
148386
- const [nudgeCursorOffset, setNudgeCursorOffset] = import_react29.useState(undefined);
148554
+ const [displayValue, setDisplayValue] = import_react30.useState(value);
148555
+ const [actualValue, setActualValue] = import_react30.useState(value);
148556
+ const lastPasteDetectedAtRef = import_react30.useRef(0);
148557
+ const suppressNextChangeRef = import_react30.useRef(false);
148558
+ const caretOffsetRef = import_react30.useRef((value || "").length);
148559
+ const [nudgeCursorOffset, setNudgeCursorOffset] = import_react30.useState(undefined);
148387
148560
  const TextInputAny = build_default;
148388
- import_react29.useEffect(() => {
148561
+ import_react30.useEffect(() => {
148389
148562
  setDisplayValue(value);
148390
148563
  const resolved = resolvePlaceholders(value);
148391
148564
  setActualValue(resolved);
@@ -148499,7 +148672,7 @@ function PasteAwareTextInput({
148499
148672
  onSubmit(displayValue);
148500
148673
  }
148501
148674
  };
148502
- import_react29.useEffect(() => {
148675
+ import_react30.useEffect(() => {
148503
148676
  if (typeof nudgeCursorOffset === "number") {
148504
148677
  const t = setTimeout(() => setNudgeCursorOffset(undefined), 0);
148505
148678
  return () => clearTimeout(t);
@@ -148517,7 +148690,7 @@ function PasteAwareTextInput({
148517
148690
  focus
148518
148691
  }, undefined, false, undefined, this);
148519
148692
  }
148520
- var import_react29, jsx_dev_runtime10;
148693
+ var import_react30, jsx_dev_runtime10;
148521
148694
  var init_PasteAwareTextInput = __esm(async () => {
148522
148695
  init_clipboard();
148523
148696
  init_pasteRegistry();
@@ -148525,7 +148698,7 @@ var init_PasteAwareTextInput = __esm(async () => {
148525
148698
  init_build3(),
148526
148699
  init_build4()
148527
148700
  ]);
148528
- import_react29 = __toESM(require_react2(), 1);
148701
+ import_react30 = __toESM(require_react2(), 1);
148529
148702
  jsx_dev_runtime10 = __toESM(require_jsx_dev_runtime(), 1);
148530
148703
  });
148531
148704
 
@@ -148563,22 +148736,23 @@ function Input({
148563
148736
  thinkingMessage,
148564
148737
  onSubmit,
148565
148738
  permissionMode: externalMode,
148566
- onPermissionModeChange
148739
+ onPermissionModeChange,
148740
+ onExit
148567
148741
  }) {
148568
- const [value, setValue] = import_react30.useState("");
148569
- const [escapePressed, setEscapePressed] = import_react30.useState(false);
148570
- const escapeTimerRef = import_react30.useRef(null);
148571
- const [ctrlCPressed, setCtrlCPressed] = import_react30.useState(false);
148572
- const ctrlCTimerRef = import_react30.useRef(null);
148573
- const previousValueRef = import_react30.useRef(value);
148574
- const [currentMode, setCurrentMode] = import_react30.useState(externalMode || permissionMode2.getMode());
148575
- import_react30.useEffect(() => {
148742
+ const [value, setValue] = import_react31.useState("");
148743
+ const [escapePressed, setEscapePressed] = import_react31.useState(false);
148744
+ const escapeTimerRef = import_react31.useRef(null);
148745
+ const [ctrlCPressed, setCtrlCPressed] = import_react31.useState(false);
148746
+ const ctrlCTimerRef = import_react31.useRef(null);
148747
+ const previousValueRef = import_react31.useRef(value);
148748
+ const [currentMode, setCurrentMode] = import_react31.useState(externalMode || permissionMode2.getMode());
148749
+ import_react31.useEffect(() => {
148576
148750
  if (externalMode !== undefined) {
148577
148751
  setCurrentMode(externalMode);
148578
148752
  }
148579
148753
  }, [externalMode]);
148580
- const [shimmerOffset, setShimmerOffset] = import_react30.useState(-3);
148581
- const columns = typeof process !== "undefined" && process.stdout && "columns" in process.stdout ? process.stdout.columns ?? 80 : 80;
148754
+ const [shimmerOffset, setShimmerOffset] = import_react31.useState(-3);
148755
+ const columns = useTerminalWidth();
148582
148756
  const contentWidth = Math.max(0, columns - 2);
148583
148757
  use_input_default((_input, key) => {
148584
148758
  if (key.escape && value) {
@@ -148600,6 +148774,8 @@ function Input({
148600
148774
  use_input_default((input, key) => {
148601
148775
  if (input === "c" && key.ctrl) {
148602
148776
  if (ctrlCPressed) {
148777
+ if (onExit)
148778
+ onExit();
148603
148779
  process.exit(0);
148604
148780
  } else {
148605
148781
  setCtrlCPressed(true);
@@ -148629,7 +148805,7 @@ function Input({
148629
148805
  }
148630
148806
  }
148631
148807
  });
148632
- import_react30.useEffect(() => {
148808
+ import_react31.useEffect(() => {
148633
148809
  if (value !== previousValueRef.current && value !== "") {
148634
148810
  setEscapePressed(false);
148635
148811
  if (escapeTimerRef.current)
@@ -148640,7 +148816,7 @@ function Input({
148640
148816
  }
148641
148817
  previousValueRef.current = value;
148642
148818
  }, [value]);
148643
- import_react30.useEffect(() => {
148819
+ import_react31.useEffect(() => {
148644
148820
  return () => {
148645
148821
  if (escapeTimerRef.current)
148646
148822
  clearTimeout(escapeTimerRef.current);
@@ -148648,7 +148824,7 @@ function Input({
148648
148824
  clearTimeout(ctrlCTimerRef.current);
148649
148825
  };
148650
148826
  }, []);
148651
- import_react30.useEffect(() => {
148827
+ import_react31.useEffect(() => {
148652
148828
  if (!streaming)
148653
148829
  return;
148654
148830
  const id = setInterval(() => {
@@ -148717,7 +148893,7 @@ function Input({
148717
148893
  children: [
148718
148894
  " (",
148719
148895
  tokenCount,
148720
- "↑)"
148896
+ " ↑)"
148721
148897
  ]
148722
148898
  }, undefined, true, undefined, this)
148723
148899
  ]
@@ -148807,9 +148983,10 @@ function Input({
148807
148983
  ]
148808
148984
  }, undefined, true, undefined, this);
148809
148985
  }
148810
- var import_react30, jsx_dev_runtime12, Spinner2, COUNTER_VISIBLE_THRESHOLD = 1000;
148986
+ var import_react31, jsx_dev_runtime12, Spinner2, COUNTER_VISIBLE_THRESHOLD = 1000;
148811
148987
  var init_InputRich = __esm(async () => {
148812
148988
  init_mode2();
148989
+ init_useTerminalWidth();
148813
148990
  init_colors();
148814
148991
  await __promiseAll([
148815
148992
  init_build3(),
@@ -148818,7 +148995,7 @@ var init_InputRich = __esm(async () => {
148818
148995
  init_PasteAwareTextInput(),
148819
148996
  init_ShimmerText()
148820
148997
  ]);
148821
- import_react30 = __toESM(require_react2(), 1);
148998
+ import_react31 = __toESM(require_react2(), 1);
148822
148999
  jsx_dev_runtime12 = __toESM(require_jsx_dev_runtime(), 1);
148823
149000
  Spinner2 = build_default2;
148824
149001
  });
@@ -148933,7 +149110,7 @@ function ModelSelector({
148933
149110
  onSelect,
148934
149111
  onCancel
148935
149112
  }) {
148936
- const [selectedIndex, setSelectedIndex] = import_react31.useState(0);
149113
+ const [selectedIndex, setSelectedIndex] = import_react32.useState(0);
148937
149114
  use_input_default((_input, key) => {
148938
149115
  if (key.upArrow) {
148939
149116
  setSelectedIndex((prev) => Math.max(0, prev - 1));
@@ -149002,17 +149179,17 @@ function ModelSelector({
149002
149179
  ]
149003
149180
  }, undefined, true, undefined, this);
149004
149181
  }
149005
- var import_react31, import_models, jsx_dev_runtime13;
149182
+ var import_react32, import_models, jsx_dev_runtime13;
149006
149183
  var init_ModelSelector = __esm(async () => {
149007
149184
  init_colors();
149008
149185
  await init_build3();
149009
- import_react31 = __toESM(require_react2(), 1);
149186
+ import_react32 = __toESM(require_react2(), 1);
149010
149187
  import_models = __toESM(require_models3(), 1);
149011
149188
  jsx_dev_runtime13 = __toESM(require_jsx_dev_runtime(), 1);
149012
149189
  });
149013
149190
 
149014
149191
  // src/cli/components/PlanModeDialog.tsx
149015
- var import_react32, jsx_dev_runtime14, OptionsRenderer2, PlanModeDialog;
149192
+ var import_react33, jsx_dev_runtime14, OptionsRenderer2, PlanModeDialog;
149016
149193
  var init_PlanModeDialog = __esm(async () => {
149017
149194
  init_colors();
149018
149195
  await __promiseAll([
@@ -149020,9 +149197,9 @@ var init_PlanModeDialog = __esm(async () => {
149020
149197
  init_build4(),
149021
149198
  init_MarkdownDisplay()
149022
149199
  ]);
149023
- import_react32 = __toESM(require_react2(), 1);
149200
+ import_react33 = __toESM(require_react2(), 1);
149024
149201
  jsx_dev_runtime14 = __toESM(require_jsx_dev_runtime(), 1);
149025
- OptionsRenderer2 = import_react32.memo(({
149202
+ OptionsRenderer2 = import_react33.memo(({
149026
149203
  options,
149027
149204
  selectedOption
149028
149205
  }) => {
@@ -149048,10 +149225,10 @@ var init_PlanModeDialog = __esm(async () => {
149048
149225
  }, undefined, false, undefined, this);
149049
149226
  });
149050
149227
  OptionsRenderer2.displayName = "OptionsRenderer";
149051
- PlanModeDialog = import_react32.memo(({ plan, onApprove, onApproveAndAcceptEdits, onKeepPlanning }) => {
149052
- const [selectedOption, setSelectedOption] = import_react32.useState(0);
149053
- const [isEnteringReason, setIsEnteringReason] = import_react32.useState(false);
149054
- const [denyReason, setDenyReason] = import_react32.useState("");
149228
+ PlanModeDialog = import_react33.memo(({ plan, onApprove, onApproveAndAcceptEdits, onKeepPlanning }) => {
149229
+ const [selectedOption, setSelectedOption] = import_react33.useState(0);
149230
+ const [isEnteringReason, setIsEnteringReason] = import_react33.useState(false);
149231
+ const [denyReason, setDenyReason] = import_react33.useState("");
149055
149232
  const options = [
149056
149233
  { label: "Yes, and auto-accept edits", action: onApproveAndAcceptEdits },
149057
149234
  { label: "Yes, and manually approve edits", action: onApprove },
@@ -149171,19 +149348,20 @@ var init_PlanModeDialog = __esm(async () => {
149171
149348
  });
149172
149349
 
149173
149350
  // src/cli/components/ReasoningMessageRich.tsx
149174
- var import_react33, jsx_dev_runtime15, normalize2 = (s) => s.replace(/\r\n/g, `
149351
+ var import_react34, jsx_dev_runtime15, normalize2 = (s) => s.replace(/\r\n/g, `
149175
149352
  `).replace(/[ \t]+$/gm, "").replace(/\n{3,}/g, `
149176
149353
 
149177
149354
  `).replace(/^\n+|\n+$/g, ""), ReasoningMessage;
149178
149355
  var init_ReasoningMessageRich = __esm(async () => {
149356
+ init_useTerminalWidth();
149179
149357
  await __promiseAll([
149180
149358
  init_build3(),
149181
149359
  init_MarkdownDisplay()
149182
149360
  ]);
149183
- import_react33 = __toESM(require_react2(), 1);
149361
+ import_react34 = __toESM(require_react2(), 1);
149184
149362
  jsx_dev_runtime15 = __toESM(require_jsx_dev_runtime(), 1);
149185
- ReasoningMessage = import_react33.memo(({ line }) => {
149186
- const columns = typeof process !== "undefined" && process.stdout && "columns" in process.stdout ? process.stdout.columns ?? 80 : 80;
149363
+ ReasoningMessage = import_react34.memo(({ line }) => {
149364
+ const columns = useTerminalWidth();
149187
149365
  const contentWidth = Math.max(0, columns - 2);
149188
149366
  const normalizedText = normalize2(line.text);
149189
149367
  return /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Box_default, {
@@ -149239,6 +149417,60 @@ var init_ReasoningMessageRich = __esm(async () => {
149239
149417
  ReasoningMessage.displayName = "ReasoningMessage";
149240
149418
  });
149241
149419
 
149420
+ // src/cli/components/SessionStats.tsx
149421
+ function formatDuration(ms) {
149422
+ if (ms < 1000) {
149423
+ return `${Math.round(ms)}ms`;
149424
+ }
149425
+ return `${(ms / 1000).toFixed(1)}s`;
149426
+ }
149427
+ function formatNumber(n) {
149428
+ return n.toLocaleString();
149429
+ }
149430
+ function SessionStats2({ stats }) {
149431
+ const wallDuration = formatDuration(stats.totalWallMs);
149432
+ const apiDuration = formatDuration(stats.totalApiMs);
149433
+ return /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Box_default, {
149434
+ flexDirection: "column",
149435
+ paddingTop: 1,
149436
+ children: [
149437
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
149438
+ dimColor: true,
149439
+ children: [
149440
+ "Total duration (API): ",
149441
+ apiDuration
149442
+ ]
149443
+ }, undefined, true, undefined, this),
149444
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
149445
+ dimColor: true,
149446
+ children: [
149447
+ "Total duration (wall): ",
149448
+ wallDuration
149449
+ ]
149450
+ }, undefined, true, undefined, this),
149451
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
149452
+ dimColor: true,
149453
+ children: [
149454
+ "Usage: ",
149455
+ stats.usage.stepCount,
149456
+ " steps,",
149457
+ " ",
149458
+ formatNumber(stats.usage.promptTokens),
149459
+ " input,",
149460
+ " ",
149461
+ formatNumber(stats.usage.completionTokens),
149462
+ " output"
149463
+ ]
149464
+ }, undefined, true, undefined, this)
149465
+ ]
149466
+ }, undefined, true, undefined, this);
149467
+ }
149468
+ var jsx_dev_runtime16;
149469
+ var init_SessionStats = __esm(async () => {
149470
+ await init_build3();
149471
+ jsx_dev_runtime16 = __toESM(require_jsx_dev_runtime(), 1);
149472
+ });
149473
+
149242
149474
  // src/cli/helpers/formatArgsDisplay.ts
149243
149475
  function formatArgsDisplay(argsJson) {
149244
149476
  let parsed = {};
@@ -149298,14 +149530,14 @@ function formatArgsDisplay(argsJson) {
149298
149530
  var isRecord3 = (v) => typeof v === "object" && v !== null;
149299
149531
 
149300
149532
  // src/cli/components/TodoRenderer.tsx
149301
- var jsx_dev_runtime16, TodoRenderer = ({ todos }) => {
149302
- return /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Box_default, {
149533
+ var jsx_dev_runtime17, TodoRenderer = ({ todos }) => {
149534
+ return /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
149303
149535
  flexDirection: "column",
149304
149536
  children: todos.map((todo, index) => {
149305
149537
  const checkbox = todo.status === "completed" ? "☒" : "☐";
149306
149538
  let textElement;
149307
149539
  if (todo.status === "completed") {
149308
- textElement = /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
149540
+ textElement = /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
149309
149541
  color: colors.todo.completed,
149310
149542
  strikethrough: true,
149311
149543
  children: [
@@ -149315,7 +149547,7 @@ var jsx_dev_runtime16, TodoRenderer = ({ todos }) => {
149315
149547
  ]
149316
149548
  }, undefined, true, undefined, this);
149317
149549
  } else if (todo.status === "in_progress") {
149318
- textElement = /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
149550
+ textElement = /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
149319
149551
  color: colors.todo.inProgress,
149320
149552
  bold: true,
149321
149553
  children: [
@@ -149325,7 +149557,7 @@ var jsx_dev_runtime16, TodoRenderer = ({ todos }) => {
149325
149557
  ]
149326
149558
  }, undefined, true, undefined, this);
149327
149559
  } else {
149328
- textElement = /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
149560
+ textElement = /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
149329
149561
  children: [
149330
149562
  checkbox,
149331
149563
  " ",
@@ -149334,9 +149566,9 @@ var jsx_dev_runtime16, TodoRenderer = ({ todos }) => {
149334
149566
  }, undefined, true, undefined, this);
149335
149567
  }
149336
149568
  const prefix = index === 0 ? " ⎿ " : " ";
149337
- return /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Box_default, {
149569
+ return /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
149338
149570
  children: [
149339
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
149571
+ /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
149340
149572
  children: prefix
149341
149573
  }, undefined, false, undefined, this),
149342
149574
  textElement
@@ -149348,35 +149580,36 @@ var jsx_dev_runtime16, TodoRenderer = ({ todos }) => {
149348
149580
  var init_TodoRenderer = __esm(async () => {
149349
149581
  init_colors();
149350
149582
  await init_build3();
149351
- jsx_dev_runtime16 = __toESM(require_jsx_dev_runtime(), 1);
149583
+ jsx_dev_runtime17 = __toESM(require_jsx_dev_runtime(), 1);
149352
149584
  });
149353
149585
 
149354
149586
  // src/cli/components/ToolCallMessageRich.tsx
149355
- var import_react34, jsx_dev_runtime17, BlinkDot2 = ({
149587
+ var import_react35, jsx_dev_runtime18, BlinkDot2 = ({
149356
149588
  color = colors.tool.pending
149357
149589
  }) => {
149358
- const [on, setOn] = import_react34.useState(true);
149359
- import_react34.useEffect(() => {
149590
+ const [on, setOn] = import_react35.useState(true);
149591
+ import_react35.useEffect(() => {
149360
149592
  const t = setInterval(() => setOn((v) => !v), 400);
149361
149593
  return () => clearInterval(t);
149362
149594
  }, []);
149363
- return /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
149595
+ return /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
149364
149596
  color,
149365
149597
  children: on ? "●" : " "
149366
149598
  }, undefined, false, undefined, this);
149367
149599
  }, ToolCallMessage;
149368
149600
  var init_ToolCallMessageRich = __esm(async () => {
149369
149601
  init_manager();
149602
+ init_useTerminalWidth();
149370
149603
  init_colors();
149371
149604
  await __promiseAll([
149372
149605
  init_build3(),
149373
149606
  init_MarkdownDisplay(),
149374
149607
  init_TodoRenderer()
149375
149608
  ]);
149376
- import_react34 = __toESM(require_react2(), 1);
149377
- jsx_dev_runtime17 = __toESM(require_jsx_dev_runtime(), 1);
149378
- ToolCallMessage = import_react34.memo(({ line }) => {
149379
- const columns = typeof process !== "undefined" && process.stdout && "columns" in process.stdout ? process.stdout.columns ?? 80 : 80;
149609
+ import_react35 = __toESM(require_react2(), 1);
149610
+ jsx_dev_runtime18 = __toESM(require_jsx_dev_runtime(), 1);
149611
+ ToolCallMessage = import_react35.memo(({ line }) => {
149612
+ const columns = useTerminalWidth();
149380
149613
  const rawName = line.name ?? "?";
149381
149614
  const argsText = line.argsText ?? "...";
149382
149615
  let displayName = rawName;
@@ -149405,31 +149638,31 @@ var init_ToolCallMessageRich = __esm(async () => {
149405
149638
  const getDotElement = () => {
149406
149639
  switch (line.phase) {
149407
149640
  case "streaming":
149408
- return /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
149641
+ return /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
149409
149642
  color: colors.tool.streaming,
149410
149643
  children: "●"
149411
149644
  }, undefined, false, undefined, this);
149412
149645
  case "ready":
149413
- return /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(BlinkDot2, {
149646
+ return /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(BlinkDot2, {
149414
149647
  color: colors.tool.pending
149415
149648
  }, undefined, false, undefined, this);
149416
149649
  case "running":
149417
- return /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(BlinkDot2, {
149650
+ return /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(BlinkDot2, {
149418
149651
  color: colors.tool.running
149419
149652
  }, undefined, false, undefined, this);
149420
149653
  case "finished":
149421
149654
  if (line.resultOk === false) {
149422
- return /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
149655
+ return /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
149423
149656
  color: colors.tool.error,
149424
149657
  children: "●"
149425
149658
  }, undefined, false, undefined, this);
149426
149659
  }
149427
- return /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
149660
+ return /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
149428
149661
  color: colors.tool.completed,
149429
149662
  children: "●"
149430
149663
  }, undefined, false, undefined, this);
149431
149664
  default:
149432
- return /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
149665
+ return /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
149433
149666
  children: "●"
149434
149667
  }, undefined, false, undefined, this);
149435
149668
  }
@@ -149441,20 +149674,20 @@ var init_ToolCallMessageRich = __esm(async () => {
149441
149674
  const prefixWidth = 5;
149442
149675
  const contentWidth = Math.max(0, columns - prefixWidth);
149443
149676
  if (line.resultText === "Running...") {
149444
- return /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
149677
+ return /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
149445
149678
  flexDirection: "row",
149446
149679
  children: [
149447
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
149680
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
149448
149681
  width: prefixWidth,
149449
149682
  flexShrink: 0,
149450
- children: /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
149683
+ children: /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
149451
149684
  children: prefix
149452
149685
  }, undefined, false, undefined, this)
149453
149686
  }, undefined, false, undefined, this),
149454
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
149687
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
149455
149688
  flexGrow: 1,
149456
149689
  width: contentWidth,
149457
- children: /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
149690
+ children: /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
149458
149691
  dimColor: true,
149459
149692
  children: "Running..."
149460
149693
  }, undefined, false, undefined, this)
@@ -149463,20 +149696,20 @@ var init_ToolCallMessageRich = __esm(async () => {
149463
149696
  }, undefined, true, undefined, this);
149464
149697
  }
149465
149698
  if (line.resultText === "Interrupted by user") {
149466
- return /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
149699
+ return /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
149467
149700
  flexDirection: "row",
149468
149701
  children: [
149469
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
149702
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
149470
149703
  width: prefixWidth,
149471
149704
  flexShrink: 0,
149472
- children: /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
149705
+ children: /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
149473
149706
  children: prefix
149474
149707
  }, undefined, false, undefined, this)
149475
149708
  }, undefined, false, undefined, this),
149476
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
149709
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
149477
149710
  flexGrow: 1,
149478
149711
  width: contentWidth,
149479
- children: /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
149712
+ children: /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
149480
149713
  color: colors.status.interrupt,
149481
149714
  children: "Interrupted by user"
149482
149715
  }, undefined, false, undefined, this)
@@ -149499,7 +149732,7 @@ var init_ToolCallMessageRich = __esm(async () => {
149499
149732
  const priority = rec.priority === "high" ? "high" : rec.priority === "medium" ? "medium" : rec.priority === "low" ? "low" : undefined;
149500
149733
  return { content, status, id, priority };
149501
149734
  });
149502
- return /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(TodoRenderer, {
149735
+ return /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(TodoRenderer, {
149503
149736
  todos: safeTodos
149504
149737
  }, undefined, false, undefined, this);
149505
149738
  }
@@ -149513,59 +149746,59 @@ var init_ToolCallMessageRich = __esm(async () => {
149513
149746
  displayText = parsed.error;
149514
149747
  }
149515
149748
  } catch {}
149516
- return /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
149749
+ return /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
149517
149750
  flexDirection: "row",
149518
149751
  children: [
149519
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
149752
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
149520
149753
  width: prefixWidth,
149521
149754
  flexShrink: 0,
149522
- children: /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
149755
+ children: /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
149523
149756
  children: prefix
149524
149757
  }, undefined, false, undefined, this)
149525
149758
  }, undefined, false, undefined, this),
149526
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
149759
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
149527
149760
  flexGrow: 1,
149528
149761
  width: contentWidth,
149529
- children: isError ? /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
149762
+ children: isError ? /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
149530
149763
  color: colors.status.error,
149531
149764
  children: displayText
149532
- }, undefined, false, undefined, this) : /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(MarkdownDisplay, {
149765
+ }, undefined, false, undefined, this) : /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(MarkdownDisplay, {
149533
149766
  text: displayText
149534
149767
  }, undefined, false, undefined, this)
149535
149768
  }, undefined, false, undefined, this)
149536
149769
  ]
149537
149770
  }, undefined, true, undefined, this);
149538
149771
  };
149539
- return /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
149772
+ return /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
149540
149773
  flexDirection: "column",
149541
149774
  children: [
149542
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
149775
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
149543
149776
  flexDirection: "row",
149544
149777
  children: [
149545
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
149778
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
149546
149779
  width: 2,
149547
149780
  flexShrink: 0,
149548
149781
  children: [
149549
149782
  getDotElement(),
149550
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {}, undefined, false, undefined, this)
149783
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {}, undefined, false, undefined, this)
149551
149784
  ]
149552
149785
  }, undefined, true, undefined, this),
149553
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
149786
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
149554
149787
  flexGrow: 1,
149555
149788
  width: rightWidth,
149556
- children: fallback ? /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
149789
+ children: fallback ? /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
149557
149790
  wrap: "wrap",
149558
149791
  children: `${displayName}${args}`
149559
- }, undefined, false, undefined, this) : /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
149792
+ }, undefined, false, undefined, this) : /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
149560
149793
  flexDirection: "row",
149561
149794
  children: [
149562
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
149795
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
149563
149796
  children: displayName
149564
149797
  }, undefined, false, undefined, this),
149565
- args ? /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
149798
+ args ? /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
149566
149799
  flexGrow: 1,
149567
149800
  width: Math.max(0, rightWidth - displayName.length),
149568
- children: /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
149801
+ children: /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
149569
149802
  wrap: "wrap",
149570
149803
  children: args
149571
149804
  }, undefined, false, undefined, this)
@@ -149583,34 +149816,35 @@ var init_ToolCallMessageRich = __esm(async () => {
149583
149816
  });
149584
149817
 
149585
149818
  // src/cli/components/UserMessageRich.tsx
149586
- var import_react35, jsx_dev_runtime18, UserMessage;
149819
+ var import_react36, jsx_dev_runtime19, UserMessage;
149587
149820
  var init_UserMessageRich = __esm(async () => {
149821
+ init_useTerminalWidth();
149588
149822
  await __promiseAll([
149589
149823
  init_build3(),
149590
149824
  init_MarkdownDisplay()
149591
149825
  ]);
149592
- import_react35 = __toESM(require_react2(), 1);
149593
- jsx_dev_runtime18 = __toESM(require_jsx_dev_runtime(), 1);
149594
- UserMessage = import_react35.memo(({ line }) => {
149595
- const columns = typeof process !== "undefined" && process.stdout && "columns" in process.stdout ? process.stdout.columns ?? 80 : 80;
149826
+ import_react36 = __toESM(require_react2(), 1);
149827
+ jsx_dev_runtime19 = __toESM(require_jsx_dev_runtime(), 1);
149828
+ UserMessage = import_react36.memo(({ line }) => {
149829
+ const columns = useTerminalWidth();
149596
149830
  const contentWidth = Math.max(0, columns - 2);
149597
- return /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
149831
+ return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
149598
149832
  flexDirection: "row",
149599
149833
  children: [
149600
- /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
149834
+ /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
149601
149835
  width: 2,
149602
149836
  flexShrink: 0,
149603
- children: /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
149837
+ children: /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
149604
149838
  children: [
149605
149839
  ">",
149606
149840
  " "
149607
149841
  ]
149608
149842
  }, undefined, true, undefined, this)
149609
149843
  }, undefined, false, undefined, this),
149610
- /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
149844
+ /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
149611
149845
  flexGrow: 1,
149612
149846
  width: contentWidth,
149613
- children: /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(MarkdownDisplay, {
149847
+ children: /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(MarkdownDisplay, {
149614
149848
  text: line.text
149615
149849
  }, undefined, false, undefined, this)
149616
149850
  }, undefined, false, undefined, this)
@@ -149648,26 +149882,26 @@ function WelcomeScreen({
149648
149882
  checking: "Checking for pending approvals...",
149649
149883
  ready: getReadyMessage()
149650
149884
  };
149651
- return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
149885
+ return /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(Box_default, {
149652
149886
  flexDirection: "column",
149653
149887
  children: [
149654
- /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
149888
+ /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(Text, {
149655
149889
  bold: true,
149656
149890
  color: colors.welcome.accent,
149657
149891
  children: "Letta Code"
149658
149892
  }, undefined, false, undefined, this),
149659
- /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
149893
+ /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(Text, {
149660
149894
  dimColor: true,
149661
149895
  children: stateMessages[loadingState]
149662
149896
  }, undefined, false, undefined, this)
149663
149897
  ]
149664
149898
  }, undefined, true, undefined, this);
149665
149899
  }
149666
- var jsx_dev_runtime19;
149900
+ var jsx_dev_runtime20;
149667
149901
  var init_WelcomeScreen = __esm(async () => {
149668
149902
  init_colors();
149669
149903
  await init_build3();
149670
- jsx_dev_runtime19 = __toESM(require_jsx_dev_runtime(), 1);
149904
+ jsx_dev_runtime20 = __toESM(require_jsx_dev_runtime(), 1);
149671
149905
  });
149672
149906
 
149673
149907
  // src/cli/helpers/backfill.ts
@@ -149881,20 +150115,35 @@ function App2({
149881
150115
  messageHistory = [],
149882
150116
  tokenStreaming = true
149883
150117
  }) {
149884
- const [streaming, setStreaming] = import_react36.useState(false);
149885
- const [commandRunning, setCommandRunning] = import_react36.useState(false);
149886
- const [pendingApproval, setPendingApproval] = import_react36.useState(null);
149887
- const [approvalContext, setApprovalContext] = import_react36.useState(null);
149888
- const [planApprovalPending, setPlanApprovalPending] = import_react36.useState(null);
149889
- const [modelSelectorOpen, setModelSelectorOpen] = import_react36.useState(false);
149890
- const [llmConfig, setLlmConfig] = import_react36.useState(null);
149891
- const [tokenStreamingEnabled, setTokenStreamingEnabled] = import_react36.useState(tokenStreaming);
149892
- const [tokenCount, setTokenCount] = import_react36.useState(0);
149893
- const [thinkingMessage, setThinkingMessage] = import_react36.useState(getRandomThinkingMessage());
149894
- const [staticItems, setStaticItems] = import_react36.useState([]);
149895
- const emittedIdsRef = import_react36.useRef(new Set);
149896
- const welcomeCommittedRef = import_react36.useRef(false);
149897
- const commitEligibleLines = import_react36.useCallback((b) => {
150118
+ const [streaming, setStreaming] = import_react37.useState(false);
150119
+ const [commandRunning, setCommandRunning] = import_react37.useState(false);
150120
+ const [pendingApproval, setPendingApproval] = import_react37.useState(null);
150121
+ const [approvalContext, setApprovalContext] = import_react37.useState(null);
150122
+ const [planApprovalPending, setPlanApprovalPending] = import_react37.useState(null);
150123
+ const [modelSelectorOpen, setModelSelectorOpen] = import_react37.useState(false);
150124
+ const [llmConfig, setLlmConfig] = import_react37.useState(null);
150125
+ const [tokenStreamingEnabled, setTokenStreamingEnabled] = import_react37.useState(tokenStreaming);
150126
+ const [tokenCount, setTokenCount] = import_react37.useState(0);
150127
+ const [thinkingMessage, setThinkingMessage] = import_react37.useState(getRandomThinkingMessage());
150128
+ const sessionStatsRef = import_react37.useRef(new SessionStats);
150129
+ const [showExitStats, setShowExitStats] = import_react37.useState(false);
150130
+ const [staticItems, setStaticItems] = import_react37.useState([]);
150131
+ const emittedIdsRef = import_react37.useRef(new Set);
150132
+ const welcomeCommittedRef = import_react37.useRef(false);
150133
+ const columns = useTerminalWidth();
150134
+ const prevColumnsRef = import_react37.useRef(columns);
150135
+ const [staticRenderEpoch, setStaticRenderEpoch] = import_react37.useState(0);
150136
+ import_react37.useEffect(() => {
150137
+ const prev = prevColumnsRef.current;
150138
+ if (columns === prev)
150139
+ return;
150140
+ if (columns < prev && typeof process !== "undefined" && process.stdout && "write" in process.stdout && process.stdout.isTTY) {
150141
+ process.stdout.write(CLEAR_SCREEN_AND_HOME);
150142
+ }
150143
+ setStaticRenderEpoch((epoch) => epoch + 1);
150144
+ prevColumnsRef.current = columns;
150145
+ }, [columns]);
150146
+ const commitEligibleLines = import_react37.useCallback((b) => {
149898
150147
  const newlyCommitted = [];
149899
150148
  for (const id of b.order) {
149900
150149
  if (emittedIdsRef.current.has(id))
@@ -149923,17 +150172,17 @@ function App2({
149923
150172
  setStaticItems((prev) => [...prev, ...newlyCommitted]);
149924
150173
  }
149925
150174
  }, []);
149926
- const [lines, setLines] = import_react36.useState([]);
149927
- const buffersRef = import_react36.useRef(createBuffers());
149928
- const hasBackfilledRef = import_react36.useRef(false);
149929
- const refreshDerived = import_react36.useCallback(() => {
150175
+ const [lines, setLines] = import_react37.useState([]);
150176
+ const buffersRef = import_react37.useRef(createBuffers());
150177
+ const hasBackfilledRef = import_react37.useRef(false);
150178
+ const refreshDerived = import_react37.useCallback(() => {
149930
150179
  const b = buffersRef.current;
149931
150180
  setTokenCount(b.tokenCount);
149932
150181
  const newLines = toLines(b);
149933
150182
  setLines(newLines);
149934
150183
  commitEligibleLines(b);
149935
150184
  }, [commitEligibleLines]);
149936
- const refreshDerivedThrottled = import_react36.useCallback(() => {
150185
+ const refreshDerivedThrottled = import_react37.useCallback(() => {
149937
150186
  if (!buffersRef.current.pendingRefresh) {
149938
150187
  buffersRef.current.pendingRefresh = true;
149939
150188
  setTimeout(() => {
@@ -149942,7 +150191,7 @@ function App2({
149942
150191
  }, 16);
149943
150192
  }
149944
150193
  }, [refreshDerived]);
149945
- import_react36.useEffect(() => {
150194
+ import_react37.useEffect(() => {
149946
150195
  if (loadingState === "ready" && startupApproval) {
149947
150196
  if (startupApproval.toolName === "ExitPlanMode") {
149948
150197
  const parsedArgs = safeJsonParseOr(startupApproval.toolArgs, {});
@@ -149967,7 +150216,7 @@ function App2({
149967
150216
  }
149968
150217
  }
149969
150218
  }, [loadingState, startupApproval]);
149970
- import_react36.useEffect(() => {
150219
+ import_react37.useEffect(() => {
149971
150220
  if (loadingState === "ready" && messageHistory.length > 0 && !hasBackfilledRef.current) {
149972
150221
  hasBackfilledRef.current = true;
149973
150222
  if (!welcomeCommittedRef.current) {
@@ -149996,7 +150245,7 @@ function App2({
149996
150245
  agentId,
149997
150246
  continueSession
149998
150247
  ]);
149999
- import_react36.useEffect(() => {
150248
+ import_react37.useEffect(() => {
150000
150249
  if (loadingState === "ready" && agentId && agentId !== "loading") {
150001
150250
  const fetchConfig = async () => {
150002
150251
  try {
@@ -150011,7 +150260,7 @@ function App2({
150011
150260
  fetchConfig();
150012
150261
  }
150013
150262
  }, [loadingState, agentId]);
150014
- const appendError = import_react36.useCallback((message) => {
150263
+ const appendError = import_react37.useCallback((message) => {
150015
150264
  const id = uid("err");
150016
150265
  buffersRef.current.byId.set(id, {
150017
150266
  kind: "error",
@@ -150021,13 +150270,15 @@ function App2({
150021
150270
  buffersRef.current.order.push(id);
150022
150271
  refreshDerived();
150023
150272
  }, [refreshDerived]);
150024
- const processConversation = import_react36.useCallback(async (initialInput) => {
150273
+ const processConversation = import_react37.useCallback(async (initialInput) => {
150025
150274
  let currentInput = initialInput;
150026
150275
  try {
150027
150276
  setStreaming(true);
150028
150277
  while (true) {
150029
150278
  const stream = await sendMessageStream(agentId, currentInput);
150030
- const { stopReason, approval } = await drainStream(stream, buffersRef.current, refreshDerivedThrottled);
150279
+ const { stopReason, approval, apiDurationMs } = await drainStream(stream, buffersRef.current, refreshDerivedThrottled);
150280
+ sessionStatsRef.current.endTurn(apiDurationMs);
150281
+ sessionStatsRef.current.updateUsageFromBuffers(buffersRef.current);
150031
150282
  refreshDerived();
150032
150283
  if (stopReason === import_letta_client6.Letta.StopReasonType.EndTurn) {
150033
150284
  setStreaming(false);
@@ -150107,7 +150358,13 @@ function App2({
150107
150358
  setStreaming(false);
150108
150359
  }
150109
150360
  }, [agentId, appendError, refreshDerived, refreshDerivedThrottled]);
150110
- const onSubmit = import_react36.useCallback(async (message) => {
150361
+ const handleExit = import_react37.useCallback(() => {
150362
+ setShowExitStats(true);
150363
+ setTimeout(() => {
150364
+ process.exit(0);
150365
+ }, 100);
150366
+ }, []);
150367
+ const onSubmit = import_react37.useCallback(async (message) => {
150111
150368
  const msg = message?.trim() ?? "";
150112
150369
  if (!msg || streaming || commandRunning)
150113
150370
  return;
@@ -150131,6 +150388,10 @@ function App2({
150131
150388
  refreshDerived();
150132
150389
  return;
150133
150390
  }
150391
+ if (msg.trim() === "/exit") {
150392
+ handleExit();
150393
+ return;
150394
+ }
150134
150395
  if (msg.trim() === "/stream") {
150135
150396
  const newValue = !tokenStreamingEnabled;
150136
150397
  const cmdId2 = uid("cmd");
@@ -150239,9 +150500,10 @@ function App2({
150239
150500
  processConversation,
150240
150501
  tokenStreamingEnabled,
150241
150502
  refreshDerived,
150242
- agentId
150503
+ agentId,
150504
+ handleExit
150243
150505
  ]);
150244
- const handleApprove = import_react36.useCallback(async () => {
150506
+ const handleApprove = import_react37.useCallback(async () => {
150245
150507
  if (!pendingApproval)
150246
150508
  return;
150247
150509
  const { toolCallId, toolName, toolArgs } = pendingApproval;
@@ -150281,7 +150543,7 @@ function App2({
150281
150543
  setStreaming(false);
150282
150544
  }
150283
150545
  }, [pendingApproval, processConversation, appendError, refreshDerived]);
150284
- const handleApproveAlways = import_react36.useCallback(async (scope) => {
150546
+ const handleApproveAlways = import_react37.useCallback(async (scope) => {
150285
150547
  if (!pendingApproval || !approvalContext)
150286
150548
  return;
150287
150549
  const rule = approvalContext.recommendedRule;
@@ -150300,7 +150562,7 @@ function App2({
150300
150562
  setApprovalContext(null);
150301
150563
  await handleApprove();
150302
150564
  }, [pendingApproval, approvalContext, handleApprove, refreshDerived]);
150303
- const handleDeny = import_react36.useCallback(async (reason) => {
150565
+ const handleDeny = import_react37.useCallback(async (reason) => {
150304
150566
  if (!pendingApproval)
150305
150567
  return;
150306
150568
  const { toolCallId } = pendingApproval;
@@ -150320,7 +150582,7 @@ function App2({
150320
150582
  setStreaming(false);
150321
150583
  }
150322
150584
  }, [pendingApproval, processConversation, appendError]);
150323
- const handleModelSelect = import_react36.useCallback(async (modelId) => {
150585
+ const handleModelSelect = import_react37.useCallback(async (modelId) => {
150324
150586
  setModelSelectorOpen(false);
150325
150587
  let cmdId = null;
150326
150588
  try {
@@ -150380,8 +150642,8 @@ function App2({
150380
150642
  setCommandRunning(false);
150381
150643
  }
150382
150644
  }, [agentId, refreshDerived]);
150383
- const [uiPermissionMode, setUiPermissionMode] = import_react36.useState(permissionMode2.getMode());
150384
- const handlePlanApprove = import_react36.useCallback(async (acceptEdits = false) => {
150645
+ const [uiPermissionMode, setUiPermissionMode] = import_react37.useState(permissionMode2.getMode());
150646
+ const handlePlanApprove = import_react37.useCallback(async (acceptEdits = false) => {
150385
150647
  if (!planApprovalPending)
150386
150648
  return;
150387
150649
  const { toolCallId, toolArgs } = planApprovalPending;
@@ -150424,7 +150686,7 @@ function App2({
150424
150686
  setStreaming(false);
150425
150687
  }
150426
150688
  }, [planApprovalPending, processConversation, appendError, refreshDerived]);
150427
- const handlePlanKeepPlanning = import_react36.useCallback(async (reason) => {
150689
+ const handlePlanKeepPlanning = import_react37.useCallback(async (reason) => {
150428
150690
  if (!planApprovalPending)
150429
150691
  return;
150430
150692
  const { toolCallId } = planApprovalPending;
@@ -150444,7 +150706,7 @@ function App2({
150444
150706
  setStreaming(false);
150445
150707
  }
150446
150708
  }, [planApprovalPending, processConversation, appendError]);
150447
- const liveItems = import_react36.useMemo(() => {
150709
+ const liveItems = import_react37.useMemo(() => {
150448
150710
  return lines.filter((ln) => {
150449
150711
  if (!("phase" in ln))
150450
150712
  return false;
@@ -150461,7 +150723,7 @@ function App2({
150461
150723
  return ln.phase === "streaming";
150462
150724
  });
150463
150725
  }, [lines, tokenStreamingEnabled]);
150464
- import_react36.useEffect(() => {
150726
+ import_react37.useEffect(() => {
150465
150727
  if (loadingState === "ready" && !welcomeCommittedRef.current && messageHistory.length === 0) {
150466
150728
  welcomeCommittedRef.current = true;
150467
150729
  setStaticItems((prev) => [
@@ -150477,87 +150739,91 @@ function App2({
150477
150739
  ]);
150478
150740
  }
150479
150741
  }, [loadingState, continueSession, agentId, messageHistory.length]);
150480
- return /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(Box_default, {
150742
+ return /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(Box_default, {
150481
150743
  flexDirection: "column",
150482
150744
  gap: 1,
150483
150745
  children: [
150484
- /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(Static, {
150746
+ /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(Static, {
150485
150747
  items: staticItems,
150486
150748
  style: { flexDirection: "column" },
150487
- children: (item, index) => /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(Box_default, {
150749
+ children: (item, index) => /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(Box_default, {
150488
150750
  marginTop: index > 0 ? 1 : 0,
150489
- children: item.kind === "welcome" ? /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(WelcomeScreen, {
150751
+ children: item.kind === "welcome" ? /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(WelcomeScreen, {
150490
150752
  loadingState: "ready",
150491
150753
  ...item.snapshot
150492
- }, undefined, false, undefined, this) : item.kind === "user" ? /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(UserMessage, {
150754
+ }, undefined, false, undefined, this) : item.kind === "user" ? /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(UserMessage, {
150493
150755
  line: item
150494
- }, undefined, false, undefined, this) : item.kind === "reasoning" ? /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(ReasoningMessage, {
150756
+ }, undefined, false, undefined, this) : item.kind === "reasoning" ? /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(ReasoningMessage, {
150495
150757
  line: item
150496
- }, undefined, false, undefined, this) : item.kind === "assistant" ? /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(AssistantMessage, {
150758
+ }, undefined, false, undefined, this) : item.kind === "assistant" ? /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(AssistantMessage, {
150497
150759
  line: item
150498
- }, undefined, false, undefined, this) : item.kind === "tool_call" ? /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(ToolCallMessage, {
150760
+ }, undefined, false, undefined, this) : item.kind === "tool_call" ? /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(ToolCallMessage, {
150499
150761
  line: item
150500
- }, undefined, false, undefined, this) : item.kind === "error" ? /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(ErrorMessage, {
150762
+ }, undefined, false, undefined, this) : item.kind === "error" ? /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(ErrorMessage, {
150501
150763
  line: item
150502
- }, undefined, false, undefined, this) : /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(CommandMessage, {
150764
+ }, undefined, false, undefined, this) : /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(CommandMessage, {
150503
150765
  line: item
150504
150766
  }, undefined, false, undefined, this)
150505
150767
  }, item.id, false, undefined, this)
150506
- }, undefined, false, undefined, this),
150507
- /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(Box_default, {
150768
+ }, staticRenderEpoch, false, undefined, this),
150769
+ /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(Box_default, {
150508
150770
  flexDirection: "column",
150509
150771
  gap: 1,
150510
150772
  children: [
150511
- loadingState !== "ready" && /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(WelcomeScreen, {
150773
+ loadingState !== "ready" && /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(WelcomeScreen, {
150512
150774
  loadingState,
150513
150775
  continueSession,
150514
150776
  agentId: agentId !== "loading" ? agentId : undefined
150515
150777
  }, undefined, false, undefined, this),
150516
- loadingState === "ready" && /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(jsx_dev_runtime20.Fragment, {
150778
+ loadingState === "ready" && /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(jsx_dev_runtime21.Fragment, {
150517
150779
  children: [
150518
- liveItems.length > 0 && /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(Box_default, {
150780
+ liveItems.length > 0 && /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(Box_default, {
150519
150781
  flexDirection: "column",
150520
- children: liveItems.map((ln) => /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(Box_default, {
150782
+ children: liveItems.map((ln) => /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(Box_default, {
150521
150783
  marginTop: 1,
150522
- children: ln.kind === "user" ? /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(UserMessage, {
150784
+ children: ln.kind === "user" ? /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(UserMessage, {
150523
150785
  line: ln
150524
- }, undefined, false, undefined, this) : ln.kind === "reasoning" ? /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(ReasoningMessage, {
150786
+ }, undefined, false, undefined, this) : ln.kind === "reasoning" ? /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(ReasoningMessage, {
150525
150787
  line: ln
150526
- }, undefined, false, undefined, this) : ln.kind === "assistant" ? /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(AssistantMessage, {
150788
+ }, undefined, false, undefined, this) : ln.kind === "assistant" ? /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(AssistantMessage, {
150527
150789
  line: ln
150528
- }, undefined, false, undefined, this) : ln.kind === "tool_call" ? /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(ToolCallMessage, {
150790
+ }, undefined, false, undefined, this) : ln.kind === "tool_call" ? /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(ToolCallMessage, {
150529
150791
  line: ln
150530
- }, undefined, false, undefined, this) : ln.kind === "error" ? /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(ErrorMessage, {
150792
+ }, undefined, false, undefined, this) : ln.kind === "error" ? /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(ErrorMessage, {
150531
150793
  line: ln
150532
- }, undefined, false, undefined, this) : /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(CommandMessage, {
150794
+ }, undefined, false, undefined, this) : /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(CommandMessage, {
150533
150795
  line: ln
150534
150796
  }, undefined, false, undefined, this)
150535
150797
  }, ln.id, false, undefined, this))
150536
150798
  }, undefined, false, undefined, this),
150537
- liveItems.length === 0 && /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(Box_default, {
150799
+ liveItems.length === 0 && /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(Box_default, {
150538
150800
  height: 1
150539
150801
  }, undefined, false, undefined, this),
150540
- /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(Input, {
150541
- visible: !pendingApproval && !modelSelectorOpen && !planApprovalPending,
150802
+ showExitStats && /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(SessionStats2, {
150803
+ stats: sessionStatsRef.current.getSnapshot()
150804
+ }, undefined, false, undefined, this),
150805
+ /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(Input, {
150806
+ visible: !showExitStats && !pendingApproval && !modelSelectorOpen && !planApprovalPending,
150542
150807
  streaming,
150543
150808
  commandRunning,
150544
150809
  tokenCount,
150545
150810
  thinkingMessage,
150546
150811
  onSubmit,
150547
150812
  permissionMode: uiPermissionMode,
150548
- onPermissionModeChange: setUiPermissionMode
150813
+ onPermissionModeChange: setUiPermissionMode,
150814
+ onExit: handleExit
150549
150815
  }, undefined, false, undefined, this),
150550
- modelSelectorOpen && /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(ModelSelector, {
150816
+ modelSelectorOpen && /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(ModelSelector, {
150551
150817
  currentModel: llmConfig?.model,
150552
150818
  onSelect: handleModelSelect,
150553
150819
  onCancel: () => setModelSelectorOpen(false)
150554
150820
  }, undefined, false, undefined, this),
150555
- planApprovalPending && /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(jsx_dev_runtime20.Fragment, {
150821
+ planApprovalPending && /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(jsx_dev_runtime21.Fragment, {
150556
150822
  children: [
150557
- /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(Box_default, {
150823
+ /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(Box_default, {
150558
150824
  height: 1
150559
150825
  }, undefined, false, undefined, this),
150560
- /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(PlanModeDialog, {
150826
+ /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(PlanModeDialog, {
150561
150827
  plan: planApprovalPending.plan,
150562
150828
  onApprove: () => handlePlanApprove(false),
150563
150829
  onApproveAndAcceptEdits: () => handlePlanApprove(true),
@@ -150565,12 +150831,12 @@ function App2({
150565
150831
  }, undefined, false, undefined, this)
150566
150832
  ]
150567
150833
  }, undefined, true, undefined, this),
150568
- pendingApproval && /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(jsx_dev_runtime20.Fragment, {
150834
+ pendingApproval && /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(jsx_dev_runtime21.Fragment, {
150569
150835
  children: [
150570
- /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(Box_default, {
150836
+ /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(Box_default, {
150571
150837
  height: 1
150572
150838
  }, undefined, false, undefined, this),
150573
- /* @__PURE__ */ jsx_dev_runtime20.jsxDEV(ApprovalDialog, {
150839
+ /* @__PURE__ */ jsx_dev_runtime21.jsxDEV(ApprovalDialog, {
150574
150840
  approvalRequest: pendingApproval,
150575
150841
  approvalContext,
150576
150842
  onApprove: handleApprove,
@@ -150586,7 +150852,7 @@ function App2({
150586
150852
  ]
150587
150853
  }, undefined, true, undefined, this);
150588
150854
  }
150589
- var import_letta_client6, import_react36, jsx_dev_runtime20;
150855
+ var import_letta_client6, import_react37, jsx_dev_runtime21, CLEAR_SCREEN_AND_HOME = "\x1B[2J\x1B[H";
150590
150856
  var init_App2 = __esm(async () => {
150591
150857
  init_message();
150592
150858
  init_mode2();
@@ -150594,6 +150860,7 @@ var init_App2 = __esm(async () => {
150594
150860
  init_pasteRegistry();
150595
150861
  init_stream();
150596
150862
  init_thinkingMessages();
150863
+ init_useTerminalWidth();
150597
150864
  await __promiseAll([
150598
150865
  init_build3(),
150599
150866
  init_ApprovalDialogRich(),
@@ -150604,13 +150871,14 @@ var init_App2 = __esm(async () => {
150604
150871
  init_ModelSelector(),
150605
150872
  init_PlanModeDialog(),
150606
150873
  init_ReasoningMessageRich(),
150874
+ init_SessionStats(),
150607
150875
  init_ToolCallMessageRich(),
150608
150876
  init_UserMessageRich(),
150609
150877
  init_WelcomeScreen()
150610
150878
  ]);
150611
150879
  import_letta_client6 = __toESM(require_letta_client(), 1);
150612
- import_react36 = __toESM(require_react2(), 1);
150613
- jsx_dev_runtime20 = __toESM(require_jsx_dev_runtime(), 1);
150880
+ import_react37 = __toESM(require_react2(), 1);
150881
+ jsx_dev_runtime21 = __toESM(require_jsx_dev_runtime(), 1);
150614
150882
  });
150615
150883
 
150616
150884
  // src/agent/create.ts
@@ -150774,10 +151042,11 @@ init_toolDefinitions();
150774
151042
  var TOOL_NAMES = Object.keys(TOOL_DEFINITIONS);
150775
151043
  var REGISTRY_KEY = Symbol.for("@letta/toolRegistry");
150776
151044
  function getRegistry() {
150777
- if (!globalThis[REGISTRY_KEY]) {
150778
- globalThis[REGISTRY_KEY] = new Map;
151045
+ const global2 = globalThis;
151046
+ if (!global2[REGISTRY_KEY]) {
151047
+ global2[REGISTRY_KEY] = new Map;
150779
151048
  }
150780
- return globalThis[REGISTRY_KEY];
151049
+ return global2[REGISTRY_KEY];
150781
151050
  }
150782
151051
  var toolRegistry = getRegistry();
150783
151052
  function generatePythonStub(name, _description, schema) {
@@ -150859,12 +151128,17 @@ OPTIONS
150859
151128
  -c, --continue Resume previous session (uses settings.lastAgent)
150860
151129
  -a, --agent <id> Use a specific agent ID
150861
151130
  -p, --prompt Headless prompt mode
151131
+ --output-format <fmt> Output format for headless mode (text, json, stream-json)
151132
+ Default: text
150862
151133
 
150863
151134
  EXAMPLES
150864
151135
  # when installed as an executable
150865
151136
  letta --help
150866
151137
  letta --continue
150867
151138
  letta --agent agent_123
151139
+
151140
+ # headless with JSON output (includes stats)
151141
+ letta -p "hello" --output-format json
150868
151142
 
150869
151143
  `.trim();
150870
151144
  console.log(usage);
@@ -150885,7 +151159,8 @@ async function main() {
150885
151159
  allowedTools: { type: "string" },
150886
151160
  disallowedTools: { type: "string" },
150887
151161
  "permission-mode": { type: "string" },
150888
- yolo: { type: "boolean" }
151162
+ yolo: { type: "boolean" },
151163
+ "output-format": { type: "string" }
150889
151164
  },
150890
151165
  strict: true,
150891
151166
  allowPositionals: true
@@ -150960,17 +151235,17 @@ Note: Flags should use double dashes for full names (e.g., --yolo, not -yolo)`);
150960
151235
  }
150961
151236
  const React12 = await Promise.resolve().then(() => __toESM(require_react(), 1));
150962
151237
  const { render: render2 } = await init_build2().then(() => exports_build);
150963
- const { useState: useState12, useEffect: useEffect10 } = React12;
151238
+ const { useState: useState13, useEffect: useEffect11 } = React12;
150964
151239
  const AppModule = await init_App2().then(() => exports_App);
150965
151240
  const App3 = AppModule.default;
150966
151241
  function LoadingApp({
150967
151242
  continueSession,
150968
151243
  agentIdArg
150969
151244
  }) {
150970
- const [loadingState, setLoadingState] = useState12("assembling");
150971
- const [agentId, setAgentId] = useState12(null);
150972
- const [resumeData, setResumeData] = useState12(null);
150973
- useEffect10(() => {
151245
+ const [loadingState, setLoadingState] = useState13("assembling");
151246
+ const [agentId, setAgentId] = useState13(null);
151247
+ const [resumeData, setResumeData] = useState13(null);
151248
+ useEffect11(() => {
150974
151249
  async function init() {
150975
151250
  setLoadingState("assembling");
150976
151251
  await loadTools();
@@ -151038,4 +151313,4 @@ Note: Flags should use double dashes for full names (e.g., --yolo, not -yolo)`);
151038
151313
  }
151039
151314
  main();
151040
151315
 
151041
- //# debugId=37B80CB1E5E14EF264756E2164756E21
151316
+ //# debugId=6656CCE5EA031CEB64756E2164756E21