@agent-native/core 0.196.0-nightly-20260928172902 → 0.196.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 (86) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/CHANGELOG.md +17 -0
  3. package/corpus/templates/assets/CHANGELOG.md +18 -0
  4. package/corpus/templates/brain/CHANGELOG.md +6 -0
  5. package/corpus/templates/calendar/CHANGELOG.md +4 -0
  6. package/corpus/templates/clips/CHANGELOG.md +19 -0
  7. package/corpus/templates/clips/actions/create-recording-agent-link.ts +8 -2
  8. package/corpus/templates/clips/actions/update-recording.ts +5 -1
  9. package/corpus/templates/clips/app/routes/share.$shareId.tsx +10 -3
  10. package/corpus/templates/clips/changelog/2026-09-28-agent-links-stay-valid-when-clip-details-change.md +6 -0
  11. package/corpus/templates/clips/changelog/2026-09-28-password-changes-immediately-invalidate-old-recording-links.md +6 -0
  12. package/corpus/templates/clips/changelog/2026-09-28-password-protected-recording-links-stop-working-when-the-pas.md +6 -0
  13. package/corpus/templates/clips/server/db/schema.ts +3 -0
  14. package/corpus/templates/clips/server/lib/player-video-url.ts +9 -1
  15. package/corpus/templates/clips/server/lib/public-agent-context.ts +12 -4
  16. package/corpus/templates/clips/server/lib/share-password.ts +25 -0
  17. package/corpus/templates/clips/server/plugins/db.ts +36 -0
  18. package/corpus/templates/clips/server/routes/[...page].get.ts +8 -1
  19. package/corpus/templates/clips/server/routes/api/public-recording.get.ts +33 -6
  20. package/corpus/templates/clips/server/routes/api/thumbnail/[recordingId].get.ts +34 -6
  21. package/corpus/templates/clips/server/routes/api/video/[recordingId].get.ts +26 -5
  22. package/corpus/templates/content/CHANGELOG.md +1 -0
  23. package/corpus/templates/crm/CHANGELOG.md +12 -0
  24. package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +265 -3
  25. package/corpus/templates/design/CHANGELOG.md +21 -0
  26. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +463 -6
  27. package/corpus/templates/design/app/pages/Index.tsx +1 -1
  28. package/corpus/templates/design/changelog/2026-09-27-auto-focused-app-fields-no-longer-interrupt-canvas-shortcuts.md +6 -0
  29. package/corpus/templates/design/changelog/2026-09-28-model-picker-loads-available-models.md +6 -0
  30. package/corpus/templates/design/changelog/2026-09-28-template-menus-stay-available-on-hover.md +6 -0
  31. package/corpus/templates/dispatch/CHANGELOG.md +18 -0
  32. package/corpus/templates/forms/CHANGELOG.md +6 -0
  33. package/corpus/templates/mail/.env.example +1 -1
  34. package/corpus/templates/mail/CHANGELOG.md +33 -0
  35. package/corpus/templates/mail/changelog/2026-09-28-fixed-inbox-loading-stalls-and-showed-progress-during-google-2.md +6 -0
  36. package/corpus/templates/mail/changelog/2026-09-28-fixed-inbox-loading-stalls-and-showed-progress-during-google.md +6 -0
  37. package/corpus/templates/mail/server/db/schema.ts +7 -0
  38. package/corpus/templates/mail/server/lib/ai-filter-backfill.ts +4 -0
  39. package/corpus/templates/mail/server/lib/jobs.ts +5 -2
  40. package/corpus/templates/mail/server/plugins/db.ts +16 -0
  41. package/corpus/templates/mail/server/plugins/mail-jobs.ts +355 -44
  42. package/corpus/templates/slides/CHANGELOG.md +28 -0
  43. package/corpus/templates/slides/app/pages/Index.tsx +1 -1
  44. package/corpus/templates/slides/changelog/2026-09-28-model-picker-loads-available-models.md +6 -0
  45. package/corpus/templates/slides/changelog/2026-09-28-template-menus-stay-available-on-hover.md +6 -0
  46. package/dist/automation/index.d.ts +1 -1
  47. package/dist/client/auth/AuthPage.js +3 -2
  48. package/dist/client/org/OrgSwitcher.js +31 -19
  49. package/dist/client/settings/UsageSection.js +3 -3
  50. package/dist/client/use-action.js +1 -1
  51. package/dist/collab/awareness.d.ts +2 -2
  52. package/dist/collab/routes.d.ts +1 -1
  53. package/dist/file-upload/actions/upload-image.d.ts +2 -2
  54. package/dist/jobs/background-automation-runner.d.ts +2 -0
  55. package/dist/jobs/background-automation-runner.js +20 -1
  56. package/dist/jobs/sweep-hooks.d.ts +6 -2
  57. package/dist/jobs/sweep-hooks.js +17 -9
  58. package/dist/localization/core-messages/ar-SA.js +2 -2
  59. package/dist/localization/core-messages/de-DE.js +2 -2
  60. package/dist/localization/core-messages/en-US.d.ts +2 -2
  61. package/dist/localization/core-messages/en-US.js +2 -2
  62. package/dist/localization/core-messages/es-ES.js +2 -2
  63. package/dist/localization/core-messages/fr-FR.js +2 -2
  64. package/dist/localization/core-messages/hi-IN.js +2 -2
  65. package/dist/localization/core-messages/ja-JP.js +2 -2
  66. package/dist/localization/core-messages/ko-KR.js +2 -2
  67. package/dist/localization/core-messages/pt-BR.js +2 -2
  68. package/dist/localization/core-messages/zh-CN.js +2 -2
  69. package/dist/localization/core-messages/zh-TW.js +2 -2
  70. package/dist/localization/core-messages.d.ts +2 -2
  71. package/dist/notifications/routes.d.ts +5 -5
  72. package/dist/observability/routes.d.ts +6 -6
  73. package/dist/progress/routes.d.ts +1 -1
  74. package/dist/provider-api/actions/custom-provider-registration.d.ts +11 -11
  75. package/dist/provider-api/actions/provider-api.d.ts +7 -7
  76. package/dist/resources/handlers.d.ts +1 -1
  77. package/dist/secrets/routes.d.ts +4 -4
  78. package/dist/server/agent-chat-plugin.js +6 -2
  79. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  80. package/dist/server/agent-engine-default-model-route.d.ts +1 -1
  81. package/dist/server/agent-engine-ollama-models-route.d.ts +1 -1
  82. package/dist/server/index.d.ts +1 -1
  83. package/dist/triggers/dispatcher.js +167 -36
  84. package/dist/triggers/event-queue.d.ts +18 -1
  85. package/dist/triggers/event-queue.js +143 -10
  86. package/package.json +4 -4
