@agent-native/core 0.182.1 → 0.182.2-nightly-20260917225811

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 (119) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/clips/app/root.tsx +59 -10
  3. package/corpus/templates/clips/changelog/2026-09-17-desktop-popover-closes-when-clicking-away.md +6 -0
  4. package/corpus/templates/clips/changelog/2026-09-17-self-hosted-extension-sign-in.md +6 -0
  5. package/corpus/templates/clips/chrome-extension/src/background.ts +45 -25
  6. package/corpus/templates/clips/chrome-extension/src/content-script.ts +43 -0
  7. package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +55 -6
  8. package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +107 -19
  9. package/corpus/templates/design/.generated/bridge/hit-test.generated.ts +1 -0
  10. package/corpus/templates/design/actions/add-localhost-screens.ts +54 -22
  11. package/corpus/templates/design/actions/apply-component-prop-edit.ts +174 -14
  12. package/corpus/templates/design/actions/apply-visual-edit.ts +3 -1
  13. package/corpus/templates/design/actions/create-component.ts +173 -12
  14. package/corpus/templates/design/actions/create-design-from-template.ts +50 -35
  15. package/corpus/templates/design/actions/create-design-version.ts +21 -0
  16. package/corpus/templates/design/actions/create-file.ts +35 -33
  17. package/corpus/templates/design/actions/delete-design.ts +29 -28
  18. package/corpus/templates/design/actions/delete-file.ts +154 -23
  19. package/corpus/templates/design/actions/generate-design.ts +28 -16
  20. package/corpus/templates/design/actions/get-component-details.ts +272 -33
  21. package/corpus/templates/design/actions/get-design-version.ts +9 -1
  22. package/corpus/templates/design/actions/go-to-main-component.ts +37 -35
  23. package/corpus/templates/design/actions/index-components.ts +241 -126
  24. package/corpus/templates/design/actions/migrate-board-objects-to-file.ts +12 -9
  25. package/corpus/templates/design/actions/present-design-variants.ts +68 -72
  26. package/corpus/templates/design/actions/rename-component.ts +294 -0
  27. package/corpus/templates/design/actions/rename-screen.ts +10 -10
  28. package/corpus/templates/design/actions/update-file.ts +327 -330
  29. package/corpus/templates/design/actions/update-screen-source.ts +2 -43
  30. package/corpus/templates/design/app/components/design/EditPanel.tsx +17 -1
  31. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +228 -24
  32. package/corpus/templates/design/app/components/design/ResponsiveInteractBar.tsx +17 -1
  33. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +151 -32
  34. package/corpus/templates/design/app/components/design/bridge/hit-test.bridge.ts +4 -0
  35. package/corpus/templates/design/app/components/design/canvas-primitive-style.ts +1 -1
  36. package/corpus/templates/design/app/components/design/code-workbench/CodeWorkbench.tsx +8 -1
  37. package/corpus/templates/design/app/components/design/code-workbench/explorer/FileTree.tsx +55 -33
  38. package/corpus/templates/design/app/components/design/code-workbench/workspace/create-providers.ts +2 -0
  39. package/corpus/templates/design/app/components/design/code-workbench/workspace/inline-provider.ts +4 -2
  40. package/corpus/templates/design/app/components/design/edit-panel/component-section.tsx +273 -60
  41. package/corpus/templates/design/app/components/design/edit-panel/element-classification.ts +9 -2
  42. package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +57 -9
  43. package/corpus/templates/design/app/components/design/multi-screen/primitive-drop-target.ts +13 -0
  44. package/corpus/templates/design/app/components/design/multi-screen/types.ts +14 -0
  45. package/corpus/templates/design/app/components/design/types.ts +9 -1
  46. package/corpus/templates/design/app/hooks/use-design-versions.ts +3 -2
  47. package/corpus/templates/design/app/i18n-breakpoints.ts +0 -110
  48. package/corpus/templates/design/app/i18n-data.ts +0 -10
  49. package/corpus/templates/design/app/pages/DesignEditor.tsx +669 -161
  50. package/corpus/templates/design/app/pages/design-editor/clone-and-pen-edit.ts +20 -0
  51. package/corpus/templates/design/app/pages/design-editor/code-layer-state.ts +2 -0
  52. package/corpus/templates/design/app/pages/design-editor/commands/apply-design-editor-command.ts +21 -3
  53. package/corpus/templates/design/app/pages/design-editor/commands/apply-file-content-update.ts +2 -0
  54. package/corpus/templates/design/app/pages/design-editor/commands/create-component.ts +44 -3
  55. package/corpus/templates/design/app/pages/design-editor/commands/delete-files.ts +69 -47
  56. package/corpus/templates/design/app/pages/design-editor/commands/duplicate-screen.ts +157 -52
  57. package/corpus/templates/design/app/pages/design-editor/commands/duplicate-selection.ts +76 -1
  58. package/corpus/templates/design/app/pages/design-editor/commands/redo.ts +152 -44
  59. package/corpus/templates/design/app/pages/design-editor/commands/save-file-content.ts +131 -2
  60. package/corpus/templates/design/app/pages/design-editor/commands/screen-visual-duplicate-change.ts +5 -1
  61. package/corpus/templates/design/app/pages/design-editor/commands/undo.ts +26 -1
  62. package/corpus/templates/design/app/pages/design-editor/commands/visual-duplicate-change.ts +1 -0
  63. package/corpus/templates/design/app/pages/design-editor/editor-helpers.ts +58 -8
  64. package/corpus/templates/design/app/pages/design-editor/editor-state.ts +63 -2
  65. package/corpus/templates/design/app/pages/design-editor/history.ts +3 -0
  66. package/corpus/templates/design/app/pages/design-editor/nudge-intent.ts +74 -22
  67. package/corpus/templates/design/app/pages/design-editor/source-publication.ts +14 -2
  68. package/corpus/templates/design/changelog/2026-09-16-design-components-retain-linked-identities-when-edited-and-d.md +6 -0
  69. package/corpus/templates/design/changelog/2026-09-16-fix-design-nested-layer-dragging-and-screen-duplication-pari.md +6 -0
  70. package/corpus/templates/design/changelog/2026-09-17-design-drag-and-drop-keeps-duplicates-cross-screen-moves-and.md +6 -0
  71. package/corpus/templates/design/changelog/2026-09-17-design-preserves-reusable-component-identity-and-props-acros.md +6 -0
  72. package/corpus/templates/design/changelog/2026-09-17-open-vector-paths-no-longer-show-fills-and-interact-dimensio.md +6 -0
  73. package/corpus/templates/design/changelog/2026-09-17-screen-deletion-is-immediate-and-undoable-with-history-that-.md +6 -0
  74. package/corpus/templates/design/e2e/fixtures/design-component-react/index.html +98 -0
  75. package/corpus/templates/design/e2e/fixtures/design-component-react/inline-component.html +65 -0
  76. package/corpus/templates/design/e2e/helpers.ts +6 -1
  77. package/corpus/templates/design/server/lib/design-data-mutation.ts +9 -5
  78. package/corpus/templates/design/server/lib/design-snapshot.ts +28 -16
  79. package/corpus/templates/design/server/lib/design-versions.ts +208 -130
  80. package/corpus/templates/design/server/lib/fusion-screens.ts +46 -20
  81. package/corpus/templates/design/server/lib/import-design-files.ts +5 -1
  82. package/corpus/templates/design/server/lib/localhost-connection.ts +54 -0
  83. package/corpus/templates/design/server/source-workspace.ts +412 -356
  84. package/corpus/templates/design/shared/component-library.ts +36 -6
  85. package/corpus/templates/design/shared/component-model.ts +12 -2
  86. package/corpus/templates/design/shared/local-jsx-visual-edit.ts +231 -5
  87. package/corpus/templates/design/shared/source-mode.ts +22 -0
  88. package/dist/automation/index.d.ts +1 -1
  89. package/dist/client/AssistantChat.d.ts +4 -1
  90. package/dist/client/AssistantChat.js +26 -3
  91. package/dist/client/chat/agentkit-protocol.js +148 -34
  92. package/dist/client/chat/message-components.js +7 -5
  93. package/dist/client/chat/tool-call-display.js +4 -3
  94. package/dist/client/conversation/AgentConversation.js +4 -2
  95. package/dist/client/tool-display.d.ts +9 -0
  96. package/dist/client/tool-display.js +15 -0
  97. package/dist/collab/awareness.d.ts +2 -2
  98. package/dist/collab/routes.d.ts +1 -1
  99. package/dist/localization/core-messages/ar-SA.js +2 -0
  100. package/dist/localization/core-messages/de-DE.js +2 -0
  101. package/dist/localization/core-messages/en-US.d.ts +2 -0
  102. package/dist/localization/core-messages/en-US.js +2 -0
  103. package/dist/localization/core-messages/es-ES.js +2 -0
  104. package/dist/localization/core-messages/fr-FR.js +2 -0
  105. package/dist/localization/core-messages/hi-IN.js +2 -0
  106. package/dist/localization/core-messages/ja-JP.js +2 -0
  107. package/dist/localization/core-messages/ko-KR.js +2 -0
  108. package/dist/localization/core-messages/pt-BR.js +2 -0
  109. package/dist/localization/core-messages/zh-CN.js +2 -0
  110. package/dist/localization/core-messages/zh-TW.js +2 -0
  111. package/dist/localization/core-messages.d.ts +2 -0
  112. package/dist/notifications/routes.d.ts +3 -3
  113. package/dist/observability/routes.d.ts +3 -3
  114. package/dist/resources/handlers.d.ts +1 -1
  115. package/dist/secrets/routes.d.ts +3 -3
  116. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  117. package/dist/server/core-routes-plugin.d.ts +1 -1
  118. package/package.json +3 -3
  119. package/corpus/templates/design/app/components/design/editor/PendingScreenDeletionDialog.tsx +0 -66
