@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.
- package/corpus/README.md +1 -1
- package/corpus/templates/analytics/CHANGELOG.md +17 -0
- package/corpus/templates/assets/CHANGELOG.md +18 -0
- package/corpus/templates/brain/CHANGELOG.md +6 -0
- package/corpus/templates/calendar/CHANGELOG.md +4 -0
- package/corpus/templates/clips/CHANGELOG.md +19 -0
- package/corpus/templates/clips/actions/create-recording-agent-link.ts +8 -2
- package/corpus/templates/clips/actions/update-recording.ts +5 -1
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +10 -3
- package/corpus/templates/clips/changelog/2026-09-28-agent-links-stay-valid-when-clip-details-change.md +6 -0
- package/corpus/templates/clips/changelog/2026-09-28-password-changes-immediately-invalidate-old-recording-links.md +6 -0
- package/corpus/templates/clips/changelog/2026-09-28-password-protected-recording-links-stop-working-when-the-pas.md +6 -0
- package/corpus/templates/clips/server/db/schema.ts +3 -0
- package/corpus/templates/clips/server/lib/player-video-url.ts +9 -1
- package/corpus/templates/clips/server/lib/public-agent-context.ts +12 -4
- package/corpus/templates/clips/server/lib/share-password.ts +25 -0
- package/corpus/templates/clips/server/plugins/db.ts +36 -0
- package/corpus/templates/clips/server/routes/[...page].get.ts +8 -1
- package/corpus/templates/clips/server/routes/api/public-recording.get.ts +33 -6
- package/corpus/templates/clips/server/routes/api/thumbnail/[recordingId].get.ts +34 -6
- package/corpus/templates/clips/server/routes/api/video/[recordingId].get.ts +26 -5
- package/corpus/templates/content/CHANGELOG.md +1 -0
- package/corpus/templates/crm/CHANGELOG.md +12 -0
- package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +265 -3
- package/corpus/templates/design/CHANGELOG.md +21 -0
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +463 -6
- package/corpus/templates/design/app/pages/Index.tsx +1 -1
- package/corpus/templates/design/changelog/2026-09-27-auto-focused-app-fields-no-longer-interrupt-canvas-shortcuts.md +6 -0
- package/corpus/templates/design/changelog/2026-09-28-model-picker-loads-available-models.md +6 -0
- package/corpus/templates/design/changelog/2026-09-28-template-menus-stay-available-on-hover.md +6 -0
- package/corpus/templates/dispatch/CHANGELOG.md +18 -0
- package/corpus/templates/forms/CHANGELOG.md +6 -0
- package/corpus/templates/mail/.env.example +1 -1
- package/corpus/templates/mail/CHANGELOG.md +33 -0
- package/corpus/templates/mail/changelog/2026-09-28-fixed-inbox-loading-stalls-and-showed-progress-during-google-2.md +6 -0
- package/corpus/templates/mail/changelog/2026-09-28-fixed-inbox-loading-stalls-and-showed-progress-during-google.md +6 -0
- package/corpus/templates/mail/server/db/schema.ts +7 -0
- package/corpus/templates/mail/server/lib/ai-filter-backfill.ts +4 -0
- package/corpus/templates/mail/server/lib/jobs.ts +5 -2
- package/corpus/templates/mail/server/plugins/db.ts +16 -0
- package/corpus/templates/mail/server/plugins/mail-jobs.ts +355 -44
- package/corpus/templates/slides/CHANGELOG.md +28 -0
- package/corpus/templates/slides/app/pages/Index.tsx +1 -1
- package/corpus/templates/slides/changelog/2026-09-28-model-picker-loads-available-models.md +6 -0
- package/corpus/templates/slides/changelog/2026-09-28-template-menus-stay-available-on-hover.md +6 -0
- package/dist/automation/index.d.ts +1 -1
- package/dist/client/auth/AuthPage.js +3 -2
- package/dist/client/org/OrgSwitcher.js +31 -19
- package/dist/client/settings/UsageSection.js +3 -3
- package/dist/client/use-action.js +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/routes.d.ts +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +2 -2
- package/dist/jobs/background-automation-runner.d.ts +2 -0
- package/dist/jobs/background-automation-runner.js +20 -1
- package/dist/jobs/sweep-hooks.d.ts +6 -2
- package/dist/jobs/sweep-hooks.js +17 -9
- package/dist/localization/core-messages/ar-SA.js +2 -2
- package/dist/localization/core-messages/de-DE.js +2 -2
- package/dist/localization/core-messages/en-US.d.ts +2 -2
- package/dist/localization/core-messages/en-US.js +2 -2
- package/dist/localization/core-messages/es-ES.js +2 -2
- package/dist/localization/core-messages/fr-FR.js +2 -2
- package/dist/localization/core-messages/hi-IN.js +2 -2
- package/dist/localization/core-messages/ja-JP.js +2 -2
- package/dist/localization/core-messages/ko-KR.js +2 -2
- package/dist/localization/core-messages/pt-BR.js +2 -2
- package/dist/localization/core-messages/zh-CN.js +2 -2
- package/dist/localization/core-messages/zh-TW.js +2 -2
- package/dist/localization/core-messages.d.ts +2 -2
- package/dist/notifications/routes.d.ts +5 -5
- package/dist/observability/routes.d.ts +6 -6
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +11 -11
- package/dist/provider-api/actions/provider-api.d.ts +7 -7
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/secrets/routes.d.ts +4 -4
- package/dist/server/agent-chat-plugin.js +6 -2
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/agent-engine-default-model-route.d.ts +1 -1
- package/dist/server/agent-engine-ollama-models-route.d.ts +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/triggers/dispatcher.js +167 -36
- package/dist/triggers/event-queue.d.ts +18 -1
- package/dist/triggers/event-queue.js +143 -10
- package/package.json +4 -4
|
@@ -104,9 +104,15 @@ declare var __INITIAL_SOURCE_HEAD__: string;
|
|
|
104
104
|
var userFocusedElement: Element | null = null;
|
|
105
105
|
var trustedFocusIntent: {
|
|
106
106
|
target: Element | null;
|
|
107
|
-
kind: "pointer" | "tab" | "activation";
|
|
107
|
+
kind: "pointer" | "tab" | "activation" | "navigation";
|
|
108
|
+
key?: string;
|
|
109
|
+
rovingGroup?: Element | null;
|
|
110
|
+
activeDescendantBefore?: string | null;
|
|
111
|
+
tabIndexesBefore?: Array<{ element: Element; value: string | null }>;
|
|
108
112
|
expiresAt: number;
|
|
109
113
|
} | null = null;
|
|
114
|
+
var rovingGroupSelector =
|
|
115
|
+
'[role="grid"], [role="listbox"], [role="menu"], [role="menubar"], [role="radiogroup"], [role="tablist"], [role="toolbar"], [role="tree"], [role="treegrid"]';
|
|
110
116
|
var focusTargetSelector =
|
|
111
117
|
'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"]';
|
|
112
118
|
|
|
@@ -134,23 +140,472 @@ declare var __INITIAL_SOURCE_HEAD__: string;
|
|
|
134
140
|
|
|
135
141
|
function armTrustedFocusIntent(
|
|
136
142
|
target: Element | null,
|
|
137
|
-
kind: "pointer" | "tab" | "activation",
|
|
143
|
+
kind: "pointer" | "tab" | "activation" | "navigation",
|
|
144
|
+
key?: string,
|
|
138
145
|
): void {
|
|
146
|
+
var rovingGroup =
|
|
147
|
+
kind === "navigation" && target
|
|
148
|
+
? target.closest(rovingGroupSelector)
|
|
149
|
+
: null;
|
|
139
150
|
trustedFocusIntent = {
|
|
140
151
|
target: target,
|
|
141
152
|
kind: kind,
|
|
153
|
+
...(key ? { key: key } : {}),
|
|
154
|
+
...(rovingGroup
|
|
155
|
+
? {
|
|
156
|
+
rovingGroup: rovingGroup,
|
|
157
|
+
activeDescendantBefore: rovingGroup.getAttribute(
|
|
158
|
+
"aria-activedescendant",
|
|
159
|
+
),
|
|
160
|
+
tabIndexesBefore: Array.from(
|
|
161
|
+
rovingGroup.querySelectorAll("[tabindex]"),
|
|
162
|
+
).map(function (element) {
|
|
163
|
+
return {
|
|
164
|
+
element: element,
|
|
165
|
+
value: element.getAttribute("tabindex"),
|
|
166
|
+
};
|
|
167
|
+
}),
|
|
168
|
+
}
|
|
169
|
+
: {}),
|
|
142
170
|
expiresAt: Date.now() + 1000,
|
|
143
171
|
};
|
|
144
172
|
}
|
|
145
173
|
|
|
174
|
+
function clearNavigationFocusIntentAfterAppTasks(): void {
|
|
175
|
+
var navigationIntent = trustedFocusIntent;
|
|
176
|
+
// Let app key handlers enqueue their roving-focus task before clearing intent.
|
|
177
|
+
window.setTimeout(function () {
|
|
178
|
+
window.setTimeout(function () {
|
|
179
|
+
if (trustedFocusIntent === navigationIntent) {
|
|
180
|
+
trustedFocusIntent = null;
|
|
181
|
+
}
|
|
182
|
+
}, 0);
|
|
183
|
+
}, 0);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function isRovingFocusSibling(
|
|
187
|
+
current: Element | null,
|
|
188
|
+
next: Element,
|
|
189
|
+
key: string | undefined,
|
|
190
|
+
intent: {
|
|
191
|
+
rovingGroup?: Element | null;
|
|
192
|
+
activeDescendantBefore?: string | null;
|
|
193
|
+
tabIndexesBefore?: Array<{ element: Element; value: string | null }>;
|
|
194
|
+
},
|
|
195
|
+
): boolean {
|
|
196
|
+
if (!current) return false;
|
|
197
|
+
|
|
198
|
+
function isNativeRadio(element: Element): element is HTMLInputElement {
|
|
199
|
+
return (
|
|
200
|
+
element.tagName === "INPUT" &&
|
|
201
|
+
(element as HTMLInputElement).type === "radio"
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (isNativeRadio(current) && isNativeRadio(next)) {
|
|
206
|
+
var radioName = current.name;
|
|
207
|
+
var radioForm = current.form || current.closest("form");
|
|
208
|
+
var radios = Array.from(
|
|
209
|
+
(current.getRootNode() as ParentNode).querySelectorAll(
|
|
210
|
+
'input[type="radio"]',
|
|
211
|
+
),
|
|
212
|
+
).filter(function (candidate) {
|
|
213
|
+
var radio = candidate as HTMLInputElement;
|
|
214
|
+
return (
|
|
215
|
+
radioName !== "" &&
|
|
216
|
+
radio.name === radioName &&
|
|
217
|
+
(radio.form || radio.closest("form")) === radioForm
|
|
218
|
+
);
|
|
219
|
+
});
|
|
220
|
+
var currentRadioIndex = radios.indexOf(current);
|
|
221
|
+
var nextRadioIndex = radios.indexOf(next);
|
|
222
|
+
var delta =
|
|
223
|
+
key === "ArrowRight" || key === "ArrowDown"
|
|
224
|
+
? 1
|
|
225
|
+
: key === "ArrowLeft" || key === "ArrowUp"
|
|
226
|
+
? -1
|
|
227
|
+
: 0;
|
|
228
|
+
if (key === "ArrowLeft" || key === "ArrowRight") {
|
|
229
|
+
if (window.getComputedStyle(current).direction === "rtl") {
|
|
230
|
+
delta *= -1;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
if (
|
|
234
|
+
radios.length > 1 &&
|
|
235
|
+
currentRadioIndex !== -1 &&
|
|
236
|
+
nextRadioIndex !== -1 &&
|
|
237
|
+
delta !== 0
|
|
238
|
+
) {
|
|
239
|
+
return (
|
|
240
|
+
nextRadioIndex ===
|
|
241
|
+
(currentRadioIndex + delta + radios.length) % radios.length
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
var currentGroup = current.closest(rovingGroupSelector);
|
|
247
|
+
if (
|
|
248
|
+
!currentGroup ||
|
|
249
|
+
currentGroup !== next.closest(rovingGroupSelector) ||
|
|
250
|
+
intent.rovingGroup !== currentGroup
|
|
251
|
+
) {
|
|
252
|
+
return false;
|
|
253
|
+
}
|
|
254
|
+
var role = currentGroup.getAttribute("role");
|
|
255
|
+
var itemSelector: string | null = null;
|
|
256
|
+
switch (role) {
|
|
257
|
+
case "grid":
|
|
258
|
+
case "treegrid":
|
|
259
|
+
itemSelector =
|
|
260
|
+
'[role="row"], [role="gridcell"], [role="columnheader"], [role="rowheader"], tr, td, th';
|
|
261
|
+
break;
|
|
262
|
+
case "listbox":
|
|
263
|
+
itemSelector = '[role="option"]';
|
|
264
|
+
break;
|
|
265
|
+
case "menu":
|
|
266
|
+
case "menubar":
|
|
267
|
+
itemSelector =
|
|
268
|
+
'[role="menuitem"], [role="menuitemcheckbox"], [role="menuitemradio"]';
|
|
269
|
+
break;
|
|
270
|
+
case "radiogroup":
|
|
271
|
+
itemSelector = '[role="radio"], input[type="radio"]';
|
|
272
|
+
break;
|
|
273
|
+
case "tablist":
|
|
274
|
+
itemSelector = '[role="tab"]';
|
|
275
|
+
break;
|
|
276
|
+
case "toolbar":
|
|
277
|
+
itemSelector = 'button, a[href], [role="button"], [role="link"]';
|
|
278
|
+
break;
|
|
279
|
+
case "tree":
|
|
280
|
+
itemSelector = '[role="treeitem"]';
|
|
281
|
+
break;
|
|
282
|
+
}
|
|
283
|
+
if (!itemSelector) return false;
|
|
284
|
+
var currentItem = current.closest(itemSelector);
|
|
285
|
+
var nextItem = next.closest(itemSelector);
|
|
286
|
+
if (!currentItem || !nextItem || currentItem === nextItem) return false;
|
|
287
|
+
|
|
288
|
+
function belongsToGroup(item: Element): boolean {
|
|
289
|
+
if (item.closest(rovingGroupSelector) !== currentGroup) return false;
|
|
290
|
+
if (item.getAttribute("role")) return true;
|
|
291
|
+
if (
|
|
292
|
+
item.tagName !== "TR" &&
|
|
293
|
+
item.tagName !== "TD" &&
|
|
294
|
+
item.tagName !== "TH"
|
|
295
|
+
) {
|
|
296
|
+
return true;
|
|
297
|
+
}
|
|
298
|
+
return (
|
|
299
|
+
item.closest('table[role="grid"], table[role="treegrid"]') ===
|
|
300
|
+
currentGroup
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function isGridRow(item: Element): boolean {
|
|
305
|
+
return (
|
|
306
|
+
item.getAttribute("role") === "row" ||
|
|
307
|
+
(item.tagName === "TR" && belongsToGroup(item))
|
|
308
|
+
);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function gridRows(): Element[] {
|
|
312
|
+
return Array.from(
|
|
313
|
+
currentGroup.querySelectorAll('[role="row"], tr'),
|
|
314
|
+
).filter(function (row) {
|
|
315
|
+
return belongsToGroup(row) && isGridRow(row);
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
function gridCells(row: Element): Element[] {
|
|
320
|
+
return Array.from(
|
|
321
|
+
row.querySelectorAll(
|
|
322
|
+
'[role="gridcell"], [role="columnheader"], [role="rowheader"], td, th',
|
|
323
|
+
),
|
|
324
|
+
).filter(function (cell) {
|
|
325
|
+
if (!belongsToGroup(cell)) return false;
|
|
326
|
+
if (cell.getAttribute("role")) {
|
|
327
|
+
return cell.closest('[role="row"]') === row;
|
|
328
|
+
}
|
|
329
|
+
if (cell.tagName === "TD" || cell.tagName === "TH") {
|
|
330
|
+
return (
|
|
331
|
+
cell.closest("tr") === row &&
|
|
332
|
+
cell.closest('table[role="grid"], table[role="treegrid"]') ===
|
|
333
|
+
currentGroup
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
return cell.closest('[role="row"]') === row;
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
function ariaIndex(
|
|
341
|
+
element: Element,
|
|
342
|
+
name: string,
|
|
343
|
+
fallback: number,
|
|
344
|
+
): number {
|
|
345
|
+
var value = Number(element.getAttribute(name));
|
|
346
|
+
return Number.isInteger(value) && value > 0 ? value - 1 : fallback;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
function hasRovingFocusTransition(
|
|
350
|
+
currentRovingItem: Element,
|
|
351
|
+
nextRovingItem: Element,
|
|
352
|
+
): boolean {
|
|
353
|
+
var activeDescendant = currentGroup.getAttribute("aria-activedescendant");
|
|
354
|
+
var previousActiveDescendant = intent.activeDescendantBefore || null;
|
|
355
|
+
if (
|
|
356
|
+
activeDescendant &&
|
|
357
|
+
activeDescendant !== previousActiveDescendant &&
|
|
358
|
+
(activeDescendant === (nextRovingItem as HTMLElement).id ||
|
|
359
|
+
activeDescendant === (next as HTMLElement).id)
|
|
360
|
+
) {
|
|
361
|
+
return true;
|
|
362
|
+
}
|
|
363
|
+
var previousTabIndex = intent.tabIndexesBefore?.find(function (entry) {
|
|
364
|
+
return entry.element === currentRovingItem;
|
|
365
|
+
});
|
|
366
|
+
var nextTabIndex = intent.tabIndexesBefore?.find(function (entry) {
|
|
367
|
+
return entry.element === nextRovingItem;
|
|
368
|
+
});
|
|
369
|
+
if (
|
|
370
|
+
previousTabIndex?.value === "0" &&
|
|
371
|
+
currentRovingItem.getAttribute("tabindex") !== "0" &&
|
|
372
|
+
nextTabIndex !== undefined &&
|
|
373
|
+
nextTabIndex.value !== "0" &&
|
|
374
|
+
nextRovingItem.getAttribute("tabindex") === "0"
|
|
375
|
+
) {
|
|
376
|
+
return true;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
function isGridCell(item: Element): boolean {
|
|
380
|
+
return (
|
|
381
|
+
item.getAttribute("role") === "gridcell" ||
|
|
382
|
+
item.getAttribute("role") === "columnheader" ||
|
|
383
|
+
item.getAttribute("role") === "rowheader" ||
|
|
384
|
+
item.tagName === "TD" ||
|
|
385
|
+
item.tagName === "TH"
|
|
386
|
+
);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
return (
|
|
390
|
+
(role === "grid" || role === "treegrid") &&
|
|
391
|
+
isGridCell(currentRovingItem) &&
|
|
392
|
+
isGridCell(nextRovingItem) &&
|
|
393
|
+
current !== currentRovingItem &&
|
|
394
|
+
next !== nextRovingItem &&
|
|
395
|
+
current.matches(focusTargetSelector) &&
|
|
396
|
+
next.matches(focusTargetSelector)
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
if (role === "grid" || role === "treegrid") {
|
|
401
|
+
var currentRow = currentItem.closest('[role="row"], tr');
|
|
402
|
+
var nextRow = nextItem.closest('[role="row"], tr');
|
|
403
|
+
if (
|
|
404
|
+
!currentRow ||
|
|
405
|
+
!nextRow ||
|
|
406
|
+
!belongsToGroup(currentRow) ||
|
|
407
|
+
!belongsToGroup(nextRow)
|
|
408
|
+
) {
|
|
409
|
+
return false;
|
|
410
|
+
}
|
|
411
|
+
var rows = gridRows();
|
|
412
|
+
var currentRowIndex = ariaIndex(
|
|
413
|
+
currentRow,
|
|
414
|
+
"aria-rowindex",
|
|
415
|
+
rows.indexOf(currentRow),
|
|
416
|
+
);
|
|
417
|
+
var nextRowIndex = ariaIndex(
|
|
418
|
+
nextRow,
|
|
419
|
+
"aria-rowindex",
|
|
420
|
+
rows.indexOf(nextRow),
|
|
421
|
+
);
|
|
422
|
+
var verticalDelta = key === "ArrowDown" ? 1 : key === "ArrowUp" ? -1 : 0;
|
|
423
|
+
if (isGridRow(currentItem) && isGridRow(nextItem)) {
|
|
424
|
+
return (
|
|
425
|
+
verticalDelta !== 0 &&
|
|
426
|
+
nextRowIndex === currentRowIndex + verticalDelta &&
|
|
427
|
+
hasRovingFocusTransition(currentItem, nextItem)
|
|
428
|
+
);
|
|
429
|
+
}
|
|
430
|
+
if (isGridRow(currentItem) || isGridRow(nextItem)) {
|
|
431
|
+
if (role !== "treegrid" || currentRow !== nextRow) return false;
|
|
432
|
+
var currentIsRow = isGridRow(currentItem);
|
|
433
|
+
var cells = gridCells(currentRow);
|
|
434
|
+
if (currentIsRow && key === "ArrowRight") {
|
|
435
|
+
return (
|
|
436
|
+
cells[0] === nextItem &&
|
|
437
|
+
hasRovingFocusTransition(currentItem, nextItem)
|
|
438
|
+
);
|
|
439
|
+
}
|
|
440
|
+
if (!currentIsRow && key === "ArrowLeft") {
|
|
441
|
+
return (
|
|
442
|
+
cells[0] === currentItem &&
|
|
443
|
+
hasRovingFocusTransition(currentItem, nextItem)
|
|
444
|
+
);
|
|
445
|
+
}
|
|
446
|
+
return false;
|
|
447
|
+
}
|
|
448
|
+
var currentColumnIndex = ariaIndex(
|
|
449
|
+
currentItem,
|
|
450
|
+
"aria-colindex",
|
|
451
|
+
gridCells(currentRow).indexOf(currentItem),
|
|
452
|
+
);
|
|
453
|
+
var nextColumnIndex = ariaIndex(
|
|
454
|
+
nextItem,
|
|
455
|
+
"aria-colindex",
|
|
456
|
+
gridCells(nextRow).indexOf(nextItem),
|
|
457
|
+
);
|
|
458
|
+
if (key === "ArrowLeft" || key === "ArrowRight") {
|
|
459
|
+
var columnDelta = key === "ArrowRight" ? 1 : -1;
|
|
460
|
+
if (window.getComputedStyle(currentGroup).direction === "rtl") {
|
|
461
|
+
columnDelta *= -1;
|
|
462
|
+
}
|
|
463
|
+
return (
|
|
464
|
+
currentRow === nextRow &&
|
|
465
|
+
nextColumnIndex === currentColumnIndex + columnDelta &&
|
|
466
|
+
hasRovingFocusTransition(currentItem, nextItem)
|
|
467
|
+
);
|
|
468
|
+
}
|
|
469
|
+
return (
|
|
470
|
+
verticalDelta !== 0 &&
|
|
471
|
+
nextRowIndex === currentRowIndex + verticalDelta &&
|
|
472
|
+
nextColumnIndex === currentColumnIndex &&
|
|
473
|
+
hasRovingFocusTransition(currentItem, nextItem)
|
|
474
|
+
);
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
function itemFor(target: Element): Element | null {
|
|
478
|
+
if (role === "tree") return target.closest('[role="treeitem"]');
|
|
479
|
+
return target.closest(itemSelector!);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
function isNavigableTreeItem(item: Element): boolean {
|
|
483
|
+
var currentItem: Element | null = item;
|
|
484
|
+
while (currentItem && currentItem !== currentGroup) {
|
|
485
|
+
if (
|
|
486
|
+
currentItem.getAttribute("hidden") !== null ||
|
|
487
|
+
currentItem.getAttribute("inert") !== null ||
|
|
488
|
+
currentItem.getAttribute("aria-hidden") === "true"
|
|
489
|
+
) {
|
|
490
|
+
return false;
|
|
491
|
+
}
|
|
492
|
+
if (
|
|
493
|
+
currentItem !== item &&
|
|
494
|
+
currentItem.getAttribute("role") === "treeitem" &&
|
|
495
|
+
currentItem.getAttribute("aria-expanded") === "false"
|
|
496
|
+
) {
|
|
497
|
+
return false;
|
|
498
|
+
}
|
|
499
|
+
currentItem = currentItem.parentElement;
|
|
500
|
+
}
|
|
501
|
+
return true;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
var currentRovingItem = itemFor(current);
|
|
505
|
+
var nextRovingItem = itemFor(next);
|
|
506
|
+
if (
|
|
507
|
+
!currentRovingItem ||
|
|
508
|
+
!nextRovingItem ||
|
|
509
|
+
!belongsToGroup(currentRovingItem) ||
|
|
510
|
+
!belongsToGroup(nextRovingItem)
|
|
511
|
+
) {
|
|
512
|
+
return false;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
var isRtl = window.getComputedStyle(currentGroup).direction === "rtl";
|
|
516
|
+
var childKey = isRtl ? "ArrowLeft" : "ArrowRight";
|
|
517
|
+
var parentKey = isRtl ? "ArrowRight" : "ArrowLeft";
|
|
518
|
+
if (role === "tree" && key === childKey) {
|
|
519
|
+
return (
|
|
520
|
+
isNavigableTreeItem(currentRovingItem) &&
|
|
521
|
+
isNavigableTreeItem(nextRovingItem) &&
|
|
522
|
+
nextRovingItem.parentElement?.closest('[role="treeitem"]') ===
|
|
523
|
+
currentRovingItem &&
|
|
524
|
+
hasRovingFocusTransition(currentRovingItem, nextRovingItem)
|
|
525
|
+
);
|
|
526
|
+
}
|
|
527
|
+
if (role === "tree" && key === parentKey) {
|
|
528
|
+
return (
|
|
529
|
+
isNavigableTreeItem(currentRovingItem) &&
|
|
530
|
+
isNavigableTreeItem(nextRovingItem) &&
|
|
531
|
+
currentRovingItem.parentElement?.closest('[role="treeitem"]') ===
|
|
532
|
+
nextRovingItem &&
|
|
533
|
+
hasRovingFocusTransition(currentRovingItem, nextRovingItem)
|
|
534
|
+
);
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
var items = Array.from(currentGroup.querySelectorAll(itemSelector)).filter(
|
|
538
|
+
function (item) {
|
|
539
|
+
return (
|
|
540
|
+
belongsToGroup(item) &&
|
|
541
|
+
itemFor(item) === item &&
|
|
542
|
+
(role !== "tree" || isNavigableTreeItem(item))
|
|
543
|
+
);
|
|
544
|
+
},
|
|
545
|
+
);
|
|
546
|
+
var currentIndex = items.indexOf(currentRovingItem);
|
|
547
|
+
var nextIndex = items.indexOf(nextRovingItem);
|
|
548
|
+
if (currentIndex === -1 || nextIndex === -1) return false;
|
|
549
|
+
|
|
550
|
+
var orientation = currentGroup.getAttribute("aria-orientation");
|
|
551
|
+
if (!orientation) {
|
|
552
|
+
orientation =
|
|
553
|
+
role === "toolbar" ||
|
|
554
|
+
role === "menubar" ||
|
|
555
|
+
role === "tablist" ||
|
|
556
|
+
role === "radiogroup"
|
|
557
|
+
? "horizontal"
|
|
558
|
+
: "vertical";
|
|
559
|
+
}
|
|
560
|
+
var delta =
|
|
561
|
+
key === "ArrowRight"
|
|
562
|
+
? 1
|
|
563
|
+
: key === "ArrowLeft"
|
|
564
|
+
? -1
|
|
565
|
+
: key === "ArrowDown"
|
|
566
|
+
? 1
|
|
567
|
+
: key === "ArrowUp"
|
|
568
|
+
? -1
|
|
569
|
+
: 0;
|
|
570
|
+
if (!delta) return false;
|
|
571
|
+
if (orientation === "horizontal") {
|
|
572
|
+
if (key !== "ArrowLeft" && key !== "ArrowRight") return false;
|
|
573
|
+
if (window.getComputedStyle(currentGroup).direction === "rtl")
|
|
574
|
+
delta *= -1;
|
|
575
|
+
} else if (key !== "ArrowUp" && key !== "ArrowDown") {
|
|
576
|
+
return false;
|
|
577
|
+
}
|
|
578
|
+
var expectedIndex = currentIndex + delta;
|
|
579
|
+
if (
|
|
580
|
+
role === "radiogroup" ||
|
|
581
|
+
role === "tablist" ||
|
|
582
|
+
role === "menu" ||
|
|
583
|
+
role === "menubar" ||
|
|
584
|
+
role === "toolbar"
|
|
585
|
+
) {
|
|
586
|
+
expectedIndex = (expectedIndex + items.length) % items.length;
|
|
587
|
+
}
|
|
588
|
+
return (
|
|
589
|
+
nextIndex === expectedIndex &&
|
|
590
|
+
hasRovingFocusTransition(currentRovingItem, nextRovingItem)
|
|
591
|
+
);
|
|
592
|
+
}
|
|
593
|
+
|
|
146
594
|
function rememberUserFocusedElement(event: FocusEvent): void {
|
|
147
595
|
var intent = trustedFocusIntent;
|
|
148
596
|
var target = getCanvasFocusTarget(event);
|
|
597
|
+
var navigationTargetMatches =
|
|
598
|
+
intent?.kind !== "navigation" ||
|
|
599
|
+
target === intent.target ||
|
|
600
|
+
(target !== null &&
|
|
601
|
+
isRovingFocusSibling(intent.target, target, intent.key, intent));
|
|
149
602
|
if (
|
|
150
603
|
!intent ||
|
|
151
604
|
Date.now() > intent.expiresAt ||
|
|
152
605
|
!target ||
|
|
153
|
-
|
|
606
|
+
!navigationTargetMatches ||
|
|
607
|
+
(intent.kind !== "tab" &&
|
|
608
|
+
intent.kind !== "navigation" &&
|
|
154
609
|
(intent.target === null ||
|
|
155
610
|
(intent.target !== target &&
|
|
156
611
|
!event.composedPath().includes(intent.target) &&
|
|
@@ -213,11 +668,13 @@ declare var __INITIAL_SOURCE_HEAD__: string;
|
|
|
213
668
|
var active = document.activeElement;
|
|
214
669
|
if (active instanceof Element && isCanvasFocusTarget(active)) {
|
|
215
670
|
userFocusedElement = active;
|
|
216
|
-
if (
|
|
671
|
+
if (keyEvent.key.startsWith("Arrow")) {
|
|
672
|
+
armTrustedFocusIntent(active, "navigation", keyEvent.key);
|
|
673
|
+
clearNavigationFocusIntentAfterAppTasks();
|
|
674
|
+
} else if (
|
|
217
675
|
keyEvent.key === "Enter" ||
|
|
218
676
|
keyEvent.key === " " ||
|
|
219
|
-
keyEvent.key === "Escape"
|
|
220
|
-
keyEvent.key.startsWith("Arrow")
|
|
677
|
+
keyEvent.key === "Escape"
|
|
221
678
|
) {
|
|
222
679
|
armTrustedFocusIntent(active, "activation");
|
|
223
680
|
}
|
|
@@ -1108,7 +1108,7 @@ export default function Index() {
|
|
|
1108
1108
|
disabled={!agentEngineConfigured}
|
|
1109
1109
|
submissionDisabled={!agentEngineConfigured}
|
|
1110
1110
|
showModelSelector={agentEngineConfigured}
|
|
1111
|
-
modelStatusChecksEnabled={
|
|
1111
|
+
modelStatusChecksEnabled={agentEngineConfigured}
|
|
1112
1112
|
title={t("home.newDesignLower")}
|
|
1113
1113
|
draftScope="design:new:0"
|
|
1114
1114
|
placeholder={
|
|
@@ -3,6 +3,24 @@
|
|
|
3
3
|
All notable user-facing changes to Agent-Native Dispatch are documented here. Open it any
|
|
4
4
|
time from the command menu (Cmd+K → "What's new").
|
|
5
5
|
|
|
6
|
+
## 2026-09-28
|
|
7
|
+
|
|
8
|
+
### Fixed
|
|
9
|
+
|
|
10
|
+
- Desktop sign-in now carries over to Mail and other eligible apps.
|
|
11
|
+
|
|
12
|
+
## 2026-09-27
|
|
13
|
+
|
|
14
|
+
### Improved
|
|
15
|
+
|
|
16
|
+
- Workspace connection changes now show clear confirmations in chat.
|
|
17
|
+
|
|
18
|
+
## 2026-09-25
|
|
19
|
+
|
|
20
|
+
### Improved
|
|
21
|
+
|
|
22
|
+
- Dispatch settings now live on Dispatch › General (Chat-first workspace, Resources, and Connect apps), and Members keeps the Dispatch access column.
|
|
23
|
+
|
|
6
24
|
## 2026-09-23
|
|
7
25
|
|
|
8
26
|
### Fixed
|
|
@@ -3,6 +3,12 @@
|
|
|
3
3
|
All notable user-facing changes to Agent-Native Forms are documented here. Open it any
|
|
4
4
|
time from the command menu (Cmd+K → "What's new").
|
|
5
5
|
|
|
6
|
+
## 2026-09-27
|
|
7
|
+
|
|
8
|
+
### Improved
|
|
9
|
+
|
|
10
|
+
- Forms keeps newly added follow-up questions and actionable response signals visible in chat.
|
|
11
|
+
|
|
6
12
|
## 2026-09-15
|
|
7
13
|
|
|
8
14
|
### Fixed
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
# GMAIL_WATCH_TOPIC=projects/<project>/topics/<topic>
|
|
19
19
|
# GMAIL_PUSH_AUDIENCE=https://<your-domain>/api/gmail/push
|
|
20
20
|
# GMAIL_PUSH_SIGNER_EMAIL=<pubsub-signer>@<project>.iam.gserviceaccount.com
|
|
21
|
-
# GMAIL_WATCH_RENEW_AUDIENCE=https://<your-domain>/api/gmail/renew
|
|
21
|
+
# GMAIL_WATCH_RENEW_AUDIENCE=https://<your-domain>/api/gmail/watch/renew
|
|
22
22
|
|
|
23
23
|
# Inbound email webhooks (Resend / SendGrid)
|
|
24
24
|
# REQUIRED in prod when inbound email is enabled — webhooks fail-closed without it
|
|
@@ -3,16 +3,46 @@
|
|
|
3
3
|
All notable user-facing changes to Agent-Native Mail are documented here. Open it any
|
|
4
4
|
time from the command menu (Cmd+K → "What's new") or from Settings.
|
|
5
5
|
|
|
6
|
+
## 2026-09-28
|
|
7
|
+
|
|
8
|
+
### Improved
|
|
9
|
+
|
|
10
|
+
- Builder credit notices appear above sidebar actions in a full-width layout.
|
|
11
|
+
- Mail automation rules use a consistent neutral color treatment.
|
|
12
|
+
- Open the current agent conversation in a full-page view
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- Avoid automatic retries after Gmail quota cooldowns
|
|
17
|
+
|
|
6
18
|
## 2026-09-27
|
|
7
19
|
|
|
20
|
+
### Added
|
|
21
|
+
|
|
22
|
+
- Mail can mark prompt-matched messages Important and show browser notifications while Mail is open; mobile app notifications are coming soon.
|
|
23
|
+
|
|
8
24
|
### Improved
|
|
9
25
|
|
|
26
|
+
- AI triage links open the relevant rule group.
|
|
27
|
+
- Inbox Priority shows each email's score with quick feedback and rule settings.
|
|
28
|
+
- Mail rule changes in chat now link to the matching Settings section
|
|
29
|
+
- Updated drafts now include a review link in chat
|
|
10
30
|
- Add AI inbox triage to Mail's first-run onboarding.
|
|
11
31
|
- Scheduled-send cards show the subject and local send time
|
|
12
32
|
- Successful draft, filter, and inbox rule changes now appear as concise action cards in chat.
|
|
13
33
|
|
|
14
34
|
### Fixed
|
|
15
35
|
|
|
36
|
+
- Failed queued draft sends now report an error instead of appearing successful.
|
|
37
|
+
- Gmail cooldown messages now show when to try again.
|
|
38
|
+
- Inbox sorting recovers automatically when background processing is interrupted
|
|
39
|
+
- Mail resumes inbox organization after temporary Gmail limits
|
|
40
|
+
- Mail retries inbox rules after temporary Google token refresh failures
|
|
41
|
+
- Mail setup stays visible while triage availability loads
|
|
42
|
+
- Mail setup waits for first-run onboarding, and empty importance prompts require an explicit skip.
|
|
43
|
+
- Inbox tabs are visible on mobile, and the full toolbar scrolls together horizontally.
|
|
44
|
+
- Triage examples stay placeholders until you choose them
|
|
45
|
+
- Undo resumes safely after an interrupted mail restore
|
|
16
46
|
- Fixed the inbox crash when the sidebar is pinned
|
|
17
47
|
- Inbox navigation stays in a hamburger drawer, and filter tabs use available toolbar space before scrolling.
|
|
18
48
|
- Inbox sorting finishes reliably across larger mailboxes
|
|
@@ -32,6 +62,7 @@ time from the command menu (Cmd+K → "What's new") or from Settings.
|
|
|
32
62
|
|
|
33
63
|
### Fixed
|
|
34
64
|
|
|
65
|
+
- Removing a member from your organization now completes instead of failing with a pending cleanup error
|
|
35
66
|
- Chat-created inbox rules appear immediately while recent mail is processed in the background.
|
|
36
67
|
- Chat-created Mail rules save and queue recent-mail processing before background model checks run.
|
|
37
68
|
- Fixed AI rule setup progress and chat updates
|
|
@@ -51,6 +82,8 @@ time from the command menu (Cmd+K → "What's new") or from Settings.
|
|
|
51
82
|
|
|
52
83
|
### Improved
|
|
53
84
|
|
|
85
|
+
- Mail settings now live in tabs on Mail > General (Drafting, Snippets, Rules, AI filter, Gmail filters, Aliases, Tracking), and Slack draft requests sit on Channels > Slack.
|
|
86
|
+
- Settings now opens from your name at the bottom of the sidebar, or with ⌘,.
|
|
54
87
|
- Mail now guides users to connect Jev before setting up triage and lets them remove existing rules if Jev becomes unavailable.
|
|
55
88
|
- Tune inbox priorities with Jev, label messages clearly, and teach importance with feedback.
|
|
56
89
|
|
|
@@ -166,6 +166,13 @@ export const mailSyncAccounts = table(
|
|
|
166
166
|
.default(0),
|
|
167
167
|
syncClaimId: text("sync_claim_id"),
|
|
168
168
|
syncClaimedAt: integer("sync_claimed_at"),
|
|
169
|
+
lastWatchRenewedAt: bigint("last_watch_renewed_at", { mode: "number" }),
|
|
170
|
+
lastWatchAttemptedAt: bigint("last_watch_attempted_at", { mode: "number" }),
|
|
171
|
+
lastAutomationAttemptedAt: bigint("last_automation_attempted_at", {
|
|
172
|
+
mode: "number",
|
|
173
|
+
}),
|
|
174
|
+
watchRenewClaimId: text("watch_renew_claim_id"),
|
|
175
|
+
watchRenewClaimedAt: bigint("watch_renew_claimed_at", { mode: "number" }),
|
|
169
176
|
labelsJson: text("labels_json"),
|
|
170
177
|
labelsUpdatedAt: integer("labels_updated_at"),
|
|
171
178
|
createdAt: integer("created_at").notNull(),
|