@agent-native/core 0.153.10 → 0.154.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 (149) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/AGENTS.md +20 -30
  3. package/corpus/templates/analytics/actions/search-dashboard-references.ts +58 -0
  4. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +1 -1
  5. package/corpus/templates/analytics/app/lib/utils.ts +1 -1
  6. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/ViewSqlPopover.tsx +1 -1
  7. package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +2 -0
  8. package/corpus/templates/analytics/server/lib/dashboards-store.ts +366 -3
  9. package/corpus/templates/analytics/server/lib/real-data-actions.ts +3 -1
  10. package/corpus/templates/analytics/server/plugins/agent-chat.ts +6 -2
  11. package/corpus/templates/calendar/app/components/calendar/EventDialog.tsx +1 -1
  12. package/corpus/templates/calendar/app/lib/utils.ts +1 -1
  13. package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +32 -5
  14. package/corpus/templates/clips/app/components/sharing/share-ui.tsx +15 -15
  15. package/corpus/templates/clips/app/i18n/en-US.ts +3 -3
  16. package/corpus/templates/clips/app/lib/utils.ts +5 -6
  17. package/corpus/templates/clips/chrome-extension/src/offscreen.ts +43 -8
  18. package/corpus/templates/clips/desktop/src/app.tsx +26 -12
  19. package/corpus/templates/clips/desktop/src/lib/recorder.ts +23 -9
  20. package/corpus/templates/clips/desktop/src-tauri/src/native_screen/custom_capture.rs +261 -11
  21. package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +21 -3
  22. package/corpus/templates/clips/shared/mic-audio-cleanup.ts +350 -0
  23. package/corpus/templates/content/actions/resolve-content-landing.ts +162 -32
  24. package/corpus/templates/content/app/i18n-data.ts +10 -10
  25. package/corpus/templates/content/scripts/check-native-deps.mjs +181 -15
  26. package/corpus/templates/content/shared/content-landing.ts +5 -0
  27. package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +79 -7
  28. package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +14 -2
  29. package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +2 -2
  30. package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +35 -11
  31. package/corpus/templates/design/actions/get-design-system.ts +103 -3
  32. package/corpus/templates/design/actions/import-design-tokens.ts +37 -8
  33. package/corpus/templates/design/actions/import-github.ts +32 -138
  34. package/corpus/templates/design/actions/index-design-system-with-builder.ts +49 -16
  35. package/corpus/templates/design/actions/present-design-variants.ts +93 -4
  36. package/corpus/templates/design/actions/run-design-audit.ts +229 -0
  37. package/corpus/templates/design/actions/sync-design-system-with-builder.ts +64 -0
  38. package/corpus/templates/design/app/components/design/code-workbench/commands.ts +2 -2
  39. package/corpus/templates/design/app/components/design/inspector/DesignColorPicker.tsx +17 -4
  40. package/corpus/templates/design/app/components/design/inspector/GradientEditor.tsx +5 -1
  41. package/corpus/templates/design/app/components/design/inspector/ImageFillControls.tsx +5 -1
  42. package/corpus/templates/design/app/hooks/use-question-flow.ts +81 -5
  43. package/corpus/templates/design/app/i18n/en-US.ts +1 -1
  44. package/corpus/templates/design/app/i18n-data.ts +32 -1
  45. package/corpus/templates/design/app/i18n-keyboard-shortcuts.ts +10 -10
  46. package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +83 -11
  47. package/corpus/templates/design/app/pages/DesignSystems.tsx +14 -0
  48. package/corpus/templates/design/app/pages/design-editor/generation-prompt-directives.ts +22 -0
  49. package/corpus/templates/design/changelog/2026-08-13-a-screen-that-would-render-behind-an-invisible-alpine-overla.md +6 -0
  50. package/corpus/templates/design/changelog/2026-08-13-attach-a-ui-screenshot-and-the-design-is-reproduced-not-rein.md +6 -0
  51. package/corpus/templates/design/changelog/2026-08-13-linking-a-design-system-means-you-never-get-generic-directio.md +6 -0
  52. package/corpus/templates/design/changelog/2026-08-13-the-design-audit-now-reports-when-a-screen-ignores-its-linke.md +6 -0
  53. package/corpus/templates/design/changelog/2026-08-13-the-design-system-preview-now-shows-how-many-named-tokens-we.md +6 -0
  54. package/corpus/templates/design/changelog/2026-08-13-your-design-system-prompt-and-reference-screenshots-now-reac.md +6 -0
  55. package/corpus/templates/design/server/lib/builder-design-system-proxy.ts +18 -2
  56. package/corpus/templates/design/shared/design-review.ts +1 -0
  57. package/corpus/templates/design/shared/html-integrity.ts +171 -0
  58. package/corpus/templates/mail/app/lib/utils.ts +1 -1
  59. package/corpus/templates/slides/.agents/skills/design-systems/SKILL.md +10 -6
  60. package/corpus/templates/slides/actions/index-design-system-with-builder.ts +41 -3
  61. package/corpus/templates/slides/actions/patch-deck.ts +12 -3
  62. package/corpus/templates/slides/actions/sync-design-system-with-builder.ts +64 -0
  63. package/corpus/templates/slides/app/components/deck/DeckCard.tsx +1 -1
  64. package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +193 -20
  65. package/corpus/templates/slides/app/components/editor/EditorActionCluster.tsx +73 -1
  66. package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +64 -34
  67. package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +34 -41
  68. package/corpus/templates/slides/app/components/editor/ExportMenu.tsx +119 -91
  69. package/corpus/templates/slides/app/components/editor/ImageOverlay.tsx +16 -0
  70. package/corpus/templates/slides/app/components/editor/NewDeckReferenceStep.tsx +15 -0
  71. package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +158 -31
  72. package/corpus/templates/slides/app/components/editor/SlideOverflowWarning.tsx +30 -14
  73. package/corpus/templates/slides/app/components/editor/SpeakerNotesPanel.tsx +2 -2
  74. package/corpus/templates/slides/app/components/editor/canvas-interactions/slides-canvas-adapter.ts +4 -1
  75. package/corpus/templates/slides/app/components/editor/rich-text-selection.ts +14 -0
  76. package/corpus/templates/slides/app/components/editor/slide-text-targets.ts +24 -0
  77. package/corpus/templates/slides/app/context/DeckContext.tsx +19 -31
  78. package/corpus/templates/slides/app/global.css +24 -0
  79. package/corpus/templates/slides/app/hooks/use-navigation-state.ts +20 -17
  80. package/corpus/templates/slides/app/i18n/en-US.ts +19 -10
  81. package/corpus/templates/slides/app/lib/deck-filter.ts +47 -0
  82. package/corpus/templates/slides/app/lib/export-google-slides-client.ts +15 -4
  83. package/corpus/templates/slides/app/lib/export-pptx-client.ts +637 -1
  84. package/corpus/templates/slides/app/lib/image-download.ts +84 -0
  85. package/corpus/templates/slides/app/lib/utils.ts +1 -1
  86. package/corpus/templates/slides/app/pages/DeckEditor.tsx +9 -0
  87. package/corpus/templates/slides/app/pages/Index.tsx +25 -9
  88. package/corpus/templates/slides/changelog/2026-08-13-clicking-a-slide-thumbnail-now-focuses-it-so-the-slide-shortc.md +6 -0
  89. package/corpus/templates/slides/changelog/2026-08-13-duplicating-or-restoring-a-slide-now-keeps-its-transition-ani.md +6 -0
  90. package/corpus/templates/slides/changelog/2026-08-13-opening-presentation-mode-from-the-agent-now-starts-on-the-re.md +6 -0
  91. package/corpus/templates/slides/changelog/2026-08-13-slide-transitions-can-be-set-from-a-visible-control-in-the-sl.md +6 -0
  92. package/corpus/templates/slides/netlify.toml +1 -0
  93. package/corpus/templates/slides/server/lib/builder-design-system-proxy.ts +14 -2
  94. package/dist/a2a/audience.d.ts +2 -0
  95. package/dist/a2a/audience.js +23 -0
  96. package/dist/a2a/client.d.ts +4 -0
  97. package/dist/a2a/client.js +32 -14
  98. package/dist/a2a/server.d.ts +9 -4
  99. package/dist/a2a/server.js +52 -25
  100. package/dist/a2a/types.d.ts +4 -4
  101. package/dist/agent/production-agent.js +1 -1
  102. package/dist/brand-kit/types.d.ts +10 -2
  103. package/dist/cli/code.js +1 -1
  104. package/dist/cli/index.js +30 -1
  105. package/dist/cli/native-dependencies.d.ts +24 -0
  106. package/dist/cli/native-dependencies.js +264 -0
  107. package/dist/cli/plan-local.js +1 -1
  108. package/dist/cli/skills-content/design-visual-edit-skill.d.ts +1 -1
  109. package/dist/cli/skills-content/design-visual-edit-skill.js +2 -2
  110. package/dist/cli/visualize-repo.js +1 -1
  111. package/dist/client/FeedbackButton.js +12 -12
  112. package/dist/client/agent-chat-adapter.js +3 -4
  113. package/dist/client/assistant-ui-recovery.d.ts +1 -1
  114. package/dist/client/assistant-ui-recovery.js +4 -0
  115. package/dist/client/chat/message-components.d.ts +11 -3
  116. package/dist/client/chat/message-components.js +31 -5
  117. package/dist/client/chat/tool-call-display.d.ts +2 -1
  118. package/dist/client/chat/tool-call-display.js +33 -15
  119. package/dist/client/db-admin/SqlEditor.js +1 -1
  120. package/dist/client/dev-overlay/DevOverlay.js +2 -2
  121. package/dist/client/extensions/portable-extension.js +4 -0
  122. package/dist/client/guided-questions.d.ts +8 -0
  123. package/dist/client/guided-questions.js +12 -3
  124. package/dist/client/sharing/ShareButton.js +16 -24
  125. package/dist/client/sse-event-processor.js +35 -15
  126. package/dist/client/tool-display.d.ts +9 -0
  127. package/dist/client/tool-display.js +39 -0
  128. package/dist/client/vite-dev-recovery-script.js +1 -1
  129. package/dist/collab/awareness.d.ts +2 -2
  130. package/dist/collab/routes.d.ts +1 -1
  131. package/dist/collab/struct-routes.d.ts +1 -1
  132. package/dist/extensions/html-shell.js +5 -0
  133. package/dist/notifications/routes.d.ts +1 -1
  134. package/dist/observability/routes.d.ts +3 -3
  135. package/dist/provider-api/actions/custom-provider-registration.d.ts +2 -2
  136. package/dist/server/agent-capabilities.js +0 -0
  137. package/dist/server/agent-chat/action-filters-a2a.d.ts +14 -13
  138. package/dist/server/agent-chat/action-filters-a2a.js +59 -23
  139. package/dist/server/agent-chat/prompt-resources.js +17 -16
  140. package/dist/server/agent-chat-plugin.d.ts +9 -0
  141. package/dist/server/agent-chat-plugin.js +29 -7
  142. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  143. package/dist/server/builder-design-systems.d.ts +33 -1
  144. package/dist/server/builder-design-systems.js +293 -11
  145. package/dist/server/design-token-utils.d.ts +11 -0
  146. package/dist/server/design-token-utils.js +68 -16
  147. package/dist/server/index.d.ts +1 -1
  148. package/dist/server/index.js +1 -1
  149. package/package.json +2 -2
