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 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/ # Session branches
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-S525EOFQ.js";
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-F2HMO5Q2.js";
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({ model, serviceName, workspaceName, columns }) {
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,
@@ -4,7 +4,7 @@ import {
4
4
  message,
5
5
  redactErrorText,
6
6
  redactSecrets
7
- } from "./chunk-S525EOFQ.js";
7
+ } from "./chunk-PF457XCH.js";
8
8
 
9
9
  // src/rpc/server.ts
10
10
  import { createInterface } from "readline";
@@ -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: Math.max(state.nextId, ...completed.map((turn) => turn.id + 1), 1),
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
- return new _SessionHistory(options, document);
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", deltaSourceValue(previous, value)));
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
- if (this.#dropStaleContextUpdates()) {
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 session is saved and will resume after restart.`
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(persistAndCheckpointAfter(runMain(
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, () => sessionHistory.append({
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) {
@@ -10,7 +10,7 @@ import {
10
10
  useStdout,
11
11
  use_app_default,
12
12
  use_input_default
13
- } from "./chunk-F2HMO5Q2.js";
13
+ } from "./chunk-36UKDXPF.js";
14
14
  import "./chunk-RQTYHUMK.js";
15
15
  import "./chunk-S32JRDZK.js";
16
16
  export {
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-LMFN2QEA.js";
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-S525EOFQ.js";
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-ORUA7GWG.js"),
879
+ import("./claude-ink-AUZBJ3BE.js"),
880
880
  import("react"),
881
- import("./app-6SEGTMMC.js")
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(runtime, mainPath, argv) {
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 report showed 4.29GB retained with only ~130K
36
- // context tokens, and no static candidate explained the retention.
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(runtime, mainPath, argv);
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(runtime, mainPath, argv) {
84
- const child = spawn(process.execPath, cliMainArguments(runtime, mainPath, argv), { stdio: "inherit" });
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
  };