@tracecode/harness 0.5.1 → 0.6.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 (49) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/README.md +30 -3
  3. package/dist/browser.cjs +974 -19
  4. package/dist/browser.cjs.map +1 -1
  5. package/dist/browser.d.cts +3 -2
  6. package/dist/browser.d.ts +3 -2
  7. package/dist/browser.js +974 -19
  8. package/dist/browser.js.map +1 -1
  9. package/dist/cli.cjs +24 -0
  10. package/dist/cli.cjs.map +1 -1
  11. package/dist/cli.js +24 -0
  12. package/dist/cli.js.map +1 -1
  13. package/dist/core.cjs +611 -4
  14. package/dist/core.cjs.map +1 -1
  15. package/dist/core.d.cts +20 -6
  16. package/dist/core.d.ts +20 -6
  17. package/dist/core.js +605 -4
  18. package/dist/core.js.map +1 -1
  19. package/dist/index.cjs +1004 -19
  20. package/dist/index.cjs.map +1 -1
  21. package/dist/index.d.cts +3 -3
  22. package/dist/index.d.ts +3 -3
  23. package/dist/index.js +998 -19
  24. package/dist/index.js.map +1 -1
  25. package/dist/internal/browser.cjs +211 -0
  26. package/dist/internal/browser.cjs.map +1 -1
  27. package/dist/internal/browser.d.cts +62 -6
  28. package/dist/internal/browser.d.ts +62 -6
  29. package/dist/internal/browser.js +210 -0
  30. package/dist/internal/browser.js.map +1 -1
  31. package/dist/javascript.d.cts +2 -2
  32. package/dist/javascript.d.ts +2 -2
  33. package/dist/{runtime-types-DtaaAhHL.d.ts → runtime-types-89nchXlY.d.cts} +8 -4
  34. package/dist/{runtime-types--lBQ6rYu.d.cts → runtime-types-CCQ-ZLc9.d.ts} +8 -4
  35. package/dist/{types-DwIYM3Ku.d.cts → types-zyvpJKCi.d.cts} +1 -0
  36. package/dist/{types-DwIYM3Ku.d.ts → types-zyvpJKCi.d.ts} +1 -0
  37. package/package.json +17 -5
  38. package/workers/java/.build/classes/harness/browser/JavaRewriteLibrary.class +0 -0
  39. package/workers/java/java-worker.js +712 -0
  40. package/workers/java/src/harness/browser/JavaRewriteLibrary.java +54 -0
  41. package/workers/javascript/javascript-worker.js +343 -63
  42. package/workers/python/generated-python-harness-snippets.js +3 -3
  43. package/workers/python/pyodide-worker.js +419 -68
  44. package/workers/python/runtime-core.js +52 -3
  45. package/workers/vendor/java-browser-spike-helper.jar +0 -0
  46. package/workers/vendor/java-practice-rewriter.jar +0 -0
  47. package/workers/vendor/java-rewrite-bridge.jar +0 -0
  48. package/workers/vendor/javaparser-core-3.25.10.jar +0 -0
  49. package/workers/vendor/jdk.compiler-17.jar +0 -0
package/dist/core.cjs CHANGED
@@ -22,15 +22,21 @@ var src_exports = {};
22
22
  __export(src_exports, {
23
23
  RUNTIME_TRACE_CONTRACT_SCHEMA_VERSION: () => RUNTIME_TRACE_CONTRACT_SCHEMA_VERSION,
24
24
  adaptJavaScriptTraceExecutionResult: () => adaptJavaScriptTraceExecutionResult,
25
+ adaptJavaSpikeTraceExecutionResult: () => adaptJavaTraceExecutionResult,
26
+ adaptJavaTraceExecutionResult: () => adaptJavaTraceExecutionResult,
25
27
  adaptPythonTraceExecutionResult: () => adaptPythonTraceExecutionResult,
26
28
  adaptTraceExecutionResult: () => adaptTraceExecutionResult,
29
+ buildJavaExecutionResult: () => buildJavaExecutionResult,
30
+ buildJavaSpikeExecutionResult: () => buildJavaExecutionResult,
31
+ normalizeJavaSpikeTraceContract: () => normalizeJavaTraceContract,
32
+ normalizeJavaTraceContract: () => normalizeJavaTraceContract,
27
33
  normalizeRuntimeTraceContract: () => normalizeRuntimeTraceContract,
28
34
  stableStringifyRuntimeTraceContract: () => stableStringifyRuntimeTraceContract
29
35
  });
