@agent-native/core 0.120.2 → 0.120.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 (266) hide show
  1. package/corpus/README.md +3 -3
  2. package/corpus/core/CHANGELOG.md +20 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/cli/context-xray-local.ts +1 -1
  5. package/corpus/core/src/cli/index.ts +63 -18
  6. package/corpus/core/src/cli/skills.ts +5 -0
  7. package/corpus/core/src/cli/telemetry.ts +118 -1
  8. package/corpus/core/src/client/AgentPanel.tsx +10 -0
  9. package/corpus/core/src/client/CommandMenu.tsx +13 -1
  10. package/corpus/core/src/client/agent-page/AgentTabsPage.tsx +39 -4
  11. package/corpus/core/src/client/analytics.ts +13 -0
  12. package/corpus/core/src/client/error-capture.ts +6 -1
  13. package/corpus/core/src/client/extensions/ExtensionsListPage.tsx +12 -5
  14. package/corpus/core/src/client/extensions/agent-native-extension-runtime.ts +1 -1
  15. package/corpus/core/src/client/navigation/index.ts +2 -0
  16. package/corpus/core/src/client/org/OrgSwitcher.tsx +14 -32
  17. package/corpus/core/src/client/settings/ExtensionsSettingsContent.tsx +1 -1
  18. package/corpus/core/src/extensions/theme.ts +1 -1
  19. package/corpus/core/src/localization/default-messages.ts +2 -0
  20. package/corpus/core/src/server/core-routes-plugin.ts +10 -1
  21. package/corpus/core/src/server/framework-request-handler.ts +17 -26
  22. package/corpus/core/src/styles/agent-native.css +13 -0
  23. package/corpus/core/src/templates/chat/app/components/layout/Layout.tsx +3 -0
  24. package/corpus/core/src/templates/chat/app/components/layout/Sidebar.tsx +78 -45
  25. package/corpus/core/src/templates/chat/app/global.css +1 -1
  26. package/corpus/core/src/templates/default/app/global.css +1 -1
  27. package/corpus/core/src/tracking/error-capture.ts +151 -0
  28. package/corpus/core/src/tracking/index.ts +5 -0
  29. package/corpus/templates/analytics/app/components/dashboard/CumulativeNetChart.tsx +1 -1
  30. package/corpus/templates/analytics/app/components/dashboard/DashboardHistoryPanel.tsx +1 -4
  31. package/corpus/templates/analytics/app/components/dashboard/DashboardPanelSkeleton.tsx +1 -1
  32. package/corpus/templates/analytics/app/components/dashboard/DataTable.tsx +1 -1
  33. package/corpus/templates/analytics/app/components/dashboard/DateRangePicker.tsx +2 -2
  34. package/corpus/templates/analytics/app/components/dashboard/MetricCard.tsx +1 -1
  35. package/corpus/templates/analytics/app/components/dashboard/RecentActivity.tsx +1 -1
  36. package/corpus/templates/analytics/app/components/dashboard/RevenueChart.tsx +1 -1
  37. package/corpus/templates/analytics/app/components/dashboard/RevenueComparisonChart.tsx +1 -1
  38. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +41 -9
  39. package/corpus/templates/analytics/app/components/dashboard/StatsCard.tsx +1 -1
  40. package/corpus/templates/analytics/app/components/dashboard/TimeSeriesChart.tsx +1 -1
  41. package/corpus/templates/analytics/app/components/layout/CommandPalette.tsx +2 -0
  42. package/corpus/templates/analytics/app/components/layout/Layout.tsx +28 -14
  43. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +152 -124
  44. package/corpus/templates/analytics/app/global.css +5 -5
  45. package/corpus/templates/analytics/app/lib/dashboard-report-capture.ts +42 -0
  46. package/corpus/templates/analytics/app/pages/adhoc/_shared/KpiChart.tsx +1 -1
  47. package/corpus/templates/analytics/app/pages/adhoc/explorer/components/ChartTypePicker.tsx +1 -1
  48. package/corpus/templates/analytics/app/pages/adhoc/explorer/components/DateRangePicker.tsx +1 -1
  49. package/corpus/templates/analytics/app/pages/adhoc/explorer/components/EventRow.tsx +1 -1
  50. package/corpus/templates/analytics/app/pages/adhoc/explorer/components/SqlPreview.tsx +2 -2
  51. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/DashboardFilterBar.tsx +3 -3
  52. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/EmailReportDialog.tsx +2 -2
  53. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/PanelEditorDialog.tsx +1 -1
  54. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +1 -1
  55. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +162 -51
  56. package/corpus/templates/analytics/app/root.tsx +28 -0
  57. package/corpus/templates/analytics/changelog/2026-07-24-analytics-charts-now-explain-slow-loads-and-offer-a-direct-r.md +6 -0
  58. package/corpus/templates/analytics/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  59. package/corpus/templates/analytics/changelog/2026-07-24-daily-dashboard-emails-now-load-signed-reports-more-reliably.md +6 -0
  60. package/corpus/templates/analytics/changelog/2026-07-24-manage-agent-is-clearly-marked-as-a-link-to-its-dedicated-pa.md +6 -0
  61. package/corpus/templates/analytics/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  62. package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +1 -1
  63. package/corpus/templates/analytics/server/db/schema.ts +5 -0
  64. package/corpus/templates/analytics/server/jobs/dashboard-report.ts +21 -0
  65. package/corpus/templates/analytics/server/lib/canonical-first-party-dashboard-repair.ts +11 -0
  66. package/corpus/templates/analytics/server/lib/dashboard-report-subscriptions.ts +54 -0
  67. package/corpus/templates/analytics/server/lib/dashboard-report.ts +235 -26
  68. package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +4 -1
  69. package/corpus/templates/analytics/server/plugins/db.ts +9 -0
  70. package/corpus/templates/analytics/shared/dashboard-report-timeouts.ts +1 -1
  71. package/corpus/templates/assets/app/components/asset/AssetPreviewDialog.tsx +376 -0
  72. package/corpus/templates/assets/app/components/create/RecentDraftsSection.tsx +14 -4
  73. package/corpus/templates/assets/app/components/layout/Layout.tsx +5 -0
  74. package/corpus/templates/assets/app/components/layout/Sidebar.tsx +118 -74
  75. package/corpus/templates/assets/app/global.css +1 -1
  76. package/corpus/templates/assets/app/i18n-data.ts +10 -0
  77. package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +99 -10
  78. package/corpus/templates/assets/app/routes/library.tsx +21 -198
  79. package/corpus/templates/assets/changelog/2026-07-21-unified-asset-preview-click-any-asset-to-open-one-preview-wi.md +6 -0
  80. package/corpus/templates/assets/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  81. package/corpus/templates/assets/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  82. package/corpus/templates/brain/app/components/layout/Layout.tsx +3 -0
  83. package/corpus/templates/brain/app/components/layout/Sidebar.tsx +76 -43
  84. package/corpus/templates/brain/app/global.css +1 -1
  85. package/corpus/templates/brain/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  86. package/corpus/templates/brain/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  87. package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +67 -52
  88. package/corpus/templates/calendar/app/global.css +1 -1
  89. package/corpus/templates/calendar/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  90. package/corpus/templates/calendar/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  91. package/corpus/templates/chat/app/components/layout/Layout.tsx +3 -0
  92. package/corpus/templates/chat/app/components/layout/Sidebar.tsx +78 -45
  93. package/corpus/templates/chat/app/global.css +1 -1
  94. package/corpus/templates/chat/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  95. package/corpus/templates/chat/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  96. package/corpus/templates/clips/app/components/library/library-layout.tsx +65 -31
  97. package/corpus/templates/clips/app/components/library/organization-switcher.tsx +2 -2
  98. package/corpus/templates/clips/app/components/player/video-player.tsx +16 -1
  99. package/corpus/templates/clips/app/global.css +1 -1
  100. package/corpus/templates/clips/app/hooks/use-view-tracking.ts +55 -12
  101. package/corpus/templates/clips/app/routes/embed.$shareId.tsx +6 -5
  102. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +7 -7
  103. package/corpus/templates/clips/app/routes/share.$shareId.tsx +6 -5
  104. package/corpus/templates/clips/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  105. package/corpus/templates/clips/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  106. package/corpus/templates/clips/server/plugins/db.ts +113 -68
  107. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +66 -42
  108. package/corpus/templates/content/app/global.css +1 -1
  109. package/corpus/templates/content/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  110. package/corpus/templates/content/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  111. package/corpus/templates/design/app/components/layout/Sidebar.tsx +65 -30
  112. package/corpus/templates/design/app/entry.client.tsx +14 -1
  113. package/corpus/templates/design/app/global.css +1 -1
  114. package/corpus/templates/design/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  115. package/corpus/templates/design/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  116. package/corpus/templates/dispatch/app/global.css +1 -1
  117. package/corpus/templates/dispatch/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  118. package/corpus/templates/dispatch/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  119. package/corpus/templates/forms/app/components/layout/Layout.tsx +3 -0
  120. package/corpus/templates/forms/app/components/layout/Sidebar.tsx +72 -37
  121. package/corpus/templates/forms/app/global.css +1 -1
  122. package/corpus/templates/forms/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  123. package/corpus/templates/forms/changelog/2026-07-24-forms-sidebar-actions-now-keep-search-language-feedback-and-.md +6 -0
  124. package/corpus/templates/forms/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  125. package/corpus/templates/macros/app/components/DailyProgress.tsx +5 -5
  126. package/corpus/templates/macros/app/components/ExerciseCard.tsx +2 -2
  127. package/corpus/templates/macros/app/components/MealCard.tsx +2 -2
  128. package/corpus/templates/macros/app/components/WeightCard.tsx +2 -2
  129. package/corpus/templates/macros/app/components/layout/AppLayout.tsx +56 -29
  130. package/corpus/templates/macros/app/components/ui/button.tsx +1 -2
  131. package/corpus/templates/macros/app/components/ui/card.tsx +1 -1
  132. package/corpus/templates/macros/app/global.css +1 -1
  133. package/corpus/templates/macros/app/routes/_index.tsx +1 -1
  134. package/corpus/templates/macros/app/routes/analytics.tsx +4 -7
  135. package/corpus/templates/macros/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  136. package/corpus/templates/macros/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  137. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +125 -37
  138. package/corpus/templates/mail/app/global.css +1 -1
  139. package/corpus/templates/mail/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  140. package/corpus/templates/mail/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  141. package/corpus/templates/plan/app/components/layout/Layout.tsx +3 -0
  142. package/corpus/templates/plan/app/components/layout/Sidebar.tsx +90 -60
  143. package/corpus/templates/plan/app/global.css +1 -1
  144. package/corpus/templates/plan/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  145. package/corpus/templates/plan/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  146. package/corpus/templates/slides/app/components/layout/Sidebar.tsx +69 -32
  147. package/corpus/templates/slides/app/global.css +1 -1
  148. package/corpus/templates/slides/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  149. package/corpus/templates/slides/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  150. package/corpus/templates/tasks/app/global.css +1 -1
  151. package/corpus/templates/tasks/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  152. package/corpus/toolkit/CHANGELOG.md +8 -0
  153. package/corpus/toolkit/README.md +8 -1
  154. package/corpus/toolkit/agent-native.eject.json +1 -1
  155. package/corpus/toolkit/package.json +1 -1
  156. package/corpus/toolkit/src/app-shell/index.ts +1 -0
  157. package/corpus/toolkit/src/app-shell/sidebar-footer-actions.tsx +48 -0
  158. package/corpus/toolkit/src/chat-history.css +52 -1
  159. package/corpus/toolkit/src/design-system/default-adapter.tsx +1 -1
  160. package/corpus/toolkit/src/ui/button.tsx +1 -2
  161. package/corpus/toolkit/src/ui/card.tsx +1 -1
  162. package/corpus/toolkit/src/ui/table.tsx +4 -11
  163. package/dist/cli/context-xray-local.js +1 -1
  164. package/dist/cli/context-xray-local.js.map +1 -1
  165. package/dist/cli/index.js +56 -17
  166. package/dist/cli/index.js.map +1 -1
  167. package/dist/cli/skills.d.ts.map +1 -1
  168. package/dist/cli/skills.js +5 -0
  169. package/dist/cli/skills.js.map +1 -1
  170. package/dist/cli/telemetry.d.ts +7 -0
  171. package/dist/cli/telemetry.d.ts.map +1 -1
  172. package/dist/cli/telemetry.js +91 -1
  173. package/dist/cli/telemetry.js.map +1 -1
  174. package/dist/client/AgentPanel.d.ts +7 -1
  175. package/dist/client/AgentPanel.d.ts.map +1 -1
  176. package/dist/client/AgentPanel.js +2 -2
  177. package/dist/client/AgentPanel.js.map +1 -1
  178. package/dist/client/CommandMenu.d.ts +2 -0
  179. package/dist/client/CommandMenu.d.ts.map +1 -1
  180. package/dist/client/CommandMenu.js +12 -1
  181. package/dist/client/CommandMenu.js.map +1 -1
  182. package/dist/client/agent-page/AgentTabsPage.d.ts +4 -0
  183. package/dist/client/agent-page/AgentTabsPage.d.ts.map +1 -1
  184. package/dist/client/agent-page/AgentTabsPage.js +8 -4
  185. package/dist/client/agent-page/AgentTabsPage.js.map +1 -1
  186. package/dist/client/analytics.d.ts.map +1 -1
  187. package/dist/client/analytics.js +7 -0
  188. package/dist/client/analytics.js.map +1 -1
  189. package/dist/client/error-capture.d.ts.map +1 -1
  190. package/dist/client/error-capture.js +8 -1
  191. package/dist/client/error-capture.js.map +1 -1
  192. package/dist/client/extensions/ExtensionsListPage.d.ts.map +1 -1
  193. package/dist/client/extensions/ExtensionsListPage.js +2 -2
  194. package/dist/client/extensions/ExtensionsListPage.js.map +1 -1
  195. package/dist/client/extensions/agent-native-extension-runtime.js +1 -1
  196. package/dist/client/extensions/agent-native-extension-runtime.js.map +1 -1
  197. package/dist/client/navigation/index.d.ts +1 -1
  198. package/dist/client/navigation/index.d.ts.map +1 -1
  199. package/dist/client/navigation/index.js +1 -1
  200. package/dist/client/navigation/index.js.map +1 -1
  201. package/dist/client/org/OrgSwitcher.d.ts.map +1 -1
  202. package/dist/client/org/OrgSwitcher.js +9 -13
  203. package/dist/client/org/OrgSwitcher.js.map +1 -1
  204. package/dist/client/settings/ExtensionsSettingsContent.js +1 -1
  205. package/dist/client/settings/ExtensionsSettingsContent.js.map +1 -1
  206. package/dist/collab/awareness.d.ts +2 -2
  207. package/dist/collab/awareness.d.ts.map +1 -1
  208. package/dist/extensions/theme.js +1 -1
  209. package/dist/extensions/theme.js.map +1 -1
  210. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  211. package/dist/localization/default-messages.d.ts +2 -0
  212. package/dist/localization/default-messages.d.ts.map +1 -1
  213. package/dist/localization/default-messages.js +2 -0
  214. package/dist/localization/default-messages.js.map +1 -1
  215. package/dist/provider-api/actions/provider-api.d.ts +2 -2
  216. package/dist/resources/handlers.d.ts +1 -1
  217. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  218. package/dist/server/core-routes-plugin.js +8 -1
  219. package/dist/server/core-routes-plugin.js.map +1 -1
  220. package/dist/server/framework-request-handler.d.ts.map +1 -1
  221. package/dist/server/framework-request-handler.js +17 -27
  222. package/dist/server/framework-request-handler.js.map +1 -1
  223. package/dist/server/realtime-token.d.ts +1 -1
  224. package/dist/styles/agent-native.css +13 -0
  225. package/dist/templates/chat/app/components/layout/Layout.tsx +3 -0
  226. package/dist/templates/chat/app/components/layout/Sidebar.tsx +78 -45
  227. package/dist/templates/chat/app/global.css +1 -1
  228. package/dist/templates/chat/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  229. package/dist/templates/chat/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  230. package/dist/templates/default/app/global.css +1 -1
  231. package/dist/tracking/error-capture.d.ts +14 -0
  232. package/dist/tracking/error-capture.d.ts.map +1 -0
  233. package/dist/tracking/error-capture.js +113 -0
  234. package/dist/tracking/error-capture.js.map +1 -0
  235. package/dist/tracking/index.d.ts +1 -0
  236. package/dist/tracking/index.d.ts.map +1 -1
  237. package/dist/tracking/index.js +1 -0
  238. package/dist/tracking/index.js.map +1 -1
  239. package/package.json +2 -2
  240. package/src/cli/context-xray-local.ts +1 -1
  241. package/src/cli/index.ts +63 -18
  242. package/src/cli/skills.ts +5 -0
  243. package/src/cli/telemetry.ts +118 -1
  244. package/src/client/AgentPanel.tsx +10 -0
  245. package/src/client/CommandMenu.tsx +13 -1
  246. package/src/client/agent-page/AgentTabsPage.tsx +39 -4
  247. package/src/client/analytics.ts +13 -0
  248. package/src/client/error-capture.ts +6 -1
  249. package/src/client/extensions/ExtensionsListPage.tsx +12 -5
  250. package/src/client/extensions/agent-native-extension-runtime.ts +1 -1
  251. package/src/client/navigation/index.ts +2 -0
  252. package/src/client/org/OrgSwitcher.tsx +14 -32
  253. package/src/client/settings/ExtensionsSettingsContent.tsx +1 -1
  254. package/src/extensions/theme.ts +1 -1
  255. package/src/localization/default-messages.ts +2 -0
  256. package/src/server/core-routes-plugin.ts +10 -1
  257. package/src/server/framework-request-handler.ts +17 -26
  258. package/src/styles/agent-native.css +13 -0
  259. package/src/templates/chat/app/components/layout/Layout.tsx +3 -0
  260. package/src/templates/chat/app/components/layout/Sidebar.tsx +78 -45
  261. package/src/templates/chat/app/global.css +1 -1
  262. package/src/templates/chat/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  263. package/src/templates/chat/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  264. package/src/templates/default/app/global.css +1 -1
  265. package/src/tracking/error-capture.ts +151 -0
  266. package/src/tracking/index.ts +5 -0
