@agent-native/core 0.81.2 → 0.82.0

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 (81) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +25 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/client/frame.ts +55 -0
  5. package/corpus/core/src/file-upload/builder.ts +199 -37
  6. package/corpus/core/src/file-upload/index.ts +2 -0
  7. package/corpus/core/src/file-upload/types.ts +38 -0
  8. package/corpus/core/src/mcp/build-server.ts +30 -4
  9. package/corpus/core/src/mcp/embed-app.ts +33 -18
  10. package/corpus/templates/clips/actions/create-recording.ts +44 -0
  11. package/corpus/templates/clips/actions/finalize-recording.ts +198 -88
  12. package/corpus/templates/clips/actions/lib/create-recording-schema.ts +12 -0
  13. package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +83 -29
  14. package/corpus/templates/clips/app/routes/record.tsx +12 -1
  15. package/corpus/templates/clips/server/lib/resumable-session.ts +39 -0
  16. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/abort.post.ts +2 -0
  17. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +186 -29
  18. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/reset-chunks.post.ts +4 -0
  19. package/corpus/templates/clips/shared/recording-core.ts +5 -0
  20. package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +63 -16
  21. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +28 -33
  22. package/corpus/templates/content/app/components/sidebar/document-sidebar-sections.ts +47 -0
  23. package/corpus/templates/content/app/hooks/use-documents.ts +37 -0
  24. package/corpus/templates/content/changelog/2026-06-30-sidebar-favorites-now-keep-long-titles-tidy-and-stay-in-sync.md +6 -0
  25. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +8 -1
  26. package/corpus/templates/design/app/components/design/LayersPanel.tsx +11 -2
  27. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +89 -16
  28. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +21 -14
  29. package/corpus/templates/design/app/pages/DesignEditor.tsx +557 -211
  30. package/corpus/templates/design/changelog/2026-06-30-design-studio-canvas-layers-can-be-copied-pasted-and-reparen.md +6 -0
  31. package/corpus/templates/design/e2e/global-setup.ts +3 -1
  32. package/corpus/templates/design/e2e/helpers.ts +4 -1
  33. package/corpus/templates/design/playwright.config.ts +4 -1
  34. package/corpus/templates/plan/actions/consume-plan-feedback.ts +1 -9
  35. package/corpus/templates/plan/actions/convert-visual-plan-to-prototype.ts +1 -1
  36. package/corpus/templates/plan/actions/create-plan-design.ts +1 -1
  37. package/corpus/templates/plan/actions/create-prototype-plan.ts +1 -1
  38. package/corpus/templates/plan/actions/create-ui-plan.ts +1 -1
  39. package/corpus/templates/plan/actions/create-visual-plan.ts +36 -19
  40. package/corpus/templates/plan/actions/create-visual-questions.ts +1 -1
  41. package/corpus/templates/plan/actions/create-visual-recap.ts +1 -1
  42. package/corpus/templates/plan/actions/delete-plan-comment.ts +1 -9
  43. package/corpus/templates/plan/actions/delete-visual-plan.ts +1 -9
  44. package/corpus/templates/plan/actions/get-plan-feedback.ts +1 -9
  45. package/corpus/templates/plan/actions/get-visual-plan.ts +1 -9
  46. package/corpus/templates/plan/actions/import-visual-plan-source.ts +1 -1
  47. package/corpus/templates/plan/actions/list-visual-plans.ts +1 -9
  48. package/corpus/templates/plan/actions/reply-to-plan-comment.ts +1 -9
  49. package/corpus/templates/plan/actions/resolve-plan-comment.ts +1 -9
  50. package/corpus/templates/plan/actions/update-visual-plan.ts +1 -1
  51. package/corpus/templates/plan/actions/visual-answer.ts +1 -1
  52. package/corpus/templates/plan/app/components/layout/Layout.tsx +15 -0
  53. package/corpus/templates/plan/app/entry.client.tsx +10 -0
  54. package/corpus/templates/plan/app/global.css +28 -0
  55. package/corpus/templates/plan/shared/plan-content.ts +10 -6
  56. package/dist/client/frame.d.ts.map +1 -1
  57. package/dist/client/frame.js +59 -0
  58. package/dist/client/frame.js.map +1 -1
  59. package/dist/collab/routes.d.ts +1 -1
  60. package/dist/file-upload/builder.d.ts.map +1 -1
  61. package/dist/file-upload/builder.js +137 -25
  62. package/dist/file-upload/builder.js.map +1 -1
  63. package/dist/file-upload/index.d.ts +1 -1
  64. package/dist/file-upload/index.d.ts.map +1 -1
  65. package/dist/file-upload/index.js.map +1 -1
  66. package/dist/file-upload/types.d.ts +26 -0
  67. package/dist/file-upload/types.d.ts.map +1 -1
  68. package/dist/file-upload/types.js.map +1 -1
  69. package/dist/mcp/build-server.d.ts.map +1 -1
  70. package/dist/mcp/build-server.js +31 -4
  71. package/dist/mcp/build-server.js.map +1 -1
  72. package/dist/mcp/embed-app.d.ts.map +1 -1
  73. package/dist/mcp/embed-app.js +33 -18
  74. package/dist/mcp/embed-app.js.map +1 -1
  75. package/dist/notifications/routes.d.ts +3 -3
  76. package/dist/observability/routes.d.ts +3 -3
  77. package/dist/progress/routes.d.ts +1 -1
  78. package/dist/resources/handlers.d.ts +3 -3
  79. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  80. package/dist/server/transcribe-voice.d.ts +1 -1
  81. package/package.json +1 -1
