agent-relay-server 0.61.1 → 0.62.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/openapi.json +479 -1
- package/package.json +2 -2
- package/public/assets/{MessageBubble-CX63ZV4X.js → MessageBubble-BP0Ym3xb.js} +2 -2
- package/public/assets/{MessageBubble-CX63ZV4X.js.map → MessageBubble-BP0Ym3xb.js.map} +1 -1
- package/public/assets/PlanGraphPanel-DKc3gdou.js +2 -0
- package/public/assets/PlanGraphPanel-DKc3gdou.js.map +1 -0
- package/public/assets/{activity-2xPOScu_.js → activity-CRLG6ICe.js} +2 -2
- package/public/assets/{activity-2xPOScu_.js.map → activity-CRLG6ICe.js.map} +1 -1
- package/public/assets/{agent-profiles-BfGTTbeY.js → agent-profiles-DItyEkXP.js} +2 -2
- package/public/assets/{agent-profiles-BfGTTbeY.js.map → agent-profiles-DItyEkXP.js.map} +1 -1
- package/public/assets/{agents-Bg3WOBRV.js → agents-5mKiZ1rz.js} +2 -2
- package/public/assets/{agents-Bg3WOBRV.js.map → agents-5mKiZ1rz.js.map} +1 -1
- package/public/assets/{analytics-De0cEZGx.js → analytics-J5pPcS-v.js} +3 -3
- package/public/assets/{analytics-De0cEZGx.js.map → analytics-J5pPcS-v.js.map} +1 -1
- package/public/assets/{automation-CHxhzq2t.js → automation-BG2HWK5N.js} +2 -2
- package/public/assets/{automation-CHxhzq2t.js.map → automation-BG2HWK5N.js.map} +1 -1
- package/public/assets/{badge-DhLyCPag.js → badge-CZhIdlTJ.js} +2 -2
- package/public/assets/{badge-DhLyCPag.js.map → badge-CZhIdlTJ.js.map} +1 -1
- package/public/assets/{branch-state-badge-DSyWKluD.js → branch-state-badge-BZMoxs65.js} +2 -2
- package/public/assets/{branch-state-badge-DSyWKluD.js.map → branch-state-badge-BZMoxs65.js.map} +1 -1
- package/public/assets/{button-K20wAZG1.js → button-2taQeNHW.js} +2 -2
- package/public/assets/{button-K20wAZG1.js.map → button-2taQeNHW.js.map} +1 -1
- package/public/assets/card-DzIsAI41.js +2 -0
- package/public/assets/{card-CcZ9hLI7.js.map → card-DzIsAI41.js.map} +1 -1
- package/public/assets/channels-B2PeqiRT.js +2 -0
- package/public/assets/{channels-BG0Nib7y.js.map → channels-B2PeqiRT.js.map} +1 -1
- package/public/assets/chat-CLRJVagA.js +2 -0
- package/public/assets/{chat-CjP_crSl.js.map → chat-CLRJVagA.js.map} +1 -1
- package/public/assets/{connectors-DWh7MwV_.js → connectors-Bzvkxsgo.js} +2 -2
- package/public/assets/{connectors-DWh7MwV_.js.map → connectors-Bzvkxsgo.js.map} +1 -1
- package/public/assets/copy-button-HEkwi6xX.js +2 -0
- package/public/assets/{copy-button-eF3cKp4Q.js.map → copy-button-HEkwi6xX.js.map} +1 -1
- package/public/assets/display-DzNvOu1j.js.map +1 -1
- package/public/assets/dist-1rXN5FN9.js +2 -0
- package/public/assets/{dist-YpHfnnIA.js.map → dist-1rXN5FN9.js.map} +1 -1
- package/public/assets/{dist-1dhfdhm9.js → dist-AbEQuFoK.js} +2 -2
- package/public/assets/{dist-1dhfdhm9.js.map → dist-AbEQuFoK.js.map} +1 -1
- package/public/assets/{dist-COQuunEv.js → dist-B7p1zkvf.js} +2 -2
- package/public/assets/{dist-COQuunEv.js.map → dist-B7p1zkvf.js.map} +1 -1
- package/public/assets/{dist-Ci5Y37nj.js → dist-CG10hM1-.js} +2 -2
- package/public/assets/{dist-Ci5Y37nj.js.map → dist-CG10hM1-.js.map} +1 -1
- package/public/assets/dist-Cfm5_zPB.js +2 -0
- package/public/assets/{dist-qd198ib9.js.map → dist-Cfm5_zPB.js.map} +1 -1
- package/public/assets/{dist-BrQsqBbc.js → dist-Cgw85UcE.js} +2 -2
- package/public/assets/{dist-BrQsqBbc.js.map → dist-Cgw85UcE.js.map} +1 -1
- package/public/assets/{dist-CoROafNg.js → dist-D3_TJKTC.js} +2 -2
- package/public/assets/{dist-CoROafNg.js.map → dist-D3_TJKTC.js.map} +1 -1
- package/public/assets/{dist-I-MFUv51.js → dist-DQkLq0hs.js} +2 -2
- package/public/assets/{dist-I-MFUv51.js.map → dist-DQkLq0hs.js.map} +1 -1
- package/public/assets/{dist-UQGKwqZH.js → dist-D_sl7u_f.js} +2 -2
- package/public/assets/{dist-UQGKwqZH.js.map → dist-D_sl7u_f.js.map} +1 -1
- package/public/assets/{dist-yGOq6sB3.js → dist-Ilb3r1im.js} +2 -2
- package/public/assets/{dist-yGOq6sB3.js.map → dist-Ilb3r1im.js.map} +1 -1
- package/public/assets/dist-Pf_3Gf38.js +2 -0
- package/public/assets/{dist-BLBF7qqr.js.map → dist-Pf_3Gf38.js.map} +1 -1
- package/public/assets/{es2015-CRxz9lOj.js → es2015-GSepNaIS.js} +2 -2
- package/public/assets/{es2015-CRxz9lOj.js.map → es2015-GSepNaIS.js.map} +1 -1
- package/public/assets/{formatted-body-impl-u0W_hWYA.js → formatted-body-impl-QqHxdMGP.js} +2 -2
- package/public/assets/{formatted-body-impl-u0W_hWYA.js.map → formatted-body-impl-QqHxdMGP.js.map} +1 -1
- package/public/assets/index-CCp1V35c.js +22 -0
- package/public/assets/index-CCp1V35c.js.map +1 -0
- package/public/assets/index-DiR-fqy_.css +2 -0
- package/public/assets/{input-BHYNpXAG.js → input-BsNqlONJ.js} +2 -2
- package/public/assets/{input-BHYNpXAG.js.map → input-BsNqlONJ.js.map} +1 -1
- package/public/assets/{insights-CAF9Hi5D.js → insights-D-EyDfoZ.js} +2 -2
- package/public/assets/{insights-CAF9Hi5D.js.map → insights-D-EyDfoZ.js.map} +1 -1
- package/public/assets/{integrations-CG9qyHUf.js → integrations-D1kc-yNi.js} +2 -2
- package/public/assets/{integrations-CG9qyHUf.js.map → integrations-D1kc-yNi.js.map} +1 -1
- package/public/assets/{lib-Df4aph5u.js → lib-bXPu6xCL.js} +2 -2
- package/public/assets/{lib-Df4aph5u.js.map → lib-bXPu6xCL.js.map} +1 -1
- package/public/assets/lucide-react-DWYjU-AF.js +9 -0
- package/public/assets/{lucide-react-L2UxFDic.js.map → lucide-react-DWYjU-AF.js.map} +1 -1
- package/public/assets/{maintenance-DgHA35ve.js → maintenance-COqID7aq.js} +2 -2
- package/public/assets/{maintenance-DgHA35ve.js.map → maintenance-COqID7aq.js.map} +1 -1
- package/public/assets/{managed-agents-Rk6ghKR9.js → managed-agents-b4B8qewQ.js} +2 -2
- package/public/assets/{managed-agents-Rk6ghKR9.js.map → managed-agents-b4B8qewQ.js.map} +1 -1
- package/public/assets/{markdown-preview-impl-NWMtJdYz.js → markdown-preview-impl-D7o8jS07.js} +2 -2
- package/public/assets/{markdown-preview-impl-NWMtJdYz.js.map → markdown-preview-impl-D7o8jS07.js.map} +1 -1
- package/public/assets/memory-Q0qF7_i3.js +2 -0
- package/public/assets/{memory-DamwWa9A.js.map → memory-Q0qF7_i3.js.map} +1 -1
- package/public/assets/{messages--NU-YIL6.js → messages-m4EpkK6s.js} +2 -2
- package/public/assets/{messages--NU-YIL6.js.map → messages-m4EpkK6s.js.map} +1 -1
- package/public/assets/{orchestrators-DQnIn6qx.js → orchestrators-CnAtGfUN.js} +2 -2
- package/public/assets/{orchestrators-DQnIn6qx.js.map → orchestrators-CnAtGfUN.js.map} +1 -1
- package/public/assets/{overview-DCmNgXDf.js → overview-D7CF88ik.js} +2 -2
- package/public/assets/{overview-DCmNgXDf.js.map → overview-D7CF88ik.js.map} +1 -1
- package/public/assets/pairs-Q6PlFJtH.js +2 -0
- package/public/assets/{pairs-DNELeC9P.js.map → pairs-Q6PlFJtH.js.map} +1 -1
- package/public/assets/{react-dom-CrP_AtcL.js → react-dom-CPghDLpB.js} +2 -2
- package/public/assets/{react-dom-CrP_AtcL.js.map → react-dom-CPghDLpB.js.map} +1 -1
- package/public/assets/{security-Dd3Kh0oC.js → security-BeV-6SdA.js} +2 -2
- package/public/assets/{security-Dd3Kh0oC.js.map → security-BeV-6SdA.js.map} +1 -1
- package/public/assets/{select-DQbeJZX0.js → select-Dchc0_Jg.js} +2 -2
- package/public/assets/{select-DQbeJZX0.js.map → select-Dchc0_Jg.js.map} +1 -1
- package/public/assets/{settings-BMAJrBIH.js → settings-hPwL-31u.js} +3 -3
- package/public/assets/{settings-BMAJrBIH.js.map → settings-hPwL-31u.js.map} +1 -1
- package/public/assets/store-Buwkqv_7.js +9 -0
- package/public/assets/store-Buwkqv_7.js.map +1 -0
- package/public/assets/tasks-DKUMPEgk.js +2 -0
- package/public/assets/{tasks-BYR4L9GP.js.map → tasks-DKUMPEgk.js.map} +1 -1
- package/public/assets/teams-T5fFsdOX.js +2 -0
- package/public/assets/teams-T5fFsdOX.js.map +1 -0
- package/public/assets/{terminal-viewer-impl-B1YzfpE6.js → terminal-viewer-impl-Bk0u_Mav.js} +3 -3
- package/public/assets/{terminal-viewer-impl-B1YzfpE6.js.map → terminal-viewer-impl-Bk0u_Mav.js.map} +1 -1
- package/public/assets/{use-keyboard-viewport-DrRH_QzG.js → use-keyboard-viewport-NKw1O5gC.js} +2 -2
- package/public/assets/{use-keyboard-viewport-DrRH_QzG.js.map → use-keyboard-viewport-NKw1O5gC.js.map} +1 -1
- package/public/assets/{work-queue-x57vlgyZ.js → work-queue-D26jok09.js} +2 -2
- package/public/assets/{work-queue-x57vlgyZ.js.map → work-queue-D26jok09.js.map} +1 -1
- package/public/assets/{workspaces-CYm5bLg9.js → workspaces-BMj6zx23.js} +3 -3
- package/public/assets/{workspaces-CYm5bLg9.js.map → workspaces-BMj6zx23.js.map} +1 -1
- package/public/index.html +21 -21
- package/public/sw.js +32 -8
- package/src/automations.ts +40 -7
- package/src/branch-landed.ts +5 -0
- package/src/bus.ts +3 -0
- package/src/cli/workspace.ts +9 -17
- package/src/db/activity.ts +191 -3
- package/src/db/integrations.ts +1 -0
- package/src/db/issue-associations.ts +128 -0
- package/src/db/issue-lifecycle.ts +187 -0
- package/src/db/issue-refs.ts +254 -0
- package/src/db/mappers.ts +2 -0
- package/src/db/migrations.ts +47 -0
- package/src/db/schema.ts +2 -2
- package/src/issue-tracker/adapter.ts +24 -0
- package/src/issue-tracker/github.ts +136 -0
- package/src/issue-tracker/index.ts +13 -0
- package/src/issue-tracker/registry.ts +26 -0
- package/src/maintenance.ts +22 -169
- package/src/mcp-issue-activity-tools.ts +114 -0
- package/src/mcp-issue-association-tools.ts +130 -0
- package/src/mcp-issue-lifecycle-tools.ts +55 -0
- package/src/mcp-issue-ref-tools.ts +174 -0
- package/src/mcp-team-tools.ts +1 -1
- package/src/mcp.ts +3 -3
- package/src/provider-config-store.ts +30 -8
- package/src/routes/activity.ts +6 -1
- package/src/routes/commands.ts +29 -0
- package/src/routes/index.ts +19 -0
- package/src/routes/issue-activity.ts +78 -0
- package/src/routes/issue-associations.ts +76 -0
- package/src/routes/issue-lifecycle.ts +34 -0
- package/src/routes/issue-refs.ts +137 -0
- package/src/routes/orchestrator.ts +42 -1
- package/src/security.ts +8 -0
- package/src/services/issue-activity.ts +30 -0
- package/src/services/issue-associations.ts +72 -0
- package/src/services/issue-lifecycle.ts +308 -0
- package/src/services/issue-refs.ts +32 -0
- package/src/services/plan-graph.ts +40 -2
- package/src/services/team.ts +4 -0
- package/src/token-db.ts +3 -3
- package/src/workspace-actions.ts +8 -1
- package/src/workspace-auto-merge.ts +228 -0
- package/src/workspace-probe.ts +125 -0
- package/public/assets/PlanGraphPanel-Dby7wq9c.js +0 -2
- package/public/assets/PlanGraphPanel-Dby7wq9c.js.map +0 -1
- package/public/assets/card-CcZ9hLI7.js +0 -2
- package/public/assets/channels-BG0Nib7y.js +0 -2
- package/public/assets/chat-CjP_crSl.js +0 -2
- package/public/assets/copy-button-eF3cKp4Q.js +0 -2
- package/public/assets/dist-BLBF7qqr.js +0 -2
- package/public/assets/dist-YpHfnnIA.js +0 -2
- package/public/assets/dist-qd198ib9.js +0 -2
- package/public/assets/index-BwfVOzUG.js +0 -21
- package/public/assets/index-BwfVOzUG.js.map +0 -1
- package/public/assets/index-Dn_GDXbi.css +0 -2
- package/public/assets/lucide-react-L2UxFDic.js +0 -9
- package/public/assets/memory-DamwWa9A.js +0 -2
- package/public/assets/pairs-DNELeC9P.js +0 -2
- package/public/assets/store-B8xP6z6T.js +0 -9
- package/public/assets/store-B8xP6z6T.js.map +0 -1
- package/public/assets/tasks-BYR4L9GP.js +0 -2
- package/public/assets/teams-CoTifrq_.js +0 -2
- package/public/assets/teams-CoTifrq_.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings-BMAJrBIH.js","names":[],"sources":["../../dashboard/src/components/settings/schema-utils.ts","../../dashboard/src/components/settings/schema-form.tsx","../../dashboard/src/components/settings/browser-settings.tsx","../../dashboard/src/components/settings/model-catalog-settings.tsx","../../dashboard/src/components/views/settings.tsx"],"sourcesContent":["import { isRecord, type JSONSchema, type SettingEntry } from 'agent-relay-sdk/types'\n\nexport { hasScope } from 'agent-relay-sdk/types'\nexport type { SettingEntry }\n\ninterface SettingGroup {\n group: string\n slug: string\n settings: SettingEntry[]\n}\n\nexport type Path = Array<string | number>\n\nexport function settingId(setting: Pick<SettingEntry, 'namespace' | 'key'>): string {\n return `${setting.namespace}/${setting.key}`\n}\n\nexport function settingPath(setting: Pick<SettingEntry, 'namespace' | 'key'>): string {\n return `/settings/${encodeURIComponent(setting.namespace)}/${encodeURIComponent(setting.key)}`\n}\n\nexport function slugify(value: string): string {\n return value.trim().toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '') || 'settings'\n}\n\nexport function groupSettings(settings: SettingEntry[]): SettingGroup[] {\n const groups = new Map<string, SettingEntry[]>()\n for (const setting of settings.filter((entry) => entry.readable)) {\n const group = setting.display?.group?.trim() || setting.namespace\n groups.set(group, [...(groups.get(group) ?? []), setting])\n }\n return [...groups.entries()]\n .map(([group, items]) => ({\n group,\n slug: slugify(group),\n settings: items.sort(compareSettings),\n }))\n .sort((a, b) => groupOrder(a.settings) - groupOrder(b.settings) || a.group.localeCompare(b.group))\n}\n\nfunction compareSettings(a: SettingEntry, b: SettingEntry): number {\n return (a.display?.order ?? Number.MAX_SAFE_INTEGER) - (b.display?.order ?? Number.MAX_SAFE_INTEGER)\n || a.display?.label?.localeCompare(b.display?.label ?? '') || 0\n || settingId(a).localeCompare(settingId(b))\n}\n\nfunction groupOrder(settings: SettingEntry[]): number {\n return Math.min(...settings.map((setting) => setting.display?.order ?? Number.MAX_SAFE_INTEGER))\n}\n\nexport function schemaType(schema: JSONSchema): string | undefined {\n return Array.isArray(schema.type) ? schema.type.find((type) => type !== 'null') : schema.type\n}\n\nexport function valueAtPath(value: unknown, path: Path): unknown {\n let current = value\n for (const part of path) {\n if (typeof part === 'number') {\n if (!Array.isArray(current)) return undefined\n current = current[part]\n } else {\n if (!isRecord(current)) return undefined\n current = current[part]\n }\n }\n return current\n}\n\nexport function setValueAtPath(value: unknown, path: Path, next: unknown): unknown {\n if (!path.length) return next\n const [head, ...tail] = path\n if (head === undefined) return next\n if (typeof head === 'number') {\n const array = Array.isArray(value) ? [...value] : []\n array[head] = setValueAtPath(array[head], tail, next)\n return array\n }\n const record = isRecord(value) ? { ...value } : {}\n const updated = setValueAtPath(record[head], tail, next)\n if (updated === undefined) delete record[head]\n else record[head] = updated\n return record\n}\n\nexport function defaultValueForSchema(schema: JSONSchema): unknown {\n if (schema.default !== undefined) return schema.default\n if (schema.const !== undefined) return schema.const\n if (schema.enum?.length) return schema.enum[0]\n switch (schemaType(schema)) {\n case 'boolean': return false\n case 'integer':\n case 'number': return 0\n case 'array': return []\n case 'object': return {}\n case 'string': return ''\n default: return undefined\n }\n}\n\nexport function lines(value: string): string[] {\n return value.split(/\\r?\\n|,/).map((line) => line.trim()).filter(Boolean)\n}\n\nexport function arrayText(value: unknown): string {\n return Array.isArray(value) ? value.map((item) => String(item)).join('\\n') : ''\n}\n\nexport function recordText(value: unknown): string {\n if (!isRecord(value)) return ''\n return Object.entries(value).map(([key, item]) => `${key}=${String(item ?? '')}`).join('\\n')\n}\n\nexport function parseRecordText(value: string): Record<string, string> {\n return Object.fromEntries(value.split(/\\r?\\n/).map((raw) => raw.trim()).filter(Boolean).map((line) => {\n const idx = line.indexOf('=')\n return idx >= 0 ? [line.slice(0, idx).trim(), line.slice(idx + 1)] : [line, '']\n }))\n}\n\nexport { isRecord }\n","import { useState, type ReactNode } from 'react'\nimport type { JSONSchema, SettingTier } from 'agent-relay-sdk/types'\nimport { api, type ApiError } from '@/lib/api'\nimport { Button } from '@/components/ui/button'\nimport { Input } from '@/components/ui/input'\nimport { Textarea } from '@/components/ui/textarea'\nimport { Switch } from '@/components/ui/switch'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'\nimport { Badge } from '@/components/ui/badge'\nimport { Card, CardAction, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'\nimport { AlertCircle, CheckCircle2, MonitorCog, Save, ServerCog } from 'lucide-react'\nimport {\n arrayText,\n defaultValueForSchema,\n isRecord,\n lines,\n parseRecordText,\n recordText,\n schemaType,\n setValueAtPath,\n settingId,\n settingPath,\n type Path,\n type SettingEntry,\n} from './schema-utils'\n\nexport const UNSET = '__unset__'\n\nfunction tierLabel(tier: SettingTier): string {\n if (tier === 'server-runtime') return 'Server runtime'\n if (tier === 'bootstrap') return 'Bootstrap'\n return 'Browser'\n}\n\nfunction tierDescription(tier: SettingTier): string {\n if (tier === 'server-runtime') return 'Stored by Relay and mutable while the server is running.'\n if (tier === 'bootstrap') return 'Read from startup configuration; restart or host config changes are required.'\n return 'Stored only in this browser profile.'\n}\n\nfunction tierIcon(tier: SettingTier) {\n if (tier === 'browser') return <MonitorCog className=\"size-3.5\" />\n return <ServerCog className=\"size-3.5\" />\n}\n\nexport function errorDetails(error: unknown): string[] {\n return (error as ApiError).details ?? []\n}\n\nexport function SchemaGroup({ group, settings, onSaved }: { group: string; settings: SettingEntry[]; onSaved: (setting: SettingEntry) => void }) {\n const tiers = [...new Set(settings.map((setting) => setting.tier))]\n return (\n <section className=\"space-y-3\">\n <div className=\"flex flex-wrap items-center justify-between gap-2\">\n <h2 className=\"text-base font-semibold\">{group}</h2>\n <div className=\"flex flex-wrap gap-1\">\n {tiers.map((tier) => (\n <Badge key={tier} variant=\"outline\" className=\"gap-1\" title={tierDescription(tier)}>\n {tierIcon(tier)}\n {tierLabel(tier)}\n </Badge>\n ))}\n </div>\n </div>\n {settings.length === 0 ? (\n <Card size=\"sm\">\n <CardContent className=\"text-sm text-muted-foreground\">No settings in this group.</CardContent>\n </Card>\n ) : (\n <div className=\"space-y-3\">\n {settings.map((setting) => (\n <SettingCard key={settingId(setting)} setting={setting} onSaved={onSaved} />\n ))}\n </div>\n )}\n </section>\n )\n}\n\nfunction SettingCard({ setting, onSaved }: { setting: SettingEntry; onSaved: (setting: SettingEntry) => void }) {\n const [draft, setDraft] = useState<unknown>(() => setting.value ?? setting.defaults ?? defaultValueForSchema(setting.schema))\n const [saving, setSaving] = useState(false)\n const [status, setStatus] = useState('')\n const [errors, setErrors] = useState<string[]>([])\n const isWritable = setting.writable && setting.tier === 'server-runtime'\n\n function update(path: Path, value: unknown) {\n setDraft((current: unknown) => setValueAtPath(current, path, value))\n setErrors([])\n setStatus('')\n }\n\n async function save() {\n if (!isWritable) return\n setSaving(true)\n setErrors([])\n setStatus('')\n try {\n const saved = await api<SettingEntry>('PUT', settingPath(setting), { value: draft, updatedBy: 'dashboard' })\n setDraft(saved.value)\n onSaved(saved)\n setStatus('Saved')\n } catch (e) {\n const details = errorDetails(e)\n setErrors(details.length ? details : [(e as Error).message])\n } finally {\n setSaving(false)\n }\n }\n\n return (\n <Card size=\"sm\">\n <CardHeader>\n <CardTitle className=\"flex flex-wrap items-center gap-2 text-sm\">\n {setting.display.label}\n <Badge variant=\"outline\" className=\"gap-1\" title={tierDescription(setting.tier)}>{tierIcon(setting.tier)}{tierLabel(setting.tier)}</Badge>\n {!setting.writable && <Badge variant=\"secondary\">Read only</Badge>}\n </CardTitle>\n {setting.display.description && <CardDescription>{setting.display.description}</CardDescription>}\n <CardAction>\n <Button size=\"sm\" onClick={save} disabled={!isWritable || saving}>\n <Save className=\"size-4\" />\n {saving ? 'Saving' : 'Save'}\n </Button>\n </CardAction>\n </CardHeader>\n\n <CardContent className=\"space-y-3\">\n <SchemaField\n schema={setting.schema}\n value={draft}\n path={[]}\n label={setting.display.label}\n required\n disabled={!isWritable || saving}\n onChange={update}\n />\n\n <p className=\"flex flex-wrap items-center gap-x-2 text-[11px] text-muted-foreground\">\n <code className=\"rounded bg-muted px-1.5 py-0.5 font-mono\">{setting.namespace}/{setting.key}</code>\n <span>read <span className=\"text-foreground/70\">{setting.scope.read}</span></span>\n <span aria-hidden>·</span>\n <span>write <span className=\"text-foreground/70\">{setting.scope.write}</span></span>\n </p>\n\n {errors.length > 0 && (\n <div className=\"rounded-md border border-destructive/40 bg-destructive/10 p-3 text-sm text-destructive\">\n <div className=\"mb-1 flex items-center gap-2 font-medium\"><AlertCircle className=\"size-4\" />Save failed</div>\n <ul className=\"list-disc space-y-1 pl-5\">\n {errors.map((detail) => <li key={detail}>{detail}</li>)}\n </ul>\n </div>\n )}\n {status && <p className=\"flex items-center gap-1 text-sm text-emerald-500\"><CheckCircle2 className=\"size-4\" />{status}</p>}\n </CardContent>\n </Card>\n )\n}\n\nfunction SchemaField(props: {\n schema: JSONSchema\n value: unknown\n path: Path\n label: string\n required: boolean\n disabled: boolean\n onChange: (path: Path, value: unknown) => void\n}) {\n const { schema, value, path, label, required, disabled, onChange } = props\n const type = schemaType(schema)\n\n if (schema.enum?.length) {\n const current = value === undefined || value === null || value === '' ? UNSET : String(value)\n return (\n <Field label={label} description={schema.description}>\n <Select value={current} onValueChange={(next) => onChange(path, next === UNSET ? undefined : next)} disabled={disabled}>\n <SelectTrigger><SelectValue /></SelectTrigger>\n <SelectContent>\n {!required && <SelectItem value={UNSET}>Not set</SelectItem>}\n {schema.enum.map((item) => <SelectItem key={String(item)} value={String(item)}>{String(item)}</SelectItem>)}\n </SelectContent>\n </Select>\n </Field>\n )\n }\n\n if (type === 'boolean') {\n return (\n <div className=\"flex items-center justify-between gap-3 rounded-md border bg-muted/20 p-3\">\n <div>\n <div className=\"text-sm font-medium\">{label}</div>\n {schema.description && <div className=\"text-xs text-muted-foreground\">{schema.description}</div>}\n </div>\n <Switch checked={Boolean(value)} onCheckedChange={(next) => onChange(path, next)} disabled={disabled} />\n </div>\n )\n }\n\n if (type === 'integer' || type === 'number') {\n return (\n <Field label={label} description={schema.description}>\n <Input\n type=\"number\"\n min={typeof schema.minimum === 'number' ? schema.minimum : undefined}\n max={typeof schema.maximum === 'number' ? schema.maximum : undefined}\n step={type === 'integer' ? 1 : 'any'}\n value={typeof value === 'number' ? value : ''}\n disabled={disabled}\n onChange={(e) => onChange(path, e.target.value === '' && !required ? undefined : Number(e.target.value))}\n />\n </Field>\n )\n }\n\n if (type === 'array') {\n return (\n <Field label={label} description={schema.description ?? 'One item per line.'}>\n <Textarea\n rows={Math.min(8, Math.max(3, Array.isArray(value) ? value.length + 1 : 3))}\n value={arrayText(value)}\n disabled={disabled}\n onChange={(e) => onChange(path, lines(e.target.value))}\n />\n </Field>\n )\n }\n\n if (type === 'object') {\n const properties = schema.properties ?? {}\n const requiredKeys = new Set(schema.required ?? [])\n if (Object.keys(properties).length === 0 && schema.additionalProperties) {\n return (\n <Field label={label} description={schema.description ?? 'KEY=value, one entry per line.'}>\n <Textarea rows={5} value={recordText(value)} disabled={disabled} onChange={(e) => onChange(path, parseRecordText(e.target.value))} />\n </Field>\n )\n }\n return (\n <div className=\"space-y-3\">\n {path.length > 0 && (\n <div>\n <div className=\"text-sm font-medium\">{label}</div>\n {schema.description && <div className=\"text-xs text-muted-foreground\">{schema.description}</div>}\n </div>\n )}\n <div className=\"grid gap-3 md:grid-cols-2\">\n {Object.entries(properties).map(([key, child]) => {\n const childValue = isRecord(value) ? value[key] : undefined\n return (\n <SchemaField\n key={key}\n schema={child}\n value={childValue === undefined && requiredKeys.has(key) ? defaultValueForSchema(child) : childValue}\n path={[...path, key]}\n label={child.title || labelForKey(key)}\n required={requiredKeys.has(key)}\n disabled={disabled}\n onChange={onChange}\n />\n )\n })}\n </div>\n </div>\n )\n }\n\n return (\n <Field label={label} description={schema.description}>\n <Input\n value={typeof value === 'string' ? value : value == null ? '' : String(value)}\n disabled={disabled}\n onChange={(e) => onChange(path, e.target.value === '' && !required ? undefined : e.target.value)}\n />\n </Field>\n )\n}\n\nexport function Field({ label, description, children }: { label: string; description?: string; children: ReactNode }) {\n return (\n <label className=\"block space-y-1.5 text-sm\">\n <span className=\"text-muted-foreground\">{label}</span>\n {children}\n {description && <span className=\"block text-xs text-muted-foreground\">{description}</span>}\n </label>\n )\n}\n\nfunction labelForKey(key: string): string {\n return key.replace(/([a-z0-9])([A-Z])/g, '$1 $2').replace(/[-_]+/g, ' ').replace(/^\\w/, (char) => char.toUpperCase())\n}\n","import { useEffect, useState } from 'react'\nimport { THEMES } from '@/lib/themes'\nimport { KOKORO_VOICES, availableSpeechVoices } from '@/lib/voice'\nimport { useRelayStore } from '@/store'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'\nimport { Switch } from '@/components/ui/switch'\nimport { Badge } from '@/components/ui/badge'\nimport { Card, CardAction, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'\nimport { Brain, MonitorCog, Volume2 } from 'lucide-react'\nimport type { ThemeId } from '@/types'\nimport { Field, UNSET } from './schema-form'\n\nexport function BrowserSettings() {\n const theme = useRelayStore((s) => s.theme)\n const showReasoning = useRelayStore((s) => s.showReasoning)\n const set = useRelayStore((s) => s.set)\n return (\n <section className=\"space-y-4\">\n <div>\n <h2 className=\"text-base font-semibold\">Browser preferences</h2>\n <p className=\"text-sm text-muted-foreground\">These are stored in local dashboard state, not in Relay server config.</p>\n </div>\n <Card size=\"sm\">\n <CardHeader>\n <CardTitle className=\"text-sm\">Dashboard display</CardTitle>\n <CardDescription className=\"text-xs\">Browser tier · persisted in this browser profile.</CardDescription>\n <CardAction>\n <Badge variant=\"outline\" className=\"gap-1\"><MonitorCog className=\"size-3.5\" />Browser</Badge>\n </CardAction>\n </CardHeader>\n <CardContent className=\"grid gap-3 md:grid-cols-2\">\n <Field label=\"Theme\">\n <Select value={theme} onValueChange={(value) => set({ theme: value as ThemeId })}>\n <SelectTrigger><SelectValue /></SelectTrigger>\n <SelectContent>\n {THEMES.map((item) => <SelectItem key={item.id} value={item.id}>{item.label}</SelectItem>)}\n </SelectContent>\n </Select>\n </Field>\n <div className=\"flex items-center justify-between gap-3 rounded-md border bg-muted/20 p-3\">\n <div className=\"flex items-center gap-2\">\n <Brain className=\"size-4\" />\n <div>\n <div className=\"text-sm font-medium\">Show reasoning details</div>\n <div className=\"text-xs text-muted-foreground\">Display captured reasoning/tool steps in chat. Server capture is controlled separately by provider reasoningCapture.</div>\n </div>\n </div>\n <Switch checked={showReasoning} onCheckedChange={(value) => set({ showReasoning: value })} />\n </div>\n </CardContent>\n </Card>\n <VoiceSettings />\n </section>\n )\n}\n\nfunction VoiceSettings() {\n const voiceTtsEnabled = useRelayStore((s) => s.voiceTtsEnabled)\n const setVoiceTtsEnabled = useRelayStore((s) => s.setVoiceTtsEnabled)\n const voiceTtsMode = useRelayStore((s) => s.voiceTtsMode)\n const setVoiceTtsMode = useRelayStore((s) => s.setVoiceTtsMode)\n const voiceTtsKokoroVoice = useRelayStore((s) => s.voiceTtsKokoroVoice)\n const setVoiceTtsKokoroVoice = useRelayStore((s) => s.setVoiceTtsKokoroVoice)\n const voiceTtsBrowserVoice = useRelayStore((s) => s.voiceTtsBrowserVoice)\n const setVoiceTtsBrowserVoice = useRelayStore((s) => s.setVoiceTtsBrowserVoice)\n const voiceInputMode = useRelayStore((s) => s.voiceInputMode)\n const setVoiceInputMode = useRelayStore((s) => s.setVoiceInputMode)\n\n // External sync: the browser loads speech voices asynchronously.\n const [browserVoices, setBrowserVoices] = useState(() => availableSpeechVoices())\n useEffect(() => {\n if (typeof window === 'undefined' || !('speechSynthesis' in window)) return\n const refresh = () => setBrowserVoices(availableSpeechVoices())\n refresh()\n window.speechSynthesis.addEventListener?.('voiceschanged', refresh)\n return () => window.speechSynthesis.removeEventListener?.('voiceschanged', refresh)\n }, [])\n\n const kokoroOptions = KOKORO_VOICES.some((voice) => voice.id === voiceTtsKokoroVoice)\n ? KOKORO_VOICES\n : [...KOKORO_VOICES, { id: voiceTtsKokoroVoice, label: voiceTtsKokoroVoice }]\n\n return (\n <Card size=\"sm\">\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2 text-sm\"><Volume2 className=\"size-4\" />Voice</CardTitle>\n <CardDescription className=\"text-xs\">Browser tier TTS and push-to-talk behavior.</CardDescription>\n <CardAction>\n <Switch checked={voiceTtsEnabled} onCheckedChange={setVoiceTtsEnabled} />\n </CardAction>\n </CardHeader>\n <CardContent className=\"grid gap-3 md:grid-cols-2\">\n <Field label=\"Speech engine\">\n <Select value={voiceTtsMode} onValueChange={(value) => setVoiceTtsMode(value as 'kokoro' | 'browser')}>\n <SelectTrigger><SelectValue /></SelectTrigger>\n <SelectContent>\n <SelectItem value=\"kokoro\">Kokoro (server, fallback to browser)</SelectItem>\n <SelectItem value=\"browser\">Browser Web Speech API</SelectItem>\n </SelectContent>\n </Select>\n </Field>\n <Field label=\"Kokoro voice\">\n <Select value={voiceTtsKokoroVoice} onValueChange={setVoiceTtsKokoroVoice}>\n <SelectTrigger><SelectValue /></SelectTrigger>\n <SelectContent>\n {kokoroOptions.map((voice) => <SelectItem key={voice.id} value={voice.id}>{voice.label}</SelectItem>)}\n </SelectContent>\n </Select>\n </Field>\n <Field label=\"Browser voice\">\n <Select value={voiceTtsBrowserVoice || UNSET} onValueChange={(value) => setVoiceTtsBrowserVoice(value === UNSET ? '' : value)}>\n <SelectTrigger><SelectValue /></SelectTrigger>\n <SelectContent>\n <SelectItem value={UNSET}>System default</SelectItem>\n {browserVoices.map((voice) => <SelectItem key={voice.uri} value={voice.uri}>{voice.label}</SelectItem>)}\n </SelectContent>\n </Select>\n </Field>\n <Field label=\"Push-to-talk input\">\n <Select value={voiceInputMode} onValueChange={(value) => setVoiceInputMode(value as 'compose' | 'autosend' | 'handsfree')}>\n <SelectTrigger><SelectValue /></SelectTrigger>\n <SelectContent>\n <SelectItem value=\"compose\">Fill message box</SelectItem>\n <SelectItem value=\"autosend\">Send immediately</SelectItem>\n </SelectContent>\n </Select>\n </Field>\n </CardContent>\n </Card>\n )\n}\n","import { useState } from 'react'\nimport type { SpawnProvider } from 'agent-relay-sdk/types'\nimport type { ProviderCatalogEntry, ProviderModelCatalogEntry } from 'agent-relay-sdk/provider-catalog'\nimport { api } from '@/lib/api'\nimport { Button } from '@/components/ui/button'\nimport { Input } from '@/components/ui/input'\nimport { Switch } from '@/components/ui/switch'\nimport { Badge } from '@/components/ui/badge'\nimport { Card, CardAction, CardContent, CardHeader, CardTitle } from '@/components/ui/card'\nimport { CheckCircle2, Eye, EyeOff, Pencil, Plus, ServerCog, SlidersHorizontal, Trash2 } from 'lucide-react'\nimport { errorDetails, Field } from './schema-form'\nimport { lines } from './schema-utils'\n\ninterface ProvidersResponse {\n catalog: ProviderCatalogEntry[]\n}\n\ninterface ModelForm {\n provider: SpawnProvider\n alias: string\n label: string\n providerModel: string\n efforts: string\n defaultEffort: string\n disabled: boolean\n}\n\nexport function ModelCatalogSettings({\n catalog,\n error,\n canWrite,\n onCatalog,\n}: {\n catalog: ProviderCatalogEntry[]\n error: string\n canWrite: boolean\n onCatalog: (catalog: ProviderCatalogEntry[]) => void\n}) {\n const firstProvider = catalog[0]?.provider ?? 'codex'\n const [provider, setProvider] = useState<SpawnProvider>(firstProvider)\n const [form, setForm] = useState<ModelForm>(() => emptyModelForm(firstProvider))\n const [status, setStatus] = useState('')\n const [errors, setErrors] = useState<string[]>([])\n\n const selectedProvider = catalog.some((entry) => entry.provider === provider) ? provider : firstProvider\n const selectedCatalog = catalog.find((entry) => entry.provider === selectedProvider) ?? catalog[0]\n const providers = catalog.map((entry) => entry.provider)\n\n function updateForm(patch: Partial<ModelForm>) {\n setForm((current) => ({ ...current, ...patch }))\n setErrors([])\n setStatus('')\n }\n\n function switchProvider(next: SpawnProvider) {\n setProvider(next)\n setForm(emptyModelForm(next))\n setErrors([])\n setStatus('')\n }\n\n async function reloadCatalog() {\n const res = await api<ProvidersResponse>('GET', '/providers')\n onCatalog(res.catalog)\n }\n\n async function saveModel() {\n if (!canWrite) return\n setErrors([])\n setStatus('')\n try {\n await api('PUT', `/providers/${encodeURIComponent(form.provider)}/models/${encodeURIComponent(form.alias)}`, {\n label: form.label,\n providerModel: form.providerModel,\n efforts: lines(form.efforts),\n defaultEffort: form.defaultEffort.trim() || undefined,\n disabled: form.disabled,\n updatedBy: 'dashboard',\n })\n await reloadCatalog()\n setStatus(`${form.alias} saved`)\n setForm(emptyModelForm(form.provider))\n } catch (e) {\n const details = errorDetails(e)\n setErrors(details.length ? details : [(e as Error).message])\n }\n }\n\n async function setDisabled(model: ProviderModelCatalogEntry, disabled: boolean) {\n if (!canWrite) return\n setErrors([])\n setStatus('')\n try {\n await api('PATCH', `/providers/${encodeURIComponent(selectedProvider)}/models/${encodeURIComponent(model.alias)}`, { disabled, updatedBy: 'dashboard' })\n await reloadCatalog()\n setStatus(`${model.alias} ${disabled ? 'disabled' : 'enabled'}`)\n } catch (e) {\n const details = errorDetails(e)\n setErrors(details.length ? details : [(e as Error).message])\n }\n }\n\n async function removeModel(model: ProviderModelCatalogEntry) {\n if (!canWrite) return\n setErrors([])\n setStatus('')\n try {\n await api('DELETE', `/providers/${encodeURIComponent(selectedProvider)}/models/${encodeURIComponent(model.alias)}`)\n await reloadCatalog()\n setStatus(`${model.alias} removed`)\n } catch (e) {\n const details = errorDetails(e)\n setErrors(details.length ? details : [(e as Error).message])\n }\n }\n\n function editModel(model: ProviderModelCatalogEntry) {\n setForm({\n provider: selectedProvider,\n alias: model.alias,\n label: model.label,\n providerModel: model.providerModel,\n efforts: model.efforts.join(', '),\n defaultEffort: model.defaultEffort ?? '',\n disabled: Boolean(model.disabled),\n })\n setErrors([])\n setStatus('')\n }\n\n if (error) {\n return (\n <Card size=\"sm\">\n <CardContent className=\"text-sm text-muted-foreground\">\n <div className=\"mb-1 flex items-center gap-2 font-medium text-foreground\"><SlidersHorizontal className=\"size-4\" />Model catalog</div>\n {error}\n </CardContent>\n </Card>\n )\n }\n\n return (\n <section className=\"space-y-4\">\n <div className=\"flex flex-wrap items-start justify-between gap-3\">\n <div>\n <h2 className=\"text-base font-semibold\">Model catalog</h2>\n <p className=\"text-sm text-muted-foreground\">Add override models, disable unavailable models, or remove custom entries from the provider catalog.</p>\n </div>\n {!canWrite && <Badge variant=\"secondary\">Read only: needs settings:write:provider</Badge>}\n </div>\n\n <div className=\"flex flex-wrap gap-2\">\n {providers.map((item) => (\n <Button key={item} variant={item === selectedProvider ? 'default' : 'outline'} size=\"sm\" onClick={() => switchProvider(item)}>\n {item}\n </Button>\n ))}\n </div>\n\n <Card size=\"sm\">\n <CardHeader>\n <CardTitle className=\"text-sm\">Add or edit model</CardTitle>\n <CardAction>\n <Badge variant=\"outline\" className=\"gap-1\"><ServerCog className=\"size-3.5\" />Server runtime</Badge>\n </CardAction>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n <div className=\"grid gap-3 md:grid-cols-2\">\n <Field label=\"Alias\">\n <Input value={form.alias} disabled={!canWrite} placeholder=\"nightly\" onChange={(e) => updateForm({ alias: e.target.value.trim() })} />\n </Field>\n <Field label=\"Label\">\n <Input value={form.label} disabled={!canWrite} placeholder=\"Nightly Codex\" onChange={(e) => updateForm({ label: e.target.value })} />\n </Field>\n <Field label=\"Provider model\">\n <Input value={form.providerModel} disabled={!canWrite} placeholder=\"codex-nightly\" onChange={(e) => updateForm({ providerModel: e.target.value })} />\n </Field>\n <Field label=\"Efforts\">\n <Input value={form.efforts} disabled={!canWrite} placeholder=\"low, medium, high\" onChange={(e) => updateForm({ efforts: e.target.value })} />\n </Field>\n <Field label=\"Default effort\">\n <Input value={form.defaultEffort} disabled={!canWrite} placeholder=\"medium\" onChange={(e) => updateForm({ defaultEffort: e.target.value })} />\n </Field>\n <div className=\"flex items-center justify-between gap-3 rounded-md border bg-muted/20 p-3\">\n <div>\n <div className=\"text-sm font-medium\">Disabled</div>\n <div className=\"text-xs text-muted-foreground\">Keep visible but unavailable for new launches.</div>\n </div>\n <Switch checked={form.disabled} disabled={!canWrite} onCheckedChange={(disabled) => updateForm({ disabled })} />\n </div>\n </div>\n <Button onClick={saveModel} disabled={!canWrite || !form.alias || !form.label || !form.providerModel}>\n <Plus className=\"size-4\" />\n Save model\n </Button>\n </CardContent>\n </Card>\n\n <div className=\"space-y-2\">\n {selectedCatalog && selectedCatalog.models.length === 0 && (\n <Card size=\"sm\">\n <CardContent className=\"text-sm text-muted-foreground\">No models in this provider catalog yet.</CardContent>\n </Card>\n )}\n {selectedCatalog?.models.map((model) => (\n <Card key={model.alias} size=\"sm\">\n <CardContent className=\"flex flex-wrap items-center justify-between gap-3\">\n <div className=\"min-w-0\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"font-medium\">{model.label}</span>\n <code className=\"rounded bg-muted px-1.5 py-0.5 font-mono text-xs\">{model.alias}</code>\n {model.disabled && <Badge variant=\"secondary\">Disabled</Badge>}\n </div>\n <p className=\"mt-1 text-xs text-muted-foreground\">\n {model.providerModel}\n {model.efforts.length > 0 ? ` · efforts ${model.efforts.join(', ')}` : ' · no effort levels'}\n {model.defaultEffort ? ` · default ${model.defaultEffort}` : ''}\n </p>\n </div>\n <div className=\"flex flex-wrap gap-2\">\n <Button variant=\"outline\" size=\"sm\" onClick={() => editModel(model)}>\n <Pencil className=\"size-4\" />\n Edit\n </Button>\n <Button variant=\"outline\" size=\"sm\" disabled={!canWrite} onClick={() => void setDisabled(model, !model.disabled)}>\n {model.disabled ? <Eye className=\"size-4\" /> : <EyeOff className=\"size-4\" />}\n {model.disabled ? 'Enable' : 'Disable'}\n </Button>\n <Button variant=\"outline\" size=\"sm\" disabled={!canWrite} onClick={() => void removeModel(model)}>\n <Trash2 className=\"size-4\" />\n Remove\n </Button>\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n\n {errors.length > 0 && (\n <div className=\"rounded-md border border-destructive/40 bg-destructive/10 p-3 text-sm text-destructive\">\n <ul className=\"list-disc space-y-1 pl-5\">\n {errors.map((detail) => <li key={detail}>{detail}</li>)}\n </ul>\n </div>\n )}\n {status && <p className=\"flex items-center gap-1 text-sm text-emerald-500\"><CheckCircle2 className=\"size-4\" />{status}</p>}\n </section>\n )\n}\n\nfunction emptyModelForm(provider: SpawnProvider): ModelForm {\n return { provider, alias: '', label: '', providerModel: '', efforts: '', defaultEffort: '', disabled: false }\n}\n","import { useEffect, useMemo, useState } from 'react'\nimport type { ProviderCatalogEntry } from 'agent-relay-sdk/provider-catalog'\nimport { api } from '@/lib/api'\nimport { cn } from '@/lib/utils'\nimport { Button } from '@/components/ui/button'\nimport { Badge } from '@/components/ui/badge'\nimport { Card, CardContent } from '@/components/ui/card'\nimport { AlertCircle, Globe2, RefreshCw } from 'lucide-react'\nimport { BrowserSettings } from '@/components/settings/browser-settings'\nimport { ModelCatalogSettings } from '@/components/settings/model-catalog-settings'\nimport { SchemaGroup } from '@/components/settings/schema-form'\nimport {\n groupSettings,\n hasScope,\n settingId,\n type SettingEntry,\n} from '@/components/settings/schema-utils'\n\ninterface SettingsResponse {\n settings: SettingEntry[]\n}\n\ninterface TokenMe {\n actor: string\n kind: string\n role?: string\n scopes: string[]\n}\n\ninterface ProvidersResponse {\n catalog: ProviderCatalogEntry[]\n}\n\nconst BROWSER_GROUP_SLUG = 'browser'\nconst MODELS_GROUP_SLUG = 'models'\n\nfunction settingsHash(): string {\n if (typeof window === 'undefined') return ''\n const hash = window.location.hash.replace(/^#/, '')\n if (!hash.startsWith('settings/')) return ''\n return decodeURIComponent(hash.slice('settings/'.length))\n}\n\nfunction writeSettingsHash(slug: string): void {\n if (typeof window === 'undefined') return\n const url = new URL(window.location.href)\n url.hash = `settings/${encodeURIComponent(slug)}`\n window.history.pushState({}, '', url)\n}\n\nexport function SettingsView() {\n const [settings, setSettings] = useState<SettingEntry[]>([])\n const [token, setToken] = useState<TokenMe | null>(null)\n const [catalog, setCatalog] = useState<ProviderCatalogEntry[]>([])\n const [active, setActive] = useState(() => settingsHash())\n const [loading, setLoading] = useState(true)\n const [loadError, setLoadError] = useState('')\n const [catalogError, setCatalogError] = useState('')\n\n async function reload() {\n setLoading(true)\n setLoadError('')\n setCatalogError('')\n try {\n const [settingsRes, tokenRes, providersRes] = await Promise.all([\n api<SettingsResponse>('GET', '/settings'),\n api<TokenMe>('GET', '/tokens/me'),\n api<ProvidersResponse>('GET', '/providers').catch((e) => {\n setCatalogError((e as Error).message)\n return { catalog: [] }\n }),\n ])\n setSettings(settingsRes.settings)\n setToken(tokenRes)\n setCatalog(providersRes.catalog)\n } catch (e) {\n setLoadError((e as Error).message)\n } finally {\n setLoading(false)\n }\n }\n\n useEffect(() => {\n void reload()\n }, [])\n\n // External sync: keep the selected settings group aligned with browser history.\n useEffect(() => {\n const sync = () => setActive(settingsHash())\n window.addEventListener('hashchange', sync)\n window.addEventListener('popstate', sync)\n return () => {\n window.removeEventListener('hashchange', sync)\n window.removeEventListener('popstate', sync)\n }\n }, [])\n\n const descriptorGroups = useMemo(() => groupSettings(settings), [settings])\n const groups = useMemo(() => [\n ...descriptorGroups.map((group) => ({\n slug: group.slug,\n label: group.group,\n description: `${group.settings.length} schema setting${group.settings.length === 1 ? '' : 's'}`,\n kind: 'descriptors' as const,\n settings: group.settings,\n })),\n {\n slug: BROWSER_GROUP_SLUG,\n label: 'Browser',\n description: 'Local dashboard preferences',\n kind: 'browser' as const,\n settings: [],\n },\n {\n slug: MODELS_GROUP_SLUG,\n label: 'Models',\n description: 'Provider model catalog',\n kind: 'models' as const,\n settings: [],\n },\n ], [descriptorGroups])\n\n const activeGroup = groups.find((group) => group.slug === active) ?? groups[0]\n\n function selectGroup(slug: string) {\n setActive(slug)\n writeSettingsHash(slug)\n }\n\n function replaceSetting(updated: SettingEntry) {\n setSettings((current) => current.map((entry) => settingId(entry) === settingId(updated) ? updated : entry))\n }\n\n return (\n <div className=\"space-y-4\">\n <div className=\"flex flex-wrap items-start justify-between gap-3\">\n <div>\n <h1 className=\"text-lg font-semibold\">Settings</h1>\n <p className=\"text-sm text-muted-foreground\">Schema-driven Relay settings, browser preferences, and model catalog controls.</p>\n </div>\n <div className=\"flex flex-wrap items-center gap-2\">\n {token && (\n <Badge variant=\"outline\" className=\"gap-1\">\n <Globe2 className=\"size-3\" />\n {token.kind}:{token.actor}\n </Badge>\n )}\n <Button variant=\"outline\" size=\"sm\" onClick={() => void reload()} disabled={loading}>\n <RefreshCw className={cn('size-4', loading && 'animate-spin')} />\n Refresh\n </Button>\n </div>\n </div>\n\n {loadError && (\n <div className=\"flex items-start gap-2 rounded-lg border border-destructive/40 bg-destructive/10 p-3 text-sm text-destructive\">\n <AlertCircle className=\"mt-0.5 size-4\" />\n <span>{loadError}</span>\n </div>\n )}\n\n <div className=\"grid gap-4 lg:grid-cols-[230px_minmax(0,1fr)]\">\n <nav className=\"space-y-1 lg:sticky lg:top-4 lg:self-start\">\n {groups.map((group) => (\n <button\n key={group.slug}\n type=\"button\"\n className={cn(\n 'w-full rounded-md border px-3 py-2 text-left text-sm transition-colors',\n activeGroup?.slug === group.slug ? 'border-primary/50 bg-primary/10 text-foreground' : 'border-transparent hover:border-border hover:bg-accent',\n )}\n onClick={() => selectGroup(group.slug)}\n >\n <span className=\"block font-medium\">{group.label}</span>\n <span className=\"block truncate text-xs text-muted-foreground\">{group.description}</span>\n </button>\n ))}\n </nav>\n\n <div className=\"min-w-0 space-y-4\">\n {loading && !settings.length ? (\n <Card size=\"sm\">\n <CardContent className=\"text-sm text-muted-foreground\">Loading settings…</CardContent>\n </Card>\n ) : activeGroup?.kind === 'descriptors' ? (\n <SchemaGroup\n group={activeGroup.label}\n settings={activeGroup.settings}\n onSaved={replaceSetting}\n />\n ) : activeGroup?.kind === 'browser' ? (\n <BrowserSettings />\n ) : (\n <ModelCatalogSettings\n catalog={catalog}\n error={catalogError}\n canWrite={hasScope(token?.scopes, 'settings:write:provider')}\n onCatalog={setCatalog}\n />\n )}\n </div>\n </div>\n </div>\n )\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"settings-hPwL-31u.js","names":[],"sources":["../../dashboard/src/components/settings/schema-utils.ts","../../dashboard/src/components/settings/schema-form.tsx","../../dashboard/src/components/settings/browser-settings.tsx","../../dashboard/src/components/settings/model-catalog-settings.tsx","../../dashboard/src/components/views/settings.tsx"],"sourcesContent":["import { isRecord, type JSONSchema, type SettingEntry } from 'agent-relay-sdk/types'\n\nexport { hasScope } from 'agent-relay-sdk/types'\nexport type { SettingEntry }\n\ninterface SettingGroup {\n group: string\n slug: string\n settings: SettingEntry[]\n}\n\nexport type Path = Array<string | number>\n\nexport function settingId(setting: Pick<SettingEntry, 'namespace' | 'key'>): string {\n return `${setting.namespace}/${setting.key}`\n}\n\nexport function settingPath(setting: Pick<SettingEntry, 'namespace' | 'key'>): string {\n return `/settings/${encodeURIComponent(setting.namespace)}/${encodeURIComponent(setting.key)}`\n}\n\nexport function slugify(value: string): string {\n return value.trim().toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '') || 'settings'\n}\n\nexport function groupSettings(settings: SettingEntry[]): SettingGroup[] {\n const groups = new Map<string, SettingEntry[]>()\n for (const setting of settings.filter((entry) => entry.readable)) {\n const group = setting.display?.group?.trim() || setting.namespace\n groups.set(group, [...(groups.get(group) ?? []), setting])\n }\n return [...groups.entries()]\n .map(([group, items]) => ({\n group,\n slug: slugify(group),\n settings: items.sort(compareSettings),\n }))\n .sort((a, b) => groupOrder(a.settings) - groupOrder(b.settings) || a.group.localeCompare(b.group))\n}\n\nfunction compareSettings(a: SettingEntry, b: SettingEntry): number {\n return (a.display?.order ?? Number.MAX_SAFE_INTEGER) - (b.display?.order ?? Number.MAX_SAFE_INTEGER)\n || a.display?.label?.localeCompare(b.display?.label ?? '') || 0\n || settingId(a).localeCompare(settingId(b))\n}\n\nfunction groupOrder(settings: SettingEntry[]): number {\n return Math.min(...settings.map((setting) => setting.display?.order ?? Number.MAX_SAFE_INTEGER))\n}\n\nexport function schemaType(schema: JSONSchema): string | undefined {\n return Array.isArray(schema.type) ? schema.type.find((type) => type !== 'null') : schema.type\n}\n\nexport function valueAtPath(value: unknown, path: Path): unknown {\n let current = value\n for (const part of path) {\n if (typeof part === 'number') {\n if (!Array.isArray(current)) return undefined\n current = current[part]\n } else {\n if (!isRecord(current)) return undefined\n current = current[part]\n }\n }\n return current\n}\n\nexport function setValueAtPath(value: unknown, path: Path, next: unknown): unknown {\n if (!path.length) return next\n const [head, ...tail] = path\n if (head === undefined) return next\n if (typeof head === 'number') {\n const array = Array.isArray(value) ? [...value] : []\n array[head] = setValueAtPath(array[head], tail, next)\n return array\n }\n const record = isRecord(value) ? { ...value } : {}\n const updated = setValueAtPath(record[head], tail, next)\n if (updated === undefined) delete record[head]\n else record[head] = updated\n return record\n}\n\nexport function defaultValueForSchema(schema: JSONSchema): unknown {\n if (schema.default !== undefined) return schema.default\n if (schema.const !== undefined) return schema.const\n if (schema.enum?.length) return schema.enum[0]\n switch (schemaType(schema)) {\n case 'boolean': return false\n case 'integer':\n case 'number': return 0\n case 'array': return []\n case 'object': return {}\n case 'string': return ''\n default: return undefined\n }\n}\n\nexport function lines(value: string): string[] {\n return value.split(/\\r?\\n|,/).map((line) => line.trim()).filter(Boolean)\n}\n\nexport function arrayText(value: unknown): string {\n return Array.isArray(value) ? value.map((item) => String(item)).join('\\n') : ''\n}\n\nexport function recordText(value: unknown): string {\n if (!isRecord(value)) return ''\n return Object.entries(value).map(([key, item]) => `${key}=${String(item ?? '')}`).join('\\n')\n}\n\nexport function parseRecordText(value: string): Record<string, string> {\n return Object.fromEntries(value.split(/\\r?\\n/).map((raw) => raw.trim()).filter(Boolean).map((line) => {\n const idx = line.indexOf('=')\n return idx >= 0 ? [line.slice(0, idx).trim(), line.slice(idx + 1)] : [line, '']\n }))\n}\n\nexport { isRecord }\n","import { useState, type ReactNode } from 'react'\nimport type { JSONSchema, SettingTier } from 'agent-relay-sdk/types'\nimport { api, type ApiError } from '@/lib/api'\nimport { Button } from '@/components/ui/button'\nimport { Input } from '@/components/ui/input'\nimport { Textarea } from '@/components/ui/textarea'\nimport { Switch } from '@/components/ui/switch'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'\nimport { Badge } from '@/components/ui/badge'\nimport { Card, CardAction, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'\nimport { AlertCircle, CheckCircle2, MonitorCog, Save, ServerCog } from 'lucide-react'\nimport {\n arrayText,\n defaultValueForSchema,\n isRecord,\n lines,\n parseRecordText,\n recordText,\n schemaType,\n setValueAtPath,\n settingId,\n settingPath,\n type Path,\n type SettingEntry,\n} from './schema-utils'\n\nexport const UNSET = '__unset__'\n\nfunction tierLabel(tier: SettingTier): string {\n if (tier === 'server-runtime') return 'Server runtime'\n if (tier === 'bootstrap') return 'Bootstrap'\n return 'Browser'\n}\n\nfunction tierDescription(tier: SettingTier): string {\n if (tier === 'server-runtime') return 'Stored by Relay and mutable while the server is running.'\n if (tier === 'bootstrap') return 'Read from startup configuration; restart or host config changes are required.'\n return 'Stored only in this browser profile.'\n}\n\nfunction tierIcon(tier: SettingTier) {\n if (tier === 'browser') return <MonitorCog className=\"size-3.5\" />\n return <ServerCog className=\"size-3.5\" />\n}\n\nexport function errorDetails(error: unknown): string[] {\n return (error as ApiError).details ?? []\n}\n\nexport function SchemaGroup({ group, settings, onSaved }: { group: string; settings: SettingEntry[]; onSaved: (setting: SettingEntry) => void }) {\n const tiers = [...new Set(settings.map((setting) => setting.tier))]\n return (\n <section className=\"space-y-3\">\n <div className=\"flex flex-wrap items-center justify-between gap-2\">\n <h2 className=\"text-base font-semibold\">{group}</h2>\n <div className=\"flex flex-wrap gap-1\">\n {tiers.map((tier) => (\n <Badge key={tier} variant=\"outline\" className=\"gap-1\" title={tierDescription(tier)}>\n {tierIcon(tier)}\n {tierLabel(tier)}\n </Badge>\n ))}\n </div>\n </div>\n {settings.length === 0 ? (\n <Card size=\"sm\">\n <CardContent className=\"text-sm text-muted-foreground\">No settings in this group.</CardContent>\n </Card>\n ) : (\n <div className=\"space-y-3\">\n {settings.map((setting) => (\n <SettingCard key={settingId(setting)} setting={setting} onSaved={onSaved} />\n ))}\n </div>\n )}\n </section>\n )\n}\n\nfunction SettingCard({ setting, onSaved }: { setting: SettingEntry; onSaved: (setting: SettingEntry) => void }) {\n const [draft, setDraft] = useState<unknown>(() => setting.value ?? setting.defaults ?? defaultValueForSchema(setting.schema))\n const [saving, setSaving] = useState(false)\n const [status, setStatus] = useState('')\n const [errors, setErrors] = useState<string[]>([])\n const isWritable = setting.writable && setting.tier === 'server-runtime'\n\n function update(path: Path, value: unknown) {\n setDraft((current: unknown) => setValueAtPath(current, path, value))\n setErrors([])\n setStatus('')\n }\n\n async function save() {\n if (!isWritable) return\n setSaving(true)\n setErrors([])\n setStatus('')\n try {\n const saved = await api<SettingEntry>('PUT', settingPath(setting), { value: draft, updatedBy: 'dashboard' })\n setDraft(saved.value)\n onSaved(saved)\n setStatus('Saved')\n } catch (e) {\n const details = errorDetails(e)\n setErrors(details.length ? details : [(e as Error).message])\n } finally {\n setSaving(false)\n }\n }\n\n return (\n <Card size=\"sm\">\n <CardHeader>\n <CardTitle className=\"flex flex-wrap items-center gap-2 text-sm\">\n {setting.display.label}\n <Badge variant=\"outline\" className=\"gap-1\" title={tierDescription(setting.tier)}>{tierIcon(setting.tier)}{tierLabel(setting.tier)}</Badge>\n {!setting.writable && <Badge variant=\"secondary\">Read only</Badge>}\n </CardTitle>\n {setting.display.description && <CardDescription>{setting.display.description}</CardDescription>}\n <CardAction>\n <Button size=\"sm\" onClick={save} disabled={!isWritable || saving}>\n <Save className=\"size-4\" />\n {saving ? 'Saving' : 'Save'}\n </Button>\n </CardAction>\n </CardHeader>\n\n <CardContent className=\"space-y-3\">\n <SchemaField\n schema={setting.schema}\n value={draft}\n path={[]}\n label={setting.display.label}\n required\n disabled={!isWritable || saving}\n onChange={update}\n />\n\n <p className=\"flex flex-wrap items-center gap-x-2 text-[11px] text-muted-foreground\">\n <code className=\"rounded bg-muted px-1.5 py-0.5 font-mono\">{setting.namespace}/{setting.key}</code>\n <span>read <span className=\"text-foreground/70\">{setting.scope.read}</span></span>\n <span aria-hidden>·</span>\n <span>write <span className=\"text-foreground/70\">{setting.scope.write}</span></span>\n </p>\n\n {errors.length > 0 && (\n <div className=\"rounded-md border border-destructive/40 bg-destructive/10 p-3 text-sm text-destructive\">\n <div className=\"mb-1 flex items-center gap-2 font-medium\"><AlertCircle className=\"size-4\" />Save failed</div>\n <ul className=\"list-disc space-y-1 pl-5\">\n {errors.map((detail) => <li key={detail}>{detail}</li>)}\n </ul>\n </div>\n )}\n {status && <p className=\"flex items-center gap-1 text-sm text-emerald-500\"><CheckCircle2 className=\"size-4\" />{status}</p>}\n </CardContent>\n </Card>\n )\n}\n\nfunction SchemaField(props: {\n schema: JSONSchema\n value: unknown\n path: Path\n label: string\n required: boolean\n disabled: boolean\n onChange: (path: Path, value: unknown) => void\n}) {\n const { schema, value, path, label, required, disabled, onChange } = props\n const type = schemaType(schema)\n\n if (schema.enum?.length) {\n const current = value === undefined || value === null || value === '' ? UNSET : String(value)\n return (\n <Field label={label} description={schema.description}>\n <Select value={current} onValueChange={(next) => onChange(path, next === UNSET ? undefined : next)} disabled={disabled}>\n <SelectTrigger><SelectValue /></SelectTrigger>\n <SelectContent>\n {!required && <SelectItem value={UNSET}>Not set</SelectItem>}\n {schema.enum.map((item) => <SelectItem key={String(item)} value={String(item)}>{String(item)}</SelectItem>)}\n </SelectContent>\n </Select>\n </Field>\n )\n }\n\n if (type === 'boolean') {\n return (\n <div className=\"flex items-center justify-between gap-3 rounded-md border bg-muted/20 p-3\">\n <div>\n <div className=\"text-sm font-medium\">{label}</div>\n {schema.description && <div className=\"text-xs text-muted-foreground\">{schema.description}</div>}\n </div>\n <Switch checked={Boolean(value)} onCheckedChange={(next) => onChange(path, next)} disabled={disabled} />\n </div>\n )\n }\n\n if (type === 'integer' || type === 'number') {\n return (\n <Field label={label} description={schema.description}>\n <Input\n type=\"number\"\n min={typeof schema.minimum === 'number' ? schema.minimum : undefined}\n max={typeof schema.maximum === 'number' ? schema.maximum : undefined}\n step={type === 'integer' ? 1 : 'any'}\n value={typeof value === 'number' ? value : ''}\n disabled={disabled}\n onChange={(e) => onChange(path, e.target.value === '' && !required ? undefined : Number(e.target.value))}\n />\n </Field>\n )\n }\n\n if (type === 'array') {\n return (\n <Field label={label} description={schema.description ?? 'One item per line.'}>\n <Textarea\n rows={Math.min(8, Math.max(3, Array.isArray(value) ? value.length + 1 : 3))}\n value={arrayText(value)}\n disabled={disabled}\n onChange={(e) => onChange(path, lines(e.target.value))}\n />\n </Field>\n )\n }\n\n if (type === 'object') {\n const properties = schema.properties ?? {}\n const requiredKeys = new Set(schema.required ?? [])\n if (Object.keys(properties).length === 0 && schema.additionalProperties) {\n return (\n <Field label={label} description={schema.description ?? 'KEY=value, one entry per line.'}>\n <Textarea rows={5} value={recordText(value)} disabled={disabled} onChange={(e) => onChange(path, parseRecordText(e.target.value))} />\n </Field>\n )\n }\n return (\n <div className=\"space-y-3\">\n {path.length > 0 && (\n <div>\n <div className=\"text-sm font-medium\">{label}</div>\n {schema.description && <div className=\"text-xs text-muted-foreground\">{schema.description}</div>}\n </div>\n )}\n <div className=\"grid gap-3 md:grid-cols-2\">\n {Object.entries(properties).map(([key, child]) => {\n const childValue = isRecord(value) ? value[key] : undefined\n return (\n <SchemaField\n key={key}\n schema={child}\n value={childValue === undefined && requiredKeys.has(key) ? defaultValueForSchema(child) : childValue}\n path={[...path, key]}\n label={child.title || labelForKey(key)}\n required={requiredKeys.has(key)}\n disabled={disabled}\n onChange={onChange}\n />\n )\n })}\n </div>\n </div>\n )\n }\n\n return (\n <Field label={label} description={schema.description}>\n <Input\n value={typeof value === 'string' ? value : value == null ? '' : String(value)}\n disabled={disabled}\n onChange={(e) => onChange(path, e.target.value === '' && !required ? undefined : e.target.value)}\n />\n </Field>\n )\n}\n\nexport function Field({ label, description, children }: { label: string; description?: string; children: ReactNode }) {\n return (\n <label className=\"block space-y-1.5 text-sm\">\n <span className=\"text-muted-foreground\">{label}</span>\n {children}\n {description && <span className=\"block text-xs text-muted-foreground\">{description}</span>}\n </label>\n )\n}\n\nfunction labelForKey(key: string): string {\n return key.replace(/([a-z0-9])([A-Z])/g, '$1 $2').replace(/[-_]+/g, ' ').replace(/^\\w/, (char) => char.toUpperCase())\n}\n","import { useEffect, useState } from 'react'\nimport { THEMES } from '@/lib/themes'\nimport { KOKORO_VOICES, availableSpeechVoices } from '@/lib/voice'\nimport { useRelayStore } from '@/store'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'\nimport { Switch } from '@/components/ui/switch'\nimport { Badge } from '@/components/ui/badge'\nimport { Card, CardAction, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'\nimport { Brain, MonitorCog, Volume2 } from 'lucide-react'\nimport type { ThemeId } from '@/types'\nimport { Field, UNSET } from './schema-form'\n\nexport function BrowserSettings() {\n const theme = useRelayStore((s) => s.theme)\n const showReasoning = useRelayStore((s) => s.showReasoning)\n const set = useRelayStore((s) => s.set)\n return (\n <section className=\"space-y-4\">\n <div>\n <h2 className=\"text-base font-semibold\">Browser preferences</h2>\n <p className=\"text-sm text-muted-foreground\">These are stored in local dashboard state, not in Relay server config.</p>\n </div>\n <Card size=\"sm\">\n <CardHeader>\n <CardTitle className=\"text-sm\">Dashboard display</CardTitle>\n <CardDescription className=\"text-xs\">Browser tier · persisted in this browser profile.</CardDescription>\n <CardAction>\n <Badge variant=\"outline\" className=\"gap-1\"><MonitorCog className=\"size-3.5\" />Browser</Badge>\n </CardAction>\n </CardHeader>\n <CardContent className=\"grid gap-3 md:grid-cols-2\">\n <Field label=\"Theme\">\n <Select value={theme} onValueChange={(value) => set({ theme: value as ThemeId })}>\n <SelectTrigger><SelectValue /></SelectTrigger>\n <SelectContent>\n {THEMES.map((item) => <SelectItem key={item.id} value={item.id}>{item.label}</SelectItem>)}\n </SelectContent>\n </Select>\n </Field>\n <div className=\"flex items-center justify-between gap-3 rounded-md border bg-muted/20 p-3\">\n <div className=\"flex items-center gap-2\">\n <Brain className=\"size-4\" />\n <div>\n <div className=\"text-sm font-medium\">Show reasoning details</div>\n <div className=\"text-xs text-muted-foreground\">Display captured reasoning/tool steps in chat. Server capture is controlled separately by provider reasoningCapture.</div>\n </div>\n </div>\n <Switch checked={showReasoning} onCheckedChange={(value) => set({ showReasoning: value })} />\n </div>\n </CardContent>\n </Card>\n <VoiceSettings />\n </section>\n )\n}\n\nfunction VoiceSettings() {\n const voiceTtsEnabled = useRelayStore((s) => s.voiceTtsEnabled)\n const setVoiceTtsEnabled = useRelayStore((s) => s.setVoiceTtsEnabled)\n const voiceTtsMode = useRelayStore((s) => s.voiceTtsMode)\n const setVoiceTtsMode = useRelayStore((s) => s.setVoiceTtsMode)\n const voiceTtsKokoroVoice = useRelayStore((s) => s.voiceTtsKokoroVoice)\n const setVoiceTtsKokoroVoice = useRelayStore((s) => s.setVoiceTtsKokoroVoice)\n const voiceTtsBrowserVoice = useRelayStore((s) => s.voiceTtsBrowserVoice)\n const setVoiceTtsBrowserVoice = useRelayStore((s) => s.setVoiceTtsBrowserVoice)\n const voiceInputMode = useRelayStore((s) => s.voiceInputMode)\n const setVoiceInputMode = useRelayStore((s) => s.setVoiceInputMode)\n\n // External sync: the browser loads speech voices asynchronously.\n const [browserVoices, setBrowserVoices] = useState(() => availableSpeechVoices())\n useEffect(() => {\n if (typeof window === 'undefined' || !('speechSynthesis' in window)) return\n const refresh = () => setBrowserVoices(availableSpeechVoices())\n refresh()\n window.speechSynthesis.addEventListener?.('voiceschanged', refresh)\n return () => window.speechSynthesis.removeEventListener?.('voiceschanged', refresh)\n }, [])\n\n const kokoroOptions = KOKORO_VOICES.some((voice) => voice.id === voiceTtsKokoroVoice)\n ? KOKORO_VOICES\n : [...KOKORO_VOICES, { id: voiceTtsKokoroVoice, label: voiceTtsKokoroVoice }]\n\n return (\n <Card size=\"sm\">\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2 text-sm\"><Volume2 className=\"size-4\" />Voice</CardTitle>\n <CardDescription className=\"text-xs\">Browser tier TTS and push-to-talk behavior.</CardDescription>\n <CardAction>\n <Switch checked={voiceTtsEnabled} onCheckedChange={setVoiceTtsEnabled} />\n </CardAction>\n </CardHeader>\n <CardContent className=\"grid gap-3 md:grid-cols-2\">\n <Field label=\"Speech engine\">\n <Select value={voiceTtsMode} onValueChange={(value) => setVoiceTtsMode(value as 'kokoro' | 'browser')}>\n <SelectTrigger><SelectValue /></SelectTrigger>\n <SelectContent>\n <SelectItem value=\"kokoro\">Kokoro (server, fallback to browser)</SelectItem>\n <SelectItem value=\"browser\">Browser Web Speech API</SelectItem>\n </SelectContent>\n </Select>\n </Field>\n <Field label=\"Kokoro voice\">\n <Select value={voiceTtsKokoroVoice} onValueChange={setVoiceTtsKokoroVoice}>\n <SelectTrigger><SelectValue /></SelectTrigger>\n <SelectContent>\n {kokoroOptions.map((voice) => <SelectItem key={voice.id} value={voice.id}>{voice.label}</SelectItem>)}\n </SelectContent>\n </Select>\n </Field>\n <Field label=\"Browser voice\">\n <Select value={voiceTtsBrowserVoice || UNSET} onValueChange={(value) => setVoiceTtsBrowserVoice(value === UNSET ? '' : value)}>\n <SelectTrigger><SelectValue /></SelectTrigger>\n <SelectContent>\n <SelectItem value={UNSET}>System default</SelectItem>\n {browserVoices.map((voice) => <SelectItem key={voice.uri} value={voice.uri}>{voice.label}</SelectItem>)}\n </SelectContent>\n </Select>\n </Field>\n <Field label=\"Push-to-talk input\">\n <Select value={voiceInputMode} onValueChange={(value) => setVoiceInputMode(value as 'compose' | 'autosend' | 'handsfree')}>\n <SelectTrigger><SelectValue /></SelectTrigger>\n <SelectContent>\n <SelectItem value=\"compose\">Fill message box</SelectItem>\n <SelectItem value=\"autosend\">Send immediately</SelectItem>\n </SelectContent>\n </Select>\n </Field>\n </CardContent>\n </Card>\n )\n}\n","import { useState } from 'react'\nimport type { SpawnProvider } from 'agent-relay-sdk/types'\nimport type { ProviderCatalogEntry, ProviderModelCatalogEntry } from 'agent-relay-sdk/provider-catalog'\nimport { api } from '@/lib/api'\nimport { Button } from '@/components/ui/button'\nimport { Input } from '@/components/ui/input'\nimport { Switch } from '@/components/ui/switch'\nimport { Badge } from '@/components/ui/badge'\nimport { Card, CardAction, CardContent, CardHeader, CardTitle } from '@/components/ui/card'\nimport { CheckCircle2, Eye, EyeOff, Pencil, Plus, ServerCog, SlidersHorizontal, Trash2 } from 'lucide-react'\nimport { errorDetails, Field } from './schema-form'\nimport { lines } from './schema-utils'\n\ninterface ProvidersResponse {\n catalog: ProviderCatalogEntry[]\n}\n\ninterface ModelForm {\n provider: SpawnProvider\n alias: string\n label: string\n providerModel: string\n efforts: string\n defaultEffort: string\n disabled: boolean\n}\n\nexport function ModelCatalogSettings({\n catalog,\n error,\n canWrite,\n onCatalog,\n}: {\n catalog: ProviderCatalogEntry[]\n error: string\n canWrite: boolean\n onCatalog: (catalog: ProviderCatalogEntry[]) => void\n}) {\n const firstProvider = catalog[0]?.provider ?? 'codex'\n const [provider, setProvider] = useState<SpawnProvider>(firstProvider)\n const [form, setForm] = useState<ModelForm>(() => emptyModelForm(firstProvider))\n const [status, setStatus] = useState('')\n const [errors, setErrors] = useState<string[]>([])\n\n const selectedProvider = catalog.some((entry) => entry.provider === provider) ? provider : firstProvider\n const selectedCatalog = catalog.find((entry) => entry.provider === selectedProvider) ?? catalog[0]\n const providers = catalog.map((entry) => entry.provider)\n\n function updateForm(patch: Partial<ModelForm>) {\n setForm((current) => ({ ...current, ...patch }))\n setErrors([])\n setStatus('')\n }\n\n function switchProvider(next: SpawnProvider) {\n setProvider(next)\n setForm(emptyModelForm(next))\n setErrors([])\n setStatus('')\n }\n\n async function reloadCatalog() {\n const res = await api<ProvidersResponse>('GET', '/providers')\n onCatalog(res.catalog)\n }\n\n async function saveModel() {\n if (!canWrite) return\n setErrors([])\n setStatus('')\n try {\n await api('PUT', `/providers/${encodeURIComponent(form.provider)}/models/${encodeURIComponent(form.alias)}`, {\n label: form.label,\n providerModel: form.providerModel,\n efforts: lines(form.efforts),\n defaultEffort: form.defaultEffort.trim() || undefined,\n disabled: form.disabled,\n updatedBy: 'dashboard',\n })\n await reloadCatalog()\n setStatus(`${form.alias} saved`)\n setForm(emptyModelForm(form.provider))\n } catch (e) {\n const details = errorDetails(e)\n setErrors(details.length ? details : [(e as Error).message])\n }\n }\n\n async function setDisabled(model: ProviderModelCatalogEntry, disabled: boolean) {\n if (!canWrite) return\n setErrors([])\n setStatus('')\n try {\n await api('PATCH', `/providers/${encodeURIComponent(selectedProvider)}/models/${encodeURIComponent(model.alias)}`, { disabled, updatedBy: 'dashboard' })\n await reloadCatalog()\n setStatus(`${model.alias} ${disabled ? 'disabled' : 'enabled'}`)\n } catch (e) {\n const details = errorDetails(e)\n setErrors(details.length ? details : [(e as Error).message])\n }\n }\n\n async function removeModel(model: ProviderModelCatalogEntry) {\n if (!canWrite) return\n setErrors([])\n setStatus('')\n try {\n await api('DELETE', `/providers/${encodeURIComponent(selectedProvider)}/models/${encodeURIComponent(model.alias)}`)\n await reloadCatalog()\n setStatus(`${model.alias} removed`)\n } catch (e) {\n const details = errorDetails(e)\n setErrors(details.length ? details : [(e as Error).message])\n }\n }\n\n function editModel(model: ProviderModelCatalogEntry) {\n setForm({\n provider: selectedProvider,\n alias: model.alias,\n label: model.label,\n providerModel: model.providerModel,\n efforts: model.efforts.join(', '),\n defaultEffort: model.defaultEffort ?? '',\n disabled: Boolean(model.disabled),\n })\n setErrors([])\n setStatus('')\n }\n\n if (error) {\n return (\n <Card size=\"sm\">\n <CardContent className=\"text-sm text-muted-foreground\">\n <div className=\"mb-1 flex items-center gap-2 font-medium text-foreground\"><SlidersHorizontal className=\"size-4\" />Model catalog</div>\n {error}\n </CardContent>\n </Card>\n )\n }\n\n return (\n <section className=\"space-y-4\">\n <div className=\"flex flex-wrap items-start justify-between gap-3\">\n <div>\n <h2 className=\"text-base font-semibold\">Model catalog</h2>\n <p className=\"text-sm text-muted-foreground\">Add override models, disable unavailable models, or remove custom entries from the provider catalog.</p>\n </div>\n {!canWrite && <Badge variant=\"secondary\">Read only: needs settings:write:provider</Badge>}\n </div>\n\n <div className=\"flex flex-wrap gap-2\">\n {providers.map((item) => (\n <Button key={item} variant={item === selectedProvider ? 'default' : 'outline'} size=\"sm\" onClick={() => switchProvider(item)}>\n {item}\n </Button>\n ))}\n </div>\n\n <Card size=\"sm\">\n <CardHeader>\n <CardTitle className=\"text-sm\">Add or edit model</CardTitle>\n <CardAction>\n <Badge variant=\"outline\" className=\"gap-1\"><ServerCog className=\"size-3.5\" />Server runtime</Badge>\n </CardAction>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n <div className=\"grid gap-3 md:grid-cols-2\">\n <Field label=\"Alias\">\n <Input value={form.alias} disabled={!canWrite} placeholder=\"nightly\" onChange={(e) => updateForm({ alias: e.target.value.trim() })} />\n </Field>\n <Field label=\"Label\">\n <Input value={form.label} disabled={!canWrite} placeholder=\"Nightly Codex\" onChange={(e) => updateForm({ label: e.target.value })} />\n </Field>\n <Field label=\"Provider model\">\n <Input value={form.providerModel} disabled={!canWrite} placeholder=\"codex-nightly\" onChange={(e) => updateForm({ providerModel: e.target.value })} />\n </Field>\n <Field label=\"Efforts\">\n <Input value={form.efforts} disabled={!canWrite} placeholder=\"low, medium, high\" onChange={(e) => updateForm({ efforts: e.target.value })} />\n </Field>\n <Field label=\"Default effort\">\n <Input value={form.defaultEffort} disabled={!canWrite} placeholder=\"medium\" onChange={(e) => updateForm({ defaultEffort: e.target.value })} />\n </Field>\n <div className=\"flex items-center justify-between gap-3 rounded-md border bg-muted/20 p-3\">\n <div>\n <div className=\"text-sm font-medium\">Disabled</div>\n <div className=\"text-xs text-muted-foreground\">Keep visible but unavailable for new launches.</div>\n </div>\n <Switch checked={form.disabled} disabled={!canWrite} onCheckedChange={(disabled) => updateForm({ disabled })} />\n </div>\n </div>\n <Button onClick={saveModel} disabled={!canWrite || !form.alias || !form.label || !form.providerModel}>\n <Plus className=\"size-4\" />\n Save model\n </Button>\n </CardContent>\n </Card>\n\n <div className=\"space-y-2\">\n {selectedCatalog && selectedCatalog.models.length === 0 && (\n <Card size=\"sm\">\n <CardContent className=\"text-sm text-muted-foreground\">No models in this provider catalog yet.</CardContent>\n </Card>\n )}\n {selectedCatalog?.models.map((model) => (\n <Card key={model.alias} size=\"sm\">\n <CardContent className=\"flex flex-wrap items-center justify-between gap-3\">\n <div className=\"min-w-0\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"font-medium\">{model.label}</span>\n <code className=\"rounded bg-muted px-1.5 py-0.5 font-mono text-xs\">{model.alias}</code>\n {model.disabled && <Badge variant=\"secondary\">Disabled</Badge>}\n </div>\n <p className=\"mt-1 text-xs text-muted-foreground\">\n {model.providerModel}\n {model.efforts.length > 0 ? ` · efforts ${model.efforts.join(', ')}` : ' · no effort levels'}\n {model.defaultEffort ? ` · default ${model.defaultEffort}` : ''}\n </p>\n </div>\n <div className=\"flex flex-wrap gap-2\">\n <Button variant=\"outline\" size=\"sm\" onClick={() => editModel(model)}>\n <Pencil className=\"size-4\" />\n Edit\n </Button>\n <Button variant=\"outline\" size=\"sm\" disabled={!canWrite} onClick={() => void setDisabled(model, !model.disabled)}>\n {model.disabled ? <Eye className=\"size-4\" /> : <EyeOff className=\"size-4\" />}\n {model.disabled ? 'Enable' : 'Disable'}\n </Button>\n <Button variant=\"outline\" size=\"sm\" disabled={!canWrite} onClick={() => void removeModel(model)}>\n <Trash2 className=\"size-4\" />\n Remove\n </Button>\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n\n {errors.length > 0 && (\n <div className=\"rounded-md border border-destructive/40 bg-destructive/10 p-3 text-sm text-destructive\">\n <ul className=\"list-disc space-y-1 pl-5\">\n {errors.map((detail) => <li key={detail}>{detail}</li>)}\n </ul>\n </div>\n )}\n {status && <p className=\"flex items-center gap-1 text-sm text-emerald-500\"><CheckCircle2 className=\"size-4\" />{status}</p>}\n </section>\n )\n}\n\nfunction emptyModelForm(provider: SpawnProvider): ModelForm {\n return { provider, alias: '', label: '', providerModel: '', efforts: '', defaultEffort: '', disabled: false }\n}\n","import { useEffect, useMemo, useState } from 'react'\nimport type { ProviderCatalogEntry } from 'agent-relay-sdk/provider-catalog'\nimport { api } from '@/lib/api'\nimport { cn } from '@/lib/utils'\nimport { Button } from '@/components/ui/button'\nimport { Badge } from '@/components/ui/badge'\nimport { Card, CardContent } from '@/components/ui/card'\nimport { AlertCircle, Globe2, RefreshCw } from 'lucide-react'\nimport { BrowserSettings } from '@/components/settings/browser-settings'\nimport { ModelCatalogSettings } from '@/components/settings/model-catalog-settings'\nimport { SchemaGroup } from '@/components/settings/schema-form'\nimport {\n groupSettings,\n hasScope,\n settingId,\n type SettingEntry,\n} from '@/components/settings/schema-utils'\n\ninterface SettingsResponse {\n settings: SettingEntry[]\n}\n\ninterface TokenMe {\n actor: string\n kind: string\n role?: string\n scopes: string[]\n}\n\ninterface ProvidersResponse {\n catalog: ProviderCatalogEntry[]\n}\n\nconst BROWSER_GROUP_SLUG = 'browser'\nconst MODELS_GROUP_SLUG = 'models'\n\nfunction settingsHash(): string {\n if (typeof window === 'undefined') return ''\n const hash = window.location.hash.replace(/^#/, '')\n if (!hash.startsWith('settings/')) return ''\n return decodeURIComponent(hash.slice('settings/'.length))\n}\n\nfunction writeSettingsHash(slug: string): void {\n if (typeof window === 'undefined') return\n const url = new URL(window.location.href)\n url.hash = `settings/${encodeURIComponent(slug)}`\n window.history.pushState({}, '', url)\n}\n\nexport function SettingsView() {\n const [settings, setSettings] = useState<SettingEntry[]>([])\n const [token, setToken] = useState<TokenMe | null>(null)\n const [catalog, setCatalog] = useState<ProviderCatalogEntry[]>([])\n const [active, setActive] = useState(() => settingsHash())\n const [loading, setLoading] = useState(true)\n const [loadError, setLoadError] = useState('')\n const [catalogError, setCatalogError] = useState('')\n\n async function reload() {\n setLoading(true)\n setLoadError('')\n setCatalogError('')\n try {\n const [settingsRes, tokenRes, providersRes] = await Promise.all([\n api<SettingsResponse>('GET', '/settings'),\n api<TokenMe>('GET', '/tokens/me'),\n api<ProvidersResponse>('GET', '/providers').catch((e) => {\n setCatalogError((e as Error).message)\n return { catalog: [] }\n }),\n ])\n setSettings(settingsRes.settings)\n setToken(tokenRes)\n setCatalog(providersRes.catalog)\n } catch (e) {\n setLoadError((e as Error).message)\n } finally {\n setLoading(false)\n }\n }\n\n useEffect(() => {\n void reload()\n }, [])\n\n // External sync: keep the selected settings group aligned with browser history.\n useEffect(() => {\n const sync = () => setActive(settingsHash())\n window.addEventListener('hashchange', sync)\n window.addEventListener('popstate', sync)\n return () => {\n window.removeEventListener('hashchange', sync)\n window.removeEventListener('popstate', sync)\n }\n }, [])\n\n const descriptorGroups = useMemo(() => groupSettings(settings), [settings])\n const groups = useMemo(() => [\n ...descriptorGroups.map((group) => ({\n slug: group.slug,\n label: group.group,\n description: `${group.settings.length} schema setting${group.settings.length === 1 ? '' : 's'}`,\n kind: 'descriptors' as const,\n settings: group.settings,\n })),\n {\n slug: BROWSER_GROUP_SLUG,\n label: 'Browser',\n description: 'Local dashboard preferences',\n kind: 'browser' as const,\n settings: [],\n },\n {\n slug: MODELS_GROUP_SLUG,\n label: 'Models',\n description: 'Provider model catalog',\n kind: 'models' as const,\n settings: [],\n },\n ], [descriptorGroups])\n\n const activeGroup = groups.find((group) => group.slug === active) ?? groups[0]\n\n function selectGroup(slug: string) {\n setActive(slug)\n writeSettingsHash(slug)\n }\n\n function replaceSetting(updated: SettingEntry) {\n setSettings((current) => current.map((entry) => settingId(entry) === settingId(updated) ? updated : entry))\n }\n\n return (\n <div className=\"space-y-4\">\n <div className=\"flex flex-wrap items-start justify-between gap-3\">\n <div>\n <h1 className=\"text-lg font-semibold\">Settings</h1>\n <p className=\"text-sm text-muted-foreground\">Schema-driven Relay settings, browser preferences, and model catalog controls.</p>\n </div>\n <div className=\"flex flex-wrap items-center gap-2\">\n {token && (\n <Badge variant=\"outline\" className=\"gap-1\">\n <Globe2 className=\"size-3\" />\n {token.kind}:{token.actor}\n </Badge>\n )}\n <Button variant=\"outline\" size=\"sm\" onClick={() => void reload()} disabled={loading}>\n <RefreshCw className={cn('size-4', loading && 'animate-spin')} />\n Refresh\n </Button>\n </div>\n </div>\n\n {loadError && (\n <div className=\"flex items-start gap-2 rounded-lg border border-destructive/40 bg-destructive/10 p-3 text-sm text-destructive\">\n <AlertCircle className=\"mt-0.5 size-4\" />\n <span>{loadError}</span>\n </div>\n )}\n\n <div className=\"grid gap-4 lg:grid-cols-[230px_minmax(0,1fr)]\">\n <nav className=\"space-y-1 lg:sticky lg:top-4 lg:self-start\">\n {groups.map((group) => (\n <button\n key={group.slug}\n type=\"button\"\n className={cn(\n 'w-full rounded-md border px-3 py-2 text-left text-sm transition-colors',\n activeGroup?.slug === group.slug ? 'border-primary/50 bg-primary/10 text-foreground' : 'border-transparent hover:border-border hover:bg-accent',\n )}\n onClick={() => selectGroup(group.slug)}\n >\n <span className=\"block font-medium\">{group.label}</span>\n <span className=\"block truncate text-xs text-muted-foreground\">{group.description}</span>\n </button>\n ))}\n </nav>\n\n <div className=\"min-w-0 space-y-4\">\n {loading && !settings.length ? (\n <Card size=\"sm\">\n <CardContent className=\"text-sm text-muted-foreground\">Loading settings…</CardContent>\n </Card>\n ) : activeGroup?.kind === 'descriptors' ? (\n <SchemaGroup\n group={activeGroup.label}\n settings={activeGroup.settings}\n onSaved={replaceSetting}\n />\n ) : activeGroup?.kind === 'browser' ? (\n <BrowserSettings />\n ) : (\n <ModelCatalogSettings\n catalog={catalog}\n error={catalogError}\n canWrite={hasScope(token?.scopes, 'settings:write:provider')}\n onCatalog={setCatalog}\n />\n )}\n </div>\n </div>\n </div>\n )\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import{r as e}from"./chunk-CilyBKbf.js";import{Bn as t,Jn as n,Kn as r,Rn as i,Vn as a,Wn as o,Yn as s,qn as c}from"./lucide-react-DWYjU-AF.js";import{B as l,C as u,D as d,I as f,O as p,Q as m,W as h,Y as g,Z as ee,_,at as v,b as y,d as te,it as b,j as x,nt as S,ot as C,p as w,rt as T,st as E,tt as D,w as ne}from"./display-DzNvOu1j.js";var O=e(s(),1),re=e=>{let t,n=new Set,r=(e,r)=>{let i=typeof e==`function`?e(t):e;if(!Object.is(i,t)){let e=t;t=r??(typeof i!=`object`||!i)?i:Object.assign({},t,i),n.forEach(n=>n(t,e))}},i=()=>t,a={setState:r,getState:i,getInitialState:()=>o,subscribe:e=>(n.add(e),()=>n.delete(e))},o=t=e(r,i,a);return a},ie=(e=>e?re(e):re),ae=e=>e;function oe(e,t=ae){let n=O.useSyncExternalStore(e.subscribe,O.useCallback(()=>t(e.getState()),[e,t]),O.useCallback(()=>t(e.getInitialState()),[e,t]));return O.useDebugValue(n),n}var se=e=>{let t=ie(e),n=e=>oe(t,e);return Object.assign(n,t),n},ce=(e=>e?se(e):se);function le(e,t){let n;try{n=e()}catch{return}return{getItem:e=>{let r=e=>e===null?null:JSON.parse(e,t?.reviver),i=n.getItem(e)??null;return i instanceof Promise?i.then(r):r(i)},setItem:(e,r)=>n.setItem(e,JSON.stringify(r,t?.replacer)),removeItem:e=>n.removeItem(e)}}var k=e=>t=>{try{let n=e(t);return n instanceof Promise?n:{then(e){return k(e)(n)},catch(e){return this}}}catch(e){return{then(e){return this},catch(t){return k(t)(e)}}}},ue=(e,t)=>(n,r,i)=>{let a={storage:le(()=>window.localStorage),partialize:e=>e,version:0,merge:(e,t)=>({...t,...e}),...t},o=!1,s=0,c=new Set,l=new Set,u=a.storage;if(!u)return e((...e)=>{console.warn(`[zustand persist middleware] Unable to update item '${a.name}', the given storage is currently unavailable.`),n(...e)},r,i);let d=()=>{let e=a.partialize({...r()});return u.setItem(a.name,{state:e,version:a.version})},f=i.setState;i.setState=(e,t)=>(f(e,t),d());let p=e((...e)=>(n(...e),d()),r,i);i.getInitialState=()=>p;let m,h=()=>{if(!u)return;let e=++s;o=!1,c.forEach(e=>e(r()??p));let t=a.onRehydrateStorage?.call(a,r()??p)||void 0;return k(u.getItem.bind(u))(a.name).then(e=>{if(e)if(typeof e.version==`number`&&e.version!==a.version){if(a.migrate){let t=a.migrate(e.state,e.version);return t instanceof Promise?t.then(e=>[!0,e]):[!0,t]}console.error(`State loaded from storage couldn't be migrated since no migrate function was provided`)}else return[!1,e.state];return[!1,void 0]}).then(t=>{if(e!==s)return;let[i,o]=t;if(m=a.merge(o,r()??p),n(m,!0),i)return d()}).then(()=>{e===s&&(t?.(r(),void 0),m=r(),o=!0,l.forEach(e=>e(m)))}).catch(n=>{e===s&&t?.(void 0,n)})};return i.persist={setOptions:e=>{a={...a,...e},e.storage&&(u=e.storage)},clearStorage:()=>{u?.removeItem(a.name)},getOptions:()=>a,rehydrate:()=>h(),hasHydrated:()=>o,onHydrate:e=>(c.add(e),()=>{c.delete(e)}),onFinishHydration:e=>(l.add(e),()=>{l.delete(e)})},a.skipHydration||h(),m||p};function de(e){if(!e)return``;let t=e.replace(/\r\n/g,`
|
|
2
|
+
`);return t=t.replace(/```[^\n]*\n([\s\S]*?)```/g,(e,t)=>{let n=t.replace(/\n+$/,``).split(`
|
|
3
|
+
`).length;return` code block, ${n} ${n===1?`line`:`lines`}. `}),t=t.replace(/```[^\n]*/g,` code block. `),t=he(t),t=t.replace(/^#{1,6}\s+/gm,``),t=t.replace(/^\s*[-*+]\s+/gm,`. `),t=t.replace(/^\s*\d+\.\s+/gm,`. `),t=t.replace(/`([^`]+)`/g,`$1`),t=t.replace(/\[([^\]]+)\]\([^)]+\)/g,`$1`),t=t.replace(/(\*\*|__|\*|_)(.*?)\1/g,`$2`),t=t.replace(/[ \t]+/g,` `),t=t.replace(/\n{2,}/g,`. `),t=t.replace(/\s*\.\s*\.\s*(\.\s*)+/g,`. `),t.trim()}function fe(e){return/\|/.test(e)&&e.trim().length>0}function pe(e){return/^\s*\|?\s*:?-{2,}:?\s*(\|\s*:?-{2,}:?\s*)+\|?\s*$/.test(e)}function me(e){return e.trim().replace(/^\||\|$/g,``).split(`|`).map(e=>e.trim()).filter(e=>e.length>0)}function he(e){let t=e.split(`
|
|
4
|
+
`),n=[],r=0;for(;r<t.length;){if(fe(t[r])&&r+1<t.length&&pe(t[r+1])){let e=me(t[r]),i=r+2,a=0;for(;i<t.length&&fe(t[i])&&!pe(t[i]);)a++,i++;let o=e.length?`with columns ${e.join(`, `)}`:``,s=`${a} ${a===1?`row`:`rows`}`;n.push(`table ${o?`${o}, `:``}${s}.`.replace(/\s+/g,` `).trim()),r=i;continue}n.push(t[r]),r++}return n.join(`
|
|
5
|
+
`)}var A={ms:`milliseconds`,s:`seconds`,kb:`kilobytes`,mb:`megabytes`,gb:`gigabytes`,tb:`terabytes`};function ge(e){return e.split(``).join(` `)}function _e(e){return e.split(``).map(e=>/[0-9]/.test(e)?e:e.toUpperCase()).join(` `)}var ve=[{name:`url`,pattern:/\bhttps?:\/\/\S+/gi,replace:` link `},{name:`path`,pattern:/(?:\/[A-Za-z0-9._-]+){2,}\/?/g,replace:e=>` `+e.replace(/[/._-]+/g,` `).trim()+` `},{name:`slash`,pattern:/(?<=[A-Za-z0-9])\/(?=[A-Za-z0-9])/g,replace:` `},{name:`func-call`,pattern:/\b([A-Za-z_$][\w$]*)\(\)/g,replace:`$1`},{name:`approx`,pattern:/~(?=\s*[\d.])/g,replace:`approximately `},{name:`range`,pattern:/(\d)\s*[-–—]\s*(?=\d)/g,replace:`$1 to `},{name:`version`,pattern:/\b(v?)(\d+(?:\.\d+){2,})\b/gi,replace:(e,t,n)=>`${t?`version `:``}${n.replace(/\./g,` dot `)}`},{name:`decimal`,pattern:/\b(\d+)\.(\d+)\b/g,replace:(e,t,n)=>`${t} point ${ge(n)}`},{name:`hash`,pattern:/\b(?=[0-9a-f]{7,40}\b)(?=[0-9a-f]*[a-f])(?=[0-9a-f]*\d)[0-9a-f]{7,40}\b/gi,replace:e=>_e(e)},{name:`id-camel`,pattern:/([a-z])(Id|ID)(s)?\b/g,replace:(e,t,n,r)=>`${t} I D${r?`s`:``}`},{name:`id-word`,pattern:/\b(?:id|Id|ID)(s)?\b/g,replace:(e,t)=>`I D${t?`s`:``}`},{name:`byte-unit`,pattern:/\b(\d+)\s?(kb|mb|gb|tb)\b/gi,replace:(e,t,n)=>`${t} ${A[n.toLowerCase()]}`},{name:`ms-unit`,pattern:/\b(\d{1,5})\s?ms\b/g,replace:(e,t)=>`${t} ${A.ms}`},{name:`s-unit`,pattern:/\b(\d{1,3})\s?s\b/g,replace:(e,t)=>`${t} ${A.s}`},{name:`live-adjective`,pattern:/\b(is|are|was|were|be|been|being|now|and|stays?|staying|went|go|goes|going|deployed|it's|that's|here's|there's|we're|you're|they're)\s+live\b/gi,replace:(e,t)=>`${t} lyve`},{name:`interior-dot`,pattern:/\.(?=[A-Za-z0-9])/g,replace:` dot `}];function ye(e){if(!e)return``;let t=e;for(let e of ve)t=t.replace(e.pattern,e.replace);return t.replace(/[ \t]{2,}/g,` `).trim()}function be(e){return ye(de(e))}var xe=[{id:`am_michael`,label:`Michael (US ♂)`},{id:`am_adam`,label:`Adam (US ♂)`},{id:`af_heart`,label:`Heart (US ♀)`},{id:`af_bella`,label:`Bella (US ♀)`},{id:`af_nicole`,label:`Nicole (US ♀)`},{id:`af_sarah`,label:`Sarah (US ♀)`},{id:`bm_george`,label:`George (UK ♂)`},{id:`bf_emma`,label:`Emma (UK ♀)`}],j=220;function Se(e){let t=e.match(/[^.!?]+[.!?]*\s*/g)?.map(e=>e.trim()).filter(Boolean)??[e],n=[];for(let e of t){if(e.length<=j){n.push(e);continue}let t=e;for(;t.length>j;){let e=t.lastIndexOf(` `,j);e<=0&&(e=j),n.push(t.slice(0,e).trim()),t=t.slice(e).trim()}t&&n.push(t)}return n}var M=typeof window<`u`&&`speechSynthesis`in window,N=new class{enabled=!1;lang=`en-US`;mode=`kokoro`;kokoroVoice=`am_michael`;browserVoice=``;active=null;queue=[];currentChat=null;speaking=!1;gen=0;audioEl=null;audioUrl=null;playingKey=null;manual=!1;listeners=new Set;get available(){return M||typeof Audio<`u`}isEnabled(){return this.enabled}subscribe(e){return this.listeners.add(e),()=>{this.listeners.delete(e)}}getPlayingKey(){return this.playingKey}setPlayingKey(e){if(e!==this.playingKey){this.playingKey=e;for(let e of this.listeners)e()}}setEnabled(e){e!==this.enabled&&(this.enabled=e,e||this.reset())}setLang(e){this.lang=e}setMode(e){e!==this.mode&&(this.mode=e,this.reset())}setKokoroVoice(e){this.kokoroVoice=e}setBrowserVoice(e){this.browserVoice=e}setActiveChat(e){e!==this.active&&(this.active=e,this.queue=this.queue.filter(t=>t.chatId===e))}onResponse(e,t){if(!this.enabled||!this.available||!e||e!==this.active)return;let n=be(t);n&&(this.speaking&&(this.manual||this.currentChat&&this.currentChat!==e)&&(this.queue=[],this.cancel()),this.queue.push({chatId:e,text:n}),this.pump())}speak(e,t){if(!this.available)return;let n=be(e);if(!n)return;this.reset(),this.manual=!0,this.speaking=!0,this.currentChat=null,this.setPlayingKey(t??null);let r=++this.gen,i=Se(n),a=()=>{r===this.gen&&(this.speaking=!1,this.manual=!1,this.setPlayingKey(null))};this.mode===`kokoro`?this.speakKokoro(i,0,r,a):this.speakBrowser(i,0,r,a)}bargeIn(){this.reset()}reset(){this.queue=[],this.cancel()}cancel(){this.gen++,this.currentChat=null,this.speaking=!1,this.manual=!1,this.setPlayingKey(null);try{window.speechSynthesis.cancel()}catch{}this.stopAudio()}stopAudio(){if(this.audioEl)try{this.audioEl.pause(),this.audioEl.src=``}catch{}if(this.audioUrl){try{URL.revokeObjectURL(this.audioUrl)}catch{}this.audioUrl=null}}pump(){if(this.speaking)return;let e=this.queue.shift();if(!e)return;this.speaking=!0,this.manual=!1,this.currentChat=e.chatId;let t=++this.gen,n=Se(e.text),r=()=>{t===this.gen&&(this.speaking=!1,this.currentChat=null,this.pump())};this.mode===`kokoro`?this.speakKokoro(n,0,t,r):this.speakBrowser(n,0,t,r)}speakBrowser(e,t,n,r){if(n!==this.gen)return;if(!M||t>=e.length)return r();let i=new SpeechSynthesisUtterance(e[t]),a=this.browserVoice?window.speechSynthesis.getVoices().find(e=>e.voiceURI===this.browserVoice):void 0;a?(i.voice=a,i.lang=a.lang):i.lang=this.lang||navigator.language||`en-US`,i.onend=()=>this.speakBrowser(e,t+1,n,r),i.onerror=()=>this.speakBrowser(e,t+1,n,r),window.speechSynthesis.speak(i)}speakKokoro(e,t,n,r,i){if(n!==this.gen)return;let a=e[t];if(a===void 0)return r();let o=i??this.fetchSpeech(a),s=e[t+1],c=s===void 0?void 0:this.fetchSpeech(s);o.then(i=>{n===this.gen&&this.playBlob(i,n,()=>this.speakKokoro(e,t+1,n,r,c),()=>{this.speakBrowser(e,t,n,r)})}).catch(()=>{n===this.gen&&this.speakBrowser(e,t,n,r)})}fetchSpeech(e){return a(`/connectors/voice/call/speak`,{text:e,voice:this.kokoroVoice})}playBlob(e,t,n,r){if(t!==this.gen)return;if(typeof Audio>`u`)return r();this.stopAudio(),this.audioEl||=new Audio;let i=URL.createObjectURL(e);this.audioUrl=i;let a=this.audioEl;a.src=i,a.onended=()=>{t===this.gen&&n()},a.onerror=()=>{t===this.gen&&r()},a.play().catch(()=>{t===this.gen&&r()})}};function Ce(){if(!M)return[];try{return window.speechSynthesis.getVoices().map(e=>({uri:e.voiceURI,label:`${e.name} (${e.lang})`,lang:e.lang})).sort((e,t)=>e.lang.localeCompare(t.lang)||e.label.localeCompare(t.label))}catch{return[]}}var we=typeof navigator<`u`&&!!navigator.mediaDevices?.getUserMedia&&typeof window<`u`&&`MediaRecorder`in window;function Te(){for(let e of[`audio/webm;codecs=opus`,`audio/webm`,`audio/ogg;codecs=opus`,`audio/mp4`])if(typeof MediaRecorder<`u`&&MediaRecorder.isTypeSupported?.(e))return e}var Ee=class{rec=null;chunks=[];stream=null;async start(){this.stream=await navigator.mediaDevices.getUserMedia({audio:!0}),this.chunks=[];let e=Te();this.rec=new MediaRecorder(this.stream,e?{mimeType:e}:void 0),this.rec.ondataavailable=e=>{e.data.size&&this.chunks.push(e.data)},this.rec.start()}async stop(){let e=this.rec;if(!e)return this.teardown(),null;let t=new Promise(t=>{e.onstop=()=>t()});try{e.stop()}catch{}await t;let n=e.mimeType||`audio/webm`,r=new Blob(this.chunks,{type:n});return this.teardown(),r.size?r:null}cancel(){try{this.rec?.stop()}catch{}this.teardown()}teardown(){this.stream?.getTracks().forEach(e=>e.stop()),this.rec=null,this.stream=null,this.chunks=[]}};async function De(e){return((await t(`/connectors/voice/call/transcribe`,e))?.text??``).trim()}var P=ce((e,t)=>({now:Date.now(),_timer:null,start(){t()._timer||e({_timer:setInterval(()=>e({now:Date.now()}),1e3)})},stop(){let n=t()._timer;n&&(clearInterval(n),e({_timer:null}))}}));function Oe(){return P(e=>e.now)}function ke(e=3e4){return P(t=>Math.floor(t.now/e))}var F=[`low`,`medium`,`high`,`max`],I=[`low`,`medium`,`high`,`xhigh`,`max`],L=[`low`,`medium`,`high`,`xhigh`],R={value:2e5,source:`catalog`,confidence:`declared`},z={value:1e6,source:`catalog`,confidence:`declared`},Ae={modalities:{input:{text:!0,image:!0},output:{text:!0}},tools:{code:!0,review:!0,debug:!0,refactor:!0},source:`catalog`,confidence:`declared`};function B(e){return{...e?{limits:e}:{},capabilities:Ae}}var V={claude:{provider:`claude`,label:`Claude Code`,defaultModel:`sonnet-4.6`,models:[{alias:`fable-5`,label:`Fable 5`,providerModel:`claude-fable-5`,efforts:I,defaultEffort:`medium`,...B({contextWindowTokens:z})},{alias:`opus-4.8`,label:`Opus 4.8`,providerModel:`claude-opus-4-8`,efforts:I,defaultEffort:`medium`,...B({contextWindowTokens:R})},{alias:`opus-4.8[1m]`,label:`Opus 4.8 1M`,providerModel:`claude-opus-4-8[1m]`,efforts:I,defaultEffort:`medium`,...B({contextWindowTokens:z})},{alias:`opus-4.7`,label:`Opus 4.7`,providerModel:`claude-opus-4-7`,efforts:I,defaultEffort:`medium`,...B({contextWindowTokens:R})},{alias:`opus-4.7[1m]`,label:`Opus 4.7 1M`,providerModel:`claude-opus-4-7[1m]`,efforts:I,defaultEffort:`medium`,...B({contextWindowTokens:z})},{alias:`opus-4.6`,label:`Opus 4.6`,providerModel:`claude-opus-4-6`,efforts:F,defaultEffort:`medium`,...B({contextWindowTokens:R})},{alias:`opus-4.6[1m]`,label:`Opus 4.6 1M`,providerModel:`claude-opus-4-6[1m]`,efforts:F,defaultEffort:`medium`,...B({contextWindowTokens:z})},{alias:`sonnet-4.6`,label:`Sonnet 4.6`,providerModel:`claude-sonnet-4-6`,efforts:F,defaultEffort:`medium`,...B({contextWindowTokens:R})},{alias:`sonnet-4.6[1m]`,label:`Sonnet 4.6 1M`,providerModel:`claude-sonnet-4-6[1m]`,efforts:F,defaultEffort:`medium`,...B({contextWindowTokens:z})},{alias:`haiku`,label:`Haiku`,providerModel:`haiku`,efforts:[],...B()}]},codex:{provider:`codex`,label:`Codex`,defaultModel:`gpt-5.5`,models:[{alias:`gpt-5.5`,label:`GPT-5.5`,providerModel:`gpt-5.5`,efforts:L,defaultEffort:`medium`,...B({contextWindowTokens:R})},{alias:`gpt-5.4`,label:`GPT-5.4`,providerModel:`gpt-5.4`,efforts:L,defaultEffort:`medium`,...B({contextWindowTokens:R})},{alias:`gpt-5.4-mini`,label:`GPT-5.4 Mini`,providerModel:`gpt-5.4-mini`,efforts:L,defaultEffort:`medium`,...B({contextWindowTokens:R})},{alias:`gpt-5.3-codex`,label:`GPT-5.3 Codex`,providerModel:`gpt-5.3-codex`,efforts:L,defaultEffort:`medium`,...B({contextWindowTokens:R})},{alias:`gpt-5.3-codex-spark`,label:`GPT-5.3 Codex Spark`,providerModel:`gpt-5.3-codex-spark`,efforts:L,defaultEffort:`high`,...B({contextWindowTokens:R})},{alias:`gpt-5.2`,label:`GPT-5.2`,providerModel:`gpt-5.2`,efforts:L,defaultEffort:`medium`,...B({contextWindowTokens:R})}]}};function H(e){return e?.providers[0]??`claude`}function U(e){return V[e]?.defaultModel??``}function je(e,t){return e.filter(e=>e.status===`online`&&f(t,e.baseDir)).sort((e,t)=>x(t.baseDir).length-x(e.baseDir).length)[0]}function Me(e,t){let n=e.find(e=>e.managedAgents.some(e=>e.agentId===t.id));if(n)return n;let r=typeof t.meta?.cwd==`string`?t.meta.cwd:``;return r?je(e,r):void 0}function Ne(e){let t={};for(let n of e)t[n.id]=n;return t}function W(e,t){let n=e.findIndex(e=>e.id===t.id),r=[...e];return n>=0?r[n]=t:r.push(t),r}var Pe=3e3;function G(e,t,n,r=Date.now(),i){if(!t||!n)return e;let a=[...e[t]||[]],o=i||`s-${n}-${r}`;return a.some(e=>e.id===o)||a.some(e=>e.status===n&&Math.abs(e.timestamp-r)<=Pe)?e:(a.push({id:o,status:n,timestamp:r}),a.length>200&&a.splice(0,a.length-200),{...e,[t]:a})}function Fe(e,t){if(!(!e||e.status===t.status)){if((e.status===`offline`||e.status===`stale`)&&(t.status===`online`||t.status===`idle`||t.status===`busy`))return`online`;if(t.status===`offline`)return`offline`}}var Ie=new Set([`compacting`,`compacted`,`clearing-context`,`context-cleared`]);function Le(e){let t=e.meta?.timelineEvent;if(!t||typeof t!=`object`||Array.isArray(t))return;let n=t.status;if(typeof n!=`string`||!n)return;let r=t.id,i=t.timestamp;return{status:n,...typeof r==`string`?{id:r}:{},...typeof i==`number`&&Number.isFinite(i)?{timestamp:i}:{}}}function Re(e){let t=e.params?.agentId;return typeof t==`string`&&t?t:typeof e.target==`string`&&e.target?e.target:void 0}function ze(e,t){if(t===`command.dispatched`)return e.type===`agent.compact`?`compaction-requested`:e.type===`agent.clearContext`?`clear-requested`:e.type===`agent.shutdown`?`shutting-down`:void 0;if(t===`command.succeeded`){if(e.type===`agent.shutdown`)return`shutdown`;if(e.type===`agent.restart`)return`restarted`}}function Be(e){return JSON.stringify(e)}function Ve(e,t){let n=new Map(e.map(e=>[e.id,e])),r=!(e.length===t.length&&e.every((e,n)=>e.id===t[n]?.id)),i=t.map(e=>{let t=n.get(e.id);return t&&Be(t)===Be(e)?t:(r=!0,e)});return r?i:e}function K(e,t){let n=[...new Map(t.map(e=>[e.id,e])).values()],r=new Map(e.map(e=>[e.id,e])),i=!(e.length===n.length&&e.every((e,t)=>e.id===n[t]?.id)),a=n.map(e=>{let t=r.get(e.id);return t&&JSON.stringify(t)===JSON.stringify(e)?t:(i=!0,e)});return i?a:e}function He(){return typeof document>`u`?!0:document.hidden}function Ue(e,t){return!!(e&&t.view===`chat`&&t.selectedInboxThread===e&&!He())}function We(e){return e.threadPeer||e.agentId||``}function Ge(e,t){return Ue(We(e),t)}function Ke(e){return e.filter(e=>e.to===`user`&&e.from!==`user`&&y(e)).reduce((e,t)=>Math.max(e,t.id),0)}var qe={enabled:!0,browserEnabled:!1,messages:!0,replies:!0,errors:!0};function Je(e,t){return t.enabled?e.kind===`message`?t.messages:e.kind===`reply`?t.replies:t.errors:!1}function Ye(){return typeof window<`u`&&`Notification`in window}function q(){return Ye()?window.Notification.permission:`unsupported`}function Xe(e,t){return!Je(e,t.notificationSettings)||!t.notificationSettings.browserEnabled||q()!==`granted`||Ge(e,t)?!1:He()||t.view!==`chat`}function Ze(e,t){if(q()===`granted`)try{let n=new window.Notification(e.title,{body:e.body,tag:e.id,icon:`icons/agent-relay-192.png`,data:{view:e.view,threadPeer:e.threadPeer,agentId:e.agentId,messageId:e.messageId}});n.onclick=()=>{window.focus(),t(),n.close()}}catch{}}var Qe=(e,t)=>({notification:null,toastNotification:null,notifications:[],notificationUnread:0,notificationSettings:{...qe},notificationPermission:q(),confirmModal:{show:!1,title:``,message:``,action:null},errorModal:{show:!1,title:``,message:``},openConfirm(t,n,r){e({confirmModal:{show:!0,title:t,message:n,action:r}})},showError(t,n){e({errorModal:{show:!0,title:t,message:n}})},showNotification(t){e({notification:t,toastNotification:null}),setTimeout(()=>e({notification:null}),3e3)},handleRelayNotification(n){let r=t();if(!Je(n,r.notificationSettings)||r.notifications.some(e=>e.id===n.id))return;let i=Ge(n,r),a=`${n.title}: ${n.body}`;e({notifications:[n,...r.notifications].slice(0,100),notificationUnread:i?r.notificationUnread:Math.min(99,r.notificationUnread+1),notification:i?r.notification:a,toastNotification:i?r.toastNotification:n}),i||setTimeout(()=>{t().toastNotification?.id===n.id&&e({notification:null,toastNotification:null})},4500),Xe(n,r)&&Ze(n,()=>t().openNotification(n)),i&&n.threadPeer&&n.messageId&&t().markInboxThreadReadTo(n.threadPeer,n.messageId)},async openNotification(n){if(e({notificationUnread:0}),n.threadPeer&&(t().openInboxThread(n.threadPeer),n.messageId&&t().markInboxThreadReadTo(n.threadPeer,n.messageId)),n.view&&await t().switchView(n.view),n.agentId&&n.view===`agents`){let e=t().agentsById[n.agentId];e&&t().openAgentDetail(e)}},dismissToast(){e({notification:null,toastNotification:null})},markNotificationsRead(){e({notificationUnread:0})},clearNotifications(){e({notifications:[],notificationUnread:0})},async requestBrowserNotifications(){if(!Ye()){e({notificationPermission:`unsupported`,notificationSettings:{...t().notificationSettings,browserEnabled:!1}}),t().showNotification(`Browser notifications are not supported here`);return}let n=await window.Notification.requestPermission();e({notificationPermission:n,notificationSettings:{...t().notificationSettings,browserEnabled:n===`granted`}}),t().showNotification(n===`granted`?`Browser notifications enabled`:`Browser notifications not enabled`)}}),$e=e=>({voiceTtsEnabled:!1,voiceTtsLang:`en-US`,voiceTtsMode:`kokoro`,voiceTtsKokoroVoice:`am_michael`,voiceTtsBrowserVoice:``,voiceInputMode:`compose`,setVoiceTtsEnabled(t){N.setEnabled(t),e({voiceTtsEnabled:t})},setVoiceTtsLang(t){N.setLang(t),e({voiceTtsLang:t})},setVoiceTtsMode(t){N.setMode(t),e({voiceTtsMode:t})},setVoiceTtsKokoroVoice(t){N.setKokoroVoice(t),e({voiceTtsKokoroVoice:t})},setVoiceTtsBrowserVoice(t){N.setBrowserVoice(t),e({voiceTtsBrowserVoice:t})},setVoiceInputMode(t){e({voiceInputMode:t})}}),et=null;function tt(e){let t=e.voiceTtsEnabled&&e.view===`chat`&&e.selectedInboxThread||null;t!==et&&(et=t,N.setActiveChat(t))}var nt=(e,t)=>({theme:`dark`,view:`overview`,autoRefresh:!0,mobileMenuOpen:!1,commandPaletteOpen:!1,commandQuery:``,connected:!1,connectionError:!1,authNeeded:!1,authToken:``,stats:{},fileOrchestratorId:``,filePath:``,fileSelectedPath:``,fileSelectedLine:0,fileOverlayOpen:!1,_es:null,_refreshTimer:null,_refreshInFlight:!1,set:t=>e(t),async init(){$.persist.hasHydrated()||await new Promise(e=>{let t=$.persist.onFinishHydration(()=>{t(),e()})});let a=t().authToken;a&&r(a),n(t().view),N.setEnabled(t().voiceTtsEnabled),N.setLang(t().voiceTtsLang),N.setMode(t().voiceTtsMode),N.setKokoroVoice(t().voiceTtsKokoroVoice),N.setBrowserVoice(t().voiceTtsBrowserVoice),tt(t()),c(()=>{t().authNeeded||e({authNeeded:!0,connectionError:!1})}),e({notificationPermission:q()}),t().startClock();try{e({stats:await i(`GET`,`/stats`)})}catch(t){if(t.status===401){e({authNeeded:!0});return}}await t().refresh(),t().connectSSE(),t().startAutoRefresh()},async switchView(r){n(r),e({view:r,mobileMenuOpen:!1});let i=t();[`chat`,`messages`].includes(r)&&await Promise.all([i.fetchMessages(),i.fetchChatHistoryImports()]),r===`activity`&&await Promise.all([i.fetchMessages(),i.fetchPairs(),i.fetchTasks(),i.fetchActivityEvents()]),r===`work`&&await Promise.all([i.fetchMessages(),i.fetchTasks()]),r===`pairs`&&await i.fetchPairs(),r===`channels`&&await i.fetchChannels(),r===`connectors`&&await i.fetchConnectors(),r===`integrations`&&await i.fetchIntegrations(),r===`memory`&&await i.refreshMemory(),r===`tasks`&&await i.fetchTasks(),r===`teams`&&await Promise.all([i.fetchTeams(),i.fetchTeamOutcomeAggregates(),i.refreshIssueRefs()]),r===`automation`&&await Promise.all([i.fetchAutomations(),i.fetchAutomationRuns()]),r===`maintenance`&&await i.fetchMaintenanceJobs(),r===`workspaces`&&await Promise.all([i.fetchWorkspaces(),i.fetchOrchestrators(),i.fetchAgents()]),r===`files`&&await i.fetchOrchestrators(),r===`analytics`&&await i.fetchAnalytics()},startClock(){P.getState().start()},stopClock(){P.getState().stop()},startAutoRefresh(){t().stopAutoRefresh(),t().autoRefresh&&e({_refreshTimer:setInterval(()=>t().refreshLiveData(),E)})},stopAutoRefresh(){let n=t();n._refreshTimer&&(clearInterval(n._refreshTimer),e({_refreshTimer:null}))},async apiCall(e,t,n){return i(e,t,n)},async openFilesAt(n){let r=t();e({fileOrchestratorId:n.orchestratorId||je(r.orchestrators,n.selectedPath||n.path)?.id||r.orchestrators.find(e=>e.status===`online`)?.id||``,filePath:n.path,fileSelectedPath:n.selectedPath||``,fileSelectedLine:n.line||0,fileOverlayOpen:n.overlay===!0}),n.overlay||await t().switchView(`files`)},async openFilesForAgent(e,n=!1){let r=typeof e.meta?.cwd==`string`?e.meta.cwd:``;if(!r){t().showNotification(`Agent has no cwd`);return}let i=Me(t().orchestrators,e);if(!i){t().showNotification(`No online orchestrator covers that cwd`);return}await t().openFilesAt({orchestratorId:i.id,path:r,overlay:n})},closeFileOverlay(){e({fileOverlayOpen:!1})},async refresh(){let e=t();await Promise.all([e.fetchStats(),e.fetchHealth(),e.fetchAgents(),e.fetchOrchestrators(),e.fetchPairs(),e.fetchMessages(),e.fetchTasks(),e.fetchChannels(),e.fetchConnectors(),e.fetchIntegrations(),e.fetchAutomations(),e.fetchAutomationRuns(),e.fetchManagedPolicies(),e.fetchAgentProfiles(),e.fetchMaintenanceJobs(),e.fetchWorkspaces(),e.fetchInboxState(),e.fetchActivityEvents(),e.fetchChatHistoryImports()])},async refreshLiveData(){if(!(t()._refreshInFlight||t().authNeeded)){e({_refreshInFlight:!0});try{try{let n=await i(`GET`,`/stats`);e(t().connectionError?{stats:n,connectionError:!1}:{stats:n})}catch(n){if(n.status===401)return;t().connectionError||e({connectionError:!0});return}let n=t(),r=[n.fetchHealth(),n.fetchAgents(),n.fetchOrchestrators(),n.fetchPairs(),n.fetchMessages(),n.fetchTasks(),n.fetchManagedPolicies(),n.fetchInboxState()],a=n.view;[`chat`,`messages`].includes(a)&&r.push(n.fetchChatHistoryImports()),a===`activity`&&r.push(n.fetchActivityEvents()),a===`memory`&&r.push(n.refreshMemory()),a===`automation`&&r.push(n.fetchAutomations(),n.fetchAutomationRuns()),a===`channels`&&r.push(n.fetchChannels()),a===`connectors`&&r.push(n.fetchConnectors()),a===`integrations`&&r.push(n.fetchIntegrations()),a===`maintenance`&&r.push(n.fetchMaintenanceJobs()),a===`profiles`&&r.push(n.fetchAgentProfiles()),a===`workspaces`&&r.push(n.fetchWorkspaces()),a===`analytics`&&r.push(n.fetchAnalytics()),a===`teams`&&r.push(n.fetchTeams(),n.fetchTeamOutcomeAggregates(),n.refreshIssueRefs()),n.agentDetailOpen&&n.agentDetailId&&r.push(n.fetchAgentIssueActivity(n.agentDetailId)),await Promise.all(r)}finally{e({_refreshInFlight:!1})}}},async fetchStats(){try{e({stats:await i(`GET`,`/stats`)})}catch{}},connectSSE(){t().disconnectSSE(),e({_es:o(t().authToken,{connected:()=>{e(t().connectionError?{connected:!0,connectionError:!1}:{connected:!0}),t().refreshLiveData();let n=Object.entries(t().agentChatByAgent).filter(([,e])=>e.loadedInitial).map(([e])=>e);Promise.all(n.map(e=>t().gapFillAgentChat(e))),t().refreshPlans(),t().refreshIssueRefs()},disconnected:()=>e({connected:!1}),message:(n,r)=>{if(n!==`connected`){if(n===`message.new`){let n=JSON.parse(r);if(n.kind===`session`&&n.from!==`user`){let e=n.payload?.session;e?.type===`response`&&e?.origin===`provider`&&N.onResponse(_(n),n.body)}let i=t();if(!i.messages.some(e=>e.id===n.id)){let t=[...i.messages,n];t.length>500&&t.splice(0,t.length-500),e({messages:t})}let a=_(n);for(let e of Object.keys(t().agentChatByAgent))t().appendChatTail(e,[n]);u(n)&&y(n)&&Ue(a,i)&&t().markInboxThreadReadTo(a,n.id);return}if(n===`message.queued`||n===`message.expired`||n===`message.delivery_updated`||n===`message.reaction_updated`){let n=JSON.parse(r);e({messages:W(t().messages,n)}),t().applyChatMessageUpdate(n);return}if(n===`notification.created`){t().handleRelayNotification(JSON.parse(r));return}if(n===`plan.created`||n===`plan.changed`){let e=JSON.parse(r),n=e.plan??e.data?.plan;n&&t().upsertPlan(n);return}if(n===`plan.deleted`){let e=JSON.parse(r),n=e.plan??e.data?.plan,i=n?.id??e.planId??e.id??e.data?.planId??e.data?.id;(n||i)&&t().removePlan(n??i);return}if(n===`team.dissolved`){let e=JSON.parse(r);e.teamId&&t().markTeamDissolved({teamId:e.teamId,outcomeStatus:e.outcomeStatus,reason:e.reason}),Promise.all([t().fetchTeams(),t().fetchTeamOutcomeAggregates()]);return}if(n===`activity.created`){let n=JSON.parse(r);e({activityEvents:W(t().activityEvents,n)}),n.issueRefId&&t().fetchIssueRef(n.issueRefId),n.agentId&&t().agentDetailOpen&&t().agentDetailId===n.agentId&&t().fetchAgentIssueActivity(n.agentId);return}if(n===`agent.status`){let n=JSON.parse(r),i=t(),a=i.agentsById[n.id];if(e({agents:W(i.agents,n),agentsById:{...i.agentsById,[n.id]:n}}),i.livenessMismatches[n.id]&&n.status!==`offline`){let t={...i.livenessMismatches};delete t[n.id],e({livenessMismatches:t})}let o=i.commandStalls[n.id];if(o){let t=Le(n);if(t?.status&&Ie.has(t.status)&&(t.timestamp??0)>o.ts){let t={...i.commandStalls};delete t[n.id],e({commandStalls:t})}}let s=Le(n),c=s?.status??Fe(a,n);if(c){let t=s?.timestamp??Date.now(),r=s?.id||`agent-status:${n.id}:${c}:${t}`;e({chatStatusEvents:G(i.chatStatusEvents,n.id,c,t,r)})}return}if(n===`liveness.mismatch`){let n=JSON.parse(r);n.agentId&&e({livenessMismatches:{...t().livenessMismatches,[n.agentId]:{agentId:n.agentId,detail:n.detail??`Process reported running but relay marked it offline`,ts:Date.now(),policyName:n.policyName,spawnRequestId:n.spawnRequestId}}});return}if(n===`command.stalled`){let n=JSON.parse(r);if(n.agentId){let r=Date.now(),i=n.kind??`compact`,a=i===`clear`?`clear-stalled`:`compaction-stalled`;e({commandStalls:{...t().commandStalls,[n.agentId]:{agentId:n.agentId,kind:i,detail:n.detail??`A context command was requested but never started — the session may need manual intervention.`,ts:r,commandId:n.commandId}},chatStatusEvents:G(t().chatStatusEvents,n.agentId,a,r,`command-stalled:${n.agentId}:${n.commandId??r}`)})}return}if(n===`agent.removed`){let n=JSON.parse(r),i=t(),a={...i.agentsById};delete a[n.id];let o={...i.livenessMismatches};delete o[n.id];let s={...i.commandStalls};delete s[n.id],e({livenessMismatches:o,commandStalls:s}),e({agents:i.agents.filter(e=>e.id!==n.id),agentsById:a});return}if(n===`message.claimed`){let n=JSON.parse(r);e({messages:t().messages.map(e=>e.id===n.messageId?{...e,claimedBy:n.claimedBy,claimExpiresAt:n.claimExpiresAt}:e)});return}if(n===`message.claim_released`){let n=JSON.parse(r);e({messages:t().messages.map(e=>e.id===n.messageId?{...e,claimedBy:void 0,claimedAt:void 0,claimExpiresAt:void 0}:e)});return}if(n===`message.deleted`){let n=JSON.parse(r);e({messages:t().messages.filter(e=>e.id!==n.messageId)});return}if(n===`orchestrator.status`){let n=JSON.parse(r);e({orchestrators:W(t().orchestrators,n)});return}if(n===`orchestrator.removed`){let n=JSON.parse(r);e({orchestrators:t().orchestrators.filter(e=>e.id!==n.id)});return}if(n===`policy.state.changed`||n===`config.changed`){t().fetchManagedPolicies();return}if(n===`command.dispatched`||n===`command.succeeded`){let i=JSON.parse(r).command;if(i){let r=ze(i,n);if(r){let n=typeof i.updatedAt==`number`?i.updatedAt:typeof i.createdAt==`number`?i.createdAt:Date.now();e({chatStatusEvents:G(t().chatStatusEvents,Re(i),r,n,i.id?`command:${i.id}:${r}`:void 0)})}}return}if([`task.created`,`task.updated`,`task.claimed`,`task.status`].includes(n)){let n=JSON.parse(r);e({tasks:W(t().tasks,n)})}}}})})},disconnectSSE(){let n=t()._es;n&&(n.close(),e({_es:null}))},openCommandPalette(){e({commandQuery:``,commandPaletteOpen:!0})},closeCommandPalette(){e({commandPaletteOpen:!1,commandQuery:``})},async runCommand(n){let{action:r,payload:i}=n;if(t().closeCommandPalette(),r===`openView`)await t().switchView(i.view);else if(r===`agentPreset`)e({showOffline:!0,agentPresetFilter:i.preset||``}),await t().switchView(`agents`);else if(r===`copy`)try{await navigator.clipboard?.writeText(i.value||``)}catch{}else if(r===`messageAgent`){let e=t().agentsById[i.agentId];e&&t().openComposeToAgent(e)}else r===`pairAgent`?t().openPairInvite(i.agentId):r===`filterTag`?(e({agentTagFilter:i.tag||``,tagFilter:i.tag||``}),await t().switchView(`agents`)):r===`exportActivity`&&t().exportActivity(i.format||`markdown`)},async saveTokenAndRefresh(){let n=t().authToken;r(n);try{await i(`GET`,`/stats`)}catch(t){if(t.status===401){e({authNeeded:!0});return}}e({authNeeded:!1,connectionError:!1}),t().connectSSE(),await t().refresh(),t().startAutoRefresh()},destroy(){c(null),t().disconnectSSE(),t().stopAutoRefresh(),t().stopClock()}}),rt=(e,t)=>({agents:[],agentsById:{},showOffline:!1,showBuiltIns:!1,agentSort:`status`,agentSortDir:`asc`,agentPresetFilter:``,agentStatusFilter:``,agentTagFilter:``,agentHostFilter:``,selectedAgent:``,agentDetailOpen:!1,agentDetailId:``,livenessMismatches:{},commandStalls:{},channelDetailOpen:!1,channelDetailId:``,renameModal:{show:!1,agentId:``,label:``},tagFilter:``,async fetchAgents(){try{let n=await i(`GET`,`/agents`),r=K(t().agents,n);if(r===t().agents)return;e({agents:r,agentsById:Ne(r)})}catch{}},openAgentDetail(t){e({agentDetailId:t.id,agentDetailOpen:!0})},closeAgentDetail(){e({agentDetailOpen:!1})},openChannelDetail(t){e({channelDetailId:t.id,channelDetailOpen:!0})},closeChannelDetail(){e({channelDetailOpen:!1})},openRename(t){e({renameModal:{show:!0,agentId:t.id,label:t.label||``}})},async doRename(){let n=t(),r=n.renameModal.label.trim()||null;try{await i(`PATCH`,`/agents/`+n.renameModal.agentId+`/label`,{label:r}),e({renameModal:{...n.renameModal,show:!1}})}catch(e){t().showError(`Rename Failed`,e.message)}},async doDeleteAgent(n){try{await i(`DELETE`,`/agents/`+n);let r=t(),a={...r.agentsById};delete a[n],e({agents:r.agents.filter(e=>e.id!==n),agentsById:a,selectedAgent:r.selectedAgent===n?``:r.selectedAgent})}catch(e){t().showError(`Delete Failed`,e.message)}},async doAgentAction(e,n,r){try{await i(`POST`,`/agents/`+encodeURIComponent(e.id)+`/actions`,{action:n,...r?{surface:{component:r}}:{}});let a=n===`restart`?`Restart`:n===`resume`?`Resume`:n===`shutdown`?`Shutdown`:n===`compact`?`Compact`:n===`clearContext`?`Clear context`:n;t().showNotification(`${a} command sent to ${te(e)}`),await Promise.all([t().fetchMessages(),t().fetchActivityEvents()])}catch(e){t().showError(`Action Failed`,e.message)}}}),J=300,Y={messages:[],oldestLoadedId:null,hasMore:!0,loading:!1,loadedInitial:!1};function it(e,t){let n=new URLSearchParams;for(let[e,r]of Object.entries(t))n.set(e,String(r));return`/agents/${encodeURIComponent(e)}/chat?${n.toString()}`}function at(e,t){return t.filter(t=>p(e,t)&&!ne(t)).sort((e,t)=>e.id-t.id)}function ot(e,t){return K(e,[...e,...t].sort((e,t)=>e.id-t.id))}function st(e){return e[0]?.id??null}var ct=(e,t)=>({messages:[],agentChatByAgent:{},threadHistory:{},threadMessages:[],threadOpen:!1,chatHistoryImports:[],selectedInboxThread:``,replyTo:null,composeOpen:!1,showReasoning:!1,chatAgentSearch:``,chatAgentProviderFilter:``,chatAgentStatusFilter:``,chatAgentTagFilter:``,chatAgentCapFilter:``,chatAgentHostFilter:``,chatAgentSort:`status`,chatAgentSortDir:`asc`,chatAgentGroupBy:``,chatAgentFiltersCollapsed:!0,chatStatusEvents:{},chatStickToBottom:!0,chatHasNewItems:!1,inboxReadCursors:{},inboxArchivedThreads:{},inboxDrafts:{},chatSending:!1,inboxSearch:``,inboxSort:`attention`,inboxSortDir:`desc`,inboxShowArchived:!1,channelFilter:``,compose:{...D},inboxCompose:{...S},async fetchMessages(){try{let n=t(),r=`/messages?limit=100`;n.view===`messages`&&n.selectedAgent&&(r+=`&for=`+encodeURIComponent(n.selectedAgent)),n.view===`messages`&&n.channelFilter&&(r+=`&channel=`+encodeURIComponent(n.channelFilter));let a=await i(`GET`,r),o=Ve(t().messages,a);e({messages:o});let s=t(),c=s.selectedInboxThread;if(Ue(c,s)){let e=0;for(let t of o)t.id>e&&_(t)===c&&u(t)&&y(t)&&(e=t.id);e&&t().markInboxThreadReadTo(c,e)}}catch{}},async loadAgentChat(n){if(n&&!t().agentChatByAgent[n]?.loading){e(e=>({agentChatByAgent:{...e.agentChatByAgent,[n]:{...e.agentChatByAgent[n]??Y,loading:!0}}}));try{let r=await i(`GET`,it(n,{limit:J})),a=at(n,r),o=t().agentChatByAgent[n]??Y,s=o.loadedInitial?ot(o.messages,a):K([],a);e(e=>({agentChatByAgent:{...e.agentChatByAgent,[n]:{messages:s,oldestLoadedId:st(s),hasMore:r.length===J,loading:!1,loadedInitial:!0}}}))}catch(r){e(e=>({agentChatByAgent:{...e.agentChatByAgent,[n]:{...e.agentChatByAgent[n]??Y,loading:!1}}})),t().showError(`Chat Load Failed`,r.message)}}},async loadOlder(n){if(!n)return;let r=t().agentChatByAgent[n];if(!r?.loadedInitial){await t().loadAgentChat(n);return}if(!(r.loading||!r.hasMore||r.oldestLoadedId===null)){e(e=>({agentChatByAgent:{...e.agentChatByAgent,[n]:{...r,loading:!0}}}));try{let a=await i(`GET`,it(n,{before:r.oldestLoadedId,limit:J})),o=at(n,a),s=t().agentChatByAgent[n]??r,c=K(s.messages,[...o,...s.messages].sort((e,t)=>e.id-t.id));e(e=>({agentChatByAgent:{...e.agentChatByAgent,[n]:{messages:c,oldestLoadedId:st(c),hasMore:a.length===J,loading:!1,loadedInitial:!0}}}))}catch(i){e(e=>({agentChatByAgent:{...e.agentChatByAgent,[n]:{...e.agentChatByAgent[n]??r,loading:!1}}})),t().showError(`Chat Load Failed`,i.message)}}},async gapFillAgentChat(e){if(!e)return;let n=t().agentChatByAgent[e];if(!n?.loadedInitial||n.messages.length===0)return;let r=n.messages[n.messages.length-1].id;try{for(;;){let a=r,o=await i(`GET`,it(e,{since:r,limit:J}));if(o.length===0||(t().appendChatTail(e,o.filter(e=>e.id>a)),r=o[o.length-1].id,r<=a)||o.length<J)return;n=t().agentChatByAgent[e];let s=n?.messages[n.messages.length-1]?.id;s&&s>r&&(r=s)}}catch(e){t().showError(`Chat Gap Fill Failed`,e.message)}},appendChatTail(n,r){if(!n||r.length===0)return;let i=at(n,r);if(i.length===0)return;let a=t().agentChatByAgent[n]??Y,o=ot(a.messages,i);e({agentChatByAgent:{...t().agentChatByAgent,[n]:{...a,messages:o,oldestLoadedId:st(o)}}})},async fetchThreadHistory(n){if(n)try{let r=await i(`GET`,`/messages?for=`+encodeURIComponent(n)+`&limit=500`);e({threadHistory:{...t().threadHistory,[n]:r}})}catch{}},async fetchChatHistoryImports(){try{e({chatHistoryImports:await i(`GET`,`/chat/history-imports?limit=500`)})}catch{}},async fetchInboxState(){try{let n=await i(`GET`,`/inbox/state?operatorId=user`),r={},a={},o={};for(let e of n?.threads||[])e.readCursorMessageId&&(r[e.peerId]=e.readCursorMessageId),e.archivedAtMessageId&&(a[e.peerId]=e.archivedAtMessageId);for(let e of n?.drafts||[])e.body&&(o[e.peerId]=e.body);let s=t().inboxDrafts;e({inboxReadCursors:r,inboxArchivedThreads:a,...Object.keys(s).length>0?{}:{inboxDrafts:o}})}catch{}},openCompose(){e({composeOpen:!0,compose:{...D,from:v}})},openComposeToAgent(t){e({replyTo:null,compose:{...D,from:v,to:t.id},composeOpen:!0})},async doSend(){let n=t();if(!n.compose.from||!n.compose.to||!n.compose.body){t().showError(`Validation`,`From, To, and Message are required.`);return}try{let r={from:n.compose.from,to:n.compose.to,body:n.compose.body};n.compose.channel&&(r.channel=n.compose.channel),n.compose.subject&&(r.subject=n.compose.subject),n.replyTo&&(r.replyTo=n.replyTo.id),n.compose.claimable&&(r.claimable=!0,r.kind=`task`,r.payload={title:n.compose.subject||`Claimable task`}),await i(`POST`,`/messages`,r),e({composeOpen:!1,replyTo:null,compose:{...D,from:v}}),await t().fetchMessages()}catch(e){t().showError(`Send Failed`,e.message)}},async doClaim(e){let n=t(),r=n.compose.from||n.selectedAgent;if(!r){t().showError(`Validation`,`Select an agent first.`);return}try{let n=await i(`POST`,`/messages/`+e+`/claim`,{agentId:r});n.ok||t().showError(`Claim Failed`,n.error||`unknown`),n.ok&&await Promise.all([t().fetchMessages(),t().fetchTasks()])}catch(e){t().showError(`Claim Failed`,e.message)}},async doDeliveryAction(e,n,r){try{await i(`POST`,`/messages/`+e+`/delivery/actions`,{action:n,reason:r,agentId:t().compose.from||t().selectedAgent||`user`}),await t().fetchMessages()}catch(e){t().showError(`Delivery Update Failed`,e.message)}},async doDeleteMessage(n){try{await i(`DELETE`,`/messages/`+n),e({messages:t().messages.filter(e=>e.id!==n)})}catch(e){t().showError(`Delete Failed`,e.message)}},applyChatMessageUpdate(n){let r=t().agentChatByAgent,i={};for(let[e,t]of Object.entries(r))t.messages.some(e=>e.id===n.id)&&(i[e]={...t,messages:t.messages.map(e=>e.id===n.id?n:e)});Object.keys(i).length!==0&&e({agentChatByAgent:{...r,...i}})},async reactToMessage(n,r){try{let a=(n.reactions||[]).some(e=>e.actorId===`user`&&e.emoji===r),o=await i(`POST`,`/messages/`+n.id+`/reactions`,{actorId:v,emoji:r,action:a?`remove`:`add`});e({messages:W(t().messages,o)}),t().applyChatMessageUpdate(o)}catch(e){t().showError(`Reaction Failed`,e.message)}},startReply(t){let n=t.from===`user`?t.to:t.from;e({replyTo:{id:t.id,from:t.from},compose:{...D,from:v,to:n,channel:t.channel||``},composeOpen:!0})},cancelReply(){e({replyTo:null})},async openThread(n){e({threadMessages:[],threadOpen:!0});try{e({threadMessages:await i(`GET`,`/messages/`+n+`/thread`)})}catch(e){t().showError(`Thread Load Failed`,e.message)}},openInboxThread(n,r=[]){e({selectedInboxThread:n}),r.length&&t().markInboxThreadRead(n,r),t().loadAgentChat(n)},async sendChatMessage(n,r,a=[]){if(!(!n.trim()&&a.length===0||t().chatSending)){e({chatSending:!0});try{if(t().agentsById[r.peer]?.providerCapabilities?.liveSession?.inject)await i(`POST`,`/agents/`+encodeURIComponent(r.peer)+`/prompt`,{body:n.trim()||`Attachment`,...a.length?{attachments:a}:{}});else{let e={from:v,to:r.peer,body:n.trim()||`Attachment`};r.lastMessage?.channel&&(e.channel=r.lastMessage.channel),r.lastMessage?.id&&(e.replyTo=r.lastMessage.id),a.length&&(e.payload={attachments:a}),await i(`POST`,`/messages`,e)}let o={...t().inboxDrafts};delete o[r.peer],e({inboxDrafts:o}),i(`DELETE`,`/inbox/drafts?operatorId=`+encodeURIComponent(C)+`&peerId=`+encodeURIComponent(r.peer)).catch(()=>{}),await Promise.all([t().fetchMessages(),t().loadAgentChat(r.peer)])}catch(e){t().showError(`Send Failed`,e.message)}e({chatSending:!1})}},async sendPermissionDecision(e,n,r,a){try{await i(`POST`,`/agents/`+encodeURIComponent(e)+`/permission-decision`,{approvalId:n,decision:r,...a?{answers:a}:{}});let o=r===`approve`?`Approved`:r===`approve-session`?`Approved for session`:r===`abort`?`Aborted`:r===`answer`?`Answer sent for`:`Denied`;t().showNotification(`${o} ${r===`answer`?`Claude's question`:`permission request`}`),await t().fetchAgents()}catch(e){t().showError(`Permission Failed`,e.message)}},markInboxThreadReadTo(n,r){!n||r<=(t().inboxReadCursors[n]||0)||(e({inboxReadCursors:{...t().inboxReadCursors,[n]:r}}),i(`PATCH`,`/inbox/threads`,{operatorId:C,peerId:n,readCursorMessageId:r}).catch(()=>{}))},markInboxThreadRead(e,n){!e||!n.length||t().markInboxThreadReadTo(e,Ke(n))},markInboxThreadUnread(n){let r={...t().inboxReadCursors};delete r[n],e({inboxReadCursors:r}),i(`PATCH`,`/inbox/threads`,{operatorId:C,peerId:n,readCursorMessageId:null}).catch(()=>{})},archiveInboxThread(n,r){e({inboxArchivedThreads:{...t().inboxArchivedThreads,[n]:r}}),t().selectedInboxThread===n&&e({selectedInboxThread:``}),i(`PATCH`,`/inbox/threads`,{operatorId:C,peerId:n,archivedAtMessageId:r}).catch(()=>{})},unarchiveInboxThread(n){let r={...t().inboxArchivedThreads};delete r[n],e({inboxArchivedThreads:r}),i(`PATCH`,`/inbox/threads`,{operatorId:C,peerId:n,archivedAtMessageId:null}).catch(()=>{})},setReplyDraft(n,r){let a={...t().inboxDrafts};r?a[n]=r:delete a[n],e({inboxDrafts:a}),r?i(`PUT`,`/inbox/drafts`,{operatorId:C,peerId:n,body:r}).catch(()=>{}):i(`DELETE`,`/inbox/drafts?operatorId=`+encodeURIComponent(C)+`&peerId=`+encodeURIComponent(n)).catch(()=>{})},async sendInboxReply(n,r){let a=(t().inboxDrafts[n]||``).trim();if(!a||t().chatSending){a||t().showError(`Validation`,`Reply body is required.`);return}e({chatSending:!0});try{let o={from:v,to:n,body:a};r?.channel&&(o.channel=r.channel),r?.id&&(o.replyTo=r.id),await i(`POST`,`/messages`,o);let s={...t().inboxDrafts};delete s[n],e({inboxDrafts:s}),i(`DELETE`,`/inbox/drafts?operatorId=`+encodeURIComponent(C)+`&peerId=`+encodeURIComponent(n)).catch(()=>{}),await t().fetchMessages()}catch(e){t().showError(`Reply Failed`,e.message)}e({chatSending:!1})},async doSendInboxCompose(){let n=t().inboxCompose,r=n.to;if(r){if(n.toMode===`tag`?r=`tag:`+r:n.toMode===`cap`&&(r=`cap:`+r),!n.body){t().showError(`Validation`,`Message is required.`);return}try{let a={from:v,to:r,body:n.body};n.channel&&(a.channel=n.channel),n.subject&&(a.subject=n.subject),n.claimable&&(a.claimable=!0,a.kind=`task`,a.payload={title:n.subject||`Claimable task`}),await i(`POST`,`/messages`,a),e({inboxCompose:{...S,toMode:n.toMode,to:n.to}}),await t().fetchMessages()}catch(e){t().showError(`Send Failed`,e.message)}}}});function X(e,t){return JSON.stringify([String(e),t||``])}function Z(e,t){return JSON.stringify([`team`,e,t||``])}function lt(e){return{threadId:String(e.threadId),...e.channel?{channel:e.channel}:{}}}function ut(e){return e.teamId?{teamId:e.teamId,...e.channel?{channel:e.channel}:{}}:null}function dt(e){return`teamId`in e?Z(e.teamId,e.channel):X(e.threadId,e.channel)}function ft(e){let t=new URLSearchParams(`teamId`in e?{teamId:e.teamId}:{threadId:String(e.threadId)});return e.channel&&t.set(`channel`,e.channel),`/plans?${t.toString()}`}var pt=(e,t)=>({plansById:{},plansByThread:{},plansByTeam:{},planLookups:{},planLoading:{},planCollapsed:null,setPlanCollapsed(t){e({planCollapsed:t})},async fetchPlan(n){let r=`teamId`in n?{teamId:n.teamId,...n.channel?{channel:n.channel}:{}}:{threadId:String(n.threadId),...n.channel?{channel:n.channel}:{}},a=dt(r);e({planLookups:{...t().planLookups,[a]:r},planLoading:{...t().planLoading,[a]:!0}});try{let n=await i(`GET`,ft(r)),o=lt(n),s=X(o.threadId,o.channel),c=ut(n),l=c?Z(c.teamId,c.channel):``,u=!(`teamId`in r),d=`teamId`in r;e({plansById:{...t().plansById,[n.id]:n},plansByThread:{...t().plansByThread,...u?{[a]:n}:{},[s]:n},plansByTeam:c?{...t().plansByTeam,...d?{[a]:n}:{},[l]:n}:t().plansByTeam,planLookups:{...t().planLookups,[a]:r,[s]:o,...c?{[l]:c}:{}},planLoading:{...t().planLoading,[a]:!1,[s]:!1,...c?{[l]:!1}:{}}}),t().hydrateIssueRefsForPlan(n)}catch(n){let i=typeof n.status==`number`?n.status:0;e({plansByThread:i===404&&!(`teamId`in r)?{...t().plansByThread,[a]:null}:t().plansByThread,plansByTeam:i===404&&`teamId`in r?{...t().plansByTeam,[a]:null}:t().plansByTeam,planLoading:{...t().planLoading,[a]:!1}}),i&&i!==404&&t().showError(`Plan Load Failed`,n.message)}},async refreshPlans(){let e=Object.values(t().planLookups);await Promise.all(e.map(e=>t().fetchPlan(e)))},upsertPlan(n){let r=lt(n),i=X(r.threadId,r.channel),a=ut(n),o=a?Z(a.teamId,a.channel):``;e({plansById:{...t().plansById,[n.id]:n},plansByThread:{...t().plansByThread,[i]:n},plansByTeam:a?{...t().plansByTeam,[o]:n}:t().plansByTeam,planLookups:{...t().planLookups,[i]:r,...a?{[o]:a}:{}},planLoading:{...t().planLoading,[i]:!1,...a?{[o]:!1}:{}}}),t().hydrateIssueRefsForPlan(n)},removePlan(n){let r=typeof n==`string`?n:n.id,i={...t().plansById};delete i[r],e({plansById:i,plansByThread:Object.fromEntries(Object.entries(t().plansByThread).filter(([,e])=>e?.id!==r)),plansByTeam:Object.fromEntries(Object.entries(t().plansByTeam).filter(([,e])=>e?.id!==r)),planLookups:Object.fromEntries(Object.entries(t().planLookups).filter(([e])=>t().plansByThread[e]?.id!==r&&t().plansByTeam[e]?.id!==r))})}}),mt=(e,t)=>({teams:[],teamsLoading:!1,teamsError:null,teamOutcomeAggregates:null,teamOutcomeAggregatesLoading:!1,teamOutcomeAggregatesError:null,async fetchTeams(){e({teamsLoading:!0,teamsError:null});try{let n=await i(`GET`,`/teams`),r=K(t().teams,n.teams);return e({teams:r,teamsLoading:!1,teamsError:null}),r}catch(n){return e({teamsLoading:!1,teamsError:g(n)}),t().teams}},async fetchTeamOutcomeAggregates(){e({teamOutcomeAggregatesLoading:!0,teamOutcomeAggregatesError:null});try{let t=await i(`GET`,`/teams/outcomes`);return e({teamOutcomeAggregates:t,teamOutcomeAggregatesLoading:!1,teamOutcomeAggregatesError:null}),t}catch(n){return e({teamOutcomeAggregatesLoading:!1,teamOutcomeAggregatesError:g(n)}),t().teamOutcomeAggregates}},upsertTeam(n){let r=W(t().teams,n);r!==t().teams&&e({teams:r})},markTeamDissolved(n){let r=Date.now();e({teams:t().teams.map(e=>e.id===n.teamId?{...e,status:`dissolved`,updatedAt:r,dissolvedAt:e.dissolvedAt??r,zeroMembersSince:void 0,...n.outcomeStatus?{outcomeStatus:n.outcomeStatus}:{},...n.reason?{outcomeSummary:n.reason}:{}}:e)})},async dissolveTeam(e){try{let n=await i(`POST`,`/teams/${encodeURIComponent(e)}/dissolve`,{});t().upsertTeam(n),t().showNotification(`Team dissolved`),await Promise.all([t().fetchTeams(),t().fetchTeamOutcomeAggregates(),t().fetchActivityEvents()])}catch(e){t().showError(`Dissolve Failed`,g(e))}}});function ht(e,t){return JSON.stringify([e,t])}function gt(e){return[...new Set(e.nodes.map(e=>e.refs?.issueId).filter(e=>!!e))]}function Q(e,t){let n=!1,r={...e};for(let i of t){let t=e[i.id];(!t||JSON.stringify(t)!==JSON.stringify(i))&&(r[i.id]=i,n=!0)}return n?r:e}var _t=(e,t)=>({issueRefsById:{},issuesByEntity:{},issueActivityByAgent:{},issueLoading:{},issueErrors:{},async fetchIssueRef(n){let r=`ref:${n}`;e({issueLoading:{...t().issueLoading,[r]:!0},issueErrors:{...t().issueErrors,[r]:null}});try{let a=await i(`GET`,`/issue-refs/${encodeURIComponent(n)}`);return e({issueRefsById:Q(t().issueRefsById,[a.issueRef]),issueLoading:{...t().issueLoading,[r]:!1}}),a.issueRef}catch(i){return e({issueLoading:{...t().issueLoading,[r]:!1},issueErrors:{...t().issueErrors,[r]:g(i)}}),t().issueRefsById[n]??null}},async fetchIssuesForEntity(n,r){let a=ht(n,r);e({issueLoading:{...t().issueLoading,[a]:!0},issueErrors:{...t().issueErrors,[a]:null}});try{let o=await i(`GET`,`/issue-associations/entities/${encodeURIComponent(n)}/${encodeURIComponent(r)}/issues`);return e({issuesByEntity:{...t().issuesByEntity,[a]:o.issues},issueRefsById:Q(t().issueRefsById,o.issues.map(e=>e.issueRef)),issueLoading:{...t().issueLoading,[a]:!1}}),o.issues}catch(n){return e({issueLoading:{...t().issueLoading,[a]:!1},issueErrors:{...t().issueErrors,[a]:g(n)}}),t().issuesByEntity[a]??[]}},async fetchAgentIssueActivity(n){let r=`agent:${n}`;e({issueLoading:{...t().issueLoading,[r]:!0},issueErrors:{...t().issueErrors,[r]:null}});try{let a=await i(`GET`,`/issue-activity/agents/${encodeURIComponent(n)}`);return e({issueActivityByAgent:{...t().issueActivityByAgent,[n]:a.issues},issueRefsById:Q(t().issueRefsById,a.issues.map(e=>e.issueRef)),issueLoading:{...t().issueLoading,[r]:!1}}),a.issues}catch(i){return e({issueLoading:{...t().issueLoading,[r]:!1},issueErrors:{...t().issueErrors,[r]:g(i)}}),t().issueActivityByAgent[n]??[]}},async hydrateIssueRefsForPlan(e){let n=gt(e).filter(e=>!t().issueRefsById[e]);await Promise.all(n.map(e=>t().fetchIssueRef(e)))},async refreshIssueRefs(){let e=Object.keys(t().issueRefsById).map(e=>t().fetchIssueRef(e)),n=Object.keys(t().issuesByEntity).map(e=>{try{let[n,r]=JSON.parse(e);return t().fetchIssuesForEntity(n,r)}catch{return Promise.resolve([])}});await Promise.all([...e,...n])},upsertIssueRef(n){let r=Q(t().issueRefsById,[n]);r!==t().issueRefsById&&e({issueRefsById:r})}}),vt=(e,t)=>({pairs:[],tasks:[],taskEvents:[],taskEventCache:{},taskEventsOpen:!1,pairInviteOpen:!1,pairMessageOpen:!1,pairInvite:{...T},pairMessage:{...b},pairStatusFilter:`open`,taskStatusFilter:``,taskSourceFilter:``,async fetchPairs(){try{let n=t(),r;if(n.view===`activity`)r=await i(`GET`,`/pairs`);else if(n.pairStatusFilter===`open`){let[e,t]=await Promise.all([i(`GET`,`/pairs?status=active`),i(`GET`,`/pairs?status=pending`)]);r=[...e,...t]}else r=n.pairStatusFilter?await i(`GET`,`/pairs?status=`+encodeURIComponent(n.pairStatusFilter)):await i(`GET`,`/pairs`);let a=r.sort((e,t)=>new Date(t.updatedAt).getTime()-new Date(e.updatedAt).getTime()),o=K(t().pairs,a);o!==t().pairs&&e({pairs:o})}catch{}},async fetchTasks(){try{let n=t(),r=new URLSearchParams({limit:`100`});n.taskStatusFilter&&r.set(`status`,n.taskStatusFilter),n.taskSourceFilter&&r.set(`source`,n.taskSourceFilter);let a=K(t().tasks,await i(`GET`,`/tasks?`+r.toString()));a!==t().tasks&&e({tasks:a})}catch{}},async doClaimTask(e){let n=t(),r=n.compose.from||n.selectedAgent;if(!r){t().showError(`Validation`,`Select an agent first.`);return}try{let n=await i(`POST`,`/tasks/`+e+`/claim`,{agentId:r});n.ok?await Promise.all([t().fetchTasks(),t().fetchMessages()]):t().showError(`Claim Failed`,n.error||`unknown`)}catch(e){t().showError(`Claim Failed`,e.message)}},async doUpdateTaskStatus(n,r){if(!(!n||!r||r===n.status))try{let a={status:r},o=n.claimedBy||t().compose.from||t().selectedAgent;o&&(a.agentId=o);let s=await i(`PATCH`,`/tasks/`+n.id+`/status`,a),c=s.task||s;if(e({tasks:t().tasks.map(e=>e.id===n.id?c:e)}),s.memoryEvent){let r=t().taskEventCache[n.id]||[];e({taskEventCache:{...t().taskEventCache,[n.id]:[...r,s.memoryEvent]},...t().taskEventsOpen?{taskEvents:[...t().taskEvents,s.memoryEvent]}:{}})}s.memory&&t().showNotification(`Memory captured: ${s.memory.title}`)}catch(e){t().showError(`Status Update Failed`,e.message),await t().fetchTasks()}},async openTaskEvents(n){e({taskEvents:[],taskEventsOpen:!0});try{let r=await i(`GET`,`/tasks/`+n.id+`/events`);e({taskEvents:r,taskEventCache:{...t().taskEventCache,[n.id]:r}})}catch(e){t().showError(`Task Events Failed`,e.message)}},openPairInvite(n){e({pairInvite:{...T,requesterId:n||t().selectedAgent||``},pairInviteOpen:!0})},closePairInvite(){e({pairInviteOpen:!1,pairInvite:{...T}})},async doCreatePair(){let n=t();if(!n.pairInvite.requesterId||!n.pairInvite.targetId){t().showError(`Validation`,`Requester and Target are required.`);return}if(n.pairInvite.requesterId===n.pairInvite.targetId){t().showError(`Validation`,`Requester and Target must be different.`);return}try{let r={from:n.pairInvite.requesterId,target:n.pairInvite.targetId};n.pairInvite.objective&&(r.objective=n.pairInvite.objective),await i(`POST`,`/pairs`,r),e({pairInviteOpen:!1,pairInvite:{...T}}),await Promise.all([t().fetchPairs(),t().fetchMessages()])}catch(e){t().showError(`Pair Invite Failed`,e.message)}},openPairMessage(t,n){e({pairMessage:{...b,pairId:t.id,from:n||t.requesterId},pairMessageOpen:!0})},closePairMessage(){e({pairMessageOpen:!1,pairMessage:{...b}})},async doSendPairMessage(){let n=t();if(!n.pairMessage.pairId||!n.pairMessage.from||!n.pairMessage.body){t().showError(`Validation`,`Pair, From, and Message are required.`);return}try{let r={from:n.pairMessage.from,body:n.pairMessage.body};n.pairMessage.subject&&(r.subject=n.pairMessage.subject),await i(`POST`,`/pairs/`+encodeURIComponent(n.pairMessage.pairId)+`/messages`,r),e({pairMessageOpen:!1,pairMessage:{...b}}),await Promise.all([t().fetchPairs(),t().fetchMessages()])}catch(e){t().showError(`Pair Message Failed`,e.message)}},async doAcceptPair(e){try{await i(`POST`,`/pairs/`+encodeURIComponent(e.id)+`/accept`,{agentId:e.targetId}),await Promise.all([t().fetchPairs(),t().fetchMessages()])}catch(e){t().showError(`Accept Failed`,e.message)}},async doRejectPair(e){try{await i(`POST`,`/pairs/`+encodeURIComponent(e.id)+`/reject`,{agentId:e.targetId}),await Promise.all([t().fetchPairs(),t().fetchMessages()])}catch(e){t().showError(`Reject Failed`,e.message)}},async doHangupPair(e,n){try{await i(`POST`,`/pairs/`+encodeURIComponent(e.id)+`/hangup`,{agentId:n||e.requesterId}),await Promise.all([t().fetchPairs(),t().fetchMessages()])}catch(e){t().showError(`Hang Up Failed`,e.message)}}}),yt=(e,t)=>({orchestrators:[],orchestratorSpawnOpen:!1,orchestratorInstallOpen:!1,spawnOrchId:``,spawnProvider:`claude`,spawnModel:U(`claude`),spawnEffort:``,spawnProfile:`default-relay`,spawnCwd:``,spawnLabel:``,spawnApproval:`guarded`,spawnWorkspaceMode:`inherit`,spawnPrompt:``,spawnSystemPromptAppend:``,spawnCount:1,spawnCwdHistory:[],isSpawning:!1,spawnDirBrowser:{open:!1,loading:!1,path:``,parent:``,baseDir:``,entries:[],error:``},pendingForkImport:null,async fetchOrchestrators(){try{let n=K(t().orchestrators,await i(`GET`,`/orchestrators`));n!==t().orchestrators&&e({orchestrators:n})}catch{}},async refreshOrchestratorProviders(e){try{await i(`GET`,`/orchestrators/`+encodeURIComponent(e)+`/providers?refresh=1`),await t().fetchOrchestrators(),t().showNotification(`Provider status refreshed`)}catch(e){t().showError(`Provider Refresh Failed`,e.message)}},openAgentSpawn(){t().openOrchestratorSpawn()},closeAgentSpawn(){e({orchestratorSpawnOpen:!1})},async doSpawnAgent(){await t().submitOrchestratorSpawn()},openOrchestratorSpawn(){t().openOrchestratorSpawnAt()},openOrchestratorSpawnAt(n={}){let r=t().orchestrators.filter(e=>e.status===`online`);if(!r.length){t().showError(`No Orchestrators`,`No orchestrators are currently online.`);return}let i=t(),a=n.orchestratorId?r.find(e=>e.id===n.orchestratorId):void 0;if(n.orchestratorId&&!a){t().showError(`Orchestrator Offline`,`The selected orchestrator is not online.`);return}let o=n.cwd?.trim()||i.spawnCwd,s=o?r.find(e=>f(o,e.baseDir)):void 0,c=i.spawnOrchId?r.find(e=>e.id===i.spawnOrchId):void 0,l=a?.id||s?.id||c?.id||r[0].id,u=r.find(e=>e.id===l),d=i.spawnProvider&&u.providers.includes(i.spawnProvider)?i.spawnProvider:H(u),p=i.spawnProvider===d&&i.spawnModel?i.spawnModel:U(d),m=o&&f(o,u.baseDir)?o:u.baseDir||``;e({spawnOrchId:l,spawnProvider:d,spawnModel:p,spawnEffort:i.spawnProvider===d&&i.spawnModel===p?i.spawnEffort:``,spawnProfile:i.spawnProfile||`default-relay`,spawnCwd:m,spawnLabel:``,spawnWorkspaceMode:`inherit`,spawnPrompt:``,spawnSystemPromptAppend:``,spawnCount:1,pendingForkImport:null,orchestratorSpawnOpen:!0})},forkFromAgent(n,r){let i=t(),a=i.agentsById[n];if(!a){t().showError(`Fork`,`Agent not found.`);return}let o=i.orchestrators.filter(e=>e.status===`online`);if(!o.length){t().showError(`No Orchestrators`,`No orchestrators are currently online.`);return}let s=a.providerCapabilities,c=s?.model?.provider||(typeof a.meta?.provider==`string`?a.meta.provider:``),l=s?.model?.alias||s?.model?.id||``,u=(c?V[c]:void 0)?.models.find(e=>e.alias===l||e.providerModel===l)?.alias||``,p=s?.model?.effort||``,h=a.meta?.workspace,g=ee(h)?h:{},_=m(g.repoRoot)||m(g.sourceCwd)||(typeof a.meta?.cwd==`string`?a.meta.cwd:``),v=m(g.mode),y=v===`isolated`?`isolated`:v===`shared`?`shared`:`inherit`,b=s?.session?.approvalMode||(typeof a.meta?.approvalMode==`string`?a.meta.approvalMode:`guarded`),x=a.label?`${a.label} (fork)`:``,S=o.find(e=>e.hostname===a.machine)||o.find(e=>f(_,e.baseDir))||o[0],C=te(a),w=[];for(let e of r){let t=d(e).trim();if(!t)continue;let n=e.from===`user`?`user`:`agent`;w.push(`[${n}]: ${t}`)}let T=w.join(`
|
|
6
|
+
`),E=14e3,D=`You are continuing work from a previous agent session (${C}). Below is the conversation history. Treat it as context for your work, not as your own actions.\n\n${T.length>E?`...
|
|
7
|
+
`+T.slice(T.length-E):T}`,ne=r.filter(e=>typeof e.id==`number`&&e.id>0).map(e=>e.id);e({spawnOrchId:S.id,spawnProvider:c||H(S),spawnModel:u||U(c||H(S)),spawnEffort:p,spawnProfile:i.spawnProfile||`default-relay`,spawnCwd:_||S.baseDir||``,spawnLabel:x,spawnApproval:b,spawnWorkspaceMode:y,spawnPrompt:`Continue from this previous session.`,spawnSystemPromptAppend:D,spawnCount:1,pendingForkImport:{sourcePeerId:a.id,sourceAgentId:a.id,sourceThreadId:a.id,sourceAgentLabel:C,messageIds:ne},orchestratorSpawnOpen:!0})},openOrchestratorInstall(){e({orchestratorInstallOpen:!0})},openOrchestratorSpawnFor(n){let r=t(),i=r.orchestrators.find(e=>e.id===n),a=H(i),o=U(a),s=r.spawnProvider===a&&r.spawnModel===o?r.spawnEffort:``,c=r.spawnCwd&&f(r.spawnCwd,i?.baseDir)?r.spawnCwd:i?.baseDir||``;e({spawnOrchId:n,spawnProvider:a,spawnModel:o,spawnEffort:s,spawnProfile:r.spawnProfile||`default-relay`,spawnCwd:c,spawnLabel:``,spawnWorkspaceMode:`inherit`,spawnPrompt:``,spawnSystemPromptAppend:``,spawnCount:1,pendingForkImport:null,orchestratorSpawnOpen:!0})},selectSpawnHistory(n,r){let i=t(),a=i.orchestrators.find(e=>e.id===n&&e.status===`online`);if(!a){t().showError(`Unavailable`,`That orchestrator is no longer online.`);return}if(n===i.spawnOrchId){e({spawnCwd:r});return}let o=i.spawnProvider&&a.providers.includes(i.spawnProvider)?i.spawnProvider:H(a),s=i.spawnProvider===o&&i.spawnModel?i.spawnModel:U(o);e({spawnOrchId:n,spawnProvider:o,spawnModel:s,spawnEffort:i.spawnProvider===o&&i.spawnModel===s?i.spawnEffort:``,spawnCwd:r})},async submitOrchestratorSpawn(){let n=t();if(n.isSpawning)return;if(!n.spawnOrchId){t().showError(`Validation`,`Select an orchestrator.`);return}let r=n.orchestrators.find(e=>e.id===n.spawnOrchId);if(!r){t().showError(`Validation`,`Selected orchestrator is not available.`);return}let a=n.spawnCwd.trim();if(!a){t().showError(`Validation`,`Select a working directory.`);return}if(!f(a,r.baseDir)){t().showError(`Validation`,`Working directory must be under ${r.baseDir}.`);return}let o=n.pendingForkImport,s=o?1:Math.max(1,Math.min(10,Math.round(n.spawnCount)||1));e({isSpawning:!0});try{for(let e=0;e<s;e++){let t={provider:n.spawnProvider,orchestratorId:n.spawnOrchId,approvalMode:n.spawnApproval,workspaceMode:n.spawnWorkspaceMode||`inherit`};n.spawnModel&&(t.model=n.spawnModel),n.spawnEffort&&(t.effort=n.spawnEffort),n.spawnProfile&&(t.profile=n.spawnProfile),t.cwd=a,n.spawnLabel&&(t.label=s>1?`${n.spawnLabel} ${e+1}`:n.spawnLabel),n.spawnPrompt&&(t.prompt=n.spawnPrompt),n.spawnSystemPromptAppend&&(t.systemPromptAppend=n.spawnSystemPromptAppend);let r=(await i(`POST`,`/agents/spawn`,t)).command?.params?.spawnRequestId;o&&r&&o.messageIds.length>0&&await i(`POST`,`/chat/history-imports`,{targetSpawnRequestId:r,sourcePeerId:o.sourcePeerId,sourceAgentId:o.sourceAgentId,sourceThreadId:o.sourceThreadId,sourceAgentLabel:o.sourceAgentLabel,importedBy:C,messageIds:o.messageIds})}e({orchestratorSpawnOpen:!1,pendingForkImport:null,isSpawning:!1,spawnCwdHistory:[{orchId:n.spawnOrchId,cwd:a},...n.spawnCwdHistory.filter(e=>!(e.orchId===n.spawnOrchId&&e.cwd===a))].slice(0,5)}),await Promise.all([t().fetchAgents(),t().fetchOrchestrators(),t().fetchActivityEvents(),t().fetchChatHistoryImports()])}catch(n){e({isSpawning:!1}),t().showError(`Spawn Failed`,n.message)}},orchestratorAction(e,n,r,a){let o=n===`restart`?`Restart`:`Shutdown`,s=r?`agent "${r}"`:`all agents`;t().openConfirm(`${o} Agent`,`${o} ${s} on orchestrator "${e}"?`,async()=>{try{await i(`POST`,`/orchestrators/`+encodeURIComponent(e)+`/actions`,{action:n,agentId:r,...a?{surface:{component:a}}:{}}),await Promise.all([t().fetchOrchestrators(),t().fetchActivityEvents()])}catch(e){t().showError(`${o} Failed`,e.message)}})},upgradeOrchestrator(e,n){let r=n?` to v${n}`:` to match the relay`;t().openConfirm(`Upgrade Orchestrator`,`Upgrade "${e}"${r}? It will install the new version and restart itself.`,async()=>{try{await i(`POST`,`/orchestrators/`+encodeURIComponent(e)+`/actions`,{action:`upgrade`,...n?{targetVersion:n}:{}}),await Promise.all([t().fetchOrchestrators(),t().fetchActivityEvents()])}catch(e){t().showError(`Upgrade Failed`,e.message)}})},deleteOrchestrator(e){t().openConfirm(`Remove Orchestrator`,`Remove orchestrator "${e}"?`,async()=>{try{await i(`DELETE`,`/orchestrators/`+encodeURIComponent(e)),await Promise.all([t().fetchOrchestrators(),t().fetchActivityEvents()])}catch(e){t().showError(`Delete Failed`,e.message)}})},async browseSpawnDirectory(n){let r=t().spawnOrchId;if(!r)return;let a=t().spawnDirBrowser;e({spawnDirBrowser:{...a,loading:!0,error:``}});try{let a=n?`?path=`+encodeURIComponent(n):``,o=await i(`GET`,`/orchestrators/`+encodeURIComponent(r)+`/directories`+a);e({spawnDirBrowser:{open:!0,loading:!1,path:o.path||``,parent:o.parent||``,baseDir:o.baseDir||``,entries:o.entries||[],error:``},spawnCwd:o.path||t().spawnCwd})}catch(n){e({spawnDirBrowser:{...t().spawnDirBrowser,loading:!1,error:n.message}})}},selectSpawnDirectory(n){e({spawnCwd:n||t().spawnDirBrowser.path,spawnDirBrowser:{...t().spawnDirBrowser,open:!1}})}}),bt=(e,t)=>({managedPolicies:[],policyModal:{open:!1,editing:``,name:``,description:``,orchestratorId:``,cwd:``,enabled:void 0,provider:`claude`,rig:``,model:U(`claude`),effort:``,profile:`default-relay`,providerArgs:``,prompt:``,tags:``,capabilities:``,label:``,mode:`always-on`,permissionMode:`guarded`,restartOnUpdate:!0,scheduledDailyRestart:!1,keepaliveSeconds:`300`,backoffSchedule:`5,15,60,300`,backoffResetAfterSeconds:`600`,channelId:``},policyDirBrowser:{open:!1,loading:!1,path:``,parent:``,baseDir:``,entries:[],error:``},agentProfiles:[],profileModal:{open:!1,mode:`create`,profile:{name:``,description:``,provider:`any`,base:`host`,instructions:{system:``,append:[],repoInstructions:`allow`,globalInstructions:`allow`},relay:{context:!0,skills:!0,plugins:!0,statusLine:!0,mcp:!0},skills:[],plugins:[],mcp:{mode:`host`},hooks:{mode:`host`},permissions:{filesystem:`host`},env:{},providerOptions:{}}},async fetchManagedPolicies(){try{e({managedPolicies:await i(`GET`,`/spawn-policies/health`)})}catch{}},async fetchAgentProfiles(){try{e({agentProfiles:(await i(`GET`,`/agent-profiles`)).map(e=>e.value)})}catch{}},openPolicyCreate(){let n=t().orchestrators.filter(e=>e.status===`online`);if(!n.length){t().showError(`No Orchestrators`,`No orchestrators are currently online.`);return}e({policyModal:{open:!0,editing:``,name:``,description:``,orchestratorId:n[0].id,cwd:``,enabled:void 0,provider:H(n[0]),rig:``,model:U(H(n[0])),effort:``,profile:`default-relay`,providerArgs:``,prompt:``,tags:``,capabilities:``,label:``,mode:`always-on`,permissionMode:`guarded`,restartOnUpdate:!0,scheduledDailyRestart:!1,keepaliveSeconds:`300`,backoffSchedule:`5,15,60,300`,backoffResetAfterSeconds:`600`,channelId:``},policyDirBrowser:{open:!1,loading:!1,path:``,parent:``,baseDir:``,entries:[],error:``}})},openPolicyEdit(t){e({policyModal:{open:!0,editing:t.name,name:t.name,enabled:t.enabled,description:t.description||``,orchestratorId:t.orchestratorId,cwd:t.cwd,provider:t.provider,rig:t.rig||``,model:t.model||U(t.provider),effort:t.effort||``,profile:t.profile||`default-relay`,providerArgs:(t.providerArgs||[]).join(` `),prompt:t.prompt||``,tags:(t.tags||[]).join(`, `),capabilities:(t.capabilities||[]).join(`, `),label:t.label||``,mode:t.mode,permissionMode:t.permissionMode,restartOnUpdate:t.restartOnUpdate,scheduledDailyRestart:t.scheduledDailyRestart,keepaliveSeconds:String(t.onDemand?.keepaliveSeconds??300),backoffSchedule:(t.backoff?.schedule||[5,15,60,300]).join(`, `),backoffResetAfterSeconds:String(t.backoff?.resetAfterSeconds??600),channelId:t.binding?.channelId||``},policyDirBrowser:{open:!1,loading:!1,path:``,parent:``,baseDir:``,entries:[],error:``}})},async submitPolicy(){let n=t().policyModal;if(!n.name.trim()){t().showError(`Validation`,`Policy name is required.`);return}if(!n.orchestratorId){t().showError(`Validation`,`Select an orchestrator.`);return}if(!n.cwd.trim()){t().showError(`Validation`,`Working directory is required.`);return}let r=e=>e.split(/[,\s]+/).map(e=>e.trim()).filter(Boolean),a={name:n.name.trim(),...n.description.trim()?{description:n.description.trim()}:{},...n.enabled===void 0?{}:{enabled:n.enabled},orchestratorId:n.orchestratorId,cwd:n.cwd.trim(),provider:n.provider,...n.rig.trim()?{rig:n.rig.trim()}:{},...n.model?{model:n.model}:{},...n.effort?{effort:n.effort}:{},...n.profile?{profile:n.profile}:{},providerArgs:n.providerArgs.trim()?n.providerArgs.trim().split(/\s+/):[],...n.prompt.trim()?{prompt:n.prompt.trim()}:{},tags:r(n.tags),capabilities:r(n.capabilities),...n.label.trim()?{label:n.label.trim()}:{},mode:n.mode,permissionMode:n.permissionMode,restartOnUpdate:n.restartOnUpdate,scheduledDailyRestart:n.scheduledDailyRestart,...n.mode===`on-demand`?{onDemand:{keepaliveSeconds:Number(n.keepaliveSeconds)||300,idleDefinition:`no-activity`}}:{},backoff:{schedule:r(n.backoffSchedule).map(Number).filter(e=>e>0),resetAfterSeconds:Number(n.backoffResetAfterSeconds)||600},...n.channelId.trim()?{binding:{type:`channel`,channelId:n.channelId.trim()}}:{}};a.backoff.schedule.length||(a.backoff.schedule=[5,15,60,300]);try{await i(`PUT`,`/spawn-policy/`+encodeURIComponent(a.name),a),e({policyModal:{...n,open:!1}}),await t().fetchManagedPolicies()}catch(e){t().showError(`Save Failed`,e.message)}},deletePolicy(e){t().openConfirm(`Delete Policy`,`Delete managed agent policy "${e}"? This will stop any running agent.`,async()=>{try{await i(`DELETE`,`/spawn-policy/`+encodeURIComponent(e)),await t().fetchManagedPolicies()}catch(e){t().showError(`Delete Failed`,e.message)}})},async browsePolicyDirectory(n){let r=t().policyModal.orchestratorId;if(!r)return;let a=t().policyDirBrowser;e({policyDirBrowser:{...a,loading:!0,error:``}});try{let a=n?`?path=`+encodeURIComponent(n):``,o=await i(`GET`,`/orchestrators/`+encodeURIComponent(r)+`/directories`+a);e({policyDirBrowser:{open:!0,loading:!1,path:o.path||``,parent:o.parent||``,baseDir:o.baseDir||``,entries:o.entries||[],error:``},policyModal:{...t().policyModal,cwd:o.path||t().policyModal.cwd}})}catch(n){e({policyDirBrowser:{...t().policyDirBrowser,loading:!1,error:n.message}})}},selectPolicyDirectory(n){e({policyModal:{...t().policyModal,cwd:n||t().policyDirBrowser.path},policyDirBrowser:{...t().policyDirBrowser,open:!1}})},openProfileModal(t,n){let r={name:``,description:``,provider:`any`,base:`host`,instructions:{system:``,append:[],repoInstructions:`allow`,globalInstructions:`allow`},relay:{context:!0,skills:!0,plugins:!0,statusLine:!0,mcp:!0},skills:[],plugins:[],mcp:{mode:`host`},hooks:{mode:`host`},permissions:{filesystem:`host`},env:{},providerOptions:{}},i;n&&t===`duplicate`?(i=JSON.parse(JSON.stringify(n)),i.name=n.name+`-copy`,delete i.builtIn):i=n&&(t===`edit`||t===`view`)?JSON.parse(JSON.stringify(n)):r,e({profileModal:{open:!0,mode:t,profile:i}})},closeProfileModal(){e({profileModal:{...t().profileModal,open:!1}})},updateProfileModal(n){let r=t().profileModal.profile;e({profileModal:{...t().profileModal,profile:{...r,...n}}})},async saveProfile(){let{mode:n,profile:r}=t().profileModal;if(!r.name.trim()){t().showError(`Validation`,`Profile name is required.`);return}if(n!==`view`)try{await i(`PUT`,`/agent-profiles/`+encodeURIComponent(r.name.trim()),r),e({profileModal:{...t().profileModal,open:!1}}),await t().fetchAgentProfiles(),t().showNotification(`Profile "${r.name}" saved`)}catch(e){t().showError(`Save Failed`,e.message)}},deleteProfile(e){t().openConfirm(`Delete Profile`,`Delete agent profile "${e}"?`,async()=>{try{await i(`DELETE`,`/agent-profiles/`+encodeURIComponent(e)),await t().fetchAgentProfiles(),t().showNotification(`Profile "${e}" deleted`)}catch(e){t().showError(`Delete Failed`,e.message)}})}}),xt=(e,t)=>({operatorActivity:[],recordOperatorActivity(n){let r={id:Date.now(),kind:`operator`,title:n.title||`Activity`,body:n.body,meta:n.meta,icon:n.icon,view:n.view,peer:n.peer,messageId:n.messageId,pairId:n.pairId,taskId:n.taskId,agentId:n.agentId,ts:Date.now(),clientId:`op-`+Date.now(),createdAt:Date.now()};e({operatorActivity:[r,...t().operatorActivity.slice(0,79)]}),i(`POST`,`/activity`,{operatorId:C,clientId:r.clientId,kind:r.kind,title:r.title,body:r.body,meta:r.meta,icon:r.icon,view:r.view,peer:r.peer,messageId:r.messageId,pairId:r.pairId,taskId:r.taskId,agentId:r.agentId}).catch(()=>{})},async openActivityItem(e){if(e.view&&await t().switchView(e.view===`inbox`?`chat`:e.view),e.peer&&t().openInboxThread(e.peer),e.agentId){let n=t().agentsById[e.agentId];n&&t().openAgentDetail(n)}if(e.taskId){let n=t().tasks.find(t=>t.id===e.taskId);n&&await t().openTaskEvents(n)}}});function St(e){return h(e.createdAt??e.ts)}function Ct(e,t){let n=[`# Agent Relay Timeline`,``,`Exported: ${t}`,`Events: ${e.length}`,``];for(let t of e){let e=new Date(St(t)).toISOString();n.push(`## ${t.title||t.kind||`Event`}`),n.push(`- When: ${e}`),t.kind&&n.push(`- Kind: ${t.kind}`),t.agentId&&n.push(`- Agent: ${t.agentId}`),t.peer&&n.push(`- Peer: ${t.peer}`),t.body&&n.push(``,t.body),n.push(``)}return n.join(`
|
|
8
|
+
`)}var wt=(e,t)=>({activityEvents:[],activityFilter:``,async fetchActivityEvents(){try{e({activityEvents:await i(`GET`,`/activity?limit=200`)})}catch{}},exportActivity(e){let n=t(),r=[...n.operatorActivity,...n.activityEvents].sort((e,t)=>St(t)-St(e)),i=new Date().toISOString(),a=`agent-relay-timeline-${i.slice(0,10)}.${e===`json`?`json`:`md`}`;e===`json`?w(a,JSON.stringify({title:`Agent Relay Timeline`,exportedAt:i,events:r},null,2),`application/json`):w(a,Ct(r,i),`text/markdown`)},exportThread(e,t){let n=`agent-relay-thread-${l(e.peer)}.${t===`json`?`json`:`md`}`,r={title:`Thread: `+e.peer,importedHistory:e.importedHistory||[],messages:e.messages,exportedAt:new Date().toISOString()};w(n,JSON.stringify(r,null,2),t===`json`?`application/json`:`text/markdown`)},exportPair(e,t){let n=`agent-relay-pair-${l(e.id)}.${t===`json`?`json`:`md`}`,r={title:`Pair: `+e.id,pair:e,exportedAt:new Date().toISOString()};w(n,JSON.stringify(r,null,2),t===`json`?`application/json`:`text/markdown`)},async exportTask(n,r){let a=t().taskEventCache[n.id]||[];if(!a.length)try{a=await i(`GET`,`/tasks/`+n.id+`/events`),e({taskEventCache:{...t().taskEventCache,[n.id]:a}})}catch{}let o=`agent-relay-task-${n.id}.${r===`json`?`json`:`md`}`,s={title:`Task: `+(n.title||`#`+n.id),task:n,events:a,exportedAt:new Date().toISOString()};w(o,JSON.stringify(s,null,2),r===`json`?`application/json`:`text/markdown`)}}),Tt=(e,t)=>({channels:[],connectors:[],integrations:[],automations:[],automationRuns:[],health:null,maintenanceJobs:[],analyticsPeriod:`24h`,analyticsData:null,async fetchChannels(){try{e({channels:await i(`GET`,`/channels`)})}catch{}},async fetchConnectors(){try{e({connectors:await i(`GET`,`/connectors`)})}catch{}},async fetchIntegrations(){try{e({integrations:await i(`GET`,`/integrations`)})}catch{}},async fetchAutomations(){try{e({automations:await i(`GET`,`/automations`)})}catch{}},async fetchAutomationRuns(t){try{let n=new URLSearchParams({limit:`100`});t&&n.set(`automationId`,t),e({automationRuns:await i(`GET`,`/automation-runs?`+n.toString())})}catch{}},async fetchHealth(){try{e({health:await i(`GET`,`/health`)})}catch{}},async fetchMaintenanceJobs(){try{e({maintenanceJobs:await i(`GET`,`/maintenance/jobs`)})}catch{}},async runMaintenanceJob(n){try{let r=await i(`POST`,`/maintenance/jobs/`+encodeURIComponent(n)+`/run`,{});return e({maintenanceJobs:r.jobs}),t().showNotification(r.run.status===`succeeded`?`Maintenance job completed`:`Maintenance job skipped`),r.run}catch(e){return t().showError(`Maintenance Job Failed`,e.message),await t().fetchMaintenanceJobs(),null}},async runHealthAction(n){if(n.preset&&e({agentPresetFilter:n.preset,showOffline:!0}),n.api&&n.path&&(await i(n.api,n.path),await t().refreshLiveData()),n.view&&await t().switchView(n.view),n.copy)try{await navigator.clipboard?.writeText(n.copy)}catch{}},async runConnectorAction(e,n){try{let r=await i(`POST`,`/connectors/`+encodeURIComponent(e)+`/actions`,{action:n});if(await t().fetchConnectors(),!r.ok)throw Error(r.stderr||`${n} failed`);return r}catch(e){throw t().showError(`Connector Action Failed`,e.message),e}},async fetchAnalytics(){try{e({analyticsData:await i(`GET`,`/stats/analytics?period=`+t().analyticsPeriod)})}catch{}},setAnalyticsPeriod(n){e({analyticsPeriod:n}),t().fetchAnalytics()}}),Et=(e,t)=>({workspaces:[],workspaceFocusId:null,workspaceGitState:{},workspaceMergePreview:{},workspaceDiff:{},workspaceOrphans:[],async openWorkspaceFocus(n){e({workspaceFocusId:n}),await t().switchView(`workspaces`)},async fetchWorkspaces(){try{e({workspaces:await i(`GET`,`/workspaces`)})}catch{}},async fetchWorkspaceGitState(t){try{let n=await i(`GET`,`/workspaces/`+encodeURIComponent(t)+`/git-state`);e(e=>({workspaceGitState:{...e.workspaceGitState,[t]:n}}))}catch(n){e(e=>({workspaceGitState:{...e.workspaceGitState,[t]:{available:!1,reason:n.message}}}))}},async fetchWorkspaceMergePreview(t){try{let n=await i(`GET`,`/workspaces/`+encodeURIComponent(t)+`/merge-preview`);e(e=>({workspaceMergePreview:{...e.workspaceMergePreview,[t]:n}}))}catch(n){e(e=>({workspaceMergePreview:{...e.workspaceMergePreview,[t]:{available:!1,reason:n.message}}}))}},async fetchWorkspaceDiff(t){try{let n=await i(`GET`,`/workspaces/`+encodeURIComponent(t)+`/diff`);e(e=>({workspaceDiff:{...e.workspaceDiff,[t]:n}}))}catch(n){e(e=>({workspaceDiff:{...e.workspaceDiff,[t]:{available:!1,reason:n.message}}}))}},async fetchWorkspaceOrphans(){try{e({workspaceOrphans:(await i(`GET`,`/workspaces/orphans`)).orphans??[]})}catch{}},async reclaimWorkspaceOrphan(e){t().openConfirm(`Reclaim Orphan Worktree`,`Remove the orphaned worktree "${e.branch||e.worktreePath}" from disk? It has no live agent.`,async()=>{try{await i(`POST`,`/workspaces/orphans/reclaim`,{worktreePath:e.worktreePath,repoRoot:e.repoRoot,branch:e.branch}),t().showNotification(`Orphan reclaim dispatched`),await Promise.all([t().fetchWorkspaceOrphans(),t().fetchActivityEvents()])}catch(e){t().showError(`Reclaim Failed`,e.message)}})},async workspaceAction(e,n){let r=n===`ready`?`Mark ready`:n===`request-review`?`Request review`:n===`merge-plan`?`Mark merge planned`:n===`merge`?`Merge`:n===`abandon`?`Abandon`:`Cleanup`,a=async()=>{try{await i(`POST`,`/workspaces/`+encodeURIComponent(e)+`/actions`,{action:n}),t().showNotification(n===`cleanup`?`Workspace cleanup requested`:n===`merge`?`Workspace merge dispatched`:`Workspace updated: ${r}`),await Promise.all([t().fetchWorkspaces(),t().fetchOrchestrators(),t().fetchActivityEvents()])}catch(e){t().showError(`Workspace Action Failed`,e.message)}};if(n===`cleanup`||n===`abandon`||n===`merge`){let r=t().workspaces.find(t=>t.id===e),i=r?.branch||r?.worktreePath||e;if(n===`merge`){let n=t().workspaceMergePreview[e],r=n&&n.available!==!1?` — ${n.strategy===`pr`?`opens a PR`:`rebases & fast-forwards into ${n.baseRef||`base`}, then deletes the branch`}.`:` — lands the work and deletes the branch.`;t().openConfirm(`Merge Workspace`,`Merge workspace "${i}"?${r}`,a);return}if(n===`cleanup`){await t().fetchWorkspaceGitState(e);let n=t().workspaceGitState[e],r=``;if(n&&n.available!==!1&&!n.missing){let e=n.ahead??0,t=n.dirtyCount??0;(e>0||t>0)&&(r=` ⚠ This destroys ${[e>0?`${e} unmerged commit(s)`:``,t>0?`${t} uncommitted change(s)`:``].filter(Boolean).join(` and `)}.`)}t().openConfirm(`Cleanup Workspace`,`Remove the worktree for "${i}" on the host?${r}`,a);return}t().openConfirm(`Abandon Workspace`,`Abandon workspace "${i}"?`,a);return}await a()},async purgeWorkspace(e){let n=t().workspaces.find(t=>t.id===e),r=n?.branch||n?.worktreePath||e;t().openConfirm(`Purge Workspace Record`,`Permanently remove the record for "${r}"? This only clears the dashboard row — it does not touch disk.`,async()=>{try{await i(`DELETE`,`/workspaces/`+encodeURIComponent(e)),t().showNotification(`Workspace record purged`),await Promise.all([t().fetchWorkspaces(),t().fetchActivityEvents()])}catch(e){t().showError(`Purge Failed`,e.message)}})}}),Dt=(e,t)=>({memories:[],memoryTotal:0,memoryBrokerInfo:null,memoryStats:null,memoryFilters:{search:``,type:``,scope:``,tags:``,visibility:``,minRelevance:`0`},selectedMemoryId:``,memoryLoading:!1,async refreshMemory(){await Promise.all([t().fetchMemoryBroker(),t().fetchMemoryStats(),t().fetchMemories()])},async fetchMemoryBroker(){try{e({memoryBrokerInfo:await i(`GET`,`/memories/broker`)})}catch(e){t().showError(`Memory Broker Failed`,e.message)}},async fetchMemoryStats(){try{e({memoryStats:await i(`GET`,`/memories/stats`)})}catch{}},async fetchMemories(){let n=t().memoryFilters,r={limit:100};if(n.type&&(r.type=n.type),n.scope.trim()&&(r.scope=n.scope.trim()),n.visibility&&(r.visibility=n.visibility),n.tags.trim()&&(r.tags=n.tags.split(`,`).map(e=>e.trim()).filter(Boolean)),n.minRelevance.trim()!==``){let e=Number(n.minRelevance);Number.isFinite(e)&&(r.minRelevance=Math.max(0,Math.min(1,e)))}e({memoryLoading:!0});try{let n=await i(`POST`,`/memories/search`,r),a=n.memories.some(e=>e.id===t().selectedMemoryId)?t().selectedMemoryId:n.memories[0]?.id||``;e({memories:n.memories,memoryTotal:n.total,selectedMemoryId:a})}catch(e){t().showError(`Memory Search Failed`,e.message)}finally{e({memoryLoading:!1})}},async saveMemory(n,r){try{e({selectedMemoryId:(r?await i(`PATCH`,`/memories/`+encodeURIComponent(r),n):await i(`POST`,`/memories`,n)).id}),await Promise.all([t().fetchMemories(),t().fetchMemoryStats()]),t().showNotification(r?`Memory updated`:`Memory created`)}catch(e){t().showError(`Memory Save Failed`,e.message)}},deleteMemory(n){t().openConfirm(`Delete Memory`,`Delete memory "${n}"?`,async()=>{try{await i(`DELETE`,`/memories/`+encodeURIComponent(n)),e({selectedMemoryId:``}),await Promise.all([t().fetchMemories(),t().fetchMemoryStats()]),t().showNotification(`Memory deleted`)}catch(e){t().showError(`Delete Failed`,e.message)}})},async injectMemory(e){try{let n=await i(`POST`,`/memories/inject`,e);return t().showNotification(`Memory inject command sent to ${e.agentId}`),n}catch(e){return t().showError(`Memory Inject Failed`,e.message),null}}}),$=ce()(ue((...e)=>({...nt(...e),...rt(...e),...ct(...e),...pt(...e),...mt(...e),..._t(...e),...vt(...e),...yt(...e),...bt(...e),...Qe(...e),...xt(...e),...wt(...e),...$e(...e),...Tt(...e),...Et(...e),...Dt(...e)}),{name:`agent-relay-dashboard`,partialize:e=>({theme:e.theme,view:e.view,showOffline:e.showOffline,showBuiltIns:e.showBuiltIns,showReasoning:e.showReasoning,autoRefresh:e.autoRefresh,voiceTtsEnabled:e.voiceTtsEnabled,voiceTtsLang:e.voiceTtsLang,voiceTtsMode:e.voiceTtsMode,voiceTtsKokoroVoice:e.voiceTtsKokoroVoice,voiceTtsBrowserVoice:e.voiceTtsBrowserVoice,voiceInputMode:e.voiceInputMode,agentSort:e.agentSort,agentSortDir:e.agentSortDir,agentPresetFilter:e.agentPresetFilter,agentStatusFilter:e.agentStatusFilter,agentTagFilter:e.agentTagFilter,agentHostFilter:e.agentHostFilter,pairStatusFilter:e.pairStatusFilter,inboxSort:e.inboxSort,inboxSortDir:e.inboxSortDir,inboxShowArchived:e.inboxShowArchived,chatAgentProviderFilter:e.chatAgentProviderFilter,chatAgentStatusFilter:e.chatAgentStatusFilter,chatAgentTagFilter:e.chatAgentTagFilter,chatAgentCapFilter:e.chatAgentCapFilter,chatAgentHostFilter:e.chatAgentHostFilter,chatAgentSort:e.chatAgentSort,chatAgentSortDir:e.chatAgentSortDir,chatAgentGroupBy:e.chatAgentGroupBy,chatAgentFiltersCollapsed:e.chatAgentFiltersCollapsed,planCollapsed:e.planCollapsed,activityFilter:e.activityFilter,analyticsPeriod:e.analyticsPeriod,memoryFilters:e.memoryFilters,authToken:e.authToken,inboxReadCursors:e.inboxReadCursors,inboxArchivedThreads:e.inboxArchivedThreads,inboxDrafts:e.inboxDrafts,chatStatusEvents:e.chatStatusEvents,operatorActivity:e.operatorActivity,notifications:e.notifications,notificationUnread:e.notificationUnread,notificationSettings:e.notificationSettings,spawnOrchId:e.spawnOrchId,spawnProvider:e.spawnProvider,spawnModel:e.spawnModel,spawnEffort:e.spawnEffort,spawnProfile:e.spawnProfile,spawnCwd:e.spawnCwd,spawnApproval:e.spawnApproval,spawnWorkspaceMode:e.spawnWorkspaceMode,spawnCwdHistory:e.spawnCwdHistory})}));$.subscribe(tt);export{V as a,ke as c,Ce as d,we as f,Z as i,xe as l,N as m,ht as n,P as o,De as p,X as r,Oe as s,$ as t,Ee as u};
|
|
9
|
+
//# sourceMappingURL=store-Buwkqv_7.js.map
|