@garuda-agent/garuda 0.18.0 → 0.18.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +106 -0
- package/README.md +3 -2
- package/dist/{acpCommand-IUZPLPLI.js → acpCommand-JAYNMIMP.js} +17 -14
- package/dist/advise-HDKJGNBL.js +195 -0
- package/dist/brief-RWKESOPT.js +91 -0
- package/dist/buildCheck-HB46NWLX.js +19 -0
- package/dist/buildInfo-K73FFI5S.js +8 -0
- package/dist/chunk-2OYTNNUJ.js +216 -0
- package/dist/{chunk-OQ26W5L4.js → chunk-34WBDQBL.js} +134 -77
- package/dist/chunk-4QRTTRVK.js +88 -0
- package/dist/{chunk-NHWHG3SW.js → chunk-5UDYQ5MK.js} +354 -59
- package/dist/chunk-CWVXOSAA.js +894 -0
- package/dist/{chunk-FARS4R67.js → chunk-DQSCCE77.js} +18 -1
- package/dist/chunk-DUYLVGPY.js +821 -0
- package/dist/{chunk-Q4P3W657.js → chunk-GKU62MHQ.js} +10 -1124
- package/dist/chunk-H7LIBGZT.js +9 -0
- package/dist/{chunk-FOPBOB7W.js → chunk-IKPGHM54.js} +6 -4
- package/dist/chunk-IYGJWX65.js +9 -0
- package/dist/{chunk-65NUEOI7.js → chunk-JMH5W5DG.js} +1 -44
- package/dist/chunk-L55VUSX3.js +54 -0
- package/dist/{chunk-B4SJY7KT.js → chunk-LMKGSYJC.js} +77 -8
- package/dist/{chunk-23FXBNBB.js → chunk-MNE7HHX2.js} +2 -1
- package/dist/chunk-NH72AELP.js +48 -0
- package/dist/{chunk-UKIE4AAM.js → chunk-NLS7GMF7.js} +11 -105
- package/dist/{chunk-2FIV2VZP.js → chunk-QLBCM2YQ.js} +2 -2
- package/dist/{chunk-6XHON3Q6.js → chunk-QXTHEFKP.js} +3 -3
- package/dist/{chunk-4BVCYCQT.js → chunk-R7RCW4BQ.js} +9 -7
- package/dist/chunk-TLA2PDGM.js +156 -0
- package/dist/{chunk-5B5HDTUR.js → chunk-TWQ7V2L6.js} +2 -2
- package/dist/chunk-ULAJPMY7.js +107 -0
- package/dist/chunk-VISKX36R.js +306 -0
- package/dist/{chunk-55CFEEIN.js → chunk-WK5NE6RY.js} +2 -2
- package/dist/chunk-Y62J7PTD.js +90 -0
- package/dist/chunk-YAQ6QLKB.js +40 -0
- package/dist/{chunk-7TH3NHCQ.js → chunk-ZKT4P2PC.js} +2 -2
- package/dist/cli/index.js +252 -61
- package/dist/{create-W6BV75QX.js → create-OACSGJ37.js} +5 -5
- package/dist/{evalCommand-SKJQ6CW2.js → evalCommand-BLJJ4G76.js} +43 -33
- package/dist/{evalTune-CZRCPSZ3.js → evalTune-W53KAD4V.js} +25 -18
- package/dist/{export-SJ3DUP6W.js → export-E677HIQS.js} +27 -4
- package/dist/exportHtml-BMV73YRO.js +21 -0
- package/dist/{inkChat-WYYAFZXD.js → inkChat-EVLYDC3K.js} +258 -42
- package/dist/{install-TKWN5AYH.js → install-4ST5BNRG.js} +3 -3
- package/dist/{jobCommand-2ODQLHB3.js → jobCommand-ILOTYOX3.js} +8 -7
- package/dist/{launchd-3A3ONEW5.js → launchd-QG6R5RAK.js} +4 -4
- package/dist/{lspCommand-ZZ6R4PA2.js → lspCommand-X4FTTONR.js} +3 -3
- package/dist/{manager-TCYTA5XU.js → manager-L25IUXHW.js} +3 -3
- package/dist/{nightCommand-WJU6VZA6.js → nightCommand-XPWT6CQZ.js} +8 -7
- package/dist/receiptView-YFDHV253.js +19 -0
- package/dist/{remove-42WQNVPX.js → remove-STX5UO7X.js} +3 -3
- package/dist/{run-PTMRQCIU.js → run-W4TK52WT.js} +5 -5
- package/dist/{server-VEYIJHEU.js → server-ASM73QVY.js} +3 -3
- package/dist/{setupCommand-YMF6I3MD.js → setupCommand-OSOMFHDQ.js} +9 -8
- package/dist/tour-CEVMAC5S.js +18 -0
- package/dist/tune-VX2WQTHS.js +52 -0
- package/dist/uiState-YFJQ43D7.js +16 -0
- package/package.json +1 -1
- package/dist/chunk-4JSUUDFQ.js +0 -118
- package/dist/chunk-C57GHLKP.js +0 -9
- package/dist/chunk-DOCDCQVM.js +0 -484
- package/dist/tune-YVI2KWQF.js +0 -31
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
mergedModels,
|
|
4
|
-
writeFileAtomic
|
|
5
|
-
} from "./chunk-65NUEOI7.js";
|
|
6
2
|
import {
|
|
7
3
|
loadLspConfig
|
|
8
4
|
} from "./chunk-G2AX7MGS.js";
|
|
5
|
+
import {
|
|
6
|
+
gateProjectSettings
|
|
7
|
+
} from "./chunk-ULAJPMY7.js";
|
|
8
|
+
import {
|
|
9
|
+
mergedModels
|
|
10
|
+
} from "./chunk-JMH5W5DG.js";
|
|
11
|
+
import {
|
|
12
|
+
writeFileAtomic
|
|
13
|
+
} from "./chunk-NH72AELP.js";
|
|
14
|
+
import {
|
|
15
|
+
ReceiptCollector
|
|
16
|
+
} from "./chunk-4QRTTRVK.js";
|
|
9
17
|
import {
|
|
10
18
|
hasServerBlocks,
|
|
11
19
|
serverCallText,
|
|
@@ -29,17 +37,17 @@ import {
|
|
|
29
37
|
compacted,
|
|
30
38
|
createSession,
|
|
31
39
|
emptyUndoState,
|
|
32
|
-
gateProjectSettings,
|
|
33
40
|
isCostIncomplete,
|
|
34
41
|
newSessionId,
|
|
35
42
|
newUserMessage,
|
|
43
|
+
pendingChildTokens,
|
|
36
44
|
popPoint,
|
|
37
45
|
pushPoint,
|
|
38
46
|
redoPoint,
|
|
39
47
|
redoTurn,
|
|
40
48
|
settleChildDebits,
|
|
41
49
|
undoTurn
|
|
42
|
-
} from "./chunk-
|
|
50
|
+
} from "./chunk-NLS7GMF7.js";
|
|
43
51
|
import {
|
|
44
52
|
REDACTED,
|
|
45
53
|
Redactor,
|
|
@@ -57,10 +65,10 @@ import {
|
|
|
57
65
|
} from "./chunk-B25VL4RU.js";
|
|
58
66
|
import {
|
|
59
67
|
BUILTIN_COMMANDS
|
|
60
|
-
} from "./chunk-
|
|
68
|
+
} from "./chunk-MNE7HHX2.js";
|
|
61
69
|
import {
|
|
62
70
|
VERSION
|
|
63
|
-
} from "./chunk-
|
|
71
|
+
} from "./chunk-IYGJWX65.js";
|
|
64
72
|
import {
|
|
65
73
|
TrustStore
|
|
66
74
|
} from "./chunk-5DEWP3YX.js";
|
|
@@ -91,8 +99,9 @@ import {
|
|
|
91
99
|
expandAllowlist,
|
|
92
100
|
hostAllowed,
|
|
93
101
|
isSensitive,
|
|
94
|
-
loadSettings
|
|
95
|
-
|
|
102
|
+
loadSettings,
|
|
103
|
+
presetFor
|
|
104
|
+
} from "./chunk-LMKGSYJC.js";
|
|
96
105
|
import {
|
|
97
106
|
EFFORTS,
|
|
98
107
|
ZERO_USAGE,
|
|
@@ -1502,7 +1511,12 @@ ${z.prettifyError(parsed.error)}`,
|
|
|
1502
1511
|
await logRun(outcome.isError);
|
|
1503
1512
|
const final = context.hooks === void 0 ? outcome : await context.hooks.after(hookCall, outcome, context.signal);
|
|
1504
1513
|
const subagent = tool.report?.(output);
|
|
1505
|
-
|
|
1514
|
+
const command = tool.commandFacts?.(output);
|
|
1515
|
+
return {
|
|
1516
|
+
...final,
|
|
1517
|
+
...subagent === void 0 ? {} : { subagent },
|
|
1518
|
+
...command === void 0 ? {} : { command }
|
|
1519
|
+
};
|
|
1506
1520
|
} catch (error) {
|
|
1507
1521
|
if (context.signal.aborted) throw error;
|
|
1508
1522
|
if (error instanceof AuditWriteError) {
|
|
@@ -1795,7 +1809,8 @@ function createBashTool({
|
|
|
1795
1809
|
}
|
|
1796
1810
|
const result = await executor.run(run, policy, { signal });
|
|
1797
1811
|
const hints = commandHints(run, stripped);
|
|
1798
|
-
const
|
|
1812
|
+
const blocks = sandboxed ? permissions.takeNetworkBlocks?.() ?? [] : [];
|
|
1813
|
+
const network = sandboxed ? networkHint(blocks, strict) : void 0;
|
|
1799
1814
|
if (network !== void 0) hints.push(network);
|
|
1800
1815
|
const blocked = sandboxed && network === void 0 ? sandboxHint(result, policy.proxy !== void 0, strict) : void 0;
|
|
1801
1816
|
if (blocked !== void 0) hints.push(blocked);
|
|
@@ -1810,7 +1825,21 @@ function createBashTool({
|
|
|
1810
1825
|
`Garuda could not check for processes that left the command's process group (${result.reapProblem}). Such a process may still run, inside the sandbox.`
|
|
1811
1826
|
);
|
|
1812
1827
|
}
|
|
1813
|
-
return {
|
|
1828
|
+
return {
|
|
1829
|
+
...result,
|
|
1830
|
+
hints,
|
|
1831
|
+
sandboxed,
|
|
1832
|
+
blockedHosts: [...new Set(blocks.map((b) => b.host))]
|
|
1833
|
+
};
|
|
1834
|
+
},
|
|
1835
|
+
commandFacts(result) {
|
|
1836
|
+
if ("daemon" in result && result.daemon !== void 0) return void 0;
|
|
1837
|
+
return {
|
|
1838
|
+
exitCode: result.exitCode,
|
|
1839
|
+
timedOut: result.timedOut,
|
|
1840
|
+
sandboxed: result.sandboxed ?? false,
|
|
1841
|
+
blockedHosts: result.blockedHosts ?? []
|
|
1842
|
+
};
|
|
1814
1843
|
},
|
|
1815
1844
|
toText(result) {
|
|
1816
1845
|
const lines = [];
|
|
@@ -6725,7 +6754,8 @@ function rebuildState(records) {
|
|
|
6725
6754
|
unreportedTokens: 0,
|
|
6726
6755
|
childDebits: /* @__PURE__ */ new Map(),
|
|
6727
6756
|
start: void 0,
|
|
6728
|
-
undo: emptyUndoState()
|
|
6757
|
+
undo: emptyUndoState(),
|
|
6758
|
+
turns: 0
|
|
6729
6759
|
};
|
|
6730
6760
|
const addCost2 = (cost) => {
|
|
6731
6761
|
state.costUsd = state.costUsd === void 0 || cost === void 0 ? void 0 : state.costUsd + cost;
|
|
@@ -6743,10 +6773,15 @@ function rebuildState(records) {
|
|
|
6743
6773
|
case "user":
|
|
6744
6774
|
state.messages.push(record.message);
|
|
6745
6775
|
newUserMessage(state.undo);
|
|
6776
|
+
state.turns++;
|
|
6746
6777
|
break;
|
|
6747
|
-
case "snapshot":
|
|
6778
|
+
case "snapshot": {
|
|
6748
6779
|
pushPoint(state.undo, record.tree, record.messages, record.prompt);
|
|
6780
|
+
const point = state.undo.points.at(-1);
|
|
6781
|
+
const at = record.at ?? Date.parse(record.t);
|
|
6782
|
+
if (point !== void 0 && !Number.isNaN(at)) point.at = at;
|
|
6749
6783
|
break;
|
|
6784
|
+
}
|
|
6750
6785
|
case "undo":
|
|
6751
6786
|
popPoint(state.undo, state.messages, record.after);
|
|
6752
6787
|
break;
|
|
@@ -6792,6 +6827,23 @@ function rebuildState(records) {
|
|
|
6792
6827
|
case "thinking":
|
|
6793
6828
|
state.thinking = record.choice;
|
|
6794
6829
|
break;
|
|
6830
|
+
case "fork":
|
|
6831
|
+
state.messages = structuredClone(record.messages);
|
|
6832
|
+
state.turns = record.from.turn - 1;
|
|
6833
|
+
break;
|
|
6834
|
+
case "receipt": {
|
|
6835
|
+
const point = state.undo.points.at(-1);
|
|
6836
|
+
if (point !== void 0 && record.receipt.files !== void 0) {
|
|
6837
|
+
point.changedFiles = record.receipt.files.length;
|
|
6838
|
+
}
|
|
6839
|
+
if (point !== void 0 && record.receipt.costUsd !== void 0) {
|
|
6840
|
+
point.costUsd = record.receipt.costUsd;
|
|
6841
|
+
}
|
|
6842
|
+
if (record.receipt.tests?.total !== void 0) {
|
|
6843
|
+
state.lastTestTotal = record.receipt.tests.total;
|
|
6844
|
+
}
|
|
6845
|
+
break;
|
|
6846
|
+
}
|
|
6795
6847
|
case "unreported":
|
|
6796
6848
|
state.unreportedTokens += record.tokens;
|
|
6797
6849
|
state.costIncomplete = true;
|
|
@@ -6835,6 +6887,8 @@ async function resumeSession(options) {
|
|
|
6835
6887
|
session.childDebits = state.childDebits;
|
|
6836
6888
|
session.undo = state.undo;
|
|
6837
6889
|
if (state.thinking !== void 0) session.thinking = state.thinking;
|
|
6890
|
+
session.turns = state.turns;
|
|
6891
|
+
if (state.lastTestTotal !== void 0) session.lastTestTotal = state.lastTestTotal;
|
|
6838
6892
|
journal.write({ type: "resume", sessionId: id2, ...options.start });
|
|
6839
6893
|
closeOpenToolCalls(session);
|
|
6840
6894
|
return session;
|
|
@@ -6863,6 +6917,34 @@ function repairServerBlocks(message) {
|
|
|
6863
6917
|
return { ...message, content: withoutServerBlocks(message.content) };
|
|
6864
6918
|
}
|
|
6865
6919
|
|
|
6920
|
+
// src/session/list.ts
|
|
6921
|
+
var TITLE_CHARS = 60;
|
|
6922
|
+
function summariseSession(id2, updated, records) {
|
|
6923
|
+
const prompts = records.filter((r) => r.type === "user");
|
|
6924
|
+
const first = prompts[0]?.message.content.find((b) => b.type === "text");
|
|
6925
|
+
const named = records.findLast((r) => r.type === "title");
|
|
6926
|
+
const line = named?.type === "title" ? named.title : (first?.type === "text" ? first.text : "").trim().split("\n")[0] ?? "";
|
|
6927
|
+
const state = rebuildState(records);
|
|
6928
|
+
return {
|
|
6929
|
+
id: id2,
|
|
6930
|
+
updated,
|
|
6931
|
+
title: line.length <= TITLE_CHARS ? line : `${line.slice(0, TITLE_CHARS - 1)}\u2026`,
|
|
6932
|
+
turns: prompts.length,
|
|
6933
|
+
model: state.start?.model,
|
|
6934
|
+
costUsd: state.costUsd,
|
|
6935
|
+
// A child debit with no report: its USD cost is not known (Codex review of 1370184).
|
|
6936
|
+
costIncomplete: isCostIncomplete(state)
|
|
6937
|
+
};
|
|
6938
|
+
}
|
|
6939
|
+
var MAX_TITLE_CHARS = TITLE_CHARS;
|
|
6940
|
+
function cleanTitle(text) {
|
|
6941
|
+
const one = [...text].map((c) => {
|
|
6942
|
+
const code = c.codePointAt(0) ?? 0;
|
|
6943
|
+
return code < 32 || code >= 127 && code < 160 ? " " : c;
|
|
6944
|
+
}).join("").replace(/\s+/g, " ").trim();
|
|
6945
|
+
return one.length <= MAX_TITLE_CHARS ? one : `${one.slice(0, MAX_TITLE_CHARS - 1)}\u2026`;
|
|
6946
|
+
}
|
|
6947
|
+
|
|
6866
6948
|
// src/skills/load.ts
|
|
6867
6949
|
import { createHash as createHash7 } from "crypto";
|
|
6868
6950
|
import { lstat as lstat4, readdir as readdir5, readFile as readFile12, stat as stat7 } from "fs/promises";
|
|
@@ -8136,6 +8218,10 @@ function networkNote(entries, strict = false) {
|
|
|
8136
8218
|
strict ? "For any other host, also run the command in the sandbox: Garuda asks the user for that host, and the result says if it was blocked." : "For any other host, also run the command in the sandbox: Garuda asks the user for that host, and the result says if it was blocked. Use outside_sandbox only when the sandbox blocks something else (a write outside the project)."
|
|
8137
8219
|
].join("\n");
|
|
8138
8220
|
}
|
|
8221
|
+
function networkKeepHint(host2) {
|
|
8222
|
+
const entry = presetFor(host2) ?? host2;
|
|
8223
|
+
return `${host2} works for commands in this session. To keep it for this project, add "${entry}" to "network.allow" in .garuda/settings.json.`;
|
|
8224
|
+
}
|
|
8139
8225
|
function networkConsent(entries, isolation, changed) {
|
|
8140
8226
|
const lines = [
|
|
8141
8227
|
changed ? "The network allowlist in .garuda/settings.json changed since you allowed it." : "This project's .garuda/settings.json opens the network for commands in the sandbox.",
|
|
@@ -8167,34 +8253,6 @@ function nodeBinary(execPath = process.execPath, path = process.env.PATH ?? "")
|
|
|
8167
8253
|
return void 0;
|
|
8168
8254
|
}
|
|
8169
8255
|
|
|
8170
|
-
// src/session/list.ts
|
|
8171
|
-
var TITLE_CHARS = 60;
|
|
8172
|
-
function summariseSession(id2, updated, records) {
|
|
8173
|
-
const prompts = records.filter((r) => r.type === "user");
|
|
8174
|
-
const first = prompts[0]?.message.content.find((b) => b.type === "text");
|
|
8175
|
-
const named = records.findLast((r) => r.type === "title");
|
|
8176
|
-
const line = named?.type === "title" ? named.title : (first?.type === "text" ? first.text : "").trim().split("\n")[0] ?? "";
|
|
8177
|
-
const state = rebuildState(records);
|
|
8178
|
-
return {
|
|
8179
|
-
id: id2,
|
|
8180
|
-
updated,
|
|
8181
|
-
title: line.length <= TITLE_CHARS ? line : `${line.slice(0, TITLE_CHARS - 1)}\u2026`,
|
|
8182
|
-
turns: prompts.length,
|
|
8183
|
-
model: state.start?.model,
|
|
8184
|
-
costUsd: state.costUsd,
|
|
8185
|
-
// A child debit with no report: its USD cost is not known (Codex review of 1370184).
|
|
8186
|
-
costIncomplete: isCostIncomplete(state)
|
|
8187
|
-
};
|
|
8188
|
-
}
|
|
8189
|
-
var MAX_TITLE_CHARS = TITLE_CHARS;
|
|
8190
|
-
function cleanTitle(text) {
|
|
8191
|
-
const one = [...text].map((c) => {
|
|
8192
|
-
const code = c.codePointAt(0) ?? 0;
|
|
8193
|
-
return code < 32 || code >= 127 && code < 160 ? " " : c;
|
|
8194
|
-
}).join("").replace(/\s+/g, " ").trim();
|
|
8195
|
-
return one.length <= MAX_TITLE_CHARS ? one : `${one.slice(0, MAX_TITLE_CHARS - 1)}\u2026`;
|
|
8196
|
-
}
|
|
8197
|
-
|
|
8198
8256
|
// src/app/sessionManager.ts
|
|
8199
8257
|
async function findSession(ref, store) {
|
|
8200
8258
|
const all = await store.list();
|
|
@@ -8307,6 +8365,34 @@ function filesText(changes) {
|
|
|
8307
8365
|
if (changes.length === 0) return "no file changes";
|
|
8308
8366
|
return `${changes.length} file${changes.length === 1 ? "" : "s"} changed`;
|
|
8309
8367
|
}
|
|
8368
|
+
function rewindQuestion(kind, turn, prompt, count2, changes, isolation) {
|
|
8369
|
+
const lines = [`Back to the start of turn ${turn}: "${prompt}"`];
|
|
8370
|
+
if (changes.length === 0) lines.push("No file changes.");
|
|
8371
|
+
else {
|
|
8372
|
+
lines.push(`Files (${changes.length}):`);
|
|
8373
|
+
for (const c of changes.slice(0, MAX_CHANGE_LINES))
|
|
8374
|
+
lines.push(` ${MARKS[c.status]} ${cleanText(c.path).replace(/\n/g, " ")}`);
|
|
8375
|
+
if (changes.length > MAX_CHANGE_LINES) {
|
|
8376
|
+
lines.push(` \u2026 and ${changes.length - MAX_CHANGE_LINES} more.`);
|
|
8377
|
+
}
|
|
8378
|
+
lines.push(" (+ comes back, - is removed, ~ changes)");
|
|
8379
|
+
}
|
|
8380
|
+
lines.push("Files that .gitignore covers (for example build output) are not in undo.");
|
|
8381
|
+
lines.push(
|
|
8382
|
+
kind === "rewind" ? `This takes back ${count2} turn${count2 === 1 ? "" : "s"}: their file changes and their messages. /redo brings them back one at a time.` : "A new session starts with the conversation up to this turn. This session stays as it is: /sessions opens it again.",
|
|
8383
|
+
"Changes that you made to these files since then go back too."
|
|
8384
|
+
);
|
|
8385
|
+
return {
|
|
8386
|
+
tool: kind === "rewind" ? "undo" : "fork",
|
|
8387
|
+
target: { kind: "input", json: "{}" },
|
|
8388
|
+
preview: lines.join("\n"),
|
|
8389
|
+
isolation,
|
|
8390
|
+
title: kind === "rewind" ? `Rewind to turn ${turn}?` : `Fork a new session from turn ${turn}?`,
|
|
8391
|
+
question: kind === "rewind" ? "Rewind?" : "Fork?",
|
|
8392
|
+
choices: ["once", "deny"],
|
|
8393
|
+
labels: { once: kind === "rewind" ? "Yes, rewind" : "Yes, fork", deny: "No" }
|
|
8394
|
+
};
|
|
8395
|
+
}
|
|
8310
8396
|
|
|
8311
8397
|
// src/app/undoCoordinator.ts
|
|
8312
8398
|
var UndoCoordinator = class {
|
|
@@ -8361,6 +8447,81 @@ var UndoCoordinator = class {
|
|
|
8361
8447
|
return `The ${kind} failed, and no file changed: ${error.message}`;
|
|
8362
8448
|
}
|
|
8363
8449
|
}
|
|
8450
|
+
/**
|
|
8451
|
+
* /rewind <n> (UX U6): back to the start of undo point `index` (0-based) in one step: one
|
|
8452
|
+
* question, one restore, then each later turn leaves the conversation as /undo does, newest
|
|
8453
|
+
* first. Each redo entry keeps the files after its turn, so /redo brings them back in order.
|
|
8454
|
+
*/
|
|
8455
|
+
async rewind(session, index3, pendingNotes, signal) {
|
|
8456
|
+
const store = this.snapshots;
|
|
8457
|
+
if (store === void 0) return "Undo is off for this session, so /rewind cannot go back.";
|
|
8458
|
+
const points = session?.undo.points ?? [];
|
|
8459
|
+
const target = points[index3];
|
|
8460
|
+
if (session === void 0 || target === void 0) {
|
|
8461
|
+
return `There is no turn ${index3 + 1}. Type /rewind for the list.`;
|
|
8462
|
+
}
|
|
8463
|
+
try {
|
|
8464
|
+
const now = await store.take(signal);
|
|
8465
|
+
const changes = await store.changes(now, target.tree, signal);
|
|
8466
|
+
const count2 = points.length - index3;
|
|
8467
|
+
const choice = await this.approver.ask(
|
|
8468
|
+
rewindQuestion("rewind", index3 + 1, target.prompt, count2, changes, this.isolation),
|
|
8469
|
+
signal
|
|
8470
|
+
);
|
|
8471
|
+
if (choice === "deny") return "Nothing changed.";
|
|
8472
|
+
const afters = points.slice(index3).map((_, i) => points[index3 + i + 1]?.tree ?? now);
|
|
8473
|
+
await store.restore(now, target.tree, signal);
|
|
8474
|
+
let compacted2 = false;
|
|
8475
|
+
for (let i = afters.length - 1; i >= 0; i--) {
|
|
8476
|
+
const point = undoTurn(session, afters[i]);
|
|
8477
|
+
if (point !== void 0 && !point.conversation) compacted2 = true;
|
|
8478
|
+
}
|
|
8479
|
+
if (compacted2) {
|
|
8480
|
+
pendingNotes.push(
|
|
8481
|
+
`The user rewound to before the turn "${target.prompt}": the file changes of that turn and the later ones are gone. Read files again before you edit them.`
|
|
8482
|
+
);
|
|
8483
|
+
}
|
|
8484
|
+
return `Rewound to the start of turn ${index3 + 1} ("${target.prompt}"): ${count2} turn${count2 === 1 ? "" : "s"} taken back, ${filesText(changes)}. /redo brings them back one at a time.`;
|
|
8485
|
+
} catch (error) {
|
|
8486
|
+
if (!(error instanceof SnapshotError)) throw error;
|
|
8487
|
+
return `The rewind failed, and no file changed: ${error.message}`;
|
|
8488
|
+
}
|
|
8489
|
+
}
|
|
8490
|
+
/**
|
|
8491
|
+
* The files for a fork (UX U6): back to undo point `index`, after one question. The caller
|
|
8492
|
+
* starts the new session. Returns undefined when the user said no.
|
|
8493
|
+
*/
|
|
8494
|
+
async restoreForFork(session, index3, signal) {
|
|
8495
|
+
const store = this.snapshots;
|
|
8496
|
+
if (store === void 0)
|
|
8497
|
+
return {
|
|
8498
|
+
ok: false,
|
|
8499
|
+
text: "Undo is off for this session, so a fork cannot restore the files."
|
|
8500
|
+
};
|
|
8501
|
+
const target = session.undo.points[index3];
|
|
8502
|
+
if (target === void 0)
|
|
8503
|
+
return { ok: false, text: `There is no turn ${index3 + 1}. Type /rewind for the list.` };
|
|
8504
|
+
if (!target.conversation) {
|
|
8505
|
+
return {
|
|
8506
|
+
ok: false,
|
|
8507
|
+
text: `Turn ${index3 + 1} is before a compaction: its messages are no longer separate, so it cannot start a fork.`
|
|
8508
|
+
};
|
|
8509
|
+
}
|
|
8510
|
+
try {
|
|
8511
|
+
const now = await store.take(signal);
|
|
8512
|
+
const changes = await store.changes(now, target.tree, signal);
|
|
8513
|
+
const choice = await this.approver.ask(
|
|
8514
|
+
rewindQuestion("fork", index3 + 1, target.prompt, 0, changes, this.isolation),
|
|
8515
|
+
signal
|
|
8516
|
+
);
|
|
8517
|
+
if (choice === "deny") return { ok: false, text: "Nothing changed." };
|
|
8518
|
+
await store.restore(now, target.tree, signal);
|
|
8519
|
+
return { ok: true };
|
|
8520
|
+
} catch (error) {
|
|
8521
|
+
if (!(error instanceof SnapshotError)) throw error;
|
|
8522
|
+
return { ok: false, text: `The fork failed, and no file changed: ${error.message}` };
|
|
8523
|
+
}
|
|
8524
|
+
}
|
|
8364
8525
|
async undoNow(session, pendingNotes, signal) {
|
|
8365
8526
|
const store = this.snapshots;
|
|
8366
8527
|
if (store === void 0) return "Undo is off for this session.";
|
|
@@ -8534,6 +8695,8 @@ var Runtime = class _Runtime {
|
|
|
8534
8695
|
startModel;
|
|
8535
8696
|
/** The prompt of the turn that runs or ran last (0.9: the note after a stopped turn). */
|
|
8536
8697
|
lastPrompt;
|
|
8698
|
+
/** The receipt of the last turn (UX U1); undefined before a turn ends, or after a failed one. */
|
|
8699
|
+
receipt;
|
|
8537
8700
|
/** LSP diagnostics after edits are on (0.4). */
|
|
8538
8701
|
lspEnabled;
|
|
8539
8702
|
lspOptions;
|
|
@@ -8718,6 +8881,10 @@ var Runtime = class _Runtime {
|
|
|
8718
8881
|
);
|
|
8719
8882
|
}
|
|
8720
8883
|
}
|
|
8884
|
+
/** The chat's look (0.18.1); the CLI applies it. */
|
|
8885
|
+
get uiSettings() {
|
|
8886
|
+
return this.settings.ui;
|
|
8887
|
+
}
|
|
8721
8888
|
/** The notification settings for the chat (0.6); the CLI applies them. */
|
|
8722
8889
|
get notificationSettings() {
|
|
8723
8890
|
return this.settings.notifications;
|
|
@@ -9352,6 +9519,8 @@ ${neutralizeTags(output)}`
|
|
|
9352
9519
|
}
|
|
9353
9520
|
/** Run one turn: the user's prompt, then the loop until it stops. */
|
|
9354
9521
|
async runTurn(prompt, signal) {
|
|
9522
|
+
const started = Date.now();
|
|
9523
|
+
this.receipt = void 0;
|
|
9355
9524
|
this.lastPrompt = prompt;
|
|
9356
9525
|
this.turnSignal = signal;
|
|
9357
9526
|
await this.startHooks(signal);
|
|
@@ -9382,6 +9551,22 @@ ${neutralizeTags(output)}`
|
|
|
9382
9551
|
];
|
|
9383
9552
|
if (lines.length > 0) this.onEvent?.({ type: "notice", text: lines.join("\n") });
|
|
9384
9553
|
closeOpenToolCalls(session);
|
|
9554
|
+
session.turns = (session.turns ?? 0) + 1;
|
|
9555
|
+
const before = {
|
|
9556
|
+
cost: session.costUsd,
|
|
9557
|
+
unreported: session.unreportedTokens,
|
|
9558
|
+
pending: pendingChildTokens(session),
|
|
9559
|
+
incomplete: session.costIncomplete
|
|
9560
|
+
};
|
|
9561
|
+
const collector = new ReceiptCollector(detectTestCommand(this.root, this.profiles));
|
|
9562
|
+
let changesFiles = false;
|
|
9563
|
+
const onEvent = (event) => {
|
|
9564
|
+
collector.onEvent(event);
|
|
9565
|
+
if (event.type === "tool_call" && !this.tools.isReadOnly(event.call.name)) {
|
|
9566
|
+
changesFiles = true;
|
|
9567
|
+
}
|
|
9568
|
+
this.onEvent?.(event);
|
|
9569
|
+
};
|
|
9385
9570
|
addUserMessage(
|
|
9386
9571
|
session,
|
|
9387
9572
|
prompt,
|
|
@@ -9407,17 +9592,84 @@ ${neutralizeTags(output)}`
|
|
|
9407
9592
|
...this.outputTokens(),
|
|
9408
9593
|
contextWindow: this.limits.contextWindow,
|
|
9409
9594
|
...this.price === void 0 ? {} : { price: this.price },
|
|
9410
|
-
|
|
9595
|
+
onEvent,
|
|
9411
9596
|
...this.settings.thinking?.keepBlocks === false ? { keepThinking: false } : {},
|
|
9412
9597
|
...this.thinkingParams === void 0 ? {} : { thinking: this.thinkingParams },
|
|
9413
9598
|
signal
|
|
9414
9599
|
});
|
|
9600
|
+
this.receipt = await this.makeReceipt(session, result, collector, {
|
|
9601
|
+
...before,
|
|
9602
|
+
started,
|
|
9603
|
+
changesFiles,
|
|
9604
|
+
signal
|
|
9605
|
+
});
|
|
9415
9606
|
if (this.turnMode === "plan" && result.stopReason === "done") {
|
|
9416
9607
|
const plan2 = lastAssistantText(session.messages);
|
|
9417
9608
|
if (plan2 !== "") this.plan = { request: prompt, plan: plan2, sessionId: session.id };
|
|
9418
9609
|
}
|
|
9419
9610
|
return result;
|
|
9420
9611
|
}
|
|
9612
|
+
/** The receipt of the last turn (UX U1), or undefined. */
|
|
9613
|
+
get lastReceipt() {
|
|
9614
|
+
return this.receipt;
|
|
9615
|
+
}
|
|
9616
|
+
/**
|
|
9617
|
+
* The turn's receipt (UX U1; docs/lld/ux.md): the files from a snapshot at the end of the turn
|
|
9618
|
+
* (only when a tool that can change files ran), the commands' facts, and the costs.
|
|
9619
|
+
*/
|
|
9620
|
+
async makeReceipt(session, result, collector, before) {
|
|
9621
|
+
const store = this.undoCoordinator.store;
|
|
9622
|
+
const point = session.undo.points.at(-1);
|
|
9623
|
+
let files;
|
|
9624
|
+
if (store !== void 0 && point !== void 0) {
|
|
9625
|
+
files = [];
|
|
9626
|
+
if (before.changesFiles) {
|
|
9627
|
+
try {
|
|
9628
|
+
const end = await store.take(before.signal);
|
|
9629
|
+
files = (await store.stats(point.tree, end, before.signal)).map((f) => ({
|
|
9630
|
+
path: f.path,
|
|
9631
|
+
...f.added === void 0 ? {} : { added: f.added, removed: f.removed ?? 0 }
|
|
9632
|
+
}));
|
|
9633
|
+
} catch (error) {
|
|
9634
|
+
if (before.signal.aborted) throw error;
|
|
9635
|
+
files = void 0;
|
|
9636
|
+
}
|
|
9637
|
+
}
|
|
9638
|
+
if (files !== void 0) point.changedFiles = files.length;
|
|
9639
|
+
if (session.costUsd !== void 0 && before.cost !== void 0) {
|
|
9640
|
+
point.costUsd = session.costUsd - before.cost;
|
|
9641
|
+
}
|
|
9642
|
+
}
|
|
9643
|
+
const costIncomplete = session.unreportedTokens > before.unreported || pendingChildTokens(session) > before.pending || session.costIncomplete && !before.incomplete;
|
|
9644
|
+
const tests = collector.tests;
|
|
9645
|
+
if (tests !== void 0 && session.lastTestTotal !== void 0) {
|
|
9646
|
+
tests.previousTotal = session.lastTestTotal;
|
|
9647
|
+
}
|
|
9648
|
+
if (tests?.total !== void 0) session.lastTestTotal = tests.total;
|
|
9649
|
+
const receipt = {
|
|
9650
|
+
turn: session.turns ?? 1,
|
|
9651
|
+
stopReason: result.stopReason,
|
|
9652
|
+
steps: result.steps,
|
|
9653
|
+
durationMs: Date.now() - before.started,
|
|
9654
|
+
...session.costUsd === void 0 || before.cost === void 0 ? {} : { costUsd: session.costUsd - before.cost },
|
|
9655
|
+
...costIncomplete ? { costIncomplete: true } : {},
|
|
9656
|
+
...files === void 0 ? {} : { files },
|
|
9657
|
+
...tests === void 0 ? {} : { tests },
|
|
9658
|
+
commands: {
|
|
9659
|
+
sandboxed: collector.sandboxed,
|
|
9660
|
+
outside: collector.outside,
|
|
9661
|
+
blockedHosts: [...collector.blockedHosts]
|
|
9662
|
+
},
|
|
9663
|
+
contextPercent: Math.round(session.contextTokens / this.limits.contextWindow * 100),
|
|
9664
|
+
...session.costUsd === void 0 ? {} : { sessionCostUsd: session.costUsd },
|
|
9665
|
+
...isCostIncomplete(session) ? { sessionCostIncomplete: true } : {},
|
|
9666
|
+
...store === void 0 ? {} : {
|
|
9667
|
+
keptChanges: session.undo.points.filter((p) => (p.changedFiles ?? 0) > 0).length
|
|
9668
|
+
}
|
|
9669
|
+
};
|
|
9670
|
+
session.journal?.write({ type: "receipt", receipt });
|
|
9671
|
+
return receipt;
|
|
9672
|
+
}
|
|
9421
9673
|
/** The last finished plan of this process, for /schedule (0.7). */
|
|
9422
9674
|
get lastPlan() {
|
|
9423
9675
|
return this.plan;
|
|
@@ -9434,7 +9686,7 @@ ${neutralizeTags(output)}`
|
|
|
9434
9686
|
text: "There is no finished plan in this chat. Make one in plan mode (/plan), then type /schedule."
|
|
9435
9687
|
};
|
|
9436
9688
|
}
|
|
9437
|
-
const { createJob } = await import("./create-
|
|
9689
|
+
const { createJob } = await import("./create-OACSGJ37.js");
|
|
9438
9690
|
const created = await createJob({
|
|
9439
9691
|
root: this.root,
|
|
9440
9692
|
executor: this.executor,
|
|
@@ -9517,7 +9769,7 @@ ${result.stderr.text}`)
|
|
|
9517
9769
|
*/
|
|
9518
9770
|
async cancelJob(id2, agent = {}) {
|
|
9519
9771
|
const { loadJob, saveJob } = await import("./job-7JOI4YIQ.js");
|
|
9520
|
-
const { defaultAgentEnv, nightSpec, removeAgent, removeSpec } = await import("./launchd-
|
|
9772
|
+
const { defaultAgentEnv, nightSpec, removeAgent, removeSpec } = await import("./launchd-QG6R5RAK.js");
|
|
9521
9773
|
if (id2 === "night") {
|
|
9522
9774
|
const removed = await removeSpec(
|
|
9523
9775
|
agent.executor ?? this.executor,
|
|
@@ -9549,8 +9801,8 @@ ${result.stderr.text}`)
|
|
|
9549
9801
|
*/
|
|
9550
9802
|
async deleteJob(id2, signal, agent = {}) {
|
|
9551
9803
|
const { loadJob } = await import("./job-7JOI4YIQ.js");
|
|
9552
|
-
const { defaultAgentEnv, removeAgent } = await import("./launchd-
|
|
9553
|
-
const { jobLeftovers, removeJob } = await import("./remove-
|
|
9804
|
+
const { defaultAgentEnv, removeAgent } = await import("./launchd-QG6R5RAK.js");
|
|
9805
|
+
const { jobLeftovers, removeJob } = await import("./remove-STX5UO7X.js");
|
|
9554
9806
|
let job;
|
|
9555
9807
|
try {
|
|
9556
9808
|
job = await loadJob(this.root, id2);
|
|
@@ -9722,7 +9974,7 @@ ${result.stderr.text}`)
|
|
|
9722
9974
|
* The files it writes are new only; the turn's own writes go through the normal approvals.
|
|
9723
9975
|
*/
|
|
9724
9976
|
async init(signal) {
|
|
9725
|
-
const { runInit } = await import("./run-
|
|
9977
|
+
const { runInit } = await import("./run-W4TK52WT.js");
|
|
9726
9978
|
const result = await runInit({
|
|
9727
9979
|
root: this.root,
|
|
9728
9980
|
home: this.commandsHome,
|
|
@@ -9757,6 +10009,8 @@ ${result.stderr.text}`)
|
|
|
9757
10009
|
await this.staged?.remove().catch(() => {
|
|
9758
10010
|
});
|
|
9759
10011
|
}
|
|
10012
|
+
/** UX U2: the proxy runs with no host on the list, only to ask for the hosts that commands need. */
|
|
10013
|
+
watchingNetwork = false;
|
|
9760
10014
|
/** The network allowlist in effect (0.13): the settings entries, or [] when the proxy is off. */
|
|
9761
10015
|
networkAllowlist() {
|
|
9762
10016
|
return this.networkProxy === void 0 ? [] : [...this.settings.network?.allow ?? []];
|
|
@@ -9768,9 +10022,11 @@ ${result.stderr.text}`)
|
|
|
9768
10022
|
*/
|
|
9769
10023
|
async startNetwork(signal) {
|
|
9770
10024
|
const entries = this.settings.network?.allow ?? [];
|
|
9771
|
-
if (
|
|
10025
|
+
if (this.executor.isolation !== "os") return;
|
|
10026
|
+
const watch = entries.length === 0 && this.networkOptions.watch === true;
|
|
10027
|
+
if (entries.length === 0 && !watch) return;
|
|
9772
10028
|
this.networkStarted ??= (async () => {
|
|
9773
|
-
if (this.networkOptions.approved !== true) {
|
|
10029
|
+
if (!watch && this.networkOptions.approved !== true) {
|
|
9774
10030
|
const trust = await TrustStore.open(this.networkOptions.home ?? homedir5());
|
|
9775
10031
|
const hash = networkHash(entries);
|
|
9776
10032
|
const known = trust.networkHash(this.root);
|
|
@@ -9790,9 +10046,11 @@ ${result.stderr.text}`)
|
|
|
9790
10046
|
if (this.executor.name === "bwrap") {
|
|
9791
10047
|
bridge = nodeBinary();
|
|
9792
10048
|
if (bridge === void 0) {
|
|
9793
|
-
|
|
9794
|
-
|
|
9795
|
-
|
|
10049
|
+
if (!watch) {
|
|
10050
|
+
this.onNotice?.(
|
|
10051
|
+
"Network for commands: off. On Linux the allowlist needs node on the PATH (for the bridge into the sandbox)."
|
|
10052
|
+
);
|
|
10053
|
+
}
|
|
9796
10054
|
return;
|
|
9797
10055
|
}
|
|
9798
10056
|
}
|
|
@@ -9807,6 +10065,10 @@ ${result.stderr.text}`)
|
|
|
9807
10065
|
policy: { ...started, ...bridge === void 0 ? {} : { bridge } },
|
|
9808
10066
|
takeBlocked: () => proxy.takeBlocked()
|
|
9809
10067
|
});
|
|
10068
|
+
if (watch) {
|
|
10069
|
+
this.watchingNetwork = true;
|
|
10070
|
+
return;
|
|
10071
|
+
}
|
|
9810
10072
|
this.onNotice?.(
|
|
9811
10073
|
`Network for commands: ${entries.join(", ")}, through Garuda's proxy. Other hosts ask.`
|
|
9812
10074
|
);
|
|
@@ -9840,12 +10102,15 @@ ${result.stderr.text}`)
|
|
|
9840
10102
|
readOnly: false,
|
|
9841
10103
|
info: {
|
|
9842
10104
|
target: { kind: "url", url: `https://${host2}`, host: host2 },
|
|
9843
|
-
preview: `A command in the sandbox wants to reach ${host2}:${port} through Garuda's proxy. The host is not on the network allowlist ("network.allow" in .garuda/settings.json).`,
|
|
10105
|
+
preview: this.watchingNetwork ? `A command in the sandbox wants to reach ${host2}:${port}. Commands have no network unless you allow a host; Garuda's proxy sees only the host name.` : `A command in the sandbox wants to reach ${host2}:${port} through Garuda's proxy. The host is not on the network allowlist ("network.allow" in .garuda/settings.json).`,
|
|
9844
10106
|
title: `Let a command reach ${host2}?`
|
|
9845
10107
|
}
|
|
9846
10108
|
},
|
|
9847
10109
|
this.turnSignal ?? new AbortController().signal
|
|
9848
10110
|
);
|
|
10111
|
+
if (decision.allowed && decision.remembered === true) {
|
|
10112
|
+
this.onNotice?.(networkKeepHint(host2));
|
|
10113
|
+
}
|
|
9849
10114
|
return decision.allowed ? { allowed: true } : { allowed: false, reason: decision.reason.replace(/\.$/, "") };
|
|
9850
10115
|
}
|
|
9851
10116
|
get lspHome() {
|
|
@@ -9879,7 +10144,7 @@ ${result.stderr.text}`)
|
|
|
9879
10144
|
}
|
|
9880
10145
|
/** Install a language server into ~/.garuda/lsp (the user asked for it). */
|
|
9881
10146
|
async installLsp(language, signal) {
|
|
9882
|
-
const { installServer } = await import("./install-
|
|
10147
|
+
const { installServer } = await import("./install-4ST5BNRG.js");
|
|
9883
10148
|
const result = await installServer(language, {
|
|
9884
10149
|
executor: this.executor,
|
|
9885
10150
|
home: this.lspHome,
|
|
@@ -9890,7 +10155,7 @@ ${result.stderr.text}`)
|
|
|
9890
10155
|
}
|
|
9891
10156
|
/** autoInstall (~/.garuda/lsp.json): ask before a managed install. */
|
|
9892
10157
|
async askInstall(language, signal) {
|
|
9893
|
-
const { installCommand } = await import("./install-
|
|
10158
|
+
const { installCommand } = await import("./install-4ST5BNRG.js");
|
|
9894
10159
|
const { LANGUAGE_LABELS } = await import("./manager-4PMSXT47.js");
|
|
9895
10160
|
const { managedLabel, managedDir } = await import("./servers-6YDGWOZ6.js");
|
|
9896
10161
|
const dir = managedDir(language, this.lspHome);
|
|
@@ -9923,7 +10188,7 @@ ${result.stderr.text}`)
|
|
|
9923
10188
|
async startMcp(signal) {
|
|
9924
10189
|
if (this.mcpServers.length === 0) return;
|
|
9925
10190
|
this.mcpStarted ??= (async () => {
|
|
9926
|
-
const { McpManager } = await import("./manager-
|
|
10191
|
+
const { McpManager } = await import("./manager-L25IUXHW.js");
|
|
9927
10192
|
const { AuthStore } = await import("./oauth-W6OK6XXO.js");
|
|
9928
10193
|
const manager = new McpManager({
|
|
9929
10194
|
root: this.root,
|
|
@@ -10091,6 +10356,36 @@ ${result.stderr.text}`)
|
|
|
10091
10356
|
async undo(signal) {
|
|
10092
10357
|
return this.undoCoordinator.undo(this.current, this.pendingNotes, signal);
|
|
10093
10358
|
}
|
|
10359
|
+
/** The undo points of this session, oldest first (UX U6: the /rewind list). */
|
|
10360
|
+
get rewindPoints() {
|
|
10361
|
+
return this.current?.undo.points ?? [];
|
|
10362
|
+
}
|
|
10363
|
+
/** /rewind <n> (UX U6): back to the start of turn n (1-based in the list). */
|
|
10364
|
+
async rewind(turn, signal) {
|
|
10365
|
+
return this.undoCoordinator.rewind(this.current, turn - 1, this.pendingNotes, signal);
|
|
10366
|
+
}
|
|
10367
|
+
/**
|
|
10368
|
+
* /rewind fork <n> (UX U6): a new session with the conversation up to the start of turn n, and
|
|
10369
|
+
* the files as they were then. The old session stays on disk as it is.
|
|
10370
|
+
*/
|
|
10371
|
+
async fork(turn, signal) {
|
|
10372
|
+
const old = this.current;
|
|
10373
|
+
if (old === void 0) return "No turn has run in this session yet.";
|
|
10374
|
+
const restored = await this.undoCoordinator.restoreForFork(old, turn - 1, signal);
|
|
10375
|
+
if (!restored.ok) return restored.text;
|
|
10376
|
+
const point = old.undo.points[turn - 1];
|
|
10377
|
+
const messages = structuredClone(old.messages.slice(0, point.messages));
|
|
10378
|
+
this.newSession();
|
|
10379
|
+
const fresh = this.ensureSession();
|
|
10380
|
+
fresh.messages = messages;
|
|
10381
|
+
fresh.turns = turn - 1;
|
|
10382
|
+
fresh.journal?.write({ type: "fork", from: { sessionId: old.id, turn }, messages });
|
|
10383
|
+
fresh.journal?.write({
|
|
10384
|
+
type: "title",
|
|
10385
|
+
title: cleanTitle(`Fork of turn ${turn}: ${point.prompt}`)
|
|
10386
|
+
});
|
|
10387
|
+
return `New session ${fresh.id}: the conversation up to turn ${turn} ("${point.prompt}"), and the files as they were then. The old session ${old.id} stays as it was: /sessions opens it.`;
|
|
10388
|
+
}
|
|
10094
10389
|
/** /redo (0.4): bring back the last undone turn: its files and its messages. */
|
|
10095
10390
|
async redo(signal) {
|
|
10096
10391
|
return this.undoCoordinator.redo(this.current, this.pendingNotes, signal);
|
|
@@ -10192,4 +10487,4 @@ export {
|
|
|
10192
10487
|
modelFacts,
|
|
10193
10488
|
Runtime
|
|
10194
10489
|
};
|
|
10195
|
-
//# sourceMappingURL=chunk-
|
|
10490
|
+
//# sourceMappingURL=chunk-5UDYQ5MK.js.map
|