@@ -72,7 +72,10 @@ import {
72
72
  import { isRecordingExpiredForViewer } from "../../../lib/recording-page-access.js";
73
73
  import { getOrganizationRoleForEmail } from "../../../lib/recordings.js";
74
74
  import { fetchS3ObjectByUrl } from "../../../lib/s3-upload-provider.js";
75
- import { verifySharePassword } from "../../../lib/share-password.js";
75
+ import {
76
+ getRecordingAccessTokenResourceId,
77
+ verifySharePassword,
78
+ } from "../../../lib/share-password.js";
76
79
 
77
80
  interface RecordingRow {
78
81
  editsJson?: string | null;
@@ -80,6 +83,8 @@ interface RecordingRow {
80
83
  organizationId?: string | null;
81
84
  ownerEmail?: string | null;
82
85
  password?: string | null;
86
+ sharePasswordVersion?: string | null;
87
+ updatedAt?: string | null;
83
88
  sourceAppName?: string | null;
84
89
  sourceWindowTitle?: string | null;
85
90
  videoUrl?: string | null;
@@ -130,9 +135,15 @@ function isHttpsRequest(event: H3Event): boolean {
130
135
  function setProtectedMediaAccessCookie(
131
136
  event: H3Event,
132
137
  recordingId: string,
138
+ password: string | null | undefined,
139
+ sharePasswordVersion: string | null | undefined,
133
140
  ): void {
134
141
  const token = signShortLivedToken({
135
- resourceId: recordingId,
142
+ resourceId: getRecordingAccessTokenResourceId(
143
+ recordingId,
144
+ password,
145
+ sharePasswordVersion,
146
+ ),
136
147
  ttlSeconds: PROTECTED_MEDIA_ACCESS_TTL_SECONDS,
137
148
  });
138
149
  const secure = isHttpsRequest(event);
@@ -389,12 +400,17 @@ export default defineEventHandler(async (event: H3Event) => {
389
400
  const supplied = typeof q.password === "string" ? q.password : "";
390
401
 
391
402
  let allowed = false;
403
+ const scopedRecordingId = getRecordingAccessTokenResourceId(
404
+ recordingId,
405
+ rec.password,
406
+ rec.sharePasswordVersion,
407
+ );
392
408
  if (token) {
393
- const result = verifyShortLivedToken(token, recordingId);
409
+ const result = verifyShortLivedToken(token, scopedRecordingId);
394
410
  if (result.ok) allowed = true;
395
411
  }
396
412
  if (!allowed && cookieToken) {
397
- const result = verifyShortLivedToken(cookieToken, recordingId);
413
+ const result = verifyShortLivedToken(cookieToken, scopedRecordingId);
398
414
  if (result.ok) allowed = true;
399
415
  }
400
416
  if (
@@ -408,7 +424,12 @@ export default defineEventHandler(async (event: H3Event) => {
408
424
  setResponseStatus(event, 401);
409
425
  return { error: "Password required", passwordRequired: true };
410
426
  }
411
- setProtectedMediaAccessCookie(event, recordingId);
427
+ setProtectedMediaAccessCookie(
428
+ event,
429
+ recordingId,
430
+ rec.password,
431
+ rec.sharePasswordVersion,
432
+ );
412
433
  }
413
434
 
414
435
  if (isLoomEmbedBackedRecording(rec)) {
@@ -13,6 +13,7 @@ time from the command menu (Cmd+K → "What's new").
13
13
 
14
14
  ### Added
15
15
 
16
+ - Ask the agent to turn comment, reply, and mention emails on or off.
16
17
  - Chat messages can be reverted to their autosaved version, including a shortcut to restore the start of a chat.
17
18
 
18
19
  ### Improved
@@ -1,5 +1,17 @@
1
1
  # CRM changelog
2
2
 
3
+ ## 2026-09-28
4
+
5
+ ### Improved
6
+
7
+ - Ask CRM now starts with a focused title.
8
+
9
+ ## 2026-09-27
10
+
11
+ ### Fixed
12
+
13
+ - Custom CRM field labels and settings stay unchanged when records update
14
+
3
15
  ## 2026-08-11
4
16
 
5
17
  ### Improved
@@ -945,6 +945,7 @@ export const editorChromeBridgeScript: string = `"use strict";
945
945
  var repairingEditorChromeHost = false;
946
946
  var userFocusedElement = null;
947
947
  var trustedFocusIntent = null;
948
+ var rovingGroupSelector = '[role="grid"], [role="listbox"], [role="menu"], [role="menubar"], [role="radiogroup"], [role="tablist"], [role="toolbar"], [role="tree"], [role="treegrid"]';
948
949
  var focusTargetSelector = 'a[href], area[href], button, input:not([type="hidden"]), select, textarea, summary, iframe, audio[controls], video[controls], [tabindex], [contenteditable]:not([contenteditable="false"]), [role="button"], [role="link"], [role="switch"], [role="checkbox"], [role="radio"], [role="slider"], [role="spinbutton"], [role="menuitem"], [role="textbox"], [role="combobox"], [role="searchbox"]';
949
950
  function isCanvasFocusTarget(target) {
950
951
  return !!(target && (isEditorTypingTarget(target) || target.matches(focusTargetSelector)));
@@ -963,17 +964,275 @@ export const editorChromeBridgeScript: string = `"use strict";
963
964
  }
964
965
  return null;
965
966
  }
966
- function armTrustedFocusIntent(target, kind) {
967
+ function armTrustedFocusIntent(target, kind, key) {
968
+ var rovingGroup = kind === "navigation" && target ? target.closest(rovingGroupSelector) : null;
967
969
  trustedFocusIntent = {
968
970
  target,
969
971
  kind,
972
+ ...key ? { key } : {},
973
+ ...rovingGroup ? {
974
+ rovingGroup,
975
+ activeDescendantBefore: rovingGroup.getAttribute(
976
+ "aria-activedescendant"
977
+ ),
978
+ tabIndexesBefore: Array.from(
979
+ rovingGroup.querySelectorAll("[tabindex]")
980
+ ).map(function(element) {
981
+ return {
982
+ element,
983
+ value: element.getAttribute("tabindex")
984
+ };
985
+ })
986
+ } : {},
970
987
  expiresAt: Date.now() + 1e3
971
988
  };
972
989
  }
990
+ function clearNavigationFocusIntentAfterAppTasks() {
991
+ var navigationIntent = trustedFocusIntent;
992
+ window.setTimeout(function() {
993
+ window.setTimeout(function() {
994
+ if (trustedFocusIntent === navigationIntent) {
995
+ trustedFocusIntent = null;
996
+ }
997
+ }, 0);
998
+ }, 0);
999
+ }
1000
+ function isRovingFocusSibling(current, next, key, intent) {
1001
+ if (!current) return false;
1002
+ function isNativeRadio(element) {
1003
+ return element.tagName === "INPUT" && element.type === "radio";
1004
+ }
1005
+ if (isNativeRadio(current) && isNativeRadio(next)) {
1006
+ var radioName = current.name;
1007
+ var radioForm = current.form || current.closest("form");
1008
+ var radios = Array.from(
1009
+ current.getRootNode().querySelectorAll(
1010
+ 'input[type="radio"]'
1011
+ )
1012
+ ).filter(function(candidate) {
1013
+ var radio = candidate;
1014
+ return radioName !== "" && radio.name === radioName && (radio.form || radio.closest("form")) === radioForm;
1015
+ });
1016
+ var currentRadioIndex = radios.indexOf(current);
1017
+ var nextRadioIndex = radios.indexOf(next);
1018
+ var delta = key === "ArrowRight" || key === "ArrowDown" ? 1 : key === "ArrowLeft" || key === "ArrowUp" ? -1 : 0;
1019
+ if (key === "ArrowLeft" || key === "ArrowRight") {
1020
+ if (window.getComputedStyle(current).direction === "rtl") {
1021
+ delta *= -1;
1022
+ }
1023
+ }
1024
+ if (radios.length > 1 && currentRadioIndex !== -1 && nextRadioIndex !== -1 && delta !== 0) {
1025
+ return nextRadioIndex === (currentRadioIndex + delta + radios.length) % radios.length;
1026
+ }
1027
+ }
1028
+ var currentGroup = current.closest(rovingGroupSelector);
1029
+ if (!currentGroup || currentGroup !== next.closest(rovingGroupSelector) || intent.rovingGroup !== currentGroup) {
1030
+ return false;
1031
+ }
1032
+ var role = currentGroup.getAttribute("role");
1033
+ var itemSelector = null;
1034
+ switch (role) {
1035
+ case "grid":
1036
+ case "treegrid":
1037
+ itemSelector = '[role="row"], [role="gridcell"], [role="columnheader"], [role="rowheader"], tr, td, th';
1038
+ break;
1039
+ case "listbox":
1040
+ itemSelector = '[role="option"]';
1041
+ break;
1042
+ case "menu":
1043
+ case "menubar":
1044
+ itemSelector = '[role="menuitem"], [role="menuitemcheckbox"], [role="menuitemradio"]';
1045
+ break;
1046
+ case "radiogroup":
1047
+ itemSelector = '[role="radio"], input[type="radio"]';
1048
+ break;
1049
+ case "tablist":
1050
+ itemSelector = '[role="tab"]';
1051
+ break;
1052
+ case "toolbar":
1053
+ itemSelector = 'button, a[href], [role="button"], [role="link"]';
1054
+ break;
1055
+ case "tree":
1056
+ itemSelector = '[role="treeitem"]';
1057
+ break;
1058
+ }
1059
+ if (!itemSelector) return false;
1060
+ var currentItem = current.closest(itemSelector);
1061
+ var nextItem = next.closest(itemSelector);
1062
+ if (!currentItem || !nextItem || currentItem === nextItem) return false;
1063
+ function belongsToGroup(item) {
1064
+ if (item.closest(rovingGroupSelector) !== currentGroup) return false;
1065
+ if (item.getAttribute("role")) return true;
1066
+ if (item.tagName !== "TR" && item.tagName !== "TD" && item.tagName !== "TH") {
1067
+ return true;
1068
+ }
1069
+ return item.closest('table[role="grid"], table[role="treegrid"]') === currentGroup;
1070
+ }
1071
+ function isGridRow(item) {
1072
+ return item.getAttribute("role") === "row" || item.tagName === "TR" && belongsToGroup(item);
1073
+ }
1074
+ function gridRows() {
1075
+ return Array.from(
1076
+ currentGroup.querySelectorAll('[role="row"], tr')
1077
+ ).filter(function(row) {
1078
+ return belongsToGroup(row) && isGridRow(row);
1079
+ });
1080
+ }
1081
+ function gridCells(row) {
1082
+ return Array.from(
1083
+ row.querySelectorAll(
1084
+ '[role="gridcell"], [role="columnheader"], [role="rowheader"], td, th'
1085
+ )
1086
+ ).filter(function(cell) {
1087
+ if (!belongsToGroup(cell)) return false;
1088
+ if (cell.getAttribute("role")) {
1089
+ return cell.closest('[role="row"]') === row;
1090
+ }
1091
+ if (cell.tagName === "TD" || cell.tagName === "TH") {
1092
+ return cell.closest("tr") === row && cell.closest('table[role="grid"], table[role="treegrid"]') === currentGroup;
1093
+ }
1094
+ return cell.closest('[role="row"]') === row;
1095
+ });
1096
+ }
1097
+ function ariaIndex(element, name, fallback) {
1098
+ var value = Number(element.getAttribute(name));
1099
+ return Number.isInteger(value) && value > 0 ? value - 1 : fallback;
1100
+ }
1101
+ function hasRovingFocusTransition(currentRovingItem2, nextRovingItem2) {
1102
+ var activeDescendant = currentGroup.getAttribute("aria-activedescendant");
1103
+ var previousActiveDescendant = intent.activeDescendantBefore || null;
1104
+ if (activeDescendant && activeDescendant !== previousActiveDescendant && (activeDescendant === nextRovingItem2.id || activeDescendant === next.id)) {
1105
+ return true;
1106
+ }
1107
+ var previousTabIndex = intent.tabIndexesBefore?.find(function(entry) {
1108
+ return entry.element === currentRovingItem2;
1109
+ });
1110
+ var nextTabIndex = intent.tabIndexesBefore?.find(function(entry) {
1111
+ return entry.element === nextRovingItem2;
1112
+ });
1113
+ if (previousTabIndex?.value === "0" && currentRovingItem2.getAttribute("tabindex") !== "0" && nextTabIndex !== void 0 && nextTabIndex.value !== "0" && nextRovingItem2.getAttribute("tabindex") === "0") {
1114
+ return true;
1115
+ }
1116
+ function isGridCell(item) {
1117
+ return item.getAttribute("role") === "gridcell" || item.getAttribute("role") === "columnheader" || item.getAttribute("role") === "rowheader" || item.tagName === "TD" || item.tagName === "TH";
1118
+ }
1119
+ return (role === "grid" || role === "treegrid") && isGridCell(currentRovingItem2) && isGridCell(nextRovingItem2) && current !== currentRovingItem2 && next !== nextRovingItem2 && current.matches(focusTargetSelector) && next.matches(focusTargetSelector);
1120
+ }
1121
+ if (role === "grid" || role === "treegrid") {
1122
+ var currentRow = currentItem.closest('[role="row"], tr');
1123
+ var nextRow = nextItem.closest('[role="row"], tr');
1124
+ if (!currentRow || !nextRow || !belongsToGroup(currentRow) || !belongsToGroup(nextRow)) {
1125
+ return false;
1126
+ }
1127
+ var rows = gridRows();
1128
+ var currentRowIndex = ariaIndex(
1129
+ currentRow,
1130
+ "aria-rowindex",
1131
+ rows.indexOf(currentRow)
1132
+ );
1133
+ var nextRowIndex = ariaIndex(
1134
+ nextRow,
1135
+ "aria-rowindex",
1136
+ rows.indexOf(nextRow)
1137
+ );
1138
+ var verticalDelta = key === "ArrowDown" ? 1 : key === "ArrowUp" ? -1 : 0;
1139
+ if (isGridRow(currentItem) && isGridRow(nextItem)) {
1140
+ return verticalDelta !== 0 && nextRowIndex === currentRowIndex + verticalDelta && hasRovingFocusTransition(currentItem, nextItem);
1141
+ }
1142
+ if (isGridRow(currentItem) || isGridRow(nextItem)) {
1143
+ if (role !== "treegrid" || currentRow !== nextRow) return false;
1144
+ var currentIsRow = isGridRow(currentItem);
1145
+ var cells = gridCells(currentRow);
1146
+ if (currentIsRow && key === "ArrowRight") {
1147
+ return cells[0] === nextItem && hasRovingFocusTransition(currentItem, nextItem);
1148
+ }
1149
+ if (!currentIsRow && key === "ArrowLeft") {
1150
+ return cells[0] === currentItem && hasRovingFocusTransition(currentItem, nextItem);
1151
+ }
1152
+ return false;
1153
+ }
1154
+ var currentColumnIndex = ariaIndex(
1155
+ currentItem,
1156
+ "aria-colindex",
1157
+ gridCells(currentRow).indexOf(currentItem)
1158
+ );
1159
+ var nextColumnIndex = ariaIndex(
1160
+ nextItem,
1161
+ "aria-colindex",
1162
+ gridCells(nextRow).indexOf(nextItem)
1163
+ );
1164
+ if (key === "ArrowLeft" || key === "ArrowRight") {
1165
+ var columnDelta = key === "ArrowRight" ? 1 : -1;
1166
+ if (window.getComputedStyle(currentGroup).direction === "rtl") {
1167
+ columnDelta *= -1;
1168
+ }
1169
+ return currentRow === nextRow && nextColumnIndex === currentColumnIndex + columnDelta && hasRovingFocusTransition(currentItem, nextItem);
1170
+ }
1171
+ return verticalDelta !== 0 && nextRowIndex === currentRowIndex + verticalDelta && nextColumnIndex === currentColumnIndex && hasRovingFocusTransition(currentItem, nextItem);
1172
+ }
1173
+ function itemFor(target) {
1174
+ if (role === "tree") return target.closest('[role="treeitem"]');
1175
+ return target.closest(itemSelector);
1176
+ }
1177
+ function isNavigableTreeItem(item) {
1178
+ var currentItem2 = item;
1179
+ while (currentItem2 && currentItem2 !== currentGroup) {
1180
+ if (currentItem2.getAttribute("hidden") !== null || currentItem2.getAttribute("inert") !== null || currentItem2.getAttribute("aria-hidden") === "true") {
1181
+ return false;
1182
+ }
1183
+ if (currentItem2 !== item && currentItem2.getAttribute("role") === "treeitem" && currentItem2.getAttribute("aria-expanded") === "false") {
1184
+ return false;
1185
+ }
1186
+ currentItem2 = currentItem2.parentElement;
1187
+ }
1188
+ return true;
1189
+ }
1190
+ var currentRovingItem = itemFor(current);
1191
+ var nextRovingItem = itemFor(next);
1192
+ if (!currentRovingItem || !nextRovingItem || !belongsToGroup(currentRovingItem) || !belongsToGroup(nextRovingItem)) {
1193
+ return false;
1194
+ }
1195
+ var isRtl = window.getComputedStyle(currentGroup).direction === "rtl";
1196
+ var childKey = isRtl ? "ArrowLeft" : "ArrowRight";
1197
+ var parentKey = isRtl ? "ArrowRight" : "ArrowLeft";
1198
+ if (role === "tree" && key === childKey) {
1199
+ return isNavigableTreeItem(currentRovingItem) && isNavigableTreeItem(nextRovingItem) && nextRovingItem.parentElement?.closest('[role="treeitem"]') === currentRovingItem && hasRovingFocusTransition(currentRovingItem, nextRovingItem);
1200
+ }
1201
+ if (role === "tree" && key === parentKey) {
1202
+ return isNavigableTreeItem(currentRovingItem) && isNavigableTreeItem(nextRovingItem) && currentRovingItem.parentElement?.closest('[role="treeitem"]') === nextRovingItem && hasRovingFocusTransition(currentRovingItem, nextRovingItem);
1203
+ }
1204
+ var items = Array.from(currentGroup.querySelectorAll(itemSelector)).filter(
1205
+ function(item) {
1206
+ return belongsToGroup(item) && itemFor(item) === item && (role !== "tree" || isNavigableTreeItem(item));
1207
+ }
1208
+ );
1209
+ var currentIndex = items.indexOf(currentRovingItem);
1210
+ var nextIndex = items.indexOf(nextRovingItem);
1211
+ if (currentIndex === -1 || nextIndex === -1) return false;
1212
+ var orientation = currentGroup.getAttribute("aria-orientation");
1213
+ if (!orientation) {
1214
+ orientation = role === "toolbar" || role === "menubar" || role === "tablist" || role === "radiogroup" ? "horizontal" : "vertical";
1215
+ }
1216
+ var delta = key === "ArrowRight" ? 1 : key === "ArrowLeft" ? -1 : key === "ArrowDown" ? 1 : key === "ArrowUp" ? -1 : 0;
1217
+ if (!delta) return false;
1218
+ if (orientation === "horizontal") {
1219
+ if (key !== "ArrowLeft" && key !== "ArrowRight") return false;
1220
+ if (window.getComputedStyle(currentGroup).direction === "rtl")
1221
+ delta *= -1;
1222
+ } else if (key !== "ArrowUp" && key !== "ArrowDown") {
1223
+ return false;
1224
+ }
1225
+ var expectedIndex = currentIndex + delta;
1226
+ if (role === "radiogroup" || role === "tablist" || role === "menu" || role === "menubar" || role === "toolbar") {
1227
+ expectedIndex = (expectedIndex + items.length) % items.length;
1228
+ }
1229
+ return nextIndex === expectedIndex && hasRovingFocusTransition(currentRovingItem, nextRovingItem);
1230
+ }
973
1231
  function rememberUserFocusedElement(event) {
974
1232
  var intent = trustedFocusIntent;
975
1233
  var target = getCanvasFocusTarget(event);
976
- if (!intent || Date.now() > intent.expiresAt || !target || intent.kind === "pointer" && (intent.target === null || intent.target !== target && !event.composedPath().includes(intent.target) && !intent.target.contains(target) && !target.contains(intent.target))) {
1234
+ var navigationTargetMatches = intent?.kind !== "navigation" || target === intent.target || target !== null && isRovingFocusSibling(intent.target, target, intent.key, intent);
1235
+ if (!intent || Date.now() > intent.expiresAt || !target || !navigationTargetMatches || intent.kind !== "tab" && intent.kind !== "navigation" && (intent.target === null || intent.target !== target && !event.composedPath().includes(intent.target) && !intent.target.contains(target) && !target.contains(intent.target))) {
977
1236
  trustedFocusIntent = null;
978
1237
  userFocusedElement = null;
979
1238
  return;
@@ -1024,7 +1283,10 @@ export const editorChromeBridgeScript: string = `"use strict";
1024
1283
  var active = document.activeElement;
1025
1284
  if (active instanceof Element && isCanvasFocusTarget(active)) {
1026
1285
  userFocusedElement = active;
1027
- if (keyEvent.key === "Enter" || keyEvent.key === " " || keyEvent.key === "Escape" || keyEvent.key.startsWith("Arrow")) {
1286
+ if (keyEvent.key.startsWith("Arrow")) {
1287
+ armTrustedFocusIntent(active, "navigation", keyEvent.key);
1288
+ clearNavigationFocusIntentAfterAppTasks();
1289
+ } else if (keyEvent.key === "Enter" || keyEvent.key === " " || keyEvent.key === "Escape") {
1028
1290
  armTrustedFocusIntent(active, "activation");
1029
1291
  }
1030
1292
  }
@@ -3,15 +3,33 @@
3
3
  All notable user-facing changes to Design are documented here. Open it any time
4
4
  from the command menu (Cmd+K → "What's new") or from Settings.
5
5
 
6
+ ## 2026-09-28
7
+
8
+ ### Improved
9
+
10
+ - Starter prompts now sit below the chat composer
11
+ - The design list search and import controls stay legible on narrow screens.
12
+
13
+ ### Fixed
14
+
15
+ - Canvas navigation and undo keep working when connected apps focus controls automatically
16
+ - The model picker shows available models when AI is configured.
17
+ - Template menus stay available when you hover over a card.
18
+
6
19
  ## 2026-09-27
7
20
 
8
21
  ### Improved
9
22
 
23
+ - Chrome local editing guidance uses sharper permission screenshots and a neutral backdrop
24
+ - Local access setup shows Chrome permission screenshots and confirms before closing
10
25
  - The Connect AI setup card now has even spacing above and below the composer.
11
26
  - Chrome local access guidance clarifies how to approve live editing
12
27
 
13
28
  ### Fixed
14
29
 
30
+ - Auto-focused app fields no longer interrupt canvas shortcuts while editing live screens
31
+ - Fix deeply nested drag-and-drop placement on Design canvases
32
+ - Personalized home suggestions work when responses include extra text
15
33
  - Canvas shortcuts keep working when a connected app focuses an input.
16
34
  - Drops into plain frames now stack above existing content, while auto-layout keeps the chosen insertion position.
17
35
  - Layers dragged out of a frame now stay above the frame.
@@ -37,6 +55,7 @@ from the command menu (Cmd+K → "What's new") or from Settings.
37
55
 
38
56
  ### Fixed
39
57
 
58
+ - Opening a shared visual editor now completes its initial setup and hands visual edits back to your coding agent.
40
59
  - Live previews keep canvas keyboard shortcuts available when app fields autofocus
41
60
  - API key settings recover when loading stalls.
42
61
  - Cmd+D copies avoid existing screens while reserving simultaneous duplicates.
@@ -66,6 +85,8 @@ from the command menu (Cmd+K → "What's new") or from Settings.
66
85
 
67
86
  ### Improved
68
87
 
88
+ - In the new Settings, Agent Observability is a page in the Design group for owners and admins, and the MCP server page says what a connected app can do in Design.
89
+ - Settings now opens from your name at the bottom of the sidebar, or with ⌘,.
69
90
  - Design shows how to connect file storage before uploading media or fonts
70
91
  - Attach Figma frames and websites from focused dialogs while keeping prompt drafts and uploaded design.md files intact.
71
92
  - Recent designs now use the same consistent library card layout as templates.