@runtypelabs/cli 2.56.4 → 2.56.5

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.
Files changed (2) hide show
  1. package/dist/index.js +234 -216
  2. package/package.json +5 -5
package/dist/index.js CHANGED
@@ -11498,7 +11498,7 @@ const transcriptToolCallSchema = object$4({
11498
11498
  const transcriptToolResultSchema = object$4({
11499
11499
  toolCallId: string$2().min(1).describe("Must answer a toolCalls entry issued earlier."),
11500
11500
  toolName: string$2().min(1),
11501
- result: unknown().describe("Whatever the tool returned."),
11501
+ result: unknown().default(null).describe("Whatever the tool returned."),
11502
11502
  providerOptions: record$2(string$2(), unknown()).optional()
11503
11503
  });
11504
11504
  const CONVERSATION_TRANSCRIPT_ROLES = [
@@ -31408,6 +31408,48 @@ function MutationResult({ loading, loadingLabel = "Processing...", success, succ
31408
31408
  });
31409
31409
  return null;
31410
31410
  }
31411
+ // src/ink/shared/useMutationState.ts
31412
+ function useMutationState(initial = "loading") {
31413
+ const [state, setState] = useState({ status: initial });
31414
+ return {
31415
+ state,
31416
+ start: useCallback(() => setState({ status: "loading" }), []),
31417
+ succeed: useCallback((result) => setState({
31418
+ status: "success",
31419
+ result
31420
+ }), []),
31421
+ fail: useCallback((error) => setState({
31422
+ status: "error",
31423
+ error: error instanceof Error ? error : new Error(String(error))
31424
+ }), [])
31425
+ };
31426
+ }
31427
+ /** The MutationResult props a lifecycle state renders as. */
31428
+ function mutationResultProps(state) {
31429
+ switch (state.status) {
31430
+ case "idle": return {
31431
+ loading: false,
31432
+ success: null,
31433
+ error: null
31434
+ };
31435
+ case "loading": return {
31436
+ loading: true,
31437
+ success: null,
31438
+ error: null
31439
+ };
31440
+ case "success": return {
31441
+ loading: false,
31442
+ success: true,
31443
+ error: null,
31444
+ result: state.result
31445
+ };
31446
+ case "error": return {
31447
+ loading: false,
31448
+ success: false,
31449
+ error: state.error
31450
+ };
31451
+ }
31452
+ }
31411
31453
  // src/ink/shared/account-picker.ts
31412
31454
  /** Interactive picker over stored logins; resolves undefined if the user exits without choosing. */
31413
31455
  async function promptForAccount(accounts) {
@@ -31766,27 +31808,19 @@ async function getBillingInfo(apiKey, apiUrl) {
31766
31808
  /** Run one async step under the shared spinner/result chrome. */
31767
31809
  async function renderTask(loadingLabel, task) {
31768
31810
  const App = () => {
31769
- const [loading, setLoading] = useState(true);
31770
31811
  const [label, setLabel] = useState(loadingLabel);
31771
- const [success, setSuccess] = useState(null);
31772
- const [error, setError] = useState(null);
31773
- const [outcome, setOutcome] = useState(null);
31812
+ const [message, setMessage] = useState("");
31813
+ const mutation = useMutationState();
31774
31814
  useEffect(() => {
31775
31815
  task(setLabel).then((value) => {
31776
- setOutcome(value);
31777
- setSuccess(true);
31778
- }).catch((err) => {
31779
- setError(err instanceof Error ? err : new Error(String(err)));
31780
- setSuccess(false);
31781
- }).finally(() => setLoading(false));
31816
+ setMessage(value.message);
31817
+ mutation.succeed(value.result);
31818
+ }).catch((err) => mutation.fail(err));
31782
31819
  }, []);
31783
31820
  return React.createElement(MutationResult, {
31784
- loading,
31821
+ ...mutationResultProps(mutation.state),
31785
31822
  loadingLabel: label,
31786
- success,
31787
- successMessage: outcome?.message ?? "",
31788
- error,
31789
- result: outcome?.result
31823
+ successMessage: message
31790
31824
  });
31791
31825
  };
31792
31826
  const { waitUntilExit } = render(React.createElement(App));
@@ -35055,6 +35089,30 @@ promptsCommand.command("delete <id>").description("Delete a prompt").option("--t
35055
35089
  const { waitUntilExit } = render(React.createElement(runDelete()));
35056
35090
  await waitUntilExit();
35057
35091
  });
35092
+ // ../shared/dist/batch-execution-status.mjs
35093
+ /**
35094
+ * Lifecycle of a batch execution as the API writes it: `batch_executions.status` and the
35095
+ * BatchExecutionDO state. Every SDK, CLI and MCP consumer classifies batch status through this list.
35096
+ */
35097
+ const BATCH_EXECUTION_STATUSES = [
35098
+ "queued",
35099
+ "processing",
35100
+ "completed",
35101
+ "failed",
35102
+ "cancelled"
35103
+ ];
35104
+ const TERMINAL_BATCH_EXECUTION_STATUSES = [
35105
+ "completed",
35106
+ "failed",
35107
+ "cancelled"
35108
+ ];
35109
+ function isBatchExecutionStatus(value) {
35110
+ return BATCH_EXECUTION_STATUSES.includes(value);
35111
+ }
35112
+ /** False for an unknown status: a value this list does not name must never read as finished. */
35113
+ function isTerminalBatchExecutionStatus(status) {
35114
+ return TERMINAL_BATCH_EXECUTION_STATUSES.includes(status);
35115
+ }
35058
35116
  // src/lib/wait-for-status.ts
35059
35117
  const MAX_WAIT_DURATION_MS = 2147483647;
35060
35118
  /** Poll read-only status until terminal, timeout, or caller abort; never cancel the remote task. */
@@ -35108,18 +35166,16 @@ function parseWatchDuration(value) {
35108
35166
  if (!/^\d+$/.test(value) || !Number.isInteger(duration) || duration <= 0 || duration > 2147483647) throw new InvalidArgumentError(`Expected an integer between 1 and ${MAX_WAIT_DURATION_MS} ms`);
35109
35167
  return duration;
35110
35168
  }
35111
- function isTerminalBatchStatus(data) {
35112
- switch (data.status) {
35113
- case "queued":
35114
- case "pending":
35115
- case "processing":
35116
- case "running": return false;
35117
- case "completed":
35118
- case "failed":
35119
- case "cancelled":
35120
- case "partial": return true;
35121
- default: throw new Error(`Unknown batch status: ${data.status}`);
35122
- }
35169
+ /** Unknown statuses keep polling with one warning each, so a newer API state never ends a watch early. */
35170
+ function createBatchTerminalCheck(warn) {
35171
+ const warnedStatuses = /* @__PURE__ */ new Set();
35172
+ return (data) => {
35173
+ if (!isBatchExecutionStatus(data.status) && !warnedStatuses.has(data.status)) {
35174
+ warnedStatuses.add(data.status);
35175
+ warn(`Unknown batch status "${data.status}"; continuing to poll until a terminal status`);
35176
+ }
35177
+ return isTerminalBatchExecutionStatus(data.status);
35178
+ };
35123
35179
  }
35124
35180
  function parseBatchStatusResponse(value) {
35125
35181
  if (!value || typeof value !== "object" || !("status" in value) || typeof value.status !== "string") throw new Error("Invalid batch status response: expected an object with a status string");
@@ -35229,7 +35285,7 @@ batchCommand.command("status <id>").description("Check batch job status").option
35229
35285
  signal
35230
35286
  })).json());
