@agent-native/core 0.184.0 → 0.184.1-nightly-20260922203115

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 (56) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/changelog/2026-09-22-apps-start-with-an-app-shaped-skeleton-while-session-data-lo.md +6 -0
  3. package/corpus/templates/calendar/changelog/2026-09-22-apps-start-with-an-app-shaped-skeleton-while-session-data-lo.md +6 -0
  4. package/corpus/templates/clips/changelog/2026-09-22-apps-start-with-an-app-shaped-skeleton-while-session-data-lo.md +6 -0
  5. package/corpus/templates/content/AGENTS.md +1 -1
  6. package/corpus/templates/content/actions/_document-search-ranking.ts +191 -0
  7. package/corpus/templates/content/actions/search-documents.ts +184 -49
  8. package/corpus/templates/content/changelog/2026-09-21-search-ranks-title-matches-first.md +6 -0
  9. package/corpus/templates/content/docs/product/capabilities/content.knowledge.search.md +11 -8
  10. package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +10 -3
  11. package/corpus/templates/design/.generated/bridge/nav.generated.ts +1 -0
  12. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +67 -6
  13. package/corpus/templates/design/app/components/design/bridge/nav.bridge.ts +16 -0
  14. package/corpus/templates/design/app/components/design/multi-screen/board-surface-html.ts +26 -0
  15. package/corpus/templates/design/changelog/2026-09-22-apps-start-with-an-app-shaped-skeleton-while-session-data-lo.md +6 -0
  16. package/corpus/templates/design/changelog/2026-09-22-blocks-can-be-selected-with-one-click-inside-screens.md +6 -0
  17. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +136 -123
  18. package/corpus/templates/mail/changelog/2026-09-22-apps-start-with-an-app-shaped-skeleton-while-session-data-lo.md +6 -0
  19. package/corpus/templates/slides/changelog/2026-09-22-apps-start-with-an-app-shaped-skeleton-while-session-data-lo.md +6 -0
  20. package/dist/client/AppShellSkeleton.d.ts +5 -0
  21. package/dist/client/AppShellSkeleton.js +69 -0
  22. package/dist/client/ClientOnly.d.ts +1 -1
  23. package/dist/client/ClientOnly.js +1 -1
  24. package/dist/client/LanguagePicker.d.ts +6 -0
  25. package/dist/client/LanguagePicker.js +128 -0
  26. package/dist/client/analytics.d.ts +3 -2
  27. package/dist/client/analytics.js +1 -1
  28. package/dist/client/app-providers.d.ts +3 -3
  29. package/dist/client/app-providers.js +53 -23
  30. package/dist/client/client-status-requests.d.ts +5 -0
  31. package/dist/client/client-status-requests.js +31 -18
  32. package/dist/client/i18n.d.ts +1 -6
  33. package/dist/client/i18n.js +3 -117
  34. package/dist/client/onboarding/first-run-startup-gate.js +14 -3
  35. package/dist/client/require-session.d.ts +1 -1
  36. package/dist/client/require-session.js +3 -3
  37. package/dist/client/session-replay-context.d.ts +16 -0
  38. package/dist/client/session-replay-context.js +93 -0
  39. package/dist/client/session-replay.d.ts +2 -26
  40. package/dist/client/session-replay.js +1 -64
  41. package/dist/collab/awareness.d.ts +2 -2
  42. package/dist/collab/routes.d.ts +1 -1
  43. package/dist/collab/struct-routes.d.ts +1 -1
  44. package/dist/deploy/build.js +19 -29
  45. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  46. package/dist/observability/routes.d.ts +1 -1
  47. package/dist/progress/routes.d.ts +1 -1
  48. package/dist/resources/handlers.d.ts +1 -1
  49. package/dist/secrets/routes.d.ts +6 -6
  50. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  51. package/dist/server/core-routes-plugin.d.ts +1 -1
  52. package/dist/shared/ssr-session-bootstrap.d.ts +3 -0
  53. package/dist/shared/ssr-session-bootstrap.js +44 -0
  54. package/dist/sharing/actions/list-resource-shares.d.ts +1 -1
  55. package/dist/triggers/actions/manage-automation.d.ts +2 -2
  56. package/package.json +3 -3
