@tracecode/harness 0.6.2 → 0.6.6

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.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,29 @@ All notable changes to this project are documented here.
4
4
 
5
5
  This repo uses Git tags as release boundaries. Version notes below summarize what shipped in each tagged release.
6
6
 
7
+ ## [0.6.6] - 2026-04-27
8
+
9
+ ### Fixed
10
+
11
+ - Improved Java worker rewrite-failure handling so parser failures are surfaced as user-facing syntax errors instead of opaque Java object strings.
12
+ - Added a compile probe fallback when Java source rewriting fails, allowing harness clients to receive compiler stderr/stdout diagnostics in the standard failed execution payload.
13
+
14
+ ## [0.6.5] - 2026-04-26
15
+
16
+ ### Added
17
+
18
+ - Added Java visualizer harness support for public runtime trace metadata used by the app visualization path.
19
+
20
+ ### Fixed
21
+
22
+ - Improved Java trace bookkeeping parity so emitted trace steps line up with the shared runtime contract.
23
+ - Fixed Python runtime access attribution regressions caught while validating cross-language visualization parity.
24
+ - Preserved Java script-mode tracing behavior through the updated harness assets.
25
+
26
+ ### Notes
27
+
28
+ - `0.6.5` skips `0.6.4` intentionally because this release bundles the larger Java visualization compatibility update.
29
+
7
30
  ## [0.6.2] - 2026-04-23
8
31
 
9
32
  ### Added
package/dist/browser.cjs CHANGED
@@ -1223,6 +1223,16 @@ function parseScalar(raw) {
1223
1223
  }
1224
1224
  return raw;
1225
1225
  }
1226
+ function normalizeJavaSerializedResult(output) {
1227
+ if (typeof output !== "string") {
1228
+ return output;
1229
+ }
1230
+ try {
1231
+ return JSON.parse(output);
1232
+ } catch {
1233
+ return output;
1234
+ }
1235
+ }
1226
1236
  function parseKeyValuePairs(fragment) {
1227
1237
  const variables = {};
1228
1238
  const matches = Array.from(fragment.matchAll(/\b([A-Za-z_][A-Za-z0-9_.]*)=/g));
@@ -1403,10 +1413,29 @@ function parseAccessEvent(payload) {
1403
1413
  pathDepth: 1
1404
1414
  }];
1405
1415
  }
1416
+ const indexedMutatingCall = payload.match(/^mutate-indexed ([A-Za-z_][A-Za-z0-9_]*)\[(\d+)\] method=([A-Za-z_][A-Za-z0-9_]*)$/);
1417
+ if (indexedMutatingCall) {
1418
+ return [{
1419
+ variable: indexedMutatingCall[1],
1420
+ kind: "mutating-call",
1421
+ indices: [Number.parseInt(indexedMutatingCall[2], 10)],
1422
+ method: indexedMutatingCall[3],
1423
+ pathDepth: 1
1424
+ }];
1425
+ }
1426
+ const keyedCall = payload.match(/^keyed-call ([A-Za-z_][A-Za-z0-9_]*) method=([A-Za-z_][A-Za-z0-9_]*)(?:\s+.*)?$/);
1427
+ if (keyedCall) {
1428
+ return [{
1429
+ variable: keyedCall[1],
1430
+ kind: "mutating-call",
1431
+ method: keyedCall[2],
1432
+ pathDepth: 1
1433
+ }];
1434
+ }
1406
1435
  return void 0;
1407
1436
  }
