codesesh 1.0.4 → 1.0.6

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 (59) hide show
  1. package/README.md +5 -4
  2. package/dist/{chunk-W4PZHL2C.js → chunk-4ND6AT6W.js} +154 -92
  3. package/dist/chunk-4ND6AT6W.js.map +1 -0
  4. package/dist/chunk-4QFNZCBR.js +1271 -0
  5. package/dist/chunk-4QFNZCBR.js.map +1 -0
  6. package/dist/{chunk-MBZ4VV4C.js → chunk-A3MT6L6Z.js} +3 -3
  7. package/dist/chunk-COZSWVCH.js +89 -0
  8. package/dist/chunk-COZSWVCH.js.map +1 -0
  9. package/dist/{chunk-YCUN52HA.js → chunk-L3DDWTYV.js} +81 -115
  10. package/dist/chunk-L3DDWTYV.js.map +1 -0
  11. package/dist/{chunk-BYB77UAJ.js → chunk-XQDYKKRC.js} +139 -80
  12. package/dist/chunk-XQDYKKRC.js.map +1 -0
  13. package/dist/{chunk-3SXCTDD6.js → chunk-YZ6XCSVQ.js} +4 -3
  14. package/dist/{discovery-K3GLISI6.js → discovery-ADSQARBV.js} +11 -5
  15. package/dist/index.js +1538 -1030
  16. package/dist/index.js.map +1 -1
  17. package/dist/project-identity-worker.js +4 -4
  18. package/dist/scan-refresh-worker.js +17 -7
  19. package/dist/scan-refresh-worker.js.map +1 -1
  20. package/dist/search-index-worker.js +16 -8
  21. package/dist/search-index-worker.js.map +1 -1
  22. package/dist/session-detail-worker.js +79 -0
  23. package/dist/session-detail-worker.js.map +1 -0
  24. package/dist/smart-tag-worker.js +3 -3
  25. package/dist/web/assets/CustomTimeWindowDialog-D2bx7uDv.js +1 -0
  26. package/dist/web/assets/InteractiveReceipt-BFpIdno8.js +1 -0
  27. package/dist/web/assets/OverviewScreen-D_KXfiJi.js +1 -0
  28. package/dist/web/assets/{PrismHighlighter-B1a2dPJO.js → PrismHighlighter-BgVkYu_S.js} +1 -1
  29. package/dist/web/assets/Projects-CN44UpuR.js +1 -0
  30. package/dist/web/assets/SearchResultsPanel-CWD01v-a.js +1 -0
  31. package/dist/web/assets/SessionDetail-D8taQ6Tl.js +53 -0
  32. package/dist/web/assets/api-B9lJtVbO.js +1 -0
  33. package/dist/web/assets/index-XpolWMY4.js +1423 -0
  34. package/dist/web/assets/index-xbEEMszv.css +1 -0
  35. package/dist/web/assets/session-indexes-fib48ZKn.js +4 -0
  36. package/dist/web/assets/translate-Dmym1ZDl.js +2 -0
  37. package/dist/web/assets/utils-Bk66u8b3.js +1 -0
  38. package/dist/web/index.html +7 -7
  39. package/package.json +3 -3
  40. package/dist/chunk-BYB77UAJ.js.map +0 -1
  41. package/dist/chunk-G4HRD3AR.js +0 -246
  42. package/dist/chunk-G4HRD3AR.js.map +0 -1
  43. package/dist/chunk-W4PZHL2C.js.map +0 -1
  44. package/dist/chunk-YCUN52HA.js.map +0 -1
  45. package/dist/web/assets/InteractiveReceipt-Dk50TBsH.js +0 -1
  46. package/dist/web/assets/OverviewScreen-5hvQVp4H.js +0 -1
  47. package/dist/web/assets/Projects-Cy_v2yep.js +0 -1
  48. package/dist/web/assets/SearchResultsPanel-DfheEwpz.js +0 -1
  49. package/dist/web/assets/SessionDetail-DRI8R3st.js +0 -53
  50. package/dist/web/assets/api-GP9UCedC.js +0 -1
  51. package/dist/web/assets/contract-xJyW5u7a.js +0 -2
  52. package/dist/web/assets/index-Bd-YkWkZ.css +0 -1
  53. package/dist/web/assets/index-DEjvzumm.js +0 -1410
  54. package/dist/web/assets/panel-ND0J63d3.js +0 -1
  55. package/dist/web/assets/session-indexes-BsgjUoc1.js +0 -4
  56. package/dist/web/assets/utils-C7BqyxxV.js +0 -1
  57. /package/dist/{chunk-MBZ4VV4C.js.map → chunk-A3MT6L6Z.js.map} +0 -0
  58. /package/dist/{chunk-3SXCTDD6.js.map → chunk-YZ6XCSVQ.js.map} +0 -0
  59. /package/dist/{discovery-K3GLISI6.js.map → discovery-ADSQARBV.js.map} +0 -0
