@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/index.cjs CHANGED
@@ -39,9 +39,13 @@ __export(src_exports, {
39
39
  TEMPLATE_PYTHON_TRACE_SERIALIZE_FUNCTION: () => TEMPLATE_PYTHON_TRACE_SERIALIZE_FUNCTION,
40
40
  TYPESCRIPT_RUNTIME_DECLARATIONS: () => TYPESCRIPT_RUNTIME_DECLARATIONS,
41
41
  adaptJavaScriptTraceExecutionResult: () => adaptJavaScriptTraceExecutionResult,
42
+ adaptJavaSpikeTraceExecutionResult: () => adaptJavaTraceExecutionResult,
43
+ adaptJavaTraceExecutionResult: () => adaptJavaTraceExecutionResult,
42
44
  adaptPythonTraceExecutionResult: () => adaptPythonTraceExecutionResult,
43
45
  adaptTraceExecutionResult: () => adaptTraceExecutionResult,
44
46
  assertRuntimeRequestSupported: () => assertRuntimeRequestSupported,
47
+ buildJavaExecutionResult: () => buildJavaExecutionResult,
48
+ buildJavaSpikeExecutionResult: () => buildJavaExecutionResult,
45
49
  createBrowserHarness: () => createBrowserHarness,
46
50
  executeJavaScriptCode: () => executeJavaScriptCode,
47
51
  executeJavaScriptWithTracing: () => executeJavaScriptWithTracing,
@@ -53,6 +57,8 @@ __export(src_exports, {
53
57
  getSupportedLanguageProfiles: () => getSupportedLanguageProfiles,
54
58
  identifyConversions: () => identifyConversions,
55
59
  isLanguageSupported: () => isLanguageSupported,
60
+ normalizeJavaSpikeTraceContract: () => normalizeJavaTraceContract,
61
+ normalizeJavaTraceContract: () => normalizeJavaTraceContract,
56
62
  normalizeRuntimeTraceContract: () => normalizeRuntimeTraceContract,
57
63
  resolveBrowserHarnessAssets: () => resolveBrowserHarnessAssets,
58
64
  stableStringifyRuntimeTraceContract: () => stableStringifyRuntimeTraceContract,
@@ -63,7 +69,7 @@ __export(src_exports, {
63
69
  module.exports = __toCommonJS(src_exports);
64
70
 
65
71
  // packages/harness-core/src/trace-contract.ts
66
- var RUNTIME_TRACE_CONTRACT_SCHEMA_VERSION = "2026-03-13";
72
+ var RUNTIME_TRACE_CONTRACT_SCHEMA_VERSION = "2026-04-21";
67
73
  var TRACE_EVENTS = /* @__PURE__ */ new Set([
68
74
  "line",
69
75
  "call",
@@ -184,7 +190,39 @@ function normalizeAccesses(accesses) {
184
190
  }
185
191
  return payload;
186
192
  }).filter((access) => access !== null);
187
- return normalized.length > 0 ? normalized : void 0;
193
+ if (normalized.length === 0) {
194
+ return void 0;
195
+ }
196
+ const statsByVariable = /* @__PURE__ */ new Map();
197
+ for (const access of normalized) {
198
+ const stats = statsByVariable.get(access.variable) ?? { hasCellRead: false, hasCellWrite: false };
199
+ if (access.kind === "cell-read") stats.hasCellRead = true;
200
+ if (access.kind === "cell-write") stats.hasCellWrite = true;
201
+ statsByVariable.set(access.variable, stats);
202
+ }
203
+ const deduped = /* @__PURE__ */ new Set();
204
+ const collapsed = normalized.filter((access) => {
205
+ const stats = statsByVariable.get(access.variable);
206
+ if (access.kind === "indexed-read" && (stats?.hasCellRead || stats?.hasCellWrite)) {
207
+ return false;
208
+ }
209
+ if (access.kind === "indexed-write" && stats?.hasCellWrite) {
210
+ return false;
211
+ }
212
+ const key = JSON.stringify([
213
+ access.variable,
214
+ access.kind,
215
+ access.indices ?? null,
216
+ access.pathDepth ?? null,
217
+ access.method ?? null
218
+ ]);
219
+ if (deduped.has(key)) {
220
+ return false;
221
+ }
222
+ deduped.add(key);
223
+ return true;
224
+ });
225
+ return collapsed.length > 0 ? collapsed : void 0;
188
226
  }
189
227
  function normalizeRecord(value) {
190
228
  if (!value || typeof value !== "object" || Array.isArray(value)) return {};
@@ -248,8 +286,64 @@ function normalizeTraceStep(step) {
248
286
  ...normalizedVisualization ? { visualization: normalizedVisualization } : {}
249
287
  };
250
288
  }
289
+ function collapseTraceAccessNoise(trace) {
290
+ const variablesWithCellAccess = /* @__PURE__ */ new Set();
291
+ const accessStatsByVariable = /* @__PURE__ */ new Map();
292
+ for (const step of trace) {
293
+ for (const access of step.accesses ?? []) {
294
+ const stats = accessStatsByVariable.get(access.variable) ?? {
295
+ hasCellRead: false,
296
+ hasCellWrite: false,
297
+ hasMutatingCall: false,
298
+ hasIndexedWrite: false
299
+ };
300
+ if (access.kind === "cell-read" || access.kind === "cell-write") {
301
+ variablesWithCellAccess.add(access.variable);
302
+ }
303
+ if (access.kind === "cell-read") stats.hasCellRead = true;
304
+ if (access.kind === "cell-write") stats.hasCellWrite = true;
305
+ if (access.kind === "mutating-call") stats.hasMutatingCall = true;
306
+ if (access.kind === "indexed-write") stats.hasIndexedWrite = true;
307
+ accessStatsByVariable.set(access.variable, stats);
308
+ }
309
+ }
310
+ if (variablesWithCellAccess.size === 0) {
311
+ return trace;
312
+ }
313
+ return trace.map((step) => {
314
+ if (!step.accesses?.length) {
315
+ return step;
316
+ }
317
+ const filtered = step.accesses.filter((access) => {
318
+ const stats = accessStatsByVariable.get(access.variable);
319
+ if (variablesWithCellAccess.has(access.variable)) {
320
+ return access.kind !== "indexed-read" && access.kind !== "indexed-write";
321
+ }
322
+ if (access.kind === "mutating-call" && stats?.hasIndexedWrite && !stats.hasCellRead && !stats.hasCellWrite) {
323
+ return false;
324
+ }
325
+ if (access.kind === "indexed-read" && stats?.hasMutatingCall && !stats.hasIndexedWrite && !stats.hasCellRead && !stats.hasCellWrite) {
326
+ return false;
327
+ }
328
+ return true;
329
+ });
330
+ if (filtered.length === step.accesses.length) {
331
+ return step;
332
+ }
333
+ return {
334
+ ...step,
335
+ ...filtered.length > 0 ? { accesses: filtered } : {},
336
+ ...filtered.length === 0 ? { accesses: void 0 } : {}
337
+ };
338
+ });
339
+ }
251
340
  function normalizeRuntimeTraceContract(language, result) {
252
- const normalizedTrace = Array.isArray(result.trace) ? result.trace.map(normalizeTraceStep) : [];
341
+ const rawNormalizedTrace = collapseTraceAccessNoise(
342
+ Array.isArray(result.trace) ? result.trace.map(normalizeTraceStep) : []
343
+ );
344
+ const maxTraceSteps = typeof result.maxTraceSteps === "number" && Number.isFinite(result.maxTraceSteps) ? Math.max(1, Math.floor(result.maxTraceSteps)) : void 0;
345
+ const traceWasClipped = maxTraceSteps !== void 0 && rawNormalizedTrace.length > maxTraceSteps;
346
+ const normalizedTrace = traceWasClipped && maxTraceSteps !== void 0 ? rawNormalizedTrace.slice(0, maxTraceSteps) : rawNormalizedTrace;
253
347
  const lineEventCount = typeof result.lineEventCount === "number" && Number.isFinite(result.lineEventCount) ? Math.floor(result.lineEventCount) : normalizedTrace.filter((step) => step.event === "line").length;
254
348
  const normalizedConsole = Array.isArray(result.consoleOutput) ? result.consoleOutput.map((line) => String(line)) : [];
255
349
  return {
@@ -261,7 +355,7 @@ function normalizeRuntimeTraceContract(language, result) {
261
355
  ...typeof result.errorLine === "number" && Number.isFinite(result.errorLine) ? { errorLine: Math.floor(result.errorLine) } : {},
262
356
  consoleOutput: normalizedConsole,
263
357
  trace: normalizedTrace,
264
- ...result.traceLimitExceeded !== void 0 ? { traceLimitExceeded: Boolean(result.traceLimitExceeded) } : {},
358
+ ...result.traceLimitExceeded !== void 0 || traceWasClipped ? { traceLimitExceeded: Boolean(result.traceLimitExceeded) || traceWasClipped } : {},
265
359
  ...typeof result.timeoutReason === "string" && result.timeoutReason.length > 0 ? { timeoutReason: result.timeoutReason } : {},
266
360
  lineEventCount: Math.max(0, lineEventCount),
267
361
  traceStepCount: normalizedTrace.length
@@ -320,6 +414,513 @@ function adaptJavaScriptTraceExecutionResult(language, result) {
320
414
  return adaptTraceExecutionResult(language, result);
321
415
  }
322
416
 
417
+ // packages/harness-core/src/trace-adapters/java.ts
418
+ function parseScalar(raw) {
419
+ if (raw === "null") return null;
420
+ if (raw === "true") return true;
421
+ if (raw === "false") return false;
422
+ if (/^-?\d+$/.test(raw)) return Number.parseInt(raw, 10);
423
+ if (/^-?\d+\.\d+$/.test(raw)) return Number.parseFloat(raw);
424
+ if (raw.startsWith('"') && raw.endsWith('"') || raw.startsWith("[") && raw.endsWith("]") || raw.startsWith("{") && raw.endsWith("}")) {
425
+ try {
426
+ return JSON.parse(raw);
427
+ } catch {
428
+ }
429
+ }
430
+ return raw;
431
+ }
432
+ function parseKeyValuePairs(fragment) {
433
+ const variables = {};
434
+ const matches = Array.from(fragment.matchAll(/\b([A-Za-z_][A-Za-z0-9_.]*)=/g));
435
+ for (let index = 0; index < matches.length; index += 1) {
436
+ const match = matches[index];
437
+ const rawKey = match[1];
438
+ const valueStart = (match.index ?? 0) + match[0].length;
439
+ const valueEnd = index + 1 < matches.length ? matches[index + 1].index ?? fragment.length : fragment.length;
440
+ const rawValue = fragment.slice(valueStart, valueEnd).trim();
441
+ if (!rawKey || rawValue === void 0) continue;
442
+ if (rawKey === "method") continue;
443
+ variables[rawKey.replaceAll(".", "_")] = parseScalar(rawValue);
444
+ }
445
+ return variables;
446
+ }
447
+ function extractLineMetadata(event) {
448
+ const match = event.match(/^line=(\d+)(?:\s+(.*))?$/);
449
+ if (!match) {
450
+ return { line: 1, payload: event };
451
+ }
452
+ return {
453
+ line: Number.parseInt(match[1], 10),
454
+ payload: match[2] ?? ""
455
+ };
456
+ }
457
+ function stripInlineComments(line, inBlockComment) {
458
+ let result = "";
459
+ let index = 0;
460
+ let inBlock = inBlockComment;
461
+ while (index < line.length) {
462
+ const current = line[index];
463
+ const next = index + 1 < line.length ? line[index + 1] : "";
464
+ if (inBlock) {
465
+ if (current === "*" && next === "/") {
466
+ inBlock = false;
467
+ index += 2;
468
+ continue;
469
+ }
470
+ index += 1;
471
+ continue;
472
+ }
473
+ if (current === "/" && next === "*") {
474
+ inBlock = true;
475
+ index += 2;
476
+ continue;
477
+ }
478
+ if (current === "/" && next === "/") {
479
+ break;
480
+ }
481
+ result += current;
482
+ index += 1;
483
+ }
484
+ return { text: result, inBlockComment: inBlock };
485
+ }
486
+ function isMethodDeclarationLine(line) {
487
+ const trimmed = line.trim();
488
+ if (!trimmed) return false;
489
+ if (trimmed.startsWith("@")) return false;
490
+ if (!trimmed.includes("(") || !trimmed.includes(")")) return false;
491
+ if (trimmed.endsWith(";")) return false;
492
+ if (trimmed.includes("->")) return false;
493
+ if (/^(?:if|for|while|switch|catch|do|try|else|return|throw|new)\b/.test(trimmed)) {
494
+ return false;
495
+ }
496
+ if (!/[A-Za-z_][A-Za-z0-9_]*\s*\([^{};]*\)/.test(trimmed)) {
497
+ return false;
498
+ }
499
+ return /(?:\{\s*)?$/.test(trimmed);
500
+ }
501
+ function buildLineRemap(sourceText) {
502
+ if (typeof sourceText !== "string" || sourceText.length === 0) {
503
+ return null;
504
+ }
505
+ const lines = sourceText.split(/\r?\n/);
506
+ const executable = /* @__PURE__ */ new Set();
507
+ let inBlockComment = false;
508
+ for (let index = 0; index < lines.length; index += 1) {
509
+ const { text, inBlockComment: nextInBlockComment } = stripInlineComments(lines[index] ?? "", inBlockComment);
510
+ inBlockComment = nextInBlockComment;
511
+ if (text.trim().length > 0) {
512
+ executable.add(index + 1);
513
+ }
514
+ }
515
+ if (executable.size === 0) {
516
+ return null;
517
+ }
518
+ const nextExecutableAtOrAfter = new Array(lines.length + 2).fill(null);
519
+ let nextExecutable = null;
520
+ for (let line = lines.length; line >= 1; line -= 1) {
521
+ if (executable.has(line)) {
522
+ nextExecutable = line;
523
+ }
524
+ nextExecutableAtOrAfter[line] = nextExecutable;
525
+ }
526
+ const previousExecutableAtOrBefore = new Array(lines.length + 2).fill(null);
527
+ let previousExecutable = null;
528
+ for (let line = 1; line <= lines.length; line += 1) {
529
+ if (executable.has(line)) {
530
+ previousExecutable = line;
531
+ }
532
+ previousExecutableAtOrBefore[line] = previousExecutable;
533
+ }
534
+ const remap = /* @__PURE__ */ new Map();
535
+ for (let line = 1; line <= lines.length; line += 1) {
536
+ if (executable.has(line)) continue;
537
+ const forward = nextExecutableAtOrAfter[line];
538
+ const backward = previousExecutableAtOrBefore[line];
539
+ const target = forward ?? backward;
540
+ if (target !== null && target !== line) {
541
+ remap.set(line, target);
542
+ }
543
+ }
544
+ return remap;
545
+ }
546
+ function buildMethodDeclarationLineSet(sourceText) {
547
+ if (typeof sourceText !== "string" || sourceText.length === 0) {
548
+ return null;
549
+ }
550
+ const declarationLines = /* @__PURE__ */ new Set();
551
+ const lines = sourceText.split(/\r?\n/);
552
+ let inBlockComment = false;
553
+ for (let index = 0; index < lines.length; index += 1) {
554
+ const { text, inBlockComment: nextInBlockComment } = stripInlineComments(lines[index] ?? "", inBlockComment);
555
+ inBlockComment = nextInBlockComment;
556
+ if (isMethodDeclarationLine(text)) {
557
+ declarationLines.add(index + 1);
558
+ }
559
+ }
560
+ return declarationLines;
561
+ }
562
+ function parseAccessEvent(payload) {
563
+ const isEphemeralOutputArrayName = (name) => /^(output|outputs)$/i.test(name);
564
+ const cellRead = payload.match(/^access ([A-Za-z_][A-Za-z0-9_]*)\[(\d+)\]\[(\d+)\]=(.+)$/);
565
+ if (cellRead) {
566
+ return [{
567
+ variable: cellRead[1],
568
+ kind: "cell-read",
569
+ indices: [Number.parseInt(cellRead[2], 10), Number.parseInt(cellRead[3], 10)],
570
+ pathDepth: 2
571
+ }];
572
+ }
573
+ const indexedRead = payload.match(/^access ([A-Za-z_][A-Za-z0-9_]*)\[(\d+)\]=(.+)$/);
574
+ if (indexedRead) {
575
+ return [{
576
+ variable: indexedRead[1],
577
+ kind: "indexed-read",
578
+ indices: [Number.parseInt(indexedRead[2], 10)],
579
+ pathDepth: 1
580
+ }];
581
+ }
582
+ const cellWrite = payload.match(/^write-array ([A-Za-z_][A-Za-z0-9_]*)\[(\d+)\]\[(\d+)\]=(.+)$/);
583
+ if (cellWrite) {
584
+ return [{
585
+ variable: cellWrite[1],
586
+ kind: "cell-write",
587
+ indices: [Number.parseInt(cellWrite[2], 10), Number.parseInt(cellWrite[3], 10)],
588
+ pathDepth: 2
589
+ }];
590
+ }
591
+ const indexedWrite = payload.match(/^write-array ([A-Za-z_][A-Za-z0-9_]*)\[(\d+)\]=(.+)$/);
592
+ if (indexedWrite) {
593
+ if (isEphemeralOutputArrayName(indexedWrite[1])) {
594
+ return void 0;
595
+ }
596
+ return [{
597
+ variable: indexedWrite[1],
598
+ kind: "indexed-write",
599
+ indices: [Number.parseInt(indexedWrite[2], 10)],
600
+ pathDepth: 1
601
+ }];
602
+ }
603
+ const mutatingCall = payload.match(/^mutate ([A-Za-z_][A-Za-z0-9_]*) method=([A-Za-z_][A-Za-z0-9_]*)$/);
604
+ if (mutatingCall) {
605
+ return [{
606
+ variable: mutatingCall[1],
607
+ kind: "mutating-call",
608
+ method: mutatingCall[2],
609
+ pathDepth: 1
610
+ }];
611
+ }
612
+ return void 0;
613
+ }
614
+ function parseStructureState(payload) {
615
+ const match = payload.match(/^state (linked-list|tree) ([A-Za-z_][A-Za-z0-9_]*)=(.+)$/);
616
+ if (!match) return null;
617
+ return {
618
+ structure: match[1],
619
+ variable: match[2],
620
+ value: JSON.parse(match[3])
621
+ };
622
+ }
623
+ function parseObjectState(payload) {
624
+ const match = payload.match(/^object-state ([A-Za-z_][A-Za-z0-9_]*)=(.+)$/);
625
+ if (!match) return null;
626
+ return {
627
+ variable: match[1],
628
+ visualization: JSON.parse(match[2])
629
+ };
630
+ }
631
+ function parseObjectFieldEvent(payload) {
632
+ const match = payload.match(/^(access|write) ([A-Za-z_][A-Za-z0-9_]*)\.([A-Za-z_][A-Za-z0-9_]*)=(.+)$/);
633
+ if (!match) return null;
634
+ return {
635
+ variable: match[2],
636
+ field: match[3],
637
+ value: parseScalar(match[4])
638
+ };
639
+ }
640
+ function buildFieldVisualization(event) {
641
+ return {
642
+ objectKinds: {
643
+ [event.variable]: "object"
644
+ },
645
+ hashMaps: [
646
+ {
647
+ name: event.variable,
648
+ kind: "object",
649
+ objectClassName: event.field === "next" || event.field === "prev" ? "ListNode" : event.field === "left" || event.field === "right" ? "TreeNode" : void 0,
650
+ objectId: `${event.variable}-object`,
651
+ highlightedKey: event.field,
652
+ entries: [{ key: event.field, value: event.value, highlight: true }]
653
+ }
654
+ ]
655
+ };
656
+ }
657
+ function callStacksEqual(left, right) {
658
+ return JSON.stringify(left ?? []) === JSON.stringify(right ?? []);
659
+ }
660
+ function mergeVisualizationPayloads(left, right) {
661
+ if (!left) return right;
662
+ if (!right) return left;
663
+ return {
664
+ ...left,
665
+ ...right,
666
+ objectKinds: {
667
+ ...left.objectKinds ?? {},
668
+ ...right.objectKinds ?? {}
669
+ },
670
+ hashMaps: [
671
+ ...left.hashMaps ?? [],
672
+ ...right.hashMaps ?? []
673
+ ]
674
+ };
675
+ }
676
+ function maybeMergeConsecutiveLineStep(trace, nextStep) {
677
+ if (nextStep.event !== "line") {
678
+ return false;
679
+ }
680
+ const previous = trace.at(-1);
681
+ if (!previous || previous.event !== "line") {
682
+ return false;
683
+ }
684
+ if (previous.line !== nextStep.line || previous.function !== nextStep.function) {
685
+ return false;
686
+ }
687
+ if (!callStacksEqual(previous.callStack, nextStep.callStack)) {
688
+ return false;
689
+ }
690
+ previous.variables = { ...previous.variables ?? {}, ...nextStep.variables ?? {} };
691
+ if (nextStep.accesses?.length) {
692
+ previous.accesses = [...previous.accesses ?? [], ...nextStep.accesses];
693
+ }
694
+ previous.visualization = mergeVisualizationPayloads(previous.visualization, nextStep.visualization);
695
+ return true;
696
+ }
697
+ function filterStructuredVariables(variables) {
698
+ if (!variables) {
699
+ return void 0;
700
+ }
701
+ const isEphemeralOutputArrayName = (name) => /^(output|outputs)$/i.test(name);
702
+ const entries = Object.entries(variables).filter(([name, value]) => {
703
+ if (value === null || typeof value !== "object") {
704
+ return false;
705
+ }
706
+ if (!Array.isArray(value)) {
707
+ return true;
708
+ }
709
+ if (Array.isArray(value[0])) {
710
+ return true;
711
+ }
712
+ return !isEphemeralOutputArrayName(name);
713
+ });
714
+ if (entries.length === 0) {
715
+ return void 0;
716
+ }
717
+ return Object.fromEntries(entries);
718
+ }
719
+ function appendJavaTraceStep(trace, step, pendingAccesses) {
720
+ const nextStep = pendingAccesses.length > 0 ? { ...step, accesses: [...pendingAccesses] } : step;
721
+ pendingAccesses.length = 0;
722
+ if (!maybeMergeConsecutiveLineStep(trace, nextStep)) {
723
+ trace.push(nextStep);
724
+ }
725
+ }
726
+ function mergeIntoPreviousMatchingLineStep(trace, line, currentFunction, currentCallStack, patch) {
727
+ const candidate = trace.at(-1);
728
+ if (!candidate || candidate.event !== "line") {
729
+ return false;
730
+ }
731
+ if (candidate.line !== line || candidate.function !== currentFunction) {
732
+ return false;
733
+ }
734
+ if (!callStacksEqual(candidate.callStack, currentCallStack)) {
735
+ return false;
736
+ }
737
+ candidate.variables = { ...candidate.variables ?? {}, ...patch.variables ?? {} };
738
+ if (patch.accesses?.length) {
739
+ candidate.accesses = [...candidate.accesses ?? [], ...patch.accesses];
740
+ }
741
+ candidate.visualization = mergeVisualizationPayloads(candidate.visualization, patch.visualization);
742
+ return true;
743
+ }
744
+ function mergeAccessesIntoPreviousMatchingLineStep(trace, line, currentFunction, currentCallStack, accesses) {
745
+ return mergeIntoPreviousMatchingLineStep(trace, line, currentFunction, currentCallStack, {
746
+ variables: void 0,
747
+ accesses,
748
+ visualization: void 0
749
+ });
750
+ }
751
+ function eventsToRawTrace(events, sourceText) {
752
+ const trace = [];
753
+ const variables = {};
754
+ const objectKinds = {};
755
+ const stack = [];
756
+ const pendingAccesses = [];
757
+ let currentFunction = "<module>";
758
+ const lineRemap = buildLineRemap(sourceText);
759
+ const declarationLines = buildMethodDeclarationLineSet(sourceText);
760
+ for (const rawEvent of events) {
761
+ if (rawEvent === "clear" || rawEvent === "reset") continue;
762
+ const metadata = extractLineMetadata(rawEvent);
763
+ const line = lineRemap?.get(metadata.line) ?? metadata.line;
764
+ const payload = metadata.payload;
765
+ const isDeclarationLine = declarationLines?.has(line) === true;
766
+ if (payload.startsWith("call ")) {
767
+ const match = payload.match(/^call\s+(\S+)(?:\s+(.*))?$/);
768
+ const functionName = match?.[1] ?? currentFunction;
769
+ const argsFragment = match?.[2] ?? "";
770
+ Object.assign(variables, parseKeyValuePairs(argsFragment));
771
+ currentFunction = functionName || currentFunction;
772
+ stack.push({ function: currentFunction, line });
773
+ appendJavaTraceStep(trace, {
774
+ line,
775
+ event: "call",
776
+ function: currentFunction,
777
+ variables: { ...variables },
778
+ callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} }))
779
+ }, pendingAccesses);
780
+ continue;
781
+ }
782
+ if (payload.startsWith("return ")) {
783
+ const match = payload.match(/^return\s+(\S+)$/);
784
+ const functionName = match?.[1] ?? currentFunction;
785
+ const returnVariables = functionName === "<module>" ? { ...variables } : filterStructuredVariables(variables) ?? {};
786
+ appendJavaTraceStep(trace, {
787
+ line,
788
+ event: "return",
789
+ function: functionName || currentFunction,
790
+ variables: returnVariables,
791
+ callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} }))
792
+ }, pendingAccesses);
793
+ stack.pop();
794
+ currentFunction = stack[stack.length - 1]?.function ?? "<module>";
795
+ continue;
796
+ }
797
+ if (isDeclarationLine) {
798
+ continue;
799
+ }
800
+ if (payload.length === 0) {
801
+ appendJavaTraceStep(trace, {
802
+ line,
803
+ event: "line",
804
+ function: currentFunction,
805
+ variables: { ...variables },
806
+ ...stack.length > 0 ? { callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })) } : {}
807
+ }, pendingAccesses);
808
+ continue;
809
+ }
810
+ const structureState = parseStructureState(payload);
811
+ if (structureState) {
812
+ variables[structureState.variable] = structureState.value;
813
+ objectKinds[structureState.variable] = structureState.structure;
814
+ appendJavaTraceStep(trace, {
815
+ line,
816
+ event: "line",
817
+ function: currentFunction,
818
+ variables: { ...variables },
819
+ callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })),
820
+ visualization: {
821
+ objectKinds: { ...objectKinds }
822
+ }
823
+ }, pendingAccesses);
824
+ continue;
825
+ }
826
+ const objectState = parseObjectState(payload);
827
+ if (objectState) {
828
+ variables[objectState.variable] = { __ref__: objectState.visualization.objectId ?? `${objectState.variable}-object` };
829
+ appendJavaTraceStep(trace, {
830
+ line,
831
+ event: "line",
832
+ function: currentFunction,
833
+ variables: { ...variables },
834
+ callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })),
835
+ visualization: {
836
+ objectKinds: { [objectState.variable]: "object" },
837
+ hashMaps: [objectState.visualization]
838
+ }
839
+ }, pendingAccesses);
840
+ continue;
841
+ }
842
+ const objectField = parseObjectFieldEvent(payload);
843
+ if (objectField) {
844
+ variables[objectField.variable] = { __ref__: `${objectField.variable}-object` };
845
+ const currentCallStack = stack.length > 0 ? stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })) : void 0;
846
+ if (mergeIntoPreviousMatchingLineStep(trace, line, currentFunction, currentCallStack, {
847
+ variables: { ...variables },
848
+ accesses: void 0,
849
+ visualization: buildFieldVisualization(objectField)
850
+ })) {
851
+ continue;
852
+ }
853
+ appendJavaTraceStep(trace, {
854
+ line,
855
+ event: "line",
856
+ function: currentFunction,
857
+ variables: { ...variables },
858
+ callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })),
859
+ visualization: buildFieldVisualization(objectField)
860
+ }, pendingAccesses);
861
+ continue;
862
+ }
863
+ Object.assign(variables, parseKeyValuePairs(payload));
864
+ const accesses = parseAccessEvent(payload);
865
+ if (accesses) {
866
+ const currentCallStack = stack.length > 0 ? stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })) : void 0;
867
+ if (mergeAccessesIntoPreviousMatchingLineStep(trace, line, currentFunction, currentCallStack, accesses)) {
868
+ continue;
869
+ }
870
+ pendingAccesses.push(...accesses);
871
+ continue;
872
+ }
873
+ appendJavaTraceStep(trace, {
874
+ line,
875
+ event: "line",
876
+ function: currentFunction,
877
+ variables: { ...variables },
878
+ ...stack.length > 0 ? { callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })) } : {}
879
+ }, pendingAccesses);
880
+ }
881
+ if (pendingAccesses.length > 0 && trace.length > 0) {
882
+ const last = trace[trace.length - 1];
883
+ last.accesses = [...last.accesses ?? [], ...pendingAccesses];
884
+ }
885
+ return trace;
886
+ }
887
+ function buildJavaExecutionResult(output, events, executionTimeMs = 0, traceLimitExceeded, timeoutReason, maxTraceSteps, sourceText) {
888
+ const trace = eventsToRawTrace(events, sourceText);
889
+ return {
890
+ success: true,
891
+ output,
892
+ trace,
893
+ executionTimeMs,
894
+ consoleOutput: [],
895
+ ...traceLimitExceeded !== void 0 ? { traceLimitExceeded } : {},
896
+ ...maxTraceSteps !== void 0 ? { maxTraceSteps } : {},
897
+ ...timeoutReason ? { timeoutReason } : {},
898
+ lineEventCount: trace.filter((step) => step.event === "line").length,
899
+ traceStepCount: trace.length
900
+ };
901
+ }
902
+ function normalizeJavaTraceContract(result) {
903
+ const normalized = normalizeRuntimeTraceContract(
904
+ "java",
905
+ buildJavaExecutionResult(
906
+ result.output,
907
+ result.events,
908
+ 0,
909
+ result.traceLimitExceeded,
910
+ result.timeoutReason,
911
+ void 0,
912
+ result.sourceText
913
+ )
914
+ );
915
+ return {
916
+ ...normalized,
917
+ language: "java"
918
+ };
919
+ }
920
+ function adaptJavaTraceExecutionResult(result) {
921
+ return adaptTraceExecutionResult("java", result);
922
+ }
923
+
323
924
  // packages/harness-browser/src/javascript-worker-client.ts
