flavor-code 1.3.15 → 1.3.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent/loop.d.ts +10 -1
- package/dist/agent/types.d.ts +1 -1
- package/dist/{app-DDYOKGCX.js → app-6SEGTMMC.js} +3 -2
- package/dist/chunk-CIVPKHF4.js +53 -0
- package/dist/{chunk-JFKRX2KG.js → chunk-HJOCNKPN.js} +1 -1
- package/dist/{chunk-TQXNF337.js → chunk-LMFN2QEA.js} +1 -1
- package/dist/{chunk-WB4IJXFT.js → chunk-S525EOFQ.js} +138 -12
- package/dist/cli-main.js +6 -5
- package/dist/cli.js +52 -9
- package/dist/context/manager.d.ts +7 -0
- package/dist/desktop/main.js +316 -172
- package/dist/desktop-renderer/assets/{index-BAHTmEUI.js → index-C3JpD2_B.js} +2 -2
- package/dist/desktop-renderer/assets/{interactive-terminal-Bn8G5Pig.js → interactive-terminal-f1PNniPO.js} +1 -1
- package/dist/desktop-renderer/index.html +1 -1
- package/dist/{load-LTTKVPJZ.js → load-DELQW42K.js} +1 -1
- package/dist/sdk/index.js +4 -3
- package/dist/utils/memory-restart.d.ts +33 -0
- package/package.json +3 -1
package/dist/agent/loop.d.ts
CHANGED
|
@@ -4,7 +4,16 @@ import type { HookBus } from "../hooks/bus.js";
|
|
|
4
4
|
import type { ModelRegistry } from "../models/registry.js";
|
|
5
5
|
import { type ModelMessage, type ModelTool } from "../models/types.js";
|
|
6
6
|
import type { ToolRuntime } from "../tools/runtime.js";
|
|
7
|
-
import type { AgentEvent, AgentRunRequest } from "./types.js";
|
|
7
|
+
import type { AgentError, AgentEvent, AgentRunRequest } from "./types.js";
|
|
8
|
+
/**
|
|
9
|
+
* Stop a turn before the V8 heap reaches its hard limit. A retained-memory
|
|
10
|
+
* leak otherwise ends in a native OOM crash with no recovery; tripping this
|
|
11
|
+
* watermark saves the session and lets the launcher relaunch on a fresh heap.
|
|
12
|
+
* 0.8 keeps headroom for compaction payloads and the GC death spiral that
|
|
13
|
+
* starts near ~0.95.
|
|
14
|
+
*/
|
|
15
|
+
export declare const MEMORY_PRESSURE_HEAP_RATIO = 0.8;
|
|
16
|
+
export declare function memoryPressureError(heapUsed: number, heapLimit: number): AgentError | undefined;
|
|
8
17
|
export interface AgentLoopOptions {
|
|
9
18
|
registry: ModelRegistry;
|
|
10
19
|
modelId: string;
|
package/dist/agent/types.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ export interface AgentRunRequest {
|
|
|
15
15
|
/** Messages supplied while a tool batch is running, injected before the next model call. */
|
|
16
16
|
getSteeringMessages?(): readonly string[];
|
|
17
17
|
}
|
|
18
|
-
export type AgentErrorCode = ProviderErrorCode | "iteration_limit" | "incomplete_stream" | "empty_response";
|
|
18
|
+
export type AgentErrorCode = ProviderErrorCode | "iteration_limit" | "incomplete_stream" | "empty_response" | "memory_pressure";
|
|
19
19
|
export interface AgentError {
|
|
20
20
|
code: AgentErrorCode;
|
|
21
21
|
message: string;
|
|
@@ -18,8 +18,9 @@ import {
|
|
|
18
18
|
thinkingWindow,
|
|
19
19
|
transcriptReducer,
|
|
20
20
|
withTimeout
|
|
21
|
-
} from "./chunk-
|
|
22
|
-
import "./chunk-
|
|
21
|
+
} from "./chunk-S525EOFQ.js";
|
|
22
|
+
import "./chunk-CIVPKHF4.js";
|
|
23
|
+
import "./chunk-HJOCNKPN.js";
|
|
23
24
|
import {
|
|
24
25
|
Box_default,
|
|
25
26
|
ClockContext,
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from "node:module"; const require = createRequire(import.meta.url);
|
|
3
|
+
|
|
4
|
+
// src/utils/memory-restart.ts
|
|
5
|
+
import { join } from "path";
|
|
6
|
+
var MEMORY_RESTART_EXIT_CODE = 75;
|
|
7
|
+
var MEMORY_RESTART_MARKER_FILE = "memory-restart.json";
|
|
8
|
+
var MEMORY_RESTART_MAX_ATTEMPTS = 3;
|
|
9
|
+
var MEMORY_RESTART_WINDOW_MS = 30 * 60 * 1e3;
|
|
10
|
+
var SESSION_ID_PATTERN = /^session-[A-Za-z0-9_-]+$/u;
|
|
11
|
+
function memoryRestartMarkerPath(workspace) {
|
|
12
|
+
return join(workspace, ".flavor", "tmp", MEMORY_RESTART_MARKER_FILE);
|
|
13
|
+
}
|
|
14
|
+
function nextMemoryRestartMarker(previous, sessionId, now) {
|
|
15
|
+
const reusable = previous !== void 0 && previous.sessionId === sessionId && now.getTime() - Date.parse(previous.requestedAt) < MEMORY_RESTART_WINDOW_MS && Number.isInteger(previous.attempts) && previous.attempts > 0;
|
|
16
|
+
return { sessionId, requestedAt: now.toISOString(), attempts: reusable ? previous.attempts + 1 : 1 };
|
|
17
|
+
}
|
|
18
|
+
function shouldRelaunchForMemoryRestart(marker) {
|
|
19
|
+
return marker !== void 0 && SESSION_ID_PATTERN.test(marker.sessionId) && Number.isInteger(marker.attempts) && marker.attempts >= 1 && marker.attempts <= MEMORY_RESTART_MAX_ATTEMPTS;
|
|
20
|
+
}
|
|
21
|
+
function memoryRestartArgs(argv, marker) {
|
|
22
|
+
if (!shouldRelaunchForMemoryRestart(marker)) return void 0;
|
|
23
|
+
const stripped = [];
|
|
24
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
25
|
+
const argument = argv[index];
|
|
26
|
+
if (argument === "--resume") {
|
|
27
|
+
if (index + 1 < argv.length && !argv[index + 1].startsWith("-")) index += 1;
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
if (argument.startsWith("--resume=")) continue;
|
|
31
|
+
stripped.push(argument);
|
|
32
|
+
}
|
|
33
|
+
return [...stripped, "--resume", marker.sessionId];
|
|
34
|
+
}
|
|
35
|
+
function parseMemoryRestartMarker(json) {
|
|
36
|
+
try {
|
|
37
|
+
const value = JSON.parse(json);
|
|
38
|
+
if (typeof value.sessionId !== "string" || typeof value.requestedAt !== "string" || typeof value.attempts !== "number") {
|
|
39
|
+
return void 0;
|
|
40
|
+
}
|
|
41
|
+
return { sessionId: value.sessionId, requestedAt: value.requestedAt, attempts: value.attempts };
|
|
42
|
+
} catch {
|
|
43
|
+
return void 0;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export {
|
|
48
|
+
MEMORY_RESTART_EXIT_CODE,
|
|
49
|
+
memoryRestartMarkerPath,
|
|
50
|
+
nextMemoryRestartMarker,
|
|
51
|
+
memoryRestartArgs,
|
|
52
|
+
parseMemoryRestartMarker
|
|
53
|
+
};
|
|
@@ -129,7 +129,7 @@ var FlavorConfigSchema = z.object({
|
|
|
129
129
|
context: z.object({
|
|
130
130
|
windowTokens: z.number().int().positive().default(2e5),
|
|
131
131
|
reservedOutputTokens: z.number().int().nonnegative().default(2e4),
|
|
132
|
-
autoCompactBufferTokens: z.number().int().nonnegative().default(
|
|
132
|
+
autoCompactBufferTokens: z.number().int().nonnegative().default(27e3),
|
|
133
133
|
warningBufferTokens: z.number().int().nonnegative().default(2e4),
|
|
134
134
|
blockingBufferTokens: z.number().int().nonnegative().default(3e3),
|
|
135
135
|
microcompactKeepRecentToolResults: z.number().int().nonnegative().default(5),
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from "node:module"; const require = createRequire(import.meta.url);
|
|
3
|
+
import {
|
|
4
|
+
MEMORY_RESTART_EXIT_CODE,
|
|
5
|
+
memoryRestartMarkerPath,
|
|
6
|
+
nextMemoryRestartMarker,
|
|
7
|
+
parseMemoryRestartMarker
|
|
8
|
+
} from "./chunk-CIVPKHF4.js";
|
|
3
9
|
import {
|
|
4
10
|
PERMISSION_MODES,
|
|
5
11
|
PermissionModeSchema,
|
|
@@ -12,7 +18,7 @@ import {
|
|
|
12
18
|
redactConfig,
|
|
13
19
|
setProjectMcpServerDisabled,
|
|
14
20
|
updateProtectedFile
|
|
15
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-HJOCNKPN.js";
|
|
16
22
|
import {
|
|
17
23
|
AuditLogger,
|
|
18
24
|
appendUsageLog,
|
|
@@ -5326,9 +5332,10 @@ async function ensureOnce(options) {
|
|
|
5326
5332
|
|
|
5327
5333
|
// src/production.ts
|
|
5328
5334
|
import { readFile as readFile22 } from "fs/promises";
|
|
5335
|
+
import { mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync } from "fs";
|
|
5329
5336
|
import { createHash as createHash18, randomUUID as randomUUID20 } from "crypto";
|
|
5330
5337
|
import { homedir as homedir2, release as osRelease, tmpdir as tmpdir4, version as osVersion } from "os";
|
|
5331
|
-
import { basename as basename6, join as join26, relative as relative20, resolve as resolve28, sep as sep20 } from "path";
|
|
5338
|
+
import { basename as basename6, dirname as dirname19, join as join26, relative as relative20, resolve as resolve28, sep as sep20 } from "path";
|
|
5332
5339
|
|
|
5333
5340
|
// src/agent/subagents.ts
|
|
5334
5341
|
import { z as z5 } from "zod";
|
|
@@ -5877,7 +5884,9 @@ import { createHash as createHash4, randomUUID as randomUUID6 } from "crypto";
|
|
|
5877
5884
|
var DEFAULT_COMPACTION_POLICY = {
|
|
5878
5885
|
windowTokens: 2e5,
|
|
5879
5886
|
reservedOutputTokens: 2e4,
|
|
5880
|
-
|
|
5887
|
+
// 85% of the effective window (180_000 - 27_000 = 153_000): compaction used
|
|
5888
|
+
// to trigger at ~92.8%, which let sessions ride the threshold into heap OOM.
|
|
5889
|
+
autoCompactBufferTokens: 27e3,
|
|
5881
5890
|
warningBufferTokens: 2e4,
|
|
5882
5891
|
blockingBufferTokens: 3e3,
|
|
5883
5892
|
microcompactKeepRecentToolResults: 5,
|
|
@@ -6087,6 +6096,13 @@ var ContextManager = class _ContextManager {
|
|
|
6087
6096
|
#epoch;
|
|
6088
6097
|
#visibilityLog = [];
|
|
6089
6098
|
#activeTransientSystem = /* @__PURE__ */ new Map();
|
|
6099
|
+
/**
|
|
6100
|
+
* The visibility audit log persists every transient system admission and is
|
|
6101
|
+
* serialized in full on every session save. Bound both dimensions or a long
|
|
6102
|
+
* subagent-driven run grows it into hundreds of megabytes (heap OOM).
|
|
6103
|
+
*/
|
|
6104
|
+
static VISIBILITY_LOG_MAX_ENTRIES = 1e3;
|
|
6105
|
+
static VISIBILITY_RECORD_CONTENT_LIMIT = 2048;
|
|
6090
6106
|
constructor(options) {
|
|
6091
6107
|
if (options.compactAtChars !== void 0 && options.compactAtChars <= 0) throw new Error("compactAtChars must be positive");
|
|
6092
6108
|
if (options.toolOutputChars <= 0) throw new Error("toolOutputChars must be positive");
|
|
@@ -6182,11 +6198,14 @@ var ContextManager = class _ContextManager {
|
|
|
6182
6198
|
const record = {
|
|
6183
6199
|
id,
|
|
6184
6200
|
role: "system",
|
|
6185
|
-
content,
|
|
6201
|
+
content: limitVisibilityContent(content),
|
|
6186
6202
|
admittedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6187
6203
|
scope: "run"
|
|
6188
6204
|
};
|
|
6189
6205
|
this.#visibilityLog.push(record);
|
|
6206
|
+
if (this.#visibilityLog.length > _ContextManager.VISIBILITY_LOG_MAX_ENTRIES) {
|
|
6207
|
+
this.#visibilityLog = this.#visibilityLog.slice(-_ContextManager.VISIBILITY_LOG_MAX_ENTRIES);
|
|
6208
|
+
}
|
|
6190
6209
|
this.#activeTransientSystem.set(id, { role: "system", content });
|
|
6191
6210
|
return id;
|
|
6192
6211
|
}
|
|
@@ -6210,8 +6229,9 @@ var ContextManager = class _ContextManager {
|
|
|
6210
6229
|
const currentStableHash = currentStable === void 0 ? this.#epoch.stableSourceHash : hashMessages(currentStable);
|
|
6211
6230
|
if (currentStable !== void 0 && currentStableHash !== this.#epoch.stableSourceHash) {
|
|
6212
6231
|
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");
|
|
6213
6233
|
if (this.#epoch.sources["system-baseline"] !== value) {
|
|
6214
|
-
updates.push(contextUpdateMessage("system-baseline", value));
|
|
6234
|
+
updates.push(contextUpdateMessage("system-baseline", deltaSourceValue(previous, value)));
|
|
6215
6235
|
this.#epoch.sources["system-baseline"] = value;
|
|
6216
6236
|
}
|
|
6217
6237
|
} else if (currentStable !== void 0 && this.#epoch.sources["system-baseline"] !== void 0) {
|
|
@@ -6222,7 +6242,7 @@ var ContextManager = class _ContextManager {
|
|
|
6222
6242
|
for (const key of DYNAMIC_SOURCE_ORDER) {
|
|
6223
6243
|
const value = next[key];
|
|
6224
6244
|
if (value === void 0 || value === this.#epoch.sources[key]) continue;
|
|
6225
|
-
updates.push(contextUpdateMessage(key, displaySourceValue(key, value)));
|
|
6245
|
+
updates.push(contextUpdateMessage(key, deltaSourceValue(this.#epoch.sources[key], displaySourceValue(key, value))));
|
|
6226
6246
|
this.#epoch.sources[key] = value;
|
|
6227
6247
|
}
|
|
6228
6248
|
for (const key of DYNAMIC_SOURCE_ORDER) {
|
|
@@ -6249,7 +6269,7 @@ var ContextManager = class _ContextManager {
|
|
|
6249
6269
|
const legacySummary = snapshot4.summary?.role === "system" && snapshot4.summary.content.startsWith("Conversation summary\n") ? snapshot4.summary.content.slice("Conversation summary\n".length) : void 0;
|
|
6250
6270
|
this.#compact = snapshot4.compact === void 0 ? legacySummary === void 0 ? void 0 : { summary: legacySummary, compactedAt: (/* @__PURE__ */ new Date(0)).toISOString() } : { ...snapshot4.compact };
|
|
6251
6271
|
if (snapshot4.epoch !== void 0) this.#epoch = cloneEpoch(snapshot4.epoch);
|
|
6252
|
-
this.#visibilityLog = snapshot4.visibilityLog
|
|
6272
|
+
this.#visibilityLog = boundVisibilityLog(snapshot4.visibilityLog);
|
|
6253
6273
|
this.#activeTransientSystem.clear();
|
|
6254
6274
|
this.#messages = messages.map((message2) => message2.role === "tool" ? { ...message2, content: truncateToolOutput(message2.content, this.#toolOutputChars) } : cloneMessage2(message2));
|
|
6255
6275
|
this.#lastRecordedInputTokens = void 0;
|
|
@@ -6293,6 +6313,10 @@ var ContextManager = class _ContextManager {
|
|
|
6293
6313
|
async prepareForModelCall(signal = new AbortController().signal) {
|
|
6294
6314
|
signal.throwIfAborted();
|
|
6295
6315
|
this.refreshContextSources();
|
|
6316
|
+
if (this.#dropStaleContextUpdates()) {
|
|
6317
|
+
this.#lastRecordedInputTokens = void 0;
|
|
6318
|
+
this.#estimatedTokensAtLastRecordedUsage = void 0;
|
|
6319
|
+
}
|
|
6296
6320
|
if (!this.needsCompaction()) return false;
|
|
6297
6321
|
const originalMessages = this.#messages;
|
|
6298
6322
|
const originalRecordedUsage = this.#lastRecordedInputTokens;
|
|
@@ -6392,6 +6416,26 @@ var ContextManager = class _ContextManager {
|
|
|
6392
6416
|
this.#reportCompactProgress(100);
|
|
6393
6417
|
return true;
|
|
6394
6418
|
}
|
|
6419
|
+
#dropStaleContextUpdates() {
|
|
6420
|
+
const latestBySource = /* @__PURE__ */ new Map();
|
|
6421
|
+
for (let index = this.#messages.length - 1; index >= 0; index -= 1) {
|
|
6422
|
+
const source = contextUpdateSource(this.#messages[index]);
|
|
6423
|
+
if (source === void 0 || latestBySource.has(source)) continue;
|
|
6424
|
+
latestBySource.set(source, index);
|
|
6425
|
+
}
|
|
6426
|
+
const next = [];
|
|
6427
|
+
let changed = false;
|
|
6428
|
+
this.#messages.forEach((message2, index) => {
|
|
6429
|
+
const source = contextUpdateSource(message2);
|
|
6430
|
+
if (source !== void 0 && latestBySource.get(source) !== index) {
|
|
6431
|
+
changed = true;
|
|
6432
|
+
return;
|
|
6433
|
+
}
|
|
6434
|
+
next.push(message2);
|
|
6435
|
+
});
|
|
6436
|
+
if (changed) this.#messages = next;
|
|
6437
|
+
return changed;
|
|
6438
|
+
}
|
|
6395
6439
|
#reportCompactProgress(percentage) {
|
|
6396
6440
|
const normalized = Math.max(0, Math.min(100, Math.floor(percentage / 10) * 10));
|
|
6397
6441
|
if (normalized === this.#lastCompactProgress) return;
|
|
@@ -6503,6 +6547,33 @@ function contextUpdateMessage(source, content) {
|
|
|
6503
6547
|
return { role: "system", content: `Context update [${source}]
|
|
6504
6548
|
${content}` };
|
|
6505
6549
|
}
|
|
6550
|
+
var CONTEXT_UPDATE_PREFIX = "Context update [";
|
|
6551
|
+
function contextUpdateSource(message2) {
|
|
6552
|
+
if (message2.role !== "system" || typeof message2.content !== "string") return void 0;
|
|
6553
|
+
if (!message2.content.startsWith(CONTEXT_UPDATE_PREFIX)) return void 0;
|
|
6554
|
+
const end = message2.content.indexOf("]\n", CONTEXT_UPDATE_PREFIX.length);
|
|
6555
|
+
if (end < 0) return void 0;
|
|
6556
|
+
return message2.content.slice(CONTEXT_UPDATE_PREFIX.length, end);
|
|
6557
|
+
}
|
|
6558
|
+
function deltaSourceValue(previous, display) {
|
|
6559
|
+
if (previous === void 0 || !display.startsWith(previous)) return display;
|
|
6560
|
+
return display.slice(previous.length).replace(/^\s+/, "") || display;
|
|
6561
|
+
}
|
|
6562
|
+
function limitVisibilityContent(content) {
|
|
6563
|
+
const limit = ContextManager.VISIBILITY_RECORD_CONTENT_LIMIT;
|
|
6564
|
+
if (content.length <= limit) return content;
|
|
6565
|
+
return `${content.slice(0, limit)}
|
|
6566
|
+
...[truncated; original length: ${content.length} characters]...`;
|
|
6567
|
+
}
|
|
6568
|
+
function boundVisibilityLog(records) {
|
|
6569
|
+
if (records === void 0) return [];
|
|
6570
|
+
const limit = ContextManager.VISIBILITY_RECORD_CONTENT_LIMIT;
|
|
6571
|
+
const bounded2 = records.map((item) => ({
|
|
6572
|
+
...item,
|
|
6573
|
+
...item.content.length <= limit ? {} : { content: limitVisibilityContent(item.content) }
|
|
6574
|
+
}));
|
|
6575
|
+
return bounded2.length > ContextManager.VISIBILITY_LOG_MAX_ENTRIES ? bounded2.slice(-ContextManager.VISIBILITY_LOG_MAX_ENTRIES) : bounded2;
|
|
6576
|
+
}
|
|
6506
6577
|
function cloneEpoch(epoch) {
|
|
6507
6578
|
return {
|
|
6508
6579
|
...epoch,
|
|
@@ -6797,6 +6868,9 @@ function reportProgress(callback, percentage) {
|
|
|
6797
6868
|
}
|
|
6798
6869
|
}
|
|
6799
6870
|
|
|
6871
|
+
// src/agent/loop.ts
|
|
6872
|
+
import { getHeapStatistics } from "v8";
|
|
6873
|
+
|
|
6800
6874
|
// src/models/structured.ts
|
|
6801
6875
|
import { z as z7 } from "zod";
|
|
6802
6876
|
var DEFAULT_RETRY_DELAYS = [1e3, 2e3, 4e3];
|
|
@@ -7214,6 +7288,18 @@ function envMaxIterations() {
|
|
|
7214
7288
|
if (!Number.isInteger(parsed) || parsed <= 0) return void 0;
|
|
7215
7289
|
return parsed;
|
|
7216
7290
|
}
|
|
7291
|
+
var MEMORY_PRESSURE_HEAP_RATIO = 0.8;
|
|
7292
|
+
function memoryPressureError(heapUsed, heapLimit) {
|
|
7293
|
+
if (heapLimit <= 0 || heapUsed < heapLimit * MEMORY_PRESSURE_HEAP_RATIO) return void 0;
|
|
7294
|
+
const mb = (bytes) => Math.round(bytes / 1048576);
|
|
7295
|
+
return {
|
|
7296
|
+
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.`
|
|
7298
|
+
};
|
|
7299
|
+
}
|
|
7300
|
+
function currentMemoryPressure() {
|
|
7301
|
+
return memoryPressureError(process.memoryUsage().heapUsed, getHeapStatistics().heap_size_limit);
|
|
7302
|
+
}
|
|
7217
7303
|
var AgentLoop = class {
|
|
7218
7304
|
#options;
|
|
7219
7305
|
#iterationLimitMode = "standard";
|
|
@@ -7284,6 +7370,11 @@ var AgentLoop = class {
|
|
|
7284
7370
|
yield { type: "error", error: { code: "cancelled", message: abortMessage(request.signal) } };
|
|
7285
7371
|
return;
|
|
7286
7372
|
}
|
|
7373
|
+
const pressure = currentMemoryPressure();
|
|
7374
|
+
if (pressure !== void 0) {
|
|
7375
|
+
yield { type: "error", error: pressure };
|
|
7376
|
+
return;
|
|
7377
|
+
}
|
|
7287
7378
|
const softLimit = Math.floor(maxIterations * this.#options.softLimitFactor);
|
|
7288
7379
|
if (!warned && iteration >= softLimit) {
|
|
7289
7380
|
warned = true;
|
|
@@ -12679,7 +12770,8 @@ var BoundedOutput = class {
|
|
|
12679
12770
|
#headLimit;
|
|
12680
12771
|
#tailLimit;
|
|
12681
12772
|
#head = Buffer.alloc(0);
|
|
12682
|
-
#
|
|
12773
|
+
#tailChunks = [];
|
|
12774
|
+
#tailBytes = 0;
|
|
12683
12775
|
#complete = Buffer.alloc(0);
|
|
12684
12776
|
#bytes = 0;
|
|
12685
12777
|
constructor(limit) {
|
|
@@ -12699,15 +12791,24 @@ var BoundedOutput = class {
|
|
|
12699
12791
|
const count = Math.min(this.#headLimit - this.#head.length, chunk.length);
|
|
12700
12792
|
this.#head = Buffer.concat([this.#head, chunk.subarray(0, count)]);
|
|
12701
12793
|
}
|
|
12702
|
-
if (this.#tailLimit > 0)
|
|
12794
|
+
if (this.#tailLimit > 0) {
|
|
12795
|
+
this.#tailChunks.push(chunk);
|
|
12796
|
+
this.#tailBytes += chunk.length;
|
|
12797
|
+
if (this.#tailBytes >= this.#tailLimit * 2) {
|
|
12798
|
+
const merged = Buffer.concat(this.#tailChunks).subarray(-this.#tailLimit);
|
|
12799
|
+
this.#tailChunks = [merged];
|
|
12800
|
+
this.#tailBytes = merged.length;
|
|
12801
|
+
}
|
|
12802
|
+
}
|
|
12703
12803
|
}
|
|
12704
12804
|
metadata() {
|
|
12705
12805
|
return { truncated: this.truncated, originalBytes: this.#bytes, limitBytes: this.#limit };
|
|
12706
12806
|
}
|
|
12707
12807
|
text() {
|
|
12708
12808
|
if (!this.truncated) return decodeOutput(this.#complete);
|
|
12809
|
+
const tail = Buffer.concat(this.#tailChunks).subarray(-this.#tailLimit);
|
|
12709
12810
|
const encoding = classifyUtf8(this.#complete) === "invalid" && process.platform === "win32" ? "gb18030" : "utf-8";
|
|
12710
|
-
return `${decodePrefix(this.#head, encoding)}${ELLIPSIS}${decodeSuffix(
|
|
12811
|
+
return `${decodePrefix(this.#head, encoding)}${ELLIPSIS}${decodeSuffix(tail, encoding)}`;
|
|
12711
12812
|
}
|
|
12712
12813
|
};
|
|
12713
12814
|
var AdaptiveOutputDecoder = class {
|
|
@@ -22634,7 +22735,7 @@ async function createProductionRuntime(options) {
|
|
|
22634
22735
|
contextEpoch: harness.main.context.snapshot().epoch?.id ?? "legacy"
|
|
22635
22736
|
});
|
|
22636
22737
|
const turnId = harnessJournal.startTurn(turnConfig, { prompt, initialUserMessage: runOptions?.initialUserMessage });
|
|
22637
|
-
return durableTurn(persistAndCheckpointAfter(runMain(
|
|
22738
|
+
return monitorMemoryRestart(durableTurn(persistAndCheckpointAfter(runMain(
|
|
22638
22739
|
harness,
|
|
22639
22740
|
skills,
|
|
22640
22741
|
prompt,
|
|
@@ -22654,7 +22755,7 @@ async function createProductionRuntime(options) {
|
|
|
22654
22755
|
prompt,
|
|
22655
22756
|
context: harness.main.context.snapshot(),
|
|
22656
22757
|
label: `turn: ${prompt.slice(0, 80)}`
|
|
22657
|
-
})), harnessJournal, turnId, turnConfig);
|
|
22758
|
+
})), harnessJournal, turnId, turnConfig), () => requestMemoryRestart(workspace, sessionId, emitOutput));
|
|
22658
22759
|
},
|
|
22659
22760
|
runSkill: (skill, prompt, signal) => persistAfter(
|
|
22660
22761
|
runExplicitSkill(harness, skills, skill, prompt, signal, selectedModels.mainError),
|
|
@@ -23403,6 +23504,31 @@ async function* durableTurn(source, journal, turnId, config) {
|
|
|
23403
23504
|
}
|
|
23404
23505
|
}
|
|
23405
23506
|
}
|
|
23507
|
+
async function* monitorMemoryRestart(source, onRestartNeeded) {
|
|
23508
|
+
let pressure = false;
|
|
23509
|
+
for await (const event of source) {
|
|
23510
|
+
if (event.type === "error" && event.error.code === "memory_pressure") pressure = true;
|
|
23511
|
+
yield event;
|
|
23512
|
+
}
|
|
23513
|
+
if (pressure) onRestartNeeded();
|
|
23514
|
+
}
|
|
23515
|
+
function requestMemoryRestart(workspace, sessionId, emitOutput) {
|
|
23516
|
+
try {
|
|
23517
|
+
const markerPath = memoryRestartMarkerPath(workspace);
|
|
23518
|
+
let previous;
|
|
23519
|
+
try {
|
|
23520
|
+
previous = parseMemoryRestartMarker(readFileSync3(markerPath, "utf8"));
|
|
23521
|
+
} catch {
|
|
23522
|
+
}
|
|
23523
|
+
mkdirSync3(dirname19(markerPath), { recursive: true });
|
|
23524
|
+
writeFileSync(markerPath, `${JSON.stringify(nextMemoryRestartMarker(previous, sessionId, /* @__PURE__ */ new Date()))}
|
|
23525
|
+
`, "utf8");
|
|
23526
|
+
} catch {
|
|
23527
|
+
}
|
|
23528
|
+
process.exitCode = MEMORY_RESTART_EXIT_CODE;
|
|
23529
|
+
emitOutput({ type: "notice", message: "Memory watermark reached; the session is saved and Flavor is restarting with a fresh heap." });
|
|
23530
|
+
emitOutput({ type: "exit" });
|
|
23531
|
+
}
|
|
23406
23532
|
async function runGitCommit(deps, hint, signal) {
|
|
23407
23533
|
if (!await isGitRepository(deps.workspace)) return "Not a git repository \u2014 /commit needs git.";
|
|
23408
23534
|
let summary2 = await changeSummary(deps.workspace);
|
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-LMFN2QEA.js";
|
|
7
7
|
import {
|
|
8
8
|
staticTaskLines
|
|
9
9
|
} from "./chunk-2BF7CVWZ.js";
|
|
@@ -23,7 +23,8 @@ import {
|
|
|
23
23
|
packageVersion,
|
|
24
24
|
redactErrorText,
|
|
25
25
|
runPalBroker
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-S525EOFQ.js";
|
|
27
|
+
import "./chunk-CIVPKHF4.js";
|
|
27
28
|
import {
|
|
28
29
|
McpServerConfigSchema,
|
|
29
30
|
McpServerNameSchema,
|
|
@@ -32,7 +33,7 @@ import {
|
|
|
32
33
|
readRecoverableFile,
|
|
33
34
|
setProjectSkillDisabled,
|
|
34
35
|
updateProtectedFile
|
|
35
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-HJOCNKPN.js";
|
|
36
37
|
import "./chunk-RQTYHUMK.js";
|
|
37
38
|
import "./chunk-S32JRDZK.js";
|
|
38
39
|
|
|
@@ -750,7 +751,7 @@ async function runEvaluationFile(path, outputPath) {
|
|
|
750
751
|
})),
|
|
751
752
|
...parsed.maxTokens === void 0 ? {} : { maxTokens: parsed.maxTokens }
|
|
752
753
|
};
|
|
753
|
-
const configured = await import("./load-
|
|
754
|
+
const configured = await import("./load-DELQW42K.js").then(({ loadConfig: loadConfig2 }) => loadConfig2({ cwd: workspace, home: process.env.USERPROFILE ?? process.env.HOME ?? workspace }));
|
|
754
755
|
const environment = createExecutionEnvironment(workspace, configured.config.execution) ?? new LocalExecutionEnvironment();
|
|
755
756
|
let report;
|
|
756
757
|
try {
|
|
@@ -877,7 +878,7 @@ async function runInteractiveCli(props) {
|
|
|
877
878
|
const [{ render, AlternateScreen }, { createElement }, { App }] = await Promise.all([
|
|
878
879
|
import("./claude-ink-ORUA7GWG.js"),
|
|
879
880
|
import("react"),
|
|
880
|
-
import("./app-
|
|
881
|
+
import("./app-6SEGTMMC.js")
|
|
881
882
|
]);
|
|
882
883
|
const instance = await render(createElement(
|
|
883
884
|
AlternateScreen,
|
package/dist/cli.js
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from "node:module"; const require = createRequire(import.meta.url);
|
|
3
|
+
import {
|
|
4
|
+
MEMORY_RESTART_EXIT_CODE,
|
|
5
|
+
memoryRestartArgs,
|
|
6
|
+
memoryRestartMarkerPath,
|
|
7
|
+
parseMemoryRestartMarker
|
|
8
|
+
} from "./chunk-CIVPKHF4.js";
|
|
3
9
|
import "./chunk-S32JRDZK.js";
|
|
4
10
|
|
|
5
11
|
// src/launcher.ts
|
|
6
12
|
import { spawn } from "child_process";
|
|
7
|
-
import { realpathSync } from "fs";
|
|
13
|
+
import { realpathSync, readFileSync } from "fs";
|
|
8
14
|
import { release } from "os";
|
|
9
15
|
import { fileURLToPath } from "url";
|
|
10
16
|
function needsWindowsMaglevWorkaround(runtime) {
|
|
@@ -14,9 +20,23 @@ function needsWindowsMaglevWorkaround(runtime) {
|
|
|
14
20
|
if (build !== 26200 || major < 24) return false;
|
|
15
21
|
return !runtime.execArgv.some((argument) => argument === "--no-maglev" || argument === "--jitless");
|
|
16
22
|
}
|
|
23
|
+
function needsRelaunch(runtime) {
|
|
24
|
+
if (needsWindowsMaglevWorkaround(runtime)) return true;
|
|
25
|
+
if (!runtime.execArgv.some((argument) => argument === "--report-on-fatalerror")) return true;
|
|
26
|
+
return !runtime.execArgv.some((argument) => argument.startsWith("--heapsnapshot-near-heap-limit"));
|
|
27
|
+
}
|
|
17
28
|
function cliMainArguments(runtime, mainPath, argv) {
|
|
18
29
|
return [
|
|
19
30
|
...needsWindowsMaglevWorkaround(runtime) ? ["--no-maglev"] : [],
|
|
31
|
+
// Fatal V8 errors (heap OOM, native crashes) bypass crash-guard.ts and
|
|
32
|
+
// leave only an unusable native stack. Ask Node to dump a diagnostic
|
|
33
|
+
// report next to the working directory so the next crash has a scene.
|
|
34
|
+
"--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.
|
|
37
|
+
// Capture one heap snapshot as the heap nears its limit so the next
|
|
38
|
+
// crash leaves a .heapsnapshot retainer trail next to the report.
|
|
39
|
+
"--heapsnapshot-near-heap-limit=1",
|
|
20
40
|
mainPath,
|
|
21
41
|
...argv
|
|
22
42
|
];
|
|
@@ -29,26 +49,48 @@ async function launchCli() {
|
|
|
29
49
|
nodeVersion: process.version,
|
|
30
50
|
execArgv: process.execArgv
|
|
31
51
|
};
|
|
32
|
-
if (!
|
|
52
|
+
if (!needsRelaunch(runtime)) {
|
|
33
53
|
const cli = await import(mainUrl.href);
|
|
34
54
|
await cli.runCli(process.argv);
|
|
35
55
|
return;
|
|
36
56
|
}
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
57
|
+
const mainPath = fileURLToPath(mainUrl);
|
|
58
|
+
let argv = process.argv.slice(2);
|
|
59
|
+
for (; ; ) {
|
|
60
|
+
const code = await spawnAndWait(runtime, mainPath, argv);
|
|
61
|
+
if (code === MEMORY_RESTART_EXIT_CODE) {
|
|
62
|
+
let marker;
|
|
63
|
+
try {
|
|
64
|
+
marker = parseMemoryRestartMarker(readFileSync(memoryRestartMarkerPath(process.cwd()), "utf8"));
|
|
65
|
+
} catch {
|
|
66
|
+
marker = void 0;
|
|
67
|
+
}
|
|
68
|
+
const resumed = memoryRestartArgs(argv, marker);
|
|
69
|
+
if (resumed !== void 0) {
|
|
70
|
+
process.stderr.write(`flavor launcher: heap watermark restart, resuming session ${marker.sessionId}
|
|
71
|
+
`);
|
|
72
|
+
argv = resumed;
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
if (marker !== void 0) {
|
|
76
|
+
process.stderr.write("flavor launcher: heap watermark restart budget exhausted; restart manually and consider a fresh session.\n");
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
process.exitCode = code;
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
async function spawnAndWait(runtime, mainPath, argv) {
|
|
84
|
+
const child = spawn(process.execPath, cliMainArguments(runtime, mainPath, argv), { stdio: "inherit" });
|
|
42
85
|
const ignoreSignal = () => {
|
|
43
86
|
};
|
|
44
87
|
process.on("SIGINT", ignoreSignal);
|
|
45
88
|
process.on("SIGBREAK", ignoreSignal);
|
|
46
89
|
try {
|
|
47
|
-
|
|
90
|
+
return await new Promise((resolvePromise, reject) => {
|
|
48
91
|
child.once("error", reject);
|
|
49
92
|
child.once("exit", (exitCode) => resolvePromise(exitCode ?? 1));
|
|
50
93
|
});
|
|
51
|
-
process.exitCode = code;
|
|
52
94
|
} finally {
|
|
53
95
|
process.off("SIGINT", ignoreSignal);
|
|
54
96
|
process.off("SIGBREAK", ignoreSignal);
|
|
@@ -69,5 +111,6 @@ if (process.argv[1]) {
|
|
|
69
111
|
export {
|
|
70
112
|
cliMainArguments,
|
|
71
113
|
launchCli,
|
|
114
|
+
needsRelaunch,
|
|
72
115
|
needsWindowsMaglevWorkaround
|
|
73
116
|
};
|
|
@@ -67,6 +67,13 @@ export type ContextForkOptions = Partial<Pick<ContextManagerOptions, "summarize"
|
|
|
67
67
|
export { estimateTokens } from "./compaction.js";
|
|
68
68
|
export declare class ContextManager {
|
|
69
69
|
#private;
|
|
70
|
+
/**
|
|
71
|
+
* The visibility audit log persists every transient system admission and is
|
|
72
|
+
* serialized in full on every session save. Bound both dimensions or a long
|
|
73
|
+
* subagent-driven run grows it into hundreds of megabytes (heap OOM).
|
|
74
|
+
*/
|
|
75
|
+
static readonly VISIBILITY_LOG_MAX_ENTRIES = 1000;
|
|
76
|
+
static readonly VISIBILITY_RECORD_CONTENT_LIMIT = 2048;
|
|
70
77
|
constructor(options: ContextManagerOptions);
|
|
71
78
|
clear(): void;
|
|
72
79
|
/**
|