@tracecode/harness 0.5.1 → 0.6.0

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 +23 -0
  2. package/README.md +29 -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 +11 -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.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // packages/harness-core/src/trace-contract.ts
2
- var RUNTIME_TRACE_CONTRACT_SCHEMA_VERSION = "2026-03-13";
2
+ var RUNTIME_TRACE_CONTRACT_SCHEMA_VERSION = "2026-04-21";
3
3
  var TRACE_EVENTS = /* @__PURE__ */ new Set([
4
4
  "line",
5
5
  "call",
@@ -120,7 +120,39 @@ function normalizeAccesses(accesses) {
120
120
  }
121
121
  return payload;
122
122
  }).filter((access) => access !== null);
123
- return normalized.length > 0 ? normalized : void 0;
123
+ if (normalized.length === 0) {
124
+ return void 0;
125
+ }
126
+ const statsByVariable = /* @__PURE__ */ new Map();
127
+ for (const access of normalized) {
128
+ const stats = statsByVariable.get(access.variable) ?? { hasCellRead: false, hasCellWrite: false };
129
+ if (access.kind === "cell-read") stats.hasCellRead = true;
130
+ if (access.kind === "cell-write") stats.hasCellWrite = true;
131
+ statsByVariable.set(access.variable, stats);
132
+ }
133
+ const deduped = /* @__PURE__ */ new Set();
134
+ const collapsed = normalized.filter((access) => {
135
+ const stats = statsByVariable.get(access.variable);
136
+ if (access.kind === "indexed-read" && (stats?.hasCellRead || stats?.hasCellWrite)) {
137
+ return false;
138
+ }
139
+ if (access.kind === "indexed-write" && stats?.hasCellWrite) {
140
+ return false;
141
+ }
142
+ const key = JSON.stringify([
143
+ access.variable,
144
+ access.kind,
145
+ access.indices ?? null,
146
+ access.pathDepth ?? null,
147
+ access.method ?? null
148
+ ]);
149
+ if (deduped.has(key)) {
150
+ return false;
151
+ }
152
+ deduped.add(key);
153
+ return true;
154
+ });
155
+ return collapsed.length > 0 ? collapsed : void 0;
124
156
  }
125
157
  function normalizeRecord(value) {
126
158
  if (!value || typeof value !== "object" || Array.isArray(value)) return {};
@@ -184,8 +216,64 @@ function normalizeTraceStep(step) {
184
216
  ...normalizedVisualization ? { visualization: normalizedVisualization } : {}
185
217
  };
186
218
  }
