@runtypelabs/cli 1.9.3 → 2.0.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/README.md +143 -0
- package/dist/index.js +754 -370
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -428,7 +428,7 @@ var require_builtin_tools_registry = __commonJS({
|
|
|
428
428
|
{
|
|
429
429
|
id: "firecrawl",
|
|
430
430
|
name: "Firecrawl",
|
|
431
|
-
description: "Scrape and extract content from
|
|
431
|
+
description: "Scrape and extract content from a URL as markdown. Provide a url and optional formats array.",
|
|
432
432
|
category: exports.BuiltInToolCategory.WEB_SCRAPING,
|
|
433
433
|
providers: [exports.BuiltInToolProvider.MULTI],
|
|
434
434
|
parametersSchema: {
|
|
@@ -436,12 +436,12 @@ var require_builtin_tools_registry = __commonJS({
|
|
|
436
436
|
properties: {
|
|
437
437
|
url: {
|
|
438
438
|
type: "string",
|
|
439
|
-
description:
|
|
439
|
+
description: 'The full URL to scrape (e.g. "https://example.com/page")',
|
|
440
440
|
minLength: 1
|
|
441
441
|
},
|
|
442
442
|
formats: {
|
|
443
443
|
type: "array",
|
|
444
|
-
description:
|
|
444
|
+
description: 'Output formats (e.g. ["markdown"]). Options: markdown, html, rawHtml, screenshot, links',
|
|
445
445
|
items: {
|
|
446
446
|
type: "string",
|
|
447
447
|
enum: ["markdown", "html", "rawHtml", "screenshot", "links"]
|
|
@@ -450,12 +450,12 @@ var require_builtin_tools_registry = __commonJS({
|
|
|
450
450
|
},
|
|
451
451
|
onlyMainContent: {
|
|
452
452
|
type: "boolean",
|
|
453
|
-
description: "
|
|
453
|
+
description: "If true, strips navigation/footers/ads and returns only the main content",
|
|
454
454
|
default: true
|
|
455
455
|
},
|
|
456
456
|
waitFor: {
|
|
457
457
|
type: "number",
|
|
458
|
-
description: "Milliseconds to wait
|
|
458
|
+
description: "Milliseconds to wait for dynamic content before scraping (0-30000)",
|
|
459
459
|
minimum: 0,
|
|
460
460
|
maximum: 3e4
|
|
461
461
|
}
|
|
@@ -4545,8 +4545,8 @@ var CallbackServer = class {
|
|
|
4545
4545
|
expectedState;
|
|
4546
4546
|
constructor() {
|
|
4547
4547
|
this.app = express();
|
|
4548
|
-
this.codePromise = new Promise((
|
|
4549
|
-
this.codeResolve =
|
|
4548
|
+
this.codePromise = new Promise((resolve7, reject) => {
|
|
4549
|
+
this.codeResolve = resolve7;
|
|
4550
4550
|
this.codeReject = reject;
|
|
4551
4551
|
});
|
|
4552
4552
|
this.app.get("/callback", (req, res) => {
|
|
@@ -5741,14 +5741,14 @@ async function promptConfirm(message, options) {
|
|
|
5741
5741
|
output: process.stdout,
|
|
5742
5742
|
terminal: true
|
|
5743
5743
|
});
|
|
5744
|
-
return new Promise((
|
|
5744
|
+
return new Promise((resolve7) => {
|
|
5745
5745
|
rl.question(chalk2.cyan(`${message} (${hint}): `), (answer) => {
|
|
5746
5746
|
rl.close();
|
|
5747
5747
|
const trimmed = answer.trim().toLowerCase();
|
|
5748
5748
|
if (trimmed === "") {
|
|
5749
|
-
|
|
5749
|
+
resolve7(defaultYes);
|
|
5750
5750
|
} else {
|
|
5751
|
-
|
|
5751
|
+
resolve7(trimmed === "y" || trimmed === "yes");
|
|
5752
5752
|
}
|
|
5753
5753
|
});
|
|
5754
5754
|
});
|
|
@@ -5849,9 +5849,9 @@ var ApiClient = class {
|
|
|
5849
5849
|
this.baseUrl = baseUrl || getApiUrl();
|
|
5850
5850
|
}
|
|
5851
5851
|
/** Prefix path with API version (e.g. /v1) so all requests hit versioned routes. */
|
|
5852
|
-
path(
|
|
5852
|
+
path(path13) {
|
|
5853
5853
|
const version = getApiVersion();
|
|
5854
|
-
const p =
|
|
5854
|
+
const p = path13.startsWith("/") ? path13 : `/${path13}`;
|
|
5855
5855
|
return p.startsWith(`/${version}/`) ? p : `/${version}${p}`;
|
|
5856
5856
|
}
|
|
5857
5857
|
headers(extra) {
|
|
@@ -5884,8 +5884,8 @@ var ApiClient = class {
|
|
|
5884
5884
|
}
|
|
5885
5885
|
return response.json();
|
|
5886
5886
|
}
|
|
5887
|
-
async get(
|
|
5888
|
-
const url = new URL(this.path(
|
|
5887
|
+
async get(path13, params) {
|
|
5888
|
+
const url = new URL(this.path(path13), this.baseUrl);
|
|
5889
5889
|
if (params) {
|
|
5890
5890
|
for (const [key, value] of Object.entries(params)) {
|
|
5891
5891
|
if (value !== void 0 && value !== "") {
|
|
@@ -5898,32 +5898,32 @@ var ApiClient = class {
|
|
|
5898
5898
|
});
|
|
5899
5899
|
return this.handleResponse(response);
|
|
5900
5900
|
}
|
|
5901
|
-
async post(
|
|
5902
|
-
const response = await fetch(new URL(this.path(
|
|
5901
|
+
async post(path13, body) {
|
|
5902
|
+
const response = await fetch(new URL(this.path(path13), this.baseUrl).toString(), {
|
|
5903
5903
|
method: "POST",
|
|
5904
5904
|
headers: this.headers(),
|
|
5905
5905
|
body: body !== void 0 ? JSON.stringify(body) : void 0
|
|
5906
5906
|
});
|
|
5907
5907
|
return this.handleResponse(response);
|
|
5908
5908
|
}
|
|
5909
|
-
async put(
|
|
5910
|
-
const response = await fetch(new URL(this.path(
|
|
5909
|
+
async put(path13, body) {
|
|
5910
|
+
const response = await fetch(new URL(this.path(path13), this.baseUrl).toString(), {
|
|
5911
5911
|
method: "PUT",
|
|
5912
5912
|
headers: this.headers(),
|
|
5913
5913
|
body: body !== void 0 ? JSON.stringify(body) : void 0
|
|
5914
5914
|
});
|
|
5915
5915
|
return this.handleResponse(response);
|
|
5916
5916
|
}
|
|
5917
|
-
async patch(
|
|
5918
|
-
const response = await fetch(new URL(this.path(
|
|
5917
|
+
async patch(path13, body) {
|
|
5918
|
+
const response = await fetch(new URL(this.path(path13), this.baseUrl).toString(), {
|
|
5919
5919
|
method: "PATCH",
|
|
5920
5920
|
headers: this.headers(),
|
|
5921
5921
|
body: body !== void 0 ? JSON.stringify(body) : void 0
|
|
5922
5922
|
});
|
|
5923
5923
|
return this.handleResponse(response);
|
|
5924
5924
|
}
|
|
5925
|
-
async delete(
|
|
5926
|
-
const response = await fetch(new URL(this.path(
|
|
5925
|
+
async delete(path13) {
|
|
5926
|
+
const response = await fetch(new URL(this.path(path13), this.baseUrl).toString(), {
|
|
5927
5927
|
method: "DELETE",
|
|
5928
5928
|
headers: this.headers()
|
|
5929
5929
|
});
|
|
@@ -5937,8 +5937,8 @@ var ApiClient = class {
|
|
|
5937
5937
|
throw new ApiError(response.status, message);
|
|
5938
5938
|
}
|
|
5939
5939
|
}
|
|
5940
|
-
async stream(
|
|
5941
|
-
const response = await fetch(new URL(this.path(
|
|
5940
|
+
async stream(path13, body) {
|
|
5941
|
+
const response = await fetch(new URL(this.path(path13), this.baseUrl).toString(), {
|
|
5942
5942
|
method: "POST",
|
|
5943
5943
|
headers: this.headers({ Accept: "text/event-stream" }),
|
|
5944
5944
|
body: body !== void 0 ? JSON.stringify(body) : void 0
|
|
@@ -8588,8 +8588,8 @@ function useMarathonStream() {
|
|
|
8588
8588
|
const reset = useCallback2(() => {
|
|
8589
8589
|
setState(INITIAL_STATE);
|
|
8590
8590
|
}, []);
|
|
8591
|
-
const
|
|
8592
|
-
setState((prev) => ({ ...prev, phase: "
|
|
8591
|
+
const setCheckpoint = useCallback2(() => {
|
|
8592
|
+
setState((prev) => ({ ...prev, phase: "checkpoint" }));
|
|
8593
8593
|
}, []);
|
|
8594
8594
|
const markPendingStart = useCallback2(() => {
|
|
8595
8595
|
setState((prev) => ({
|
|
@@ -8667,7 +8667,7 @@ function useMarathonStream() {
|
|
|
8667
8667
|
state,
|
|
8668
8668
|
callbacks,
|
|
8669
8669
|
reset,
|
|
8670
|
-
|
|
8670
|
+
setCheckpoint,
|
|
8671
8671
|
markPendingStart,
|
|
8672
8672
|
startContextCompaction,
|
|
8673
8673
|
finishContextCompaction,
|
|
@@ -8895,6 +8895,37 @@ function renderSegments(segments) {
|
|
|
8895
8895
|
(seg, i) => /* @__PURE__ */ jsx8(Text8, { color: seg.color, bold: seg.bold, children: seg.text }, i)
|
|
8896
8896
|
);
|
|
8897
8897
|
}
|
|
8898
|
+
function buildMilestoneText(milestones, currentMilestone) {
|
|
8899
|
+
if (milestones.length === 0) return "";
|
|
8900
|
+
const currentIndex = currentMilestone ? currentMilestone === "complete" ? milestones.length : milestones.indexOf(currentMilestone) : 0;
|
|
8901
|
+
return " " + milestones.map((name, i) => {
|
|
8902
|
+
const isCompleted = currentIndex > i;
|
|
8903
|
+
const isCurrent = currentIndex === i;
|
|
8904
|
+
if (isCompleted) return `\u2713 ${name}`;
|
|
8905
|
+
if (isCurrent) return `\u25CF ${name}`;
|
|
8906
|
+
return `\u25CB ${name}`;
|
|
8907
|
+
}).join(" \u2500\u2500 ");
|
|
8908
|
+
}
|
|
8909
|
+
function buildMilestoneSegments(milestones, currentMilestone) {
|
|
8910
|
+
if (milestones.length === 0) return [];
|
|
8911
|
+
const currentIndex = currentMilestone ? currentMilestone === "complete" ? milestones.length : milestones.indexOf(currentMilestone) : 0;
|
|
8912
|
+
const segments = [{ text: " " }];
|
|
8913
|
+
milestones.forEach((name, i) => {
|
|
8914
|
+
const isCompleted = currentIndex > i;
|
|
8915
|
+
const isCurrent = currentIndex === i;
|
|
8916
|
+
if (isCompleted) {
|
|
8917
|
+
segments.push({ text: `\u2713 ${name}`, color: theme9.textMuted });
|
|
8918
|
+
} else if (isCurrent) {
|
|
8919
|
+
segments.push({ text: `\u25CF ${name}`, color: theme9.accent, bold: true });
|
|
8920
|
+
} else {
|
|
8921
|
+
segments.push({ text: `\u25CB ${name}`, color: theme9.textSubtle });
|
|
8922
|
+
}
|
|
8923
|
+
if (i < milestones.length - 1) {
|
|
8924
|
+
segments.push({ text: " \u2500\u2500 ", color: theme9.border });
|
|
8925
|
+
}
|
|
8926
|
+
});
|
|
8927
|
+
return segments;
|
|
8928
|
+
}
|
|
8898
8929
|
function SessionHeader({
|
|
8899
8930
|
sessionName,
|
|
8900
8931
|
sessionCount,
|
|
@@ -8911,13 +8942,17 @@ function SessionHeader({
|
|
|
8911
8942
|
runnerLaps,
|
|
8912
8943
|
onRunnerPositionChange,
|
|
8913
8944
|
trackWidth,
|
|
8914
|
-
previewUrl
|
|
8945
|
+
previewUrl,
|
|
8946
|
+
workflowMilestones,
|
|
8947
|
+
currentMilestone
|
|
8915
8948
|
}) {
|
|
8916
8949
|
const showName = sessionName && sessionName !== `Marathon #${sessionCount}`;
|
|
8917
8950
|
const separator = theme9.separator ?? " \xB7 ";
|
|
8918
8951
|
const resolvedWidth = trackWidth ?? 40;
|
|
8952
|
+
const hasMilestones = workflowMilestones && workflowMilestones.length > 0;
|
|
8919
8953
|
let contentRowCount = 1;
|
|
8920
8954
|
if (previewUrl) contentRowCount++;
|
|
8955
|
+
if (hasMilestones) contentRowCount++;
|
|
8921
8956
|
if (goal) contentRowCount++;
|
|
8922
8957
|
const { topSegments, bottomSegments, innerWidth, borderSegments } = useRunnerTrack({
|
|
8923
8958
|
width: resolvedWidth,
|
|
@@ -8956,6 +8991,11 @@ function SessionHeader({
|
|
|
8956
8991
|
rowIdx++
|
|
8957
8992
|
));
|
|
8958
8993
|
}
|
|
8994
|
+
if (hasMilestones) {
|
|
8995
|
+
const milestoneSegs = buildMilestoneSegments(workflowMilestones, currentMilestone);
|
|
8996
|
+
const milestoneText = buildMilestoneText(workflowMilestones, currentMilestone);
|
|
8997
|
+
rows.push(borderSegments(milestoneSegs, milestoneText.length, rowIdx++));
|
|
8998
|
+
}
|
|
8959
8999
|
if (goal) {
|
|
8960
9000
|
const maxGoalLen = innerWidth - 1;
|
|
8961
9001
|
const displayGoal = goalExpanded ? goal : goal.slice(0, maxGoalLen);
|
|
@@ -10170,7 +10210,7 @@ var FILES_SHORTCUTS = [
|
|
|
10170
10210
|
{ key: "\u2190/\u2192", desc: "Previous / next file" },
|
|
10171
10211
|
{ key: "c", desc: "Copy path / content" }
|
|
10172
10212
|
];
|
|
10173
|
-
var
|
|
10213
|
+
var CHECKPOINT_COMMANDS = [
|
|
10174
10214
|
{ key: "/model", desc: "Change AI model" },
|
|
10175
10215
|
{ key: "/tools", desc: "Toggle local tools on/off" },
|
|
10176
10216
|
{ key: "/sandbox", desc: "Switch sandbox provider" },
|
|
@@ -10183,7 +10223,7 @@ var STEERING_COMMANDS = [
|
|
|
10183
10223
|
{ key: "/stop", desc: "Stop the marathon" },
|
|
10184
10224
|
{ key: "/help", desc: "Toggle this help dialog" }
|
|
10185
10225
|
];
|
|
10186
|
-
function buildLines(
|
|
10226
|
+
function buildLines(isCheckpoint) {
|
|
10187
10227
|
const lines = [];
|
|
10188
10228
|
const sections = [
|
|
10189
10229
|
{ title: "Navigation", items: NAVIGATION_SHORTCUTS },
|
|
@@ -10191,7 +10231,7 @@ function buildLines(isSteering) {
|
|
|
10191
10231
|
{ title: "Reasoning", items: REASONING_SHORTCUTS },
|
|
10192
10232
|
{ title: "Events", items: EVENTS_SHORTCUTS },
|
|
10193
10233
|
{ title: "Files", items: FILES_SHORTCUTS },
|
|
10194
|
-
...
|
|
10234
|
+
...isCheckpoint ? [{ title: "Checkpoint Commands", items: CHECKPOINT_COMMANDS }] : []
|
|
10195
10235
|
];
|
|
10196
10236
|
for (let s = 0; s < sections.length; s++) {
|
|
10197
10237
|
const section = sections[s];
|
|
@@ -10205,14 +10245,14 @@ function buildLines(isSteering) {
|
|
|
10205
10245
|
}
|
|
10206
10246
|
return lines;
|
|
10207
10247
|
}
|
|
10208
|
-
function getHelpLineCount(
|
|
10209
|
-
return buildLines(
|
|
10248
|
+
function getHelpLineCount(isCheckpoint) {
|
|
10249
|
+
return buildLines(isCheckpoint).length;
|
|
10210
10250
|
}
|
|
10211
|
-
function HelpPanel({ width, height,
|
|
10251
|
+
function HelpPanel({ width, height, isCheckpoint, scrollOffset }) {
|
|
10212
10252
|
const dialogWidth = Math.min(width - 4, 60);
|
|
10213
|
-
const contentHeight = Math.min(height - 2,
|
|
10253
|
+
const contentHeight = Math.min(height - 2, isCheckpoint ? 38 : 28) - 8;
|
|
10214
10254
|
const visibleRows = Math.max(1, contentHeight);
|
|
10215
|
-
const allLines = useMemo7(() => buildLines(
|
|
10255
|
+
const allLines = useMemo7(() => buildLines(isCheckpoint), [isCheckpoint]);
|
|
10216
10256
|
const maxScroll = Math.max(0, allLines.length - visibleRows);
|
|
10217
10257
|
const clampedOffset = Math.min(scrollOffset, maxScroll);
|
|
10218
10258
|
const visibleLines = allLines.slice(clampedOffset, clampedOffset + visibleRows);
|
|
@@ -10220,7 +10260,7 @@ function HelpPanel({ width, height, isSteering, scrollOffset }) {
|
|
|
10220
10260
|
Box17,
|
|
10221
10261
|
{
|
|
10222
10262
|
width: dialogWidth,
|
|
10223
|
-
height: Math.min(height - 2,
|
|
10263
|
+
height: Math.min(height - 2, isCheckpoint ? 38 : 28),
|
|
10224
10264
|
flexDirection: "column",
|
|
10225
10265
|
borderStyle: "round",
|
|
10226
10266
|
borderColor: theme21.accent,
|
|
@@ -10257,10 +10297,10 @@ function HelpPanel({ width, height, isSteering, scrollOffset }) {
|
|
|
10257
10297
|
/* @__PURE__ */ jsx20(Text18, { color: theme21.muted, children: " or " }),
|
|
10258
10298
|
/* @__PURE__ */ jsx20(Text18, { color: theme21.info, children: "?" }),
|
|
10259
10299
|
/* @__PURE__ */ jsx20(Text18, { color: theme21.muted, children: " to close" }),
|
|
10260
|
-
|
|
10300
|
+
isCheckpoint && /* @__PURE__ */ jsxs16(Fragment2, { children: [
|
|
10261
10301
|
/* @__PURE__ */ jsx20(Text18, { color: theme21.muted, children: " (use " }),
|
|
10262
10302
|
/* @__PURE__ */ jsx20(Text18, { color: theme21.info, children: "/help" }),
|
|
10263
|
-
/* @__PURE__ */ jsx20(Text18, { color: theme21.muted, children: " during
|
|
10303
|
+
/* @__PURE__ */ jsx20(Text18, { color: theme21.muted, children: " during checkpoint)" })
|
|
10264
10304
|
] })
|
|
10265
10305
|
] })
|
|
10266
10306
|
]
|
|
@@ -10733,7 +10773,7 @@ function readSessionEventLog(stateFilePath2, sessionIndex) {
|
|
|
10733
10773
|
return events;
|
|
10734
10774
|
}
|
|
10735
10775
|
|
|
10736
|
-
// src/ink/marathon/
|
|
10776
|
+
// src/ink/marathon/CheckpointPrompt.tsx
|
|
10737
10777
|
import { useState as useState21, useEffect as useEffect19, useRef as useRef7 } from "react";
|
|
10738
10778
|
import { Box as Box22, Text as Text24 } from "ink";
|
|
10739
10779
|
|
|
@@ -10868,7 +10908,7 @@ function BlinkingTextInput({
|
|
|
10868
10908
|
return /* @__PURE__ */ jsx21(Text19, { children: placeholder ? value.length > 0 ? renderedValue : renderedPlaceholder : renderedValue });
|
|
10869
10909
|
}
|
|
10870
10910
|
|
|
10871
|
-
// src/ink/marathon/
|
|
10911
|
+
// src/ink/marathon/CheckpointPrompt.tsx
|
|
10872
10912
|
import { theme as theme26 } from "@runtypelabs/ink-components";
|
|
10873
10913
|
|
|
10874
10914
|
// src/ink/talk/ModelPicker.tsx
|
|
@@ -11052,7 +11092,7 @@ import TextInput3 from "ink-text-input";
|
|
|
11052
11092
|
import { theme as theme23 } from "@runtypelabs/ink-components";
|
|
11053
11093
|
|
|
11054
11094
|
// src/ink/marathon/types.ts
|
|
11055
|
-
var
|
|
11095
|
+
var MARATHON_CHECKPOINT_COMMANDS = [
|
|
11056
11096
|
{ name: "/model", description: "Change AI model", hasArgs: false },
|
|
11057
11097
|
{ name: "/tools", description: "Toggle local tools on/off", hasArgs: false },
|
|
11058
11098
|
{
|
|
@@ -11086,9 +11126,9 @@ function CommandPicker({ onSelect, onCancel, initialFilter = "" }) {
|
|
|
11086
11126
|
[contentWidth]
|
|
11087
11127
|
);
|
|
11088
11128
|
const filtered = useMemo9(() => {
|
|
11089
|
-
if (!search.trim()) return
|
|
11129
|
+
if (!search.trim()) return MARATHON_CHECKPOINT_COMMANDS;
|
|
11090
11130
|
const q = search.toLowerCase();
|
|
11091
|
-
return
|
|
11131
|
+
return MARATHON_CHECKPOINT_COMMANDS.filter(
|
|
11092
11132
|
(cmd) => cmd.name.toLowerCase().includes(q) || cmd.description.toLowerCase().includes(q)
|
|
11093
11133
|
);
|
|
11094
11134
|
}, [search]);
|
|
@@ -11510,14 +11550,14 @@ function ReflectEditor({ onSubmit, onCancel, maxHeight = 10 }) {
|
|
|
11510
11550
|
);
|
|
11511
11551
|
}
|
|
11512
11552
|
|
|
11513
|
-
// src/ink/marathon/
|
|
11553
|
+
// src/ink/marathon/CheckpointRecap.tsx
|
|
11514
11554
|
import { Box as Box21, Text as Text23 } from "ink";
|
|
11515
11555
|
import { theme as theme25 } from "@runtypelabs/ink-components";
|
|
11516
11556
|
import { jsx as jsx26, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
11517
11557
|
function formatTokenCount2(value) {
|
|
11518
11558
|
return value.toLocaleString("en-US");
|
|
11519
11559
|
}
|
|
11520
|
-
function
|
|
11560
|
+
function CheckpointRecap({
|
|
11521
11561
|
sessionNumber,
|
|
11522
11562
|
toolCallsMade,
|
|
11523
11563
|
tokensInput,
|
|
@@ -11553,13 +11593,13 @@ function SteeringRecap({
|
|
|
11553
11593
|
);
|
|
11554
11594
|
}
|
|
11555
11595
|
|
|
11556
|
-
// src/ink/marathon/
|
|
11557
|
-
function
|
|
11596
|
+
// src/ink/marathon/checkpoint-prompt-state.ts
|
|
11597
|
+
function shouldPauseCheckpointTimer(state) {
|
|
11558
11598
|
return Boolean(
|
|
11559
11599
|
state.isTerminal || state.timeout === 0 || state.isTyping || state.hasPendingChanges || state.showModelPicker || state.showReflectEditor || state.showCommandPicker || state.isReviewing
|
|
11560
11600
|
);
|
|
11561
11601
|
}
|
|
11562
|
-
function
|
|
11602
|
+
function getCheckpointCountdownText(state) {
|
|
11563
11603
|
if (state.isTerminal) return "(complete)";
|
|
11564
11604
|
if (state.timeout === 0) return "";
|
|
11565
11605
|
if (state.isTyping) return "(typing)";
|
|
@@ -11568,9 +11608,9 @@ function getSteeringCountdownText(state) {
|
|
|
11568
11608
|
return `(${state.remaining}s)`;
|
|
11569
11609
|
}
|
|
11570
11610
|
|
|
11571
|
-
// src/ink/marathon/
|
|
11611
|
+
// src/ink/marathon/CheckpointPrompt.tsx
|
|
11572
11612
|
import { jsx as jsx27, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
11573
|
-
function
|
|
11613
|
+
function CheckpointPrompt({
|
|
11574
11614
|
onSubmit,
|
|
11575
11615
|
onToggleHelp,
|
|
11576
11616
|
onCopySession,
|
|
@@ -11637,7 +11677,7 @@ function SteeringPrompt({
|
|
|
11637
11677
|
}
|
|
11638
11678
|
};
|
|
11639
11679
|
useEffect19(() => {
|
|
11640
|
-
if (
|
|
11680
|
+
if (shouldPauseCheckpointTimer({
|
|
11641
11681
|
isTerminal,
|
|
11642
11682
|
timeout,
|
|
11643
11683
|
isTyping,
|
|
@@ -11760,7 +11800,7 @@ ${trimmed}` : trimmed);
|
|
|
11760
11800
|
const handleCommandCancel = () => {
|
|
11761
11801
|
setShowCommandPicker(false);
|
|
11762
11802
|
};
|
|
11763
|
-
const countdownText =
|
|
11803
|
+
const countdownText = getCheckpointCountdownText({
|
|
11764
11804
|
isTerminal,
|
|
11765
11805
|
timeout,
|
|
11766
11806
|
isTyping,
|
|
@@ -11823,7 +11863,7 @@ ${trimmed}` : trimmed);
|
|
|
11823
11863
|
value,
|
|
11824
11864
|
onChange: handleChange,
|
|
11825
11865
|
onSubmit: handleSubmit,
|
|
11826
|
-
placeholder: isTerminal ? "Send new instructions to continue marathon, or press enter to exit..." : "
|
|
11866
|
+
placeholder: isTerminal ? "Send new instructions to continue marathon, or press enter to exit..." : "Guide next iteration..."
|
|
11827
11867
|
}
|
|
11828
11868
|
) }),
|
|
11829
11869
|
countdownText && /* @__PURE__ */ jsxs21(Text24, { color: theme26.textSubtle, children: [
|
|
@@ -11840,7 +11880,7 @@ ${trimmed}` : trimmed);
|
|
|
11840
11880
|
]
|
|
11841
11881
|
}
|
|
11842
11882
|
),
|
|
11843
|
-
/* @__PURE__ */ jsx27(
|
|
11883
|
+
/* @__PURE__ */ jsx27(CheckpointRecap, { ...recap, isTerminal })
|
|
11844
11884
|
] });
|
|
11845
11885
|
}
|
|
11846
11886
|
|
|
@@ -12144,8 +12184,8 @@ function getSessionTabKeyForShortcut(visibleTabs, input) {
|
|
|
12144
12184
|
return visibleTabs.find((tab) => tab.shortcut === slot)?.key;
|
|
12145
12185
|
}
|
|
12146
12186
|
|
|
12147
|
-
// src/ink/marathon/
|
|
12148
|
-
function
|
|
12187
|
+
// src/ink/marathon/checkpoint-navigation.ts
|
|
12188
|
+
function isAllowedCheckpointBrowseKey(key, isBrowsingScreen) {
|
|
12149
12189
|
return Boolean(
|
|
12150
12190
|
key.upArrow || key.downArrow || key.return && isBrowsingScreen || key.input === "c" && isBrowsingScreen || key.leftArrow && isBrowsingScreen || key.rightArrow && isBrowsingScreen || key.tab || key.escape || key.shift && key.leftArrow || key.shift && key.rightArrow
|
|
12151
12191
|
);
|
|
@@ -12160,7 +12200,7 @@ var STACKED_THRESHOLD = 80;
|
|
|
12160
12200
|
var CHROME_ROWS_BASE = 9;
|
|
12161
12201
|
var GOAL_ROW = 1;
|
|
12162
12202
|
var SCROLL_STEP = 3;
|
|
12163
|
-
var
|
|
12203
|
+
var CHECKPOINT_PROMPT_ROWS = 7;
|
|
12164
12204
|
var SESSION_TABS_ROWS = 2;
|
|
12165
12205
|
var SCREEN_TABS_ROWS = 2;
|
|
12166
12206
|
function cloneSessionSnapshot(snapshot) {
|
|
@@ -12246,8 +12286,10 @@ function MarathonApp({
|
|
|
12246
12286
|
stateFilePath: stateFilePath2,
|
|
12247
12287
|
debug: _debug,
|
|
12248
12288
|
plainText,
|
|
12249
|
-
|
|
12250
|
-
|
|
12289
|
+
noCheckpoint: _noCheckpoint,
|
|
12290
|
+
checkpointTimeout,
|
|
12291
|
+
workflowMilestones,
|
|
12292
|
+
currentMilestone: initialCurrentMilestone,
|
|
12251
12293
|
dashboardUrl,
|
|
12252
12294
|
billingUrl,
|
|
12253
12295
|
onSaveState,
|
|
@@ -12258,7 +12300,7 @@ function MarathonApp({
|
|
|
12258
12300
|
state,
|
|
12259
12301
|
callbacks,
|
|
12260
12302
|
reset: _reset,
|
|
12261
|
-
|
|
12303
|
+
setCheckpoint,
|
|
12262
12304
|
markPendingStart,
|
|
12263
12305
|
startContextCompaction,
|
|
12264
12306
|
finishContextCompaction,
|
|
@@ -12270,11 +12312,12 @@ function MarathonApp({
|
|
|
12270
12312
|
const { exit } = useApp4();
|
|
12271
12313
|
const { stdout } = useStdout5();
|
|
12272
12314
|
const separator = theme30.separator ?? " \xB7 ";
|
|
12273
|
-
const
|
|
12274
|
-
const [
|
|
12315
|
+
const checkpointResolveRef = useRef8(null);
|
|
12316
|
+
const [checkpointRecap, setCheckpointRecap] = useState22(null);
|
|
12275
12317
|
const [currentModel, setCurrentModel] = useState22(model || "default");
|
|
12276
12318
|
const [currentSandbox, setCurrentSandbox] = useState22(sandbox);
|
|
12277
|
-
const [
|
|
12319
|
+
const [isTerminalCheckpoint, setIsTerminalCheckpoint] = useState22(false);
|
|
12320
|
+
const [currentMilestone, setCurrentMilestone] = useState22(initialCurrentMilestone);
|
|
12278
12321
|
const [allowInitialInlineLoader, setAllowInitialInlineLoader] = useState22(!suppressInitialInlineLoader);
|
|
12279
12322
|
const [sessionSnapshots, setSessionSnapshots] = useState22(
|
|
12280
12323
|
() => (initialSessionSnapshots || []).map((snapshot) => cloneSessionSnapshot(snapshot))
|
|
@@ -12284,35 +12327,35 @@ function MarathonApp({
|
|
|
12284
12327
|
const [followLatest, setFollowLatest] = useState22(true);
|
|
12285
12328
|
const [latestUnreadKey, setLatestUnreadKey] = useState22(void 0);
|
|
12286
12329
|
const [previewUrl, setPreviewUrl] = useState22(initialPreviewUrl);
|
|
12287
|
-
const [
|
|
12330
|
+
const [isCheckpointExploring, setIsCheckpointExploring] = useState22(false);
|
|
12288
12331
|
const isRunnerAnimating = state.phase === "thinking" || state.phase === "streaming" || state.phase === "tool" || Boolean(state.contextCompaction?.active);
|
|
12289
|
-
const
|
|
12290
|
-
const
|
|
12291
|
-
if (state.phase === "
|
|
12292
|
-
|
|
12332
|
+
const isTerminalCheckpointRef = useRef8(false);
|
|
12333
|
+
const markCheckpointExploring = useCallback8(() => {
|
|
12334
|
+
if (state.phase === "checkpoint" && checkpointRecap) {
|
|
12335
|
+
setIsCheckpointExploring(true);
|
|
12293
12336
|
}
|
|
12294
|
-
}, [state.phase,
|
|
12295
|
-
const
|
|
12337
|
+
}, [state.phase, checkpointRecap]);
|
|
12338
|
+
const handleCheckpointSubmit = useCallback8(
|
|
12296
12339
|
(result) => {
|
|
12297
|
-
|
|
12340
|
+
setIsCheckpointExploring(false);
|
|
12298
12341
|
if (result.model) {
|
|
12299
12342
|
setCurrentModel(result.model);
|
|
12300
12343
|
}
|
|
12301
12344
|
if (result.sandbox !== void 0) {
|
|
12302
12345
|
setCurrentSandbox(result.sandbox || void 0);
|
|
12303
12346
|
}
|
|
12304
|
-
if (
|
|
12305
|
-
if (
|
|
12306
|
-
|
|
12307
|
-
|
|
12347
|
+
if (isTerminalCheckpointRef.current) {
|
|
12348
|
+
if (checkpointResolveRef.current) {
|
|
12349
|
+
checkpointResolveRef.current(result);
|
|
12350
|
+
checkpointResolveRef.current = null;
|
|
12308
12351
|
}
|
|
12309
12352
|
} else {
|
|
12310
12353
|
resetForNewSession();
|
|
12311
|
-
|
|
12312
|
-
|
|
12313
|
-
if (
|
|
12314
|
-
|
|
12315
|
-
|
|
12354
|
+
setIsTerminalCheckpoint(false);
|
|
12355
|
+
isTerminalCheckpointRef.current = false;
|
|
12356
|
+
if (checkpointResolveRef.current) {
|
|
12357
|
+
checkpointResolveRef.current(result);
|
|
12358
|
+
checkpointResolveRef.current = null;
|
|
12316
12359
|
}
|
|
12317
12360
|
}
|
|
12318
12361
|
},
|
|
@@ -12342,18 +12385,21 @@ function MarathonApp({
|
|
|
12342
12385
|
setFollowLatest(true);
|
|
12343
12386
|
setLatestUnreadKey(void 0);
|
|
12344
12387
|
},
|
|
12345
|
-
|
|
12346
|
-
|
|
12347
|
-
|
|
12348
|
-
|
|
12388
|
+
requestCheckpoint: async (recap, isTerminal) => {
|
|
12389
|
+
setCheckpoint();
|
|
12390
|
+
setCheckpointRecap(recap);
|
|
12391
|
+
setIsCheckpointExploring(false);
|
|
12349
12392
|
if (isTerminal) {
|
|
12350
|
-
|
|
12351
|
-
|
|
12393
|
+
setIsTerminalCheckpoint(true);
|
|
12394
|
+
isTerminalCheckpointRef.current = true;
|
|
12352
12395
|
}
|
|
12353
|
-
return new Promise((
|
|
12354
|
-
|
|
12396
|
+
return new Promise((resolve7) => {
|
|
12397
|
+
checkpointResolveRef.current = resolve7;
|
|
12355
12398
|
});
|
|
12356
12399
|
},
|
|
12400
|
+
updateMilestone: (milestone) => {
|
|
12401
|
+
setCurrentMilestone(milestone);
|
|
12402
|
+
},
|
|
12357
12403
|
startContextCompaction,
|
|
12358
12404
|
finishContextCompaction,
|
|
12359
12405
|
reportContextNotice,
|
|
@@ -12370,9 +12416,9 @@ function MarathonApp({
|
|
|
12370
12416
|
latestCompletedSessionIndex,
|
|
12371
12417
|
markPendingStart,
|
|
12372
12418
|
reportContextNotice,
|
|
12373
|
-
|
|
12419
|
+
setIsCheckpointExploring,
|
|
12374
12420
|
setEventWriter,
|
|
12375
|
-
|
|
12421
|
+
setCheckpoint,
|
|
12376
12422
|
showError,
|
|
12377
12423
|
startContextCompaction,
|
|
12378
12424
|
state,
|
|
@@ -12381,7 +12427,8 @@ function MarathonApp({
|
|
|
12381
12427
|
]);
|
|
12382
12428
|
const terminalWidth = stdout?.columns ?? 120;
|
|
12383
12429
|
const terminalRows = stdout?.rows ?? 40;
|
|
12384
|
-
const
|
|
12430
|
+
const milestoneRow = workflowMilestones && workflowMilestones.length > 0 ? 1 : 0;
|
|
12431
|
+
const chromeRows = CHROME_ROWS_BASE + (goal ? GOAL_ROW : 0) + milestoneRow;
|
|
12385
12432
|
const contentHeight = Math.max(5, terminalRows - chromeRows);
|
|
12386
12433
|
const isStacked = terminalWidth < STACKED_THRESHOLD;
|
|
12387
12434
|
const toolPanelWidth = terminalWidth < NARROW_THRESHOLD ? TOOL_PANEL_NARROW : TOOL_PANEL_WIDE;
|
|
@@ -12470,7 +12517,7 @@ function MarathonApp({
|
|
|
12470
12517
|
void open4(agentPageUrl);
|
|
12471
12518
|
}
|
|
12472
12519
|
}, [agentPageUrl]);
|
|
12473
|
-
const shouldShowLiveTab = Boolean(state.contextCompaction?.active) || state.phase !== "idle" && state.phase !== "
|
|
12520
|
+
const shouldShowLiveTab = Boolean(state.contextCompaction?.active) || state.phase !== "idle" && state.phase !== "checkpoint" && state.phase !== "complete" && (Boolean(state.content) || Boolean(state.reasoning) || state.tools.length > 0 || state.rawEvents.length > 0 || state.phase === "thinking" || state.phase === "error");
|
|
12474
12521
|
const liveSessionSnapshot = useMemo11(
|
|
12475
12522
|
() => shouldShowLiveTab ? buildLiveSessionSnapshot(state, latestCompletedSessionIndex + 1, currentModel) : void 0,
|
|
12476
12523
|
[currentModel, latestCompletedSessionIndex, shouldShowLiveTab, state]
|
|
@@ -12641,7 +12688,7 @@ function MarathonApp({
|
|
|
12641
12688
|
setUpgradeModalDismissed(true);
|
|
12642
12689
|
return;
|
|
12643
12690
|
}
|
|
12644
|
-
if (_input === "o" && agentPageUrl && !(state.phase === "
|
|
12691
|
+
if (_input === "o" && agentPageUrl && !(state.phase === "checkpoint" && checkpointRecap)) {
|
|
12645
12692
|
void open4(agentPageUrl);
|
|
12646
12693
|
return;
|
|
12647
12694
|
}
|
|
@@ -12689,19 +12736,19 @@ function MarathonApp({
|
|
|
12689
12736
|
setShowHelpOverlay(false);
|
|
12690
12737
|
setHelpScrollOffset(0);
|
|
12691
12738
|
} else if (key.downArrow) {
|
|
12692
|
-
const
|
|
12693
|
-
const maxScroll = Math.max(0, getHelpLineCount(
|
|
12739
|
+
const isAtCheckpoint = state.phase === "checkpoint" && !!checkpointRecap;
|
|
12740
|
+
const maxScroll = Math.max(0, getHelpLineCount(isAtCheckpoint) - 1);
|
|
12694
12741
|
setHelpScrollOffset((prev) => Math.min(prev + SCROLL_STEP, maxScroll));
|
|
12695
12742
|
} else if (key.upArrow) {
|
|
12696
12743
|
setHelpScrollOffset((prev) => Math.max(0, prev - SCROLL_STEP));
|
|
12697
12744
|
}
|
|
12698
12745
|
return;
|
|
12699
12746
|
}
|
|
12700
|
-
if (_input === "?" && !(state.phase === "
|
|
12747
|
+
if (_input === "?" && !(state.phase === "checkpoint" && checkpointRecap)) {
|
|
12701
12748
|
setShowHelpOverlay(true);
|
|
12702
12749
|
return;
|
|
12703
12750
|
}
|
|
12704
|
-
if (_input === "s" && !(state.phase === "
|
|
12751
|
+
if (_input === "s" && !(state.phase === "checkpoint" && checkpointRecap)) {
|
|
12705
12752
|
setShowSessionMenu(true);
|
|
12706
12753
|
return;
|
|
12707
12754
|
}
|
|
@@ -12718,16 +12765,16 @@ function MarathonApp({
|
|
|
12718
12765
|
return;
|
|
12719
12766
|
}
|
|
12720
12767
|
}
|
|
12721
|
-
if (state.phase === "
|
|
12722
|
-
if (!
|
|
12768
|
+
if (state.phase === "checkpoint" && checkpointRecap) {
|
|
12769
|
+
if (!isAllowedCheckpointBrowseKey({ ...key, input: _input }, showFilesPanel || showEventStream || showToolsPanel)) return;
|
|
12723
12770
|
}
|
|
12724
12771
|
if (key.shift && key.leftArrow) {
|
|
12725
|
-
|
|
12772
|
+
markCheckpointExploring();
|
|
12726
12773
|
selectSessionTab(getAdjacentSessionTabKey(allTabs, selectedSessionKey, -1));
|
|
12727
12774
|
return;
|
|
12728
12775
|
}
|
|
12729
12776
|
if (key.shift && key.rightArrow) {
|
|
12730
|
-
|
|
12777
|
+
markCheckpointExploring();
|
|
12731
12778
|
selectSessionTab(getAdjacentSessionTabKey(allTabs, selectedSessionKey, 1));
|
|
12732
12779
|
return;
|
|
12733
12780
|
}
|
|
@@ -12741,7 +12788,7 @@ function MarathonApp({
|
|
|
12741
12788
|
return;
|
|
12742
12789
|
}
|
|
12743
12790
|
if (key.tab) {
|
|
12744
|
-
|
|
12791
|
+
markCheckpointExploring();
|
|
12745
12792
|
if (showFilesPanel) {
|
|
12746
12793
|
setDetailFile(null);
|
|
12747
12794
|
setDetailFileContent(null);
|
|
@@ -12769,8 +12816,8 @@ function MarathonApp({
|
|
|
12769
12816
|
return;
|
|
12770
12817
|
}
|
|
12771
12818
|
if (key.escape) {
|
|
12772
|
-
if (state.phase === "
|
|
12773
|
-
|
|
12819
|
+
if (state.phase === "checkpoint" && checkpointRecap) {
|
|
12820
|
+
markCheckpointExploring();
|
|
12774
12821
|
}
|
|
12775
12822
|
if (detailFile) {
|
|
12776
12823
|
setDetailFile(null);
|
|
@@ -12881,8 +12928,8 @@ function MarathonApp({
|
|
|
12881
12928
|
return;
|
|
12882
12929
|
}
|
|
12883
12930
|
if (key.upArrow) {
|
|
12884
|
-
if (state.phase === "
|
|
12885
|
-
|
|
12931
|
+
if (state.phase === "checkpoint" && checkpointRecap) {
|
|
12932
|
+
markCheckpointExploring();
|
|
12886
12933
|
}
|
|
12887
12934
|
if (showReasoningPanel) {
|
|
12888
12935
|
setReasoningScrollOffset((prev) => Math.max(0, prev - SCROLL_STEP));
|
|
@@ -12900,15 +12947,15 @@ function MarathonApp({
|
|
|
12900
12947
|
setEventCursor((prev) => Math.max(0, prev - 1));
|
|
12901
12948
|
} else {
|
|
12902
12949
|
const contentLines = displayedContent.split("\n").length * 2;
|
|
12903
|
-
const visibleRows = state.phase === "
|
|
12950
|
+
const visibleRows = state.phase === "checkpoint" && checkpointRecap ? adjustedContentHeight - checkpointPromptRows : transcriptRows;
|
|
12904
12951
|
const maxOverviewScroll = Math.max(0, contentLines - visibleRows);
|
|
12905
12952
|
setScrollOffset((prev) => Math.min(prev + SCROLL_STEP, maxOverviewScroll));
|
|
12906
12953
|
}
|
|
12907
12954
|
return;
|
|
12908
12955
|
}
|
|
12909
12956
|
if (key.downArrow) {
|
|
12910
|
-
if (state.phase === "
|
|
12911
|
-
|
|
12957
|
+
if (state.phase === "checkpoint" && checkpointRecap) {
|
|
12958
|
+
markCheckpointExploring();
|
|
12912
12959
|
}
|
|
12913
12960
|
if (showReasoningPanel) {
|
|
12914
12961
|
const totalReasoningLines = getReasoningLines(displayedReasoning, terminalWidth).length;
|
|
@@ -13049,7 +13096,7 @@ function MarathonApp({
|
|
|
13049
13096
|
if (clipboardFlash) return clipboardFlash;
|
|
13050
13097
|
if (showUpgradeModal) return joinHints("u: upgrade", "Enter: upgrade", "Esc: close", "Ctrl+C");
|
|
13051
13098
|
if (state.phase === "error" && !canBrowseAfterUpgradeError) return joinHints("Enter: exit", "Ctrl+C");
|
|
13052
|
-
if (state.phase === "
|
|
13099
|
+
if (state.phase === "checkpoint" && checkpointRecap) {
|
|
13053
13100
|
return joinHints(
|
|
13054
13101
|
"\u2191\u2193: scroll",
|
|
13055
13102
|
activeScreen !== "overview" ? "Esc: overview" : void 0,
|
|
@@ -13121,8 +13168,8 @@ function MarathonApp({
|
|
|
13121
13168
|
const goalText = goal || "";
|
|
13122
13169
|
const goalExpandedRows = goalExpanded && goalText.length > terminalWidth - 4 ? Math.ceil(goalText.length / (terminalWidth - 4)) - 1 : 0;
|
|
13123
13170
|
const adjustedContentHeight = contentHeight - goalExpandedRows - SCREEN_TABS_ROWS - (hasTabs ? SESSION_TABS_ROWS : 0);
|
|
13124
|
-
const
|
|
13125
|
-
const
|
|
13171
|
+
const checkpointWarningRows = checkpointRecap?.historyWarning ? Math.max(1, Math.ceil(checkpointRecap.historyWarning.length / Math.max(10, terminalWidth - 6))) : 0;
|
|
13172
|
+
const checkpointPromptRows = CHECKPOINT_PROMPT_ROWS + checkpointWarningRows;
|
|
13126
13173
|
const reasoningHintRows = hasReasoning ? 1 : 0;
|
|
13127
13174
|
const thinkingRows = showThinkingIndicator ? 2 : 0;
|
|
13128
13175
|
const compactionIndicatorRows = showContextCompactionIndicator ? 1 : 0;
|
|
@@ -13165,7 +13212,9 @@ function MarathonApp({
|
|
|
13165
13212
|
showRunner,
|
|
13166
13213
|
showFinish,
|
|
13167
13214
|
trackWidth: terminalWidth,
|
|
13168
|
-
previewUrl
|
|
13215
|
+
previewUrl,
|
|
13216
|
+
workflowMilestones,
|
|
13217
|
+
currentMilestone
|
|
13169
13218
|
}
|
|
13170
13219
|
),
|
|
13171
13220
|
/* @__PURE__ */ jsx31(Box26, { marginLeft: 1, children: /* @__PURE__ */ jsx31(ScreenTabs, { activeTab: activeScreen, width: terminalWidth - 1, shortcutHint: "Tab: next screen" }) }),
|
|
@@ -13255,7 +13304,7 @@ function MarathonApp({
|
|
|
13255
13304
|
}
|
|
13256
13305
|
)
|
|
13257
13306
|
}
|
|
13258
|
-
) : state.phase === "
|
|
13307
|
+
) : state.phase === "checkpoint" && checkpointRecap ? /* @__PURE__ */ jsxs25(
|
|
13259
13308
|
Box26,
|
|
13260
13309
|
{
|
|
13261
13310
|
flexDirection: isStacked ? "column" : "row",
|
|
@@ -13277,38 +13326,38 @@ function MarathonApp({
|
|
|
13277
13326
|
content: displayedContent,
|
|
13278
13327
|
isStreaming: false,
|
|
13279
13328
|
enableMarkdown: !plainText,
|
|
13280
|
-
maxVisibleLines: adjustedContentHeight -
|
|
13329
|
+
maxVisibleLines: adjustedContentHeight - checkpointPromptRows - 1,
|
|
13281
13330
|
scrollOffset
|
|
13282
13331
|
}
|
|
13283
13332
|
) }),
|
|
13284
13333
|
(() => {
|
|
13285
|
-
const
|
|
13286
|
-
const
|
|
13287
|
-
const
|
|
13334
|
+
const checkpointVisibleRows = adjustedContentHeight - checkpointPromptRows - 1;
|
|
13335
|
+
const checkpointTotalLines = displayedContent.split("\n").length;
|
|
13336
|
+
const checkpointMaxScroll = Math.max(0, checkpointTotalLines - checkpointVisibleRows);
|
|
13288
13337
|
return /* @__PURE__ */ jsx31(
|
|
13289
13338
|
Scrollbar,
|
|
13290
13339
|
{
|
|
13291
|
-
totalLines:
|
|
13292
|
-
visibleLines:
|
|
13293
|
-
scrollOffset:
|
|
13294
|
-
height:
|
|
13340
|
+
totalLines: checkpointTotalLines,
|
|
13341
|
+
visibleLines: checkpointVisibleRows,
|
|
13342
|
+
scrollOffset: checkpointMaxScroll - Math.min(scrollOffset, checkpointMaxScroll),
|
|
13343
|
+
height: checkpointVisibleRows
|
|
13295
13344
|
}
|
|
13296
13345
|
);
|
|
13297
13346
|
})()
|
|
13298
13347
|
] }),
|
|
13299
13348
|
/* @__PURE__ */ jsx31(
|
|
13300
|
-
|
|
13349
|
+
CheckpointPrompt,
|
|
13301
13350
|
{
|
|
13302
|
-
onSubmit:
|
|
13351
|
+
onSubmit: handleCheckpointSubmit,
|
|
13303
13352
|
onToggleHelp: () => setShowHelpOverlay((prev) => !prev),
|
|
13304
13353
|
onCopySession: handleCopySession,
|
|
13305
13354
|
onOpenStateFile: handleOpenStateFile,
|
|
13306
|
-
timeout:
|
|
13307
|
-
isTerminal:
|
|
13355
|
+
timeout: checkpointTimeout ?? 10,
|
|
13356
|
+
isTerminal: isTerminalCheckpoint,
|
|
13308
13357
|
currentModel,
|
|
13309
13358
|
currentSandbox,
|
|
13310
|
-
recap:
|
|
13311
|
-
isReviewing:
|
|
13359
|
+
recap: checkpointRecap,
|
|
13360
|
+
isReviewing: isCheckpointExploring
|
|
13312
13361
|
}
|
|
13313
13362
|
)
|
|
13314
13363
|
]
|
|
@@ -13458,7 +13507,7 @@ function MarathonApp({
|
|
|
13458
13507
|
{
|
|
13459
13508
|
width: terminalWidth,
|
|
13460
13509
|
height: adjustedContentHeight,
|
|
13461
|
-
|
|
13510
|
+
isCheckpoint: state.phase === "checkpoint" && !!checkpointRecap,
|
|
13462
13511
|
scrollOffset: helpScrollOffset
|
|
13463
13512
|
}
|
|
13464
13513
|
)
|
|
@@ -13545,11 +13594,13 @@ function MarathonApp({
|
|
|
13545
13594
|
import { useEffect as useEffect21, useRef as useRef9, useState as useState23 } from "react";
|
|
13546
13595
|
import { Box as Box27, Text as Text29, useApp as useApp5, useInput as useInput12, useStdout as useStdout6 } from "ink";
|
|
13547
13596
|
import { theme as theme31 } from "@runtypelabs/ink-components";
|
|
13597
|
+
import { AnimatedVariant, StartupGridIconCompactLightInverted } from "@runtypelabs/terminal-animations";
|
|
13548
13598
|
import { jsx as jsx32, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
13549
13599
|
var SCROLL_HINT = "\u2191\u2193 Enter 1-3";
|
|
13550
13600
|
var PROMPT_COLUMN_MAX = 68;
|
|
13551
13601
|
var MIN_HOLD_MS = 1500;
|
|
13552
13602
|
var FADE_DURATION_MS = 260;
|
|
13603
|
+
var STARTUP_BACKGROUND_VARIANTS = ["vector3d-ghost-wave", "vector3d-ghost-box-drift"];
|
|
13553
13604
|
function shortenPath2(filePath, maxLength) {
|
|
13554
13605
|
if (filePath.length <= maxLength) return filePath;
|
|
13555
13606
|
const normalizedSegments = filePath.split("/").filter(Boolean);
|
|
@@ -13599,6 +13650,7 @@ function MarathonStartupShell({
|
|
|
13599
13650
|
const mountedAtRef = useRef9(Date.now());
|
|
13600
13651
|
const promptResolverRef = useRef9(null);
|
|
13601
13652
|
const modelResolverRef = useRef9(null);
|
|
13653
|
+
const playbookConfirmResolverRef = useRef9(null);
|
|
13602
13654
|
const appReadyResolverRef = useRef9(null);
|
|
13603
13655
|
const dismissResolverRef = useRef9(null);
|
|
13604
13656
|
const transitionPromiseRef = useRef9(null);
|
|
@@ -13609,20 +13661,24 @@ function MarathonStartupShell({
|
|
|
13609
13661
|
const [prompt, setPrompt] = useState23(null);
|
|
13610
13662
|
const [modelChoices, setModelChoices] = useState23(null);
|
|
13611
13663
|
const [currentModel, setCurrentModel] = useState23("default");
|
|
13664
|
+
const [playbookConfirm, setPlaybookConfirm] = useState23(null);
|
|
13612
13665
|
const [selectedPromptIndex, setSelectedPromptIndex] = useState23(0);
|
|
13666
|
+
const [backgroundVariantId] = useState23(
|
|
13667
|
+
() => STARTUP_BACKGROUND_VARIANTS[Math.floor(Math.random() * STARTUP_BACKGROUND_VARIANTS.length)]
|
|
13668
|
+
);
|
|
13613
13669
|
latestAppPropsRef.current = marathonAppProps;
|
|
13614
13670
|
useEffect21(() => {
|
|
13615
13671
|
if (scene !== "app" || !appReadyResolverRef.current) return;
|
|
13616
|
-
const
|
|
13672
|
+
const resolve7 = appReadyResolverRef.current;
|
|
13617
13673
|
appReadyResolverRef.current = null;
|
|
13618
|
-
|
|
13674
|
+
resolve7();
|
|
13619
13675
|
}, [scene]);
|
|
13620
13676
|
const beginTransition = (target) => {
|
|
13621
13677
|
if (transitionPromiseRef.current) return transitionPromiseRef.current;
|
|
13622
13678
|
if (target === "app" && !latestAppPropsRef.current) {
|
|
13623
13679
|
throw new Error("Cannot complete startup before marathon app props are ready.");
|
|
13624
13680
|
}
|
|
13625
|
-
const promise = new Promise((
|
|
13681
|
+
const promise = new Promise((resolve7) => {
|
|
13626
13682
|
globalThis.setTimeout(() => {
|
|
13627
13683
|
setPrompt(null);
|
|
13628
13684
|
setModelChoices(null);
|
|
@@ -13643,12 +13699,12 @@ function MarathonStartupShell({
|
|
|
13643
13699
|
if (target === "app") {
|
|
13644
13700
|
appReadyResolverRef.current = () => {
|
|
13645
13701
|
transitionPromiseRef.current = null;
|
|
13646
|
-
|
|
13702
|
+
resolve7();
|
|
13647
13703
|
};
|
|
13648
13704
|
} else {
|
|
13649
13705
|
dismissResolverRef.current = () => {
|
|
13650
13706
|
transitionPromiseRef.current = null;
|
|
13651
|
-
|
|
13707
|
+
resolve7();
|
|
13652
13708
|
};
|
|
13653
13709
|
}
|
|
13654
13710
|
}, Math.max(0, MIN_HOLD_MS - (Date.now() - mountedAtRef.current)));
|
|
@@ -13665,16 +13721,33 @@ function MarathonStartupShell({
|
|
|
13665
13721
|
setModelChoices(null);
|
|
13666
13722
|
setPrompt(nextPrompt);
|
|
13667
13723
|
setSelectedPromptIndex(0);
|
|
13668
|
-
return new Promise((
|
|
13669
|
-
promptResolverRef.current =
|
|
13724
|
+
return new Promise((resolve7) => {
|
|
13725
|
+
promptResolverRef.current = resolve7;
|
|
13670
13726
|
});
|
|
13671
13727
|
},
|
|
13672
13728
|
requestModelChoice: async (nextCurrentModel, models) => {
|
|
13673
13729
|
setPrompt(null);
|
|
13730
|
+
setPlaybookConfirm(null);
|
|
13674
13731
|
setCurrentModel(nextCurrentModel);
|
|
13675
13732
|
setModelChoices(models);
|
|
13676
|
-
return new Promise((
|
|
13677
|
-
modelResolverRef.current =
|
|
13733
|
+
return new Promise((resolve7) => {
|
|
13734
|
+
modelResolverRef.current = resolve7;
|
|
13735
|
+
});
|
|
13736
|
+
},
|
|
13737
|
+
requestPlaybookModelConfirm: async (playbookName, milestoneModels) => {
|
|
13738
|
+
setPrompt(null);
|
|
13739
|
+
setModelChoices(null);
|
|
13740
|
+
const names = Object.keys(milestoneModels);
|
|
13741
|
+
setPlaybookConfirm({
|
|
13742
|
+
name: playbookName,
|
|
13743
|
+
milestoneModels: { ...milestoneModels },
|
|
13744
|
+
originalModels: { ...milestoneModels },
|
|
13745
|
+
milestoneNames: names,
|
|
13746
|
+
// Default selection is the "Confirm" action (first item after milestones)
|
|
13747
|
+
selectedIndex: names.length
|
|
13748
|
+
});
|
|
13749
|
+
return new Promise((resolve7) => {
|
|
13750
|
+
playbookConfirmResolverRef.current = resolve7;
|
|
13678
13751
|
});
|
|
13679
13752
|
},
|
|
13680
13753
|
completeStartup: () => beginTransition("app"),
|
|
@@ -13690,7 +13763,7 @@ function MarathonStartupShell({
|
|
|
13690
13763
|
process.kill(process.pid, "SIGINT");
|
|
13691
13764
|
return;
|
|
13692
13765
|
}
|
|
13693
|
-
if (!prompt || transition || modelChoices) return;
|
|
13766
|
+
if (!prompt || transition || modelChoices || playbookConfirm) return;
|
|
13694
13767
|
if (key.upArrow || input === "k") {
|
|
13695
13768
|
setSelectedPromptIndex((current) => (current - 1 + prompt.choices.length) % prompt.choices.length);
|
|
13696
13769
|
return;
|
|
@@ -13719,97 +13792,253 @@ function MarathonStartupShell({
|
|
|
13719
13792
|
}
|
|
13720
13793
|
}
|
|
13721
13794
|
},
|
|
13722
|
-
{ isActive: scene !== "app" }
|
|
13795
|
+
{ isActive: scene !== "app" && !playbookConfirm && !modelChoices }
|
|
13796
|
+
);
|
|
13797
|
+
useInput12(
|
|
13798
|
+
(input, key) => {
|
|
13799
|
+
if (key.ctrl && input === "c") {
|
|
13800
|
+
process.kill(process.pid, "SIGINT");
|
|
13801
|
+
return;
|
|
13802
|
+
}
|
|
13803
|
+
if (!playbookConfirm) return;
|
|
13804
|
+
const hasEdits = JSON.stringify(playbookConfirm.milestoneModels) !== JSON.stringify(playbookConfirm.originalModels);
|
|
13805
|
+
const actionCount = hasEdits ? 3 : 2;
|
|
13806
|
+
const totalItems = playbookConfirm.milestoneNames.length + actionCount;
|
|
13807
|
+
if (key.upArrow || input === "k") {
|
|
13808
|
+
setPlaybookConfirm((prev) => prev ? {
|
|
13809
|
+
...prev,
|
|
13810
|
+
selectedIndex: (prev.selectedIndex - 1 + totalItems) % totalItems
|
|
13811
|
+
} : null);
|
|
13812
|
+
return;
|
|
13813
|
+
}
|
|
13814
|
+
if (key.downArrow || input === "j") {
|
|
13815
|
+
setPlaybookConfirm((prev) => prev ? {
|
|
13816
|
+
...prev,
|
|
13817
|
+
selectedIndex: (prev.selectedIndex + 1) % totalItems
|
|
13818
|
+
} : null);
|
|
13819
|
+
return;
|
|
13820
|
+
}
|
|
13821
|
+
if (key.return) {
|
|
13822
|
+
const idx = playbookConfirm.selectedIndex;
|
|
13823
|
+
const milestoneCount = playbookConfirm.milestoneNames.length;
|
|
13824
|
+
if (idx < milestoneCount) {
|
|
13825
|
+
const milestone = playbookConfirm.milestoneNames[idx];
|
|
13826
|
+
playbookConfirmResolverRef.current?.({
|
|
13827
|
+
action: "edit",
|
|
13828
|
+
milestoneModels: playbookConfirm.milestoneModels,
|
|
13829
|
+
editMilestone: milestone
|
|
13830
|
+
});
|
|
13831
|
+
playbookConfirmResolverRef.current = null;
|
|
13832
|
+
setPlaybookConfirm(null);
|
|
13833
|
+
} else {
|
|
13834
|
+
const actionIndex = idx - milestoneCount;
|
|
13835
|
+
if (actionIndex === 0) {
|
|
13836
|
+
playbookConfirmResolverRef.current?.({
|
|
13837
|
+
action: "confirm",
|
|
13838
|
+
milestoneModels: playbookConfirm.milestoneModels
|
|
13839
|
+
});
|
|
13840
|
+
playbookConfirmResolverRef.current = null;
|
|
13841
|
+
setPlaybookConfirm(null);
|
|
13842
|
+
} else if (actionIndex === 1) {
|
|
13843
|
+
playbookConfirmResolverRef.current?.({ action: "override" });
|
|
13844
|
+
playbookConfirmResolverRef.current = null;
|
|
13845
|
+
setPlaybookConfirm(null);
|
|
13846
|
+
} else if (actionIndex === 2 && hasEdits) {
|
|
13847
|
+
setPlaybookConfirm((prev) => prev ? {
|
|
13848
|
+
...prev,
|
|
13849
|
+
milestoneModels: { ...prev.originalModels },
|
|
13850
|
+
selectedIndex: prev.milestoneNames.length
|
|
13851
|
+
// back to Confirm
|
|
13852
|
+
} : null);
|
|
13853
|
+
}
|
|
13854
|
+
}
|
|
13855
|
+
}
|
|
13856
|
+
},
|
|
13857
|
+
{ isActive: scene !== "app" && !!playbookConfirm }
|
|
13723
13858
|
);
|
|
13724
13859
|
const terminalWidth = stdout?.columns ?? 120;
|
|
13725
13860
|
const terminalRows = stdout?.rows ?? 40;
|
|
13726
13861
|
const promptColumnWidth = Math.max(44, Math.min(PROMPT_COLUMN_MAX, terminalWidth - 14));
|
|
13727
13862
|
const promptShellModel = prompt ? buildPromptShellModel(prompt, promptColumnWidth) : null;
|
|
13728
13863
|
const selectedChoice = prompt?.choices[selectedPromptIndex];
|
|
13864
|
+
const contentWidth = prompt || modelChoices || playbookConfirm ? promptColumnWidth : void 0;
|
|
13729
13865
|
if (scene === "app" && marathonAppProps) {
|
|
13730
13866
|
return /* @__PURE__ */ jsx32(MarathonApp, { ...marathonAppProps });
|
|
13731
13867
|
}
|
|
13732
|
-
return /* @__PURE__ */
|
|
13733
|
-
|
|
13734
|
-
|
|
13735
|
-
|
|
13736
|
-
|
|
13737
|
-
|
|
13738
|
-
|
|
13739
|
-
|
|
13740
|
-
|
|
13741
|
-
|
|
13742
|
-
!prompt && !modelChoices && /* @__PURE__ */ jsx32(Box27, { width: terminalWidth, justifyContent: "center", children: /* @__PURE__ */ jsx32(Text29, { color: theme31.textMuted, children: statusMessage }) }),
|
|
13743
|
-
modelChoices && /* @__PURE__ */ jsx32(Box27, { width: promptColumnWidth, flexDirection: "column", marginTop: 1, children: /* @__PURE__ */ jsx32(
|
|
13744
|
-
ModelPicker,
|
|
13868
|
+
return /* @__PURE__ */ jsxs26(Box27, { width: terminalWidth, height: terminalRows, backgroundColor: theme31.background, children: [
|
|
13869
|
+
/* @__PURE__ */ jsx32(
|
|
13870
|
+
Box27,
|
|
13871
|
+
{
|
|
13872
|
+
position: "absolute",
|
|
13873
|
+
width: terminalWidth,
|
|
13874
|
+
height: terminalRows,
|
|
13875
|
+
overflow: "hidden",
|
|
13876
|
+
children: /* @__PURE__ */ jsx32(
|
|
13877
|
+
AnimatedVariant,
|
|
13745
13878
|
{
|
|
13746
|
-
|
|
13747
|
-
|
|
13748
|
-
|
|
13749
|
-
modelResolverRef.current?.(model);
|
|
13750
|
-
modelResolverRef.current = null;
|
|
13751
|
-
setCurrentModel(model);
|
|
13752
|
-
setModelChoices(null);
|
|
13753
|
-
},
|
|
13754
|
-
onCancel: () => {
|
|
13755
|
-
modelResolverRef.current?.(currentModel);
|
|
13756
|
-
modelResolverRef.current = null;
|
|
13757
|
-
setModelChoices(null);
|
|
13758
|
-
}
|
|
13879
|
+
variantId: backgroundVariantId,
|
|
13880
|
+
width: terminalWidth,
|
|
13881
|
+
height: terminalRows
|
|
13759
13882
|
}
|
|
13760
|
-
)
|
|
13761
|
-
|
|
13762
|
-
|
|
13763
|
-
|
|
13764
|
-
|
|
13765
|
-
|
|
13766
|
-
|
|
13767
|
-
|
|
13768
|
-
|
|
13769
|
-
|
|
13770
|
-
|
|
13771
|
-
|
|
13772
|
-
|
|
13773
|
-
|
|
13774
|
-
|
|
13775
|
-
|
|
13776
|
-
|
|
13777
|
-
|
|
13778
|
-
|
|
13779
|
-
|
|
13780
|
-
|
|
13781
|
-
|
|
13782
|
-
|
|
13783
|
-
|
|
13784
|
-
|
|
13785
|
-
|
|
13883
|
+
)
|
|
13884
|
+
}
|
|
13885
|
+
),
|
|
13886
|
+
/* @__PURE__ */ jsx32(
|
|
13887
|
+
Box27,
|
|
13888
|
+
{
|
|
13889
|
+
position: "absolute",
|
|
13890
|
+
width: terminalWidth,
|
|
13891
|
+
height: terminalRows,
|
|
13892
|
+
alignItems: "flex-start",
|
|
13893
|
+
justifyContent: "flex-start",
|
|
13894
|
+
paddingX: 1,
|
|
13895
|
+
paddingY: 1,
|
|
13896
|
+
children: /* @__PURE__ */ jsx32(StartupGridIconCompactLightInverted, { autoplay: false })
|
|
13897
|
+
}
|
|
13898
|
+
),
|
|
13899
|
+
/* @__PURE__ */ jsx32(
|
|
13900
|
+
Box27,
|
|
13901
|
+
{
|
|
13902
|
+
width: terminalWidth,
|
|
13903
|
+
height: terminalRows,
|
|
13904
|
+
flexDirection: "column",
|
|
13905
|
+
justifyContent: "center",
|
|
13906
|
+
alignItems: "center",
|
|
13907
|
+
children: /* @__PURE__ */ jsxs26(
|
|
13908
|
+
Box27,
|
|
13909
|
+
{
|
|
13910
|
+
flexDirection: "column",
|
|
13911
|
+
alignItems: prompt || modelChoices || playbookConfirm ? "stretch" : "center",
|
|
13912
|
+
backgroundColor: theme31.background,
|
|
13913
|
+
paddingX: 2,
|
|
13914
|
+
paddingY: 1,
|
|
13915
|
+
children: [
|
|
13916
|
+
!prompt && !modelChoices && !playbookConfirm && /* @__PURE__ */ jsx32(Text29, { color: theme31.textMuted, children: statusMessage }),
|
|
13917
|
+
playbookConfirm && !modelChoices && (() => {
|
|
13918
|
+
const milestoneCount = playbookConfirm.milestoneNames.length;
|
|
13919
|
+
const hasEdits = JSON.stringify(playbookConfirm.milestoneModels) !== JSON.stringify(playbookConfirm.originalModels);
|
|
13920
|
+
const actions = [
|
|
13921
|
+
"Confirm",
|
|
13922
|
+
"Use single model instead",
|
|
13923
|
+
...hasEdits ? ["Discard changes"] : []
|
|
13924
|
+
];
|
|
13925
|
+
return /* @__PURE__ */ jsxs26(Box27, { width: contentWidth, flexDirection: "column", marginTop: 1, children: [
|
|
13926
|
+
/* @__PURE__ */ jsxs26(Text29, { bold: true, color: theme31.text, children: [
|
|
13927
|
+
"Playbook: ",
|
|
13928
|
+
playbookConfirm.name
|
|
13929
|
+
] }),
|
|
13930
|
+
/* @__PURE__ */ jsx32(Box27, { marginTop: 1, flexDirection: "column", children: playbookConfirm.milestoneNames.map((milestone, i) => {
|
|
13931
|
+
const isSelected = i === playbookConfirm.selectedIndex;
|
|
13932
|
+
const model = playbookConfirm.milestoneModels[milestone];
|
|
13933
|
+
const wasEdited = model !== playbookConfirm.originalModels[milestone];
|
|
13934
|
+
return /* @__PURE__ */ jsxs26(Box27, { children: [
|
|
13935
|
+
/* @__PURE__ */ jsx32(Text29, { color: isSelected ? theme31.accent : theme31.textSubtle, children: isSelected ? "\u203A " : " " }),
|
|
13936
|
+
/* @__PURE__ */ jsx32(Text29, { color: isSelected ? theme31.text : theme31.textSubtle, bold: isSelected, children: milestone.padEnd(16) }),
|
|
13937
|
+
/* @__PURE__ */ jsx32(Text29, { color: isSelected ? theme31.accent : theme31.textMuted, children: model }),
|
|
13938
|
+
wasEdited && /* @__PURE__ */ jsx32(Text29, { color: theme31.textSubtle, children: " (edited)" })
|
|
13939
|
+
] }, milestone);
|
|
13940
|
+
}) }),
|
|
13941
|
+
/* @__PURE__ */ jsx32(Box27, { marginTop: 1, flexDirection: "column", children: actions.map((label, ai) => {
|
|
13942
|
+
const isSelected = playbookConfirm.selectedIndex === milestoneCount + ai;
|
|
13943
|
+
return /* @__PURE__ */ jsxs26(Box27, { children: [
|
|
13944
|
+
/* @__PURE__ */ jsx32(Text29, { color: isSelected ? theme31.accent : theme31.textSubtle, children: isSelected ? "\u203A " : " " }),
|
|
13945
|
+
/* @__PURE__ */ jsx32(Text29, { color: isSelected ? theme31.text : theme31.textSubtle, bold: isSelected, children: label })
|
|
13946
|
+
] }, label);
|
|
13947
|
+
}) }),
|
|
13948
|
+
/* @__PURE__ */ jsx32(Box27, { marginTop: 1, children: /* @__PURE__ */ jsx32(Text29, { color: theme31.border, children: "\u2191\u2193 navigate \xB7 Enter select" }) })
|
|
13949
|
+
] });
|
|
13950
|
+
})(),
|
|
13951
|
+
modelChoices && /* @__PURE__ */ jsx32(Box27, { width: contentWidth, flexDirection: "column", marginTop: 1, children: /* @__PURE__ */ jsx32(
|
|
13952
|
+
ModelPicker,
|
|
13953
|
+
{
|
|
13954
|
+
currentModel,
|
|
13955
|
+
models: modelChoices,
|
|
13956
|
+
onSelect: (model) => {
|
|
13957
|
+
modelResolverRef.current?.(model);
|
|
13958
|
+
modelResolverRef.current = null;
|
|
13959
|
+
setCurrentModel(model);
|
|
13960
|
+
setModelChoices(null);
|
|
13961
|
+
},
|
|
13962
|
+
onCancel: () => {
|
|
13963
|
+
modelResolverRef.current?.(currentModel);
|
|
13964
|
+
modelResolverRef.current = null;
|
|
13965
|
+
setModelChoices(null);
|
|
13966
|
+
}
|
|
13967
|
+
}
|
|
13968
|
+
) }),
|
|
13969
|
+
prompt && /* @__PURE__ */ jsxs26(Box27, { width: contentWidth, flexDirection: "column", marginTop: 1, children: [
|
|
13970
|
+
/* @__PURE__ */ jsx32(Text29, { bold: true, color: theme31.text, children: promptShellModel?.heading }),
|
|
13971
|
+
promptShellModel?.task && /* @__PURE__ */ jsxs26(Box27, { marginTop: 1, children: [
|
|
13972
|
+
/* @__PURE__ */ jsx32(Text29, { color: theme31.textSubtle, children: "task " }),
|
|
13973
|
+
/* @__PURE__ */ jsx32(Text29, { color: theme31.text, children: promptShellModel.task })
|
|
13974
|
+
] }),
|
|
13975
|
+
promptShellModel?.filePath && /* @__PURE__ */ jsxs26(Box27, { children: [
|
|
13976
|
+
/* @__PURE__ */ jsx32(Text29, { color: theme31.textSubtle, children: "state " }),
|
|
13977
|
+
/* @__PURE__ */ jsx32(Text29, { color: theme31.textSubtle, children: promptShellModel.filePath })
|
|
13978
|
+
] }),
|
|
13979
|
+
promptShellModel?.metaLine && /* @__PURE__ */ jsx32(Box27, { marginTop: 1, children: /* @__PURE__ */ jsx32(Text29, { color: theme31.textSubtle, children: promptShellModel.metaLine }) }),
|
|
13980
|
+
/* @__PURE__ */ jsx32(Box27, { marginTop: 1, children: /* @__PURE__ */ jsx32(Text29, { color: theme31.textSubtle, children: prompt.hint }) }),
|
|
13981
|
+
/* @__PURE__ */ jsx32(Box27, { flexDirection: "column", marginTop: 1, children: prompt.choices.map((choice, index) => {
|
|
13982
|
+
const isSelected = index === selectedPromptIndex;
|
|
13983
|
+
return /* @__PURE__ */ jsxs26(Box27, { marginTop: index === 0 ? 0 : 1, children: [
|
|
13984
|
+
/* @__PURE__ */ jsx32(Text29, { color: isSelected ? theme31.accent : theme31.textSubtle, bold: isSelected, children: isSelected ? "\u203A " : " " }),
|
|
13985
|
+
/* @__PURE__ */ jsx32(Text29, { color: isSelected ? theme31.text : theme31.textSubtle, bold: isSelected, children: `${index + 1} ${choice.label}` })
|
|
13986
|
+
] }, choice.value);
|
|
13987
|
+
}) }),
|
|
13988
|
+
selectedChoice && /* @__PURE__ */ jsx32(Box27, { marginTop: 1, children: /* @__PURE__ */ jsx32(Text29, { color: theme31.textSubtle, children: selectedChoice.description }) }),
|
|
13989
|
+
/* @__PURE__ */ jsx32(Box27, { marginTop: 1, children: /* @__PURE__ */ jsx32(Text29, { color: theme31.border, children: SCROLL_HINT }) })
|
|
13990
|
+
] })
|
|
13991
|
+
]
|
|
13992
|
+
}
|
|
13993
|
+
)
|
|
13994
|
+
}
|
|
13995
|
+
)
|
|
13996
|
+
] });
|
|
13786
13997
|
}
|
|
13787
13998
|
|
|
13788
13999
|
// src/commands/agents-task.ts
|
|
13789
|
-
import * as
|
|
14000
|
+
import * as fs13 from "fs";
|
|
13790
14001
|
import {
|
|
13791
14002
|
RuntypeClient as RuntypeClient2,
|
|
14003
|
+
defaultWorkflow,
|
|
13792
14004
|
deployWorkflow,
|
|
13793
14005
|
gameWorkflow
|
|
13794
14006
|
} from "@runtypelabs/sdk";
|
|
13795
14007
|
|
|
14008
|
+
// src/lib/terminal-title.ts
|
|
14009
|
+
import path4 from "path";
|
|
14010
|
+
function setTerminalTitle(title) {
|
|
14011
|
+
if (process.stdout.isTTY) {
|
|
14012
|
+
process.stdout.write(`\x1B]0;${title}\x07`);
|
|
14013
|
+
}
|
|
14014
|
+
}
|
|
14015
|
+
function getFolderName() {
|
|
14016
|
+
return path4.basename(process.cwd());
|
|
14017
|
+
}
|
|
14018
|
+
function setCliTitle() {
|
|
14019
|
+
setTerminalTitle(`Runtype (${getFolderName()})`);
|
|
14020
|
+
}
|
|
14021
|
+
function setMarathonTitle() {
|
|
14022
|
+
setTerminalTitle(`Runtype: Marathon (${getFolderName()})`);
|
|
14023
|
+
}
|
|
14024
|
+
|
|
13796
14025
|
// src/marathon/checkpoint.ts
|
|
13797
14026
|
import * as fs6 from "fs";
|
|
13798
|
-
import * as
|
|
14027
|
+
import * as path6 from "path";
|
|
13799
14028
|
|
|
13800
14029
|
// src/config/paths.ts
|
|
13801
14030
|
import * as os3 from "os";
|
|
13802
|
-
import * as
|
|
14031
|
+
import * as path5 from "path";
|
|
13803
14032
|
import * as crypto3 from "crypto";
|
|
13804
14033
|
import * as fs5 from "fs";
|
|
13805
14034
|
function getRuntypeHomeDir() {
|
|
13806
|
-
return process.env.RUNTYPE_STATE_DIR ||
|
|
14035
|
+
return process.env.RUNTYPE_STATE_DIR || path5.join(os3.homedir(), ".runtype");
|
|
13807
14036
|
}
|
|
13808
14037
|
function getProjectStateDir(projectDir) {
|
|
13809
14038
|
const dir = projectDir || process.cwd();
|
|
13810
14039
|
const hash = crypto3.createHash("sha256").update(dir).digest("hex").slice(0, 12);
|
|
13811
|
-
const stateDir =
|
|
13812
|
-
const breadcrumb =
|
|
14040
|
+
const stateDir = path5.join(getRuntypeHomeDir(), "projects", hash);
|
|
14041
|
+
const breadcrumb = path5.join(stateDir, "project-path.txt");
|
|
13813
14042
|
if (!fs5.existsSync(breadcrumb)) {
|
|
13814
14043
|
fs5.mkdirSync(stateDir, { recursive: true });
|
|
13815
14044
|
fs5.writeFileSync(breadcrumb, dir);
|
|
@@ -13817,7 +14046,7 @@ function getProjectStateDir(projectDir) {
|
|
|
13817
14046
|
return stateDir;
|
|
13818
14047
|
}
|
|
13819
14048
|
function getMarathonStateDir(projectDir) {
|
|
13820
|
-
return
|
|
14049
|
+
return path5.join(getProjectStateDir(projectDir), "marathons");
|
|
13821
14050
|
}
|
|
13822
14051
|
|
|
13823
14052
|
// src/marathon/checkpoint.ts
|
|
@@ -13828,12 +14057,12 @@ function stateSafeName(name) {
|
|
|
13828
14057
|
return name.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
13829
14058
|
}
|
|
13830
14059
|
function marathonArtifactsDir(taskName, stateDir) {
|
|
13831
|
-
return
|
|
14060
|
+
return path6.join(stateDir || defaultStateDir(), stateSafeName(taskName));
|
|
13832
14061
|
}
|
|
13833
14062
|
function resolveMarathonCheckpointPath(taskName, targetPath, stateDir) {
|
|
13834
|
-
const normalizedTargetPath =
|
|
13835
|
-
const relativeTargetPath =
|
|
13836
|
-
return
|
|
14063
|
+
const normalizedTargetPath = path6.normalize(targetPath);
|
|
14064
|
+
const relativeTargetPath = path6.isAbsolute(normalizedTargetPath) ? path6.relative(process.cwd(), normalizedTargetPath) : normalizedTargetPath;
|
|
14065
|
+
return path6.join(
|
|
13837
14066
|
marathonArtifactsDir(taskName, stateDir),
|
|
13838
14067
|
"checkpoints",
|
|
13839
14068
|
"original",
|
|
@@ -13841,23 +14070,23 @@ function resolveMarathonCheckpointPath(taskName, targetPath, stateDir) {
|
|
|
13841
14070
|
);
|
|
13842
14071
|
}
|
|
13843
14072
|
function ensureMarathonFileCheckpoint(taskName, targetPath, stateDir) {
|
|
13844
|
-
const normalizedTargetPath =
|
|
13845
|
-
const relativeTargetPath =
|
|
14073
|
+
const normalizedTargetPath = path6.resolve(targetPath);
|
|
14074
|
+
const relativeTargetPath = path6.relative(process.cwd(), normalizedTargetPath);
|
|
13846
14075
|
if (!relativeTargetPath || relativeTargetPath.startsWith("..")) return void 0;
|
|
13847
14076
|
if (!fs6.existsSync(normalizedTargetPath)) return void 0;
|
|
13848
14077
|
if (!fs6.statSync(normalizedTargetPath).isFile()) return void 0;
|
|
13849
14078
|
const normalizedRelativeTargetPath = relativeTargetPath.replace(/\\/g, "/");
|
|
13850
14079
|
if (normalizedRelativeTargetPath.startsWith(".runtype/")) return void 0;
|
|
13851
|
-
if (normalizedTargetPath.startsWith(getRuntypeHomeDir() +
|
|
14080
|
+
if (normalizedTargetPath.startsWith(getRuntypeHomeDir() + path6.sep)) return void 0;
|
|
13852
14081
|
const checkpointPath = resolveMarathonCheckpointPath(taskName, normalizedTargetPath, stateDir);
|
|
13853
14082
|
if (fs6.existsSync(checkpointPath)) return checkpointPath;
|
|
13854
|
-
fs6.mkdirSync(
|
|
14083
|
+
fs6.mkdirSync(path6.dirname(checkpointPath), { recursive: true });
|
|
13855
14084
|
fs6.copyFileSync(normalizedTargetPath, checkpointPath);
|
|
13856
14085
|
return checkpointPath;
|
|
13857
14086
|
}
|
|
13858
14087
|
function restoreMarathonFileCheckpoint(taskName, targetPath, stateDir) {
|
|
13859
|
-
const normalizedTargetPath =
|
|
13860
|
-
const relativeTargetPath =
|
|
14088
|
+
const normalizedTargetPath = path6.resolve(targetPath);
|
|
14089
|
+
const relativeTargetPath = path6.relative(process.cwd(), normalizedTargetPath);
|
|
13861
14090
|
if (!relativeTargetPath || relativeTargetPath.startsWith("..")) {
|
|
13862
14091
|
return {
|
|
13863
14092
|
restored: false,
|
|
@@ -13872,7 +14101,7 @@ function restoreMarathonFileCheckpoint(taskName, targetPath, stateDir) {
|
|
|
13872
14101
|
error: `No checkpoint found for ${normalizedTargetPath}`
|
|
13873
14102
|
};
|
|
13874
14103
|
}
|
|
13875
|
-
fs6.mkdirSync(
|
|
14104
|
+
fs6.mkdirSync(path6.dirname(normalizedTargetPath), { recursive: true });
|
|
13876
14105
|
fs6.copyFileSync(checkpointPath, normalizedTargetPath);
|
|
13877
14106
|
return { restored: true, checkpointPath };
|
|
13878
14107
|
}
|
|
@@ -13930,7 +14159,7 @@ async function retryOnNetworkError(fn, opts = {}) {
|
|
|
13930
14159
|
}
|
|
13931
14160
|
const delay = Math.min(baseDelay * 2 ** attempt, maxDelay);
|
|
13932
14161
|
opts.onRetry?.(attempt + 1, delay, error);
|
|
13933
|
-
await new Promise((
|
|
14162
|
+
await new Promise((resolve7) => setTimeout(resolve7, delay));
|
|
13934
14163
|
}
|
|
13935
14164
|
}
|
|
13936
14165
|
throw lastError;
|
|
@@ -14046,7 +14275,7 @@ function isSafeVerificationCommand(command) {
|
|
|
14046
14275
|
|
|
14047
14276
|
// src/marathon/state.ts
|
|
14048
14277
|
import * as fs7 from "fs";
|
|
14049
|
-
import * as
|
|
14278
|
+
import * as path7 from "path";
|
|
14050
14279
|
import chalk15 from "chalk";
|
|
14051
14280
|
|
|
14052
14281
|
// src/lib/select-prompt.ts
|
|
@@ -14081,14 +14310,14 @@ async function promptNumericSelect(choices, promptLabel) {
|
|
|
14081
14310
|
output: process.stdout,
|
|
14082
14311
|
terminal: true
|
|
14083
14312
|
});
|
|
14084
|
-
return new Promise((
|
|
14313
|
+
return new Promise((resolve7) => {
|
|
14085
14314
|
const ask = () => {
|
|
14086
14315
|
rl.question(chalk14.cyan(`
|
|
14087
14316
|
${promptLabel} (1-${choices.length}): `), (answer) => {
|
|
14088
14317
|
const value = parseInt(answer.trim(), 10);
|
|
14089
14318
|
if (value >= 1 && value <= choices.length) {
|
|
14090
14319
|
rl.close();
|
|
14091
|
-
|
|
14320
|
+
resolve7(choices[value - 1].value);
|
|
14092
14321
|
return;
|
|
14093
14322
|
}
|
|
14094
14323
|
console.log(chalk14.red(`Please enter a number between 1 and ${choices.length}.`));
|
|
@@ -14116,7 +14345,7 @@ ${message}`));
|
|
|
14116
14345
|
const previousRawMode = input.isRaw === true;
|
|
14117
14346
|
let selectedIndex = 0;
|
|
14118
14347
|
let renderedLineCount = 0;
|
|
14119
|
-
return new Promise((
|
|
14348
|
+
return new Promise((resolve7) => {
|
|
14120
14349
|
const renderMenu = () => {
|
|
14121
14350
|
if (renderedLineCount > 0) {
|
|
14122
14351
|
clearRenderedLines(output, renderedLineCount);
|
|
@@ -14138,7 +14367,7 @@ ${message}`));
|
|
|
14138
14367
|
};
|
|
14139
14368
|
const finish = (value) => {
|
|
14140
14369
|
cleanup();
|
|
14141
|
-
|
|
14370
|
+
resolve7(value);
|
|
14142
14371
|
};
|
|
14143
14372
|
const onKeypress = (_, key) => {
|
|
14144
14373
|
if (key.ctrl && key.name === "c") {
|
|
@@ -14184,7 +14413,7 @@ function stateSafeName2(name) {
|
|
|
14184
14413
|
}
|
|
14185
14414
|
function stateFilePath(name, stateDir) {
|
|
14186
14415
|
const dir = stateDir || defaultStateDir2();
|
|
14187
|
-
return
|
|
14416
|
+
return path7.join(dir, `${stateSafeName2(name)}.json`);
|
|
14188
14417
|
}
|
|
14189
14418
|
function normalizeMarathonStatePath(candidatePath) {
|
|
14190
14419
|
if (!candidatePath) return void 0;
|
|
@@ -14193,15 +14422,15 @@ function normalizeMarathonStatePath(candidatePath) {
|
|
|
14193
14422
|
}
|
|
14194
14423
|
function marathonStatePathExists(candidatePath) {
|
|
14195
14424
|
if (!candidatePath) return false;
|
|
14196
|
-
return fs7.existsSync(
|
|
14425
|
+
return fs7.existsSync(path7.resolve(candidatePath));
|
|
14197
14426
|
}
|
|
14198
14427
|
function isMarathonArtifactStatePath(candidatePath) {
|
|
14199
14428
|
if (!candidatePath) return false;
|
|
14200
14429
|
const normalized = normalizeMarathonStatePath(candidatePath)?.toLowerCase();
|
|
14201
14430
|
if (normalized === ".runtype" || normalized?.startsWith(".runtype/") === true) return true;
|
|
14202
|
-
const resolved =
|
|
14431
|
+
const resolved = path7.resolve(candidatePath);
|
|
14203
14432
|
const homeStateDir = getRuntypeHomeDir();
|
|
14204
|
-
return resolved.startsWith(homeStateDir +
|
|
14433
|
+
return resolved.startsWith(homeStateDir + path7.sep) || resolved === homeStateDir;
|
|
14205
14434
|
}
|
|
14206
14435
|
function scoreMarathonCandidatePath(candidatePath) {
|
|
14207
14436
|
const normalized = candidatePath.toLowerCase();
|
|
@@ -14374,7 +14603,7 @@ function loadState(filePath) {
|
|
|
14374
14603
|
}
|
|
14375
14604
|
}
|
|
14376
14605
|
function saveState(filePath, state, options) {
|
|
14377
|
-
const dir =
|
|
14606
|
+
const dir = path7.dirname(filePath);
|
|
14378
14607
|
fs7.mkdirSync(dir, { recursive: true });
|
|
14379
14608
|
const stateToWrite = options?.stripSnapshotEvents && state.sessionSnapshots?.length ? {
|
|
14380
14609
|
...state,
|
|
@@ -14412,9 +14641,9 @@ function findStateFile(name, stateDir) {
|
|
|
14412
14641
|
}
|
|
14413
14642
|
const homePath = stateFilePath(name, getMarathonStateDir());
|
|
14414
14643
|
if (fs7.existsSync(homePath)) return homePath;
|
|
14415
|
-
const oldMarathonPath = stateFilePath(name,
|
|
14644
|
+
const oldMarathonPath = stateFilePath(name, path7.join(process.cwd(), ".runtype", "marathons"));
|
|
14416
14645
|
if (fs7.existsSync(oldMarathonPath)) return oldMarathonPath;
|
|
14417
|
-
const oldTaskPath = stateFilePath(name,
|
|
14646
|
+
const oldTaskPath = stateFilePath(name, path7.join(process.cwd(), ".runtype", "tasks"));
|
|
14418
14647
|
if (fs7.existsSync(oldTaskPath)) return oldTaskPath;
|
|
14419
14648
|
return homePath;
|
|
14420
14649
|
}
|
|
@@ -14423,15 +14652,15 @@ function findLatestStateFile(stateDir) {
|
|
|
14423
14652
|
// New home-dir location
|
|
14424
14653
|
getMarathonStateDir(),
|
|
14425
14654
|
// Old project-dir locations (backward compat)
|
|
14426
|
-
|
|
14427
|
-
|
|
14655
|
+
path7.join(process.cwd(), ".runtype", "marathons"),
|
|
14656
|
+
path7.join(process.cwd(), ".runtype", "tasks")
|
|
14428
14657
|
];
|
|
14429
14658
|
let latest = null;
|
|
14430
14659
|
for (const dir of dirs) {
|
|
14431
14660
|
if (!fs7.existsSync(dir)) continue;
|
|
14432
14661
|
const files = fs7.readdirSync(dir).filter((f) => f.endsWith(".json"));
|
|
14433
14662
|
for (const file of files) {
|
|
14434
|
-
const fullPath =
|
|
14663
|
+
const fullPath = path7.join(dir, file);
|
|
14435
14664
|
const stat = fs7.statSync(fullPath);
|
|
14436
14665
|
if (!latest || stat.mtimeMs > latest.mtime) {
|
|
14437
14666
|
latest = { name: file.replace(".json", ""), filePath: fullPath, mtime: stat.mtimeMs };
|
|
@@ -14553,12 +14782,12 @@ function buildResumeCommand(agent, options, parsedSandbox) {
|
|
|
14553
14782
|
|
|
14554
14783
|
// src/marathon/local-tools.ts
|
|
14555
14784
|
import * as fs9 from "fs";
|
|
14556
|
-
import * as
|
|
14785
|
+
import * as path9 from "path";
|
|
14557
14786
|
import { spawnSync } from "child_process";
|
|
14558
14787
|
|
|
14559
14788
|
// src/marathon/repo-discovery.ts
|
|
14560
14789
|
import * as fs8 from "fs";
|
|
14561
|
-
import * as
|
|
14790
|
+
import * as path8 from "path";
|
|
14562
14791
|
var IGNORED_REPO_DIRS = /* @__PURE__ */ new Set([
|
|
14563
14792
|
".git",
|
|
14564
14793
|
".next",
|
|
@@ -14633,8 +14862,8 @@ var SEARCH_STOP_WORDS = /* @__PURE__ */ new Set([
|
|
|
14633
14862
|
"do"
|
|
14634
14863
|
]);
|
|
14635
14864
|
function normalizeToolPath(toolPath) {
|
|
14636
|
-
const resolved =
|
|
14637
|
-
return
|
|
14865
|
+
const resolved = path8.resolve(toolPath || ".");
|
|
14866
|
+
return path8.relative(process.cwd(), resolved) || ".";
|
|
14638
14867
|
}
|
|
14639
14868
|
function tokenizeSearchQuery(query) {
|
|
14640
14869
|
return query.toLowerCase().split(/[^a-z0-9./_-]+/g).map((token) => token.trim()).filter((token) => token.length >= 2 && !SEARCH_STOP_WORDS.has(token));
|
|
@@ -14643,7 +14872,7 @@ function scoreSearchPath(relativePath) {
|
|
|
14643
14872
|
const normalized = relativePath.replace(/\\/g, "/");
|
|
14644
14873
|
const segments = normalized.split("/");
|
|
14645
14874
|
const fileName = segments[segments.length - 1] || normalized;
|
|
14646
|
-
const extension =
|
|
14875
|
+
const extension = path8.extname(fileName).toLowerCase();
|
|
14647
14876
|
let score = 0;
|
|
14648
14877
|
if (LOW_SIGNAL_FILE_NAMES.has(fileName)) score -= 50;
|
|
14649
14878
|
if (segments.some((segment) => LOW_SIGNAL_PATH_SEGMENTS.has(segment))) score -= 15;
|
|
@@ -14658,7 +14887,7 @@ function scoreSearchPath(relativePath) {
|
|
|
14658
14887
|
function shouldIgnoreRepoEntry(entryPath) {
|
|
14659
14888
|
const normalized = normalizeToolPath(entryPath);
|
|
14660
14889
|
if (normalized === ".") return false;
|
|
14661
|
-
return normalized.split(
|
|
14890
|
+
return normalized.split(path8.sep).some((segment) => IGNORED_REPO_DIRS.has(segment));
|
|
14662
14891
|
}
|
|
14663
14892
|
function safeReadTextFile(filePath) {
|
|
14664
14893
|
try {
|
|
@@ -14684,7 +14913,7 @@ function walkRepo(startPath, visitor) {
|
|
|
14684
14913
|
continue;
|
|
14685
14914
|
}
|
|
14686
14915
|
for (const entry of entries) {
|
|
14687
|
-
const entryPath =
|
|
14916
|
+
const entryPath = path8.join(currentDir, entry.name);
|
|
14688
14917
|
if (shouldIgnoreRepoEntry(entryPath)) continue;
|
|
14689
14918
|
const shouldStop = visitor(entryPath, entry);
|
|
14690
14919
|
if (shouldStop === true) return;
|
|
@@ -14729,7 +14958,7 @@ function buildTree(dirPath, maxDepth, depth = 0) {
|
|
|
14729
14958
|
}
|
|
14730
14959
|
const lines = [];
|
|
14731
14960
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
14732
|
-
const entryPath =
|
|
14961
|
+
const entryPath = path8.join(dirPath, entry.name);
|
|
14733
14962
|
if (shouldIgnoreRepoEntry(entryPath)) continue;
|
|
14734
14963
|
lines.push(`${" ".repeat(depth)}- ${entry.name}${entry.isDirectory() ? "/" : ""}`);
|
|
14735
14964
|
if (entry.isDirectory() && depth < maxDepth) {
|
|
@@ -14745,14 +14974,14 @@ function stateSafeName3(name) {
|
|
|
14745
14974
|
return name.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
14746
14975
|
}
|
|
14747
14976
|
function getOffloadedOutputDir(taskName, stateDir) {
|
|
14748
|
-
return
|
|
14977
|
+
return path9.join(stateDir || getMarathonStateDir(), stateSafeName3(taskName), "outputs");
|
|
14749
14978
|
}
|
|
14750
14979
|
function isPathWithinRoot(targetPath, rootPath) {
|
|
14751
|
-
const relativePath =
|
|
14752
|
-
return relativePath === "" || !relativePath.startsWith("..") && !
|
|
14980
|
+
const relativePath = path9.relative(rootPath, targetPath);
|
|
14981
|
+
return relativePath === "" || !relativePath.startsWith("..") && !path9.isAbsolute(relativePath);
|
|
14753
14982
|
}
|
|
14754
14983
|
function resolveCanonicalToolPath(toolPath, allowMissing) {
|
|
14755
|
-
const absolutePath =
|
|
14984
|
+
const absolutePath = path9.resolve(toolPath);
|
|
14756
14985
|
if (fs9.existsSync(absolutePath)) {
|
|
14757
14986
|
return {
|
|
14758
14987
|
canonicalPath: fs9.realpathSync.native(absolutePath),
|
|
@@ -14763,22 +14992,22 @@ function resolveCanonicalToolPath(toolPath, allowMissing) {
|
|
|
14763
14992
|
const missingSegments = [];
|
|
14764
14993
|
let currentPath = absolutePath;
|
|
14765
14994
|
while (!fs9.existsSync(currentPath)) {
|
|
14766
|
-
const parentPath =
|
|
14995
|
+
const parentPath = path9.dirname(currentPath);
|
|
14767
14996
|
if (parentPath === currentPath) return null;
|
|
14768
|
-
missingSegments.unshift(
|
|
14997
|
+
missingSegments.unshift(path9.basename(currentPath));
|
|
14769
14998
|
currentPath = parentPath;
|
|
14770
14999
|
}
|
|
14771
15000
|
return {
|
|
14772
|
-
canonicalPath:
|
|
15001
|
+
canonicalPath: path9.join(fs9.realpathSync.native(currentPath), ...missingSegments),
|
|
14773
15002
|
exists: false
|
|
14774
15003
|
};
|
|
14775
15004
|
}
|
|
14776
15005
|
function canonicalizeAllowedRoot(rootPath) {
|
|
14777
|
-
return resolveCanonicalToolPath(rootPath, true)?.canonicalPath ||
|
|
15006
|
+
return resolveCanonicalToolPath(rootPath, true)?.canonicalPath || path9.resolve(rootPath);
|
|
14778
15007
|
}
|
|
14779
15008
|
function findBlockedWorkspaceSegment(targetPath, workspaceRoot) {
|
|
14780
15009
|
if (!isPathWithinRoot(targetPath, workspaceRoot)) return void 0;
|
|
14781
|
-
const relativePath =
|
|
15010
|
+
const relativePath = path9.relative(workspaceRoot, targetPath).replace(/\\/g, "/");
|
|
14782
15011
|
if (!relativePath) return void 0;
|
|
14783
15012
|
return relativePath.split("/").find((segment) => DIRECT_TOOL_BLOCKED_SEGMENTS.has(segment));
|
|
14784
15013
|
}
|
|
@@ -14871,7 +15100,7 @@ function createDefaultLocalTools(context) {
|
|
|
14871
15100
|
if (fs9.existsSync(resolvedPath.resolvedPath) && fs9.statSync(resolvedPath.resolvedPath).isDirectory()) {
|
|
14872
15101
|
return `Error: Path is a directory: ${String(args.path || "")}`;
|
|
14873
15102
|
}
|
|
14874
|
-
const dir =
|
|
15103
|
+
const dir = path9.dirname(resolvedPath.resolvedPath);
|
|
14875
15104
|
fs9.mkdirSync(dir, { recursive: true });
|
|
14876
15105
|
fs9.writeFileSync(resolvedPath.resolvedPath, content);
|
|
14877
15106
|
return "ok";
|
|
@@ -14888,7 +15117,7 @@ function createDefaultLocalTools(context) {
|
|
|
14888
15117
|
requireDirectory: true
|
|
14889
15118
|
});
|
|
14890
15119
|
if (!resolvedPath.ok) return `Error: ${resolvedPath.error}`;
|
|
14891
|
-
return fs9.readdirSync(resolvedPath.resolvedPath, { withFileTypes: true }).filter((entry) => !shouldIgnoreRepoEntry(
|
|
15120
|
+
return fs9.readdirSync(resolvedPath.resolvedPath, { withFileTypes: true }).filter((entry) => !shouldIgnoreRepoEntry(path9.join(resolvedPath.resolvedPath, entry.name))).map((entry) => entry.name).join("\n");
|
|
14892
15121
|
}
|
|
14893
15122
|
},
|
|
14894
15123
|
search_repo: {
|
|
@@ -15053,7 +15282,7 @@ function createCheckpointedWriteFileTool(taskName, stateDir) {
|
|
|
15053
15282
|
if (!resolvedPath.ok) return `Error: ${resolvedPath.error}`;
|
|
15054
15283
|
const content = String(args.content || "");
|
|
15055
15284
|
ensureMarathonFileCheckpoint(taskName, resolvedPath.resolvedPath, stateDir);
|
|
15056
|
-
const dir =
|
|
15285
|
+
const dir = path9.dirname(resolvedPath.resolvedPath);
|
|
15057
15286
|
fs9.mkdirSync(dir, { recursive: true });
|
|
15058
15287
|
fs9.writeFileSync(resolvedPath.resolvedPath, content);
|
|
15059
15288
|
return "ok";
|
|
@@ -15102,7 +15331,7 @@ function createReadOffloadedOutputTool(taskName, stateDir) {
|
|
|
15102
15331
|
if (!/^[a-zA-Z0-9_-]+$/.test(outputId)) {
|
|
15103
15332
|
return `Error: invalid offloaded output id: ${outputId}`;
|
|
15104
15333
|
}
|
|
15105
|
-
const outputPath =
|
|
15334
|
+
const outputPath = path9.join(getOffloadedOutputDir(taskName, stateDir), `${outputId}.txt`);
|
|
15106
15335
|
if (!fs9.existsSync(outputPath) || !fs9.statSync(outputPath).isFile()) {
|
|
15107
15336
|
return `Error: offloaded output not found: ${outputId}`;
|
|
15108
15337
|
}
|
|
@@ -15265,7 +15494,7 @@ function createLoopDetector(options = {}) {
|
|
|
15265
15494
|
cachedLoopInfo = null;
|
|
15266
15495
|
dirty = false;
|
|
15267
15496
|
},
|
|
15268
|
-
|
|
15497
|
+
getCheckpointMessage() {
|
|
15269
15498
|
const info = this.getLoopInfo();
|
|
15270
15499
|
if (!info) return "";
|
|
15271
15500
|
return [
|
|
@@ -15284,7 +15513,7 @@ function createLoopDetector(options = {}) {
|
|
|
15284
15513
|
|
|
15285
15514
|
// src/marathon/context-offload.ts
|
|
15286
15515
|
import * as fs10 from "fs";
|
|
15287
|
-
import * as
|
|
15516
|
+
import * as path10 from "path";
|
|
15288
15517
|
var DEFAULT_OUTPUT_THRESHOLD = 2e3;
|
|
15289
15518
|
var DEFAULT_PREVIEW_LENGTH = 200;
|
|
15290
15519
|
function buildOffloadedOutputId(toolName) {
|
|
@@ -15316,13 +15545,13 @@ function offloadToolOutput(taskName, toolName, output, options = {}, stateDir) {
|
|
|
15316
15545
|
return { offloaded: false, content: output };
|
|
15317
15546
|
}
|
|
15318
15547
|
const outputId = buildOffloadedOutputId(toolName);
|
|
15319
|
-
const dir =
|
|
15548
|
+
const dir = path10.join(
|
|
15320
15549
|
stateDir || defaultStateDir3(),
|
|
15321
15550
|
stateSafeName4(taskName),
|
|
15322
15551
|
"outputs"
|
|
15323
15552
|
);
|
|
15324
15553
|
const fileName = `${outputId}.txt`;
|
|
15325
|
-
const filePath =
|
|
15554
|
+
const filePath = path10.join(dir, fileName);
|
|
15326
15555
|
fs10.mkdirSync(dir, { recursive: true });
|
|
15327
15556
|
fs10.writeFileSync(filePath, output, "utf-8");
|
|
15328
15557
|
const preview = output.slice(0, previewLength).replace(/\n/g, " ");
|
|
@@ -15497,42 +15726,17 @@ function resolveAutoCompactTokenThreshold(modelContextLength, rawThreshold, stra
|
|
|
15497
15726
|
|
|
15498
15727
|
// src/marathon/recipes.ts
|
|
15499
15728
|
import * as fs11 from "fs";
|
|
15500
|
-
import * as
|
|
15501
|
-
var RECIPES_DIR = ".marathon/recipes";
|
|
15502
|
-
function loadRecipe(nameOrPath, cwd) {
|
|
15503
|
-
const baseCwd = cwd || process.cwd();
|
|
15504
|
-
const candidates = [
|
|
15505
|
-
// Exact path
|
|
15506
|
-
path10.resolve(baseCwd, nameOrPath),
|
|
15507
|
-
// .marathon/recipes/<name>.json
|
|
15508
|
-
path10.resolve(baseCwd, RECIPES_DIR, `${nameOrPath}.json`),
|
|
15509
|
-
// .marathon/recipes/<name>/recipe.json
|
|
15510
|
-
path10.resolve(baseCwd, RECIPES_DIR, nameOrPath, "recipe.json")
|
|
15511
|
-
];
|
|
15512
|
-
for (const candidate of candidates) {
|
|
15513
|
-
if (!fs11.existsSync(candidate)) continue;
|
|
15514
|
-
try {
|
|
15515
|
-
const raw = fs11.readFileSync(candidate, "utf-8");
|
|
15516
|
-
const parsed = JSON.parse(raw);
|
|
15517
|
-
if (parsed.meta?.name && parsed.meta?.version) {
|
|
15518
|
-
return parsed;
|
|
15519
|
-
}
|
|
15520
|
-
} catch {
|
|
15521
|
-
continue;
|
|
15522
|
-
}
|
|
15523
|
-
}
|
|
15524
|
-
return null;
|
|
15525
|
-
}
|
|
15729
|
+
import * as path11 from "path";
|
|
15526
15730
|
var RULES_DIR = ".marathon/rules";
|
|
15527
15731
|
function loadRules(cwd) {
|
|
15528
15732
|
const baseCwd = cwd || process.cwd();
|
|
15529
|
-
const rulesDir =
|
|
15733
|
+
const rulesDir = path11.resolve(baseCwd, RULES_DIR);
|
|
15530
15734
|
if (!fs11.existsSync(rulesDir)) return [];
|
|
15531
15735
|
const rules = [];
|
|
15532
15736
|
try {
|
|
15533
15737
|
const entries = fs11.readdirSync(rulesDir).filter((f) => f.endsWith(".md"));
|
|
15534
15738
|
for (const entry of entries) {
|
|
15535
|
-
const filePath =
|
|
15739
|
+
const filePath = path11.join(rulesDir, entry);
|
|
15536
15740
|
try {
|
|
15537
15741
|
const raw = fs11.readFileSync(filePath, "utf-8");
|
|
15538
15742
|
const parsed = parseRuleFile(raw);
|
|
@@ -15567,26 +15771,154 @@ function extractYamlArray(yaml, key) {
|
|
|
15567
15771
|
if (!match) return [];
|
|
15568
15772
|
return match[1].split(",").map((s) => s.trim().replace(/^["']|["']$/g, "")).filter(Boolean);
|
|
15569
15773
|
}
|
|
15570
|
-
function resolveModelForPhase(phase,
|
|
15774
|
+
function resolveModelForPhase(phase, cliOverrides, milestoneModels) {
|
|
15775
|
+
if (phase && milestoneModels?.[phase]) {
|
|
15776
|
+
return milestoneModels[phase];
|
|
15777
|
+
}
|
|
15571
15778
|
if (phase === "research" || phase === "planning") {
|
|
15572
15779
|
if (cliOverrides.planningModel) return cliOverrides.planningModel;
|
|
15573
15780
|
}
|
|
15574
15781
|
if (phase === "execution") {
|
|
15575
15782
|
if (cliOverrides.executionModel) return cliOverrides.executionModel;
|
|
15576
15783
|
}
|
|
15577
|
-
if (recipe?.model) {
|
|
15578
|
-
if (phase === "research" && recipe.model.research) return recipe.model.research;
|
|
15579
|
-
if (phase === "planning" && recipe.model.planning) return recipe.model.planning;
|
|
15580
|
-
if (phase === "execution" && recipe.model.execution) return recipe.model.execution;
|
|
15581
|
-
}
|
|
15582
15784
|
return cliOverrides.defaultModel;
|
|
15583
15785
|
}
|
|
15584
15786
|
|
|
15787
|
+
// src/marathon/playbook-loader.ts
|
|
15788
|
+
import * as fs12 from "fs";
|
|
15789
|
+
import * as path12 from "path";
|
|
15790
|
+
import * as os4 from "os";
|
|
15791
|
+
import { parse as parseYaml } from "yaml";
|
|
15792
|
+
var PLAYBOOKS_DIR = ".runtype/marathons/playbooks";
|
|
15793
|
+
function getCandidatePaths(nameOrPath, cwd) {
|
|
15794
|
+
const home = os4.homedir();
|
|
15795
|
+
return [
|
|
15796
|
+
// Exact path
|
|
15797
|
+
path12.resolve(cwd, nameOrPath),
|
|
15798
|
+
// Repo-level
|
|
15799
|
+
path12.resolve(cwd, PLAYBOOKS_DIR, `${nameOrPath}.yaml`),
|
|
15800
|
+
path12.resolve(cwd, PLAYBOOKS_DIR, `${nameOrPath}.yml`),
|
|
15801
|
+
path12.resolve(cwd, PLAYBOOKS_DIR, `${nameOrPath}.json`),
|
|
15802
|
+
// User-level
|
|
15803
|
+
path12.resolve(home, PLAYBOOKS_DIR, `${nameOrPath}.yaml`),
|
|
15804
|
+
path12.resolve(home, PLAYBOOKS_DIR, `${nameOrPath}.yml`),
|
|
15805
|
+
path12.resolve(home, PLAYBOOKS_DIR, `${nameOrPath}.json`)
|
|
15806
|
+
];
|
|
15807
|
+
}
|
|
15808
|
+
function parsePlaybookFile(filePath) {
|
|
15809
|
+
const raw = fs12.readFileSync(filePath, "utf-8");
|
|
15810
|
+
const ext = path12.extname(filePath).toLowerCase();
|
|
15811
|
+
if (ext === ".json") {
|
|
15812
|
+
return JSON.parse(raw);
|
|
15813
|
+
}
|
|
15814
|
+
return parseYaml(raw);
|
|
15815
|
+
}
|
|
15816
|
+
function validatePlaybook(config2, filePath) {
|
|
15817
|
+
if (!config2.name) {
|
|
15818
|
+
throw new Error(`Playbook at ${filePath} is missing required 'name' field`);
|
|
15819
|
+
}
|
|
15820
|
+
if (!config2.milestones || config2.milestones.length === 0) {
|
|
15821
|
+
throw new Error(`Playbook '${config2.name}' must have at least one milestone`);
|
|
15822
|
+
}
|
|
15823
|
+
for (const milestone of config2.milestones) {
|
|
15824
|
+
if (!milestone.name) {
|
|
15825
|
+
throw new Error(`Playbook '${config2.name}': each milestone must have a 'name'`);
|
|
15826
|
+
}
|
|
15827
|
+
if (!milestone.instructions) {
|
|
15828
|
+
throw new Error(`Playbook '${config2.name}': milestone '${milestone.name}' is missing 'instructions'`);
|
|
15829
|
+
}
|
|
15830
|
+
}
|
|
15831
|
+
}
|
|
15832
|
+
function interpolate(template, state) {
|
|
15833
|
+
return template.replace(/\{\{(\w+)\}\}/g, (_match, key) => {
|
|
15834
|
+
const value = state[key];
|
|
15835
|
+
if (value === void 0 || value === null) return `{{${key}}}`;
|
|
15836
|
+
return String(value);
|
|
15837
|
+
});
|
|
15838
|
+
}
|
|
15839
|
+
function buildIsComplete(criteria) {
|
|
15840
|
+
if (!criteria) return () => false;
|
|
15841
|
+
switch (criteria.type) {
|
|
15842
|
+
case "evidence":
|
|
15843
|
+
return (ctx) => {
|
|
15844
|
+
const minFiles = criteria.minReadFiles ?? 1;
|
|
15845
|
+
return (ctx.state.recentReadPaths?.length ?? 0) >= minFiles;
|
|
15846
|
+
};
|
|
15847
|
+
case "sessions": {
|
|
15848
|
+
let baselineSessionCount;
|
|
15849
|
+
return (ctx) => {
|
|
15850
|
+
const minSessions = criteria.minSessions ?? 1;
|
|
15851
|
+
if (baselineSessionCount === void 0) {
|
|
15852
|
+
baselineSessionCount = ctx.state.sessions.length;
|
|
15853
|
+
}
|
|
15854
|
+
return ctx.state.sessions.length - baselineSessionCount >= minSessions;
|
|
15855
|
+
};
|
|
15856
|
+
}
|
|
15857
|
+
case "planWritten":
|
|
15858
|
+
return (ctx) => {
|
|
15859
|
+
return ctx.trace.planWritten;
|
|
15860
|
+
};
|
|
15861
|
+
case "never":
|
|
15862
|
+
default:
|
|
15863
|
+
return () => false;
|
|
15864
|
+
}
|
|
15865
|
+
}
|
|
15866
|
+
function convertToWorkflow(config2) {
|
|
15867
|
+
const phases = config2.milestones.map((milestone) => ({
|
|
15868
|
+
name: milestone.name,
|
|
15869
|
+
description: milestone.description,
|
|
15870
|
+
buildInstructions(state) {
|
|
15871
|
+
const header = `--- Workflow Phase: ${milestone.name} ---`;
|
|
15872
|
+
const desc = milestone.description ? `
|
|
15873
|
+
${milestone.description}` : "";
|
|
15874
|
+
const instructions = interpolate(milestone.instructions, state);
|
|
15875
|
+
return `${header}${desc}
|
|
15876
|
+
${instructions}`;
|
|
15877
|
+
},
|
|
15878
|
+
buildToolGuidance(_state) {
|
|
15879
|
+
return milestone.toolGuidance ?? [];
|
|
15880
|
+
},
|
|
15881
|
+
isComplete: buildIsComplete(milestone.completionCriteria),
|
|
15882
|
+
// Default to rejecting TASK_COMPLETE unless the playbook explicitly allows it.
|
|
15883
|
+
// The SDK accepts completion by default when canAcceptCompletion is undefined,
|
|
15884
|
+
// which would let the model end the marathon prematurely in early phases.
|
|
15885
|
+
canAcceptCompletion: milestone.canAcceptCompletion !== void 0 ? () => milestone.canAcceptCompletion : () => false
|
|
15886
|
+
}));
|
|
15887
|
+
return {
|
|
15888
|
+
name: config2.name,
|
|
15889
|
+
phases
|
|
15890
|
+
};
|
|
15891
|
+
}
|
|
15892
|
+
function loadPlaybook(nameOrPath, cwd) {
|
|
15893
|
+
const baseCwd = cwd || process.cwd();
|
|
15894
|
+
const candidates = getCandidatePaths(nameOrPath, baseCwd);
|
|
15895
|
+
for (const candidate of candidates) {
|
|
15896
|
+
if (!fs12.existsSync(candidate)) continue;
|
|
15897
|
+
const config2 = parsePlaybookFile(candidate);
|
|
15898
|
+
validatePlaybook(config2, candidate);
|
|
15899
|
+
const milestoneModels = {};
|
|
15900
|
+
for (const m of config2.milestones) {
|
|
15901
|
+
if (m.model) milestoneModels[m.name] = m.model;
|
|
15902
|
+
}
|
|
15903
|
+
return {
|
|
15904
|
+
workflow: convertToWorkflow(config2),
|
|
15905
|
+
milestones: config2.milestones.map((m) => m.name),
|
|
15906
|
+
milestoneModels: Object.keys(milestoneModels).length > 0 ? milestoneModels : void 0,
|
|
15907
|
+
verification: config2.verification,
|
|
15908
|
+
rules: config2.rules
|
|
15909
|
+
};
|
|
15910
|
+
}
|
|
15911
|
+
throw new Error(
|
|
15912
|
+
`Playbook '${nameOrPath}' not found. Searched:
|
|
15913
|
+
${candidates.map((c) => ` ${c}`).join("\n")}`
|
|
15914
|
+
);
|
|
15915
|
+
}
|
|
15916
|
+
|
|
15585
15917
|
// src/commands/agents-task.ts
|
|
15586
15918
|
var import_builtin_tools_registry = __toESM(require_builtin_tools_registry(), 1);
|
|
15587
15919
|
var import_provider_routing = __toESM(require_provider_routing(), 1);
|
|
15588
|
-
function
|
|
15589
|
-
if (status !== "paused" ||
|
|
15920
|
+
function shouldRequestResumeCheckpoint(status, resumeMessage, noCheckpoint, originalMessage, continuations) {
|
|
15921
|
+
if (status !== "paused" || noCheckpoint) return false;
|
|
15590
15922
|
const normalizedResumeMessage = resumeMessage?.trim();
|
|
15591
15923
|
if (!normalizedResumeMessage) return true;
|
|
15592
15924
|
const normalizedOriginalMessage = originalMessage?.trim();
|
|
@@ -15600,7 +15932,7 @@ function shouldRequestResumeSteering(status, resumeMessage, noSteer, originalMes
|
|
|
15600
15932
|
}
|
|
15601
15933
|
return false;
|
|
15602
15934
|
}
|
|
15603
|
-
function
|
|
15935
|
+
function buildResumeCheckpointRecap(state, snapshots) {
|
|
15604
15936
|
const latestSnapshot = snapshots[snapshots.length - 1];
|
|
15605
15937
|
const derivedTokens = state.sessions?.reduce(
|
|
15606
15938
|
(totals, session) => ({
|
|
@@ -15780,15 +16112,6 @@ async function taskAction(agent, options) {
|
|
|
15780
16112
|
console.error(chalk16.red(error instanceof Error ? error.message : String(error)));
|
|
15781
16113
|
process.exit(1);
|
|
15782
16114
|
}
|
|
15783
|
-
let recipe = null;
|
|
15784
|
-
if (options.recipe) {
|
|
15785
|
-
recipe = loadRecipe(options.recipe);
|
|
15786
|
-
if (!recipe) {
|
|
15787
|
-
console.error(chalk16.red(`Recipe not found: "${options.recipe}"`));
|
|
15788
|
-
console.log(chalk16.gray(" Place recipes in .marathon/recipes/<name>.json"));
|
|
15789
|
-
process.exit(1);
|
|
15790
|
-
}
|
|
15791
|
-
}
|
|
15792
16115
|
const rules = loadRules();
|
|
15793
16116
|
const rulesContext = rules.length > 0 ? rules.map((r) => r.content).join("\n\n---\n\n") : "";
|
|
15794
16117
|
const allModels = [
|
|
@@ -15796,10 +16119,7 @@ async function taskAction(agent, options) {
|
|
|
15796
16119
|
[
|
|
15797
16120
|
options.model,
|
|
15798
16121
|
options.planningModel,
|
|
15799
|
-
options.executionModel
|
|
15800
|
-
recipe?.model?.planning,
|
|
15801
|
-
recipe?.model?.execution,
|
|
15802
|
-
recipe?.model?.research
|
|
16122
|
+
options.executionModel
|
|
15803
16123
|
].filter((m) => Boolean(m))
|
|
15804
16124
|
)
|
|
15805
16125
|
];
|
|
@@ -15841,7 +16161,7 @@ async function taskAction(agent, options) {
|
|
|
15841
16161
|
waitForUiExit = renderedShell.waitUntilExit;
|
|
15842
16162
|
rerenderUi = renderedShell.rerender;
|
|
15843
16163
|
unmountUi = renderedShell.unmount;
|
|
15844
|
-
await new Promise((
|
|
16164
|
+
await new Promise((resolve7) => setTimeout(resolve7, 0));
|
|
15845
16165
|
if (!startupShellRef.current) {
|
|
15846
16166
|
exitAltScreen();
|
|
15847
16167
|
unmountUi?.();
|
|
@@ -15962,7 +16282,7 @@ async function taskAction(agent, options) {
|
|
|
15962
16282
|
forcedResumeFilePath = stateResolution.filePath;
|
|
15963
16283
|
} else {
|
|
15964
16284
|
resumeRequested = false;
|
|
15965
|
-
if (options.fresh &&
|
|
16285
|
+
if (options.fresh && fs13.existsSync(filePath)) {
|
|
15966
16286
|
if (useStartupShell) {
|
|
15967
16287
|
setStartupStatus("starting fresh");
|
|
15968
16288
|
} else {
|
|
@@ -15989,7 +16309,7 @@ async function taskAction(agent, options) {
|
|
|
15989
16309
|
let persistedSessionSnapshots = [];
|
|
15990
16310
|
let resumeState;
|
|
15991
16311
|
let resumeLoadedState = null;
|
|
15992
|
-
let
|
|
16312
|
+
let shouldPromptResumeCheckpoint = false;
|
|
15993
16313
|
let resumeHistoryWarning;
|
|
15994
16314
|
let eventLogWriter;
|
|
15995
16315
|
if (resumeRequested) {
|
|
@@ -16038,15 +16358,15 @@ async function taskAction(agent, options) {
|
|
|
16038
16358
|
resumeLoadedState = existing;
|
|
16039
16359
|
resumeHistoryWarning = buildResumeHistoryWarning(existing);
|
|
16040
16360
|
const resumeMessage = typeof options.resume === "string" ? options.resume : options.goal;
|
|
16041
|
-
|
|
16361
|
+
shouldPromptResumeCheckpoint = shouldRequestResumeCheckpoint(
|
|
16042
16362
|
existing.status,
|
|
16043
16363
|
resumeMessage,
|
|
16044
|
-
options.
|
|
16364
|
+
options.noCheckpoint ?? false,
|
|
16045
16365
|
existing.originalMessage,
|
|
16046
16366
|
existing.continuations
|
|
16047
16367
|
);
|
|
16048
16368
|
previousMessages = existing.messages ?? [];
|
|
16049
|
-
continuationMessage =
|
|
16369
|
+
continuationMessage = shouldPromptResumeCheckpoint ? void 0 : resumeMessage;
|
|
16050
16370
|
useCompact = options.compact ?? false;
|
|
16051
16371
|
priorContinuations = [...existing.continuations ?? []];
|
|
16052
16372
|
resumeState = extractRunTaskResumeState(existing);
|
|
@@ -16071,19 +16391,64 @@ async function taskAction(agent, options) {
|
|
|
16071
16391
|
}
|
|
16072
16392
|
}
|
|
16073
16393
|
}
|
|
16394
|
+
let playbookWorkflow;
|
|
16395
|
+
let playbookMilestones;
|
|
16396
|
+
let playbookMilestoneModels;
|
|
16397
|
+
if (options.playbook) {
|
|
16398
|
+
const result = loadPlaybook(options.playbook);
|
|
16399
|
+
playbookWorkflow = result.workflow;
|
|
16400
|
+
playbookMilestones = result.milestones;
|
|
16401
|
+
playbookMilestoneModels = result.milestoneModels;
|
|
16402
|
+
}
|
|
16074
16403
|
if (useStartupShell && !options.model?.trim()) {
|
|
16075
|
-
|
|
16076
|
-
|
|
16077
|
-
|
|
16078
|
-
|
|
16079
|
-
|
|
16080
|
-
|
|
16081
|
-
|
|
16082
|
-
|
|
16083
|
-
|
|
16084
|
-
|
|
16085
|
-
|
|
16086
|
-
|
|
16404
|
+
if (playbookMilestoneModels && Object.keys(playbookMilestoneModels).length > 0 && startupShellRef.current) {
|
|
16405
|
+
let editableModels = { ...playbookMilestoneModels };
|
|
16406
|
+
let confirmed = false;
|
|
16407
|
+
while (!confirmed) {
|
|
16408
|
+
setStartupStatus("reviewing playbook models");
|
|
16409
|
+
const confirmResult = await startupShellRef.current.requestPlaybookModelConfirm(
|
|
16410
|
+
options.playbook,
|
|
16411
|
+
editableModels
|
|
16412
|
+
);
|
|
16413
|
+
if (confirmResult.action === "confirm") {
|
|
16414
|
+
playbookMilestoneModels = confirmResult.milestoneModels ?? editableModels;
|
|
16415
|
+
const firstMilestoneModel = Object.values(playbookMilestoneModels)[0];
|
|
16416
|
+
if (firstMilestoneModel) options.model = firstMilestoneModel;
|
|
16417
|
+
confirmed = true;
|
|
16418
|
+
} else if (confirmResult.action === "edit" && confirmResult.editMilestone) {
|
|
16419
|
+
let startupModelOptions = buildMarathonStartupModelOptions(configuredModels, availableModels);
|
|
16420
|
+
if (startupModelOptions.length === 0) {
|
|
16421
|
+
startupModelOptions = DEFAULT_MODELS;
|
|
16422
|
+
}
|
|
16423
|
+
const currentMilestoneModel = editableModels[confirmResult.editMilestone];
|
|
16424
|
+
const pickedModel = await startupShellRef.current.requestModelChoice(
|
|
16425
|
+
currentMilestoneModel,
|
|
16426
|
+
startupModelOptions
|
|
16427
|
+
);
|
|
16428
|
+
editableModels = {
|
|
16429
|
+
...confirmResult.milestoneModels ?? editableModels,
|
|
16430
|
+
[confirmResult.editMilestone]: pickedModel
|
|
16431
|
+
};
|
|
16432
|
+
} else {
|
|
16433
|
+
playbookMilestoneModels = void 0;
|
|
16434
|
+
confirmed = true;
|
|
16435
|
+
}
|
|
16436
|
+
}
|
|
16437
|
+
}
|
|
16438
|
+
if (!playbookMilestoneModels) {
|
|
16439
|
+
let startupModelOptions = buildMarathonStartupModelOptions(configuredModels, availableModels);
|
|
16440
|
+
if (startupModelOptions.length === 0) {
|
|
16441
|
+
startupModelOptions = DEFAULT_MODELS;
|
|
16442
|
+
}
|
|
16443
|
+
const initialStartupModel = agentConfigModel || defaultConfiguredModel || startupModelOptions[0]?.value;
|
|
16444
|
+
if (startupModelOptions.length > 0 && initialStartupModel && startupShellRef.current) {
|
|
16445
|
+
setStartupStatus("selecting model");
|
|
16446
|
+
options.model = await startupShellRef.current.requestModelChoice(
|
|
16447
|
+
initialStartupModel,
|
|
16448
|
+
startupModelOptions
|
|
16449
|
+
);
|
|
16450
|
+
setStartupStatus(`model ready: ${options.model}`);
|
|
16451
|
+
}
|
|
16087
16452
|
}
|
|
16088
16453
|
}
|
|
16089
16454
|
try {
|
|
@@ -16109,23 +16474,25 @@ async function taskAction(agent, options) {
|
|
|
16109
16474
|
const remainingCost = maxCost ? maxCost - priorCost : void 0;
|
|
16110
16475
|
const baseMessage = options.goal || (resumeRequested ? "Continue the task." : "");
|
|
16111
16476
|
const sandboxPrompt = parsedSandbox ? createSandboxInstructions(parsedSandbox) : "";
|
|
16112
|
-
const resolvedWorkflow = detectDeployWorkflow(baseMessage, parsedSandbox, resumeState);
|
|
16477
|
+
const resolvedWorkflow = playbookWorkflow ?? detectDeployWorkflow(baseMessage, parsedSandbox, resumeState);
|
|
16478
|
+
const DEFAULT_MILESTONE_NAMES = ["research", "planning", "execution"];
|
|
16479
|
+
const EXTERNAL_MILESTONE_NAMES = ["research", "report"];
|
|
16480
|
+
const detectedVariant = resumeState?.workflowVariant ?? defaultWorkflow.classifyVariant?.(baseMessage);
|
|
16481
|
+
const defaultMilestones = detectedVariant === "external" ? EXTERNAL_MILESTONE_NAMES : DEFAULT_MILESTONE_NAMES;
|
|
16482
|
+
const workflowMilestones = playbookMilestones ?? (resolvedWorkflow ? resolvedWorkflow.phases.map((p) => p.name) : defaultMilestones);
|
|
16113
16483
|
let taskMessage = baseMessage;
|
|
16114
16484
|
if (sandboxPrompt && !resolvedWorkflow) taskMessage = `${taskMessage}
|
|
16115
16485
|
|
|
16116
16486
|
${sandboxPrompt}`;
|
|
16117
|
-
if (recipe?.rules) taskMessage = `${taskMessage}
|
|
16118
|
-
|
|
16119
|
-
${recipe.rules}`;
|
|
16120
16487
|
if (rulesContext) taskMessage = `${taskMessage}
|
|
16121
16488
|
|
|
16122
16489
|
${rulesContext}`;
|
|
16123
16490
|
const currentPhase = resumeState?.workflowPhase;
|
|
16124
|
-
const resolvedModel = resolveModelForPhase(currentPhase,
|
|
16491
|
+
const resolvedModel = resolveModelForPhase(currentPhase, {
|
|
16125
16492
|
planningModel: options.planningModel,
|
|
16126
16493
|
executionModel: options.executionModel,
|
|
16127
16494
|
defaultModel: options.model
|
|
16128
|
-
});
|
|
16495
|
+
}, playbookMilestoneModels);
|
|
16129
16496
|
if (resolvedModel) options.model = resolvedModel;
|
|
16130
16497
|
let localTools = buildLocalTools(client, parsedSandbox, options, {
|
|
16131
16498
|
taskName,
|
|
@@ -16186,12 +16553,12 @@ ${rulesContext}`;
|
|
|
16186
16553
|
}
|
|
16187
16554
|
}
|
|
16188
16555
|
let toolsEnabled = true;
|
|
16189
|
-
const
|
|
16190
|
-
const
|
|
16556
|
+
const checkpointHasConfigChanges = (result) => Boolean(result.model) || result.tools === true || result.sandbox !== void 0;
|
|
16557
|
+
const rebuildCheckpointTools = () => buildLocalTools(client, parsedSandbox, options, {
|
|
16191
16558
|
taskName,
|
|
16192
16559
|
stateDir: options.stateDir
|
|
16193
16560
|
});
|
|
16194
|
-
const
|
|
16561
|
+
const applyCheckpointConfig = (result) => {
|
|
16195
16562
|
if (result.model) {
|
|
16196
16563
|
options.model = result.model;
|
|
16197
16564
|
}
|
|
@@ -16205,12 +16572,12 @@ ${rulesContext}`;
|
|
|
16205
16572
|
}
|
|
16206
16573
|
}
|
|
16207
16574
|
if (toolsEnabled) {
|
|
16208
|
-
localTools =
|
|
16575
|
+
localTools = rebuildCheckpointTools();
|
|
16209
16576
|
}
|
|
16210
16577
|
}
|
|
16211
16578
|
if (result.tools) {
|
|
16212
16579
|
toolsEnabled = !toolsEnabled;
|
|
16213
|
-
localTools = toolsEnabled ?
|
|
16580
|
+
localTools = toolsEnabled ? rebuildCheckpointTools() : void 0;
|
|
16214
16581
|
}
|
|
16215
16582
|
};
|
|
16216
16583
|
const loopDetector = createLoopDetector();
|
|
@@ -16235,8 +16602,10 @@ ${rulesContext}`;
|
|
|
16235
16602
|
stateFilePath: filePath,
|
|
16236
16603
|
debug: options.debug,
|
|
16237
16604
|
plainText: options.plainText ?? false,
|
|
16238
|
-
|
|
16239
|
-
|
|
16605
|
+
noCheckpoint: options.noCheckpoint ?? false,
|
|
16606
|
+
checkpointTimeout: parseInt(options.checkpointTimeout || "10", 10),
|
|
16607
|
+
workflowMilestones: workflowMilestones.length > 0 ? workflowMilestones : void 0,
|
|
16608
|
+
currentMilestone: detectedVariant === "external" && resumeState?.workflowPhase === "research" && resumeLoadedState?.planWritten ? "report" : resumeState?.workflowPhase ?? workflowMilestones[0],
|
|
16240
16609
|
dashboardUrl: marathonDashboardBaseUrl,
|
|
16241
16610
|
billingUrl: `${marathonDashboardBaseUrl}/settings/billing`,
|
|
16242
16611
|
onSaveState: (payload) => {
|
|
@@ -16268,6 +16637,7 @@ Saving state... done. Session saved to ${filePath}`);
|
|
|
16268
16637
|
},
|
|
16269
16638
|
streamRef
|
|
16270
16639
|
};
|
|
16640
|
+
setMarathonTitle();
|
|
16271
16641
|
if (useStartupShell) {
|
|
16272
16642
|
setStartupStatus("preparing marathon");
|
|
16273
16643
|
rerenderUi?.(
|
|
@@ -16286,7 +16656,7 @@ Saving state... done. Session saved to ${filePath}`);
|
|
|
16286
16656
|
waitForUiExit = renderedApp.waitUntilExit;
|
|
16287
16657
|
unmountUi = renderedApp.unmount;
|
|
16288
16658
|
}
|
|
16289
|
-
await new Promise((
|
|
16659
|
+
await new Promise((resolve7) => setTimeout(resolve7, 0));
|
|
16290
16660
|
const streamActions = streamRef.current;
|
|
16291
16661
|
if (!streamActions) {
|
|
16292
16662
|
exitAltScreen();
|
|
@@ -16300,14 +16670,14 @@ Saving state... done. Session saved to ${filePath}`);
|
|
|
16300
16670
|
if (persistedSessionSnapshots.length > 0) {
|
|
16301
16671
|
streamActions.hydrateSessionSnapshots(persistedSessionSnapshots);
|
|
16302
16672
|
}
|
|
16303
|
-
if (resumeLoadedState &&
|
|
16304
|
-
const recap =
|
|
16673
|
+
if (resumeLoadedState && shouldPromptResumeCheckpoint) {
|
|
16674
|
+
const recap = buildResumeCheckpointRecap(resumeLoadedState, persistedSessionSnapshots);
|
|
16305
16675
|
if (resumeHistoryWarning) {
|
|
16306
16676
|
recap.historyWarning = resumeHistoryWarning;
|
|
16307
16677
|
}
|
|
16308
|
-
const
|
|
16309
|
-
|
|
16310
|
-
switch (
|
|
16678
|
+
const checkpointResult = await streamActions.requestCheckpoint(recap);
|
|
16679
|
+
applyCheckpointConfig(checkpointResult);
|
|
16680
|
+
switch (checkpointResult.action) {
|
|
16311
16681
|
case "stop":
|
|
16312
16682
|
streamActions.exit();
|
|
16313
16683
|
await waitForUiExit?.();
|
|
@@ -16316,9 +16686,9 @@ Saving state... done. Session saved to ${filePath}`);
|
|
|
16316
16686
|
console.log(chalk16.gray(`Resume cancelled. Local state unchanged at ${filePath}`));
|
|
16317
16687
|
return;
|
|
16318
16688
|
case "steer":
|
|
16319
|
-
if (
|
|
16320
|
-
taskMessage =
|
|
16321
|
-
continuationMessage =
|
|
16689
|
+
if (checkpointResult.message) {
|
|
16690
|
+
taskMessage = checkpointResult.message;
|
|
16691
|
+
continuationMessage = checkpointResult.message;
|
|
16322
16692
|
useCompact = false;
|
|
16323
16693
|
}
|
|
16324
16694
|
break;
|
|
@@ -16364,12 +16734,12 @@ Saving state... done. Session saved to ${filePath}`);
|
|
|
16364
16734
|
const currentRemainingCost = remainingCost ? remainingCost - accumulatedCost : void 0;
|
|
16365
16735
|
const phaseModel = resolveModelForPhase(
|
|
16366
16736
|
resumeState?.workflowPhase,
|
|
16367
|
-
recipe,
|
|
16368
16737
|
{
|
|
16369
16738
|
planningModel: options.planningModel,
|
|
16370
16739
|
executionModel: options.executionModel,
|
|
16371
16740
|
defaultModel: options.model
|
|
16372
|
-
}
|
|
16741
|
+
},
|
|
16742
|
+
playbookMilestoneModels
|
|
16373
16743
|
);
|
|
16374
16744
|
const effectiveModelForContext = phaseModel || options.model || agentConfigModel || defaultConfiguredModel;
|
|
16375
16745
|
const compactStrategy = resolveCompactStrategyForModel(effectiveModelForContext);
|
|
@@ -16389,7 +16759,7 @@ Saving state... done. Session saved to ${filePath}`);
|
|
|
16389
16759
|
trackProgress: options.track ? taskName : void 0,
|
|
16390
16760
|
...resolvedToolIds.length > 0 ? { toolIds: resolvedToolIds } : {},
|
|
16391
16761
|
...resolvedWorkflow ? { workflow: resolvedWorkflow } : {},
|
|
16392
|
-
// Continuation context (only set on resume or after
|
|
16762
|
+
// Continuation context (only set on resume or after checkpoint restart)
|
|
16393
16763
|
...previousMessages.length > 0 ? {
|
|
16394
16764
|
previousMessages,
|
|
16395
16765
|
continuationMessage,
|
|
@@ -16409,7 +16779,7 @@ Saving state... done. Session saved to ${filePath}`);
|
|
|
16409
16779
|
};
|
|
16410
16780
|
if (event.phase === "start") {
|
|
16411
16781
|
currentActions.startContextCompaction(absoluteEvent);
|
|
16412
|
-
await new Promise((
|
|
16782
|
+
await new Promise((resolve7) => setTimeout(resolve7, 0));
|
|
16413
16783
|
return;
|
|
16414
16784
|
}
|
|
16415
16785
|
currentActions.finishContextCompaction(absoluteEvent);
|
|
@@ -16466,18 +16836,24 @@ Saving state... done. Session saved to ${filePath}`);
|
|
|
16466
16836
|
resumeState = extractRunTaskResumeState(adjustedState);
|
|
16467
16837
|
lastSessionMessages = state.messages ?? [];
|
|
16468
16838
|
saveState(filePath, adjustedState, { stripSnapshotEvents: !!eventLogWriter });
|
|
16839
|
+
if (resumeState?.workflowPhase) {
|
|
16840
|
+
const displayMilestone = detectedVariant === "external" && resumeState.workflowPhase === "research" && adjustedState.planWritten ? "report" : resumeState.workflowPhase;
|
|
16841
|
+
streamRef.current?.updateMilestone(displayMilestone);
|
|
16842
|
+
}
|
|
16843
|
+
let modelChangedOnPhaseTransition = false;
|
|
16469
16844
|
if (resumeState?.workflowPhase) {
|
|
16470
16845
|
const newPhaseModel = resolveModelForPhase(
|
|
16471
16846
|
resumeState.workflowPhase,
|
|
16472
|
-
recipe,
|
|
16473
16847
|
{
|
|
16474
16848
|
planningModel: options.planningModel,
|
|
16475
16849
|
executionModel: options.executionModel,
|
|
16476
16850
|
defaultModel: options.model
|
|
16477
|
-
}
|
|
16851
|
+
},
|
|
16852
|
+
playbookMilestoneModels
|
|
16478
16853
|
);
|
|
16479
16854
|
if (newPhaseModel && newPhaseModel !== options.model) {
|
|
16480
16855
|
options.model = newPhaseModel;
|
|
16856
|
+
modelChangedOnPhaseTransition = true;
|
|
16481
16857
|
}
|
|
16482
16858
|
}
|
|
16483
16859
|
if (state.recentActionKeys && state.recentActionKeys.length > 0) {
|
|
@@ -16485,7 +16861,11 @@ Saving state... done. Session saved to ${filePath}`);
|
|
|
16485
16861
|
loopDetector.recordAction(key);
|
|
16486
16862
|
}
|
|
16487
16863
|
}
|
|
16488
|
-
if (
|
|
16864
|
+
if (modelChangedOnPhaseTransition) {
|
|
16865
|
+
shouldContinue = true;
|
|
16866
|
+
return false;
|
|
16867
|
+
}
|
|
16868
|
+
if (options.noCheckpoint) return;
|
|
16489
16869
|
if (state.status !== "running") return;
|
|
16490
16870
|
if (!currentActions) return;
|
|
16491
16871
|
const recap = {
|
|
@@ -16496,15 +16876,15 @@ Saving state... done. Session saved to ${filePath}`);
|
|
|
16496
16876
|
cost: state.totalCost,
|
|
16497
16877
|
outputPreview: adjustedState.lastOutput.slice(0, 100)
|
|
16498
16878
|
};
|
|
16499
|
-
const
|
|
16500
|
-
|
|
16501
|
-
switch (
|
|
16879
|
+
const checkpointResult = await currentActions.requestCheckpoint(recap);
|
|
16880
|
+
applyCheckpointConfig(checkpointResult);
|
|
16881
|
+
switch (checkpointResult.action) {
|
|
16502
16882
|
case "stop":
|
|
16503
16883
|
return false;
|
|
16504
16884
|
// Tells SDK to stop the loop
|
|
16505
16885
|
case "steer":
|
|
16506
|
-
if (
|
|
16507
|
-
taskMessage =
|
|
16886
|
+
if (checkpointResult.message) {
|
|
16887
|
+
taskMessage = checkpointResult.message;
|
|
16508
16888
|
shouldContinue = true;
|
|
16509
16889
|
return false;
|
|
16510
16890
|
}
|
|
@@ -16577,6 +16957,9 @@ Saving state... done. Session saved to ${filePath}`);
|
|
|
16577
16957
|
};
|
|
16578
16958
|
}
|
|
16579
16959
|
lastResult = result2;
|
|
16960
|
+
if (result2.status === "complete") {
|
|
16961
|
+
streamRef.current?.updateMilestone("complete");
|
|
16962
|
+
}
|
|
16580
16963
|
if (shouldContinue) {
|
|
16581
16964
|
previousMessages = lastSessionMessages;
|
|
16582
16965
|
continuationMessage = taskMessage;
|
|
@@ -16584,7 +16967,7 @@ Saving state... done. Session saved to ${filePath}`);
|
|
|
16584
16967
|
resumeState = extractRunTaskResumeState(lastKnownState);
|
|
16585
16968
|
}
|
|
16586
16969
|
if (result2.status === "complete" || result2.status === "budget_exceeded" || result2.status === "max_sessions") {
|
|
16587
|
-
if (options.
|
|
16970
|
+
if (options.noCheckpoint) break;
|
|
16588
16971
|
const currentActions = streamRef.current;
|
|
16589
16972
|
if (!currentActions) break;
|
|
16590
16973
|
let exitTerminal = false;
|
|
@@ -16599,13 +16982,13 @@ Saving state... done. Session saved to ${filePath}`);
|
|
|
16599
16982
|
cost: accumulatedCost,
|
|
16600
16983
|
outputPreview: terminalPreview.slice(0, 100)
|
|
16601
16984
|
};
|
|
16602
|
-
const
|
|
16603
|
-
|
|
16604
|
-
switch (
|
|
16985
|
+
const checkpointResult = await currentActions.requestCheckpoint(recap, true);
|
|
16986
|
+
applyCheckpointConfig(checkpointResult);
|
|
16987
|
+
switch (checkpointResult.action) {
|
|
16605
16988
|
case "steer":
|
|
16606
|
-
if (
|
|
16989
|
+
if (checkpointResult.message) {
|
|
16607
16990
|
currentActions.resetForNewSession();
|
|
16608
|
-
taskMessage =
|
|
16991
|
+
taskMessage = checkpointResult.message;
|
|
16609
16992
|
previousMessages = lastSessionMessages;
|
|
16610
16993
|
continuationMessage = taskMessage;
|
|
16611
16994
|
useCompact = false;
|
|
@@ -16615,7 +16998,7 @@ Saving state... done. Session saved to ${filePath}`);
|
|
|
16615
16998
|
exitTerminal = true;
|
|
16616
16999
|
break;
|
|
16617
17000
|
case "continue":
|
|
16618
|
-
if (
|
|
17001
|
+
if (checkpointHasConfigChanges(checkpointResult)) {
|
|
16619
17002
|
break;
|
|
16620
17003
|
}
|
|
16621
17004
|
currentActions.exit();
|
|
@@ -16860,7 +17243,7 @@ function detectDeployWorkflow(message, sandboxProvider, resumeState) {
|
|
|
16860
17243
|
return void 0;
|
|
16861
17244
|
}
|
|
16862
17245
|
function applyTaskOptions(cmd) {
|
|
16863
|
-
return cmd.argument("<agent>", "Agent ID or name").option("-g, --goal <text>", "Goal message for the agent").option("--max-sessions <n>", "Maximum sessions", "50").option("--max-cost <n>", "Budget in USD").option("--model <modelId>", "Model ID to use (overrides agent config)").option("--name <name>", "Task name (used for state file, defaults to agent name)").option("--session <name>", "Resume a specific session by name").option("--state-dir <path>", "Directory for state files (default: ~/.runtype/projects/<hash>/marathons/)").option("--resume [message]", "Resume from existing local state, optionally with a new message").option("--fresh", "Start a new run and ignore any existing local state for this task").option("--compact", "Force compact-summary resume mode instead of replaying full history").option("--compact-strategy <strategy>", "Compaction strategy: auto (default), provider_native, or summary_fallback").option("--compact-threshold <value>", "Auto-compact when estimated context crosses this threshold (default: 80% fallback, 90% native; accepts percent like 90% or absolute token count like 120000)").option("--compact-instructions <text>", "Extra instructions for what a compact summary must preserve").option("--no-auto-compact", "Disable automatic context-aware history compaction").option("--track", "Sync progress to a Runtype record (visible in dashboard)").option("--debug", "Show debug output from each session").option("--json", "Output final result as JSON").option("--sandbox <provider>", "Enable sandbox code execution tool (cloudflare-worker, quickjs, or daytona)").option("--no-local-tools", "Disable built-in local tool execution (read_file, write_file, list_directory)").option("-t, --tools <tools...>", "Enable built-in tools (e.g., exa, firecrawl, dalle, openai_web_search, anthropic_web_search)").option("--plain-text", "Disable markdown rendering in output").option("--no-
|
|
17246
|
+
return cmd.argument("<agent>", "Agent ID or name").option("-g, --goal <text>", "Goal message for the agent").option("--max-sessions <n>", "Maximum sessions", "50").option("--max-cost <n>", "Budget in USD").option("--model <modelId>", "Model ID to use (overrides agent config)").option("--name <name>", "Task name (used for state file, defaults to agent name)").option("--session <name>", "Resume a specific session by name").option("--state-dir <path>", "Directory for state files (default: ~/.runtype/projects/<hash>/marathons/)").option("--resume [message]", "Resume from existing local state, optionally with a new message").option("--fresh", "Start a new run and ignore any existing local state for this task").option("--compact", "Force compact-summary resume mode instead of replaying full history").option("--compact-strategy <strategy>", "Compaction strategy: auto (default), provider_native, or summary_fallback").option("--compact-threshold <value>", "Auto-compact when estimated context crosses this threshold (default: 80% fallback, 90% native; accepts percent like 90% or absolute token count like 120000)").option("--compact-instructions <text>", "Extra instructions for what a compact summary must preserve").option("--no-auto-compact", "Disable automatic context-aware history compaction").option("--track", "Sync progress to a Runtype record (visible in dashboard)").option("--debug", "Show debug output from each session").option("--json", "Output final result as JSON").option("--sandbox <provider>", "Enable sandbox code execution tool (cloudflare-worker, quickjs, or daytona)").option("--no-local-tools", "Disable built-in local tool execution (read_file, write_file, list_directory)").option("-t, --tools <tools...>", "Enable built-in tools (e.g., exa, firecrawl, dalle, openai_web_search, anthropic_web_search)").option("--plain-text", "Disable markdown rendering in output").option("--no-checkpoint", "Run all iterations without checkpoint pauses (fully autonomous)").option("--checkpoint-timeout <seconds>", "Auto-continue timeout in seconds (default: 10)", "10").option("--planning-model <modelId>", "Model to use during research/planning phases").option("--execution-model <modelId>", "Model to use during execution phase").option("--playbook <name>", "Load a playbook from .runtype/marathons/playbooks/").option("--offload-threshold <chars>", 'Offload tool outputs larger than this to files (default: 100000; use "off" or "0" to disable guardrails)').option("--tool-context <mode>", "Tool result storage: hot-tail (default), observation-mask, or full-inline").option("--tool-window <window>", 'Compaction window: "session" (default) or a number for last-N tool results (e.g. 10)').option("--runner-char <char>", "Custom runner emoji (default: \u{1F3C3})").option("--finish-char <char>", "Custom finish line emoji (default: \u{1F3C1})").option("--no-runner", "Hide the runner emoji from the header border").option("--no-finish", "Hide the finish line emoji from the header border").action(taskAction);
|
|
16864
17247
|
}
|
|
16865
17248
|
var taskCommand = applyTaskOptions(
|
|
16866
17249
|
new Command10("task").description("Run a multi-session agent task")
|
|
@@ -17783,14 +18166,14 @@ import React13 from "react";
|
|
|
17783
18166
|
import { render as render13 } from "ink";
|
|
17784
18167
|
import { useState as useState27, useEffect as useEffect25 } from "react";
|
|
17785
18168
|
import { Text as Text30 } from "ink";
|
|
17786
|
-
import { readFileSync as
|
|
18169
|
+
import { readFileSync as readFileSync13 } from "fs";
|
|
17787
18170
|
var evalCommand = new Command14("eval").description("Manage evaluations");
|
|
17788
18171
|
evalCommand.command("submit").description("Submit an eval batch").requiredOption("-f, --flow <id>", "Flow ID to evaluate").requiredOption("-r, --records <file>", "JSON file with record IDs").option("-n, --name <name>", "Eval batch name").option("--json", "Output as JSON").option("--tty", "Force TTY mode").option("--no-tty", "Force non-TTY mode").action(async (options) => {
|
|
17789
18172
|
const apiKey = await ensureAuth();
|
|
17790
18173
|
if (!apiKey) return;
|
|
17791
18174
|
let recordIds;
|
|
17792
18175
|
try {
|
|
17793
|
-
const content =
|
|
18176
|
+
const content = readFileSync13(options.records, "utf-8");
|
|
17794
18177
|
const parsed = JSON.parse(content);
|
|
17795
18178
|
recordIds = Array.isArray(parsed) ? parsed : parsed.recordIds || parsed.records || [];
|
|
17796
18179
|
} catch (error) {
|
|
@@ -18348,13 +18731,13 @@ apiKeysCommand.command("delete <id>").description("Delete an API key").option("-
|
|
|
18348
18731
|
await waitUntilExit2();
|
|
18349
18732
|
return;
|
|
18350
18733
|
}
|
|
18351
|
-
const confirmed = await new Promise((
|
|
18734
|
+
const confirmed = await new Promise((resolve7) => {
|
|
18352
18735
|
const { unmount } = render14(
|
|
18353
18736
|
React14.createElement(ConfirmPrompt, {
|
|
18354
18737
|
message: `Delete API key ${id}?`,
|
|
18355
18738
|
defaultValue: false,
|
|
18356
18739
|
onConfirm: (result) => {
|
|
18357
|
-
|
|
18740
|
+
resolve7(result);
|
|
18358
18741
|
unmount();
|
|
18359
18742
|
}
|
|
18360
18743
|
})
|
|
@@ -18459,8 +18842,8 @@ apiKeysCommand.command("analytics").description("Show API key usage analytics").
|
|
|
18459
18842
|
const client = new ApiClient(apiKey);
|
|
18460
18843
|
if (!isTTY(options) || options.json) {
|
|
18461
18844
|
try {
|
|
18462
|
-
const
|
|
18463
|
-
const data = await client.get(
|
|
18845
|
+
const path13 = options.key ? `/api-keys/${options.key}/analytics` : "/api-keys/analytics";
|
|
18846
|
+
const data = await client.get(path13);
|
|
18464
18847
|
printJson(data);
|
|
18465
18848
|
} catch (error) {
|
|
18466
18849
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
@@ -18477,8 +18860,8 @@ apiKeysCommand.command("analytics").description("Show API key usage analytics").
|
|
|
18477
18860
|
useEffect26(() => {
|
|
18478
18861
|
const run = async () => {
|
|
18479
18862
|
try {
|
|
18480
|
-
const
|
|
18481
|
-
const data = await client.get(
|
|
18863
|
+
const path13 = options.key ? `/api-keys/${options.key}/analytics` : "/api-keys/analytics";
|
|
18864
|
+
const data = await client.get(path13);
|
|
18482
18865
|
printJson(data);
|
|
18483
18866
|
setSuccess(true);
|
|
18484
18867
|
setLoading(false);
|
|
@@ -19264,6 +19647,7 @@ function maybeNotifyAboutCliUpdate(args, options = {}) {
|
|
|
19264
19647
|
|
|
19265
19648
|
// src/index.ts
|
|
19266
19649
|
loadEnv();
|
|
19650
|
+
setCliTitle();
|
|
19267
19651
|
var program = new Command19();
|
|
19268
19652
|
program.name("runtype").description("CLI for Runtype AI Platform").version(getCliVersion()).option("-v, --verbose", "Enable verbose output").option("--api-url <url>", "Override API URL").option("--json", "Output in JSON format");
|
|
19269
19653
|
program.addCommand(initCommand);
|