@tracecode/harness 0.4.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/LICENSE +67 -80
  3. package/README.md +2 -1
  4. package/dist/browser.cjs +16 -4
  5. package/dist/browser.cjs.map +1 -1
  6. package/dist/browser.d.cts +2 -2
  7. package/dist/browser.d.ts +2 -2
  8. package/dist/browser.js +16 -4
  9. package/dist/browser.js.map +1 -1
  10. package/dist/cli.js +0 -0
  11. package/dist/core.cjs +16 -4
  12. package/dist/core.cjs.map +1 -1
  13. package/dist/core.d.cts +9 -6
  14. package/dist/core.d.ts +9 -6
  15. package/dist/core.js +16 -4
  16. package/dist/core.js.map +1 -1
  17. package/dist/index.cjs +354 -44
  18. package/dist/index.cjs.map +1 -1
  19. package/dist/index.d.cts +2 -2
  20. package/dist/index.d.ts +2 -2
  21. package/dist/index.js +354 -44
  22. package/dist/index.js.map +1 -1
  23. package/dist/internal/browser.d.cts +1 -1
  24. package/dist/internal/browser.d.ts +1 -1
  25. package/dist/javascript.cjs +262 -26
  26. package/dist/javascript.cjs.map +1 -1
  27. package/dist/javascript.d.cts +4 -4
  28. package/dist/javascript.d.ts +4 -4
  29. package/dist/javascript.js +262 -26
  30. package/dist/javascript.js.map +1 -1
  31. package/dist/python.cjs +76 -14
  32. package/dist/python.cjs.map +1 -1
  33. package/dist/python.d.cts +8 -8
  34. package/dist/python.d.ts +8 -8
  35. package/dist/python.js +76 -14
  36. package/dist/python.js.map +1 -1
  37. package/dist/{runtime-types-Dvgn07z9.d.cts → runtime-types--lBQ6rYu.d.cts} +1 -1
  38. package/dist/{runtime-types-C7d1LFbx.d.ts → runtime-types-DtaaAhHL.d.ts} +1 -1
  39. package/dist/{types-Bzr1Ohcf.d.cts → types-DwIYM3Ku.d.cts} +5 -2
  40. package/dist/{types-Bzr1Ohcf.d.ts → types-DwIYM3Ku.d.ts} +5 -2
  41. package/package.json +13 -11
  42. package/workers/javascript/javascript-worker.js +455 -31
  43. package/workers/python/generated-python-harness-snippets.js +1 -1
  44. package/workers/python/pyodide-worker.js +31 -0
  45. package/workers/python/runtime-core.js +235 -8
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- export { L as Language, a as LanguageRuntimeProfile, R as RuntimeCapabilities, b as RuntimeClient, c as RuntimeExecutionStyle, d as RuntimeMaturity, T as TraceExecutionOptions } from './runtime-types-Dvgn07z9.cjs';
2
- export { C as CallStackFrame, a as CodeExecutionResult, E as ExecutionResult, b as ExecutionStatus, P as ProcessedStep, c as PyodideState, R as RawTraceStep, d as RuntimeHashMapEntry, e as RuntimeHashMapVisualization, f as RuntimeObjectKind, g as RuntimeTraceAccessEvent, h as RuntimeTraceAccessKind, i as RuntimeVisualizationPayload, T as TestResult } from './types-Bzr1Ohcf.cjs';
1
+ export { L as Language, a as LanguageRuntimeProfile, R as RuntimeCapabilities, b as RuntimeClient, c as RuntimeExecutionStyle, d as RuntimeMaturity, T as TraceExecutionOptions } from './runtime-types--lBQ6rYu.cjs';
2
+ export { C as CallStackFrame, a as CodeExecutionResult, E as ExecutionResult, b as ExecutionStatus, P as ProcessedStep, c as PyodideState, R as RawTraceStep, d as RuntimeHashMapEntry, e as RuntimeHashMapVisualization, f as RuntimeObjectKind, g as RuntimeTraceAccessEvent, h as RuntimeTraceAccessKind, i as RuntimeVisualizationPayload, T as TestResult } from './types-DwIYM3Ku.cjs';
3
3
  export { RUNTIME_TRACE_CONTRACT_SCHEMA_VERSION, RuntimeTraceContractCallStackFrame, RuntimeTraceContractEvent, RuntimeTraceContractHashMap, RuntimeTraceContractHashMapEntry, RuntimeTraceContractResult, RuntimeTraceContractStep, RuntimeTraceContractVisualization, adaptJavaScriptTraceExecutionResult, adaptPythonTraceExecutionResult, adaptTraceExecutionResult, normalizeRuntimeTraceContract, stableStringifyRuntimeTraceContract } from './core.cjs';
4
4
  export { BrowserHarness, BrowserHarnessAssetOverrides, BrowserHarnessAssets, CreateBrowserHarnessOptions, DEFAULT_BROWSER_HARNESS_ASSET_RELATIVE_PATHS, LANGUAGE_RUNTIME_PROFILES, SUPPORTED_LANGUAGES, assertRuntimeRequestSupported, createBrowserHarness, getLanguageRuntimeProfile, getSupportedLanguageProfiles, isLanguageSupported, resolveBrowserHarnessAssets } from './browser.cjs';