@@ -579,13 +579,13 @@ export default function ShareRoute() {
579
579
 
580
580
  usePlayerShortcuts({ playerRef });
581
581
 
582
+ const [trackedVideoEl, setTrackedVideoEl] = useState<HTMLVideoElement | null>(
583
+ null,
584
+ );
585
+
582
586
  const tracking = useViewTracking({
583
587
  recordingId: shareId ?? "",
584
- videoRef: {
585
- get current() {
586
- return playerRef.current?.video ?? null;
587
- },
588
- } as any,
588
+ videoEl: trackedVideoEl,
589
589
  durationMs: recording?.durationMs ?? 0,
590
590
  trackOpenWithoutVideo: isLoomEmbedBacked,
591
591
  });
@@ -961,6 +961,7 @@ export default function ShareRoute() {
961
961
  <div className="aspect-video w-full lg:min-h-0 lg:flex-1 lg:aspect-auto">
962
962
  <VideoPlayer
963
963
  ref={playerRef}
964
+ onVideoElementChange={setTrackedVideoEl}
964
965
  recordingId={recording.id}
965
966
  videoUrl={recording.videoUrl}
966
967
  videoFormat={recording.videoFormat}
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-07-24
4
+ ---
5
+
6
+ Secondary controls and dashboard surfaces now use quieter borderless styling.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-07-24
4
+ ---
5
+
6
+ Sidebar utility controls now follow a consistent footer order.
@@ -1261,16 +1261,6 @@ async function sweepOrphanedRecordingChunks(): Promise<void> {
1261
1261
  }
1262
1262
  }
1263
1263
 
1264
- function rowNumber(value: unknown): number {
1265
- if (typeof value === "number" && Number.isFinite(value)) return value;
1266
- if (typeof value === "bigint") return Number(value);
1267
- if (typeof value === "string") {
1268
- const parsed = Number(value);
1269
- return Number.isFinite(parsed) ? parsed : 0;
1270
- }
1271
- return 0;
1272
- }
1273
-
1274
1264
  /**
1275
1265
  * Sweep orphaned resumable upload sessions out of `application_state`.
1276
1266
  *
@@ -1287,6 +1277,8 @@ function rowNumber(value: unknown): number {
1287
1277
  async function sweepOrphanedResumableSessions(): Promise<void> {
1288
1278
  const exec = getDbExec();
1289
1279
  const pg = isPostgres();
1280
+ const SWEEP_BATCH = 500;
1281
+ const IN_CHUNK = 200;
1290
1282
 
1291
1283
  let sessionRows: Array<{
1292
1284
  session_id?: unknown;
@@ -1295,7 +1287,7 @@ async function sweepOrphanedResumableSessions(): Promise<void> {
1295
1287
  }> = [];
1296
1288
  try {
1297
1289
  const probe = await exec.execute({
1298
- sql: `SELECT session_id, key, updated_at FROM application_state WHERE key LIKE 'resumable-session-%'`,
1290
+ sql: `SELECT session_id, key, updated_at FROM application_state WHERE key LIKE 'resumable-session-%' ORDER BY updated_at ASC LIMIT ${SWEEP_BATCH}`,
1299
1291
  args: [],
1300
1292
  });
1301
1293
  sessionRows =
@@ -1326,8 +1318,15 @@ async function sweepOrphanedResumableSessions(): Promise<void> {
1326
1318
  const staleInProgressIso = new Date(
1327
1319
  Date.now() - 24 * 60 * 60 * 1000,
1328
1320
  ).toISOString();
1329
- let totalDeleted = 0;
1330
1321
 
1322
+ // Parse candidate rows and collect the referenced recording ids so they can
1323
+ // be resolved in a few batched lookups instead of one query per session.
1324
+ const candidates: Array<{
1325
+ key: string;
1326
+ recordingId: string;
1327
+ sessionUpdatedAt: string;
1328
+ }> = [];
1329
+ const recordingIds = new Set<string>();
1331
1330
  for (const row of sessionRows) {
1332
1331
  const key = typeof row.key === "string" ? row.key : "";
1333
1332
  if (!key.startsWith(prefix)) continue;
@@ -1343,78 +1342,124 @@ async function sweepOrphanedResumableSessions(): Promise<void> {
1343
1342
  Number.isFinite(sessionUpdatedAtMs) && sessionUpdatedAtMs > 0
1344
1343
  ? new Date(sessionUpdatedAtMs).toISOString()
1345
1344
  : "";
1345
+ candidates.push({ key, recordingId, sessionUpdatedAt });
1346
+ recordingIds.add(recordingId);
1347
+ }
1348
+ if (candidates.length === 0) return;
1346
1349
 
1347
- let shouldSweep = false;
1350
+ // Resolve every referenced recording in chunked `IN (...)` lookups.
1351
+ const recordingById = new Map<
1352
+ string,
1353
+ { status?: string; updatedAt?: string }
1354
+ >();
1355
+ const idList = [...recordingIds];
1356
+ for (let i = 0; i < idList.length; i += IN_CHUNK) {
1357
+ const chunk = idList.slice(i, i + IN_CHUNK);
1358
+ const placeholders = chunk
1359
+ .map((_, j) => (pg ? `$${j + 1}` : "?"))
1360
+ .join(", ");
1348
1361
  try {
1349
1362
  const probe = await exec.execute({
1350
- sql: pg
1351
- ? `SELECT status, updated_at FROM recordings WHERE id = $1 LIMIT 1`
1352
- : `SELECT status, updated_at FROM recordings WHERE id = ? LIMIT 1`,
1353
- args: [recordingId],
1363
+ sql: `SELECT id, status, updated_at FROM recordings WHERE id IN (${placeholders})`,
1364
+ args: chunk,
1354
1365
  });
1355
- const recording = (
1356
- probe.rows as Array<{ status?: string; updated_at?: string }>
1357
- )[0];
1358
- if (!recording) {
1359
- shouldSweep = true;
1360
- } else if (
1361
- (recording.status === "ready" || recording.status === "failed") &&
1362
- (recording.updated_at ?? "") < oneHourAgoIso
1363
- ) {
1364
- shouldSweep = true;
1365
- } else if (
1366
- (recording.status === "uploading" ||
1367
- recording.status === "processing") &&
1368
- (sessionUpdatedAt || recording.updated_at || "") < staleInProgressIso
1369
- ) {
1370
- try {
1371
- await exec.execute({
1372
- sql: pg
1373
- ? `UPDATE recordings SET status = 'failed', failure_reason = $1, updated_at = $2 WHERE id = $3 AND status = $4`
1374
- : `UPDATE recordings SET status = 'failed', failure_reason = ?, updated_at = ? WHERE id = ? AND status = ?`,
1375
- args: [
1376
- "Upload did not finish before the resumable upload cleanup window.",
1377
- new Date().toISOString(),
1378
- recordingId,
1379
- recording.status,
1380
- ],
1366
+ for (const rec of probe.rows as Array<{
1367
+ id?: string;
1368
+ status?: string;
1369
+ updated_at?: string;
1370
+ }>) {
1371
+ if (typeof rec.id === "string") {
1372
+ recordingById.set(rec.id, {
1373
+ status: rec.status,
1374
+ updatedAt: rec.updated_at,
1381
1375
  });
1382
- } catch (err) {
1383
- console.warn(
1384
- "[db] resumable-session sweep: stale upload mark-failed failed",
1385
- {
1386
- recordingId,
1387
- status: recording.status,
1388
- err: (err as Error)?.message ?? err,
1389
- },
1390
- );
1391
1376
  }
1392
- shouldSweep = true;
1393
1377
  }
1394
1378
  } catch (err) {
1395
- console.warn("[db] resumable-session sweep: recording probe failed", {
1396
- recordingId,
1397
- err: (err as Error)?.message ?? err,
1398
- });
1379
+ console.warn(
1380
+ "[db] resumable-session sweep: recordings batch probe failed",
1381
+ (err as Error)?.message ?? err,
1382
+ );
1383
+ return;
1384
+ }
1385
+ }
1386
+
1387
+ // Decide sweeps in memory, then mark stale uploads failed and batch-delete.
1388
+ const keysToDelete = new Set<string>();
1389
+ const staleIdsByStatus = new Map<string, Set<string>>();
1390
+ for (const candidate of candidates) {
1391
+ const recording = recordingById.get(candidate.recordingId);
1392
+ if (!recording) {
1393
+ keysToDelete.add(candidate.key);
1399
1394
  continue;
1400
1395
  }
1396
+ const status = recording.status;
1397
+ if (
1398
+ (status === "ready" || status === "failed") &&
1399
+ (recording.updatedAt ?? "") < oneHourAgoIso
1400
+ ) {
1401
+ keysToDelete.add(candidate.key);
1402
+ } else if (
1403
+ (status === "uploading" || status === "processing") &&
1404
+ (candidate.sessionUpdatedAt || recording.updatedAt || "") <
1405
+ staleInProgressIso
1406
+ ) {
1407
+ const bucket = staleIdsByStatus.get(status) ?? new Set<string>();
1408
+ bucket.add(candidate.recordingId);
1409
+ staleIdsByStatus.set(status, bucket);
1410
+ keysToDelete.add(candidate.key);
1411
+ }
1412
+ }
1401
1413
 
1402
- if (!shouldSweep) continue;
1414
+ // Mark stale in-progress uploads failed, one chunked `IN (...)` update per
1415
+ // status. The `status = ?` guard keeps a recording that concurrently
1416
+ // advanced out of that status from being clobbered back to failed.
1417
+ const staleReason =
1418
+ "Upload did not finish before the resumable upload cleanup window.";
1419
+ for (const [status, idSet] of staleIdsByStatus) {
1420
+ const ids = [...idSet];
1421
+ for (let i = 0; i < ids.length; i += IN_CHUNK) {
1422
+ const chunk = ids.slice(i, i + IN_CHUNK);
1423
+ const idPlaceholders = chunk
1424
+ .map((_, j) => (pg ? `$${j + 3}` : "?"))
1425
+ .join(", ");
1426
+ const statusPlaceholder = pg ? `$${chunk.length + 3}` : "?";
1427
+ try {
1428
+ await exec.execute({
1429
+ sql: `UPDATE recordings SET status = 'failed', failure_reason = ${pg ? "$1" : "?"}, updated_at = ${pg ? "$2" : "?"} WHERE id IN (${idPlaceholders}) AND status = ${statusPlaceholder}`,
1430
+ args: [staleReason, new Date().toISOString(), ...chunk, status],
1431
+ });
1432
+ } catch (err) {
1433
+ console.warn(
1434
+ "[db] resumable-session sweep: stale upload mark-failed failed",
1435
+ {
1436
+ status,
1437
+ recordingIds: chunk,
1438
+ err: (err as Error)?.message ?? err,
1439
+ },
1440
+ );
1441
+ }
1442
+ }
1443
+ }
1403
1444
 
1445
+ let totalDeleted = 0;
1446
+ const deleteKeys = [...keysToDelete];
1447
+ for (let i = 0; i < deleteKeys.length; i += IN_CHUNK) {
1448
+ const chunk = deleteKeys.slice(i, i + IN_CHUNK);
1449
+ const placeholders = chunk
1450
+ .map((_, j) => (pg ? `$${j + 1}` : "?"))
1451
+ .join(", ");
1404
1452
  try {
1405
1453
  await exec.execute({
1406
- sql: pg
1407
- ? `DELETE FROM application_state WHERE session_id = $1 AND key = $2`
1408
- : `DELETE FROM application_state WHERE session_id = ? AND key = ?`,
1409
- args: [String(row.session_id ?? ""), key],
1454
+ sql: `DELETE FROM application_state WHERE key IN (${placeholders})`,
1455
+ args: chunk,
1410
1456
  });
1411
- totalDeleted += 1;
1457
+ totalDeleted += chunk.length;
1412
1458
  } catch (err) {
1413
- console.warn("[db] resumable-session sweep: delete failed", {
1414
- key,
1415
- updatedAt: rowNumber(row.updated_at),
1416
- err: (err as Error)?.message ?? err,
1417
- });
1459
+ console.warn(
1460
+ "[db] resumable-session sweep: batch delete failed",
1461
+ (err as Error)?.message ?? err,
1462
+ );
1418
1463
  }
1419
1464
  }
1420
1465
 
@@ -7,9 +7,10 @@ import {
7
7
  useActionMutation,
8
8
  useActionQuery,
9
9
  } from "@agent-native/core/client/hooks";
10
- import { useT } from "@agent-native/core/client/i18n";
10
+ import { LanguagePicker, useT } from "@agent-native/core/client/i18n";
11
11
  import { OrgSwitcher } from "@agent-native/core/client/org";
12
12
  import { FeedbackButton } from "@agent-native/core/client/ui";
13
+ import { SidebarFooterActions } from "@agent-native/toolkit/app-shell";
13
14
  import {
14
15
  closestCenter,
15
16
  DndContext,
@@ -1278,6 +1279,53 @@ export function DocumentSidebar({
1278
1279
  </Link>
1279
1280
  );
1280
1281
 
1282
+ const collapseButton = (
1283
+ <Tooltip>
1284
+ <TooltipTrigger asChild>
1285
+ <button
1286
+ type="button"
1287
+ aria-label={collapsed ? t("sidebar.expand") : t("sidebar.collapse")}
1288
+ className="flex size-8 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground"
1289
+ onClick={onToggleCollapsed}
1290
+ >
1291
+ {collapsed ? (
1292
+ <IconLayoutSidebarLeftExpand size={16} />
1293
+ ) : (
1294
+ <IconLayoutSidebarLeftCollapse size={16} />
1295
+ )}
1296
+ </button>
1297
+ </TooltipTrigger>
1298
+ <TooltipContent side="right">
1299
+ {collapsed ? t("sidebar.expand") : t("sidebar.collapse")}
1300
+ </TooltipContent>
1301
+ </Tooltip>
1302
+ );
1303
+ const searchButton = (
1304
+ <Tooltip>
1305
+ <TooltipTrigger asChild>
1306
+ <button
1307
+ type="button"
1308
+ aria-label={t("sidebar.search")}
1309
+ className="flex size-8 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground"
1310
+ onClick={() => setIsSearching((value) => !value)}
1311
+ >
1312
+ <IconSearch size={16} />
1313
+ </button>
1314
+ </TooltipTrigger>
1315
+ <TooltipContent side="right">{t("sidebar.search")}</TooltipContent>
1316
+ </Tooltip>
1317
+ );
1318
+ const translateButton = (
1319
+ <LanguagePicker variant="ghost-icon" label={t("settings.languageLabel")} />
1320
+ );
1321
+ const feedbackButton = (
1322
+ <FeedbackButton
1323
+ variant={collapsed ? "icon" : "sidebar"}
1324
+ side="right"
1325
+ className={collapsed ? "size-8" : "h-8 min-w-0"}
1326
+ />
1327
+ );
1328
+
1281
1329
  const renderAgentNavButton = () => (
1282
1330
  <Link
1283
1331
  to="/agent"
@@ -1832,17 +1880,6 @@ export function DocumentSidebar({
1832
1880
  if (collapsed) {
1833
1881
  return (
1834
1882
  <div className="agent-layout-left-drawer flex h-full w-12 flex-col items-center gap-1 border-e border-border bg-sidebar py-3 transition-[width] duration-200 ease-out">
1835
- <Tooltip>
1836
- <TooltipTrigger asChild>
1837
- <button
1838
- className="w-10 h-10 flex items-center justify-center rounded-lg hover:bg-accent text-muted-foreground hover:text-foreground"
1839
- onClick={onToggleCollapsed}
1840
- >
1841
- <IconLayoutSidebarLeftExpand size={18} />
1842
- </button>
1843
- </TooltipTrigger>
1844
- <TooltipContent>{t("sidebar.expand")}</TooltipContent>
1845
- </Tooltip>
1846
1883
  {renderCollapsedNewButton()}
1847
1884
  <Tooltip>
1848
1885
  <TooltipTrigger asChild>
@@ -1876,6 +1913,13 @@ export function DocumentSidebar({
1876
1913
  </TooltipTrigger>
1877
1914
  <TooltipContent>{t("navigation.settings")}</TooltipContent>
1878
1915
  </Tooltip>
1916
+ <SidebarFooterActions
1917
+ collapsed
1918
+ feedback={feedbackButton}
1919
+ translate={translateButton}
1920
+ search={searchButton}
1921
+ collapse={collapseButton}
1922
+ />
1879
1923
  </div>
1880
1924
  );
1881
1925
  }
@@ -1908,30 +1952,6 @@ export function DocumentSidebar({
1908
1952
  Content
1909
1953
  </span>
1910
1954
  </div>
1911
- <div className="flex items-center gap-0.5">
1912
- <Tooltip>
1913
- <TooltipTrigger asChild>
1914
- <button
1915
- className="w-9 h-9 flex items-center justify-center rounded-lg hover:bg-accent text-muted-foreground hover:text-foreground"
1916
- onClick={() => setIsSearching(!isSearching)}
1917
- >
1918
- <IconSearch size={16} />
1919
- </button>
1920
- </TooltipTrigger>
1921
- <TooltipContent>{t("sidebar.search")}</TooltipContent>
1922
- </Tooltip>
1923
- <Tooltip>
1924
- <TooltipTrigger asChild>
1925
- <button
1926
- className="w-9 h-9 flex items-center justify-center rounded-lg hover:bg-accent text-muted-foreground hover:text-foreground"
1927
- onClick={onToggleCollapsed}
1928
- >
1929
- <IconLayoutSidebarLeftCollapse size={16} />
1930
- </button>
1931
- </TooltipTrigger>
1932
- <TooltipContent>{t("sidebar.collapse")}</TooltipContent>
1933
- </Tooltip>
1934
- </div>
1935
1955
  </div>
1936
1956
 
1937
1957
  {/* Search */}
