@agent-native/core 0.151.1 → 0.152.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (256) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/.agents/skills/sharing/SKILL.md +1 -1
  3. package/corpus/templates/analytics/.agents/skills/turn-into-app/SKILL.md +24 -0
  4. package/corpus/templates/analytics/actions/bigquery-query.ts +21 -0
  5. package/corpus/templates/analytics/app/components/ConnectionTestStatus.tsx +65 -0
  6. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +3 -3
  7. package/corpus/templates/analytics/app/pages/DataSources.tsx +15 -37
  8. package/corpus/templates/analytics/app/root.tsx +0 -1
  9. package/corpus/templates/analytics/changelog/2026-08-11-analytics-custom-blocks-keep-loading-with-legacy-bigquery-action.md +6 -0
  10. package/corpus/templates/analytics/changelog/2026-08-11-analytics-routes-company-knowledge-and-slack-context-questio.md +6 -0
  11. package/corpus/templates/analytics/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
  12. package/corpus/templates/analytics/public/manifest.json +0 -1
  13. package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +5 -0
  14. package/corpus/templates/analytics/server/plugins/agent-chat.ts +5 -0
  15. package/corpus/templates/assets/.agents/skills/sharing/SKILL.md +1 -1
  16. package/corpus/templates/assets/.agents/skills/turn-into-app/SKILL.md +24 -0
  17. package/corpus/templates/assets/app/root.tsx +0 -1
  18. package/corpus/templates/assets/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
  19. package/corpus/templates/assets/public/manifest.json +0 -1
  20. package/corpus/templates/brain/.agents/skills/sharing/SKILL.md +1 -1
  21. package/corpus/templates/brain/.agents/skills/turn-into-app/SKILL.md +24 -0
  22. package/corpus/templates/brain/app/root.tsx +0 -1
  23. package/corpus/templates/brain/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
  24. package/corpus/templates/brain/public/manifest.json +0 -1
  25. package/corpus/templates/calendar/.agents/skills/sharing/SKILL.md +1 -1
  26. package/corpus/templates/calendar/.agents/skills/turn-into-app/SKILL.md +24 -0
  27. package/corpus/templates/calendar/app/components/calendar/GoogleConnectBanner.tsx +0 -53
  28. package/corpus/templates/calendar/app/i18n-data.ts +0 -80
  29. package/corpus/templates/calendar/app/root.tsx +0 -1
  30. package/corpus/templates/calendar/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
  31. package/corpus/templates/calendar/changelog/2026-08-11-google-calendar-connection-buttons-now-open-the-sign-in-flow.md +6 -0
  32. package/corpus/templates/calendar/public/manifest.json +0 -1
  33. package/corpus/templates/calendar/server/plugins/auth.ts +0 -10
  34. package/corpus/templates/chat/.agents/skills/sharing/SKILL.md +1 -1
  35. package/corpus/templates/chat/.agents/skills/turn-into-app/SKILL.md +24 -0
  36. package/corpus/templates/chat/app/root.tsx +0 -1
  37. package/corpus/templates/chat/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
  38. package/corpus/templates/chat/public/manifest.json +0 -1
  39. package/corpus/templates/clips/.agents/skills/turn-into-app/SKILL.md +24 -0
  40. package/corpus/templates/clips/app/components/player/playback-comment-overlay.tsx +1 -1
  41. package/corpus/templates/clips/app/components/player/share-dialog.tsx +6 -0
  42. package/corpus/templates/clips/app/components/sharing/share-ui.tsx +20 -3
  43. package/corpus/templates/clips/app/i18n/en-US.ts +4 -4
  44. package/corpus/templates/clips/app/root.tsx +0 -1
  45. package/corpus/templates/clips/app/routes/_app.meetings._index.tsx +1 -3
  46. package/corpus/templates/clips/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
  47. package/corpus/templates/clips/changelog/2026-08-11-clips-desktop-settings-are-now-easier-to-scan-with-a-wider-t.md +6 -0
  48. package/corpus/templates/clips/changelog/2026-08-11-google-calendar-connections-from-meetings-now-open-directly.md +6 -0
  49. package/corpus/templates/clips/changelog/2026-08-11-recording-viewers-can-comment-and-react.md +6 -0
  50. package/corpus/templates/clips/changelog/2026-08-11-system-audio-recording-now-lives-inside-the-microphone-menu-.md +6 -0
  51. package/corpus/templates/clips/changelog/2026-08-11-timestamped-comments-stay-on-the-video-for-three-seconds-wh.md +6 -0
  52. package/corpus/templates/clips/desktop/src/app.tsx +773 -1001
  53. package/corpus/templates/clips/desktop/src/components/MediaDeviceRow.tsx +15 -27
  54. package/corpus/templates/clips/desktop/src/styles.css +364 -5
  55. package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +1 -1
  56. package/corpus/templates/clips/public/manifest.json +0 -1
  57. package/corpus/templates/content/.agents/skills/sharing/SKILL.md +1 -1
  58. package/corpus/templates/content/.agents/skills/turn-into-app/SKILL.md +24 -0
  59. package/corpus/templates/content/AGENTS.md +3 -0
  60. package/corpus/templates/content/actions/resolve-content-landing.ts +120 -0
  61. package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +9 -0
  62. package/corpus/templates/content/app/i18n-data.ts +58 -0
  63. package/corpus/templates/content/app/lib/content-landing.ts +22 -0
  64. package/corpus/templates/content/app/root.tsx +0 -1
  65. package/corpus/templates/content/app/routes/_app._index.tsx +36 -26
  66. package/corpus/templates/content/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
  67. package/corpus/templates/content/changelog/2026-08-11-content-opens-your-last-page-on-return-and-gives-new-users-a.md +6 -0
  68. package/corpus/templates/content/docs/product/capabilities/content.workspace.session-restore.md +7 -1
  69. package/corpus/templates/content/parity/matrix.md +1 -0
  70. package/corpus/templates/content/parity/matrix.ts +22 -0
  71. package/corpus/templates/content/public/manifest.json +0 -1
  72. package/corpus/templates/content/shared/content-landing.ts +17 -0
  73. package/corpus/templates/crm/.agents/skills/sharing/SKILL.md +1 -1
  74. package/corpus/templates/crm/.agents/skills/turn-into-app/SKILL.md +24 -0
  75. package/corpus/templates/crm/app/root.tsx +0 -1
  76. package/corpus/templates/crm/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
  77. package/corpus/templates/crm/public/manifest.json +0 -1
  78. package/corpus/templates/design/.agents/skills/sharing/SKILL.md +1 -1
  79. package/corpus/templates/design/.agents/skills/turn-into-app/SKILL.md +24 -0
  80. package/corpus/templates/design/app/i18n/en-US.ts +5 -0
  81. package/corpus/templates/design/app/root.tsx +0 -1
  82. package/corpus/templates/design/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
  83. package/corpus/templates/design/changelog/2026-08-11-design-sharing-now-identifies-viewers-who-can-add-review-com.md +6 -0
  84. package/corpus/templates/design/public/manifest.json +0 -1
  85. package/corpus/templates/dispatch/.agents/skills/sharing/SKILL.md +1 -1
  86. package/corpus/templates/dispatch/.agents/skills/turn-into-app/SKILL.md +24 -0
  87. package/corpus/templates/dispatch/AGENTS.md +9 -0
  88. package/corpus/templates/dispatch/actions/list-dispatch-usage-metrics.ts +5 -19
  89. package/corpus/templates/dispatch/actions/view-screen.ts +10 -3
  90. package/corpus/templates/dispatch/app/root.tsx +0 -1
  91. package/corpus/templates/dispatch/app/routes/settings.tsx +13 -1
  92. package/corpus/templates/dispatch/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
  93. package/corpus/templates/dispatch/changelog/2026-08-11-clicking-the-dispatch-logo-returns-to-the-overview-page.md +6 -0
  94. package/corpus/templates/dispatch/changelog/2026-08-11-dispatch-no-longer-links-to-itself-from-the-app-switcher.md +6 -0
  95. package/corpus/templates/dispatch/changelog/2026-08-11-dispatch-settings-now-link-directly-to-admin.md +6 -0
  96. package/corpus/templates/dispatch/changelog/2026-08-11-dispatch-shows-usage-trends-recent-prompts-and-an-agent-revi.md +6 -0
  97. package/corpus/templates/dispatch/changelog/2026-08-11-human-friendly-app-names.md +6 -0
  98. package/corpus/templates/dispatch/public/manifest.json +0 -1
  99. package/corpus/templates/dispatch/server/lib/identity-sso.ts +432 -158
  100. package/corpus/templates/dispatch/server/plugins/identity-sso.ts +204 -123
  101. package/corpus/templates/dispatch/server/plugins/setup-dispatch.ts +1 -0
  102. package/corpus/templates/factory/.agents/skills/sharing/SKILL.md +1 -1
  103. package/corpus/templates/factory/.agents/skills/turn-into-app/SKILL.md +24 -0
  104. package/corpus/templates/factory/app/root.tsx +0 -1
  105. package/corpus/templates/factory/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
  106. package/corpus/templates/factory/public/manifest.json +0 -1
  107. package/corpus/templates/forms/.agents/skills/sharing/SKILL.md +1 -1
  108. package/corpus/templates/forms/.agents/skills/turn-into-app/SKILL.md +24 -0
  109. package/corpus/templates/forms/app/root.tsx +0 -1
  110. package/corpus/templates/forms/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
  111. package/corpus/templates/forms/public/manifest.json +0 -1
  112. package/corpus/templates/macros/.agents/skills/sharing/SKILL.md +1 -1
  113. package/corpus/templates/macros/.agents/skills/turn-into-app/SKILL.md +24 -0
  114. package/corpus/templates/mail/.agents/skills/sharing/SKILL.md +1 -1
  115. package/corpus/templates/mail/.agents/skills/turn-into-app/SKILL.md +24 -0
  116. package/corpus/templates/mail/app/root.tsx +0 -1
  117. package/corpus/templates/mail/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
  118. package/corpus/templates/mail/changelog/2026-08-11-google-sign-in-now-opens-the-gmail-connection-flow-directly.md +6 -0
  119. package/corpus/templates/mail/public/manifest.json +0 -1
  120. package/corpus/templates/mail/server/plugins/auth.ts +0 -10
  121. package/corpus/templates/plan/.agents/skills/sharing/SKILL.md +1 -1
  122. package/corpus/templates/plan/.agents/skills/turn-into-app/SKILL.md +24 -0
  123. package/corpus/templates/plan/app/i18n/en-US.ts +2 -0
  124. package/corpus/templates/plan/app/pages/PlansPage.tsx +6 -0
  125. package/corpus/templates/plan/app/root.tsx +0 -1
  126. package/corpus/templates/plan/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
  127. package/corpus/templates/plan/changelog/2026-08-11-plan-sharing-now-identifies-viewers-who-can-add-comments.md +6 -0
  128. package/corpus/templates/plan/public/manifest.json +0 -1
  129. package/corpus/templates/slides/.agents/skills/sharing/SKILL.md +1 -1
  130. package/corpus/templates/slides/.agents/skills/slide-editing/SKILL.md +13 -0
  131. package/corpus/templates/slides/.agents/skills/turn-into-app/SKILL.md +24 -0
  132. package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +6 -0
  133. package/corpus/templates/slides/app/i18n/en-US.ts +2 -0
  134. package/corpus/templates/slides/app/root.tsx +0 -1
  135. package/corpus/templates/slides/changelog/2026-08-10-asking-the-agent-for-several-slide-animations-at-once-now-ke.md +6 -0
  136. package/corpus/templates/slides/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
  137. package/corpus/templates/slides/changelog/2026-08-11-share-dialog-uses-commenter-terminology.md +6 -0
  138. package/corpus/templates/slides/public/manifest.json +0 -1
  139. package/corpus/templates/tasks/.agents/skills/sharing/SKILL.md +1 -1
  140. package/corpus/templates/tasks/.agents/skills/turn-into-app/SKILL.md +24 -0
  141. package/corpus/templates/tasks/app/root.tsx +0 -1
  142. package/corpus/templates/tasks/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
  143. package/corpus/templates/tasks/public/manifest.json +0 -1
  144. package/dist/agent/production-agent.js +1 -22
  145. package/dist/agent/run-manager.d.ts +7 -0
  146. package/dist/agent/run-manager.js +46 -3
  147. package/dist/agent/tool-approval-migrations.d.ts +40 -0
  148. package/dist/agent/tool-approval-migrations.js +51 -0
  149. package/dist/agent/tool-approval-store.js +5 -20
  150. package/dist/cli/templates-meta.js +2 -2
  151. package/dist/client/AgentPanel.js +10 -1
  152. package/dist/client/AssistantChat.d.ts +3 -0
  153. package/dist/client/AssistantChat.js +148 -140
  154. package/dist/client/agent-page/AgentTabsPage.js +2 -2
  155. package/dist/client/chat/attachment-adapters.js +8 -2
  156. package/dist/client/chat/tool-call-display.d.ts +1 -0
  157. package/dist/client/chat/tool-call-display.js +3 -1
  158. package/dist/client/chat-first.js +11 -5
  159. package/dist/client/hooks/index.d.ts +1 -1
  160. package/dist/client/hooks/index.js +1 -1
  161. package/dist/client/org/OrgSwitcher.d.ts +3 -1
  162. package/dist/client/org/OrgSwitcher.js +22 -16
  163. package/dist/client/org/WorkspaceNotice.js +3 -1
  164. package/dist/client/resources/index.d.ts +1 -1
  165. package/dist/client/resources/index.js +1 -1
  166. package/dist/client/resources/use-mcp-servers.d.ts +1 -0
  167. package/dist/client/resources/use-mcp-servers.js +14 -0
  168. package/dist/client/settings/AccountSettingsCard.js +8 -4
  169. package/dist/client/settings/SettingsPanel.js +46 -13
  170. package/dist/client/settings/SettingsTabsPage.js +8 -3
  171. package/dist/client/sharing/ShareButton.d.ts +7 -1
  172. package/dist/client/sharing/ShareButton.js +14 -7
  173. package/dist/client/sharing/ShareDialog.js +5 -1
  174. package/dist/client/sharing/useShareButtonController.d.ts +4 -0
  175. package/dist/client/sharing/useShareButtonController.js +15 -0
  176. package/dist/client/sharing/useShareDialogController.d.ts +7 -0
  177. package/dist/client/sharing/useShareDialogController.js +14 -0
  178. package/dist/client/sse-event-processor.js +37 -0
  179. package/dist/client/use-session.d.ts +2 -0
  180. package/dist/client/use-session.js +69 -5
  181. package/dist/collab/struct-routes.d.ts +1 -1
  182. package/dist/deploy/build.js +1 -1
  183. package/dist/file-upload/pre-upload-attachments.d.ts +3 -4
  184. package/dist/file-upload/pre-upload-attachments.js +65 -17
  185. package/dist/ingestion/index.d.ts +1 -0
  186. package/dist/ingestion/index.js +1 -0
  187. package/dist/ingestion/office.d.ts +3 -3
  188. package/dist/ingestion/office.js +24 -2
  189. package/dist/ingestion/spreadsheet.d.ts +41 -0
  190. package/dist/ingestion/spreadsheet.js +172 -0
  191. package/dist/integrations/adapters/slack.js +7 -3
  192. package/dist/localization/default-messages.d.ts +3 -0
  193. package/dist/localization/default-messages.js +3 -0
  194. package/dist/mcp/embed-app.js +20 -9
  195. package/dist/mcp/screen-memory-stdio.d.ts +7 -7
  196. package/dist/notifications/routes.d.ts +6 -6
  197. package/dist/oauth-tokens/migrations.d.ts +8 -0
  198. package/dist/oauth-tokens/migrations.js +36 -0
  199. package/dist/observability/routes.d.ts +5 -5
  200. package/dist/org/workspace-url.d.ts +8 -0
  201. package/dist/org/workspace-url.js +26 -2
  202. package/dist/progress/routes.d.ts +1 -1
  203. package/dist/secrets/routes.d.ts +3 -3
  204. package/dist/server/agent-chat-plugin.js +16 -8
  205. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  206. package/dist/server/auth.d.ts +0 -11
  207. package/dist/server/auth.js +37 -20
  208. package/dist/server/better-auth-migrations.js +23 -0
  209. package/dist/server/email-template.d.ts +5 -0
  210. package/dist/server/email-template.js +9 -0
  211. package/dist/server/embed-route.js +17 -5
  212. package/dist/server/identity-sso-store.d.ts +40 -66
  213. package/dist/server/identity-sso-store.js +187 -150
  214. package/dist/server/identity-sso.d.ts +17 -73
  215. package/dist/server/identity-sso.js +294 -297
  216. package/dist/server/onboarding-html.d.ts +0 -12
  217. package/dist/server/onboarding-html.js +46 -269
  218. package/dist/server/realtime-token.d.ts +1 -1
  219. package/dist/server/release-migrations.js +8 -0
  220. package/dist/server/transcribe-voice.d.ts +1 -1
  221. package/dist/shared/index.d.ts +1 -1
  222. package/dist/shared/index.js +1 -1
  223. package/dist/shared/workspace-app-id.d.ts +2 -0
  224. package/dist/shared/workspace-app-id.js +10 -0
  225. package/dist/sharing/actions/share-resource.d.ts +1 -0
  226. package/dist/sharing/actions/share-resource.js +20 -5
  227. package/dist/templates/chat/.agents/skills/sharing/SKILL.md +1 -1
  228. package/dist/templates/chat/.agents/skills/turn-into-app/SKILL.md +24 -0
  229. package/dist/templates/chat/app/root.tsx +0 -1
  230. package/dist/templates/chat/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
  231. package/dist/templates/chat/public/manifest.json +0 -1
  232. package/dist/templates/default/.agents/skills/turn-into-app/SKILL.md +24 -0
  233. package/dist/templates/default/app/root.tsx +0 -1
  234. package/dist/templates/default/public/manifest.json +0 -1
  235. package/dist/templates/headless/.agents/skills/turn-into-app/SKILL.md +24 -0
  236. package/dist/templates/workspace-core/.agents/skills/authentication/SKILL.md +22 -11
  237. package/dist/templates/workspace-core/.agents/skills/sharing/SKILL.md +1 -1
  238. package/dist/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +24 -0
  239. package/docs/content/cross-app-sso.mdx +85 -27
  240. package/docs/content/template-mail.mdx +0 -6
  241. package/package.json +4 -3
  242. package/src/templates/chat/.agents/skills/sharing/SKILL.md +1 -1
  243. package/src/templates/chat/.agents/skills/turn-into-app/SKILL.md +24 -0
  244. package/src/templates/chat/app/root.tsx +0 -1
  245. package/src/templates/chat/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
  246. package/src/templates/chat/public/manifest.json +0 -1
  247. package/src/templates/default/.agents/skills/turn-into-app/SKILL.md +24 -0
  248. package/src/templates/default/app/root.tsx +0 -1
  249. package/src/templates/default/public/manifest.json +0 -1
  250. package/src/templates/headless/.agents/skills/turn-into-app/SKILL.md +24 -0
  251. package/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +22 -11
  252. package/src/templates/workspace-core/.agents/skills/sharing/SKILL.md +1 -1
  253. package/src/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +24 -0
  254. package/corpus/templates/calendar/changelog/2026-06-23-added-a-heads-up-explaining-google-s-app-not-verified-screen.md +0 -6
  255. package/corpus/templates/clips/app/components/meetings/google-oauth-identity-notice.tsx +0 -51
  256. package/corpus/templates/clips/changelog/2026-07-30-google-calendar-warning.md +0 -6
