@agent-native/core 0.80.10 → 0.80.11

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 (66) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +6 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/agent/production-agent.ts +108 -15
  5. package/corpus/core/src/client/AssistantChat.tsx +123 -26
  6. package/corpus/core/src/client/sse-event-processor.ts +9 -0
  7. package/corpus/templates/assets/.agents/skills/image-generation/SKILL.md +9 -2
  8. package/corpus/templates/assets/AGENTS.md +4 -0
  9. package/corpus/templates/assets/actions/_tool-activity.ts +46 -0
  10. package/corpus/templates/assets/actions/generate-image-batch.ts +26 -5
  11. package/corpus/templates/assets/actions/generate-image.ts +118 -67
  12. package/corpus/templates/assets/actions/list-draft-assets.ts +50 -0
  13. package/corpus/templates/assets/actions/rerun-generation-run.ts +52 -31
  14. package/corpus/templates/assets/app/components/create/RecentDraftsSection.tsx +100 -0
  15. package/corpus/templates/assets/app/i18n/zh-TW.ts +7 -0
  16. package/corpus/templates/assets/app/i18n-data.ts +61 -0
  17. package/corpus/templates/assets/app/routes/_index.tsx +4 -0
  18. package/corpus/templates/assets/app/routes/library.tsx +145 -38
  19. package/corpus/templates/assets/changelog/2026-06-29-image-generation-can-now-render-requested-text-and-respect-b.md +6 -0
  20. package/corpus/templates/assets/changelog/2026-06-30-image-generation-no-longer-looks-stuck-while-the-provider-is-still-working.md +6 -0
  21. package/corpus/templates/assets/changelog/2026-06-30-tagged-presets-now-control-the-image-aspect-ratio.md +6 -0
  22. package/corpus/templates/assets/server/lib/generation.ts +135 -11
  23. package/corpus/templates/assets/shared/api.ts +4 -0
  24. package/corpus/templates/clips/actions/list-ai-requests.ts +60 -0
  25. package/corpus/templates/clips/app/hooks/use-auto-title.ts +24 -25
  26. package/corpus/templates/design/actions/apply-component-prop-edit.ts +13 -5
  27. package/corpus/templates/design/actions/apply-design-state.ts +17 -4
  28. package/corpus/templates/design/actions/apply-motion-edit.ts +9 -46
  29. package/corpus/templates/design/actions/delete-design.ts +20 -0
  30. package/corpus/templates/design/actions/get-component-details.ts +16 -7
  31. package/corpus/templates/design/actions/index-design-tokens.ts +8 -4
  32. package/corpus/templates/design/actions/list-design-states.ts +19 -1
  33. package/corpus/templates/design/actions/open-component-source.ts +7 -2
  34. package/corpus/templates/design/actions/preview-component-prop-edit.ts +32 -26
  35. package/corpus/templates/design/actions/preview-shader-fill.ts +9 -11
  36. package/corpus/templates/design/actions/run-design-audit.ts +21 -6
  37. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +139 -14
  38. package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +20 -3
  39. package/corpus/templates/design/app/components/design/EditPanel.tsx +428 -31
  40. package/corpus/templates/design/app/components/design/LayersPanel.tsx +110 -30
  41. package/corpus/templates/design/app/components/design/MotionDock.tsx +9 -0
  42. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +1 -1
  43. package/corpus/templates/design/app/components/design/ReviewPanel.tsx +12 -5
  44. package/corpus/templates/design/app/components/design/StatesPanel.tsx +4 -2
  45. package/corpus/templates/design/app/components/design/TokensPanel.tsx +13 -8
  46. package/corpus/templates/design/app/i18n/zh-TW.ts +1 -0
  47. package/corpus/templates/design/app/i18n-data.ts +11 -0
  48. package/corpus/templates/design/app/pages/DesignEditor.tsx +684 -179
  49. package/corpus/templates/design/changelog/2026-06-30-design-token-edits-now-stay-visible-in-previews-and-token-li.md +6 -0
  50. package/corpus/templates/design/e2e/global-setup.ts +94 -2
  51. package/corpus/templates/design/shared/component-model.ts +35 -0
  52. package/corpus/templates/design/shared/motion-compiler.ts +79 -8
  53. package/corpus/templates/design/shared/resolve-tweaks.ts +32 -9
  54. package/dist/agent/production-agent.d.ts.map +1 -1
  55. package/dist/agent/production-agent.js +94 -10
  56. package/dist/agent/production-agent.js.map +1 -1
  57. package/dist/client/AssistantChat.d.ts +14 -0
  58. package/dist/client/AssistantChat.d.ts.map +1 -1
  59. package/dist/client/AssistantChat.js +115 -22
  60. package/dist/client/AssistantChat.js.map +1 -1
  61. package/dist/client/sse-event-processor.d.ts.map +1 -1
  62. package/dist/client/sse-event-processor.js +10 -0
  63. package/dist/client/sse-event-processor.js.map +1 -1
  64. package/dist/observability/routes.d.ts +3 -3
  65. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  66. package/package.json +1 -1
