From 4718feb7733126e1a7499f886dac9272f179b097 Mon Sep 17 00:00:00 2001 From: Nico Date: Wed, 1 Apr 2026 00:17:51 +0200 Subject: [PATCH] Remove vite-ssg temp from tracking --- .gitignore | 1 + .../eyyt8tgg8y/assets/AgentsView-CFS236kk.js | 2324 ------------- .../eyyt8tgg8y/assets/CompanyView-9MVdsTPz.js | 66 - .../assets/DatenschutzView-CmUxA-7Z.js | 50 - .../eyyt8tgg8y/assets/DevView-CqaEvdwT.js | 738 ----- .../assets/ImpressumView-B77dj09a.js | 50 - .../eyyt8tgg8y/assets/ViewerView-5go7ZmZ8.js | 445 --- .vite-ssg-temp/eyyt8tgg8y/favicon-eras.svg | 11 - .vite-ssg-temp/eyyt8tgg8y/favicon-loop42.svg | 9 - .vite-ssg-temp/eyyt8tgg8y/favicon-titan.svg | 12 - .vite-ssg-temp/eyyt8tgg8y/favicon.svg | 12 - .../ubuntu-sans/UbuntuSans-Italic[wght].woff2 | Bin 39052 -> 0 bytes .../fonts/ubuntu-sans/UbuntuSans[wght].woff2 | Bin 24280 -> 0 bytes .vite-ssg-temp/eyyt8tgg8y/main.mjs | 2890 ----------------- 14 files changed, 1 insertion(+), 6607 deletions(-) delete mode 100644 .vite-ssg-temp/eyyt8tgg8y/assets/AgentsView-CFS236kk.js delete mode 100644 .vite-ssg-temp/eyyt8tgg8y/assets/CompanyView-9MVdsTPz.js delete mode 100644 .vite-ssg-temp/eyyt8tgg8y/assets/DatenschutzView-CmUxA-7Z.js delete mode 100644 .vite-ssg-temp/eyyt8tgg8y/assets/DevView-CqaEvdwT.js delete mode 100644 .vite-ssg-temp/eyyt8tgg8y/assets/ImpressumView-B77dj09a.js delete mode 100644 .vite-ssg-temp/eyyt8tgg8y/assets/ViewerView-5go7ZmZ8.js delete mode 100644 .vite-ssg-temp/eyyt8tgg8y/favicon-eras.svg delete mode 100644 .vite-ssg-temp/eyyt8tgg8y/favicon-loop42.svg delete mode 100644 .vite-ssg-temp/eyyt8tgg8y/favicon-titan.svg delete mode 100644 .vite-ssg-temp/eyyt8tgg8y/favicon.svg delete mode 100644 .vite-ssg-temp/eyyt8tgg8y/fonts/ubuntu-sans/UbuntuSans-Italic[wght].woff2 delete mode 100644 .vite-ssg-temp/eyyt8tgg8y/fonts/ubuntu-sans/UbuntuSans[wght].woff2 delete mode 100644 .vite-ssg-temp/eyyt8tgg8y/main.mjs diff --git a/.gitignore b/.gitignore index 1f6f14d..5cce96d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ node_modules dist .env.local +.vite-ssg-temp diff --git a/.vite-ssg-temp/eyyt8tgg8y/assets/AgentsView-CFS236kk.js b/.vite-ssg-temp/eyyt8tgg8y/assets/AgentsView-CFS236kk.js deleted file mode 100644 index 28df8fb..0000000 --- a/.vite-ssg-temp/eyyt8tgg8y/assets/AgentsView-CFS236kk.js +++ /dev/null @@ -1,2324 +0,0 @@ -import { ref, triggerRef, watch, computed, nextTick, onUnmounted, defineComponent, mergeProps, useSSRContext, createSlots, withCtx, openBlock, createBlock, createCommentVNode, toDisplayString, Fragment, renderList, createVNode, unref, createTextVNode, resolveDynamicComponent, withModifiers, onUpdated, toRef, onMounted, resolveComponent } from "vue"; -import { ssrRenderAttrs, ssrRenderSlot, ssrRenderComponent, ssrRenderAttr, ssrInterpolate, ssrRenderList, ssrRenderVNode, ssrRenderClass, ssrIncludeBooleanAttr, ssrRenderStyle } from "vue/server-renderer"; -import { useRouter, useRoute } from "vue-router"; -import { u as useChatStore, w as ws, a as agents, g as getApiBase, b as auth, _ as _export_sfc, c as useTtsPlayer, d as useUI, e as agentLogo, s as scrollbarOptions } from "../main.mjs"; -import { marked } from "marked"; -import { OverlayScrollbarsComponent } from "overlayscrollbars-vue"; -import { BoltIcon, ComputerDesktopIcon, CpuChipIcon, GlobeAltIcon, DocumentPlusIcon, WrenchIcon, PencilIcon, BookOpenIcon, ChatBubbleLeftIcon, LinkIcon, Cog6ToothIcon, SpeakerWaveIcon, ExclamationTriangleIcon, ChevronDownIcon, InformationCircleIcon, LockClosedIcon, UserGroupIcon, ChatBubbleBottomCenterTextIcon, PaperClipIcon, MicrophoneIcon, StopIcon, ArrowUpIcon } from "@heroicons/vue/20/solid"; -import "@unhead/vue/server"; -import "pinia"; -import "@heroicons/vue/24/outline"; -import "overlayscrollbars"; -const VISIBLE_PAGE$1 = 50; -const MAX_HUD_NODES = 100; -function useSessionHistory(isAgentRunning, visibleCount, agentIdFn) { - const store = useChatStore(); - const sessionHistoryComplete = ref(false); - const lastUsage = ref(null); - let loadStartTime = null; - let pendingMessages = []; - let pendingUsageTotals = null; - const lastSystemMsgRef = ref(null); - const hudTree = ref([]); - const hudVersion = ref(0); - const hudPending = /* @__PURE__ */ new Map(); - const hudTurns = /* @__PURE__ */ new Map(); - const toolCallMap = /* @__PURE__ */ new Map(); - function lookupByToolCallId(toolCallId) { - if (!toolCallId) return null; - const ref2 = toolCallMap.get(toolCallId); - if (!ref2) return null; - const node = ref2.deref(); - if (!node) { - toolCallMap.delete(toolCallId); - return null; - } - return node; - } - const activeTurnCorrId = ref(null); - function makeNode(partial) { - return { - id: partial.id || crypto.randomUUID(), - type: partial.type || "received", - state: partial.state || "running", - label: partial.label || "", - children: [], - replay: partial.replay ?? false, - startedAt: partial.startedAt || Date.now(), - ...partial - }; - } - function findNode(nodes, corrId) { - for (const n of nodes) { - if (n.correlationId === corrId) return n; - if (n.children) { - const found = findNode(n.children, corrId); - if (found) return found; - } - } - return null; - } - function addHudNode(node, parentCorrelationId) { - if (parentCorrelationId && parentCorrelationId !== "history") { - const parent = hudTurns.get(parentCorrelationId); - if (parent) { - parent.children.push(node); - triggerRef(hudTree); - hudVersion.value++; - return; - } - } - hudTree.value.unshift(node); - if (hudTree.value.length > MAX_HUD_NODES) hudTree.value.splice(MAX_HUD_NODES); - triggerRef(hudTree); - hudVersion.value++; - } - function pushHudEvent(event) { - const replay = !!event.replay; - const ts = event.ts || Date.now(); - const corrId = event.correlationId; - const parentId = event.parentId; - switch (event.event) { - case "turn_start": { - if (corrId && (hudPending.has(corrId) || hudTurns.has(corrId))) break; - const node = makeNode({ - type: "turn", - state: "running", - label: "πŸ”„ Turn", - correlationId: corrId, - startedAt: ts, - replay - }); - if (corrId) { - hudPending.set(corrId, node); - hudTurns.set(corrId, node); - } - if (!replay && corrId) activeTurnCorrId.value = corrId; - addHudNode(node); - break; - } - case "turn_end": { - const node = corrId ? hudPending.get(corrId) : null; - if (node) { - node.state = "done"; - node.endedAt = ts; - node.durationMs = event.durationMs; - if (corrId) { - hudPending.delete(corrId); - hudTurns.delete(corrId); - } - triggerRef(hudTree); - hudVersion.value++; - } - if (!replay && corrId && activeTurnCorrId.value === corrId) activeTurnCorrId.value = null; - break; - } - case "think_start": { - const node = makeNode({ - type: "think", - state: "running", - label: "Thinking", - correlationId: corrId, - startedAt: ts, - replay - }); - if (corrId) hudPending.set(corrId, node); - addHudNode(node, parentId); - break; - } - case "think_end": { - const node = corrId ? hudPending.get(corrId) : null; - if (node) { - node.state = "done"; - node.endedAt = ts; - node.durationMs = event.durationMs; - if (corrId) hudPending.delete(corrId); - triggerRef(hudTree); - hudVersion.value++; - } else { - addHudNode(makeNode({ type: "think", state: "done", label: "Thinking", correlationId: corrId, startedAt: ts, endedAt: ts, durationMs: event.durationMs, replay }), parentId); - } - break; - } - case "tool_start": { - const tool = event.tool || "unknown"; - const args = event.args || {}; - const label = buildToolLabel(tool, args); - const node = makeNode({ - type: "tool", - state: "running", - label, - tool, - args, - correlationId: corrId, - startedAt: ts, - replay - }); - if (corrId) hudPending.set(corrId, node); - if (event.toolCallId) toolCallMap.set(event.toolCallId, new WeakRef(node)); - addHudNode(node, parentId); - lastSystemMsgRef.value = label; - break; - } - case "tool_end": { - const tool = event.tool || "unknown"; - const result = event.result || {}; - let node = lookupByToolCallId(event.toolCallId) ?? (corrId ? hudPending.get(corrId) : null); - if (!node && parentId) { - const turnNode = findNode(hudTree.value, parentId); - if (turnNode?.children) { - const match = turnNode.children.find( - (n) => n.type === "tool" && n.state === "running" && (n.tool === tool || n.tool === "unknown") - ); - if (match) { - node = match; - if (match.correlationId) hudPending.delete(match.correlationId); - } - } - } - if (node) { - node.state = result.ok === false ? "error" : "done"; - node.result = result; - node.endedAt = ts; - node.durationMs = event.durationMs; - node.label = buildToolLabel(tool, node.args || {}, result); - if (corrId) hudPending.delete(corrId); - if (event.toolCallId) toolCallMap.delete(event.toolCallId); - triggerRef(hudTree); - hudVersion.value++; - } else { - const label = buildToolLabel(tool, event.args || {}, result); - addHudNode(makeNode({ type: "tool", state: "done", label, tool, result, correlationId: corrId, startedAt: ts, endedAt: ts, durationMs: event.durationMs, replay }), parentId); - } - break; - } - case "received": { - const node = makeNode({ - type: "received", - state: "done", - subtype: event.subtype, - label: event.label || event.subtype || "received", - startedAt: ts, - endedAt: ts, - replay - }); - addHudNode(node); - break; - } - } - } - function buildToolLabel(tool, args, result) { - const fileTools = ["read", "write", "edit", "append"]; - if (fileTools.includes(tool)) { - const vp = args.viewerPath || args.path || ""; - const filename = vp.split("/").pop() || vp; - const area = result?.area || args.area; - const areaStr = area ? `:L${area.startLine}–${area.endLine}` : ""; - return `${filename}${areaStr}`; - } - if (tool === "exec") { - const cmd = args.command || ""; - return `${cmd.slice(0, 60)}${cmd.length > 60 ? "…" : ""}`; - } - if (tool === "web_fetch") return (args.url || "").slice(0, 60); - if (tool === "web_search") return (args.query || "").slice(0, 60); - return tool; - } - function getToolsForTurn(corrId) { - if (!corrId) return []; - const turn = hudTree.value.find((n) => n.correlationId === corrId) ?? [...hudTurns.values()].find((n) => n.correlationId === corrId); - return turn ? turn.children.filter((c) => c.type === "tool") : []; - } - function hudSnapshot() { - const lines = [`HUD tree β€” ${hudTree.value.length} root node(s) -`]; - for (const node of hudTree.value) { - const dur = node.durationMs != null ? ` [${node.durationMs}ms]` : ""; - const repl = node.replay ? " (replay)" : ""; - lines.push(` ${node.state === "running" ? "⏳" : node.state === "error" ? "❌" : "βœ…"} [${node.type}] ${node.label}${dur}${repl}`); - lines.push(` id=${node.id.slice(0, 8)} corrId=${(node.correlationId || "β€”").slice(0, 8)} children=${node.children.length}`); - for (const child of node.children) { - const cdur = child.durationMs != null ? ` [${child.durationMs}ms]` : ""; - lines.push(` ${child.state === "running" ? "⏳" : child.state === "error" ? "❌" : "βœ…"} [${child.type}] ${child.label}${cdur}`); - if (child.args) lines.push(` args: ${JSON.stringify(child.args).slice(0, 80)}`); - if (child.result) lines.push(` result: ${JSON.stringify(child.result).slice(0, 80)}`); - } - } - return lines.join("\n"); - } - function pushSystem(text) { - lastSystemMsgRef.value = text; - } - function flushPendingClear(pendingClearRef) { - if (!pendingClearRef.value) return; - pendingClearRef.value = false; - store.clearMessages(); - visibleCount.value = VISIBLE_PAGE$1; - sessionHistoryComplete.value = false; - loadStartTime = performance.now(); - pendingMessages = []; - pendingUsageTotals = null; - } - function revealMessages() { - loadStartTime = null; - const _pending = pendingMessages; - const _usage = pendingUsageTotals; - pendingMessages = []; - pendingUsageTotals = null; - const idx = store.messages.findIndex((m) => m.role === "system" && m.content.includes("Loading session history...")); - if (idx !== -1) { - store.messages.splice(idx, 1, ..._pending); - } else { - store.messages.unshift(..._pending); - } - const revealedCount = _pending.filter((m) => m.role !== "system").length; - store.sessionContextHint = revealedCount > 0 ? `${revealedCount} msgs in context` : "fresh context"; - if (_usage) lastUsage.value = _usage; - } - function handleSessionHistory(entries) { - if (!entries?.length) return; - if (loadStartTime === null) loadStartTime = performance.now(); - if (!store.messages.some((m) => m.content?.includes("Loading session history..."))) { - store.pushSystem("⏳ Loading session history...", agentIdFn()); - } - const newMsgs = []; - const currentAgentId = agentIdFn(); - const currentSessionId = store.localSessionId; - let pendingUsage = null; - for (const data of entries) { - if (data.type === "hud") { - pushHudEvent({ ...data, replay: true }); - continue; - } - if (data.event === "tool_start" || data.event === "tool_end" || data.event === "think_start" || data.event === "think_end" || data.event === "turn_start" || data.event === "turn_end" || data.event === "received") { - pushHudEvent({ ...data, replay: true }); - continue; - } - if (data.entry_type === "session_context") { - newMsgs.push({ role: "session_context", content: data.content || "", agentId: currentAgentId, sessionId: currentSessionId }); - } else if (data.entry_type === "user_message") { - newMsgs.push({ role: "user", content: data.content || "", agentId: currentAgentId, sessionId: currentSessionId }); - } else if (data.entry_type === "assistant_text") { - const content = (data.content || "").replace(/^\[\[reply_to[^\]]*\]\]\s*/i, "").trim(); - if (!content) continue; - const msg = { role: "assistant", content, streaming: false, agentId: currentAgentId, sessionId: currentSessionId, timestamp: data.ts || null }; - if (data.truncated) msg.truncated = true; - if (pendingUsage) { - msg.usage = pendingUsage; - pendingUsage = null; - } - newMsgs.push(msg); - } else if (data.entry_type === "usage") { - pendingUsage = { - input_tokens: data.input_tokens || 0, - output_tokens: data.output_tokens || 0, - total_tokens: data.total_tokens || 0, - cost: Number(data.cost || 0) - }; - const last = newMsgs[newMsgs.length - 1]; - if (last?.role === "assistant") { - last.usage = pendingUsage; - pendingUsage = null; - } - } - } - pendingMessages = newMsgs; - const totalUsage = entries.filter((e) => e.entry_type === "usage").reduce((acc, e) => ({ - input_tokens: acc.input_tokens + (e.input_tokens || 0), - output_tokens: acc.output_tokens + (e.output_tokens || 0), - total_tokens: acc.total_tokens + (e.total_tokens || 0), - cost: acc.cost + Number(e.cost || 0) - }), { input_tokens: 0, output_tokens: 0, total_tokens: 0, cost: 0 }); - pendingUsageTotals = totalUsage.total_tokens > 0 ? totalUsage : null; - } - function handleSessionEntry(data, sentMessages, pushSystemFn) { - if (data.type === "hud") { - pushHudEvent(data); - return; - } - const isReplay = !sessionHistoryComplete.value; - const currentAgentId = agentIdFn(); - const currentSessionId = store.localSessionId; - switch (data.entry_type) { - case "user_message": { - const raw = data.content || ""; - if (raw.startsWith("A new session was started")) break; - if (!isReplay && raw.includes("[voice transcript]:")) break; - const hasByMsgId = data.msgId && store.messages.some((m) => m.msgId === data.msgId); - if (hasByMsgId) break; - if (!isReplay && !sentMessages.has(raw.trim())) { - store.messages.push({ role: "user", content: raw, agentId: currentAgentId, sessionId: currentSessionId, msgId: data.msgId }); - } else { - sentMessages.delete(raw.trim()); - } - break; - } - } - } - function resetHudMaps() { - hudPending.clear(); - hudTurns.clear(); - toolCallMap.clear(); - activeTurnCorrId.value = null; - hudTree.value = []; - hudVersion.value++; - } - function toolCallMapSnapshot() { - return [...toolCallMap.entries()].map(([k, ref2]) => { - const node = ref2.deref(); - return { toolCallId: k, label: node?.label ?? null, state: node?.state ?? null, stale: !node }; - }); - } - return { - sessionHistoryComplete, - lastUsage, - lastSystemMsgRef, - hudTree, - hudVersion, - activeTurnCorrId, - getToolsForTurn, - pushHudEvent, - hudSnapshot, - toolCallMapSnapshot, - resetHudMaps, - flushPendingClear, - revealMessages, - handleSessionHistory, - handleSessionEntry, - pushSystem - }; -} -function useAgentSocket(visibleCount, lastUsage, pendingClearRef, sentMessages, restoreLastSent) { - const chatStore = useChatStore(); - const { send: wsSend, onMessage: onWsMessage, replayBuffer } = ws; - const { updateFromServer, selectedAgent } = agents; - const handoverInProgress = () => chatStore.smState === "HANDOVER_PENDING" || chatStore.smState === "HANDOVER_DONE"; - const isAgentRunning = () => chatStore.smState === "AGENT_RUNNING"; - const history = useSessionHistory(isAgentRunning, visibleCount, () => selectedAgent.value); - history.lastUsage = lastUsage; - watch(history.activeTurnCorrId, (id) => { - chatStore.activeTurnCorrId = id; - }); - function pushSystem(text) { - history.pushSystem(text); - } - function mount() { - const handlers = { - auth_ok(data) { - updateFromServer(data); - }, - ready(data) { - updateFromServer(data); - if (data.session_id) chatStore.sessionKey = data.session_id; - else if (data.sessionId) chatStore.sessionKey = data.sessionId; - chatStore.applyConnectionState("SYNCED"); - chatStore.applyChannelState("READY"); - }, - // assay session info β€” store session ID for reconnect - session_info(data) { - if (data.session_id) chatStore.sessionKey = data.session_id; - }, - // assay UI controls β€” store for later rendering - controls(_data) { - }, - // assay artifacts β€” store for later rendering - artifacts(_data) { - }, - // assay session cleared - cleared(_data) { - chatStore.messages.splice(0); - }, - thinking(data) { - if (!handoverInProgress()) chatStore.appendThinking(data.content); - }, - delta(data) { - if (!handoverInProgress()) { - history.flushPendingClear(pendingClearRef); - chatStore.collapseThinking(); - chatStore.appendAssistantDelta(data.content, data.agentId); - } - }, - message(data) { - if (handoverInProgress()) return; - history.flushPendingClear(pendingClearRef); - if (data.streaming === false) { - chatStore.createCompleteAssistantMessage(data.content, data.agentId, data.usage); - } else if (data.final) { - chatStore.finalizeAssistantMessage(null, data.usage); - } - }, - truncated_warning(_data) { - chatStore.collapseThinking(); - if (chatStore.hasActiveStreamingMessage()) chatStore.finalizeAssistantMessage(null, void 0, true); - chatStore.truncatedWarning = true; - }, - done(data) { - if (handoverInProgress()) return; - chatStore.collapseThinking(); - if (data.suppress) { - chatStore.suppressAssistantMessage(); - } else { - const doneContent = data.content || null; - if (chatStore.hasActiveStreamingMessage()) { - const deltaLen = chatStore.streamingMessageLength(); - const useContent = doneContent && deltaLen < doneContent.length ? doneContent : null; - chatStore.finalizeAssistantMessage(useContent, data.usage); - } else if (doneContent) { - chatStore.createCompleteAssistantMessage(doneContent, void 0, data.usage); - } - } - history.lastSystemMsgRef.value = null; - }, - session_history(data) { - if (chatStore.hasActiveStreamingMessage()) chatStore.finalizeAssistantMessage(null); - chatStore.collapseThinking(); - history.flushPendingClear(pendingClearRef); - history.handleSessionHistory(data.entries); - }, - hud(data) { - history.pushHudEvent(data); - if (data.event === "turn_start" && !data.replay) { - chatStore.activeTurnCorrId = data.correlationId ?? null; - chatStore.startNewAssistantMessage(selectedAgent.value); - } - }, - event(data) { - if (data.event === "agent") { - const stream = data.payload?.stream; - if (stream === "tool") { - console.log("[HUD agent/tool]", JSON.stringify(data.payload).slice(0, 400)); - } - } - }, - tool(data) { - if (data.action === "call") { - pushSystem(`${data.tool} ${data.args || ""}`); - } else if (data.action === "result") { - pushSystem(`β†’ ${data.result || ""}`); - } - }, - session_entry(data) { - history.handleSessionEntry(data, sentMessages, pushSystem); - }, - message_update(data) { - if (!data.msgId || !data.patch) return; - const patch = { ...data.patch }; - if (patch.voiceAudioUrl) { - const token = localStorage.getItem("nyx_session") || localStorage.getItem("titan_token") || ""; - patch.voiceAudioUrl = `${patch.voiceAudioUrl}?token=${encodeURIComponent(token)}`; - } - if (patch.transcript) { - sentMessages.add(`[voice transcript]: ${patch.transcript}`.trim()); - } - const patched = chatStore.patchMessage(data.msgId, patch); - if (!patched) { - console.warn("[message_update] no message found for msgId:", data.msgId); - } - }, - handover_done(data) { - chatStore.messages.push({ - role: "assistant", - content: data.content || "πŸ“‹ Handover written.", - agentId: selectedAgent.value, - sessionId: chatStore.localSessionId - }); - chatStore.messages.push({ - role: "system", - content: "Start a new session with this handover context?", - confirmNew: true, - confirmed: false, - agentId: selectedAgent.value, - sessionId: chatStore.localSessionId - }); - }, - handover_context(_data) { - }, - // New two-SM protocol: channel_state + connection_state - channel_state(data) { - if (!data.state) return; - if (data.clear_history) { - console.log("[clear] channel switch", { state: data.state, msgCount: chatStore.messages.length }); - history.resetHudMaps(); - chatStore.messages.length = 0; - pendingClearRef.value = false; - } - const prevChannel = chatStore.channelState; - chatStore.applyChannelState(data.state); - if (data.state === "READY" || data.state === "FRESH") { - history.lastSystemMsgRef.value = null; - if (chatStore.queuedThought !== null && prevChannel === "AGENT_RUNNING") { - const thought = chatStore.queuedThought; - chatStore.queuedThought = null; - wsSend({ type: "message", content: thought }); - } - } - }, - connection_state(data) { - if (!data.state) return; - chatStore.applyConnectionState(data.state); - if (data.state === "LOADING_HISTORY") { - history.resetHudMaps(); - chatStore.messages.length = 0; - pendingClearRef.value = false; - } - if (data.state === "SYNCED") { - history.flushPendingClear(pendingClearRef); - history.revealMessages(); - } - }, - // Legacy: still handle session_state for backward compat - session_state(data) { - if (!data.state) return; - if (data.reconnected) ; - if (data.reconnected || data.clear_history) { - console.log("[clear] immediate flush", { reconnected: data.reconnected, clear_history: data.clear_history, state: data.state, msgCount: chatStore.messages.length }); - chatStore.stashMessages(); - history.resetHudMaps(); - chatStore.messages.length = 0; - pendingClearRef.value = false; - } - chatStore.applySessionState(data.state); - if (data.state === "READY" || data.state === "FRESH" || data.state === "IDLE") { - history.lastSystemMsgRef.value = null; - if (chatStore.queuedThought !== null) { - const thought = chatStore.queuedThought; - chatStore.queuedThought = null; - wsSend({ type: "message", content: thought }); - } - } - }, - session_total_tokens(data) { - chatStore.sessionTotalTokens = data; - }, - finance_update(data) { - chatStore.finance = data; - }, - usage(data) { - if (!handoverInProgress()) { - chatStore.sessionTotalTokens = { - input_tokens: data.input_tokens || (chatStore.sessionTotalTokens?.input_tokens || 0), - cache_read_tokens: data.cache_read_tokens || (chatStore.sessionTotalTokens?.cache_read_tokens || 0), - output_tokens: data.output_tokens || (chatStore.sessionTotalTokens?.output_tokens || 0) - }; - } - }, - session_status(data) { - if (data.status === "no_session") { - pendingClearRef.value = true; - history.flushPendingClear(pendingClearRef); - chatStore.messages.push({ - role: "system", - type: "no_session", - content: "-- NO SESSION --", - agentId: selectedAgent.value, - sessionId: chatStore.localSessionId - }); - chatStore.sessionContextHint = ""; - } else if (data.status === "watching") { - history.flushPendingClear(pendingClearRef); - history.sessionHistoryComplete.value = true; - history.revealMessages(); - } - }, - sent(_data) { - }, - switch_ok(data) { - history.sessionHistoryComplete.value = false; - if (data.sessionKey) chatStore.sessionKey = data.sessionKey; - }, - new_ok(_data) { - history.sessionHistoryComplete.value = false; - }, - error(data) { - if (data.code === "SESSION_TERMINATED") { - chatStore.pushSystem("⚠️ Message not delivered β€” session was resetting. Please try again.", selectedAgent.value); - restoreLastSent?.(); - } else if (data.code === "DISCARDED_NOT_IDLE" || data.code === "DISCARDED_NOT_READY") { - chatStore.pushSystem("⚠️ Message not delivered β€” agent was busy. Please try again.", selectedAgent.value); - restoreLastSent?.(); - } - }, - stopped(_data) { - chatStore.pushSystem("βœ… Agent stopped", selectedAgent.value); - }, - killed(_data) { - chatStore.pushSystem("☠️ Agent killed", selectedAgent.value); - } - }; - const unsubscribe = onWsMessage((data) => { - const handler = handlers[data.type]; - if (handler) handler(data); - }); - replayBuffer((data) => { - const handler = handlers[data.type]; - if (handler) handler(data); - }); - return unsubscribe; - } - return { - mount, - lastSystemMsg: history.lastSystemMsgRef, - hudTree: history.hudTree, - hudVersion: history.hudVersion, - getToolsForTurn: history.getToolsForTurn, - hudSnapshot: history.hudSnapshot, - toolCallMapSnapshot: history.toolCallMapSnapshot, - sessionHistoryComplete: history.sessionHistoryComplete, - pushSystem, - hasActiveStreamingMessage: chatStore.hasActiveStreamingMessage - }; -} -function generateMsgId() { - return crypto.randomUUID(); -} -const renderer = new marked.Renderer(); -renderer.link = ({ href, title, text }) => { - const titleAttr = title ? ` title="${title}"` : ""; - return `${text}`; -}; -function ansiToHtml(text) { - const colorMap = { - 30: "#555", - 31: "#e06c75", - 32: "#98c379", - 33: "#e5c07b", - 34: "#61afef", - 35: "#c678dd", - 36: "#56b6c2", - 37: "#abb2bf" - }; - let open = false, bold = false, dim = false; - const result = text.replace(/\x1b\[([0-9;]*)m/g, (_match, codes) => { - const parts = codes.split(";").map(Number); - let out = ""; - for (const code of parts) { - if (code === 0) { - if (open) { - out += ""; - open = false; - } - if (bold) { - out += ""; - bold = false; - } - if (dim) { - out += ""; - dim = false; - } - } else if (code === 1) { - if (!bold) { - out += ""; - bold = true; - } - } else if (code === 2) { - if (!dim) { - out += ''; - dim = true; - } - } else if (colorMap[code]) { - if (open) { - out += ""; - } - out += ``; - open = true; - } - } - return out; - }); - let tail = ""; - if (open) tail += ""; - if (bold) tail += ""; - if (dim) tail += ""; - return result + tail; -} -const WORKSPACE_PATH_RE = /(workspace\/[^\s"'<>)]+\.(?:pdf|png|jpg|jpeg|gif|csv|json|txt|md|html|zip|mp3|wav|ogg|webm|m4a))/g; -const WORKSPACE_PREFIX = ""; -const AUDIO_EXTENSIONS = /* @__PURE__ */ new Set(["mp3", "wav", "ogg", "webm", "m4a"]); -function linkifyWorkspaceFiles(html) { - return html.replace(WORKSPACE_PATH_RE, (match) => { - const name = match.split("/").pop() || match; - const absPath = match.startsWith("/") ? match : WORKSPACE_PREFIX + match; - const ext = name.split(".").pop()?.toLowerCase() || ""; - if (AUDIO_EXTENSIONS.has(ext)) { - return ``; - } - return ``; - }); -} -if (typeof window !== "undefined" && !window.__hermesAudioSrc) { - window.__hermesAudioSrc = (el) => { - if (el.src) return; - const filepath = el.dataset.filepath; - if (!filepath) return; - const token = localStorage.getItem("nyx_session") || localStorage.getItem("titan_token") || ""; - const apiBase = getApiBase(); - el.src = `${apiBase}/api/files${filepath}?token=${encodeURIComponent(token)}`; - }; -} -if (typeof window !== "undefined" && !window.__hermesDownload) { - window.__hermesDownload = async (el) => { - const filepath = el.dataset.filepath; - const filename = el.dataset.filename || "download"; - if (!filepath) return; - el.textContent = "⏳ " + filename; - try { - const token = localStorage.getItem("nyx_session") || localStorage.getItem("titan_token") || ""; - const apiBase2 = getApiBase(); - const res = await fetch(`${apiBase2}/api/files${filepath}?token=${encodeURIComponent(token)}`); - if (!res.ok) throw new Error(`${res.status}`); - const blob = await res.blob(); - const url = URL.createObjectURL(blob); - const a = document.createElement("a"); - a.href = url; - a.download = filename; - a.click(); - URL.revokeObjectURL(url); - el.textContent = "βœ… " + filename; - } catch (err) { - el.textContent = "❌ " + filename; - console.error("[download]", err); - } - }; -} -function parseMd(content) { - const raw = content || ""; - if (/\x1b\[/.test(raw)) { - const escaped = raw.replace(/&/g, "&").replace(//g, ">"); - return `
${ansiToHtml(escaped)}
`; - } - let html = marked.parse(raw, { renderer, async: false, gfm: true, breaks: true }); - html = linkifyWorkspaceFiles(html); - return html; -} -const DRAFT_KEY = "chat_draft"; -const HISTORY_KEY = "chat_input_history"; -const HISTORY_MAX = 50; -function loadDraft() { - try { - return sessionStorage.getItem(DRAFT_KEY) || ""; - } catch { - return ""; - } -} -function saveDraft(v) { - try { - if (v) sessionStorage.setItem(DRAFT_KEY, v); - else sessionStorage.removeItem(DRAFT_KEY); - } catch { - } -} -function loadHistory() { - try { - return JSON.parse(sessionStorage.getItem(HISTORY_KEY) || "[]"); - } catch { - return []; - } -} -function pushHistory(v) { - try { - const h = loadHistory().filter((x) => x !== v); - h.unshift(v); - sessionStorage.setItem(HISTORY_KEY, JSON.stringify(h.slice(0, HISTORY_MAX))); - } catch { - } -} -function useMessages(wsSendFn) { - const store = useChatStore(); - const sending = ref(false); - const input = ref(loadDraft()); - const messagesEl = ref(null); - let historyIdx = -1; - function getViewport() { - const el = messagesEl.value; - if (!el) return null; - const root = el.$el || el; - return root.querySelector?.("[data-overlayscrollbars-viewport]") || root; - } - function scrollToBottom() { - nextTick(() => { - nextTick(() => { - requestAnimationFrame(() => { - const vp = getViewport(); - if (vp) vp.scrollTop = vp.scrollHeight; - }); - }); - }); - } - function scrollIfAtBottom() { - const vp = getViewport(); - if (!vp) return; - if (vp.scrollHeight - vp.scrollTop - vp.clientHeight < 80) scrollToBottom(); - } - let draftTimer = null; - function onInputChange() { - if (draftTimer) clearTimeout(draftTimer); - draftTimer = setTimeout(() => saveDraft(input.value), 1e3); - } - function navigateHistory(dir) { - const history = loadHistory(); - if (!history.length) return; - if (dir === "up") { - historyIdx = Math.min(historyIdx + 1, history.length - 1); - } else { - historyIdx = Math.max(historyIdx - 1, -1); - } - input.value = historyIdx === -1 ? "" : history[historyIdx]; - } - let lastSentContent = ""; - function restoreLastSent() { - input.value = lastSentContent; - } - async function send(attachmentPayload) { - const hasText = input.value.trim().length > 0; - const hasAttachments = attachmentPayload && attachmentPayload.length > 0; - if (!hasText && !hasAttachments || sending.value) return; - const content = input.value.trim(); - if (hasText) { - lastSentContent = content; - pushHistory(content); - } - historyIdx = -1; - input.value = ""; - saveDraft(""); - sending.value = true; - const msgId = generateMsgId(); - const localAttachments = hasAttachments ? attachmentPayload.map((a) => { - const mime = a.mimeType.split(";")[0]; - let dataUrl; - if (a.mimeType.startsWith("audio/")) { - const bytes = Uint8Array.from(atob(a.content), (c) => c.charCodeAt(0)); - dataUrl = URL.createObjectURL(new Blob([bytes], { type: mime })); - } else { - dataUrl = `data:${mime};base64,${a.content}`; - } - return { mimeType: a.mimeType, fileName: a.fileName, dataUrl }; - }) : void 0; - const hasAudio = hasAttachments && attachmentPayload.some((a) => a.mimeType.startsWith("audio/")); - store.pushMessage({ - role: "user", - content, - agentId: null, - msgId, - attachments: localAttachments, - pending: hasAudio - // audio messages are pending until transcript arrives - }); - const payload = { type: "message", content, msgId }; - if (hasAttachments) payload.attachments = attachmentPayload; - wsSendFn(payload); - sending.value = false; - } - return { - sending, - input, - messagesEl, - parseMd, - scrollToBottom, - scrollIfAtBottom, - send, - onInputChange, - navigateHistory, - restoreLastSent, - startNewAssistantMessage: store.startNewAssistantMessage, - appendAssistantMessage: store.appendAssistantDelta, - finalizeAssistantMessage: store.finalizeAssistantMessage, - resetAssistantMessageState: store.resetLocalSession, - hasActiveStreamingMessage: store.hasActiveStreamingMessage, - streamingMessageVisibleContent: computed(() => store.streamingMessageVisibleContent) - }; -} -function useMessageGrouping(messages, visibleCount, selectedAgent, allAgents, sessionKey) { - const VISIBLE_PAGE2 = 50; - const visibleMsgs = computed(() => { - const all = messages.value; - const start = Math.max(0, all.length - visibleCount.value); - return all.slice(start).map((m, i) => ({ ...m, _sourceIndex: start + i })); - }); - const hasMore = computed(() => messages.value.length > visibleCount.value); - function loadMore() { - visibleCount.value += VISIBLE_PAGE2; - } - function getFormattedAgentName(agentId) { - if (!agentId) return "Unknown"; - const agent = allAgents.value.find((a) => a.id === agentId); - return agent ? agent.name : agentId; - } - function shouldShowHeadline(index, msgsArr) { - if (index === 0) return true; - const current = msgsArr[index]; - const prev = msgsArr[index - 1]; - if (!current.agentId || !prev.agentId) { - return current.sessionId !== prev.sessionId; - } - return current.agentId !== prev.agentId || current.sessionId !== prev.sessionId; - } - function formatHeadlineText(agentName) { - const key = sessionKey?.value; - return key ? `${agentName} Β· ${key}` : agentName; - } - function getHeadline(index, msgsArr) { - const current = msgsArr[index]; - const targetAgentId = current.agentId || selectedAgent.value; - const agentName = getFormattedAgentName(targetAgentId); - if (index === 0) return { text: formatHeadlineText(agentName), kind: "agent" }; - const prev = msgsArr[index - 1]; - if (current.agentId !== prev.agentId) return { text: formatHeadlineText(agentName), kind: "agent" }; - if (current.sessionId !== prev.sessionId) return { text: "New Session", kind: "new-session" }; - return { text: formatHeadlineText(agentName), kind: "agent" }; - } - const groupedVisibleMsgs = computed(() => { - const raw = visibleMsgs.value; - const result = []; - let currentGroup = null; - for (let i = 0; i < raw.length; i++) { - const msg = raw[i]; - if (shouldShowHeadline(i, raw)) { - if (currentGroup) { - result.push(currentGroup); - currentGroup = null; - } - const { text, kind } = getHeadline(i, raw); - result.push({ - role: "system", - type: "headline", - content: text, - headlineKind: kind, - agentId: msg.agentId, - sessionId: msg.sessionId, - position: "header" - // Header appears before agent block - }); - } - if (msg.role === "system" && msg.type !== "no_session") { - if (!currentGroup) { - currentGroup = { role: "system_group", messages: [msg], agentId: msg.agentId, sessionId: msg.sessionId }; - } else { - currentGroup.messages.push(msg); - } - } else { - if (currentGroup) { - result.push(currentGroup); - currentGroup = null; - } - result.push(msg); - const effectiveAgentId = msg.agentId || selectedAgent.value; - if (effectiveAgentId && i === raw.length - 1) { - const agentName = getFormattedAgentName(effectiveAgentId); - result.push({ - role: "system", - type: "headline", - content: formatHeadlineText(agentName), - headlineKind: "agent", - agentId: effectiveAgentId, - sessionId: msg.sessionId, - position: "footer" - }); - } - } - } - if (currentGroup) result.push(currentGroup); - return result; - }); - return { - visibleMsgs, - groupedVisibleMsgs, - hasMore, - loadMore, - getFormattedAgentName - }; -} -function useInputAutogrow(input) { - const inputEl = ref(null); - const isShaking = ref(false); - function autoGrow() { - const el = inputEl.value; - if (!el) return; - el.style.height = "auto"; - el.style.height = el.scrollHeight + "px"; - el.style.overflowY = el.scrollHeight > 160 ? "auto" : "hidden"; - } - function triggerShake() { - isShaking.value = true; - setTimeout(() => { - isShaking.value = false; - }, 400); - } - watch(input, (val) => { - if (!val) nextTick(() => autoGrow()); - }); - return { inputEl, isShaking, autoGrow, triggerShake }; -} -function useAgentDisplay(selectedAgent, defaultAgent, allAgents) { - const chatStore = useChatStore(); - const defaultAgentName = computed(() => { - const agent = allAgents.value.find((a) => a.id === defaultAgent.value); - return agent ? agent.name : defaultAgent.value; - }); - const agentDisplayName = computed(() => { - const agent = allAgents.value.find((a) => a.id === selectedAgent.value); - return (agent ? agent.name : selectedAgent.value).toUpperCase(); - }); - const isAgentRunning = computed(() => chatStore.smState === "AGENT_RUNNING"); - const agentStatusDone = computed(() => chatStore.channelState === "READY" || chatStore.channelState === "FRESH"); - const agentStatus = computed(() => { - switch (chatStore.smState) { - case "CONNECTING": - return "βš™οΈ Connecting…"; - case "AGENT_RUNNING": - return "βš™οΈ Working…"; - case "HANDOVER_PENDING": - return "πŸ“ Writing handover…"; - case "HANDOVER_DONE": - return "βœ… Handover ready"; - case "SWITCHING": - return "πŸ”€ Switching…"; - default: - return null; - } - }); - return { defaultAgentName, agentDisplayName, isAgentRunning, agentStatusDone, agentStatus }; -} -const ACCEPTED_TYPES = [ - "image/jpeg", - "image/png", - "image/gif", - "image/webp", - "application/pdf", - "audio/webm", - "audio/mp4", - "audio/ogg", - "audio/mpeg", - "audio/wav", - "audio/x-m4a" -]; -const MAX_BYTES = 10 * 1024 * 1024; -function readAsBase64(file) { - return new Promise((resolve, reject) => { - const reader = new FileReader(); - reader.onload = () => { - const result = reader.result; - const idx = result.indexOf(","); - resolve(idx >= 0 ? result.slice(idx + 1) : result); - }; - reader.onerror = () => reject(reader.error); - reader.readAsDataURL(file); - }); -} -function useAttachments() { - const attachments = ref([]); - async function addFiles(files) { - for (const file of Array.from(files)) { - const baseType = file.type.split(";")[0]; - if (!ACCEPTED_TYPES.includes(baseType) && !ACCEPTED_TYPES.includes(file.type)) { - console.warn(`[attachments] skipped ${file.name}: unsupported type ${file.type}`); - continue; - } - if (file.size > MAX_BYTES) { - console.warn(`[attachments] skipped ${file.name}: exceeds 5MB (${(file.size / 1024 / 1024).toFixed(1)}MB)`); - continue; - } - const base64 = await readAsBase64(file); - const preview = URL.createObjectURL(file); - attachments.value.push({ file, preview, base64, mimeType: file.type, fileName: file.name }); - } - } - function removeAttachment(index) { - const att = attachments.value[index]; - if (att) URL.revokeObjectURL(att.preview); - attachments.value.splice(index, 1); - } - function clearAttachments() { - for (const att of attachments.value) URL.revokeObjectURL(att.preview); - attachments.value = []; - } - function toPayload() { - return attachments.value.map((a) => ({ - type: a.mimeType.startsWith("image/") ? "image" : a.mimeType.startsWith("audio/") ? "audio" : "document", - mimeType: a.mimeType, - content: a.base64, - fileName: a.fileName - })); - } - function hasAttachments() { - return attachments.value.length > 0; - } - return { attachments, addFiles, removeAttachment, clearAttachments, toPayload, hasAttachments }; -} -function useAudioRecorder() { - const isRecording = ref(false); - const duration = ref(0); - const audioLevel = ref(0); - const micDenied = ref(false); - let mediaRecorder = null; - let stream = null; - let audioCtx = null; - let analyser = null; - let levelBuf = null; - let chunks = []; - let timer = null; - let startTime = 0; - function cleanup() { - if (timer) { - clearInterval(timer); - timer = null; - } - if (audioCtx) { - audioCtx.close().catch(() => { - }); - audioCtx = null; - analyser = null; - levelBuf = null; - } - if (stream) { - stream.getTracks().forEach((t) => t.stop()); - stream = null; - } - mediaRecorder = null; - chunks = []; - duration.value = 0; - audioLevel.value = 0; - isRecording.value = false; - } - function updateLevel() { - if (!analyser || !levelBuf) return; - analyser.getByteTimeDomainData(levelBuf); - let sum = 0; - for (let i = 0; i < levelBuf.length; i++) { - const v = (levelBuf[i] - 128) / 128; - sum += v * v; - } - audioLevel.value = Math.min(1, Math.sqrt(sum / levelBuf.length) * 3); - } - async function startRecording() { - if (isRecording.value) return; - try { - stream = await navigator.mediaDevices.getUserMedia({ audio: true }); - } catch (err) { - console.warn("[audio] mic access denied:", err); - micDenied.value = true; - setTimeout(() => { - micDenied.value = false; - }, 5e3); - return; - } - try { - audioCtx = new AudioContext(); - const source = audioCtx.createMediaStreamSource(stream); - analyser = audioCtx.createAnalyser(); - analyser.fftSize = 256; - source.connect(analyser); - levelBuf = new Uint8Array(analyser.fftSize); - } catch (err) { - console.warn("[audio] analyser setup failed:", err); - } - chunks = []; - const mimeType = MediaRecorder.isTypeSupported("audio/webm;codecs=opus") ? "audio/webm;codecs=opus" : MediaRecorder.isTypeSupported("audio/webm") ? "audio/webm" : ""; - mediaRecorder = new MediaRecorder(stream, mimeType ? { mimeType } : void 0); - mediaRecorder.ondataavailable = (e) => { - if (e.data.size > 0) chunks.push(e.data); - }; - mediaRecorder.start(250); - isRecording.value = true; - startTime = Date.now(); - timer = setInterval(() => { - duration.value = Math.floor((Date.now() - startTime) / 1e3); - updateLevel(); - }, 80); - } - function stopRecording() { - return new Promise((resolve) => { - if (!mediaRecorder || mediaRecorder.state === "inactive") { - cleanup(); - resolve(null); - return; - } - mediaRecorder.onstop = () => { - const mimeType = mediaRecorder?.mimeType || "audio/webm"; - const ext = mimeType.includes("mp4") ? "mp4" : mimeType.includes("ogg") ? "ogg" : "webm"; - const blob = new Blob(chunks, { type: mimeType }); - const file = new File([blob], `recording-${Date.now()}.${ext}`, { type: mimeType }); - cleanup(); - resolve(file); - }; - mediaRecorder.stop(); - }); - } - function cancelRecording() { - if (mediaRecorder && mediaRecorder.state !== "inactive") { - mediaRecorder.onstop = () => { - }; - mediaRecorder.stop(); - } - cleanup(); - } - function formatDuration(secs) { - const m = Math.floor(secs / 60); - const s = secs % 60; - return `${m}:${s.toString().padStart(2, "0")}`; - } - onUnmounted(cleanup); - return { isRecording, duration, audioLevel, micDenied, startRecording, stopRecording, cancelRecording, formatDuration }; -} -const _sfc_main$6 = /* @__PURE__ */ defineComponent({ - __name: "MessageFrame", - __ssrInlineRender: true, - props: { - role: {}, - copyContent: {} - }, - setup(__props) { - return (_ctx, _push, _parent, _attrs) => { - _push(``); - if (__props.role !== "system") { - _push(``); - } else { - _push(``); - } - ssrRenderSlot(_ctx.$slots, "default", {}, null, _push, _parent); - if (_ctx.$slots.footer) { - _push(``); - } else { - _push(``); - } - _push(``); - }; - } -}); -const _sfc_setup$6 = _sfc_main$6.setup; -_sfc_main$6.setup = (props, ctx) => { - const ssrContext = useSSRContext(); - (ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("src/components/MessageFrame.vue"); - return _sfc_setup$6 ? _sfc_setup$6(props, ctx) : void 0; -}; -const _sfc_main$5 = /* @__PURE__ */ defineComponent({ - __name: "UserMessage", - __ssrInlineRender: true, - props: { - msg: {} - }, - setup(__props) { - const props = __props; - const username = auth.currentUser; - const expandedSrc = ref(""); - function expandImage(src) { - expandedSrc.value = src; - } - const audioAttachment = computed(() => (props.msg.attachments || []).find((a) => a.mimeType?.startsWith("audio/"))); - const nonAudioAttachments = computed(() => (props.msg.attachments || []).filter((a) => !a.mimeType?.startsWith("audio/"))); - return (_ctx, _push, _parent, _attrs) => { - _push(``); - _push(ssrRenderComponent(_sfc_main$6, { - role: "user", - copyContent: __props.msg.content - }, createSlots({ - default: withCtx((_, _push2, _parent2, _scopeId) => { - if (_push2) { - if (__props.msg.voiceAudioUrl) { - _push2(``); - } else if (audioAttachment.value) { - _push2(``); - } else { - _push2(``); - } - if (__props.msg.pending) { - _push2(`
transcribing...
`); - } else { - _push2(``); - } - if (__props.msg.content) { - _push2(`
${ssrInterpolate(__props.msg.content)}
`); - } else { - _push2(``); - } - if (nonAudioAttachments.value.length) { - _push2(`
`); - ssrRenderList(nonAudioAttachments.value, (att, i) => { - _push2(``); - if (att.mimeType === "application/pdf") { - _push2(`
πŸ“„${ssrInterpolate(att.fileName || "document.pdf")}
`); - } else { - _push2(`
`); - } - _push2(``); - }); - _push2(`
`); - } else { - _push2(``); - } - } else { - return [ - __props.msg.voiceAudioUrl ? (openBlock(), createBlock("audio", { - key: 0, - controls: "", - src: __props.msg.voiceAudioUrl, - class: "user-att-audio" - }, null, 8, ["src"])) : audioAttachment.value ? (openBlock(), createBlock("audio", { - key: 1, - controls: "", - src: audioAttachment.value.dataUrl, - class: "user-att-audio" - }, null, 8, ["src"])) : createCommentVNode("", true), - __props.msg.pending ? (openBlock(), createBlock("div", { - key: 2, - class: "voice-pending" - }, "transcribing...")) : createCommentVNode("", true), - __props.msg.content ? (openBlock(), createBlock("div", { key: 3 }, toDisplayString(__props.msg.content), 1)) : createCommentVNode("", true), - nonAudioAttachments.value.length ? (openBlock(), createBlock("div", { - key: 4, - class: "user-attachments" - }, [ - (openBlock(true), createBlock(Fragment, null, renderList(nonAudioAttachments.value, (att, i) => { - return openBlock(), createBlock(Fragment, { key: i }, [ - att.mimeType === "application/pdf" ? (openBlock(), createBlock("div", { - key: 0, - class: "user-att-pdf", - title: att.fileName || "PDF" - }, [ - createVNode("span", { class: "pdf-icon" }, "πŸ“„"), - createVNode("span", { class: "pdf-name" }, toDisplayString(att.fileName || "document.pdf"), 1) - ], 8, ["title"])) : (openBlock(), createBlock("div", { - key: 1, - class: "user-att-thumb", - onClick: ($event) => expandImage(att.dataUrl) - }, [ - createVNode("img", { - src: att.dataUrl, - alt: att.fileName || "image", - loading: "lazy" - }, null, 8, ["src", "alt"]) - ], 8, ["onClick"])) - ], 64); - }), 128)) - ])) : createCommentVNode("", true) - ]; - } - }), - _: 2 - }, [ - unref(username) ? { - name: "footer", - fn: withCtx((_, _push2, _parent2, _scopeId) => { - if (_push2) { - _push2(`${ssrInterpolate(unref(username))}`); - } else { - return [ - createTextVNode(toDisplayString(unref(username)), 1) - ]; - } - }), - key: "0" - } : void 0 - ]), _parent)); - if (expandedSrc.value) { - _push(``); - } else { - _push(``); - } - _push(``); - }; - } -}); -const _sfc_setup$5 = _sfc_main$5.setup; -_sfc_main$5.setup = (props, ctx) => { - const ssrContext = useSSRContext(); - (ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("src/components/UserMessage.vue"); - return _sfc_setup$5 ? _sfc_setup$5(props, ctx) : void 0; -}; -const UserMessage = /* @__PURE__ */ _export_sfc(_sfc_main$5, [["__scopeId", "data-v-90f9dace"]]); -const _sfc_main$4 = /* @__PURE__ */ defineComponent({ - __name: "ToolIcon", - __ssrInlineRender: true, - props: { - tool: {} - }, - setup(__props) { - const props = __props; - const iconMap = { - read: BookOpenIcon, - write: PencilIcon, - edit: WrenchIcon, - append: DocumentPlusIcon, - exec: BoltIcon, - web_search: GlobeAltIcon, - web_fetch: GlobeAltIcon, - memory_search: CpuChipIcon, - memory_get: CpuChipIcon, - browser: ComputerDesktopIcon - }; - const icon = computed(() => { - if (!props.tool) return BoltIcon; - const t = props.tool.toLowerCase(); - if (iconMap[t]) return iconMap[t]; - if (t.includes("message")) return ChatBubbleLeftIcon; - if (t.includes("session")) return LinkIcon; - return Cog6ToothIcon; - }); - return (_ctx, _push, _parent, _attrs) => { - ssrRenderVNode(_push, createVNode(resolveDynamicComponent(icon.value), mergeProps({ class: "tool-icon w-3.5 h-3.5 inline shrink-0" }, _attrs), null), _parent); - }; - } -}); -const _sfc_setup$4 = _sfc_main$4.setup; -_sfc_main$4.setup = (props, ctx) => { - const ssrContext = useSSRContext(); - (ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("src/components/ToolIcon.vue"); - return _sfc_setup$4 ? _sfc_setup$4(props, ctx) : void 0; -}; -function relativeTime(isoOrDate) { - const then = typeof isoOrDate === "string" ? new Date(isoOrDate) : isoOrDate; - const now = Date.now(); - const diffMs = now - then.getTime(); - if (diffMs < 0) return "just now"; - const sec = Math.floor(diffMs / 1e3); - if (sec < 60) return "just now"; - const min = Math.floor(sec / 60); - if (min < 60) return `${min}m ago`; - const hr = Math.floor(min / 60); - if (hr < 24) return `${hr}h ago`; - const days = Math.floor(hr / 24); - if (days < 30) return `${days}d ago`; - return then.toLocaleDateString(); -} -const _sfc_main$3 = /* @__PURE__ */ defineComponent({ - __name: "AssistantMessage", - __ssrInlineRender: true, - props: { - msg: {}, - agentDisplayName: {}, - isAgentRunning: { type: Boolean }, - allAgents: {}, - getToolsForTurn: { type: Function }, - hudVersion: {} - }, - setup(__props) { - const chatStore = useChatStore(); - const ttsPlayer = useTtsPlayer(); - const props = __props; - const displayName = computed(() => { - const id = props.msg.agentId; - if (id) { - const agent = props.allAgents?.find((a) => a.id === id); - return (agent ? agent.name : id).toUpperCase(); - } - return props.agentDisplayName; - }); - const msgTimeLabel = computed(() => { - if (props.msg.timestamp) { - return relativeTime(props.msg.timestamp); - } - return "Done"; - }); - const content = computed(() => { - if (props.msg.streaming) { - return chatStore.streamingMessageVisibleContent + '...'; - } - return props.msg.content; - }); - const tools = computed(() => { - void props.hudVersion; - return props.getToolsForTurn(props.msg.turnCorrId); - }); - return (_ctx, _push, _parent, _attrs) => { - _push(ssrRenderComponent(_sfc_main$6, mergeProps({ - role: "assistant", - copyContent: __props.msg.content - }, _attrs), { - footer: withCtx((_, _push2, _parent2, _scopeId) => { - if (_push2) { - _push2(`${ssrInterpolate(displayName.value)}`); - if (!__props.msg.streaming && __props.msg.content) { - _push2(``); - } else { - _push2(``); - } - if (__props.msg.streaming && tools.value.length === 0) { - _push2(` ...`); - } else if (!__props.msg.streaming && tools.value.length === 0) { - _push2(` | ${ssrInterpolate(msgTimeLabel.value)}`); - } else { - _push2(``); - } - if (tools.value.length > 0) { - _push2(``); - ssrRenderList(tools.value, (tool) => { - _push2(``); - _push2(ssrRenderComponent(_sfc_main$4, { - tool: tool.tool || "" - }, null, _parent2, _scopeId)); - _push2(``); - }); - _push2(``); - } else { - _push2(``); - } - if (__props.msg.truncated) { - _push2(``); - _push2(ssrRenderComponent(unref(ExclamationTriangleIcon), { class: "w-4 h-4 inline" }, null, _parent2, _scopeId)); - _push2(` Output limit reached β€” response was cut off`); - } else { - _push2(``); - } - } else { - return [ - createVNode("span", { class: "footer-name" }, toDisplayString(displayName.value), 1), - !__props.msg.streaming && __props.msg.content ? (openBlock(), createBlock("button", { - key: 0, - class: ["tts-btn", { active: unref(ttsPlayer).isPlayingMsg(__props.msg) }], - onClick: withModifiers(($event) => unref(ttsPlayer).play(__props.msg, __props.msg._sourceIndex ?? 0), ["stop"]), - title: "Listen" - }, [ - unref(ttsPlayer).isPlayingMsg(__props.msg) && unref(ttsPlayer).state.value === "loading" ? (openBlock(), createBlock("span", { - key: 0, - class: "tts-spinner" - })) : (openBlock(), createBlock(unref(SpeakerWaveIcon), { - key: 1, - class: "w-3.5 h-3.5" - })) - ], 10, ["onClick"])) : createCommentVNode("", true), - __props.msg.streaming && tools.value.length === 0 ? (openBlock(), createBlock("span", { - key: 1, - class: "footer-status" - }, " ...")) : !__props.msg.streaming && tools.value.length === 0 ? (openBlock(), createBlock("span", { - key: 2, - class: "footer-status" - }, " | " + toDisplayString(msgTimeLabel.value), 1)) : createCommentVNode("", true), - tools.value.length > 0 ? (openBlock(), createBlock("span", { - key: 3, - class: "footer-tools" - }, [ - (openBlock(true), createBlock(Fragment, null, renderList(tools.value, (tool) => { - return openBlock(), createBlock("span", { - key: tool.id, - class: ["footer-tool-icon", tool.state], - title: `${tool.label} [${tool.state}]` - }, [ - createVNode(_sfc_main$4, { - tool: tool.tool || "" - }, null, 8, ["tool"]) - ], 10, ["title"]); - }), 128)) - ])) : createCommentVNode("", true), - __props.msg.truncated ? (openBlock(), createBlock("span", { - key: 4, - class: "truncated-notice" - }, [ - createVNode(unref(ExclamationTriangleIcon), { class: "w-4 h-4 inline" }), - createTextVNode(" Output limit reached β€” response was cut off") - ])) : createCommentVNode("", true) - ]; - } - }), - default: withCtx((_, _push2, _parent2, _scopeId) => { - if (_push2) { - _push2(`
${unref(parseMd)(content.value) ?? ""}
`); - } else { - return [ - createVNode("div", { - innerHTML: unref(parseMd)(content.value) - }, null, 8, ["innerHTML"]) - ]; - } - }), - _: 1 - }, _parent)); - }; - } -}); -const _sfc_setup$3 = _sfc_main$3.setup; -_sfc_main$3.setup = (props, ctx) => { - const ssrContext = useSSRContext(); - (ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("src/components/AssistantMessage.vue"); - return _sfc_setup$3 ? _sfc_setup$3(props, ctx) : void 0; -}; -const AssistantMessage = /* @__PURE__ */ _export_sfc(_sfc_main$3, [["__scopeId", "data-v-a59db10d"]]); -const _sfc_main$2 = /* @__PURE__ */ defineComponent({ - __name: "SystemMessage", - __ssrInlineRender: true, - props: { - msg: {} - }, - setup(__props) { - const props = __props; - const isCollapsed = ref(false); - const groupContentEl = ref(null); - onUpdated(() => { - nextTick(() => { - if (groupContentEl.value) { - groupContentEl.value.scrollTop = groupContentEl.value.scrollHeight; - } - }); - }); - function isSqlResult(content) { - if (!content) return false; - const raw = content.startsWith("β†’ ") ? content.slice(2) : content; - const lines = raw.split("\n").filter((l) => l.trim()); - if (lines.length < 2) return false; - return lines.filter((l) => l.includes(" ")).length >= 2; - } - function parseSqlTable(content) { - const raw = content.startsWith("β†’ ") ? content.slice(2) : content; - const lines = raw.split("\n").filter((l) => l.trim()); - const [headerLine, ...dataLines] = lines; - const headers = headerLine.split(" "); - const rows = dataLines.filter((l) => !l.startsWith("… [")).map((l) => l.split(" ")); - return { headers, rows }; - } - function getSummary() { - const msgs = props.msg.messages; - if (!msgs?.length) return "Event"; - const toolNames = []; - for (const m of msgs) { - const raw = m.content || ""; - const match = raw.match(/^[^\w]*(\w+)/u); - if (match) { - const name = match[1]; - if (!["true", "false", "null", "done", "ok"].includes(name.toLowerCase())) { - if (!toolNames.includes(name)) toolNames.push(name); - } - } - } - const callCount = msgs.length; - const label = toolNames.length ? toolNames.join(" Β· ") : "Event"; - return callCount === 1 ? label : `${label} Β· ${callCount}`; - } - return (_ctx, _push, _parent, _attrs) => { - _push(``); - if (__props.msg.type === "headline" && __props.msg.headlineKind !== "new-session" && __props.msg.position !== "footer") { - _push(`
${ssrInterpolate(__props.msg.content)}
`); - } else if (__props.msg.type === "headline" && __props.msg.headlineKind !== "new-session" && __props.msg.position === "footer") { - _push(``); - } else if (__props.msg.type === "headline" && __props.msg.headlineKind === "new-session") { - _push(`
${ssrInterpolate(__props.msg.content)}
`); - } else if (__props.msg.role === "system_group" || __props.msg.messages) { - _push(`
`); - _push(ssrRenderComponent(unref(Cog6ToothIcon), { class: "system-group-icon-svg" }, null, _parent)); - _push(`${ssrInterpolate(getSummary())}`); - _push(ssrRenderComponent(unref(ChevronDownIcon), { - class: ["chevron", { open: !isCollapsed.value }] - }, null, _parent)); - _push(`
`); - if (!isCollapsed.value) { - _push(`
`); - ssrRenderList(__props.msg.messages, (subMsg, idx) => { - _push(`
`); - if (isSqlResult(subMsg.content)) { - _push(`
`); - ssrRenderList(parseSqlTable(subMsg.content).headers, (col, ci) => { - _push(``); - }); - _push(``); - ssrRenderList(parseSqlTable(subMsg.content).rows, (row, ri) => { - _push(``); - ssrRenderList(row, (cell, ci) => { - _push(``); - }); - _push(``); - }); - _push(`
${ssrInterpolate(col)}
${ssrInterpolate(cell)}
`); - } else { - _push(`
${ssrInterpolate(subMsg.content)}
`); - } - _push(`
`); - }); - _push(`
`); - } else { - _push(``); - } - _push(`
`); - } else { - _push(`
`); - _push(ssrRenderComponent(unref(InformationCircleIcon), { class: "system-group-icon-svg" }, null, _parent)); - _push(`${ssrInterpolate(__props.msg.content)}
`); - } - _push(``); - }; - } -}); -const _sfc_setup$2 = _sfc_main$2.setup; -_sfc_main$2.setup = (props, ctx) => { - const ssrContext = useSSRContext(); - (ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("src/components/SystemMessage.vue"); - return _sfc_setup$2 ? _sfc_setup$2(props, ctx) : void 0; -}; -const SystemMessage = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["__scopeId", "data-v-6cdcd5f1"]]); -const _sfc_main$1 = /* @__PURE__ */ defineComponent({ - __name: "HudControls", - __ssrInlineRender: true, - props: { - smState: String, - connected: Boolean, - isAgentRunning: Boolean, - handoverPending: Boolean, - isPublic: Boolean - }, - emits: ["new", "handover", "confirm-new", "stay"], - setup(__props) { - return (_ctx, _push, _parent, _attrs) => { - _push(`
`); - if (!__props.isPublic) { - _push(``); - } else { - _push(``); - } - _push(`
`); - }; - } -}); -const _sfc_setup$1 = _sfc_main$1.setup; -_sfc_main$1.setup = (props, ctx) => { - const ssrContext = useSSRContext(); - (ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("src/components/HudControls.vue"); - return _sfc_setup$1 ? _sfc_setup$1(props, ctx) : void 0; -}; -const HudControls = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["__scopeId", "data-v-89c5a82c"]]); -const VISIBLE_PAGE = 50; -const _sfc_main = /* @__PURE__ */ defineComponent({ - ...{ name: "AgentsView" }, - __name: "AgentsView", - __ssrInlineRender: true, - setup(__props) { - useRouter(); - const agentsRoute = useRoute(); - const chatStore = useChatStore(); - const showPicker = computed(() => !agentsRoute.query.agent); - watch(() => agentsRoute.query.agent, (val) => { - if (!val && agentsRoute.name === "agents") ; - }, { immediate: true }); - const prevSessions = ref([]); - const prevHasMore = ref(false); - const prevLoading = ref(false); - const prevSkip = ref(0); - const prevMessages = computed(() => prevSessions.value.flatMap((s) => s.messages)); - async function fetchPreviousSession(loadMore2 = false) { - if (!selectedAgent.value || prevLoading.value) return; - prevLoading.value = true; - try { - const token = localStorage.getItem("nyx_session") || localStorage.getItem("titan_token") || ""; - const skip = loadMore2 ? prevSkip.value : 0; - const apiBase = getApiBase(); - const res = await fetch(`${apiBase}/api/session-history?agent=${selectedAgent.value}&mode=${selectedMode.value}&skip=${skip}&count=1`, { - headers: { "Authorization": `Bearer ${token}` } - }); - if (!res.ok) return; - const data = await res.json(); - const newSessions = (data.sessions || []).map((s) => ({ - messages: (s.entries || []).map((e) => ({ - role: e.role, - content: e.content, - timestamp: e.timestamp, - agentId: selectedAgent.value, - streaming: false - })), - timestamp: s.resetTimestamp, - timeLabel: s.resetTimestamp ? relativeTime(s.resetTimestamp) : "" - })); - if (loadMore2) { - prevSessions.value = [...newSessions, ...prevSessions.value]; - } else { - prevSessions.value = newSessions; - } - prevSkip.value = skip + newSessions.length; - prevHasMore.value = data.hasMore ?? false; - } catch { - } finally { - prevLoading.value = false; - } - } - const { connected, status, send: wsSend } = ws; - useUI(status); - ref(""); - const { isLoggedIn } = auth; - const { selectedAgent, selectedMode, filteredAgents, defaultAgent, allAgents } = agents; - const SEGMENTS = ["personal", "common", "private", "public"]; - const agentSegments = computed( - () => SEGMENTS.map((key) => ({ - key, - agents: filteredAgents.value.filter((a) => (a.segment ?? "utility") === key).sort((a, b) => a.name.localeCompare(b.name)) - })).filter((s) => s.agents.length > 0) - ); - computed(() => agentLogo(selectedAgent.value)); - const { sending, input, messagesEl, scrollToBottom, restoreLastSent } = useMessages(wsSend); - const controlsEl = ref(null); - ref(null); - const smState = toRef(chatStore, "smState"); - const channelState = toRef(chatStore, "channelState"); - const connectionState = toRef(chatStore, "connectionState"); - const smLabel = toRef(chatStore, "smLabel"); - const isHidden = computed(() => connectionState.value !== "SYNCED"); - const footerHeadline = computed(() => { - const msgs = groupedVisibleMsgs.value; - const last = msgs[msgs.length - 1]; - return last?.position === "footer" ? last : null; - }); - const lastRealMsgIdx = computed(() => { - const msgs = groupedVisibleMsgs.value; - for (let i = msgs.length - 1; i >= 0; i--) { - if (msgs[i].type !== "headline") return i; - } - return -1; - }); - const visibleCount = ref(VISIBLE_PAGE); - const { groupedVisibleMsgs, hasMore, loadMore, getFormattedAgentName } = useMessageGrouping( - computed(() => chatStore.messages), - visibleCount, - selectedAgent, - allAgents, - toRef(chatStore, "sessionKey") - ); - const sentMessages = /* @__PURE__ */ new Set(); - const lastUsage = ref(null); - const pendingClearRef = ref(false); - const { mount, hudVersion, getToolsForTurn, hudSnapshot, toolCallMapSnapshot } = useAgentSocket(visibleCount, lastUsage, pendingClearRef, sentMessages, restoreLastSent); - if (typeof window !== "undefined") { - window.__hudSnapshot = hudSnapshot; - window.__toolCallMap = toolCallMapSnapshot; - } - const viewActive = computed(() => agentsRoute.name === "agents"); - let userSendInFlight = false; - const spacerHeight = ref(0); - function getViewport() { - const el = messagesEl.value; - if (!el) return null; - const root = el.$el || el; - return root.querySelector("[data-overlayscrollbars-viewport]"); - } - function recalcSpacerSync() { - const viewport = getViewport(); - if (!viewport) return 0; - const controls = controlsEl.value || viewport.querySelector(".msg-controls"); - if (!controls) return 0; - const userMsgs = viewport.querySelectorAll(".message.user"); - const last = userMsgs[userMsgs.length - 1]; - if (!last) return 0; - const vpRect = viewport.getBoundingClientRect(); - const st = viewport.scrollTop; - const msgTop = last.getBoundingClientRect().top - vpRect.top + st; - const ctrlBottom = controls.getBoundingClientRect().bottom - vpRect.top + st; - const vpH = viewport.clientHeight; - const needed = msgTop - 40 + vpH; - const h = Math.max(0, needed - ctrlBottom); - spacerHeight.value = h; - return h; - } - let _spacerInterval = null; - onMounted(() => { - _spacerInterval = setInterval(recalcSpacerSync, 200); - onUnmounted(() => { - if (_spacerInterval) clearInterval(_spacerInterval); - }); - }); - watch(connectionState, (val) => { - if (!viewActive.value) return; - if (val === "SYNCED") { - if (!prevMessages.value.length) fetchPreviousSession(); - scrollToBottom(); - } - }); - watch(channelState, (val, prev) => { - if (!viewActive.value) return; - if (prev === "AGENT_RUNNING" && (val === "READY" || val === "FRESH")) { - userSendInFlight = false; - } - if (val === "AGENT_RUNNING" && prev !== "AGENT_RUNNING") { - if (!userSendInFlight) { - scrollToBottom(); - } - } - }); - function onNew() { - chatStore.newSession(); - scrollToBottom(); - } - function onConfirmNew() { - chatStore.confirmNew(); - scrollToBottom(); - } - const { isShaking } = useInputAutogrow(input); - const { isAgentRunning } = useAgentDisplay(selectedAgent, defaultAgent, allAgents); - const { attachments, hasAttachments } = useAttachments(); - ref(null); - const isDragOver = ref(false); - const { isRecording, duration, audioLevel, micDenied, formatDuration } = useAudioRecorder(); - watch([selectedAgent, selectedMode], ([agent, mode], [oldAgent, oldMode]) => { - if (agent !== oldAgent || mode !== oldMode) { - sessionStorage.setItem("agent", agent); - lastUsage.value = null; - sentMessages.clear(); - prevSessions.value = []; - prevHasMore.value = false; - prevSkip.value = 0; - chatStore.resetLocalSession(); - } - }); - onMounted(() => { - chatStore.setWsSend(wsSend); - const unsubscribe = mount(); - if (connectionState.value === "SYNCED") fetchPreviousSession(); - const viewport = getViewport(); - let ro = null; - if (viewport) { - ro = new ResizeObserver(() => recalcSpacerSync()); - ro.observe(viewport); - } - recalcSpacerSync(); - onUnmounted(() => { - unsubscribe(); - ro?.disconnect(); - }); - }); - return (_ctx, _push, _parent, _attrs) => { - const _component_RouterLink = resolveComponent("RouterLink"); - if (unref(isLoggedIn)) { - _push(`

Select an agent

`); - ssrRenderList(agentSegments.value, (seg) => { - _push(`
${ssrInterpolate(seg.key)}
`); - ssrRenderList(seg.agents, (agent) => { - _push(`
`); - if (agent.modes?.includes("private")) { - _push(``); - } else { - _push(``); - } - if (agent.modes?.includes("public")) { - _push(``); - } else { - _push(``); - } - _push(`
`); - }); - _push(`
`); - }); - _push(`
`); - _push(ssrRenderComponent(unref(OverlayScrollbarsComponent), { - class: ["messages h-full pb-4 flex flex-col gap-3 relative", { "is-switching": isHidden.value }], - options: unref(scrollbarOptions), - ref_key: "messagesEl", - ref: messagesEl, - element: "div" - }, { - default: withCtx((_, _push2, _parent2, _scopeId) => { - if (_push2) { - if (prevSessions.value.length) { - _push2(``); - if (prevHasMore.value) { - _push2(``); - } else { - _push2(``); - } - _push2(``); - ssrRenderList(prevSessions.value, (session, si) => { - _push2(`
Session ${ssrInterpolate(prevSessions.value.length - si)}${ssrInterpolate(session.timeLabel ? " β€” " + session.timeLabel : "")}
`); - ssrRenderList(session.messages, (msg, mi) => { - _push2(``); - if (msg.role === "user") { - _push2(ssrRenderComponent(UserMessage, { msg }, null, _parent2, _scopeId)); - } else if (msg.role === "assistant") { - _push2(ssrRenderComponent(AssistantMessage, { - msg, - agentDisplayName: unref(getFormattedAgentName)(msg.agentId || unref(selectedAgent)), - isAgentRunning: false, - allAgents: unref(allAgents), - getToolsForTurn: () => [], - hudVersion: 0 - }, null, _parent2, _scopeId)); - } else { - _push2(``); - } - _push2(``); - }); - _push2(`
`); - }); - _push2(`
Current session
`); - } else { - _push2(``); - } - _push2(``); - ssrRenderList(unref(groupedVisibleMsgs), (msg, i) => { - _push2(``); - if (msg.type === "no_session") { - _push2(`
β€” NO SESSION β€”
`); - } else { - _push2(``); - } - if (msg.type !== "no_session" && (msg.role === "system" || msg.role === "system_group" || msg.type === "headline") && msg.position !== "footer") { - _push2(ssrRenderComponent(SystemMessage, { msg }, null, _parent2, _scopeId)); - } else { - _push2(``); - } - if (unref(hasMore) && msg.type === "headline" && msg.position !== "footer" && i === 0) { - _push2(``); - } else if (msg.role === "session_context") { - _push2(`
${ssrInterpolate(msg.content)}
`); - } else if (msg.role === "user") { - _push2(ssrRenderComponent(UserMessage, { msg }, null, _parent2, _scopeId)); - } else if (msg.role === "thinking") { - _push2(`
`); - _push2(ssrRenderComponent(unref(ChatBubbleBottomCenterTextIcon), { class: "w-4 h-4 inline" }, null, _parent2, _scopeId)); - _push2(` thinking…
${ssrInterpolate(typeof msg.content === "object" ? msg.content.value : msg.content)}
`); - } else if (msg.role === "assistant") { - _push2(ssrRenderComponent(AssistantMessage, { - msg, - agentDisplayName: unref(getFormattedAgentName)(msg.agentId), - isAgentRunning: unref(isAgentRunning), - allAgents: unref(allAgents), - getToolsForTurn: unref(getToolsForTurn), - hudVersion: unref(hudVersion) - }, null, _parent2, _scopeId)); - } else { - _push2(``); - } - if (i === lastRealMsgIdx.value) { - _push2(`
${ssrInterpolate(smLabel.value)}
`); - } else { - _push2(``); - } - _push2(``); - }); - _push2(``); - if (lastRealMsgIdx.value === -1) { - _push2(`
${ssrInterpolate(smLabel.value)}
`); - } else { - _push2(``); - } - if (footerHeadline.value) { - _push2(ssrRenderComponent(SystemMessage, { msg: footerHeadline.value }, null, _parent2, _scopeId)); - } else { - _push2(``); - } - _push2(`
`); - _push2(ssrRenderComponent(HudControls, { - smState: smState.value, - connected: unref(connected), - isAgentRunning: unref(chatStore).isRunning, - handoverPending: unref(chatStore).handoverPending, - isPublic: unref(selectedMode) === "public", - onNew, - onHandover: ($event) => unref(chatStore).handover(), - onConfirmNew, - onStay: ($event) => unref(chatStore).stay() - }, null, _parent2, _scopeId)); - _push2(`
`); - } else { - return [ - prevSessions.value.length ? (openBlock(), createBlock(Fragment, { key: 0 }, [ - prevHasMore.value ? (openBlock(), createBlock("button", { - key: 0, - class: "prev-load-more", - onClick: ($event) => fetchPreviousSession(true), - disabled: prevLoading.value - }, toDisplayString(prevLoading.value ? "Loading..." : "Load older session"), 9, ["onClick", "disabled"])) : createCommentVNode("", true), - (openBlock(true), createBlock(Fragment, null, renderList(prevSessions.value, (session, si) => { - return openBlock(), createBlock(Fragment, { - key: "ps-" + si - }, [ - createVNode("div", { class: "prev-session-header" }, " Session " + toDisplayString(prevSessions.value.length - si) + toDisplayString(session.timeLabel ? " β€” " + session.timeLabel : ""), 1), - createVNode("div", { class: "prev-session-wrapper" }, [ - (openBlock(true), createBlock(Fragment, null, renderList(session.messages, (msg, mi) => { - return openBlock(), createBlock(Fragment, { - key: "prev-" + si + "-" + mi - }, [ - msg.role === "user" ? (openBlock(), createBlock(UserMessage, { - key: 0, - msg - }, null, 8, ["msg"])) : msg.role === "assistant" ? (openBlock(), createBlock(AssistantMessage, { - key: 1, - msg, - agentDisplayName: unref(getFormattedAgentName)(msg.agentId || unref(selectedAgent)), - isAgentRunning: false, - allAgents: unref(allAgents), - getToolsForTurn: () => [], - hudVersion: 0 - }, null, 8, ["msg", "agentDisplayName", "allAgents"])) : createCommentVNode("", true) - ], 64); - }), 128)) - ]) - ], 64); - }), 128)), - createVNode("div", { class: "session-divider" }, [ - createVNode("span", { class: "session-divider-text" }, "Current session") - ]) - ], 64)) : createCommentVNode("", true), - (openBlock(true), createBlock(Fragment, null, renderList(unref(groupedVisibleMsgs), (msg, i) => { - return openBlock(), createBlock(Fragment, { key: i }, [ - msg.type === "no_session" ? (openBlock(), createBlock("div", { - key: 0, - class: "no-session-center" - }, "β€” NO SESSION β€”")) : createCommentVNode("", true), - msg.type !== "no_session" && (msg.role === "system" || msg.role === "system_group" || msg.type === "headline") && msg.position !== "footer" ? (openBlock(), createBlock(SystemMessage, { - key: 1, - msg - }, null, 8, ["msg"])) : createCommentVNode("", true), - unref(hasMore) && msg.type === "headline" && msg.position !== "footer" && i === 0 ? (openBlock(), createBlock("button", { - key: 2, - class: "load-more-btn", - onClick: unref(loadMore) - }, "↑ Load previous messages", 8, ["onClick"])) : msg.role === "session_context" ? (openBlock(), createBlock("div", { - key: 3, - class: "session-context-badge" - }, [ - createVNode("span", { class: "session-context-text" }, toDisplayString(msg.content), 1) - ])) : msg.role === "user" ? (openBlock(), createBlock(UserMessage, { - key: 4, - msg - }, null, 8, ["msg"])) : msg.role === "thinking" ? (openBlock(), createBlock("div", { - key: 5, - class: "message thinking" - }, [ - createVNode("details", { - open: !msg.collapsed - }, [ - createVNode("summary", null, [ - createVNode(unref(ChatBubbleBottomCenterTextIcon), { class: "w-4 h-4 inline" }), - createTextVNode(" thinking…") - ]), - createVNode("pre", { class: "thinking-content" }, toDisplayString(typeof msg.content === "object" ? msg.content.value : msg.content), 1) - ], 8, ["open"]) - ])) : msg.role === "assistant" ? (openBlock(), createBlock(AssistantMessage, { - key: 6, - msg, - agentDisplayName: unref(getFormattedAgentName)(msg.agentId), - isAgentRunning: unref(isAgentRunning), - allAgents: unref(allAgents), - getToolsForTurn: unref(getToolsForTurn), - hudVersion: unref(hudVersion) - }, null, 8, ["msg", "agentDisplayName", "isAgentRunning", "allAgents", "getToolsForTurn", "hudVersion"])) : createCommentVNode("", true), - i === lastRealMsgIdx.value ? (openBlock(), createBlock("div", { - key: 7, - class: "sm-status-bar" - }, [ - createVNode("div", { - class: ["sm-dot", smState.value] - }, null, 2), - createVNode("span", { class: "sm-status-label" }, toDisplayString(smLabel.value), 1) - ])) : createCommentVNode("", true) - ], 64); - }), 128)), - lastRealMsgIdx.value === -1 ? (openBlock(), createBlock("div", { - key: 1, - class: "sm-status-bar" - }, [ - createVNode("div", { - class: ["sm-dot", smState.value] - }, null, 2), - createVNode("span", { class: "sm-status-label" }, toDisplayString(smLabel.value), 1) - ])) : createCommentVNode("", true), - footerHeadline.value ? (openBlock(), createBlock(SystemMessage, { - key: 2, - msg: footerHeadline.value - }, null, 8, ["msg"])) : createCommentVNode("", true), - createVNode("div", { - class: "msg-controls", - ref_key: "controlsEl", - ref: controlsEl - }, [ - createVNode(HudControls, { - smState: smState.value, - connected: unref(connected), - isAgentRunning: unref(chatStore).isRunning, - handoverPending: unref(chatStore).handoverPending, - isPublic: unref(selectedMode) === "public", - onNew, - onHandover: ($event) => unref(chatStore).handover(), - onConfirmNew, - onStay: ($event) => unref(chatStore).stay() - }, null, 8, ["smState", "connected", "isAgentRunning", "handoverPending", "isPublic", "onHandover", "onStay"]) - ], 512), - createVNode("div", { - class: "scroll-spacer", - style: { height: spacerHeight.value + "px", flexShrink: 0 } - }, null, 4) - ]; - } - }), - _: 1 - }, _parent)); - _push(`
`); - if (unref(micDenied)) { - _push(`
Mic access denied β€” enable in browser settings
`); - } else { - _push(``); - } - if (unref(isRecording)) { - _push(`
${ssrInterpolate(unref(formatDuration)(unref(duration)))}
`); - } else { - _push(``); - } - if (unref(attachments).length) { - _push(`
`); - ssrRenderList(unref(attachments), (att, i) => { - _push(`
`); - if (att.mimeType.startsWith("audio/")) { - _push(`β™«${ssrInterpolate(att.fileName)}`); - } else { - _push(``); - } - _push(`
`); - }); - _push(`
`); - } else { - _push(``); - } - _push(`
`); - if (smState.value === "AGENT_RUNNING" || smState.value === "STOP_PENDING") { - _push(``); - } else { - _push(``); - } - _push(`
`); - } else { - _push(`

`); - _push(ssrRenderComponent(unref(LockClosedIcon), { class: "w-5 h-5 inline" }, null, _parent)); - _push(` Not logged in

`); - _push(ssrRenderComponent(_component_RouterLink, { to: "/login" }, { - default: withCtx((_, _push2, _parent2, _scopeId) => { - if (_push2) { - _push2(`Sign in β†’`); - } else { - return [ - createTextVNode("Sign in β†’") - ]; - } - }), - _: 1 - }, _parent)); - _push(``); - } - }; - } -}); -const _sfc_setup = _sfc_main.setup; -_sfc_main.setup = (props, ctx) => { - const ssrContext = useSSRContext(); - (ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("src/views/AgentsView.vue"); - return _sfc_setup ? _sfc_setup(props, ctx) : void 0; -}; -const AgentsView = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-8c19bd9d"]]); -export { - AgentsView as default -}; diff --git a/.vite-ssg-temp/eyyt8tgg8y/assets/CompanyView-9MVdsTPz.js b/.vite-ssg-temp/eyyt8tgg8y/assets/CompanyView-9MVdsTPz.js deleted file mode 100644 index 3b04a99..0000000 --- a/.vite-ssg-temp/eyyt8tgg8y/assets/CompanyView-9MVdsTPz.js +++ /dev/null @@ -1,66 +0,0 @@ -import { resolveComponent, mergeProps, withCtx, createTextVNode, useSSRContext } from "vue"; -import { ssrRenderAttrs, ssrRenderComponent } from "vue/server-renderer"; -import { _ as _export_sfc } from "../main.mjs"; -import "@unhead/vue/server"; -import "vue-router"; -import "pinia"; -import "@heroicons/vue/24/outline"; -import "@heroicons/vue/20/solid"; -import "overlayscrollbars-vue"; -import "overlayscrollbars"; -const _sfc_main = {}; -function _sfc_ssrRender(_ctx, _push, _parent, _attrs) { - const _component_router_link = resolveComponent("router-link"); - _push(`

Wir bauen
agentische Produkte.

Eigene Plattform. Eigene Infrastruktur. Eigene Regeln.


Was dahintersteht.

Das Wesentliche

Jedes Produkt kennt seinen Bereich und bleibt darin. Tiefe schlΓ€gt Breite β€” verlΓ€sslich, jeden Tag. Keine Extras, die niemand braucht.

Produkte fΓΌr Teams

Ein Produkt fΓΌr das ganze Team. Alle arbeiten mit demselben Zugang β€” in eigenen Sitzungen, mit voller Kontrolle darΓΌber, wer was sieht.

Sicher & konform

Alle Daten liegen in Deutschland. Mandantentrennung auf Containerebene, DSGVO-konforme Verarbeitung, Auftragsverarbeitung inklusive.


Woran wir gerade bauen.

FrΓΌhkindliche Bildung

FachkrΓ€fte sagen, was sie brauchen β€” unser Produkt baut daraus fertige Bildungsangebote. Passend zur Einrichtung, zur Altersgruppe, zum Alltag.

Erwachsenen-Grundbildung

LehrkrΓ€fte an Bildungseinrichtungen bekommen UnterstΓΌtzung bei der Erstellung von Lernangeboten β€” strukturiert, lehrplannah, sofort einsetzbar.


nyx

Produkte kennenlernen, ausprobieren, Zugang einrichten β€” direkt hier, direkt mit nyx.

`); - _push(ssrRenderComponent(_component_router_link, { - to: "/agents", - class: "btn" - }, { - default: withCtx((_, _push2, _parent2, _scopeId) => { - if (_push2) { - _push2(`nyx ΓΆffnen`); - } else { - return [ - createTextVNode("nyx ΓΆffnen") - ]; - } - }), - _: 1 - }, _parent)); - _push(`
Β© 2026 loop42 UG (haftungsbeschrΓ€nkt)
`); -} -const _sfc_setup = _sfc_main.setup; -_sfc_main.setup = (props, ctx) => { - const ssrContext = useSSRContext(); - (ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("src/views/CompanyView.vue"); - return _sfc_setup ? _sfc_setup(props, ctx) : void 0; -}; -const CompanyView = /* @__PURE__ */ _export_sfc(_sfc_main, [["ssrRender", _sfc_ssrRender], ["__scopeId", "data-v-7d8ccc13"]]); -export { - CompanyView as default -}; diff --git a/.vite-ssg-temp/eyyt8tgg8y/assets/DatenschutzView-CmUxA-7Z.js b/.vite-ssg-temp/eyyt8tgg8y/assets/DatenschutzView-CmUxA-7Z.js deleted file mode 100644 index b0d22f5..0000000 --- a/.vite-ssg-temp/eyyt8tgg8y/assets/DatenschutzView-CmUxA-7Z.js +++ /dev/null @@ -1,50 +0,0 @@ -import { resolveComponent, mergeProps, withCtx, createTextVNode, useSSRContext } from "vue"; -import { ssrRenderAttrs, ssrRenderComponent } from "vue/server-renderer"; -import { _ as _export_sfc } from "../main.mjs"; -import "@unhead/vue/server"; -import "vue-router"; -import "pinia"; -import "@heroicons/vue/24/outline"; -import "@heroicons/vue/20/solid"; -import "overlayscrollbars-vue"; -import "overlayscrollbars"; -const _sfc_main = {}; -function _sfc_ssrRender(_ctx, _push, _parent, _attrs) { - const _component_router_link = resolveComponent("router-link"); - _push(`

DatenschutzerklΓ€rung

1. Verantwortlicher

loop42 UG (haftungsbeschrΓ€nkt)
[NAME]
[STRASSE HAUSNUMMER], [PLZ ORT]

2. Erhebung und Speicherung personenbezogener Daten

Beim Besuch dieser Website werden automatisch Informationen allgemeiner Natur erfasst (sog. Server-Logfiles). Diese umfassen u. a. den Browsertyp, das verwendete Betriebssystem, den Referrer, die IP-Adresse sowie Datum und Uhrzeit des Zugriffs. Diese Daten sind nicht bestimmten Personen zuordbar und werden nicht mit anderen Datenquellen zusammengefΓΌhrt.

Eine darΓΌber hinausgehende Erhebung personenbezogener Daten findet auf dieser Website derzeit nicht statt. Sobald weitere Dienste (z. B. Kontaktformular, Nutzerkonten) eingefΓΌhrt werden, wird diese ErklΓ€rung entsprechend aktualisiert.

3. Hosting und Infrastruktur

Diese Website wird auf einem Server in einem deutschen Rechenzentrum betrieben. Der Anbieter ist IONOS SE, Elgendorfer Str. 57, 56410 Montabaur, Deutschland. Weitere Informationen zum Datenschutz bei IONOS finden Sie unter ionos.de.

4. Cookies

Diese Website verwendet keine Cookies.

5. Analyse-Tools und Tracking

Diese Website verwendet keine Analyse-Tools, kein Tracking und keine eingebetteten Inhalte Dritter (z. B. Google Fonts, Social-Media-Widgets). Es werden keine Daten an Dritte ΓΌbermittelt.

6. Ihre Rechte

Sie haben gegenΓΌber uns folgende Rechte hinsichtlich Ihrer personenbezogenen Daten:

  • Recht auf Auskunft (Art. 15 DSGVO)
  • Recht auf Berichtigung (Art. 16 DSGVO)
  • Recht auf LΓΆschung (Art. 17 DSGVO)
  • Recht auf EinschrΓ€nkung der Verarbeitung (Art. 18 DSGVO)
  • Recht auf DatenΓΌbertragbarkeit (Art. 20 DSGVO)
  • Recht auf Widerspruch gegen die Verarbeitung (Art. 21 DSGVO)

Zur AusΓΌbung Ihrer Rechte wenden Sie sich bitte an: [E-MAIL]

7. Beschwerderecht bei der AufsichtsbehΓΆrde

Sie haben das Recht, sich bei einer Datenschutz-AufsichtsbehΓΆrde ΓΌber die Verarbeitung Ihrer personenbezogenen Daten durch uns zu beschweren. Die zustΓ€ndige AufsichtsbehΓΆrde richtet sich nach dem Bundesland des Unternehmenssitzes.

8. AktualitΓ€t und Γ„nderungen

Diese DatenschutzerklΓ€rung ist aktuell gΓΌltig und hat den Stand MΓ€rz 2026. Durch die Weiterentwicklung unserer Website oder aufgrund geΓ€nderter gesetzlicher Vorgaben kann es notwendig werden, diese DatenschutzerklΓ€rung anzupassen.

Β© 2026 loop42 UG (haftungsbeschrΓ€nkt)
`); -} -const _sfc_setup = _sfc_main.setup; -_sfc_main.setup = (props, ctx) => { - const ssrContext = useSSRContext(); - (ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("src/views/DatenschutzView.vue"); - return _sfc_setup ? _sfc_setup(props, ctx) : void 0; -}; -const DatenschutzView = /* @__PURE__ */ _export_sfc(_sfc_main, [["ssrRender", _sfc_ssrRender], ["__scopeId", "data-v-2cc9352e"]]); -export { - DatenschutzView as default -}; diff --git a/.vite-ssg-temp/eyyt8tgg8y/assets/DevView-CqaEvdwT.js b/.vite-ssg-temp/eyyt8tgg8y/assets/DevView-CqaEvdwT.js deleted file mode 100644 index 16d384f..0000000 --- a/.vite-ssg-temp/eyyt8tgg8y/assets/DevView-CqaEvdwT.js +++ /dev/null @@ -1,738 +0,0 @@ -import { defineComponent, ref, computed, onMounted, nextTick, watch, onUnmounted, resolveComponent, unref, mergeProps, withCtx, createVNode, createTextVNode, resolveDynamicComponent, openBlock, createBlock, withDirectives, vModelCheckbox, toDisplayString, createCommentVNode, Fragment, renderList, Teleport, withModifiers, useSSRContext } from "vue"; -import { ssrRenderComponent, ssrIncludeBooleanAttr, ssrRenderClass, ssrRenderVNode, ssrLooseContain, ssrRenderStyle, ssrInterpolate, ssrRenderList, ssrRenderTeleport, ssrRenderAttrs } from "vue/server-renderer"; -import { useRoute } from "vue-router"; -import { t as takeover, g as getApiBase, w as ws, b as auth, s as scrollbarOptions, T as THEME_ICONS, f as useTheme, h as useDevFlags, _ as _export_sfc } from "../main.mjs"; -import { OverlayScrollbarsComponent } from "overlayscrollbars-vue"; -import { HomeIcon, BoltIcon, SignalSlashIcon, LinkIcon, XMarkIcon, CameraIcon, LockClosedIcon } from "@heroicons/vue/20/solid"; -import "@unhead/vue/server"; -import "pinia"; -import "@heroicons/vue/24/outline"; -import "overlayscrollbars"; -const SESSION_KEY = "nyx_session"; -const _sfc_main = /* @__PURE__ */ defineComponent({ - ...{ name: "DevView" }, - __name: "DevView", - __ssrInlineRender: true, - setup(__props) { - const route = useRoute(); - const { isLoggedIn } = auth; - const { connected, send: wsSend, onMessage } = ws; - const { theme, setTheme } = useTheme(); - const devFlags = useDevFlags(); - const takeoverToken = takeover.token; - const captureActive = takeover.capture.isActive; - const breakoutReq = takeover.breakout.pendingRequest; - function handleInitTakeover() { - takeover.init(); - } - function handleRevoke() { - takeover.revoke(); - } - function confirmBreakout() { - breakoutReq.value?.resolve(true); - } - function denyBreakout() { - breakoutReq.value?.resolve(false); - } - async function handleToggleCapture() { - if (captureActive.value) { - takeover.capture.disable(); - } else { - await takeover.capture.enable(); - } - } - const SESSION_TOKEN = () => localStorage.getItem(SESSION_KEY) ?? ""; - const systemRequests = ref([]); - const systemGranted = ref(null); - async function fetchPendingSystemRequests() { - try { - const res = await fetch(`${getApiBase()}/api/system/pending`, { - headers: { Authorization: `Bearer ${SESSION_TOKEN()}` } - }); - if (res.ok) { - const { pending } = await res.json(); - systemRequests.value = pending ?? []; - } - } catch { - } - } - async function approveSystemRequest(requestId) { - const res = await fetch(`${getApiBase()}/api/system/approve`, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ sessionToken: SESSION_TOKEN(), requestId }) - }); - if (res.ok) systemRequests.value = systemRequests.value.filter((r) => r.requestId !== requestId); - } - async function denySystemRequest(requestId) { - await fetch(`${getApiBase()}/api/system/deny`, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ sessionToken: SESSION_TOKEN(), requestId }) - }); - systemRequests.value = systemRequests.value.filter((r) => r.requestId !== requestId); - } - const counterValue = ref(Math.floor(Math.random() * 11)); - const counterBusy = ref(false); - const counterMuted = ref(true); - const challengeMessage = ref(""); - const challengeTimer = ref(0); - let challengeInterval = null; - let challengeGen = 0; - const actionPicker = ref({ title: "", options: [] }); - const actionPickerBusy = ref(false); - async function pickAction(id) { - actionPickerBusy.value = true; - actionPicker.value = { title: "", options: [] }; - try { - await fetch(`${getApiBase()}/api/dev/counter`, { - method: "POST", - headers: { "Content-Type": "application/json", Authorization: `Bearer ${SESSION_TOKEN()}` }, - body: JSON.stringify({ action: "pick", pick: id }) - }); - } catch { - } - actionPickerBusy.value = false; - } - async function counterAction(action) { - counterMuted.value = true; - challengeGen++; - if (challengeInterval) { - clearInterval(challengeInterval); - challengeInterval = null; - } - challengeMessage.value = ""; - challengeTimer.value = 0; - counterBusy.value = true; - try { - await fetch(`${getApiBase()}/api/dev/counter`, { - method: "POST", - headers: { "Content-Type": "application/json", Authorization: `Bearer ${SESSION_TOKEN()}` }, - body: JSON.stringify({ action }) - }); - } catch { - } - counterBusy.value = false; - } - const loading = ref(false); - const statsError = ref(""); - const stats = ref(null); - function fmt(v) { - if (v === null || v === void 0) return "β€”"; - return v.toFixed(2); - } - const usedPct = computed(() => { - const t = stats.value?.credits?.total; - const u = stats.value?.credits?.used; - if (!t) return 0; - return Math.min(100, u / t * 100); - }); - function load() { - if (!connected.value) return; - loading.value = true; - statsError.value = ""; - wsSend({ type: "stats_request" }); - } - const discoing = ref(false); - const discoChatting = ref(false); - function disco() { - if (!connected.value) return; - discoing.value = true; - wsSend({ type: "disco_request" }); - setTimeout(() => { - discoing.value = false; - }, 2e3); - } - function discoChat() { - if (!connected.value) return; - discoChatting.value = true; - wsSend({ type: "disco_chat_request" }); - setTimeout(() => { - discoChatting.value = false; - }, 3e3); - } - let unsubscribeWs = null; - let refreshInterval; - onMounted(() => { - fetchPendingSystemRequests(); - unsubscribeWs = onMessage((data) => { - if (data.type === "system_access_request") { - if (!systemRequests.value.find((r) => r.requestId === data.requestId)) - systemRequests.value.push(data); - return; - } - if (data.type === "counter_update") { - counterValue.value = data.value ?? counterValue.value; - return; - } - if (data.type === "counter_challenge") { - challengeMessage.value = data.message || "DECIDE NOW!"; - challengeTimer.value = data.timeout || 30; - counterMuted.value = false; - nextTick(() => { - const el = document.querySelector(".counter-widget"); - if (el) { - el.classList.remove("flash"); - void el.offsetWidth; - el.classList.add("flash"); - el.scrollIntoView({ behavior: "smooth", block: "center" }); - } - }); - if (challengeInterval) clearInterval(challengeInterval); - const cid = ++challengeGen; - challengeInterval = setInterval(() => { - if (cid !== challengeGen) { - clearInterval(challengeInterval); - return; - } - challengeTimer.value--; - if (challengeTimer.value <= 0) { - if (challengeInterval) { - clearInterval(challengeInterval); - challengeInterval = null; - } - counterMuted.value = true; - challengeMessage.value = ""; - fetch(`${getApiBase()}/api/dev/counter`, { - method: "POST", - headers: { "Content-Type": "application/json", Authorization: `Bearer ${SESSION_TOKEN()}` }, - body: JSON.stringify({ action: "timeout" }) - }); - } - }, 1e3); - return; - } - if (data.type === "confetti") { - const container = document.createElement("div"); - container.className = "confetti-container"; - const colors = ["#ff6b6b", "#ffd93d", "#6bcb77", "#4d96ff", "#ff922b", "#cc5de8"]; - for (let i = 0; i < 60; i++) { - const piece = document.createElement("div"); - piece.className = "confetti-piece"; - piece.style.left = Math.random() * 100 + "%"; - piece.style.background = colors[Math.floor(Math.random() * colors.length)]; - piece.style.animationDelay = Math.random() * 2 + "s"; - piece.style.borderRadius = Math.random() > 0.5 ? "50%" : "0"; - container.appendChild(piece); - } - document.body.appendChild(container); - setTimeout(() => container.remove(), 5e3); - return; - } - if (data.type === "action_picker") { - actionPicker.value = { title: data.title || "Next?", options: data.options || [] }; - actionPickerBusy.value = false; - return; - } - if (data.type === "counter_mute") { - counterMuted.value = true; - challengeMessage.value = data.message || ""; - if (challengeInterval) { - clearInterval(challengeInterval); - challengeInterval = null; - } - challengeTimer.value = 0; - return; - } - if (data.type === "stats") { - loading.value = false; - if (data.error) { - statsError.value = data.error; - } else { - stats.value = data; - } - } - }); - const startRefresh = () => { - load(); - refreshInterval = setInterval(load, 15e3); - }; - if (connected.value) { - startRefresh(); - } else { - const stop = watch(connected, (val) => { - if (val) { - stop(); - startRefresh(); - } - }); - } - }); - watch(() => route.name, (name, prev) => { - if (name === "dev" && !refreshInterval && connected.value) { - load(); - refreshInterval = setInterval(load, 15e3); - } else if (prev === "dev" && name !== "dev" && refreshInterval) { - clearInterval(refreshInterval); - refreshInterval = void 0; - } - }); - onUnmounted(() => { - if (unsubscribeWs) unsubscribeWs(); - if (refreshInterval) clearInterval(refreshInterval); - }); - return (_ctx, _push, _parent, _attrs) => { - const _component_RouterLink = resolveComponent("RouterLink"); - if (unref(isLoggedIn)) { - _push(ssrRenderComponent(unref(OverlayScrollbarsComponent), mergeProps({ - class: "dev-view", - options: unref(scrollbarOptions), - element: "div" - }, _attrs), { - default: withCtx((_, _push2, _parent2, _scopeId) => { - if (_push2) { - _push2(`

/dev

`); - _push2(ssrRenderComponent(_component_RouterLink, { - to: "/agents", - class: "dev-disco-btn" - }, { - default: withCtx((_2, _push3, _parent3, _scopeId2) => { - if (_push3) { - _push3(ssrRenderComponent(unref(HomeIcon), { class: "w-4 h-4 inline" }, null, _parent3, _scopeId2)); - _push3(` Home`); - } else { - return [ - createVNode(unref(HomeIcon), { class: "w-4 h-4 inline" }), - createTextVNode(" Home") - ]; - } - }), - _: 1 - }, _parent2, _scopeId)); - _push2(`

Theme

Dev Flags

Takeover

`); - if (!unref(takeoverToken)) { - _push2(`
`); - } else { - _push2(`
${ssrInterpolate(unref(takeoverToken))}
`); - } - _push2(`
`); - if (systemRequests.value.length > 0 || systemGranted.value) { - _push2(`

System Access

`); - if (systemGranted.value) { - _push2(`
Access granted to ${ssrInterpolate(systemGranted.value.user)} β€” active until session end.
`); - } else { - _push2(``); - } - _push2(``); - ssrRenderList(systemRequests.value, (req) => { - _push2(`
${ssrInterpolate(req.userCode)}
${ssrInterpolate(req.description)}
expires in ${ssrInterpolate(Math.max(0, Math.ceil((req.expiresAt - Date.now()) / 1e3)))}s
`); - }); - _push2(`
`); - } else { - _push2(``); - } - _push2(`

MCP Counter

${ssrInterpolate(counterValue.value)}
`); - if (challengeMessage.value) { - _push2(`
${ssrInterpolate(challengeMessage.value)}`); - if (challengeTimer.value > 0) { - _push2(`${ssrInterpolate(challengeTimer.value)}s`); - } else { - _push2(``); - } - _push2(`
`); - } else { - _push2(`
Waiting for Claude...
`); - } - _push2(`
`); - if (actionPicker.value.title) { - _push2(`

${ssrInterpolate(actionPicker.value.title)}

`); - ssrRenderList(actionPicker.value.options, (opt, i) => { - _push2(``); - }); - _push2(`
`); - } else { - _push2(``); - } - _push2(`

OpenRouter Credits

`); - if (loading.value && !stats.value) { - _push2(`
Loading…
`); - } else if (statsError.value) { - _push2(`
${ssrInterpolate(statsError.value)}
`); - } else if (stats.value) { - _push2(`
Used$${ssrInterpolate(fmt(stats.value.credits.used))}
Remaining$${ssrInterpolate(fmt(stats.value.credits.remaining))}
Total$${ssrInterpolate(fmt(stats.value.credits.total))}
`); - } else { - _push2(``); - } - _push2(`
`); - if (stats.value) { - _push2(`

Agents

`); - ssrRenderList(stats.value.agents, (a) => { - _push2(``); - }); - _push2(`
AgentModelContextPrompt / 1MCompletion / 1M
${ssrInterpolate(a.id)}${ssrInterpolate(a.modelId || a.model)}${ssrInterpolate(a.contextLength ? (a.contextLength / 1e3).toFixed(0) + "k" : "β€”")}${ssrInterpolate(a.promptPrice !== null ? "$" + a.promptPrice.toFixed(3) : "β€”")}${ssrInterpolate(a.completionPrice !== null ? "$" + a.completionPrice.toFixed(3) : "β€”")}
`); - } else { - _push2(``); - } - _push2(`
`); - ssrRenderTeleport(_push2, (_push3) => { - if (unref(breakoutReq)) { - _push3(`

Open Breakout

Name: ${ssrInterpolate(unref(breakoutReq).name)}

Size: ${ssrInterpolate(unref(breakoutReq).preset)}

${ssrInterpolate(unref(breakoutReq).nonce)}

`); - } else { - _push3(``); - } - }, "body", false, _parent2); - } else { - return [ - createVNode("div", { class: "page" }, [ - createVNode("div", { class: "dev-header" }, [ - createVNode("h2", null, "/dev"), - createVNode("div", { class: "dev-actions" }, [ - createVNode(_component_RouterLink, { - to: "/agents", - class: "dev-disco-btn" - }, { - default: withCtx(() => [ - createVNode(unref(HomeIcon), { class: "w-4 h-4 inline" }), - createTextVNode(" Home") - ]), - _: 1 - }), - createVNode("button", { - class: "dev-disco-btn", - onClick: disco, - disabled: discoing.value - }, [ - createVNode(unref(BoltIcon), { class: "w-4 h-4 inline" }), - createTextVNode(" Disconnect Gateway") - ], 8, ["disabled"]), - createVNode("button", { - class: "dev-disco-btn", - onClick: discoChat, - disabled: discoChatting.value - }, [ - createVNode(unref(SignalSlashIcon), { class: "w-4 h-4 inline" }), - createTextVNode(" Disconnect Chat") - ], 8, ["disabled"]) - ]) - ]), - createVNode("div", { class: "content" }, [ - createVNode("div", { class: "dev-section" }, [ - createVNode("h3", null, "Theme"), - createVNode("div", { class: "dev-actions" }, [ - createVNode("button", { - class: ["dev-theme-btn", { active: unref(theme) === "loop42" }], - onClick: ($event) => unref(setTheme)("loop42") - }, [ - (openBlock(), createBlock(resolveDynamicComponent(unref(THEME_ICONS).loop42), { class: "w-4 h-4 inline" })), - createTextVNode(" loop42") - ], 10, ["onClick"]), - createVNode("button", { - class: ["dev-theme-btn", { active: unref(theme) === "titan" }], - onClick: ($event) => unref(setTheme)("titan") - }, [ - (openBlock(), createBlock(resolveDynamicComponent(unref(THEME_ICONS).titan), { class: "w-4 h-4 inline" })), - createTextVNode(" Titan") - ], 10, ["onClick"]), - createVNode("button", { - class: ["dev-theme-btn", { active: unref(theme) === "eras" }], - onClick: ($event) => unref(setTheme)("eras") - }, [ - (openBlock(), createBlock(resolveDynamicComponent(unref(THEME_ICONS).eras), { class: "w-4 h-4 inline" })), - createTextVNode(" ERAS") - ], 10, ["onClick"]) - ]) - ]), - createVNode("div", { class: "dev-section" }, [ - createVNode("h3", null, "Dev Flags"), - createVNode("div", { class: "dev-flags" }, [ - createVNode("label", { class: "dev-flag" }, [ - withDirectives(createVNode("input", { - type: "checkbox", - "onUpdate:modelValue": ($event) => unref(devFlags).showGrid = $event - }, null, 8, ["onUpdate:modelValue"]), [ - [vModelCheckbox, unref(devFlags).showGrid] - ]), - createVNode("span", null, "showGrid") - ]), - createVNode("label", { class: "dev-flag" }, [ - withDirectives(createVNode("input", { - type: "checkbox", - "onUpdate:modelValue": ($event) => unref(devFlags).showDebugInfo = $event - }, null, 8, ["onUpdate:modelValue"]), [ - [vModelCheckbox, unref(devFlags).showDebugInfo] - ]), - createVNode("span", null, "showDebugInfo") - ]), - createVNode("label", { class: "dev-flag" }, [ - withDirectives(createVNode("input", { - type: "checkbox", - "onUpdate:modelValue": ($event) => unref(devFlags).showHud = $event - }, null, 8, ["onUpdate:modelValue"]), [ - [vModelCheckbox, unref(devFlags).showHud] - ]), - createVNode("span", null, "showHud") - ]) - ]) - ]), - createVNode("div", { class: "dev-section" }, [ - createVNode("h3", null, "Takeover"), - !unref(takeoverToken) ? (openBlock(), createBlock("div", { - key: 0, - class: "dev-actions" - }, [ - createVNode("button", { - class: "dev-theme-btn", - onClick: handleInitTakeover - }, [ - createVNode(unref(LinkIcon), { class: "w-4 h-4 inline" }), - createTextVNode(" Enable Takeover") - ]) - ])) : (openBlock(), createBlock("div", { - key: 1, - class: "dev-actions", - style: { "gap": "var(--space-page)", "align-items": "center", "flex-wrap": "wrap" } - }, [ - createVNode("code", { class: "takeover-token" }, toDisplayString(unref(takeoverToken)), 1), - createVNode("button", { - class: "dev-theme-btn active", - onClick: handleRevoke - }, [ - createVNode(unref(XMarkIcon), { class: "w-4 h-4 inline" }), - createTextVNode(" Revoke") - ]), - createVNode("button", { - class: ["dev-theme-btn", { active: unref(captureActive) }], - onClick: handleToggleCapture - }, [ - createVNode(unref(CameraIcon), { class: "w-4 h-4 inline" }), - createTextVNode(" " + toDisplayString(unref(captureActive) ? "Capture ON" : "Enable Capture"), 1) - ], 2) - ])) - ]), - systemRequests.value.length > 0 || systemGranted.value ? (openBlock(), createBlock("div", { - key: 0, - class: "dev-section" - }, [ - createVNode("h3", null, "System Access"), - systemGranted.value ? (openBlock(), createBlock("div", { - key: 0, - class: "dev-system-granted" - }, " Access granted to " + toDisplayString(systemGranted.value.user) + " β€” active until session end. ", 1)) : createCommentVNode("", true), - (openBlock(true), createBlock(Fragment, null, renderList(systemRequests.value, (req) => { - return openBlock(), createBlock("div", { - key: req.requestId, - class: "dev-system-request" - }, [ - createVNode("div", { class: "dev-system-code" }, toDisplayString(req.userCode), 1), - createVNode("div", { class: "dev-system-desc" }, toDisplayString(req.description), 1), - createVNode("div", { class: "dev-system-expiry" }, "expires in " + toDisplayString(Math.max(0, Math.ceil((req.expiresAt - Date.now()) / 1e3))) + "s", 1), - createVNode("div", { - class: "dev-actions", - style: { "margin-top": "8px" } - }, [ - createVNode("button", { - class: "dev-theme-btn", - onClick: ($event) => denySystemRequest(req.requestId) - }, "Deny", 8, ["onClick"]), - createVNode("button", { - class: "dev-theme-btn active", - onClick: ($event) => approveSystemRequest(req.requestId) - }, "Approve", 8, ["onClick"]) - ]) - ]); - }), 128)) - ])) : createCommentVNode("", true), - createVNode("div", { class: "dev-section" }, [ - createVNode("h3", null, "MCP Counter"), - createVNode("div", { - class: ["counter-widget", { muted: counterMuted.value }] - }, [ - createVNode("div", { class: "counter-controls" }, [ - createVNode("button", { - class: "counter-btn", - onClick: ($event) => counterAction("decrement"), - disabled: counterMuted.value || counterBusy.value - }, "βˆ’", 8, ["onClick", "disabled"]), - createVNode("span", { - class: "counter-value", - id: "mcp-counter-value" - }, toDisplayString(counterValue.value), 1), - createVNode("button", { - class: "counter-btn", - onClick: ($event) => counterAction("increment"), - disabled: counterMuted.value || counterBusy.value - }, "+", 8, ["onClick", "disabled"]) - ]), - challengeMessage.value ? (openBlock(), createBlock("div", { - key: 0, - class: "counter-challenge" - }, [ - createVNode("span", { class: "counter-message" }, toDisplayString(challengeMessage.value), 1), - challengeTimer.value > 0 ? (openBlock(), createBlock("span", { - key: 0, - class: "counter-timer" - }, toDisplayString(challengeTimer.value) + "s", 1)) : createCommentVNode("", true) - ])) : (openBlock(), createBlock("div", { - key: 1, - class: "counter-hint" - }, "Waiting for Claude...")) - ], 2) - ]), - actionPicker.value.title ? (openBlock(), createBlock("div", { - key: 1, - class: "dev-section" - }, [ - createVNode("h3", null, toDisplayString(actionPicker.value.title), 1), - createVNode("div", { class: "action-picker" }, [ - (openBlock(true), createBlock(Fragment, null, renderList(actionPicker.value.options, (opt, i) => { - return openBlock(), createBlock("button", { - key: i, - class: "action-pick-btn", - disabled: actionPickerBusy.value, - onClick: ($event) => pickAction(opt.id) - }, toDisplayString(opt.label), 9, ["disabled", "onClick"]); - }), 128)) - ]) - ])) : createCommentVNode("", true), - createVNode("div", { class: "dev-section" }, [ - createVNode("h3", null, "OpenRouter Credits"), - loading.value && !stats.value ? (openBlock(), createBlock("div", { - key: 0, - class: "dev-loading" - }, "Loading…")) : statsError.value ? (openBlock(), createBlock("div", { - key: 1, - class: "dev-error" - }, toDisplayString(statsError.value), 1)) : stats.value ? (openBlock(), createBlock("div", { - key: 2, - class: "credits-widget" - }, [ - createVNode("div", { class: "credits-bar-track" }, [ - createVNode("div", { - class: "credits-bar-fill", - style: { width: usedPct.value + "%" } - }, null, 4) - ]), - createVNode("div", { class: "credits-row" }, [ - createVNode("div", { class: "credits-stat" }, [ - createVNode("span", { class: "credits-label" }, "Used"), - createVNode("span", { class: "credits-amount credits-used" }, "$" + toDisplayString(fmt(stats.value.credits.used)), 1) - ]), - createVNode("div", { class: "credits-stat" }, [ - createVNode("span", { class: "credits-label" }, "Remaining"), - createVNode("span", { class: "credits-amount credits-remaining" }, "$" + toDisplayString(fmt(stats.value.credits.remaining)), 1) - ]), - createVNode("div", { class: "credits-stat" }, [ - createVNode("span", { class: "credits-label" }, "Total"), - createVNode("span", { class: "credits-amount" }, "$" + toDisplayString(fmt(stats.value.credits.total)), 1) - ]) - ]) - ])) : createCommentVNode("", true) - ]), - stats.value ? (openBlock(), createBlock("div", { - key: 2, - class: "dev-section" - }, [ - createVNode("h3", null, "Agents"), - createVNode("div", { class: "dev-table-wrap" }, [ - createVNode("table", { class: "dev-table" }, [ - createVNode("thead", null, [ - createVNode("tr", null, [ - createVNode("th", null, "Agent"), - createVNode("th", null, "Model"), - createVNode("th", null, "Context"), - createVNode("th", null, "Prompt / 1M"), - createVNode("th", null, "Completion / 1M") - ]) - ]), - createVNode("tbody", null, [ - (openBlock(true), createBlock(Fragment, null, renderList(stats.value.agents, (a) => { - return openBlock(), createBlock("tr", { - key: a.id - }, [ - createVNode("td", { class: "agent-id" }, toDisplayString(a.id), 1), - createVNode("td", null, [ - createVNode("code", null, toDisplayString(a.modelId || a.model), 1) - ]), - createVNode("td", null, toDisplayString(a.contextLength ? (a.contextLength / 1e3).toFixed(0) + "k" : "β€”"), 1), - createVNode("td", null, toDisplayString(a.promptPrice !== null ? "$" + a.promptPrice.toFixed(3) : "β€”"), 1), - createVNode("td", null, toDisplayString(a.completionPrice !== null ? "$" + a.completionPrice.toFixed(3) : "β€”"), 1) - ]); - }), 128)) - ]) - ]) - ]) - ])) : createCommentVNode("", true) - ]) - ]), - (openBlock(), createBlock(Teleport, { to: "body" }, [ - unref(breakoutReq) ? (openBlock(), createBlock("div", { - key: 0, - class: "breakout-modal-overlay", - onClick: withModifiers(denyBreakout, ["self"]) - }, [ - createVNode("div", { class: "breakout-modal" }, [ - createVNode("h3", null, "Open Breakout"), - createVNode("p", null, [ - createTextVNode("Name: "), - createVNode("strong", null, toDisplayString(unref(breakoutReq).name), 1) - ]), - createVNode("p", null, [ - createTextVNode("Size: "), - createVNode("strong", null, toDisplayString(unref(breakoutReq).preset), 1) - ]), - createVNode("p", { class: "breakout-nonce" }, toDisplayString(unref(breakoutReq).nonce), 1), - createVNode("div", { class: "breakout-modal-actions" }, [ - createVNode("button", { - class: "dev-theme-btn", - onClick: denyBreakout - }, "Cancel"), - createVNode("button", { - class: "dev-theme-btn active", - onClick: confirmBreakout - }, "Confirm") - ]) - ]) - ])) : createCommentVNode("", true) - ])) - ]; - } - }), - _: 1 - }, _parent)); - } else { - _push(`

`); - _push(ssrRenderComponent(unref(LockClosedIcon), { class: "w-5 h-5 inline" }, null, _parent)); - _push(` Not logged in

`); - _push(ssrRenderComponent(_component_RouterLink, { to: "/login" }, { - default: withCtx((_, _push2, _parent2, _scopeId) => { - if (_push2) { - _push2(`Sign in β†’`); - } else { - return [ - createTextVNode("Sign in β†’") - ]; - } - }), - _: 1 - }, _parent)); - _push(``); - } - }; - } -}); -const _sfc_setup = _sfc_main.setup; -_sfc_main.setup = (props, ctx) => { - const ssrContext = useSSRContext(); - (ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("src/views/DevView.vue"); - return _sfc_setup ? _sfc_setup(props, ctx) : void 0; -}; -const DevView = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-6fcff79f"]]); -export { - DevView as default -}; diff --git a/.vite-ssg-temp/eyyt8tgg8y/assets/ImpressumView-B77dj09a.js b/.vite-ssg-temp/eyyt8tgg8y/assets/ImpressumView-B77dj09a.js deleted file mode 100644 index b79a791..0000000 --- a/.vite-ssg-temp/eyyt8tgg8y/assets/ImpressumView-B77dj09a.js +++ /dev/null @@ -1,50 +0,0 @@ -import { resolveComponent, mergeProps, withCtx, createTextVNode, useSSRContext } from "vue"; -import { ssrRenderAttrs, ssrRenderComponent } from "vue/server-renderer"; -import { _ as _export_sfc } from "../main.mjs"; -import "@unhead/vue/server"; -import "vue-router"; -import "pinia"; -import "@heroicons/vue/24/outline"; -import "@heroicons/vue/20/solid"; -import "overlayscrollbars-vue"; -import "overlayscrollbars"; -const _sfc_main = {}; -function _sfc_ssrRender(_ctx, _push, _parent, _attrs) { - const _component_router_link = resolveComponent("router-link"); - _push(`

Impressum

Angaben gemÀß § 5 TMG

loop42 UG (haftungsbeschrΓ€nkt)
[STRASSE HAUSNUMMER]
[PLZ ORT]
Deutschland

Vertreten durch

[NAME]

Kontakt

Telefon: [TELEFONNUMMER]

Registereintrag

Eintragung im Handelsregister.
Registergericht: [AMTSGERICHT]
Registernummer: [HRB-NUMMER]

Umsatzsteuer-ID

Umsatzsteuer-Identifikationsnummer gemÀß § 27 a Umsatzsteuergesetz:
[UST-ID-NUMMER]

Verantwortlich fΓΌr den Inhalt nach Β§ 55 Abs. 2 RStV

[NAME]
[STRASSE HAUSNUMMER]
[PLZ ORT]

Streitschlichtung

Die EuropΓ€ische Kommission stellt eine Plattform zur Online-Streitbeilegung (OS) bereit: https://ec.europa.eu/consumers/odr/.
Unsere E-Mail-Adresse finden Sie oben im Impressum.

Wir sind nicht bereit oder verpflichtet, an Streitbeilegungsverfahren vor einer Verbraucherschlichtungsstelle teilzunehmen.

Β© 2026 loop42 UG (haftungsbeschrΓ€nkt)
`); -} -const _sfc_setup = _sfc_main.setup; -_sfc_main.setup = (props, ctx) => { - const ssrContext = useSSRContext(); - (ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("src/views/ImpressumView.vue"); - return _sfc_setup ? _sfc_setup(props, ctx) : void 0; -}; -const ImpressumView = /* @__PURE__ */ _export_sfc(_sfc_main, [["ssrRender", _sfc_ssrRender], ["__scopeId", "data-v-d8c150db"]]); -export { - ImpressumView as default -}; diff --git a/.vite-ssg-temp/eyyt8tgg8y/assets/ViewerView-5go7ZmZ8.js b/.vite-ssg-temp/eyyt8tgg8y/assets/ViewerView-5go7ZmZ8.js deleted file mode 100644 index 34e1e60..0000000 --- a/.vite-ssg-temp/eyyt8tgg8y/assets/ViewerView-5go7ZmZ8.js +++ /dev/null @@ -1,445 +0,0 @@ -import { computed, ref, onMounted, watch, onUnmounted, defineComponent, mergeProps, unref, withCtx, openBlock, createBlock, createVNode, toDisplayString, Fragment, renderList, createCommentVNode, createTextVNode, useSSRContext } from "vue"; -import { ssrRenderAttrs, ssrRenderList, ssrRenderClass, ssrInterpolate, ssrRenderAttr, ssrRenderComponent } from "vue/server-renderer"; -import { OverlayScrollbarsComponent } from "overlayscrollbars-vue"; -import { i as useViewerStore, g as getApiBase, w as ws, l as lastViewerPath, s as scrollbarOptions, _ as _export_sfc } from "../main.mjs"; -import { ArrowDownTrayIcon, FolderOpenIcon, FolderIcon, DocumentIcon } from "@heroicons/vue/20/solid"; -import { useRoute, useRouter } from "vue-router"; -import { marked } from "marked"; -import "@unhead/vue/server"; -import "pinia"; -import "@heroicons/vue/24/outline"; -import "overlayscrollbars"; -function useViewer() { - const route = useRoute(); - const router = useRouter(); - const { onMessage } = ws; - const viewerStore = useViewerStore(); - const fstoken = computed(() => viewerStore.fstoken); - const viewerRoots = computed(() => viewerStore.roots); - const token = fstoken; - function normalizePath(path) { - if (!path) return path; - const roots = viewerStore.roots; - if (!roots.length) return path; - const [prefix, ...rest] = path.split("/"); - if (roots.includes(prefix)) return path; - const canonical = roots.find((r) => r === `workspace-${prefix}` || r.endsWith(`-${prefix}`)); - return canonical ? [canonical, ...rest].join("/") : path; - } - const currentPath = ref(normalizePath( - route.query.path || localStorage.getItem("viewer_last_path") || "" - )); - const sidebarCollapsed = ref(window.innerWidth < 768); - const content = ref(""); - const fileType = ref(""); - const dirFiles = ref([]); - const dirDirs = ref([]); - const loading = ref(false); - const showLoading = ref(false); - let loadingTimer = null; - const fetchError = ref(""); - const pdfCacheBust = ref(Date.now()); - const mdRaw = ref(false); - const mdLineCount = computed(() => { - if (!content.value) return 0; - return content.value.split("\n").length; - }); - const renderedMd = computed(() => { - if (fileType.value !== "md" || !content.value) return ""; - return marked.parse(content.value); - }); - const pdfSrc = computed(() => { - if (fileType.value !== "pdf" || !currentPath.value || !token.value) return ""; - const base = getBaseUrl(); - return `${base}/api/viewer/file?path=${encodeURIComponent(currentPath.value)}&token=${encodeURIComponent(token.value)}&t=${pdfCacheBust.value}`; - }); - function getBaseUrl() { - return getApiBase(); - } - function extOf(p) { - const m = p.match(/\.([^./]+)$/); - return m ? m[1].toLowerCase() : ""; - } - function startLoading(silent) { - if (silent) return; - loading.value = true; - showLoading.value = false; - if (loadingTimer) clearTimeout(loadingTimer); - loadingTimer = setTimeout(() => { - showLoading.value = true; - }, 3e3); - } - function stopLoading() { - loading.value = false; - showLoading.value = false; - if (loadingTimer) { - clearTimeout(loadingTimer); - loadingTimer = null; - } - } - async function fetchContent(path, silent = false, _retry = false) { - startLoading(silent); - try { - const base = getBaseUrl(); - const url = `${base}/api/viewer/file?path=${encodeURIComponent(path)}&token=${encodeURIComponent(token.value)}`; - const res = await fetch(url); - if (res.status === 401 && !_retry) { - viewerStore.invalidate(); - await viewerStore.acquire(true); - return fetchContent(path, silent, true); - } - if (!res.ok) { - fetchError.value = `${res.status}: ${await res.text()}`; - return; - } - fetchError.value = ""; - content.value = await res.text(); - } catch (e) { - fetchError.value = e.message || "Fetch failed"; - } finally { - stopLoading(); - } - } - async function openFile(path) { - path = normalizePath(path); - currentPath.value = path; - localStorage.setItem("viewer_last_path", path); - lastViewerPath.value = path; - if (route.query.path !== path) { - router.push({ name: "viewer", query: { path } }); - } - const ext = extOf(path); - if (!path) { - fileType.value = "dir"; - content.value = ""; - fetchError.value = ""; - dirDirs.value = viewerRoots.value.length ? viewerRoots.value : ["shared", "workspace-titan"]; - dirFiles.value = []; - return; - } - if (!ext) { - fileType.value = "dir"; - content.value = ""; - fetchError.value = ""; - startLoading(false); - try { - const base = getBaseUrl(); - const url = `${base}/api/viewer/tree?root=${encodeURIComponent(path)}&token=${encodeURIComponent(token.value)}`; - const res = await fetch(url); - if (!res.ok) throw new Error(`${res.status} ${res.statusText}`); - const data = await res.json(); - dirDirs.value = data.dirs || []; - dirFiles.value = data.files || []; - } catch (e) { - dirDirs.value = []; - dirFiles.value = []; - fetchError.value = e.message || "Failed to load directory"; - } finally { - stopLoading(); - } - return; - } - if (ext === "pdf") { - fileType.value = "pdf"; - content.value = ""; - fetchError.value = ""; - pdfCacheBust.value = Date.now(); - fetch(`${getBaseUrl()}/api/viewer/file?path=${encodeURIComponent(path)}&token=${encodeURIComponent(token.value)}`, { method: "HEAD" }).catch(() => { - }); - return; - } - fileType.value = ext === "md" ? "md" : "text"; - fetchError.value = ""; - await fetchContent(path, false); - } - function onCopy(e) { - const sel = window.getSelection(); - if (!sel || sel.isCollapsed) return; - const html = (() => { - const div = document.createElement("div"); - div.appendChild(sel.getRangeAt(0).cloneContents()); - return div.innerHTML; - })(); - const clean = html.replace(/background(-color)?:[^;"]*(;|(?="))/gi, ""); - const plain = sel.toString(); - e.clipboardData.setData("text/html", clean); - e.clipboardData.setData("text/plain", plain); - e.preventDefault(); - } - async function refreshFile(path) { - const ext = extOf(path); - if (ext === "pdf") { - pdfCacheBust.value = Date.now(); - return; - } - await fetchContent(path, true); - } - let unsubscribe = null; - onMounted(() => { - unsubscribe = onMessage((data) => { - if (data.type === "viewer_file_changed" && data.path === currentPath.value) { - refreshFile(currentPath.value); - } - if (data.type === "viewer_tree_changed" && data.path === currentPath.value && fileType.value === "dir") { - openFile(currentPath.value); - } - }); - viewerStore.acquire(); - if (currentPath.value) openFile(currentPath.value); - }); - watch(() => route.query.path, (newPath) => { - if (newPath && newPath !== currentPath.value) { - openFile(newPath); - } - }); - onUnmounted(() => { - if (unsubscribe) unsubscribe(); - }); - return { - fstoken, - viewerRoots, - currentPath, - sidebarCollapsed, - content, - fileType, - loading, - fetchError, - mdRaw, - mdLineCount, - renderedMd, - pdfSrc, - openFile, - onCopy, - dirFiles, - dirDirs, - showLoading - }; -} -const _sfc_main = /* @__PURE__ */ defineComponent({ - ...{ name: "ViewerView" }, - __name: "ViewerView", - __ssrInlineRender: true, - setup(__props) { - const { - fstoken, - currentPath, - content, - fileType, - showLoading, - fetchError, - mdRaw, - renderedMd, - pdfSrc, - openFile, - onCopy, - dirFiles, - dirDirs - } = useViewer(); - const contentLines = computed(() => content.value.split("\n")); - const fileName = computed(() => { - if (!currentPath.value) return ""; - return currentPath.value.split("/").pop() || ""; - }); - const downloadUrl = computed(() => { - if (!currentPath.value || !fstoken.value) return ""; - return `${getApiBase()}/api/viewer/file?path=${encodeURIComponent(currentPath.value)}&token=${encodeURIComponent(fstoken.value)}&dl=1`; - }); - const breadcrumbs = computed(() => { - const crumbs = [{ label: "files", path: "" }]; - if (!currentPath.value) return crumbs; - const parts = currentPath.value.split("/"); - for (let i = 0; i < parts.length; i++) { - crumbs.push({ label: parts[i], path: parts.slice(0, i + 1).join("/") }); - } - return crumbs; - }); - return (_ctx, _push, _parent, _attrs) => { - _push(`
`); - if (unref(currentPath) || unref(fileType) === "dir") { - _push(`
`); - if (unref(fileType) === "md") { - _push(`
`); - } else { - _push(``); - } - if (unref(fileType) && unref(fileType) !== "dir") { - _push(``); - _push(ssrRenderComponent(unref(ArrowDownTrayIcon), { class: "w-4 h-4" }, null, _parent)); - _push(``); - } else { - _push(``); - } - _push(`
`); - } else { - _push(``); - } - _push(ssrRenderComponent(unref(OverlayScrollbarsComponent), { - class: "content flex-1 min-h-0", - options: unref(scrollbarOptions), - element: "div" - }, { - default: withCtx((_, _push2, _parent2, _scopeId) => { - if (_push2) { - if (!unref(currentPath) && unref(fileType) !== "dir") { - _push2(`
`); - _push2(ssrRenderComponent(unref(FolderOpenIcon), { class: "w-8 h-8 text-text-dim" }, null, _parent2, _scopeId)); - _push2(`

Select a file from the tree

`); - } else if (unref(showLoading)) { - _push2(`
loading…
`); - } else if (unref(fetchError)) { - _push2(`
${ssrInterpolate(unref(fetchError))}
`); - } else if (unref(fileType) === "dir") { - _push2(`
`); - ssrRenderList(unref(dirDirs), (d) => { - _push2(`
`); - _push2(ssrRenderComponent(unref(FolderIcon), { class: "w-4 h-4" }, null, _parent2, _scopeId)); - _push2(`${ssrInterpolate(d)}/
`); - }); - _push2(``); - ssrRenderList(unref(dirFiles), (f) => { - _push2(`
`); - _push2(ssrRenderComponent(unref(DocumentIcon), { class: "w-4 h-4" }, null, _parent2, _scopeId)); - _push2(`${ssrInterpolate(f.name)}
`); - }); - _push2(``); - if (!unref(dirDirs).length && !unref(dirFiles).length) { - _push2(`

Empty directory

`); - } else { - _push2(``); - } - _push2(`
`); - } else if (unref(fileType) === "pdf") { - _push2(``); - } else if (unref(fileType) === "md" && !unref(mdRaw)) { - _push2(`
${unref(renderedMd) ?? ""}
`); - } else if (unref(fileType) === "md" && unref(mdRaw)) { - _push2(`
`);
-              ssrRenderList(contentLines.value, (line, i) => {
-                _push2(`${ssrInterpolate(i + 1)}${ssrInterpolate(line)}
-`);
-              });
-              _push2(`
`); - } else { - _push2(`
`);
-              ssrRenderList(contentLines.value, (line, i) => {
-                _push2(`${ssrInterpolate(i + 1)}${ssrInterpolate(line)}
-`);
-              });
-              _push2(`
`); - } - } else { - return [ - !unref(currentPath) && unref(fileType) !== "dir" ? (openBlock(), createBlock("div", { - key: 0, - class: "viewer-empty" - }, [ - createVNode(unref(FolderOpenIcon), { class: "w-8 h-8 text-text-dim" }), - createVNode("p", null, "Select a file from the tree") - ])) : unref(showLoading) ? (openBlock(), createBlock("div", { - key: 1, - class: "viewer-loading" - }, "loading…")) : unref(fetchError) ? (openBlock(), createBlock("div", { - key: 2, - class: "viewer-error" - }, toDisplayString(unref(fetchError)), 1)) : unref(fileType) === "dir" ? (openBlock(), createBlock("div", { - key: 3, - class: "viewer-dir" - }, [ - (openBlock(true), createBlock(Fragment, null, renderList(unref(dirDirs), (d) => { - return openBlock(), createBlock("div", { - key: d, - class: "dir-entry dir-entry--dir", - onClick: ($event) => unref(openFile)(unref(currentPath) ? unref(currentPath) + "/" + d : d) - }, [ - createVNode(unref(FolderIcon), { class: "w-4 h-4" }), - createVNode("span", null, toDisplayString(d) + "/", 1) - ], 8, ["onClick"]); - }), 128)), - (openBlock(true), createBlock(Fragment, null, renderList(unref(dirFiles), (f) => { - return openBlock(), createBlock("div", { - key: f.path, - class: "dir-entry dir-entry--file", - onClick: ($event) => unref(openFile)(f.path) - }, [ - createVNode(unref(DocumentIcon), { class: "w-4 h-4" }), - createVNode("span", null, toDisplayString(f.name), 1) - ], 8, ["onClick"]); - }), 128)), - !unref(dirDirs).length && !unref(dirFiles).length ? (openBlock(), createBlock("div", { - key: 0, - class: "viewer-empty" - }, [ - createVNode("p", null, "Empty directory") - ])) : createCommentVNode("", true) - ])) : unref(fileType) === "pdf" ? (openBlock(), createBlock("iframe", { - key: 4, - class: "viewer-pdf", - src: unref(pdfSrc), - frameborder: "0" - }, null, 8, ["src"])) : unref(fileType) === "md" && !unref(mdRaw) ? (openBlock(), createBlock("div", { - key: 5, - class: "viewer-md md-body", - innerHTML: unref(renderedMd), - onCopy: unref(onCopy) - }, null, 40, ["innerHTML", "onCopy"])) : unref(fileType) === "md" && unref(mdRaw) ? (openBlock(), createBlock("div", { - key: 6, - class: "viewer-raw-md" - }, [ - createVNode("pre", { class: "viewer-raw-code" }, [ - createVNode("code", null, [ - (openBlock(true), createBlock(Fragment, null, renderList(contentLines.value, (line, i) => { - return openBlock(), createBlock("span", { - key: i, - class: "code-line" - }, [ - createVNode("span", { class: "line-num" }, toDisplayString(i + 1), 1), - createTextVNode(toDisplayString(line) + "\n", 1) - ]); - }), 128)) - ]) - ]) - ])) : (openBlock(), createBlock("pre", { - key: 7, - class: "viewer-raw-code" - }, [ - createVNode("code", null, [ - (openBlock(true), createBlock(Fragment, null, renderList(contentLines.value, (line, i) => { - return openBlock(), createBlock("span", { - key: i, - class: "code-line" - }, [ - createVNode("span", { class: "line-num" }, toDisplayString(i + 1), 1), - createTextVNode(toDisplayString(line) + "\n", 1) - ]); - }), 128)) - ]) - ])) - ]; - } - }), - _: 1 - }, _parent)); - _push(`
`); - }; - } -}); -const _sfc_setup = _sfc_main.setup; -_sfc_main.setup = (props, ctx) => { - const ssrContext = useSSRContext(); - (ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("src/views/ViewerView.vue"); - return _sfc_setup ? _sfc_setup(props, ctx) : void 0; -}; -const ViewerView = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-6b5cb038"]]); -export { - ViewerView as default -}; diff --git a/.vite-ssg-temp/eyyt8tgg8y/favicon-eras.svg b/.vite-ssg-temp/eyyt8tgg8y/favicon-eras.svg deleted file mode 100644 index 39b02f3..0000000 --- a/.vite-ssg-temp/eyyt8tgg8y/favicon-eras.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/.vite-ssg-temp/eyyt8tgg8y/favicon-loop42.svg b/.vite-ssg-temp/eyyt8tgg8y/favicon-loop42.svg deleted file mode 100644 index 9aeb27c..0000000 --- a/.vite-ssg-temp/eyyt8tgg8y/favicon-loop42.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - 42 - diff --git a/.vite-ssg-temp/eyyt8tgg8y/favicon-titan.svg b/.vite-ssg-temp/eyyt8tgg8y/favicon-titan.svg deleted file mode 100644 index 22ec087..0000000 --- a/.vite-ssg-temp/eyyt8tgg8y/favicon-titan.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/.vite-ssg-temp/eyyt8tgg8y/favicon.svg b/.vite-ssg-temp/eyyt8tgg8y/favicon.svg deleted file mode 100644 index 22ec087..0000000 --- a/.vite-ssg-temp/eyyt8tgg8y/favicon.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/.vite-ssg-temp/eyyt8tgg8y/fonts/ubuntu-sans/UbuntuSans-Italic[wght].woff2 b/.vite-ssg-temp/eyyt8tgg8y/fonts/ubuntu-sans/UbuntuSans-Italic[wght].woff2 deleted file mode 100644 index 6b711544ed4eadc076e9e4390b2dcf94fece6f2c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 39052 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 UD~-b%Nw>FSBeq7y25UYJ0J$;BAOHXW diff --git a/.vite-ssg-temp/eyyt8tgg8y/fonts/ubuntu-sans/UbuntuSans[wght].woff2 b/.vite-ssg-temp/eyyt8tgg8y/fonts/ubuntu-sans/UbuntuSans[wght].woff2 deleted file mode 100644 index 6dd2f360b2b0c2b1aa06c7e1b05130258bdff2cd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24280 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 Lx;ctG;kDBPR}?em diff --git a/.vite-ssg-temp/eyyt8tgg8y/main.mjs b/.vite-ssg-temp/eyyt8tgg8y/main.mjs deleted file mode 100644 index b27bd4f..0000000 --- a/.vite-ssg-temp/eyyt8tgg8y/main.mjs +++ /dev/null @@ -1,2890 +0,0 @@ -import { createHead } from "@unhead/vue/server"; -import { defineComponent, ref, onMounted, createSSRApp, computed, watch, reactive, nextTick, unref, mergeProps, useSSRContext, onUnmounted, resolveComponent, withCtx, createVNode, resolveDynamicComponent, openBlock, createBlock, toDisplayString, createCommentVNode, defineAsyncComponent } from "vue"; -import { createRouter, createMemoryHistory, useRouter, useRoute } from "vue-router"; -import { defineStore, createPinia } from "pinia"; -import { ssrRenderAttrs, ssrRenderList, ssrRenderClass, ssrRenderStyle, ssrRenderComponent, ssrInterpolate, ssrRenderAttr, ssrRenderVNode, ssrIncludeBooleanAttr } from "vue/server-renderer"; -import { CubeTransparentIcon, SunIcon, CommandLineIcon } from "@heroicons/vue/24/outline"; -import { ChevronDownIcon, ChevronRightIcon, DocumentIcon, ChevronLeftIcon, ChatBubbleLeftRightIcon, FolderIcon, FolderOpenIcon, WifiIcon, SignalIcon, CodeBracketIcon, UserCircleIcon, ArrowRightEndOnRectangleIcon } from "@heroicons/vue/20/solid"; -import { OverlayScrollbarsComponent } from "overlayscrollbars-vue"; -import { OverlayScrollbars, ClickScrollPlugin } from "overlayscrollbars"; -if (typeof window === "undefined") { - const noop = () => { - }; - const storage = { getItem: () => null, setItem: noop, removeItem: noop, length: 0, clear: noop, key: () => null }; - globalThis.window = { - location: { protocol: "https:", hostname: "", port: "", hash: "", pathname: "/", origin: "", search: "", href: "" }, - addEventListener: noop, - removeEventListener: noop, - __hermes: {}, - matchMedia: () => ({ matches: false, addEventListener: noop, removeEventListener: noop }), - innerWidth: 1280, - innerHeight: 800, - open: noop, - getComputedStyle: () => ({}) - }; - globalThis.localStorage = storage; - globalThis.sessionStorage = storage; - globalThis.document = { - querySelector: () => null, - querySelectorAll: () => [], - createElement: () => ({ style: {}, getContext: () => null, addEventListener: noop }), - title: "", - head: { appendChild: noop }, - body: { appendChild: noop }, - documentElement: { setAttribute: noop, removeAttribute: noop, style: {} } - }; - try { - globalThis.navigator = { mediaDevices: {}, clipboard: {}, userAgent: "", platform: "" }; - } catch { - } - globalThis.HTMLElement = class { - }; - globalThis.MediaStream = class { - }; - globalThis.WebSocket = class { - send() { - } - close() { - } - }; - globalThis.AudioContext = class { - }; - globalThis.MediaRecorder = class { - }; - globalThis.MutationObserver = class { - observe() { - } - disconnect() { - } - }; - globalThis.ResizeObserver = class { - observe() { - } - disconnect() { - } - }; - globalThis.IntersectionObserver = class { - observe() { - } - disconnect() { - } - }; -} -const ClientOnly = defineComponent({ - setup(props, { slots }) { - const mounted = ref(false); - onMounted(() => mounted.value = true); - return () => { - if (!mounted.value) - return slots.placeholder && slots.placeholder({}); - return slots.default && slots.default({}); - }; - } -}); -function ViteSSG(App, routerOptions, fn, options) { - const { - transformState, - registerComponents = true, - useHead = true, - rootContainer = "#app" - } = {}; - async function createApp$1(routePath) { - const app = createSSRApp(App); - let head; - if (useHead) { - app.use(head = createHead()); - } - const router = createRouter({ - history: createMemoryHistory(routerOptions.base), - ...routerOptions - }); - const { routes: routes2 } = routerOptions; - if (registerComponents) - app.component("ClientOnly", ClientOnly); - const appRenderCallbacks = []; - const onSSRAppRendered = (cb) => appRenderCallbacks.push(cb); - const triggerOnSSRAppRendered = () => { - return Promise.all(appRenderCallbacks.map((cb) => cb())); - }; - const context = { - app, - head, - isClient: false, - router, - routes: routes2, - onSSRAppRendered, - triggerOnSSRAppRendered, - initialState: {}, - transformState, - routePath - }; - await fn?.(context); - app.use(router); - let entryRoutePath; - let isFirstRoute = true; - router.beforeEach((to, from, next) => { - if (isFirstRoute || entryRoutePath && entryRoutePath === to.path) { - isFirstRoute = false; - entryRoutePath = to.path; - to.meta.state = context.initialState; - } - next(); - }); - { - const route = context.routePath ?? "/"; - router.push(route); - await router.isReady(); - context.initialState = router.currentRoute.value.meta.state || {}; - } - const initialState = context.initialState; - return { - ...context, - initialState - }; - } - return createApp$1; -} -const version = "0.1.0"; -const pkg = { - version -}; -function useUI(status2) { - const version2 = `${pkg.version}-${"mnf5vvcg"}`; - const statusClass = computed(() => { - if (status2.value.includes("Connected")) return "connected"; - if (status2.value.includes("Connecting")) return "connecting"; - if (status2.value.includes("Error")) return "error"; - return ""; - }); - return { version: version2, statusClass }; -} -const _ssrFallback = {}; -function useHermes() { - if (typeof window === "undefined") return _ssrFallback; - const w = window; - if (!w.__hermes) w.__hermes = {}; - return w.__hermes; -} -const H$1 = useHermes(); -function getStream() { - return H$1.captureStream || null; -} -function setStream(s) { - H$1.captureStream = s; -} -const isActive = ref(false); -syncState(); -function syncState() { - const stream = getStream(); - isActive.value = !!(stream && stream.active && stream.getVideoTracks().some((t) => t.readyState === "live")); - if (!isActive.value && stream) { - stream.getTracks().forEach((t) => t.stop()); - setStream(null); - } -} -function useCapture() { - async function enable() { - const stream = getStream(); - if (stream && stream.active) { - syncState(); - if (isActive.value) return { enabled: true }; - } - try { - const newStream = await navigator.mediaDevices.getDisplayMedia({ - video: { displaySurface: "browser" }, - preferCurrentTab: true - }); - newStream.getVideoTracks()[0].onended = () => { - setStream(null); - syncState(); - }; - setStream(newStream); - syncState(); - return { enabled: true }; - } catch (e) { - setStream(null); - syncState(); - return { enabled: false, error: `Capture denied: ${e.message}` }; - } - } - function disable() { - const stream = getStream(); - if (stream) { - stream.getTracks().forEach((t) => t.stop()); - setStream(null); - } - syncState(); - } - async function capture(quality = 0.7) { - syncState(); - const stream = getStream(); - if (!stream) return { error: "Capture not enabled -- send enableCapture first" }; - const track = stream.getVideoTracks()[0]; - if (!track || track.readyState !== "live") { - setStream(null); - syncState(); - return { error: "Capture stream ended -- re-enable with enableCapture" }; - } - const video = document.createElement("video"); - video.srcObject = stream; - video.muted = true; - await video.play(); - const canvas = document.createElement("canvas"); - canvas.width = video.videoWidth; - canvas.height = video.videoHeight; - canvas.getContext("2d").drawImage(video, 0, 0); - video.pause(); - video.srcObject = null; - return new Promise((resolve) => { - canvas.toBlob((blob) => { - if (!blob) { - resolve({ error: "Canvas toBlob failed" }); - return; - } - const reader = new FileReader(); - reader.onloadend = () => { - const dataUrl = reader.result; - resolve({ dataUrl, length: dataUrl.length }); - }; - reader.readAsDataURL(blob); - }, "image/jpeg", quality); - }); - } - function healthCheck() { - const stream = getStream(); - if (!stream) return { active: false, tracks: 0, reason: "no stream" }; - const tracks = stream.getVideoTracks(); - const live = tracks.filter((t) => t.readyState === "live"); - if (!stream.active || live.length === 0) { - setStream(null); - syncState(); - return { active: false, tracks: 0, reason: "stream ended" }; - } - return { active: true, tracks: live.length }; - } - return { isActive, enable, disable, capture, healthCheck }; -} -const windows = /* @__PURE__ */ new Map(); -const PRESETS = { - mobile: [375, 812], - tablet: [768, 1024], - "tablet-landscape": [1024, 768], - desktop: [1280, 800] -}; -function deriveToken(parentToken, name) { - return `${parentToken}-breakout-${name}`; -} -function useBreakout() { - const pendingRequest = ref(null); - async function open(args) { - const parentToken = sessionStorage.getItem("hermes_takeover_token"); - if (!parentToken) return { error: "No takeover token active" }; - const name = args.name || "mobile"; - const preset = args.preset || "desktop"; - const existing = windows.get(name); - if (existing && !existing.closed) existing.close(); - const nonce = Math.random().toString(36).slice(2, 6); - const [pw, ph] = args.w && args.h ? [args.w, args.h] : PRESETS[preset] || PRESETS.desktop; - const presetLabel = `${pw}x${ph}`; - return new Promise((resolve) => { - pendingRequest.value = { - name, - preset: presetLabel, - nonce, - resolve: (confirmed) => { - pendingRequest.value = null; - if (!confirmed) { - resolve({ error: "rejected by user" }); - return; - } - const token = deriveToken(parentToken, name); - const url = `${window.location.origin}${window.location.pathname}?breakout_token=${token}/agents`; - const popup = window.open(url, `hermes_breakout_${name}`, `width=${pw},height=${ph},resizable=yes,scrollbars=yes`); - if (!popup) { - resolve({ error: "popup blocked" }); - return; - } - windows.set(name, popup); - resolve({ opened: name, token, size: presetLabel }); - } - }; - }); - } - function openDirect(name, presetStr, parentToken) { - const [w, h] = presetStr.split("x").map(Number); - const token = deriveToken(parentToken, name); - const url = `${window.location.origin}${window.location.pathname}?breakout_token=${token}/agents`; - const popup = window.open(url, `hermes_breakout_${name}`, `width=${w},height=${h},resizable=yes,scrollbars=yes`); - if (!popup) { - alert("Popup blocked -- allow popups for this site"); - return; - } - windows.set(name, popup); - } - function list() { - const result = {}; - for (const [name, win] of windows) { - result[name] = { alive: !win.closed }; - if (win.closed) windows.delete(name); - } - return result; - } - function close(args) { - const win = windows.get(args.name); - if (!win) return { error: `No breakout: ${args.name}` }; - if (!win.closed) win.close(); - windows.delete(args.name); - return { closed: args.name }; - } - return { windows, pendingRequest, open, openDirect, list, close }; -} -const TAKEOVER_KEY = "hermes_takeover_token"; -let currentToken = typeof sessionStorage !== "undefined" ? sessionStorage.getItem(TAKEOVER_KEY) || "" : ""; -function useTakeover(wsSend) { - const token = ref(currentToken); - const capture = useCapture(); - const breakout = useBreakout(); - function init() { - const t = crypto.randomUUID(); - token.value = t; - currentToken = t; - sessionStorage.setItem(TAKEOVER_KEY, t); - wsSend({ type: "dev_takeover", token: t }); - return t; - } - function revoke() { - token.value = ""; - currentToken = ""; - sessionStorage.removeItem(TAKEOVER_KEY); - } - function reregister() { - const urlParams = new URLSearchParams(window.location.search); - const breakoutToken = urlParams.get("breakout_token"); - if (breakoutToken) { - sessionStorage.setItem(TAKEOVER_KEY, breakoutToken); - urlParams.delete("breakout_token"); - const clean = urlParams.toString(); - const newUrl = window.location.pathname + (clean ? "?" + clean : "") + window.location.hash; - window.history.replaceState(null, "", newUrl); - } - const t = sessionStorage.getItem(TAKEOVER_KEY); - if (t) { - token.value = t; - currentToken = t; - wsSend({ type: "dev_takeover", token: t }); - } - } - function boxChain(args) { - const el = document.querySelector(args.selector); - if (!el) return { error: `No element: ${args.selector}` }; - const chain = []; - let node = el; - while (node && node !== document.documentElement) { - const cs = getComputedStyle(node); - const rect = node.getBoundingClientRect(); - chain.push({ - tag: node.tagName.toLowerCase(), - cls: (node.className?.toString() || "").split(" ").filter(Boolean).slice(0, 5).join(" "), - w: Math.round(rect.width), - h: Math.round(rect.height), - l: Math.round(rect.left), - r: Math.round(rect.right), - pl: cs.paddingLeft, - pr: cs.paddingRight, - ml: cs.marginLeft, - mr: cs.marginRight - }); - node = node.parentElement; - } - return chain; - } - function getStyles(args) { - const el = document.querySelector(args.selector); - if (!el) return { error: `No element: ${args.selector}` }; - const cs = getComputedStyle(el); - const rect = el.getBoundingClientRect(); - const props = args.props || ["padding", "margin", "width", "height", "display", "flexDirection", "overflow", "gap"]; - const styles = {}; - for (const p of props) styles[p] = cs.getPropertyValue(p.replace(/[A-Z]/g, (m) => "-" + m.toLowerCase())); - return { ...styles, boundingRect: { w: Math.round(rect.width), h: Math.round(rect.height), l: Math.round(rect.left), r: Math.round(rect.right), t: Math.round(rect.top), b: Math.round(rect.bottom) } }; - } - function viewport() { - return { w: window.innerWidth, h: window.innerHeight, dpr: window.devicePixelRatio, hash: window.location.hash }; - } - function navigate(args) { - window.location.hash = args.hash; - return { navigated: args.hash }; - } - function reload() { - setTimeout(() => window.location.reload(), 100); - return { reloading: true }; - } - function resize(args) { - window.resizeTo(args.w, args.h); - return { resized: `${args.w}x${args.h}` }; - } - function querySelector(args) { - const els = document.querySelectorAll(args.selector); - const limit = args.limit || 10; - return Array.from(els).slice(0, limit).map((el, i) => { - const rect = el.getBoundingClientRect(); - return { - i, - tag: el.tagName.toLowerCase(), - cls: (el.className?.toString() || "").split(" ").filter(Boolean).slice(0, 5).join(" "), - text: (el.textContent || "").slice(0, 60), - w: Math.round(rect.width), - h: Math.round(rect.height), - l: Math.round(rect.left), - t: Math.round(rect.top) - }; - }); - } - function click(args) { - const els = document.querySelectorAll(args.selector); - const idx = args.index || 0; - const el = els[idx]; - if (!el) return { error: `No element: ${args.selector}[${idx}]` }; - el.click(); - return { clicked: args.selector, index: idx }; - } - function getValue(args) { - const el = document.querySelector(args.selector); - if (!el) return { error: `No element: ${args.selector}` }; - return { value: el.value, tag: el.tagName.toLowerCase() }; - } - function setValue(args) { - const el = document.querySelector(args.selector); - if (!el) return { error: `No element: ${args.selector}` }; - const nativeInputValueSetter = Object.getOwnPropertyDescriptor( - el.tagName === "SELECT" ? HTMLSelectElement.prototype : HTMLInputElement.prototype, - "value" - )?.set; - nativeInputValueSetter?.call(el, args.value); - el.dispatchEvent(new Event("input", { bubbles: true })); - el.dispatchEvent(new Event("change", { bubbles: true })); - return { set: args.value, selector: args.selector }; - } - function typeText(args) { - const el = document.querySelector(args.selector); - if (!el) return { error: `No element: ${args.selector}` }; - el.focus(); - el.value = args.text; - el.dispatchEvent(new Event("input", { bubbles: true })); - return { typed: args.text, selector: args.selector }; - } - function screenshot() { - return { - url: window.location.hash, - title: document.title, - viewport: { w: window.innerWidth, h: window.innerHeight }, - body: document.body.innerText.slice(0, 2e3) - }; - } - function scroll(args) { - const el = document.querySelector(args.selector); - if (!el) return { error: `No element: ${args.selector}` }; - const before = el.scrollTop; - if (args.to !== void 0) { - if (args.to === "top") el.scrollTop = 0; - else if (args.to === "bottom") el.scrollTop = el.scrollHeight; - else if (args.to === "middle") el.scrollTop = (el.scrollHeight - el.clientHeight) / 2; - else el.scrollTop = args.to; - } - return { - scrollTop: el.scrollTop, - scrollHeight: el.scrollHeight, - clientHeight: el.clientHeight, - before - }; - } - function getConsole(args) { - const h = useHermes(); - if (!h.console?.length && !h._origConsole) return { error: "Console hook not initialized" }; - let entries = h.console; - if (args.level) entries = entries.filter((e) => e.l === args.level); - if (args.pattern) { - const re = new RegExp(args.pattern, "i"); - entries = entries.filter((e) => re.test(e.m)); - } - const result = entries.slice(-(args.last || 50)); - if (args.clear) h.console.length = 0; - return result; - } - const autoCommands = { - boxChain, - getStyles, - viewport, - navigate, - reload, - resize, - querySelector, - click, - screenshot, - getValue, - setValue, - typeText, - scroll, - getConsole, - listBreakouts: () => breakout.list(), - closeBreakout: (args) => breakout.close(args) - }; - const asyncCommands = { - captureScreen: (args) => capture.capture(args.quality), - enableCapture: () => capture.enable(), - openBreakout: (args) => breakout.open(args) - }; - function dispatch(cmdId, cmd, args, sendResult) { - const fn = autoCommands[cmd]; - if (fn) { - try { - const result = fn(args); - sendResult({ type: "dev_cmd_result", cmdId, result: JSON.parse(JSON.stringify(result ?? null)) }); - } catch (err) { - sendResult({ type: "dev_cmd_result", cmdId, error: err.message }); - } - return; - } - const asyncFn = asyncCommands[cmd]; - if (asyncFn) { - asyncFn(args).then((result) => { - sendResult({ type: "dev_cmd_result", cmdId, result: JSON.parse(JSON.stringify(result ?? null)) }); - }).catch((err) => { - sendResult({ type: "dev_cmd_result", cmdId, error: err.message }); - }); - return; - } - if (cmd === "eval") { - const js = args.js; - if (!js) { - sendResult({ type: "dev_cmd_result", cmdId, error: "js required" }); - return; - } - const ok = window.confirm(`Dev takeover eval request: - -${js.slice(0, 500)} - -Allow?`); - if (!ok) { - sendResult({ type: "dev_cmd_result", cmdId, error: "rejected by user" }); - return; - } - try { - const result = new Function("return (" + js + ")")(); - const serialized = result instanceof Element ? result.outerHTML.slice(0, 500) : JSON.parse(JSON.stringify(result ?? null)); - sendResult({ type: "dev_cmd_result", cmdId, result: serialized }); - } catch (err) { - sendResult({ type: "dev_cmd_result", cmdId, error: err.message }); - } - return; - } - sendResult({ type: "dev_cmd_result", cmdId, error: `Unknown command: ${cmd}` }); - } - return { - token, - capture, - breakout, - init, - revoke, - reregister, - dispatch - }; -} -const H = useHermes(); -let _ws = H.ws ?? null; -let _pingInterval = H.wsPing ?? null; -const _onMessageCallbacks = H.wsCbs ?? []; -const _messageBuffer = H.wsBuf ?? []; -let _reconnectTimer = null; -let _reconnectDelay = 1e3; -let _selectedAgentRef = null; -let _selectedModeRef = null; -let _isLoggedInRef = null; -let _loginErrorRef = null; -let _takeover = null; -const connected = H.wsConnected ?? ref(false); -const status = H.wsStatus ?? ref("Disconnected"); -const currentUser = H.wsUser ?? ref(""); -const sessionId = H.wsSid ?? ref(null); -const isInitialLoad = H.wsInit ?? ref(true); -H.wsConnected = connected; -H.wsStatus = status; -H.wsUser = currentUser; -H.wsSid = sessionId; -H.wsInit = isInitialLoad; -H.wsCbs = _onMessageCallbacks; -H.wsBuf = _messageBuffer; -function send(payload) { - if (_ws && _ws.readyState === WebSocket.OPEN) _ws.send(JSON.stringify(payload)); -} -function getTakeover() { - if (!_takeover) _takeover = useTakeover(send); - return _takeover; -} -const DEV_TOKEN$1 = "7Oorb9S3OpwFyWgm4zi_Tq7GeamefbjjTgooPVPWAwPDOf6B4TvgvQlLbhmT4DjsqBS_D1g"; -function getWsUrl() { - let base; - { - base = "wss://assay.loop42.de/ws"; - } - const token = localStorage.getItem("nyx_session") || localStorage.getItem("titan_token") || DEV_TOKEN$1; - const session = sessionStorage.getItem("nyx_ws_session") || ""; - const qs = new URLSearchParams(); - qs.set("token", token); - if (session) qs.set("session", session); - return qs.toString() ? `${base}?${qs}` : base; -} -function scheduleReconnect() { - if (_reconnectTimer) return; - if (!_isLoggedInRef?.value) return; - status.value = `Reconnecting in ${Math.round(_reconnectDelay / 1e3)}s…`; - _reconnectTimer = setTimeout(() => { - _reconnectTimer = null; - if (_isLoggedInRef?.value) connect(_selectedAgentRef, _isLoggedInRef, _loginErrorRef); - }, _reconnectDelay); - _reconnectDelay = Math.min(_reconnectDelay * 2, 16e3); -} -function connect(selectedAgent, isLoggedInRef, loginErrorRef, selectedMode) { - if (_ws && _ws.readyState <= WebSocket.OPEN) return; - _selectedAgentRef = selectedAgent; - _selectedModeRef = selectedMode ?? null; - _isLoggedInRef = isLoggedInRef; - _loginErrorRef = loginErrorRef; - _reconnectDelay = 1e3; - console.log("WS CONNECT attempt, ws state:", _ws?.readyState, "url:", getWsUrl()); - const wsUrl = getWsUrl(); - if (isInitialLoad.value) { - status.value = "Connecting..."; - isInitialLoad.value = false; - } - _ws = new WebSocket(wsUrl); - H.ws = _ws; - _ws.onopen = () => { - _reconnectDelay = 1e3; - if (_pingInterval) clearInterval(_pingInterval); - _pingInterval = setInterval(() => { - if (_ws?.readyState === WebSocket.OPEN) _ws.send(JSON.stringify({ type: "ping" })); - }, 3e4); - H.wsPing = _pingInterval; - }; - _ws.onmessage = (event) => { - try { - const data = JSON.parse(event.data); - if (data.type === "dev_cmd" && data.cmdId && data.cmd) { - getTakeover().dispatch(data.cmdId, data.cmd, data.args || {}, send); - return; - } - if (data.type === "session_info") { - sessionId.value = data.session_id; - sessionStorage.setItem("nyx_ws_session", data.session_id); - } - if (data.type === "ready") { - connected.value = true; - status.value = "Connected"; - } - if (data.type === "error" && data.code === "SESSION_TERMINATED") { - console.warn("Message bounced: Session terminated."); - } - _messageBuffer.push(data); - _onMessageCallbacks.forEach((fn) => fn(data)); - } catch (e) { - console.error("Parse error:", e); - } - }; - _ws.onclose = (e) => { - if (_pingInterval) { - clearInterval(_pingInterval); - _pingInterval = null; - } - connected.value = false; - _messageBuffer.length = 0; - if (e.code === 4001) { - isLoggedInRef.value = false; - loginErrorRef.value = "Session expired. Please log in again."; - localStorage.removeItem("nyx_session"); - localStorage.removeItem("titan_token"); - sessionStorage.removeItem("agent"); - status.value = "Logged out"; - if (window.location.pathname !== "/login") { - window.location.pathname = "/login"; - } - } else { - scheduleReconnect(); - } - }; - _ws.onerror = () => { - }; -} -function disconnect() { - if (_pingInterval) { - clearInterval(_pingInterval); - _pingInterval = null; - H.wsPing = null; - } - if (_ws) { - _ws.onclose = null; - _ws.close(); - _ws = null; - H.ws = null; - } - connected.value = false; - status.value = "Disconnected"; - currentUser.value = ""; - sessionId.value = null; - isInitialLoad.value = true; -} -function sendDeferredAuth() { -} -function switchAgent(agentId, mode) { - _messageBuffer.length = 0; - send({ type: "switch_agent", agent: agentId, mode: mode ?? _selectedModeRef?.value ?? "private" }); -} -function clearBuffer() { - _messageBuffer.length = 0; -} -function onMessage(fn) { - _onMessageCallbacks.push(fn); - return () => { - const i = _onMessageCallbacks.indexOf(fn); - if (i !== -1) _onMessageCallbacks.splice(i, 1); - }; -} -function replayBuffer(fn) { - _messageBuffer.forEach((data) => fn(data)); -} -function useWebSocket() { - return { - connected, - status, - currentUser, - sessionId, - connect, - disconnect, - send, - switchAgent, - sendDeferredAuth, - clearBuffer, - onMessage, - replayBuffer, - getTakeover - }; -} -let _cached = null; -function getApiBase() { - if (_cached !== null) return _cached; - const wsUrl = "wss://assay.loop42.de/ws"; - try { - const url = new URL(wsUrl); - const proto = url.protocol === "wss:" ? "https:" : "http:"; - _cached = `${proto}//${url.host}`; - } catch { - _cached = ""; - } - return _cached; -} -const _allAgents = ref([]); -const _initAgent = (() => { - if (typeof window === "undefined") return ""; - const url = new URLSearchParams(window.location.hash.split("?")[1] || "").get("agent"); - if (url) return url; - const saved = sessionStorage.getItem("agent"); - if (saved) return saved; - return ""; -})(); -const _selectedAgent = ref(_initAgent); -const _initMode = (() => { - if (typeof window === "undefined") return "private"; - const url = new URLSearchParams(window.location.hash.split("?")[1] || "").get("mode"); - if (url === "public" || url === "private") return url; - const saved = sessionStorage.getItem("agent_mode"); - if (saved === "public" || saved === "private") return saved; - return "private"; -})(); -const _selectedMode = ref(_initMode); -const _defaultAgent = ref("titan"); -const _allowedAgentIds = ref([]); -function useAgents(connected2) { - const allAgents = _allAgents; - const selectedAgent = _selectedAgent; - const selectedMode = _selectedMode; - const defaultAgent = _defaultAgent; - const allowedAgentIds = _allowedAgentIds; - const agentModels = ref([]); - const filteredAgents = computed(() => { - if (allowedAgentIds.value.length === 0) return allAgents.value; - return allAgents.value.filter((a) => allowedAgentIds.value.includes(a.id)); - }); - function updateFromServer(data) { - if (data.agents) { - allAgents.value = data.agents; - } - if (data.defaultAgent) { - _defaultAgent.value = data.defaultAgent; - } - if (data.allowedAgents) { - _allowedAgentIds.value = data.allowedAgents; - } - if (allAgents.value.length === 0) { - allAgents.value = [{ id: "assay", name: "assay", promptPrice: null, completionPrice: null }]; - _allowedAgentIds.value = ["assay"]; - _defaultAgent.value = "assay"; - } - const urlParams = new URLSearchParams(window.location.hash.split("?")[1] || ""); - const urlMode = urlParams.get("mode"); - const savedMode = sessionStorage.getItem("agent_mode"); - if (urlMode === "public" || urlMode === "private") { - _selectedMode.value = urlMode; - } else if (savedMode === "public" || savedMode === "private") { - _selectedMode.value = savedMode; - } - const urlAgent = urlParams.get("agent"); - const savedAgent = sessionStorage.getItem("agent"); - const isUrlAgentAllowed = urlAgent && _allowedAgentIds.value.includes(urlAgent); - const isSavedAgentAllowed = savedAgent && _allowedAgentIds.value.includes(savedAgent); - if (isUrlAgentAllowed) { - selectedAgent.value = urlAgent; - } else if (isSavedAgentAllowed) { - selectedAgent.value = savedAgent; - } else if (!selectedAgent.value && _defaultAgent.value) { - selectedAgent.value = _defaultAgent.value; - } - } - async function fetchAgentModels() { - try { - const protocol = window.location.protocol === "https:" ? "https:" : "http:"; - const host = window.location.hostname; - const sessionToken = localStorage.getItem("nyx_session") ?? ""; - const res = await fetch(`${protocol}//${host}/agents`, { - headers: { Authorization: `Bearer ${sessionToken}` } - }); - agentModels.value = await res.json(); - } catch (e) { - console.error("Failed to fetch agent models:", e); - } - } - watch([connected2, _allowedAgentIds], () => { - if (connected2.value && !_selectedAgent.value) { - updateFromServer({}); - } - }); - const channelStates = ref({}); - let _pollTimer = null; - let _pollIdx = 0; - async function fetchOneAgent(agentId) { - const sessionToken = localStorage.getItem("nyx_session") ?? ""; - if (!sessionToken) return; - try { - const apiBase = getApiBase(); - const res = await fetch(`${apiBase}/api/channels/${agentId}`, { - headers: { Authorization: `Bearer ${sessionToken}` } - }); - if (!res.ok) return; - const data = await res.json(); - channelStates.value = { - ...channelStates.value, - [agentId]: { - private: data.private ?? null, - public: data.public ?? null - } - }; - } catch { - } - } - function pollNextAgent() { - const agents2 = allAgents.value; - if (!agents2.length) return; - _pollIdx = _pollIdx % agents2.length; - fetchOneAgent(agents2[_pollIdx].id); - _pollIdx++; - } - function startChannelPolling() { - if (_pollTimer) return; - _pollIdx = 0; - pollNextAgent(); - _pollTimer = setInterval(pollNextAgent, 1e3); - } - function stopChannelPolling() { - if (_pollTimer) { - clearInterval(_pollTimer); - _pollTimer = null; - } - } - function getChannelState(agentId, mode) { - const entry = channelStates.value[agentId]; - if (!entry) return null; - return mode === "private" ? entry.private : entry.public; - } - let currentUserRef = null; - function setCurrentUser(userRef) { - currentUserRef = userRef; - } - function syncStorage() { - if (_selectedAgent.value) sessionStorage.setItem("agent", _selectedAgent.value); - sessionStorage.setItem("agent_mode", _selectedMode.value); - } - watch([_selectedAgent, _selectedMode], syncStorage); - return { - allAgents, - selectedAgent, - selectedMode, - defaultAgent, - allowedAgentIds, - agentModels, - filteredAgents, - channelStates, - fetchAgentModels, - updateFromServer, - getChannelState, - setCurrentUser, - startChannelPolling, - stopChannelPolling - }; -} -const SESSION_TOKEN_KEY = "nyx_session"; -const DEV_TOKEN = "7Oorb9S3OpwFyWgm4zi_Tq7GeamefbjjTgooPVPWAwPDOf6B4TvgvQlLbhmT4DjsqBS_D1g"; -function useAuth(connectFn) { - const router = useRouter(); - if (typeof localStorage !== "undefined") { - if (!localStorage.getItem(SESSION_TOKEN_KEY) && !localStorage.getItem("titan_token")) { - localStorage.setItem(SESSION_TOKEN_KEY, DEV_TOKEN); - } - } - const isLoggedIn = ref(typeof localStorage !== "undefined" ? !!localStorage.getItem(SESSION_TOKEN_KEY) : false); - const loginToken = ref(""); - const loginError = ref(""); - const loggingIn = ref(false); - async function doLogin() { - const token = loginToken.value.trim(); - if (!token) return; - loggingIn.value = true; - loginError.value = ""; - try { - const nonceRes = await fetch(`${getApiBase()}/api/auth/nonce`); - if (!nonceRes.ok) { - loginError.value = "Auth unavailable"; - loggingIn.value = false; - return; - } - const { nonce } = await nonceRes.json(); - const res = await fetch(`${getApiBase()}/api/auth`, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ token, nonce }) - }); - if (!res.ok) { - const err = await res.json().catch(() => ({ error: "Login failed" })); - loginError.value = err.error || "Invalid token"; - loggingIn.value = false; - return; - } - const { sessionToken } = await res.json(); - localStorage.removeItem("titan_token"); - localStorage.removeItem("nyx_token"); - localStorage.setItem(SESSION_TOKEN_KEY, sessionToken); - sessionStorage.removeItem("agent"); - isLoggedIn.value = true; - connectFn(); - router.push("/chat"); - setTimeout(() => { - loggingIn.value = false; - }, 500); - } catch { - loginError.value = "Network error"; - loggingIn.value = false; - } - } - async function doLogout(disconnectFn) { - const sessionToken = localStorage.getItem(SESSION_TOKEN_KEY); - if (sessionToken) { - fetch(`${getApiBase()}/api/auth/logout`, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ sessionToken }) - }).catch(() => { - }); - } - if (disconnectFn) disconnectFn(); - localStorage.removeItem(SESSION_TOKEN_KEY); - localStorage.removeItem("titan_token"); - localStorage.removeItem("nyx_token"); - sessionStorage.removeItem("agent"); - sessionStorage.removeItem("viewer_auth"); - isLoggedIn.value = false; - loginToken.value = ""; - loggingIn.value = false; - router.push("/"); - } - return { isLoggedIn, loginToken, loginError, loggingIn, doLogin, doLogout }; -} -const STORAGE_KEY$2 = "viewer_auth"; -const REFRESH_BEFORE_EXPIRY_MS = 5 * 60 * 1e3; -function loadStored() { - try { - const raw = sessionStorage.getItem(STORAGE_KEY$2); - if (!raw) return null; - return JSON.parse(raw); - } catch { - return null; - } -} -function saveStored(auth2) { - try { - sessionStorage.setItem(STORAGE_KEY$2, JSON.stringify(auth2)); - } catch { - } -} -function clearStored() { - sessionStorage.removeItem(STORAGE_KEY$2); -} -const useViewerStore = defineStore("viewer", () => { - const stored2 = loadStored(); - const fstoken = ref(stored2?.fstoken ?? ""); - const roots = ref(stored2?.roots ?? []); - const expiresAt = ref(stored2?.expiresAt ?? 0); - const ready = computed(() => !!fstoken.value && Date.now() < expiresAt.value); - let acquiring = null; - async function acquire(force = false) { - if (!force && fstoken.value && Date.now() < expiresAt.value - REFRESH_BEFORE_EXPIRY_MS) return; - if (acquiring) return acquiring; - acquiring = _acquire().finally(() => { - acquiring = null; - }); - return acquiring; - } - async function _acquire() { - const sessionToken = localStorage.getItem("nyx_session") || localStorage.getItem("titan_token") || ""; - if (!sessionToken) return; - try { - const res = await fetch(`${getApiBase()}/api/viewer/token`, { - method: "POST", - headers: { Authorization: `Bearer ${sessionToken}` } - }); - if (!res.ok) { - fstoken.value = ""; - roots.value = []; - expiresAt.value = 0; - clearStored(); - return; - } - const data = await res.json(); - const newToken = data.fstoken; - let newRoots = roots.value.length ? roots.value : ["shared", "workspace-titan"]; - try { - const tr = await fetch(`${getApiBase()}/api/viewer/tree?root=&token=${encodeURIComponent(newToken)}`); - if (tr.ok) { - const td = await tr.json(); - if (Array.isArray(td.dirs) && td.dirs.length) newRoots = td.dirs; - } - } catch { - } - const newExpiresAt = Date.now() + 60 * 60 * 1e3; - fstoken.value = newToken; - roots.value = newRoots; - expiresAt.value = newExpiresAt; - saveStored({ fstoken: newToken, roots: newRoots, expiresAt: newExpiresAt }); - } catch { - } - } - function invalidate() { - fstoken.value = ""; - roots.value = []; - expiresAt.value = 0; - clearStored(); - } - return { fstoken, roots, ready, acquire, invalidate }; -}); -const lastViewerPath = ref(typeof localStorage !== "undefined" ? localStorage.getItem("viewer_last_path") || "" : ""); -const viewerOpenDirs = reactive(/* @__PURE__ */ new Set()); -const ws = useWebSocket(); -const takeover = ws.getTakeover(); -const agents = useAgents(ws.connected); -agents.setCurrentUser(ws.currentUser); -const auth = useAuth(() => { - ws.connect(agents.selectedAgent, auth.isLoggedIn, auth.loginError, agents.selectedMode); - useViewerStore().acquire(); -}); -const STORAGE_KEY$1 = "hermes_theme"; -const THEME_ICONS = { - titan: CommandLineIcon, - eras: SunIcon, - loop42: CubeTransparentIcon -}; -const THEME_NAMES = { - titan: "Titan", - eras: "ERAS", - loop42: "loop42" -}; -const THEME_LOGOS = { - titan: null, - eras: null, - loop42: null -}; -const AGENT_THEME_MAP = { - eras: "eras" -}; -function agentLogo(agentId) { - const t = AGENT_THEME_MAP[agentId] ?? "titan"; - return THEME_LOGOS[t]; -} -const stored = localStorage.getItem(STORAGE_KEY$1); -const theme = ref( - stored === "workhorse" ? "loop42" : ( - // migrate legacy name - stored || "loop42" - ) -); -const THEME_FAVICONS = { - titan: "/favicon-titan.svg", - eras: "/favicon-eras.svg", - loop42: "/favicon-loop42.svg" -}; -function applyTheme(t) { - if (t === "titan") { - document.documentElement.removeAttribute("data-theme"); - } else { - document.documentElement.setAttribute("data-theme", t); - } - const link = document.querySelector('link[rel="icon"]'); - if (link) link.href = THEME_FAVICONS[t] || "/favicon.svg"; -} -applyTheme(theme.value); -watch(theme, (t) => { - applyTheme(t); - localStorage.setItem(STORAGE_KEY$1, t); -}); -function useTheme() { - function setTheme(t) { - theme.value = t; - } - return { theme, setTheme }; -} -const useChatStore = defineStore("chat", () => { - const messages = ref([]); - const channelState = ref("NO_SESSION"); - const connectionState = ref("CONNECTING"); - const smState = computed(() => { - if (connectionState.value !== "SYNCED") return connectionState.value; - return _stopPending.value ? "STOP_PENDING" : channelState.value; - }); - const _stopPending = ref(false); - const truncatedWarning = ref(false); - const localSessionId = ref(Math.random().toString(36).slice(2, 10)); - const sessionTotalTokens = ref(null); - const sessionUsage = ref(null); - const beVersion = ref(""); - const finance = ref(null); - const sessionKey = ref(""); - const sessionCost = computed(() => { - const p = finance.value?.pricing; - const u = sessionTotalTokens.value; - if (!p || !u) return 0; - return ((u.input_tokens || 0) * p.prompt + (u.output_tokens || 0) * p.completion) / 1e6; - }); - const queuedThought = ref(null); - const activeTurnCorrId = ref(null); - const handoverPending = computed( - () => messages.value.some((m) => m.confirmNew && !m.confirmed) - ); - const isRunning = computed( - () => channelState.value === "AGENT_RUNNING" || _stopPending.value || channelState.value === "HANDOVER_PENDING" - ); - let _wsSend = null; - function setWsSend(fn) { - _wsSend = fn; - } - function newSession() { - stashMessages(); - resetLocalSession(); - _wsSend?.({ type: "new" }); - } - function handover() { - _wsSend?.({ type: "handover_request" }); - } - function stop() { - if (channelState.value !== "AGENT_RUNNING" && !_stopPending.value) return; - queuedThought.value = null; - _stopPending.value = true; - pushSystem("Stopping after current turn..."); - _wsSend?.({ type: "stop" }); - } - function confirmNew() { - const bubble = [...messages.value].reverse().find((m) => m.confirmNew && !m.confirmed); - if (bubble) bubble.confirmed = true; - stashMessages(); - resetLocalSession(); - _wsSend?.({ type: "new" }); - } - function stay() { - const bubble = [...messages.value].reverse().find((m) => m.confirmNew && !m.confirmed); - if (bubble) { - bubble.confirmed = true; - setTimeout(() => { - const idx = messages.value.findIndex((m) => m === bubble); - if (idx !== -1) messages.value.splice(idx, 1); - }, 1e3); - } - _wsSend?.({ type: "cancel_handover" }); - } - function applyChannelState(state) { - channelState.value = state; - if (state === "AGENT_RUNNING") sessionContextHint.value = ""; - if (state === "READY" || state === "FRESH") _stopPending.value = false; - } - function applyConnectionState(state) { - connectionState.value = state; - } - function applySessionState(state) { - if (["FRESH", "READY", "AGENT_RUNNING", "HANDOVER_PENDING", "HANDOVER_DONE", "NO_SESSION"].includes(state)) { - applyChannelState(state); - } else if (["CONNECTING", "LOADING_HISTORY", "SYNCED", "SWITCHING"].includes(state)) { - applyConnectionState(state); - } - } - function setConnecting() { - connectionState.value = "CONNECTING"; - } - let currentAssistantMessageIndex = -1; - const streamingMessageVisibleContent = ref(""); - let streamingMessageFullContent = ""; - let streamingInterval = null; - let charIndex = 0; - let pendingVisibleClear = false; - let thinkingMessageIndex = -1; - const thinkingContent = ref(""); - const sessionContextHint = ref(""); - const TYPING_TICK_MS = 10; - const smLabel = computed(() => { - if (connectionState.value !== "SYNCED") { - switch (connectionState.value) { - case "CONNECTING": - return "⏳ Connecting..."; - case "LOADING_HISTORY": - return "⏳ Loading..."; - case "SWITCHING": - return "πŸ”€ Switching..."; - } - } - if (_stopPending.value) return "β›” Stopping..."; - switch (channelState.value) { - case "AGENT_RUNNING": - return "βš™οΈ Working..."; - case "HANDOVER_PENDING": - return "πŸ“ Handover..."; - case "HANDOVER_DONE": - return "βœ… Handover ready"; - case "READY": - return sessionContextHint.value ? `βœ“ Ready - ${sessionContextHint.value}` : "● βœ“ Ready"; - case "FRESH": - return "✨ New session"; - case "RESETTING": - return "πŸ”„ Resetting..."; - case "NO_SESSION": - return "β—‹ No session"; - default: - return "● βœ“ Ready"; - } - }); - const visibleMsgs = (visibleCount) => { - return messages.value.slice(-visibleCount); - }; - function resetLocalSession() { - localSessionId.value = Math.random().toString(36).slice(2, 10); - console.log("[ChatStore] Local Session Reset:", localSessionId.value); - resetStreamingState(); - } - function stashMessages() { - const saveable = messages.value.filter((m) => m.role === "user" || m.role === "assistant").map((m) => ({ role: m.role, content: m.content, agentId: m.agentId })); - if (saveable.length > 0) { - try { - sessionStorage.setItem("hermes_prev_session", JSON.stringify(saveable)); - } catch (_) { - } - } - } - function getPreviousSession() { - try { - const raw = sessionStorage.getItem("hermes_prev_session"); - return raw ? JSON.parse(raw) : []; - } catch { - return []; - } - } - function clearMessages() { - stashMessages(); - messages.value = []; - sessionTotalTokens.value = null; - finance.value = null; - resetStreamingState(); - } - function pushMessage(msg) { - hasActiveStreamingMessage() ? currentAssistantMessageIndex : messages.value.length; - const msgWithId = { - ...msg, - sessionId: localSessionId.value - }; - if (hasActiveStreamingMessage() && msg.role === "user") { - messages.value.splice(currentAssistantMessageIndex, 0, msgWithId); - currentAssistantMessageIndex++; - } else { - messages.value.push(msgWithId); - } - } - function patchMessage(msgId, patch) { - const msg = messages.value.find((m) => m.msgId === msgId); - if (!msg) return false; - Object.assign(msg, patch); - return true; - } - function pushSystem(text, agentId) { - const msg = { - role: "system", - content: text, - agentId: agentId || null, - sessionId: localSessionId.value - }; - if (hasActiveStreamingMessage()) { - messages.value.splice(currentAssistantMessageIndex, 0, msg); - currentAssistantMessageIndex++; - } else { - messages.value.push(msg); - } - } - function resetStreamingState() { - if (streamingInterval !== null) clearInterval(streamingInterval); - streamingInterval = null; - currentAssistantMessageIndex = -1; - streamingMessageFullContent = ""; - charIndex = 0; - pendingVisibleClear = true; - nextTick(() => { - if (pendingVisibleClear) { - streamingMessageVisibleContent.value = ""; - pendingVisibleClear = false; - } - }); - } - function startNewAssistantMessage(agentId) { - if (currentAssistantMessageIndex === -1 || !messages.value[currentAssistantMessageIndex]?.streaming) { - pendingVisibleClear = false; - resetStreamingState(); - messages.value.push({ - role: "assistant", - content: "", - fullContent: "", - usage: null, - streaming: true, - agentId: agentId ?? null, - sessionId: localSessionId.value, - turnCorrId: activeTurnCorrId.value ?? null - }); - currentAssistantMessageIndex = messages.value.length - 1; - } - } - function appendAssistantDelta(delta, agentId) { - if (currentAssistantMessageIndex !== -1 && messages.value[currentAssistantMessageIndex]?.streaming) { - streamingMessageFullContent += delta; - messages.value[currentAssistantMessageIndex].fullContent = streamingMessageFullContent; - if (!streamingInterval) startTypewriter(); - } else { - startNewAssistantMessage(agentId); - appendAssistantDelta(delta, agentId); - } - } - function startTypewriter() { - if (streamingInterval !== null) clearInterval(streamingInterval); - streamingInterval = setInterval(() => { - const backlog = streamingMessageFullContent.length - charIndex; - if (backlog <= 0) { - console.log( - "[hermes] typewriter done: charIndex=%d fullLen=%d visibleLen=%d streaming=%s", - charIndex, - streamingMessageFullContent.length, - streamingMessageVisibleContent.value.length, - messages.value[currentAssistantMessageIndex]?.streaming - ); - if (streamingInterval !== null) clearInterval(streamingInterval); - streamingInterval = null; - return; - } - const charsThisTick = backlog >= 200 ? 10 : backlog >= 50 ? 4 : 1; - const end = Math.min(charIndex + charsThisTick, streamingMessageFullContent.length); - streamingMessageVisibleContent.value += streamingMessageFullContent.slice(charIndex, end); - charIndex = end; - }, TYPING_TICK_MS); - } - function finalizeAssistantMessage(content, usage, truncated = false) { - if (currentAssistantMessageIndex !== -1 && messages.value[currentAssistantMessageIndex]?.streaming) { - const msg = messages.value[currentAssistantMessageIndex]; - const finalContent = (content !== null && content !== void 0 ? content : streamingMessageFullContent).replace(/\s*NO_REPLY\s*$/g, "").trim(); - console.log( - "[hermes] finalizeAssistantMessage: charIndex=%d fullLen=%d visibleLen=%d finalLen=%d", - charIndex, - streamingMessageFullContent.length, - streamingMessageVisibleContent.value.length, - finalContent.length - ); - if (streamingInterval !== null) { - clearInterval(streamingInterval); - streamingInterval = null; - } - streamingMessageVisibleContent.value = finalContent; - charIndex = finalContent.length; - msg.content = finalContent; - msg.fullContent = finalContent; - if (usage) msg.usage = usage; - if (truncated) msg.truncated = true; - msg.streaming = false; - console.log( - "[hermes] post-finalize: msg.content.length=%d msg.streaming=%s idx=%d", - msg.content.length, - msg.streaming, - currentAssistantMessageIndex - ); - resetStreamingState(); - } - } - function appendThinking(content) { - if (!content) return; - thinkingContent.value += content; - if (thinkingMessageIndex === -1) { - messages.value.push({ role: "thinking", content: thinkingContent, collapsed: false }); - thinkingMessageIndex = messages.value.length - 1; - } - } - function collapseThinking() { - if (thinkingMessageIndex !== -1 && messages.value[thinkingMessageIndex]) { - messages.value[thinkingMessageIndex].collapsed = true; - } - thinkingMessageIndex = -1; - thinkingContent.value = ""; - } - function createCompleteAssistantMessage(content, agentId, usage) { - if (hasActiveStreamingMessage()) { - finalizeAssistantMessage(content, usage); - return; - } - const msg = { - role: "assistant", - content: content.replace(/\s*NO_REPLY\s*$/g, "").trim(), - fullContent: content.replace(/\s*NO_REPLY\s*$/g, "").trim(), - usage: usage || null, - streaming: false, - agentId: agentId ?? null, - sessionId: localSessionId.value, - turnCorrId: activeTurnCorrId.value ?? null - }; - messages.value.push(msg); - } - function hasActiveStreamingMessage() { - return currentAssistantMessageIndex !== -1 && messages.value[currentAssistantMessageIndex]?.streaming; - } - function streamingMessageLength() { - return streamingMessageFullContent.length; - } - function suppressAssistantMessage() { - if (currentAssistantMessageIndex !== -1 && messages.value[currentAssistantMessageIndex]?.streaming) { - if (streamingInterval !== null) { - clearInterval(streamingInterval); - streamingInterval = null; - } - messages.value.splice(currentAssistantMessageIndex, 1); - } - resetStreamingState(); - } - return { - messages, - activeTurnCorrId, - sessionKey, - smState, - // legacy computed: connection priority, then channel - channelState, - connectionState, - applySessionState, - // legacy compat - applyChannelState, - applyConnectionState, - setConnecting, - truncatedWarning, - localSessionId, - sessionTotalTokens, - sessionUsage, - beVersion, - sessionCost, - finance, - smLabel, - sessionContextHint, - streamingMessageVisibleContent, - visibleMsgs, - resetLocalSession, - clearMessages, - stashMessages, - getPreviousSession, - pushMessage, - patchMessage, - pushSystem, - startNewAssistantMessage, - appendAssistantDelta, - finalizeAssistantMessage, - createCompleteAssistantMessage, - appendThinking, - collapseThinking, - hasActiveStreamingMessage, - streamingMessageLength, - suppressAssistantMessage, - queuedThought, - handoverPending, - isRunning, - setWsSend, - newSession, - handover, - stop, - confirmNew, - stay - }; -}); -const STORAGE_KEY = "hermes_dev_flags"; -const defaults = { - showGrid: false, - showDebugInfo: false, - showHud: false -}; -function load() { - try { - const raw = sessionStorage.getItem(STORAGE_KEY); - if (!raw) return { ...defaults }; - return { ...defaults, ...JSON.parse(raw) }; - } catch { - return { ...defaults }; - } -} -const flags = reactive(load()); -watch(flags, (v) => { - sessionStorage.setItem(STORAGE_KEY, JSON.stringify(v)); -}, { deep: true }); -function useDevFlags() { - return flags; -} -const columns = 12; -const _sfc_main$8 = /* @__PURE__ */ defineComponent({ - __name: "GridOverlay", - __ssrInlineRender: true, - setup(__props) { - const devFlags = useDevFlags(); - return (_ctx, _push, _parent, _attrs) => { - if (unref(devFlags).showGrid) { - _push(``); - ssrRenderList(columns, (n) => { - _push(`
`); - }); - _push(``); - } else { - _push(``); - } - }; - } -}); -const _export_sfc = (sfc, props) => { - const target = sfc.__vccOpts || sfc; - for (const [key, val] of props) { - target[key] = val; - } - return target; -}; -const _sfc_setup$8 = _sfc_main$8.setup; -_sfc_main$8.setup = (props, ctx) => { - const ssrContext = useSSRContext(); - (ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("src/components/GridOverlay.vue"); - return _sfc_setup$8 ? _sfc_setup$8(props, ctx) : void 0; -}; -const GridOverlay = /* @__PURE__ */ _export_sfc(_sfc_main$8, [["__scopeId", "data-v-967a780b"]]); -const _sfc_main$7 = /* @__PURE__ */ defineComponent({ - __name: "BreakpointBadge", - __ssrInlineRender: true, - setup(__props) { - const devFlags = useDevFlags(); - return (_ctx, _push, _parent, _attrs) => { - if (unref(devFlags).showDebugInfo) { - _push(`xs`); - } else { - _push(``); - } - }; - } -}); -const _sfc_setup$7 = _sfc_main$7.setup; -_sfc_main$7.setup = (props, ctx) => { - const ssrContext = useSSRContext(); - (ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("src/components/BreakpointBadge.vue"); - return _sfc_setup$7 ? _sfc_setup$7(props, ctx) : void 0; -}; -const BreakpointBadge = /* @__PURE__ */ _export_sfc(_sfc_main$7, [["__scopeId", "data-v-321be928"]]); -OverlayScrollbars.plugin(ClickScrollPlugin); -const scrollbarOptions = { - overflow: { - x: "hidden" - }, - scrollbars: { - clickScroll: true, - autoHide: "never" - } -}; -const _sfc_main$6 = /* @__PURE__ */ defineComponent({ - __name: "TreeNode", - __ssrInlineRender: true, - props: { - label: {}, - path: {}, - token: {}, - activePath: {}, - expandTo: {}, - depth: {}, - hideSelf: { type: Boolean }, - foldersOnly: { type: Boolean } - }, - emits: ["select"], - setup(__props, { emit: __emit }) { - const props = __props; - const childDepth = computed(() => props.hideSelf ? props.depth : props.depth + 1); - const fetched = ref(false); - const hasSubdirs = computed(() => dirs.value.length > 0); - const isLeaf = computed(() => props.foldersOnly ? !hasSubdirs.value : false); - const viewerStore = useViewerStore(); - const open = computed(() => viewerOpenDirs.has(props.path)); - const loading = ref(false); - const showLoading = ref(false); - let loadingTimer = null; - const error = ref(""); - const dirs = ref([]); - const files = ref([]); - function getBaseUrl() { - return getApiBase(); - } - async function fetchTree(_retry = false) { - if (loading.value) return; - loading.value = true; - showLoading.value = false; - if (loadingTimer) clearTimeout(loadingTimer); - loadingTimer = setTimeout(() => { - showLoading.value = true; - }, 3e3); - error.value = ""; - try { - const base = getBaseUrl(); - const url = `${base}/api/viewer/tree?root=${encodeURIComponent(props.path)}&token=${encodeURIComponent(props.token)}`; - const res = await fetch(url); - if (res.status === 401 && !_retry) { - loading.value = false; - viewerStore.invalidate(); - await viewerStore.acquire(true); - return fetchTree(true); - } - if (!res.ok) throw new Error(`${res.status} ${res.statusText}`); - const data = await res.json(); - dirs.value = data.dirs || []; - files.value = data.files || []; - } catch (e) { - error.value = e.message || "Failed to load"; - } finally { - loading.value = false; - showLoading.value = false; - fetched.value = true; - if (loadingTimer) { - clearTimeout(loadingTimer); - loadingTimer = null; - } - } - } - function setOpen(val) { - viewerOpenDirs.add(props.path); - } - function maybeExpand(expandTo) { - if (expandTo && expandTo.startsWith(props.path + "/") && !open.value) { - setOpen(); - if (!dirs.value.length && !files.value.length) fetchTree(); - } - } - const { onMessage: onMessage2 } = ws; - let unsubDirWatch = null; - onMounted(() => { - if (props.hideSelf && !open.value) setOpen(); - if ((open.value || props.hideSelf) && !dirs.value.length && !files.value.length) fetchTree(); - else if (props.foldersOnly && !fetched.value && !loading.value) fetchTree(); - maybeExpand(props.expandTo); - unsubDirWatch = onMessage2((data) => { - if (data.type === "viewer_tree_changed" && data.path === props.path && open.value) { - fetchTree(); - } - }); - }); - onUnmounted(() => { - if (unsubDirWatch) unsubDirWatch(); - }); - watch(() => props.expandTo, maybeExpand); - return (_ctx, _push, _parent, _attrs) => { - const _component_TreeNode = resolveComponent("TreeNode", true); - _push(``); - if (!__props.hideSelf) { - _push(`
`); - if (!isLeaf.value) { - _push(``); - if (open.value) { - _push(ssrRenderComponent(unref(ChevronDownIcon), { class: "icon w-3 h-3" }, null, _parent)); - } else { - _push(ssrRenderComponent(unref(ChevronRightIcon), { class: "icon w-3 h-3" }, null, _parent)); - } - _push(``); - } else { - _push(``); - } - _push(`${ssrInterpolate(__props.label)}
`); - } else { - _push(``); - } - if (open.value || __props.hideSelf) { - _push(`
`); - if (showLoading.value) { - _push(`
…
`); - } else if (error.value) { - _push(`
${ssrInterpolate(error.value)}
`); - } else { - _push(``); - ssrRenderList(dirs.value, (dir) => { - _push(ssrRenderComponent(_component_TreeNode, { - key: __props.path + "/" + dir, - label: dir, - path: __props.path + "/" + dir, - token: __props.token, - "active-path": __props.activePath, - "expand-to": __props.expandTo, - depth: childDepth.value, - "folders-only": __props.foldersOnly, - onSelect: ($event) => _ctx.$emit("select", $event) - }, null, _parent)); - }); - _push(``); - if (!__props.foldersOnly) { - _push(``); - ssrRenderList(files.value, (file) => { - _push(`
`); - _push(ssrRenderComponent(unref(DocumentIcon), { class: "icon file-icon w-3 h-3" }, null, _parent)); - _push(`${ssrInterpolate(file.name)}
`); - }); - _push(``); - } else { - _push(``); - } - if (!loading.value && !dirs.value.length && !__props.foldersOnly && !files.value.length) { - _push(`
empty
`); - } else { - _push(``); - } - _push(``); - } - _push(`
`); - } else { - _push(``); - } - _push(``); - }; - } -}); -const _sfc_setup$6 = _sfc_main$6.setup; -_sfc_main$6.setup = (props, ctx) => { - const ssrContext = useSSRContext(); - (ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("src/components/TreeNode.vue"); - return _sfc_setup$6 ? _sfc_setup$6(props, ctx) : void 0; -}; -const TreeNode = /* @__PURE__ */ _export_sfc(_sfc_main$6, [["__scopeId", "data-v-ae9a8cbc"]]); -const _sfc_main$5 = /* @__PURE__ */ defineComponent({ - __name: "FileTree", - __ssrInlineRender: true, - props: { - token: {}, - activePath: {}, - expandTo: {}, - roots: {}, - hideRoot: { type: Boolean }, - foldersOnly: { type: Boolean } - }, - emits: ["select"], - setup(__props) { - const props = __props; - const roots = computed( - () => (props.roots && props.roots.length > 0 ? props.roots : ["shared", "workspace-titan"]).map((r) => ({ label: r, prefix: r })) - ); - return (_ctx, _push, _parent, _attrs) => { - _push(``); - ssrRenderList(roots.value, (root) => { - _push(ssrRenderComponent(TreeNode, { - key: root.prefix, - label: root.label, - path: root.prefix, - token: __props.token, - "active-path": __props.activePath, - "expand-to": __props.expandTo, - depth: 0, - "hide-self": __props.hideRoot, - "folders-only": __props.foldersOnly, - onSelect: ($event) => _ctx.$emit("select", $event) - }, null, _parent)); - }); - _push(``); - }; - } -}); -const _sfc_setup$5 = _sfc_main$5.setup; -_sfc_main$5.setup = (props, ctx) => { - const ssrContext = useSSRContext(); - (ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("src/components/FileTree.vue"); - return _sfc_setup$5 ? _sfc_setup$5(props, ctx) : void 0; -}; -const FileTree = /* @__PURE__ */ _export_sfc(_sfc_main$5, [["__scopeId", "data-v-e4eaa1f9"]]); -const _sfc_main$4 = /* @__PURE__ */ defineComponent({ - ...{ name: "AppSidebar" }, - __name: "AppSidebar", - __ssrInlineRender: true, - emits: ["logout"], - setup(__props, { emit: __emit }) { - const takeoverToken = takeover.token; - const captureActive = takeover.capture.isActive; - const takeoverPanelOpen = ref(false); - const tokenCopied = ref(false); - const systemOpen = ref(sessionStorage.getItem("sidebar_panel_system") === "true"); - const connPanelOpen = ref(false); - const anyPanelOpen = computed(() => takeoverPanelOpen.value || userMenuOpen.value || versionPanelOpen.value || connPanelOpen.value); - const homeAgent = computed(() => allAgents.value.find((a) => a.id === defaultAgent.value)); - computed( - () => filteredAgents.value.filter((a) => a.id !== defaultAgent.value).sort((a, b) => a.name.localeCompare(b.name)) - ); - const chatStore = useChatStore(); - const viewerStore = useViewerStore(); - const viewerToken = computed(() => viewerStore.fstoken); - const viewerRoots = computed(() => viewerStore.roots); - const sharedOpen = ref(lastViewerPath.value.startsWith("shared")); - const workspaceOpen = ref(lastViewerPath.value.startsWith("workspace")); - const viewerWorkspaceRoot = computed(() => { - const ws2 = viewerRoots.value.find((r) => r.startsWith("workspace")); - return ws2 || "workspace-titan"; - }); - function openInViewer(path) { - lastViewerPath.value = path; - localStorage.setItem("viewer_last_path", path); - router.push({ name: "viewer", query: { path } }); - } - const { version: version2 } = useUI(ws.status); - const versionShort = version2.split("-")[0]; - const envLabel = "prod"; - const versionPanelOpen = ref(false); - const versionCopied = ref(false); - function stateToIndicator(state) { - switch (state) { - case "AGENT_RUNNING": - return { icon: "βš™οΈ", cls: "ch-running" }; - case "FRESH": - return { icon: "✨", cls: "ch-fresh" }; - case "READY": - return { icon: "●", cls: "ch-ready" }; - case "HANDOVER_PENDING": - return { icon: "πŸ“", cls: "ch-handover" }; - case "HANDOVER_DONE": - return { icon: "βœ…", cls: "ch-handover" }; - case "RESETTING": - return { icon: "πŸ”„", cls: "ch-resetting" }; - case "NO_SESSION": - return { icon: "β—‹", cls: "ch-nosession" }; - default: - return { icon: "Β·", cls: "ch-none" }; - } - } - computed(() => stateToIndicator(chatStore.channelState)); - const connLabel = computed(() => { - switch (chatStore.connectionState) { - case "CONNECTING": - return "Connecting..."; - case "LOADING_HISTORY": - return "Loading..."; - case "SWITCHING": - return "Switching..."; - case "SYNCED": - return "Connected"; - default: - return ""; - } - }); - const connActive = computed(() => chatStore.connectionState === "SYNCED"); - const route = useRoute(); - const router = useRouter(); - const { theme: theme2 } = useTheme(); - const navLogo = computed(() => THEME_LOGOS[theme2.value]); - const { isLoggedIn } = auth; - const { currentUser: currentUser2 } = ws; - const { filteredAgents, selectedAgent, selectedMode, defaultAgent, allAgents } = agents; - const SEGMENTS = ["personal", "common", "private", "public"]; - computed( - () => SEGMENTS.map((key) => ({ - key, - agents: filteredAgents.value.filter((a) => (a.segment ?? "utility") === key && a.id !== defaultAgent.value).sort((a, b) => a.name.localeCompare(b.name)) - })).filter((s) => s.agents.length > 0) - ); - const isMobile = window.innerWidth <= 480; - const isLarge = window.innerWidth >= 1024; - const isOpen = ref(isMobile ? false : isLarge ? true : localStorage.getItem("sidebar_open") !== "false"); - const userMenuOpen = ref(false); - const lgQuery = window.matchMedia("(min-width: 1024px)"); - lgQuery.addEventListener("change", (e) => { - if (e.matches && !isOpen.value) { - isOpen.value = true; - localStorage.setItem("sidebar_open", "true"); - } else if (!e.matches && isOpen.value) { - isOpen.value = false; - localStorage.setItem("sidebar_open", "false"); - } - }); - function collapse() { - if (window.innerWidth >= 1024) return; - isOpen.value = false; - localStorage.setItem("sidebar_open", "false"); - } - return (_ctx, _push, _parent, _attrs) => { - const _component_RouterLink = resolveComponent("RouterLink"); - _push(``); - if (unref(isLoggedIn) && isOpen.value) { - _push(`
`); - if (viewerToken.value) { - _push(`
`); - if (sharedOpen.value) { - _push(ssrRenderComponent(unref(OverlayScrollbarsComponent), { - class: "sidebar-file-scroll", - options: unref(scrollbarOptions), - element: "div" - }, { - default: withCtx((_, _push2, _parent2, _scopeId) => { - if (_push2) { - _push2(ssrRenderComponent(FileTree, { - token: viewerToken.value, - "active-path": unref(lastViewerPath), - "expand-to": unref(lastViewerPath), - roots: ["shared"], - "hide-root": true, - "folders-only": true, - onSelect: openInViewer - }, null, _parent2, _scopeId)); - } else { - return [ - createVNode(FileTree, { - token: viewerToken.value, - "active-path": unref(lastViewerPath), - "expand-to": unref(lastViewerPath), - roots: ["shared"], - "hide-root": true, - "folders-only": true, - onSelect: openInViewer - }, null, 8, ["token", "active-path", "expand-to"]) - ]; - } - }), - _: 1 - }, _parent)); - } else { - _push(``); - } - _push(`
`); - } else { - _push(``); - } - if (viewerToken.value) { - _push(`
`); - if (workspaceOpen.value) { - _push(ssrRenderComponent(unref(OverlayScrollbarsComponent), { - class: "sidebar-file-scroll", - options: unref(scrollbarOptions), - element: "div" - }, { - default: withCtx((_, _push2, _parent2, _scopeId) => { - if (_push2) { - _push2(ssrRenderComponent(FileTree, { - token: viewerToken.value, - "active-path": unref(lastViewerPath), - "expand-to": unref(lastViewerPath), - roots: [viewerWorkspaceRoot.value], - "hide-root": true, - "folders-only": true, - onSelect: openInViewer - }, null, _parent2, _scopeId)); - } else { - return [ - createVNode(FileTree, { - token: viewerToken.value, - "active-path": unref(lastViewerPath), - "expand-to": unref(lastViewerPath), - roots: [viewerWorkspaceRoot.value], - "hide-root": true, - "folders-only": true, - onSelect: openInViewer - }, null, 8, ["token", "active-path", "expand-to", "roots"]) - ]; - } - }), - _: 1 - }, _parent)); - } else { - _push(``); - } - _push(`
`); - } else { - _push(``); - } - _push(`
`); - } else { - _push(``); - } - if (unref(isLoggedIn) && !isOpen.value) { - _push(``); - } else { - _push(``); - } - if (unref(isLoggedIn)) { - _push(``); - } else { - _push(``); - } - if (anyPanelOpen.value) { - _push(``); - } else { - _push(``); - } - if (unref(isLoggedIn) && isOpen.value) { - _push(`
`); - if (systemOpen.value) { - _push(``); - } else { - _push(``); - } - _push(`
`); - } else { - _push(``); - } - if (unref(isLoggedIn) && !isOpen.value) { - _push(``); - } else { - _push(``); - } - _push(``); - }; - } -}); -const _sfc_setup$4 = _sfc_main$4.setup; -_sfc_main$4.setup = (props, ctx) => { - const ssrContext = useSSRContext(); - (ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("src/components/AppSidebar.vue"); - return _sfc_setup$4 ? _sfc_setup$4(props, ctx) : void 0; -}; -function stripMdForTts(text) { - return text.replace(/```[\s\S]*?```/g, "").replace(/`[^`]+`/g, "").replace(/!\[.*?\]\(.*?\)/g, "").replace(/\[([^\]]+)\]\(.*?\)/g, "$1").replace(/#{1,6}\s*/g, "").replace(/[*_~]+/g, "").replace(/\n{2,}/g, ". ").replace(/\n/g, " ").trim(); -} -function createTtsPlayer() { - const store = useChatStore(); - const state = ref("idle"); - const currentTrack = ref(null); - const currentTime = ref(0); - const duration = ref(0); - const progress = computed(() => duration.value > 0 ? currentTime.value / duration.value : 0); - let audio = null; - const urlCache = /* @__PURE__ */ new Map(); - function getAudio() { - if (!audio) { - audio = new Audio(); - audio.addEventListener("timeupdate", () => { - currentTime.value = audio.currentTime; - }); - audio.addEventListener("durationchange", () => { - duration.value = audio.duration || 0; - }); - audio.addEventListener("ended", () => { - state.value = "idle"; - currentTrack.value = null; - }); - audio.addEventListener("error", () => { - console.error("[tts] playback error"); - state.value = "idle"; - currentTrack.value = null; - }); - } - return audio; - } - const speakableMessages = computed(() => { - const result = []; - for (let i = 0; i < store.messages.length; i++) { - const m = store.messages[i]; - if (m.role === "assistant" && !m.streaming && m.content) { - result.push({ msg: m, index: i }); - } - } - return result; - }); - function contentKey(text) { - let h = 0; - for (let i = 0; i < text.length; i++) { - h = (h << 5) - h + text.charCodeAt(i) | 0; - } - return String(h); - } - async function play(msg, sourceIndex) { - const el = getAudio(); - el.pause(); - const rawText = stripMdForTts(msg.content || ""); - if (!rawText) return; - const text = rawText.slice(0, 4096); - const snippet = rawText.slice(0, 60) + (rawText.length > 60 ? "..." : ""); - currentTrack.value = { msgRef: msg, sourceIndex, snippet, audioUrl: null }; - currentTime.value = 0; - duration.value = 0; - state.value = "loading"; - const key = contentKey(text); - let url = urlCache.get(key); - if (!url) { - try { - const token = localStorage.getItem("nyx_session") || ""; - const apiBase = getApiBase(); - const res = await fetch(`${apiBase}/api/tts`, { - method: "POST", - headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}` }, - body: JSON.stringify({ text }) - }); - if (!res.ok) throw new Error(`TTS ${res.status}`); - const data = await res.json(); - url = `${apiBase}${data.url}?token=${encodeURIComponent(token)}`; - urlCache.set(key, url); - } catch (err) { - console.error("[tts]", err); - state.value = "idle"; - currentTrack.value = null; - return; - } - } - if (currentTrack.value) currentTrack.value.audioUrl = url; - el.src = url; - try { - await el.play(); - state.value = "playing"; - } catch (err) { - console.error("[tts] play failed:", err); - state.value = "idle"; - currentTrack.value = null; - } - } - function pause() { - if (audio && state.value === "playing") { - audio.pause(); - state.value = "paused"; - } - } - function resume() { - if (audio && state.value === "paused") { - audio.play(); - state.value = "playing"; - } - } - function stop() { - if (audio) { - audio.pause(); - audio.removeAttribute("src"); - audio.load(); - } - state.value = "idle"; - currentTrack.value = null; - currentTime.value = 0; - duration.value = 0; - } - function seek(fraction) { - if (audio && duration.value > 0) { - audio.currentTime = fraction * duration.value; - } - } - function nav(delta) { - if (!currentTrack.value) return; - const msgs = speakableMessages.value; - const idx = msgs.findIndex((m) => m.msg === currentTrack.value.msgRef); - if (idx < 0) return; - const next2 = msgs[idx + delta]; - if (next2) play(next2.msg, next2.index); - } - function prev() { - nav(-1); - } - function next() { - nav(1); - } - function isPlayingMsg(msg) { - return currentTrack.value?.msgRef === msg; - } - watch(() => store.localSessionId, () => { - stop(); - urlCache.clear(); - }); - return { - state, - currentTrack, - currentTime, - duration, - progress, - speakableMessages, - play, - pause, - resume, - stop, - seek, - prev, - next, - isPlayingMsg - }; -} -let _instance = null; -function useTtsPlayer() { - if (!_instance) _instance = createTtsPlayer(); - return _instance; -} -const _sfc_main$3 = /* @__PURE__ */ defineComponent({ - __name: "TtsPlayerBar", - __ssrInlineRender: true, - setup(__props) { - const tts = useTtsPlayer(); - function formatTime(secs) { - if (!secs || !isFinite(secs)) return "0:00"; - const m = Math.floor(secs / 60); - const s = Math.floor(secs % 60); - return `${m}:${s.toString().padStart(2, "0")}`; - } - return (_ctx, _push, _parent, _attrs) => { - if (unref(tts).state.value !== "idle") { - _push(`
${ssrInterpolate(formatTime(unref(tts).currentTime.value))} / ${ssrInterpolate(formatTime(unref(tts).duration.value))}${ssrInterpolate(unref(tts).currentTrack.value?.snippet || "")}`); - } else { - _push(``); - } - }; - } -}); -const _sfc_setup$3 = _sfc_main$3.setup; -_sfc_main$3.setup = (props, ctx) => { - const ssrContext = useSSRContext(); - (ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("src/components/TtsPlayerBar.vue"); - return _sfc_setup$3 ? _sfc_setup$3(props, ctx) : void 0; -}; -const TtsPlayerBar = /* @__PURE__ */ _export_sfc(_sfc_main$3, [["__scopeId", "data-v-7125b8a5"]]); -const _sfc_main$2 = /* @__PURE__ */ defineComponent({ - __name: "App", - __ssrInlineRender: true, - setup(__props) { - const router = useRouter(); - const AgentsView = defineAsyncComponent(() => import("./assets/AgentsView-CFS236kk.js")); - const ViewerView = defineAsyncComponent(() => import("./assets/ViewerView-5go7ZmZ8.js")); - const DevView = defineAsyncComponent(() => import("./assets/DevView-CqaEvdwT.js")); - const chatStore = useChatStore(); - const visited = reactive({ agents: false, viewer: false, dev: false }); - const isSocketRoute = computed(() => ["agents", "viewer", "dev"].includes(route.name)); - const routerReady = ref(false); - router.isReady().then(() => { - routerReady.value = true; - }); - const route = useRoute(); - const { version: version2 } = useUI(ws.status); - const { doLogout } = auth; - const { currentUser: currentUser2, connected: connected2, status: status2, sessionId: sessionId2, disconnect: disconnect2, onMessage: onWsMessage, replayBuffer: replayBuffer2 } = ws; - const { selectedAgent, updateFromServer } = agents; - const { theme: theme2 } = useTheme(); - function handleLogout() { - doLogout(disconnect2); - visited.agents = visited.viewer = visited.dev = false; - } - function maybeConnect() { - if (auth.isLoggedIn.value && !ws.connected.value) { - ws.connect(agents.selectedAgent, auth.isLoggedIn, auth.loginError, agents.selectedMode); - } - } - router.beforeEach((to) => { - if (to.meta?.requiresSocket) { - if (!auth.isLoggedIn.value) return { name: "login" }; - if (!selectedAgent.value) { - const urlAgent = to.query?.agent; - const saved = sessionStorage.getItem("agent"); - if (urlAgent) selectedAgent.value = urlAgent; - else if (saved) selectedAgent.value = saved; - } - maybeConnect(); - } - }); - router.afterEach((to) => { - const name = to.name; - if (name in visited) visited[name] = true; - }); - watch(connected2, (isConnected) => { - if (!isConnected) chatStore.setConnecting(); - }); - onWsMessage((data) => { - if (data.type === "connection_state" && data.state) { - chatStore.applyConnectionState(data.state); - } - if (data.type === "channel_state" && data.state) { - chatStore.applyChannelState(data.state); - } - }); - replayBuffer2((data) => { - if (data.type === "connection_state" && data.state) chatStore.applyConnectionState(data.state); - if (data.type === "channel_state" && data.state) chatStore.applyChannelState(data.state); - }); - watch(theme2, (t) => { - const logo = THEME_LOGOS[t]; - const el = document.querySelector('link[rel~="icon"]'); - if (el) el.href = logo ?? "/favicon.ico"; - }); - const beVersion = ref(""); - const envLabel = "prod"; - const versionState = ref("short"); - const fullVersionText = computed(() => `[${envLabel}] fe: ${version2} | be: ${beVersion.value || "…"}`); - computed(() => { - if (versionState.value === "short") return version2.split("-")[0]; - if (versionState.value === "copied") return "βœ“ copied"; - return fullVersionText.value; - }); - onMounted(() => { - onWsMessage((data) => { - if (data.type === "ready" || data.type === "auth_ok") { - connected2.value = true; - currentUser2.value = data.user; - sessionId2.value = data.sessionId; - status2.value = "Connected"; - if (data.version) { - beVersion.value = data.version; - chatStore.beVersion = data.version; - } - updateFromServer(data); - if (route.path === "/login") router.push("/agents"); - } else if (data.type === "cost_update") { - chatStore.sessionUsage = data.usage; - chatStore.sessionCost = data.cost; - } - }); - }); - return (_ctx, _push, _parent, _attrs) => { - const _component_RouterView = resolveComponent("RouterView"); - _push(`
`); - _push(ssrRenderComponent(_sfc_main$4, { onLogout: handleLogout }, null, _parent)); - _push(`
`); - _push(ssrRenderComponent(TtsPlayerBar, null, null, _parent)); - if (visited.agents) { - _push(ssrRenderComponent(unref(AgentsView), { - class: { "view-hidden": unref(route).name !== "agents" } - }, null, _parent)); - } else { - _push(``); - } - if (visited.viewer) { - _push(ssrRenderComponent(unref(ViewerView), { - class: { "view-hidden": unref(route).name !== "viewer" } - }, null, _parent)); - } else { - _push(``); - } - if (visited.dev) { - _push(ssrRenderComponent(unref(DevView), { - class: { "view-hidden": unref(route).name !== "dev" } - }, null, _parent)); - } else { - _push(``); - } - if (routerReady.value && !isSocketRoute.value) { - _push(ssrRenderComponent(_component_RouterView, null, null, _parent)); - } else { - _push(``); - } - _push(`
`); - _push(ssrRenderComponent(GridOverlay, null, null, _parent)); - _push(ssrRenderComponent(BreakpointBadge, null, null, _parent)); - _push(`
`); - }; - } -}); -const _sfc_setup$2 = _sfc_main$2.setup; -_sfc_main$2.setup = (props, ctx) => { - const ssrContext = useSSRContext(); - (ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("src/App.vue"); - return _sfc_setup$2 ? _sfc_setup$2(props, ctx) : void 0; -}; -const vertexShader = ` - attribute vec2 a_position; - uniform float u_aspect; - void main() { - vec2 pos = a_position; - pos.x /= u_aspect; - gl_Position = vec4(pos, 0, 1); - gl_PointSize = 7.0; - } -`; -const fragmentShader = ` - precision mediump float; - uniform vec3 u_color; - void main() { - float d = distance(gl_PointCoord, vec2(0.5)); - if (d > 0.5) discard; - float alpha = (0.5 - d) * 2.0; - gl_FragColor = vec4(u_color, alpha * 0.9); - } -`; -const _sfc_main$1 = /* @__PURE__ */ defineComponent({ - __name: "WebGLBackground", - __ssrInlineRender: true, - setup(__props) { - const canvas = ref(); - const ready = ref(false); - let ctx = null; - let animationId; - let resizeHandler = null; - function createShader(gl, type, source) { - const shader = gl.createShader(type); - if (!shader) return null; - gl.shaderSource(shader, source); - gl.compileShader(shader); - if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { - console.error(gl.getShaderInfoLog(shader)); - gl.deleteShader(shader); - return null; - } - return shader; - } - function createProgram(gl, vs, fs) { - const program = gl.createProgram(); - if (!program) return null; - gl.attachShader(program, vs); - gl.attachShader(program, fs); - gl.linkProgram(program); - if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { - console.error(gl.getProgramInfoLog(program)); - return null; - } - return program; - } - onMounted(() => { - const c = canvas.value; - if (!c) return; - resizeHandler = () => { - c.width = window.innerWidth; - c.height = window.innerHeight; - }; - resizeHandler(); - window.addEventListener("resize", resizeHandler); - ctx = c.getContext("webgl", { alpha: true, premultipliedAlpha: false }); - if (!ctx) return; - const gl = ctx; - gl.clearColor(0, 0, 0, 0); - gl.clear(gl.COLOR_BUFFER_BIT); - const vs = createShader(gl, gl.VERTEX_SHADER, vertexShader); - const fs = createShader(gl, gl.FRAGMENT_SHADER, fragmentShader); - if (!vs || !fs) return; - const program = createProgram(gl, vs, fs); - if (!program) return; - const positionLoc = gl.getAttribLocation(program, "a_position"); - const colorLoc = gl.getUniformLocation(program, "u_color"); - const aspectLoc = gl.getUniformLocation(program, "u_aspect"); - const particleCount = 150; - const positions = new Float32Array(particleCount * 2); - const velocities = new Float32Array(particleCount * 2); - const initAspect = c.width / c.height; - for (let i = 0; i < particleCount; i++) { - positions[i * 2] = (Math.random() * 2 - 1) * initAspect; - positions[i * 2 + 1] = Math.random() * 2 - 1; - velocities[i * 2] = (Math.random() - 0.5) * 6e-4; - velocities[i * 2 + 1] = (Math.random() - 0.5) * 6e-4; - } - const buffer = gl.createBuffer(); - gl.bindBuffer(gl.ARRAY_BUFFER, buffer); - gl.enableVertexAttribArray(positionLoc); - gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0); - gl.useProgram(program); - const cssColor = getComputedStyle(document.documentElement).getPropertyValue("--secondary").trim(); - let pr = 0.4, pg = 0.6, pb = 1; - if (cssColor.startsWith("#") && cssColor.length >= 7) { - pr = parseInt(cssColor.slice(1, 3), 16) / 255; - pg = parseInt(cssColor.slice(3, 5), 16) / 255; - pb = parseInt(cssColor.slice(5, 7), 16) / 255; - } - gl.uniform3f(colorLoc, pr, pg, pb); - let frameCount = 0; - function animate() { - if (!ready.value && ++frameCount > 30) ready.value = true; - gl.viewport(0, 0, c.width, c.height); - gl.uniform1f(aspectLoc, c.width / c.height); - gl.enable(gl.BLEND); - gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); - gl.clearColor(0, 0, 0, 0); - gl.clear(gl.COLOR_BUFFER_BIT); - const aspect = c.width / c.height; - for (let i = 0; i < particleCount; i++) { - positions[i * 2] += velocities[i * 2]; - positions[i * 2 + 1] += velocities[i * 2 + 1]; - if (positions[i * 2] > aspect) positions[i * 2] -= 2 * aspect; - if (positions[i * 2] < -aspect) positions[i * 2] += 2 * aspect; - if (positions[i * 2 + 1] > 1) positions[i * 2 + 1] -= 2; - if (positions[i * 2 + 1] < -1) positions[i * 2 + 1] += 2; - } - gl.bufferData(gl.ARRAY_BUFFER, positions, gl.DYNAMIC_DRAW); - gl.drawArrays(gl.POINTS, 0, particleCount); - animationId = requestAnimationFrame(animate); - } - animate(); - }); - onUnmounted(() => { - cancelAnimationFrame(animationId); - if (resizeHandler) window.removeEventListener("resize", resizeHandler); - }); - return (_ctx, _push, _parent, _attrs) => { - _push(``); - }; - } -}); -const _sfc_setup$1 = _sfc_main$1.setup; -_sfc_main$1.setup = (props, ctx) => { - const ssrContext = useSSRContext(); - (ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("src/components/WebGLBackground.vue"); - return _sfc_setup$1 ? _sfc_setup$1(props, ctx) : void 0; -}; -const WebGLBackground = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["__scopeId", "data-v-3b55d999"]]); -const _sfc_main = /* @__PURE__ */ defineComponent({ - __name: "LoginView", - __ssrInlineRender: true, - setup(__props) { - useRouter(); - const { isLoggedIn, loginToken, loginError, loggingIn } = auth; - return (_ctx, _push, _parent, _attrs) => { - _push(``); - _push(ssrRenderComponent(WebGLBackground, null, null, _parent)); - _push(``); - }; - } -}); -const _sfc_setup = _sfc_main.setup; -_sfc_main.setup = (props, ctx) => { - const ssrContext = useSSRContext(); - (ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("src/views/LoginView.vue"); - return _sfc_setup ? _sfc_setup(props, ctx) : void 0; -}; -const routes = [ - { path: "/", name: "home", component: () => import("./assets/CompanyView-9MVdsTPz.js"), meta: { suffix: "" } }, - { path: "/impressum", name: "impressum", component: () => import("./assets/ImpressumView-B77dj09a.js"), meta: { suffix: "Impressum" } }, - { path: "/datenschutz", name: "datenschutz", component: () => import("./assets/DatenschutzView-CmUxA-7Z.js"), meta: { suffix: "Datenschutz" } }, - { path: "/login", name: "login", component: _sfc_main, meta: { suffix: "Login" } }, - { path: "/agents", name: "agents", component: () => import("./assets/AgentsView-CFS236kk.js"), meta: { suffix: "Home", requiresSocket: true } }, - { path: "/chat", redirect: "/agents" }, - { path: "/dev", name: "dev", component: () => import("./assets/DevView-CqaEvdwT.js"), meta: { suffix: "Dev", requiresSocket: true } }, - { path: "/viewer", name: "viewer", component: () => import("./assets/ViewerView-5go7ZmZ8.js"), meta: { suffix: "Viewer", requiresSocket: true } }, - { path: "/:pathMatch(.*)*", redirect: "/" } -]; -const _h = typeof window !== "undefined" ? window.__hermes || (window.__hermes = {}) : {}; -if (typeof window !== "undefined" && !_h._origConsole) { - const MAX = 200; - const buf = _h.console || []; - const orig = { log: console.log, warn: console.warn, error: console.error, info: console.info, debug: console.debug }; - for (const [level, fn] of Object.entries(orig)) { - console[level] = (...args) => { - buf.push({ t: Date.now(), l: level, m: args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ") }); - if (buf.length > MAX) buf.splice(0, buf.length - MAX); - fn.apply(console, args); - }; - } - _h.console = buf; - _h._origConsole = orig; -} -const createApp = ViteSSG( - _sfc_main$2, - { routes }, - ({ app }) => { - app.use(createPinia()); - } -); -export { - THEME_ICONS as T, - _export_sfc as _, - agents as a, - auth as b, - useTtsPlayer as c, - createApp, - useUI as d, - agentLogo as e, - useTheme as f, - getApiBase as g, - useDevFlags as h, - useViewerStore as i, - lastViewerPath as l, - scrollbarOptions as s, - takeover as t, - useChatStore as u, - ws as w -};