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