@agent-native/core 0.163.4 → 0.164.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (200) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/app/hooks/use-dashboard-chat-context.ts +29 -0
  3. package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +1 -2
  4. package/corpus/templates/analytics/netlify.toml +2 -0
  5. package/corpus/templates/assets/netlify.toml +2 -0
  6. package/corpus/templates/brain/netlify.toml +2 -0
  7. package/corpus/templates/calendar/app/components/calendar/DayView.tsx +2 -1
  8. package/corpus/templates/calendar/changelog/2026-08-19-calendar-page-loads-stay-fast-after-idle-periods.md +6 -0
  9. package/corpus/templates/calendar/netlify.toml +2 -0
  10. package/corpus/templates/chat/netlify.toml +2 -0
  11. package/corpus/templates/clips/app/components/player/player-controls.tsx +3 -3
  12. package/corpus/templates/clips/app/components/player/reaction-emojis.ts +12 -0
  13. package/corpus/templates/clips/app/components/player/reactions-tray.tsx +90 -9
  14. package/corpus/templates/clips/app/components/player/scrubber.tsx +43 -10
  15. package/corpus/templates/clips/app/components/player/video-player.tsx +105 -15
  16. package/corpus/templates/clips/app/routes/_app.settings._index.tsx +1 -2
  17. package/corpus/templates/clips/app/routes/_index.tsx +10 -2
  18. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +13 -8
  19. package/corpus/templates/clips/app/routes/share.$shareId.tsx +15 -8
  20. package/corpus/templates/clips/netlify.toml +2 -0
  21. package/corpus/templates/clips/server/routes/[...page].head.ts +5 -0
  22. package/corpus/templates/content/netlify.toml +2 -0
  23. package/corpus/templates/design/.agents/skills/design-editor-architecture/SKILL.md +103 -0
  24. package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +2 -1
  25. package/corpus/templates/design/AGENTS.md +3 -1
  26. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +3 -2
  27. package/corpus/templates/design/app/components/design/editor/AgentNativeMenuMark.tsx +25 -0
  28. package/corpus/templates/design/app/components/design/editor/DesignBottomToolbar.tsx +411 -0
  29. package/corpus/templates/design/app/components/design/editor/DesignCollaborators.tsx +153 -0
  30. package/corpus/templates/design/app/components/design/editor/DesignWorkspaceRail.tsx +231 -0
  31. package/corpus/templates/design/app/components/design/editor/MakeRealDialog.tsx +223 -0
  32. package/corpus/templates/design/app/components/design/editor/PendingScreenDeletionDialog.tsx +58 -0
  33. package/corpus/templates/design/app/components/design/editor/PendingVisualStyleWarningDialog.tsx +56 -0
  34. package/corpus/templates/design/app/components/design/editor/ReadOnlyEditorPanel.tsx +23 -0
  35. package/corpus/templates/design/app/components/design/editor/SaveTemplateDialog.tsx +161 -0
  36. package/corpus/templates/design/app/components/design/editor/toolbar-controls.tsx +185 -0
  37. package/corpus/templates/design/app/pages/DesignEditor.tsx +20913 -0
  38. package/corpus/templates/design/app/pages/design-editor/command-types.ts +120 -0
  39. package/corpus/templates/design/app/pages/design-editor/commands/README.md +193 -0
  40. package/corpus/templates/design/app/pages/design-editor/commands/add-auto-layout.ts +416 -0
  41. package/corpus/templates/design/app/pages/design-editor/commands/add-screen.ts +112 -0
  42. package/corpus/templates/design/app/pages/design-editor/commands/align-selection.ts +183 -0
  43. package/corpus/templates/design/app/pages/design-editor/commands/apply-design-editor-command.ts +243 -0
  44. package/corpus/templates/design/app/pages/design-editor/commands/apply-file-content-update.ts +236 -0
  45. package/corpus/templates/design/app/pages/design-editor/commands/apply-local-content-update.ts +304 -0
  46. package/corpus/templates/design/app/pages/design-editor/commands/apply-pending-visual-styles-with-agent.ts +376 -0
  47. package/corpus/templates/design/app/pages/design-editor/commands/apply-to-source.ts +132 -0
  48. package/corpus/templates/design/app/pages/design-editor/commands/can-move-layer.ts +117 -0
  49. package/corpus/templates/design/app/pages/design-editor/commands/change-selected-z-index.ts +212 -0
  50. package/corpus/templates/design/app/pages/design-editor/commands/commit-relative-style-delta-to-selected-layers.ts +176 -0
  51. package/corpus/templates/design/app/pages/design-editor/commands/commit-styles-to-selected-layers.ts +175 -0
  52. package/corpus/templates/design/app/pages/design-editor/commands/commit-visual-styles.ts +710 -0
  53. package/corpus/templates/design/app/pages/design-editor/commands/confirm-make-real.ts +99 -0
  54. package/corpus/templates/design/app/pages/design-editor/commands/copy-as-figma-svg.ts +95 -0
  55. package/corpus/templates/design/app/pages/design-editor/commands/copy-selection.ts +156 -0
  56. package/corpus/templates/design/app/pages/design-editor/commands/create-primitive.ts +291 -0
  57. package/corpus/templates/design/app/pages/design-editor/commands/create-screen-frame.ts +131 -0
  58. package/corpus/templates/design/app/pages/design-editor/commands/cross-screen-element-drop.ts +577 -0
  59. package/corpus/templates/design/app/pages/design-editor/commands/delete-files.ts +364 -0
  60. package/corpus/templates/design/app/pages/design-editor/commands/delete-selection.ts +521 -0
  61. package/corpus/templates/design/app/pages/design-editor/commands/detach-instance-menu-action.ts +88 -0
  62. package/corpus/templates/design/app/pages/design-editor/commands/distribute-selection.ts +114 -0
  63. package/corpus/templates/design/app/pages/design-editor/commands/download-all-screens-pdf.ts +116 -0
  64. package/corpus/templates/design/app/pages/design-editor/commands/download-pdf.ts +103 -0
  65. package/corpus/templates/design/app/pages/design-editor/commands/download-svg.ts +159 -0
  66. package/corpus/templates/design/app/pages/design-editor/commands/duplicate-screen.ts +201 -0
  67. package/corpus/templates/design/app/pages/design-editor/commands/duplicate-selection.ts +279 -0
  68. package/corpus/templates/design/app/pages/design-editor/commands/editor-paste.ts +81 -0
  69. package/corpus/templates/design/app/pages/design-editor/commands/enter-hotkey.ts +155 -0
  70. package/corpus/templates/design/app/pages/design-editor/commands/enter-single-screen.ts +168 -0
  71. package/corpus/templates/design/app/pages/design-editor/commands/escape-hotkey.ts +212 -0
  72. package/corpus/templates/design/app/pages/design-editor/commands/frame-selection.ts +119 -0
  73. package/corpus/templates/design/app/pages/design-editor/commands/geometry-commit.ts +169 -0
  74. package/corpus/templates/design/app/pages/design-editor/commands/get-selected-layer-snapshots.ts +177 -0
  75. package/corpus/templates/design/app/pages/design-editor/commands/group-selection.ts +127 -0
  76. package/corpus/templates/design/app/pages/design-editor/commands/iframe-context-menu.ts +121 -0
  77. package/corpus/templates/design/app/pages/design-editor/commands/import-figma-clipboard-into-design.ts +119 -0
  78. package/corpus/templates/design/app/pages/design-editor/commands/layer-marquee-selection-change.ts +163 -0
  79. package/corpus/templates/design/app/pages/design-editor/commands/layer-move-to-screen.ts +331 -0
  80. package/corpus/templates/design/app/pages/design-editor/commands/layer-move.ts +517 -0
  81. package/corpus/templates/design/app/pages/design-editor/commands/layer-rename.ts +247 -0
  82. package/corpus/templates/design/app/pages/design-editor/commands/layer-selection-change.ts +161 -0
  83. package/corpus/templates/design/app/pages/design-editor/commands/mode-change.ts +122 -0
  84. package/corpus/templates/design/app/pages/design-editor/commands/nudge-selection.ts +213 -0
  85. package/corpus/templates/design/app/pages/design-editor/commands/overview-primitive-reparent.ts +318 -0
  86. package/corpus/templates/design/app/pages/design-editor/commands/paste-copied-screens.ts +114 -0
  87. package/corpus/templates/design/app/pages/design-editor/commands/paste-over-selection.ts +70 -0
  88. package/corpus/templates/design/app/pages/design-editor/commands/paste-selection.ts +436 -0
  89. package/corpus/templates/design/app/pages/design-editor/commands/paste-to-replace.ts +135 -0
  90. package/corpus/templates/design/app/pages/design-editor/commands/pasted-image-files.ts +209 -0
  91. package/corpus/templates/design/app/pages/design-editor/commands/persist-frame-geometry-save.ts +113 -0
  92. package/corpus/templates/design/app/pages/design-editor/commands/persist-tweak-save.ts +160 -0
  93. package/corpus/templates/design/app/pages/design-editor/commands/primitive-created.ts +168 -0
  94. package/corpus/templates/design/app/pages/design-editor/commands/record-pending-live-layer-state-edit.ts +149 -0
  95. package/corpus/templates/design/app/pages/design-editor/commands/record-pending-live-structure-edit.ts +200 -0
  96. package/corpus/templates/design/app/pages/design-editor/commands/record-pending-live-text-edit.ts +152 -0
  97. package/corpus/templates/design/app/pages/design-editor/commands/record-pending-visual-style-edit.ts +247 -0
  98. package/corpus/templates/design/app/pages/design-editor/commands/redo.ts +1086 -0
  99. package/corpus/templates/design/app/pages/design-editor/commands/render-png-blob.ts +200 -0
  100. package/corpus/templates/design/app/pages/design-editor/commands/save-file-content.ts +207 -0
  101. package/corpus/templates/design/app/pages/design-editor/commands/screen-element-select.ts +262 -0
  102. package/corpus/templates/design/app/pages/design-editor/commands/screen-text-content-change.ts +216 -0
  103. package/corpus/templates/design/app/pages/design-editor/commands/screen-visual-duplicate-change.ts +108 -0
  104. package/corpus/templates/design/app/pages/design-editor/commands/screen-visual-structure-change.ts +280 -0
  105. package/corpus/templates/design/app/pages/design-editor/commands/screen-visual-style-change.ts +151 -0
  106. package/corpus/templates/design/app/pages/design-editor/commands/send-overview-annotations.ts +88 -0
  107. package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-move-semantic-handoff.ts +122 -0
  108. package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-semantic-handoff.ts +143 -0
  109. package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-state-semantic-handoff.ts +115 -0
  110. package/corpus/templates/design/app/pages/design-editor/commands/start-retry-generation.ts +152 -0
  111. package/corpus/templates/design/app/pages/design-editor/commands/start-sidebar-resize.ts +99 -0
  112. package/corpus/templates/design/app/pages/design-editor/commands/style-change.ts +152 -0
  113. package/corpus/templates/design/app/pages/design-editor/commands/styles-change.ts +155 -0
  114. package/corpus/templates/design/app/pages/design-editor/commands/suggest-auto-layout.ts +125 -0
  115. package/corpus/templates/design/app/pages/design-editor/commands/text-content-change.ts +201 -0
  116. package/corpus/templates/design/app/pages/design-editor/commands/tidy-up.ts +123 -0
  117. package/corpus/templates/design/app/pages/design-editor/commands/toggle-layer-hidden.ts +167 -0
  118. package/corpus/templates/design/app/pages/design-editor/commands/toggle-layer-locked.ts +175 -0
  119. package/corpus/templates/design/app/pages/design-editor/commands/toggle-motion-keyframe.ts +99 -0
  120. package/corpus/templates/design/app/pages/design-editor/commands/tweak-prompt-submit.ts +84 -0
  121. package/corpus/templates/design/app/pages/design-editor/commands/undo.ts +906 -0
  122. package/corpus/templates/design/app/pages/design-editor/commands/ungroup-selection.ts +170 -0
  123. package/corpus/templates/design/app/pages/design-editor/commands/visual-duplicate-change.ts +119 -0
  124. package/corpus/templates/design/app/pages/design-editor/commands/visual-structure-change.ts +274 -0
  125. package/corpus/templates/design/app/pages/design-editor/commands/write-frame-geometry-snapshot.ts +99 -0
  126. package/corpus/templates/design/app/pages/design-editor/derive/design-breakpoints.ts +56 -0
  127. package/corpus/templates/design/app/pages/design-editor/derive/overview-screens.ts +146 -0
  128. package/corpus/templates/design/app/pages/design-editor/domains/use-tweaks.ts +326 -0
  129. package/corpus/templates/design/app/pages/design-editor/editor-constants.ts +54 -0
  130. package/corpus/templates/design/app/pages/design-editor/editor-helpers.ts +183 -0
  131. package/corpus/templates/design/app/pages/design-editor/effects/adopt-db-file-content.ts +270 -0
  132. package/corpus/templates/design/app/pages/design-editor/effects/mirror-selection-to-agent-chat.ts +134 -0
  133. package/corpus/templates/design/app/pages/design-editor/effects/motion-autosave.ts +335 -0
  134. package/corpus/templates/design/app/pages/design-editor/effects/observe-collab-text.ts +183 -0
  135. package/corpus/templates/design/app/pages/design-editor/effects/publish-agent-selection-context.ts +252 -0
  136. package/corpus/templates/design/app/pages/design-editor/effects/resume-pending-generation.ts +178 -0
  137. package/corpus/templates/design/app/pages/design-editor/effects/seed-collab-content.ts +157 -0
  138. package/corpus/templates/design/app/pages/design-editor/preview-html.ts +19 -0
  139. package/corpus/templates/design/netlify.toml +2 -0
  140. package/corpus/templates/design/shared/board-file.ts +2 -1
  141. package/corpus/templates/dispatch/netlify.toml +2 -0
  142. package/corpus/templates/forms/netlify.toml +2 -0
  143. package/corpus/templates/mail/netlify.toml +2 -0
  144. package/corpus/templates/plan/netlify.toml +2 -0
  145. package/corpus/templates/slides/netlify.toml +2 -0
  146. package/dist/agent/engine/builder-engine.d.ts +6 -4
  147. package/dist/agent/engine/builder-engine.js +91 -26
  148. package/dist/agent/engine/registry.js +16 -0
  149. package/dist/cli/code-agent-agent-tools.d.ts +2 -0
  150. package/dist/cli/code-agent-agent-tools.js +188 -0
  151. package/dist/cli/code-agent-collaboration.d.ts +34 -0
  152. package/dist/cli/code-agent-collaboration.js +104 -0
  153. package/dist/cli/code-agent-executor.js +6 -0
  154. package/dist/cli/code-agent-schedules.d.ts +54 -0
  155. package/dist/cli/code-agent-schedules.js +198 -0
  156. package/dist/client/AgentPanel.js +1 -1
  157. package/dist/client/ConnectBuilderCard.js +5 -2
  158. package/dist/client/EnvironmentBadge.js +6 -5
  159. package/dist/client/chat/run-recovery.js +3 -2
  160. package/dist/client/chat/tool-call-display.js +2 -3
  161. package/dist/client/components/CodeRequiredDialog.js +4 -2
  162. package/dist/client/i18n.js +5 -4
  163. package/dist/client/settings/SettingsPanel.js +1 -1
  164. package/dist/client/settings/VoiceTranscriptionSection.js +1 -1
  165. package/dist/client/settings/useBuilderStatus.d.ts +6 -1
  166. package/dist/client/settings/useBuilderStatus.js +22 -33
  167. package/dist/client/transcription/BuilderTranscriptionCta.js +1 -1
  168. package/dist/code-agents/index.d.ts +2 -0
  169. package/dist/code-agents/index.js +2 -0
  170. package/dist/collab/routes.d.ts +1 -1
  171. package/dist/localization/shared.d.ts +2 -0
  172. package/dist/localization/shared.js +5 -0
  173. package/dist/mcp-client/oauth-client.d.ts +1 -0
  174. package/dist/mcp-client/oauth-client.js +50 -1
  175. package/dist/observability/routes.d.ts +1 -1
  176. package/dist/progress/routes.d.ts +1 -1
  177. package/dist/provider-api/actions/provider-api.d.ts +2 -2
  178. package/dist/resources/handlers.d.ts +1 -1
  179. package/dist/server/auth-marketing-locales.d.ts +7 -0
  180. package/dist/server/auth-marketing-locales.js +1322 -0
  181. package/dist/server/auth-marketing.d.ts +1 -0
  182. package/dist/server/auth-marketing.js +35 -6
  183. package/dist/server/auth.js +4 -17
  184. package/dist/server/builder-browser.d.ts +22 -0
  185. package/dist/server/builder-browser.js +77 -1
  186. package/dist/server/builder-oauth.d.ts +50 -0
  187. package/dist/server/builder-oauth.js +263 -0
  188. package/dist/server/core-routes-plugin.d.ts +11 -0
  189. package/dist/server/core-routes-plugin.js +291 -415
  190. package/dist/server/credential-provider.d.ts +1 -1
  191. package/dist/server/credential-provider.js +1 -1
  192. package/dist/server/csrf.js +2 -2
  193. package/dist/server/onboarding-html.js +52 -120
  194. package/dist/settings/store.d.ts +9 -0
  195. package/dist/settings/store.js +19 -0
  196. package/dist/templates/chat/netlify.toml +2 -0
  197. package/docs/content/deployment.mdx +2 -0
  198. package/docs/content/multi-app-workspace.mdx +1 -1
  199. package/package.json +2 -2
  200. package/src/templates/chat/netlify.toml +2 -0