324
925
  var EXECUTION_TIMEOUT_MS = 7e3;
325
926
  var INTERVIEW_MODE_TIMEOUT_MS = 5e3;
@@ -646,6 +1247,7 @@ var PYTHON_RUNTIME_PROFILE = {
646
1247
  maxTraceSteps: true,
647
1248
  maxLineEvents: true,
648
1249
  maxSingleLineHits: true,
1250
+ maxStoredEvents: true,
649
1251
  minimalTrace: true
650
1252
  },
651
1253
  fidelity: {
@@ -707,6 +1309,7 @@ var JAVASCRIPT_RUNTIME_PROFILE = {
707
1309
  maxTraceSteps: true,
708
1310
  maxLineEvents: true,
709
1311
  maxSingleLineHits: true,
1312
+ maxStoredEvents: true,
710
1313
  minimalTrace: true
711
1314
  },
712
1315
  fidelity: {
@@ -768,6 +1371,7 @@ var TYPESCRIPT_RUNTIME_PROFILE = {
768
1371
  maxTraceSteps: true,
769
1372
  maxLineEvents: true,
770
1373
  maxSingleLineHits: true,
1374
+ maxStoredEvents: true,
771
1375
  minimalTrace: true
772
1376
  },
773
1377
  fidelity: {
@@ -798,10 +1402,78 @@ var TYPESCRIPT_RUNTIME_PROFILE = {
798
1402
  }
799
1403
  }
800
1404
  };
1405
+ var JAVA_RUNTIME_PROFILE = {
1406
+ language: "java",
1407
+ maturity: "experimental",
1408
+ capabilities: {
1409
+ execution: {
1410
+ styles: {
1411
+ function: true,
1412
+ solutionMethod: true,
1413
+ opsClass: true,
1414
+ script: false,
1415
+ interviewMode: true
1416
+ },
1417
+ timeouts: {
1418
+ clientTimeouts: true,
1419
+ runtimeTimeouts: true
1420
+ }
1421
+ },
1422
+ tracing: {
1423
+ supported: true,
1424
+ events: {
1425
+ line: true,
1426
+ call: true,
1427
+ return: true,
1428
+ exception: true,
1429
+ stdout: false,
1430
+ timeout: true
1431
+ },
1432
+ controls: {
1433
+ maxTraceSteps: true,
1434
+ maxLineEvents: false,
1435
+ maxSingleLineHits: false,
1436
+ maxStoredEvents: true,
1437
+ minimalTrace: false
1438
+ },
1439
+ fidelity: {
1440
+ preciseLineMapping: true,
1441
+ stableFunctionNames: true,
1442
+ callStack: true
1443
+ }
1444
+ },
1445
+ diagnostics: {
1446
+ compileErrors: true,
1447
+ runtimeErrors: true,
1448
+ mappedErrorLines: false,
1449
+ stackTraces: true
1450
+ },
1451
+ structures: {
1452
+ treeNodeRefs: true,
1453
+ listNodeRefs: true,
1454
+ mapSerialization: true,
1455
+ setSerialization: true,
1456
+ graphSerialization: false,
1457
+ cycleReferences: true
1458
+ },
1459
+ visualization: {
1460
+ runtimePayloads: true,
1461
+ objectKinds: true,
1462
+ hashMaps: true,
1463
+ stepVisualization: true
1464
+ }
1465
+ },
1466
+ notes: [
1467
+ "Java currently supports the browser-local Java 17 lane for function, solution-method, and ops-class execution.",
1468
+ "Interview-mode Java reuses the same browser-local execution path and remains experimental in the first harness slice.",
1469
+ "Script-style Java is not enabled yet."
1470
+ ]
1471
+ };
801
1472
  var LANGUAGE_RUNTIME_PROFILES = {
802
1473
  python: PYTHON_RUNTIME_PROFILE,
803
1474
  javascript: JAVASCRIPT_RUNTIME_PROFILE,
804
- typescript: TYPESCRIPT_RUNTIME_PROFILE
1475
+ typescript: TYPESCRIPT_RUNTIME_PROFILE,
1476
+ java: JAVA_RUNTIME_PROFILE
805
1477
  };
806
1478
  var SUPPORTED_LANGUAGES = Object.freeze(
807
1479
  Object.keys(LANGUAGE_RUNTIME_PROFILES)
@@ -878,13 +1550,307 @@ function createJavaScriptRuntimeClient(runtimeLanguage, workerClient) {
878
1550
  return new JavaScriptRuntimeClient(runtimeLanguage, workerClient);
879
1551
  }
880
1552
 
1553
+ // packages/harness-browser/src/java-worker-client.ts
1554
+ var TRACING_TIMEOUT_MS2 = 25e3;
1555
+ var INIT_TIMEOUT_MS2 = 25e3;
1556
+ var MESSAGE_TIMEOUT_MS2 = 3e4;
1557
+ var WORKER_READY_TIMEOUT_MS2 = 1e4;
1558
+ var JavaWorkerClient = class {
1559
+ constructor(options) {
1560
+ this.options = options;
1561
+ this.debug = options.debug ?? process.env.NODE_ENV === "development";
1562
+ }
1563
+ worker = null;
1564
+ pendingMessages = /* @__PURE__ */ new Map();
1565
+ messageId = 0;
1566
+ isInitializing = false;
1567
+ initPromise = null;
1568
+ workerReadyPromise = null;
1569
+ workerReadyResolve = null;
1570
+ workerReadyReject = null;
1571
+ debug;
1572
+ isSupported() {
1573
+ return typeof Worker !== "undefined";
1574
+ }
1575
+ getWorker() {
1576
+ if (this.worker) return this.worker;
1577
+ if (!this.isSupported()) {
1578
+ throw new Error("Web Workers are not supported in this environment");
1579
+ }
1580
+ this.workerReadyPromise = new Promise((resolve, reject) => {
1581
+ this.workerReadyResolve = resolve;
1582
+ this.workerReadyReject = (error) => reject(error);
1583
+ });
1584
+ const workerUrl = this.debug && !this.options.workerUrl.includes("?") ? `${this.options.workerUrl}?dev=${Date.now()}` : this.options.workerUrl;
1585
+ this.worker = new Worker(workerUrl);
1586
+ this.worker.onmessage = (event) => {
1587
+ const { id, type, payload } = event.data;
1588
+ if (type === "worker-ready") {
1589
+ this.workerReadyResolve?.();
1590
+ this.workerReadyResolve = null;
1591
+ this.workerReadyReject = null;
1592
+ return;
1593
+ }
1594
+ if (!id) return;
1595
+ const pending = this.pendingMessages.get(id);
1596
+ if (!pending) return;
1597
+ this.pendingMessages.delete(id);
1598
+ if (pending.timeoutId) globalThis.clearTimeout(pending.timeoutId);
1599
+ if (type === "error") {
1600
+ pending.reject(new Error(payload.error));
1601
+ return;
1602
+ }
1603
+ pending.resolve(payload);
1604
+ };
1605
+ this.worker.onerror = (error) => {
1606
+ const workerError = new Error(error.message || "Java worker error");
1607
+ this.workerReadyReject?.(workerError);
1608
+ this.workerReadyResolve = null;
1609
+ this.workerReadyReject = null;
1610
+ for (const [, pending] of this.pendingMessages) {
1611
+ if (pending.timeoutId) globalThis.clearTimeout(pending.timeoutId);
1612
+ pending.reject(workerError);
1613
+ }
1614
+ this.pendingMessages.clear();
1615
+ this.terminateAndReset(workerError);
1616
+ };
1617
+ return this.worker;
1618
+ }
1619
+ async waitForWorkerReady() {
1620
+ const readyPromise = this.workerReadyPromise;
1621
+ if (!readyPromise) return;
1622
+ await new Promise((resolve, reject) => {
1623
+ let settled = false;
1624
+ const timeoutId = globalThis.setTimeout(() => {
1625
+ if (settled) return;
1626
+ settled = true;
1627
+ const timeoutError = new Error(
1628
+ `Java worker failed to initialize in time (${Math.round(WORKER_READY_TIMEOUT_MS2 / 1e3)}s)`
1629
+ );
1630
+ this.terminateAndReset(timeoutError);
1631
+ reject(timeoutError);
1632
+ }, WORKER_READY_TIMEOUT_MS2);
1633
+ readyPromise.then(() => {
1634
+ if (settled) return;
1635
+ settled = true;
1636
+ globalThis.clearTimeout(timeoutId);
1637
+ resolve();
1638
+ }).catch((error) => {
1639
+ if (settled) return;
1640
+ settled = true;
1641
+ globalThis.clearTimeout(timeoutId);
1642
+ reject(error instanceof Error ? error : new Error(String(error)));
1643
+ });
1644
+ });
1645
+ }
1646
+ async sendMessage(type, payload, timeoutMs = MESSAGE_TIMEOUT_MS2) {
1647
+ const worker = this.getWorker();
1648
+ await this.waitForWorkerReady();
1649
+ const id = String(++this.messageId);
1650
+ return new Promise((resolve, reject) => {
1651
+ this.pendingMessages.set(id, {
1652
+ resolve,
1653
+ reject
1654
+ });
1655
+ const timeoutId = globalThis.setTimeout(() => {
1656
+ const pending2 = this.pendingMessages.get(id);
1657
+ if (!pending2) return;
1658
+ this.pendingMessages.delete(id);
1659
+ pending2.reject(new Error(`Worker request timed out: ${type}`));
1660
+ }, timeoutMs);
1661
+ const pending = this.pendingMessages.get(id);
1662
+ if (pending) pending.timeoutId = timeoutId;
1663
+ worker.postMessage({ id, type, payload });
1664
+ });
1665
+ }
1666
+ async executeWithTimeout(executor, timeoutMs) {
1667
+ return new Promise((resolve, reject) => {
1668
+ let settled = false;
1669
+ const timeoutId = globalThis.setTimeout(() => {
1670
+ if (settled) return;
1671
+ settled = true;
1672
+ this.terminateAndReset();
1673
+ reject(
1674
+ new Error(
1675
+ `Java execution timed out after ${Math.round(timeoutMs / 1e3)} seconds.`
1676
+ )
1677
+ );
1678
+ }, timeoutMs);
1679
+ executor().then((result) => {
1680
+ if (settled) return;
1681
+ settled = true;
1682
+ globalThis.clearTimeout(timeoutId);
1683
+ resolve(result);
1684
+ }).catch((error) => {
1685
+ if (settled) return;
1686
+ settled = true;
1687
+ globalThis.clearTimeout(timeoutId);
1688
+ reject(error);
1689
+ });
1690
+ });
1691
+ }
1692
+ terminateAndReset(reason = new Error("Worker was terminated")) {
1693
+ this.workerReadyReject?.(reason);
1694
+ if (this.worker) {
1695
+ this.worker.terminate();
1696
+ this.worker = null;
1697
+ }
1698
+ this.initPromise = null;
1699
+ this.isInitializing = false;
1700
+ this.workerReadyPromise = null;
1701
+ this.workerReadyResolve = null;
1702
+ this.workerReadyReject = null;
1703
+ for (const [, pending] of this.pendingMessages) {
1704
+ if (pending.timeoutId) globalThis.clearTimeout(pending.timeoutId);
1705
+ pending.reject(reason);
1706
+ }
1707
+ this.pendingMessages.clear();
1708
+ }
1709
+ async init() {
1710
+ if (this.initPromise) return this.initPromise;
1711
+ if (this.isInitializing) {
1712
+ await new Promise((resolve) => globalThis.setTimeout(resolve, 100));
1713
+ return this.init();
1714
+ }
1715
+ this.isInitializing = true;
1716
+ this.initPromise = this.sendMessage("init", void 0, INIT_TIMEOUT_MS2);
1717
+ try {
1718
+ return await this.initPromise;
1719
+ } catch (error) {
1720
+ this.initPromise = null;
1721
+ throw error;
1722
+ } finally {
1723
+ this.isInitializing = false;
1724
+ }
1725
+ }
1726
+ async executeWithTracing(code, functionName, inputs, options, executionStyle) {
1727
+ await this.init();
1728
+ return this.executeWithTimeout(
1729
+ () => this.sendMessage(
1730
+ "execute-with-tracing",
1731
+ { code, functionName, inputs, options, executionStyle },
1732
+ TRACING_TIMEOUT_MS2 + 5e3
1733
+ ),
1734
+ TRACING_TIMEOUT_MS2
1735
+ );
1736
+ }
1737
+ async executeCode(code, functionName, inputs, options, executionStyle) {
1738
+ const result = await this.executeWithTracing(code, functionName, inputs, options, executionStyle);
1739
+ if (!result.success) {
1740
+ return {
1741
+ success: false,
1742
+ output: null,
1743
+ error: result.error ?? "Java execution failed",
1744
+ ...result.errorLine !== void 0 ? { errorLine: result.errorLine } : {},
1745
+ consoleOutput: result.consoleOutput
1746
+ };
1747
+ }
1748
+ return {
1749
+ success: true,
1750
+ output: result.output,
1751
+ consoleOutput: result.consoleOutput
1752
+ };
1753
+ }
1754
+ async executeCodeInterviewMode(code, functionName, inputs, options, executionStyle) {
1755
+ return this.executeCode(code, functionName, inputs, options, executionStyle);
1756
+ }
1757
+ terminate() {
1758
+ this.terminateAndReset();
1759
+ }
1760
+ };
1761
+
1762
+ // packages/harness-browser/src/java-runtime-client.ts
1763
+ var JavaRuntimeClient = class {
1764
+ constructor(workerClient) {
1765
+ this.workerClient = workerClient;
1766
+ }
1767
+ async init() {
1768
+ return this.workerClient.init();
1769
+ }
1770
+ async executeWithTracing(code, functionName, inputs, options, executionStyle = "function") {
1771
+ assertRuntimeRequestSupported(getLanguageRuntimeProfile("java"), {
1772
+ request: "trace",
1773
+ executionStyle,
1774
+ functionName
1775
+ });
1776
+ const rawResult = await this.workerClient.executeWithTracing(
1777
+ code,
1778
+ functionName ?? "",
1779
+ inputs,
1780
+ options,
1781
+ executionStyle
1782
+ );
1783
+ if (!rawResult.success) {
1784
+ return {
1785
+ success: false,
1786
+ error: rawResult.error ?? "Java tracing failed",
1787
+ ...rawResult.errorLine !== void 0 ? { errorLine: rawResult.errorLine } : {},
1788
+ trace: [],
1789
+ executionTimeMs: rawResult.executionTimeMs,
1790
+ consoleOutput: rawResult.consoleOutput,
1791
+ ...rawResult.traceLimitExceeded !== void 0 ? { traceLimitExceeded: rawResult.traceLimitExceeded } : {},
1792
+ ...rawResult.timeoutReason ? { timeoutReason: rawResult.timeoutReason } : {},
1793
+ lineEventCount: 0,
1794
+ traceStepCount: 0
1795
+ };
1796
+ }
1797
+ const adapted = adaptJavaTraceExecutionResult(
1798
+ buildJavaExecutionResult(
1799
+ rawResult.output,
1800
+ rawResult.events,
1801
+ rawResult.executionTimeMs,
1802
+ rawResult.traceLimitExceeded,
1803
+ rawResult.timeoutReason,
1804
+ void 0,
1805
+ rawResult.sourceText
1806
+ )
1807
+ );
1808
+ return {
1809
+ ...adapted,
1810
+ consoleOutput: rawResult.consoleOutput,
1811
+ executionTimeMs: rawResult.executionTimeMs
1812
+ };
1813
+ }
1814
+ async executeCode(code, functionName, inputs, executionStyle = "function") {
1815
+ assertRuntimeRequestSupported(getLanguageRuntimeProfile("java"), {
1816
+ request: "execute",
1817
+ executionStyle,
1818
+ functionName
1819
+ });
1820
+ return this.workerClient.executeCode(
1821
+ code,
1822
+ functionName,
1823
+ inputs,
1824
+ void 0,
1825
+ executionStyle
1826
+ );
1827
+ }
1828
+ async executeCodeInterviewMode(code, functionName, inputs, executionStyle = "function") {
1829
+ assertRuntimeRequestSupported(getLanguageRuntimeProfile("java"), {
1830
+ request: "interview",
1831
+ executionStyle,
1832
+ functionName
1833
+ });
1834
+ return this.workerClient.executeCodeInterviewMode(
1835
+ code,
1836
+ functionName,
1837
+ inputs,
1838
+ void 0,
1839
+ executionStyle
1840
+ );
1841
+ }
1842
+ };
1843
+ function createJavaRuntimeClient(workerClient) {
1844
+ return new JavaRuntimeClient(workerClient);
1845
+ }
1846
+
881
1847
  // packages/harness-browser/src/pyodide-worker-client.ts
882
1848
  var EXECUTION_TIMEOUT_MS2 = 1e4;
883
1849
  var INTERVIEW_MODE_TIMEOUT_MS2 = 5e3;
884
- var TRACING_TIMEOUT_MS2 = 3e4;
885
- var INIT_TIMEOUT_MS2 = 12e4;
886
- var MESSAGE_TIMEOUT_MS2 = 2e4;
887
- var WORKER_READY_TIMEOUT_MS2 = 1e4;
1850
+ var TRACING_TIMEOUT_MS3 = 3e4;
1851
+ var INIT_TIMEOUT_MS3 = 12e4;
1852
+ var MESSAGE_TIMEOUT_MS3 = 2e4;
1853
+ var WORKER_READY_TIMEOUT_MS3 = 1e4;
888
1854
  var PyodideWorkerClient = class {
889
1855
  constructor(options) {
890
1856
  this.options = options;
@@ -974,14 +1940,14 @@ var PyodideWorkerClient = class {
974
1940
  if (settled) return;
975
1941
  settled = true;
976
1942
  const timeoutError = new Error(
977
- `Python worker failed to initialize in time (${Math.round(WORKER_READY_TIMEOUT_MS2 / 1e3)}s)`
1943
+ `Python worker failed to initialize in time (${Math.round(WORKER_READY_TIMEOUT_MS3 / 1e3)}s)`
978
1944
  );
979
1945
  if (this.debug) {
980
- console.warn("[PyodideWorkerClient] worker-ready timeout", { timeoutMs: WORKER_READY_TIMEOUT_MS2 });
1946
+ console.warn("[PyodideWorkerClient] worker-ready timeout", { timeoutMs: WORKER_READY_TIMEOUT_MS3 });
981
1947
  }
982
1948
  this.terminateAndReset(timeoutError);
983
1949
  reject(timeoutError);
984
- }, WORKER_READY_TIMEOUT_MS2);
1950
+ }, WORKER_READY_TIMEOUT_MS3);
985
1951
  readyPromise.then(() => {
986
1952
  if (settled) return;
987
1953
  settled = true;
@@ -998,7 +1964,7 @@ var PyodideWorkerClient = class {
998
1964
  /**
999
1965
  * Send a message to the worker and wait for a response
1000
1966
  */
1001
- async sendMessage(type, payload, timeoutMs = MESSAGE_TIMEOUT_MS2) {
1967
+ async sendMessage(type, payload, timeoutMs = MESSAGE_TIMEOUT_MS3) {
1002
1968
  const worker = this.getWorker();
1003
1969
  await this.waitForWorkerReady();
1004
1970
  const id = String(++this.messageId);
@@ -1082,7 +2048,7 @@ var PyodideWorkerClient = class {
1082
2048
  this.isInitializing = true;
1083
2049
  this.initPromise = (async () => {
1084
2050
  try {
1085
- return await this.sendMessage("init", void 0, INIT_TIMEOUT_MS2);
2051
+ return await this.sendMessage("init", void 0, INIT_TIMEOUT_MS3);
1086
2052
  } catch (error) {
1087
2053
  const message = error instanceof Error ? error.message : String(error);
1088
2054
  const shouldRetry = message.includes("Worker request timed out: init") || message.includes("Worker was terminated") || message.includes("Worker error") || message.includes("failed to initialize in time");
@@ -1093,7 +2059,7 @@ var PyodideWorkerClient = class {
1093
2059
  console.warn("[PyodideWorkerClient] init failed, resetting worker and retrying once", { message });
1094
2060
  }
1095
2061
  this.terminateAndReset();
1096
- return this.sendMessage("init", void 0, INIT_TIMEOUT_MS2);
2062
+ return this.sendMessage("init", void 0, INIT_TIMEOUT_MS3);
1097
2063
  }
1098
2064
  })();
1099
2065
  try {
@@ -1120,9 +2086,9 @@ var PyodideWorkerClient = class {
1120
2086
  inputs,
1121
2087
  executionStyle,
1122
2088
  options
1123
- }, TRACING_TIMEOUT_MS2 + 5e3),
2089
+ }, TRACING_TIMEOUT_MS3 + 5e3),
1124
2090
  // Message timeout slightly longer than execution timeout
1125
- TRACING_TIMEOUT_MS2
2091
+ TRACING_TIMEOUT_MS3
1126
2092
  );
1127
2093
  } catch (error) {
1128
2094
  const errorMessage = error instanceof Error ? error.message : String(error);
@@ -1132,7 +2098,7 @@ var PyodideWorkerClient = class {
1132
2098
  success: false,
1133
2099
  error: errorMessage,
1134
2100
  trace: [],
1135
- executionTimeMs: TRACING_TIMEOUT_MS2,
2101
+ executionTimeMs: TRACING_TIMEOUT_MS3,
1136
2102
  consoleOutput: [],
1137
2103
  traceLimitExceeded: true,
1138
2104
  timeoutReason: "client-timeout",
@@ -1288,6 +2254,7 @@ var DEFAULT_BROWSER_HARNESS_ASSET_RELATIVE_PATHS = Object.freeze({
1288
2254
  pythonRuntimeCore: "pyodide/runtime-core.js",
1289
2255
  pythonSnippets: "generated-python-harness-snippets.js",
1290
2256
  javascriptWorker: "javascript-worker.js",
2257
+ javaWorker: "java-worker.js",
1291
2258
  typescriptCompiler: "vendor/typescript.js"
1292
2259
  });
1293
2260
  function isExplicitAssetPath(pathname) {
@@ -1321,6 +2288,7 @@ function resolveBrowserHarnessAssets(options = {}) {
1321
2288
  assetBaseUrl,
1322
2289
  assets.javascriptWorker ?? DEFAULT_BROWSER_HARNESS_ASSET_RELATIVE_PATHS.javascriptWorker
1323
2290
  ),
2291
+ javaWorker: resolveAssetPath(assetBaseUrl, assets.javaWorker ?? DEFAULT_BROWSER_HARNESS_ASSET_RELATIVE_PATHS.javaWorker),
1324
2292
  typescriptCompiler: resolveAssetPath(
1325
2293
  assetBaseUrl,
1326
2294
  assets.typescriptCompiler ?? DEFAULT_BROWSER_HARNESS_ASSET_RELATIVE_PATHS.typescriptCompiler
@@ -1334,6 +2302,7 @@ var BrowserHarnessRuntime = class {
1334
2302
  supportedLanguages = SUPPORTED_LANGUAGES;
1335
2303
  pythonWorkerClient;
1336
2304
  javaScriptWorkerClient;
2305
+ javaWorkerClient;
1337
2306
  clients;
1338
2307
  constructor(options = {}) {
1339
2308
  this.assets = resolveBrowserHarnessAssets(options);
@@ -1345,10 +2314,15 @@ var BrowserHarnessRuntime = class {
1345
2314
  workerUrl: this.assets.javascriptWorker,
1346
2315
  debug: options.debug
1347
2316
  });
2317
+ this.javaWorkerClient = new JavaWorkerClient({
2318
+ workerUrl: this.assets.javaWorker,
2319
+ debug: options.debug
2320
+ });
1348
2321
  this.clients = {
1349
2322
  python: createPythonRuntimeClient(this.pythonWorkerClient),
1350
2323
  javascript: createJavaScriptRuntimeClient("javascript", this.javaScriptWorkerClient),
1351
- typescript: createJavaScriptRuntimeClient("typescript", this.javaScriptWorkerClient)
2324
+ typescript: createJavaScriptRuntimeClient("typescript", this.javaScriptWorkerClient),
2325
+ java: createJavaRuntimeClient(this.javaWorkerClient)
1352
2326
  };
1353
2327
  }
1354
2328
  getClient(language) {
@@ -1372,11 +2346,16 @@ var BrowserHarnessRuntime = class {
1372
2346
  this.pythonWorkerClient.terminate();
1373
2347
  return;
1374
2348
  }
2349
+ if (language === "java") {
2350
+ this.javaWorkerClient.terminate();
2351
+ return;
2352
+ }
1375
2353
  this.javaScriptWorkerClient.terminate();
1376
2354
  }
1377
2355
  dispose() {
1378
2356
  this.pythonWorkerClient.terminate();
1379
2357
  this.javaScriptWorkerClient.terminate();
2358
+ this.javaWorkerClient.terminate();
1380
2359
  }
1381
2360
  };
1382
2361
  function createBrowserHarness(options = {}) {
@@ -2889,9 +3868,13 @@ async function executeTypeScriptCode(code, functionName, inputs, executionStyle
2889
3868
  TEMPLATE_PYTHON_TRACE_SERIALIZE_FUNCTION,
2890
3869
  TYPESCRIPT_RUNTIME_DECLARATIONS,
2891
3870
  adaptJavaScriptTraceExecutionResult,
3871
+ adaptJavaSpikeTraceExecutionResult,
3872
+ adaptJavaTraceExecutionResult,
2892
3873
  adaptPythonTraceExecutionResult,
2893
3874
  adaptTraceExecutionResult,
2894
3875
  assertRuntimeRequestSupported,
3876
+ buildJavaExecutionResult,
3877
+ buildJavaSpikeExecutionResult,
2895
3878
  createBrowserHarness,
2896
3879
  executeJavaScriptCode,
2897
3880
  executeJavaScriptWithTracing,
@@ -2903,6 +3886,8 @@ async function executeTypeScriptCode(code, functionName, inputs, executionStyle
2903
3886
  getSupportedLanguageProfiles,
2904
3887
  identifyConversions,
2905
3888
  isLanguageSupported,
3889
+ normalizeJavaSpikeTraceContract,
3890
+ normalizeJavaTraceContract,
2906
3891
  normalizeRuntimeTraceContract,
2907
3892
  resolveBrowserHarnessAssets,
2908
3893
  stableStringifyRuntimeTraceContract,