@@ -991,20 +991,29 @@ declare var __INITIAL_SOURCE_HEAD__: string;
991
991
  ];
992
992
 
993
993
  function reactFiberOf(el: Element): any {
994
- var keys = Object.keys(el);
994
+ var keys = Object.getOwnPropertyNames(el);
995
+ var fallback = null;
995
996
  for (var i = 0; i < keys.length; i += 1) {
996
997
  for (var j = 0; j < REACT_FIBER_KEY_PREFIXES.length; j += 1) {
997
998
  if (keys[i]!.indexOf(REACT_FIBER_KEY_PREFIXES[j]!) === 0) {
998
- return (el as unknown as Record<string, any>)[keys[i]!];
999
+ var fiber = (el as unknown as Record<string, any>)[keys[i]!];
1000
+ if (!fallback) fallback = fiber;
1001
+ if (fiber && fiber._debugSource) return fiber;
999
1002
  }
1000
1003
  }
1001
1004
  }
1002
- return null;
1005
+ return fallback;
1003
1006
  }
1004
1007
 
1005
1008
  function reactDebugProvenance(el: Element): FrameworkDebugProvenance {
1006
1009
  var cached = reactDebugProvenanceCache?.get(el);
1007
- if (cached !== undefined) return cached;
1010
+ if (
1011
+ cached !== undefined &&
1012
+ (cached.method === "debug-source" ||
1013
+ cached.method === "debug-stack-remapped")
1014
+ ) {
1015
+ return cached;
1016
+ }
1008
1017
  // Deliberately no climb to an ancestor's fiber: this runs over every node
1009
1018
  // in the runtime snapshot, and borrowing a parent's location would stamp a
1010
1019
  // non-React node with a source line that is not its own.
@@ -1674,10 +1683,8 @@ declare var __INITIAL_SOURCE_HEAD__: string;
1674
1683
  cloneNode.setAttribute("data-an-runtime-layer-remove", "true");
1675
1684
  continue;
1676
1685
  }