@@ -1,6 +1,6 @@
1
1
  // Owns: image/document/text attachment adapters and attachment serialization helpers.
2
2
  import { CHAT_DOCUMENT_ATTACHMENT_ACCEPT, IMAGE_ATTACHMENT_ACCEPT, } from "@agent-native/toolkit/composer/attachment-accept";
3
- // Maximum PDF/document size (4 MB). Larger PDFs would bloat the JSON POST
3
+ // Maximum document size (4 MB). Larger files would bloat the JSON POST
4
4
  // body past Vercel's ~4.5 MB limit after base64 encoding (+33% overhead).
5
5
  export const MAX_PDF_BYTES = 4 * 1024 * 1024;
6
6
  // Anthropic / OpenAI vision inputs choke on multi-megabyte images, and
@@ -28,6 +28,12 @@ export function inferDocumentContentType(file) {
28
28
  return file.type;
29
29
  if (file.name.toLowerCase().endsWith(".pdf"))
30
30
  return "application/pdf";
31
+ if (file.name.toLowerCase().endsWith(".xlsx")) {
32
+ return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
33
+ }
34
+ if (file.name.toLowerCase().endsWith(".xls")) {
35
+ return "application/vnd.ms-excel";
36
+ }
31
37
  if (file.name.toLowerCase().endsWith(".svg"))
32
38
  return "image/svg+xml";
33
39
  return "application/octet-stream";
@@ -43,7 +49,7 @@ export function getFileDataURL(file) {
43
49
  function formatOversizedDocumentError(name, size) {
44
50
  const mb = (size / 1024 / 1024).toFixed(1);
45
51
  const maxMb = (MAX_PDF_BYTES / 1024 / 1024).toFixed(0);
46
- return `"${name}" is ${mb} MB — PDFs are capped at ${maxMb} MB to stay within message limits. Please reduce the file size or split it into smaller parts.`;
52
+ return `"${name}" is ${mb} MB - documents are capped at ${maxMb} MB to stay within message limits. Please reduce the file size or split it into smaller parts.`;
47
53
  }
48
54
  function loadImage(url) {
49
55
  return new Promise((resolve, reject) => {
@@ -8,6 +8,7 @@ export declare const ChatRunningContext: React.Context<boolean>;
8
8
  export declare const ChatRunningRunIdContext: React.Context<string | null>;
9
9
  export declare const ChatRunningTurnIdContext: React.Context<string | null>;
10
10
  export declare const ChatRunDurationContext: React.Context<number | null>;
11
+ export declare const SuppressInlineOpenAppContext: React.Context<boolean>;
11
12
  export declare const ASSISTANT_VISIBLE_TOOL_CALL_LIMIT = 3;
12
13
  /**
13
14
  * Keeps the tool-call stack layout-transparent. Tool-entry motion is disabled
@@ -22,6 +22,7 @@ export const ChatRunningContext = React.createContext(false);
22
22
  export const ChatRunningRunIdContext = React.createContext(null);
23
23
  export const ChatRunningTurnIdContext = React.createContext(null);
24
24
  export const ChatRunDurationContext = React.createContext(null);
25
+ export const SuppressInlineOpenAppContext = React.createContext(false);
25
26
  export const ASSISTANT_VISIBLE_TOOL_CALL_LIMIT = 3;
26
27
  /**
27
28
  * Keeps the tool-call stack layout-transparent. Tool-entry motion is disabled
@@ -291,6 +292,7 @@ export function ToolCallDisplay({ toolName, toolCallId, argsText, args, result,
291
292
  return wrapToolDisplay(_jsx(ToolCallDisplayGeneric, { toolName: toolName, toolCallId: toolCallId, argsText: argsText, args: args, result: result, mcpApp: mcpApp, chatUI: chatUI, isRunning: isRunning, outcome: outcome, isActiveTail: showActiveTail, structuredMeta: structuredMeta, approval: approval, repeatCount: repeatCount }));
292
293
  }
293
294
  function ToolCallDisplayGeneric({ toolName, toolCallId, argsText, args, result, mcpApp, chatUI, isRunning, outcome, isActiveTail, structuredMeta, approval, repeatCount, }) {
295
+ const suppressInlineOpenApp = React.useContext(SuppressInlineOpenAppContext);
294
296
  const isRawCallAgent = toolName === "call-agent";
295
297
  const isAgentCall = toolName.startsWith("agent:") || isRawCallAgent;
296
298
  const [expanded, setExpanded] = useState(isAgentCall);
@@ -405,7 +407,7 @@ function ToolCallDisplayGeneric({ toolName, toolCallId, argsText, args, result,
405
407
  ? structuredMeta.agentDurationMs
406
408
  : agentActivity?.durationMs }));
407
409
  }
408
- return (_jsxs("div", { className: "group/tool my-0.5 w-full overflow-hidden", children: [mcpApp && _jsx(McpAppRenderer, { app: mcpApp, className: "mb-1.5" }), _jsxs("button", { type: "button", onClick: () => canExpand && setExpanded(!isExpanded), "aria-expanded": canExpand ? isExpanded : undefined, className: cn("flex w-full items-center gap-1.5 rounded-md py-0.5 text-left text-[13px] text-muted-foreground transition-colors", canExpand && "hover:text-foreground", isRunning && "text-muted-foreground"), children: [_jsx("span", { className: "relative flex size-4 shrink-0 items-center justify-center", children: isRunning ? (_jsx(IconLoader2, { className: "size-3.5 animate-spin" })) : isAgentError ? (_jsx(IconCircleX, { className: "size-3.5 text-destructive" })) : isUnknownOutcome ? (_jsx(IconAlertTriangle, { className: "size-3.5 text-muted-foreground" })) : (_jsxs(_Fragment, { children: [_jsx(ToolIcon, { className: cn("size-3.5 transition-opacity", canExpand && "group-hover/tool:opacity-0") }), canExpand && (_jsx(IconChevronRight, { className: cn("absolute size-3.5 opacity-0 transition-[opacity,transform] group-hover/tool:opacity-100", isExpanded && "rotate-90") }))] })) }), _jsx("span", { className: cn("min-w-0 truncate font-normal", isActiveTail && "agent-running-shimmer"), children: displayName }), repeatCount && repeatCount > 1 && (_jsxs("span", { className: "shrink-0 rounded border border-border/60 px-1.5 py-0.5 text-[10px] leading-none text-muted-foreground", title: `Repeated ${repeatCount} times`, children: [repeatCount, "x"] }))] }), _jsx(AnimatedCollapse, { open: isExpanded && !isAgentCall && (hasArgs || result !== undefined), children: _jsxs("div", { className: "mt-1 space-y-2 pl-5", children: [inputPayload && (_jsx(SimpleCodeViewer, { text: inputPayload.text, lang: inputPayload.lang })), resultPayload && (_jsx(ToolOutputPopover, { open: outputOpen, onOpenChange: setOutputOpen, title: outputTitle, payload: resultPayload, children: _jsx("button", { type: "button", "aria-label": `View ${toolName} output`, className: "inline-flex size-6 items-center justify-center rounded-md text-muted-foreground/70 transition-colors hover:bg-accent hover:text-foreground", children: _jsx(IconCode, { className: "size-3.5" }) }) }))] }) }), isUnknownOutcome && (_jsx("p", { role: "status", className: "ps-5 text-xs text-muted-foreground", children: "Interrupted before this finished reporting \u2014 it may or may not have completed. Check before retrying." })), approval && (_jsx(ApprovalAffordance, { toolName: toolName, toolCallId: toolCallId, approval: approval }))] }));
410
+ return (_jsxs("div", { className: "group/tool my-0.5 w-full overflow-hidden", children: [mcpApp && !(suppressInlineOpenApp && toolName === "open_app") && (_jsx(McpAppRenderer, { app: mcpApp, className: "mb-1.5" })), _jsxs("button", { type: "button", onClick: () => canExpand && setExpanded(!isExpanded), "aria-expanded": canExpand ? isExpanded : undefined, className: cn("flex w-full items-center gap-1.5 rounded-md py-0.5 text-left text-[13px] text-muted-foreground transition-colors", canExpand && "hover:text-foreground", isRunning && "text-muted-foreground"), children: [_jsx("span", { className: "relative flex size-4 shrink-0 items-center justify-center", children: isRunning ? (_jsx(IconLoader2, { className: "size-3.5 animate-spin" })) : isAgentError ? (_jsx(IconCircleX, { className: "size-3.5 text-destructive" })) : isUnknownOutcome ? (_jsx(IconAlertTriangle, { className: "size-3.5 text-muted-foreground" })) : (_jsxs(_Fragment, { children: [_jsx(ToolIcon, { className: cn("size-3.5 transition-opacity", canExpand && "group-hover/tool:opacity-0") }), canExpand && (_jsx(IconChevronRight, { className: cn("absolute size-3.5 opacity-0 transition-[opacity,transform] group-hover/tool:opacity-100", isExpanded && "rotate-90") }))] })) }), _jsx("span", { className: cn("min-w-0 truncate font-normal", isActiveTail && "agent-running-shimmer"), children: displayName }), repeatCount && repeatCount > 1 && (_jsxs("span", { className: "shrink-0 rounded border border-border/60 px-1.5 py-0.5 text-[10px] leading-none text-muted-foreground", title: `Repeated ${repeatCount} times`, children: [repeatCount, "x"] }))] }), _jsx(AnimatedCollapse, { open: isExpanded && !isAgentCall && (hasArgs || result !== undefined), children: _jsxs("div", { className: "mt-1 space-y-2 pl-5", children: [inputPayload && (_jsx(SimpleCodeViewer, { text: inputPayload.text, lang: inputPayload.lang })), resultPayload && (_jsx(ToolOutputPopover, { open: outputOpen, onOpenChange: setOutputOpen, title: outputTitle, payload: resultPayload, children: _jsx("button", { type: "button", "aria-label": `View ${toolName} output`, className: "inline-flex size-6 items-center justify-center rounded-md text-muted-foreground/70 transition-colors hover:bg-accent hover:text-foreground", children: _jsx(IconCode, { className: "size-3.5" }) }) }))] }) }), isUnknownOutcome && (_jsx("p", { role: "status", className: "ps-5 text-xs text-muted-foreground", children: "Interrupted before this finished reporting \u2014 it may or may not have completed. Check before retrying." })), approval && (_jsx(ApprovalAffordance, { toolName: toolName, toolCallId: toolCallId, approval: approval }))] }));
409
411
  }
410
412
  function AgentCallCell({ agentName, activity, progress, responseText, isRunning, isError, durationMs, }) {
411
413
  const t = useT();
@@ -312,14 +312,20 @@ export function orderChatFirstAppIds(appIds, layout) {
312
312
  ...preferredDefaults,
313
313
  ...appIds.filter((id) => !preferredDefaultSet.has(id)),
314
314
  ];
315
+ const manualOrderedIds = layout.orderedIds.filter((id) => available.has(id));
316
+ const hasManualOrder = manualOrderedIds.length > 0;
315
317
  const ordered = [
316
- ...layout.orderedIds.filter((id) => available.has(id)),
318
+ ...manualOrderedIds,
317
319
  ...fallbackOrder.filter((id) => !layout.orderedIds.includes(id)),
318
320
  ];
319
- const pinned = new Set(layout.pinnedIds.filter((id) => available.has(id)));
320
- // `orderedIds` is the single source of positional truth. Pinning changes
321
- // presentation only; it must not rewrite the user's drag order or make an
322
- // unpinned app jump to the fallback order.
321
+ const pinnedIds = layout.pinnedIds.filter((id) => available.has(id));
322
+ const pinned = new Set(pinnedIds);
323
+ // A live `orderedIds` value is the single source of positional truth. Pinning
324
+ // changes presentation only; it must not rewrite the user's drag order or
325
+ // make an unpinned app jump to the fallback order.
326
+ if (!hasManualOrder) {
327
+ return [...pinnedIds, ...fallbackOrder.filter((id) => !pinned.has(id))];
328
+ }
323
329
  return [
324
330
  ...ordered.filter((id) => pinned.has(id)),
325
331
  ...ordered.filter((id) => !pinned.has(id)),
@@ -4,7 +4,7 @@ export { useDbSync, useFileWatcher, useScreenRefreshKey, } from "../use-db-sync.
4
4
  export { useChangeVersion, useChangeVersions, getChangeVersion, bumpChangeVersion, } from "../use-change-version.js";
5
5
  export { useDemoModeStatus, type DemoModeStatus, } from "../use-demo-mode-status.js";
6
6
  export { useReconciledState } from "../use-external-value.js";
7
- export { useSession, type AuthSession } from "../use-session.js";
7
+ export { notifySessionInvalidated, useSession, type AuthSession, } from "../use-session.js";
8
8
  export { ACTION_KEEPALIVE_BODY_BUDGET_BYTES, callAction, tryCallActionKeepalive, useActionQuery, useActionMutation, type ActionRegistry, type ClientActionCallOptions, type ClientActionMethod, type KeepaliveActionCallRejectionReason, type KeepaliveActionCallResult, } from "../use-action.js";
9
9
  export { createAgentNativeQueryClient } from "../create-query-client.js";
10
10
  export { AppProviders, type AppProvidersProps } from "../app-providers.js";
@@ -4,7 +4,7 @@ export { useDbSync, useFileWatcher, useScreenRefreshKey, } from "../use-db-sync.
4
4
  export { useChangeVersion, useChangeVersions, getChangeVersion, bumpChangeVersion, } from "../use-change-version.js";
5
5
  export { useDemoModeStatus, } from "../use-demo-mode-status.js";
6
6
  export { useReconciledState } from "../use-external-value.js";
7
- export { useSession } from "../use-session.js";
7
+ export { notifySessionInvalidated, useSession, } from "../use-session.js";
8
8
  export { ACTION_KEEPALIVE_BODY_BUDGET_BYTES, callAction, tryCallActionKeepalive, useActionQuery, useActionMutation, } from "../use-action.js";
9
9
  export { createAgentNativeQueryClient } from "../create-query-client.js";
10
10
  export { AppProviders } from "../app-providers.js";
@@ -27,6 +27,8 @@ export interface OrgSwitcherProps {
27
27
  * Pass `null` for apps that do not mount the Agent page.
28
28
  */
29
29
  agentPath?: string | null;
30
+ /** Omit the link to the app that currently owns this switcher. */
31
+ currentAppId?: string;
30
32
  }
31
33
  /**
32
34
  * Compact org switcher button. Shows the active org (or "Personal" when the
@@ -34,4 +36,4 @@ export interface OrgSwitcherProps {
34
36
  * invitations, inline forms to create a new org / invite a teammate, and a
35
37
  * sign-out item. Renders nothing in dev / no-auth mode.
36
38
  */
37
- export declare function OrgSwitcher({ className, hideWhenSingle, reserveSpace, compact, settingsPath, profilePath, agentPath, }: OrgSwitcherProps): import("react").JSX.Element | null;
39
+ export declare function OrgSwitcher({ className, hideWhenSingle, reserveSpace, compact, settingsPath, profilePath, agentPath, currentAppId, }: OrgSwitcherProps): import("react").JSX.Element | null;
@@ -8,7 +8,7 @@ import { shouldOfferWorkspace } from "../../org/workspace-url.js";
8
8
  import { agentNativePath } from "../api-path.js";
9
9
  import { useT } from "../i18n.js";
10
10
  import { useDemoModeStatus } from "../use-demo-mode-status.js";
11
- import { useSession } from "../use-session.js";
11
+ import { notifySessionInvalidated, useSession } from "../use-session.js";
12
12
  import { useOrg, useSwitchOrg, useCreateOrg, useInviteMember, useAcceptInvitation, useJoinByDomain, } from "./hooks.js";
13
13
  import { ORG_SWITCHER_MAX_APP_LINKS, useOrgSwitcherAppLinks, visibleOrgAppLinks, } from "./workspace-app-links.js";
14
14
  function personalLabelFromEmail(email) {
@@ -76,23 +76,28 @@ function AppMenuLink({ app, onNavigate, }) {
76
76
  (app.isDispatch ? "Workspace hub" : `${app.name} workspace`);
77
77
  return (_jsxs("a", { href: app.href, onClick: onNavigate, className: "flex items-center gap-2 rounded-sm px-2.5 py-2 text-xs outline-none hover:bg-accent focus:bg-accent", children: [_jsx("span", { className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-md bg-muted text-muted-foreground", children: _jsx(Icon, { className: "h-3.5 w-3.5" }) }), _jsxs("span", { className: "min-w-0 flex-1", children: [_jsx("span", { className: "block truncate font-medium text-foreground", children: app.name }), _jsx("span", { className: "block truncate text-[11px] text-muted-foreground", title: description, children: description })] }), _jsx(IconArrowUpRight, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" })] }));
78
78
  }
79
- function AppsSubmenu({ apps, isLoading, dispatchHref, dispatchAllAppsHref, onNavigate, }) {
80
- const { links, overflowCount } = visibleOrgAppLinks(apps);
79
+ function AppsSubmenu({ apps, isLoading, dispatchHref, dispatchAllAppsHref, currentAppId, onNavigate, }) {
80
+ const appsForMenu = currentAppId
81
+ ? apps.filter((app) => app.id !== currentAppId)
82
+ : apps;
83
+ const { links, overflowCount } = visibleOrgAppLinks(appsForMenu);
81
84
  const visibleDispatchApp = links.find((app) => app.isDispatch);
82
- const dispatchApp = visibleDispatchApp ??
83
- {
84
- id: "dispatch",
85
- name: "Dispatch",
86
- href: dispatchHref,
87
- isDispatch: true,
88
- status: "ready",
89
- };
85
+ const dispatchApp = currentAppId === "dispatch"
86
+ ? null
87
+ : (visibleDispatchApp ??
88
+ {
89
+ id: "dispatch",
90
+ name: "Dispatch",
91
+ href: dispatchHref,
92
+ isDispatch: true,
93
+ status: "ready",
94
+ });
90
95
  const visibleNonDispatch = links
91
96
  .filter((app) => !app.isDispatch)
92
- .slice(0, visibleDispatchApp ? undefined : ORG_SWITCHER_MAX_APP_LINKS - 1);
97
+ .slice(0, dispatchApp ? undefined : ORG_SWITCHER_MAX_APP_LINKS);
93
98
  const shownCount = (dispatchApp ? 1 : 0) + visibleNonDispatch.length;
94
- const remainingCount = Math.max(overflowCount, apps.length - shownCount);
95
- return (_jsxs(PopoverPrimitive.Root, { children: [_jsx(PopoverPrimitive.Trigger, { asChild: true, children: _jsxs("button", { type: "button", className: `${ITEM_CLASS} cursor-pointer`, children: [_jsx(IconApps, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }), _jsx("span", { className: "flex-1 text-start", children: "Apps" }), _jsx("span", { className: "text-[11px] text-muted-foreground", children: isLoading ? (_jsx(IconLoader2, { className: "h-3 w-3 animate-spin" })) : (apps.length) }), _jsx(IconChevronRight, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground rtl:-scale-x-100" })] }) }), _jsx(PopoverPrimitive.Portal, { children: _jsxs(PopoverPrimitive.Content, { side: "right", align: "start", sideOffset: 8, collisionPadding: 12, className: APP_SUBMENU_CONTENT_CLASS, children: [_jsx(AppMenuLink, { app: dispatchApp, onNavigate: onNavigate }), visibleNonDispatch.length > 0 && (_jsx("div", { className: "my-1 h-px bg-border" })), visibleNonDispatch.map((app) => (_jsx(AppMenuLink, { app: app, onNavigate: onNavigate }, app.id))), remainingCount > 0 && (_jsxs(_Fragment, { children: [_jsx("div", { className: "my-1 h-px bg-border" }), _jsxs("a", { href: dispatchAllAppsHref, onClick: onNavigate, className: "flex items-center gap-2 rounded-sm px-2.5 py-1.5 text-xs text-foreground outline-none hover:bg-accent focus:bg-accent", children: [_jsx(IconApps, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }), _jsx("span", { className: "flex-1", children: `View ${remainingCount} more in Dispatch` }), _jsx(IconArrowUpRight, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" })] })] }))] }) })] }));
99
+ const remainingCount = Math.max(overflowCount, appsForMenu.length - shownCount);
100
+ return (_jsxs(PopoverPrimitive.Root, { children: [_jsx(PopoverPrimitive.Trigger, { asChild: true, children: _jsxs("button", { type: "button", className: `${ITEM_CLASS} cursor-pointer`, children: [_jsx(IconApps, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }), _jsx("span", { className: "flex-1 text-start", children: "Apps" }), _jsx("span", { className: "text-[11px] text-muted-foreground", children: isLoading ? (_jsx(IconLoader2, { className: "h-3 w-3 animate-spin" })) : (appsForMenu.length) }), _jsx(IconChevronRight, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground rtl:-scale-x-100" })] }) }), _jsx(PopoverPrimitive.Portal, { children: _jsxs(PopoverPrimitive.Content, { side: "right", align: "start", sideOffset: 8, collisionPadding: 12, className: APP_SUBMENU_CONTENT_CLASS, children: [dispatchApp && (_jsx(AppMenuLink, { app: dispatchApp, onNavigate: onNavigate })), dispatchApp && visibleNonDispatch.length > 0 && (_jsx("div", { className: "my-1 h-px bg-border" })), visibleNonDispatch.map((app) => (_jsx(AppMenuLink, { app: app, onNavigate: onNavigate }, app.id))), remainingCount > 0 && (_jsxs(_Fragment, { children: [_jsx("div", { className: "my-1 h-px bg-border" }), _jsxs("a", { href: dispatchAllAppsHref, onClick: onNavigate, className: "flex items-center gap-2 rounded-sm px-2.5 py-1.5 text-xs text-foreground outline-none hover:bg-accent focus:bg-accent", children: [_jsx(IconApps, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }), _jsx("span", { className: "flex-1", children: `View ${remainingCount} more in Dispatch` }), _jsx(IconArrowUpRight, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" })] })] }))] }) })] }));
96
101
  }
