@runtypelabs/cli 2.0.1 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -688,7 +688,7 @@ var require_builtin_tools_registry = __commonJS({
688
688
  return compatibility.models.some((m) => modelId.includes(m));
689
689
  }
690
690
  function getCompatibleBuiltInTools(modelId, provider) {
691
- return exports.BUILTIN_TOOLS_REGISTRY.filter((tool) => isToolCompatibleWithModel2(tool.id, modelId, provider));
691
+ return exports.BUILTIN_TOOLS_REGISTRY.filter((tool) => !tool.hidden && isToolCompatibleWithModel2(tool.id, modelId, provider));
692
692
  }
693
693
  function validateToolConfig(toolId, config2) {
694
694
  const tool = getBuiltInToolById2(toolId);
@@ -8333,7 +8333,7 @@ import { Command as Command11 } from "commander";
8333
8333
  import chalk17 from "chalk";
8334
8334
  import React10 from "react";
8335
8335
  import { render as render10 } from "ink";
8336
- import { useState as useState24, useEffect as useEffect22 } from "react";
8336
+ import { useState as useState24, useEffect as useEffect21 } from "react";
8337
8337
  import { processStream as processStream4 } from "@runtypelabs/sdk";
8338
8338
 
8339
8339
  // src/commands/agents-task.ts
@@ -8343,7 +8343,7 @@ import { render as render9 } from "ink";
8343
8343
  import React9 from "react";
8344
8344
 
8345
8345
  // src/ink/marathon/MarathonApp.tsx
8346
- import { useState as useState22, useEffect as useEffect20, useRef as useRef8, useCallback as useCallback8, useMemo as useMemo11 } from "react";
8346
+ import { useState as useState22, useEffect as useEffect19, useRef as useRef9, useCallback as useCallback8, useMemo as useMemo11 } from "react";
8347
8347
  import { execSync } from "child_process";
8348
8348
  import * as fs4 from "fs";
8349
8349
  import open4 from "open";
@@ -8539,12 +8539,12 @@ function pushRawEvent(eventsRef, type, data, writer, listData) {
8539
8539
  type: event.type,
8540
8540
  data: buildPersistedEventData(event.data, listData)
8541
8541
  };
8542
- setTimeout(() => {
8542
+ queueMicrotask(() => {
8543
8543
  try {
8544
8544
  w(jsonlEvent);
8545
8545
  } catch {
8546
8546
  }
8547
- }, 0);
8547
+ });
8548
8548
  }
8549
8549
  eventsRef.current.push(event);
8550
8550
  if (eventsRef.current.length > MAX_RAW_EVENTS) {
@@ -10821,7 +10821,7 @@ function createSandboxInstructions(provider) {
10821
10821
  "Deploy rules:",
10822
10822
  "1. Use this when you need to run a web server (Express, Hono, etc.) that the user can visit in their browser.",
10823
10823
  "2. The `code` is written to main.ts (or main.js/main.py). The `packageJson` object installs dependencies.",
10824
- "3. The `files` parameter writes additional files (path \u2192 content). Use this for HTML/CSS/JS assets instead of embedding them in template literals.",
10824
+ "3. The `files` parameter writes additional files (path \u2192 content). Keys must be plain file paths without wrapping quotes. Use this for HTML/CSS/JS assets instead of embedding them in template literals.",
10825
10825
  "4. The server must listen on the specified `port` (default 3000).",
10826
10826
  "5. The sandbox is persistent \u2014 it stays alive across sessions. The same sandbox is reused on subsequent calls.",
10827
10827
  "6. The returned `previewUrl` is a live URL the user can open in their browser.",
@@ -10979,7 +10979,7 @@ function createDeploySandboxLocalTool(client, debugMode) {
10979
10979
  },
10980
10980
  files: {
10981
10981
  type: "object",
10982
- description: 'Additional files to write (path \u2192 content), e.g. { "public/index.html": "<html>..." }. Use this for multi-file projects instead of embedding HTML in template literals.',
10982
+ description: 'Additional files to write (path \u2192 content), e.g. { "public/index.html": "<html>..." }. Keys must be plain file paths without wrapping quotes. Use this for multi-file projects instead of embedding HTML in template literals.',
10983
10983
  additionalProperties: { type: "string" }
10984
10984
  }
10985
10985
  },
@@ -11109,7 +11109,7 @@ function readSessionEventLog(stateFilePath2, sessionIndex) {
11109
11109
  }
11110
11110
 
11111
11111
  // src/ink/marathon/CheckpointPrompt.tsx
11112
- import { useState as useState18, useEffect as useEffect16, useRef as useRef7 } from "react";
11112
+ import { useState as useState18, useEffect as useEffect15, useRef as useRef8 } from "react";
11113
11113
  import { Box as Box21, Text as Text23 } from "ink";
11114
11114
 
11115
11115
  // src/ink/marathon/BlinkingTextInput.tsx
@@ -11247,12 +11247,11 @@ function BlinkingTextInput({
11247
11247
  import { theme as theme23 } from "@runtypelabs/ink-components";
11248
11248
 
11249
11249
  // src/ink/talk/ModelPicker.tsx
11250
- import { useState as useState15, useMemo as useMemo7, useCallback as useCallback5, useEffect as useEffect14 } from "react";
11250
+ import { useState as useState15, useMemo as useMemo7, useCallback as useCallback5, useRef as useRef6 } from "react";
11251
11251
  import { Box as Box17, Text as Text19, useInput as useInput7, useStdout as useStdout2 } from "ink";
11252
- import TextInput2 from "ink-text-input";
11253
11252
  import open3 from "open";
11254
11253
  import { theme as theme19 } from "@runtypelabs/ink-components";
11255
- import { jsx as jsx19, jsxs as jsxs16 } from "react/jsx-runtime";
11254
+ import { Fragment as Fragment2, jsx as jsx19, jsxs as jsxs16 } from "react/jsx-runtime";
11256
11255
  var DEFAULT_MODELS = [
11257
11256
  // Anthropic
11258
11257
  { label: "Claude Opus 4.6", value: "claude-opus-4-6", group: "Anthropic" },
@@ -11293,38 +11292,45 @@ function ModelPicker({ currentModel, onSelect, onCancel, models }) {
11293
11292
  (text) => text.length < contentWidth ? text + " ".repeat(contentWidth - text.length) : text,
11294
11293
  [contentWidth]
11295
11294
  );
11295
+ const sorted = useMemo7(
11296
+ () => [...availableModels].sort((a, b) => a.group.localeCompare(b.group)),
11297
+ [availableModels]
11298
+ );
11296
11299
  const filtered = useMemo7(() => {
11297
- if (!search.trim()) return availableModels;
11300
+ if (!search.trim()) return sorted;
11298
11301
  const q = search.toLowerCase();
11299
- return availableModels.filter(
11302
+ return sorted.filter(
11300
11303
  (m) => m.label.toLowerCase().includes(q) || m.value.toLowerCase().includes(q) || m.group.toLowerCase().includes(q)
11301
11304
  );
11302
- }, [availableModels, search]);
11305
+ }, [sorted, search]);
11306
+ const searchRef = useRef6("");
11307
+ const cursorRef = useRef6(0);
11308
+ const [cursorPos, setCursorPos] = useState15(0);
11303
11309
  const [selectedIndex, setSelectedIndex] = useState15(() => {
11304
- const currentIndex = availableModels.findIndex((model) => model.value === currentModel);
11310
+ const currentIndex = sorted.findIndex((model) => model.value === currentModel);
11305
11311
  return currentIndex >= 0 ? currentIndex : 0;
11306
11312
  });
11307
- const handleSearchChange = (value) => {
11308
- if (value === search) return;
11309
- setSearch(value);
11310
- setSelectedIndex(0);
11311
- };
11312
- useEffect14(() => {
11313
- if (!search.trim()) {
11314
- const currentIndex = filtered.findIndex((model) => model.value === currentModel);
11315
- setSelectedIndex(currentIndex >= 0 ? currentIndex : 0);
11316
- return;
11313
+ const safeIndex = filtered.length > 0 ? Math.min(selectedIndex, filtered.length - 1) : 0;
11314
+ const applySearch = useCallback5((newValue, newCursor) => {
11315
+ searchRef.current = newValue;
11316
+ cursorRef.current = newCursor;
11317
+ setSearch(newValue);
11318
+ setCursorPos(newCursor);
11319
+ if (!newValue.trim()) {
11320
+ const idx = sorted.findIndex((model) => model.value === currentModel);
11321
+ setSelectedIndex(idx >= 0 ? idx : 0);
11322
+ } else {
11323
+ setSelectedIndex(0);
11317
11324
  }
11318
- setSelectedIndex((prev) => Math.min(prev, Math.max(0, filtered.length - 1)));
11319
- }, [currentModel, filtered, search]);
11320
- useInput7((_input, key) => {
11325
+ }, [sorted, currentModel]);
11326
+ useInput7((input, key) => {
11321
11327
  if (key.escape) {
11322
11328
  onCancel();
11323
11329
  return;
11324
11330
  }
11325
11331
  if (key.return) {
11326
11332
  if (filtered.length > 0) {
11327
- onSelect(filtered[selectedIndex].value);
11333
+ onSelect(filtered[safeIndex].value);
11328
11334
  }
11329
11335
  return;
11330
11336
  }
@@ -11340,30 +11346,65 @@ function ModelPicker({ currentModel, onSelect, onCancel, models }) {
11340
11346
  void open3(`${getDashboardUrl()}/settings/models`);
11341
11347
  return;
11342
11348
  }
11349
+ if (key.backspace || key.delete) {
11350
+ const cursor = cursorRef.current;
11351
+ if (cursor > 0) {
11352
+ const prev = searchRef.current;
11353
+ applySearch(prev.slice(0, cursor - 1) + prev.slice(cursor), cursor - 1);
11354
+ }
11355
+ return;
11356
+ }
11357
+ if (key.leftArrow) {
11358
+ const nc = Math.max(0, cursorRef.current - 1);
11359
+ cursorRef.current = nc;
11360
+ setCursorPos(nc);
11361
+ return;
11362
+ }
11363
+ if (key.rightArrow) {
11364
+ const nc = Math.min(searchRef.current.length, cursorRef.current + 1);
11365
+ cursorRef.current = nc;
11366
+ setCursorPos(nc);
11367
+ return;
11368
+ }
11369
+ if (input && !key.ctrl && !key.meta) {
11370
+ const cursor = cursorRef.current;
11371
+ const prev = searchRef.current;
11372
+ applySearch(prev.slice(0, cursor) + input + prev.slice(cursor), cursor + input.length);
11373
+ }
11343
11374
  });
11344
- const MODEL_WINDOW = MAX_VISIBLE2 - 4;
11345
- const modelWindowStart = Math.max(
11346
- 0,
11347
- Math.min(
11348
- selectedIndex - Math.floor(MODEL_WINDOW / 2),
11349
- filtered.length - MODEL_WINDOW
11350
- )
11351
- );
11352
- const modelWindowEnd = Math.min(modelWindowStart + MODEL_WINDOW, filtered.length);
11353
- const rows = [];
11354
- let lastGroup = "";
11355
- for (let i = modelWindowStart; i < modelWindowEnd; i++) {
11356
- const model = filtered[i];
11357
- if (model.group !== lastGroup) {
11358
- rows.push({ type: "group", label: model.group });
11359
- lastGroup = model.group;
11360
- }
11361
- rows.push({
11362
- type: "model",
11363
- model,
11364
- isHighlighted: i === selectedIndex,
11365
- isCurrent: model.value === currentModel
11366
- });
11375
+ let modelWindow = MAX_VISIBLE2 - 4;
11376
+ let modelWindowStart = 0;
11377
+ let modelWindowEnd = 0;
11378
+ let rows = [];
11379
+ for (let attempt = 0; attempt < 3; attempt++) {
11380
+ modelWindowStart = Math.max(
11381
+ 0,
11382
+ Math.min(
11383
+ safeIndex - Math.floor(modelWindow / 2),
11384
+ filtered.length - modelWindow
11385
+ )
11386
+ );
11387
+ modelWindowEnd = Math.min(modelWindowStart + modelWindow, filtered.length);
11388
+ rows = [];
11389
+ let lastGroup = "";
11390
+ for (let i = modelWindowStart; i < modelWindowEnd; i++) {
11391
+ const model = filtered[i];
11392
+ if (model.group !== lastGroup) {
11393
+ rows.push({ type: "group", label: model.group });
11394
+ lastGroup = model.group;
11395
+ }
11396
+ rows.push({
11397
+ type: "model",
11398
+ model,
11399
+ isHighlighted: i === safeIndex,
11400
+ isCurrent: model.value === currentModel
11401
+ });
11402
+ }
11403
+ if (rows.length <= MAX_VISIBLE2) break;
11404
+ modelWindow = Math.max(1, modelWindow - (rows.length - MAX_VISIBLE2));
11405
+ }
11406
+ while (rows.length < MAX_VISIBLE2) {
11407
+ rows.push({ type: "blank" });
11367
11408
  }
11368
11409
  const showScrollUp = modelWindowStart > 0;
11369
11410
  const showScrollDown = modelWindowEnd < filtered.length;
@@ -11387,17 +11428,23 @@ function ModelPicker({ currentModel, onSelect, onCancel, models }) {
11387
11428
  ] }),
11388
11429
  /* @__PURE__ */ jsxs16(Box17, { marginBottom: 1, children: [
11389
11430
  /* @__PURE__ */ jsx19(Text19, { color: theme19.textSubtle, children: "/ " }),
11390
- /* @__PURE__ */ jsx19(
11391
- TextInput2,
11392
- {
11393
- value: search,
11394
- onChange: handleSearchChange,
11395
- placeholder: "Search models..."
11396
- }
11397
- )
11431
+ search.length > 0 ? /* @__PURE__ */ jsxs16(Fragment2, { children: [
11432
+ /* @__PURE__ */ jsx19(Text19, { children: search.slice(0, cursorPos) }),
11433
+ /* @__PURE__ */ jsx19(Text19, { inverse: true, children: search[cursorPos] ?? " " }),
11434
+ cursorPos < search.length && /* @__PURE__ */ jsx19(Text19, { children: search.slice(cursorPos + 1) })
11435
+ ] }) : /* @__PURE__ */ jsxs16(Fragment2, { children: [
11436
+ /* @__PURE__ */ jsx19(Text19, { inverse: true, children: " " }),
11437
+ /* @__PURE__ */ jsx19(Text19, { color: theme19.textSubtle, children: "Search models..." })
11438
+ ] })
11398
11439
  ] }),
11399
11440
  /* @__PURE__ */ jsx19(Box17, { height: 1, children: /* @__PURE__ */ jsx19(Text19, { color: theme19.textSubtle, children: pad(showScrollUp ? " ..." : "") }) }),
11400
- /* @__PURE__ */ jsx19(Box17, { flexDirection: "column", height: MAX_VISIBLE2, children: filtered.length === 0 ? /* @__PURE__ */ jsx19(Text19, { color: theme19.textSubtle, children: " No matching models" }) : rows.map((row) => {
11441
+ /* @__PURE__ */ jsx19(Box17, { flexDirection: "column", height: MAX_VISIBLE2, children: filtered.length === 0 ? /* @__PURE__ */ jsxs16(Fragment2, { children: [
11442
+ /* @__PURE__ */ jsx19(Text19, { color: theme19.textSubtle, children: pad(" No matching models") }),
11443
+ Array.from({ length: MAX_VISIBLE2 - 1 }, (_, i) => /* @__PURE__ */ jsx19(Text19, { children: pad("") }, `empty-${i}`))
11444
+ ] }) : rows.map((row, i) => {
11445
+ if (row.type === "blank") {
11446
+ return /* @__PURE__ */ jsx19(Text19, { children: pad("") }, `blank-${i}`);
11447
+ }
11401
11448
  if (row.type === "group") {
11402
11449
  return /* @__PURE__ */ jsx19(Box17, { children: /* @__PURE__ */ jsx19(Text19, { color: theme19.textSubtle, dimColor: true, children: pad(` ${row.label}`) }) }, `group-${row.label}`);
11403
11450
  }
@@ -11423,7 +11470,7 @@ function ModelPicker({ currentModel, onSelect, onCancel, models }) {
11423
11470
  // src/ink/marathon/CommandPicker.tsx
11424
11471
  import { useState as useState16, useMemo as useMemo8, useCallback as useCallback6 } from "react";
11425
11472
  import { Box as Box18, Text as Text20, useInput as useInput8, useStdout as useStdout3 } from "ink";
11426
- import TextInput3 from "ink-text-input";
11473
+ import TextInput2 from "ink-text-input";
11427
11474
  import { theme as theme20 } from "@runtypelabs/ink-components";
11428
11475
 
11429
11476
  // src/ink/marathon/types.ts
@@ -11513,7 +11560,7 @@ function CommandPicker({ onSelect, onCancel, initialFilter = "" }) {
11513
11560
  /* @__PURE__ */ jsxs17(Box18, { marginBottom: 1, children: [
11514
11561
  /* @__PURE__ */ jsx20(Text20, { color: theme20.textSubtle, children: "/ " }),
11515
11562
  /* @__PURE__ */ jsx20(
11516
- TextInput3,
11563
+ TextInput2,
11517
11564
  {
11518
11565
  value: search,
11519
11566
  onChange: handleSearchChange,
@@ -11541,7 +11588,7 @@ function CommandPicker({ onSelect, onCancel, initialFilter = "" }) {
11541
11588
  }
11542
11589
 
11543
11590
  // src/ink/marathon/TextArea.tsx
11544
- import { useState as useState17, useCallback as useCallback7, useRef as useRef6, useEffect as useEffect15, useMemo as useMemo9 } from "react";
11591
+ import { useState as useState17, useCallback as useCallback7, useRef as useRef7, useEffect as useEffect14, useMemo as useMemo9 } from "react";
11545
11592
  import { Box as Box19, Text as Text21, useInput as useInput9, useStdout as useStdout4 } from "ink";
11546
11593
  import { theme as theme21 } from "@runtypelabs/ink-components";
11547
11594
 
@@ -11633,12 +11680,12 @@ function TextArea({
11633
11680
  });
11634
11681
  const [scrollOffset, setScrollOffset] = useState17(0);
11635
11682
  const [blinkVisible, setBlinkVisible] = useState17(true);
11636
- const blinkRef = useRef6(null);
11637
- const linesRef = useRef6(lines);
11683
+ const blinkRef = useRef7(null);
11684
+ const linesRef = useRef7(lines);
11638
11685
  linesRef.current = lines;
11639
- const cursorRef = useRef6(cursor);
11686
+ const cursorRef = useRef7(cursor);
11640
11687
  cursorRef.current = cursor;
11641
- useEffect15(() => {
11688
+ useEffect14(() => {
11642
11689
  blinkRef.current = setInterval(() => {
11643
11690
  setBlinkVisible((v) => !v);
11644
11691
  }, CURSOR_BLINK_MS);
@@ -11649,10 +11696,10 @@ function TextArea({
11649
11696
  }
11650
11697
  };
11651
11698
  }, []);
11652
- useEffect15(() => {
11699
+ useEffect14(() => {
11653
11700
  setBlinkVisible(true);
11654
11701
  }, [lines, cursor]);
11655
- useEffect15(() => {
11702
+ useEffect14(() => {
11656
11703
  const visibleStart = scrollOffset;
11657
11704
  const visibleEnd = scrollOffset + maxHeight - 1;
11658
11705
  if (cursor.line < visibleStart) {
@@ -11902,7 +11949,7 @@ function CheckpointRecap({
11902
11949
  historyWarning,
11903
11950
  isTerminal
11904
11951
  }) {
11905
- const label = isTerminal ? `\u2713 Session ${sessionNumber} complete` : `Session ${sessionNumber} complete`;
11952
+ const label = isTerminal ? `\u2713 Run ${sessionNumber} complete` : `Run ${sessionNumber} complete`;
11906
11953
  const separator = theme22.separator ?? " \xB7 ";
11907
11954
  const usageSummary = [
11908
11955
  `Tools: ${toolCallsMade}`,
@@ -11966,7 +12013,7 @@ function CheckpointPrompt({
11966
12013
  const [pendingSandbox, setPendingSandbox] = useState18(void 0);
11967
12014
  const [pendingToolsToggle, setPendingToolsToggle] = useState18(false);
11968
12015
  const [pendingStop, setPendingStop] = useState18(false);
11969
- const timerRef = useRef7(null);
12016
+ const timerRef = useRef8(null);
11970
12017
  const separator = theme23.separator ?? " \xB7 ";
11971
12018
  const hasPendingChanges = pendingModel !== void 0 || pendingSandbox !== void 0 || pendingToolsToggle || pendingStop;
11972
12019
  const clearInputDraft = () => {
@@ -11991,9 +12038,9 @@ function CheckpointPrompt({
11991
12038
  resetDraft();
11992
12039
  onSubmit(result);
11993
12040
  };
11994
- useEffect16(() => {
12041
+ useEffect15(() => {
11995
12042
  const title = "Marathon";
11996
- const body = isTerminal ? "Marathon complete" : `Session ${recap?.sessionNumber ?? "?"} complete`;
12043
+ const body = isTerminal ? "Marathon complete" : `Run ${recap?.sessionNumber ?? "?"} complete`;
11997
12044
  process.stderr.write(`\x1B]777;notify;${title};${body}\x07`);
11998
12045
  process.stderr.write(`\x1B]9;${body}\x07`);
11999
12046
  process.stderr.write("\x07");
@@ -12011,7 +12058,7 @@ function CheckpointPrompt({
12011
12058
  setIsTyping(false);
12012
12059
  }
12013
12060
  };
12014
- useEffect16(() => {
12061
+ useEffect15(() => {
12015
12062
  if (shouldPauseCheckpointTimer({
12016
12063
  isTerminal,
12017
12064
  timeout,
@@ -12225,7 +12272,7 @@ import { theme as theme24 } from "@runtypelabs/ink-components";
12225
12272
  import { jsx as jsx25, jsxs as jsxs21 } from "react/jsx-runtime";
12226
12273
  var MENU_ITEMS = [
12227
12274
  { key: "c", label: "Copy session JSON" },
12228
- { key: "o", label: "Open session JSON in editor" },
12275
+ { key: "e", label: "Open session JSON in editor" },
12229
12276
  { key: "f", label: "Open marathon folder in file manager" },
12230
12277
  { key: "d", label: "Open agent in Runtype dashboard" }
12231
12278
  ];
@@ -12247,7 +12294,7 @@ function SessionActionMenu({
12247
12294
  onCopySession();
12248
12295
  return;
12249
12296
  }
12250
- if (input === "o" && hasStateFile) {
12297
+ if (input === "e" && hasStateFile) {
12251
12298
  onOpenStateFile();
12252
12299
  return;
12253
12300
  }
@@ -12273,7 +12320,7 @@ function SessionActionMenu({
12273
12320
  children: [
12274
12321
  /* @__PURE__ */ jsx25(Text24, { bold: true, color: theme24.accent, children: "Session" }),
12275
12322
  /* @__PURE__ */ jsx25(Box22, { flexDirection: "column", marginTop: 1, children: MENU_ITEMS.map((item) => {
12276
- const dimmed = item.key === "o" && !hasStateFile || item.key === "f" && !hasStateFile || item.key === "d" && !hasDashboard;
12323
+ const dimmed = item.key === "e" && !hasStateFile || item.key === "f" && !hasStateFile || item.key === "d" && !hasDashboard;
12277
12324
  return /* @__PURE__ */ jsxs21(Text24, { children: [
12278
12325
  /* @__PURE__ */ jsx25(Text24, { color: dimmed ? theme24.textSubtle : theme24.accentActive, children: ` ${item.key} ` }),
12279
12326
  /* @__PURE__ */ jsx25(Text24, { color: dimmed ? theme24.textSubtle : theme24.textMuted, children: item.label })
@@ -12338,10 +12385,10 @@ import { Box as Box25 } from "ink";
12338
12385
  import { theme as theme27 } from "@runtypelabs/ink-components";
12339
12386
 
12340
12387
  // src/ink/marathon/ToolPanel.tsx
12341
- import { useState as useState19, useEffect as useEffect17, useMemo as useMemo10, memo as memo3 } from "react";
12388
+ import { useState as useState19, useEffect as useEffect16, useMemo as useMemo10, memo as memo3 } from "react";
12342
12389
  import { Box as Box24, Text as Text26 } from "ink";
12343
12390
  import { Spinner as Spinner5, theme as theme26 } from "@runtypelabs/ink-components";
12344
- import { Fragment as Fragment2, jsx as jsx27, jsxs as jsxs23 } from "react/jsx-runtime";
12391
+ import { Fragment as Fragment3, jsx as jsx27, jsxs as jsxs23 } from "react/jsx-runtime";
12345
12392
  var TOOL_PANEL_TIMER_MS = 500;
12346
12393
  function formatCharCount2(chars) {
12347
12394
  if (chars >= 1e3) {
@@ -12402,7 +12449,7 @@ var ToolPanel = memo3(function ToolPanel2({
12402
12449
  }) {
12403
12450
  const [now, setNow] = useState19(Date.now());
12404
12451
  const hasRunning = tools.some((t) => t.status === "running");
12405
- useEffect17(() => {
12452
+ useEffect16(() => {
12406
12453
  if (!hasRunning) return;
12407
12454
  const interval = setInterval(() => setNow(Date.now()), TOOL_PANEL_TIMER_MS);
12408
12455
  return () => clearInterval(interval);
@@ -12460,7 +12507,7 @@ var ToolPanel = memo3(function ToolPanel2({
12460
12507
  ] })
12461
12508
  ] }, tool.id);
12462
12509
  }),
12463
- visibleFiles.length > 0 && /* @__PURE__ */ jsxs23(Fragment2, { children: [
12510
+ visibleFiles.length > 0 && /* @__PURE__ */ jsxs23(Fragment3, { children: [
12464
12511
  /* @__PURE__ */ jsxs23(Box24, { marginTop: 1, children: [
12465
12512
  /* @__PURE__ */ jsx27(Text26, { bold: true, color: theme26.accent, children: "Files" }),
12466
12513
  hiddenFileCount > 0 && /* @__PURE__ */ jsxs23(Text26, { color: theme26.textSubtle, children: [
@@ -12523,14 +12570,14 @@ import { StreamOutput, ErrorDisplay as ErrorDisplay3 } from "@runtypelabs/ink-co
12523
12570
  import { LoadingAnimation } from "@runtypelabs/terminal-animations";
12524
12571
 
12525
12572
  // src/ink/marathon/ThinkingIndicator.tsx
12526
- import { useState as useState20, useEffect as useEffect18 } from "react";
12573
+ import { useState as useState20, useEffect as useEffect17 } from "react";
12527
12574
  import { Spinner as Spinner6, theme as theme28 } from "@runtypelabs/ink-components";
12528
12575
  import { jsx as jsx29 } from "react/jsx-runtime";
12529
12576
  function ThinkingIndicator({ startedAt }) {
12530
12577
  const [elapsed, setElapsed] = useState20(
12531
12578
  () => startedAt ? Math.floor((Date.now() - startedAt) / 1e3) : 0
12532
12579
  );
12533
- useEffect18(() => {
12580
+ useEffect17(() => {
12534
12581
  const start = startedAt ?? Date.now();
12535
12582
  setElapsed(Math.floor((Date.now() - start) / 1e3));
12536
12583
  const interval = setInterval(() => {
@@ -12542,7 +12589,7 @@ function ThinkingIndicator({ startedAt }) {
12542
12589
  }
12543
12590
 
12544
12591
  // src/ink/marathon/ContextCompactionIndicator.tsx
12545
- import { useEffect as useEffect19, useState as useState21 } from "react";
12592
+ import { useEffect as useEffect18, useState as useState21 } from "react";
12546
12593
  import { Spinner as Spinner7, theme as theme29 } from "@runtypelabs/ink-components";
12547
12594
  import { jsx as jsx30 } from "react/jsx-runtime";
12548
12595
  function buildCompactionLabel(compaction, elapsedSeconds) {
@@ -12560,7 +12607,7 @@ function ContextCompactionIndicator({
12560
12607
  const [elapsed, setElapsed] = useState21(
12561
12608
  () => Math.floor((Date.now() - compaction.startedAt) / 1e3)
12562
12609
  );
12563
- useEffect19(() => {
12610
+ useEffect18(() => {
12564
12611
  const start = compaction.startedAt;
12565
12612
  setElapsed(Math.floor((Date.now() - start) / 1e3));
12566
12613
  const interval = setInterval(() => {
@@ -12613,7 +12660,7 @@ function ReasoningBlock({
12613
12660
  }
12614
12661
 
12615
12662
  // src/ink/marathon/OverviewTranscriptPane.tsx
12616
- import { Fragment as Fragment3, jsx as jsx32, jsxs as jsxs25 } from "react/jsx-runtime";
12663
+ import { Fragment as Fragment4, jsx as jsx32, jsxs as jsxs25 } from "react/jsx-runtime";
12617
12664
  var UPGRADE_BROWSE_HINT_LINES = [
12618
12665
  "Upgrade modal dismissed.",
12619
12666
  "Use Shift+Left/Right or 1-9 to review previous marathon runs."
@@ -12642,7 +12689,7 @@ var OverviewTranscriptPane = memo5(function OverviewTranscriptPane2({
12642
12689
  return /* @__PURE__ */ jsx32(Box27, { flexGrow: 1, minHeight: contentHeight, overflow: "hidden", children: /* @__PURE__ */ jsx32(LoadingAnimation, { width: paneWidth, height: contentHeight }) });
12643
12690
  }
12644
12691
  const maxScroll = Math.max(0, totalLines - maxVisibleLines);
12645
- return /* @__PURE__ */ jsxs25(Fragment3, { children: [
12692
+ return /* @__PURE__ */ jsxs25(Fragment4, { children: [
12646
12693
  hasReasoning && /* @__PURE__ */ jsx32(Box27, { flexDirection: "column", marginBottom: reasoningCollapsed ? 0 : 1, children: /* @__PURE__ */ jsx32(
12647
12694
  ReasoningBlock,
12648
12695
  {
@@ -12958,7 +13005,7 @@ function MarathonApp({
12958
13005
  const { exit } = useApp4();
12959
13006
  const { stdout } = useStdout5();
12960
13007
  const separator = theme31.separator ?? " \xB7 ";
12961
- const checkpointResolveRef = useRef8(null);
13008
+ const checkpointResolveRef = useRef9(null);
12962
13009
  const [checkpointRecap, setCheckpointRecap] = useState22(null);
12963
13010
  const [currentModel, setCurrentModel] = useState22(model || "default");
12964
13011
  const [currentSandbox, setCurrentSandbox] = useState22(sandbox);
@@ -12975,7 +13022,7 @@ function MarathonApp({
12975
13022
  const [previewUrl, setPreviewUrl] = useState22(initialPreviewUrl);
12976
13023
  const [isCheckpointExploring, setIsCheckpointExploring] = useState22(false);
12977
13024
  const isRunnerAnimating = state.phase === "thinking" || state.phase === "streaming" || state.phase === "tool" || Boolean(state.contextCompaction?.active);
12978
- const isTerminalCheckpointRef = useRef8(false);
13025
+ const isTerminalCheckpointRef = useRef9(false);
12979
13026
  const markCheckpointExploring = useCallback8(() => {
12980
13027
  if (state.phase === "checkpoint" && checkpointRecap) {
12981
13028
  setIsCheckpointExploring(true);
@@ -13007,7 +13054,7 @@ function MarathonApp({
13007
13054
  },
13008
13055
  [resetForNewSession]
13009
13056
  );
13010
- useEffect20(() => {
13057
+ useEffect19(() => {
13011
13058
  streamRef.current = {
13012
13059
  getCallbacks: () => callbacks,
13013
13060
  getState: () => getHydratedState(),
@@ -13079,7 +13126,7 @@ function MarathonApp({
13079
13126
  const isStacked = terminalWidth < STACKED_THRESHOLD;
13080
13127
  const toolPanelWidth = terminalWidth < NARROW_THRESHOLD ? TOOL_PANEL_NARROW : TOOL_PANEL_WIDE;
13081
13128
  const [ctrlCPressed, setCtrlCPressed] = useState22(false);
13082
- const ctrlCTimeout = useRef8(null);
13129
+ const ctrlCTimeout = useRef9(null);
13083
13130
  const [activeScreen, setActiveScreen] = useState22("overview");
13084
13131
  const showEventStream = activeScreen === "events";
13085
13132
  const showReasoningPanel = activeScreen === "reasoning";
@@ -13109,7 +13156,7 @@ function MarathonApp({
13109
13156
  const [goalExpanded, setGoalExpanded] = useState22(false);
13110
13157
  const [upgradeModalDismissed, setUpgradeModalDismissed] = useState22(false);
13111
13158
  const [clipboardFlash, setClipboardFlash] = useState22(null);
13112
- const flashTimeout = useRef8(null);
13159
+ const flashTimeout = useRef9(null);
13113
13160
  const billingPageUrl = billingUrl || `${(dashboardUrl || "https://use.runtype.com").replace(/\/$/, "")}/settings/billing`;
13114
13161
  function showFlash(msg) {
13115
13162
  setClipboardFlash(msg);
@@ -13200,7 +13247,7 @@ function MarathonApp({
13200
13247
  }
13201
13248
  return snapshotEvents ?? liveRawEvents;
13202
13249
  }, [displayedSessionSnapshot, liveRawEvents, stateFilePath2]);
13203
- const seenTypesRef = useRef8({
13250
+ const seenTypesRef = useRef9({
13204
13251
  set: /* @__PURE__ */ new Set(),
13205
13252
  lastLen: 0,
13206
13253
  eventsRef: null
@@ -13222,7 +13269,7 @@ function MarathonApp({
13222
13269
  }
13223
13270
  return void 0;
13224
13271
  }, [displayedEvents]);
13225
- const stableSeenEventTypesRef = useRef8([]);
13272
+ const stableSeenEventTypesRef = useRef9([]);
13226
13273
  if (seenEventTypes !== void 0) {
13227
13274
  stableSeenEventTypesRef.current = seenEventTypes;
13228
13275
  }
@@ -13234,7 +13281,7 @@ function MarathonApp({
13234
13281
  () => displayedTools.filter((t) => t.name === "write_file" || t.name === "read_file").map((t) => `${t.id}:${t.name}:${String(t.parameters?.path ?? "")}:${t.startedAt}`).join("|"),
13235
13282
  [displayedTools]
13236
13283
  );
13237
- const trackedFilesCacheRef = useRef8({
13284
+ const trackedFilesCacheRef = useRef9({
13238
13285
  snapshots: null,
13239
13286
  fingerprint: "",
13240
13287
  planPath: void 0,
@@ -13248,7 +13295,7 @@ function MarathonApp({
13248
13295
  trackedFilesCache.value = extractTrackedFiles(sessionSnapshots, displayedTools, planPath);
13249
13296
  }
13250
13297
  const trackedFiles = trackedFilesCache.value;
13251
- const latestLiveActivityRef = useRef8(void 0);
13298
+ const latestLiveActivityRef = useRef9(void 0);
13252
13299
  const upgradePrompt = useMemo11(() => parseMarathonUpgradePrompt(state.error), [state.error]);
13253
13300
  const upgradePromptKey = useMemo11(
13254
13301
  () => upgradePrompt ? `${upgradePrompt.message}|${upgradePrompt.code ?? ""}|${upgradePrompt.limitType ?? ""}|${upgradePrompt.retryAfter ?? ""}` : void 0,
@@ -13279,25 +13326,25 @@ function MarathonApp({
13279
13326
  },
13280
13327
  [latestSessionKey]
13281
13328
  );
13282
- useEffect20(() => {
13329
+ useEffect19(() => {
13283
13330
  if (!selectedSessionKey && latestSessionKey) {
13284
13331
  setSelectedSessionKey(latestSessionKey);
13285
13332
  }
13286
13333
  }, [latestSessionKey, selectedSessionKey]);
13287
- useEffect20(() => {
13334
+ useEffect19(() => {
13288
13335
  if (followLatest && latestSessionKey && selectedSessionKey !== latestSessionKey) {
13289
13336
  setSelectedSessionKey(latestSessionKey);
13290
13337
  }
13291
13338
  }, [followLatest, latestSessionKey, selectedSessionKey]);
13292
- useEffect20(() => {
13339
+ useEffect19(() => {
13293
13340
  if (selectedSessionKey && selectedSessionKey === latestSessionKey && latestUnreadKey) {
13294
13341
  setLatestUnreadKey(void 0);
13295
13342
  }
13296
13343
  }, [latestSessionKey, latestUnreadKey, selectedSessionKey]);
13297
- useEffect20(() => {
13344
+ useEffect19(() => {
13298
13345
  setUpgradeModalDismissed(false);
13299
13346
  }, [upgradePromptKey]);
13300
- useEffect20(() => {
13347
+ useEffect19(() => {
13301
13348
  const liveActivityKey = liveSessionSnapshot ? `${liveSessionSnapshot.sessionIndex}:${state.phase}:${state.content.length}:${state.reasoning.length}:${state.tools.length}:${rawEventsRef.current.length}` : void 0;
13302
13349
  if (!liveActivityKey) {
13303
13350
  latestLiveActivityRef.current = void 0;
@@ -13316,7 +13363,7 @@ function MarathonApp({
13316
13363
  state.reasoning.length,
13317
13364
  state.tools.length
13318
13365
  ]);
13319
- useEffect20(() => {
13366
+ useEffect19(() => {
13320
13367
  if (selectedIsLive || followLatest) {
13321
13368
  const liveUrl = getActiveDeploySandboxPreviewUrl();
13322
13369
  if (liveUrl) {
@@ -13336,14 +13383,14 @@ function MarathonApp({
13336
13383
  }
13337
13384
  setPreviewUrl(void 0);
13338
13385
  }, [displayedTools, selectedIsLive, followLatest, state.phase]);
13339
- useEffect20(() => {
13386
+ useEffect19(() => {
13340
13387
  if (allowInitialInlineLoader) return;
13341
13388
  const hasVisibleSessionActivity = !isBlank(state.content) || !isBlank(state.reasoning) || state.tools.length > 0 || state.error !== null;
13342
13389
  if (hasVisibleSessionActivity) {
13343
13390
  setAllowInitialInlineLoader(true);
13344
13391
  }
13345
13392
  }, [allowInitialInlineLoader, state.content, state.error, state.reasoning, state.tools.length]);
13346
- useEffect20(() => {
13393
+ useEffect19(() => {
13347
13394
  if (showToolsPanel && displayedTools.length > 0 && toolCursor === -1) {
13348
13395
  setToolCursor(displayedTools.length - 1);
13349
13396
  }
@@ -13753,7 +13800,7 @@ function MarathonApp({
13753
13800
  return;
13754
13801
  }
13755
13802
  });
13756
- useEffect20(() => {
13803
+ useEffect19(() => {
13757
13804
  return () => {
13758
13805
  if (ctrlCTimeout.current) clearTimeout(ctrlCTimeout.current);
13759
13806
  if (flashTimeout.current) clearTimeout(flashTimeout.current);
@@ -14222,7 +14269,7 @@ function MarathonApp({
14222
14269
  }
14223
14270
 
14224
14271
  // src/ink/marathon/MarathonStartupShell.tsx
14225
- import { useEffect as useEffect21, useRef as useRef9, useState as useState23 } from "react";
14272
+ import { useEffect as useEffect20, useRef as useRef10, useState as useState23 } from "react";
14226
14273
  import { Box as Box29, Text as Text29, useApp as useApp5, useInput as useInput12, useStdout as useStdout6 } from "ink";
14227
14274
  import { theme as theme32 } from "@runtypelabs/ink-components";
14228
14275
  import { AnimatedVariant, StartupGridIconCompactLightInverted } from "@runtypelabs/terminal-animations";
@@ -14278,14 +14325,14 @@ function MarathonStartupShell({
14278
14325
  }) {
14279
14326
  const { exit } = useApp5();
14280
14327
  const { stdout } = useStdout6();
14281
- const mountedAtRef = useRef9(Date.now());
14282
- const promptResolverRef = useRef9(null);
14283
- const modelResolverRef = useRef9(null);
14284
- const playbookConfirmResolverRef = useRef9(null);
14285
- const appReadyResolverRef = useRef9(null);
14286
- const dismissResolverRef = useRef9(null);
14287
- const transitionPromiseRef = useRef9(null);
14288
- const latestAppPropsRef = useRef9(marathonAppProps);
14328
+ const mountedAtRef = useRef10(Date.now());
14329
+ const promptResolverRef = useRef10(null);
14330
+ const modelResolverRef = useRef10(null);
14331
+ const playbookConfirmResolverRef = useRef10(null);
14332
+ const appReadyResolverRef = useRef10(null);
14333
+ const dismissResolverRef = useRef10(null);
14334
+ const transitionPromiseRef = useRef10(null);
14335
+ const latestAppPropsRef = useRef10(marathonAppProps);
14289
14336
  const [statusMessage, setStatusMessage] = useState23("preparing marathon");
14290
14337
  const [scene, setScene] = useState23("splash");
14291
14338
  const [transition, setTransition] = useState23(null);
@@ -14298,7 +14345,7 @@ function MarathonStartupShell({
14298
14345
  () => STARTUP_BACKGROUND_VARIANTS[Math.floor(Math.random() * STARTUP_BACKGROUND_VARIANTS.length)]
14299
14346
  );
14300
14347
  latestAppPropsRef.current = marathonAppProps;
14301
- useEffect21(() => {
14348
+ useEffect20(() => {
14302
14349
  if (scene !== "app" || !appReadyResolverRef.current) return;
14303
14350
  const resolve7 = appReadyResolverRef.current;
14304
14351
  appReadyResolverRef.current = null;
@@ -14343,7 +14390,7 @@ function MarathonStartupShell({
14343
14390
  transitionPromiseRef.current = promise;
14344
14391
  return promise;
14345
14392
  };
14346
- useEffect21(() => {
14393
+ useEffect20(() => {
14347
14394
  startupRef.current = {
14348
14395
  setStatus: (message) => {
14349
14396
  setStatusMessage(message);
@@ -14509,7 +14556,8 @@ function MarathonStartupShell({
14509
14556
  {
14510
14557
  variantId: backgroundVariantId,
14511
14558
  width: terminalWidth,
14512
- height: terminalRows
14559
+ height: terminalRows,
14560
+ autoplay: !modelChoices && !playbookConfirm
14513
14561
  }
14514
14562
  )
14515
14563
  }
@@ -15263,7 +15311,9 @@ function extractRunTaskResumeState(state) {
15263
15311
  ...sanitized.bestCandidateNeedsVerification ? { bestCandidateNeedsVerification: sanitized.bestCandidateNeedsVerification } : {},
15264
15312
  ...sanitized.bestCandidateVerified ? { bestCandidateVerified: sanitized.bestCandidateVerified } : {},
15265
15313
  ...sanitized.verificationRequired !== void 0 ? { verificationRequired: sanitized.verificationRequired } : {},
15266
- ...sanitized.lastVerificationPassed ? { lastVerificationPassed: sanitized.lastVerificationPassed } : {}
15314
+ ...sanitized.lastVerificationPassed ? { lastVerificationPassed: sanitized.lastVerificationPassed } : {},
15315
+ ...sanitized.isCreationTask !== void 0 ? { isCreationTask: sanitized.isCreationTask } : {},
15316
+ ...sanitized.outputRoot ? { outputRoot: sanitized.outputRoot } : {}
15267
15317
  };
15268
15318
  }
15269
15319
  function findStateFile(name, stateDir) {
@@ -15428,6 +15478,29 @@ var IGNORED_REPO_DIRS = /* @__PURE__ */ new Set([
15428
15478
  "dist",
15429
15479
  "node_modules"
15430
15480
  ]);
15481
+ var SENSITIVE_PATH_PATTERNS = [
15482
+ { name: ".env", test: (n) => n === ".env" || n.endsWith("/.env") },
15483
+ { name: ".env.*", test: (n) => /\.env\.?[^/]*$/.test(n) || /\/\.env\.?[^/]*$/.test(n) },
15484
+ { name: "private keys", test: (n) => /(^|\/)(id_rsa|id_ed25519|id_ecdsa)(\.pub)?$/.test(n) },
15485
+ { name: "known_hosts", test: (n) => n.endsWith("known_hosts") || n.endsWith("/known_hosts") },
15486
+ { name: "authorized_keys", test: (n) => n.endsWith("authorized_keys") || n.endsWith("/authorized_keys") },
15487
+ { name: "cert/key extensions", test: (n) => /\.(pem|key|p12|pfx)$/i.test(n) },
15488
+ { name: "npm/pypi config", test: (n) => /(^|\/)(\.npmrc|\.pypirc|\.netrc)$/.test(n) },
15489
+ { name: "docker config", test: (n) => /\.docker\/config\.json$/i.test(n) },
15490
+ { name: "credentials", test: (n) => /(^|\/)(credentials\.json|secrets\.json)$/i.test(n) },
15491
+ { name: "service account", test: (n) => /service-account.*\.json$/i.test(n) || /firebase-admin.*\.json$/i.test(n) },
15492
+ { name: ".ssh", test: (n) => n === ".ssh" || n.startsWith(".ssh/") || n.includes("/.ssh/") },
15493
+ { name: ".aws", test: (n) => n === ".aws" || n.startsWith(".aws/") || n.includes("/.aws/") },
15494
+ { name: ".gnupg", test: (n) => n === ".gnupg" || n.startsWith(".gnupg/") || n.includes("/.gnupg/") },
15495
+ { name: ".terraform", test: (n) => n === ".terraform" || n.startsWith(".terraform/") || n.includes("/.terraform/") },
15496
+ { name: ".git", test: (n) => n === ".git" || n.startsWith(".git/") || n.includes("/.git/") },
15497
+ { name: ".runtype", test: (n) => n === ".runtype" || n.startsWith(".runtype/") || n.includes("/.runtype/") }
15498
+ ];
15499
+ function isSensitivePath(normalizedPath) {
15500
+ const n = normalizedPath.replace(/\\/g, "/").trim();
15501
+ if (!n) return false;
15502
+ return SENSITIVE_PATH_PATTERNS.some(({ test }) => test(n));
15503
+ }
15431
15504
  var DEFAULT_DISCOVERY_MAX_RESULTS = 50;
15432
15505
  var MAX_FILE_BYTES_TO_SCAN = 1024 * 1024;
15433
15506
  var LOW_SIGNAL_FILE_NAMES = /* @__PURE__ */ new Set([
@@ -15516,12 +15589,15 @@ function scoreSearchPath(relativePath) {
15516
15589
  return score;
15517
15590
  }
15518
15591
  function shouldIgnoreRepoEntry(entryPath) {
15519
- const normalized = normalizeToolPath(entryPath);
15592
+ const normalized = normalizeToolPath(entryPath).replace(/\\/g, "/");
15520
15593
  if (normalized === ".") return false;
15594
+ if (isSensitivePath(normalized)) return true;
15521
15595
  return normalized.split(path8.sep).some((segment) => IGNORED_REPO_DIRS.has(segment));
15522
15596
  }
15523
15597
  function safeReadTextFile(filePath) {
15524
15598
  try {
15599
+ const normalized = normalizeToolPath(filePath).replace(/\\/g, "/");
15600
+ if (isSensitivePath(normalized)) return null;
15525
15601
  const stat = fs8.statSync(filePath);
15526
15602
  if (!stat.isFile() || stat.size > MAX_FILE_BYTES_TO_SCAN) return null;
15527
15603
  const buffer = fs8.readFileSync(filePath);
@@ -15652,9 +15728,10 @@ function resolveToolPath(toolPath, options = {}) {
15652
15728
  return { ok: false, error: `Path does not exist: ${requestedPath}` };
15653
15729
  }
15654
15730
  const workspaceRoot = fs9.realpathSync.native(process.cwd());
15731
+ const extraRoots = (options.allowedRoots || []).map((rootPath) => canonicalizeAllowedRoot(rootPath));
15655
15732
  const allowedRoots = [
15656
- workspaceRoot,
15657
- ...(options.allowedRoots || []).map((rootPath) => canonicalizeAllowedRoot(rootPath))
15733
+ ...extraRoots,
15734
+ workspaceRoot
15658
15735
  ];
15659
15736
  const matchedRoot = allowedRoots.find(
15660
15737
  (rootPath) => isPathWithinRoot(resolved.canonicalPath, rootPath)
@@ -15673,6 +15750,13 @@ function resolveToolPath(toolPath, options = {}) {
15673
15750
  error: `Access denied: ${requestedPath} is inside restricted workspace state (${blockedSegment})`
15674
15751
  };
15675
15752
  }
15753
+ const relativeFromWorkspace = path9.relative(workspaceRoot, resolved.canonicalPath).replace(/\\/g, "/");
15754
+ if (isSensitivePath(relativeFromWorkspace)) {
15755
+ return {
15756
+ ok: false,
15757
+ error: `Access denied: ${requestedPath} is a sensitive path and cannot be read or written`
15758
+ };
15759
+ }
15676
15760
  }
15677
15761
  if (resolved.exists) {
15678
15762
  const stat = fs9.statSync(resolved.canonicalPath);
@@ -15693,8 +15777,17 @@ function resolveToolPath(toolPath, options = {}) {
15693
15777
  }
15694
15778
  return { ok: true, resolvedPath: resolved.canonicalPath };
15695
15779
  }
15780
+ function getTaskStateRoot(taskName, stateDir) {
15781
+ return path9.join(stateDir || getMarathonStateDir(), stateSafeName3(taskName));
15782
+ }
15696
15783
  function createDefaultLocalTools(context) {
15697
- const allowedReadRoots = context?.taskName ? [getOffloadedOutputDir(context.taskName, context.stateDir)] : [];
15784
+ const taskStateRoot = context?.taskName ? getTaskStateRoot(context.taskName, context.stateDir) : void 0;
15785
+ const planDir = context?.taskName ? path9.resolve(`.runtype/marathons/${stateSafeName3(context.taskName)}`) : void 0;
15786
+ const allowedReadRoots = context?.taskName ? [
15787
+ getOffloadedOutputDir(context.taskName, context.stateDir),
15788
+ ...taskStateRoot ? [taskStateRoot] : [],
15789
+ ...planDir ? [planDir] : []
15790
+ ] : [];
15698
15791
  return {
15699
15792
  read_file: {
15700
15793
  description: "Read the contents of a file at the given path",
@@ -15896,6 +15989,8 @@ function createDefaultLocalTools(context) {
15896
15989
  };
15897
15990
  }
15898
15991
  function createCheckpointedWriteFileTool(taskName, stateDir) {
15992
+ const taskStateRoot = getTaskStateRoot(taskName, stateDir);
15993
+ const planDir = path9.resolve(`.runtype/marathons/${stateSafeName3(taskName)}`);
15899
15994
  return {
15900
15995
  description: "Write content to a file, creating directories as needed and checkpointing original repo files",
15901
15996
  parametersSchema: {
@@ -15908,7 +16003,8 @@ function createCheckpointedWriteFileTool(taskName, stateDir) {
15908
16003
  },
15909
16004
  execute: async (args) => {
15910
16005
  const resolvedPath = resolveToolPath(String(args.path || ""), {
15911
- allowMissing: true
16006
+ allowMissing: true,
16007
+ allowedRoots: [taskStateRoot, planDir]
15912
16008
  });
15913
16009
  if (!resolvedPath.ok) return `Error: ${resolvedPath.error}`;
15914
16010
  const content = String(args.content || "");
@@ -15999,6 +16095,7 @@ function createRunCheckTool() {
15999
16095
  if (!isSafeVerificationCommand(command)) {
16000
16096
  return JSON.stringify({
16001
16097
  success: false,
16098
+ blocked: true,
16002
16099
  command,
16003
16100
  error: "Blocked unsafe verification command. Use a single non-destructive lint/test/typecheck/build command."
16004
16101
  });
@@ -16414,12 +16511,46 @@ function resolveModelForPhase(phase, cliOverrides, milestoneModels) {
16414
16511
  }
16415
16512
  return cliOverrides.defaultModel;
16416
16513
  }
16514
+ function resolveErrorHandlingForPhase(phase, cliFallbackModel, milestoneFallbackModels) {
16515
+ const phaseFallbacks = phase ? milestoneFallbackModels?.[phase] : void 0;
16516
+ if (phaseFallbacks?.length) {
16517
+ return {
16518
+ onError: "fallback",
16519
+ fallbacks: [
16520
+ { type: "retry", delay: 5e3 },
16521
+ ...phaseFallbacks.map((fb) => ({
16522
+ type: "model",
16523
+ model: fb.model,
16524
+ ...fb.temperature !== void 0 ? { temperature: fb.temperature } : {},
16525
+ ...fb.maxTokens !== void 0 ? { maxTokens: fb.maxTokens } : {}
16526
+ }))
16527
+ ]
16528
+ };
16529
+ }
16530
+ if (cliFallbackModel) {
16531
+ return {
16532
+ onError: "fallback",
16533
+ fallbacks: [
16534
+ { type: "retry", delay: 5e3 },
16535
+ { type: "model", model: cliFallbackModel }
16536
+ ]
16537
+ };
16538
+ }
16539
+ return void 0;
16540
+ }
16417
16541
 
16418
16542
  // src/marathon/playbook-loader.ts
16419
16543
  import * as fs12 from "fs";
16420
16544
  import * as path12 from "path";
16421
16545
  import * as os4 from "os";
16546
+ import micromatch from "micromatch";
16422
16547
  import { parse as parseYaml } from "yaml";
16548
+ var DISCOVERY_TOOLS = /* @__PURE__ */ new Set([
16549
+ "search_repo",
16550
+ "glob_files",
16551
+ "tree_directory",
16552
+ "list_directory"
16553
+ ]);
16423
16554
  var PLAYBOOKS_DIR = ".runtype/marathons/playbooks";
16424
16555
  function getCandidatePaths(nameOrPath, cwd) {
16425
16556
  const home = os4.homedir();
@@ -16494,7 +16625,54 @@ function buildIsComplete(criteria) {
16494
16625
  return () => false;
16495
16626
  }
16496
16627
  }
16628
+ function buildPolicyIntercept(policy) {
16629
+ if (!policy.blockedTools?.length && !policy.blockDiscoveryTools && !policy.allowedReadGlobs?.length && !policy.allowedWriteGlobs?.length && !policy.requirePlanBeforeWrite) {
16630
+ return void 0;
16631
+ }
16632
+ const blockedSet = new Set(
16633
+ (policy.blockedTools ?? []).map((t) => t.trim()).filter(Boolean)
16634
+ );
16635
+ const readGlobs = policy.allowedReadGlobs ?? [];
16636
+ const writeGlobs = policy.allowedWriteGlobs ?? [];
16637
+ return (toolName, args, ctx) => {
16638
+ if (blockedSet.has(toolName)) {
16639
+ return `Blocked by playbook policy: ${toolName} is not allowed for this task.`;
16640
+ }
16641
+ if (policy.blockDiscoveryTools && DISCOVERY_TOOLS.has(toolName)) {
16642
+ return `Blocked by playbook policy: discovery tools are disabled for this task.`;
16643
+ }
16644
+ const pathArg = typeof args.path === "string" && args.path.trim() ? ctx.normalizePath(String(args.path)) : void 0;
16645
+ if (pathArg) {
16646
+ const isWrite = toolName === "write_file" || toolName === "restore_file_checkpoint";
16647
+ const isRead = toolName === "read_file";
16648
+ if (isRead && readGlobs.length > 0) {
16649
+ const allowed = micromatch.some(pathArg, readGlobs, { dot: true });
16650
+ if (!allowed) {
16651
+ return `Blocked by playbook policy: ${toolName} path "${pathArg}" is outside allowed read globs: ${readGlobs.join(", ")}`;
16652
+ }
16653
+ }
16654
+ if (isWrite && writeGlobs.length > 0) {
16655
+ const planPath = ctx.state.planPath ? ctx.normalizePath(ctx.state.planPath) : void 0;
16656
+ if (planPath && pathArg === planPath) {
16657
+ } else {
16658
+ const allowed = micromatch.some(pathArg, writeGlobs, { dot: true });
16659
+ if (!allowed) {
16660
+ return `Blocked by playbook policy: ${toolName} path "${pathArg}" is outside allowed write globs: ${writeGlobs.join(", ")}`;
16661
+ }
16662
+ }
16663
+ }
16664
+ if (isWrite && policy.requirePlanBeforeWrite && !ctx.state.planWritten && !ctx.trace.planWritten) {
16665
+ const planPath = ctx.state.planPath ? ctx.normalizePath(ctx.state.planPath) : void 0;
16666
+ if (!planPath || pathArg !== planPath) {
16667
+ return `Blocked by playbook policy: write the plan before creating other files.`;
16668
+ }
16669
+ }
16670
+ }
16671
+ return void 0;
16672
+ };
16673
+ }
16497
16674
  function convertToWorkflow(config2) {
16675
+ const policyIntercept = config2.policy ? buildPolicyIntercept(config2.policy) : void 0;
16498
16676
  const phases = config2.milestones.map((milestone) => ({
16499
16677
  name: milestone.name,
16500
16678
  description: milestone.description,
@@ -16510,6 +16688,7 @@ ${instructions}`;
16510
16688
  return milestone.toolGuidance ?? [];
16511
16689
  },
16512
16690
  isComplete: buildIsComplete(milestone.completionCriteria),
16691
+ interceptToolCall: policyIntercept,
16513
16692
  // Default to rejecting TASK_COMPLETE unless the playbook explicitly allows it.
16514
16693
  // The SDK accepts completion by default when canAcceptCompletion is undefined,
16515
16694
  // which would let the model end the marathon prematurely in early phases.
@@ -16520,23 +16699,37 @@ ${instructions}`;
16520
16699
  phases
16521
16700
  };
16522
16701
  }
16702
+ function normalizeFallbackModel(input) {
16703
+ if (typeof input === "string") return { model: input };
16704
+ return {
16705
+ model: input.model,
16706
+ ...input.temperature !== void 0 ? { temperature: input.temperature } : {},
16707
+ ...input.maxTokens !== void 0 ? { maxTokens: input.maxTokens } : {}
16708
+ };
16709
+ }
16523
16710
  function loadPlaybook(nameOrPath, cwd) {
16524
16711
  const baseCwd = cwd || process.cwd();
16525
16712
  const candidates = getCandidatePaths(nameOrPath, baseCwd);
16526
16713
  for (const candidate of candidates) {
16527
- if (!fs12.existsSync(candidate)) continue;
16714
+ if (!fs12.existsSync(candidate) || fs12.statSync(candidate).isDirectory()) continue;
16528
16715
  const config2 = parsePlaybookFile(candidate);
16529
16716
  validatePlaybook(config2, candidate);
16530
16717
  const milestoneModels = {};
16718
+ const milestoneFallbackModels = {};
16531
16719
  for (const m of config2.milestones) {
16532
16720
  if (m.model) milestoneModels[m.name] = m.model;
16721
+ if (m.fallbackModels?.length) {
16722
+ milestoneFallbackModels[m.name] = m.fallbackModels.map(normalizeFallbackModel);
16723
+ }
16533
16724
  }
16534
16725
  return {
16535
16726
  workflow: convertToWorkflow(config2),
16536
16727
  milestones: config2.milestones.map((m) => m.name),
16537
16728
  milestoneModels: Object.keys(milestoneModels).length > 0 ? milestoneModels : void 0,
16729
+ milestoneFallbackModels: Object.keys(milestoneFallbackModels).length > 0 ? milestoneFallbackModels : void 0,
16538
16730
  verification: config2.verification,
16539
- rules: config2.rules
16731
+ rules: config2.rules,
16732
+ policy: config2.policy
16540
16733
  };
16541
16734
  }
16542
16735
  throw new Error(
@@ -16564,7 +16757,7 @@ function shouldRequestResumeCheckpoint(status, resumeMessage, noCheckpoint, orig
16564
16757
  return false;
16565
16758
  }
16566
16759
  function buildResumeCheckpointRecap(state, snapshots) {
16567
- const latestSnapshot = snapshots[snapshots.length - 1];
16760
+ const totalToolCalls = snapshots.reduce((sum, s) => sum + s.tools.length, 0);
16568
16761
  const derivedTokens = state.sessions?.reduce(
16569
16762
  (totals, session) => ({
16570
16763
  input: totals.input + (session.totalTokens?.input ?? 0),
@@ -16575,7 +16768,7 @@ function buildResumeCheckpointRecap(state, snapshots) {
16575
16768
  const resumeTokens = state.totalTokens ?? derivedTokens;
16576
16769
  return {
16577
16770
  sessionNumber: state.sessionCount,
16578
- toolCallsMade: latestSnapshot?.tools.length ?? 0,
16771
+ toolCallsMade: totalToolCalls,
16579
16772
  tokensInput: resumeTokens.input,
16580
16773
  tokensOutput: resumeTokens.output,
16581
16774
  cost: state.totalCost,
@@ -16701,13 +16894,22 @@ function normalizeMarathonAgentArgument(agent) {
16701
16894
  function buildMarathonAutoCreatedAgentBootstrap(agentName, options = {}) {
16702
16895
  const normalizedModel = options.model?.trim();
16703
16896
  const normalizedToolIds = [...new Set((options.toolIds || []).map((toolId) => toolId.trim()).filter(Boolean))];
16704
- const config2 = normalizedModel || normalizedToolIds.length > 0 ? {
16897
+ const normalizedFallbackModel = options.fallbackModel?.trim();
16898
+ const errorHandling = normalizedFallbackModel ? {
16899
+ onError: "fallback",
16900
+ fallbacks: [
16901
+ { type: "retry", delay: 5e3 },
16902
+ { type: "model", model: normalizedFallbackModel }
16903
+ ]
16904
+ } : void 0;
16905
+ const config2 = normalizedModel || normalizedToolIds.length > 0 || errorHandling ? {
16705
16906
  ...normalizedModel ? { model: normalizedModel } : {},
16706
16907
  ...normalizedToolIds.length > 0 ? {
16707
16908
  tools: {
16708
16909
  toolIds: normalizedToolIds
16709
16910
  }
16710
- } : {}
16911
+ } : {},
16912
+ ...errorHandling ? { errorHandling } : {}
16711
16913
  } : void 0;
16712
16914
  return {
16713
16915
  description: `Powering a marathon for ${agentName}`,
@@ -17061,11 +17263,17 @@ async function taskAction(agent, options) {
17061
17263
  let playbookWorkflow;
17062
17264
  let playbookMilestones;
17063
17265
  let playbookMilestoneModels;
17266
+ let playbookMilestoneFallbackModels;
17267
+ let playbookPolicy;
17064
17268
  if (options.playbook) {
17065
17269
  const result = loadPlaybook(options.playbook);
17066
17270
  playbookWorkflow = result.workflow;
17067
17271
  playbookMilestones = result.milestones;
17068
17272
  playbookMilestoneModels = result.milestoneModels;
17273
+ playbookMilestoneFallbackModels = result.milestoneFallbackModels;
17274
+ playbookPolicy = result.policy;
17275
+ } else {
17276
+ playbookPolicy = void 0;
17069
17277
  }
17070
17278
  if (useStartupShell && !options.model?.trim()) {
17071
17279
  if (playbookMilestoneModels && Object.keys(playbookMilestoneModels).length > 0 && startupShellRef.current) {
@@ -17166,7 +17374,8 @@ ${rulesContext}`;
17166
17374
  if (autoCreatedAgent) {
17167
17375
  const bootstrapPayload = buildMarathonAutoCreatedAgentBootstrap(normalizedAgent, {
17168
17376
  model: options.model || agentConfigModel || defaultConfiguredModel,
17169
- toolIds: resolvedToolIds
17377
+ toolIds: resolvedToolIds,
17378
+ fallbackModel: options.fallbackModel
17170
17379
  });
17171
17380
  try {
17172
17381
  await client.agents.update(agentId, bootstrapPayload);
@@ -17182,6 +17391,16 @@ ${rulesContext}`;
17182
17391
  );
17183
17392
  }
17184
17393
  }
17394
+ } else if (options.fallbackModel || playbookMilestoneFallbackModels) {
17395
+ const initialErrorHandling = resolveErrorHandlingForPhase(
17396
+ currentPhase,
17397
+ options.fallbackModel,
17398
+ playbookMilestoneFallbackModels
17399
+ );
17400
+ if (initialErrorHandling) {
17401
+ await client.agents.update(agentId, { config: { errorHandling: initialErrorHandling } }).catch(() => {
17402
+ });
17403
+ }
17185
17404
  }
17186
17405
  let localTools = buildLocalTools(client, parsedSandbox, options, {
17187
17406
  taskName,
@@ -17390,6 +17609,7 @@ Saving state... done. Session saved to ${filePath}`);
17390
17609
  let accumulatedSessions = 0;
17391
17610
  let accumulatedCost = 0;
17392
17611
  let accumulatedTokens = { input: 0, output: 0 };
17612
+ let accumulatedToolCalls = 0;
17393
17613
  let lastResult = null;
17394
17614
  let lastSessionMessages = [];
17395
17615
  if (resumeLoadedState) {
@@ -17441,6 +17661,7 @@ Saving state... done. Session saved to ${filePath}`);
17441
17661
  maxSessions: remainingSessions - accumulatedSessions,
17442
17662
  maxCost: currentRemainingCost,
17443
17663
  model: phaseModel || options.model,
17664
+ reasoning: !options.noReasoning,
17444
17665
  debugMode: options.debug ?? true,
17445
17666
  stream: true,
17446
17667
  streamCallbacks: currentStreamCallbacks,
@@ -17482,7 +17703,13 @@ Saving state... done. Session saved to ${filePath}`);
17482
17703
  model: event.model || effectiveModelForContext
17483
17704
  });
17484
17705
  },
17485
- ...resumeState ? { resumeState } : {},
17706
+ ...resumeState || playbookPolicy ? {
17707
+ resumeState: {
17708
+ ...resumeState ?? {},
17709
+ ...playbookPolicy?.outputRoot ? { outputRoot: playbookPolicy.outputRoot } : {},
17710
+ ...playbookPolicy?.requireVerification !== void 0 ? { verificationRequired: playbookPolicy.requireVerification } : {}
17711
+ }
17712
+ } : {},
17486
17713
  toolContextMode: options.toolContext || "hot-tail",
17487
17714
  toolWindow: options.toolWindow === "session" || !options.toolWindow ? "session" : parseInt(options.toolWindow, 10) || 10,
17488
17715
  onSession: async (state) => {
@@ -17544,12 +17771,32 @@ Saving state... done. Session saved to ${filePath}`);
17544
17771
  options.model = newPhaseModel;
17545
17772
  modelChangedOnPhaseTransition = true;
17546
17773
  }
17774
+ if (options.fallbackModel || playbookMilestoneFallbackModels) {
17775
+ const newErrorHandling = resolveErrorHandlingForPhase(
17776
+ resumeState.workflowPhase,
17777
+ options.fallbackModel,
17778
+ playbookMilestoneFallbackModels
17779
+ );
17780
+ client.agents.update(agentId, {
17781
+ config: { errorHandling: newErrorHandling ?? null }
17782
+ }).catch(() => {
17783
+ });
17784
+ }
17547
17785
  }
17548
17786
  if (state.recentActionKeys && state.recentActionKeys.length > 0) {
17549
17787
  for (const key of state.recentActionKeys) {
17550
17788
  loopDetector.recordAction(key);
17551
17789
  }
17552
17790
  }
17791
+ if (loopDetector.isLooping() && state.status === "running") {
17792
+ const checkpointMsg = loopDetector.getCheckpointMessage();
17793
+ loopDetector.reset();
17794
+ taskMessage = checkpointMsg;
17795
+ continuationMessage = checkpointMsg;
17796
+ useCompact = false;
17797
+ shouldContinue = true;
17798
+ return false;
17799
+ }
17553
17800
  if (modelChangedOnPhaseTransition) {
17554
17801
  shouldContinue = true;
17555
17802
  return false;
@@ -17559,10 +17806,10 @@ Saving state... done. Session saved to ${filePath}`);
17559
17806
  if (!currentActions) return;
17560
17807
  const recap = {
17561
17808
  sessionNumber: adjustedState.sessionCount,
17562
- toolCallsMade: currentActions.getState().tools.length,
17563
- tokensInput: state.totalTokens?.input ?? 0,
17564
- tokensOutput: state.totalTokens?.output ?? 0,
17565
- cost: state.totalCost,
17809
+ toolCallsMade: accumulatedToolCalls + currentActions.getState().tools.length,
17810
+ tokensInput: accumulatedTokens.input + (state.totalTokens?.input ?? 0),
17811
+ tokensOutput: accumulatedTokens.output + (state.totalTokens?.output ?? 0),
17812
+ cost: adjustedState.totalCost,
17566
17813
  outputPreview: adjustedState.lastOutput.slice(0, 100)
17567
17814
  };
17568
17815
  const checkpointResult = await currentActions.requestCheckpoint(recap);
@@ -17645,6 +17892,7 @@ Saving state... done. Session saved to ${filePath}`);
17645
17892
  output: accumulatedTokens.output + result2.totalTokens.output
17646
17893
  };
17647
17894
  }
17895
+ accumulatedToolCalls += streamRef.current?.getState().tools.length ?? 0;
17648
17896
  lastResult = result2;
17649
17897
  if (result2.status === "complete") {
17650
17898
  streamRef.current?.updateMilestone("complete");
@@ -17665,7 +17913,7 @@ Saving state... done. Session saved to ${filePath}`);
17665
17913
  const terminalPreview = knownState2?.lastOutput ?? currentActions.getState().content;
17666
17914
  const recap = {
17667
17915
  sessionNumber: priorSessionCount + accumulatedSessions,
17668
- toolCallsMade: currentActions.getState().tools.length,
17916
+ toolCallsMade: accumulatedToolCalls,
17669
17917
  tokensInput: accumulatedTokens.input,
17670
17918
  tokensOutput: accumulatedTokens.output,
17671
17919
  cost: accumulatedCost,
@@ -17879,7 +18127,7 @@ ${details}`);
17879
18127
  }
17880
18128
  return resolved;
17881
18129
  }
17882
- function detectSandboxWorkflow(message, resumeState) {
18130
+ function detectDeployWorkflow(_message, sandboxProvider, resumeState) {
17883
18131
  if (resumeState?.workflowVariant === "game") return gameWorkflow;
17884
18132
  if (resumeState?.workflowPhase === "design" || resumeState?.workflowPhase === "build" || resumeState?.workflowPhase === "verify") {
17885
18133
  return gameWorkflow;
@@ -17888,52 +18136,6 @@ function detectSandboxWorkflow(message, resumeState) {
17888
18136
  if (resumeState?.workflowPhase === "scaffold" || resumeState?.workflowPhase === "deploy") {
17889
18137
  return deployWorkflow;
17890
18138
  }
17891
- const lower = message.toLowerCase();
17892
- const gamePatterns = [
17893
- /\b3d\b.*\bgame\b/,
17894
- /\bgame\b.*\b3d\b/,
17895
- /\bthree\.?js\b/,
17896
- /\bphaser\b/,
17897
- /\bwebgl\b/,
17898
- /\bplatformer\b/,
17899
- /\bracing\b.*\bgame\b/,
17900
- /\bgame\b.*\bracing\b/,
17901
- /\bgame\b/
17902
- ];
17903
- if (gamePatterns.some((p) => p.test(lower))) {
17904
- return gameWorkflow;
17905
- }
17906
- const deployPatterns = [
17907
- /\bdeploy\b/,
17908
- /\bsandbox\b/,
17909
- /\bpreview\s*url\b/,
17910
- /\blive\s*preview\b/,
17911
- /\bhost(?:ed|ing)?\b.*\b(?:app|server|api|site)\b/,
17912
- /\b(?:app|server|api|site)\b.*\bhost(?:ed|ing)?\b/,
17913
- /\b(?:run|launch|start)\b.*\b(?:app|server|api|site|web\s*app|web\s*server)\b/,
17914
- /\bnpx\s+serve\b/,
17915
- /\bserve(?:d|s|ing)?\b.*\b(?:app|site|preview|route|routes|localhost|url|urls)\b/,
17916
- /\b(?:route|routes|preview|localhost|url|urls)\b.*\bserve(?:d|s|ing)?\b/,
17917
- /\bverify\b.*\b(?:route|routes|preview|localhost|url|urls)\b/,
17918
- /\bmulti[-\s]route\b/,
17919
- /\b(?:serve|start|run|listen)\b.{0,40}\bport\s*\d{2,5}\b/,
17920
- /\bport\s*\d{2,5}\b.{0,40}\b(?:serve|server|preview|localhost|route|routes)\b/
17921
- ];
17922
- if (deployPatterns.some((p) => p.test(lower))) {
17923
- return deployWorkflow;
17924
- }
17925
- const webAppPatterns = [
17926
- /\bbuild\b.*\b(?:web\s*app|website|api|server|express|hono|fastify)\b/,
17927
- /\bcreate\b.*\b(?:web\s*app|website|api|server|express|hono|fastify)\b/,
17928
- /\bmake\b.*\b(?:web\s*app|website|api|server|express|hono|fastify)\b/
17929
- ];
17930
- const repoEditPatterns = [
17931
- /\b(?:edit|modify|update|fix|refactor|change|patch|rename|remove)\b.*\b(?:file|files|repo|repository|codebase|project|directory|folder|component|module|page|route|router)\b/,
17932
- /\b(?:file|files|repo|repository|codebase|project|directory|folder|component|module|page|route|router)\b.*\b(?:edit|modify|update|fix|refactor|change|patch|rename|remove)\b/
17933
- ];
17934
- if (webAppPatterns.some((p) => p.test(lower)) && !repoEditPatterns.some((p) => p.test(lower))) {
17935
- return deployWorkflow;
17936
- }
17937
18139
  return void 0;
17938
18140
  }
17939
18141
  function resolveSandboxWorkflowSelection(message, sandboxProvider, resumeState) {
@@ -17943,7 +18145,7 @@ function resolveSandboxWorkflowSelection(message, sandboxProvider, resumeState)
17943
18145
  sandboxProvider
17944
18146
  };
17945
18147
  }
17946
- const workflow = detectSandboxWorkflow(message, resumeState);
18148
+ const workflow = detectDeployWorkflow(message, sandboxProvider, resumeState);
17947
18149
  if (!workflow) {
17948
18150
  return {
17949
18151
  workflow: void 0,
@@ -17956,7 +18158,7 @@ function resolveSandboxWorkflowSelection(message, sandboxProvider, resumeState)
17956
18158
  };
17957
18159
  }
17958
18160
  function applyTaskOptions(cmd) {
17959
- 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-checkpoint", "Run all iterations without checkpoint pauses (fully autonomous)").option("--checkpoint-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("--playbook <name>", "Load a playbook from .runtype/marathons/playbooks/").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);
18161
+ 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-reasoning", "Disable model reasoning/thinking (enabled by default for supported models)").option("--no-checkpoint", "Run all iterations without checkpoint pauses (fully autonomous)").option("--checkpoint-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("--fallback-model <modelId>", "Model to fall back to when primary model fails").option("--playbook <name>", "Load a playbook from .runtype/marathons/playbooks/").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);
17960
18162
  }
17961
18163
  var taskCommand = applyTaskOptions(
17962
18164
  new Command10("task").description("Run a multi-session agent task")
@@ -18009,7 +18211,7 @@ agentsCommand.command("list").description("List all agents").option("--json", "O
18009
18211
  const [items, setItems] = useState24(null);
18010
18212
  const [error, setError] = useState24(null);
18011
18213
  const [total, setTotal] = useState24();
18012
- useEffect22(() => {
18214
+ useEffect21(() => {
18013
18215
  client.get("/agents", { limit: options.limit }).then((res) => {
18014
18216
  setItems(res.data ?? []);
18015
18217
  setTotal(getTotalCount(res.pagination));
@@ -18069,7 +18271,7 @@ agentsCommand.command("get <id>").description("Get agent details").option("--jso
18069
18271
  const App = () => {
18070
18272
  const [items, setItems] = useState24(null);
18071
18273
  const [error, setError] = useState24(null);
18072
- useEffect22(() => {
18274
+ useEffect21(() => {
18073
18275
  client.get(`/agents/${id}`).then((res) => setItems([res])).catch((err) => setError(err instanceof Error ? err : new Error(String(err))));
18074
18276
  }, []);
18075
18277
  return React10.createElement(DataList, {
@@ -18123,7 +18325,7 @@ agentsCommand.command("create").description("Create a new agent").requiredOption
18123
18325
  const [success, setSuccess] = useState24(null);
18124
18326
  const [error, setError] = useState24(null);
18125
18327
  const [result, setResult] = useState24(null);
18126
- useEffect22(() => {
18328
+ useEffect21(() => {
18127
18329
  client.post("/agents", {
18128
18330
  name: options.name,
18129
18331
  description: options.description
@@ -18174,7 +18376,7 @@ agentsCommand.command("delete <id>").description("Delete an agent").option("--tt
18174
18376
  const [loading, setLoading] = useState24(false);
18175
18377
  const [success, setSuccess] = useState24(null);
18176
18378
  const [error, setError] = useState24(null);
18177
- useEffect22(() => {
18379
+ useEffect21(() => {
18178
18380
  if (confirmed !== true) return void 0;
18179
18381
  setLoading(true);
18180
18382
  client.delete(`/agents/${id}`).then(() => {
@@ -18264,7 +18466,7 @@ import { Command as Command12 } from "commander";
18264
18466
  import chalk18 from "chalk";
18265
18467
  import React11 from "react";
18266
18468
  import { render as render11 } from "ink";
18267
- import { useState as useState25, useEffect as useEffect23 } from "react";
18469
+ import { useState as useState25, useEffect as useEffect22 } from "react";
18268
18470
  var modelsCommand = new Command12("models").description("Manage model configurations");
18269
18471
  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) => {
18270
18472
  const apiKey = await ensureAuth();
@@ -18304,7 +18506,7 @@ modelsCommand.command("list").description("List your enabled model configuration
18304
18506
  const [items, setItems] = useState25(null);
18305
18507
  const [error, setError] = useState25(null);
18306
18508
  const [total, setTotal] = useState25();
18307
- useEffect23(() => {
18509
+ useEffect22(() => {
18308
18510
  client.get("/model-configs").then((res) => {
18309
18511
  setItems(res.data ?? []);
18310
18512
  setTotal(getTotalCount(res.pagination));
@@ -18368,7 +18570,7 @@ modelsCommand.command("available").description("List all available models groupe
18368
18570
  const App = () => {
18369
18571
  const [items, setItems] = useState25(null);
18370
18572
  const [error, setError] = useState25(null);
18371
- useEffect23(() => {
18573
+ useEffect22(() => {
18372
18574
  client.get("/model-configs/grouped").then((res) => setItems(res.data ?? [])).catch((err) => setError(err instanceof Error ? err : new Error(String(err))));
18373
18575
  }, []);
18374
18576
  return React11.createElement(DataList, {
@@ -18418,7 +18620,7 @@ modelsCommand.command("enable <modelId>").description("Enable a model by creatin
18418
18620
  const [success, setSuccess] = useState25(null);
18419
18621
  const [error, setError] = useState25(null);
18420
18622
  const [result, setResult] = useState25(null);
18421
- useEffect23(() => {
18623
+ useEffect22(() => {
18422
18624
  client.post("/model-configs", { modelId }).then((data) => {
18423
18625
  setResult(data);
18424
18626
  setSuccess(true);
@@ -18465,7 +18667,7 @@ modelsCommand.command("disable <id>").description("Disable a model configuration
18465
18667
  const [loading, setLoading] = useState25(true);
18466
18668
  const [success, setSuccess] = useState25(null);
18467
18669
  const [error, setError] = useState25(null);
18468
- useEffect23(() => {
18670
+ useEffect22(() => {
18469
18671
  client.patch(`/model-configs/${id}/status`, { enabled: false }).then(() => {
18470
18672
  setSuccess(true);
18471
18673
  setLoading(false);
@@ -18505,7 +18707,7 @@ modelsCommand.command("default <id>").description("Set a model configuration as
18505
18707
  const [loading, setLoading] = useState25(true);
18506
18708
  const [success, setSuccess] = useState25(null);
18507
18709
  const [error, setError] = useState25(null);
18508
- useEffect23(() => {
18710
+ useEffect22(() => {
18509
18711
  client.patch(`/model-configs/${id}/default`, {}).then(() => {
18510
18712
  setSuccess(true);
18511
18713
  setLoading(false);
@@ -18546,7 +18748,7 @@ import { Command as Command13 } from "commander";
18546
18748
  import chalk19 from "chalk";
18547
18749
  import React12 from "react";
18548
18750
  import { render as render12 } from "ink";
18549
- import { useState as useState26, useEffect as useEffect24 } from "react";
18751
+ import { useState as useState26, useEffect as useEffect23 } from "react";
18550
18752
  var schedulesCommand = new Command13("schedules").description("Manage schedules");
18551
18753
  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) => {
18552
18754
  const apiKey = await ensureAuth();
@@ -18593,7 +18795,7 @@ schedulesCommand.command("list").description("List all schedules").option("--jso
18593
18795
  const [items, setItems] = useState26(null);
18594
18796
  const [error, setError] = useState26(null);
18595
18797
  const [total, setTotal] = useState26();
18596
- useEffect24(() => {
18798
+ useEffect23(() => {
18597
18799
  client.get("/schedules").then((res) => {
18598
18800
  setItems(res.data ?? []);
18599
18801
  setTotal(getTotalCount(res.pagination));
@@ -18658,7 +18860,7 @@ schedulesCommand.command("get <id>").description("Get schedule details").option(
18658
18860
  const App = () => {
18659
18861
  const [items, setItems] = useState26(null);
18660
18862
  const [error, setError] = useState26(null);
18661
- useEffect24(() => {
18863
+ useEffect23(() => {
18662
18864
  client.get(`/schedules/${id}`).then((res) => setItems([res])).catch((err) => setError(err instanceof Error ? err : new Error(String(err))));
18663
18865
  }, []);
18664
18866
  return React12.createElement(DataList, {
@@ -18716,7 +18918,7 @@ schedulesCommand.command("create").description("Create a new schedule").required
18716
18918
  const [success, setSuccess] = useState26(null);
18717
18919
  const [error, setError] = useState26(null);
18718
18920
  const [result, setResult] = useState26(null);
18719
- useEffect24(() => {
18921
+ useEffect23(() => {
18720
18922
  client.post("/schedules", {
18721
18923
  flowId: options.flow,
18722
18924
  cronExpression: options.cron,
@@ -18770,7 +18972,7 @@ function simpleMutationCommand(name, description, mutationFn, successMsg, loadin
18770
18972
  const [loading, setLoading] = useState26(true);
18771
18973
  const [success, setSuccess] = useState26(null);
18772
18974
  const [error, setError] = useState26(null);
18773
- useEffect24(() => {
18975
+ useEffect23(() => {
18774
18976
  mutationFn(client, id).then(() => {
18775
18977
  setSuccess(true);
18776
18978
  setLoading(false);
@@ -18833,7 +19035,7 @@ schedulesCommand.command("delete <id>").description("Delete a schedule").option(
18833
19035
  const [loading, setLoading] = useState26(false);
18834
19036
  const [success, setSuccess] = useState26(null);
18835
19037
  const [error, setError] = useState26(null);
18836
- useEffect24(() => {
19038
+ useEffect23(() => {
18837
19039
  if (confirmed !== true) return void 0;
18838
19040
  setLoading(true);
18839
19041
  client.delete(`/schedules/${id}`).then(() => {
@@ -18877,7 +19079,7 @@ import { Command as Command14 } from "commander";
18877
19079
  import chalk20 from "chalk";
18878
19080
  import React13 from "react";
18879
19081
  import { render as render13 } from "ink";
18880
- import { useState as useState27, useEffect as useEffect25 } from "react";
19082
+ import { useState as useState27, useEffect as useEffect24 } from "react";
18881
19083
  import { Text as Text30 } from "ink";
18882
19084
  import { readFileSync as readFileSync13 } from "fs";
18883
19085
  var evalCommand = new Command14("eval").description("Manage evaluations");
@@ -18926,7 +19128,7 @@ evalCommand.command("submit").description("Submit an eval batch").requiredOption
18926
19128
  const [success, setSuccess] = useState27(null);
18927
19129
  const [error, setError] = useState27(null);
18928
19130
  const [resultNode, setResultNode] = useState27(void 0);
18929
- useEffect25(() => {
19131
+ useEffect24(() => {
18930
19132
  const run = async () => {
18931
19133
  try {
18932
19134
  const data = await client.post("/eval/submit", {
@@ -19009,7 +19211,7 @@ evalCommand.command("list").description("List eval batches").option("--flow <id>
19009
19211
  const [items, setItems] = useState27(null);
19010
19212
  const [total, setTotal] = useState27(void 0);
19011
19213
  const [error, setError] = useState27(null);
19012
- useEffect25(() => {
19214
+ useEffect24(() => {
19013
19215
  const run = async () => {
19014
19216
  try {
19015
19217
  const data = await client.get("/eval/batches", params);
@@ -19089,7 +19291,7 @@ evalCommand.command("results <id>").description("Get eval batch results").option
19089
19291
  const [success, setSuccess] = useState27(null);
19090
19292
  const [error, setError] = useState27(null);
19091
19293
  const [resultNode, setResultNode] = useState27(void 0);
19092
- useEffect25(() => {
19294
+ useEffect24(() => {
19093
19295
  const run = async () => {
19094
19296
  try {
19095
19297
  const data = await client.get(`/eval/${id}/results`);
@@ -19152,7 +19354,7 @@ evalCommand.command("compare <groupId>").description("Compare evals in a group")
19152
19354
  const [loading, setLoading] = useState27(true);
19153
19355
  const [success, setSuccess] = useState27(null);
19154
19356
  const [error, setError] = useState27(null);
19155
- useEffect25(() => {
19357
+ useEffect24(() => {
19156
19358
  const run = async () => {
19157
19359
  try {
19158
19360
  const data = await client.post("/eval/compare", { groupId });
@@ -19184,7 +19386,7 @@ import { Command as Command15 } from "commander";
19184
19386
  import chalk21 from "chalk";
19185
19387
  import React14 from "react";
19186
19388
  import { render as render14 } from "ink";
19187
- import { useState as useState28, useEffect as useEffect26 } from "react";
19389
+ import { useState as useState28, useEffect as useEffect25 } from "react";
19188
19390
  import { Text as Text31 } from "ink";
19189
19391
  var apiKeysCommand = new Command15("api-keys").description("Manage API keys");
19190
19392
  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) => {
@@ -19227,7 +19429,7 @@ apiKeysCommand.command("list").description("List your API keys").option("--json"
19227
19429
  const [items, setItems] = useState28(null);
19228
19430
  const [total, setTotal] = useState28(void 0);
19229
19431
  const [error, setError] = useState28(null);
19230
- useEffect26(() => {
19432
+ useEffect25(() => {
19231
19433
  const run = async () => {
19232
19434
  try {
19233
19435
  const data = await client.get("/api-keys");
@@ -19291,7 +19493,7 @@ apiKeysCommand.command("get <id>").description("Get API key details").option("--
19291
19493
  const [success, setSuccess] = useState28(null);
19292
19494
  const [error, setError] = useState28(null);
19293
19495
  const [resultNode, setResultNode] = useState28(void 0);
19294
- useEffect26(() => {
19496
+ useEffect25(() => {
19295
19497
  const run = async () => {
19296
19498
  try {
19297
19499
  const data = await client.get(`/api-keys/${id}`);
@@ -19360,7 +19562,7 @@ apiKeysCommand.command("create").description("Create a new API key").requiredOpt
19360
19562
  const [success, setSuccess] = useState28(null);
19361
19563
  const [error, setError] = useState28(null);
19362
19564
  const [resultNode, setResultNode] = useState28(void 0);
19363
- useEffect26(() => {
19565
+ useEffect25(() => {
19364
19566
  const run = async () => {
19365
19567
  try {
19366
19568
  const data = await client.post("/api-keys", {
@@ -19418,7 +19620,7 @@ apiKeysCommand.command("delete <id>").description("Delete an API key").option("-
19418
19620
  const [loading, setLoading] = useState28(true);
19419
19621
  const [success, setSuccess] = useState28(null);
19420
19622
  const [error, setError] = useState28(null);
19421
- useEffect26(() => {
19623
+ useEffect25(() => {
19422
19624
  const run = async () => {
19423
19625
  try {
19424
19626
  await client.delete(`/api-keys/${id}`);
@@ -19461,7 +19663,7 @@ apiKeysCommand.command("delete <id>").description("Delete an API key").option("-
19461
19663
  const [loading, setLoading] = useState28(true);
19462
19664
  const [success, setSuccess] = useState28(null);
19463
19665
  const [error, setError] = useState28(null);
19464
- useEffect26(() => {
19666
+ useEffect25(() => {
19465
19667
  const run = async () => {
19466
19668
  try {
19467
19669
  await client.delete(`/api-keys/${id}`);
@@ -19515,7 +19717,7 @@ apiKeysCommand.command("regenerate <id>").description("Regenerate an API key").o
19515
19717
  const [success, setSuccess] = useState28(null);
19516
19718
  const [error, setError] = useState28(null);
19517
19719
  const [resultNode, setResultNode] = useState28(void 0);
19518
- useEffect26(() => {
19720
+ useEffect25(() => {
19519
19721
  const run = async () => {
19520
19722
  try {
19521
19723
  const data = await client.post(`/api-keys/${id}/regenerate`);
@@ -19570,7 +19772,7 @@ apiKeysCommand.command("analytics").description("Show API key usage analytics").
19570
19772
  const [loading, setLoading] = useState28(true);
19571
19773
  const [success, setSuccess] = useState28(null);
19572
19774
  const [error, setError] = useState28(null);
19573
- useEffect26(() => {
19775
+ useEffect25(() => {
19574
19776
  const run = async () => {
19575
19777
  try {
19576
19778
  const path13 = options.key ? `/api-keys/${options.key}/analytics` : "/api-keys/analytics";
@@ -19603,7 +19805,7 @@ import { Command as Command16 } from "commander";
19603
19805
  import chalk22 from "chalk";
19604
19806
  import React15 from "react";
19605
19807
  import { render as render15 } from "ink";
19606
- import { useState as useState29, useEffect as useEffect27 } from "react";
19808
+ import { useState as useState29, useEffect as useEffect26 } from "react";
19607
19809
  import { Text as Text32 } from "ink";
19608
19810
  var analyticsCommand = new Command16("analytics").description("View analytics and execution results");
19609
19811
  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) => {
@@ -19636,7 +19838,7 @@ analyticsCommand.command("stats").description("Show account statistics").option(
19636
19838
  const [success, setSuccess] = useState29(null);
19637
19839
  const [error, setError] = useState29(null);
19638
19840
  const [resultNode, setResultNode] = useState29(void 0);
19639
- useEffect27(() => {
19841
+ useEffect26(() => {
19640
19842
  const run = async () => {
19641
19843
  try {
19642
19844
  const data = await client.get("/analytics/stats");
@@ -19720,7 +19922,7 @@ analyticsCommand.command("results").description("List execution results").option
19720
19922
  const [items, setItems] = useState29(null);
19721
19923
  const [total, setTotal] = useState29(void 0);
19722
19924
  const [error, setError] = useState29(null);
19723
- useEffect27(() => {
19925
+ useEffect26(() => {
19724
19926
  const run = async () => {
19725
19927
  try {
19726
19928
  const data = await client.get(
@@ -19765,7 +19967,7 @@ import { Command as Command17 } from "commander";
19765
19967
  import chalk23 from "chalk";
19766
19968
  import React16 from "react";
19767
19969
  import { render as render16 } from "ink";
19768
- import { useState as useState30, useEffect as useEffect28 } from "react";
19970
+ import { useState as useState30, useEffect as useEffect27 } from "react";
19769
19971
  import open5 from "open";
19770
19972
  var billingCommand = new Command17("billing").description("View billing and subscription info");
19771
19973
  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) => {
@@ -19815,7 +20017,7 @@ billingCommand.command("status").description("Show current plan and usage").opti
19815
20017
  const [success, setSuccess] = useState30(null);
19816
20018
  const [error, setError] = useState30(null);
19817
20019
  const [resultNode, setResultNode] = useState30(void 0);
19818
- useEffect28(() => {
20020
+ useEffect27(() => {
19819
20021
  const run = async () => {
19820
20022
  try {
19821
20023
  const data = await client.get("/billing/status");
@@ -19886,7 +20088,7 @@ billingCommand.command("portal").description("Open the billing portal in your br
19886
20088
  const [success, setSuccess] = useState30(null);
19887
20089
  const [error, setError] = useState30(null);
19888
20090
  const [msg, setMsg] = useState30("Opening billing portal...");
19889
- useEffect28(() => {
20091
+ useEffect27(() => {
19890
20092
  const run = async () => {
19891
20093
  try {
19892
20094
  const data = await client.post("/billing/portal");
@@ -19938,7 +20140,7 @@ billingCommand.command("refresh").description("Refresh plan data from billing pr
19938
20140
  const [loading, setLoading] = useState30(true);
19939
20141
  const [success, setSuccess] = useState30(null);
19940
20142
  const [error, setError] = useState30(null);
19941
- useEffect28(() => {
20143
+ useEffect27(() => {
19942
20144
  const run = async () => {
19943
20145
  try {
19944
20146
  await client.post("/billing/refresh");
@@ -19969,7 +20171,7 @@ import { Command as Command18 } from "commander";
19969
20171
  import chalk24 from "chalk";
19970
20172
  import React17 from "react";
19971
20173
  import { render as render17 } from "ink";
19972
- import { useState as useState31, useEffect as useEffect29 } from "react";
20174
+ import { useState as useState31, useEffect as useEffect28 } from "react";
19973
20175
  import { Text as Text33 } from "ink";
19974
20176
  var flowVersionsCommand = new Command18("flow-versions").description(
19975
20177
  "Manage flow versions"
@@ -20009,7 +20211,7 @@ flowVersionsCommand.command("list <flowId>").description("List all versions for
20009
20211
  const [loading, setLoading] = useState31(true);
20010
20212
  const [items, setItems] = useState31(null);
20011
20213
  const [error, setError] = useState31(null);
20012
- useEffect29(() => {
20214
+ useEffect28(() => {
20013
20215
  const run = async () => {
20014
20216
  try {
20015
20217
  const data = await client.get(`/flow-versions/${flowId}`);
@@ -20071,7 +20273,7 @@ flowVersionsCommand.command("get <flowId> <versionId>").description("Get a speci
20071
20273
  const [success, setSuccess] = useState31(null);
20072
20274
  const [error, setError] = useState31(null);
20073
20275
  const [resultNode, setResultNode] = useState31(void 0);
20074
- useEffect29(() => {
20276
+ useEffect28(() => {
20075
20277
  const run = async () => {
20076
20278
  try {
20077
20279
  const data = await client.get(`/flow-versions/${flowId}/${versionId}`);
@@ -20137,7 +20339,7 @@ flowVersionsCommand.command("published <flowId>").description("Get the published
20137
20339
  const [success, setSuccess] = useState31(null);
20138
20340
  const [error, setError] = useState31(null);
20139
20341
  const [resultNode, setResultNode] = useState31(void 0);
20140
- useEffect29(() => {
20342
+ useEffect28(() => {
20141
20343
  const run = async () => {
20142
20344
  try {
20143
20345
  const data = await client.get(`/flow-versions/${flowId}/published`);
@@ -20193,7 +20395,7 @@ flowVersionsCommand.command("publish <flowId>").description("Publish a version")
20193
20395
  const [loading, setLoading] = useState31(true);
20194
20396
  const [success, setSuccess] = useState31(null);
20195
20397
  const [error, setError] = useState31(null);
20196
- useEffect29(() => {
20398
+ useEffect28(() => {
20197
20399
  const run = async () => {
20198
20400
  try {
20199
20401
  await client.post(`/flow-versions/${flowId}/publish`, {