@agent-native/core 0.157.3 → 0.157.4

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 (152) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  3. package/corpus/templates/analytics/.agents/skills/sharing/SKILL.md +21 -0
  4. package/corpus/templates/analytics/server/lib/first-party-analytics-backend.ts +40 -1
  5. package/corpus/templates/assets/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  6. package/corpus/templates/assets/.agents/skills/sharing/SKILL.md +21 -0
  7. package/corpus/templates/brain/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  8. package/corpus/templates/brain/.agents/skills/sharing/SKILL.md +21 -0
  9. package/corpus/templates/calendar/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  10. package/corpus/templates/calendar/.agents/skills/sharing/SKILL.md +21 -0
  11. package/corpus/templates/calendar/app/components/layout/AppLayout.tsx +3 -1
  12. package/corpus/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  13. package/corpus/templates/chat/.agents/skills/sharing/SKILL.md +21 -0
  14. package/corpus/templates/clips/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  15. package/corpus/templates/clips/.agents/skills/meetings/SKILL.md +7 -7
  16. package/corpus/templates/clips/actions/approve-recording-access-request.ts +147 -0
  17. package/corpus/templates/clips/actions/request-recording-access.ts +121 -23
  18. package/corpus/templates/clips/actions/view-screen.ts +1 -1
  19. package/corpus/templates/clips/app/components/meetings/share-meeting-dialog.tsx +34 -53
  20. package/corpus/templates/clips/app/components/player/request-access-dialog.tsx +104 -0
  21. package/corpus/templates/clips/app/components/player/share-dialog.tsx +36 -45
  22. package/corpus/templates/clips/app/components/sharing/share-ui.tsx +3 -6
  23. package/corpus/templates/clips/app/i18n/en-US.ts +26 -1
  24. package/corpus/templates/clips/app/lib/public-meeting.ts +1 -1
  25. package/corpus/templates/clips/app/routes/access-request.approve.tsx +250 -0
  26. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +9 -32
  27. package/corpus/templates/clips/app/routes/share.$shareId.tsx +123 -37
  28. package/corpus/templates/clips/app/routes/share.meeting.$meetingId.tsx +41 -1
  29. package/corpus/templates/clips/server/lib/calendar-event-meetings.ts +1 -0
  30. package/corpus/templates/clips/server/lib/emails.ts +40 -11
  31. package/corpus/templates/clips/shared/recording-link.ts +32 -1
  32. package/corpus/templates/clips/shared/share-attribution.ts +13 -0
  33. package/corpus/templates/content/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  34. package/corpus/templates/content/.agents/skills/sharing/SKILL.md +21 -0
  35. package/corpus/templates/content/app/components/editor/DocumentBlockFields.tsx +22 -10
  36. package/corpus/templates/content/app/components/editor/SlashCommandMenu.tsx +2 -1
  37. package/corpus/templates/content/app/components/editor/VisualEditor.tsx +245 -9
  38. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +185 -134
  39. package/corpus/templates/content/app/components/editor/extensions/ImageBlock.tsx +61 -45
  40. package/corpus/templates/content/app/components/editor/extensions/ImageNode.ts +6 -0
  41. package/corpus/templates/content/app/components/editor/image-upload.ts +137 -5
  42. package/corpus/templates/content/app/global.css +8 -0
  43. package/corpus/templates/content/changelog/2026-08-12-image-uploads-now-confirm-the-image-can-be-displayed-before-.md +6 -0
  44. package/corpus/templates/content/changelog/2026-08-14-images-fill-the-page-width-by-default-and-remain-visible-whe.md +6 -0
  45. package/corpus/templates/content/changelog/2026-08-14-images-inserted-from-the-slash-command-stay-saved-after-uplo.md +6 -0
  46. package/corpus/templates/content/changelog/2026-08-14-svg-files-can-be-selected-reliably-from-the-image-picker.md +6 -0
  47. package/corpus/templates/crm/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  48. package/corpus/templates/crm/.agents/skills/sharing/SKILL.md +21 -0
  49. package/corpus/templates/design/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  50. package/corpus/templates/design/.agents/skills/sharing/SKILL.md +21 -0
  51. package/corpus/templates/dispatch/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  52. package/corpus/templates/dispatch/.agents/skills/sharing/SKILL.md +21 -0
  53. package/corpus/templates/factory/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  54. package/corpus/templates/factory/.agents/skills/sharing/SKILL.md +21 -0
  55. package/corpus/templates/forms/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  56. package/corpus/templates/forms/.agents/skills/sharing/SKILL.md +21 -0
  57. package/corpus/templates/macros/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  58. package/corpus/templates/macros/.agents/skills/sharing/SKILL.md +21 -0
  59. package/corpus/templates/mail/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  60. package/corpus/templates/mail/.agents/skills/sharing/SKILL.md +21 -0
  61. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +6 -1
  62. package/corpus/templates/plan/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  63. package/corpus/templates/plan/.agents/skills/sharing/SKILL.md +21 -0
  64. package/corpus/templates/plan/app/pages/PlansPage.tsx +25 -30
  65. package/corpus/templates/slides/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  66. package/corpus/templates/slides/.agents/skills/sharing/SKILL.md +21 -0
  67. package/corpus/templates/slides/app/components/deck/SlideRenderer.tsx +2 -1
  68. package/corpus/templates/slides/app/components/editor/ShareDialog.tsx +124 -180
  69. package/corpus/templates/slides/app/components/onboarding/FirstDeckOnboardingFlow.tsx +1 -0
  70. package/corpus/templates/slides/app/global.css +99 -3
  71. package/corpus/templates/slides/app/i18n/en-US.ts +1 -0
  72. package/corpus/templates/tasks/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  73. package/corpus/templates/tasks/.agents/skills/sharing/SKILL.md +21 -0
  74. package/dist/chat-threads/schema.d.ts +1 -1
  75. package/dist/cli/code-agent-executor.js +318 -0
  76. package/dist/client/AgentPanel.d.ts +13 -1
  77. package/dist/client/AgentPanel.js +41 -3
  78. package/dist/client/AssistantChat.d.ts +9 -1
  79. package/dist/client/AssistantChat.js +26 -13
  80. package/dist/client/MultiTabAssistantChat.js +18 -5
  81. package/dist/client/agent-chat.d.ts +8 -0
  82. package/dist/client/agent-chat.js +15 -0
  83. package/dist/client/app-chat-sidebar.d.ts +23 -0
  84. package/dist/client/app-chat-sidebar.js +53 -0
  85. package/dist/client/app-providers.js +31 -2
  86. package/dist/client/frame-protocol.d.ts +20 -2
  87. package/dist/client/hooks/index.d.ts +1 -0
  88. package/dist/client/hooks/index.js +1 -0
  89. package/dist/client/sharing/AgentShareSection.d.ts +8 -0
  90. package/dist/client/sharing/AgentShareSection.js +50 -0
  91. package/dist/client/sharing/ShareButton.js +2 -1
  92. package/dist/client/sharing/ShareDialog.d.ts +2 -2
  93. package/dist/client/sharing/ShareDialog.js +21 -29
  94. package/dist/client/sharing/index.d.ts +1 -0
  95. package/dist/client/sharing/index.js +1 -0
  96. package/dist/client/sharing/useShareButtonController.d.ts +1 -0
  97. package/dist/client/sharing/useShareDialogController.d.ts +3 -0
  98. package/dist/client/sharing/useShareDialogController.js +2 -1
  99. package/dist/client/theme.d.ts +21 -0
  100. package/dist/client/theme.js +60 -0
  101. package/dist/client/ui/index.d.ts +1 -1
  102. package/dist/client/ui/index.js +1 -1
  103. package/dist/client/use-session.js +23 -0
  104. package/dist/collab/awareness.d.ts +2 -2
  105. package/dist/collab/struct-routes.d.ts +1 -1
  106. package/dist/dashboard-storage/schema.d.ts +1 -1
  107. package/dist/data-programs/schema.d.ts +1 -1
  108. package/dist/extensions/schema.d.ts +1 -1
  109. package/dist/localization/core-messages/ar-SA.js +6 -0
  110. package/dist/localization/core-messages/de-DE.js +6 -0
  111. package/dist/localization/core-messages/en-US.d.ts +6 -0
  112. package/dist/localization/core-messages/en-US.js +6 -0
  113. package/dist/localization/core-messages/es-ES.js +6 -0
  114. package/dist/localization/core-messages/fr-FR.js +6 -0
  115. package/dist/localization/core-messages/hi-IN.js +6 -0
  116. package/dist/localization/core-messages/ja-JP.js +6 -0
  117. package/dist/localization/core-messages/ko-KR.js +6 -0
  118. package/dist/localization/core-messages/pt-BR.js +6 -0
  119. package/dist/localization/core-messages/zh-CN.js +6 -0
  120. package/dist/localization/core-messages/zh-TW.js +6 -0
  121. package/dist/localization/core-messages.d.ts +6 -0
  122. package/dist/localization/default-messages.d.ts +1 -0
  123. package/dist/localization/default-messages.js +1 -0
  124. package/dist/notifications/routes.d.ts +3 -3
  125. package/dist/progress/routes.d.ts +1 -1
  126. package/dist/provider-api/actions/custom-provider-registration.d.ts +14 -14
  127. package/dist/provider-api/actions/provider-api.d.ts +14 -14
  128. package/dist/server/auth.js +8 -5
  129. package/dist/server/identity-sso-store.d.ts +6 -1
  130. package/dist/server/identity-sso-store.js +57 -14
  131. package/dist/server/identity-sso.d.ts +7 -8
  132. package/dist/server/identity-sso.js +15 -12
  133. package/dist/sharing/actions/list-resource-shares.d.ts +2 -0
  134. package/dist/sharing/actions/list-resource-shares.js +1 -0
  135. package/dist/sharing/schema.d.ts +1 -1
  136. package/dist/sharing/schema.js +4 -1
  137. package/dist/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  138. package/dist/templates/chat/.agents/skills/sharing/SKILL.md +21 -0
  139. package/dist/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  140. package/dist/templates/default/.agents/skills/sharing/SKILL.md +21 -0
  141. package/dist/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  142. package/dist/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  143. package/dist/templates/workspace-core/.agents/skills/sharing/SKILL.md +21 -0
  144. package/docs/content/cross-app-sso.mdx +24 -17
  145. package/package.json +2 -2
  146. package/src/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  147. package/src/templates/chat/.agents/skills/sharing/SKILL.md +21 -0
  148. package/src/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  149. package/src/templates/default/.agents/skills/sharing/SKILL.md +21 -0
  150. package/src/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  151. package/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  152. package/src/templates/workspace-core/.agents/skills/sharing/SKILL.md +21 -0
