@agent-native/core 0.181.0 → 0.181.1-nightly-20260916141207

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 (21) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +27 -7
  3. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +45 -15
  4. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +35 -8
  5. package/corpus/templates/design/app/components/design/design-canvas/element-payload.ts +14 -0
  6. package/corpus/templates/design/app/pages/DesignEditor.tsx +18 -5
  7. package/corpus/templates/design/app/pages/design-editor/commands/record-pending-live-structure-edit.ts +9 -4
  8. package/corpus/templates/design/app/pages/design-editor/commands/screen-visual-structure-change.ts +3 -0
  9. package/corpus/templates/design/app/pages/design-editor/commands/start-sidebar-resize.ts +7 -2
  10. package/corpus/templates/design/app/pages/design-editor/commands/visual-structure-change.ts +2 -0
  11. package/corpus/templates/design/app/pages/design-editor/pending-edits.ts +4 -0
  12. package/corpus/templates/design/app/pages/design-editor/pending-structure-verification.ts +197 -147
  13. package/corpus/templates/design/changelog/2026-09-16-design-editor-agent-chat-uses-shared-conversation-tabs-and-s.md +6 -0
  14. package/corpus/templates/design/changelog/2026-09-16-visual-edits-stay-applied-after-replacements.md +5 -0
  15. package/dist/client/AgentPanel.d.ts +1 -1
  16. package/dist/client/AgentPanel.js +4 -4
  17. package/dist/collab/routes.d.ts +1 -1
  18. package/dist/mcp/screen-memory-stdio.d.ts +7 -7
  19. package/dist/notifications/routes.d.ts +3 -3
  20. package/dist/secrets/routes.d.ts +6 -6
  21. package/package.json +4 -4
package/corpus/README.md CHANGED
@@ -31,4 +31,4 @@ rg -n "defineAction|useActionQuery" node_modules/@agent-native/core/corpus
31
31
 
32
32
  ## Generated Counts
33
33
 