35231
35287
  },
35232
- isTerminal: isTerminalBatchStatus,
35288
+ isTerminal: createBatchTerminalCheck((message) => console.error(message)),
35233
35289
  timeoutMs,
35234
35290
  intervalMs: options.interval ?? 2e3,
35235
35291
  onStatus: (data) => {
@@ -35823,15 +35879,12 @@ secretsCommand.command("get <id>").description("Get secret metadata (value is ne
35823
35879
  return;
35824
35880
  }
35825
35881
  const App = () => {
35826
- const [loading, setLoading] = useState(true);
35827
- const [success, setSuccess] = useState(null);
35828
- const [error, setError] = useState(null);
35829
- const [resultNode, setResultNode] = useState(void 0);
35882
+ const mutation = useMutationState();
35830
35883
  useEffect(() => {
35831
35884
  const run = async () => {
35832
35885
  try {
35833
35886
  const s = (await client.get(`/secrets/${id}`)).data;
35834
- setResultNode(React.createElement(EntityCard, { fields: [
35887
+ mutation.succeed(React.createElement(EntityCard, { fields: [
35835
35888
  {
35836
35889
  label: "ID",
35837
35890
  value: s.id,
@@ -35862,23 +35915,16 @@ secretsCommand.command("get <id>").description("Get secret metadata (value is ne
35862
35915
  value: s.createdAt
35863
35916
  }
35864
35917
  ] }));
35865
- setSuccess(true);
35866
- setLoading(false);
35867
35918
  } catch (err) {
35868
- setError(err instanceof Error ? err : new Error(String(err)));
35869
- setSuccess(false);
35870
- setLoading(false);
35919
+ mutation.fail(err);
35871
35920
  }
35872
35921
  };
35873
35922
  run();
35874
35923
  }, []);
35875
35924
  return React.createElement(MutationResult, {
35876
- loading,
35925
+ ...mutationResultProps(mutation.state),
35877
35926
  loadingLabel: "Fetching secret...",
35878
- success,
35879
- successMessage: "Secret",
35880
- error,
35881
- result: resultNode
35927
+ successMessage: "Secret"
35882
35928
  });
35883
35929
  };
35884
35930
  const { waitUntilExit } = render(React.createElement(App));
@@ -35923,15 +35969,12 @@ secretsCommand.command("create").description("Create a new secret (provide the v
35923
35969
  return;
35924
35970
  }
35925
35971
  const App = () => {
35926
- const [loading, setLoading] = useState(true);
35927
- const [success, setSuccess] = useState(null);
35928
- const [error, setError] = useState(null);
35929
- const [resultNode, setResultNode] = useState(void 0);
35972
+ const mutation = useMutationState();
35930
35973
  useEffect(() => {
35931
35974
  const run = async () => {
35932
35975
  try {
35933
35976
  const data = await client.post("/secrets", body);
35934
- setResultNode(React.createElement(EntityCard, { fields: [
35977
+ mutation.succeed(React.createElement(EntityCard, { fields: [
35935
35978
  {
35936
35979
  label: "ID",
35937
35980
  value: data.data.id,
@@ -35946,23 +35989,16 @@ secretsCommand.command("create").description("Create a new secret (provide the v
35946
35989
  value: data.data.status
35947
35990
  }
35948
35991
  ] }));
35949
- setSuccess(true);
35950
- setLoading(false);
35951
35992
  } catch (err) {
35952
- setError(err instanceof Error ? err : new Error(String(err)));
35953
- setSuccess(false);
35954
- setLoading(false);
35993
+ mutation.fail(err);
35955
35994
  }
35956
35995
  };
35957
35996
  run();
35958
35997
  }, []);
35959
35998
  return React.createElement(MutationResult, {
35960
- loading,
35999
+ ...mutationResultProps(mutation.state),
35961
36000
  loadingLabel: "Creating secret...",
35962
- success,
35963
- successMessage: "Secret created",
35964
- error,
35965
- result: resultNode
36001
+ successMessage: "Secret created"
35966
36002
  });
35967
36003
  };
35968
36004
  const { waitUntilExit } = render(React.createElement(App));
@@ -36015,15 +36051,12 @@ secretsCommand.command("update <id>").description("Update or rotate a secret (va
36015
36051
  return;
36016
36052
  }
36017
36053
  const App = () => {
36018
- const [loading, setLoading] = useState(true);
36019
- const [success, setSuccess] = useState(null);
36020
- const [error, setError] = useState(null);
36021
- const [resultNode, setResultNode] = useState(void 0);
36054
+ const mutation = useMutationState();
36022
36055
  useEffect(() => {
36023
36056
  const run = async () => {
36024
36057
  try {
36025
36058
  const data = await client.put(`/secrets/${id}`, body);
36026
- setResultNode(React.createElement(EntityCard, { fields: [
36059
+ mutation.succeed(React.createElement(EntityCard, { fields: [
36027
36060
  {
36028
36061
  label: "ID",
36029
36062
  value: data.data.id,
@@ -36038,23 +36071,16 @@ secretsCommand.command("update <id>").description("Update or rotate a secret (va
36038
36071
  value: String(data.data.version)
36039
36072
  }
36040
36073
  ] }));
36041
- setSuccess(true);
36042
- setLoading(false);
36043
36074
  } catch (err) {
36044
- setError(err instanceof Error ? err : new Error(String(err)));
36045
- setSuccess(false);
36046
- setLoading(false);
36075
+ mutation.fail(err);
36047
36076
  }
36048
36077
  };
36049
36078
  run();
36050
36079
  }, []);
36051
36080
  return React.createElement(MutationResult, {
36052
- loading,
36081
+ ...mutationResultProps(mutation.state),
36053
36082
  loadingLabel: "Updating secret...",
36054
- success,
36055
- successMessage: "Secret updated",
36056
- error,
36057
- result: resultNode
36083
+ successMessage: "Secret updated"
36058
36084
  });
36059
36085
  };
36060
36086
  const { waitUntilExit } = render(React.createElement(App));
@@ -36077,25 +36103,18 @@ secretsCommand.command("delete <id>").description("Delete a secret").option("--t
36077
36103
  }
36078
36104
  const runDelete = () => {
36079
36105
  const App = () => {
36080
- const [loading, setLoading] = useState(true);
36081
- const [success, setSuccess] = useState(null);
36082
- const [error, setError] = useState(null);
36106
+ const mutation = useMutationState();
36083
36107
  useEffect(() => {
36084
36108
  client.delete(`/secrets/${id}`).then(() => {
36085
- setSuccess(true);
36086
- setLoading(false);
36109
+ mutation.succeed();
36087
36110
  }).catch((err) => {
36088
- setError(err instanceof Error ? err : new Error(String(err)));
36089
- setSuccess(false);
36090
- setLoading(false);
36111
+ mutation.fail(err);
36091
36112
  });
36092
36113
  }, []);
36093
36114
  return React.createElement(MutationResult, {
36094
- loading,
36115
+ ...mutationResultProps(mutation.state),
36095
36116
  loadingLabel: "Deleting secret...",
36096
- success,
36097
- successMessage: "Secret deleted",
36098
- error
36117
+ successMessage: "Secret deleted"
36099
36118
  });
36100
36119
  };
36101
36120
  return App;
@@ -36142,15 +36161,12 @@ secretsCommand.command("check <keys...>").description("Check which secret keys e
36142
36161
  return;
36143
36162
  }
36144
36163
  const App = () => {
36145
- const [loading, setLoading] = useState(true);
36146
- const [success, setSuccess] = useState(null);
36147
- const [error, setError] = useState(null);
36148
- const [resultNode, setResultNode] = useState(void 0);
36164
+ const mutation = useMutationState();
36149
36165
  useEffect(() => {
36150
36166
  const run = async () => {
36151
36167
  try {
36152
36168
  const data = await client.post("/secrets/check", body);
36153
- setResultNode(React.createElement(EntityCard, { fields: [
36169
+ mutation.succeed(React.createElement(EntityCard, { fields: [
36154
36170
  {
36155
36171
  label: "Found",
36156
36172
  value: data.found.join(", ") || "(none)",
@@ -36167,23 +36183,16 @@ secretsCommand.command("check <keys...>").description("Check which secret keys e
36167
36183
  color: "red"
36168
36184
  }
36169
36185
  ] }));
36170
- setSuccess(true);
36171
- setLoading(false);
36172
36186
  } catch (err) {
36173
- setError(err instanceof Error ? err : new Error(String(err)));
36174
- setSuccess(false);
36175
- setLoading(false);
36187
+ mutation.fail(err);
36176
36188
  }
36177
36189
  };
36178
36190
  run();
36179
36191
  }, []);
36180
36192
  return React.createElement(MutationResult, {
36181
- loading,
36193
+ ...mutationResultProps(mutation.state),
36182
36194
  loadingLabel: "Checking secrets...",
36183
- success,
36184
- successMessage: "Secret check",
36185
- error,
36186
- result: resultNode
36195
+ successMessage: "Secret check"
36187
36196
  });
36188
36197
  };
36189
36198
  const { waitUntilExit } = render(React.createElement(App));
@@ -39532,6 +39541,10 @@ const INITIAL_STATE = {
39532
39541
  totalOutputTokens: 0,
39533
39542
  contextCompaction: null
39534
39543
  };
39544
+ /** Frames arriving after a leg completed never move the phase; only a new start or a lifecycle action does. */
39545
+ function streamFramePhase(current, next) {
39546
+ return current === "complete" || current === "checkpoint" ? current : next;
39547
+ }
39535
39548
  /** Max raw events to keep in memory */
39536
39549
  const MAX_RAW_EVENTS = 15e3;
39537
39550
  const TOOL_PREVIEW_FIELD_LIMIT = 2;
@@ -39757,15 +39770,15 @@ function useMarathonStream() {
39757
39770
  setState((prev) => ({
39758
39771
  ...prev,
39759
39772
  ...event.contentType === "text" ? {
39760
- phase: "streaming",
39773
+ phase: streamFramePhase(prev.phase, "streaming"),
39761
39774
  content: appendTranscriptText(prev.content, event.delta, prev.lastTranscriptKind),
39762
39775
  lastTranscriptKind: "text",
39763
39776
  thinkingStartedAt: null
39764
39777
  } : event.contentType === "tool_input" ? {
39765
- phase: "tool",
39778
+ phase: streamFramePhase(prev.phase, "tool"),
39766
39779
  thinkingStartedAt: null
39767
39780
  } : {
39768
- phase: "thinking",
39781
+ phase: streamFramePhase(prev.phase, "thinking"),
39769
39782
  reasoning: prev.reasoning + event.delta,
39770
39783
  thinkingStartedAt: prev.thinkingStartedAt ?? Date.now()
39771
39784
  }
@@ -39807,7 +39820,7 @@ function useMarathonStream() {
39807
39820
  });
39808
39821
  return {
39809
39822
  ...prev,
39810
- phase: "tool",
39823
+ phase: streamFramePhase(prev.phase, "tool"),
39811
39824
  thinkingStartedAt: null,
39812
39825
  tools
39813
39826
  };
@@ -39819,7 +39832,7 @@ function useMarathonStream() {
39819
39832
  setStoredToolPayloadField(toolPayloadsRef.current, uniqueId, "parameters", inlineParameters ? void 0 : event.parameters);
39820
39833
  return {
39821
39834
  ...prev,
39822
- phase: "tool",
39835
+ phase: streamFramePhase(prev.phase, "tool"),
39823
39836
  thinkingStartedAt: null,
39824
39837
  content: appendContentLine(prev.content, `[${sequence}] ${event.toolName}`),
39825
39838
  lastTranscriptKind: "tool",
@@ -39862,7 +39875,7 @@ function useMarathonStream() {
39862
39875
  });
39863
39876
  return {
39864
39877
  ...prev,
39865
- phase: "tool",
39878
+ phase: streamFramePhase(prev.phase, "tool"),
39866
39879
  thinkingStartedAt: null,
39867
39880
  tools
39868
39881
  };
@@ -39891,7 +39904,7 @@ function useMarathonStream() {
39891
39904
  });
39892
39905
  return {
39893
39906
  ...prev,
39894
- phase: "tool",
39907
+ phase: streamFramePhase(prev.phase, "tool"),
39895
39908
  thinkingStartedAt: null,
39896
39909
  tools
39897
39910
  };
@@ -39922,7 +39935,7 @@ function useMarathonStream() {
39922
39935
  });
39923
39936
  return {
39924
39937
  ...prev,
39925
- phase: "streaming",
39938
+ phase: streamFramePhase(prev.phase, "streaming"),
39926
39939
  tools
39927
39940
  };
39928
39941
  });
@@ -39948,7 +39961,7 @@ function useMarathonStream() {
39948
39961
  pushRawEvent(rawEventsRef, "agent_await", { ...event }, eventWriterRef, awaitListData);
39949
39962
  setState((prev) => ({
39950
39963
  ...prev,
39951
- phase: "tool",
39964
+ phase: streamFramePhase(prev.phase, "tool"),
39952
39965
  thinkingStartedAt: null,
39953
39966
  tools: prev.tools.map((t) => {
39954
39967
  if (t.status !== "running") return t;
@@ -39978,7 +39991,7 @@ function useMarathonStream() {
39978
39991
  pushRawEvent(rawEventsRef, "local_tool_execution_start", { ...event }, eventWriterRef, listData);
39979
39992
  setState((prev) => ({
39980
39993
  ...prev,
39981
- phase: "tool",
39994
+ phase: streamFramePhase(prev.phase, "tool"),
39982
39995
  thinkingStartedAt: null,
39983
39996
  tools: prev.tools.map((tool) => {
39984
39997
  if (!(tool.status === "running" && (tool.localToolCallId === event.toolCallId || tool.sourceToolCallId === event.toolCallId || tool.name === event.toolName))) return tool;
@@ -45641,7 +45654,7 @@ function MarathonApp({ taskName, agentId, model, sandbox, goal, initialSessionCo
45641
45654
  const { exit } = useApp();
45642
45655
  const { stdout } = useStdout();
45643
45656
  const separator = theme.separator ?? " · ";
45644
- const checkpointResolveRef = useRef(null);
45657
+ const pendingCheckpointRef = useRef(null);
45645
45658
  const [checkpointRecap, setCheckpointRecap] = useState(null);
45646
45659
  const [currentModel, setCurrentModel] = useState(model || "default");
45647
45660
  const [currentSandbox, setCurrentSandbox] = useState(sandbox);
@@ -45677,19 +45690,14 @@ function MarathonApp({ taskName, agentId, model, sandbox, goal, initialSessionCo
45677
45690
  setCheckpointInitialMessage(void 0);
45678
45691
  if (result.model) setCurrentModel(result.model);
45679
45692
  if (result.sandbox !== void 0) setCurrentSandbox(result.sandbox || void 0);
45680
- if (isTerminalCheckpointRef.current) {
45681
- if (checkpointResolveRef.current) {
45682
- checkpointResolveRef.current(result);
45683
- checkpointResolveRef.current = null;
45684
- }
45685
- } else {
45693
+ const pending = pendingCheckpointRef.current;
45694
+ pendingCheckpointRef.current = null;
45695
+ if (isTerminalCheckpointRef.current) pending?.resolve(result);
45696
+ else {
45686
45697
  resetForNewSession();
45687
45698
  setIsTerminalCheckpoint(false);
45688
45699
  isTerminalCheckpointRef.current = false;
45689
- if (checkpointResolveRef.current) {
45690
- checkpointResolveRef.current(result);
45691
- checkpointResolveRef.current = null;
45692
- }
45700
+ pending?.resolve(result);
45693
45701
  }
45694
45702
  }, [resetForNewSession]);
45695
45703
  useEffect(() => {
@@ -45723,15 +45731,22 @@ function MarathonApp({ taskName, agentId, model, sandbox, goal, initialSessionCo
45723
45731
  setFollowLatest(true);
45724
45732
  setLatestUnreadKey(void 0);
45725
45733
  },
45726
- requestCheckpoint: async (recap, isTerminal) => {
45734
+ requestCheckpoint: (recap, isTerminal) => {
45735
+ if (pendingCheckpointRef.current) return pendingCheckpointRef.current.promise;
45727
45736
  setCheckpoint();
45728
45737
  setCheckpointRecap(recap);
45729
45738
  setIsCheckpointExploring(false);
45730
45739
  setIsTerminalCheckpoint(Boolean(isTerminal));
45731
45740
  isTerminalCheckpointRef.current = Boolean(isTerminal);
45732
- return new Promise((resolve) => {
45733
- checkpointResolveRef.current = resolve;
45741
+ let resolve = () => {};
45742
+ const promise = new Promise((settle) => {
45743
+ resolve = settle;
45734
45744
  });
45745
+ pendingCheckpointRef.current = {
45746
+ promise,
45747
+ resolve
45748
+ };
45749
+ return promise;
45735
45750
  },
45736
45751
  updateMilestone: (milestone) => {
45737
45752
  setCurrentMilestone(milestone);
@@ -47900,6 +47915,62 @@ async function promptSelect(message, choices, options) {
47900
47915
  renderMenu();
47901
47916
  });
47902
47917
  }
47918
+ // src/marathon/run-task-status.ts
47919
+ const RUN_TASK_STATUS_CLASSIFICATION = {
47920
+ complete: {
47921
+ terminalCheckpoint: true,
47922
+ resumable: false,
47923
+ resumeCheckpoint: false,
47924
+ tone: "success",
47925
+ snapshotStatus: "complete"
47926
+ },
47927
+ budget_exceeded: {
47928
+ terminalCheckpoint: true,
47929
+ resumable: false,
47930
+ resumeCheckpoint: false,
47931
+ tone: "failure",
47932
+ snapshotStatus: "budget_exceeded"
47933
+ },
47934
+ max_sessions: {
47935
+ terminalCheckpoint: true,
47936
+ resumable: true,
47937
+ resumeCheckpoint: false,
47938
+ tone: "warning",
47939
+ snapshotStatus: null
47940
+ },
47941
+ stalled: {
47942
+ terminalCheckpoint: true,
47943
+ resumable: true,
47944
+ resumeCheckpoint: false,
47945
+ tone: "warning",
47946
+ snapshotStatus: null
47947
+ },
47948
+ error: {
47949
+ terminalCheckpoint: false,
47950
+ resumable: true,
47951
+ resumeCheckpoint: false,
47952
+ tone: "failure",
47953
+ snapshotStatus: "error"
47954
+ },
47955
+ paused: {
47956
+ terminalCheckpoint: false,
47957
+ resumable: true,
47958
+ resumeCheckpoint: true,
47959
+ tone: "warning",
47960
+ snapshotStatus: null
47961
+ },
47962
+ running: {
47963
+ terminalCheckpoint: false,
47964
+ resumable: true,
47965
+ resumeCheckpoint: true,
47966
+ tone: "warning",
47967
+ snapshotStatus: null
47968
+ }
47969
+ };
47970
+ /** A status this table does not name (an older or newer saved state) is treated like an interrupted run. */
47971
+ function classifyRunTaskStatus(status) {
47972
+ return RUN_TASK_STATUS_CLASSIFICATION[status] ?? RUN_TASK_STATUS_CLASSIFICATION.running;
47973
+ }
47903
47974
  // src/marathon/state.ts
47904
47975
  function defaultStateDir$1() {
47905
47976
  return getMarathonStateDir();
@@ -48049,13 +48120,10 @@ function buildMarathonSessionSnapshot(liveState, sessionSummary, model, status =
48049
48120
  };
48050
48121
  }
48051
48122
  function mapRunTaskStatusToSnapshotStatus(status, fallback) {
48052
- if (status === "complete") return "complete";
48053
- if (status === "error") return "error";
48054
- if (status === "budget_exceeded") return "budget_exceeded";
48055
- return fallback;
48123
+ return classifyRunTaskStatus(status).snapshotStatus ?? fallback;
48056
48124
  }
48057
48125
  function isMarathonResumableStatus(status) {
48058
- return status === "paused" || status === "max_sessions" || status === "error";
48126
+ return classifyRunTaskStatus(status).resumable;
48059
48127
  }
48060
48128
  function sanitizeLoadedMarathonState(state) {
48061
48129
  const planPath = normalizeMarathonStatePath(state.planPath) || state.planPath;
@@ -49970,7 +50038,7 @@ function normalizeFallbackModel(input) {
49970
50038
  }
49971
50039
  // src/commands/agents-task.ts
49972
50040
  function shouldRequestResumeCheckpoint(status, resumeMessage, noCheckpoint, originalMessage, continuations) {
49973
- if (status !== "paused" || noCheckpoint) return false;
50041
+ if (!classifyRunTaskStatus(status).resumeCheckpoint || noCheckpoint) return false;
49974
50042
  const normalizedResumeMessage = resumeMessage?.trim();
49975
50043
  if (!normalizedResumeMessage) return true;
49976
50044
  const normalizedOriginalMessage = originalMessage?.trim();
@@ -51084,7 +51152,7 @@ async function taskAction(agent, options) {
51084
51152
  useCompact = false;
51085
51153
  resumeState = extractRunTaskResumeState(lastKnownState);
51086
51154
  }
51087
- if (wasAborted || result.status === "complete" || result.status === "budget_exceeded" || result.status === "max_sessions") {
51155
+ if (wasAborted || classifyRunTaskStatus(result.status).terminalCheckpoint) {
51088
51156
  if (options.noCheckpoint) {
51089
51157
  if (wasAborted) undeliveredSteering = streamRef.current?.drainSteeringQueue?.() ?? [];
51090
51158
  break;
@@ -51191,7 +51259,8 @@ async function taskAction(agent, options) {
51191
51259
  })]);
51192
51260
  }
51193
51261
  console.log();
51194
- const statusColor = result.status === "complete" ? chalk.green : result.status === "budget_exceeded" || result.status === "error" ? chalk.red : chalk.yellow;
51262
+ const statusTone = classifyRunTaskStatus(result.status).tone;
51263
+ const statusColor = statusTone === "success" ? chalk.green : statusTone === "failure" ? chalk.red : chalk.yellow;
51195
51264
  console.log(`Status: ${statusColor(result.status)}`);
51196
51265
  console.log(`Sessions: ${finalState.sessionCount}`);
51197
51266
  console.log(`Total cost: ${chalk.yellow(`$${finalState.totalCost.toFixed(4)}`)}`);
@@ -55832,15 +55901,12 @@ apiKeysCommand.command("get <id>").description("Get API key details").option("--
55832
55901
  return;
55833
55902
  }
55834
55903
  const App = () => {
55835
- const [loading, setLoading] = useState(true);
55836
- const [success, setSuccess] = useState(null);
55837
- const [error, setError] = useState(null);
55838
- const [resultNode, setResultNode] = useState(void 0);
55904
+ const mutation = useMutationState();
55839
55905
  useEffect(() => {
55840
55906
  const run = async () => {
55841
55907
  try {
55842
55908
  const data = await client.get(`/api-keys/${id}`);
55843
- setResultNode(React.createElement(EntityCard, { fields: [
55909
+ mutation.succeed(React.createElement(EntityCard, { fields: [
55844
55910
  {
55845
55911
  label: "ID",
55846
55912
  value: data.id
@@ -55866,23 +55932,16 @@ apiKeysCommand.command("get <id>").description("Get API key details").option("--
55866
55932
  value: data.createdAt
55867
55933
  }
55868
55934
  ] }));
55869
- setSuccess(true);
55870
- setLoading(false);
55871
55935
  } catch (err) {
55872
- setError(err instanceof Error ? err : new Error(String(err)));
55873
- setSuccess(false);
55874
- setLoading(false);
55936
+ mutation.fail(err);
55875
55937
  }
55876
55938
  };
55877
55939
  run();
55878
55940
  }, []);
55879
55941
  return React.createElement(MutationResult, {
55880
- loading,
55942
+ ...mutationResultProps(mutation.state),
55881
55943
  loadingLabel: "Fetching API key...",
55882
- success,
55883
- successMessage: "API Key",
55884
- error,
55885
- result: resultNode
55944
+ successMessage: "API Key"
55886
55945
  });
55887
55946
  };
55888
55947
  const { waitUntilExit } = render(React.createElement(App));
@@ -55947,10 +56006,7 @@ apiKeysCommand.command("create").description("Create a new API key").requiredOpt
55947
56006
  return;
55948
56007
  }
55949
56008
  const App = () => {
55950
- const [loading, setLoading] = useState(true);
55951
- const [success, setSuccess] = useState(null);
55952
- const [error, setError] = useState(null);
55953
- const [resultNode, setResultNode] = useState(void 0);
56009
+ const mutation = useMutationState();
55954
56010
  useEffect(() => {
55955
56011
  const run = async () => {
55956
56012
  try {
@@ -55988,24 +56044,17 @@ apiKeysCommand.command("create").description("Create a new API key").requiredOpt
55988
56044
  value: "Save this key - it will not be shown again"
55989
56045
  });
55990
56046
  }
55991
- setResultNode(React.createElement(EntityCard, { fields }));
55992
- setSuccess(true);
55993
- setLoading(false);
56047
+ mutation.succeed(React.createElement(EntityCard, { fields }));
55994
56048
  } catch (err) {
55995
- setError(err instanceof Error ? err : new Error(String(err)));
55996
- setSuccess(false);
55997
- setLoading(false);
56049
+ mutation.fail(err);
55998
56050
  }
55999
56051
  };
56000
56052
  run();
56001
56053
  }, []);
56002
56054
  return React.createElement(MutationResult, {
56003
- loading,
56055
+ ...mutationResultProps(mutation.state),
56004
56056
  loadingLabel: "Creating API key...",
56005
- success,
56006
- successMessage: "API key created",
56007
- error,
56008
- result: resultNode
56057
+ successMessage: "API key created"
56009
56058
  });
56010
56059
  };
56011
56060
  const { waitUntilExit } = render(React.createElement(App));
@@ -56029,29 +56078,22 @@ apiKeysCommand.command("delete <id>").description("Delete an API key").option("-
56029
56078
  }
56030
56079
  if (options.yes) {
56031
56080
  const App = () => {
56032
- const [loading, setLoading] = useState(true);
56033
- const [success, setSuccess] = useState(null);
56034
- const [error, setError] = useState(null);
56081
+ const mutation = useMutationState();
56035
56082
  useEffect(() => {
56036
56083
  const run = async () => {
56037
56084
  try {
56038
56085
  await client.apiKeys.delete(id);
56039
- setSuccess(true);
56040
- setLoading(false);
56086
+ mutation.succeed();
56041
56087
  } catch (err) {
56042
- setError(err instanceof Error ? err : new Error(String(err)));
56043
- setSuccess(false);
56044
- setLoading(false);
56088
+ mutation.fail(err);
56045
56089
  }
56046
56090
  };
56047
56091
  run();
56048
56092
  }, []);
56049
56093
  return React.createElement(MutationResult, {
56050
- loading,
56094
+ ...mutationResultProps(mutation.state),
56051
56095
  loadingLabel: "Deleting API key...",
56052
- success,
56053
- successMessage: "API key deleted",
56054
- error
56096
+ successMessage: "API key deleted"
56055
56097
  });
56056
56098
  };
56057
56099
  const { waitUntilExit } = render(React.createElement(App));
@@ -56069,29 +56111,22 @@ apiKeysCommand.command("delete <id>").description("Delete an API key").option("-
56069
56111
  }));
56070
56112
  })) return;
56071
56113
  const DeleteApp = () => {
56072
- const [loading, setLoading] = useState(true);
56073
- const [success, setSuccess] = useState(null);
56074
- const [error, setError] = useState(null);
56114
+ const mutation = useMutationState();
56075
56115
  useEffect(() => {
56076
56116
  const run = async () => {
56077
56117
  try {
56078
56118
  await client.apiKeys.delete(id);
56079
- setSuccess(true);
56080
- setLoading(false);
56119
+ mutation.succeed();
56081
56120
  } catch (err) {
56082
- setError(err instanceof Error ? err : new Error(String(err)));
56083
- setSuccess(false);
56084
- setLoading(false);
56121
+ mutation.fail(err);
56085
56122
  }
56086
56123
  };
56087
56124
  run();
56088
56125
  }, []);
56089
56126
  return React.createElement(MutationResult, {
56090
- loading,
56127
+ ...mutationResultProps(mutation.state),
56091
56128
  loadingLabel: "Deleting API key...",
56092
- success,
56093
- successMessage: "API key deleted",
56094
- error
56129
+ successMessage: "API key deleted"
56095
56130
  });
56096
56131
  };
56097
56132
  const { waitUntilExit } = render(React.createElement(DeleteApp));
@@ -56121,39 +56156,29 @@ apiKeysCommand.command("regenerate <id>").description("Regenerate an API key").o
56121
56156
  return;
56122
56157
  }
56123
56158
  const App = () => {
56124
- const [loading, setLoading] = useState(true);
56125
- const [success, setSuccess] = useState(null);
56126
- const [error, setError] = useState(null);
56127
- const [resultNode, setResultNode] = useState(void 0);
56159
+ const mutation = useMutationState();
56128
56160
  useEffect(() => {
56129
56161
  const run = async () => {
56130
56162
  try {
56131
56163
  const data = await client.post(`/api-keys/${id}/regenerate`);
56132
- if (data.key) setResultNode(React.createElement(EntityCard, { fields: [{
56164
+ mutation.succeed(data.key ? React.createElement(EntityCard, { fields: [{
56133
56165
  label: "New Key",
56134
56166
  value: data.key,
56135
56167
  color: "yellow"
56136
56168
  }, {
56137
56169
  label: "Note",
56138
56170
  value: "Save this key - it will not be shown again"
56139
- }] }));
56140
- setSuccess(true);
56141
- setLoading(false);
56171
+ }] }) : void 0);
56142
56172
  } catch (err) {
56143
- setError(err instanceof Error ? err : new Error(String(err)));
56144
- setSuccess(false);
56145
- setLoading(false);
56173
+ mutation.fail(err);
56146
56174
  }
56147
56175
  };
56148
56176
  run();
56149
56177
  }, []);
56150
56178
  return React.createElement(MutationResult, {
56151
- loading,
56179
+ ...mutationResultProps(mutation.state),
56152
56180
  loadingLabel: "Regenerating API key...",
56153
- success,
56154
- successMessage: "API key regenerated",
56155
- error,
56156
- result: resultNode
56181
+ successMessage: "API key regenerated"
56157
56182
  });
56158
56183
  };
56159
56184
  const { waitUntilExit } = render(React.createElement(App));
@@ -56176,30 +56201,23 @@ apiKeysCommand.command("analytics").description("Show API key usage analytics").
56176
56201
  return;
56177
56202
  }
56178
56203
  const App = () => {
56179
- const [loading, setLoading] = useState(true);
56180
- const [success, setSuccess] = useState(null);
56181
- const [error, setError] = useState(null);
56204
+ const mutation = useMutationState();
56182
56205
  useEffect(() => {
56183
56206
  const run = async () => {
56184
56207
  try {
56185
56208
  const path = options.key ? `/api-keys/${options.key}/analytics` : "/api-keys/analytics";
56186
56209
  printJson(await client.get(path));
56187
- setSuccess(true);
56188
- setLoading(false);
56210
+ mutation.succeed();
56189
56211
  } catch (err) {
56190
- setError(err instanceof Error ? err : new Error(String(err)));
56191
- setSuccess(false);
56192
- setLoading(false);
56212
+ mutation.fail(err);
56193
56213
  }
56194
56214
  };
56195
56215
  run();
56196
56216
  }, []);
56197
56217
  return React.createElement(MutationResult, {
56198
- loading,
56218
+ ...mutationResultProps(mutation.state),
56199
56219
  loadingLabel: "Fetching analytics...",
56200
- success,
56201
- successMessage: "Analytics",
56202
- error
56220
+ successMessage: "Analytics"
56203
56221
  });
56204
56222
  };
56205
56223
  const { waitUntilExit } = render(React.createElement(App));
@@ -69121,7 +69139,7 @@ const productKindSchema = _enum([
69121
69139
  "external",
69122
69140
  "spec_only"
69123
69141
  ]);
69124
- // ../shared/dist/chunk-BM4DAX8-.mjs
69142
+ // ../shared/dist/chunk-Ibmsq8NB.mjs
69125
69143
  const amount = number$2().finite().nonnegative();
69126
69144
  const tokens = amount.int();
69127
69145
  /** Producer estimates for one turn, independent of Runtype's measured usage and billing. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@runtypelabs/cli",
3
- "version": "2.56.4",
3
+ "version": "2.56.5",
4
4
  "description": "Command-line interface for Runtype AI platform",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -13,9 +13,9 @@
13
13
  "@modelcontextprotocol/core": "2.3.1",
14
14
  "@napi-rs/keyring": "2.1.0",
15
15
  "@runtypelabs/ink-components": "0.3.13",
16
- "@runtypelabs/sdk": "11.13.2",
16
+ "@runtypelabs/sdk": "11.14.0",
17
17
  "@runtypelabs/terminal-animations": "0.2.4",
18
- "add-mcp": "2.0.0",
18
+ "add-mcp": "2.6.0",
19
19
  "chalk": "^5.3.0",
20
20
  "commander": "^15.0.0",
21
21
  "conf": "^15.1.0",
@@ -37,9 +37,9 @@
37
37
  "devDependencies": {
38
38
  "@modelcontextprotocol/server": "2.3.1",
39
39
  "@runtypelabs/device-bridge": "0.2.5",
40
- "@runtypelabs/model-execution": "0.41.3",
40
+ "@runtypelabs/model-execution": "0.41.4",
41
41
  "@runtypelabs/persona": "4.34.0",
42
- "@runtypelabs/shared": "3.105.0",
42
+ "@runtypelabs/shared": "3.105.1",
43
43
  "@types/express": "^5.0.6",
44
44
  "@types/micromatch": "^4.0.9",
45
45
  "@types/node": "^25.3.3",