crewswarm 0.8.1-beta → 0.8.2-beta

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.
Files changed (62) hide show
  1. package/.env.example +50 -0
  2. package/apps/dashboard/dist/assets/{chat-core-BwSoInmZ.js → chat-core-CMoqlR6D.js} +1 -1
  3. package/apps/dashboard/dist/assets/{index-Px49zu76.js → index-DqVVQLTW.js} +1 -1
  4. package/apps/dashboard/dist/assets/setup-wizard-D4g5DMhW.js +1 -0
  5. package/apps/dashboard/dist/assets/tab-models-tab-CQzvaeVh.js +1 -0
  6. package/apps/dashboard/dist/index.html +24 -7
  7. package/apps/dashboard/dist/manifest.json +20 -0
  8. package/apps/dashboard/dist/sw.js +28 -0
  9. package/apps/dashboard/index.html +19 -2
  10. package/apps/dashboard/src/setup-wizard.js +7 -0
  11. package/apps/dashboard/src/tabs/models-tab.js +10 -1
  12. package/apps/vibe/.crew/agent-memory/pipeline.json +45 -1
  13. package/apps/vibe/.crew/cost.json +3 -3
  14. package/apps/vibe/.crew/json-parse-metrics.jsonl +4 -0
  15. package/apps/vibe/.crew/pipeline-metrics.jsonl +4 -0
  16. package/apps/vibe/.crew/pipeline-runs/pipeline-288a7765-da24-4a22-89bc-1f3cc9b0562c.jsonl +4 -0
  17. package/apps/vibe/.crew/pipeline-runs/pipeline-3da23550-22ed-4904-9a0a-8e79c1f3024c.jsonl +5 -0
  18. package/apps/vibe/.crew/pipeline-runs/pipeline-6413fa33-a802-4b57-a8c0-a9056ad67842.jsonl +5 -0
  19. package/apps/vibe/.crew/pipeline-runs/pipeline-9bef2dd2-6122-42e5-b3d9-19f4d80f9e40.jsonl +5 -0
  20. package/apps/vibe/.crew/session.json +37 -1
  21. package/apps/vibe/.studio-data/project-messages/chuck-norris.jsonl +6 -0
  22. package/apps/vibe/.studio-data/project-messages/general.jsonl +18 -0
  23. package/apps/vibe/.studio-data/project-messages/studio-local.jsonl +8 -0
  24. package/apps/vibe/capture-full-demo.mjs +255 -0
  25. package/apps/vibe/capture-quickstart.mjs +255 -0
  26. package/apps/vibe/index.html +1 -0
  27. package/apps/vibe/server.mjs +100 -5
  28. package/apps/vibe/src/main.js +21 -0
  29. package/install.sh +53 -0
  30. package/lib/crew-lead/http-server.mjs +109 -23
  31. package/package.json +5 -2
  32. package/apps/dashboard/dist/assets/chat-core-BwSoInmZ.js.br +0 -0
  33. package/apps/dashboard/dist/assets/cli-process-COMRNPqr.js.br +0 -0
  34. package/apps/dashboard/dist/assets/components-CSUb80ze.js.br +0 -0
  35. package/apps/dashboard/dist/assets/core-utils-CAVnDoe1.js.br +0 -0
  36. package/apps/dashboard/dist/assets/index-CF0aJRtC.css.br +0 -0
  37. package/apps/dashboard/dist/assets/index-Px49zu76.js.br +0 -0
  38. package/apps/dashboard/dist/assets/orchestration-Ca2DLWN-.js.br +0 -0
  39. package/apps/dashboard/dist/assets/setup-wizard-i3eEixlo.js +0 -1
  40. package/apps/dashboard/dist/assets/setup-wizard-i3eEixlo.js.br +0 -0
  41. package/apps/dashboard/dist/assets/tab-agents-tab-BThdsdJY.js.br +0 -0
  42. package/apps/dashboard/dist/assets/tab-comms-tab-eHpOSBhG.js.br +0 -0
  43. package/apps/dashboard/dist/assets/tab-contacts-tab-yEegNyO4.js.br +0 -0
  44. package/apps/dashboard/dist/assets/tab-engines-tab-C3DYxTwy.js.br +0 -0
  45. package/apps/dashboard/dist/assets/tab-memory-tab-C59BYFQD.js.br +0 -0
  46. package/apps/dashboard/dist/assets/tab-models-tab-9Ur7pXWA.js +0 -1
  47. package/apps/dashboard/dist/assets/tab-models-tab-9Ur7pXWA.js.br +0 -0
  48. package/apps/dashboard/dist/assets/tab-pm-loop-tab-D7mnDelU.js.br +0 -0
  49. package/apps/dashboard/dist/assets/tab-projects-tab-C6h2Mv1K.js.br +0 -0
  50. package/apps/dashboard/dist/assets/tab-prompts-tab-C0wZvWK3.js.br +0 -0
  51. package/apps/dashboard/dist/assets/tab-services-tab-DBj_w3bc.js.br +0 -0
  52. package/apps/dashboard/dist/assets/tab-settings-tab-ezeqAjZk.js.br +0 -0
  53. package/apps/dashboard/dist/assets/tab-skills-tab-BYdU2whk.js.br +0 -0
  54. package/apps/dashboard/dist/assets/tab-spending-tab-Bg6w9t_p.js.br +0 -0
  55. package/apps/dashboard/dist/assets/tab-swarm-chat-tab-BBV9HB2X.js.br +0 -0
  56. package/apps/dashboard/dist/assets/tab-swarm-tab-ChqLlEVs.js.br +0 -0
  57. package/apps/dashboard/dist/assets/tab-usage-tab-B2UWXenJ.js.br +0 -0
  58. package/apps/dashboard/dist/assets/tab-waves-tab-SaJDkb4x.js.br +0 -0
  59. package/apps/dashboard/dist/assets/tab-workflows-tab-6QSXLJ0i.js.br +0 -0
  60. package/apps/dashboard/dist/index.html.br +0 -0
  61. package/apps/dashboard/dist/index.html.gz +0 -0
  62. /package/apps/dashboard/dist/assets/{tab-contacts-tab-yEegNyO4.js → tab-contacts-tab-5LHSthJM.js} +0 -0
package/.env.example CHANGED
@@ -73,12 +73,62 @@
73
73
  # Free tier: kimi-k2, qwen3, llama-3.3-70b (via Groq passthrough)
74
74
  # OPENCODE_API_KEY=
75
75
 
76
+ # ── Together AI (Fast open-source model hosting) ────────────────────────────
77
+ # Get key: https://api.together.xyz/settings/api-keys
78
+ # Models: meta-llama/Llama-3.3-70B, Qwen/Qwen2.5-Coder-32B, deepseek-ai/DeepSeek-R1
79
+ # TOGETHER_API_KEY=
80
+
81
+ # ── Fireworks AI (Fast inference, code models) ──────────────────────────────
82
+ # Get key: https://fireworks.ai/api-keys
83
+ # Models: accounts/fireworks/models/llama-v3p3-70b-instruct
84
+ # FIREWORKS_API_KEY=
85
+
86
+ # ── Hugging Face (Open-source model inference) ─────────────────────────────
87
+ # Get key: https://huggingface.co/settings/tokens
88
+ # Models: meta-llama/Llama-3.3-70B-Instruct, Qwen/Qwen2.5-Coder-32B-Instruct
89
+ # HUGGINGFACE_API_KEY=
90
+
91
+ # ── Venice AI (Privacy-focused, uncensored models) ─────────────────────────
92
+ # Get key: https://venice.ai/settings/api
93
+ # Models: llama-3.3-70b, deepseek-r1-671b
94
+ # VENICE_API_KEY=
95
+
96
+ # ── Moonshot / Kimi (Chinese market, strong coding) ────────────────────────
97
+ # Get key: https://platform.moonshot.cn/console/api-keys
98
+ # Models: moonshot-v1-128k, moonshot-v1-32k
99
+ # MOONSHOT_API_KEY=
100
+
101
+ # ── MiniMax (Chinese LLM provider) ─────────────────────────────────────────
102
+ # Get key: https://www.minimaxi.com/
103
+ # Models: abab6.5-chat, abab5.5-chat
104
+ # MINIMAX_API_KEY=
105
+
106
+ # ── Volcengine / ByteDance (Doubao models) ─────────────────────────────────
107
+ # Get key: https://console.volcengine.com/ark
108
+ # Models: doubao-pro-128k, doubao-lite-128k
109
+ # VOLCENGINE_API_KEY=
110
+
111
+ # ── Baidu Qianfan (ERNIE models) ───────────────────────────────────────────
112
+ # Get key: https://console.bce.baidu.com/qianfan/
113
+ # Models: ernie-4.0-8k, ernie-speed-128k
114
+ # QIANFAN_API_KEY=
115
+
76
116
  # ── Ollama (Local models — no API key needed) ─────────────────────────────────
77
117
  # Download: https://ollama.com/download
78
118
  # Run: ollama serve (default http://127.0.0.1:11434)
79
119
  # Models: llama3.1, qwen2.5-coder, deepseek-r1
80
120
  # OLLAMA_BASE_URL=http://127.0.0.1:11434
81
121
 
122
+ # ── vLLM (Self-hosted inference server) ─────────────────────────────────────
123
+ # Setup: pip install vllm && vllm serve meta-llama/Llama-3.3-70B-Instruct
124
+ # Default: http://localhost:8000
125
+ # VLLM_BASE_URL=http://localhost:8000
126
+
127
+ # ── SGLang (Self-hosted inference server) ───────────────────────────────────
128
+ # Setup: pip install sglang && python -m sglang.launch_server --model meta-llama/Llama-3.3-70B-Instruct
129
+ # Default: http://localhost:30000
130
+ # SGLANG_BASE_URL=http://localhost:30000
131
+
82
132
  # ── OpenAI (Local ChatGPT Plus/Pro via ChatMock) ──────────────────────────────
83
133
  # Setup: https://github.com/RayBytes/ChatMock (port 8000)
84
134
  # Use your ChatGPT Plus/Pro subscription instead of API credits
