@wrongstack/core 0.310.1 → 0.313.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chronicle/index.js +84 -6391
- package/dist/chronicle/project-server.js +84 -4868
- package/dist/chunk-2BUUIMQB.js +225 -0
- package/dist/chunk-2FK4WTFF.js +207 -0
- package/dist/chunk-2FQL4PDC.js +292 -0
- package/dist/chunk-2KKODIQU.js +2256 -0
- package/dist/chunk-2YU4WVBW.js +134 -0
- package/dist/chunk-3E244UDA.js +356 -0
- package/dist/chunk-3XPVB7BA.js +135 -0
- package/dist/chunk-4LJJYBAU.js +388 -0
- package/dist/chunk-4VWO3ZXL.js +342 -0
- package/dist/chunk-4XV6IR37.js +187 -0
- package/dist/chunk-4ZHTKJHM.js +183 -0
- package/dist/chunk-52RTVH4M.js +361 -0
- package/dist/chunk-57GEWK5X.js +26 -0
- package/dist/chunk-5DSMEVA4.js +931 -0
- package/dist/chunk-5RP3QTRL.js +1223 -0
- package/dist/chunk-5S437PRC.js +50 -0
- package/dist/chunk-5XDUGTKN.js +511 -0
- package/dist/chunk-62V2AFVG.js +422 -0
- package/dist/chunk-65RDIOR2.js +2470 -0
- package/dist/chunk-6AKOTGLM.js +597 -0
- package/dist/chunk-7ZHZE5EO.js +28 -0
- package/dist/chunk-A455ATZB.js +140 -0
- package/dist/chunk-AD7ZFZCS.js +46 -0
- package/dist/chunk-AI4LLQ2U.js +856 -0
- package/dist/chunk-ASX6AW36.js +789 -0
- package/dist/chunk-AT4V4XGI.js +3522 -0
- package/dist/chunk-AWNQ6ED6.js +311 -0
- package/dist/chunk-B4AMLZPB.js +9 -0
- package/dist/chunk-BAKVJLEV.js +417 -0
- package/dist/chunk-BJHVULHO.js +55 -0
- package/dist/chunk-CB2HFKTP.js +9 -0
- package/dist/chunk-CE4ZOCOI.js +1640 -0
- package/dist/chunk-CQQL4ZOQ.js +151 -0
- package/dist/chunk-DEIQMBD2.js +65 -0
- package/dist/chunk-E6I5RXVK.js +58 -0
- package/dist/chunk-EFEHDQGY.js +1589 -0
- package/dist/chunk-EODDVJBM.js +82 -0
- package/dist/chunk-EPC3GZD4.js +308 -0
- package/dist/chunk-FAYRX2AD.js +13 -0
- package/dist/chunk-FFSX2QDQ.js +362 -0
- package/dist/chunk-FHAMQS7Q.js +5856 -0
- package/dist/chunk-FIV4IJL7.js +2263 -0
- package/dist/chunk-FNXVT7HF.js +52 -0
- package/dist/chunk-FSWCWSTS.js +395 -0
- package/dist/chunk-FW5LDDMJ.js +16464 -0
- package/dist/chunk-FXQLIX3K.js +211 -0
- package/dist/chunk-G5AAKEEZ.js +228 -0
- package/dist/chunk-G5S3S5ZN.js +38 -0
- package/dist/chunk-GAZEWQEZ.js +231 -0
- package/dist/chunk-GFJOMSHG.js +125 -0
- package/dist/chunk-GFXZTHNI.js +158 -0
- package/dist/chunk-GM54GJBU.js +960 -0
- package/dist/chunk-GPQ3NJPR.js +900 -0
- package/dist/chunk-GTCU6DZ3.js +1 -0
- package/dist/chunk-H5E77KUJ.js +15 -0
- package/dist/chunk-H72H4XDU.js +1023 -0
- package/dist/chunk-HA4ZYA6T.js +178 -0
- package/dist/chunk-I45KAW2N.js +5020 -0
- package/dist/chunk-IQ35HMQL.js +1396 -0
- package/dist/chunk-IYFBFX34.js +86 -0
- package/dist/chunk-JJPMWPB6.js +109 -0
- package/dist/chunk-JTHKOYWU.js +663 -0
- package/dist/chunk-JVGPR3TS.js +365 -0
- package/dist/chunk-JVKB2TBL.js +48 -0
- package/dist/chunk-JX7VBZDK.js +31 -0
- package/dist/chunk-K3G6JBUC.js +5232 -0
- package/dist/chunk-K4YUNKU7.js +589 -0
- package/dist/chunk-KBZGE6LN.js +710 -0
- package/dist/chunk-KDQJCT2J.js +45 -0
- package/dist/chunk-KI4L2DUL.js +560 -0
- package/dist/chunk-KJ2ZTQSL.js +47 -0
- package/dist/chunk-KSJ5UTP7.js +154 -0
- package/dist/chunk-LHOA5DWA.js +28 -0
- package/dist/chunk-LX5QWLBL.js +27 -0
- package/dist/chunk-LZDDLNCZ.js +279 -0
- package/dist/chunk-M2WF6AXG.js +115 -0
- package/dist/chunk-M7BS2K6U.js +1 -0
- package/dist/chunk-NDBIPFNY.js +102 -0
- package/dist/chunk-NEMIWEXC.js +1199 -0
- package/dist/chunk-NFAYHPRH.js +323 -0
- package/dist/chunk-O37BQ65S.js +21 -0
- package/dist/chunk-O74MJHXU.js +187 -0
- package/dist/chunk-OJZEX73F.js +112 -0
- package/dist/chunk-PAAWLLZX.js +74 -0
- package/dist/chunk-PFXFQQRT.js +339 -0
- package/dist/chunk-PFZO3C6H.js +14 -0
- package/dist/chunk-PHH7LD45.js +113 -0
- package/dist/chunk-QRTG4XTI.js +188 -0
- package/dist/chunk-QVOVMXJR.js +1351 -0
- package/dist/chunk-RCQYT2I4.js +757 -0
- package/dist/chunk-RD6DEE36.js +1178 -0
- package/dist/chunk-RJIZEJ42.js +30 -0
- package/dist/chunk-RPOA7IAE.js +150 -0
- package/dist/chunk-SN2DQRL6.js +1172 -0
- package/dist/chunk-SQJVFEBV.js +41 -0
- package/dist/chunk-SQP64RCS.js +5391 -0
- package/dist/chunk-SVT4RNTR.js +49 -0
- package/dist/chunk-SWUFN7XM.js +43 -0
- package/dist/chunk-SXMVYC5H.js +174 -0
- package/dist/chunk-SZ6AYUIZ.js +23 -0
- package/dist/chunk-T3KGZBU5.js +3171 -0
- package/dist/chunk-TBRL2RCC.js +9 -0
- package/dist/chunk-TRT2HRWZ.js +18 -0
- package/dist/chunk-TYW2GI5I.js +1077 -0
- package/dist/chunk-UIWONWVG.js +4959 -0
- package/dist/chunk-VB3H5WWB.js +151 -0
- package/dist/chunk-W4A6QA3D.js +258 -0
- package/dist/chunk-WBPVKEEE.js +227 -0
- package/dist/chunk-WEBMSQP2.js +123 -0
- package/dist/chunk-WOEZV3Q4.js +333 -0
- package/dist/chunk-WQQON3SV.js +473 -0
- package/dist/chunk-WQTOVMGV.js +119 -0
- package/dist/chunk-WZO23AWO.js +2779 -0
- package/dist/chunk-XBDP4QPW.js +7 -0
- package/dist/chunk-XEBHSJLT.js +103 -0
- package/dist/chunk-XQ2ECNK3.js +1 -0
- package/dist/chunk-XQ2XGIBF.js +2086 -0
- package/dist/chunk-Y2GE5TSI.js +355 -0
- package/dist/chunk-YBUJCZ57.js +351 -0
- package/dist/chunk-YNCVSFGF.js +149 -0
- package/dist/chunk-YUPMXOGP.js +282 -0
- package/dist/chunk-YY6APYUM.js +49 -0
- package/dist/chunk-Z2IJUO45.js +691 -0
- package/dist/chunk-ZEHUCJHY.js +129 -0
- package/dist/chunk-ZYU2YOJ6.js +1496 -0
- package/dist/chunk-ZZ4V3WIZ.js +163 -0
- package/dist/coordination/agents/index.js +145 -6260
- package/dist/coordination/index.js +365 -34323
- package/dist/coordination/mailbox-project-server.js +48 -3220
- package/dist/coordination/mailbox-types.d.ts +13 -1
- package/dist/coordination/provider-status-tracker.d.ts +4 -0
- package/dist/coordination/sqlite-mailbox.d.ts +2 -1
- package/dist/core/agent.d.ts +14 -1
- package/dist/core/index.js +267 -12479
- package/dist/core/model-ref.js +5 -23
- package/dist/core/provider-runner.d.ts +36 -1
- package/dist/design/index.js +50 -1087
- package/dist/execution/index.d.ts +1 -1
- package/dist/execution/index.js +1599 -21887
- package/dist/execution/prompt-enhancer.js +16 -535
- package/dist/execution/retry-policy.d.ts +31 -1
- package/dist/extension/index.js +7 -311
- package/dist/goal/index.js +33 -3435
- package/dist/hooks/index.js +14 -1138
- package/dist/hq/index.js +112 -5139
- package/dist/hq/protocol.js +21 -668
- package/dist/index.js +1410 -92655
- package/dist/infrastructure/index.js +64 -4811
- package/dist/kernel/events/provider-events.d.ts +15 -0
- package/dist/kernel/events/wrongtrace-events.d.ts +26 -0
- package/dist/kernel/events.d.ts +16 -7
- package/dist/kernel/index.js +14 -992
- package/dist/models/index.js +40 -1117
- package/dist/notifications/index.js +3 -108
- package/dist/observability/index.js +17 -279
- package/dist/plugin/index.js +584 -14835
- package/dist/prompts/index.js +14 -948
- package/dist/registry/index.js +9 -822
- package/dist/registry-R23UBE7H.js +14 -0
- package/dist/replay/index.js +6 -84
- package/dist/review-finding-store-DKAV3AS6.js +21 -0
- package/dist/review-report-store-OWY3EC3N.js +19 -0
- package/dist/security/index.js +114 -2202
- package/dist/session-catalog/index.js +36 -2103
- package/dist/session-catalog/project-server.js +42 -1435
- package/dist/skills/index.js +35 -1578
- package/dist/storage/index.js +182 -15600
- package/dist/tasking/index.js +10 -676
- package/dist/tools/index.js +52 -9589
- package/dist/types/config/autonomy.d.ts +5 -0
- package/dist/types/config/tools.d.ts +2 -2
- package/dist/types/config/ui.d.ts +1 -1
- package/dist/types/errors.d.ts +18 -0
- package/dist/types/index.js +121 -1341
- package/dist/types/provider-runner.d.ts +8 -0
- package/dist/types/session-markers.js +8 -144
- package/dist/utils/error.js +3 -4
- package/dist/utils/expect-defined.js +3 -9
- package/dist/utils/heap-watchdog.js +6 -706
- package/dist/utils/index.js +269 -5685
- package/dist/utils/sage-output-block.js +5 -42
- package/dist/wiring/proxy-rewrite.d.ts +92 -4
- package/dist/wiring/proxy-rewrite.js +20 -61
- package/dist/worktree/index.js +6 -887
- package/package.json +4 -4
|
@@ -0,0 +1,710 @@
|
|
|
1
|
+
import {
|
|
2
|
+
wstackGlobalRoot
|
|
3
|
+
} from "./chunk-YNCVSFGF.js";
|
|
4
|
+
|
|
5
|
+
// src/utils/heap-watchdog.ts
|
|
6
|
+
import * as fs from "node:fs";
|
|
7
|
+
import * as fsp2 from "node:fs/promises";
|
|
8
|
+
import * as path2 from "node:path";
|
|
9
|
+
import {
|
|
10
|
+
PerformanceObserver,
|
|
11
|
+
constants as performanceConstants
|
|
12
|
+
} from "node:perf_hooks";
|
|
13
|
+
import * as v8 from "node:v8";
|
|
14
|
+
|
|
15
|
+
// src/utils/memory-flight-recorder.ts
|
|
16
|
+
import * as fsp from "node:fs/promises";
|
|
17
|
+
import * as path from "node:path";
|
|
18
|
+
|
|
19
|
+
// src/utils/continuous-memory-profiler.ts
|
|
20
|
+
import { Session } from "node:inspector/promises";
|
|
21
|
+
var DEFAULT_SAMPLE_INTERVAL_BYTES = 512 * 1024;
|
|
22
|
+
var DEFAULT_STACK_DEPTH = 64;
|
|
23
|
+
var MAX_SUMMARY_STACKS = 20;
|
|
24
|
+
var MAX_FRAMES_PER_STACK = 12;
|
|
25
|
+
function errorMessage(error) {
|
|
26
|
+
return error instanceof Error ? error.message : String(error);
|
|
27
|
+
}
|
|
28
|
+
function numeric(value) {
|
|
29
|
+
if (typeof value === "bigint") return Number(value);
|
|
30
|
+
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
31
|
+
}
|
|
32
|
+
function summarizePprof(profile) {
|
|
33
|
+
const strings = profile.stringTable.strings;
|
|
34
|
+
const functions = new Map(profile.function.map((entry) => [numeric(entry.id), entry]));
|
|
35
|
+
const locations = new Map(profile.location.map((entry) => [numeric(entry.id), entry]));
|
|
36
|
+
const stacks = /* @__PURE__ */ new Map();
|
|
37
|
+
let sampledBytes = 0;
|
|
38
|
+
let sampledObjects = 0;
|
|
39
|
+
for (const sample of profile.sample) {
|
|
40
|
+
const objects = numeric(sample.value[0]);
|
|
41
|
+
const bytes = numeric(sample.value[1]);
|
|
42
|
+
sampledObjects += objects;
|
|
43
|
+
sampledBytes += bytes;
|
|
44
|
+
const frames = sample.locationId.slice(0, MAX_FRAMES_PER_STACK).flatMap((locationId) => {
|
|
45
|
+
const location = locations.get(numeric(locationId));
|
|
46
|
+
const line = location?.line[0];
|
|
47
|
+
const fn = line ? functions.get(numeric(line.functionId)) : void 0;
|
|
48
|
+
if (!fn) return [];
|
|
49
|
+
const name = strings[numeric(fn.name)] || "(anonymous)";
|
|
50
|
+
const filename = strings[numeric(fn.filename)] || "";
|
|
51
|
+
const lineNumber = numeric(line?.line);
|
|
52
|
+
return [filename ? `${name} (${filename}${lineNumber > 0 ? `:${lineNumber}` : ""})` : name];
|
|
53
|
+
});
|
|
54
|
+
if (frames.length === 0) frames.push("(unknown)");
|
|
55
|
+
const key = frames.join("\n");
|
|
56
|
+
const existing = stacks.get(key);
|
|
57
|
+
if (existing) {
|
|
58
|
+
existing.bytes += bytes;
|
|
59
|
+
existing.objects += objects;
|
|
60
|
+
} else {
|
|
61
|
+
stacks.set(key, { bytes, objects, frames });
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
sampledBytes,
|
|
66
|
+
sampledObjects,
|
|
67
|
+
sampleCount: profile.sample.length,
|
|
68
|
+
topStacks: [...stacks.values()].sort((left, right) => right.bytes - left.bytes).slice(0, MAX_SUMMARY_STACKS)
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
async function startDatadogProfiler() {
|
|
72
|
+
const pprof = await import("@datadog/pprof");
|
|
73
|
+
pprof.heap.start(DEFAULT_SAMPLE_INTERVAL_BYTES, DEFAULT_STACK_DEPTH);
|
|
74
|
+
let stopped = false;
|
|
75
|
+
return {
|
|
76
|
+
backend: "datadog-pprof",
|
|
77
|
+
capture: async () => {
|
|
78
|
+
if (stopped) throw new Error("Continuous memory profiler is stopped");
|
|
79
|
+
const profile = pprof.heap.profile();
|
|
80
|
+
return {
|
|
81
|
+
backend: "datadog-pprof",
|
|
82
|
+
data: await pprof.encode(profile),
|
|
83
|
+
extension: ".pb.gz",
|
|
84
|
+
summary: summarizePprof(profile)
|
|
85
|
+
};
|
|
86
|
+
},
|
|
87
|
+
stop: async () => {
|
|
88
|
+
if (stopped) return;
|
|
89
|
+
stopped = true;
|
|
90
|
+
pprof.heap.stop();
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
async function startInspectorProfiler() {
|
|
95
|
+
const session = new Session();
|
|
96
|
+
session.connect();
|
|
97
|
+
try {
|
|
98
|
+
await session.post("HeapProfiler.enable");
|
|
99
|
+
await session.post("HeapProfiler.startSampling", {
|
|
100
|
+
samplingInterval: DEFAULT_SAMPLE_INTERVAL_BYTES,
|
|
101
|
+
includeObjectsCollectedByMajorGC: false,
|
|
102
|
+
includeObjectsCollectedByMinorGC: false
|
|
103
|
+
});
|
|
104
|
+
} catch (error) {
|
|
105
|
+
try {
|
|
106
|
+
session.disconnect();
|
|
107
|
+
} catch {
|
|
108
|
+
}
|
|
109
|
+
throw error;
|
|
110
|
+
}
|
|
111
|
+
let stopped = false;
|
|
112
|
+
return {
|
|
113
|
+
backend: "node-inspector",
|
|
114
|
+
capture: async () => {
|
|
115
|
+
if (stopped) throw new Error("Continuous memory profiler is stopped");
|
|
116
|
+
const result = await session.post("HeapProfiler.stopSampling");
|
|
117
|
+
await session.post("HeapProfiler.startSampling", {
|
|
118
|
+
samplingInterval: DEFAULT_SAMPLE_INTERVAL_BYTES,
|
|
119
|
+
includeObjectsCollectedByMajorGC: false,
|
|
120
|
+
includeObjectsCollectedByMinorGC: false
|
|
121
|
+
});
|
|
122
|
+
return {
|
|
123
|
+
backend: "node-inspector",
|
|
124
|
+
data: JSON.stringify(result.profile),
|
|
125
|
+
extension: ".heapprofile"
|
|
126
|
+
};
|
|
127
|
+
},
|
|
128
|
+
stop: async () => {
|
|
129
|
+
if (stopped) return;
|
|
130
|
+
stopped = true;
|
|
131
|
+
try {
|
|
132
|
+
await session.post("HeapProfiler.disable");
|
|
133
|
+
} catch {
|
|
134
|
+
}
|
|
135
|
+
try {
|
|
136
|
+
session.disconnect();
|
|
137
|
+
} catch {
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
async function startContinuousMemoryProfiler() {
|
|
143
|
+
try {
|
|
144
|
+
return { profiler: await startDatadogProfiler() };
|
|
145
|
+
} catch (error) {
|
|
146
|
+
const fallbackReason = errorMessage(error);
|
|
147
|
+
return {
|
|
148
|
+
profiler: await startInspectorProfiler(),
|
|
149
|
+
fallbackReason
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// src/utils/memory-flight-recorder.ts
|
|
155
|
+
var MB = 1024 * 1024;
|
|
156
|
+
var HOUR_MS = 60 * 60 * 1e3;
|
|
157
|
+
var DEFAULT_WINDOW_MS = 5 * 60 * 1e3;
|
|
158
|
+
var DEFAULT_MINIMUM_WINDOW_MS = 2 * 60 * 1e3;
|
|
159
|
+
var DEFAULT_COOLDOWN_MS = 15 * 60 * 1e3;
|
|
160
|
+
var DEFAULT_CONTINUOUS_CAPTURE_MS = 5 * 60 * 1e3;
|
|
161
|
+
var MAX_OBSERVATIONS = 24;
|
|
162
|
+
var MAX_CAPTURE_SESSIONS = 12;
|
|
163
|
+
var MAX_CAPTURES_PER_SESSION = 6;
|
|
164
|
+
var SESSION_MAX_AGE_MS = 7 * 24 * HOUR_MS;
|
|
165
|
+
function timestampSlug(date = /* @__PURE__ */ new Date()) {
|
|
166
|
+
return date.toISOString().replaceAll(":", "").replaceAll(".", "-");
|
|
167
|
+
}
|
|
168
|
+
async function pruneCaptureFiles(artifactDir) {
|
|
169
|
+
const entries = await fsp.readdir(artifactDir, { withFileTypes: true });
|
|
170
|
+
const captures = entries.filter(
|
|
171
|
+
(entry) => entry.isFile() && entry.name.startsWith("event-") && entry.name.endsWith(".json")
|
|
172
|
+
).map((entry) => entry.name).sort();
|
|
173
|
+
const remove = captures.slice(0, Math.max(0, captures.length - MAX_CAPTURES_PER_SESSION));
|
|
174
|
+
await Promise.all(
|
|
175
|
+
remove.flatMap((eventName) => {
|
|
176
|
+
const stem = eventName.slice("event-".length, -".json".length);
|
|
177
|
+
return [
|
|
178
|
+
fsp.rm(path.join(artifactDir, eventName), { force: true }),
|
|
179
|
+
fsp.rm(path.join(artifactDir, `allocations-${stem}.heapprofile`), { force: true }),
|
|
180
|
+
fsp.rm(path.join(artifactDir, `allocations-${stem}.pb.gz`), { force: true })
|
|
181
|
+
];
|
|
182
|
+
})
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
async function pruneOldSessions(root, currentDir) {
|
|
186
|
+
const entries = await fsp.readdir(root, { withFileTypes: true });
|
|
187
|
+
const sessions = await Promise.all(
|
|
188
|
+
entries.filter((entry) => entry.isDirectory() && entry.name !== path.basename(currentDir)).map(async (entry) => {
|
|
189
|
+
const fullPath = path.join(root, entry.name);
|
|
190
|
+
const stat2 = await fsp.stat(fullPath);
|
|
191
|
+
return { fullPath, mtimeMs: stat2.mtimeMs };
|
|
192
|
+
})
|
|
193
|
+
);
|
|
194
|
+
sessions.sort((a, b) => b.mtimeMs - a.mtimeMs);
|
|
195
|
+
const now = Date.now();
|
|
196
|
+
await Promise.all(
|
|
197
|
+
sessions.filter(
|
|
198
|
+
(session, index) => now - session.mtimeMs > SESSION_MAX_AGE_MS || index >= MAX_CAPTURE_SESSIONS && now - session.mtimeMs > 24 * HOUR_MS
|
|
199
|
+
).map((session) => fsp.rm(session.fullPath, { recursive: true, force: true }))
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
var ContinuousMemoryCaptureWriter = class {
|
|
203
|
+
artifactDir;
|
|
204
|
+
root;
|
|
205
|
+
ready;
|
|
206
|
+
profiler;
|
|
207
|
+
profilerBackend = "initializing";
|
|
208
|
+
fallbackReason;
|
|
209
|
+
startError;
|
|
210
|
+
lastSummary;
|
|
211
|
+
stopped = false;
|
|
212
|
+
constructor(root) {
|
|
213
|
+
this.root = root;
|
|
214
|
+
this.artifactDir = path.join(root, `${timestampSlug()}-pid-${process.pid}`);
|
|
215
|
+
this.ready = this.start().catch((error) => {
|
|
216
|
+
this.startError = error instanceof Error ? error.message : String(error);
|
|
217
|
+
this.profilerBackend = "unavailable";
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
async start() {
|
|
221
|
+
const started = await startContinuousMemoryProfiler();
|
|
222
|
+
this.profiler = started.profiler;
|
|
223
|
+
this.profilerBackend = started.profiler.backend;
|
|
224
|
+
this.fallbackReason = started.fallbackReason;
|
|
225
|
+
}
|
|
226
|
+
diagnostics() {
|
|
227
|
+
return {
|
|
228
|
+
memoryProfilerBackend: this.profilerBackend,
|
|
229
|
+
...this.fallbackReason ? { memoryProfilerFallbackReason: this.fallbackReason } : {},
|
|
230
|
+
...this.startError ? { memoryProfilerStartError: this.startError } : {},
|
|
231
|
+
...this.lastSummary ? {
|
|
232
|
+
memoryProfileSampledBytes: this.lastSummary.sampledBytes,
|
|
233
|
+
memoryProfileSampledObjects: this.lastSummary.sampledObjects,
|
|
234
|
+
memoryProfileSampleCount: this.lastSummary.sampleCount,
|
|
235
|
+
memoryProfileTopStack: this.lastSummary.topStack,
|
|
236
|
+
memoryProfileTopStackBytes: this.lastSummary.topStackBytes
|
|
237
|
+
} : {}
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
async capture(event) {
|
|
241
|
+
await this.ready;
|
|
242
|
+
if (this.stopped) return;
|
|
243
|
+
let profile;
|
|
244
|
+
let captureError = this.startError;
|
|
245
|
+
if (!captureError && this.profiler) {
|
|
246
|
+
try {
|
|
247
|
+
profile = await this.profiler.capture();
|
|
248
|
+
const top = profile.summary?.topStacks[0];
|
|
249
|
+
if (profile.summary) {
|
|
250
|
+
this.lastSummary = {
|
|
251
|
+
sampledBytes: profile.summary.sampledBytes,
|
|
252
|
+
sampledObjects: profile.summary.sampledObjects,
|
|
253
|
+
sampleCount: profile.summary.sampleCount,
|
|
254
|
+
topStack: top?.frames.join(" <- "),
|
|
255
|
+
topStackBytes: top?.bytes
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
} catch (error) {
|
|
259
|
+
captureError = error instanceof Error ? error.message : String(error);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
await fsp.mkdir(this.artifactDir, { recursive: true });
|
|
263
|
+
const stem = `${timestampSlug(new Date(event.capturedAt))}-${event.reason}`;
|
|
264
|
+
await fsp.writeFile(
|
|
265
|
+
path.join(this.artifactDir, `event-${stem}.json`),
|
|
266
|
+
`${JSON.stringify(
|
|
267
|
+
{
|
|
268
|
+
...event,
|
|
269
|
+
profilerBackend: profile?.backend ?? this.profilerBackend,
|
|
270
|
+
...profile?.summary ? { allocationSummary: profile.summary } : {},
|
|
271
|
+
...this.fallbackReason ? { profilerFallbackReason: this.fallbackReason } : {},
|
|
272
|
+
...captureError ? { captureError } : {}
|
|
273
|
+
},
|
|
274
|
+
null,
|
|
275
|
+
2
|
|
276
|
+
)}
|
|
277
|
+
`,
|
|
278
|
+
"utf8"
|
|
279
|
+
);
|
|
280
|
+
if (profile) {
|
|
281
|
+
await fsp.writeFile(
|
|
282
|
+
path.join(this.artifactDir, `allocations-${stem}${profile.extension}`),
|
|
283
|
+
profile.data
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
await Promise.all([
|
|
287
|
+
pruneCaptureFiles(this.artifactDir),
|
|
288
|
+
fsp.mkdir(this.root, { recursive: true }).then(() => pruneOldSessions(this.root, this.artifactDir))
|
|
289
|
+
]);
|
|
290
|
+
}
|
|
291
|
+
async stop() {
|
|
292
|
+
if (this.stopped) return;
|
|
293
|
+
this.stopped = true;
|
|
294
|
+
await this.ready;
|
|
295
|
+
await this.profiler?.stop();
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
function disabledWriter(artifactDir) {
|
|
299
|
+
return {
|
|
300
|
+
artifactDir,
|
|
301
|
+
capture: async () => void 0,
|
|
302
|
+
stop: async () => void 0
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
function createMemoryFlightRecorder(options = {}) {
|
|
306
|
+
const now = options.now ?? Date.now;
|
|
307
|
+
const startedAt = now();
|
|
308
|
+
const root = options.diagnosticsRoot ?? path.join(wstackGlobalRoot(), "diagnostics", "memory");
|
|
309
|
+
const isBunRuntime = typeof globalThis.Bun !== "undefined";
|
|
310
|
+
const enabled = options.enabled ?? (!isBunRuntime && process.env["WRONGSTACK_MEMORY_FLIGHT_RECORDER"] !== "0" && process.env["NODE_ENV"] !== "test");
|
|
311
|
+
const writer = options.captureWriter ?? (enabled ? new ContinuousMemoryCaptureWriter(root) : disabledWriter(path.join(root, `${timestampSlug()}-pid-${process.pid}`)));
|
|
312
|
+
const observations = [];
|
|
313
|
+
const windowMs = options.windowMs ?? DEFAULT_WINDOW_MS;
|
|
314
|
+
const minimumWindowMs = options.minimumWindowMs ?? DEFAULT_MINIMUM_WINDOW_MS;
|
|
315
|
+
const cooldownMs = options.cooldownMs ?? DEFAULT_COOLDOWN_MS;
|
|
316
|
+
const continuousCaptureMs = options.continuousCaptureMs ?? DEFAULT_CONTINUOUS_CAPTURE_MS;
|
|
317
|
+
const warmupMs = options.warmupMs ?? 6e4;
|
|
318
|
+
let lastSignalCaptureAt = Number.NEGATIVE_INFINITY;
|
|
319
|
+
let lastContinuousCaptureAt = startedAt;
|
|
320
|
+
let captureInFlight = false;
|
|
321
|
+
let capturePromise;
|
|
322
|
+
const observe = (sample, stats) => {
|
|
323
|
+
const at = now();
|
|
324
|
+
const postGcHeapUsed = typeof stats["postGcHeapUsed"] === "number" ? stats["postGcHeapUsed"] : 0;
|
|
325
|
+
const postMajorGcHeapUsed = typeof stats["postMajorGcHeapUsed"] === "number" ? stats["postMajorGcHeapUsed"] : 0;
|
|
326
|
+
const lastGcAgoMs = typeof stats["lastGcAgoMs"] === "number" ? stats["lastGcAgoMs"] : -1;
|
|
327
|
+
const lastMajorGcAgoMs = typeof stats["lastMajorGcAgoMs"] === "number" ? stats["lastMajorGcAgoMs"] : -1;
|
|
328
|
+
const retainedHeapUsed = postMajorGcHeapUsed > 0 && lastMajorGcAgoMs >= 0 && lastMajorGcAgoMs <= windowMs ? postMajorGcHeapUsed : postGcHeapUsed > 0 && lastGcAgoMs >= 0 && lastGcAgoMs <= minimumWindowMs ? postGcHeapUsed : sample.heapUsed;
|
|
329
|
+
observations.push({
|
|
330
|
+
at,
|
|
331
|
+
heapUsed: retainedHeapUsed,
|
|
332
|
+
rss: sample.rss,
|
|
333
|
+
nativeResidual: sample.nativeResidual ?? 0
|
|
334
|
+
});
|
|
335
|
+
while (observations.length > MAX_OBSERVATIONS || observations.length > 1 && at - (observations[0]?.at ?? at) > windowMs) {
|
|
336
|
+
observations.shift();
|
|
337
|
+
}
|
|
338
|
+
const first = observations[0] ?? observations.at(-1);
|
|
339
|
+
const elapsedMs = first ? Math.max(0, at - first.at) : 0;
|
|
340
|
+
const heapGrowthBytes = first ? retainedHeapUsed - first.heapUsed : 0;
|
|
341
|
+
const rssGrowthBytes = first ? sample.rss - first.rss : 0;
|
|
342
|
+
const nativeGrowthBytes = first ? (sample.nativeResidual ?? 0) - first.nativeResidual : 0;
|
|
343
|
+
const heapGrowthBytesPerHour = elapsedMs > 0 ? Math.round(heapGrowthBytes / elapsedMs * HOUR_MS) : 0;
|
|
344
|
+
const rssGrowthBytesPerHour = elapsedMs > 0 ? Math.round(rssGrowthBytes / elapsedMs * HOUR_MS) : 0;
|
|
345
|
+
const nativeGrowthBytesPerHour = elapsedMs > 0 ? Math.round(nativeGrowthBytes / elapsedMs * HOUR_MS) : 0;
|
|
346
|
+
let signal = "stable";
|
|
347
|
+
if ((sample.detachedContexts ?? 0) > 0) signal = "detached-contexts";
|
|
348
|
+
else if (heapGrowthBytes >= 32 * MB && heapGrowthBytesPerHour > 0) signal = "js-retention";
|
|
349
|
+
else if (nativeGrowthBytes >= 64 * MB && nativeGrowthBytesPerHour > 0) signal = "native-rss";
|
|
350
|
+
const diagnosis = {
|
|
351
|
+
memorySignal: signal,
|
|
352
|
+
memoryWindowMs: elapsedMs,
|
|
353
|
+
retainedHeapUsed,
|
|
354
|
+
transientHeapBytes: Math.max(0, sample.heapUsed - retainedHeapUsed),
|
|
355
|
+
heapGrowthBytes,
|
|
356
|
+
rssGrowthBytes,
|
|
357
|
+
nativeGrowthBytes,
|
|
358
|
+
heapGrowthBytesPerHour,
|
|
359
|
+
rssGrowthBytesPerHour,
|
|
360
|
+
nativeGrowthBytesPerHour,
|
|
361
|
+
memoryArtifactDir: writer.artifactDir,
|
|
362
|
+
...writer.diagnostics?.() ?? {}
|
|
363
|
+
};
|
|
364
|
+
let reason;
|
|
365
|
+
if (at - startedAt >= warmupMs) {
|
|
366
|
+
if ((sample.detachedContexts ?? 0) > 0) reason = "detached-contexts";
|
|
367
|
+
else if (sample.load >= 0.45) reason = "heap-load";
|
|
368
|
+
else if (sample.heapUsed >= (options.absoluteHeapBytes ?? 768 * MB)) {
|
|
369
|
+
reason = "absolute-heap";
|
|
370
|
+
} else if (elapsedMs >= minimumWindowMs && heapGrowthBytes >= (options.heapGrowthBytes ?? 32 * MB) && heapGrowthBytesPerHour >= (options.heapGrowthBytesPerHour ?? 192 * MB)) {
|
|
371
|
+
reason = "heap-growth";
|
|
372
|
+
} else if (elapsedMs >= minimumWindowMs && nativeGrowthBytes >= (options.nativeGrowthBytes ?? 128 * MB) && nativeGrowthBytesPerHour >= (options.nativeGrowthBytesPerHour ?? 256 * MB)) {
|
|
373
|
+
reason = "native-rss-growth";
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
const signalCaptureDue = reason !== void 0 && at - lastSignalCaptureAt >= cooldownMs;
|
|
377
|
+
const intervalCaptureDue = at - lastContinuousCaptureAt >= continuousCaptureMs;
|
|
378
|
+
const captureReason = signalCaptureDue ? reason : intervalCaptureDue ? "interval" : void 0;
|
|
379
|
+
if (enabled && captureReason && !captureInFlight) {
|
|
380
|
+
if (captureReason !== "interval") lastSignalCaptureAt = at;
|
|
381
|
+
lastContinuousCaptureAt = at;
|
|
382
|
+
captureInFlight = true;
|
|
383
|
+
diagnosis["memoryCaptureReason"] = captureReason;
|
|
384
|
+
capturePromise = writer.capture({
|
|
385
|
+
reason: captureReason,
|
|
386
|
+
capturedAt: new Date(at).toISOString(),
|
|
387
|
+
pid: process.pid,
|
|
388
|
+
sample,
|
|
389
|
+
stats,
|
|
390
|
+
diagnosis: { ...diagnosis },
|
|
391
|
+
observations: observations.map((observation) => ({ ...observation }))
|
|
392
|
+
}).catch(() => {
|
|
393
|
+
}).finally(() => {
|
|
394
|
+
captureInFlight = false;
|
|
395
|
+
capturePromise = void 0;
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
return diagnosis;
|
|
399
|
+
};
|
|
400
|
+
return {
|
|
401
|
+
artifactDir: writer.artifactDir,
|
|
402
|
+
observe,
|
|
403
|
+
stop: async () => {
|
|
404
|
+
await capturePromise;
|
|
405
|
+
await writer.stop();
|
|
406
|
+
}
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// src/utils/heap-watchdog.ts
|
|
411
|
+
var MB2 = 1024 * 1024;
|
|
412
|
+
function defaultHeapLogPath() {
|
|
413
|
+
const override = process.env["WRONGSTACK_HEAP_LOG_PATH"]?.trim();
|
|
414
|
+
if (override) return path2.resolve(override);
|
|
415
|
+
return path2.join(wstackGlobalRoot(), "logs", "heap.jsonl");
|
|
416
|
+
}
|
|
417
|
+
function takeHeapSample() {
|
|
418
|
+
const m = process.memoryUsage();
|
|
419
|
+
const heap = v8.getHeapStatistics();
|
|
420
|
+
let spaces = [];
|
|
421
|
+
try {
|
|
422
|
+
spaces = v8.getHeapSpaceStatistics();
|
|
423
|
+
} catch {
|
|
424
|
+
}
|
|
425
|
+
const spaceUsed = (name) => spaces.find((space) => space.space_name === name)?.space_used_size ?? 0;
|
|
426
|
+
const limit = heap.heap_size_limit || 0;
|
|
427
|
+
let activeResources = 0;
|
|
428
|
+
let activeResourceTypes = "";
|
|
429
|
+
try {
|
|
430
|
+
const resources = process.getActiveResourcesInfo?.() ?? [];
|
|
431
|
+
activeResources = resources.length;
|
|
432
|
+
const counts = /* @__PURE__ */ new Map();
|
|
433
|
+
for (const resource of resources) counts.set(resource, (counts.get(resource) ?? 0) + 1);
|
|
434
|
+
activeResourceTypes = [...counts].sort(([left], [right]) => left.localeCompare(right)).map(([resource, count]) => `${resource}=${count}`).join(",");
|
|
435
|
+
} catch {
|
|
436
|
+
}
|
|
437
|
+
return {
|
|
438
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
439
|
+
rss: m.rss,
|
|
440
|
+
heapUsed: m.heapUsed,
|
|
441
|
+
heapTotal: m.heapTotal,
|
|
442
|
+
external: m.external,
|
|
443
|
+
arrayBuffers: m.arrayBuffers,
|
|
444
|
+
nativeResidual: Math.max(0, m.rss - m.heapTotal - m.external),
|
|
445
|
+
oldSpaceUsed: spaceUsed("old_space"),
|
|
446
|
+
newSpaceUsed: spaceUsed("new_space"),
|
|
447
|
+
largeObjectSpaceUsed: spaceUsed("large_object_space"),
|
|
448
|
+
codeSpaceUsed: spaceUsed("code_space"),
|
|
449
|
+
mallocedMemory: heap.malloced_memory,
|
|
450
|
+
peakMallocedMemory: heap.peak_malloced_memory,
|
|
451
|
+
nativeContexts: heap.number_of_native_contexts,
|
|
452
|
+
detachedContexts: heap.number_of_detached_contexts,
|
|
453
|
+
activeResources,
|
|
454
|
+
activeResourceTypes,
|
|
455
|
+
heapLimit: limit,
|
|
456
|
+
load: limit > 0 ? m.heapUsed / limit : 0
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
function startHeapWatchdog(opts = {}) {
|
|
460
|
+
const profileMode = process.env["WRONGSTACK_MEMORY_PROFILE"] === "1";
|
|
461
|
+
const sampleEveryMs = opts.sampleEveryMs ?? (profileMode ? 5e3 : 3e4);
|
|
462
|
+
const logEveryMs = opts.logEveryMs ?? (profileMode ? 5e3 : 6e4);
|
|
463
|
+
const logPath = opts.logPath ?? defaultHeapLogPath();
|
|
464
|
+
const warnAt = opts.warnAt ?? 0.6;
|
|
465
|
+
const criticalAt = opts.criticalAt ?? 0.85;
|
|
466
|
+
const REARM_MARGIN = 0.05;
|
|
467
|
+
let warnArmed = true;
|
|
468
|
+
let criticalArmed = true;
|
|
469
|
+
let lastLogAt = 0;
|
|
470
|
+
let writeInFlight = false;
|
|
471
|
+
let pendingLine;
|
|
472
|
+
let drainPromise;
|
|
473
|
+
let stopped = false;
|
|
474
|
+
let dirReady = false;
|
|
475
|
+
const flightRecorder = createMemoryFlightRecorder();
|
|
476
|
+
let gcMajorCount = 0;
|
|
477
|
+
let gcMinorCount = 0;
|
|
478
|
+
let gcIncrementalCount = 0;
|
|
479
|
+
let gcWeakCallbackCount = 0;
|
|
480
|
+
let gcDurationMs = 0;
|
|
481
|
+
let postGcHeapUsed = 0;
|
|
482
|
+
let postMajorGcHeapUsed = 0;
|
|
483
|
+
let lastGcAt = 0;
|
|
484
|
+
let lastMajorGcAt = 0;
|
|
485
|
+
const gcObserver = new PerformanceObserver((list) => {
|
|
486
|
+
for (const entry of list.getEntries()) {
|
|
487
|
+
const kind = entry.detail?.kind ?? 0;
|
|
488
|
+
if ((kind & performanceConstants.NODE_PERFORMANCE_GC_MAJOR) !== 0) gcMajorCount++;
|
|
489
|
+
if ((kind & performanceConstants.NODE_PERFORMANCE_GC_MINOR) !== 0) gcMinorCount++;
|
|
490
|
+
if ((kind & performanceConstants.NODE_PERFORMANCE_GC_INCREMENTAL) !== 0) {
|
|
491
|
+
gcIncrementalCount++;
|
|
492
|
+
}
|
|
493
|
+
if ((kind & performanceConstants.NODE_PERFORMANCE_GC_WEAKCB) !== 0) gcWeakCallbackCount++;
|
|
494
|
+
gcDurationMs += entry.duration;
|
|
495
|
+
postGcHeapUsed = process.memoryUsage().heapUsed;
|
|
496
|
+
if ((kind & performanceConstants.NODE_PERFORMANCE_GC_MAJOR) !== 0) {
|
|
497
|
+
postMajorGcHeapUsed = postGcHeapUsed;
|
|
498
|
+
lastMajorGcAt = Date.now();
|
|
499
|
+
}
|
|
500
|
+
lastGcAt = Date.now();
|
|
501
|
+
}
|
|
502
|
+
});
|
|
503
|
+
try {
|
|
504
|
+
gcObserver.observe({ entryTypes: ["gc"] });
|
|
505
|
+
} catch {
|
|
506
|
+
}
|
|
507
|
+
const collectRuntimeStats = () => ({
|
|
508
|
+
gcMajorCount,
|
|
509
|
+
gcMinorCount,
|
|
510
|
+
gcIncrementalCount,
|
|
511
|
+
gcWeakCallbackCount,
|
|
512
|
+
gcDurationMs: Math.round(gcDurationMs),
|
|
513
|
+
postGcHeapUsed,
|
|
514
|
+
postMajorGcHeapUsed,
|
|
515
|
+
lastGcAgoMs: lastGcAt > 0 ? Date.now() - lastGcAt : -1,
|
|
516
|
+
lastMajorGcAgoMs: lastMajorGcAt > 0 ? Date.now() - lastMajorGcAt : -1
|
|
517
|
+
});
|
|
518
|
+
const writeDiagnosticLine = opts.writeDiagnosticLine ?? (async (targetPath, line) => {
|
|
519
|
+
if (!dirReady) {
|
|
520
|
+
await fsp2.mkdir(path2.dirname(targetPath), { recursive: true });
|
|
521
|
+
dirReady = true;
|
|
522
|
+
}
|
|
523
|
+
await fsp2.appendFile(targetPath, `${line}
|
|
524
|
+
`, { encoding: "utf8", mode: 384 });
|
|
525
|
+
});
|
|
526
|
+
const drainWrites = async (firstLine) => {
|
|
527
|
+
let line = firstLine;
|
|
528
|
+
while (line !== void 0) {
|
|
529
|
+
try {
|
|
530
|
+
await writeDiagnosticLine(logPath, line);
|
|
531
|
+
} catch {
|
|
532
|
+
}
|
|
533
|
+
line = pendingLine;
|
|
534
|
+
pendingLine = void 0;
|
|
535
|
+
}
|
|
536
|
+
writeInFlight = false;
|
|
537
|
+
};
|
|
538
|
+
const append = (line) => {
|
|
539
|
+
if (stopped) return;
|
|
540
|
+
if (writeInFlight) {
|
|
541
|
+
pendingLine = line;
|
|
542
|
+
return;
|
|
543
|
+
}
|
|
544
|
+
writeInFlight = true;
|
|
545
|
+
drainPromise = drainWrites(line);
|
|
546
|
+
};
|
|
547
|
+
const appendTerminalSample = (event, error, origin) => {
|
|
548
|
+
if (stopped) return;
|
|
549
|
+
let extras = {};
|
|
550
|
+
try {
|
|
551
|
+
extras = opts.collectStats?.() ?? {};
|
|
552
|
+
} catch {
|
|
553
|
+
}
|
|
554
|
+
try {
|
|
555
|
+
const sample = takeHeapSample();
|
|
556
|
+
const runtimeStats = collectRuntimeStats();
|
|
557
|
+
fs.mkdirSync(path2.dirname(logPath), { recursive: true });
|
|
558
|
+
fs.appendFileSync(
|
|
559
|
+
logPath,
|
|
560
|
+
`${JSON.stringify({
|
|
561
|
+
...extras,
|
|
562
|
+
...runtimeStats,
|
|
563
|
+
event,
|
|
564
|
+
...origin ? { crashOrigin: origin } : {},
|
|
565
|
+
...error instanceof Error ? { errorName: error.name, errorMessage: error.message.slice(0, 1e3) } : {},
|
|
566
|
+
pid: process.pid,
|
|
567
|
+
...sample,
|
|
568
|
+
exitCode: process.exitCode
|
|
569
|
+
})}
|
|
570
|
+
`,
|
|
571
|
+
"utf8"
|
|
572
|
+
);
|
|
573
|
+
} catch {
|
|
574
|
+
}
|
|
575
|
+
};
|
|
576
|
+
const onUncaughtException = (error, origin) => {
|
|
577
|
+
appendTerminalSample("memory.flight_recorder.crash", error, origin);
|
|
578
|
+
};
|
|
579
|
+
const onProcessExit = () => {
|
|
580
|
+
appendTerminalSample("memory.flight_recorder.exit");
|
|
581
|
+
};
|
|
582
|
+
process.on("uncaughtExceptionMonitor", onUncaughtException);
|
|
583
|
+
process.on("exit", onProcessExit);
|
|
584
|
+
const tick = () => {
|
|
585
|
+
let userTimings = 0;
|
|
586
|
+
try {
|
|
587
|
+
userTimings = performance.getEntriesByType("mark").length + performance.getEntriesByType("measure").length;
|
|
588
|
+
if (userTimings > 0) {
|
|
589
|
+
performance.clearMarks();
|
|
590
|
+
performance.clearMeasures();
|
|
591
|
+
}
|
|
592
|
+
} catch {
|
|
593
|
+
}
|
|
594
|
+
const s = takeHeapSample();
|
|
595
|
+
let extras = {};
|
|
596
|
+
try {
|
|
597
|
+
extras = opts.collectStats?.() ?? {};
|
|
598
|
+
} catch {
|
|
599
|
+
}
|
|
600
|
+
const runtimeStats = collectRuntimeStats();
|
|
601
|
+
const diagnosticStats = { ...extras, ...runtimeStats };
|
|
602
|
+
const memoryDiagnosis = flightRecorder.observe(s, diagnosticStats);
|
|
603
|
+
if (s.load >= criticalAt && criticalArmed) {
|
|
604
|
+
criticalArmed = false;
|
|
605
|
+
warnArmed = false;
|
|
606
|
+
opts.onWarn?.(
|
|
607
|
+
"critical",
|
|
608
|
+
`Heap critical: ${Math.round(s.heapUsed / MB2)} MB of ~${Math.round(s.heapLimit / MB2)} MB V8 limit (${Math.round(s.load * 100)}%). An out-of-memory crash is likely soon \u2014 finish/checkpoint work and restart the session. Diagnostics: ${logPath}`,
|
|
609
|
+
s
|
|
610
|
+
);
|
|
611
|
+
} else if (s.load >= warnAt && warnArmed) {
|
|
612
|
+
warnArmed = false;
|
|
613
|
+
opts.onWarn?.(
|
|
614
|
+
"warn",
|
|
615
|
+
`Heap high: ${Math.round(s.heapUsed / MB2)} MB of ~${Math.round(s.heapLimit / MB2)} MB V8 limit (${Math.round(s.load * 100)}%). Memory diagnostics are being recorded to ${logPath}`,
|
|
616
|
+
s
|
|
617
|
+
);
|
|
618
|
+
}
|
|
619
|
+
if (!warnArmed && s.load < warnAt - REARM_MARGIN) warnArmed = true;
|
|
620
|
+
if (!criticalArmed && s.load < criticalAt - REARM_MARGIN) criticalArmed = true;
|
|
621
|
+
const due = Date.now() - lastLogAt >= logEveryMs;
|
|
622
|
+
const crossed = s.load >= warnAt;
|
|
623
|
+
const captured = typeof memoryDiagnosis["memoryCaptureReason"] === "string";
|
|
624
|
+
if (due || crossed || captured) {
|
|
625
|
+
lastLogAt = Date.now();
|
|
626
|
+
append(
|
|
627
|
+
JSON.stringify({
|
|
628
|
+
...extras,
|
|
629
|
+
...runtimeStats,
|
|
630
|
+
...memoryDiagnosis,
|
|
631
|
+
pid: process.pid,
|
|
632
|
+
...s,
|
|
633
|
+
userTimings
|
|
634
|
+
})
|
|
635
|
+
);
|
|
636
|
+
}
|
|
637
|
+
};
|
|
638
|
+
const timer = setInterval(tick, sampleEveryMs);
|
|
639
|
+
timer.unref?.();
|
|
640
|
+
tick();
|
|
641
|
+
return async () => {
|
|
642
|
+
stopped = true;
|
|
643
|
+
clearInterval(timer);
|
|
644
|
+
gcObserver.disconnect();
|
|
645
|
+
process.removeListener("uncaughtExceptionMonitor", onUncaughtException);
|
|
646
|
+
process.removeListener("exit", onProcessExit);
|
|
647
|
+
await drainPromise;
|
|
648
|
+
await flightRecorder.stop();
|
|
649
|
+
};
|
|
650
|
+
}
|
|
651
|
+
var sharedContributors = /* @__PURE__ */ new Map();
|
|
652
|
+
var nextSharedContributorId = 1;
|
|
653
|
+
var sharedSamplerActive = false;
|
|
654
|
+
var stopSharedSampler;
|
|
655
|
+
function collectSharedStats() {
|
|
656
|
+
const merged = {};
|
|
657
|
+
for (const contributor of sharedContributors.values()) {
|
|
658
|
+
try {
|
|
659
|
+
Object.assign(merged, contributor.collectStats?.() ?? {});
|
|
660
|
+
} catch {
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
return merged;
|
|
664
|
+
}
|
|
665
|
+
function warnSharedContributors(level, message, sample) {
|
|
666
|
+
for (const contributor of sharedContributors.values()) {
|
|
667
|
+
try {
|
|
668
|
+
contributor.onWarn?.(level, message, sample);
|
|
669
|
+
} catch {
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
function startSharedHeapWatchdog(opts = {}) {
|
|
674
|
+
if (process.env["NODE_ENV"] === "test" && !sharedSamplerActive && opts.logPath === void 0 && opts.writeDiagnosticLine === void 0) {
|
|
675
|
+
return async () => void 0;
|
|
676
|
+
}
|
|
677
|
+
const id = nextSharedContributorId++;
|
|
678
|
+
sharedContributors.set(id, {
|
|
679
|
+
collectStats: opts.collectStats,
|
|
680
|
+
onWarn: opts.onWarn
|
|
681
|
+
});
|
|
682
|
+
if (!sharedSamplerActive) {
|
|
683
|
+
sharedSamplerActive = true;
|
|
684
|
+
stopSharedSampler = startHeapWatchdog({
|
|
685
|
+
...opts,
|
|
686
|
+
collectStats: collectSharedStats,
|
|
687
|
+
onWarn: warnSharedContributors
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
let stopped = false;
|
|
691
|
+
return async () => {
|
|
692
|
+
if (stopped) return;
|
|
693
|
+
stopped = true;
|
|
694
|
+
sharedContributors.delete(id);
|
|
695
|
+
if (sharedContributors.size > 0 || !sharedSamplerActive) return;
|
|
696
|
+
const stop = stopSharedSampler;
|
|
697
|
+
if (!stop) return;
|
|
698
|
+
sharedSamplerActive = false;
|
|
699
|
+
stopSharedSampler = void 0;
|
|
700
|
+
await stop();
|
|
701
|
+
};
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
export {
|
|
705
|
+
defaultHeapLogPath,
|
|
706
|
+
takeHeapSample,
|
|
707
|
+
startHeapWatchdog,
|
|
708
|
+
startSharedHeapWatchdog
|
|
709
|
+
};
|
|
710
|
+
//# sourceMappingURL=chunk-KBZGE6LN.js.map
|