@agent-native/core 0.163.4 → 0.164.3

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 (228) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/app/components/agents/FeatureFlagsFleetPanel.tsx +78 -19
  3. package/corpus/templates/analytics/app/hooks/use-dashboard-chat-context.ts +29 -0
  4. package/corpus/templates/analytics/app/lib/use-auto-focus-select.ts +4 -4
  5. package/corpus/templates/analytics/app/pages/adhoc/explorer-dashboard/index.tsx +3 -0
  6. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +6 -0
  7. package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +1 -2
  8. package/corpus/templates/analytics/app/routes/_index.tsx +3 -2
  9. package/corpus/templates/analytics/app/routes/adhoc.$id.tsx +7 -2
  10. package/corpus/templates/analytics/app/routes/dashboard.tsx +3 -2
  11. package/corpus/templates/analytics/app/routes/overview.tsx +3 -2
  12. package/corpus/templates/analytics/app/routes/traffic.tsx +3 -2
  13. package/corpus/templates/analytics/changelog/2026-08-18-verify-cross-app-feature-flag-changes.md +6 -0
  14. package/corpus/templates/analytics/netlify.toml +2 -0
  15. package/corpus/templates/analytics/server/lib/workspace-feature-flags.ts +196 -48
  16. package/corpus/templates/analytics/server/plugins/feature-flags.ts +5 -0
  17. package/corpus/templates/analytics/shared/feature-flags.ts +10 -0
  18. package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +5 -1
  19. package/corpus/templates/assets/app/routes/brand-kits._index.tsx +4 -1
  20. package/corpus/templates/assets/app/routes/libraries.tsx +4 -1
  21. package/corpus/templates/assets/app/routes/picker.tsx +4 -1
  22. package/corpus/templates/assets/netlify.toml +2 -0
  23. package/corpus/templates/brain/netlify.toml +2 -0
  24. package/corpus/templates/calendar/app/components/calendar/DayView.tsx +2 -1
  25. package/corpus/templates/calendar/changelog/2026-08-19-calendar-page-loads-stay-fast-after-idle-periods.md +6 -0
  26. package/corpus/templates/calendar/netlify.toml +2 -0
  27. package/corpus/templates/chat/netlify.toml +2 -0
  28. package/corpus/templates/clips/app/components/player/player-controls.tsx +3 -3
  29. package/corpus/templates/clips/app/components/player/reaction-emojis.ts +12 -0
  30. package/corpus/templates/clips/app/components/player/reactions-tray.tsx +90 -9
  31. package/corpus/templates/clips/app/components/player/scrubber.tsx +43 -10
  32. package/corpus/templates/clips/app/components/player/video-player.tsx +105 -15
  33. package/corpus/templates/clips/app/routes/_app.settings._index.tsx +1 -2
  34. package/corpus/templates/clips/app/routes/_app.wispr.tsx +2 -1
  35. package/corpus/templates/clips/app/routes/_index.tsx +7 -3
  36. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +13 -8
  37. package/corpus/templates/clips/app/routes/share.$shareId.tsx +15 -8
  38. package/corpus/templates/clips/netlify.toml +2 -0
  39. package/corpus/templates/clips/server/routes/[...page].head.ts +5 -0
  40. package/corpus/templates/content/netlify.toml +2 -0
  41. package/corpus/templates/design/.agents/skills/design-editor-architecture/SKILL.md +103 -0
  42. package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +2 -1
  43. package/corpus/templates/design/AGENTS.md +3 -1
  44. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +3 -2
  45. package/corpus/templates/design/app/components/design/editor/AgentNativeMenuMark.tsx +25 -0
  46. package/corpus/templates/design/app/components/design/editor/DesignBottomToolbar.tsx +411 -0
  47. package/corpus/templates/design/app/components/design/editor/DesignCollaborators.tsx +153 -0
  48. package/corpus/templates/design/app/components/design/editor/DesignWorkspaceRail.tsx +231 -0
  49. package/corpus/templates/design/app/components/design/editor/MakeRealDialog.tsx +223 -0
  50. package/corpus/templates/design/app/components/design/editor/PendingScreenDeletionDialog.tsx +58 -0
  51. package/corpus/templates/design/app/components/design/editor/PendingVisualStyleWarningDialog.tsx +56 -0
  52. package/corpus/templates/design/app/components/design/editor/ReadOnlyEditorPanel.tsx +23 -0
  53. package/corpus/templates/design/app/components/design/editor/SaveTemplateDialog.tsx +161 -0
  54. package/corpus/templates/design/app/components/design/editor/toolbar-controls.tsx +185 -0
  55. package/corpus/templates/design/app/pages/DesignEditor.tsx +20913 -0
  56. package/corpus/templates/design/app/pages/design-editor/command-types.ts +120 -0
  57. package/corpus/templates/design/app/pages/design-editor/commands/README.md +193 -0
  58. package/corpus/templates/design/app/pages/design-editor/commands/add-auto-layout.ts +416 -0
  59. package/corpus/templates/design/app/pages/design-editor/commands/add-screen.ts +112 -0
  60. package/corpus/templates/design/app/pages/design-editor/commands/align-selection.ts +183 -0
  61. package/corpus/templates/design/app/pages/design-editor/commands/apply-design-editor-command.ts +243 -0
  62. package/corpus/templates/design/app/pages/design-editor/commands/apply-file-content-update.ts +236 -0
  63. package/corpus/templates/design/app/pages/design-editor/commands/apply-local-content-update.ts +304 -0
  64. package/corpus/templates/design/app/pages/design-editor/commands/apply-pending-visual-styles-with-agent.ts +376 -0
  65. package/corpus/templates/design/app/pages/design-editor/commands/apply-to-source.ts +132 -0
  66. package/corpus/templates/design/app/pages/design-editor/commands/can-move-layer.ts +117 -0
  67. package/corpus/templates/design/app/pages/design-editor/commands/change-selected-z-index.ts +212 -0
  68. package/corpus/templates/design/app/pages/design-editor/commands/commit-relative-style-delta-to-selected-layers.ts +176 -0
  69. package/corpus/templates/design/app/pages/design-editor/commands/commit-styles-to-selected-layers.ts +175 -0
  70. package/corpus/templates/design/app/pages/design-editor/commands/commit-visual-styles.ts +710 -0
  71. package/corpus/templates/design/app/pages/design-editor/commands/confirm-make-real.ts +99 -0
  72. package/corpus/templates/design/app/pages/design-editor/commands/copy-as-figma-svg.ts +95 -0
  73. package/corpus/templates/design/app/pages/design-editor/commands/copy-selection.ts +156 -0
  74. package/corpus/templates/design/app/pages/design-editor/commands/create-primitive.ts +291 -0
  75. package/corpus/templates/design/app/pages/design-editor/commands/create-screen-frame.ts +131 -0
  76. package/corpus/templates/design/app/pages/design-editor/commands/cross-screen-element-drop.ts +577 -0
  77. package/corpus/templates/design/app/pages/design-editor/commands/delete-files.ts +364 -0
  78. package/corpus/templates/design/app/pages/design-editor/commands/delete-selection.ts +521 -0
  79. package/corpus/templates/design/app/pages/design-editor/commands/detach-instance-menu-action.ts +88 -0
  80. package/corpus/templates/design/app/pages/design-editor/commands/distribute-selection.ts +114 -0
  81. package/corpus/templates/design/app/pages/design-editor/commands/download-all-screens-pdf.ts +116 -0
  82. package/corpus/templates/design/app/pages/design-editor/commands/download-pdf.ts +103 -0
  83. package/corpus/templates/design/app/pages/design-editor/commands/download-svg.ts +159 -0
  84. package/corpus/templates/design/app/pages/design-editor/commands/duplicate-screen.ts +201 -0
  85. package/corpus/templates/design/app/pages/design-editor/commands/duplicate-selection.ts +279 -0
  86. package/corpus/templates/design/app/pages/design-editor/commands/editor-paste.ts +81 -0
  87. package/corpus/templates/design/app/pages/design-editor/commands/enter-hotkey.ts +155 -0
  88. package/corpus/templates/design/app/pages/design-editor/commands/enter-single-screen.ts +168 -0
  89. package/corpus/templates/design/app/pages/design-editor/commands/escape-hotkey.ts +212 -0
  90. package/corpus/templates/design/app/pages/design-editor/commands/frame-selection.ts +119 -0
  91. package/corpus/templates/design/app/pages/design-editor/commands/geometry-commit.ts +169 -0
  92. package/corpus/templates/design/app/pages/design-editor/commands/get-selected-layer-snapshots.ts +177 -0
  93. package/corpus/templates/design/app/pages/design-editor/commands/group-selection.ts +127 -0
  94. package/corpus/templates/design/app/pages/design-editor/commands/iframe-context-menu.ts +121 -0
  95. package/corpus/templates/design/app/pages/design-editor/commands/import-figma-clipboard-into-design.ts +119 -0
  96. package/corpus/templates/design/app/pages/design-editor/commands/layer-marquee-selection-change.ts +163 -0
  97. package/corpus/templates/design/app/pages/design-editor/commands/layer-move-to-screen.ts +331 -0
  98. package/corpus/templates/design/app/pages/design-editor/commands/layer-move.ts +517 -0
  99. package/corpus/templates/design/app/pages/design-editor/commands/layer-rename.ts +247 -0
  100. package/corpus/templates/design/app/pages/design-editor/commands/layer-selection-change.ts +161 -0
  101. package/corpus/templates/design/app/pages/design-editor/commands/mode-change.ts +122 -0
  102. package/corpus/templates/design/app/pages/design-editor/commands/nudge-selection.ts +213 -0
  103. package/corpus/templates/design/app/pages/design-editor/commands/overview-primitive-reparent.ts +318 -0
  104. package/corpus/templates/design/app/pages/design-editor/commands/paste-copied-screens.ts +114 -0
  105. package/corpus/templates/design/app/pages/design-editor/commands/paste-over-selection.ts +70 -0
  106. package/corpus/templates/design/app/pages/design-editor/commands/paste-selection.ts +436 -0
  107. package/corpus/templates/design/app/pages/design-editor/commands/paste-to-replace.ts +135 -0
  108. package/corpus/templates/design/app/pages/design-editor/commands/pasted-image-files.ts +209 -0
  109. package/corpus/templates/design/app/pages/design-editor/commands/persist-frame-geometry-save.ts +113 -0
  110. package/corpus/templates/design/app/pages/design-editor/commands/persist-tweak-save.ts +160 -0
  111. package/corpus/templates/design/app/pages/design-editor/commands/primitive-created.ts +168 -0
  112. package/corpus/templates/design/app/pages/design-editor/commands/record-pending-live-layer-state-edit.ts +149 -0
  113. package/corpus/templates/design/app/pages/design-editor/commands/record-pending-live-structure-edit.ts +200 -0
  114. package/corpus/templates/design/app/pages/design-editor/commands/record-pending-live-text-edit.ts +152 -0
  115. package/corpus/templates/design/app/pages/design-editor/commands/record-pending-visual-style-edit.ts +247 -0
  116. package/corpus/templates/design/app/pages/design-editor/commands/redo.ts +1086 -0
  117. package/corpus/templates/design/app/pages/design-editor/commands/render-png-blob.ts +200 -0
  118. package/corpus/templates/design/app/pages/design-editor/commands/save-file-content.ts +207 -0
  119. package/corpus/templates/design/app/pages/design-editor/commands/screen-element-select.ts +262 -0
  120. package/corpus/templates/design/app/pages/design-editor/commands/screen-text-content-change.ts +216 -0
  121. package/corpus/templates/design/app/pages/design-editor/commands/screen-visual-duplicate-change.ts +108 -0
  122. package/corpus/templates/design/app/pages/design-editor/commands/screen-visual-structure-change.ts +280 -0
  123. package/corpus/templates/design/app/pages/design-editor/commands/screen-visual-style-change.ts +151 -0
  124. package/corpus/templates/design/app/pages/design-editor/commands/send-overview-annotations.ts +88 -0
  125. package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-move-semantic-handoff.ts +122 -0
  126. package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-semantic-handoff.ts +143 -0
  127. package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-state-semantic-handoff.ts +115 -0
  128. package/corpus/templates/design/app/pages/design-editor/commands/start-retry-generation.ts +152 -0
  129. package/corpus/templates/design/app/pages/design-editor/commands/start-sidebar-resize.ts +99 -0
  130. package/corpus/templates/design/app/pages/design-editor/commands/style-change.ts +152 -0
  131. package/corpus/templates/design/app/pages/design-editor/commands/styles-change.ts +155 -0
  132. package/corpus/templates/design/app/pages/design-editor/commands/suggest-auto-layout.ts +125 -0
  133. package/corpus/templates/design/app/pages/design-editor/commands/text-content-change.ts +201 -0
  134. package/corpus/templates/design/app/pages/design-editor/commands/tidy-up.ts +123 -0
  135. package/corpus/templates/design/app/pages/design-editor/commands/toggle-layer-hidden.ts +167 -0
  136. package/corpus/templates/design/app/pages/design-editor/commands/toggle-layer-locked.ts +175 -0
  137. package/corpus/templates/design/app/pages/design-editor/commands/toggle-motion-keyframe.ts +99 -0
  138. package/corpus/templates/design/app/pages/design-editor/commands/tweak-prompt-submit.ts +84 -0
  139. package/corpus/templates/design/app/pages/design-editor/commands/undo.ts +906 -0
  140. package/corpus/templates/design/app/pages/design-editor/commands/ungroup-selection.ts +170 -0
  141. package/corpus/templates/design/app/pages/design-editor/commands/visual-duplicate-change.ts +119 -0
  142. package/corpus/templates/design/app/pages/design-editor/commands/visual-structure-change.ts +274 -0
  143. package/corpus/templates/design/app/pages/design-editor/commands/write-frame-geometry-snapshot.ts +99 -0
  144. package/corpus/templates/design/app/pages/design-editor/derive/design-breakpoints.ts +56 -0
  145. package/corpus/templates/design/app/pages/design-editor/derive/overview-screens.ts +146 -0
  146. package/corpus/templates/design/app/pages/design-editor/domains/use-tweaks.ts +326 -0
  147. package/corpus/templates/design/app/pages/design-editor/editor-constants.ts +54 -0
  148. package/corpus/templates/design/app/pages/design-editor/editor-helpers.ts +183 -0
  149. package/corpus/templates/design/app/pages/design-editor/effects/adopt-db-file-content.ts +270 -0
  150. package/corpus/templates/design/app/pages/design-editor/effects/mirror-selection-to-agent-chat.ts +134 -0
  151. package/corpus/templates/design/app/pages/design-editor/effects/motion-autosave.ts +335 -0
  152. package/corpus/templates/design/app/pages/design-editor/effects/observe-collab-text.ts +183 -0
  153. package/corpus/templates/design/app/pages/design-editor/effects/publish-agent-selection-context.ts +252 -0
  154. package/corpus/templates/design/app/pages/design-editor/effects/resume-pending-generation.ts +178 -0
  155. package/corpus/templates/design/app/pages/design-editor/effects/seed-collab-content.ts +157 -0
  156. package/corpus/templates/design/app/pages/design-editor/preview-html.ts +19 -0
  157. package/corpus/templates/design/app/routes/examples.tsx +2 -1
  158. package/corpus/templates/design/netlify.toml +2 -0
  159. package/corpus/templates/design/shared/board-file.ts +2 -1
  160. package/corpus/templates/dispatch/netlify.toml +2 -0
  161. package/corpus/templates/forms/app/routes/_index.tsx +3 -2
  162. package/corpus/templates/forms/netlify.toml +2 -0
  163. package/corpus/templates/mail/app/routes/_index.tsx +3 -2
  164. package/corpus/templates/mail/netlify.toml +2 -0
  165. package/corpus/templates/plan/netlify.toml +2 -0
  166. package/corpus/templates/slides/netlify.toml +2 -0
  167. package/corpus/templates/tasks/app/routes/_index.tsx +2 -1
  168. package/dist/agent/engine/builder-engine.d.ts +6 -4
  169. package/dist/agent/engine/builder-engine.js +91 -26
  170. package/dist/agent/engine/registry.js +16 -0
  171. package/dist/cli/code-agent-agent-tools.d.ts +2 -0
  172. package/dist/cli/code-agent-agent-tools.js +188 -0
  173. package/dist/cli/code-agent-collaboration.d.ts +34 -0
  174. package/dist/cli/code-agent-collaboration.js +104 -0
  175. package/dist/cli/code-agent-executor.js +6 -0
  176. package/dist/cli/code-agent-schedules.d.ts +54 -0
  177. package/dist/cli/code-agent-schedules.js +198 -0
  178. package/dist/client/AgentPanel.js +1 -1
  179. package/dist/client/ConnectBuilderCard.js +5 -2
  180. package/dist/client/EnvironmentBadge.js +6 -5
  181. package/dist/client/chat/run-recovery.js +3 -2
  182. package/dist/client/chat/tool-call-display.js +2 -3
  183. package/dist/client/components/CodeRequiredDialog.js +4 -2
  184. package/dist/client/i18n.js +5 -4
  185. package/dist/client/settings/SettingsPanel.js +1 -1
  186. package/dist/client/settings/VoiceTranscriptionSection.js +1 -1
  187. package/dist/client/settings/useBuilderStatus.d.ts +6 -1
  188. package/dist/client/settings/useBuilderStatus.js +22 -33
  189. package/dist/client/transcription/BuilderTranscriptionCta.js +1 -1
  190. package/dist/code-agents/index.d.ts +2 -0
  191. package/dist/code-agents/index.js +2 -0
  192. package/dist/collab/awareness.d.ts +2 -2
  193. package/dist/collab/routes.d.ts +1 -1
  194. package/dist/deploy/build.js +10 -4
  195. package/dist/localization/shared.d.ts +2 -0
  196. package/dist/localization/shared.js +5 -0
  197. package/dist/mcp-client/oauth-client.d.ts +1 -0
  198. package/dist/mcp-client/oauth-client.js +50 -1
  199. package/dist/notifications/routes.d.ts +3 -3
  200. package/dist/observability/routes.d.ts +1 -1
  201. package/dist/provider-api/actions/provider-api.d.ts +2 -2
  202. package/dist/server/auth-marketing-locales.d.ts +7 -0
  203. package/dist/server/auth-marketing-locales.js +1322 -0
  204. package/dist/server/auth-marketing.d.ts +1 -0
  205. package/dist/server/auth-marketing.js +35 -6
  206. package/dist/server/auth.js +4 -17
  207. package/dist/server/builder-browser.d.ts +22 -0
  208. package/dist/server/builder-browser.js +77 -1
  209. package/dist/server/builder-oauth.d.ts +50 -0
  210. package/dist/server/builder-oauth.js +263 -0
  211. package/dist/server/core-routes-plugin.d.ts +11 -0
  212. package/dist/server/core-routes-plugin.js +291 -415
  213. package/dist/server/credential-provider.d.ts +1 -1
  214. package/dist/server/credential-provider.js +1 -1
  215. package/dist/server/csrf.js +2 -2
  216. package/dist/server/onboarding-html.js +52 -120
  217. package/dist/server/ssr-handler.js +13 -4
  218. package/dist/settings/store.d.ts +9 -0
  219. package/dist/settings/store.js +19 -0
  220. package/dist/shared/cache-control.d.ts +22 -0
  221. package/dist/shared/cache-control.js +25 -0
  222. package/dist/shared/index.d.ts +1 -0
  223. package/dist/shared/index.js +1 -0
  224. package/dist/templates/chat/netlify.toml +2 -0
  225. package/docs/content/deployment.mdx +2 -0
  226. package/docs/content/multi-app-workspace.mdx +1 -1
  227. package/package.json +2 -2
  228. package/src/templates/chat/netlify.toml +2 -0
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: 8328
34
+ - template files: 8445
@@ -9,7 +9,7 @@ import {
9
9
  } from "@agent-native/core/client/hooks";