@@ -3,7 +3,7 @@ import { IconPlus, IconHistory, IconX } from "@tabler/icons-react";
3
3
  import { useState, useRef, useEffect, useCallback } from "react";
4
4
  import { DEFAULT_MODEL } from "../agent/default-model.js";
5
5
  import { DEFAULT_REASONING_EFFORT, isReasoningEffort, resolveReasoningEffortSelection, } from "../shared/reasoning-effort.js";
6
- import { AGENT_CHAT_CLEAR_CONTEXT_MESSAGE_TYPE, AGENT_CHAT_REMOVE_CONTEXT_MESSAGE_TYPE, AGENT_CHAT_SET_CONTEXT_MESSAGE_TYPE, appendAgentChatContextToMessage, claimAgentChatOpenRequest, claimAgentChatSubmit, drainBufferedAgentChatOpenRequests, drainBufferedAgentChatSubmits, getAgentChatContextState, isAgentChatSubmitCancelled, normalizeAgentChatContextItem, parseSubmitChatMessage, removeAgentChatContextItem, reportAgentChatSubmitResult, reportAgentChatSubmitTarget, setAgentChatContextItem, } from "./agent-chat.js";
6
+ import { AGENT_CHAT_CLEAR_CONTEXT_MESSAGE_TYPE, AGENT_CHAT_REMOVE_CONTEXT_MESSAGE_TYPE, AGENT_CHAT_SET_CONTEXT_MESSAGE_TYPE, appendAgentChatContextToMessage, claimAgentChatOpenRequest, claimAgentChatSubmit, drainBufferedAgentChatOpenRequests, drainBufferedAgentChatSubmits, filterAgentChatContextItems, getAgentChatContextState, isAgentChatSubmitCancelled, normalizeAgentChatContextItem, parseSubmitChatMessage, removeAgentChatContextItem, reportAgentChatSubmitResult, reportAgentChatSubmitTarget, setAgentChatContextItem, } from "./agent-chat.js";
7
7
  import { agentNativePath, appPath } from "./api-path.js";
8
8
  import { AssistantChat, } from "./AssistantChat.js";
9
9
  import { buildChatModelGroups, } from "./chat-model-groups.js";
@@ -386,6 +386,9 @@ function runToAgentTeamTabInfo(run) {
386
386
  }
