@agent-native/core 0.153.10 → 0.154.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) 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/app/i18n-data.ts +10 -10
  24. package/corpus/templates/content/scripts/check-native-deps.mjs +181 -15
  25. package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +79 -7
  26. package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +14 -2
  27. package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +2 -2
  28. package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +35 -11
  29. package/corpus/templates/design/actions/get-design-system.ts +103 -3
  30. package/corpus/templates/design/actions/import-design-tokens.ts +37 -8
  31. package/corpus/templates/design/actions/import-github.ts +32 -138
  32. package/corpus/templates/design/actions/index-design-system-with-builder.ts +49 -16
  33. package/corpus/templates/design/actions/present-design-variants.ts +93 -4
  34. package/corpus/templates/design/actions/run-design-audit.ts +229 -0
  35. package/corpus/templates/design/actions/sync-design-system-with-builder.ts +64 -0
  36. package/corpus/templates/design/app/components/design/code-workbench/commands.ts +2 -2
  37. package/corpus/templates/design/app/components/design/inspector/DesignColorPicker.tsx +17 -4
  38. package/corpus/templates/design/app/components/design/inspector/GradientEditor.tsx +5 -1
  39. package/corpus/templates/design/app/components/design/inspector/ImageFillControls.tsx +5 -1
  40. package/corpus/templates/design/app/hooks/use-question-flow.ts +81 -5
  41. package/corpus/templates/design/app/i18n/en-US.ts +1 -1
  42. package/corpus/templates/design/app/i18n-data.ts +32 -1
  43. package/corpus/templates/design/app/i18n-keyboard-shortcuts.ts +10 -10
  44. package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +83 -11
  45. package/corpus/templates/design/app/pages/DesignSystems.tsx +14 -0
  46. package/corpus/templates/design/app/pages/design-editor/generation-prompt-directives.ts +22 -0
  47. package/corpus/templates/design/changelog/2026-08-13-a-screen-that-would-render-behind-an-invisible-alpine-overla.md +6 -0
  48. package/corpus/templates/design/changelog/2026-08-13-attach-a-ui-screenshot-and-the-design-is-reproduced-not-rein.md +6 -0
  49. package/corpus/templates/design/changelog/2026-08-13-linking-a-design-system-means-you-never-get-generic-directio.md +6 -0
  50. package/corpus/templates/design/changelog/2026-08-13-the-design-audit-now-reports-when-a-screen-ignores-its-linke.md +6 -0
  51. package/corpus/templates/design/changelog/2026-08-13-the-design-system-preview-now-shows-how-many-named-tokens-we.md +6 -0
  52. package/corpus/templates/design/changelog/2026-08-13-your-design-system-prompt-and-reference-screenshots-now-reac.md +6 -0
  53. package/corpus/templates/design/server/lib/builder-design-system-proxy.ts +18 -2
  54. package/corpus/templates/design/shared/design-review.ts +1 -0
  55. package/corpus/templates/design/shared/html-integrity.ts +171 -0
  56. package/corpus/templates/mail/app/lib/utils.ts +1 -1
  57. package/corpus/templates/slides/.agents/skills/design-systems/SKILL.md +10 -6
  58. package/corpus/templates/slides/actions/index-design-system-with-builder.ts +41 -3
  59. package/corpus/templates/slides/actions/sync-design-system-with-builder.ts +64 -0
  60. package/corpus/templates/slides/app/components/deck/DeckCard.tsx +1 -1
  61. package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +193 -20
  62. package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +58 -33
  63. package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +28 -41
  64. package/corpus/templates/slides/app/components/editor/ExportMenu.tsx +119 -91
  65. package/corpus/templates/slides/app/components/editor/ImageOverlay.tsx +16 -0
  66. package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +158 -31
  67. package/corpus/templates/slides/app/components/editor/SlideOverflowWarning.tsx +30 -14
  68. package/corpus/templates/slides/app/components/editor/SpeakerNotesPanel.tsx +2 -2
  69. package/corpus/templates/slides/app/components/editor/canvas-interactions/slides-canvas-adapter.ts +4 -1
  70. package/corpus/templates/slides/app/components/editor/rich-text-selection.ts +14 -0
  71. package/corpus/templates/slides/app/components/editor/slide-text-targets.ts +24 -0
  72. package/corpus/templates/slides/app/global.css +24 -0
  73. package/corpus/templates/slides/app/hooks/use-navigation-state.ts +5 -1
  74. package/corpus/templates/slides/app/i18n/en-US.ts +19 -10
  75. package/corpus/templates/slides/app/lib/deck-filter.ts +47 -0
  76. package/corpus/templates/slides/app/lib/export-google-slides-client.ts +15 -4
  77. package/corpus/templates/slides/app/lib/export-pptx-client.ts +637 -1
  78. package/corpus/templates/slides/app/lib/image-download.ts +84 -0
  79. package/corpus/templates/slides/app/lib/utils.ts +1 -1
  80. package/corpus/templates/slides/app/pages/Index.tsx +25 -9
  81. package/corpus/templates/slides/netlify.toml +1 -0
  82. package/corpus/templates/slides/server/lib/builder-design-system-proxy.ts +14 -2
  83. package/dist/agent/production-agent.js +1 -1
  84. package/dist/brand-kit/types.d.ts +10 -2
  85. package/dist/cli/code.js +1 -1
  86. package/dist/cli/index.js +30 -1
  87. package/dist/cli/native-dependencies.d.ts +24 -0
  88. package/dist/cli/native-dependencies.js +264 -0
  89. package/dist/cli/plan-local.js +1 -1
  90. package/dist/cli/skills-content/design-visual-edit-skill.d.ts +1 -1
  91. package/dist/cli/skills-content/design-visual-edit-skill.js +2 -2
  92. package/dist/cli/visualize-repo.js +1 -1
  93. package/dist/client/FeedbackButton.js +12 -12
  94. package/dist/client/agent-chat-adapter.js +3 -4
  95. package/dist/client/assistant-ui-recovery.d.ts +1 -1
  96. package/dist/client/assistant-ui-recovery.js +4 -0
  97. package/dist/client/chat/message-components.d.ts +11 -3
  98. package/dist/client/chat/message-components.js +31 -5
  99. package/dist/client/chat/tool-call-display.d.ts +2 -1
  100. package/dist/client/chat/tool-call-display.js +33 -15
  101. package/dist/client/db-admin/SqlEditor.js +1 -1
  102. package/dist/client/dev-overlay/DevOverlay.js +2 -2
  103. package/dist/client/extensions/portable-extension.js +4 -0
  104. package/dist/client/guided-questions.d.ts +8 -0
  105. package/dist/client/guided-questions.js +12 -3
  106. package/dist/client/sharing/ShareButton.js +16 -24
  107. package/dist/client/sse-event-processor.js +35 -15
  108. package/dist/client/tool-display.d.ts +9 -0
  109. package/dist/client/tool-display.js +39 -0
  110. package/dist/client/vite-dev-recovery-script.js +1 -1
  111. package/dist/collab/awareness.d.ts +2 -2
  112. package/dist/collab/routes.d.ts +1 -1
  113. package/dist/collab/struct-routes.d.ts +1 -1
  114. package/dist/extensions/html-shell.js +5 -0
  115. package/dist/notifications/routes.d.ts +1 -1
  116. package/dist/observability/routes.d.ts +3 -3
  117. package/dist/resources/handlers.d.ts +1 -1
  118. package/dist/secrets/routes.d.ts +3 -3
  119. package/dist/server/agent-chat/prompt-resources.js +17 -16
  120. package/dist/server/agent-chat-plugin.d.ts +9 -0
  121. package/dist/server/agent-chat-plugin.js +29 -7
  122. package/dist/server/builder-design-systems.d.ts +33 -1
  123. package/dist/server/builder-design-systems.js +293 -11
  124. package/dist/server/design-token-utils.d.ts +11 -0
  125. package/dist/server/design-token-utils.js +68 -16
  126. package/dist/server/index.d.ts +1 -1
  127. package/dist/server/index.js +1 -1
  128. package/package.json +3 -3
