@runtypelabs/cli 2.2.0 → 2.2.1

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
@@ -5,10 +5,16 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getProtoOf = Object.getPrototypeOf;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
9
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
10
+ }) : x)(function(x) {
11
+ if (typeof require !== "undefined") return require.apply(this, arguments);
12
+ throw Error('Dynamic require of "' + x + '" is not supported');
13
+ });
8
14
  var __esm = (fn, res) => function __init() {
9
15
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
10
16
  };
11
- var __commonJS = (cb, mod) => function __require() {
17
+ var __commonJS = (cb, mod) => function __require2() {
12
18
  return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
13
19
  };
14
20
  var __export = (target, all) => {
@@ -147,6 +153,33 @@ var init_credential_store = __esm({
147
153
  }
148
154
  });
149
155
 
156
+ // ../shared/dist/integration-providers.js
157
+ var require_integration_providers = __commonJS({
158
+ "../shared/dist/integration-providers.js"(exports) {
159
+ "use strict";
160
+ Object.defineProperty(exports, "__esModule", { value: true });
161
+ exports.NON_AI_PROVIDER_IDS = void 0;
162
+ exports.isNonAIProvider = isNonAIProvider2;
163
+ exports.NON_AI_PROVIDER_IDS = /* @__PURE__ */ new Set([
164
+ // Analytics & Tracking
165
+ "posthog",
166
+ // Development Tools
167
+ "daytona",
168
+ // Web Scraping & Data Extraction
169
+ "firecrawl",
170
+ // Search Providers
171
+ "exa",
172
+ // Email Services
173
+ "resend",
174
+ // Audio / Speech
175
+ "elevenlabs"
176
+ ]);
177
+ function isNonAIProvider2(id) {
178
+ return exports.NON_AI_PROVIDER_IDS.has(id.trim().toLowerCase());
179
+ }
180
+ }
181
+ });
182
+
150
183
  // ../shared/dist/builtin-tools-registry.js
151
184
  var require_builtin_tools_registry = __commonJS({
152
185
  "../shared/dist/builtin-tools-registry.js"(exports) {
@@ -4565,8 +4598,8 @@ var CallbackServer = class {
4565
4598
  expectedState;
4566
4599
  constructor() {
4567
4600
  this.app = express();
4568
- this.codePromise = new Promise((resolve7, reject) => {
4569
- this.codeResolve = resolve7;
4601
+ this.codePromise = new Promise((resolve8, reject) => {
4602
+ this.codeResolve = resolve8;
4570
4603
  this.codeReject = reject;
4571
4604
  });
4572
4605
  this.app.get("/callback", (req, res) => {
@@ -5761,14 +5794,14 @@ async function promptConfirm(message, options) {
5761
5794
  output: process.stdout,
5762
5795
  terminal: true
5763
5796
  });
5764
- return new Promise((resolve7) => {
5797
+ return new Promise((resolve8) => {
5765
5798
  rl.question(chalk2.cyan(`${message} (${hint}): `), (answer) => {
5766
5799
  rl.close();
5767
5800
  const trimmed = answer.trim().toLowerCase();
5768
5801
  if (trimmed === "") {
5769
- resolve7(defaultYes);
5802
+ resolve8(defaultYes);
5770
5803
  } else {
5771
- resolve7(trimmed === "y" || trimmed === "yes");
5804
+ resolve8(trimmed === "y" || trimmed === "yes");
5772
5805
  }
5773
5806
  });
5774
5807
  });
@@ -5843,13 +5876,24 @@ function getCliVersion() {
5843
5876
  if (cachedCliVersion) {
5844
5877
  return cachedCliVersion;
5845
5878
  }
5846
- try {
5847
- const pkgPath = join(dirname(fileURLToPath(import.meta.url)), "..", "..", "package.json");
5848
- const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
5849
- cachedCliVersion = pkg.version || "0.0.0";
5850
- } catch {
5851
- cachedCliVersion = "0.0.0";
5879
+ const base = dirname(fileURLToPath(import.meta.url));
5880
+ const candidates = [
5881
+ join(base, "..", "..", "package.json"),
5882
+ // src/lib/ package root
5883
+ join(base, "..", "package.json")
5884
+ // dist/ → package root
5885
+ ];
5886
+ for (const pkgPath of candidates) {
5887
+ try {
5888
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
5889
+ if (pkg.name === CLI_PACKAGE_NAME && pkg.version) {
5890
+ cachedCliVersion = pkg.version;
5891
+ return cachedCliVersion;
5892
+ }
5893
+ } catch {
5894
+ }
5852
5895
  }
5896
+ cachedCliVersion = "0.0.0";
5853
5897
  return cachedCliVersion;
5854
5898
  }
5855
5899
 
@@ -5869,9 +5913,9 @@ var ApiClient = class {
5869
5913
  this.baseUrl = baseUrl || getApiUrl();
5870
5914
  }
5871
5915
  /** Prefix path with API version (e.g. /v1) so all requests hit versioned routes. */
5872
- path(path13) {
5916
+ path(path14) {
5873
5917
  const version = getApiVersion();
5874
- const p = path13.startsWith("/") ? path13 : `/${path13}`;
5918
+ const p = path14.startsWith("/") ? path14 : `/${path14}`;
5875
5919
  return p.startsWith(`/${version}/`) ? p : `/${version}${p}`;
5876
5920
  }
5877
5921
  headers(extra) {
@@ -5904,8 +5948,8 @@ var ApiClient = class {
5904
5948
  }
5905
5949
  return response.json();
5906
5950
  }
5907
- async get(path13, params) {
5908
- const url = new URL(this.path(path13), this.baseUrl);
5951
+ async get(path14, params) {
5952
+ const url = new URL(this.path(path14), this.baseUrl);
5909
5953
  if (params) {
5910
5954
  for (const [key, value] of Object.entries(params)) {
5911
5955
  if (value !== void 0 && value !== "") {
@@ -5918,32 +5962,32 @@ var ApiClient = class {
5918
5962
  });
5919
5963
  return this.handleResponse(response);
5920
5964
  }
5921
- async post(path13, body) {
5922
- const response = await fetch(new URL(this.path(path13), this.baseUrl).toString(), {
5965
+ async post(path14, body) {
5966
+ const response = await fetch(new URL(this.path(path14), this.baseUrl).toString(), {
5923
5967
  method: "POST",
5924
5968
  headers: this.headers(),
5925
5969
  body: body !== void 0 ? JSON.stringify(body) : void 0
5926
5970
  });
5927
5971
  return this.handleResponse(response);
5928
5972
  }
5929
- async put(path13, body) {
5930
- const response = await fetch(new URL(this.path(path13), this.baseUrl).toString(), {
5973
+ async put(path14, body) {
5974
+ const response = await fetch(new URL(this.path(path14), this.baseUrl).toString(), {
5931
5975
  method: "PUT",
5932
5976
  headers: this.headers(),
5933
5977
  body: body !== void 0 ? JSON.stringify(body) : void 0
5934
5978
  });
5935
5979
  return this.handleResponse(response);
5936
5980
  }
5937
- async patch(path13, body) {
5938
- const response = await fetch(new URL(this.path(path13), this.baseUrl).toString(), {
5981
+ async patch(path14, body) {
5982
+ const response = await fetch(new URL(this.path(path14), this.baseUrl).toString(), {
5939
5983
  method: "PATCH",
5940
5984
  headers: this.headers(),
5941
5985
  body: body !== void 0 ? JSON.stringify(body) : void 0
5942
5986
  });
5943
5987
  return this.handleResponse(response);
5944
5988
  }
5945
- async delete(path13) {
5946
- const response = await fetch(new URL(this.path(path13), this.baseUrl).toString(), {
5989
+ async delete(path14) {
5990
+ const response = await fetch(new URL(this.path(path14), this.baseUrl).toString(), {
5947
5991
  method: "DELETE",
5948
5992
  headers: this.headers()
5949
5993
  });
@@ -5957,8 +6001,8 @@ var ApiClient = class {
5957
6001
  throw new ApiError(response.status, message);
5958
6002
  }
5959
6003
  }
5960
- async stream(path13, body) {
5961
- const response = await fetch(new URL(this.path(path13), this.baseUrl).toString(), {
6004
+ async stream(path14, body) {
6005
+ const response = await fetch(new URL(this.path(path14), this.baseUrl).toString(), {
5962
6006
  method: "POST",
5963
6007
  headers: this.headers({ Accept: "text/event-stream" }),
5964
6008
  body: body !== void 0 ? JSON.stringify(body) : void 0
@@ -8346,6 +8390,7 @@ import React9 from "react";
8346
8390
  import { useState as useState22, useEffect as useEffect19, useRef as useRef9, useCallback as useCallback8, useMemo as useMemo11 } from "react";
8347
8391
  import { execSync } from "child_process";
8348
8392
  import * as fs4 from "fs";
8393
+ import * as path4 from "path";
8349
8394
  import open4 from "open";
8350
8395
  import { Box as Box28, Text as Text28, useApp as useApp4, useInput as useInput11, useStdout as useStdout5 } from "ink";
8351
8396
  import { StatusBar, theme as theme31 } from "@runtypelabs/ink-components";
@@ -8570,7 +8615,8 @@ function formatContextCompactionCompleteLine(event) {
8570
8615
  return thresholdLabel ? `[context] History compacted ${modeLabel}${modelLabel}${strategyLabel} at ${thresholdLabel}${breakdownLabel}.` : `[context] History compacted ${modeLabel}${modelLabel}${strategyLabel}${breakdownLabel}.`;
8571
8616
  }
8572
8617
  function formatContextNoticeLine(event) {
8573
- return `[context] ${event.message}`;
8618
+ const prefix = event.kind === "server_network_retry" ? "[retry]" : "[context]";
8619
+ return `${prefix} ${event.message}`;
8574
8620
  }
8575
8621
  var toolCounter = 0;
8576
8622
  function useMarathonStream() {
@@ -8578,6 +8624,7 @@ function useMarathonStream() {
8578
8624
  const rawEventsRef = useRef3([]);
8579
8625
  const stateRef = useRef3(state);
8580
8626
  stateRef.current = state;
8627
+ const costOffsetRef = useRef3(0);
8581
8628
  const eventWriterRef = useRef3(null);
8582
8629
  const toolPayloadsRef = useRef3(/* @__PURE__ */ new Map());
8583
8630
  const hydrateToolEntry = useCallback2((tool) => {
@@ -8958,7 +9005,7 @@ function useMarathonStream() {
8958
9005
  executionTime: Date.now() - (t.localExecutionStartedAt ?? t.startedAt)
8959
9006
  } : t
8960
9007
  ),
8961
- totalCost: event.totalCost != null ? event.totalCost : prev.totalCost,
9008
+ totalCost: event.totalCost != null ? costOffsetRef.current + event.totalCost : prev.totalCost,
8962
9009
  totalInputTokens: event.totalTokens?.input ?? prev.totalInputTokens,
8963
9010
  totalOutputTokens: event.totalTokens?.output ?? prev.totalOutputTokens
8964
9011
  }));
@@ -9040,18 +9087,21 @@ function useMarathonStream() {
9040
9087
  }, []);
9041
9088
  const resetForNewSession = useCallback2(() => {
9042
9089
  toolPayloadsRef.current.clear();
9043
- setState((prev) => ({
9044
- ...prev,
9045
- phase: "idle",
9046
- content: "",
9047
- reasoning: "",
9048
- lastTranscriptKind: null,
9049
- thinkingStartedAt: null,
9050
- tools: [],
9051
- currentIteration: 0,
9052
- error: null,
9053
- contextCompaction: null
9054
- }));
9090
+ setState((prev) => {
9091
+ costOffsetRef.current = prev.totalCost;
9092
+ return {
9093
+ ...prev,
9094
+ phase: "idle",
9095
+ content: "",
9096
+ reasoning: "",
9097
+ lastTranscriptKind: null,
9098
+ thinkingStartedAt: null,
9099
+ tools: [],
9100
+ currentIteration: 0,
9101
+ error: null,
9102
+ contextCompaction: null
9103
+ };
9104
+ });
9055
9105
  }, []);
9056
9106
  const showError = useCallback2((error) => {
9057
9107
  pushRawEvent(rawEventsRef, "agent_error", { message: error.message }, eventWriterRef);
@@ -10357,6 +10407,10 @@ function FileContentView({
10357
10407
  separator,
10358
10408
  "from tool call"
10359
10409
  ] }),
10410
+ /* @__PURE__ */ jsxs14(Text16, { color: theme17.textSubtle, children: [
10411
+ separator,
10412
+ "o: open"
10413
+ ] }),
10360
10414
  /* @__PURE__ */ jsxs14(Text16, { color: theme17.textSubtle, children: [
10361
10415
  separator,
10362
10416
  "c: copy"
@@ -10459,6 +10513,14 @@ function FilesPanel({
10459
10513
  separator,
10460
10514
  files.length,
10461
10515
  " files"
10516
+ ] }),
10517
+ /* @__PURE__ */ jsxs14(Text16, { color: theme17.border, children: [
10518
+ separator,
10519
+ "Enter: view",
10520
+ separator,
10521
+ "o: open",
10522
+ separator,
10523
+ "c: copy path"
10462
10524
  ] })
10463
10525
  ] }),
10464
10526
  /* @__PURE__ */ jsxs14(Box15, { flexDirection: "row", children: [
@@ -11959,7 +12021,7 @@ function CheckpointRecap({
11959
12021
  `Tools: ${toolCallsMade}`,
11960
12022
  `Tokens: ${formatTokenCount2(tokensInput)} in${separator}${formatTokenCount2(tokensOutput)} out`,
11961
12023
  ...reasoningTokens && reasoningTokens > 0 ? [`Reasoning: ${formatTokenCount2(reasoningTokens)}`] : [],
11962
- `Cost: $${cost.toFixed(4)}`
12024
+ `Total cost: $${cost.toFixed(4)}`
11963
12025
  ].join(separator);
11964
12026
  return /* @__PURE__ */ jsxs19(
11965
12027
  Box20,
@@ -13090,8 +13152,8 @@ function MarathonApp({
13090
13152
  setIsTerminalCheckpoint(true);
13091
13153
  isTerminalCheckpointRef.current = true;
13092
13154
  }
13093
- return new Promise((resolve7) => {
13094
- checkpointResolveRef.current = resolve7;
13155
+ return new Promise((resolve8) => {
13156
+ checkpointResolveRef.current = resolve8;
13095
13157
  });
13096
13158
  },
13097
13159
  updateMilestone: (milestone) => {
@@ -13417,7 +13479,7 @@ function MarathonApp({
13417
13479
  setUpgradeModalDismissed(true);
13418
13480
  return;
13419
13481
  }
13420
- if (_input === "o" && agentPageUrl && !(state.phase === "checkpoint" && checkpointRecap)) {
13482
+ if (_input === "o" && agentPageUrl && !showFilesPanel && !(state.phase === "checkpoint" && checkpointRecap)) {
13421
13483
  void open4(agentPageUrl);
13422
13484
  return;
13423
13485
  }
@@ -13573,6 +13635,19 @@ function MarathonApp({
13573
13635
  setReasoningCollapsed((prev) => !prev);
13574
13636
  return;
13575
13637
  }
13638
+ if (_input === "o" && showFilesPanel) {
13639
+ const file = detailFile ?? trackedFiles[fileCursor];
13640
+ if (file) {
13641
+ const filePath = path4.resolve(file.path);
13642
+ if (fs4.existsSync(filePath)) {
13643
+ void open4(filePath);
13644
+ showFlash(`Opening ${file.path}`);
13645
+ } else {
13646
+ showFlash("File not found on disk");
13647
+ }
13648
+ }
13649
+ return;
13650
+ }
13576
13651
  if (_input === "c" && showFilesPanel) {
13577
13652
  if (detailFile && detailFileContent) {
13578
13653
  const ok = copyToClipboard(detailFileContent);
@@ -14325,7 +14400,8 @@ function buildPromptShellModel(prompt, columnWidth) {
14325
14400
  }
14326
14401
  function MarathonStartupShell({
14327
14402
  startupRef,
14328
- marathonAppProps
14403
+ marathonAppProps,
14404
+ version
14329
14405
  }) {
14330
14406
  const { exit } = useApp5();
14331
14407
  const { stdout } = useStdout6();
@@ -14351,16 +14427,16 @@ function MarathonStartupShell({
14351
14427
  latestAppPropsRef.current = marathonAppProps;
14352
14428
  useEffect20(() => {
14353
14429
  if (scene !== "app" || !appReadyResolverRef.current) return;
14354
- const resolve7 = appReadyResolverRef.current;
14430
+ const resolve8 = appReadyResolverRef.current;
14355
14431
  appReadyResolverRef.current = null;
14356
- resolve7();
14432
+ resolve8();
14357
14433
  }, [scene]);
14358
14434
  const beginTransition = (target) => {
14359
14435
  if (transitionPromiseRef.current) return transitionPromiseRef.current;
14360
14436
  if (target === "app" && !latestAppPropsRef.current) {
14361
14437
  throw new Error("Cannot complete startup before marathon app props are ready.");
14362
14438
  }
14363
- const promise = new Promise((resolve7) => {
14439
+ const promise = new Promise((resolve8) => {
14364
14440
  globalThis.setTimeout(() => {
14365
14441
  setPrompt(null);
14366
14442
  setModelChoices(null);
@@ -14381,12 +14457,12 @@ function MarathonStartupShell({
14381
14457
  if (target === "app") {
14382
14458
  appReadyResolverRef.current = () => {
14383
14459
  transitionPromiseRef.current = null;
14384
- resolve7();
14460
+ resolve8();
14385
14461
  };
14386
14462
  } else {
14387
14463
  dismissResolverRef.current = () => {
14388
14464
  transitionPromiseRef.current = null;
14389
- resolve7();
14465
+ resolve8();
14390
14466
  };
14391
14467
  }
14392
14468
  }, Math.max(0, MIN_HOLD_MS - (Date.now() - mountedAtRef.current)));
@@ -14403,8 +14479,8 @@ function MarathonStartupShell({
14403
14479
  setModelChoices(null);
14404
14480
  setPrompt(nextPrompt);
14405
14481
  setSelectedPromptIndex(0);
14406
- return new Promise((resolve7) => {
14407
- promptResolverRef.current = resolve7;
14482
+ return new Promise((resolve8) => {
14483
+ promptResolverRef.current = resolve8;
14408
14484
  });
14409
14485
  },
14410
14486
  requestModelChoice: async (nextCurrentModel, models) => {
@@ -14412,8 +14488,8 @@ function MarathonStartupShell({
14412
14488
  setPlaybookConfirm(null);
14413
14489
  setCurrentModel(nextCurrentModel);
14414
14490
  setModelChoices(models);
14415
- return new Promise((resolve7) => {
14416
- modelResolverRef.current = resolve7;
14491
+ return new Promise((resolve8) => {
14492
+ modelResolverRef.current = resolve8;
14417
14493
  });
14418
14494
  },
14419
14495
  requestPlaybookModelConfirm: async (playbookName, milestoneModels) => {
@@ -14428,8 +14504,8 @@ function MarathonStartupShell({
14428
14504
  // Default selection is the "Confirm" action (first item after milestones)
14429
14505
  selectedIndex: names.length
14430
14506
  });
14431
- return new Promise((resolve7) => {
14432
- playbookConfirmResolverRef.current = resolve7;
14507
+ return new Promise((resolve8) => {
14508
+ playbookConfirmResolverRef.current = resolve8;
14433
14509
  });
14434
14510
  },
14435
14511
  completeStartup: () => beginTransition("app"),
@@ -14579,6 +14655,22 @@ function MarathonStartupShell({
14579
14655
  children: /* @__PURE__ */ jsx34(StartupGridIconCompactLightInverted, { autoplay: false })
14580
14656
  }
14581
14657
  ),
14658
+ version && /* @__PURE__ */ jsx34(
14659
+ Box29,
14660
+ {
14661
+ position: "absolute",
14662
+ width: terminalWidth,
14663
+ height: terminalRows,
14664
+ alignItems: "flex-end",
14665
+ justifyContent: "flex-end",
14666
+ paddingX: 2,
14667
+ paddingY: 1,
14668
+ children: /* @__PURE__ */ jsxs27(Text29, { color: theme32.border, children: [
14669
+ "v",
14670
+ version
14671
+ ] })
14672
+ }
14673
+ ),
14582
14674
  /* @__PURE__ */ jsx34(
14583
14675
  Box29,
14584
14676
  {
@@ -14680,23 +14772,25 @@ function MarathonStartupShell({
14680
14772
  }
14681
14773
 
14682
14774
  // src/commands/agents-task.ts
14775
+ var import_integration_providers = __toESM(require_integration_providers(), 1);
14683
14776
  import * as fs13 from "fs";
14684
14777
  import {
14685
14778
  RuntypeClient as RuntypeClient2,
14686
14779
  defaultWorkflow,
14687
14780
  deployWorkflow,
14688
- gameWorkflow
14781
+ gameWorkflow,
14782
+ getDefaultPlanPath
14689
14783
  } from "@runtypelabs/sdk";
14690
14784
 
14691
14785
  // src/lib/terminal-title.ts
14692
- import path4 from "path";
14786
+ import path5 from "path";
14693
14787
  function setTerminalTitle(title) {
14694
14788
  if (process.stdout.isTTY) {
14695
14789
  process.stdout.write(`\x1B]0;${title}\x07`);
14696
14790
  }
14697
14791
  }
14698
14792
  function getFolderName() {
14699
- return path4.basename(process.cwd());
14793
+ return path5.basename(process.cwd());
14700
14794
  }
14701
14795
  function setCliTitle() {
14702
14796
  setTerminalTitle(`Runtype (${getFolderName()})`);
@@ -14707,21 +14801,21 @@ function setMarathonTitle() {
14707
14801
 
14708
14802
  // src/marathon/checkpoint.ts
14709
14803
  import * as fs6 from "fs";
14710
- import * as path6 from "path";
14804
+ import * as path7 from "path";
14711
14805
 
14712
14806
  // src/config/paths.ts
14713
14807
  import * as os3 from "os";
14714
- import * as path5 from "path";
14808
+ import * as path6 from "path";
14715
14809
  import * as crypto3 from "crypto";
14716
14810
  import * as fs5 from "fs";
14717
14811
  function getRuntypeHomeDir() {
14718
- return process.env.RUNTYPE_STATE_DIR || path5.join(os3.homedir(), ".runtype");
14812
+ return process.env.RUNTYPE_STATE_DIR || path6.join(os3.homedir(), ".runtype");
14719
14813
  }
14720
14814
  function getProjectStateDir(projectDir) {
14721
14815
  const dir = projectDir || process.cwd();
14722
14816
  const hash = crypto3.createHash("sha256").update(dir).digest("hex").slice(0, 12);
14723
- const stateDir = path5.join(getRuntypeHomeDir(), "projects", hash);
14724
- const breadcrumb = path5.join(stateDir, "project-path.txt");
14817
+ const stateDir = path6.join(getRuntypeHomeDir(), "projects", hash);
14818
+ const breadcrumb = path6.join(stateDir, "project-path.txt");
14725
14819
  if (!fs5.existsSync(breadcrumb)) {
14726
14820
  fs5.mkdirSync(stateDir, { recursive: true });
14727
14821
  fs5.writeFileSync(breadcrumb, dir);
@@ -14729,7 +14823,7 @@ function getProjectStateDir(projectDir) {
14729
14823
  return stateDir;
14730
14824
  }
14731
14825
  function getMarathonStateDir(projectDir) {
14732
- return path5.join(getProjectStateDir(projectDir), "marathons");
14826
+ return path6.join(getProjectStateDir(projectDir), "marathons");
14733
14827
  }
14734
14828
 
14735
14829
  // src/marathon/checkpoint.ts
@@ -14740,12 +14834,12 @@ function stateSafeName(name) {
14740
14834
  return name.replace(/[^a-zA-Z0-9_-]/g, "_");
14741
14835
  }
14742
14836
  function marathonArtifactsDir(taskName, stateDir) {
14743
- return path6.join(stateDir || defaultStateDir(), stateSafeName(taskName));
14837
+ return path7.join(stateDir || defaultStateDir(), stateSafeName(taskName));
14744
14838
  }
14745
14839
  function resolveMarathonCheckpointPath(taskName, targetPath, stateDir) {
14746
- const normalizedTargetPath = path6.normalize(targetPath);
14747
- const relativeTargetPath = path6.isAbsolute(normalizedTargetPath) ? path6.relative(process.cwd(), normalizedTargetPath) : normalizedTargetPath;
14748
- return path6.join(
14840
+ const normalizedTargetPath = path7.normalize(targetPath);
14841
+ const relativeTargetPath = path7.isAbsolute(normalizedTargetPath) ? path7.relative(process.cwd(), normalizedTargetPath) : normalizedTargetPath;
14842
+ return path7.join(
14749
14843
  marathonArtifactsDir(taskName, stateDir),
14750
14844
  "checkpoints",
14751
14845
  "original",
@@ -14753,23 +14847,23 @@ function resolveMarathonCheckpointPath(taskName, targetPath, stateDir) {
14753
14847
  );
14754
14848
  }
14755
14849
  function ensureMarathonFileCheckpoint(taskName, targetPath, stateDir) {
14756
- const normalizedTargetPath = path6.resolve(targetPath);
14757
- const relativeTargetPath = path6.relative(process.cwd(), normalizedTargetPath);
14850
+ const normalizedTargetPath = path7.resolve(targetPath);
14851
+ const relativeTargetPath = path7.relative(process.cwd(), normalizedTargetPath);
14758
14852
  if (!relativeTargetPath || relativeTargetPath.startsWith("..")) return void 0;
14759
14853
  if (!fs6.existsSync(normalizedTargetPath)) return void 0;
14760
14854
  if (!fs6.statSync(normalizedTargetPath).isFile()) return void 0;
14761
14855
  const normalizedRelativeTargetPath = relativeTargetPath.replace(/\\/g, "/");
14762
14856
  if (normalizedRelativeTargetPath.startsWith(".runtype/")) return void 0;
14763
- if (normalizedTargetPath.startsWith(getRuntypeHomeDir() + path6.sep)) return void 0;
14857
+ if (normalizedTargetPath.startsWith(getRuntypeHomeDir() + path7.sep)) return void 0;
14764
14858
  const checkpointPath = resolveMarathonCheckpointPath(taskName, normalizedTargetPath, stateDir);
14765
14859
  if (fs6.existsSync(checkpointPath)) return checkpointPath;
14766
- fs6.mkdirSync(path6.dirname(checkpointPath), { recursive: true });
14860
+ fs6.mkdirSync(path7.dirname(checkpointPath), { recursive: true });
14767
14861
  fs6.copyFileSync(normalizedTargetPath, checkpointPath);
14768
14862
  return checkpointPath;
14769
14863
  }
14770
14864
  function restoreMarathonFileCheckpoint(taskName, targetPath, stateDir) {
14771
- const normalizedTargetPath = path6.resolve(targetPath);
14772
- const relativeTargetPath = path6.relative(process.cwd(), normalizedTargetPath);
14865
+ const normalizedTargetPath = path7.resolve(targetPath);
14866
+ const relativeTargetPath = path7.relative(process.cwd(), normalizedTargetPath);
14773
14867
  if (!relativeTargetPath || relativeTargetPath.startsWith("..")) {
14774
14868
  return {
14775
14869
  restored: false,
@@ -14784,7 +14878,7 @@ function restoreMarathonFileCheckpoint(taskName, targetPath, stateDir) {
14784
14878
  error: `No checkpoint found for ${normalizedTargetPath}`
14785
14879
  };
14786
14880
  }
14787
- fs6.mkdirSync(path6.dirname(normalizedTargetPath), { recursive: true });
14881
+ fs6.mkdirSync(path7.dirname(normalizedTargetPath), { recursive: true });
14788
14882
  fs6.copyFileSync(checkpointPath, normalizedTargetPath);
14789
14883
  return { restored: true, checkpointPath };
14790
14884
  }
@@ -14910,7 +15004,7 @@ async function retryOnNetworkError(fn, opts = {}) {
14910
15004
  }
14911
15005
  const delay = Math.min(baseDelay * 2 ** attempt, maxDelay);
14912
15006
  opts.onRetry?.(attempt + 1, delay, error);
14913
- await new Promise((resolve7) => setTimeout(resolve7, delay));
15007
+ await new Promise((resolve8) => setTimeout(resolve8, delay));
14914
15008
  }
14915
15009
  }
14916
15010
  throw lastError;
@@ -14984,6 +15078,72 @@ function formatMarathonApiError(error) {
14984
15078
  }
14985
15079
 
14986
15080
  // src/marathon/verification.ts
15081
+ var SAFE_ENV_KEYS = [
15082
+ "PATH",
15083
+ "HOME",
15084
+ "USER",
15085
+ "SHELL",
15086
+ "TERM",
15087
+ "COLORTERM",
15088
+ "FORCE_COLOR",
15089
+ "CI",
15090
+ "NODE_PATH",
15091
+ "NODE_ENV",
15092
+ "NPM_CONFIG_CACHE",
15093
+ "LANG",
15094
+ "LC_ALL",
15095
+ "LC_CTYPE",
15096
+ "TMPDIR",
15097
+ "TMP",
15098
+ "TEMP",
15099
+ "HOSTNAME",
15100
+ "PNPM_HOME",
15101
+ "XDG_CONFIG_HOME",
15102
+ "XDG_DATA_HOME",
15103
+ "XDG_CACHE_HOME"
15104
+ ];
15105
+ function getSanitizedEnv() {
15106
+ const clean = {};
15107
+ for (const key of SAFE_ENV_KEYS) {
15108
+ if (process.env[key]) clean[key] = process.env[key];
15109
+ }
15110
+ return clean;
15111
+ }
15112
+ function redactSecrets(output, secrets) {
15113
+ const sorted = secrets.filter((s) => s.length >= 8).sort((a, b) => b.length - a.length);
15114
+ let redacted = output;
15115
+ for (const secret of sorted) {
15116
+ redacted = redacted.replaceAll(secret, "[REDACTED]");
15117
+ }
15118
+ return redacted;
15119
+ }
15120
+ function collectSecretValues() {
15121
+ const secretPatterns = [
15122
+ /key/i,
15123
+ /secret/i,
15124
+ /token/i,
15125
+ /password/i,
15126
+ /credential/i,
15127
+ /auth/i,
15128
+ /api_key/i,
15129
+ /apikey/i,
15130
+ /private/i,
15131
+ /signing/i,
15132
+ /encryption/i,
15133
+ /database_url/i,
15134
+ /connection_string/i,
15135
+ /dsn/i
15136
+ ];
15137
+ const secrets = [];
15138
+ for (const [key, value] of Object.entries(process.env)) {
15139
+ if (!value || value.length < 8) continue;
15140
+ if (SAFE_ENV_KEYS.includes(key)) continue;
15141
+ if (secretPatterns.some((pattern) => pattern.test(key))) {
15142
+ secrets.push(value);
15143
+ }
15144
+ }
15145
+ return secrets;
15146
+ }
14987
15147
  var BLOCKED_VERIFICATION_PATTERNS = [
14988
15148
  /&&/,
14989
15149
  /\|\|/,
@@ -15022,10 +15182,54 @@ function isSafeVerificationCommand(command) {
15022
15182
  if (BLOCKED_VERIFICATION_PATTERNS.some((pattern) => pattern.test(trimmed))) return false;
15023
15183
  return ALLOWED_VERIFICATION_COMMANDS.some((pattern) => pattern.test(trimmed));
15024
15184
  }
15185
+ var SCRIPT_COMMAND_PATTERNS = [
15186
+ {
15187
+ pattern: /^(?:pnpm|npm|yarn|bun)\s+(?:test|lint|build|check|typecheck|run\s+\w+)\b/i,
15188
+ files: ["package.json"]
15189
+ },
15190
+ {
15191
+ pattern: /^make\s+/i,
15192
+ files: ["Makefile", "makefile", "GNUmakefile"]
15193
+ },
15194
+ {
15195
+ pattern: /^just\s+/i,
15196
+ files: ["justfile", "Justfile"]
15197
+ }
15198
+ ];
15199
+ function getScriptConfigFiles(command) {
15200
+ const trimmed = command.trim();
15201
+ for (const { pattern, files } of SCRIPT_COMMAND_PATTERNS) {
15202
+ if (pattern.test(trimmed)) return files;
15203
+ }
15204
+ return [];
15205
+ }
15206
+ function isScriptConfigModified(cwd, files) {
15207
+ try {
15208
+ const { spawnSync: spawnSync2 } = __require("child_process");
15209
+ const spawnOpts = { cwd, encoding: "utf-8", timeout: 5e3 };
15210
+ const failed = (r) => r.error != null || r.status === null || r.status !== 0;
15211
+ const diff = spawnSync2("git", ["diff", "--name-only", "HEAD", "--", ...files], spawnOpts);
15212
+ if (failed(diff)) return true;
15213
+ if (diff.stdout?.trim()) return true;
15214
+ const staged = spawnSync2("git", ["diff", "--name-only", "--cached", "--", ...files], spawnOpts);
15215
+ if (failed(staged)) return true;
15216
+ if (staged.stdout?.trim()) return true;
15217
+ const lsFiles = spawnSync2(
15218
+ "git",
15219
+ ["ls-files", "--others", "--exclude-standard", "--", ...files],
15220
+ spawnOpts
15221
+ );
15222
+ if (lsFiles.error != null || lsFiles.status === null) return true;
15223
+ if (lsFiles.stdout?.trim()) return true;
15224
+ return false;
15225
+ } catch {
15226
+ return true;
15227
+ }
15228
+ }
15025
15229
 
15026
15230
  // src/marathon/state.ts
15027
15231
  import * as fs7 from "fs";
15028
- import * as path7 from "path";
15232
+ import * as path8 from "path";
15029
15233
  import chalk15 from "chalk";
15030
15234
 
15031
15235
  // src/lib/select-prompt.ts
@@ -15060,14 +15264,14 @@ async function promptNumericSelect(choices, promptLabel) {
15060
15264
  output: process.stdout,
15061
15265
  terminal: true
15062
15266
  });
15063
- return new Promise((resolve7) => {
15267
+ return new Promise((resolve8) => {
15064
15268
  const ask = () => {
15065
15269
  rl.question(chalk14.cyan(`
15066
15270
  ${promptLabel} (1-${choices.length}): `), (answer) => {
15067
15271
  const value = parseInt(answer.trim(), 10);
15068
15272
  if (value >= 1 && value <= choices.length) {
15069
15273
  rl.close();
15070
- resolve7(choices[value - 1].value);
15274
+ resolve8(choices[value - 1].value);
15071
15275
  return;
15072
15276
  }
15073
15277
  console.log(chalk14.red(`Please enter a number between 1 and ${choices.length}.`));
@@ -15095,7 +15299,7 @@ ${message}`));
15095
15299
  const previousRawMode = input.isRaw === true;
15096
15300
  let selectedIndex = 0;
15097
15301
  let renderedLineCount = 0;
15098
- return new Promise((resolve7) => {
15302
+ return new Promise((resolve8) => {
15099
15303
  const renderMenu = () => {
15100
15304
  if (renderedLineCount > 0) {
15101
15305
  clearRenderedLines(output, renderedLineCount);
@@ -15117,7 +15321,7 @@ ${message}`));
15117
15321
  };
15118
15322
  const finish = (value) => {
15119
15323
  cleanup();
15120
- resolve7(value);
15324
+ resolve8(value);
15121
15325
  };
15122
15326
  const onKeypress = (_, key) => {
15123
15327
  if (key.ctrl && key.name === "c") {
@@ -15163,7 +15367,7 @@ function stateSafeName2(name) {
15163
15367
  }
15164
15368
  function stateFilePath(name, stateDir) {
15165
15369
  const dir = stateDir || defaultStateDir2();
15166
- return path7.join(dir, `${stateSafeName2(name)}.json`);
15370
+ return path8.join(dir, `${stateSafeName2(name)}.json`);
15167
15371
  }
15168
15372
  function normalizeMarathonStatePath(candidatePath) {
15169
15373
  if (!candidatePath) return void 0;
@@ -15172,15 +15376,15 @@ function normalizeMarathonStatePath(candidatePath) {
15172
15376
  }
15173
15377
  function marathonStatePathExists(candidatePath) {
15174
15378
  if (!candidatePath) return false;
15175
- return fs7.existsSync(path7.resolve(candidatePath));
15379
+ return fs7.existsSync(path8.resolve(candidatePath));
15176
15380
  }
15177
15381
  function isMarathonArtifactStatePath(candidatePath) {
15178
15382
  if (!candidatePath) return false;
15179
15383
  const normalized = normalizeMarathonStatePath(candidatePath)?.toLowerCase();
15180
15384
  if (normalized === ".runtype" || normalized?.startsWith(".runtype/") === true) return true;
15181
- const resolved = path7.resolve(candidatePath);
15385
+ const resolved = path8.resolve(candidatePath);
15182
15386
  const homeStateDir = getRuntypeHomeDir();
15183
- return resolved.startsWith(homeStateDir + path7.sep) || resolved === homeStateDir;
15387
+ return resolved.startsWith(homeStateDir + path8.sep) || resolved === homeStateDir;
15184
15388
  }
15185
15389
  function scoreMarathonCandidatePath(candidatePath) {
15186
15390
  const normalized = candidatePath.toLowerCase();
@@ -15353,7 +15557,7 @@ function loadState(filePath) {
15353
15557
  }
15354
15558
  }
15355
15559
  function saveState(filePath, state, options) {
15356
- const dir = path7.dirname(filePath);
15560
+ const dir = path8.dirname(filePath);
15357
15561
  fs7.mkdirSync(dir, { recursive: true });
15358
15562
  const stateToWrite = options?.stripSnapshotEvents && state.sessionSnapshots?.length ? {
15359
15563
  ...state,
@@ -15393,9 +15597,9 @@ function findStateFile(name, stateDir) {
15393
15597
  }
15394
15598
  const homePath = stateFilePath(name, getMarathonStateDir());
15395
15599
  if (fs7.existsSync(homePath)) return homePath;
15396
- const oldMarathonPath = stateFilePath(name, path7.join(process.cwd(), ".runtype", "marathons"));
15600
+ const oldMarathonPath = stateFilePath(name, path8.join(process.cwd(), ".runtype", "marathons"));
15397
15601
  if (fs7.existsSync(oldMarathonPath)) return oldMarathonPath;
15398
- const oldTaskPath = stateFilePath(name, path7.join(process.cwd(), ".runtype", "tasks"));
15602
+ const oldTaskPath = stateFilePath(name, path8.join(process.cwd(), ".runtype", "tasks"));
15399
15603
  if (fs7.existsSync(oldTaskPath)) return oldTaskPath;
15400
15604
  return homePath;
15401
15605
  }
@@ -15404,15 +15608,15 @@ function findLatestStateFile(stateDir) {
15404
15608
  // New home-dir location
15405
15609
  getMarathonStateDir(),
15406
15610
  // Old project-dir locations (backward compat)
15407
- path7.join(process.cwd(), ".runtype", "marathons"),
15408
- path7.join(process.cwd(), ".runtype", "tasks")
15611
+ path8.join(process.cwd(), ".runtype", "marathons"),
15612
+ path8.join(process.cwd(), ".runtype", "tasks")
15409
15613
  ];
15410
15614
  let latest = null;
15411
15615
  for (const dir of dirs) {
15412
15616
  if (!fs7.existsSync(dir)) continue;
15413
15617
  const files = fs7.readdirSync(dir).filter((f) => f.endsWith(".json"));
15414
15618
  for (const file of files) {
15415
- const fullPath = path7.join(dir, file);
15619
+ const fullPath = path8.join(dir, file);
15416
15620
  const stat = fs7.statSync(fullPath);
15417
15621
  if (!latest || stat.mtimeMs > latest.mtime) {
15418
15622
  latest = { name: file.replace(".json", ""), filePath: fullPath, mtime: stat.mtimeMs };
@@ -15534,12 +15738,12 @@ function buildResumeCommand(agent, options, parsedSandbox) {
15534
15738
 
15535
15739
  // src/marathon/local-tools.ts
15536
15740
  import * as fs9 from "fs";
15537
- import * as path9 from "path";
15741
+ import * as path10 from "path";
15538
15742
  import { spawnSync } from "child_process";
15539
15743
 
15540
15744
  // src/marathon/repo-discovery.ts
15541
15745
  import * as fs8 from "fs";
15542
- import * as path8 from "path";
15746
+ import * as path9 from "path";
15543
15747
  var IGNORED_REPO_DIRS = /* @__PURE__ */ new Set([
15544
15748
  ".git",
15545
15749
  ".next",
@@ -15637,8 +15841,8 @@ var SEARCH_STOP_WORDS = /* @__PURE__ */ new Set([
15637
15841
  "do"
15638
15842
  ]);
15639
15843
  function normalizeToolPath(toolPath) {
15640
- const resolved = path8.resolve(toolPath || ".");
15641
- return path8.relative(process.cwd(), resolved) || ".";
15844
+ const resolved = path9.resolve(toolPath || ".");
15845
+ return path9.relative(process.cwd(), resolved) || ".";
15642
15846
  }
15643
15847
  function tokenizeSearchQuery(query) {
15644
15848
  return query.toLowerCase().split(/[^a-z0-9./_-]+/g).map((token) => token.trim()).filter((token) => token.length >= 2 && !SEARCH_STOP_WORDS.has(token));
@@ -15647,7 +15851,7 @@ function scoreSearchPath(relativePath) {
15647
15851
  const normalized = relativePath.replace(/\\/g, "/");
15648
15852
  const segments = normalized.split("/");
15649
15853
  const fileName = segments[segments.length - 1] || normalized;
15650
- const extension = path8.extname(fileName).toLowerCase();
15854
+ const extension = path9.extname(fileName).toLowerCase();
15651
15855
  let score = 0;
15652
15856
  if (LOW_SIGNAL_FILE_NAMES.has(fileName)) score -= 50;
15653
15857
  if (segments.some((segment) => LOW_SIGNAL_PATH_SEGMENTS.has(segment))) score -= 15;
@@ -15663,7 +15867,7 @@ function shouldIgnoreRepoEntry(entryPath) {
15663
15867
  const normalized = normalizeToolPath(entryPath).replace(/\\/g, "/");
15664
15868
  if (normalized === ".") return false;
15665
15869
  if (isSensitivePath(normalized)) return true;
15666
- return normalized.split(path8.sep).some((segment) => IGNORED_REPO_DIRS.has(segment));
15870
+ return normalized.split(path9.sep).some((segment) => IGNORED_REPO_DIRS.has(segment));
15667
15871
  }
15668
15872
  function safeReadTextFile(filePath) {
15669
15873
  try {
@@ -15691,7 +15895,7 @@ function walkRepo(startPath, visitor) {
15691
15895
  continue;
15692
15896
  }
15693
15897
  for (const entry of entries) {
15694
- const entryPath = path8.join(currentDir, entry.name);
15898
+ const entryPath = path9.join(currentDir, entry.name);
15695
15899
  if (shouldIgnoreRepoEntry(entryPath)) continue;
15696
15900
  const shouldStop = visitor(entryPath, entry);
15697
15901
  if (shouldStop === true) return;
@@ -15736,7 +15940,7 @@ function buildTree(dirPath, maxDepth, depth = 0) {
15736
15940
  }
15737
15941
  const lines = [];
15738
15942
  for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
15739
- const entryPath = path8.join(dirPath, entry.name);
15943
+ const entryPath = path9.join(dirPath, entry.name);
15740
15944
  if (shouldIgnoreRepoEntry(entryPath)) continue;
15741
15945
  lines.push(`${" ".repeat(depth)}- ${entry.name}${entry.isDirectory() ? "/" : ""}`);
15742
15946
  if (entry.isDirectory() && depth < maxDepth) {
@@ -15752,14 +15956,14 @@ function stateSafeName3(name) {
15752
15956
  return name.replace(/[^a-zA-Z0-9_-]/g, "_");
15753
15957
  }
15754
15958
  function getOffloadedOutputDir(taskName, stateDir) {
15755
- return path9.join(stateDir || getMarathonStateDir(), stateSafeName3(taskName), "outputs");
15959
+ return path10.join(stateDir || getMarathonStateDir(), stateSafeName3(taskName), "outputs");
15756
15960
  }
15757
15961
  function isPathWithinRoot(targetPath, rootPath) {
15758
- const relativePath = path9.relative(rootPath, targetPath);
15759
- return relativePath === "" || !relativePath.startsWith("..") && !path9.isAbsolute(relativePath);
15962
+ const relativePath = path10.relative(rootPath, targetPath);
15963
+ return relativePath === "" || !relativePath.startsWith("..") && !path10.isAbsolute(relativePath);
15760
15964
  }
15761
15965
  function resolveCanonicalToolPath(toolPath, allowMissing) {
15762
- const absolutePath = path9.resolve(toolPath);
15966
+ const absolutePath = path10.resolve(toolPath);
15763
15967
  if (fs9.existsSync(absolutePath)) {
15764
15968
  return {
15765
15969
  canonicalPath: fs9.realpathSync.native(absolutePath),
@@ -15770,22 +15974,22 @@ function resolveCanonicalToolPath(toolPath, allowMissing) {
15770
15974
  const missingSegments = [];
15771
15975
  let currentPath = absolutePath;
15772
15976
  while (!fs9.existsSync(currentPath)) {
15773
- const parentPath = path9.dirname(currentPath);
15977
+ const parentPath = path10.dirname(currentPath);
15774
15978
  if (parentPath === currentPath) return null;
15775
- missingSegments.unshift(path9.basename(currentPath));
15979
+ missingSegments.unshift(path10.basename(currentPath));
15776
15980
  currentPath = parentPath;
15777
15981
  }
15778
15982
  return {
15779
- canonicalPath: path9.join(fs9.realpathSync.native(currentPath), ...missingSegments),
15983
+ canonicalPath: path10.join(fs9.realpathSync.native(currentPath), ...missingSegments),
15780
15984
  exists: false
15781
15985
  };
15782
15986
  }
15783
15987
  function canonicalizeAllowedRoot(rootPath) {
15784
- return resolveCanonicalToolPath(rootPath, true)?.canonicalPath || path9.resolve(rootPath);
15988
+ return resolveCanonicalToolPath(rootPath, true)?.canonicalPath || path10.resolve(rootPath);
15785
15989
  }
15786
15990
  function findBlockedWorkspaceSegment(targetPath, workspaceRoot) {
15787
15991
  if (!isPathWithinRoot(targetPath, workspaceRoot)) return void 0;
15788
- const relativePath = path9.relative(workspaceRoot, targetPath).replace(/\\/g, "/");
15992
+ const relativePath = path10.relative(workspaceRoot, targetPath).replace(/\\/g, "/");
15789
15993
  if (!relativePath) return void 0;
15790
15994
  return relativePath.split("/").find((segment) => DIRECT_TOOL_BLOCKED_SEGMENTS.has(segment));
15791
15995
  }
@@ -15814,19 +16018,24 @@ function resolveToolPath(toolPath, options = {}) {
15814
16018
  };
15815
16019
  }
15816
16020
  if (matchedRoot === workspaceRoot) {
15817
- const blockedSegment = findBlockedWorkspaceSegment(resolved.canonicalPath, workspaceRoot);
15818
- if (blockedSegment) {
15819
- return {
15820
- ok: false,
15821
- error: `Access denied: ${requestedPath} is inside restricted workspace state (${blockedSegment})`
15822
- };
15823
- }
15824
- const relativeFromWorkspace = path9.relative(workspaceRoot, resolved.canonicalPath).replace(/\\/g, "/");
15825
- if (isSensitivePath(relativeFromWorkspace)) {
15826
- return {
15827
- ok: false,
15828
- error: `Access denied: ${requestedPath} is a sensitive path and cannot be read or written`
15829
- };
16021
+ const isUnderExtraRoot = extraRoots.some(
16022
+ (extraRoot) => isPathWithinRoot(resolved.canonicalPath, extraRoot)
16023
+ );
16024
+ if (!isUnderExtraRoot) {
16025
+ const blockedSegment = findBlockedWorkspaceSegment(resolved.canonicalPath, workspaceRoot);
16026
+ if (blockedSegment) {
16027
+ return {
16028
+ ok: false,
16029
+ error: `Access denied: ${requestedPath} is inside restricted workspace state (${blockedSegment})`
16030
+ };
16031
+ }
16032
+ const relativeFromWorkspace = path10.relative(workspaceRoot, resolved.canonicalPath).replace(/\\/g, "/");
16033
+ if (isSensitivePath(relativeFromWorkspace)) {
16034
+ return {
16035
+ ok: false,
16036
+ error: `Access denied: ${requestedPath} is a sensitive path and cannot be read or written`
16037
+ };
16038
+ }
15830
16039
  }
15831
16040
  }
15832
16041
  if (resolved.exists) {
@@ -15849,15 +16058,17 @@ function resolveToolPath(toolPath, options = {}) {
15849
16058
  return { ok: true, resolvedPath: resolved.canonicalPath };
15850
16059
  }
15851
16060
  function getTaskStateRoot(taskName, stateDir) {
15852
- return path9.join(stateDir || getMarathonStateDir(), stateSafeName3(taskName));
16061
+ return path10.join(stateDir || getMarathonStateDir(), stateSafeName3(taskName));
15853
16062
  }
15854
16063
  function createDefaultLocalTools(context) {
15855
16064
  const taskStateRoot = context?.taskName ? getTaskStateRoot(context.taskName, context.stateDir) : void 0;
15856
- const planDir = context?.taskName ? path9.resolve(`.runtype/marathons/${stateSafeName3(context.taskName)}`) : void 0;
16065
+ const planDir = context?.taskName ? path10.resolve(`.runtype/marathons/${stateSafeName3(context.taskName)}`) : void 0;
16066
+ const planPathDir = context?.planPath ? path10.resolve(path10.dirname(context.planPath)) : void 0;
15857
16067
  const allowedReadRoots = context?.taskName ? [
15858
16068
  getOffloadedOutputDir(context.taskName, context.stateDir),
15859
16069
  ...taskStateRoot ? [taskStateRoot] : [],
15860
- ...planDir ? [planDir] : []
16070
+ ...planDir ? [planDir] : [],
16071
+ ...planPathDir ? [planPathDir] : []
15861
16072
  ] : [];
15862
16073
  return {
15863
16074
  read_file: {
@@ -15895,7 +16106,7 @@ function createDefaultLocalTools(context) {
15895
16106
  if (fs9.existsSync(resolvedPath.resolvedPath) && fs9.statSync(resolvedPath.resolvedPath).isDirectory()) {
15896
16107
  return `Error: Path is a directory: ${String(args.path || "")}`;
15897
16108
  }
15898
- const dir = path9.dirname(resolvedPath.resolvedPath);
16109
+ const dir = path10.dirname(resolvedPath.resolvedPath);
15899
16110
  fs9.mkdirSync(dir, { recursive: true });
15900
16111
  fs9.writeFileSync(resolvedPath.resolvedPath, content);
15901
16112
  return "ok";
@@ -15912,7 +16123,7 @@ function createDefaultLocalTools(context) {
15912
16123
  requireDirectory: true
15913
16124
  });
15914
16125
  if (!resolvedPath.ok) return `Error: ${resolvedPath.error}`;
15915
- return fs9.readdirSync(resolvedPath.resolvedPath, { withFileTypes: true }).filter((entry) => !shouldIgnoreRepoEntry(path9.join(resolvedPath.resolvedPath, entry.name))).map((entry) => entry.name).join("\n");
16126
+ return fs9.readdirSync(resolvedPath.resolvedPath, { withFileTypes: true }).filter((entry) => !shouldIgnoreRepoEntry(path10.join(resolvedPath.resolvedPath, entry.name))).map((entry) => entry.name).join("\n");
15916
16127
  }
15917
16128
  },
15918
16129
  search_repo: {
@@ -16059,9 +16270,12 @@ function createDefaultLocalTools(context) {
16059
16270
  }
16060
16271
  };
16061
16272
  }
16062
- function createCheckpointedWriteFileTool(taskName, stateDir) {
16273
+ function createCheckpointedWriteFileTool(taskName, stateDir, planPath) {
16063
16274
  const taskStateRoot = getTaskStateRoot(taskName, stateDir);
16064
- const planDir = path9.resolve(`.runtype/marathons/${stateSafeName3(taskName)}`);
16275
+ const planDir = path10.resolve(`.runtype/marathons/${stateSafeName3(taskName)}`);
16276
+ const marathonPlanRoot = path10.resolve(".runtype/marathons");
16277
+ const planPathDir = planPath ? path10.resolve(path10.dirname(planPath)) : void 0;
16278
+ const writeAllowedRoots = [taskStateRoot, planDir, marathonPlanRoot, ...planPathDir ? [planPathDir] : []];
16065
16279
  return {
16066
16280
  description: "Write content to a file, creating directories as needed and checkpointing original repo files",
16067
16281
  parametersSchema: {
@@ -16075,14 +16289,102 @@ function createCheckpointedWriteFileTool(taskName, stateDir) {
16075
16289
  execute: async (args) => {
16076
16290
  const resolvedPath = resolveToolPath(String(args.path || ""), {
16077
16291
  allowMissing: true,
16078
- allowedRoots: [taskStateRoot, planDir]
16292
+ allowedRoots: writeAllowedRoots
16079
16293
  });
16080
16294
  if (!resolvedPath.ok) return `Error: ${resolvedPath.error}`;
16081
16295
  const content = String(args.content || "");
16082
16296
  ensureMarathonFileCheckpoint(taskName, resolvedPath.resolvedPath, stateDir);
16083
- const dir = path9.dirname(resolvedPath.resolvedPath);
16297
+ const dir = path10.dirname(resolvedPath.resolvedPath);
16084
16298
  fs9.mkdirSync(dir, { recursive: true });
16085
16299
  fs9.writeFileSync(resolvedPath.resolvedPath, content);
16300
+ const ext = path10.extname(resolvedPath.resolvedPath).toLowerCase();
16301
+ if (ext === ".js" || ext === ".jsx") {
16302
+ const syntaxError = quickJsSyntaxCheck(content);
16303
+ if (syntaxError) {
16304
+ return `ok
16305
+
16306
+ \u26A0\uFE0F Syntax error detected in written file: ${syntaxError}. The file was written but contains errors. Read it back and fix the issues.`;
16307
+ }
16308
+ }
16309
+ return "ok";
16310
+ }
16311
+ };
16312
+ }
16313
+ function quickJsSyntaxCheck(content) {
16314
+ try {
16315
+ new Function(content);
16316
+ return void 0;
16317
+ } catch (err) {
16318
+ if (err instanceof SyntaxError) {
16319
+ return err.message;
16320
+ }
16321
+ return void 0;
16322
+ }
16323
+ }
16324
+ function createEditFileTool(taskName, stateDir, planPath) {
16325
+ const taskStateRoot = getTaskStateRoot(taskName, stateDir);
16326
+ const planDir = path10.resolve(`.runtype/marathons/${stateSafeName3(taskName)}`);
16327
+ const marathonPlanRoot = path10.resolve(".runtype/marathons");
16328
+ const planPathDir = planPath ? path10.resolve(path10.dirname(planPath)) : void 0;
16329
+ const writeAllowedRoots = [taskStateRoot, planDir, marathonPlanRoot, ...planPathDir ? [planPathDir] : []];
16330
+ return {
16331
+ description: "Make a targeted edit to a file by replacing a specific string. Much more efficient than rewriting the entire file with write_file. The old_string must appear exactly once in the file (or use replace_all for global replacement). Always read the file first to get the exact text to replace.",
16332
+ parametersSchema: {
16333
+ type: "object",
16334
+ properties: {
16335
+ path: { type: "string", description: "File path to edit" },
16336
+ // @snake-case-ok: Parameter names use snake_case to match agent tool conventions
16337
+ old_string: { type: "string", description: "Exact string to find and replace (must be unique in the file)" },
16338
+ // @snake-case-ok: Parameter names use snake_case to match agent tool conventions
16339
+ new_string: { type: "string", description: "Replacement string" },
16340
+ // @snake-case-ok: Parameter names use snake_case to match agent tool conventions
16341
+ replace_all: {
16342
+ type: "boolean",
16343
+ description: "If true, replace all occurrences instead of requiring uniqueness. Default: false"
16344
+ }
16345
+ },
16346
+ required: ["path", "old_string", "new_string"]
16347
+ },
16348
+ execute: async (args) => {
16349
+ const resolvedPath = resolveToolPath(String(args.path || ""), {
16350
+ requireFile: true,
16351
+ allowedRoots: writeAllowedRoots
16352
+ });
16353
+ if (!resolvedPath.ok) return `Error: ${resolvedPath.error}`;
16354
+ const oldString = String(args.old_string ?? "");
16355
+ const newString = String(args.new_string ?? "");
16356
+ const replaceAll = Boolean(args.replace_all);
16357
+ if (!oldString) return "Error: old_string cannot be empty";
16358
+ if (oldString === newString) return "Error: old_string and new_string are identical";
16359
+ let content;
16360
+ try {
16361
+ content = fs9.readFileSync(resolvedPath.resolvedPath, "utf-8");
16362
+ } catch {
16363
+ return `Error: Could not read file: ${String(args.path || "")}`;
16364
+ }
16365
+ if (!content.includes(oldString)) {
16366
+ return `Error: old_string not found in ${String(args.path || "")}. Read the file first to get the exact text.`;
16367
+ }
16368
+ if (!replaceAll) {
16369
+ const firstIndex = content.indexOf(oldString);
16370
+ const secondIndex = content.indexOf(oldString, firstIndex + 1);
16371
+ if (secondIndex !== -1) {
16372
+ const count = content.split(oldString).length - 1;
16373
+ return `Error: old_string appears ${count} times in the file. Provide more surrounding context to make it unique, or set replace_all to true.`;
16374
+ }
16375
+ }
16376
+ ensureMarathonFileCheckpoint(taskName, resolvedPath.resolvedPath, stateDir);
16377
+ const updated = replaceAll ? content.split(oldString).join(newString) : content.replace(oldString, newString);
16378
+ fs9.writeFileSync(resolvedPath.resolvedPath, updated);
16379
+ const ext = path10.extname(resolvedPath.resolvedPath).toLowerCase();
16380
+ if (ext === ".js" || ext === ".jsx") {
16381
+ const syntaxError = quickJsSyntaxCheck(updated);
16382
+ if (syntaxError) {
16383
+ return `ok
16384
+
16385
+ \u26A0\uFE0F Syntax error detected after edit: ${syntaxError}. The edit was applied but the file now contains errors.`;
16386
+ }
16387
+ }
16086
16388
  return "ok";
16087
16389
  }
16088
16390
  };
@@ -16129,7 +16431,7 @@ function createReadOffloadedOutputTool(taskName, stateDir) {
16129
16431
  if (!/^[a-zA-Z0-9_-]+$/.test(outputId)) {
16130
16432
  return `Error: invalid offloaded output id: ${outputId}`;
16131
16433
  }
16132
- const outputPath = path9.join(getOffloadedOutputDir(taskName, stateDir), `${outputId}.txt`);
16434
+ const outputPath = path10.join(getOffloadedOutputDir(taskName, stateDir), `${outputId}.txt`);
16133
16435
  if (!fs9.existsSync(outputPath) || !fs9.statSync(outputPath).isFile()) {
16134
16436
  return `Error: offloaded output not found: ${outputId}`;
16135
16437
  }
@@ -16171,6 +16473,15 @@ function createRunCheckTool() {
16171
16473
  error: "Blocked unsafe verification command. Use a single non-destructive lint/test/typecheck/build command."
16172
16474
  });
16173
16475
  }
16476
+ const configFiles = getScriptConfigFiles(command);
16477
+ if (configFiles.length > 0 && isScriptConfigModified(process.cwd(), configFiles)) {
16478
+ return JSON.stringify({
16479
+ success: false,
16480
+ blocked: true,
16481
+ command,
16482
+ error: `Blocked: ${configFiles.join("/")} has been modified since last commit. Cannot run script commands when config files have uncommitted changes.`
16483
+ });
16484
+ }
16174
16485
  const timeoutMs = Math.max(
16175
16486
  1e3,
16176
16487
  Math.min(
@@ -16184,9 +16495,11 @@ function createRunCheckTool() {
16184
16495
  encoding: "utf-8",
16185
16496
  shell: true,
16186
16497
  timeout: timeoutMs,
16187
- maxBuffer: 1024 * 1024 * 4
16498
+ maxBuffer: 1024 * 1024 * 4,
16499
+ env: getSanitizedEnv()
16188
16500
  });
16189
- const output = `${result.stdout || ""}${result.stderr || ""}`.trim().slice(0, 12e3);
16501
+ const rawOutput = `${result.stdout || ""}${result.stderr || ""}`.trim().slice(0, 12e3);
16502
+ const output = redactSecrets(rawOutput, collectSecretValues());
16190
16503
  return JSON.stringify({
16191
16504
  success: result.status === 0 && !result.error,
16192
16505
  command,
@@ -16261,7 +16574,8 @@ function buildLocalTools(client, sandboxProvider, options, context) {
16261
16574
  if (!options.noLocalTools) {
16262
16575
  Object.assign(enabledTools, createDefaultLocalTools(context));
16263
16576
  if (context) {
16264
- enabledTools.write_file = createCheckpointedWriteFileTool(context.taskName, context.stateDir);
16577
+ enabledTools.write_file = createCheckpointedWriteFileTool(context.taskName, context.stateDir, context.planPath);
16578
+ enabledTools.edit_file = createEditFileTool(context.taskName, context.stateDir, context.planPath);
16265
16579
  enabledTools.restore_file_checkpoint = createRestoreFileCheckpointTool(
16266
16580
  context.taskName,
16267
16581
  context.stateDir
@@ -16422,7 +16736,7 @@ function createLoopDetector(options = {}) {
16422
16736
 
16423
16737
  // src/marathon/context-offload.ts
16424
16738
  import * as fs10 from "fs";
16425
- import * as path10 from "path";
16739
+ import * as path11 from "path";
16426
16740
  var DEFAULT_OUTPUT_THRESHOLD = 2e3;
16427
16741
  var DEFAULT_PREVIEW_LENGTH = 200;
16428
16742
  function buildOffloadedOutputId(toolName) {
@@ -16454,13 +16768,13 @@ function offloadToolOutput(taskName, toolName, output, options = {}, stateDir) {
16454
16768
  return { offloaded: false, content: output };
16455
16769
  }
16456
16770
  const outputId = buildOffloadedOutputId(toolName);
16457
- const dir = path10.join(
16771
+ const dir = path11.join(
16458
16772
  stateDir || defaultStateDir3(),
16459
16773
  stateSafeName4(taskName),
16460
16774
  "outputs"
16461
16775
  );
16462
16776
  const fileName = `${outputId}.txt`;
16463
- const filePath = path10.join(dir, fileName);
16777
+ const filePath = path11.join(dir, fileName);
16464
16778
  fs10.mkdirSync(dir, { recursive: true });
16465
16779
  fs10.writeFileSync(filePath, output, "utf-8");
16466
16780
  const preview = output.slice(0, previewLength).replace(/\n/g, " ");
@@ -16635,17 +16949,17 @@ function resolveAutoCompactTokenThreshold(modelContextLength, rawThreshold, stra
16635
16949
 
16636
16950
  // src/marathon/recipes.ts
16637
16951
  import * as fs11 from "fs";
16638
- import * as path11 from "path";
16952
+ import * as path12 from "path";
16639
16953
  var RULES_DIR = ".marathon/rules";
16640
16954
  function loadRules(cwd) {
16641
16955
  const baseCwd = cwd || process.cwd();
16642
- const rulesDir = path11.resolve(baseCwd, RULES_DIR);
16956
+ const rulesDir = path12.resolve(baseCwd, RULES_DIR);
16643
16957
  if (!fs11.existsSync(rulesDir)) return [];
16644
16958
  const rules = [];
16645
16959
  try {
16646
16960
  const entries = fs11.readdirSync(rulesDir).filter((f) => f.endsWith(".md"));
16647
16961
  for (const entry of entries) {
16648
- const filePath = path11.join(rulesDir, entry);
16962
+ const filePath = path12.join(rulesDir, entry);
16649
16963
  try {
16650
16964
  const raw = fs11.readFileSync(filePath, "utf-8");
16651
16965
  const parsed = parseRuleFile(raw);
@@ -16722,7 +17036,7 @@ function resolveErrorHandlingForPhase(phase, cliFallbackModel, milestoneFallback
16722
17036
 
16723
17037
  // src/marathon/playbook-loader.ts
16724
17038
  import * as fs12 from "fs";
16725
- import * as path12 from "path";
17039
+ import * as path13 from "path";
16726
17040
  import * as os4 from "os";
16727
17041
  import micromatch from "micromatch";
16728
17042
  import { parse as parseYaml } from "yaml";
@@ -16737,20 +17051,20 @@ function getCandidatePaths(nameOrPath, cwd) {
16737
17051
  const home = os4.homedir();
16738
17052
  return [
16739
17053
  // Exact path
16740
- path12.resolve(cwd, nameOrPath),
17054
+ path13.resolve(cwd, nameOrPath),
16741
17055
  // Repo-level
16742
- path12.resolve(cwd, PLAYBOOKS_DIR, `${nameOrPath}.yaml`),
16743
- path12.resolve(cwd, PLAYBOOKS_DIR, `${nameOrPath}.yml`),
16744
- path12.resolve(cwd, PLAYBOOKS_DIR, `${nameOrPath}.json`),
17056
+ path13.resolve(cwd, PLAYBOOKS_DIR, `${nameOrPath}.yaml`),
17057
+ path13.resolve(cwd, PLAYBOOKS_DIR, `${nameOrPath}.yml`),
17058
+ path13.resolve(cwd, PLAYBOOKS_DIR, `${nameOrPath}.json`),
16745
17059
  // User-level
16746
- path12.resolve(home, PLAYBOOKS_DIR, `${nameOrPath}.yaml`),
16747
- path12.resolve(home, PLAYBOOKS_DIR, `${nameOrPath}.yml`),
16748
- path12.resolve(home, PLAYBOOKS_DIR, `${nameOrPath}.json`)
17060
+ path13.resolve(home, PLAYBOOKS_DIR, `${nameOrPath}.yaml`),
17061
+ path13.resolve(home, PLAYBOOKS_DIR, `${nameOrPath}.yml`),
17062
+ path13.resolve(home, PLAYBOOKS_DIR, `${nameOrPath}.json`)
16749
17063
  ];
16750
17064
  }
16751
17065
  function parsePlaybookFile(filePath) {
16752
17066
  const raw = fs12.readFileSync(filePath, "utf-8");
16753
- const ext = path12.extname(filePath).toLowerCase();
17067
+ const ext = path13.extname(filePath).toLowerCase();
16754
17068
  if (ext === ".json") {
16755
17069
  return JSON.parse(raw);
16756
17070
  }
@@ -17016,6 +17330,8 @@ function buildMarathonStartupModelOptions(configuredModels, availableModels) {
17016
17330
  for (const model of configuredModels) {
17017
17331
  const modelId = model.modelId?.trim();
17018
17332
  if (!modelId) continue;
17333
+ const provider = model.provider?.trim().toLowerCase() ?? "";
17334
+ if ((0, import_integration_providers.isNonAIProvider)(provider) || (0, import_integration_providers.isNonAIProvider)(modelId)) continue;
17019
17335
  pushOption({
17020
17336
  label: model.displayName?.trim() || modelId,
17021
17337
  value: modelId,
@@ -17027,6 +17343,8 @@ function buildMarathonStartupModelOptions(configuredModels, availableModels) {
17027
17343
  for (const provider of model.providers) {
17028
17344
  const modelId2 = provider.modelId?.trim() || model.baseModel?.trim();
17029
17345
  if (!modelId2) continue;
17346
+ const providerName = provider.provider?.trim().toLowerCase() ?? "";
17347
+ if ((0, import_integration_providers.isNonAIProvider)(providerName) || (0, import_integration_providers.isNonAIProvider)(modelId2)) continue;
17030
17348
  pushOption({
17031
17349
  label: provider.displayName?.trim() || model.displayName?.trim() || model.baseModel?.trim() || modelId2,
17032
17350
  value: modelId2,
@@ -17037,6 +17355,7 @@ function buildMarathonStartupModelOptions(configuredModels, availableModels) {
17037
17355
  }
17038
17356
  const modelId = model.baseModel?.trim();
17039
17357
  if (!modelId) continue;
17358
+ if ((0, import_integration_providers.isNonAIProvider)(modelId)) continue;
17040
17359
  pushOption({
17041
17360
  label: model.displayName?.trim() || modelId,
17042
17361
  value: modelId,
@@ -17202,14 +17521,15 @@ async function taskAction(agent, options) {
17202
17521
  const renderedShell = render9(
17203
17522
  React9.createElement(MarathonStartupShell, {
17204
17523
  startupRef: startupShellRef,
17205
- marathonAppProps: null
17524
+ marathonAppProps: null,
17525
+ version: getCliVersion()
17206
17526
  }),
17207
17527
  { exitOnCtrlC: false }
17208
17528
  );
17209
17529
  waitForUiExit = renderedShell.waitUntilExit;
17210
17530
  rerenderUi = renderedShell.rerender;
17211
17531
  unmountUi = renderedShell.unmount;
17212
- await new Promise((resolve7) => setTimeout(resolve7, 0));
17532
+ await new Promise((resolve8) => setTimeout(resolve8, 0));
17213
17533
  if (!startupShellRef.current) {
17214
17534
  exitAltScreen();
17215
17535
  unmountUi?.();
@@ -17589,9 +17909,11 @@ ${rulesContext}`;
17589
17909
  });
17590
17910
  }
17591
17911
  }
17912
+ const resolvedPlanPath = resumeLoadedState?.planPath ?? resumeState?.planPath ?? getDefaultPlanPath(taskName);
17592
17913
  let localTools = buildLocalTools(client, parsedSandbox, options, {
17593
17914
  taskName,
17594
- stateDir: options.stateDir
17915
+ stateDir: options.stateDir,
17916
+ planPath: resolvedPlanPath
17595
17917
  });
17596
17918
  const resolveContextLimitForModel = (modelId) => resolveModelContextLength(modelId, configuredModels, availableModels);
17597
17919
  const resolveCompactStrategyForModel = (modelId) => {
@@ -17651,7 +17973,8 @@ ${rulesContext}`;
17651
17973
  const checkpointHasConfigChanges = (result) => Boolean(result.model) || result.tools === true || result.sandbox !== void 0;
17652
17974
  const rebuildCheckpointTools = () => buildLocalTools(client, parsedSandbox, options, {
17653
17975
  taskName,
17654
- stateDir: options.stateDir
17976
+ stateDir: options.stateDir,
17977
+ planPath: resolvedPlanPath
17655
17978
  });
17656
17979
  const applyCheckpointConfig = (result) => {
17657
17980
  if (result.model) {
@@ -17738,7 +18061,8 @@ Saving state... done. Session saved to ${filePath}`);
17738
18061
  rerenderUi?.(
17739
18062
  React9.createElement(MarathonStartupShell, {
17740
18063
  startupRef: startupShellRef,
17741
- marathonAppProps
18064
+ marathonAppProps,
18065
+ version: getCliVersion()
17742
18066
  })
17743
18067
  );
17744
18068
  await startupShellRef.current?.completeStartup();
@@ -17751,7 +18075,7 @@ Saving state... done. Session saved to ${filePath}`);
17751
18075
  waitForUiExit = renderedApp.waitUntilExit;
17752
18076
  unmountUi = renderedApp.unmount;
17753
18077
  }
17754
- await new Promise((resolve7) => setTimeout(resolve7, 0));
18078
+ await new Promise((resolve8) => setTimeout(resolve8, 0));
17755
18079
  const streamActions = streamRef.current;
17756
18080
  if (!streamActions) {
17757
18081
  exitAltScreen();
@@ -17876,7 +18200,7 @@ Saving state... done. Session saved to ${filePath}`);
17876
18200
  };
17877
18201
  if (event.phase === "start") {
17878
18202
  currentActions.startContextCompaction(absoluteEvent);
17879
- await new Promise((resolve7) => setTimeout(resolve7, 0));
18203
+ await new Promise((resolve8) => setTimeout(resolve8, 0));
17880
18204
  return;
17881
18205
  }
17882
18206
  currentActions.finishContextCompaction(absoluteEvent);
@@ -18118,7 +18442,7 @@ Saving state... done. Session saved to ${filePath}`);
18118
18442
  toolCallsMade: accumulatedToolCalls,
18119
18443
  tokensInput: accumulatedTokens.input,
18120
18444
  tokensOutput: accumulatedTokens.output,
18121
- cost: accumulatedCost,
18445
+ cost: priorCost + accumulatedCost,
18122
18446
  outputPreview: terminalPreview.slice(0, 100)
18123
18447
  };
18124
18448
  const checkpointResult = await currentActions.requestCheckpoint(recap, true);
@@ -19848,13 +20172,13 @@ apiKeysCommand.command("delete <id>").description("Delete an API key").option("-
19848
20172
  await waitUntilExit2();
19849
20173
  return;
19850
20174
  }
19851
- const confirmed = await new Promise((resolve7) => {
20175
+ const confirmed = await new Promise((resolve8) => {
19852
20176
  const { unmount } = render14(
19853
20177
  React14.createElement(ConfirmPrompt, {
19854
20178
  message: `Delete API key ${id}?`,
19855
20179
  defaultValue: false,
19856
20180
  onConfirm: (result) => {
19857
- resolve7(result);
20181
+ resolve8(result);
19858
20182
  unmount();
19859
20183
  }
19860
20184
  })
@@ -19959,8 +20283,8 @@ apiKeysCommand.command("analytics").description("Show API key usage analytics").
19959
20283
  const client = new ApiClient(apiKey);
19960
20284
  if (!isTTY(options) || options.json) {
19961
20285
  try {
19962
- const path13 = options.key ? `/api-keys/${options.key}/analytics` : "/api-keys/analytics";
19963
- const data = await client.get(path13);
20286
+ const path14 = options.key ? `/api-keys/${options.key}/analytics` : "/api-keys/analytics";
20287
+ const data = await client.get(path14);
19964
20288
  printJson(data);
19965
20289
  } catch (error) {
19966
20290
  const message = error instanceof Error ? error.message : "Unknown error";
@@ -19977,8 +20301,8 @@ apiKeysCommand.command("analytics").description("Show API key usage analytics").
19977
20301
  useEffect25(() => {
19978
20302
  const run = async () => {
19979
20303
  try {
19980
- const path13 = options.key ? `/api-keys/${options.key}/analytics` : "/api-keys/analytics";
19981
- const data = await client.get(path13);
20304
+ const path14 = options.key ? `/api-keys/${options.key}/analytics` : "/api-keys/analytics";
20305
+ const data = await client.get(path14);
19982
20306
  printJson(data);
19983
20307
  setSuccess(true);
19984
20308
  setLoading(false);