@@ -374,6 +374,8 @@ interface DesignCanvasProps {
374
374
  designTitle?: string;
375
375
  /** Stable id for comment pins, usually scoped to the active screen. */
376
376
  commentContextId?: string;
377
+ /** Stable id of the screen containing this canvas when rendered in overview. */
378
+ screenId?: string;
377
379
  /** Human-readable label for comment-pin prompts. */
378
380
  commentContextLabel?: string;
379
381
  /**
@@ -506,6 +508,7 @@ export function DesignCanvas({
506
508
  designId,
507
509
  designTitle,
508
510
  commentContextId,
511
+ screenId,
509
512
  commentContextLabel,
510
513
  onPrototypeNavigate,
511
514
  motionTracks,
@@ -1098,7 +1101,10 @@ export function DesignCanvas({
1098
1101
  const beginTextEdit = useCallback((nodeId: string) => {
1099
1102
  const iframe = iframeRef.current;
1100
1103
  if (!iframe?.contentWindow || !nodeId) return;
1101
- iframe.contentWindow.postMessage({ type: "begin-text-edit", nodeId }, "*");
1104
+ iframe.contentWindow.postMessage(
1105
+ { type: "begin-text-edit", nodeId, force: true },
1106
+ "*",
1107
+ );
1102
1108
  }, []);
1103
1109
 
1104
1110
  const sendStyleChange = useCallback(
@@ -1342,6 +1348,7 @@ export function DesignCanvas({
1342
1348
  : "allow-scripts allow-popups allow-popups-to-escape-sandbox allow-same-origin"
1343
1349
  }
1344
1350
  data-design-preview-iframe
1351
+ data-screen-iframe-id={screenId ?? undefined}
1345
1352
  data-design-source-type={
1346
1353
  sourceType ??
1347
1354
  (externalPreviewUrl
@@ -1000,7 +1000,11 @@ function LayerRow({
1000
1000
  const hideable = node.hideable !== false && Boolean(onToggleHidden);
1001
1001
  const dragEligible = selectable && !node.locked && !node.hidden;
1002
1002
  const draggable = dragEligible && Boolean(onMoveLayer);
1003
- const canDropInside = layerCanDropInside(node, hasChildren);
1003
+ const canDropInside = layerCanDropInside(
1004
+ node,
1005
+ hasChildren,
1006
+ canAcceptChildren,
1007
+ );
1004
1008
  const activeDrop =
1005
1009
  dropIndicator?.targetId === node.id ? dropIndicator.placement : null;
1006
1010
  // Tracks whether the user pressed Escape to cancel rename so that the
@@ -1868,9 +1872,14 @@ function ElementLayerGlyph({ className }: { className?: string }) {
1868
1872
  );
1869
1873
  }
1870
1874
 
1871
- function layerCanDropInside(node: LayersPanelNode, hasChildren: boolean) {
1875
+ function layerCanDropInside(
1876
+ node: LayersPanelNode,
1877
+ hasChildren: boolean,
1878
+ canAcceptChildren: boolean,
1879
+ ) {
1872
1880
  return (
1873
1881
  hasChildren ||
1882
+ canAcceptChildren ||
1874
1883
  Boolean(node.layout?.isFlexContainer || node.layout?.isGridContainer) ||
1875
1884
  node.type === "file" ||
1876
1885
  node.type === "screen" ||
@@ -3365,15 +3365,26 @@ export function MultiScreenCanvas({
3365
3365
  [flushPendingWheelGesture],
3366
3366
  );
3367
3367
 
3368
- const handleWheelEvent = useCallback(
3369
- (event: WheelEvent) => {
3368
+ const enqueueWheelGestureFromClient = useCallback(
3369
+ (args: {
3370
+ deltaX: number;
3371
+ deltaY: number;
3372
+ deltaMode: number;
3373
+ clientX: number;
3374
+ clientY: number;
3375
+ ctrlKey: boolean;
3376
+ metaKey: boolean;
3377
+ shiftKey: boolean;
3378
+ }) => {
3370
3379
  const rect = surfaceRef.current?.getBoundingClientRect();
3371
3380
  if (!rect) return;
3372
- event.preventDefault();
3373
- event.stopPropagation();
3374
- const delta = getWheelDelta(event);
3381
+ const delta = getWheelDeltaFromValues(
3382
+ args.deltaX,
3383
+ args.deltaY,
3384
+ args.deltaMode,
3385
+ );
3375
3386
 
3376
- if (event.ctrlKey || event.metaKey) {
3387
+ if (args.ctrlKey || args.metaKey) {
3377
3388
  const zoomDeltaY = clamp(
3378
3389
  delta.y,
3379
3390
  -MAX_WHEEL_ZOOM_DELTA,
@@ -3382,20 +3393,23 @@ export function MultiScreenCanvas({
3382
3393
  enqueueWheelGesture({
3383
3394
  mode: "zoom",
3384
3395
  deltaY: zoomDeltaY,
3385
- cursor: { x: event.clientX - rect.left, y: event.clientY - rect.top },
3386
- clientX: event.clientX,
3387
- clientY: event.clientY,
3396
+ cursor: {
3397
+ x: args.clientX - rect.left,
3398
+ y: args.clientY - rect.top,
3399
+ },
3400
+ clientX: args.clientX,
3401
+ clientY: args.clientY,
3388
3402
  });
3389
3403
  return;
3390
3404
  }
3391
3405
 
3392
3406
  const deltaX = clamp(
3393
- event.shiftKey && delta.x === 0 ? delta.y : delta.x,
3407
+ args.shiftKey && delta.x === 0 ? delta.y : delta.x,
3394
3408
  -MAX_WHEEL_PAN_DELTA,
3395
3409
  MAX_WHEEL_PAN_DELTA,
3396
3410
  );
3397
3411
  const deltaY = clamp(
3398
- event.shiftKey && delta.x === 0 ? 0 : delta.y,
3412
+ args.shiftKey && delta.x === 0 ? 0 : delta.y,
3399
3413
  -MAX_WHEEL_PAN_DELTA,
3400
3414
  MAX_WHEEL_PAN_DELTA,
3401
3415
  );
@@ -3404,6 +3418,24 @@ export function MultiScreenCanvas({
3404
3418
  [enqueueWheelGesture],
3405
3419
  );
3406
3420
 
3421
+ const handleWheelEvent = useCallback(
3422
+ (event: WheelEvent) => {
3423
+ event.preventDefault();
3424
+ event.stopPropagation();
3425
+ enqueueWheelGestureFromClient({
3426
+ deltaX: event.deltaX,
3427
+ deltaY: event.deltaY,
3428
+ deltaMode: event.deltaMode,
3429
+ clientX: event.clientX,
3430
+ clientY: event.clientY,
3431
+ ctrlKey: event.ctrlKey,
3432
+ metaKey: event.metaKey,
3433
+ shiftKey: event.shiftKey,
3434
+ });
3435
+ },
3436
+ [enqueueWheelGestureFromClient],
3437
+ );
3438
+
3407
3439
  useEffect(() => {
3408
3440
  const surface = surfaceRef.current;
3409
3441
  if (!surface) return;
@@ -3418,6 +3450,44 @@ export function MultiScreenCanvas({
3418
3450
  };
3419
3451
  }, [handleWheelEvent]);
3420
3452
 
3453
+ useEffect(() => {
3454
+ const handleEmbeddedWheelMessage = (event: MessageEvent) => {
3455
+ if (!event.data || event.data.type !== "embedded-canvas-wheel") return;
3456
+ const surface = surfaceRef.current;
3457
+ if (!surface) return;
3458
+ const sourceIframe = Array.from(
3459
+ surface.querySelectorAll<HTMLIFrameElement>(
3460
+ "iframe[data-design-preview-iframe]",
3461
+ ),
3462
+ ).find((iframe) => iframe.contentWindow === event.source);
3463
+ if (!sourceIframe) return;
3464
+
3465
+ const rect = sourceIframe.getBoundingClientRect();
3466
+ const scaleX =
3467
+ sourceIframe.clientWidth > 0
3468
+ ? rect.width / sourceIframe.clientWidth
3469
+ : 1;
3470
+ const scaleY =
3471
+ sourceIframe.clientHeight > 0
3472
+ ? rect.height / sourceIframe.clientHeight
3473
+ : 1;
3474
+ enqueueWheelGestureFromClient({
3475
+ deltaX: Number(event.data.deltaX) || 0,
3476
+ deltaY: Number(event.data.deltaY) || 0,
3477
+ deltaMode: Number(event.data.deltaMode) || WheelEvent.DOM_DELTA_PIXEL,
3478
+ clientX: rect.left + (Number(event.data.clientX) || 0) * scaleX,
3479
+ clientY: rect.top + (Number(event.data.clientY) || 0) * scaleY,
3480
+ ctrlKey: Boolean(event.data.ctrlKey),
3481
+ metaKey: Boolean(event.data.metaKey),
3482
+ shiftKey: Boolean(event.data.shiftKey),
3483
+ });
3484
+ };
3485
+
3486
+ window.addEventListener("message", handleEmbeddedWheelMessage);
3487
+ return () =>
3488
+ window.removeEventListener("message", handleEmbeddedWheelMessage);
3489
+ }, [enqueueWheelGestureFromClient]);
3490
+
3421
3491
  useEffect(() => {
3422
3492
  const handleKeyDown = (event: KeyboardEvent) => {
3423
3493
  if (activePenPathRef.current) return;
@@ -6060,12 +6130,15 @@ function getSelectableBounds(geometry: FrameGeometry): BoundsRect {
6060
6130
  };
6061
6131
  }
6062
6132
 
6063
- function getWheelDelta(event: WheelEvent) {
6064
- const multiplier =
6065
- event.deltaMode === 1 ? 16 : event.deltaMode === 2 ? 800 : 1;
6133
+ function getWheelDeltaFromValues(
6134
+ deltaX: number,
6135
+ deltaY: number,
6136
+ deltaMode: number,
6137
+ ) {
6138
+ const multiplier = deltaMode === 1 ? 16 : deltaMode === 2 ? 800 : 1;
6066
6139
  return {
6067
- x: event.deltaX * multiplier,
6068
- y: event.deltaY * multiplier,
6140
+ x: deltaX * multiplier,
6141
+ y: deltaY * multiplier,
6069
6142
  };
6070
6143
  }
6071
6144
 
@@ -3468,17 +3468,20 @@ declare var __EDITOR_CHROME_SCALE_Y__: string;
3468
3468
  }
3469
3469
  }
3470
3470
 
3471
- function beginTextEditingFromEvent(e) {
3471
+ function beginTextEditingFromEvent(e, forceTextEditing) {
3472
3472
  if (activeTextEditEl && e.target && activeTextEditEl.contains(e.target))
3473
3473
  return;
3474
- if (!textEditingEnabled) {
3474
+ if (!textEditingEnabled && !forceTextEditing) {
3475
3475
  stopNativeInteraction(e);
3476
3476
  return;
3477
3477
  }
3478
3478
  stopNativeInteraction(e);
3479
- var target = findTextEditTarget(
3480
- elementFromEditorPoint(e.clientX, e.clientY),
3481
- );
3479
+ var eventTarget =
3480
+ e && e.target && e.target.nodeType === 1 ? e.target : null;
3481
+ var target =
3482
+ findTextEditTarget(elementFromEditorPoint(e.clientX, e.clientY)) ||
3483
+ findTextEditTarget(eventTarget) ||
3484
+ eventTarget;
3482
3485
  if (!target || target.nodeType !== 1) return;
3483
3486
  // Anchor the selection identity to the nearest source-backed element. Text
3484
3487
  // editing still operates on the actual target text node, but a later
@@ -3725,7 +3728,8 @@ declare var __EDITOR_CHROME_SCALE_Y__: string;
3725
3728
  // text-element creation so the user can type right away and the autosize
3726
3729
  // CSS (width:max-content or similar) takes effect from the first keystroke.
3727
3730
  if (e.data.type === "begin-text-edit") {
3728
- if (readOnly || !textEditingEnabled) return;
3731
+ var forceBeginTextEdit = e.data.force === true;
3732
+ if ((readOnly || !textEditingEnabled) && !forceBeginTextEdit) return;
3729
3733
  var nodeId: string =
3730
3734
  typeof e.data.nodeId === "string" ? e.data.nodeId : "";
3731
3735
  if (!nodeId) return;
@@ -3749,14 +3753,17 @@ declare var __EDITOR_CHROME_SCALE_Y__: string;
3749
3753
  var bteCenterY = bteRect.top + bteRect.height / 2;
3750
3754
  // Delegate to the canonical path so all state, events, and postMessages
3751
3755
  // stay consistent with a normal double-click text edit.
3752
- beginTextEditingFromEvent({
3753
- clientX: bteCenterX,
3754
- clientY: bteCenterY,
3755
- target: textTarget,
3756
- preventDefault: function () {},
3757
- stopPropagation: function () {},
3758
- stopImmediatePropagation: function () {},
3759
- } as unknown as MouseEvent);
3756
+ beginTextEditingFromEvent(
3757
+ {
3758
+ clientX: bteCenterX,
3759
+ clientY: bteCenterY,
3760
+ target: textTarget,
3761
+ preventDefault: function () {},
3762
+ stopPropagation: function () {},
3763
+ stopImmediatePropagation: function () {},
3764
+ } as unknown as MouseEvent,
3765
+ forceBeginTextEdit,
3766
+ );
3760
3767
  return;
3761
3768
  }
3762
3769
  if (e.data.type === "set-editor-chrome-scale") {