387
387
  export function MultiTabAssistantChat({ showTabBar = true, renderHeader, renderOverlay, contentHidden = false, apiUrl = agentNativePath("/_agent-native/agent-chat"), storageKey, restoreActiveThread = true, browserTabId, threadUrlSync = false, scope = null, agentTeamPollMs = DEFAULT_AGENT_TEAM_POLL_MS, ...props }) {
388
388
  const translate = useT();
389
+ const contextNamespace = scope
390
+ ? scope.contextKey?.trim() || `scope:${scope.type}:${scope.id}`
391
+ : undefined;
389
392
  const { enabled: threadUrlSyncEnabled, paramName: threadUrlParamName, routeThreadId, getPath: getThreadPath, navigate: navigateThreadUrl, } = resolveThreadUrlSync(threadUrlSync);
390
393
  const threadRouteControlsActiveThread = threadUrlSyncEnabled &&
391
394
  threadUrlSync !== true &&
@@ -578,6 +581,9 @@ export function MultiTabAssistantChat({ showTabBar = true, renderHeader, renderO
578
581
  }, [bumpModelSelectionVersion, modelSelectionKey]);
579
582
  const postMessageSubmissionsDisabled = props.composerDisabled === true;
580
583
  const setContextInTab = useCallback((threadId, item, options) => {
584
+ if (filterAgentChatContextItems([item], contextNamespace).length === 0) {
585
+ return;
586
+ }
581
587
  const ref = chatRefs.current.get(threadId);
582
588
  if (ref) {
583
589
  ref.setComposerContextItem(item, options);
@@ -589,7 +595,7 @@ export function MultiTabAssistantChat({ showTabBar = true, renderHeader, renderO
589
595
  ? [...existing, item]
590
596
  : existing.map((current, currentIndex) => currentIndex === index ? item : current);
591
597
  pendingContextItems.current.set(threadId, next);
592
- }, []);
598
+ }, [contextNamespace]);
593
599
  const removeContextInTab = useCallback((threadId, key) => {
594
600
  const ref = chatRefs.current.get(threadId);
595
601
  if (ref) {
@@ -772,7 +778,7 @@ export function MultiTabAssistantChat({ showTabBar = true, renderHeader, renderO
772
778
  const type = formatScopeType(nextScope.type);
773
779
  const title = nextScope.label?.trim() ||
774
780
  type.replace(/^./, (character) => character.toUpperCase());
775
- const key = nextScope.contextKey || "agent-current-resource-context";
781
+ const key = nextScope.contextKey?.trim() || "agent-current-resource-context";
776
782
  const marker = `Resource context: ${nextScope.type}:${nextScope.id}`;
777
783
  const existing = getAgentChatContextState().items.find((item) => item.key === key);
778
784
  let ownsContextItem = false;
@@ -780,6 +786,7 @@ export function MultiTabAssistantChat({ showTabBar = true, renderHeader, renderO
780
786
  setAgentChatContextItem({
781
787
  key,
782
788
  title,
789
+ ...(contextNamespace ? { contextNamespace } : {}),
783
790
  context: [
784
791
  marker,
785
792
  `The user is currently viewing this ${type}.`,
@@ -802,7 +809,13 @@ export function MultiTabAssistantChat({ showTabBar = true, renderHeader, renderO
802
809
  removeAgentChatContextItem(key);
803
810
  }
804
811
  };
805
- }, [scope?.contextKey, scope?.id, scope?.label, scope?.type]);
812
+ }, [
813
+ contextNamespace,
814
+ scope?.contextKey,
815
+ scope?.id,
816
+ scope?.label,
817
+ scope?.type,
818
+ ]);
806
819
  // Persist open tab IDs to localStorage (exclude sub-agent tabs — they're session-only)
807
820
  useEffect(() => {
808
821
  if (openTabsKeyRef.current !== OPEN_TABS_KEY)
@@ -1797,7 +1810,7 @@ export function MultiTabAssistantChat({ showTabBar = true, renderHeader, renderO
1797
1810
  else {
1798
1811
  chatRefs.current.delete(tabId);
1799
1812
  }
1800
- }, threadId: tabId, tabId: tabId, browserTabId: browserTabId, isActiveComposer: tabId === activeThreadId, apiUrl: apiUrl, isNewThread: newThreadIds.current.has(tabId) || isNewThread(tabId), isThreadStateLoading: isLoading, onMessageCountChange: (count) => setMessageCounts((prev) => prev[tabId] === count
1813
+ }, threadId: tabId, tabId: tabId, browserTabId: browserTabId, contextNamespace: contextNamespace, isActiveComposer: tabId === activeThreadId, apiUrl: apiUrl, isNewThread: newThreadIds.current.has(tabId) || isNewThread(tabId), isThreadStateLoading: isLoading, onMessageCountChange: (count) => setMessageCounts((prev) => prev[tabId] === count
1801
1814
  ? prev
1802
1815
  : { ...prev, [tabId]: count }), onSaveThread: handleSaveThread, onGenerateTitle: handleGenerateTitle, onSlashCommand: handleSlashCommand, selectedModel: modelSelection?.model, selectedEngine: modelSelection?.engine, selectedEffort: modelSelection?.effort ?? DEFAULT_REASONING_EFFORT, composerSlot: props.composerSlot, defaultModel: defaultModel, availableModels: availableModels, modelListLoading: modelListLoading, onModelChange: handleModelChange, onEffortChange: handleEffortChange, onForkChat: () => handleForkChat(tabId),
1803
1816
  // Sub-agent tabs are read-only: sending a new message from the
@@ -94,6 +94,8 @@ export interface AgentChatContextItem {
94
94
  title: string;
95
95
  /** Hidden context included with the next submitted prompt. */
96
96
  context: string;
97
+ /** Optional host namespace used to keep ambient context local to one surface. */
98
+ contextNamespace?: string;
97
99
  }
98
100
  export interface AgentChatContextSetOptions extends AgentChatContextItem {
99
101
  /**
@@ -233,6 +235,12 @@ export declare function claimAgentChatOpenRequest(id: unknown): boolean;
233
235
  /** Test-only: reset the self-submit buffer and claim set. */
234
236
  export declare function _resetAgentChatSubmitBufferForTests(): void;
235
237
  export declare function normalizeAgentChatContextItem(item: unknown): AgentChatContextItem | null;
238
+ /**
239
+ * Keep unscoped context visible everywhere, but hide ambient context owned by
240
+ * a different host surface. This prevents mounted-but-hidden app panes from
241
+ * leaking their resource chips into the active app's composer.
242
+ */
243
+ export declare function filterAgentChatContextItems(items: readonly AgentChatContextItem[], contextNamespace?: string | null): AgentChatContextItem[];
236
244
  export declare function normalizeAgentChatContextItems(items: unknown): AgentChatContextItem[];
237
245
  export declare function publishAgentChatContextItems(items: readonly AgentChatContextItem[], options?: {
238
246
  persist?: boolean;
@@ -207,12 +207,27 @@ export function normalizeAgentChatContextItem(item) {
207
207
  const context = candidate.context.trim();
208
208
  if (!key || !context)
209
209
  return null;
210
+ const contextNamespace = typeof candidate.contextNamespace === "string"
211
+ ? candidate.contextNamespace.trim()
212
+ : "";
210
213
  return {
211
214
  key,
212
215
  title: candidate.title.trim() || key,
213
216
  context,
217
+ ...(contextNamespace ? { contextNamespace } : {}),
214
218
  };
215
219
  }
220
+ /**
221
+ * Keep unscoped context visible everywhere, but hide ambient context owned by
222
+ * a different host surface. This prevents mounted-but-hidden app panes from
223
+ * leaking their resource chips into the active app's composer.
224
+ */
225
+ export function filterAgentChatContextItems(items, contextNamespace) {
226
+ const namespace = contextNamespace?.trim();
227
+ if (!namespace)
228
+ return [...items];
229
+ return items.filter((item) => !item.contextNamespace || item.contextNamespace.trim() === namespace);
230
+ }
216
231
  export function normalizeAgentChatContextItems(items) {
217
232
  if (!Array.isArray(items))
218
233
  return [];
@@ -0,0 +1,23 @@
1
+ /** Custom event used by top-level hosts such as Electron webviews. */
2
+ export declare const APP_CHAT_SIDEBAR_STATE_EVENT = "agent-native:per-app-chat-state";
3
+ /** postMessage sent from a per-app chat host to its embedded app. */
4
+ export declare const APP_CHAT_SIDEBAR_STATE_MESSAGE = "agentNative.perAppChatState";
5
+ /** Request sent by an iframe that mounted after the host announced its state. */
6
+ export declare const APP_CHAT_SIDEBAR_STATE_REQUEST_MESSAGE = "agentNative.perAppChatStateRequest";
7
+ export interface AppChatSidebarState {
8
+ open: boolean;
9
+ }
10
+ export declare function buildAppChatSidebarStateMessage(open: boolean): {
11
+ type: typeof APP_CHAT_SIDEBAR_STATE_MESSAGE;
12
+ data: AppChatSidebarState;
13
+ };
14
+ export declare function buildAppChatSidebarStateRequest(): {
15
+ type: typeof APP_CHAT_SIDEBAR_STATE_REQUEST_MESSAGE;
16
+ };
17
+ /**
18
+ * The two host shells are the only AgentSidebar instances that control a
19
+ * separate app surface. Keeping this check here prevents ordinary in-app
20
+ * agent panels from changing the app's navigation chrome.
21
+ */
22
+ export declare function isPerAppChatStorageKey(storageKey: string | undefined): boolean;
23
+ export declare function usePerAppChatOpen(): boolean;
@@ -0,0 +1,53 @@
1
+ import { useEffect, useState } from "react";
2
+ /** Custom event used by top-level hosts such as Electron webviews. */
3
+ export const APP_CHAT_SIDEBAR_STATE_EVENT = "agent-native:per-app-chat-state";
4
+ /** postMessage sent from a per-app chat host to its embedded app. */
5
+ export const APP_CHAT_SIDEBAR_STATE_MESSAGE = "agentNative.perAppChatState";
6
+ /** Request sent by an iframe that mounted after the host announced its state. */
7
+ export const APP_CHAT_SIDEBAR_STATE_REQUEST_MESSAGE = "agentNative.perAppChatStateRequest";
8
+ export function buildAppChatSidebarStateMessage(open) {
9
+ return {
10
+ type: APP_CHAT_SIDEBAR_STATE_MESSAGE,
11
+ data: { open },
12
+ };
13
+ }
14
+ export function buildAppChatSidebarStateRequest() {
15
+ return { type: APP_CHAT_SIDEBAR_STATE_REQUEST_MESSAGE };
16
+ }
17
+ /**
18
+ * The two host shells are the only AgentSidebar instances that control a
19
+ * separate app surface. Keeping this check here prevents ordinary in-app
20
+ * agent panels from changing the app's navigation chrome.
21
+ */
22
+ export function isPerAppChatStorageKey(storageKey) {
23
+ return (storageKey === "desktop-app-chat" || storageKey === "dispatch-app-chat");
24
+ }
25
+ export function usePerAppChatOpen() {
26
+ const [open, setOpen] = useState(false);
27
+ useEffect(() => {
28
+ const applyState = (value) => {
29
+ if (typeof value === "boolean")
30
+ setOpen(value);
31
+ };
32
+ const handleCustomEvent = (event) => {
33
+ applyState(event.detail?.open);
34
+ };
35
+ const handleMessage = (event) => {
36
+ if (window.parent === window || event.source !== window.parent)
37
+ return;
38
+ if (event.data?.type !== APP_CHAT_SIDEBAR_STATE_MESSAGE)
39
+ return;
40
+ applyState(event.data.data?.open);
41
+ };
42
+ window.addEventListener(APP_CHAT_SIDEBAR_STATE_EVENT, handleCustomEvent);
43
+ window.addEventListener("message", handleMessage);
44
+ if (window.parent !== window) {
45
+ window.parent.postMessage(buildAppChatSidebarStateRequest(), "*");
46
+ }
47
+ return () => {
48
+ window.removeEventListener(APP_CHAT_SIDEBAR_STATE_EVENT, handleCustomEvent);
49
+ window.removeEventListener("message", handleMessage);
50
+ };
51
+ }, []);
52
+ return open;
53
+ }
@@ -51,7 +51,7 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
51
51
  import { Toaster } from "@agent-native/toolkit/ui/sonner";
52
52
  import { TooltipProvider } from "@radix-ui/react-tooltip";
53
53
  import { QueryClientProvider } from "@tanstack/react-query";
54
- import { ThemeProvider } from "next-themes";
54
+ import { ThemeProvider, useTheme } from "next-themes";
55
55
  import { useEffect, useRef } from "react";
56
56
  import { useInRouterContext } from "react-router";
57
57
  import { isHumanReadableDocumentTitle, normalizeDocumentTitle, } from "../shared/document-title.js";
@@ -63,6 +63,7 @@ import { RequireSession } from "./require-session.js";
63
63
  import { AgentNativeRouteWarmup } from "./route-warmup.js";
64
64
  import { RouteTransitionIndicator } from "./RouteTransitionIndicator.js";
65
65
  import { RuntimeConfigNotice } from "./RuntimeConfigNotice.js";
66
+ import { EMBEDDED_THEME_CHANGE_EVENT, applyEmbeddedThemeUpdate, parseEmbeddedThemeUpdate, } from "./theme.js";
66
67
  const DEFAULT_TOASTER = _jsx(Toaster, { richColors: true, position: "bottom-left" });
67
68
  function RoutedAppEnhancements() {
68
69
  const isInRouter = useInRouterContext();
@@ -81,6 +82,34 @@ function readDocumentTitleFallback() {
81
82
  .find((title) => isHumanReadableDocumentTitle(title));
82
83
  return normalizeDocumentTitle(metadataTitle, "Agent Native");
83
84
  }
85
+ function EmbeddedThemeSync() {
86
+ const { setTheme } = useTheme();
87
+ useEffect(() => {
88
+ const applyUpdate = (update) => {
89
+ if (!update)
90
+ return;
91
+ applyEmbeddedThemeUpdate(document.documentElement, update);
92
+ setTheme(update.theme);
93
+ };
94
+ const onMessage = (event) => {
95
+ if (window.parent === window || event.source !== window.parent)
96
+ return;
97
+ applyUpdate(parseEmbeddedThemeUpdate(event.data));
98
+ };
99
+ const onThemeChange = (event) => {
100
+ if (!(event instanceof CustomEvent))
101
+ return;
102
+ applyUpdate(parseEmbeddedThemeUpdate(event.detail));
103
+ };
104
+ window.addEventListener("message", onMessage);
105
+ window.addEventListener(EMBEDDED_THEME_CHANGE_EVENT, onThemeChange);
106
+ return () => {
107
+ window.removeEventListener("message", onMessage);
108
+ window.removeEventListener(EMBEDDED_THEME_CHANGE_EVENT, onThemeChange);
109
+ };
110
+ }, [setTheme]);
111
+ return null;
112
+ }
84
113
  /** Repairs route metadata that would otherwise expose a structured payload in the tab. */
85
114
  function DocumentTitleGuard({ fallbackTitle }) {
86
115
  const initialTitleRef = useRef(null);
@@ -115,7 +144,7 @@ function DocumentTitleGuard({ fallbackTitle }) {
115
144
  }
116
145
  function ProvidersInner({ queryClient, defaultTheme = "system", themeAttribute = "class", tooltipDelayDuration, toaster = DEFAULT_TOASTER, disableThemeTransitions = true, i18n, documentTitleFallback, children, }) {
117
146
  const localizedChildren = i18n === false ? (children) : (_jsx(AgentNativeI18nProvider, { ...(i18n ?? {}), children: children }));
118
- return (_jsx(QueryClientProvider, { client: queryClient, children: _jsx(ThemeProvider, { attribute: themeAttribute, defaultTheme: defaultTheme, enableSystem: true, disableTransitionOnChange: disableThemeTransitions, children: _jsxs(TooltipProvider, { delayDuration: tooltipDelayDuration, children: [localizedChildren, _jsx(DocumentTitleGuard, { fallbackTitle: documentTitleFallback }), _jsx(RuntimeConfigNotice, {}), _jsx(RoutedAppEnhancements, {}), toaster] }) }) }));
147
+ return (_jsx(QueryClientProvider, { client: queryClient, children: _jsxs(ThemeProvider, { attribute: themeAttribute, defaultTheme: defaultTheme, enableSystem: true, disableTransitionOnChange: disableThemeTransitions, children: [_jsx(EmbeddedThemeSync, {}), _jsxs(TooltipProvider, { delayDuration: tooltipDelayDuration, children: [localizedChildren, _jsx(DocumentTitleGuard, { fallbackTitle: documentTitleFallback }), _jsx(RuntimeConfigNotice, {}), _jsx(RoutedAppEnhancements, {}), toaster] })] }) }));
119
148
  }
120
149
  export function AppProviders({ queryClient, isPublicPath = false, clientOnlyFallback, sessionBypass = false, defaultTheme, themeAttribute, tooltipDelayDuration, toaster, disableThemeTransitions, i18n, documentTitleFallback, children, }) {
121
150
  const fallback = clientOnlyFallback ?? _jsx(DefaultSpinner, {});
@@ -49,6 +49,17 @@ export interface ToggleSidebarMessage {
49
49
  open?: boolean;
50
50
  };
51
51
  }
52
+ /** The host chat rail asks the embedded app to compact its own navigation. */
53
+ export interface PerAppChatSidebarStateMessage {
54
+ type: "agentNative.perAppChatState";
55
+ data: {
56
+ open: boolean;
57
+ };
58
+ }
59
+ /** The embedded app asks a host for the current per-app chat state on mount. */
60
+ export interface PerAppChatSidebarStateRequestMessage {
61
+ type: "agentNative.perAppChatStateRequest";
62
+ }
52
63
  export interface EnterStyleEditingMessage {
53
64
  type: "agentNative.enterStyleEditing";
54
65
  data: {
@@ -78,7 +89,7 @@ export interface PresentationModeMessage {
78
89
  export interface DesignCloseMessage {
79
90
  type: "design:close";
80
91
  }
81
- export type AppToFrameMessage = AppReadyMessage | SubmitChatMessage | SetChatContextMessage | RemoveChatContextMessage | ClearChatContextMessage | GetUserInfoMessage | SetEnvVarsMessage | DevModeChangeMessage | ToggleSidebarMessage | EnterStyleEditingMessage | EnterTextEditingMessage | ExitSelectionModeMessage | PresentationModeMessage | DesignCloseMessage;
92
+ export type AppToFrameMessage = AppReadyMessage | AuthStateMessage | SubmitChatMessage | SetChatContextMessage | RemoveChatContextMessage | ClearChatContextMessage | GetUserInfoMessage | SetEnvVarsMessage | DevModeChangeMessage | ToggleSidebarMessage | PerAppChatSidebarStateRequestMessage | EnterStyleEditingMessage | EnterTextEditingMessage | ExitSelectionModeMessage | PresentationModeMessage | DesignCloseMessage;
82
93
  export interface FrameOriginMessage {
83
94
  type: "agentNative.frameOrigin";
84
95
  origin: string;
@@ -98,6 +109,13 @@ export interface UserInfoMessage {
98
109
  email?: string;
99
110
  };
100
111
  }
112
+ /** The embedded app's own session state, surfaced to a trusted host frame. */
113
+ export interface AuthStateMessage {
114
+ type: "agentNative.authState";
115
+ data: {
116
+ status: "authenticated" | "unauthenticated";
117
+ };
118
+ }
101
119
  export interface CodeCompleteMessage {
102
120
  type: "agentNative.codeComplete";
103
121
  tabId: string;
@@ -132,5 +150,5 @@ export interface DesignInitMessage {
132
150
  };
133
151
  };
134
152
  }
135
- export type FrameToAppMessage = FrameOriginMessage | ChatRunningMessage | UserInfoMessage | CodeCompleteMessage | SidebarModeMessage | PresentationModeMessage | DesignInitMessage;
153
+ export type FrameToAppMessage = FrameOriginMessage | ChatRunningMessage | UserInfoMessage | PerAppChatSidebarStateMessage | CodeCompleteMessage | SidebarModeMessage | PresentationModeMessage | DesignInitMessage;
136
154
  export type FrameMessage = AppToFrameMessage | FrameToAppMessage;
@@ -8,6 +8,7 @@ export { notifySessionInvalidated, useSession, type AuthSession, } from "../use-
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";
11
+ export { APP_CHAT_SIDEBAR_STATE_EVENT, APP_CHAT_SIDEBAR_STATE_MESSAGE, APP_CHAT_SIDEBAR_STATE_REQUEST_MESSAGE, buildAppChatSidebarStateMessage, buildAppChatSidebarStateRequest, isPerAppChatStorageKey, usePerAppChatOpen, type AppChatSidebarState, } from "../app-chat-sidebar.js";
11
12
  export { usePinchZoom, type UsePinchZoomOptions } from "../use-pinch-zoom.js";
12
13
  export { useAvatarUrl, uploadAvatar, invalidateAvatarCache, } from "../use-avatar.js";
13
14
  export { usePollLoop, type UsePollLoopOptions, type UsePollLoopHandle, } from "../use-poll-loop.js";
@@ -8,6 +8,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";
11
+ export { APP_CHAT_SIDEBAR_STATE_EVENT, APP_CHAT_SIDEBAR_STATE_MESSAGE, APP_CHAT_SIDEBAR_STATE_REQUEST_MESSAGE, buildAppChatSidebarStateMessage, buildAppChatSidebarStateRequest, isPerAppChatStorageKey, usePerAppChatOpen, } from "../app-chat-sidebar.js";
11
12
  export { usePinchZoom } from "../use-pinch-zoom.js";
12
13
  export { useAvatarUrl, uploadAvatar, invalidateAvatarCache, } from "../use-avatar.js";
13
14
  export { usePollLoop, } from "../use-poll-loop.js";
@@ -0,0 +1,8 @@
1
+ export interface AgentShareSectionProps {
2
+ resourceType: string;
3
+ resourceId: string;
4
+ enabled?: boolean;
5
+ className?: string;
6
+ }
7
+ /** Optional shared handoff for resources with a registered agent context. */
8
+ export declare function AgentShareSection({ resourceType, resourceId, enabled, className, }: AgentShareSectionProps): import("react").JSX.Element | null;
@@ -0,0 +1,50 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { ActionButton } from "@agent-native/toolkit/design-system";
3
+ import { ShareAgentsSection, ShareCopyRow, } from "@agent-native/toolkit/sharing";
4
+ import { useCallback, useState } from "react";
5
+ import { writeClipboardText } from "../clipboard.js";
6
+ import { useT } from "../i18n.js";
7
+ import { useActionMutation } from "../use-action.js";
8
+ /** Optional shared handoff for resources with a registered agent context. */
9
+ export function AgentShareSection({ resourceType, resourceId, enabled = false, className, }) {
10
+ const t = useT();
11
+ const createAgentLink = useActionMutation("create-agent-resource-link");
12
+ const [open, setOpen] = useState(false);
13
+ const [contextUrl, setContextUrl] = useState("");
14
+ const [linkError, setLinkError] = useState(false);
15
+ const loadContextUrl = useCallback(() => {
16
+ setContextUrl("");
17
+ setLinkError(false);
18
+ createAgentLink.mutate({ resourceType, resourceId }, {
19
+ onSuccess: (result) => {
20
+ if (result.contextUrl)
21
+ setContextUrl(result.contextUrl);
22
+ else
23
+ setLinkError(true);
24
+ },
25
+ onError: () => setLinkError(true),
26
+ });
27
+ }, [createAgentLink, resourceId, resourceType]);
28
+ const handleOpenChange = useCallback((nextOpen) => {
29
+ setOpen(nextOpen);
30
+ if (nextOpen && !contextUrl)
31
+ loadContextUrl();
32
+ }, [contextUrl, loadContextUrl]);
33
+ if (!enabled)
34
+ return null;
35
+ return (_jsx(ShareAgentsSection, { label: t("agentChat.share.shareWithAgents", {
36
+ defaultValue: "Share with agents",
37
+ }), open: open, onOpenChange: handleOpenChange, className: className, children: _jsxs("div", { className: "space-y-2", children: [contextUrl ? (_jsx(ShareCopyRow, { label: t("agentChat.share.agentContext", {
38
+ defaultValue: "Agent context link",
39
+ }), description: t("agentChat.share.agentContextDescription", {
40
+ defaultValue: "Read-only context for an external agent.",
41
+ }), value: contextUrl, copyLabel: t("agentChat.share.copy", { defaultValue: "Copy" }), copiedLabel: t("agentChat.share.copied", {
42
+ defaultValue: "Copied",
43
+ }), onCopy: writeClipboardText })) : null, createAgentLink.isPending ? (_jsx("div", { className: "text-xs text-muted-foreground", children: t("agentChat.share.preparingAgentLink", {
44
+ defaultValue: "Preparing agent link...",
45
+ }) })) : null, linkError ? (_jsxs("div", { className: "flex items-center justify-between gap-2 rounded-md border border-border bg-muted/30 px-3 py-2", children: [_jsx("span", { className: "text-xs text-muted-foreground", children: t("agentChat.share.agentLinkUnavailable", {
46
+ defaultValue: "Agent link unavailable.",
47
+ }) }), _jsx(ActionButton, { type: "button", emphasis: "ghost", size: "compact", onPress: loadContextUrl, disabled: createAgentLink.isPending, children: t("agentChat.share.retryAgentLink", {
48
+ defaultValue: "Retry",
49
+ }) })] })) : null] }) }));
50
+ }
@@ -7,6 +7,7 @@ import { writeClipboardText } from "../clipboard.js";
7
7
  import { Popover, PopoverAnchor, PopoverContent, PopoverTrigger, } from "../components/ui/popover.js";
8
8
  import { useT } from "../i18n.js";
9
9
  import { cn } from "../utils.js";
10
+ import { AgentShareSection } from "./AgentShareSection.js";
10
11
  import { useShareButtonController, } from "./useShareButtonController.js";
11
12
  // Match shadcn's <Button size="sm" variant="outline"> sizing so the trigger
12
13
  // sits flush next to other controls while staying transparent at rest.
@@ -181,7 +182,7 @@ function SharePanel(props) {
181
182
  defaultValue: "Remove",
182
183
  }), onClick: () => handleRemove(s), disabled: inFlight.has(keyOf(s)), className: BUTTON_GHOST_ICON, children: _jsx(IconTrash, { size: 14 }) })) : null] }, keyOf(s)))), !shares.length && !data?.ownerEmail ? (_jsx("li", { className: "px-1 py-1.5 text-sm text-muted-foreground", children: t("agentChat.share.noAccess", {
183
184
  defaultValue: "No one has access yet.",
184
- }) })) : null] })] }), shareError && !canManage ? (_jsx("div", { role: "alert", className: "mb-4 rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive", children: shareError })) : null, props.accessNote ? (_jsx("div", { className: "mb-4 rounded-md border border-border bg-muted/35 p-3 text-xs text-muted-foreground", children: props.accessNote })) : null, showShareLinks && shareUrlPlacement === "bottom" ? shareLinks : null, props.shareFooterContent] }));
185
+ }) })) : null] })] }), shareError && !canManage ? (_jsx("div", { role: "alert", className: "mb-4 rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive", children: shareError })) : null, _jsx(AgentShareSection, { enabled: data?.agentReadable === true, resourceType: props.resourceType, resourceId: props.resourceId }), props.accessNote ? (_jsx("div", { className: "mb-4 rounded-md border border-border bg-muted/35 p-3 text-xs text-muted-foreground", children: props.accessNote })) : null, showShareLinks && shareUrlPlacement === "bottom" ? shareLinks : null, props.shareFooterContent] }));
185
186
  if (!hasTabs)