@@ -2098,13 +2118,17 @@ export function DocumentSidebar({
2098
2118
  {/* Footer */}
2099
2119
  <div className="shrink-0 space-y-2 px-3 py-2">
2100
2120
  {isCodeMode ? <DevDatabaseLink /> : null}
2101
- <div className="flex items-center justify-end gap-1">
2102
- <FeedbackButton className="h-8 min-w-0 flex-1 gap-2 rounded-md px-2 py-0" />
2103
- <div className="flex shrink-0 items-center gap-0.5">
2104
- <NotionButton />
2105
- <ThemeToggle />
2106
- </div>
2121
+ <div className="flex justify-end gap-0.5">
2122
+ <NotionButton />
2123
+ <ThemeToggle />
2107
2124
  </div>
2125
+ <SidebarFooterActions
2126
+ feedback={feedbackButton}
2127
+ translate={translateButton}
2128
+ search={searchButton}
2129
+ collapse={collapseButton}
2130
+ className="px-0 py-0"
2131
+ />
2108
2132
  </div>
2109
2133
 
2110
2134
  {/* Resize handle */}
@@ -80,7 +80,7 @@
80
80
  --accent: 0 0% 18%;
81
81
  --accent-foreground: 0 0% 90%;
82
82
 
83
- --destructive: 0 84% 60%;
83
+ --destructive: 0 91% 71%;
84
84
  --destructive-foreground: 0 0% 100%;
85
85
 
86
86
  --border: 0 0% 24%;
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-07-24
4
+ ---
5
+
6
+ Secondary controls and dashboard surfaces now use quieter borderless styling.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-07-24
4
+ ---
5
+
6
+ Sidebar utility controls now follow a consistent footer order.
@@ -1,8 +1,10 @@
1
1
  import { appPath } from "@agent-native/core/client/api-path";
2
2
  import { DevDatabaseLink } from "@agent-native/core/client/db-admin";
3
- import { useT } from "@agent-native/core/client/i18n";
3
+ import { LanguagePicker, useT } from "@agent-native/core/client/i18n";
4
+ import { openCommandMenu } from "@agent-native/core/client/navigation";
4
5
  import { OrgSwitcher } from "@agent-native/core/client/org";
5
6
  import { FeedbackButton } from "@agent-native/core/client/ui";
7
+ import { SidebarFooterActions } from "@agent-native/toolkit/app-shell";
6
8
  import {
7
9
  IconPencil,
8
10
  IconTemplate,
@@ -11,6 +13,7 @@ import {
11
13
  IconSettings,
12
14
  IconLayoutSidebarLeftCollapse,
13
15
  IconLayoutSidebarLeftExpand,
16
+ IconSearch,
14
17
  } from "@tabler/icons-react";
15
18
  import { useEffect, useState } from "react";
16
19
  import { Link, useLocation } from "react-router";
@@ -61,6 +64,59 @@ export function Sidebar() {
61
64
  }
62
65
  }, [collapsed]);
63
66
 
67
+ const collapseButton = (
68
+ <Tooltip delayDuration={0}>
69
+ <TooltipTrigger asChild>
70
+ <button
71
+ type="button"
72
+ onClick={() => setCollapsed((value) => !value)}
73
+ className="flex size-8 items-center justify-center rounded-md text-muted-foreground hover:bg-sidebar-accent/50 hover:text-foreground"
74
+ aria-label={
75
+ collapsed
76
+ ? t("navigation.expandSidebar")
77
+ : t("navigation.collapseSidebar")
78
+ }
79
+ >
80
+ {collapsed ? (
81
+ <IconLayoutSidebarLeftExpand className="h-4 w-4 rtl:-scale-x-100" />
82
+ ) : (
83
+ <IconLayoutSidebarLeftCollapse className="h-4 w-4 rtl:-scale-x-100" />
84
+ )}
85
+ </button>
86
+ </TooltipTrigger>
87
+ <TooltipContent side="right">
88
+ {collapsed
89
+ ? t("navigation.expandSidebar")
90
+ : t("navigation.collapseSidebar")}
91
+ </TooltipContent>
92
+ </Tooltip>
93
+ );
94
+ const searchButton = (
95
+ <Tooltip delayDuration={0}>
96
+ <TooltipTrigger asChild>
97
+ <button
98
+ type="button"
99
+ onClick={openCommandMenu}
100
+ className="flex size-8 items-center justify-center rounded-md text-muted-foreground hover:bg-sidebar-accent/50 hover:text-foreground"
101
+ aria-label={t("root.commandSearch")}
102
+ >
103
+ <IconSearch className="h-4 w-4" />
104
+ </button>
105
+ </TooltipTrigger>
106
+ <TooltipContent side="right">{t("root.commandSearch")}</TooltipContent>
107
+ </Tooltip>
108
+ );
109
+ const translateButton = (
110
+ <LanguagePicker variant="ghost-icon" label={t("settings.languageLabel")} />
111
+ );
112
+ const feedbackButton = (
113
+ <FeedbackButton
114
+ variant={collapsed ? "icon" : "sidebar"}
115
+ side="right"
116
+ className={collapsed ? "h-8 w-8" : "min-w-0"}
117
+ />
118
+ );
119
+
64
120
  return (
65
121
  <aside
66
122
  className={cn(
@@ -93,30 +149,6 @@ export function Sidebar() {
93
149
  </span>
94
150
  </div>
95
151
  )}
96
- <Tooltip delayDuration={0}>
97
- <TooltipTrigger asChild>
98
- <button
99
- onClick={() => setCollapsed((c) => !c)}
100
- className="flex h-7 w-7 cursor-pointer items-center justify-center rounded-md text-muted-foreground hover:bg-sidebar-accent/50 hover:text-foreground"
101
- aria-label={
102
- collapsed
103
- ? t("navigation.expandSidebar")
104
- : t("navigation.collapseSidebar")
105
- }
106
- >
107
- {collapsed ? (
108
- <IconLayoutSidebarLeftExpand className="h-4 w-4 rtl:-scale-x-100" />
109
- ) : (
110
- <IconLayoutSidebarLeftCollapse className="h-4 w-4 rtl:-scale-x-100" />
111
- )}
112
- </button>
113
- </TooltipTrigger>
114
- <TooltipContent side="right">
115
- {collapsed
116
- ? t("navigation.expandSidebar")
117
- : t("navigation.collapseSidebar")}
118
- </TooltipContent>
119
- </Tooltip>
120
152
  </div>
121
153
 
122
154
  <div className="flex min-h-0 flex-1 flex-col overflow-y-auto">
@@ -202,17 +234,20 @@ export function Sidebar() {
202
234
  <div className="px-3 py-2">
203
235
  <OrgSwitcher reserveSpace />
204
236
  </div>
205
-
206
237
  <div className="px-3 py-2">
207
238
  <DevDatabaseLink />
208
- <div className="flex items-center justify-end gap-1">
209
- <FeedbackButton className="min-w-0 flex-1" />
210
- <ThemeToggle className="h-8 w-8 shrink-0" />
211
- </div>
239
+ <ThemeToggle className="h-8 w-8 shrink-0" />
212
240
  </div>
213
241
  </div>
214
242
  )}
215
243
  </div>
244
+ <SidebarFooterActions
245
+ collapsed={collapsed}
246
+ feedback={feedbackButton}
247
+ translate={translateButton}
248
+ search={searchButton}
249
+ collapse={collapseButton}
250
+ />
216
251
  </div>
217
252
  </aside>
218
253
  );
@@ -1,3 +1,4 @@
1
+ import { captureException } from "@agent-native/core/client/analytics";
1
2
  import { appBasePath } from "@agent-native/core/client/api-path";
2
3
  import { hydrateRoot } from "react-dom/client";
3
4
  import { HydratedRouter } from "react-router/dom";
@@ -16,4 +17,16 @@ if (context) {
16
17
  context.basename = routerBasePath;
17
18
  }
18
19
 
19
- hydrateRoot(document, <HydratedRouter />);
20
+ hydrateRoot(document, <HydratedRouter />, {
21
+ onRecoverableError(error, info) {
22
+ captureException(error, {
23
+ tags: {
24
+ source: "react-recoverable-error",
25
+ kind: "hydration",
26
+ },
27
+ extra: {
28
+ componentStack: info.componentStack?.slice(0, 2_000),
29
+ },
30
+ });
31
+ },
32
+ });
@@ -113,7 +113,7 @@
113
113
  --muted-foreground: 0 0% 60%;
114
114
  --accent: 0 0% 18%;
115
115
  --accent-foreground: 0 0% 96%;
116
- --destructive: 0 84% 60%;
116
+ --destructive: 0 91% 71%;
117
117
  --destructive-foreground: 0 0% 98%;
118
118
  --border: 0 0% 24%;
119
119
  --input: 0 0% 24%;
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-07-24
4
+ ---
5
+
6
+ Secondary controls and dashboard surfaces now use quieter borderless styling.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-07-24
4
+ ---
5
+
6
+ Sidebar utility controls now follow a consistent footer order.
@@ -22,7 +22,7 @@
22
22
  --muted-foreground: 0 0% 45%;
23
23
  --accent: 0 0% 95%;
24
24
  --accent-foreground: 0 0% 15%;
25
- --destructive: 0 84% 60%;
25
+ --destructive: 0 91% 71%;
26
26
  --destructive-foreground: 0 0% 98%;
27
27
  --border: 0 0% 90%;
28
28
  --input: 0 0% 90%;
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-07-24
4
+ ---
5
+
6
+ Secondary controls and dashboard surfaces now use quieter borderless styling.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-07-24
4
+ ---
5
+
6
+ Sidebar utility controls now follow a consistent footer order.