@truefoundry/trueforge-ui 0.3.0-rc.4 → 0.3.0-rc.6

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 (85) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/{AgentCodeSnippets-U6KQWVBJ.js → AgentCodeSnippets-UWKIJI6U.js} +7 -7
  3. package/dist/AgentMetricChart-4ZJJED5Q.js +15 -0
  4. package/dist/{AgentOverview-RLJ6HZCN.js → AgentOverview-UZBCVNMP.js} +11 -9
  5. package/dist/AgentOverview-UZBCVNMP.js.map +1 -0
  6. package/dist/{AgentSessionEventTimeline-CDXRRUZQ.js → AgentSessionEventTimeline-N4RXG2NU.js} +7 -7
  7. package/dist/{AgentSessionEventTimelineChart-S2WX6ZEA.js → AgentSessionEventTimelineChart-EMWNJMMK.js} +7 -7
  8. package/dist/{AgentSessions-UI3L7XY2.js → AgentSessions-CD7JAQTC.js} +8 -8
  9. package/dist/{ConnectorSettings-OIGAC2HU.js → ConnectorSettings-GEI4S6SD.js} +7 -7
  10. package/dist/{DockLayout-J5BRKMJZ.js → DockLayout-JZ4DKDOR.js} +10 -10
  11. package/dist/{DrawerLayout-65YHGHIF.js → DrawerLayout-AV4FJTGV.js} +11 -11
  12. package/dist/{ModelSettings-VP6WCMGT.js → ModelSettings-4TNETPJJ.js} +7 -7
  13. package/dist/OpenUiFenceBlock-KPZFLUSC.js +9 -0
  14. package/dist/{SandboxSettings-GTZT7LD6.js → SandboxSettings-IEIWFKQW.js} +7 -7
  15. package/dist/SchedulesPage-ZG5IMQI3.js +15 -0
  16. package/dist/{SettingsBuilder-A4BPYIFZ.js → SettingsBuilder-B2ULQPIT.js} +9 -9
  17. package/dist/{SettingsBuilder-A4BPYIFZ.js.map → SettingsBuilder-B2ULQPIT.js.map} +1 -1
  18. package/dist/{ShellRouteSync-SSLGM35F.js → ShellRouteSync-SJXFKUAJ.js} +4 -4
  19. package/dist/{SidebarLayout-MFDOGAVJ.js → SidebarLayout-XUM2Y6PA.js} +12 -12
  20. package/dist/{SkillSettings-WQPUQ5TE.js → SkillSettings-NHBL5ZXU.js} +7 -7
  21. package/dist/{TrueForgeUIWithRouter-5CDICMCE.js → TrueForgeUIWithRouter-NVV7IXXP.js} +9 -9
  22. package/dist/{WidgetLayout-HE7E4UL5.js → WidgetLayout-T7DBLKV3.js} +10 -10
  23. package/dist/{chunk-F7ZAQIRE.js → chunk-22A4HHBQ.js} +27 -16
  24. package/dist/{chunk-F7ZAQIRE.js.map → chunk-22A4HHBQ.js.map} +1 -1
  25. package/dist/{chunk-6CFZHEYH.js → chunk-2GIZY3JJ.js} +32 -3
  26. package/dist/chunk-2GIZY3JJ.js.map +1 -0
  27. package/dist/{chunk-2BDTG544.js → chunk-2QTH6JHX.js} +3 -3
  28. package/dist/{chunk-TGKQRK3S.js → chunk-3R62ISBR.js} +5 -5
  29. package/dist/{chunk-KCYBMKQL.js → chunk-3TV6SKGW.js} +4 -4
  30. package/dist/{chunk-MAA7U4RF.js → chunk-3ZW74FHC.js} +3 -3
  31. package/dist/{chunk-GTTMLDCI.js → chunk-CG75X77Q.js} +2 -2
  32. package/dist/{chunk-2OKGEU6X.js → chunk-DNOQ4WYH.js} +360 -217
  33. package/dist/chunk-DNOQ4WYH.js.map +1 -0
  34. package/dist/{chunk-IOPHQEUY.js → chunk-GA4AC4XL.js} +2 -2
  35. package/dist/chunk-JCL3Q7RW.js +587 -0
  36. package/dist/chunk-JCL3Q7RW.js.map +1 -0
  37. package/dist/{chunk-VXKNS7FH.js → chunk-NFUX2ESW.js} +9 -9
  38. package/dist/{chunk-XO3FYN2W.js → chunk-NYMNCYWL.js} +8 -8
  39. package/dist/chunk-NYMNCYWL.js.map +1 -0
  40. package/dist/{chunk-E4GVP6PM.js → chunk-T6QQV5LK.js} +55 -12
  41. package/dist/chunk-T6QQV5LK.js.map +1 -0
  42. package/dist/{chunk-MJULWIPI.js → chunk-TDG7GHXE.js} +478 -268
  43. package/dist/chunk-TDG7GHXE.js.map +1 -0
  44. package/dist/index.d.ts +27 -15
  45. package/dist/index.js +12 -12
  46. package/dist/plugins/trueforge-agent-server-adapter/index.d.ts +2 -1
  47. package/dist/plugins/trueforge-agent-server-adapter/index.js +65 -14
  48. package/dist/plugins/trueforge-agent-server-adapter/index.js.map +1 -1
  49. package/dist/styles.css +1 -1
  50. package/package.json +4 -3
  51. package/dist/AgentMetricChart-3D6FUFO6.js +0 -15
  52. package/dist/AgentOverview-RLJ6HZCN.js.map +0 -1
  53. package/dist/OpenUiFenceBlock-UTDCTNTM.js +0 -9
  54. package/dist/SchedulesPage-ARWU7BZF.js +0 -15
  55. package/dist/chunk-2OKGEU6X.js.map +0 -1
  56. package/dist/chunk-6CFZHEYH.js.map +0 -1
  57. package/dist/chunk-E4GVP6PM.js.map +0 -1
  58. package/dist/chunk-MJULWIPI.js.map +0 -1
  59. package/dist/chunk-P7J2ABEP.js +0 -587
  60. package/dist/chunk-P7J2ABEP.js.map +0 -1
  61. package/dist/chunk-XO3FYN2W.js.map +0 -1
  62. /package/dist/{AgentCodeSnippets-U6KQWVBJ.js.map → AgentCodeSnippets-UWKIJI6U.js.map} +0 -0
  63. /package/dist/{AgentMetricChart-3D6FUFO6.js.map → AgentMetricChart-4ZJJED5Q.js.map} +0 -0
  64. /package/dist/{AgentSessionEventTimeline-CDXRRUZQ.js.map → AgentSessionEventTimeline-N4RXG2NU.js.map} +0 -0
  65. /package/dist/{AgentSessionEventTimelineChart-S2WX6ZEA.js.map → AgentSessionEventTimelineChart-EMWNJMMK.js.map} +0 -0
  66. /package/dist/{AgentSessions-UI3L7XY2.js.map → AgentSessions-CD7JAQTC.js.map} +0 -0
  67. /package/dist/{ConnectorSettings-OIGAC2HU.js.map → ConnectorSettings-GEI4S6SD.js.map} +0 -0
  68. /package/dist/{DockLayout-J5BRKMJZ.js.map → DockLayout-JZ4DKDOR.js.map} +0 -0
  69. /package/dist/{DrawerLayout-65YHGHIF.js.map → DrawerLayout-AV4FJTGV.js.map} +0 -0
  70. /package/dist/{ModelSettings-VP6WCMGT.js.map → ModelSettings-4TNETPJJ.js.map} +0 -0
  71. /package/dist/{OpenUiFenceBlock-UTDCTNTM.js.map → OpenUiFenceBlock-KPZFLUSC.js.map} +0 -0
  72. /package/dist/{SandboxSettings-GTZT7LD6.js.map → SandboxSettings-IEIWFKQW.js.map} +0 -0
  73. /package/dist/{SchedulesPage-ARWU7BZF.js.map → SchedulesPage-ZG5IMQI3.js.map} +0 -0
  74. /package/dist/{ShellRouteSync-SSLGM35F.js.map → ShellRouteSync-SJXFKUAJ.js.map} +0 -0
  75. /package/dist/{SidebarLayout-MFDOGAVJ.js.map → SidebarLayout-XUM2Y6PA.js.map} +0 -0
  76. /package/dist/{SkillSettings-WQPUQ5TE.js.map → SkillSettings-NHBL5ZXU.js.map} +0 -0
  77. /package/dist/{TrueForgeUIWithRouter-5CDICMCE.js.map → TrueForgeUIWithRouter-NVV7IXXP.js.map} +0 -0
  78. /package/dist/{WidgetLayout-HE7E4UL5.js.map → WidgetLayout-T7DBLKV3.js.map} +0 -0
  79. /package/dist/{chunk-2BDTG544.js.map → chunk-2QTH6JHX.js.map} +0 -0
  80. /package/dist/{chunk-TGKQRK3S.js.map → chunk-3R62ISBR.js.map} +0 -0
  81. /package/dist/{chunk-KCYBMKQL.js.map → chunk-3TV6SKGW.js.map} +0 -0
  82. /package/dist/{chunk-MAA7U4RF.js.map → chunk-3ZW74FHC.js.map} +0 -0
  83. /package/dist/{chunk-GTTMLDCI.js.map → chunk-CG75X77Q.js.map} +0 -0
  84. /package/dist/{chunk-IOPHQEUY.js.map → chunk-GA4AC4XL.js.map} +0 -0
  85. /package/dist/{chunk-VXKNS7FH.js.map → chunk-NFUX2ESW.js.map} +0 -0
