@tracecode/harness 0.5.0 → 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 (60) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/LICENSE +67 -80
  3. package/README.md +31 -4
  4. package/dist/browser.cjs +974 -19
  5. package/dist/browser.cjs.map +1 -1
  6. package/dist/browser.d.cts +3 -2
  7. package/dist/browser.d.ts +3 -2
  8. package/dist/browser.js +974 -19
  9. package/dist/browser.js.map +1 -1
  10. package/dist/cli.cjs +24 -0
  11. package/dist/cli.cjs.map +1 -1
  12. package/dist/cli.js +24 -0
  13. package/dist/cli.js.map +1 -1
  14. package/dist/core.cjs +611 -4
  15. package/dist/core.cjs.map +1 -1
  16. package/dist/core.d.cts +20 -6
  17. package/dist/core.d.ts +20 -6
  18. package/dist/core.js +605 -4
  19. package/dist/core.js.map +1 -1
  20. package/dist/index.cjs +1055 -52
  21. package/dist/index.cjs.map +1 -1
  22. package/dist/index.d.cts +3 -3
  23. package/dist/index.d.ts +3 -3
  24. package/dist/index.js +1049 -52
  25. package/dist/index.js.map +1 -1
  26. package/dist/internal/browser.cjs +211 -0
  27. package/dist/internal/browser.cjs.map +1 -1
  28. package/dist/internal/browser.d.cts +62 -6
  29. package/dist/internal/browser.d.ts +62 -6
  30. package/dist/internal/browser.js +210 -0
  31. package/dist/internal/browser.js.map +1 -1
  32. package/dist/javascript.cjs +37 -19
  33. package/dist/javascript.cjs.map +1 -1
  34. package/dist/javascript.d.cts +2 -2
  35. package/dist/javascript.d.ts +2 -2
  36. package/dist/javascript.js +37 -19
  37. package/dist/javascript.js.map +1 -1
  38. package/dist/python.cjs +14 -14
  39. package/dist/python.cjs.map +1 -1
  40. package/dist/python.d.cts +8 -8
  41. package/dist/python.d.ts +8 -8
  42. package/dist/python.js +14 -14
  43. package/dist/python.js.map +1 -1
  44. package/dist/{runtime-types-DtaaAhHL.d.ts → runtime-types-89nchXlY.d.cts} +8 -4
  45. package/dist/{runtime-types--lBQ6rYu.d.cts → runtime-types-CCQ-ZLc9.d.ts} +8 -4
  46. package/dist/{types-DwIYM3Ku.d.cts → types-zyvpJKCi.d.cts} +1 -0
  47. package/dist/{types-DwIYM3Ku.d.ts → types-zyvpJKCi.d.ts} +1 -0
  48. package/package.json +12 -6
  49. package/workers/java/.build/classes/harness/browser/JavaRewriteLibrary.class +0 -0
  50. package/workers/java/java-worker.js +712 -0
  51. package/workers/java/src/harness/browser/JavaRewriteLibrary.java +54 -0
  52. package/workers/javascript/javascript-worker.js +343 -63
  53. package/workers/python/generated-python-harness-snippets.js +3 -3
  54. package/workers/python/pyodide-worker.js +419 -68
  55. package/workers/python/runtime-core.js +52 -3
  56. package/workers/vendor/java-browser-spike-helper.jar +0 -0
  57. package/workers/vendor/java-practice-rewriter.jar +0 -0
  58. package/workers/vendor/java-rewrite-bridge.jar +0 -0
  59. package/workers/vendor/javaparser-core-3.25.10.jar +0 -0
  60. package/workers/vendor/jdk.compiler-17.jar +0 -0
package/dist/browser.cjs CHANGED
@@ -289,7 +289,7 @@ var JavaScriptWorkerClient = class {
289
289
  };
290
290
 
291
291
  // packages/harness-core/src/trace-contract.ts
292
- var RUNTIME_TRACE_CONTRACT_SCHEMA_VERSION = "2026-03-13";
292
+ var RUNTIME_TRACE_CONTRACT_SCHEMA_VERSION = "2026-04-21";
293
293
  var TRACE_EVENTS = /* @__PURE__ */ new Set([
294
294
  "line",
295
295
  "call",
@@ -410,7 +410,39 @@ function normalizeAccesses(accesses) {
410
410
  }
411
411
  return payload;
412
412
  }).filter((access) => access !== null);
413
- return normalized.length > 0 ? normalized : void 0;
413
+ if (normalized.length === 0) {
414
+ return void 0;
415
+ }
416
+ const statsByVariable = /* @__PURE__ */ new Map();
417
+ for (const access of normalized) {
418
+ const stats = statsByVariable.get(access.variable) ?? { hasCellRead: false, hasCellWrite: false };
419
+ if (access.kind === "cell-read") stats.hasCellRead = true;
420
+ if (access.kind === "cell-write") stats.hasCellWrite = true;
421
+ statsByVariable.set(access.variable, stats);
422
+ }
423
+ const deduped = /* @__PURE__ */ new Set();
424
+ const collapsed = normalized.filter((access) => {
425
+ const stats = statsByVariable.get(access.variable);
426
+ if (access.kind === "indexed-read" && (stats?.hasCellRead || stats?.hasCellWrite)) {
427
+ return false;
428
+ }
429
+ if (access.kind === "indexed-write" && stats?.hasCellWrite) {
430
+ return false;
431
+ }
432
+ const key = JSON.stringify([
433
+ access.variable,
434
+ access.kind,
435
+ access.indices ?? null,
436
+ access.pathDepth ?? null,
437
+ access.method ?? null
438
+ ]);
439
+ if (deduped.has(key)) {
440
+ return false;
441
+ }
442
+ deduped.add(key);
443
+ return true;
444
+ });
445
+ return collapsed.length > 0 ? collapsed : void 0;
414
446
  }
415
447
  function normalizeRecord(value) {
416
448
  if (!value || typeof value !== "object" || Array.isArray(value)) return {};
@@ -474,8 +506,64 @@ function normalizeTraceStep(step) {
474
506
  ...normalizedVisualization ? { visualization: normalizedVisualization } : {}
475
507
  };
476
508
  }
