@runtypelabs/cli 1.9.0 → 1.9.2

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/dist/index.js CHANGED
@@ -3741,7 +3741,7 @@ var require_provider_routing = __commonJS({
3741
3741
  exports.extractBaseModel = extractBaseModel;
3742
3742
  exports.extractModelIdentity = extractModelIdentity;
3743
3743
  exports.getRoutedModelDisplayName = getRoutedModelDisplayName;
3744
- exports.normalizeModelId = normalizeModelId;
3744
+ exports.normalizeModelId = normalizeModelId2;
3745
3745
  exports.buildModelId = buildModelId;
3746
3746
  exports.parseModelId = parseModelId;
3747
3747
  exports.parseModelIdLegacy = parseModelIdLegacy;
@@ -4049,7 +4049,7 @@ var require_provider_routing = __commonJS({
4049
4049
  }
4050
4050
  return baseModel.split("-").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
4051
4051
  }
4052
- function normalizeModelId(modelId) {
4052
+ function normalizeModelId2(modelId) {
4053
4053
  if (modelId.startsWith("model/")) {
4054
4054
  return modelId.slice(6);
4055
4055
  }
@@ -8305,7 +8305,7 @@ import { Command as Command11 } from "commander";
8305
8305
  import chalk17 from "chalk";
8306
8306
  import React10 from "react";
8307
8307
  import { render as render10 } from "ink";
8308
- import { useState as useState22, useEffect as useEffect20 } from "react";
8308
+ import { useState as useState23, useEffect as useEffect22 } from "react";
8309
8309
  import { processStream as processStream4 } from "@runtypelabs/sdk";
8310
8310
 
8311
8311
  // src/commands/agents-task.ts
@@ -8315,17 +8315,33 @@ import { render as render9 } from "ink";
8315
8315
  import React9 from "react";
8316
8316
 
8317
8317
  // src/ink/marathon/MarathonApp.tsx
8318
- import { useState as useState20, useEffect as useEffect18, useRef as useRef8, useCallback as useCallback7, useMemo as useMemo10 } from "react";
8318
+ import { useState as useState21, useEffect as useEffect20, useRef as useRef8, useCallback as useCallback7, useMemo as useMemo10 } from "react";
8319
8319
  import { execSync } from "child_process";
8320
8320
  import * as fs3 from "fs";
8321
8321
  import open4 from "open";
8322
8322
  import { Box as Box24, Text as Text26, useApp as useApp4, useInput as useInput10, useStdout as useStdout4 } from "ink";
8323
- import { StreamOutput, StatusBar, ErrorDisplay as ErrorDisplay3, theme as theme26 } from "@runtypelabs/ink-components";
8323
+ import { StreamOutput, StatusBar, ErrorDisplay as ErrorDisplay3, theme as theme27 } from "@runtypelabs/ink-components";
8324
8324
  import { LoadingAnimation } from "@runtypelabs/terminal-animations";
8325
8325
 
8326
8326
  // src/ink/marathon/useMarathonStream.ts
8327
8327
  import { useState as useState10, useRef as useRef3, useMemo, useCallback as useCallback2 } from "react";
8328
8328
 
8329
+ // src/ink/marathon/context-compaction-format.ts
8330
+ function formatTokenCount(value) {
8331
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) return void 0;
8332
+ return value.toLocaleString();
8333
+ }
8334
+ function formatCompactionThresholdLabel(compaction) {
8335
+ const estimated = formatTokenCount(compaction.estimatedTokens);
8336
+ const threshold = formatTokenCount(compaction.thresholdTokens);
8337
+ const contextLimit = formatTokenCount(compaction.contextLimitTokens);
8338
+ if (estimated && contextLimit) return `~${estimated}/${contextLimit} tokens`;
8339
+ if (estimated && threshold) return `~${estimated}/${threshold} tokens`;
8340
+ if (estimated) return `~${estimated} tokens`;
8341
+ if (threshold && contextLimit) return `${threshold}/${contextLimit} tokens`;
8342
+ return contextLimit ? `${contextLimit} tokens` : threshold ? `${threshold} tokens` : void 0;
8343
+ }
8344
+
8329
8345
  // src/ink/marathon/transcript-utils.ts
8330
8346
  function appendTranscriptText(content, delta, previousKind) {
8331
8347
  if (!content) return delta;
@@ -8354,7 +8370,8 @@ var INITIAL_STATE = {
8354
8370
  error: null,
8355
8371
  rawEvents: [],
8356
8372
  totalInputTokens: 0,
8357
- totalOutputTokens: 0
8373
+ totalOutputTokens: 0,
8374
+ contextCompaction: null
8358
8375
  };
8359
8376
  var MAX_RAW_EVENTS = 500;
8360
8377
  function appendContentLine(content, line) {
@@ -8367,6 +8384,23 @@ function pushRawEvent(prev, type, data) {
8367
8384
  const events = [...prev.rawEvents, event];
8368
8385
  return events.length > MAX_RAW_EVENTS ? events.slice(-MAX_RAW_EVENTS) : events;
8369
8386
  }
8387
+ function formatContextCompactionCompleteLine(event) {
8388
+ const modeLabel = event.mode === "auto" ? "automatically" : "with compact mode";
8389
+ const modelLabel = event.model ? ` for ${event.model}` : "";
8390
+ const strategyLabel = event.strategy === "provider_native" ? " via provider-native compaction" : " via summary compaction";
8391
+ const thresholdLabel = formatCompactionThresholdLabel(event);
8392
+ const breakdownParts = [
8393
+ event.breakdown?.historyTokens ? `history ${formatTokenCount(event.breakdown.historyTokens)}` : void 0,
8394
+ event.breakdown?.toolOutputTokens ? `tool outputs ${formatTokenCount(event.breakdown.toolOutputTokens)}` : void 0,
8395
+ event.breakdown?.toolDefinitionTokens ? `tool defs ${formatTokenCount(event.breakdown.toolDefinitionTokens)}` : void 0,
8396
+ event.reservedOutputTokens ? `reserve ${formatTokenCount(event.reservedOutputTokens)}` : void 0
8397
+ ].filter(Boolean);
8398
+ const breakdownLabel = breakdownParts.length > 0 ? ` (${breakdownParts.join(", ")})` : "";
8399
+ return thresholdLabel ? `[context] History compacted ${modeLabel}${modelLabel}${strategyLabel} at ${thresholdLabel}${breakdownLabel}.` : `[context] History compacted ${modeLabel}${modelLabel}${strategyLabel}${breakdownLabel}.`;
8400
+ }
8401
+ function formatContextNoticeLine(event) {
8402
+ return `[context] ${event.message}`;
8403
+ }
8370
8404
  var toolCounter = 0;
8371
8405
  function useMarathonStream() {
8372
8406
  const [state, setState] = useState10(INITIAL_STATE);
@@ -8515,6 +8549,45 @@ function useMarathonStream() {
8515
8549
  const setSteering = useCallback2(() => {
8516
8550
  setState((prev) => ({ ...prev, phase: "steering" }));
8517
8551
  }, []);
8552
+ const startContextCompaction = useCallback2((event) => {
8553
+ setState((prev) => ({
8554
+ ...prev,
8555
+ contextCompaction: {
8556
+ active: true,
8557
+ mode: event.mode,
8558
+ strategy: event.strategy,
8559
+ sessionIndex: event.sessionIndex,
8560
+ model: event.model,
8561
+ estimatedTokens: event.estimatedTokens,
8562
+ thresholdTokens: event.thresholdTokens,
8563
+ contextLimitTokens: event.contextLimitTokens,
8564
+ effectiveInputBudgetTokens: event.effectiveInputBudgetTokens,
8565
+ reservedOutputTokens: event.reservedOutputTokens,
8566
+ beforeTokens: event.beforeTokens,
8567
+ afterTokens: event.afterTokens,
8568
+ breakdown: event.breakdown,
8569
+ startedAt: Date.now()
8570
+ },
8571
+ rawEvents: pushRawEvent(prev, "marathon_context_compaction_start", { ...event })
8572
+ }));
8573
+ }, []);
8574
+ const finishContextCompaction = useCallback2((event) => {
8575
+ setState((prev) => ({
8576
+ ...prev,
8577
+ contextCompaction: null,
8578
+ content: appendContentLine(prev.content, formatContextCompactionCompleteLine(event)),
8579
+ lastTranscriptKind: "text",
8580
+ rawEvents: pushRawEvent(prev, "marathon_context_compaction_complete", { ...event })
8581
+ }));
8582
+ }, []);
8583
+ const reportContextNotice = useCallback2((event) => {
8584
+ setState((prev) => ({
8585
+ ...prev,
8586
+ content: appendContentLine(prev.content, formatContextNoticeLine(event)),
8587
+ lastTranscriptKind: "text",
8588
+ rawEvents: pushRawEvent(prev, "marathon_context_notice", { ...event })
8589
+ }));
8590
+ }, []);
8518
8591
  const resetForNewSession = useCallback2(() => {
8519
8592
  setState((prev) => ({
8520
8593
  ...prev,
@@ -8525,7 +8598,8 @@ function useMarathonStream() {
8525
8598
  thinkingStartedAt: null,
8526
8599
  tools: [],
8527
8600
  currentIteration: 0,
8528
- error: null
8601
+ error: null,
8602
+ contextCompaction: null
8529
8603
  }));
8530
8604
  }, []);
8531
8605
  const showError = useCallback2((error) => {
@@ -8536,7 +8610,17 @@ function useMarathonStream() {
8536
8610
  rawEvents: pushRawEvent(prev, "agent_error", { message: error.message })
8537
8611
  }));
8538
8612
  }, []);
8539
- return { state, callbacks, reset, setSteering, resetForNewSession, showError };
8613
+ return {
8614
+ state,
8615
+ callbacks,
8616
+ reset,
8617
+ setSteering,
8618
+ startContextCompaction,
8619
+ finishContextCompaction,
8620
+ reportContextNotice,
8621
+ resetForNewSession,
8622
+ showError
8623
+ };
8540
8624
  }
8541
8625
 
8542
8626
  // src/ink/marathon/SessionHeader.tsx
@@ -8918,18 +9002,48 @@ function ThinkingIndicator({ startedAt }) {
8918
9002
  return /* @__PURE__ */ jsx11(Spinner4, { label: `Thinking... ${elapsed}s`, color: theme11.textMuted });
8919
9003
  }
8920
9004
 
9005
+ // src/ink/marathon/ContextCompactionIndicator.tsx
9006
+ import { useEffect as useEffect13, useState as useState13 } from "react";
9007
+ import { Spinner as Spinner5, theme as theme12 } from "@runtypelabs/ink-components";
9008
+ import { jsx as jsx12 } from "react/jsx-runtime";
9009
+ function buildCompactionLabel(compaction, elapsedSeconds) {
9010
+ const modeLabel = compaction.mode === "auto" ? "auto" : "manual";
9011
+ const strategyLabel = compaction.strategy === "provider_native" ? "native" : "summary";
9012
+ const thresholdLabel = formatCompactionThresholdLabel(compaction);
9013
+ if (thresholdLabel) {
9014
+ return `Compacting context for session ${compaction.sessionIndex} (${modeLabel}, ${strategyLabel}, ${thresholdLabel})... ${elapsedSeconds}s`;
9015
+ }
9016
+ return `Compacting context for session ${compaction.sessionIndex} (${modeLabel}, ${strategyLabel})... ${elapsedSeconds}s`;
9017
+ }
9018
+ function ContextCompactionIndicator({
9019
+ compaction
9020
+ }) {
9021
+ const [elapsed, setElapsed] = useState13(
9022
+ () => Math.floor((Date.now() - compaction.startedAt) / 1e3)
9023
+ );
9024
+ useEffect13(() => {
9025
+ const start = compaction.startedAt;
9026
+ setElapsed(Math.floor((Date.now() - start) / 1e3));
9027
+ const interval = setInterval(() => {
9028
+ setElapsed(Math.floor((Date.now() - start) / 1e3));
9029
+ }, 1e3);
9030
+ return () => clearInterval(interval);
9031
+ }, [compaction.startedAt]);
9032
+ return /* @__PURE__ */ jsx12(Spinner5, { label: buildCompactionLabel(compaction, elapsed), color: theme12.warning });
9033
+ }
9034
+
8921
9035
  // src/ink/marathon/ToolPanel.tsx
8922
- import { useState as useState13, useEffect as useEffect13, useMemo as useMemo2 } from "react";
9036
+ import { useState as useState14, useEffect as useEffect14, useMemo as useMemo2 } from "react";
8923
9037
  import { Box as Box11, Text as Text12 } from "ink";
8924
- import { Spinner as Spinner5, theme as theme13 } from "@runtypelabs/ink-components";
9038
+ import { Spinner as Spinner6, theme as theme14 } from "@runtypelabs/ink-components";
8925
9039
 
8926
9040
  // src/ink/marathon/ReasoningBlock.tsx
8927
9041
  import { Box as Box10, Text as Text11 } from "ink";
8928
- import { theme as theme12 } from "@runtypelabs/ink-components";
8929
- import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
8930
- var REASONING_LABEL_COLOR = theme12.accent;
8931
- var REASONING_TEXT_COLOR = theme12.textMuted;
8932
- var REASONING_HINT_COLOR = theme12.textSubtle;
9042
+ import { theme as theme13 } from "@runtypelabs/ink-components";
9043
+ import { jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
9044
+ var REASONING_LABEL_COLOR = theme13.accent;
9045
+ var REASONING_TEXT_COLOR = theme13.textMuted;
9046
+ var REASONING_HINT_COLOR = theme13.textSubtle;
8933
9047
  function renderReasoningLine(line) {
8934
9048
  return line ? `| ${line}` : "|";
8935
9049
  }
@@ -8944,14 +9058,14 @@ function ReasoningBlock({
8944
9058
  const hint = showToggleHint ? collapsed ? "r to show" : "r to hide" : null;
8945
9059
  return /* @__PURE__ */ jsxs9(Box10, { flexDirection: "column", children: [
8946
9060
  /* @__PURE__ */ jsxs9(Box10, { children: [
8947
- /* @__PURE__ */ jsx12(Text11, { color: REASONING_LABEL_COLOR, children: label }),
9061
+ /* @__PURE__ */ jsx13(Text11, { color: REASONING_LABEL_COLOR, children: label }),
8948
9062
  hint && /* @__PURE__ */ jsxs9(Text11, { color: REASONING_HINT_COLOR, children: [
8949
9063
  " (",
8950
9064
  hint,
8951
9065
  ")"
8952
9066
  ] })
8953
9067
  ] }),
8954
- !collapsed && lines.map((line, index) => /* @__PURE__ */ jsx12(
9068
+ !collapsed && lines.map((line, index) => /* @__PURE__ */ jsx13(
8955
9069
  Text11,
8956
9070
  {
8957
9071
  color: REASONING_TEXT_COLOR,
@@ -8960,12 +9074,12 @@ function ReasoningBlock({
8960
9074
  },
8961
9075
  `${index}:${line}`
8962
9076
  )),
8963
- !collapsed && live && /* @__PURE__ */ jsx12(Text11, { color: REASONING_TEXT_COLOR, wrap: compact ? "truncate" : void 0, children: "| ..." })
9077
+ !collapsed && live && /* @__PURE__ */ jsx13(Text11, { color: REASONING_TEXT_COLOR, wrap: compact ? "truncate" : void 0, children: "| ..." })
8964
9078
  ] });
8965
9079
  }
8966
9080
 
8967
9081
  // src/ink/marathon/ToolPanel.tsx
8968
- import { Fragment, jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
9082
+ import { Fragment, jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
8969
9083
  var REASONING_PREVIEW_LINES = 4;
8970
9084
  var STATUS_ICONS = {
8971
9085
  complete: "\u2713",
@@ -8983,18 +9097,18 @@ function formatElapsed(tool, now) {
8983
9097
  return `${((now - tool.startedAt) / 1e3).toFixed(1)}s`;
8984
9098
  }
8985
9099
  function getStatusColor(status) {
8986
- if (status === "error") return theme13.danger;
8987
- if (status === "complete") return theme13.success;
8988
- return theme13.accent;
9100
+ if (status === "error") return theme14.danger;
9101
+ if (status === "complete") return theme14.success;
9102
+ return theme14.accent;
8989
9103
  }
8990
9104
  function ToolPanel({ tools, reasoning, files, maxHeight }) {
8991
- const [now, setNow] = useState13(Date.now());
9105
+ const [now, setNow] = useState14(Date.now());
8992
9106
  const hasRunning = tools.some((t) => t.status === "running");
8993
9107
  const reasoningLines = useMemo2(
8994
9108
  () => getVisibleReasoningLines(reasoning || "", REASONING_PREVIEW_LINES),
8995
9109
  [reasoning]
8996
9110
  );
8997
- useEffect13(() => {
9111
+ useEffect14(() => {
8998
9112
  if (!hasRunning) return;
8999
9113
  const interval = setInterval(() => setNow(Date.now()), 100);
9000
9114
  return () => clearInterval(interval);
@@ -9014,10 +9128,10 @@ function ToolPanel({ tools, reasoning, files, maxHeight }) {
9014
9128
  }, [tools, files, maxHeight, reasoningLines]);
9015
9129
  const hiddenToolCount = tools.length - visibleTools.length;
9016
9130
  const hiddenFileCount = (files || []).length - visibleFiles.length;
9017
- return /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", backgroundColor: theme13.background, children: [
9018
- reasoningLines.length > 0 && /* @__PURE__ */ jsx13(Box11, { flexDirection: "column", marginBottom: theme13.sectionGap, children: /* @__PURE__ */ jsx13(ReasoningBlock, { lines: reasoningLines, compact: true }) }),
9019
- /* @__PURE__ */ jsx13(Text12, { bold: true, color: theme13.accent, children: "Activity" }),
9020
- hiddenToolCount > 0 && /* @__PURE__ */ jsxs10(Text12, { color: theme13.textSubtle, children: [
9131
+ return /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", backgroundColor: theme14.background, children: [
9132
+ reasoningLines.length > 0 && /* @__PURE__ */ jsx14(Box11, { flexDirection: "column", marginBottom: theme14.sectionGap, children: /* @__PURE__ */ jsx14(ReasoningBlock, { lines: reasoningLines, compact: true }) }),
9133
+ /* @__PURE__ */ jsx14(Text12, { bold: true, color: theme14.accent, children: "Activity" }),
9134
+ hiddenToolCount > 0 && /* @__PURE__ */ jsxs10(Text12, { color: theme14.textSubtle, children: [
9021
9135
  " ",
9022
9136
  hiddenToolCount,
9023
9137
  " earlier hidden"
@@ -9026,9 +9140,9 @@ function ToolPanel({ tools, reasoning, files, maxHeight }) {
9026
9140
  const statusColor = getStatusColor(tool.status);
9027
9141
  const elapsed = formatElapsed(tool, now);
9028
9142
  return /* @__PURE__ */ jsxs10(Box11, { flexDirection: "row", flexWrap: "nowrap", children: [
9029
- /* @__PURE__ */ jsx13(Box11, { width: 2, flexShrink: 0, children: tool.status === "running" ? /* @__PURE__ */ jsx13(Spinner5, { label: "", color: theme13.spinner }) : /* @__PURE__ */ jsx13(Text12, { color: statusColor, children: STATUS_ICONS[tool.status] || "?" }) }),
9030
- /* @__PURE__ */ jsx13(Box11, { flexShrink: 1, flexGrow: 1, children: /* @__PURE__ */ jsx13(Text12, { color: theme13.text, wrap: "truncate", children: tool.name }) }),
9031
- /* @__PURE__ */ jsx13(Box11, { flexShrink: 0, children: /* @__PURE__ */ jsxs10(Text12, { color: theme13.textMuted, children: [
9143
+ /* @__PURE__ */ jsx14(Box11, { width: 2, flexShrink: 0, children: tool.status === "running" ? /* @__PURE__ */ jsx14(Spinner6, { label: "", color: theme14.spinner }) : /* @__PURE__ */ jsx14(Text12, { color: statusColor, children: STATUS_ICONS[tool.status] || "?" }) }),
9144
+ /* @__PURE__ */ jsx14(Box11, { flexShrink: 1, flexGrow: 1, children: /* @__PURE__ */ jsx14(Text12, { color: theme14.text, wrap: "truncate", children: tool.name }) }),
9145
+ /* @__PURE__ */ jsx14(Box11, { flexShrink: 0, children: /* @__PURE__ */ jsxs10(Text12, { color: theme14.textMuted, children: [
9032
9146
  " ",
9033
9147
  elapsed
9034
9148
  ] }) })
@@ -9036,8 +9150,8 @@ function ToolPanel({ tools, reasoning, files, maxHeight }) {
9036
9150
  }),
9037
9151
  visibleFiles.length > 0 && /* @__PURE__ */ jsxs10(Fragment, { children: [
9038
9152
  /* @__PURE__ */ jsxs10(Box11, { marginTop: 1, children: [
9039
- /* @__PURE__ */ jsx13(Text12, { bold: true, color: theme13.accent, children: "Files" }),
9040
- hiddenFileCount > 0 && /* @__PURE__ */ jsxs10(Text12, { color: theme13.textSubtle, children: [
9153
+ /* @__PURE__ */ jsx14(Text12, { bold: true, color: theme14.accent, children: "Files" }),
9154
+ hiddenFileCount > 0 && /* @__PURE__ */ jsxs10(Text12, { color: theme14.textSubtle, children: [
9041
9155
  " +",
9042
9156
  hiddenFileCount
9043
9157
  ] })
@@ -9046,8 +9160,8 @@ function ToolPanel({ tools, reasoning, files, maxHeight }) {
9046
9160
  const icon = FILE_TYPE_ICONS[file.type] || "\u2022";
9047
9161
  const filename = file.path.split("/").pop() || file.path;
9048
9162
  return /* @__PURE__ */ jsxs10(Box11, { flexDirection: "row", flexWrap: "nowrap", children: [
9049
- /* @__PURE__ */ jsx13(Box11, { width: 2, flexShrink: 0, children: /* @__PURE__ */ jsx13(Text12, { color: file.type === "written" ? theme13.success : theme13.textMuted, children: icon }) }),
9050
- /* @__PURE__ */ jsx13(Box11, { flexShrink: 1, children: /* @__PURE__ */ jsx13(Text12, { color: theme13.text, wrap: "truncate", children: filename }) })
9163
+ /* @__PURE__ */ jsx14(Box11, { width: 2, flexShrink: 0, children: /* @__PURE__ */ jsx14(Text12, { color: file.type === "written" ? theme14.success : theme14.textMuted, children: icon }) }),
9164
+ /* @__PURE__ */ jsx14(Box11, { flexShrink: 1, children: /* @__PURE__ */ jsx14(Text12, { color: theme14.text, wrap: "truncate", children: filename }) })
9051
9165
  ] }, file.path);
9052
9166
  })
9053
9167
  ] })
@@ -9055,28 +9169,28 @@ function ToolPanel({ tools, reasoning, files, maxHeight }) {
9055
9169
  }
9056
9170
 
9057
9171
  // src/ink/marathon/ToolsPanel.tsx
9058
- import { useState as useState14, useEffect as useEffect14, useMemo as useMemo3 } from "react";
9172
+ import { useState as useState15, useEffect as useEffect15, useMemo as useMemo3 } from "react";
9059
9173
  import { Box as Box13, Text as Text14 } from "ink";
9060
- import { Spinner as Spinner6, theme as theme15 } from "@runtypelabs/ink-components";
9174
+ import { Spinner as Spinner7, theme as theme16 } from "@runtypelabs/ink-components";
9061
9175
 
9062
9176
  // src/ink/marathon/Scrollbar.tsx
9063
9177
  import { Box as Box12, Text as Text13 } from "ink";
9064
- import { theme as theme14 } from "@runtypelabs/ink-components";
9065
- import { jsx as jsx14 } from "react/jsx-runtime";
9178
+ import { theme as theme15 } from "@runtypelabs/ink-components";
9179
+ import { jsx as jsx15 } from "react/jsx-runtime";
9066
9180
  function Scrollbar({ totalLines, visibleLines, scrollOffset, height }) {
9067
9181
  if (totalLines <= visibleLines) return null;
9068
9182
  const maxScroll = Math.max(0, totalLines - visibleLines);
9069
9183
  const clampedOffset = Math.min(scrollOffset, maxScroll);
9070
9184
  const thumbSize = Math.max(1, Math.round(visibleLines / totalLines * height));
9071
9185
  const thumbStart = maxScroll > 0 ? Math.round(clampedOffset / maxScroll * (height - thumbSize)) : 0;
9072
- return /* @__PURE__ */ jsx14(Box12, { flexDirection: "column", marginLeft: 1, children: Array.from({ length: height }, (_, i) => {
9186
+ return /* @__PURE__ */ jsx15(Box12, { flexDirection: "column", marginLeft: 1, children: Array.from({ length: height }, (_, i) => {
9073
9187
  const isThumb = i >= thumbStart && i < thumbStart + thumbSize;
9074
- return /* @__PURE__ */ jsx14(Text13, { color: isThumb ? theme14.textMuted : theme14.border, children: isThumb ? "\u2588" : "\u2502" }, i);
9188
+ return /* @__PURE__ */ jsx15(Text13, { color: isThumb ? theme15.textMuted : theme15.border, children: isThumb ? "\u2588" : "\u2502" }, i);
9075
9189
  }) });
9076
9190
  }
9077
9191
 
9078
9192
  // src/ink/marathon/ToolsPanel.tsx
9079
- import { jsx as jsx15, jsxs as jsxs11 } from "react/jsx-runtime";
9193
+ import { jsx as jsx16, jsxs as jsxs11 } from "react/jsx-runtime";
9080
9194
  function formatElapsed2(tool, now) {
9081
9195
  if (tool.executionTime != null) {
9082
9196
  return `${(tool.executionTime / 1e3).toFixed(1)}s`;
@@ -9088,9 +9202,9 @@ var STATUS_ICONS2 = {
9088
9202
  error: "\u2717"
9089
9203
  };
9090
9204
  function getStatusColor2(status) {
9091
- if (status === "error") return theme15.danger;
9092
- if (status === "complete") return theme15.success;
9093
- return theme15.accent;
9205
+ if (status === "error") return theme16.danger;
9206
+ if (status === "complete") return theme16.success;
9207
+ return theme16.accent;
9094
9208
  }
9095
9209
  function wrapLines(lines, width) {
9096
9210
  if (width <= 0) return lines;
@@ -9141,7 +9255,7 @@ function ToolDetailView({
9141
9255
  scrollOffset = 0,
9142
9256
  width = 120
9143
9257
  }) {
9144
- const separator = theme15.separator ?? " \xB7 ";
9258
+ const separator = theme16.separator ?? " \xB7 ";
9145
9259
  const statusColor = getStatusColor2(tool.status);
9146
9260
  const { lines, totalLines, clampedOffset } = useMemo3(() => {
9147
9261
  const allLines = getToolDetailLines(tool, width);
@@ -9155,29 +9269,29 @@ function ToolDetailView({
9155
9269
  Box13,
9156
9270
  {
9157
9271
  flexDirection: "column",
9158
- paddingX: theme15.panelPaddingX,
9159
- paddingY: theme15.panelPaddingY,
9272
+ paddingX: theme16.panelPaddingX,
9273
+ paddingY: theme16.panelPaddingY,
9160
9274
  children: [
9161
- /* @__PURE__ */ jsxs11(Box13, { marginBottom: theme15.sectionGap, children: [
9162
- tool.status === "running" ? /* @__PURE__ */ jsx15(Spinner6, { label: "", color: theme15.spinner }) : /* @__PURE__ */ jsx15(Text14, { color: statusColor, children: STATUS_ICONS2[tool.status] || "?" }),
9163
- /* @__PURE__ */ jsx15(Text14, { color: theme15.textMuted, children: ` [${tool.sequence}] ` }),
9164
- /* @__PURE__ */ jsx15(Text14, { bold: true, color: theme15.text, children: tool.name }),
9165
- /* @__PURE__ */ jsxs11(Text14, { color: theme15.textMuted, children: [
9275
+ /* @__PURE__ */ jsxs11(Box13, { marginBottom: theme16.sectionGap, children: [
9276
+ tool.status === "running" ? /* @__PURE__ */ jsx16(Spinner7, { label: "", color: theme16.spinner }) : /* @__PURE__ */ jsx16(Text14, { color: statusColor, children: STATUS_ICONS2[tool.status] || "?" }),
9277
+ /* @__PURE__ */ jsx16(Text14, { color: theme16.textMuted, children: ` [${tool.sequence}] ` }),
9278
+ /* @__PURE__ */ jsx16(Text14, { bold: true, color: theme16.text, children: tool.name }),
9279
+ /* @__PURE__ */ jsxs11(Text14, { color: theme16.textMuted, children: [
9166
9280
  " ",
9167
9281
  formatElapsed2(tool, now)
9168
9282
  ] }),
9169
- /* @__PURE__ */ jsxs11(Text14, { color: theme15.textSubtle, children: [
9283
+ /* @__PURE__ */ jsxs11(Text14, { color: theme16.textSubtle, children: [
9170
9284
  separator,
9171
9285
  "c: copy"
9172
9286
  ] }),
9173
- /* @__PURE__ */ jsxs11(Text14, { color: theme15.textSubtle, children: [
9287
+ /* @__PURE__ */ jsxs11(Text14, { color: theme16.textSubtle, children: [
9174
9288
  separator,
9175
9289
  "Esc: close"
9176
9290
  ] })
9177
9291
  ] }),
9178
9292
  /* @__PURE__ */ jsxs11(Box13, { flexDirection: "row", flexGrow: 1, children: [
9179
- /* @__PURE__ */ jsx15(Box13, { flexDirection: "column", flexGrow: 1, children: lines.map((line, i) => /* @__PURE__ */ jsx15(Text14, { color: theme15.text, wrap: "truncate", children: line }, i)) }),
9180
- /* @__PURE__ */ jsx15(
9293
+ /* @__PURE__ */ jsx16(Box13, { flexDirection: "column", flexGrow: 1, children: lines.map((line, i) => /* @__PURE__ */ jsx16(Text14, { color: theme16.text, wrap: "truncate", children: line }, i)) }),
9294
+ /* @__PURE__ */ jsx16(
9181
9295
  Scrollbar,
9182
9296
  {
9183
9297
  totalLines,
@@ -9199,10 +9313,10 @@ function ToolsPanel({
9199
9313
  detailScrollOffset = 0,
9200
9314
  width = 120
9201
9315
  }) {
9202
- const separator = theme15.separator ?? " \xB7 ";
9203
- const [now, setNow] = useState14(Date.now());
9316
+ const separator = theme16.separator ?? " \xB7 ";
9317
+ const [now, setNow] = useState15(Date.now());
9204
9318
  const hasRunning = tools.some((t) => t.status === "running");
9205
- useEffect14(() => {
9319
+ useEffect15(() => {
9206
9320
  if (!hasRunning) return;
9207
9321
  const interval = setInterval(() => setNow(Date.now()), 100);
9208
9322
  return () => clearInterval(interval);
@@ -9232,7 +9346,7 @@ function ToolsPanel({
9232
9346
  };
9233
9347
  }, [tools, maxVisibleLines, selectedIndex]);
9234
9348
  if (detailTool) {
9235
- return /* @__PURE__ */ jsx15(
9349
+ return /* @__PURE__ */ jsx16(
9236
9350
  ToolDetailView,
9237
9351
  {
9238
9352
  tool: detailTool,
@@ -9244,13 +9358,13 @@ function ToolsPanel({
9244
9358
  );
9245
9359
  }
9246
9360
  if (tools.length === 0) {
9247
- return /* @__PURE__ */ jsx15(
9361
+ return /* @__PURE__ */ jsx16(
9248
9362
  Box13,
9249
9363
  {
9250
9364
  flexDirection: "column",
9251
- paddingX: theme15.panelPaddingX,
9252
- paddingY: theme15.panelPaddingY,
9253
- children: /* @__PURE__ */ jsx15(Text14, { color: theme15.textSubtle, children: "No tool calls yet..." })
9365
+ paddingX: theme16.panelPaddingX,
9366
+ paddingY: theme16.panelPaddingY,
9367
+ children: /* @__PURE__ */ jsx16(Text14, { color: theme16.textSubtle, children: "No tool calls yet..." })
9254
9368
  }
9255
9369
  );
9256
9370
  }
@@ -9258,43 +9372,43 @@ function ToolsPanel({
9258
9372
  Box13,
9259
9373
  {
9260
9374
  flexDirection: "column",
9261
- paddingX: theme15.panelPaddingX,
9262
- paddingY: theme15.panelPaddingY,
9375
+ paddingX: theme16.panelPaddingX,
9376
+ paddingY: theme16.panelPaddingY,
9263
9377
  children: [
9264
9378
  /* @__PURE__ */ jsxs11(Box13, { marginBottom: 0, children: [
9265
- /* @__PURE__ */ jsx15(Text14, { bold: true, color: theme15.accent, children: "Tools" }),
9266
- /* @__PURE__ */ jsxs11(Text14, { color: theme15.textSubtle, children: [
9379
+ /* @__PURE__ */ jsx16(Text14, { bold: true, color: theme16.accent, children: "Tools" }),
9380
+ /* @__PURE__ */ jsxs11(Text14, { color: theme16.textSubtle, children: [
9267
9381
  separator,
9268
9382
  tools.length,
9269
9383
  " calls"
9270
9384
  ] })
9271
9385
  ] }),
9272
9386
  /* @__PURE__ */ jsxs11(Box13, { flexDirection: "row", children: [
9273
- /* @__PURE__ */ jsx15(Box13, { flexDirection: "column", flexGrow: 1, children: rows.map((row) => {
9387
+ /* @__PURE__ */ jsx16(Box13, { flexDirection: "column", flexGrow: 1, children: rows.map((row) => {
9274
9388
  const isSelected = row.globalIndex === selectedIndex;
9275
9389
  const statusColor = getStatusColor2(row.tool.status);
9276
9390
  const elapsed = formatElapsed2(row.tool, now);
9277
9391
  return /* @__PURE__ */ jsxs11(Box13, { flexDirection: "row", flexWrap: "nowrap", children: [
9278
- /* @__PURE__ */ jsx15(Box13, { width: 2, flexShrink: 0, children: /* @__PURE__ */ jsx15(Text14, { color: isSelected ? theme15.accentActive : theme15.textSubtle, children: isSelected ? "\u203A" : " " }) }),
9279
- /* @__PURE__ */ jsx15(Box13, { width: 2, flexShrink: 0, children: row.tool.status === "running" ? /* @__PURE__ */ jsx15(Spinner6, { label: "", color: theme15.spinner }) : /* @__PURE__ */ jsx15(Text14, { color: statusColor, children: STATUS_ICONS2[row.tool.status] || "?" }) }),
9280
- /* @__PURE__ */ jsx15(Box13, { width: 5, flexShrink: 0, children: /* @__PURE__ */ jsxs11(Text14, { color: theme15.textMuted, children: [
9392
+ /* @__PURE__ */ jsx16(Box13, { width: 2, flexShrink: 0, children: /* @__PURE__ */ jsx16(Text14, { color: isSelected ? theme16.accentActive : theme16.textSubtle, children: isSelected ? "\u203A" : " " }) }),
9393
+ /* @__PURE__ */ jsx16(Box13, { width: 2, flexShrink: 0, children: row.tool.status === "running" ? /* @__PURE__ */ jsx16(Spinner7, { label: "", color: theme16.spinner }) : /* @__PURE__ */ jsx16(Text14, { color: statusColor, children: STATUS_ICONS2[row.tool.status] || "?" }) }),
9394
+ /* @__PURE__ */ jsx16(Box13, { width: 5, flexShrink: 0, children: /* @__PURE__ */ jsxs11(Text14, { color: theme16.textMuted, children: [
9281
9395
  "[",
9282
9396
  row.tool.sequence,
9283
9397
  "] "
9284
9398
  ] }) }),
9285
- /* @__PURE__ */ jsx15(Box13, { flexShrink: 1, flexGrow: 1, children: /* @__PURE__ */ jsx15(
9399
+ /* @__PURE__ */ jsx16(Box13, { flexShrink: 1, flexGrow: 1, children: /* @__PURE__ */ jsx16(
9286
9400
  Text14,
9287
9401
  {
9288
- color: isSelected ? theme15.accentActive : theme15.text,
9402
+ color: isSelected ? theme16.accentActive : theme16.text,
9289
9403
  bold: isSelected,
9290
9404
  wrap: "truncate",
9291
9405
  children: row.tool.name
9292
9406
  }
9293
9407
  ) }),
9294
- /* @__PURE__ */ jsx15(Box13, { width: 7, flexShrink: 0, justifyContent: "flex-end", children: /* @__PURE__ */ jsx15(Text14, { color: theme15.textMuted, children: elapsed }) })
9408
+ /* @__PURE__ */ jsx16(Box13, { width: 7, flexShrink: 0, justifyContent: "flex-end", children: /* @__PURE__ */ jsx16(Text14, { color: theme16.textMuted, children: elapsed }) })
9295
9409
  ] }, row.key);
9296
9410
  }) }),
9297
- /* @__PURE__ */ jsx15(
9411
+ /* @__PURE__ */ jsx16(
9298
9412
  Scrollbar,
9299
9413
  {
9300
9414
  totalLines: tools.length,
@@ -9312,19 +9426,22 @@ function ToolsPanel({
9312
9426
  // src/ink/marathon/EventStreamPanel.tsx
9313
9427
  import { useMemo as useMemo4 } from "react";
9314
9428
  import { Box as Box14, Text as Text15 } from "ink";
9315
- import { theme as theme16 } from "@runtypelabs/ink-components";
9316
- import { jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
9429
+ import { theme as theme17 } from "@runtypelabs/ink-components";
9430
+ import { jsx as jsx17, jsxs as jsxs12 } from "react/jsx-runtime";
9317
9431
  var EVENT_COLORS = {
9318
- agent_start: theme16.success,
9319
- agent_complete: theme16.success,
9320
- agent_error: theme16.danger,
9321
- agent_await: theme16.warning,
9322
- agent_iteration_start: theme16.accent,
9323
- agent_iteration_complete: theme16.accent,
9324
- agent_turn_delta: theme16.textMuted,
9325
- agent_turn_complete: theme16.accentActive,
9326
- agent_tool_start: theme16.warning,
9327
- agent_tool_complete: theme16.warning
9432
+ agent_start: theme17.success,
9433
+ agent_complete: theme17.success,
9434
+ agent_error: theme17.danger,
9435
+ agent_await: theme17.warning,
9436
+ agent_iteration_start: theme17.accent,
9437
+ agent_iteration_complete: theme17.accent,
9438
+ agent_turn_delta: theme17.textMuted,
9439
+ agent_turn_complete: theme17.accentActive,
9440
+ agent_tool_start: theme17.warning,
9441
+ agent_tool_complete: theme17.warning,
9442
+ marathon_context_compaction_start: theme17.warning,
9443
+ marathon_context_compaction_complete: theme17.success,
9444
+ marathon_context_notice: theme17.warning
9328
9445
  };
9329
9446
  function formatTimestamp(ts, start) {
9330
9447
  if (!start) return "0.000s";
@@ -9369,7 +9486,7 @@ function EventDetailView({
9369
9486
  scrollOffset = 0,
9370
9487
  width = 120
9371
9488
  }) {
9372
- const separator = theme16.separator ?? " \xB7 ";
9489
+ const separator = theme17.separator ?? " \xB7 ";
9373
9490
  const { lines, totalLines, clampedOffset } = useMemo4(() => {
9374
9491
  const allLines = getEventDetailLines(event, width);
9375
9492
  const total = allLines.length;
@@ -9378,32 +9495,32 @@ function EventDetailView({
9378
9495
  const end = Math.min(total, start + maxVisibleLines);
9379
9496
  return { lines: allLines.slice(start, end), totalLines: total, clampedOffset: clamped };
9380
9497
  }, [event, maxVisibleLines, scrollOffset, width]);
9381
- const color = EVENT_COLORS[event.type] || theme16.text;
9498
+ const color = EVENT_COLORS[event.type] || theme17.text;
9382
9499
  return /* @__PURE__ */ jsxs12(
9383
9500
  Box14,
9384
9501
  {
9385
9502
  flexDirection: "column",
9386
- paddingX: theme16.panelPaddingX,
9387
- paddingY: theme16.panelPaddingY,
9503
+ paddingX: theme17.panelPaddingX,
9504
+ paddingY: theme17.panelPaddingY,
9388
9505
  children: [
9389
- /* @__PURE__ */ jsxs12(Box14, { marginBottom: theme16.sectionGap, children: [
9390
- /* @__PURE__ */ jsxs12(Text15, { color: theme16.textMuted, children: [
9506
+ /* @__PURE__ */ jsxs12(Box14, { marginBottom: theme17.sectionGap, children: [
9507
+ /* @__PURE__ */ jsxs12(Text15, { color: theme17.textMuted, children: [
9391
9508
  formatTimestamp(event.timestamp, startTime),
9392
9509
  " "
9393
9510
  ] }),
9394
- /* @__PURE__ */ jsx16(Text15, { bold: true, color, children: event.type }),
9395
- /* @__PURE__ */ jsxs12(Text15, { color: theme16.textSubtle, children: [
9511
+ /* @__PURE__ */ jsx17(Text15, { bold: true, color, children: event.type }),
9512
+ /* @__PURE__ */ jsxs12(Text15, { color: theme17.textSubtle, children: [
9396
9513
  separator,
9397
9514
  "c: copy"
9398
9515
  ] }),
9399
- /* @__PURE__ */ jsxs12(Text15, { color: theme16.textSubtle, children: [
9516
+ /* @__PURE__ */ jsxs12(Text15, { color: theme17.textSubtle, children: [
9400
9517
  separator,
9401
9518
  "Esc: close"
9402
9519
  ] })
9403
9520
  ] }),
9404
9521
  /* @__PURE__ */ jsxs12(Box14, { flexDirection: "row", flexGrow: 1, children: [
9405
- /* @__PURE__ */ jsx16(Box14, { flexDirection: "column", flexGrow: 1, children: lines.map((line, i) => /* @__PURE__ */ jsx16(Text15, { color: theme16.text, wrap: "truncate", children: line }, i)) }),
9406
- /* @__PURE__ */ jsx16(
9522
+ /* @__PURE__ */ jsx17(Box14, { flexDirection: "column", flexGrow: 1, children: lines.map((line, i) => /* @__PURE__ */ jsx17(Text15, { color: theme17.text, wrap: "truncate", children: line }, i)) }),
9523
+ /* @__PURE__ */ jsx17(
9407
9524
  Scrollbar,
9408
9525
  {
9409
9526
  totalLines,
@@ -9426,7 +9543,7 @@ function EventStreamPanel({
9426
9543
  detailScrollOffset = 0,
9427
9544
  width = 120
9428
9545
  }) {
9429
- const separator = theme16.separator ?? " \xB7 ";
9546
+ const separator = theme17.separator ?? " \xB7 ";
9430
9547
  const { rows, hiddenAbove } = useMemo4(() => {
9431
9548
  if (events.length === 0) return { rows: [], hiddenAbove: 0 };
9432
9549
  const total = events.length;
@@ -9448,14 +9565,14 @@ function EventStreamPanel({
9448
9565
  key: `${start + i}`,
9449
9566
  time: formatTimestamp(evt.timestamp, startTime),
9450
9567
  type: evt.type,
9451
- color: EVENT_COLORS[evt.type] || theme16.text,
9568
+ color: EVENT_COLORS[evt.type] || theme17.text,
9452
9569
  data: formatEventData(evt.data)
9453
9570
  })),
9454
9571
  hiddenAbove: start
9455
9572
  };
9456
9573
  }, [events, startTime, maxVisibleLines, selectedIndex]);
9457
9574
  if (detailEvent) {
9458
- return /* @__PURE__ */ jsx16(
9575
+ return /* @__PURE__ */ jsx17(
9459
9576
  EventDetailView,
9460
9577
  {
9461
9578
  event: detailEvent,
@@ -9467,13 +9584,13 @@ function EventStreamPanel({
9467
9584
  );
9468
9585
  }
9469
9586
  if (events.length === 0) {
9470
- return /* @__PURE__ */ jsx16(
9587
+ return /* @__PURE__ */ jsx17(
9471
9588
  Box14,
9472
9589
  {
9473
9590
  flexDirection: "column",
9474
- paddingX: theme16.panelPaddingX,
9475
- paddingY: theme16.panelPaddingY,
9476
- children: /* @__PURE__ */ jsx16(Text15, { color: theme16.textSubtle, children: "Waiting for events..." })
9591
+ paddingX: theme17.panelPaddingX,
9592
+ paddingY: theme17.panelPaddingY,
9593
+ children: /* @__PURE__ */ jsx17(Text15, { color: theme17.textSubtle, children: "Waiting for events..." })
9477
9594
  }
9478
9595
  );
9479
9596
  }
@@ -9481,28 +9598,28 @@ function EventStreamPanel({
9481
9598
  Box14,
9482
9599
  {
9483
9600
  flexDirection: "column",
9484
- paddingX: theme16.panelPaddingX,
9485
- paddingY: theme16.panelPaddingY,
9601
+ paddingX: theme17.panelPaddingX,
9602
+ paddingY: theme17.panelPaddingY,
9486
9603
  children: [
9487
9604
  /* @__PURE__ */ jsxs12(Box14, { marginBottom: 0, children: [
9488
- /* @__PURE__ */ jsx16(Text15, { bold: true, color: theme16.accent, children: "Event Stream" }),
9489
- /* @__PURE__ */ jsxs12(Text15, { color: theme16.textSubtle, children: [
9605
+ /* @__PURE__ */ jsx17(Text15, { bold: true, color: theme17.accent, children: "Event Stream" }),
9606
+ /* @__PURE__ */ jsxs12(Text15, { color: theme17.textSubtle, children: [
9490
9607
  separator,
9491
9608
  events.length,
9492
9609
  " events"
9493
9610
  ] })
9494
9611
  ] }),
9495
9612
  /* @__PURE__ */ jsxs12(Box14, { flexDirection: "row", children: [
9496
- /* @__PURE__ */ jsx16(Box14, { flexDirection: "column", flexGrow: 1, children: rows.map((row) => {
9613
+ /* @__PURE__ */ jsx17(Box14, { flexDirection: "column", flexGrow: 1, children: rows.map((row) => {
9497
9614
  const isSelected = row.globalIndex === selectedIndex;
9498
9615
  return /* @__PURE__ */ jsxs12(Box14, { flexDirection: "row", flexWrap: "nowrap", children: [
9499
- /* @__PURE__ */ jsx16(Box14, { width: 2, flexShrink: 0, children: /* @__PURE__ */ jsx16(Text15, { color: isSelected ? theme16.accentActive : theme16.textSubtle, children: isSelected ? "\u203A" : " " }) }),
9500
- /* @__PURE__ */ jsx16(Box14, { width: 9, flexShrink: 0, children: /* @__PURE__ */ jsx16(Text15, { color: theme16.textMuted, children: row.time }) }),
9501
- /* @__PURE__ */ jsx16(Box14, { width: 28, flexShrink: 0, children: /* @__PURE__ */ jsx16(Text15, { color: isSelected ? theme16.accentActive : row.color, bold: isSelected, children: row.type }) }),
9502
- /* @__PURE__ */ jsx16(Box14, { flexShrink: 1, children: /* @__PURE__ */ jsx16(Text15, { color: theme16.textMuted, wrap: "truncate", children: row.data }) })
9616
+ /* @__PURE__ */ jsx17(Box14, { width: 2, flexShrink: 0, children: /* @__PURE__ */ jsx17(Text15, { color: isSelected ? theme17.accentActive : theme17.textSubtle, children: isSelected ? "\u203A" : " " }) }),
9617
+ /* @__PURE__ */ jsx17(Box14, { width: 9, flexShrink: 0, children: /* @__PURE__ */ jsx17(Text15, { color: theme17.textMuted, children: row.time }) }),
9618
+ /* @__PURE__ */ jsx17(Box14, { width: 28, flexShrink: 0, children: /* @__PURE__ */ jsx17(Text15, { color: isSelected ? theme17.accentActive : row.color, bold: isSelected, children: row.type }) }),
9619
+ /* @__PURE__ */ jsx17(Box14, { flexShrink: 1, children: /* @__PURE__ */ jsx17(Text15, { color: theme17.textMuted, wrap: "truncate", children: row.data }) })
9503
9620
  ] }, row.key);
9504
9621
  }) }),
9505
- /* @__PURE__ */ jsx16(
9622
+ /* @__PURE__ */ jsx17(
9506
9623
  Scrollbar,
9507
9624
  {
9508
9625
  totalLines: events.length,
@@ -9520,12 +9637,12 @@ function EventStreamPanel({
9520
9637
  // src/ink/marathon/FilesPanel.tsx
9521
9638
  import { useMemo as useMemo5 } from "react";
9522
9639
  import { Box as Box15, Text as Text16 } from "ink";
9523
- import { theme as theme17, renderMarkdownToTerminal } from "@runtypelabs/ink-components";
9524
- import { jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
9640
+ import { theme as theme18, renderMarkdownToTerminal } from "@runtypelabs/ink-components";
9641
+ import { jsx as jsx18, jsxs as jsxs13 } from "react/jsx-runtime";
9525
9642
  var TYPE_COLORS = {
9526
- plan: theme17.accent,
9527
- written: theme17.success,
9528
- read: theme17.textMuted
9643
+ plan: theme18.accent,
9644
+ written: theme18.success,
9645
+ read: theme18.textMuted
9529
9646
  };
9530
9647
  var TYPE_LABELS = {
9531
9648
  plan: "plan",
@@ -9597,7 +9714,7 @@ function FileContentView({
9597
9714
  scrollOffset = 0,
9598
9715
  width = 120
9599
9716
  }) {
9600
- const separator = theme17.separator ?? " \xB7 ";
9717
+ const separator = theme18.separator ?? " \xB7 ";
9601
9718
  const contentWidth = Math.max(20, width - 4);
9602
9719
  const isMd = isMarkdownFile(file.path);
9603
9720
  const { lines, displayTotalLines, clampedOffset } = useMemo5(() => {
@@ -9615,32 +9732,32 @@ function FileContentView({
9615
9732
  Box15,
9616
9733
  {
9617
9734
  flexDirection: "column",
9618
- paddingX: theme17.panelPaddingX,
9619
- paddingY: theme17.panelPaddingY,
9735
+ paddingX: theme18.panelPaddingX,
9736
+ paddingY: theme18.panelPaddingY,
9620
9737
  children: [
9621
- /* @__PURE__ */ jsxs13(Box15, { marginBottom: theme17.sectionGap, children: [
9622
- /* @__PURE__ */ jsx17(Text16, { bold: true, color: theme17.accent, children: filename }),
9623
- /* @__PURE__ */ jsxs13(Text16, { color: theme17.textSubtle, children: [
9738
+ /* @__PURE__ */ jsxs13(Box15, { marginBottom: theme18.sectionGap, children: [
9739
+ /* @__PURE__ */ jsx18(Text16, { bold: true, color: theme18.accent, children: filename }),
9740
+ /* @__PURE__ */ jsxs13(Text16, { color: theme18.textSubtle, children: [
9624
9741
  separator,
9625
9742
  totalLines,
9626
9743
  " lines"
9627
9744
  ] }),
9628
- truncated && /* @__PURE__ */ jsxs13(Text16, { color: theme17.warning, children: [
9745
+ truncated && /* @__PURE__ */ jsxs13(Text16, { color: theme18.warning, children: [
9629
9746
  separator,
9630
9747
  "truncated"
9631
9748
  ] }),
9632
- /* @__PURE__ */ jsxs13(Text16, { color: theme17.textSubtle, children: [
9749
+ /* @__PURE__ */ jsxs13(Text16, { color: theme18.textSubtle, children: [
9633
9750
  separator,
9634
9751
  "c: copy"
9635
9752
  ] }),
9636
- /* @__PURE__ */ jsxs13(Text16, { color: theme17.textSubtle, children: [
9753
+ /* @__PURE__ */ jsxs13(Text16, { color: theme18.textSubtle, children: [
9637
9754
  separator,
9638
9755
  "Esc: back"
9639
9756
  ] })
9640
9757
  ] }),
9641
9758
  /* @__PURE__ */ jsxs13(Box15, { flexDirection: "row", flexGrow: 1, children: [
9642
- /* @__PURE__ */ jsx17(Box15, { flexDirection: "column", flexGrow: 1, children: lines.map((line, i) => /* @__PURE__ */ jsx17(Text16, { color: theme17.text, wrap: "truncate", children: line }, i)) }),
9643
- /* @__PURE__ */ jsx17(
9759
+ /* @__PURE__ */ jsx18(Box15, { flexDirection: "column", flexGrow: 1, children: lines.map((line, i) => /* @__PURE__ */ jsx18(Text16, { color: theme18.text, wrap: "truncate", children: line }, i)) }),
9760
+ /* @__PURE__ */ jsx18(
9644
9761
  Scrollbar,
9645
9762
  {
9646
9763
  totalLines: displayTotalLines,
@@ -9665,9 +9782,9 @@ function FilesPanel({
9665
9782
  detailScrollOffset = 0,
9666
9783
  width = 120
9667
9784
  }) {
9668
- const separator = theme17.separator ?? " \xB7 ";
9785
+ const separator = theme18.separator ?? " \xB7 ";
9669
9786
  if (detailFile && detailContent !== null) {
9670
- return /* @__PURE__ */ jsx17(
9787
+ return /* @__PURE__ */ jsx18(
9671
9788
  FileContentView,
9672
9789
  {
9673
9790
  file: detailFile,
@@ -9705,13 +9822,13 @@ function FilesPanel({
9705
9822
  };
9706
9823
  }, [files, maxVisibleLines, selectedIndex]);
9707
9824
  if (files.length === 0) {
9708
- return /* @__PURE__ */ jsx17(
9825
+ return /* @__PURE__ */ jsx18(
9709
9826
  Box15,
9710
9827
  {
9711
9828
  flexDirection: "column",
9712
- paddingX: theme17.panelPaddingX,
9713
- paddingY: theme17.panelPaddingY,
9714
- children: /* @__PURE__ */ jsx17(Text16, { color: theme17.textSubtle, children: "No files tracked yet..." })
9829
+ paddingX: theme18.panelPaddingX,
9830
+ paddingY: theme18.panelPaddingY,
9831
+ children: /* @__PURE__ */ jsx18(Text16, { color: theme18.textSubtle, children: "No files tracked yet..." })
9715
9832
  }
9716
9833
  );
9717
9834
  }
@@ -9719,33 +9836,33 @@ function FilesPanel({
9719
9836
  Box15,
9720
9837
  {
9721
9838
  flexDirection: "column",
9722
- paddingX: theme17.panelPaddingX,
9723
- paddingY: theme17.panelPaddingY,
9839
+ paddingX: theme18.panelPaddingX,
9840
+ paddingY: theme18.panelPaddingY,
9724
9841
  children: [
9725
9842
  /* @__PURE__ */ jsxs13(Box15, { marginBottom: 0, children: [
9726
- /* @__PURE__ */ jsx17(Text16, { bold: true, color: theme17.accent, children: "Files" }),
9727
- /* @__PURE__ */ jsxs13(Text16, { color: theme17.textSubtle, children: [
9843
+ /* @__PURE__ */ jsx18(Text16, { bold: true, color: theme18.accent, children: "Files" }),
9844
+ /* @__PURE__ */ jsxs13(Text16, { color: theme18.textSubtle, children: [
9728
9845
  separator,
9729
9846
  files.length,
9730
9847
  " files"
9731
9848
  ] })
9732
9849
  ] }),
9733
9850
  /* @__PURE__ */ jsxs13(Box15, { flexDirection: "row", children: [
9734
- /* @__PURE__ */ jsx17(Box15, { flexDirection: "column", flexGrow: 1, children: rows.map((row) => {
9851
+ /* @__PURE__ */ jsx18(Box15, { flexDirection: "column", flexGrow: 1, children: rows.map((row) => {
9735
9852
  const isSelected = row.globalIndex === selectedIndex;
9736
- const typeColor = TYPE_COLORS[row.file.type] || theme17.text;
9853
+ const typeColor = TYPE_COLORS[row.file.type] || theme18.text;
9737
9854
  const typeLabel = TYPE_LABELS[row.file.type] || row.file.type;
9738
9855
  return /* @__PURE__ */ jsxs13(Box15, { flexDirection: "row", flexWrap: "nowrap", children: [
9739
- /* @__PURE__ */ jsx17(Box15, { width: 2, flexShrink: 0, children: /* @__PURE__ */ jsx17(Text16, { color: isSelected ? theme17.accentActive : theme17.textSubtle, children: isSelected ? "\u203A" : " " }) }),
9740
- /* @__PURE__ */ jsx17(Box15, { width: 8, flexShrink: 0, children: /* @__PURE__ */ jsxs13(Text16, { color: typeColor, children: [
9856
+ /* @__PURE__ */ jsx18(Box15, { width: 2, flexShrink: 0, children: /* @__PURE__ */ jsx18(Text16, { color: isSelected ? theme18.accentActive : theme18.textSubtle, children: isSelected ? "\u203A" : " " }) }),
9857
+ /* @__PURE__ */ jsx18(Box15, { width: 8, flexShrink: 0, children: /* @__PURE__ */ jsxs13(Text16, { color: typeColor, children: [
9741
9858
  "[",
9742
9859
  typeLabel,
9743
9860
  "]"
9744
9861
  ] }) }),
9745
- /* @__PURE__ */ jsx17(Box15, { flexShrink: 1, children: /* @__PURE__ */ jsx17(
9862
+ /* @__PURE__ */ jsx18(Box15, { flexShrink: 1, children: /* @__PURE__ */ jsx18(
9746
9863
  Text16,
9747
9864
  {
9748
- color: isSelected ? theme17.accentActive : theme17.text,
9865
+ color: isSelected ? theme18.accentActive : theme18.text,
9749
9866
  bold: isSelected,
9750
9867
  wrap: "truncate",
9751
9868
  children: shortenPath(row.file.path, 80)
@@ -9753,7 +9870,7 @@ function FilesPanel({
9753
9870
  ) })
9754
9871
  ] }, row.key);
9755
9872
  }) }),
9756
- /* @__PURE__ */ jsx17(
9873
+ /* @__PURE__ */ jsx18(
9757
9874
  Scrollbar,
9758
9875
  {
9759
9876
  totalLines: files.length,
@@ -9771,8 +9888,8 @@ function FilesPanel({
9771
9888
  // src/ink/marathon/HelpPanel.tsx
9772
9889
  import { useMemo as useMemo6 } from "react";
9773
9890
  import { Box as Box16, Text as Text17 } from "ink";
9774
- import { theme as theme18 } from "@runtypelabs/ink-components";
9775
- import { Fragment as Fragment2, jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
9891
+ import { theme as theme19 } from "@runtypelabs/ink-components";
9892
+ import { Fragment as Fragment2, jsx as jsx19, jsxs as jsxs14 } from "react/jsx-runtime";
9776
9893
  var NAVIGATION_SHORTCUTS = [
9777
9894
  { key: "Tab", desc: "Next screen" },
9778
9895
  { key: "Esc", desc: "Back / close detail / close help" },
@@ -9850,26 +9967,26 @@ function HelpPanel({ width, height, isSteering, scrollOffset }) {
9850
9967
  height: Math.min(height - 2, isSteering ? 38 : 28),
9851
9968
  flexDirection: "column",
9852
9969
  borderStyle: "round",
9853
- borderColor: theme18.accent,
9854
- backgroundColor: theme18.surfaceElevated,
9970
+ borderColor: theme19.accent,
9971
+ backgroundColor: theme19.surfaceElevated,
9855
9972
  paddingX: 2,
9856
9973
  paddingY: 1,
9857
9974
  children: [
9858
- /* @__PURE__ */ jsx18(Text17, { bold: true, color: theme18.accent, children: "Keyboard Shortcuts" }),
9975
+ /* @__PURE__ */ jsx19(Text17, { bold: true, color: theme19.accent, children: "Keyboard Shortcuts" }),
9859
9976
  /* @__PURE__ */ jsxs14(Box16, { flexDirection: "row", flexGrow: 1, marginTop: 1, children: [
9860
- /* @__PURE__ */ jsx18(Box16, { flexDirection: "column", flexGrow: 1, children: visibleLines.map((line, idx) => {
9977
+ /* @__PURE__ */ jsx19(Box16, { flexDirection: "column", flexGrow: 1, children: visibleLines.map((line, idx) => {
9861
9978
  if (line.type === "header") {
9862
- return /* @__PURE__ */ jsx18(Text17, { bold: true, color: theme18.accentActive, children: line.title }, idx);
9979
+ return /* @__PURE__ */ jsx19(Text17, { bold: true, color: theme19.accentActive, children: line.title }, idx);
9863
9980
  }
9864
9981
  if (line.type === "item") {
9865
9982
  return /* @__PURE__ */ jsxs14(Text17, { children: [
9866
- /* @__PURE__ */ jsx18(Text17, { color: theme18.textSubtle, children: ` ${line.key.padEnd(16)}` }),
9867
- /* @__PURE__ */ jsx18(Text17, { color: theme18.textMuted, children: line.desc })
9983
+ /* @__PURE__ */ jsx19(Text17, { color: theme19.textSubtle, children: ` ${line.key.padEnd(16)}` }),
9984
+ /* @__PURE__ */ jsx19(Text17, { color: theme19.textMuted, children: line.desc })
9868
9985
  ] }, idx);
9869
9986
  }
9870
- return /* @__PURE__ */ jsx18(Text17, { children: " " }, idx);
9987
+ return /* @__PURE__ */ jsx19(Text17, { children: " " }, idx);
9871
9988
  }) }),
9872
- /* @__PURE__ */ jsx18(
9989
+ /* @__PURE__ */ jsx19(
9873
9990
  Scrollbar,
9874
9991
  {
9875
9992
  totalLines: allLines.length,
@@ -9880,14 +9997,14 @@ function HelpPanel({ width, height, isSteering, scrollOffset }) {
9880
9997
  )
9881
9998
  ] }),
9882
9999
  /* @__PURE__ */ jsxs14(Box16, { marginTop: 1, children: [
9883
- /* @__PURE__ */ jsx18(Text17, { color: theme18.info, children: "Esc" }),
9884
- /* @__PURE__ */ jsx18(Text17, { color: theme18.muted, children: " or " }),
9885
- /* @__PURE__ */ jsx18(Text17, { color: theme18.info, children: "?" }),
9886
- /* @__PURE__ */ jsx18(Text17, { color: theme18.muted, children: " to close" }),
10000
+ /* @__PURE__ */ jsx19(Text17, { color: theme19.info, children: "Esc" }),
10001
+ /* @__PURE__ */ jsx19(Text17, { color: theme19.muted, children: " or " }),
10002
+ /* @__PURE__ */ jsx19(Text17, { color: theme19.info, children: "?" }),
10003
+ /* @__PURE__ */ jsx19(Text17, { color: theme19.muted, children: " to close" }),
9887
10004
  isSteering && /* @__PURE__ */ jsxs14(Fragment2, { children: [
9888
- /* @__PURE__ */ jsx18(Text17, { color: theme18.muted, children: " (use " }),
9889
- /* @__PURE__ */ jsx18(Text17, { color: theme18.info, children: "/help" }),
9890
- /* @__PURE__ */ jsx18(Text17, { color: theme18.muted, children: " during steering)" })
10005
+ /* @__PURE__ */ jsx19(Text17, { color: theme19.muted, children: " (use " }),
10006
+ /* @__PURE__ */ jsx19(Text17, { color: theme19.info, children: "/help" }),
10007
+ /* @__PURE__ */ jsx19(Text17, { color: theme19.muted, children: " during steering)" })
9891
10008
  ] })
9892
10009
  ] })
9893
10010
  ]
@@ -9951,14 +10068,14 @@ function readFileContent(filePath, maxLines = 5e3) {
9951
10068
  }
9952
10069
 
9953
10070
  // src/ink/marathon/SteeringPrompt.tsx
9954
- import { useState as useState19, useEffect as useEffect17, useRef as useRef7 } from "react";
10071
+ import { useState as useState20, useEffect as useEffect19, useRef as useRef7 } from "react";
9955
10072
  import { Box as Box21, Text as Text23 } from "ink";
9956
10073
 
9957
10074
  // src/ink/marathon/BlinkingTextInput.tsx
9958
- import { useState as useState15, useEffect as useEffect15, useRef as useRef5 } from "react";
10075
+ import { useState as useState16, useEffect as useEffect16, useRef as useRef5 } from "react";
9959
10076
  import { Text as Text18, useInput as useInput5 } from "ink";
9960
10077
  import chalk11 from "chalk";
9961
- import { jsx as jsx19 } from "react/jsx-runtime";
10078
+ import { jsx as jsx20 } from "react/jsx-runtime";
9962
10079
  var CURSOR_BLINK_MS = 800;
9963
10080
  function BlinkingTextInput({
9964
10081
  value: originalValue,
@@ -9971,14 +10088,14 @@ function BlinkingTextInput({
9971
10088
  onChange,
9972
10089
  onSubmit
9973
10090
  }) {
9974
- const [state, setState] = useState15({
10091
+ const [state, setState] = useState16({
9975
10092
  cursorOffset: (originalValue || "").length,
9976
10093
  cursorWidth: 0
9977
10094
  });
9978
- const [blinkVisible, setBlinkVisible] = useState15(true);
10095
+ const [blinkVisible, setBlinkVisible] = useState16(true);
9979
10096
  const blinkRef = useRef5(null);
9980
10097
  const { cursorOffset, cursorWidth } = state;
9981
- useEffect15(() => {
10098
+ useEffect16(() => {
9982
10099
  if (!focus || !showCursor || !blinkCursor) {
9983
10100
  setBlinkVisible(true);
9984
10101
  return;
@@ -9993,10 +10110,10 @@ function BlinkingTextInput({
9993
10110
  }
9994
10111
  };
9995
10112
  }, [focus, showCursor, blinkCursor]);
9996
- useEffect15(() => {
10113
+ useEffect16(() => {
9997
10114
  setBlinkVisible(true);
9998
10115
  }, [originalValue, cursorOffset]);
9999
- useEffect15(() => {
10116
+ useEffect16(() => {
10000
10117
  setState((previousState) => {
10001
10118
  if (!focus || !showCursor) {
10002
10119
  return previousState;
@@ -10082,20 +10199,20 @@ function BlinkingTextInput({
10082
10199
  },
10083
10200
  { isActive: focus }
10084
10201
  );
10085
- return /* @__PURE__ */ jsx19(Text18, { children: placeholder ? value.length > 0 ? renderedValue : renderedPlaceholder : renderedValue });
10202
+ return /* @__PURE__ */ jsx20(Text18, { children: placeholder ? value.length > 0 ? renderedValue : renderedPlaceholder : renderedValue });
10086
10203
  }
10087
10204
 
10088
10205
  // src/ink/marathon/SteeringPrompt.tsx
10089
- import { theme as theme23 } from "@runtypelabs/ink-components";
10206
+ import { theme as theme24 } from "@runtypelabs/ink-components";
10090
10207
 
10091
10208
  // src/ink/talk/ModelPicker.tsx
10092
- import { useState as useState16, useMemo as useMemo7, useCallback as useCallback4 } from "react";
10209
+ import { useState as useState17, useMemo as useMemo7, useCallback as useCallback4, useEffect as useEffect17 } from "react";
10093
10210
  import { Box as Box17, Text as Text19, useInput as useInput6, useStdout } from "ink";
10094
10211
  import TextInput2 from "ink-text-input";
10095
10212
  import open3 from "open";
10096
- import { theme as theme19 } from "@runtypelabs/ink-components";
10097
- import { jsx as jsx20, jsxs as jsxs15 } from "react/jsx-runtime";
10098
- var ALL_MODELS = [
10213
+ import { theme as theme20 } from "@runtypelabs/ink-components";
10214
+ import { jsx as jsx21, jsxs as jsxs15 } from "react/jsx-runtime";
10215
+ var DEFAULT_MODELS = [
10099
10216
  // Anthropic
10100
10217
  { label: "Claude Opus 4.6", value: "claude-opus-4-6", group: "Anthropic" },
10101
10218
  { label: "Claude Sonnet 4.6", value: "claude-sonnet-4-6", group: "Anthropic" },
@@ -10126,27 +10243,39 @@ var ALL_MODELS = [
10126
10243
  { label: "Qwen 3 8B", value: "qwen/qwen3-8b", group: "Qwen" }
10127
10244
  ];
10128
10245
  var MAX_VISIBLE = 12;
10129
- function ModelPicker({ currentModel, onSelect, onCancel }) {
10246
+ function ModelPicker({ currentModel, onSelect, onCancel, models }) {
10130
10247
  const { stdout } = useStdout();
10131
- const [search, setSearch] = useState16("");
10132
- const [selectedIndex, setSelectedIndex] = useState16(0);
10248
+ const [search, setSearch] = useState17("");
10249
+ const availableModels = models && models.length > 0 ? models : DEFAULT_MODELS;
10133
10250
  const contentWidth = (stdout?.columns ?? 120) - 4;
10134
10251
  const pad = useCallback4(
10135
10252
  (text) => text.length < contentWidth ? text + " ".repeat(contentWidth - text.length) : text,
10136
10253
  [contentWidth]
10137
10254
  );
10138
10255
  const filtered = useMemo7(() => {
10139
- if (!search.trim()) return ALL_MODELS;
10256
+ if (!search.trim()) return availableModels;
10140
10257
  const q = search.toLowerCase();
10141
- return ALL_MODELS.filter(
10258
+ return availableModels.filter(
10142
10259
  (m) => m.label.toLowerCase().includes(q) || m.value.toLowerCase().includes(q) || m.group.toLowerCase().includes(q)
10143
10260
  );
10144
- }, [search]);
10261
+ }, [availableModels, search]);
10262
+ const [selectedIndex, setSelectedIndex] = useState17(() => {
10263
+ const currentIndex = availableModels.findIndex((model) => model.value === currentModel);
10264
+ return currentIndex >= 0 ? currentIndex : 0;
10265
+ });
10145
10266
  const handleSearchChange = (value) => {
10146
10267
  if (value === search) return;
10147
10268
  setSearch(value);
10148
10269
  setSelectedIndex(0);
10149
10270
  };
10271
+ useEffect17(() => {
10272
+ if (!search.trim()) {
10273
+ const currentIndex = filtered.findIndex((model) => model.value === currentModel);
10274
+ setSelectedIndex(currentIndex >= 0 ? currentIndex : 0);
10275
+ return;
10276
+ }
10277
+ setSelectedIndex((prev) => Math.min(prev, Math.max(0, filtered.length - 1)));
10278
+ }, [currentModel, filtered, search]);
10150
10279
  useInput6((_input, key) => {
10151
10280
  if (key.escape) {
10152
10281
  onCancel();
@@ -10201,23 +10330,23 @@ function ModelPicker({ currentModel, onSelect, onCancel }) {
10201
10330
  Box17,
10202
10331
  {
10203
10332
  borderStyle: "single",
10204
- borderColor: theme19.border,
10205
- backgroundColor: theme19.surfaceElevated,
10206
- paddingX: theme19.panelPaddingX,
10207
- paddingY: theme19.panelPaddingY,
10333
+ borderColor: theme20.border,
10334
+ backgroundColor: theme20.surfaceElevated,
10335
+ paddingX: theme20.panelPaddingX,
10336
+ paddingY: theme20.panelPaddingY,
10208
10337
  flexDirection: "column",
10209
10338
  children: [
10210
10339
  /* @__PURE__ */ jsxs15(Box17, { marginBottom: 1, children: [
10211
- /* @__PURE__ */ jsx20(Text19, { color: theme19.accent, bold: true, children: "Select Model" }),
10212
- /* @__PURE__ */ jsxs15(Text19, { color: theme19.textSubtle, children: [
10340
+ /* @__PURE__ */ jsx21(Text19, { color: theme20.accent, bold: true, children: "Select Model" }),
10341
+ /* @__PURE__ */ jsxs15(Text19, { color: theme20.textSubtle, children: [
10213
10342
  " ",
10214
10343
  filtered.length,
10215
10344
  " models"
10216
10345
  ] })
10217
10346
  ] }),
10218
10347
  /* @__PURE__ */ jsxs15(Box17, { marginBottom: 1, children: [
10219
- /* @__PURE__ */ jsx20(Text19, { color: theme19.textSubtle, children: "/ " }),
10220
- /* @__PURE__ */ jsx20(
10348
+ /* @__PURE__ */ jsx21(Text19, { color: theme20.textSubtle, children: "/ " }),
10349
+ /* @__PURE__ */ jsx21(
10221
10350
  TextInput2,
10222
10351
  {
10223
10352
  value: search,
@@ -10226,35 +10355,35 @@ function ModelPicker({ currentModel, onSelect, onCancel }) {
10226
10355
  }
10227
10356
  )
10228
10357
  ] }),
10229
- /* @__PURE__ */ jsx20(Box17, { height: 1, children: /* @__PURE__ */ jsx20(Text19, { color: theme19.textSubtle, children: pad(showScrollUp ? " ..." : "") }) }),
10230
- /* @__PURE__ */ jsx20(Box17, { flexDirection: "column", height: MAX_VISIBLE, children: filtered.length === 0 ? /* @__PURE__ */ jsx20(Text19, { color: theme19.textSubtle, children: " No matching models" }) : rows.map((row) => {
10358
+ /* @__PURE__ */ jsx21(Box17, { height: 1, children: /* @__PURE__ */ jsx21(Text19, { color: theme20.textSubtle, children: pad(showScrollUp ? " ..." : "") }) }),
10359
+ /* @__PURE__ */ jsx21(Box17, { flexDirection: "column", height: MAX_VISIBLE, children: filtered.length === 0 ? /* @__PURE__ */ jsx21(Text19, { color: theme20.textSubtle, children: " No matching models" }) : rows.map((row) => {
10231
10360
  if (row.type === "group") {
10232
- return /* @__PURE__ */ jsx20(Box17, { children: /* @__PURE__ */ jsx20(Text19, { color: theme19.textSubtle, dimColor: true, children: pad(` ${row.label}`) }) }, `group-${row.label}`);
10361
+ return /* @__PURE__ */ jsx21(Box17, { children: /* @__PURE__ */ jsx21(Text19, { color: theme20.textSubtle, dimColor: true, children: pad(` ${row.label}`) }) }, `group-${row.label}`);
10233
10362
  }
10234
10363
  const { model, isHighlighted, isCurrent } = row;
10235
10364
  const indicator = isHighlighted ? "\u203A " : " ";
10236
10365
  const suffix = isCurrent ? " *" : "";
10237
- return /* @__PURE__ */ jsx20(Box17, { children: /* @__PURE__ */ jsx20(
10366
+ return /* @__PURE__ */ jsx21(Box17, { children: /* @__PURE__ */ jsx21(
10238
10367
  Text19,
10239
10368
  {
10240
- color: isHighlighted ? theme19.accentActive : isCurrent ? theme19.accent : theme19.textMuted,
10369
+ color: isHighlighted ? theme20.accentActive : isCurrent ? theme20.accent : theme20.textMuted,
10241
10370
  bold: isHighlighted,
10242
10371
  children: pad(`${indicator}${model.label}${suffix}`)
10243
10372
  }
10244
10373
  ) }, model.value);
10245
10374
  }) }),
10246
- /* @__PURE__ */ jsx20(Box17, { height: 1, children: /* @__PURE__ */ jsx20(Text19, { color: theme19.textSubtle, children: pad(showScrollDown ? " ..." : "") }) }),
10247
- /* @__PURE__ */ jsx20(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx20(Text19, { color: theme19.textSubtle, children: ["\u2191\u2193 navigate", "Enter select", "Tab manage models", "Esc cancel"].join(theme19.separator ?? " \xB7 ") }) })
10375
+ /* @__PURE__ */ jsx21(Box17, { height: 1, children: /* @__PURE__ */ jsx21(Text19, { color: theme20.textSubtle, children: pad(showScrollDown ? " ..." : "") }) }),
10376
+ /* @__PURE__ */ jsx21(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx21(Text19, { color: theme20.textSubtle, children: ["\u2191\u2193 navigate", "Enter select", "Tab manage models", "Esc cancel"].join(theme20.separator ?? " \xB7 ") }) })
10248
10377
  ]
10249
10378
  }
10250
10379
  );
10251
10380
  }
10252
10381
 
10253
10382
  // src/ink/marathon/CommandPicker.tsx
10254
- import { useState as useState17, useMemo as useMemo8, useCallback as useCallback5 } from "react";
10383
+ import { useState as useState18, useMemo as useMemo8, useCallback as useCallback5 } from "react";
10255
10384
  import { Box as Box18, Text as Text20, useInput as useInput7, useStdout as useStdout2 } from "ink";
10256
10385
  import TextInput3 from "ink-text-input";
10257
- import { theme as theme20 } from "@runtypelabs/ink-components";
10386
+ import { theme as theme21 } from "@runtypelabs/ink-components";
10258
10387
 
10259
10388
  // src/ink/marathon/types.ts
10260
10389
  var MARATHON_STEER_COMMANDS = [
@@ -10280,11 +10409,11 @@ var MARATHON_STEER_COMMANDS = [
10280
10409
  ];
10281
10410
 
10282
10411
  // src/ink/marathon/CommandPicker.tsx
10283
- import { jsx as jsx21, jsxs as jsxs16 } from "react/jsx-runtime";
10412
+ import { jsx as jsx22, jsxs as jsxs16 } from "react/jsx-runtime";
10284
10413
  function CommandPicker({ onSelect, onCancel, initialFilter = "" }) {
10285
10414
  const { stdout } = useStdout2();
10286
- const [search, setSearch] = useState17(initialFilter);
10287
- const [selectedIndex, setSelectedIndex] = useState17(0);
10415
+ const [search, setSearch] = useState18(initialFilter);
10416
+ const [selectedIndex, setSelectedIndex] = useState18(0);
10288
10417
  const contentWidth = (stdout?.columns ?? 120) - 4;
10289
10418
  const pad = useCallback5(
10290
10419
  (text) => text.length < contentWidth ? text + " ".repeat(contentWidth - text.length) : text,
@@ -10326,23 +10455,23 @@ function CommandPicker({ onSelect, onCancel, initialFilter = "" }) {
10326
10455
  Box18,
10327
10456
  {
10328
10457
  borderStyle: "single",
10329
- borderColor: theme20.border,
10330
- backgroundColor: theme20.surfaceElevated,
10331
- paddingX: theme20.panelPaddingX,
10332
- paddingY: theme20.panelPaddingY,
10458
+ borderColor: theme21.border,
10459
+ backgroundColor: theme21.surfaceElevated,
10460
+ paddingX: theme21.panelPaddingX,
10461
+ paddingY: theme21.panelPaddingY,
10333
10462
  flexDirection: "column",
10334
10463
  children: [
10335
10464
  /* @__PURE__ */ jsxs16(Box18, { marginBottom: 1, children: [
10336
- /* @__PURE__ */ jsx21(Text20, { color: theme20.accent, bold: true, children: "Commands" }),
10337
- /* @__PURE__ */ jsxs16(Text20, { color: theme20.textSubtle, children: [
10465
+ /* @__PURE__ */ jsx22(Text20, { color: theme21.accent, bold: true, children: "Commands" }),
10466
+ /* @__PURE__ */ jsxs16(Text20, { color: theme21.textSubtle, children: [
10338
10467
  " ",
10339
10468
  filtered.length,
10340
10469
  " available"
10341
10470
  ] })
10342
10471
  ] }),
10343
10472
  /* @__PURE__ */ jsxs16(Box18, { marginBottom: 1, children: [
10344
- /* @__PURE__ */ jsx21(Text20, { color: theme20.textSubtle, children: "/ " }),
10345
- /* @__PURE__ */ jsx21(
10473
+ /* @__PURE__ */ jsx22(Text20, { color: theme21.textSubtle, children: "/ " }),
10474
+ /* @__PURE__ */ jsx22(
10346
10475
  TextInput3,
10347
10476
  {
10348
10477
  value: search,
@@ -10351,29 +10480,29 @@ function CommandPicker({ onSelect, onCancel, initialFilter = "" }) {
10351
10480
  }
10352
10481
  )
10353
10482
  ] }),
10354
- /* @__PURE__ */ jsx21(Box18, { flexDirection: "column", children: filtered.length === 0 ? /* @__PURE__ */ jsx21(Text20, { color: theme20.textSubtle, children: pad(" No matching commands") }) : filtered.map((cmd, index) => {
10483
+ /* @__PURE__ */ jsx22(Box18, { flexDirection: "column", children: filtered.length === 0 ? /* @__PURE__ */ jsx22(Text20, { color: theme21.textSubtle, children: pad(" No matching commands") }) : filtered.map((cmd, index) => {
10355
10484
  const isHighlighted = index === selectedIndex;
10356
10485
  const indicator = isHighlighted ? "\u203A " : " ";
10357
10486
  const nameCol = cmd.name.padEnd(14);
10358
- return /* @__PURE__ */ jsx21(Box18, { children: /* @__PURE__ */ jsx21(
10487
+ return /* @__PURE__ */ jsx22(Box18, { children: /* @__PURE__ */ jsx22(
10359
10488
  Text20,
10360
10489
  {
10361
- color: isHighlighted ? theme20.accentActive : theme20.textMuted,
10490
+ color: isHighlighted ? theme21.accentActive : theme21.textMuted,
10362
10491
  bold: isHighlighted,
10363
10492
  children: pad(`${indicator}${nameCol}${cmd.description}`)
10364
10493
  }
10365
10494
  ) }, cmd.name);
10366
10495
  }) }),
10367
- /* @__PURE__ */ jsx21(Box18, { marginTop: 1, children: /* @__PURE__ */ jsx21(Text20, { color: theme20.textSubtle, children: ["\u2191\u2193 navigate", "Enter select", "Esc cancel"].join(theme20.separator ?? " \xB7 ") }) })
10496
+ /* @__PURE__ */ jsx22(Box18, { marginTop: 1, children: /* @__PURE__ */ jsx22(Text20, { color: theme21.textSubtle, children: ["\u2191\u2193 navigate", "Enter select", "Esc cancel"].join(theme21.separator ?? " \xB7 ") }) })
10368
10497
  ]
10369
10498
  }
10370
10499
  );
10371
10500
  }
10372
10501
 
10373
10502
  // src/ink/marathon/TextArea.tsx
10374
- import { useState as useState18, useCallback as useCallback6, useRef as useRef6, useEffect as useEffect16, useMemo as useMemo9 } from "react";
10503
+ import { useState as useState19, useCallback as useCallback6, useRef as useRef6, useEffect as useEffect18, useMemo as useMemo9 } from "react";
10375
10504
  import { Box as Box19, Text as Text21, useInput as useInput8, useStdout as useStdout3 } from "ink";
10376
- import { theme as theme21 } from "@runtypelabs/ink-components";
10505
+ import { theme as theme22 } from "@runtypelabs/ink-components";
10377
10506
 
10378
10507
  // src/ink/marathon/text-area-editing.ts
10379
10508
  function ensureLines(lines) {
@@ -10437,7 +10566,7 @@ function deleteToLineStart(lines, cursor) {
10437
10566
  }
10438
10567
 
10439
10568
  // src/ink/marathon/TextArea.tsx
10440
- import { jsx as jsx22, jsxs as jsxs17 } from "react/jsx-runtime";
10569
+ import { jsx as jsx23, jsxs as jsxs17 } from "react/jsx-runtime";
10441
10570
  function splitLines(text) {
10442
10571
  const lines = text.split("\n");
10443
10572
  return lines.length === 0 ? [""] : lines;
@@ -10455,20 +10584,20 @@ function TextArea({
10455
10584
  const { stdout } = useStdout3();
10456
10585
  const terminalWidth = stdout?.columns ?? 120;
10457
10586
  const contentWidth = Math.max(20, terminalWidth - 6);
10458
- const separator = theme21.separator ?? " \xB7 ";
10459
- const [lines, setLines] = useState18(() => splitLines(defaultValue));
10460
- const [cursor, setCursor] = useState18(() => {
10587
+ const separator = theme22.separator ?? " \xB7 ";
10588
+ const [lines, setLines] = useState19(() => splitLines(defaultValue));
10589
+ const [cursor, setCursor] = useState19(() => {
10461
10590
  const l = splitLines(defaultValue);
10462
10591
  return { line: l.length - 1, col: l[l.length - 1].length };
10463
10592
  });
10464
- const [scrollOffset, setScrollOffset] = useState18(0);
10465
- const [blinkVisible, setBlinkVisible] = useState18(true);
10593
+ const [scrollOffset, setScrollOffset] = useState19(0);
10594
+ const [blinkVisible, setBlinkVisible] = useState19(true);
10466
10595
  const blinkRef = useRef6(null);
10467
10596
  const linesRef = useRef6(lines);
10468
10597
  linesRef.current = lines;
10469
10598
  const cursorRef = useRef6(cursor);
10470
10599
  cursorRef.current = cursor;
10471
- useEffect16(() => {
10600
+ useEffect18(() => {
10472
10601
  blinkRef.current = setInterval(() => {
10473
10602
  setBlinkVisible((v) => !v);
10474
10603
  }, CURSOR_BLINK_MS);
@@ -10479,10 +10608,10 @@ function TextArea({
10479
10608
  }
10480
10609
  };
10481
10610
  }, []);
10482
- useEffect16(() => {
10611
+ useEffect18(() => {
10483
10612
  setBlinkVisible(true);
10484
10613
  }, [lines, cursor]);
10485
- useEffect16(() => {
10614
+ useEffect18(() => {
10486
10615
  const visibleStart = scrollOffset;
10487
10616
  const visibleEnd = scrollOffset + maxHeight - 1;
10488
10617
  if (cursor.line < visibleStart) {
@@ -10629,23 +10758,23 @@ function TextArea({
10629
10758
  Box19,
10630
10759
  {
10631
10760
  borderStyle: "single",
10632
- borderColor: theme21.borderActive,
10633
- backgroundColor: theme21.surface,
10761
+ borderColor: theme22.borderActive,
10762
+ backgroundColor: theme22.surface,
10634
10763
  flexDirection: "column",
10635
10764
  paddingX: 1,
10636
10765
  children: [
10637
10766
  title && /* @__PURE__ */ jsxs17(Box19, { marginBottom: 1, children: [
10638
- /* @__PURE__ */ jsx22(Text21, { color: theme21.accent, bold: true, children: title }),
10639
- /* @__PURE__ */ jsxs17(Text21, { color: theme21.textSubtle, children: [
10767
+ /* @__PURE__ */ jsx23(Text21, { color: theme22.accent, bold: true, children: title }),
10768
+ /* @__PURE__ */ jsxs17(Text21, { color: theme22.textSubtle, children: [
10640
10769
  " ",
10641
10770
  lines.length,
10642
10771
  " lines"
10643
10772
  ] })
10644
10773
  ] }),
10645
10774
  /* @__PURE__ */ jsxs17(Box19, { flexDirection: "row", height: maxHeight, children: [
10646
- /* @__PURE__ */ jsx22(Box19, { flexDirection: "column", flexGrow: 1, children: visibleLines.map((vl, idx) => /* @__PURE__ */ jsxs17(Box19, { children: [
10647
- /* @__PURE__ */ jsx22(Text21, { color: theme21.textSubtle, children: vl.lineIndex >= 0 ? `${String(vl.lineIndex + 1).padStart(3)} ` : " " }),
10648
- vl.hasCursor ? /* @__PURE__ */ jsx22(
10775
+ /* @__PURE__ */ jsx23(Box19, { flexDirection: "column", flexGrow: 1, children: visibleLines.map((vl, idx) => /* @__PURE__ */ jsxs17(Box19, { children: [
10776
+ /* @__PURE__ */ jsx23(Text21, { color: theme22.textSubtle, children: vl.lineIndex >= 0 ? `${String(vl.lineIndex + 1).padStart(3)} ` : " " }),
10777
+ vl.hasCursor ? /* @__PURE__ */ jsx23(
10649
10778
  CursorLine,
10650
10779
  {
10651
10780
  content: vl.content,
@@ -10653,9 +10782,9 @@ function TextArea({
10653
10782
  maxWidth: contentWidth - 6,
10654
10783
  visible: blinkVisible
10655
10784
  }
10656
- ) : /* @__PURE__ */ jsx22(Text21, { color: theme21.text, children: vl.content.slice(0, contentWidth - 6) })
10785
+ ) : /* @__PURE__ */ jsx23(Text21, { color: theme22.text, children: vl.content.slice(0, contentWidth - 6) })
10657
10786
  ] }, idx)) }),
10658
- /* @__PURE__ */ jsx22(
10787
+ /* @__PURE__ */ jsx23(
10659
10788
  Scrollbar,
10660
10789
  {
10661
10790
  totalLines: lines.length,
@@ -10668,7 +10797,7 @@ function TextArea({
10668
10797
  ]
10669
10798
  }
10670
10799
  ),
10671
- /* @__PURE__ */ jsx22(Text21, { color: theme21.textSubtle, children: [
10800
+ /* @__PURE__ */ jsx23(Text21, { color: theme22.textSubtle, children: [
10672
10801
  "Ctrl+S: submit",
10673
10802
  "Esc: cancel",
10674
10803
  "Enter: newline",
@@ -10689,21 +10818,21 @@ function CursorLine({
10689
10818
  const cursorChar = truncated[col] ?? " ";
10690
10819
  const after = truncated.slice(col + 1);
10691
10820
  return /* @__PURE__ */ jsxs17(Text21, { children: [
10692
- /* @__PURE__ */ jsx22(Text21, { color: theme21.text, children: before }),
10693
- visible ? /* @__PURE__ */ jsx22(Text21, { color: theme21.background, backgroundColor: theme21.accentActive, children: cursorChar }) : /* @__PURE__ */ jsx22(Text21, { color: theme21.text, children: cursorChar }),
10694
- /* @__PURE__ */ jsx22(Text21, { color: theme21.text, children: after })
10821
+ /* @__PURE__ */ jsx23(Text21, { color: theme22.text, children: before }),
10822
+ visible ? /* @__PURE__ */ jsx23(Text21, { color: theme22.background, backgroundColor: theme22.accentActive, children: cursorChar }) : /* @__PURE__ */ jsx23(Text21, { color: theme22.text, children: cursorChar }),
10823
+ /* @__PURE__ */ jsx23(Text21, { color: theme22.text, children: after })
10695
10824
  ] });
10696
10825
  }
10697
10826
 
10698
10827
  // src/ink/marathon/ReflectEditor.tsx
10699
- import { jsx as jsx23 } from "react/jsx-runtime";
10828
+ import { jsx as jsx24 } from "react/jsx-runtime";
10700
10829
  var DEFAULT_REFLECT_PROMPT = `Before continuing, step back and reflect:
10701
10830
  - What has been accomplished so far?
10702
10831
  - What isn't working or is blocking progress?
10703
10832
  - What approach should be taken next and why?
10704
10833
  - Are there any assumptions that should be reconsidered?`;
10705
10834
  function ReflectEditor({ onSubmit, onCancel, maxHeight = 10 }) {
10706
- return /* @__PURE__ */ jsx23(
10835
+ return /* @__PURE__ */ jsx24(
10707
10836
  TextArea,
10708
10837
  {
10709
10838
  title: "Reflect",
@@ -10717,9 +10846,9 @@ function ReflectEditor({ onSubmit, onCancel, maxHeight = 10 }) {
10717
10846
 
10718
10847
  // src/ink/marathon/SteeringRecap.tsx
10719
10848
  import { Box as Box20, Text as Text22 } from "ink";
10720
- import { theme as theme22 } from "@runtypelabs/ink-components";
10721
- import { jsx as jsx24, jsxs as jsxs18 } from "react/jsx-runtime";
10722
- function formatTokenCount(value) {
10849
+ import { theme as theme23 } from "@runtypelabs/ink-components";
10850
+ import { jsx as jsx25, jsxs as jsxs18 } from "react/jsx-runtime";
10851
+ function formatTokenCount2(value) {
10723
10852
  return value.toLocaleString("en-US");
10724
10853
  }
10725
10854
  function SteeringRecap({
@@ -10733,26 +10862,26 @@ function SteeringRecap({
10733
10862
  isTerminal
10734
10863
  }) {
10735
10864
  const label = isTerminal ? `\u2713 Session ${sessionNumber} complete` : `Session ${sessionNumber} complete`;
10736
- const separator = theme22.separator ?? " \xB7 ";
10865
+ const separator = theme23.separator ?? " \xB7 ";
10737
10866
  const usageSummary = [
10738
10867
  `Tools: ${toolCallsMade}`,
10739
- `Tokens: ${formatTokenCount(tokensInput)} in${separator}${formatTokenCount(tokensOutput)} out`,
10740
- ...reasoningTokens && reasoningTokens > 0 ? [`Reasoning: ${formatTokenCount(reasoningTokens)}`] : [],
10868
+ `Tokens: ${formatTokenCount2(tokensInput)} in${separator}${formatTokenCount2(tokensOutput)} out`,
10869
+ ...reasoningTokens && reasoningTokens > 0 ? [`Reasoning: ${formatTokenCount2(reasoningTokens)}`] : [],
10741
10870
  `Cost: $${cost.toFixed(4)}`
10742
10871
  ].join(separator);
10743
10872
  return /* @__PURE__ */ jsxs18(
10744
10873
  Box20,
10745
10874
  {
10746
10875
  borderStyle: "single",
10747
- borderColor: theme22.border,
10748
- backgroundColor: theme22.background,
10876
+ borderColor: theme23.border,
10877
+ backgroundColor: theme23.background,
10749
10878
  flexDirection: "column",
10750
- paddingX: theme22.panelPaddingX,
10751
- paddingY: theme22.panelPaddingY,
10879
+ paddingX: theme23.panelPaddingX,
10880
+ paddingY: theme23.panelPaddingY,
10752
10881
  children: [
10753
- /* @__PURE__ */ jsx24(Text22, { color: isTerminal ? theme22.accentActive : theme22.accent, children: label }),
10754
- /* @__PURE__ */ jsx24(Text22, { color: theme22.textMuted, children: usageSummary }),
10755
- historyWarning && /* @__PURE__ */ jsx24(Text22, { color: theme22.warning, children: historyWarning })
10882
+ /* @__PURE__ */ jsx25(Text22, { color: isTerminal ? theme23.accentActive : theme23.accent, children: label }),
10883
+ /* @__PURE__ */ jsx25(Text22, { color: theme23.textMuted, children: usageSummary }),
10884
+ historyWarning && /* @__PURE__ */ jsx25(Text22, { color: theme23.warning, children: historyWarning })
10756
10885
  ]
10757
10886
  }
10758
10887
  );
@@ -10774,7 +10903,7 @@ function getSteeringCountdownText(state) {
10774
10903
  }
10775
10904
 
10776
10905
  // src/ink/marathon/SteeringPrompt.tsx
10777
- import { jsx as jsx25, jsxs as jsxs19 } from "react/jsx-runtime";
10906
+ import { jsx as jsx26, jsxs as jsxs19 } from "react/jsx-runtime";
10778
10907
  function SteeringPrompt({
10779
10908
  onSubmit,
10780
10909
  onToggleHelp,
@@ -10786,18 +10915,18 @@ function SteeringPrompt({
10786
10915
  recap,
10787
10916
  isReviewing = false
10788
10917
  }) {
10789
- const [value, setValue] = useState19("");
10790
- const [remaining, setRemaining] = useState19(timeout);
10791
- const [isTyping, setIsTyping] = useState19(false);
10792
- const [showModelPicker, setShowModelPicker] = useState19(false);
10793
- const [showReflectEditor, setShowReflectEditor] = useState19(false);
10794
- const [showCommandPicker, setShowCommandPicker] = useState19(false);
10795
- const [pendingModel, setPendingModel] = useState19(void 0);
10796
- const [pendingSandbox, setPendingSandbox] = useState19(void 0);
10797
- const [pendingToolsToggle, setPendingToolsToggle] = useState19(false);
10798
- const [pendingStop, setPendingStop] = useState19(false);
10918
+ const [value, setValue] = useState20("");
10919
+ const [remaining, setRemaining] = useState20(timeout);
10920
+ const [isTyping, setIsTyping] = useState20(false);
10921
+ const [showModelPicker, setShowModelPicker] = useState20(false);
10922
+ const [showReflectEditor, setShowReflectEditor] = useState20(false);
10923
+ const [showCommandPicker, setShowCommandPicker] = useState20(false);
10924
+ const [pendingModel, setPendingModel] = useState20(void 0);
10925
+ const [pendingSandbox, setPendingSandbox] = useState20(void 0);
10926
+ const [pendingToolsToggle, setPendingToolsToggle] = useState20(false);
10927
+ const [pendingStop, setPendingStop] = useState20(false);
10799
10928
  const timerRef = useRef7(null);
10800
- const separator = theme23.separator ?? " \xB7 ";
10929
+ const separator = theme24.separator ?? " \xB7 ";
10801
10930
  const hasPendingChanges = pendingModel !== void 0 || pendingSandbox !== void 0 || pendingToolsToggle || pendingStop;
10802
10931
  const clearInputDraft = () => {
10803
10932
  setValue("");
@@ -10821,7 +10950,7 @@ function SteeringPrompt({
10821
10950
  resetDraft();
10822
10951
  onSubmit(result);
10823
10952
  };
10824
- useEffect17(() => {
10953
+ useEffect19(() => {
10825
10954
  const title = "Marathon";
10826
10955
  const body = isTerminal ? "Marathon complete" : `Session ${recap?.sessionNumber ?? "?"} complete`;
10827
10956
  process.stderr.write(`\x1B]777;notify;${title};${body}\x07`);
@@ -10841,7 +10970,7 @@ function SteeringPrompt({
10841
10970
  setIsTyping(false);
10842
10971
  }
10843
10972
  };
10844
- useEffect17(() => {
10973
+ useEffect19(() => {
10845
10974
  if (shouldPauseSteeringTimer({
10846
10975
  isTerminal,
10847
10976
  timeout,
@@ -10987,20 +11116,20 @@ ${trimmed}` : trimmed);
10987
11116
  return "Enter: continue";
10988
11117
  })();
10989
11118
  return /* @__PURE__ */ jsxs19(Box21, { flexDirection: "column", flexShrink: 0, children: [
10990
- showCommandPicker ? /* @__PURE__ */ jsx25(
11119
+ showCommandPicker ? /* @__PURE__ */ jsx26(
10991
11120
  CommandPicker,
10992
11121
  {
10993
11122
  onSelect: handleCommandSelect,
10994
11123
  onCancel: handleCommandCancel
10995
11124
  }
10996
- ) : showModelPicker ? /* @__PURE__ */ jsx25(
11125
+ ) : showModelPicker ? /* @__PURE__ */ jsx26(
10997
11126
  ModelPicker,
10998
11127
  {
10999
11128
  currentModel,
11000
11129
  onSelect: handleModelSelect,
11001
11130
  onCancel: handleModelCancel
11002
11131
  }
11003
- ) : showReflectEditor ? /* @__PURE__ */ jsx25(
11132
+ ) : showReflectEditor ? /* @__PURE__ */ jsx26(
11004
11133
  ReflectEditor,
11005
11134
  {
11006
11135
  onSubmit: handleReflectSubmit,
@@ -11014,15 +11143,15 @@ ${trimmed}` : trimmed);
11014
11143
  borderRight: false,
11015
11144
  borderTop: false,
11016
11145
  borderBottom: false,
11017
- borderColor: theme23.accent,
11018
- backgroundColor: theme23.backgroundDeep,
11146
+ borderColor: theme24.accent,
11147
+ backgroundColor: theme24.backgroundDeep,
11019
11148
  flexDirection: "column",
11020
11149
  paddingX: 1,
11021
11150
  paddingY: 1,
11022
11151
  children: [
11023
11152
  /* @__PURE__ */ jsxs19(Box21, { children: [
11024
- /* @__PURE__ */ jsx25(Text23, { color: theme23.accentActive, children: "> " }),
11025
- /* @__PURE__ */ jsx25(Box21, { flexGrow: 1, children: /* @__PURE__ */ jsx25(
11153
+ /* @__PURE__ */ jsx26(Text23, { color: theme24.accentActive, children: "> " }),
11154
+ /* @__PURE__ */ jsx26(Box21, { flexGrow: 1, children: /* @__PURE__ */ jsx26(
11026
11155
  BlinkingTextInput,
11027
11156
  {
11028
11157
  value,
@@ -11031,28 +11160,28 @@ ${trimmed}` : trimmed);
11031
11160
  placeholder: isTerminal ? "Send new instructions to continue marathon, or press enter to exit..." : "Steer next iteration..."
11032
11161
  }
11033
11162
  ) }),
11034
- countdownText && /* @__PURE__ */ jsxs19(Text23, { color: theme23.textSubtle, children: [
11163
+ countdownText && /* @__PURE__ */ jsxs19(Text23, { color: theme24.textSubtle, children: [
11035
11164
  " ",
11036
11165
  countdownText
11037
11166
  ] })
11038
11167
  ] }),
11039
- /* @__PURE__ */ jsx25(Text23, { color: theme23.textSubtle, children: [
11168
+ /* @__PURE__ */ jsx26(Text23, { color: theme24.textSubtle, children: [
11040
11169
  enterHint,
11041
11170
  "/: commands",
11042
11171
  "/help"
11043
11172
  ].join(separator) }),
11044
- pendingSummary.length > 0 && /* @__PURE__ */ jsx25(Text23, { color: theme23.textMuted, children: `Pending: ${pendingSummary.join(separator)}` })
11173
+ pendingSummary.length > 0 && /* @__PURE__ */ jsx26(Text23, { color: theme24.textMuted, children: `Pending: ${pendingSummary.join(separator)}` })
11045
11174
  ]
11046
11175
  }
11047
11176
  ),
11048
- /* @__PURE__ */ jsx25(SteeringRecap, { ...recap, isTerminal })
11177
+ /* @__PURE__ */ jsx26(SteeringRecap, { ...recap, isTerminal })
11049
11178
  ] });
11050
11179
  }
11051
11180
 
11052
11181
  // src/ink/marathon/SessionActionMenu.tsx
11053
11182
  import { Box as Box22, Text as Text24, useInput as useInput9 } from "ink";
11054
- import { theme as theme24 } from "@runtypelabs/ink-components";
11055
- import { jsx as jsx26, jsxs as jsxs20 } from "react/jsx-runtime";
11183
+ import { theme as theme25 } from "@runtypelabs/ink-components";
11184
+ import { jsx as jsx27, jsxs as jsxs20 } from "react/jsx-runtime";
11056
11185
  var MENU_ITEMS = [
11057
11186
  { key: "c", label: "Copy session JSON" },
11058
11187
  { key: "o", label: "Open state file" },
@@ -11089,23 +11218,23 @@ function SessionActionMenu({
11089
11218
  {
11090
11219
  flexDirection: "column",
11091
11220
  borderStyle: "round",
11092
- borderColor: theme24.accent,
11093
- backgroundColor: theme24.surfaceElevated,
11221
+ borderColor: theme25.accent,
11222
+ backgroundColor: theme25.surfaceElevated,
11094
11223
  paddingX: 2,
11095
11224
  paddingY: 1,
11096
11225
  width: 36,
11097
11226
  children: [
11098
- /* @__PURE__ */ jsx26(Text24, { bold: true, color: theme24.accent, children: "Session" }),
11099
- /* @__PURE__ */ jsx26(Box22, { flexDirection: "column", marginTop: 1, children: MENU_ITEMS.map((item) => {
11227
+ /* @__PURE__ */ jsx27(Text24, { bold: true, color: theme25.accent, children: "Session" }),
11228
+ /* @__PURE__ */ jsx27(Box22, { flexDirection: "column", marginTop: 1, children: MENU_ITEMS.map((item) => {
11100
11229
  const dimmed = item.key === "o" && !hasStateFile || item.key === "d" && !hasDashboard;
11101
11230
  return /* @__PURE__ */ jsxs20(Text24, { children: [
11102
- /* @__PURE__ */ jsx26(Text24, { color: dimmed ? theme24.textSubtle : theme24.accentActive, children: ` ${item.key} ` }),
11103
- /* @__PURE__ */ jsx26(Text24, { color: dimmed ? theme24.textSubtle : theme24.textMuted, children: item.label })
11231
+ /* @__PURE__ */ jsx27(Text24, { color: dimmed ? theme25.textSubtle : theme25.accentActive, children: ` ${item.key} ` }),
11232
+ /* @__PURE__ */ jsx27(Text24, { color: dimmed ? theme25.textSubtle : theme25.textMuted, children: item.label })
11104
11233
  ] }, item.key);
11105
11234
  }) }),
11106
11235
  /* @__PURE__ */ jsxs20(Box22, { marginTop: 1, children: [
11107
- /* @__PURE__ */ jsx26(Text24, { color: theme24.info, children: "Esc" }),
11108
- /* @__PURE__ */ jsx26(Text24, { color: theme24.muted, children: " to close" })
11236
+ /* @__PURE__ */ jsx27(Text24, { color: theme25.info, children: "Esc" }),
11237
+ /* @__PURE__ */ jsx27(Text24, { color: theme25.muted, children: " to close" })
11109
11238
  ] })
11110
11239
  ]
11111
11240
  }
@@ -11114,8 +11243,8 @@ function SessionActionMenu({
11114
11243
 
11115
11244
  // src/ink/marathon/UpgradeModal.tsx
11116
11245
  import { Box as Box23, Text as Text25 } from "ink";
11117
- import { theme as theme25 } from "@runtypelabs/ink-components";
11118
- import { jsx as jsx27, jsxs as jsxs21 } from "react/jsx-runtime";
11246
+ import { theme as theme26 } from "@runtypelabs/ink-components";
11247
+ import { jsx as jsx28, jsxs as jsxs21 } from "react/jsx-runtime";
11119
11248
  function UpgradeModal({ prompt, width }) {
11120
11249
  return /* @__PURE__ */ jsxs21(
11121
11250
  Box23,
@@ -11123,34 +11252,34 @@ function UpgradeModal({ prompt, width }) {
11123
11252
  width,
11124
11253
  flexDirection: "column",
11125
11254
  borderStyle: "round",
11126
- borderColor: theme25.warning,
11127
- backgroundColor: theme25.surfaceElevated,
11255
+ borderColor: theme26.warning,
11256
+ backgroundColor: theme26.surfaceElevated,
11128
11257
  paddingX: 2,
11129
11258
  paddingY: 1,
11130
11259
  children: [
11131
- /* @__PURE__ */ jsx27(Text25, { color: theme25.warning, bold: true, children: "Upgrade available" }),
11132
- /* @__PURE__ */ jsx27(Box23, { marginTop: 1, children: /* @__PURE__ */ jsx27(Text25, { color: theme25.label, children: prompt.message }) }),
11260
+ /* @__PURE__ */ jsx28(Text25, { color: theme26.warning, bold: true, children: "Upgrade available" }),
11261
+ /* @__PURE__ */ jsx28(Box23, { marginTop: 1, children: /* @__PURE__ */ jsx28(Text25, { color: theme26.label, children: prompt.message }) }),
11133
11262
  (prompt.code || prompt.limitType || prompt.retryAfter) && /* @__PURE__ */ jsxs21(Box23, { flexDirection: "column", marginTop: 1, children: [
11134
- prompt.code && /* @__PURE__ */ jsxs21(Text25, { color: theme25.muted, children: [
11263
+ prompt.code && /* @__PURE__ */ jsxs21(Text25, { color: theme26.muted, children: [
11135
11264
  "Code: ",
11136
- /* @__PURE__ */ jsx27(Text25, { color: theme25.label, children: prompt.code })
11265
+ /* @__PURE__ */ jsx28(Text25, { color: theme26.label, children: prompt.code })
11137
11266
  ] }),
11138
- prompt.limitType && /* @__PURE__ */ jsxs21(Text25, { color: theme25.muted, children: [
11267
+ prompt.limitType && /* @__PURE__ */ jsxs21(Text25, { color: theme26.muted, children: [
11139
11268
  "Limit: ",
11140
- /* @__PURE__ */ jsx27(Text25, { color: theme25.label, children: prompt.limitType })
11269
+ /* @__PURE__ */ jsx28(Text25, { color: theme26.label, children: prompt.limitType })
11141
11270
  ] }),
11142
- prompt.retryAfter && /* @__PURE__ */ jsxs21(Text25, { color: theme25.muted, children: [
11271
+ prompt.retryAfter && /* @__PURE__ */ jsxs21(Text25, { color: theme26.muted, children: [
11143
11272
  "Retry after: ",
11144
- /* @__PURE__ */ jsx27(Text25, { color: theme25.label, children: prompt.retryAfter })
11273
+ /* @__PURE__ */ jsx28(Text25, { color: theme26.label, children: prompt.retryAfter })
11145
11274
  ] })
11146
11275
  ] }),
11147
11276
  /* @__PURE__ */ jsxs21(Box23, { marginTop: 1, children: [
11148
- /* @__PURE__ */ jsx27(Text25, { color: theme25.info, children: "Enter" }),
11149
- /* @__PURE__ */ jsx27(Text25, { color: theme25.muted, children: " open billing " }),
11150
- /* @__PURE__ */ jsx27(Text25, { color: theme25.info, children: "Esc" }),
11151
- /* @__PURE__ */ jsx27(Text25, { color: theme25.muted, children: " close" })
11277
+ /* @__PURE__ */ jsx28(Text25, { color: theme26.info, children: "Enter" }),
11278
+ /* @__PURE__ */ jsx28(Text25, { color: theme26.muted, children: " open billing " }),
11279
+ /* @__PURE__ */ jsx28(Text25, { color: theme26.info, children: "Esc" }),
11280
+ /* @__PURE__ */ jsx28(Text25, { color: theme26.muted, children: " close" })
11152
11281
  ] }),
11153
- /* @__PURE__ */ jsx27(Box23, { marginTop: 1, children: /* @__PURE__ */ jsx27(Text25, { color: theme25.dimLabel, children: "Opens your dashboard billing page" }) })
11282
+ /* @__PURE__ */ jsx28(Box23, { marginTop: 1, children: /* @__PURE__ */ jsx28(Text25, { color: theme26.dimLabel, children: "Opens your dashboard billing page" }) })
11154
11283
  ]
11155
11284
  }
11156
11285
  );
@@ -11310,7 +11439,7 @@ function isAllowedSteeringBrowseKey(key, isBrowsingScreen) {
11310
11439
  }
11311
11440
 
11312
11441
  // src/ink/marathon/MarathonApp.tsx
11313
- import { Fragment as Fragment3, jsx as jsx28, jsxs as jsxs22 } from "react/jsx-runtime";
11442
+ import { Fragment as Fragment3, jsx as jsx29, jsxs as jsxs22 } from "react/jsx-runtime";
11314
11443
  var TOOL_PANEL_WIDE = 48;
11315
11444
  var TOOL_PANEL_NARROW = 36;
11316
11445
  var NARROW_THRESHOLD = 100;
@@ -11344,7 +11473,7 @@ function upsertSessionSnapshots(snapshots, nextSnapshot) {
11344
11473
  return Array.from(bySessionIndex.values()).sort((left, right) => left.sessionIndex - right.sessionIndex);
11345
11474
  }
11346
11475
  function buildLiveSessionSnapshot(liveState, sessionIndex, model) {
11347
- const hasLiveState = Boolean(liveState.content) || Boolean(liveState.reasoning) || liveState.tools.length > 0 || liveState.rawEvents.length > 0;
11476
+ const hasLiveState = Boolean(liveState.content) || Boolean(liveState.reasoning) || liveState.tools.length > 0 || liveState.rawEvents.length > 0 || Boolean(liveState.contextCompaction?.active);
11348
11477
  if (!hasLiveState) return void 0;
11349
11478
  return {
11350
11479
  sessionIndex,
@@ -11412,25 +11541,35 @@ function MarathonApp({
11412
11541
  onComplete: _onComplete,
11413
11542
  streamRef
11414
11543
  }) {
11415
- const { state, callbacks, reset: _reset, setSteering, resetForNewSession, showError } = useMarathonStream();
11544
+ const {
11545
+ state,
11546
+ callbacks,
11547
+ reset: _reset,
11548
+ setSteering,
11549
+ startContextCompaction,
11550
+ finishContextCompaction,
11551
+ reportContextNotice,
11552
+ resetForNewSession,
11553
+ showError
11554
+ } = useMarathonStream();
11416
11555
  const { exit } = useApp4();
11417
11556
  const { stdout } = useStdout4();
11418
- const separator = theme26.separator ?? " \xB7 ";
11557
+ const separator = theme27.separator ?? " \xB7 ";
11419
11558
  const steeringResolveRef = useRef8(null);
11420
- const [steeringRecap, setSteeringRecap] = useState20(null);
11421
- const [currentModel, setCurrentModel] = useState20(model || "default");
11422
- const [currentSandbox, setCurrentSandbox] = useState20(sandbox);
11423
- const [isTerminalSteering, setIsTerminalSteering] = useState20(false);
11424
- const [allowInitialInlineLoader, setAllowInitialInlineLoader] = useState20(!suppressInitialInlineLoader);
11425
- const [sessionSnapshots, setSessionSnapshots] = useState20(
11559
+ const [steeringRecap, setSteeringRecap] = useState21(null);
11560
+ const [currentModel, setCurrentModel] = useState21(model || "default");
11561
+ const [currentSandbox, setCurrentSandbox] = useState21(sandbox);
11562
+ const [isTerminalSteering, setIsTerminalSteering] = useState21(false);
11563
+ const [allowInitialInlineLoader, setAllowInitialInlineLoader] = useState21(!suppressInitialInlineLoader);
11564
+ const [sessionSnapshots, setSessionSnapshots] = useState21(
11426
11565
  () => (initialSessionSnapshots || []).map((snapshot) => cloneSessionSnapshot(snapshot))
11427
11566
  );
11428
- const [selectedSessionKey, setSelectedSessionKey] = useState20(void 0);
11429
- const [followLatest, setFollowLatest] = useState20(true);
11430
- const [latestUnreadKey, setLatestUnreadKey] = useState20(void 0);
11431
- const [previewUrl, setPreviewUrl] = useState20(initialPreviewUrl);
11432
- const [isSteeringExploring, setIsSteeringExploring] = useState20(false);
11433
- const isRunnerAnimating = state.phase === "thinking" || state.phase === "streaming" || state.phase === "tool";
11567
+ const [selectedSessionKey, setSelectedSessionKey] = useState21(void 0);
11568
+ const [followLatest, setFollowLatest] = useState21(true);
11569
+ const [latestUnreadKey, setLatestUnreadKey] = useState21(void 0);
11570
+ const [previewUrl, setPreviewUrl] = useState21(initialPreviewUrl);
11571
+ const [isSteeringExploring, setIsSteeringExploring] = useState21(false);
11572
+ const isRunnerAnimating = state.phase === "thinking" || state.phase === "streaming" || state.phase === "tool" || Boolean(state.contextCompaction?.active);
11434
11573
  const isTerminalSteeringRef = useRef8(false);
11435
11574
  const markSteeringExploring = useCallback7(() => {
11436
11575
  if (state.phase === "steering" && steeringRecap) {
@@ -11463,7 +11602,7 @@ function MarathonApp({
11463
11602
  },
11464
11603
  [resetForNewSession]
11465
11604
  );
11466
- useEffect18(() => {
11605
+ useEffect20(() => {
11467
11606
  streamRef.current = {
11468
11607
  getCallbacks: () => callbacks,
11469
11608
  getState: () => state,
@@ -11492,6 +11631,9 @@ function MarathonApp({
11492
11631
  steeringResolveRef.current = resolve6;
11493
11632
  });
11494
11633
  },
11634
+ startContextCompaction,
11635
+ finishContextCompaction,
11636
+ reportContextNotice,
11495
11637
  resetForNewSession,
11496
11638
  showError,
11497
11639
  exit: () => exit()
@@ -11500,9 +11642,12 @@ function MarathonApp({
11500
11642
  callbacks,
11501
11643
  exit,
11502
11644
  followLatest,
11645
+ finishContextCompaction,
11646
+ reportContextNotice,
11503
11647
  setIsSteeringExploring,
11504
11648
  setSteering,
11505
11649
  showError,
11650
+ startContextCompaction,
11506
11651
  state,
11507
11652
  streamRef,
11508
11653
  resetForNewSession
@@ -11513,32 +11658,32 @@ function MarathonApp({
11513
11658
  const contentHeight = Math.max(5, terminalRows - chromeRows);
11514
11659
  const isStacked = terminalWidth < STACKED_THRESHOLD;
11515
11660
  const toolPanelWidth = terminalWidth < NARROW_THRESHOLD ? TOOL_PANEL_NARROW : TOOL_PANEL_WIDE;
11516
- const [ctrlCPressed, setCtrlCPressed] = useState20(false);
11661
+ const [ctrlCPressed, setCtrlCPressed] = useState21(false);
11517
11662
  const ctrlCTimeout = useRef8(null);
11518
- const [activeScreen, setActiveScreen] = useState20("overview");
11663
+ const [activeScreen, setActiveScreen] = useState21("overview");
11519
11664
  const showEventStream = activeScreen === "events";
11520
11665
  const showToolsPanel = activeScreen === "tools";
11521
11666
  const showFilesPanel = activeScreen === "files";
11522
- const [showHelpOverlay, setShowHelpOverlay] = useState20(false);
11523
- const [helpScrollOffset, setHelpScrollOffset] = useState20(0);
11524
- const [showSessionMenu, setShowSessionMenu] = useState20(false);
11525
- const [fileCursor, setFileCursor] = useState20(0);
11526
- const [detailFile, setDetailFile] = useState20(null);
11527
- const [detailFileContent, setDetailFileContent] = useState20(null);
11528
- const [detailFileTotalLines, setDetailFileTotalLines] = useState20(0);
11529
- const [detailFileTruncated, setDetailFileTruncated] = useState20(false);
11530
- const [fileDetailScrollOffset, setFileDetailScrollOffset] = useState20(0);
11531
- const [scrollOffset, setScrollOffset] = useState20(0);
11532
- const [reasoningCollapsed, setReasoningCollapsed] = useState20(false);
11533
- const [eventCursor, setEventCursor] = useState20(-1);
11534
- const [detailEvent, setDetailEvent] = useState20(null);
11535
- const [detailScrollOffset, setDetailScrollOffset] = useState20(0);
11536
- const [toolCursor, setToolCursor] = useState20(-1);
11537
- const [detailToolEntry, setDetailToolEntry] = useState20(null);
11538
- const [toolDetailScrollOffset, setToolDetailScrollOffset] = useState20(0);
11539
- const [goalExpanded, setGoalExpanded] = useState20(false);
11540
- const [upgradeModalDismissed, setUpgradeModalDismissed] = useState20(false);
11541
- const [clipboardFlash, setClipboardFlash] = useState20(null);
11667
+ const [showHelpOverlay, setShowHelpOverlay] = useState21(false);
11668
+ const [helpScrollOffset, setHelpScrollOffset] = useState21(0);
11669
+ const [showSessionMenu, setShowSessionMenu] = useState21(false);
11670
+ const [fileCursor, setFileCursor] = useState21(0);
11671
+ const [detailFile, setDetailFile] = useState21(null);
11672
+ const [detailFileContent, setDetailFileContent] = useState21(null);
11673
+ const [detailFileTotalLines, setDetailFileTotalLines] = useState21(0);
11674
+ const [detailFileTruncated, setDetailFileTruncated] = useState21(false);
11675
+ const [fileDetailScrollOffset, setFileDetailScrollOffset] = useState21(0);
11676
+ const [scrollOffset, setScrollOffset] = useState21(0);
11677
+ const [reasoningCollapsed, setReasoningCollapsed] = useState21(false);
11678
+ const [eventCursor, setEventCursor] = useState21(-1);
11679
+ const [detailEvent, setDetailEvent] = useState21(null);
11680
+ const [detailScrollOffset, setDetailScrollOffset] = useState21(0);
11681
+ const [toolCursor, setToolCursor] = useState21(-1);
11682
+ const [detailToolEntry, setDetailToolEntry] = useState21(null);
11683
+ const [toolDetailScrollOffset, setToolDetailScrollOffset] = useState21(0);
11684
+ const [goalExpanded, setGoalExpanded] = useState21(false);
11685
+ const [upgradeModalDismissed, setUpgradeModalDismissed] = useState21(false);
11686
+ const [clipboardFlash, setClipboardFlash] = useState21(null);
11542
11687
  const flashTimeout = useRef8(null);
11543
11688
  const billingPageUrl = billingUrl || `${(dashboardUrl || "https://use.runtype.com").replace(/\/$/, "")}/settings/billing`;
11544
11689
  function showFlash(msg) {
@@ -11584,7 +11729,7 @@ function MarathonApp({
11584
11729
  }
11585
11730
  }, [agentPageUrl]);
11586
11731
  const latestCompletedSessionIndex = sessionSnapshots[sessionSnapshots.length - 1]?.sessionIndex ?? initialSessionCount;
11587
- const shouldShowLiveTab = state.phase !== "idle" && state.phase !== "steering" && state.phase !== "complete" && (Boolean(state.content) || Boolean(state.reasoning) || state.tools.length > 0 || state.rawEvents.length > 0 || state.phase === "thinking" || state.phase === "error");
11732
+ const shouldShowLiveTab = Boolean(state.contextCompaction?.active) || state.phase !== "idle" && state.phase !== "steering" && state.phase !== "complete" && (Boolean(state.content) || Boolean(state.reasoning) || state.tools.length > 0 || state.rawEvents.length > 0 || state.phase === "thinking" || state.phase === "error");
11588
11733
  const liveSessionSnapshot = useMemo10(
11589
11734
  () => shouldShowLiveTab ? buildLiveSessionSnapshot(state, latestCompletedSessionIndex + 1, currentModel) : void 0,
11590
11735
  [currentModel, latestCompletedSessionIndex, shouldShowLiveTab, state]
@@ -11643,25 +11788,25 @@ function MarathonApp({
11643
11788
  },
11644
11789
  [latestSessionKey]
11645
11790
  );
11646
- useEffect18(() => {
11791
+ useEffect20(() => {
11647
11792
  if (!selectedSessionKey && latestSessionKey) {
11648
11793
  setSelectedSessionKey(latestSessionKey);
11649
11794
  }
11650
11795
  }, [latestSessionKey, selectedSessionKey]);
11651
- useEffect18(() => {
11796
+ useEffect20(() => {
11652
11797
  if (followLatest && latestSessionKey && selectedSessionKey !== latestSessionKey) {
11653
11798
  setSelectedSessionKey(latestSessionKey);
11654
11799
  }
11655
11800
  }, [followLatest, latestSessionKey, selectedSessionKey]);
11656
- useEffect18(() => {
11801
+ useEffect20(() => {
11657
11802
  if (selectedSessionKey && selectedSessionKey === latestSessionKey && latestUnreadKey) {
11658
11803
  setLatestUnreadKey(void 0);
11659
11804
  }
11660
11805
  }, [latestSessionKey, latestUnreadKey, selectedSessionKey]);
11661
- useEffect18(() => {
11806
+ useEffect20(() => {
11662
11807
  setUpgradeModalDismissed(false);
11663
11808
  }, [upgradePromptKey]);
11664
- useEffect18(() => {
11809
+ useEffect20(() => {
11665
11810
  const liveActivityKey = liveSessionSnapshot ? `${liveSessionSnapshot.sessionIndex}:${state.phase}:${state.content.length}:${state.reasoning.length}:${state.tools.length}:${state.rawEvents.length}` : void 0;
11666
11811
  if (!liveActivityKey) {
11667
11812
  latestLiveActivityRef.current = void 0;
@@ -11681,7 +11826,7 @@ function MarathonApp({
11681
11826
  state.reasoning.length,
11682
11827
  state.tools.length
11683
11828
  ]);
11684
- useEffect18(() => {
11829
+ useEffect20(() => {
11685
11830
  const deploySandboxTool = state.tools.find(
11686
11831
  (t) => t.name === "deploy_sandbox" && t.status === "complete" && t.result
11687
11832
  );
@@ -11692,19 +11837,19 @@ function MarathonApp({
11692
11837
  }
11693
11838
  }
11694
11839
  }, [state.tools]);
11695
- useEffect18(() => {
11840
+ useEffect20(() => {
11696
11841
  if (showEventStream && displayedEvents.length > 0 && eventCursor === -1) {
11697
11842
  setEventCursor(displayedEvents.length - 1);
11698
11843
  }
11699
11844
  }, [displayedEvents.length, eventCursor, showEventStream]);
11700
- useEffect18(() => {
11845
+ useEffect20(() => {
11701
11846
  if (allowInitialInlineLoader) return;
11702
11847
  const hasVisibleSessionActivity = Boolean(state.content.trim()) || Boolean(state.reasoning.trim()) || state.tools.length > 0 || state.error !== null;
11703
11848
  if (hasVisibleSessionActivity) {
11704
11849
  setAllowInitialInlineLoader(true);
11705
11850
  }
11706
11851
  }, [allowInitialInlineLoader, state.content, state.error, state.reasoning, state.tools.length]);
11707
- useEffect18(() => {
11852
+ useEffect20(() => {
11708
11853
  if (showToolsPanel && displayedTools.length > 0 && toolCursor === -1) {
11709
11854
  setToolCursor(displayedTools.length - 1);
11710
11855
  }
@@ -12060,7 +12205,7 @@ function MarathonApp({
12060
12205
  return;
12061
12206
  }
12062
12207
  });
12063
- useEffect18(() => {
12208
+ useEffect20(() => {
12064
12209
  return () => {
12065
12210
  if (ctrlCTimeout.current) clearTimeout(ctrlCTimeout.current);
12066
12211
  if (flashTimeout.current) clearTimeout(flashTimeout.current);
@@ -12072,7 +12217,8 @@ function MarathonApp({
12072
12217
  const hasTools = displayedTools.length > 0;
12073
12218
  const hasReasoning = Boolean(displayedReasoning.trim());
12074
12219
  const showThinkingIndicator = selectedIsLive && state.phase === "thinking" && !hasReasoning;
12075
- const showLoadingAnimation = shouldShowMarathonLoadingAnimation({
12220
+ const showContextCompactionIndicator = selectedIsLive && Boolean(state.contextCompaction?.active);
12221
+ const showLoadingAnimation = !showContextCompactionIndicator && shouldShowMarathonLoadingAnimation({
12076
12222
  allowInitialInlineLoader,
12077
12223
  content: displayedContent,
12078
12224
  reasoning: displayedReasoning,
@@ -12175,10 +12321,11 @@ function MarathonApp({
12175
12321
  const steeringPromptRows = STEERING_PROMPT_ROWS + steeringWarningRows;
12176
12322
  const reasoningHintRows = hasReasoning ? 1 : 0;
12177
12323
  const thinkingRows = showThinkingIndicator ? 2 : 0;
12324
+ const compactionIndicatorRows = showContextCompactionIndicator ? 1 : 0;
12178
12325
  const reasoningLiveRows = hasReasoning && !reasoningCollapsed && selectedIsLive && state.phase === "thinking" ? 1 : 0;
12179
12326
  const maxReasoningRows = Math.max(
12180
12327
  0,
12181
- adjustedContentHeight - reasoningHintRows - reasoningLiveRows - thinkingRows - 3
12328
+ adjustedContentHeight - reasoningHintRows - reasoningLiveRows - thinkingRows - compactionIndicatorRows - 3
12182
12329
  );
12183
12330
  const targetReasoningRows = hasReasoning && !reasoningCollapsed ? Math.min(maxReasoningRows, Math.max(3, Math.min(8, Math.floor(adjustedContentHeight * 0.3)))) : 0;
12184
12331
  const visibleReasoningLines = useMemo10(
@@ -12188,7 +12335,7 @@ function MarathonApp({
12188
12335
  const reasoningBodyRows = reasoningCollapsed ? 0 : visibleReasoningLines.length;
12189
12336
  const transcriptRows = Math.max(
12190
12337
  3,
12191
- adjustedContentHeight - reasoningHintRows - reasoningBodyRows - reasoningLiveRows - thinkingRows
12338
+ adjustedContentHeight - reasoningHintRows - reasoningBodyRows - reasoningLiveRows - thinkingRows - compactionIndicatorRows
12192
12339
  );
12193
12340
  const upgradeModalWidth = Math.max(24, Math.min(terminalWidth - 6, 88));
12194
12341
  const showUpgradeBrowseHint = canBrowseAfterUpgradeError && selectedIsLive && !displayedContent.trim() && !displayedReasoning.trim() && displayedTools.length === 0 && displayedEvents.length === 0;
@@ -12199,7 +12346,7 @@ function MarathonApp({
12199
12346
  height: terminalRows,
12200
12347
  width: terminalWidth,
12201
12348
  children: [
12202
- /* @__PURE__ */ jsx28(
12349
+ /* @__PURE__ */ jsx29(
12203
12350
  SessionHeader,
12204
12351
  {
12205
12352
  sessionName: taskName,
@@ -12217,8 +12364,8 @@ function MarathonApp({
12217
12364
  previewUrl
12218
12365
  }
12219
12366
  ),
12220
- /* @__PURE__ */ jsx28(Box24, { marginLeft: 1, children: /* @__PURE__ */ jsx28(ScreenTabs, { activeTab: activeScreen, width: terminalWidth - 1 }) }),
12221
- hasTabs && /* @__PURE__ */ jsx28(Box24, { width: terminalWidth, marginBottom: 1, marginLeft: 1, children: /* @__PURE__ */ jsx28(
12367
+ /* @__PURE__ */ jsx29(Box24, { marginLeft: 1, children: /* @__PURE__ */ jsx29(ScreenTabs, { activeTab: activeScreen, width: terminalWidth - 1 }) }),
12368
+ hasTabs && /* @__PURE__ */ jsx29(Box24, { width: terminalWidth, marginBottom: 1, marginLeft: 1, children: /* @__PURE__ */ jsx29(
12222
12369
  SessionTabs,
12223
12370
  {
12224
12371
  tabs: visibleTabs.tabs,
@@ -12227,13 +12374,13 @@ function MarathonApp({
12227
12374
  shortcutHint: "Shift+\\u2190/\\u2192: runs"
12228
12375
  }
12229
12376
  ) }),
12230
- showFilesPanel ? /* @__PURE__ */ jsx28(
12377
+ showFilesPanel ? /* @__PURE__ */ jsx29(
12231
12378
  Box24,
12232
12379
  {
12233
12380
  flexDirection: "column",
12234
12381
  height: adjustedContentHeight,
12235
12382
  overflow: "hidden",
12236
- children: /* @__PURE__ */ jsx28(
12383
+ children: /* @__PURE__ */ jsx29(
12237
12384
  FilesPanel,
12238
12385
  {
12239
12386
  files: trackedFiles,
@@ -12248,13 +12395,13 @@ function MarathonApp({
12248
12395
  }
12249
12396
  )
12250
12397
  }
12251
- ) : showEventStream ? /* @__PURE__ */ jsx28(
12398
+ ) : showEventStream ? /* @__PURE__ */ jsx29(
12252
12399
  Box24,
12253
12400
  {
12254
12401
  flexDirection: "column",
12255
12402
  height: adjustedContentHeight,
12256
12403
  overflow: "hidden",
12257
- children: /* @__PURE__ */ jsx28(
12404
+ children: /* @__PURE__ */ jsx29(
12258
12405
  EventStreamPanel,
12259
12406
  {
12260
12407
  events: displayedEvents,
@@ -12267,13 +12414,13 @@ function MarathonApp({
12267
12414
  }
12268
12415
  )
12269
12416
  }
12270
- ) : showToolsPanel ? /* @__PURE__ */ jsx28(
12417
+ ) : showToolsPanel ? /* @__PURE__ */ jsx29(
12271
12418
  Box24,
12272
12419
  {
12273
12420
  flexDirection: "column",
12274
12421
  height: adjustedContentHeight,
12275
12422
  overflow: "hidden",
12276
- children: /* @__PURE__ */ jsx28(
12423
+ children: /* @__PURE__ */ jsx29(
12277
12424
  ToolsPanel,
12278
12425
  {
12279
12426
  tools: displayedTools,
@@ -12301,7 +12448,7 @@ function MarathonApp({
12301
12448
  marginRight: contentMarginRight,
12302
12449
  children: [
12303
12450
  /* @__PURE__ */ jsxs22(Box24, { flexDirection: "row", flexGrow: 1, overflow: "hidden", marginBottom: 1, children: [
12304
- /* @__PURE__ */ jsx28(Box24, { flexDirection: "column", flexGrow: 1, marginRight: 1, children: /* @__PURE__ */ jsx28(
12451
+ /* @__PURE__ */ jsx29(Box24, { flexDirection: "column", flexGrow: 1, marginRight: 1, children: /* @__PURE__ */ jsx29(
12305
12452
  StreamOutput,
12306
12453
  {
12307
12454
  content: displayedContent,
@@ -12315,7 +12462,7 @@ function MarathonApp({
12315
12462
  const steeringVisibleRows = adjustedContentHeight - steeringPromptRows - 1;
12316
12463
  const steeringTotalLines = displayedContent.split("\n").length;
12317
12464
  const steeringMaxScroll = Math.max(0, steeringTotalLines - steeringVisibleRows);
12318
- return /* @__PURE__ */ jsx28(
12465
+ return /* @__PURE__ */ jsx29(
12319
12466
  Scrollbar,
12320
12467
  {
12321
12468
  totalLines: steeringTotalLines,
@@ -12326,7 +12473,7 @@ function MarathonApp({
12326
12473
  );
12327
12474
  })()
12328
12475
  ] }),
12329
- /* @__PURE__ */ jsx28(
12476
+ /* @__PURE__ */ jsx29(
12330
12477
  SteeringPrompt,
12331
12478
  {
12332
12479
  onSubmit: handleSteeringSubmit,
@@ -12344,18 +12491,18 @@ function MarathonApp({
12344
12491
  ]
12345
12492
  }
12346
12493
  ),
12347
- !isStacked && (hasTools || hasReasoning) && /* @__PURE__ */ jsx28(
12494
+ !isStacked && (hasTools || hasReasoning) && /* @__PURE__ */ jsx29(
12348
12495
  Box24,
12349
12496
  {
12350
12497
  flexDirection: "column",
12351
12498
  width: toolPanelWidth,
12352
12499
  flexShrink: 0,
12353
12500
  borderStyle: "single",
12354
- borderColor: theme26.border,
12355
- backgroundColor: theme26.background,
12356
- paddingX: theme26.panelPaddingX,
12357
- paddingY: theme26.panelPaddingY,
12358
- children: /* @__PURE__ */ jsx28(
12501
+ borderColor: theme27.border,
12502
+ backgroundColor: theme27.background,
12503
+ paddingX: theme27.panelPaddingX,
12504
+ paddingY: theme27.panelPaddingY,
12505
+ children: /* @__PURE__ */ jsx29(
12359
12506
  ToolPanel,
12360
12507
  {
12361
12508
  tools: displayedTools,
@@ -12375,7 +12522,7 @@ function MarathonApp({
12375
12522
  height: adjustedContentHeight,
12376
12523
  overflow: "hidden",
12377
12524
  children: [
12378
- /* @__PURE__ */ jsx28(
12525
+ /* @__PURE__ */ jsx29(
12379
12526
  Box24,
12380
12527
  {
12381
12528
  flexDirection: "column",
@@ -12383,13 +12530,13 @@ function MarathonApp({
12383
12530
  flexShrink: 1,
12384
12531
  marginLeft: contentMarginLeft,
12385
12532
  marginRight: contentMarginRight,
12386
- children: showLoadingAnimation ? /* @__PURE__ */ jsx28(
12533
+ children: showLoadingAnimation ? /* @__PURE__ */ jsx29(
12387
12534
  Box24,
12388
12535
  {
12389
12536
  flexGrow: 1,
12390
12537
  minHeight: adjustedContentHeight,
12391
12538
  overflow: "hidden",
12392
- children: /* @__PURE__ */ jsx28(
12539
+ children: /* @__PURE__ */ jsx29(
12393
12540
  LoadingAnimation,
12394
12541
  {
12395
12542
  width: transcriptPaneWidth,
@@ -12398,7 +12545,7 @@ function MarathonApp({
12398
12545
  )
12399
12546
  }
12400
12547
  ) : /* @__PURE__ */ jsxs22(Fragment3, { children: [
12401
- hasReasoning && /* @__PURE__ */ jsx28(Box24, { flexDirection: "column", marginBottom: reasoningCollapsed ? 0 : 1, children: /* @__PURE__ */ jsx28(
12548
+ hasReasoning && /* @__PURE__ */ jsx29(Box24, { flexDirection: "column", marginBottom: reasoningCollapsed ? 0 : 1, children: /* @__PURE__ */ jsx29(
12402
12549
  ReasoningBlock,
12403
12550
  {
12404
12551
  lines: visibleReasoningLines,
@@ -12407,8 +12554,9 @@ function MarathonApp({
12407
12554
  showToggleHint: true
12408
12555
  }
12409
12556
  ) }),
12410
- showThinkingIndicator && /* @__PURE__ */ jsx28(ThinkingIndicator, { startedAt: state.thinkingStartedAt }),
12411
- showUpgradeBrowseHint && /* @__PURE__ */ jsx28(Box24, { marginBottom: 1, children: /* @__PURE__ */ jsx28(
12557
+ showThinkingIndicator && /* @__PURE__ */ jsx29(ThinkingIndicator, { startedAt: state.thinkingStartedAt }),
12558
+ showContextCompactionIndicator && state.contextCompaction && /* @__PURE__ */ jsx29(ContextCompactionIndicator, { compaction: state.contextCompaction }),
12559
+ showUpgradeBrowseHint && /* @__PURE__ */ jsx29(Box24, { marginBottom: 1, children: /* @__PURE__ */ jsx29(
12412
12560
  ReasoningBlock,
12413
12561
  {
12414
12562
  lines: [
@@ -12419,7 +12567,7 @@ function MarathonApp({
12419
12567
  }
12420
12568
  ) }),
12421
12569
  /* @__PURE__ */ jsxs22(Box24, { flexDirection: "row", children: [
12422
- /* @__PURE__ */ jsx28(Box24, { flexDirection: "column", flexGrow: 1, marginRight: 1, children: /* @__PURE__ */ jsx28(
12570
+ /* @__PURE__ */ jsx29(Box24, { flexDirection: "column", flexGrow: 1, marginRight: 1, children: /* @__PURE__ */ jsx29(
12423
12571
  StreamOutput,
12424
12572
  {
12425
12573
  content: displayedContent,
@@ -12432,7 +12580,7 @@ function MarathonApp({
12432
12580
  (() => {
12433
12581
  const overviewTotalLines = displayedContent.split("\n").length;
12434
12582
  const overviewMaxScroll = Math.max(0, overviewTotalLines - transcriptRows);
12435
- return /* @__PURE__ */ jsx28(
12583
+ return /* @__PURE__ */ jsx29(
12436
12584
  Scrollbar,
12437
12585
  {
12438
12586
  totalLines: overviewTotalLines,
@@ -12443,22 +12591,22 @@ function MarathonApp({
12443
12591
  );
12444
12592
  })()
12445
12593
  ] }),
12446
- selectedIsLive && state.error && !upgradePrompt && /* @__PURE__ */ jsx28(ErrorDisplay3, { error: state.error })
12594
+ selectedIsLive && state.error && !upgradePrompt && /* @__PURE__ */ jsx29(ErrorDisplay3, { error: state.error })
12447
12595
  ] })
12448
12596
  }
12449
12597
  ),
12450
- (hasTools || hasReasoning) && /* @__PURE__ */ jsx28(
12598
+ (hasTools || hasReasoning) && /* @__PURE__ */ jsx29(
12451
12599
  Box24,
12452
12600
  {
12453
12601
  flexDirection: "column",
12454
12602
  width: isStacked ? void 0 : toolPanelWidth,
12455
12603
  flexShrink: 0,
12456
12604
  borderStyle: "single",
12457
- borderColor: theme26.border,
12458
- backgroundColor: theme26.background,
12459
- paddingX: theme26.panelPaddingX,
12460
- paddingY: theme26.panelPaddingY,
12461
- children: /* @__PURE__ */ jsx28(
12605
+ borderColor: theme27.border,
12606
+ backgroundColor: theme27.background,
12607
+ paddingX: theme27.panelPaddingX,
12608
+ paddingY: theme27.panelPaddingY,
12609
+ children: /* @__PURE__ */ jsx29(
12462
12610
  ToolPanel,
12463
12611
  {
12464
12612
  tools: displayedTools,
@@ -12472,7 +12620,7 @@ function MarathonApp({
12472
12620
  ]
12473
12621
  }
12474
12622
  ),
12475
- showHelpOverlay && /* @__PURE__ */ jsx28(
12623
+ showHelpOverlay && /* @__PURE__ */ jsx29(
12476
12624
  Box24,
12477
12625
  {
12478
12626
  width: terminalWidth,
@@ -12481,8 +12629,8 @@ function MarathonApp({
12481
12629
  justifyContent: "center",
12482
12630
  alignItems: "center",
12483
12631
  flexShrink: 0,
12484
- backgroundColor: theme26.surfaceMuted,
12485
- children: /* @__PURE__ */ jsx28(
12632
+ backgroundColor: theme27.surfaceMuted,
12633
+ children: /* @__PURE__ */ jsx29(
12486
12634
  HelpPanel,
12487
12635
  {
12488
12636
  width: terminalWidth,
@@ -12493,7 +12641,7 @@ function MarathonApp({
12493
12641
  )
12494
12642
  }
12495
12643
  ),
12496
- showSessionMenu && /* @__PURE__ */ jsx28(
12644
+ showSessionMenu && /* @__PURE__ */ jsx29(
12497
12645
  Box24,
12498
12646
  {
12499
12647
  width: terminalWidth,
@@ -12502,8 +12650,8 @@ function MarathonApp({
12502
12650
  justifyContent: "center",
12503
12651
  alignItems: "center",
12504
12652
  flexShrink: 0,
12505
- backgroundColor: theme26.surfaceMuted,
12506
- children: /* @__PURE__ */ jsx28(
12653
+ backgroundColor: theme27.surfaceMuted,
12654
+ children: /* @__PURE__ */ jsx29(
12507
12655
  SessionActionMenu,
12508
12656
  {
12509
12657
  onCopySession: handleCopySession,
@@ -12516,7 +12664,7 @@ function MarathonApp({
12516
12664
  )
12517
12665
  }
12518
12666
  ),
12519
- showUpgradeModal && upgradePrompt && /* @__PURE__ */ jsx28(
12667
+ showUpgradeModal && upgradePrompt && /* @__PURE__ */ jsx29(
12520
12668
  Box24,
12521
12669
  {
12522
12670
  marginTop: -adjustedContentHeight,
@@ -12525,15 +12673,15 @@ function MarathonApp({
12525
12673
  justifyContent: "center",
12526
12674
  alignItems: "center",
12527
12675
  flexShrink: 0,
12528
- children: /* @__PURE__ */ jsx28(UpgradeModal, { prompt: upgradePrompt, width: upgradeModalWidth })
12676
+ children: /* @__PURE__ */ jsx29(UpgradeModal, { prompt: upgradePrompt, width: upgradeModalWidth })
12529
12677
  }
12530
12678
  ),
12531
- /* @__PURE__ */ jsx28(
12679
+ /* @__PURE__ */ jsx29(
12532
12680
  StatusBar,
12533
12681
  {
12534
- left: /* @__PURE__ */ jsxs22(Text26, { color: theme26.textMuted, children: [
12682
+ left: /* @__PURE__ */ jsxs22(Text26, { color: theme27.textMuted, children: [
12535
12683
  `Model: ${currentModel}${currentSandbox ? `${separator}Sandbox: ${currentSandbox}` : ""}`,
12536
- previewUrl && /* @__PURE__ */ jsx28(Text26, { color: theme26.accent, children: `${separator}\x1B]8;;${previewUrl}\x07preview\x1B]8;;\x07` })
12684
+ previewUrl && /* @__PURE__ */ jsx29(Text26, { color: theme27.accent, children: `${separator}\x1B]8;;${previewUrl}\x07preview\x1B]8;;\x07` })
12537
12685
  ] }),
12538
12686
  center: showFilesPanel ? filesCenter : showEventStream ? detailCenter : showToolsPanel ? toolsCenter : void 0,
12539
12687
  right: statusRight
@@ -12545,10 +12693,10 @@ function MarathonApp({
12545
12693
  }
12546
12694
 
12547
12695
  // src/ink/marathon/MarathonStartupShell.tsx
12548
- import { useEffect as useEffect19, useRef as useRef9, useState as useState21 } from "react";
12696
+ import { useEffect as useEffect21, useRef as useRef9, useState as useState22 } from "react";
12549
12697
  import { Box as Box25, Text as Text27, useApp as useApp5, useInput as useInput11, useStdout as useStdout5 } from "ink";
12550
- import { theme as theme27 } from "@runtypelabs/ink-components";
12551
- import { jsx as jsx29, jsxs as jsxs23 } from "react/jsx-runtime";
12698
+ import { theme as theme28 } from "@runtypelabs/ink-components";
12699
+ import { jsx as jsx30, jsxs as jsxs23 } from "react/jsx-runtime";
12552
12700
  var SCROLL_HINT = "\u2191\u2193 Enter 1-3";
12553
12701
  var PROMPT_COLUMN_MAX = 68;
12554
12702
  var MIN_HOLD_MS = 1500;
@@ -12601,17 +12749,20 @@ function MarathonStartupShell({
12601
12749
  const { stdout } = useStdout5();
12602
12750
  const mountedAtRef = useRef9(Date.now());
12603
12751
  const promptResolverRef = useRef9(null);
12752
+ const modelResolverRef = useRef9(null);
12604
12753
  const appReadyResolverRef = useRef9(null);
12605
12754
  const dismissResolverRef = useRef9(null);
12606
12755
  const transitionPromiseRef = useRef9(null);
12607
12756
  const latestAppPropsRef = useRef9(marathonAppProps);
12608
- const [statusMessage, setStatusMessage] = useState21("preparing marathon");
12609
- const [scene, setScene] = useState21("splash");
12610
- const [transition, setTransition] = useState21(null);
12611
- const [prompt, setPrompt] = useState21(null);
12612
- const [selectedPromptIndex, setSelectedPromptIndex] = useState21(0);
12757
+ const [statusMessage, setStatusMessage] = useState22("preparing marathon");
12758
+ const [scene, setScene] = useState22("splash");
12759
+ const [transition, setTransition] = useState22(null);
12760
+ const [prompt, setPrompt] = useState22(null);
12761
+ const [modelChoices, setModelChoices] = useState22(null);
12762
+ const [currentModel, setCurrentModel] = useState22("default");
12763
+ const [selectedPromptIndex, setSelectedPromptIndex] = useState22(0);
12613
12764
  latestAppPropsRef.current = marathonAppProps;
12614
- useEffect19(() => {
12765
+ useEffect21(() => {
12615
12766
  if (scene !== "app" || !appReadyResolverRef.current) return;
12616
12767
  const resolve6 = appReadyResolverRef.current;
12617
12768
  appReadyResolverRef.current = null;
@@ -12625,6 +12776,7 @@ function MarathonStartupShell({
12625
12776
  const promise = new Promise((resolve6) => {
12626
12777
  globalThis.setTimeout(() => {
12627
12778
  setPrompt(null);
12779
+ setModelChoices(null);
12628
12780
  setTransition({
12629
12781
  startedAt: Date.now(),
12630
12782
  target
@@ -12655,18 +12807,27 @@ function MarathonStartupShell({
12655
12807
  transitionPromiseRef.current = promise;
12656
12808
  return promise;
12657
12809
  };
12658
- useEffect19(() => {
12810
+ useEffect21(() => {
12659
12811
  startupRef.current = {
12660
12812
  setStatus: (message) => {
12661
12813
  setStatusMessage(message);
12662
12814
  },
12663
12815
  requestStateChoice: async (nextPrompt) => {
12816
+ setModelChoices(null);
12664
12817
  setPrompt(nextPrompt);
12665
12818
  setSelectedPromptIndex(0);
12666
12819
  return new Promise((resolve6) => {
12667
12820
  promptResolverRef.current = resolve6;
12668
12821
  });
12669
12822
  },
12823
+ requestModelChoice: async (nextCurrentModel, models) => {
12824
+ setPrompt(null);
12825
+ setCurrentModel(nextCurrentModel);
12826
+ setModelChoices(models);
12827
+ return new Promise((resolve6) => {
12828
+ modelResolverRef.current = resolve6;
12829
+ });
12830
+ },
12670
12831
  completeStartup: () => beginTransition("app"),
12671
12832
  dismiss: () => beginTransition("exit")
12672
12833
  };
@@ -12680,7 +12841,7 @@ function MarathonStartupShell({
12680
12841
  process.kill(process.pid, "SIGINT");
12681
12842
  return;
12682
12843
  }
12683
- if (!prompt || transition) return;
12844
+ if (!prompt || transition || modelChoices) return;
12684
12845
  if (key.upArrow || input === "k") {
12685
12846
  setSelectedPromptIndex((current) => (current - 1 + prompt.choices.length) % prompt.choices.length);
12686
12847
  return;
@@ -12717,7 +12878,7 @@ function MarathonStartupShell({
12717
12878
  const promptShellModel = prompt ? buildPromptShellModel(prompt, promptColumnWidth) : null;
12718
12879
  const selectedChoice = prompt?.choices[selectedPromptIndex];
12719
12880
  if (scene === "app" && marathonAppProps) {
12720
- return /* @__PURE__ */ jsx29(
12881
+ return /* @__PURE__ */ jsx30(
12721
12882
  MarathonApp,
12722
12883
  {
12723
12884
  ...marathonAppProps,
@@ -12725,38 +12886,56 @@ function MarathonStartupShell({
12725
12886
  }
12726
12887
  );
12727
12888
  }
12728
- return /* @__PURE__ */ jsx29(
12889
+ return /* @__PURE__ */ jsx30(
12729
12890
  Box25,
12730
12891
  {
12731
12892
  width: terminalWidth,
12732
12893
  height: terminalRows,
12733
- backgroundColor: theme27.background,
12894
+ backgroundColor: theme28.background,
12734
12895
  flexDirection: "column",
12735
12896
  justifyContent: "center",
12736
12897
  alignItems: "center",
12737
12898
  children: /* @__PURE__ */ jsxs23(Box25, { flexDirection: "column", alignItems: "center", children: [
12738
- !prompt && /* @__PURE__ */ jsx29(Box25, { width: terminalWidth, justifyContent: "center", children: /* @__PURE__ */ jsx29(Text27, { color: theme27.textMuted, children: statusMessage }) }),
12899
+ !prompt && !modelChoices && /* @__PURE__ */ jsx30(Box25, { width: terminalWidth, justifyContent: "center", children: /* @__PURE__ */ jsx30(Text27, { color: theme28.textMuted, children: statusMessage }) }),
12900
+ modelChoices && /* @__PURE__ */ jsx30(Box25, { width: promptColumnWidth, flexDirection: "column", marginTop: 1, children: /* @__PURE__ */ jsx30(
12901
+ ModelPicker,
12902
+ {
12903
+ currentModel,
12904
+ models: modelChoices,
12905
+ onSelect: (model) => {
12906
+ modelResolverRef.current?.(model);
12907
+ modelResolverRef.current = null;
12908
+ setCurrentModel(model);
12909
+ setModelChoices(null);
12910
+ },
12911
+ onCancel: () => {
12912
+ modelResolverRef.current?.(currentModel);
12913
+ modelResolverRef.current = null;
12914
+ setModelChoices(null);
12915
+ }
12916
+ }
12917
+ ) }),
12739
12918
  prompt && /* @__PURE__ */ jsxs23(Box25, { width: promptColumnWidth, flexDirection: "column", marginTop: 1, children: [
12740
- /* @__PURE__ */ jsx29(Text27, { bold: true, color: theme27.text, children: promptShellModel?.heading }),
12919
+ /* @__PURE__ */ jsx30(Text27, { bold: true, color: theme28.text, children: promptShellModel?.heading }),
12741
12920
  promptShellModel?.task && /* @__PURE__ */ jsxs23(Box25, { marginTop: 1, children: [
12742
- /* @__PURE__ */ jsx29(Text27, { color: theme27.textSubtle, children: "task " }),
12743
- /* @__PURE__ */ jsx29(Text27, { color: theme27.text, children: promptShellModel.task })
12921
+ /* @__PURE__ */ jsx30(Text27, { color: theme28.textSubtle, children: "task " }),
12922
+ /* @__PURE__ */ jsx30(Text27, { color: theme28.text, children: promptShellModel.task })
12744
12923
  ] }),
12745
12924
  promptShellModel?.filePath && /* @__PURE__ */ jsxs23(Box25, { children: [
12746
- /* @__PURE__ */ jsx29(Text27, { color: theme27.textSubtle, children: "state " }),
12747
- /* @__PURE__ */ jsx29(Text27, { color: theme27.textSubtle, children: promptShellModel.filePath })
12925
+ /* @__PURE__ */ jsx30(Text27, { color: theme28.textSubtle, children: "state " }),
12926
+ /* @__PURE__ */ jsx30(Text27, { color: theme28.textSubtle, children: promptShellModel.filePath })
12748
12927
  ] }),
12749
- promptShellModel?.metaLine && /* @__PURE__ */ jsx29(Box25, { marginTop: 1, children: /* @__PURE__ */ jsx29(Text27, { color: theme27.textSubtle, children: promptShellModel.metaLine }) }),
12750
- /* @__PURE__ */ jsx29(Box25, { marginTop: 1, children: /* @__PURE__ */ jsx29(Text27, { color: theme27.textSubtle, children: prompt.hint }) }),
12751
- /* @__PURE__ */ jsx29(Box25, { flexDirection: "column", marginTop: 1, children: prompt.choices.map((choice, index) => {
12928
+ promptShellModel?.metaLine && /* @__PURE__ */ jsx30(Box25, { marginTop: 1, children: /* @__PURE__ */ jsx30(Text27, { color: theme28.textSubtle, children: promptShellModel.metaLine }) }),
12929
+ /* @__PURE__ */ jsx30(Box25, { marginTop: 1, children: /* @__PURE__ */ jsx30(Text27, { color: theme28.textSubtle, children: prompt.hint }) }),
12930
+ /* @__PURE__ */ jsx30(Box25, { flexDirection: "column", marginTop: 1, children: prompt.choices.map((choice, index) => {
12752
12931
  const isSelected = index === selectedPromptIndex;
12753
12932
  return /* @__PURE__ */ jsxs23(Box25, { marginTop: index === 0 ? 0 : 1, children: [
12754
- /* @__PURE__ */ jsx29(Text27, { color: isSelected ? theme27.accent : theme27.textSubtle, bold: isSelected, children: isSelected ? "\u203A " : " " }),
12755
- /* @__PURE__ */ jsx29(Text27, { color: isSelected ? theme27.text : theme27.textSubtle, bold: isSelected, children: `${index + 1} ${choice.label}` })
12933
+ /* @__PURE__ */ jsx30(Text27, { color: isSelected ? theme28.accent : theme28.textSubtle, bold: isSelected, children: isSelected ? "\u203A " : " " }),
12934
+ /* @__PURE__ */ jsx30(Text27, { color: isSelected ? theme28.text : theme28.textSubtle, bold: isSelected, children: `${index + 1} ${choice.label}` })
12756
12935
  ] }, choice.value);
12757
12936
  }) }),
12758
- selectedChoice && /* @__PURE__ */ jsx29(Box25, { marginTop: 1, children: /* @__PURE__ */ jsx29(Text27, { color: theme27.textSubtle, children: selectedChoice.description }) }),
12759
- /* @__PURE__ */ jsx29(Box25, { marginTop: 1, children: /* @__PURE__ */ jsx29(Text27, { color: theme27.border, children: SCROLL_HINT }) })
12937
+ selectedChoice && /* @__PURE__ */ jsx30(Box25, { marginTop: 1, children: /* @__PURE__ */ jsx30(Text27, { color: theme28.textSubtle, children: selectedChoice.description }) }),
12938
+ /* @__PURE__ */ jsx30(Box25, { marginTop: 1, children: /* @__PURE__ */ jsx30(Text27, { color: theme28.border, children: SCROLL_HINT }) })
12760
12939
  ] })
12761
12940
  ] })
12762
12941
  }
@@ -14451,7 +14630,17 @@ function stateSafeName3(name) {
14451
14630
  var offloadCounter = 0;
14452
14631
  function offloadToolOutput(taskName, toolName, output, options = {}, stateDir) {
14453
14632
  const threshold = options.threshold ?? DEFAULT_OUTPUT_THRESHOLD;
14633
+ const warnThreshold = options.warnThreshold;
14454
14634
  const previewLength = options.previewLength ?? DEFAULT_PREVIEW_LENGTH;
14635
+ if (typeof warnThreshold === "number" && warnThreshold > 0 && output.length > warnThreshold && output.length <= threshold) {
14636
+ options.onEvent?.({
14637
+ kind: "warning",
14638
+ toolName,
14639
+ outputLength: output.length,
14640
+ threshold,
14641
+ warnThreshold
14642
+ });
14643
+ }
14455
14644
  if (output.length <= threshold) {
14456
14645
  return { offloaded: false, content: output };
14457
14646
  }
@@ -14473,6 +14662,14 @@ function offloadToolOutput(taskName, toolName, output, options = {}, stateDir) {
14473
14662
  "",
14474
14663
  "Use read_file to retrieve the full output if needed."
14475
14664
  ].join("\n");
14665
+ options.onEvent?.({
14666
+ kind: "offloaded",
14667
+ toolName,
14668
+ outputLength: output.length,
14669
+ threshold,
14670
+ warnThreshold,
14671
+ filePath
14672
+ });
14476
14673
  return { offloaded: true, content: reference, filePath };
14477
14674
  }
14478
14675
  function withOffloading(tool, taskName, toolName, options, stateDir) {
@@ -14487,6 +14684,147 @@ function withOffloading(tool, taskName, toolName, options, stateDir) {
14487
14684
  };
14488
14685
  }
14489
14686
 
14687
+ // src/marathon/model-context.ts
14688
+ var DEFAULT_AUTO_COMPACT_THRESHOLD_RATIO = 0.8;
14689
+ var DEFAULT_PROVIDER_NATIVE_COMPACT_THRESHOLD_RATIO = 0.9;
14690
+ var DEFAULT_OUTPUT_RESERVE_RATIO = 0.15;
14691
+ var MIN_OUTPUT_RESERVE_TOKENS = 8e3;
14692
+ var MAX_OUTPUT_RESERVE_TOKENS = 64e3;
14693
+ function normalizeModelId(value) {
14694
+ return value?.trim().toLowerCase().replace(/^model\//, "") ?? "";
14695
+ }
14696
+ function buildModelLookupCandidates(modelId) {
14697
+ const raw = modelId?.trim();
14698
+ if (!raw) return [];
14699
+ const candidates = /* @__PURE__ */ new Set();
14700
+ const push = (value) => {
14701
+ const normalized = normalizeModelId(value);
14702
+ if (normalized) {
14703
+ candidates.add(normalized);
14704
+ }
14705
+ };
14706
+ push(raw);
14707
+ if (raw.includes(":")) {
14708
+ const colonTail = raw.split(":").slice(1).join(":");
14709
+ push(colonTail);
14710
+ if (colonTail.includes("/")) {
14711
+ push(colonTail.split("/").slice(1).join("/"));
14712
+ push(colonTail.split("/").pop());
14713
+ }
14714
+ }
14715
+ if (raw.includes("/")) {
14716
+ push(raw.split("/").slice(1).join("/"));
14717
+ push(raw.split("/").pop());
14718
+ }
14719
+ return [...candidates];
14720
+ }
14721
+ function matchesModelIdentifier(sourceModelId, candidates) {
14722
+ const normalizedSource = normalizeModelId(sourceModelId);
14723
+ if (!normalizedSource) return false;
14724
+ return candidates.some((candidate) => normalizedSource === candidate || normalizedSource.endsWith(`/${candidate}`) || normalizedSource.endsWith(`:${candidate}`));
14725
+ }
14726
+ function extractAgentConfigModel(agent) {
14727
+ const config2 = agent?.config;
14728
+ if (!config2 || typeof config2 !== "object") return void 0;
14729
+ const model = config2.model;
14730
+ return typeof model === "string" && model.trim() ? model.trim() : void 0;
14731
+ }
14732
+ function findDefaultModelId(configuredModels) {
14733
+ return configuredModels.find((model) => model.isDefault)?.modelId;
14734
+ }
14735
+ function resolveModelProvider(modelId, configuredModels, availableModels) {
14736
+ const candidates = buildModelLookupCandidates(modelId);
14737
+ if (candidates.length === 0) return void 0;
14738
+ for (const configuredModel of configuredModels) {
14739
+ if (configuredModel.provider && matchesModelIdentifier(configuredModel.modelId, candidates)) {
14740
+ return configuredModel.provider;
14741
+ }
14742
+ }
14743
+ for (const availableModel of availableModels) {
14744
+ const providerMatch = availableModel.providers?.find((provider) => matchesModelIdentifier(provider.modelId, candidates) || matchesModelIdentifier(availableModel.baseModel, candidates));
14745
+ if (providerMatch?.provider) {
14746
+ return providerMatch.provider;
14747
+ }
14748
+ }
14749
+ const normalizedModelId = normalizeModelId(modelId);
14750
+ if (!normalizedModelId) return void 0;
14751
+ if (normalizedModelId.includes("claude") || normalizedModelId.includes("anthropic")) {
14752
+ return "anthropic";
14753
+ }
14754
+ if (normalizedModelId.startsWith("gpt-") || normalizedModelId.includes("openai") || normalizedModelId.startsWith("o1") || normalizedModelId.startsWith("o3") || normalizedModelId.startsWith("o4")) {
14755
+ return "openai";
14756
+ }
14757
+ return void 0;
14758
+ }
14759
+ function resolveDefaultCompactStrategy(modelId, configuredModels, availableModels) {
14760
+ const provider = resolveModelProvider(modelId, configuredModels, availableModels);
14761
+ return provider === "anthropic" ? "provider_native" : "summary_fallback";
14762
+ }
14763
+ function resolveOutputReserveTokens(modelContextLength) {
14764
+ if (typeof modelContextLength !== "number" || modelContextLength <= 0) {
14765
+ return void 0;
14766
+ }
14767
+ return Math.max(
14768
+ MIN_OUTPUT_RESERVE_TOKENS,
14769
+ Math.min(MAX_OUTPUT_RESERVE_TOKENS, Math.floor(modelContextLength * DEFAULT_OUTPUT_RESERVE_RATIO))
14770
+ );
14771
+ }
14772
+ function resolveEffectiveInputBudgetTokens(modelContextLength, reservedOutputTokens) {
14773
+ if (typeof modelContextLength !== "number" || modelContextLength <= 0) {
14774
+ return void 0;
14775
+ }
14776
+ const reserve = reservedOutputTokens ?? resolveOutputReserveTokens(modelContextLength) ?? 0;
14777
+ return Math.max(1, modelContextLength - reserve);
14778
+ }
14779
+ function resolveModelContextLength(modelId, configuredModels, availableModels) {
14780
+ const candidates = buildModelLookupCandidates(modelId);
14781
+ if (candidates.length === 0) return void 0;
14782
+ for (const configuredModel of configuredModels) {
14783
+ if (typeof configuredModel.contextLength === "number" && configuredModel.contextLength > 0 && matchesModelIdentifier(configuredModel.modelId, candidates)) {
14784
+ return configuredModel.contextLength;
14785
+ }
14786
+ }
14787
+ for (const availableModel of availableModels) {
14788
+ if (typeof availableModel.contextLength !== "number" || availableModel.contextLength <= 0) {
14789
+ continue;
14790
+ }
14791
+ if (matchesModelIdentifier(availableModel.baseModel, candidates)) {
14792
+ return availableModel.contextLength;
14793
+ }
14794
+ if (availableModel.providers?.some(
14795
+ (provider) => matchesModelIdentifier(provider.modelId, candidates)
14796
+ )) {
14797
+ return availableModel.contextLength;
14798
+ }
14799
+ }
14800
+ return void 0;
14801
+ }
14802
+ function resolveAutoCompactTokenThreshold(modelContextLength, rawThreshold, strategy = "summary_fallback") {
14803
+ const effectiveBudget = resolveEffectiveInputBudgetTokens(modelContextLength);
14804
+ const trimmed = rawThreshold?.trim();
14805
+ if (!trimmed) {
14806
+ const ratio = strategy === "provider_native" ? DEFAULT_PROVIDER_NATIVE_COMPACT_THRESHOLD_RATIO : DEFAULT_AUTO_COMPACT_THRESHOLD_RATIO;
14807
+ return typeof effectiveBudget === "number" && effectiveBudget > 0 ? Math.max(1, Math.floor(effectiveBudget * ratio)) : void 0;
14808
+ }
14809
+ const percentMatch = trimmed.match(/^(\d+(?:\.\d+)?)%$/);
14810
+ if (percentMatch) {
14811
+ const percentValue = Number(percentMatch[1]);
14812
+ if (!Number.isFinite(percentValue) || percentValue <= 0 || percentValue > 100) {
14813
+ throw new Error(
14814
+ `Invalid --compact-threshold value "${rawThreshold}". Use a percentage (e.g. 80%) or absolute token count (e.g. 120000).`
14815
+ );
14816
+ }
14817
+ return typeof effectiveBudget === "number" && effectiveBudget > 0 ? Math.max(1, Math.floor(effectiveBudget * (percentValue / 100))) : void 0;
14818
+ }
14819
+ const numericValue = Number(trimmed);
14820
+ if (!Number.isFinite(numericValue) || numericValue <= 0) {
14821
+ throw new Error(
14822
+ `Invalid --compact-threshold value "${rawThreshold}". Use a percentage (e.g. 80%) or absolute token count (e.g. 120000).`
14823
+ );
14824
+ }
14825
+ return Math.max(1, Math.floor(numericValue));
14826
+ }
14827
+
14490
14828
  // src/marathon/recipes.ts
14491
14829
  import * as fs10 from "fs";
14492
14830
  import * as path9 from "path";
@@ -14631,6 +14969,80 @@ function buildResumeHistoryWarning(state) {
14631
14969
  function canUseMarathonStartupShell(options) {
14632
14970
  return process.stdin.isTTY === true && process.stdout.isTTY === true && !options.json;
14633
14971
  }
14972
+ function normalizeStartupModelOptionValue(value) {
14973
+ const trimmed = value?.trim().toLowerCase().replace(/^model\//, "") ?? "";
14974
+ if (!trimmed) return "";
14975
+ const withoutProvider = trimmed.includes(":") ? trimmed.split(":").slice(1).join(":") : trimmed;
14976
+ if (withoutProvider.includes("/")) {
14977
+ return withoutProvider.split("/").pop() ?? withoutProvider;
14978
+ }
14979
+ return withoutProvider;
14980
+ }
14981
+ function formatModelGroup(provider, fallbackValue) {
14982
+ const normalized = provider?.trim().toLowerCase() || normalizeStartupModelOptionValue(fallbackValue).split("-")[0];
14983
+ switch (normalized) {
14984
+ case "anthropic":
14985
+ return "Anthropic";
14986
+ case "openai":
14987
+ return "OpenAI";
14988
+ case "google":
14989
+ return "Google";
14990
+ case "xai":
14991
+ return "xAI";
14992
+ case "qwen":
14993
+ return "Qwen";
14994
+ case "deepseek":
14995
+ return "DeepSeek";
14996
+ case "mistral":
14997
+ return "Mistral";
14998
+ case "meta":
14999
+ return "Meta";
15000
+ default:
15001
+ return "Other";
15002
+ }
15003
+ }
15004
+ function buildMarathonStartupModelOptions(configuredModels, availableModels) {
15005
+ const options = [];
15006
+ const seen = /* @__PURE__ */ new Set();
15007
+ const pushOption = (option) => {
15008
+ if (!option) return;
15009
+ const normalizedValue = normalizeStartupModelOptionValue(option.value);
15010
+ if (!normalizedValue || seen.has(normalizedValue)) return;
15011
+ seen.add(normalizedValue);
15012
+ options.push(option);
15013
+ };
15014
+ for (const model of configuredModels) {
15015
+ const modelId = model.modelId?.trim();
15016
+ if (!modelId) continue;
15017
+ pushOption({
15018
+ label: model.displayName?.trim() || modelId,
15019
+ value: modelId,
15020
+ group: formatModelGroup(model.provider, modelId)
15021
+ });
15022
+ }
15023
+ for (const model of availableModels) {
15024
+ if (Array.isArray(model.providers) && model.providers.length > 0) {
15025
+ for (const provider of model.providers) {
15026
+ const modelId2 = provider.modelId?.trim() || model.baseModel?.trim();
15027
+ if (!modelId2) continue;
15028
+ pushOption({
15029
+ label: provider.displayName?.trim() || model.displayName?.trim() || model.baseModel?.trim() || modelId2,
15030
+ value: modelId2,
15031
+ group: formatModelGroup(provider.provider, modelId2)
15032
+ });
15033
+ }
15034
+ continue;
15035
+ }
15036
+ const modelId = model.baseModel?.trim();
15037
+ if (!modelId) continue;
15038
+ pushOption({
15039
+ label: model.displayName?.trim() || modelId,
15040
+ value: modelId,
15041
+ group: formatModelGroup(void 0, modelId)
15042
+ });
15043
+ }
15044
+ return options;
15045
+ }
14634
15046
  function buildMarathonClientHeaders(devPlanOverride) {
14635
15047
  const cliVersion = getCliVersion();
14636
15048
  return {
@@ -14641,6 +15053,42 @@ function buildMarathonClientHeaders(devPlanOverride) {
14641
15053
  ...devPlanOverride ? { "X-Dev-Plan-Override": devPlanOverride } : {}
14642
15054
  };
14643
15055
  }
15056
+ var DEFAULT_TOOL_OUTPUT_WARNING_CHARS = 4e4;
15057
+ var DEFAULT_TOOL_OUTPUT_OFFLOAD_CHARS = 1e5;
15058
+ function parseCompactStrategy(value) {
15059
+ if (!value) return void 0;
15060
+ const normalized = value.trim().toLowerCase();
15061
+ if (normalized === "auto" || normalized === "provider_native" || normalized === "summary_fallback") {
15062
+ return normalized;
15063
+ }
15064
+ throw new Error(
15065
+ `Invalid --compact-strategy value "${value}". Use auto, provider_native, or summary_fallback.`
15066
+ );
15067
+ }
15068
+ function resolveToolOutputGuardrails(rawThreshold) {
15069
+ if (!rawThreshold || rawThreshold.trim() === "") {
15070
+ return {
15071
+ warnThreshold: DEFAULT_TOOL_OUTPUT_WARNING_CHARS,
15072
+ threshold: DEFAULT_TOOL_OUTPUT_OFFLOAD_CHARS
15073
+ };
15074
+ }
15075
+ const normalized = rawThreshold.trim().toLowerCase();
15076
+ if (normalized === "0" || normalized === "off" || normalized === "false") {
15077
+ return false;
15078
+ }
15079
+ const numericValue = Number(rawThreshold);
15080
+ if (!Number.isFinite(numericValue) || numericValue <= 0) {
15081
+ throw new Error(
15082
+ `Invalid --offload-threshold value "${rawThreshold}". Use a positive number of characters, "0", or "off".`
15083
+ );
15084
+ }
15085
+ const threshold = Math.max(1, Math.floor(numericValue));
15086
+ const warnThreshold = threshold <= 1 ? void 0 : threshold > DEFAULT_TOOL_OUTPUT_WARNING_CHARS ? DEFAULT_TOOL_OUTPUT_WARNING_CHARS : Math.max(1, Math.floor(threshold * 0.8));
15087
+ return {
15088
+ warnThreshold,
15089
+ threshold
15090
+ };
15091
+ }
14644
15092
  async function taskAction(agent, options) {
14645
15093
  if (!options.resume && !options.goal) {
14646
15094
  console.error(chalk16.red("Error: -g, --goal <text> is required for new tasks"));
@@ -14660,6 +15108,13 @@ async function taskAction(agent, options) {
14660
15108
  console.error(chalk16.red(`Invalid --sandbox value "${options.sandbox}". Use: cloudflare-worker, quickjs, or daytona`));
14661
15109
  process.exit(1);
14662
15110
  }
15111
+ let requestedCompactStrategy;
15112
+ try {
15113
+ requestedCompactStrategy = parseCompactStrategy(options.compactStrategy);
15114
+ } catch (error) {
15115
+ console.error(chalk16.red(error instanceof Error ? error.message : String(error)));
15116
+ process.exit(1);
15117
+ }
14663
15118
  let recipe = null;
14664
15119
  if (options.recipe) {
14665
15120
  recipe = loadRecipe(options.recipe);
@@ -14693,8 +15148,15 @@ async function taskAction(agent, options) {
14693
15148
  if (resolvedToolIds.length > 0) {
14694
15149
  console.log(chalk16.cyan(`Built-in tools: ${resolvedToolIds.join(", ")}`));
14695
15150
  }
14696
- const offloadOptions = options.offloadThreshold ? { threshold: parseInt(options.offloadThreshold, 10) || 2e3 } : void 0;
14697
- const useStartupShell = canUseMarathonStartupShell(options);
15151
+ let offloadOptions;
15152
+ try {
15153
+ const guardrails = resolveToolOutputGuardrails(options.offloadThreshold);
15154
+ offloadOptions = guardrails === false ? void 0 : guardrails;
15155
+ } catch (error) {
15156
+ console.error(chalk16.red(error instanceof Error ? error.message : String(error)));
15157
+ process.exit(1);
15158
+ }
15159
+ const useStartupShell = canUseMarathonStartupShell(options);
14698
15160
  const streamRef = { current: null };
14699
15161
  const startupShellRef = { current: null };
14700
15162
  let waitForUiExit;
@@ -14789,6 +15251,26 @@ async function taskAction(agent, options) {
14789
15251
  ]);
14790
15252
  }
14791
15253
  }
15254
+ let agentConfigModel;
15255
+ let defaultConfiguredModel;
15256
+ let configuredModels = [];
15257
+ let availableModels = [];
15258
+ const modelMetadataResults = await Promise.allSettled([
15259
+ client.agents.get(agentId),
15260
+ client.modelConfigs.list(),
15261
+ client.modelConfigs.getAvailable()
15262
+ ]);
15263
+ const [agentResult, configuredModelsResult, availableModelsResult] = modelMetadataResults;
15264
+ if (agentResult.status === "fulfilled") {
15265
+ agentConfigModel = extractAgentConfigModel(agentResult.value);
15266
+ }
15267
+ if (configuredModelsResult.status === "fulfilled") {
15268
+ configuredModels = configuredModelsResult.value;
15269
+ defaultConfiguredModel = findDefaultModelId(configuredModels);
15270
+ }
15271
+ if (availableModelsResult.status === "fulfilled") {
15272
+ availableModels = availableModelsResult.value;
15273
+ }
14792
15274
  let taskName = options.session || options.name || agentId;
14793
15275
  let filePath = stateFilePath(taskName, options.stateDir);
14794
15276
  const maxSessions = parseInt(options.maxSessions, 10);
@@ -14927,6 +15409,37 @@ async function taskAction(agent, options) {
14927
15409
  }
14928
15410
  }
14929
15411
  }
15412
+ if (useStartupShell && !options.model?.trim()) {
15413
+ const startupModelOptions = buildMarathonStartupModelOptions(configuredModels, availableModels);
15414
+ const initialStartupModel = agentConfigModel || defaultConfiguredModel || startupModelOptions[0]?.value;
15415
+ if (startupModelOptions.length > 0 && initialStartupModel && startupShellRef.current) {
15416
+ setStartupStatus("selecting model");
15417
+ options.model = await startupShellRef.current.requestModelChoice(
15418
+ initialStartupModel,
15419
+ startupModelOptions
15420
+ );
15421
+ setStartupStatus(`model ready: ${options.model}`);
15422
+ }
15423
+ }
15424
+ try {
15425
+ const validationStrategy = options.compact ? "summary_fallback" : requestedCompactStrategy && requestedCompactStrategy !== "auto" ? requestedCompactStrategy : resolveDefaultCompactStrategy(
15426
+ options.model || agentConfigModel || defaultConfiguredModel,
15427
+ configuredModels,
15428
+ availableModels
15429
+ );
15430
+ resolveAutoCompactTokenThreshold(
15431
+ resolveModelContextLength(
15432
+ options.model || agentConfigModel || defaultConfiguredModel,
15433
+ configuredModels,
15434
+ availableModels
15435
+ ),
15436
+ options.compactThreshold,
15437
+ validationStrategy
15438
+ );
15439
+ } catch (error) {
15440
+ const message = error instanceof Error ? error.message : String(error);
15441
+ await failBeforeMain([chalk16.red(message)]);
15442
+ }
14930
15443
  const remainingSessions = maxSessions - priorSessionCount;
14931
15444
  const remainingCost = maxCost ? maxCost - priorCost : void 0;
14932
15445
  const baseMessage = options.goal || (resumeRequested ? "Continue the task." : "");
@@ -14953,15 +15466,55 @@ ${rulesContext}`;
14953
15466
  taskName,
14954
15467
  stateDir: options.stateDir
14955
15468
  });
15469
+ const resolveContextLimitForModel = (modelId) => resolveModelContextLength(modelId, configuredModels, availableModels);
15470
+ const resolveCompactStrategyForModel = (modelId) => {
15471
+ if (options.compact) return "summary_fallback";
15472
+ if (requestedCompactStrategy && requestedCompactStrategy !== "auto") {
15473
+ return requestedCompactStrategy === "provider_native" ? resolveDefaultCompactStrategy(modelId, configuredModels, availableModels) === "provider_native" ? "provider_native" : "summary_fallback" : "summary_fallback";
15474
+ }
15475
+ return resolveDefaultCompactStrategy(modelId, configuredModels, availableModels);
15476
+ };
15477
+ const resolveCompactThresholdForModel = (modelId) => {
15478
+ if (options.autoCompact === false) return void 0;
15479
+ const contextLength = resolveContextLimitForModel(modelId);
15480
+ return resolveAutoCompactTokenThreshold(
15481
+ contextLength,
15482
+ options.compactThreshold,
15483
+ resolveCompactStrategyForModel(modelId)
15484
+ );
15485
+ };
15486
+ const reportContextNotice = (event) => {
15487
+ streamRef.current?.reportContextNotice(event);
15488
+ };
14956
15489
  if (localTools && offloadOptions) {
14957
15490
  const toolNames = Object.keys(localTools);
14958
15491
  for (const toolName of toolNames) {
14959
- if (toolName === "search_repo" || toolName === "read_file" || toolName === "glob_files") {
15492
+ if (toolName === "search_repo" || toolName === "read_file" || toolName === "glob_files" || toolName === "tree_directory" || toolName === "list_directory") {
14960
15493
  localTools[toolName] = withOffloading(
14961
15494
  localTools[toolName],
14962
15495
  taskName,
14963
15496
  toolName,
14964
- offloadOptions,
15497
+ {
15498
+ ...offloadOptions,
15499
+ onEvent: (event) => {
15500
+ if (event.kind === "warning") {
15501
+ reportContextNotice({
15502
+ kind: "tool_output_warning",
15503
+ message: `${event.toolName} returned ${Math.ceil(event.outputLength / 4).toLocaleString()} estimated tokens of output. Consider narrowing the query or reading a smaller slice.`,
15504
+ toolName: event.toolName,
15505
+ outputLength: event.outputLength
15506
+ });
15507
+ return;
15508
+ }
15509
+ reportContextNotice({
15510
+ kind: "tool_output_offloaded",
15511
+ message: `${event.toolName} returned ${Math.ceil(event.outputLength / 4).toLocaleString()} estimated tokens and was offloaded ${event.filePath ? `to ${event.filePath}` : "to a file"} to protect the context window.`,
15512
+ toolName: event.toolName,
15513
+ outputLength: event.outputLength,
15514
+ filePath: event.filePath
15515
+ });
15516
+ }
15517
+ },
14965
15518
  options.stateDir
14966
15519
  );
14967
15520
  }
@@ -15002,7 +15555,7 @@ ${rulesContext}`;
15002
15555
  const marathonAppProps = {
15003
15556
  taskName,
15004
15557
  agentId,
15005
- model: options.model,
15558
+ model: options.model || agentConfigModel || defaultConfiguredModel,
15006
15559
  sandbox: parsedSandbox,
15007
15560
  goal: baseMessage,
15008
15561
  initialSessionCount: priorSessionCount,
@@ -15146,6 +15699,12 @@ Saving state... done. Session saved to ${filePath}`);
15146
15699
  defaultModel: options.model
15147
15700
  }
15148
15701
  );
15702
+ const effectiveModelForContext = phaseModel || options.model || agentConfigModel || defaultConfiguredModel;
15703
+ const compactStrategy = resolveCompactStrategyForModel(effectiveModelForContext);
15704
+ const contextLimitTokens = resolveContextLimitForModel(effectiveModelForContext);
15705
+ const autoCompactTokenThreshold = resolveCompactThresholdForModel(
15706
+ effectiveModelForContext
15707
+ );
15149
15708
  const runTaskOptions = {
15150
15709
  message: taskMessage,
15151
15710
  maxSessions: remainingSessions - accumulatedSessions,
@@ -15164,6 +15723,34 @@ Saving state... done. Session saved to ${filePath}`);
15164
15723
  continuationMessage,
15165
15724
  compact: useCompact
15166
15725
  } : {},
15726
+ ...autoCompactTokenThreshold ? { autoCompactTokenThreshold } : {},
15727
+ ...contextLimitTokens ? { contextLimitTokens } : {},
15728
+ compactStrategy,
15729
+ ...options.compactInstructions ? { compactInstructions: options.compactInstructions } : {},
15730
+ onContextCompaction: async (event) => {
15731
+ const currentActions = streamRef.current;
15732
+ if (!currentActions) return;
15733
+ const absoluteEvent = {
15734
+ ...event,
15735
+ sessionIndex: currentSessionOffset + event.sessionIndex,
15736
+ model: event.model || effectiveModelForContext
15737
+ };
15738
+ if (event.phase === "start") {
15739
+ currentActions.startContextCompaction(absoluteEvent);
15740
+ await new Promise((resolve6) => setTimeout(resolve6, 0));
15741
+ return;
15742
+ }
15743
+ currentActions.finishContextCompaction(absoluteEvent);
15744
+ },
15745
+ onContextNotice: async (event) => {
15746
+ const currentActions = streamRef.current;
15747
+ if (!currentActions) return;
15748
+ currentActions.reportContextNotice({
15749
+ ...event,
15750
+ sessionIndex: typeof event.sessionIndex === "number" ? currentSessionOffset + event.sessionIndex : void 0,
15751
+ model: event.model || effectiveModelForContext
15752
+ });
15753
+ },
15167
15754
  ...resumeState ? { resumeState } : {},
15168
15755
  toolContextMode: options.toolContext || "hot-tail",
15169
15756
  toolWindow: options.toolWindow === "session" || !options.toolWindow ? "session" : parseInt(options.toolWindow, 10) || 10,
@@ -15592,7 +16179,7 @@ function detectDeployWorkflow(message, sandboxProvider, resumeState) {
15592
16179
  return void 0;
15593
16180
  }
15594
16181
  function applyTaskOptions(cmd) {
15595
- return cmd.argument("<agent>", "Agent ID or name").option("-g, --goal <text>", "Goal message for the agent").option("--max-sessions <n>", "Maximum sessions", "50").option("--max-cost <n>", "Budget in USD").option("--model <modelId>", "Model ID to use (overrides agent config)").option("--name <name>", "Task name (used for state file, defaults to agent name)").option("--session <name>", "Resume a specific session by name").option("--state-dir <path>", "Directory for state files (default: ~/.runtype/projects/<hash>/marathons/)").option("--resume [message]", "Resume from existing local state, optionally with a new message").option("--fresh", "Start a new run and ignore any existing local state for this task").option("--compact", "Use compact summary instead of full history on resume").option("--track", "Sync progress to a Runtype record (visible in dashboard)").option("--debug", "Show debug output from each session").option("--json", "Output final result as JSON").option("--sandbox <provider>", "Enable sandbox code execution tool (cloudflare-worker, quickjs, or daytona)").option("--no-local-tools", "Disable built-in local tool execution (read_file, write_file, list_directory)").option("-t, --tools <tools...>", "Enable built-in tools (e.g., exa, firecrawl, dalle, openai_web_search, anthropic_web_search)").option("--plain-text", "Disable markdown rendering in output").option("--no-steer", "Run all iterations without steering pauses (fully autonomous)").option("--steer-timeout <seconds>", "Auto-continue timeout in seconds (default: 10)", "10").option("--planning-model <modelId>", "Model to use during research/planning phases").option("--execution-model <modelId>", "Model to use during execution phase").option("--recipe <name>", "Load a workflow recipe from .marathon/recipes/").option("--offload-threshold <chars>", "Offload tool outputs larger than this to files (default: disabled)").option("--tool-context <mode>", "Tool result storage: hot-tail (default), observation-mask, or full-inline").option("--tool-window <window>", 'Compaction window: "session" (default) or a number for last-N tool results (e.g. 10)').option("--runner-char <char>", "Custom runner emoji (default: \u{1F3C3})").option("--finish-char <char>", "Custom finish line emoji (default: \u{1F3C1})").option("--no-runner", "Hide the runner emoji from the header border").option("--no-finish", "Hide the finish line emoji from the header border").action(taskAction);
16182
+ return cmd.argument("<agent>", "Agent ID or name").option("-g, --goal <text>", "Goal message for the agent").option("--max-sessions <n>", "Maximum sessions", "50").option("--max-cost <n>", "Budget in USD").option("--model <modelId>", "Model ID to use (overrides agent config)").option("--name <name>", "Task name (used for state file, defaults to agent name)").option("--session <name>", "Resume a specific session by name").option("--state-dir <path>", "Directory for state files (default: ~/.runtype/projects/<hash>/marathons/)").option("--resume [message]", "Resume from existing local state, optionally with a new message").option("--fresh", "Start a new run and ignore any existing local state for this task").option("--compact", "Force compact-summary resume mode instead of replaying full history").option("--compact-strategy <strategy>", "Compaction strategy: auto (default), provider_native, or summary_fallback").option("--compact-threshold <value>", "Auto-compact when estimated context crosses this threshold (default: 80% fallback, 90% native; accepts percent like 90% or absolute token count like 120000)").option("--compact-instructions <text>", "Extra instructions for what a compact summary must preserve").option("--no-auto-compact", "Disable automatic context-aware history compaction").option("--track", "Sync progress to a Runtype record (visible in dashboard)").option("--debug", "Show debug output from each session").option("--json", "Output final result as JSON").option("--sandbox <provider>", "Enable sandbox code execution tool (cloudflare-worker, quickjs, or daytona)").option("--no-local-tools", "Disable built-in local tool execution (read_file, write_file, list_directory)").option("-t, --tools <tools...>", "Enable built-in tools (e.g., exa, firecrawl, dalle, openai_web_search, anthropic_web_search)").option("--plain-text", "Disable markdown rendering in output").option("--no-steer", "Run all iterations without steering pauses (fully autonomous)").option("--steer-timeout <seconds>", "Auto-continue timeout in seconds (default: 10)", "10").option("--planning-model <modelId>", "Model to use during research/planning phases").option("--execution-model <modelId>", "Model to use during execution phase").option("--recipe <name>", "Load a workflow recipe from .marathon/recipes/").option("--offload-threshold <chars>", 'Offload tool outputs larger than this to files (default: 100000; use "off" or "0" to disable guardrails)').option("--tool-context <mode>", "Tool result storage: hot-tail (default), observation-mask, or full-inline").option("--tool-window <window>", 'Compaction window: "session" (default) or a number for last-N tool results (e.g. 10)').option("--runner-char <char>", "Custom runner emoji (default: \u{1F3C3})").option("--finish-char <char>", "Custom finish line emoji (default: \u{1F3C1})").option("--no-runner", "Hide the runner emoji from the header border").option("--no-finish", "Hide the finish line emoji from the header border").action(taskAction);
15596
16183
  }
15597
16184
  var taskCommand = applyTaskOptions(
15598
16185
  new Command10("task").description("Run a multi-session agent task")
@@ -15642,10 +16229,10 @@ agentsCommand.command("list").description("List all agents").option("--json", "O
15642
16229
  return;
15643
16230
  }
15644
16231
  const App = () => {
15645
- const [items, setItems] = useState22(null);
15646
- const [error, setError] = useState22(null);
15647
- const [total, setTotal] = useState22();
15648
- useEffect20(() => {
16232
+ const [items, setItems] = useState23(null);
16233
+ const [error, setError] = useState23(null);
16234
+ const [total, setTotal] = useState23();
16235
+ useEffect22(() => {
15649
16236
  client.get("/agents", { limit: options.limit }).then((res) => {
15650
16237
  setItems(res.data ?? []);
15651
16238
  setTotal(getTotalCount(res.pagination));
@@ -15703,9 +16290,9 @@ agentsCommand.command("get <id>").description("Get agent details").option("--jso
15703
16290
  return;
15704
16291
  }
15705
16292
  const App = () => {
15706
- const [items, setItems] = useState22(null);
15707
- const [error, setError] = useState22(null);
15708
- useEffect20(() => {
16293
+ const [items, setItems] = useState23(null);
16294
+ const [error, setError] = useState23(null);
16295
+ useEffect22(() => {
15709
16296
  client.get(`/agents/${id}`).then((res) => setItems([res])).catch((err) => setError(err instanceof Error ? err : new Error(String(err))));
15710
16297
  }, []);
15711
16298
  return React10.createElement(DataList, {
@@ -15755,11 +16342,11 @@ agentsCommand.command("create").description("Create a new agent").requiredOption
15755
16342
  return;
15756
16343
  }
15757
16344
  const App = () => {
15758
- const [loading, setLoading] = useState22(true);
15759
- const [success, setSuccess] = useState22(null);
15760
- const [error, setError] = useState22(null);
15761
- const [result, setResult] = useState22(null);
15762
- useEffect20(() => {
16345
+ const [loading, setLoading] = useState23(true);
16346
+ const [success, setSuccess] = useState23(null);
16347
+ const [error, setError] = useState23(null);
16348
+ const [result, setResult] = useState23(null);
16349
+ useEffect22(() => {
15763
16350
  client.post("/agents", {
15764
16351
  name: options.name,
15765
16352
  description: options.description
@@ -15806,11 +16393,11 @@ agentsCommand.command("delete <id>").description("Delete an agent").option("--tt
15806
16393
  return;
15807
16394
  }
15808
16395
  const App = () => {
15809
- const [confirmed, setConfirmed] = useState22(null);
15810
- const [loading, setLoading] = useState22(false);
15811
- const [success, setSuccess] = useState22(null);
15812
- const [error, setError] = useState22(null);
15813
- useEffect20(() => {
16396
+ const [confirmed, setConfirmed] = useState23(null);
16397
+ const [loading, setLoading] = useState23(false);
16398
+ const [success, setSuccess] = useState23(null);
16399
+ const [error, setError] = useState23(null);
16400
+ useEffect22(() => {
15814
16401
  if (confirmed !== true) return void 0;
15815
16402
  setLoading(true);
15816
16403
  client.delete(`/agents/${id}`).then(() => {
@@ -15900,7 +16487,7 @@ import { Command as Command12 } from "commander";
15900
16487
  import chalk18 from "chalk";
15901
16488
  import React11 from "react";
15902
16489
  import { render as render11 } from "ink";
15903
- import { useState as useState23, useEffect as useEffect21 } from "react";
16490
+ import { useState as useState24, useEffect as useEffect23 } from "react";
15904
16491
  var modelsCommand = new Command12("models").description("Manage model configurations");
15905
16492
  modelsCommand.command("list").description("List your enabled model configurations").option("--json", "Output as JSON").option("--tty", "Force TTY mode").option("--no-tty", "Force non-TTY mode").action(async (options) => {
15906
16493
  const apiKey = await ensureAuth();
@@ -15937,10 +16524,10 @@ modelsCommand.command("list").description("List your enabled model configuration
15937
16524
  return;
15938
16525
  }
15939
16526
  const App = () => {
15940
- const [items, setItems] = useState23(null);
15941
- const [error, setError] = useState23(null);
15942
- const [total, setTotal] = useState23();
15943
- useEffect21(() => {
16527
+ const [items, setItems] = useState24(null);
16528
+ const [error, setError] = useState24(null);
16529
+ const [total, setTotal] = useState24();
16530
+ useEffect23(() => {
15944
16531
  client.get("/model-configs").then((res) => {
15945
16532
  setItems(res.data ?? []);
15946
16533
  setTotal(getTotalCount(res.pagination));
@@ -16002,9 +16589,9 @@ modelsCommand.command("available").description("List all available models groupe
16002
16589
  return;
16003
16590
  }
16004
16591
  const App = () => {
16005
- const [items, setItems] = useState23(null);
16006
- const [error, setError] = useState23(null);
16007
- useEffect21(() => {
16592
+ const [items, setItems] = useState24(null);
16593
+ const [error, setError] = useState24(null);
16594
+ useEffect23(() => {
16008
16595
  client.get("/model-configs/grouped").then((res) => setItems(res.data ?? [])).catch((err) => setError(err instanceof Error ? err : new Error(String(err))));
16009
16596
  }, []);
16010
16597
  return React11.createElement(DataList, {
@@ -16050,11 +16637,11 @@ modelsCommand.command("enable <modelId>").description("Enable a model by creatin
16050
16637
  return;
16051
16638
  }
16052
16639
  const App = () => {
16053
- const [loading, setLoading] = useState23(true);
16054
- const [success, setSuccess] = useState23(null);
16055
- const [error, setError] = useState23(null);
16056
- const [result, setResult] = useState23(null);
16057
- useEffect21(() => {
16640
+ const [loading, setLoading] = useState24(true);
16641
+ const [success, setSuccess] = useState24(null);
16642
+ const [error, setError] = useState24(null);
16643
+ const [result, setResult] = useState24(null);
16644
+ useEffect23(() => {
16058
16645
  client.post("/model-configs", { modelId }).then((data) => {
16059
16646
  setResult(data);
16060
16647
  setSuccess(true);
@@ -16098,10 +16685,10 @@ modelsCommand.command("disable <id>").description("Disable a model configuration
16098
16685
  return;
16099
16686
  }
16100
16687
  const App = () => {
16101
- const [loading, setLoading] = useState23(true);
16102
- const [success, setSuccess] = useState23(null);
16103
- const [error, setError] = useState23(null);
16104
- useEffect21(() => {
16688
+ const [loading, setLoading] = useState24(true);
16689
+ const [success, setSuccess] = useState24(null);
16690
+ const [error, setError] = useState24(null);
16691
+ useEffect23(() => {
16105
16692
  client.patch(`/model-configs/${id}/status`, { enabled: false }).then(() => {
16106
16693
  setSuccess(true);
16107
16694
  setLoading(false);
@@ -16138,10 +16725,10 @@ modelsCommand.command("default <id>").description("Set a model configuration as
16138
16725
  return;
16139
16726
  }
16140
16727
  const App = () => {
16141
- const [loading, setLoading] = useState23(true);
16142
- const [success, setSuccess] = useState23(null);
16143
- const [error, setError] = useState23(null);
16144
- useEffect21(() => {
16728
+ const [loading, setLoading] = useState24(true);
16729
+ const [success, setSuccess] = useState24(null);
16730
+ const [error, setError] = useState24(null);
16731
+ useEffect23(() => {
16145
16732
  client.patch(`/model-configs/${id}/default`, {}).then(() => {
16146
16733
  setSuccess(true);
16147
16734
  setLoading(false);
@@ -16182,7 +16769,7 @@ import { Command as Command13 } from "commander";
16182
16769
  import chalk19 from "chalk";
16183
16770
  import React12 from "react";
16184
16771
  import { render as render12 } from "ink";
16185
- import { useState as useState24, useEffect as useEffect22 } from "react";
16772
+ import { useState as useState25, useEffect as useEffect24 } from "react";
16186
16773
  var schedulesCommand = new Command13("schedules").description("Manage schedules");
16187
16774
  schedulesCommand.command("list").description("List all schedules").option("--json", "Output as JSON").option("--tty", "Force TTY mode").option("--no-tty", "Force non-TTY mode").action(async (options) => {
16188
16775
  const apiKey = await ensureAuth();
@@ -16226,10 +16813,10 @@ schedulesCommand.command("list").description("List all schedules").option("--jso
16226
16813
  return;
16227
16814
  }
16228
16815
  const App = () => {
16229
- const [items, setItems] = useState24(null);
16230
- const [error, setError] = useState24(null);
16231
- const [total, setTotal] = useState24();
16232
- useEffect22(() => {
16816
+ const [items, setItems] = useState25(null);
16817
+ const [error, setError] = useState25(null);
16818
+ const [total, setTotal] = useState25();
16819
+ useEffect24(() => {
16233
16820
  client.get("/schedules").then((res) => {
16234
16821
  setItems(res.data ?? []);
16235
16822
  setTotal(getTotalCount(res.pagination));
@@ -16292,9 +16879,9 @@ schedulesCommand.command("get <id>").description("Get schedule details").option(
16292
16879
  return;
16293
16880
  }
16294
16881
  const App = () => {
16295
- const [items, setItems] = useState24(null);
16296
- const [error, setError] = useState24(null);
16297
- useEffect22(() => {
16882
+ const [items, setItems] = useState25(null);
16883
+ const [error, setError] = useState25(null);
16884
+ useEffect24(() => {
16298
16885
  client.get(`/schedules/${id}`).then((res) => setItems([res])).catch((err) => setError(err instanceof Error ? err : new Error(String(err))));
16299
16886
  }, []);
16300
16887
  return React12.createElement(DataList, {
@@ -16348,11 +16935,11 @@ schedulesCommand.command("create").description("Create a new schedule").required
16348
16935
  return;
16349
16936
  }
16350
16937
  const App = () => {
16351
- const [loading, setLoading] = useState24(true);
16352
- const [success, setSuccess] = useState24(null);
16353
- const [error, setError] = useState24(null);
16354
- const [result, setResult] = useState24(null);
16355
- useEffect22(() => {
16938
+ const [loading, setLoading] = useState25(true);
16939
+ const [success, setSuccess] = useState25(null);
16940
+ const [error, setError] = useState25(null);
16941
+ const [result, setResult] = useState25(null);
16942
+ useEffect24(() => {
16356
16943
  client.post("/schedules", {
16357
16944
  flowId: options.flow,
16358
16945
  cronExpression: options.cron,
@@ -16403,10 +16990,10 @@ function simpleMutationCommand(name, description, mutationFn, successMsg, loadin
16403
16990
  return;
16404
16991
  }
16405
16992
  const App = () => {
16406
- const [loading, setLoading] = useState24(true);
16407
- const [success, setSuccess] = useState24(null);
16408
- const [error, setError] = useState24(null);
16409
- useEffect22(() => {
16993
+ const [loading, setLoading] = useState25(true);
16994
+ const [success, setSuccess] = useState25(null);
16995
+ const [error, setError] = useState25(null);
16996
+ useEffect24(() => {
16410
16997
  mutationFn(client, id).then(() => {
16411
16998
  setSuccess(true);
16412
16999
  setLoading(false);
@@ -16465,11 +17052,11 @@ schedulesCommand.command("delete <id>").description("Delete a schedule").option(
16465
17052
  return;
16466
17053
  }
16467
17054
  const App = () => {
16468
- const [confirmed, setConfirmed] = useState24(null);
16469
- const [loading, setLoading] = useState24(false);
16470
- const [success, setSuccess] = useState24(null);
16471
- const [error, setError] = useState24(null);
16472
- useEffect22(() => {
17055
+ const [confirmed, setConfirmed] = useState25(null);
17056
+ const [loading, setLoading] = useState25(false);
17057
+ const [success, setSuccess] = useState25(null);
17058
+ const [error, setError] = useState25(null);
17059
+ useEffect24(() => {
16473
17060
  if (confirmed !== true) return void 0;
16474
17061
  setLoading(true);
16475
17062
  client.delete(`/schedules/${id}`).then(() => {
@@ -16513,7 +17100,7 @@ import { Command as Command14 } from "commander";
16513
17100
  import chalk20 from "chalk";
16514
17101
  import React13 from "react";
16515
17102
  import { render as render13 } from "ink";
16516
- import { useState as useState25, useEffect as useEffect23 } from "react";
17103
+ import { useState as useState26, useEffect as useEffect25 } from "react";
16517
17104
  import { Text as Text28 } from "ink";
16518
17105
  import { readFileSync as readFileSync11 } from "fs";
16519
17106
  var evalCommand = new Command14("eval").description("Manage evaluations");
@@ -16558,11 +17145,11 @@ evalCommand.command("submit").description("Submit an eval batch").requiredOption
16558
17145
  return;
16559
17146
  }
16560
17147
  const App = () => {
16561
- const [loading, setLoading] = useState25(true);
16562
- const [success, setSuccess] = useState25(null);
16563
- const [error, setError] = useState25(null);
16564
- const [resultNode, setResultNode] = useState25(void 0);
16565
- useEffect23(() => {
17148
+ const [loading, setLoading] = useState26(true);
17149
+ const [success, setSuccess] = useState26(null);
17150
+ const [error, setError] = useState26(null);
17151
+ const [resultNode, setResultNode] = useState26(void 0);
17152
+ useEffect25(() => {
16566
17153
  const run = async () => {
16567
17154
  try {
16568
17155
  const data = await client.post("/eval/submit", {
@@ -16641,11 +17228,11 @@ evalCommand.command("list").description("List eval batches").option("--flow <id>
16641
17228
  return;
16642
17229
  }
16643
17230
  const App = () => {
16644
- const [loading, setLoading] = useState25(true);
16645
- const [items, setItems] = useState25(null);
16646
- const [total, setTotal] = useState25(void 0);
16647
- const [error, setError] = useState25(null);
16648
- useEffect23(() => {
17231
+ const [loading, setLoading] = useState26(true);
17232
+ const [items, setItems] = useState26(null);
17233
+ const [total, setTotal] = useState26(void 0);
17234
+ const [error, setError] = useState26(null);
17235
+ useEffect25(() => {
16649
17236
  const run = async () => {
16650
17237
  try {
16651
17238
  const data = await client.get("/eval/batches", params);
@@ -16721,11 +17308,11 @@ evalCommand.command("results <id>").description("Get eval batch results").option
16721
17308
  return;
16722
17309
  }
16723
17310
  const App = () => {
16724
- const [loading, setLoading] = useState25(true);
16725
- const [success, setSuccess] = useState25(null);
16726
- const [error, setError] = useState25(null);
16727
- const [resultNode, setResultNode] = useState25(void 0);
16728
- useEffect23(() => {
17311
+ const [loading, setLoading] = useState26(true);
17312
+ const [success, setSuccess] = useState26(null);
17313
+ const [error, setError] = useState26(null);
17314
+ const [resultNode, setResultNode] = useState26(void 0);
17315
+ useEffect25(() => {
16729
17316
  const run = async () => {
16730
17317
  try {
16731
17318
  const data = await client.get(`/eval/${id}/results`);
@@ -16785,10 +17372,10 @@ evalCommand.command("compare <groupId>").description("Compare evals in a group")
16785
17372
  return;
16786
17373
  }
16787
17374
  const App = () => {
16788
- const [loading, setLoading] = useState25(true);
16789
- const [success, setSuccess] = useState25(null);
16790
- const [error, setError] = useState25(null);
16791
- useEffect23(() => {
17375
+ const [loading, setLoading] = useState26(true);
17376
+ const [success, setSuccess] = useState26(null);
17377
+ const [error, setError] = useState26(null);
17378
+ useEffect25(() => {
16792
17379
  const run = async () => {
16793
17380
  try {
16794
17381
  const data = await client.post("/eval/compare", { groupId });
@@ -16820,7 +17407,7 @@ import { Command as Command15 } from "commander";
16820
17407
  import chalk21 from "chalk";
16821
17408
  import React14 from "react";
16822
17409
  import { render as render14 } from "ink";
16823
- import { useState as useState26, useEffect as useEffect24 } from "react";
17410
+ import { useState as useState27, useEffect as useEffect26 } from "react";
16824
17411
  import { Text as Text29 } from "ink";
16825
17412
  var apiKeysCommand = new Command15("api-keys").description("Manage API keys");
16826
17413
  apiKeysCommand.command("list").description("List your API keys").option("--json", "Output as JSON").option("--tty", "Force TTY mode").option("--no-tty", "Force non-TTY mode").action(async (options) => {
@@ -16859,11 +17446,11 @@ apiKeysCommand.command("list").description("List your API keys").option("--json"
16859
17446
  return;
16860
17447
  }
16861
17448
  const App = () => {
16862
- const [loading, setLoading] = useState26(true);
16863
- const [items, setItems] = useState26(null);
16864
- const [total, setTotal] = useState26(void 0);
16865
- const [error, setError] = useState26(null);
16866
- useEffect24(() => {
17449
+ const [loading, setLoading] = useState27(true);
17450
+ const [items, setItems] = useState27(null);
17451
+ const [total, setTotal] = useState27(void 0);
17452
+ const [error, setError] = useState27(null);
17453
+ useEffect26(() => {
16867
17454
  const run = async () => {
16868
17455
  try {
16869
17456
  const data = await client.get("/api-keys");
@@ -16923,11 +17510,11 @@ apiKeysCommand.command("get <id>").description("Get API key details").option("--
16923
17510
  return;
16924
17511
  }
16925
17512
  const App = () => {
16926
- const [loading, setLoading] = useState26(true);
16927
- const [success, setSuccess] = useState26(null);
16928
- const [error, setError] = useState26(null);
16929
- const [resultNode, setResultNode] = useState26(void 0);
16930
- useEffect24(() => {
17513
+ const [loading, setLoading] = useState27(true);
17514
+ const [success, setSuccess] = useState27(null);
17515
+ const [error, setError] = useState27(null);
17516
+ const [resultNode, setResultNode] = useState27(void 0);
17517
+ useEffect26(() => {
16931
17518
  const run = async () => {
16932
17519
  try {
16933
17520
  const data = await client.get(`/api-keys/${id}`);
@@ -16992,11 +17579,11 @@ apiKeysCommand.command("create").description("Create a new API key").requiredOpt
16992
17579
  return;
16993
17580
  }
16994
17581
  const App = () => {
16995
- const [loading, setLoading] = useState26(true);
16996
- const [success, setSuccess] = useState26(null);
16997
- const [error, setError] = useState26(null);
16998
- const [resultNode, setResultNode] = useState26(void 0);
16999
- useEffect24(() => {
17582
+ const [loading, setLoading] = useState27(true);
17583
+ const [success, setSuccess] = useState27(null);
17584
+ const [error, setError] = useState27(null);
17585
+ const [resultNode, setResultNode] = useState27(void 0);
17586
+ useEffect26(() => {
17000
17587
  const run = async () => {
17001
17588
  try {
17002
17589
  const data = await client.post("/api-keys", {
@@ -17051,10 +17638,10 @@ apiKeysCommand.command("delete <id>").description("Delete an API key").option("-
17051
17638
  }
17052
17639
  if (options.yes) {
17053
17640
  const App = () => {
17054
- const [loading, setLoading] = useState26(true);
17055
- const [success, setSuccess] = useState26(null);
17056
- const [error, setError] = useState26(null);
17057
- useEffect24(() => {
17641
+ const [loading, setLoading] = useState27(true);
17642
+ const [success, setSuccess] = useState27(null);
17643
+ const [error, setError] = useState27(null);
17644
+ useEffect26(() => {
17058
17645
  const run = async () => {
17059
17646
  try {
17060
17647
  await client.delete(`/api-keys/${id}`);
@@ -17094,10 +17681,10 @@ apiKeysCommand.command("delete <id>").description("Delete an API key").option("-
17094
17681
  });
17095
17682
  if (!confirmed) return;
17096
17683
  const DeleteApp = () => {
17097
- const [loading, setLoading] = useState26(true);
17098
- const [success, setSuccess] = useState26(null);
17099
- const [error, setError] = useState26(null);
17100
- useEffect24(() => {
17684
+ const [loading, setLoading] = useState27(true);
17685
+ const [success, setSuccess] = useState27(null);
17686
+ const [error, setError] = useState27(null);
17687
+ useEffect26(() => {
17101
17688
  const run = async () => {
17102
17689
  try {
17103
17690
  await client.delete(`/api-keys/${id}`);
@@ -17147,11 +17734,11 @@ apiKeysCommand.command("regenerate <id>").description("Regenerate an API key").o
17147
17734
  return;
17148
17735
  }
17149
17736
  const App = () => {
17150
- const [loading, setLoading] = useState26(true);
17151
- const [success, setSuccess] = useState26(null);
17152
- const [error, setError] = useState26(null);
17153
- const [resultNode, setResultNode] = useState26(void 0);
17154
- useEffect24(() => {
17737
+ const [loading, setLoading] = useState27(true);
17738
+ const [success, setSuccess] = useState27(null);
17739
+ const [error, setError] = useState27(null);
17740
+ const [resultNode, setResultNode] = useState27(void 0);
17741
+ useEffect26(() => {
17155
17742
  const run = async () => {
17156
17743
  try {
17157
17744
  const data = await client.post(`/api-keys/${id}/regenerate`);
@@ -17203,10 +17790,10 @@ apiKeysCommand.command("analytics").description("Show API key usage analytics").
17203
17790
  return;
17204
17791
  }
17205
17792
  const App = () => {
17206
- const [loading, setLoading] = useState26(true);
17207
- const [success, setSuccess] = useState26(null);
17208
- const [error, setError] = useState26(null);
17209
- useEffect24(() => {
17793
+ const [loading, setLoading] = useState27(true);
17794
+ const [success, setSuccess] = useState27(null);
17795
+ const [error, setError] = useState27(null);
17796
+ useEffect26(() => {
17210
17797
  const run = async () => {
17211
17798
  try {
17212
17799
  const path10 = options.key ? `/api-keys/${options.key}/analytics` : "/api-keys/analytics";
@@ -17239,7 +17826,7 @@ import { Command as Command16 } from "commander";
17239
17826
  import chalk22 from "chalk";
17240
17827
  import React15 from "react";
17241
17828
  import { render as render15 } from "ink";
17242
- import { useState as useState27, useEffect as useEffect25 } from "react";
17829
+ import { useState as useState28, useEffect as useEffect27 } from "react";
17243
17830
  import { Text as Text30 } from "ink";
17244
17831
  var analyticsCommand = new Command16("analytics").description("View analytics and execution results");
17245
17832
  analyticsCommand.command("stats").description("Show account statistics").option("--json", "Output as JSON").option("--tty", "Force TTY mode").option("--no-tty", "Force non-TTY mode").action(async (options) => {
@@ -17268,11 +17855,11 @@ analyticsCommand.command("stats").description("Show account statistics").option(
17268
17855
  return;
17269
17856
  }
17270
17857
  const App = () => {
17271
- const [loading, setLoading] = useState27(true);
17272
- const [success, setSuccess] = useState27(null);
17273
- const [error, setError] = useState27(null);
17274
- const [resultNode, setResultNode] = useState27(void 0);
17275
- useEffect25(() => {
17858
+ const [loading, setLoading] = useState28(true);
17859
+ const [success, setSuccess] = useState28(null);
17860
+ const [error, setError] = useState28(null);
17861
+ const [resultNode, setResultNode] = useState28(void 0);
17862
+ useEffect27(() => {
17276
17863
  const run = async () => {
17277
17864
  try {
17278
17865
  const data = await client.get("/analytics/stats");
@@ -17352,11 +17939,11 @@ analyticsCommand.command("results").description("List execution results").option
17352
17939
  return;
17353
17940
  }
17354
17941
  const App = () => {
17355
- const [loading, setLoading] = useState27(true);
17356
- const [items, setItems] = useState27(null);
17357
- const [total, setTotal] = useState27(void 0);
17358
- const [error, setError] = useState27(null);
17359
- useEffect25(() => {
17942
+ const [loading, setLoading] = useState28(true);
17943
+ const [items, setItems] = useState28(null);
17944
+ const [total, setTotal] = useState28(void 0);
17945
+ const [error, setError] = useState28(null);
17946
+ useEffect27(() => {
17360
17947
  const run = async () => {
17361
17948
  try {
17362
17949
  const data = await client.get(
@@ -17401,7 +17988,7 @@ import { Command as Command17 } from "commander";
17401
17988
  import chalk23 from "chalk";
17402
17989
  import React16 from "react";
17403
17990
  import { render as render16 } from "ink";
17404
- import { useState as useState28, useEffect as useEffect26 } from "react";
17991
+ import { useState as useState29, useEffect as useEffect28 } from "react";
17405
17992
  import open5 from "open";
17406
17993
  var billingCommand = new Command17("billing").description("View billing and subscription info");
17407
17994
  billingCommand.command("status").description("Show current plan and usage").option("--json", "Output as JSON").option("--tty", "Force TTY mode").option("--no-tty", "Force non-TTY mode").action(async (options) => {
@@ -17447,11 +18034,11 @@ billingCommand.command("status").description("Show current plan and usage").opti
17447
18034
  return;
17448
18035
  }
17449
18036
  const App = () => {
17450
- const [loading, setLoading] = useState28(true);
17451
- const [success, setSuccess] = useState28(null);
17452
- const [error, setError] = useState28(null);
17453
- const [resultNode, setResultNode] = useState28(void 0);
17454
- useEffect26(() => {
18037
+ const [loading, setLoading] = useState29(true);
18038
+ const [success, setSuccess] = useState29(null);
18039
+ const [error, setError] = useState29(null);
18040
+ const [resultNode, setResultNode] = useState29(void 0);
18041
+ useEffect28(() => {
17455
18042
  const run = async () => {
17456
18043
  try {
17457
18044
  const data = await client.get("/billing/status");
@@ -17518,11 +18105,11 @@ billingCommand.command("portal").description("Open the billing portal in your br
17518
18105
  return;
17519
18106
  }
17520
18107
  const App = () => {
17521
- const [loading, setLoading] = useState28(true);
17522
- const [success, setSuccess] = useState28(null);
17523
- const [error, setError] = useState28(null);
17524
- const [msg, setMsg] = useState28("Opening billing portal...");
17525
- useEffect26(() => {
18108
+ const [loading, setLoading] = useState29(true);
18109
+ const [success, setSuccess] = useState29(null);
18110
+ const [error, setError] = useState29(null);
18111
+ const [msg, setMsg] = useState29("Opening billing portal...");
18112
+ useEffect28(() => {
17526
18113
  const run = async () => {
17527
18114
  try {
17528
18115
  const data = await client.post("/billing/portal");
@@ -17571,10 +18158,10 @@ billingCommand.command("refresh").description("Refresh plan data from billing pr
17571
18158
  return;
17572
18159
  }
17573
18160
  const App = () => {
17574
- const [loading, setLoading] = useState28(true);
17575
- const [success, setSuccess] = useState28(null);
17576
- const [error, setError] = useState28(null);
17577
- useEffect26(() => {
18161
+ const [loading, setLoading] = useState29(true);
18162
+ const [success, setSuccess] = useState29(null);
18163
+ const [error, setError] = useState29(null);
18164
+ useEffect28(() => {
17578
18165
  const run = async () => {
17579
18166
  try {
17580
18167
  await client.post("/billing/refresh");
@@ -17605,7 +18192,7 @@ import { Command as Command18 } from "commander";
17605
18192
  import chalk24 from "chalk";
17606
18193
  import React17 from "react";
17607
18194
  import { render as render17 } from "ink";
17608
- import { useState as useState29, useEffect as useEffect27 } from "react";
18195
+ import { useState as useState30, useEffect as useEffect29 } from "react";
17609
18196
  import { Text as Text31 } from "ink";
17610
18197
  var flowVersionsCommand = new Command18("flow-versions").description(
17611
18198
  "Manage flow versions"
@@ -17642,10 +18229,10 @@ flowVersionsCommand.command("list <flowId>").description("List all versions for
17642
18229
  return;
17643
18230
  }
17644
18231
  const App = () => {
17645
- const [loading, setLoading] = useState29(true);
17646
- const [items, setItems] = useState29(null);
17647
- const [error, setError] = useState29(null);
17648
- useEffect27(() => {
18232
+ const [loading, setLoading] = useState30(true);
18233
+ const [items, setItems] = useState30(null);
18234
+ const [error, setError] = useState30(null);
18235
+ useEffect29(() => {
17649
18236
  const run = async () => {
17650
18237
  try {
17651
18238
  const data = await client.get(`/flow-versions/${flowId}`);
@@ -17703,11 +18290,11 @@ flowVersionsCommand.command("get <flowId> <versionId>").description("Get a speci
17703
18290
  return;
17704
18291
  }
17705
18292
  const App = () => {
17706
- const [loading, setLoading] = useState29(true);
17707
- const [success, setSuccess] = useState29(null);
17708
- const [error, setError] = useState29(null);
17709
- const [resultNode, setResultNode] = useState29(void 0);
17710
- useEffect27(() => {
18293
+ const [loading, setLoading] = useState30(true);
18294
+ const [success, setSuccess] = useState30(null);
18295
+ const [error, setError] = useState30(null);
18296
+ const [resultNode, setResultNode] = useState30(void 0);
18297
+ useEffect29(() => {
17711
18298
  const run = async () => {
17712
18299
  try {
17713
18300
  const data = await client.get(`/flow-versions/${flowId}/${versionId}`);
@@ -17769,11 +18356,11 @@ flowVersionsCommand.command("published <flowId>").description("Get the published
17769
18356
  return;
17770
18357
  }
17771
18358
  const App = () => {
17772
- const [loading, setLoading] = useState29(true);
17773
- const [success, setSuccess] = useState29(null);
17774
- const [error, setError] = useState29(null);
17775
- const [resultNode, setResultNode] = useState29(void 0);
17776
- useEffect27(() => {
18359
+ const [loading, setLoading] = useState30(true);
18360
+ const [success, setSuccess] = useState30(null);
18361
+ const [error, setError] = useState30(null);
18362
+ const [resultNode, setResultNode] = useState30(void 0);
18363
+ useEffect29(() => {
17777
18364
  const run = async () => {
17778
18365
  try {
17779
18366
  const data = await client.get(`/flow-versions/${flowId}/published`);
@@ -17826,10 +18413,10 @@ flowVersionsCommand.command("publish <flowId>").description("Publish a version")
17826
18413
  return;
17827
18414
  }
17828
18415
  const App = () => {
17829
- const [loading, setLoading] = useState29(true);
17830
- const [success, setSuccess] = useState29(null);
17831
- const [error, setError] = useState29(null);
17832
- useEffect27(() => {
18416
+ const [loading, setLoading] = useState30(true);
18417
+ const [success, setSuccess] = useState30(null);
18418
+ const [error, setError] = useState30(null);
18419
+ useEffect29(() => {
17833
18420
  const run = async () => {
17834
18421
  try {
17835
18422
  await client.post(`/flow-versions/${flowId}/publish`, {