@@ -2,35 +2,35 @@ import {
2
2
  AgentConfigDrawerContainer,
3
3
  NamedAgentHeaderLabel,
4
4
  ShellActions
5
- } from "./chunk-TGKQRK3S.js";
5
+ } from "./chunk-3R62ISBR.js";
6
6
  import {
7
7
  Thread
8
- } from "./chunk-KCYBMKQL.js";
8
+ } from "./chunk-3TV6SKGW.js";
9
9
  import {
10
10
  useSlot
11
- } from "./chunk-2OKGEU6X.js";
11
+ } from "./chunk-DNOQ4WYH.js";
12
12
  import {
13
13
  Icon,
14
14
  PageHeader,
15
15
  Spinner,
16
16
  auiButtonClass
17
- } from "./chunk-MAA7U4RF.js";
17
+ } from "./chunk-3ZW74FHC.js";
18
18
  import {
19
19
  useOptionalShellMode
20
- } from "./chunk-6CFZHEYH.js";
20
+ } from "./chunk-2GIZY3JJ.js";
21
21
  import {
22
22
  useAui
23
23
  } from "./chunk-M6MHLVSO.js";
24
24
  import {
25
25
  cn
26
- } from "./chunk-P7J2ABEP.js";
26
+ } from "./chunk-JCL3Q7RW.js";
27
27
 
28
28
  // src/layouts/StackChatPanel.tsx
29
29
  import { lazy, Suspense, useEffect } from "react";
30
30
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
31
- var TruefoundrySettingsBuilder = lazy(() => import("./SettingsBuilder-A4BPYIFZ.js"));
31
+ var TruefoundrySettingsBuilder = lazy(() => import("./SettingsBuilder-B2ULQPIT.js"));
32
32
  var SchedulesPage = lazy(
33
- () => import("./SchedulesPage-ARWU7BZF.js").then((m) => ({ default: m.SchedulesPage }))
33
+ () => import("./SchedulesPage-ZG5IMQI3.js").then((m) => ({ default: m.SchedulesPage }))
34
34
  );
35
35
  function StackChatPanel({ className, threadHeaderEnd }) {
36
36
  const aui = useAui();
@@ -181,4 +181,4 @@ function StackChatPanel({ className, threadHeaderEnd }) {
181
181
  export {
182
182
  StackChatPanel
183
183
  };
184
- //# sourceMappingURL=chunk-VXKNS7FH.js.map
184
+ //# sourceMappingURL=chunk-NFUX2ESW.js.map
@@ -10,23 +10,23 @@ import {
10
10
  useIsMobile,
11
11
  useResourcePermissions,
12
12
  useSlot
13
- } from "./chunk-2OKGEU6X.js";
13
+ } from "./chunk-DNOQ4WYH.js";
14
14
  import {
15
15
  useSearchAgentsList
16
- } from "./chunk-E4GVP6PM.js";
16
+ } from "./chunk-T6QQV5LK.js";
17
17
  import {
18
18
  Icon,
19
19
  auiButtonClass,
20
20
  useCompactLayout
21
- } from "./chunk-MAA7U4RF.js";
21
+ } from "./chunk-3ZW74FHC.js";
22
22
  import {
23
23
  libraryAgentId,
24
24
  useOptionalServer,
25
25
  useOptionalShellMode
26
- } from "./chunk-6CFZHEYH.js";
26
+ } from "./chunk-2GIZY3JJ.js";
27
27
  import {
28
28
  cn
29
- } from "./chunk-P7J2ABEP.js";
29
+ } from "./chunk-JCL3Q7RW.js";
30
30
 
31
31
  // src/containers/ThreadListContainer.tsx
32
32
  import {
@@ -196,7 +196,7 @@ function AgentHistoryFilterButton() {
196
196
  role: "menu",
197
197
  "aria-label": "Filter agents",
198
198
  style: { top: menuPos.top, left: menuPos.left },
199
- className: "font-sans-flex fixed z-50 w-56 rounded-md border border-border bg-card-bg p-1 text-text-primary shadow-md",
199
+ className: "aui-popup-enter font-sans-flex fixed z-50 w-56 rounded-md border border-border bg-card-bg p-1 text-text-primary shadow-md",
200
200
  children: filterBody
201
201
  }
202
202
  ),
