@tracecode/harness 0.5.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +29 -3
  3. package/dist/browser.cjs +974 -19
  4. package/dist/browser.cjs.map +1 -1
  5. package/dist/browser.d.cts +3 -2
  6. package/dist/browser.d.ts +3 -2
  7. package/dist/browser.js +974 -19
  8. package/dist/browser.js.map +1 -1
  9. package/dist/cli.cjs +24 -0
  10. package/dist/cli.cjs.map +1 -1
  11. package/dist/cli.js +24 -0
  12. package/dist/cli.js.map +1 -1
  13. package/dist/core.cjs +611 -4
  14. package/dist/core.cjs.map +1 -1
  15. package/dist/core.d.cts +20 -6
  16. package/dist/core.d.ts +20 -6
  17. package/dist/core.js +605 -4
  18. package/dist/core.js.map +1 -1
  19. package/dist/index.cjs +1004 -19
  20. package/dist/index.cjs.map +1 -1
  21. package/dist/index.d.cts +3 -3
  22. package/dist/index.d.ts +3 -3
  23. package/dist/index.js +998 -19
  24. package/dist/index.js.map +1 -1
  25. package/dist/internal/browser.cjs +211 -0
  26. package/dist/internal/browser.cjs.map +1 -1
  27. package/dist/internal/browser.d.cts +62 -6
  28. package/dist/internal/browser.d.ts +62 -6
  29. package/dist/internal/browser.js +210 -0
  30. package/dist/internal/browser.js.map +1 -1
  31. package/dist/javascript.d.cts +2 -2
  32. package/dist/javascript.d.ts +2 -2
  33. package/dist/{runtime-types-DtaaAhHL.d.ts → runtime-types-89nchXlY.d.cts} +8 -4
  34. package/dist/{runtime-types--lBQ6rYu.d.cts → runtime-types-CCQ-ZLc9.d.ts} +8 -4
  35. package/dist/{types-DwIYM3Ku.d.cts → types-zyvpJKCi.d.cts} +1 -0
  36. package/dist/{types-DwIYM3Ku.d.ts → types-zyvpJKCi.d.ts} +1 -0
  37. package/package.json +11 -5
  38. package/workers/java/.build/classes/harness/browser/JavaRewriteLibrary.class +0 -0
  39. package/workers/java/java-worker.js +712 -0
  40. package/workers/java/src/harness/browser/JavaRewriteLibrary.java +54 -0
  41. package/workers/javascript/javascript-worker.js +343 -63
  42. package/workers/python/generated-python-harness-snippets.js +3 -3
  43. package/workers/python/pyodide-worker.js +419 -68
  44. package/workers/python/runtime-core.js +52 -3
  45. package/workers/vendor/java-browser-spike-helper.jar +0 -0
  46. package/workers/vendor/java-practice-rewriter.jar +0 -0
  47. package/workers/vendor/java-rewrite-bridge.jar +0 -0
  48. package/workers/vendor/javaparser-core-3.25.10.jar +0 -0
  49. package/workers/vendor/jdk.compiler-17.jar +0 -0
package/dist/browser.js CHANGED
@@ -255,7 +255,7 @@ var JavaScriptWorkerClient = class {
255
255
  };
256
256
 
257
257
  // packages/harness-core/src/trace-contract.ts
258
- var RUNTIME_TRACE_CONTRACT_SCHEMA_VERSION = "2026-03-13";
258
+ var RUNTIME_TRACE_CONTRACT_SCHEMA_VERSION = "2026-04-21";
259
259
  var TRACE_EVENTS = /* @__PURE__ */ new Set([
260
260
  "line",
261
261
  "call",
@@ -376,7 +376,39 @@ function normalizeAccesses(accesses) {
376
376
  }
377
377
  return payload;
378
378
  }).filter((access) => access !== null);
379
- return normalized.length > 0 ? normalized : void 0;
379
+ if (normalized.length === 0) {
380
+ return void 0;
381
+ }
382
+ const statsByVariable = /* @__PURE__ */ new Map();
383
+ for (const access of normalized) {
384
+ const stats = statsByVariable.get(access.variable) ?? { hasCellRead: false, hasCellWrite: false };
385
+ if (access.kind === "cell-read") stats.hasCellRead = true;
386
+ if (access.kind === "cell-write") stats.hasCellWrite = true;
387
+ statsByVariable.set(access.variable, stats);
388
+ }
389
+ const deduped = /* @__PURE__ */ new Set();
390
+ const collapsed = normalized.filter((access) => {
391
+ const stats = statsByVariable.get(access.variable);
392
+ if (access.kind === "indexed-read" && (stats?.hasCellRead || stats?.hasCellWrite)) {
393
+ return false;
394
+ }
395
+ if (access.kind === "indexed-write" && stats?.hasCellWrite) {
396
+ return false;
397
+ }
398
+ const key = JSON.stringify([
399
+ access.variable,
400
+ access.kind,
401
+ access.indices ?? null,
402
+ access.pathDepth ?? null,
403
+ access.method ?? null
404
+ ]);
405
+ if (deduped.has(key)) {
406
+ return false;
407
+ }
408
+ deduped.add(key);
409
+ return true;
410
+ });
411
+ return collapsed.length > 0 ? collapsed : void 0;
380
412
  }
381
413
  function normalizeRecord(value) {
382
414
  if (!value || typeof value !== "object" || Array.isArray(value)) return {};
@@ -440,8 +472,64 @@ function normalizeTraceStep(step) {
440
472
  ...normalizedVisualization ? { visualization: normalizedVisualization } : {}
441
473
  };
442
474
  }