@@ -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)
@@ -1,7 +1,7 @@
1
1
  import { LLM_MISSING_CREDENTIALS_ERROR_CODE, LLM_MISSING_CREDENTIALS_MESSAGE, } from "../agent/engine/credential-errors.js";
2
2
  import { emitChatFirstOpenApp } from "./chat-first.js";
3
3
  import { formatChatErrorText, normalizeChatError } from "./error-format.js";
4
- import { humanizeToolLabelText, humanizeToolName, runningToolLabel, } from "./tool-display.js";
4
+ import { humanizeToolLabelText, humanizeToolName, isToolCallActive, runningToolLabel, } from "./tool-display.js";
5
5
  /**
6
6
  * Kept verbatim in sync with `INTERRUPTED_TOOL_RESULT_MARKER`
7
7
  * (agent/production-agent.ts): the server matches this substring in replayed
@@ -13,16 +13,21 @@ const INTERRUPTED_ACTIVITY_RESULT = "Stopped before this action started.";
13
13
  /**
14
14
  * Maximum number of assistant-ui repository updates we deliver in one browser
15
15
  * event-loop turn. Durable-run replay can put hundreds of SSE frames into the
16
- * stream queue before the client attaches; draining all of them through
17
- * assistant-ui without a macrotask boundary synchronously nests React external
18
- * store notifications until React throws "Maximum update depth exceeded."
16
+ * stream queue before the client attaches; allowing even a small burst through
17
+ * assistant-ui can synchronously nest React external-store notifications until
18
+ * React throws "Maximum update depth exceeded."
19
19
  *
20
- * A timer scheduled on the first result resets the count when the stream is
20
+ * A task scheduled on the first result resets the count when the stream is
21
21
  * naturally idle between network chunks. We only await it when results are
22
22
  * arriving densely enough to hit this bound, so normal live token streaming
23
23
  * keeps its existing latency while replay bursts yield cooperatively.
24
24
  */