@@ -271,7 +271,7 @@ function ThreadListItemDeleteMenu({ disabled }) {
271
271
  portalProps: { container: portalContainer },
272
272
  align: "end",
273
273
  sideOffset: 4,
274
- className: "font-sans-flex z-50 min-w-[8rem] rounded-md border border-border bg-card-bg p-1 text-text-primary shadow-md *:w-full",
274
+ className: "aui-popup-enter font-sans-flex z-50 min-w-[8rem] rounded-md border border-border bg-card-bg p-1 text-text-primary shadow-md *:w-full",
275
275
  children: /* @__PURE__ */ jsx2(PermissionGuard, { allowed: !disabled, children: /* @__PURE__ */ jsxs2(ThreadListItemPrimitive.Delete, { className: deleteItemClass, children: [
276
276
  /* @__PURE__ */ jsx2(Icon, { name: "trash", className: "size-3.5" }),
277
277
  "Delete"
@@ -514,4 +514,4 @@ function ThreadListContainer({ onThreadOpen, variant = "default" } = {}) {
514
514
  export {
515
515
  ThreadListContainer
516
516
  };
517
- //# sourceMappingURL=chunk-XO3FYN2W.js.map
517
+ //# sourceMappingURL=chunk-NYMNCYWL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/containers/ThreadListContainer.tsx","../src/atoms/AgentHistoryFilterButton.tsx"],"sourcesContent":["'use client';\n\nimport {\n ThreadListItemByIndexProvider,\n ThreadListItemMorePrimitive,\n ThreadListItemPrimitive,\n ThreadListPrimitive,\n useAui,\n useAuiState,\n} from '@assistant-ui/react';\nimport { useCallback, useEffect, useMemo, useRef, useState, type ReactNode, type Ref } from 'react';\n\nimport { AgentHistoryFilterButton } from '../atoms/AgentHistoryFilterButton.js';\nimport { auiButtonClass } from '../atoms/lib/buttonClasses.js';\nimport { cn } from '../atoms/lib/cn.js';\nimport { useCompactLayout } from '../atoms/lib/CompactLayoutContext.js';\nimport {\n canReuseMutableShell,\n readThreadAgentName,\n threadListIndicesByRecency,\n threadListItemIsMutable,\n} from '../atoms/lib/threadListMeta.js';\nimport { useIsMobile } from '../atoms/lib/useIsMobile.js';\nimport { BottomSheet } from '../atoms/primitives/BottomSheet.js';\nimport { useResourcePermissions } from '../hooks/useResourcePermissions.js';\nimport { Icon } from '../icons/Icon.js';\nimport { useOptionalServer } from '../server/ServerContext.js';\nimport { useOptionalShellMode } from '../server/ShellModeContext.js';\nimport { useSlot } from '../theme/SlotsProvider.js';\n\n/**\n * Simplified relative to the reference: renders threads in a single flat list\n * rather than grouping them by Today/Yesterday/Earlier.\n *\n * Delete uses assistant-ui ThreadListItemPrimitive.Delete / ThreadListItemMorePrimitive\n * (adapter.delete → server.deleteSession). Mobile/compact keeps a BottomSheet chrome.\n */\nexport type ThreadListContainerProps = {\n /** Called after New chat or selecting a row — used by stack/drawer chrome. */\n onThreadOpen?: () => void;\n /** `recent-history` hides navigation and lists only persisted sessions. */\n variant?: 'default' | 'recent-history';\n};\n\nconst deleteItemClass =\n 'flex w-full cursor-pointer select-none items-center gap-2 rounded-md px-2 py-1.5 text-sm font-medium text-failure-bg outline-none transition-colors hover:bg-failure-bg/12 hover:text-failure-bg focus:bg-failure-bg/12 focus:text-failure-bg data-[highlighted]:bg-failure-bg/12 data-[highlighted]:text-failure-bg';\n\nfunction ThreadListItemDeleteMenu({ disabled }: { disabled: boolean }) {\n const PermissionGuard = useSlot('PermissionGuard');\n const compact = useCompactLayout();\n const isMobile = useIsMobile();\n const [sheetOpen, setSheetOpen] = useState(false);\n const [portalContainer, setPortalContainer] = useState<HTMLElement>();\n const useSheet = isMobile || compact;\n const setTriggerElement = useCallback((element: HTMLButtonElement | null) => {\n const themeRoot = element?.closest('.aui-theme-root');\n setPortalContainer(themeRoot instanceof HTMLElement ? themeRoot : undefined);\n }, []);\n\n const moreButtonClass = auiButtonClass({\n variant: 'ghost',\n size: 'icon',\n className: 'size-7 shrink-0 text-text-secondary hover:bg-transparent hover:text-text-primary',\n });\n\n if (useSheet) {\n return (\n <>\n <button\n type=\"button\"\n aria-label=\"Session actions\"\n title=\"Session actions\"\n aria-haspopup=\"dialog\"\n aria-expanded={sheetOpen}\n className={moreButtonClass}\n onClick={() => setSheetOpen(true)}\n >\n <Icon name=\"ellipsis\" className=\"size-3.5\" />\n </button>\n {sheetOpen ? (\n <BottomSheet open onOpenChange={setSheetOpen} aria-label=\"Session actions\">\n <div className=\"flex flex-col gap-1 p-2 *:w-full\" role=\"menu\">\n <PermissionGuard allowed={!disabled}>\n <ThreadListItemPrimitive.Delete\n className={deleteItemClass}\n onClick={() => {\n if (!disabled) setSheetOpen(false);\n }}\n >\n <Icon name=\"trash\" className=\"size-3.5\" />\n Delete\n </ThreadListItemPrimitive.Delete>\n </PermissionGuard>\n </div>\n </BottomSheet>\n ) : null}\n </>\n );\n }\n\n return (\n <ThreadListItemMorePrimitive.Root sharedFocusGroup>\n <ThreadListItemMorePrimitive.Trigger\n ref={setTriggerElement}\n aria-label=\"Session actions\"\n title=\"Session actions\"\n className={moreButtonClass}\n >\n <Icon name=\"ellipsis\" className=\"size-3.5\" />\n </ThreadListItemMorePrimitive.Trigger>\n <ThreadListItemMorePrimitive.Content\n portalProps={{ container: portalContainer }}\n align=\"end\"\n sideOffset={4}\n className=\"aui-popup-enter font-sans-flex z-50 min-w-[8rem] rounded-md border border-border bg-card-bg p-1 text-text-primary shadow-md *:w-full\"\n >\n <PermissionGuard allowed={!disabled}>\n <ThreadListItemPrimitive.Delete className={deleteItemClass}>\n <Icon name=\"trash\" className=\"size-3.5\" />\n Delete\n </ThreadListItemPrimitive.Delete>\n </PermissionGuard>\n </ThreadListItemMorePrimitive.Content>\n </ThreadListItemMorePrimitive.Root>\n );\n}\n\nfunction ThreadListItemRow({\n onThreadOpen,\n canDeleteSession,\n canDeleteResource,\n}: {\n onThreadOpen?: () => void;\n canDeleteSession: boolean;\n canDeleteResource: (sessionId: string) => boolean;\n}) {\n const aui = useAui();\n const shell = useOptionalShellMode();\n const ThreadListRow = useSlot('ThreadListRow');\n const id = useAuiState(s => s.threadListItem.id);\n const remoteId = useAuiState(s => s.threadListItem.remoteId);\n const title = useAuiState(s => s.threadListItem.title);\n const lastMessageAt = useAuiState(s => s.threadListItem.lastMessageAt);\n const custom = useAuiState(s => s.threadListItem.custom);\n const mainThreadId = useAuiState(s => s.threads.mainThreadId);\n const agentName = readThreadAgentName(custom);\n const showDelete = canDeleteSession && remoteId != null;\n const deleteDisabled = remoteId != null && !canDeleteResource(remoteId);\n const sidebarNavOpen = shell?.libraryOpen === true || shell?.sessionsOpen === true || shell?.schedulesOpen === true;\n\n return (\n <ThreadListItemPrimitive.Root className=\"min-w-0\">\n <ThreadListRow\n title={title ?? 'New Chat'}\n active={id === mainThreadId && !sidebarNavOpen}\n agentName={agentName}\n lastMessageAt={lastMessageAt}\n onSelect={() => {\n onThreadOpen?.();\n shell?.setSettingsOpen(false);\n shell?.setLibraryOpen(false);\n shell?.setSessionsOpen(false);\n shell?.setSchedulesOpen(false);\n\n // Prefer custom.isMutable (session wire); agentName-only is a legacy fallback.\n const sessionMutable = threadListItemIsMutable(custom);\n const sameImmutable =\n !sessionMutable &&\n shell?.mode.status === 'active' &&\n !shell.mode.isMutable &&\n (agentName == null\n ? shell.mode.agentName == null && shell.mode.agentId == null\n : shell.mode.agentName === agentName || shell.mode.agentId === agentName);\n const sameMutable = canReuseMutableShell({\n sessionMutable,\n shellMutable: shell?.mode.status === 'active' && shell.mode.isMutable,\n ...(shell?.mode.status === 'active' && shell.mode.isMutable\n ? { shellAgentName: shell.mode.agentName, shellAgentId: shell.mode.agentId }\n : {}),\n remoteId,\n pendingSessionId: shell?.pendingSessionId,\n });\n\n if ((sameImmutable || sameMutable) && remoteId != null) {\n void Promise.resolve(aui.threads().switchToThread(id)).catch(() => undefined);\n return;\n }\n if (remoteId != null) {\n shell?.openHistorySession({\n sessionId: remoteId,\n isMutable: sessionMutable,\n ...(agentName != null ? { agentName } : {}),\n });\n return;\n }\n void Promise.resolve(aui.threads().switchToThread(id)).catch(() => undefined);\n }}\n actions={showDelete ? <ThreadListItemDeleteMenu disabled={deleteDisabled} /> : undefined}\n />\n </ThreadListItemPrimitive.Root>\n );\n}\n\nfunction useThreadListIndicesByRecency(variant: NonNullable<ThreadListContainerProps['variant']>): number[] {\n const threadIds = useAuiState(s => s.threads.threadIds);\n const threadItems = useAuiState(s => s.threads.threadItems);\n\n return useMemo(() => {\n const indices = threadListIndicesByRecency({ threadIds, threadItems });\n if (variant === 'default') return indices;\n\n const itemById = new Map<string, (typeof threadItems)[number]>();\n for (const item of threadItems) {\n itemById.set(item.id, item);\n if (item.remoteId != null) itemById.set(item.remoteId, item);\n }\n\n return indices.filter(index => {\n const id = threadIds[index];\n if (id === undefined) return false;\n const item = itemById.get(id);\n return item?.remoteId != null;\n });\n }, [threadIds, threadItems, variant]);\n}\n\nfunction ThreadListItemsByRecency({\n indices,\n onThreadOpen,\n canDeleteSession,\n canDeleteResource,\n}: {\n indices: number[];\n onThreadOpen?: () => void;\n canDeleteSession: boolean;\n canDeleteResource: (sessionId: string) => boolean;\n}) {\n // Newest-first: remount/switchToThread can append the active session to threadIds.\n const threadIds = useAuiState(s => s.threads.threadIds);\n\n return (\n <>\n {indices.map(index => {\n const key = threadIds[index] ?? String(index);\n return (\n <ThreadListItemByIndexProvider key={key} index={index} archived={false}>\n <ThreadListItemRow\n onThreadOpen={onThreadOpen}\n canDeleteSession={canDeleteSession}\n canDeleteResource={canDeleteResource}\n />\n </ThreadListItemByIndexProvider>\n );\n })}\n </>\n );\n}\n\nconst THREAD_LIST_VIEWPORT_SLOT = 'aui_thread-list-viewport';\n/** How close to the bottom (px) before the next sessions page is fetched. */\nconst LOAD_MORE_BOTTOM_PX = 80;\n\nfunction RecentChatsSection({\n children,\n viewportRef,\n hideScrollbar,\n}: {\n children: ReactNode;\n viewportRef: Ref<HTMLDivElement>;\n hideScrollbar: boolean;\n}) {\n const shell = useOptionalShellMode();\n const activeRemoteId = useAuiState(s => s.threadListItem.remoteId);\n const historyFilterIntent = shell?.historyAgentFilter?.intent;\n const showFilter =\n shell?.isLibraryEnabled === true &&\n historyFilterIntent !== 'try-agent' &&\n (historyFilterIntent === 'history' ||\n shell.mode.status !== 'active' ||\n shell.mode.isMutable ||\n shell.pendingSessionId != null ||\n activeRemoteId != null);\n const heading =\n shell?.historyAgentFilter == null ? 'Chat History' : `Chats for ${shell.historyAgentFilter.agentName}`;\n\n return (\n <div className=\"flex min-h-0 flex-1 flex-col\">\n <div className=\"flex shrink-0 items-center gap-1 px-1 py-1\">\n <h2 className=\"min-w-0 flex-1 truncate px-1.5 py-1 text-sm font-medium text-text-secondary\">{heading}</h2>\n {showFilter ? <AgentHistoryFilterButton /> : null}\n </div>\n <div\n ref={viewportRef}\n data-slot={THREAD_LIST_VIEWPORT_SLOT}\n className={cn('flex min-h-0 flex-1 flex-col gap-0.5 overflow-y-auto', hideScrollbar && 'aui-scrollbar-hidden')}\n >\n {children}\n </div>\n </div>\n );\n}\n\nexport function ThreadListContainer({ onThreadOpen, variant = 'default' }: ThreadListContainerProps = {}) {\n const aui = useAui();\n const server = useOptionalServer();\n const isLoading = useAuiState(s => s.threads.isLoading);\n const isLoadingMore = useAuiState(s => s.threads.isLoadingMore);\n const hasMore = useAuiState(s => s.threads.hasMore);\n const threadIds = useAuiState(s => s.threads.threadIds);\n const threadItems = useAuiState(s => s.threads.threadItems);\n const shell = useOptionalShellMode();\n\n const ThreadListShell = useSlot('ThreadListShell');\n const ThreadListNewButton = useSlot('ThreadListNewButton');\n const AgentsLibraryButton = useSlot('AgentsLibraryButton');\n const SessionsBrowserButton = useSlot('SessionsBrowserButton');\n const SchedulesButton = useSlot('SchedulesButton');\n const ThreadListRowSkeleton = useSlot('ThreadListRowSkeleton');\n const ThreadListEmptyState = useSlot('ThreadListEmptyState');\n\n const indices = useThreadListIndicesByRecency(variant);\n const viewportRef = useRef<HTMLDivElement>(null);\n const hasMoreRef = useRef(hasMore);\n const auiRef = useRef(aui);\n hasMoreRef.current = hasMore;\n auiRef.current = aui;\n\n const showNewChat = shell?.isNewChatEnabled !== false;\n const isIdle = shell?.mode.status === 'idle';\n const isRecentHistory = variant === 'recent-history';\n const canDeleteSession = typeof server?.deleteSession === 'function';\n const remoteSessionIds = useMemo(\n () => threadItems.flatMap(item => (item.remoteId == null ? [] : [item.remoteId])),\n [threadItems],\n );\n const { allows } = useResourcePermissions({ resourceType: 'session', resourceIds: remoteSessionIds });\n\n // Fill an underflowing viewport; once it scrolls, paginate only near the bottom.\n // Re-measure after commit (threadIds / hasMore) instead of rAF-chaining, which\n // raced layout and could drain every remaining listSessions page.\n // The runtime owns request deduplication, so Strict Mode remounts can recheck safely.\n useEffect(() => {\n if (isIdle || isLoading || isLoadingMore) return;\n const viewport = viewportRef.current;\n if (!viewport) return;\n\n let cancelled = false;\n\n const tryLoadMore = () => {\n if (cancelled || !hasMoreRef.current) return;\n if (viewport.clientHeight <= 0) return;\n\n const remaining = viewport.scrollHeight - viewport.scrollTop - viewport.clientHeight;\n if (viewport.scrollHeight > viewport.clientHeight && remaining > LOAD_MORE_BOTTOM_PX) return;\n\n void auiRef.current.threads().loadMore();\n };\n\n viewport.addEventListener('scroll', tryLoadMore, { passive: true });\n const resizeObserver = typeof ResizeObserver === 'undefined' ? undefined : new ResizeObserver(() => tryLoadMore());\n if (resizeObserver) {\n resizeObserver.observe(viewport);\n } else {\n window.addEventListener('resize', tryLoadMore);\n }\n tryLoadMore();\n\n return () => {\n cancelled = true;\n viewport.removeEventListener('scroll', tryLoadMore);\n resizeObserver?.disconnect();\n if (!resizeObserver) {\n window.removeEventListener('resize', tryLoadMore);\n }\n };\n }, [hasMore, isIdle, isLoading, isLoadingMore, threadIds.length]);\n\n const handleNewChat = () => {\n onThreadOpen?.();\n shell?.setLibraryOpen(false);\n shell?.setSessionsOpen(false);\n if (shell?.isComposerEnabled) {\n shell.openDraft();\n return;\n }\n shell?.setSettingsOpen(false);\n shell?.setSchedulesOpen(false);\n void Promise.resolve(aui.threads().switchToNewThread()).catch(() => undefined);\n };\n\n let listBody: ReactNode;\n if (isIdle) {\n listBody = <ThreadListEmptyState message={isRecentHistory ? 'No recent chats' : undefined} />;\n } else if (isLoading) {\n listBody = <ThreadListRowSkeleton />;\n } else if (indices.length === 0) {\n listBody = <ThreadListEmptyState message={isRecentHistory ? 'No recent chats' : undefined} />;\n } else {\n listBody = (\n <ThreadListPrimitive.Root className=\"flex min-h-0 flex-col gap-0.5\">\n <ThreadListItemsByRecency\n indices={indices}\n onThreadOpen={onThreadOpen}\n canDeleteSession={canDeleteSession}\n canDeleteResource={sessionId => allows(sessionId, 'DELETE')}\n />\n </ThreadListPrimitive.Root>\n );\n }\n\n return (\n <ThreadListShell\n header={\n isRecentHistory ? null : (\n <div className=\"flex flex-col gap-1\">\n {showNewChat ? <ThreadListNewButton onClick={handleNewChat} /> : null}\n <AgentsLibraryButton />\n <SessionsBrowserButton />\n <SchedulesButton />\n </div>\n )\n }\n >\n <RecentChatsSection viewportRef={viewportRef} hideScrollbar={isRecentHistory}>\n {listBody}\n {!isIdle && hasMore ? <div className=\"h-4 shrink-0\" aria-hidden /> : null}\n </RecentChatsSection>\n </ThreadListShell>\n );\n}\n","'use client';\n\nimport { useEffect, useId, useLayoutEffect, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\n\nimport { Icon } from '../icons/Icon.js';\nimport { useOptionalServer } from '../server/ServerContext.js';\nimport { libraryAgentId, useOptionalShellMode, type HistoryAgentFilter } from '../server/ShellModeContext.js';\nimport { auiButtonClass } from './lib/buttonClasses.js';\nimport { cn } from './lib/cn.js';\nimport { useCompactLayout } from './lib/CompactLayoutContext.js';\nimport { themePortalRoot } from './lib/themePortalRoot.js';\nimport { useIsMobile } from './lib/useIsMobile.js';\nimport { useSearchAgentsList } from './lib/useSearchAgentsList.js';\nimport { BottomSheet } from './primitives/BottomSheet.js';\nimport { DropdownMenuItem } from './primitives/DropdownMenu.js';\nimport SearchInput from './primitives/SearchInput.js';\n\n/**\n * Funnel popover for filtering chat history by agent id.\n * Desktop: fixed menu to the right of the funnel. Mobile/compact: bottom sheet.\n */\nexport function AgentHistoryFilterButton() {\n const shell = useOptionalShellMode();\n const server = useOptionalServer();\n const isMobile = useIsMobile();\n const compact = useCompactLayout();\n const useSheet = isMobile || compact;\n\n const [open, setOpen] = useState(false);\n const [query, setQuery] = useState('');\n const [menuPos, setMenuPos] = useState<{ top: number; left: number } | null>(null);\n const buttonRef = useRef<HTMLButtonElement>(null);\n const menuRef = useRef<HTMLDivElement>(null);\n const menuId = useId();\n\n const enabled = shell?.isLibraryEnabled === true && server != null;\n const selected = shell?.historyAgentFilter ?? null;\n\n useEffect(() => {\n if (!open) setQuery('');\n }, [open]);\n\n const { agents, isInitialLoading, isSearching, loadingMore, hasMore, listRef, sentinelRef } = useSearchAgentsList({\n enabled: open && enabled,\n query,\n });\n\n // Desktop only: anchor to the right of the funnel; portal escapes sidebar overflow.\n useLayoutEffect(() => {\n if (!open || useSheet) {\n setMenuPos(null);\n return;\n }\n const update = () => {\n const rect = buttonRef.current?.getBoundingClientRect();\n if (!rect) return;\n setMenuPos({ top: rect.top, left: rect.right + 4 });\n };\n update();\n window.addEventListener('resize', update);\n window.addEventListener('scroll', update, true);\n return () => {\n window.removeEventListener('resize', update);\n window.removeEventListener('scroll', update, true);\n };\n }, [open, useSheet]);\n\n useEffect(() => {\n if (!open || useSheet) return;\n const handler = (e: MouseEvent) => {\n const target = e.target as Node;\n if (buttonRef.current?.contains(target) || menuRef.current?.contains(target)) return;\n setOpen(false);\n };\n document.addEventListener('mousedown', handler);\n return () => document.removeEventListener('mousedown', handler);\n }, [open, useSheet]);\n\n if (!enabled) return null;\n\n // Reset the active session so the newly scoped history starts from a clean runtime and first page.\n const pick = (filter: HistoryAgentFilter | null) => {\n if (shell?.isComposerEnabled === true) {\n shell.openDraft();\n } else {\n shell?.openLibraryHome();\n }\n shell?.setHistoryAgentFilter(filter);\n setOpen(false);\n };\n\n const filterBody = (\n <>\n <div className=\"p-1\" onMouseDown={e => e.stopPropagation()}>\n <SearchInput query={query} setQuery={setQuery} placeholder=\"Search agents\" />\n {isSearching ? (\n <p className=\"text-text-secondary px-1 pt-1 text-[11px]\" role=\"status\">\n Searching…\n </p>\n ) : null}\n </div>\n <div\n ref={listRef}\n className={cn('mt-1 overflow-y-auto', useSheet ? 'min-h-0 flex-1 px-1 pb-2' : 'min-h-48 max-h-64')}\n >\n {query.trim() === '' ? (\n <DropdownMenuItem\n className={cn(\n 'justify-between',\n selected == null && 'bg-dropdown-selected-item-bg text-dropdown-selected-item-text',\n )}\n onClick={() => pick(null)}\n >\n All chats\n {selected == null ? <Icon name=\"check\" className=\"size-3.5 shrink-0\" /> : null}\n </DropdownMenuItem>\n ) : null}\n {isInitialLoading ? (\n <p className=\"px-2 py-3 text-center text-xs text-text-secondary\">Loading…</p>\n ) : agents.length === 0 ? (\n <p className=\"text-text-secondary px-2 py-6 text-center text-xs\" role=\"status\">\n {query.trim() ? `No agents match \"${query.trim()}\".` : 'No agents yet.'}\n </p>\n ) : (\n <>\n {agents.map(agent => {\n const id = libraryAgentId(agent);\n const active = selected?.agentId === id;\n return (\n <DropdownMenuItem\n key={id}\n className={cn(\n 'justify-between gap-2 text-left',\n active && 'bg-dropdown-selected-item-bg text-dropdown-selected-item-text',\n )}\n onClick={() => pick({ agentId: id, agentName: agent.name, intent: 'history' })}\n >\n <span className=\"min-w-0 truncate\">{agent.name}</span>\n {active ? <Icon name=\"check\" className=\"size-3.5 shrink-0\" /> : null}\n </DropdownMenuItem>\n );\n })}\n {hasMore ? (\n <div ref={sentinelRef} className=\"flex h-6 shrink-0 items-center justify-center\" aria-hidden>\n {loadingMore ? (\n <span className=\"text-text-secondary text-[11px]\" role=\"status\">\n Loading more…\n </span>\n ) : null}\n </div>\n ) : null}\n </>\n )}\n </div>\n </>\n );\n\n return (\n <div className=\"relative shrink-0\">\n <button\n ref={buttonRef}\n type=\"button\"\n aria-label={\n selected != null ? `Filter chat history by agent (${selected.agentName})` : 'Filter chat history by agent'\n }\n aria-haspopup={useSheet ? 'dialog' : 'menu'}\n aria-expanded={open}\n aria-controls={open ? menuId : undefined}\n title=\"Filter by agent\"\n className={auiButtonClass({\n variant: 'ghost',\n size: 'icon',\n className: cn(\n 'relative size-7 shrink-0 text-text-secondary hover:bg-ghost-button-hover hover:text-ghost-button-text',\n selected != null && 'text-text-primary',\n ),\n })}\n onClick={() => setOpen(v => !v)}\n >\n <Icon name=\"funnel\" className=\"size-3.5\" />\n {selected != null ? (\n <span\n className=\"bg-primary-button-bg absolute top-1 right-1 size-1.5 rounded-full\"\n aria-hidden\n data-testid=\"history-filter-active-dot\"\n />\n ) : null}\n </button>\n {useSheet && open ? (\n <BottomSheet open onOpenChange={setOpen} id={menuId} aria-label=\"Filter agents\">\n <div className=\"flex min-h-0 flex-1 flex-col p-2\" role=\"menu\">\n {filterBody}\n </div>\n </BottomSheet>\n ) : null}\n {!useSheet && open && menuPos != null\n ? createPortal(\n <div\n ref={menuRef}\n id={menuId}\n role=\"menu\"\n aria-label=\"Filter agents\"\n style={{ top: menuPos.top, left: menuPos.left }}\n className=\"aui-popup-enter font-sans-flex fixed z-50 w-56 rounded-md border border-border bg-card-bg p-1 text-text-primary shadow-md\"\n >\n {filterBody}\n </div>,\n themePortalRoot(buttonRef.current),\n )\n : null}\n </div>\n );\n}\n"],"mappings":"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","names":["useEffect","useRef","useState","Fragment","jsx","jsxs","useState","useRef","useEffect"]}
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  getErrorMessage,
3
3
  useOptionalServer
4
- } from "./chunk-6CFZHEYH.js";
4
+ } from "./chunk-2GIZY3JJ.js";
5
5
 
6
6
  // src/atoms/lib/useSearchAgentsList.ts
7
7
  import { useCallback, useEffect as useEffect2, useRef, useState as useState2 } from "react";
@@ -19,8 +19,12 @@ function useDebouncedValue(value, delayMs) {
19
19
 
20
20
  // src/atoms/lib/useSearchAgentsList.ts
21
21
  var SEARCH_AGENTS_PAGE_SIZE = 50;
22
+ var SEARCH_AGENTS_PAGE_MAX = 100;
22
23
  var DEFAULT_DEBOUNCE_MS = 300;
23
24
  var LOAD_MORE_ROOT_MARGIN = "48px";
25
+ function clampPageSize(size) {
26
+ return Math.min(Math.max(size, 1), SEARCH_AGENTS_PAGE_MAX);
27
+ }
24
28
  async function searchAllAgents(server, offset = 0) {
25
29
  const rows = await server.searchAgents({ limit: SEARCH_AGENTS_PAGE_SIZE, offset });
26
30
  if (rows.length < SEARCH_AGENTS_PAGE_SIZE) return rows;
@@ -36,12 +40,23 @@ async function findAgentByName({
36
40
  if (match != null || rows.length < SEARCH_AGENTS_PAGE_SIZE) return match;
37
41
  return findAgentByName({ server, agentName, offset: offset + rows.length });
38
42
  }
43
+ async function findLibraryAgent({
44
+ server,
45
+ agentKey,
46
+ offset = 0
47
+ }) {
48
+ const rows = await server.searchAgents({ limit: SEARCH_AGENTS_PAGE_SIZE, offset });
49
+ const match = rows.find((agent) => agent.name === agentKey || agent.agentId === agentKey);
50
+ if (match != null || rows.length < SEARCH_AGENTS_PAGE_SIZE) return match;
51
+ return findLibraryAgent({ server, agentKey, offset: offset + rows.length });
52
+ }
39
53
  function useSearchAgentsList({
40
54
  enabled,
41
55
  query,
42
56
  refreshKey = 0,
43
- limit = SEARCH_AGENTS_PAGE_SIZE,
44
- debounceMs = DEFAULT_DEBOUNCE_MS
57
+ limit: limitOption = SEARCH_AGENTS_PAGE_SIZE,
58
+ debounceMs = DEFAULT_DEBOUNCE_MS,
59
+ mode = "infinite"
45
60
  }) {
46
61
  const server = useOptionalServer();
47
62
  const debouncedQuery = useDebouncedValue(query, enabled ? debounceMs : 0);
@@ -50,6 +65,8 @@ function useSearchAgentsList({
50
65
  const [loadingMore, setLoadingMore] = useState2(false);
51
66
  const [error, setError] = useState2(null);
52
67
  const [hasMore, setHasMore] = useState2(false);
68
+ const [pageSize, setPageSizeState] = useState2(() => clampPageSize(limitOption));
69
+ const [offset, setOffset] = useState2(0);
53
70
  const genRef = useRef(0);
54
71
  const loadMoreInflightRef = useRef(false);
55
72
  const hasMoreRef = useRef(false);
@@ -58,6 +75,7 @@ function useSearchAgentsList({
58
75
  const sentinelElRef = useRef(null);
59
76
  const [listEl, setListEl] = useState2(null);
60
77
  const [sentinelEl, setSentinelEl] = useState2(null);
78
+ const limit = mode === "paged" ? pageSize : clampPageSize(limitOption);
61
79
  hasMoreRef.current = hasMore;
62
80
  agentsLenRef.current = agents.length;
63
81
  const listRef = useCallback((node) => {
@@ -69,13 +87,18 @@ function useSearchAgentsList({
69
87
  setSentinelEl(node);
70
88
  }, []);
71
89
  const searchQuery = debouncedQuery.trim() || void 0;
90
+ useEffect2(() => {
91
+ if (mode !== "paged") return;
92
+ setOffset(0);
93
+ }, [mode, searchQuery, refreshKey]);
72
94
  useEffect2(() => {
73
95
  if (!enabled || server == null) return;
74
96
  const gen = ++genRef.current;
75
97
  loadMoreInflightRef.current = false;
76
98
  setLoading(true);
77
99
  setError(null);
78
- void server.searchAgents({ query: searchQuery, limit, offset: 0 }).then((rows) => {
100
+ const fetchOffset = mode === "paged" ? offset : 0;
101
+ void server.searchAgents({ query: searchQuery, limit, offset: fetchOffset }).then((rows) => {
79
102
  if (gen !== genRef.current) return;
80
103
  setAgents(rows);
81
104
  setHasMore(rows.length >= limit);
@@ -90,16 +113,17 @@ function useSearchAgentsList({
90
113
  return () => {
91
114
  genRef.current += 1;
92
115
  };
93
- }, [enabled, server, searchQuery, limit, refreshKey]);
116
+ }, [enabled, server, searchQuery, limit, refreshKey, mode, offset]);
94
117
  const loadMore = useCallback(() => {
118
+ if (mode !== "infinite") return;
95
119
  if (!enabled || server == null || !hasMoreRef.current || loadMoreInflightRef.current || loading) {
96
120
  return;
97
121
  }
98
122
  const gen = genRef.current;
99
- const offset = agentsLenRef.current;
123
+ const nextOffset = agentsLenRef.current;
100
124
  loadMoreInflightRef.current = true;
101
125
  setLoadingMore(true);
102
- void server.searchAgents({ query: searchQuery, limit, offset }).then((rows) => {
126
+ void server.searchAgents({ query: searchQuery, limit, offset: nextOffset }).then((rows) => {
103
127
  if (gen !== genRef.current) return;
104
128
  setAgents((prev) => [...prev, ...rows]);
105
129
  setHasMore(rows.length >= limit);
@@ -110,9 +134,9 @@ function useSearchAgentsList({
110
134
  loadMoreInflightRef.current = false;
111
135
  if (gen === genRef.current) setLoadingMore(false);
112
136
  });
113
- }, [enabled, server, searchQuery, limit, loading]);
137
+ }, [enabled, server, searchQuery, limit, loading, mode]);
114
138
  useEffect2(() => {
115
- if (!enabled || !hasMore || listEl == null || sentinelEl == null) return;
139
+ if (mode !== "infinite" || !enabled || !hasMore || listEl == null || sentinelEl == null) return;
116
140
  const observer = new IntersectionObserver(
117
141
  (entries) => {
118
142
  if (entries.some((entry) => entry.isIntersecting)) {
@@ -123,7 +147,19 @@ function useSearchAgentsList({
123
147
  );
124
148
  observer.observe(sentinelEl);
125
149
  return () => observer.disconnect();
126
- }, [enabled, hasMore, listEl, sentinelEl, loadMore, agents.length]);
150
+ }, [mode, enabled, hasMore, listEl, sentinelEl, loadMore, agents.length]);
151
+ const setPageSize = useCallback((size) => {
152
+ setPageSizeState(clampPageSize(size));
153
+ setOffset(0);
154
+ }, []);
155
+ const goNext = useCallback(() => {
156
+ if (mode !== "paged" || !hasMoreRef.current || loading) return;
157
+ setOffset((current) => current + pageSize);
158
+ }, [mode, loading, pageSize]);
159
+ const goPrev = useCallback(() => {
160
+ if (mode !== "paged" || loading) return;
161
+ setOffset((current) => Math.max(0, current - pageSize));
162
+ }, [mode, loading, pageSize]);
127
163
  return {
128
164
  agents,
129
165
  isInitialLoading: loading && agents.length === 0,
@@ -132,7 +168,13 @@ function useSearchAgentsList({
132
168
  error,
133
169
  hasMore,
134
170
  listRef,
135
- sentinelRef
171
+ sentinelRef,
172
+ pageSize,
173
+ setPageSize,
174
+ canPrev: mode === "paged" && offset > 0,
175
+ canNext: mode === "paged" && hasMore,
176
+ goPrev,
177
+ goNext
136
178
  };
137
179
  }
138
180
 
@@ -186,10 +228,11 @@ export {
186
228
  SEARCH_AGENTS_PAGE_SIZE,
187
229
  searchAllAgents,
188
230
  findAgentByName,
231
+ findLibraryAgent,
189
232
  useSearchAgentsList,
190
233
  readScheduleShareSearch,
191
234
  writeScheduleShareSearch,
192
235
  clearScheduleShareSearch,
193
236
  replaceScheduleShareSearch
194
237
  };
195
- //# sourceMappingURL=chunk-E4GVP6PM.js.map
238
+ //# sourceMappingURL=chunk-T6QQV5LK.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/atoms/lib/useSearchAgentsList.ts","../src/atoms/lib/useDebouncedValue.ts","../src/utils/scheduleShareUrl.ts"],"sourcesContent":["'use client';\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\n\nimport { useOptionalServer } from '../../server/ServerContext.js';\nimport type { AgentBuilderServer, AgentLibraryEntry } from '../../server/types.js';\nimport { getErrorMessage } from '../../utils/getErrorMessage.js';\nimport { useDebouncedValue } from './useDebouncedValue.js';\n\n/** Matches API AGENTS_PAGE_DEFAULT / AGENTS_PAGE_LIMIT. */\nexport const SEARCH_AGENTS_PAGE_SIZE = 50;\nexport const SEARCH_AGENTS_PAGE_MAX = 100;\nconst DEFAULT_DEBOUNCE_MS = 300;\nconst LOAD_MORE_ROOT_MARGIN = '48px';\n\nfunction clampPageSize(size: number): number {\n return Math.min(Math.max(size, 1), SEARCH_AGENTS_PAGE_MAX);\n}\n\n/** Drain every `searchAgents` page (offset pagination). */\nexport async function searchAllAgents(\n server: Pick<AgentBuilderServer, 'searchAgents'>,\n offset = 0,\n): Promise<AgentLibraryEntry[]> {\n const rows = await server.searchAgents({ limit: SEARCH_AGENTS_PAGE_SIZE, offset });\n if (rows.length < SEARCH_AGENTS_PAGE_SIZE) return rows;\n return [...rows, ...(await searchAllAgents(server, offset + rows.length))];\n}\n\n/** Exact-name lookup walks server-filtered pages until a precise match is found. */\nexport async function findAgentByName({\n server,\n agentName,\n offset = 0,\n}: {\n server: Pick<AgentBuilderServer, 'searchAgents'>;\n agentName: string;\n offset?: number;\n}): Promise<AgentLibraryEntry | undefined> {\n const rows = await server.searchAgents({ query: agentName, limit: SEARCH_AGENTS_PAGE_SIZE, offset });\n const match = rows.find(agent => agent.name === agentName);\n if (match != null || rows.length < SEARCH_AGENTS_PAGE_SIZE) return match;\n return findAgentByName({ server, agentName, offset: offset + rows.length });\n}\n\n/** Resolve by agent id or exact name by walking unfiltered pages (ids are not name-searchable). */\nexport async function findLibraryAgent({\n server,\n agentKey,\n offset = 0,\n}: {\n server: Pick<AgentBuilderServer, 'searchAgents'>;\n agentKey: string;\n offset?: number;\n}): Promise<AgentLibraryEntry | undefined> {\n const rows = await server.searchAgents({ limit: SEARCH_AGENTS_PAGE_SIZE, offset });\n const match = rows.find(agent => agent.name === agentKey || agent.agentId === agentKey);\n if (match != null || rows.length < SEARCH_AGENTS_PAGE_SIZE) return match;\n return findLibraryAgent({ server, agentKey, offset: offset + rows.length });\n}\n\nexport type UseSearchAgentsListOptions = {\n /** When false, no fetches run. */\n enabled: boolean;\n query: string;\n /** Bump to force a replace fetch (e.g. agentsListEpoch). */\n refreshKey?: number;\n /** Page size for infinite mode, or initial size for paged mode. Capped at 100. */\n limit?: number;\n debounceMs?: number;\n /**\n * `infinite` — append via IntersectionObserver sentinel (default).\n * `paged` — replace rows; navigate with goPrev / goNext.\n */\n mode?: 'infinite' | 'paged';\n};\n\nexport type UseSearchAgentsListResult = {\n agents: AgentLibraryEntry[];\n /** True while the replace fetch is in flight and the list is still empty. */\n isInitialLoading: boolean;\n /** True while replacing results that are already on screen (softer than a skeleton wipe). */\n isSearching: boolean;\n loadingMore: boolean;\n error: string | null;\n hasMore: boolean;\n listRef: (node: HTMLElement | null) => void;\n sentinelRef: (node: HTMLElement | null) => void;\n pageSize: number;\n setPageSize: (pageSize: number) => void;\n canPrev: boolean;\n canNext: boolean;\n goPrev: () => void;\n goNext: () => void;\n};\n\n/**\n * Debounced `searchAgents` with offset pagination.\n * Infinite mode: attach `listRef` / `sentinelRef` for IntersectionObserver load-more.\n * Paged mode: use `goPrev` / `goNext` / `setPageSize` (rows replaced each fetch).\n */\nexport function useSearchAgentsList({\n enabled,\n query,\n refreshKey = 0,\n limit: limitOption = SEARCH_AGENTS_PAGE_SIZE,\n debounceMs = DEFAULT_DEBOUNCE_MS,\n mode = 'infinite',\n}: UseSearchAgentsListOptions): UseSearchAgentsListResult {\n const server = useOptionalServer();\n // While closed, sync immediately so reopen never fetches a stale query.\n const debouncedQuery = useDebouncedValue(query, enabled ? debounceMs : 0);\n\n const [agents, setAgents] = useState<AgentLibraryEntry[]>([]);\n const [loading, setLoading] = useState(false);\n const [loadingMore, setLoadingMore] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [hasMore, setHasMore] = useState(false);\n const [pageSize, setPageSizeState] = useState(() => clampPageSize(limitOption));\n const [offset, setOffset] = useState(0);\n\n const genRef = useRef(0);\n const loadMoreInflightRef = useRef(false);\n const hasMoreRef = useRef(false);\n const agentsLenRef = useRef(0);\n const listElRef = useRef<HTMLElement | null>(null);\n const sentinelElRef = useRef<HTMLElement | null>(null);\n const [listEl, setListEl] = useState<HTMLElement | null>(null);\n const [sentinelEl, setSentinelEl] = useState<HTMLElement | null>(null);\n\n const limit = mode === 'paged' ? pageSize : clampPageSize(limitOption);\n\n hasMoreRef.current = hasMore;\n agentsLenRef.current = agents.length;\n\n const listRef = useCallback((node: HTMLElement | null) => {\n listElRef.current = node;\n setListEl(node);\n }, []);\n\n const sentinelRef = useCallback((node: HTMLElement | null) => {\n sentinelElRef.current = node;\n setSentinelEl(node);\n }, []);\n\n const searchQuery = debouncedQuery.trim() || undefined;\n\n // Reset to first page when the query or catalog epoch changes.\n useEffect(() => {\n if (mode !== 'paged') return;\n setOffset(0);\n }, [mode, searchQuery, refreshKey]);\n\n useEffect(() => {\n if (!enabled || server == null) return;\n\n const gen = ++genRef.current;\n loadMoreInflightRef.current = false;\n setLoading(true);\n setError(null);\n\n const fetchOffset = mode === 'paged' ? offset : 0;\n\n void server\n .searchAgents({ query: searchQuery, limit, offset: fetchOffset })\n .then(rows => {\n if (gen !== genRef.current) return;\n setAgents(rows);\n setHasMore(rows.length >= limit);\n })\n .catch((err: unknown) => {\n if (gen !== genRef.current) return;\n setAgents([]);\n setHasMore(false);\n setError(getErrorMessage(err, 'Failed to load agents.'));\n })\n .finally(() => {\n if (gen === genRef.current) setLoading(false);\n });\n\n return () => {\n genRef.current += 1;\n };\n }, [enabled, server, searchQuery, limit, refreshKey, mode, offset]);\n\n const loadMore = useCallback(() => {\n if (mode !== 'infinite') return;\n if (!enabled || server == null || !hasMoreRef.current || loadMoreInflightRef.current || loading) {\n return;\n }\n\n const gen = genRef.current;\n const nextOffset = agentsLenRef.current;\n loadMoreInflightRef.current = true;\n setLoadingMore(true);\n\n void server\n .searchAgents({ query: searchQuery, limit, offset: nextOffset })\n .then(rows => {\n if (gen !== genRef.current) return;\n setAgents(prev => [...prev, ...rows]);\n setHasMore(rows.length >= limit);\n })\n .catch(() => {\n if (gen !== genRef.current) return;\n setHasMore(false);\n })\n .finally(() => {\n loadMoreInflightRef.current = false;\n if (gen === genRef.current) setLoadingMore(false);\n });\n }, [enabled, server, searchQuery, limit, loading, mode]);\n\n useEffect(() => {\n if (mode !== 'infinite' || !enabled || !hasMore || listEl == null || sentinelEl == null) return;\n\n const observer = new IntersectionObserver(\n entries => {\n if (entries.some(entry => entry.isIntersecting)) {\n loadMore();\n }\n },\n { root: listEl, rootMargin: LOAD_MORE_ROOT_MARGIN },\n );\n observer.observe(sentinelEl);\n return () => observer.disconnect();\n }, [mode, enabled, hasMore, listEl, sentinelEl, loadMore, agents.length]);\n\n const setPageSize = useCallback((size: number) => {\n setPageSizeState(clampPageSize(size));\n setOffset(0);\n }, []);\n\n const goNext = useCallback(() => {\n if (mode !== 'paged' || !hasMoreRef.current || loading) return;\n setOffset(current => current + pageSize);\n }, [mode, loading, pageSize]);\n\n const goPrev = useCallback(() => {\n if (mode !== 'paged' || loading) return;\n setOffset(current => Math.max(0, current - pageSize));\n }, [mode, loading, pageSize]);\n\n return {\n agents,\n isInitialLoading: loading && agents.length === 0,\n isSearching: loading && agents.length > 0,\n loadingMore,\n error,\n hasMore,\n listRef,\n sentinelRef,\n pageSize,\n setPageSize,\n canPrev: mode === 'paged' && offset > 0,\n canNext: mode === 'paged' && hasMore,\n goPrev,\n goNext,\n };\n}\n","'use client';\n\nimport { useEffect, useState } from 'react';\n\n/** Returns `value` immediately on first render; subsequent changes apply after `delayMs`. */\nexport function useDebouncedValue<T>(value: T, delayMs: number): T {\n const [debounced, setDebounced] = useState(value);\n\n useEffect(() => {\n const id = window.setTimeout(() => setDebounced(value), delayMs);\n return () => window.clearTimeout(id);\n }, [value, delayMs]);\n\n return debounced;\n}\n","import type { ScheduleStatus } from '../server/types.js';\nimport { writeSessionShareSearch } from './sessionShareUrl.js';\n\nexport const SCHEDULE_AGENT_QUERY = 'agent';\nexport const SCHEDULE_STATUS_QUERY = 'status';\nexport const SCHEDULE_NAME_QUERY = 'q';\nexport const SCHEDULE_IS_NEW_QUERY = 'isNew';\n\nexport const SCHEDULE_SHARE_CHANGE_EVENT = 'trueforge-schedule-share';\n\nexport type ScheduleShareSearch = {\n /** Agent id filter; `null` means all agents. */\n agent: string | null;\n /** Status filter; `null` means all statuses. */\n status: ScheduleStatus | null;\n /** Name search; `null` when empty. */\n q: string | null;\n /** One-shot flag to open the create schedule drawer. */\n isNew: boolean;\n};\n\nexport type ScheduleShareWrite = {\n agent?: string | null;\n status?: ScheduleStatus | null;\n q?: string | null;\n isNew?: boolean | null;\n};\n\nfunction nonEmpty(value: string | null): string | null {\n return value != null && value.length > 0 ? value : null;\n}\n\nfunction parseStatus(value: string | null): ScheduleStatus | null {\n if (value === 'active' || value === 'paused') return value;\n return null;\n}\n\nexport function readScheduleShareSearch(search: string): ScheduleShareSearch {\n const params = new URLSearchParams(search.startsWith('?') ? search.slice(1) : search);\n return {\n agent: nonEmpty(params.get(SCHEDULE_AGENT_QUERY)),\n status: parseStatus(params.get(SCHEDULE_STATUS_QUERY)),\n q: nonEmpty(params.get(SCHEDULE_NAME_QUERY)),\n isNew: params.get(SCHEDULE_IS_NEW_QUERY) === 'true',\n };\n}\n\nexport function writeScheduleShareSearch(params: URLSearchParams, next: ScheduleShareWrite): void {\n if (next.agent === null) params.delete(SCHEDULE_AGENT_QUERY);\n else if (next.agent != null) params.set(SCHEDULE_AGENT_QUERY, next.agent);\n if (next.status === null) params.delete(SCHEDULE_STATUS_QUERY);\n else if (next.status != null) params.set(SCHEDULE_STATUS_QUERY, next.status);\n if (next.q === null) params.delete(SCHEDULE_NAME_QUERY);\n else if (next.q != null) params.set(SCHEDULE_NAME_QUERY, next.q);\n if (next.isNew === null || next.isNew === false) params.delete(SCHEDULE_IS_NEW_QUERY);\n else if (next.isNew === true) params.set(SCHEDULE_IS_NEW_QUERY, 'true');\n}\n\n/** Drop all schedules-owned query keys (used when leaving the schedules place). */\nexport function clearScheduleShareSearch(params: URLSearchParams): void {\n params.delete(SCHEDULE_AGENT_QUERY);\n params.delete(SCHEDULE_STATUS_QUERY);\n params.delete(SCHEDULE_NAME_QUERY);\n params.delete(SCHEDULE_IS_NEW_QUERY);\n}\n\nexport function replaceScheduleShareSearch(next: ScheduleShareWrite): string {\n const url = new URL(window.location.href);\n writeScheduleShareSearch(url.searchParams, next);\n window.history.replaceState(window.history.state, '', url);\n window.dispatchEvent(new Event(SCHEDULE_SHARE_CHANGE_EVENT));\n return url.search;\n}\n\n/**\n * Point the address bar at schedules filtered to `agentId` (clears library agent\n * share keys). Caller still opens the schedules place via shell.\n */\nexport function writeOpenSchedulesForAgentSearch({ agentId, isNew }: { agentId: string; isNew?: boolean }): void {\n const url = new URL(window.location.href);\n writeSessionShareSearch(url.searchParams, {\n sessionId: null,\n agentId: null,\n tab: null,\n view: null,\n timeRange: null,\n });\n writeScheduleShareSearch(url.searchParams, {\n agent: agentId,\n status: null,\n q: null,\n isNew: isNew === true ? true : null,\n });\n window.history.replaceState(window.history.state, '', url);\n}\n"],"mappings":"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","names":["useEffect","useState","useState","useEffect"]}