@truefoundry/trueforge-ui 0.3.0-rc.0 → 0.3.0-rc.2
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.
- package/CHANGELOG.md +68 -0
- package/README.md +21 -6
- package/dist/AgentCodeSnippets-637HQUXD.js +74 -0
- package/dist/AgentCodeSnippets-637HQUXD.js.map +1 -0
- package/dist/AgentMetricChart-4FYECRIN.js +15 -0
- package/dist/AgentOverview-3FJ5EE6N.js +167 -0
- package/dist/AgentOverview-3FJ5EE6N.js.map +1 -0
- package/dist/AgentSessionEventTimeline-VELWUYPR.js +88 -0
- package/dist/AgentSessionEventTimeline-VELWUYPR.js.map +1 -0
- package/dist/AgentSessionEventTimelineChart-CUKETHWM.js +591 -0
- package/dist/AgentSessionEventTimelineChart-CUKETHWM.js.map +1 -0
- package/dist/AgentSessions-T7MOGOTZ.js +275 -0
- package/dist/AgentSessions-T7MOGOTZ.js.map +1 -0
- package/dist/{ConnectorSettings-FXQ5B7TN.js → ConnectorSettings-ESZ2RSRG.js} +19 -21
- package/dist/ConnectorSettings-ESZ2RSRG.js.map +1 -0
- package/dist/{DockLayout-LBNQJZNF.js → DockLayout-NLFNU6F2.js} +11 -10
- package/dist/{DockLayout-LBNQJZNF.js.map → DockLayout-NLFNU6F2.js.map} +1 -1
- package/dist/DrawerLayout-PR3SMKA6.js +184 -0
- package/dist/DrawerLayout-PR3SMKA6.js.map +1 -0
- package/dist/{ModelSettings-4L4LOQJA.js → ModelSettings-LYW64IRR.js} +20 -24
- package/dist/ModelSettings-LYW64IRR.js.map +1 -0
- package/dist/OpenUiFenceBlock-JEPNPJ7U.js +9 -0
- package/dist/OpenUiFenceBlock-JEPNPJ7U.js.map +1 -0
- package/dist/{SandboxSettings-Z4ZG6ZX4.js → SandboxSettings-DF64LHYI.js} +16 -18
- package/dist/SandboxSettings-DF64LHYI.js.map +1 -0
- package/dist/SchedulesPage-WQU4H25F.js +15 -0
- package/dist/SchedulesPage-WQU4H25F.js.map +1 -0
- package/dist/{SettingsBuilder-WF7ZWKQW.js → SettingsBuilder-LSXK2VN4.js} +26 -22
- package/dist/SettingsBuilder-LSXK2VN4.js.map +1 -0
- package/dist/ShellRouteSync-B22IAV2W.js +255 -0
- package/dist/ShellRouteSync-B22IAV2W.js.map +1 -0
- package/dist/SidebarLayout-XW6LXB7R.js +309 -0
- package/dist/SidebarLayout-XW6LXB7R.js.map +1 -0
- package/dist/{SkillSettings-3EPPC3IT.js → SkillSettings-64VXUO6J.js} +14 -15
- package/dist/SkillSettings-64VXUO6J.js.map +1 -0
- package/dist/{TrueForgeUIWithRouter-NZ4FGPE4.js → TrueForgeUIWithRouter-3TSLV22Q.js} +14 -10
- package/dist/{TrueForgeUIWithRouter-NZ4FGPE4.js.map → TrueForgeUIWithRouter-3TSLV22Q.js.map} +1 -1
- package/dist/{WidgetLayout-3QZ357FL.js → WidgetLayout-Q5P7PYSJ.js} +17 -13
- package/dist/WidgetLayout-Q5P7PYSJ.js.map +1 -0
- package/dist/chunk-5I2COQNL.js +119 -0
- package/dist/chunk-5I2COQNL.js.map +1 -0
- package/dist/chunk-BWHOZFIV.js +587 -0
- package/dist/chunk-BWHOZFIV.js.map +1 -0
- package/dist/chunk-DJUFS2BW.js +27 -0
- package/dist/chunk-DJUFS2BW.js.map +1 -0
- package/dist/chunk-FQK2XVVE.js +880 -0
- package/dist/chunk-FQK2XVVE.js.map +1 -0
- package/dist/chunk-G2TUAD65.js +555 -0
- package/dist/chunk-G2TUAD65.js.map +1 -0
- package/dist/chunk-GXYAOAK5.js +1357 -0
- package/dist/chunk-GXYAOAK5.js.map +1 -0
- package/dist/{chunk-FJ5RSSMA.js → chunk-H6WTY5PM.js} +196 -32
- package/dist/chunk-H6WTY5PM.js.map +1 -0
- package/dist/chunk-I3AL54MA.js +180 -0
- package/dist/chunk-I3AL54MA.js.map +1 -0
- package/dist/{chunk-WREC7D54.js → chunk-LGRHHFHN.js} +120 -32
- package/dist/chunk-LGRHHFHN.js.map +1 -0
- package/dist/chunk-NHHSZB5N.js +74 -0
- package/dist/chunk-NHHSZB5N.js.map +1 -0
- package/dist/{chunk-CFLVPV5M.js → chunk-QC42MLAK.js} +7 -2
- package/dist/chunk-QC42MLAK.js.map +1 -0
- package/dist/chunk-RDXBMTP5.js +32 -0
- package/dist/chunk-RDXBMTP5.js.map +1 -0
- package/dist/chunk-SFZNIO6U.js +18 -0
- package/dist/chunk-SFZNIO6U.js.map +1 -0
- package/dist/chunk-SQGT43Z3.js +200 -0
- package/dist/chunk-SQGT43Z3.js.map +1 -0
- package/dist/{chunk-B52K63AW.js → chunk-VJ7BZGAF.js} +2 -2
- package/dist/chunk-VUMGMGKZ.js +252 -0
- package/dist/chunk-VUMGMGKZ.js.map +1 -0
- package/dist/chunk-Y6S4OVVQ.js +16 -0
- package/dist/chunk-Y6S4OVVQ.js.map +1 -0
- package/dist/chunk-YQO2NMJ3.js +13341 -0
- package/dist/chunk-YQO2NMJ3.js.map +1 -0
- package/dist/{createTrueFoundryServer-B72bU-J7.d.ts → createTrueFoundryServer-CmZnBh_l.d.ts} +15 -4
- package/dist/index.d.ts +1024 -24
- package/dist/index.js +691 -67
- package/dist/index.js.map +1 -1
- package/dist/plugins/trueforge-agent-server-adapter/index.d.ts +552 -8
- package/dist/plugins/trueforge-agent-server-adapter/index.js +504 -188
- package/dist/plugins/trueforge-agent-server-adapter/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +9 -8
- package/dist/ConnectorSettings-FXQ5B7TN.js.map +0 -1
- package/dist/DrawerLayout-Q6UK4VMI.js +0 -159
- package/dist/DrawerLayout-Q6UK4VMI.js.map +0 -1
- package/dist/ModelSettings-4L4LOQJA.js.map +0 -1
- package/dist/OpenUiFenceBlock-6UIIAVBX.js +0 -9
- package/dist/SandboxSettings-Z4ZG6ZX4.js.map +0 -1
- package/dist/SettingsBuilder-WF7ZWKQW.js.map +0 -1
- package/dist/ShellRouteSync-T4WLY57Q.js +0 -172
- package/dist/ShellRouteSync-T4WLY57Q.js.map +0 -1
- package/dist/SidebarLayout-3WZ3CVON.js +0 -256
- package/dist/SidebarLayout-3WZ3CVON.js.map +0 -1
- package/dist/SkillSettings-3EPPC3IT.js.map +0 -1
- package/dist/WidgetLayout-3QZ357FL.js.map +0 -1
- package/dist/chunk-36KOSC2J.js +0 -567
- package/dist/chunk-36KOSC2J.js.map +0 -1
- package/dist/chunk-3S6KHO7H.js +0 -2121
- package/dist/chunk-3S6KHO7H.js.map +0 -1
- package/dist/chunk-7L63OK3O.js +0 -91
- package/dist/chunk-7L63OK3O.js.map +0 -1
- package/dist/chunk-CFLVPV5M.js.map +0 -1
- package/dist/chunk-FJ5RSSMA.js.map +0 -1
- package/dist/chunk-OSV3HI5M.js +0 -6891
- package/dist/chunk-OSV3HI5M.js.map +0 -1
- package/dist/chunk-WQULF5AT.js +0 -460
- package/dist/chunk-WQULF5AT.js.map +0 -1
- package/dist/chunk-WREC7D54.js.map +0 -1
- package/dist/chunk-YIWUG6MC.js +0 -101
- package/dist/chunk-YIWUG6MC.js.map +0 -1
- package/dist/chunk-ZXOADNF3.js +0 -75
- package/dist/chunk-ZXOADNF3.js.map +0 -1
- /package/dist/{OpenUiFenceBlock-6UIIAVBX.js.map → AgentMetricChart-4FYECRIN.js.map} +0 -0
- /package/dist/{chunk-B52K63AW.js.map → chunk-VJ7BZGAF.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/containers/SettingsBuilder/SandboxSettings.tsx","../src/containers/SettingsBuilder/ConfigureSandboxForm.tsx"],"sourcesContent":["'use client';\n\nimport { useCallback, useEffect, useMemo, useState } from 'react';\n\nimport { Spinner } from '@/atoms/primitives/Spinner.js';\nimport { Button } from '../../atoms/primitives/Button.js';\nimport { Tooltip } from '../../atoms/primitives/Tooltip.js';\nimport { Icon } from '../../icons/Icon.js';\nimport { useCatalogServer } from '../../server/ServerContext.js';\nimport type {\n SandboxProviderBase,\n SandboxProviderCatalogEntry,\n SandboxProviderConfig,\n SandboxProviderListEntry,\n SandboxSnapshotSyncStatus,\n} from '../../server/types.js';\nimport { getErrorMessage } from '../../utils/getErrorMessage.js';\nimport { useToasterOptional } from '../ToasterContainer.js';\nimport ConfigureSandboxForm, { type SandboxConfigDraft } from './ConfigureSandboxForm.js';\n\nconst SNAPSHOT_STATUS_POLL_INTERVAL_MS = 10000;\n\nconst configFrom = ({\n execTimeoutMs,\n autoStopIntervalInMinutes,\n autoArchiveIntervalInMinutes,\n autoDeleteIntervalInMinutes,\n}: SandboxProviderConfig): SandboxProviderConfig => ({\n execTimeoutMs,\n autoStopIntervalInMinutes,\n autoArchiveIntervalInMinutes,\n autoDeleteIntervalInMinutes,\n});\n\nconst statusPresentation = (status: SandboxSnapshotSyncStatus['status']): { label: string; className: string } => {\n switch (status) {\n case 'pending':\n return {\n label: 'Syncing image...',\n className: 'text-warning-bg',\n };\n case 'ready':\n return {\n label: 'Connected',\n className: 'text-success-bg',\n };\n case 'failed':\n return {\n label: 'Sync failed',\n className: 'text-failure-bg',\n };\n default:\n return {\n label: status,\n className: 'text-text-secondary',\n };\n }\n};\n\nconst SandboxSettings = () => {\n const { sandboxCatalog } = useCatalogServer();\n const toaster = useToasterOptional();\n\n const [providers, setProviders] = useState<SandboxProviderListEntry[]>([]);\n const [catalog, setCatalog] = useState<SandboxProviderCatalogEntry[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [formError, setFormError] = useState<string | null>(null);\n const [busy, setBusy] = useState(false);\n\n const [createEntry, setCreateEntry] = useState<SandboxProviderCatalogEntry | null>(null);\n const [updateProvider, setUpdateProvider] = useState<SandboxProviderBase | null>(null);\n\n const refresh = useCallback(\n async ({ quiet = false }: { quiet?: boolean } = {}) => {\n if (!sandboxCatalog) return;\n if (!quiet) setLoading(true);\n setError(null);\n try {\n const [listed, available] = await Promise.all([\n sandboxCatalog.listSandboxProviders(),\n sandboxCatalog.getSandboxProviderCatalog(),\n ]);\n setProviders(listed);\n setCatalog(available);\n } catch (err) {\n setError(getErrorMessage(err, 'Failed to load sandbox providers'));\n } finally {\n if (!quiet) setLoading(false);\n }\n },\n [sandboxCatalog],\n );\n\n useEffect(() => {\n void refresh();\n }, [refresh]);\n\n const hasPendingProvider = providers.some(entry => entry.snapshotSyncStatus.status === 'pending');\n\n useEffect(() => {\n if (!sandboxCatalog || !hasPendingProvider) return;\n const activeSandboxCatalog = sandboxCatalog;\n\n let cancelled = false;\n let timeoutId: number | undefined;\n\n function schedulePoll() {\n timeoutId = window.setTimeout(() => {\n void poll();\n }, SNAPSHOT_STATUS_POLL_INTERVAL_MS);\n }\n\n async function poll() {\n try {\n const listed = await activeSandboxCatalog.listSandboxProviders();\n if (cancelled) return;\n setProviders(listed);\n setError(null);\n if (listed.some(entry => entry.snapshotSyncStatus.status === 'pending')) {\n schedulePoll();\n }\n } catch (err) {\n if (cancelled) return;\n setError(getErrorMessage(err, 'Failed to refresh sandbox providers'));\n schedulePoll();\n }\n }\n\n schedulePoll();\n return () => {\n cancelled = true;\n if (timeoutId !== undefined) {\n window.clearTimeout(timeoutId);\n }\n };\n }, [sandboxCatalog, hasPendingProvider]);\n\n // Tenant/UI-wide: only one sandbox provider may be configured at a time.\n const hasConfiguredProvider = providers.length > 0;\n const availableEntries = useMemo(() => {\n if (hasConfiguredProvider) return [];\n const connectedCatalogIds = new Set(providers.map(provider => provider.data.catalogId));\n return catalog.filter(entry => !connectedCatalogIds.has(entry.id));\n }, [catalog, providers, hasConfiguredProvider]);\n\n const formInitialConfig = useMemo(\n () => (updateProvider ? configFrom(updateProvider) : createEntry ? configFrom(createEntry) : null),\n [updateProvider, createEntry],\n );\n\n if (!sandboxCatalog) {\n return <p className=\"text-sm text-text-secondary\">Sandbox provider catalog is not available.</p>;\n }\n\n const runMutation = async (fn: () => Promise<void>, setMutationError = setError) => {\n setBusy(true);\n setError(null);\n try {\n await fn();\n await refresh({ quiet: true });\n } catch (err) {\n setMutationError(getErrorMessage(err, 'Request failed'));\n throw err;\n } finally {\n setBusy(false);\n }\n };\n\n const handleCreate = async (draft: SandboxConfigDraft) => {\n if (!createEntry) return;\n setFormError(null);\n await runMutation(async () => {\n await sandboxCatalog.createSandboxProvider({\n catalogId: createEntry.id,\n name: createEntry.name,\n type: createEntry.type,\n ...configFrom(draft),\n apiKey: draft.apiKey,\n });\n }, setFormError);\n setCreateEntry(null);\n setTimeout(() => {\n toaster?.showSuccess({ title: `${createEntry.name} configured` });\n }, 0);\n };\n\n const handleUpdate = async (draft: SandboxConfigDraft) => {\n if (!updateProvider) return;\n setFormError(null);\n await runMutation(async () => {\n await sandboxCatalog.updateSandboxProvider({\n id: updateProvider.id,\n ...configFrom(draft),\n ...(draft.apiKey ? { apiKey: draft.apiKey } : {}),\n });\n }, setFormError);\n setUpdateProvider(null);\n setTimeout(() => {\n toaster?.showSuccess({ title: `${updateProvider.name} updated` });\n }, 0);\n };\n\n const handleRetry = (provider: SandboxProviderBase) => {\n void runMutation(async () => {\n await sandboxCatalog.updateSandboxProvider({\n id: provider.id,\n ...configFrom(provider),\n });\n }).catch(() => {});\n };\n\n const handleRemove = (provider: SandboxProviderBase) => {\n const deleteSandboxProvider = sandboxCatalog.deleteSandboxProvider;\n if (!deleteSandboxProvider) return;\n void runMutation(async () => {\n await deleteSandboxProvider({ id: provider.id });\n }).catch(() => {});\n };\n\n const formOpen = createEntry != null || updateProvider != null;\n const isUpdate = updateProvider != null;\n const formTitle = updateProvider\n ? `Update ${updateProvider.name}`\n : createEntry\n ? `Configure ${createEntry.name}`\n : 'Configure sandbox provider';\n\n return (\n <>\n <h3 className=\"text-xl font-semibold tracking-tight text-text-primary\">Sandbox providers</h3>\n <p className=\"mt-1 text-sm text-text-secondary\">\n Choose a provider that runs sandboxes for code, files and shell commands. Only one can be active at a time.\n </p>\n\n {error ? (\n <p className=\"mt-3 rounded-md border border-failure-bg/30 bg-failure-bg/10 px-3 py-2 text-sm text-failure-bg\">\n {error}\n </p>\n ) : null}\n\n <div className=\"mt-4 flex-1 overflow-y-auto\">\n {loading ? (\n <p className=\"text-sm text-text-secondary\">Loading sandbox providers…</p>\n ) : (\n <div className=\"space-y-6\">\n {providers.length > 0 ? (\n <section>\n <h4 className=\"mb-2 text-xs font-semibold uppercase tracking-wide text-text-secondary\">\n Configured · {providers.length}\n </h4>\n <div className=\"overflow-hidden rounded-xl border border-border bg-card-bg\">\n {providers.map(entry => {\n const provider = entry.data;\n const status = statusPresentation(entry.snapshotSyncStatus.status);\n const statusReason = entry.snapshotSyncStatus.statusReason;\n const statusIndicator = (\n <span className={`inline-flex items-center gap-1.5 text-sm font-medium ${status.className}`}>\n {entry.snapshotSyncStatus.status === 'pending' ? (\n <Spinner size={16} aria-label=\"Syncing snapshot image\" />\n ) : entry.snapshotSyncStatus.status === 'ready' ? (\n <span className=\"size-2 rounded-full bg-success-bg\" aria-hidden />\n ) : entry.snapshotSyncStatus.status === 'failed' ? (\n <Icon name=\"triangle-exclamation\" className=\"size-4\" />\n ) : null}\n {status.label}\n </span>\n );\n return (\n <article\n key={provider.id}\n className=\"flex flex-col gap-3 border-b border-border p-3 last:border-b-0 sm:flex-row sm:items-center\"\n >\n <div className=\"flex min-w-0 flex-1 items-center gap-3\">\n <span\n className=\"flex size-9 shrink-0 items-center justify-center rounded-lg border border-border bg-secondary-bg text-text-primary\"\n aria-hidden\n >\n <Icon name=\"cube\" className=\"size-4.5\" />\n </span>\n <div className=\"min-w-0\">\n <h5 className=\"truncate text-sm font-medium text-text-primary\">{provider.name}</h5>\n </div>\n </div>\n\n <div className=\"flex flex-wrap items-center gap-2.5 sm:justify-end\">\n {statusIndicator}\n {statusReason ? (\n <Tooltip content={statusReason}>\n <button\n type=\"button\"\n aria-label=\"Snapshot sync status details\"\n className=\"inline-flex text-text-secondary transition-colors hover:text-text-primary\"\n >\n <Icon name=\"info\" className=\"size-4\" />\n </button>\n </Tooltip>\n ) : null}\n {entry.snapshotSyncStatus.status === 'failed' ? (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n type=\"button\"\n disabled={busy}\n onClick={() => {\n handleRetry(provider);\n }}\n >\n Retry\n </Button>\n ) : null}\n <Button\n variant=\"secondary\"\n size=\"sm\"\n type=\"button\"\n disabled={busy}\n onClick={() => {\n setFormError(null);\n setCreateEntry(null);\n setUpdateProvider(provider);\n }}\n >\n Update\n </Button>\n\n {sandboxCatalog.deleteSandboxProvider ? (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"text-text-secondary\"\n type=\"button\"\n disabled={busy}\n onClick={() => {\n handleRemove(provider);\n }}\n >\n Remove\n </Button>\n ) : null}\n </div>\n </article>\n );\n })}\n </div>\n </section>\n ) : null}\n\n {!hasConfiguredProvider ? (\n <section>\n <h4 className=\"mb-2 text-xs font-semibold uppercase tracking-wide text-text-secondary\">\n Available · {availableEntries.length}\n </h4>\n {availableEntries.length === 0 ? (\n <p className=\"text-sm text-text-secondary\">\n {catalog.length > 0\n ? 'All catalog providers are configured.'\n : 'No sandbox providers in the catalog.'}\n </p>\n ) : (\n <div className=\"overflow-hidden rounded-xl border border-border bg-card-bg\">\n {availableEntries.map(entry => (\n <article\n key={entry.id}\n className=\"flex flex-col gap-3 border-b border-border p-3 last:border-b-0 sm:flex-row sm:items-center\"\n >\n <div className=\"flex min-w-0 flex-1 items-center gap-3\">\n <span\n className=\"flex size-9 shrink-0 items-center justify-center rounded-lg border border-border bg-secondary-bg text-text-primary\"\n aria-hidden\n >\n <Icon name=\"cube\" className=\"size-4.5\" />\n </span>\n <div className=\"min-w-0\">\n <h5 className=\"truncate text-sm font-medium text-text-primary\">{entry.name}</h5>\n </div>\n </div>\n\n <Button\n variant=\"secondary\"\n type=\"button\"\n disabled={busy}\n onClick={() => {\n setFormError(null);\n setUpdateProvider(null);\n setCreateEntry(entry);\n }}\n >\n Configure\n </Button>\n </article>\n ))}\n </div>\n )}\n </section>\n ) : null}\n </div>\n )}\n </div>\n\n <ConfigureSandboxForm\n open={formOpen}\n onOpenChange={open => {\n if (!open) {\n setFormError(null);\n setCreateEntry(null);\n setUpdateProvider(null);\n }\n }}\n onSave={isUpdate ? handleUpdate : handleCreate}\n title={formTitle}\n description={\n isUpdate\n ? 'Update this sandbox provider. Leave API key blank to keep the existing key.'\n : 'Configure this sandbox provider. API key is never stored in the catalog.'\n }\n initialConfig={formInitialConfig}\n requireApiKey={!isUpdate}\n busy={busy}\n error={formError}\n />\n </>\n );\n};\n\nexport default SandboxSettings;\n","'use client';\n\nimport { useEffect, useState, type FormEvent } from 'react';\n\nimport { cn } from '../../atoms/lib/cn.js';\nimport { auiInputClass } from '../../atoms/lib/inputClasses.js';\nimport { Accordion, AccordionDetails, AccordionSummary } from '../../atoms/primitives/Accordion.js';\nimport { Button } from '../../atoms/primitives/Button.js';\nimport { CenteredModal } from '../../atoms/primitives/CenteredModal.js';\nimport { Icon } from '../../icons/Icon.js';\nimport type { SandboxProviderConfig } from '../../server/types.js';\n\nexport type SandboxConfigDraft = SandboxProviderConfig & {\n apiKey: string;\n};\n\ntype ConfigureSandboxFormProps = {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n onSave: (draft: SandboxConfigDraft) => void | Promise<void>;\n title: string;\n description?: string;\n /** Prefills config fields; apiKey is never autofilled. */\n initialConfig?: SandboxProviderConfig | null;\n /** When false (updates), empty apiKey means keep the existing key. */\n requireApiKey?: boolean;\n busy?: boolean;\n error?: string | null;\n};\n\n/** Sensible defaults so the advanced fields are never blank, even without a catalog preset. */\nconst EMPTY_CONFIG: SandboxProviderConfig = {\n // Snapshot/image is release-owned now; kept only to satisfy the external SandboxProviderConfig type.\n execTimeoutMs: 300000,\n autoStopIntervalInMinutes: 15,\n autoArchiveIntervalInMinutes: 10080,\n autoDeleteIntervalInMinutes: 43200,\n};\n\nconst inputClassName = auiInputClass('h-11 shadow-sm');\n\nfunction parseNonNegInt(raw: string): number | null {\n if (raw.trim() === '') return null;\n const n = Number(raw);\n if (!Number.isFinite(n) || n < 0) return null;\n return n;\n}\n\nconst ConfigureSandboxForm = ({\n open,\n onOpenChange,\n onSave,\n title,\n description,\n initialConfig = null,\n requireApiKey = true,\n busy = false,\n error,\n}: ConfigureSandboxFormProps) => {\n const [execTimeoutMs, setExecTimeoutMs] = useState('');\n const [autoStopIntervalInMinutes, setAutoStopIntervalInMinutes] = useState('');\n const [autoArchiveIntervalInMinutes, setAutoArchiveIntervalInMinutes] = useState('');\n const [autoDeleteIntervalInMinutes, setAutoDeleteIntervalInMinutes] = useState('');\n const [apiKey, setApiKey] = useState('');\n const [advancedOpen, setAdvancedOpen] = useState(false);\n\n const resetForm = () => {\n setExecTimeoutMs('');\n setAutoStopIntervalInMinutes('');\n setAutoArchiveIntervalInMinutes('');\n setAutoDeleteIntervalInMinutes('');\n setApiKey('');\n setAdvancedOpen(false);\n };\n\n useEffect(() => {\n if (!open) return;\n const config = initialConfig ?? EMPTY_CONFIG;\n setExecTimeoutMs(String(config.execTimeoutMs));\n setAutoStopIntervalInMinutes(String(config.autoStopIntervalInMinutes));\n setAutoArchiveIntervalInMinutes(String(config.autoArchiveIntervalInMinutes));\n setAutoDeleteIntervalInMinutes(String(config.autoDeleteIntervalInMinutes));\n setApiKey('');\n setAdvancedOpen(false);\n }, [open, initialConfig]);\n\n const handleOpenChange = (nextOpen: boolean) => {\n if (!nextOpen) resetForm();\n onOpenChange(nextOpen);\n };\n\n const execTimeout = parseNonNegInt(execTimeoutMs);\n const autoStop = parseNonNegInt(autoStopIntervalInMinutes);\n const autoArchive = parseNonNegInt(autoArchiveIntervalInMinutes);\n const autoDelete = parseNonNegInt(autoDeleteIntervalInMinutes);\n const trimmedKey = apiKey.trim();\n\n const isValid =\n (!requireApiKey || !!trimmedKey) &&\n execTimeout != null &&\n autoStop != null &&\n autoArchive != null &&\n autoDelete != null;\n\n const handleSubmit = async (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n if (!isValid || busy || execTimeout == null || autoStop == null || autoArchive == null || autoDelete == null) {\n return;\n }\n\n try {\n await onSave({\n // Snapshot/image is release-owned; the field is retained only for the external type.\n execTimeoutMs: execTimeout,\n autoStopIntervalInMinutes: autoStop,\n autoArchiveIntervalInMinutes: autoArchive,\n autoDeleteIntervalInMinutes: autoDelete,\n apiKey: trimmedKey,\n });\n resetForm();\n onOpenChange(false);\n } catch {\n // Parent surfaces error; keep form open.\n }\n };\n\n return (\n <CenteredModal\n open={open}\n onOpenChange={handleOpenChange}\n title={title}\n description={description}\n contentSized\n headerIcon={\n <span\n className=\"flex size-11 shrink-0 items-center justify-center rounded-lg border border-border bg-secondary-bg text-text-primary\"\n aria-hidden\n >\n <Icon name=\"cube\" className=\"size-6\" />\n </span>\n }\n >\n <form className=\"flex flex-col overflow-y-auto p-5 md:p-6\" onSubmit={handleSubmit}>\n <div className=\"space-y-4\">\n <div>\n <label htmlFor=\"sandbox-api-key\" className=\"mb-1.5 block text-sm font-medium text-text-primary\">\n API key\n {!requireApiKey ? <span className=\"font-normal text-text-secondary\"> (optional)</span> : null}\n </label>\n <input\n id=\"sandbox-api-key\"\n type=\"password\"\n required={requireApiKey}\n value={apiKey}\n onChange={event => {\n setApiKey(event.target.value);\n }}\n placeholder={requireApiKey ? 'dtn_...' : 'Leave blank to keep existing'}\n autoFocus\n className={inputClassName}\n />\n </div>\n\n <Accordion\n expanded={advancedOpen}\n onChange={(_event, next) => setAdvancedOpen(next)}\n className=\"rounded-md border border-border\"\n >\n <AccordionSummary className=\"px-3 py-2.5\">\n <span className=\"flex w-full items-center justify-between text-sm font-medium text-text-primary\">\n Advanced settings\n <Icon\n name=\"chevron-down\"\n className={cn(\n 'size-4 shrink-0 text-text-secondary transition-transform duration-200',\n advancedOpen ? 'rotate-0' : '-rotate-90',\n )}\n />\n </span>\n </AccordionSummary>\n <AccordionDetails className=\"space-y-4 border-t border-border px-3 pb-3 pt-4\">\n <div>\n <label htmlFor=\"sandbox-exec-timeout\" className=\"mb-1.5 block text-sm font-medium text-text-primary\">\n Exec timeout (ms)\n </label>\n <input\n id=\"sandbox-exec-timeout\"\n type=\"number\"\n min={0}\n required\n value={execTimeoutMs}\n onChange={event => {\n setExecTimeoutMs(event.target.value);\n }}\n placeholder=\"300000\"\n className={inputClassName}\n />\n </div>\n\n <div>\n <label htmlFor=\"sandbox-auto-stop\" className=\"mb-1.5 block text-sm font-medium text-text-primary\">\n Auto-stop interval (minutes)\n </label>\n <input\n id=\"sandbox-auto-stop\"\n type=\"number\"\n min={0}\n required\n value={autoStopIntervalInMinutes}\n onChange={event => {\n setAutoStopIntervalInMinutes(event.target.value);\n }}\n placeholder=\"15\"\n className={inputClassName}\n />\n </div>\n\n <div>\n <label htmlFor=\"sandbox-auto-archive\" className=\"mb-1.5 block text-sm font-medium text-text-primary\">\n Auto-archive interval (minutes)\n </label>\n <input\n id=\"sandbox-auto-archive\"\n type=\"number\"\n min={0}\n required\n value={autoArchiveIntervalInMinutes}\n onChange={event => {\n setAutoArchiveIntervalInMinutes(event.target.value);\n }}\n placeholder=\"10080\"\n className={inputClassName}\n />\n </div>\n\n <div>\n <label htmlFor=\"sandbox-auto-delete\" className=\"mb-1.5 block text-sm font-medium text-text-primary\">\n Auto-delete interval (minutes)\n </label>\n <input\n id=\"sandbox-auto-delete\"\n type=\"number\"\n min={0}\n required\n value={autoDeleteIntervalInMinutes}\n onChange={event => {\n setAutoDeleteIntervalInMinutes(event.target.value);\n }}\n placeholder=\"43200\"\n className={inputClassName}\n />\n </div>\n </AccordionDetails>\n </Accordion>\n </div>\n\n <div className=\"mt-6 space-y-3\">\n {error ? <p className=\"text-failure-bg text-sm\">{error}</p> : null}\n <Button type=\"submit\" size=\"lg\" disabled={!isValid || busy} className=\"w-full shrink-0\">\n Save\n </Button>\n </div>\n </form>\n </CenteredModal>\n );\n};\n\nexport default ConfigureSandboxForm;\n"],"mappings":"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","names":["useEffect","useState","jsx","jsxs","useState","useEffect"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/containers/SettingsBuilder/index.tsx"],"sourcesContent":["'use client';\n\nimport { lazy, Suspense, useCallback, useEffect, useMemo } from 'react';\n\nimport { useDraftCatalog } from '@/atoms/draft/DraftCatalogProvider.js';\nimport { auiButtonClass } from '@/atoms/lib/buttonClasses.js';\nimport { cn } from '@/atoms/lib/cn.js';\nimport { useCompactLayout } from '@/atoms/lib/CompactLayoutContext.js';\nimport { Spinner } from '@/atoms/primitives/Spinner.js';\nimport { Icon } from '@/icons/Icon.js';\nimport { useOptionalCatalogServer, useOptionalRefreshServerCapabilities } from '@/server/ServerContext.js';\nimport { useShellMode, type SettingsSection } from '@/server/ShellModeContext.js';\n\n// Section modules (and their list/catalog APIs) load only when that tab mounts.\nconst ModelSettings = lazy(() => import('./ModelSettings.js'));\nconst ConnectorSettings = lazy(() => import('./ConnectorSettings.js'));\nconst SkillSettings = lazy(() => import('./SkillSettings.js'));\nconst SandboxSettings = lazy(() => import('./SandboxSettings.js'));\n\nfunction SettingsSectionFallback() {\n return (\n <div className=\"flex flex-1 items-center justify-center py-8\" role=\"status\" aria-live=\"polite\" aria-busy=\"true\">\n <Spinner size={20} className=\"text-text-secondary\" />\n <span className=\"sr-only\">Loading</span>\n </div>\n );\n}\n\nconst TruefoundrySettingsBuilder = () => {\n const { settingsOpen, settingsSection: section, setSettingsOpen } = useShellMode();\n const catalog = useOptionalCatalogServer();\n const refreshServerCapabilities = useOptionalRefreshServerCapabilities();\n const { refresh: refreshDraftCatalog } = useDraftCatalog();\n // dock/widget panels are ~mobile width even on a wide viewport — keep Settings stacked.\n const compact = useCompactLayout();\n const hasSkills = catalog?.skillCatalog != null;\n const hasSandbox = catalog?.sandboxCatalog != null;\n\n const closeSettings = useCallback(() => {\n setSettingsOpen(false);\n }, [setSettingsOpen]);\n\n // Refresh catalogs whenever settings are closed or navigated away from.\n useEffect(() => {\n if (!settingsOpen) return;\n return () => {\n refreshDraftCatalog();\n refreshServerCapabilities?.();\n };\n }, [settingsOpen, refreshDraftCatalog, refreshServerCapabilities]);\n\n useEffect(() => {\n if (!hasSkills && section === 'skills') {\n setSettingsOpen(settingsOpen, 'models');\n }\n if (!hasSandbox && section === 'sandbox') {\n setSettingsOpen(settingsOpen, 'models');\n }\n }, [hasSkills, hasSandbox, section, settingsOpen, setSettingsOpen]);\n\n useEffect(() => {\n if (!settingsOpen) return;\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key !== 'Escape') return;\n event.stopImmediatePropagation();\n closeSettings();\n };\n // Capture so layout Escape handlers (sessions drawer / widget) do not also fire.\n window.addEventListener('keydown', onKeyDown, true);\n return () => window.removeEventListener('keydown', onKeyDown, true);\n }, [closeSettings, settingsOpen]);\n\n const sections = useMemo<\n Array<{\n id: SettingsSection;\n label: string;\n icon: 'cpu' | 'plug' | 'lightbulb' | 'cube';\n }>\n >(() => {\n const baseSections: Array<{\n id: SettingsSection;\n label: string;\n icon: 'cpu' | 'plug' | 'lightbulb' | 'cube';\n }> = [\n { id: 'models', label: 'Models', icon: 'cpu' },\n { id: 'connectors', label: 'Connectors', icon: 'plug' },\n ];\n if (hasSkills) {\n baseSections.push({ id: 'skills', label: 'Skills', icon: 'lightbulb' });\n }\n if (hasSandbox) {\n baseSections.push({ id: 'sandbox', label: 'Sandbox providers', icon: 'cube' });\n }\n return baseSections;\n }, [hasSkills, hasSandbox]);\n\n if (!settingsOpen || !catalog) return null;\n\n return (\n <div className=\"flex h-full min-h-0 w-full flex-col bg-primary-bg\">\n <header className=\"flex shrink-0 items-center gap-2 border-b border-border px-2 py-1.5\">\n <button\n type=\"button\"\n aria-label=\"Back\"\n title=\"Back\"\n className={auiButtonClass({ variant: 'ghost', size: 'icon' })}\n onClick={closeSettings}\n >\n <Icon name=\"arrow-left\" />\n </button>\n <h1 className=\"text-lg font-semibold tracking-tight text-text-primary\">Settings</h1>\n </header>\n\n <div className={cn('flex min-h-0 flex-1 flex-col', !compact && 'md:flex-row')}>\n <nav\n aria-label=\"Settings sections\"\n className={cn(\n 'flex w-full gap-1 border-b border-border bg-secondary-bg/40 p-2',\n compact ? 'min-w-0' : 'justify-center md:w-48 md:flex-col md:justify-start md:border-b-0 md:border-r',\n )}\n >\n {sections.map(item => (\n <button\n key={item.id}\n type=\"button\"\n aria-current={section === item.id ? 'page' : undefined}\n {...(compact ? { title: item.label } : {})}\n className={cn(\n 'flex min-h-9 items-center gap-2 rounded-md px-3 text-sm font-medium transition-colors',\n 'focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-focus-ring',\n // Narrow panels cannot fit fixed-width tabs, so tabs split the row instead.\n compact ? 'min-w-0 flex-1 justify-center gap-1.5 px-1.5' : 'shrink-0',\n section === item.id\n ? 'bg-primary-button-bg text-primary-button-text'\n : 'text-text-secondary hover:bg-ghost-button-hover/60 hover:text-text-primary',\n )}\n onClick={() => {\n setSettingsOpen(true, item.id);\n }}\n >\n <Icon name={item.icon} className=\"h-4 w-4 shrink-0\" />\n {compact ? <span className=\"truncate\">{item.label}</span> : item.label}\n </button>\n ))}\n </nav>\n\n <section className=\"flex flex-col h-full flex-1 overflow-y-hidden px-6 py-4\">\n <div className=\"w-full max-w-210 h-full min-h-0 flex flex-col mx-auto\">\n <Suspense fallback={<SettingsSectionFallback />}>\n {section === 'models' ? <ModelSettings /> : null}\n {section === 'connectors' ? <ConnectorSettings /> : null}\n {section === 'skills' && hasSkills ? <SkillSettings /> : null}\n {section === 'sandbox' && hasSandbox ? <SandboxSettings /> : null}\n </Suspense>\n </div>\n </section>\n </div>\n </div>\n );\n};\n\nexport default TruefoundrySettingsBuilder;\n"],"mappings":"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","names":[]}
|
|
@@ -1,172 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import {
|
|
3
|
-
buildPath,
|
|
4
|
-
matchPath,
|
|
5
|
-
placesEqual
|
|
6
|
-
} from "./chunk-YIWUG6MC.js";
|
|
7
|
-
import {
|
|
8
|
-
useOptionalServer,
|
|
9
|
-
useShellMode
|
|
10
|
-
} from "./chunk-WQULF5AT.js";
|
|
11
|
-
|
|
12
|
-
// src/routing/ShellRouteSync.tsx
|
|
13
|
-
import { useCallback, useEffect, useRef } from "react";
|
|
14
|
-
import { useLocation, useNavigate } from "react-router-dom";
|
|
15
|
-
|
|
16
|
-
// src/routing/derivePlace.ts
|
|
17
|
-
function deriveChatPlace(snapshot) {
|
|
18
|
-
const sessionId = snapshot.activeRemoteId ?? snapshot.pendingSessionId;
|
|
19
|
-
if (sessionId != null) return { type: "session", sessionId };
|
|
20
|
-
const { mode, agentConfigMode } = snapshot;
|
|
21
|
-
if (mode.status === "active" && !mode.isMutable && agentConfigMode !== "SingleAgent") {
|
|
22
|
-
const agentName = mode.agentName ?? mode.agentId;
|
|
23
|
-
if (agentName != null) return { type: "agent", agentName };
|
|
24
|
-
}
|
|
25
|
-
return { type: "root" };
|
|
26
|
-
}
|
|
27
|
-
function derivePlace(snapshot) {
|
|
28
|
-
if (snapshot.settingsOpen) return { type: "settings" };
|
|
29
|
-
return deriveChatPlace(snapshot);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// src/routing/ShellRouteSync.tsx
|
|
33
|
-
function ShellRouteSync({
|
|
34
|
-
routes,
|
|
35
|
-
activeRemoteId,
|
|
36
|
-
initialSettingsOpen
|
|
37
|
-
}) {
|
|
38
|
-
const shell = useShellMode();
|
|
39
|
-
const server = useOptionalServer();
|
|
40
|
-
const navigate = useNavigate();
|
|
41
|
-
const location = useLocation();
|
|
42
|
-
const snapshot = {
|
|
43
|
-
settingsOpen: shell.settingsOpen,
|
|
44
|
-
pendingSessionId: shell.pendingSessionId,
|
|
45
|
-
activeRemoteId,
|
|
46
|
-
mode: shell.mode,
|
|
47
|
-
agentConfigMode: shell.agentConfigMode
|
|
48
|
-
};
|
|
49
|
-
const place = derivePlace(snapshot);
|
|
50
|
-
const placeKey = JSON.stringify(place);
|
|
51
|
-
const selfNavPathRef = useRef(null);
|
|
52
|
-
const prevPlaceRef = useRef(null);
|
|
53
|
-
const bootedRef = useRef(false);
|
|
54
|
-
const requestedSessionRef = useRef(null);
|
|
55
|
-
const shellSyncStartedRef = useRef(false);
|
|
56
|
-
const urlSyncStartedRef = useRef(false);
|
|
57
|
-
const openSession = useCallback(
|
|
58
|
-
(sessionId) => {
|
|
59
|
-
requestedSessionRef.current = sessionId;
|
|
60
|
-
if (server == null) {
|
|
61
|
-
shell.openHistorySession({ sessionId });
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
void server.getSession({ sessionId }).then((session) => {
|
|
65
|
-
if (requestedSessionRef.current !== sessionId) return;
|
|
66
|
-
shell.openHistorySession({
|
|
67
|
-
sessionId,
|
|
68
|
-
isMutable: session.isMutable,
|
|
69
|
-
...session.agentName != null ? { agentName: session.agentName } : {}
|
|
70
|
-
});
|
|
71
|
-
}).catch(() => {
|
|
72
|
-
if (requestedSessionRef.current !== sessionId) return;
|
|
73
|
-
shell.openHistorySession({ sessionId });
|
|
74
|
-
});
|
|
75
|
-
},
|
|
76
|
-
[server, shell]
|
|
77
|
-
);
|
|
78
|
-
const applyPlace = useCallback(
|
|
79
|
-
(target) => {
|
|
80
|
-
switch (target.type) {
|
|
81
|
-
case "settings":
|
|
82
|
-
shell.setSettingsOpen(true);
|
|
83
|
-
return;
|
|
84
|
-
case "session":
|
|
85
|
-
if (shell.pendingSessionId === target.sessionId || activeRemoteId === target.sessionId) return;
|
|
86
|
-
openSession(target.sessionId);
|
|
87
|
-
return;
|
|
88
|
-
case "agent":
|
|
89
|
-
shell.selectLibraryAgent({ isMutable: false, agentName: target.agentName });
|
|
90
|
-
return;
|
|
91
|
-
case "root":
|
|
92
|
-
shell.setSettingsOpen(false);
|
|
93
|
-
switch (shell.agentConfigMode) {
|
|
94
|
-
case "AgentLibrary":
|
|
95
|
-
shell.openLibraryHome();
|
|
96
|
-
return;
|
|
97
|
-
case "AgentComposer":
|
|
98
|
-
case "AgentLibraryWithComposer":
|
|
99
|
-
shell.openDraft();
|
|
100
|
-
return;
|
|
101
|
-
case "SingleAgent":
|
|
102
|
-
shell.clearChat();
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
},
|
|
107
|
-
[shell, activeRemoteId, openSession]
|
|
108
|
-
);
|
|
109
|
-
useEffect(() => {
|
|
110
|
-
if (bootedRef.current) return;
|
|
111
|
-
bootedRef.current = true;
|
|
112
|
-
const urlPlace = matchPath(location.pathname, routes) ?? { type: "root" };
|
|
113
|
-
const settingsOnBoot = initialSettingsOpen || urlPlace.type === "settings";
|
|
114
|
-
if (urlPlace.type === "settings") {
|
|
115
|
-
shell.setSettingsOpen(true);
|
|
116
|
-
} else {
|
|
117
|
-
const chatPlace = deriveChatPlace(snapshot);
|
|
118
|
-
if (!placesEqual(chatPlace, urlPlace)) applyPlace(urlPlace);
|
|
119
|
-
if (initialSettingsOpen) shell.setSettingsOpen(true);
|
|
120
|
-
}
|
|
121
|
-
const desiredPlace = settingsOnBoot ? { type: "settings" } : urlPlace;
|
|
122
|
-
const desiredPath = buildPath(desiredPlace, routes);
|
|
123
|
-
prevPlaceRef.current = desiredPlace;
|
|
124
|
-
if (desiredPath != null && desiredPath !== location.pathname) {
|
|
125
|
-
selfNavPathRef.current = desiredPath;
|
|
126
|
-
navigate({ pathname: desiredPath, search: location.search, hash: location.hash }, { replace: true });
|
|
127
|
-
}
|
|
128
|
-
}, []);
|
|
129
|
-
useEffect(() => {
|
|
130
|
-
if (!bootedRef.current) return;
|
|
131
|
-
if (!shellSyncStartedRef.current) {
|
|
132
|
-
shellSyncStartedRef.current = true;
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
const target = buildPath(place, routes);
|
|
136
|
-
if (target == null) return;
|
|
137
|
-
const prev = prevPlaceRef.current;
|
|
138
|
-
prevPlaceRef.current = place;
|
|
139
|
-
if (target === location.pathname) return;
|
|
140
|
-
const replace = place.type === "session" && shell.pendingSessionId == null && prev != null && prev.type !== "session";
|
|
141
|
-
selfNavPathRef.current = target;
|
|
142
|
-
navigate({ pathname: target, search: location.search, hash: location.hash }, { replace });
|
|
143
|
-
}, [placeKey]);
|
|
144
|
-
useEffect(() => {
|
|
145
|
-
if (!bootedRef.current) return;
|
|
146
|
-
if (!urlSyncStartedRef.current) {
|
|
147
|
-
urlSyncStartedRef.current = true;
|
|
148
|
-
return;
|
|
149
|
-
}
|
|
150
|
-
if (selfNavPathRef.current === location.pathname) {
|
|
151
|
-
selfNavPathRef.current = null;
|
|
152
|
-
return;
|
|
153
|
-
}
|
|
154
|
-
const urlPlace = matchPath(location.pathname, routes);
|
|
155
|
-
if (urlPlace == null) {
|
|
156
|
-
const rootPath = routes.root;
|
|
157
|
-
selfNavPathRef.current = rootPath;
|
|
158
|
-
navigate({ pathname: rootPath, search: location.search, hash: location.hash }, { replace: true });
|
|
159
|
-
applyPlace({ type: "root" });
|
|
160
|
-
return;
|
|
161
|
-
}
|
|
162
|
-
if (urlPlace.type !== "settings" && shell.settingsOpen) {
|
|
163
|
-
shell.setSettingsOpen(false);
|
|
164
|
-
}
|
|
165
|
-
applyPlace(urlPlace);
|
|
166
|
-
}, [location.pathname]);
|
|
167
|
-
return null;
|
|
168
|
-
}
|
|
169
|
-
export {
|
|
170
|
-
ShellRouteSync
|
|
171
|
-
};
|
|
172
|
-
//# sourceMappingURL=ShellRouteSync-T4WLY57Q.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/routing/ShellRouteSync.tsx","../src/routing/derivePlace.ts"],"sourcesContent":["'use client';\n\nimport { useCallback, useEffect, useRef } from 'react';\nimport { useLocation, useNavigate } from 'react-router-dom';\n\nimport { useOptionalServer } from '../server/ServerContext.js';\nimport { useShellMode } from '../server/ShellModeContext.js';\nimport { deriveChatPlace, derivePlace } from './derivePlace.js';\nimport { buildPath, matchPath, placesEqual } from './paths.js';\nimport type { ResolvedRoutes, RoutePlace, ShellSnapshot } from './types.js';\n\n/**\n * Single bidirectional bridge between shell state and the URL. Mounted under\n * `ShellModeProvider` but outside the keyed chat runtime so boot applies once.\n */\nexport function ShellRouteSync({\n routes,\n activeRemoteId,\n initialSettingsOpen,\n}: {\n routes: ResolvedRoutes;\n activeRemoteId: string | undefined;\n initialSettingsOpen: boolean;\n}) {\n const shell = useShellMode();\n const server = useOptionalServer();\n const navigate = useNavigate();\n const location = useLocation();\n\n const snapshot: ShellSnapshot = {\n settingsOpen: shell.settingsOpen,\n pendingSessionId: shell.pendingSessionId,\n activeRemoteId,\n mode: shell.mode,\n agentConfigMode: shell.agentConfigMode,\n };\n\n const place = derivePlace(snapshot);\n const placeKey = JSON.stringify(place);\n\n // Guards. `selfNavPathRef` marks a path we navigated to ourselves so the\n // URL->shell effect does not re-apply it. `prevPlaceRef` powers push/replace.\n const selfNavPathRef = useRef<string | null>(null);\n const prevPlaceRef = useRef<RoutePlace | null>(null);\n const bootedRef = useRef(false);\n // Latest session id the URL asked for, so slower lookups cannot bind over it.\n const requestedSessionRef = useRef<string | null>(null);\n // Boot owns the first URL; the ongoing effects skip their initial commit so\n // they do not fight boot with the stale first-render place.\n const shellSyncStartedRef = useRef(false);\n const urlSyncStartedRef = useRef(false);\n\n /**\n * A URL carries only the id, so ask the server whether it names a mutable\n * draft or an agent chat; guessing \"mutable\" opens an agent session as a\n * blank draft. `requestedSessionRef` drops replies a later place superseded.\n */\n const openSession = useCallback(\n (sessionId: string) => {\n requestedSessionRef.current = sessionId;\n if (server == null) {\n shell.openHistorySession({ sessionId });\n return;\n }\n void server\n .getSession({ sessionId })\n .then(session => {\n if (requestedSessionRef.current !== sessionId) return;\n shell.openHistorySession({\n sessionId,\n isMutable: session.isMutable,\n ...(session.agentName != null ? { agentName: session.agentName } : {}),\n });\n })\n .catch(() => {\n if (requestedSessionRef.current !== sessionId) return;\n // Unreachable session: bind by id alone rather than stranding the shell.\n shell.openHistorySession({ sessionId });\n });\n },\n [server, shell],\n );\n\n const applyPlace = useCallback(\n (target: RoutePlace) => {\n switch (target.type) {\n case 'settings':\n shell.setSettingsOpen(true);\n return;\n case 'session':\n if (shell.pendingSessionId === target.sessionId || activeRemoteId === target.sessionId) return;\n openSession(target.sessionId);\n return;\n case 'agent':\n shell.selectLibraryAgent({ isMutable: false, agentName: target.agentName });\n return;\n case 'root':\n shell.setSettingsOpen(false);\n switch (shell.agentConfigMode) {\n case 'AgentLibrary':\n shell.openLibraryHome();\n return;\n case 'AgentComposer':\n case 'AgentLibraryWithComposer':\n shell.openDraft();\n return;\n case 'SingleAgent':\n shell.clearChat();\n return;\n }\n }\n },\n [shell, activeRemoteId, openSession],\n );\n\n // Boot: URL wins, except an explicit `initialSettingsOpen` overlay. Boot is the\n // sole authority for the first commit and sets the final URL + `prevPlaceRef`.\n useEffect(() => {\n if (bootedRef.current) return;\n bootedRef.current = true;\n\n const urlPlace = matchPath(location.pathname, routes) ?? { type: 'root' };\n const settingsOnBoot = initialSettingsOpen || urlPlace.type === 'settings';\n\n if (urlPlace.type === 'settings') {\n shell.setSettingsOpen(true);\n } else {\n const chatPlace = deriveChatPlace(snapshot);\n if (!placesEqual(chatPlace, urlPlace)) applyPlace(urlPlace);\n if (initialSettingsOpen) shell.setSettingsOpen(true);\n }\n\n const desiredPlace: RoutePlace = settingsOnBoot ? { type: 'settings' } : urlPlace;\n const desiredPath = buildPath(desiredPlace, routes);\n prevPlaceRef.current = desiredPlace;\n if (desiredPath != null && desiredPath !== location.pathname) {\n selfNavPathRef.current = desiredPath;\n navigate({ pathname: desiredPath, search: location.search, hash: location.hash }, { replace: true });\n }\n // Boot runs once; snapshot is read imperatively here.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // Shell -> URL: mirror the derived place. Skip the first commit (boot owns it).\n useEffect(() => {\n if (!bootedRef.current) return;\n if (!shellSyncStartedRef.current) {\n shellSyncStartedRef.current = true;\n return;\n }\n const target = buildPath(place, routes);\n if (target == null) return; // place has no configured URL (e.g. settings disabled)\n\n const prev = prevPlaceRef.current;\n prevPlaceRef.current = place;\n\n if (target === location.pathname) return;\n\n // Replace when a fresh chat just acquired its session id (same place, new id).\n const replace =\n place.type === 'session' && shell.pendingSessionId == null && prev != null && prev.type !== 'session';\n\n selfNavPathRef.current = target;\n // Only the pathname is ours; host query/hash state rides along unchanged.\n navigate({ pathname: target, search: location.search, hash: location.hash }, { replace });\n // location.pathname intentionally excluded: only react to shell-derived place changes.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [placeKey]);\n\n // URL -> shell: apply on genuine location changes (Back/Forward, manual edits).\n useEffect(() => {\n if (!bootedRef.current) return;\n if (!urlSyncStartedRef.current) {\n urlSyncStartedRef.current = true;\n return;\n }\n if (selfNavPathRef.current === location.pathname) {\n selfNavPathRef.current = null;\n return;\n }\n const urlPlace = matchPath(location.pathname, routes);\n if (urlPlace == null) {\n // Unknown path: normalize to root.\n const rootPath = routes.root;\n selfNavPathRef.current = rootPath;\n navigate({ pathname: rootPath, search: location.search, hash: location.hash }, { replace: true });\n applyPlace({ type: 'root' });\n return;\n }\n if (urlPlace.type !== 'settings' && shell.settingsOpen) {\n // Leaving settings via Back to a chat place.\n shell.setSettingsOpen(false);\n }\n applyPlace(urlPlace);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [location.pathname]);\n\n return null;\n}\n","import type { RoutePlace, ShellSnapshot } from './types.js';\n\n/**\n * The chat place implied by shell state, ignoring the settings overlay.\n * SingleAgent canonicalizes to `root` so `/` and `/agents/{name}` alias.\n */\nexport function deriveChatPlace(snapshot: ShellSnapshot): RoutePlace {\n // The live thread wins: reusing a mutable shell switches thread without a\n // remount, leaving `pendingSessionId` on the session the shell last opened.\n // It only leads while a requested session has not reported its thread yet.\n const sessionId = snapshot.activeRemoteId ?? snapshot.pendingSessionId;\n if (sessionId != null) return { type: 'session', sessionId };\n\n const { mode, agentConfigMode } = snapshot;\n if (mode.status === 'active' && !mode.isMutable && agentConfigMode !== 'SingleAgent') {\n const agentName = mode.agentName ?? mode.agentId;\n if (agentName != null) return { type: 'agent', agentName };\n }\n return { type: 'root' };\n}\n\n/** Full place including the settings overlay, which wins over the chat place. */\nexport function derivePlace(snapshot: ShellSnapshot): RoutePlace {\n if (snapshot.settingsOpen) return { type: 'settings' };\n return deriveChatPlace(snapshot);\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,256 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import {
|
|
3
|
-
NamedAgentHeaderLabel,
|
|
4
|
-
ShellActions
|
|
5
|
-
} from "./chunk-ZXOADNF3.js";
|
|
6
|
-
import {
|
|
7
|
-
Thread,
|
|
8
|
-
ThreadListContainer
|
|
9
|
-
} from "./chunk-3S6KHO7H.js";
|
|
10
|
-
import "./chunk-BSIPI3KV.js";
|
|
11
|
-
import {
|
|
12
|
-
useAui
|
|
13
|
-
} from "./chunk-M6MHLVSO.js";
|
|
14
|
-
import {
|
|
15
|
-
resolveBrandChrome,
|
|
16
|
-
useBrandName,
|
|
17
|
-
useChatHeaderContentVisible,
|
|
18
|
-
useSlot
|
|
19
|
-
} from "./chunk-OSV3HI5M.js";
|
|
20
|
-
import {
|
|
21
|
-
Icon,
|
|
22
|
-
Spinner,
|
|
23
|
-
auiButtonClass
|
|
24
|
-
} from "./chunk-FJ5RSSMA.js";
|
|
25
|
-
import {
|
|
26
|
-
useOptionalShellMode
|
|
27
|
-
} from "./chunk-WQULF5AT.js";
|
|
28
|
-
import "./chunk-B52K63AW.js";
|
|
29
|
-
import {
|
|
30
|
-
cn,
|
|
31
|
-
useBrand
|
|
32
|
-
} from "./chunk-36KOSC2J.js";
|
|
33
|
-
|
|
34
|
-
// src/layouts/SidebarLayout.tsx
|
|
35
|
-
import { lazy, Suspense, useEffect, useRef, useState } from "react";
|
|
36
|
-
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
37
|
-
var TruefoundrySettingsBuilder = lazy(() => import("./SettingsBuilder-WF7ZWKQW.js"));
|
|
38
|
-
var desktopCollapsed = false;
|
|
39
|
-
var brandLogoClassName = "h-5 max-w-40 shrink-0 object-contain";
|
|
40
|
-
function SidebarLayout({ className }) {
|
|
41
|
-
const aui = useAui();
|
|
42
|
-
const shell = useOptionalShellMode();
|
|
43
|
-
const brand = useBrand();
|
|
44
|
-
const brandName = useBrandName();
|
|
45
|
-
const chrome = resolveBrandChrome(brand);
|
|
46
|
-
const BrandLogo = useSlot("BrandLogo");
|
|
47
|
-
const AgentsLibraryButton = useSlot("AgentsLibraryButton");
|
|
48
|
-
const ClearChatButton = useSlot("ClearChatButton");
|
|
49
|
-
const SaveAgentButton = useSlot("SaveAgentButton");
|
|
50
|
-
const SelectAgentEmptyState = useSlot("SelectAgentEmptyState");
|
|
51
|
-
const [collapsed, setCollapsed] = useState(desktopCollapsed);
|
|
52
|
-
const setDesktopCollapsed = (value) => {
|
|
53
|
-
setCollapsed((prev) => {
|
|
54
|
-
const next = typeof value === "function" ? value(prev) : value;
|
|
55
|
-
desktopCollapsed = next;
|
|
56
|
-
return next;
|
|
57
|
-
});
|
|
58
|
-
};
|
|
59
|
-
const [mobileNavOpen, setMobileNavOpen] = useState(false);
|
|
60
|
-
const menuBtnRef = useRef(null);
|
|
61
|
-
const dialogRef = useRef(null);
|
|
62
|
-
const mainRef = useRef(null);
|
|
63
|
-
const wasOpen = useRef(false);
|
|
64
|
-
const isIdle = shell?.mode.status === "idle";
|
|
65
|
-
const settingsOpen = shell?.settingsOpen === true;
|
|
66
|
-
const hasChatHeaderContent = useChatHeaderContentVisible();
|
|
67
|
-
useEffect(() => {
|
|
68
|
-
if (!mobileNavOpen) return;
|
|
69
|
-
const onKeyDown = (event) => {
|
|
70
|
-
if (event.key === "Escape") setMobileNavOpen(false);
|
|
71
|
-
};
|
|
72
|
-
window.addEventListener("keydown", onKeyDown);
|
|
73
|
-
return () => window.removeEventListener("keydown", onKeyDown);
|
|
74
|
-
}, [mobileNavOpen]);
|
|
75
|
-
useEffect(() => {
|
|
76
|
-
const main = mainRef.current;
|
|
77
|
-
if (mobileNavOpen) {
|
|
78
|
-
wasOpen.current = true;
|
|
79
|
-
if (main) main.inert = true;
|
|
80
|
-
dialogRef.current?.focus();
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
if (wasOpen.current) {
|
|
84
|
-
if (main) main.inert = false;
|
|
85
|
-
menuBtnRef.current?.focus();
|
|
86
|
-
wasOpen.current = false;
|
|
87
|
-
}
|
|
88
|
-
}, [mobileNavOpen]);
|
|
89
|
-
const handleNewChat = () => {
|
|
90
|
-
if (shell?.isComposerEnabled) {
|
|
91
|
-
shell.openDraft();
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
94
|
-
shell?.setSettingsOpen(false);
|
|
95
|
-
void Promise.resolve(aui.threads().switchToNewThread()).catch(() => void 0);
|
|
96
|
-
};
|
|
97
|
-
return /* @__PURE__ */ jsxs("div", { className: cn("relative flex h-full min-h-0 w-full min-w-0", className), children: [
|
|
98
|
-
/* @__PURE__ */ jsxs(
|
|
99
|
-
"aside",
|
|
100
|
-
{
|
|
101
|
-
className: cn(
|
|
102
|
-
"hidden min-h-0 shrink-0 flex-col border-r border-border bg-sidebar-bg transition-[width] duration-300 ease-in-out md:flex",
|
|
103
|
-
collapsed ? "w-16" : "w-64"
|
|
104
|
-
),
|
|
105
|
-
children: [
|
|
106
|
-
/* @__PURE__ */ jsxs(
|
|
107
|
-
"div",
|
|
108
|
-
{
|
|
109
|
-
className: cn("flex shrink-0 items-center px-3 py-3", collapsed ? "flex-col gap-3" : "justify-between gap-2"),
|
|
110
|
-
children: [
|
|
111
|
-
/* @__PURE__ */ jsxs("div", { className: cn("flex min-w-0 items-center text-text-primary", collapsed ? "justify-center" : "gap-2"), children: [
|
|
112
|
-
/* @__PURE__ */ jsx(
|
|
113
|
-
BrandLogo,
|
|
114
|
-
{
|
|
115
|
-
variant: collapsed ? chrome.collapsedVariant : chrome.expandedVariant,
|
|
116
|
-
className: cn(brandLogoClassName, (collapsed || chrome.expandedVariant === "icon") && "w-5")
|
|
117
|
-
}
|
|
118
|
-
),
|
|
119
|
-
!collapsed && chrome.showTitle && brandName != null ? /* @__PURE__ */ jsx("span", { className: "truncate text-lg font-semibold tracking-tight", children: brandName }) : null
|
|
120
|
-
] }),
|
|
121
|
-
/* @__PURE__ */ jsx(
|
|
122
|
-
"button",
|
|
123
|
-
{
|
|
124
|
-
type: "button",
|
|
125
|
-
"aria-label": collapsed ? "Expand sidebar" : "Collapse sidebar",
|
|
126
|
-
title: collapsed ? "Expand sidebar" : "Collapse sidebar",
|
|
127
|
-
"aria-expanded": !collapsed,
|
|
128
|
-
className: auiButtonClass({ variant: "ghost", size: "icon" }),
|
|
129
|
-
onClick: () => setDesktopCollapsed((value) => !value),
|
|
130
|
-
children: /* @__PURE__ */ jsx(Icon, { name: collapsed ? "panel-left-open" : "panel-left-close" })
|
|
131
|
-
}
|
|
132
|
-
)
|
|
133
|
-
]
|
|
134
|
-
}
|
|
135
|
-
),
|
|
136
|
-
/* @__PURE__ */ jsxs("nav", { className: "flex min-h-0 flex-1 flex-col items-center gap-2 px-3", hidden: !collapsed, "aria-label": "Sidebar", children: [
|
|
137
|
-
shell?.isNewChatEnabled !== false ? /* @__PURE__ */ jsx(
|
|
138
|
-
"button",
|
|
139
|
-
{
|
|
140
|
-
type: "button",
|
|
141
|
-
"aria-label": "Start new chat",
|
|
142
|
-
title: "New chat",
|
|
143
|
-
className: auiButtonClass({ variant: "ghost", size: "icon" }),
|
|
144
|
-
onClick: handleNewChat,
|
|
145
|
-
children: /* @__PURE__ */ jsx(Icon, { name: "square-pen" })
|
|
146
|
-
}
|
|
147
|
-
) : null,
|
|
148
|
-
/* @__PURE__ */ jsx(AgentsLibraryButton, { compact: true })
|
|
149
|
-
] }),
|
|
150
|
-
/* @__PURE__ */ jsx("div", { className: "flex min-h-0 flex-1 flex-col overflow-hidden", hidden: collapsed, children: /* @__PURE__ */ jsx(ThreadListContainer, {}) }),
|
|
151
|
-
/* @__PURE__ */ jsx(
|
|
152
|
-
"footer",
|
|
153
|
-
{
|
|
154
|
-
className: cn(
|
|
155
|
-
"flex shrink-0 border-t border-border px-3 py-2",
|
|
156
|
-
collapsed ? "flex-col items-center gap-2" : "items-center gap-1"
|
|
157
|
-
),
|
|
158
|
-
children: /* @__PURE__ */ jsx(ShellActions, { className: collapsed ? "flex-col" : void 0 })
|
|
159
|
-
}
|
|
160
|
-
)
|
|
161
|
-
]
|
|
162
|
-
}
|
|
163
|
-
),
|
|
164
|
-
/* @__PURE__ */ jsxs("div", { className: "flex min-h-0 min-w-0 flex-1 flex-col bg-primary-bg", children: [
|
|
165
|
-
/* @__PURE__ */ jsxs(
|
|
166
|
-
"header",
|
|
167
|
-
{
|
|
168
|
-
className: cn(
|
|
169
|
-
"flex shrink-0 items-center gap-1 border-b border-border bg-topbar-bg px-2 py-1.5",
|
|
170
|
-
// Desktop: hide when settings/idle or the thread header has nothing to show
|
|
171
|
-
// (empty untitled draft). Mobile still needs Sessions + ShellActions.
|
|
172
|
-
(settingsOpen || isIdle || !hasChatHeaderContent) && "md:hidden"
|
|
173
|
-
),
|
|
174
|
-
children: [
|
|
175
|
-
!settingsOpen ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
176
|
-
/* @__PURE__ */ jsx(
|
|
177
|
-
"button",
|
|
178
|
-
{
|
|
179
|
-
ref: menuBtnRef,
|
|
180
|
-
type: "button",
|
|
181
|
-
"aria-label": "Sessions",
|
|
182
|
-
"aria-expanded": mobileNavOpen,
|
|
183
|
-
className: cn(auiButtonClass({ variant: "ghost", size: "icon" }), "md:hidden"),
|
|
184
|
-
onClick: () => setMobileNavOpen(true),
|
|
185
|
-
children: /* @__PURE__ */ jsx(Icon, { name: "bars" })
|
|
186
|
-
}
|
|
187
|
-
),
|
|
188
|
-
/* @__PURE__ */ jsx(NamedAgentHeaderLabel, {}),
|
|
189
|
-
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1" }),
|
|
190
|
-
/* @__PURE__ */ jsx(ClearChatButton, {}),
|
|
191
|
-
/* @__PURE__ */ jsx(SaveAgentButton, {})
|
|
192
|
-
] }) : /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1" }),
|
|
193
|
-
/* @__PURE__ */ jsx("div", { className: "md:hidden", children: /* @__PURE__ */ jsx(ShellActions, {}) }, "mobile-shell-actions")
|
|
194
|
-
]
|
|
195
|
-
}
|
|
196
|
-
),
|
|
197
|
-
/* @__PURE__ */ jsx("div", { ref: mainRef, className: "min-h-0 min-w-0 flex-1", children: settingsOpen ? /* @__PURE__ */ jsx(
|
|
198
|
-
Suspense,
|
|
199
|
-
{
|
|
200
|
-
fallback: /* @__PURE__ */ jsxs(
|
|
201
|
-
"div",
|
|
202
|
-
{
|
|
203
|
-
className: "flex h-full items-center justify-center",
|
|
204
|
-
role: "status",
|
|
205
|
-
"aria-live": "polite",
|
|
206
|
-
"aria-busy": "true",
|
|
207
|
-
children: [
|
|
208
|
-
/* @__PURE__ */ jsx(Spinner, { size: 28, className: "text-text-primary" }),
|
|
209
|
-
/* @__PURE__ */ jsx("span", { className: "sr-only", children: "Loading" })
|
|
210
|
-
]
|
|
211
|
-
}
|
|
212
|
-
),
|
|
213
|
-
children: /* @__PURE__ */ jsx(TruefoundrySettingsBuilder, {})
|
|
214
|
-
}
|
|
215
|
-
) : isIdle ? /* @__PURE__ */ jsx(SelectAgentEmptyState, {}) : /* @__PURE__ */ jsx(Thread, {}) })
|
|
216
|
-
] }),
|
|
217
|
-
mobileNavOpen ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
218
|
-
/* @__PURE__ */ jsx(
|
|
219
|
-
"button",
|
|
220
|
-
{
|
|
221
|
-
type: "button",
|
|
222
|
-
"aria-label": "Close sessions",
|
|
223
|
-
className: "absolute inset-0 z-[9] cursor-pointer bg-[var(--overlay)] md:hidden",
|
|
224
|
-
onClick: () => setMobileNavOpen(false)
|
|
225
|
-
}
|
|
226
|
-
),
|
|
227
|
-
/* @__PURE__ */ jsxs(
|
|
228
|
-
"div",
|
|
229
|
-
{
|
|
230
|
-
ref: dialogRef,
|
|
231
|
-
className: "absolute inset-y-0 left-0 z-10 flex w-full max-w-80 flex-col border-r border-border bg-sidebar-bg shadow-lg outline-none md:hidden",
|
|
232
|
-
role: "dialog",
|
|
233
|
-
"aria-label": "Sessions",
|
|
234
|
-
tabIndex: -1,
|
|
235
|
-
children: [
|
|
236
|
-
/* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-2 border-b border-border px-3 py-3 text-text-primary", children: [
|
|
237
|
-
/* @__PURE__ */ jsx(
|
|
238
|
-
BrandLogo,
|
|
239
|
-
{
|
|
240
|
-
variant: chrome.expandedVariant,
|
|
241
|
-
className: cn(brandLogoClassName, chrome.expandedVariant === "icon" && "w-5")
|
|
242
|
-
}
|
|
243
|
-
),
|
|
244
|
-
chrome.showTitle && brandName != null ? /* @__PURE__ */ jsx("span", { className: "truncate text-lg font-semibold tracking-tight", children: brandName }) : null
|
|
245
|
-
] }),
|
|
246
|
-
/* @__PURE__ */ jsx(ThreadListContainer, { onThreadOpen: () => setMobileNavOpen(false) })
|
|
247
|
-
]
|
|
248
|
-
}
|
|
249
|
-
)
|
|
250
|
-
] }) : null
|
|
251
|
-
] });
|
|
252
|
-
}
|
|
253
|
-
export {
|
|
254
|
-
SidebarLayout
|
|
255
|
-
};
|
|
256
|
-
//# sourceMappingURL=SidebarLayout-3WZ3CVON.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/layouts/SidebarLayout.tsx"],"sourcesContent":["'use client';\n\nimport { lazy, Suspense, useEffect, useRef, useState } from 'react';\n\nimport { useAui } from '../assistant-ui.js';\nimport { auiButtonClass } from '../atoms/lib/buttonClasses.js';\nimport { cn } from '../atoms/lib/cn.js';\nimport { NamedAgentHeaderLabel } from '../atoms/NamedAgentHeaderLabel.js';\nimport { Spinner } from '../atoms/primitives/Spinner.js';\nimport { ShellActions } from '../atoms/ShellActions.js';\nimport { Thread } from '../containers/Thread.js';\nimport { ThreadListContainer } from '../containers/ThreadListContainer.js';\nimport { useChatHeaderContentVisible } from '../hooks/useChatChromeActionsVisible.js';\nimport { Icon } from '../icons/Icon.js';\nimport { useOptionalShellMode } from '../server/ShellModeContext.js';\nimport { resolveBrandChrome, useBrandName } from '../theme/brand.js';\nimport { useSlot } from '../theme/SlotsProvider.js';\nimport { useBrand } from '../theme/ThemeProvider.js';\n\nconst TruefoundrySettingsBuilder = lazy(() => import('../containers/SettingsBuilder/index.js'));\n\n// Survives ChatProvider remounts when openDraft / selectAgent bumps runtimeKey.\nlet desktopCollapsed = false;\n\nconst brandLogoClassName = 'h-5 max-w-40 shrink-0 object-contain';\n\nexport function SidebarLayout({ className }: { className?: string }) {\n const aui = useAui();\n const shell = useOptionalShellMode();\n const brand = useBrand();\n const brandName = useBrandName();\n const chrome = resolveBrandChrome(brand);\n const BrandLogo = useSlot('BrandLogo');\n const AgentsLibraryButton = useSlot('AgentsLibraryButton');\n const ClearChatButton = useSlot('ClearChatButton');\n const SaveAgentButton = useSlot('SaveAgentButton');\n const SelectAgentEmptyState = useSlot('SelectAgentEmptyState');\n const [collapsed, setCollapsed] = useState(desktopCollapsed);\n const setDesktopCollapsed = (value: boolean | ((prev: boolean) => boolean)) => {\n setCollapsed(prev => {\n const next = typeof value === 'function' ? value(prev) : value;\n desktopCollapsed = next;\n return next;\n });\n };\n const [mobileNavOpen, setMobileNavOpen] = useState(false);\n const menuBtnRef = useRef<HTMLButtonElement>(null);\n const dialogRef = useRef<HTMLDivElement>(null);\n const mainRef = useRef<HTMLDivElement>(null);\n const wasOpen = useRef(false);\n const isIdle = shell?.mode.status === 'idle';\n const settingsOpen = shell?.settingsOpen === true;\n const hasChatHeaderContent = useChatHeaderContentVisible();\n\n useEffect(() => {\n if (!mobileNavOpen) return;\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') setMobileNavOpen(false);\n };\n window.addEventListener('keydown', onKeyDown);\n return () => window.removeEventListener('keydown', onKeyDown);\n }, [mobileNavOpen]);\n\n useEffect(() => {\n const main = mainRef.current;\n if (mobileNavOpen) {\n wasOpen.current = true;\n if (main) main.inert = true;\n dialogRef.current?.focus();\n return;\n }\n if (wasOpen.current) {\n if (main) main.inert = false;\n menuBtnRef.current?.focus();\n wasOpen.current = false;\n }\n }, [mobileNavOpen]);\n\n const handleNewChat = () => {\n if (shell?.isComposerEnabled) {\n shell.openDraft();\n return;\n }\n shell?.setSettingsOpen(false);\n void Promise.resolve(aui.threads().switchToNewThread()).catch(() => undefined);\n };\n\n return (\n <div className={cn('relative flex h-full min-h-0 w-full min-w-0', className)}>\n {/* Desktop sidebar */}\n <aside\n className={cn(\n 'hidden min-h-0 shrink-0 flex-col border-r border-border bg-sidebar-bg transition-[width] duration-300 ease-in-out md:flex',\n collapsed ? 'w-16' : 'w-64',\n )}\n >\n <div\n className={cn('flex shrink-0 items-center px-3 py-3', collapsed ? 'flex-col gap-3' : 'justify-between gap-2')}\n >\n <div className={cn('flex min-w-0 items-center text-text-primary', collapsed ? 'justify-center' : 'gap-2')}>\n <BrandLogo\n variant={collapsed ? chrome.collapsedVariant : chrome.expandedVariant}\n className={cn(brandLogoClassName, (collapsed || chrome.expandedVariant === 'icon') && 'w-5')}\n />\n {!collapsed && chrome.showTitle && brandName != null ? (\n <span className=\"truncate text-lg font-semibold tracking-tight\">{brandName}</span>\n ) : null}\n </div>\n <button\n type=\"button\"\n aria-label={collapsed ? 'Expand sidebar' : 'Collapse sidebar'}\n title={collapsed ? 'Expand sidebar' : 'Collapse sidebar'}\n aria-expanded={!collapsed}\n className={auiButtonClass({ variant: 'ghost', size: 'icon' })}\n onClick={() => setDesktopCollapsed(value => !value)}\n >\n <Icon name={collapsed ? 'panel-left-open' : 'panel-left-close'} />\n </button>\n </div>\n\n {/* Keep both trees mounted; toggle with `hidden` so AgentsLibraryButton does not remount. */}\n <nav className=\"flex min-h-0 flex-1 flex-col items-center gap-2 px-3\" hidden={!collapsed} aria-label=\"Sidebar\">\n {shell?.isNewChatEnabled !== false ? (\n <button\n type=\"button\"\n aria-label=\"Start new chat\"\n title=\"New chat\"\n className={auiButtonClass({ variant: 'ghost', size: 'icon' })}\n onClick={handleNewChat}\n >\n <Icon name=\"square-pen\" />\n </button>\n ) : null}\n <AgentsLibraryButton compact />\n </nav>\n <div className=\"flex min-h-0 flex-1 flex-col overflow-hidden\" hidden={collapsed}>\n <ThreadListContainer />\n </div>\n\n <footer\n className={cn(\n 'flex shrink-0 border-t border-border px-3 py-2',\n collapsed ? 'flex-col items-center gap-2' : 'items-center gap-1',\n )}\n >\n <ShellActions className={collapsed ? 'flex-col' : undefined} />\n </footer>\n </aside>\n\n <div className=\"flex min-h-0 min-w-0 flex-1 flex-col bg-primary-bg\">\n {/* Mobile ShellActions stay mounted while Settings is open so host overrides (e.g. logout) do not remount.\n Desktop keeps shell chrome in the aside footer (always mounted). */}\n <header\n className={cn(\n 'flex shrink-0 items-center gap-1 border-b border-border bg-topbar-bg px-2 py-1.5',\n // Desktop: hide when settings/idle or the thread header has nothing to show\n // (empty untitled draft). Mobile still needs Sessions + ShellActions.\n (settingsOpen || isIdle || !hasChatHeaderContent) && 'md:hidden',\n )}\n >\n {!settingsOpen ? (\n <>\n <button\n ref={menuBtnRef}\n type=\"button\"\n aria-label=\"Sessions\"\n aria-expanded={mobileNavOpen}\n className={cn(auiButtonClass({ variant: 'ghost', size: 'icon' }), 'md:hidden')}\n onClick={() => setMobileNavOpen(true)}\n >\n <Icon name=\"bars\" />\n </button>\n <NamedAgentHeaderLabel />\n <span className=\"min-w-0 flex-1\" />\n <ClearChatButton />\n <SaveAgentButton />\n </>\n ) : (\n <span className=\"min-w-0 flex-1\" />\n )}\n <div key=\"mobile-shell-actions\" className=\"md:hidden\">\n <ShellActions />\n </div>\n </header>\n\n <div ref={mainRef} className=\"min-h-0 min-w-0 flex-1\">\n {settingsOpen ? (\n <Suspense\n fallback={\n <div\n className=\"flex h-full items-center justify-center\"\n role=\"status\"\n aria-live=\"polite\"\n aria-busy=\"true\"\n >\n <Spinner size={28} className=\"text-text-primary\" />\n <span className=\"sr-only\">Loading</span>\n </div>\n }\n >\n <TruefoundrySettingsBuilder />\n </Suspense>\n ) : isIdle ? (\n <SelectAgentEmptyState />\n ) : (\n <Thread />\n )}\n </div>\n </div>\n\n {/* Mobile sessions drawer */}\n {mobileNavOpen ? (\n <>\n <button\n type=\"button\"\n aria-label=\"Close sessions\"\n className=\"absolute inset-0 z-[9] cursor-pointer bg-[var(--overlay)] md:hidden\"\n onClick={() => setMobileNavOpen(false)}\n />\n <div\n ref={dialogRef}\n className=\"absolute inset-y-0 left-0 z-10 flex w-full max-w-80 flex-col border-r border-border bg-sidebar-bg shadow-lg outline-none md:hidden\"\n role=\"dialog\"\n aria-label=\"Sessions\"\n tabIndex={-1}\n >\n <div className=\"flex shrink-0 items-center gap-2 border-b border-border px-3 py-3 text-text-primary\">\n <BrandLogo\n variant={chrome.expandedVariant}\n className={cn(brandLogoClassName, chrome.expandedVariant === 'icon' && 'w-5')}\n />\n {chrome.showTitle && brandName != null ? (\n <span className=\"truncate text-lg font-semibold tracking-tight\">{brandName}</span>\n ) : null}\n </div>\n <ThreadListContainer onThreadOpen={() => setMobileNavOpen(false)} />\n </div>\n </>\n ) : null}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA,SAAS,MAAM,UAAU,WAAW,QAAQ,gBAAgB;AAiGlD,SA8DE,UA7DA,KADF;AAhFV,IAAM,6BAA6B,KAAK,MAAM,OAAO,+BAAwC,CAAC;AAG9F,IAAI,mBAAmB;AAEvB,IAAM,qBAAqB;AAEpB,SAAS,cAAc,EAAE,UAAU,GAA2B;AACnE,QAAM,MAAM,OAAO;AACnB,QAAM,QAAQ,qBAAqB;AACnC,QAAM,QAAQ,SAAS;AACvB,QAAM,YAAY,aAAa;AAC/B,QAAM,SAAS,mBAAmB,KAAK;AACvC,QAAM,YAAY,QAAQ,WAAW;AACrC,QAAM,sBAAsB,QAAQ,qBAAqB;AACzD,QAAM,kBAAkB,QAAQ,iBAAiB;AACjD,QAAM,kBAAkB,QAAQ,iBAAiB;AACjD,QAAM,wBAAwB,QAAQ,uBAAuB;AAC7D,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,gBAAgB;AAC3D,QAAM,sBAAsB,CAAC,UAAkD;AAC7E,iBAAa,UAAQ;AACnB,YAAM,OAAO,OAAO,UAAU,aAAa,MAAM,IAAI,IAAI;AACzD,yBAAmB;AACnB,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AACA,QAAM,CAAC,eAAe,gBAAgB,IAAI,SAAS,KAAK;AACxD,QAAM,aAAa,OAA0B,IAAI;AACjD,QAAM,YAAY,OAAuB,IAAI;AAC7C,QAAM,UAAU,OAAuB,IAAI;AAC3C,QAAM,UAAU,OAAO,KAAK;AAC5B,QAAM,SAAS,OAAO,KAAK,WAAW;AACtC,QAAM,eAAe,OAAO,iBAAiB;AAC7C,QAAM,uBAAuB,4BAA4B;AAEzD,YAAU,MAAM;AACd,QAAI,CAAC,cAAe;AACpB,UAAM,YAAY,CAAC,UAAyB;AAC1C,UAAI,MAAM,QAAQ,SAAU,kBAAiB,KAAK;AAAA,IACpD;AACA,WAAO,iBAAiB,WAAW,SAAS;AAC5C,WAAO,MAAM,OAAO,oBAAoB,WAAW,SAAS;AAAA,EAC9D,GAAG,CAAC,aAAa,CAAC;AAElB,YAAU,MAAM;AACd,UAAM,OAAO,QAAQ;AACrB,QAAI,eAAe;AACjB,cAAQ,UAAU;AAClB,UAAI,KAAM,MAAK,QAAQ;AACvB,gBAAU,SAAS,MAAM;AACzB;AAAA,IACF;AACA,QAAI,QAAQ,SAAS;AACnB,UAAI,KAAM,MAAK,QAAQ;AACvB,iBAAW,SAAS,MAAM;AAC1B,cAAQ,UAAU;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,aAAa,CAAC;AAElB,QAAM,gBAAgB,MAAM;AAC1B,QAAI,OAAO,mBAAmB;AAC5B,YAAM,UAAU;AAChB;AAAA,IACF;AACA,WAAO,gBAAgB,KAAK;AAC5B,SAAK,QAAQ,QAAQ,IAAI,QAAQ,EAAE,kBAAkB,CAAC,EAAE,MAAM,MAAM,MAAS;AAAA,EAC/E;AAEA,SACE,qBAAC,SAAI,WAAW,GAAG,+CAA+C,SAAS,GAEzE;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,WAAW;AAAA,UACT;AAAA,UACA,YAAY,SAAS;AAAA,QACvB;AAAA,QAEA;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,WAAW,GAAG,wCAAwC,YAAY,mBAAmB,uBAAuB;AAAA,cAE5G;AAAA,qCAAC,SAAI,WAAW,GAAG,+CAA+C,YAAY,mBAAmB,OAAO,GACtG;AAAA;AAAA,oBAAC;AAAA;AAAA,sBACC,SAAS,YAAY,OAAO,mBAAmB,OAAO;AAAA,sBACtD,WAAW,GAAG,qBAAqB,aAAa,OAAO,oBAAoB,WAAW,KAAK;AAAA;AAAA,kBAC7F;AAAA,kBACC,CAAC,aAAa,OAAO,aAAa,aAAa,OAC9C,oBAAC,UAAK,WAAU,iDAAiD,qBAAU,IACzE;AAAA,mBACN;AAAA,gBACA;AAAA,kBAAC;AAAA;AAAA,oBACC,MAAK;AAAA,oBACL,cAAY,YAAY,mBAAmB;AAAA,oBAC3C,OAAO,YAAY,mBAAmB;AAAA,oBACtC,iBAAe,CAAC;AAAA,oBAChB,WAAW,eAAe,EAAE,SAAS,SAAS,MAAM,OAAO,CAAC;AAAA,oBAC5D,SAAS,MAAM,oBAAoB,WAAS,CAAC,KAAK;AAAA,oBAElD,8BAAC,QAAK,MAAM,YAAY,oBAAoB,oBAAoB;AAAA;AAAA,gBAClE;AAAA;AAAA;AAAA,UACF;AAAA,UAGA,qBAAC,SAAI,WAAU,wDAAuD,QAAQ,CAAC,WAAW,cAAW,WAClG;AAAA,mBAAO,qBAAqB,QAC3B;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,cAAW;AAAA,gBACX,OAAM;AAAA,gBACN,WAAW,eAAe,EAAE,SAAS,SAAS,MAAM,OAAO,CAAC;AAAA,gBAC5D,SAAS;AAAA,gBAET,8BAAC,QAAK,MAAK,cAAa;AAAA;AAAA,YAC1B,IACE;AAAA,YACJ,oBAAC,uBAAoB,SAAO,MAAC;AAAA,aAC/B;AAAA,UACA,oBAAC,SAAI,WAAU,gDAA+C,QAAQ,WACpE,8BAAC,uBAAoB,GACvB;AAAA,UAEA;AAAA,YAAC;AAAA;AAAA,cACC,WAAW;AAAA,gBACT;AAAA,gBACA,YAAY,gCAAgC;AAAA,cAC9C;AAAA,cAEA,8BAAC,gBAAa,WAAW,YAAY,aAAa,QAAW;AAAA;AAAA,UAC/D;AAAA;AAAA;AAAA,IACF;AAAA,IAEA,qBAAC,SAAI,WAAU,sDAGb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,WAAW;AAAA,YACT;AAAA;AAAA;AAAA,aAGC,gBAAgB,UAAU,CAAC,yBAAyB;AAAA,UACvD;AAAA,UAEC;AAAA,aAAC,eACA,iCACE;AAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,KAAK;AAAA,kBACL,MAAK;AAAA,kBACL,cAAW;AAAA,kBACX,iBAAe;AAAA,kBACf,WAAW,GAAG,eAAe,EAAE,SAAS,SAAS,MAAM,OAAO,CAAC,GAAG,WAAW;AAAA,kBAC7E,SAAS,MAAM,iBAAiB,IAAI;AAAA,kBAEpC,8BAAC,QAAK,MAAK,QAAO;AAAA;AAAA,cACpB;AAAA,cACA,oBAAC,yBAAsB;AAAA,cACvB,oBAAC,UAAK,WAAU,kBAAiB;AAAA,cACjC,oBAAC,mBAAgB;AAAA,cACjB,oBAAC,mBAAgB;AAAA,eACnB,IAEA,oBAAC,UAAK,WAAU,kBAAiB;AAAA,YAEnC,oBAAC,SAA+B,WAAU,aACxC,8BAAC,gBAAa,KADP,sBAET;AAAA;AAAA;AAAA,MACF;AAAA,MAEA,oBAAC,SAAI,KAAK,SAAS,WAAU,0BAC1B,yBACC;AAAA,QAAC;AAAA;AAAA,UACC,UACE;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,MAAK;AAAA,cACL,aAAU;AAAA,cACV,aAAU;AAAA,cAEV;AAAA,oCAAC,WAAQ,MAAM,IAAI,WAAU,qBAAoB;AAAA,gBACjD,oBAAC,UAAK,WAAU,WAAU,qBAAO;AAAA;AAAA;AAAA,UACnC;AAAA,UAGF,8BAAC,8BAA2B;AAAA;AAAA,MAC9B,IACE,SACF,oBAAC,yBAAsB,IAEvB,oBAAC,UAAO,GAEZ;AAAA,OACF;AAAA,IAGC,gBACC,iCACE;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,cAAW;AAAA,UACX,WAAU;AAAA,UACV,SAAS,MAAM,iBAAiB,KAAK;AAAA;AAAA,MACvC;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,KAAK;AAAA,UACL,WAAU;AAAA,UACV,MAAK;AAAA,UACL,cAAW;AAAA,UACX,UAAU;AAAA,UAEV;AAAA,iCAAC,SAAI,WAAU,uFACb;AAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,SAAS,OAAO;AAAA,kBAChB,WAAW,GAAG,oBAAoB,OAAO,oBAAoB,UAAU,KAAK;AAAA;AAAA,cAC9E;AAAA,cACC,OAAO,aAAa,aAAa,OAChC,oBAAC,UAAK,WAAU,iDAAiD,qBAAU,IACzE;AAAA,eACN;AAAA,YACA,oBAAC,uBAAoB,cAAc,MAAM,iBAAiB,KAAK,GAAG;AAAA;AAAA;AAAA,MACpE;AAAA,OACF,IACE;AAAA,KACN;AAEJ;","names":[]}
|