186
187
  return sharePanel;
187
188
  const tabs = [
@@ -26,7 +26,7 @@ export interface ShareDialogProps {
26
26
  * Framework share dialog. Drop into any template via
27
27
  * `<ShareDialog open onClose resourceType resourceId />`. Passing `shareUrl`
28
28
  * lights up a Link tab with a copy field; passing `embedUrl` lights up an
29
- * Embed tab. With neither prop, renders a single Invite + general-access
30
- * panel (Google-Docs-lite).
29
+ * Embed tab. People access stays on the primary sharing surface so the same
30
+ * Google-Docs-style flow works whether or not a link or embed is available.
31
31
  */
32
32
  export declare function ShareDialog({ open, onClose, resourceType, resourceId, resourceTitle, shareUrl, embedUrl, embedTabContent, linkTabExtras, }: ShareDialogProps): import("react").JSX.Element | null;
@@ -1,10 +1,9 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { ActionButton, Avatar as DesignSystemAvatar, Dialog as DesignSystemDialog, IconButton, Picker, Status, TextArea, } from "@agent-native/toolkit/design-system";
3
3
  import { ShareCopyRow } from "@agent-native/toolkit/sharing";
4
- import { Collapsible, CollapsibleContent, CollapsibleTrigger, } from "@agent-native/toolkit/ui";
5
- import { IconCheck, IconCode, IconCopy, IconChevronDown, IconLink, IconLock, IconMail, IconTrash, IconUsersGroup, IconWorld, } from "@tabler/icons-react";
6
- import { useState } from "react";
4
+ import { IconCheck, IconCopy, IconLock, IconTrash, IconUsersGroup, IconWorld, } from "@tabler/icons-react";
7
5
  import { cn } from "../utils.js";
6
+ import { AgentShareSection } from "./AgentShareSection.js";
8
7
  import { useShareDialogController, } from "./useShareDialogController.js";
9
8
  const BUTTON_BASE = "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors active:!scale-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0";
10
9
  const BUTTON_OUTLINE_SM = cn(BUTTON_BASE, "!h-9 !px-3 border border-input bg-background hover:bg-accent hover:text-accent-foreground");
@@ -14,17 +13,12 @@ const VIS_ICONS = {
14
13
  org: IconUsersGroup,
15
14
  public: IconWorld,
16
15
  };
17
- const TAB_ICONS = {
18
- link: IconLink,
19
- invite: IconMail,
20
- embed: IconCode,
21
- };
22
16
  /**
23
17
  * Framework share dialog. Drop into any template via
24
18
  * `<ShareDialog open onClose resourceType resourceId />`. Passing `shareUrl`
25
19
  * lights up a Link tab with a copy field; passing `embedUrl` lights up an
26
- * Embed tab. With neither prop, renders a single Invite + general-access
27
- * panel (Google-Docs-lite).
20
+ * Embed tab. People access stays on the primary sharing surface so the same
21
+ * Google-Docs-style flow works whether or not a link or embed is available.
28
22
  */
29
23
  export function ShareDialog({ open, onClose, resourceType, resourceId, resourceTitle, shareUrl, embedUrl, embedTabContent, linkTabExtras, }) {
30
24
  const controller = useShareDialogController({
@@ -40,39 +34,37 @@ export function ShareDialog({ open, onClose, resourceType, resourceId, resourceT
40
34
  return null;
41
35
  return (_jsxs(DesignSystemDialog, { open: controller.open, onOpenChange: controller.onOpenChange, title: _jsx("span", { className: cn(controller.tabsEnabled
42
36
  ? "sr-only"
43
- : "truncate !text-base !leading-normal !tracking-normal !text-inherit"), title: controller.title, children: controller.title }), closeLabel: controller.labels.close, size: "large", className: "!top-4 !z-[2010] !block !max-h-none !w-[calc(100vw-2rem)] !max-w-lg !translate-y-0 !gap-0 !overflow-visible !rounded-xl !border-border !bg-popover !p-0 !text-popover-foreground !shadow-2xl sm:!top-1/2 sm:!-translate-y-1/2", "aria-label": controller.title, children: [!controller.tabsEnabled && controller.ownerLabel ? (_jsx("div", { className: "px-5 pt-0 pb-3", children: _jsx("div", { className: "truncate text-xs text-muted-foreground", children: controller.ownerLabel }) })) : null, controller.tabsEnabled ? (_jsx("div", { role: "tablist", "aria-label": controller.labels.shareOptions, className: "mx-5 mt-1 flex gap-1 border-b border-border", children: controller.tabs.map((tab) => {
44
- const Icon = TAB_ICONS[tab.value];
45
- return (_jsx(TabTrigger, { active: controller.activeTab === tab.value, onClick: () => controller.setActiveTab(tab.value), icon: _jsx(Icon, { size: 14, strokeWidth: 1.75 }), label: tab.label }, tab.value));
37
+ : "truncate !text-base !leading-normal !tracking-normal !text-inherit"), title: controller.title, children: controller.title }), closeLabel: controller.labels.close, size: "large", className: "!top-4 !z-[2010] !block !max-h-none !w-[calc(100vw-2rem)] !max-w-lg !translate-y-0 !gap-0 !overflow-visible !rounded-xl !border-border !bg-popover !p-0 !text-popover-foreground !shadow-2xl sm:!top-1/2 sm:!-translate-y-1/2", "aria-label": controller.title, children: [!controller.tabsEnabled && controller.ownerLabel ? (_jsx("div", { className: "px-5 pt-0 pb-3", children: _jsx("div", { className: "truncate text-xs text-muted-foreground", children: controller.ownerLabel }) })) : null, controller.tabsEnabled ? (_jsx("div", { role: "tablist", "aria-label": controller.labels.shareOptions, className: "mx-5 mt-1 flex gap-1 rounded-xl bg-muted/70 p-1", children: controller.tabs.map((tab) => {
38
+ return (_jsx(TabTrigger, { active: controller.activeTab === tab.value, onClick: () => controller.setActiveTab(tab.value), label: tab.label }, tab.value));
46
39
  }) })) : null, _jsxs("div", { className: "px-5 py-4", children: [controller.tabsEnabled && controller.activeTab === "link" ? (_jsx(LinkTab, { controller: controller, extras: linkTabExtras })) : null, !controller.tabsEnabled || controller.activeTab === "invite" ? (_jsx(InviteTab, { controller: controller, showVisibility: !controller.tabsEnabled })) : null, controller.tabsEnabled && controller.activeTab === "embed"
47
40
  ? (embedTabContent ?? _jsx(DefaultEmbedBody, { controller: controller }))
48
- : null] })] }));
41
+ : null, _jsx(AgentShareSection, { enabled: controller.agentReadable, resourceType: resourceType, resourceId: resourceId, className: "mt-4" })] })] }));
49
42
  }
50
- function TabTrigger({ active, onClick, icon, label, }) {
51
- return (_jsxs(ActionButton, { type: "button", emphasis: "ghost", "aria-pressed": active, onPress: onClick, className: cn("inline-flex !h-auto items-center gap-1.5 !rounded-none border-b-2 !px-3 !py-2 text-sm font-medium transition-colors hover:!bg-transparent active:!scale-100 focus-visible:!ring-0 focus-visible:!ring-offset-0 [&_svg]:!size-auto", active
52
- ? "border-foreground text-foreground"
53
- : "border-transparent text-muted-foreground hover:text-foreground"), children: [icon, label] }));
43
+ function TabTrigger({ active, onClick, label, }) {
44
+ return (_jsx(ActionButton, { type: "button", emphasis: "ghost", "aria-pressed": active, onPress: onClick, className: cn("min-w-0 flex-1 !rounded-lg !px-3 !py-2 text-sm font-medium transition-colors hover:!bg-background/70 active:!scale-100 focus-visible:!ring-0 focus-visible:!ring-offset-0", active
45
+ ? "bg-background text-foreground shadow-sm ring-1 ring-border"
46
+ : "text-muted-foreground hover:text-foreground"), children: _jsx("span", { className: "block truncate", children: label }) }));
54
47
  }
55
48
  function LinkTab({ controller, extras, }) {
56
49
  const Icon = VIS_ICONS[controller.visibility.value];
57
- return (_jsxs("div", { className: "space-y-3", children: [_jsx(ShareCopyRow, { label: controller.labels.shareLink, value: controller.shareUrl, copyLabel: controller.labels.copy, copiedLabel: "Copied", onCopy: (value) => controller.copy("share-link", value), className: "mb-4" }), _jsxs("div", { children: [_jsx("div", { className: "mb-2 text-xs font-medium text-muted-foreground", children: controller.labels.generalAccess }), _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("span", { "aria-hidden": true, className: "inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-muted text-muted-foreground", children: _jsx(Icon, { size: 16, strokeWidth: 1.75 }) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx(VisibilitySelect, { controller: controller }), _jsx("div", { className: "sr-only text-xs text-muted-foreground", children: controller.visibility.description })] })] })] }), extras] }));
50
+ return (_jsxs("div", { className: "space-y-3", children: [_jsx(ShareCopyRow, { label: controller.labels.shareLink, value: controller.shareUrl, copyLabel: controller.labels.copy, copiedLabel: controller.labels.copied, onCopy: (value) => controller.copy("share-link", value), className: "mb-4" }), _jsxs("div", { children: [_jsx("div", { className: "mb-2 text-xs font-medium text-muted-foreground", children: controller.labels.generalAccess }), _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("span", { "aria-hidden": true, className: "inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-muted text-muted-foreground", children: _jsx(Icon, { size: 16, strokeWidth: 1.75 }) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx(VisibilitySelect, { controller: controller }), _jsx("div", { className: "sr-only text-xs text-muted-foreground", children: controller.visibility.description })] })] })] }), _jsx(InviteTab, { controller: controller, showVisibility: false }), extras] }));
58
51
  }