@@ -1 +1 @@
1
- import{s as e,a as t,g as n}from"./core-utils-CAVnDoe1.js";let o=!1;function a(){var n;const o=t.chatActiveProjectId;if(!o||"general"===o)return void e("Search requires an active project",!0);const a=document.getElementById("searchModal");a&&(a.style.display="flex",null==(n=document.getElementById("searchInput"))||n.focus())}function s(){const e=document.getElementById("searchModal");e&&(e.style.display="none")}async function r(){var o,a,s,r;const l=t.chatActiveProjectId;if(!l||"general"===l)return void e("Search requires an active project",!0);const c=null==(a=null==(o=document.getElementById("searchInput"))?void 0:o.value)?void 0:a.trim();if(!c)return void e("Enter a search query",!0);const d=(null==(s=document.getElementById("searchCaseSensitive"))?void 0:s.checked)||!1,u=(null==(r=document.getElementById("searchSource"))?void 0:r.value)||"",p=document.getElementById("searchResults");if(p){p.innerHTML='<div style="text-align:center;padding:20px;">Searching...</div>';try{let t=`/api/crew-lead/search-project-messages?projectId=${encodeURIComponent(l)}&q=${encodeURIComponent(c)}`;d&&(t+="&caseSensitive=true"),u&&(t+=`&source=${encodeURIComponent(u)}`);const o=await n(t);if(!o.ok)return void(p.innerHTML=`<div style="color:var(--red);padding:20px;">Error: ${i(o.error)}</div>`);if(0===o.results.length)return void(p.innerHTML='<div style="text-align:center;color:var(--text-3);padding:20px;">No results found</div>');const a={dashboard:"💻",cli:"⚡","sub-agent":"👷",agent:"🤖"};let s=`<div style="margin-bottom:12px;font-weight:600;color:var(--text-2);">${o.results.length} results</div>`;for(const e of o.results){const t=a[e.source]||"📝",n=e.agent?` [${e.agent}]`:"",o=new Date(e.ts).toLocaleString();s+=`\n <div style="border:1px solid var(--border);border-radius:6px;padding:12px;margin-bottom:8px;background:var(--bg-card2);">\n <div style="font-size:11px;color:var(--text-3);margin-bottom:6px;">\n ${t} <strong>${e.source}</strong>${n} · ${o}\n </div>\n <div style="font-size:13px;color:var(--text-1);">\n ${i(e.snippet)}\n </div>\n </div>\n `}p.innerHTML=s,e(`Found ${o.results.length} results`)}catch(g){console.error("Search failed:",g),p.innerHTML=`<div style="color:var(--red);padding:20px;">Search failed: ${i(g.message)}</div>`}}}function i(e){const t=document.createElement("div");return t.textContent=e,t.innerHTML}function l(e){const t=(n=String(e||"").replace(/\r/g,""),String(n||"").replace(/\u001b\[[\d;?]*[ -/]*[@-~]/g,"").replace(/\u001b\][^\u0007]*(?:\u0007|\u001b\\)/g,"")).trim();var n;return!t||(!!/^>\s*(build|run|eval|install|pack|starting|sync|watch|plan)\b/i.test(t)||(!!/^>\s*(build|run|eval|install|pack|starting|sync|watch|plan)\b.*\/[\w.-]+/i.test(t)||(!!/^>\s*[^\n]+[\u00B7\u2022\u22C5\u2027\u30FB‧⋅]\s*\S/u.test(t)||!!/^[─═━\-]{3,}$/.test(t))))}function c(e,t){if("opencode"!==e&&"antigravity"!==e)return String(t??"");const n=String(t??"");return n?n.split("\n").filter(e=>!l(e)).join("\n"):n}function d(e){const t=(n=String(e||"").replace(/\r/g,""),String(n||"").replace(/\u001b\[[\d;?]*[ -/]*[@-~]/g,"").replace(/\u001b\][^\u0007]*(?:\u0007|\u001b\\)/g,"")).trim();var n;return!t||(!!/^YOLO mode is enabled/i.test(t)||(!!/All tool calls will be automatically approved/i.test(t)||(!!/Loaded cached credentials/i.test(t)||(!!/^Using bundled/i.test(t)||(!!/^Authenticated via/i.test(t)||!!/^OpenTelemetry/i.test(t))))))}function u(e,t){if("gemini"!==e&&"gemini-cli"!==e)return String(t??"");const n=String(t??"");return n?n.split("\n").filter(e=>!d(e)).join("\n"):n}function p(e){return String(e||"").replace(/\r$/,"")}function g(e,t){const n=p(t);return!n.trim()||(!!/rmcp::/i.test(n)||(!!/error decoding response body.*initialized notification/i.test(n)||(!("codex"!==e||!/worker quit with fatal/i.test(n)||!/rmcp|mcp/i.test(n))||!!("codex"===e&&/\/mcp/i.test(n)&&/127\.0\.0\.1:\d+|localhost:\d+/i.test(n)&&/Connection refused|ConnectError|Transport channel closed|tcp connect error/i.test(n)))))}function m(e){return String(e||"").replace(/\u001b\[[\d;?]*[ -/]*[@-~]/g,"").replace(/\u001b\][^\u0007]*(?:\u0007|\u001b\\)/g,"")}function h(e){const t=String(e||"");let n=0;return/SecItemCopyMatching|keychain|Keychain/i.test(t)&&(n+=100),/ERROR:\s|^ERROR\s|error:\s|FATAL|fatal|panic/i.test(t)&&(n+=45),/authentication|unauthorized|\b401\b|\b403\b|not logged in/i.test(t)&&(n+=30),/ENOTFOUND|ECONNREFUSED|ECONNRESET|certificate|TLS|SSL/i.test(t)&&(n+=25),/command not found|No such file|ENOENT/i.test(t)&&(n+=20),n}function f(e,t){const n=String(e||"").split("\n"),o=[];for(const r of n){if(g(t,r))continue;const e=m(p(r)).trim();e&&o.push(e)}if(!o.length)return"";let a=o[0],s=h(a);for(const r of o){const e=h(r);e>s&&(s=e,a=r)}return 0===s&&o.length>4?`${o[0]} (${o.length} lines)`:a}function y(e){var t,n;const{postJSON:o,getJSON:a,appendChatBubble:s,showNotification:r,state:i,getChatSessionId:l,getChatActiveProjectId:d,getCrewLeadInfo:h,appendRoadmapCard:y,getLastAppendedAssistantContent:v,setLastAppendedAssistantContent:x,setLastAppendedUserContent:b,setLastSentContent:w}=e,I="crewswarm_passthrough_log";function C(){var e;const t=document.getElementById("chatProjectSelect"),n=String((null==t?void 0:t.value)||"").trim(),o=document.querySelector("#chatProjectTabs [data-project-id].active"),a=String((null==(e=null==o?void 0:o.dataset)?void 0:e.projectId)||"").trim(),s=n&&"undefined"!==n?n:a&&"undefined"!==a?a:d()||i.chatActiveProjectId||"general";i.chatActiveProjectId=s;try{localStorage.setItem("crewswarm_chat_active_project_id",s)}catch{}return s}const E=[{id:"RESET",label:"Clear session history and start fresh",template:""},{id:"STOP",label:"Cancel all running pipelines (agents keep running)",template:""},{id:"KILL",label:"Kill all pipelines + terminate all agent bridges",template:""},{id:"SEARCH_HISTORY",label:"Search long-term chat history by keyword",template:"your search terms"},{id:"DISPATCH",label:"Dispatch task to an agent",template:'{"agent":"crew-coder","task":"Your task here"}'},{id:"PIPELINE",label:"Multi-step pipeline (waves of agents)",template:'[{"wave":1,"agent":"crew-coder","task":"..."},{"wave":2,"agent":"crew-qa","task":"..."}]'},{id:"PROMPT",label:"Append or set agent system prompt",template:'{"agent":"crew-lead","append":"Your new rule here"}'},{id:"SKILL",label:"Run a skill by name",template:'skillName {"param":"value"}'},{id:"SERVICE",label:"Restart/stop a service or agent",template:"restart crew-coder"},{id:"READ_FILE",label:"Read a file and get its contents",template:"/path/to/file"},{id:"RUN_CMD",label:"Run a shell command",template:"ls -la /home/user/CrewSwarm"},{id:"WEB_SEARCH",label:"Search the web (Perplexity)",template:"your search query"},{id:"WEB_FETCH",label:"Fetch a webpage or URL",template:"https://example.com"},{id:"PROJECT",label:"Draft a new project roadmap",template:'{"name":"MyApp","description":"...","outputDir":"/path/to/dir"}'},{id:"BRAIN",label:"Append a fact to brain.md",template:"crew-lead: fact to remember"},{id:"TOOLS",label:"Grant/revoke tools for an agent",template:'{"agent":"crew-qa","allow":["read_file","write_file"]}'},{id:"CREATE_AGENT",label:"Create a dynamic agent",template:'{"id":"crew-ml","role":"coder","description":"ML specialist"}'},{id:"REMOVE_AGENT",label:"Remove a dynamic agent",template:"crew-ml"},{id:"DEFINE_SKILL",label:"Define a new skill (then @@END_SKILL)",template:'skillName\\n{"description":"...","url":"..."}'},{id:"DEFINE_WORKFLOW",label:"Save a workflow for cron",template:'name\\n[{"agent":"crew-copywriter","task":"..."}]'}];let S=0;const T=[];let L=[],k=0;async function $(e=!1){const t=Date.now();if(!e&&L.length&&t-k<3e4)return L;const n=await a("/api/agents-config");return L=(n.agents||[]).filter(e=>e.id&&"crew-lead"!==e.id).sort((e,t)=>e.id.localeCompare(t.id)),k=t,L}async function A(){var e,t;const n=++S,o=()=>n!==S,r=document.getElementById("chatMessages");r&&(r.dataset.historyLoading="true");try{const n=d(),r=n&&"undefined"!==n?n:"general";if(console.log("📚 [LOAD HISTORY] =================="),console.log("📚 [LOAD HISTORY] START - projectId:",n),console.log("📚 [LOAD HISTORY] state.chatActiveProjectId:",i.chatActiveProjectId),console.log("📚 [LOAD HISTORY] URL hash:",window.location.hash),r){console.log("📚 [LOAD HISTORY] Loading unified project messages (all sources)"),console.log("📚 [LOAD HISTORY] ProjectId:",n);try{const t=`/api/crew-lead/project-messages?projectId=${encodeURIComponent(r)}&limit=250`;console.log("📚 [LOAD HISTORY] Fetching:",t);const n=await a(t);if(o())return;console.log("📚 [LOAD HISTORY] Unified response:",{ok:n.ok,messagesCount:(null==(e=n.messages)?void 0:e.length)||0,sources:n.messages?[...new Set(n.messages.map(e=>e.source))]:[]});const i=document.getElementById("chatMessages");if(!i)return void console.error("📚 [LOAD HISTORY] ERROR: chatMessages element not found!");if(o())return;if(i.innerHTML="",i.dataset.historyLoaded="false",x(""),b(""),n.messages&&n.messages.length>0){const e={dashboard:"💻",cli:"⚡",agent:"🤖","sub-agent":"👷"};let t=new Map;try{const e=await a("/api/agents-config");t=new Map(((null==e?void 0:e.agents)||[]).map(e=>[e.id,e]))}catch{}if(o())return;const r=n.messages;console.log("📚 [LOAD HISTORY] Appending",r.length,"unified messages (chunked rAF)...");const l=32;if(await new Promise(n=>{let a=0;const i=()=>{var c,d,u,p,g,m,h,f,y,v;if(o())return void n();const w=Math.min(a+l,r.length);for(;a<w;a++){if(o())return void n();const i=r[a],l=i.agent||(null==(c=i.metadata)?void 0:c.agentId)||null,w=l?t.get(l):null,I=(null==(d=i.metadata)?void 0:d.agentEmoji)||(null==w?void 0:w.emoji)||e[i.source]||"📝",C=(null==(u=i.metadata)?void 0:u.agentName)||(null==w?void 0:w.name)||l||null,E=new Date(i.ts).toLocaleTimeString(),S={emoji:I,source:i.source,agent:C,agentName:C,agentId:l,targetAgent:(null==(p=i.metadata)?void 0:p.targetAgent)||(null==(g=i.metadata)?void 0:g.agentId)||null,engine:(null==(m=i.metadata)?void 0:m.engine)||(null==(h=i.metadata)?void 0:h.runtime)||(null==(f=i.metadata)?void 0:f.model)||null,timestamp:E};s("user"===i.role?"user":"assistant",i.content,null,null,null==(y=i.metadata)?void 0:y.model,null==(v=i.metadata)?void 0:v.engine,S),"assistant"===i.role&&x(i.content),"user"===i.role&&b(i.content)}a<r.length?requestAnimationFrame(i):n()};requestAnimationFrame(i)}),o())return;return console.log("📚 [LOAD HISTORY] ✅ Loaded unified view with all sources"),i.dataset.historyLoaded="true",void(i.scrollTop=i.scrollHeight)}return console.log("📚 [LOAD HISTORY] No messages in unified response (might be empty project)"),void(i.dataset.historyLoaded="true")}catch(l){console.error("📚 [LOAD HISTORY] ⚠️ Unified view failed:",l),console.error("📚 [LOAD HISTORY] Error details:",{message:l.message,stack:l.stack});const e=document.getElementById("chatMessages");if(e){const t=document.createElement("div");t.style.cssText="padding:12px;margin:8px;background:rgba(239,68,68,0.1);border:1px solid rgba(239,68,68,0.3);border-radius:8px;color:#ef4444;font-size:13px;",t.innerHTML="⚠️ <strong>crew-lead unavailable</strong> — Cannot load project message history.<br><small>Check that crew-lead is running: <code>node crew-lead.mjs</code></small>",e.appendChild(t)}console.log("📚 [LOAD HISTORY] Falling back to crew-lead-only history...")}}let c="/api/crew-lead/history?sessionId=owner";r&&"general"!==r&&(c+="&projectId="+encodeURIComponent(r)),console.log("📚 [LOAD HISTORY] Fetching crew-lead history:",c);const u=await a(c);if(o())return;if(console.log("📚 [LOAD HISTORY] Response:",{historyCount:(null==(t=u.history)?void 0:t.length)||0}),console.log("📚 [LOAD HISTORY] Response projectId:",u.projectId),u.history&&u.history.length>0){const e=u.history.filter(e=>"user"===e.role);e.length>0&&(console.log("📚 [LOAD HISTORY] First user msg:",e[0].content.slice(0,50)),console.log("📚 [LOAD HISTORY] Last user msg:",e[e.length-1].content.slice(0,50)))}const p=document.getElementById("chatMessages");if(!p)return void console.error("📚 [LOAD HISTORY] ERROR: chatMessages element not found!");if(o())return;if(console.log("📚 [LOAD HISTORY] Clearing chatMessages..."),p.innerHTML="",p.dataset.historyLoaded="false",x(""),b(""),u.history&&u.history.length){const e=u.history.slice(-50);console.log("📚 [LOAD HISTORY] Appending",e.length,"messages..."),e.forEach(e=>{o()||(s("user"===e.role?"user":"assistant",e.content),"assistant"===e.role&&x(e.content),"user"===e.role&&b(e.content))}),console.log("📚 [LOAD HISTORY] Appended",e.length,"messages")}else console.log("📚 [LOAD HISTORY] No history found");if(!u.history||0===u.history.length){const e=JSON.parse(localStorage.getItem(I)||"[]"),t=Date.now()-216e5,n=e.filter(e=>e.timestamp&&"number"==typeof e.timestamp&&e.timestamp>t&&e.text&&e.text.trim().length>0);n.length>0&&O(n),n.length!==e.length&&localStorage.setItem(I,JSON.stringify(n))}p.scrollTop=p.scrollHeight,p.dataset.historyLoaded="true"}catch(c){if(o())return;console.warn("Failed to load chat history:",c);const e=document.getElementById("chatMessages");e&&(e.dataset.historyLoaded="true")}finally{r&&(r.dataset.historyLoading="false"),T.splice(0).forEach(e=>{try{e()}catch{}})}}function O(e){const t=document.getElementById("chatMessages");if(!t||!e.length)return;const n={claude:"Claude Code",cursor:"Cursor CLI",opencode:"OpenCode",codex:"Codex CLI",gemini:"Gemini CLI","gemini-cli":"Gemini CLI","docker-sandbox":"Docker Sandbox","crew-cli":"Crew CLI"};for(const o of e)if("user"===o.role)s("user",o.text);else{let e=String(o.text||"").split("\n").filter(e=>!g(o.engine,e)).join("\n").trim();e=c(o.engine,e),e=u(o.engine,e);const a=document.createElement("div");a.className="chat-bubble assistant",a.style.cssText="background:var(--surface-2);border-radius:10px;padding:12px 14px;font-size:14px;line-height:1.6;white-space:pre-wrap;word-break:break-word;font-family:monospace;font-size:12px;color:var(--text-2);";const s=document.createElement("div");s.style.cssText="font-size:11px;font-weight:700;color:var(--text-3);margin-bottom:6px;";const r=o.exitCode??0;s.textContent=(n[o.engine]||o.engine)+" · direct passthrough "+(0===r?"✓":"⚠")+" (exit "+r+")";const i=document.createElement("div");i.textContent=e||o.text,a.appendChild(s),a.appendChild(i),t.appendChild(a)}}let R=null;async function M(){var e,t;const n=document.getElementById("chatInput"),a=document.querySelector('[data-action="sendChat"]'),r=n.value.trim();if(!r)return;if(R)return R.abort(),R=null,n.disabled=!1,a&&(a.disabled=!1,a.textContent="Send",a.className="btn-green"),void n.focus();const c=(null==(e=document.getElementById("passthroughEngine"))?void 0:e.value)||"",d=(null==(t=document.getElementById("chatAgentSelector"))?void 0:t.value)||"",u=document.getElementById("chatModeSelector"),p=(null==u?void 0:u.value)||"crew-lead";if(p.startsWith("cli:")){const e=p.replace("cli:","");return void(await B(r,e))}if("crew-lead"!==p)return void(await z(r,p));if(c)return void(await B(r,c));if(d)return void(await z(r,d));const g=await async function(e){const t=String(e||"").match(/^\s*@([a-zA-Z0-9_-]+)\b([\s\S]*)$/);if(!t)return null;const n=t[1];return n&&"crew-lead"!==n&&(await $()).some(e=>e.id===n)?{agentId:n,message:t[2].trim()||e.trim()}:null}(r);if(g)return void(await z(g.message,g.agentId));n.value="",a&&(a.disabled=!1,a.textContent="Send",a.className="btn-green"),s("user",r),b(r),w(r),x("");const m="typing-"+Date.now(),f=document.createElement("div");f.id=m,f.style.cssText="font-size:12px;color:var(--text-3);padding:4px 6px;";const I=h()||{emoji:"🧠",name:"crew-lead"};f.textContent=I.emoji+" "+I.name+" is thinking...";const E=document.getElementById("chatMessages");E.appendChild(f),E.scrollTop=E.scrollHeight;const S=new AbortController;try{const e=C(),t=e&&i.projectsData[e],n=await o("/api/chat/unified",{mode:"crew-lead",message:r,sessionId:l(),projectId:e||"general",...(null==t?void 0:t.outputDir)?{projectDir:t.outputDir}:{}},S.signal);if(document.querySelectorAll('[id^="typing-"]').forEach(e=>e.remove()),!1===n.ok&&n.error?(s("assistant","⚠️ "+n.error),x("")):n.reply&&(v()||(s("assistant",n.reply),x(n.reply),E&&(E.scrollTop=E.scrollHeight))),n.dispatched){const e=Array.isArray(n.dispatched)?n.dispatched.map(e=>(null==e?void 0:e.agent)||(null==e?void 0:e.id)).filter(Boolean):[n.dispatched.agent].filter(Boolean),t=document.createElement("div");t.style.cssText="font-size:11px;color:var(--text-3);text-align:center;padding:4px;",e.length&&(t.textContent="⚡ Dispatched to "+e.join(", "),E.appendChild(t))}n.pendingProject&&y(E,n.pendingProject),E.scrollTop=E.scrollHeight}catch(T){if(document.querySelectorAll('[id^="typing-"]').forEach(e=>e.remove()),"AbortError"===T.name)s("assistant","⚠️ Message cancelled"),x("");else{let e=T.message||String(T);try{const t=JSON.parse(e);t&&"string"==typeof t.error&&(e=t.error)}catch{}s("assistant","⚠️ Error: "+e),x("")}E.scrollTop=E.scrollHeight}finally{R=null,a&&(a.disabled=!1,a.textContent="Send",a.className="btn-green"),n.focus()}}function D(e,t,n,o){try{const a=JSON.parse(localStorage.getItem(I)||"[]");a.push({role:e,engine:t,text:n,exitCode:o,timestamp:Date.now()}),a.length>200&&a.splice(0,a.length-200),localStorage.setItem(I,JSON.stringify(a))}catch{}}let j=null;async function H(){var e;const t=document.getElementById("passthroughSessionIndicator");if(!t)return;const n=null==(e=document.getElementById("passthroughEngine"))?void 0:e.value;if(!n)return void(t.style.display="none");const o=C(),s=o&&i.projectsData[o],r=(null==s?void 0:s.outputDir)||null,c=l()||"owner";try{const e=(await a("/api/passthrough-sessions")).sessions||{},o=r?`${n}:${r}:${c}`:null,i=o&&(e[o]||e[`${n}:${r}`]);t.style.display=i?"inline-block":"none",t.title=i?`Session active for ${(null==s?void 0:s.name)||(null==r?void 0:r.split("/").pop())||"this project"} — click to clear`:""}catch{t.style.display="none"}}async function B(e,t){var n;const o=document.getElementById("chatInput"),a=document.querySelector('[data-action="sendChat"]'),r=document.querySelector('[data-action="stopPassthrough"]'),d=document.getElementById("passthroughModel");if(j)return j.abort(),j=null,o.disabled=!1,a&&(a.disabled=!1,a.textContent="Send",a.className="btn-green"),r&&(r.style.display="none"),void o.focus();o.value="",a&&(a.disabled=!1,a.textContent="Send",a.className="btn-green"),r&&(r.style.display="none"),s("user",e);const h=document.getElementById("chatMessages"),y=document.createElement("div");y.className="chat-bubble assistant",y.style.cssText="background:var(--surface-2);border-radius:10px;padding:12px 14px;font-size:14px;line-height:1.6;white-space:pre-wrap;word-break:break-word;font-family:monospace;font-size:12px;color:var(--text-2);";const v=document.createElement("div");v.style.cssText="font-size:11px;font-weight:700;color:var(--text-3);margin-bottom:6px;";const x=C(),b=x&&i.projectsData[x],w=(null==d?void 0:d.value)||"",I=w?` [${w}]`:"";v.textContent=({claude:"Claude Code",cursor:"Cursor CLI",opencode:"OpenCode",codex:"Codex CLI",gemini:"Gemini CLI","gemini-cli":"Gemini CLI","docker-sandbox":"Docker Sandbox","crew-cli":"Crew CLI"}[t]||t)+I+" · direct passthrough"+((null==b?void 0:b.outputDir)?" @ "+b.outputDir.split("/").pop():"");const E=document.createElement("div");y.appendChild(v),y.appendChild(E),h.appendChild(y),h.scrollTop=h.scrollHeight;const S=new AbortController,T=function(e){let t="";return{push(n){t+=String(n||"");const o=t.split("\n");t=o.pop()??"";const a=[];for(const t of o){if(g(e,t))continue;const n=m(p(t)).trimEnd();n&&a.push(n)}return a.length?`${a.join("\n")}\n`:""},flush(){const n=t;if(t="",!n)return"";if(g(e,n))return"";const o=m(p(n)).trimEnd();return o?`${o}\n`:""}}}(t);let L="",k=!1;try{const o=(null==b?void 0:b.outputDir)||void 0,a=(null==(n=document.getElementById("passthroughInjectHistory"))?void 0:n.checked)||!1,s={engine:t,message:e};o&&(s.projectDir=o),s.projectId=x||"general",s.sessionId=l(),a&&(s.injectHistory=!0),w&&(s.model=w);const r=await fetch("/api/chat/unified",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({mode:"cli",...s}),signal:S.signal});if(!r.ok)return void(E.textContent=`Error ${r.status}: ${await r.text()}`);const i=r.body.getReader(),d=new TextDecoder;let p="";for(;;){const{done:n,value:o}=await i.read();if(n)break;p+=d.decode(o,{stream:!0});const a=p.split("\n");p=a.pop()||"";for(const s of a)if(s.startsWith("data: "))try{const n=JSON.parse(s.slice(6));if("chunk"===n.type&&n.text){let e=c(t,n.text);e=u(t,e),e&&(k=!0,E.textContent+=e,h.scrollTop=h.scrollHeight)}else if("stderr"===n.type&&n.text){const e=T.push(n.text);if(e){L+=e;let n=c(t,e);n=u(t,n);n&&(!("opencode"===t||"antigravity"===t)||!k)&&(E.textContent+=n,h.scrollTop=h.scrollHeight)}}else if("done"===n.type){const o=T.flush();if(o){L+=o;let e=c(t,o);e=u(t,e);!e||("opencode"===t||"antigravity"===t)&&k||(E.textContent+=e,h.scrollTop=h.scrollHeight)}const a=n.exitCode??0,s=0===a;v.textContent+=` ${s?"✓":"⚠"} (exit ${a})`;const r=f(L,t);if(!s&&r&&!E.textContent.includes(r)){const e=document.createElement("div");e.style.cssText="font-size:11px;font-weight:600;color:var(--danger, #f87171);margin-top:8px;white-space:pre-wrap;word-break:break-word;",e.textContent=`↳ ${r}`,y.appendChild(e),h.scrollTop=h.scrollHeight}D("user",t,e,null),D("engine",t,E.textContent,a)}}catch{}}const g=T.flush();if(g){L+=g;let e=c(t,g);e=u(t,e);!e||("opencode"===t||"antigravity"===t)&&k||(E.textContent+=e,h.scrollTop=h.scrollHeight)}}catch($){"AbortError"===$.name?(v.textContent+=" ✗ (killed)",E.textContent+=E.textContent?"\n\n[stopped]":"[stopped]"):E.textContent="Error: "+$.message}finally{j=null,r&&(r.style.display="none"),a&&(a.disabled=!1,a.textContent="Send",a.className="btn-green"),o.focus(),H()}}let P=null,N=[];async function F(e,t){let n;if(e instanceof File)n=e;else{const e=document.getElementById("imageUpload");if(!e.files||!e.files[0])return;n=e.files[0],e.value=""}const a=n.name,r=n.type;(n.size/1024).toFixed(1);const i=r.startsWith("image/"),l="application/pdf"===r,c=r.includes("spreadsheet")||r.includes("excel")||a.match(/\.(xlsx?|csv)$/i),d=r.includes("document")||a.match(/\.(docx?|txt|md)$/i);let u="📎";i?u="📷":l?u="📄":c?u="📊":d&&(u="📝");const p=document.getElementById("chatInput"),g=p?p.value.trim():"",m=t||g||(i?"Describe this image in detail. What do you see?":`Analyze this ${a} file`);s("user",`${u} [Attached: ${a}] ${g?`\n\n${g}`:""}`),s("assistant",`🔍 Analyzing ${i?"image":"file"}...`);try{const e=await function(e){return new Promise((t,n)=>{const o=new FileReader;o.onload=()=>t(o.result),o.onerror=n,o.readAsDataURL(e)})}(n),t=await o("/api/analyze-image",{image:e,prompt:m,fileName:a,fileType:r});t.ok?(s("assistant",`**${i?"Image":"File"} Analysis:**\n\n${t.result}`),p&&(p.value=`[Attached: ${a}]\n\n${t.result}\n\n`,p.focus())):s("assistant",`⚠️ Analysis failed: ${t.error}`)}catch(h){s("assistant",`⚠️ Analysis error: ${h.message}`)}p&&g&&(p.value="")}async function z(e,t){const n=document.getElementById("chatInput");document.querySelector('[data-action="sendChat"]');const r=document.getElementById("chatMessages");n.value="",s("user",e),b(e),w(e);let i={emoji:"🤖",name:t,model:""};try{const e=((await a("/api/agents-config")).agents||[]).find(e=>e.id===t);e&&(i={emoji:e.emoji||"🤖",name:e.name||t,model:Y(e)})}catch(u){console.warn("Could not fetch agent info:",u)}const c="typing-"+Date.now(),d=document.createElement("div");d.id=c,d.style.cssText="font-size:12px;color:var(--text-3);padding:4px 6px;",d.textContent=`${i.emoji} ${i.name} is thinking...`,r.appendChild(d),r.scrollTop=r.scrollHeight;try{const n=C(),a=await o("/api/chat/unified",{mode:"agent",agentId:t,message:e,sessionId:`dashboard-chat-${t}-${l()}`,projectId:n||"general"});if(document.querySelectorAll('[id^="typing-"]').forEach(e=>e.remove()),a.error)return U(i,"⚠️ "+a.error,r),void x("");if(a.reply&&(U(i,a.reply,r),x(a.reply)),a.cliInvoked){const e=document.createElement("div");e.style.cssText="font-size:11px;color:var(--text-3);text-align:center;padding:4px;",e.textContent=`⚡ Executing ${a.cliInvoked}... (check process status)`,r.appendChild(e)}r.scrollTop=r.scrollHeight}catch(u){document.querySelectorAll('[id^="typing-"]').forEach(e=>e.remove()),U(i,"⚠️ Error: "+u.message,r),x("")}}function U(e,t,n){const o=document.createElement("div");o.style.cssText="display:flex;flex-direction:column;align-items:flex-start;gap:4px;";const a=document.createElement("div");if(a.style.cssText="font-size:11px;color:var(--text-3);padding:0 6px;display:flex;align-items:center;gap:6px;",a.textContent=`${e.emoji} ${e.name}`,e.model){const t=document.createElement("span");t.title="Primary model",t.style.cssText="font-size:10px;padding:1px 6px;border-radius:999px;background:rgba(52,211,153,0.1);color:#34d399;border:1px solid rgba(52,211,153,0.2);cursor:default;";const[n,...o]=e.model.split("/");t.textContent=o.join("/")||e.model,a.appendChild(t)}const s=document.createElement("div");s.style.cssText="max-width:80%;padding:10px 14px;border-radius:14px 14px 14px 4px;background:var(--surface-2);color:var(--text-2);white-space:pre-wrap;word-break:break-word;line-height:1.5;border:1px solid var(--border);",s.textContent=t,o.appendChild(a),o.appendChild(s),n.appendChild(o)}function Y(e){const{route:t,model:n}=function(e){return e.useCursorCli?{route:"cursor",model:e.cursorCliModel||"auto"}:e.useClaudeCode?{route:"claude",model:e.claudeCodeModel||"auto"}:e.useCodex?{route:"codex",model:e.codexModel||"auto"}:e.useGeminiCli?{route:"gemini",model:e.geminiCliModel||"auto"}:e.useCrewCLI?{route:"crew-cli",model:e.crewCliModel||"auto"}:!0===e.useOpenCode?{route:"opencode",model:e.opencodeModel||e.model||"default"}:{route:"llm",model:e.model||"no model"}}(e);return"llm"===t?n:`${t}:${n}`}[document.getElementById("chatInput"),document.getElementById("chatMessages")].forEach(e=>{e&&(e.addEventListener("dragover",t=>{t.preventDefault(),t.stopPropagation(),e.style.outline="2px dashed var(--accent, #3b82f6)"}),e.addEventListener("dragleave",t=>{t.preventDefault(),t.stopPropagation(),e.style.outline=""}),e.addEventListener("drop",async t=>{t.preventDefault(),t.stopPropagation(),e.style.outline="";const n=t.dataTransfer.files;if(n&&n.length>0){const e=n[0];await F(e)}}))});let q=0;async function _(e=!1){if(!e&&Date.now()-q<5e3)return;const t=document.getElementById("chatModeSelector"),n=document.getElementById("agentsOptgroup");if(t&&n)try{const e=(await a("/api/agents-config")).agents||[],t=new Set(["crew-lead","orchestrator","crew-orchestrator","crew-pm-cli","crew-pm-frontend","crew-pm-core"]);n.innerHTML="",e.filter(e=>!t.has(e.id)).sort((e,t)=>e.id.localeCompare(t.id)).forEach(e=>{const t=document.createElement("option");t.value=e.id;const o=e.emoji||"🤖",a=Y(e);t.textContent=`${o} ${e.id} — ${a}`,n.appendChild(t)}),q=Date.now()}catch(s){console.error("Failed to load agents for unified mode selector:",s)}const o=document.getElementById("chatAgentSelector");if(o)try{const e=(await a("/api/agents-config")).agents||[];o.innerHTML='<option value="">🧠 Crew Lead (default)</option>';const t=new Set(["crew-lead","orchestrator","crew-orchestrator"]);e.filter(e=>!t.has(e.id)).sort((e,t)=>e.id.localeCompare(t.id)).forEach(e=>{const t=document.createElement("option");t.value=e.id;const n=Y(e);t.textContent=`${e.id} — ${n}`,o.appendChild(t)})}catch(s){console.error("Failed to load agents for chat selector:",s)}}_(),null==(t=document.getElementById("chatModeSelector"))||t.addEventListener("focus",()=>{_(!0)});let K=null;function J(e){const t=Math.floor(e/1e3);if(t<60)return`${t}s`;const n=Math.floor(t/60);if(n<60)return`${n}m ${t%60}s`;return`${Math.floor(n/60)}h ${n%60}m`}return K&&clearInterval(K),K=setInterval(async()=>{var e;const t=document.getElementById("chatModeSelector"),n=(null==t?void 0:t.value)||"crew-lead";let o=null;if(n.startsWith("cli:")){const e=document.getElementById("chatCLIProcessStatus");return void(e&&(e.style.display="none"))}if("crew-lead"!==n&&(o=n),o||(o=null==(e=document.getElementById("chatAgentSelector"))?void 0:e.value),!o){const e=document.getElementById("chatCLIProcessStatus");return void(e&&(e.style.display="none"))}try{const e=await a(`/api/cli-processes?agent=${o}`);!function(e){const t=document.getElementById("chatCLIProcessStatus");t&&(0!==e.length?(t.style.display="block",t.innerHTML=e.map(e=>{const t=J(e.duration),n=J(e.idleFor);return`\n <div style="border-left:3px solid ${"running"===e.status?"#22c55e":"#f59e0b"};padding:8px 12px;background:var(--bg-card2);border-radius:6px;margin-bottom:8px;">\n <div style="display:flex;justify-content:space-between;margin-bottom:6px;">\n <span style="font-weight:600;font-family:monospace;font-size:13px;">${"running"===e.status?"⚡":"⏸️"} ${e.cli}</span>\n <span style="text-transform:uppercase;font-size:11px;font-weight:700;color:var(--text-3);">${e.status}</span>\n </div>\n <div style="font-size:12px;color:var(--text-2);line-height:1.5;">\n <div>Task: ${(e.task||"unknown").slice(0,80)}</div>\n <div>Duration: ${t} | Idle: ${n} | Lines: ${e.outputLines||0}</div>\n </div>\n </div>\n `}).join("")):t.style.display="none")}(e.processes||[])}catch(s){console.error("Failed to load CLI process status:",s)}},3e3),null==(n=document.getElementById("chatAgentSelector"))||n.addEventListener("change",()=>{var e;const t=null==(e=document.getElementById("chatAgentSelector"))?void 0:e.value;t&&r(`Switched to ${t} - messages go directly to this agent's LLM`,"success")}),{loadChatHistory:A,waitForChatHistoryIdle:function(){const e=document.getElementById("chatMessages");return e&&"true"===e.dataset.historyLoading?new Promise(e=>{T.push(e)}):Promise.resolve()},chatAtAtInput:function(){const e=document.getElementById("chatInput"),t=document.getElementById("chatAtAtMenu"),n=document.getElementById("chatAtAtTemplate");if(e&&t&&n)try{const o=e.value,a=e.selectionStart,s=o.slice(0,a),r=s.match(/(^|\s)@([a-zA-Z0-9_-]*)$/);if(r&&s.lastIndexOf("@@")!==s.length-r[0].length)return void $().then(s=>{const i=(r[2]||"").toLowerCase(),l=s.filter(e=>e.id.toLowerCase().includes(i)).slice(0,8);if(!l.length)return t.style.display="none",void(n.style.display="none");t.style.display="block",t.dataset.mode="mention",t.innerHTML="",l.forEach(s=>{const i=document.createElement("div");i.style.cssText="padding:8px 12px;cursor:pointer;font-size:13px;border-bottom:1px solid var(--border);",i.onmouseenter=function(){i.style.background="var(--bg-hover)"},i.onmouseleave=function(){i.style.background=""},i.innerHTML=`<span style="color:var(--accent);font-weight:600;">@${s.id}</span> <span style="color:var(--text-3);">${s.name||s.role||"agent"}</span>`,i.onclick=function(){const i=a-r[0].length+r[1].length,l=`@${s.id} `;e.value=o.slice(0,i)+l+o.slice(a),e.selectionStart=e.selectionEnd=i+l.length,e.focus(),t.style.display="none",n.style.display="block",n.textContent=`Mention target: @${s.id}`},t.appendChild(i)}),n.style.display="block",n.textContent=i?`Matching agents for @${i}`:"Type an agent name, e.g. @crew-coder"}).catch(()=>{t.style.display="none",n.style.display="none"});const i=s.lastIndexOf("@@");if(-1===i)return t.style.display="none",void(n.style.display="none");const l=s.slice(i+2);if(/\s/.test(l))return t.style.display="none",void(n.style.display="none");const c=l.toUpperCase(),d=E.filter(e=>0===e.id.indexOf(c));if(0===d.length)return t.style.display="none",void(n.style.display="none");t.style.display="block",t.style.visibility="visible",t.dataset.mode="atat",t.innerHTML="",d.forEach(s=>{const r=document.createElement("div");r.style.cssText="padding:8px 12px;cursor:pointer;font-size:13px;border-bottom:1px solid var(--border);",r.onmouseenter=function(){r.style.background="var(--bg-hover)"},r.onmouseleave=function(){r.style.background=""},r.innerHTML='<span style="color:var(--accent);font-weight:600;">@@'+s.id+'</span> <span style="color:var(--text-3);">'+s.label+"</span>",r.onclick=function(){const r="@@"+s.id+(s.template?" "+s.template:"");e.value=o.slice(0,i)+r+o.slice(a),e.selectionStart=e.selectionEnd=i+r.length,e.focus(),t.style.display="none",n.style.display="block",n.textContent=("PROMPT"===s.id?"Full line to send: @@PROMPT ":"Template: ")+(s.template?s.template:"")},t.appendChild(r)});const u=d.find(e=>e.id===c);u?(n.style.display="block",n.textContent=("PROMPT"===u.id?"Full line: @@PROMPT ":"Template: ")+(u.template||"")):n.style.display="none"}catch(o){"undefined"!=typeof console&&console.warn("chatAtAtInput",o)}},chatKeydown:function(e){const t=document.getElementById("chatAtAtMenu");if(t&&"block"===t.style.display&&("Enter"===e.key||"Tab"===e.key)){const n=t.firstElementChild;if(n)return e.preventDefault(),void n.click()}"Enter"!==e.key||e.shiftKey||(e.preventDefault(),M()),!t||"block"!==t.style.display||"Escape"!==e.key&&"Tab"!==e.key||(t.style.display="none")},sendChat:M,sendDirectAgent:z,loadChatAgentSelector:_,clearChatHistory:async function(){if(!confirm("Clear chat history for this session?"))return;const e=document.getElementById("chatMessages");e.innerHTML="",e.dataset.historyLoaded="false",localStorage.removeItem(I),await o("/api/crew-lead/clear",{sessionId:l()}).catch(()=>{}),await A()},restorePassthroughLog:function(){var e;try{const t=JSON.parse(localStorage.getItem(I)||"[]");if(!t.length)return;const n=document.getElementById("chatMessages");if(!n)return;(null==(e=document.getElementById("passthroughEngine"))?void 0:e.value)&&0===n.children.length&&(O(t),n.scrollTop=n.scrollHeight)}catch{}},sendPassthrough:B,stopAll:async function(){if(confirm("Stop all running pipelines?"))try{await o("/api/crew-lead/chat",{message:"@@STOP",sessionId:l()}),r("⏹ Stop signal sent")}catch(e){r("Failed: "+e.message,!0)}},killAll:async function(){if(confirm("Kill all agents? Bridges must be restarted after."))try{await o("/api/crew-lead/chat",{message:"@@KILL",sessionId:l()}),r("☠️ Kill signal sent")}catch(e){r("Failed: "+e.message,!0)}},killPassthrough:function(){j&&(j.abort(),j=null)},refreshSessionIndicator:H,clearPassthroughSession:async function(){var e;const t=null==(e=document.getElementById("passthroughEngine"))?void 0:e.value;if(!t)return;const n=C(),o=n&&i.projectsData[n],a=(null==o?void 0:o.outputDir)||null;if(!a)return;const s=`${t}:${a}:${l()||"owner"}`,c=`${t}:${a}`;try{await fetch(`/api/passthrough-sessions?key=${encodeURIComponent(s)}`,{method:"DELETE"}),await fetch(`/api/passthrough-sessions?key=${encodeURIComponent(c)}`,{method:"DELETE"}),r("Session cleared — next message starts fresh"),H()}catch(d){r("Failed: "+d.message,!0)}},resetSendButton:function(){const e=document.querySelector('[data-action="sendChat"]');e&&(e.textContent="Send",e.className="btn-green",e.disabled=!1)},handleImageUpload:F,toggleVoiceRecording:async function(){const e=document.getElementById("recordVoiceBtn");if(P&&"inactive"!==P.state)P.stop(),e.textContent="🎤",e.style.background="";else try{const t=await navigator.mediaDevices.getUserMedia({audio:!0});N=[],P=new MediaRecorder(t,{mimeType:"audio/webm"}),P.ondataavailable=e=>{e.data.size>0&&N.push(e.data)},P.onstop=async()=>{const e=new Blob(N,{type:"audio/webm"});t.getTracks().forEach(e=>e.stop()),s("user",`🎤 [Voice message recorded - ${(e.size/1024).toFixed(0)} KB]`),s("assistant","🎤 Transcribing voice...");try{const t=new FormData;t.append("audio",e,"voice.webm");const o=new AbortController,a=setTimeout(()=>o.abort(),6e4),r=await fetch("/api/transcribe-audio",{method:"POST",body:t,signal:o.signal});let i;clearTimeout(a);try{i=await r.json()}catch(n){return s("assistant",`⚠️ Transcription error: Server returned invalid response (${r.status})`),void(N=[])}if(i.ok&&i.transcription){s("assistant",`**Transcription:**\n\n"${i.transcription}"`);const e=document.getElementById("chatInput");e.value=i.transcription,e.focus()}else s("assistant",`⚠️ Transcription failed: ${i.error||"No result"}`)}catch(o){const e=o.message||String(o);s("assistant",`⚠️ Transcription error: ${e}${"Failed to fetch"===e?" (Is the dashboard running on port 4319? Try: npm run restart-dashboard)":""}`)}N=[]},P.start(),e.textContent="⏹️",e.style.background="var(--red, #ef4444)",r("🎤 Recording... Click again to stop")}catch(t){r("⚠️ Microphone access denied: "+t.message,!0)}}}}"undefined"!=typeof window&&(window.toggleUnifiedView=async function(){o=!o;const a=document.getElementById("unifiedViewToggle");o?(a.style.background="var(--accent)",a.style.color="#fff",a.textContent="📊 Unified ✓",e("Unified view enabled — showing all sources")):(a.style.background="",a.style.color="",a.textContent="📊 Unified View",e("Standard view restored")),await async function(){const a=t.chatActiveProjectId;if(a&&"general"!==a)if(o)try{const t=await n(`/api/crew-lead/project-messages?projectId=${encodeURIComponent(a)}&limit=100`);if(!t.ok)return console.error("Failed to load unified messages:",t.error),void e("Failed to load unified view",!0);const o=document.getElementById("chatMessages");if(!o)return;o.innerHTML="";const s={dashboard:"💻",cli:"⚡","sub-agent":"👷",agent:"🤖"};for(const e of t.messages){const t=document.createElement("div");t.className=`chat-bubble ${e.role}`;const n=s[e.source]||"📝",a=e.agent?` [${e.agent}]`:"",r=new Date(e.ts).toLocaleTimeString();t.innerHTML=`\n <div style="font-size:10px;color:var(--text-3);margin-bottom:4px;">\n ${n} <strong>${e.source}</strong>${a} · ${r}\n </div>\n <div style="white-space:pre-wrap;word-break:break-word;">${i(e.content)}</div>\n `,o.appendChild(t)}o.scrollTop=o.scrollHeight,e(`Loaded ${t.messages.length} messages from all sources`)}catch(s){console.error("Failed to load unified messages:",s),e("Failed to load unified view",!0)}else window.loadChatHistory&&await window.loadChatHistory()}()},window.openSearchModal=a,window.closeSearchModal=s,window.performSearch=r,window.exportMessages=async function(){const n=t.chatActiveProjectId;if(!n||"general"===n)return void e("Export requires an active project",!0);const o=await new Promise(e=>{const t=document.createElement("div");t.style.cssText="position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.7);z-index:10001;display:flex;align-items:center;justify-content:center;",t.innerHTML='\n <div style="background:var(--bg-card);border-radius:12px;padding:24px;max-width:400px;">\n <h3 style="margin:0 0 16px 0;">Export Format</h3>\n <div style="display:flex;flex-direction:column;gap:8px;margin-bottom:16px;">\n <button class="export-format-btn btn-ghost" data-format="markdown" style="text-align:left;padding:12px;">\n 📝 Markdown (.md) — Best for reading\n </button>\n <button class="export-format-btn btn-ghost" data-format="json" style="text-align:left;padding:12px;">\n 📋 JSON — Full data with metadata\n </button>\n <button class="export-format-btn btn-ghost" data-format="csv" style="text-align:left;padding:12px;">\n 📊 CSV — Spreadsheet compatible\n </button>\n <button class="export-format-btn btn-ghost" data-format="txt" style="text-align:left;padding:12px;">\n 📄 Plain Text (.txt)\n </button>\n </div>\n <button onclick="this.closest(\'div\').parentElement.remove()" class="btn-ghost" style="width:100%;">Cancel</button>\n </div>\n ',document.body.appendChild(t),t.querySelectorAll(".export-format-btn").forEach(n=>{n.onclick=()=>{e(n.dataset.format),t.remove()}}),t.onclick=n=>{n.target===t&&(e(null),t.remove())}});if(o)try{e("Exporting...");const t=`/api/crew-lead/export-project-messages?projectId=${encodeURIComponent(n)}&format=${o}&includeMetadata=true`,a=document.createElement("a");a.href=t,a.download=`project-${n}.${"markdown"===o?"md":o}`,document.body.appendChild(a),a.click(),document.body.removeChild(a),e(`Exported as ${o.toUpperCase()}`)}catch(a){console.error("Export failed:",a),e("Export failed: "+a.message,!0)}}),"undefined"!=typeof window&&document.addEventListener("keydown",e=>{if((e.metaKey||e.ctrlKey)&&"k"===e.key){const n=t.chatActiveProjectId;n&&"general"!==n&&(e.preventDefault(),a())}if("Escape"===e.key){const e=document.getElementById("searchModal");e&&"none"!==e.style.display&&s()}"Enter"===e.key&&"searchInput"===e.target.id&&(e.preventDefault(),r())});export{y as i};
1
+ import{s as e,a as t,g as n}from"./core-utils-CAVnDoe1.js";let o=!1;function a(){var n;const o=t.chatActiveProjectId;if(!o||"general"===o)return void e("Search requires an active project",!0);const a=document.getElementById("searchModal");a&&(a.style.display="flex",null==(n=document.getElementById("searchInput"))||n.focus())}function s(){const e=document.getElementById("searchModal");e&&(e.style.display="none")}async function r(){var o,a,s,r;const l=t.chatActiveProjectId;if(!l||"general"===l)return void e("Search requires an active project",!0);const c=null==(a=null==(o=document.getElementById("searchInput"))?void 0:o.value)?void 0:a.trim();if(!c)return void e("Enter a search query",!0);const d=(null==(s=document.getElementById("searchCaseSensitive"))?void 0:s.checked)||!1,u=(null==(r=document.getElementById("searchSource"))?void 0:r.value)||"",p=document.getElementById("searchResults");if(p){p.innerHTML='<div style="text-align:center;padding:20px;">Searching...</div>';try{let t=`/api/crew-lead/search-project-messages?projectId=${encodeURIComponent(l)}&q=${encodeURIComponent(c)}`;d&&(t+="&caseSensitive=true"),u&&(t+=`&source=${encodeURIComponent(u)}`);const o=await n(t);if(!o.ok)return void(p.innerHTML=`<div style="color:var(--red);padding:20px;">Error: ${i(o.error)}</div>`);if(0===o.results.length)return void(p.innerHTML='<div style="text-align:center;color:var(--text-3);padding:20px;">No results found</div>');const a={dashboard:"💻",cli:"⚡","sub-agent":"👷",agent:"🤖"};let s=`<div style="margin-bottom:12px;font-weight:600;color:var(--text-2);">${o.results.length} results</div>`;for(const e of o.results){const t=a[e.source]||"📝",n=e.agent?` [${e.agent}]`:"",o=new Date(e.ts).toLocaleString();s+=`\n <div style="border:1px solid var(--border);border-radius:6px;padding:12px;margin-bottom:8px;background:var(--bg-card2);">\n <div style="font-size:11px;color:var(--text-3);margin-bottom:6px;">\n ${t} <strong>${e.source}</strong>${n} · ${o}\n </div>\n <div style="font-size:13px;color:var(--text-1);">\n ${i(e.snippet)}\n </div>\n </div>\n `}p.innerHTML=s,e(`Found ${o.results.length} results`)}catch(g){console.error("Search failed:",g),p.innerHTML=`<div style="color:var(--red);padding:20px;">Search failed: ${i(g.message)}</div>`}}}function i(e){const t=document.createElement("div");return t.textContent=e,t.innerHTML}function l(e){const t=(n=String(e||"").replace(/\r/g,""),String(n||"").replace(/\u001b\[[\d;?]*[ -/]*[@-~]/g,"").replace(/\u001b\][^\u0007]*(?:\u0007|\u001b\\)/g,"")).trim();var n;return!t||(!!/^>\s*(build|run|eval|install|pack|starting|sync|watch|plan)\b/i.test(t)||(!!/^>\s*(build|run|eval|install|pack|starting|sync|watch|plan)\b.*\/[\w.-]+/i.test(t)||(!!/^>\s*[^\n]+[\u00B7\u2022\u22C5\u2027\u30FB‧⋅]\s*\S/u.test(t)||!!/^[─═━\-]{3,}$/.test(t))))}function c(e,t){if("opencode"!==e&&"antigravity"!==e)return String(t??"");const n=String(t??"");return n?n.split("\n").filter(e=>!l(e)).join("\n"):n}function d(e){const t=(n=String(e||"").replace(/\r/g,""),String(n||"").replace(/\u001b\[[\d;?]*[ -/]*[@-~]/g,"").replace(/\u001b\][^\u0007]*(?:\u0007|\u001b\\)/g,"")).trim();var n;return!t||(!!/^YOLO mode is enabled/i.test(t)||(!!/All tool calls will be automatically approved/i.test(t)||(!!/Loaded cached credentials/i.test(t)||(!!/^Using bundled/i.test(t)||(!!/^Authenticated via/i.test(t)||!!/^OpenTelemetry/i.test(t))))))}function u(e,t){if("gemini"!==e&&"gemini-cli"!==e)return String(t??"");const n=String(t??"");return n?n.split("\n").filter(e=>!d(e)).join("\n"):n}function p(e){return String(e||"").replace(/\r$/,"")}function g(e,t){const n=p(t);return!n.trim()||(!!/rmcp::/i.test(n)||(!!/error decoding response body.*initialized notification/i.test(n)||(!("codex"!==e||!/worker quit with fatal/i.test(n)||!/rmcp|mcp/i.test(n))||!!("codex"===e&&/\/mcp/i.test(n)&&/127\.0\.0\.1:\d+|localhost:\d+/i.test(n)&&/Connection refused|ConnectError|Transport channel closed|tcp connect error/i.test(n)))))}function m(e){return String(e||"").replace(/\u001b\[[\d;?]*[ -/]*[@-~]/g,"").replace(/\u001b\][^\u0007]*(?:\u0007|\u001b\\)/g,"")}function h(e){const t=String(e||"");let n=0;return/SecItemCopyMatching|keychain|Keychain/i.test(t)&&(n+=100),/ERROR:\s|^ERROR\s|error:\s|FATAL|fatal|panic/i.test(t)&&(n+=45),/authentication|unauthorized|\b401\b|\b403\b|not logged in/i.test(t)&&(n+=30),/ENOTFOUND|ECONNREFUSED|ECONNRESET|certificate|TLS|SSL/i.test(t)&&(n+=25),/command not found|No such file|ENOENT/i.test(t)&&(n+=20),n}function f(e,t){const n=String(e||"").split("\n"),o=[];for(const r of n){if(g(t,r))continue;const e=m(p(r)).trim();e&&o.push(e)}if(!o.length)return"";let a=o[0],s=h(a);for(const r of o){const e=h(r);e>s&&(s=e,a=r)}return 0===s&&o.length>4?`${o[0]} (${o.length} lines)`:a}function y(e){var t,n;const{postJSON:o,getJSON:a,appendChatBubble:s,showNotification:r,state:i,getChatSessionId:l,getChatActiveProjectId:d,getCrewLeadInfo:h,appendRoadmapCard:y,getLastAppendedAssistantContent:v,setLastAppendedAssistantContent:x,setLastAppendedUserContent:b,setLastSentContent:w}=e,I="crewswarm_passthrough_log";function C(){var e;const t=document.getElementById("chatProjectSelect"),n=String((null==t?void 0:t.value)||"").trim(),o=document.querySelector("#chatProjectTabs [data-project-id].active"),a=String((null==(e=null==o?void 0:o.dataset)?void 0:e.projectId)||"").trim(),s=n&&"undefined"!==n?n:a&&"undefined"!==a?a:d()||i.chatActiveProjectId||"general";i.chatActiveProjectId=s;try{localStorage.setItem("crewswarm_chat_active_project_id",s)}catch{}return s}const E=[{id:"RESET",label:"Clear session history and start fresh",template:""},{id:"STOP",label:"Cancel all running pipelines (agents keep running)",template:""},{id:"KILL",label:"Kill all pipelines + terminate all agent bridges",template:""},{id:"SEARCH_HISTORY",label:"Search long-term chat history by keyword",template:"your search terms"},{id:"DISPATCH",label:"Dispatch task to an agent",template:'{"agent":"crew-coder","task":"Your task here"}'},{id:"PIPELINE",label:"Multi-step pipeline (waves of agents)",template:'[{"wave":1,"agent":"crew-coder","task":"..."},{"wave":2,"agent":"crew-qa","task":"..."}]'},{id:"PROMPT",label:"Append or set agent system prompt",template:'{"agent":"crew-lead","append":"Your new rule here"}'},{id:"SKILL",label:"Run a skill by name",template:'skillName {"param":"value"}'},{id:"SERVICE",label:"Restart/stop a service or agent",template:"restart crew-coder"},{id:"READ_FILE",label:"Read a file and get its contents",template:"/path/to/file"},{id:"RUN_CMD",label:"Run a shell command",template:"ls -la /home/user/CrewSwarm"},{id:"WEB_SEARCH",label:"Search the web (Perplexity)",template:"your search query"},{id:"WEB_FETCH",label:"Fetch a webpage or URL",template:"https://example.com"},{id:"PROJECT",label:"Draft a new project roadmap",template:'{"name":"MyApp","description":"...","outputDir":"/path/to/dir"}'},{id:"BRAIN",label:"Append a fact to brain.md",template:"crew-lead: fact to remember"},{id:"TOOLS",label:"Grant/revoke tools for an agent",template:'{"agent":"crew-qa","allow":["read_file","write_file"]}'},{id:"CREATE_AGENT",label:"Create a dynamic agent",template:'{"id":"crew-ml","role":"coder","description":"ML specialist"}'},{id:"REMOVE_AGENT",label:"Remove a dynamic agent",template:"crew-ml"},{id:"DEFINE_SKILL",label:"Define a new skill (then @@END_SKILL)",template:'skillName\\n{"description":"...","url":"..."}'},{id:"DEFINE_WORKFLOW",label:"Save a workflow for cron",template:'name\\n[{"agent":"crew-copywriter","task":"..."}]'}];let S=0;const T=[];let L=[],k=0;async function $(e=!1){const t=Date.now();if(!e&&L.length&&t-k<3e4)return L;const n=await a("/api/agents-config");return L=(n.agents||[]).filter(e=>e.id&&"crew-lead"!==e.id).sort((e,t)=>e.id.localeCompare(t.id)),k=t,L}async function A(){var e,t;const n=++S,o=()=>n!==S,r=document.getElementById("chatMessages");r&&(r.dataset.historyLoading="true");try{const n=d(),r=n&&"undefined"!==n?n:"general";if(console.log("📚 [LOAD HISTORY] =================="),console.log("📚 [LOAD HISTORY] START - projectId:",n),console.log("📚 [LOAD HISTORY] state.chatActiveProjectId:",i.chatActiveProjectId),console.log("📚 [LOAD HISTORY] URL hash:",window.location.hash),r){console.log("📚 [LOAD HISTORY] Loading unified project messages (all sources)"),console.log("📚 [LOAD HISTORY] ProjectId:",n);try{const t=`/api/crew-lead/project-messages?projectId=${encodeURIComponent(r)}&limit=250`;console.log("📚 [LOAD HISTORY] Fetching:",t);const n=await a(t);if(o())return;console.log("📚 [LOAD HISTORY] Unified response:",{ok:n.ok,messagesCount:(null==(e=n.messages)?void 0:e.length)||0,sources:n.messages?[...new Set(n.messages.map(e=>e.source))]:[]});const i=document.getElementById("chatMessages");if(!i)return void console.error("📚 [LOAD HISTORY] ERROR: chatMessages element not found!");if(o())return;if(i.innerHTML="",i.dataset.historyLoaded="false",x(""),b(""),n.messages&&n.messages.length>0){const e={dashboard:"💻",cli:"⚡",agent:"🤖","sub-agent":"👷"};let t=new Map;try{const e=await a("/api/agents-config");t=new Map(((null==e?void 0:e.agents)||[]).map(e=>[e.id,e]))}catch{}if(o())return;const r=n.messages;console.log("📚 [LOAD HISTORY] Appending",r.length,"unified messages (chunked rAF)...");const l=32;if(await new Promise(n=>{let a=0;const i=()=>{var c,d,u,p,g,m,h,f,y,v;if(o())return void n();const w=Math.min(a+l,r.length);for(;a<w;a++){if(o())return void n();const i=r[a],l=i.agent||(null==(c=i.metadata)?void 0:c.agentId)||null,w=l?t.get(l):null,I=(null==(d=i.metadata)?void 0:d.agentEmoji)||(null==w?void 0:w.emoji)||e[i.source]||"📝",C=(null==(u=i.metadata)?void 0:u.agentName)||(null==w?void 0:w.name)||l||null,E=new Date(i.ts).toLocaleTimeString(),S={emoji:I,source:i.source,agent:C,agentName:C,agentId:l,targetAgent:(null==(p=i.metadata)?void 0:p.targetAgent)||(null==(g=i.metadata)?void 0:g.agentId)||null,engine:(null==(m=i.metadata)?void 0:m.engine)||(null==(h=i.metadata)?void 0:h.runtime)||(null==(f=i.metadata)?void 0:f.model)||null,timestamp:E};s("user"===i.role?"user":"assistant",i.content,null,null,null==(y=i.metadata)?void 0:y.model,null==(v=i.metadata)?void 0:v.engine,S),"assistant"===i.role&&x(i.content),"user"===i.role&&b(i.content)}a<r.length?requestAnimationFrame(i):n()};requestAnimationFrame(i)}),o())return;return console.log("📚 [LOAD HISTORY] ✅ Loaded unified view with all sources"),i.dataset.historyLoaded="true",void(i.scrollTop=i.scrollHeight)}return console.log("📚 [LOAD HISTORY] No messages in unified response (might be empty project)"),void(i.dataset.historyLoaded="true")}catch(l){console.error("📚 [LOAD HISTORY] ⚠️ Unified view failed:",l),console.error("📚 [LOAD HISTORY] Error details:",{message:l.message,stack:l.stack});const e=document.getElementById("chatMessages");if(e){const t=document.createElement("div");t.style.cssText="padding:12px;margin:8px;background:rgba(239,68,68,0.1);border:1px solid rgba(239,68,68,0.3);border-radius:8px;color:#ef4444;font-size:13px;",t.innerHTML="⚠️ <strong>crew-lead unavailable</strong> — Cannot load project message history.<br><small>Check that crew-lead is running: <code>node crew-lead.mjs</code></small>",e.appendChild(t)}console.log("📚 [LOAD HISTORY] Falling back to crew-lead-only history...")}}let c="/api/crew-lead/history?sessionId=owner";r&&"general"!==r&&(c+="&projectId="+encodeURIComponent(r)),console.log("📚 [LOAD HISTORY] Fetching crew-lead history:",c);const u=await a(c);if(o())return;if(console.log("📚 [LOAD HISTORY] Response:",{historyCount:(null==(t=u.history)?void 0:t.length)||0}),console.log("📚 [LOAD HISTORY] Response projectId:",u.projectId),u.history&&u.history.length>0){const e=u.history.filter(e=>"user"===e.role);e.length>0&&(console.log("📚 [LOAD HISTORY] First user msg:",e[0].content.slice(0,50)),console.log("📚 [LOAD HISTORY] Last user msg:",e[e.length-1].content.slice(0,50)))}const p=document.getElementById("chatMessages");if(!p)return void console.error("📚 [LOAD HISTORY] ERROR: chatMessages element not found!");if(o())return;if(console.log("📚 [LOAD HISTORY] Clearing chatMessages..."),p.innerHTML="",p.dataset.historyLoaded="false",x(""),b(""),u.history&&u.history.length){const e=u.history.slice(-50);console.log("📚 [LOAD HISTORY] Appending",e.length,"messages..."),e.forEach(e=>{o()||(s("user"===e.role?"user":"assistant",e.content),"assistant"===e.role&&x(e.content),"user"===e.role&&b(e.content))}),console.log("📚 [LOAD HISTORY] Appended",e.length,"messages")}else console.log("📚 [LOAD HISTORY] No history found");if(!u.history||0===u.history.length){const e=JSON.parse(localStorage.getItem(I)||"[]"),t=Date.now()-216e5,n=e.filter(e=>e.timestamp&&"number"==typeof e.timestamp&&e.timestamp>t&&e.text&&e.text.trim().length>0);n.length>0&&O(n),n.length!==e.length&&localStorage.setItem(I,JSON.stringify(n))}p.scrollTop=p.scrollHeight,p.dataset.historyLoaded="true"}catch(c){if(o())return;console.warn("Failed to load chat history:",c);const e=document.getElementById("chatMessages");e&&(e.dataset.historyLoaded="true")}finally{r&&(r.dataset.historyLoading="false"),T.splice(0).forEach(e=>{try{e()}catch{}})}}function O(e){const t=document.getElementById("chatMessages");if(!t||!e.length)return;const n={claude:"Claude Code",cursor:"Cursor CLI",opencode:"OpenCode",codex:"Codex CLI",gemini:"Gemini CLI","gemini-cli":"Gemini CLI","docker-sandbox":"Docker Sandbox","crew-cli":"Crew CLI"};for(const o of e)if("user"===o.role)s("user",o.text);else{let e=String(o.text||"").split("\n").filter(e=>!g(o.engine,e)).join("\n").trim();e=c(o.engine,e),e=u(o.engine,e);const a=document.createElement("div");a.className="chat-bubble assistant",a.style.cssText="background:var(--surface-2);border-radius:10px;padding:12px 14px;font-size:14px;line-height:1.6;white-space:pre-wrap;word-break:break-word;font-family:monospace;font-size:12px;color:var(--text-2);";const s=document.createElement("div");s.style.cssText="font-size:11px;font-weight:700;color:var(--text-3);margin-bottom:6px;";const r=o.exitCode??0;s.textContent=(n[o.engine]||o.engine)+" · direct passthrough "+(0===r?"✓":"⚠")+" (exit "+r+")";const i=document.createElement("div");i.textContent=e||o.text,a.appendChild(s),a.appendChild(i),t.appendChild(a)}}let R=null;async function M(){var e,t;const n=document.getElementById("chatInput"),a=document.querySelector('[data-action="sendChat"]'),r=n.value.trim();if(!r)return;if(R)return R.abort(),R=null,n.disabled=!1,a&&(a.disabled=!1,a.textContent="Send",a.className="btn-green"),void n.focus();const c=(null==(e=document.getElementById("passthroughEngine"))?void 0:e.value)||"",d=(null==(t=document.getElementById("chatAgentSelector"))?void 0:t.value)||"",u=document.getElementById("chatModeSelector"),p=(null==u?void 0:u.value)||"crew-lead";if(p.startsWith("cli:")){const e=p.replace("cli:","");return void(await B(r,e))}if("crew-lead"!==p)return void(await z(r,p));if(c)return void(await B(r,c));if(d)return void(await z(r,d));const g=await async function(e){const t=String(e||"").match(/^\s*@([a-zA-Z0-9_-]+)\b([\s\S]*)$/);if(!t)return null;const n=t[1];return n&&"crew-lead"!==n&&(await $()).some(e=>e.id===n)?{agentId:n,message:t[2].trim()||e.trim()}:null}(r);if(g)return void(await z(g.message,g.agentId));n.value="",a&&(a.disabled=!1,a.textContent="Send",a.className="btn-green"),s("user",r),b(r),w(r),x("");const m="typing-"+Date.now(),f=document.createElement("div");f.id=m,f.style.cssText="font-size:12px;color:var(--text-3);padding:4px 6px;";const I=h()||{emoji:"🧠",name:"crew-lead"};f.textContent=I.emoji+" "+I.name+" is thinking...";const E=document.getElementById("chatMessages");E.appendChild(f),E.scrollTop=E.scrollHeight;const S=new AbortController;try{const e=C(),t=e&&i.projectsData[e],n=await o("/api/chat/unified",{mode:"crew-lead",message:r,sessionId:l(),projectId:e||"general",...(null==t?void 0:t.outputDir)?{projectDir:t.outputDir}:{}},S.signal);if(document.querySelectorAll('[id^="typing-"]').forEach(e=>e.remove()),!1===n.ok&&n.error?(s("assistant","⚠️ "+n.error),x("")):n.reply&&(v()||(s("assistant",n.reply),x(n.reply),E&&(E.scrollTop=E.scrollHeight))),n.dispatched){const e=Array.isArray(n.dispatched)?n.dispatched.map(e=>(null==e?void 0:e.agent)||(null==e?void 0:e.id)).filter(Boolean):[n.dispatched.agent].filter(Boolean),t=document.createElement("div");t.style.cssText="font-size:11px;color:var(--text-3);text-align:center;padding:4px;",e.length&&(t.textContent="⚡ Dispatched to "+e.join(", "),E.appendChild(t))}n.pendingProject&&y(E,n.pendingProject),E.scrollTop=E.scrollHeight}catch(T){if(document.querySelectorAll('[id^="typing-"]').forEach(e=>e.remove()),"AbortError"===T.name)s("assistant","⚠️ Message cancelled"),x("");else{let e=T.message||String(T);try{const t=JSON.parse(e);t&&"string"==typeof t.error&&(e=t.error)}catch{}s("assistant","⚠️ Error: "+e),x("")}E.scrollTop=E.scrollHeight}finally{R=null,a&&(a.disabled=!1,a.textContent="Send",a.className="btn-green"),n.focus()}}function D(e,t,n,o){try{const a=JSON.parse(localStorage.getItem(I)||"[]");a.push({role:e,engine:t,text:n,exitCode:o,timestamp:Date.now()}),a.length>200&&a.splice(0,a.length-200),localStorage.setItem(I,JSON.stringify(a))}catch{}}let j=null;async function H(){var e;const t=document.getElementById("passthroughSessionIndicator");if(!t)return;const n=null==(e=document.getElementById("passthroughEngine"))?void 0:e.value;if(!n)return void(t.style.display="none");const o=C(),s=o&&i.projectsData[o],r=(null==s?void 0:s.outputDir)||null,c=l()||"owner";try{const e=(await a("/api/passthrough-sessions")).sessions||{},o=r?`${n}:${r}:${c}`:null,i=o&&(e[o]||e[`${n}:${r}`]);t.style.display=i?"inline-block":"none",t.title=i?`Session active for ${(null==s?void 0:s.name)||(null==r?void 0:r.split("/").pop())||"this project"} — click to clear`:""}catch{t.style.display="none"}}async function B(e,t){var n;const o=document.getElementById("chatInput"),a=document.querySelector('[data-action="sendChat"]'),r=document.querySelector('[data-action="stopPassthrough"]'),d=document.getElementById("passthroughModel");if(j)return j.abort(),j=null,o.disabled=!1,a&&(a.disabled=!1,a.textContent="Send",a.className="btn-green"),r&&(r.style.display="none"),void o.focus();o.value="",a&&(a.disabled=!1,a.textContent="Send",a.className="btn-green"),r&&(r.style.display="none"),s("user",e);const h=document.getElementById("chatMessages"),y=document.createElement("div");y.className="chat-bubble assistant",y.style.cssText="background:var(--surface-2);border-radius:10px;padding:12px 14px;font-size:14px;line-height:1.6;white-space:pre-wrap;word-break:break-word;font-family:monospace;font-size:12px;color:var(--text-2);";const v=document.createElement("div");v.style.cssText="font-size:11px;font-weight:700;color:var(--text-3);margin-bottom:6px;";const x=C(),b=x&&i.projectsData[x],w=(null==d?void 0:d.value)||"",I=w?` [${w}]`:"";v.textContent=({claude:"Claude Code",cursor:"Cursor CLI",opencode:"OpenCode",codex:"Codex CLI",gemini:"Gemini CLI","gemini-cli":"Gemini CLI","docker-sandbox":"Docker Sandbox","crew-cli":"Crew CLI"}[t]||t)+I+" · direct passthrough"+((null==b?void 0:b.outputDir)?" @ "+b.outputDir.split("/").pop():"");const E=document.createElement("div");y.appendChild(v),y.appendChild(E),h.appendChild(y),h.scrollTop=h.scrollHeight;const S=new AbortController,T=function(e){let t="";return{push(n){t+=String(n||"");const o=t.split("\n");t=o.pop()??"";const a=[];for(const t of o){if(g(e,t))continue;const n=m(p(t)).trimEnd();n&&a.push(n)}return a.length?`${a.join("\n")}\n`:""},flush(){const n=t;if(t="",!n)return"";if(g(e,n))return"";const o=m(p(n)).trimEnd();return o?`${o}\n`:""}}}(t);let L="",k=!1;try{const o=(null==b?void 0:b.outputDir)||void 0,a=(null==(n=document.getElementById("passthroughInjectHistory"))?void 0:n.checked)||!1,s={engine:t,message:e};o&&(s.projectDir=o),s.projectId=x||"general",s.sessionId=l(),a&&(s.injectHistory=!0),w&&(s.model=w);const r=await fetch("/api/chat/unified",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({mode:"cli",...s}),signal:S.signal});if(!r.ok)return void(E.textContent=`Error ${r.status}: ${await r.text()}`);const i=r.body.getReader(),d=new TextDecoder;let p="";for(;;){const{done:n,value:o}=await i.read();if(n)break;p+=d.decode(o,{stream:!0});const a=p.split("\n");p=a.pop()||"";for(const s of a)if(s.startsWith("data: "))try{const n=JSON.parse(s.slice(6));if("chunk"===n.type&&n.text){let e=c(t,n.text);e=u(t,e),e&&(k=!0,E.textContent+=e,h.scrollTop=h.scrollHeight)}else if("stderr"===n.type&&n.text){const e=T.push(n.text);if(e){L+=e;let n=c(t,e);n=u(t,n);n&&(!("opencode"===t||"antigravity"===t)||!k)&&(E.textContent+=n,h.scrollTop=h.scrollHeight)}}else if("done"===n.type){const o=T.flush();if(o){L+=o;let e=c(t,o);e=u(t,e);!e||("opencode"===t||"antigravity"===t)&&k||(E.textContent+=e,h.scrollTop=h.scrollHeight)}const a=n.exitCode??0,s=0===a;v.textContent+=` ${s?"✓":"⚠"} (exit ${a})`;const r=f(L,t);if(!s&&r&&!E.textContent.includes(r)){const e=document.createElement("div");e.style.cssText="font-size:11px;font-weight:600;color:var(--danger, #f87171);margin-top:8px;white-space:pre-wrap;word-break:break-word;",e.textContent=`↳ ${r}`,y.appendChild(e),h.scrollTop=h.scrollHeight}D("user",t,e,null),D("engine",t,E.textContent,a)}}catch{}}const g=T.flush();if(g){L+=g;let e=c(t,g);e=u(t,e);!e||("opencode"===t||"antigravity"===t)&&k||(E.textContent+=e,h.scrollTop=h.scrollHeight)}}catch($){"AbortError"===$.name?(v.textContent+=" ✗ (killed)",E.textContent+=E.textContent?"\n\n[stopped]":"[stopped]"):E.textContent="Error: "+$.message}finally{j=null,r&&(r.style.display="none"),a&&(a.disabled=!1,a.textContent="Send",a.className="btn-green"),o.focus(),H()}}let P=null,N=[];async function F(e,t){let n;if(e instanceof File)n=e;else{const e=document.getElementById("imageUpload");if(!e.files||!e.files[0])return;n=e.files[0],e.value=""}const a=n.name,r=n.type;(n.size/1024).toFixed(1);const i=r.startsWith("image/"),l="application/pdf"===r,c=r.includes("spreadsheet")||r.includes("excel")||a.match(/\.(xlsx?|csv)$/i),d=r.includes("document")||a.match(/\.(docx?|txt|md)$/i);let u="📎";i?u="📷":l?u="📄":c?u="📊":d&&(u="📝");const p=document.getElementById("chatInput"),g=p?p.value.trim():"",m=t||g||(i?"Describe this image in detail. What do you see?":`Analyze this ${a} file`);s("user",`${u} [Attached: ${a}] ${g?`\n\n${g}`:""}`),s("assistant",`🔍 Analyzing ${i?"image":"file"}...`);try{const e=await function(e){return new Promise((t,n)=>{const o=new FileReader;o.onload=()=>t(o.result),o.onerror=n,o.readAsDataURL(e)})}(n),t=await o("/api/analyze-image",{image:e,prompt:m,fileName:a,fileType:r});t.ok?(s("assistant",`**${i?"Image":"File"} Analysis:**\n\n${t.result}`),p&&(p.value=`[Attached: ${a}]\n\n${t.result}\n\n`,p.focus())):s("assistant",`⚠️ Analysis failed: ${t.error}`)}catch(h){s("assistant",`⚠️ Analysis error: ${h.message}`)}p&&g&&(p.value="")}async function z(e,t){const n=document.getElementById("chatInput");document.querySelector('[data-action="sendChat"]');const r=document.getElementById("chatMessages");n.value="",s("user",e),b(e),w(e);let i={emoji:"🤖",name:t,model:""};try{const e=((await a("/api/agents-config")).agents||[]).find(e=>e.id===t);e&&(i={emoji:e.emoji||"🤖",name:e.name||t,model:U(e)})}catch(u){console.warn("Could not fetch agent info:",u)}const c="typing-"+Date.now(),d=document.createElement("div");d.id=c,d.style.cssText="font-size:12px;color:var(--text-3);padding:4px 6px;",d.textContent=`${i.emoji} ${i.name} is thinking...`,r.appendChild(d),r.scrollTop=r.scrollHeight;try{const n=C(),a=await o("/api/chat/unified",{mode:"agent",agentId:t,message:e,sessionId:`dashboard-chat-${t}-${l()}`,projectId:n||"general"});if(document.querySelectorAll('[id^="typing-"]').forEach(e=>e.remove()),a.error)return Y(i,"⚠️ "+a.error,r),void x("");if(a.reply&&(Y(i,a.reply,r),x(a.reply)),a.cliInvoked){const e=document.createElement("div");e.style.cssText="font-size:11px;color:var(--text-3);text-align:center;padding:4px;",e.textContent=`⚡ Executing ${a.cliInvoked}... (check process status)`,r.appendChild(e)}r.scrollTop=r.scrollHeight}catch(u){document.querySelectorAll('[id^="typing-"]').forEach(e=>e.remove()),Y(i,"⚠️ Error: "+u.message,r),x("")}}function Y(e,t,n){const o=document.createElement("div");o.style.cssText="display:flex;flex-direction:column;align-items:flex-start;gap:4px;";const a=document.createElement("div");if(a.style.cssText="font-size:11px;color:var(--text-3);padding:0 6px;display:flex;align-items:center;gap:6px;",a.textContent=`${e.emoji} ${e.name}`,e.model){const t=document.createElement("span");t.title="Primary model",t.style.cssText="font-size:10px;padding:1px 6px;border-radius:999px;background:rgba(52,211,153,0.1);color:#34d399;border:1px solid rgba(52,211,153,0.2);cursor:default;";const[n,...o]=e.model.split("/");t.textContent=o.join("/")||e.model,a.appendChild(t)}const s=document.createElement("div");s.style.cssText="max-width:80%;padding:10px 14px;border-radius:14px 14px 14px 4px;background:var(--surface-2);color:var(--text-2);white-space:pre-wrap;word-break:break-word;line-height:1.5;border:1px solid var(--border);",s.textContent=t,o.appendChild(a),o.appendChild(s),n.appendChild(o)}function U(e){const{route:t,model:n}=function(e){return e.useCursorCli?{route:"cursor",model:e.cursorCliModel||"auto"}:e.useClaudeCode?{route:"claude",model:e.claudeCodeModel||"auto"}:e.useCodex?{route:"codex",model:e.codexModel||"auto"}:e.useGeminiCli?{route:"gemini",model:e.geminiCliModel||"auto"}:e.useCrewCLI?{route:"crew-cli",model:e.crewCliModel||"auto"}:!0===e.useOpenCode?{route:"opencode",model:e.opencodeModel||e.model||"default"}:{route:"llm",model:e.model||"no model"}}(e);return"llm"===t?n:`${t}:${n}`}[document.getElementById("chatInput"),document.getElementById("chatMessages")].forEach(e=>{e&&(e.addEventListener("dragover",t=>{t.preventDefault(),t.stopPropagation(),e.style.outline="2px dashed var(--accent, #3b82f6)"}),e.addEventListener("dragleave",t=>{t.preventDefault(),t.stopPropagation(),e.style.outline=""}),e.addEventListener("drop",async t=>{t.preventDefault(),t.stopPropagation(),e.style.outline="";const n=t.dataTransfer.files;if(n&&n.length>0){const e=n[0];await F(e)}}))});let q=0;async function _(e=!1){if(!e&&Date.now()-q<5e3)return;const t=document.getElementById("chatModeSelector"),n=document.getElementById("agentsOptgroup");if(t&&n)try{const e=(await a("/api/agents-config")).agents||[],t=new Set(["crew-lead","orchestrator","crew-orchestrator","crew-pm-cli","crew-pm-frontend","crew-pm-core"]);n.innerHTML="",e.filter(e=>!t.has(e.id)).sort((e,t)=>e.id.localeCompare(t.id)).forEach(e=>{const t=document.createElement("option");t.value=e.id;const o=e.emoji||"🤖",a=U(e);t.textContent=`${o} ${e.id} — ${a}`,n.appendChild(t)}),q=Date.now()}catch(s){console.error("Failed to load agents for unified mode selector:",s)}const o=document.getElementById("chatAgentSelector");if(o)try{const e=(await a("/api/agents-config")).agents||[];o.innerHTML='<option value="">🧠 Crew Lead (default)</option>';const t=new Set(["crew-lead","orchestrator","crew-orchestrator"]);e.filter(e=>!t.has(e.id)).sort((e,t)=>e.id.localeCompare(t.id)).forEach(e=>{const t=document.createElement("option");t.value=e.id;const n=U(e);t.textContent=`${e.id} — ${n}`,o.appendChild(t)})}catch(s){console.error("Failed to load agents for chat selector:",s)}}_(),null==(t=document.getElementById("chatModeSelector"))||t.addEventListener("focus",()=>{_(!0)});let K=null;function J(e){const t=Math.floor(e/1e3);if(t<60)return`${t}s`;const n=Math.floor(t/60);if(n<60)return`${n}m ${t%60}s`;return`${Math.floor(n/60)}h ${n%60}m`}return K&&clearInterval(K),K=setInterval(async()=>{var e;const t=document.getElementById("chatModeSelector"),n=(null==t?void 0:t.value)||"crew-lead";let o=null;if(n.startsWith("cli:")){const e=document.getElementById("chatCLIProcessStatus");return void(e&&(e.style.display="none"))}if("crew-lead"!==n&&(o=n),o||(o=null==(e=document.getElementById("chatAgentSelector"))?void 0:e.value),!o){const e=document.getElementById("chatCLIProcessStatus");return void(e&&(e.style.display="none"))}try{const e=await a(`/api/cli-processes?agent=${o}`);!function(e){const t=document.getElementById("chatCLIProcessStatus");t&&(0!==e.length?(t.style.display="block",t.innerHTML=e.map(e=>{const t=J(e.duration),n=J(e.idleFor);return`\n <div style="border-left:3px solid ${"running"===e.status?"#22c55e":"#f59e0b"};padding:8px 12px;background:var(--bg-card2);border-radius:6px;margin-bottom:8px;">\n <div style="display:flex;justify-content:space-between;margin-bottom:6px;">\n <span style="font-weight:600;font-family:monospace;font-size:13px;">${"running"===e.status?"⚡":"⏸️"} ${e.cli}</span>\n <span style="text-transform:uppercase;font-size:11px;font-weight:700;color:var(--text-3);">${e.status}</span>\n </div>\n <div style="font-size:12px;color:var(--text-2);line-height:1.5;">\n <div>Task: ${(e.task||"unknown").slice(0,80)}</div>\n <div>Duration: ${t} | Idle: ${n} | Lines: ${e.outputLines||0}</div>\n </div>\n </div>\n `}).join("")):t.style.display="none")}(e.processes||[])}catch(s){console.error("Failed to load CLI process status:",s)}},3e3),null==(n=document.getElementById("chatAgentSelector"))||n.addEventListener("change",()=>{var e;const t=null==(e=document.getElementById("chatAgentSelector"))?void 0:e.value;t&&r(`Switched to ${t} - messages go directly to this agent's LLM`,"success")}),{loadChatHistory:A,waitForChatHistoryIdle:function(){const e=document.getElementById("chatMessages");return e&&"true"===e.dataset.historyLoading?new Promise(e=>{T.push(e)}):Promise.resolve()},chatAtAtInput:function(){const e=document.getElementById("chatInput"),t=document.getElementById("chatAtAtMenu"),n=document.getElementById("chatAtAtTemplate");if(e&&t&&n)try{const o=e.value,a=e.selectionStart,s=o.slice(0,a),r=s.match(/(^|\s)@([a-zA-Z0-9_-]*)$/);if(r&&s.lastIndexOf("@@")!==s.length-r[0].length)return void $().then(s=>{const i=(r[2]||"").toLowerCase(),l=s.filter(e=>e.id.toLowerCase().includes(i)).slice(0,8);if(!l.length)return t.style.display="none",void(n.style.display="none");t.style.display="block",t.dataset.mode="mention",t.innerHTML="",l.forEach(s=>{const i=document.createElement("div");i.style.cssText="padding:8px 12px;cursor:pointer;font-size:13px;border-bottom:1px solid var(--border);",i.onmouseenter=function(){i.style.background="var(--bg-hover)"},i.onmouseleave=function(){i.style.background=""},i.innerHTML=`<span style="color:var(--accent);font-weight:600;">@${s.id}</span> <span style="color:var(--text-3);">${s.name||s.role||"agent"}</span>`,i.onclick=function(){const i=a-r[0].length+r[1].length,l=`@${s.id} `;e.value=o.slice(0,i)+l+o.slice(a),e.selectionStart=e.selectionEnd=i+l.length,e.focus(),t.style.display="none",n.style.display="block",n.textContent=`Mention target: @${s.id}`},t.appendChild(i)}),n.style.display="block",n.textContent=i?`Matching agents for @${i}`:"Type an agent name, e.g. @crew-coder"}).catch(()=>{t.style.display="none",n.style.display="none"});const i=s.lastIndexOf("@@");if(-1===i)return t.style.display="none",void(n.style.display="none");const l=s.slice(i+2);if(/\s/.test(l))return t.style.display="none",void(n.style.display="none");const c=l.toUpperCase(),d=E.filter(e=>0===e.id.indexOf(c));if(0===d.length)return t.style.display="none",void(n.style.display="none");t.style.display="block",t.style.visibility="visible",t.dataset.mode="atat",t.innerHTML="",d.forEach(s=>{const r=document.createElement("div");r.style.cssText="padding:8px 12px;cursor:pointer;font-size:13px;border-bottom:1px solid var(--border);",r.onmouseenter=function(){r.style.background="var(--bg-hover)"},r.onmouseleave=function(){r.style.background=""},r.innerHTML='<span style="color:var(--accent);font-weight:600;">@@'+s.id+'</span> <span style="color:var(--text-3);">'+s.label+"</span>",r.onclick=function(){const r="@@"+s.id+(s.template?" "+s.template:"");e.value=o.slice(0,i)+r+o.slice(a),e.selectionStart=e.selectionEnd=i+r.length,e.focus(),t.style.display="none",n.style.display="block",n.textContent=("PROMPT"===s.id?"Full line to send: @@PROMPT ":"Template: ")+(s.template?s.template:"")},t.appendChild(r)});const u=d.find(e=>e.id===c);u?(n.style.display="block",n.textContent=("PROMPT"===u.id?"Full line: @@PROMPT ":"Template: ")+(u.template||"")):n.style.display="none"}catch(o){"undefined"!=typeof console&&console.warn("chatAtAtInput",o)}},chatKeydown:function(e){const t=document.getElementById("chatAtAtMenu");if(t&&"block"===t.style.display&&("Enter"===e.key||"Tab"===e.key)){const n=t.firstElementChild;if(n)return e.preventDefault(),void n.click()}"Enter"!==e.key||e.shiftKey||(e.preventDefault(),M()),!t||"block"!==t.style.display||"Escape"!==e.key&&"Tab"!==e.key||(t.style.display="none")},sendChat:M,sendDirectAgent:z,loadChatAgentSelector:_,clearChatHistory:async function(){if(!confirm("Clear chat history for this session?"))return;const e=document.getElementById("chatMessages");e.innerHTML="",e.dataset.historyLoaded="false",localStorage.removeItem(I),await o("/api/crew-lead/clear",{sessionId:l()}).catch(()=>{}),await A()},restorePassthroughLog:function(){var e;try{const t=JSON.parse(localStorage.getItem(I)||"[]");if(!t.length)return;const n=document.getElementById("chatMessages");if(!n)return;(null==(e=document.getElementById("passthroughEngine"))?void 0:e.value)&&0===n.children.length&&(O(t),n.scrollTop=n.scrollHeight)}catch{}},sendPassthrough:B,stopAll:async function(){if(confirm("Stop all running pipelines?"))try{await o("/api/crew-lead/chat",{message:"@@STOP",sessionId:l()}),r("⏹ Stop signal sent")}catch(e){r("Failed: "+e.message,!0)}},killAll:async function(){if(confirm("Kill all agents? Bridges must be restarted after."))try{await o("/api/crew-lead/chat",{message:"@@KILL",sessionId:l()}),r("☠️ Kill signal sent")}catch(e){r("Failed: "+e.message,!0)}},killPassthrough:function(){j&&(j.abort(),j=null)},refreshSessionIndicator:H,clearPassthroughSession:async function(){var e;const t=null==(e=document.getElementById("passthroughEngine"))?void 0:e.value;if(!t)return;const n=C(),o=n&&i.projectsData[n],a=(null==o?void 0:o.outputDir)||null;if(!a)return;const s=`${t}:${a}:${l()||"owner"}`,c=`${t}:${a}`;try{await fetch(`/api/passthrough-sessions?key=${encodeURIComponent(s)}`,{method:"DELETE"}),await fetch(`/api/passthrough-sessions?key=${encodeURIComponent(c)}`,{method:"DELETE"}),r("Session cleared — next message starts fresh"),H()}catch(d){r("Failed: "+d.message,!0)}},resetSendButton:function(){const e=document.querySelector('[data-action="sendChat"]');e&&(e.textContent="Send",e.className="btn-green",e.disabled=!1)},handleImageUpload:F,toggleVoiceRecording:async function(){const e=document.getElementById("recordVoiceBtn");if(P&&"inactive"!==P.state)P.stop(),e.textContent="🎤",e.style.background="";else try{const t=await navigator.mediaDevices.getUserMedia({audio:!0});N=[],P=new MediaRecorder(t,{mimeType:"audio/webm"}),P.ondataavailable=e=>{e.data.size>0&&N.push(e.data)},P.onstop=async()=>{const e=new Blob(N,{type:"audio/webm"});t.getTracks().forEach(e=>e.stop()),s("user",`🎤 [Voice message recorded - ${(e.size/1024).toFixed(0)} KB]`),s("assistant","🎤 Transcribing voice...");try{const t=new FormData;t.append("audio",e,"voice.webm");const o=new AbortController,a=setTimeout(()=>o.abort(),6e4),r=await fetch("/api/transcribe-audio",{method:"POST",body:t,signal:o.signal});let i;clearTimeout(a);try{i=await r.json()}catch(n){return s("assistant",`⚠️ Transcription error: Server returned invalid response (${r.status})`),void(N=[])}if(i.ok&&i.transcription){s("assistant",`**Transcription:**\n\n"${i.transcription}"`);const e=document.getElementById("chatInput");e.value=i.transcription,e.focus()}else s("assistant",`⚠️ Transcription failed: ${i.error||"No result"}`)}catch(o){const e=o.message||String(o);s("assistant",`⚠️ Transcription error: ${e}${"Failed to fetch"===e?" (Is the dashboard running on port 4319? Try: npm run restart-dashboard)":""}`)}N=[]},P.start(),e.textContent="⏹️",e.style.background="var(--red, #ef4444)",r("🎤 Recording... Click again to stop")}catch(t){r("⚠️ Microphone access denied: "+t.message,!0)}}}}"undefined"!=typeof window&&(window.toggleUnifiedView=async function(){o=!o;const a=document.getElementById("unifiedViewToggle");o?(a.style.background="var(--accent)",a.style.color="#fff",a.textContent="📊 Unified ✓",e("Unified view enabled — showing all sources")):(a.style.background="",a.style.color="",a.textContent="📊 Unified View",e("Standard view restored")),await async function(){const a=t.chatActiveProjectId;if(a&&"general"!==a)if(o)try{const t=await n(`/api/crew-lead/project-messages?projectId=${encodeURIComponent(a)}&limit=100`);if(!t.ok)return console.error("Failed to load unified messages:",t.error),void e("Failed to load unified view",!0);const o=document.getElementById("chatMessages");if(!o)return;o.innerHTML="";const s={dashboard:"💻",cli:"⚡","sub-agent":"👷",agent:"🤖"};for(const e of t.messages){const t=document.createElement("div");t.className=`chat-bubble ${e.role}`;const n=s[e.source]||"📝",a=e.agent?` [${e.agent}]`:"",r=new Date(e.ts).toLocaleTimeString();t.innerHTML=`\n <div style="font-size:10px;color:var(--text-3);margin-bottom:4px;">\n ${n} <strong>${e.source}</strong>${a} · ${r}\n </div>\n <div style="white-space:pre-wrap;word-break:break-word;">${i(e.content)}</div>\n `,o.appendChild(t)}o.scrollTop=o.scrollHeight,e(`Loaded ${t.messages.length} messages from all sources`)}catch(s){console.error("Failed to load unified messages:",s),e("Failed to load unified view",!0)}else window.loadChatHistory&&await window.loadChatHistory()}()},window.openSearchModal=a,window.closeSearchModal=s,window.performSearch=r,window.exportMessages=async function(){const n=t.chatActiveProjectId;if(!n||"general"===n)return void e("Export requires an active project",!0);const o=await new Promise(e=>{const t=document.createElement("div");t.style.cssText="position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.7);z-index:10001;display:flex;align-items:center;justify-content:center;",t.innerHTML='\n <div style="background:var(--bg-card);border-radius:12px;padding:24px;max-width:400px;">\n <h3 style="margin:0 0 16px 0;">Export Format</h3>\n <div style="display:flex;flex-direction:column;gap:8px;margin-bottom:16px;">\n <button class="export-format-btn btn-ghost" data-format="markdown" style="text-align:left;padding:12px;">\n 📝 Markdown (.md) — Best for reading\n </button>\n <button class="export-format-btn btn-ghost" data-format="json" style="text-align:left;padding:12px;">\n 📋 JSON — Full data with metadata\n </button>\n <button class="export-format-btn btn-ghost" data-format="csv" style="text-align:left;padding:12px;">\n 📊 CSV — Spreadsheet compatible\n </button>\n <button class="export-format-btn btn-ghost" data-format="txt" style="text-align:left;padding:12px;">\n 📄 Plain Text (.txt)\n </button>\n </div>\n <button onclick="this.closest(\'div\').parentElement.remove()" class="btn-ghost" style="width:100%;">Cancel</button>\n </div>\n ',document.body.appendChild(t),t.querySelectorAll(".export-format-btn").forEach(n=>{n.onclick=()=>{e(n.dataset.format),t.remove()}}),t.onclick=n=>{n.target===t&&(e(null),t.remove())}});if(o)try{e("Exporting...");const t=`/api/crew-lead/export-project-messages?projectId=${encodeURIComponent(n)}&format=${o}&includeMetadata=true`,a=document.createElement("a");a.href=t,a.download=`project-${n}.${"markdown"===o?"md":o}`,document.body.appendChild(a),a.click(),document.body.removeChild(a),e(`Exported as ${o.toUpperCase()}`)}catch(a){console.error("Export failed:",a),e("Export failed: "+a.message,!0)}}),"undefined"!=typeof window&&document.addEventListener("keydown",e=>{if((e.metaKey||e.ctrlKey)&&"k"===e.key){const n=t.chatActiveProjectId;n&&"general"!==n&&(e.preventDefault(),a())}if("Escape"===e.key){const e=document.getElementById("searchModal");e&&"none"!==e.style.display&&s()}"Enter"===e.key&&"searchInput"===e.target.id&&(e.preventDefault(),r())});export{y as i};