30
36
  module.exports = __toCommonJS(src_exports);
31
37
 
32
38
  // packages/harness-core/src/trace-contract.ts
33
- var RUNTIME_TRACE_CONTRACT_SCHEMA_VERSION = "2026-03-13";
39
+ var RUNTIME_TRACE_CONTRACT_SCHEMA_VERSION = "2026-04-21";
34
40
  var TRACE_EVENTS = /* @__PURE__ */ new Set([
35
41
  "line",
36
42
  "call",
@@ -151,7 +157,39 @@ function normalizeAccesses(accesses) {
151
157
  }
152
158
  return payload;
153
159
  }).filter((access) => access !== null);
154
- return normalized.length > 0 ? normalized : void 0;
160
+ if (normalized.length === 0) {
161
+ return void 0;
162
+ }
163
+ const statsByVariable = /* @__PURE__ */ new Map();
164
+ for (const access of normalized) {
165
+ const stats = statsByVariable.get(access.variable) ?? { hasCellRead: false, hasCellWrite: false };
166
+ if (access.kind === "cell-read") stats.hasCellRead = true;
167
+ if (access.kind === "cell-write") stats.hasCellWrite = true;
168
+ statsByVariable.set(access.variable, stats);
169
+ }
170
+ const deduped = /* @__PURE__ */ new Set();
171
+ const collapsed = normalized.filter((access) => {
172
+ const stats = statsByVariable.get(access.variable);
173
+ if (access.kind === "indexed-read" && (stats?.hasCellRead || stats?.hasCellWrite)) {
174
+ return false;
175
+ }
176
+ if (access.kind === "indexed-write" && stats?.hasCellWrite) {
177
+ return false;
178
+ }
179
+ const key = JSON.stringify([
180
+ access.variable,
181
+ access.kind,
182
+ access.indices ?? null,
183
+ access.pathDepth ?? null,
184
+ access.method ?? null
185
+ ]);
186
+ if (deduped.has(key)) {
187
+ return false;
188
+ }
189
+ deduped.add(key);
190
+ return true;
191
+ });
192
+ return collapsed.length > 0 ? collapsed : void 0;
155
193
  }
156
194
  function normalizeRecord(value) {
157
195
  if (!value || typeof value !== "object" || Array.isArray(value)) return {};
@@ -215,8 +253,64 @@ function normalizeTraceStep(step) {
215
253
  ...normalizedVisualization ? { visualization: normalizedVisualization } : {}
216
254
  };
217
255
  }