97
102
  function ReservedOrgSwitcherSpace({ className }) {
98
103
  return _jsx("div", { "aria-hidden": "true", className: `h-8 ${className ?? ""}` });
@@ -106,7 +111,7 @@ function OrgSwitcherLoadingPlaceholder({ className }) {
106
111
  * invitations, inline forms to create a new org / invite a teammate, and a
107
112
  * sign-out item. Renders nothing in dev / no-auth mode.
108
113
  */
109
- export function OrgSwitcher({ className, hideWhenSingle, reserveSpace, compact, settingsPath = DEFAULT_ORGANIZATION_SETTINGS_PATH, profilePath = DEFAULT_PROFILE_PATH, agentPath = DEFAULT_AGENT_PATH, }) {
114
+ export function OrgSwitcher({ className, hideWhenSingle, reserveSpace, compact, settingsPath = DEFAULT_ORGANIZATION_SETTINGS_PATH, profilePath = DEFAULT_PROFILE_PATH, agentPath = DEFAULT_AGENT_PATH, currentAppId, }) {
110
115
  const { data: org, isLoading } = useOrg();
111
116
  const { session } = useSession();
112
117
  const { enabled: demoModeEnabled } = useDemoModeStatus();
@@ -145,6 +150,7 @@ export function OrgSwitcher({ className, hideWhenSingle, reserveSpace, compact,
145
150
  catch {
146
151
  /* fall through to reload — server may already have cleared the cookie */
147
152
  }
153
+ notifySessionInvalidated();
148
154
  window.location.reload();
149
155
  };
150
156
  if (!org) {
@@ -216,7 +222,7 @@ export function OrgSwitcher({ className, hideWhenSingle, reserveSpace, compact,
216
222
  setJoiningOrgId(null);
217
223
  }
218
224
  }, disabled: joinByDomain.isPending, className: "rounded px-1.5 py-0.5 text-[11px] font-medium text-primary hover:bg-primary/10 disabled:opacity-50 cursor-pointer", children: isJoining ? (_jsx(IconLoader2, { className: "h-3 w-3 animate-spin" })) : ("Join") })] }, match.orgId));
