@agent-native/core 0.90.11 → 0.91.1

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 (322) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +34 -0
  3. package/corpus/core/docs/content/toolkit-settings.mdx +56 -3
  4. package/corpus/core/package.json +2 -1
  5. package/corpus/core/src/agent/run-ownership.ts +29 -1
  6. package/corpus/core/src/changelog/parse.ts +78 -0
  7. package/corpus/core/src/chat-threads/schema.ts +43 -0
  8. package/corpus/core/src/chat-threads/store.ts +144 -12
  9. package/corpus/core/src/cli/design-connect.ts +53 -9
  10. package/corpus/core/src/cli/workspace-dev.ts +25 -5
  11. package/corpus/core/src/client/AgentPanel.tsx +79 -14
  12. package/corpus/core/src/client/AssistantChat.tsx +359 -425
  13. package/corpus/core/src/client/analytics-session.ts +70 -0
  14. package/corpus/core/src/client/analytics.ts +175 -49
  15. package/corpus/core/src/client/chat/message-components.tsx +22 -2
  16. package/corpus/core/src/client/components/ui/message-scroller.tsx +131 -0
  17. package/corpus/core/src/client/conversation/AgentConversation.tsx +63 -41
  18. package/corpus/core/src/client/error-capture.ts +616 -0
  19. package/corpus/core/src/client/index.ts +12 -0
  20. package/corpus/core/src/client/session-replay.ts +57 -7
  21. package/corpus/core/src/client/settings/SettingsPanel.tsx +123 -1
  22. package/corpus/core/src/client/settings/SettingsTabsPage.tsx +292 -45
  23. package/corpus/core/src/client/settings/index.ts +1 -0
  24. package/corpus/core/src/client/sharing/ShareButton.tsx +14 -11
  25. package/corpus/core/src/client/sharing/ShareDialog.tsx +13 -10
  26. package/corpus/core/src/mcp/builtin-tools.ts +29 -2
  27. package/corpus/core/src/server/agent-chat-plugin.ts +174 -79
  28. package/corpus/core/src/server/onboarding-html.ts +28 -16
  29. package/corpus/core/src/sharing/actions/list-resource-shares.ts +45 -1
  30. package/corpus/core/src/sharing/actions/share-resource.ts +9 -0
  31. package/corpus/core/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +4 -2
  32. package/corpus/core/src/templates/workspace-core/.agents/skills/changelog/SKILL.md +9 -6
  33. package/corpus/core/src/vite/client.ts +217 -35
  34. package/corpus/templates/analytics/.agents/skills/adhoc-analysis/SKILL.md +8 -7
  35. package/corpus/templates/analytics/.agents/skills/analysis-workspace/SKILL.md +14 -10
  36. package/corpus/templates/analytics/.agents/skills/bigquery/SKILL.md +15 -15
  37. package/corpus/templates/analytics/.agents/skills/cross-source-analysis/SKILL.md +1 -0
  38. package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +38 -22
  39. package/corpus/templates/analytics/.agents/skills/data-programs/SKILL.md +114 -61
  40. package/corpus/templates/analytics/.agents/skills/data-querying/SKILL.md +1 -0
  41. package/corpus/templates/analytics/.agents/skills/gong/SKILL.md +7 -7
  42. package/corpus/templates/analytics/.agents/skills/hubspot/SKILL.md +1 -0
  43. package/corpus/templates/analytics/.agents/skills/prometheus/SKILL.md +1 -1
  44. package/corpus/templates/analytics/.builder/skills/bigquery/SKILL.md +17 -17
  45. package/corpus/templates/analytics/.builder/skills/gcloud/SKILL.md +5 -5
  46. package/corpus/templates/analytics/.builder/skills/github/SKILL.md +7 -7
  47. package/corpus/templates/analytics/.builder/skills/gong/SKILL.md +12 -12
  48. package/corpus/templates/analytics/.builder/skills/grafana/SKILL.md +7 -7
  49. package/corpus/templates/analytics/.builder/skills/sentry/SKILL.md +7 -7
  50. package/corpus/templates/analytics/.builder/skills/slack/SKILL.md +6 -6
  51. package/corpus/templates/analytics/.builder/skills/stripe/SKILL.md +7 -7
  52. package/corpus/templates/analytics/AGENTS.md +47 -2
  53. package/corpus/templates/analytics/actions/add-status-page-monitor.ts +36 -0
  54. package/corpus/templates/analytics/actions/capture-test-error.ts +33 -0
  55. package/corpus/templates/analytics/actions/delete-monitor.ts +24 -0
  56. package/corpus/templates/analytics/actions/delete-status-page.ts +23 -0
  57. package/corpus/templates/analytics/actions/get-error-issue.ts +36 -0
  58. package/corpus/templates/analytics/actions/get-monitor-stats.ts +55 -0
  59. package/corpus/templates/analytics/actions/get-monitor.ts +27 -0
  60. package/corpus/templates/analytics/actions/get-public-status-page.ts +41 -0
  61. package/corpus/templates/analytics/actions/get-status-page.ts +29 -0
  62. package/corpus/templates/analytics/actions/list-error-issues.ts +40 -0
  63. package/corpus/templates/analytics/actions/list-monitors.ts +21 -0
  64. package/corpus/templates/analytics/actions/list-status-pages.ts +21 -0
  65. package/corpus/templates/analytics/actions/match-error-issues.ts +51 -0
  66. package/corpus/templates/analytics/actions/navigate.ts +58 -4
  67. package/corpus/templates/analytics/actions/remove-status-page-monitor.ts +22 -0
  68. package/corpus/templates/analytics/actions/reorder-status-page-monitors.ts +25 -0
  69. package/corpus/templates/analytics/actions/resolve-error-issue.ts +38 -0
  70. package/corpus/templates/analytics/actions/run-monitor-check.ts +23 -0
  71. package/corpus/templates/analytics/actions/save-analysis.ts +1 -0
  72. package/corpus/templates/analytics/actions/save-monitor.ts +145 -0
  73. package/corpus/templates/analytics/actions/save-status-page.ts +47 -0
  74. package/corpus/templates/analytics/actions/view-screen.ts +212 -0
  75. package/corpus/templates/analytics/app/components/layout/Header.tsx +1 -0
  76. package/corpus/templates/analytics/app/components/layout/Layout.tsx +10 -1
  77. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +134 -39
  78. package/corpus/templates/analytics/app/components/monitoring/PublicStatusView.tsx +351 -0
  79. package/corpus/templates/analytics/app/components/monitoring/ResponseTimeChart.tsx +174 -0
  80. package/corpus/templates/analytics/app/components/monitoring/UptimeStatCards.tsx +85 -0
  81. package/corpus/templates/analytics/app/components/monitoring/UptimeTimelineBars.tsx +106 -0
  82. package/corpus/templates/analytics/app/components/monitoring/chart-utils.ts +101 -0
  83. package/corpus/templates/analytics/app/components/monitoring/index.ts +28 -0
  84. package/corpus/templates/analytics/app/components/monitoring/types.ts +42 -0
  85. package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +34 -0
  86. package/corpus/templates/analytics/app/i18n/zh-TW.ts +6 -0
  87. package/corpus/templates/analytics/app/i18n-data.ts +33 -0
  88. package/corpus/templates/analytics/app/pages/DataSources.tsx +28 -0
  89. package/corpus/templates/analytics/app/pages/Settings.tsx +77 -9
  90. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +3 -3
  91. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/dashboard-layout.ts +7 -0
  92. package/corpus/templates/analytics/app/pages/monitoring/ErrorsPanel.tsx +205 -0
  93. package/corpus/templates/analytics/app/pages/monitoring/MonitoringPage.tsx +100 -0
  94. package/corpus/templates/analytics/app/pages/monitoring/UptimePanel.tsx +475 -0
  95. package/corpus/templates/analytics/app/pages/monitoring/errors/IssueDetail.tsx +372 -0
  96. package/corpus/templates/analytics/app/pages/monitoring/errors/IssueList.tsx +360 -0
  97. package/corpus/templates/analytics/app/pages/monitoring/errors/Sparkline.tsx +55 -0
  98. package/corpus/templates/analytics/app/pages/monitoring/errors/i18n.ts +106 -0
  99. package/corpus/templates/analytics/app/pages/monitoring/errors/types.ts +75 -0
  100. package/corpus/templates/analytics/app/pages/monitoring/errors/utils.ts +132 -0
  101. package/corpus/templates/analytics/app/pages/monitoring/uptime/MonitorDetail.tsx +535 -0
  102. package/corpus/templates/analytics/app/pages/monitoring/uptime/MonitorFormPage.tsx +1026 -0
  103. package/corpus/templates/analytics/app/pages/monitoring/uptime/MonitorList.tsx +311 -0
  104. package/corpus/templates/analytics/app/pages/monitoring/uptime/i18n.ts +235 -0
  105. package/corpus/templates/analytics/app/pages/monitoring/uptime/status-pages/StatusPageEditor.tsx +661 -0
  106. package/corpus/templates/analytics/app/pages/monitoring/uptime/status-pages/StatusPagesView.tsx +355 -0
  107. package/corpus/templates/analytics/app/pages/monitoring/uptime/status-pages/i18n.ts +106 -0
  108. package/corpus/templates/analytics/app/pages/monitoring/uptime/status-pages/slug.ts +24 -0
  109. package/corpus/templates/analytics/app/pages/monitoring/uptime/status-pages/types.ts +20 -0
  110. package/corpus/templates/analytics/app/pages/monitoring/uptime/status-summary.ts +87 -0
  111. package/corpus/templates/analytics/app/pages/monitoring/uptime/types.ts +161 -0
  112. package/corpus/templates/analytics/app/pages/monitoring/uptime/utils.ts +210 -0
  113. package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +76 -1
  114. package/corpus/templates/analytics/app/pages/sessions/SessionDevToolsPanel.tsx +74 -9
  115. package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +197 -20
  116. package/corpus/templates/analytics/app/root.tsx +33 -1
  117. package/corpus/templates/analytics/app/routes/monitoring._index.tsx +10 -0
  118. package/corpus/templates/analytics/app/routes/status.$slug.tsx +118 -0
  119. package/corpus/templates/analytics/changelog/2026-07-08-add-uptime-monitors-that-ping-your-urls-and-alert-you-when-t.md +6 -0
  120. package/corpus/templates/analytics/changelog/2026-07-08-analytics-chats-keep-large-data-dictionaries-compact-so-prov.md +6 -0
  121. package/corpus/templates/analytics/changelog/2026-07-08-create-public-status-pages-that-share-the-live-health-of-cho.md +6 -0
  122. package/corpus/templates/analytics/changelog/2026-07-08-dashboard-extension-panels-use-clearer-open-copy.md +6 -0
  123. package/corpus/templates/analytics/changelog/2026-07-08-error-capture.md +6 -0
  124. package/corpus/templates/analytics/changelog/2026-07-08-fixed-single-panel-dashboard-drags-so-they-no-longer-rewrite.md +6 -0
  125. package/corpus/templates/analytics/changelog/2026-07-08-jump-straight-from-an-error-in-a-session-recording-to-its-fu.md +6 -0
  126. package/corpus/templates/analytics/changelog/2026-07-08-monitor-detail-and-list-now-show-colorful-uptime-timelines-r.md +6 -0
  127. package/corpus/templates/analytics/changelog/2026-07-08-pinned-ask-chats-now-show-a-pin-icon-in-the-sidebar.md +6 -0
  128. package/corpus/templates/analytics/changelog/2026-07-08-publish-a-public-uptime-status-page-with-colorful-uptime-tim.md +6 -0
  129. package/corpus/templates/analytics/changelog/2026-07-08-sessions-now-hide-visitor-emails-in-demo-mode-and-show-clean.md +6 -0
  130. package/corpus/templates/analytics/changelog/2026-07-08-settings-are-cleaner-searchable-and-alerts-have-their-own-tab.md +5 -0
  131. package/corpus/templates/analytics/changelog/2026-07-08-sidebar-sections-stay-collapsed-until-opened.md +5 -0
  132. package/corpus/templates/analytics/changelog/2026-07-08-the-uptime-monitor-list-now-has-a-current-status-overview-wi.md +6 -0
  133. package/corpus/templates/analytics/docs/error-capture.md +172 -0
  134. package/corpus/templates/analytics/docs/uptime-monitoring.md +150 -0
  135. package/corpus/templates/analytics/server/db/schema-errors.ts +150 -0
  136. package/corpus/templates/analytics/server/db/schema-monitoring.ts +177 -0
  137. package/corpus/templates/analytics/server/db/schema.ts +6 -0
  138. package/corpus/templates/analytics/server/jobs/uptime-monitors.ts +123 -0
  139. package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +41 -0
  140. package/corpus/templates/analytics/server/lib/data-dictionary-context.ts +55 -12
  141. package/corpus/templates/analytics/server/lib/error-capture.ts +1331 -0
  142. package/corpus/templates/analytics/server/lib/first-party-analytics.ts +47 -1
  143. package/corpus/templates/analytics/server/lib/monitor-stats.ts +494 -0
  144. package/corpus/templates/analytics/server/lib/status-pages.ts +798 -0
  145. package/corpus/templates/analytics/server/lib/uptime-monitors.ts +1665 -0
  146. package/corpus/templates/analytics/server/plugins/agent-chat.ts +7 -37
  147. package/corpus/templates/analytics/server/plugins/auth.ts +11 -1
  148. package/corpus/templates/analytics/server/plugins/db.ts +408 -0
  149. package/corpus/templates/analytics/server/plugins/uptime-monitor-jobs.ts +63 -0
  150. package/corpus/templates/assets/app/routes/_index.tsx +1 -1
  151. package/corpus/templates/assets/app/routes/settings.tsx +22 -1
  152. package/corpus/templates/assets/changelog/2026-07-08-recent-drafts-keep-comfortable-side-padding.md +6 -0
  153. package/corpus/templates/assets/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
  154. package/corpus/templates/brain/app/routes/settings.tsx +43 -5
  155. package/corpus/templates/brain/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
  156. package/corpus/templates/calendar/app/pages/Settings.tsx +44 -6
  157. package/corpus/templates/calendar/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
  158. package/corpus/templates/chat/app/routes/settings.tsx +16 -1
  159. package/corpus/templates/chat/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
  160. package/corpus/templates/clips/actions/lib/audio-only-transcription.ts +79 -37
  161. package/corpus/templates/clips/app/components/player/player-controls.tsx +35 -0
  162. package/corpus/templates/clips/app/components/player/video-player.tsx +162 -18
  163. package/corpus/templates/clips/app/routes/_app.settings._index.tsx +63 -6
  164. package/corpus/templates/clips/app/routes/record.tsx +18 -1
  165. package/corpus/templates/clips/changelog/2026-07-07-shared-clips-start-playback-reliably-from-the-first-play-click.md +6 -0
  166. package/corpus/templates/clips/changelog/2026-07-08-chrome-extension-camera-and-microphone-menus-now-show-which-.md +6 -0
  167. package/corpus/templates/clips/changelog/2026-07-08-chrome-extension-copies-new-clip-links-after-saving.md +6 -0
  168. package/corpus/templates/clips/changelog/2026-07-08-chrome-extension-recordings-now-continue-after-granting-came.md +6 -0
  169. package/corpus/templates/clips/changelog/2026-07-08-mobile-shared-clips-now-have-loom-style-tap-and-skip-controls.md +6 -0
  170. package/corpus/templates/clips/changelog/2026-07-08-recordings-and-uploads-copy-links-after-saving.md +6 -0
  171. package/corpus/templates/clips/changelog/2026-07-08-settings-are-cleaner-searchable-and-collapse-s3-with-builder.md +5 -0
  172. package/corpus/templates/clips/changelog/2026-07-08-transcripts-are-more-reliable-for-longer-desktop-recordings-.md +6 -0
  173. package/corpus/templates/clips/chrome-extension/public/manifest.json +1 -0
  174. package/corpus/templates/clips/chrome-extension/src/background.ts +162 -13
  175. package/corpus/templates/clips/chrome-extension/src/content-script.ts +14 -0
  176. package/corpus/templates/clips/chrome-extension/src/offscreen.ts +36 -0
  177. package/corpus/templates/clips/chrome-extension/src/overlay.ts +99 -25
  178. package/corpus/templates/clips/chrome-extension/src/permission.ts +63 -14
  179. package/corpus/templates/clips/chrome-extension/src/popup.ts +123 -23
  180. package/corpus/templates/content/actions/_builder-cms-read-client.ts +47 -0
  181. package/corpus/templates/content/actions/_database-source-utils.ts +33 -4
  182. package/corpus/templates/content/actions/add-content-database-source-field-property.ts +214 -29
  183. package/corpus/templates/content/actions/attach-content-database-source.ts +3 -0
  184. package/corpus/templates/content/actions/change-content-database-source-role.ts +1 -0
  185. package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +42 -32
  186. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +352 -81
  187. package/corpus/templates/content/app/components/editor/database/settings.tsx +49 -24
  188. package/corpus/templates/content/app/routes/_app.settings.tsx +19 -1
  189. package/corpus/templates/content/changelog/2026-07-07-builder-source-tag-fields-now-import-as-multi-select.md +6 -0
  190. package/corpus/templates/content/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
  191. package/corpus/templates/content/shared/api.ts +3 -0
  192. package/corpus/templates/content/shared/properties.ts +42 -0
  193. package/corpus/templates/design/AGENTS.md +9 -0
  194. package/corpus/templates/design/actions/generate-design.ts +3 -0
  195. package/corpus/templates/design/actions/get-design-system.ts +147 -1
  196. package/corpus/templates/design/actions/request-localhost-write-consent.ts +141 -0
  197. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +13 -19
  198. package/corpus/templates/design/app/routes/settings.tsx +16 -1
  199. package/corpus/templates/design/changelog/2026-07-08-design-generation-now-follows-hydrated-builder-design-system.md +6 -0
  200. package/corpus/templates/design/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
  201. package/corpus/templates/design/server/lib/verify-write-grant.ts +4 -2
  202. package/corpus/templates/dispatch/app/routes/settings.tsx +23 -2
  203. package/corpus/templates/dispatch/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
  204. package/corpus/templates/forms/app/routes/_app.settings.tsx +16 -1
  205. package/corpus/templates/forms/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
  206. package/corpus/templates/macros/app/routes/settings.tsx +16 -1
  207. package/corpus/templates/macros/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
  208. package/corpus/templates/mail/app/components/settings/GmailFiltersSection.tsx +1 -1
  209. package/corpus/templates/mail/app/components/settings/SnippetsSection.tsx +1 -1
  210. package/corpus/templates/mail/app/pages/SettingsPage.tsx +123 -105
  211. package/corpus/templates/mail/changelog/2026-07-08-settings-redesigned-with-a-consistent-searchable-layout.md +5 -0
  212. package/corpus/templates/plan/app/routes/settings.tsx +23 -2
  213. package/corpus/templates/plan/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
  214. package/corpus/templates/slides/actions/add-slide.ts +1 -0
  215. package/corpus/templates/slides/actions/get-design-system.ts +147 -1
  216. package/corpus/templates/slides/app/pages/Index.tsx +46 -1
  217. package/corpus/templates/slides/app/routes/settings.tsx +16 -1
  218. package/corpus/templates/slides/changelog/2026-07-08-deck-generation-now-follows-hydrated-builder-design-system-g.md +6 -0
  219. package/corpus/templates/slides/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
  220. package/dist/agent/run-ownership.d.ts +6 -0
  221. package/dist/agent/run-ownership.d.ts.map +1 -1
  222. package/dist/agent/run-ownership.js +11 -1
  223. package/dist/agent/run-ownership.js.map +1 -1
  224. package/dist/changelog/parse.d.ts +7 -0
  225. package/dist/changelog/parse.d.ts.map +1 -1
  226. package/dist/changelog/parse.js +64 -0
  227. package/dist/changelog/parse.js.map +1 -1
  228. package/dist/chat-threads/schema.d.ts +445 -0
  229. package/dist/chat-threads/schema.d.ts.map +1 -0
  230. package/dist/chat-threads/schema.js +39 -0
  231. package/dist/chat-threads/schema.js.map +1 -0
  232. package/dist/chat-threads/store.d.ts +12 -0
  233. package/dist/chat-threads/store.d.ts.map +1 -1
  234. package/dist/chat-threads/store.js +99 -10
  235. package/dist/chat-threads/store.js.map +1 -1
  236. package/dist/cli/design-connect.d.ts.map +1 -1
  237. package/dist/cli/design-connect.js +40 -10
  238. package/dist/cli/design-connect.js.map +1 -1
  239. package/dist/cli/workspace-dev.d.ts.map +1 -1
  240. package/dist/cli/workspace-dev.js +20 -5
  241. package/dist/cli/workspace-dev.js.map +1 -1
  242. package/dist/client/AgentPanel.d.ts.map +1 -1
  243. package/dist/client/AgentPanel.js +35 -7
  244. package/dist/client/AgentPanel.js.map +1 -1
  245. package/dist/client/AssistantChat.d.ts.map +1 -1
  246. package/dist/client/AssistantChat.js +105 -183
  247. package/dist/client/AssistantChat.js.map +1 -1
  248. package/dist/client/analytics-session.d.ts +3 -0
  249. package/dist/client/analytics-session.d.ts.map +1 -0
  250. package/dist/client/analytics-session.js +66 -0
  251. package/dist/client/analytics-session.js.map +1 -0
  252. package/dist/client/analytics.d.ts +32 -0
  253. package/dist/client/analytics.d.ts.map +1 -1
  254. package/dist/client/analytics.js +116 -46
  255. package/dist/client/analytics.js.map +1 -1
  256. package/dist/client/chat/message-components.d.ts +2 -1
  257. package/dist/client/chat/message-components.d.ts.map +1 -1
  258. package/dist/client/chat/message-components.js +16 -6
  259. package/dist/client/chat/message-components.js.map +1 -1
  260. package/dist/client/components/ui/message-scroller.d.ts +16 -0
  261. package/dist/client/components/ui/message-scroller.d.ts.map +1 -0
  262. package/dist/client/components/ui/message-scroller.js +25 -0
  263. package/dist/client/components/ui/message-scroller.js.map +1 -0
  264. package/dist/client/conversation/AgentConversation.d.ts +1 -1
  265. package/dist/client/conversation/AgentConversation.d.ts.map +1 -1
  266. package/dist/client/conversation/AgentConversation.js +3 -8
  267. package/dist/client/conversation/AgentConversation.js.map +1 -1
  268. package/dist/client/error-capture.d.ts +99 -0
  269. package/dist/client/error-capture.d.ts.map +1 -0
  270. package/dist/client/error-capture.js +437 -0
  271. package/dist/client/error-capture.js.map +1 -0
  272. package/dist/client/index.d.ts +2 -2
  273. package/dist/client/index.d.ts.map +1 -1
  274. package/dist/client/index.js +3 -1
  275. package/dist/client/index.js.map +1 -1
  276. package/dist/client/session-replay.d.ts +22 -0
  277. package/dist/client/session-replay.d.ts.map +1 -1
  278. package/dist/client/session-replay.js +45 -4
  279. package/dist/client/session-replay.js.map +1 -1
  280. package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
  281. package/dist/client/settings/SettingsPanel.js +100 -5
  282. package/dist/client/settings/SettingsPanel.js.map +1 -1
  283. package/dist/client/settings/SettingsTabsPage.d.ts +49 -1
  284. package/dist/client/settings/SettingsTabsPage.d.ts.map +1 -1
  285. package/dist/client/settings/SettingsTabsPage.js +131 -19
  286. package/dist/client/settings/SettingsTabsPage.js.map +1 -1
  287. package/dist/client/settings/index.d.ts +1 -1
  288. package/dist/client/settings/index.d.ts.map +1 -1
  289. package/dist/client/settings/index.js.map +1 -1
  290. package/dist/client/sharing/ShareButton.d.ts.map +1 -1
  291. package/dist/client/sharing/ShareButton.js +13 -8
  292. package/dist/client/sharing/ShareButton.js.map +1 -1
  293. package/dist/client/sharing/ShareDialog.d.ts.map +1 -1
  294. package/dist/client/sharing/ShareDialog.js +12 -7
  295. package/dist/client/sharing/ShareDialog.js.map +1 -1
  296. package/dist/collab/routes.d.ts +1 -1
  297. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  298. package/dist/mcp/builtin-tools.d.ts.map +1 -1
  299. package/dist/mcp/builtin-tools.js +21 -2
  300. package/dist/mcp/builtin-tools.js.map +1 -1
  301. package/dist/observability/routes.d.ts +1 -1
  302. package/dist/org/schema.d.ts +15 -15
  303. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  304. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  305. package/dist/server/agent-chat-plugin.js +109 -73
  306. package/dist/server/agent-chat-plugin.js.map +1 -1
  307. package/dist/server/onboarding-html.d.ts.map +1 -1
  308. package/dist/server/onboarding-html.js +28 -16
  309. package/dist/server/onboarding-html.js.map +1 -1
  310. package/dist/sharing/actions/list-resource-shares.js +30 -1
  311. package/dist/sharing/actions/list-resource-shares.js.map +1 -1
  312. package/dist/sharing/actions/share-resource.js +6 -0
  313. package/dist/sharing/actions/share-resource.js.map +1 -1
  314. package/dist/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +4 -2
  315. package/dist/templates/workspace-core/.agents/skills/changelog/SKILL.md +9 -6
  316. package/dist/vite/client.d.ts.map +1 -1
  317. package/dist/vite/client.js +192 -30
  318. package/dist/vite/client.js.map +1 -1
  319. package/docs/content/toolkit-settings.mdx +56 -3
  320. package/package.json +2 -1
  321. package/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +4 -2
  322. package/src/templates/workspace-core/.agents/skills/changelog/SKILL.md +9 -6