59
52
  function InviteTab({ controller, showVisibility, }) {
60
53
  const Icon = VIS_ICONS[controller.visibility.value];
61
- const [advancedOpen, setAdvancedOpen] = useState(false);
62
- return (_jsxs("div", { className: "space-y-3", children: [_jsxs(Collapsible, { open: advancedOpen, onOpenChange: setAdvancedOpen, className: "overflow-hidden rounded-md border border-border", children: [_jsx(CollapsibleTrigger, { asChild: true, children: _jsxs("button", { type: "button", className: "flex min-h-10 w-full items-center justify-between gap-3 px-3 py-2 text-left text-sm font-medium transition-colors hover:bg-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset", children: [_jsx("span", { className: "truncate", children: controller.labels.peopleWithAccess }), _jsx(IconChevronDown, { "aria-hidden": true, size: 16, strokeWidth: 1.8, className: cn("shrink-0 text-muted-foreground transition-transform", advancedOpen && "rotate-180") })] }) }), _jsx(CollapsibleContent, { className: "border-t border-border px-3 py-3", children: _jsxs("div", { className: "space-y-4", children: [controller.canManage ? (_jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "flex items-stretch gap-2", children: [_jsx("input", { type: "email", placeholder: controller.labels.addPeopleByEmail, value: controller.invite.email, onChange: (event) => controller.invite.setEmail(event.currentTarget.value), onKeyDown: (event) => {
63
- if (event.key === "Enter")
64
- controller.invite.submit();
65
- }, autoComplete: "off", className: "h-9 min-w-0 flex-1 rounded-md border border-input bg-background px-3 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 focus:ring-offset-background" }), _jsx(RoleSelect, { controller: controller })] }), controller.invite.showNotifyPeople ? (_jsxs("div", { className: "flex flex-wrap items-center gap-x-3 gap-y-2 text-xs text-muted-foreground", children: [_jsxs("label", { className: "inline-flex items-center gap-2", children: [_jsx("input", { type: "checkbox", checked: controller.invite.notifyPeople, onChange: (event) => controller.invite.setNotifyPeople(event.currentTarget.checked), className: "h-4 w-4 rounded border-input accent-primary" }), controller.labels.notifyPeople] }), controller.invite.notifyPeople ? (_jsx(ActionButton, { type: "button", emphasis: "ghost", "aria-expanded": controller.invite.messageOpen, onPress: () => controller.invite.setMessageOpen(!controller.invite.messageOpen), className: "!h-auto !rounded-sm !px-1 !py-0.5 text-xs font-medium !text-foreground underline decoration-border underline-offset-2 hover:!bg-accent hover:!text-accent-foreground active:!scale-100", children: controller.invite.messageOpen
66
- ? controller.labels.hideMessage
67
- : controller.labels.addMessage })) : null] })) : null, controller.invite.showNotifyPeople &&
68
- controller.invite.notifyPeople &&
69
- controller.invite.messageOpen ? (_jsx(TextArea, { "aria-label": controller.labels.addMessage, placeholder: controller.labels.messagePlaceholder, value: controller.invite.message, onChange: (value) => controller.invite.setMessage(value), maxLength: 500, rows: 3, className: "min-h-20 resize-y text-sm" })) : null] })) : null, _jsxs("div", { children: [_jsx("div", { className: "mb-2 text-sm font-semibold", children: controller.labels.peopleWithAccess }), _jsxs("ul", { className: "m-0 flex list-none flex-col gap-1 p-0", children: [controller.people.map((person) => (_jsx(PersonRow, { person: person, canManage: controller.canManage, removeLabel: controller.labels.remove, onRemove: controller.removeShare }, person.key))), !controller.people.length ? (_jsx("li", { className: "px-1 py-1.5 text-sm text-muted-foreground", children: controller.labels.noAccess })) : null] })] })] }) })] }), showVisibility ? (_jsxs("div", { children: [_jsx("div", { className: "mb-2 text-sm font-semibold", children: controller.labels.generalAccess }), _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("span", { "aria-hidden": true, className: "inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-muted text-muted-foreground", children: _jsx(Icon, { size: 16, strokeWidth: 1.75 }) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx(VisibilitySelect, { controller: controller }), _jsx("div", { className: "sr-only text-xs text-muted-foreground", children: controller.visibility.description })] })] })] })) : null] }));
54
+ return (_jsxs("div", { className: "space-y-4", children: [showVisibility ? (_jsxs("div", { children: [_jsx("div", { className: "mb-2 text-sm font-semibold", children: controller.labels.generalAccess }), _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("span", { "aria-hidden": true, className: "inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-muted text-muted-foreground", children: _jsx(Icon, { size: 16, strokeWidth: 1.75 }) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx(VisibilitySelect, { controller: controller }), _jsx("div", { className: "sr-only text-xs text-muted-foreground", children: controller.visibility.description })] })] })] })) : null, _jsxs("div", { className: "space-y-4", children: [_jsx("div", { className: "text-sm font-semibold", children: controller.labels.peopleWithAccess }), controller.canManage ? (_jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "flex items-stretch gap-2", children: [_jsx("input", { type: "email", placeholder: controller.labels.addPeopleByEmail, value: controller.invite.email, onChange: (event) => controller.invite.setEmail(event.currentTarget.value), onKeyDown: (event) => {
55
+ if (event.key === "Enter")
56
+ controller.invite.submit();
57
+ }, autoComplete: "off", className: "h-9 min-w-0 flex-1 rounded-md border border-input bg-background px-3 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 focus:ring-offset-background" }), _jsx(RoleSelect, { controller: controller })] }), controller.invite.showNotifyPeople ? (_jsxs("div", { className: "flex flex-wrap items-center gap-x-3 gap-y-2 text-xs text-muted-foreground", children: [_jsxs("label", { className: "inline-flex items-center gap-2", children: [_jsx("input", { type: "checkbox", checked: controller.invite.notifyPeople, onChange: (event) => controller.invite.setNotifyPeople(event.currentTarget.checked), className: "h-4 w-4 rounded border-input accent-primary" }), controller.labels.notifyPeople] }), controller.invite.notifyPeople ? (_jsx(ActionButton, { type: "button", emphasis: "ghost", "aria-expanded": controller.invite.messageOpen, onPress: () => controller.invite.setMessageOpen(!controller.invite.messageOpen), className: "!h-auto !rounded-sm !px-1 !py-0.5 text-xs font-medium !text-foreground underline decoration-border underline-offset-2 hover:!bg-accent hover:!text-accent-foreground active:!scale-100", children: controller.invite.messageOpen
58
+ ? controller.labels.hideMessage
59
+ : controller.labels.addMessage })) : null] })) : null, controller.invite.showNotifyPeople &&
60
+ controller.invite.notifyPeople &&
61
+ controller.invite.messageOpen ? (_jsx(TextArea, { "aria-label": controller.labels.addMessage, placeholder: controller.labels.messagePlaceholder, value: controller.invite.message, onChange: (value) => controller.invite.setMessage(value), maxLength: 500, rows: 3, className: "min-h-20 resize-y text-sm" })) : null] })) : null, _jsxs("ul", { className: "m-0 flex list-none flex-col gap-1 p-0", children: [controller.people.map((person) => (_jsx(PersonRow, { person: person, canManage: controller.canManage, removeLabel: controller.labels.remove, onRemove: controller.removeShare }, person.key))), !controller.people.length ? (_jsx("li", { className: "px-1 py-1.5 text-sm text-muted-foreground", children: controller.labels.noAccess })) : null] })] })] }));
70
62
  }