@@ -0,0 +1,1271 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ AGENT_CATALOG,
4
+ PRIVATE_DIR_MODE,
5
+ PRIVATE_FILE_MODE,
6
+ WORKER_LOG_MESSAGE_TYPE,
7
+ isWorkerLogMessage,
8
+ setCoreDiagnostics
9
+ } from "./chunk-4ND6AT6W.js";
10
+
11
+ // src/logging.ts
12
+ import { AsyncLocalStorage } from "async_hooks";
13
+ import { randomBytes, randomUUID } from "crypto";
14
+ import { homedir as homedir2 } from "os";
15
+ import { join as join2 } from "path";
16
+ import { getEnvironmentData, setEnvironmentData } from "worker_threads";
17
+
18
+ // src/log-file-writer.ts
19
+ import { appendFileSync, chmodSync, mkdirSync } from "fs";
20
+ import {
21
+ chmod,
22
+ lstat,
23
+ mkdir,
24
+ open,
25
+ readdir,
26
+ rename,
27
+ unlink
28
+ } from "fs/promises";
29
+ import { join } from "path";
30
+ var MAX_BATCH_BYTES = 64 * 1024;
31
+ var UUID_PATTERN = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}";
32
+ var CURRENT_LOG_PATTERN = new RegExp(`^codesesh-(\\d+)-${UUID_PATTERN}-active\\.log$`);
33
+ var EMERGENCY_LOG_PATTERN = new RegExp(`^codesesh-(\\d+)-${UUID_PATTERN}-emergency\\.log$`);
34
+ var RUN_LOG_PATTERN = new RegExp(`^codesesh-\\d+-${UUID_PATTERN}-\\d+\\.log$`);
35
+ var LEGACY_ACTIVE_LOG_PATTERN = /^codesesh-(\d+)\.log$/;
36
+ var LEGACY_ROTATED_LOG_PATTERN = /^codesesh-\d+-\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}-\d{3}Z-\d+\.log$/;
37
+ var ORIGINAL_ROTATED_LOG_PATTERN = /^codesesh-\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}-\d{3}Z-\d+-\d+\.log$/;
38
+ var ORIGINAL_ACTIVE_LOG_PATTERN = /^codesesh\.log$/;
39
+ var LOG_LEVEL_PRIORITY = {
40
+ debug: 10,
41
+ info: 20,
42
+ warn: 30,
43
+ error: 40
44
+ };
45
+ function emptyDropCounts() {
46
+ return { debug: 0, info: 0, warn: 0, error: 0 };
47
+ }
48
+ function droppedCount(counts) {
49
+ return counts.debug + counts.info + counts.warn + counts.error;
50
+ }
51
+ function errorCode(error) {
52
+ return typeof error === "object" && error !== null && "code" in error ? String(error.code) : void 0;
53
+ }
54
+ function isProcessAlive(pid) {
55
+ if (pid === process.pid) return true;
56
+ try {
57
+ process.kill(pid, 0);
58
+ return true;
59
+ } catch (error) {
60
+ return errorCode(error) !== "ESRCH";
61
+ }
62
+ }
63
+ function activeLogPid(name) {
64
+ const match = CURRENT_LOG_PATTERN.exec(name) ?? EMERGENCY_LOG_PATTERN.exec(name) ?? LEGACY_ACTIVE_LOG_PATTERN.exec(name);
65
+ if (!match) return null;
66
+ const pid = Number(match[1]);
67
+ return Number.isSafeInteger(pid) && pid > 0 ? pid : null;
68
+ }
69
+ function isManagedLog(name) {
70
+ return CURRENT_LOG_PATTERN.test(name) || EMERGENCY_LOG_PATTERN.test(name) || RUN_LOG_PATTERN.test(name) || LEGACY_ACTIVE_LOG_PATTERN.test(name) || LEGACY_ROTATED_LOG_PATTERN.test(name) || ORIGINAL_ROTATED_LOG_PATTERN.test(name) || ORIGINAL_ACTIVE_LOG_PATTERN.test(name);
71
+ }
72
+ var AsyncLogFileWriter = class {
73
+ logDir;
74
+ prefix;
75
+ currentPath;
76
+ emergencyPath;
77
+ maxFileBytes;
78
+ maxFiles;
79
+ maxDirectoryBytes;
80
+ maxAgeMs;
81
+ maxQueueBytes;
82
+ createDropSummary;
83
+ queue = [];
84
+ inFlight = [];
85
+ dropped = emptyDropCounts();
86
+ queuedBytes = 0;
87
+ currentBytes = 0;
88
+ rotationIndex = 0;
89
+ handle = null;
90
+ drainPromise = null;
91
+ closePromise = null;
92
+ storagePrepared = false;
93
+ currentFileCreated = false;
94
+ needsRecoverySeparator = false;
95
+ writeFailureReported = false;
96
+ overflowReported = false;
97
+ closedWriteReported = false;
98
+ constructor(options) {
99
+ this.logDir = options.logDir;
100
+ this.prefix = `codesesh-${process.pid}-${options.runId}`;
101
+ this.currentPath = join(this.logDir, `${this.prefix}-active.log`);
102
+ this.emergencyPath = join(this.logDir, `${this.prefix}-emergency.log`);
103
+ this.maxFileBytes = options.maxFileBytes;
104
+ this.maxFiles = options.maxFiles;
105
+ this.maxDirectoryBytes = options.maxDirectoryBytes;
106
+ this.maxAgeMs = options.maxAgeMs;
107
+ this.maxQueueBytes = options.maxQueueBytes;
108
+ this.createDropSummary = options.createDropSummary;
109
+ }
110
+ get path() {
111
+ return this.currentPath;
112
+ }
113
+ enqueue(entry) {
114
+ if (this.closePromise) {
115
+ if (!this.closedWriteReported) {
116
+ this.closedWriteReported = true;
117
+ this.writeStderr("Log entry dropped after logger close");
118
+ }
119
+ return;
120
+ }
121
+ if (!this.makeRoom(entry)) {
122
+ this.recordDrop(entry.level);
123
+ this.scheduleDrain();
124
+ return;
125
+ }
126
+ this.queue.push(entry);
127
+ this.queuedBytes += entry.bytes;
128
+ this.scheduleDrain();
129
+ }
130
+ async flush() {
131
+ while (this.queue.length > 0 || droppedCount(this.dropped) > 0 || this.drainPromise) {
132
+ this.scheduleDrain();
133
+ const drain = this.drainPromise;
134
+ if (!drain) break;
135
+ await drain;
136
+ }
137
+ }
138
+ close() {
139
+ if (this.closePromise) return this.closePromise;
140
+ this.closePromise = this.finishClose();
141
+ return this.closePromise;
142
+ }
143
+ flushSync() {
144
+ const pending = this.queue.splice(0);
145
+ const pendingBytes = pending.reduce((total, entry) => total + entry.bytes, 0);
146
+ this.queuedBytes = Math.max(0, this.queuedBytes - pendingBytes);
147
+ const dropped = droppedCount(this.dropped);
148
+ const emergency = [...this.inFlight, ...pending];
149
+ if (dropped > 0) {
150
+ emergency.push(this.createDropSummary({ ...this.dropped }));
151
+ this.dropped = emptyDropCounts();
152
+ }
153
+ if (emergency.length === 0) return;
154
+ try {
155
+ mkdirSync(this.logDir, { recursive: true, mode: PRIVATE_DIR_MODE });
156
+ if (process.platform !== "win32") chmodSync(this.logDir, PRIVATE_DIR_MODE);
157
+ appendFileSync(this.emergencyPath, emergency.map((entry) => entry.line).join(""), {
158
+ encoding: "utf8",
159
+ mode: PRIVATE_FILE_MODE
160
+ });
161
+ if (process.platform !== "win32") chmodSync(this.emergencyPath, PRIVATE_FILE_MODE);
162
+ } catch (error) {
163
+ this.reportWriteFailure(error);
164
+ }
165
+ }
166
+ makeRoom(entry) {
167
+ if (entry.bytes > this.maxQueueBytes) return false;
168
+ if (entry.bytes <= this.maxQueueBytes - this.queuedBytes) return true;
169
+ if (entry.level === "debug" || entry.level === "info") return false;
170
+ const requiredBytes = entry.bytes - (this.maxQueueBytes - this.queuedBytes);
171
+ const candidates = this.queue.map((candidate, index) => ({ candidate, index })).filter(
172
+ ({ candidate }) => !candidate.internal && LOG_LEVEL_PRIORITY[candidate.level] < LOG_LEVEL_PRIORITY[entry.level]
173
+ ).toSorted((left, right) => {
174
+ return LOG_LEVEL_PRIORITY[left.candidate.level] - LOG_LEVEL_PRIORITY[right.candidate.level] || left.index - right.index;
175
+ });
176
+ const removedIndexes = /* @__PURE__ */ new Set();
177
+ let removedBytes = 0;
178
+ for (const { candidate, index } of candidates) {
179
+ removedIndexes.add(index);
180
+ removedBytes += candidate.bytes;
181
+ if (removedBytes >= requiredBytes) break;
182
+ }
183
+ if (removedBytes < requiredBytes) return false;
184
+ this.queue = this.queue.filter((candidate, index) => {
185
+ if (!removedIndexes.has(index)) return true;
186
+ this.queuedBytes -= candidate.bytes;
187
+ this.recordDrop(candidate.level);
188
+ return false;
189
+ });
190
+ return true;
191
+ }
192
+ recordDrop(level) {
193
+ this.dropped[level] += 1;
194
+ if (this.overflowReported) return;
195
+ this.overflowReported = true;
196
+ this.writeStderr("Log queue full; entries were dropped");
197
+ }
198
+ scheduleDrain() {
199
+ if (this.drainPromise) return;
200
+ const drain = Promise.resolve().then(() => this.drain()).catch((error) => {
201
+ this.discardPending();
202
+ this.reportWriteFailure(error);
203
+ });
204
+ this.drainPromise = drain;
205
+ void drain.then(() => {
206
+ if (this.drainPromise === drain) this.drainPromise = null;
207
+ if (this.queue.length > 0 || droppedCount(this.dropped) > 0) this.scheduleDrain();
208
+ });
209
+ }
210
+ async drain() {
211
+ while (this.queue.length > 0 || droppedCount(this.dropped) > 0) {
212
+ try {
213
+ await this.openCurrentFile();
214
+ } catch (error) {
215
+ this.discardPending();
216
+ this.reportWriteFailure(error);
217
+ return;
218
+ }
219
+ this.enqueueDropSummaryIfPossible();
220
+ if (this.queue.length === 0) return;
221
+ if (this.shouldRotate(this.queue[0].bytes)) await this.rotate();
222
+ const batch = this.takeBatch();
223
+ await this.appendBatch(batch);
224
+ }
225
+ }
226
+ enqueueDropSummaryIfPossible() {
227
+ if (droppedCount(this.dropped) === 0) return;
228
+ const summary = this.createDropSummary({ ...this.dropped });
229
+ if (summary.bytes > this.maxQueueBytes - this.queuedBytes) {
230
+ if (this.queue.length === 0) this.dropped = emptyDropCounts();
231
+ return;
232
+ }
233
+ this.dropped = emptyDropCounts();
234
+ this.queue.push({ ...summary, internal: true });
235
+ this.queuedBytes += summary.bytes;
236
+ }
237
+ takeBatch() {
238
+ const first = this.queue[0];
239
+ const remainingFileBytes = Math.max(0, this.maxFileBytes - this.currentBytes);
240
+ const batchLimit = this.currentBytes === 0 && first.bytes > this.maxFileBytes ? first.bytes : Math.min(MAX_BATCH_BYTES, remainingFileBytes);
241
+ let count = 0;
242
+ let bytes = 0;
243
+ for (const next of this.queue) {
244
+ if (count > 0 && next.bytes > batchLimit - bytes) break;
245
+ count += 1;
246
+ if (count === 1 && next.bytes > batchLimit) {
247
+ break;
248
+ }
249
+ bytes += next.bytes;
250
+ }
251
+ return this.queue.splice(0, count);
252
+ }
253
+ async appendBatch(batch) {
254
+ const bytes = batch.reduce((total, entry) => total + entry.bytes, 0);
255
+ this.inFlight = batch;
256
+ try {
257
+ if (!this.handle) throw new Error("Log file is not open");
258
+ if (this.needsRecoverySeparator && this.currentBytes > 0) {
259
+ await this.handle.writeFile("\n", "utf8");
260
+ this.currentBytes += 1;
261
+ }
262
+ this.needsRecoverySeparator = false;
263
+ await this.handle.writeFile(batch.map((entry) => entry.line).join(""), "utf8");
264
+ this.currentBytes += bytes;
265
+ this.writeFailureReported = false;
266
+ this.overflowReported = false;
267
+ } catch (error) {
268
+ this.needsRecoverySeparator = true;
269
+ for (const entry of batch) {
270
+ if (!entry.internal) this.recordDrop(entry.level);
271
+ }
272
+ await this.closeHandle();
273
+ this.reportWriteFailure(error);
274
+ } finally {
275
+ if (this.inFlight === batch) this.inFlight = [];
276
+ this.queuedBytes = Math.max(0, this.queuedBytes - bytes);
277
+ }
278
+ }
279
+ shouldRotate(nextBytes) {
280
+ return this.currentBytes > 0 && nextBytes > this.maxFileBytes - this.currentBytes;
281
+ }
282
+ async rotate() {
283
+ await this.closeHandle();
284
+ this.rotationIndex += 1;
285
+ const rotatedPath = join(this.logDir, `${this.prefix}-${this.rotationIndex}.log`);
286
+ await rename(this.currentPath, rotatedPath);
287
+ this.currentFileCreated = false;
288
+ this.currentBytes = 0;
289
+ await this.openCurrentFile();
290
+ }
291
+ async openCurrentFile() {
292
+ if (this.handle) return;
293
+ await this.prepareStorage();
294
+ const handle = await open(
295
+ this.currentPath,
296
+ this.currentFileCreated ? "a" : "ax",
297
+ PRIVATE_FILE_MODE
298
+ );
299
+ this.currentFileCreated = true;
300
+ try {
301
+ const stats = await handle.stat();
302
+ this.currentBytes = stats.size;
303
+ if (process.platform !== "win32") await chmod(this.currentPath, PRIVATE_FILE_MODE);
304
+ } catch (error) {
305
+ await handle.close().catch(() => void 0);
306
+ throw error;
307
+ }
308
+ this.handle = handle;
309
+ await this.pruneLogs();
310
+ }
311
+ async prepareStorage() {
312
+ if (this.storagePrepared) return;
313
+ await mkdir(this.logDir, { recursive: true, mode: PRIVATE_DIR_MODE });
314
+ if (process.platform !== "win32") await chmod(this.logDir, PRIVATE_DIR_MODE);
315
+ await this.restrictExistingLogs();
316
+ this.storagePrepared = true;
317
+ }
318
+ async restrictExistingLogs() {
319
+ if (process.platform === "win32") return;
320
+ const entries = await readdir(this.logDir, { withFileTypes: true });
321
+ await Promise.all(
322
+ entries.filter((entry) => entry.isFile() && isManagedLog(entry.name)).map(
323
+ (entry) => chmod(join(this.logDir, entry.name), PRIVATE_FILE_MODE).catch((error) => {
324
+ this.reportWriteFailure(error);
325
+ })
326
+ )
327
+ );
328
+ }
329
+ async pruneLogs() {
330
+ let files;
331
+ try {
332
+ files = await this.managedLogs();
333
+ } catch (error) {
334
+ this.reportWriteFailure(error);
335
+ return;
336
+ }
337
+ const now = Date.now();
338
+ for (const file of files) {
339
+ if (!file.isProtected && now - file.mtimeMs > this.maxAgeMs) {
340
+ if (await this.removeLog(file)) files = files.filter((item) => item.path !== file.path);
341
+ }
342
+ }
343
+ let totalBytes = files.reduce((total, file) => total + file.bytes, 0);
344
+ let totalFiles = files.length;
345
+ const candidates = files.filter((file) => !file.isProtected).toSorted(
346
+ (left, right) => left.mtimeMs - right.mtimeMs || left.name.localeCompare(right.name)
347
+ );
348
+ for (const file of candidates) {
349
+ if (totalFiles <= this.maxFiles && totalBytes <= this.maxDirectoryBytes) break;
350
+ if (!await this.removeLog(file)) continue;
351
+ totalFiles -= 1;
352
+ totalBytes = Math.max(0, totalBytes - file.bytes);
353
+ }
354
+ }
355
+ async managedLogs() {
356
+ const entries = await readdir(this.logDir, { withFileTypes: true });
357
+ const files = [];
358
+ for (const entry of entries) {
359
+ if (!entry.isFile() || !isManagedLog(entry.name)) continue;
360
+ const path = join(this.logDir, entry.name);
361
+ try {
362
+ const stats = await lstat(path);
363
+ if (!stats.isFile()) continue;
364
+ const pid = activeLogPid(entry.name);
365
+ files.push({
366
+ name: entry.name,
367
+ path,
368
+ bytes: stats.size,
369
+ mtimeMs: stats.mtimeMs,
370
+ isProtected: path === this.currentPath || ORIGINAL_ACTIVE_LOG_PATTERN.test(entry.name) || pid != null && isProcessAlive(pid)
371
+ });
372
+ } catch (error) {
373
+ if (errorCode(error) !== "ENOENT") this.reportWriteFailure(error);
374
+ }
375
+ }
376
+ return files;
377
+ }
378
+ async removeLog(file) {
379
+ try {
380
+ await unlink(file.path);
381
+ return true;
382
+ } catch (error) {
383
+ if (errorCode(error) === "ENOENT") return true;
384
+ this.reportWriteFailure(error);
385
+ return false;
386
+ }
387
+ }
388
+ async finishClose() {
389
+ await this.flush();
390
+ await this.closeHandle();
391
+ if (this.storagePrepared) await this.pruneLogs();
392
+ }
393
+ async closeHandle() {
394
+ const handle = this.handle;
395
+ this.handle = null;
396
+ if (!handle) return;
397
+ try {
398
+ await handle.close();
399
+ } catch (error) {
400
+ this.reportWriteFailure(error);
401
+ }
402
+ }
403
+ reportWriteFailure(error) {
404
+ if (this.writeFailureReported) return;
405
+ this.writeFailureReported = true;
406
+ const message = error instanceof Error ? error.message : String(error);
407
+ this.writeStderr(`Failed to write log ${this.currentPath}: ${message}`);
408
+ }
409
+ discardPending() {
410
+ this.queue.splice(0);
411
+ this.queuedBytes = 0;
412
+ this.dropped = emptyDropCounts();
413
+ }
414
+ writeStderr(message) {
415
+ try {
416
+ process.stderr.write(`[codesesh] ${message}
417
+ `);
418
+ } catch {
419
+ }
420
+ }
421
+ };
422
+
423
+ // src/log-record.ts
424
+ import { createHmac } from "crypto";
425
+ import { homedir } from "os";
426
+ import { types } from "util";
427
+ var LOG_SCHEMA_VERSION = 1;
428
+ var MIN_LOG_RECORD_BYTES = 512;
429
+ var MAX_ARRAY_ITEMS = 50;
430
+ var MAX_OBJECT_FIELDS = 100;
431
+ var MAX_DEPTH = 5;
432
+ var MAX_STRING_LENGTH = 4e3;
433
+ var MAX_SANITIZED_VALUES = 1e3;
434
+ var REDACTED_VALUE = "[redacted]";
435
+ var OMITTED_VALUE = "[omitted]";
436
+ var TRUNCATED_VALUE = "[truncated]";
437
+ var UNSERIALIZABLE_VALUE = "[unserializable]";
438
+ var ACCESSOR_VALUE = "[accessor]";
439
+ var CIRCULAR_VALUE = "[circular]";
440
+ var SAFE_SENTINELS = /* @__PURE__ */ new Set([
441
+ ACCESSOR_VALUE,
442
+ CIRCULAR_VALUE,
443
+ OMITTED_VALUE,
444
+ REDACTED_VALUE,
445
+ TRUNCATED_VALUE,
446
+ UNSERIALIZABLE_VALUE
447
+ ]);
448
+ var LOG_CONTEXT_KEYS = /* @__PURE__ */ new Set([
449
+ "request_id",
450
+ "operation_id",
451
+ "publication_id"
452
+ ]);
453
+ var CORRELATION_ID_KEYS = /* @__PURE__ */ new Set([...LOG_CONTEXT_KEYS, "connection_id"]);
454
+ var SENSITIVE_KEYS = /* @__PURE__ */ new Set([
455
+ "access_token",
456
+ "api_key",
457
+ "apikey",
458
+ "authorization",
459
+ "client_secret",
460
+ "cookie",
461
+ "credential",
462
+ "credentials",
463
+ "id_token",
464
+ "passphrase",
465
+ "passwd",
466
+ "password",
467
+ "private_key",
468
+ "refresh_token",
469
+ "secret",
470
+ "set_cookie",
471
+ "token"
472
+ ]);
473
+ var OMITTED_KEYS = /* @__PURE__ */ new Set([
474
+ "argv",
475
+ "body",
476
+ "command_args",
477
+ "content",
478
+ "env",
479
+ "environment",
480
+ "headers",
481
+ "http_body",
482
+ "message",
483
+ "messages",
484
+ "prompt",
485
+ "prompts",
486
+ "request_body",
487
+ "response_body",
488
+ "stderr",
489
+ "stdout",
490
+ "tool_output",
491
+ "tool_outputs",
492
+ "transcript",
493
+ "transcripts"
494
+ ]);
495
+ var IDENTIFIER_KEYS = /* @__PURE__ */ new Set([
496
+ "cursor",
497
+ "message_cursor",
498
+ "request_key",
499
+ "session",
500
+ "session_id"
501
+ ]);
502
+ var ERROR_TEXT_KEYS = /* @__PURE__ */ new Set(["cause", "error"]);
503
+ var KNOWN_AGENT_NAMES = new Set(AGENT_CATALOG.map(({ name }) => name));
504
+ var HTTP_METHODS = /* @__PURE__ */ new Set(["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"]);
505
+ var AUDITED_STRING_VALUES = /* @__PURE__ */ new Map([
506
+ [
507
+ "mode",
508
+ /* @__PURE__ */ new Set([
509
+ "agent",
510
+ "bulk",
511
+ "incremental",
512
+ "invalidRoute",
513
+ "missingAgent",
514
+ "project",
515
+ "projects",
516
+ "root",
517
+ "session"
518
+ ])
519
+ ],
520
+ ["phase", /* @__PURE__ */ new Set(["measure", "mount", "nested-update", "update"])],
521
+ [
522
+ "profiler_id",
523
+ /* @__PURE__ */ new Set([
524
+ "App",
525
+ "InteractiveReceipt",
526
+ "MainContent",
527
+ "MessageList",
528
+ "OverviewScreen",
529
+ "SearchControls",
530
+ "SearchResultsPanel",
531
+ "SessionDetail",
532
+ "SessionTreeSidebar"
533
+ ])
534
+ ],
535
+ ["source", /* @__PURE__ */ new Set(["commit-latency", "custom-timing", "react-profiler"])],
536
+ ["trigger", /* @__PURE__ */ new Set(["route"])],
537
+ ["reason", /* @__PURE__ */ new Set(["query-cancelled"])],
538
+ ["exception_origin", /* @__PURE__ */ new Set(["uncaughtException", "unhandledRejection"])]
539
+ ]);
540
+ var INTERNAL_PLAINTEXT_KEYS = /* @__PURE__ */ new Set([
541
+ "authentication",
542
+ "bind_category",
543
+ "cache",
544
+ "close_reason",
545
+ "context",
546
+ "encoding",
547
+ "endpoint",
548
+ "event",
549
+ "exception_origin",
550
+ "failure_stage",
551
+ "field",
552
+ "indexes",
553
+ "label",
554
+ "loopback_authority",
555
+ "message_update",
556
+ "operation",
557
+ "outcome",
558
+ "parameter",
559
+ "persistent_index_worker_job",
560
+ "publication_completeness",
561
+ "query_keys",
562
+ "request_type",
563
+ "result",
564
+ "route",
565
+ "signal",
566
+ "stage",
567
+ "state",
568
+ "status",
569
+ "transport",
570
+ "update",
571
+ "validation_outcome",
572
+ "version",
573
+ "worker_level"
574
+ ]);
575
+ var UUID_PATTERN2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
576
+ var FINGERPRINT_TOKEN_PATTERN = /^(?:error_message|field|identifier|path|string|url):[a-f0-9]{16}$/;
577
+ var PATH_KEY_PATTERN = /(?:^|_)(?:cwd|directory|file|path|root)$/;
578
+ var URL_KEY_PATTERN = /(?:^|_)(?:origin|url)$/;
579
+ var SENSITIVE_KEY_SUFFIX_PATTERN = /(?:^|_)(?:api_key|authorization|cookie|credential|credentials|passphrase|passwd|password|private_key|secret|token)$/;
580
+ var BEARER_PATTERN = /\bBearer\s+[^\s,;]+/gi;
581
+ var JWT_PATTERN = /\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/g;
582
+ var SECRET_QUERY_PATTERN = /([?&](?:access_token|api_key|apikey|password|secret|token)=)[^&#\s]*/gi;
583
+ var PRIVATE_KEY_PATTERN = /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g;
584
+ var INCOMPLETE_PRIVATE_KEY_PATTERN = /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*$/g;
585
+ var INCOMPLETE_JWT_PATTERN = /\beyJ[A-Za-z0-9_-]*(?:\.[A-Za-z0-9_-]*){0,2}$/g;
586
+ var LINE_BREAK_PATTERN = /\r\n|[\n\r]/;
587
+ function normalizedKey(key) {
588
+ return key.trim().replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^a-zA-Z0-9]+/g, "_").toLowerCase();
589
+ }
590
+ function isSensitiveKey(key) {
591
+ return SENSITIVE_KEYS.has(key) || SENSITIVE_KEY_SUFFIX_PATTERN.test(key);
592
+ }
593
+ function isIdentifierKey(key) {
594
+ return !CORRELATION_ID_KEYS.has(key) && (IDENTIFIER_KEYS.has(key) || /(?:^|_)(?:cursor|id|request_key|session_id)$/.test(key));
595
+ }
596
+ function isAuditedString(key, value) {
597
+ if ((key === "agent" || key === "agent_name" || key === "agents" || key === "failed_agents") && KNOWN_AGENT_NAMES.has(value)) {
598
+ return true;
599
+ }
600
+ if (key === "method" && HTTP_METHODS.has(value)) return true;
601
+ return AUDITED_STRING_VALUES.get(key)?.has(value) === true;
602
+ }
603
+ function windowsPathPattern(value) {
604
+ if (!/^(?:[a-z]:[\\/]|\\\\)/i.test(value)) return void 0;
605
+ const pattern = value.split(/[\\/]+/).map((segment) => segment.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("[\\\\/]+");
606
+ return new RegExp(pattern, "gi");
607
+ }
608
+ var LogRecordEncoder = class {
609
+ fingerprintKey;
610
+ maxRecordBytes;
611
+ personalPrefixes;
612
+ constructor(options) {
613
+ this.fingerprintKey = options.fingerprintKey;
614
+ this.maxRecordBytes = Math.max(
615
+ MIN_LOG_RECORD_BYTES,
616
+ Number.isFinite(options.maxRecordBytes) ? Math.floor(options.maxRecordBytes) : 0
617
+ );
618
+ const personalPrefixes = [
619
+ [options.currentWorkingDirectory ?? process.cwd(), "<cwd>"],
620
+ [options.homeDirectory ?? homedir(), "~"]
621
+ ];
622
+ this.personalPrefixes = personalPrefixes.toSorted(([left], [right]) => right.length - left.length).map(([prefix, replacement]) => ({
623
+ prefix,
624
+ replacement,
625
+ pattern: windowsPathPattern(prefix)
626
+ }));
627
+ }
628
+ encode(input) {
629
+ const budget = this.createSanitizationBudget();
630
+ const trustedCorrelationIds = !input.event.startsWith("client.");
631
+ const fixed = {
632
+ schema_version: LOG_SCHEMA_VERSION,
633
+ ts: input.timestamp,
634
+ level: input.level,
635
+ event: this.sanitizeEvent(input.event, budget),
636
+ run_id: input.runId,
637
+ seq: input.sequence,
638
+ pid: input.pid,
639
+ ...input.threadId == null ? {} : { thread_id: input.threadId }
640
+ };
641
+ const context = this.sanitizeContext(input.context, trustedCorrelationIds, budget);
642
+ const data = this.sanitizeFields(input.data, trustedCorrelationIds, budget);
643
+ const line = `${JSON.stringify({ ...data, ...context, ...fixed })}
644
+ `;
645
+ const bytes = Buffer.byteLength(line);
646
+ if (bytes <= this.maxRecordBytes) return { line, bytes, level: input.level };
647
+ const truncatedLine = `${JSON.stringify({
648
+ ...context,
649
+ ...fixed,
650
+ record_truncated: true,
651
+ original_bytes: bytes
652
+ })}
653
+ `;
654
+ const truncatedBytes = Buffer.byteLength(truncatedLine);
655
+ if (truncatedBytes <= this.maxRecordBytes) {
656
+ return { line: truncatedLine, bytes: truncatedBytes, level: input.level };
657
+ }
658
+ const minimalLine = `${JSON.stringify({
659
+ schema_version: LOG_SCHEMA_VERSION,
660
+ ts: input.timestamp.slice(0, 40).replace(/[^0-9TZ:.-]/g, "_"),
661
+ level: input.level,
662
+ event: fixed.event.slice(0, 64),
663
+ record_truncated: true,
664
+ original_bytes: bytes
665
+ })}
666
+ `;
667
+ return {
668
+ line: minimalLine,
669
+ bytes: Buffer.byteLength(minimalLine),
670
+ level: input.level
671
+ };
672
+ }
673
+ sanitizeForTransport(data, event = "") {
674
+ const sanitized = this.sanitizeFields(
675
+ data,
676
+ !event.startsWith("client."),
677
+ this.createSanitizationBudget()
678
+ );
679
+ const bytes = Buffer.byteLength(JSON.stringify(sanitized));
680
+ return bytes <= this.maxRecordBytes ? sanitized : { transport_truncated: true, original_bytes: bytes };
681
+ }
682
+ sanitizeFields(data, trustedCorrelationIds, budget) {
683
+ const normalized = this.sanitizeValue(
684
+ data,
685
+ "",
686
+ 0,
687
+ /* @__PURE__ */ new WeakSet(),
688
+ trustedCorrelationIds,
689
+ budget
690
+ );
691
+ return normalized && typeof normalized === "object" && !Array.isArray(normalized) ? normalized : { diagnostic_data: normalized };
692
+ }
693
+ sanitizeValue(value, key, depth, ancestors, trustedCorrelationIds, budget) {
694
+ if (budget.remainingValues <= 0 || budget.remainingCharacters <= 0) return TRUNCATED_VALUE;
695
+ budget.remainingValues -= 1;
696
+ const normalized = normalizedKey(this.takeKeyInput(key, budget));
697
+ if (isSensitiveKey(normalized)) return REDACTED_VALUE;
698
+ if (ERROR_TEXT_KEYS.has(normalized) && typeof value === "string") {
699
+ return this.fingerprint("error_message", value, budget);
700
+ }
701
+ if (OMITTED_KEYS.has(normalized) && value != null && typeof value !== "number" && typeof value !== "boolean") {
702
+ return OMITTED_VALUE;
703
+ }
704
+ const valueType = typeof value;
705
+ if ((valueType === "function" || valueType === "object" && value !== null) && types.isProxy(value)) {
706
+ return UNSERIALIZABLE_VALUE;
707
+ }
708
+ if (value == null || typeof value === "boolean") return value;
709
+ if (typeof value === "number") {
710
+ if (Number.isFinite(value)) return value;
711
+ return value === Number.POSITIVE_INFINITY ? "Infinity" : value === Number.NEGATIVE_INFINITY ? "-Infinity" : "NaN";
712
+ }
713
+ if (typeof value === "bigint") {
714
+ return this.sanitizeString(value.toString(), normalized, budget, trustedCorrelationIds);
715
+ }
716
+ if (typeof value === "string") {
717
+ if (normalized === "stack") return this.sanitizeStack(value, budget);
718
+ return this.sanitizeString(value, normalized, budget, trustedCorrelationIds);
719
+ }
720
+ if (typeof value !== "object") return OMITTED_VALUE;
721
+ if (depth >= MAX_DEPTH) return TRUNCATED_VALUE;
722
+ if (ArrayBuffer.isView(value) || types.isAnyArrayBuffer(value)) {
723
+ return OMITTED_VALUE;
724
+ }
725
+ if (ancestors.has(value)) return CIRCULAR_VALUE;
726
+ ancestors.add(value);
727
+ try {
728
+ if (types.isDate(value)) {
729
+ const timestamp = Date.prototype.getTime.call(value);
730
+ return Number.isNaN(timestamp) ? this.takeLiteral("Invalid Date", budget) : this.takeLiteral(Date.prototype.toISOString.call(value), budget);
731
+ }
732
+ const url = this.urlString(value);
733
+ if (url != null) {
734
+ return this.sanitizeString(url, "url", budget, trustedCorrelationIds);
735
+ }
736
+ if (types.isNativeError(value)) {
737
+ return this.sanitizeError(value, depth, ancestors, trustedCorrelationIds, budget);
738
+ }
739
+ if (Array.isArray(value)) {
740
+ return this.sanitizeArray(value, key, depth, ancestors, trustedCorrelationIds, budget);
741
+ }
742
+ if (types.isMap(value)) {
743
+ const result = [];
744
+ for (const [mapKey, item] of Map.prototype.entries.call(value)) {
745
+ result.push([
746
+ this.sanitizeValue(mapKey, "key", depth + 1, ancestors, trustedCorrelationIds, budget),
747
+ this.sanitizeValue(item, key, depth + 1, ancestors, trustedCorrelationIds, budget)
748
+ ]);
749
+ if (result.length >= MAX_ARRAY_ITEMS || budget.remainingValues <= 0 || budget.remainingCharacters <= 0) {
750
+ break;
751
+ }
752
+ }
753
+ return result;
754
+ }
755
+ if (types.isSet(value)) {
756
+ const result = [];
757
+ for (const item of Set.prototype.values.call(value)) {
758
+ result.push(
759
+ this.sanitizeValue(item, key, depth + 1, ancestors, trustedCorrelationIds, budget)
760
+ );
761
+ if (result.length >= MAX_ARRAY_ITEMS || budget.remainingValues <= 0 || budget.remainingCharacters <= 0) {
762
+ break;
763
+ }
764
+ }
765
+ return result;
766
+ }
767
+ return this.sanitizeObject(value, depth, ancestors, trustedCorrelationIds, budget);
768
+ } catch {
769
+ return UNSERIALIZABLE_VALUE;
770
+ } finally {
771
+ ancestors.delete(value);
772
+ }
773
+ }
774
+ sanitizeObject(value, depth, ancestors, trustedCorrelationIds, budget) {
775
+ let keys;
776
+ try {
777
+ keys = Object.getOwnPropertyNames(value).slice(0, MAX_OBJECT_FIELDS);
778
+ } catch {
779
+ return UNSERIALIZABLE_VALUE;
780
+ }
781
+ const result = {};
782
+ for (const key of keys) {
783
+ let descriptor;
784
+ try {
785
+ descriptor = Object.getOwnPropertyDescriptor(value, key);
786
+ } catch {
787
+ result[this.boundedFieldName(key, budget)] = UNSERIALIZABLE_VALUE;
788
+ if (budget.remainingCharacters <= 0) break;
789
+ continue;
790
+ }
791
+ if (!descriptor) continue;
792
+ result[this.boundedFieldName(key, budget)] = "value" in descriptor ? this.sanitizeValue(
793
+ descriptor.value,
794
+ key,
795
+ depth + 1,
796
+ ancestors,
797
+ trustedCorrelationIds,
798
+ budget
799
+ ) : ACCESSOR_VALUE;
800
+ if (budget.remainingValues <= 0 || budget.remainingCharacters <= 0) break;
801
+ }
802
+ return result;
803
+ }
804
+ sanitizeArray(value, key, depth, ancestors, trustedCorrelationIds, budget) {
805
+ const lengthDescriptor = Object.getOwnPropertyDescriptor(value, "length");
806
+ const length = lengthDescriptor && "value" in lengthDescriptor && typeof lengthDescriptor.value === "number" ? Math.min(lengthDescriptor.value, MAX_ARRAY_ITEMS) : 0;
807
+ const result = [];
808
+ for (let index = 0; index < length; index += 1) {
809
+ const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
810
+ result.push(
811
+ !descriptor ? null : "value" in descriptor ? this.sanitizeValue(
812
+ descriptor.value,
813
+ key,
814
+ depth + 1,
815
+ ancestors,
816
+ trustedCorrelationIds,
817
+ budget
818
+ ) : ACCESSOR_VALUE
819
+ );
820
+ if (budget.remainingValues <= 0 || budget.remainingCharacters <= 0) break;
821
+ }
822
+ return result;
823
+ }
824
+ sanitizeError(error, depth, ancestors, trustedCorrelationIds, budget) {
825
+ const code = this.errorProperty(error, "code");
826
+ const cause = this.errorProperty(error, "cause");
827
+ const message = this.errorStringProperty(error, "message", "");
828
+ const stack = this.errorStringProperty(error, "stack", "");
829
+ return {
830
+ name: this.sanitizeString(
831
+ this.errorStringProperty(error, "name", "Error"),
832
+ "name",
833
+ budget,
834
+ trustedCorrelationIds
835
+ ),
836
+ message_fingerprint: this.fingerprint("error_message", message, budget),
837
+ stack: this.sanitizeStack(stack, budget),
838
+ ...code == null ? {} : {
839
+ code: this.sanitizeValue(
840
+ code,
841
+ "code",
842
+ depth + 1,
843
+ ancestors,
844
+ trustedCorrelationIds,
845
+ budget
846
+ )
847
+ },
848
+ ...cause == null ? {} : {
849
+ cause: this.sanitizeValue(
850
+ cause,
851
+ "cause",
852
+ depth + 1,
853
+ ancestors,
854
+ trustedCorrelationIds,
855
+ budget
856
+ )
857
+ }
858
+ };
859
+ }
860
+ errorProperty(error, key) {
861
+ try {
862
+ const descriptor = Object.getOwnPropertyDescriptor(error, key);
863
+ if (!descriptor) return void 0;
864
+ return "value" in descriptor ? descriptor.value : ACCESSOR_VALUE;
865
+ } catch {
866
+ return UNSERIALIZABLE_VALUE;
867
+ }
868
+ }
869
+ errorStringProperty(error, key, fallback) {
870
+ const value = this.errorProperty(error, key);
871
+ return value == null ? fallback : typeof value === "string" ? value : UNSERIALIZABLE_VALUE;
872
+ }
873
+ urlString(value) {
874
+ try {
875
+ return URL.prototype.toString.call(value);
876
+ } catch {
877
+ return void 0;
878
+ }
879
+ }
880
+ createSanitizationBudget() {
881
+ return {
882
+ remainingValues: MAX_SANITIZED_VALUES,
883
+ remainingCharacters: Math.max(0, Math.floor(this.maxRecordBytes))
884
+ };
885
+ }
886
+ sanitizeContext(context, trustedCorrelationIds, budget) {
887
+ if (!context) return {};
888
+ return Object.fromEntries(
889
+ Object.entries(context).flatMap(
890
+ ([key, value]) => LOG_CONTEXT_KEYS.has(key) && typeof value === "string" && value.length > 0 ? [
891
+ [
892
+ key,
893
+ this.sanitizeString(value, normalizedKey(key), budget, trustedCorrelationIds).slice(
894
+ 0,
895
+ 160
896
+ )
897
+ ]
898
+ ] : []
899
+ )
900
+ );
901
+ }
902
+ sanitizeEvent(event, budget) {
903
+ return this.takePrefix(event, budget).trim().replace(/[^a-zA-Z0-9_.:-]/g, "_").slice(0, 160);
904
+ }
905
+ sanitizeString(value, key, budget, trustedCorrelationIds = false) {
906
+ if (FINGERPRINT_TOKEN_PATTERN.test(value) || SAFE_SENTINELS.has(value)) {
907
+ return this.takeLiteral(value, budget);
908
+ }
909
+ if (CORRELATION_ID_KEYS.has(key)) {
910
+ return trustedCorrelationIds || UUID_PATTERN2.test(value) ? this.takeLiteral(value, budget) : this.fingerprint("identifier", value, budget);
911
+ }
912
+ if (isAuditedString(key, value)) return this.takeLiteral(value, budget);
913
+ if (isIdentifierKey(key)) return this.fingerprint("identifier", value, budget);
914
+ if (trustedCorrelationIds && INTERNAL_PLAINTEXT_KEYS.has(key)) {
915
+ const bounded = this.takePrefix(value, budget);
916
+ return this.sanitizeBoundedString(bounded, key, bounded.length < value.length);
917
+ }
918
+ if (PATH_KEY_PATTERN.test(key)) return this.fingerprint("path", value, budget);
919
+ if (URL_KEY_PATTERN.test(key) && value.length > Math.min(MAX_STRING_LENGTH, budget.remainingCharacters)) {
920
+ return this.fingerprint("url", value, budget);
921
+ }
922
+ if (URL_KEY_PATTERN.test(key)) {
923
+ const bounded = this.takePrefix(value, budget);
924
+ return this.sanitizeBoundedString(bounded, key, bounded.length < value.length);
925
+ }
926
+ return this.fingerprint("string", value, budget);
927
+ }
928
+ takeLiteral(value, budget) {
929
+ if (value.length > budget.remainingCharacters) return TRUNCATED_VALUE;
930
+ budget.remainingCharacters -= value.length;
931
+ return value;
932
+ }
933
+ sanitizeStack(value, budget) {
934
+ const bounded = this.takePrefix(value, budget);
935
+ const inputTruncated = bounded.length < value.length;
936
+ const startsWithFrame = /^\s*at(?:\s|$)/.test(bounded);
937
+ const lineBreak = LINE_BREAK_PATTERN.exec(bounded);
938
+ if (!startsWithFrame && !lineBreak) return inputTruncated ? TRUNCATED_VALUE : "";
939
+ const stackBody = startsWithFrame ? bounded : bounded.slice(lineBreak.index + lineBreak[0].length);
940
+ const sanitized = this.sanitizeBoundedString(stackBody, "stack", inputTruncated);
941
+ return inputTruncated && !sanitized.endsWith(TRUNCATED_VALUE) ? `${sanitized}[truncated]` : sanitized;
942
+ }
943
+ sanitizeBoundedString(value, key, inputTruncated) {
944
+ let sanitized = value.replace(PRIVATE_KEY_PATTERN, REDACTED_VALUE).replace(BEARER_PATTERN, `Bearer ${REDACTED_VALUE}`).replace(JWT_PATTERN, REDACTED_VALUE).replace(SECRET_QUERY_PATTERN, `$1${REDACTED_VALUE}`);
945
+ if (inputTruncated) {
946
+ sanitized = sanitized.replace(INCOMPLETE_PRIVATE_KEY_PATTERN, REDACTED_VALUE).replace(INCOMPLETE_JWT_PATTERN, REDACTED_VALUE);
947
+ }
948
+ if (URL_KEY_PATTERN.test(key)) sanitized = this.sanitizeUrl(sanitized);
949
+ sanitized = this.replacePersonalPrefixes(sanitized);
950
+ return !inputTruncated && sanitized.length <= MAX_STRING_LENGTH ? sanitized : `${sanitized.slice(0, MAX_STRING_LENGTH)}[truncated]`;
951
+ }
952
+ takePrefix(value, budget) {
953
+ const length = Math.min(value.length, MAX_STRING_LENGTH, budget.remainingCharacters);
954
+ budget.remainingCharacters -= length;
955
+ return value.slice(0, length);
956
+ }
957
+ takeKeyInput(key, budget) {
958
+ const length = Math.min(key.length, MAX_STRING_LENGTH, budget.remainingCharacters);
959
+ budget.remainingCharacters -= length;
960
+ if (length >= key.length) return key;
961
+ if (length === 0) return "";
962
+ if (length < 3) return key.slice(-length);
963
+ const contentLength = length - 1;
964
+ const prefixLength = Math.ceil(contentLength / 2);
965
+ return `${key.slice(0, prefixLength)}_${key.slice(-(contentLength - prefixLength))}`;
966
+ }
967
+ boundedFieldName(key, budget) {
968
+ if (key.length <= MAX_STRING_LENGTH && key.length <= budget.remainingCharacters) {
969
+ budget.remainingCharacters -= key.length;
970
+ return key;
971
+ }
972
+ return this.fingerprint("field", key, budget);
973
+ }
974
+ sanitizeUrl(value) {
975
+ let url;
976
+ try {
977
+ url = new URL(value);
978
+ } catch {
979
+ return OMITTED_VALUE;
980
+ }
981
+ return url.origin === "null" ? OMITTED_VALUE : `${url.origin}/`;
982
+ }
983
+ replacePersonalPrefixes(value) {
984
+ return this.personalPrefixes.reduce(
985
+ (text, { prefix, replacement, pattern }) => pattern ? text.replace(pattern, replacement) : text.split(prefix).join(replacement),
986
+ value
987
+ );
988
+ }
989
+ fingerprint(kind, value, budget) {
990
+ if (FINGERPRINT_TOKEN_PATTERN.test(value)) return this.takeLiteral(value, budget);
991
+ const suffix = `\0${value.length}`;
992
+ const contentLength = MAX_STRING_LENGTH - suffix.length;
993
+ const prefixLength = Math.ceil(contentLength / 2);
994
+ const bounded = value.length <= MAX_STRING_LENGTH ? value : `${value.slice(0, prefixLength)}${value.slice(-(contentLength - prefixLength))}${suffix}`;
995
+ if (bounded.length > budget.remainingCharacters) return TRUNCATED_VALUE;
996
+ budget.remainingCharacters -= bounded.length;
997
+ const digest = createHmac("sha256", this.fingerprintKey).update(bounded).digest("hex").slice(0, 16);
998
+ return `${kind}:${digest}`;
999
+ }
1000
+ };
1001
+
1002
+ // src/logging.ts
1003
+ var DEFAULT_MAX_FILE_BYTES = 5e6;
1004
+ var DEFAULT_MAX_FILES = 10;
1005
+ var DEFAULT_MAX_DIRECTORY_BYTES = 5e7;
1006
+ var DEFAULT_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
1007
+ var DEFAULT_MAX_QUEUE_BYTES = 1e6;
1008
+ var DEFAULT_MAX_RECORD_BYTES = 64 * 1024;
1009
+ var FINGERPRINT_KEY_ENVIRONMENT_DATA = "codesesh.logging.fingerprint-key.v1";
1010
+ var LOG_CONTEXT_KEYS2 = /* @__PURE__ */ new Set([
1011
+ "request_id",
1012
+ "operation_id",
1013
+ "publication_id"
1014
+ ]);
1015
+ var LEVEL_WEIGHT = {
1016
+ debug: 10,
1017
+ info: 20,
1018
+ warn: 30,
1019
+ error: 40
1020
+ };
1021
+ function parseLevel(value) {
1022
+ if (value === "debug" || value === "info" || value === "warn" || value === "error") {
1023
+ return value;
1024
+ }
1025
+ return "info";
1026
+ }
1027
+ function positiveInteger(value, fallback) {
1028
+ const parsed = Math.floor(value ?? Number.NaN);
1029
+ return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : fallback;
1030
+ }
1031
+ function parsePositiveInteger(value, fallback) {
1032
+ return positiveInteger(value == null ? void 0 : Number(value), fallback);
1033
+ }
1034
+ function parseMaxAge(value) {
1035
+ const days = parsePositiveInteger(value, DEFAULT_MAX_AGE_MS / (24 * 60 * 60 * 1e3));
1036
+ const milliseconds = days * 24 * 60 * 60 * 1e3;
1037
+ return Number.isSafeInteger(milliseconds) ? milliseconds : DEFAULT_MAX_AGE_MS;
1038
+ }
1039
+ function getDefaultLogDir() {
1040
+ const base = process.env.XDG_CACHE_HOME ?? join2(homedir2(), ".cache");
1041
+ return join2(base, "codesesh", "logs");
1042
+ }
1043
+ function sharedFingerprintKey() {
1044
+ const existing = getEnvironmentData(FINGERPRINT_KEY_ENVIRONMENT_DATA);
1045
+ if (typeof existing === "string" && /^[a-f0-9]{64}$/.test(existing)) return existing;
1046
+ const generated = randomBytes(32).toString("hex");
1047
+ setEnvironmentData(FINGERPRINT_KEY_ENVIRONMENT_DATA, generated);
1048
+ return generated;
1049
+ }
1050
+ var LOG_FINGERPRINT_KEY = sharedFingerprintKey();
1051
+ function normalizedContext(context) {
1052
+ return Object.fromEntries(
1053
+ Object.entries(context).flatMap(
1054
+ ([key, value]) => LOG_CONTEXT_KEYS2.has(key) && typeof value === "string" && value.length > 0 ? [[key, value.slice(0, 160)]] : []
1055
+ )
1056
+ );
1057
+ }
1058
+ var AppLogger = class {
1059
+ level;
1060
+ runId;
1061
+ context = new AsyncLocalStorage();
1062
+ encoder;
1063
+ writer;
1064
+ workerTarget = null;
1065
+ sequence = 0;
1066
+ transportFailureReported = false;
1067
+ constructor(options = {}) {
1068
+ const logDir = options.logDir ?? process.env.CODESESH_LOG_DIR ?? getDefaultLogDir();
1069
+ this.level = options.level ?? parseLevel(process.env.CODESESH_LOG_LEVEL);
1070
+ this.runId = randomUUID();
1071
+ const maxRecordBytes = positiveInteger(
1072
+ options.maxRecordBytes,
1073
+ parsePositiveInteger(process.env.CODESESH_LOG_MAX_RECORD_BYTES, DEFAULT_MAX_RECORD_BYTES)
1074
+ );
1075
+ this.encoder = new LogRecordEncoder({
1076
+ fingerprintKey: LOG_FINGERPRINT_KEY,
1077
+ maxRecordBytes
1078
+ });
1079
+ this.writer = new AsyncLogFileWriter({
1080
+ logDir,
1081
+ runId: this.runId,
1082
+ maxFileBytes: positiveInteger(
1083
+ options.maxBytes,
1084
+ parsePositiveInteger(process.env.CODESESH_LOG_MAX_BYTES, DEFAULT_MAX_FILE_BYTES)
1085
+ ),
1086
+ maxFiles: positiveInteger(
1087
+ options.maxFiles,
1088
+ parsePositiveInteger(process.env.CODESESH_LOG_MAX_FILES, DEFAULT_MAX_FILES)
1089
+ ),
1090
+ maxDirectoryBytes: positiveInteger(
1091
+ options.maxDirectoryBytes,
1092
+ parsePositiveInteger(process.env.CODESESH_LOG_MAX_TOTAL_BYTES, DEFAULT_MAX_DIRECTORY_BYTES)
1093
+ ),
1094
+ maxAgeMs: positiveInteger(
1095
+ options.maxAgeMs,
1096
+ parseMaxAge(process.env.CODESESH_LOG_MAX_AGE_DAYS)
1097
+ ),
1098
+ maxQueueBytes: positiveInteger(
1099
+ options.maxQueueBytes,
1100
+ parsePositiveInteger(process.env.CODESESH_LOG_MAX_QUEUE_BYTES, DEFAULT_MAX_QUEUE_BYTES)
1101
+ ),
1102
+ createDropSummary: (counts) => this.encodeDropSummary(counts)
1103
+ });
1104
+ }
1105
+ getLogPath() {
1106
+ return this.writer.path;
1107
+ }
1108
+ runWithContext(context, operation) {
1109
+ return this.context.run({ ...this.captureContext(), ...normalizedContext(context) }, operation);
1110
+ }
1111
+ restoreContext(context, operation) {
1112
+ return this.context.run(normalizedContext(context), operation);
1113
+ }
1114
+ captureContext() {
1115
+ return { ...this.context.getStore() };
1116
+ }
1117
+ forwardToParent(port, threadId2) {
1118
+ this.workerTarget = { port, threadId: threadId2 };
1119
+ }
1120
+ consumeWorkerMessage(message) {
1121
+ if (!isWorkerLogMessage(message)) return false;
1122
+ if (LEVEL_WEIGHT[message.level] < LEVEL_WEIGHT[this.level]) return true;
1123
+ try {
1124
+ this.writer.enqueue(
1125
+ this.encode({
1126
+ timestamp: message.ts,
1127
+ level: message.level,
1128
+ event: message.event,
1129
+ pid: message.pid,
1130
+ threadId: message.threadId,
1131
+ context: message.context,
1132
+ data: message.data
1133
+ })
1134
+ );
1135
+ this.transportFailureReported = false;
1136
+ } catch (error) {
1137
+ this.reportTransportFailure(error);
1138
+ }
1139
+ return true;
1140
+ }
1141
+ debug(event, data = {}) {
1142
+ this.write("debug", event, data);
1143
+ }
1144
+ info(event, data = {}) {
1145
+ this.write("info", event, data);
1146
+ }
1147
+ warn(event, data = {}) {
1148
+ this.write("warn", event, data);
1149
+ }
1150
+ error(event, data = {}) {
1151
+ this.write("error", event, data);
1152
+ }
1153
+ flush() {
1154
+ return this.writer.flush();
1155
+ }
1156
+ close() {
1157
+ return this.writer.close();
1158
+ }
1159
+ flushSync() {
1160
+ this.writer.flushSync();
1161
+ }
1162
+ write(level, event, data) {
1163
+ if (LEVEL_WEIGHT[level] < LEVEL_WEIGHT[this.level]) return;
1164
+ try {
1165
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
1166
+ const context = this.captureContext();
1167
+ if (this.workerTarget) {
1168
+ this.workerTarget.port.postMessage({
1169
+ type: WORKER_LOG_MESSAGE_TYPE,
1170
+ ts: timestamp,
1171
+ level,
1172
+ event,
1173
+ pid: process.pid,
1174
+ threadId: this.workerTarget.threadId,
1175
+ context,
1176
+ data: this.encoder.sanitizeForTransport(data, event)
1177
+ });
1178
+ this.transportFailureReported = false;
1179
+ return;
1180
+ }
1181
+ this.writer.enqueue(
1182
+ this.encode({
1183
+ timestamp,
1184
+ level,
1185
+ event,
1186
+ pid: process.pid,
1187
+ context,
1188
+ data
1189
+ })
1190
+ );
1191
+ } catch (error) {
1192
+ this.reportTransportFailure(error);
1193
+ }
1194
+ }
1195
+ encode(input) {
1196
+ this.sequence += 1;
1197
+ return this.encoder.encode({
1198
+ ...input,
1199
+ runId: this.runId,
1200
+ sequence: this.sequence
1201
+ });
1202
+ }
1203
+ encodeDropSummary(counts) {
1204
+ return this.encode({
1205
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1206
+ level: "warn",
1207
+ event: "logger.records_dropped",
1208
+ pid: process.pid,
1209
+ data: { ...counts }
1210
+ });
1211
+ }
1212
+ reportTransportFailure(error) {
1213
+ if (this.transportFailureReported) return;
1214
+ this.transportFailureReported = true;
1215
+ const message = error instanceof Error ? error.message : String(error);
1216
+ try {
1217
+ process.stderr.write(`[codesesh] Failed to prepare log entry: ${message}
1218
+ `);
1219
+ } catch {
1220
+ }
1221
+ }
1222
+ };
1223
+ var appLogger = new AppLogger();
1224
+ function logSearchIndexSync(context, result, data = {}) {
1225
+ if (result?.failures?.length) {
1226
+ appLogger.warn("search_index.sessions_skipped", {
1227
+ context,
1228
+ agent: result.agentName,
1229
+ failures: result.failures
1230
+ });
1231
+ }
1232
+ if (!result) return;
1233
+ const detail = {
1234
+ context,
1235
+ agent: result.agentName,
1236
+ mode: result.mode,
1237
+ sessions: result.sessions,
1238
+ changed: result.changed,
1239
+ deleted: result.deleted,
1240
+ indexed: result.indexed,
1241
+ skipped: result.skipped,
1242
+ duration_ms: Math.round(result.durationMs),
1243
+ planning_ms: Math.round(result.planningDurationMs),
1244
+ get_session_data_calls: result.getSessionDataCalls,
1245
+ reused_materializations: result.reusedMaterializations,
1246
+ get_session_data_ms: Math.round(result.getSessionDataDurationMs),
1247
+ materialization_ms: Math.round(result.materializationDurationMs),
1248
+ rebuild_duration_ms: result.rebuildDurationMs != null ? Math.round(result.rebuildDurationMs) : void 0,
1249
+ ...data
1250
+ };
1251
+ if (result.mode === "bulk") appLogger.info("search_index.sync", detail);
1252
+ else appLogger.debug("search_index.sync", detail);
1253
+ }
1254
+
1255
+ // src/diagnostics-bridge.ts
1256
+ import { parentPort, threadId } from "worker_threads";
1257
+ if (parentPort) appLogger.forwardToParent(parentPort, threadId);
1258
+ setCoreDiagnostics({
1259
+ info(event, detail) {
1260
+ appLogger.info(event, detail);
1261
+ },
1262
+ warn(event, detail) {
1263
+ appLogger.warn(event, detail);
1264
+ }
1265
+ });
1266
+
1267
+ export {
1268
+ appLogger,
1269
+ logSearchIndexSync
1270
+ };
1271
+ //# sourceMappingURL=chunk-4QFNZCBR.js.map