475
+ function collapseTraceAccessNoise(trace) {
476
+ const variablesWithCellAccess = /* @__PURE__ */ new Set();
477
+ const accessStatsByVariable = /* @__PURE__ */ new Map();
478
+ for (const step of trace) {
479
+ for (const access of step.accesses ?? []) {
480
+ const stats = accessStatsByVariable.get(access.variable) ?? {
481
+ hasCellRead: false,
482
+ hasCellWrite: false,
483
+ hasMutatingCall: false,
484
+ hasIndexedWrite: false
485
+ };
486
+ if (access.kind === "cell-read" || access.kind === "cell-write") {
487
+ variablesWithCellAccess.add(access.variable);
488
+ }
489
+ if (access.kind === "cell-read") stats.hasCellRead = true;
490
+ if (access.kind === "cell-write") stats.hasCellWrite = true;
491
+ if (access.kind === "mutating-call") stats.hasMutatingCall = true;
492
+ if (access.kind === "indexed-write") stats.hasIndexedWrite = true;
493
+ accessStatsByVariable.set(access.variable, stats);
494
+ }
495
+ }
496
+ if (variablesWithCellAccess.size === 0) {
497
+ return trace;
498
+ }
499
+ return trace.map((step) => {
500
+ if (!step.accesses?.length) {
501
+ return step;
502
+ }
503
+ const filtered = step.accesses.filter((access) => {
504
+ const stats = accessStatsByVariable.get(access.variable);
505
+ if (variablesWithCellAccess.has(access.variable)) {
506
+ return access.kind !== "indexed-read" && access.kind !== "indexed-write";
507
+ }
508
+ if (access.kind === "mutating-call" && stats?.hasIndexedWrite && !stats.hasCellRead && !stats.hasCellWrite) {
509
+ return false;
510
+ }
511
+ if (access.kind === "indexed-read" && stats?.hasMutatingCall && !stats.hasIndexedWrite && !stats.hasCellRead && !stats.hasCellWrite) {
512
+ return false;
513
+ }
514
+ return true;
515
+ });
516
+ if (filtered.length === step.accesses.length) {
517
+ return step;
518
+ }
519
+ return {
520
+ ...step,
521
+ ...filtered.length > 0 ? { accesses: filtered } : {},
522
+ ...filtered.length === 0 ? { accesses: void 0 } : {}
523
+ };
524
+ });
525
+ }
443
526
  function normalizeRuntimeTraceContract(language, result) {
444
- const normalizedTrace = Array.isArray(result.trace) ? result.trace.map(normalizeTraceStep) : [];
527
+ const rawNormalizedTrace = collapseTraceAccessNoise(
528
+ Array.isArray(result.trace) ? result.trace.map(normalizeTraceStep) : []
529
+ );
530
+ const maxTraceSteps = typeof result.maxTraceSteps === "number" && Number.isFinite(result.maxTraceSteps) ? Math.max(1, Math.floor(result.maxTraceSteps)) : void 0;
531
+ const traceWasClipped = maxTraceSteps !== void 0 && rawNormalizedTrace.length > maxTraceSteps;
532
+ const normalizedTrace = traceWasClipped && maxTraceSteps !== void 0 ? rawNormalizedTrace.slice(0, maxTraceSteps) : rawNormalizedTrace;
445
533
  const lineEventCount = typeof result.lineEventCount === "number" && Number.isFinite(result.lineEventCount) ? Math.floor(result.lineEventCount) : normalizedTrace.filter((step) => step.event === "line").length;
446
534
  const normalizedConsole = Array.isArray(result.consoleOutput) ? result.consoleOutput.map((line) => String(line)) : [];
447
535
  return {
@@ -453,7 +541,7 @@ function normalizeRuntimeTraceContract(language, result) {
453
541
  ...typeof result.errorLine === "number" && Number.isFinite(result.errorLine) ? { errorLine: Math.floor(result.errorLine) } : {},
454
542
  consoleOutput: normalizedConsole,
455
543
  trace: normalizedTrace,
456
- ...result.traceLimitExceeded !== void 0 ? { traceLimitExceeded: Boolean(result.traceLimitExceeded) } : {},
544
+ ...result.traceLimitExceeded !== void 0 || traceWasClipped ? { traceLimitExceeded: Boolean(result.traceLimitExceeded) || traceWasClipped } : {},
457
545
  ...typeof result.timeoutReason === "string" && result.timeoutReason.length > 0 ? { timeoutReason: result.timeoutReason } : {},
458
546
  lineEventCount: Math.max(0, lineEventCount),
459
547
  traceStepCount: normalizedTrace.length
@@ -574,6 +662,7 @@ var PYTHON_RUNTIME_PROFILE = {
574
662
  maxTraceSteps: true,
575
663
  maxLineEvents: true,
576
664
  maxSingleLineHits: true,
665
+ maxStoredEvents: true,
577
666
  minimalTrace: true
578
667
  },
579
668
  fidelity: {
@@ -635,6 +724,7 @@ var JAVASCRIPT_RUNTIME_PROFILE = {
635
724
  maxTraceSteps: true,
636
725
  maxLineEvents: true,
637
726
  maxSingleLineHits: true,
727
+ maxStoredEvents: true,
638
728
  minimalTrace: true
639
729
  },
640
730
  fidelity: {
@@ -696,6 +786,7 @@ var TYPESCRIPT_RUNTIME_PROFILE = {
696
786
  maxTraceSteps: true,
697
787
  maxLineEvents: true,
698
788
  maxSingleLineHits: true,
789
+ maxStoredEvents: true,
699
790
  minimalTrace: true
700
791
  },
701
792
  fidelity: {
@@ -726,10 +817,78 @@ var TYPESCRIPT_RUNTIME_PROFILE = {
726
817
  }
727
818
  }
728
819
  };
820
+ var JAVA_RUNTIME_PROFILE = {
821
+ language: "java",
822
+ maturity: "experimental",
823
+ capabilities: {
824
+ execution: {
825
+ styles: {
826
+ function: true,
827
+ solutionMethod: true,
828
+ opsClass: true,
829
+ script: false,
830
+ interviewMode: true
831
+ },
832
+ timeouts: {
833
+ clientTimeouts: true,
834
+ runtimeTimeouts: true
835
+ }
836
+ },
837
+ tracing: {
838
+ supported: true,
839
+ events: {
840
+ line: true,
841
+ call: true,
842
+ return: true,
843
+ exception: true,
844
+ stdout: false,
845
+ timeout: true
846
+ },
847
+ controls: {
848
+ maxTraceSteps: true,
849
+ maxLineEvents: false,
850
+ maxSingleLineHits: false,
851
+ maxStoredEvents: true,
852
+ minimalTrace: false
853
+ },
854
+ fidelity: {
855
+ preciseLineMapping: true,
856
+ stableFunctionNames: true,
857
+ callStack: true
858
+ }
859
+ },
860
+ diagnostics: {
861
+ compileErrors: true,
862
+ runtimeErrors: true,
863
+ mappedErrorLines: false,
864
+ stackTraces: true
865
+ },
866
+ structures: {
867
+ treeNodeRefs: true,
868
+ listNodeRefs: true,
869
+ mapSerialization: true,
870
+ setSerialization: true,
871
+ graphSerialization: false,
872
+ cycleReferences: true
873
+ },
874
+ visualization: {
875
+ runtimePayloads: true,
876
+ objectKinds: true,
877
+ hashMaps: true,
878
+ stepVisualization: true
879
+ }
880
+ },
881
+ notes: [
882
+ "Java currently supports the browser-local Java 17 lane for function, solution-method, and ops-class execution.",
883
+ "Interview-mode Java reuses the same browser-local execution path and remains experimental in the first harness slice.",
884
+ "Script-style Java is not enabled yet."
885
+ ]
886
+ };
729
887
  var LANGUAGE_RUNTIME_PROFILES = {
730
888
  python: PYTHON_RUNTIME_PROFILE,
731
889
  javascript: JAVASCRIPT_RUNTIME_PROFILE,
732
- typescript: TYPESCRIPT_RUNTIME_PROFILE
890
+ typescript: TYPESCRIPT_RUNTIME_PROFILE,
891
+ java: JAVA_RUNTIME_PROFILE
733
892
  };
734
893
  var SUPPORTED_LANGUAGES = Object.freeze(
735
894
  Object.keys(LANGUAGE_RUNTIME_PROFILES)
@@ -806,13 +965,796 @@ function createJavaScriptRuntimeClient(runtimeLanguage, workerClient) {
806
965
  return new JavaScriptRuntimeClient(runtimeLanguage, workerClient);
807
966
  }
808
967
 
968
+ // packages/harness-browser/src/java-worker-client.ts
969
+ var TRACING_TIMEOUT_MS2 = 25e3;
970
+ var INIT_TIMEOUT_MS2 = 25e3;
971
+ var MESSAGE_TIMEOUT_MS2 = 3e4;
972
+ var WORKER_READY_TIMEOUT_MS2 = 1e4;
973
+ var JavaWorkerClient = class {
974
+ constructor(options) {
975
+ this.options = options;
976
+ this.debug = options.debug ?? process.env.NODE_ENV === "development";
977
+ }
978
+ worker = null;
979
+ pendingMessages = /* @__PURE__ */ new Map();
980
+ messageId = 0;
981
+ isInitializing = false;
982
+ initPromise = null;
983
+ workerReadyPromise = null;
984
+ workerReadyResolve = null;
985
+ workerReadyReject = null;
986
+ debug;
987
+ isSupported() {
988
+ return typeof Worker !== "undefined";
989
+ }
990
+ getWorker() {
991
+ if (this.worker) return this.worker;
992
+ if (!this.isSupported()) {
993
+ throw new Error("Web Workers are not supported in this environment");
994
+ }
995
+ this.workerReadyPromise = new Promise((resolve, reject) => {
996
+ this.workerReadyResolve = resolve;
997
+ this.workerReadyReject = (error) => reject(error);
998
+ });
999
+ const workerUrl = this.debug && !this.options.workerUrl.includes("?") ? `${this.options.workerUrl}?dev=${Date.now()}` : this.options.workerUrl;
1000
+ this.worker = new Worker(workerUrl);
1001
+ this.worker.onmessage = (event) => {
1002
+ const { id, type, payload } = event.data;
1003
+ if (type === "worker-ready") {
1004
+ this.workerReadyResolve?.();
1005
+ this.workerReadyResolve = null;
1006
+ this.workerReadyReject = null;
1007
+ return;
1008
+ }
1009
+ if (!id) return;
1010
+ const pending = this.pendingMessages.get(id);
1011
+ if (!pending) return;
1012
+ this.pendingMessages.delete(id);
1013
+ if (pending.timeoutId) globalThis.clearTimeout(pending.timeoutId);
1014
+ if (type === "error") {
1015
+ pending.reject(new Error(payload.error));
1016
+ return;
1017
+ }
1018
+ pending.resolve(payload);
1019
+ };
1020
+ this.worker.onerror = (error) => {
1021
+ const workerError = new Error(error.message || "Java worker error");
1022
+ this.workerReadyReject?.(workerError);
1023
+ this.workerReadyResolve = null;
1024
+ this.workerReadyReject = null;
1025
+ for (const [, pending] of this.pendingMessages) {
1026
+ if (pending.timeoutId) globalThis.clearTimeout(pending.timeoutId);
1027
+ pending.reject(workerError);
1028
+ }
1029
+ this.pendingMessages.clear();
1030
+ this.terminateAndReset(workerError);
1031
+ };
1032
+ return this.worker;
1033
+ }
1034
+ async waitForWorkerReady() {
1035
+ const readyPromise = this.workerReadyPromise;
1036
+ if (!readyPromise) return;
1037
+ await new Promise((resolve, reject) => {
1038
+ let settled = false;
1039
+ const timeoutId = globalThis.setTimeout(() => {
1040
+ if (settled) return;
1041
+ settled = true;
1042
+ const timeoutError = new Error(
1043
+ `Java worker failed to initialize in time (${Math.round(WORKER_READY_TIMEOUT_MS2 / 1e3)}s)`
1044
+ );
1045
+ this.terminateAndReset(timeoutError);
1046
+ reject(timeoutError);
1047
+ }, WORKER_READY_TIMEOUT_MS2);
1048
+ readyPromise.then(() => {
1049
+ if (settled) return;
1050
+ settled = true;
1051
+ globalThis.clearTimeout(timeoutId);
1052
+ resolve();
1053
+ }).catch((error) => {
1054
+ if (settled) return;
1055
+ settled = true;
1056
+ globalThis.clearTimeout(timeoutId);
1057
+ reject(error instanceof Error ? error : new Error(String(error)));
1058
+ });
1059
+ });
1060
+ }
1061
+ async sendMessage(type, payload, timeoutMs = MESSAGE_TIMEOUT_MS2) {
1062
+ const worker = this.getWorker();
1063
+ await this.waitForWorkerReady();
1064
+ const id = String(++this.messageId);
1065
+ return new Promise((resolve, reject) => {
1066
+ this.pendingMessages.set(id, {
1067
+ resolve,
1068
+ reject
1069
+ });
1070
+ const timeoutId = globalThis.setTimeout(() => {
1071
+ const pending2 = this.pendingMessages.get(id);
1072
+ if (!pending2) return;
1073
+ this.pendingMessages.delete(id);
1074
+ pending2.reject(new Error(`Worker request timed out: ${type}`));
1075
+ }, timeoutMs);
1076
+ const pending = this.pendingMessages.get(id);
1077
+ if (pending) pending.timeoutId = timeoutId;
1078
+ worker.postMessage({ id, type, payload });
1079
+ });
1080
+ }
1081
+ async executeWithTimeout(executor, timeoutMs) {
1082
+ return new Promise((resolve, reject) => {
1083
+ let settled = false;
1084
+ const timeoutId = globalThis.setTimeout(() => {
1085
+ if (settled) return;
1086
+ settled = true;
1087
+ this.terminateAndReset();
1088
+ reject(
1089
+ new Error(
1090
+ `Java execution timed out after ${Math.round(timeoutMs / 1e3)} seconds.`
1091
+ )
1092
+ );
1093
+ }, timeoutMs);
1094
+ executor().then((result) => {
1095
+ if (settled) return;
1096
+ settled = true;
1097
+ globalThis.clearTimeout(timeoutId);
1098
+ resolve(result);
1099
+ }).catch((error) => {
1100
+ if (settled) return;
1101
+ settled = true;
1102
+ globalThis.clearTimeout(timeoutId);
1103
+ reject(error);
1104
+ });
1105
+ });
1106
+ }
1107
+ terminateAndReset(reason = new Error("Worker was terminated")) {
1108
+ this.workerReadyReject?.(reason);
1109
+ if (this.worker) {
1110
+ this.worker.terminate();
1111
+ this.worker = null;
1112
+ }
1113
+ this.initPromise = null;
1114
+ this.isInitializing = false;
1115
+ this.workerReadyPromise = null;
1116
+ this.workerReadyResolve = null;
1117
+ this.workerReadyReject = null;
1118
+ for (const [, pending] of this.pendingMessages) {
1119
+ if (pending.timeoutId) globalThis.clearTimeout(pending.timeoutId);
1120
+ pending.reject(reason);
1121
+ }
1122
+ this.pendingMessages.clear();
1123
+ }
1124
+ async init() {
1125
+ if (this.initPromise) return this.initPromise;
1126
+ if (this.isInitializing) {
1127
+ await new Promise((resolve) => globalThis.setTimeout(resolve, 100));
1128
+ return this.init();
1129
+ }
1130
+ this.isInitializing = true;
1131
+ this.initPromise = this.sendMessage("init", void 0, INIT_TIMEOUT_MS2);
1132
+ try {
1133
+ return await this.initPromise;
1134
+ } catch (error) {
1135
+ this.initPromise = null;
1136
+ throw error;
1137
+ } finally {
1138
+ this.isInitializing = false;
1139
+ }
1140
+ }
1141
+ async executeWithTracing(code, functionName, inputs, options, executionStyle) {
1142
+ await this.init();
1143
+ return this.executeWithTimeout(
1144
+ () => this.sendMessage(
1145
+ "execute-with-tracing",
1146
+ { code, functionName, inputs, options, executionStyle },
1147
+ TRACING_TIMEOUT_MS2 + 5e3
1148
+ ),
1149
+ TRACING_TIMEOUT_MS2
1150
+ );
1151
+ }
1152
+ async executeCode(code, functionName, inputs, options, executionStyle) {
1153
+ const result = await this.executeWithTracing(code, functionName, inputs, options, executionStyle);
1154
+ if (!result.success) {
1155
+ return {
1156
+ success: false,
1157
+ output: null,
1158
+ error: result.error ?? "Java execution failed",
1159
+ ...result.errorLine !== void 0 ? { errorLine: result.errorLine } : {},
1160
+ consoleOutput: result.consoleOutput
1161
+ };
1162
+ }
1163
+ return {
1164
+ success: true,
1165
+ output: result.output,
1166
+ consoleOutput: result.consoleOutput
1167
+ };
1168
+ }
1169
+ async executeCodeInterviewMode(code, functionName, inputs, options, executionStyle) {
1170
+ return this.executeCode(code, functionName, inputs, options, executionStyle);
1171
+ }
1172
+ terminate() {
1173
+ this.terminateAndReset();
1174
+ }
1175
+ };
1176
+
1177
+ // packages/harness-core/src/trace-adapters/java.ts
1178
+ function parseScalar(raw) {
1179
+ if (raw === "null") return null;
1180
+ if (raw === "true") return true;
1181
+ if (raw === "false") return false;
1182
+ if (/^-?\d+$/.test(raw)) return Number.parseInt(raw, 10);
1183
+ if (/^-?\d+\.\d+$/.test(raw)) return Number.parseFloat(raw);
1184
+ if (raw.startsWith('"') && raw.endsWith('"') || raw.startsWith("[") && raw.endsWith("]") || raw.startsWith("{") && raw.endsWith("}")) {
1185
+ try {
1186
+ return JSON.parse(raw);
1187
+ } catch {
1188
+ }
1189
+ }
1190
+ return raw;
1191
+ }
1192
+ function parseKeyValuePairs(fragment) {
1193
+ const variables = {};
1194
+ const matches = Array.from(fragment.matchAll(/\b([A-Za-z_][A-Za-z0-9_.]*)=/g));
1195
+ for (let index = 0; index < matches.length; index += 1) {
1196
+ const match = matches[index];
1197
+ const rawKey = match[1];
1198
+ const valueStart = (match.index ?? 0) + match[0].length;
1199
+ const valueEnd = index + 1 < matches.length ? matches[index + 1].index ?? fragment.length : fragment.length;
1200
+ const rawValue = fragment.slice(valueStart, valueEnd).trim();
1201
+ if (!rawKey || rawValue === void 0) continue;
1202
+ if (rawKey === "method") continue;
1203
+ variables[rawKey.replaceAll(".", "_")] = parseScalar(rawValue);
1204
+ }
1205
+ return variables;
1206
+ }
1207
+ function extractLineMetadata(event) {
1208
+ const match = event.match(/^line=(\d+)(?:\s+(.*))?$/);
1209
+ if (!match) {
1210
+ return { line: 1, payload: event };
1211
+ }
1212
+ return {
1213
+ line: Number.parseInt(match[1], 10),
1214
+ payload: match[2] ?? ""
1215
+ };
1216
+ }
1217
+ function stripInlineComments(line, inBlockComment) {
1218
+ let result = "";
1219
+ let index = 0;
1220
+ let inBlock = inBlockComment;
1221
+ while (index < line.length) {
1222
+ const current = line[index];
1223
+ const next = index + 1 < line.length ? line[index + 1] : "";
1224
+ if (inBlock) {
1225
+ if (current === "*" && next === "/") {
1226
+ inBlock = false;
1227
+ index += 2;
1228
+ continue;
1229
+ }
1230
+ index += 1;
1231
+ continue;
1232
+ }
1233
+ if (current === "/" && next === "*") {
1234
+ inBlock = true;
1235
+ index += 2;
1236
+ continue;
1237
+ }
1238
+ if (current === "/" && next === "/") {
1239
+ break;
1240
+ }
1241
+ result += current;
1242
+ index += 1;
1243
+ }
1244
+ return { text: result, inBlockComment: inBlock };
1245
+ }
1246
+ function isMethodDeclarationLine(line) {
1247
+ const trimmed = line.trim();
1248
+ if (!trimmed) return false;
1249
+ if (trimmed.startsWith("@")) return false;
1250
+ if (!trimmed.includes("(") || !trimmed.includes(")")) return false;
1251
+ if (trimmed.endsWith(";")) return false;
1252
+ if (trimmed.includes("->")) return false;
1253
+ if (/^(?:if|for|while|switch|catch|do|try|else|return|throw|new)\b/.test(trimmed)) {
1254
+ return false;
1255
+ }
1256
+ if (!/[A-Za-z_][A-Za-z0-9_]*\s*\([^{};]*\)/.test(trimmed)) {
1257
+ return false;
1258
+ }
1259
+ return /(?:\{\s*)?$/.test(trimmed);
1260
+ }
1261
+ function buildLineRemap(sourceText) {
1262
+ if (typeof sourceText !== "string" || sourceText.length === 0) {
1263
+ return null;
1264
+ }
1265
+ const lines = sourceText.split(/\r?\n/);
1266
+ const executable = /* @__PURE__ */ new Set();
1267
+ let inBlockComment = false;
1268
+ for (let index = 0; index < lines.length; index += 1) {
1269
+ const { text, inBlockComment: nextInBlockComment } = stripInlineComments(lines[index] ?? "", inBlockComment);
1270
+ inBlockComment = nextInBlockComment;
1271
+ if (text.trim().length > 0) {
1272
+ executable.add(index + 1);
1273
+ }
1274
+ }
1275
+ if (executable.size === 0) {
1276
+ return null;
1277
+ }
1278
+ const nextExecutableAtOrAfter = new Array(lines.length + 2).fill(null);
1279
+ let nextExecutable = null;
1280
+ for (let line = lines.length; line >= 1; line -= 1) {
1281
+ if (executable.has(line)) {
1282
+ nextExecutable = line;
1283
+ }
1284
+ nextExecutableAtOrAfter[line] = nextExecutable;
1285
+ }
1286
+ const previousExecutableAtOrBefore = new Array(lines.length + 2).fill(null);
1287
+ let previousExecutable = null;
1288
+ for (let line = 1; line <= lines.length; line += 1) {
1289
+ if (executable.has(line)) {
1290
+ previousExecutable = line;
1291
+ }
1292
+ previousExecutableAtOrBefore[line] = previousExecutable;
1293
+ }
1294
+ const remap = /* @__PURE__ */ new Map();
1295
+ for (let line = 1; line <= lines.length; line += 1) {
1296
+ if (executable.has(line)) continue;
1297
+ const forward = nextExecutableAtOrAfter[line];
1298
+ const backward = previousExecutableAtOrBefore[line];
1299
+ const target = forward ?? backward;
1300
+ if (target !== null && target !== line) {
1301
+ remap.set(line, target);
1302
+ }
1303
+ }
1304
+ return remap;
1305
+ }
1306
+ function buildMethodDeclarationLineSet(sourceText) {
1307
+ if (typeof sourceText !== "string" || sourceText.length === 0) {
1308
+ return null;
1309
+ }
1310
+ const declarationLines = /* @__PURE__ */ new Set();
1311
+ const lines = sourceText.split(/\r?\n/);
1312
+ let inBlockComment = false;
1313
+ for (let index = 0; index < lines.length; index += 1) {
1314
+ const { text, inBlockComment: nextInBlockComment } = stripInlineComments(lines[index] ?? "", inBlockComment);
1315
+ inBlockComment = nextInBlockComment;
1316
+ if (isMethodDeclarationLine(text)) {
1317
+ declarationLines.add(index + 1);
1318
+ }
1319
+ }
1320
+ return declarationLines;
1321
+ }
1322
+ function parseAccessEvent(payload) {
1323
+ const isEphemeralOutputArrayName = (name) => /^(output|outputs)$/i.test(name);
1324
+ const cellRead = payload.match(/^access ([A-Za-z_][A-Za-z0-9_]*)\[(\d+)\]\[(\d+)\]=(.+)$/);
1325
+ if (cellRead) {
1326
+ return [{
1327
+ variable: cellRead[1],
1328
+ kind: "cell-read",
1329
+ indices: [Number.parseInt(cellRead[2], 10), Number.parseInt(cellRead[3], 10)],
1330
+ pathDepth: 2
1331
+ }];
1332
+ }
1333
+ const indexedRead = payload.match(/^access ([A-Za-z_][A-Za-z0-9_]*)\[(\d+)\]=(.+)$/);
1334
+ if (indexedRead) {
1335
+ return [{
1336
+ variable: indexedRead[1],
1337
+ kind: "indexed-read",
1338
+ indices: [Number.parseInt(indexedRead[2], 10)],
1339
+ pathDepth: 1
1340
+ }];
1341
+ }
1342
+ const cellWrite = payload.match(/^write-array ([A-Za-z_][A-Za-z0-9_]*)\[(\d+)\]\[(\d+)\]=(.+)$/);
1343
+ if (cellWrite) {
1344
+ return [{
1345
+ variable: cellWrite[1],
1346
+ kind: "cell-write",
1347
+ indices: [Number.parseInt(cellWrite[2], 10), Number.parseInt(cellWrite[3], 10)],
1348
+ pathDepth: 2
1349
+ }];
1350
+ }
1351
+ const indexedWrite = payload.match(/^write-array ([A-Za-z_][A-Za-z0-9_]*)\[(\d+)\]=(.+)$/);
1352
+ if (indexedWrite) {
1353
+ if (isEphemeralOutputArrayName(indexedWrite[1])) {
1354
+ return void 0;
1355
+ }
1356
+ return [{
1357
+ variable: indexedWrite[1],
1358
+ kind: "indexed-write",
1359
+ indices: [Number.parseInt(indexedWrite[2], 10)],
1360
+ pathDepth: 1
1361
+ }];
1362
+ }
1363
+ const mutatingCall = payload.match(/^mutate ([A-Za-z_][A-Za-z0-9_]*) method=([A-Za-z_][A-Za-z0-9_]*)$/);
1364
+ if (mutatingCall) {
1365
+ return [{
1366
+ variable: mutatingCall[1],
1367
+ kind: "mutating-call",
1368
+ method: mutatingCall[2],
1369
+ pathDepth: 1
1370
+ }];
1371
+ }
1372
+ return void 0;
1373
+ }
1374
+ function parseStructureState(payload) {
1375
+ const match = payload.match(/^state (linked-list|tree) ([A-Za-z_][A-Za-z0-9_]*)=(.+)$/);
1376
+ if (!match) return null;
1377
+ return {
1378
+ structure: match[1],
1379
+ variable: match[2],
1380
+ value: JSON.parse(match[3])
1381
+ };
1382
+ }
1383
+ function parseObjectState(payload) {
1384
+ const match = payload.match(/^object-state ([A-Za-z_][A-Za-z0-9_]*)=(.+)$/);
1385
+ if (!match) return null;
1386
+ return {
1387
+ variable: match[1],
1388
+ visualization: JSON.parse(match[2])
1389
+ };
1390
+ }
1391
+ function parseObjectFieldEvent(payload) {
1392
+ const match = payload.match(/^(access|write) ([A-Za-z_][A-Za-z0-9_]*)\.([A-Za-z_][A-Za-z0-9_]*)=(.+)$/);
1393
+ if (!match) return null;
1394
+ return {
1395
+ variable: match[2],
1396
+ field: match[3],
1397
+ value: parseScalar(match[4])
1398
+ };
1399
+ }
1400
+ function buildFieldVisualization(event) {
1401
+ return {
1402
+ objectKinds: {
1403
+ [event.variable]: "object"
1404
+ },
1405
+ hashMaps: [
1406
+ {
1407
+ name: event.variable,
1408
+ kind: "object",
1409
+ objectClassName: event.field === "next" || event.field === "prev" ? "ListNode" : event.field === "left" || event.field === "right" ? "TreeNode" : void 0,
1410
+ objectId: `${event.variable}-object`,
1411
+ highlightedKey: event.field,
1412
+ entries: [{ key: event.field, value: event.value, highlight: true }]
1413
+ }
1414
+ ]
1415
+ };
1416
+ }
1417
+ function callStacksEqual(left, right) {
1418
+ return JSON.stringify(left ?? []) === JSON.stringify(right ?? []);
1419
+ }
1420
+ function mergeVisualizationPayloads(left, right) {
1421
+ if (!left) return right;
1422
+ if (!right) return left;
1423
+ return {
1424
+ ...left,
1425
+ ...right,
1426
+ objectKinds: {
1427
+ ...left.objectKinds ?? {},
1428
+ ...right.objectKinds ?? {}
1429
+ },
1430
+ hashMaps: [
1431
+ ...left.hashMaps ?? [],
1432
+ ...right.hashMaps ?? []
1433
+ ]
1434
+ };
1435
+ }
1436
+ function maybeMergeConsecutiveLineStep(trace, nextStep) {
1437
+ if (nextStep.event !== "line") {
1438
+ return false;
1439
+ }
1440
+ const previous = trace.at(-1);
1441
+ if (!previous || previous.event !== "line") {
1442
+ return false;
1443
+ }
1444
+ if (previous.line !== nextStep.line || previous.function !== nextStep.function) {
1445
+ return false;
1446
+ }
1447
+ if (!callStacksEqual(previous.callStack, nextStep.callStack)) {
1448
+ return false;
1449
+ }
1450
+ previous.variables = { ...previous.variables ?? {}, ...nextStep.variables ?? {} };
1451
+ if (nextStep.accesses?.length) {
1452
+ previous.accesses = [...previous.accesses ?? [], ...nextStep.accesses];
1453
+ }
1454
+ previous.visualization = mergeVisualizationPayloads(previous.visualization, nextStep.visualization);
1455
+ return true;
1456
+ }
1457
+ function filterStructuredVariables(variables) {
1458
+ if (!variables) {
1459
+ return void 0;
1460
+ }
1461
+ const isEphemeralOutputArrayName = (name) => /^(output|outputs)$/i.test(name);
1462
+ const entries = Object.entries(variables).filter(([name, value]) => {
1463
+ if (value === null || typeof value !== "object") {
1464
+ return false;
1465
+ }
1466
+ if (!Array.isArray(value)) {
1467
+ return true;
1468
+ }
1469
+ if (Array.isArray(value[0])) {
1470
+ return true;
1471
+ }
1472
+ return !isEphemeralOutputArrayName(name);
1473
+ });
1474
+ if (entries.length === 0) {
1475
+ return void 0;
1476
+ }
1477
+ return Object.fromEntries(entries);
1478
+ }
1479
+ function appendJavaTraceStep(trace, step, pendingAccesses) {
1480
+ const nextStep = pendingAccesses.length > 0 ? { ...step, accesses: [...pendingAccesses] } : step;
1481
+ pendingAccesses.length = 0;
1482
+ if (!maybeMergeConsecutiveLineStep(trace, nextStep)) {
1483
+ trace.push(nextStep);
1484
+ }
1485
+ }
1486
+ function mergeIntoPreviousMatchingLineStep(trace, line, currentFunction, currentCallStack, patch) {
1487
+ const candidate = trace.at(-1);
1488
+ if (!candidate || candidate.event !== "line") {
1489
+ return false;
1490
+ }
1491
+ if (candidate.line !== line || candidate.function !== currentFunction) {
1492
+ return false;
1493
+ }
1494
+ if (!callStacksEqual(candidate.callStack, currentCallStack)) {
1495
+ return false;
1496
+ }
1497
+ candidate.variables = { ...candidate.variables ?? {}, ...patch.variables ?? {} };
1498
+ if (patch.accesses?.length) {
1499
+ candidate.accesses = [...candidate.accesses ?? [], ...patch.accesses];
1500
+ }
1501
+ candidate.visualization = mergeVisualizationPayloads(candidate.visualization, patch.visualization);
1502
+ return true;
1503
+ }
1504
+ function mergeAccessesIntoPreviousMatchingLineStep(trace, line, currentFunction, currentCallStack, accesses) {
1505
+ return mergeIntoPreviousMatchingLineStep(trace, line, currentFunction, currentCallStack, {
1506
+ variables: void 0,
1507
+ accesses,
1508
+ visualization: void 0
1509
+ });
1510
+ }
1511
+ function eventsToRawTrace(events, sourceText) {
1512
+ const trace = [];
1513
+ const variables = {};
1514
+ const objectKinds = {};
1515
+ const stack = [];
1516
+ const pendingAccesses = [];
1517
+ let currentFunction = "<module>";
1518
+ const lineRemap = buildLineRemap(sourceText);
1519
+ const declarationLines = buildMethodDeclarationLineSet(sourceText);
1520
+ for (const rawEvent of events) {
1521
+ if (rawEvent === "clear" || rawEvent === "reset") continue;
1522
+ const metadata = extractLineMetadata(rawEvent);
1523
+ const line = lineRemap?.get(metadata.line) ?? metadata.line;
1524
+ const payload = metadata.payload;
1525
+ const isDeclarationLine = declarationLines?.has(line) === true;
1526
+ if (payload.startsWith("call ")) {
1527
+ const match = payload.match(/^call\s+(\S+)(?:\s+(.*))?$/);
1528
+ const functionName = match?.[1] ?? currentFunction;
1529
+ const argsFragment = match?.[2] ?? "";
1530
+ Object.assign(variables, parseKeyValuePairs(argsFragment));
1531
+ currentFunction = functionName || currentFunction;
1532
+ stack.push({ function: currentFunction, line });
1533
+ appendJavaTraceStep(trace, {
1534
+ line,
1535
+ event: "call",
1536
+ function: currentFunction,
1537
+ variables: { ...variables },
1538
+ callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} }))
1539
+ }, pendingAccesses);
1540
+ continue;
1541
+ }
1542
+ if (payload.startsWith("return ")) {
1543
+ const match = payload.match(/^return\s+(\S+)$/);
1544
+ const functionName = match?.[1] ?? currentFunction;
1545
+ const returnVariables = functionName === "<module>" ? { ...variables } : filterStructuredVariables(variables) ?? {};
1546
+ appendJavaTraceStep(trace, {
1547
+ line,
1548
+ event: "return",
1549
+ function: functionName || currentFunction,
1550
+ variables: returnVariables,
1551
+ callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} }))
1552
+ }, pendingAccesses);
1553
+ stack.pop();
1554
+ currentFunction = stack[stack.length - 1]?.function ?? "<module>";
1555
+ continue;
1556
+ }
1557
+ if (isDeclarationLine) {
1558
+ continue;
1559
+ }
1560
+ if (payload.length === 0) {
1561
+ appendJavaTraceStep(trace, {
1562
+ line,
1563
+ event: "line",
1564
+ function: currentFunction,
1565
+ variables: { ...variables },
1566
+ ...stack.length > 0 ? { callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })) } : {}
1567
+ }, pendingAccesses);
1568
+ continue;
1569
+ }
1570
+ const structureState = parseStructureState(payload);
1571
+ if (structureState) {
1572
+ variables[structureState.variable] = structureState.value;
1573
+ objectKinds[structureState.variable] = structureState.structure;
1574
+ appendJavaTraceStep(trace, {
1575
+ line,
1576
+ event: "line",
1577
+ function: currentFunction,
1578
+ variables: { ...variables },
1579
+ callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })),
1580
+ visualization: {
1581
+ objectKinds: { ...objectKinds }
1582
+ }
1583
+ }, pendingAccesses);
1584
+ continue;
1585
+ }
1586
+ const objectState = parseObjectState(payload);
1587
+ if (objectState) {
1588
+ variables[objectState.variable] = { __ref__: objectState.visualization.objectId ?? `${objectState.variable}-object` };
1589
+ appendJavaTraceStep(trace, {
1590
+ line,
1591
+ event: "line",
1592
+ function: currentFunction,
1593
+ variables: { ...variables },
1594
+ callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })),
1595
+ visualization: {
1596
+ objectKinds: { [objectState.variable]: "object" },
1597
+ hashMaps: [objectState.visualization]
1598
+ }
1599
+ }, pendingAccesses);
1600
+ continue;
1601
+ }
1602
+ const objectField = parseObjectFieldEvent(payload);
1603
+ if (objectField) {
1604
+ variables[objectField.variable] = { __ref__: `${objectField.variable}-object` };
1605
+ const currentCallStack = stack.length > 0 ? stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })) : void 0;
1606
+ if (mergeIntoPreviousMatchingLineStep(trace, line, currentFunction, currentCallStack, {
1607
+ variables: { ...variables },
1608
+ accesses: void 0,
1609
+ visualization: buildFieldVisualization(objectField)
1610
+ })) {
1611
+ continue;
1612
+ }
1613
+ appendJavaTraceStep(trace, {
1614
+ line,
1615
+ event: "line",
1616
+ function: currentFunction,
1617
+ variables: { ...variables },
1618
+ callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })),
1619
+ visualization: buildFieldVisualization(objectField)
1620
+ }, pendingAccesses);
1621
+ continue;
1622
+ }
1623
+ Object.assign(variables, parseKeyValuePairs(payload));
1624
+ const accesses = parseAccessEvent(payload);
1625
+ if (accesses) {
1626
+ const currentCallStack = stack.length > 0 ? stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })) : void 0;
1627
+ if (mergeAccessesIntoPreviousMatchingLineStep(trace, line, currentFunction, currentCallStack, accesses)) {
1628
+ continue;
1629
+ }
1630
+ pendingAccesses.push(...accesses);
1631
+ continue;
1632
+ }
1633
+ appendJavaTraceStep(trace, {
1634
+ line,
1635
+ event: "line",
1636
+ function: currentFunction,
1637
+ variables: { ...variables },
1638
+ ...stack.length > 0 ? { callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })) } : {}
1639
+ }, pendingAccesses);
1640
+ }
1641
+ if (pendingAccesses.length > 0 && trace.length > 0) {
1642
+ const last = trace[trace.length - 1];
1643
+ last.accesses = [...last.accesses ?? [], ...pendingAccesses];
1644
+ }
1645
+ return trace;
1646
+ }
1647
+ function buildJavaExecutionResult(output, events, executionTimeMs = 0, traceLimitExceeded, timeoutReason, maxTraceSteps, sourceText) {
1648
+ const trace = eventsToRawTrace(events, sourceText);
1649
+ return {
1650
+ success: true,
1651
+ output,
1652
+ trace,
1653
+ executionTimeMs,
1654
+ consoleOutput: [],
1655
+ ...traceLimitExceeded !== void 0 ? { traceLimitExceeded } : {},
1656
+ ...maxTraceSteps !== void 0 ? { maxTraceSteps } : {},
1657
+ ...timeoutReason ? { timeoutReason } : {},
1658
+ lineEventCount: trace.filter((step) => step.event === "line").length,
1659
+ traceStepCount: trace.length
1660
+ };
1661
+ }
1662
+ function adaptJavaTraceExecutionResult(result) {
1663
+ return adaptTraceExecutionResult("java", result);
1664
+ }
1665
+
1666
+ // packages/harness-browser/src/java-runtime-client.ts
1667
+ var JavaRuntimeClient = class {
1668
+ constructor(workerClient) {
1669
+ this.workerClient = workerClient;
1670
+ }
1671
+ async init() {
1672
+ return this.workerClient.init();
1673
+ }
1674
+ async executeWithTracing(code, functionName, inputs, options, executionStyle = "function") {
1675
+ assertRuntimeRequestSupported(getLanguageRuntimeProfile("java"), {
1676
+ request: "trace",
1677
+ executionStyle,
1678
+ functionName
1679
+ });
1680
+ const rawResult = await this.workerClient.executeWithTracing(
1681
+ code,
1682
+ functionName ?? "",
1683
+ inputs,
1684
+ options,
1685
+ executionStyle
1686
+ );
1687
+ if (!rawResult.success) {
1688
+ return {
1689
+ success: false,
1690
+ error: rawResult.error ?? "Java tracing failed",
1691
+ ...rawResult.errorLine !== void 0 ? { errorLine: rawResult.errorLine } : {},
1692
+ trace: [],
1693
+ executionTimeMs: rawResult.executionTimeMs,
1694
+ consoleOutput: rawResult.consoleOutput,
1695
+ ...rawResult.traceLimitExceeded !== void 0 ? { traceLimitExceeded: rawResult.traceLimitExceeded } : {},
1696
+ ...rawResult.timeoutReason ? { timeoutReason: rawResult.timeoutReason } : {},
1697
+ lineEventCount: 0,
1698
+ traceStepCount: 0
1699
+ };
1700
+ }
1701
+ const adapted = adaptJavaTraceExecutionResult(
1702
+ buildJavaExecutionResult(
1703
+ rawResult.output,
1704
+ rawResult.events,
1705
+ rawResult.executionTimeMs,
1706
+ rawResult.traceLimitExceeded,
1707
+ rawResult.timeoutReason,
1708
+ void 0,
1709
+ rawResult.sourceText
1710
+ )
1711
+ );
1712
+ return {
1713
+ ...adapted,
1714
+ consoleOutput: rawResult.consoleOutput,
1715
+ executionTimeMs: rawResult.executionTimeMs
1716
+ };
1717
+ }
1718
+ async executeCode(code, functionName, inputs, executionStyle = "function") {
1719
+ assertRuntimeRequestSupported(getLanguageRuntimeProfile("java"), {
1720
+ request: "execute",
1721
+ executionStyle,
1722
+ functionName
1723
+ });
1724
+ return this.workerClient.executeCode(
1725
+ code,
1726
+ functionName,
1727
+ inputs,
1728
+ void 0,
1729
+ executionStyle
1730
+ );
1731
+ }
1732
+ async executeCodeInterviewMode(code, functionName, inputs, executionStyle = "function") {
1733
+ assertRuntimeRequestSupported(getLanguageRuntimeProfile("java"), {
1734
+ request: "interview",
1735
+ executionStyle,
1736
+ functionName
1737
+ });
1738
+ return this.workerClient.executeCodeInterviewMode(
1739
+ code,
1740
+ functionName,
1741
+ inputs,
1742
+ void 0,
1743
+ executionStyle
1744
+ );
1745
+ }
1746
+ };
1747
+ function createJavaRuntimeClient(workerClient) {
1748
+ return new JavaRuntimeClient(workerClient);
1749
+ }
1750
+
809
1751
  // packages/harness-browser/src/pyodide-worker-client.ts