@@ -294,7 +294,9 @@ import {
294
294
  getBoardSurfaceHtml,
295
295
  getBoardSurfaceRenderContent,
296
296
  getBoardSurfaceStaticPreviewContent,
297
+ hasBoardRuntimeSurfaceContent,
297
298
  hasBoardSurfaceContent,
299
+ shouldMountBoardSurface,
298
300
  shouldRenderEmptyBoardReviewCanvas,
299
301
  } from "./multi-screen/board-surface-html";
300
302
  import {
@@ -729,6 +731,10 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
729
731
  // before the first layout measurement.
730
732
  const [surfaceSize, setSurfaceSize] = useState({ width: 0, height: 0 });
731
733
  const [crossScreenDragActive, setCrossScreenDragActive] = useState(false);
734
+ const [boardRuntimeSurfaceState, setBoardRuntimeSurfaceState] = useState<{
735
+ boardFileId: string | null;
736
+ requestKeys: string[];
737
+ }>({ boardFileId: null, requestKeys: [] });
732
738
  const [frameGeometry, setFrameGeometry] = useState<FrameGeometryById>({});
733
739
  const frameGeometryRef = useRef(frameGeometry);
734
740
  const renderedScreenIdsRef = useRef<Set<string>>(new Set());
@@ -898,10 +904,65 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
898
904
  // Keep the empty board unmounted during normal editing so the text/shape
899
905
  // creation path can still own its first mount. Mount it for the duration of
900
906
  // a cross-screen drag so the drop has a real DOM target before release.
901
- const boardSurfaceHtml =
902
- crossScreenDragActive || hasBoardSurfaceContent(boardFileContent)
903
- ? getBoardSurfaceHtml(boardFileContent)
904
- : undefined;
907
+ const boardSurfaceHtml = shouldMountBoardSurface({
908
+ hasAuthoredContent: hasBoardSurfaceContent(boardFileContent),
909
+ crossScreenDragActive,
910
+ hasPendingRuntimeInsert: Boolean(boardRuntimeStructureInsertRequest),
911
+ hasRuntimeContent: hasBoardRuntimeSurfaceContent({
912
+ boardFileId,
913
+ runtimeBoardFileId: boardRuntimeSurfaceState.boardFileId,
914
+ runtimeRequestKeys: boardRuntimeSurfaceState.requestKeys,
915
+ }),
916
+ })
917
+ ? getBoardSurfaceHtml(boardFileContent)
918
+ : undefined;
919
+ const handleBoardRuntimeStructureInsertApplied = useCallback(
920
+ (details: {
921
+ requestId: string;
922
+ transactionId?: string;
923
+ routePath?: string;
924
+ selector: string;
925
+ sourceId?: string;
926
+ applied?: boolean;
927
+ }) => {
928
+ if (details.applied !== false && details.selector && boardFileId) {
929
+ const requestKey = details.transactionId ?? details.requestId;
930
+ setBoardRuntimeSurfaceState((current) => {
931
+ const base =
932
+ current.boardFileId === boardFileId
933
+ ? current
934
+ : { boardFileId, requestKeys: [] };
935
+ return base.requestKeys.includes(requestKey)
936
+ ? base
937
+ : { ...base, requestKeys: [...base.requestKeys, requestKey] };
938
+ });
939
+ }
940
+ onBoardRuntimeStructureInsertApplied?.(details);
941
+ },
942
+ [boardFileId, onBoardRuntimeStructureInsertApplied],
943
+ );
944
+ const handleBoardRuntimeStructureRollbackResult = useCallback(
945
+ (details: {
946
+ requestId: string;
947
+ transactionId?: string;
948
+ applied: boolean;
949
+ reason?: string;
950
+ }) => {
951
+ if (details.applied && details.transactionId && boardFileId) {
952
+ setBoardRuntimeSurfaceState((current) => {
953
+ if (current.boardFileId !== boardFileId) return current;
954
+ const requestKeys = current.requestKeys.filter(
955
+ (key) => key !== details.transactionId,
956
+ );
957
+ return requestKeys.length > 0
958
+ ? { ...current, requestKeys }
959
+ : { boardFileId: null, requestKeys: [] };
960
+ });
961
+ }
962
+ onBoardRuntimeStructureRollbackResult?.(details);
963
+ },
964
+ [boardFileId, onBoardRuntimeStructureRollbackResult],
965
+ );
905
966
  const boardHasSurfaceContent = boardSurfaceHtml !== undefined;
906
967
  const boardReviewGeometry = boardSurfaceRenderGeometry ?? {
907
968
  x: 0,
@@ -10739,10 +10800,10 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
10739
10800
  onBoardRuntimeStructureInsertRejected
10740
10801
  }
10741
10802
  onRuntimeStructureInsertApplied={
10742
- onBoardRuntimeStructureInsertApplied
10803
+ handleBoardRuntimeStructureInsertApplied
10743
10804
  }
10744
10805
  onRuntimeStructureRollbackResult={
10745
- onBoardRuntimeStructureRollbackResult
10806
+ handleBoardRuntimeStructureRollbackResult
10746
10807
  }
10747
10808
  clearSelectionRequest={boardClearSelectionRequest}
10748
10809
  selectedSelector={boardSelectedSelector ?? null}
@@ -11,6 +11,13 @@
11
11
  * - internal/relative links (or an explicit `data-screen`): asked to switch
12
12
  * to the matching screen in a multi-screen design; otherwise a no-op so the
13
13
  * prototype never blows itself away.
14
+ * - Cmd/Ctrl/Shift-click and middle-click on a real `<a href>`: left
15
+ * completely alone so the browser's own new-tab/new-window gesture runs
16
+ * (see the modifier-click guard below). A screen switch is a same-tab
17
+ * mutation of the live editor's mode/selection state; forcing it on a
18
+ * click whose entire point was "don't disturb my current tab" corrupts
19
+ * that state instead of opening a new one, which is what produced the
20
+ * Interact-mode crash this guard fixes.
14
21
  *
15
22
  * Protocol (iframe → parent):
16
23
  *
@@ -47,6 +54,15 @@
47
54
  if (!t || !t.closest) return;
48
55
  var a = t.closest("a[href], [data-screen]") as HTMLElement | null;
49
56
  if (!a) return;
57
+ // Cmd/Ctrl-click (new tab), Shift-click (new window), and middle-click
58
+ // are the browser's own "open this somewhere else, leave my tab alone"
59
+ // gestures. Forcing our same-tab screen-switch/postMessage path on top
60
+ // of one of these ignores that intent and mutates the live editor's
61
+ // mode/selection state on a click the user never meant to touch the
62
+ // current tab with. Step aside entirely and let the browser (or, for a
63
+ // `data-screen`-only element with no real destination, simply nothing)
64
+ // handle it instead.
65
+ if (e.metaKey || e.ctrlKey || e.shiftKey || e.button !== 0) return;
50
66
  var ds = a.getAttribute && a.getAttribute("data-screen");
51
67
  // In-page anchors ('#...') and empty hrefs must be handled in-document.
52
68
  // A srcdoc document resolves '#'/'' against the PARENT app URL, so the
@@ -17,6 +17,32 @@ export function getBoardSurfaceHtml(html: string | undefined) {
17
17
  return hasBoardSurfaceContent(html) ? html : EMPTY_BOARD_SURFACE_HTML;
18
18
  }
19
19
 
20
+ export function shouldMountBoardSurface(args: {
21
+ hasAuthoredContent: boolean;
22
+ crossScreenDragActive: boolean;
23
+ hasPendingRuntimeInsert: boolean;
24
+ hasRuntimeContent: boolean;
25
+ }): boolean {
26
+ return (
27
+ args.hasAuthoredContent ||
28
+ args.crossScreenDragActive ||
29
+ args.hasPendingRuntimeInsert ||
30
+ args.hasRuntimeContent
31
+ );
32
+ }
33
+
34
+ export function hasBoardRuntimeSurfaceContent(args: {
35
+ boardFileId?: string;
36
+ runtimeBoardFileId: string | null;
37
+ runtimeRequestKeys: readonly string[];
38
+ }): boolean {
39
+ return (
40
+ args.boardFileId !== undefined &&
41
+ args.runtimeBoardFileId === args.boardFileId &&
42
+ args.runtimeRequestKeys.length > 0
43
+ );
44
+ }
45
+
20
46
  export function shouldRenderEmptyBoardReviewCanvas(args: {
21
47
  hasSurfaceContent: boolean;
22
48
  reviewPinMode: boolean;
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-09-22
4
+ ---
5
+
6
+ Apps start with an app-shaped skeleton while session data loads immediately.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-09-22
4
+ ---
5
+
6
+ Blocks can be selected with one click inside screens
@@ -44,14 +44,19 @@ import {
44
44
  IconFilter,
45
45
  } from "@tabler/icons-react";
46
46
  import { useQueryClient } from "@tanstack/react-query";
47
- import { useState, useCallback, useRef, useEffect, useMemo } from "react";
47
+ import {
48
+ lazy,
49
+ Suspense,
50
+ useState,
51
+ useCallback,
52
+ useRef,
53
+ useEffect,
54
+ useMemo,
55
+ } from "react";
48
56
  import { Link, useNavigate, useLocation, useSearchParams } from "react-router";
49
57
  import { toast } from "sonner";
50
58
 
51
- import {
52
- ComposeModal,
53
- type ComposePaletteCommands,
54
- } from "@/components/email/ComposeModal";
59
+ import type { ComposePaletteCommands } from "@/components/email/ComposeModal";
55
60
  import { SnoozeModal } from "@/components/email/SnoozeModal";
56
61
  import { GoogleConnectBanner } from "@/components/GoogleConnectBanner";
57
62
  import { ThemeToggle } from "@/components/ThemeToggle";
@@ -121,6 +126,12 @@ import { useHeaderTitle, useHeaderActions } from "./HeaderActions";
121
126
  import { SearchBar } from "./SearchBar";
122
127
  import { useCommandPaletteFocus } from "./use-command-palette-focus";
123
128
 
129
+ const ComposeModal = lazy(() =>
130
+ import("@/components/email/ComposeModal").then(({ ComposeModal }) => ({
131
+ default: ComposeModal,
132
+ })),
133
+ );
134
+
124
135
  const BARE_ROUTES = new Set(["/email"]);
125
136
  const EMPTY_SAVED_FILTERS: SavedMailFilter[] = [];
126
137
 
@@ -2068,138 +2079,140 @@ function AppLayoutInner({ children }: AppLayoutProps) {
2068
2079
  const popoutActiveDraft =
2069
2080
  popoutDrafts.find((d) => d.id === popoutActiveId) ?? null;
2070
2081
  return (
2071
- <ComposeModal
2072
- drafts={popoutDrafts}
2073
- activeId={popoutActiveId}
2074
- activeDraft={popoutActiveDraft}
2075
- initialExpanded={composeInitialExpanded}
2076
- onSetActiveId={compose.setActiveId}
2077
- onUpdate={compose.update}
2078
- onClose={(id) => {
2079
- const draft = popoutDrafts.find((d) => d.id === id);
2080
- const hasContent = !!(
2081
- draft?.to?.trim() ||
2082
- draft?.cc?.trim() ||
2083
- draft?.bcc?.trim() ||
2084
- draft?.subject?.trim() ||
2085
- draft?.body?.trim()
2086
- );
2087
- const snapshot = draft ? { ...draft } : null;
2088
- const savePromise = compose.close(id);
2089
- if (hasContent && snapshot) {
2090
- toast(t("mail.toasts.draftClosed"), {
2091
- action: {
2092
- label: t("mail.compose.reopenDraft"),
2093
- onClick: async () => {
2094
- const savedSnapshot = applyDraftSaveResult(
2095
- snapshot,
2096
- await savePromise,
2097
- );
2098
- const { id: _id, ...reopenData } = savedSnapshot;
2099
- compose.open(reopenData);
2100
- },
2101
- },
2102
- cancel: {
2103
- label: t("mail.compose.deleteDraft"),
2104
- onClick: async () => {
2105
- const savedSnapshot = applyDraftSaveResult(
2106
- snapshot,
2107
- await savePromise,
2108
- );
2109
- if (savedSnapshot.savedDraftId) {
2110
- await compose.deleteSavedDraft(savedSnapshot);
2111
- }
2112
- },
2113
- },
2114
- });
2115
- }
2116
- }}
2117
- onCloseAll={() => {
2118
- const draftsWithContent = popoutDrafts.filter(
2119
- (d) =>
2120
- !!(
2121
- d.to?.trim() ||
2122
- d.cc?.trim() ||
2123
- d.bcc?.trim() ||
2124
- d.subject?.trim() ||
2125
- d.body?.trim()
2126
- ),
2127
- );
2128
- const snapshots = draftsWithContent.map((d) => ({ ...d }));
2129
- const savePromises = compose.closeAll(
2130
- popoutDrafts.map((draft) => draft.id),
2131
- );
2132
- if (snapshots.length > 0) {
2133
- toast(
2134
- t("mail.toasts.draftsClosed", { count: snapshots.length }),
2135
- {
2082
+ <Suspense fallback={null}>
2083
+ <ComposeModal
2084
+ drafts={popoutDrafts}
2085
+ activeId={popoutActiveId}
2086
+ activeDraft={popoutActiveDraft}
2087
+ initialExpanded={composeInitialExpanded}
2088
+ onSetActiveId={compose.setActiveId}
2089
+ onUpdate={compose.update}
2090
+ onClose={(id) => {
2091
+ const draft = popoutDrafts.find((d) => d.id === id);
2092
+ const hasContent = !!(
2093
+ draft?.to?.trim() ||
2094
+ draft?.cc?.trim() ||
2095
+ draft?.bcc?.trim() ||
2096
+ draft?.subject?.trim() ||
2097
+ draft?.body?.trim()
2098
+ );
2099
+ const snapshot = draft ? { ...draft } : null;
2100
+ const savePromise = compose.close(id);
2101
+ if (hasContent && snapshot) {
2102
+ toast(t("mail.toasts.draftClosed"), {
2136
2103
  action: {
2137
2104
  label: t("mail.compose.reopenDraft"),
2138
2105
  onClick: async () => {
2139
- const saveResults = await Promise.all(
2140
- snapshots.map(async (snapshot) => ({
2141
- snapshot,
2142
- result: await savePromises.get(snapshot.id),
2143
- })),
2106
+ const savedSnapshot = applyDraftSaveResult(
2107
+ snapshot,
2108
+ await savePromise,
2144
2109
  );
2145
- for (const { snapshot, result } of saveResults) {
2146
- if (
2147
- result?.status === "failed" ||
2148
- result?.status === "unavailable" ||
2149
- result?.status === "cancelled"
2150
- ) {
2151
- compose.setActiveId(snapshot.id);
2152
- continue;
2153
- }
2154
- const savedSnapshot = applyDraftSaveResult(
2155
- snapshot,
2156
- result,
2157
- );
2158
- const { id: _id, ...reopenData } = savedSnapshot;
2159
- compose.open(reopenData);
2160
- }
2110
+ const { id: _id, ...reopenData } = savedSnapshot;
2111
+ compose.open(reopenData);
2161
2112
  },
2162
2113
  },
2163
2114
  cancel: {
2164
- label: t("mail.compose.deleteDrafts"),
2115
+ label: t("mail.compose.deleteDraft"),
2165
2116
  onClick: async () => {
2166
- const saveResults = await Promise.all(
2167
- snapshots.map(async (snapshot) => ({
2168
- snapshot,
2169
- result: await savePromises.get(snapshot.id),
2170
- })),
2117
+ const savedSnapshot = applyDraftSaveResult(
2118
+ snapshot,
2119
+ await savePromise,
2171
2120
  );
2172
- for (const { snapshot, result } of saveResults) {
2173
- if (
2174
- result?.status === "failed" ||
2175
- result?.status === "unavailable" ||
2176
- result?.status === "cancelled"
2177
- ) {
2178
- compose.discard(snapshot.id);
2179
- continue;
2121
+ if (savedSnapshot.savedDraftId) {
2122
+ await compose.deleteSavedDraft(savedSnapshot);
2123
+ }
2124
+ },
2125
+ },
2126
+ });
2127
+ }
2128
+ }}
2129
+ onCloseAll={() => {
2130
+ const draftsWithContent = popoutDrafts.filter(
2131
+ (d) =>
2132
+ !!(
2133
+ d.to?.trim() ||
2134
+ d.cc?.trim() ||
2135
+ d.bcc?.trim() ||
2136
+ d.subject?.trim() ||
2137
+ d.body?.trim()
2138
+ ),
2139
+ );
2140
+ const snapshots = draftsWithContent.map((d) => ({ ...d }));
2141
+ const savePromises = compose.closeAll(
2142
+ popoutDrafts.map((draft) => draft.id),
2143
+ );
2144
+ if (snapshots.length > 0) {
2145
+ toast(
2146
+ t("mail.toasts.draftsClosed", { count: snapshots.length }),
2147
+ {
2148
+ action: {
2149
+ label: t("mail.compose.reopenDraft"),
2150
+ onClick: async () => {
2151
+ const saveResults = await Promise.all(
2152
+ snapshots.map(async (snapshot) => ({
2153
+ snapshot,
2154
+ result: await savePromises.get(snapshot.id),
2155
+ })),
2156
+ );
2157
+ for (const { snapshot, result } of saveResults) {
2158
+ if (
2159
+ result?.status === "failed" ||
2160
+ result?.status === "unavailable" ||
2161
+ result?.status === "cancelled"
2162
+ ) {
2163
+ compose.setActiveId(snapshot.id);
2164
+ continue;
2165
+ }
2166
+ const savedSnapshot = applyDraftSaveResult(
2167
+ snapshot,
2168
+ result,
2169
+ );
2170
+ const { id: _id, ...reopenData } = savedSnapshot;
2171
+ compose.open(reopenData);
2180
2172
  }
2181
- const savedSnapshot = applyDraftSaveResult(
2182
- snapshot,
2183
- result,
2173
+ },
2174
+ },
2175
+ cancel: {
2176
+ label: t("mail.compose.deleteDrafts"),
2177
+ onClick: async () => {
2178
+ const saveResults = await Promise.all(
2179
+ snapshots.map(async (snapshot) => ({
2180
+ snapshot,
2181
+ result: await savePromises.get(snapshot.id),
2182
+ })),
2184
2183
  );
2185
- if (savedSnapshot.savedDraftId) {
2186
- await compose.deleteSavedDraft(savedSnapshot);
2184
+ for (const { snapshot, result } of saveResults) {
2185
+ if (
2186
+ result?.status === "failed" ||
2187
+ result?.status === "unavailable" ||
2188
+ result?.status === "cancelled"
2189
+ ) {
2190
+ compose.discard(snapshot.id);
2191
+ continue;
2192
+ }
2193
+ const savedSnapshot = applyDraftSaveResult(
2194
+ snapshot,
2195
+ result,
2196
+ );
2197
+ if (savedSnapshot.savedDraftId) {
2198
+ await compose.deleteSavedDraft(savedSnapshot);
2199
+ }
2187
2200
  }
2188
- }
2201
+ },
2189
2202
  },
2190
2203
  },
2191
- },
2192
- );
2193
- }
2194
- }}
2195
- onDiscard={compose.discard}
2196
- onStageForSend={compose.stageForSend}
2197
- onRestoreAfterSend={compose.restoreAfterSend}
2198
- onNewDraft={handleCompose}
2199
- onFlush={compose.flush}
2200
- onInitialExpandedConsumed={clearComposeInitialExpanded}
2201
- onRegisterComposeCommands={registerComposePaletteCommands}
2202
- />
2204
+ );
2205
+ }
2206
+ }}
2207
+ onDiscard={compose.discard}
2208
+ onStageForSend={compose.stageForSend}
2209
+ onRestoreAfterSend={compose.restoreAfterSend}
2210
+ onNewDraft={handleCompose}
2211
+ onFlush={compose.flush}
2212
+ onInitialExpandedConsumed={clearComposeInitialExpanded}
2213
+ onRegisterComposeCommands={registerComposePaletteCommands}
2214
+ />
2215
+ </Suspense>
2203
2216
  );
2204
2217
  })()}
2205
2218
  <CommandPalette
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-09-22
4
+ ---
5
+
6
+ Apps start with an app-shaped skeleton while session data loads immediately.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-09-22
4
+ ---
5
+
6
+ Apps start with an app-shaped skeleton while session data loads immediately.
@@ -0,0 +1,5 @@
1
+ import type { CSSProperties } from "react";
2
+ export declare function AppShellSkeleton({ ariaLabel, height, }: {
3
+ ariaLabel?: string;
4
+ height?: CSSProperties["height"];
5
+ }): import("react").JSX.Element;
@@ -0,0 +1,69 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ const BLOCK_STYLE = {
3
+ display: "block",
4
+ backgroundColor: "hsl(var(--muted, 240 5% 96.1%))",
5
+ borderRadius: 6,
6
+ opacity: 0.7,
7
+ };
8
+ function Block({ style }) {
9
+ return _jsx("span", { "aria-hidden": true, style: { ...BLOCK_STYLE, ...style } });
10
+ }
11
+ export function AppShellSkeleton({ ariaLabel = "Loading application", height = "var(--agent-native-viewport-height, 100vh)", }) {
12
+ return (_jsxs("div", { role: "status", "aria-label": ariaLabel, "data-agent-native-app-skeleton": "true", style: {
13
+ display: "flex",
14
+ height,
15
+ width: "100%",
16
+ overflow: "hidden",
17
+ backgroundColor: "hsl(var(--background, 0 0% 100%))",
18
+ color: "hsl(var(--foreground, 240 10% 3.9%))",
19
+ }, children: [_jsx("style", { children: `
20
+ [data-agent-native-app-skeleton] [aria-hidden="true"] {
21
+ animation: an-app-shell-skeleton-pulse 1.2s ease-in-out infinite;
22
+ }
23
+ @keyframes an-app-shell-skeleton-pulse {
24
+ 0%, 100% { opacity: 0.45; }
25
+ 50% { opacity: 0.85; }
26
+ }
27
+ @media (prefers-reduced-motion: reduce) {
28
+ [data-agent-native-app-skeleton] [aria-hidden="true"] { animation: none; }
29
+ }
30
+ @media (max-width: 767px) {
31
+ [data-agent-native-app-skeleton] [data-agent-native-app-skeleton-sidebar] { display: none; }
32
+ }
33
+ ` }), _jsxs("aside", { "data-agent-native-app-skeleton-sidebar": "true", "aria-hidden": "true", style: {
34
+ display: "flex",
35
+ width: 248,
36
+ flexShrink: 0,
37
+ flexDirection: "column",
38
+ gap: 16,
39
+ borderRight: "1px solid hsl(var(--border, 240 5.9% 90%))",
40
+ padding: 16,
41
+ }, children: [_jsx(Block, { style: { width: 132, height: 32 } }), _jsx("div", { style: { display: "flex", flexDirection: "column", gap: 10 }, children: [0, 1, 2, 3, 4, 5].map((item) => (_jsx(Block, { style: { width: `${68 + (item % 3) * 14}%`, height: 14 } }, item))) })] }), _jsxs("main", { style: {
42
+ display: "flex",
43
+ minWidth: 0,
44
+ flex: 1,
45
+ flexDirection: "column",
46
+ }, children: [_jsxs("header", { "aria-hidden": "true", style: {
47
+ display: "flex",
48
+ height: 48,
49
+ flexShrink: 0,
50
+ alignItems: "center",
51
+ gap: 12,
52
+ borderBottom: "1px solid hsl(var(--border, 240 5.9% 90%))",
53
+ padding: "0 16px",
54
+ }, children: [_jsx(Block, { style: { width: 32, height: 32, borderRadius: 8 } }), _jsx(Block, { style: { width: 128, height: 14 } })] }), _jsxs("section", { "aria-hidden": "true", style: {
55
+ display: "flex",
56
+ width: "100%",
57
+ maxWidth: 960,
58
+ flex: 1,
59
+ flexDirection: "column",
60
+ gap: 12,
61
+ margin: "0 auto",
62
+ padding: 24,
63
+ }, children: [_jsx(Block, { style: { width: "38%", height: 28, marginBottom: 8 } }), _jsx(Block, { style: { width: "24%", height: 14, marginBottom: 16 } }), [0, 1, 2, 3, 4, 5].map((item) => (_jsxs("div", { style: { display: "flex", alignItems: "center", gap: 12 }, children: [_jsx(Block, { style: { width: 32, height: 32, borderRadius: 8 } }), _jsxs("div", { style: {
64
+ display: "flex",
65
+ flex: 1,
66
+ flexDirection: "column",
67
+ gap: 8,
68
+ }, children: [_jsx(Block, { style: { width: `${52 + (item % 3) * 12}%`, height: 12 } }), _jsx(Block, { style: { width: `${34 + (item % 4) * 10}%`, height: 10 } })] })] }, item)))] })] })] }));
69
+ }
@@ -3,7 +3,7 @@ import { type ReactNode } from "react";
3
3
  * Renders children only on the client (after hydration).
4
4
  *
5
5
  * Used in root.tsx to wrap all app content so the server only renders
6
- * the HTML shell (meta tags, styles, scripts) + a fallback spinner.
6
+ * the HTML shell (meta tags, styles, scripts) + an app-shell skeleton.
7
7
  * This prevents hydration mismatches from browser-only APIs like
8
8
  * window, localStorage, new Date(), next-themes, etc.
9
9
  */
@@ -4,7 +4,7 @@ const useBrowserLayoutEffect = typeof window === "undefined" ? useEffect : useLa
4
4
  * Renders children only on the client (after hydration).
5
5
  *
6
6
  * Used in root.tsx to wrap all app content so the server only renders
7
- * the HTML shell (meta tags, styles, scripts) + a fallback spinner.
7
+ * the HTML shell (meta tags, styles, scripts) + an app-shell skeleton.
8
8
  * This prevents hydration mismatches from browser-only APIs like
9
9
  * window, localStorage, new Date(), next-themes, etc.
10
10
  */
@@ -0,0 +1,6 @@
1
+ export declare function LanguagePicker({ className, includeSystem, label, variant, }: {
2
+ className?: string;
3
+ includeSystem?: boolean;
4
+ label?: string;
5
+ variant?: "select" | "icon" | "ghost-icon";
6
+ }): import("react").JSX.Element;