1408
1437
  function parseStructureState(payload) {
1409
- const match = payload.match(/^state (linked-list|tree) ([A-Za-z_][A-Za-z0-9_]*)=(.+)$/);
1438
+ const match = payload.match(/^state (linked-list|tree|graph-adjacency) ([A-Za-z_][A-Za-z0-9_]*)=(.+)$/);
1410
1439
  if (!match) return null;
1411
1440
  return {
1412
1441
  structure: match[1],
@@ -1422,6 +1451,22 @@ function parseObjectState(payload) {
1422
1451
  visualization: JSON.parse(match[2])
1423
1452
  };
1424
1453
  }
1454
+ function parseMapState(payload) {
1455
+ const match = payload.match(/^map-state ([A-Za-z_][A-Za-z0-9_]*)=(.+)$/);
1456
+ if (!match) return null;
1457
+ return {
1458
+ variable: match[1],
1459
+ visualization: JSON.parse(match[2])
1460
+ };
1461
+ }
1462
+ function parseSetState(payload) {
1463
+ const match = payload.match(/^set-state ([A-Za-z_][A-Za-z0-9_]*)=(.+)$/);
1464
+ if (!match) return null;
1465
+ return {
1466
+ variable: match[1],
1467
+ visualization: JSON.parse(match[2])
1468
+ };
1469
+ }
1425
1470
  function parseObjectFieldEvent(payload) {
1426
1471
  const match = payload.match(/^(access|write) ([A-Za-z_][A-Za-z0-9_]*)\.([A-Za-z_][A-Za-z0-9_]*)=(.+)$/);
1427
1472
  if (!match) return null;
@@ -1431,6 +1476,9 @@ function parseObjectFieldEvent(payload) {
1431
1476
  value: parseScalar(match[4])
1432
1477
  };
1433
1478
  }
1479
+ function isArrayLengthAccessEvent(payload) {
1480
+ return /^access [A-Za-z_][A-Za-z0-9_]*\.length=\d+$/.test(payload);
1481
+ }
1434
1482
  function buildFieldVisualization(event) {
1435
1483
  return {
1436
1484
  objectKinds: {
@@ -1510,12 +1558,13 @@ function filterStructuredVariables(variables) {
1510
1558
  }
1511
1559
  return Object.fromEntries(entries);
1512
1560
  }
1513
- function appendJavaTraceStep(trace, step, pendingAccesses) {
1561
+ function appendJavaTraceStep(trace, step, pendingAccesses, options = {}) {
1514
1562
  const nextStep = pendingAccesses.length > 0 ? { ...step, accesses: [...pendingAccesses] } : step;
1515
1563
  pendingAccesses.length = 0;
1516
- if (!maybeMergeConsecutiveLineStep(trace, nextStep)) {
1517
- trace.push(nextStep);
1564
+ if (options.allowMerge !== false && maybeMergeConsecutiveLineStep(trace, nextStep)) {
1565
+ return;
1518
1566
  }
1567
+ trace.push(nextStep);
1519
1568
  }
1520
1569
  function mergeIntoPreviousMatchingLineStep(trace, line, currentFunction, currentCallStack, patch) {
1521
1570
  const candidate = trace.at(-1);
@@ -1549,11 +1598,14 @@ function eventsToRawTrace(events, sourceText) {
1549
1598
  const stack = [];
1550
1599
  const pendingAccesses = [];
1551
1600
  let currentFunction = "<module>";
1601
+ let previousRawLine = null;
1552
1602
  const lineRemap = buildLineRemap(sourceText);
1553
1603
  const declarationLines = buildMethodDeclarationLineSet(sourceText);
1554
1604
  for (const rawEvent of events) {
1555
1605
  if (rawEvent === "clear" || rawEvent === "reset") continue;
1556
1606
  const metadata = extractLineMetadata(rawEvent);
1607
+ const previousEventRawLine = previousRawLine;
1608
+ previousRawLine = metadata.line;
1557
1609
  const line = lineRemap?.get(metadata.line) ?? metadata.line;
1558
1610
  const payload = metadata.payload;
1559
1611
  const isDeclarationLine = declarationLines?.has(line) === true;
@@ -1561,28 +1613,31 @@ function eventsToRawTrace(events, sourceText) {
1561
1613
  const match = payload.match(/^call\s+(\S+)(?:\s+(.*))?$/);
1562
1614
  const functionName = match?.[1] ?? currentFunction;
1563
1615
  const argsFragment = match?.[2] ?? "";
1564
- Object.assign(variables, parseKeyValuePairs(argsFragment));
1616
+ const args = parseKeyValuePairs(argsFragment);
1617
+ Object.assign(variables, args);
1565
1618
  currentFunction = functionName || currentFunction;
1566
- stack.push({ function: currentFunction, line });
1619
+ stack.push({ function: currentFunction, line, args });
1567
1620
  appendJavaTraceStep(trace, {
1568
1621
  line,
1569
1622
  event: "call",
1570
1623
  function: currentFunction,
1571
1624
  variables: { ...variables },
1572
- callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} }))
1625
+ callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: { ...frame.args } }))
1573
1626
  }, pendingAccesses);
1574
1627
  continue;
1575
1628
  }
1576
1629
  if (payload.startsWith("return ")) {
1577
- const match = payload.match(/^return\s+(\S+)$/);
1630
+ const match = payload.match(/^return\s+(\S+)(?:\s+value=(.*))?$/);
1578
1631
  const functionName = match?.[1] ?? currentFunction;
1632
+ const returnValue = match?.[2] !== void 0 ? parseScalar(match[2].trim()) : void 0;
1579
1633
  const returnVariables = functionName === "<module>" ? { ...variables } : filterStructuredVariables(variables) ?? {};
1580
1634
  appendJavaTraceStep(trace, {
1581
1635
  line,
1582
1636
  event: "return",
1583
1637
  function: functionName || currentFunction,
1584
1638
  variables: returnVariables,
1585
- callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} }))
1639
+ callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: { ...frame.args } })),
1640
+ ...returnValue !== void 0 ? { returnValue } : {}
1586
1641
  }, pendingAccesses);