5
5
  export { PYTHON_CLASS_DEFINITIONS, PYTHON_CONVERSION_HELPERS, PYTHON_EXECUTE_SERIALIZE_FUNCTION, PYTHON_INTERVIEW_MATERIALIZE_SERIALIZE_FUNCTION, PYTHON_PRACTICE_MATERIALIZE_SERIALIZE_FUNCTION, PYTHON_SERIALIZE_FUNCTION, PYTHON_TRACE_SERIALIZE_FUNCTION, TEMPLATE_PYTHON_CLASS_DEFINITIONS, TEMPLATE_PYTHON_CONVERSION_HELPERS, TEMPLATE_PYTHON_EXECUTE_SERIALIZE_FUNCTION, TEMPLATE_PYTHON_INTERVIEW_MATERIALIZE_SERIALIZE_FUNCTION, TEMPLATE_PYTHON_PRACTICE_MATERIALIZE_SERIALIZE_FUNCTION, TEMPLATE_PYTHON_SERIALIZE_FUNCTION, TEMPLATE_PYTHON_TRACE_SERIALIZE_FUNCTION, generateConversionCode, generateInputSetup, generateSolutionScript, identifyConversions, templateToPythonLiteral, toPythonLiteral } from './python.cjs';
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- export { L as Language, a as LanguageRuntimeProfile, R as RuntimeCapabilities, b as RuntimeClient, c as RuntimeExecutionStyle, d as RuntimeMaturity, T as TraceExecutionOptions } from './runtime-types-C7d1LFbx.js';
2
- export { C as CallStackFrame, a as CodeExecutionResult, E as ExecutionResult, b as ExecutionStatus, P as ProcessedStep, c as PyodideState, R as RawTraceStep, d as RuntimeHashMapEntry, e as RuntimeHashMapVisualization, f as RuntimeObjectKind, g as RuntimeTraceAccessEvent, h as RuntimeTraceAccessKind, i as RuntimeVisualizationPayload, T as TestResult } from './types-Bzr1Ohcf.js';
1
+ export { L as Language, a as LanguageRuntimeProfile, R as RuntimeCapabilities, b as RuntimeClient, c as RuntimeExecutionStyle, d as RuntimeMaturity, T as TraceExecutionOptions } from './runtime-types-DtaaAhHL.js';
2
+ export { C as CallStackFrame, a as CodeExecutionResult, E as ExecutionResult, b as ExecutionStatus, P as ProcessedStep, c as PyodideState, R as RawTraceStep, d as RuntimeHashMapEntry, e as RuntimeHashMapVisualization, f as RuntimeObjectKind, g as RuntimeTraceAccessEvent, h as RuntimeTraceAccessKind, i as RuntimeVisualizationPayload, T as TestResult } from './types-DwIYM3Ku.js';
3
3
  export { RUNTIME_TRACE_CONTRACT_SCHEMA_VERSION, RuntimeTraceContractCallStackFrame, RuntimeTraceContractEvent, RuntimeTraceContractHashMap, RuntimeTraceContractHashMapEntry, RuntimeTraceContractResult, RuntimeTraceContractStep, RuntimeTraceContractVisualization, adaptJavaScriptTraceExecutionResult, adaptPythonTraceExecutionResult, adaptTraceExecutionResult, normalizeRuntimeTraceContract, stableStringifyRuntimeTraceContract } from './core.js';
4
4
  export { BrowserHarness, BrowserHarnessAssetOverrides, BrowserHarnessAssets, CreateBrowserHarnessOptions, DEFAULT_BROWSER_HARNESS_ASSET_RELATIVE_PATHS, LANGUAGE_RUNTIME_PROFILES, SUPPORTED_LANGUAGES, assertRuntimeRequestSupported, createBrowserHarness, getLanguageRuntimeProfile, getSupportedLanguageProfiles, isLanguageSupported, resolveBrowserHarnessAssets } from './browser.js';