1677
- cloneNode.setAttribute(
1678
- "data-agent-native-node-id",
1679
- ensureRuntimeLayerNodeId(sourceNode),
1680
- );
1686
+ var runtimeNodeId = ensureRuntimeLayerNodeId(sourceNode);
1687
+ cloneNode.setAttribute("data-agent-native-node-id", runtimeNodeId);
1681
1688
  inlineSnapshotComputedStyle(sourceNode, cloneNode);
1682
1689
  var provenance = elementDebugProvenance(sourceNode);
1683
1690
  if (provenance.sourceFile) {
@@ -1700,6 +1707,25 @@ declare var __INITIAL_SOURCE_HEAD__: string;
1700
1707
  if (provenance.component) {
1701
1708
  cloneNode.setAttribute("data-component-name", provenance.component);
1702
1709
  }
1710
+ var runtimeComponent = runtimeComponentIdentityForElement(
1711
+ sourceNode,
1712
+ provenance,
1713
+ runtimeNodeId,
1714
+ );
1715
+ if (runtimeComponent) {
1716
+ cloneNode.setAttribute(
1717
+ "data-agent-native-runtime-component-id",
1718
+ runtimeComponent.componentId,
1719
+ );
1720
+ cloneNode.setAttribute(
1721
+ "data-agent-native-runtime-instance-id",
1722
+ runtimeComponent.instanceId,
1723
+ );
1724
+ cloneNode.setAttribute(
1725
+ "data-agent-native-runtime-component-capability",
1726
+ runtimeComponent.writeCapability,
1727
+ );
1728
+ }
1703
1729
  if (provenance.ownerSourceFile) {
1704
1730
  cloneNode.setAttribute(
1705
1731
  "data-source-owner-file",
@@ -2539,6 +2565,82 @@ declare var __INITIAL_SOURCE_HEAD__: string;
2539
2565
  return layerNameForElement(el);
2540
2566
  }
2541
2567
 
2568
+ function runtimeComponentPropsForElement(
2569
+ el: Element,
2570
+ ): Array<{ name: string; value: string }> {
2571
+ var props: Array<{ name: string; value: string }> = [];
2572
+ if (!el.attributes) return props;
2573
+ for (var index = 0; index < el.attributes.length; index += 1) {
2574
+ var attribute = el.attributes[index];
2575
+ if (!attribute || attribute.name.indexOf("data-agent-native-prop-") !== 0)
2576
+ continue;
2577
+ var rawName = attribute.name.slice("data-agent-native-prop-".length);
2578
+ if (!rawName) continue;
2579
+ props.push({
2580
+ name: rawName.replace(/-([a-z])/g, function (_match, letter) {
2581
+ return String(letter).toUpperCase();
2582
+ }),
2583
+ value: attribute.value,
2584
+ });
2585
+ }
2586
+ return props;
2587
+ }
2588
+
2589
+ /** Runtime identity is separate from the persisted component annotation. */
2590
+ function runtimeComponentIdentityForElement(
2591
+ el: Element,
2592
+ provenance: FrameworkDebugProvenance,
2593
+ instanceId: string,
2594
+ ): any {
2595
+ var name = provenance.component && provenance.component.trim();
2596
+ var definitionSourceFile =
2597
+ provenance.sourceFile && provenance.sourceFile.trim();
2598
+ var invocationSourceFile =
2599
+ provenance.ownerSourceFile && provenance.ownerSourceFile.trim();
2600
+ var invocationLine = provenance.ownerLine;
2601
+ var invocationColumn = provenance.ownerColumn;
2602
+ var invocationMethod = provenance.ownerMethod;
2603
+ if (
2604
+ !name ||
2605
+ !definitionSourceFile ||
2606
+ !provenance.framework ||
2607
+ provenance.framework === "html" ||
2608
+ !instanceId
2609
+ ) {
2610
+ return undefined;
2611
+ }
2612
+ var boundary = [
2613
+ provenance.framework,
2614
+ definitionSourceFile,
2615
+ provenance.line || "",
2616
+ provenance.column || "",
2617
+ name,
2618
+ ].join("|");
2619
+ var writable =
2620
+ provenance.framework === "react" &&
2621
+ invocationSourceFile !== undefined &&
2622
+ invocationMethod !== undefined &&
2623
+ invocationMethod !== "debug-stack" &&
2624
+ Number.isFinite(invocationLine) &&
2625
+ Number.isFinite(invocationColumn);
2626
+ return {
2627
+ componentId: "runtime-component-" + runtimeLayerHash(boundary),
2628
+ instanceId: instanceId,
2629
+ name: name,
2630
+ framework: provenance.framework,
2631
+ sourceFile: invocationSourceFile,
2632
+ line: invocationLine,
2633
+ column: invocationColumn,
2634
+ method: invocationMethod,
2635
+ ownerKey: provenance.ownerKey,
2636
+ props: runtimeComponentPropsForElement(el),
2637
+ writeCapability: writable ? "authored-jsx-literal" : "unsupported",
2638
+ reason: writable
2639
+ ? undefined
2640
+ : "The runtime did not expose a verified authored component invocation location.",
2641
+ };
2642
+ }
2643
+
2542
2644
  function isAutoLayoutDisplay(display: string | undefined): boolean {
2543
2645
  return (
2544
2646
  display === "flex" ||
@@ -3605,6 +3707,7 @@ declare var __INITIAL_SOURCE_HEAD__: string;
3605
3707
  alignItems: parentStyles.alignItems,
3606
3708
  justifyContent: parentStyles.justifyContent,
3607
3709
  gap: parentStyles.gap,
3710
+ gridAutoFlow: parentStyles.gridAutoFlow,
3608
3711
  gridTemplateColumns: parentStyles.gridTemplateColumns,
3609
3712
  gridTemplateRows: parentStyles.gridTemplateRows,
3610
3713
  position: parentStyles.position,
@@ -3649,10 +3752,17 @@ declare var __INITIAL_SOURCE_HEAD__: string;
3649
3752
  // site; framework runtime metadata fills the React owner call site. The
3650
3753
  // shared resolver crosses ShadowRoot.host for Vue, Svelte, and attributes.
3651
3754
  var provenance: FrameworkDebugProvenance = elementDebugProvenance(el);
3755
+ var runtimeComponent = runtimeComponentIdentityForElement(
3756
+ el,
3757
+ provenance,
3758
+ sourceId || runtimeSourceId || pendingNodeId || getSelector(el),
3759
+ );
3652
3760
  var portableStyleSnapshot = collectPortableStyleSnapshot(el);
3653
3761
  return {
3654
3762
  tagName: el.tagName.toLowerCase(),
3655
3763
  componentName: componentName || undefined,
3764
+ componentAnnotation: explicitComponentNameForElement(el) || undefined,
3765
+ runtimeComponent: runtimeComponent,
3656
3766
  id: el.id || undefined,
3657
3767
  sourceId: sourceId,
3658
3768
  runtimeSelector: runtimeSelector || undefined,
@@ -16023,8 +16133,11 @@ declare var __INITIAL_SOURCE_HEAD__: string;
16023
16133
 
16024
16134
  var originLeft = gestureState.originLeft;
16025
16135
  var originTop = gestureState.originTop;
16026
- var startX = e.clientX;
16027
- var startY = e.clientY;
16136
+ // Shield drags hand off after crossing their outer threshold. The legacy
16137
+ // moved flag must use the original press too, or a small follow-up delta
16138
+ // is mistaken for an Alt-click and the optimistic clone is removed.
16139
+ var startX = pointerStartParam ? pointerStartParam.clientX : e.clientX;
16140
+ var startY = pointerStartParam ? pointerStartParam.clientY : e.clientY;
16028
16141
  // Snapshot the element being moved so that a concurrent select-element or
16029
16142
  // clear-selection postMessage cannot swap selectedEl mid-drag and cause
16030
16143
  // mutations on the wrong element or a null-deref in onUp.
@@ -16063,11 +16176,15 @@ declare var __INITIAL_SOURCE_HEAD__: string;
16063
16176
  bridgeMoveController.pointerDown({
16064
16177
  kind: "move",
16065
16178
  objectIds: [getSelector(gestureEl)],
16066
- // `e` is deliberately the event that actually began the legacy move
16067
- // lifecycle, not `pointerStartParam`: anchoring the controller at the
16068
- // pointerdown moves the element the extra threshold-crossing distance,
16069
- // which breaks the cross-screen drop's target resolution.
16070
- pointer: bridgeGesturePointer(e),
16179
+ // Shield drags begin here after their threshold-crossing event. For an
16180
+ // alt-drag, the clone must include the movement from the original press;
16181
+ // plain shield drags keep their existing threshold-relative baseline so
16182
+ // cross-screen target resolution is unchanged.
16183
+ pointer: bridgeGesturePointer(
16184
+ duplicatedForDrag && pointerStartParam
16185
+ ? { ...e, ...pointerStartParam }
16186
+ : e,
16187
+ ),
16071
16188
  viewport: gestureViewport,
16072
16189
  canvas: { width: gestureViewport.width, height: gestureViewport.height },
16073
16190
  });
@@ -16112,7 +16229,7 @@ declare var __INITIAL_SOURCE_HEAD__: string;
16112
16229
  var dragElOffsetScaleX = ancestorScale(dragEl, "x");
16113
16230
  var dragElOffsetScaleY = ancestorScale(dragEl, "y");
16114
16231
  if (!isGroupDrag) {
16115
- postCrossScreenDrag("start", dragEl, e, {
16232
+ postCrossScreenDrag("start", dragEl, pointerStartParam || e, {
16116
16233
  duplicate: duplicatedForDrag,
16117
16234
  });
16118
16235
  }
@@ -16244,15 +16361,14 @@ declare var __INITIAL_SOURCE_HEAD__: string;
16244
16361
  // host only resends a claim message on a claimed-value CHANGE, so
16245
16362
  // once clobbered it stayed false for the rest of the drag with no
16246
16363
  // further message ever arriving to correct it.
16247
- currentAutoLayoutTarget =
16248
- !duplicatedForDrag && !bridgeSpaceKeyPressed
16249
- ? autoLayoutInsertionTargetForPoint(
16250
- dragEl,
16251
- ev.clientX,
16252
- ev.clientY,
16253
- groupOthers,
16254
- )
16255
- : null;
16364
+ currentAutoLayoutTarget = !bridgeSpaceKeyPressed
16365
+ ? autoLayoutInsertionTargetForPoint(
16366
+ dragEl,
16367
+ ev.clientX,
16368
+ ev.clientY,
16369
+ groupOthers,
16370
+ )
16371
+ : null;
16256
16372
  if (currentAutoLayoutTarget && ev.ctrlKey) {
16257
16373
  currentAutoLayoutTarget = ignoreAutoLayoutForDropTarget(
16258
16374
  currentAutoLayoutTarget,
@@ -16374,6 +16490,11 @@ declare var __INITIAL_SOURCE_HEAD__: string;
16374
16490
  positionOverlay(selectionOverlay, selectedEl);
16375
16491
  postElementSelect(selectedEl);
16376
16492
  postCrossScreenDrag("cancel");
16493
+ } else if (!isGroupDrag) {
16494
+ // A selection-box press that never crosses the drag threshold still
16495
+ // arms the host's cross-screen listener. Clear that claim on the
16496
+ // click path too, or the next drag inherits a stale board gesture.
16497
+ postCrossScreenDrag("cancel");
16377
16498
  }
16378
16499
  return;
16379
16500
  }
@@ -16410,12 +16531,7 @@ declare var __INITIAL_SOURCE_HEAD__: string;
16410
16531
  }
16411
16532
  return;
16412
16533
  }
16413
- if (
16414
- ev &&
16415
- !duplicatedForDrag &&
16416
- !outsideOnDrop &&
16417
- !bridgeSpaceKeyPressed
16418
- ) {
16534
+ if (ev && !outsideOnDrop && !bridgeSpaceKeyPressed) {
16419
16535
  var finalAutoLayoutTarget = autoLayoutInsertionTargetForPoint(
16420
16536
  dragEl,
16421
16537
  ev.clientX,
@@ -16450,7 +16566,7 @@ declare var __INITIAL_SOURCE_HEAD__: string;
16450
16566
  postVisualDuplicateChange(
16451
16567
  originalSelectedEl,
16452
16568
  dragEl,
16453
- null,
16569
+ currentAutoLayoutTarget,
16454
16570
  duplicatedSourceNodeIdMap,
16455
16571
  );
16456
16572
  postCrossScreenDrag("cancel");
@@ -21176,6 +21292,9 @@ declare var __INITIAL_SOURCE_HEAD__: string;
21176
21292
  "aria-label",
21177
21293
  "class",
21178
21294
  "data-agent-native-component",
21295
+ "data-agent-native-runtime-component-capability",
21296
+ "data-agent-native-runtime-component-id",
21297
+ "data-agent-native-runtime-instance-id",
21179
21298
  "data-agent-native-layer-name",
21180
21299
  "data-layer-name",
21181
21300
  "layer-name",
@@ -535,6 +535,10 @@
535
535
  // getNodeId itself (a pending id is not a stable id until persisted).
536
536
  function getOrMintPendingNodeId(el: Element | null): string {
537
537
  if (!el || !el.getAttribute || !el.setAttribute) return "";
538
+ // The document body is the root fallback for an empty-screen drop, not a
539
+ // durable layer anchor. Minting a pending id here makes the host treat the
540
+ // root as an unresolved authored node and refuse the otherwise valid drop.
541
+ if (el === document.body || el === document.documentElement) return "";
538
542
  // Defensive guard: resolveHitTarget's anchor-candidate gates (see
539
543
  // isTemplateCloneElement call sites there) already keep template clones
540
544
  // out of `result.anchor`, so this should never fire in practice — but a
@@ -130,7 +130,7 @@ export function canvasVectorPaint(overrides: {
130
130
  }): CanvasVectorPaint {
131
131
  const { closed, fill, stroke, strokeWidth } = overrides;
132
132
  return {
133
- fill: fill ?? (closed ? DEFAULT_SHAPE_FILL : "none"),
133
+ fill: closed ? (fill ?? DEFAULT_SHAPE_FILL) : "none",
134
134
  stroke: stroke ?? (closed ? "none" : DEFAULT_LINE_STROKE),
135
135
  strokeWidth: strokeWidth ?? DEFAULT_LINE_STROKE_WIDTH_PX,
136
136
  };
@@ -69,6 +69,7 @@ export interface CodeWorkbenchProps {
69
69
  selectedNodeId?: string | null;
70
70
  selectedSelector?: string | null;
71
71
  localhostConnections?: CodeWorkbenchLocalhostConnection[];
72
+ onDeleteInlineFile?: (fileId: string) => void | Promise<void>;
72
73
  onActiveFileChange?: (file: CodeWorkbenchActiveFile | null) => void;
73
74
  onRequestLocalWriteConsent?: (
74
75
  connectionId: string,
@@ -84,9 +85,15 @@ export function CodeWorkbench(props: CodeWorkbenchProps) {
84
85
  createWorkspaceProviders({
85
86
  designId: props.designId,
86
87
  canEdit: props.canEdit,
88
+ onDeleteInlineFile: props.onDeleteInlineFile,
87
89
  localhostConnections: props.localhostConnections ?? [],
88
90
  }),
89
- [props.designId, props.canEdit, props.localhostConnections],
91
+ [
92
+ props.designId,
93
+ props.canEdit,
94
+ props.localhostConnections,
95
+ props.onDeleteInlineFile,
96
+ ],
90
97
  );
91
98
  return (
92
99
  <WorkbenchProvider key={props.designId} providers={providers}>
@@ -179,16 +179,36 @@ export function FileTree({
179
179
  [api, handleWriteError, providerKey, renameDraft],
180
180
  );
181
181
 
182
- const commitDelete = useCallback(async () => {
182
+ const commitDelete = useCallback(
183
+ async (target: TreeNode) => {
184
+ try {
185
+ await api.deleteFile(providerKey, target.path);
186
+ } catch (error) {
187
+ handleWriteError(error);
188
+ }
189
+ },
190
+ [api, handleWriteError, providerKey],
191
+ );
192
+
193
+ const confirmDelete = useCallback(() => {
183
194
  if (!deleteTarget) return;
184
195
  const target = deleteTarget;
185
196
  setDeleteTarget(null);
186
- try {
187
- await api.deleteFile(providerKey, target.path);
188
- } catch (error) {
189
- handleWriteError(error);
190
- }
191
- }, [api, deleteTarget, handleWriteError, providerKey]);
197
+ void commitDelete(target);
198
+ }, [commitDelete, deleteTarget]);
199
+
200
+ const requestDelete = useCallback(
201
+ (target: TreeNode) => {
202
+ if (providerKey.startsWith("inline:")) {
203
+ // Inline Design files are covered by the editor's durable undo/history
204
+ // boundary; external providers remain confirmation-gated below.
205
+ void commitDelete(target);
206
+ } else {
207
+ setDeleteTarget(target);
208
+ }
209
+ },
210
+ [commitDelete, providerKey],
211
+ );
192
212
 
193
213
  const commitNewFile = useCallback(async () => {
194
214
  if (!pendingNewFile) return;
@@ -496,7 +516,7 @@ export function FileTree({
496
516
  {canDeleteNode ? (
497
517
  <ContextMenuItem
498
518
  className="text-[12px] text-destructive focus:text-destructive"
499
- onSelect={() => setDeleteTarget(row.node)}
519
+ onSelect={() => requestDelete(row.node)}
500
520
  >
501
521
  {"Delete" /* i18n-ignore */}
502
522
  </ContextMenuItem>
@@ -572,32 +592,34 @@ export function FileTree({
572
592
  />
573
593
  </div>
574
594
  ) : null}
595
+ <AlertDialog
596
+ open={Boolean(deleteTarget)}
597
+ onOpenChange={(open) => {
598
+ if (!open) setDeleteTarget(null);
599
+ }}
600
+ >
601
+ <AlertDialogContent>
602
+ <AlertDialogHeader>
603
+ <AlertDialogTitle>
604
+ {"Delete file?" /* i18n-ignore */}
605
+ </AlertDialogTitle>
606
+ <AlertDialogDescription>
607
+ {deleteTarget?.path
608
+ ? `"${deleteTarget.path}" will be permanently deleted.` /* i18n-ignore */
609
+ : ""}
610
+ </AlertDialogDescription>
611
+ </AlertDialogHeader>
612
+ <AlertDialogFooter>
613
+ <AlertDialogCancel>
614
+ {"Cancel" /* i18n-ignore */}
615
+ </AlertDialogCancel>
616
+ <AlertDialogAction onClick={confirmDelete}>
617
+ {"Delete" /* i18n-ignore */}
618
+ </AlertDialogAction>
619
+ </AlertDialogFooter>
620
+ </AlertDialogContent>
621
+ </AlertDialog>
575
622
  </div>
576
- <AlertDialog
577
- open={Boolean(deleteTarget)}
578
- onOpenChange={(open) => {
579
- if (!open) setDeleteTarget(null);
580
- }}
581
- >
582
- <AlertDialogContent>
583
- <AlertDialogHeader>
584
- <AlertDialogTitle>
585
- {"Delete file?" /* i18n-ignore */}
586
- </AlertDialogTitle>
587
- <AlertDialogDescription>
588
- {deleteTarget?.path
589
- ? `"${deleteTarget.path}" will be permanently deleted.` /* i18n-ignore */
590
- : ""}
591
- </AlertDialogDescription>
592
- </AlertDialogHeader>
593
- <AlertDialogFooter>
594
- <AlertDialogCancel>{"Cancel" /* i18n-ignore */}</AlertDialogCancel>
595
- <AlertDialogAction onClick={() => void commitDelete()}>
596
- {"Delete" /* i18n-ignore */}
597
- </AlertDialogAction>
598
- </AlertDialogFooter>
599
- </AlertDialogContent>
600
- </AlertDialog>
601
623
  </div>
602
624
  );
603
625
  }
@@ -5,6 +5,7 @@ import type { WorkspaceProvider } from "./types";
5
5
  export interface CreateWorkspaceProvidersOptions {
6
6
  designId: string;
7
7
  canEdit: boolean;
8
+ onDeleteInlineFile?: (fileId: string) => void | Promise<void>;
8
9
  localhostConnections: Array<{
9
10
  connectionId: string;
10
11
  label: string;
@@ -24,6 +25,7 @@ export function createWorkspaceProviders(
24
25
  createInlineProvider({
25
26
  designId: options.designId,
26
27
  canEdit: options.canEdit,
28
+ onDeleteFile: options.onDeleteInlineFile,
27
29
  }),
28
30
  ];
29
31
  for (const connection of options.localhostConnections) {
@@ -54,12 +54,13 @@ interface CreateFileResponse {
54
54
  export interface CreateInlineProviderOptions {
55
55
  designId: string;
56
56
  canEdit: boolean;
57
+ onDeleteFile?: (fileId: string) => void | Promise<void>;
57
58
  }
58
59
 
59
60
  export function createInlineProvider(
60
61
  options: CreateInlineProviderOptions,
61
62
  ): WorkspaceProvider {
62
- const { designId, canEdit } = options;
63
+ const { designId, canEdit, onDeleteFile } = options;
63
64
  const key = `inline:${designId}`;
64
65
  // path -> fileId, populated by listFiles and refreshed on demand so
65
66
  // renameFile/deleteFile can resolve a file's id without re-listing when
@@ -177,7 +178,8 @@ export function createInlineProvider(
177
178
 
178
179
  async function deleteFile(path: string): Promise<void> {
179
180
  const id = await resolveFileId(path);
180
- await callAction("delete-file", { id });
181
+ if (onDeleteFile) await onDeleteFile(id);
182
+ else await callAction("delete-file", { id });
181
183
  fileIdByPath.delete(path);
182
184
  }
183
185