@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 +488 -164
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
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
|
|
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((
|
|
4569
|
-
this.codeResolve =
|
|
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((
|
|
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
|
-
|
|
5802
|
+
resolve8(defaultYes);
|
|
5770
5803
|
} else {
|
|
5771
|
-
|
|
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
|
-
|
|
5847
|
-
|
|
5848
|
-
|
|
5849
|
-
|
|
5850
|
-
|
|
5851
|
-
|
|
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(
|
|
5916
|
+
path(path14) {
|
|
5873
5917
|
const version = getApiVersion();
|
|
5874
|
-
const p =
|
|
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(
|
|
5908
|
-
const url = new URL(this.path(
|
|
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(
|
|
5922
|
-
const response = await fetch(new URL(this.path(
|
|
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(
|
|
5930
|
-
const response = await fetch(new URL(this.path(
|
|
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(
|
|
5938
|
-
const response = await fetch(new URL(this.path(
|
|
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(
|
|
5946
|
-
const response = await fetch(new URL(this.path(
|
|
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(
|
|
5961
|
-
const response = await fetch(new URL(this.path(
|
|
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
|
-
|
|
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
|
-
|
|
9045
|
-
|
|
9046
|
-
|
|
9047
|
-
|
|
9048
|
-
|
|
9049
|
-
|
|
9050
|
-
|
|
9051
|
-
|
|
9052
|
-
|
|
9053
|
-
|
|
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
|
-
`
|
|
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((
|
|
13094
|
-
checkpointResolveRef.current =
|
|
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
|
|
14430
|
+
const resolve8 = appReadyResolverRef.current;
|
|
14355
14431
|
appReadyResolverRef.current = null;
|
|
14356
|
-
|
|
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((
|
|
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
|
-
|
|
14460
|
+
resolve8();
|
|
14385
14461
|
};
|
|
14386
14462
|
} else {
|
|
14387
14463
|
dismissResolverRef.current = () => {
|
|
14388
14464
|
transitionPromiseRef.current = null;
|
|
14389
|
-
|
|
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((
|
|
14407
|
-
promptResolverRef.current =
|
|
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((
|
|
14416
|
-
modelResolverRef.current =
|
|
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((
|
|
14432
|
-
playbookConfirmResolverRef.current =
|
|
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
|
|
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
|
|
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
|
|
14804
|
+
import * as path7 from "path";
|
|
14711
14805
|
|
|
14712
14806
|
// src/config/paths.ts
|
|
14713
14807
|
import * as os3 from "os";
|
|
14714
|
-
import * as
|
|
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 ||
|
|
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 =
|
|
14724
|
-
const breadcrumb =
|
|
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
|
|
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
|
|
14837
|
+
return path7.join(stateDir || defaultStateDir(), stateSafeName(taskName));
|
|
14744
14838
|
}
|
|
14745
14839
|
function resolveMarathonCheckpointPath(taskName, targetPath, stateDir) {
|
|
14746
|
-
const normalizedTargetPath =
|
|
14747
|
-
const relativeTargetPath =
|
|
14748
|
-
return
|
|
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 =
|
|
14757
|
-
const relativeTargetPath =
|
|
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() +
|
|
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(
|
|
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 =
|
|
14772
|
-
const relativeTargetPath =
|
|
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(
|
|
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((
|
|
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
|
|
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((
|
|
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
|
-
|
|
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((
|
|
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
|
-
|
|
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
|
|
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(
|
|
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 =
|
|
15385
|
+
const resolved = path8.resolve(candidatePath);
|
|
15182
15386
|
const homeStateDir = getRuntypeHomeDir();
|
|
15183
|
-
return resolved.startsWith(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 =
|
|
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,
|
|
15600
|
+
const oldMarathonPath = stateFilePath(name, path8.join(process.cwd(), ".runtype", "marathons"));
|
|
15397
15601
|
if (fs7.existsSync(oldMarathonPath)) return oldMarathonPath;
|
|
15398
|
-
const oldTaskPath = stateFilePath(name,
|
|
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
|
-
|
|
15408
|
-
|
|
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 =
|
|
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
|
|
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
|
|
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 =
|
|
15641
|
-
return
|
|
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 =
|
|
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(
|
|
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 =
|
|
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 =
|
|
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
|
|
15959
|
+
return path10.join(stateDir || getMarathonStateDir(), stateSafeName3(taskName), "outputs");
|
|
15756
15960
|
}
|
|
15757
15961
|
function isPathWithinRoot(targetPath, rootPath) {
|
|
15758
|
-
const relativePath =
|
|
15759
|
-
return relativePath === "" || !relativePath.startsWith("..") && !
|
|
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 =
|
|
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 =
|
|
15977
|
+
const parentPath = path10.dirname(currentPath);
|
|
15774
15978
|
if (parentPath === currentPath) return null;
|
|
15775
|
-
missingSegments.unshift(
|
|
15979
|
+
missingSegments.unshift(path10.basename(currentPath));
|
|
15776
15980
|
currentPath = parentPath;
|
|
15777
15981
|
}
|
|
15778
15982
|
return {
|
|
15779
|
-
canonicalPath:
|
|
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 ||
|
|
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 =
|
|
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
|
|
15818
|
-
|
|
15819
|
-
|
|
15820
|
-
|
|
15821
|
-
|
|
15822
|
-
|
|
15823
|
-
|
|
15824
|
-
|
|
15825
|
-
|
|
15826
|
-
|
|
15827
|
-
|
|
15828
|
-
|
|
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
|
|
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 ?
|
|
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 =
|
|
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(
|
|
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 =
|
|
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:
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
-
|
|
17054
|
+
path13.resolve(cwd, nameOrPath),
|
|
16741
17055
|
// Repo-level
|
|
16742
|
-
|
|
16743
|
-
|
|
16744
|
-
|
|
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
|
-
|
|
16747
|
-
|
|
16748
|
-
|
|
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 =
|
|
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((
|
|
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((
|
|
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((
|
|
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((
|
|
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
|
-
|
|
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
|
|
19963
|
-
const data = await client.get(
|
|
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
|
|
19981
|
-
const data = await client.get(
|
|
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);
|