25
- const SSE_RENDER_UPDATES_PER_EVENT_LOOP_TURN = 20;
25
+ const SSE_RENDER_UPDATES_PER_EVENT_LOOP_TURN = 1;
26
+ function waitForNextEventLoopTurn() {
27
+ return new Promise((resolve) => {
28
+ setTimeout(resolve, 0);
29
+ });
30
+ }
26
31
  export function settleInterruptedToolCalls(content, result = INTERRUPTED_TOOL_RESULT, options) {
27
32
  let changed = false;
28
33
  for (const part of content) {
@@ -825,6 +830,8 @@ function hasCompletedCustomUi(content) {
825
830
  return hasCompletedTool && lastCompletedToolIsCustomUi;
826
831
  }
827
832
  export function appendMissingFinalResponseWarning(content, completedToolNames) {
833
+ if (content.some((part) => isToolCallActive(part)))
834
+ return null;
828
835
  const lastTextIndex = lastAssistantTextIndex(content);
829
836
  const successfulToolNames = [
830
837
  ...new Set(completedToolNames ?? completedToolNamesAfterLastAssistantText(content)),
@@ -1245,6 +1252,7 @@ export function processEvent(ev, content, toolCallCounter, tabId, state) {
1245
1252
  : "Done";
1246
1253
  part.structuredMeta = {
1247
1254
  ...part.structuredMeta,
1255
+ ...(ev.status === "pending" ? { agentPending: true } : {}),
1248
1256
  ...(ev.durationMs != null
1249
1257
  ? { agentDurationMs: ev.durationMs }
1250
1258
  : {}),
@@ -1618,15 +1626,19 @@ export async function* readSSEStream(body, content, toolCallCounter, tabId, onSe
1618
1626
  const currentNoProgressTimeoutMs = () => inFlightWork > 0
1619
1627
  ? Math.max(noProgressTimeoutMs, SSE_IN_FLIGHT_WORK_TIMEOUT_MS)
1620
1628
  : noProgressTimeoutMs;
1621
- const paceRenderUpdate = async () => {
1629
+ const paceRenderUpdate = async (hasBufferedEvent) => {
1630
+ // A single event in a network chunk already has a natural read boundary.
1631
+ // Avoid inserting a task into quiet streams so watchdogs and fake-clock
1632
+ // consumers can continue to observe their own timers normally.
1633
+ if (!hasBufferedEvent) {
1634
+ renderUpdatesThisTurn = 0;
1635
+ return;
1636
+ }
1622
1637
  renderUpdatesThisTurn += 1;
1623
1638
  if (!nextEventLoopTurn) {
1624
- nextEventLoopTurn = new Promise((resolve) => {
1625
- setTimeout(() => {
1626
- renderUpdatesThisTurn = 0;
1627
- nextEventLoopTurn = null;
1628
- resolve();
1629
- }, 0);
1639
+ nextEventLoopTurn = waitForNextEventLoopTurn().then(() => {
1640
+ renderUpdatesThisTurn = 0;
1641
+ nextEventLoopTurn = null;
1630
1642
  });
1631
1643
  }
1632
1644
  if (renderUpdatesThisTurn >= SSE_RENDER_UPDATES_PER_EVENT_LOOP_TURN) {
@@ -1686,12 +1698,19 @@ export async function* readSSEStream(body, content, toolCallCounter, tabId, onSe
1686
1698
  const lines = buf.split("\n");
1687
1699
  buf = lines.pop() ?? "";
1688
1700
  let sawProgressEvent = false;
1689
- for (const line of lines) {
1701
+ let bufferedDataEvents = lines.reduce((count, pendingLine) => count +
1702
+ (pendingLine.startsWith("data: ") &&
1703
+ pendingLine.slice(6).trim().length > 0
1704
+ ? 1
1705
+ : 0), 0);
1706
+ for (let lineIndex = 0; lineIndex < lines.length; lineIndex += 1) {
1707
+ const line = lines[lineIndex];
1690
1708
  if (!line.startsWith("data: "))
1691
1709
  continue;
1692
1710
  const raw = line.slice(6).trim();
1693
1711
  if (!raw)
1694
1712
  continue;
1713
+ bufferedDataEvents -= 1;
1695
1714
  let ev;
1696
1715
  try {
1697
1716
  ev = JSON.parse(raw);
@@ -1751,7 +1770,8 @@ export async function* readSSEStream(body, content, toolCallCounter, tabId, onSe
1751
1770
  }
1752
1771
  : result;
1753
1772
  if (terminalResult) {
1754
- await paceRenderUpdate();
1773
+ const hasBufferedEvent = bufferedDataEvents > 0;
1774
+ await paceRenderUpdate(hasBufferedEvent);
1755
1775
  yield withStreamMetadata(terminalResult);
1756
1776
  }
1757
1777
  if (hasStalledPreparingAction(preparingActionState, Date.now(), preparationStallTimeoutMs)) {
@@ -7,7 +7,16 @@ type ToolDisplayPart = {
7
7
  toolName?: string;
8
8
  argsText?: string;
9
9
  args?: Record<string, unknown>;
10
+ result?: unknown;
11
+ outcome?: "unknown";
12
+ activity?: boolean;
13
+ structuredMeta?: Record<string, unknown>;
10
14
  };
15
+ export declare function isDelegatedAgentToolCall(part: ToolDisplayPart): boolean;
16
+ /** True when a tool has not reported a result and the stream did not mark it unknown. */
17
+ export declare function isToolCallInFlight(part: ToolDisplayPart): boolean;
18
+ /** True when the UI must not present this tool as finished. */
19
+ export declare function isToolCallActive(part: ToolDisplayPart): boolean;
11
20
  /**
12
21
  * `call-agent` emits both its ordinary tool row and a richer `agent:<name>`
13
22
  * progress row. Keep the ordinary part in message state for tool completion
@@ -33,6 +33,45 @@ export function humanizeToolLabelText(label, toolName) {
33
33
  return text;
34
34
  return text.split(tool).join(humanizeToolName(tool));
35
35
  }
36
+ const ACTIVE_AGENT_ACTIVITY_PHASES = new Set([
37
+ "reasoning",
38
+ "tool",
39
+ "responding",
40
+ ]);
41
+ export function isDelegatedAgentToolCall(part) {
42
+ return (part.type === "tool-call" && part.toolName?.startsWith("agent:") === true);
43
+ }
44
+ function hasActiveDelegatedAgentActivity(part) {
45
+ const snapshot = part.structuredMeta?.agentActivity;
46
+ if (!snapshot || typeof snapshot !== "object")
47
+ return false;
48
+ const record = snapshot;
49
+ if (typeof record.activePhase === "string" &&
50
+ ACTIVE_AGENT_ACTIVITY_PHASES.has(record.activePhase)) {
51
+ return true;
52
+ }
53
+ return (Array.isArray(record.toolCalls) &&
54
+ record.toolCalls.some((tool) => tool != null &&
55
+ typeof tool === "object" &&
56
+ tool.status === "running"));
57
+ }
58
+ /** True when a tool has not reported a result and the stream did not mark it unknown. */
59
+ export function isToolCallInFlight(part) {
60
+ if (part.type !== "tool-call")
61
+ return false;
62
+ if (part.result !== undefined || part.outcome === "unknown")
63
+ return false;
64
+ return part.activity !== true || isDelegatedAgentToolCall(part);
65
+ }
66
+ /** True when the UI must not present this tool as finished. */
67
+ export function isToolCallActive(part) {
68
+ if (isToolCallInFlight(part))
69
+ return true;
70
+ return (isDelegatedAgentToolCall(part) &&
71
+ part.outcome !== "unknown" &&
72
+ (part.structuredMeta?.agentPending === true ||
73
+ hasActiveDelegatedAgentActivity(part)));
74
+ }
36
75
  function normalizedAgentName(value) {
37
76
  if (typeof value !== "string")
38
77
  return null;
@@ -87,7 +87,7 @@ export function getViteDevRecoveryScript() {
87
87
  console.warn("[agent-native] Dev server keeps re-bundling. Manual refresh needed.", reason);
88
88
  showOverlay(
89
89
  "Dev server out of sync",
90
- "Auto-reload gave up after " + MAX_RELOADS + " tries. Refresh the page (\\u2318R / Ctrl+R)."
90
+ "Auto-reload gave up after " + MAX_RELOADS + " tries. Refresh the page (\\u2318R / Ctrl R)."
91
91
  );
92
92
  return;
93
93
  }
@@ -62,11 +62,11 @@ export declare const postAwareness: import("h3").EventHandlerWithFetch<import("h
62
62
  error: string;
63
63
  states?: undefined;
64
64
  } | {
65
- error?: undefined;
66
65
  states: {
67
66
  clientId: number;
68
67
  state: string;
69
68
  }[];
69
+ error?: undefined;
70
70
  }>>;
71
71
  /**
72
72
  * GET /_agent-native/collab/:docId/users
@@ -77,9 +77,9 @@ export declare const getActiveUsers: import("h3").EventHandlerWithFetch<import("
77
77
  error: string;
78
78
  users?: undefined;
79
79
  } | {
80
- error?: undefined;
81
80
  users: {
82
81
  clientId: number;
83
82
  lastSeen: number;
84
83
  }[];
84
+ error?: undefined;
85
85
  }>>;
@@ -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
- ok?: undefined;
30
29
  error: string;
30
+ ok?: undefined;
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;
@@ -147,6 +147,11 @@ export function buildExtensionHtml(content, themeVars, isDark, extensionId, bind
147
147
  </style>
148
148
  <style>
149
149
  *, *::before, *::after { border-color: hsl(var(--border)); }
150
+ /* Alpine only honours x-cloak when a stylesheet hides it, and extension
151
+ content is a body snippet that cannot supply one. Without this, an
152
+ x-cloak overlay paints over the whole extension until Alpine boots —
153
+ and forever if it never does. */
154
+ [x-cloak] { display: none !important; }
150
155
  html, body {
151
156
  /* Transparent so the iframe inherits the host surface (dashboard panel,
152
157
  sidebar, chat) instead of painting the browser's default white canvas.
@@ -28,6 +28,6 @@ export declare function createNotificationsHandler(): import("h3").EventHandlerW
28
28
  } | {
29
29
  count?: undefined;
30
30
  updated?: undefined;
31
- error?: undefined;
32
31
  ok: boolean;
32
+ error?: undefined;
33
33
  }>>;
@@ -41,23 +41,23 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
41
41
  thumbsUpRate: number;
42
42
  avgEvalScore: number;
43
43
  } | {
44
+ ok?: undefined;
44
45
  error?: undefined;
45
46
  summary: import("./types.js").TraceSummary;
46
47
  spans: import("./types.js").TraceSpan[];
47
48
  id?: undefined;
48
- ok?: undefined;
49
49
  } | {
50
+ ok?: undefined;
50
51
  error?: undefined;
51
52
  summary?: undefined;
52
53
  spans?: undefined;
53
54
  id: string;
54
- ok?: undefined;
55
55
  } | {
56
+ ok?: undefined;
56
57
  summary?: undefined;
57
58
  spans?: undefined;
58
59
  id?: undefined;
59
60
  error: any;
60
- ok?: undefined;
61
61
  } | {
62
62
  error?: undefined;
63
63
  summary?: undefined;
@@ -48,8 +48,8 @@ export declare function handleUpdateResource(event: any): Promise<import("./stor
48
48
  }>;
49
49
  /** DELETE /_agent-native/resources/:id — delete a resource */
50
50
  export declare function handleDeleteResource(event: any): Promise<{
51
- error: string;
52
51
  ok?: undefined;
52
+ error: string;
53
53
  } | {
54
54
  error?: undefined;
55
55
  ok: boolean;
@@ -34,16 +34,16 @@ export declare function createListSecretsHandler(): import("h3").EventHandlerWit
34
34
  /** POST /_agent-native/secrets/:key — write a secret. */
35
35
  export declare function createWriteSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
36
36
  error: string;
37
- status?: undefined;
38
37
  ok?: undefined;
38
+ status?: undefined;
39
39
  } | {
40
40
  ok: boolean;
41
41
  status: string;
42
42
  error?: undefined;
43
43
  } | {
44
+ ok?: undefined;
44
45
  error: string;
45
46
  removed?: undefined;
46
- ok?: undefined;
47
47
  } | {
48
48
  ok: boolean;
49
49
  removed: boolean;
@@ -54,9 +54,9 @@ export declare function createWriteSecretHandler(): import("h3").EventHandlerWit
54
54
  * or the current stored value without changing anything.
55
55
  */
56
56
  export declare function createTestSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
57
+ ok?: undefined;
57
58
  error: string;
58
59
  note?: undefined;
59
- ok?: undefined;
60
60
  } | {
61
61
  ok: boolean;
62
62
  note?: undefined;
@@ -416,21 +416,22 @@ export function resourceScopeForOwner(owner, currentOwner) {
416
416
  return "resource";
417
417
  }
418
418
  async function loadAgentsResourceForPrompt(owner, scope, maxChars = SHARED_PROMPT_RESOURCE_MAX_CHARS) {
419
+ let agents;
419
420
  try {
420
- const agents = await resourceGetByPath(owner, "AGENTS.md");
421
- if (!agents?.content?.trim())
422
- return null;
423
- return promptResourceBlock({
424
- name: "AGENTS.md",
425
- scope,
426
- path: "AGENTS.md",
427
- content: agents.content,
428
- maxChars,
429
- });
421
+ agents = await resourceGetByPath(owner, "AGENTS.md");
430
422
  }
431
- catch {
432
- return null;
423
+ catch (error) {
424
+ throw new Error(`Unable to read durable AGENTS.md instructions for ${scope} (${owner}). The run cannot safely continue without them.`, { cause: error });
433
425
  }
426
+ if (!agents?.content?.trim())
427
+ return null;
428
+ return promptResourceBlock({
429
+ name: "AGENTS.md",
430
+ scope,
431
+ path: "AGENTS.md",
432
+ content: agents.content,
433
+ maxChars,
434
+ });
434
435
  }
435
436
  async function loadInstructionResourcesForPrompt(owner, scope, maxChars = SHARED_PROMPT_RESOURCE_MAX_CHARS, summaryOnly = false) {
436
437
  try {
@@ -671,14 +672,14 @@ export async function loadResourcesForPrompt(owner, compact = false, selfAppId,
671
672
  // every app in the workspace, not copied into app scopes. They may come from
672
673
  // SQL, Dispatch, or local file mode.
673
674
  const workspaceAgents = await loadAgentsResourceForPrompt(WORKSPACE_OWNER, "workspace", promptResourceMaxChars);
674
- addSection(workspaceAgents);
675
+ addSection(workspaceAgents, "required");
675
676
  addSections(await loadInstructionResourcesForPrompt(WORKSPACE_OWNER, "workspace-instruction", promptResourceMaxChars, compact));
676
677
  const organizationOwner = sharedResourceOwner(orgId);
677
678
  // 4. Legacy app-wide defaults. Existing deployments keep their seeded
678
679
  // shared guidance as an inherited fallback; organization writes never
679
680
  // mutate this owner.
680
681
  const appDefaultAgents = await loadAgentsResourceForPrompt(SHARED_OWNER, organizationOwner === SHARED_OWNER ? "shared" : "app-default", promptResourceMaxChars);
681
- addSection(appDefaultAgents);
682
+ addSection(appDefaultAgents, "required");
682
683
  addSections(await loadInstructionResourcesForPrompt(SHARED_OWNER, organizationOwner === SHARED_OWNER
683
684
  ? "shared-instruction"
684
685
  : "app-default-instruction", promptResourceMaxChars, compact));
@@ -686,14 +687,14 @@ export async function loadResourcesForPrompt(owner, compact = false, selfAppId,
686
687
  // learnings that Slack/integration runs share with interactive app chat.
687
688
  if (organizationOwner !== SHARED_OWNER) {
688
689
  const organizationAgents = await loadAgentsResourceForPrompt(organizationOwner, "organization", promptResourceMaxChars);
689
- addSection(organizationAgents);
690
+ addSection(organizationAgents, "required");
690
691
  addSections(await loadInstructionResourcesForPrompt(organizationOwner, "organization-instruction", promptResourceMaxChars, compact));
691
692
  }
692
693
  // 6. Personal SQL resources. These come last in the instruction stack so a
693
694
  // user can narrow or override organization/app and workspace defaults.
694
695
  if (owner !== SHARED_OWNER && owner !== WORKSPACE_OWNER) {
695
696
  const personalAgents = await loadAgentsResourceForPrompt(owner, "personal", promptResourceMaxChars);
696
- addSection(personalAgents, "user");
697
+ addSection(personalAgents, "required");
697
698
  addSections(await loadInstructionResourcesForPrompt(owner, "personal-instruction", promptResourceMaxChars, compact), "user");
698
699
  }
699
700
  const resourceSkillsBlock = await loadResourceSkillsPromptBlock(owner, orgId);
@@ -16,6 +16,15 @@ export { loadResourcesForPrompt };
16
16
  export { _agentChatPromptSectionsForTests };
17
17
  export { buildPublicAgentA2ASkills };
18
18
  export { assembleA2AFinalResponse };
19
+ export declare function buildLeanSystemPrompt(input: {
20
+ basePrompt: string;
21
+ resources: string;
22
+ additionalFramework?: string;
23
+ cacheSplit?: string;
24
+ extra?: string;
25
+ modelOverlay?: string;
26
+ runtimeContext?: string;
27
+ }): string;
19
28
  export type { AgentChatPluginOptions };
20
29
  export { runA2AAgentLoop };
21
30
  export { runMCPAgentLoop };