@toothfairyai/tfdesign 0.4.7 → 0.4.9-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/apps/web/out/404/index.html +1 -1
- package/apps/web/out/404.html +1 -1
- package/apps/web/out/__next.$oc$slug.__PAGE__.txt +3 -3
- package/apps/web/out/__next.$oc$slug.txt +3 -3
- package/apps/web/out/__next._full.txt +16 -16
- package/apps/web/out/__next._head.txt +4 -4
- package/apps/web/out/__next._index.txt +6 -7
- package/apps/web/out/__next._tree.txt +3 -3
- package/apps/web/out/_next/static/chunks/0-94cql6nl0jv.css +2 -0
- package/apps/web/out/_next/static/chunks/0-_4nyrx9a0p_.js +4586 -0
- package/apps/web/out/_next/static/chunks/012el4mxdksfa.js +1 -0
- package/apps/web/out/_next/static/chunks/033hdyh92lap-.js +1 -0
- package/apps/web/out/_next/static/chunks/{0~saitcv01ulm.js → 09kj3eb8dudq..js} +1 -3
- package/apps/web/out/_next/static/chunks/0eyc01y70gfu8.js +5 -0
- package/apps/web/out/_next/static/chunks/0gfud9-ayub5k.css +1 -0
- package/apps/web/out/_next/static/chunks/0otg4bwz5am.y.css +2 -0
- package/apps/web/out/_next/static/chunks/0qgizcmqgdduz.js +1 -0
- package/apps/web/out/_next/static/chunks/0rjd9p0m-xust.js +31 -0
- package/apps/web/out/_next/static/chunks/111k.piti8qwb.js +1 -0
- package/apps/web/out/_next/static/chunks/1434omkut_t67.js +1 -0
- package/apps/web/out/_next/static/chunks/{turbopack-0qjykn58ffuft.js → turbopack-15aa1bhzoau.r.js} +1 -3
- package/apps/web/out/_not-found/__next._full.txt +23 -19
- package/apps/web/out/_not-found/__next._head.txt +4 -4
- package/apps/web/out/_not-found/__next._index.txt +6 -7
- package/apps/web/out/_not-found/__next._not-found.__PAGE__.txt +2 -2
- package/apps/web/out/_not-found/__next._not-found.txt +3 -3
- package/apps/web/out/_not-found/__next._tree.txt +3 -3
- package/apps/web/out/_not-found/index.html +1 -1
- package/apps/web/out/_not-found/index.txt +23 -19
- package/apps/web/out/align-center.png +0 -0
- package/apps/web/out/align-right.png +0 -0
- package/apps/web/out/align-text.png +0 -0
- package/apps/web/out/app-icon.png +0 -0
- package/apps/web/out/app-icon.svg +1 -1
- package/apps/web/out/bottom-alignment.png +0 -0
- package/apps/web/out/fonts/Gilroy-Regular.woff2 +0 -0
- package/apps/web/out/fonts/Gilroy-SemiBold.woff2 +0 -0
- package/apps/web/out/html2canvas.min.js +20 -0
- package/apps/web/out/icon-add-file.png +0 -0
- package/apps/web/out/icon-copy.png +0 -0
- package/apps/web/out/icon-remove.png +0 -0
- package/apps/web/out/index.html +1 -1
- package/apps/web/out/index.txt +16 -16
- package/apps/web/out/left-alignment.png +0 -0
- package/apps/web/out/logo.svg +14 -5
- package/apps/web/out/top-alignment.png +0 -0
- package/dist/{chunk-VIER63EE.js → chunk-Q2ALQSZX.js} +590 -110
- package/dist/cli.js +29 -6
- package/dist/{server-RXVSJGZG.js → server-PZVSL7GD.js} +1 -1
- package/package.json +11 -1
- package/apps/web/out/_next/static/chunks/00.vhdzyqgugx.js.map +0 -1
- package/apps/web/out/_next/static/chunks/026q~go~dh3ct.js.map +0 -1
- package/apps/web/out/_next/static/chunks/03lp76x6ml3q7.js.map +0 -1
- package/apps/web/out/_next/static/chunks/03rwb84ufo-ml.css +0 -2
- package/apps/web/out/_next/static/chunks/03~yq9q893hmn.js.map +0 -1
- package/apps/web/out/_next/static/chunks/05z1ica28h4v4.js.map +0 -1
- package/apps/web/out/_next/static/chunks/06pwisw_r78h0.js.map +0 -1
- package/apps/web/out/_next/static/chunks/07e0~_ag4wd_2.js +0 -3
- package/apps/web/out/_next/static/chunks/0856t9l8e24kl.js +0 -3459
- package/apps/web/out/_next/static/chunks/09dn2kc7uy573.css +0 -3
- package/apps/web/out/_next/static/chunks/0_h7u0wcctdvf.js.map +0 -1
- package/apps/web/out/_next/static/chunks/0bfs9u56d4mzi.js.map +0 -1
- package/apps/web/out/_next/static/chunks/0bnhnqs10zvm0.js +0 -3
- package/apps/web/out/_next/static/chunks/0b~oqibb-klk8.js.map +0 -1
- package/apps/web/out/_next/static/chunks/0dlz0h-q.e8t5.js.map +0 -1
- package/apps/web/out/_next/static/chunks/0e2qn3b70-t2i.js +0 -34
- package/apps/web/out/_next/static/chunks/0fv_wqm4-r1hb.js +0 -12
- package/apps/web/out/_next/static/chunks/0fysc_wo2kzsu.js.map +0 -1
- package/apps/web/out/_next/static/chunks/0i-mjuoftnsa3.js +0 -3
- package/apps/web/out/_next/static/chunks/0ix3s5zdxhkjq.js +0 -12
- package/apps/web/out/_next/static/chunks/0ovz1kz3yt45_.js +0 -33
- package/apps/web/out/_next/static/chunks/0ps7zql~4nu4c.js.map +0 -1
- package/apps/web/out/_next/static/chunks/0qans9q_q-pop.js +0 -7
- package/apps/web/out/_next/static/chunks/0t3k3fodzjqbk.js +0 -3
- package/apps/web/out/_next/static/chunks/0vh07vpip-7jr.js.map +0 -1
- package/apps/web/out/_next/static/chunks/0weq586uhw-26.js.map +0 -1
- package/apps/web/out/_next/static/chunks/0y1f9xlua9~_u.css +0 -2
- package/apps/web/out/_next/static/chunks/0zvsnz1lw0thi.js.map +0 -1
- package/apps/web/out/_next/static/chunks/0~ge_azerwvf9.css.map +0 -6
- package/apps/web/out/_next/static/chunks/0~wbkak703p3z.js +0 -3
- package/apps/web/out/_next/static/chunks/11uef98fc_tfp.css.map +0 -1
- package/apps/web/out/_next/static/chunks/14hojq718_2.u.js +0 -34
- package/apps/web/out/_next/static/chunks/15j8a~eyh6.eg.css.map +0 -1
- package/apps/web/out/_next/static/chunks/16cm9w~y8~hqh.js.map +0 -1
- package/apps/web/out/_next/static/chunks/17p64lujxa85m.js +0 -3
- package/apps/web/out/agent-icons/aider.png +0 -0
- package/apps/web/out/agent-icons/amr.svg +0 -8
- package/apps/web/out/agent-icons/antigravity.svg +0 -1
- package/apps/web/out/agent-icons/claude.svg +0 -1
- package/apps/web/out/agent-icons/codex.svg +0 -1
- package/apps/web/out/agent-icons/copilot.svg +0 -1
- package/apps/web/out/agent-icons/cursor-agent.svg +0 -1
- package/apps/web/out/agent-icons/deepseek.svg +0 -1
- package/apps/web/out/agent-icons/devin.png +0 -0
- package/apps/web/out/agent-icons/gemini.svg +0 -1
- package/apps/web/out/agent-icons/grok-build.svg +0 -15
- package/apps/web/out/agent-icons/hermes.svg +0 -1
- package/apps/web/out/agent-icons/kilo.svg +0 -1
- package/apps/web/out/agent-icons/kimi.svg +0 -1
- package/apps/web/out/agent-icons/kiro.svg +0 -1
- package/apps/web/out/agent-icons/mimo.svg +0 -1
- package/apps/web/out/agent-icons/opencode.svg +0 -1
- package/apps/web/out/agent-icons/pi.svg +0 -1
- package/apps/web/out/agent-icons/qoder.svg +0 -1
- package/apps/web/out/agent-icons/qwen.svg +0 -1
- package/apps/web/out/agent-icons/reasonix.svg +0 -37
- package/apps/web/out/agent-icons/trae-cli.png +0 -0
- package/apps/web/out/agent-icons/vibe.svg +0 -1
- package/apps/web/out/brand-icon.svg +0 -5
- package/apps/web/out/desktop-pet/__next._full.txt +0 -20
- package/apps/web/out/desktop-pet/__next._head.txt +0 -6
- package/apps/web/out/desktop-pet/__next._index.txt +0 -8
- package/apps/web/out/desktop-pet/__next._tree.txt +0 -3
- package/apps/web/out/desktop-pet/__next.desktop-pet.__PAGE__.txt +0 -6
- package/apps/web/out/desktop-pet/__next.desktop-pet.txt +0 -5
- package/apps/web/out/desktop-pet/index.html +0 -1
- package/apps/web/out/desktop-pet/index.txt +0 -20
- package/apps/web/out/logo.png +0 -0
- package/apps/web/out/model-icons/black-forest-labs.svg +0 -10
- package/apps/web/out/model-icons/bytedance.svg +0 -1
- package/apps/web/out/model-icons/elevenlabs.svg +0 -1
- package/apps/web/out/model-icons/fishaudio.svg +0 -1
- package/apps/web/out/model-icons/flux.svg +0 -1
- package/apps/web/out/model-icons/google-gemini.svg +0 -1
- package/apps/web/out/model-icons/minimax.svg +0 -1
- package/apps/web/out/model-icons/openai.svg +0 -1
- package/apps/web/out/model-icons/openrouter.svg +0 -1
- package/apps/web/out/model-icons/suno.svg +0 -1
- package/apps/web/out/model-icons/x.svg +0 -1
- package/apps/web/out/official_badge.svg +0 -48
- package/apps/web/out/remixicon.woff2 +0 -0
- /package/apps/web/out/_next/static/{EOfAKklAkTBpVS50QG3jX → LZdEU9ZvDchB9VDyfg54d}/_buildManifest.js +0 -0
- /package/apps/web/out/_next/static/{EOfAKklAkTBpVS50QG3jX → LZdEU9ZvDchB9VDyfg54d}/_clientMiddlewareManifest.js +0 -0
- /package/apps/web/out/_next/static/{EOfAKklAkTBpVS50QG3jX → LZdEU9ZvDchB9VDyfg54d}/_ssgManifest.js +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["turbopack:///[project]/apps/web/src/providers/sse.ts","turbopack:///[project]/apps/web/src/observability/stuck-run.ts","turbopack:///[project]/apps/web/src/providers/daemon.ts","turbopack:///[project]/apps/web/src/components/pet/DesktopPetSurface.tsx"],"sourcesContent":["export type ParsedSseFrame =\n | { kind: 'event'; event: string; data: Record<string, unknown>; id?: string }\n | { kind: 'comment'; comment: string }\n | { kind: 'empty' };\n\nexport function parseSseFrame(frame: string): ParsedSseFrame | null {\n const lines = frame.split('\\n');\n const comments: string[] = [];\n let event = 'message';\n let id: string | undefined;\n const dataLines: string[] = [];\n\n for (const rawLine of lines) {\n const line = rawLine.endsWith('\\r') ? rawLine.slice(0, -1) : rawLine;\n if (line.startsWith(':')) {\n comments.push(line.slice(1).trimStart());\n } else if (line.startsWith('event: ')) {\n event = line.slice(7).trim();\n } else if (line.startsWith('id: ')) {\n id = line.slice(4).trim();\n } else if (line.startsWith('data: ')) {\n dataLines.push(line.slice(6));\n }\n }\n\n if (dataLines.length === 0) {\n if (comments.length > 0) {\n return { kind: 'comment', comment: comments.join('\\n') };\n }\n return { kind: 'empty' };\n }\n\n try {\n return { kind: 'event', event, data: JSON.parse(dataLines.join('\\n')), ...(id ? { id } : {}) };\n } catch {\n return null;\n }\n}\n","// Stuck-run watchdog.\n//\n// Emits `client_run_stuck` when a run that we've seen `run_created` for\n// has not progressed within `STUCK_AFTER_MS` (no SSE events, no terminal\n// state, no cancellation). This is the web-side proxy for SSE health —\n// we don't yet instrument the full stream lifecycle (start / heartbeat /\n// disconnect) but the user-visible symptom is invariably \"I started a run\n// and nothing's happening\", so a coarse stuck-after-timeout watchdog\n// catches the most common bad outcome.\n//\n// The watchdog is fired-and-forgotten: callers tell us a run started,\n// poke us every time they see progress, and tell us when it terminates.\n// Anything else and we emit the stuck event exactly once per run.\n//\n// Tied directly to issues #2464 / #2405 / #1451 — all reported as \"run\n// stuck in working state forever\". After this lands those reports become\n// data instead of GitHub anecdotes.\n\nimport { reportSafetyEvent } from '../analytics/error-tracking';\n\nconst STUCK_AFTER_MS = 5 * 60 * 1000; // 5 minutes with no progress\n\ninterface WatchedRun {\n runId: string;\n startedAt: number;\n lastProgressAt: number;\n timer: ReturnType<typeof setTimeout>;\n emitted: boolean;\n context: Record<string, unknown>;\n}\n\nconst runs = new Map<string, WatchedRun>();\n\nexport function trackRunStart(runId: string, context: Record<string, unknown> = {}): void {\n if (typeof window === 'undefined') return;\n // Replace any prior entry — a fresh start invalidates the previous\n // watchdog (rare but possible during reconnect storms).\n cancelRun(runId);\n const now = Date.now();\n const entry: WatchedRun = {\n runId,\n startedAt: now,\n lastProgressAt: now,\n timer: scheduleEmit(runId),\n emitted: false,\n context,\n };\n runs.set(runId, entry);\n}\n\nexport function trackRunProgress(runId: string): void {\n const entry = runs.get(runId);\n if (!entry) return;\n if (entry.emitted) return;\n entry.lastProgressAt = Date.now();\n clearTimeout(entry.timer);\n entry.timer = scheduleEmit(runId);\n}\n\nexport function trackRunTerminal(runId: string, terminalState: string): void {\n const entry = runs.get(runId);\n if (!entry) return;\n clearTimeout(entry.timer);\n runs.delete(runId);\n // Don't double-emit if we already declared it stuck — the late\n // terminal arrival is still useful to know about, though, so emit a\n // recovery event so the dashboard can pair the two.\n if (entry.emitted) {\n reportSafetyEvent('client_run_unstuck', {\n run_id: runId,\n terminal_state: terminalState,\n total_duration_ms: Date.now() - entry.startedAt,\n ...entry.context,\n });\n }\n}\n\nfunction cancelRun(runId: string): void {\n const existing = runs.get(runId);\n if (!existing) return;\n clearTimeout(existing.timer);\n runs.delete(runId);\n}\n\nfunction scheduleEmit(runId: string): ReturnType<typeof setTimeout> {\n return setTimeout(() => emitStuck(runId), STUCK_AFTER_MS);\n}\n\nfunction emitStuck(runId: string): void {\n const entry = runs.get(runId);\n if (!entry) return;\n if (entry.emitted) return;\n entry.emitted = true;\n reportSafetyEvent('client_run_stuck', {\n run_id: runId,\n duration_since_last_progress_ms: Date.now() - entry.lastProgressAt,\n duration_since_start_ms: Date.now() - entry.startedAt,\n ...entry.context,\n });\n}\n\n// Test-only — flush internal state between cases.\nexport function __resetStuckRunWatchdog(): void {\n for (const entry of runs.values()) {\n clearTimeout(entry.timer);\n }\n runs.clear();\n}\n","/**\n * Daemon provider — fetch-based SSE client for /api/runs. The daemon can\n * emit three event streams depending on the agent's streamFormat:\n * - 'agent' : typed events emitted by Claude Code's stream-json parser\n * (status, text_delta, thinking_delta, tool_use, tool_result,\n * usage, raw). We forward these to the UI as AgentEvent items.\n * - 'stdout' : plain chunks from other CLIs. We wrap them in a single\n * rolling 'text' event.\n * - 'stderr' : incidental stderr. Shown only when the process exits\n * non-zero (tail appended to the error message).\n */\nimport type { AgentEvent, ChatCommentAttachment, ChatMessage } from '../types';\nimport type {\n ChatAnalyticsHints,\n ChatRunCreateResponse,\n ChatRunListResponse,\n ChatRunStatus,\n ChatRunStatusResponse,\n ChatRequest,\n ChatSseEvent,\n ChatSseStartPayload,\n DaemonAgentPayload,\n MediaExecutionPolicy,\n ResearchOptions,\n RunContextSelection,\n SseErrorPayload,\n} from '@open-design/contracts';\nimport type { StreamHandlers } from './anthropic';\n\n/**\n * Returns the front-end carrier that's about to send this request:\n * - 'desktop' when running inside the Electron shell\n * - 'web' when running in a regular browser\n * - 'unknown' in non-browser test environments (jsdom without a UA)\n *\n * The daemon uses this to label telemetry traces. Cheap, called once per\n * run so caching isn't worth the complexity.\n */\nfunction detectClientType(): 'desktop' | 'web' | 'unknown' {\n if (typeof navigator === 'undefined') return 'unknown';\n const ua = navigator.userAgent ?? '';\n if (ua.includes('Electron/')) return 'desktop';\n if (ua) return 'web';\n return 'unknown';\n}\nimport { parseSseFrame } from './sse';\nimport { trackRunProgress, trackRunStart, trackRunTerminal } from '../observability/stuck-run';\n\nconst MAX_TRANSCRIPT_MESSAGE_CHARS = 12_000;\nconst LARGE_TOOL_RESULT_CHARS = 8_000;\nconst HIGH_INPUT_TOKEN_WARNING_THRESHOLD = 200_000;\n\nexport function latestUserPromptFromHistory(history: ChatMessage[]): string {\n for (let i = history.length - 1; i >= 0; i -= 1) {\n const message = history[i];\n if (message?.role === 'user') return message.content;\n }\n return '';\n}\n\nfunction truncateForTranscript(content: string): string {\n if (content.length <= MAX_TRANSCRIPT_MESSAGE_CHARS) return content;\n const omitted = content.length - MAX_TRANSCRIPT_MESSAGE_CHARS;\n return `${content.slice(0, MAX_TRANSCRIPT_MESSAGE_CHARS)}\\n\\n[Open Design truncated ${omitted} chars from this prior message before sending it to the agent. Full content remains in persisted history.]`;\n}\n\nfunction escapeTranscriptRoleDelimiters(content: string): string {\n return content.replace(/^(## (?:user|assistant)[ \\t]*)(\\r?)$/gm, '\\\\$1$2');\n}\n\nfunction compactInput(input: unknown): string {\n if (typeof input === 'string') return input;\n try {\n return JSON.stringify(input);\n } catch {\n return String(input);\n }\n}\n\nfunction buildPriorRunContextWarning(history: ChatMessage[]): string | null {\n let highestInputTokens = 0;\n let largeToolResults = 0;\n let sawAgentBrowserCoreDump = false;\n\n for (const message of history) {\n for (const event of message.events ?? []) {\n if (event.kind === 'usage' && typeof event.inputTokens === 'number') {\n highestInputTokens = Math.max(highestInputTokens, event.inputTokens);\n }\n if (event.kind === 'tool_result') {\n if (event.content.length > LARGE_TOOL_RESULT_CHARS) largeToolResults += 1;\n if (\n event.content.includes('agent-browser skills get core') ||\n event.content.includes('Agent Browser Core') ||\n event.content.includes('name: core')\n ) {\n sawAgentBrowserCoreDump = true;\n }\n }\n if (event.kind === 'tool_use') {\n const input = compactInput(event.input);\n if (input.includes('agent-browser skills get core')) {\n sawAgentBrowserCoreDump = true;\n }\n }\n }\n }\n\n const notes: string[] = [];\n if (highestInputTokens >= HIGH_INPUT_TOKEN_WARNING_THRESHOLD) {\n notes.push(`a previous run reported ${highestInputTokens} input tokens`);\n }\n if (largeToolResults > 0) {\n notes.push(`${largeToolResults} large prior tool result${largeToolResults === 1 ? '' : 's'} exist only in persisted event history`);\n }\n if (sawAgentBrowserCoreDump) {\n notes.push('agent-browser documentation output was seen earlier; do not replay it into this turn');\n }\n if (notes.length === 0) return null;\n\n return [\n '## context warning',\n `Open Design detected ${notes.join(', ')}.`,\n 'Keep this turn compact: summarize prior tool output, read large references from temp files, and quote only task-relevant lines.',\n ].join('\\n');\n}\n\nfunction scopeHistoryToAgent(history: ChatMessage[], targetAgentId?: string): ChatMessage[] {\n if (!targetAgentId) return history;\n for (let i = history.length - 1; i >= 0; i -= 1) {\n const message = history[i];\n if (message?.role === 'assistant' && message.agentId && message.agentId !== targetAgentId) {\n return history.slice(i + 1);\n }\n }\n return history;\n}\n\n// Strip OD-specific markup that the agent emitted on a prior turn but\n// that the model would otherwise pattern-match as a template to echo.\n// Today this is `<question-form>` blocks and the ```json fenced schemas\n// some models (GPT-OSS-120B Medium, Gemini 3.5 Flash) emit alongside\n// them — leaving those literal in the transcript causes weak/medium\n// plain-stream models to re-emit an identical form on the user's\n// follow-up turn, looking like the discovery form loop never breaks\n// (see PR #3157 form-loop investigation).\n//\n// User content is preserved verbatim — a user message that legitimately\n// quotes `<question-form>` (e.g. discussing the markup with the agent)\n// must not be mangled.\nexport function sanitizePriorAssistantTurnForTranscript(content: string): string {\n let sanitized = content.replace(\n /<question-form\\b[^>]*>[\\s\\S]*?<\\/question-form>/g,\n '[question-form was emitted here on a prior turn; the user already answered, see their reply below.]',\n );\n // Strip ```json (or plain ```) fenced blocks whose body matches the\n // form schema shape — `\"questions\": [` is the strongest tell. A\n // generic JSON snippet without that key (e.g. an API response the\n // agent shared) is left intact.\n sanitized = sanitized.replace(\n /```(?:json)?\\s*\\n([\\s\\S]*?)\\n```/g,\n (match, body: string) => {\n if (/\"questions\"\\s*:\\s*\\[/.test(body)) {\n return '[form schema was echoed here on a prior turn; stripped to avoid a loop.]';\n }\n return match;\n },\n );\n return sanitized;\n}\n\nexport function buildDaemonTranscript(history: ChatMessage[], targetAgentId?: string): string {\n const scopedHistory = scopeHistoryToAgent(history, targetAgentId);\n const transcript = scopedHistory\n .map((m) => {\n const trimmed = m.content.trim();\n const sanitized =\n m.role === 'assistant'\n ? sanitizePriorAssistantTurnForTranscript(trimmed)\n : trimmed;\n return `## ${m.role}\\n${escapeTranscriptRoleDelimiters(truncateForTranscript(sanitized))}`;\n })\n .join('\\n\\n');\n const warning = buildPriorRunContextWarning(scopedHistory);\n return warning ? `${warning}\\n\\n${transcript}` : transcript;\n}\n\nexport interface DaemonStreamHandlers extends StreamHandlers {\n onAgentEvent: (ev: AgentEvent) => void;\n}\n\nexport interface DaemonStreamOptions {\n agentId: string;\n history: ChatMessage[];\n /** Legacy field accepted by older tests/callers. Daemon-owned prompt composition ignores it. */\n systemPrompt?: string;\n /** Stops the current browser-side SSE subscription. The daemon run continues. */\n signal: AbortSignal;\n /** Explicit user cancellation signal. This maps to POST /api/runs/:id/cancel. */\n cancelSignal?: AbortSignal;\n handlers: DaemonStreamHandlers;\n // The active project's id. When supplied, the daemon spawns the agent\n // with cwd = the project folder so its file tools target the right\n // workspace.\n projectId?: string | null;\n conversationId?: string | null;\n assistantMessageId?: string | null;\n clientRequestId?: string | null;\n skillId?: string | null;\n // Per-turn skill ids picked via the composer's @-mention popover. These\n // are layered onto the system prompt for this run only and do not\n // change the project's persistent `skillId`.\n skillIds?: string[];\n designSystemId?: string | null;\n // Project-relative paths the user has staged for this turn. The\n // daemon resolves them inside the project folder, validates they\n // exist, and stitches them into the user message as `@<path>` hints.\n attachments?: string[];\n commentAttachments?: ChatCommentAttachment[];\n // Per-CLI model + reasoning the user picked in the model menu. Both are\n // optional; the daemon validates them against the agent's declared\n // options and falls back to the CLI default when missing.\n model?: string | null;\n reasoning?: string | null;\n research?: ResearchOptions;\n context?: RunContextSelection;\n mediaExecution?: MediaExecutionPolicy;\n locale?: string;\n initialLastEventId?: string | null;\n onRunCreated?: (runId: string) => void;\n onRunStatus?: (status: ChatRunStatus) => void;\n onRunEventId?: (eventId: string) => void;\n // v2 analytics context propagated to run_created / run_finished.\n // Optional; the daemon only consumes these to shape PostHog props\n // (page_name / area / entry_from / DS context). Behavior never\n // depends on them.\n analyticsHints?: ChatAnalyticsHints;\n}\n\nexport interface DaemonReattachOptions {\n runId: string;\n signal: AbortSignal;\n cancelSignal?: AbortSignal;\n handlers: DaemonStreamHandlers;\n initialLastEventId?: string | null;\n onRunStatus?: (status: ChatRunStatus) => void;\n onRunEventId?: (eventId: string) => void;\n}\n\nexport const RUNS_CHANGED_EVENT = 'open-design:runs-changed';\n\nfunction notifyRunsChanged() {\n if (typeof window === 'undefined') return;\n window.dispatchEvent(new Event(RUNS_CHANGED_EVENT));\n}\n\nfunction daemonSseErrorMessage(data: SseErrorPayload): string {\n const message = String(data.error?.message ?? data.message ?? 'daemon error');\n const detail =\n data.error?.details &&\n typeof data.error.details === 'object' &&\n !Array.isArray(data.error.details) &&\n typeof data.error.details.detail === 'string'\n ? data.error.details.detail\n : null;\n if (!detail || detail === message || message.includes(detail)) return message;\n return `${message}\\n${detail}`;\n}\n\nfunction daemonSseError(data: SseErrorPayload): Error {\n const error = new Error(daemonSseErrorMessage(data)) as Error & {\n code?: string;\n details?: unknown;\n };\n if (data.error?.code) error.code = data.error.code;\n if (data.error?.details !== undefined) error.details = data.error.details;\n return error;\n}\n\nfunction shouldSuppressLifecycleExitFallback(\n agentId: string | undefined,\n exitCode: number | null,\n exitSignal: string | null,\n stderrTail: string,\n): boolean {\n if (exitCode !== 130 || exitSignal) return false;\n if (agentId === 'amr') return true;\n const normalizedStderr = stderrTail.toLowerCase();\n return (\n normalizedStderr.includes('opencode server listening') ||\n normalizedStderr.includes('opencode_server_password')\n );\n}\n\nexport async function streamViaDaemon({\n agentId,\n history,\n signal,\n cancelSignal,\n handlers,\n projectId,\n conversationId,\n assistantMessageId,\n clientRequestId,\n skillId,\n skillIds,\n designSystemId,\n attachments,\n commentAttachments,\n model,\n reasoning,\n research,\n context,\n mediaExecution,\n locale,\n initialLastEventId,\n onRunCreated,\n onRunStatus,\n onRunEventId,\n analyticsHints,\n}: DaemonStreamOptions): Promise<void> {\n const emitRunStatus = (status: ChatRunStatus) => {\n onRunStatus?.(status);\n notifyRunsChanged();\n };\n // Local CLIs are single-turn print-mode programs, so we collapse the whole\n // chat into one string. If this becomes too noisy for long histories, the\n // fix is to only include the final user turn.\n const transcript = buildDaemonTranscript(history, agentId);\n const request: ChatRequest = {\n agentId,\n message: transcript,\n currentPrompt: latestUserPromptFromHistory(history),\n projectId: projectId ?? null,\n conversationId: conversationId ?? null,\n assistantMessageId: assistantMessageId ?? null,\n clientRequestId: clientRequestId ?? null,\n skillId: skillId ?? null,\n skillIds: Array.isArray(skillIds) ? skillIds : [],\n designSystemId: designSystemId ?? null,\n attachments: attachments ?? [],\n commentAttachments: commentAttachments ?? [],\n model: model ?? null,\n reasoning: reasoning ?? null,\n locale,\n ...(context ? { context } : {}),\n ...(research ? { research } : {}),\n ...(mediaExecution ? { mediaExecution } : {}),\n ...(analyticsHints ? { analyticsHints } : {}),\n };\n const body = JSON.stringify(request);\n\n try {\n const createResp = await fetch('/api/runs', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n // Tells the daemon which front-end carrier started the run so the\n // telemetry trace can be tagged 'client:desktop' vs 'client:web'.\n // The daemon falls back to a User-Agent sniff when this header is\n // absent (e.g. third-party clients), so omitting it in tests is OK.\n 'X-OD-Client': detectClientType(),\n },\n body,\n });\n\n if (!createResp.ok) {\n const text = await createResp.text().catch(() => '');\n emitRunStatus('failed');\n handlers.onError(new Error(`daemon ${createResp.status}: ${text || 'no body'}`));\n return;\n }\n\n const created = (await createResp.json()) as ChatRunCreateResponse;\n const runId = created.runId;\n onRunCreated?.(runId);\n // Start the stuck-run watchdog. trackRunProgress is called inside the\n // SSE consumer below on every event; trackRunTerminal fires when the\n // stream resolves to a terminal state (or errors out).\n trackRunStart(runId, {\n agent_id: agentId,\n project_id: projectId ?? undefined,\n conversation_id: conversationId ?? undefined,\n client_type: detectClientType(),\n });\n notifyRunsChanged();\n emitRunStatus('queued');\n await consumeDaemonRun({\n agentId,\n runId,\n signal,\n cancelSignal,\n handlers,\n initialLastEventId,\n onRunStatus: emitRunStatus,\n onRunEventId,\n });\n } catch (err) {\n if ((err as Error).name === 'AbortError') return;\n emitRunStatus('failed');\n handlers.onError(err instanceof Error ? err : new Error(String(err)));\n }\n}\n\nexport async function reattachDaemonRun(options: DaemonReattachOptions): Promise<void> {\n await consumeDaemonRun({\n ...options,\n onRunStatus: (status) => {\n options.onRunStatus?.(status);\n notifyRunsChanged();\n },\n });\n}\n\nexport async function fetchChatRunStatus(runId: string): Promise<ChatRunStatusResponse | null> {\n try {\n const resp = await fetch(`/api/runs/${encodeURIComponent(runId)}`);\n if (!resp.ok) return null;\n return (await resp.json()) as ChatRunStatusResponse;\n } catch {\n return null;\n }\n}\n\n// Push a `tool_result` content block back into a running stream-json child.\n// Used to answer Claude's `AskUserQuestion` tool: the host card collects the\n// user's pick, formats it as one text string, and we route it through the\n// daemon's POST /api/runs/:id/tool-result. The daemon writes it as a JSONL\n// line on the still-open stdin so claude-code can resume mid-call instead\n// of auto-erroring the tool in headless mode.\nexport async function submitChatRunToolResult(\n runId: string,\n toolUseId: string,\n content: string,\n options: { isError?: boolean } = {},\n): Promise<{ ok: boolean; status?: number }> {\n try {\n const resp = await fetch(`/api/runs/${encodeURIComponent(runId)}/tool-result`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ toolUseId, content, isError: !!options.isError }),\n });\n return { ok: resp.ok, status: resp.status };\n } catch {\n return { ok: false };\n }\n}\n\n// PR #3157: Antigravity's auth banner can offer a one-click \"open\n// system terminal with agy\" button. The daemon endpoint spawns\n// osascript / x-terminal-emulator / `cmd /c start` for the user; on\n// success the new Terminal window pops up with agy running and the\n// browser opens for OAuth. The Promise resolves once the daemon kicks\n// off the spawn (not when OAuth completes), so the UI can disable the\n// button momentarily and then re-enable for a retry click after the\n// user finishes in the terminal.\nexport interface LaunchAntigravityOauthResult {\n ok: boolean;\n platform?: string;\n via?: string;\n error?: string;\n}\nexport async function launchAntigravityOauth(): Promise<LaunchAntigravityOauthResult> {\n try {\n const resp = await fetch('/api/agents/antigravity/oauth-launch', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: '{}',\n });\n const body = (await resp.json().catch(() => null)) as\n | LaunchAntigravityOauthResult\n | null;\n if (!resp.ok) {\n return {\n ok: false,\n error:\n body?.error ?? `daemon returned ${resp.status} ${resp.statusText}`,\n };\n }\n return body ?? { ok: true };\n } catch (err) {\n return {\n ok: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n}\n\nexport interface VelaUser {\n id: string;\n email: string;\n name?: string;\n image?: string | null;\n plan?: string;\n}\n\nexport interface VelaLoginStatus {\n loggedIn: boolean;\n loginInFlight?: boolean;\n profile: string;\n user: VelaUser | null;\n configPath: string;\n}\n\n// AMR (vela) login surfaces three thin endpoints on the daemon:\n// GET /api/integrations/vela/status — read ~/.amr/config.json projection\n// POST /api/integrations/vela/login — spawn `vela login` (vela opens browser itself)\n// POST /api/integrations/vela/login/cancel — terminate a still-pending login\n// POST /api/integrations/vela/logout — clear ~/.amr auth and Settings-backed AMR auth env\n// The Settings UI polls /status after kicking off /login to detect completion.\nexport async function fetchVelaLoginStatus(): Promise<VelaLoginStatus | null> {\n try {\n const resp = await fetch('/api/integrations/vela/status');\n if (!resp.ok) return null;\n return (await resp.json()) as VelaLoginStatus;\n } catch {\n return null;\n }\n}\n\nexport interface StartVelaLoginResult {\n ok: boolean;\n status: number;\n pid?: number;\n alreadyRunning?: boolean;\n error?: string;\n}\n\nexport async function startVelaLogin(): Promise<StartVelaLoginResult> {\n try {\n const resp = await fetch('/api/integrations/vela/login', { method: 'POST' });\n if (resp.ok) {\n const body = (await resp.json()) as { pid?: number };\n return { ok: true, status: resp.status, pid: body.pid };\n }\n const body = (await resp.json().catch(() => null)) as { error?: string } | null;\n return {\n ok: false,\n status: resp.status,\n alreadyRunning: resp.status === 409,\n error: body?.error ?? '',\n };\n } catch (err) {\n return { ok: false, status: 0, error: err instanceof Error ? err.message : String(err) };\n }\n}\n\nexport async function cancelVelaLogin(): Promise<{ ok: boolean; canceled?: boolean }> {\n try {\n const resp = await fetch('/api/integrations/vela/login/cancel', { method: 'POST' });\n if (!resp.ok) return { ok: false };\n const body = (await resp.json().catch(() => null)) as { canceled?: boolean } | null;\n return { ok: true, canceled: body?.canceled };\n } catch {\n return { ok: false };\n }\n}\n\nexport async function velaLogout(): Promise<{ ok: boolean }> {\n try {\n const resp = await fetch('/api/integrations/vela/logout', { method: 'POST' });\n return { ok: resp.ok };\n } catch {\n return { ok: false };\n }\n}\n\n// Forwards the user's assistant-turn rating to the daemon so it can emit\n// a Langfuse `score-create`. Fire-and-forget — failures are not surfaced\n// to the UI (the rating is already persisted on the message itself via\n// the PUT /messages/:id round-trip).\nexport async function reportChatRunFeedback(req: {\n runId: string;\n projectId: string;\n conversationId: string;\n assistantMessageId: string;\n rating: 'positive' | 'negative';\n reasonCodes: string[];\n hasCustomReason: boolean;\n customReason: string;\n}): Promise<void> {\n try {\n await fetch(`/api/runs/${encodeURIComponent(req.runId)}/feedback`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(req),\n });\n } catch {\n // Best-effort.\n }\n}\n\nexport async function listActiveChatRuns(\n projectId: string,\n conversationId: string,\n): Promise<ChatRunStatusResponse[]> {\n try {\n const qs = new URLSearchParams({ projectId, conversationId, status: 'active' });\n const resp = await fetch(`/api/runs?${qs.toString()}`);\n if (!resp.ok) return [];\n const body = (await resp.json()) as ChatRunListResponse;\n return body.runs ?? [];\n } catch {\n return [];\n }\n}\n\nexport async function listProjectRuns(): Promise<ChatRunStatusResponse[]> {\n try {\n const resp = await fetch('/api/runs');\n if (!resp.ok) return [];\n const body = (await resp.json()) as ChatRunListResponse;\n return body.runs ?? [];\n } catch {\n return [];\n }\n}\n\nasync function consumeDaemonRun({\n agentId,\n runId,\n signal,\n cancelSignal,\n handlers,\n initialLastEventId,\n onRunStatus,\n onRunEventId,\n}: DaemonReattachOptions & { agentId?: string }): Promise<void> {\n let acc = '';\n let stderrBuf = '';\n let exitCode: number | null = null;\n let exitSignal: string | null = null;\n let endStatus: ChatRunStatus | null = null;\n // Tracks whether the server explicitly declared `status: 'succeeded'` in\n // the SSE end payload (or via the fallback run-status fetch). Distinct\n // from `endStatus === 'succeeded'`, which can be a local fallback when\n // the SSE end event omits or sends an invalid `status` field. Only the\n // explicit declaration is allowed to bypass the exit-code/signal safety\n // net below — a missing-status fallback keeps the old behavior so a\n // failure response with `{code:1}` or `{code:null,signal:\"SIGTERM\"}` and\n // no `status` field still surfaces an error banner.\n let serverDeclaredSuccess = false;\n let lastEventId: string | null = initialLastEventId ?? null;\n let canceled = false;\n const cancelRun = () => {\n if (canceled) return;\n canceled = true;\n void fetch(`/api/runs/${encodeURIComponent(runId)}/cancel`, { method: 'POST' }).catch(() => {});\n };\n\n cancelSignal?.addEventListener('abort', cancelRun, { once: true });\n try {\n if (cancelSignal?.aborted) {\n cancelRun();\n return;\n }\n\n for (let reconnects = 0; endStatus === null && reconnects < 5;) {\n const qs = lastEventId ? `?after=${encodeURIComponent(lastEventId)}` : '';\n let resp: Response;\n try {\n resp = await fetch(`/api/runs/${encodeURIComponent(runId)}/events${qs}`, {\n method: 'GET',\n signal,\n });\n } catch (err) {\n if ((err as Error).name === 'AbortError') throw err;\n reconnects += 1;\n continue;\n }\n\n if (!resp.ok || !resp.body) {\n const text = await resp.text().catch(() => '');\n handlers.onError(new Error(`daemon ${resp.status}: ${text || 'no body'}`));\n return;\n }\n\n const reader = resp.body.getReader();\n const decoder = new TextDecoder();\n let buf = '';\n let sawStreamProgress = false;\n\n while (true) {\n const { value, done } = await reader.read();\n if (done) break;\n buf += decoder.decode(value, { stream: true });\n let idx: number;\n while ((idx = buf.indexOf('\\n\\n')) !== -1) {\n const frame = buf.slice(0, idx);\n buf = buf.slice(idx + 2);\n const parsed = parseSseFrame(frame);\n if (!parsed) continue;\n if (parsed.kind === 'comment') {\n sawStreamProgress = true;\n trackRunProgress(runId);\n continue;\n }\n if (parsed.kind !== 'event') continue;\n sawStreamProgress = true;\n trackRunProgress(runId);\n if (parsed.id) {\n lastEventId = parsed.id;\n onRunEventId?.(parsed.id);\n }\n\n const event = parsed as unknown as ChatSseEvent;\n\n if (event.event === 'stdout') {\n const chunk = String(event.data.chunk ?? '');\n acc += chunk;\n handlers.onDelta(chunk);\n handlers.onAgentEvent({ kind: 'text', text: chunk });\n continue;\n }\n\n if (event.event === 'stderr') {\n stderrBuf += event.data.chunk ?? '';\n continue;\n }\n\n if (event.event === 'agent') {\n const translated = translateAgentEvent(event.data);\n if (!translated) continue;\n if (translated.kind === 'text') {\n acc += translated.text;\n handlers.onDelta(translated.text);\n }\n handlers.onAgentEvent(translated);\n continue;\n }\n\n if (event.event === 'start') {\n const data = event.data as ChatSseStartPayload;\n onRunStatus?.('running');\n handlers.onAgentEvent({\n kind: 'status',\n label: 'starting',\n detail: typeof data.bin === 'string' ? data.bin : undefined,\n });\n continue;\n }\n\n if (event.event === 'error') {\n onRunStatus?.('failed');\n const data = event.data as SseErrorPayload;\n handlers.onError(daemonSseError(data));\n return;\n }\n\n if (event.event === 'end') {\n exitCode = typeof event.data.code === 'number' ? event.data.code : null;\n exitSignal = typeof event.data.signal === 'string' ? event.data.signal : null;\n // `serverDeclaredSuccess` records whether the server explicitly\n // set `status: 'succeeded'` in the end payload — the local\n // `'succeeded'` fallback below does not count and must keep\n // hitting the exit-code/signal safety net later.\n serverDeclaredSuccess = event.data.status === 'succeeded';\n endStatus = isChatRunStatus(event.data.status) ? event.data.status : 'succeeded';\n onRunStatus?.(endStatus);\n }\n }\n }\n reconnects = sawStreamProgress ? 0 : reconnects + 1;\n }\n\n if (endStatus === null) {\n const status = await fetchChatRunStatus(runId);\n if (status && isChatRunStatus(status.status) && status.status !== 'queued' && status.status !== 'running') {\n endStatus = status.status;\n exitCode = status.exitCode ?? null;\n exitSignal = status.signal ?? null;\n // Fallback REST path: `status.status` is explicitly declared by the\n // daemon's run record (it passed `isChatRunStatus()` above), so an\n // explicit `'succeeded'` here is just as authoritative as the SSE\n // end-event success.\n serverDeclaredSuccess = status.status === 'succeeded';\n onRunStatus?.(endStatus);\n } else {\n onRunStatus?.('failed');\n handlers.onError(new Error('daemon stream disconnected before run completed'));\n return;\n }\n }\n\n if (endStatus === 'canceled') {\n handlers.onDone(acc);\n return;\n }\n\n // Trust the server's authoritative success declaration. When the server\n // explicitly sets `status: 'succeeded'` (either in the SSE end payload\n // or via the fallback run-status fetch), the run completed cleanly even\n // if the underlying process exited via a signal — some agents (e.g.\n // ACP agents like Devin for Terminal) intentionally exit via SIGTERM\n // after a clean prompt completion because they don't shut down on\n // `stdin.end()`. The signal/non-zero-code safety net is bypassed only\n // for that explicit declaration; a missing/invalid `status` from a\n // compatible or older daemon still falls back to `endStatus =\n // 'succeeded'` for the run-status surface but must keep the safety net\n // intact so a real failure response like `{code:1}` or\n // `{code:null,signal:\"SIGTERM\"}` without `status` still surfaces an\n // error banner.\n const looksLikeFailure =\n endStatus === 'failed' ||\n (!serverDeclaredSuccess &&\n (exitSignal || (exitCode !== null && exitCode !== 0)));\n if (looksLikeFailure) {\n if (shouldSuppressLifecycleExitFallback(agentId, exitCode, exitSignal, stderrBuf)) {\n handlers.onDone(acc);\n return;\n }\n const tail = stderrBuf.trim().slice(-400);\n handlers.onError(\n new Error(`agent exited with ${exitSignal ? `signal ${exitSignal}` : `code ${exitCode}`}${tail ? `\\n${tail}` : ''}`),\n );\n return;\n }\n handlers.onDone(acc);\n } finally {\n cancelSignal?.removeEventListener('abort', cancelRun);\n // Settle the stuck-run watchdog with whatever terminal state we\n // resolved. If the watchdog was never armed (reattach paths that\n // hit the daemon for an already-finished run), trackRunTerminal\n // is a no-op for unknown runIds.\n trackRunTerminal(runId, endStatus ?? (canceled ? 'canceled' : 'unknown'));\n }\n}\n\nfunction isChatRunStatus(value: unknown): value is ChatRunStatus {\n return value === 'queued' || value === 'running' || value === 'succeeded' || value === 'failed' || value === 'canceled';\n}\n\nfunction normalizeToolInput(input: unknown): unknown {\n if (input == null || typeof input !== 'object') return input;\n const obj = input as Record<string, unknown>;\n if ('filePath' in obj && typeof obj.filePath === 'string') {\n return { ...obj, file_path: obj.filePath };\n }\n return input;\n}\n\n// Translate a raw `agent` SSE payload (what apps/daemon/src/claude-stream.ts emits)\n// into the UI's AgentEvent union. Keep this liberal — unknown types just\n// return null so the UI ignores them instead of rendering garbage.\nfunction translateAgentEvent(data: DaemonAgentPayload): AgentEvent | null {\n const t = data.type;\n if (t === 'status' && typeof data.label === 'string') {\n return {\n kind: 'status',\n label: data.label,\n detail:\n typeof data.detail === 'string'\n ? data.detail\n : typeof data.model === 'string'\n ? data.model\n : typeof data.ttftMs === 'number'\n ? `first token in ${Math.round((data.ttftMs as number) / 100) / 10}s`\n : undefined,\n };\n }\n if (t === 'text_delta' && typeof data.delta === 'string') {\n return { kind: 'text', text: data.delta };\n }\n if (t === 'thinking_delta' && typeof data.delta === 'string') {\n return { kind: 'thinking', text: data.delta };\n }\n if (t === 'thinking_start') {\n return { kind: 'status', label: 'thinking' };\n }\n if (t === 'live_artifact') {\n return {\n kind: 'live_artifact',\n action: data.action,\n projectId: data.projectId,\n artifactId: data.artifactId,\n title: data.title,\n refreshStatus: data.refreshStatus,\n };\n }\n if (t === 'live_artifact_refresh') {\n return {\n kind: 'live_artifact_refresh',\n phase: data.phase,\n projectId: data.projectId,\n artifactId: data.artifactId,\n refreshId: data.refreshId,\n title: data.title,\n refreshedSourceCount: data.refreshedSourceCount,\n error: data.error,\n };\n }\n if (t === 'tool_use' && typeof data.id === 'string' && typeof data.name === 'string') {\n return { kind: 'tool_use', id: data.id, name: data.name, input: normalizeToolInput(data.input) };\n }\n if (t === 'tool_result' && typeof data.toolUseId === 'string') {\n return {\n kind: 'tool_result',\n toolUseId: data.toolUseId,\n content: String(data.content ?? ''),\n isError: Boolean(data.isError),\n };\n }\n if (t === 'usage') {\n const usage = (data.usage ?? {}) as Record<string, number>;\n return {\n kind: 'usage',\n inputTokens: usage.input_tokens,\n outputTokens: usage.output_tokens,\n costUsd: typeof data.costUsd === 'number' ? data.costUsd : undefined,\n durationMs: typeof data.durationMs === 'number' ? data.durationMs : undefined,\n };\n }\n if (t === 'fabricated_role_marker' && typeof data.marker === 'string') {\n return {\n kind: 'status',\n label: 'warning',\n detail: `Model emitted fabricated role marker (\"${data.marker}\"). Response was truncated to prevent unauthorized instruction injection.`,\n };\n }\n if (t === 'raw' && typeof data.line === 'string') {\n return { kind: 'raw', line: data.line };\n }\n return null;\n}\n\nexport async function saveArtifact(\n identifier: string,\n title: string,\n html: string,\n): Promise<{ url: string; path: string } | null> {\n try {\n const resp = await fetch('/api/artifacts/save', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ identifier, title, html }),\n });\n if (!resp.ok) return null;\n return (await resp.json()) as { url: string; path: string };\n } catch {\n return null;\n }\n}\n","'use client';\n\nimport { useEffect, useState } from 'react';\nimport { setHostPetVisible } from '@open-design/host';\nimport { RUNS_CHANGED_EVENT, listProjectRuns } from '../../providers/daemon';\nimport { loadConfig } from '../../state/config';\nimport { listProjects } from '../../state/projects';\nimport type { AppConfig } from '../../types';\nimport { PetOverlay, type PetTaskCenter } from './PetOverlay';\nimport { buildPetTaskCenter } from './taskCenter';\n\nconst CONFIG_POLL_MS = 1500;\nconst TASK_POLL_MS = 2000;\n\nexport function DesktopPetSurface() {\n const [config, setConfig] = useState<AppConfig>(() => loadConfig());\n const [taskCenter, setTaskCenter] = useState<PetTaskCenter>({\n running: [],\n queued: [],\n recent: [],\n });\n const pet = config.pet?.enabled ? config.pet : undefined;\n\n useEffect(() => {\n document.body.classList.add('desktop-pet-shell');\n return () => document.body.classList.remove('desktop-pet-shell');\n }, []);\n\n useEffect(() => {\n const refresh = () => setConfig(loadConfig());\n window.addEventListener('storage', refresh);\n const id = window.setInterval(refresh, CONFIG_POLL_MS);\n return () => {\n window.removeEventListener('storage', refresh);\n window.clearInterval(id);\n };\n }, []);\n\n useEffect(() => {\n setHostPetVisible(Boolean(pet));\n }, [pet]);\n\n useEffect(() => {\n if (!pet) {\n setTaskCenter({ running: [], queued: [], recent: [] });\n return;\n }\n let cancelled = false;\n const refresh = async () => {\n const [projects, runs] = await Promise.all([\n listProjects(),\n listProjectRuns(),\n ]);\n if (cancelled) return;\n setTaskCenter(buildPetTaskCenter(projects, runs));\n };\n const handleRunsChanged = () => {\n void refresh();\n };\n void refresh();\n window.addEventListener(RUNS_CHANGED_EVENT, handleRunsChanged);\n const id = window.setInterval(refresh, TASK_POLL_MS);\n return () => {\n cancelled = true;\n window.removeEventListener(RUNS_CHANGED_EVENT, handleRunsChanged);\n window.clearInterval(id);\n };\n }, [pet]);\n\n return (\n <PetOverlay\n pet={pet}\n taskCenter={taskCenter}\n persistentBubble\n />\n );\n}\n"],"names":["parseSseFrame","frame","lines","split","comments","event","id","dataLines","rawLine","line","endsWith","slice","startsWith","push","trimStart","trim","length","kind","comment","join","data","JSON","parse","CONFIG_POLL_MS","TASK_POLL_MS","DesktopPetSurface","config","setConfig","taskCenter","setTaskCenter","running","queued","recent","pet","enabled","undefined","document","body","classList","add","remove","refresh","window","addEventListener","setInterval","removeEventListener","clearInterval","Boolean","cancelled","projects","runs","Promise","all","handleRunsChanged","persistentBubble"],"mappings":"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"}
|