10
10
  import { useT } from "@agent-native/core/client/i18n";
11
11
  import { IconRefresh } from "@tabler/icons-react";
12
- import { useQueryClient } from "@tanstack/react-query";
12
+ import { type QueryClient, useQueryClient } from "@tanstack/react-query";
13
13
 
14
14
  import { Badge } from "@/components/ui/badge";
15
15
  import { Button } from "@/components/ui/button";
@@ -40,6 +40,51 @@ export interface FlagDirectory {
40
40
  apps?: FlagApp[];
41
41
  }
42
42
 
43
+ interface VerifiedFlagMutation {
44
+ contractVersion: 3;
45
+ status: "verified";
46
+ key: string;
47
+ rules: FeatureFlagMetadata["rules"];
48
+ enabledForCurrentUser: boolean;
49
+ }
50
+
51
+ export function reconcileVerifiedFleetMutation(
52
+ value: unknown,
53
+ targetAppId: string,
54
+ verified: VerifiedFlagMutation,
55
+ ): FlagDirectory {
56
+ const data = asDirectory(value);
57
+ return {
58
+ ...data,
59
+ apps: data.apps?.map((app) =>
60
+ appId(app) !== targetAppId
61
+ ? app
62
+ : {
63
+ ...app,
64
+ flags: app.flags?.map((flag) =>
65
+ flag.key === verified.key
66
+ ? {
67
+ ...flag,
68
+ rules: verified.rules,
69
+ enabledForCurrentUser: verified.enabledForCurrentUser,
70
+ }
71
+ : flag,
72
+ ),
73
+ },
74
+ ),
75
+ };
76
+ }
77
+
78
+ export function recoverFleetMutationFailure(
79
+ client: QueryClient,
80
+ context?: { previous: unknown; key: readonly unknown[] },
81
+ ) {
82
+ if (context) client.setQueryData(context.key, context.previous);
83
+ void client.invalidateQueries({
84
+ queryKey: ["action", "list-workspace-feature-flags"],
85
+ });
86
+ }
87
+
43
88
  function asDirectory(value: unknown): FlagDirectory {
44
89
  return value && typeof value === "object" ? (value as FlagDirectory) : {};
45
90
  }
