@agent-native/core 0.183.0-nightly-20260921181954 → 0.183.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 (29) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/calendar/CHANGELOG.md +6 -0
  3. package/corpus/templates/clips/CHANGELOG.md +59 -0
  4. package/corpus/templates/design/CHANGELOG.md +92 -0
  5. package/corpus/templates/design/app/components/design/EditPanel.tsx +10 -1
  6. package/corpus/templates/design/app/components/design/edit-panel/typography-properties.tsx +82 -22
  7. package/corpus/templates/design/app/lib/font-upload.ts +90 -0
  8. package/corpus/templates/design/app/pages/design-editor/code-layer-state.ts +61 -9
  9. package/corpus/templates/design/changelog/2026-09-21-design-includes-more-google-fonts-and-supports-custom-font-u.md +6 -0
  10. package/corpus/templates/design/server/handlers/fonts.ts +171 -0
  11. package/corpus/templates/design/server/routes/api/fonts.post.ts +1 -0
  12. package/corpus/templates/mail/CHANGELOG.md +13 -0
  13. package/corpus/templates/slides/CHANGELOG.md +38 -0
  14. package/corpus/templates/slides/app/components/editor/SlideContextToolbar.tsx +5 -1
  15. package/dist/automation/index.d.ts +1 -1
  16. package/dist/client/org/TeamPage.js +1 -1
  17. package/dist/client/settings/SecretsSection.js +1 -1
  18. package/dist/client/settings/SettingsPanel.js +1 -1
  19. package/dist/collab/awareness.d.ts +2 -2
  20. package/dist/collab/routes.d.ts +1 -1
  21. package/dist/collab/struct-routes.d.ts +1 -1
  22. package/dist/file-upload/actions/upload-image.d.ts +2 -2
  23. package/dist/observability/routes.d.ts +4 -4
  24. package/dist/org/handlers.d.ts +1 -1
  25. package/dist/resources/handlers.d.ts +1 -1
  26. package/dist/server/agent-engine-api-key-route.d.ts +2 -2
  27. package/dist/server/core-routes-plugin.d.ts +1 -1
  28. package/dist/server/realtime-token.d.ts +1 -1
  29. package/package.json +4 -4
package/corpus/README.md CHANGED
@@ -31,4 +31,4 @@ rg -n "defineAction|useActionQuery" node_modules/@agent-native/core/corpus
31
31
 
32
32
  ## Generated Counts
33
33
 
34
- - template files: 9664
34
+ - template files: 9668
@@ -3,6 +3,12 @@
3
3
  All notable user-facing changes to Agent-Native Calendar 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-18
7
+
8
+ ### Fixed
9
+
10
+ - Calendar now preserves grouped guest counts and keeps the event detail panel keyboard accessible.
11
+
6
12
  ## 2026-09-16
7
13
 
8
14
  ### Fixed
@@ -3,17 +3,76 @@
3
3
  All notable user-facing changes to Clips 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-21
7
+
8
+ ### Fixed
9
+
10
+ - Clips keeps the menu-bar popover open, restarts cleanly after updates, and waits for Google sign-in without a loading indicator.
11
+
12
+ ## 2026-09-19
13
+
14
+ ### Fixed
15
+
16
+ - Clips library loads on older browsers that lack modern object helpers
17
+ - After cutting a selected range from the editor toolbar, the selection follows the playhead again.
18
+
19
+ ## 2026-09-18
20
+
21
+ ### Improved
22
+
23
+ - Clips loads recording and organization lists faster
24
+ - Desktop recording alerts use matching warning and error highlights in the recorder and recovery list
25
+ - Desktop recording failures notify you and stay available in Clips with upload retry and local recovery options.
26
+ - Desktop recording recovery opens in a compact page, and completion cards close after Open or Copy succeeds
27
+ - Dictation now shows listening, finalizing, pasting, and success states so release-to-paste never feels stalled.
28
+ - Dictation keeps a quiet waveform pill, reveals controls on hover, and falls back to the clipboard when no text field is focused.
29
+ - Recording shortcuts now start, stop, cancel, and pause recordings with editable platform defaults.
30
+ - Use Fn as the default desktop dictation shortcut and keep its live waveform responsive during capture.
31
+
32
+ ### Fixed
33
+
34
+ - Desktop recorder popover dismissal now works from outside clicks, the menu-bar icon, and Escape after native capture setup.
35
+ - Desktop recording setup recovers cleanly from cancellation and no longer stalls on a hidden microphone request.
36
+ - Fix Google sign-in popups when replying while signed out
37
+ - Clips extension sign-in now works for self-hosted apps mounted under a path.
38
+ - Hide recording recovery alerts from the sign-in screen
39
+ - Large recordings now support on-demand frame extraction.
40
+ - Refresh the desktop Dictate status surface and prevent shortcut-triggered native speech crashes.
41
+ - Reply controls stay clickable near the bottom of a recording's comments.
42
+ - Recordings with different frame sizes can now be stitched together.
43
+
6
44
  ## 2026-09-17
7
45
 
46
+ ### Improved
47
+
48
+ - Hardened macOS Window recording handoff and simplified the web recorder desktop menu.
49
+ - Recordings keep capturing through brief connection losses and resume uploading when the open tab reconnects.
50
+ - Refresh the Chrome extension recorder UI to match the current Desktop shell.
51
+ - Screen and region recording controls are clearer and more reliable.
52
+
8
53
  ### Fixed
9
54
 
55
+ - The desktop popover now closes when you click away from it.
56
+ - Escape now cancels native window selection regardless of pointer position.
57
+ - Full screen, Region, and Window now appear together in the capture menu
58
+ - macOS Window recording now uses the native single-window picker without the WebKit sharing-controls stall
59
+ - Self-hosted Clips extensions now finish sign-in reliably.
60
+ - Window picker cancellation responds to Escape immediately
61
+ - Window picker launch no longer waits on Screen Memory or exposes a parked popover artifact
62
+ - Window recording starts without interrupting Screen Memory or leaving the recorder stuck in finalization
10
63
  - Clips waits for authentication before showing the recording action
11
64
  - The Clips sort control keeps its keyboard focus ring visible
12
65
 
66
+ ### Changed
67
+
68
+ - Chrome extension recorder labels now match the Web and Desktop capture controls.
69
+ - Web recording labels full-screen capture as Full screen.
70
+
13
71
  ## 2026-09-16
14
72
 
15
73
  ### Improved
16
74
 
75
+ - Folder breadcrumbs now collapse to fit and show a back button to the parent folder
17
76
  - Agents can continue through long recording transcripts without losing later sections.
18
77
 
19
78
  ### Fixed