1587
1642
  stack.pop();
1588
1643
  currentFunction = stack[stack.length - 1]?.function ?? "<module>";
@@ -1597,8 +1652,8 @@ function eventsToRawTrace(events, sourceText) {
1597
1652
  event: "line",
1598
1653
  function: currentFunction,
1599
1654
  variables: { ...variables },
1600
- ...stack.length > 0 ? { callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })) } : {}
1601
- }, pendingAccesses);
1655
+ ...stack.length > 0 ? { callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: { ...frame.args } })) } : {}
1656
+ }, pendingAccesses, { allowMerge: previousEventRawLine !== metadata.line });
1602
1657
  continue;
1603
1658
  }
1604
1659
  const structureState = parseStructureState(payload);
@@ -1610,7 +1665,7 @@ function eventsToRawTrace(events, sourceText) {
1610
1665
  event: "line",
1611
1666
  function: currentFunction,
1612
1667
  variables: { ...variables },
1613
- callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })),
1668
+ callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: { ...frame.args } })),
1614
1669
  visualization: {
1615
1670
  objectKinds: { ...objectKinds }
1616
1671
  }
@@ -1625,7 +1680,7 @@ function eventsToRawTrace(events, sourceText) {
1625
1680
  event: "line",
1626
1681
  function: currentFunction,
1627
1682
  variables: { ...variables },
1628
- callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })),
1683
+ callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: { ...frame.args } })),
1629
1684
  visualization: {
1630
1685
  objectKinds: { [objectState.variable]: "object" },
1631
1686
  hashMaps: [objectState.visualization]
@@ -1633,10 +1688,56 @@ function eventsToRawTrace(events, sourceText) {
1633
1688
  }, pendingAccesses);
1634
1689
  continue;
1635
1690
  }