509
+ function collapseTraceAccessNoise(trace) {
510
+ const variablesWithCellAccess = /* @__PURE__ */ new Set();
511
+ const accessStatsByVariable = /* @__PURE__ */ new Map();
512
+ for (const step of trace) {
513
+ for (const access of step.accesses ?? []) {
514
+ const stats = accessStatsByVariable.get(access.variable) ?? {
515
+ hasCellRead: false,
516
+ hasCellWrite: false,
517
+ hasMutatingCall: false,
518
+ hasIndexedWrite: false
519
+ };
520
+ if (access.kind === "cell-read" || access.kind === "cell-write") {
521
+ variablesWithCellAccess.add(access.variable);
522
+ }
523
+ if (access.kind === "cell-read") stats.hasCellRead = true;
524
+ if (access.kind === "cell-write") stats.hasCellWrite = true;
525
+ if (access.kind === "mutating-call") stats.hasMutatingCall = true;
526
+ if (access.kind === "indexed-write") stats.hasIndexedWrite = true;
527
+ accessStatsByVariable.set(access.variable, stats);
528
+ }
529
+ }
530
+ if (variablesWithCellAccess.size === 0) {
531
+ return trace;
532
+ }
533
+ return trace.map((step) => {
534
+ if (!step.accesses?.length) {
535
+ return step;
536
+ }
537
+ const filtered = step.accesses.filter((access) => {
538
+ const stats = accessStatsByVariable.get(access.variable);
539
+ if (variablesWithCellAccess.has(access.variable)) {
540
+ return access.kind !== "indexed-read" && access.kind !== "indexed-write";
541
+ }
542
+ if (access.kind === "mutating-call" && stats?.hasIndexedWrite && !stats.hasCellRead && !stats.hasCellWrite) {
543
+ return false;
544
+ }
545
+ if (access.kind === "indexed-read" && stats?.hasMutatingCall && !stats.hasIndexedWrite && !stats.hasCellRead && !stats.hasCellWrite) {
546
+ return false;
547
+ }
548
+ return true;
549
+ });
550
+ if (filtered.length === step.accesses.length) {
551
+ return step;
552
+ }
553
+ return {
554
+ ...step,
555
+ ...filtered.length > 0 ? { accesses: filtered } : {},
556
+ ...filtered.length === 0 ? { accesses: void 0 } : {}
557
+ };
558
+ });
559
+ }
477
560
  function normalizeRuntimeTraceContract(language, result) {
478
- const normalizedTrace = Array.isArray(result.trace) ? result.trace.map(normalizeTraceStep) : [];
561
+ const rawNormalizedTrace = collapseTraceAccessNoise(
562
+ Array.isArray(result.trace) ? result.trace.map(normalizeTraceStep) : []
563
+ );
564
+ const maxTraceSteps = typeof result.maxTraceSteps === "number" && Number.isFinite(result.maxTraceSteps) ? Math.max(1, Math.floor(result.maxTraceSteps)) : void 0;
565
+ const traceWasClipped = maxTraceSteps !== void 0 && rawNormalizedTrace.length > maxTraceSteps;
566
+ const normalizedTrace = traceWasClipped && maxTraceSteps !== void 0 ? rawNormalizedTrace.slice(0, maxTraceSteps) : rawNormalizedTrace;
479
567
  const lineEventCount = typeof result.lineEventCount === "number" && Number.isFinite(result.lineEventCount) ? Math.floor(result.lineEventCount) : normalizedTrace.filter((step) => step.event === "line").length;
480
568
  const normalizedConsole = Array.isArray(result.consoleOutput) ? result.consoleOutput.map((line) => String(line)) : [];
481
569
  return {
@@ -487,7 +575,7 @@ function normalizeRuntimeTraceContract(language, result) {
487
575
  ...typeof result.errorLine === "number" && Number.isFinite(result.errorLine) ? { errorLine: Math.floor(result.errorLine) } : {},
488
576
  consoleOutput: normalizedConsole,
489
577
  trace: normalizedTrace,
490
- ...result.traceLimitExceeded !== void 0 ? { traceLimitExceeded: Boolean(result.traceLimitExceeded) } : {},
578
+ ...result.traceLimitExceeded !== void 0 || traceWasClipped ? { traceLimitExceeded: Boolean(result.traceLimitExceeded) || traceWasClipped } : {},
491
579
  ...typeof result.timeoutReason === "string" && result.timeoutReason.length > 0 ? { timeoutReason: result.timeoutReason } : {},
492
580
  lineEventCount: Math.max(0, lineEventCount),
493
581
  traceStepCount: normalizedTrace.length
@@ -608,6 +696,7 @@ var PYTHON_RUNTIME_PROFILE = {
608
696
  maxTraceSteps: true,
609
697
  maxLineEvents: true,
610
698
  maxSingleLineHits: true,
699
+ maxStoredEvents: true,
611
700
  minimalTrace: true
612
701
  },
613
702
  fidelity: {
@@ -669,6 +758,7 @@ var JAVASCRIPT_RUNTIME_PROFILE = {
669
758
  maxTraceSteps: true,
670
759
  maxLineEvents: true,
671
760
  maxSingleLineHits: true,
761
+ maxStoredEvents: true,
672
762
  minimalTrace: true
673
763
  },
674
764
  fidelity: {
@@ -730,6 +820,7 @@ var TYPESCRIPT_RUNTIME_PROFILE = {
730
820
  maxTraceSteps: true,
731
821
  maxLineEvents: true,
732
822
  maxSingleLineHits: true,
823
+ maxStoredEvents: true,
733
824
  minimalTrace: true
734
825
  },
735
826
  fidelity: {
@@ -760,10 +851,78 @@ var TYPESCRIPT_RUNTIME_PROFILE = {
760
851
  }
761
852
  }
762
853
  };
854
+ var JAVA_RUNTIME_PROFILE = {
855
+ language: "java",
856
+ maturity: "experimental",
857
+ capabilities: {
858
+ execution: {
859
+ styles: {
860
+ function: true,
861
+ solutionMethod: true,
862
+ opsClass: true,
863
+ script: false,
864
+ interviewMode: true
865
+ },
866
+ timeouts: {
867
+ clientTimeouts: true,
868
+ runtimeTimeouts: true
869
+ }
870
+ },
871
+ tracing: {
872
+ supported: true,
873
+ events: {
874
+ line: true,
875
+ call: true,
876
+ return: true,
877
+ exception: true,
878
+ stdout: false,
879
+ timeout: true
880
+ },
881
+ controls: {
882
+ maxTraceSteps: true,
883
+ maxLineEvents: false,
884
+ maxSingleLineHits: false,
885
+ maxStoredEvents: true,
886
+ minimalTrace: false
887
+ },
888
+ fidelity: {
889
+ preciseLineMapping: true,
890
+ stableFunctionNames: true,
891
+ callStack: true
892
+ }
893
+ },
894
+ diagnostics: {
895
+ compileErrors: true,
896
+ runtimeErrors: true,
897
+ mappedErrorLines: false,
898
+ stackTraces: true
899
+ },
900
+ structures: {
901
+ treeNodeRefs: true,
902
+ listNodeRefs: true,
903
+ mapSerialization: true,
904
+ setSerialization: true,
905
+ graphSerialization: false,
906
+ cycleReferences: true
907
+ },
908
+ visualization: {
909
+ runtimePayloads: true,
910
+ objectKinds: true,
911
+ hashMaps: true,
912
+ stepVisualization: true
913
+ }
914
+ },
915
+ notes: [
916
+ "Java currently supports the browser-local Java 17 lane for function, solution-method, and ops-class execution.",
917
+ "Interview-mode Java reuses the same browser-local execution path and remains experimental in the first harness slice.",
918
+ "Script-style Java is not enabled yet."
919
+ ]
920
+ };
763
921
  var LANGUAGE_RUNTIME_PROFILES = {
764
922
  python: PYTHON_RUNTIME_PROFILE,
765
923
  javascript: JAVASCRIPT_RUNTIME_PROFILE,
766
- typescript: TYPESCRIPT_RUNTIME_PROFILE
924
+ typescript: TYPESCRIPT_RUNTIME_PROFILE,
925
+ java: JAVA_RUNTIME_PROFILE
767
926
  };
768
927
  var SUPPORTED_LANGUAGES = Object.freeze(
769
928
  Object.keys(LANGUAGE_RUNTIME_PROFILES)
@@ -840,13 +999,796 @@ function createJavaScriptRuntimeClient(runtimeLanguage, workerClient) {
840
999
  return new JavaScriptRuntimeClient(runtimeLanguage, workerClient);
841
1000
  }
842
1001
 
1002
+ // packages/harness-browser/src/java-worker-client.ts
1003
+ var TRACING_TIMEOUT_MS2 = 25e3;
1004
+ var INIT_TIMEOUT_MS2 = 25e3;
1005
+ var MESSAGE_TIMEOUT_MS2 = 3e4;
1006
+ var WORKER_READY_TIMEOUT_MS2 = 1e4;
1007
+ var JavaWorkerClient = class {
1008
+ constructor(options) {
1009
+ this.options = options;
1010
+ this.debug = options.debug ?? process.env.NODE_ENV === "development";
1011
+ }
1012
+ worker = null;
1013
+ pendingMessages = /* @__PURE__ */ new Map();
1014
+ messageId = 0;
1015
+ isInitializing = false;
1016
+ initPromise = null;
1017
+ workerReadyPromise = null;
1018
+ workerReadyResolve = null;
1019
+ workerReadyReject = null;
1020
+ debug;
1021
+ isSupported() {
1022
+ return typeof Worker !== "undefined";
1023
+ }
1024
+ getWorker() {
1025
+ if (this.worker) return this.worker;
1026
+ if (!this.isSupported()) {
1027
+ throw new Error("Web Workers are not supported in this environment");
1028
+ }
1029
+ this.workerReadyPromise = new Promise((resolve, reject) => {
1030
+ this.workerReadyResolve = resolve;
1031
+ this.workerReadyReject = (error) => reject(error);
1032
+ });
1033
+ const workerUrl = this.debug && !this.options.workerUrl.includes("?") ? `${this.options.workerUrl}?dev=${Date.now()}` : this.options.workerUrl;
1034
+ this.worker = new Worker(workerUrl);
1035
+ this.worker.onmessage = (event) => {
1036
+ const { id, type, payload } = event.data;
1037
+ if (type === "worker-ready") {
1038
+ this.workerReadyResolve?.();
1039
+ this.workerReadyResolve = null;
1040
+ this.workerReadyReject = null;
1041
+ return;
1042
+ }
1043
+ if (!id) return;
1044
+ const pending = this.pendingMessages.get(id);
1045
+ if (!pending) return;
1046
+ this.pendingMessages.delete(id);
1047
+ if (pending.timeoutId) globalThis.clearTimeout(pending.timeoutId);
1048
+ if (type === "error") {
1049
+ pending.reject(new Error(payload.error));
1050
+ return;
1051
+ }
1052
+ pending.resolve(payload);
1053
+ };
1054
+ this.worker.onerror = (error) => {
1055
+ const workerError = new Error(error.message || "Java worker error");
1056
+ this.workerReadyReject?.(workerError);
1057
+ this.workerReadyResolve = null;
1058
+ this.workerReadyReject = null;
1059
+ for (const [, pending] of this.pendingMessages) {
1060
+ if (pending.timeoutId) globalThis.clearTimeout(pending.timeoutId);
1061
+ pending.reject(workerError);
1062
+ }
1063
+ this.pendingMessages.clear();
1064
+ this.terminateAndReset(workerError);
1065
+ };
1066
+ return this.worker;
1067
+ }
1068
+ async waitForWorkerReady() {
1069
+ const readyPromise = this.workerReadyPromise;
1070
+ if (!readyPromise) return;
1071
+ await new Promise((resolve, reject) => {
1072
+ let settled = false;
1073
+ const timeoutId = globalThis.setTimeout(() => {
1074
+ if (settled) return;
1075
+ settled = true;
1076
+ const timeoutError = new Error(
1077
+ `Java worker failed to initialize in time (${Math.round(WORKER_READY_TIMEOUT_MS2 / 1e3)}s)`
1078
+ );
1079
+ this.terminateAndReset(timeoutError);
1080
+ reject(timeoutError);
1081
+ }, WORKER_READY_TIMEOUT_MS2);
1082
+ readyPromise.then(() => {
1083
+ if (settled) return;
1084
+ settled = true;
1085
+ globalThis.clearTimeout(timeoutId);
1086
+ resolve();
1087
+ }).catch((error) => {
1088
+ if (settled) return;
1089
+ settled = true;
1090
+ globalThis.clearTimeout(timeoutId);
1091
+ reject(error instanceof Error ? error : new Error(String(error)));
1092
+ });
1093
+ });
1094
+ }
1095
+ async sendMessage(type, payload, timeoutMs = MESSAGE_TIMEOUT_MS2) {
1096
+ const worker = this.getWorker();
1097
+ await this.waitForWorkerReady();
1098
+ const id = String(++this.messageId);
1099
+ return new Promise((resolve, reject) => {
1100
+ this.pendingMessages.set(id, {
1101
+ resolve,
1102
+ reject
1103
+ });
1104
+ const timeoutId = globalThis.setTimeout(() => {
1105
+ const pending2 = this.pendingMessages.get(id);
1106
+ if (!pending2) return;
1107
+ this.pendingMessages.delete(id);
1108
+ pending2.reject(new Error(`Worker request timed out: ${type}`));
1109
+ }, timeoutMs);
1110
+ const pending = this.pendingMessages.get(id);
1111
+ if (pending) pending.timeoutId = timeoutId;
1112
+ worker.postMessage({ id, type, payload });
1113
+ });
1114
+ }
1115
+ async executeWithTimeout(executor, timeoutMs) {
1116
+ return new Promise((resolve, reject) => {
1117
+ let settled = false;
1118
+ const timeoutId = globalThis.setTimeout(() => {
1119
+ if (settled) return;
1120
+ settled = true;
1121
+ this.terminateAndReset();
1122
+ reject(
1123
+ new Error(
1124
+ `Java execution timed out after ${Math.round(timeoutMs / 1e3)} seconds.`
1125
+ )
1126
+ );
1127
+ }, timeoutMs);
1128
+ executor().then((result) => {
1129
+ if (settled) return;
1130
+ settled = true;
1131
+ globalThis.clearTimeout(timeoutId);
1132
+ resolve(result);
1133
+ }).catch((error) => {
1134
+ if (settled) return;
1135
+ settled = true;
1136
+ globalThis.clearTimeout(timeoutId);
1137
+ reject(error);
1138
+ });
1139
+ });
1140
+ }
1141
+ terminateAndReset(reason = new Error("Worker was terminated")) {
1142
+ this.workerReadyReject?.(reason);
1143
+ if (this.worker) {
1144
+ this.worker.terminate();
1145
+ this.worker = null;
1146
+ }
1147
+ this.initPromise = null;
1148
+ this.isInitializing = false;
1149
+ this.workerReadyPromise = null;
1150
+ this.workerReadyResolve = null;
1151
+ this.workerReadyReject = null;
1152
+ for (const [, pending] of this.pendingMessages) {
1153
+ if (pending.timeoutId) globalThis.clearTimeout(pending.timeoutId);
1154
+ pending.reject(reason);
1155
+ }
1156
+ this.pendingMessages.clear();
1157
+ }
1158
+ async init() {
1159
+ if (this.initPromise) return this.initPromise;
1160
+ if (this.isInitializing) {
1161
+ await new Promise((resolve) => globalThis.setTimeout(resolve, 100));
1162
+ return this.init();
1163
+ }
1164
+ this.isInitializing = true;
1165
+ this.initPromise = this.sendMessage("init", void 0, INIT_TIMEOUT_MS2);
1166
+ try {
1167
+ return await this.initPromise;
1168
+ } catch (error) {
1169
+ this.initPromise = null;
1170
+ throw error;
1171
+ } finally {
1172
+ this.isInitializing = false;
1173
+ }
1174
+ }
1175
+ async executeWithTracing(code, functionName, inputs, options, executionStyle) {
1176
+ await this.init();
1177
+ return this.executeWithTimeout(
1178
+ () => this.sendMessage(
1179
+ "execute-with-tracing",
1180
+ { code, functionName, inputs, options, executionStyle },
1181
+ TRACING_TIMEOUT_MS2 + 5e3
1182
+ ),
1183
+ TRACING_TIMEOUT_MS2
1184
+ );
1185
+ }
1186
+ async executeCode(code, functionName, inputs, options, executionStyle) {
1187
+ const result = await this.executeWithTracing(code, functionName, inputs, options, executionStyle);
1188
+ if (!result.success) {
1189
+ return {
1190
+ success: false,
1191
+ output: null,
1192
+ error: result.error ?? "Java execution failed",
1193
+ ...result.errorLine !== void 0 ? { errorLine: result.errorLine } : {},
1194
+ consoleOutput: result.consoleOutput
1195
+ };
1196
+ }
1197
+ return {
1198
+ success: true,
1199
+ output: result.output,
1200
+ consoleOutput: result.consoleOutput
1201
+ };
1202
+ }
1203
+ async executeCodeInterviewMode(code, functionName, inputs, options, executionStyle) {
1204
+ return this.executeCode(code, functionName, inputs, options, executionStyle);
1205
+ }
1206
+ terminate() {
1207
+ this.terminateAndReset();
1208
+ }
1209
+ };
1210
+
1211
+ // packages/harness-core/src/trace-adapters/java.ts
1212
+ function parseScalar(raw) {
1213
+ if (raw === "null") return null;
1214
+ if (raw === "true") return true;
1215
+ if (raw === "false") return false;
1216
+ if (/^-?\d+$/.test(raw)) return Number.parseInt(raw, 10);
1217
+ if (/^-?\d+\.\d+$/.test(raw)) return Number.parseFloat(raw);
1218
+ if (raw.startsWith('"') && raw.endsWith('"') || raw.startsWith("[") && raw.endsWith("]") || raw.startsWith("{") && raw.endsWith("}")) {
1219
+ try {
1220
+ return JSON.parse(raw);
1221
+ } catch {
1222
+ }
1223
+ }
1224
+ return raw;
1225
+ }
1226
+ function parseKeyValuePairs(fragment) {
1227
+ const variables = {};
1228
+ const matches = Array.from(fragment.matchAll(/\b([A-Za-z_][A-Za-z0-9_.]*)=/g));
1229
+ for (let index = 0; index < matches.length; index += 1) {
1230
+ const match = matches[index];
1231
+ const rawKey = match[1];
1232
+ const valueStart = (match.index ?? 0) + match[0].length;
1233
+ const valueEnd = index + 1 < matches.length ? matches[index + 1].index ?? fragment.length : fragment.length;
1234
+ const rawValue = fragment.slice(valueStart, valueEnd).trim();
1235
+ if (!rawKey || rawValue === void 0) continue;
1236
+ if (rawKey === "method") continue;
1237
+ variables[rawKey.replaceAll(".", "_")] = parseScalar(rawValue);
1238
+ }
1239
+ return variables;
1240
+ }
1241
+ function extractLineMetadata(event) {
1242
+ const match = event.match(/^line=(\d+)(?:\s+(.*))?$/);
1243
+ if (!match) {
1244
+ return { line: 1, payload: event };
1245
+ }
1246
+ return {
1247
+ line: Number.parseInt(match[1], 10),
1248
+ payload: match[2] ?? ""
1249
+ };
1250
+ }
1251
+ function stripInlineComments(line, inBlockComment) {
1252
+ let result = "";
1253
+ let index = 0;
1254
+ let inBlock = inBlockComment;
1255
+ while (index < line.length) {
1256
+ const current = line[index];
1257
+ const next = index + 1 < line.length ? line[index + 1] : "";
1258
+ if (inBlock) {
1259
+ if (current === "*" && next === "/") {
1260
+ inBlock = false;
1261
+ index += 2;
1262
+ continue;
1263
+ }
1264
+ index += 1;
1265
+ continue;
1266
+ }
1267
+ if (current === "/" && next === "*") {
1268
+ inBlock = true;
1269
+ index += 2;
1270
+ continue;
1271
+ }
1272
+ if (current === "/" && next === "/") {
1273
+ break;
1274
+ }
1275
+ result += current;
1276
+ index += 1;
1277
+ }
1278
+ return { text: result, inBlockComment: inBlock };
1279
+ }
1280
+ function isMethodDeclarationLine(line) {
1281
+ const trimmed = line.trim();
1282
+ if (!trimmed) return false;
1283
+ if (trimmed.startsWith("@")) return false;
1284
+ if (!trimmed.includes("(") || !trimmed.includes(")")) return false;
1285
+ if (trimmed.endsWith(";")) return false;
1286
+ if (trimmed.includes("->")) return false;
1287
+ if (/^(?:if|for|while|switch|catch|do|try|else|return|throw|new)\b/.test(trimmed)) {
1288
+ return false;
1289
+ }
1290
+ if (!/[A-Za-z_][A-Za-z0-9_]*\s*\([^{};]*\)/.test(trimmed)) {
1291
+ return false;
1292
+ }
1293
+ return /(?:\{\s*)?$/.test(trimmed);
1294
+ }
1295
+ function buildLineRemap(sourceText) {
1296
+ if (typeof sourceText !== "string" || sourceText.length === 0) {
1297
+ return null;
1298
+ }
1299
+ const lines = sourceText.split(/\r?\n/);
1300
+ const executable = /* @__PURE__ */ new Set();
1301
+ let inBlockComment = false;
1302
+ for (let index = 0; index < lines.length; index += 1) {
1303
+ const { text, inBlockComment: nextInBlockComment } = stripInlineComments(lines[index] ?? "", inBlockComment);
1304
+ inBlockComment = nextInBlockComment;
1305
+ if (text.trim().length > 0) {
1306
+ executable.add(index + 1);
1307
+ }
1308
+ }
1309
+ if (executable.size === 0) {
1310
+ return null;
1311
+ }
1312
+ const nextExecutableAtOrAfter = new Array(lines.length + 2).fill(null);
1313
+ let nextExecutable = null;
1314
+ for (let line = lines.length; line >= 1; line -= 1) {
1315
+ if (executable.has(line)) {
1316
+ nextExecutable = line;
1317
+ }
1318
+ nextExecutableAtOrAfter[line] = nextExecutable;
1319
+ }
1320
+ const previousExecutableAtOrBefore = new Array(lines.length + 2).fill(null);
1321
+ let previousExecutable = null;
1322
+ for (let line = 1; line <= lines.length; line += 1) {
1323
+ if (executable.has(line)) {
1324
+ previousExecutable = line;
1325
+ }
1326
+ previousExecutableAtOrBefore[line] = previousExecutable;
1327
+ }
1328
+ const remap = /* @__PURE__ */ new Map();
1329
+ for (let line = 1; line <= lines.length; line += 1) {
1330
+ if (executable.has(line)) continue;
1331
+ const forward = nextExecutableAtOrAfter[line];
1332
+ const backward = previousExecutableAtOrBefore[line];
1333
+ const target = forward ?? backward;
1334
+ if (target !== null && target !== line) {
1335
+ remap.set(line, target);
1336
+ }
1337
+ }
1338
+ return remap;
1339
+ }
1340
+ function buildMethodDeclarationLineSet(sourceText) {
1341
+ if (typeof sourceText !== "string" || sourceText.length === 0) {
1342
+ return null;
1343
+ }
1344
+ const declarationLines = /* @__PURE__ */ new Set();
1345
+ const lines = sourceText.split(/\r?\n/);
1346
+ let inBlockComment = false;
1347
+ for (let index = 0; index < lines.length; index += 1) {
1348
+ const { text, inBlockComment: nextInBlockComment } = stripInlineComments(lines[index] ?? "", inBlockComment);
1349
+ inBlockComment = nextInBlockComment;
1350
+ if (isMethodDeclarationLine(text)) {
1351
+ declarationLines.add(index + 1);
1352
+ }
1353
+ }
1354
+ return declarationLines;
1355
+ }
1356
+ function parseAccessEvent(payload) {
1357
+ const isEphemeralOutputArrayName = (name) => /^(output|outputs)$/i.test(name);
1358
+ const cellRead = payload.match(/^access ([A-Za-z_][A-Za-z0-9_]*)\[(\d+)\]\[(\d+)\]=(.+)$/);
1359
+ if (cellRead) {
1360
+ return [{
1361
+ variable: cellRead[1],
1362
+ kind: "cell-read",
1363
+ indices: [Number.parseInt(cellRead[2], 10), Number.parseInt(cellRead[3], 10)],
1364
+ pathDepth: 2
1365
+ }];
1366
+ }
1367
+ const indexedRead = payload.match(/^access ([A-Za-z_][A-Za-z0-9_]*)\[(\d+)\]=(.+)$/);
1368
+ if (indexedRead) {
1369
+ return [{
1370
+ variable: indexedRead[1],
1371
+ kind: "indexed-read",
1372
+ indices: [Number.parseInt(indexedRead[2], 10)],
1373
+ pathDepth: 1
1374
+ }];
1375
+ }
1376
+ const cellWrite = payload.match(/^write-array ([A-Za-z_][A-Za-z0-9_]*)\[(\d+)\]\[(\d+)\]=(.+)$/);
1377
+ if (cellWrite) {
1378
+ return [{
1379
+ variable: cellWrite[1],
1380
+ kind: "cell-write",
1381
+ indices: [Number.parseInt(cellWrite[2], 10), Number.parseInt(cellWrite[3], 10)],
1382
+ pathDepth: 2
1383
+ }];
1384
+ }
1385
+ const indexedWrite = payload.match(/^write-array ([A-Za-z_][A-Za-z0-9_]*)\[(\d+)\]=(.+)$/);
1386
+ if (indexedWrite) {
1387
+ if (isEphemeralOutputArrayName(indexedWrite[1])) {
1388
+ return void 0;
1389
+ }
1390
+ return [{
1391
+ variable: indexedWrite[1],
1392
+ kind: "indexed-write",
1393
+ indices: [Number.parseInt(indexedWrite[2], 10)],
1394
+ pathDepth: 1
1395
+ }];
1396
+ }
1397
+ const mutatingCall = payload.match(/^mutate ([A-Za-z_][A-Za-z0-9_]*) method=([A-Za-z_][A-Za-z0-9_]*)$/);
1398
+ if (mutatingCall) {
1399
+ return [{
1400
+ variable: mutatingCall[1],
1401
+ kind: "mutating-call",
1402
+ method: mutatingCall[2],
1403
+ pathDepth: 1
1404
+ }];
1405
+ }
1406
+ return void 0;
1407
+ }
1408
+ function parseStructureState(payload) {
1409
+ const match = payload.match(/^state (linked-list|tree) ([A-Za-z_][A-Za-z0-9_]*)=(.+)$/);
1410
+ if (!match) return null;
1411
+ return {
1412
+ structure: match[1],
1413
+ variable: match[2],
1414
+ value: JSON.parse(match[3])
1415
+ };
1416
+ }
1417
+ function parseObjectState(payload) {
1418
+ const match = payload.match(/^object-state ([A-Za-z_][A-Za-z0-9_]*)=(.+)$/);
1419
+ if (!match) return null;
1420
+ return {
1421
+ variable: match[1],
1422
+ visualization: JSON.parse(match[2])
1423
+ };
1424
+ }
1425
+ function parseObjectFieldEvent(payload) {
1426
+ const match = payload.match(/^(access|write) ([A-Za-z_][A-Za-z0-9_]*)\.([A-Za-z_][A-Za-z0-9_]*)=(.+)$/);
1427
+ if (!match) return null;
1428
+ return {
1429
+ variable: match[2],
1430
+ field: match[3],
1431
+ value: parseScalar(match[4])
1432
+ };
1433
+ }
1434
+ function buildFieldVisualization(event) {
1435
+ return {
1436
+ objectKinds: {
1437
+ [event.variable]: "object"
1438
+ },
1439
+ hashMaps: [
1440
+ {
1441
+ name: event.variable,
1442
+ kind: "object",
1443
+ objectClassName: event.field === "next" || event.field === "prev" ? "ListNode" : event.field === "left" || event.field === "right" ? "TreeNode" : void 0,
1444
+ objectId: `${event.variable}-object`,
1445
+ highlightedKey: event.field,
1446
+ entries: [{ key: event.field, value: event.value, highlight: true }]
1447
+ }
1448
+ ]
1449
+ };
1450
+ }
1451
+ function callStacksEqual(left, right) {
1452
+ return JSON.stringify(left ?? []) === JSON.stringify(right ?? []);
1453
+ }
1454
+ function mergeVisualizationPayloads(left, right) {
1455
+ if (!left) return right;
1456
+ if (!right) return left;
1457
+ return {
1458
+ ...left,
1459
+ ...right,
1460
+ objectKinds: {
1461
+ ...left.objectKinds ?? {},
1462
+ ...right.objectKinds ?? {}
1463
+ },
1464
+ hashMaps: [
1465
+ ...left.hashMaps ?? [],
1466
+ ...right.hashMaps ?? []
1467
+ ]
1468
+ };
1469
+ }
1470
+ function maybeMergeConsecutiveLineStep(trace, nextStep) {
1471
+ if (nextStep.event !== "line") {
1472
+ return false;
1473
+ }
1474
+ const previous = trace.at(-1);
1475
+ if (!previous || previous.event !== "line") {
1476
+ return false;
1477
+ }
1478
+ if (previous.line !== nextStep.line || previous.function !== nextStep.function) {
1479
+ return false;
1480
+ }
1481
+ if (!callStacksEqual(previous.callStack, nextStep.callStack)) {
1482
+ return false;
1483
+ }
1484
+ previous.variables = { ...previous.variables ?? {}, ...nextStep.variables ?? {} };
1485
+ if (nextStep.accesses?.length) {
1486
+ previous.accesses = [...previous.accesses ?? [], ...nextStep.accesses];
1487
+ }
1488
+ previous.visualization = mergeVisualizationPayloads(previous.visualization, nextStep.visualization);
1489
+ return true;
1490
+ }
1491
+ function filterStructuredVariables(variables) {
1492
+ if (!variables) {
1493
+ return void 0;
1494
+ }
1495
+ const isEphemeralOutputArrayName = (name) => /^(output|outputs)$/i.test(name);
1496
+ const entries = Object.entries(variables).filter(([name, value]) => {
1497
+ if (value === null || typeof value !== "object") {
1498
+ return false;
1499
+ }
1500
+ if (!Array.isArray(value)) {
1501
+ return true;
1502
+ }
1503
+ if (Array.isArray(value[0])) {
1504
+ return true;
1505
+ }
1506
+ return !isEphemeralOutputArrayName(name);
1507
+ });
1508
+ if (entries.length === 0) {
1509
+ return void 0;
1510
+ }
1511
+ return Object.fromEntries(entries);
1512
+ }
1513
+ function appendJavaTraceStep(trace, step, pendingAccesses) {
1514
+ const nextStep = pendingAccesses.length > 0 ? { ...step, accesses: [...pendingAccesses] } : step;
1515
+ pendingAccesses.length = 0;
1516
+ if (!maybeMergeConsecutiveLineStep(trace, nextStep)) {
1517
+ trace.push(nextStep);
1518
+ }
1519
+ }
1520
+ function mergeIntoPreviousMatchingLineStep(trace, line, currentFunction, currentCallStack, patch) {
1521
+ const candidate = trace.at(-1);
1522
+ if (!candidate || candidate.event !== "line") {
1523
+ return false;
1524
+ }
1525
+ if (candidate.line !== line || candidate.function !== currentFunction) {
1526
+ return false;
1527
+ }
1528
+ if (!callStacksEqual(candidate.callStack, currentCallStack)) {
1529
+ return false;
1530
+ }
1531
+ candidate.variables = { ...candidate.variables ?? {}, ...patch.variables ?? {} };
1532
+ if (patch.accesses?.length) {
1533
+ candidate.accesses = [...candidate.accesses ?? [], ...patch.accesses];
1534
+ }
1535
+ candidate.visualization = mergeVisualizationPayloads(candidate.visualization, patch.visualization);
1536
+ return true;
1537
+ }
1538
+ function mergeAccessesIntoPreviousMatchingLineStep(trace, line, currentFunction, currentCallStack, accesses) {
1539
+ return mergeIntoPreviousMatchingLineStep(trace, line, currentFunction, currentCallStack, {
1540
+ variables: void 0,
1541
+ accesses,
1542
+ visualization: void 0
1543
+ });
1544
+ }
1545
+ function eventsToRawTrace(events, sourceText) {
1546
+ const trace = [];
1547
+ const variables = {};
1548
+ const objectKinds = {};
1549
+ const stack = [];
1550
+ const pendingAccesses = [];
1551
+ let currentFunction = "<module>";
1552
+ const lineRemap = buildLineRemap(sourceText);
1553
+ const declarationLines = buildMethodDeclarationLineSet(sourceText);
1554
+ for (const rawEvent of events) {
1555
+ if (rawEvent === "clear" || rawEvent === "reset") continue;
1556
+ const metadata = extractLineMetadata(rawEvent);
1557
+ const line = lineRemap?.get(metadata.line) ?? metadata.line;
1558
+ const payload = metadata.payload;
1559
+ const isDeclarationLine = declarationLines?.has(line) === true;
1560
+ if (payload.startsWith("call ")) {
1561
+ const match = payload.match(/^call\s+(\S+)(?:\s+(.*))?$/);
1562
+ const functionName = match?.[1] ?? currentFunction;
1563
+ const argsFragment = match?.[2] ?? "";
1564
+ Object.assign(variables, parseKeyValuePairs(argsFragment));
1565
+ currentFunction = functionName || currentFunction;
1566
+ stack.push({ function: currentFunction, line });
1567
+ appendJavaTraceStep(trace, {
1568
+ line,
1569
+ event: "call",
1570
+ function: currentFunction,
1571
+ variables: { ...variables },
1572
+ callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} }))
1573
+ }, pendingAccesses);
1574
+ continue;
1575
+ }
1576
+ if (payload.startsWith("return ")) {
1577
+ const match = payload.match(/^return\s+(\S+)$/);
1578
+ const functionName = match?.[1] ?? currentFunction;
1579
+ const returnVariables = functionName === "<module>" ? { ...variables } : filterStructuredVariables(variables) ?? {};
1580
+ appendJavaTraceStep(trace, {
1581
+ line,
1582
+ event: "return",
1583
+ function: functionName || currentFunction,
1584
+ variables: returnVariables,
1585
+ callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} }))
1586
+ }, pendingAccesses);
1587
+ stack.pop();
1588
+ currentFunction = stack[stack.length - 1]?.function ?? "<module>";
1589
+ continue;
1590
+ }
1591
+ if (isDeclarationLine) {
1592
+ continue;
1593
+ }
1594
+ if (payload.length === 0) {
1595
+ appendJavaTraceStep(trace, {
1596
+ line,
1597
+ event: "line",
1598
+ function: currentFunction,
1599
+ variables: { ...variables },
1600
+ ...stack.length > 0 ? { callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })) } : {}
1601
+ }, pendingAccesses);
1602
+ continue;
1603
+ }
1604
+ const structureState = parseStructureState(payload);
1605
+ if (structureState) {
1606
+ variables[structureState.variable] = structureState.value;
1607
+ objectKinds[structureState.variable] = structureState.structure;
1608
+ appendJavaTraceStep(trace, {
1609
+ line,
1610
+ event: "line",
1611
+ function: currentFunction,
1612
+ variables: { ...variables },
1613
+ callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })),
1614
+ visualization: {
1615
+ objectKinds: { ...objectKinds }
1616
+ }
1617
+ }, pendingAccesses);
1618
+ continue;
1619
+ }
1620
+ const objectState = parseObjectState(payload);
1621
+ if (objectState) {
1622
+ variables[objectState.variable] = { __ref__: objectState.visualization.objectId ?? `${objectState.variable}-object` };
1623
+ appendJavaTraceStep(trace, {
1624
+ line,
1625
+ event: "line",
1626
+ function: currentFunction,
1627
+ variables: { ...variables },
1628
+ callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })),
1629
+ visualization: {
1630
+ objectKinds: { [objectState.variable]: "object" },
1631
+ hashMaps: [objectState.visualization]
1632
+ }
1633
+ }, pendingAccesses);
1634
+ continue;
1635
+ }
1636
+ const objectField = parseObjectFieldEvent(payload);
1637
+ if (objectField) {
1638
+ variables[objectField.variable] = { __ref__: `${objectField.variable}-object` };
1639
+ const currentCallStack = stack.length > 0 ? stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })) : void 0;
1640
+ if (mergeIntoPreviousMatchingLineStep(trace, line, currentFunction, currentCallStack, {
1641
+ variables: { ...variables },
1642
+ accesses: void 0,
1643
+ visualization: buildFieldVisualization(objectField)
1644
+ })) {
1645
+ continue;
1646
+ }
1647
+ appendJavaTraceStep(trace, {
1648
+ line,
1649
+ event: "line",
1650
+ function: currentFunction,
1651
+ variables: { ...variables },
1652
+ callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })),
1653
+ visualization: buildFieldVisualization(objectField)
1654
+ }, pendingAccesses);
1655
+ continue;
1656
+ }
1657
+ Object.assign(variables, parseKeyValuePairs(payload));
1658
+ const accesses = parseAccessEvent(payload);
1659
+ if (accesses) {
1660
+ const currentCallStack = stack.length > 0 ? stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })) : void 0;
1661
+ if (mergeAccessesIntoPreviousMatchingLineStep(trace, line, currentFunction, currentCallStack, accesses)) {
1662
+ continue;
1663
+ }
1664
+ pendingAccesses.push(...accesses);
1665
+ continue;
1666
+ }
1667
+ appendJavaTraceStep(trace, {
1668
+ line,
1669
+ event: "line",
1670
+ function: currentFunction,
1671
+ variables: { ...variables },
1672
+ ...stack.length > 0 ? { callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })) } : {}
1673
+ }, pendingAccesses);
1674
+ }
1675
+ if (pendingAccesses.length > 0 && trace.length > 0) {
1676
+ const last = trace[trace.length - 1];
1677
+ last.accesses = [...last.accesses ?? [], ...pendingAccesses];
1678
+ }
1679
+ return trace;
1680
+ }
1681
+ function buildJavaExecutionResult(output, events, executionTimeMs = 0, traceLimitExceeded, timeoutReason, maxTraceSteps, sourceText) {
1682
+ const trace = eventsToRawTrace(events, sourceText);
1683
+ return {
1684
+ success: true,
1685
+ output,
1686
+ trace,
1687
+ executionTimeMs,
1688
+ consoleOutput: [],
1689
+ ...traceLimitExceeded !== void 0 ? { traceLimitExceeded } : {},
1690
+ ...maxTraceSteps !== void 0 ? { maxTraceSteps } : {},
1691
+ ...timeoutReason ? { timeoutReason } : {},
1692
+ lineEventCount: trace.filter((step) => step.event === "line").length,
1693
+ traceStepCount: trace.length
1694
+ };
1695
+ }
1696
+ function adaptJavaTraceExecutionResult(result) {
1697
+ return adaptTraceExecutionResult("java", result);
1698
+ }
1699
+
1700
+ // packages/harness-browser/src/java-runtime-client.ts
1701
+ var JavaRuntimeClient = class {
1702
+ constructor(workerClient) {
1703
+ this.workerClient = workerClient;
1704
+ }
1705
+ async init() {
1706
+ return this.workerClient.init();
1707
+ }
1708
+ async executeWithTracing(code, functionName, inputs, options, executionStyle = "function") {
1709
+ assertRuntimeRequestSupported(getLanguageRuntimeProfile("java"), {
1710
+ request: "trace",
1711
+ executionStyle,
1712
+ functionName
1713
+ });
1714
+ const rawResult = await this.workerClient.executeWithTracing(
1715
+ code,
1716
+ functionName ?? "",
1717
+ inputs,
1718
+ options,
1719
+ executionStyle
1720
+ );
1721
+ if (!rawResult.success) {
1722
+ return {
1723
+ success: false,
1724
+ error: rawResult.error ?? "Java tracing failed",
1725
+ ...rawResult.errorLine !== void 0 ? { errorLine: rawResult.errorLine } : {},
1726
+ trace: [],
1727
+ executionTimeMs: rawResult.executionTimeMs,
1728
+ consoleOutput: rawResult.consoleOutput,
1729
+ ...rawResult.traceLimitExceeded !== void 0 ? { traceLimitExceeded: rawResult.traceLimitExceeded } : {},
1730
+ ...rawResult.timeoutReason ? { timeoutReason: rawResult.timeoutReason } : {},
1731
+ lineEventCount: 0,
1732
+ traceStepCount: 0
1733
+ };
1734
+ }
1735
+ const adapted = adaptJavaTraceExecutionResult(
1736
+ buildJavaExecutionResult(
1737
+ rawResult.output,
1738
+ rawResult.events,
1739
+ rawResult.executionTimeMs,
1740
+ rawResult.traceLimitExceeded,
1741
+ rawResult.timeoutReason,
1742
+ void 0,
1743
+ rawResult.sourceText
1744
+ )
1745
+ );
1746
+ return {
1747
+ ...adapted,
1748
+ consoleOutput: rawResult.consoleOutput,
1749
+ executionTimeMs: rawResult.executionTimeMs
1750
+ };
1751
+ }
1752
+ async executeCode(code, functionName, inputs, executionStyle = "function") {
1753
+ assertRuntimeRequestSupported(getLanguageRuntimeProfile("java"), {
1754
+ request: "execute",
1755
+ executionStyle,
1756
+ functionName
1757
+ });
1758
+ return this.workerClient.executeCode(
1759
+ code,
1760
+ functionName,
1761
+ inputs,
1762
+ void 0,
1763
+ executionStyle
1764
+ );
1765
+ }
1766
+ async executeCodeInterviewMode(code, functionName, inputs, executionStyle = "function") {
1767
+ assertRuntimeRequestSupported(getLanguageRuntimeProfile("java"), {
1768
+ request: "interview",
1769
+ executionStyle,
1770
+ functionName
1771
+ });
1772
+ return this.workerClient.executeCodeInterviewMode(
1773
+ code,
1774
+ functionName,
1775
+ inputs,
1776
+ void 0,
1777
+ executionStyle
1778
+ );
1779
+ }
1780
+ };
1781
+ function createJavaRuntimeClient(workerClient) {
1782
+ return new JavaRuntimeClient(workerClient);
1783
+ }
1784
+
843
1785
  // packages/harness-browser/src/pyodide-worker-client.ts
