@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.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
@@ -256,6 +344,513 @@ function adaptJavaScriptTraceExecutionResult(language, result) {
256
344
  return adaptTraceExecutionResult(language, result);
257
345
  }
258
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
+ }
853
+
259
854
  // packages/harness-browser/src/javascript-worker-client.ts
260
855
  var EXECUTION_TIMEOUT_MS = 7e3;
261
856
  var INTERVIEW_MODE_TIMEOUT_MS = 5e3;
@@ -582,6 +1177,7 @@ var PYTHON_RUNTIME_PROFILE = {
582
1177
  maxTraceSteps: true,
583
1178
  maxLineEvents: true,
584
1179
  maxSingleLineHits: true,
1180
+ maxStoredEvents: true,
585
1181
  minimalTrace: true
586
1182
  },
587
1183
  fidelity: {
@@ -643,6 +1239,7 @@ var JAVASCRIPT_RUNTIME_PROFILE = {
643
1239
  maxTraceSteps: true,
644
1240
  maxLineEvents: true,
645
1241
  maxSingleLineHits: true,
1242
+ maxStoredEvents: true,
646
1243
  minimalTrace: true
647
1244
  },
648
1245
  fidelity: {
@@ -704,6 +1301,7 @@ var TYPESCRIPT_RUNTIME_PROFILE = {
704
1301
  maxTraceSteps: true,
705
1302
  maxLineEvents: true,
706
1303
  maxSingleLineHits: true,
1304
+ maxStoredEvents: true,
707
1305
  minimalTrace: true
708
1306
  },
709
1307
  fidelity: {
@@ -734,10 +1332,78 @@ var TYPESCRIPT_RUNTIME_PROFILE = {
734
1332
  }
735
1333
  }
736
1334
  };
1335
+ var JAVA_RUNTIME_PROFILE = {
1336
+ language: "java",
1337
+ maturity: "experimental",
1338
+ capabilities: {
1339
+ execution: {
1340
+ styles: {
1341
+ function: true,
1342
+ solutionMethod: true,
1343
+ opsClass: true,
1344
+ script: false,
1345
+ interviewMode: true
1346
+ },
1347
+ timeouts: {
1348
+ clientTimeouts: true,
1349
+ runtimeTimeouts: true
1350
+ }
1351
+ },
1352
+ tracing: {
1353
+ supported: true,
1354
+ events: {
1355
+ line: true,
1356
+ call: true,
1357
+ return: true,
1358
+ exception: true,
1359
+ stdout: false,
1360
+ timeout: true
1361
+ },
1362
+ controls: {
1363
+ maxTraceSteps: true,
1364
+ maxLineEvents: false,
1365
+ maxSingleLineHits: false,
1366
+ maxStoredEvents: true,
1367
+ minimalTrace: false
1368
+ },
1369
+ fidelity: {
1370
+ preciseLineMapping: true,
1371
+ stableFunctionNames: true,
1372
+ callStack: true
1373
+ }
1374
+ },
1375
+ diagnostics: {
1376
+ compileErrors: true,
1377
+ runtimeErrors: true,
1378
+ mappedErrorLines: false,
1379
+ stackTraces: true
1380
+ },
1381
+ structures: {
1382
+ treeNodeRefs: true,
1383
+ listNodeRefs: true,
1384
+ mapSerialization: true,
1385
+ setSerialization: true,
1386
+ graphSerialization: false,
1387
+ cycleReferences: true
1388
+ },
1389
+ visualization: {
1390
+ runtimePayloads: true,
1391
+ objectKinds: true,
1392
+ hashMaps: true,
1393
+ stepVisualization: true
1394
+ }
1395
+ },
1396
+ notes: [
1397
+ "Java currently supports the browser-local Java 17 lane for function, solution-method, and ops-class execution.",
1398
+ "Interview-mode Java reuses the same browser-local execution path and remains experimental in the first harness slice.",
1399
+ "Script-style Java is not enabled yet."
1400
+ ]
1401
+ };
737
1402
  var LANGUAGE_RUNTIME_PROFILES = {
738
1403
  python: PYTHON_RUNTIME_PROFILE,
739
1404
  javascript: JAVASCRIPT_RUNTIME_PROFILE,
740
- typescript: TYPESCRIPT_RUNTIME_PROFILE
1405
+ typescript: TYPESCRIPT_RUNTIME_PROFILE,
1406
+ java: JAVA_RUNTIME_PROFILE
741
1407
  };
742
1408
  var SUPPORTED_LANGUAGES = Object.freeze(
743
1409
  Object.keys(LANGUAGE_RUNTIME_PROFILES)
@@ -814,13 +1480,307 @@ function createJavaScriptRuntimeClient(runtimeLanguage, workerClient) {
814
1480
  return new JavaScriptRuntimeClient(runtimeLanguage, workerClient);
815
1481
  }
816
1482
 
1483
+ // packages/harness-browser/src/java-worker-client.ts
1484
+ var TRACING_TIMEOUT_MS2 = 25e3;
1485
+ var INIT_TIMEOUT_MS2 = 25e3;
1486
+ var MESSAGE_TIMEOUT_MS2 = 3e4;
1487
+ var WORKER_READY_TIMEOUT_MS2 = 1e4;
1488
+ var JavaWorkerClient = class {
1489
+ constructor(options) {
1490
+ this.options = options;
1491
+ this.debug = options.debug ?? process.env.NODE_ENV === "development";
1492
+ }
1493
+ worker = null;
1494
+ pendingMessages = /* @__PURE__ */ new Map();
1495
+ messageId = 0;
1496
+ isInitializing = false;
1497
+ initPromise = null;
1498
+ workerReadyPromise = null;
1499
+ workerReadyResolve = null;
1500
+ workerReadyReject = null;
1501
+ debug;
1502
+ isSupported() {
1503
+ return typeof Worker !== "undefined";
1504
+ }
1505
+ getWorker() {
1506
+ if (this.worker) return this.worker;
1507
+ if (!this.isSupported()) {
1508
+ throw new Error("Web Workers are not supported in this environment");
1509
+ }
1510
+ this.workerReadyPromise = new Promise((resolve, reject) => {
1511
+ this.workerReadyResolve = resolve;
1512
+ this.workerReadyReject = (error) => reject(error);
1513
+ });
1514
+ const workerUrl = this.debug && !this.options.workerUrl.includes("?") ? `${this.options.workerUrl}?dev=${Date.now()}` : this.options.workerUrl;
1515
+ this.worker = new Worker(workerUrl);
1516
+ this.worker.onmessage = (event) => {
1517
+ const { id, type, payload } = event.data;
1518
+ if (type === "worker-ready") {
1519
+ this.workerReadyResolve?.();
1520
+ this.workerReadyResolve = null;
1521
+ this.workerReadyReject = null;
1522
+ return;
1523
+ }
1524
+ if (!id) return;
1525
+ const pending = this.pendingMessages.get(id);
1526
+ if (!pending) return;
1527
+ this.pendingMessages.delete(id);
1528
+ if (pending.timeoutId) globalThis.clearTimeout(pending.timeoutId);
1529
+ if (type === "error") {
1530
+ pending.reject(new Error(payload.error));
1531
+ return;
1532
+ }
1533
+ pending.resolve(payload);
1534
+ };
1535
+ this.worker.onerror = (error) => {
1536
+ const workerError = new Error(error.message || "Java worker error");
1537
+ this.workerReadyReject?.(workerError);
1538
+ this.workerReadyResolve = null;
1539
+ this.workerReadyReject = null;
1540
+ for (const [, pending] of this.pendingMessages) {
1541
+ if (pending.timeoutId) globalThis.clearTimeout(pending.timeoutId);
1542
+ pending.reject(workerError);
1543
+ }
1544
+ this.pendingMessages.clear();
1545
+ this.terminateAndReset(workerError);
1546
+ };
1547
+ return this.worker;
1548
+ }
1549
+ async waitForWorkerReady() {
1550
+ const readyPromise = this.workerReadyPromise;
1551
+ if (!readyPromise) return;
1552
+ await new Promise((resolve, reject) => {
1553
+ let settled = false;
1554
+ const timeoutId = globalThis.setTimeout(() => {
1555
+ if (settled) return;
1556
+ settled = true;
1557
+ const timeoutError = new Error(
1558
+ `Java worker failed to initialize in time (${Math.round(WORKER_READY_TIMEOUT_MS2 / 1e3)}s)`
1559
+ );
1560
+ this.terminateAndReset(timeoutError);
1561
+ reject(timeoutError);
1562
+ }, WORKER_READY_TIMEOUT_MS2);
1563
+ readyPromise.then(() => {
1564
+ if (settled) return;
1565
+ settled = true;
1566
+ globalThis.clearTimeout(timeoutId);
1567
+ resolve();
1568
+ }).catch((error) => {
1569
+ if (settled) return;
1570
+ settled = true;
1571
+ globalThis.clearTimeout(timeoutId);
1572
+ reject(error instanceof Error ? error : new Error(String(error)));
1573
+ });
1574
+ });
1575
+ }
1576
+ async sendMessage(type, payload, timeoutMs = MESSAGE_TIMEOUT_MS2) {
1577
+ const worker = this.getWorker();
1578
+ await this.waitForWorkerReady();
1579
+ const id = String(++this.messageId);
1580
+ return new Promise((resolve, reject) => {
1581
+ this.pendingMessages.set(id, {
1582
+ resolve,
1583
+ reject
1584
+ });
1585
+ const timeoutId = globalThis.setTimeout(() => {
1586
+ const pending2 = this.pendingMessages.get(id);
1587
+ if (!pending2) return;
1588
+ this.pendingMessages.delete(id);
1589
+ pending2.reject(new Error(`Worker request timed out: ${type}`));
1590
+ }, timeoutMs);
1591
+ const pending = this.pendingMessages.get(id);
1592
+ if (pending) pending.timeoutId = timeoutId;
1593
+ worker.postMessage({ id, type, payload });
1594
+ });
1595
+ }
1596
+ async executeWithTimeout(executor, timeoutMs) {
1597
+ return new Promise((resolve, reject) => {
1598
+ let settled = false;
1599
+ const timeoutId = globalThis.setTimeout(() => {
1600
+ if (settled) return;
1601
+ settled = true;
1602
+ this.terminateAndReset();
1603
+ reject(
1604
+ new Error(
1605
+ `Java execution timed out after ${Math.round(timeoutMs / 1e3)} seconds.`
1606
+ )
1607
+ );
1608
+ }, timeoutMs);
1609
+ executor().then((result) => {
1610
+ if (settled) return;
1611
+ settled = true;
1612
+ globalThis.clearTimeout(timeoutId);
1613
+ resolve(result);
1614
+ }).catch((error) => {
1615
+ if (settled) return;
1616
+ settled = true;
1617
+ globalThis.clearTimeout(timeoutId);
1618
+ reject(error);
1619
+ });
1620
+ });
1621
+ }
1622
+ terminateAndReset(reason = new Error("Worker was terminated")) {
1623
+ this.workerReadyReject?.(reason);
1624
+ if (this.worker) {
1625
+ this.worker.terminate();
1626
+ this.worker = null;
1627
+ }
1628
+ this.initPromise = null;
1629
+ this.isInitializing = false;
1630
+ this.workerReadyPromise = null;
1631
+ this.workerReadyResolve = null;
1632
+ this.workerReadyReject = null;
1633
+ for (const [, pending] of this.pendingMessages) {
1634
+ if (pending.timeoutId) globalThis.clearTimeout(pending.timeoutId);
1635
+ pending.reject(reason);
1636
+ }
1637
+ this.pendingMessages.clear();
1638
+ }
1639
+ async init() {
1640
+ if (this.initPromise) return this.initPromise;
1641
+ if (this.isInitializing) {
1642
+ await new Promise((resolve) => globalThis.setTimeout(resolve, 100));
1643
+ return this.init();
1644
+ }
1645
+ this.isInitializing = true;
1646
+ this.initPromise = this.sendMessage("init", void 0, INIT_TIMEOUT_MS2);
1647
+ try {
1648
+ return await this.initPromise;
1649
+ } catch (error) {
1650
+ this.initPromise = null;
1651
+ throw error;
1652
+ } finally {
1653
+ this.isInitializing = false;
1654
+ }
1655
+ }
1656
+ async executeWithTracing(code, functionName, inputs, options, executionStyle) {
1657
+ await this.init();
1658
+ return this.executeWithTimeout(
1659
+ () => this.sendMessage(
1660
+ "execute-with-tracing",
1661
+ { code, functionName, inputs, options, executionStyle },
1662
+ TRACING_TIMEOUT_MS2 + 5e3
1663
+ ),
1664
+ TRACING_TIMEOUT_MS2
1665
+ );
1666
+ }
1667
+ async executeCode(code, functionName, inputs, options, executionStyle) {
1668
+ const result = await this.executeWithTracing(code, functionName, inputs, options, executionStyle);
1669
+ if (!result.success) {
1670
+ return {
1671
+ success: false,
1672
+ output: null,
1673
+ error: result.error ?? "Java execution failed",
1674
+ ...result.errorLine !== void 0 ? { errorLine: result.errorLine } : {},
1675
+ consoleOutput: result.consoleOutput
1676
+ };
1677
+ }
1678
+ return {
1679
+ success: true,
1680
+ output: result.output,
1681
+ consoleOutput: result.consoleOutput
1682
+ };
1683
+ }
1684
+ async executeCodeInterviewMode(code, functionName, inputs, options, executionStyle) {
1685
+ return this.executeCode(code, functionName, inputs, options, executionStyle);
1686
+ }
1687
+ terminate() {
1688
+ this.terminateAndReset();
1689
+ }
1690
+ };
1691
+
1692
+ // packages/harness-browser/src/java-runtime-client.ts
1693
+ var JavaRuntimeClient = class {
1694
+ constructor(workerClient) {
1695
+ this.workerClient = workerClient;
1696
+ }
1697
+ async init() {
1698
+ return this.workerClient.init();
1699
+ }
1700
+ async executeWithTracing(code, functionName, inputs, options, executionStyle = "function") {
1701
+ assertRuntimeRequestSupported(getLanguageRuntimeProfile("java"), {
1702
+ request: "trace",
1703
+ executionStyle,
1704
+ functionName
1705
+ });
1706
+ const rawResult = await this.workerClient.executeWithTracing(
1707
+ code,
1708
+ functionName ?? "",
1709
+ inputs,
1710
+ options,
1711
+ executionStyle
1712
+ );
1713
+ if (!rawResult.success) {
1714
+ return {
1715
+ success: false,
1716
+ error: rawResult.error ?? "Java tracing failed",
1717
+ ...rawResult.errorLine !== void 0 ? { errorLine: rawResult.errorLine } : {},
1718
+ trace: [],
1719
+ executionTimeMs: rawResult.executionTimeMs,
1720
+ consoleOutput: rawResult.consoleOutput,
1721
+ ...rawResult.traceLimitExceeded !== void 0 ? { traceLimitExceeded: rawResult.traceLimitExceeded } : {},
1722
+ ...rawResult.timeoutReason ? { timeoutReason: rawResult.timeoutReason } : {},
1723
+ lineEventCount: 0,
1724
+ traceStepCount: 0
1725
+ };
1726
+ }
1727
+ const adapted = adaptJavaTraceExecutionResult(
1728
+ buildJavaExecutionResult(
1729
+ rawResult.output,
1730
+ rawResult.events,
1731
+ rawResult.executionTimeMs,
1732
+ rawResult.traceLimitExceeded,
1733
+ rawResult.timeoutReason,
1734
+ void 0,
1735
+ rawResult.sourceText
1736
+ )
1737
+ );
1738
+ return {
1739
+ ...adapted,
1740
+ consoleOutput: rawResult.consoleOutput,
1741
+ executionTimeMs: rawResult.executionTimeMs
1742
+ };
1743
+ }
1744
+ async executeCode(code, functionName, inputs, executionStyle = "function") {
1745
+ assertRuntimeRequestSupported(getLanguageRuntimeProfile("java"), {
1746
+ request: "execute",
1747
+ executionStyle,
1748
+ functionName
1749
+ });
1750
+ return this.workerClient.executeCode(
1751
+ code,
1752
+ functionName,
1753
+ inputs,
1754
+ void 0,
1755
+ executionStyle
1756
+ );
1757
+ }
1758
+ async executeCodeInterviewMode(code, functionName, inputs, executionStyle = "function") {
1759
+ assertRuntimeRequestSupported(getLanguageRuntimeProfile("java"), {
1760
+ request: "interview",
1761
+ executionStyle,
1762
+ functionName
1763
+ });
1764
+ return this.workerClient.executeCodeInterviewMode(
1765
+ code,
1766
+ functionName,
1767
+ inputs,
1768
+ void 0,
1769
+ executionStyle
1770
+ );
1771
+ }
1772
+ };
1773
+ function createJavaRuntimeClient(workerClient) {
1774
+ return new JavaRuntimeClient(workerClient);
1775
+ }
1776
+
817
1777
  // packages/harness-browser/src/pyodide-worker-client.ts
818
1778
  var EXECUTION_TIMEOUT_MS2 = 1e4;
819
1779
  var INTERVIEW_MODE_TIMEOUT_MS2 = 5e3;
820
- var TRACING_TIMEOUT_MS2 = 3e4;
821
- var INIT_TIMEOUT_MS2 = 12e4;
822
- var MESSAGE_TIMEOUT_MS2 = 2e4;
823
- var WORKER_READY_TIMEOUT_MS2 = 1e4;
1780
+ var TRACING_TIMEOUT_MS3 = 3e4;
1781
+ var INIT_TIMEOUT_MS3 = 12e4;
1782
+ var MESSAGE_TIMEOUT_MS3 = 2e4;
1783
+ var WORKER_READY_TIMEOUT_MS3 = 1e4;
824
1784
  var PyodideWorkerClient = class {
825
1785
  constructor(options) {
826
1786
  this.options = options;
@@ -910,14 +1870,14 @@ var PyodideWorkerClient = class {
910
1870
  if (settled) return;
911
1871
  settled = true;
912
1872
  const timeoutError = new Error(
913
- `Python worker failed to initialize in time (${Math.round(WORKER_READY_TIMEOUT_MS2 / 1e3)}s)`
1873
+ `Python worker failed to initialize in time (${Math.round(WORKER_READY_TIMEOUT_MS3 / 1e3)}s)`
914
1874
  );
915
1875
  if (this.debug) {
916
- console.warn("[PyodideWorkerClient] worker-ready timeout", { timeoutMs: WORKER_READY_TIMEOUT_MS2 });
1876
+ console.warn("[PyodideWorkerClient] worker-ready timeout", { timeoutMs: WORKER_READY_TIMEOUT_MS3 });
917
1877
  }
918
1878
  this.terminateAndReset(timeoutError);
919
1879
  reject(timeoutError);
920
- }, WORKER_READY_TIMEOUT_MS2);
1880
+ }, WORKER_READY_TIMEOUT_MS3);
921
1881
  readyPromise.then(() => {
922
1882
  if (settled) return;
923
1883
  settled = true;
@@ -934,7 +1894,7 @@ var PyodideWorkerClient = class {
934
1894
  /**
935
1895
  * Send a message to the worker and wait for a response
936
1896
  */
937
- async sendMessage(type, payload, timeoutMs = MESSAGE_TIMEOUT_MS2) {
1897
+ async sendMessage(type, payload, timeoutMs = MESSAGE_TIMEOUT_MS3) {
938
1898
  const worker = this.getWorker();
939
1899
  await this.waitForWorkerReady();
940
1900
  const id = String(++this.messageId);
@@ -1018,7 +1978,7 @@ var PyodideWorkerClient = class {
1018
1978
  this.isInitializing = true;
1019
1979
  this.initPromise = (async () => {
1020
1980
  try {
1021
- return await this.sendMessage("init", void 0, INIT_TIMEOUT_MS2);
1981
+ return await this.sendMessage("init", void 0, INIT_TIMEOUT_MS3);
1022
1982
  } catch (error) {
1023
1983
  const message = error instanceof Error ? error.message : String(error);
1024
1984
  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");
@@ -1029,7 +1989,7 @@ var PyodideWorkerClient = class {
1029
1989
  console.warn("[PyodideWorkerClient] init failed, resetting worker and retrying once", { message });
1030
1990
  }
1031
1991
  this.terminateAndReset();
1032
- return this.sendMessage("init", void 0, INIT_TIMEOUT_MS2);
1992
+ return this.sendMessage("init", void 0, INIT_TIMEOUT_MS3);
1033
1993
  }
1034
1994
  })();
1035
1995
  try {
@@ -1056,9 +2016,9 @@ var PyodideWorkerClient = class {
1056
2016
  inputs,
1057
2017
  executionStyle,
1058
2018
  options
1059
- }, TRACING_TIMEOUT_MS2 + 5e3),
2019
+ }, TRACING_TIMEOUT_MS3 + 5e3),
1060
2020
  // Message timeout slightly longer than execution timeout
1061
- TRACING_TIMEOUT_MS2
2021
+ TRACING_TIMEOUT_MS3
1062
2022
  );
1063
2023
  } catch (error) {
1064
2024
  const errorMessage = error instanceof Error ? error.message : String(error);
@@ -1068,7 +2028,7 @@ var PyodideWorkerClient = class {
1068
2028
  success: false,
1069
2029
  error: errorMessage,
1070
2030
  trace: [],
1071
- executionTimeMs: TRACING_TIMEOUT_MS2,
2031
+ executionTimeMs: TRACING_TIMEOUT_MS3,
1072
2032
  consoleOutput: [],
1073
2033
  traceLimitExceeded: true,
1074
2034
  timeoutReason: "client-timeout",
@@ -1224,6 +2184,7 @@ var DEFAULT_BROWSER_HARNESS_ASSET_RELATIVE_PATHS = Object.freeze({
1224
2184
  pythonRuntimeCore: "pyodide/runtime-core.js",
1225
2185
  pythonSnippets: "generated-python-harness-snippets.js",
1226
2186
  javascriptWorker: "javascript-worker.js",
2187
+ javaWorker: "java-worker.js",
1227
2188
  typescriptCompiler: "vendor/typescript.js"
1228
2189
  });
1229
2190
  function isExplicitAssetPath(pathname) {
@@ -1257,6 +2218,7 @@ function resolveBrowserHarnessAssets(options = {}) {
1257
2218
  assetBaseUrl,
1258
2219
  assets.javascriptWorker ?? DEFAULT_BROWSER_HARNESS_ASSET_RELATIVE_PATHS.javascriptWorker
1259
2220
  ),
2221
+ javaWorker: resolveAssetPath(assetBaseUrl, assets.javaWorker ?? DEFAULT_BROWSER_HARNESS_ASSET_RELATIVE_PATHS.javaWorker),
1260
2222
  typescriptCompiler: resolveAssetPath(
1261
2223
  assetBaseUrl,
1262
2224
  assets.typescriptCompiler ?? DEFAULT_BROWSER_HARNESS_ASSET_RELATIVE_PATHS.typescriptCompiler
@@ -1270,6 +2232,7 @@ var BrowserHarnessRuntime = class {
1270
2232
  supportedLanguages = SUPPORTED_LANGUAGES;
1271
2233
  pythonWorkerClient;
1272
2234
  javaScriptWorkerClient;
2235
+ javaWorkerClient;
1273
2236
  clients;
1274
2237
  constructor(options = {}) {
1275
2238
  this.assets = resolveBrowserHarnessAssets(options);
@@ -1281,10 +2244,15 @@ var BrowserHarnessRuntime = class {
1281
2244
  workerUrl: this.assets.javascriptWorker,
1282
2245
  debug: options.debug
1283
2246
  });
2247
+ this.javaWorkerClient = new JavaWorkerClient({
2248
+ workerUrl: this.assets.javaWorker,
2249
+ debug: options.debug
2250
+ });
1284
2251
  this.clients = {
1285
2252
  python: createPythonRuntimeClient(this.pythonWorkerClient),
1286
2253
  javascript: createJavaScriptRuntimeClient("javascript", this.javaScriptWorkerClient),
1287
- typescript: createJavaScriptRuntimeClient("typescript", this.javaScriptWorkerClient)
2254
+ typescript: createJavaScriptRuntimeClient("typescript", this.javaScriptWorkerClient),
2255
+ java: createJavaRuntimeClient(this.javaWorkerClient)
1288
2256
  };
1289
2257
  }
1290
2258
  getClient(language) {
@@ -1308,11 +2276,16 @@ var BrowserHarnessRuntime = class {
1308
2276
  this.pythonWorkerClient.terminate();
1309
2277
  return;
1310
2278
  }
2279
+ if (language === "java") {
2280
+ this.javaWorkerClient.terminate();
2281
+ return;
2282
+ }
1311
2283
  this.javaScriptWorkerClient.terminate();
1312
2284
  }
1313
2285
  dispose() {
1314
2286
  this.pythonWorkerClient.terminate();
1315
2287
  this.javaScriptWorkerClient.terminate();
2288
+ this.javaWorkerClient.terminate();
1316
2289
  }
1317
2290
  };
1318
2291
  function createBrowserHarness(options = {}) {
@@ -2824,9 +3797,13 @@ export {
2824
3797
  TEMPLATE_PYTHON_TRACE_SERIALIZE_FUNCTION,
2825
3798
  TYPESCRIPT_RUNTIME_DECLARATIONS,
2826
3799
  adaptJavaScriptTraceExecutionResult,
3800
+ adaptJavaTraceExecutionResult as adaptJavaSpikeTraceExecutionResult,
3801
+ adaptJavaTraceExecutionResult,
2827
3802
  adaptPythonTraceExecutionResult,
2828
3803
  adaptTraceExecutionResult,
2829
3804
  assertRuntimeRequestSupported,
3805
+ buildJavaExecutionResult,
3806
+ buildJavaExecutionResult as buildJavaSpikeExecutionResult,
2830
3807
  createBrowserHarness,
2831
3808
  executeJavaScriptCode,
2832
3809
  executeJavaScriptWithTracing,
@@ -2838,6 +3815,8 @@ export {
2838
3815
  getSupportedLanguageProfiles,
2839
3816
  identifyConversions,
2840
3817
  isLanguageSupported,
3818
+ normalizeJavaTraceContract as normalizeJavaSpikeTraceContract,
3819
+ normalizeJavaTraceContract,
2841
3820
  normalizeRuntimeTraceContract,
2842
3821
  resolveBrowserHarnessAssets,
2843
3822
  stableStringifyRuntimeTraceContract,