34
- - template files: 9430
34
+ - template files: 9432
@@ -1840,8 +1840,8 @@ export const editorChromeBridgeScript: string = `"use strict";
1840
1840
  }
1841
1841
  return !(isOverlayElement(el) || el.closest("[data-agent-native-edit-overlay]"));
1842
1842
  }
1843
- function serializeRuntimeLayerSnapshot() {
1844
- if (!document.body) return null;
1843
+ function serializeRuntimeLayerSnapshot(excludedRoot) {
1844
+ if (!document.body) return { ok: false, reason: "snapshot-unavailable" };
1845
1845
  var snapshotComputedProperties = [
1846
1846
  "box-sizing",
1847
1847
  "display",
@@ -1931,7 +1931,7 @@ export const editorChromeBridgeScript: string = `"use strict";
1931
1931
  for (var index = 0; index < sourceNodes.length && index < cloneNodes.length; index += 1) {
1932
1932
  var sourceNode = sourceNodes[index];
1933
1933
  var cloneNode = cloneNodes[index];
1934
- if (!isRuntimeLayerVisualNode(sourceNode)) {
1934
+ if (excludedRoot?.contains(sourceNode) || !isRuntimeLayerVisualNode(sourceNode)) {
1935
1935
  cloneNode.setAttribute("data-an-runtime-layer-remove", "true");
1936
1936
  continue;
1937
1937
  }
@@ -2026,8 +2026,10 @@ export const editorChromeBridgeScript: string = `"use strict";
2026
2026
  inlineSnapshotComputedStyle(document.body, cloneBody);
2027
2027
  cloneBody.setAttribute("data-an-runtime-layer-snapshot", "true");
2028
2028
  var html = "<!doctype html><html>" + cloneBody.outerHTML + "</html>";
2029
- if (html.length > 2e6) return null;
2029
+ if (html.length > 2e6)
2030
+ return { ok: false, reason: "snapshot-too-large" };
2030
2031
  return {
2032
+ ok: true,
2031
2033
  html,
2032
2034
  nodeCount,
2033
2035
  documentId: runtimeDocumentId
@@ -2043,7 +2045,17 @@ export const editorChromeBridgeScript: string = `"use strict";
2043
2045
  runtimeLayerSnapshotTimer = null;
2044
2046
  runtimeLayerSnapshotMaxTimer = null;
2045
2047
  var snapshot = serializeRuntimeLayerSnapshot();
2046
- if (!snapshot || snapshot.html === lastRuntimeLayerSnapshotHtml) return;
2048
+ if (!snapshot.ok) {
2049
+ window.parent.postMessage(
2050
+ {
2051
+ type: "agent-native:runtime-layer-snapshot-error",
2052
+ payload: snapshot
2053
+ },
2054
+ "*"
2055
+ );
2056
+ return;
2057
+ }
2058
+ if (snapshot.html === lastRuntimeLayerSnapshotHtml) return;
2047
2059
  lastRuntimeLayerSnapshotHtml = snapshot.html;
2048
2060
  window.parent.postMessage(
2049
2061
  {
@@ -9739,7 +9751,7 @@ export const editorChromeBridgeScript: string = `"use strict";
9739
9751
  correctAbsoluteMemberClientPosition(el, desiredDropPoint);
9740
9752
  publishSourceDocumentProvenance(void 0, true);
9741
9753
  }
9742
- function postVisualStructureChange(el, target, origin, insertedHtml, replaced) {
9754
+ function postVisualStructureChange(el, target, origin, insertedHtml, replaced, replacementSnapshotHtml) {
9743
9755
  if (!el || !target || !target.anchor) return;
9744
9756
  dndLog("post:structure-change", {
9745
9757
  el: getSelector(el),
@@ -9770,6 +9782,7 @@ export const editorChromeBridgeScript: string = `"use strict";
9770
9782
  // element the source file has never contained.
9771
9783
  insertedHtml: typeof insertedHtml === "string" ? insertedHtml : void 0,
9772
9784
  replaced: replaced === true ? true : void 0,
9785
+ replacementSnapshotHtml,
9773
9786
  sourceRect: rectInfoForElement(el),
9774
9787
  anchorRect: rectInfoForElement(target.anchor),
9775
9788
  payload: getElementInfo(el),
@@ -14241,6 +14254,12 @@ export const editorChromeBridgeScript: string = `"use strict";
14241
14254
  }
14242
14255
  var replaceNextSibling = insertAnchor.nextSibling;
14243
14256
  replaceParent.insertBefore(parsedInsertEl, insertAnchor);
14257
+ var replacementSnapshot = serializeRuntimeLayerSnapshot(insertAnchor);
14258
+ if (!replacementSnapshot.ok) {
14259
+ parsedInsertEl.remove();
14260
+ rejectInsert("replacement-" + replacementSnapshot.reason);
14261
+ return;
14262
+ }
14244
14263
  selectedEl = parsedInsertEl;
14245
14264
  positionOverlay(selectionOverlay, selectedEl);
14246
14265
  refreshOverlays();
@@ -14254,7 +14273,8 @@ export const editorChromeBridgeScript: string = `"use strict";
14254
14273
  prevNextSibling: replaceNextSibling
14255
14274
  },
14256
14275
  parsedInsertEl.outerHTML,
14257
- true
14276
+ true,
14277
+ replacementSnapshot.html
14258
14278
  );
14259
14279
  replaceParent.removeChild(insertAnchor);
14260
14280
  refreshOverlays();
@@ -103,6 +103,7 @@ import {
103
103
  import {
104
104
  isComputedStyleMap,
105
105
  isElementInfoPayload,
106
+ parseRuntimeSnapshotHtml,
106
107
  } from "./design-canvas/element-payload";
107
108
  import {
108
109
  embeddedContentOffsetCss,
@@ -698,6 +699,7 @@ interface DesignCanvasProps {
698
699
  replacementSelector?: string;
699
700
  replacementSourceId?: string;
700
701
  replacementElementInfo?: ElementInfo;
702
+ replacementSnapshotHtml?: string;
701
703
  },
702
704
  ) => boolean | "pending" | void;
703
705
  onVisualDuplicateChange?: (
@@ -3298,24 +3300,34 @@ export function DesignCanvas({
3298
3300
  allowedOrigins: canvasBridgeAllowedOrigins,
3299
3301
  });
3300
3302
  if (trustedRuntimeVerificationFrame) {
3303
+ if (e.data?.type === "agent-native:runtime-layer-snapshot-error") {
3304
+ onRuntimeStructureInsertRejected?.(
3305
+ e.data.payload?.reason === "snapshot-too-large"
3306
+ ? "verification-snapshot-too-large"
3307
+ : "verification-snapshot-unavailable",
3308
+ );
3309
+ return;
3310
+ }
3301
3311
  if (e.data?.type !== "agent-native:runtime-layer-snapshot") return;
3302
3312
  const payload = e.data.payload;
3303
- if (
3304
- payload &&
3305
- typeof payload.html === "string" &&
3306
- payload.html.length <= 2_000_000 &&
3307
- Number.isFinite(payload.nodeCount)
3308
- ) {
3309
- onRuntimeVerificationSnapshot?.({
3310
- requestId: runtimeVerificationRequest.requestId,
3311
- html: payload.html,
3312
- nodeCount: Math.max(0, Math.floor(payload.nodeCount)),
3313
- documentId:
3314
- typeof payload.documentId === "string"
3315
- ? payload.documentId
3316
- : undefined,
3317
- });
3313
+ const snapshot = parseRuntimeSnapshotHtml(payload?.html);
3314
+ if (!snapshot.ok || !Number.isFinite(payload?.nodeCount)) {
3315
+ onRuntimeStructureInsertRejected?.(
3316
+ snapshot.ok
3317
+ ? "verification-snapshot-unavailable"
3318
+ : `verification-${snapshot.reason}`,
3319
+ );
3320
+ return;
3318
3321
  }
3322
+ onRuntimeVerificationSnapshot?.({
3323
+ requestId: runtimeVerificationRequest.requestId,
3324
+ html: snapshot.html,
3325
+ nodeCount: Math.max(0, Math.floor(payload.nodeCount)),
3326
+ documentId:
3327
+ typeof payload.documentId === "string"
3328
+ ? payload.documentId
3329
+ : undefined,
3330
+ });
3319
3331
  return;
3320
3332
  }
3321
3333
  const lateReadyRecovery =
@@ -3593,6 +3605,21 @@ export function DesignCanvas({
3593
3605
  });
3594
3606
  const requestId =
3595
3607
  typeof e.data.requestId === "string" ? e.data.requestId : undefined;
3608
+ const replacementSnapshot = replaced
3609
+ ? parseRuntimeSnapshotHtml(e.data.replacementSnapshotHtml)
3610
+ : undefined;
3611
+ if (replacementSnapshot?.ok === false) {
3612
+ if (requestId) {
3613
+ iframeRef.current?.contentWindow?.postMessage(
3614
+ { type: "visual-structure-ack", requestId, applied: false },
3615
+ "*",
3616
+ );
3617
+ }
3618
+ onRuntimeStructureInsertRejected?.(
3619
+ `replacement-${replacementSnapshot.reason}`,
3620
+ );
3621
+ return;
3622
+ }
3596
3623
  const sourceId =
3597
3624
  typeof e.data.sourceId === "string" ? e.data.sourceId : undefined;
3598
3625
  const anchorSourceId =
@@ -3667,6 +3694,9 @@ export function DesignCanvas({
3667
3694
  replaced: true as const,
3668
3695
  replacementSelector: selector,
3669
3696
  replacementSourceId: sourceId,
3697
+ replacementSnapshotHtml: replacementSnapshot?.ok
3698
+ ? replacementSnapshot.html
3699
+ : undefined,
3670
3700
  replacementElementInfo: isElementInfoPayload(e.data.payload)
3671
3701
  ? e.data.payload
3672
3702
  : undefined,
@@ -1557,11 +1557,12 @@ declare var __INITIAL_SOURCE_HEAD__: string;
1557
1557
  );
1558
1558
  }
1559
1559
 
1560
- function serializeRuntimeLayerSnapshot(): {
1561
- html: string;
1562
- nodeCount: number;
1563
- } | null {
1564
- if (!document.body) return null;
1560
+ function serializeRuntimeLayerSnapshot(
1561
+ excludedRoot?: Element,
1562
+ ):
1563
+ | { ok: true; html: string; nodeCount: number; documentId: string }
1564
+ | { ok: false; reason: "snapshot-unavailable" | "snapshot-too-large" } {
1565
+ if (!document.body) return { ok: false, reason: "snapshot-unavailable" };
1565
1566
  // Keep this list export-focused and bounded. The runtime snapshot is also
1566
1567
  // the hosted/cross-origin Design→Figma fallback: inlining the resolved
1567
1568
  // paint/layout values lets the parent reconstruct the already-rendered
@@ -1666,7 +1667,10 @@ declare var __INITIAL_SOURCE_HEAD__: string;
1666
1667
  ) {
1667
1668
  var sourceNode = sourceNodes[index];
1668
1669
  var cloneNode = cloneNodes[index];
1669
- if (!isRuntimeLayerVisualNode(sourceNode)) {
1670
+ if (
1671
+ excludedRoot?.contains(sourceNode) ||
1672
+ !isRuntimeLayerVisualNode(sourceNode)
1673
+ ) {
1670
1674
  cloneNode.setAttribute("data-an-runtime-layer-remove", "true");
1671
1675
  continue;
1672
1676
  }
@@ -1787,8 +1791,10 @@ declare var __INITIAL_SOURCE_HEAD__: string;
1787
1791
  inlineSnapshotComputedStyle(document.body, cloneBody);
1788
1792
  cloneBody.setAttribute("data-an-runtime-layer-snapshot", "true");
1789
1793
  var html = "<!doctype html><html>" + cloneBody.outerHTML + "</html>"; // i18n-ignore serialized runtime-layer HTML payload, not visible UI copy
1790
- if (html.length > 2_000_000) return null;
1794
+ if (html.length > 2_000_000)
1795
+ return { ok: false, reason: "snapshot-too-large" };
1791
1796
  return {
1797
+ ok: true,
1792
1798
  html: html,
1793
1799
  nodeCount: nodeCount,
1794
1800
  documentId: runtimeDocumentId,
@@ -1805,7 +1811,17 @@ declare var __INITIAL_SOURCE_HEAD__: string;
1805
1811
  runtimeLayerSnapshotTimer = null;
1806
1812
  runtimeLayerSnapshotMaxTimer = null;
1807
1813
  var snapshot = serializeRuntimeLayerSnapshot();
1808
- if (!snapshot || snapshot.html === lastRuntimeLayerSnapshotHtml) return;
1814
+ if (!snapshot.ok) {
1815
+ (window.parent as Window).postMessage(
1816
+ {
1817
+ type: "agent-native:runtime-layer-snapshot-error",
1818
+ payload: snapshot,
1819
+ },
1820
+ "*",
1821
+ );
1822
+ return;
1823
+ }
1824
+ if (snapshot.html === lastRuntimeLayerSnapshotHtml) return;
1809
1825
  lastRuntimeLayerSnapshotHtml = snapshot.html;
1810
1826
  (window.parent as Window).postMessage(
1811
1827
  {
@@ -13603,6 +13619,7 @@ declare var __INITIAL_SOURCE_HEAD__: string;
13603
13619
  origin,
13604
13620
  insertedHtml?,
13605
13621
  replaced?,
13622
+ replacementSnapshotHtml?: string,
13606
13623
  ) {
13607
13624
  if (!el || !target || !target.anchor) return;
13608
13625
  dndLog("post:structure-change", {
@@ -13636,6 +13653,7 @@ declare var __INITIAL_SOURCE_HEAD__: string;
13636
13653
  insertedHtml:
13637
13654
  typeof insertedHtml === "string" ? insertedHtml : undefined,
13638
13655
  replaced: replaced === true ? true : undefined,
13656
+ replacementSnapshotHtml: replacementSnapshotHtml,
13639
13657
  sourceRect: rectInfoForElement(el),
13640
13658
  anchorRect: rectInfoForElement(target.anchor),
13641
13659
  payload: getElementInfo(el),
@@ -20146,6 +20164,14 @@ declare var __INITIAL_SOURCE_HEAD__: string;
20146
20164
  }
20147
20165
  var replaceNextSibling = insertAnchor.nextSibling;
20148
20166
  replaceParent.insertBefore(parsedInsertEl, insertAnchor);
20167
+ // Capture while the original still supplies its selector/provenance,
20168
+ // and reject before publishing a pending operation if proof is unavailable.
20169
+ var replacementSnapshot = serializeRuntimeLayerSnapshot(insertAnchor);
20170
+ if (!replacementSnapshot.ok) {
20171
+ parsedInsertEl.remove();
20172
+ rejectInsert("replacement-" + replacementSnapshot.reason);
20173
+ return;
20174
+ }
20149
20175
  selectedEl = parsedInsertEl;
20150
20176
  positionOverlay(selectionOverlay, selectedEl);
20151
20177
  refreshOverlays();
@@ -20160,6 +20186,7 @@ declare var __INITIAL_SOURCE_HEAD__: string;
20160
20186
  },
20161
20187
  parsedInsertEl.outerHTML,
20162
20188
  true,
20189
+ replacementSnapshot.html,
20163
20190
  );
20164
20191
  replaceParent.removeChild(insertAnchor);
20165
20192
  refreshOverlays();
@@ -36,3 +36,17 @@ export function isElementInfoPayload(value: unknown): value is ElementInfo {
36
36
  typeof value.isFlexContainer === "boolean"
37
37
  );
38
38
  }
39
+
40
+ export function parseRuntimeSnapshotHtml(
41
+ value: unknown,
42
+ ):
43
+ | { ok: true; html: string }
44
+ | { ok: false; reason: "snapshot-unavailable" | "snapshot-too-large" } {
45
+ if (typeof value !== "string" || !value) {
46
+ return { ok: false, reason: "snapshot-unavailable" };
47
+ }
48
+ if (value.length > 2_000_000) {
49
+ return { ok: false, reason: "snapshot-too-large" };
50
+ }
51
+ return { ok: true, html: value };
52
+ }
@@ -1721,7 +1721,7 @@ function DesignEditor() {
1721
1721
  const initialUrlSelectionHydratedForIdRef = useRef<string | null>(null);
1722
1722
  // Figma's 56px workspace rail (plus its 1px divider) and 280px Layers/Pages
1723
1723
  // pane place the content divider at x=337. Keep that total while honoring
1724
- // resizable 220–420px content range.
1724
+ // the resizable 220–420px content range, with 320px reserved for Agent chat.
1725
1725
  const [leftSidebarWidth, setLeftSidebarWidth] = useState(280);
1726
1726
  const [rightSidebarWidth, setRightSidebarWidth] = useState(240);
1727
1727
  // Cmd/Ctrl+\ hides the sidebars while leaving the bottom tools available.
@@ -7828,6 +7828,7 @@ function DesignEditor() {
7828
7828
  replacementSelector?: string;
7829
7829
  replacementSourceId?: string;
7830
7830
  replacementElementInfo?: ElementInfo;
7831
+ replacementSnapshotHtml?: string;
7831
7832
  /** This change DELETED the subject; it has no anchor. */
7832
7833
  removed?: true;
7833
7834
  },
@@ -12092,6 +12093,7 @@ function DesignEditor() {
12092
12093
  replacementSelector?: string;
12093
12094
  replacementSourceId?: string;
12094
12095
  replacementElementInfo?: ElementInfo;
12096
+ replacementSnapshotHtml?: string;
12095
12097
  },
12096
12098
  ) =>
12097
12099
  runVisualStructureChange(
@@ -12334,6 +12336,7 @@ function DesignEditor() {
12334
12336
  replacementSelector?: string;
12335
12337
  replacementSourceId?: string;
12336
12338
  replacementElementInfo?: ElementInfo;
12339
+ replacementSnapshotHtml?: string;
12337
12340
  },
12338
12341
  ) =>
12339
12342
  runScreenVisualStructureChange(
@@ -14461,6 +14464,11 @@ function DesignEditor() {
14461
14464
 
14462
14465
  const handleRuntimeStructureInsertRejected = useCallback(
14463
14466
  (reason: string) => {
14467
+ if (reason.startsWith("verification-")) {
14468
+ cancelPendingStructureVerification("conflict");
14469
+ toast.error(t("designEditor.pendingVisualStyles.conflictToast"));
14470
+ return;
14471
+ }
14464
14472
  // Never swallow this: a rejected insert leaves nothing on screen and
14465
14473
  // nothing in the pending list, so a silent return is indistinguishable
14466
14474
  // from the drop never having happened.
@@ -14469,7 +14477,7 @@ function DesignEditor() {
14469
14477
  }
14470
14478
  toast.error(t("designEditor.toasts.layerMoveFailed"), { duration: 4000 });
14471
14479
  },
14472
- [t],
14480
+ [cancelPendingStructureVerification, t],
14473
14481
  );
14474
14482
 
14475
14483
  const handleCutSelection = useCallback(async () => {
@@ -23398,7 +23406,10 @@ function DesignEditor() {
23398
23406
  const leftContentWidth =
23399
23407
  activeLeftPanel === "code"
23400
23408
  ? Math.max(leftSidebarWidth, 640)
23401
- : Math.max(Math.min(leftSidebarWidth, 420), 220);
23409
+ : Math.max(
23410
+ Math.min(leftSidebarWidth, 420),
23411
+ activeLeftPanel === "agent" ? 320 : 220,
23412
+ );
23402
23413
  const leftSidebarVisible = !hostOwnsChrome && !uiHidden && !minimalUi;
23403
23414
  // These focused surfaces need a clear viewport beside the absolute rail.
23404
23415
  const leftChromeOverlayInset = leftSidebarVisible
@@ -23712,7 +23723,7 @@ function DesignEditor() {
23712
23723
  <div
23713
23724
  data-design-agent-panel
23714
23725
  className={cn(
23715
- "min-h-0 flex-1 flex-col overflow-hidden",
23726
+ "min-h-0 min-w-0 flex-1 flex-col overflow-hidden",
23716
23727
  activeLeftPanel === "agent" ? "flex" : "hidden",
23717
23728
  )}
23718
23729
  >
@@ -23721,7 +23732,9 @@ function DesignEditor() {
23721
23732
  ) : canEditDesign ? (
23722
23733
  <AgentChatSurface
23723
23734
  mode="panel"
23724
- className="min-h-0 flex-1 border-0 bg-transparent shadow-none"
23735
+ className="min-h-0 min-w-0 flex-1 border-0 bg-transparent shadow-none"
23736
+ chatOnly={true}
23737
+ onCollapse={() => setActiveLeftPanel(null)}
23725
23738
  storageKey={DESIGN_CHAT_STORAGE_KEY}
23726
23739
  emptyStateText={t("chat.emptyState")}
23727
23740
  suggestions={designAgentSuggestions}
@@ -23,7 +23,10 @@ import {
23
23
  reactSourceAnchorForPendingEdit,
24
24
  runtimeStructureNodeSignature,
25
25
  } from "@/pages/design-editor/pending-edits";
26
- import { isPendingStructureDropNoOp } from "@/pages/design-editor/pending-structure-verification";
26
+ import {
27
+ isPendingStructureDropNoOp,
28
+ runtimeStructureSnapshotSignature,
29
+ } from "@/pages/design-editor/pending-structure-verification";
27
30
  import type { DesignFile } from "@/pages/design-editor/types";
28
31
 
29
32
  export interface RecordPendingLiveStructureEditArgs {
@@ -86,6 +89,7 @@ export function runRecordPendingLiveStructureEdit(
86
89
  replacementSelector?: string;
87
90
  replacementSourceId?: string;
88
91
  replacementElementInfo?: ElementInfo;
92
+ replacementSnapshotHtml?: string;
89
93
  /** This change DELETED the subject; it has no anchor. */
90
94
  removed?: true;
91
95
  },
@@ -108,9 +112,7 @@ export function runRecordPendingLiveStructureEdit(
108
112
  const subjectInfo = details?.replaced
109
113
  ? details.anchorElementInfo
110
114
  : elementInfo;
111
- const subjectSourceId = details?.replaced
112
- ? details.anchorSourceId
113
- : (details?.sourceId ?? elementInfo?.sourceId);
115
+ const subjectSourceId = details?.sourceId ?? subjectInfo?.sourceId;
114
116
  const nextEdit: PendingLiveStructureEdit = {
115
117
  kind: "structure",
116
118
  screenId,
@@ -164,6 +166,9 @@ export function runRecordPendingLiveStructureEdit(
164
166
  replaced: true as const,
165
167
  replacementSelector: details.replacementSelector,
166
168
  replacementSourceId: details.replacementSourceId,
169
+ replacementSnapshotSignature: details.replacementSnapshotHtml
170
+ ? runtimeStructureSnapshotSignature(details.replacementSnapshotHtml)
171
+ : undefined,
167
172
  }
168
173
  : {}),
169
174
  ...(details?.removed ? { removed: true as const } : {}),
@@ -48,6 +48,7 @@ export interface ScreenVisualStructureChangeArgs {
48
48
  replacementSelector?: string;
49
49
  replacementSourceId?: string;
50
50
  replacementElementInfo?: ElementInfo;
51
+ replacementSnapshotHtml?: string;
51
52
  },
52
53
  ) => boolean | "pending";
53
54
  overviewScreens: OverviewScreen[];
@@ -71,6 +72,7 @@ export interface ScreenVisualStructureChangeArgs {
71
72
  replacementSelector?: string;
72
73
  replacementSourceId?: string;
73
74
  replacementElementInfo?: ElementInfo;
75
+ replacementSnapshotHtml?: string;
74
76
  removed?: true;
75
77
  },
76
78
  ) => void;
@@ -117,6 +119,7 @@ export function runScreenVisualStructureChange(
117
119
  replacementSelector?: string;
118
120
  replacementSourceId?: string;
119
121
  replacementElementInfo?: ElementInfo;
122
+ replacementSnapshotHtml?: string;
120
123
  },
121
124
  ) {
122
125
  if (screenId === activeFile?.id) {
@@ -35,14 +35,19 @@ export function runStartSidebarResize(
35
35
  event.currentTarget.setPointerCapture?.(event.pointerId);
36
36
  const startX = event.clientX;
37
37
  const codePanelOpen = side === "left" && activeLeftPanel === "code";
38
+ const leftPanelMinWidth = codePanelOpen
39
+ ? 520
40
+ : activeLeftPanel === "agent"
41
+ ? 320
42
+ : 220;
38
43
  const startWidth =
39
44
  side === "left"
40
45
  ? codePanelOpen
41
46
  ? Math.max(leftSidebarWidth, 640)
42
- : Math.min(leftSidebarWidth, 420)
47
+ : Math.max(Math.min(leftSidebarWidth, 420), leftPanelMinWidth)
43
48
  : rightSidebarWidth;
44
49
  const setWidth = side === "left" ? setLeftSidebarWidth : setRightSidebarWidth;
45
- const minWidth = side === "left" ? (codePanelOpen ? 520 : 220) : 240;
50
+ const minWidth = side === "left" ? leftPanelMinWidth : 240;
46
51
  const maxWidth = side === "left" ? (codePanelOpen ? 1100 : 420) : 390;
47
52
  const target =
48
53
  side === "left"
@@ -73,6 +73,7 @@ export interface VisualStructureChangeArgs {
73
73
  replacementSelector?: string;
74
74
  replacementSourceId?: string;
75
75
  replacementElementInfo?: ElementInfo;
76
+ replacementSnapshotHtml?: string;
76
77
  removed?: true;
77
78
  },
78
79
  ) => void;
@@ -114,6 +115,7 @@ export function runVisualStructureChange(
114
115
  replacementSelector?: string;
115
116
  replacementSourceId?: string;
116
117
  replacementElementInfo?: ElementInfo;
118
+ replacementSnapshotHtml?: string;
117
119
  },
118
120
  ) {
119
121
  dndHostLog("persist:begin", {
@@ -326,6 +326,10 @@ export interface PendingLiveStructureEdit {
326
326
  replacementSelector?: string;
327
327
  replacementSourceId?: string | null;
328
328
  replacementSignature?: RuntimeStructureNodeSignature;
329
+ /** Expected visual tree captured by the bridge while it still owns the
330
+ * original DOM element. Runtime ids and computed styles are excluded.
331
+ * Missing evidence or later context changes cannot prove replacement. */
332
+ replacementSnapshotSignature?: string;
329
333
  /**
330
334
  * This edit DELETED the subject from the running app. A removal has no
331
335
  * anchor — `anchorSelector`/`placement` carry no meaning for it — so every
@@ -2,9 +2,9 @@ import {
2
2
  buildCodeLayerProjection,
3
3
  type CodeLayerNode,
4
4
  } from "@shared/code-layer";
5
+ import { parse, type DefaultTreeAdapterMap } from "parse5";
5
6
 
6
7
  import {
7
- bridgeSourceIdForCodeLayerNode,
8
8
  collapsedElementText,
9
9
  resolveCodeLayerTargetFromBridge,
10
10
  } from "./code-layer-state";
@@ -20,6 +20,8 @@ export type RuntimeStructureVerificationFailure =
20
20
  | "ambiguous-subject"
21
21
  | "subject-still-present"
22
22
  | "missing-replacement"
23
+ | "missing-replacement-evidence"
24
+ | "replacement-context-changed"
23
25
  | "ambiguous-replacement"
24
26
  | "missing-anchor"
25
27
  | "ambiguous-anchor"
@@ -37,7 +39,6 @@ type RuntimeStructureNodeRole = "subject" | "replacement" | "anchor";
37
39
  interface RuntimeStructureNodeResolution {
38
40
  node?: CodeLayerNode;
39
41
  failure?: RuntimeStructureVerificationFailure;
40
- matchedBy?: "identity" | "selector" | "signature";
41
42
  }
42
43
 
43
44
  function runtimeStructureResolutionFailure(
@@ -85,16 +86,11 @@ function resolveRuntimeStructureNode(args: {
85
86
  args.sourceId ?? undefined,
86
87
  );
87
88
  if (direct.status === "resolved") {
88
- const matchedBy =
89
- args.sourceId &&
90
- bridgeSourceIdForCodeLayerNode(direct.node) === args.sourceId
91
- ? "identity"
92
- : "selector";
93
89
  if (
94
90
  !args.signature ||
95
91
  runtimeStructureNodeMatchesSignature(direct.node, args.signature)
96
92
  ) {
97
- return { node: direct.node, matchedBy };
93
+ return { node: direct.node };
98
94
  }
99
95
  // A live identity is stronger evidence than a stale content signature.
100
96
  // Do not let an unrelated sibling with the old signature validate this
@@ -108,75 +104,31 @@ function resolveRuntimeStructureNode(args: {
108
104
  : "missing-anchor",
109
105
  };
110
106
  }
111
-
112
- if (!args.signature) {
107
+ if (direct.status === "ambiguous") {
113
108
  return {
114
- failure: runtimeStructureResolutionFailure(
115
- direct.status === "ambiguous" ? "ambiguous" : "absent",
116
- args.role,
117
- ),
109
+ failure: runtimeStructureResolutionFailure("ambiguous", args.role),
118
110
  };
119
111
  }
120
112
 
121
- const matches = args.projection.nodes.filter((node) =>
122
- runtimeStructureNodeMatchesSignature(node, args.signature!),
123
- );
124
- if (matches.length === 1) {
125
- return { node: matches[0], matchedBy: "signature" };
126
- }
127
- return {
128
- failure: runtimeStructureResolutionFailure(
129
- matches.length > 1 ? "ambiguous" : "absent",
130
- args.role,
131
- ),
132
- };
133
- }
134
-
135
- function resolveRuntimeStructureNodeByIdentity(args: {
136
- projection: { nodes: CodeLayerNode[] };
137
- selector?: string;
138
- sourceId?: string | null;
139
- role: RuntimeStructureNodeRole;
140
- }): RuntimeStructureNodeResolution {
141
- const direct = resolveCodeLayerTargetFromBridge(
142
- args.projection,
143
- args.selector,
144
- args.sourceId ?? undefined,
145
- );
146
- if (direct.status === "resolved") {
147
- return {
148
- node: direct.node,
149
- matchedBy:
150
- args.sourceId &&
151
- bridgeSourceIdForCodeLayerNode(direct.node) === args.sourceId
152
- ? "identity"
153
- : "selector",
154
- };
155
- }
156
- return {
157
- failure: runtimeStructureResolutionFailure(
158
- direct.status === "ambiguous" ? "ambiguous" : "absent",
159
- args.role,
160
- ),
161
- };
113
+ return resolveRuntimeStructureNodeBySignature(args);
162
114
  }
163
115
 
164
116
  function resolveRuntimeStructureNodeBySignature(args: {
165
117
  projection: { nodes: CodeLayerNode[] };
166
118
  signature?: RuntimeStructureNodeSignature;
167
119
  role: RuntimeStructureNodeRole;
168
- excludedNodeIds?: ReadonlySet<string>;
120
+ excludedNode?: CodeLayerNode;
169
121
  }): RuntimeStructureNodeResolution {
170
122
  if (!args.signature) {
171
123
  return { failure: runtimeStructureResolutionFailure("absent", args.role) };
172
124
  }
173
125
  const matches = args.projection.nodes.filter(
174
126
  (node) =>
175
- !args.excludedNodeIds?.has(node.id) &&
127
+ node !== args.excludedNode &&
176
128
  runtimeStructureNodeMatchesSignature(node, args.signature!),
177
129
  );
178
130
  if (matches.length === 1) {
179
- return { node: matches[0], matchedBy: "signature" };
131
+ return { node: matches[0] };
180
132
  }
181
133
  return {
182
134
  failure: runtimeStructureResolutionFailure(
@@ -186,18 +138,142 @@ function resolveRuntimeStructureNodeBySignature(args: {
186
138
  };
187
139
  }
188
140
 
189
- function resolveRuntimeStructureNodeForPresence(args: {
190
- projection: { nodes: CodeLayerNode[] };
191
- selector?: string;
192
- sourceId?: string | null;
193
- signature?: RuntimeStructureNodeSignature;
194
- role: RuntimeStructureNodeRole;
195
- }): RuntimeStructureNodeResolution {
196
- const identity = resolveRuntimeStructureNodeByIdentity(args);
197
- if (identity.node || identity.failure?.startsWith("ambiguous")) {
198
- return identity;
141
+ function verifyRuntimeStructureSubjectAbsent(
142
+ projection: { nodes: CodeLayerNode[] },
143
+ edit: PendingLiveStructureEdit,
144
+ replacement?: CodeLayerNode,
145
+ ): RuntimeStructureVerificationResult {
146
+ // Absence must inspect the old identity alone: a positional selector may
147
+ // now point at the replacement or an unrelated sibling.
148
+ const subject = resolveCodeLayerTargetFromBridge(
149
+ projection,
150
+ edit.sourceId ? undefined : edit.selector,
151
+ edit.sourceId ?? undefined,
152
+ );
153
+ if (subject.status === "ambiguous") {
154
+ return { ok: false, failure: "ambiguous-subject" };
199
155
  }
200
- return resolveRuntimeStructureNodeBySignature(args);
156
+ if (
157
+ subject.status === "resolved" &&
158
+ (edit.sourceId ||
159
+ replacement === undefined ||
160
+ (subject.node === replacement &&
161
+ (!edit.subjectSignature ||
162
+ runtimeStructureNodeMatchesSignature(
163
+ subject.node,
164
+ edit.subjectSignature,
165
+ ))))
166
+ ) {
167
+ return { ok: false, failure: "subject-still-present" };
168
+ }
169
+
170
+ // Signature-only fallback cannot distinguish unchanged old content. A
171
+ // unique identity or selector independently resolves the replacement;
172
+ // captured document evidence still has to prove the resulting structure.
173
+ const replacementTarget = resolveCodeLayerTargetFromBridge(
174
+ projection,
175
+ edit.replacementSourceId ? undefined : edit.replacementSelector,
176
+ edit.replacementSourceId ?? undefined,
177
+ );
178
+ const signature = resolveRuntimeStructureNodeBySignature({
179
+ projection,
180
+ signature: edit.subjectSignature,
181
+ role: "subject",
182
+ excludedNode:
183
+ replacementTarget.status === "resolved" &&
184
+ replacementTarget.node === replacement
185
+ ? replacement
186
+ : undefined,
187
+ });
188
+ if (signature.failure === "ambiguous-subject") {
189
+ return { ok: false, failure: signature.failure };
190
+ }
191
+ return signature.node
192
+ ? { ok: false, failure: "subject-still-present" }
193
+ : { ok: true };
194
+ }
195
+
196
+ // These attributes are injected by serializeRuntimeLayerSnapshot, not authored
197
+ // semantic state. Keep this list exact so other data-* attributes remain evidence.
198
+ const runtimeSnapshotMetadataAttributes = new Set([
199
+ "style",
200
+ "data-agent-native-node-id",
201
+ "data-agent-native-node-rewrite-proposal",
202
+ "data-agent-native-group-runtime-state",
203
+ "data-agent-native-runtime-hidden",
204
+ "data-agent-native-runtime-locked",
205
+ "data-agent-native-previous-display",
206
+ "data-agent-native-text-editing",
207
+ "data-an-runtime-layer-snapshot",
208
+ "data-an-pending-node-id",
209
+ "data-an-state-preview",
210
+ "data-an-state-preview-key",
211
+ "data-an-vector-logical-width",
212
+ "data-an-vector-stroke-defs",
213
+ "data-an-vector-stroke-geometry",
214
+ "data-an-vector-stroke-original-overflow",
215
+ "data-an-vector-stroke-original-overflow-priority",
216
+ "data-an-vector-stroke-overlay",
217
+ "data-an-vector-stroke-position",
218
+ "data-source-framework",
219
+ "data-source-file",
220
+ "data-source-line",
221
+ "data-source-method",
222
+ "data-source-column",
223
+ "data-component-name",
224
+ "data-source-owner-file",
225
+ "data-source-owner-line",
226
+ "data-source-owner-column",
227
+ "data-source-owner-component",
228
+ "data-source-owner-method",
229
+ "data-source-owner-key",
230
+ "data-source-unavailable",
231
+ ]);
232
+
233
+ /** Full visual-tree evidence: sibling order, nesting, content and semantic
234
+ * attributes must match; runtime identities and computed styles may change. */
235
+ export function runtimeStructureSnapshotSignature(
236
+ snapshotHtml: string,
237
+ ): string {
238
+ function structure(node: DefaultTreeAdapterMap["node"]): unknown[] {
239
+ if ("value" in node && node.nodeName === "#text") {
240
+ const text = collapsedElementText(node.value);
241
+ return text ? [text] : [];
242
+ }
243
+ if ("tagName" in node && node.tagName === "head") return [];
244
+ const children =
245
+ "childNodes" in node ? node.childNodes.flatMap(structure) : [];
246
+ if (!("tagName" in node) || node.tagName === "html") return children;
247
+ return [
248
+ [
249
+ node.namespaceURI,
250
+ node.tagName,
251
+ normalizeRuntimeStructureClasses(
252
+ (
253
+ node.attrs.find((attribute) => attribute.name === "class")?.value ??
254
+ ""
255
+ ).split(/\s+/),
256
+ ),
257
+ node.attrs
258
+ .filter(
259
+ (attribute) =>
260
+ attribute.namespace ||
261
+ (attribute.name !== "class" &&
262
+ !runtimeSnapshotMetadataAttributes.has(attribute.name)),
263
+ )
264
+ .map((attribute) =>
265
+ JSON.stringify([
266
+ attribute.namespace ?? "",
267
+ attribute.name,
268
+ attribute.value,
269
+ ]),
270
+ )
271
+ .sort(),
272
+ children,
273
+ ],
274
+ ];
275
+ }
276
+ return JSON.stringify(structure(parse(snapshotHtml)));
201
277
  }
202
278
 
203
279
  function runtimeStructureNodeForNoOp(
@@ -229,9 +305,9 @@ export function verifyPendingStructureRuntime(
229
305
  ): RuntimeStructureVerificationResult {
230
306
  const projection = buildCodeLayerProjection(snapshotHtml);
231
307
  if (edit.replaced) {
232
- const replacementResolution = resolveRuntimeStructureNodeForPresence({
308
+ const replacementResolution = resolveRuntimeStructureNode({
233
309
  projection,
234
- selector: edit.replacementSelector,
310
+ selector: edit.replacementSourceId ? undefined : edit.replacementSelector,
235
311
  sourceId: edit.replacementSourceId,
236
312
  signature: edit.replacementSignature,
237
313
  role: "replacement",
@@ -243,83 +319,22 @@ export function verifyPendingStructureRuntime(
243
319
  };
244
320
  }
245
321
 
246
- const subjectIdentityResolution = resolveRuntimeStructureNodeByIdentity({
322
+ const absence = verifyRuntimeStructureSubjectAbsent(
247
323
  projection,
248
- selector: edit.selector,
249
- sourceId: edit.sourceId,
250
- role: "subject",
251
- });
252
- if (subjectIdentityResolution.failure === "ambiguous-subject") {
253
- return { ok: false, failure: "ambiguous-subject" };
254
- }
255
- if (subjectIdentityResolution.node) {
256
- const sameNode =
257
- subjectIdentityResolution.node.id === replacementResolution.node.id;
258
- const replacementIsProvenByPosition =
259
- sameNode &&
260
- subjectIdentityResolution.matchedBy === "selector" &&
261
- replacementResolution.matchedBy === "selector";
262
- if (!replacementIsProvenByPosition) {
263
- return { ok: false, failure: "subject-still-present" };
264
- }
265
- }
266
-
267
- const subjectMatches = projection.nodes.filter((node) =>
268
- edit.subjectSignature
269
- ? runtimeStructureNodeMatchesSignature(node, edit.subjectSignature)
270
- : false,
324
+ edit,
325
+ replacementResolution.node,
271
326
  );
272
- const replacementIsUniquelyLocated =
273
- replacementResolution.matchedBy === "identity" ||
274
- replacementResolution.matchedBy === "selector";
275
- const remainingSubjectMatches = replacementIsUniquelyLocated
276
- ? subjectMatches.filter(
277
- (node) => node.id !== replacementResolution.node!.id,
278
- )
279
- : subjectMatches;
280
- const replacementIsProvenByPosition =
281
- subjectIdentityResolution.node?.id === replacementResolution.node.id &&
282
- subjectIdentityResolution.matchedBy === "selector" &&
283
- replacementResolution.matchedBy === "selector";
284
- if (!replacementIsProvenByPosition) {
285
- if (remainingSubjectMatches.length > 1) {
286
- return { ok: false, failure: "ambiguous-subject" };
287
- }
288
- if (remainingSubjectMatches.length === 1) {
289
- return { ok: false, failure: "subject-still-present" };
290
- }
327
+ if (!absence.ok) return absence;
328
+ if (!edit.replacementSnapshotSignature) {
329
+ return { ok: false, failure: "missing-replacement-evidence" };
291
330
  }
292
- return { ok: true };
331
+ return runtimeStructureSnapshotSignature(snapshotHtml) ===
332
+ edit.replacementSnapshotSignature
333
+ ? { ok: true }
334
+ : { ok: false, failure: "replacement-context-changed" };
293
335
  }
294
- // A removal proves itself by ABSENCE. Running it through the anchor/order
295
- // checks below would report "missing-subject" for the exact outcome it
296
- // asked for, and the apply flow would sit in awaiting-runtime until it
297
- // timed out on a source write that actually succeeded.
298
336
  if (edit.removed) {
299
- const subjectIdentityResolution = resolveRuntimeStructureNodeByIdentity({
300
- projection,
301
- selector: edit.selector,
302
- sourceId: edit.sourceId,
303
- role: "subject",
304
- });
305
- if (subjectIdentityResolution.failure === "ambiguous-subject") {
306
- return { ok: false, failure: "ambiguous-subject" };
307
- }
308
- if (subjectIdentityResolution.node) {
309
- return { ok: false, failure: "subject-still-present" };
310
- }
311
- const subjectSignatureResolution = resolveRuntimeStructureNodeBySignature({
312
- projection,
313
- signature: edit.subjectSignature,
314
- role: "subject",
315
- });
316
- if (subjectSignatureResolution.failure === "ambiguous-subject") {
317
- return { ok: false, failure: "ambiguous-subject" };
318
- }
319
- if (subjectSignatureResolution.node) {
320
- return { ok: false, failure: "subject-still-present" };
321
- }
322
- return { ok: true };
337
+ return verifyRuntimeStructureSubjectAbsent(projection, edit);
323
338
  }
324
339
 
325
340
  const subjectResolution = resolveRuntimeStructureNode({
@@ -433,14 +448,30 @@ export function isPendingStructureDropNoOp(
433
448
  );
434
449
  }
435
450
 
451
+ function replacementSnapshotsByScreen(
452
+ edits: readonly PendingLiveStructureEdit[],
453
+ ) {
454
+ // Later replacement gestures include the earlier optimistic replacements.
455
+ // Verify the composed screen without discarding each edit's identity checks.
456
+ return new Map(
457
+ edits
458
+ .filter((edit) => edit.replaced)
459
+ .map((edit) => [edit.screenId, edit.replacementSnapshotSignature]),
460
+ );
461
+ }
462
+
436
463
  export function verifyPendingStructuresRuntime(
437
464
  snapshots: Record<string, { html: string } | undefined>,
438
465
  edits: readonly PendingLiveStructureEdit[],
439
466
  ): RuntimeStructureVerificationResult {
467
+ const replacementSnapshots = replacementSnapshotsByScreen(edits);
440
468
  for (const edit of edits) {
441
469
  const snapshot = snapshots[edit.screenId];
442
470
  if (!snapshot) return { ok: false, failure: "missing-subject" };
443
- const result = verifyPendingStructureRuntime(snapshot.html, edit);
471
+ const result = verifyPendingStructureRuntime(snapshot.html, {
472
+ ...edit,
473
+ replacementSnapshotSignature: replacementSnapshots.get(edit.screenId),
474
+ });
444
475
  if (!result.ok) return result;
445
476
  }
446
477
  return { ok: true };
@@ -453,11 +484,30 @@ export function partitionPendingStructuresRuntime(
453
484
  verified: PendingLiveStructureEdit[];
454
485
  remaining: PendingLiveStructureEdit[];
455
486
  } {
487
+ const replacementSnapshots = replacementSnapshotsByScreen(edits);
488
+ const results = edits.map((edit) => {
489
+ const snapshot = snapshots[edit.screenId];
490
+ return {
491
+ edit,
492
+ ok: Boolean(
493
+ snapshot &&
494
+ verifyPendingStructureRuntime(snapshot.html, {
495
+ ...edit,
496
+ replacementSnapshotSignature: replacementSnapshots.get(edit.screenId),
497
+ }).ok,
498
+ ),
499
+ };
500
+ });
501
+ // Keep the shared evidence until every replacement using it verifies.
502
+ const blockedScreens = new Set(
503
+ results
504
+ .filter(({ edit, ok }) => edit.replaced && !ok)
505
+ .map(({ edit }) => edit.screenId),
506
+ );
456
507
  const verified: PendingLiveStructureEdit[] = [];
457
508
  const remaining: PendingLiveStructureEdit[] = [];
458
- for (const edit of edits) {
459
- const snapshot = snapshots[edit.screenId];
460
- if (snapshot && verifyPendingStructureRuntime(snapshot.html, edit).ok) {
509
+ for (const { edit, ok } of results) {
510
+ if (ok && (!edit.replaced || !blockedScreens.has(edit.screenId))) {
461
511
  verified.push(edit);
462
512
  } else {
463
513
  remaining.push(edit);
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-09-16
4
+ ---
5
+
6
+ Design editor agent chat uses shared conversation tabs and stays usable at narrow widths
@@ -0,0 +1,5 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-09-16
4
+ ---
5
+ Visual edits stay applied when the page structure shifts after a replacement.
@@ -55,7 +55,7 @@ export declare function shouldShowAgentPanelSidebarChatTabs(tabs: MultiTabAssist
55
55
  export declare function shouldShowAgentPanelPageNewChatButton(tabs: MultiTabAssistantChatHeaderProps["tabs"], activeTabId: string, activeTabMessageCount: number): boolean;
56
56
  export declare function shouldShowAgentPanelPageHeader(tabs: MultiTabAssistantChatHeaderProps["tabs"], activeTabId: string, activeTabMessageCount: number): boolean;
57
57
  export declare function shouldShowAgentPanelCliTabBar(cliTabs: string[]): boolean;
58
- export declare function shouldShowAgentPanelModeButtons(isSidebar: boolean): boolean;
58
+ export declare function shouldShowAgentPanelModeButtons(isSidebar: boolean, chatOnly?: boolean): boolean;
59
59
  export declare function shouldShowAgentPanelFullViewAction(agentPageHref: string | undefined, mode: PanelMode, isSidebar?: boolean, currentPath?: string): boolean;
60
60
  export declare function resolveAgentPanelFullViewAction(agentPageHref: string | undefined, onFullViewRequest: (() => void) | undefined, mode: PanelMode, isSidebar?: boolean, currentPath?: string): {
61
61
  readonly kind: "callback";
@@ -342,8 +342,8 @@ export function shouldShowAgentPanelPageHeader(tabs, activeTabId, activeTabMessa
342
342
  export function shouldShowAgentPanelCliTabBar(cliTabs) {
343
343
  return cliTabs.length > 1;
344
344
  }
345
- export function shouldShowAgentPanelModeButtons(isSidebar) {
346
- return !isSidebar;
345
+ export function shouldShowAgentPanelModeButtons(isSidebar, chatOnly = false) {
346
+ return !isSidebar && !chatOnly;
347
347
  }
348
348
  export function shouldShowAgentPanelFullViewAction(agentPageHref, mode, isSidebar = false, currentPath) {
349
349
  return (Boolean(agentPageHref) &&
@@ -1018,7 +1018,7 @@ function AgentPanelInner({ defaultMode = "chat", className, style, apiUrl, empty
1018
1018
  borderRadius: "0 6px 6px 0",
1019
1019
  background: "linear-gradient(to right, transparent, hsl(var(--accent)) 40%)",
1020
1020
  }, children: _jsx(IconX, { size: 10 }) })] }, tab.id));
1021
- }) })) : shouldShowAgentPanelModeButtons(Boolean(onCollapse)) ? (renderModeButtons(mode)) : null }), _jsx("div", { className: "flex items-center gap-0.5", children: renderHeaderActions({
1021
+ }) })) : shouldShowAgentPanelModeButtons(Boolean(onCollapse), chatOnly) ? (renderModeButtons(mode)) : null }), _jsx("div", { className: "flex items-center gap-0.5", children: renderHeaderActions({
1022
1022
  activeChatSessionId: activeTabId,
1023
1023
  activeTabId,
1024
1024
  activeTabMessageCount,
@@ -1119,7 +1119,7 @@ function AgentPanelInner({ defaultMode = "chat", className, style, apiUrl, empty
1119
1119
  switchMode,
1120
1120
  t,
1121
1121
  ]);
1122
- return (_jsxs(ThinkingDisplayProvider, { value: assistantChatProps.thinkingDisplay, children: [_jsx(AgentPanelSettingsNavigation, { onOpenSettings: onOpenSettings }), _jsxs("div", { className: cn("agent-panel-root agent-kit-density flex flex-1 flex-col min-h-0 h-full antialiased", className), style: {
1122
+ return (_jsxs(ThinkingDisplayProvider, { value: assistantChatProps.thinkingDisplay, children: [_jsx(AgentPanelSettingsNavigation, { onOpenSettings: onOpenSettings }), _jsxs("div", { className: cn("agent-panel-root agent-kit-density flex flex-1 flex-col min-h-0 min-w-0 h-full antialiased", className), style: {
1123
1123
  ...AGENT_PANEL_ROOT_STYLE,
1124
1124
  ...style,
1125
1125
  // The chat view-transition container otherwise traps fixed onboarding
@@ -26,8 +26,8 @@ export declare const getCollabState: import("h3").EventHandlerWithFetch<import("
26
26
  * Body: { update: string (base64), requestSource?: string }
27
27
  */
28
28
  export declare const postCollabUpdate: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
29
- ok?: undefined;
30
29
  error: string;
30
+ ok?: undefined;
31
31
  } | {
32
32
  error?: undefined;
33
33
  ok: boolean;
@@ -137,13 +137,13 @@ export declare function screenMemoryMcpToolDefinitions(): ({
137
137
  inputSchema: {
138
138
  type: string;
139
139
  properties: {
140
+ count?: undefined;
140
141
  query?: undefined;
141
142
  minutes?: undefined;
142
143
  limit?: undefined;
143
144
  clientHint?: undefined;
144
145
  timestamp?: undefined;
145
146
  chapterId?: undefined;
146
- count?: undefined;
147
147
  startAt?: undefined;
148
148
  endAt?: undefined;
149
149
  reason?: undefined;
@@ -159,6 +159,7 @@ export declare function screenMemoryMcpToolDefinitions(): ({
159
159
  inputSchema: {
160
160
  type: string;
161
161
  properties: {
162
+ count?: undefined;
162
163
  query: {
163
164
  type: string;
164
165
  description: string;
@@ -174,7 +175,6 @@ export declare function screenMemoryMcpToolDefinitions(): ({
174
175
  clientHint?: undefined;
175
176
  timestamp?: undefined;
176
177
  chapterId?: undefined;
177
- count?: undefined;
178
178
  startAt?: undefined;
179
179
  endAt?: undefined;
180
180
  reason?: undefined;
@@ -190,6 +190,7 @@ export declare function screenMemoryMcpToolDefinitions(): ({
190
190
  inputSchema: {
191
191
  type: string;
192
192
  properties: {
193
+ count?: undefined;
193
194
  minutes: {
194
195
  type: string;
195
196
  description: string;
@@ -199,7 +200,6 @@ export declare function screenMemoryMcpToolDefinitions(): ({
199
200
  clientHint?: undefined;
200
201
  timestamp?: undefined;
201
202
  chapterId?: undefined;
202
- count?: undefined;
203
203
  startAt?: undefined;
204
204
  endAt?: undefined;
205
205
  reason?: undefined;
@@ -216,6 +216,7 @@ export declare function screenMemoryMcpToolDefinitions(): ({
216
216
  type: string;
217
217
  required: string[];
218
218
  properties: {
219
+ count?: undefined;
219
220
  query: {
220
221
  type: string;
221
222
  description: string;
@@ -234,7 +235,6 @@ export declare function screenMemoryMcpToolDefinitions(): ({
234
235
  };
235
236
  timestamp?: undefined;
236
237
  chapterId?: undefined;
237
- count?: undefined;
238
238
  startAt?: undefined;
239
239
  endAt?: undefined;
240
240
  reason?: undefined;
@@ -250,6 +250,7 @@ export declare function screenMemoryMcpToolDefinitions(): ({
250
250
  type: string;
251
251
  required: string[];
252
252
  properties: {
253
+ count?: undefined;
253
254
  query?: undefined;
254
255
  minutes?: undefined;
255
256
  limit?: undefined;
@@ -263,7 +264,6 @@ export declare function screenMemoryMcpToolDefinitions(): ({
263
264
  description: string;
264
265
  };
265
266
  chapterId?: undefined;
266
- count?: undefined;
267
267
  startAt?: undefined;
268
268
  endAt?: undefined;
269
269
  includeMicrophone?: undefined;
@@ -314,13 +314,13 @@ export declare function screenMemoryMcpToolDefinitions(): ({
314
314
  type: string;
315
315
  required: string[];
316
316
  properties: {
317
+ count?: undefined;
317
318
  query?: undefined;
318
319
  minutes?: undefined;
319
320
  limit?: undefined;
320
321
  clientHint?: undefined;
321
322
  timestamp?: undefined;
322
323
  chapterId?: undefined;
323
- count?: undefined;
324
324
  startAt: {
325
325
  type: string;
326
326
  description: string;
@@ -349,13 +349,13 @@ export declare function screenMemoryMcpToolDefinitions(): ({
349
349
  type: string;
350
350
  required: string[];
351
351
  properties: {
352
+ count?: undefined;
352
353
  query?: undefined;
353
354
  minutes?: undefined;
354
355
  limit?: undefined;
355
356
  clientHint?: undefined;
356
357
  timestamp?: undefined;
357
358
  chapterId?: undefined;
358
- count?: undefined;
359
359
  startAt?: undefined;
360
360
  endAt?: undefined;
361
361
  reason?: undefined;
@@ -16,18 +16,18 @@ export declare function createNotificationsHandler(): import("h3").EventHandlerW
16
16
  error?: undefined;
17
17
  ok?: undefined;
18
18
  } | {
19
+ count?: undefined;
19
20
  updated: number;
20
21
  error?: undefined;
21
22
  ok?: undefined;
22
- count?: undefined;
23
23
  } | {
24
+ count?: undefined;
24
25
  updated?: undefined;
25
26
  error: string;
26
27
  ok?: undefined;
27
- count?: undefined;
28
28
  } | {
29
+ count?: undefined;
29
30
  updated?: undefined;
30
31
  error?: undefined;
31
32
  ok: boolean;
32
- count?: undefined;
33
33
  }>>;
@@ -60,17 +60,17 @@ export declare function createWriteSecretHandler(): import("h3").EventHandlerWit
60
60
  ok?: undefined;
61
61
  status?: undefined;
62
62
  } | {
63
+ error?: undefined;
63
64
  ok: boolean;
64
65
  status: string;
65
- error?: undefined;
66
66
  } | {
67
67
  ok?: undefined;
68
68
  error: string;
69
69
  removed?: undefined;
70
70
  } | {
71
+ error?: undefined;
71
72
  ok: boolean;
72
73
  removed: boolean;
73
- error?: undefined;
74
74
  }>>;
75
75
  /**
76
76
  * POST /_agent-native/secrets/:key/test — validate an optional candidate value
@@ -81,13 +81,13 @@ export declare function createTestSecretHandler(): import("h3").EventHandlerWith
81
81
  error: string;
82
82
  note?: undefined;
83
83
  } | {
84
+ error?: undefined;
84
85
  ok: boolean;
85
86
  note?: undefined;
86
- error?: undefined;
87
87
  } | {
88
+ error?: undefined;
88
89
  ok: boolean;
89
90
  note: string;
90
- error?: undefined;
91
91
  } | {
92
92
  note?: undefined;
93
93
  ok: boolean;
@@ -119,11 +119,11 @@ export interface AdHocSecretPayload {
119
119
  export declare function createAdHocSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<AdHocSecretPayload[] | {
120
120
  error: string;
121
121
  } | {
122
+ error?: undefined;
122
123
  ok: boolean;
123
124
  key: string;
124
- error?: undefined;
125
125
  } | {
126
+ error?: undefined;
126
127
  ok: boolean;
127
128
  removed: boolean;
128
- error?: undefined;
129
129
  }>>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/core",
3
- "version": "0.181.0",
3
+ "version": "0.181.1-nightly-20260916141207",
4
4
  "description": "The agentic application framework for building autonomous agents with intuitive UIs",
5
5
  "homepage": "https://github.com/BuilderIO/agent-native#readme",
6
6
  "bugs": {
@@ -484,9 +484,9 @@
484
484
  "yaml": "^2.9.0",
485
485
  "yjs": "^13.6.32",
486
486
  "zod": "^4.3.6",
487
- "@agent-native/recap-cli": "0.5.32",
488
- "@agent-native/agentkit": "^0.2.2",
489
- "@agent-native/toolkit": "^0.20.2"
487
+ "@agent-native/toolkit": "^0.20.3-nightly-20260916141207",
488
+ "@agent-native/agentkit": "^0.2.3-nightly-20260916141207",
489
+ "@agent-native/recap-cli": "0.5.32"
490
490
  },
491
491
  "devDependencies": {
492
492
  "@ai-sdk/anthropic": "^3.0.71",