made-refine 0.2.11 → 0.2.15

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/dist/index.mjs CHANGED
@@ -117,6 +117,225 @@ function getZoomScale() {
117
117
  return snap.active ? snap.zoom : 1;
118
118
  }
119
119
 
120
+ // src/utils/react-fiber.ts
121
+ function getFiberForElement(element) {
122
+ if (typeof window !== "undefined") {
123
+ const devtools = window.__DIRECT_EDIT_DEVTOOLS__;
124
+ if (devtools?.getFiberForElement) {
125
+ const fiber = devtools.getFiberForElement(element);
126
+ if (fiber) return fiber;
127
+ }
128
+ }
129
+ const fiberKey = Object.keys(element).find(
130
+ (key) => key.startsWith("__reactFiber$") || key.startsWith("__reactInternalInstance$")
131
+ );
132
+ if (!fiberKey) return null;
133
+ return element[fiberKey] || null;
134
+ }
135
+ function getSourceFromFiber(fiber) {
136
+ const debugSource = fiber?._debugSource;
137
+ if (debugSource?.fileName) return debugSource;
138
+ const owner = fiber?._debugOwner;
139
+ const ownerPending = owner?.pendingProps?.__source;
140
+ if (ownerPending?.fileName) return ownerPending;
141
+ const ownerMemo = owner?.memoizedProps?.__source;
142
+ if (ownerMemo?.fileName) return ownerMemo;
143
+ const pending = fiber?.pendingProps?.__source;
144
+ if (pending?.fileName) return pending;
145
+ const memo = fiber?.memoizedProps?.__source;
146
+ if (memo?.fileName) return memo;
147
+ return null;
148
+ }
149
+ function buildFrame(fiber) {
150
+ const type = fiber?.type;
151
+ if (typeof type !== "function" && typeof type !== "object") return null;
152
+ const name = type?.displayName || type?.name || null;
153
+ if (!name || name === "Fragment") return null;
154
+ const frame = { name };
155
+ const source = getSourceFromFiber(fiber);
156
+ if (source?.fileName) {
157
+ frame.file = source.fileName;
158
+ if (typeof source.lineNumber === "number") {
159
+ frame.line = source.lineNumber;
160
+ }
161
+ if (typeof source.columnNumber === "number") {
162
+ frame.column = source.columnNumber;
163
+ }
164
+ }
165
+ return frame;
166
+ }
167
+ function shouldIncludeFrame(frame, lastFrame) {
168
+ if (!lastFrame) return true;
169
+ if (frame.name !== lastFrame.name) return true;
170
+ if (!lastFrame.file && frame.file) return true;
171
+ if (lastFrame.file && frame.file && lastFrame.line == null && frame.line != null) return true;
172
+ if (lastFrame.file && frame.file && lastFrame.line != null && frame.line != null && lastFrame.column == null && frame.column != null) {
173
+ return true;
174
+ }
175
+ return false;
176
+ }
177
+ function getOwnerStack(fiber) {
178
+ const frames = [];
179
+ let current = fiber;
180
+ let lastFrame = null;
181
+ let nearestComponentFiber = null;
182
+ while (current) {
183
+ const frame = buildFrame(current);
184
+ if (frame && shouldIncludeFrame(frame, lastFrame)) {
185
+ frames.push(frame);
186
+ lastFrame = frame;
187
+ if (!nearestComponentFiber) {
188
+ nearestComponentFiber = current;
189
+ }
190
+ }
191
+ current = current._debugOwner;
192
+ }
193
+ return { frames, nearestComponentFiber };
194
+ }
195
+ function getRenderStack(fiber) {
196
+ const frames = [];
197
+ let current = fiber;
198
+ let lastFrame = null;
199
+ let nearestComponentFiber = null;
200
+ while (current) {
201
+ const frame = buildFrame(current);
202
+ if (frame && shouldIncludeFrame(frame, lastFrame)) {
203
+ frames.push(frame);
204
+ lastFrame = frame;
205
+ if (!nearestComponentFiber) {
206
+ nearestComponentFiber = current;
207
+ }
208
+ }
209
+ current = current.return;
210
+ }
211
+ return { frames, nearestComponentFiber };
212
+ }
213
+ function getReactComponentInfo(element) {
214
+ const fiber = getFiberForElement(element);
215
+ if (!fiber) return { frames: [], nearestComponentFiber: null };
216
+ const elementSource = getSourceFromFiber(fiber);
217
+ const elementSourceFile = elementSource?.fileName || void 0;
218
+ const ownerResult = getOwnerStack(fiber);
219
+ if (ownerResult.frames.length > 0) {
220
+ return { ...ownerResult, elementSourceFile };
221
+ }
222
+ return { ...getRenderStack(fiber), elementSourceFile };
223
+ }
224
+ var EXCLUDED_PROP_KEYS = /* @__PURE__ */ new Set([
225
+ "className",
226
+ "style",
227
+ "children",
228
+ "ref",
229
+ "key",
230
+ "render"
231
+ ]);
232
+ function serializePropValue(value) {
233
+ if (typeof value === "function") return "[function]";
234
+ if (typeof value === "symbol") return void 0;
235
+ if (value === void 0) return void 0;
236
+ if (value !== null && typeof value === "object") {
237
+ if ("$$typeof" in value) return "[element]";
238
+ try {
239
+ JSON.stringify(value);
240
+ return value;
241
+ } catch {
242
+ return "[object]";
243
+ }
244
+ }
245
+ return value;
246
+ }
247
+ function getComponentProps(fiber) {
248
+ const props = fiber?.memoizedProps ?? fiber?.pendingProps;
249
+ if (!props || typeof props !== "object") return {};
250
+ const result = {};
251
+ for (const [key, value] of Object.entries(props)) {
252
+ if (EXCLUDED_PROP_KEYS.has(key)) continue;
253
+ if (key.startsWith("data-")) continue;
254
+ const serialized = serializePropValue(value);
255
+ if (serialized !== void 0) {
256
+ result[key] = serialized;
257
+ }
258
+ }
259
+ return result;
260
+ }
261
+ function getCallSiteSource(fiber) {
262
+ const source = fiber?._debugSource;
263
+ if (source?.fileName) {
264
+ return {
265
+ file: source.fileName,
266
+ line: typeof source.lineNumber === "number" ? source.lineNumber : void 0,
267
+ column: typeof source.columnNumber === "number" ? source.columnNumber : void 0
268
+ };
269
+ }
270
+ const pending = fiber?.pendingProps?.__source;
271
+ if (pending?.fileName) {
272
+ return {
273
+ file: pending.fileName,
274
+ line: typeof pending.lineNumber === "number" ? pending.lineNumber : void 0,
275
+ column: typeof pending.columnNumber === "number" ? pending.columnNumber : void 0
276
+ };
277
+ }
278
+ return null;
279
+ }
280
+ function deriveDefinitionSource(frames) {
281
+ for (const frame of frames) {
282
+ if (frame.file && isComponentPrimitivePath(frame.file)) {
283
+ return { file: frame.file, line: frame.line, column: frame.column };
284
+ }
285
+ }
286
+ return null;
287
+ }
288
+ var PRIMITIVE_PATH_PATTERNS = [
289
+ /\/components\/ui\//,
290
+ /\/ui\/primitives\//,
291
+ /\/design-system\//
292
+ ];
293
+ var PRIMITIVE_NPM_PATTERNS = [
294
+ /@base-ui\//,
295
+ /@radix-ui\//,
296
+ /@headlessui\//,
297
+ /@chakra-ui\//,
298
+ /@mantine\//,
299
+ /@mui\//,
300
+ /@ark-ui\//
301
+ ];
302
+ var FRAMEWORK_EXCLUSION_PATTERNS = [
303
+ /node_modules\/react\//,
304
+ /node_modules\/react-dom\//,
305
+ /node_modules\/next\/dist\//,
306
+ /node_modules\/scheduler\//,
307
+ /node_modules\/react-server\//
308
+ ];
309
+ function isComponentPrimitivePath(filePath) {
310
+ const normalized = filePath.replace(/\\/g, "/");
311
+ for (const pattern of FRAMEWORK_EXCLUSION_PATTERNS) {
312
+ if (pattern.test(normalized)) return false;
313
+ }
314
+ for (const pattern of PRIMITIVE_NPM_PATTERNS) {
315
+ if (pattern.test(normalized)) return true;
316
+ }
317
+ for (const pattern of PRIMITIVE_PATH_PATTERNS) {
318
+ if (pattern.test(normalized)) return true;
319
+ }
320
+ return false;
321
+ }
322
+ function classifyComponentFiber(fiber, frames, elementSourceFile) {
323
+ if (elementSourceFile && isComponentPrimitivePath(elementSourceFile)) {
324
+ return { isComponentPrimitive: true };
325
+ }
326
+ if (!fiber) return { isComponentPrimitive: false };
327
+ const callSite = getCallSiteSource(fiber);
328
+ if (callSite?.file && isComponentPrimitivePath(callSite.file)) {
329
+ return { isComponentPrimitive: true };
330
+ }
331
+ for (const frame of frames) {
332
+ if (frame.file && isComponentPrimitivePath(frame.file)) {
333
+ return { isComponentPrimitive: true };
334
+ }
335
+ }
336
+ return { isComponentPrimitive: false };
337
+ }
338
+
120
339
  // src/utils.ts