71
63
  function PersonRow({ person, canManage, removeLabel, onRemove, }) {
72
64
  return (_jsxs("li", { className: "flex items-center gap-3 px-1 py-1.5 text-sm", children: [_jsx(DesignSystemAvatar, { name: person.label, fallback: person.principalType === "org" ? (_jsx(IconUsersGroup, { size: 14, strokeWidth: 1.75 })) : (person.avatarText), size: "compact", className: "inline-flex h-7 w-7 shrink-0 text-[11px] font-semibold" }), _jsx("span", { className: "flex-1 min-w-0 truncate", children: person.label }), _jsx(Status, { tone: "neutral", size: "compact", className: "border-0 bg-transparent px-0 text-xs text-muted-foreground", children: person.roleLabel }), canManage && person.share ? (_jsx(IconButton, { intent: "danger", emphasis: "ghost", size: "compact", icon: _jsx(IconTrash, { size: 14 }), label: removeLabel, "aria-label": removeLabel, onPress: () => onRemove(person.share), className: cn(BUTTON_GHOST_ICON, "[&_svg]:!size-auto") })) : null] }));
73
65
  }
74
66
  function DefaultEmbedBody({ controller, }) {
75
- return (_jsxs("div", { className: "space-y-3", children: [_jsx(ShareCopyRow, { label: controller.labels.embedUrl, value: controller.embedUrl, copyLabel: controller.labels.copy, copiedLabel: "Copied", onCopy: (value) => controller.copy("embed-url", value) }), _jsx(CopyField, { field: "embed-code", label: controller.labels.embedCode, value: controller.embedCode, controller: controller, multiline: true })] }));
67
+ return (_jsxs("div", { className: "space-y-3", children: [_jsx(ShareCopyRow, { label: controller.labels.embedUrl, value: controller.embedUrl, copyLabel: controller.labels.copy, copiedLabel: controller.labels.copied, onCopy: (value) => controller.copy("embed-url", value) }), _jsx(CopyField, { field: "embed-code", label: controller.labels.embedCode, value: controller.embedCode, controller: controller, multiline: true })] }));
76
68
  }