219
- })] })), _jsx("div", { className: "my-1 h-px bg-border" }), _jsx(AppsSubmenu, { apps: appLinks.apps, isLoading: appLinks.isLoading, dispatchHref: appLinks.dispatchHref, dispatchAllAppsHref: appLinks.dispatchAllAppsHref, onNavigate: () => setOpen(false) }), profilePath && (_jsxs("button", { type: "button", onClick: () => {
225
+ })] })), _jsx("div", { className: "my-1 h-px bg-border" }), _jsx(AppsSubmenu, { apps: appLinks.apps, isLoading: appLinks.isLoading, dispatchHref: appLinks.dispatchHref, dispatchAllAppsHref: appLinks.dispatchAllAppsHref, currentAppId: currentAppId, onNavigate: () => setOpen(false) }), profilePath && (_jsxs("button", { type: "button", onClick: () => {
220
226
  setOpen(false);
221
227
  navigate(profilePath);
222
228
  }, className: `${ITEM_CLASS} cursor-pointer`, children: [_jsx(IconUserCircle, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }), _jsx("span", { className: "flex-1 text-start", children: t("settings.profileMenuItem") })] })), agentPath && (_jsxs("button", { type: "button", onClick: () => {
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { IconExternalLink } from "@tabler/icons-react";
3
3
  import { useState } from "react";
4
- import { shouldOfferWorkspace } from "../../org/workspace-url.js";
4
+ import { isLocalDevelopmentOrigin, shouldOfferWorkspace, } from "../../org/workspace-url.js";
5
5
  import { useOrg } from "./hooks.js";
6
6
  const DISMISS_KEY_PREFIX = "agent-native:workspace-notice-dismissed:";
7
7
  function dismissKey(workspaceUrl) {
@@ -38,6 +38,8 @@ export function WorkspaceNotice({ className }) {
38
38
  const workspaceUrl = org?.workspaceUrl ?? null;
39
39
  if (typeof window === "undefined")
40
40
  return null;
41
+ if (isLocalDevelopmentOrigin(window.location.href))
42
+ return null;
41
43
  if (!workspaceUrl || dismissedNow || readDismissed(workspaceUrl))
42
44
  return null;
43
45
  if (!shouldOfferWorkspace(window.location.href, workspaceUrl))
@@ -7,4 +7,4 @@ export * from "./use-builtin-capabilities.js";
7
7
  export { DEFAULT_MCP_INTEGRATIONS, filterMcpIntegrations, findMcpIntegrationForText, getDefaultMcpIntegrations, isCustomMcpIntegrationEnabled, isMcpIntegrationCatalogAvailable, mergeDefaultMcpIntegrations, type DefaultMcpIntegration, } from "./mcp-integration-catalog.js";
8
8
  export { McpIntegrationDialog, type McpIntegrationDialogProps, } from "./McpIntegrationDialog.js";
9
9
  export { McpConnectionSuggestion, type McpConnectionSuggestionProps, type McpConnectionSuggestionVariant, } from "./McpConnectionSuggestion.js";
10
- export { McpServersApiProvider, useMcpServersApi, useMcpServers, useCreateMcpServer, useDeleteMcpServer, useReconnectMcpServer, testMcpServerUrl, type CreateMcpServerArgs, type McpServer, type McpServerScope, type McpServersApi, type McpServersList, type ReconnectMcpServerArgs, type TestMcpUrlResult, } from "./use-mcp-servers.js";
10
+ export { McpServersApiProvider, useMcpServersApi, useMcpServers, useCreateMcpServer, useDeleteMcpServer, useReconnectMcpServer, testMcpServerUrl, formatMcpServersLoadError, type CreateMcpServerArgs, type McpServer, type McpServerScope, type McpServersApi, type McpServersList, type ReconnectMcpServerArgs, type TestMcpUrlResult, } from "./use-mcp-servers.js";
@@ -7,4 +7,4 @@ export * from "./use-builtin-capabilities.js";
7
7
  export { DEFAULT_MCP_INTEGRATIONS, filterMcpIntegrations, findMcpIntegrationForText, getDefaultMcpIntegrations, isCustomMcpIntegrationEnabled, isMcpIntegrationCatalogAvailable, mergeDefaultMcpIntegrations, } from "./mcp-integration-catalog.js";
8
8
  export { McpIntegrationDialog, } from "./McpIntegrationDialog.js";
9
9
  export { McpConnectionSuggestion, } from "./McpConnectionSuggestion.js";
10
- export { McpServersApiProvider, useMcpServersApi, useMcpServers, useCreateMcpServer, useDeleteMcpServer, useReconnectMcpServer, testMcpServerUrl, } from "./use-mcp-servers.js";
10
+ export { McpServersApiProvider, useMcpServersApi, useMcpServers, useCreateMcpServer, useDeleteMcpServer, useReconnectMcpServer, testMcpServerUrl, formatMcpServersLoadError, } from "./use-mcp-servers.js";
@@ -83,6 +83,7 @@ export interface TestMcpUrlResult {
83
83
  }
84
84
  export declare function getMcpUrlValidationError(rawUrl: string): string | null;
85
85
  export declare function formatMcpServerError(error: unknown): string;
86
+ export declare function formatMcpServersLoadError(error: unknown): string;
86
87
  export declare function testMcpServerUrl(url: string, headers?: Record<string, string>): Promise<TestMcpUrlResult>;
87
88
  /**
88
89
  * Virtual tree-node id used when a server is surfaced in the Workspace tree.
@@ -178,6 +178,20 @@ export function formatMcpServerError(error) {
178
178
  }
179
179
  return text.length > 240 ? `${text.slice(0, 237).trimEnd()}...` : text;
180
180
  }
181
+ export function formatMcpServersLoadError(error) {
182
+ const raw = typeof error === "string"
183
+ ? error
184
+ : error instanceof Error
185
+ ? error.message
186
+ : String(error ?? "");
187
+ const text = raw.trim();
188
+ if (!text)
189
+ return "Could not load agent integrations.";
190
+ if (/401|unauthorized|signed-in workspace app|workspace app/i.test(text)) {
191
+ return "Sign in to a workspace app, then retry loading agent integrations.";
192
+ }
193
+ return text.length > 240 ? `${text.slice(0, 237).trimEnd()}...` : text;
194
+ }
181
195
  export async function testMcpServerUrl(url, headers) {
182
196
  const validationError = getMcpUrlValidationError(url);
183
197
  if (validationError)
@@ -107,11 +107,17 @@ export function AccountSettingsForm({ compact = false, }) {
107
107
  const [uploading, setUploading] = useState(false);
108
108
  const [photoStatus, setPhotoStatus] = useState("idle");
109
109
  const [name, setName] = useState("");
110
+ const nameEditedRef = useRef(false);
110
111
  const displayName = profileQuery.data?.name ||
111
112
  session?.name ||
112
113
  email ||
113
114
  t("settings.profileSignedOut");
114
115
  useEffect(() => {
116
+ nameEditedRef.current = false;
117
+ }, [email]);
118
+ useEffect(() => {
119
+ if (nameEditedRef.current)
120
+ return;
115
121
  const nextName = profileQuery.data?.name || session?.name;
116
122
  if (nextName)
117
123
  setName(nextName);
@@ -144,12 +150,10 @@ export function AccountSettingsForm({ compact = false, }) {
144
150
  return (_jsxs(SettingsGroup, { id: "account", title: t("settings.profileTitle"), description: t("settings.profileDescription"), className: cn(compact && "[&>div:last-child>div>div]:py-3"), children: [_jsx(SettingsRow, { id: "profile", label: t("settings.profileTitle"), description: profileStatus, control: _jsxs("div", { className: "flex items-center gap-3", children: [_jsx(Avatar, { name: displayName, src: avatarUrl, fallback: profileInitials(displayName), size: "default", className: "size-10 shrink-0 rounded-full border border-border bg-accent font-semibold text-muted-foreground" }), _jsx("input", { ref: fileInputRef, type: "file", accept: "image/*", className: "hidden", onChange: handleAvatarChange }), _jsx(ActionButton, { type: "button", intent: "neutral", emphasis: "outline", size: "compact", disabled: !email || uploading, leadingIcon: _jsx(IconCamera, { className: "size-3.5" }), onPress: () => fileInputRef.current?.click(), children: uploading
145
151
  ? t("settings.profileUploading")
146
152
  : t("settings.profileChangePhoto") })] }) }), _jsx(SettingsRow, { id: "profile-name", label: t("settings.profileNameLabel"), description: updateProfile.isSuccess ? (_jsx("span", { className: "text-primary", children: t("settings.profileSaved") })) : updateProfile.error ? (_jsx("span", { className: "text-destructive", children: t("settings.profileSaveError") })) : (t("settings.profileNameDescription")), control: _jsxs("div", { className: "flex w-full items-center gap-2 sm:w-80", children: [_jsx(TextField, { id: "agent-native-profile-name", value: name, onChange: (value) => {
153
+ nameEditedRef.current = true;
147
154
  updateProfile.reset();
148
155
  setName(value);
149
- }, placeholder: t("settings.profileNamePlaceholder"), disabled: !email || profileQuery.isLoading || updateProfile.isPending, "aria-label": t("settings.profileNameLabel"), className: "min-w-0 flex-1" }), _jsx(ActionButton, { type: "button", intent: "primary", emphasis: "solid", size: "compact", pending: updateProfile.isPending, disabled: !email ||
150
- profileQuery.isLoading ||
151
- updateProfile.isPending ||
152
- !name.trim(), onPress: handleProfileSave, children: updateProfile.isPending
156
+ }, placeholder: t("settings.profileNamePlaceholder"), disabled: !email || updateProfile.isPending, "aria-label": t("settings.profileNameLabel"), className: "min-w-0 flex-1" }), _jsx(ActionButton, { type: "button", intent: "primary", emphasis: "solid", size: "compact", pending: updateProfile.isPending, disabled: !email || updateProfile.isPending || !name.trim(), onPress: handleProfileSave, children: updateProfile.isPending
153
157
  ? t("settings.profileSaving")
154
158
  : t("settings.profileSave") })] }) }), _jsx(SettingsRow, { id: "timezone", label: t("settings.timezoneLabel", { defaultValue: "Timezone" }), description: t("settings.timezoneHint", {
155
159
  defaultValue: "Used for timestamps and scheduled automations.",
@@ -8,7 +8,7 @@ import { PROVIDER_ENV_PLACEHOLDERS } from "../../agent/engine/provider-env-vars.
8
8
  import { buildSettingsRoute } from "../../navigation/index.js";
9
9
  import { saveAgentEngineProviderSettings, setAgentEngineProvider, } from "../agent-engine-key.js";
10
10
  import { AgentWorkspaceContent } from "../agent-page/AgentWorkspaceContent.js";
11
- import { getAgentProviderOption, providerIdForEngine, } from "../agent-provider-catalog.js";
11
+ import { AGENT_PROVIDER_CATALOG, getAgentProviderOption, providerIdForEngine, } from "../agent-provider-catalog.js";
12
12
  import { agentNativePath } from "../api-path.js";
13
13
  import { BuilderBMark } from "../builder-mark.js";
14
14
  import { Popover, PopoverContent, PopoverTrigger, } from "../components/ui/popover.js";
@@ -208,8 +208,6 @@ function UseBuilderCard({ builderFlow, connectUrl, connected, orgName, envManage
208
208
  ? "Connect account"
209
209
  : "Reconnect" })), credentialSource !== "env" ? _jsx(DisconnectBuilderButton, {}) : null] })) : null] }));
210
210
  }
211
- if (!connectUrl)
212
- return null;
213
211
  if (compact) {
214
212
  return (_jsxs(Button, { type: "button", intent: "primary", emphasis: "solid", onClick: () => builderFlow.start({ trackingSource, trackingFlow }), disabled: builderFlow.connecting, className: "inline-flex shrink-0 items-center gap-1.5 rounded-md bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:bg-primary/90 disabled:cursor-wait disabled:opacity-70", children: [builderFlow.connecting ? "Connecting…" : "Connect Builder.io", builderFlow.connecting ? (_jsx(IconLoader2, { size: 14, className: "animate-spin" })) : null] }));
215
213
  }
@@ -278,6 +276,9 @@ function computeSourceBadge(args) {
278
276
  if (settingsStatus?.source === "env") {
279
277
  return `Connected via ${settingsStatus.envVar ?? args.envVar ?? "env"}`;
280
278
  }
279
+ if (settingsStatus?.source === "app_secrets") {
280
+ return "Connected via saved key";
281
+ }
281
282
  return "Connected via template (server-side)";
282
283
  }
283
284
  if (args.envConfigured)
@@ -373,7 +374,9 @@ function LLMSectionInner({ builderFlow, builderLoading, connectUrl, connected, o
373
374
  setBaseUrlConfigured(Boolean(data?.openAiBaseUrlConfigured));
374
375
  if (data?.configured &&
375
376
  typeof data.engine === "string" &&
376
- (data.source === "env" || data.source === "settings")) {
377
+ (data.source === "env" ||
378
+ data.source === "settings" ||
379
+ data.source === "app_secrets")) {
377
380
  setSettingsStatus({
378
381
  engine: data.engine,
379
382
  source: data.source,
@@ -407,15 +410,40 @@ function LLMSectionInner({ builderFlow, builderLoading, connectUrl, connected, o
407
410
  .finally(() => setEnginesLoaded(true));
408
411
  }, []);
409
412
  const selectedEngineInfo = engines.find((e) => e.name === selectedEngine);
410
- const envVar = selectedEngineInfo?.requiredEnvVars?.[0];
413
+ const selectedProvider = providerIdForEngine(selectedEngine) ?? "anthropic";
414
+ const selectedProviderOption = getAgentProviderOption(selectedProvider);
415
+ const envVar = selectedProviderOption.key;
411
416
  const selectedEnginePackageInstalled = selectedEngineInfo?.packageInstalled !== false;
412
417
  const envConfigured = envVar
413
418
  ? (envKeys.find((k) => k.key === envVar)?.configured ?? false)
414
419
  : false;
415
- const settingsConfigured = settingsStatus != null && settingsStatus.engine === currentEngine;
420
+ const settingsConfigured = settingsStatus != null &&
421
+ (settingsStatus.engine === selectedEngine ||
422
+ (!!envVar && settingsStatus.envVar === envVar));
423
+ const configuredProviderIds = useMemo(() => {
424
+ const configured = new Set();
425
+ for (const option of AGENT_PROVIDER_CATALOG) {
426
+ if (option.key &&
427
+ envKeys.some((entry) => entry.key === option.key && entry.configured)) {
428
+ configured.add(option.id);
429
+ }
430
+ }
431
+ if (settingsStatus) {
432
+ const statusProvider = providerIdForEngine(settingsStatus.engine);
433
+ if (statusProvider)
434
+ configured.add(statusProvider);
435
+ if (settingsStatus.envVar) {
436
+ const statusOption = AGENT_PROVIDER_CATALOG.find((option) => option.key === settingsStatus.envVar);
437
+ if (statusOption)
438
+ configured.add(statusOption.id);
439
+ }
440
+ }
441
+ return configured;
442
+ }, [envKeys, settingsStatus]);
416
443
  const builderConnected = connected || builderFlow.configured;
417
444
  const anyKeyConfigured = builderConnected ||
418
- (selectedEnginePackageInstalled && (envConfigured || settingsConfigured));
445
+ (selectedEnginePackageInstalled &&
446
+ (envConfigured || settingsConfigured || configuredProviderIds.size > 0));
419
447
  const sourceBadge = computeSourceBadge({
420
448
  settingsConfigured,
421
449
  settingsStatus,
@@ -425,8 +453,6 @@ function LLMSectionInner({ builderFlow, builderLoading, connectUrl, connected, o
425
453
  });
426
454
  const manualSetupHint = "Select a provider.";
427
455
  const engineChanged = selectedEngine !== currentEngine || selectedModel !== currentModel;
428
- const selectedProvider = providerIdForEngine(selectedEngine) ?? "anthropic";
429
- const selectedProviderOption = getAgentProviderOption(selectedProvider);
430
456
  const isEndpointProvider = selectedProviderOption.supportsEndpoint === true;
431
457
  const endpointChanged = isEndpointProvider && (!!baseUrl.trim() || clearBaseUrl);
432
458
  const providerSettingsChanged = !!apiKey.trim() || endpointChanged;
@@ -553,7 +579,7 @@ function LLMSectionInner({ builderFlow, builderLoading, connectUrl, connected, o
553
579
  ? "Manage"
554
580
  : t("agentPanel.addOwnKeys", {
555
581
  defaultValue: "Custom keys",
556
- }), children: _jsxs("div", { className: "space-y-2 mb-1", children: [_jsx(AgentProviderPicker, { value: selectedProvider, layout: isPage ? "page" : "compact", onChange: (provider) => {
582
+ }), children: _jsxs("div", { className: "space-y-2 mb-1", children: [_jsx(AgentProviderPicker, { value: selectedProvider, configuredProviders: configuredProviderIds, layout: isPage ? "page" : "compact", onChange: (provider) => {
557
583
  const option = getAgentProviderOption(provider);
558
584
  setSelectedEngine(option.engine);
559
585
  setSelectedModel(option.defaultModel);
@@ -578,7 +604,10 @@ function LLMSectionInner({ builderFlow, builderLoading, connectUrl, connected, o
578
604
  setClearBaseUrl(checked);
579
605
  if (checked)
580
606
  setBaseUrl("");
581
- }, "aria-label": "Clear saved endpoint override", className: "shrink-0" }), "Clear saved endpoint override"] })), endpointChanged && (_jsx(Button, { type: "button", intent: "neutral", emphasis: "solid", onClick: handleSave, disabled: saving, className: "rounded bg-accent px-2.5 py-1 text-[10px] font-medium text-foreground hover:bg-accent/80 disabled:opacity-40", children: saving ? (_jsx(IconLoader2, { size: 10, className: "animate-spin" })) : saved ? (_jsx(IconCheck, { size: 10 })) : ("Save endpoint") }))] }))] })), envVar && envConfigured ? (_jsxs("div", { className: cn("flex items-center gap-1.5 text-primary", isPage ? "text-xs" : "text-[10px]"), children: [_jsx(IconCheck, { size: isPage ? 14 : 10 }), envVar, " configured"] })) : envVar ? (_jsxs("div", { className: "flex gap-1.5", children: [_jsx("input", { type: "password", value: apiKey, onChange: (e) => setApiKey(e.target.value), onKeyDown: (e) => {
607
+ }, "aria-label": "Clear saved endpoint override", className: "shrink-0" }), "Clear saved endpoint override"] })), endpointChanged && (_jsx(Button, { type: "button", intent: "neutral", emphasis: "solid", onClick: handleSave, disabled: saving, className: "rounded bg-accent px-2.5 py-1 text-[10px] font-medium text-foreground hover:bg-accent/80 disabled:opacity-40", children: saving ? (_jsx(IconLoader2, { size: 10, className: "animate-spin" })) : saved ? (_jsx(IconCheck, { size: 10 })) : ("Save endpoint") }))] }))] })), envVar && (envConfigured || settingsConfigured) ? (_jsxs("div", { className: cn("flex items-center gap-1.5 text-primary", isPage ? "text-xs" : "text-[10px]"), children: [_jsx(IconCheck, { size: isPage ? 14 : 10 }), settingsStatus?.source === "app_secrets" &&
608
+ settingsConfigured
609
+ ? "Saved key configured"
610
+ : `${envVar} configured`] })) : envVar ? (_jsxs("div", { className: "flex gap-1.5", children: [_jsx("input", { type: "password", value: apiKey, onChange: (e) => setApiKey(e.target.value), onKeyDown: (e) => {
582
611
  if (e.key === "Enter")
583
612
  handleSave();
584
613
  }, placeholder: PROVIDER_ENV_PLACEHOLDERS[envVar] ?? "...", className: cn(textInputClass(isPage), "flex-1"), style: isPage ? CONTROL_STYLE_PAGE : undefined }), _jsx(Button, { intent: "primary", emphasis: "solid", onClick: handleSave, disabled: !providerSettingsChanged || saving, className: pillButtonClass(isPage, "solid"), children: saving ? (_jsx(IconLoader2, { size: isPage ? 14 : 10, className: "animate-spin" })) : saved ? (_jsx(IconCheck, { size: isPage ? 14 : 10 })) : ("Save") })] })) : null, _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Button, { intent: "neutral", emphasis: "outline", onClick: handleTest, disabled: testing, className: pillButtonClass(isPage, "outline"), children: testing ? (_jsxs("span", { className: "flex items-center gap-1", children: [_jsx(IconLoader2, { size: isPage ? 14 : 10, className: "animate-spin" }), "Testing\u2026"] })) : ("Test") }), PROVIDER_DOCS[selectedEngine] ? (_jsxs("a", { href: PROVIDER_DOCS[selectedEngine], target: "_blank", rel: "noopener noreferrer", className: cn(pillButtonClass(isPage, "outline"), "no-underline"), children: ["Get an API key", _jsx(IconExternalLink, { size: isPage ? 14 : 10 })] })) : null, engineChanged && (_jsx(Button, { intent: "primary", emphasis: "solid", onClick: handleApply, className: pillButtonClass(isPage, "solid"), children: "Apply" })), settingsStatus != null && (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(Button, { intent: "danger", emphasis: "outline", onClick: handleDisconnect, className: cn(pillButtonClass(isPage, "outline"), "ms-auto text-muted-foreground hover:bg-destructive/10 hover:text-destructive hover:border-destructive/40"), children: "Disconnect" }) }), _jsx(TooltipContent, { children: "Clear the saved engine \u2014 the app will fall back to the default until you re-apply." })] }))] }), testResult && testResult.ok && (_jsxs("p", { className: cn("flex items-center gap-1 text-primary", isPage ? "text-xs" : "text-[10px]"), children: [_jsx(IconCheck, { size: isPage ? 14 : 10 }), "Test passed \u2014 ", testResult.latencyMs, "ms"] })), testResult && testResult.ok === false && (_jsxs("p", { className: cn("text-destructive", isPage ? "text-xs" : "text-[10px]"), children: ["Test failed: ", testResult.error] })), disconnectError && (_jsxs("p", { className: cn("text-destructive", isPage ? "text-xs" : "text-[10px]"), children: ["Disconnect failed: ", disconnectError] })), applyError && (_jsxs("p", { className: cn("text-destructive", isPage ? "text-xs" : "text-[10px]"), children: ["Apply failed: ", applyError] })), applyNote && (_jsx("p", { className: cn("text-muted-foreground", isPage ? "text-xs" : "text-[10px]"), children: "Changes take effect on next conversation" }))] }) })] })] })) }));
@@ -667,6 +696,8 @@ function AppModelDefaultsSectionInner({ grouped = false, open, onToggle, }) {
667
696
  };
668
697
  }, []);
669
698
  useEffect(() => load(), [load]);
699
+ if (!loading && !settings)
700
+ return null;
670
701
  const selectedEngineInfo = settings?.engines.find((engine) => engine.name === selectedEngine) ?? null;
671
702
  const engineOptions = (settings?.engines ?? [])
672
703
  .filter((engine) => engine.name === selectedEngine || engine.name !== "ai-sdk:anthropic")
@@ -793,7 +824,7 @@ function AppModelDefaultsSectionInner({ grouped = false, open, onToggle, }) {
793
824
  }, onEnter: () => {
794
825
  if (hasPendingChange)
795
826
  void save();
796
- } }), _jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx(Button, { type: "button", intent: "primary", emphasis: "solid", onClick: () => void save(), disabled: !hasPendingChange || saving, className: pillButtonClass(isPage, "solid"), children: saving ? (_jsx(IconLoader2, { size: isPage ? 14 : 10, className: "animate-spin" })) : saved ? (_jsx(IconCheck, { size: isPage ? 14 : 10 })) : ("Save") }), _jsx(Button, { type: "button", intent: "neutral", emphasis: "outline", onClick: reset, disabled: !settings.canUpdate || !hasAppDefault || saving, className: pillButtonClass(isPage, "outline"), children: "Reset" })] })] }), !settings.canUpdate && (_jsx("p", { className: cn("mt-2 text-muted-foreground", noteTextClass(isPage)), children: "Only organization owners and admins can change app model defaults." })), selectedEngineInfo?.packageInstalled === false ? (_jsx("p", { className: cn("mt-2 text-muted-foreground", noteTextClass(isPage)), children: "This app does not include the optional runtime packages for this provider." })) : selectedEngineInfo && !selectedEngineInfo.configured ? (_jsx("p", { className: cn("mt-2 text-muted-foreground", noteTextClass(isPage)), children: "Credentials for this provider were not detected; runtime will fall back if the model cannot be used." })) : null, error && (_jsx("p", { className: cn("mt-2 text-destructive", noteTextClass(isPage)), children: error }))] }) }))) : (_jsx("p", { className: cn("text-muted-foreground", noteTextClass(isPage)), children: "App model defaults are unavailable." })) }));
827
+ } }), _jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx(Button, { type: "button", intent: "primary", emphasis: "solid", onClick: () => void save(), disabled: !hasPendingChange || saving, className: pillButtonClass(isPage, "solid"), children: saving ? (_jsx(IconLoader2, { size: isPage ? 14 : 10, className: "animate-spin" })) : saved ? (_jsx(IconCheck, { size: isPage ? 14 : 10 })) : ("Save") }), _jsx(Button, { type: "button", intent: "neutral", emphasis: "outline", onClick: reset, disabled: !settings.canUpdate || !hasAppDefault || saving, className: pillButtonClass(isPage, "outline"), children: "Reset" })] })] }), !settings.canUpdate && (_jsx("p", { className: cn("mt-2 text-muted-foreground", noteTextClass(isPage)), children: "Only organization owners and admins can change app model defaults." })), selectedEngineInfo?.packageInstalled === false ? (_jsx("p", { className: cn("mt-2 text-muted-foreground", noteTextClass(isPage)), children: "This app does not include the optional runtime packages for this provider." })) : selectedEngineInfo && !selectedEngineInfo.configured ? (_jsx("p", { className: cn("mt-2 text-muted-foreground", noteTextClass(isPage)), children: "Credentials for this provider were not detected; runtime will fall back if the model cannot be used." })) : null, error && (_jsx("p", { className: cn("mt-2 text-destructive", noteTextClass(isPage)), children: error }))] }) }))) : null }));
797
828
  }
798
829
  // ─── Email Section ──────────────────────────────────────────────────────────
799
830
  function EmailSectionInner({ open, onToggle, }) {
@@ -920,6 +951,8 @@ function AgentLimitsSectionInner({ grouped = false, open, onToggle, }) {
920
951
  window.addEventListener("agent-loop-settings:changed", handler);
921
952
  return () => window.removeEventListener("agent-loop-settings:changed", handler);
922
953
  }, []);
954
+ if (!loading && !settings)
955
+ return null;
923
956
  const numericValue = Number(value);
924
957
  const hasPendingChange = !!settings &&
925
958
  settings.canUpdate &&
@@ -1004,7 +1037,7 @@ function AgentLimitsSectionInner({ grouped = false, open, onToggle, }) {
1004
1037
  void save();
1005
1038
  }, className: cn(textInputClass(isPage), "min-w-0 flex-1 disabled:opacity-60"), style: isPage ? CONTROL_STYLE_PAGE : undefined }), _jsx(Button, { type: "button", intent: "primary", emphasis: "solid", onClick: save, disabled: !hasPendingChange || saving, className: pillButtonClass(isPage, "solid"), children: saving ? (_jsx(IconLoader2, { size: isPage ? 14 : 10, className: "animate-spin" })) : saved ? (_jsx(IconCheck, { size: isPage ? 14 : 10 })) : ("Save") }), _jsx(Button, { type: "button", intent: "neutral", emphasis: "outline", onClick: reset, disabled: !settings.canUpdate ||
1006
1039
  saving ||
1007
- settings.maxIterations === settings.defaultMaxIterations, className: pillButtonClass(isPage, "outline"), children: "Reset" })] }), !settings.canUpdate && (_jsx("p", { className: cn("mt-2 text-muted-foreground", noteTextClass(isPage)), children: "Only organization owners and admins can change this limit." })), error && (_jsx("p", { className: cn("mt-2 text-destructive", noteTextClass(isPage)), children: error }))] }) }))) : (_jsx("p", { className: cn("text-muted-foreground", noteTextClass(isPage)), children: "Agent limit settings are unavailable." })) }));
1040
+ settings.maxIterations === settings.defaultMaxIterations, className: pillButtonClass(isPage, "outline"), children: "Reset" })] }), !settings.canUpdate && (_jsx("p", { className: cn("mt-2 text-muted-foreground", noteTextClass(isPage)), children: "Only organization owners and admins can change this limit." })), error && (_jsx("p", { className: cn("mt-2 text-destructive", noteTextClass(isPage)), children: error }))] }) }))) : null }));
1008
1041
  }
1009
1042
  export function areExtensionSettingsEnabled(options = {}) {
1010
1043
  return options.extensionTools === true;
@@ -29,9 +29,6 @@ function normalizeTabId(value) {
29
29
  if (normalized === "workspace" || normalized === "workspace-settings") {
30
30
  return "workspace";
31
31
  }
32
- if (normalized === "connections") {
33
- return "integrations";
34
- }
35
32
  return normalized;
36
33
  }
37
34
  function resolveTabId(tabs, value) {
@@ -40,6 +37,14 @@ function resolveTabId(tabs, value) {
40
37
  return null;
41
38
  if (tabs.some((tab) => tab.id === normalized))
42
39
  return normalized;
40
+ const alternateTabId = normalized === "connections"
41
+ ? "integrations"
42
+ : normalized === "integrations"
43
+ ? "connections"
44
+ : null;
45
+ if (alternateTabId && tabs.some((tab) => tab.id === alternateTabId)) {
46
+ return alternateTabId;
47
+ }
43
48
  const nestedTab = tabs
44
49
  .filter((tab) => normalized.startsWith(`${tab.id}:`) ||
45
50
  tab.id.startsWith(`${normalized}:`))
@@ -1,5 +1,5 @@
1
1
  import { type ReactNode } from "react";
2
- import { type ShareButtonVisibility } from "./useShareButtonController.js";
2
+ import { type ShareButtonRole, type ShareButtonVisibility } from "./useShareButtonController.js";
3
3
  export interface ShareButtonProps {
4
4
  resourceType: string;
5
5
  resourceId: string;
@@ -61,6 +61,11 @@ export interface ShareButtonProps {
61
61
  label?: string;
62
62
  description?: string;
63
63
  }>>;
64
+ /** Optional template-specific labels and descriptions for share roles. */
65
+ roleCopy?: Partial<Record<Role, {
66
+ label?: string;
67
+ description?: string;
68
+ }>>;
64
69
  /** Optional label for the explicit per-person access list. */
65
70
  peopleAccessLabel?: ReactNode;
66
71
  /** Optional label for the coarse visibility control. */
@@ -95,6 +100,7 @@ export interface ShareButtonProps {
95
100
  popoverClassName?: string;
96
101
  }
97
102
  type Visibility = ShareButtonVisibility;
103
+ type Role = ShareButtonRole;
98
104
  /**
99
105
  * Framework share control. Renders a shadcn-outline-styled trigger that
100
106
  * opens a Google-Docs-style popover anchored beneath it. Uses Tailwind