@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.
- package/corpus/README.md +1 -1
- package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +27 -7
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +45 -15
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +35 -8
- package/corpus/templates/design/app/components/design/design-canvas/element-payload.ts +14 -0
- package/corpus/templates/design/app/pages/DesignEditor.tsx +18 -5
- package/corpus/templates/design/app/pages/design-editor/commands/record-pending-live-structure-edit.ts +9 -4
- package/corpus/templates/design/app/pages/design-editor/commands/screen-visual-structure-change.ts +3 -0
- package/corpus/templates/design/app/pages/design-editor/commands/start-sidebar-resize.ts +7 -2
- package/corpus/templates/design/app/pages/design-editor/commands/visual-structure-change.ts +2 -0
- package/corpus/templates/design/app/pages/design-editor/pending-edits.ts +4 -0
- package/corpus/templates/design/app/pages/design-editor/pending-structure-verification.ts +197 -147
- package/corpus/templates/design/changelog/2026-09-16-design-editor-agent-chat-uses-shared-conversation-tabs-and-s.md +6 -0
- package/corpus/templates/design/changelog/2026-09-16-visual-edits-stay-applied-after-replacements.md +5 -0
- package/dist/client/AgentPanel.d.ts +1 -1
- package/dist/client/AgentPanel.js +4 -4
- package/dist/collab/routes.d.ts +1 -1
- package/dist/mcp/screen-memory-stdio.d.ts +7 -7
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/secrets/routes.d.ts +6 -6
- package/package.json +4 -4
package/corpus/README.md
CHANGED
|
@@ -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
|
|
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)
|
|
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
|
|
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
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
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
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
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 (
|
|
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)
|
|
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
|
|
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(
|
|
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 {
|
|
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?.
|
|
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 } : {}),
|
package/corpus/templates/design/app/pages/design-editor/commands/screen-visual-structure-change.ts
CHANGED
|
@@ -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" ?
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
127
|
+
node !== args.excludedNode &&
|
|
176
128
|
runtimeStructureNodeMatchesSignature(node, args.signature!),
|
|
177
129
|
);
|
|
178
130
|
if (matches.length === 1) {
|
|
179
|
-
return { node: matches[0]
|
|
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
|
|
190
|
-
projection: { nodes: CodeLayerNode[] }
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
const
|
|
197
|
-
|
|
198
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
|
322
|
+
const absence = verifyRuntimeStructureSubjectAbsent(
|
|
247
323
|
projection,
|
|
248
|
-
|
|
249
|
-
|
|
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
|
-
|
|
273
|
-
|
|
274
|
-
|
|
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
|
|
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
|
-
|
|
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,
|
|
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
|
|
459
|
-
|
|
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);
|
|
@@ -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
|
package/dist/collab/routes.d.ts
CHANGED
|
@@ -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
|
}>>;
|
package/dist/secrets/routes.d.ts
CHANGED
|
@@ -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.
|
|
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/
|
|
488
|
-
"@agent-native/agentkit": "^0.2.
|
|
489
|
-
"@agent-native/
|
|
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",
|