5
5
  export { PYTHON_CLASS_DEFINITIONS, PYTHON_CONVERSION_HELPERS, PYTHON_EXECUTE_SERIALIZE_FUNCTION, PYTHON_INTERVIEW_MATERIALIZE_SERIALIZE_FUNCTION, PYTHON_PRACTICE_MATERIALIZE_SERIALIZE_FUNCTION, PYTHON_SERIALIZE_FUNCTION, PYTHON_TRACE_SERIALIZE_FUNCTION, TEMPLATE_PYTHON_CLASS_DEFINITIONS, TEMPLATE_PYTHON_CONVERSION_HELPERS, TEMPLATE_PYTHON_EXECUTE_SERIALIZE_FUNCTION, TEMPLATE_PYTHON_INTERVIEW_MATERIALIZE_SERIALIZE_FUNCTION, TEMPLATE_PYTHON_PRACTICE_MATERIALIZE_SERIALIZE_FUNCTION, TEMPLATE_PYTHON_SERIALIZE_FUNCTION, TEMPLATE_PYTHON_TRACE_SERIALIZE_FUNCTION, generateConversionCode, generateInputSetup, generateSolutionScript, identifyConversions, templateToPythonLiteral, toPythonLiteral } from './python.js';
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // packages/harness-core/src/trace-contract.ts
2
- var RUNTIME_TRACE_CONTRACT_SCHEMA_VERSION = "2026-03-07";
2
+ var RUNTIME_TRACE_CONTRACT_SCHEMA_VERSION = "2026-03-13";
3
3
  var TRACE_EVENTS = /* @__PURE__ */ new Set([
4
4
  "line",
5
5
  "call",
@@ -42,13 +42,13 @@ function normalizeFunctionName(value) {
42
42
  return "<module>";
43
43
  }
44
44
  function normalizeKind(value) {
45
- if (value === "map" || value === "set" || value === "hashmap") {
45
+ if (value === "map" || value === "set" || value === "hashmap" || value === "object") {
46
46
  return value;
47
47
  }
48
48
  return "hashmap";
49
49
  }
50
50
  function normalizeObjectKind(value) {
51
- if (value === "hashmap" || value === "map" || value === "set" || value === "tree" || value === "linked-list" || value === "graph-adjacency") {
51
+ if (value === "hashmap" || value === "object" || value === "map" || value === "set" || value === "tree" || value === "linked-list" || value === "graph-adjacency") {
52
52
  return value;
53
53
  }
54
54
  return null;
@@ -126,6 +126,14 @@ function normalizeRecord(value) {
126
126
  if (!value || typeof value !== "object" || Array.isArray(value)) return {};
127
127
  return normalizeUnknown(value);
128
128
  }
129
+ function normalizeVariableSources(value) {
130
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
131
+ const entries = Object.entries(value).filter(
132
+ ([name, source]) => typeof name === "string" && name.length > 0 && (source === "user" || source === "user-input" || source === "harness-prelude")
133
+ ).sort((a, b) => a[0].localeCompare(b[0]));
134
+ if (entries.length === 0) return void 0;
135
+ return Object.fromEntries(entries);
136
+ }
129
137
  function normalizeCallStackFrame(frame) {
130
138
  return {
131
139
  function: normalizeFunctionName(frame?.function),
@@ -143,7 +151,9 @@ function normalizeVisualizationPayload(payload) {
143
151
  ...item?.highlight ? { highlight: true } : {}
144
152
  })) : [],
145
153
  ...entry?.highlightedKey !== void 0 ? { highlightedKey: normalizeUnknown(entry.highlightedKey) } : {},
146
- ...entry?.deletedKey !== void 0 ? { deletedKey: normalizeUnknown(entry.deletedKey) } : {}
154
+ ...entry?.deletedKey !== void 0 ? { deletedKey: normalizeUnknown(entry.deletedKey) } : {},
155
+ ...typeof entry?.objectClassName === "string" && entry.objectClassName.length > 0 ? { objectClassName: entry.objectClassName } : {},
156
+ ...typeof entry?.objectId === "string" && entry.objectId.length > 0 ? { objectId: entry.objectId } : {}
147
157
  })).sort((a, b) => `${a.name}:${a.kind}`.localeCompare(`${b.name}:${b.kind}`)) : [];
148
158
  const objectKinds = payload?.objectKinds && typeof payload.objectKinds === "object" ? Object.fromEntries(
149
159
  Object.entries(payload.objectKinds).filter(([name]) => typeof name === "string" && name.length > 0).map(([name, kind]) => [name, normalizeObjectKind(kind)]).filter((entry) => entry[1] !== null).sort((a, b) => a[0].localeCompare(b[0]))
@@ -160,11 +170,13 @@ function normalizeTraceStep(step) {
160
170
  const normalizedStdoutCount = normalizeOutputLineCount(step?.stdoutLineCount);
161
171
  const normalizedVisualization = normalizeVisualizationPayload(step?.visualization);
162
172
  const normalizedAccesses = normalizeAccesses(step?.accesses);
173
+ const normalizedVariableSources = normalizeVariableSources(step?.variableSources);
163
174
  return {
164
175
  event: normalizeEvent(step?.event),
165
176
  line: normalizeLineNumber(step?.line, 1),
166
177
  function: normalizeFunctionName(step?.function),
167
178
  variables: normalizeRecord(step?.variables),
179
+ ...normalizedVariableSources ? { variableSources: normalizedVariableSources } : {},
168
180
  ...Array.isArray(step?.callStack) && step.callStack.length > 0 ? { callStack: step.callStack.map(normalizeCallStackFrame) } : {},
169
181
  ...normalizedAccesses ? { accesses: normalizedAccesses } : {},
170
182
  ...step?.returnValue !== void 0 ? { returnValue: normalizeUnknown(step.returnValue) } : {},
@@ -1375,6 +1387,7 @@ var PYTHON_TRACE_SERIALIZE_FUNCTION = `
1375
1387
  # Sentinel to mark skipped values (functions, etc.) - distinct from None
1376
1388
  _SKIP_SENTINEL = "__TRACECODE_SKIP__"
1377
1389
  _MAX_SERIALIZE_DEPTH = 48
1390
+ _MAX_OBJECT_FIELDS = 32
1378
1391
 
1379
1392
  def _serialize(obj, depth=0, node_refs=None):
1380
1393
  if node_refs is None:
@@ -1402,7 +1415,7 @@ def _serialize(obj, depth=0, node_refs=None):
1402
1415
  except TypeError:
1403
1416
  sorted_vals = [_serialize(x, depth + 1, node_refs) for x in obj]
1404
1417
  return {"__type__": "set", "values": sorted_vals}
1405
- elif (hasattr(obj, 'val') or hasattr(obj, 'value')) and (hasattr(obj, 'left') or hasattr(obj, 'right')):
1418
+ elif isinstance(obj, TreeNode):
1406
1419
  obj_ref = id(obj)
1407
1420
  if obj_ref in node_refs:
1408
1421
  return {"__ref__": node_refs[obj_ref]}
@@ -1418,7 +1431,7 @@ def _serialize(obj, depth=0, node_refs=None):
1418
1431
  if hasattr(obj, 'right'):
1419
1432
  result["right"] = _serialize(obj.right, depth + 1, node_refs)
1420
1433
  return result
1421
- elif (hasattr(obj, 'val') or hasattr(obj, 'value')) and hasattr(obj, 'next'):
1434
+ elif isinstance(obj, ListNode):
1422
1435
  obj_ref = id(obj)
1423
1436
  if obj_ref in node_refs:
1424
1437
  return {"__ref__": node_refs[obj_ref]}
@@ -1431,6 +1444,36 @@ def _serialize(obj, depth=0, node_refs=None):
1431
1444
  }
1432
1445
  result["next"] = _serialize(obj.next, depth + 1, node_refs)
1433
1446
  return result
1447
+ elif hasattr(obj, '__dict__'):
1448
+ obj_ref = id(obj)
1449
+ if obj_ref in node_refs:
1450
+ return {"__ref__": node_refs[obj_ref]}
1451
+ node_id = f"object-{obj_ref}"
1452
+ node_refs[obj_ref] = node_id
1453
+ class_name = getattr(getattr(obj, '__class__', None), '__name__', 'object')
1454
+ result = {
1455
+ "__type__": "object",
1456
+ "__class__": class_name,
1457
+ "__id__": node_id,
1458
+ }
1459
+ try:
1460
+ raw_fields = getattr(obj, '__dict__', None)
1461
+ except Exception:
1462
+ raw_fields = None
1463
+ if isinstance(raw_fields, dict):
1464
+ added = 0
1465
+ for key, value in raw_fields.items():
1466
+ key_str = str(key)
1467
+ if key_str.startswith('_'):
1468
+ continue
1469
+ if callable(value):
1470
+ continue
1471
+ result[key_str] = _serialize(value, depth + 1, node_refs)
1472
+ added += 1
1473
+ if added >= _MAX_OBJECT_FIELDS:
1474
+ result["__truncated__"] = True
1475
+ break
1476
+ return result
1434
1477
  elif callable(obj):
1435
1478
  # Skip functions entirely - return sentinel
1436
1479
  return _SKIP_SENTINEL
@@ -1466,14 +1509,14 @@ def _serialize(obj, depth=0):
1466
1509
  return {"__type__": "set", "values": sorted([_serialize(x, depth + 1) for x in obj])}
1467
1510
  except TypeError:
1468
1511
  return {"__type__": "set", "values": [_serialize(x, depth + 1) for x in obj]}
1469
- elif (hasattr(obj, 'val') or hasattr(obj, 'value')) and (hasattr(obj, 'left') or hasattr(obj, 'right')):
1512
+ elif isinstance(obj, TreeNode):
1470
1513
  result = {"__type__": "TreeNode", "val": _serialize(getattr(obj, 'val', getattr(obj, 'value', None)), depth + 1)}
1471
1514
  if hasattr(obj, 'left'):
1472
1515
  result["left"] = _serialize(obj.left, depth + 1)
1473
1516
  if hasattr(obj, 'right'):
1474
1517
  result["right"] = _serialize(obj.right, depth + 1)
1475
1518
  return result
1476
- elif (hasattr(obj, 'val') or hasattr(obj, 'value')) and hasattr(obj, 'next'):
1519
+ elif isinstance(obj, ListNode):
1477
1520
  result = {"__type__": "ListNode", "val": _serialize(getattr(obj, 'val', getattr(obj, 'value', None)), depth + 1)}
1478
1521
  result["next"] = _serialize(obj.next, depth + 1)
1479
1522
  return result
@@ -1548,14 +1591,14 @@ def _serialize(obj, depth=0):
1548
1591
  return {"__type__": "set", "values": sorted([_serialize(x, depth + 1) for x in obj])}
1549
1592
  except TypeError:
1550
1593
  return {"__type__": "set", "values": [_serialize(x, depth + 1) for x in obj]}
1551
- elif hasattr(obj, 'val') and (hasattr(obj, 'left') or hasattr(obj, 'right')):
1594
+ elif isinstance(obj, TreeNode):
1552
1595
  result = {"__type__": "TreeNode", "val": _serialize(getattr(obj, 'val', None), depth + 1)}
1553
1596
  if hasattr(obj, 'left'):
1554
1597
  result["left"] = _serialize(obj.left, depth + 1)
1555
1598
  if hasattr(obj, 'right'):
1556
1599
  result["right"] = _serialize(obj.right, depth + 1)
1557
1600
  return result
1558
- elif hasattr(obj, 'val') and hasattr(obj, 'next'):
1601
+ elif isinstance(obj, ListNode):
1559
1602
  result = {"__type__": "ListNode", "val": _serialize(getattr(obj, 'val', None), depth + 1)}
1560
1603
  result["next"] = _serialize(obj.next, depth + 1)
1561
1604
  return result
@@ -1587,14 +1630,14 @@ def _serialize(obj, depth=0):
1587
1630
  return {"__type__": "set", "values": sorted([_serialize(x, depth + 1) for x in obj])}
1588
1631
  except TypeError:
1589
1632
  return {"__type__": "set", "values": [_serialize(x, depth + 1) for x in obj]}
1590
- elif (hasattr(obj, 'val') or hasattr(obj, 'value')) and (hasattr(obj, 'left') or hasattr(obj, 'right')):
1633
+ elif isinstance(obj, TreeNode):
1591
1634
  result = {"__type__": "TreeNode", "val": _serialize(getattr(obj, 'val', getattr(obj, 'value', None)), depth + 1)}
1592
1635
  if hasattr(obj, 'left'):
1593
1636
  result["left"] = _serialize(obj.left, depth + 1)
1594
1637
  if hasattr(obj, 'right'):
1595
1638
  result["right"] = _serialize(obj.right, depth + 1)
1596
1639
  return result
1597
- elif (hasattr(obj, 'val') or hasattr(obj, 'value')) and hasattr(obj, 'next'):
1640
+ elif isinstance(obj, ListNode):
1598
1641
  result = {"__type__": "ListNode", "val": _serialize(getattr(obj, 'val', getattr(obj, 'value', None)), depth + 1)}
1599
1642
  result["next"] = _serialize(obj.next, depth + 1)
1600
1643
  return result
@@ -1794,6 +1837,7 @@ var TEMPLATE_PYTHON_TRACE_SERIALIZE_FUNCTION = `
1794
1837
  # Sentinel to mark skipped values (functions, etc.) - distinct from None
1795
1838
  _SKIP_SENTINEL = "__TRACECODE_SKIP__"
1796
1839
  _MAX_SERIALIZE_DEPTH = 48
1840
+ _MAX_OBJECT_FIELDS = 32
1797
1841
 
1798
1842
  def _serialize(obj, depth=0, node_refs=None):
1799
1843
  if node_refs is None:
@@ -1821,7 +1865,7 @@ def _serialize(obj, depth=0, node_refs=None):
1821
1865
  except TypeError:
1822
1866
  sorted_vals = [_serialize(x, depth + 1, node_refs) for x in obj]
1823
1867
  return {"__type__": "set", "values": sorted_vals}
1824
- elif (hasattr(obj, 'val') or hasattr(obj, 'value')) and (hasattr(obj, 'left') or hasattr(obj, 'right')):
1868
+ elif isinstance(obj, TreeNode):
1825
1869
  obj_ref = id(obj)
1826
1870
  if obj_ref in node_refs:
1827
1871
  return {"__ref__": node_refs[obj_ref]}
@@ -1837,7 +1881,7 @@ def _serialize(obj, depth=0, node_refs=None):
1837
1881
  if hasattr(obj, 'right'):
1838
1882
  result["right"] = _serialize(obj.right, depth + 1, node_refs)
1839
1883
  return result
1840
- elif (hasattr(obj, 'val') or hasattr(obj, 'value')) and hasattr(obj, 'next'):
1884
+ elif isinstance(obj, ListNode):
1841
1885
  obj_ref = id(obj)
1842
1886
  if obj_ref in node_refs:
1843
1887
  return {"__ref__": node_refs[obj_ref]}
@@ -1850,6 +1894,36 @@ def _serialize(obj, depth=0, node_refs=None):
1850
1894
  }
1851
1895
  result["next"] = _serialize(obj.next, depth + 1, node_refs)
1852
1896
  return result
1897
+ elif hasattr(obj, '__dict__'):
1898
+ obj_ref = id(obj)
1899
+ if obj_ref in node_refs:
1900
+ return {"__ref__": node_refs[obj_ref]}
1901
+ node_id = f"object-{obj_ref}"
1902
+ node_refs[obj_ref] = node_id
1903
+ class_name = getattr(getattr(obj, '__class__', None), '__name__', 'object')
1904
+ result = {
1905
+ "__type__": "object",
1906
+ "__class__": class_name,
1907
+ "__id__": node_id,
1908
+ }
1909
+ try:
1910
+ raw_fields = getattr(obj, '__dict__', None)
1911
+ except Exception:
1912
+ raw_fields = None
1913
+ if isinstance(raw_fields, dict):
1914
+ added = 0
1915
+ for key, value in raw_fields.items():
1916
+ key_str = str(key)
1917
+ if key_str.startswith('_'):
1918
+ continue
1919
+ if callable(value):
1920
+ continue
1921
+ result[key_str] = _serialize(value, depth + 1, node_refs)
1922
+ added += 1
1923
+ if added >= _MAX_OBJECT_FIELDS:
1924
+ result["__truncated__"] = True
1925
+ break
1926
+ return result
1853
1927
  elif callable(obj):
1854
1928
  # Skip functions entirely - return sentinel
1855
1929
  return _SKIP_SENTINEL
@@ -1885,14 +1959,14 @@ def _serialize(obj, depth=0):
1885
1959
  return {"__type__": "set", "values": sorted([_serialize(x, depth + 1) for x in obj])}
1886
1960
  except TypeError:
1887
1961
  return {"__type__": "set", "values": [_serialize(x, depth + 1) for x in obj]}
1888
- elif (hasattr(obj, 'val') or hasattr(obj, 'value')) and (hasattr(obj, 'left') or hasattr(obj, 'right')):
1962
+ elif isinstance(obj, TreeNode):
1889
1963
  result = {"__type__": "TreeNode", "val": _serialize(getattr(obj, 'val', getattr(obj, 'value', None)), depth + 1)}
1890
1964
  if hasattr(obj, 'left'):
1891
1965
  result["left"] = _serialize(obj.left, depth + 1)
1892
1966
  if hasattr(obj, 'right'):
1893
1967
  result["right"] = _serialize(obj.right, depth + 1)
1894
1968
  return result
1895
- elif (hasattr(obj, 'val') or hasattr(obj, 'value')) and hasattr(obj, 'next'):
1969
+ elif isinstance(obj, ListNode):
1896
1970
  result = {"__type__": "ListNode", "val": _serialize(getattr(obj, 'val', getattr(obj, 'value', None)), depth + 1)}
1897
1971
  result["next"] = _serialize(obj.next, depth + 1)
1898
1972
  return result
@@ -1967,14 +2041,14 @@ def _serialize(obj, depth=0):
1967
2041
  return {"__type__": "set", "values": sorted([_serialize(x, depth + 1) for x in obj])}
1968
2042
  except TypeError:
1969
2043
  return {"__type__": "set", "values": [_serialize(x, depth + 1) for x in obj]}
1970
- elif hasattr(obj, 'val') and (hasattr(obj, 'left') or hasattr(obj, 'right')):
2044
+ elif isinstance(obj, TreeNode):
1971
2045
  result = {"__type__": "TreeNode", "val": _serialize(getattr(obj, 'val', None), depth + 1)}
1972
2046
  if hasattr(obj, 'left'):
1973
2047
  result["left"] = _serialize(obj.left, depth + 1)
1974
2048
  if hasattr(obj, 'right'):
1975
2049
  result["right"] = _serialize(obj.right, depth + 1)
1976
2050
  return result
1977
- elif hasattr(obj, 'val') and hasattr(obj, 'next'):
2051
+ elif isinstance(obj, ListNode):
1978
2052
  result = {"__type__": "ListNode", "val": _serialize(getattr(obj, 'val', None), depth + 1)}
1979
2053
  result["next"] = _serialize(obj.next, depth + 1)
1980
2054
  return result
@@ -2068,16 +2142,28 @@ function createConsoleProxy(output) {
2068
2142
  }
2069
2143
  function isLikelyTreeNodeValue(value) {
2070
2144
  if (!value || typeof value !== "object" || Array.isArray(value)) return false;
2071
- const hasValue = "val" in value || "value" in value;
2072
- const hasTreeLinks = "left" in value || "right" in value;
2073
- return hasValue && hasTreeLinks;
2145
+ const record = value;
2146
+ if (record.__type__ === "TreeNode") return true;
2147
+ const ctor = value.constructor;
2148
+ return ctor?.name === "TreeNode";
2074
2149
  }
2075
2150
  function isLikelyListNodeValue(value) {
2076
2151
  if (!value || typeof value !== "object" || Array.isArray(value)) return false;
2077
- const hasValue = "val" in value || "value" in value;
2078
- const hasTreeLinks = "left" in value || "right" in value;
2079
- const hasListLinks = "next" in value || "prev" in value;
2080
- return hasValue && hasListLinks && !hasTreeLinks;
2152
+ const record = value;
2153
+ if (record.__type__ === "ListNode") return true;
2154
+ const ctor = value.constructor;
2155
+ return ctor?.name === "ListNode";
2156
+ }
2157
+ function getCustomClassName(value) {
2158
+ if (!value || typeof value !== "object" || Array.isArray(value)) return null;
2159
+ if (value instanceof Map || value instanceof Set) return null;
2160
+ if (isLikelyTreeNodeValue(value) || isLikelyListNodeValue(value)) return null;
2161
+ const ctor = value.constructor;
2162
+ const name = typeof ctor?.name === "string" ? ctor.name : "";
2163
+ if (!name || name === "Object" || name === "Array" || name === "Map" || name === "Set") {
2164
+ return null;
2165
+ }
2166
+ return name;
2081
2167
  }
2082
2168
  function serializeValue(value, depth = 0, seen = /* @__PURE__ */ new WeakSet(), nodeRefState = { ids: /* @__PURE__ */ new Map(), nextId: 1 }) {
2083
2169
  if (depth > 48) return "<max depth>";
@@ -2121,22 +2207,47 @@ function serializeValue(value, depth = 0, seen = /* @__PURE__ */ new WeakSet(),
2121
2207
  const nodePrefix = isTree ? "tree" : "list";
2122
2208
  const nodeId = `${nodePrefix}-${nodeRefState.nextId++}`;
2123
2209
  nodeRefState.ids.set(objectValue, nodeId);
2124
- if (isTree) {
2125
- return {
2126
- __type__: "TreeNode",
2127
- __id__: nodeId,
2128
- val: serializeValue(nodeValue.val ?? nodeValue.value ?? null, depth + 1, seen, nodeRefState),
2129
- left: serializeValue(nodeValue.left ?? null, depth + 1, seen, nodeRefState),
2130
- right: serializeValue(nodeValue.right ?? null, depth + 1, seen, nodeRefState)
2131
- };
2132
- }
2133
- return {
2210
+ const out2 = isTree ? {
2211
+ __type__: "TreeNode",
2212
+ __id__: nodeId,
2213
+ val: serializeValue(nodeValue.val ?? nodeValue.value ?? null, depth + 1, seen, nodeRefState),
2214
+ left: serializeValue(nodeValue.left ?? null, depth + 1, seen, nodeRefState),
2215
+ right: serializeValue(nodeValue.right ?? null, depth + 1, seen, nodeRefState)
2216
+ } : {
2134
2217
  __type__: "ListNode",
2135
2218
  __id__: nodeId,
2136
2219
  val: serializeValue(nodeValue.val ?? nodeValue.value ?? null, depth + 1, seen, nodeRefState),
2137
2220
  next: serializeValue(nodeValue.next ?? null, depth + 1, seen, nodeRefState),
2138
2221
  ..."prev" in nodeValue ? { prev: serializeValue(nodeValue.prev ?? null, depth + 1, seen, nodeRefState) } : {}
2139
2222
  };
2223
+ const skipped = isTree ? /* @__PURE__ */ new Set(["__id__", "__type__", "__class__", "val", "value", "left", "right"]) : /* @__PURE__ */ new Set(["__id__", "__type__", "__class__", "val", "value", "next", "prev"]);
2224
+ for (const [k, v] of Object.entries(nodeValue)) {
2225
+ if (skipped.has(k)) continue;
2226
+ out2[k] = serializeValue(v, depth + 1, seen, nodeRefState);
2227
+ }
2228
+ return out2;
2229
+ }
2230
+ const customClassName = getCustomClassName(value);
2231
+ if (customClassName) {
2232
+ const objectValue = value;
2233
+ const existingId = nodeRefState.ids.get(objectValue);
2234
+ if (existingId) {
2235
+ return { __ref__: existingId };
2236
+ }
2237
+ const objectId = `object-${nodeRefState.nextId++}`;
2238
+ nodeRefState.ids.set(objectValue, objectId);
2239
+ if (seen.has(objectValue)) return { __ref__: objectId };
2240
+ seen.add(objectValue);
2241
+ const out2 = {
2242
+ __type__: "object",
2243
+ __class__: customClassName,
2244
+ __id__: objectId
2245
+ };
2246
+ for (const [k, v] of Object.entries(value)) {
2247
+ out2[k] = serializeValue(v, depth + 1, seen, nodeRefState);
2248
+ }
2249
+ seen.delete(objectValue);
2250
+ return out2;
2140
2251
  }
2141
2252
  if (seen.has(value)) return "<cycle>";
2142
2253
  seen.add(value);
@@ -2227,6 +2338,194 @@ function normalizeInputs(inputs) {
2227
2338
  }
2228
2339
  return hydrated;
2229
2340
  }
2341
+ function buildTreeNodeFromLevelOrder(values) {
2342
+ if (!Array.isArray(values) || values.length === 0) return null;
2343
+ const firstValue = values[0];
2344
+ if (firstValue === null || firstValue === void 0) return null;
2345
+ const root = {
2346
+ val: firstValue,
2347
+ value: firstValue,
2348
+ left: null,
2349
+ right: null
2350
+ };
2351
+ const queue = [root];
2352
+ let index = 1;
2353
+ while (queue.length > 0 && index < values.length) {
2354
+ const node = queue.shift();
2355
+ if (!node) break;
2356
+ const leftValue = values[index++];
2357
+ if (leftValue !== null && leftValue !== void 0) {
2358
+ const leftNode = {
2359
+ val: leftValue,
2360
+ value: leftValue,
2361
+ left: null,
2362
+ right: null
2363
+ };
2364
+ node.left = leftNode;
2365
+ queue.push(leftNode);
2366
+ }
2367
+ if (index >= values.length) break;
2368
+ const rightValue = values[index++];
2369
+ if (rightValue !== null && rightValue !== void 0) {
2370
+ const rightNode = {
2371
+ val: rightValue,
2372
+ value: rightValue,
2373
+ left: null,
2374
+ right: null
2375
+ };
2376
+ node.right = rightNode;
2377
+ queue.push(rightNode);
2378
+ }
2379
+ }
2380
+ return root;
2381
+ }
2382
+ function materializeTreeInput(value) {
2383
+ if (value === null || value === void 0) return value;
2384
+ if (Array.isArray(value)) {
2385
+ return buildTreeNodeFromLevelOrder(value);
2386
+ }
2387
+ if (!isPlainObjectRecord(value)) {
2388
+ return value;
2389
+ }
2390
+ const record = value;
2391
+ if (isLikelyTreeNodeValue(record)) {
2392
+ const node = {
2393
+ val: record.val ?? record.value ?? null,
2394
+ value: record.val ?? record.value ?? null,
2395
+ left: materializeTreeInput(record.left ?? null),
2396
+ right: materializeTreeInput(record.right ?? null)
2397
+ };
2398
+ for (const [key, nested] of Object.entries(record)) {
2399
+ if (key === "__id__" || key === "__type__" || key === "val" || key === "value" || key === "left" || key === "right") continue;
2400
+ node[key] = materializeTreeInput(nested);
2401
+ }
2402
+ return node;
2403
+ }
2404
+ const taggedRecord = value;
2405
+ if (taggedRecord.__type__ === "TreeNode") {
2406
+ const node = {
2407
+ val: taggedRecord.val ?? taggedRecord.value ?? null,
2408
+ value: taggedRecord.val ?? taggedRecord.value ?? null,
2409
+ left: materializeTreeInput(taggedRecord.left ?? null),
2410
+ right: materializeTreeInput(taggedRecord.right ?? null)
2411
+ };
2412
+ for (const [key, nested] of Object.entries(taggedRecord)) {
2413
+ if (key === "__id__" || key === "__type__" || key === "val" || key === "value" || key === "left" || key === "right") continue;
2414
+ node[key] = materializeTreeInput(nested);
2415
+ }
2416
+ return node;
2417
+ }
2418
+ return value;
2419
+ }
2420
+ function materializeListInput(value, refs = /* @__PURE__ */ new Map(), materialized = /* @__PURE__ */ new WeakMap()) {
2421
+ if (value === null || value === void 0) return value;
2422
+ if (Array.isArray(value)) {
2423
+ if (value.length === 0) return null;
2424
+ const head = {
2425
+ val: value[0],
2426
+ value: value[0],
2427
+ next: null
2428
+ };
2429
+ let current = head;
2430
+ for (let i = 1; i < value.length; i++) {
2431
+ const nextNode = { val: value[i], value: value[i], next: null };
2432
+ current.next = nextNode;
2433
+ current = nextNode;
2434
+ }
2435
+ return head;
2436
+ }
2437
+ if (!isPlainObjectRecord(value)) {
2438
+ return value;
2439
+ }
2440
+ const record = value;
2441
+ if (typeof record.__ref__ === "string") {
2442
+ return refs.get(record.__ref__) ?? null;
2443
+ }
2444
+ const taggedRecord = value;
2445
+ if (isLikelyListNodeValue(record) || taggedRecord.__type__ === "ListNode") {
2446
+ const existingMaterialized = materialized.get(record);
2447
+ if (existingMaterialized) {
2448
+ return existingMaterialized;
2449
+ }
2450
+ const node = {
2451
+ val: taggedRecord.val ?? taggedRecord.value ?? null,
2452
+ value: taggedRecord.val ?? taggedRecord.value ?? null,
2453
+ next: null
2454
+ };
2455
+ materialized.set(record, node);
2456
+ if (typeof taggedRecord.__id__ === "string" && taggedRecord.__id__.length > 0) {
2457
+ refs.set(taggedRecord.__id__, node);
2458
+ }
2459
+ node.next = materializeListInput(taggedRecord.next ?? null, refs, materialized);
2460
+ for (const [key, nested] of Object.entries(taggedRecord)) {
2461
+ if (key === "__id__" || key === "__type__" || key === "__class__" || key === "val" || key === "value" || key === "next") continue;
2462
+ node[key] = materializeListInput(nested, refs, materialized);
2463
+ }
2464
+ return node;
2465
+ }
2466
+ return value;
2467
+ }
2468
+ function detectMaterializerKind(ts, typeNode) {
2469
+ if (!typeNode) return null;
2470
+ if (ts.isParenthesizedTypeNode(typeNode)) {
2471
+ return detectMaterializerKind(ts, typeNode.type);
2472
+ }
2473
+ if (ts.isUnionTypeNode(typeNode)) {
2474
+ for (const child of typeNode.types) {
2475
+ const resolved = detectMaterializerKind(ts, child);
2476
+ if (resolved) return resolved;
2477
+ }
2478
+ return null;
2479
+ }
2480
+ if (ts.isTypeReferenceNode(typeNode)) {
2481
+ const typeNameText = typeNode.typeName.getText();
2482
+ if (typeNameText === "TreeNode") return "tree";
2483
+ if (typeNameText === "ListNode") return "list";
2484
+ return null;
2485
+ }
2486
+ return null;
2487
+ }
2488
+ function collectInputMaterializers(ts, functionLikeNode) {
2489
+ const out = {};
2490
+ for (const parameter of functionLikeNode.parameters ?? []) {
2491
+ if (!ts.isIdentifier(parameter.name)) continue;
2492
+ if (parameter.name.text === "this") continue;
2493
+ const kind = detectMaterializerKind(ts, parameter.type);
2494
+ if (kind) {
2495
+ out[parameter.name.text] = kind;
2496
+ }
2497
+ }
2498
+ return out;
2499
+ }
2500
+ async function resolveInputMaterializers(code, functionName, executionStyle, language) {
2501
+ if (!functionName || executionStyle === "ops-class" || language !== "typescript") {
2502
+ return {};
2503
+ }
2504
+ try {
2505
+ const ts = await getTypeScriptModule();
2506
+ const sourceFile = ts.createSourceFile(
2507
+ "runtime-input.ts",
2508
+ code,
2509
+ ts.ScriptTarget.ES2020,
2510
+ true,
2511
+ ts.ScriptKind.TS
2512
+ );
2513
+ const target = findFunctionLikeNode(ts, sourceFile, functionName, executionStyle);
2514
+ if (!target) return {};
2515
+ return collectInputMaterializers(ts, target);
2516
+ } catch {
2517
+ return {};
2518
+ }
2519
+ }
2520
+ function applyInputMaterializers(inputs, materializers) {
2521
+ if (Object.keys(materializers).length === 0) return inputs;
2522
+ const next = { ...inputs };
2523
+ for (const [name, kind] of Object.entries(materializers)) {
2524
+ if (!Object.prototype.hasOwnProperty.call(next, name)) continue;
2525
+ next[name] = kind === "tree" ? materializeTreeInput(next[name]) : materializeListInput(next[name]);
2526
+ }
2527
+ return next;
2528
+ }
2230
2529
  function collectSimpleParameterNames(ts, functionLikeNode) {
2231
2530
  const names = [];
2232
2531
  for (const parameter of functionLikeNode.parameters ?? []) {
@@ -2280,14 +2579,20 @@ function findFunctionLikeNode(ts, sourceFile, functionName, executionStyle) {
2280
2579
  visit(sourceFile);
2281
2580
  return found;
2282
2581
  }
2283
- async function resolveOrderedInputKeys(code, functionName, inputs, executionStyle) {
2582
+ async function resolveOrderedInputKeys(code, functionName, inputs, executionStyle, language = "javascript") {
2284
2583
  const fallbackKeys = Object.keys(inputs);
2285
2584
  if (!functionName || executionStyle === "ops-class" || fallbackKeys.length <= 1) {
2286
2585
  return fallbackKeys;
2287
2586
  }
2288
2587
  try {
2289
2588
  const ts = await getTypeScriptModule();
2290
- const sourceFile = ts.createSourceFile("runtime-input.js", code, ts.ScriptTarget.ES2020, true, ts.ScriptKind.JS);
2589
+ const sourceFile = ts.createSourceFile(
2590
+ `runtime-input.${language === "typescript" ? "ts" : "js"}`,
2591
+ code,
2592
+ ts.ScriptTarget.ES2020,
2593
+ true,
2594
+ language === "typescript" ? ts.ScriptKind.TS : ts.ScriptKind.JS
2595
+ );
2291
2596
  const target = findFunctionLikeNode(ts, sourceFile, functionName, executionStyle);
2292
2597
  if (!target) {
2293
2598
  return fallbackKeys;
@@ -2431,20 +2736,22 @@ async function transpileTypeScript(code) {
2431
2736
  }
2432
2737
  return transpiled.outputText;
2433
2738
  }
2434
- async function executeJavaScriptCode(code, functionName, inputs, executionStyle = "function") {
2739
+ async function executeJavaScriptCode(code, functionName, inputs, executionStyle = "function", language = "javascript") {
2435
2740
  const consoleOutput = [];
2436
2741
  const consoleProxy = createConsoleProxy(consoleOutput);
2437
2742
  const normalizedInputs = normalizeInputs(inputs);
2743
+ const materializers = await resolveInputMaterializers(code, functionName, executionStyle, language);
2744
+ const materializedInputs = applyInputMaterializers(normalizedInputs, materializers);
2438
2745
  try {
2439
2746
  let output;
2440
2747
  if (executionStyle === "ops-class") {
2441
- const { operations, argumentsList } = getOpsClassInputs(normalizedInputs);
2748
+ const { operations, argumentsList } = getOpsClassInputs(materializedInputs);
2442
2749
  const runner = buildRunner(code, executionStyle, []);
2443
2750
  output = await Promise.resolve(runner(consoleProxy, functionName, operations, argumentsList));
2444
2751
  } else {
2445
- const inputKeys = await resolveOrderedInputKeys(code, functionName, normalizedInputs, executionStyle);
2752
+ const inputKeys = await resolveOrderedInputKeys(code, functionName, materializedInputs, executionStyle, language);
2446
2753
  const argNames = inputKeys.map((_, index) => `__arg${index}`);
2447
- const argValues = inputKeys.map((key) => normalizedInputs[key]);
2754
+ const argValues = inputKeys.map((key) => materializedInputs[key]);
2448
2755
  const runner = buildRunner(code, executionStyle, argNames);
2449
2756
  output = await Promise.resolve(runner(consoleProxy, functionName, ...argValues));
2450
2757
  }
@@ -2463,9 +2770,9 @@ async function executeJavaScriptCode(code, functionName, inputs, executionStyle
2463
2770
  };
2464
2771
  }
2465
2772
  }
2466
- async function executeJavaScriptWithTracing(code, functionName, inputs, executionStyle = "function") {
2773
+ async function executeJavaScriptWithTracing(code, functionName, inputs, executionStyle = "function", language = "javascript") {
2467
2774
  const startedAt = performanceNow();
2468
- const codeResult = await executeJavaScriptCode(code, functionName ?? "", inputs, executionStyle);
2775
+ const codeResult = await executeJavaScriptCode(code, functionName ?? "", inputs, executionStyle, language);
2469
2776
  const executionTimeMs = performanceNow() - startedAt;
2470
2777
  if (!codeResult.success) {
2471
2778
  return {
@@ -2490,8 +2797,11 @@ async function executeJavaScriptWithTracing(code, functionName, inputs, executio
2490
2797
  };
2491
2798
  }
2492
2799
  async function executeTypeScriptCode(code, functionName, inputs, executionStyle = "function") {
2800
+ const normalizedInputs = normalizeInputs(inputs);
2801
+ const materializers = await resolveInputMaterializers(code, functionName, executionStyle, "typescript");
2802
+ const materializedInputs = applyInputMaterializers(normalizedInputs, materializers);
2493
2803
  const transpiledCode = await transpileTypeScript(code);
2494
- return executeJavaScriptCode(transpiledCode, functionName, inputs, executionStyle);
2804
+ return executeJavaScriptCode(transpiledCode, functionName, materializedInputs, executionStyle, "typescript");
2495
2805
  }
2496
2806
  export {
2497
2807
  DEFAULT_BROWSER_HARNESS_ASSET_RELATIVE_PATHS,