@@ -13,6 +13,10 @@ export function assistantUiRecoverableRenderErrorKind(error) {
13
13
  if (/^Tried to unmount a fiber that is already unmounted\b/.test(message)) {
14
14
  return "assistant-ui-react-fiber-unmount";
15
15
  }
16
+ // guard:allow-raw-color — #185 is a React diagnostic code, not a UI color.
17
+ if (/Maximum update depth exceeded|Minified React error #185/.test(message)) {
18
+ return "assistant-ui-react-update-depth";
19
+ }
16
20
  return null;
17
21
  }
18
22
  export function isAssistantUiStaleIndexError(error) {
@@ -57,6 +57,10 @@ export declare function resolveAssistantRequestId(message: unknown, activeRun: {
57
57
  runId: string;
58
58
  } | null, threadId: string): string | undefined;
59
59
  export declare function MessageBranchPicker(): React.JSX.Element;
60
+ export declare function ChatImageAttachmentPreview({ src, alt, }: {
61
+ src: string;
62
+ alt: string;
63
+ }): React.JSX.Element;
60
64
  export declare function MessageActionsMenu({ showRevert, onRevert, threadId, }?: {
61
65
  showRevert?: boolean;
62
66
  onRevert?: () => void;
@@ -68,13 +72,14 @@ export declare function isMissingFinalResponseWarningText(text: string): boolean
68
72
  export declare function latestUserMessageText(messages: readonly unknown[]): string;
69
73
  export declare function userMessageTextBeforeAssistant(messages: readonly unknown[], assistantMessageId: string): string;
70
74
  export declare function assistantMessageHasUnresolvedTool(content: unknown): boolean;
75
+ export declare function assistantMessageHasActiveTool(content: unknown): boolean;
71
76
  export declare function assistantMessageHasCompletedCustomUi(content: unknown): boolean;
72
77
  export declare function assistantMessageHasCustomUi(content: unknown): boolean;
73
78
  export declare function computeActiveTailToolCallId(content: ContentPart[] | undefined, { chatRunning, isLast }: {
74
79
  chatRunning: boolean;
75
80
  isLast: boolean;
76
81
  }): string | null;
77
- export declare function shouldShowAssistantMessageFooter({ isLast, chatRunning, activeRunId, messageRunId, activeTurnId, messageTurnId, hasRenderableContent, statusIsTerminal, hasUnresolvedTool, }: {
82
+ export declare function shouldShowAssistantMessageFooter({ isLast, chatRunning, activeRunId, messageRunId, activeTurnId, messageTurnId, hasRenderableContent, statusIsTerminal, hasUnresolvedTool, hasActiveTool, }: {
78
83
  isLast: boolean;
79
84
  chatRunning: boolean;
80
85
  activeRunId?: string | null;
@@ -84,6 +89,7 @@ export declare function shouldShowAssistantMessageFooter({ isLast, chatRunning,
84
89
  hasRenderableContent: boolean;
85
90
  statusIsTerminal: boolean;
86
91
  hasUnresolvedTool?: boolean;
92
+ hasActiveTool?: boolean;
87
93
  }): boolean;
88
94
  /**
89
95
  * Server-authoritative "a run for this thread is still active and running".
@@ -93,21 +99,23 @@ export declare function shouldShowAssistantMessageFooter({ isLast, chatRunning,
93
99
  */
94
100
  export declare const ServerRunActiveContext: React.Context<boolean>;
95
101
  export declare const UserStoppedRunContext: React.Context<(runId?: string) => boolean>;
96
- export declare function shouldShowMissingFinalResponse({ isCurrentTurnRunning, serverRunActive, statusIsTerminal, hasAssistantText, hasUnresolvedTool, hasCompletedCustomUi, userStoppedRun, }: {
102
+ export declare function shouldShowMissingFinalResponse({ isCurrentTurnRunning, serverRunActive, statusIsTerminal, hasAssistantText, hasUnresolvedTool, hasCompletedCustomUi, hasActiveTool, userStoppedRun, }: {
97
103
  isCurrentTurnRunning: boolean;
98
104
  serverRunActive?: boolean;
99
105
  statusIsTerminal: boolean;
100
106
  hasAssistantText: boolean;
101
107
  hasUnresolvedTool: boolean;
102
108
  hasCompletedCustomUi?: boolean;
109
+ hasActiveTool?: boolean;
103
110
  userStoppedRun?: boolean;
104
111
  }): boolean;
105
112
  export declare function useSettledFlag(active: boolean, delayMs: number): boolean;
106
- export declare function shouldShowAssistantWorkSummary({ isLast, isComplete, hasCollapsibleWork, hasUnresolvedTool, chatRunning, }: {
113
+ export declare function shouldShowAssistantWorkSummary({ isLast, isComplete, hasCollapsibleWork, hasUnresolvedTool, hasActiveTool, chatRunning, }: {
107
114
  isLast: boolean;
108
115
  isComplete: boolean;
109
116
  hasCollapsibleWork: boolean;
110
117
  hasUnresolvedTool: boolean;
118
+ hasActiveTool?: boolean;
111
119
  chatRunning: boolean;
112
120
  }): boolean;
113
121
  export declare function getAssistantWorkSummaryDurationMs(durationMs: number | null | undefined, groupStartIndex: number, firstWorkPartIndex: number): number | null | undefined;
@@ -11,11 +11,12 @@ import React, { useState, useEffect, useCallback, useRef } from "react";
11
11
  import { getActiveRun } from "../active-run-state.js";
12
12
  import { agentNativePath } from "../api-path.js";
13
13
  import { writeClipboardText } from "../clipboard.js";
14
+ import { Dialog, DialogClose, DialogContent, DialogTitle, } from "../components/ui/dialog.js";
14
15
  import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from "../components/ui/dropdown-menu.js";
15
16
  import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from "../components/ui/tooltip.js";
16
17
  import { ThumbsFeedback } from "../observability/ThumbsFeedback.js";
17
18
  import { McpConnectionSuggestion } from "../resources/McpConnectionSuggestion.js";
18
- import { isCallAgentToolCallShadowed, shadowedCallAgentToolCallIds, } from "../tool-display.js";
19
+ import { isCallAgentToolCallShadowed, isToolCallActive, shadowedCallAgentToolCallIds, } from "../tool-display.js";
19
20
  import { cn } from "../utils.js";
20
21
  import { MarkdownText, renderMarkdownToClipboardHtml, SmoothMarkdownText, } from "./markdown-renderer.js";
21
22
  import { getAssistantRunDurationMs } from "./repo-helpers.js";
@@ -292,11 +293,18 @@ function UserMessageAttachments() {
292
293
  !!p.image);
293
294
  const imageSrc = uploadUrl || imagePart?.image || null;
294
295
  if (imageSrc) {
295
- return (_jsx("div", { className: "h-16 w-16 overflow-hidden rounded-lg border border-border/70 bg-muted/50", title: att.name, children: _jsx("img", { src: imageSrc, alt: att.name, className: "h-full w-full object-cover" }) }, att.id));
296
+ return (_jsx(ChatImageAttachmentPreview, { src: imageSrc, alt: att.name }, att.id));
296
297
  }
297
298
  return (_jsxs("div", { className: "flex items-center gap-1.5 rounded-lg border border-border/70 bg-muted/50 px-2 py-1.5 text-xs text-muted-foreground", title: att.name, children: [_jsx(IconFile, { className: "h-3.5 w-3.5 shrink-0" }), _jsx("span", { className: "truncate max-w-[120px]", children: att.name || "file" })] }, att.id));
298
299
  }) }));
299
300
  }
301
+ export function ChatImageAttachmentPreview({ src, alt, }) {
302
+ const [open, setOpen] = useState(false);
303
+ return (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", "aria-label": `Preview ${alt}`, title: alt, onClick: () => setOpen(true), className: "h-16 w-16 cursor-zoom-in overflow-hidden rounded-lg border border-border/70 bg-muted/50 p-0 transition-[border-color,box-shadow] hover:border-foreground/40 hover:shadow-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2", children: _jsx("img", { src: src, alt: alt, className: "h-full w-full object-cover" }) }), _jsx(Dialog, { open: open, onOpenChange: setOpen, children: _jsxs(DialogContent, { hideClose: true, "aria-describedby": undefined, className: "fixed inset-0 left-0 top-0 flex h-screen max-h-none w-screen max-w-none translate-x-0 translate-y-0 items-center justify-center gap-0 overflow-hidden rounded-none border-0 bg-foreground/90 p-0 text-background shadow-none backdrop-blur-sm dark:bg-background/95 dark:text-foreground", onOpenAutoFocus: (event) => event.preventDefault(), children: [_jsx(DialogTitle, { className: "sr-only", children: alt || "Image preview" }), _jsx("div", { className: "flex h-full w-full items-center justify-center overflow-auto p-6", onClick: (event) => {
304
+ if (event.target === event.currentTarget)
305
+ setOpen(false);
306
+ }, children: _jsx("img", { src: src, alt: alt, draggable: false, className: "max-h-[90vh] max-w-[92vw] rounded-lg object-contain shadow-2xl" }) }), _jsx(DialogClose, { asChild: true, children: _jsx("button", { type: "button", "aria-label": "Close image preview", className: "absolute end-4 top-4 inline-flex size-9 items-center justify-center rounded-full border border-background/25 bg-background/10 text-background transition-colors hover:bg-background/20 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring dark:border-foreground/25 dark:bg-foreground/10 dark:text-foreground dark:hover:bg-foreground/20", children: _jsx(IconX, { className: "size-4" }) }) })] }) })] }));
307
+ }
300
308
  // ─── UserMessageEditComposer ──────────────────────────────────────────────────