@@ -99,6 +99,8 @@ const MOTION_PREVIEW_BRIDGE_SCRIPT = `
99
99
  var loadedTracks = [];
100
100
  // Map of nodeId -> [property, ...] we have touched, for cleanup.
101
101
  var touchedProps = {};
102
+ // Map of nodeId -> property -> original inline style value.
103
+ var originalInlineValues = {};
102
104
 
103
105
  function lerp(a, b, ratio) {
104
106
  var numA = parseFloat(a);
@@ -137,6 +139,10 @@ const MOTION_PREVIEW_BRIDGE_SCRIPT = `
137
139
  if (!el) continue;
138
140
  var value = interpolate(track.keyframes, t);
139
141
  if (value === '') continue;
142
+ if (!originalInlineValues[track.targetNodeId]) originalInlineValues[track.targetNodeId] = {};
143
+ if (!(track.property in originalInlineValues[track.targetNodeId])) {
144
+ originalInlineValues[track.targetNodeId][track.property] = el.style[track.property] || '';
145
+ }
140
146
  el.style[track.property] = value;
141
147
  if (!touchedProps[track.targetNodeId]) touchedProps[track.targetNodeId] = [];
142
148
  if (touchedProps[track.targetNodeId].indexOf(track.property) === -1) {
@@ -152,10 +158,14 @@ const MOTION_PREVIEW_BRIDGE_SCRIPT = `
152
158
  if (!el) continue;
153
159
  var props = touchedProps[nodeIds[i]];
154
160
  for (var j = 0; j < props.length; j++) {
155
- el.style[props[j]] = '';
161
+ var originals = originalInlineValues[nodeIds[i]] || {};
162
+ el.style[props[j]] = Object.prototype.hasOwnProperty.call(originals, props[j])
163
+ ? originals[props[j]]
164
+ : '';
156
165
  }
157
166
  }
158
167
  touchedProps = {};
168
+ originalInlineValues = {};
159
169
  loadedTracks = [];
160
170
  }
161
171
 
@@ -163,8 +173,8 @@ const MOTION_PREVIEW_BRIDGE_SCRIPT = `
163
173
  if (e.source !== window.parent) return;
164
174
  if (!e.data || typeof e.data.type !== 'string') return;
165
175
  if (e.data.type === 'motion-load-tracks') {
176
+ clearPreview();
166
177
  loadedTracks = Array.isArray(e.data.tracks) ? e.data.tracks : [];
167
- touchedProps = {};
168
178
  return;
169
179
  }
170
180
  if (e.data.type === 'motion-preview') {
@@ -1074,6 +1084,10 @@ const EDITOR_CHROME_BRIDGE_SCRIPT = `
1074
1084
  }
1075
1085
 
1076
1086
  function isLayerInteractionBlocked(el) {
1087
+ if (!el) return false;
1088
+ if (el.closest && el.closest('[data-agent-native-locked="true"], [data-agent-native-hidden="true"]')) {
1089
+ return true;
1090
+ }
1077
1091
  return matchesSelectorList(el, lockedSelectors) || matchesSelectorList(el, hiddenSelectors);
1078
1092
  }
1079
1093
 
@@ -1948,6 +1962,12 @@ const EDITOR_CHROME_BRIDGE_SCRIPT = `
1948
1962
  selectedSpacingHovered = false;
1949
1963
  hoveredSpacingHandleKey = '';
1950
1964
  selectedEl = selectionTargetForHit(target);
1965
+ if (!selectedEl || isLayerInteractionBlocked(selectedEl)) {
1966
+ selectedEl = null;
1967
+ selectionOverlay.style.display = 'none';
1968
+ clearComponentTag();
1969
+ return;
1970
+ }
1951
1971
  var info = getElementInfo(selectedEl);
1952
1972
  positionOverlay(selectionOverlay, selectedEl);
1953
1973
  window.parent.postMessage({ type: 'element-select', payload: info }, '*');
@@ -1973,9 +1993,15 @@ const EDITOR_CHROME_BRIDGE_SCRIPT = `
1973
1993
  selectedSpacingHovered = false;
1974
1994
  hoveredSpacingHandleKey = '';
1975
1995
  selectedEl = selectionTargetForHit(target);
1976
- info = getElementInfo(selectedEl);
1977
- positionOverlay(selectionOverlay, selectedEl);
1978
- window.parent.postMessage({ type: 'element-select', payload: info }, '*');
1996
+ if (selectedEl && !isLayerInteractionBlocked(selectedEl)) {
1997
+ info = getElementInfo(selectedEl);
1998
+ positionOverlay(selectionOverlay, selectedEl);
1999
+ window.parent.postMessage({ type: 'element-select', payload: info }, '*');
2000
+ } else {
2001
+ selectedEl = null;
2002
+ selectionOverlay.style.display = 'none';
2003
+ clearComponentTag();
2004
+ }
1979
2005
  }
1980
2006
  window.parent.postMessage({
1981
2007
  type: 'element-contextmenu',
@@ -2198,6 +2224,21 @@ const EDITOR_CHROME_BRIDGE_SCRIPT = `
2198
2224
  return !!(ancestorEl && (ancestorEl === el || el.contains(ancestorEl)));
2199
2225
  }
2200
2226
 
2227
+ function normalizeCssPropertyName(property) {
2228
+ var prop = String(property || '').trim();
2229
+ if (!prop) return '';
2230
+ if (prop.indexOf('--') === 0) return prop;
2231
+ return prop.replace(/([A-Z])/g, '-$1').toLowerCase();
2232
+ }
2233
+
2234
+ function applyInlineStyleProperty(el, property, value) {
2235
+ if (!el || !property) return false;
2236
+ var cssProperty = normalizeCssPropertyName(property);
2237
+ if (!cssProperty) return false;
2238
+ el.style.setProperty(cssProperty, String(value));
2239
+ return true;
2240
+ }
2241
+
2201
2242
  function applyTextRangeStyle(property, value) {
2202
2243
  if (!activeTextEditEl || !property) return false;
2203
2244
  var selection = window.getSelection && window.getSelection();
@@ -2205,7 +2246,7 @@ const EDITOR_CHROME_BRIDGE_SCRIPT = `
2205
2246
  if (!selectionBelongsToElement(selection, activeTextEditEl)) return false;
2206
2247
  var range = selection.getRangeAt(0);
2207
2248
  var span = document.createElement('span');
2208
- span.style[property] = value;
2249
+ applyInlineStyleProperty(span, property, value);
2209
2250
  if (!span.getAttribute('style')) return false;
2210
2251
  try {
2211
2252
  range.surroundContents(span);
@@ -2384,7 +2425,7 @@ const EDITOR_CHROME_BRIDGE_SCRIPT = `
2384
2425
  insertionGuide.style.height = rect.height + 'px';
2385
2426
  insertionGuide.style.background = 'color-mix(in srgb, var(--design-editor-accent-color) 14%, transparent)';
2386
2427
  insertionGuide.style.border = '2px solid var(--design-editor-accent-color)';
2387
- insertionGuide.style.borderRadius = '4px';
2428
+ insertionGuide.style.borderRadius = '2px';
2388
2429
  insertionGuide.style.boxShadow = 'none';
2389
2430
  return;
2390
2431
  }
@@ -2905,6 +2946,17 @@ const EDITOR_CHROME_BRIDGE_SCRIPT = `
2905
2946
  shieldOverlay.addEventListener(type, stopNativeInteraction, true);
2906
2947
  });
2907
2948
 
2949
+ function stopBlockedLayerInteraction(e) {
2950
+ if (isOverlayElement(e.target)) return;
2951
+ var target = e.target && e.target.nodeType === 1 ? e.target : null;
2952
+ if (!target || !isLayerInteractionBlocked(target)) return;
2953
+ stopNativeInteraction(e);
2954
+ }
2955
+
2956
+ ['pointerdown','pointerup','mousedown','mouseup','click','auxclick'].forEach(function(type) {
2957
+ document.addEventListener(type, stopBlockedLayerInteraction, true);
2958
+ });
2959
+
2908
2960
  shieldOverlay.addEventListener('click', selectElementAtEvent, true);
2909
2961
  shieldOverlay.addEventListener('contextmenu', openContextMenuAtEvent, true);
2910
2962
  selectionOverlay.addEventListener('contextmenu', openContextMenuAtEvent, true);
@@ -3123,6 +3175,11 @@ const EDITOR_CHROME_BRIDGE_SCRIPT = `
3123
3175
  window.addEventListener('message', function(e) {
3124
3176
  if (e.source !== window.parent) return;
3125
3177
  if (!e.data) return;
3178
+ if (e.data.payload && typeof e.data.payload === 'object') {
3179
+ Object.keys(e.data.payload).forEach(function(key) {
3180
+ if (e.data[key] === undefined) e.data[key] = e.data.payload[key];
3181
+ });
3182
+ }
3126
3183
  if (e.data.type === 'set-editor-chrome-scale') {
3127
3184
  // Live-update the constant-size chrome scale WITHOUT rebuilding srcdoc.
3128
3185
  // Rebuilding srcdoc reloads the iframe and flashes the content white.
@@ -3211,6 +3268,7 @@ const EDITOR_CHROME_BRIDGE_SCRIPT = `
3211
3268
  if (selectedEl && isLayerInteractionBlocked(selectedEl)) {
3212
3269
  selectedEl = null;
3213
3270
  selectionOverlay.style.display = 'none';
3271
+ clearComponentTag();
3214
3272
  }
3215
3273
  if (hoveredEl && isLayerInteractionBlocked(hoveredEl)) {
3216
3274
  hoveredEl = null;
@@ -3242,7 +3300,11 @@ const EDITOR_CHROME_BRIDGE_SCRIPT = `
3242
3300
  return;
3243
3301
  }
3244
3302
  if (e.data.type === 'replace-document-content') {
3245
- replaceRuntimeDocument(e.data.content, e.data.selectedSelector, e.data.selectorCandidates);
3303
+ replaceRuntimeDocument(
3304
+ e.data.content,
3305
+ e.data.forceFullDocument ? '' : e.data.selectedSelector,
3306
+ e.data.forceFullDocument ? [] : e.data.selectorCandidates
3307
+ );
3246
3308
  return;
3247
3309
  }
3248
3310
  if (e.data.type === 'delete-element') {
@@ -3253,13 +3315,63 @@ const EDITOR_CHROME_BRIDGE_SCRIPT = `
3253
3315
  var sel = e.data.selector;
3254
3316
  var prop = e.data.property;
3255
3317
  var val = e.data.value;
3256
- var el = sel ? document.querySelector(sel) : null;
3257
- if (activeTextEditEl && el === activeTextEditEl && applyTextRangeStyle(prop, val)) {
3318
+ var candidatesForStyle = Array.isArray(e.data.selectorCandidates) ? e.data.selectorCandidates : [];
3319
+ if (sel && candidatesForStyle.indexOf(String(sel)) === -1) candidatesForStyle.push(String(sel));
3320
+ if (e.data.nodeId) {
3321
+ candidatesForStyle.push('[data-agent-native-node-id="' + String(e.data.nodeId).replace(/"/g, '\\\\"') + '"]');
3322
+ }
3323
+ var el = findRuntimeTarget(String(sel || ''), candidatesForStyle);
3324
+ if (prop && activeTextEditEl && el === activeTextEditEl && applyTextRangeStyle(prop, val)) {
3258
3325
  postTextContentChange(activeTextEditEl, activeTextEditEl.textContent || '', activeTextEditEl.innerHTML || '');
3259
3326
  refreshOverlays();
3260
3327
  return;
3261
3328
  }
3262
- if (el) el.style[prop] = val;
3329
+ if (!el) return;
3330
+ var didPatchDom = false;
3331
+ var attributeOverrides = e.data.attributeOverrides;
3332
+ if (attributeOverrides && typeof attributeOverrides === 'object' && !Array.isArray(attributeOverrides)) {
3333
+ Object.keys(attributeOverrides).forEach(function(name) {
3334
+ if (!/^(?!on)[a-zA-Z][a-zA-Z0-9:_.-]*$/i.test(name)) return;
3335
+ var nextValue = attributeOverrides[name];
3336
+ if (nextValue === null || nextValue === undefined || nextValue === false) {
3337
+ el.removeAttribute(name);
3338
+ } else {
3339
+ el.setAttribute(name, String(nextValue));
3340
+ }
3341
+ didPatchDom = true;
3342
+ });
3343
+ }
3344
+ var classEdit = e.data.classEdit;
3345
+ if (classEdit && typeof classEdit === 'object') {
3346
+ var currentClass = (el.getAttribute('class') || '').trim().split(/\\s+/).filter(Boolean);
3347
+ var nextClass = currentClass.slice();
3348
+ if (classEdit.operation === 'replace' && classEdit.from && classEdit.to) {
3349
+ var replaced = false;
3350
+ nextClass = currentClass.map(function(token) {
3351
+ if (token === classEdit.from) {
3352
+ replaced = true;
3353
+ return String(classEdit.to);
3354
+ }
3355
+ return token;
3356
+ });
3357
+ if (!replaced && nextClass.indexOf(String(classEdit.to)) === -1) nextClass.push(String(classEdit.to));
3358
+ didPatchDom = true;
3359
+ } else if (classEdit.operation === 'add' && classEdit.className) {
3360
+ if (nextClass.indexOf(String(classEdit.className)) === -1) nextClass.push(String(classEdit.className));
3361
+ didPatchDom = true;
3362
+ } else if (classEdit.operation === 'remove' && classEdit.className) {
3363
+ nextClass = currentClass.filter(function(token) { return token !== String(classEdit.className); });
3364
+ didPatchDom = true;
3365
+ }
3366
+ if (didPatchDom) el.setAttribute('class', nextClass.join(' '));
3367
+ }
3368
+ if (prop && typeof prop === 'string') {
3369
+ applyInlineStyleProperty(el, prop, val);
3370
+ didPatchDom = true;
3371
+ }
3372
+ if (didPatchDom) {
3373
+ refreshOverlays();
3374
+ }
3263
3375
  });
3264
3376
 
3265
3377
  window.addEventListener('scroll', refreshOverlays, true);
@@ -3590,7 +3702,8 @@ export function DesignCanvas({
3590
3702
  });
3591
3703
 
3592
3704
  // Build the srcdoc. The tweak bridge ALWAYS goes in so the panel works
3593
- // outside Edit mode. The editor chrome bridge is omitted only for Interact.
3705
+ // outside Edit mode. The editor chrome bridge is omitted for Interact and
3706
+ // read-only surfaces so preview/app users can interact with the app normally.
3594
3707
  const srcdoc = useMemo(() => {
3595
3708
  if (externalPreviewUrl) return undefined;
3596
3709
  const editorChromeBridge =
@@ -4074,11 +4187,23 @@ export function DesignCanvas({
4074
4187
  }, [editorChromeScaleX, editorChromeScaleY]);
4075
4188
 
4076
4189
  const sendStyleChange = useCallback(
4077
- (selector: string, property: string, value: string) => {
4190
+ (
4191
+ selector: string,
4192
+ property: string,
4193
+ value: string,
4194
+ options?: { selectorCandidates?: string[]; nodeId?: string | null },
4195
+ ) => {
4078
4196
  const iframe = iframeRef.current;
4079
4197
  if (!iframe?.contentWindow) return;
4080
4198
  iframe.contentWindow.postMessage(
4081
- { type: "style-change", selector, property, value },
4199
+ {
4200
+ type: "style-change",
4201
+ selector,
4202
+ property,
4203
+ value,
4204
+ selectorCandidates: options?.selectorCandidates ?? [],
4205
+ nodeId: options?.nodeId ?? "",
4206
+ },
4082
4207
  "*",
4083
4208
  );
4084
4209
  },
@@ -26,7 +26,7 @@ import {
26
26
  IconSparkles,
27
27
  } from "@tabler/icons-react";
28
28
  import { useQuery, useQueryClient } from "@tanstack/react-query";
29
- import { useCallback, useEffect, useMemo, useState } from "react";
29
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
30
30
  import { toast } from "sonner";
31
31
 
32
32
  import { Button } from "@/components/ui/button";
@@ -86,6 +86,8 @@ export interface DesignExtensionSlotContext extends Record<string, unknown> {
86
86
  mode: string;
87
87
  activeTool: string;
88
88
  tweakValues: Record<string, string | number | boolean>;
89
+ onShaderFillPreview?: (descriptor: ShaderDescriptor, css: string) => void;
90
+ onShaderFillPreviewClear?: () => void;
89
91
  }
90
92
 
91
93
  interface DesignExtensionsPanelProps {
@@ -447,6 +449,20 @@ interface ShaderFillsExtPanelProps {
447
449
 
448
450
  function ShaderFillsExtPanel({ context }: ShaderFillsExtPanelProps) {
449
451
  const [showShaders, setShowShaders] = useState(false);
452
+ const clearPreviewRef = useRef(context.onShaderFillPreviewClear);
453
+ useEffect(() => {
454
+ clearPreviewRef.current = context.onShaderFillPreviewClear;
455
+ }, [context.onShaderFillPreviewClear]);
456
+ useEffect(
457
+ () => () => {
458
+ clearPreviewRef.current?.();
459
+ },
460
+ [],
461
+ );
462
+ const closeShaders = () => {
463
+ context.onShaderFillPreviewClear?.();
464
+ setShowShaders(false);
465
+ };
450
466
  // The most recently previewed descriptor — Apply persists exactly this one,
451
467
  // so the write is intentional (one atomic call) rather than firing on every
452
468
  // slider tweak.
@@ -535,14 +551,15 @@ function ShaderFillsExtPanel({ context }: ShaderFillsExtPanelProps) {
535
551
  return (
536
552
  <div className="flex flex-col">
537
553
  <ShaderFillsPanel
538
- onApply={(descriptor, _css) => {
554
+ onApply={(descriptor, css) => {
539
555
  // Preview only: ShaderFillsPanel fires apply-shader (planning/codegen)
540
556
  // for agent context on every tune and the iframe shows the gradient.
541
557
  // We just record the latest descriptor here; the explicit Apply
542
558
  // button below performs the single intentional persist write.
543
559
  setPreviewed(descriptor);
560
+ context.onShaderFillPreview?.(descriptor, css);
544
561
  }}
545
- onBack={() => setShowShaders(false)}
562
+ onBack={closeShaders}
546
563
  applyContext={{
547
564
  designId: context.designId || undefined,
548
565
  fileId: context.activeFileId || undefined,