donobu 5.36.0 → 5.36.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.
@@ -982,17 +982,17 @@ function renderSteps(steps, stepScreenshots, nativeSteps, aiInvocations, outputD
982
982
  tEnd: ns.endWallTime,
983
983
  children: buildNativeTree(ns.children),
984
984
  }));
985
- const roots = buildNativeTree(nativeSteps);
986
- // Place a node into the deepest container whose [t, tEnd] window
987
- // contains its [tStart, tEnd]. Returns true on placement. Both native
988
- // steps and AI invocations are eligible parents.
989
- const placeNode = (nodes, leaf, tStart, tEnd) => {
985
+ let roots = buildNativeTree(nativeSteps);
986
+ // Place a leaf into the deepest container whose [t, tEnd] window
987
+ // contains its [tStart, tEnd]. Used for Donobu screenshots, which can
988
+ // never gain new children, so no absorption is needed.
989
+ const placeLeaf = (nodes, leaf, tStart, tEnd) => {
990
990
  for (const n of nodes) {
991
991
  if (n.kind !== 'native' && n.kind !== 'ai') {
992
992
  continue;
993
993
  }
994
994
  if (tStart >= n.t && tEnd <= n.tEnd) {
995
- if (!placeNode(n.children, leaf, tStart, tEnd)) {
995
+ if (!placeLeaf(n.children, leaf, tStart, tEnd)) {
996
996
  n.children.push(leaf);
997
997
  }
998
998
  return true;
@@ -1000,6 +1000,34 @@ function renderSteps(steps, stepScreenshots, nativeSteps, aiInvocations, outputD
1000
1000
  }
1001
1001
  return false;
1002
1002
  };
1003
+ // Place a container into the tree at the deepest level whose window
1004
+ // contains it. Once placed, absorb any pre-existing siblings whose
1005
+ // windows fall fully inside the container's window — this matters when
1006
+ // a cached `page.ai` runs raw `expect(...)` calls that Playwright's
1007
+ // `_steps` recorded as bare native steps at the parent level. Without
1008
+ // absorption they'd render as siblings of the wrapper instead of
1009
+ // children. Returns the (possibly rebuilt) `level` array.
1010
+ const placeContainer = (level, container) => {
1011
+ for (const n of level) {
1012
+ if ((n.kind === 'native' || n.kind === 'ai') &&
1013
+ container.t >= n.t &&
1014
+ container.tEnd <= n.tEnd) {
1015
+ n.children = placeContainer(n.children, container);
1016
+ return level;
1017
+ }
1018
+ }
1019
+ const remaining = [];
1020
+ for (const child of level) {
1021
+ if (child.t >= container.t && child.tEnd <= container.tEnd) {
1022
+ container.children.push(child);
1023
+ }
1024
+ else {
1025
+ remaining.push(child);
1026
+ }
1027
+ }
1028
+ remaining.push(container);
1029
+ return remaining;
1030
+ };
1003
1031
  // AI invocations placed first, longer-window first so an outer cached
1004
1032
  // `page.ai` is in place before its inner `page.ai.assert` lands.
1005
1033
  const sortedInvocations = [...aiInvocations].sort((a, b) => b.endedAt - b.startedAt - (a.endedAt - a.startedAt));
@@ -1011,9 +1039,7 @@ function renderSteps(steps, stepScreenshots, nativeSteps, aiInvocations, outputD
1011
1039
  tEnd: inv.endedAt,
1012
1040
  children: [],
1013
1041
  };
1014
- if (!placeNode(roots, node, inv.startedAt, inv.endedAt)) {
1015
- roots.push(node);
1016
- }
1042
+ roots = placeContainer(roots, node);
1017
1043
  }
1018
1044
  for (const ss of stepScreenshots) {
1019
1045
  const d = {
@@ -1022,7 +1048,7 @@ function renderSteps(steps, stepScreenshots, nativeSteps, aiInvocations, outputD
1022
1048
  t: ss.startedAt,
1023
1049
  tEnd: ss.completedAt,
1024
1050
  };
1025
- if (!placeNode(roots, d, ss.startedAt, ss.completedAt)) {
1051
+ if (!placeLeaf(roots, d, ss.startedAt, ss.completedAt)) {
1026
1052
  roots.push(d);
1027
1053
  }
1028
1054
  }
@@ -982,17 +982,17 @@ function renderSteps(steps, stepScreenshots, nativeSteps, aiInvocations, outputD
982
982
  tEnd: ns.endWallTime,
983
983
  children: buildNativeTree(ns.children),
984
984
  }));
985
- const roots = buildNativeTree(nativeSteps);
986
- // Place a node into the deepest container whose [t, tEnd] window
987
- // contains its [tStart, tEnd]. Returns true on placement. Both native
988
- // steps and AI invocations are eligible parents.
989
- const placeNode = (nodes, leaf, tStart, tEnd) => {
985
+ let roots = buildNativeTree(nativeSteps);
986
+ // Place a leaf into the deepest container whose [t, tEnd] window
987
+ // contains its [tStart, tEnd]. Used for Donobu screenshots, which can
988
+ // never gain new children, so no absorption is needed.
989
+ const placeLeaf = (nodes, leaf, tStart, tEnd) => {
990
990
  for (const n of nodes) {
991
991
  if (n.kind !== 'native' && n.kind !== 'ai') {
992
992
  continue;
993
993
  }
994
994
  if (tStart >= n.t && tEnd <= n.tEnd) {
995
- if (!placeNode(n.children, leaf, tStart, tEnd)) {
995
+ if (!placeLeaf(n.children, leaf, tStart, tEnd)) {
996
996
  n.children.push(leaf);
997
997
  }
998
998
  return true;
@@ -1000,6 +1000,34 @@ function renderSteps(steps, stepScreenshots, nativeSteps, aiInvocations, outputD
1000
1000
  }
1001
1001
  return false;
1002
1002
  };
1003
+ // Place a container into the tree at the deepest level whose window
1004
+ // contains it. Once placed, absorb any pre-existing siblings whose
1005
+ // windows fall fully inside the container's window — this matters when
1006
+ // a cached `page.ai` runs raw `expect(...)` calls that Playwright's
1007
+ // `_steps` recorded as bare native steps at the parent level. Without
1008
+ // absorption they'd render as siblings of the wrapper instead of
1009
+ // children. Returns the (possibly rebuilt) `level` array.
1010
+ const placeContainer = (level, container) => {
1011
+ for (const n of level) {
1012
+ if ((n.kind === 'native' || n.kind === 'ai') &&
1013
+ container.t >= n.t &&
1014
+ container.tEnd <= n.tEnd) {
1015
+ n.children = placeContainer(n.children, container);
1016
+ return level;
1017
+ }
1018
+ }
1019
+ const remaining = [];
1020
+ for (const child of level) {
1021
+ if (child.t >= container.t && child.tEnd <= container.tEnd) {
1022
+ container.children.push(child);
1023
+ }
1024
+ else {
1025
+ remaining.push(child);
1026
+ }
1027
+ }
1028
+ remaining.push(container);
1029
+ return remaining;
1030
+ };
1003
1031
  // AI invocations placed first, longer-window first so an outer cached
1004
1032
  // `page.ai` is in place before its inner `page.ai.assert` lands.
1005
1033
  const sortedInvocations = [...aiInvocations].sort((a, b) => b.endedAt - b.startedAt - (a.endedAt - a.startedAt));
@@ -1011,9 +1039,7 @@ function renderSteps(steps, stepScreenshots, nativeSteps, aiInvocations, outputD
1011
1039
  tEnd: inv.endedAt,
1012
1040
  children: [],
1013
1041
  };
1014
- if (!placeNode(roots, node, inv.startedAt, inv.endedAt)) {
1015
- roots.push(node);
1016
- }
1042
+ roots = placeContainer(roots, node);
1017
1043
  }
1018
1044
  for (const ss of stepScreenshots) {
1019
1045
  const d = {
@@ -1022,7 +1048,7 @@ function renderSteps(steps, stepScreenshots, nativeSteps, aiInvocations, outputD
1022
1048
  t: ss.startedAt,
1023
1049
  tEnd: ss.completedAt,
1024
1050
  };
1025
- if (!placeNode(roots, d, ss.startedAt, ss.completedAt)) {
1051
+ if (!placeLeaf(roots, d, ss.startedAt, ss.completedAt)) {
1026
1052
  roots.push(d);
1027
1053
  }
1028
1054
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "donobu",
3
- "version": "5.36.0",
3
+ "version": "5.36.1",
4
4
  "description": "Create browser automations with an LLM agent and replay them as Playwright scripts.",
5
5
  "main": "dist/main.js",
6
6
  "module": "dist/esm/main.js",