@agent-native/core 0.153.0 → 0.153.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/corpus/templates/calendar/app/components/calendar/DayView.tsx +3 -2
  2. package/corpus/templates/calendar/app/components/calendar/WeekView.tsx +3 -2
  3. package/corpus/templates/calendar/app/lib/event-layout.ts +16 -35
  4. package/corpus/templates/clips/app/components/meetings/share-meeting-dialog.tsx +27 -44
  5. package/corpus/templates/clips/app/components/player/share-dialog.tsx +72 -33
  6. package/corpus/templates/clips/app/components/sharing/share-ui.tsx +18 -6
  7. package/corpus/templates/clips/desktop/src/app.tsx +1 -1
  8. package/corpus/templates/clips/desktop/src/styles.css +10 -2
  9. package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +2 -2
  10. package/corpus/templates/clips/desktop/src-tauri/src/util.rs +1 -1
  11. package/corpus/templates/factory/app/routes/factory.tsx +0 -3
  12. package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +1 -1
  13. package/corpus/templates/slides/app/components/editor/ShareDialog.tsx +28 -25
  14. package/corpus/templates/slides/app/components/editor/SlideContextToolbar.tsx +50 -0
  15. package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +12 -60
  16. package/dist/agent/production-agent.d.ts +8 -0
  17. package/dist/agent/production-agent.js +25 -2
  18. package/dist/agent/run-manager.js +13 -3
  19. package/dist/client/AgentPanel.js +6 -4
  20. package/dist/client/org/WorkspaceNotice.js +7 -4
  21. package/dist/client/sharing/ShareButton.d.ts +2 -2
  22. package/dist/client/sharing/ShareButton.js +18 -13
  23. package/dist/client/sharing/ShareDialog.d.ts +1 -1
  24. package/dist/client/sharing/ShareDialog.js +13 -10
  25. package/dist/collab/routes.d.ts +1 -1
  26. package/dist/collab/struct-routes.d.ts +1 -1
  27. package/dist/notifications/routes.d.ts +1 -1
  28. package/dist/observability/routes.d.ts +3 -3
  29. package/dist/progress/routes.d.ts +1 -1
  30. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  31. package/dist/server/auth.js +18 -4
  32. package/dist/server/better-auth-instance.js +8 -1
  33. package/dist/server/magic-link-attribution.d.ts +21 -0
  34. package/dist/server/magic-link-attribution.js +115 -0
  35. package/dist/server/realtime-token.d.ts +1 -1
  36. package/package.json +1 -1
@@ -36,6 +36,8 @@ import {
36
36
  IconStackBack,
37
37
  IconStackFront,
38
38
  IconUnderline,
39
+ IconZoomIn,
40
+ IconZoomOut,
39
41
  } from "@tabler/icons-react";
40
42
  import type { ReactNode } from "react";
41
43
 