219
+ function collapseTraceAccessNoise(trace) {
220
+ const variablesWithCellAccess = /* @__PURE__ */ new Set();
221
+ const accessStatsByVariable = /* @__PURE__ */ new Map();
222
+ for (const step of trace) {
223
+ for (const access of step.accesses ?? []) {
224
+ const stats = accessStatsByVariable.get(access.variable) ?? {
225
+ hasCellRead: false,
226
+ hasCellWrite: false,
227
+ hasMutatingCall: false,
228
+ hasIndexedWrite: false
229
+ };
230
+ if (access.kind === "cell-read" || access.kind === "cell-write") {
231
+ variablesWithCellAccess.add(access.variable);
232
+ }
233
+ if (access.kind === "cell-read") stats.hasCellRead = true;
234
+ if (access.kind === "cell-write") stats.hasCellWrite = true;
235
+ if (access.kind === "mutating-call") stats.hasMutatingCall = true;
236
+ if (access.kind === "indexed-write") stats.hasIndexedWrite = true;
237
+ accessStatsByVariable.set(access.variable, stats);
238
+ }
239
+ }
240
+ if (variablesWithCellAccess.size === 0) {
241
+ return trace;
242
+ }
243
+ return trace.map((step) => {
244
+ if (!step.accesses?.length) {
245
+ return step;
246
+ }
247
+ const filtered = step.accesses.filter((access) => {
248
+ const stats = accessStatsByVariable.get(access.variable);
249
+ if (variablesWithCellAccess.has(access.variable)) {
250
+ return access.kind !== "indexed-read" && access.kind !== "indexed-write";
251
+ }
252
+ if (access.kind === "mutating-call" && stats?.hasIndexedWrite && !stats.hasCellRead && !stats.hasCellWrite) {
253
+ return false;
254
+ }
255
+ if (access.kind === "indexed-read" && stats?.hasMutatingCall && !stats.hasIndexedWrite && !stats.hasCellRead && !stats.hasCellWrite) {
256
+ return false;
257
+ }
258
+ return true;
259
+ });
260
+ if (filtered.length === step.accesses.length) {
261
+ return step;
262
+ }
263
+ return {
264
+ ...step,
265
+ ...filtered.length > 0 ? { accesses: filtered } : {},
266
+ ...filtered.length === 0 ? { accesses: void 0 } : {}
267
+ };
268
+ });
269
+ }
187
270
  function normalizeRuntimeTraceContract(language, result) {
188
- const normalizedTrace = Array.isArray(result.trace) ? result.trace.map(normalizeTraceStep) : [];
271
+ const rawNormalizedTrace = collapseTraceAccessNoise(
272
+ Array.isArray(result.trace) ? result.trace.map(normalizeTraceStep) : []
273
+ );
274
+ const maxTraceSteps = typeof result.maxTraceSteps === "number" && Number.isFinite(result.maxTraceSteps) ? Math.max(1, Math.floor(result.maxTraceSteps)) : void 0;
275
+ const traceWasClipped = maxTraceSteps !== void 0 && rawNormalizedTrace.length > maxTraceSteps;
276
+ const normalizedTrace = traceWasClipped && maxTraceSteps !== void 0 ? rawNormalizedTrace.slice(0, maxTraceSteps) : rawNormalizedTrace;
189
277
  const lineEventCount = typeof result.lineEventCount === "number" && Number.isFinite(result.lineEventCount) ? Math.floor(result.lineEventCount) : normalizedTrace.filter((step) => step.event === "line").length;
190
278
  const normalizedConsole = Array.isArray(result.consoleOutput) ? result.consoleOutput.map((line) => String(line)) : [];
191
279
  return {
@@ -197,7 +285,7 @@ function normalizeRuntimeTraceContract(language, result) {
197
285
  ...typeof result.errorLine === "number" && Number.isFinite(result.errorLine) ? { errorLine: Math.floor(result.errorLine) } : {},
198
286
  consoleOutput: normalizedConsole,
199
287
  trace: normalizedTrace,
200
- ...result.traceLimitExceeded !== void 0 ? { traceLimitExceeded: Boolean(result.traceLimitExceeded) } : {},
288
+ ...result.traceLimitExceeded !== void 0 || traceWasClipped ? { traceLimitExceeded: Boolean(result.traceLimitExceeded) || traceWasClipped } : {},
201
289
  ...typeof result.timeoutReason === "string" && result.timeoutReason.length > 0 ? { timeoutReason: result.timeoutReason } : {},
202
290
  lineEventCount: Math.max(0, lineEventCount),
203
291
  traceStepCount: normalizedTrace.length
@@ -255,11 +343,524 @@ function adaptPythonTraceExecutionResult(result) {
255
343
  function adaptJavaScriptTraceExecutionResult(language, result) {
256
344
  return adaptTraceExecutionResult(language, result);
257
345
  }
346
+
347
+ // packages/harness-core/src/trace-adapters/java.ts
348
+ function parseScalar(raw) {
349
+ if (raw === "null") return null;
350
+ if (raw === "true") return true;
351
+ if (raw === "false") return false;
352
+ if (/^-?\d+$/.test(raw)) return Number.parseInt(raw, 10);
353
+ if (/^-?\d+\.\d+$/.test(raw)) return Number.parseFloat(raw);
354
+ if (raw.startsWith('"') && raw.endsWith('"') || raw.startsWith("[") && raw.endsWith("]") || raw.startsWith("{") && raw.endsWith("}")) {
355
+ try {
356
+ return JSON.parse(raw);
357
+ } catch {
358
+ }
359
+ }
360
+ return raw;
361
+ }
362
+ function parseKeyValuePairs(fragment) {
363
+ const variables = {};
364
+ const matches = Array.from(fragment.matchAll(/\b([A-Za-z_][A-Za-z0-9_.]*)=/g));
365
+ for (let index = 0; index < matches.length; index += 1) {
366
+ const match = matches[index];
367
+ const rawKey = match[1];
368
+ const valueStart = (match.index ?? 0) + match[0].length;
369
+ const valueEnd = index + 1 < matches.length ? matches[index + 1].index ?? fragment.length : fragment.length;
370
+ const rawValue = fragment.slice(valueStart, valueEnd).trim();
371
+ if (!rawKey || rawValue === void 0) continue;
372
+ if (rawKey === "method") continue;
373
+ variables[rawKey.replaceAll(".", "_")] = parseScalar(rawValue);
374
+ }
375
+ return variables;
376
+ }
377
+ function extractLineMetadata(event) {
378
+ const match = event.match(/^line=(\d+)(?:\s+(.*))?$/);
379
+ if (!match) {
380
+ return { line: 1, payload: event };
381
+ }
382
+ return {
383
+ line: Number.parseInt(match[1], 10),
384
+ payload: match[2] ?? ""
385
+ };
386
+ }
387
+ function stripInlineComments(line, inBlockComment) {
388
+ let result = "";
389
+ let index = 0;
390
+ let inBlock = inBlockComment;
391
+ while (index < line.length) {
392
+ const current = line[index];
393
+ const next = index + 1 < line.length ? line[index + 1] : "";
394
+ if (inBlock) {
395
+ if (current === "*" && next === "/") {
396
+ inBlock = false;
397
+ index += 2;
398
+ continue;
399
+ }
400
+ index += 1;
401
+ continue;
402
+ }
403
+ if (current === "/" && next === "*") {
404
+ inBlock = true;
405
+ index += 2;
406
+ continue;
407
+ }
408
+ if (current === "/" && next === "/") {
409
+ break;
410
+ }
411
+ result += current;
412
+ index += 1;
413
+ }
414
+ return { text: result, inBlockComment: inBlock };
415
+ }
416
+ function isMethodDeclarationLine(line) {
417
+ const trimmed = line.trim();
418
+ if (!trimmed) return false;
419
+ if (trimmed.startsWith("@")) return false;
420
+ if (!trimmed.includes("(") || !trimmed.includes(")")) return false;
421
+ if (trimmed.endsWith(";")) return false;
422
+ if (trimmed.includes("->")) return false;
423
+ if (/^(?:if|for|while|switch|catch|do|try|else|return|throw|new)\b/.test(trimmed)) {
424
+ return false;
425
+ }
426
+ if (!/[A-Za-z_][A-Za-z0-9_]*\s*\([^{};]*\)/.test(trimmed)) {
427
+ return false;
428
+ }
429
+ return /(?:\{\s*)?$/.test(trimmed);
430
+ }
431
+ function buildLineRemap(sourceText) {
432
+ if (typeof sourceText !== "string" || sourceText.length === 0) {
433
+ return null;
434
+ }
435
+ const lines = sourceText.split(/\r?\n/);
436
+ const executable = /* @__PURE__ */ new Set();
437
+ let inBlockComment = false;
438
+ for (let index = 0; index < lines.length; index += 1) {
439
+ const { text, inBlockComment: nextInBlockComment } = stripInlineComments(lines[index] ?? "", inBlockComment);
440
+ inBlockComment = nextInBlockComment;
441
+ if (text.trim().length > 0) {
442
+ executable.add(index + 1);
443
+ }
444
+ }
445
+ if (executable.size === 0) {
446
+ return null;
447
+ }
448
+ const nextExecutableAtOrAfter = new Array(lines.length + 2).fill(null);
449
+ let nextExecutable = null;
450
+ for (let line = lines.length; line >= 1; line -= 1) {
451
+ if (executable.has(line)) {
452
+ nextExecutable = line;
453
+ }
454
+ nextExecutableAtOrAfter[line] = nextExecutable;
455
+ }
456
+ const previousExecutableAtOrBefore = new Array(lines.length + 2).fill(null);
457
+ let previousExecutable = null;
458
+ for (let line = 1; line <= lines.length; line += 1) {
459
+ if (executable.has(line)) {
460
+ previousExecutable = line;
461
+ }
462
+ previousExecutableAtOrBefore[line] = previousExecutable;
463
+ }
464
+ const remap = /* @__PURE__ */ new Map();
465
+ for (let line = 1; line <= lines.length; line += 1) {
466
+ if (executable.has(line)) continue;
467
+ const forward = nextExecutableAtOrAfter[line];
468
+ const backward = previousExecutableAtOrBefore[line];
469
+ const target = forward ?? backward;
470
+ if (target !== null && target !== line) {
471
+ remap.set(line, target);
472
+ }
473
+ }
474
+ return remap;
475
+ }
476
+ function buildMethodDeclarationLineSet(sourceText) {
477
+ if (typeof sourceText !== "string" || sourceText.length === 0) {
478
+ return null;
479
+ }
480
+ const declarationLines = /* @__PURE__ */ new Set();
481
+ const lines = sourceText.split(/\r?\n/);
482
+ let inBlockComment = false;
483
+ for (let index = 0; index < lines.length; index += 1) {
484
+ const { text, inBlockComment: nextInBlockComment } = stripInlineComments(lines[index] ?? "", inBlockComment);
485
+ inBlockComment = nextInBlockComment;
486
+ if (isMethodDeclarationLine(text)) {
487
+ declarationLines.add(index + 1);
488
+ }
489
+ }
490
+ return declarationLines;
491
+ }
492
+ function parseAccessEvent(payload) {
493
+ const isEphemeralOutputArrayName = (name) => /^(output|outputs)$/i.test(name);
494
+ const cellRead = payload.match(/^access ([A-Za-z_][A-Za-z0-9_]*)\[(\d+)\]\[(\d+)\]=(.+)$/);
495
+ if (cellRead) {
496
+ return [{
497
+ variable: cellRead[1],
498
+ kind: "cell-read",
499
+ indices: [Number.parseInt(cellRead[2], 10), Number.parseInt(cellRead[3], 10)],
500
+ pathDepth: 2
501
+ }];
502
+ }
503
+ const indexedRead = payload.match(/^access ([A-Za-z_][A-Za-z0-9_]*)\[(\d+)\]=(.+)$/);
504
+ if (indexedRead) {
505
+ return [{
506
+ variable: indexedRead[1],
507
+ kind: "indexed-read",
508
+ indices: [Number.parseInt(indexedRead[2], 10)],
509
+ pathDepth: 1
510
+ }];
511
+ }
512
+ const cellWrite = payload.match(/^write-array ([A-Za-z_][A-Za-z0-9_]*)\[(\d+)\]\[(\d+)\]=(.+)$/);
513
+ if (cellWrite) {
514
+ return [{
515
+ variable: cellWrite[1],
516
+ kind: "cell-write",
517
+ indices: [Number.parseInt(cellWrite[2], 10), Number.parseInt(cellWrite[3], 10)],
518
+ pathDepth: 2
519
+ }];
520
+ }
521
+ const indexedWrite = payload.match(/^write-array ([A-Za-z_][A-Za-z0-9_]*)\[(\d+)\]=(.+)$/);
522
+ if (indexedWrite) {
523
+ if (isEphemeralOutputArrayName(indexedWrite[1])) {
524
+ return void 0;
525
+ }
526
+ return [{
527
+ variable: indexedWrite[1],
528
+ kind: "indexed-write",
529
+ indices: [Number.parseInt(indexedWrite[2], 10)],
530
+ pathDepth: 1
531
+ }];
532
+ }
533
+ const mutatingCall = payload.match(/^mutate ([A-Za-z_][A-Za-z0-9_]*) method=([A-Za-z_][A-Za-z0-9_]*)$/);
534
+ if (mutatingCall) {
535
+ return [{
536
+ variable: mutatingCall[1],
537
+ kind: "mutating-call",
538
+ method: mutatingCall[2],
539
+ pathDepth: 1
540
+ }];
541
+ }
542
+ return void 0;
543
+ }
544
+ function parseStructureState(payload) {
545
+ const match = payload.match(/^state (linked-list|tree) ([A-Za-z_][A-Za-z0-9_]*)=(.+)$/);
546
+ if (!match) return null;
547
+ return {
548
+ structure: match[1],
549
+ variable: match[2],
550
+ value: JSON.parse(match[3])
551
+ };
552
+ }
553
+ function parseObjectState(payload) {
554
+ const match = payload.match(/^object-state ([A-Za-z_][A-Za-z0-9_]*)=(.+)$/);
555
+ if (!match) return null;
556
+ return {
557
+ variable: match[1],
558
+ visualization: JSON.parse(match[2])
559
+ };
560
+ }
561
+ function parseObjectFieldEvent(payload) {
562
+ const match = payload.match(/^(access|write) ([A-Za-z_][A-Za-z0-9_]*)\.([A-Za-z_][A-Za-z0-9_]*)=(.+)$/);
563
+ if (!match) return null;
564
+ return {
565
+ variable: match[2],
566
+ field: match[3],
567
+ value: parseScalar(match[4])
568
+ };
569
+ }
570
+ function buildFieldVisualization(event) {
571
+ return {
572
+ objectKinds: {
573
+ [event.variable]: "object"
574
+ },
575
+ hashMaps: [
576
+ {
577
+ name: event.variable,
578
+ kind: "object",
579
+ objectClassName: event.field === "next" || event.field === "prev" ? "ListNode" : event.field === "left" || event.field === "right" ? "TreeNode" : void 0,
580
+ objectId: `${event.variable}-object`,
581
+ highlightedKey: event.field,
582
+ entries: [{ key: event.field, value: event.value, highlight: true }]
583
+ }
584
+ ]
585
+ };
586
+ }
587
+ function callStacksEqual(left, right) {
588
+ return JSON.stringify(left ?? []) === JSON.stringify(right ?? []);
589
+ }
590
+ function mergeVisualizationPayloads(left, right) {
591
+ if (!left) return right;
592
+ if (!right) return left;
593
+ return {
594
+ ...left,
595
+ ...right,
596
+ objectKinds: {
597
+ ...left.objectKinds ?? {},
598
+ ...right.objectKinds ?? {}
599
+ },
600
+ hashMaps: [
601
+ ...left.hashMaps ?? [],
602
+ ...right.hashMaps ?? []
603
+ ]
604
+ };
605
+ }
606
+ function maybeMergeConsecutiveLineStep(trace, nextStep) {
607
+ if (nextStep.event !== "line") {
608
+ return false;
609
+ }
610
+ const previous = trace.at(-1);
611
+ if (!previous || previous.event !== "line") {
612
+ return false;
613
+ }
614
+ if (previous.line !== nextStep.line || previous.function !== nextStep.function) {
615
+ return false;
616
+ }
617
+ if (!callStacksEqual(previous.callStack, nextStep.callStack)) {
618
+ return false;
619
+ }
620
+ previous.variables = { ...previous.variables ?? {}, ...nextStep.variables ?? {} };
621
+ if (nextStep.accesses?.length) {
622
+ previous.accesses = [...previous.accesses ?? [], ...nextStep.accesses];
623
+ }
624
+ previous.visualization = mergeVisualizationPayloads(previous.visualization, nextStep.visualization);
625
+ return true;
626
+ }
627
+ function filterStructuredVariables(variables) {
628
+ if (!variables) {
629
+ return void 0;
630
+ }
631
+ const isEphemeralOutputArrayName = (name) => /^(output|outputs)$/i.test(name);
632
+ const entries = Object.entries(variables).filter(([name, value]) => {
633
+ if (value === null || typeof value !== "object") {
634
+ return false;
635
+ }
636
+ if (!Array.isArray(value)) {
637
+ return true;
638
+ }
639
+ if (Array.isArray(value[0])) {
640
+ return true;
641
+ }
642
+ return !isEphemeralOutputArrayName(name);
643
+ });
644
+ if (entries.length === 0) {
645
+ return void 0;
646
+ }
647
+ return Object.fromEntries(entries);
648
+ }
649
+ function appendJavaTraceStep(trace, step, pendingAccesses) {
650
+ const nextStep = pendingAccesses.length > 0 ? { ...step, accesses: [...pendingAccesses] } : step;
651
+ pendingAccesses.length = 0;
652
+ if (!maybeMergeConsecutiveLineStep(trace, nextStep)) {
653
+ trace.push(nextStep);
654
+ }
655
+ }
656
+ function mergeIntoPreviousMatchingLineStep(trace, line, currentFunction, currentCallStack, patch) {
657
+ const candidate = trace.at(-1);
658
+ if (!candidate || candidate.event !== "line") {
659
+ return false;
660
+ }
661
+ if (candidate.line !== line || candidate.function !== currentFunction) {
662
+ return false;
663
+ }
664
+ if (!callStacksEqual(candidate.callStack, currentCallStack)) {
665
+ return false;
666
+ }
667
+ candidate.variables = { ...candidate.variables ?? {}, ...patch.variables ?? {} };
668
+ if (patch.accesses?.length) {
669
+ candidate.accesses = [...candidate.accesses ?? [], ...patch.accesses];
670
+ }
671
+ candidate.visualization = mergeVisualizationPayloads(candidate.visualization, patch.visualization);
672
+ return true;
673
+ }
674
+ function mergeAccessesIntoPreviousMatchingLineStep(trace, line, currentFunction, currentCallStack, accesses) {
675
+ return mergeIntoPreviousMatchingLineStep(trace, line, currentFunction, currentCallStack, {
676
+ variables: void 0,
677
+ accesses,
678
+ visualization: void 0
679
+ });
680
+ }
681
+ function eventsToRawTrace(events, sourceText) {
682
+ const trace = [];
683
+ const variables = {};
684
+ const objectKinds = {};
685
+ const stack = [];
686
+ const pendingAccesses = [];
687
+ let currentFunction = "<module>";
688
+ const lineRemap = buildLineRemap(sourceText);
689
+ const declarationLines = buildMethodDeclarationLineSet(sourceText);
690
+ for (const rawEvent of events) {
691
+ if (rawEvent === "clear" || rawEvent === "reset") continue;
692
+ const metadata = extractLineMetadata(rawEvent);
693
+ const line = lineRemap?.get(metadata.line) ?? metadata.line;
694
+ const payload = metadata.payload;
695
+ const isDeclarationLine = declarationLines?.has(line) === true;
696
+ if (payload.startsWith("call ")) {
697
+ const match = payload.match(/^call\s+(\S+)(?:\s+(.*))?$/);
698
+ const functionName = match?.[1] ?? currentFunction;
699
+ const argsFragment = match?.[2] ?? "";
700
+ Object.assign(variables, parseKeyValuePairs(argsFragment));
701
+ currentFunction = functionName || currentFunction;
702
+ stack.push({ function: currentFunction, line });
703
+ appendJavaTraceStep(trace, {
704
+ line,
705
+ event: "call",
706
+ function: currentFunction,
707
+ variables: { ...variables },
708
+ callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} }))
709
+ }, pendingAccesses);
710
+ continue;
711
+ }
712
+ if (payload.startsWith("return ")) {
713
+ const match = payload.match(/^return\s+(\S+)$/);
714
+ const functionName = match?.[1] ?? currentFunction;
715
+ const returnVariables = functionName === "<module>" ? { ...variables } : filterStructuredVariables(variables) ?? {};
716
+ appendJavaTraceStep(trace, {
717
+ line,
718
+ event: "return",
719
+ function: functionName || currentFunction,
720
+ variables: returnVariables,
721
+ callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} }))
722
+ }, pendingAccesses);
723
+ stack.pop();
724
+ currentFunction = stack[stack.length - 1]?.function ?? "<module>";
725
+ continue;
726
+ }
727
+ if (isDeclarationLine) {
728
+ continue;
729
+ }
730
+ if (payload.length === 0) {
731
+ appendJavaTraceStep(trace, {
732
+ line,
733
+ event: "line",
734
+ function: currentFunction,
735
+ variables: { ...variables },
736
+ ...stack.length > 0 ? { callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })) } : {}
737
+ }, pendingAccesses);
738
+ continue;
739
+ }
740
+ const structureState = parseStructureState(payload);
741
+ if (structureState) {
742
+ variables[structureState.variable] = structureState.value;
743
+ objectKinds[structureState.variable] = structureState.structure;
744
+ appendJavaTraceStep(trace, {
745
+ line,
746
+ event: "line",
747
+ function: currentFunction,
748
+ variables: { ...variables },
749
+ callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })),
750
+ visualization: {
751
+ objectKinds: { ...objectKinds }
752
+ }
753
+ }, pendingAccesses);
754
+ continue;
755
+ }
756
+ const objectState = parseObjectState(payload);
757
+ if (objectState) {
758
+ variables[objectState.variable] = { __ref__: objectState.visualization.objectId ?? `${objectState.variable}-object` };
759
+ appendJavaTraceStep(trace, {
760
+ line,
761
+ event: "line",
762
+ function: currentFunction,
763
+ variables: { ...variables },
764
+ callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })),
765
+ visualization: {
766
+ objectKinds: { [objectState.variable]: "object" },
767
+ hashMaps: [objectState.visualization]
768
+ }
769
+ }, pendingAccesses);
770
+ continue;
771
+ }
772
+ const objectField = parseObjectFieldEvent(payload);
773
+ if (objectField) {
774
+ variables[objectField.variable] = { __ref__: `${objectField.variable}-object` };
775
+ const currentCallStack = stack.length > 0 ? stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })) : void 0;
776
+ if (mergeIntoPreviousMatchingLineStep(trace, line, currentFunction, currentCallStack, {
777
+ variables: { ...variables },
778
+ accesses: void 0,
779
+ visualization: buildFieldVisualization(objectField)
780
+ })) {
781
+ continue;
782
+ }
783
+ appendJavaTraceStep(trace, {
784
+ line,
785
+ event: "line",
786
+ function: currentFunction,
787
+ variables: { ...variables },
788
+ callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })),
789
+ visualization: buildFieldVisualization(objectField)
790
+ }, pendingAccesses);
791
+ continue;
792
+ }
793
+ Object.assign(variables, parseKeyValuePairs(payload));
794
+ const accesses = parseAccessEvent(payload);
795
+ if (accesses) {
796
+ const currentCallStack = stack.length > 0 ? stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })) : void 0;
797
+ if (mergeAccessesIntoPreviousMatchingLineStep(trace, line, currentFunction, currentCallStack, accesses)) {
798
+ continue;
799
+ }
800
+ pendingAccesses.push(...accesses);
801
+ continue;
802
+ }
803
+ appendJavaTraceStep(trace, {
804
+ line,
805
+ event: "line",
806
+ function: currentFunction,
807
+ variables: { ...variables },
808
+ ...stack.length > 0 ? { callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })) } : {}
809
+ }, pendingAccesses);
810
+ }
811
+ if (pendingAccesses.length > 0 && trace.length > 0) {
812
+ const last = trace[trace.length - 1];
813
+ last.accesses = [...last.accesses ?? [], ...pendingAccesses];
814
+ }
815
+ return trace;
816
+ }
817
+ function buildJavaExecutionResult(output, events, executionTimeMs = 0, traceLimitExceeded, timeoutReason, maxTraceSteps, sourceText) {
818
+ const trace = eventsToRawTrace(events, sourceText);
819
+ return {
820
+ success: true,
821
+ output,
822
+ trace,
823
+ executionTimeMs,
824
+ consoleOutput: [],
825
+ ...traceLimitExceeded !== void 0 ? { traceLimitExceeded } : {},
826
+ ...maxTraceSteps !== void 0 ? { maxTraceSteps } : {},
827
+ ...timeoutReason ? { timeoutReason } : {},
828
+ lineEventCount: trace.filter((step) => step.event === "line").length,
829
+ traceStepCount: trace.length
830
+ };
831
+ }
832
+ function normalizeJavaTraceContract(result) {
833
+ const normalized = normalizeRuntimeTraceContract(
834
+ "java",
835
+ buildJavaExecutionResult(
836
+ result.output,
837
+ result.events,
838
+ 0,
839
+ result.traceLimitExceeded,
840
+ result.timeoutReason,
841
+ void 0,
842
+ result.sourceText
843
+ )
844
+ );
845
+ return {
846
+ ...normalized,
847
+ language: "java"
848
+ };
849
+ }
850
+ function adaptJavaTraceExecutionResult(result) {
851
+ return adaptTraceExecutionResult("java", result);
852
+ }
258
853
  export {
259
854
  RUNTIME_TRACE_CONTRACT_SCHEMA_VERSION,
260
855
  adaptJavaScriptTraceExecutionResult,
856
+ adaptJavaTraceExecutionResult as adaptJavaSpikeTraceExecutionResult,
857
+ adaptJavaTraceExecutionResult,
261
858
  adaptPythonTraceExecutionResult,
262
859
  adaptTraceExecutionResult,
860
+ buildJavaExecutionResult,
861
+ buildJavaExecutionResult as buildJavaSpikeExecutionResult,
862
+ normalizeJavaTraceContract as normalizeJavaSpikeTraceContract,
863
+ normalizeJavaTraceContract,
263
864
  normalizeRuntimeTraceContract,
264
865
  stableStringifyRuntimeTraceContract
265
866
  };