256
+ function collapseTraceAccessNoise(trace) {
257
+ const variablesWithCellAccess = /* @__PURE__ */ new Set();
258
+ const accessStatsByVariable = /* @__PURE__ */ new Map();
259
+ for (const step of trace) {
260
+ for (const access of step.accesses ?? []) {
261
+ const stats = accessStatsByVariable.get(access.variable) ?? {
262
+ hasCellRead: false,
263
+ hasCellWrite: false,
264
+ hasMutatingCall: false,
265
+ hasIndexedWrite: false
266
+ };
267
+ if (access.kind === "cell-read" || access.kind === "cell-write") {
268
+ variablesWithCellAccess.add(access.variable);
269
+ }
270
+ if (access.kind === "cell-read") stats.hasCellRead = true;
271
+ if (access.kind === "cell-write") stats.hasCellWrite = true;
272
+ if (access.kind === "mutating-call") stats.hasMutatingCall = true;
273
+ if (access.kind === "indexed-write") stats.hasIndexedWrite = true;
274
+ accessStatsByVariable.set(access.variable, stats);
275
+ }
276
+ }
277
+ if (variablesWithCellAccess.size === 0) {
278
+ return trace;
279
+ }
280
+ return trace.map((step) => {
281
+ if (!step.accesses?.length) {
282
+ return step;
283
+ }
284
+ const filtered = step.accesses.filter((access) => {
285
+ const stats = accessStatsByVariable.get(access.variable);
286
+ if (variablesWithCellAccess.has(access.variable)) {
287
+ return access.kind !== "indexed-read" && access.kind !== "indexed-write";
288
+ }
289
+ if (access.kind === "mutating-call" && stats?.hasIndexedWrite && !stats.hasCellRead && !stats.hasCellWrite) {
290
+ return false;
291
+ }
292
+ if (access.kind === "indexed-read" && stats?.hasMutatingCall && !stats.hasIndexedWrite && !stats.hasCellRead && !stats.hasCellWrite) {
293
+ return false;
294
+ }
295
+ return true;
296
+ });
297
+ if (filtered.length === step.accesses.length) {
298
+ return step;
299
+ }
300
+ return {
301
+ ...step,
302
+ ...filtered.length > 0 ? { accesses: filtered } : {},
303
+ ...filtered.length === 0 ? { accesses: void 0 } : {}
304
+ };
305
+ });
306
+ }
218
307
  function normalizeRuntimeTraceContract(language, result) {
219
- const normalizedTrace = Array.isArray(result.trace) ? result.trace.map(normalizeTraceStep) : [];
308
+ const rawNormalizedTrace = collapseTraceAccessNoise(
309
+ Array.isArray(result.trace) ? result.trace.map(normalizeTraceStep) : []
310
+ );
311
+ const maxTraceSteps = typeof result.maxTraceSteps === "number" && Number.isFinite(result.maxTraceSteps) ? Math.max(1, Math.floor(result.maxTraceSteps)) : void 0;
312
+ const traceWasClipped = maxTraceSteps !== void 0 && rawNormalizedTrace.length > maxTraceSteps;
313
+ const normalizedTrace = traceWasClipped && maxTraceSteps !== void 0 ? rawNormalizedTrace.slice(0, maxTraceSteps) : rawNormalizedTrace;
220
314
  const lineEventCount = typeof result.lineEventCount === "number" && Number.isFinite(result.lineEventCount) ? Math.floor(result.lineEventCount) : normalizedTrace.filter((step) => step.event === "line").length;
221
315
  const normalizedConsole = Array.isArray(result.consoleOutput) ? result.consoleOutput.map((line) => String(line)) : [];
222
316
  return {
@@ -228,7 +322,7 @@ function normalizeRuntimeTraceContract(language, result) {
228
322
  ...typeof result.errorLine === "number" && Number.isFinite(result.errorLine) ? { errorLine: Math.floor(result.errorLine) } : {},
229
323
  consoleOutput: normalizedConsole,
230
324
  trace: normalizedTrace,
231
- ...result.traceLimitExceeded !== void 0 ? { traceLimitExceeded: Boolean(result.traceLimitExceeded) } : {},
325
+ ...result.traceLimitExceeded !== void 0 || traceWasClipped ? { traceLimitExceeded: Boolean(result.traceLimitExceeded) || traceWasClipped } : {},
232
326
  ...typeof result.timeoutReason === "string" && result.timeoutReason.length > 0 ? { timeoutReason: result.timeoutReason } : {},
233
327
  lineEventCount: Math.max(0, lineEventCount),
234
328
  traceStepCount: normalizedTrace.length
@@ -286,12 +380,525 @@ function adaptPythonTraceExecutionResult(result) {
286
380
  function adaptJavaScriptTraceExecutionResult(language, result) {
287
381
  return adaptTraceExecutionResult(language, result);
288
382
  }
383
+
384
+ // packages/harness-core/src/trace-adapters/java.ts
385
+ function parseScalar(raw) {
386
+ if (raw === "null") return null;
387
+ if (raw === "true") return true;
388
+ if (raw === "false") return false;
389
+ if (/^-?\d+$/.test(raw)) return Number.parseInt(raw, 10);
390
+ if (/^-?\d+\.\d+$/.test(raw)) return Number.parseFloat(raw);
391
+ if (raw.startsWith('"') && raw.endsWith('"') || raw.startsWith("[") && raw.endsWith("]") || raw.startsWith("{") && raw.endsWith("}")) {
392
+ try {
393
+ return JSON.parse(raw);
394
+ } catch {
395
+ }
396
+ }
397
+ return raw;
398
+ }
399
+ function parseKeyValuePairs(fragment) {
400
+ const variables = {};
401
+ const matches = Array.from(fragment.matchAll(/\b([A-Za-z_][A-Za-z0-9_.]*)=/g));
402
+ for (let index = 0; index < matches.length; index += 1) {
403
+ const match = matches[index];
404
+ const rawKey = match[1];
405
+ const valueStart = (match.index ?? 0) + match[0].length;
406
+ const valueEnd = index + 1 < matches.length ? matches[index + 1].index ?? fragment.length : fragment.length;
407
+ const rawValue = fragment.slice(valueStart, valueEnd).trim();
408
+ if (!rawKey || rawValue === void 0) continue;
409
+ if (rawKey === "method") continue;
410
+ variables[rawKey.replaceAll(".", "_")] = parseScalar(rawValue);
411
+ }
412
+ return variables;
413
+ }
414
+ function extractLineMetadata(event) {
415
+ const match = event.match(/^line=(\d+)(?:\s+(.*))?$/);
416
+ if (!match) {
417
+ return { line: 1, payload: event };
418
+ }
419
+ return {
420
+ line: Number.parseInt(match[1], 10),
421
+ payload: match[2] ?? ""
422
+ };
423
+ }
424
+ function stripInlineComments(line, inBlockComment) {
425
+ let result = "";
426
+ let index = 0;
427
+ let inBlock = inBlockComment;
428
+ while (index < line.length) {
429
+ const current = line[index];
430
+ const next = index + 1 < line.length ? line[index + 1] : "";
431
+ if (inBlock) {
432
+ if (current === "*" && next === "/") {
433
+ inBlock = false;
434
+ index += 2;
435
+ continue;
436
+ }
437
+ index += 1;
438
+ continue;
439
+ }
440
+ if (current === "/" && next === "*") {
441
+ inBlock = true;
442
+ index += 2;
443
+ continue;
444
+ }
445
+ if (current === "/" && next === "/") {
446
+ break;
447
+ }
448
+ result += current;
449
+ index += 1;
450
+ }
451
+ return { text: result, inBlockComment: inBlock };
452
+ }
453
+ function isMethodDeclarationLine(line) {
454
+ const trimmed = line.trim();
455
+ if (!trimmed) return false;
456
+ if (trimmed.startsWith("@")) return false;
457
+ if (!trimmed.includes("(") || !trimmed.includes(")")) return false;
458
+ if (trimmed.endsWith(";")) return false;
459
+ if (trimmed.includes("->")) return false;
460
+ if (/^(?:if|for|while|switch|catch|do|try|else|return|throw|new)\b/.test(trimmed)) {
461
+ return false;
462
+ }
463
+ if (!/[A-Za-z_][A-Za-z0-9_]*\s*\([^{};]*\)/.test(trimmed)) {
464
+ return false;
465
+ }
466
+ return /(?:\{\s*)?$/.test(trimmed);
467
+ }
468
+ function buildLineRemap(sourceText) {
469
+ if (typeof sourceText !== "string" || sourceText.length === 0) {
470
+ return null;
471
+ }
472
+ const lines = sourceText.split(/\r?\n/);
473
+ const executable = /* @__PURE__ */ new Set();
474
+ let inBlockComment = false;
475
+ for (let index = 0; index < lines.length; index += 1) {
476
+ const { text, inBlockComment: nextInBlockComment } = stripInlineComments(lines[index] ?? "", inBlockComment);
477
+ inBlockComment = nextInBlockComment;
478
+ if (text.trim().length > 0) {
479
+ executable.add(index + 1);
480
+ }
481
+ }
482
+ if (executable.size === 0) {
483
+ return null;
484
+ }
485
+ const nextExecutableAtOrAfter = new Array(lines.length + 2).fill(null);
486
+ let nextExecutable = null;
487
+ for (let line = lines.length; line >= 1; line -= 1) {
488
+ if (executable.has(line)) {
489
+ nextExecutable = line;
490
+ }
491
+ nextExecutableAtOrAfter[line] = nextExecutable;
492
+ }
493
+ const previousExecutableAtOrBefore = new Array(lines.length + 2).fill(null);
494
+ let previousExecutable = null;
495
+ for (let line = 1; line <= lines.length; line += 1) {
496
+ if (executable.has(line)) {
497
+ previousExecutable = line;
498
+ }
499
+ previousExecutableAtOrBefore[line] = previousExecutable;
500
+ }
501
+ const remap = /* @__PURE__ */ new Map();
502
+ for (let line = 1; line <= lines.length; line += 1) {
503
+ if (executable.has(line)) continue;
504
+ const forward = nextExecutableAtOrAfter[line];
505
+ const backward = previousExecutableAtOrBefore[line];
506
+ const target = forward ?? backward;
507
+ if (target !== null && target !== line) {
508
+ remap.set(line, target);
509
+ }
510
+ }
511
+ return remap;
512
+ }
513
+ function buildMethodDeclarationLineSet(sourceText) {
514
+ if (typeof sourceText !== "string" || sourceText.length === 0) {
515
+ return null;
516
+ }
517
+ const declarationLines = /* @__PURE__ */ new Set();
518
+ const lines = sourceText.split(/\r?\n/);
519
+ let inBlockComment = false;
520
+ for (let index = 0; index < lines.length; index += 1) {
521
+ const { text, inBlockComment: nextInBlockComment } = stripInlineComments(lines[index] ?? "", inBlockComment);
522
+ inBlockComment = nextInBlockComment;
523
+ if (isMethodDeclarationLine(text)) {
524
+ declarationLines.add(index + 1);
525
+ }
526
+ }
527
+ return declarationLines;
528
+ }
529
+ function parseAccessEvent(payload) {
530
+ const isEphemeralOutputArrayName = (name) => /^(output|outputs)$/i.test(name);
531
+ const cellRead = payload.match(/^access ([A-Za-z_][A-Za-z0-9_]*)\[(\d+)\]\[(\d+)\]=(.+)$/);
532
+ if (cellRead) {
533
+ return [{
534
+ variable: cellRead[1],
535
+ kind: "cell-read",
536
+ indices: [Number.parseInt(cellRead[2], 10), Number.parseInt(cellRead[3], 10)],
537
+ pathDepth: 2
538
+ }];
539
+ }
540
+ const indexedRead = payload.match(/^access ([A-Za-z_][A-Za-z0-9_]*)\[(\d+)\]=(.+)$/);
541
+ if (indexedRead) {
542
+ return [{
543
+ variable: indexedRead[1],
544
+ kind: "indexed-read",
545
+ indices: [Number.parseInt(indexedRead[2], 10)],
546
+ pathDepth: 1
547
+ }];
548
+ }
549
+ const cellWrite = payload.match(/^write-array ([A-Za-z_][A-Za-z0-9_]*)\[(\d+)\]\[(\d+)\]=(.+)$/);
550
+ if (cellWrite) {
551
+ return [{
552
+ variable: cellWrite[1],
553
+ kind: "cell-write",
554
+ indices: [Number.parseInt(cellWrite[2], 10), Number.parseInt(cellWrite[3], 10)],
555
+ pathDepth: 2
556
+ }];
557
+ }
558
+ const indexedWrite = payload.match(/^write-array ([A-Za-z_][A-Za-z0-9_]*)\[(\d+)\]=(.+)$/);
559
+ if (indexedWrite) {
560
+ if (isEphemeralOutputArrayName(indexedWrite[1])) {
561
+ return void 0;
562
+ }
563
+ return [{
564
+ variable: indexedWrite[1],
565
+ kind: "indexed-write",
566
+ indices: [Number.parseInt(indexedWrite[2], 10)],
567
+ pathDepth: 1
568
+ }];
569
+ }
570
+ const mutatingCall = payload.match(/^mutate ([A-Za-z_][A-Za-z0-9_]*) method=([A-Za-z_][A-Za-z0-9_]*)$/);
571
+ if (mutatingCall) {
572
+ return [{
573
+ variable: mutatingCall[1],
574
+ kind: "mutating-call",
575
+ method: mutatingCall[2],
576
+ pathDepth: 1
577
+ }];
578
+ }
579
+ return void 0;
580
+ }
581
+ function parseStructureState(payload) {
582
+ const match = payload.match(/^state (linked-list|tree) ([A-Za-z_][A-Za-z0-9_]*)=(.+)$/);
583
+ if (!match) return null;
584
+ return {
585
+ structure: match[1],
586
+ variable: match[2],
587
+ value: JSON.parse(match[3])
588
+ };
589
+ }
590
+ function parseObjectState(payload) {
591
+ const match = payload.match(/^object-state ([A-Za-z_][A-Za-z0-9_]*)=(.+)$/);
592
+ if (!match) return null;
593
+ return {
594
+ variable: match[1],
595
+ visualization: JSON.parse(match[2])
596
+ };
597
+ }
598
+ function parseObjectFieldEvent(payload) {
599
+ const match = payload.match(/^(access|write) ([A-Za-z_][A-Za-z0-9_]*)\.([A-Za-z_][A-Za-z0-9_]*)=(.+)$/);
600
+ if (!match) return null;
601
+ return {
602
+ variable: match[2],
603
+ field: match[3],
604
+ value: parseScalar(match[4])
605
+ };
606
+ }
607
+ function buildFieldVisualization(event) {
608
+ return {
609
+ objectKinds: {
610
+ [event.variable]: "object"
611
+ },
612
+ hashMaps: [
613
+ {
614
+ name: event.variable,
615
+ kind: "object",
616
+ objectClassName: event.field === "next" || event.field === "prev" ? "ListNode" : event.field === "left" || event.field === "right" ? "TreeNode" : void 0,
617
+ objectId: `${event.variable}-object`,
618
+ highlightedKey: event.field,
619
+ entries: [{ key: event.field, value: event.value, highlight: true }]
620
+ }
621
+ ]
622
+ };
623
+ }
624
+ function callStacksEqual(left, right) {
625
+ return JSON.stringify(left ?? []) === JSON.stringify(right ?? []);
626
+ }
627
+ function mergeVisualizationPayloads(left, right) {
628
+ if (!left) return right;
629
+ if (!right) return left;
630
+ return {
631
+ ...left,
632
+ ...right,
633
+ objectKinds: {
634
+ ...left.objectKinds ?? {},
635
+ ...right.objectKinds ?? {}
636
+ },
637
+ hashMaps: [
638
+ ...left.hashMaps ?? [],
639
+ ...right.hashMaps ?? []
640
+ ]
641
+ };
642
+ }
643
+ function maybeMergeConsecutiveLineStep(trace, nextStep) {
644
+ if (nextStep.event !== "line") {
645
+ return false;
646
+ }
647
+ const previous = trace.at(-1);
648
+ if (!previous || previous.event !== "line") {
649
+ return false;
650
+ }
651
+ if (previous.line !== nextStep.line || previous.function !== nextStep.function) {
652
+ return false;
653
+ }
654
+ if (!callStacksEqual(previous.callStack, nextStep.callStack)) {
655
+ return false;
656
+ }
657
+ previous.variables = { ...previous.variables ?? {}, ...nextStep.variables ?? {} };
658
+ if (nextStep.accesses?.length) {
659
+ previous.accesses = [...previous.accesses ?? [], ...nextStep.accesses];
660
+ }
661
+ previous.visualization = mergeVisualizationPayloads(previous.visualization, nextStep.visualization);
662
+ return true;
663
+ }
664
+ function filterStructuredVariables(variables) {
665
+ if (!variables) {
666
+ return void 0;
667
+ }
668
+ const isEphemeralOutputArrayName = (name) => /^(output|outputs)$/i.test(name);
669
+ const entries = Object.entries(variables).filter(([name, value]) => {
670
+ if (value === null || typeof value !== "object") {
671
+ return false;
672
+ }
673
+ if (!Array.isArray(value)) {
674
+ return true;
675
+ }
676
+ if (Array.isArray(value[0])) {
677
+ return true;
678
+ }
679
+ return !isEphemeralOutputArrayName(name);
680
+ });
681
+ if (entries.length === 0) {
682
+ return void 0;
683
+ }
684
+ return Object.fromEntries(entries);
685
+ }
686
+ function appendJavaTraceStep(trace, step, pendingAccesses) {
687
+ const nextStep = pendingAccesses.length > 0 ? { ...step, accesses: [...pendingAccesses] } : step;
688
+ pendingAccesses.length = 0;
689
+ if (!maybeMergeConsecutiveLineStep(trace, nextStep)) {
690
+ trace.push(nextStep);
691
+ }
692
+ }
693
+ function mergeIntoPreviousMatchingLineStep(trace, line, currentFunction, currentCallStack, patch) {
694
+ const candidate = trace.at(-1);
695
+ if (!candidate || candidate.event !== "line") {
696
+ return false;
697
+ }
698
+ if (candidate.line !== line || candidate.function !== currentFunction) {
699
+ return false;
700
+ }
701
+ if (!callStacksEqual(candidate.callStack, currentCallStack)) {
702
+ return false;
703
+ }
704
+ candidate.variables = { ...candidate.variables ?? {}, ...patch.variables ?? {} };
705
+ if (patch.accesses?.length) {
706
+ candidate.accesses = [...candidate.accesses ?? [], ...patch.accesses];
707
+ }
708
+ candidate.visualization = mergeVisualizationPayloads(candidate.visualization, patch.visualization);
709
+ return true;
710
+ }
711
+ function mergeAccessesIntoPreviousMatchingLineStep(trace, line, currentFunction, currentCallStack, accesses) {
712
+ return mergeIntoPreviousMatchingLineStep(trace, line, currentFunction, currentCallStack, {
713
+ variables: void 0,
714
+ accesses,
715
+ visualization: void 0
716
+ });
717
+ }
718
+ function eventsToRawTrace(events, sourceText) {
719
+ const trace = [];
720
+ const variables = {};
721
+ const objectKinds = {};
722
+ const stack = [];
723
+ const pendingAccesses = [];
724
+ let currentFunction = "<module>";
725
+ const lineRemap = buildLineRemap(sourceText);
726
+ const declarationLines = buildMethodDeclarationLineSet(sourceText);
727
+ for (const rawEvent of events) {
728
+ if (rawEvent === "clear" || rawEvent === "reset") continue;
729
+ const metadata = extractLineMetadata(rawEvent);
730
+ const line = lineRemap?.get(metadata.line) ?? metadata.line;
731
+ const payload = metadata.payload;
732
+ const isDeclarationLine = declarationLines?.has(line) === true;
733
+ if (payload.startsWith("call ")) {
734
+ const match = payload.match(/^call\s+(\S+)(?:\s+(.*))?$/);
735
+ const functionName = match?.[1] ?? currentFunction;
736
+ const argsFragment = match?.[2] ?? "";
737
+ Object.assign(variables, parseKeyValuePairs(argsFragment));
738
+ currentFunction = functionName || currentFunction;
739
+ stack.push({ function: currentFunction, line });
740
+ appendJavaTraceStep(trace, {
741
+ line,
742
+ event: "call",
743
+ function: currentFunction,
744
+ variables: { ...variables },
745
+ callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} }))
746
+ }, pendingAccesses);
747
+ continue;
748
+ }
749
+ if (payload.startsWith("return ")) {
750
+ const match = payload.match(/^return\s+(\S+)$/);
751
+ const functionName = match?.[1] ?? currentFunction;
752
+ const returnVariables = functionName === "<module>" ? { ...variables } : filterStructuredVariables(variables) ?? {};
753
+ appendJavaTraceStep(trace, {
754
+ line,
755
+ event: "return",
756
+ function: functionName || currentFunction,
757
+ variables: returnVariables,
758
+ callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} }))
759
+ }, pendingAccesses);
760
+ stack.pop();
761
+ currentFunction = stack[stack.length - 1]?.function ?? "<module>";
762
+ continue;
763
+ }
764
+ if (isDeclarationLine) {
765
+ continue;
766
+ }
767
+ if (payload.length === 0) {
768
+ appendJavaTraceStep(trace, {
769
+ line,
770
+ event: "line",
771
+ function: currentFunction,
772
+ variables: { ...variables },
773
+ ...stack.length > 0 ? { callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })) } : {}
774
+ }, pendingAccesses);
775
+ continue;
776
+ }
777
+ const structureState = parseStructureState(payload);
778
+ if (structureState) {
779
+ variables[structureState.variable] = structureState.value;
780
+ objectKinds[structureState.variable] = structureState.structure;
781
+ appendJavaTraceStep(trace, {
782
+ line,
783
+ event: "line",
784
+ function: currentFunction,
785
+ variables: { ...variables },
786
+ callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })),
787
+ visualization: {
788
+ objectKinds: { ...objectKinds }
789
+ }
790
+ }, pendingAccesses);
791
+ continue;
792
+ }
793
+ const objectState = parseObjectState(payload);
794
+ if (objectState) {
795
+ variables[objectState.variable] = { __ref__: objectState.visualization.objectId ?? `${objectState.variable}-object` };
796
+ appendJavaTraceStep(trace, {
797
+ line,
798
+ event: "line",
799
+ function: currentFunction,
800
+ variables: { ...variables },
801
+ callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })),
802
+ visualization: {
803
+ objectKinds: { [objectState.variable]: "object" },
804
+ hashMaps: [objectState.visualization]
805
+ }
806
+ }, pendingAccesses);
807
+ continue;
808
+ }
809
+ const objectField = parseObjectFieldEvent(payload);
810
+ if (objectField) {
811
+ variables[objectField.variable] = { __ref__: `${objectField.variable}-object` };
812
+ const currentCallStack = stack.length > 0 ? stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })) : void 0;
813
+ if (mergeIntoPreviousMatchingLineStep(trace, line, currentFunction, currentCallStack, {
814
+ variables: { ...variables },
815
+ accesses: void 0,
816
+ visualization: buildFieldVisualization(objectField)
817
+ })) {
818
+ continue;
819
+ }
820
+ appendJavaTraceStep(trace, {
821
+ line,
822
+ event: "line",
823
+ function: currentFunction,
824
+ variables: { ...variables },
825
+ callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })),
826
+ visualization: buildFieldVisualization(objectField)
827
+ }, pendingAccesses);
828
+ continue;
829
+ }
830
+ Object.assign(variables, parseKeyValuePairs(payload));
831
+ const accesses = parseAccessEvent(payload);
832
+ if (accesses) {
833
+ const currentCallStack = stack.length > 0 ? stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })) : void 0;
834
+ if (mergeAccessesIntoPreviousMatchingLineStep(trace, line, currentFunction, currentCallStack, accesses)) {
835
+ continue;
836
+ }
837
+ pendingAccesses.push(...accesses);
838
+ continue;
839
+ }
840
+ appendJavaTraceStep(trace, {
841
+ line,
842
+ event: "line",
843
+ function: currentFunction,
844
+ variables: { ...variables },
845
+ ...stack.length > 0 ? { callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })) } : {}
846
+ }, pendingAccesses);
847
+ }
848
+ if (pendingAccesses.length > 0 && trace.length > 0) {
849
+ const last = trace[trace.length - 1];
850
+ last.accesses = [...last.accesses ?? [], ...pendingAccesses];
851
+ }
852
+ return trace;
853
+ }
854
+ function buildJavaExecutionResult(output, events, executionTimeMs = 0, traceLimitExceeded, timeoutReason, maxTraceSteps, sourceText) {
855
+ const trace = eventsToRawTrace(events, sourceText);
856
+ return {
857
+ success: true,
858
+ output,
859
+ trace,
860
+ executionTimeMs,
861
+ consoleOutput: [],
862
+ ...traceLimitExceeded !== void 0 ? { traceLimitExceeded } : {},
863
+ ...maxTraceSteps !== void 0 ? { maxTraceSteps } : {},
864
+ ...timeoutReason ? { timeoutReason } : {},
865
+ lineEventCount: trace.filter((step) => step.event === "line").length,
866
+ traceStepCount: trace.length
867
+ };
868
+ }
869
+ function normalizeJavaTraceContract(result) {
870
+ const normalized = normalizeRuntimeTraceContract(
871
+ "java",
872
+ buildJavaExecutionResult(
873
+ result.output,
874
+ result.events,
875
+ 0,
876
+ result.traceLimitExceeded,
877
+ result.timeoutReason,
878
+ void 0,
879
+ result.sourceText
880
+ )
881
+ );
882
+ return {
883
+ ...normalized,
884
+ language: "java"
885
+ };
886
+ }
887
+ function adaptJavaTraceExecutionResult(result) {
888
+ return adaptTraceExecutionResult("java", result);
889
+ }
289
890
  // Annotate the CommonJS export names for ESM import in node:
290
891
  0 && (module.exports = {
291
892
  RUNTIME_TRACE_CONTRACT_SCHEMA_VERSION,
292
893
  adaptJavaScriptTraceExecutionResult,
894
+ adaptJavaSpikeTraceExecutionResult,
895
+ adaptJavaTraceExecutionResult,
293
896
  adaptPythonTraceExecutionResult,
294
897
  adaptTraceExecutionResult,
898
+ buildJavaExecutionResult,
899
+ buildJavaSpikeExecutionResult,
900
+ normalizeJavaSpikeTraceContract,
901
+ normalizeJavaTraceContract,
295
902
  normalizeRuntimeTraceContract,
296
903
  stableStringifyRuntimeTraceContract
297
904
  });