844
1786
  var EXECUTION_TIMEOUT_MS2 = 1e4;
845
1787
  var INTERVIEW_MODE_TIMEOUT_MS2 = 5e3;
846
- var TRACING_TIMEOUT_MS2 = 3e4;
847
- var INIT_TIMEOUT_MS2 = 12e4;
848
- var MESSAGE_TIMEOUT_MS2 = 2e4;
849
- var WORKER_READY_TIMEOUT_MS2 = 1e4;
1788
+ var TRACING_TIMEOUT_MS3 = 3e4;
1789
+ var INIT_TIMEOUT_MS3 = 12e4;
1790
+ var MESSAGE_TIMEOUT_MS3 = 2e4;
1791
+ var WORKER_READY_TIMEOUT_MS3 = 1e4;
850
1792
  var PyodideWorkerClient = class {
851
1793
  constructor(options) {
852
1794
  this.options = options;
@@ -936,14 +1878,14 @@ var PyodideWorkerClient = class {
936
1878
  if (settled) return;
937
1879
  settled = true;
938
1880
  const timeoutError = new Error(
939
- `Python worker failed to initialize in time (${Math.round(WORKER_READY_TIMEOUT_MS2 / 1e3)}s)`
1881
+ `Python worker failed to initialize in time (${Math.round(WORKER_READY_TIMEOUT_MS3 / 1e3)}s)`
940
1882
  );
941
1883
  if (this.debug) {
942
- console.warn("[PyodideWorkerClient] worker-ready timeout", { timeoutMs: WORKER_READY_TIMEOUT_MS2 });
1884
+ console.warn("[PyodideWorkerClient] worker-ready timeout", { timeoutMs: WORKER_READY_TIMEOUT_MS3 });
943
1885
  }
944
1886
  this.terminateAndReset(timeoutError);
945
1887
  reject(timeoutError);
946
- }, WORKER_READY_TIMEOUT_MS2);
1888
+ }, WORKER_READY_TIMEOUT_MS3);
947
1889
  readyPromise.then(() => {
948
1890
  if (settled) return;
949
1891
  settled = true;
@@ -960,7 +1902,7 @@ var PyodideWorkerClient = class {
960
1902
  /**
961
1903
  * Send a message to the worker and wait for a response
962
1904
  */
963
- async sendMessage(type, payload, timeoutMs = MESSAGE_TIMEOUT_MS2) {
1905
+ async sendMessage(type, payload, timeoutMs = MESSAGE_TIMEOUT_MS3) {
964
1906
  const worker = this.getWorker();
965
1907
  await this.waitForWorkerReady();
966
1908
  const id = String(++this.messageId);
@@ -1044,7 +1986,7 @@ var PyodideWorkerClient = class {
1044
1986
  this.isInitializing = true;
1045
1987
  this.initPromise = (async () => {
1046
1988
  try {
1047
- return await this.sendMessage("init", void 0, INIT_TIMEOUT_MS2);
1989
+ return await this.sendMessage("init", void 0, INIT_TIMEOUT_MS3);
1048
1990
  } catch (error) {
1049
1991
  const message = error instanceof Error ? error.message : String(error);
1050
1992
  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");
@@ -1055,7 +1997,7 @@ var PyodideWorkerClient = class {
1055
1997
  console.warn("[PyodideWorkerClient] init failed, resetting worker and retrying once", { message });
1056
1998
  }
1057
1999
  this.terminateAndReset();
1058
- return this.sendMessage("init", void 0, INIT_TIMEOUT_MS2);
2000
+ return this.sendMessage("init", void 0, INIT_TIMEOUT_MS3);
1059
2001
  }
1060
2002
  })();
1061
2003
  try {
@@ -1082,9 +2024,9 @@ var PyodideWorkerClient = class {
1082
2024
  inputs,
1083
2025
  executionStyle,
1084
2026
  options
1085
- }, TRACING_TIMEOUT_MS2 + 5e3),
2027
+ }, TRACING_TIMEOUT_MS3 + 5e3),
1086
2028
  // Message timeout slightly longer than execution timeout
1087
- TRACING_TIMEOUT_MS2
2029
+ TRACING_TIMEOUT_MS3
1088
2030
  );
1089
2031
  } catch (error) {
1090
2032
  const errorMessage = error instanceof Error ? error.message : String(error);
@@ -1094,7 +2036,7 @@ var PyodideWorkerClient = class {
1094
2036
  success: false,
1095
2037
  error: errorMessage,
1096
2038
  trace: [],
1097
- executionTimeMs: TRACING_TIMEOUT_MS2,
2039
+ executionTimeMs: TRACING_TIMEOUT_MS3,
1098
2040
  consoleOutput: [],
1099
2041
  traceLimitExceeded: true,
1100
2042
  timeoutReason: "client-timeout",
@@ -1255,6 +2197,7 @@ var DEFAULT_BROWSER_HARNESS_ASSET_RELATIVE_PATHS = Object.freeze({
1255
2197
  pythonRuntimeCore: "pyodide/runtime-core.js",
1256
2198
  pythonSnippets: "generated-python-harness-snippets.js",
1257
2199
  javascriptWorker: "javascript-worker.js",
2200
+ javaWorker: "java-worker.js",
1258
2201
  typescriptCompiler: "vendor/typescript.js"
1259
2202
  });
1260
2203
  function isExplicitAssetPath(pathname) {
@@ -1288,6 +2231,7 @@ function resolveBrowserHarnessAssets(options = {}) {
1288
2231
  assetBaseUrl,
1289
2232
  assets.javascriptWorker ?? DEFAULT_BROWSER_HARNESS_ASSET_RELATIVE_PATHS.javascriptWorker
1290
2233
  ),
2234
+ javaWorker: resolveAssetPath(assetBaseUrl, assets.javaWorker ?? DEFAULT_BROWSER_HARNESS_ASSET_RELATIVE_PATHS.javaWorker),
1291
2235
  typescriptCompiler: resolveAssetPath(
1292
2236
  assetBaseUrl,
1293
2237
  assets.typescriptCompiler ?? DEFAULT_BROWSER_HARNESS_ASSET_RELATIVE_PATHS.typescriptCompiler
@@ -1301,6 +2245,7 @@ var BrowserHarnessRuntime = class {
1301
2245
  supportedLanguages = SUPPORTED_LANGUAGES;
1302
2246
  pythonWorkerClient;
1303
2247
  javaScriptWorkerClient;
2248
+ javaWorkerClient;
1304
2249
  clients;
1305
2250
  constructor(options = {}) {
1306
2251
  this.assets = resolveBrowserHarnessAssets(options);
@@ -1312,10 +2257,15 @@ var BrowserHarnessRuntime = class {
1312
2257
  workerUrl: this.assets.javascriptWorker,
1313
2258
  debug: options.debug
1314
2259
  });
2260
+ this.javaWorkerClient = new JavaWorkerClient({
2261
+ workerUrl: this.assets.javaWorker,
2262
+ debug: options.debug
2263
+ });
1315
2264
  this.clients = {
1316
2265
  python: createPythonRuntimeClient(this.pythonWorkerClient),
1317
2266
  javascript: createJavaScriptRuntimeClient("javascript", this.javaScriptWorkerClient),
1318
- typescript: createJavaScriptRuntimeClient("typescript", this.javaScriptWorkerClient)
2267
+ typescript: createJavaScriptRuntimeClient("typescript", this.javaScriptWorkerClient),
2268
+ java: createJavaRuntimeClient(this.javaWorkerClient)
1319
2269
  };
1320
2270
  }
1321
2271
  getClient(language) {
@@ -1339,11 +2289,16 @@ var BrowserHarnessRuntime = class {
1339
2289
  this.pythonWorkerClient.terminate();
1340
2290
  return;
1341
2291
  }
2292
+ if (language === "java") {
2293
+ this.javaWorkerClient.terminate();
2294
+ return;
2295
+ }
1342
2296
  this.javaScriptWorkerClient.terminate();
1343
2297
  }
1344
2298
  dispose() {
1345
2299
  this.pythonWorkerClient.terminate();
1346
2300
  this.javaScriptWorkerClient.terminate();
2301
+ this.javaWorkerClient.terminate();
1347
2302
  }
1348
2303
  };
1349
2304
  function createBrowserHarness(options = {}) {