810
1752
  var EXECUTION_TIMEOUT_MS2 = 1e4;
811
1753
  var INTERVIEW_MODE_TIMEOUT_MS2 = 5e3;
812
- var TRACING_TIMEOUT_MS2 = 3e4;
813
- var INIT_TIMEOUT_MS2 = 12e4;
814
- var MESSAGE_TIMEOUT_MS2 = 2e4;
815
- var WORKER_READY_TIMEOUT_MS2 = 1e4;
1754
+ var TRACING_TIMEOUT_MS3 = 3e4;
1755
+ var INIT_TIMEOUT_MS3 = 12e4;
1756
+ var MESSAGE_TIMEOUT_MS3 = 2e4;
1757
+ var WORKER_READY_TIMEOUT_MS3 = 1e4;
816
1758
  var PyodideWorkerClient = class {
817
1759
  constructor(options) {
818
1760
  this.options = options;
@@ -902,14 +1844,14 @@ var PyodideWorkerClient = class {
902
1844
  if (settled) return;
903
1845
  settled = true;
904
1846
  const timeoutError = new Error(
905
- `Python worker failed to initialize in time (${Math.round(WORKER_READY_TIMEOUT_MS2 / 1e3)}s)`
1847
+ `Python worker failed to initialize in time (${Math.round(WORKER_READY_TIMEOUT_MS3 / 1e3)}s)`
906
1848
  );
907
1849
  if (this.debug) {
908
- console.warn("[PyodideWorkerClient] worker-ready timeout", { timeoutMs: WORKER_READY_TIMEOUT_MS2 });
1850
+ console.warn("[PyodideWorkerClient] worker-ready timeout", { timeoutMs: WORKER_READY_TIMEOUT_MS3 });
909
1851
  }
910
1852
  this.terminateAndReset(timeoutError);
911
1853
  reject(timeoutError);
912
- }, WORKER_READY_TIMEOUT_MS2);
1854
+ }, WORKER_READY_TIMEOUT_MS3);
913
1855
  readyPromise.then(() => {
914
1856
  if (settled) return;
915
1857
  settled = true;
@@ -926,7 +1868,7 @@ var PyodideWorkerClient = class {
926
1868
  /**
927
1869
  * Send a message to the worker and wait for a response
928
1870
  */
929
- async sendMessage(type, payload, timeoutMs = MESSAGE_TIMEOUT_MS2) {
1871
+ async sendMessage(type, payload, timeoutMs = MESSAGE_TIMEOUT_MS3) {
930
1872
  const worker = this.getWorker();
931
1873
  await this.waitForWorkerReady();
932
1874
  const id = String(++this.messageId);
@@ -1010,7 +1952,7 @@ var PyodideWorkerClient = class {
1010
1952
  this.isInitializing = true;
1011
1953
  this.initPromise = (async () => {
1012
1954
  try {
1013
- return await this.sendMessage("init", void 0, INIT_TIMEOUT_MS2);
1955
+ return await this.sendMessage("init", void 0, INIT_TIMEOUT_MS3);
1014
1956
  } catch (error) {
1015
1957
  const message = error instanceof Error ? error.message : String(error);
1016
1958
  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");
@@ -1021,7 +1963,7 @@ var PyodideWorkerClient = class {
1021
1963
  console.warn("[PyodideWorkerClient] init failed, resetting worker and retrying once", { message });
1022
1964
  }
1023
1965
  this.terminateAndReset();
1024
- return this.sendMessage("init", void 0, INIT_TIMEOUT_MS2);
1966
+ return this.sendMessage("init", void 0, INIT_TIMEOUT_MS3);
1025
1967
  }
1026
1968
  })();
1027
1969
  try {
@@ -1048,9 +1990,9 @@ var PyodideWorkerClient = class {
1048
1990
  inputs,
1049
1991
  executionStyle,
1050
1992
  options
1051
- }, TRACING_TIMEOUT_MS2 + 5e3),
1993
+ }, TRACING_TIMEOUT_MS3 + 5e3),
1052
1994
  // Message timeout slightly longer than execution timeout
1053
- TRACING_TIMEOUT_MS2
1995
+ TRACING_TIMEOUT_MS3
1054
1996
  );
1055
1997
  } catch (error) {
1056
1998
  const errorMessage = error instanceof Error ? error.message : String(error);
@@ -1060,7 +2002,7 @@ var PyodideWorkerClient = class {
1060
2002
  success: false,
1061
2003
  error: errorMessage,
1062
2004
  trace: [],
1063
- executionTimeMs: TRACING_TIMEOUT_MS2,
2005
+ executionTimeMs: TRACING_TIMEOUT_MS3,
1064
2006
  consoleOutput: [],
1065
2007
  traceLimitExceeded: true,
1066
2008
  timeoutReason: "client-timeout",
@@ -1221,6 +2163,7 @@ var DEFAULT_BROWSER_HARNESS_ASSET_RELATIVE_PATHS = Object.freeze({
1221
2163
  pythonRuntimeCore: "pyodide/runtime-core.js",
1222
2164
  pythonSnippets: "generated-python-harness-snippets.js",
1223
2165
  javascriptWorker: "javascript-worker.js",
2166
+ javaWorker: "java-worker.js",
1224
2167
  typescriptCompiler: "vendor/typescript.js"
1225
2168
  });
1226
2169
  function isExplicitAssetPath(pathname) {
@@ -1254,6 +2197,7 @@ function resolveBrowserHarnessAssets(options = {}) {
1254
2197
  assetBaseUrl,
1255
2198
  assets.javascriptWorker ?? DEFAULT_BROWSER_HARNESS_ASSET_RELATIVE_PATHS.javascriptWorker
1256
2199
  ),
2200
+ javaWorker: resolveAssetPath(assetBaseUrl, assets.javaWorker ?? DEFAULT_BROWSER_HARNESS_ASSET_RELATIVE_PATHS.javaWorker),
1257
2201
  typescriptCompiler: resolveAssetPath(
1258
2202
  assetBaseUrl,
1259
2203
  assets.typescriptCompiler ?? DEFAULT_BROWSER_HARNESS_ASSET_RELATIVE_PATHS.typescriptCompiler
@@ -1267,6 +2211,7 @@ var BrowserHarnessRuntime = class {
1267
2211
  supportedLanguages = SUPPORTED_LANGUAGES;
1268
2212
  pythonWorkerClient;
1269
2213
  javaScriptWorkerClient;
2214
+ javaWorkerClient;
1270
2215
  clients;
1271
2216
  constructor(options = {}) {
1272
2217
  this.assets = resolveBrowserHarnessAssets(options);
@@ -1278,10 +2223,15 @@ var BrowserHarnessRuntime = class {
1278
2223
  workerUrl: this.assets.javascriptWorker,
1279
2224
  debug: options.debug
1280
2225
  });
2226
+ this.javaWorkerClient = new JavaWorkerClient({
2227
+ workerUrl: this.assets.javaWorker,
2228
+ debug: options.debug
2229
+ });
1281
2230
  this.clients = {
1282
2231
  python: createPythonRuntimeClient(this.pythonWorkerClient),
1283
2232
  javascript: createJavaScriptRuntimeClient("javascript", this.javaScriptWorkerClient),
1284
- typescript: createJavaScriptRuntimeClient("typescript", this.javaScriptWorkerClient)
2233
+ typescript: createJavaScriptRuntimeClient("typescript", this.javaScriptWorkerClient),
2234
+ java: createJavaRuntimeClient(this.javaWorkerClient)
1285
2235
  };
1286
2236
  }
1287
2237
  getClient(language) {
@@ -1305,11 +2255,16 @@ var BrowserHarnessRuntime = class {
1305
2255
  this.pythonWorkerClient.terminate();
1306
2256
  return;
1307
2257
  }
2258
+ if (language === "java") {
2259
+ this.javaWorkerClient.terminate();
2260
+ return;
2261
+ }
1308
2262
  this.javaScriptWorkerClient.terminate();
1309
2263
  }
1310
2264
  dispose() {
1311
2265
  this.pythonWorkerClient.terminate();
1312
2266
  this.javaScriptWorkerClient.terminate();
2267
+ this.javaWorkerClient.terminate();
1313
2268
  }
1314
2269
  };
1315
2270
  function createBrowserHarness(options = {}) {