301
309
  function UserMessageEditComposer() {
302
310
  return (_jsxs(ComposerPrimitive.Root, { className: "flex flex-col gap-2 rounded-lg border border-border bg-background px-3 py-2 shadow-sm", children: [_jsx(ComposerPrimitive.Input, { className: "w-full resize-none bg-transparent text-sm leading-relaxed text-foreground placeholder:text-muted-foreground focus:outline-none", rows: 1, submitMode: "enter" }), _jsxs("div", { className: "flex justify-end gap-2", children: [_jsx(ComposerPrimitive.Cancel, { asChild: true, children: _jsx("button", { type: "button", className: "cursor-pointer rounded-md px-2 py-1 text-xs font-medium text-muted-foreground hover:bg-accent hover:text-foreground", children: "Cancel" }) }), _jsx(ComposerPrimitive.Send, { asChild: true, children: _jsx("button", { type: "submit", className: "cursor-pointer rounded-md bg-foreground px-2 py-1 text-xs font-medium text-background hover:opacity-90 disabled:opacity-50", children: "Save" }) })] })] }));
@@ -545,6 +553,15 @@ export function assistantMessageHasUnresolvedTool(content) {
545
553
  return record.type === "tool-call" && record.result === undefined;
546
554
  });
547
555
  }
556
+ export function assistantMessageHasActiveTool(content) {
557
+ if (!Array.isArray(content))
558
+ return false;
559
+ return content.some((part) => {
560
+ if (!part || typeof part !== "object")
561
+ return false;
562
+ return isToolCallActive(part);
563
+ });
564
+ }
548
565
  export function assistantMessageHasCompletedCustomUi(content) {
549
566
  if (!Array.isArray(content))
550
567
  return false;
@@ -606,7 +623,7 @@ export function computeActiveTailToolCallId(content, { chatRunning, isLast }) {
606
623
  ? part.toolCallId
607
624
  : latestToolCallId, null) ?? null);