77
69
  function CopyField({ field, label, value, controller, multiline, }) {
78
70
  const copied = controller.copiedField === field;
@@ -1,3 +1,4 @@
1
+ export { AgentShareSection, type AgentShareSectionProps, } from "./AgentShareSection.js";
1
2
  export { ShareDialog, type ShareDialogProps } from "./ShareDialog.js";
2
3
  export { ShareButton, type ShareButtonProps } from "./ShareButton.js";
3
4
  export { useShareButtonController, type ShareButtonController, type ShareButtonControllerOptions, type ShareButtonOrgMember, type ShareButtonOrgMemberSearch, type ShareButtonRole, type ShareButtonShare, type ShareButtonSharesResponse, type ShareButtonVisibility, } from "./useShareButtonController.js";
@@ -1,3 +1,4 @@
1
+ export { AgentShareSection, } from "./AgentShareSection.js";
1
2
  export { ShareDialog } from "./ShareDialog.js";
2
3
  export { ShareButton } from "./ShareButton.js";
3
4
  export { useShareButtonController, } from "./useShareButtonController.js";
@@ -13,6 +13,7 @@ export interface ShareButtonSharesResponse {
13
13
  orgId: string | null;
14
14
  visibility: ShareButtonVisibility | null;
15
15
  role?: "owner" | ShareButtonRole;
16
+ agentReadable?: boolean;
16
17
  shares: ShareButtonShare[];
17
18
  policy?: {
18
19
  allowPublic: boolean;
@@ -13,6 +13,7 @@ export interface ResourceSharesResponse {
13
13
  orgId: string | null;
14
14
  visibility: ShareVisibility | null;
15
15
  role?: "owner" | ShareRole;
16
+ agentReadable?: boolean;
16
17
  shares: ResourceShare[];
17
18
  policy?: {
18
19
  allowPublic: boolean;
@@ -69,6 +70,7 @@ export interface ShareDialogController {
69
70
  remove: string;
70
71
  noAccess: string;
71
72
  copy: string;
73
+ copied: string;
72
74
  embedUrl: string;
73
75
  embedCode: string;
74
76
  };
@@ -110,5 +112,6 @@ export interface ShareDialogController {
110
112
  error: unknown;
111
113
  refetch: () => unknown;
112
114
  canManage: boolean;
115
+ agentReadable: boolean;
113
116
  }
114
117
  export declare function useShareDialogController({ open, onClose, resourceType, resourceId, resourceTitle, shareUrl, embedUrl, }: ShareDialogControllerOptions): ShareDialogController;
@@ -214,7 +214,6 @@ export function useShareDialogController({ open, onClose, resourceType, resource
214
214
  ...(hasLinkTab
215
215
  ? [{ value: "link", label: t("share.link") }]
216
216
  : []),
217
- { value: "invite", label: t("share.invite") },
218
217
  ...(hasEmbedTab
219
218
  ? [{ value: "embed", label: t("share.embed") }]
220
219
  : []),
@@ -234,6 +233,7 @@ export function useShareDialogController({ open, onClose, resourceType, resource
234
233
  remove: t("share.remove"),
235
234
  noAccess: t("share.noAccess"),
236
235
  copy: t("share.copy"),
236
+ copied: t("share.copied"),
237
237
  embedUrl: t("share.embedUrl"),
238
238
  embedCode: t("share.embedCode"),
239
239
  },
@@ -275,6 +275,7 @@ export function useShareDialogController({ open, onClose, resourceType, resource
275
275
  error: sharesQuery.error ?? mutationError,
276
276
  refetch,
277
277
  canManage,
278
+ agentReadable: data?.agentReadable === true,
278
279
  };
279
280
  }
280
281
  function visibilityOption(visibility, t) {