@@ -76,9 +121,10 @@ export function FeatureFlagsFleetPanel() {
76
121
  { retry: false },
77
122
  );
78
123
  const mutation = useActionMutation<
79
- unknown,
124
+ VerifiedFlagMutation | unknown,
80
125
  { appId: string } & SetFeatureFlagInput
81
126
  >("set-workspace-feature-flag", {
127
+ skipActionQueryInvalidation: true,
82
128
  onMutate: async (input) => {
83
129
  await client.cancelQueries({
84
130
  queryKey: ["action", "list-workspace-feature-flags"],
@@ -119,13 +165,25 @@ export function FeatureFlagsFleetPanel() {
119
165
  });
120
166
  return { previous, key };
121
167
  },
122
- onError: (_error, _input, context: any) => {
123
- if (context) client.setQueryData(context.key, context.previous);
168
+ onError: (_error, _input, context: any) =>
169
+ recoverFleetMutationFailure(client, context),
170
+ onSuccess: (result, input, context: any) => {
171
+ if (
172
+ !result ||
173
+ typeof result !== "object" ||
174
+ (result as Partial<VerifiedFlagMutation>).contractVersion !== 3 ||
175
+ (result as Partial<VerifiedFlagMutation>).status !== "verified"
176
+ ) {
177
+ void client.invalidateQueries({
178
+ queryKey: ["action", "list-workspace-feature-flags"],
179
+ });
180
+ return;
181
+ }
182
+ const verified = result as VerifiedFlagMutation;
183
+ client.setQueryData(context.key, (old: unknown) =>
184
+ reconcileVerifiedFleetMutation(old, input.appId, verified),
185
+ );
124
186
  },
125
- onSettled: () =>
126
- void client.invalidateQueries({
127
- queryKey: ["action", "list-workspace-feature-flags"],
128
- }),
129
187
  });
130
188
  const directory = asDirectory(flags.data);
131
189
  const apps = directory.apps ?? [];
@@ -134,7 +192,11 @@ export function FeatureFlagsFleetPanel() {
134
192
  return (
135
193
  <StatusState
136
194
  title={t("agents.flagsUnavailable")}
137
- detail={flags.error?.message || t("agents.flagsUnreachable")}
195
+ detail={
196
+ mutation.error?.message ||
197
+ flags.error?.message ||
198
+ t("agents.flagsUnreachable")
199
+ }
138
200
  onRetry={() => void flags.refetch()}
139
201
  />
140
202
  );
@@ -179,22 +241,19 @@ export function FeatureFlagsFleetPanel() {
179
241
  </div>
180
242
  {isReady(app) ? (
181
243
  <div className="p-4">
244
+ {mutation.variables?.appId === appId(app) && mutation.error ? (
245
+ <p className="mb-3 text-sm text-destructive">
246
+ {mutation.error.message}
247
+ </p>
248
+ ) : null}
182
249
  <FeatureFlagsEditor
183
250
  flags={(app.flags ?? []).filter(
184
251
  (flag): flag is FeatureFlagMetadata =>
185
252
  !!flag.rules && typeof flag.defaultValue === "boolean",
186
253
  )}
187
254
  isPending={mutation.isPending}
188
- error={
189
- mutation.variables?.appId === appId(app)
190
- ? mutation.error
191
- : null
192
- }
193
- errorFlagKey={
194
- mutation.variables?.appId === appId(app)
195
- ? mutation.variables.key
196
- : null
197
- }
255
+ error={null}
256
+ errorFlagKey={null}
198
257
  showHeader={false}
199
258
  onMutate={(input) =>
200
259
  mutation.mutate(qualifyFleetMutation(appId(app), input))
@@ -132,6 +132,7 @@ export function useDashboardChatContext(
132
132
  : null;
133
133
  const hasSelectedPanel = selectedPanelId !== null;
134
134
  const publishedSelectionRef = useRef<SelectedDashboardObject | null>(null);
135
+ const suppressDashboardContextRef = useRef(false);
135
136
 
136
137
  const selectPanelForChat = useCallback(
137
138
  (
@@ -140,6 +141,7 @@ export function useDashboardChatContext(
140
141
  ) => {
141
142
  if (!id) return;
142
143
  if (options.openSidebar !== true && !isAgentSidebarOpen) return;
144
+ suppressDashboardContextRef.current = false;
143
145
  const displayDashboardTitle = title?.trim() || id;
144
146
  const displayPanelTitle = panel.panelTitle.trim() || panel.panelId;
145
147
  const contextLines = [
@@ -211,13 +213,38 @@ export function useDashboardChatContext(
211
213
  );
212
214
  }, []);
213
215
 
216
+ useEffect(() => {
217
+ const handleNewChat = () => {
218
+ removeAgentChatContextItem({
219
+ key: DASHBOARD_CONTEXT_KEY,
220
+ openSidebar: false,
221
+ });
222
+ removeAgentChatContextItem({
223
+ key: DASHBOARD_PANEL_CONTEXT_KEY,
224
+ openSidebar: false,
225
+ });
226
+ const publishedSelection = publishedSelectionRef.current;
227
+ publishedSelectionRef.current = null;
228
+ suppressDashboardContextRef.current = true;
229
+ if (publishedSelection) {
230
+ void clearSelectedDashboardObjectIfOwned(publishedSelection);
231
+ }
232
+ };
233
+
234
+ window.addEventListener("agent-chat:new-chat", handleNewChat);
235
+ return () =>
236
+ window.removeEventListener("agent-chat:new-chat", handleNewChat);
237
+ }, []);
238
+
214
239
  // Dashboard metadata lands in pieces — title first, then panel count, then
215
240
  // the access role. Publishing each piece costs a round-trip and a sync event
216
241
  // that invalidates every mounted query, so only the settled value is sent.
217
242
  useEffect(() => {
218
243
  if (!id) return;
244
+ suppressDashboardContextRef.current = false;
219
245
  const displayTitle = title?.trim() || id;
220
246
  const timer = setTimeout(() => {
247
+ if (suppressDashboardContextRef.current) return;
221
248
  setAgentChatContextItem({
222
249
  key: DASHBOARD_CONTEXT_KEY,
223
250
  title: `Dashboard: ${displayTitle}`,
@@ -237,6 +264,7 @@ export function useDashboardChatContext(
237
264
 
238
265
  useEffect(() => {
239
266
  if (!id || hasSelectedPanel) return;
267
+ if (suppressDashboardContextRef.current) return;
240
268
  const displayTitle = title?.trim() || id;
241
269
  const selection: SelectedDashboardObject = {
242
270
  type: "dashboard",
@@ -248,6 +276,7 @@ export function useDashboardChatContext(
248
276
  [SELECTED_OBJECT_SOURCE_FIELD]: TAB_ID,
249
277
  };
250
278
  const timer = setTimeout(() => {
279
+ if (suppressDashboardContextRef.current) return;
251
280
  setClientAppState(SELECTED_OBJECT_STATE_KEY, selection, {
252
281
  keepalive: true,
253
282
  requestSource: TAB_ID,
@@ -1,9 +1,9 @@
1
1
  import { useEffect, useRef, type RefObject } from "react";
2
2
 
3
- /** Focus an input and select its existing value after the next paint. */
4
- export function useAutoFocusSelect<T extends HTMLInputElement>(
5
- enabled: boolean,
6
- ): RefObject<T | null> {
3
+ /** Focus an input/textarea and select its existing value after the next paint. */
4
+ export function useAutoFocusSelect<
5
+ T extends HTMLInputElement | HTMLTextAreaElement,
6
+ >(enabled: boolean): RefObject<T | null> {
7
7
  const inputRef = useRef<T | null>(null);
8
8
 
9
9
  useEffect(() => {
@@ -93,6 +93,7 @@ import {
93
93
  resourceCanManage,
94
94
  type ResourceAccess,
95
95
  } from "@/lib/resource-access";
96
+ import { useAutoFocusSelect } from "@/lib/use-auto-focus-select";
96
97
 
97
98
  import { DashboardSkeleton } from "../DashboardSkeleton";
98
99
  import { DashboardChartCard } from "./ChartCard";
@@ -206,6 +207,7 @@ export default function ExplorerDashboardPage() {
206
207
  );
207
208
  const [editingName, setEditingName] = useState(false);
208
209
  const [nameInput, setNameInput] = useState("");
210
+ const nameInputRef = useAutoFocusSelect<HTMLInputElement>(editingName);
209
211
  const [addChartOpen, setAddChartOpen] = useState(false);
210
212
  const [loaded, setLoaded] = useState(false);
211
213
  const [confirmDeleteOpen, setConfirmDeleteOpen] = useState(false);
@@ -635,6 +637,7 @@ export default function ExplorerDashboardPage() {
635
637
  ) : null}
636
638
  {editingName && canEdit ? (
637
639
  <Input
640
+ ref={nameInputRef}
638
641
  value={nameInput}
639
642
  onChange={(e) => setNameInput(e.target.value)}
640
643
  onBlur={handleSaveName}
@@ -129,6 +129,7 @@ import {
129
129
  resourceCanManage,
130
130
  type ResourceAccess,
131
131
  } from "@/lib/resource-access";
132
+ import { useAutoFocusSelect } from "@/lib/use-auto-focus-select";
132
133
 
133
134
  import BlankDashboard from "../BlankDashboard";
134
135
  import { DashboardSkeleton } from "../DashboardSkeleton";
@@ -598,8 +599,11 @@ function SqlDashboardPageContent({
598
599
  );
599
600
  const [editingName, setEditingName] = useState(false);
600
601
  const [nameInput, setNameInput] = useState("");
602
+ const nameInputRef = useAutoFocusSelect<HTMLInputElement>(editingName);
601
603
  const [editingDescription, setEditingDescription] = useState(false);
602
604
  const [descriptionInput, setDescriptionInput] = useState("");
605
+ const descriptionInputRef =
606
+ useAutoFocusSelect<HTMLTextAreaElement>(editingDescription);
603
607
  const [loaded, setLoaded] = useState(false);
604
608
  const [confirmDeleteOpen, setConfirmDeleteOpen] = useState(false);
605
609
  const [openDeleteAfterMenuClose, setOpenDeleteAfterMenuClose] =
@@ -1734,6 +1738,7 @@ function SqlDashboardPageContent({
1734
1738
  <div className="flex min-w-0 items-center gap-2">
1735
1739
  {editingName && canEdit ? (
1736
1740
  <Input
1741
+ ref={nameInputRef}
1737
1742
  value={nameInput}
1738
1743
  onChange={(e) => setNameInput(e.target.value)}
1739
1744
  onBlur={handleSaveName}
@@ -2159,6 +2164,7 @@ function SqlDashboardPageContent({
2159
2164
  {/* Description (click to edit) */}
2160
2165
  {editingDescription && canEdit ? (
2161
2166
  <Textarea
2167
+ ref={descriptionInputRef}
2162
2168
  value={descriptionInput}
2163
2169
  onChange={(e) => setDescriptionInput(e.target.value)}
2164
2170
  onBlur={handleSaveDescription}
@@ -526,8 +526,7 @@ export function ReplayStorageHint({
526
526
  const storageStatus = useReplayStorageStatus();
527
527
  const builderStatus = useBuilderStatus();
528
528
  const builderConnect = useBuilderConnectFlow({
529
- popupUrl:
530
- builderStatus.status?.cliAuthUrl ?? builderStatus.status?.connectUrl,
529
+ popupUrl: builderStatus.status?.connectUrl,
531
530
  trackingSource: "analytics_sessions_storage_hint",
532
531
  trackingFlow: "replay_storage",
533
532
  onConnected: async () => {
@@ -1,3 +1,4 @@
1
+ import { withSsrHtmlContentType } from "@agent-native/core/shared";
1
2
  import { redirect, type LoaderFunctionArgs } from "react-router";
2
3
 
3
4
  const SEO_TITLE =
@@ -25,11 +26,11 @@ function target(url: URL): string {
25
26
  }
26
27
 
27
28
  export function loader({ url }: LoaderFunctionArgs) {
28
- throw redirect(target(url));
29
+ throw withSsrHtmlContentType(redirect(target(url)), { varyByQuery: true });
29
30
  }
30
31
 
31
32
  export function clientLoader({ url }: LoaderFunctionArgs) {
32
- throw redirect(target(url));
33
+ throw withSsrHtmlContentType(redirect(target(url)), { varyByQuery: true });
33
34
  }
34
35
 
35
36
  export default function IndexRoute() {
@@ -1,3 +1,4 @@
1
+ import { withSsrHtmlContentType } from "@agent-native/core/shared";
1
2
  import { redirect, type LoaderFunctionArgs } from "react-router";
2
3
 
3
4
  // `/adhoc/:id` is the legacy dashboard URL. The canonical, user-facing URL is
@@ -9,11 +10,15 @@ function target({ params, url }: LoaderFunctionArgs): string {
9
10
  }
10
11
 
11
12
  export function loader(args: LoaderFunctionArgs) {
12
- throw redirect(target(args));
13
+ throw withSsrHtmlContentType(redirect(target(args)), {
14
+ varyByQuery: true,
15
+ });
13
16
  }
14
17
 
15
18
  export function clientLoader(args: LoaderFunctionArgs) {
16
- throw redirect(target(args));
19
+ throw withSsrHtmlContentType(redirect(target(args)), {
20
+ varyByQuery: true,
21
+ });
17
22
  }
18
23
 
19
24
  export default function AdhocRedirectRoute() {
@@ -1,3 +1,4 @@
1
+ import { withSsrHtmlContentType } from "@agent-native/core/shared";
1
2
  import { redirect, type LoaderFunctionArgs } from "react-router";
2
3
 
3
4
  function target(url: URL): string {
@@ -5,11 +6,11 @@ function target(url: URL): string {
5
6
  }
6
7
 
7
8
  export function loader({ url }: LoaderFunctionArgs) {
8
- throw redirect(target(url));
9
+ throw withSsrHtmlContentType(redirect(target(url)), { varyByQuery: true });
9
10
  }
10
11
 
11
12
  export function clientLoader({ url }: LoaderFunctionArgs) {
12
- throw redirect(target(url));
13
+ throw withSsrHtmlContentType(redirect(target(url)), { varyByQuery: true });
13
14
  }
14
15
 
15
16
  export default function DashboardAliasRoute() {
@@ -1,3 +1,4 @@
1
+ import { withSsrHtmlContentType } from "@agent-native/core/shared";
1
2
  import { redirect, type LoaderFunctionArgs } from "react-router";
2
3
 
3
4
  function target(url: URL): string {
@@ -5,11 +6,11 @@ function target(url: URL): string {
5
6
  }
6
7
 
7
8
  export function loader({ url }: LoaderFunctionArgs) {
8
- throw redirect(target(url));
9
+ throw withSsrHtmlContentType(redirect(target(url)), { varyByQuery: true });
9
10
  }
10
11
 
11
12
  export function clientLoader({ url }: LoaderFunctionArgs) {
12
- throw redirect(target(url));
13
+ throw withSsrHtmlContentType(redirect(target(url)), { varyByQuery: true });
13
14
  }
14
15
 
15
16
  export default function OverviewAliasRoute() {
@@ -1,3 +1,4 @@
1
+ import { withSsrHtmlContentType } from "@agent-native/core/shared";
1
2
  import { redirect, type LoaderFunctionArgs } from "react-router";
2
3
 
3
4
  const TRAFFIC_DASHBOARD_PATH = "/dashboards/agent-native-templates-first-party";
@@ -7,11 +8,11 @@ function target(url: URL): string {
7
8
  }
8
9
 
9
10
  export function loader({ url }: LoaderFunctionArgs) {
10
- throw redirect(target(url));
11
+ throw withSsrHtmlContentType(redirect(target(url)), { varyByQuery: true });
11
12
  }
12
13
 
13
14
  export function clientLoader({ url }: LoaderFunctionArgs) {
14
- throw redirect(target(url));
15
+ throw withSsrHtmlContentType(redirect(target(url)), { varyByQuery: true });
15
16
  }
16
17
 
17
18
  export default function TrafficDashboardAliasRoute() {
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-08-18
4
+ ---
5
+
6
+ Feature flag changes now preserve actionable failures and verify the target app's persisted state.
@@ -20,6 +20,8 @@ AGENT_CHAT_DURABLE_BACKGROUND = "true"
20
20
 
21
21
  [context.production.environment]
22
22
  AGENT_NATIVE_HOSTED_HARNESS = "true"
23
+ AGENT_NATIVE_ENABLE_KEEP_WARM = "1"
24
+ AGENT_NATIVE_DISABLE_KEEP_WARM_BACKGROUND = "1"
23
25
  # Analytics owns its schema at release time (`migrate:production` above), so
24
26
  # production request functions skip migrations. Preview functions still run
25
27
  # request-path migrations because previews do not run the production release