@@ -0,0 +1,151 @@
1
+ import { buildCodeLayerProjection } from "@shared/code-layer";
2
+ import type { InteractionState } from "@shared/interaction-states";
3
+ import { normalizeDesignSourceType } from "@shared/source-mode";
4
+ import type { RefObject } from "react";
5
+
6
+ import type { ElementInfo } from "@/components/design/types";
7
+ import type { ClipboardContentMutationPublication } from "@/lib/clipboard-content-lineage";
8
+ import {
9
+ codeLayerPatchMessage,
10
+ resolveCodeLayerNodeFromBridge,
11
+ resolveCodeLayerNodeFromElementInfo,
12
+ } from "@/pages/design-editor/code-layer-state";
13
+ import type { ResponsiveEditScope } from "@/pages/design-editor/command-types";
14
+ import type { OverviewScreen } from "@/pages/design-editor/derive/overview-screens";
15
+ import { applyScopedVisualStyleEdit } from "@/pages/design-editor/pending-edits";
16
+ import type { DesignFile } from "@/pages/design-editor/types";
17
+
18
+ export interface ScreenVisualStyleChangeArgs {
19
+ activeBreakpointUpperBoundPx: number | null;
20
+ activeBreakpointWidthStateRef: RefObject<number | undefined>;
21
+ activeFile: DesignFile;
22
+ applyFileContentUpdate: (
23
+ fileId: string,
24
+ nextContent: string,
25
+ options?: {
26
+ refreshPreview?: boolean;
27
+ skipPreview?: boolean;
28
+ forcePreviewFullDocument?: boolean;
29
+ persist?: boolean;
30
+ recordHistory?: boolean;
31
+ updatedAt?: string;
32
+ clipboardMutation?: ClipboardContentMutationPublication;
33
+ },
34
+ ) => void;
35
+ canEditDesign: boolean;
36
+ designSourceType: "inline" | "localhost" | "fusion";
37
+ getScreenContent: (screenId: string) => string;
38
+ handleVisualStyleChange: (
39
+ selector: string,
40
+ styles: Record<string, string>,
41
+ elementInfo?: ElementInfo,
42
+ metadata?: { originalStyles?: Record<string, string> },
43
+ ) => void;
44
+ overviewScreens: OverviewScreen[];
45
+ recordPendingVisualStyleEdit: (
46
+ screenId: string,
47
+ selector: string,
48
+ styles: Record<string, string>,
49
+ elementInfo?: ElementInfo,
50
+ metadata?: {
51
+ originalStyles?: Record<string, string>;
52
+ interactionState?: InteractionState;
53
+ },
54
+ ) => void;
55
+ responsiveEditScopeRef: RefObject<ResponsiveEditScope>;
56
+ t: (key: string, options?: Record<string, unknown>) => string;
57
+ }
58
+
59
+ export function runScreenVisualStyleChange(
60
+ {
61
+ activeBreakpointUpperBoundPx,
62
+ activeBreakpointWidthStateRef,
63
+ activeFile,
64
+ applyFileContentUpdate,
65
+ canEditDesign,
66
+ designSourceType,
67
+ getScreenContent,
68
+ handleVisualStyleChange,
69
+ overviewScreens,
70
+ recordPendingVisualStyleEdit,
71
+ responsiveEditScopeRef,
72
+ t,
73
+ }: ScreenVisualStyleChangeArgs,
74
+ screenId: string,
75
+ selector: string,
76
+ styles: Record<string, string>,
77
+ elementInfo?: ElementInfo,
78
+ metadata?: { originalStyles?: Record<string, string> },
79
+ ) {
80
+ if (screenId === activeFile?.id) {
81
+ handleVisualStyleChange(selector, styles, elementInfo, metadata);
82
+ return;
83
+ }
84
+ // §gesture-persistence — mirror handleVisualStyleChange's source-type
85
+ // branch for overview screens other than the active one: localhost
86
+ // still queues for agent apply, inline/fusion screens persist the
87
+ // gesture commit immediately (breakpoint-aware, single history step),
88
+ // matching commitStylesToSelectedLayers's established per-file write
89
+ // pattern below.
90
+ const overviewScreen = overviewScreens.find(
91
+ (screen) => screen.id === screenId,
92
+ );
93
+ const screenSourceType =
94
+ normalizeDesignSourceType(overviewScreen?.sourceType) ?? designSourceType;
95
+ if (screenSourceType === "localhost") {
96
+ recordPendingVisualStyleEdit(
97
+ screenId,
98
+ selector,
99
+ styles,
100
+ elementInfo,
101
+ metadata,
102
+ );
103
+ return;
104
+ }
105
+ if (!canEditDesign) return;
106
+ const entries = Object.entries(styles).filter(
107
+ ([, value]) => value !== undefined,
108
+ );
109
+ if (entries.length === 0) return;
110
+ const baseContent = getScreenContent(screenId);
111
+ if (!baseContent) return;
112
+ const projection = buildCodeLayerProjection(baseContent);
113
+ const targetInfo = elementInfo ? { ...elementInfo, selector } : null;
114
+ const targetNode = targetInfo
115
+ ? resolveCodeLayerNodeFromElementInfo(projection, targetInfo)
116
+ : resolveCodeLayerNodeFromBridge(projection, selector);
117
+ const stylePatch = entries.reduce<{
118
+ content: string;
119
+ failed: string | null;
120
+ }>(
121
+ (current, [property, value]) => {
122
+ if (current.failed) return current;
123
+ const patch = applyScopedVisualStyleEdit({
124
+ content: current.content,
125
+ target: targetNode ? { nodeId: targetNode.id } : { selector },
126
+ property,
127
+ value,
128
+ upperBoundPx: activeBreakpointUpperBoundPx,
129
+ lowerBoundPx:
130
+ responsiveEditScopeRef.current === "only"
131
+ ? activeBreakpointWidthStateRef.current
132
+ : null,
133
+ });
134
+ if (patch.result.status !== "applied") {
135
+ return {
136
+ content: current.content,
137
+ failed: codeLayerPatchMessage(
138
+ patch.result.message,
139
+ t("designEditor.patchProof.selectorMissing"),
140
+ ),
141
+ };
142
+ }
143
+ return { content: patch.content, failed: null };
144
+ },
145
+ { content: baseContent, failed: null },
146
+ );
147
+ if (stylePatch.failed || stylePatch.content === baseContent) return;
148
+ applyFileContentUpdate(screenId, stylePatch.content, {
149
+ skipPreview: true,
150
+ });
151
+ }
@@ -0,0 +1,88 @@
1
+ import type { Dispatch, RefObject, SetStateAction } from "react";
2
+ import { toast } from "sonner";
3
+
4
+ import type { DrawAnnotation } from "@/components/visual-editor/DrawOverlay";
5
+ import { sendToDesignAgentChatAndConfirm } from "@/lib/agent-chat";
6
+ import { prettyScreenName } from "@/lib/screen-names";
7
+ import type { OverviewScreen } from "@/pages/design-editor/derive/overview-screens";
8
+ import {
9
+ collectOverviewAnnotationViewportMap,
10
+ formatOverviewAnnotationMessage,
11
+ } from "@/pages/design-editor/overview-annotation-context";
12
+ import type { DesignData } from "@/pages/design-editor/types";
13
+
14
+ export interface SendOverviewAnnotationsArgs {
15
+ canvasContainerRef: RefObject<HTMLDivElement | null>;
16
+ design: DesignData | null;
17
+ handleExitOverviewDrawMode: () => void;
18
+ id: string | undefined;
19
+ overviewAnnotationSendingRef: RefObject<boolean>;
20
+ overviewCanvasZoom: number;
21
+ overviewScreens: OverviewScreen[];
22
+ setOverviewAnnotationSending: Dispatch<SetStateAction<boolean>>;
23
+ t: (key: string, options?: Record<string, unknown>) => string;
24
+ }
25
+
26
+ export async function runSendOverviewAnnotations(
27
+ {
28
+ canvasContainerRef,
29
+ design,
30
+ handleExitOverviewDrawMode,
31
+ id,
32
+ overviewAnnotationSendingRef,
33
+ overviewCanvasZoom,
34
+ overviewScreens,
35
+ setOverviewAnnotationSending,
36
+ t,
37
+ }: SendOverviewAnnotationsArgs,
38
+ annotations: DrawAnnotation[],
39
+ instruction: string,
40
+ canvasSize: { width: number; height: number },
41
+ ) {
42
+ if (overviewAnnotationSendingRef.current) return;
43
+ const container = canvasContainerRef.current;
44
+ const viewportMap = container
45
+ ? collectOverviewAnnotationViewportMap({
46
+ container,
47
+ screens: overviewScreens.map((screen) => ({
48
+ id: screen.id,
49
+ name: prettyScreenName(screen.filename),
50
+ })),
51
+ zoom: overviewCanvasZoom,
52
+ })
53
+ : {
54
+ width: canvasSize.width,
55
+ height: canvasSize.height,
56
+ zoom: overviewCanvasZoom,
57
+ screens: [],
58
+ };
59
+ const message = formatOverviewAnnotationMessage({
60
+ designId: id ?? "",
61
+ designTitle: design?.title,
62
+ annotations,
63
+ instruction,
64
+ viewportMap,
65
+ });
66
+
67
+ overviewAnnotationSendingRef.current = true;
68
+ setOverviewAnnotationSending(true);
69
+ try {
70
+ const result = await sendToDesignAgentChatAndConfirm({
71
+ message,
72
+ submit: true,
73
+ openSidebar: true,
74
+ });
75
+ if (!result.delivered) {
76
+ throw new Error(
77
+ `Overview annotation message was not delivered to the agent chat (${result.reason ?? "unknown"})`,
78
+ );
79
+ }
80
+ handleExitOverviewDrawMode();
81
+ } catch (error) {
82
+ console.error("[DesignEditor] failed to submit overview drawing:", error);
83
+ toast.error(t("designEditor.toasts.annotationSendError"));
84
+ } finally {
85
+ overviewAnnotationSendingRef.current = false;
86
+ setOverviewAnnotationSending(false);
87
+ }
88
+ }
@@ -0,0 +1,122 @@
1
+ import type { CodeLayerNode, CodeLayerTreeNode } from "@shared/code-layer";
2
+ import type { Dispatch, RefObject, SetStateAction } from "react";
3
+ import { toast } from "sonner";
4
+
5
+ import { sendToDesignAgentChat } from "@/lib/agent-chat";
6
+ import { elementInfoFromCodeLayerNode } from "@/pages/design-editor/code-layer-state";
7
+ import type { RuntimeLayerSnapshot } from "@/pages/design-editor/command-types";
8
+ import type { OverviewScreen } from "@/pages/design-editor/derive/overview-screens";
9
+ import { runtimeMultiplicityForElementProvenance } from "@/pages/design-editor/editor-helpers";
10
+ import {
11
+ reactSourceAnchorForPendingEdit,
12
+ reactSourceAnchorUnavailableReason,
13
+ } from "@/pages/design-editor/pending-edits";
14
+ import { buildRuntimeReactStructureMoveHandoff } from "@/pages/design-editor/react-semantic-handoff";
15
+ import type { DesignLeftPanel } from "@/pages/design-editor/types";
16
+
17
+ export interface SendRuntimeLayerMoveSemanticHandoffArgs {
18
+ codeLayerOwnerByNodeIdRef: RefObject<
19
+ Map<
20
+ string,
21
+ {
22
+ fileId: string;
23
+ node: CodeLayerNode;
24
+ tree: CodeLayerTreeNode[];
25
+ runtimeOnly: boolean;
26
+ }
27
+ >
28
+ >;
29
+ localhostConnectionRootPathByIdRef: RefObject<Map<string, string>>;
30
+ overviewScreens: OverviewScreen[];
31
+ runtimeLayerSnapshotsById: Record<string, RuntimeLayerSnapshot>;
32
+ setActiveLeftPanel: Dispatch<SetStateAction<DesignLeftPanel>>;
33
+ t: (key: string, options?: Record<string, unknown>) => string;
34
+ }
35
+
36
+ export function runSendRuntimeLayerMoveSemanticHandoff(
37
+ {
38
+ codeLayerOwnerByNodeIdRef,
39
+ localhostConnectionRootPathByIdRef,
40
+ overviewScreens,
41
+ runtimeLayerSnapshotsById,
42
+ setActiveLeftPanel,
43
+ t,
44
+ }: SendRuntimeLayerMoveSemanticHandoffArgs,
45
+ subjectLayerId: string,
46
+ targetLayerId: string,
47
+ placement: "before" | "after" | "inside",
48
+ ): boolean {
49
+ const subjectOwner = codeLayerOwnerByNodeIdRef.current.get(subjectLayerId);
50
+ const targetOwner = codeLayerOwnerByNodeIdRef.current.get(targetLayerId);
51
+ if (!subjectOwner || !targetOwner) return false;
52
+
53
+ const sourceAnchorForOwner = (
54
+ owner: typeof subjectOwner,
55
+ anchorId: "subject" | "target",
56
+ ) => {
57
+ const screen = overviewScreens.find(
58
+ (candidate) => candidate.id === owner.fileId,
59
+ );
60
+ const rootPath = screen?.connectionId
61
+ ? localhostConnectionRootPathByIdRef.current.get(screen.connectionId)
62
+ : undefined;
63
+ const info = elementInfoFromCodeLayerNode(owner.node);
64
+ return reactSourceAnchorForPendingEdit({
65
+ info,
66
+ id: anchorId,
67
+ rootPath,
68
+ runtimeMultiplicity: runtimeMultiplicityForElementProvenance(
69
+ runtimeLayerSnapshotsById,
70
+ info,
71
+ ),
72
+ reason:
73
+ anchorId === "subject"
74
+ ? `Runtime Layers-panel move subject in screen ${owner.fileId}.`
75
+ : `Runtime Layers-panel move target in screen ${owner.fileId}.`,
76
+ });
77
+ };
78
+
79
+ const subjectAnchor = sourceAnchorForOwner(subjectOwner, "subject");
80
+ const targetAnchor = sourceAnchorForOwner(targetOwner, "target");
81
+ if (!subjectAnchor || !targetAnchor) {
82
+ // Mixed runtime/source moves are only safe when BOTH endpoints carry
83
+ // exact compiler provenance. Never fall back to selectors or a generic
84
+ // source/AST move for the missing side.
85
+ toast.error(
86
+ reactSourceAnchorUnavailableReason([
87
+ elementInfoFromCodeLayerNode(subjectOwner.node),
88
+ elementInfoFromCodeLayerNode(targetOwner.node),
89
+ ])
90
+ ? t("designEditor.toasts.reactSourceAnchorsUnavailable")
91
+ : t("designEditor.toasts.reactSourceAnchorsLoading"),
92
+ );
93
+ return true;
94
+ }
95
+
96
+ const handoff = buildRuntimeReactStructureMoveHandoff({
97
+ subjectAnchor,
98
+ targetAnchor,
99
+ placement,
100
+ sourceScreenId: subjectOwner.fileId,
101
+ targetScreenId: targetOwner.fileId,
102
+ });
103
+ if (!handoff.ok) {
104
+ toast.error(handoff.rejection.reason);
105
+ return true;
106
+ }
107
+
108
+ sendToDesignAgentChat({
109
+ message: t("designEditor.pendingVisualStyles.agentMessage"),
110
+ context: [
111
+ "Apply this runtime Layers-panel move/reparent to the connected React source.",
112
+ `The exact subject belongs to screen ${subjectOwner.fileId}; the exact target belongs to screen ${targetOwner.fileId}.`,
113
+ "Compiler provenance is for anchoring and validation only, and only as precise as each anchor's positionPrecision says. Never apply a generic AST reparent or structure transform.",
114
+ "Read every affected file first, obtain human write consent, write with each read's expectedVersionHash and requireExpectedVersionHash: true, re-read/re-plan on conflict, and keep any optimistic preview pending only until HMR confirms the intended runtime relationship.",
115
+ JSON.stringify(handoff.handoff, null, 2),
116
+ ].join("\n\n"),
117
+ submit: true,
118
+ openSidebar: true,
119
+ });
120
+ setActiveLeftPanel("agent");
121
+ return true;
122
+ }
@@ -0,0 +1,143 @@
1
+ import type { CodeLayerNode, CodeLayerTreeNode } from "@shared/code-layer";
2
+ import type { Dispatch, RefObject, SetStateAction } from "react";
3
+ import { toast } from "sonner";
4
+
5
+ import { sendToDesignAgentChat } from "@/lib/agent-chat";
6
+ import { elementInfoFromCodeLayerNode } from "@/pages/design-editor/code-layer-state";
7
+ import type { RuntimeLayerSnapshot } from "@/pages/design-editor/command-types";
8
+ import type { OverviewScreen } from "@/pages/design-editor/derive/overview-screens";
9
+ import { runtimeMultiplicityForElementProvenance } from "@/pages/design-editor/editor-helpers";
10
+ import {
11
+ reactSourceAnchorForPendingEdit,
12
+ reactSourceAnchorUnavailableReason,
13
+ } from "@/pages/design-editor/pending-edits";
14
+ import { buildReactSemanticHandoff } from "@/pages/design-editor/react-semantic-handoff";
15
+ import type { DesignLeftPanel } from "@/pages/design-editor/types";
16
+
17
+ export interface SendRuntimeLayerSemanticHandoffArgs {
18
+ codeLayerOwnerByNodeIdRef: RefObject<
19
+ Map<
20
+ string,
21
+ {
22
+ fileId: string;
23
+ node: CodeLayerNode;
24
+ tree: CodeLayerTreeNode[];
25
+ runtimeOnly: boolean;
26
+ }
27
+ >
28
+ >;
29
+ localhostConnectionRootPathByIdRef: RefObject<Map<string, string>>;
30
+ overviewScreens: OverviewScreen[];
31
+ runtimeLayerSnapshotsById: Record<string, RuntimeLayerSnapshot>;
32
+ setActiveLeftPanel: Dispatch<SetStateAction<DesignLeftPanel>>;
33
+ t: (key: string, options?: Record<string, unknown>) => string;
34
+ }
35
+
36
+ export function runSendRuntimeLayerSemanticHandoff(
37
+ {
38
+ codeLayerOwnerByNodeIdRef,
39
+ localhostConnectionRootPathByIdRef,
40
+ overviewScreens,
41
+ runtimeLayerSnapshotsById,
42
+ setActiveLeftPanel,
43
+ t,
44
+ }: SendRuntimeLayerSemanticHandoffArgs,
45
+ operation: "group" | "ungroup" | "auto-layout",
46
+ layerIds: readonly string[],
47
+ options: {
48
+ desiredChange?: string;
49
+ description?: string;
50
+ commandContext?: string;
51
+ } = {},
52
+ ): boolean {
53
+ const owners = layerIds
54
+ .map((layerId) => codeLayerOwnerByNodeIdRef.current.get(layerId))
55
+ .filter(
56
+ (
57
+ owner,
58
+ ): owner is NonNullable<
59
+ ReturnType<typeof codeLayerOwnerByNodeIdRef.current.get>
60
+ > => Boolean(owner?.runtimeOnly),
61
+ );
62
+ if (owners.length !== layerIds.length || owners.length === 0) return false;
63
+ const screenId = owners[0]!.fileId;
64
+ if (owners.some((owner) => owner.fileId !== screenId)) return false;
65
+ const connectionId = overviewScreens.find(
66
+ (screen) => screen.id === screenId,
67
+ )?.connectionId;
68
+ const rootPath = connectionId
69
+ ? localhostConnectionRootPathByIdRef.current.get(connectionId)
70
+ : undefined;
71
+ const infos = owners.map((owner) => elementInfoFromCodeLayerNode(owner.node));
72
+ const sourceAnchors = infos.map((info, index) =>
73
+ reactSourceAnchorForPendingEdit({
74
+ info,
75
+ id: `subject-${index + 1}`,
76
+ rootPath,
77
+ runtimeMultiplicity: runtimeMultiplicityForElementProvenance(
78
+ runtimeLayerSnapshotsById,
79
+ info,
80
+ ),
81
+ }),
82
+ );
83
+ if (sourceAnchors.some((anchor) => !anchor)) {
84
+ toast.error(
85
+ reactSourceAnchorUnavailableReason(infos)
86
+ ? t("designEditor.toasts.reactSourceAnchorsUnavailable")
87
+ : t("designEditor.toasts.reactSourceAnchorsLoading"),
88
+ );
89
+ return true;
90
+ }
91
+ const subjectAnchorIds = sourceAnchors.map(
92
+ (_anchor, index) => `subject-${index + 1}`,
93
+ );
94
+ const handoff = buildReactSemanticHandoff({
95
+ operation,
96
+ desiredChange:
97
+ options.desiredChange ??
98
+ (operation === "group"
99
+ ? "Wrap the selected runtime React elements in one new group container while preserving their visual order and layout."
100
+ : operation === "ungroup"
101
+ ? "Remove the selected runtime React container wrapper and preserve its children in the same visual position and order."
102
+ : owners.length > 1
103
+ ? "Wrap the selected runtime React elements in an inferred auto-layout container while preserving their visual order."
104
+ : "Convert the selected runtime React container to inferred auto layout without changing unrelated behavior."),
105
+ sourceAnchors: sourceAnchors.filter(
106
+ (anchor): anchor is NonNullable<typeof anchor> => Boolean(anchor),
107
+ ),
108
+ runtimeRelationship: {
109
+ kind:
110
+ operation === "group"
111
+ ? "wrap"
112
+ : operation === "ungroup"
113
+ ? "unwrap"
114
+ : owners.length > 1
115
+ ? "wrap"
116
+ : "style",
117
+ subjectAnchorIds,
118
+ screenId,
119
+ description:
120
+ options.description ??
121
+ `${operation} ${owners.length} selected runtime React layer${owners.length === 1 ? "" : "s"}`,
122
+ },
123
+ versionHashes: [],
124
+ });
125
+ if (!handoff.ok) {
126
+ toast.error(handoff.rejection.reason);
127
+ return true;
128
+ }
129
+ sendToDesignAgentChat({
130
+ message: t("designEditor.pendingVisualStyles.agentMessage"),
131
+ context: [
132
+ options.commandContext ??
133
+ "Apply this runtime Layers-panel command to the connected React source.",
134
+ "The compiler metadata is for source anchoring and validation only; do not use a generic AST structural transform. Respect each anchor's positionPrecision — a non-authored line is the dev server's, not the file's.",
135
+ "Read every target file, obtain human write consent, write with expectedVersionHash and requireExpectedVersionHash: true, then verify the resulting HMR/runtime relationship.",
136
+ JSON.stringify(handoff.handoff, null, 2),
137
+ ].join("\n\n"),
138
+ submit: true,
139
+ openSidebar: true,
140
+ });
141
+ setActiveLeftPanel("agent");
142
+ return true;
143
+ }
@@ -0,0 +1,115 @@
1
+ import type { CodeLayerNode, CodeLayerTreeNode } from "@shared/code-layer";
2
+ import type { Dispatch, RefObject, SetStateAction } from "react";
3
+ import { toast } from "sonner";
4
+
5
+ import { sendToDesignAgentChat } from "@/lib/agent-chat";
6
+ import {
7
+ elementInfoFromCodeLayerNode,
8
+ runtimeLayerStateHandoffMode,
9
+ } from "@/pages/design-editor/code-layer-state";
10
+ import type { RuntimeLayerSnapshot } from "@/pages/design-editor/command-types";
11
+ import type { OverviewScreen } from "@/pages/design-editor/derive/overview-screens";
12
+ import { runtimeMultiplicityForElementProvenance } from "@/pages/design-editor/editor-helpers";
13
+ import {
14
+ reactSourceAnchorForPendingEdit,
15
+ reactSourceAnchorUnavailableReason,
16
+ } from "@/pages/design-editor/pending-edits";
17
+ import { buildRuntimeReactLayerStateHandoff } from "@/pages/design-editor/react-semantic-handoff";
18
+ import type { DesignLeftPanel } from "@/pages/design-editor/types";
19
+
20
+ export interface SendRuntimeLayerStateSemanticHandoffArgs {
21
+ codeLayerOwnerByNodeIdRef: RefObject<
22
+ Map<
23
+ string,
24
+ {
25
+ fileId: string;
26
+ node: CodeLayerNode;
27
+ tree: CodeLayerTreeNode[];
28
+ runtimeOnly: boolean;
29
+ }
30
+ >
31
+ >;
32
+ localhostConnectionRootPathByIdRef: RefObject<Map<string, string>>;
33
+ overviewScreens: OverviewScreen[];
34
+ runtimeLayerSnapshotsById: Record<string, RuntimeLayerSnapshot>;
35
+ setActiveLeftPanel: Dispatch<SetStateAction<DesignLeftPanel>>;
36
+ t: (key: string, options?: Record<string, unknown>) => string;
37
+ }
38
+
39
+ export function runSendRuntimeLayerStateSemanticHandoff(
40
+ {
41
+ codeLayerOwnerByNodeIdRef,
42
+ localhostConnectionRootPathByIdRef,
43
+ overviewScreens,
44
+ runtimeLayerSnapshotsById,
45
+ setActiveLeftPanel,
46
+ t,
47
+ }: SendRuntimeLayerStateSemanticHandoffArgs,
48
+ layerId: string,
49
+ state: "locked" | "hidden",
50
+ enabled: boolean,
51
+ ): true | "preview-only" | false {
52
+ const owner = codeLayerOwnerByNodeIdRef.current.get(layerId);
53
+ if (!owner) return "preview-only";
54
+
55
+ const screen = overviewScreens.find(
56
+ (candidate) => candidate.id === owner.fileId,
57
+ );
58
+ const rootPath = screen?.connectionId
59
+ ? localhostConnectionRootPathByIdRef.current.get(screen.connectionId)
60
+ : undefined;
61
+ const info = elementInfoFromCodeLayerNode(owner.node);
62
+ if (
63
+ runtimeLayerStateHandoffMode({
64
+ runtimeOnly: owner.runtimeOnly,
65
+ provenanceSourceFile: info.provenance?.sourceFile,
66
+ }) === "preview-only"
67
+ ) {
68
+ return "preview-only";
69
+ }
70
+ const subjectAnchor = reactSourceAnchorForPendingEdit({
71
+ info,
72
+ id: "subject",
73
+ rootPath,
74
+ runtimeMultiplicity: runtimeMultiplicityForElementProvenance(
75
+ runtimeLayerSnapshotsById,
76
+ info,
77
+ ),
78
+ reason: `Runtime Layers-panel ${state} state for layer ${layerId} in screen ${owner.fileId}.`,
79
+ });
80
+ if (!subjectAnchor) {
81
+ toast.error(
82
+ reactSourceAnchorUnavailableReason([info])
83
+ ? t("designEditor.toasts.reactSourceAnchorsUnavailable")
84
+ : t("designEditor.toasts.reactSourceAnchorsLoading"),
85
+ );
86
+ return false;
87
+ }
88
+
89
+ const handoff = buildRuntimeReactLayerStateHandoff({
90
+ subjectAnchor,
91
+ screenId: owner.fileId,
92
+ state,
93
+ enabled,
94
+ });
95
+ if (!handoff.ok) {
96
+ toast.error(handoff.rejection.reason);
97
+ return false;
98
+ }
99
+
100
+ const attributeName = `data-agent-native-${state}`;
101
+ sendToDesignAgentChat({
102
+ message: t("designEditor.pendingVisualStyles.agentMessage"),
103
+ context: [
104
+ `Apply this runtime Layers-panel ${state} change to the connected React source.`,
105
+ `Use the compiler anchor to ${enabled ? `set ${attributeName}=\"true\" on` : `remove ${attributeName} from`} the existing JSX host element. The runtime Layers snapshot recognizes this durable source metadata; do not replace it with CSS, a transient DOM mutation, or a wrapper.`,
106
+ "Compiler provenance is for anchoring and validation only, and only as precise as each anchor's positionPrecision says. Never apply a generic AST transform.",
107
+ "Read the affected file first, obtain human write consent, write with that read's expectedVersionHash and requireExpectedVersionHash: true, re-read/re-plan on conflict, and keep the optimistic layer-state preview only until HMR confirms the source metadata.",
108
+ JSON.stringify(handoff.handoff, null, 2),
109
+ ].join("\n\n"),
110
+ submit: true,
111
+ openSidebar: true,
112
+ });
113
+ setActiveLeftPanel("agent");
114
+ return true;
115
+ }