@@ -150,6 +152,7 @@ export function SlideContextToolbar({
150
152
  objectSelectionCount = 0,
151
153
  onAlignObjects,
152
154
  onDistributeObjects,
155
+ zoomControls,
153
156
  }: {
154
157
  snapshot: SlideStyleSnapshot | null;
155
158
  background: string | undefined;
@@ -164,6 +167,13 @@ export function SlideContextToolbar({
164
167
  objectSelectionCount?: number;
165
168
  onAlignObjects?: (alignment: SlideObjectAlignment) => void;
166
169
  onDistributeObjects?: (distribution: SlideObjectDistribution) => void;
170
+ zoomControls?: {
171
+ value: number;
172
+ onZoomOut: () => void;
173
+ onZoomIn: () => void;
174
+ canZoomOut: boolean;
175
+ canZoomIn: boolean;
176
+ };
167
177
  }) {
168
178
  const t = useT();
169
179
  const documentColors = tokenPalette(designSystem, t).map(
@@ -914,6 +924,46 @@ export function SlideContextToolbar({
914
924
  </Popover>
915
925
  </>
916
926
  )}
927
+ {zoomControls && (
928
+ <>
929
+ <div className={TOOLBAR_DIVIDER} />
930
+ <Tooltip>
931
+ <TooltipTrigger asChild>
932
+ <Button
933
+ type="button"
934
+ variant="ghost"
935
+ size="icon"
936
+ className={MENU_BUTTON_CLASS}
937
+ onClick={zoomControls.onZoomOut}
938
+ disabled={!zoomControls.canZoomOut}
939
+ aria-label={t("raw.zoomOut")}
940
+ >
941
+ <IconZoomOut className="size-3.5" />
942
+ </Button>
943
+ </TooltipTrigger>
944
+ <TooltipContent>{t("raw.zoomOut")}</TooltipContent>
945
+ </Tooltip>
946
+ <span className="w-11 shrink-0 text-center text-xs tabular-nums text-muted-foreground">
947
+ {zoomControls.value}%
948
+ </span>
949
+ <Tooltip>
950
+ <TooltipTrigger asChild>
951
+ <Button
952
+ type="button"
953
+ variant="ghost"
954
+ size="icon"
955
+ className={MENU_BUTTON_CLASS}
956
+ onClick={zoomControls.onZoomIn}
957
+ disabled={!zoomControls.canZoomIn}
958
+ aria-label={t("raw.zoomIn")}
959
+ >
960
+ <IconZoomIn className="size-3.5" />
961
+ </Button>
962
+ </TooltipTrigger>
963
+ <TooltipContent>{t("raw.zoomIn")}</TooltipContent>
964
+ </Tooltip>
965
+ </>
966
+ )}
917
967
  </div>
918
968
  );
919
969
  }
@@ -21,13 +21,10 @@ import {
21
21
  IconBrush,
22
22
  IconClipboard,
23
23
  IconCopy,
24
- IconMaximize,
25
24
  IconStackBack,
26
25
  IconStackFront,
27
26
  IconTrash,
28
27
  IconX,
29
- IconZoomIn,
30
- IconZoomOut,
31
28
  } from "@tabler/icons-react";
32
29
  import {
33
30
  useState,
@@ -1252,10 +1249,6 @@ export default function SlideEditor({
1252
1249
  .find((preset) => preset < canvasZoom);
1253
1250
  setManualCanvasZoom(previous ?? CANVAS_ZOOM_PRESETS[0]);
1254
1251
  }, [canvasZoom, setManualCanvasZoom]);
1255
- const fitCanvasToScreen = useCallback(() => {
1256
- userSetCanvasZoomRef.current = false;
1257
- setCanvasZoom(fitCanvasZoom);
1258
- }, [fitCanvasZoom]);
1259
1252
 
1260
1253
  usePinchZoom({
1261
1254
  containerRef: scrollContainerRef,
@@ -5010,6 +5003,16 @@ export default function SlideEditor({
5010
5003
  const objectOperationSelection = getObjectOperationSelection();
5011
5004
  const hasObjectSelection = objectOperationSelection !== null;
5012
5005
  const objectSelectionCount = objectOperationSelection?.elements.length ?? 0;
5006
+ const zoomControls = slide.excalidrawData
5007
+ ? undefined
5008
+ : {
5009
+ value: canvasZoom,
5010
+ onZoomOut: canvasZoomOut,
5011
+ onZoomIn: canvasZoomIn,
5012
+ canZoomOut: canvasZoom > MIN_CANVAS_ZOOM,
5013
+ canZoomIn:
5014
+ canvasZoom < CANVAS_ZOOM_PRESETS[CANVAS_ZOOM_PRESETS.length - 1],
5015
+ };
5013
5016
 
5014
5017
  // Excalidraw slides have no selectable slide content, so the row collapses
5015
5018
  // to its slide-level state — but that state owns the background picker, and
@@ -5038,6 +5041,7 @@ export default function SlideEditor({
5038
5041
  objectSelectionCount={objectSelectionCount}
5039
5042
  onAlignObjects={handleAlignSelectedObjects}
5040
5043
  onDistributeObjects={handleDistributeSelectedObjects}
5044
+ zoomControls={zoomControls}
5041
5045
  />
5042
5046
  </div>
5043
5047
  ) : null;
@@ -5061,6 +5065,7 @@ export default function SlideEditor({
5061
5065
  objectSelectionCount={objectSelectionCount}
5062
5066
  onAlignObjects={handleAlignSelectedObjects}
5063
5067
  onDistributeObjects={handleDistributeSelectedObjects}
5068
+ zoomControls={zoomControls}
5064
5069
  className="slide-context-toolbar--top-row"
5065
5070
  />
5066
5071
  </div>
@@ -5102,59 +5107,6 @@ export default function SlideEditor({
5102
5107
  </div>
5103
5108
  ) : (
5104
5109
  <div className="relative h-full bg-[var(--slides-editor-surface)]">
5105
- <div className="absolute right-3 top-3 z-20 flex h-8 items-center gap-0.5 rounded-md bg-popover/95 px-1">
5106
- <Tooltip>
5107
- <TooltipTrigger asChild>
5108
- <Button
5109
- variant="ghost"
5110
- size="icon"
5111
- className="h-6 w-6 cursor-pointer"
5112
- onClick={canvasZoomOut}
5113
- disabled={canvasZoom <= MIN_CANVAS_ZOOM}
5114
- aria-label={t("raw.zoomOut")}
5115
- >
5116
- <IconZoomOut className="h-3.5 w-3.5" />
5117
- </Button>
5118
- </TooltipTrigger>
5119
- <TooltipContent>{t("raw.zoomOut")}</TooltipContent>
5120
- </Tooltip>
5121
- <span className="w-11 text-center text-xs tabular-nums text-muted-foreground">
5122
- {canvasZoom}%
5123
- </span>
5124
- <Tooltip>
5125
- <TooltipTrigger asChild>
5126
- <Button
5127
- variant="ghost"
5128
- size="icon"
5129
- className="h-6 w-6 cursor-pointer"
5130
- onClick={canvasZoomIn}
5131
- disabled={
5132
- canvasZoom >=
5133
- CANVAS_ZOOM_PRESETS[CANVAS_ZOOM_PRESETS.length - 1]
5134
- }
5135
- aria-label={t("raw.zoomIn")}
5136
- >
5137
- <IconZoomIn className="h-3.5 w-3.5" />
5138
- </Button>
5139
- </TooltipTrigger>
5140
- <TooltipContent>{t("raw.zoomIn")}</TooltipContent>
5141
- </Tooltip>
5142
- <div className="mx-0.5 h-4 w-px bg-border" />
5143
- <Tooltip>
5144
- <TooltipTrigger asChild>
5145
- <Button
5146
- variant="ghost"
5147
- size="icon"
5148
- className="h-6 w-6 cursor-pointer"
5149
- onClick={fitCanvasToScreen}
5150
- aria-label={t("raw.fitSlideToScreen")}
5151
- >
5152
- <IconMaximize className="h-3.5 w-3.5" />
5153
- </Button>
5154
- </TooltipTrigger>
5155
- <TooltipContent>{t("raw.fitToScreen")}</TooltipContent>
5156
- </Tooltip>
5157
- </div>
5158
5110
  <div
5159
5111
  ref={scrollContainerRef}
5160
5112
  className={`h-full overflow-auto ${
@@ -373,6 +373,14 @@ export interface ProductionAgentOptions {
373
373
  };
374
374
  }
375
375
  export declare function resolveAgentOwnerEmail(options: Pick<ProductionAgentOptions, "resolveOwnerEmail">, event: any): Promise<string | null>;
376
+ /**
377
+ * A transient database failure in the completion callback used to prevent a
378
+ * background continuation from ever being handed off. Keep the retry bounded
379
+ * and database-only so a permanent persistence error still fails loudly.
380
+ */
381
+ export declare function runCompletionCallbackWithDatabaseRetry(callback: () => void | Promise<void>, options?: {
382
+ sleep?: (ms: number) => Promise<void>;
383
+ }): Promise<void>;
376
384
  declare function generateRunId(): string;
377
385
  /** Check if an error is transient and should be retried
378
386
  * @internal exported for unit tests only
@@ -5,7 +5,7 @@ import { parseA2AAgentActivityPart } from "../a2a/activity.js";
5
5
  import { describeToolParameterSignature, isAgentActionStopError, } from "../action.js";
6
6
  import { readAppState } from "../application-state/script-helpers.js";
7
7
  import { isReadOnlyShellCommand } from "../coding-tools/index.js";
8
- import { getDbExec } from "../db/client.js";
8
+ import { getDbExec, isTransientDatabaseError } from "../db/client.js";
9
9
  import { extensionIdFromPathname } from "../extensions/path.js";
10
10
  import { preUploadAttachments } from "../file-upload/pre-upload-attachments.js";
11
11
  import { isMcpActionResult } from "../mcp-client/app-result.js";
@@ -620,6 +620,29 @@ export async function resolveAgentOwnerEmail(options, event) {
620
620
  return ownerEmail ?? getRequestUserEmail() ?? null;
621
621
  }
622
622
  const MAX_RETRIES = 3;
623
+ const COMPLETION_DATABASE_RETRY_DELAYS_MS = [250, 750, 1_500];
624
+ /**
625
+ * A transient database failure in the completion callback used to prevent a
626
+ * background continuation from ever being handed off. Keep the retry bounded
627
+ * and database-only so a permanent persistence error still fails loudly.
628
+ */
629
+ export async function runCompletionCallbackWithDatabaseRetry(callback, options) {
630
+ const sleep = options?.sleep ??
631
+ ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
632
+ for (let attempt = 0;; attempt += 1) {
633
+ try {
634
+ await callback();
635
+ return;
636
+ }
637
+ catch (error) {
638
+ const retryDelay = COMPLETION_DATABASE_RETRY_DELAYS_MS[attempt];
639
+ if (!isTransientDatabaseError(error) || retryDelay === undefined) {
640
+ throw error;
641
+ }
642
+ await sleep(retryDelay);
643
+ }
644
+ }
645
+ }
623
646
  /**
624
647
  * Retry budget override for `builder_gateway_error` — the no-detail Builder
625
648
  * gateway fallback. Production data shows this code is almost never
@@ -6981,7 +7004,7 @@ export function createProductionAgentHandler(options) {
6981
7004
  const baseHandleRunComplete = options.onRunComplete || trackedProgressRunId
6982
7005
  ? async (run) => {
6983
7006
  try {
6984
- await options.onRunComplete?.(run, threadId);
7007
+ await runCompletionCallbackWithDatabaseRetry(() => options.onRunComplete?.(run, threadId));
6985
7008
  }
6986
7009
  catch (err) {
6987
7010
  await completeTrackedProgressRun(run, err);
@@ -448,6 +448,11 @@ function terminalEventForcesErroredStatus(event) {
448
448
  return event?.type === "error" || event?.type === "missing_api_key";
449
449
  }
450
450
  function terminalReasonForRun(finalStatus, terminalEvent, abortReason, completionError) {
451
+ if (finalStatus !== "aborted" &&
452
+ completionError &&
453
+ terminalEvent?.type === "auto_continue") {
454
+ return "completion_error";
455
+ }
451
456
  if (terminalEvent?.type === "auto_continue") {
452
457
  return terminalEvent.reason || "auto_continue";
453
458
  }
@@ -1295,13 +1300,18 @@ export function startRun(runId, threadId, runFn, onComplete, options) {
1295
1300
  : terminalEventForCompletion?.event.type === "error" ||
1296
1301
  terminalEventForCompletion?.event.type === "missing_api_key"
1297
1302
  ? terminalEventForCompletion.event
1298
- : terminalEventForCompletion?.event.type === "auto_continue"
1303
+ : terminalEventForCompletion?.event.type === "auto_continue" &&
1304
+ run.continuationTerminalEvent
1299
1305
  ? // The run was checkpointed at a soft-timeout/loop boundary and
1300
1306
  // is recoverable: the partial turn is in agent_run_events and
1301
- // the continuation run will re-attempt the thread_data save.
1307
+ // the handed-off continuation run will re-attempt the
1308
+ // thread_data save.
1302
1309
  // Even though the completion save failed (finalStatus stays
1303
1310
  // "errored" for SQL/diagnostics), re-emit the auto_continue so
1304
- // the client resumes instead of seeing a dead chat.
1311
+ // the client resumes instead of seeing a dead chat. A
1312
+ // pending auto_continue without this handoff marker is not
1313
+ // recoverable: advertising it makes the client poll a dead
1314
+ // run until it reports background_run_lost.
1305
1315
  terminalEventForCompletion.event
1306
1316
  : {
1307
1317
  type: "error",
@@ -22,7 +22,7 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
22
22
  * <AgentChatSurface mode="page" className="h-screen" />
23
23
  */
24
24
  import { Tooltip as DesignSystemTooltip } from "@agent-native/toolkit/design-system";
25
- import { IconMessageCircle, IconMessageDots, IconTerminal2, IconSettings, IconLayoutSidebarRightCollapse, IconLayoutGrid, IconCheck, IconPlus, IconX, IconDotsVertical, IconHistory, IconArrowsHorizontal, IconArrowsMaximize, IconExternalLink, } from "@tabler/icons-react";
25
+ import { IconMessageCircle, IconMessageDots, IconTerminal2, IconSettings, IconLayoutSidebarRightCollapse, IconLayoutGrid, IconCheck, IconPlus, IconX, IconDotsVertical, IconHistory, IconArrowsHorizontal, IconArrowsMaximize, IconExternalLink, IconShare3, } from "@tabler/icons-react";
26
26
  import React, { useState, useEffect, useRef, useCallback, useMemo, lazy, Suspense, startTransition, } from "react";
27
27
  import { flushSync } from "react-dom";
28
28
  import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuTrigger, } from "./components/ui/dropdown-menu.js";
@@ -666,6 +666,7 @@ function AgentPanelInner({ defaultMode = "chat", className, style, apiUrl, empty
666
666
  : "text-muted-foreground hover:bg-accent/50 hover:text-foreground"), style: AGENT_PANEL_CONTROL_STYLE, children: [_jsx(IconLayoutGrid, { size: 14 }), t("agentPanel.workspace")] }), content: t("agentPanel.workspaceMode"), delayMs: 200 })] })), [codeAccessEnabled, codeUnavailableDescription, showCliMode, t]);
667
667
  const [headerMenuOpen, setHeaderMenuOpen] = useState(false);
668
668
  const [feedbackOpen, setFeedbackOpen] = useState(false);
669
+ const [shareFromMenuOpen, setShareFromMenuOpen] = useState(false);
669
670
  const getChatThreadShareUrl = useCallback((threadId) => {
670
671
  if (typeof window === "undefined")
671
672
  return undefined;
@@ -700,7 +701,7 @@ function AgentPanelInner({ defaultMode = "chat", className, style, apiUrl, empty
700
701
  document.addEventListener("keydown", handleKeyDown);
701
702
  return () => document.removeEventListener("keydown", handleKeyDown);
702
703
  }, [mode, onCollapse, wideDrawerAction]);
703
- const renderHeaderActions = useCallback(({ activeChatSessionId, activeTabId, activeTabMessageCount, addTab, clearActiveTab, closeAllTabs, closeOtherTabs, closeTab, showHistory, tabs, toggleHistory, }) => (_jsxs("div", { className: "relative flex shrink-0 items-center gap-0.5", children: [!onCollapse && SHOW_ONBOARDING && (_jsx(Suspense, { fallback: null, children: _jsx(SetupButton, {}) })), !onCollapse &&
704
+ const renderHeaderActions = useCallback(({ activeChatSessionId, activeTabId, activeTabMessageCount, addTab, clearActiveTab, closeAllTabs, closeOtherTabs, closeTab, showHistory, tabs, toggleHistory, }) => (_jsxs("div", { className: "relative flex shrink-0 items-center gap-0.5", children: [!onCollapse && SHOW_ONBOARDING && (_jsx(Suspense, { fallback: null, children: _jsx(SetupButton, {}) })), (!onCollapse || shareFromMenuOpen) &&
704
705
  (() => {
705
706
  const activeTab = mode === "chat" && activeChatSessionId
706
707
  ? tabs.find((tab) => tab.id === activeChatSessionId)
@@ -709,7 +710,7 @@ function AgentPanelInner({ defaultMode = "chat", className, style, apiUrl, empty
709
710
  (activeTabMessageCount <= 0 && activeTab.status === "idle")) {
710
711
  return null;
711
712
  }
712
- return (_jsx(ShareButton, { resourceType: "chat_thread", resourceId: activeTab.id, allowedRoles: ["viewer", "editor", "admin"], resourceTitle: activeTab.label || "Chat", shareUrl: getChatThreadShareUrl(activeTab.id), trigger: "icon", triggerClassName: "h-7 w-7" }));
713
+ return (_jsx(ShareButton, { resourceType: "chat_thread", resourceId: activeTab.id, allowedRoles: ["viewer", "editor", "admin"], resourceTitle: activeTab.label || "Chat", shareUrl: getChatThreadShareUrl(activeTab.id), trigger: "icon", triggerClassName: "h-7 w-7", defaultOpen: onCollapse && shareFromMenuOpen, onOpenChange: onCollapse ? setShareFromMenuOpen : undefined }));
713
714
  })(), feedbackEnabled ? (_jsx(FeedbackButton, { variant: "icon", side: "bottom", align: "end", chatSessionId: activeChatSessionId, chatStorageKey: storageKey, open: feedbackOpen, onOpenChange: setFeedbackOpen, trigger: _jsx("button", { type: "button", tabIndex: -1, "aria-hidden": "true", className: "pointer-events-none absolute end-0 top-full h-px w-px opacity-0" }) })) : null, mode === "chat" && (_jsx(IconTooltip, { content: t("agentPanel.newChat"), children: _jsx("button", { onClick: addTab, "aria-label": t("agentPanel.newChat"), className: "flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:text-foreground hover:bg-accent/50", children: _jsx(IconPlus, { size: 14 }) }) })), !onCollapse && mode === "cli" && canUseCodeTools && (_jsx(IconTooltip, { content: t("agentPanel.newTerminal"), children: _jsx("button", { onClick: addCliTab, "aria-label": t("agentPanel.newTerminal"), className: "flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:text-foreground hover:bg-accent/50", children: _jsx(IconPlus, { size: 14 }) }) })), _jsxs(DropdownMenu, { open: headerMenuOpen, onOpenChange: setHeaderMenuOpen, children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx("button", { className: cn("flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:text-foreground hover:bg-accent/50", (headerMenuOpen || mode === "settings") &&
714
715
  "bg-accent text-foreground"), "aria-label": t("agentPanel.panelOptions"), children: _jsx(IconDotsVertical, { size: 14 }) }) }), _jsxs(DropdownMenuContent, { align: "end", sideOffset: 6, className: "w-48", children: [onCollapse && (_jsxs(_Fragment, { children: [_jsxs(DropdownMenuItem, { onSelect: onCollapse, children: [_jsx(IconLayoutSidebarRightCollapse, { size: 14, className: "shrink-0" }), t("agentPanel.collapseSidebar"), _jsx(DropdownMenuShortcut, { children: toggleSidebarHint })] }), _jsx(DropdownMenuSeparator, {})] })), onCollapse && mode === "chat" && wideDrawerAction ? (_jsxs(DropdownMenuItem, { onSelect: wideDrawerAction, children: [_jsx(IconArrowsHorizontal, { size: 14, className: "shrink-0" }), wideDrawerLabel, _jsx(DropdownMenuShortcut, { children: widenChatHint })] })) : null, fullViewAction?.kind === "callback" && onFullViewRequest ? (_jsxs(DropdownMenuItem, { onSelect: onFullViewRequest, "aria-label": t("agentPanel.openFullView"), children: [_jsx(IconArrowsMaximize, { size: 14, className: "shrink-0" }), t("agentPanel.openFullView")] })) : fullViewAction?.kind === "link" ? (_jsx(DropdownMenuItem, { asChild: true, children: _jsxs(Link, { to: fullViewAction.href, "aria-label": t("agentPanel.openFullView"), children: [_jsx(IconArrowsMaximize, { size: 14, className: "shrink-0" }), t("agentPanel.openFullView")] }) })) : null, (onCollapse && mode === "chat" && wideDrawerAction) ||
715
716
  fullViewAction ? (_jsx(DropdownMenuSeparator, {})) : null, onCollapse && mode === "chat" && (_jsxs(_Fragment, { children: [_jsxs(DropdownMenuItem, { onSelect: addTab, children: [_jsx(IconPlus, { size: 14, className: "shrink-0" }), t("agentPanel.newChat")] }), (() => {
@@ -720,7 +721,7 @@ function AgentPanelInner({ defaultMode = "chat", className, style, apiUrl, empty
720
721
  (activeTabMessageCount <= 0 && activeTab.status === "idle")) {
721
722
  return null;
722
723
  }
723
- return (_jsx("div", { className: "p-1", children: _jsx(ShareButton, { resourceType: "chat_thread", resourceId: activeTab.id, allowedRoles: ["viewer", "editor", "admin"], resourceTitle: activeTab.label || "Chat", shareUrl: getChatThreadShareUrl(activeTab.id), trigger: "label-icon", triggerClassName: "w-full justify-start" }) }));
724
+ return (_jsxs(DropdownMenuItem, { onSelect: (event) => deferAgentPanelOverlayOpen(event, () => setHeaderMenuOpen(false), () => setShareFromMenuOpen(true)), children: [_jsx(IconShare3, { size: 14, className: "shrink-0" }), "Share"] }));
724
725
  })()] })), mode === "chat" && toggleHistory && (_jsxs(DropdownMenuItem, { onSelect: (event) => deferAgentPanelOverlayOpen(event, () => setHeaderMenuOpen(false), toggleHistory), children: [_jsx(IconHistory, { size: 14, className: "shrink-0" }), showHistory
725
726
  ? t("agentPanel.hideChats")
726
727
  : t("agentPanel.allChats")] })), mode === "chat" && (_jsx(RunsTrayMenuItem, { pollMs: 0, limit: 12, showRecent: true, onOpenThread: openRunThread })), mode === "chat" && _jsx(DropdownMenuSeparator, {}), mode === "cli" && availableClis.length > 0 && (_jsxs(_Fragment, { children: [availableClis.map((cli) => (_jsxs(DropdownMenuItem, { onSelect: () => selectCli(cli.command), className: cn(cli.command === selectedCli
@@ -752,6 +753,7 @@ function AgentPanelInner({ defaultMode = "chat", className, style, apiUrl, empty
752
753
  openRunThread,
753
754
  selectCli,
754
755
  selectedCli,
756
+ shareFromMenuOpen,
755
757
  storageKey,
756
758
  switchMode,
757
759
  t,
@@ -1,8 +1,9 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { IconExternalLink } from "@tabler/icons-react";
2
+ import { IconAlertTriangle, IconExternalLink } from "@tabler/icons-react";
3
3
  import { useState } from "react";
4
4
  import { isLocalDevelopmentOrigin, shouldOfferWorkspace, } from "../../org/workspace-url.js";
5
5
  import { useOrg } from "./hooks.js";
6
+ import { isWorkspaceAppEnvironment } from "./workspace-app-links.js";
6
7
  const DISMISS_KEY_PREFIX = "agent-native:workspace-notice-dismissed:";
7
8
  function dismissKey(workspaceUrl) {
8
9
  return `${DISMISS_KEY_PREFIX}${workspaceUrl}`;
@@ -38,14 +39,16 @@ export function WorkspaceNotice({ className }) {
38
39
  const workspaceUrl = org?.workspaceUrl ?? null;
39
40
  if (typeof window === "undefined")
40
41
  return null;
41
- if (isLocalDevelopmentOrigin(window.location.href))
42
+ if (isLocalDevelopmentOrigin(window.location.href) ||
43
+ isWorkspaceAppEnvironment()) {
42
44
  return null;
45
+ }
43
46
  if (!workspaceUrl || dismissedNow || readDismissed(workspaceUrl))
44
47
  return null;
45
48
  if (!shouldOfferWorkspace(window.location.href, workspaceUrl))
46
49
  return null;
47
50
  const workspaceHost = new URL(workspaceUrl).host;
48
- return (_jsx("div", { className: `border-b border-border bg-blue-50 dark:bg-blue-950/30 px-3 py-2.5 sm:px-4 ${className ?? ""}`, children: _jsxs("div", { className: "flex items-center justify-between gap-4 text-sm", children: [_jsxs("span", { className: "min-w-0 flex-1 text-foreground", children: [_jsx("span", { className: "font-medium", children: org?.orgName }), " has its own workspace at ", _jsx("span", { className: "font-medium", children: workspaceHost }), ". Your team's apps live there, not here."] }), _jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [_jsxs("a", { href: workspaceUrl, className: "inline-flex items-center gap-1.5 rounded-md bg-green-600 px-3 py-1.5 text-xs font-medium text-white no-underline hover:bg-green-700", children: [_jsx(IconExternalLink, { className: "h-3 w-3" }), "Go there"] }), _jsx("button", { type: "button", onClick: () => {
51
+ return (_jsx("div", { role: "status", "aria-live": "polite", className: `border-b border-amber-500/30 bg-amber-500/10 px-3 py-3 text-amber-900 dark:text-amber-200 sm:px-4 ${className ?? ""}`, children: _jsxs("div", { className: "flex flex-wrap items-start gap-x-3 gap-y-2 text-sm", children: [_jsx(IconAlertTriangle, { "aria-hidden": "true", className: "mt-0.5 size-4 shrink-0 text-amber-600 dark:text-amber-400" }), _jsxs("span", { className: "min-w-0 flex-1 leading-5", children: [_jsx("span", { className: "font-medium", children: org?.orgName }), " has its own workspace at ", _jsx("span", { className: "font-medium", children: workspaceHost }), ". Your team's apps live there, not here."] }), _jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [_jsxs("a", { href: workspaceUrl, className: "inline-flex items-center gap-1.5 rounded-md border border-amber-600 bg-amber-600 px-3 py-1.5 text-xs font-medium text-primary-foreground no-underline hover:bg-amber-700 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2", children: [_jsx(IconExternalLink, { className: "h-3 w-3" }), "Go there"] }), _jsx("button", { type: "button", onClick: () => {
49
52
  try {
50
53
  localStorage.setItem(dismissKey(workspaceUrl), "1");
51
54
  }
@@ -53,5 +56,5 @@ export function WorkspaceNotice({ className }) {
53
56
  // Private-mode storage failure only costs a repeat banner.
54
57
  }
55
58
  setDismissedNow(true);
56
- }, className: "rounded-md border border-border px-3 py-1.5 text-xs font-medium text-muted-foreground hover:text-foreground cursor-pointer", children: "Stay here" })] })] }) }));
59
+ }, className: "cursor-pointer rounded-md border border-amber-500/40 bg-background/60 px-3 py-1.5 text-xs font-medium text-amber-900 hover:bg-amber-500/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 dark:border-amber-800 dark:bg-amber-950/20 dark:text-amber-100 dark:hover:bg-amber-900/40", children: "Stay here" })] })] }) }));
57
60
  }
@@ -29,8 +29,8 @@ export interface ShareButtonProps {
29
29
  shareUrlLabel?: string;
30
30
  /** Optional helper text for the primary copyable link section. */
31
31
  shareUrlDescription?: ReactNode;
32
- /** Where to render share links in the popover. Defaults to the bottom,
33
- * matching the historical Google-Docs-style share dialog. */
32
+ /** Where to render share links in the popover. Defaults to the top,
33
+ * keeping the copyable link as the primary share action. */
34
34
  shareUrlPlacement?: "top" | "bottom";
35
35
  /** Whether to render copyable share URL fields. Defaults to true. */
36
36
  showShareLinks?: boolean;
@@ -1,4 +1,5 @@
1
1
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Collapsible, CollapsibleContent, CollapsibleTrigger, } from "@agent-native/toolkit/ui";
2
3
  import * as Select from "@radix-ui/react-select";
3
4
  import { IconLock, IconWorld, IconTrash, IconCheck, IconChevronDown, IconCopy, IconLoader2, IconSearch, IconSearchOff, IconShare3, IconUsersGroup, } from "@tabler/icons-react";
4
5
  import { useEffect, useId, useRef, useState, } from "react";
@@ -114,25 +115,29 @@ function SharePanel(props) {
114
115
  (Boolean(props.shareUrl) ||
115
116
  Boolean(props.shareUrlPlaceholder) ||
116
117
  Boolean(props.secondaryShareUrl));
117
- const shareUrlPlacement = props.shareUrlPlacement ?? "bottom";
118
+ const shareUrlPlacement = props.shareUrlPlacement ?? "top";
119
+ const [advancedOpen, setAdvancedOpen] = useState(!showShareLinks);
120
+ useEffect(() => {
121
+ setAdvancedOpen(!showShareLinks);
122
+ }, [props.resourceId, showShareLinks]);
118
123
  const extraTabs = props.shareTabs?.tabs ?? [];
119
124
  const hasTabs = extraTabs.length > 0;
120
125
  const shareTabLabel = props.shareTabs?.shareLabel ?? "Share link";
121
126
  const titleText = resourceTitle
122
127
  ? `Share "${resourceTitle}"`
123
128
  : `Share ${props.resourceType}`;
124
- const sharePanel = isLoading ? (_jsxs("div", { children: [!hasTabs ? (_jsx("div", { className: "mb-3 truncate text-base font-semibold", title: titleText, children: titleText })) : null, _jsx("div", { className: "mb-4 h-9 rounded-md bg-muted animate-pulse" }), _jsx("div", { className: "mb-2 text-sm font-semibold", children: peopleAccessLabel }), _jsx("div", { className: "mb-4 h-7 rounded-md bg-muted animate-pulse" }), _jsx("div", { className: "mb-2 text-sm font-semibold", children: generalAccessLabel }), _jsx("div", { className: "mb-4 h-9 rounded-md bg-muted animate-pulse" })] })) : (_jsxs("div", { children: [!hasTabs ? (_jsx("div", { className: "mb-3 truncate text-base font-semibold", title: titleText, children: titleText })) : null, showShareLinks && shareUrlPlacement === "top" ? shareLinks : null, canManage ? (_jsxs("div", { className: "mb-4 space-y-2", children: [_jsxs("div", { className: "flex items-stretch gap-2", children: [_jsx(MemberAutocomplete, { value: inviteEmail, open: suggestionsOpen, onOpenChange: setSuggestionsOpen, onValueChange: (next) => {
125
- onInviteEmailChange(next);
126
- if (shareError)
127
- setShareError(null);
128
- }, onSelectMember: (member) => {
129
- onInviteEmailChange(member.email);
130
- setSuggestionsOpen(false);
131
- if (shareError)
132
- setShareError(null);
133
- }, onSubmit: handleAdd, placeholder: policy.requireOrgMemberForUserShares
134
- ? "Add people from your organization"
135
- : "Add people by email", suggestions: memberSuggestions, search: memberSearch }), _jsx(RoleSelect, { value: role, onChange: setRole, roleCopy: props.roleCopy, allowedRoles: props.allowedRoles }), _jsx("button", { type: "button", onClick: handleAdd, disabled: !hasInviteEmail, className: BUTTON_PRIMARY_SM, children: "Add" })] }), shareError ? (_jsx("div", { role: "alert", className: "rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive", children: shareError })) : null, hasInviteEmail ? (_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: notifyPeople, onChange: (e) => setNotifyPeople(e.target.checked), className: "h-4 w-4 rounded border-input accent-primary" }), "Notify people"] }), notifyPeople ? (_jsx("button", { type: "button", "aria-expanded": messageOpen, onClick: () => setMessageOpen(!messageOpen), className: "rounded-sm px-1 py-0.5 font-medium text-foreground underline decoration-border underline-offset-2 transition-colors hover:bg-accent hover:text-accent-foreground", children: messageOpen ? "Hide message" : "Add a message" })) : null] })) : null, hasInviteEmail && notifyPeople && messageOpen ? (_jsx("div", { className: "rounded-md border border-border/70 bg-muted/20 p-2.5", children: _jsx("textarea", { "aria-label": "Message", placeholder: "Add a short note (optional)", value: shareMessage, onChange: (event) => setShareMessage(event.target.value), maxLength: 500, rows: 3, className: "w-full resize-y rounded-md border border-input bg-card px-3 py-2 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" }) })) : null] })) : null, _jsx("div", { className: "mb-2 text-sm font-semibold", children: peopleAccessLabel }), _jsxs("ul", { className: "mb-4 flex flex-col gap-1 list-none p-0 m-0", children: [data?.ownerEmail ? (_jsxs("li", { className: "flex items-center gap-3 px-1 py-1.5 text-sm", children: [_jsx(Avatar, { label: displayName(data.ownerEmail, knownMembers) }), _jsx("span", { className: "flex-1 min-w-0 truncate", children: displayName(data.ownerEmail, knownMembers) }), _jsx("span", { className: "text-xs text-muted-foreground", children: "Owner" })] })) : null, shares.map((s) => (_jsxs("li", { className: cn("flex items-center gap-3 px-1 py-1.5 text-sm", inFlight.has(keyOf(s)) && "opacity-60"), children: [_jsx(Avatar, { label: principalLabel(s, knownMembers), org: s.principalType === "org" }), _jsx("span", { className: "flex-1 min-w-0 truncate", children: principalLabel(s, knownMembers) }), canManage ? (_jsx(RoleSelect, { value: s.role, onChange: (r) => handleChangeRole(s, r), disabled: inFlight.has(keyOf(s)), plain: true, roleCopy: props.roleCopy, allowedRoles: props.allowedRoles })) : (_jsx("span", { className: "text-xs text-muted-foreground", children: roleMeta(s.role, props.roleCopy).label })), canManage ? (_jsx("button", { type: "button", "aria-label": "Remove", 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: "No one has access yet." })) : null] }), _jsx("div", { className: "mb-2 text-sm font-semibold", children: generalAccessLabel }), _jsxs("div", { className: "mb-4 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(meta.Icon, { size: 16, strokeWidth: 1.75 }) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx(VisibilitySelect, { value: visibility, onChange: handleVisibility, disabled: !canManage, visibilityCopy: props.visibilityCopy, allowPublic: policy.allowPublic }), _jsxs("div", { className: "mt-0.5 flex flex-wrap items-center gap-x-2 gap-y-1 text-xs text-muted-foreground", children: [_jsx("span", { children: meta.description }), visibility === "org" && props.hideInSearchControl ? (_jsx(AdvancedAccessPopover, { control: props.hideInSearchControl, canManage: canManage, onToggle: handleHideInSearch })) : 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] }));
129
+ const sharePanel = isLoading ? (_jsxs("div", { children: [!hasTabs ? (_jsx("div", { className: "mb-3 truncate text-base font-semibold", title: titleText, children: titleText })) : null, _jsx("div", { className: "mb-4 h-9 rounded-md bg-muted animate-pulse" }), _jsx("div", { className: "mb-2 text-sm font-semibold", children: peopleAccessLabel }), _jsx("div", { className: "mb-4 h-7 rounded-md bg-muted animate-pulse" }), _jsx("div", { className: "mb-2 text-sm font-semibold", children: generalAccessLabel }), _jsx("div", { className: "mb-4 h-9 rounded-md bg-muted animate-pulse" })] })) : (_jsxs("div", { children: [!hasTabs ? (_jsx("div", { className: "mb-3 truncate text-base font-semibold", title: titleText, children: titleText })) : null, showShareLinks && shareUrlPlacement === "top" ? shareLinks : null, _jsxs(Collapsible, { open: advancedOpen, onOpenChange: setAdvancedOpen, className: "mb-4 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: [_jsxs("span", { className: "flex min-w-0 items-center gap-2 truncate", children: [_jsx(IconUsersGroup, { "aria-hidden": true, size: 15, strokeWidth: 1.8, className: "shrink-0 text-muted-foreground" }), canManage ? "Manage access" : peopleAccessLabel] }), _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: [canManage ? (_jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "flex items-stretch gap-2", children: [_jsx(MemberAutocomplete, { value: inviteEmail, open: suggestionsOpen, onOpenChange: setSuggestionsOpen, onValueChange: (next) => {
130
+ onInviteEmailChange(next);
131
+ if (shareError)
132
+ setShareError(null);
133
+ }, onSelectMember: (member) => {
134
+ onInviteEmailChange(member.email);
135
+ setSuggestionsOpen(false);
136
+ if (shareError)
137
+ setShareError(null);
138
+ }, onSubmit: handleAdd, placeholder: policy.requireOrgMemberForUserShares
139
+ ? "Add people from your organization"
140
+ : "Add people by email", suggestions: memberSuggestions, search: memberSearch }), _jsx(RoleSelect, { value: role, onChange: setRole, roleCopy: props.roleCopy, allowedRoles: props.allowedRoles }), _jsx("button", { type: "button", onClick: handleAdd, disabled: !hasInviteEmail, className: BUTTON_PRIMARY_SM, children: "Add" })] }), shareError ? (_jsx("div", { role: "alert", className: "rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive", children: shareError })) : null, hasInviteEmail ? (_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: notifyPeople, onChange: (e) => setNotifyPeople(e.target.checked), className: "h-4 w-4 rounded border-input accent-primary" }), "Notify people"] }), notifyPeople ? (_jsx("button", { type: "button", "aria-expanded": messageOpen, onClick: () => setMessageOpen(!messageOpen), className: "rounded-sm px-1 py-0.5 font-medium text-foreground underline decoration-border underline-offset-2 transition-colors hover:bg-accent hover:text-accent-foreground", children: messageOpen ? "Hide message" : "Add a message" })) : null] })) : null, hasInviteEmail && notifyPeople && messageOpen ? (_jsx("div", { className: "rounded-md border border-border/70 bg-muted/20 p-2.5", children: _jsx("textarea", { "aria-label": "Message", placeholder: "Add a short note (optional)", value: shareMessage, onChange: (event) => setShareMessage(event.target.value), maxLength: 500, rows: 3, className: "w-full resize-y rounded-md border border-input bg-card px-3 py-2 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" }) })) : null] })) : null, _jsxs("div", { children: [_jsx("div", { className: "mb-2 text-sm font-semibold", children: peopleAccessLabel }), _jsxs("ul", { className: "flex flex-col gap-1 list-none p-0 m-0", children: [data?.ownerEmail ? (_jsxs("li", { className: "flex items-center gap-3 px-1 py-1.5 text-sm", children: [_jsx(Avatar, { label: displayName(data.ownerEmail, knownMembers) }), _jsx("span", { className: "flex-1 min-w-0 truncate", children: displayName(data.ownerEmail, knownMembers) }), _jsx("span", { className: "text-xs text-muted-foreground", children: "Owner" })] })) : null, shares.map((s) => (_jsxs("li", { className: cn("flex items-center gap-3 px-1 py-1.5 text-sm", inFlight.has(keyOf(s)) && "opacity-60"), children: [_jsx(Avatar, { label: principalLabel(s, knownMembers), org: s.principalType === "org" }), _jsx("span", { className: "flex-1 min-w-0 truncate", children: principalLabel(s, knownMembers) }), canManage ? (_jsx(RoleSelect, { value: s.role, onChange: (r) => handleChangeRole(s, r), disabled: inFlight.has(keyOf(s)), plain: true, roleCopy: props.roleCopy, allowedRoles: props.allowedRoles })) : (_jsx("span", { className: "text-xs text-muted-foreground", children: roleMeta(s.role, props.roleCopy).label })), canManage ? (_jsx("button", { type: "button", "aria-label": "Remove", 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: "No one has access yet." })) : null] })] })] }) })] }), _jsx("div", { className: "mb-2 text-sm font-semibold", children: generalAccessLabel }), _jsxs("div", { className: "mb-4 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(meta.Icon, { size: 16, strokeWidth: 1.75 }) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx(VisibilitySelect, { value: visibility, onChange: handleVisibility, disabled: !canManage, visibilityCopy: props.visibilityCopy, allowPublic: policy.allowPublic }), _jsxs("div", { className: "mt-0.5 flex flex-wrap items-center gap-x-2 gap-y-1 text-xs text-muted-foreground", children: [_jsx("span", { className: "sr-only", children: meta.description }), visibility === "org" && props.hideInSearchControl ? (_jsx(AdvancedAccessPopover, { control: props.hideInSearchControl, canManage: canManage, onToggle: handleHideInSearch })) : 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] }));
136
141
  if (!hasTabs)
137
142
  return sharePanel;
138
143
  const tabs = [
@@ -1,4 +1,4 @@
1
- import type { ReactNode } from "react";
1
+ import { type ReactNode } from "react";
2
2
  export interface ShareDialogProps {
3
3
  open: boolean;
4
4
  onClose: () => void;
@@ -1,6 +1,8 @@
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, TextField, } from "@agent-native/toolkit/design-system";
3
- import { IconCheck, IconCode, IconCopy, IconLink, IconLock, IconMail, IconTrash, IconUsersGroup, IconWorld, } from "@tabler/icons-react";
3
+ import { Collapsible, CollapsibleContent, CollapsibleTrigger, } from "@agent-native/toolkit/ui";
4
+ import { IconCheck, IconCode, IconCopy, IconChevronDown, IconLink, IconLock, IconMail, IconTrash, IconUsersGroup, IconWorld, } from "@tabler/icons-react";
5
+ import { useState } from "react";
4
6
  import { cn } from "../utils.js";
5
7
  import { useShareDialogController, } from "./useShareDialogController.js";
6
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";
@@ -49,18 +51,19 @@ function TabTrigger({ active, onClick, icon, label, }) {
49
51
  }
50
52
  function LinkTab({ controller, extras, }) {
51
53
  const Icon = VIS_ICONS[controller.visibility.value];
52
- return (_jsxs("div", { className: "space-y-4", children: [_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: "mt-0.5 text-xs text-muted-foreground", children: controller.visibility.description })] })] })] }), _jsx(CopyField, { field: "share-link", label: controller.labels.shareLink, value: controller.shareUrl, controller: controller }), extras] }));
54
+ return (_jsxs("div", { className: "space-y-3", children: [_jsx(CopyField, { field: "share-link", label: controller.labels.shareLink, value: controller.shareUrl, controller: controller }), _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 })] })] })] }), extras] }));
53
55
  }
54
56
  function InviteTab({ controller, showVisibility, }) {
55
57
  const Icon = VIS_ICONS[controller.visibility.value];
56
- return (_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) => {
57
- if (event.key === "Enter")
58
- controller.invite.submit();
59
- }, autoComplete: "off", className: "flex-1 min-w-0 h-9 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
60
- ? controller.labels.hideMessage
61
- : controller.labels.addMessage })) : null] })) : null, controller.invite.showNotifyPeople &&
62
- controller.invite.notifyPeople &&
63
- 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: "flex flex-col gap-1 list-none p-0 m-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: "mt-0.5 text-xs text-muted-foreground", children: controller.visibility.description })] })] })] })) : null] }));
58
+ const [advancedOpen, setAdvancedOpen] = useState(false);
59
+ 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) => {
60
+ if (event.key === "Enter")
61
+ controller.invite.submit();
62
+ }, 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
63
+ ? controller.labels.hideMessage
64
+ : controller.labels.addMessage })) : null] })) : null, controller.invite.showNotifyPeople &&
65
+ controller.invite.notifyPeople &&
66
+ 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] }));
64
67
  }
65
68
  function PersonRow({ person, canManage, removeLabel, onRemove, }) {
66
69
  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] }));
@@ -26,8 +26,8 @@ export declare const getCollabState: import("h3").EventHandlerWithFetch<import("
26
26
  * Body: { update: string (base64), requestSource?: string }
27
27
  */
28
28
  export declare const postCollabUpdate: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
29
- error: string;
30
29
  ok?: undefined;
30
+ error: string;
31
31
  } | {
32
32
  error?: undefined;
33
33
  ok: boolean;
@@ -13,8 +13,8 @@
13
13
  * Body: { json: any, fieldName?: string, type?: "map"|"array", requestSource?: string }
14
14
  */
15
15
  export declare const postCollabJson: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
16
- error: string;
17
16
  ok?: undefined;
17
+ error: string;
18
18
  } | {
19
19
  error?: undefined;
20
20
  ok: boolean;
@@ -28,6 +28,6 @@ export declare function createNotificationsHandler(): import("h3").EventHandlerW
28
28
  } | {
29
29
  count?: undefined;
30
30
  updated?: undefined;
31
- ok: boolean;
32
31
  error?: undefined;
32
+ ok: boolean;
33
33
  }>>;
@@ -41,16 +41,16 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
41
41
  thumbsUpRate: number;
42
42
  avgEvalScore: number;
43
43
  } | {
44
- error?: undefined;
45
44
  summary: import("./types.js").TraceSummary;
46
45
  spans: import("./types.js").TraceSpan[];
47
46
  id?: undefined;
47
+ error?: undefined;
48
48
  ok?: undefined;
49
49
  } | {
50
- error?: undefined;
51
50
  summary?: undefined;
52
51
  spans?: undefined;
53
52
  id: string;
53
+ error?: undefined;
54
54
  ok?: undefined;
55
55
  } | {
56
56
  summary?: undefined;
@@ -59,9 +59,9 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
59
59
  error: any;
60
60
  ok?: undefined;
61
61
  } | {
62
- error?: undefined;
63
62
  summary?: undefined;
64
63
  spans?: undefined;
65
64
  id?: undefined;
65
+ error?: undefined;
66
66
  ok: boolean;
67
67
  }>>;
@@ -15,6 +15,6 @@ export declare function createProgressHandler(): import("h3").EventHandlerWithFe
15
15
  error: string;
16
16
  ok?: undefined;
17
17
  } | {
18
- ok: boolean;
19
18
  error?: undefined;
19
+ ok: boolean;
20
20
  }>>;