608
625
  }
609
- export function shouldShowAssistantMessageFooter({ isLast, chatRunning, activeRunId, messageRunId, activeTurnId, messageTurnId, hasRenderableContent, statusIsTerminal, hasUnresolvedTool, }) {
626
+ export function shouldShowAssistantMessageFooter({ isLast, chatRunning, activeRunId, messageRunId, activeTurnId, messageTurnId, hasRenderableContent, statusIsTerminal, hasUnresolvedTool, hasActiveTool, }) {
610
627
  if (!hasRenderableContent)
611
628
  return false;
612
629
  const ownsActiveTurn = activeTurnId != null &&
@@ -622,6 +639,8 @@ export function shouldShowAssistantMessageFooter({ isLast, chatRunning, activeRu
622
639
  const ownsActiveRun = isLast || ownsActiveTurn || ownsLegacyRun;
623
640
  if (chatRunning && ownsActiveRun)
624
641
  return false;
642
+ if (hasActiveTool)
643
+ return false;
625
644
  if (!isLast)
626
645
  return true;
627
646
  if (hasUnresolvedTool)
@@ -636,7 +655,7 @@ export function shouldShowAssistantMessageFooter({ isLast, chatRunning, activeRu
636
655
  */
637
656
  export const ServerRunActiveContext = React.createContext(false);
638
657
  export const UserStoppedRunContext = React.createContext(() => false);
639
- export function shouldShowMissingFinalResponse({ isCurrentTurnRunning, serverRunActive, statusIsTerminal, hasAssistantText, hasUnresolvedTool, hasCompletedCustomUi, userStoppedRun, }) {
658
+ export function shouldShowMissingFinalResponse({ isCurrentTurnRunning, serverRunActive, statusIsTerminal, hasAssistantText, hasUnresolvedTool, hasCompletedCustomUi, hasActiveTool, userStoppedRun, }) {
640
659
  if (userStoppedRun)
641
660
  return false;
642
661
  if (serverRunActive)
@@ -647,6 +666,7 @@ export function shouldShowMissingFinalResponse({ isCurrentTurnRunning, serverRun
647
666
  statusIsTerminal &&
648
667
  !hasAssistantText &&
649
668
  !hasUnresolvedTool &&
669
+ !hasActiveTool &&
650
670
  !hasCompletedCustomUi);
651
671
  }
652
672
  /**
@@ -668,9 +688,11 @@ export function useSettledFlag(active, delayMs) {
668
688
  }, [active, delayMs]);
669
689
  return active && (delayMs <= 0 || settled);
670
690
  }
671
- export function shouldShowAssistantWorkSummary({ isLast, isComplete, hasCollapsibleWork, hasUnresolvedTool, chatRunning, }) {
691
+ export function shouldShowAssistantWorkSummary({ isLast, isComplete, hasCollapsibleWork, hasUnresolvedTool, hasActiveTool, chatRunning, }) {
672
692
  if (!hasCollapsibleWork)
673
693
  return false;
694
+ if (hasActiveTool)
695
+ return false;
674
696
  // An unresolved tool means "still working" only while the turn is actually
675
697
  // running. On a stalled or interrupted turn it used to hide the summary
676
698
  // forever, so the longest turns showed no "Worked for Xm Ys" at all.
@@ -798,6 +820,7 @@ export function AssistantMessage() {
798
820
  const isUserStoppedRun = assistantMessageWasUserStopped(msg) || userStoppedRun(messageRunId);
799
821
  const hasRenderableContent = assistantMessageHasRenderableContent(msg);
800
822
  const hasUnresolvedTool = assistantMessageHasUnresolvedTool(msg.content);
823
+ const hasActiveTool = assistantMessageHasActiveTool(msg.content);
801
824
  const missingWarningText = missingFinalResponseWarningText(msg.content);
802
825
  const responseConnectionText = finalResponseTextFromContent(msg.content);
803
826
  const statusIsTerminal = assistantMessageStatusIsTerminal(msg);
@@ -818,6 +841,7 @@ export function AssistantMessage() {
818
841
  statusIsTerminal,
819
842
  hasAssistantText: responseConnectionText.trim().length > 0,
820
843
  hasUnresolvedTool,
844
+ hasActiveTool,
821
845
  hasCompletedCustomUi,
822
846
  userStoppedRun: isUserStoppedRun,
823
847
  });
@@ -876,6 +900,7 @@ export function AssistantMessage() {
876
900
  hasRenderableContent,
877
901
  statusIsTerminal,
878
902
  hasUnresolvedTool,
903
+ hasActiveTool,
879
904
  });
880
905
  const cpCtx = React.useContext(CheckpointContext);
881
906
  useEffect(() => {
@@ -995,6 +1020,7 @@ export function AssistantMessage() {
995
1020
  isComplete,
996
1021
  hasCollapsibleWork,
997
1022
  hasUnresolvedTool,
1023
+ hasActiveTool,
998
1024
  chatRunning,
999
1025
  });
1000
1026
  if (!showSummary)
@@ -78,7 +78,7 @@ export declare function AnimatedCollapse({ open, children, }: {
78
78
  open: boolean;
79
79
  children: React.ReactNode;
80
80
  }): React.JSX.Element | null;
81
- export declare function ToolCallDisplay({ toolName, toolCallId, argsText, args, result, mcpApp, chatUI, isRunning, outcome, structuredMeta, approval, repeatCount, isLatestRunning, isActiveTail, }: {
81
+ export declare function ToolCallDisplay({ toolName, toolCallId, argsText, args, result, mcpApp, chatUI, isRunning, outcome, structuredMeta, activity, approval, repeatCount, isLatestRunning, isActiveTail, }: {
82
82
  toolName: string;
83
83
  toolCallId?: string;
84
84
  argsText?: string;
@@ -90,6 +90,7 @@ export declare function ToolCallDisplay({ toolName, toolCallId, argsText, args,
90
90
  /** "unknown": the stream ended mid-flight, so the side effect may have landed. */
91
91
  outcome?: "unknown";
92
92
  structuredMeta?: Record<string, unknown>;
93
+ activity?: boolean;
93
94
  approval?: {
94
95
  approvalKey: string;
95
96
  dismissed?: boolean;
@@ -11,7 +11,7 @@ import { McpAppRenderer } from "../mcp-apps/McpAppRenderer.js";
11
11
  import { findMcpIntegrationForToolName } from "../resources/mcp-integration-catalog.js";
12
12
  import { McpIntegrationLogo } from "../resources/McpIntegrationLogo.js";
13
13
  import { BashCell, EditCell, WriteCell, FilesChangedSummary, } from "../tool-cells/index.js";
14
- import { humanizeToolName, isCallAgentToolCallShadowed, } from "../tool-display.js";
14
+ import { humanizeToolName, isCallAgentToolCallShadowed, isToolCallActive, } from "../tool-display.js";
15
15
  import { cn } from "../utils.js";
16
16
  import { ActionChatUiSurface } from "./action-chat-ui-surface.js";
17
17
  import { SmoothMarkdownText, HighlightedCodeBlock, } from "./markdown-renderer.js";
@@ -273,23 +273,34 @@ function ApprovalAffordance({ toolName, toolCallId, approval, }) {
273
273
  }, className: cn("inline-flex items-center gap-1 rounded-md border border-border px-2.5 py-1 text-xs font-medium transition-colors", "text-foreground hover:bg-muted"), children: [_jsx(IconX, { className: "h-3.5 w-3.5" }), "Deny"] })] }));
274
274
  }
275
275
  // ─── ToolCallDisplay ──────────────────────────────────────────────────────────
276
- export function ToolCallDisplay({ toolName, toolCallId, argsText, args, result, mcpApp, chatUI, isRunning, outcome, structuredMeta, approval, repeatCount, isLatestRunning = isRunning, isActiveTail, }) {
276
+ export function ToolCallDisplay({ toolName, toolCallId, argsText, args, result, mcpApp, chatUI, isRunning, outcome, structuredMeta, activity, approval, repeatCount, isLatestRunning = isRunning, isActiveTail, }) {
277
+ const isDelegatedAgentCall = toolName === "call-agent" || toolName.startsWith("agent:");
278
+ const effectiveIsRunning = isRunning ||
279
+ (isDelegatedAgentCall &&
280
+ isToolCallActive({
281
+ type: "tool-call",
282
+ toolName,
283
+ result,
284
+ outcome,
285
+ activity,
286
+ structuredMeta,
287
+ }));
277
288
  const showActiveTail = isActiveTail ?? isLatestRunning;
278
289
  // Delegate to bespoke cells when structured metadata is present.
279
290
  // These must be separate components so hook order in ToolCallDisplayGeneric
280
291
  // is always stable (no conditional hook calls).
281
292
  const toolKind = structuredMeta?.toolKind;
282
- const wrapToolDisplay = (children) => (_jsx(ToolActivityPresentation, { toolName: toolName, isRunning: isRunning, toolCallId: toolCallId, suppressLongRunningHint: toolName === "call-agent" || toolName.startsWith("agent:"), children: children }));
293
+ const wrapToolDisplay = (children) => (_jsx(ToolActivityPresentation, { toolName: toolName, isRunning: effectiveIsRunning, toolCallId: toolCallId, suppressLongRunningHint: toolName === "call-agent" || toolName.startsWith("agent:"), children: children }));
283
294
  if (toolKind === "bash") {
284
- return wrapToolDisplay(_jsx(BashCell, { meta: structuredMeta, output: result, isRunning: isRunning }));
295
+ return wrapToolDisplay(_jsx(BashCell, { meta: structuredMeta, output: result, isRunning: effectiveIsRunning }));
285
296
  }
286
297
  if (toolKind === "edit") {
287
- return wrapToolDisplay(_jsx(EditCell, { meta: structuredMeta, isRunning: isRunning }));
298
+ return wrapToolDisplay(_jsx(EditCell, { meta: structuredMeta, isRunning: effectiveIsRunning }));
288
299
  }
289
300
  if (toolKind === "write") {
290
- return wrapToolDisplay(_jsx(WriteCell, { meta: structuredMeta, isRunning: isRunning }));
301
+ return wrapToolDisplay(_jsx(WriteCell, { meta: structuredMeta, isRunning: effectiveIsRunning }));
291
302
  }
292
- return wrapToolDisplay(_jsx(ToolCallDisplayGeneric, { toolName: toolName, toolCallId: toolCallId, argsText: argsText, args: args, result: result, mcpApp: mcpApp, chatUI: chatUI, isRunning: isRunning, outcome: outcome, isActiveTail: showActiveTail, structuredMeta: structuredMeta, approval: approval, repeatCount: repeatCount }));
303
+ return wrapToolDisplay(_jsx(ToolCallDisplayGeneric, { toolName: toolName, toolCallId: toolCallId, argsText: argsText, args: args, result: result, mcpApp: mcpApp, chatUI: chatUI, isRunning: effectiveIsRunning, outcome: outcome, isActiveTail: showActiveTail, structuredMeta: structuredMeta, approval: approval, repeatCount: repeatCount }));
293
304
  }
294
305
  function ToolCallDisplayGeneric({ toolName, toolCallId, argsText, args, result, mcpApp, chatUI, isRunning, outcome, isActiveTail, structuredMeta, approval, repeatCount, }) {
295
306
  const suppressInlineOpenApp = React.useContext(SuppressInlineOpenAppContext);
@@ -460,17 +471,24 @@ function AgentActivityToolCallRow({ tool, isActiveTail, }) {
460
471
  // ─── ToolCallFallback ──────────────────────────────────────────────────────────
461
472
  export function ToolCallFallback({ toolName, toolCallId, args, argsText, result, ...rest }) {
462
473
  const chatRunning = React.useContext(ChatRunningContext);
463
- // A spinner is a claim that something is running right now, so it needs an
464
- // actually-running chat. `chatRunning` already stays true across
465
- // auto-continuation gaps and server-active runs (resolveAssistantChatRunningState),
466
- // so an activity placeholder alone must never resurrect one on rehydrated
467
- // history.
468
- const isRunning = result === undefined && chatRunning;
474
+ // `chatRunning` covers ordinary live activity. An unresolved tool or a
475
+ // delegated-agent row is also explicit work evidence, while a generic
476
+ // activity placeholder alone must stay frozen when history is rehydrated.
477
+ const isRunning = rest.outcome !== "unknown" &&
478
+ ((result === undefined && chatRunning) ||
479
+ isToolCallActive({
480
+ type: "tool-call",
481
+ toolName,
482
+ result,
483
+ outcome: rest.outcome,
484
+ activity: rest.activity,
485
+ structuredMeta: rest.structuredMeta,
486
+ }));
469
487
  return (_jsx(ToolCallDisplay, { toolName: toolName, toolCallId: toolCallId, args: args, argsText: argsText, result: typeof result === "string"
470
488
  ? result
471
489
  : result !== undefined
472
490
  ? JSON.stringify(result)
473
- : undefined, mcpApp: rest.mcpApp, chatUI: rest.chatUI, structuredMeta: rest.structuredMeta, isRunning: isRunning, outcome: rest.outcome, isActiveTail: rest.isActiveTail, isLatestRunning: rest.isLatestRunning, approval: rest.approval, repeatCount: rest.repeatCount }));
491
+ : undefined, mcpApp: rest.mcpApp, chatUI: rest.chatUI, structuredMeta: rest.structuredMeta, activity: rest.activity, isRunning: isRunning, outcome: rest.outcome, isActiveTail: rest.isActiveTail, isLatestRunning: rest.isLatestRunning, approval: rest.approval, repeatCount: rest.repeatCount }));
474
492
  }
475
493
  // ─── ReconnectStreamMessage ────────────────────────────────────────────────────
476
494
  // Renders the agent's in-progress response during reconnection (outside
@@ -496,7 +514,7 @@ export function ReconnectStreamMessage({ content, allowActivitySpinner = true, }
496
514
  if (part.type === "reasoning") {
497
515
  return (_jsx(ReasoningCell, { text: part.text, isStreaming: chatRunning && i === streamingReasoningPartIndex, resetKey: `reconnect-reasoning-${i}`, defaultOpen: i === latestReasoningPartIndex, collapseWhenReplaced: i < latestReasoningPartIndex }, `reconnect-reasoning-${i}`));
498
516
  }
499
- return (_jsx(ToolCallDisplay, { toolName: part.toolName, toolCallId: part.toolCallId, argsText: part.argsText, args: part.args, result: part.result, mcpApp: part.mcpApp, chatUI: part.chatUI, structuredMeta: part.structuredMeta, outcome: part.outcome, isRunning: part.result === undefined &&
517
+ return (_jsx(ToolCallDisplay, { toolName: part.toolName, toolCallId: part.toolCallId, argsText: part.argsText, args: part.args, result: part.result, mcpApp: part.mcpApp, chatUI: part.chatUI, structuredMeta: part.structuredMeta, activity: part.activity, outcome: part.outcome, isRunning: part.result === undefined &&
500
518
  (chatRunning || (allowActivitySpinner && part.activity === true)), isActiveTail: i === latestActiveToolIndex, approval: part.approval, repeatCount: part.repeatCount }, `reconnect-tool-${i}`));
501
519
  };
502
520
  const renderedParts = [];
@@ -343,7 +343,7 @@ export function SqlEditor({ dialect, tableNames, columnsByTable, requestConfig,
343
343
  const hasResults = result !== null;
344
344
  const canExport = hasResults && result.columns.length > 0;
345
345
  // ─── Render ──────────────────────────────────────────────────────────────
346
- return (_jsxs("div", { className: "flex h-full flex-col", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2 border-b border-border bg-background px-3 py-2", children: [_jsxs("button", { type: "button", onClick: runActiveStatement, disabled: running || !value.trim(), title: `Run selection / statement (${MOD}+Enter)`, className: "inline-flex h-8 cursor-pointer items-center gap-1.5 rounded-md bg-primary px-3 text-xs font-semibold text-primary-foreground transition-colors hover:bg-primary/90 disabled:cursor-not-allowed disabled:opacity-50", children: [running ? (_jsx(IconLoader2, { size: 14, className: "animate-spin" })) : (_jsx(IconPlayerPlayFilled, { size: 14 })), "Run"] }), _jsxs("span", { className: "hidden text-[11px] text-muted-foreground sm:inline", children: [MOD, "+Enter runs selection / statement \u00B7 ", MOD, "+Shift+Enter runs all"] }), _jsxs("div", { className: "ml-auto flex items-center gap-2", children: [_jsxs(Popover, { children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs(ToolbarButton, { title: "Query history", children: [_jsx(IconHistory, { size: 14 }), "History"] }) }), _jsxs(PopoverContent, { align: "end", className: "w-96 p-0", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-border px-3 py-2", children: [_jsx("span", { className: "text-xs font-semibold text-foreground", children: "Recent queries" }), history.length > 0 && (_jsx("button", { type: "button", onClick: () => {
346
+ return (_jsxs("div", { className: "flex h-full flex-col", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2 border-b border-border bg-background px-3 py-2", children: [_jsxs("button", { type: "button", onClick: runActiveStatement, disabled: running || !value.trim(), title: `Run selection / statement (${MOD} Enter)`, className: "inline-flex h-8 cursor-pointer items-center gap-1.5 rounded-md bg-primary px-3 text-xs font-semibold text-primary-foreground transition-colors hover:bg-primary/90 disabled:cursor-not-allowed disabled:opacity-50", children: [running ? (_jsx(IconLoader2, { size: 14, className: "animate-spin" })) : (_jsx(IconPlayerPlayFilled, { size: 14 })), "Run"] }), _jsxs("span", { className: "hidden text-[11px] text-muted-foreground sm:inline", children: [MOD, " Enter runs selection / statement \u00B7 ", MOD, " Shift Enter runs all"] }), _jsxs("div", { className: "ml-auto flex items-center gap-2", children: [_jsxs(Popover, { children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs(ToolbarButton, { title: "Query history", children: [_jsx(IconHistory, { size: 14 }), "History"] }) }), _jsxs(PopoverContent, { align: "end", className: "w-96 p-0", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-border px-3 py-2", children: [_jsx("span", { className: "text-xs font-semibold text-foreground", children: "Recent queries" }), history.length > 0 && (_jsx("button", { type: "button", onClick: () => {
347
347
  clearHistory();
348
348
  setHistory([]);
349
349
  }, className: "cursor-pointer text-[11px] text-muted-foreground hover:text-foreground", children: "Clear" }))] }), _jsx("div", { className: "max-h-80 overflow-auto py-1", children: history.length === 0 ? (_jsx("div", { className: "px-3 py-6 text-center text-xs text-muted-foreground", children: "No queries yet" })) : (history.map((h, i) => (_jsx("button", { type: "button", onClick: () => loadIntoEditor(h), className: "block w-full cursor-pointer truncate px-3 py-1.5 text-left font-mono text-[11px] text-foreground hover:bg-accent", title: h, children: h.replace(/\s+/g, " ").trim() }, i)))) })] })] }), _jsxs(Popover, { children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs(ToolbarButton, { title: "Saved snippets", children: [_jsx(IconBookmark, { size: 14 }), "Snippets"] }) }), _jsxs(PopoverContent, { align: "end", className: "w-96 p-0", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-border px-3 py-2", children: [_jsx("span", { className: "text-xs font-semibold text-foreground", children: "Saved snippets" }), _jsxs("button", { type: "button", onClick: openSaveModal, disabled: !value.trim(), className: "inline-flex cursor-pointer items-center gap-1 text-[11px] text-muted-foreground hover:text-foreground disabled:cursor-not-allowed disabled:opacity-50", children: [_jsx(IconBookmarkPlus, { size: 13 }), "Save current"] })] }), _jsx("div", { className: "max-h-80 overflow-auto py-1", children: snippets.length === 0 ? (_jsx("div", { className: "px-3 py-6 text-center text-xs text-muted-foreground", children: "No saved snippets" })) : (snippets.map((s) => (_jsxs("div", { className: "group flex items-center gap-2 px-3 py-1.5 hover:bg-accent", children: [_jsxs("button", { type: "button", onClick: () => loadIntoEditor(s.sql), className: "min-w-0 flex-1 cursor-pointer text-left", title: s.sql, children: [_jsx("div", { className: "truncate text-xs font-medium text-foreground", children: s.name }), _jsx("div", { className: "truncate font-mono text-[10px] text-muted-foreground", children: s.sql.replace(/\s+/g, " ").trim() })] }), _jsx("button", { type: "button", onClick: () => removeSnippet(s.id), className: "cursor-pointer rounded p-1 text-muted-foreground opacity-0 transition-opacity hover:text-red-500 group-hover:opacity-100", title: "Delete snippet", children: _jsx(IconTrash, { size: 13 }) })] }, s.id)))) })] })] }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsxs(ToolbarButton, { title: "Export results", disabled: !canExport, children: [_jsx(IconDownload, { size: 14 }), "Export", _jsx(IconChevronDown, { size: 12, className: "opacity-60" })] }) }), _jsxs(DropdownMenuContent, { align: "end", children: [_jsx(DropdownMenuItem, { onClick: () => exportAs("csv"), children: "Download CSV" }), _jsx(DropdownMenuItem, { onClick: () => exportAs("json"), children: "Download JSON" })] })] })] })] }), _jsx("div", { className: "shrink-0 overflow-hidden border-b border-border", style: { height: editorHeight }, children: _jsx(CodeMirror, { ref: editorRef, value: value, onChange: setValue, height: `${editorHeight}px`, theme: isDark ? oneDark : undefined, extensions: extensions, placeholder: "Write SQL here\u2026", basicSetup: {
@@ -57,8 +57,8 @@ function DevOverlayPanel({ onClose }) {
57
57
  const panels = useSyncExternalStore(subscribeDevPanels, listDevPanels, listDevPanels);
58
58
  const shortcutHint = typeof navigator !== "undefined" &&
59
59
  /Mac|iPhone|iPad/.test(navigator.userAgent)
60
- ? "Cmd+Ctrl+A"
61
- : "Ctrl+Alt+A";
60
+ ? "Cmd Ctrl A"
61
+ : "Ctrl Alt A";
62
62
  return (_jsx(TooltipProvider, { delayDuration: 200, children: _jsxs("div", { style: styles.shell, role: "dialog", "aria-label": "Dev overlay", children: [_jsxs("div", { style: styles.header, children: [_jsxs("div", { children: [_jsx("div", { style: styles.headerTitle, children: "Dev Overlay" }), _jsxs("div", { style: styles.headerSub, children: [shortcutHint, " \u00B7 localStorage-backed"] })] }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", style: styles.iconBtn, onClick: onClose, "aria-label": "Close", children: _jsx(IconX, { size: 16 }) }) }), _jsx(TooltipContent, { children: "Close (Esc)" })] })] }), _jsx("div", { style: styles.body, children: panels.length === 0 ? (_jsxs("div", { style: styles.empty, children: ["No panels registered. Call ", _jsx("code", { children: "registerDevPanel(...)" }), " from your template to add options here."] })) : (panels.map((panel) => _jsx(DevPanelCard, { panel: panel }, panel.id))) }), _jsx("div", { style: styles.footer, children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("button", { type: "button", style: { ...styles.footerBtn, ...styles.footerBtnDanger }, onClick: () => {
63
63
  clearAllDevOverlayStorage();
64
64
  }, children: [_jsx(IconTrash, { size: 13 }), "Clear all dev-overlay values"] }) }), _jsx(TooltipContent, { children: "Reset every dev-overlay value back to its default" })] }) })] }) }));
@@ -281,6 +281,10 @@ export function buildAgentNativeExtensionHtml({ extensionId, content, title, slo
281
281
  </style>
282
282
  <style>
283
283
  *, *::before, *::after { box-sizing: border-box; border-color: hsl(var(--border, 214 32% 91%)); }
284
+ /* Alpine only honours x-cloak when a stylesheet hides it, and the exported
285
+ body snippet cannot supply one. Without this an x-cloak overlay paints
286
+ over the whole extension until Alpine boots — and forever if it never does. */
287
+ [x-cloak] { display: none !important; }
284
288
  html, body { margin: 0; min-height: 100%; background: transparent; color: hsl(var(--foreground, 222 47% 11%)); }
285
289
  body {
286
290
  --agent-native-extension-padding: clamp(12px, 2vw, 20px);
@@ -40,6 +40,14 @@ export interface GuidedQuestionPayload {
40
40
  submitLabel?: string;
41
41
  submitMessage?: string;
42
42
  skipMessage?: string;
43
+ /**
44
+ * Hidden context appended to whichever message this card sends. The card's
45
+ * answer opens a continuation turn that inherits nothing from the turn that
46
+ * posed it, so anything the follow-up work depends on — a linked design
47
+ * system, the user's original brief — has to travel with the payload or it
48
+ * is gone by the time the agent acts on the answer.
49
+ */
50
+ submitContext?: string;
43
51
  /**
44
52
  * @internal Set by {@link askUserQuestion} for client-initiated questions.
45
53
  * When present, `useGuidedQuestionFlow` resolves the matching in-memory
@@ -508,8 +508,13 @@ export function useGuidedQuestionFlow({ enabled = true, stateKey = "show-questio
508
508
  }
509
509
  const formattedAnswers = formatGuidedAnswersForAgent(answers);
510
510
  const resolvedSubmitMessage = visiblePayload?.submitMessage ?? submitMessage;
511
- const context = buildSubmitContext?.({ answers, formattedAnswers }) ??
512
- defaultGuidedSubmitContext(formattedAnswers);
511
+ const context = [
512
+ buildSubmitContext?.({ answers, formattedAnswers }) ??
513
+ defaultGuidedSubmitContext(formattedAnswers),
514
+ visiblePayload?.submitContext,
515
+ ]
516
+ .filter(Boolean)
517
+ .join("\n\n");
513
518
  sendToAgentChat({
514
519
  message: resolvedSubmitMessage,
515
520
  context,
@@ -526,7 +531,11 @@ export function useGuidedQuestionFlow({ enabled = true, stateKey = "show-questio
526
531
  }
527
532
  sendToAgentChat({
528
533
  message: visiblePayload?.skipMessage ?? skipMessage,
529
- context: buildSkipContext?.(),
534
+ // Skipping a variant set asks for another one — the replacement needs the
535
+ // same context the first set was built from.
536
+ context: [buildSkipContext?.(), visiblePayload?.submitContext]
537
+ .filter(Boolean)
538
+ .join("\n\n"),
530
539
  submit: true,
531
540
  });
532
541
  clear();
@@ -1,7 +1,6 @@
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";
3
2
  import * as Select from "@radix-ui/react-select";
4
- import { IconLock, IconWorld, IconTrash, IconCheck, IconChevronDown, IconCopy, IconLoader2, IconSearch, IconSearchOff, IconShare3, IconUsersGroup, } from "@tabler/icons-react";
3
+ import { IconLock, IconWorld, IconTrash, IconCheck, IconChevronDown, IconLoader2, IconLink, IconSearch, IconSearchOff, IconShare3, IconUsersGroup, } from "@tabler/icons-react";
5
4
  import { useEffect, useId, useRef, useState, } from "react";
6
5
  import { writeClipboardText } from "../clipboard.js";
7
6
  import { Popover, PopoverAnchor, PopoverContent, PopoverTrigger, } from "../components/ui/popover.js";
@@ -103,7 +102,7 @@ export function ShareButton(props) {
103
102
  return (_jsxs(Popover, { open: controller.open, onOpenChange: controller.handleOpenChange, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs("button", { type: "button", className: cn(iconOnly ? BUTTON_GHOST_ICON : BUTTON_OUTLINE_SM, props.triggerClassName), "aria-label": triggerLabel, title: triggerLabel, children: [showTriggerIcon && _jsx(TriggerIcon, { size: 16, strokeWidth: 1.75 }), !iconOnly && _jsx("span", { children: "Share" })] }) }), _jsx(PopoverContent, { align: "end", sideOffset: 6, "data-agent-native-share-overlay": "", className: cn("z-[2000] w-[min(460px,92vw)] rounded-lg p-4 shadow-lg", SHARE_POPOVER_SURFACE, props.popoverClassName), onOpenAutoFocus: (e) => e.preventDefault(), onInteractOutside: handleSharePopoverInteractOutside, children: _jsx(SharePanel, { ...props, controller: controller }) })] }));
104
103
  }
105
104
  function SharePanel(props) {
106
- const { resourceTitle, controller } = props;
105
+ const { controller } = props;
107
106
  const { inviteEmail, setInviteEmail: onInviteEmailChange, activeShareTab, handleShareTabChange, data, policy, visibility, canManage, role, setRole, notifyPeople, setNotifyPeople, shareMessage, setShareMessage, messageOpen, setMessageOpen, shareError, setShareError, suggestionsOpen, setSuggestionsOpen, inFlight, memberSearch, memberSuggestions, knownMembers, shares, handleVisibility, handleHideInSearch, handleAdd, handleChangeRole, handleRemove, } = controller;
108
107
  const hasInviteEmail = inviteEmail.trim().length > 0;
109
108
  const isLoading = data === undefined;
@@ -116,28 +115,21 @@ function SharePanel(props) {
116
115
  Boolean(props.shareUrlPlaceholder) ||
117
116
  Boolean(props.secondaryShareUrl));
118
117
  const shareUrlPlacement = props.shareUrlPlacement ?? "top";
119
- const [advancedOpen, setAdvancedOpen] = useState(!showShareLinks);
120
- useEffect(() => {
121
- setAdvancedOpen(!showShareLinks);
122
- }, [props.resourceId, showShareLinks]);
123
- const extraTabs = props.shareTabs?.tabs ?? [];
118
+ const extraTabs = props.shareTabs?.tabs.filter((tab) => tab.value !== "context") ?? [];
124
119
  const hasTabs = extraTabs.length > 0;
125
120
  const shareTabLabel = props.shareTabs?.shareLabel ?? "Share link";
126
- const titleText = resourceTitle
127
- ? `Share "${resourceTitle}"`
128
- : `Share ${props.resourceType}`;
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] }));
121
+ const sharePanel = isLoading ? (_jsxs("div", { children: [showShareLinks ? (_jsx("div", { className: "mb-4 h-9 rounded-md bg-muted animate-pulse" })) : null, _jsx("div", { className: "mb-2 text-sm font-semibold", children: generalAccessLabel }), _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" })] })) : (_jsxs("div", { children: [showShareLinks && shareUrlPlacement === "top" ? shareLinks : null, _jsxs("div", { className: "mb-4", children: [_jsx("div", { className: "mb-2 text-sm font-semibold", children: generalAccessLabel }), _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(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] })] })] })] }), _jsxs("div", { className: "mb-4 space-y-4", children: [_jsx("div", { className: "text-sm font-semibold", children: peopleAccessLabel }), 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) => {
122
+ onInviteEmailChange(next);
123
+ if (shareError)
124
+ setShareError(null);
125
+ }, onSelectMember: (member) => {
126
+ onInviteEmailChange(member.email);
127
+ setSuggestionsOpen(false);
128
+ if (shareError)
129
+ setShareError(null);
130
+ }, onSubmit: handleAdd, placeholder: policy.requireOrgMemberForUserShares
131
+ ? "Add people from your organization"
132
+ : "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("ul", { className: "flex list-none flex-col gap-1 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] })] }), 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] }));
141
133
  if (!hasTabs)
142
134
  return sharePanel;
143
135
  const tabs = [
@@ -280,7 +272,7 @@ function CopyLinkField({ value, label = "Share link", description, }) {
280
272
  setCopied(false);
281
273
  }
282
274
  };
283
- return (_jsxs("div", { className: "mb-4", children: [_jsx("div", { className: "mb-2 text-sm font-semibold", children: label }), description ? (_jsx("div", { className: "mb-2 text-xs text-muted-foreground", children: description })) : null, _jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [_jsx("input", { readOnly: true, value: value, className: "h-9 min-w-0 flex-1 rounded-md border border-input bg-card px-3 text-sm text-muted-foreground outline-none", onFocus: (event) => event.currentTarget.select() }), _jsxs("button", { type: "button", onClick: handleCopy, className: "inline-flex h-9 shrink-0 items-center gap-2 rounded-md border border-input bg-card px-3 text-sm font-medium text-foreground hover:bg-accent", children: [copied ? _jsx(IconCheck, { size: 15 }) : _jsx(IconCopy, { size: 15 }), copied ? "Copied" : "Copy"] })] })] }));
275
+ return (_jsxs("div", { className: "mb-4 flex items-center justify-between gap-4", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "text-sm font-semibold", children: label }), description ? (_jsx("div", { className: "mt-1 text-xs text-muted-foreground", children: description })) : null] }), _jsxs("button", { type: "button", onClick: handleCopy, "aria-label": copied ? "Link copied" : "Copy", className: "inline-flex h-9 shrink-0 items-center gap-2 whitespace-nowrap rounded-md border border-input bg-card px-3 text-sm font-medium text-foreground hover:bg-accent", children: [copied ? _jsx(IconCheck, { size: 15 }) : _jsx(IconLink, { size: 15 }), copied ? "Copied" : "Copy"] })] }));
284
276
  }
285
277
  // ---------------------------------------------------------------------------
286
278
  // Radix Select wrappers styled like shadcn Select (no native <select> anywhere)