flavor-code 1.3.16 → 1.3.18
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 +1 -1
- package/README.zh-CN.md +1 -1
- package/dist/{app-6SEGTMMC.js → app-LKK5RBTO.js} +77 -6
- package/dist/{chunk-F2HMO5Q2.js → chunk-36UKDXPF.js} +9 -1
- package/dist/{chunk-LMFN2QEA.js → chunk-6LDYDQ3P.js} +1 -1
- package/dist/{chunk-S525EOFQ.js → chunk-PF457XCH.js} +89 -34
- package/dist/{claude-ink-ORUA7GWG.js → claude-ink-AUZBJ3BE.js} +1 -1
- package/dist/cli-main.js +4 -4
- package/dist/cli.js +7 -21
- package/dist/desktop/main.js +89 -34
- package/dist/desktop-renderer/assets/index-CxOMqdQf.js +154 -0
- package/dist/desktop-renderer/assets/{interactive-terminal-f1PNniPO.js → interactive-terminal-BK8GS4b3.js} +1 -1
- package/dist/desktop-renderer/index.html +1 -1
- package/dist/sdk/index.js +2 -2
- package/dist/session/tree.d.ts +3 -0
- package/dist/ui/transcript.d.ts +7 -0
- package/dist/utils/memory-restart.d.ts +3 -2
- package/package.json +2 -1
- package/dist/desktop-renderer/assets/index-C3JpD2_B.js +0 -154
package/README.md
CHANGED
|
@@ -271,7 +271,7 @@ Project runtime data lives under `.flavor/`:
|
|
|
271
271
|
├── sessions/ # Session timelines
|
|
272
272
|
│ └── *.events.jsonl # Crash-consistent execution journals
|
|
273
273
|
├── session-assets/ # Image attachments
|
|
274
|
-
├── session-trees/ #
|
|
274
|
+
├── session-trees/ # Explicit /checkpoint session branches
|
|
275
275
|
├── checkpoints/ # Workspace snapshots
|
|
276
276
|
├── memory/ # Long-term memory
|
|
277
277
|
├── traces/ # Optional execution traces
|
package/README.zh-CN.md
CHANGED
|
@@ -271,7 +271,7 @@ Skill 是带有 YAML 头信息的 `SKILL.md`,放在 `.flavor/skills/<name>/`
|
|
|
271
271
|
├── sessions/ # 会话时间线
|
|
272
272
|
│ └── *.events.jsonl # 崩溃一致执行事件日志
|
|
273
273
|
├── session-assets/ # 图片附件
|
|
274
|
-
├── session-trees/ #
|
|
274
|
+
├── session-trees/ # 手动 /checkpoint 创建的会话分支
|
|
275
275
|
├── checkpoints/ # 工作区快照
|
|
276
276
|
├── memory/ # 长期记忆
|
|
277
277
|
├── traces/ # 可选执行 trace
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
thinkingWindow,
|
|
19
19
|
transcriptReducer,
|
|
20
20
|
withTimeout
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-PF457XCH.js";
|
|
22
22
|
import "./chunk-CIVPKHF4.js";
|
|
23
23
|
import "./chunk-HJOCNKPN.js";
|
|
24
24
|
import {
|
|
@@ -30,14 +30,16 @@ import {
|
|
|
30
30
|
TerminalSizeContext,
|
|
31
31
|
TerminalWriteContext,
|
|
32
32
|
Text,
|
|
33
|
+
gt,
|
|
33
34
|
instances_default,
|
|
35
|
+
isValidVersion,
|
|
34
36
|
osc,
|
|
35
37
|
shiftAnchor,
|
|
36
38
|
stripAnsi,
|
|
37
39
|
useStdout,
|
|
38
40
|
use_app_default,
|
|
39
41
|
use_input_default
|
|
40
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-36UKDXPF.js";
|
|
41
43
|
import {
|
|
42
44
|
execFileNoThrow
|
|
43
45
|
} from "./chunk-RQTYHUMK.js";
|
|
@@ -1308,6 +1310,41 @@ function comparePaths(left, right) {
|
|
|
1308
1310
|
return left.localeCompare(right, "en");
|
|
1309
1311
|
}
|
|
1310
1312
|
|
|
1313
|
+
// src/update/check.ts
|
|
1314
|
+
var NPM_PACKAGE_NAME = "flavor-code";
|
|
1315
|
+
var REGISTRY_LATEST_URL = `https://registry.npmjs.org/${NPM_PACKAGE_NAME}/latest`;
|
|
1316
|
+
var DEFAULT_TIMEOUT_MS = 3e3;
|
|
1317
|
+
function findNewerVersion(current, latest) {
|
|
1318
|
+
if (!isValidVersion(current) || !isValidVersion(latest)) return void 0;
|
|
1319
|
+
return gt(latest, current) ? latest : void 0;
|
|
1320
|
+
}
|
|
1321
|
+
async function fetchLatestVersion(options = {}) {
|
|
1322
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
1323
|
+
const fetchImpl = options.fetchImpl ?? ((url, init) => fetch(url, init));
|
|
1324
|
+
let timer;
|
|
1325
|
+
const timeout = new Promise((resolve2) => {
|
|
1326
|
+
timer = setTimeout(() => resolve2(void 0), timeoutMs);
|
|
1327
|
+
timer.unref?.();
|
|
1328
|
+
});
|
|
1329
|
+
try {
|
|
1330
|
+
const response = await Promise.race([
|
|
1331
|
+
fetchImpl(REGISTRY_LATEST_URL, { signal: AbortSignal.timeout(timeoutMs) }),
|
|
1332
|
+
timeout
|
|
1333
|
+
]);
|
|
1334
|
+
if (response === void 0 || !response.ok) return void 0;
|
|
1335
|
+
const body = await Promise.race([response.json(), timeout]);
|
|
1336
|
+
return typeof body?.version === "string" ? body.version : void 0;
|
|
1337
|
+
} catch {
|
|
1338
|
+
return void 0;
|
|
1339
|
+
} finally {
|
|
1340
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
async function checkForUpdate(current, options = {}) {
|
|
1344
|
+
const latest = await fetchLatestVersion(options);
|
|
1345
|
+
return latest === void 0 ? void 0 : findNewerVersion(current, latest);
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1311
1348
|
// src/ui/welcome.tsx
|
|
1312
1349
|
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1313
1350
|
var WIDE_WELCOME_COLUMNS = 72;
|
|
@@ -1317,8 +1354,25 @@ var FLAVOR_WORDMARK = [
|
|
|
1317
1354
|
"\u251C\u2524 \u2502 \u251C\u2500\u2524\u2514\u2510\u250C\u2518\u2502 \u2502\u251C\u252C\u2518",
|
|
1318
1355
|
"\u2514 \u2534\u2500\u2518\u2534 \u2534 \u2514\u2518 \u2514\u2500\u2518\u2534\u2514\u2500"
|
|
1319
1356
|
].join("\n");
|
|
1320
|
-
function WelcomeCard({
|
|
1357
|
+
function WelcomeCard({
|
|
1358
|
+
model,
|
|
1359
|
+
serviceName,
|
|
1360
|
+
workspaceName,
|
|
1361
|
+
updateTo,
|
|
1362
|
+
columns
|
|
1363
|
+
}) {
|
|
1321
1364
|
const wide = Math.max(1, Math.floor(columns)) >= WIDE_WELCOME_COLUMNS;
|
|
1365
|
+
const updateHint = updateTo === void 0 ? null : /* @__PURE__ */ jsxs3(Text, { color: "yellow", wrap: "truncate-end", children: [
|
|
1366
|
+
"\u25B2 ",
|
|
1367
|
+
"Update available: v",
|
|
1368
|
+
packageVersion(),
|
|
1369
|
+
" ",
|
|
1370
|
+
"\u2192",
|
|
1371
|
+
" v",
|
|
1372
|
+
updateTo,
|
|
1373
|
+
" \xB7 npm i -g ",
|
|
1374
|
+
NPM_PACKAGE_NAME
|
|
1375
|
+
] });
|
|
1322
1376
|
return /* @__PURE__ */ jsx4(Box_default, { width: "100%", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: wide ? /* @__PURE__ */ jsxs3(Box_default, { width: "100%", flexDirection: "row", children: [
|
|
1323
1377
|
/* @__PURE__ */ jsxs3(
|
|
1324
1378
|
Box_default,
|
|
@@ -1365,7 +1419,8 @@ function WelcomeCard({ model, serviceName, workspaceName, columns }) {
|
|
|
1365
1419
|
/* @__PURE__ */ jsx4(Text, { color: "cyan", children: "/config" }),
|
|
1366
1420
|
" \xB7 ",
|
|
1367
1421
|
/* @__PURE__ */ jsx4(Text, { color: "cyan", children: "/tasks" })
|
|
1368
|
-
] })
|
|
1422
|
+
] }),
|
|
1423
|
+
updateHint
|
|
1369
1424
|
] })
|
|
1370
1425
|
] }) : /* @__PURE__ */ jsxs3(Box_default, { width: "100%", flexDirection: "column", children: [
|
|
1371
1426
|
/* @__PURE__ */ jsx4(Text, { bold: true, color: FLAVOR_ACCENT, children: "\u25C6 Flavor Code" }),
|
|
@@ -1382,7 +1437,8 @@ function WelcomeCard({ model, serviceName, workspaceName, columns }) {
|
|
|
1382
1437
|
" setup \xB7 ",
|
|
1383
1438
|
/* @__PURE__ */ jsx4(Text, { color: "cyan", children: "/help" }),
|
|
1384
1439
|
" commands"
|
|
1385
|
-
] })
|
|
1440
|
+
] }),
|
|
1441
|
+
updateHint
|
|
1386
1442
|
] }) });
|
|
1387
1443
|
}
|
|
1388
1444
|
|
|
@@ -1739,6 +1795,7 @@ function App({ workspace, home, resumeSession, instanceId, palAlias }) {
|
|
|
1739
1795
|
const [customQuestionActive, setCustomQuestionActive] = useState2(false);
|
|
1740
1796
|
const [columns, setColumns] = useState2(stdout?.columns ?? 80);
|
|
1741
1797
|
const [rows, setRows] = useState2(stdout?.rows ?? 24);
|
|
1798
|
+
const [updateTo, setUpdateTo] = useState2();
|
|
1742
1799
|
const [transcript, dispatch] = useReducer(transcriptReducer, void 0, createTranscriptState);
|
|
1743
1800
|
const scrollRef = useRef4(null);
|
|
1744
1801
|
const taskScrollRef = useRef4(null);
|
|
@@ -1911,6 +1968,15 @@ function App({ workspace, home, resumeSession, instanceId, palAlias }) {
|
|
|
1911
1968
|
};
|
|
1912
1969
|
}, [runtime, revision]);
|
|
1913
1970
|
useEffect3(() => installSigintHandler(process, interrupt), [interrupt]);
|
|
1971
|
+
useEffect3(() => {
|
|
1972
|
+
let disposed = false;
|
|
1973
|
+
void checkForUpdate(packageVersion()).then((version) => {
|
|
1974
|
+
if (version !== void 0 && !disposed) setUpdateTo(version);
|
|
1975
|
+
});
|
|
1976
|
+
return () => {
|
|
1977
|
+
disposed = true;
|
|
1978
|
+
};
|
|
1979
|
+
}, []);
|
|
1914
1980
|
useEffect3(() => {
|
|
1915
1981
|
if (runtime?.services.ideContext === void 0) {
|
|
1916
1982
|
setIdeContext(void 0);
|
|
@@ -2294,6 +2360,7 @@ function App({ workspace, home, resumeSession, instanceId, palAlias }) {
|
|
|
2294
2360
|
workspaceName: basename3(workspace),
|
|
2295
2361
|
completed: transcript.completed,
|
|
2296
2362
|
...transcript.active === void 0 ? {} : { active: transcript.active },
|
|
2363
|
+
...updateTo === void 0 ? {} : { updateTo },
|
|
2297
2364
|
columns,
|
|
2298
2365
|
rows
|
|
2299
2366
|
}
|
|
@@ -2307,6 +2374,7 @@ function App({ workspace, home, resumeSession, instanceId, palAlias }) {
|
|
|
2307
2374
|
workspaceName: basename3(workspace),
|
|
2308
2375
|
completed: transcript.completed,
|
|
2309
2376
|
...transcript.active === void 0 ? {} : { active: transcript.active },
|
|
2377
|
+
...updateTo === void 0 ? {} : { updateTo },
|
|
2310
2378
|
input,
|
|
2311
2379
|
pastedBlocks,
|
|
2312
2380
|
imageAttachments,
|
|
@@ -2340,6 +2408,7 @@ function StartingLayout({
|
|
|
2340
2408
|
workspaceName,
|
|
2341
2409
|
completed,
|
|
2342
2410
|
active,
|
|
2411
|
+
updateTo,
|
|
2343
2412
|
columns,
|
|
2344
2413
|
rows
|
|
2345
2414
|
}) {
|
|
@@ -2350,6 +2419,7 @@ function StartingLayout({
|
|
|
2350
2419
|
workspaceName,
|
|
2351
2420
|
completed,
|
|
2352
2421
|
...active === void 0 ? {} : { active },
|
|
2422
|
+
...updateTo === void 0 ? {} : { updateTo },
|
|
2353
2423
|
input: "",
|
|
2354
2424
|
promptCursor: 0,
|
|
2355
2425
|
columns,
|
|
@@ -2429,6 +2499,7 @@ function TerminalLayout({
|
|
|
2429
2499
|
model,
|
|
2430
2500
|
serviceName,
|
|
2431
2501
|
workspaceName,
|
|
2502
|
+
updateTo,
|
|
2432
2503
|
completed,
|
|
2433
2504
|
active,
|
|
2434
2505
|
input,
|
|
@@ -2481,7 +2552,7 @@ function TerminalLayout({
|
|
|
2481
2552
|
const promptMaxLines = Math.max(1, bottomMaxRows - fixedBottomRows);
|
|
2482
2553
|
return /* @__PURE__ */ jsxs4(Box_default, { height: rows, width: "100%", flexDirection: "column", overflow: "hidden", children: [
|
|
2483
2554
|
/* @__PURE__ */ jsxs4(ScrollBox_default, { ...scrollRef === void 0 ? {} : { ref: scrollRef }, flexGrow: 1, flexDirection: "column", stickyScroll: true, children: [
|
|
2484
|
-
showWelcome ? /* @__PURE__ */ jsx5(WelcomeCard, { model, ...serviceName === void 0 ? {} : { serviceName }, workspaceName, columns }) : /* @__PURE__ */ jsxs4(Text, { dimColor: true, children: [
|
|
2555
|
+
showWelcome ? /* @__PURE__ */ jsx5(WelcomeCard, { model, ...serviceName === void 0 ? {} : { serviceName }, workspaceName, ...updateTo === void 0 ? {} : { updateTo }, columns }) : /* @__PURE__ */ jsxs4(Text, { dimColor: true, children: [
|
|
2485
2556
|
"flavor \xB7 ",
|
|
2486
2557
|
model,
|
|
2487
2558
|
" \xB7 ",
|
|
@@ -28548,7 +28548,13 @@ function terminalName() {
|
|
|
28548
28548
|
var env = { terminal: terminalName() };
|
|
28549
28549
|
|
|
28550
28550
|
// src/utils/semver.ts
|
|
28551
|
-
import { gte as semverGte } from "semver";
|
|
28551
|
+
import { gt as semverGt, gte as semverGte, valid as semverValid } from "semver";
|
|
28552
|
+
function gt(a, b) {
|
|
28553
|
+
return semverGt(a, b, { loose: true });
|
|
28554
|
+
}
|
|
28555
|
+
function isValidVersion(value) {
|
|
28556
|
+
return semverValid(value, { loose: true }) !== null;
|
|
28557
|
+
}
|
|
28552
28558
|
|
|
28553
28559
|
// src/claude-ink/clearTerminal.ts
|
|
28554
28560
|
var CURSOR_HOME_WINDOWS = csi(0, "f");
|
|
@@ -35489,6 +35495,8 @@ export {
|
|
|
35489
35495
|
stripAnsi,
|
|
35490
35496
|
ScrollBox_default,
|
|
35491
35497
|
instances_default,
|
|
35498
|
+
gt,
|
|
35499
|
+
isValidVersion,
|
|
35492
35500
|
osc,
|
|
35493
35501
|
OSC2 as OSC,
|
|
35494
35502
|
TerminalWriteContext,
|
|
@@ -1314,6 +1314,8 @@ function appendThinkingText(previous, delta) {
|
|
|
1314
1314
|
}
|
|
1315
1315
|
|
|
1316
1316
|
// src/ui/transcript.ts
|
|
1317
|
+
var MAX_TRANSCRIPT_TURNS = 200;
|
|
1318
|
+
var MAX_TRANSCRIPT_CHARS = 2e6;
|
|
1317
1319
|
function createTranscriptState() {
|
|
1318
1320
|
return { completed: [], nextId: 1 };
|
|
1319
1321
|
}
|
|
@@ -1610,7 +1612,7 @@ function hydrateHistory(messages, compact) {
|
|
|
1610
1612
|
}
|
|
1611
1613
|
}
|
|
1612
1614
|
if (turn !== void 0) completed.push(turn);
|
|
1613
|
-
return { completed, nextId: completed.length + 1 };
|
|
1615
|
+
return { completed: boundedCompleted(completed), nextId: completed.length + 1 };
|
|
1614
1616
|
}
|
|
1615
1617
|
function transcriptFromLegacyConversation(messages, compact) {
|
|
1616
1618
|
return hydrateHistory(messages, compact);
|
|
@@ -1704,10 +1706,10 @@ function finishActive(state) {
|
|
|
1704
1706
|
if (state.active === void 0) return state;
|
|
1705
1707
|
const active = withoutModelActivity(state.active);
|
|
1706
1708
|
return {
|
|
1707
|
-
completed: [...state.completed, {
|
|
1709
|
+
completed: boundedCompleted([...state.completed, {
|
|
1708
1710
|
...active,
|
|
1709
1711
|
completedAt: active.completedAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
1710
|
-
}],
|
|
1712
|
+
}]),
|
|
1711
1713
|
nextId: state.nextId,
|
|
1712
1714
|
...state.taskSnapshot === void 0 ? {} : { taskSnapshot: state.taskSnapshot }
|
|
1713
1715
|
};
|
|
@@ -1736,12 +1738,26 @@ function withoutModelActivity(turn, id) {
|
|
|
1736
1738
|
function restoreTranscriptState(state) {
|
|
1737
1739
|
const completed = state.completed.map(cloneTurn);
|
|
1738
1740
|
if (state.active !== void 0) completed.push(normalizeInterruptedTurn(cloneTurn(state.active)));
|
|
1741
|
+
const nextId = Math.max(state.nextId, ...completed.map((turn) => turn.id + 1), 1);
|
|
1739
1742
|
return {
|
|
1740
|
-
completed,
|
|
1741
|
-
nextId
|
|
1743
|
+
completed: boundedCompleted(completed),
|
|
1744
|
+
nextId,
|
|
1742
1745
|
...state.taskSnapshot === void 0 ? {} : { taskSnapshot: state.taskSnapshot }
|
|
1743
1746
|
};
|
|
1744
1747
|
}
|
|
1748
|
+
function boundedCompleted(input) {
|
|
1749
|
+
const recent = input.slice(-MAX_TRANSCRIPT_TURNS);
|
|
1750
|
+
let chars = 0;
|
|
1751
|
+
let start = recent.length;
|
|
1752
|
+
for (let index = recent.length - 1; index >= 0; index -= 1) {
|
|
1753
|
+
const turn = recent[index];
|
|
1754
|
+
const size = JSON.stringify(turn).length;
|
|
1755
|
+
if (start < recent.length && chars + size > MAX_TRANSCRIPT_CHARS) break;
|
|
1756
|
+
chars += size;
|
|
1757
|
+
start = index;
|
|
1758
|
+
}
|
|
1759
|
+
return recent.slice(start);
|
|
1760
|
+
}
|
|
1745
1761
|
function compactionTurn(compact) {
|
|
1746
1762
|
const text = `Original execution steps before ${compact.compactedAt} are unavailable.`;
|
|
1747
1763
|
return {
|
|
@@ -2032,6 +2048,8 @@ function isCode(error, code) {
|
|
|
2032
2048
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
2033
2049
|
import { mkdir as mkdir3, readFile as readFile3, rename as rename2, writeFile as writeFile3 } from "fs/promises";
|
|
2034
2050
|
import { dirname as dirname5, join as join4, resolve as resolve3 } from "path";
|
|
2051
|
+
var MAX_SESSION_HISTORY_NODES = 100;
|
|
2052
|
+
var MAX_SESSION_HISTORY_CONTEXT_CHARS = 2e6;
|
|
2035
2053
|
var SessionHistory = class _SessionHistory {
|
|
2036
2054
|
#path;
|
|
2037
2055
|
#checkpoints;
|
|
@@ -2043,8 +2061,8 @@ var SessionHistory = class _SessionHistory {
|
|
|
2043
2061
|
this.#path = join4(resolve3(options.workspace), ".flavor", "session-trees", options.sessionId, "tree.json");
|
|
2044
2062
|
this.#checkpoints = new WorkspaceCheckpointStore({ workspace: options.workspace });
|
|
2045
2063
|
this.#restoreContext = options.restoreContext;
|
|
2046
|
-
this.#nodes = document.nodes;
|
|
2047
|
-
this.#leafId = document.leafId;
|
|
2064
|
+
this.#nodes = boundedNodes(document.nodes);
|
|
2065
|
+
this.#leafId = document.leafId !== null && this.#nodes.some((node) => node.id === document.leafId) ? document.leafId : this.#nodes.at(-1)?.id ?? null;
|
|
2048
2066
|
}
|
|
2049
2067
|
static async open(options) {
|
|
2050
2068
|
const path = join4(resolve3(options.workspace), ".flavor", "session-trees", options.sessionId, "tree.json");
|
|
@@ -2056,7 +2074,9 @@ var SessionHistory = class _SessionHistory {
|
|
|
2056
2074
|
} catch (error) {
|
|
2057
2075
|
if (!isCode2(error, "ENOENT")) throw error;
|
|
2058
2076
|
}
|
|
2059
|
-
|
|
2077
|
+
const history = new _SessionHistory(options, document);
|
|
2078
|
+
if (history.#nodes.length !== document.nodes.length) await history.#persist();
|
|
2079
|
+
return history;
|
|
2060
2080
|
}
|
|
2061
2081
|
get leafId() {
|
|
2062
2082
|
return this.#leafId;
|
|
@@ -2076,6 +2096,7 @@ var SessionHistory = class _SessionHistory {
|
|
|
2076
2096
|
};
|
|
2077
2097
|
this.#nodes.push(node);
|
|
2078
2098
|
this.#leafId = node.id;
|
|
2099
|
+
this.#boundNodes();
|
|
2079
2100
|
await this.#persist();
|
|
2080
2101
|
return structuredClone(node);
|
|
2081
2102
|
}
|
|
@@ -2117,6 +2138,13 @@ var SessionHistory = class _SessionHistory {
|
|
|
2117
2138
|
if (node === void 0) throw new Error(`Unknown session tree node: ${id}`);
|
|
2118
2139
|
return node;
|
|
2119
2140
|
}
|
|
2141
|
+
#boundNodes() {
|
|
2142
|
+
const bounded2 = boundedNodes(this.#nodes);
|
|
2143
|
+
this.#nodes.splice(0, this.#nodes.length, ...bounded2);
|
|
2144
|
+
if (this.#leafId !== null && !this.#nodes.some((node) => node.id === this.#leafId)) {
|
|
2145
|
+
this.#leafId = this.#nodes.at(-1)?.id ?? null;
|
|
2146
|
+
}
|
|
2147
|
+
}
|
|
2120
2148
|
async #persist() {
|
|
2121
2149
|
const document = {
|
|
2122
2150
|
version: 1,
|
|
@@ -2131,6 +2159,24 @@ var SessionHistory = class _SessionHistory {
|
|
|
2131
2159
|
await rename2(temporary, this.#path);
|
|
2132
2160
|
}
|
|
2133
2161
|
};
|
|
2162
|
+
function boundedNodes(input) {
|
|
2163
|
+
const recent = input.slice(-MAX_SESSION_HISTORY_NODES);
|
|
2164
|
+
let contextChars = 0;
|
|
2165
|
+
let start = recent.length;
|
|
2166
|
+
for (let index = recent.length - 1; index >= 0; index -= 1) {
|
|
2167
|
+
const node = recent[index];
|
|
2168
|
+
const size = JSON.stringify(node.context).length;
|
|
2169
|
+
if (start < recent.length && contextChars + size > MAX_SESSION_HISTORY_CONTEXT_CHARS) break;
|
|
2170
|
+
contextChars += size;
|
|
2171
|
+
start = index;
|
|
2172
|
+
}
|
|
2173
|
+
const retained = recent.slice(start).map((node) => structuredClone(node));
|
|
2174
|
+
const ids = new Set(retained.map((node) => node.id));
|
|
2175
|
+
for (const node of retained) {
|
|
2176
|
+
if (node.parentId !== null && !ids.has(node.parentId)) node.parentId = null;
|
|
2177
|
+
}
|
|
2178
|
+
return retained;
|
|
2179
|
+
}
|
|
2134
2180
|
function validate(value, sessionId) {
|
|
2135
2181
|
if (value.version !== 1 || value.sessionId !== sessionId || !Array.isArray(value.nodes)) {
|
|
2136
2182
|
throw new Error("Invalid session tree");
|
|
@@ -3570,6 +3616,7 @@ var HELP = [
|
|
|
3570
3616
|
"/chat <alias-or-uuid> <goal> send a task that starts on the receiving pal",
|
|
3571
3617
|
"/co-work <pal> <goal> | status [id] | cancel <id> [reason]"
|
|
3572
3618
|
].join("\n");
|
|
3619
|
+
var MAX_STOP_DENIALS = 2;
|
|
3573
3620
|
var FlavorSession = class {
|
|
3574
3621
|
#services;
|
|
3575
3622
|
#active;
|
|
@@ -3580,6 +3627,7 @@ var FlavorSession = class {
|
|
|
3580
3627
|
#submissionTail = Promise.resolve();
|
|
3581
3628
|
#coWorkEventTail = Promise.resolve();
|
|
3582
3629
|
#pendingSubmissions = 0;
|
|
3630
|
+
#stopDenials = 0;
|
|
3583
3631
|
#closePromise;
|
|
3584
3632
|
#queue = new AgentMessageQueue();
|
|
3585
3633
|
#queuedSubmissions = { steer: [], followUp: [] };
|
|
@@ -3781,6 +3829,7 @@ var FlavorSession = class {
|
|
|
3781
3829
|
return operation;
|
|
3782
3830
|
}
|
|
3783
3831
|
async #runSubmissionChain(initialSubmission) {
|
|
3832
|
+
this.#stopDenials = 0;
|
|
3784
3833
|
const pending = [initialSubmission];
|
|
3785
3834
|
let initial = true;
|
|
3786
3835
|
while (pending.length > 0) {
|
|
@@ -3874,8 +3923,9 @@ var FlavorSession = class {
|
|
|
3874
3923
|
this.#active = void 0;
|
|
3875
3924
|
this.#activeSubmission = void 0;
|
|
3876
3925
|
if (submission.coWorkPlanningKey !== void 0) this.#finishActivePlanning(submission.coWorkPlanningKey);
|
|
3926
|
+
let stopDecision;
|
|
3877
3927
|
try {
|
|
3878
|
-
await this.#services.hooks.emit({
|
|
3928
|
+
stopDecision = await this.#services.hooks.emit({
|
|
3879
3929
|
version: 1,
|
|
3880
3930
|
type: "Stop",
|
|
3881
3931
|
payload: {
|
|
@@ -3890,6 +3940,21 @@ var FlavorSession = class {
|
|
|
3890
3940
|
} catch {
|
|
3891
3941
|
}
|
|
3892
3942
|
}
|
|
3943
|
+
try {
|
|
3944
|
+
if (stopDecision?.decision === "deny" && typeof stopDecision.reason === "string" && stopDecision.reason.length > 0 && !this.#closed && outcome !== "cancelled" && outcome !== "denied") {
|
|
3945
|
+
if (this.#stopDenials < MAX_STOP_DENIALS) {
|
|
3946
|
+
this.#stopDenials += 1;
|
|
3947
|
+
const text = `[stop-guard] A Stop hook vetoed ending this turn (continuation ${this.#stopDenials}/${MAX_STOP_DENIALS}). It reported:
|
|
3948
|
+
${stopDecision.reason}
|
|
3949
|
+
Address this now (for example run the required verification or fix), then finish.`;
|
|
3950
|
+
this.#enqueueMessage("followUp", { text, displayText: text });
|
|
3951
|
+
this.#notice(`Stop hook requested continuation (${this.#stopDenials}/${MAX_STOP_DENIALS}).`);
|
|
3952
|
+
} else {
|
|
3953
|
+
this.#notice("Stop hook kept vetoing after the continuation budget; ending the turn anyway.");
|
|
3954
|
+
}
|
|
3955
|
+
}
|
|
3956
|
+
} catch {
|
|
3957
|
+
}
|
|
3893
3958
|
this.#ackDurable(submission);
|
|
3894
3959
|
this.#ackActiveSteering();
|
|
3895
3960
|
}
|
|
@@ -6229,9 +6294,8 @@ var ContextManager = class _ContextManager {
|
|
|
6229
6294
|
const currentStableHash = currentStable === void 0 ? this.#epoch.stableSourceHash : hashMessages(currentStable);
|
|
6230
6295
|
if (currentStable !== void 0 && currentStableHash !== this.#epoch.stableSourceHash) {
|
|
6231
6296
|
const value = currentStable.map((message2) => message2.content).join("\n\n");
|
|
6232
|
-
const previous = this.#epoch.sources["system-baseline"] ?? this.#epoch.stableMessages.map((message2) => message2.content).join("\n\n");
|
|
6233
6297
|
if (this.#epoch.sources["system-baseline"] !== value) {
|
|
6234
|
-
updates.push(contextUpdateMessage("system-baseline",
|
|
6298
|
+
updates.push(contextUpdateMessage("system-baseline", value));
|
|
6235
6299
|
this.#epoch.sources["system-baseline"] = value;
|
|
6236
6300
|
}
|
|
6237
6301
|
} else if (currentStable !== void 0 && this.#epoch.sources["system-baseline"] !== void 0) {
|
|
@@ -6252,8 +6316,6 @@ var ContextManager = class _ContextManager {
|
|
|
6252
6316
|
}
|
|
6253
6317
|
if (updates.length === 0) return false;
|
|
6254
6318
|
this.#messages.push(...updates);
|
|
6255
|
-
this.#lastRecordedInputTokens = void 0;
|
|
6256
|
-
this.#estimatedTokensAtLastRecordedUsage = void 0;
|
|
6257
6319
|
return true;
|
|
6258
6320
|
}
|
|
6259
6321
|
snapshot() {
|
|
@@ -6313,10 +6375,7 @@ var ContextManager = class _ContextManager {
|
|
|
6313
6375
|
async prepareForModelCall(signal = new AbortController().signal) {
|
|
6314
6376
|
signal.throwIfAborted();
|
|
6315
6377
|
this.refreshContextSources();
|
|
6316
|
-
|
|
6317
|
-
this.#lastRecordedInputTokens = void 0;
|
|
6318
|
-
this.#estimatedTokensAtLastRecordedUsage = void 0;
|
|
6319
|
-
}
|
|
6378
|
+
this.#dropStaleContextUpdates();
|
|
6320
6379
|
if (!this.needsCompaction()) return false;
|
|
6321
6380
|
const originalMessages = this.#messages;
|
|
6322
6381
|
const originalRecordedUsage = this.#lastRecordedInputTokens;
|
|
@@ -6329,8 +6388,6 @@ var ContextManager = class _ContextManager {
|
|
|
6329
6388
|
const microcompact = microcompactMessages(this.#messages, this.#compaction.microcompactKeepRecentToolResults);
|
|
6330
6389
|
if (microcompact.changed) {
|
|
6331
6390
|
this.#messages = microcompact.messages;
|
|
6332
|
-
this.#lastRecordedInputTokens = void 0;
|
|
6333
|
-
this.#estimatedTokensAtLastRecordedUsage = void 0;
|
|
6334
6391
|
}
|
|
6335
6392
|
if (!this.needsCompaction()) {
|
|
6336
6393
|
if (microcompact.changed) {
|
|
@@ -7294,7 +7351,7 @@ function memoryPressureError(heapUsed, heapLimit) {
|
|
|
7294
7351
|
const mb = (bytes) => Math.round(bytes / 1048576);
|
|
7295
7352
|
return {
|
|
7296
7353
|
code: "memory_pressure",
|
|
7297
|
-
message: `Heap usage reached ${Math.round(heapUsed / heapLimit * 100)}% of the V8 limit (${mb(heapUsed)}MB of ${mb(heapLimit)}MB); stopping to avoid a crash. The
|
|
7354
|
+
message: `Heap usage reached ${Math.round(heapUsed / heapLimit * 100)}% of the V8 limit (${mb(heapUsed)}MB of ${mb(heapLimit)}MB); stopping the current turn to avoid a crash. The saved session will reopen after restart.`
|
|
7298
7355
|
};
|
|
7299
7356
|
}
|
|
7300
7357
|
function currentMemoryPressure() {
|
|
@@ -7414,6 +7471,11 @@ var AgentLoop = class {
|
|
|
7414
7471
|
yield { type: "error", error: normalizeProviderError(error) };
|
|
7415
7472
|
return;
|
|
7416
7473
|
}
|
|
7474
|
+
const preparedPressure = currentMemoryPressure();
|
|
7475
|
+
if (preparedPressure !== void 0) {
|
|
7476
|
+
yield { type: "error", error: preparedPressure };
|
|
7477
|
+
return;
|
|
7478
|
+
}
|
|
7417
7479
|
let assistantText = "";
|
|
7418
7480
|
const collectedToolCalls = [];
|
|
7419
7481
|
const collectedThinking = [];
|
|
@@ -7437,6 +7499,11 @@ var AgentLoop = class {
|
|
|
7437
7499
|
tools: [...this.#options.tools],
|
|
7438
7500
|
...request.signal === void 0 ? {} : { signal: request.signal }
|
|
7439
7501
|
};
|
|
7502
|
+
const requestPressure = currentMemoryPressure();
|
|
7503
|
+
if (requestPressure !== void 0) {
|
|
7504
|
+
yield { type: "error", error: requestPressure };
|
|
7505
|
+
return;
|
|
7506
|
+
}
|
|
7440
7507
|
let before;
|
|
7441
7508
|
try {
|
|
7442
7509
|
before = await this.#options.hooks.emit({
|
|
@@ -22735,7 +22802,7 @@ async function createProductionRuntime(options) {
|
|
|
22735
22802
|
contextEpoch: harness.main.context.snapshot().epoch?.id ?? "legacy"
|
|
22736
22803
|
});
|
|
22737
22804
|
const turnId = harnessJournal.startTurn(turnConfig, { prompt, initialUserMessage: runOptions?.initialUserMessage });
|
|
22738
|
-
return monitorMemoryRestart(durableTurn(
|
|
22805
|
+
return monitorMemoryRestart(durableTurn(persistAfter(runMain(
|
|
22739
22806
|
harness,
|
|
22740
22807
|
skills,
|
|
22741
22808
|
prompt,
|
|
@@ -22751,11 +22818,7 @@ async function createProductionRuntime(options) {
|
|
|
22751
22818
|
runOptions?.initialUserMessage,
|
|
22752
22819
|
runOptions?.additionalContext,
|
|
22753
22820
|
ide
|
|
22754
|
-
), persist, () =>
|
|
22755
|
-
prompt,
|
|
22756
|
-
context: harness.main.context.snapshot(),
|
|
22757
|
-
label: `turn: ${prompt.slice(0, 80)}`
|
|
22758
|
-
})), harnessJournal, turnId, turnConfig), () => requestMemoryRestart(workspace, sessionId, emitOutput));
|
|
22821
|
+
), persist), harnessJournal, turnId, turnConfig), () => requestMemoryRestart(workspace, sessionId, emitOutput));
|
|
22759
22822
|
},
|
|
22760
22823
|
runSkill: (skill, prompt, signal) => persistAfter(
|
|
22761
22824
|
runExplicitSkill(harness, skills, skill, prompt, signal, selectedModels.mainError),
|
|
@@ -23465,14 +23528,6 @@ async function* persistAfter(source, persist) {
|
|
|
23465
23528
|
await persist();
|
|
23466
23529
|
}
|
|
23467
23530
|
}
|
|
23468
|
-
async function* persistAndCheckpointAfter(source, persist, checkpoint) {
|
|
23469
|
-
try {
|
|
23470
|
-
for await (const item of source) yield item;
|
|
23471
|
-
await checkpoint();
|
|
23472
|
-
} finally {
|
|
23473
|
-
await persist();
|
|
23474
|
-
}
|
|
23475
|
-
}
|
|
23476
23531
|
async function* persistEach(source, persist) {
|
|
23477
23532
|
try {
|
|
23478
23533
|
for await (const item of source) {
|
package/dist/cli-main.js
CHANGED
|
@@ -3,7 +3,7 @@ import { createRequire } from "node:module"; const require = createRequire(impor
|
|
|
3
3
|
import {
|
|
4
4
|
FlavorRpcServer,
|
|
5
5
|
TraceRecorder
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-6LDYDQ3P.js";
|
|
7
7
|
import {
|
|
8
8
|
staticTaskLines
|
|
9
9
|
} from "./chunk-2BF7CVWZ.js";
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
packageVersion,
|
|
24
24
|
redactErrorText,
|
|
25
25
|
runPalBroker
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-PF457XCH.js";
|
|
27
27
|
import "./chunk-CIVPKHF4.js";
|
|
28
28
|
import {
|
|
29
29
|
McpServerConfigSchema,
|
|
@@ -876,9 +876,9 @@ function createProgram(dependencies = {}) {
|
|
|
876
876
|
}
|
|
877
877
|
async function runInteractiveCli(props) {
|
|
878
878
|
const [{ render, AlternateScreen }, { createElement }, { App }] = await Promise.all([
|
|
879
|
-
import("./claude-ink-
|
|
879
|
+
import("./claude-ink-AUZBJ3BE.js"),
|
|
880
880
|
import("react"),
|
|
881
|
-
import("./app-
|
|
881
|
+
import("./app-LKK5RBTO.js")
|
|
882
882
|
]);
|
|
883
883
|
const instance = await render(createElement(
|
|
884
884
|
AlternateScreen,
|
package/dist/cli.js
CHANGED
|
@@ -11,29 +11,19 @@ import "./chunk-S32JRDZK.js";
|
|
|
11
11
|
// src/launcher.ts
|
|
12
12
|
import { spawn } from "child_process";
|
|
13
13
|
import { realpathSync, readFileSync } from "fs";
|
|
14
|
-
import { release } from "os";
|
|
15
14
|
import { fileURLToPath } from "url";
|
|
16
|
-
function needsWindowsMaglevWorkaround(runtime) {
|
|
17
|
-
if (runtime.platform !== "win32") return false;
|
|
18
|
-
const build = Number(runtime.osRelease.split(".")[2]);
|
|
19
|
-
const major = Number(runtime.nodeVersion.replace(/^v/u, "").split(".")[0]);
|
|
20
|
-
if (build !== 26200 || major < 24) return false;
|
|
21
|
-
return !runtime.execArgv.some((argument) => argument === "--no-maglev" || argument === "--jitless");
|
|
22
|
-
}
|
|
23
15
|
function needsRelaunch(runtime) {
|
|
24
|
-
if (needsWindowsMaglevWorkaround(runtime)) return true;
|
|
25
16
|
if (!runtime.execArgv.some((argument) => argument === "--report-on-fatalerror")) return true;
|
|
26
17
|
return !runtime.execArgv.some((argument) => argument.startsWith("--heapsnapshot-near-heap-limit"));
|
|
27
18
|
}
|
|
28
|
-
function cliMainArguments(
|
|
19
|
+
function cliMainArguments(mainPath, argv) {
|
|
29
20
|
return [
|
|
30
|
-
...needsWindowsMaglevWorkaround(runtime) ? ["--no-maglev"] : [],
|
|
31
21
|
// Fatal V8 errors (heap OOM, native crashes) bypass crash-guard.ts and
|
|
32
22
|
// leave only an unusable native stack. Ask Node to dump a diagnostic
|
|
33
23
|
// report next to the working directory so the next crash has a scene.
|
|
34
24
|
"--report-on-fatalerror",
|
|
35
|
-
// The 2026-08-29 OOM
|
|
36
|
-
//
|
|
25
|
+
// The 2026-08-29 OOM reports showed about 4.28GB used at a 4.50GB
|
|
26
|
+
// heap limit while the provider reported roughly 162K context tokens.
|
|
37
27
|
// Capture one heap snapshot as the heap nears its limit so the next
|
|
38
28
|
// crash leaves a .heapsnapshot retainer trail next to the report.
|
|
39
29
|
"--heapsnapshot-near-heap-limit=1",
|
|
@@ -44,9 +34,6 @@ function cliMainArguments(runtime, mainPath, argv) {
|
|
|
44
34
|
async function launchCli() {
|
|
45
35
|
const mainUrl = new URL("./cli-main.js", import.meta.url);
|
|
46
36
|
const runtime = {
|
|
47
|
-
platform: process.platform,
|
|
48
|
-
osRelease: release(),
|
|
49
|
-
nodeVersion: process.version,
|
|
50
37
|
execArgv: process.execArgv
|
|
51
38
|
};
|
|
52
39
|
if (!needsRelaunch(runtime)) {
|
|
@@ -57,7 +44,7 @@ async function launchCli() {
|
|
|
57
44
|
const mainPath = fileURLToPath(mainUrl);
|
|
58
45
|
let argv = process.argv.slice(2);
|
|
59
46
|
for (; ; ) {
|
|
60
|
-
const code = await spawnAndWait(
|
|
47
|
+
const code = await spawnAndWait(mainPath, argv);
|
|
61
48
|
if (code === MEMORY_RESTART_EXIT_CODE) {
|
|
62
49
|
let marker;
|
|
63
50
|
try {
|
|
@@ -80,8 +67,8 @@ async function launchCli() {
|
|
|
80
67
|
return;
|
|
81
68
|
}
|
|
82
69
|
}
|
|
83
|
-
async function spawnAndWait(
|
|
84
|
-
const child = spawn(process.execPath, cliMainArguments(
|
|
70
|
+
async function spawnAndWait(mainPath, argv) {
|
|
71
|
+
const child = spawn(process.execPath, cliMainArguments(mainPath, argv), { stdio: "inherit" });
|
|
85
72
|
const ignoreSignal = () => {
|
|
86
73
|
};
|
|
87
74
|
process.on("SIGINT", ignoreSignal);
|
|
@@ -111,6 +98,5 @@ if (process.argv[1]) {
|
|
|
111
98
|
export {
|
|
112
99
|
cliMainArguments,
|
|
113
100
|
launchCli,
|
|
114
|
-
needsRelaunch
|
|
115
|
-
needsWindowsMaglevWorkaround
|
|
101
|
+
needsRelaunch
|
|
116
102
|
};
|