1691
+ const mapState = parseMapState(payload);
1692
+ if (mapState) {
1693
+ const entries = mapState.visualization.entries.map((entry) => [entry.key, entry.value]);
1694
+ variables[mapState.variable] = { __type__: "map", entries };
1695
+ appendJavaTraceStep(trace, {
1696
+ line,
1697
+ event: "line",
1698
+ function: currentFunction,
1699
+ variables: { ...variables },
1700
+ callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: { ...frame.args } })),
1701
+ visualization: {
1702
+ objectKinds: { [mapState.variable]: "map" },
1703
+ hashMaps: [mapState.visualization]
1704
+ }
1705
+ }, pendingAccesses);
1706
+ continue;
1707
+ }
1708
+ const setState = parseSetState(payload);
1709
+ if (setState) {
1710
+ const values = setState.visualization.entries.map((entry) => entry.key);
1711
+ variables[setState.variable] = { __type__: "set", values };
1712
+ appendJavaTraceStep(trace, {
1713
+ line,
1714
+ event: "line",
1715
+ function: currentFunction,
1716
+ variables: { ...variables },
1717
+ callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: { ...frame.args } })),
1718
+ visualization: {
1719
+ objectKinds: { [setState.variable]: "set" },
1720
+ hashMaps: [setState.visualization]
1721
+ }
1722
+ }, pendingAccesses);
1723
+ continue;
1724
+ }
1725
+ if (isArrayLengthAccessEvent(payload)) {
1726
+ continue;
1727
+ }
1728
+ const accesses = parseAccessEvent(payload);
1729
+ if (accesses) {
1730
+ const currentCallStack = stack.length > 0 ? stack.map((frame) => ({ function: frame.function, line: frame.line, args: { ...frame.args } })) : void 0;
1731
+ if (mergeAccessesIntoPreviousMatchingLineStep(trace, line, currentFunction, currentCallStack, accesses)) {
1732
+ continue;
1733
+ }
1734
+ pendingAccesses.push(...accesses);
1735
+ continue;
1736
+ }
1636
1737
  const objectField = parseObjectFieldEvent(payload);
1637
1738
  if (objectField) {
1638
1739
  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;
1740
+ const currentCallStack = stack.length > 0 ? stack.map((frame) => ({ function: frame.function, line: frame.line, args: { ...frame.args } })) : void 0;
1640
1741
  if (mergeIntoPreviousMatchingLineStep(trace, line, currentFunction, currentCallStack, {
1641
1742
  variables: { ...variables },
1642
1743
  accesses: void 0,
@@ -1649,27 +1750,18 @@ function eventsToRawTrace(events, sourceText) {
1649
1750
  event: "line",
1650
1751
  function: currentFunction,
1651
1752
  variables: { ...variables },
1652
- callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })),
1753
+ callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: { ...frame.args } })),
1653
1754
  visualization: buildFieldVisualization(objectField)
1654
1755
  }, pendingAccesses);
1655
1756
  continue;
1656
1757
  }
1657
1758
  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
1759
  appendJavaTraceStep(trace, {
1668
1760
  line,
1669
1761
  event: "line",
1670
1762
  function: currentFunction,
1671
1763
  variables: { ...variables },
1672
- ...stack.length > 0 ? { callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: {} })) } : {}
1764
+ ...stack.length > 0 ? { callStack: stack.map((frame) => ({ function: frame.function, line: frame.line, args: { ...frame.args } })) } : {}
1673
1765
  }, pendingAccesses);
1674
1766
  }
1675
1767
  if (pendingAccesses.length > 0 && trace.length > 0) {
@@ -1678,11 +1770,11 @@ function eventsToRawTrace(events, sourceText) {
1678
1770
  }
1679
1771
  return trace;
1680
1772
  }
1681
- function buildJavaExecutionResult(output, events, executionTimeMs = 0, traceLimitExceeded, timeoutReason, maxTraceSteps, sourceText) {
1773
+ function buildJavaExecutionResult(output, events, executionTimeMs = 0, traceLimitExceeded, timeoutReason, maxTraceSteps, sourceText, options = {}) {
1682
1774
  const trace = eventsToRawTrace(events, sourceText);
1683
1775
  return {
1684
1776
  success: true,
1685
- output,
1777
+ output: options.outputIsSerialized === false ? output : normalizeJavaSerializedResult(output),
1686
1778
  trace,
1687
1779
  executionTimeMs,
1688
1780
  consoleOutput: [],
@@ -1740,7 +1832,8 @@ var JavaRuntimeClient = class {
1740
1832
  rawResult.traceLimitExceeded,
1741
1833
  rawResult.timeoutReason,
1742
1834
  void 0,
1743
- rawResult.sourceText
1835
+ rawResult.sourceText,
1836
+ { outputIsSerialized: false }
1744
1837
  )
1745
1838
  );
1746
1839
  return {