@@ -3,6 +3,80 @@
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-21
7
+
8
+ ### Added
9
+
10
+ - Design includes more Google Fonts and supports custom font uploads
11
+
12
+ ### Fixed
13
+
14
+ - Keep guided design choices readable in narrow panels
15
+ - Live visual-edit screens stay selectable and editable while running
16
+ - Live visual-edit screens support direct hover, selection, movement, resizing, and safe undo/redo.
17
+ - Show the generation loader as soon as design questions are submitted
18
+
19
+ ## 2026-09-20
20
+
21
+ ### Improved
22
+
23
+ - Public visual-edit links make localhost screens selectable and editable in the browser.
24
+
25
+ ### Fixed
26
+
27
+ - Deleted Design screens can be recovered with Undo and History after reload
28
+ - Design cross-screen moves now retain undo history after persisted saves
29
+ - Design cross-screen moves preserve undo history after retryable and conflicting saves
30
+ - Design layer drags now preview Figma-style hierarchy changes and preserve cancel and undo behavior
31
+ - Grouped Design drops stay atomic through Apply, undo, and reload
32
+ - Show a precise insertion line when dragging into an occupied grid cell
33
+
34
+ ## 2026-09-19
35
+
36
+ ### Improved
37
+
38
+ - Drag and drop keeps placements and ordering across screens and freeform layouts
39
+ - URL-based React editing keeps focused changes visible through hot reload
40
+
41
+ ### Fixed
42
+
43
+ - Component variant overrides persist when the main component changes
44
+ - Grouped grid layers preview their final cells and move as one undoable change
45
+
46
+ ## 2026-09-18
47
+
48
+ ### Added
49
+
50
+ - Auto Layout inspectors now show F, H, and A keyboard shortcuts
51
+ - Lines and arrows support independent endpoint styles in the inspector
52
+
53
+ ### Improved
54
+
55
+ - Canvas panning avoids unnecessary redraws, and zoomed-out board previews use less rendering memory
56
+ - Design system lists load faster
57
+ - Private design links now offer access requests and sign-in or sign-up CTAs.
58
+ - Start visual editing with the /visual-edit skill install command
59
+ - Visual edit opens signed-out local previews in hosted Design and keeps live edits connected
60
+
61
+ ### Fixed
62
+
63
+ - Auto-layout drops preserve Screen-root flow, responsive sizing, and grid track order.
64
+ - Cross-screen moves recover cleanly when a save conflict interrupts either file
65
+ - Design auto-layout drag and drop keeps wrapped rows and grid placement previews aligned
66
+ - Design auto-layout drag previews preserve wrapped rows and grid cells
67
+ - Design imports large Figma files with hundreds of frames
68
+ - Design keeps URL-backed auto-layout moves through source handoff and reload
69
+ - Editor panels stay visible while panning zoomed-out designs with background blur, and frame labels keep a consistent size when changing zoom.
70
+ - Fix Selection colors scanning and matching-layer targeting
71
+ - Imported screens stay separated from their responsive previews on the canvas
72
+ - Keep large imported canvases stable while fitting, panning, and selecting.
73
+ - Large Design canvases stay stable while panning and zooming
74
+ - Large imported frames keep panning and zooming stable without dropping the canvas UI.
75
+ - Responsive interaction mode now exits without leaving stale canvas state
76
+ - Signed-out visual editing can read and write local source from hosted Design
77
+ - Signed-out visual editing loads localhost screens reliably
78
+ - The breakpoint add control sits closer to the last frame
79
+
6
80
  ## 2026-09-17
7
81
 
8
82
  ### Added
@@ -11,16 +85,33 @@ from the command menu (Cmd+K → "What's new") or from Settings.
11
85
 
12
86
  ### Improved
13
87
 
88
+ - Design explains how to select inner layers with Cmd/Ctrl-click
89
+ - Design preserves reusable component identity and props across inline and React screens
90
+ - Signed-out users can open and visually edit a local Design canvas
91
+ - Visual edit opens local apps from a signed-out Design tab
14
92
  - Design loads faster and large .fig imports can target selected frames
15
93
 
16
94
  ### Fixed
17
95
 
96
+ - Canvas zoom now paints large previews without rerendering the iframe on every gesture frame.
97
+ - Cross-screen dragging now preserves element placement between screens and the board.
98
+ - Cross-screen drags preserve their target and persist correctly
99
+ - Design arrange shortcuts reliably move layers forward, backward, to front, and to back
100
+ - Cross-screen dragging reliably moves elements and rolls back refused saves.
101
+ - Design drag-and-drop keeps auto-layout ordering and Cmd/Ctrl free placement
102
+ - Design drag-and-drop keeps duplicates, cross-screen moves, and undo history in sync.
103
+ - Design keeps component source and live edits consistent during indexing and updates
104
+ - Design preserves animated styles when copying or moving layers
105
+ - Open vector paths no longer show fills, and Interact dimensions stay clear of the exit control.
106
+ - Option-drag duplication keeps board objects and root screens addressable at every zoom.
107
+ - Screen deletion is immediate and undoable, with history that survives reloads.
18
108
  - Large .fig files import directly in the browser without the old upload ceiling
19
109
 
20
110
  ## 2026-09-16
21
111
 
22
112
  ### Improved
23
113
 
114
+ - Design components retain linked identities when edited and duplicated
24
115
  - Design files avoid cold-start scans and open faster after idle periods
25
116
  - Design marquee selections stay responsive on large screens
26
117
  - Design editor agent chat uses shared conversation tabs and stays usable at narrow widths
@@ -28,6 +119,7 @@ from the command menu (Cmd+K → "What's new") or from Settings.
28
119
 
29
120
  ### Fixed
30
121
 
122
+ - Fix Design nested layer dragging and screen duplication parity
31
123
  - Design comments keep keyboard mentions and selected recipients through drafts and replies
32
124
  - Design Fill editing uses the visible background paint on text-bearing controls
33
125
  - Design inspector controls match compact Figma spacing
@@ -55,6 +55,7 @@ import {
55
55
  TooltipProvider,
56
56
  TooltipTrigger,
57
57
  } from "@/components/ui/tooltip";
58
+ import type { UploadedFont } from "@/lib/font-upload";
58
59
  import { cn } from "@/lib/utils";
59
60
  import type { EditorMode } from "@/pages/design-editor/types";
60
61
 