@@ -1,5 +1,12 @@
1
- import { IconHistory, IconSettings, IconUsers } from "@tabler/icons-react";
2
1
  import {
2
+ IconHistory,
3
+ IconSearch,
4
+ IconSettings,
5
+ IconUsers,
6
+ IconX,
7
+ } from "@tabler/icons-react";
8
+ import {
9
+ useCallback,
3
10
  useEffect,
4
11
  useMemo,
5
12
  useState,
@@ -11,11 +18,40 @@ import { cn } from "../utils.js";
11
18
 
12
19
  type SettingsTabIcon = ComponentType<{ className?: string }>;
13
20
 
21
+ /**
22
+ * A single deep-link target inside settings that the settings search can jump
23
+ * to. Entries usually map to a section within a tab (via a `hash`/anchor id),
24
+ * making individual controls discoverable without hunting through every tab.
25
+ */
26
+ export interface SettingsSearchEntry {
27
+ /** Stable unique id for the entry. */
28
+ id: string;
29
+ /** Primary label shown in the search results. */
30
+ label: string;
31
+ /** Extra space-separated terms to match against (synonyms, provider names). */
32
+ keywords?: string;
33
+ /** Optional secondary description shown under the label. */
34
+ description?: string;
35
+ /** Tab to activate when the entry is picked. Defaults to the owning tab. */
36
+ tabId?: string;
37
+ /**
38
+ * Optional section id / DOM element id to open + scroll to after switching
39
+ * tabs. Handled by the inner panels' own hash listeners.
40
+ */
41
+ hash?: string;
42
+ /** Optional icon override; defaults to the owning tab's icon. */
43
+ icon?: SettingsTabIcon;
44
+ }
45
+
14
46
  export interface SettingsTabItem {
15
47
  id: string;
16
48
  label: string;
17
49
  icon?: SettingsTabIcon;
18
50
  content: ReactNode;
51
+ /** Extra space-separated terms so this tab is findable via search. */
52
+ keywords?: string;
53
+ /** Deep-link entries within this tab for the settings search. */
54
+ searchEntries?: SettingsSearchEntry[];
19
55
  }
20
56
 
21
57
  export interface SettingsTabsPageProps {
@@ -31,6 +67,33 @@ export interface SettingsTabsPageProps {
31
67
  className?: string;
32
68
  navClassName?: string;
33
69
  contentClassName?: string;
70
+ /** Whether to render the settings search box. Defaults to true. */
71
+ enableSearch?: boolean;
72
+ /** Placeholder for the settings search box. */
73
+ searchPlaceholder?: string;
74
+ /** Extra global search entries (e.g. anchors within the General tab). */
75
+ searchEntries?: SettingsSearchEntry[];
76
+ /** Deep-link entries for the General tab. */
77
+ generalSearchEntries?: SettingsSearchEntry[];
78
+ /**
79
+ * Controlled active tab id. When provided, the parent owns tab state (and is
80
+ * responsible for URL/app-state sync); the component skips its own hash-based
81
+ * tab tracking. Leave undefined for the default uncontrolled, hash-driven
82
+ * behavior.
83
+ */
84
+ value?: string;
85
+ /**
86
+ * Called whenever the active tab changes via a tab click or a search result
87
+ * selection. Fires in both controlled and uncontrolled modes.
88
+ */
89
+ onValueChange?: (tabId: string) => void;
90
+ }
91
+
92
+ interface ResolvedSearchEntry extends SettingsSearchEntry {
93
+ tabId: string;
94
+ tabLabel: string;
95
+ icon?: SettingsTabIcon;
96
+ haystack: string;
34
97
  }
35
98
 
36
99
  function normalizeTabId(value?: string | null): string | null {
@@ -88,6 +151,12 @@ export function SettingsTabsPage({
88
151
  className,
89
152
  navClassName,
90
153
  contentClassName,
154
+ enableSearch = true,
155
+ searchPlaceholder = "Search settings",
156
+ searchEntries,
157
+ generalSearchEntries,
158
+ value,
159
+ onValueChange,
91
160
  }: SettingsTabsPageProps) {
92
161
  const tabs = useMemo<SettingsTabItem[]>(() => {
93
162
  const next: SettingsTabItem[] = [
@@ -96,6 +165,7 @@ export function SettingsTabsPage({
96
165
  label: generalLabel,
97
166
  icon: IconSettings,
98
167
  content: general,
168
+ searchEntries: generalSearchEntries,
99
169
  },
100
170
  ];
101
171
  next.push(...extraTabs);
@@ -120,6 +190,7 @@ export function SettingsTabsPage({
120
190
  extraTabs,
121
191
  general,
122
192
  generalLabel,
193
+ generalSearchEntries,
123
194
  team,
124
195
  teamLabel,
125
196
  whatsNew,
@@ -129,81 +200,257 @@ export function SettingsTabsPage({
129
200
  const fallbackTab = tabs.some((tab) => tab.id === defaultTab)
130
201
  ? defaultTab
131
202
  : (tabs[0]?.id ?? "general");
132
- const [activeTab, setActiveTab] = useState(() =>
203
+ const isControlled = value !== undefined;
204
+ const [internalTab, setInternalTab] = useState(() =>
133
205
  activeTabFromHash(tabs, fallbackTab),
134
206
  );
207
+ const activeTab = isControlled ? value : internalTab;
208
+ const [query, setQuery] = useState("");
209
+
210
+ const changeTab = useCallback(
211
+ (tabId: string) => {
212
+ if (!isControlled) setInternalTab(tabId);
213
+ onValueChange?.(tabId);
214
+ },
215
+ [isControlled, onValueChange],
216
+ );
135
217
 
136
218
  useEffect(() => {
137
- if (tabs.some((tab) => tab.id === activeTab)) return;
138
- setActiveTab(fallbackTab);
139
- }, [activeTab, fallbackTab, tabs]);
219
+ // In controlled mode the parent owns (and validates) the active tab.
220
+ if (isControlled) return;
221
+ if (tabs.some((tab) => tab.id === internalTab)) return;
222
+ setInternalTab(fallbackTab);
223
+ }, [fallbackTab, internalTab, isControlled, tabs]);
140
224
 
141
225
  useEffect(() => {
226
+ // Hash-driven tab tracking only applies to the uncontrolled mode. Only
227
+ // react to hashes that name a top-level tab. Section-level hashes
228
+ // (e.g. `#llm`, `#secrets`) are consumed by the inner panels, so leave
229
+ // the active tab untouched to avoid bouncing back to General.
230
+ if (isControlled) return;
142
231
  const handleHashChange = () => {
143
- setActiveTab(activeTabFromHash(tabs, fallbackTab));
232
+ const fromHash = normalizeTabId(window.location.hash);
233
+ if (fromHash && tabs.some((tab) => tab.id === fromHash)) {
234
+ setInternalTab(fromHash);
235
+ }
144
236
  };
145
237
  window.addEventListener("hashchange", handleHashChange);
146
238
  return () => window.removeEventListener("hashchange", handleHashChange);
147
- }, [fallbackTab, tabs]);
239
+ }, [isControlled, tabs]);
148
240
 
149
241
  const selectedTab = tabs.find((tab) => tab.id === activeTab) ?? tabs[0];
150
242
 
243
+ // Flatten tab + deep-link entries into one searchable index.
244
+ const searchIndex = useMemo<ResolvedSearchEntry[]>(() => {
245
+ const entries: ResolvedSearchEntry[] = [];
246
+ const seen = new Set<string>();
247
+ const add = (entry: ResolvedSearchEntry) => {
248
+ if (seen.has(entry.id)) return;
249
+ seen.add(entry.id);
250
+ entries.push(entry);
251
+ };
252
+ for (const tab of tabs) {
253
+ add({
254
+ id: `tab:${tab.id}`,
255
+ label: tab.label,
256
+ keywords: tab.keywords,
257
+ tabId: tab.id,
258
+ tabLabel: tab.label,
259
+ icon: tab.icon,
260
+ haystack: `${tab.label} ${tab.keywords ?? ""}`.toLowerCase(),
261
+ });
262
+ for (const sub of tab.searchEntries ?? []) {
263
+ add({
264
+ ...sub,
265
+ tabId: sub.tabId ?? tab.id,
266
+ tabLabel: tab.label,
267
+ icon: sub.icon ?? tab.icon,
268
+ haystack:
269
+ `${sub.label} ${sub.keywords ?? ""} ${sub.description ?? ""} ${tab.label}`.toLowerCase(),
270
+ });
271
+ }
272
+ }
273
+ for (const sub of searchEntries ?? []) {
274
+ const owner = tabs.find((tab) => tab.id === (sub.tabId ?? "general"));
275
+ add({
276
+ ...sub,
277
+ tabId: sub.tabId ?? "general",
278
+ tabLabel: owner?.label ?? sub.tabId ?? "General",
279
+ icon: sub.icon ?? owner?.icon,
280
+ haystack:
281
+ `${sub.label} ${sub.keywords ?? ""} ${sub.description ?? ""} ${owner?.label ?? ""}`.toLowerCase(),
282
+ });
283
+ }
284
+ return entries;
285
+ }, [searchEntries, tabs]);
286
+
287
+ const trimmedQuery = query.trim().toLowerCase();
288
+ const results = useMemo<ResolvedSearchEntry[]>(() => {
289
+ if (!trimmedQuery) return [];
290
+ const terms = trimmedQuery.split(/\s+/).filter(Boolean);
291
+ return searchIndex
292
+ .filter((entry) => terms.every((term) => entry.haystack.includes(term)))
293
+ .sort((a, b) => {
294
+ const aStarts = a.label.toLowerCase().startsWith(trimmedQuery) ? 0 : 1;
295
+ const bStarts = b.label.toLowerCase().startsWith(trimmedQuery) ? 0 : 1;
296
+ if (aStarts !== bStarts) return aStarts - bStarts;
297
+ return a.label.localeCompare(b.label);
298
+ });
299
+ }, [searchIndex, trimmedQuery]);
300
+
301
+ const selectEntry = (entry: ResolvedSearchEntry) => {
302
+ changeTab(entry.tabId);
303
+ setQuery("");
304
+ if (typeof window === "undefined") return;
305
+ const hash = entry.hash?.replace(/^#/, "");
306
+ if (hash) {
307
+ const { pathname, search } = window.location;
308
+ window.history.pushState(null, "", `${pathname}${search}#${hash}`);
309
+ // Let the inner panels open + scroll to their section.
310
+ window.dispatchEvent(new Event("hashchange"));
311
+ window.requestAnimationFrame(() => {
312
+ document
313
+ .getElementById(hash)
314
+ ?.scrollIntoView({ block: "start", behavior: "smooth" });
315
+ });
316
+ } else if (!isControlled) {
317
+ updateHashForTab(entry.tabId);
318
+ }
319
+ };
320
+
321
+ const searching = enableSearch && trimmedQuery.length > 0;
322
+
151
323
  return (
152
324
  <div
153
325
  className={cn(
154
- "flex min-h-full w-full flex-col overflow-hidden bg-background sm:flex-row",
326
+ "flex h-full min-h-0 w-full flex-col overflow-hidden bg-background sm:flex-row",
155
327
  className,
156
328
  )}
157
329
  >
158
- <nav
159
- aria-label={ariaLabel}
160
- role="tablist"
330
+ <div
161
331
  className={cn(
162
- "flex shrink-0 gap-1 overflow-x-auto border-b border-border/50 bg-muted/30 p-2 sm:w-48 sm:flex-col sm:overflow-x-visible sm:border-b-0 sm:border-e",
332
+ "flex shrink-0 flex-col gap-2 border-b border-border bg-background p-2 sm:min-h-0 sm:w-56 sm:overflow-y-auto sm:border-b-0 sm:border-e sm:p-3",
163
333
  navClassName,
164
334
  )}
165
335
  >
166
- {tabs.map((tab) => {
167
- const Icon = tab.icon;
168
- const selected = tab.id === selectedTab?.id;
169
- return (
170
- <button
171
- key={tab.id}
172
- type="button"
173
- role="tab"
174
- aria-selected={selected}
175
- aria-controls={`settings-tabpanel-${tab.id}`}
176
- id={`settings-tab-${tab.id}`}
177
- onClick={() => {
178
- setActiveTab(tab.id);
179
- updateHashForTab(tab.id);
336
+ {enableSearch ? (
337
+ <div className="relative sm:mb-1">
338
+ <IconSearch className="pointer-events-none absolute start-2.5 top-1/2 size-3.5 -translate-y-1/2 text-muted-foreground" />
339
+ <input
340
+ type="search"
341
+ value={query}
342
+ onChange={(event) => setQuery(event.target.value)}
343
+ onKeyDown={(event) => {
344
+ if (event.key === "Escape") setQuery("");
345
+ if (event.key === "Enter" && results[0]) {
346
+ event.preventDefault();
347
+ selectEntry(results[0]);
348
+ }
180
349
  }}
181
- className={cn(
182
- "flex min-h-9 shrink-0 items-center gap-2 rounded-md px-3 py-2 text-start text-sm font-medium transition-colors sm:w-full",
183
- selected
184
- ? "bg-background text-foreground shadow-sm ring-1 ring-border/60"
185
- : "text-muted-foreground hover:bg-accent/60 hover:text-foreground",
186
- )}
187
- >
188
- {Icon ? (
189
- <Icon
350
+ placeholder={searchPlaceholder}
351
+ aria-label={searchPlaceholder}
352
+ className="h-8 w-full rounded-md border border-border bg-background ps-8 pe-7 text-[13px] text-foreground outline-none transition-colors placeholder:text-muted-foreground focus:border-foreground/30 focus:ring-2 focus:ring-accent/40"
353
+ />
354
+ {query ? (
355
+ <button
356
+ type="button"
357
+ onClick={() => setQuery("")}
358
+ aria-label="Clear search"
359
+ className="absolute end-1.5 top-1/2 flex size-5 -translate-y-1/2 items-center justify-center rounded text-muted-foreground hover:bg-accent/60 hover:text-foreground"
360
+ >
361
+ <IconX className="size-3.5" />
362
+ </button>
363
+ ) : null}
364
+ </div>
365
+ ) : null}
366
+
367
+ {searching ? (
368
+ <div
369
+ role="listbox"
370
+ aria-label="Settings search results"
371
+ className="flex flex-col gap-0.5"
372
+ >
373
+ {results.length === 0 ? (
374
+ <p className="px-2 py-6 text-center text-[12px] text-muted-foreground">
375
+ No matching settings
376
+ </p>
377
+ ) : (
378
+ results.map((entry) => {
379
+ const Icon = entry.icon;
380
+ return (
381
+ <button
382
+ key={entry.id}
383
+ type="button"
384
+ role="option"
385
+ aria-selected={false}
386
+ onClick={() => selectEntry(entry)}
387
+ className="flex items-start gap-2 rounded-md px-2.5 py-2 text-start text-sm text-foreground transition-colors hover:bg-accent/60"
388
+ >
389
+ {Icon ? (
390
+ <Icon className="mt-0.5 size-4 shrink-0 text-muted-foreground" />
391
+ ) : null}
392
+ <span className="flex min-w-0 flex-col">
393
+ <span className="truncate font-medium">
394
+ {entry.label}
395
+ </span>
396
+ <span className="truncate text-[11px] text-muted-foreground">
397
+ {entry.description ?? entry.tabLabel}
398
+ </span>
399
+ </span>
400
+ </button>
401
+ );
402
+ })
403
+ )}
404
+ </div>
405
+ ) : (
406
+ <nav
407
+ aria-label={ariaLabel}
408
+ role="tablist"
409
+ className="flex gap-1 overflow-x-auto sm:flex-col sm:overflow-x-visible"
410
+ >
411
+ {tabs.map((tab) => {
412
+ const Icon = tab.icon;
413
+ const selected = tab.id === selectedTab?.id;
414
+ return (
415
+ <button
416
+ key={tab.id}
417
+ type="button"
418
+ role="tab"
419
+ aria-selected={selected}
420
+ aria-controls={`settings-tabpanel-${tab.id}`}
421
+ id={`settings-tab-${tab.id}`}
422
+ onClick={() => {
423
+ changeTab(tab.id);
424
+ if (!isControlled) updateHashForTab(tab.id);
425
+ }}
190
426
  className={cn(
191
- "size-4 shrink-0",
192
- selected ? "text-foreground" : "text-muted-foreground",
427
+ "flex min-h-9 shrink-0 items-center gap-2 rounded-md px-3 py-2 text-start text-sm font-medium transition-colors sm:w-full",
428
+ selected
429
+ ? "bg-accent text-foreground"
430
+ : "text-muted-foreground hover:bg-accent/50 hover:text-foreground",
193
431
  )}
194
- />
195
- ) : null}
196
- <span className="truncate">{tab.label}</span>
197
- </button>
198
- );
199
- })}
200
- </nav>
432
+ >
433
+ {Icon ? (
434
+ <Icon
435
+ className={cn(
436
+ "size-4 shrink-0",
437
+ selected ? "text-foreground" : "text-muted-foreground",
438
+ )}
439
+ />
440
+ ) : null}
441
+ <span className="truncate">{tab.label}</span>
442
+ </button>
443
+ );
444
+ })}
445
+ </nav>
446
+ )}
447
+ </div>
201
448
  <div
202
449
  id={`settings-tabpanel-${selectedTab?.id ?? "general"}`}
203
450
  role="tabpanel"
204
451
  aria-labelledby={`settings-tab-${selectedTab?.id ?? "general"}`}
205
452
  className={cn(
206
- "min-w-0 flex-1 overflow-y-auto p-4 sm:p-6",
453
+ "min-h-0 min-w-0 flex-1 overflow-y-auto p-4 sm:p-6",
207
454
  contentClassName,
208
455
  )}
209
456
  >
@@ -5,6 +5,7 @@ export {
5
5
  } from "./SettingsPanel.js";
6
6
  export {
7
7
  SettingsTabsPage,
8
+ type SettingsSearchEntry,
8
9
  type SettingsTabItem,
9
10
  type SettingsTabsPageProps,
10
11
  } from "./SettingsTabsPage.js";
@@ -142,6 +142,7 @@ interface Share {
142
142
  id: string;
143
143
  principalType: "user" | "org";
144
144
  principalId: string;
145
+ displayName?: string | null;
145
146
  role: Role;
146
147
  }
147
148
 
@@ -962,17 +963,11 @@ function SharePanel(
962
963
  )}
963
964
  >
964
965
  <Avatar
965
- label={
966
- s.principalType === "org"
967
- ? s.principalId
968
- : displayName(s.principalId, knownMembers)
969
- }
966
+ label={principalLabel(s, knownMembers)}
970
967
  org={s.principalType === "org"}
971
968
  />
972
969
  <span className="flex-1 min-w-0 truncate">
973
- {s.principalType === "org"
974
- ? s.principalId
975
- : displayName(s.principalId, knownMembers)}
970
+ {principalLabel(s, knownMembers)}
976
971
  </span>
977
972
  {canManage ? (
978
973
  <RoleSelect
@@ -1717,8 +1712,16 @@ function initials(s: string): string {
1717
1712
  return (name[0] ?? "?").toUpperCase();
1718
1713
  }
1719
1714
 
1720
- function displayName(email: string, members: OrgMember[]): string {
1721
- const match = members.find((m) => m.email === email);
1715
+ function principalLabel(share: Share, members: OrgMember[]): string {
1716
+ const serverLabel = share.displayName?.trim();
1717
+ if (serverLabel) return serverLabel;
1718
+ if (share.principalType === "org") return "Organization";
1719
+ return displayName(share.principalId, members);
1720
+ }
1721
+
1722
+ function displayName(emailOrId: string, members: OrgMember[]): string {
1723
+ const normalized = emailOrId.trim().toLowerCase();
1724
+ const match = members.find((m) => m.email.toLowerCase() === normalized);
1722
1725
  if (match?.name && match.name.trim()) return match.name;
1723
- return email;
1726
+ return normalized.includes("@") ? emailOrId : "Unknown person";
1724
1727
  }
@@ -52,6 +52,7 @@ interface Share {
52
52
  id: string;
53
53
  principalType: "user" | "org";
54
54
  principalId: string;
55
+ displayName?: string | null;
55
56
  role: Role;
56
57
  }
57
58
 
@@ -95,9 +96,10 @@ function useOrgMembers(): OrgMember[] {
95
96
  }
96
97
 
97
98
  function displayName(email: string, members: OrgMember[]): string {
98
- const match = members.find((m) => m.email === email);
99
+ const normalized = email.trim().toLowerCase();
100
+ const match = members.find((m) => m.email.toLowerCase() === normalized);
99
101
  if (match?.name && match.name.trim()) return match.name;
100
- return email;
102
+ return normalized.includes("@") ? email : "Unknown person";
101
103
  }
102
104
 
103
105
  const BUTTON_BASE =
@@ -552,17 +554,11 @@ function InviteTab(props: {
552
554
  className="flex items-center gap-3 px-1 py-1.5 text-sm"
553
555
  >
554
556
  <Avatar
555
- label={
556
- s.principalType === "org"
557
- ? s.principalId
558
- : displayName(s.principalId, orgMembers)
559
- }
557
+ label={principalLabel(s, orgMembers)}
560
558
  org={s.principalType === "org"}
561
559
  />
562
560
  <span className="flex-1 min-w-0 truncate">
563
- {s.principalType === "org"
564
- ? s.principalId
565
- : displayName(s.principalId, orgMembers)}
561
+ {principalLabel(s, orgMembers)}
566
562
  </span>
567
563
  <span className="text-xs text-muted-foreground">
568
564
  {cap(s.role)}
@@ -841,3 +837,10 @@ function getNotificationUrl(explicit?: string): string | undefined {
841
837
  function cap(s: string): string {
842
838
  return s.charAt(0).toUpperCase() + s.slice(1);
843
839
  }
840
+
841
+ function principalLabel(share: Share, members: OrgMember[]): string {
842
+ const serverLabel = share.displayName?.trim();
843
+ if (serverLabel) return serverLabel;
844
+ if (share.principalType === "org") return "Organization";
845
+ return displayName(share.principalId, members);
846
+ }
@@ -83,6 +83,7 @@ const ASK_APP_DEFAULT_INLINE_WAIT_MS = 20_000;
83
83
  const ASK_APP_MAX_INLINE_WAIT_MS = 25_000;
84
84
  const ASK_APP_POLL_INTERVAL_MS = 1_500;
85
85
  const ASK_APP_A2A_REQUEST_TIMEOUT_MS = 10_000;
86
+ const ASK_APP_STATUS_RETRY_DELAYS_MS = [250, 750, 1_500] as const;
86
87
  const ASK_APP_TERMINAL_STATES = new Set<string>([
87
88
  "completed",
88
89
  "failed",
@@ -321,8 +322,34 @@ async function fetchAskAppA2ATask(
321
322
  taskId: string,
322
323
  ): Promise<AskAppTaskResult> {
323
324
  const { client } = await createA2AClientForAskApp(route.origin);
324
- const task = await client.getTask(taskId);
325
- return askAppTaskResult(route, task);
325
+ let lastError: unknown;
326
+ for (
327
+ let attempt = 0;
328
+ attempt <= ASK_APP_STATUS_RETRY_DELAYS_MS.length;
329
+ attempt++
330
+ ) {
331
+ try {
332
+ const task = await client.getTask(taskId);
333
+ return askAppTaskResult(route, task);
334
+ } catch (err) {
335
+ lastError = err;
336
+ const delayMs = ASK_APP_STATUS_RETRY_DELAYS_MS[attempt];
337
+ if (delayMs == null || !isTransientAskAppStatusError(err)) {
338
+ throw err;
339
+ }
340
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
341
+ }
342
+ }
343
+ throw lastError;
344
+ }
345
+
346
+ function isTransientAskAppStatusError(err: unknown): boolean {
347
+ const message = err instanceof Error ? err.message : String(err ?? "");
348
+ return (
349
+ /\bfetch failed\b|failed to fetch|networkerror|socket hang up|econnreset|etimedout|timeout|aborted/i.test(
350
+ message,
351
+ ) || /A2A request failed \((?:429|500|502|503|504)\)/i.test(message)
352
+ );
326
353
  }
327
354
 
328
355
  /**