121
340
  function clamp(value, min, max) {
122
341
  if (!Number.isFinite(value)) return min;
@@ -1504,7 +1723,7 @@ function calculateDropPosition(container, pointerX, pointerY, draggedElement) {
1504
1723
  };
1505
1724
  return { insertBefore, indicator };
1506
1725
  }
1507
- function getFiberForElement(element) {
1726
+ function getFiberForElement2(element) {
1508
1727
  if (typeof window !== "undefined") {
1509
1728
  const devtools = window.__DIRECT_EDIT_DEVTOOLS__;
1510
1729
  if (devtools?.getFiberForElement) {
@@ -1765,7 +1984,7 @@ function getSourceFromDebugStack(fiber) {
1765
1984
  }
1766
1985
  return null;
1767
1986
  }
1768
- function getSourceFromFiber(fiber) {
1987
+ function getSourceFromFiber2(fiber) {
1769
1988
  const debugSource = fiber?._debugSource;
1770
1989
  if (debugSource?.fileName) return debugSource;
1771
1990
  const owner = fiber?._debugOwner;
@@ -1781,13 +2000,13 @@ function getSourceFromFiber(fiber) {
1781
2000
  if (fromDebugStack?.fileName) return fromDebugStack;
1782
2001
  return null;
1783
2002
  }
1784
- function buildFrame(fiber) {
2003
+ function buildFrame2(fiber) {
1785
2004
  const type = fiber?.type;
1786
2005
  if (typeof type !== "function" && typeof type !== "object") return null;
1787
2006
  const name = type?.displayName || type?.name || null;
1788
2007
  if (!name || name === "Fragment") return null;
1789
2008
  const frame = { name };
1790
- const source = getSourceFromFiber(fiber);
2009
+ const source = getSourceFromFiber2(fiber);
1791
2010
  if (source?.fileName) {
1792
2011
  frame.file = source.fileName;
1793
2012
  if (typeof source.lineNumber === "number") {
@@ -1799,7 +2018,7 @@ function buildFrame(fiber) {
1799
2018
  }
1800
2019
  return frame;
1801
2020
  }
1802
- function shouldIncludeFrame(frame, lastFrame) {
2021
+ function shouldIncludeFrame2(frame, lastFrame) {
1803
2022
  if (!lastFrame) return true;
1804
2023
  if (frame.name !== lastFrame.name) return true;
1805
2024
  if (!lastFrame.file && frame.file) return true;
@@ -1809,42 +2028,52 @@ function shouldIncludeFrame(frame, lastFrame) {
1809
2028
  }
1810
2029
  return false;
1811
2030
  }
1812
- function getOwnerStack(fiber) {
2031
+ function getOwnerStack2(fiber) {
1813
2032
  const frames = [];
1814
2033
  let current = fiber;
1815
2034
  let lastFrame = null;
2035
+ let nearestComponentFiber = null;
1816
2036
  while (current) {
1817
- const frame = buildFrame(current);
1818
- if (frame && shouldIncludeFrame(frame, lastFrame)) {
2037
+ const frame = buildFrame2(current);
2038
+ if (frame && shouldIncludeFrame2(frame, lastFrame)) {
1819
2039
  frames.push(frame);
1820
2040
  lastFrame = frame;
2041
+ if (!nearestComponentFiber) {
2042
+ nearestComponentFiber = current;
2043
+ }
1821
2044
  }
1822
2045
  current = current._debugOwner;
1823
2046
  }
1824
- return frames;
2047
+ return { frames, nearestComponentFiber };
1825
2048
  }
1826
- function getRenderStack(fiber) {
2049
+ function getRenderStack2(fiber) {
1827
2050
  const frames = [];
1828
2051
  let current = fiber;
1829
2052
  let lastFrame = null;
2053
+ let nearestComponentFiber = null;
1830
2054
  while (current) {
1831
- const frame = buildFrame(current);
1832
- if (frame && shouldIncludeFrame(frame, lastFrame)) {
2055
+ const frame = buildFrame2(current);
2056
+ if (frame && shouldIncludeFrame2(frame, lastFrame)) {
1833
2057
  frames.push(frame);
1834
2058
  lastFrame = frame;
2059
+ if (!nearestComponentFiber) {
2060
+ nearestComponentFiber = current;
2061
+ }
1835
2062
  }
1836
2063
  current = current.return;
1837
2064
  }
1838
- return frames;
2065
+ return { frames, nearestComponentFiber };
1839
2066
  }
1840
- function getReactComponentStack(element) {
1841
- const fiber = getFiberForElement(element);
1842
- if (!fiber) return [];
1843
- const ownerStack = getOwnerStack(fiber);
1844
- if (ownerStack.length > 0) {
1845
- return ownerStack;
2067
+ function getReactComponentInfo2(element) {
2068
+ const fiber = getFiberForElement2(element);
2069
+ if (!fiber) return { frames: [], nearestComponentFiber: null };
2070
+ const elementSource = getSourceFromFiber2(fiber);
2071
+ const elementSourceFile = elementSource?.fileName || void 0;
2072
+ const ownerResult = getOwnerStack2(fiber);
2073
+ if (ownerResult.frames.length > 0) {
2074
+ return { ...ownerResult, elementSourceFile };
1846
2075
  }
1847
- return getRenderStack(fiber);
2076
+ return { ...getRenderStack2(fiber), elementSourceFile };
1848
2077
  }
1849
2078
  function getElementDisplayName(element) {
1850
2079
  const tag = element.tagName.toLowerCase();
@@ -2139,14 +2368,35 @@ function parseDomSource(element) {
2139
2368
  }
2140
2369
  return { file, line, column };
2141
2370
  }
2371
+ var MAX_SUB_ELEMENT_SOURCES = 20;
2372
+ function collectSubElementSources(element) {
2373
+ const sources = {};
2374
+ const children = element.querySelectorAll("[data-direct-edit-source]");
2375
+ const labelCounts = /* @__PURE__ */ new Map();
2376
+ let count = 0;
2377
+ for (const child of children) {
2378
+ if (count >= MAX_SUB_ELEMENT_SOURCES) break;
2379
+ if (!(child instanceof HTMLElement)) continue;
2380
+ const source = parseDomSource(child);
2381
+ if (!source) continue;
2382
+ const text = ((child.innerText || child.textContent) ?? "").trim();
2383
+ let baseLabel = text.length > 0 && text.length <= 30 ? text.slice(0, 30).toLowerCase().replace(/\s+/g, "_") : child.tagName.toLowerCase();
2384
+ const existing = labelCounts.get(baseLabel) ?? 0;
2385
+ labelCounts.set(baseLabel, existing + 1);
2386
+ const label = existing > 0 ? `${baseLabel}_${existing + 1}` : baseLabel;
2387
+ sources[label] = source;
2388
+ count++;
2389
+ }
2390
+ return sources;
2391
+ }
2142
2392
  function getElementSource(element) {
2143
2393
  const domSource = parseDomSource(element);
2144
2394
  if (domSource) return domSource;
2145
2395
  const seenFibers = /* @__PURE__ */ new Set();
2146
- let fiber = getFiberForElement(element);
2396
+ let fiber = getFiberForElement2(element);
2147
2397
  while (fiber && !seenFibers.has(fiber)) {
2148
2398
  seenFibers.add(fiber);
2149
- const fiberSource = getSourceFromFiber(fiber);
2399
+ const fiberSource = getSourceFromFiber2(fiber);
2150
2400
  if (fiberSource?.fileName) {
2151
2401
  return {
2152
2402
  file: fiberSource.fileName,
@@ -2161,8 +2411,15 @@ function getElementSource(element) {
2161
2411
  function getElementLocator(element) {
2162
2412
  const elementInfo = getElementInfo(element);
2163
2413
  const domSource = getElementSource(element);
2414
+ const { frames, nearestComponentFiber, elementSourceFile } = getReactComponentInfo2(element);
2415
+ const componentName = nearestComponentFiber?.type?.displayName || nearestComponentFiber?.type?.name || void 0;
2416
+ const authoredProps = nearestComponentFiber ? getComponentProps(nearestComponentFiber) : void 0;
2417
+ const classification = classifyComponentFiber(nearestComponentFiber, frames, elementSourceFile);
2418
+ const callSite = nearestComponentFiber ? getCallSiteSource(nearestComponentFiber) : null;
2419
+ const definitionSrc = classification.isComponentPrimitive ? deriveDefinitionSource(frames) : null;
2420
+ const subSources = collectSubElementSources(element);
2164
2421
  return {
2165
- reactStack: getReactComponentStack(element),
2422
+ reactStack: frames,
2166
2423
  domSelector: buildDomSelector(element),
2167
2424
  domContextHtml: buildDomContextHtml(element),
2168
2425
  targetHtml: buildTargetHtml(element),
@@ -2170,36 +2427,80 @@ function getElementLocator(element) {
2170
2427
  tagName: elementInfo.tagName,
2171
2428
  id: elementInfo.id,
2172
2429
  classList: elementInfo.classList,
2173
- domSource: domSource ?? void 0
2430
+ domSource: domSource ?? void 0,
2431
+ reactComponentName: componentName,
2432
+ authoredProps: authoredProps && Object.keys(authoredProps).length > 0 ? authoredProps : void 0,
2433
+ subElementSources: Object.keys(subSources).length > 0 ? subSources : void 0,
2434
+ callSiteSource: callSite ?? void 0,
2435
+ definitionSource: definitionSrc ?? void 0,
2436
+ isComponentPrimitive: nearestComponentFiber || elementSourceFile ? classification.isComponentPrimitive : void 0
2174
2437
  };
2175
2438
  }
2176
2439
  function getLocatorHeader(locator) {
2177
2440
  const primaryFrame = getPrimaryFrame(locator);
2178
- const componentLabel = primaryFrame?.name ? primaryFrame.name : locator.tagName;
2179
- const formattedSource = locator.domSource?.file ? formatSourceLocation(locator.domSource.file, locator.domSource.line, locator.domSource.column) : primaryFrame?.file ? formatSourceLocation(primaryFrame.file, primaryFrame.line, primaryFrame.column) : null;
2180
- return { componentLabel, formattedSource };
2441
+ const componentLabel = locator.reactComponentName ?? primaryFrame?.name ?? locator.tagName;
2442
+ let formattedSource;
2443
+ if (locator.isComponentPrimitive && locator.definitionSource?.file) {
2444
+ formattedSource = formatSourceLocation(
2445
+ locator.definitionSource.file,
2446
+ locator.definitionSource.line,
2447
+ locator.definitionSource.column
2448
+ );
2449
+ } else {
2450
+ formattedSource = locator.domSource?.file ? formatSourceLocation(locator.domSource.file, locator.domSource.line, locator.domSource.column) : primaryFrame?.file ? formatSourceLocation(primaryFrame.file, primaryFrame.line, primaryFrame.column) : null;
2451
+ }
2452
+ const formattedCallSite = locator.callSiteSource?.file ? formatSourceLocation(locator.callSiteSource.file, locator.callSiteSource.line, locator.callSiteSource.column) : null;
2453
+ return { componentLabel, formattedSource, formattedCallSite };
2454
+ }
2455
+ function formatComponentTree(reactStack) {
2456
+ const names = reactStack.map((f) => f.name).filter(Boolean);
2457
+ if (names.length === 0) return null;
2458
+ if (names.length === 1) return names[0];
2459
+ const [component, ...ancestors] = names;
2460
+ return `${component} (in ${ancestors.join(" > ")})`;
2181
2461
  }
2182
2462
  function buildLocatorContextLines(locator, options) {
2183
2463
  const lines = [];
2184
- const { componentLabel, formattedSource } = getLocatorHeader(locator);
2464
+ const { componentLabel, formattedSource, formattedCallSite } = getLocatorHeader(locator);
2185
2465
  const target = (locator.targetHtml || locator.domContextHtml || "").trim();
2186
2466
  const context = locator.domContextHtml?.trim() || "";
2187
- const selector = locator.domSelector?.trim();
2467
+ const path = locator.domSelector?.trim();
2188
2468
  const text = locator.textPreview?.trim();
2189
2469
  lines.push(`@<${componentLabel}>`);
2190
2470
  lines.push("");
2471
+ const tree = formatComponentTree(locator.reactStack);
2472
+ if (tree) {
2473
+ lines.push(`react: ${tree}`);
2474
+ }
2475
+ if (locator.authoredProps && Object.keys(locator.authoredProps).length > 0) {
2476
+ lines.push(`props: ${JSON.stringify(locator.authoredProps)}`);
2477
+ }
2478
+ if (locator.isComponentPrimitive != null) {
2479
+ lines.push(`type: ${locator.isComponentPrimitive ? "component" : "instance"}`);
2480
+ }
2481
+ lines.push(`source: ${formattedSource ?? "(file not available)"}`);
2482
+ if (formattedCallSite && formattedCallSite !== formattedSource) {
2483
+ lines.push(`call-site: ${formattedCallSite}`);
2484
+ }
2485
+ if (locator.subElementSources && Object.keys(locator.subElementSources).length > 0) {
2486
+ lines.push("source-map:");
2487
+ for (const [label, source] of Object.entries(locator.subElementSources)) {
2488
+ lines.push(` - ${label}: ${formatSourceLocation(source.file, source.line, source.column)}`);
2489
+ }
2490
+ }
2491
+ if (path) {
2492
+ lines.push(`path: ${path}`);
2493
+ }
2191
2494
  if (target) {
2495
+ lines.push("");
2192
2496
  lines.push("target:");
2193
2497
  lines.push(target);
2194
2498
  }
2195
2499
  if (!options?.skipContext && context && context !== target) {
2500
+ lines.push("");
2196
2501
  lines.push("context:");
2197
2502
  lines.push(context);
2198
2503
  }
2199
- lines.push(`in ${formattedSource ?? "(file not available)"}`);
2200
- if (selector) {
2201
- lines.push(`selector: ${selector}`);
2202
- }
2203
2504
  if (text) {
2204
2505
  lines.push(`text: ${text}`);
2205
2506
  }
@@ -2900,7 +3201,7 @@ function buildExportInstruction(profile) {
2900
3201
  return hasComments ? "Address this feedback on the UI. Use the provided source location and selector to find each element in the codebase." : "";
2901
3202
  }
2902
3203
  const parts = [];
2903
- if (hasCssEdits) parts.push("Apply the CSS changes to the targeted elements using the project's existing styling approach (Tailwind, CSS modules, etc.).");
3204
+ if (hasCssEdits) parts.push("Apply the CSS changes to the targeted elements using the project's existing styling approach (Tailwind, CSS modules, etc.). Map values to existing CSS variables, design tokens, or utility classes already used in the project whenever possible.");
2904
3205
  if (hasTextEdits) parts.push("Update the text content as specified.");
2905
3206
  if (hasMoves) parts.push("Implement the move plan below directly in source code. For `structural_move`, reorder/reparent elements using the target anchors. For `layout_refactor`, apply the listed flex/grid refactor steps. Do NOT simulate movement with absolute positioning, left/top offsets, transform, or margin hacks.");
2906
3207
  if (hasComments) parts.push("Address the comments on the relevant elements.");
@@ -3612,11 +3913,6 @@ function useStyleUpdaters({
3612
3913
  import * as React3 from "react";
3613
3914
 
3614
3915
  // src/clipboard.ts
3615
- function buildAgentClipboardText(markdown) {
3616
- return `implement the visual edits
3617
-
3618
- ${markdown}`;
3619
- }
3620
3916
  function tryRestoreFocus(element) {
3621
3917
  if (!(element instanceof HTMLElement)) return;
3622
3918
  try {
@@ -3949,6 +4245,8 @@ function useSessionManager({
3949
4245
  const originalStyles = options?.originalStyles ?? existingEdit?.originalStyles ?? getOriginalInlineStyles(nextSingleElement);
3950
4246
  const pendingStyles = options?.pendingStyles ?? existingEdit?.pendingStyles ?? {};
3951
4247
  const elementInfo = getElementInfo(nextSingleElement);
4248
+ const { frames, nearestComponentFiber, elementSourceFile } = getReactComponentInfo(nextSingleElement);
4249
+ const isPrimitive = classifyComponentFiber(nearestComponentFiber, frames, elementSourceFile).isComponentPrimitive;
3952
4250
  setState((prev) => ({
3953
4251
  comments: prev.activeCommentId ? prev.comments.filter((comment) => {
3954
4252
  if (comment.id !== prev.activeCommentId) return true;
@@ -3967,6 +4265,7 @@ function useSessionManager({
3967
4265
  computedColor: computed.color,
3968
4266
  computedBoxShadow: computed.boxShadow,
3969
4267
  computedTypography: computed.typography,
4268
+ isComponentPrimitive: isPrimitive,
3970
4269
  originalStyles,
3971
4270
  pendingStyles,
3972
4271
  editModeActive: prev.editModeActive,
@@ -3997,6 +4296,7 @@ function useSessionManager({
3997
4296
  computedColor: null,
3998
4297
  computedBoxShadow: null,
3999
4298
  computedTypography: null,
4299
+ isComponentPrimitive: false,
4000
4300
  originalStyles: {},
4001
4301
  pendingStyles: {},
4002
4302
  activeCommentId: null,
@@ -4537,6 +4837,7 @@ function useSessionManager({
4537
4837
  computedColor: computed.color,
4538
4838
  computedBoxShadow: computed.boxShadow,
4539
4839
  computedTypography: computed.typography,
4840
+ isComponentPrimitive: prev.isComponentPrimitive,
4540
4841
  originalStyles: styleState.originalStyles,
4541
4842
  pendingStyles: styleState.pendingStyles,
4542
4843
  editModeActive: prev.editModeActive,
@@ -5314,7 +5615,15 @@ async function checkAgentConnection() {
5314
5615
  }
5315
5616
 
5316
5617
  // src/use-agent-comms.ts
5618
+ function withInstruction(profile, markdown) {
5619
+ const instruction = buildExportInstruction(profile);
5620
+ return instruction ? `${instruction}
5621
+
5622
+ ${markdown}` : markdown;
5623
+ }
5317
5624
  function buildLocatorPayload(locator) {
5625
+ const { componentLabel, formattedSource, formattedCallSite } = getLocatorHeader(locator);
5626
+ const reactTree = formatComponentTree(locator.reactStack);
5318
5627
  return {
5319
5628
  element: {
5320
5629
  tagName: locator.tagName,
@@ -5322,10 +5631,22 @@ function buildLocatorPayload(locator) {
5322
5631
  classList: locator.classList,
5323
5632
  domSelector: locator.domSelector,
5324
5633
  targetHtml: locator.targetHtml,
5634
+ contextHtml: locator.domContextHtml || null,
5325
5635
  textPreview: locator.textPreview
5326
5636
  },
5327
- source: locator.domSource || null,
5328
- reactStack: locator.reactStack
5637
+ componentLabel,
5638
+ reactTree,
5639
+ reactStack: locator.reactStack,
5640
+ reactComponentName: locator.reactComponentName ?? null,
5641
+ authoredProps: locator.authoredProps ?? null,
5642
+ type: locator.isComponentPrimitive != null ? locator.isComponentPrimitive ? "component" : "instance" : null,
5643
+ isComponentPrimitive: locator.isComponentPrimitive ?? false,
5644
+ source: formattedSource,
5645
+ callSite: formattedCallSite,
5646
+ rawSource: locator.domSource || null,
5647
+ callSiteSource: locator.callSiteSource ?? null,
5648
+ definitionSource: locator.definitionSource ?? null,
5649
+ subElementSources: locator.subElementSources ?? null
5329
5650
  };
5330
5651
  }
5331
5652
  function useAgentComms({ stateRef, sessionEditsRef, getSessionItems, saveCurrentToSession, removeSessionEdit, deleteComment }) {
@@ -5406,6 +5727,11 @@ function useAgentComms({ stateRef, sessionEditsRef, getSessionItems, saveCurrent
5406
5727
  const movePlan = includeBatchMoveEnvelope ? resolvedPlanContext.movePlan : null;
5407
5728
  const hasMeaningfulPayload = changes.length > 0 || sessionEdit.textEdit != null || moveIntent != null;
5408
5729
  if (!hasMeaningfulPayload) return true;
5730
+ const profile = getExportContentProfile(
5731
+ [sessionEdit],
5732
+ [],
5733
+ resolvedPlanContext
5734
+ );
5409
5735
  try {
5410
5736
  const result = await sendEditToAgent({
5411
5737
  ...buildLocatorPayload(locator),
@@ -5413,7 +5739,7 @@ function useAgentComms({ stateRef, sessionEditsRef, getSessionItems, saveCurrent
5413
5739
  textChange: sessionEdit.textEdit ?? null,
5414
5740
  moveIntent,
5415
5741
  ...movePlan ? { movePlan } : {},
5416
- exportMarkdown
5742
+ exportMarkdown: withInstruction(profile, exportMarkdown)
5417
5743
  });
5418
5744
  if (result.ok) {
5419
5745
  removeSessionEdit(sessionEdit.element);
@@ -5425,12 +5751,13 @@ function useAgentComms({ stateRef, sessionEditsRef, getSessionItems, saveCurrent
5425
5751
  }, [updateAgentAvailability, removeSessionEdit]);
5426
5752
  const sendSessionCommentToAgent = React5.useCallback(async (comment) => {
5427
5753
  const exportMarkdown = buildCommentExport(comment.locator, comment.text, comment.replies);
5754
+ const commentProfile = { hasCssEdits: false, hasTextEdits: false, hasMoves: false, hasComments: true };
5428
5755
  try {
5429
5756
  const result = await sendCommentToAgent({
5430
5757
  ...buildLocatorPayload(comment.locator),
5431
5758
  commentText: comment.text,
5432
5759
  replies: comment.replies,
5433
- exportMarkdown
5760
+ exportMarkdown: withInstruction(commentProfile, exportMarkdown)
5434
5761
  });
5435
5762
  if (result.ok) {
5436
5763
  deleteComment(comment.id);
@@ -5450,12 +5777,14 @@ function useAgentComms({ stateRef, sessionEditsRef, getSessionItems, saveCurrent
5450
5777
  );
5451
5778
  if (editsWithChanges.length === 0 && contextBlocks.length === 0) return false;
5452
5779
  const markdownParts = [];
5780
+ let movePlanCtx = null;
5453
5781
  if (editsWithChanges.length > 0) {
5454
- const movePlanContext = buildMovePlanContext(editsWithChanges);
5455
- markdownParts.push(buildSessionExport(editsWithChanges, [], { movePlanContext }));
5782
+ movePlanCtx = buildMovePlanContext(editsWithChanges);
5783
+ markdownParts.push(buildSessionExport(editsWithChanges, [], { movePlanContext: movePlanCtx }));
5456
5784
  }
5457
5785
  markdownParts.push(...contextBlocks);
5458
5786
  const exportMarkdown = markdownParts.join("\n\n");
5787
+ const multiProfile = getExportContentProfile(editsWithChanges, [], movePlanCtx);
5459
5788
  const primaryEl = current.selectedElements.find((el) => el.isConnected);
5460
5789
  if (!primaryEl) return false;
5461
5790
  const primary = getElementLocator(primaryEl);
@@ -5465,7 +5794,7 @@ function useAgentComms({ stateRef, sessionEditsRef, getSessionItems, saveCurrent
5465
5794
  changes: [],
5466
5795
  textChange: null,
5467
5796
  moveIntent: null,
5468
- exportMarkdown
5797
+ exportMarkdown: withInstruction(multiProfile, exportMarkdown)
5469
5798
  });
5470
5799
  if (result.ok) {
5471
5800
  for (const el of current.selectedElements) {
@@ -6293,6 +6622,7 @@ function DirectEditProvider({ children }) {
6293
6622
  computedColor: null,
6294
6623
  computedBoxShadow: null,
6295
6624
  computedTypography: null,
6625
+ isComponentPrimitive: false,
6296
6626
  originalStyles: {},
6297
6627
  pendingStyles: {},
6298
6628
  editModeActive: false,
@@ -6414,9 +6744,10 @@ function DirectEditProvider({ children }) {
6414
6744
  enterCanvas();
6415
6745
  }
6416
6746
  if (wasActive) {
6747
+ clearSelection();
6417
6748
  closePanel();
6418
6749
  }
6419
- }, [toggleEditModeBase, stateRef, exitCanvas, enterCanvas, closePanel]);
6750
+ }, [toggleEditModeBase, stateRef, exitCanvas, enterCanvas, clearSelection, closePanel]);
6420
6751
  const toggleCanvasWithPreference = React8.useCallback(() => {
6421
6752
  const willBeActive = !stateRef.current.canvas.active;
6422
6753
  toggleCanvas();
@@ -8584,6 +8915,7 @@ function useSelectionResize({
8584
8915
  import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
8585
8916
  var BLUE3 = "#0D99FF";
8586
8917
  var MAGENTA = "#E11BB6";
8918
+ var COMPONENT_PURPLE = "#8B5CF6";
8587
8919
  var DRAG_THRESHOLD = 4;
8588
8920
  var DBLCLICK_DELAY = 300;
8589
8921
  var HANDLE_SIZE = 12;
@@ -8627,9 +8959,11 @@ function SelectionOverlay({
8627
8959
  onHoverElement,
8628
8960
  onClickThrough,
8629
8961
  onSelectPageFrame,
8962
+ isComponentPrimitive = false,
8630
8963
  enableResizeHandles = false,
8631
8964
  onResizeSizingChange
8632
8965
  }) {
8966
+ const selectionColor = isComponentPrimitive ? COMPONENT_PURPLE : BLUE3;
8633
8967
  const rectElement = isDragging && draggedElement ? draggedElement : selectedElement;
8634
8968
  const [rect, setRect] = React19.useState(() => rectElement.getBoundingClientRect());
8635
8969
  const [pageFrameRect, setPageFrameRect] = React19.useState(() => pageFrameElement ? pageFrameElement.getBoundingClientRect() : null);
@@ -8957,7 +9291,7 @@ function SelectionOverlay({
8957
9291
  zIndex: 99997,
8958
9292
  background: "transparent",
8959
9293
  border: "none",
8960
- color: BLUE3,
9294
+ color: selectionColor,
8961
9295
  fontSize: `${pageLabelFontSize}px`,
8962
9296
  lineHeight: `${pageLabelLineHeight}px`,
8963
9297
  padding: 0,
@@ -8985,7 +9319,7 @@ function SelectionOverlay({
8985
9319
  height: rect.height,
8986
9320
  pointerEvents: "none",
8987
9321
  zIndex: 99996,
8988
- border: `1px solid ${BLUE3}`,
9322
+ border: `1px solid ${selectionColor}`,
8989
9323
  borderRadius: "0px",
8990
9324
  boxSizing: "border-box"
8991
9325
  }
@@ -9002,18 +9336,28 @@ function SelectionOverlay({
9002
9336
  transform: "translateX(-50%)",
9003
9337
  pointerEvents: "none",
9004
9338
  zIndex: 99992,
9005
- background: BLUE3,
9006
- color: "white",
9007
- fontSize: "11px",
9008
- lineHeight: "20px",
9009
- padding: "0 6px",
9010
- borderRadius: "4px",
9011
- whiteSpace: "nowrap",
9012
- fontFamily: "system-ui, sans-serif",
9013
- fontWeight: 500,
9014
- letterSpacing: "-0.01em"
9339
+ display: "flex",
9340
+ alignItems: "center",
9341
+ gap: "4px"
9015
9342
  },
9016
- children: dimensionText
9343
+ children: /* @__PURE__ */ jsx9(
9344
+ "span",
9345
+ {
9346
+ style: {
9347
+ background: selectionColor,
9348
+ color: "white",
9349
+ fontSize: "11px",
9350
+ lineHeight: "20px",
9351
+ padding: "0 6px",
9352
+ borderRadius: "4px",
9353
+ whiteSpace: "nowrap",
9354
+ fontFamily: "system-ui, sans-serif",
9355
+ fontWeight: 500,
9356
+ letterSpacing: "-0.01em"
9357
+ },
9358
+ children: dimensionText
9359
+ }
9360
+ )
9017
9361
  }
9018
9362
  ),
9019
9363
  !isDragging && !isTextEditing && /* @__PURE__ */ jsxs5(
@@ -9069,7 +9413,7 @@ function SelectionOverlay({
9069
9413
  position: "absolute",
9070
9414
  width: RESIZE_CORNER_SIZE,
9071
9415
  height: RESIZE_CORNER_SIZE,
9072
- border: `1px solid ${BLUE3}`,
9416
+ border: `1px solid ${selectionColor}`,
9073
9417
  background: "#fff",
9074
9418
  borderRadius: 1,
9075
9419
  boxSizing: "border-box",
@@ -12494,6 +12838,7 @@ function DirectEditPanelContent() {
12494
12838
  computedColor,
12495
12839
  computedBoxShadow,
12496
12840
  computedTypography,
12841
+ isComponentPrimitive,
12497
12842
  borderStyleControlPreference,
12498
12843
  pendingStyles,
12499
12844
  editModeActive,
@@ -12814,6 +13159,7 @@ function DirectEditPanelContent() {
12814
13159
  selectElement(child);
12815
13160
  }
12816
13161
  },
13162
+ isComponentPrimitive,
12817
13163
  enableResizeHandles: true,
12818
13164
  onResizeSizingChange: updateSizingProperties
12819
13165
  }
@@ -14805,7 +15151,10 @@ function DirectEditDemo() {
14805
15151
  const handleExportEdits = async () => {
14806
15152
  if (Object.keys(pendingStyles).length === 0) return false;
14807
15153
  const exportMarkdown = buildEditExport(DEMO_LOCATOR, pendingStyles);
14808
- return copyText(buildAgentClipboardText(exportMarkdown));
15154
+ const instruction = buildExportInstruction({ hasCssEdits: true, hasTextEdits: false, hasMoves: false, hasComments: false });
15155
+ return copyText(`${instruction}
15156
+
15157
+ ${exportMarkdown}`);
14809
15158
  };
14810
15159
  return /* @__PURE__ */ jsx36("div", { className: "min-h-screen p-8", children: /* @__PURE__ */ jsxs29("div", { className: "mx-auto max-w-4xl", children: [
14811
15160
  /* @__PURE__ */ jsx36("h1", { className: "mb-2 text-2xl font-bold", children: "Direct Edit Panel" }),