@@ -386,6 +387,7 @@ interface EditPanelProps {
386
387
  onRequestTweaks?: (anchor: HTMLElement) => void;
387
388
  onStyleChange: StyleChangeHandler;
388
389
  onStylesChange?: StylesChangeHandler;
390
+ onFontUploaded?: (font: UploadedFont) => void | Promise<void>;
389
391
  onExport?: (settings: ExportSettingsValue[]) => void;
390
392
  /** Rasterizes the current selection for the export preview. Must go through
391
393
  * the same renderer as `onExport`, or the preview lies about the output. */
@@ -1863,7 +1865,11 @@ function PageProperties({
1863
1865
  const baseFontFamilyOptions = sortFontFamilyOptions(
1864
1866
  FONT_FAMILY_OPTIONS.map((option) => ({
1865
1867
  value: option.value,
1866
- label: t(`editPanel.fontFamilies.${option.key}`),
1868
+ label:
1869
+ option.label ??
1870
+ (option.key
1871
+ ? t(`editPanel.fontFamilies.${option.key}`)
1872
+ : displayFontFamilyName(option.value)),
1867
1873
  })),
1868
1874
  );
1869
1875
  const fontFamily = resolveFontFamilySelectValue(styles.fontFamily);
@@ -2478,6 +2484,7 @@ export const EditPanel = memo(function EditPanel({
2478
2484
  designId,
2479
2485
  onComponentPropApplied,
2480
2486
  onShaderSourceApplied,
2487
+ onFontUploaded,
2481
2488
  reviewPanelProps,
2482
2489
  reviewCommentsPanelProps,
2483
2490
  reviewCommentsCount = 0,
@@ -3324,6 +3331,8 @@ export const EditPanel = memo(function EditPanel({
3324
3331
  onStylesChange={
3325
3332
  onStylesChangeProp ? onStylesChange : undefined
3326
3333
  }
3334
+ designId={designId}
3335
+ onFontUploaded={onFontUploaded}
3327
3336
  />
3328
3337
  ) : null}
3329
3338
  {selectionIsGroup ? (
@@ -18,9 +18,10 @@ import {
18
18
  IconSquare,
19
19
  IconStrikethrough,
20
20
  IconTextSize,
21
+ IconUpload,
21
22
  IconUnderline,
22
23
  } from "@tabler/icons-react";
23
- import { useId, useState } from "react";
24
+ import { useId, useRef, useState } from "react";
24
25
  import { toast } from "sonner";
25
26
 
26
27
  import { formatShortcutLabel } from "@/components/design/keyboard-shortcuts";
@@ -45,6 +46,7 @@ import {
45
46
  TooltipTrigger,
46
47
  } from "@/components/ui/tooltip";
47
48
  import { useApplePlatform } from "@/hooks/use-shortcut-label";
49
+ import { uploadFont, type UploadedFont } from "@/lib/font-upload";
48
50
  import { cn } from "@/lib/utils";
49
51
 
50
52
  import { ScrubInput } from "../inspector";
@@ -89,11 +91,6 @@ import {
89
91
  type TextResizeMode,
90
92
  } from "./typography-helpers";
91
93
 
92
- const LATO_FONT_FAMILY_OPTION = {
93
- value: "'Lato', sans-serif",
94
- label: "Lato",
95
- } as const;
96
-
97
94
  function TextResizeControls({
98
95
  resizeMode,
99
96
  onResizeModeChange,
@@ -386,19 +383,28 @@ export function TypographyProperties({
386
383
  element,
387
384
  onStyleChange,
388
385
  onStylesChange,
386
+ designId,
387
+ onFontUploaded,
389
388
  }: {
390
389
  element: ElementInfo;
391
390
  onStyleChange: StyleChangeHandler;
392
391
  onStylesChange?: StylesChangeHandler;
392
+ designId?: string;
393
+ onFontUploaded?: (font: UploadedFont) => void | Promise<void>;
393
394
  }) {
394
395
  const t = useT();
396
+ const fontUploadInputRef = useRef<HTMLInputElement>(null);
397
+ const [fontUploading, setFontUploading] = useState(false);
395
398
  const styles = element.computedStyles;
396
399
  const baseFontFamilyOptions = sortFontFamilyOptions([
397
400
  ...FONT_FAMILY_OPTIONS.map((option) => ({
398
401
  value: option.value,
399
- label: t(`editPanel.fontFamilies.${option.key}`),
402
+ label:
403
+ option.label ??
404
+ (option.key
405
+ ? t(`editPanel.fontFamilies.${option.key}`)
406
+ : displayFontFamilyName(option.value)),
400
407
  })),
401
- LATO_FONT_FAMILY_OPTION,
402
408
  ]);
403
409
  // Mixed-selection guards: a multi-selection with differing values injects
404
410
  // the MIXED_VALUE sentinel string into these computedStyles fields (see
@@ -494,6 +500,22 @@ export function TypographyProperties({
494
500
  ...baseFontFamilyOptions,
495
501
  ],
496
502
  );
503
+ const handleFontUpload = async (file: File) => {
504
+ if (!designId || !onFontUploaded) return;
505
+ setFontUploading(true);
506
+ try {
507
+ const uploaded = await uploadFont(file, designId);
508
+ await onFontUploaded(uploaded);
509
+ } catch (error) {
510
+ toast.error(
511
+ error instanceof Error
512
+ ? error.message
513
+ : t("promptDialog.failedToUploadFile"),
514
+ );
515
+ } finally {
516
+ setFontUploading(false);
517
+ }
518
+ };
497
519
  const baseFontWeightOptions = FONT_WEIGHT_OPTIONS.map((option) => ({
498
520
  value: option.value,
499
521
  label: t(`editPanel.fontWeights.${option.key}`),
@@ -625,20 +647,58 @@ export function TypographyProperties({
625
647
  dropdown instead). */}
626
648
  <InspectorGrid layout="field-action">
627
649
  <InspectorGridCell span={28} className="h-6 overflow-hidden">
628
- <VisualFontFamilyPicker
629
- label={t("editPanel.labels.font")}
630
- value={fontFamily}
631
- options={fontFamilyOptions}
632
- mixed={fontFamilyIsMixed}
633
- mixedLabel={MIXED_VALUE}
634
- searchable
635
- searchPlaceholder={t("root.commandSearch")}
636
- contentProps={{
637
- "data-design-chrome-region": "right-panel",
638
- }}
639
- className="h-6 w-full rounded-md border-[var(--design-editor-control-border)] bg-[var(--design-editor-control-bg)] px-1.5 !text-[11px] shadow-none focus:ring-1 focus:ring-[var(--design-editor-accent-color)]"
640
- onChange={(value) => onStyleChange("fontFamily", value)}
641
- />
650
+ <div className="flex min-w-0 items-center gap-1">
651
+ <div className="min-w-0 flex-1">
652
+ <VisualFontFamilyPicker
653
+ label={t("editPanel.labels.font")}
654
+ value={fontFamily}
655
+ options={fontFamilyOptions}
656
+ mixed={fontFamilyIsMixed}
657
+ mixedLabel={MIXED_VALUE}
658
+ searchable
659
+ searchPlaceholder={t("root.commandSearch")}
660
+ contentProps={{
661
+ "data-design-chrome-region": "right-panel",
662
+ }}
663
+ className="h-6 w-full rounded-md border-[var(--design-editor-control-border)] bg-[var(--design-editor-control-bg)] px-1.5 !text-[11px] shadow-none focus:ring-1 focus:ring-[var(--design-editor-accent-color)]"
664
+ onChange={(value) => onStyleChange("fontFamily", value)}
665
+ />
666
+ </div>
667
+ {designId && onFontUploaded ? (
668
+ <>
669
+ <input
670
+ ref={fontUploadInputRef}
671
+ type="file"
672
+ accept=".woff2,.woff,.ttf,.otf,font/woff2,font/woff,font/ttf,font/otf"
673
+ className="sr-only"
674
+ aria-label={t("promptDialog.uploadFile")}
675
+ onChange={(event) => {
676
+ const file = event.target.files?.[0];
677
+ event.target.value = "";
678
+ if (file) void handleFontUpload(file);
679
+ }}
680
+ />
681
+ <Tooltip>
682
+ <TooltipTrigger asChild>
683
+ <Button
684
+ type="button"
685
+ variant="ghost"
686
+ size="icon"
687
+ disabled={fontUploading}
688
+ aria-label={t("promptDialog.uploadFile")}
689
+ className="size-6 shrink-0"
690
+ onClick={() => fontUploadInputRef.current?.click()}
691
+ >
692
+ <IconUpload className="size-3.5" />
693
+ </Button>
694
+ </TooltipTrigger>
695
+ <TooltipContent>
696
+ {t("promptDialog.uploadFile")}
697
+ </TooltipContent>
698
+ </Tooltip>
699
+ </>
700
+ ) : null}
701
+ </div>
642
702
  </InspectorGridCell>
643
703
  </InspectorGrid>
644
704
 
@@ -0,0 +1,90 @@
1
+ import { appBasePath } from "@agent-native/core/client/api-path";
2
+
3
+ export interface UploadedFont {
4
+ family: string;
5
+ url: string;
6
+ weight: string;
7
+ style: "normal" | "italic";
8
+ format: "woff2" | "woff" | "truetype" | "opentype";
9
+ }
10
+
11
+ const FONT_WEIGHT_SUFFIX =
12
+ /\s+(?:thin|extra ?light|ultra ?light|light|book|regular|normal|medium|semi ?bold|demi ?bold|bold|extra ?bold|ultra ?bold|black|heavy)$/i;
13
+
14
+ export function inferFontUploadMetadata(filename: string): {
15
+ family: string;
16
+ weight: string;
17
+ style: "normal" | "italic";
18
+ } {
19
+ const basename = filename.replace(/\.[^.]+$/, "");
20
+ const normalized = basename
21
+ .replace(/[_-]+/g, " ")
22
+ .replace(/\s+/g, " ")
23
+ .trim();
24
+ const style = /(?:italic|oblique)/i.test(normalized) ? "italic" : "normal";
25
+ const familyAndWeight = normalized
26
+ .replace(/\s+(?:italic|oblique)$/i, "")
27
+ .trim();
28
+ const weightMatch = familyAndWeight.match(
29
+ /\s+(thin|extra ?light|ultra ?light|light|book|regular|normal|medium|semi ?bold|demi ?bold|bold|extra ?bold|ultra ?bold|black|heavy)$/i,
30
+ );
31
+ const weight =
32
+ {
33
+ thin: "100",
34
+ extralight: "200",
35
+ ultralight: "200",
36
+ light: "300",
37
+ book: "400",
38
+ regular: "400",
39
+ normal: "400",
40
+ medium: "500",
41
+ semibold: "600",
42
+ demibold: "600",
43
+ bold: "700",
44
+ extrabold: "800",
45
+ ultrabold: "800",
46
+ black: "900",
47
+ heavy: "900",
48
+ }[weightMatch?.[1]?.replace(/\s+/g, "").toLowerCase() ?? ""] ?? "400";
49
+ const family = familyAndWeight
50
+ .replace(FONT_WEIGHT_SUFFIX, "")
51
+ .replace(/\s+/g, " ")
52
+ .trim();
53
+ return { family: family || "Uploaded Font", weight, style };
54
+ }
55
+
56
+ export async function uploadFont(
57
+ file: File,
58
+ designId: string,
59
+ ): Promise<UploadedFont> {
60
+ const metadata = inferFontUploadMetadata(file.name);
61
+ const form = new FormData();
62
+ form.append("designId", designId);
63
+ form.append("family", metadata.family);
64
+ form.append("weight", metadata.weight);
65
+ form.append("style", metadata.style);
66
+ form.append("file", file, file.name);
67
+
68
+ const response = await fetch(`${appBasePath()}/api/fonts`, {
69
+ method: "POST",
70
+ credentials: "include",
71
+ body: form,
72
+ });
73
+ let payload: (UploadedFont & { error?: never }) | { error?: string } | null;
74
+ try {
75
+ payload = (await response.json()) as
76
+ | (UploadedFont & { error?: never })
77
+ | { error?: string }
78
+ | null;
79
+ } catch {
80
+ throw new Error("Font upload failed");
81
+ }
82
+ if (!response.ok || !payload || !("url" in payload)) {
83
+ throw new Error(
84
+ payload && "error" in payload && payload.error
85
+ ? payload.error
86
+ : "Font upload failed",
87
+ );
88
+ }
89
+ return payload;
90
+ }
@@ -21,8 +21,11 @@ export {
21
21
  replaceDataScreenReferences,
22
22
  } from "@shared/screen-rename";
23
23
 
24
+ import { GOOGLE_FONT_QUERIES } from "@agent-native/toolkit/design-tweaks";
25
+
24
26
  import type { LayersPanelNode } from "@/components/design/LayersPanel";
25
27
  import type { ElementInfo } from "@/components/design/types";
28
+ import type { UploadedFont } from "@/lib/font-upload";
26
29
 
27
30
  import { queryUniqueSelector } from "./dom-utils";
28
31
 
@@ -1272,16 +1275,9 @@ export function codeLayerPatchMessage(
1272
1275
  : message;
1273
1276
  }
1274
1277
 
1275
- // Known Google Font families offered by the inspector's font-family picker.
1276
1278
  // Lato's weight 500 comes from the pinned OFL face below because the CSS2 API
1277
1279
  // currently serves only its 400 and 700 files.
1278
- export const KNOWN_GOOGLE_FONTS: Record<string, string> = {
1279
- Inter: "Inter:wght@400;500;600;700",
1280
- Poppins: "Poppins:wght@400;500;600;700",
1281
- "Playfair Display": "Playfair+Display:wght@400;500;600;700",
1282
- "JetBrains Mono": "JetBrains+Mono:wght@400;500;600;700",
1283
- Lato: "Lato:wght@400;700",
1284
- };
1280
+ export const KNOWN_GOOGLE_FONTS = GOOGLE_FONT_QUERIES;
1285
1281
 
1286
1282
  const LATO_MEDIUM_FACE_URL =
1287
1283
  "https://raw.githubusercontent.com/google/fonts/809e4d8b8d7e9364a914909bb777679606c178b8/ofl/lato/Lato-Medium.ttf";
@@ -1346,7 +1342,18 @@ export function ensureGoogleFontLinkInHtml(
1346
1342
  );
1347
1343
  const alreadyLoaded = existingLinks.some((link) => {
1348
1344
  const href = link.getAttribute("href") ?? "";
1349
- return href.includes(encodeURIComponent(family)) || href.includes(family);
1345
+ let normalizedHref = href;
1346
+ try {
1347
+ normalizedHref = decodeURIComponent(href);
1348
+ } catch {
1349
+ // coercion-ok: malformed legacy URL stays raw for conservative matching.
1350
+ // Keep the raw URL when a legacy link contains malformed escaping.
1351
+ }
1352
+ normalizedHref = normalizedHref.replace(/\+/g, " ").toLowerCase();
1353
+ return (
1354
+ href.includes(`family=${fontQuery}`) ||
1355
+ normalizedHref.includes(`family=${family.toLowerCase()}:`)
1356
+ );
1350
1357
  });
1351
1358
  let changed = ensurePinnedFontFace(doc, family);
1352
1359
  if (!alreadyLoaded) {
@@ -1388,6 +1395,51 @@ export function ensureGoogleFontLinkInHtml(
1388
1395
  }
1389
1396
  }
1390
1397
 
1398
+ function escapeCssString(value: string): string {
1399
+ return value
1400
+ .replace(/\\/g, "\\\\")
1401
+ .replace(/"/g, '\\"')
1402
+ .replace(/[\r\n]/g, "");
1403
+ }
1404
+
1405
+ /** Persist an uploaded face next to the screen HTML that uses it. */
1406
+ export function ensureUploadedFontFaceInHtml(
1407
+ content: string,
1408
+ font: UploadedFont,
1409
+ ): string {
1410
+ if (typeof window === "undefined") return content;
1411
+ if (!font.url || !font.family) return content;
1412
+ const doc = new DOMParser().parseFromString(content, "text/html");
1413
+ const head = doc.head;
1414
+ if (!head) return content;
1415
+ const alreadyLoaded = Array.from(
1416
+ head.querySelectorAll('style[data-agent-native-uploaded-font="true"]'),
1417
+ ).some(
1418
+ (style) =>
1419
+ style.getAttribute("data-font-family") === font.family &&
1420
+ style.getAttribute("data-font-url") === font.url &&
1421
+ style.getAttribute("data-font-weight") === font.weight &&
1422
+ style.getAttribute("data-font-style") === font.style,
1423
+ );
1424
+ if (alreadyLoaded) return content;
1425
+
1426
+ const style = doc.createElement("style");
1427
+ style.setAttribute("data-agent-native-uploaded-font", "true");
1428
+ style.setAttribute("data-font-family", font.family);
1429
+ style.setAttribute("data-font-url", font.url);
1430
+ style.setAttribute("data-font-weight", font.weight);
1431
+ style.setAttribute("data-font-style", font.style);
1432
+ style.textContent = `@font-face {
1433
+ font-family: "${escapeCssString(font.family)}";
1434
+ font-style: ${font.style};
1435
+ font-weight: ${font.weight};
1436
+ font-display: swap;
1437
+ src: url("${escapeCssString(font.url)}") format("${font.format}");
1438
+ }`;
1439
+ head.appendChild(style);
1440
+ return `<!DOCTYPE html>\n${doc.documentElement.outerHTML}`;
1441
+ }
1442
+
1391
1443
  export function refreshElementInfoFromContent(
1392
1444
  content: string,
1393
1445
  info: ElementInfo | null,
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: added
3
+ date: 2026-09-21
4
+ ---
5
+
6
+ Design includes more Google Fonts and supports custom font uploads
@@ -0,0 +1,171 @@
1
+ import path from "node:path";
2
+
3
+ import { uploadFile } from "@agent-native/core/file-upload";
4
+ import { getSession, runWithRequestContext } from "@agent-native/core/server";
5
+ import { assertAccess } from "@agent-native/core/sharing";
6
+ import {
7
+ defineEventHandler,
8
+ getRequestHeader,
9
+ readMultipartFormData,
10
+ setResponseStatus,
11
+ } from "h3";
12
+
13
+ import {
14
+ MAX_UPLOAD_BYTES,
15
+ MAX_UPLOAD_MB,
16
+ TOTAL_BODY_LIMIT,
17
+ } from "../lib/request-body-limits.js";
18
+
19
+ const FONT_FORMATS = {
20
+ ".otf": { format: "opentype", mimeType: "font/otf" },
21
+ ".ttf": { format: "truetype", mimeType: "font/ttf" },
22
+ ".woff": { format: "woff", mimeType: "font/woff" },
23
+ ".woff2": { format: "woff2", mimeType: "font/woff2" },
24
+ } as const;
25
+
26
+ function ascii(data: Uint8Array, start: number, end: number): string {
27
+ return Buffer.from(data.subarray(start, end)).toString("ascii");
28
+ }
29
+
30
+ function hasFontSignature(ext: keyof typeof FONT_FORMATS, data: Uint8Array) {
31
+ if (ext === ".woff" || ext === ".woff2") {
32
+ return ascii(data, 0, 4) === (ext === ".woff" ? "wOFF" : "wOF2");
33
+ }
34
+ if (ext === ".otf") return ascii(data, 0, 4) === "OTTO";
35
+ return data[0] === 0 && data[1] === 1 && data[2] === 0 && data[3] === 0;
36
+ }
37
+
38
+ function fieldText(
39
+ parts: Awaited<ReturnType<typeof readMultipartFormData>>,
40
+ name: string,
41
+ ): string | undefined {
42
+ const part = parts?.find((candidate) => candidate.name === name);
43
+ return part?.data
44
+ ? Buffer.from(part.data).toString("utf8").trim()
45
+ : undefined;
46
+ }
47
+
48
+ function safeFamilyName(value: string | undefined, filename: string): string {
49
+ const fallback = path.basename(filename, path.extname(filename));
50
+ const family = (value || fallback)
51
+ .replace(/["'\\{};,\u0000-\u001f\u007f]/g, "")
52
+ .replace(/\s+/g, " ")
53
+ .trim()
54
+ .slice(0, 100);
55
+ if (!family) throw new Error("Font family is required");
56
+ return family;
57
+ }
58
+
59
+ function safeWeight(value: string | undefined): string {
60
+ const weight = value?.trim() || "400";
61
+ if (!/^\d{3}(?:\s+\d{3})?$/.test(weight)) {
62
+ throw new Error("Font weight is invalid");
63
+ }
64
+ const values = weight.split(/\s+/).map(Number);
65
+ if (values.some((entry) => entry < 1 || entry > 1000)) {
66
+ throw new Error("Font weight is invalid");
67
+ }
68
+ return weight;
69
+ }
70
+
71
+ function safeStyle(value: string | undefined): "normal" | "italic" {
72
+ if (value === "italic") return "italic";
73
+ if (!value || value === "normal") return "normal";
74
+ throw new Error("Font style is invalid");
75
+ }
76
+
77
+ export const uploadFont = defineEventHandler(async (event) => {
78
+ let session;
79
+ try {
80
+ session = await getSession(event);
81
+ } catch (error) {
82
+ console.error("[design-font-upload] session lookup failed", error);
83
+ setResponseStatus(event, 503);
84
+ return { error: "Authentication service unavailable" };
85
+ }
86
+ if (!session?.email) {
87
+ setResponseStatus(event, 401);
88
+ return { error: "Unauthorized" };
89
+ }
90
+
91
+ const contentLength = Number(getRequestHeader(event, "content-length") ?? 0);
92
+ if (contentLength > TOTAL_BODY_LIMIT) {
93
+ setResponseStatus(event, 413);
94
+ return { error: "Request body too large" };
95
+ }
96
+
97
+ return runWithRequestContext(
98
+ { userEmail: session.email, orgId: session.orgId },
99
+ async () => {
100
+ try {
101
+ const parts = await readMultipartFormData(event);
102
+ const designId = fieldText(parts, "designId");
103
+ if (!designId) {
104
+ setResponseStatus(event, 400);
105
+ return { error: "Missing designId" };
106
+ }
107
+ await assertAccess("design", designId, "editor");
108
+
109
+ const filePart = parts?.find(
110
+ (part) => part.name === "file" && part.data,
111
+ );
112
+ if (!filePart?.data) {
113
+ setResponseStatus(event, 400);
114
+ return { error: "No font uploaded" };
115
+ }
116
+ if (filePart.data.length > MAX_UPLOAD_BYTES) {
117
+ setResponseStatus(event, 413);
118
+ return { error: `Font is too large (max ${MAX_UPLOAD_MB} MB)` };
119
+ }
120
+
121
+ const originalName = filePart.filename || "font.woff2";
122
+ const ext = path
123
+ .extname(originalName)
124
+ .toLowerCase() as keyof typeof FONT_FORMATS;
125
+ const format = FONT_FORMATS[ext];
126
+ if (!format || !hasFontSignature(ext, filePart.data)) {
127
+ setResponseStatus(event, 400);
128
+ return { error: "Choose a valid .woff2, .woff, .ttf, or .otf font" };
129
+ }
130
+
131
+ const family = safeFamilyName(fieldText(parts, "family"), originalName);
132
+ const weight = safeWeight(fieldText(parts, "weight"));
133
+ const style = safeStyle(fieldText(parts, "style"));
134
+ let uploaded;
135
+ try {
136
+ uploaded = await uploadFile({
137
+ data: Buffer.from(filePart.data),
138
+ filename: originalName,
139
+ mimeType: format.mimeType,
140
+ ownerEmail: session.email,
141
+ recordAsset: false,
142
+ });
143
+ } catch (error) {
144
+ console.error("[design-font-upload] upload failed", error);
145
+ setResponseStatus(event, 502);
146
+ return { error: "Font upload failed" };
147
+ }
148
+ if (!uploaded) {
149
+ setResponseStatus(event, 503);
150
+ return { error: "File uploads are not configured" };
151
+ }
152
+
153
+ return {
154
+ family,
155
+ url: uploaded.url,
156
+ weight,
157
+ style,
158
+ format: format.format,
159
+ };
160
+ } catch (error) {
161
+ const message =
162
+ error instanceof Error ? error.message : "Font upload failed";
163
+ setResponseStatus(
164
+ event,
165
+ /access|permission|not allowed/i.test(message) ? 403 : 400,
166
+ );
167
+ return { error: message };
168
+ }
169
+ },
170
+ );
171
+ });
@@ -0,0 +1 @@
1
+ export { uploadFont as default } from "../../handlers/fonts";
@@ -3,6 +3,19 @@
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-19
7
+
8
+ ### Fixed
9
+
10
+ - New Mail drafts stay pinned to the bottom of the viewport.
11
+ - OpenAI automation settings load without a missing engine package error
12
+
13
+ ## 2026-09-18
14
+
15
+ ### Added
16
+
17
+ - Mail rules can tag messages or move spam out of Inbox with Jev-powered previews and feedback
18
+
6
19
  ## 2026-09-17
7
20
 
8
21
  ### Fixed
@@ -3,6 +3,44 @@
3
3
  All notable user-facing changes to Agent-Native Slides are documented here. Open it any
4
4
  time from the command menu (Cmd+K → "What's new").
5
5
 
6
+ ## 2026-09-21
7
+
8
+ ### Fixed
9
+
10
+ - Keep slide additions aligned with the deck's existing design system
11
+
12
+ ## 2026-09-20
13
+
14
+ ### Fixed
15
+
16
+ - Continue is available only after selecting a reference or design system.
17
+
18
+ ## 2026-09-19
19
+
20
+ ### Fixed
21
+
22
+ - HTML exports have clickable slide and fullscreen controls
23
+ - Creating another presentation in chat keeps the existing deck intact.
24
+
25
+ ## 2026-09-18
26
+
27
+ ### Improved
28
+
29
+ - New decks now keep the selected design system as the default
30
+ - Share Presentation now keeps its heading inset and shows the relevant link clearly
31
+
32
+ ### Fixed
33
+
34
+ - Inline slide editing now preserves text changes through teardown and reload
35
+ - Slides keeps chat controls, queued prompts, sharing, and design-system status in sync.
36
+ - Slides now hydrates configured design system defaults when references load after opening.
37
+
38
+ ## 2026-09-17
39
+
40
+ ### Fixed
41
+
42
+ - Text editing keeps its focus, toolbar controls, and selection outline consistent
43
+
6
44
  ## 2026-09-16
7
45
 
8
46
  ### Fixed
@@ -214,7 +214,11 @@ export function SlideContextToolbar({
214
214
  const baseFontFamilyOptions = sortFontFamilyOptions(
215
215
  FONT_FAMILY_OPTIONS.map((option) => ({
216
216
  value: option.value,
217
- label: t(`styleInspector.fontFamilies.${option.key}`),
217
+ label:
218
+ option.label ??
219
+ (option.key
220
+ ? t(`styleInspector.fontFamilies.${option.key}`)
221
+ : displayFontFamilyName(option.value)),
218
222
  })),
219
223
  );
220
224
  const inlineEditSurfaceProps = {
@@ -186,8 +186,8 @@ export declare function createAutomationCallbackHandler(runtime: AutomationRunti
186
186
  duplicate?: undefined;
187
187
  eventId?: undefined;
188
188
  } | {
189
+ error?: undefined;
189
190
  accepted: boolean;
190
191
  duplicate: boolean;
191
192
  eventId: string;
192
- error?: undefined;
193
193
  }>;
@@ -22,7 +22,7 @@ import { DEFAULT_MEMBER_SEARCH_DEBOUNCE_MS, useShareOrgMemberSearch, } from "../
22
22
  import { useActionMutation, useActionQuery } from "../use-action.js";
23
23
  import { cn } from "../utils.js";
24
24
  import { useOrg, useOrgMembers, useOrgInvitations, useCreateOrg, useUpdateOrg, useBulkInviteMembers, useChangeMemberRole, useAcceptInvitation, useRemoveMember, useDeleteOrg, useSwitchOrg, useSetOrgDomain, useSetWorkspaceAppDefaultVisibility, useWorkspaceAppAccess, useSetWorkspaceAppAccess, useSetOrgWorkspaceUrl, useSetOrgAuthProvider, useRevealA2ASecret, useSetA2ASecret, useSyncA2ASecret, useJoinByDomain, useAppRoles, useSetAppMemberRoles, useOrgSsoProviders, useCreateOrgSsoProvider, useVerifyOrgSsoProvider, useDeleteOrgSsoProvider, useOrgScim, useCreateOrgScimConnection, useDeleteOrgScimConnection, ORG_MEMBER_PAGE_SIZE, } from "./hooks.js";
25
- const Button = forwardRef(({ className, ...props }, ref) => (_jsx(ToolkitButton, { ref: ref, variant: "ghost", className: cn("h-auto p-0 hover:bg-transparent hover:text-inherit active:scale-100 [&_svg]:!size-auto", className), ...props })));
25
+ const Button = forwardRef(({ className, ...props }, ref) => (_jsx(ToolkitButton, { ref: ref, variant: "ghost", className: cn("h-auto p-0 hover:bg-transparent active:scale-100 [&_svg]:!size-auto", props.emphasis === "solid" ? null : "hover:text-inherit", className), ...props })));
26
26
  Button.displayName = "TeamPrimitiveButton";
27
27
  function RoleIcon({ role }) {
28
28
  if (role === "owner")
@@ -18,7 +18,7 @@ import { KeyProviderTile } from "./KeyProviderTile.js";
18
18
  import { NewKeyMenu, normalizeKeyName } from "./NewKeyMenu.js";
19
19
  import { SettingsCrossLinkHint } from "./SettingsCrossLinkHint.js";
20
20
  import { SettingsSkeleton } from "./SettingsSkeleton.js";
21
- const Button = React.forwardRef(({ className, ...props }, ref) => (_jsx(ToolkitButton, { ref: ref, variant: "ghost", className: cn("h-auto p-0 hover:bg-transparent hover:text-inherit active:scale-100 [&_svg]:!size-auto", className), ...props })));
21
+ const Button = React.forwardRef(({ className, ...props }, ref) => (_jsx(ToolkitButton, { ref: ref, variant: "ghost", className: cn("h-auto p-0 hover:bg-transparent active:scale-100 [&_svg]:!size-auto", props.emphasis === "solid" ? null : "hover:text-inherit", className), ...props })));
22
22
  Button.displayName = "SecretsPrimitiveButton";
23
23
  const SOURCE_LABEL_KEY = {
24
24
  vault: "secrets.sourceVault",
@@ -40,7 +40,7 @@ import { UsageSection } from "./UsageSection.js";
40
40
  import { useBuilderConnectFlow, useBuilderStatus, } from "./useBuilderStatus.js";
41
41
  import { settingsSectionDomId, useSettingsPanelController, } from "./useSettingsPanelController.js";
42
42
  import { VoiceTranscriptionSection } from "./VoiceTranscriptionSection.js";
43
- const Button = React.forwardRef(({ className, ...props }, ref) => (_jsx(ToolkitButton, { ref: ref, variant: "ghost", className: cn("h-auto p-0 hover:bg-transparent hover:text-inherit active:scale-100 [&_svg]:!size-auto", className), ...props })));
43
+ const Button = React.forwardRef(({ className, ...props }, ref) => (_jsx(ToolkitButton, { ref: ref, variant: "ghost", className: cn("h-auto p-0 hover:bg-transparent active:scale-100 [&_svg]:!size-auto", props.emphasis === "solid" ? null : "hover:text-inherit", className), ...props })));
44
44
  Button.displayName = "SettingsPrimitiveButton";
45
45
  const ManageButton = React.forwardRef(({ children = "Manage", className, ...props }, ref) => (_jsx(ToolkitButton, { ref: ref, type: "button", variant: "ghost", intent: "neutral", emphasis: "outline", className: cn("inline-flex h-9 min-h-9 items-center justify-center gap-1 rounded-md border border-border px-3 text-sm font-medium leading-none text-foreground hover:bg-accent/40 active:scale-100 [&_svg]:!size-4", className), ...props, children: children })));
46
46
  ManageButton.displayName = "SettingsManageButton";
@@ -62,11 +62,11 @@ export declare const postAwareness: import("h3").EventHandlerWithFetch<import("h
62
62
  error: string;
63
63
  states?: undefined;
64
64
  } | {
65
- error?: undefined;
66
65
  states: {
67
66
  clientId: number;
68
67
  state: string;
69
68
  }[];
69
+ error?: undefined;
70
70
  }>>;
71
71
  /**
72
72
  * GET /_agent-native/collab/:docId/users
@@ -77,9 +77,9 @@ export declare const getActiveUsers: import("h3").EventHandlerWithFetch<import("
77
77
  error: string;
78
78
  users?: undefined;
79
79
  } | {
80
- error?: undefined;
81
80
  users: {
82
81
  clientId: number;
83
82
  lastSeen: number;
84
83
  }[];
84
+ error?: undefined;
85
85
  }>>;
@@ -26,8 +26,8 @@ export declare const getCollabState: import("h3").EventHandlerWithFetch<import("
26
26
  * Body: { update: string (base64), requestSource?: string }
27
27
  */
28
28
  export declare const postCollabUpdate: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
29
- ok?: undefined;
30
29
  error: string;
30
+ ok?: undefined;
31
31
  } | {
32
32
  error?: undefined;
33
33
  ok: boolean;
@@ -13,8 +13,8 @@
13
13
  * Body: { json: any, fieldName?: string, type?: "map"|"array", requestSource?: string }
14
14
  */
15
15
  export declare const postCollabJson: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
16
- ok?: undefined;
17
16
  error: string;
17
+ ok?: undefined;
18
18
  } | {
19
19
  error?: undefined;
20
20
  ok: boolean;
@@ -34,12 +34,12 @@ declare const _default: import("../../action.js").ActionDefinition<{
34
34
  idempotencyKey: string;
35
35
  deleted: boolean;
36
36
  } | {
37
- id?: undefined;
38
37
  error: string;
39
38
  url?: undefined;
40
39
  provider?: undefined;
41
40
  configured?: undefined;
42
41
  connectPath?: undefined;
42
+ id?: undefined;
43
43
  } | {
44
44
  url: string;
45
45
  id: string;
@@ -48,11 +48,11 @@ declare const _default: import("../../action.js").ActionDefinition<{
48
48
  connectPath?: undefined;
49
49
  error?: undefined;
50
50
  } | {
51
- id?: undefined;
52
51
  url?: undefined;
53
52
  provider?: undefined;
54
53
  error: string;
55
54
  configured: boolean;
56
55
  connectPath: string;
56
+ id?: undefined;
57
57
  }>;
58
58
  export default _default;
@@ -41,9 +41,9 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
41
41
  thumbsUpRate: number;
42
42
  avgEvalScore: number;
43
43
  } | {
44
- id?: undefined;
45
44
  summary: import("./types.js").TraceSummary;
46
45
  spans: import("./types.js").TraceSpan[];
46
+ id?: undefined;
47
47
  error?: undefined;
48
48
  ok?: undefined;
49
49
  } | {
@@ -53,15 +53,15 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
53
53
  error?: undefined;
54
54
  ok?: undefined;
55
55
  } | {
56
- id?: undefined;
57
56
  summary?: undefined;
58
57
  spans?: undefined;
58
+ id?: undefined;
59
59
  error: any;
60
60
  ok?: undefined;
61
61
  } | {
62
- id?: undefined;
63
62
  summary?: undefined;
64
63
  spans?: undefined;
65
- ok: boolean;
64
+ id?: undefined;
66
65
  error?: undefined;
66
+ ok: boolean;
67
67
  }>>;
@@ -53,9 +53,9 @@ export declare const setWorkspaceAppDefaultVisibilityHandler: import("h3").Event
53
53
  /** POST /_agent-native/org — create a new organization */
54
54
  export declare const createOrgHandler: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
55
55
  success: boolean;
56
- id?: undefined;
57
56
  name?: undefined;
58
57
  role?: undefined;
58
+ id?: undefined;
59
59
  } | {
60
60
  success?: undefined;
61
61
  id: string;
@@ -48,8 +48,8 @@ export declare function handleUpdateResource(event: any): Promise<import("./stor
48
48
  }>;
49
49
  /** DELETE /_agent-native/resources/:id — delete a resource */
50
50
  export declare function handleDeleteResource(event: any): Promise<{
51
- error: string;
52
51
  ok?: undefined;
52
+ error: string;
53
53
  } | {
54
54
  error?: undefined;
55
55
  ok: boolean;
@@ -46,20 +46,20 @@ export declare function createAgentEngineApiKeyHandler(): import("h3").EventHand
46
46
  scope?: undefined;
47
47
  ok?: undefined;
48
48
  } | {
49
- error?: undefined;
50
49
  ok: boolean;
51
50
  key: string;
52
51
  scope: string;
52
+ error?: undefined;
53
53
  } | {
54
54
  key?: undefined;
55
55
  scope?: undefined;
56
56
  ok: boolean;
57
57
  error: string;
58
58
  } | {
59
- error?: undefined;
60
59
  ok: boolean;
61
60
  key: string;
62
61
  baseUrlKey?: string;
63
62
  scope: AgentEngineApiKeyScope;
63
+ error?: undefined;
64
64
  }>>;
65
65
  export {};
@@ -408,8 +408,8 @@ export declare function createPublicRemoteAgentsHandler(discover?: PublicAgentDi
408
408
  error: string;
409
409
  agents?: undefined;
410
410
  } | {
411
- error?: undefined;
412
411
  agents: Omit<import("./agent-discovery.js").DiscoveredAgent, "auth" | "kind">[];
412
+ error?: undefined;
413
413
  }>>;
414
414
  export declare function getBuilderConnectErrorDisposition(error: unknown, connectAttemptId: string | null): "correlated" | "legacy" | null;
415
415
  export declare function getBuilderConnectErrorKey(ownerEmail: string, connectAttemptId?: string | null): string;
@@ -59,8 +59,8 @@ export declare function createRealtimeTokenHandler(): import("h3").EventHandlerW
59
59
  expiresAt?: undefined;
60
60
  ttlSeconds?: undefined;
61
61
  } | {
62
- error?: undefined;
63
62
  token: string;
64
63
  expiresAt: string;
65
64
  ttlSeconds: number;
65
+ error?: undefined;
66
66
  }>>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/core",
3
- "version": "0.183.0-nightly-20260921181954",
3
+ "version": "0.183.0",
4
4
  "description": "The agentic application framework for building autonomous agents with intuitive UIs",
5
5
  "homepage": "https://github.com/BuilderIO/agent-native#readme",
6
6
  "bugs": {
@@ -488,9 +488,9 @@
488
488
  "yaml": "^2.9.0",
489
489
  "yjs": "^13.6.32",
490
490
  "zod": "^4.3.6",
491
- "@agent-native/agentkit": "^0.2.5-nightly-20260921181954",
492
- "@agent-native/recap-cli": "0.5.34",
493
- "@agent-native/toolkit": "^0.20.5-nightly-20260921181954"
491
+ "@agent-native/recap-cli": "0.5.35",
492
+ "@agent-native/toolkit": "^0.20.5",
493
+ "@agent-native/agentkit": "^0.2.5"
494
494
  },
495
495
  "devDependencies": {
496
496
  "@ai-sdk/anthropic": "^3.0.71",