@runtypelabs/cli 1.8.5 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +149 -18
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -8847,7 +8847,7 @@ function getTabBorderColor(tab) {
|
|
|
8847
8847
|
if (tab.isLive) return theme10.accent;
|
|
8848
8848
|
return theme10.borderActive;
|
|
8849
8849
|
}
|
|
8850
|
-
function SessionTabs({ tabs, hiddenLeft, hiddenRight }) {
|
|
8850
|
+
function SessionTabs({ tabs, hiddenLeft, hiddenRight, shortcutHint }) {
|
|
8851
8851
|
if (tabs.length === 0) return null;
|
|
8852
8852
|
return /* @__PURE__ */ jsxs8(Box8, { children: [
|
|
8853
8853
|
hiddenLeft > 0 && /* @__PURE__ */ jsx9(Text9, { color: theme10.textSubtle, children: `\u2039${hiddenLeft}` }),
|
|
@@ -8875,7 +8875,8 @@ function SessionTabs({ tabs, hiddenLeft, hiddenRight }) {
|
|
|
8875
8875
|
] }, tab.key);
|
|
8876
8876
|
}),
|
|
8877
8877
|
hiddenRight > 0 && /* @__PURE__ */ jsx9(Text9, { children: " " }),
|
|
8878
|
-
hiddenRight > 0 && /* @__PURE__ */ jsx9(Text9, { color: theme10.textSubtle, children: `${hiddenRight}\u203A` })
|
|
8878
|
+
hiddenRight > 0 && /* @__PURE__ */ jsx9(Text9, { color: theme10.textSubtle, children: `${hiddenRight}\u203A` }),
|
|
8879
|
+
shortcutHint && /* @__PURE__ */ jsx9(Text9, { color: theme10.textSubtle, children: ` ${shortcutHint}` })
|
|
8879
8880
|
] });
|
|
8880
8881
|
}
|
|
8881
8882
|
|
|
@@ -9519,7 +9520,7 @@ function EventStreamPanel({
|
|
|
9519
9520
|
// src/ink/marathon/FilesPanel.tsx
|
|
9520
9521
|
import { useMemo as useMemo5 } from "react";
|
|
9521
9522
|
import { Box as Box15, Text as Text16 } from "ink";
|
|
9522
|
-
import { theme as theme17 } from "@runtypelabs/ink-components";
|
|
9523
|
+
import { theme as theme17, renderMarkdownToTerminal } from "@runtypelabs/ink-components";
|
|
9523
9524
|
import { jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
9524
9525
|
var TYPE_COLORS = {
|
|
9525
9526
|
plan: theme17.accent,
|
|
@@ -9540,20 +9541,53 @@ function shortenPath(filePath, maxWidth) {
|
|
|
9540
9541
|
}
|
|
9541
9542
|
return ".../" + segments[segments.length - 1];
|
|
9542
9543
|
}
|
|
9544
|
+
var ANSI_RE = /\x1B\[[0-9;]*m/g;
|
|
9545
|
+
function visibleLength(str) {
|
|
9546
|
+
return str.replace(ANSI_RE, "").length;
|
|
9547
|
+
}
|
|
9543
9548
|
function wrapLines3(lines, width) {
|
|
9544
9549
|
if (width <= 0) return lines;
|
|
9545
9550
|
const result = [];
|
|
9546
9551
|
for (const line of lines) {
|
|
9547
|
-
if (line
|
|
9552
|
+
if (visibleLength(line) <= width) {
|
|
9548
9553
|
result.push(line);
|
|
9549
9554
|
} else {
|
|
9550
|
-
|
|
9551
|
-
|
|
9555
|
+
if (!ANSI_RE.test(line)) {
|
|
9556
|
+
for (let i = 0; i < line.length; i += width) {
|
|
9557
|
+
result.push(line.slice(i, i + width));
|
|
9558
|
+
}
|
|
9559
|
+
} else {
|
|
9560
|
+
let current = "";
|
|
9561
|
+
let vis = 0;
|
|
9562
|
+
let i = 0;
|
|
9563
|
+
while (i < line.length) {
|
|
9564
|
+
if (line[i] === "\x1B" && line[i + 1] === "[") {
|
|
9565
|
+
const end = line.indexOf("m", i);
|
|
9566
|
+
if (end !== -1) {
|
|
9567
|
+
current += line.slice(i, end + 1);
|
|
9568
|
+
i = end + 1;
|
|
9569
|
+
continue;
|
|
9570
|
+
}
|
|
9571
|
+
}
|
|
9572
|
+
current += line[i];
|
|
9573
|
+
vis++;
|
|
9574
|
+
i++;
|
|
9575
|
+
if (vis >= width) {
|
|
9576
|
+
result.push(current);
|
|
9577
|
+
current = "";
|
|
9578
|
+
vis = 0;
|
|
9579
|
+
}
|
|
9580
|
+
}
|
|
9581
|
+
if (current) result.push(current);
|
|
9552
9582
|
}
|
|
9553
9583
|
}
|
|
9554
9584
|
}
|
|
9555
9585
|
return result;
|
|
9556
9586
|
}
|
|
9587
|
+
function isMarkdownFile(filePath) {
|
|
9588
|
+
const lower = filePath.toLowerCase();
|
|
9589
|
+
return lower.endsWith(".md") || lower.endsWith(".mdx");
|
|
9590
|
+
}
|
|
9557
9591
|
function FileContentView({
|
|
9558
9592
|
file,
|
|
9559
9593
|
content,
|
|
@@ -9565,15 +9599,17 @@ function FileContentView({
|
|
|
9565
9599
|
}) {
|
|
9566
9600
|
const separator = theme17.separator ?? " \xB7 ";
|
|
9567
9601
|
const contentWidth = Math.max(20, width - 4);
|
|
9602
|
+
const isMd = isMarkdownFile(file.path);
|
|
9568
9603
|
const { lines, displayTotalLines, clampedOffset } = useMemo5(() => {
|
|
9569
|
-
const
|
|
9604
|
+
const displayContent = isMd ? renderMarkdownToTerminal(content) : content;
|
|
9605
|
+
const rawLines = displayContent.split("\n");
|
|
9570
9606
|
const allLines = wrapLines3(rawLines, contentWidth);
|
|
9571
9607
|
const total = allLines.length;
|
|
9572
9608
|
const clamped = Math.min(scrollOffset, Math.max(0, total - maxVisibleLines));
|
|
9573
9609
|
const start = clamped;
|
|
9574
9610
|
const end = Math.min(total, start + maxVisibleLines);
|
|
9575
9611
|
return { lines: allLines.slice(start, end), displayTotalLines: total, clampedOffset: clamped };
|
|
9576
|
-
}, [content, maxVisibleLines, scrollOffset, contentWidth]);
|
|
9612
|
+
}, [content, isMd, maxVisibleLines, scrollOffset, contentWidth]);
|
|
9577
9613
|
const filename = file.path.split("/").pop() || file.path;
|
|
9578
9614
|
return /* @__PURE__ */ jsxs13(
|
|
9579
9615
|
Box15,
|
|
@@ -9593,6 +9629,10 @@ function FileContentView({
|
|
|
9593
9629
|
separator,
|
|
9594
9630
|
"truncated"
|
|
9595
9631
|
] }),
|
|
9632
|
+
/* @__PURE__ */ jsxs13(Text16, { color: theme17.textSubtle, children: [
|
|
9633
|
+
separator,
|
|
9634
|
+
"c: copy"
|
|
9635
|
+
] }),
|
|
9596
9636
|
/* @__PURE__ */ jsxs13(Text16, { color: theme17.textSubtle, children: [
|
|
9597
9637
|
separator,
|
|
9598
9638
|
"Esc: back"
|
|
@@ -12054,7 +12094,6 @@ function MarathonApp({
|
|
|
12054
12094
|
if (state.phase === "steering" && steeringRecap) {
|
|
12055
12095
|
return joinHints(
|
|
12056
12096
|
"\u2191\u2193: scroll",
|
|
12057
|
-
"Shift+\u2190/\u2192: runs",
|
|
12058
12097
|
"Tab: switch screen",
|
|
12059
12098
|
activeScreen !== "overview" ? "Esc: overview" : void 0,
|
|
12060
12099
|
"Ctrl+C"
|
|
@@ -12080,7 +12119,6 @@ function MarathonApp({
|
|
|
12080
12119
|
}
|
|
12081
12120
|
if (showEventStream && detailEvent) {
|
|
12082
12121
|
return joinHints(
|
|
12083
|
-
"Shift+\u2190/\u2192: runs",
|
|
12084
12122
|
"c: copy",
|
|
12085
12123
|
"\u2190\u2192: prev/next",
|
|
12086
12124
|
"Tab: next screen",
|
|
@@ -12091,7 +12129,6 @@ function MarathonApp({
|
|
|
12091
12129
|
}
|
|
12092
12130
|
if (showEventStream) {
|
|
12093
12131
|
return joinHints(
|
|
12094
|
-
"Shift+\u2190/\u2192: runs",
|
|
12095
12132
|
"1-9: jump",
|
|
12096
12133
|
"0: latest",
|
|
12097
12134
|
"Enter: detail",
|
|
@@ -12120,7 +12157,6 @@ function MarathonApp({
|
|
|
12120
12157
|
}
|
|
12121
12158
|
return joinHints(
|
|
12122
12159
|
agentPageUrl ? "o: dashboard" : void 0,
|
|
12123
|
-
"Shift+\u2190/\u2192: runs",
|
|
12124
12160
|
"1-9: jump",
|
|
12125
12161
|
"0: latest",
|
|
12126
12162
|
"Tab: next screen",
|
|
@@ -12187,7 +12223,8 @@ function MarathonApp({
|
|
|
12187
12223
|
{
|
|
12188
12224
|
tabs: visibleTabs.tabs,
|
|
12189
12225
|
hiddenLeft: visibleTabs.hiddenLeft,
|
|
12190
|
-
hiddenRight: visibleTabs.hiddenRight
|
|
12226
|
+
hiddenRight: visibleTabs.hiddenRight,
|
|
12227
|
+
shortcutHint: "Shift+\\u2190/\\u2192: runs"
|
|
12191
12228
|
}
|
|
12192
12229
|
) }),
|
|
12193
12230
|
showFilesPanel ? /* @__PURE__ */ jsx28(
|
|
@@ -12821,6 +12858,61 @@ function restoreMarathonFileCheckpoint(taskName, targetPath, stateDir) {
|
|
|
12821
12858
|
// src/marathon/errors.ts
|
|
12822
12859
|
import chalk12 from "chalk";
|
|
12823
12860
|
import { RuntypeApiError } from "@runtypelabs/sdk";
|
|
12861
|
+
var NETWORK_ERROR_PATTERNS = [
|
|
12862
|
+
"fetch failed",
|
|
12863
|
+
"network error",
|
|
12864
|
+
"network request failed",
|
|
12865
|
+
"networkerror",
|
|
12866
|
+
"econnreset",
|
|
12867
|
+
"econnrefused",
|
|
12868
|
+
"econnaborted",
|
|
12869
|
+
"etimedout",
|
|
12870
|
+
"enetunreach",
|
|
12871
|
+
"enetdown",
|
|
12872
|
+
"ehostunreach",
|
|
12873
|
+
"enotfound",
|
|
12874
|
+
"epipe",
|
|
12875
|
+
"socket hang up",
|
|
12876
|
+
"socket disconnected",
|
|
12877
|
+
"connection reset",
|
|
12878
|
+
"connection refused",
|
|
12879
|
+
"connection closed",
|
|
12880
|
+
"connection lost",
|
|
12881
|
+
"network connection lost",
|
|
12882
|
+
"request aborted",
|
|
12883
|
+
"the operation was aborted",
|
|
12884
|
+
"other side closed",
|
|
12885
|
+
"client network socket disconnected",
|
|
12886
|
+
"unable to connect",
|
|
12887
|
+
"err_network"
|
|
12888
|
+
];
|
|
12889
|
+
function isTransientNetworkError(error) {
|
|
12890
|
+
if (error instanceof RuntypeApiError) return false;
|
|
12891
|
+
const message = error instanceof Error ? error.message.toLowerCase() : String(error).toLowerCase();
|
|
12892
|
+
if (error instanceof TypeError && message.includes("fetch")) return true;
|
|
12893
|
+
if (error instanceof DOMException && error.name === "AbortError") return true;
|
|
12894
|
+
return NETWORK_ERROR_PATTERNS.some((pattern) => message.includes(pattern));
|
|
12895
|
+
}
|
|
12896
|
+
async function retryOnNetworkError(fn, opts = {}) {
|
|
12897
|
+
const maxRetries = opts.maxRetries ?? 3;
|
|
12898
|
+
const baseDelay = opts.baseDelayMs ?? 5e3;
|
|
12899
|
+
const maxDelay = opts.maxDelayMs ?? 6e4;
|
|
12900
|
+
let lastError;
|
|
12901
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
12902
|
+
try {
|
|
12903
|
+
return await fn();
|
|
12904
|
+
} catch (error) {
|
|
12905
|
+
lastError = error;
|
|
12906
|
+
if (!isTransientNetworkError(error) || attempt === maxRetries) {
|
|
12907
|
+
throw error;
|
|
12908
|
+
}
|
|
12909
|
+
const delay = Math.min(baseDelay * 2 ** attempt, maxDelay);
|
|
12910
|
+
opts.onRetry?.(attempt + 1, delay, error);
|
|
12911
|
+
await new Promise((resolve6) => setTimeout(resolve6, delay));
|
|
12912
|
+
}
|
|
12913
|
+
}
|
|
12914
|
+
throw lastError;
|
|
12915
|
+
}
|
|
12824
12916
|
function readRateLimitHeader(headers, names) {
|
|
12825
12917
|
for (const name of names) {
|
|
12826
12918
|
const value = headers?.get(name);
|
|
@@ -14539,6 +14631,16 @@ function buildResumeHistoryWarning(state) {
|
|
|
14539
14631
|
function canUseMarathonStartupShell(options) {
|
|
14540
14632
|
return process.stdin.isTTY === true && process.stdout.isTTY === true && !options.json;
|
|
14541
14633
|
}
|
|
14634
|
+
function buildMarathonClientHeaders(devPlanOverride) {
|
|
14635
|
+
const cliVersion = getCliVersion();
|
|
14636
|
+
return {
|
|
14637
|
+
"X-Runtype-Client": "cli",
|
|
14638
|
+
"X-Runtype-Client-Origin": "marathon",
|
|
14639
|
+
"X-Runtype-CLI-Version": cliVersion,
|
|
14640
|
+
"User-Agent": `runtype-cli/${cliVersion}`,
|
|
14641
|
+
...devPlanOverride ? { "X-Dev-Plan-Override": devPlanOverride } : {}
|
|
14642
|
+
};
|
|
14643
|
+
}
|
|
14542
14644
|
async function taskAction(agent, options) {
|
|
14543
14645
|
if (!options.resume && !options.goal) {
|
|
14544
14646
|
console.error(chalk16.red("Error: -g, --goal <text> is required for new tasks"));
|
|
@@ -14551,8 +14653,7 @@ async function taskAction(agent, options) {
|
|
|
14551
14653
|
const client = new RuntypeClient2({
|
|
14552
14654
|
apiKey,
|
|
14553
14655
|
baseUrl: getApiUrl(),
|
|
14554
|
-
|
|
14555
|
-
...devPlanOverride ? { headers: { "X-Dev-Plan-Override": devPlanOverride } } : {}
|
|
14656
|
+
headers: buildMarathonClientHeaders(devPlanOverride)
|
|
14556
14657
|
});
|
|
14557
14658
|
let parsedSandbox = parseSandboxProvider(options.sandbox);
|
|
14558
14659
|
if (options.sandbox && !parsedSandbox) {
|
|
@@ -15155,7 +15256,29 @@ Saving state... done. Session saved to ${filePath}`);
|
|
|
15155
15256
|
}
|
|
15156
15257
|
}
|
|
15157
15258
|
};
|
|
15158
|
-
const result2 = await
|
|
15259
|
+
const result2 = await retryOnNetworkError(
|
|
15260
|
+
() => client.agents.runTask(agentId, runTaskOptions),
|
|
15261
|
+
{
|
|
15262
|
+
maxRetries: 3,
|
|
15263
|
+
baseDelayMs: 5e3,
|
|
15264
|
+
maxDelayMs: 6e4,
|
|
15265
|
+
onRetry: (attempt, delayMs, error) => {
|
|
15266
|
+
const delaySec = Math.round(delayMs / 1e3);
|
|
15267
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
15268
|
+
console.error(
|
|
15269
|
+
chalk16.yellow(`Network error (attempt ${attempt}/3): ${msg}. Retrying in ${delaySec}s...`)
|
|
15270
|
+
);
|
|
15271
|
+
if (lastKnownState) {
|
|
15272
|
+
previousMessages = lastSessionMessages;
|
|
15273
|
+
resumeState = extractRunTaskResumeState(lastKnownState);
|
|
15274
|
+
runTaskOptions.previousMessages = previousMessages;
|
|
15275
|
+
runTaskOptions.resumeState = resumeState;
|
|
15276
|
+
runTaskOptions.continuationMessage = taskMessage;
|
|
15277
|
+
runTaskOptions.compact = false;
|
|
15278
|
+
}
|
|
15279
|
+
}
|
|
15280
|
+
}
|
|
15281
|
+
);
|
|
15159
15282
|
persistedSessionSummaries = mergeMarathonSessionSummaries(
|
|
15160
15283
|
persistedSessionSummaries,
|
|
15161
15284
|
result2.sessions,
|
|
@@ -15326,6 +15449,9 @@ Resume: ${buildResumeCommand(agent, options, parsedSandbox)}`
|
|
|
15326
15449
|
const stateAtError = lastKnownState;
|
|
15327
15450
|
if (stateAtError) {
|
|
15328
15451
|
stateAtError.status = "paused";
|
|
15452
|
+
if (isTransientNetworkError(error)) {
|
|
15453
|
+
stateAtError.lastError = "Network connection lost.";
|
|
15454
|
+
}
|
|
15329
15455
|
saveState(filePath, stateAtError);
|
|
15330
15456
|
}
|
|
15331
15457
|
const streamActions = streamRef.current;
|
|
@@ -15341,8 +15467,13 @@ Resume: ${buildResumeCommand(agent, options, parsedSandbox)}`
|
|
|
15341
15467
|
if (!restoredScreen) {
|
|
15342
15468
|
exitAltScreen();
|
|
15343
15469
|
}
|
|
15344
|
-
|
|
15345
|
-
console.error(
|
|
15470
|
+
if (isTransientNetworkError(error)) {
|
|
15471
|
+
console.error(chalk16.red("Network connection lost after multiple retry attempts."));
|
|
15472
|
+
console.error(chalk16.gray("Your progress has been saved. Resume when connectivity is restored:"));
|
|
15473
|
+
} else {
|
|
15474
|
+
for (const line of formatMarathonApiError(error)) {
|
|
15475
|
+
console.error(line);
|
|
15476
|
+
}
|
|
15346
15477
|
}
|
|
15347
15478
|
console.log(chalk16.gray(`State saved to ${filePath} \u2014 resume with --resume`));
|
|
15348
15479
|
process.exit(1);
|