agent-relay-server 0.36.0 → 0.36.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/openapi.json +1 -1
- package/package.json +1 -1
- package/public/assets/{activity-DVdEofAq.js → activity-C3mkM6AU.js} +2 -2
- package/public/assets/{activity-DVdEofAq.js.map → activity-C3mkM6AU.js.map} +1 -1
- package/public/assets/{agent-profiles-BiQ-5F3l.js → agent-profiles-DS4_jLPT.js} +2 -2
- package/public/assets/{agent-profiles-BiQ-5F3l.js.map → agent-profiles-DS4_jLPT.js.map} +1 -1
- package/public/assets/{agents-Dt4FBBnk.js → agents-CAhQO7JH.js} +2 -2
- package/public/assets/{agents-Dt4FBBnk.js.map → agents-CAhQO7JH.js.map} +1 -1
- package/public/assets/{analytics-BeUxZhkP.js → analytics-BwihhhNn.js} +2 -2
- package/public/assets/{analytics-BeUxZhkP.js.map → analytics-BwihhhNn.js.map} +1 -1
- package/public/assets/{automation--G9ZMkL6.js → automation-BLXToUiU.js} +2 -2
- package/public/assets/{automation--G9ZMkL6.js.map → automation-BLXToUiU.js.map} +1 -1
- package/public/assets/{branch-state-badge-BTqHF74k.js → branch-state-badge-D8-T2c1K.js} +2 -2
- package/public/assets/{branch-state-badge-BTqHF74k.js.map → branch-state-badge-D8-T2c1K.js.map} +1 -1
- package/public/assets/{channels-nqTHGf6J.js → channels-ppN8k4hu.js} +2 -2
- package/public/assets/{channels-nqTHGf6J.js.map → channels-ppN8k4hu.js.map} +1 -1
- package/public/assets/chat-8iIPyww9.js +2 -0
- package/public/assets/{chat-DALcMlDH.js.map → chat-8iIPyww9.js.map} +1 -1
- package/public/assets/{connectors-ChkEg-0q.js → connectors-CL9BALhF.js} +2 -2
- package/public/assets/{connectors-ChkEg-0q.js.map → connectors-CL9BALhF.js.map} +1 -1
- package/public/assets/{formatted-body-impl-D1K3GML5.js → formatted-body-impl-BHH0wzY7.js} +2 -2
- package/public/assets/{formatted-body-impl-D1K3GML5.js.map → formatted-body-impl-BHH0wzY7.js.map} +1 -1
- package/public/assets/{index-DUxpx-Zp.css → index-3pO43nJo.css} +1 -1
- package/public/assets/{index-DdB6SVZY.js → index-CaauKXl9.js} +6 -6
- package/public/assets/{index-DdB6SVZY.js.map → index-CaauKXl9.js.map} +1 -1
- package/public/assets/{integrations-C8839Qa0.js → integrations-DX55ARy0.js} +2 -2
- package/public/assets/{integrations-C8839Qa0.js.map → integrations-DX55ARy0.js.map} +1 -1
- package/public/assets/{maintenance-Ddl4zgKZ.js → maintenance-9n_rJCHT.js} +2 -2
- package/public/assets/{maintenance-Ddl4zgKZ.js.map → maintenance-9n_rJCHT.js.map} +1 -1
- package/public/assets/{managed-agents-D-K6vUKj.js → managed-agents-Rp2-xpBx.js} +2 -2
- package/public/assets/{managed-agents-D-K6vUKj.js.map → managed-agents-Rp2-xpBx.js.map} +1 -1
- package/public/assets/{markdown-preview-impl-BjS4cnc3.js → markdown-preview-impl-YfJsGh6I.js} +2 -2
- package/public/assets/{markdown-preview-impl-BjS4cnc3.js.map → markdown-preview-impl-YfJsGh6I.js.map} +1 -1
- package/public/assets/{memory-BTV0z4uL.js → memory-BQONtGQS.js} +2 -2
- package/public/assets/{memory-BTV0z4uL.js.map → memory-BQONtGQS.js.map} +1 -1
- package/public/assets/{messages-CzHsL-om.js → messages-DGqpkH72.js} +2 -2
- package/public/assets/{messages-CzHsL-om.js.map → messages-DGqpkH72.js.map} +1 -1
- package/public/assets/{orchestrators-PMUp2sUP.js → orchestrators-b8k9QoGv.js} +2 -2
- package/public/assets/{orchestrators-PMUp2sUP.js.map → orchestrators-b8k9QoGv.js.map} +1 -1
- package/public/assets/{overview-B_od6jh0.js → overview-DSU_CggA.js} +2 -2
- package/public/assets/{overview-B_od6jh0.js.map → overview-DSU_CggA.js.map} +1 -1
- package/public/assets/{pairs-CaxiFyfY.js → pairs-DGocNC1U.js} +2 -2
- package/public/assets/{pairs-CaxiFyfY.js.map → pairs-DGocNC1U.js.map} +1 -1
- package/public/assets/{security-BZYHZ4CE.js → security-BSh0QxOl.js} +2 -2
- package/public/assets/{security-BZYHZ4CE.js.map → security-BSh0QxOl.js.map} +1 -1
- package/public/assets/{settings-RLyewdfK.js → settings-C03CAJgO.js} +2 -2
- package/public/assets/{settings-RLyewdfK.js.map → settings-C03CAJgO.js.map} +1 -1
- package/public/assets/{store-CMUFZKxf.js → store-DKVWC6Uh.js} +2 -2
- package/public/assets/store-DKVWC6Uh.js.map +1 -0
- package/public/assets/{tasks-BYTcfYDQ.js → tasks-rKbuUPOk.js} +2 -2
- package/public/assets/{tasks-BYTcfYDQ.js.map → tasks-rKbuUPOk.js.map} +1 -1
- package/public/assets/{terminal-viewer-impl-B5rPCNkZ.js → terminal-viewer-impl-CA8u4jh3.js} +2 -2
- package/public/assets/{terminal-viewer-impl-B5rPCNkZ.js.map → terminal-viewer-impl-CA8u4jh3.js.map} +1 -1
- package/public/assets/{work-queue-DYgqkTQD.js → work-queue-DOsA9s4M.js} +2 -2
- package/public/assets/{work-queue-DYgqkTQD.js.map → work-queue-DOsA9s4M.js.map} +1 -1
- package/public/assets/{workspaces-Dkq9DxCL.js → workspaces-CoC2nflZ.js} +2 -2
- package/public/assets/{workspaces-Dkq9DxCL.js.map → workspaces-CoC2nflZ.js.map} +1 -1
- package/public/index.html +3 -3
- package/public/assets/chat-DALcMlDH.js +0 -2
- package/public/assets/store-CMUFZKxf.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"store-CMUFZKxf.js","names":[],"sources":["../../dashboard/node_modules/zustand/esm/vanilla.mjs","../../dashboard/node_modules/zustand/esm/react.mjs","../../dashboard/node_modules/zustand/esm/middleware.mjs","../../sdk/src/speech-text.ts","../../dashboard/src/lib/voice.ts","../../dashboard/src/store/clock.ts","../../sdk/src/provider-catalog.ts","../../dashboard/src/store/helpers.ts","../../dashboard/src/store/merge.ts","../../dashboard/src/store/slices/notifications.ts","../../dashboard/src/store/slices/voice.ts","../../dashboard/src/store/slices/connection.ts","../../dashboard/src/store/slices/agents.ts","../../dashboard/src/store/slices/chat.ts","../../dashboard/src/store/slices/work.ts","../../dashboard/src/store/slices/spawn.ts","../../dashboard/src/store/slices/managed.ts","../../dashboard/src/store/slices/operator.ts","../../dashboard/src/store/slices/timeline.ts","../../dashboard/src/store/slices/ops.ts","../../dashboard/src/store/slices/workspaces.ts","../../dashboard/src/store/slices/memory.ts","../../dashboard/src/store/index.ts"],"sourcesContent":["const createStoreImpl = (createState) => {\n let state;\n const listeners = /* @__PURE__ */ new Set();\n const setState = (partial, replace) => {\n const nextState = typeof partial === \"function\" ? partial(state) : partial;\n if (!Object.is(nextState, state)) {\n const previousState = state;\n state = (replace != null ? replace : typeof nextState !== \"object\" || nextState === null) ? nextState : Object.assign({}, state, nextState);\n listeners.forEach((listener) => listener(state, previousState));\n }\n };\n const getState = () => state;\n const getInitialState = () => initialState;\n const subscribe = (listener) => {\n listeners.add(listener);\n return () => listeners.delete(listener);\n };\n const api = { setState, getState, getInitialState, subscribe };\n const initialState = state = createState(setState, getState, api);\n return api;\n};\nconst createStore = ((createState) => createState ? createStoreImpl(createState) : createStoreImpl);\n\nexport { createStore };\n","import React from 'react';\nimport { createStore } from 'zustand/vanilla';\n\nconst identity = (arg) => arg;\nfunction useStore(api, selector = identity) {\n const slice = React.useSyncExternalStore(\n api.subscribe,\n React.useCallback(() => selector(api.getState()), [api, selector]),\n React.useCallback(() => selector(api.getInitialState()), [api, selector])\n );\n React.useDebugValue(slice);\n return slice;\n}\nconst createImpl = (createState) => {\n const api = createStore(createState);\n const useBoundStore = (selector) => useStore(api, selector);\n Object.assign(useBoundStore, api);\n return useBoundStore;\n};\nconst create = ((createState) => createState ? createImpl(createState) : createImpl);\n\nexport { create, useStore };\n","const reduxImpl = (reducer, initial) => (set, _get, api) => {\n api.dispatch = (action) => {\n set((state) => reducer(state, action), false, action);\n return action;\n };\n api.dispatchFromDevtools = true;\n return { dispatch: (...args) => api.dispatch(...args), ...initial };\n};\nconst redux = reduxImpl;\n\nconst shouldDispatchFromDevtools = (api) => !!api.dispatchFromDevtools && typeof api.dispatch === \"function\";\nconst trackedConnections = /* @__PURE__ */ new Map();\nconst getTrackedConnectionState = (name) => {\n const api = trackedConnections.get(name);\n if (!api) return {};\n return Object.fromEntries(\n Object.entries(api.stores).map(([key, api2]) => [key, api2.getState()])\n );\n};\nconst extractConnectionInformation = (store, extensionConnector, options) => {\n if (store === void 0) {\n return {\n type: \"untracked\",\n connection: extensionConnector.connect(options)\n };\n }\n const existingConnection = trackedConnections.get(options.name);\n if (existingConnection) {\n return { type: \"tracked\", store, ...existingConnection };\n }\n const newConnection = {\n connection: extensionConnector.connect(options),\n stores: {}\n };\n trackedConnections.set(options.name, newConnection);\n return { type: \"tracked\", store, ...newConnection };\n};\nconst removeStoreFromTrackedConnections = (name, store) => {\n if (store === void 0) return;\n const connectionInfo = trackedConnections.get(name);\n if (!connectionInfo) return;\n delete connectionInfo.stores[store];\n if (Object.keys(connectionInfo.stores).length === 0) {\n trackedConnections.delete(name);\n }\n};\nconst v8StackLineRe = /.+ (.+) .+/;\nconst geckoStackLineRe = /^([^@]+)@/;\nfunction findCallerName(stack) {\n var _a, _b, _c;\n if (!stack) return void 0;\n const traceLines = stack.split(\"\\n\");\n const apiSetStateLineIndex = traceLines.findIndex(\n (traceLine) => traceLine.includes(\"api.setState\")\n );\n if (apiSetStateLineIndex < 0) return void 0;\n const callerLine = ((_a = traceLines[apiSetStateLineIndex + 1]) == null ? void 0 : _a.trim()) || \"\";\n return ((_b = v8StackLineRe.exec(callerLine)) == null ? void 0 : _b[1]) || ((_c = geckoStackLineRe.exec(callerLine)) == null ? void 0 : _c[1]);\n}\nconst devtoolsImpl = (fn, devtoolsOptions = {}) => (set, get, api) => {\n const { enabled, anonymousActionType, store, ...options } = devtoolsOptions;\n let extensionConnector;\n try {\n extensionConnector = (enabled != null ? enabled : (import.meta.env ? import.meta.env.MODE : void 0) !== \"production\") && window.__REDUX_DEVTOOLS_EXTENSION__;\n } catch (e) {\n }\n if (!extensionConnector) {\n return fn(set, get, api);\n }\n const { connection, ...connectionInformation } = extractConnectionInformation(store, extensionConnector, options);\n let isRecording = true;\n api.setState = ((state, replace, nameOrAction) => {\n const r = set(state, replace);\n if (!isRecording) return r;\n const action = nameOrAction === void 0 ? {\n type: anonymousActionType || findCallerName(new Error().stack) || \"anonymous\"\n } : typeof nameOrAction === \"string\" ? { type: nameOrAction } : nameOrAction;\n if (store === void 0) {\n connection == null ? void 0 : connection.send(action, get());\n return r;\n }\n connection == null ? void 0 : connection.send(\n {\n ...action,\n type: `${store}/${action.type}`\n },\n {\n ...getTrackedConnectionState(options.name),\n [store]: api.getState()\n }\n );\n return r;\n });\n api.devtools = {\n cleanup: () => {\n if (connection && typeof connection.unsubscribe === \"function\") {\n connection.unsubscribe();\n }\n removeStoreFromTrackedConnections(options.name, store);\n }\n };\n const setStateFromDevtools = (...a) => {\n const originalIsRecording = isRecording;\n isRecording = false;\n set(...a);\n isRecording = originalIsRecording;\n };\n const initialState = fn(api.setState, get, api);\n if (connectionInformation.type === \"untracked\") {\n connection == null ? void 0 : connection.init(initialState);\n } else {\n connectionInformation.stores[connectionInformation.store] = api;\n connection == null ? void 0 : connection.init(\n Object.fromEntries(\n Object.entries(connectionInformation.stores).map(([key, store2]) => [\n key,\n key === connectionInformation.store ? initialState : store2.getState()\n ])\n )\n );\n }\n if (shouldDispatchFromDevtools(api)) {\n let didWarnAboutReservedActionType = false;\n const originalDispatch = api.dispatch;\n api.dispatch = (...args) => {\n if ((import.meta.env ? import.meta.env.MODE : void 0) !== \"production\" && args[0].type === \"__setState\" && !didWarnAboutReservedActionType) {\n console.warn(\n '[zustand devtools middleware] \"__setState\" action type is reserved to set state from the devtools. Avoid using it.'\n );\n didWarnAboutReservedActionType = true;\n }\n originalDispatch(...args);\n };\n }\n connection.subscribe((message) => {\n var _a;\n switch (message.type) {\n case \"ACTION\":\n if (typeof message.payload !== \"string\") {\n console.error(\n \"[zustand devtools middleware] Unsupported action format\"\n );\n return;\n }\n return parseJsonThen(\n message.payload,\n (action) => {\n if (action.type === \"__setState\") {\n if (store === void 0) {\n setStateFromDevtools(action.state);\n return;\n }\n if (Object.keys(action.state).length !== 1) {\n console.error(\n `\n [zustand devtools middleware] Unsupported __setState action format.\n When using 'store' option in devtools(), the 'state' should have only one key, which is a value of 'store' that was passed in devtools(),\n and value of this only key should be a state object. Example: { \"type\": \"__setState\", \"state\": { \"abc123Store\": { \"foo\": \"bar\" } } }\n `\n );\n }\n const stateFromDevtools = action.state[store];\n if (stateFromDevtools === void 0 || stateFromDevtools === null) {\n return;\n }\n if (JSON.stringify(api.getState()) !== JSON.stringify(stateFromDevtools)) {\n setStateFromDevtools(stateFromDevtools);\n }\n return;\n }\n if (shouldDispatchFromDevtools(api)) {\n api.dispatch(action);\n }\n }\n );\n case \"DISPATCH\":\n switch (message.payload.type) {\n case \"RESET\":\n setStateFromDevtools(initialState);\n if (store === void 0) {\n return connection == null ? void 0 : connection.init(api.getState());\n }\n return connection == null ? void 0 : connection.init(getTrackedConnectionState(options.name));\n case \"COMMIT\":\n if (store === void 0) {\n connection == null ? void 0 : connection.init(api.getState());\n return;\n }\n return connection == null ? void 0 : connection.init(getTrackedConnectionState(options.name));\n case \"ROLLBACK\":\n return parseJsonThen(message.state, (state) => {\n if (store === void 0) {\n setStateFromDevtools(state);\n connection == null ? void 0 : connection.init(api.getState());\n return;\n }\n setStateFromDevtools(state[store]);\n connection == null ? void 0 : connection.init(getTrackedConnectionState(options.name));\n });\n case \"JUMP_TO_STATE\":\n case \"JUMP_TO_ACTION\":\n return parseJsonThen(message.state, (state) => {\n if (store === void 0) {\n setStateFromDevtools(state);\n return;\n }\n if (JSON.stringify(api.getState()) !== JSON.stringify(state[store])) {\n setStateFromDevtools(state[store]);\n }\n });\n case \"IMPORT_STATE\": {\n const { nextLiftedState } = message.payload;\n const lastComputedState = (_a = nextLiftedState.computedStates.slice(-1)[0]) == null ? void 0 : _a.state;\n if (!lastComputedState) return;\n if (store === void 0) {\n setStateFromDevtools(lastComputedState);\n } else {\n setStateFromDevtools(lastComputedState[store]);\n }\n connection == null ? void 0 : connection.send(\n null,\n // FIXME no-any\n nextLiftedState\n );\n return;\n }\n case \"PAUSE_RECORDING\":\n return isRecording = !isRecording;\n }\n return;\n }\n });\n return initialState;\n};\nconst devtools = devtoolsImpl;\nconst parseJsonThen = (stringified, fn) => {\n let parsed;\n try {\n parsed = JSON.parse(stringified);\n } catch (e) {\n console.error(\n \"[zustand devtools middleware] Could not parse the received json\",\n e\n );\n }\n if (parsed !== void 0) fn(parsed);\n};\n\nconst subscribeWithSelectorImpl = (fn) => (set, get, api) => {\n const origSubscribe = api.subscribe;\n api.subscribe = ((selector, optListener, options) => {\n let listener = selector;\n if (optListener) {\n const equalityFn = (options == null ? void 0 : options.equalityFn) || Object.is;\n let currentSlice = selector(api.getState());\n listener = (state) => {\n const nextSlice = selector(state);\n if (!equalityFn(currentSlice, nextSlice)) {\n const previousSlice = currentSlice;\n optListener(currentSlice = nextSlice, previousSlice);\n }\n };\n if (options == null ? void 0 : options.fireImmediately) {\n optListener(currentSlice, currentSlice);\n }\n }\n return origSubscribe(listener);\n });\n const initialState = fn(set, get, api);\n return initialState;\n};\nconst subscribeWithSelector = subscribeWithSelectorImpl;\n\nfunction combine(initialState, create) {\n return (...args) => Object.assign({}, initialState, create(...args));\n}\n\nfunction createJSONStorage(getStorage, options) {\n let storage;\n try {\n storage = getStorage();\n } catch (e) {\n return;\n }\n const persistStorage = {\n getItem: (name) => {\n var _a;\n const parse = (str2) => {\n if (str2 === null) {\n return null;\n }\n return JSON.parse(str2, options == null ? void 0 : options.reviver);\n };\n const str = (_a = storage.getItem(name)) != null ? _a : null;\n if (str instanceof Promise) {\n return str.then(parse);\n }\n return parse(str);\n },\n setItem: (name, newValue) => storage.setItem(name, JSON.stringify(newValue, options == null ? void 0 : options.replacer)),\n removeItem: (name) => storage.removeItem(name)\n };\n return persistStorage;\n}\nconst toThenable = (fn) => (input) => {\n try {\n const result = fn(input);\n if (result instanceof Promise) {\n return result;\n }\n return {\n then(onFulfilled) {\n return toThenable(onFulfilled)(result);\n },\n catch(_onRejected) {\n return this;\n }\n };\n } catch (e) {\n return {\n then(_onFulfilled) {\n return this;\n },\n catch(onRejected) {\n return toThenable(onRejected)(e);\n }\n };\n }\n};\nconst persistImpl = (config, baseOptions) => (set, get, api) => {\n let options = {\n storage: createJSONStorage(() => window.localStorage),\n partialize: (state) => state,\n version: 0,\n merge: (persistedState, currentState) => ({\n ...currentState,\n ...persistedState\n }),\n ...baseOptions\n };\n let hasHydrated = false;\n let hydrationVersion = 0;\n const hydrationListeners = /* @__PURE__ */ new Set();\n const finishHydrationListeners = /* @__PURE__ */ new Set();\n let storage = options.storage;\n if (!storage) {\n return config(\n (...args) => {\n console.warn(\n `[zustand persist middleware] Unable to update item '${options.name}', the given storage is currently unavailable.`\n );\n set(...args);\n },\n get,\n api\n );\n }\n const setItem = () => {\n const state = options.partialize({ ...get() });\n return storage.setItem(options.name, {\n state,\n version: options.version\n });\n };\n const savedSetState = api.setState;\n api.setState = (state, replace) => {\n savedSetState(state, replace);\n return setItem();\n };\n const configResult = config(\n (...args) => {\n set(...args);\n return setItem();\n },\n get,\n api\n );\n api.getInitialState = () => configResult;\n let stateFromStorage;\n const hydrate = () => {\n var _a, _b;\n if (!storage) return;\n const currentVersion = ++hydrationVersion;\n hasHydrated = false;\n hydrationListeners.forEach((cb) => {\n var _a2;\n return cb((_a2 = get()) != null ? _a2 : configResult);\n });\n const postRehydrationCallback = ((_b = options.onRehydrateStorage) == null ? void 0 : _b.call(options, (_a = get()) != null ? _a : configResult)) || void 0;\n return toThenable(storage.getItem.bind(storage))(options.name).then((deserializedStorageValue) => {\n if (deserializedStorageValue) {\n if (typeof deserializedStorageValue.version === \"number\" && deserializedStorageValue.version !== options.version) {\n if (options.migrate) {\n const migration = options.migrate(\n deserializedStorageValue.state,\n deserializedStorageValue.version\n );\n if (migration instanceof Promise) {\n return migration.then((result) => [true, result]);\n }\n return [true, migration];\n }\n console.error(\n `State loaded from storage couldn't be migrated since no migrate function was provided`\n );\n } else {\n return [false, deserializedStorageValue.state];\n }\n }\n return [false, void 0];\n }).then((migrationResult) => {\n var _a2;\n if (currentVersion !== hydrationVersion) {\n return;\n }\n const [migrated, migratedState] = migrationResult;\n stateFromStorage = options.merge(\n migratedState,\n (_a2 = get()) != null ? _a2 : configResult\n );\n set(stateFromStorage, true);\n if (migrated) {\n return setItem();\n }\n }).then(() => {\n if (currentVersion !== hydrationVersion) {\n return;\n }\n postRehydrationCallback == null ? void 0 : postRehydrationCallback(get(), void 0);\n stateFromStorage = get();\n hasHydrated = true;\n finishHydrationListeners.forEach((cb) => cb(stateFromStorage));\n }).catch((e) => {\n if (currentVersion !== hydrationVersion) {\n return;\n }\n postRehydrationCallback == null ? void 0 : postRehydrationCallback(void 0, e);\n });\n };\n api.persist = {\n setOptions: (newOptions) => {\n options = {\n ...options,\n ...newOptions\n };\n if (newOptions.storage) {\n storage = newOptions.storage;\n }\n },\n clearStorage: () => {\n storage == null ? void 0 : storage.removeItem(options.name);\n },\n getOptions: () => options,\n rehydrate: () => hydrate(),\n hasHydrated: () => hasHydrated,\n onHydrate: (cb) => {\n hydrationListeners.add(cb);\n return () => {\n hydrationListeners.delete(cb);\n };\n },\n onFinishHydration: (cb) => {\n finishHydrationListeners.add(cb);\n return () => {\n finishHydrationListeners.delete(cb);\n };\n }\n };\n if (!options.skipHydration) {\n hydrate();\n }\n return stateFromStorage || configResult;\n};\nconst persist = persistImpl;\n\nfunction ssrSafe(config, isSSR = typeof window === \"undefined\") {\n return (set, get, api) => {\n if (!isSSR) {\n return config(set, get, api);\n }\n const ssrSet = () => {\n throw new Error(\"Cannot set state of Zustand store in SSR\");\n };\n api.setState = ssrSet;\n return config(ssrSet, get, api);\n };\n}\n\nexport { combine, createJSONStorage, devtools, persist, redux, subscribeWithSelector, ssrSafe as unstable_ssrSafe };\n","/**\n * Shared text → speech preparation, imported by both the dashboard\n * (`dashboard/src/lib/voice.ts`) and the voice connector\n * (`connectors/voice/src/text.ts`). Single source of truth — these rules used to\n * live duplicated in both places and drifted.\n *\n * Two stages, applied in order by {@link prepareForSpeech}:\n * 1. {@link speechify} — collapse markdown/code structure into prose worth hearing.\n * 2. {@link normalizeForSpeech} — rule-based normalization of inline tokens\n * (numbers, units, symbols, code identifiers, paths) so the speech engine\n * reads them naturally.\n *\n * Why both, and why here: the server-side Kokoro engine (agent-speech) already\n * normalizes some of this internally (number ranges, decimals, currency) via its\n * phonemizer — but that normalization does NOT run for the browser Web Speech\n * fallback, and the dashboard's own sentence splitter trips on decimals before\n * the engine ever sees them. Normalizing here fixes the browser path and protects\n * the splitter; feeding already-normalized text to Kokoro is harmless (idempotent).\n */\n\n// ─── Stage 1: markdown/code → prose ──────────────────────────────────────────\n\n/** Collapse markdown/code into something worth hearing. */\nexport function speechify(markdown: string): string {\n if (!markdown) return ''\n let text = markdown.replace(/\\r\\n/g, '\\n')\n\n // Fenced code blocks → \"code block, N lines.\"\n text = text.replace(/```[^\\n]*\\n([\\s\\S]*?)```/g, (_m, body: string) => {\n const lines = body.replace(/\\n+$/, '').split('\\n').length\n return ` code block, ${lines} ${lines === 1 ? 'line' : 'lines'}. `\n })\n // Any unterminated fence left over → drop the marker.\n text = text.replace(/```[^\\n]*/g, ' code block. ')\n\n // Markdown tables → a spoken summary (must run before newlines collapse).\n text = collapseTables(text)\n\n // Strip ATX heading markers but keep the heading text.\n text = text.replace(/^#{1,6}\\s+/gm, '')\n // Bullet/numbered list markers → pause.\n text = text.replace(/^\\s*[-*+]\\s+/gm, '. ')\n text = text.replace(/^\\s*\\d+\\.\\s+/gm, '. ')\n // Inline code → keep the contents, drop the backticks.\n text = text.replace(/`([^`]+)`/g, '$1')\n // Markdown links [label](url) → just the label.\n text = text.replace(/\\[([^\\]]+)\\]\\([^)]+\\)/g, '$1')\n // Bold/italic emphasis markers.\n text = text.replace(/(\\*\\*|__|\\*|_)(.*?)\\1/g, '$2')\n\n // Collapse whitespace runs and stray punctuation pile-ups.\n text = text.replace(/[ \\t]+/g, ' ')\n text = text.replace(/\\n{2,}/g, '. ')\n text = text.replace(/\\s*\\.\\s*\\.\\s*(\\.\\s*)+/g, '. ')\n return text.trim()\n}\n\n/** A markdown table row: `| a | b |` or `a | b`. The separator row is `|---|:-:|`. */\nfunction isTableRow(line: string): boolean {\n return /\\|/.test(line) && line.trim().length > 0\n}\nfunction isTableSeparator(line: string): boolean {\n return /^\\s*\\|?\\s*:?-{2,}:?\\s*(\\|\\s*:?-{2,}:?\\s*)+\\|?\\s*$/.test(line)\n}\nfunction tableCells(line: string): string[] {\n return line\n .trim()\n .replace(/^\\||\\|$/g, '')\n .split('|')\n .map((c) => c.trim())\n .filter((c) => c.length > 0)\n}\n\n/**\n * Replace contiguous markdown tables with a spoken summary\n * (\"table with columns A, B, C; N rows.\") rather than reading pipes and cells.\n */\nfunction collapseTables(text: string): string {\n const lines = text.split('\\n')\n const out: string[] = []\n let i = 0\n while (i < lines.length) {\n if (\n isTableRow(lines[i]!) &&\n i + 1 < lines.length &&\n isTableSeparator(lines[i + 1]!)\n ) {\n const headers = tableCells(lines[i]!)\n let j = i + 2\n let rows = 0\n while (j < lines.length && isTableRow(lines[j]!) && !isTableSeparator(lines[j]!)) {\n rows++\n j++\n }\n const cols = headers.length ? `with columns ${headers.join(', ')}` : ''\n const rowText = `${rows} ${rows === 1 ? 'row' : 'rows'}`\n out.push(`table ${cols ? `${cols}, ` : ''}${rowText}.`.replace(/\\s+/g, ' ').trim())\n i = j\n continue\n }\n out.push(lines[i]!)\n i++\n }\n return out.join('\\n')\n}\n\n// ─── Stage 2: inline token normalization ─────────────────────────────────────\n\n/**\n * One normalization rule. Each is a single regex + replacement — add a new one\n * by appending an entry. Order matters: earlier rules see the raw text, later\n * rules see the output of earlier ones (see the ordering notes in SPEECH_RULES).\n */\ninterface SpeechRule {\n readonly name: string\n readonly pattern: RegExp\n readonly replace: string | ((substring: string, ...args: string[]) => string)\n}\n\nconst UNIT_WORDS: Record<string, string> = {\n ms: 'milliseconds',\n s: 'seconds',\n kb: 'kilobytes',\n mb: 'megabytes',\n gb: 'gigabytes',\n tb: 'terabytes',\n}\n\n/** Spell out a fractional part digit-by-digit: \"14\" → \"1 4\" (so \"3.14\" → \"3 point 1 4\"). */\nfunction spaceDigits(frac: string): string {\n return frac.split('').join(' ')\n}\n\n/**\n * Spell a token one character at a time so the engine reads each symbol on its\n * own: digits stay as digits, letters are upper-cased so they're heard as the\n * letter name (\"e\" → \"E\" = \"ee\") rather than a syllable. Used for commit hashes\n * (\"834543e\" → \"8 3 4 5 4 3 E\") and acronyms (\"id\" → \"I D\").\n */\nfunction spellOut(token: string): string {\n return token\n .split('')\n .map((c) => (/[0-9]/.test(c) ? c : c.toUpperCase()))\n .join(' ')\n}\n\n/**\n * Ordered normalization rules. ORDER IS LOAD-BEARING:\n * - URLs/paths first, before anything mangles their slashes/dots.\n * - `~` → \"approximately\" before number rules consume the digits after it.\n * - number ranges (\"5-7\") before unit expansion, so the unit attaches once: \"5 to 7 seconds\".\n * - versions (\"0.27.0\") before decimals, so all dots become \"dot\" uniformly\n * instead of the decimal rule eating only the first pair and stranding \".0\".\n * - decimals before unit expansion and before the sentence splitter sees the dot.\n * - commit-hash spelling before nothing in particular, but after decimals so a\n * real number is never mistaken for a hash.\n * - \"id\" acronym expansion (camelCase suffix before the standalone word).\n * - unit expansion among the number rules.\n * - interior-dot LAST, so it only mops up dots the structured rules left behind\n * (identifiers like \"branch.landed\", \"router.ts\") — never a decimal or version.\n */\nexport const SPEECH_RULES: readonly SpeechRule[] = [\n // Bare URLs read character-by-character → say \"link\".\n { name: 'url', pattern: /\\bhttps?:\\/\\/\\S+/gi, replace: ' link ' },\n // Absolute-ish paths (\"/api/connectors/voice\") → spoken words.\n {\n name: 'path',\n pattern: /(?:\\/[A-Za-z0-9._-]+){2,}\\/?/g,\n replace: (m) => ' ' + m.replace(/[/._-]+/g, ' ').trim() + ' ',\n },\n // A lone slash between words (\"src/router.ts\", \"TCP/IP\") → a space, so the\n // engine doesn't read \"slash\". Absolute multi-segment paths are already gone.\n { name: 'slash', pattern: /(?<=[A-Za-z0-9])\\/(?=[A-Za-z0-9])/g, replace: ' ' },\n // Empty-paren code identifiers (\"fetchSpeech()\") → drop the parens.\n { name: 'func-call', pattern: /\\b([A-Za-z_$][\\w$]*)\\(\\)/g, replace: '$1' },\n // Approximation tilde (\"~0.1\", \"~5\") → \"approximately\".\n { name: 'approx', pattern: /~(?=\\s*[\\d.])/g, replace: 'approximately ' },\n // Numeric ranges (\"5-7\", \"100–200\") → \"X to Y\".\n { name: 'range', pattern: /(\\d)\\s*[-–—]\\s*(?=\\d)/g, replace: '$1 to ' },\n // Dotted versions (\"0.27.0\", \"v1.2.3\", IPs) → every dot spoken as \"dot\".\n // Runs BEFORE decimal so 3+-part versions don't get half-eaten into \"point\".\n // A leading v/V is voiced as \"version\" (unambiguous here — v then digits then ≥2 dots).\n {\n name: 'version',\n pattern: /\\b(v?)(\\d+(?:\\.\\d+){2,})\\b/gi,\n replace: (_m, v: string, nums: string) =>\n `${v ? 'version ' : ''}${nums.replace(/\\./g, ' dot ')}`,\n },\n // Decimals (\"0.1\", \"3.14\") → \"0 point 1\" so the sentence splitter keeps them whole.\n { name: 'decimal', pattern: /\\b(\\d+)\\.(\\d+)\\b/g, replace: (_m, i: string, f: string) => `${i} point ${spaceDigits(f)}` },\n // Commit hashes (\"834543e\", \"3e0c66f85bd5\") → spell each char so the engine\n // doesn't read them as one giant number. Heuristic: 7–40 hex chars containing\n // BOTH a letter and a digit — excludes plain numbers and plain words.\n {\n name: 'hash',\n pattern: /\\b(?=[0-9a-f]{7,40}\\b)(?=[0-9a-f]*[a-f])(?=[0-9a-f]*\\d)[0-9a-f]{7,40}\\b/gi,\n replace: (m: string) => spellOut(m),\n },\n // camelCase \"Id\" suffix (\"messageId\", \"threadIds\") → \"message I D\", \"thread I Ds\".\n {\n name: 'id-camel',\n pattern: /([a-z])(Id|ID)(s)?\\b/g,\n replace: (_m, pre: string, _acr: string, plural: string) => `${pre} I D${plural ? 's' : ''}`,\n },\n // Standalone \"id\"/\"Id\"/\"ID\" word → \"I D\" (so it's not read as \"iiid\").\n {\n name: 'id-word',\n pattern: /\\b(?:id|Id|ID)(s)?\\b/g,\n replace: (_m, plural: string) => `I D${plural ? 's' : ''}`,\n },\n // Byte units (\"165KB\", \"2 MB\") → spelled out (case-insensitive).\n {\n name: 'byte-unit',\n pattern: /\\b(\\d+)\\s?(kb|mb|gb|tb)\\b/gi,\n replace: (_m, n: string, u: string) => `${n} ${UNIT_WORDS[u.toLowerCase()]}`,\n },\n // Time units (\"500ms\", \"5s\") → spelled out. Guard against 4-digit years for \"s\".\n { name: 'ms-unit', pattern: /\\b(\\d{1,5})\\s?ms\\b/g, replace: (_m, n: string) => `${n} ${UNIT_WORDS.ms}` },\n { name: 's-unit', pattern: /\\b(\\d{1,3})\\s?s\\b/g, replace: (_m, n: string) => `${n} ${UNIT_WORDS.s}` },\n // Heteronym \"live\": the engine defaults to the verb /lɪv/ (\"I want to live\"),\n // but in deployment chatter it's the adjective /laɪv/ (\"the version is live\").\n // Respell → \"lyve\" ONLY after a high-confidence adjective cue, so the verb is\n // never touched. NOTE: heteronym sense can't be fully disambiguated by regex —\n // this deliberately covers only the predicate/\"go live\" phrasings agents use.\n {\n name: 'live-adjective',\n pattern:\n /\\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,\n replace: (_m, cue: string) => `${cue} lyve`,\n },\n // Interior dot — any dot glued directly to a following alphanumeric (\"branch.landed\",\n // \"router.ts\", \"Node.js\") → \" dot \". Runs LAST: real sentence-ending dots (followed by\n // a space or end-of-string) are untouched, and versions/decimals were already consumed.\n { name: 'interior-dot', pattern: /\\.(?=[A-Za-z0-9])/g, replace: ' dot ' },\n]\n\n/**\n * Apply the inline normalization rules in order. Pure and idempotent enough to\n * feed straight into either the Kokoro engine or the browser Web Speech API.\n */\nexport function normalizeForSpeech(text: string): string {\n if (!text) return ''\n let out = text\n for (const rule of SPEECH_RULES) {\n out = out.replace(rule.pattern, rule.replace as string)\n }\n // Tidy any double spaces the rules introduced.\n return out.replace(/[ \\t]{2,}/g, ' ').trim()\n}\n\n/** Full pipeline: markdown → prose → normalized speech text. */\nexport function prepareForSpeech(markdown: string): string {\n return normalizeForSpeech(speechify(markdown))\n}\n","import { apiPostAudio, apiPostJsonForBlob } from './api'\nimport { prepareForSpeech } from 'agent-relay-sdk/speech-text'\n\n/**\n * Browser voice I/O for chat.\n *\n * TTS (output) is 100% browser-native via the Web Speech API — the store\n * already receives every agent response turn, so there is no backend round-trip.\n * STT (input) records the mic and posts the clip to the voice connector's\n * whisper endpoint through the relay proxy (single-origin, auth-gated).\n *\n * Speaker policy (\"active chat owns the speaker\"):\n * - One utterance at a time. Disabled => silent.\n * - Only the active chat speaks, and only responses that arrive while it is\n * active (no backlog replay).\n * - Switching away lets the current utterance finish but drops the now-background\n * chat's queued + future responses.\n * - The active chat preempts: if it speaks while a previous chat's audio lingers,\n * that audio is cancelled.\n */\n\n// --- text → speech sanitation -------------------------------------------------\n// The markdown-collapsing + normalization rules live once in the SDK\n// (agent-relay-sdk/speech-text), shared with the voice connector. Re-exported so\n// existing imports (and tests) keep resolving against this module.\nexport { speechify, normalizeForSpeech, prepareForSpeech } from 'agent-relay-sdk/speech-text'\n\n// Curated Kokoro voices (af/am = US female/male, bf/bm = British). Full set is\n// 28; these are the most natural for all-day listening. Shared by the Settings\n// voice picker (and any other UI) — declare once here, never re-list.\nexport const KOKORO_VOICES: { id: string; label: string }[] = [\n { id: 'am_michael', label: 'Michael (US ♂)' },\n { id: 'am_adam', label: 'Adam (US ♂)' },\n { id: 'af_heart', label: 'Heart (US ♀)' },\n { id: 'af_bella', label: 'Bella (US ♀)' },\n { id: 'af_nicole', label: 'Nicole (US ♀)' },\n { id: 'af_sarah', label: 'Sarah (US ♀)' },\n { id: 'bm_george', label: 'George (UK ♂)' },\n { id: 'bf_emma', label: 'Emma (UK ♀)' },\n]\n\nconst MAX_CHUNK = 220\n\n/** Split into utterance-sized chunks (sentence boundaries; hard-split very long runs). */\nfunction chunkForSpeech(text: string): string[] {\n const sentences = text.match(/[^.!?]+[.!?]*\\s*/g)?.map((s) => s.trim()).filter(Boolean) ?? [text]\n const out: string[] = []\n for (const s of sentences) {\n if (s.length <= MAX_CHUNK) { out.push(s); continue }\n let rest = s\n while (rest.length > MAX_CHUNK) {\n let cut = rest.lastIndexOf(' ', MAX_CHUNK)\n if (cut <= 0) cut = MAX_CHUNK\n out.push(rest.slice(0, cut).trim())\n rest = rest.slice(cut).trim()\n }\n if (rest) out.push(rest)\n }\n return out\n}\n\n// --- TTS controller -----------------------------------------------------------\n\nconst synthAvailable = typeof window !== 'undefined' && 'speechSynthesis' in window\n\nclass VoiceTts {\n private enabled = false\n // BCP-47 tag for the spoken voice. Defaults to English rather than the browser\n // UI locale: agent responses are overwhelmingly English, and keying off\n // navigator.language made a Swedish-locale browser read English text in a Swedish\n // voice. Empty string = follow the browser locale (opt-in to the old behavior).\n private lang = 'en-US'\n // 'kokoro' = high-quality server TTS (M1) with automatic browser fallback;\n // 'browser' = Web Speech API only. Kokoro is preferred for all-day listening.\n private mode: 'kokoro' | 'browser' = 'kokoro'\n private kokoroVoice = 'am_michael'\n // Selected browser voice by voiceURI. Empty = let the engine pick the default\n // voice for `lang`. A chosen voice carries its own locale, so it overrides lang.\n private browserVoice = ''\n private active: string | null = null\n private queue: { chatId: string; text: string }[] = []\n private currentChat: string | null = null\n private speaking = false\n private gen = 0\n private audioEl: HTMLAudioElement | null = null\n private audioUrl: string | null = null\n // Manual (play-button) playback bypasses the active-chat gate. `playingKey` is\n // the id of the bubble being played on demand, surfaced to the UI so it can\n // mark the active bubble; null when nothing manual is playing.\n private playingKey: string | null = null\n private manual = false\n private listeners = new Set<() => void>()\n\n // Available when either the browser engine or the server path can speak.\n get available() { return synthAvailable || typeof Audio !== 'undefined' }\n isEnabled() { return this.enabled }\n\n /** Subscribe to manual-playback changes (useSyncExternalStore). */\n subscribe(fn: () => void): () => void {\n this.listeners.add(fn)\n return () => { this.listeners.delete(fn) }\n }\n\n /** Id of the bubble currently played on demand, or null. */\n getPlayingKey(): string | null { return this.playingKey }\n\n private setPlayingKey(key: string | null): void {\n if (key === this.playingKey) return\n this.playingKey = key\n for (const fn of this.listeners) fn()\n }\n\n setEnabled(on: boolean): void {\n if (on === this.enabled) return\n this.enabled = on\n if (!on) this.reset()\n }\n\n /** Set the spoken-voice language (BCP-47, e.g. \"en-US\"). Empty = browser locale. */\n setLang(lang: string): void {\n this.lang = lang\n }\n\n setMode(mode: 'kokoro' | 'browser'): void {\n if (mode === this.mode) return\n this.mode = mode\n this.reset()\n }\n\n setKokoroVoice(voice: string): void {\n this.kokoroVoice = voice\n }\n\n /** Set the browser engine's voice by voiceURI. Empty = default for the language. */\n setBrowserVoice(uri: string): void {\n this.browserVoice = uri\n }\n\n setActiveChat(chatId: string | null): void {\n if (chatId === this.active) return\n this.active = chatId\n // Drop queued items that don't belong to the new active chat; the utterance\n // currently playing is allowed to finish.\n this.queue = this.queue.filter((q) => q.chatId === chatId)\n }\n\n /** A captured agent response turn arrived for `chatId`. */\n onResponse(chatId: string, rawText: string): void {\n if (!this.enabled || !this.available || !chatId || chatId !== this.active) return\n const text = prepareForSpeech(rawText)\n if (!text) return\n // An incoming auto response preempts lingering audio from a different chat or\n // any on-demand (manual) playback in progress.\n if (this.speaking && (this.manual || (this.currentChat && this.currentChat !== chatId))) {\n this.queue = []\n this.cancel()\n }\n this.queue.push({ chatId, text })\n this.pump()\n }\n\n /**\n * Play an arbitrary response on demand (chat-bubble play button), independent\n * of which chat is active. Preempts whatever is currently playing.\n */\n speak(rawText: string, key?: string): void {\n if (!this.available) return\n const text = prepareForSpeech(rawText)\n if (!text) return\n this.reset()\n this.manual = true\n this.speaking = true\n this.currentChat = null\n this.setPlayingKey(key ?? null)\n const gen = ++this.gen\n const chunks = chunkForSpeech(text)\n const done = (): void => {\n if (gen !== this.gen) return\n this.speaking = false\n this.manual = false\n this.setPlayingKey(null)\n }\n if (this.mode === 'kokoro') this.speakKokoro(chunks, 0, gen, done)\n else this.speakBrowser(chunks, 0, gen, done)\n }\n\n /** Cut all speech immediately (e.g. when the user starts talking). */\n bargeIn(): void { this.reset() }\n\n private reset(): void {\n this.queue = []\n this.cancel()\n }\n\n private cancel(): void {\n this.gen++\n this.currentChat = null\n this.speaking = false\n this.manual = false\n this.setPlayingKey(null)\n try { window.speechSynthesis.cancel() } catch { /* ignore */ }\n this.stopAudio()\n }\n\n private stopAudio(): void {\n if (this.audioEl) { try { this.audioEl.pause(); this.audioEl.src = '' } catch { /* */ } }\n if (this.audioUrl) { try { URL.revokeObjectURL(this.audioUrl) } catch { /* */ } this.audioUrl = null }\n }\n\n private pump(): void {\n if (this.speaking) return\n const item = this.queue.shift()\n if (!item) return\n this.speaking = true\n this.manual = false\n this.currentChat = item.chatId\n const gen = ++this.gen\n const chunks = chunkForSpeech(item.text)\n const done = (): void => {\n if (gen !== this.gen) return\n this.speaking = false\n this.currentChat = null\n this.pump()\n }\n if (this.mode === 'kokoro') this.speakKokoro(chunks, 0, gen, done)\n else this.speakBrowser(chunks, 0, gen, done)\n }\n\n // Web Speech API: one utterance per chunk, sequential.\n private speakBrowser(chunks: string[], i: number, gen: number, done: () => void): void {\n if (gen !== this.gen) return\n if (!synthAvailable || i >= chunks.length) return done()\n const u = new SpeechSynthesisUtterance(chunks[i])\n const picked = this.browserVoice ? window.speechSynthesis.getVoices().find((v) => v.voiceURI === this.browserVoice) : undefined\n if (picked) { u.voice = picked; u.lang = picked.lang } else { u.lang = this.lang || navigator.language || 'en-US' }\n u.onend = () => this.speakBrowser(chunks, i + 1, gen, done)\n u.onerror = () => this.speakBrowser(chunks, i + 1, gen, done)\n window.speechSynthesis.speak(u)\n }\n\n // Server (Kokoro) TTS: fetch each chunk's audio, play it, and prefetch the\n // next chunk while the current one plays so playback stays continuous. Any\n // fetch/playback failure falls back to the browser engine for the rest.\n private speakKokoro(chunks: string[], i: number, gen: number, done: () => void, prefetched?: Promise<Blob>): void {\n if (gen !== this.gen) return\n const text = chunks[i]\n if (text === undefined) return done()\n const cur = prefetched ?? this.fetchSpeech(text)\n const nextText = chunks[i + 1]\n const next = nextText !== undefined ? this.fetchSpeech(nextText) : undefined\n cur.then((blob) => {\n if (gen !== this.gen) return\n this.playBlob(blob, gen, () => this.speakKokoro(chunks, i + 1, gen, done, next), () => {\n // playback failed → browser fallback for the remainder\n this.speakBrowser(chunks, i, gen, done)\n })\n }).catch(() => {\n if (gen !== this.gen) return\n // server unreachable / errored → browser fallback for the remainder\n this.speakBrowser(chunks, i, gen, done)\n })\n }\n\n private fetchSpeech(text: string): Promise<Blob> {\n return apiPostJsonForBlob('/connectors/voice/call/speak', { text, voice: this.kokoroVoice })\n }\n\n private playBlob(blob: Blob, gen: number, onend: () => void, onerror: () => void): void {\n if (gen !== this.gen) return\n if (typeof Audio === 'undefined') return onerror()\n this.stopAudio()\n if (!this.audioEl) this.audioEl = new Audio()\n const url = URL.createObjectURL(blob)\n this.audioUrl = url\n const el = this.audioEl\n el.src = url\n el.onended = () => { if (gen === this.gen) onend() }\n el.onerror = () => { if (gen === this.gen) onerror() }\n el.play().catch(() => { if (gen === this.gen) onerror() })\n }\n}\n\nexport const voiceTts = new VoiceTts()\n\n/** Sorted unique BCP-47 languages the browser's speech engine can speak. May be empty\n * until the engine finishes loading voices (listen for `voiceschanged` and re-read). */\nfunction availableSpeechLangs(): string[] {\n if (!synthAvailable) return []\n try {\n const langs = new Set(window.speechSynthesis.getVoices().map((v) => v.lang).filter(Boolean))\n return [...langs].sort()\n } catch {\n return []\n }\n}\n\n/** The browser's individual speech voices ({uri, label, lang}), sorted by language\n * then name. May be empty until the engine loads (listen for `voiceschanged`). */\nexport function availableSpeechVoices(): { uri: string; label: string; lang: string }[] {\n if (!synthAvailable) return []\n try {\n return window.speechSynthesis.getVoices()\n .map((v) => ({ uri: v.voiceURI, label: `${v.name} (${v.lang})`, lang: v.lang }))\n .sort((a, b) => a.lang.localeCompare(b.lang) || a.label.localeCompare(b.label))\n } catch {\n return []\n }\n}\n\n// --- STT (push-to-talk) -------------------------------------------------------\n\nexport const micAvailable = typeof navigator !== 'undefined'\n && !!navigator.mediaDevices?.getUserMedia\n && typeof window !== 'undefined' && 'MediaRecorder' in window\n\nfunction pickMimeType(): string | undefined {\n const candidates = ['audio/webm;codecs=opus', 'audio/webm', 'audio/ogg;codecs=opus', 'audio/mp4']\n for (const m of candidates) {\n if (typeof MediaRecorder !== 'undefined' && MediaRecorder.isTypeSupported?.(m)) return m\n }\n return undefined\n}\n\n/** Hold-to-talk mic recorder. start() on press, stop() on release returns the clip. */\nexport class PttRecorder {\n private rec: MediaRecorder | null = null\n private chunks: BlobPart[] = []\n private stream: MediaStream | null = null\n\n async start(): Promise<void> {\n this.stream = await navigator.mediaDevices.getUserMedia({ audio: true })\n this.chunks = []\n const mime = pickMimeType()\n this.rec = new MediaRecorder(this.stream, mime ? { mimeType: mime } : undefined)\n this.rec.ondataavailable = (e) => { if (e.data.size) this.chunks.push(e.data) }\n this.rec.start()\n }\n\n async stop(): Promise<Blob | null> {\n const rec = this.rec\n if (!rec) { this.teardown(); return null }\n const stopped = new Promise<void>((resolve) => { rec.onstop = () => resolve() })\n try { rec.stop() } catch { /* already stopped */ }\n await stopped\n const type = rec.mimeType || 'audio/webm'\n const blob = new Blob(this.chunks, { type })\n this.teardown()\n return blob.size ? blob : null\n }\n\n cancel(): void {\n try { this.rec?.stop() } catch { /* ignore */ }\n this.teardown()\n }\n\n private teardown(): void {\n this.stream?.getTracks().forEach((t) => t.stop())\n this.rec = null\n this.stream = null\n this.chunks = []\n }\n}\n\n/** Send a recorded clip through the relay proxy to the voice connector's whisper STT. */\nexport async function transcribeClip(blob: Blob): Promise<string> {\n const result = await apiPostAudio<{ text?: string }>('/connectors/voice/call/transcribe', blob)\n return (result?.text ?? '').trim()\n}\n","import { create } from 'zustand'\n\n// Dedicated, non-persisted clock store. Kept separate from the main relay store\n// so the 1s tick never re-serializes persisted state to localStorage and never\n// churns selectors that don't actually depend on wall-clock time.\ninterface ClockStore {\n now: number\n _timer: ReturnType<typeof setInterval> | null\n start: () => void\n stop: () => void\n}\n\nexport const useClock = create<ClockStore>((set, get) => ({\n now: Date.now(),\n _timer: null,\n start() {\n if (get()._timer) return\n set({ _timer: setInterval(() => set({ now: Date.now() }), 1000) })\n },\n stop() {\n const timer = get()._timer\n if (timer) {\n clearInterval(timer)\n set({ _timer: null })\n }\n },\n}))\n\n// Live, 1s-granularity clock for relative timestamps (\"2s ago\").\nexport function useNow(): number {\n return useClock((s) => s.now)\n}\n\n// Coarse 30s bucket for expensive recomputations (e.g. staleness-aware sorting)\n// that must react to time passing but don't need per-second precision.\nexport function useNowBucket(bucketMs = 30_000): number {\n return useClock((s) => Math.floor(s.now / bucketMs))\n}\n","import type { SpawnProvider } from \"./types.js\";\n\n/** Valid reasoning-effort levels — runtime tuple is the single source of truth. */\nexport const VALID_EFFORTS = [\"low\", \"medium\", \"high\", \"xhigh\", \"max\"] as const;\nexport type ProviderEffort = (typeof VALID_EFFORTS)[number];\nfunction isProviderEffort(value: unknown): value is ProviderEffort {\n return typeof value === \"string\" && (VALID_EFFORTS as readonly string[]).includes(value);\n}\ntype ProviderCatalogValueSource = \"catalog\" | \"provider\" | \"runtime\" | \"override\";\ntype ProviderCatalogConfidence = \"declared\" | \"verified\" | \"estimated\" | \"unknown\";\n\ninterface ProviderCatalogValue<T> {\n value: T;\n source: ProviderCatalogValueSource;\n confidence: ProviderCatalogConfidence;\n lastUpdatedAt?: number;\n}\n\ninterface ProviderModelLimits {\n contextWindowTokens?: ProviderCatalogValue<number>;\n maxOutputTokens?: ProviderCatalogValue<number>;\n}\n\ninterface ProviderModelModalities {\n input: {\n text: boolean;\n image?: boolean;\n audio?: boolean;\n video?: boolean;\n pdf?: boolean;\n };\n output: {\n text: boolean;\n image?: boolean;\n audio?: boolean;\n video?: boolean;\n };\n}\n\ninterface ProviderModelToolCapabilities {\n code?: boolean;\n review?: boolean;\n debug?: boolean;\n refactor?: boolean;\n shell?: boolean;\n fileRead?: boolean;\n fileWrite?: boolean;\n webSearch?: boolean;\n imageGeneration?: boolean;\n imageEditing?: boolean;\n}\n\ninterface ProviderModelCapabilities {\n modalities: ProviderModelModalities;\n tools?: ProviderModelToolCapabilities;\n source: ProviderCatalogValueSource;\n confidence: ProviderCatalogConfidence;\n lastUpdatedAt?: number;\n}\n\nexport interface ProviderModelCatalogEntry {\n alias: string;\n label: string;\n providerModel: string;\n efforts: ProviderEffort[];\n defaultEffort?: ProviderEffort;\n limits?: ProviderModelLimits;\n capabilities?: ProviderModelCapabilities;\n}\n\nexport interface ProviderCatalogEntry {\n provider: SpawnProvider;\n label: string;\n defaultModel?: string;\n models: ProviderModelCatalogEntry[];\n}\n\ninterface ProviderSelection {\n provider: SpawnProvider;\n model?: string;\n effort?: ProviderEffort;\n}\n\ninterface ResolvedProviderSelection {\n provider: SpawnProvider;\n modelAlias?: string;\n providerModel?: string;\n effort?: ProviderEffort;\n model?: ProviderModelCatalogEntry;\n}\n\nconst CLAUDE_LOW_TO_MAX: ProviderEffort[] = [\"low\", \"medium\", \"high\", \"max\"];\nconst CLAUDE_LOW_TO_XHIGH_MAX: ProviderEffort[] = [\"low\", \"medium\", \"high\", \"xhigh\", \"max\"];\nconst CODEX_REASONING: ProviderEffort[] = [\"low\", \"medium\", \"high\", \"xhigh\"];\nconst CONTEXT_200K: ProviderCatalogValue<number> = { value: 200_000, source: \"catalog\", confidence: \"declared\" };\nconst CONTEXT_1M: ProviderCatalogValue<number> = { value: 1_000_000, source: \"catalog\", confidence: \"declared\" };\nconst CODE_MODEL_CAPABILITIES: ProviderModelCapabilities = {\n modalities: {\n input: { text: true, image: true },\n output: { text: true },\n },\n tools: {\n code: true,\n review: true,\n debug: true,\n refactor: true,\n },\n source: \"catalog\",\n confidence: \"declared\",\n};\n\nfunction codeModel(limits?: ProviderModelLimits): Pick<ProviderModelCatalogEntry, \"limits\" | \"capabilities\"> {\n return {\n ...(limits ? { limits } : {}),\n capabilities: CODE_MODEL_CAPABILITIES,\n };\n}\n\nexport const PROVIDER_CATALOG: Record<SpawnProvider, ProviderCatalogEntry> = {\n claude: {\n provider: \"claude\",\n label: \"Claude Code\",\n defaultModel: \"sonnet-4.6\",\n models: [\n // Fable 5 has a native 1M context window (no 200K default), so there is no [1m] variant to opt into.\n { alias: \"fable-5\", label: \"Fable 5\", providerModel: \"claude-fable-5\", efforts: CLAUDE_LOW_TO_XHIGH_MAX, defaultEffort: \"medium\", ...codeModel({ contextWindowTokens: CONTEXT_1M }) },\n { alias: \"opus-4.8\", label: \"Opus 4.8\", providerModel: \"claude-opus-4-8\", efforts: CLAUDE_LOW_TO_XHIGH_MAX, defaultEffort: \"medium\", ...codeModel({ contextWindowTokens: CONTEXT_200K }) },\n { alias: \"opus-4.8[1m]\", label: \"Opus 4.8 1M\", providerModel: \"claude-opus-4-8[1m]\", efforts: CLAUDE_LOW_TO_XHIGH_MAX, defaultEffort: \"medium\", ...codeModel({ contextWindowTokens: CONTEXT_1M }) },\n { alias: \"opus-4.7\", label: \"Opus 4.7\", providerModel: \"claude-opus-4-7\", efforts: CLAUDE_LOW_TO_XHIGH_MAX, defaultEffort: \"medium\", ...codeModel({ contextWindowTokens: CONTEXT_200K }) },\n { alias: \"opus-4.7[1m]\", label: \"Opus 4.7 1M\", providerModel: \"claude-opus-4-7[1m]\", efforts: CLAUDE_LOW_TO_XHIGH_MAX, defaultEffort: \"medium\", ...codeModel({ contextWindowTokens: CONTEXT_1M }) },\n { alias: \"opus-4.6\", label: \"Opus 4.6\", providerModel: \"claude-opus-4-6\", efforts: CLAUDE_LOW_TO_MAX, defaultEffort: \"medium\", ...codeModel({ contextWindowTokens: CONTEXT_200K }) },\n { alias: \"opus-4.6[1m]\", label: \"Opus 4.6 1M\", providerModel: \"claude-opus-4-6[1m]\", efforts: CLAUDE_LOW_TO_MAX, defaultEffort: \"medium\", ...codeModel({ contextWindowTokens: CONTEXT_1M }) },\n { alias: \"sonnet-4.6\", label: \"Sonnet 4.6\", providerModel: \"claude-sonnet-4-6\", efforts: CLAUDE_LOW_TO_MAX, defaultEffort: \"medium\", ...codeModel({ contextWindowTokens: CONTEXT_200K }) },\n { alias: \"sonnet-4.6[1m]\", label: \"Sonnet 4.6 1M\", providerModel: \"claude-sonnet-4-6[1m]\", efforts: CLAUDE_LOW_TO_MAX, defaultEffort: \"medium\", ...codeModel({ contextWindowTokens: CONTEXT_1M }) },\n { alias: \"haiku\", label: \"Haiku\", providerModel: \"haiku\", efforts: [], ...codeModel() },\n ],\n },\n codex: {\n provider: \"codex\",\n label: \"Codex\",\n defaultModel: \"gpt-5.5\",\n models: [\n { alias: \"gpt-5.5\", label: \"GPT-5.5\", providerModel: \"gpt-5.5\", efforts: CODEX_REASONING, defaultEffort: \"medium\", ...codeModel({ contextWindowTokens: CONTEXT_200K }) },\n { alias: \"gpt-5.4\", label: \"GPT-5.4\", providerModel: \"gpt-5.4\", efforts: CODEX_REASONING, defaultEffort: \"medium\", ...codeModel({ contextWindowTokens: CONTEXT_200K }) },\n { alias: \"gpt-5.4-mini\", label: \"GPT-5.4 Mini\", providerModel: \"gpt-5.4-mini\", efforts: CODEX_REASONING, defaultEffort: \"medium\", ...codeModel({ contextWindowTokens: CONTEXT_200K }) },\n { alias: \"gpt-5.3-codex\", label: \"GPT-5.3 Codex\", providerModel: \"gpt-5.3-codex\", efforts: CODEX_REASONING, defaultEffort: \"medium\", ...codeModel({ contextWindowTokens: CONTEXT_200K }) },\n { alias: \"gpt-5.3-codex-spark\", label: \"GPT-5.3 Codex Spark\", providerModel: \"gpt-5.3-codex-spark\", efforts: CODEX_REASONING, defaultEffort: \"high\", ...codeModel({ contextWindowTokens: CONTEXT_200K }) },\n { alias: \"gpt-5.2\", label: \"GPT-5.2\", providerModel: \"gpt-5.2\", efforts: CODEX_REASONING, defaultEffort: \"medium\", ...codeModel({ contextWindowTokens: CONTEXT_200K }) },\n ],\n },\n};\n\nexport function providerCatalogList(): ProviderCatalogEntry[] {\n return Object.values(PROVIDER_CATALOG);\n}\n\nexport function getProviderCatalog(provider: SpawnProvider): ProviderCatalogEntry {\n return PROVIDER_CATALOG[provider];\n}\n\nfunction findModel(catalog: ProviderCatalogEntry, input: string): ProviderModelCatalogEntry | undefined {\n const lower = input.toLowerCase();\n return catalog.models.find((e) => e.alias === input)\n ?? catalog.models.find((e) => e.providerModel === input)\n ?? catalog.models.find((e) => e.alias.toLowerCase() === lower || e.providerModel.toLowerCase() === lower)\n ?? catalog.models.find((e) => e.alias.startsWith(input + \"-\"));\n}\n\nexport function resolveProviderSelection(selection: ProviderSelection): ResolvedProviderSelection {\n const catalog = getProviderCatalog(selection.provider);\n const alias = selection.model || catalog.defaultModel;\n const model = alias ? findModel(catalog, alias) : undefined;\n if (alias && !model) {\n const known = catalog.models.map((e) => e.alias).join(\", \");\n throw new Error(`unknown ${selection.provider} model: ${alias} (available: ${known})`);\n }\n if (selection.effort && !model) {\n throw new Error(`effort requires a ${selection.provider} model`);\n }\n if (selection.effort && model && !model.efforts.includes(selection.effort)) {\n throw new Error(`${selection.provider} model ${model.alias} does not support effort ${selection.effort}`);\n }\n return {\n provider: selection.provider,\n modelAlias: model?.alias,\n providerModel: model?.providerModel,\n effort: selection.effort,\n model,\n };\n}\n","// Provider/orchestrator selection helpers shared by the spawn, managed and\n// connection (file-open) slices.\nimport { PROVIDER_CATALOG } from 'agent-relay-sdk/provider-catalog'\nimport type { Agent, Orchestrator, SpawnProvider } from '@/types'\nimport { normalizePathForCompare, pathWithinBase } from '@/lib/display'\n\nexport interface ConfigEntry<T> {\n value: T\n}\n\nexport function firstAvailableProvider(orchestrator: Orchestrator | undefined): SpawnProvider {\n return orchestrator?.providers[0] ?? 'claude'\n}\n\nexport function defaultModelFor(provider: string): string {\n return PROVIDER_CATALOG[provider as SpawnProvider]?.defaultModel ?? ''\n}\n\nexport function orchestratorForPath(orchestrators: Orchestrator[], path: string): Orchestrator | undefined {\n return orchestrators\n .filter((orch) => orch.status === 'online' && pathWithinBase(path, orch.baseDir))\n .sort((a, b) => normalizePathForCompare(b.baseDir).length - normalizePathForCompare(a.baseDir).length)[0]\n}\n\nexport function orchestratorForAgent(orchestrators: Orchestrator[], agent: Agent): Orchestrator | undefined {\n const managed = orchestrators.find((orch) => orch.managedAgents.some((managedAgent) => managedAgent.agentId === agent.id))\n if (managed) return managed\n const cwd = typeof agent.meta?.cwd === 'string' ? agent.meta.cwd : ''\n return cwd ? orchestratorForPath(orchestrators, cwd) : undefined\n}\n","// Correctness-sensitive pure helpers shared across slices. These are the ONE\n// home for poll-merge identity preservation, the active-visible-chat predicate,\n// and the compact/clear status derivation — keeping a single implementation is\n// the whole point (per-slice copies would silently drift, issue #292).\nimport type { Agent, Message, RelayNotification } from '@/types'\nimport { HUMAN_AGENT_ID } from '@/lib/constants'\nimport { isBadgeWorthy } from '@/lib/display'\nimport type { ChatStatusEvent, RelayStore, TimelineCommand } from './types'\n\nexport function indexAgents(agents: Agent[]): Record<string, Agent> {\n const byId: Record<string, Agent> = {}\n for (const agent of agents) byId[agent.id] = agent\n return byId\n}\n\nexport function upsertById<T extends { id: string | number }>(list: T[], item: T): T[] {\n const idx = list.findIndex((e) => e.id === item.id)\n const next = [...list]\n if (idx >= 0) next[idx] = item\n else next.push(item)\n return next\n}\n\nconst CHAT_STATUS_DEDUPE_WINDOW_MS = 3000\n\nexport function appendChatStatusEvent(\n eventsByAgent: Record<string, ChatStatusEvent[]>,\n agentId: string | undefined,\n status: string | undefined,\n timestamp = Date.now(),\n id?: string,\n): Record<string, ChatStatusEvent[]> {\n if (!agentId || !status) return eventsByAgent\n const evts = [...(eventsByAgent[agentId] || [])]\n const eventId = id || `s-${status}-${timestamp}`\n if (evts.some((event) => event.id === eventId)) return eventsByAgent\n if (evts.some((event) => event.status === status && Math.abs(event.timestamp - timestamp) <= CHAT_STATUS_DEDUPE_WINDOW_MS)) return eventsByAgent\n evts.push({ id: eventId, status, timestamp })\n if (evts.length > 200) evts.splice(0, evts.length - 200)\n return { ...eventsByAgent, [agentId]: evts }\n}\n\nexport function statusTimelineEvent(prev: Agent | undefined, next: Agent): string | undefined {\n if (!prev || prev.status === next.status) return undefined\n const cameOnline = (prev.status === 'offline' || prev.status === 'stale') && (next.status === 'online' || next.status === 'idle' || next.status === 'busy')\n if (cameOnline) return 'online'\n if (next.status === 'offline') return 'offline'\n return undefined\n}\n\n// Real provider-hook statuses that prove a compact/clear actually began — any\n// of these retracts a pending stall warning for that agent.\nexport const COMMAND_STALL_CLEAR_STATUSES = new Set(['compacting', 'compacted', 'clearing-context', 'context-cleared'])\n\nexport function agentTimelineEvent(agent: Agent): { status: string; id?: string; timestamp?: number } | undefined {\n const event = agent.meta?.timelineEvent\n if (!event || typeof event !== 'object' || Array.isArray(event)) return undefined\n const status = (event as Record<string, unknown>).status\n if (typeof status !== 'string' || !status) return undefined\n const id = (event as Record<string, unknown>).id\n const timestamp = (event as Record<string, unknown>).timestamp\n return {\n status,\n ...(typeof id === 'string' ? { id } : {}),\n ...(typeof timestamp === 'number' && Number.isFinite(timestamp) ? { timestamp } : {}),\n }\n}\n\nexport function commandAgentId(command: TimelineCommand): string | undefined {\n const paramAgentId = command.params?.agentId\n if (typeof paramAgentId === 'string' && paramAgentId) return paramAgentId\n return typeof command.target === 'string' && command.target ? command.target : undefined\n}\n\nexport function commandTimelineStatus(command: TimelineCommand, event: string): string | undefined {\n if (event === 'command.dispatched') {\n // \"We asked\" — not \"it happened\". The honest started/finished states for\n // compact/clear come from the real provider hooks (PreCompact, SessionStart)\n // via the agent's timelineEvent, not from the command lifecycle.\n if (command.type === 'agent.compact') return 'compaction-requested'\n if (command.type === 'agent.clearContext') return 'clear-requested'\n if (command.type === 'agent.shutdown') return 'shutting-down'\n return undefined\n }\n if (event === 'command.succeeded') {\n // compact/clear \"succeeded\" only means keystrokes were delivered into the\n // tmux session — say nothing here and let the hooks report the real result.\n if (command.type === 'agent.shutdown') return 'shutdown'\n if (command.type === 'agent.restart') return 'restarted'\n }\n return undefined\n}\n\nfunction messageFingerprint(message: Message): string {\n return JSON.stringify(message)\n}\n\nexport function mergeFetchedMessages(current: Message[], incoming: Message[]): Message[] {\n const byId = new Map(current.map((message) => [message.id, message]))\n const sameOrder = current.length === incoming.length && current.every((message, index) => message.id === incoming[index]?.id)\n let changed = !sameOrder\n const next = incoming.map((message) => {\n const existing = byId.get(message.id)\n if (existing && messageFingerprint(existing) === messageFingerprint(message)) return existing\n changed = true\n return message\n })\n return changed ? next : current\n}\n\n// Identity-preserving merge for polled lists: when a poll returns data that is\n// byte-identical to what we hold, return the SAME array reference so selectors\n// subscribed to it don't recompute. Reuses per-item refs that are unchanged.\nexport function mergeListById<T extends { id: string | number }>(current: T[], incoming: T[]): T[] {\n const dedupedIncoming = [...new Map(incoming.map((item) => [item.id, item])).values()]\n const byId = new Map(current.map((item) => [item.id, item]))\n const sameOrder = current.length === dedupedIncoming.length && current.every((item, index) => item.id === dedupedIncoming[index]?.id)\n let changed = !sameOrder\n const next = dedupedIncoming.map((item) => {\n const existing = byId.get(item.id)\n if (existing && JSON.stringify(existing) === JSON.stringify(item)) return existing\n changed = true\n return item\n })\n return changed ? next : current\n}\n\nexport function isDashboardHidden(): boolean {\n return typeof document === 'undefined' ? true : document.hidden\n}\n\n// True when `peer`'s thread is the one the user is actively looking at: on the\n// chat view, selected, and the tab visible. Incoming messages for such a thread\n// should never raise an unread badge — they are read on arrival.\nexport function isActiveVisibleChat(peer: string, state: RelayStore): boolean {\n return Boolean(peer && state.view === 'chat' && state.selectedInboxThread === peer && !isDashboardHidden())\n}\n\nexport function notificationPeer(notification: RelayNotification): string {\n return notification.threadPeer || notification.agentId || ''\n}\n\nexport function notificationTargetsActiveChat(notification: RelayNotification, state: RelayStore): boolean {\n return isActiveVisibleChat(notificationPeer(notification), state)\n}\n\nexport function lastInboundMessageId(messages: Message[]): number {\n return messages\n .filter((m) => m.to === HUMAN_AGENT_ID && m.from !== HUMAN_AGENT_ID && isBadgeWorthy(m))\n .reduce((max, m) => Math.max(max, m.id), 0)\n}\n","import type { RelayNotification, NotificationSettings, ViewName } from '@/types'\nimport { isDashboardHidden, notificationTargetsActiveChat } from '../merge'\nimport type { NotificationsSlice, RelayStore, StoreSlice } from '../types'\n\nconst DEFAULT_NOTIFICATION_SETTINGS: NotificationSettings = {\n enabled: true,\n browserEnabled: false,\n messages: true,\n replies: true,\n errors: true,\n}\n\nfunction notificationCategoryEnabled(notification: RelayNotification, settings: NotificationSettings): boolean {\n if (!settings.enabled) return false\n if (notification.kind === 'message') return settings.messages\n if (notification.kind === 'reply') return settings.replies\n return settings.errors\n}\n\nfunction browserNotificationsSupported(): boolean {\n return typeof window !== 'undefined' && 'Notification' in window\n}\n\nexport function browserNotificationPermission(): NotificationPermission | 'unsupported' {\n if (!browserNotificationsSupported()) return 'unsupported'\n return window.Notification.permission\n}\n\nfunction shouldShowBrowserNotification(notification: RelayNotification, state: RelayStore): boolean {\n if (!notificationCategoryEnabled(notification, state.notificationSettings)) return false\n if (!state.notificationSettings.browserEnabled) return false\n if (browserNotificationPermission() !== 'granted') return false\n if (notificationTargetsActiveChat(notification, state)) return false\n return isDashboardHidden() || state.view !== 'chat'\n}\n\nfunction showBrowserNotification(notification: RelayNotification, onClick: () => void | Promise<void>) {\n if (browserNotificationPermission() !== 'granted') return\n try {\n const n = new window.Notification(notification.title, {\n body: notification.body,\n tag: notification.id,\n icon: 'icons/agent-relay-192.png',\n data: {\n view: notification.view,\n threadPeer: notification.threadPeer,\n agentId: notification.agentId,\n messageId: notification.messageId,\n },\n })\n n.onclick = () => {\n window.focus()\n void onClick()\n n.close()\n }\n } catch {}\n}\n\nexport const createNotificationsSlice: StoreSlice<NotificationsSlice> = (set, get) => ({\n notification: null,\n toastNotification: null,\n notifications: [],\n notificationUnread: 0,\n notificationSettings: { ...DEFAULT_NOTIFICATION_SETTINGS },\n notificationPermission: browserNotificationPermission(),\n confirmModal: { show: false, title: '', message: '', action: null },\n errorModal: { show: false, title: '', message: '' },\n\n openConfirm(title, message, action) { set({ confirmModal: { show: true, title, message, action } }) },\n showError(title, message) { set({ errorModal: { show: true, title, message } }) },\n showNotification(message) {\n // Plain status toast — not actionable, so clear any pending actionable one.\n set({ notification: message, toastNotification: null })\n setTimeout(() => set({ notification: null }), 3000)\n },\n handleRelayNotification(relayNotification) {\n const s = get()\n if (!notificationCategoryEnabled(relayNotification, s.notificationSettings)) return\n if (s.notifications.some((item) => item.id === relayNotification.id)) return\n const activeChatNotification = notificationTargetsActiveChat(relayNotification, s)\n const toast = `${relayNotification.title}: ${relayNotification.body}`\n const notifications = [relayNotification, ...s.notifications].slice(0, 100)\n set({\n notifications,\n notificationUnread: activeChatNotification ? s.notificationUnread : Math.min(99, s.notificationUnread + 1),\n notification: activeChatNotification ? s.notification : toast,\n // Keep the actionable notification so the in-app toast can route to it on tap.\n toastNotification: activeChatNotification ? s.toastNotification : relayNotification,\n })\n if (!activeChatNotification) {\n setTimeout(() => {\n if (get().toastNotification?.id === relayNotification.id) set({ notification: null, toastNotification: null })\n }, 4500)\n }\n if (shouldShowBrowserNotification(relayNotification, s)) {\n showBrowserNotification(relayNotification, () => get().openNotification(relayNotification))\n }\n if (activeChatNotification && relayNotification.threadPeer && relayNotification.messageId) {\n get().markInboxThreadReadTo(relayNotification.threadPeer, relayNotification.messageId)\n }\n },\n async openNotification(relayNotification) {\n set({ notificationUnread: 0 })\n if (relayNotification.threadPeer) {\n get().openInboxThread(relayNotification.threadPeer)\n if (relayNotification.messageId) get().markInboxThreadReadTo(relayNotification.threadPeer, relayNotification.messageId)\n }\n if (relayNotification.view) await get().switchView(relayNotification.view as ViewName)\n if (relayNotification.agentId && relayNotification.view === 'agents') {\n const agent = get().agentsById[relayNotification.agentId]\n if (agent) get().openAgentDetail(agent)\n }\n },\n dismissToast() { set({ notification: null, toastNotification: null }) },\n markNotificationsRead() { set({ notificationUnread: 0 }) },\n clearNotifications() { set({ notifications: [], notificationUnread: 0 }) },\n async requestBrowserNotifications() {\n if (!browserNotificationsSupported()) {\n set({ notificationPermission: 'unsupported', notificationSettings: { ...get().notificationSettings, browserEnabled: false } })\n get().showNotification('Browser notifications are not supported here')\n return\n }\n const permission = await window.Notification.requestPermission()\n set({\n notificationPermission: permission,\n notificationSettings: { ...get().notificationSettings, browserEnabled: permission === 'granted' },\n })\n get().showNotification(permission === 'granted' ? 'Browser notifications enabled' : 'Browser notifications not enabled')\n },\n})\n","import { voiceTts } from '@/lib/voice'\nimport type { RelayStore, StoreSlice, VoiceSlice } from '../types'\n\nexport const createVoiceSlice: StoreSlice<VoiceSlice> = (set) => ({\n voiceTtsEnabled: false,\n voiceTtsLang: 'en-US',\n voiceTtsMode: 'kokoro',\n voiceTtsKokoroVoice: 'am_michael',\n voiceTtsBrowserVoice: '',\n voiceInputMode: 'compose',\n\n setVoiceTtsEnabled(on: boolean) {\n // The module-scope subscription syncs the controller's active chat from\n // (view, selectedInboxThread); here we only flip the enabled flag.\n voiceTts.setEnabled(on)\n set({ voiceTtsEnabled: on })\n },\n\n setVoiceTtsLang(lang: string) {\n voiceTts.setLang(lang)\n set({ voiceTtsLang: lang })\n },\n\n setVoiceTtsMode(mode: 'kokoro' | 'browser') {\n voiceTts.setMode(mode)\n set({ voiceTtsMode: mode })\n },\n\n setVoiceTtsKokoroVoice(voice: string) {\n voiceTts.setKokoroVoice(voice)\n set({ voiceTtsKokoroVoice: voice })\n },\n\n setVoiceTtsBrowserVoice(uri: string) {\n voiceTts.setBrowserVoice(uri)\n set({ voiceTtsBrowserVoice: uri })\n },\n\n setVoiceInputMode(mode: 'compose' | 'autosend' | 'handsfree') {\n set({ voiceInputMode: mode })\n },\n})\n\n// Keep the browser TTS controller's \"active chat\" in sync with navigation. This\n// is an external-system subscription (the speechSynthesis engine), not derived\n// React state — so it lives here, driven by the store, not by a component effect.\n// Guarded: it early-returns unless the derived active chat actually changes, so\n// it does NOT fire a side-effect on every poll merge.\nlet _voiceActiveChat: string | null = null\nexport function syncVoiceActiveChat(s: RelayStore): void {\n const active = s.voiceTtsEnabled && s.view === 'chat' ? (s.selectedInboxThread || null) : null\n if (active === _voiceActiveChat) return\n _voiceActiveChat = active\n voiceTts.setActiveChat(active)\n}\n","import { api, setAuthToken, setUnauthorizedHandler, openRelayEventStream } from '@/lib/api'\nimport { setDashboardView } from '@/lib/dashboard-attribution'\nimport { voiceTts } from '@/lib/voice'\nimport { useClock } from '@/store/clock'\nimport { LIVE_REFRESH_MS, MESSAGE_BUFFER_CAP } from '@/lib/constants'\nimport { inboxPeer, isBadgeWorthy, isHumanInboundMessage } from '@/lib/display'\nimport type { Agent, Message, Orchestrator, RelayNotification, ActivityEvent, Stats, Task, ThemeId, ViewName } from '@/types'\nimport { orchestratorForPath, orchestratorForAgent } from '../helpers'\nimport {\n appendChatStatusEvent, agentTimelineEvent, statusTimelineEvent, commandAgentId,\n commandTimelineStatus, COMMAND_STALL_CLEAR_STATUSES, isActiveVisibleChat, upsertById,\n} from '../merge'\nimport type { ConnectionSlice, StoreSlice, TimelineCommand } from '../types'\nimport { browserNotificationPermission } from './notifications'\nimport { syncVoiceActiveChat } from './voice'\nimport { useRelayStore } from '../index'\n\nexport const createConnectionSlice: StoreSlice<ConnectionSlice> = (set, get) => ({\n theme: 'dark' as ThemeId,\n view: 'overview' as ViewName,\n autoRefresh: true,\n mobileMenuOpen: false,\n commandPaletteOpen: false,\n commandQuery: '',\n connected: false,\n connectionError: false,\n authNeeded: false,\n authToken: '',\n stats: {},\n fileOrchestratorId: '',\n filePath: '',\n fileSelectedPath: '',\n fileSelectedLine: 0,\n fileOverlayOpen: false,\n _es: null,\n _refreshTimer: null,\n _refreshInFlight: false,\n\n set: (partial) => set(partial),\n\n async init() {\n const hydrated = useRelayStore.persist.hasHydrated()\n if (!hydrated) await new Promise<void>((resolve) => {\n const unsub = useRelayStore.persist.onFinishHydration(() => { unsub(); resolve() })\n })\n const token = get().authToken\n if (token) setAuthToken(token)\n setDashboardView(get().view)\n // Restore the persisted speaker toggle + language into the TTS controller.\n voiceTts.setEnabled(get().voiceTtsEnabled)\n voiceTts.setLang(get().voiceTtsLang)\n voiceTts.setMode(get().voiceTtsMode)\n voiceTts.setKokoroVoice(get().voiceTtsKokoroVoice)\n voiceTts.setBrowserVoice(get().voiceTtsBrowserVoice)\n syncVoiceActiveChat(get())\n setUnauthorizedHandler(() => { if (!get().authNeeded) set({ authNeeded: true, connectionError: false }) })\n set({ notificationPermission: browserNotificationPermission() })\n get().startClock()\n try {\n const stats = await api<Stats>('GET', '/stats')\n set({ stats })\n } catch (e: unknown) {\n if ((e as { status?: number }).status === 401) { set({ authNeeded: true }); return }\n }\n await get().refresh()\n get().connectSSE()\n get().startAutoRefresh()\n },\n\n async switchView(view: ViewName) {\n setDashboardView(view)\n set({ view, mobileMenuOpen: false })\n const s = get()\n if (['chat', 'messages'].includes(view)) await Promise.all([s.fetchMessages(), s.fetchChatHistoryImports()])\n if (view === 'activity') await Promise.all([s.fetchMessages(), s.fetchPairs(), s.fetchTasks(), s.fetchActivityEvents()])\n if (view === 'work') await Promise.all([s.fetchMessages(), s.fetchTasks()])\n if (view === 'pairs') await s.fetchPairs()\n if (view === 'channels') await s.fetchChannels()\n if (view === 'connectors') await s.fetchConnectors()\n if (view === 'integrations') await s.fetchIntegrations()\n if (view === 'memory') await s.refreshMemory()\n if (view === 'tasks') await s.fetchTasks()\n if (view === 'automation') await Promise.all([s.fetchAutomations(), s.fetchAutomationRuns()])\n if (view === 'maintenance') await s.fetchMaintenanceJobs()\n if (view === 'workspaces') await Promise.all([s.fetchWorkspaces(), s.fetchOrchestrators(), s.fetchAgents()])\n if (view === 'files') await s.fetchOrchestrators()\n if (view === 'analytics') await s.fetchAnalytics()\n },\n\n startClock() {\n useClock.getState().start()\n },\n\n stopClock() {\n useClock.getState().stop()\n },\n\n startAutoRefresh() {\n get().stopAutoRefresh()\n if (!get().autoRefresh) return\n const timer = setInterval(() => get().refreshLiveData(), LIVE_REFRESH_MS)\n set({ _refreshTimer: timer })\n },\n\n stopAutoRefresh() {\n const s = get()\n if (s._refreshTimer) { clearInterval(s._refreshTimer); set({ _refreshTimer: null }) }\n },\n\n async apiCall<T = unknown>(method: string, path: string, body?: unknown): Promise<T> {\n return api<T>(method, path, body)\n },\n\n async openFilesAt(input) {\n const s = get()\n const orchestratorId = input.orchestratorId || orchestratorForPath(s.orchestrators, input.selectedPath || input.path)?.id || s.orchestrators.find((orch) => orch.status === 'online')?.id || ''\n set({\n fileOrchestratorId: orchestratorId,\n filePath: input.path,\n fileSelectedPath: input.selectedPath || '',\n fileSelectedLine: input.line || 0,\n fileOverlayOpen: input.overlay === true,\n })\n if (!input.overlay) await get().switchView('files')\n },\n\n async openFilesForAgent(agent, overlay = false) {\n const cwd = typeof agent.meta?.cwd === 'string' ? agent.meta.cwd : ''\n if (!cwd) {\n get().showNotification('Agent has no cwd')\n return\n }\n const orch = orchestratorForAgent(get().orchestrators, agent)\n if (!orch) {\n get().showNotification('No online orchestrator covers that cwd')\n return\n }\n await get().openFilesAt({ orchestratorId: orch.id, path: cwd, overlay })\n },\n\n closeFileOverlay() {\n set({ fileOverlayOpen: false })\n },\n\n async refresh() {\n const s = get()\n await Promise.all([\n s.fetchStats(), s.fetchHealth(), s.fetchAgents(), s.fetchOrchestrators(),\n s.fetchPairs(), s.fetchMessages(), s.fetchTasks(), s.fetchChannels(),\n s.fetchConnectors(), s.fetchIntegrations(), s.fetchAutomations(), s.fetchAutomationRuns(),\n s.fetchManagedPolicies(), s.fetchAgentProfiles(), s.fetchMaintenanceJobs(), s.fetchWorkspaces(), s.fetchInboxState(), s.fetchActivityEvents(), s.fetchChatHistoryImports(),\n ])\n },\n\n // Periodic reconciliation poll. SSE is the live channel; this is the\n // safety net. Polls only the globally-visible \"core\" data plus whatever\n // the active view shows — not all ~19 endpoints every tick. A cheap\n // /stats canary detects auth/connection state and short-circuits the\n // poll when the relay is unreachable instead of failing silently.\n async refreshLiveData() {\n if (get()._refreshInFlight || get().authNeeded) return\n set({ _refreshInFlight: true })\n try {\n try {\n const stats = await api<Stats>('GET', '/stats')\n set(get().connectionError ? { stats, connectionError: false } : { stats })\n } catch (e) {\n if ((e as { status?: number }).status === 401) return\n if (!get().connectionError) set({ connectionError: true })\n return\n }\n const s = get()\n // Core: drives sidebar badges, attention counts, and SSE reconciliation.\n const work: Array<Promise<void>> = [\n s.fetchHealth(), s.fetchAgents(), s.fetchOrchestrators(),\n s.fetchPairs(), s.fetchMessages(), s.fetchTasks(),\n s.fetchManagedPolicies(), s.fetchInboxState(),\n ]\n // View-scoped: only poll what the open view actually renders.\n const view = s.view\n if (['chat', 'messages'].includes(view)) work.push(s.fetchChatHistoryImports())\n if (view === 'activity') work.push(s.fetchActivityEvents())\n if (view === 'memory') work.push(s.refreshMemory())\n if (view === 'automation') work.push(s.fetchAutomations(), s.fetchAutomationRuns())\n if (view === 'channels') work.push(s.fetchChannels())\n if (view === 'connectors') work.push(s.fetchConnectors())\n if (view === 'integrations') work.push(s.fetchIntegrations())\n if (view === 'maintenance') work.push(s.fetchMaintenanceJobs())\n if (view === 'profiles') work.push(s.fetchAgentProfiles())\n if (view === 'workspaces') work.push(s.fetchWorkspaces())\n if (view === 'analytics') work.push(s.fetchAnalytics())\n await Promise.all(work)\n } finally { set({ _refreshInFlight: false }) }\n },\n\n async fetchStats() { try { set({ stats: await api('GET', '/stats') }) } catch {} },\n\n // --- SSE ---\n connectSSE() {\n get().disconnectSSE()\n const stream = openRelayEventStream(get().authToken, {\n connected: () => {\n set(get().connectionError ? { connected: true, connectionError: false } : { connected: true })\n // Fill any gap from the disconnect window: the server does not replay missed SSE\n // events (no Last-Event-ID), so on every (re)connect pull live state via REST.\n void get().refreshLiveData()\n const loadedAgentIds = Object.entries(get().agentChatByAgent)\n .filter(([, window]) => window.loadedInitial)\n .map(([agentId]) => agentId)\n void Promise.all(loadedAgentIds.map((agentId) => get().gapFillAgentChat(agentId)))\n },\n disconnected: () => set({ connected: false }),\n message: (event, data) => {\n if (event === 'connected') return\n if (event === 'message.new') {\n const msg = JSON.parse(data) as Message\n // TTS trigger runs BEFORE dedup: the 5s fetchMessages poll can win the\n // race against SSE in busy sessions (many reasoning/tool events queued),\n // adding the response to the store first. The dedup then skips the SSE\n // event entirely — including the TTS call. Moving it here ensures TTS\n // fires exactly once (SSE delivers each message once).\n if (msg.kind === 'session' && msg.from !== 'user') {\n const sess = (msg.payload as { session?: { type?: string; origin?: string } } | undefined)?.session\n if (sess?.type === 'response' && sess?.origin === 'provider') {\n voiceTts.onResponse(inboxPeer(msg), msg.body)\n }\n }\n const s = get()\n const globalDuplicate = s.messages.some((m) => m.id === msg.id)\n if (!globalDuplicate) {\n const msgs = [...s.messages, msg]\n if (msgs.length > MESSAGE_BUFFER_CAP) msgs.splice(0, msgs.length - MESSAGE_BUFFER_CAP)\n set({ messages: msgs })\n }\n // If the user is actively viewing this thread, keep it read so no\n // stale unread badge appears while the chat is open and focused.\n const peer = inboxPeer(msg)\n get().appendChatTail(peer, [msg])\n if (isHumanInboundMessage(msg) && isBadgeWorthy(msg) && isActiveVisibleChat(peer, s)) {\n get().markInboxThreadReadTo(peer, msg.id)\n }\n return\n }\n if (event === 'message.queued' || event === 'message.expired' || event === 'message.delivery_updated' || event === 'message.reaction_updated') {\n const msg = JSON.parse(data) as Message\n set({ messages: upsertById(get().messages, msg) })\n return\n }\n if (event === 'notification.created') {\n get().handleRelayNotification(JSON.parse(data) as RelayNotification)\n return\n }\n if (event === 'activity.created') {\n const item = JSON.parse(data) as ActivityEvent\n set({ activityEvents: upsertById(get().activityEvents, item) })\n return\n }\n if (event === 'agent.status') {\n const agent = JSON.parse(data) as Agent\n const s = get()\n const prev = s.agentsById[agent.id]\n set({ agents: upsertById(s.agents, agent), agentsById: { ...s.agentsById, [agent.id]: agent } })\n if (s.livenessMismatches[agent.id] && agent.status !== 'offline') {\n const next = { ...s.livenessMismatches }\n delete next[agent.id]\n set({ livenessMismatches: next })\n }\n // A real provider hook (compacting/compacted/context-cleared) means\n // the command landed after all — retract any stall warning. But\n // timelineEvent is latched, so only a hook fresher than the warning\n // counts; a stale \"compacted\" from a prior compaction must not clear it.\n const stall = s.commandStalls[agent.id]\n if (stall) {\n const te = agentTimelineEvent(agent)\n if (te?.status && COMMAND_STALL_CLEAR_STATUSES.has(te.status) && (te.timestamp ?? 0) > stall.ts) {\n const next = { ...s.commandStalls }\n delete next[agent.id]\n set({ commandStalls: next })\n }\n }\n const timelineEvent = agentTimelineEvent(agent)\n const status = timelineEvent?.status ?? statusTimelineEvent(prev, agent)\n if (status) {\n const timestamp = timelineEvent?.timestamp ?? Date.now()\n const id = timelineEvent?.id || `agent-status:${agent.id}:${status}:${timestamp}`\n set({ chatStatusEvents: appendChatStatusEvent(s.chatStatusEvents, agent.id, status, timestamp, id) })\n }\n return\n }\n if (event === 'liveness.mismatch') {\n const d = JSON.parse(data) as { agentId: string; detail?: string; policyName?: string; spawnRequestId?: string }\n if (d.agentId) {\n set({ livenessMismatches: { ...get().livenessMismatches, [d.agentId]: { agentId: d.agentId, detail: d.detail ?? 'Process reported running but relay marked it offline', ts: Date.now(), policyName: d.policyName, spawnRequestId: d.spawnRequestId } } })\n }\n return\n }\n if (event === 'command.stalled') {\n const d = JSON.parse(data) as { agentId: string; kind?: 'compact' | 'clear'; detail?: string; commandId?: string }\n if (d.agentId) {\n const ts = Date.now()\n const kind = d.kind ?? 'compact'\n const stallStatus = kind === 'clear' ? 'clear-stalled' : 'compaction-stalled'\n set({\n commandStalls: { ...get().commandStalls, [d.agentId]: { agentId: d.agentId, kind, detail: d.detail ?? 'A context command was requested but never started — the session may need manual intervention.', ts, commandId: d.commandId } },\n // Surface it in the chat timeline too, where \"compaction requested\" lives.\n chatStatusEvents: appendChatStatusEvent(get().chatStatusEvents, d.agentId, stallStatus, ts, `command-stalled:${d.agentId}:${d.commandId ?? ts}`),\n })\n }\n return\n }\n if (event === 'agent.removed') {\n const eventData = JSON.parse(data) as { id: string }\n const s = get()\n const byId = { ...s.agentsById }\n delete byId[eventData.id]\n const liveness = { ...s.livenessMismatches }\n delete liveness[eventData.id]\n const stalls = { ...s.commandStalls }\n delete stalls[eventData.id]\n set({ livenessMismatches: liveness, commandStalls: stalls })\n set({ agents: s.agents.filter((a) => a.id !== eventData.id), agentsById: byId })\n return\n }\n if (event === 'message.claimed') {\n const eventData = JSON.parse(data) as { messageId: number; claimedBy: string; claimExpiresAt?: number }\n set({ messages: get().messages.map((m) => m.id === eventData.messageId ? { ...m, claimedBy: eventData.claimedBy, claimExpiresAt: eventData.claimExpiresAt } : m) })\n return\n }\n if (event === 'message.claim_released') {\n const eventData = JSON.parse(data) as { messageId: number }\n set({ messages: get().messages.map((m) => m.id === eventData.messageId ? { ...m, claimedBy: undefined, claimedAt: undefined, claimExpiresAt: undefined } : m) })\n return\n }\n if (event === 'message.deleted') {\n const eventData = JSON.parse(data) as { messageId: number }\n set({ messages: get().messages.filter((m) => m.id !== eventData.messageId) })\n return\n }\n if (event === 'orchestrator.status') {\n const orch = JSON.parse(data) as Orchestrator\n set({ orchestrators: upsertById(get().orchestrators, orch) })\n return\n }\n if (event === 'orchestrator.removed') {\n const eventData = JSON.parse(data) as { id: string }\n set({ orchestrators: get().orchestrators.filter((o) => o.id !== eventData.id) })\n return\n }\n if (event === 'policy.state.changed' || event === 'config.changed') {\n void get().fetchManagedPolicies()\n return\n }\n if (event === 'command.dispatched' || event === 'command.succeeded') {\n const eventData = JSON.parse(data) as { command?: TimelineCommand }\n const command = eventData.command\n if (command) {\n const status = commandTimelineStatus(command, event)\n if (status) {\n const timestamp = typeof command.updatedAt === 'number' ? command.updatedAt : typeof command.createdAt === 'number' ? command.createdAt : Date.now()\n set({ chatStatusEvents: appendChatStatusEvent(get().chatStatusEvents, commandAgentId(command), status, timestamp, command.id ? `command:${command.id}:${status}` : undefined) })\n }\n }\n return\n }\n if (['task.created', 'task.updated', 'task.claimed', 'task.status'].includes(event)) {\n const task = JSON.parse(data) as Task\n set({ tasks: upsertById(get().tasks, task) })\n }\n },\n })\n set({ _es: stream })\n },\n\n disconnectSSE() {\n const es = get()._es\n if (es) { es.close(); set({ _es: null }) }\n },\n\n // --- Command palette ---\n openCommandPalette() { set({ commandQuery: '', commandPaletteOpen: true }) },\n closeCommandPalette() { set({ commandPaletteOpen: false, commandQuery: '' }) },\n async runCommand(command) {\n const { action, payload } = command\n get().closeCommandPalette()\n if (action === 'openView') await get().switchView(payload.view as ViewName)\n else if (action === 'agentPreset') { set({ showOffline: true, agentPresetFilter: (payload.preset as string) || '' }); await get().switchView('agents') }\n else if (action === 'copy') try { await navigator.clipboard?.writeText((payload.value as string) || '') } catch {}\n else if (action === 'messageAgent') { const agent = get().agentsById[payload.agentId as string]; if (agent) get().openComposeToAgent(agent) }\n else if (action === 'pairAgent') get().openPairInvite(payload.agentId as string)\n else if (action === 'filterTag') { set({ agentTagFilter: (payload.tag as string) || '', tagFilter: (payload.tag as string) || '' }); await get().switchView('agents') }\n else if (action === 'exportActivity') get().exportActivity((payload.format as string) || 'markdown')\n },\n\n // --- Auth ---\n async saveTokenAndRefresh() {\n const token = get().authToken\n setAuthToken(token)\n try {\n await api('GET', '/stats')\n } catch (e: unknown) {\n if ((e as { status?: number }).status === 401) {\n set({ authNeeded: true })\n return\n }\n }\n set({ authNeeded: false, connectionError: false })\n get().connectSSE()\n await get().refresh()\n get().startAutoRefresh()\n },\n\n // --- Cleanup ---\n destroy() {\n setUnauthorizedHandler(null)\n get().disconnectSSE()\n get().stopAutoRefresh()\n get().stopClock()\n },\n})\n","import { api } from '@/lib/api'\nimport { displayName } from '@/lib/display'\nimport type { Agent } from '@/types'\nimport { indexAgents, mergeListById } from '../merge'\nimport type { AgentsSlice, StoreSlice } from '../types'\n\nexport const createAgentsSlice: StoreSlice<AgentsSlice> = (set, get) => ({\n agents: [],\n agentsById: {},\n showOffline: false,\n showBuiltIns: false,\n agentSort: 'status',\n agentSortDir: 'asc',\n agentPresetFilter: '',\n agentStatusFilter: '',\n agentTagFilter: '',\n agentHostFilter: '',\n selectedAgent: '',\n agentDetailOpen: false,\n agentDetailId: '',\n livenessMismatches: {},\n commandStalls: {},\n channelDetailOpen: false,\n channelDetailId: '',\n renameModal: { show: false, agentId: '', label: '' },\n tagFilter: '',\n\n async fetchAgents() {\n try {\n const incoming = await api<Agent[]>('GET', '/agents')\n const agents = mergeListById(get().agents, incoming)\n if (agents === get().agents) return\n set({ agents, agentsById: indexAgents(agents) })\n } catch {}\n },\n openAgentDetail(agent) { set({ agentDetailId: agent.id, agentDetailOpen: true }) },\n closeAgentDetail() { set({ agentDetailOpen: false }) },\n openChannelDetail(channel) { set({ channelDetailId: channel.id, channelDetailOpen: true }) },\n closeChannelDetail() { set({ channelDetailOpen: false }) },\n openRename(agent) { set({ renameModal: { show: true, agentId: agent.id, label: agent.label || '' } }) },\n async doRename() {\n const s = get()\n const label = s.renameModal.label.trim() || null\n try {\n await api('PATCH', '/agents/' + s.renameModal.agentId + '/label', { label })\n set({ renameModal: { ...s.renameModal, show: false } })\n } catch (e) { get().showError('Rename Failed', (e as Error).message) }\n },\n async doDeleteAgent(id) {\n try {\n await api('DELETE', '/agents/' + id)\n const s = get()\n const byId = { ...s.agentsById }\n delete byId[id]\n set({ agents: s.agents.filter((a) => a.id !== id), agentsById: byId, selectedAgent: s.selectedAgent === id ? '' : s.selectedAgent })\n } catch (e) { get().showError('Delete Failed', (e as Error).message) }\n },\n async doAgentAction(agent, action, component) {\n try {\n await api('POST', '/agents/' + encodeURIComponent(agent.id) + '/actions', { action, ...(component ? { surface: { component } } : {}) })\n const label = action === 'restart' ? 'Restart' : action === 'resume' ? 'Resume' : action === 'shutdown' ? 'Shutdown' : action === 'compact' ? 'Compact' : action === 'clearContext' ? 'Clear context' : action\n get().showNotification(`${label} command sent to ${displayName(agent)}`)\n await Promise.all([get().fetchMessages(), get().fetchActivityEvents()])\n } catch (e) { get().showError('Action Failed', (e as Error).message) }\n },\n})\n","import { api } from '@/lib/api'\nimport { HUMAN_AGENT_ID, INBOX_OPERATOR_ID, DEFAULT_COMPOSE, DEFAULT_INBOX_COMPOSE } from '@/lib/constants'\nimport { inboxPeer, isBadgeWorthy, isHumanInboundMessage, isReactionEventMessage } from '@/lib/display'\nimport type { ChatHistoryImport, InboxState, Message } from '@/types'\nimport { isActiveVisibleChat, lastInboundMessageId, mergeFetchedMessages, mergeListById, upsertById } from '../merge'\nimport type { AgentChatWindow } from '../types'\nimport type { ChatSlice, StoreSlice } from '../types'\n\nconst AGENT_CHAT_PAGE_LIMIT = 300\n\nconst EMPTY_AGENT_CHAT_WINDOW: AgentChatWindow = {\n messages: [],\n oldestLoadedId: null,\n hasMore: true,\n loading: false,\n loadedInitial: false,\n}\n\nfunction agentChatPath(agentId: string, params: Record<string, string | number>): string {\n const search = new URLSearchParams()\n for (const [key, value] of Object.entries(params)) search.set(key, String(value))\n return `/agents/${encodeURIComponent(agentId)}/chat?${search.toString()}`\n}\n\nfunction messagesForAgent(agentId: string, messages: Message[]): Message[] {\n return messages\n .filter((message) => inboxPeer(message) === agentId && !isReactionEventMessage(message))\n .sort((a, b) => a.id - b.id)\n}\n\nfunction mergeAgentChatMessages(current: Message[], incoming: Message[]): Message[] {\n return mergeListById(current, [...current, ...incoming].sort((a, b) => a.id - b.id))\n}\n\nfunction oldestLoadedId(messages: Message[]): number | null {\n return messages[0]?.id ?? null\n}\n\nexport const createChatSlice: StoreSlice<ChatSlice> = (set, get) => ({\n messages: [],\n agentChatByAgent: {},\n threadHistory: {},\n threadMessages: [],\n threadOpen: false,\n chatHistoryImports: [],\n selectedInboxThread: '',\n replyTo: null,\n composeOpen: false,\n showReasoning: false,\n chatAgentSearch: '',\n chatAgentProviderFilter: '',\n chatAgentStatusFilter: '',\n chatAgentTagFilter: '',\n chatAgentCapFilter: '',\n chatAgentHostFilter: '',\n chatAgentSort: 'status',\n chatAgentSortDir: 'asc',\n chatAgentGroupBy: '',\n chatAgentFiltersCollapsed: true,\n chatStatusEvents: {},\n chatStickToBottom: true,\n chatHasNewItems: false,\n inboxReadCursors: {},\n inboxArchivedThreads: {},\n inboxDrafts: {},\n chatSending: false,\n inboxSearch: '',\n inboxSort: 'attention',\n inboxSortDir: 'desc',\n inboxShowArchived: false,\n channelFilter: '',\n compose: { ...DEFAULT_COMPOSE },\n inboxCompose: { ...DEFAULT_INBOX_COMPOSE },\n\n async fetchMessages() {\n try {\n const s = get()\n let path = '/messages?limit=100'\n if (s.view === 'messages' && s.selectedAgent) path += '&for=' + encodeURIComponent(s.selectedAgent)\n if (s.view === 'messages' && s.channelFilter) path += '&channel=' + encodeURIComponent(s.channelFilter)\n const messages = await api<Message[]>('GET', path)\n const merged = mergeFetchedMessages(get().messages, messages)\n set({ messages: merged })\n // Auto-read on the poll path too. The 5s poll frequently beats SSE\n // (and on mobile is often the *only* live path, since browsers suspend\n // SSE on a backgrounded tab) — so the SSE-side auto-read alone leaves\n // an unread badge on the very thread the user is reading. Advance the\n // cursor past the latest inbound message for the active visible thread.\n const after = get()\n const peer = after.selectedInboxThread\n if (isActiveVisibleChat(peer, after)) {\n let lastId = 0\n for (const m of merged) {\n if (m.id > lastId && inboxPeer(m) === peer && isHumanInboundMessage(m) && isBadgeWorthy(m)) lastId = m.id\n }\n if (lastId) get().markInboxThreadReadTo(peer, lastId)\n }\n } catch {}\n },\n async loadAgentChat(agentId) {\n if (!agentId) return\n const current = get().agentChatByAgent[agentId]\n if (current?.loading) return\n set((state) => ({\n agentChatByAgent: {\n ...state.agentChatByAgent,\n [agentId]: { ...(state.agentChatByAgent[agentId] ?? EMPTY_AGENT_CHAT_WINDOW), loading: true },\n },\n }))\n try {\n const page = await api<Message[]>('GET', agentChatPath(agentId, { limit: AGENT_CHAT_PAGE_LIMIT }))\n const incoming = messagesForAgent(agentId, page)\n const latest = get().agentChatByAgent[agentId] ?? EMPTY_AGENT_CHAT_WINDOW\n const messages = latest.loadedInitial\n ? mergeAgentChatMessages(latest.messages, incoming)\n : mergeListById([], incoming)\n set((state) => ({\n agentChatByAgent: {\n ...state.agentChatByAgent,\n [agentId]: {\n messages,\n oldestLoadedId: oldestLoadedId(messages),\n hasMore: page.length === AGENT_CHAT_PAGE_LIMIT,\n loading: false,\n loadedInitial: true,\n },\n },\n }))\n } catch (e) {\n set((state) => ({\n agentChatByAgent: {\n ...state.agentChatByAgent,\n [agentId]: { ...(state.agentChatByAgent[agentId] ?? EMPTY_AGENT_CHAT_WINDOW), loading: false },\n },\n }))\n get().showError('Chat Load Failed', (e as Error).message)\n }\n },\n async loadOlder(agentId) {\n if (!agentId) return\n const current = get().agentChatByAgent[agentId]\n if (!current?.loadedInitial) { await get().loadAgentChat(agentId); return }\n if (current.loading || !current.hasMore || current.oldestLoadedId === null) return\n set((state) => ({\n agentChatByAgent: {\n ...state.agentChatByAgent,\n [agentId]: { ...current, loading: true },\n },\n }))\n try {\n const page = await api<Message[]>('GET', agentChatPath(agentId, { before: current.oldestLoadedId, limit: AGENT_CHAT_PAGE_LIMIT }))\n const incoming = messagesForAgent(agentId, page)\n const latest = get().agentChatByAgent[agentId] ?? current\n const messages = mergeListById(latest.messages, [...incoming, ...latest.messages].sort((a, b) => a.id - b.id))\n set((state) => ({\n agentChatByAgent: {\n ...state.agentChatByAgent,\n [agentId]: {\n messages,\n oldestLoadedId: oldestLoadedId(messages),\n hasMore: page.length === AGENT_CHAT_PAGE_LIMIT,\n loading: false,\n loadedInitial: true,\n },\n },\n }))\n } catch (e) {\n set((state) => ({\n agentChatByAgent: {\n ...state.agentChatByAgent,\n [agentId]: { ...(state.agentChatByAgent[agentId] ?? current), loading: false },\n },\n }))\n get().showError('Chat Load Failed', (e as Error).message)\n }\n },\n async gapFillAgentChat(agentId) {\n if (!agentId) return\n let current = get().agentChatByAgent[agentId]\n if (!current?.loadedInitial || current.messages.length === 0) return\n let cursor = current.messages[current.messages.length - 1]!.id\n try {\n for (;;) {\n const since = cursor\n const page = await api<Message[]>('GET', agentChatPath(agentId, { since: cursor, limit: AGENT_CHAT_PAGE_LIMIT }))\n if (page.length === 0) return\n get().appendChatTail(agentId, page.filter((message) => message.id > since))\n cursor = page[page.length - 1]!.id\n if (cursor <= since) return\n if (page.length < AGENT_CHAT_PAGE_LIMIT) return\n current = get().agentChatByAgent[agentId]\n const newest = current?.messages[current.messages.length - 1]?.id\n if (newest && newest > cursor) cursor = newest\n }\n } catch (e) {\n get().showError('Chat Gap Fill Failed', (e as Error).message)\n }\n },\n appendChatTail(agentId, msgs) {\n if (!agentId || msgs.length === 0) return\n const incoming = messagesForAgent(agentId, msgs)\n if (incoming.length === 0) return\n const current = get().agentChatByAgent[agentId] ?? EMPTY_AGENT_CHAT_WINDOW\n const messages = mergeAgentChatMessages(current.messages, incoming)\n set({\n agentChatByAgent: {\n ...get().agentChatByAgent,\n [agentId]: {\n ...current,\n messages,\n oldestLoadedId: oldestLoadedId(messages),\n },\n },\n })\n },\n async fetchThreadHistory(peer) {\n if (!peer) return\n try {\n const history = await api<Message[]>('GET', '/messages?for=' + encodeURIComponent(peer) + '&limit=500')\n set({ threadHistory: { ...get().threadHistory, [peer]: history } })\n } catch {}\n },\n async fetchChatHistoryImports() {\n try {\n set({ chatHistoryImports: await api<ChatHistoryImport[]>('GET', '/chat/history-imports?limit=500') })\n } catch {}\n },\n async fetchInboxState() {\n try {\n const state = await api<InboxState>('GET', '/inbox/state?operatorId=' + encodeURIComponent('user'))\n const readCursors: Record<string, number> = {}\n const archivedThreads: Record<string, number> = {}\n const drafts: Record<string, string> = {}\n for (const t of state?.threads || []) {\n if (t.readCursorMessageId) readCursors[t.peerId] = t.readCursorMessageId\n if (t.archivedAtMessageId) archivedThreads[t.peerId] = t.archivedAtMessageId\n }\n for (const d of state?.drafts || []) { if (d.body) drafts[d.peerId] = d.body }\n const localDrafts = get().inboxDrafts\n const hasLocalDrafts = Object.keys(localDrafts).length > 0\n set({ inboxReadCursors: readCursors, inboxArchivedThreads: archivedThreads, ...(hasLocalDrafts ? {} : { inboxDrafts: drafts }) })\n } catch {}\n },\n\n openCompose() { set({ composeOpen: true, compose: { ...DEFAULT_COMPOSE, from: HUMAN_AGENT_ID } }) },\n openComposeToAgent(agent) {\n set({ replyTo: null, compose: { ...DEFAULT_COMPOSE, from: HUMAN_AGENT_ID, to: agent.id }, composeOpen: true })\n },\n async doSend() {\n const s = get()\n if (!s.compose.from || !s.compose.to || !s.compose.body) { get().showError('Validation', 'From, To, and Message are required.'); return }\n try {\n const payload: Record<string, unknown> = { from: s.compose.from, to: s.compose.to, body: s.compose.body }\n if (s.compose.channel) payload.channel = s.compose.channel\n if (s.compose.subject) payload.subject = s.compose.subject\n if (s.replyTo) payload.replyTo = s.replyTo.id\n if (s.compose.claimable) { payload.claimable = true; payload.kind = 'task'; payload.payload = { title: s.compose.subject || 'Claimable task' } }\n await api('POST', '/messages', payload)\n set({ composeOpen: false, replyTo: null, compose: { ...DEFAULT_COMPOSE, from: HUMAN_AGENT_ID } })\n await get().fetchMessages()\n } catch (e) { get().showError('Send Failed', (e as Error).message) }\n },\n async doClaim(msgId) {\n const s = get()\n const agentId = s.compose.from || s.selectedAgent\n if (!agentId) { get().showError('Validation', 'Select an agent first.'); return }\n try {\n const result = await api<{ ok: boolean; error?: string }>('POST', '/messages/' + msgId + '/claim', { agentId })\n if (!result.ok) get().showError('Claim Failed', result.error || 'unknown')\n if (result.ok) await Promise.all([get().fetchMessages(), get().fetchTasks()])\n } catch (e) { get().showError('Claim Failed', (e as Error).message) }\n },\n async doDeliveryAction(msgId, action, reason) {\n try {\n await api('POST', '/messages/' + msgId + '/delivery/actions', { action, reason, agentId: get().compose.from || get().selectedAgent || HUMAN_AGENT_ID })\n await get().fetchMessages()\n } catch (e) { get().showError('Delivery Update Failed', (e as Error).message) }\n },\n async doDeleteMessage(id) {\n try {\n await api('DELETE', '/messages/' + id)\n set({ messages: get().messages.filter((m) => m.id !== id) })\n } catch (e) { get().showError('Delete Failed', (e as Error).message) }\n },\n async reactToMessage(msg, emoji) {\n try {\n const mine = (msg.reactions || []).some((reaction) => reaction.actorId === HUMAN_AGENT_ID && reaction.emoji === emoji)\n const updated = await api<Message>('POST', '/messages/' + msg.id + '/reactions', {\n actorId: HUMAN_AGENT_ID,\n emoji,\n action: mine ? 'remove' : 'add',\n })\n set({ messages: upsertById(get().messages, updated) })\n } catch (e) { get().showError('Reaction Failed', (e as Error).message) }\n },\n startReply(msg) {\n const target = msg.from === HUMAN_AGENT_ID ? msg.to : msg.from\n set({ replyTo: { id: msg.id, from: msg.from }, compose: { ...DEFAULT_COMPOSE, from: HUMAN_AGENT_ID, to: target, channel: msg.channel || '' }, composeOpen: true })\n },\n cancelReply() { set({ replyTo: null }) },\n async openThread(threadId) {\n set({ threadMessages: [], threadOpen: true })\n try { set({ threadMessages: await api('GET', '/messages/' + threadId + '/thread') }) }\n catch (e) { get().showError('Thread Load Failed', (e as Error).message) }\n },\n\n openInboxThread(peer, messages = []) {\n set({ selectedInboxThread: peer })\n if (messages.length) get().markInboxThreadRead(peer, messages)\n void get().loadAgentChat(peer)\n },\n async sendChatMessage(body, thread, attachments = []) {\n if ((!body.trim() && attachments.length === 0) || get().chatSending) return\n set({ chatSending: true })\n try {\n const peerAgent = get().agentsById[thread.peer]\n const useLiveSession = peerAgent?.providerCapabilities?.liveSession?.inject && attachments.length === 0\n if (useLiveSession) {\n await api('POST', '/agents/' + encodeURIComponent(thread.peer) + '/prompt', { body: body.trim() })\n } else {\n const payload: Record<string, unknown> = { from: HUMAN_AGENT_ID, to: thread.peer, body: body.trim() || 'Attachment' }\n if (thread.lastMessage?.channel) payload.channel = thread.lastMessage.channel\n if (thread.lastMessage?.id) payload.replyTo = thread.lastMessage.id\n if (attachments.length) payload.payload = { attachments }\n await api('POST', '/messages', payload)\n }\n const next = { ...get().inboxDrafts }\n delete next[thread.peer]\n set({ inboxDrafts: next })\n api('DELETE', '/inbox/drafts?operatorId=' + encodeURIComponent(INBOX_OPERATOR_ID) + '&peerId=' + encodeURIComponent(thread.peer)).catch(() => {})\n await Promise.all([get().fetchMessages(), get().loadAgentChat(thread.peer)])\n } catch (e) { get().showError('Send Failed', (e as Error).message) }\n set({ chatSending: false })\n },\n async sendPermissionDecision(agentId, approvalId, decision, answers) {\n try {\n await api('POST', '/agents/' + encodeURIComponent(agentId) + '/permission-decision', { approvalId, decision, ...(answers ? { answers } : {}) })\n const label = decision === 'approve' ? 'Approved' : decision === 'approve-session' ? 'Approved for session' : decision === 'abort' ? 'Aborted' : decision === 'answer' ? 'Answer sent for' : 'Denied'\n get().showNotification(`${label} ${decision === 'answer' ? \"Claude's question\" : 'permission request'}`)\n await get().fetchAgents()\n } catch (e) { get().showError('Permission Failed', (e as Error).message) }\n },\n markInboxThreadReadTo(peer, lastId) {\n if (!peer || lastId <= (get().inboxReadCursors[peer] || 0)) return\n set({ inboxReadCursors: { ...get().inboxReadCursors, [peer]: lastId } })\n api('PATCH', '/inbox/threads', { operatorId: INBOX_OPERATOR_ID, peerId: peer, readCursorMessageId: lastId }).catch(() => {})\n },\n markInboxThreadRead(peer, messages) {\n if (!peer || !messages.length) return\n get().markInboxThreadReadTo(peer, lastInboundMessageId(messages))\n },\n markInboxThreadUnread(peer) {\n const next = { ...get().inboxReadCursors }\n delete next[peer]\n set({ inboxReadCursors: next })\n api('PATCH', '/inbox/threads', { operatorId: INBOX_OPERATOR_ID, peerId: peer, readCursorMessageId: null }).catch(() => {})\n },\n archiveInboxThread(peer, lastMessageId) {\n set({ inboxArchivedThreads: { ...get().inboxArchivedThreads, [peer]: lastMessageId } })\n if (get().selectedInboxThread === peer) set({ selectedInboxThread: '' })\n api('PATCH', '/inbox/threads', { operatorId: INBOX_OPERATOR_ID, peerId: peer, archivedAtMessageId: lastMessageId }).catch(() => {})\n },\n unarchiveInboxThread(peer) {\n const next = { ...get().inboxArchivedThreads }\n delete next[peer]\n set({ inboxArchivedThreads: next })\n api('PATCH', '/inbox/threads', { operatorId: INBOX_OPERATOR_ID, peerId: peer, archivedAtMessageId: null }).catch(() => {})\n },\n setReplyDraft(peer, value) {\n const next = { ...get().inboxDrafts }\n if (value) next[peer] = value\n else delete next[peer]\n set({ inboxDrafts: next })\n if (value) api('PUT', '/inbox/drafts', { operatorId: INBOX_OPERATOR_ID, peerId: peer, body: value }).catch(() => {})\n else api('DELETE', '/inbox/drafts?operatorId=' + encodeURIComponent(INBOX_OPERATOR_ID) + '&peerId=' + encodeURIComponent(peer)).catch(() => {})\n },\n async sendInboxReply(peer, lastMessage) {\n const body = (get().inboxDrafts[peer] || '').trim()\n if (!body || get().chatSending) { if (!body) get().showError('Validation', 'Reply body is required.'); return }\n set({ chatSending: true })\n try {\n const payload: Record<string, unknown> = { from: HUMAN_AGENT_ID, to: peer, body }\n if (lastMessage?.channel) payload.channel = lastMessage.channel\n if (lastMessage?.id) payload.replyTo = lastMessage.id\n await api('POST', '/messages', payload)\n const next = { ...get().inboxDrafts }\n delete next[peer]\n set({ inboxDrafts: next })\n api('DELETE', '/inbox/drafts?operatorId=' + encodeURIComponent(INBOX_OPERATOR_ID) + '&peerId=' + encodeURIComponent(peer)).catch(() => {})\n await get().fetchMessages()\n } catch (e) { get().showError('Reply Failed', (e as Error).message) }\n set({ chatSending: false })\n },\n async doSendInboxCompose() {\n const s = get()\n const ic = s.inboxCompose\n let target = ic.to\n if (!target) return\n if (ic.toMode === 'tag') target = 'tag:' + target\n else if (ic.toMode === 'cap') target = 'cap:' + target\n if (!ic.body) { get().showError('Validation', 'Message is required.'); return }\n try {\n const payload: Record<string, unknown> = { from: HUMAN_AGENT_ID, to: target, body: ic.body }\n if (ic.channel) payload.channel = ic.channel\n if (ic.subject) payload.subject = ic.subject\n if (ic.claimable) { payload.claimable = true; payload.kind = 'task'; payload.payload = { title: ic.subject || 'Claimable task' } }\n await api('POST', '/messages', payload)\n set({ inboxCompose: { ...DEFAULT_INBOX_COMPOSE, toMode: ic.toMode, to: ic.to } })\n await get().fetchMessages()\n } catch (e) { get().showError('Send Failed', (e as Error).message) }\n },\n})\n","import { api } from '@/lib/api'\nimport { DEFAULT_PAIR_MESSAGE, DEFAULT_PAIR_INVITE } from '@/lib/constants'\nimport type { Memory, PairSession, Task, TaskEvent } from '@/types'\nimport { mergeListById } from '../merge'\nimport type { StoreSlice, WorkSlice } from '../types'\n\nexport const createWorkSlice: StoreSlice<WorkSlice> = (set, get) => ({\n pairs: [],\n tasks: [],\n taskEvents: [],\n taskEventCache: {},\n taskEventsOpen: false,\n pairInviteOpen: false,\n pairMessageOpen: false,\n pairInvite: { ...DEFAULT_PAIR_INVITE },\n pairMessage: { ...DEFAULT_PAIR_MESSAGE },\n pairStatusFilter: 'open',\n taskStatusFilter: '',\n taskSourceFilter: '',\n\n async fetchPairs() {\n try {\n const s = get()\n let pairs: PairSession[]\n if (s.view === 'activity') {\n pairs = await api('GET', '/pairs')\n } else if (s.pairStatusFilter === 'open') {\n const [active, pending] = await Promise.all([\n api<PairSession[]>('GET', '/pairs?status=active'),\n api<PairSession[]>('GET', '/pairs?status=pending'),\n ])\n pairs = [...active, ...pending]\n } else if (s.pairStatusFilter) {\n pairs = await api('GET', '/pairs?status=' + encodeURIComponent(s.pairStatusFilter))\n } else {\n pairs = await api('GET', '/pairs')\n }\n const sorted = pairs.sort((a, b) => new Date(b.updatedAt as string).getTime() - new Date(a.updatedAt as string).getTime())\n const merged = mergeListById(get().pairs, sorted)\n if (merged !== get().pairs) set({ pairs: merged })\n } catch {}\n },\n async fetchTasks() {\n try {\n const s = get()\n const params = new URLSearchParams({ limit: '100' })\n if (s.taskStatusFilter) params.set('status', s.taskStatusFilter)\n if (s.taskSourceFilter) params.set('source', s.taskSourceFilter)\n const tasks = mergeListById(get().tasks, await api<Task[]>('GET', '/tasks?' + params.toString()))\n if (tasks !== get().tasks) set({ tasks })\n } catch {}\n },\n async doClaimTask(taskId) {\n const s = get()\n const agentId = s.compose.from || s.selectedAgent\n if (!agentId) { get().showError('Validation', 'Select an agent first.'); return }\n try {\n const result = await api<{ ok: boolean; error?: string }>('POST', '/tasks/' + taskId + '/claim', { agentId })\n if (!result.ok) get().showError('Claim Failed', result.error || 'unknown')\n else await Promise.all([get().fetchTasks(), get().fetchMessages()])\n } catch (e) { get().showError('Claim Failed', (e as Error).message) }\n },\n async doUpdateTaskStatus(task, status) {\n if (!task || !status || status === task.status) return\n try {\n const body: Record<string, unknown> = { status }\n const agentId = task.claimedBy || get().compose.from || get().selectedAgent\n if (agentId) body.agentId = agentId\n const result = await api<{ task: Task; memory?: Memory; memoryEvent?: TaskEvent }>('PATCH', '/tasks/' + task.id + '/status', body)\n const updated = result.task || result\n set({ tasks: get().tasks.map((t) => t.id === task.id ? updated : t) })\n if (result.memoryEvent) {\n const cached = get().taskEventCache[task.id] || []\n set({\n taskEventCache: { ...get().taskEventCache, [task.id]: [...cached, result.memoryEvent] },\n ...(get().taskEventsOpen ? { taskEvents: [...get().taskEvents, result.memoryEvent] } : {}),\n })\n }\n if (result.memory) get().showNotification(`Memory captured: ${result.memory.title}`)\n } catch (e) { get().showError('Status Update Failed', (e as Error).message); await get().fetchTasks() }\n },\n async openTaskEvents(task) {\n set({ taskEvents: [], taskEventsOpen: true })\n try {\n const events = await api<TaskEvent[]>('GET', '/tasks/' + task.id + '/events')\n set({ taskEvents: events, taskEventCache: { ...get().taskEventCache, [task.id]: events } })\n } catch (e) { get().showError('Task Events Failed', (e as Error).message) }\n },\n\n openPairInvite(requesterId) { set({ pairInvite: { ...DEFAULT_PAIR_INVITE, requesterId: requesterId || get().selectedAgent || '' }, pairInviteOpen: true }) },\n closePairInvite() { set({ pairInviteOpen: false, pairInvite: { ...DEFAULT_PAIR_INVITE } }) },\n async doCreatePair() {\n const s = get()\n if (!s.pairInvite.requesterId || !s.pairInvite.targetId) { get().showError('Validation', 'Requester and Target are required.'); return }\n if (s.pairInvite.requesterId === s.pairInvite.targetId) { get().showError('Validation', 'Requester and Target must be different.'); return }\n try {\n const payload: Record<string, unknown> = { from: s.pairInvite.requesterId, target: s.pairInvite.targetId }\n if (s.pairInvite.objective) payload.objective = s.pairInvite.objective\n await api('POST', '/pairs', payload)\n set({ pairInviteOpen: false, pairInvite: { ...DEFAULT_PAIR_INVITE } })\n await Promise.all([get().fetchPairs(), get().fetchMessages()])\n } catch (e) { get().showError('Pair Invite Failed', (e as Error).message) }\n },\n openPairMessage(pair, fromId) {\n set({ pairMessage: { ...DEFAULT_PAIR_MESSAGE, pairId: pair.id, from: fromId || pair.requesterId }, pairMessageOpen: true })\n },\n closePairMessage() { set({ pairMessageOpen: false, pairMessage: { ...DEFAULT_PAIR_MESSAGE } }) },\n async doSendPairMessage() {\n const s = get()\n if (!s.pairMessage.pairId || !s.pairMessage.from || !s.pairMessage.body) { get().showError('Validation', 'Pair, From, and Message are required.'); return }\n try {\n const payload: Record<string, unknown> = { from: s.pairMessage.from, body: s.pairMessage.body }\n if (s.pairMessage.subject) payload.subject = s.pairMessage.subject\n await api('POST', '/pairs/' + encodeURIComponent(s.pairMessage.pairId) + '/messages', payload)\n set({ pairMessageOpen: false, pairMessage: { ...DEFAULT_PAIR_MESSAGE } })\n await Promise.all([get().fetchPairs(), get().fetchMessages()])\n } catch (e) { get().showError('Pair Message Failed', (e as Error).message) }\n },\n async doAcceptPair(pair) {\n try {\n await api('POST', '/pairs/' + encodeURIComponent(pair.id) + '/accept', { agentId: pair.targetId })\n await Promise.all([get().fetchPairs(), get().fetchMessages()])\n } catch (e) { get().showError('Accept Failed', (e as Error).message) }\n },\n async doRejectPair(pair) {\n try {\n await api('POST', '/pairs/' + encodeURIComponent(pair.id) + '/reject', { agentId: pair.targetId })\n await Promise.all([get().fetchPairs(), get().fetchMessages()])\n } catch (e) { get().showError('Reject Failed', (e as Error).message) }\n },\n async doHangupPair(pair, agentId) {\n try {\n await api('POST', '/pairs/' + encodeURIComponent(pair.id) + '/hangup', { agentId: agentId || pair.requesterId })\n await Promise.all([get().fetchPairs(), get().fetchMessages()])\n } catch (e) { get().showError('Hang Up Failed', (e as Error).message) }\n },\n})\n","import { api } from '@/lib/api'\nimport { HUMAN_AGENT_ID, INBOX_OPERATOR_ID } from '@/lib/constants'\nimport { messageBody, displayName, pathWithinBase } from '@/lib/display'\nimport { PROVIDER_CATALOG } from 'agent-relay-sdk/provider-catalog'\nimport type { Orchestrator, SpawnProvider } from '@/types'\nimport { firstAvailableProvider, defaultModelFor } from '../helpers'\nimport { mergeListById } from '../merge'\nimport type { SpawnSlice, StoreSlice } from '../types'\n\nexport const createSpawnSlice: StoreSlice<SpawnSlice> = (set, get) => ({\n orchestrators: [],\n orchestratorSpawnOpen: false,\n orchestratorInstallOpen: false,\n spawnOrchId: '',\n spawnProvider: 'claude',\n spawnModel: defaultModelFor('claude'),\n spawnEffort: '',\n spawnProfile: 'default-relay',\n spawnCwd: '',\n spawnLabel: '',\n spawnApproval: 'guarded',\n spawnWorkspaceMode: 'inherit',\n spawnPrompt: '',\n spawnSystemPromptAppend: '',\n spawnCount: 1,\n spawnCwdHistory: [],\n isSpawning: false,\n spawnDirBrowser: { open: false, loading: false, path: '', parent: '', baseDir: '', entries: [], error: '' },\n pendingForkImport: null,\n\n async fetchOrchestrators() {\n try {\n const orchestrators = mergeListById(get().orchestrators, await api<Orchestrator[]>('GET', '/orchestrators'))\n if (orchestrators !== get().orchestrators) set({ orchestrators })\n } catch {}\n },\n async refreshOrchestratorProviders(orchId) {\n try {\n await api('GET', '/orchestrators/' + encodeURIComponent(orchId) + '/providers?refresh=1')\n await get().fetchOrchestrators()\n get().showNotification('Provider status refreshed')\n } catch (e) { get().showError('Provider Refresh Failed', (e as Error).message) }\n },\n\n openAgentSpawn() { get().openOrchestratorSpawn() },\n closeAgentSpawn() { set({ orchestratorSpawnOpen: false }) },\n async doSpawnAgent() { await get().submitOrchestratorSpawn() },\n openOrchestratorSpawn() {\n get().openOrchestratorSpawnAt()\n },\n openOrchestratorSpawnAt(input = {}) {\n const online = get().orchestrators.filter((o) => o.status === 'online')\n if (!online.length) { get().showError('No Orchestrators', 'No orchestrators are currently online.'); return }\n const s = get()\n const requested = input.orchestratorId ? online.find((o) => o.id === input.orchestratorId) : undefined\n if (input.orchestratorId && !requested) { get().showError('Orchestrator Offline', 'The selected orchestrator is not online.'); return }\n const cwdHint = input.cwd?.trim() || s.spawnCwd\n const cwdOrch = cwdHint ? online.find((o) => pathWithinBase(cwdHint, o.baseDir)) : undefined\n const persisted = s.spawnOrchId ? online.find((o) => o.id === s.spawnOrchId) : undefined\n const orchId = requested?.id || cwdOrch?.id || persisted?.id || online[0]!.id\n const orch = online.find((o) => o.id === orchId)!\n const provider = s.spawnProvider && orch.providers.includes(s.spawnProvider as any) ? s.spawnProvider : firstAvailableProvider(orch)\n const model = s.spawnProvider === provider && s.spawnModel ? s.spawnModel : defaultModelFor(provider)\n const cwd = cwdHint && pathWithinBase(cwdHint, orch.baseDir) ? cwdHint : orch.baseDir || ''\n const effort = s.spawnProvider === provider && s.spawnModel === model ? s.spawnEffort : ''\n set({ spawnOrchId: orchId, spawnProvider: provider, spawnModel: model, spawnEffort: effort, spawnProfile: s.spawnProfile || 'default-relay', spawnCwd: cwd, spawnLabel: '', spawnWorkspaceMode: 'inherit', spawnPrompt: '', spawnSystemPromptAppend: '', spawnCount: 1, pendingForkImport: null, orchestratorSpawnOpen: true })\n },\n forkFromAgent(agentId, messages) {\n const s = get()\n const agent = s.agentsById[agentId]\n if (!agent) { get().showError('Fork', 'Agent not found.'); return }\n const online = s.orchestrators.filter((o) => o.status === 'online')\n if (!online.length) { get().showError('No Orchestrators', 'No orchestrators are currently online.'); return }\n const provCaps = agent.providerCapabilities\n const provider = provCaps?.model?.provider || (typeof agent.meta?.provider === 'string' ? agent.meta.provider as string : '')\n const reportedModel = provCaps?.model?.alias || provCaps?.model?.id || ''\n const catalog = provider ? PROVIDER_CATALOG[provider as SpawnProvider] : undefined\n const catalogEntry = catalog?.models.find((m) => m.alias === reportedModel || (m as any).providerModel === reportedModel)\n const model = catalogEntry?.alias || ''\n const effort = provCaps?.model?.effort || ''\n const cwd = typeof agent.meta?.cwd === 'string' ? agent.meta.cwd as string : ''\n const approval = provCaps?.session?.approvalMode || (typeof agent.meta?.approvalMode === 'string' ? agent.meta.approvalMode as string : 'guarded')\n const label = agent.label ? `${agent.label} (fork)` : ''\n const orch = online.find((o) => o.hostname === agent.machine) || online.find((o) => pathWithinBase(cwd, o.baseDir)) || online[0]!\n\n const agentName = displayName(agent)\n const lines: string[] = []\n for (const msg of messages) {\n const body = messageBody(msg).trim()\n if (!body) continue\n const role = msg.from === HUMAN_AGENT_ID ? 'user' : 'agent'\n lines.push(`[${role}]: ${body}`)\n }\n const history = lines.join('\\n')\n const maxHistory = 14000\n const trimmed = history.length > maxHistory ? '...\\n' + history.slice(history.length - maxHistory) : history\n const systemPromptAppend = `You are continuing work from a previous agent session (${agentName}). Below is the conversation history. Treat it as context for your work, not as your own actions.\\n\\n${trimmed}`\n const messageIds = messages\n .filter((msg) => typeof msg.id === 'number' && msg.id > 0)\n .map((msg) => msg.id)\n\n set({\n spawnOrchId: orch.id,\n spawnProvider: provider || firstAvailableProvider(orch),\n spawnModel: model || defaultModelFor(provider || firstAvailableProvider(orch)),\n spawnEffort: effort,\n spawnProfile: s.spawnProfile || 'default-relay',\n spawnCwd: cwd || orch.baseDir || '',\n spawnLabel: label,\n spawnApproval: approval,\n spawnWorkspaceMode: 'inherit',\n spawnPrompt: 'Continue from this previous session.',\n spawnSystemPromptAppend: systemPromptAppend,\n spawnCount: 1,\n pendingForkImport: {\n sourcePeerId: agent.id,\n sourceAgentId: agent.id,\n sourceThreadId: agent.id,\n sourceAgentLabel: agentName,\n messageIds,\n },\n orchestratorSpawnOpen: true,\n })\n },\n openOrchestratorInstall() {\n set({ orchestratorInstallOpen: true })\n },\n openOrchestratorSpawnFor(orchId) {\n const s = get()\n const orch = s.orchestrators.find((o) => o.id === orchId)\n const provider = firstAvailableProvider(orch)\n const model = defaultModelFor(provider)\n const effort = s.spawnProvider === provider && s.spawnModel === model ? s.spawnEffort : ''\n const cwd = s.spawnCwd && pathWithinBase(s.spawnCwd, orch?.baseDir) ? s.spawnCwd : orch?.baseDir || ''\n set({ spawnOrchId: orchId, spawnProvider: provider, spawnModel: model, spawnEffort: effort, spawnProfile: s.spawnProfile || 'default-relay', spawnCwd: cwd, spawnLabel: '', spawnWorkspaceMode: 'inherit', spawnPrompt: '', spawnSystemPromptAppend: '', spawnCount: 1, pendingForkImport: null, orchestratorSpawnOpen: true })\n },\n selectSpawnHistory(orchId, cwd) {\n const s = get()\n const orch = s.orchestrators.find((o) => o.id === orchId && o.status === 'online')\n if (!orch) { get().showError('Unavailable', 'That orchestrator is no longer online.'); return }\n if (orchId === s.spawnOrchId) { set({ spawnCwd: cwd }); return }\n const provider = s.spawnProvider && orch.providers.includes(s.spawnProvider as any) ? s.spawnProvider : firstAvailableProvider(orch)\n const model = s.spawnProvider === provider && s.spawnModel ? s.spawnModel : defaultModelFor(provider)\n const effort = s.spawnProvider === provider && s.spawnModel === model ? s.spawnEffort : ''\n set({ spawnOrchId: orchId, spawnProvider: provider, spawnModel: model, spawnEffort: effort, spawnCwd: cwd })\n },\n async submitOrchestratorSpawn() {\n const s = get()\n if (s.isSpawning) { return }\n if (!s.spawnOrchId) { get().showError('Validation', 'Select an orchestrator.'); return }\n const orch = s.orchestrators.find((o) => o.id === s.spawnOrchId)\n if (!orch) { get().showError('Validation', 'Selected orchestrator is not available.'); return }\n const cwd = s.spawnCwd.trim()\n if (!cwd) { get().showError('Validation', 'Select a working directory.'); return }\n if (!pathWithinBase(cwd, orch.baseDir)) { get().showError('Validation', `Working directory must be under ${orch.baseDir}.`); return }\n const pendingForkImport = s.pendingForkImport\n // A fork imports one source session into one target — never fan it out.\n const count = pendingForkImport ? 1 : Math.max(1, Math.min(10, Math.round(s.spawnCount) || 1))\n set({ isSpawning: true })\n try {\n for (let i = 0; i < count; i++) {\n const payload: Record<string, unknown> = { provider: s.spawnProvider, orchestratorId: s.spawnOrchId, approvalMode: s.spawnApproval, workspaceMode: s.spawnWorkspaceMode || 'inherit' }\n if (s.spawnModel) payload.model = s.spawnModel\n if (s.spawnEffort) payload.effort = s.spawnEffort\n if (s.spawnProfile) payload.profile = s.spawnProfile\n payload.cwd = cwd\n if (s.spawnLabel) payload.label = count > 1 ? `${s.spawnLabel} ${i + 1}` : s.spawnLabel\n if (s.spawnPrompt) payload.prompt = s.spawnPrompt\n if (s.spawnSystemPromptAppend) payload.systemPromptAppend = s.spawnSystemPromptAppend\n const response = await api<{ command?: { params?: { spawnRequestId?: string } } }>('POST', '/agents/spawn', payload)\n const targetSpawnRequestId = response.command?.params?.spawnRequestId\n if (pendingForkImport && targetSpawnRequestId && pendingForkImport.messageIds.length > 0) {\n await api('POST', '/chat/history-imports', {\n targetSpawnRequestId,\n sourcePeerId: pendingForkImport.sourcePeerId,\n sourceAgentId: pendingForkImport.sourceAgentId,\n sourceThreadId: pendingForkImport.sourceThreadId,\n sourceAgentLabel: pendingForkImport.sourceAgentLabel,\n importedBy: INBOX_OPERATOR_ID,\n messageIds: pendingForkImport.messageIds,\n })\n }\n }\n const history = [{ orchId: s.spawnOrchId, cwd }, ...s.spawnCwdHistory.filter((h) => !(h.orchId === s.spawnOrchId && h.cwd === cwd))].slice(0, 5)\n set({ orchestratorSpawnOpen: false, pendingForkImport: null, isSpawning: false, spawnCwdHistory: history })\n await Promise.all([get().fetchAgents(), get().fetchOrchestrators(), get().fetchActivityEvents(), get().fetchChatHistoryImports()])\n } catch (e) { set({ isSpawning: false }); get().showError('Spawn Failed', (e as Error).message) }\n },\n orchestratorAction(orchId, action, agentId, component) {\n const label = action === 'restart' ? 'Restart' : 'Shutdown'\n const target = agentId ? `agent \"${agentId}\"` : 'all agents'\n get().openConfirm(`${label} Agent`, `${label} ${target} on orchestrator \"${orchId}\"?`, async () => {\n try {\n await api('POST', '/orchestrators/' + encodeURIComponent(orchId) + '/actions', { action, agentId, ...(component ? { surface: { component } } : {}) })\n await Promise.all([get().fetchOrchestrators(), get().fetchActivityEvents()])\n } catch (e) { get().showError(`${label} Failed`, (e as Error).message) }\n })\n },\n upgradeOrchestrator(orchId, targetVersion) {\n const to = targetVersion ? ` to v${targetVersion}` : ' to match the relay'\n get().openConfirm('Upgrade Orchestrator', `Upgrade \"${orchId}\"${to}? It will install the new version and restart itself.`, async () => {\n try {\n await api('POST', '/orchestrators/' + encodeURIComponent(orchId) + '/actions', { action: 'upgrade', ...(targetVersion ? { targetVersion } : {}) })\n await Promise.all([get().fetchOrchestrators(), get().fetchActivityEvents()])\n } catch (e) { get().showError('Upgrade Failed', (e as Error).message) }\n })\n },\n deleteOrchestrator(orchId) {\n get().openConfirm('Remove Orchestrator', `Remove orchestrator \"${orchId}\"?`, async () => {\n try {\n await api('DELETE', '/orchestrators/' + encodeURIComponent(orchId))\n await Promise.all([get().fetchOrchestrators(), get().fetchActivityEvents()])\n } catch (e) { get().showError('Delete Failed', (e as Error).message) }\n })\n },\n async browseSpawnDirectory(path) {\n const orchId = get().spawnOrchId\n if (!orchId) return\n const browser = get().spawnDirBrowser\n set({ spawnDirBrowser: { ...browser, loading: true, error: '' } })\n try {\n const q = path ? '?path=' + encodeURIComponent(path) : ''\n const listing = await api<{ path: string; parent?: string; baseDir: string; entries: Array<{ name: string; path: string }> }>('GET', '/orchestrators/' + encodeURIComponent(orchId) + '/directories' + q)\n set({\n spawnDirBrowser: { open: true, loading: false, path: listing.path || '', parent: listing.parent || '', baseDir: listing.baseDir || '', entries: listing.entries || [], error: '' },\n spawnCwd: listing.path || get().spawnCwd,\n })\n } catch (e) { set({ spawnDirBrowser: { ...get().spawnDirBrowser, loading: false, error: (e as Error).message } }) }\n },\n selectSpawnDirectory(path) {\n set({ spawnCwd: path || get().spawnDirBrowser.path, spawnDirBrowser: { ...get().spawnDirBrowser, open: false } })\n },\n})\n","import { api } from '@/lib/api'\nimport type { AgentProfile, SpawnPolicy } from '@/types'\nimport { firstAvailableProvider, defaultModelFor } from '../helpers'\nimport type { ConfigEntry } from '../helpers'\nimport type { ManagedSlice, StoreSlice } from '../types'\n\nexport const createManagedSlice: StoreSlice<ManagedSlice> = (set, get) => ({\n managedPolicies: [],\n policyModal: {\n open: false, editing: '', name: '', description: '', orchestratorId: '', cwd: '',\n provider: 'claude' as const, rig: '', model: defaultModelFor('claude'), effort: '', profile: 'default-relay', providerArgs: '', prompt: '', tags: '', capabilities: '',\n label: '', mode: 'always-on' as const, permissionMode: 'guarded' as const,\n restartOnUpdate: true, scheduledDailyRestart: false,\n keepaliveSeconds: '300', backoffSchedule: '5,15,60,300', backoffResetAfterSeconds: '600',\n channelId: '',\n },\n policyDirBrowser: { open: false, loading: false, path: '', parent: '', baseDir: '', entries: [], error: '' },\n agentProfiles: [],\n profileModal: {\n open: false, mode: 'create' as const,\n profile: {\n name: '', description: '', provider: 'any' as const, base: 'host' as const,\n instructions: { system: '', append: [], repoInstructions: 'allow' as const, globalInstructions: 'allow' as const },\n relay: { context: true, skills: true, plugins: true, statusLine: true, mcp: true },\n skills: [], plugins: [],\n mcp: { mode: 'host' as const }, hooks: { mode: 'host' as const },\n permissions: { filesystem: 'host' as const },\n env: {}, providerOptions: {},\n },\n },\n\n async fetchManagedPolicies() { try { set({ managedPolicies: await api('GET', '/spawn-policies/health') }) } catch {} },\n async fetchAgentProfiles() {\n try {\n const entries = await api<ConfigEntry<AgentProfile>[]>('GET', '/agent-profiles')\n set({ agentProfiles: entries.map((entry) => entry.value) })\n } catch {}\n },\n\n openPolicyCreate() {\n const online = get().orchestrators.filter((o) => o.status === 'online')\n if (!online.length) { get().showError('No Orchestrators', 'No orchestrators are currently online.'); return }\n set({\n policyModal: {\n open: true, editing: '', name: '', description: '', orchestratorId: online[0]!.id, cwd: '',\n provider: firstAvailableProvider(online[0]), rig: '', model: defaultModelFor(firstAvailableProvider(online[0])), effort: '', profile: 'default-relay', providerArgs: '', prompt: '', tags: '', capabilities: '',\n label: '', mode: 'always-on', permissionMode: 'guarded',\n restartOnUpdate: true, scheduledDailyRestart: false,\n keepaliveSeconds: '300', backoffSchedule: '5,15,60,300', backoffResetAfterSeconds: '600',\n channelId: '',\n },\n policyDirBrowser: { open: false, loading: false, path: '', parent: '', baseDir: '', entries: [], error: '' },\n })\n },\n openPolicyEdit(policy) {\n set({\n policyModal: {\n open: true, editing: policy.name, name: policy.name,\n description: policy.description || '', orchestratorId: policy.orchestratorId,\n cwd: policy.cwd, provider: policy.provider,\n rig: policy.rig || '',\n model: policy.model || defaultModelFor(policy.provider),\n effort: policy.effort || '',\n profile: policy.profile || 'default-relay',\n providerArgs: (policy.providerArgs || []).join(' '),\n prompt: policy.prompt || '',\n tags: (policy.tags || []).join(', '),\n capabilities: (policy.capabilities || []).join(', '),\n label: policy.label || '', mode: policy.mode,\n permissionMode: policy.permissionMode,\n restartOnUpdate: policy.restartOnUpdate,\n scheduledDailyRestart: policy.scheduledDailyRestart,\n keepaliveSeconds: String(policy.onDemand?.keepaliveSeconds ?? 300),\n backoffSchedule: (policy.backoff?.schedule || [5, 15, 60, 300]).join(', '),\n backoffResetAfterSeconds: String(policy.backoff?.resetAfterSeconds ?? 600),\n channelId: policy.binding?.channelId || '',\n },\n policyDirBrowser: { open: false, loading: false, path: '', parent: '', baseDir: '', entries: [], error: '' },\n })\n },\n async submitPolicy() {\n const m = get().policyModal\n if (!m.name.trim()) { get().showError('Validation', 'Policy name is required.'); return }\n if (!m.orchestratorId) { get().showError('Validation', 'Select an orchestrator.'); return }\n if (!m.cwd.trim()) { get().showError('Validation', 'Working directory is required.'); return }\n const csvSplit = (s: string) => s.split(/[,\\s]+/).map((v) => v.trim()).filter(Boolean)\n const policy: SpawnPolicy = {\n name: m.name.trim(),\n ...(m.description.trim() ? { description: m.description.trim() } : {}),\n orchestratorId: m.orchestratorId,\n cwd: m.cwd.trim(),\n provider: m.provider,\n ...(m.rig.trim() ? { rig: m.rig.trim() } : {}),\n ...(m.model ? { model: m.model } : {}),\n ...(m.effort ? { effort: m.effort as any } : {}),\n ...(m.profile ? { profile: m.profile } : {}),\n providerArgs: m.providerArgs.trim() ? m.providerArgs.trim().split(/\\s+/) : [],\n ...(m.prompt.trim() ? { prompt: m.prompt.trim() } : {}),\n tags: csvSplit(m.tags),\n capabilities: csvSplit(m.capabilities),\n ...(m.label.trim() ? { label: m.label.trim() } : {}),\n mode: m.mode,\n permissionMode: m.permissionMode,\n restartOnUpdate: m.restartOnUpdate,\n scheduledDailyRestart: m.scheduledDailyRestart,\n ...(m.mode === 'on-demand' ? { onDemand: { keepaliveSeconds: Number(m.keepaliveSeconds) || 300, idleDefinition: 'no-activity' as const } } : {}),\n backoff: {\n schedule: csvSplit(m.backoffSchedule).map(Number).filter((n) => n > 0),\n resetAfterSeconds: Number(m.backoffResetAfterSeconds) || 600,\n },\n ...(m.channelId.trim() ? { binding: { type: 'channel' as const, channelId: m.channelId.trim() } } : {}),\n }\n if (!policy.backoff.schedule.length) policy.backoff.schedule = [5, 15, 60, 300]\n try {\n await api('PUT', '/spawn-policy/' + encodeURIComponent(policy.name), policy)\n set({ policyModal: { ...m, open: false } })\n await get().fetchManagedPolicies()\n } catch (e) { get().showError('Save Failed', (e as Error).message) }\n },\n deletePolicy(name) {\n get().openConfirm('Delete Policy', `Delete managed agent policy \"${name}\"? This will stop any running agent.`, async () => {\n try {\n await api('DELETE', '/spawn-policy/' + encodeURIComponent(name))\n await get().fetchManagedPolicies()\n } catch (e) { get().showError('Delete Failed', (e as Error).message) }\n })\n },\n async browsePolicyDirectory(path) {\n const orchId = get().policyModal.orchestratorId\n if (!orchId) return\n const browser = get().policyDirBrowser\n set({ policyDirBrowser: { ...browser, loading: true, error: '' } })\n try {\n const q = path ? '?path=' + encodeURIComponent(path) : ''\n const listing = await api<{ path: string; parent?: string; baseDir: string; entries: Array<{ name: string; path: string }> }>('GET', '/orchestrators/' + encodeURIComponent(orchId) + '/directories' + q)\n set({\n policyDirBrowser: { open: true, loading: false, path: listing.path || '', parent: listing.parent || '', baseDir: listing.baseDir || '', entries: listing.entries || [], error: '' },\n policyModal: { ...get().policyModal, cwd: listing.path || get().policyModal.cwd },\n })\n } catch (e) { set({ policyDirBrowser: { ...get().policyDirBrowser, loading: false, error: (e as Error).message } }) }\n },\n selectPolicyDirectory(path) {\n set({ policyModal: { ...get().policyModal, cwd: path || get().policyDirBrowser.path }, policyDirBrowser: { ...get().policyDirBrowser, open: false } })\n },\n\n openProfileModal(mode, profile) {\n const blank: AgentProfile = {\n name: '', description: '', provider: 'any', base: 'host',\n instructions: { system: '', append: [], repoInstructions: 'allow', globalInstructions: 'allow' },\n relay: { context: true, skills: true, plugins: true, statusLine: true, mcp: true },\n skills: [], plugins: [],\n mcp: { mode: 'host' }, hooks: { mode: 'host' },\n permissions: { filesystem: 'host' },\n env: {}, providerOptions: {},\n }\n let p: AgentProfile\n if (profile && mode === 'duplicate') {\n p = JSON.parse(JSON.stringify(profile))\n p.name = profile.name + '-copy'\n delete (p as any).builtIn\n } else if (profile && (mode === 'edit' || mode === 'view')) {\n p = JSON.parse(JSON.stringify(profile))\n } else {\n p = blank\n }\n set({ profileModal: { open: true, mode, profile: p } })\n },\n closeProfileModal() {\n set({ profileModal: { ...get().profileModal, open: false } })\n },\n updateProfileModal(partial) {\n const current = get().profileModal.profile\n set({ profileModal: { ...get().profileModal, profile: { ...current, ...partial } } })\n },\n async saveProfile() {\n const { mode, profile } = get().profileModal\n if (!profile.name.trim()) { get().showError('Validation', 'Profile name is required.'); return }\n if (mode === 'view') return\n try {\n await api('PUT', '/agent-profiles/' + encodeURIComponent(profile.name.trim()), profile)\n set({ profileModal: { ...get().profileModal, open: false } })\n await get().fetchAgentProfiles()\n get().showNotification(`Profile \"${profile.name}\" saved`)\n } catch (e) { get().showError('Save Failed', (e as Error).message) }\n },\n deleteProfile(name) {\n get().openConfirm('Delete Profile', `Delete agent profile \"${name}\"?`, async () => {\n try {\n await api('DELETE', '/agent-profiles/' + encodeURIComponent(name))\n await get().fetchAgentProfiles()\n get().showNotification(`Profile \"${name}\" deleted`)\n } catch (e) { get().showError('Delete Failed', (e as Error).message) }\n })\n },\n})\n","import { api } from '@/lib/api'\nimport { INBOX_OPERATOR_ID } from '@/lib/constants'\nimport type { ActivityEvent, ViewName } from '@/types'\nimport type { OperatorSlice, StoreSlice } from '../types'\n\nexport const createOperatorSlice: StoreSlice<OperatorSlice> = (set, get) => ({\n operatorActivity: [],\n\n recordOperatorActivity(input) {\n const item: ActivityEvent = {\n id: Date.now(),\n kind: 'operator',\n title: input.title || 'Activity',\n body: input.body,\n meta: input.meta,\n icon: input.icon,\n view: input.view,\n peer: input.peer,\n messageId: input.messageId,\n pairId: input.pairId,\n taskId: input.taskId,\n agentId: input.agentId,\n ts: Date.now(),\n clientId: 'op-' + Date.now(),\n createdAt: Date.now(),\n }\n set({ operatorActivity: [item, ...get().operatorActivity.slice(0, 79)] })\n api('POST', '/activity', {\n operatorId: INBOX_OPERATOR_ID, clientId: item.clientId, kind: item.kind,\n title: item.title, body: item.body, meta: item.meta, icon: item.icon,\n view: item.view, peer: item.peer, messageId: item.messageId,\n pairId: item.pairId, taskId: item.taskId, agentId: item.agentId,\n }).catch(() => {})\n },\n async openActivityItem(item) {\n if (item.view) await get().switchView((item.view === 'inbox' ? 'chat' : item.view) as ViewName)\n if (item.peer) get().openInboxThread(item.peer)\n if (item.agentId) {\n const agent = get().agentsById[item.agentId]\n if (agent) get().openAgentDetail(agent)\n }\n if (item.taskId) {\n const task = get().tasks.find((t) => t.id === item.taskId)\n if (task) await get().openTaskEvents(task)\n }\n },\n})\n","import { api } from '@/lib/api'\nimport { safeFilename, downloadText, toTimestamp } from '@/lib/display'\nimport type { ActivityEvent, TaskEvent } from '@/types'\nimport type { StoreSlice, TimelineSlice } from '../types'\n\nfunction timelineEventTime(event: ActivityEvent): number {\n return toTimestamp(event.createdAt ?? event.ts)\n}\n\nfunction renderTimelineMarkdown(events: ActivityEvent[], exportedAt: string): string {\n const lines = ['# Agent Relay Timeline', '', `Exported: ${exportedAt}`, `Events: ${events.length}`, '']\n for (const event of events) {\n const when = new Date(timelineEventTime(event)).toISOString()\n lines.push(`## ${event.title || event.kind || 'Event'}`)\n lines.push(`- When: ${when}`)\n if (event.kind) lines.push(`- Kind: ${event.kind}`)\n if (event.agentId) lines.push(`- Agent: ${event.agentId}`)\n if (event.peer) lines.push(`- Peer: ${event.peer}`)\n if (event.body) lines.push('', event.body)\n lines.push('')\n }\n return lines.join('\\n')\n}\n\nexport const createTimelineSlice: StoreSlice<TimelineSlice> = (set, get) => ({\n activityEvents: [],\n activityFilter: '',\n\n async fetchActivityEvents() {\n try {\n const events = await api<ActivityEvent[]>('GET', '/activity?limit=200')\n set({ activityEvents: events })\n } catch {}\n },\n\n exportActivity(format) {\n const s = get()\n const events = [...s.operatorActivity, ...s.activityEvents].sort((a, b) => timelineEventTime(b) - timelineEventTime(a))\n const exportedAt = new Date().toISOString()\n const filename = `agent-relay-timeline-${exportedAt.slice(0, 10)}.${format === 'json' ? 'json' : 'md'}`\n if (format === 'json') {\n downloadText(filename, JSON.stringify({ title: 'Agent Relay Timeline', exportedAt, events }, null, 2), 'application/json')\n } else {\n downloadText(filename, renderTimelineMarkdown(events, exportedAt), 'text/markdown')\n }\n },\n exportThread(thread, format) {\n const filename = `agent-relay-thread-${safeFilename(thread.peer)}.${format === 'json' ? 'json' : 'md'}`\n const data = { title: 'Thread: ' + thread.peer, importedHistory: thread.importedHistory || [], messages: thread.messages, exportedAt: new Date().toISOString() }\n downloadText(filename, JSON.stringify(data, null, 2), format === 'json' ? 'application/json' : 'text/markdown')\n },\n exportPair(pair, format) {\n const filename = `agent-relay-pair-${safeFilename(pair.id)}.${format === 'json' ? 'json' : 'md'}`\n const data = { title: 'Pair: ' + pair.id, pair, exportedAt: new Date().toISOString() }\n downloadText(filename, JSON.stringify(data, null, 2), format === 'json' ? 'application/json' : 'text/markdown')\n },\n async exportTask(task, format) {\n let events = get().taskEventCache[task.id] || []\n if (!events.length) {\n try { events = await api<TaskEvent[]>('GET', '/tasks/' + task.id + '/events'); set({ taskEventCache: { ...get().taskEventCache, [task.id]: events } }) } catch {}\n }\n const filename = `agent-relay-task-${task.id}.${format === 'json' ? 'json' : 'md'}`\n const data = { title: 'Task: ' + (task.title || '#' + task.id), task, events, exportedAt: new Date().toISOString() }\n downloadText(filename, JSON.stringify(data, null, 2), format === 'json' ? 'application/json' : 'text/markdown')\n },\n})\n","import { api } from '@/lib/api'\nimport type { AnalyticsPeriod, MaintenanceJob, MaintenanceJobRun, ViewName } from '@/types'\nimport type { OpsSlice, StoreSlice } from '../types'\n\nexport const createOpsSlice: StoreSlice<OpsSlice> = (set, get) => ({\n channels: [],\n connectors: [],\n integrations: [],\n automations: [],\n automationRuns: [],\n health: null,\n maintenanceJobs: [],\n analyticsPeriod: '24h' as AnalyticsPeriod,\n analyticsData: null,\n\n async fetchChannels() { try { set({ channels: await api('GET', '/channels') }) } catch {} },\n async fetchConnectors() { try { set({ connectors: await api('GET', '/connectors') }) } catch {} },\n async fetchIntegrations() { try { set({ integrations: await api('GET', '/integrations') }) } catch {} },\n async fetchAutomations() { try { set({ automations: await api('GET', '/automations') }) } catch {} },\n async fetchAutomationRuns(automationId) {\n try {\n const params = new URLSearchParams({ limit: '100' })\n if (automationId) params.set('automationId', automationId)\n set({ automationRuns: await api('GET', '/automation-runs?' + params.toString()) })\n } catch {}\n },\n async fetchHealth() { try { set({ health: await api('GET', '/health') }) } catch {} },\n async fetchMaintenanceJobs() { try { set({ maintenanceJobs: await api('GET', '/maintenance/jobs') }) } catch {} },\n async runMaintenanceJob(id) {\n try {\n const result = await api<{ run: MaintenanceJobRun; jobs: MaintenanceJob[] }>('POST', '/maintenance/jobs/' + encodeURIComponent(id) + '/run', {})\n set({ maintenanceJobs: result.jobs })\n get().showNotification(result.run.status === 'succeeded' ? 'Maintenance job completed' : 'Maintenance job skipped')\n return result.run\n } catch (e) {\n get().showError('Maintenance Job Failed', (e as Error).message)\n await get().fetchMaintenanceJobs()\n return null\n }\n },\n async runHealthAction(action) {\n if (action.preset) set({ agentPresetFilter: action.preset, showOffline: true })\n if (action.api && action.path) { await api(action.api, action.path); await get().refreshLiveData() }\n if (action.view) await get().switchView(action.view as ViewName)\n if (action.copy) try { await navigator.clipboard?.writeText(action.copy) } catch {}\n },\n async runConnectorAction(connectorId, action) {\n try {\n const result = await api<{ ok: boolean; stderr?: string; parsed?: unknown }>('POST', '/connectors/' + encodeURIComponent(connectorId) + '/actions', { action })\n await get().fetchConnectors()\n if (!result.ok) throw new Error(result.stderr || `${action} failed`)\n return result\n } catch (e) {\n get().showError('Connector Action Failed', (e as Error).message)\n throw e\n }\n },\n async fetchAnalytics() {\n try { set({ analyticsData: await api('GET', '/stats/analytics?period=' + get().analyticsPeriod) }) } catch {}\n },\n setAnalyticsPeriod(period) {\n set({ analyticsPeriod: period })\n void get().fetchAnalytics()\n },\n})\n","import { api } from '@/lib/api'\nimport type { WorkspaceRecord, WorkspaceGitStateResult, WorkspaceMergePreviewResult, WorkspaceDiffResult } from '@/types'\nimport type { StoreSlice, WorkspacesSlice } from '../types'\n\nexport const createWorkspacesSlice: StoreSlice<WorkspacesSlice> = (set, get) => ({\n workspaces: [],\n workspaceFocusId: null,\n workspaceGitState: {},\n workspaceMergePreview: {},\n workspaceDiff: {},\n workspaceOrphans: [],\n\n // Branch-state badge click-through (#236): jump to the Workspaces panel and\n // tell it which workspace to surface/highlight, solving \"can't find it among many\".\n async openWorkspaceFocus(workspaceId) {\n set({ workspaceFocusId: workspaceId })\n await get().switchView('workspaces')\n },\n async fetchWorkspaces() { try { set({ workspaces: await api<WorkspaceRecord[]>('GET', '/workspaces') }) } catch {} },\n async fetchWorkspaceGitState(workspaceId) {\n try {\n const state = await api<WorkspaceGitStateResult>('GET', '/workspaces/' + encodeURIComponent(workspaceId) + '/git-state')\n set((s) => ({ workspaceGitState: { ...s.workspaceGitState, [workspaceId]: state } }))\n } catch (e) {\n set((s) => ({ workspaceGitState: { ...s.workspaceGitState, [workspaceId]: { available: false, reason: (e as Error).message } } }))\n }\n },\n async fetchWorkspaceMergePreview(workspaceId) {\n try {\n const preview = await api<WorkspaceMergePreviewResult>('GET', '/workspaces/' + encodeURIComponent(workspaceId) + '/merge-preview')\n set((s) => ({ workspaceMergePreview: { ...s.workspaceMergePreview, [workspaceId]: preview } }))\n } catch (e) {\n set((s) => ({ workspaceMergePreview: { ...s.workspaceMergePreview, [workspaceId]: { available: false, reason: (e as Error).message } } }))\n }\n },\n async fetchWorkspaceDiff(workspaceId) {\n try {\n const diff = await api<WorkspaceDiffResult>('GET', '/workspaces/' + encodeURIComponent(workspaceId) + '/diff')\n set((s) => ({ workspaceDiff: { ...s.workspaceDiff, [workspaceId]: diff } }))\n } catch (e) {\n set((s) => ({ workspaceDiff: { ...s.workspaceDiff, [workspaceId]: { available: false, reason: (e as Error).message } } }))\n }\n },\n async fetchWorkspaceOrphans() {\n try {\n const res = await api<{ orphans: import('@/types').WorkspaceOrphan[] }>('GET', '/workspaces/orphans')\n set({ workspaceOrphans: res.orphans ?? [] })\n } catch { /* best-effort; panel just stays empty */ }\n },\n async reclaimWorkspaceOrphan(orphan) {\n get().openConfirm('Reclaim Orphan Worktree', `Remove the orphaned worktree \"${orphan.branch || orphan.worktreePath}\" from disk? It has no live agent.`, async () => {\n try {\n await api('POST', '/workspaces/orphans/reclaim', { worktreePath: orphan.worktreePath, repoRoot: orphan.repoRoot, branch: orphan.branch })\n get().showNotification('Orphan reclaim dispatched')\n await Promise.all([get().fetchWorkspaceOrphans(), get().fetchActivityEvents()])\n } catch (e) { get().showError('Reclaim Failed', (e as Error).message) }\n })\n },\n async workspaceAction(workspaceId, action) {\n const label = action === 'ready'\n ? 'Mark ready'\n : action === 'request-review'\n ? 'Request review'\n : action === 'merge-plan'\n ? 'Mark merge planned'\n : action === 'merge'\n ? 'Merge'\n : action === 'abandon'\n ? 'Abandon'\n : 'Cleanup'\n const run = async () => {\n try {\n await api('POST', '/workspaces/' + encodeURIComponent(workspaceId) + '/actions', { action })\n get().showNotification(action === 'cleanup' ? 'Workspace cleanup requested' : action === 'merge' ? 'Workspace merge dispatched' : `Workspace updated: ${label}`)\n await Promise.all([get().fetchWorkspaces(), get().fetchOrchestrators(), get().fetchActivityEvents()])\n } catch (e) { get().showError('Workspace Action Failed', (e as Error).message) }\n }\n if (action === 'cleanup' || action === 'abandon' || action === 'merge') {\n const workspace = get().workspaces.find((item) => item.id === workspaceId)\n const target = workspace?.branch || workspace?.worktreePath || workspaceId\n if (action === 'merge') {\n const preview = get().workspaceMergePreview[workspaceId]\n const mergeDetail = preview && preview.available !== false\n ? ` — ${preview.strategy === 'pr' ? 'opens a PR' : `rebases & fast-forwards into ${preview.baseRef || 'base'}, then deletes the branch`}.`\n : ' — lands the work and deletes the branch.'\n get().openConfirm('Merge Workspace', `Merge workspace \"${target}\"?${mergeDetail}`, run)\n return\n }\n if (action === 'cleanup') {\n // Destroy-guard: fetch live git state so the user sees what cleanup\n // will throw away before confirming the force-remove.\n await get().fetchWorkspaceGitState(workspaceId)\n const gs = get().workspaceGitState[workspaceId]\n let warn = ''\n if (gs && gs.available !== false && !gs.missing) {\n const ahead = gs.ahead ?? 0\n const dirty = gs.dirtyCount ?? 0\n if (ahead > 0 || dirty > 0) {\n const parts = [ahead > 0 ? `${ahead} unmerged commit(s)` : '', dirty > 0 ? `${dirty} uncommitted change(s)` : ''].filter(Boolean)\n warn = ` ⚠ This destroys ${parts.join(' and ')}.`\n }\n }\n get().openConfirm('Cleanup Workspace', `Remove the worktree for \"${target}\" on the host?${warn}`, run)\n return\n }\n get().openConfirm('Abandon Workspace', `Abandon workspace \"${target}\"?`, run)\n return\n }\n await run()\n },\n async purgeWorkspace(workspaceId) {\n const workspace = get().workspaces.find((item) => item.id === workspaceId)\n const target = workspace?.branch || workspace?.worktreePath || workspaceId\n get().openConfirm('Purge Workspace Record', `Permanently remove the record for \"${target}\"? This only clears the dashboard row — it does not touch disk.`, async () => {\n try {\n await api('DELETE', '/workspaces/' + encodeURIComponent(workspaceId))\n get().showNotification('Workspace record purged')\n await Promise.all([get().fetchWorkspaces(), get().fetchActivityEvents()])\n } catch (e) { get().showError('Purge Failed', (e as Error).message) }\n })\n },\n})\n","import { api } from '@/lib/api'\nimport type { Memory, MemoryInjectResult, MemoryQuery, MemorySearchResult } from '@/types'\nimport type { MemorySlice, StoreSlice } from '../types'\n\nexport const createMemorySlice: StoreSlice<MemorySlice> = (set, get) => ({\n memories: [],\n memoryTotal: 0,\n memoryBrokerInfo: null,\n memoryStats: null,\n memoryFilters: { search: '', type: '', scope: '', tags: '', visibility: '', minRelevance: '0' },\n selectedMemoryId: '',\n memoryLoading: false,\n\n async refreshMemory() {\n await Promise.all([get().fetchMemoryBroker(), get().fetchMemoryStats(), get().fetchMemories()])\n },\n async fetchMemoryBroker() {\n try { set({ memoryBrokerInfo: await api('GET', '/memories/broker') }) }\n catch (e) { get().showError('Memory Broker Failed', (e as Error).message) }\n },\n async fetchMemoryStats() {\n try { set({ memoryStats: await api('GET', '/memories/stats') }) }\n catch {}\n },\n async fetchMemories() {\n const filters = get().memoryFilters\n const query: MemoryQuery = { limit: 100 }\n if (filters.type) query.type = filters.type as MemoryQuery['type']\n if (filters.scope.trim()) query.scope = filters.scope.trim()\n if (filters.visibility) query.visibility = filters.visibility as MemoryQuery['visibility']\n if (filters.tags.trim()) query.tags = filters.tags.split(',').map((tag) => tag.trim()).filter(Boolean)\n if (filters.minRelevance.trim() !== '') {\n const relevance = Number(filters.minRelevance)\n if (Number.isFinite(relevance)) query.minRelevance = Math.max(0, Math.min(1, relevance))\n }\n set({ memoryLoading: true })\n try {\n const result = await api<MemorySearchResult>('POST', '/memories/search', query)\n const selectedMemoryId = result.memories.some((m) => m.id === get().selectedMemoryId) ? get().selectedMemoryId : (result.memories[0]?.id || '')\n set({ memories: result.memories, memoryTotal: result.total, selectedMemoryId })\n } catch (e) {\n get().showError('Memory Search Failed', (e as Error).message)\n } finally {\n set({ memoryLoading: false })\n }\n },\n async saveMemory(input, id) {\n try {\n const saved = id\n ? await api<Memory>('PATCH', '/memories/' + encodeURIComponent(id), input)\n : await api<Memory>('POST', '/memories', input)\n set({ selectedMemoryId: saved.id })\n await Promise.all([get().fetchMemories(), get().fetchMemoryStats()])\n get().showNotification(id ? 'Memory updated' : 'Memory created')\n } catch (e) { get().showError('Memory Save Failed', (e as Error).message) }\n },\n deleteMemory(id) {\n get().openConfirm('Delete Memory', `Delete memory \"${id}\"?`, async () => {\n try {\n await api('DELETE', '/memories/' + encodeURIComponent(id))\n set({ selectedMemoryId: '' })\n await Promise.all([get().fetchMemories(), get().fetchMemoryStats()])\n get().showNotification('Memory deleted')\n } catch (e) { get().showError('Delete Failed', (e as Error).message) }\n })\n },\n async injectMemory(input) {\n try {\n const result = await api<MemoryInjectResult>('POST', '/memories/inject', input)\n get().showNotification(`Memory inject command sent to ${input.agentId}`)\n return result\n } catch (e) {\n get().showError('Memory Inject Failed', (e as Error).message)\n return null\n }\n },\n})\n","import { create } from 'zustand'\nimport { persist } from 'zustand/middleware'\nimport type { RelayStore } from './types'\nimport { createConnectionSlice } from './slices/connection'\nimport { createAgentsSlice } from './slices/agents'\nimport { createChatSlice } from './slices/chat'\nimport { createWorkSlice } from './slices/work'\nimport { createSpawnSlice } from './slices/spawn'\nimport { createManagedSlice } from './slices/managed'\nimport { createNotificationsSlice } from './slices/notifications'\nimport { createOperatorSlice } from './slices/operator'\nimport { createTimelineSlice } from './slices/timeline'\nimport { createVoiceSlice, syncVoiceActiveChat } from './slices/voice'\nimport { createOpsSlice } from './slices/ops'\nimport { createWorkspacesSlice } from './slices/workspaces'\nimport { createMemorySlice } from './slices/memory'\n\n// Re-exports preserve the public `@/store` surface used across the dashboard.\nexport { useClock, useNow, useNowBucket } from '@/store/clock'\nexport type { ChatStatusEvent, RelayStore } from './types'\n\n// The store is assembled from per-domain slices (store/slices/*). Each slice is a\n// standard Zustand StateCreator `(set, get) => ({...})`; they all share the one\n// RelayStore type, so any slice can `get()` the whole store and `set()` any field.\n// Correctness-sensitive pure helpers (poll-merge identity, active-chat predicate,\n// compact/clear status derivation) live once in store/merge.ts — never per-slice.\nexport const useRelayStore = create<RelayStore>()(\n persist(\n (...a) => ({\n ...createConnectionSlice(...a),\n ...createAgentsSlice(...a),\n ...createChatSlice(...a),\n ...createWorkSlice(...a),\n ...createSpawnSlice(...a),\n ...createManagedSlice(...a),\n ...createNotificationsSlice(...a),\n ...createOperatorSlice(...a),\n ...createTimelineSlice(...a),\n ...createVoiceSlice(...a),\n ...createOpsSlice(...a),\n ...createWorkspacesSlice(...a),\n ...createMemorySlice(...a),\n }),\n {\n name: 'agent-relay-dashboard',\n partialize: (state) => ({\n theme: state.theme,\n view: state.view,\n showOffline: state.showOffline,\n showBuiltIns: state.showBuiltIns,\n showReasoning: state.showReasoning,\n autoRefresh: state.autoRefresh,\n voiceTtsEnabled: state.voiceTtsEnabled,\n voiceTtsLang: state.voiceTtsLang,\n voiceTtsMode: state.voiceTtsMode,\n voiceTtsKokoroVoice: state.voiceTtsKokoroVoice,\n voiceTtsBrowserVoice: state.voiceTtsBrowserVoice,\n voiceInputMode: state.voiceInputMode,\n agentSort: state.agentSort,\n agentSortDir: state.agentSortDir,\n agentPresetFilter: state.agentPresetFilter,\n agentStatusFilter: state.agentStatusFilter,\n agentTagFilter: state.agentTagFilter,\n agentHostFilter: state.agentHostFilter,\n pairStatusFilter: state.pairStatusFilter,\n inboxSort: state.inboxSort,\n inboxSortDir: state.inboxSortDir,\n inboxShowArchived: state.inboxShowArchived,\n chatAgentProviderFilter: state.chatAgentProviderFilter,\n chatAgentStatusFilter: state.chatAgentStatusFilter,\n chatAgentTagFilter: state.chatAgentTagFilter,\n chatAgentCapFilter: state.chatAgentCapFilter,\n chatAgentHostFilter: state.chatAgentHostFilter,\n chatAgentSort: state.chatAgentSort,\n chatAgentSortDir: state.chatAgentSortDir,\n chatAgentGroupBy: state.chatAgentGroupBy,\n chatAgentFiltersCollapsed: state.chatAgentFiltersCollapsed,\n activityFilter: state.activityFilter,\n analyticsPeriod: state.analyticsPeriod,\n memoryFilters: state.memoryFilters,\n authToken: state.authToken,\n inboxReadCursors: state.inboxReadCursors,\n inboxArchivedThreads: state.inboxArchivedThreads,\n inboxDrafts: state.inboxDrafts,\n chatStatusEvents: state.chatStatusEvents,\n operatorActivity: state.operatorActivity,\n notifications: state.notifications,\n notificationUnread: state.notificationUnread,\n notificationSettings: state.notificationSettings,\n spawnOrchId: state.spawnOrchId,\n spawnProvider: state.spawnProvider,\n spawnModel: state.spawnModel,\n spawnEffort: state.spawnEffort,\n spawnProfile: state.spawnProfile,\n spawnCwd: state.spawnCwd,\n spawnApproval: state.spawnApproval,\n spawnWorkspaceMode: state.spawnWorkspaceMode,\n spawnCwdHistory: state.spawnCwdHistory,\n }),\n },\n ),\n)\n\n// Keep the browser TTS controller's \"active chat\" in sync with navigation. This\n// is an external-system subscription (the speechSynthesis engine), not derived\n// React state — so it lives here, driven by the store, not by a component effect.\nuseRelayStore.subscribe(syncVoiceActiveChat)\n"],"x_google_ignoreList":[0,1,2],"mappings":"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"}
|