@runfusion/fusion 0.18.1 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/dist/bin.js +6533 -2558
  2. package/dist/client/assets/AgentDetailView-C6BG7O7i.js +18 -0
  3. package/dist/client/assets/AgentDetailView-CUtWvXBn.css +1 -0
  4. package/dist/client/assets/ChatView-DeXUYwSY.js +1 -0
  5. package/dist/client/assets/{DevServerView-r6V3FqkY.js → DevServerView-Dariyxt_.js} +1 -1
  6. package/dist/client/assets/{DirectoryPicker-CTZE95Fk.js → DirectoryPicker-SchiK-Aq.js} +1 -1
  7. package/dist/client/assets/{DocumentsView-DSEf1Lmg.js → DocumentsView-C6v-tBhG.js} +1 -1
  8. package/dist/client/assets/InsightsView-AWo5o_81.css +1 -0
  9. package/dist/client/assets/InsightsView-Cqim12az.js +11 -0
  10. package/dist/client/assets/{MemoryView-DicXjec9.js → MemoryView-CakLoJtY.js} +2 -2
  11. package/dist/client/assets/NodesView-BxGm3poT.js +14 -0
  12. package/dist/client/assets/{NodesView-sJgPLTzz.css → NodesView-fXqDk9ur.css} +1 -1
  13. package/dist/client/assets/PiExtensionsManager-lJbmskyZ.js +6 -0
  14. package/dist/client/assets/PluginManager-BZjNNf9m.js +1 -0
  15. package/dist/client/assets/ResearchView-Bzsr9V0y.js +1 -0
  16. package/dist/client/assets/{RoadmapsView-DfEF3mql.js → RoadmapsView-CeKks_OI.js} +2 -2
  17. package/dist/client/assets/SettingsModal-BWe0KrGY.css +1 -0
  18. package/dist/client/assets/SettingsModal-D-9CLguN.js +31 -0
  19. package/dist/client/assets/{SettingsModal-YcScdFiG.js → SettingsModal-YdeVPhRJ.js} +1 -1
  20. package/dist/client/assets/{SetupWizardModal-DRF5fOoR.css → SetupWizardModal-CGYGKurR.css} +1 -1
  21. package/dist/client/assets/SetupWizardModal-DAC04LlA.js +1 -0
  22. package/dist/client/assets/{SkillsView-Dkq2CQla.js → SkillsView-CClC_5RN.js} +1 -1
  23. package/dist/client/assets/index-CrHLf3pB.js +1222 -0
  24. package/dist/client/assets/index-Df1bHDY4.css +1 -0
  25. package/dist/client/assets/star-DxVRh9VT.js +6 -0
  26. package/dist/client/assets/{users-Cp5TSxVm.js → users-3SD3oNMQ.js} +1 -1
  27. package/dist/client/index.html +2 -2
  28. package/dist/client/version.json +1 -1
  29. package/dist/droid-cli/index.ts +3 -5
  30. package/dist/droid-cli/package.json +1 -1
  31. package/dist/droid-cli/src/__tests__/event-bridge.test.ts +6 -1315
  32. package/dist/droid-cli/src/__tests__/provider.test.ts +6 -1927
  33. package/dist/droid-cli/src/control-handler.ts +1 -82
  34. package/dist/droid-cli/src/event-bridge.ts +1 -397
  35. package/dist/droid-cli/src/mcp-config.ts +1 -144
  36. package/dist/droid-cli/src/process-manager.ts +1 -358
  37. package/dist/droid-cli/src/prompt-builder.ts +1 -629
  38. package/dist/droid-cli/src/provider.ts +1 -447
  39. package/dist/droid-cli/src/stream-parser.ts +1 -37
  40. package/dist/droid-cli/src/thinking-config.ts +1 -83
  41. package/dist/droid-cli/src/tool-mapping.ts +1 -147
  42. package/dist/droid-cli/src/types.ts +1 -87
  43. package/dist/extension.js +4674 -1748
  44. package/dist/pi-claude-cli/package.json +1 -1
  45. package/dist/plugins/fusion-plugin-dependency-graph/package.json +1 -1
  46. package/package.json +5 -4
  47. package/skill/fusion/references/engine-tools.md +5 -1
  48. package/skill/fusion/references/extension-tools.md +3 -1
  49. package/dist/client/assets/ChatView-3Sqm6teN.js +0 -1
  50. package/dist/client/assets/InsightsView-4KiUKzbz.css +0 -1
  51. package/dist/client/assets/InsightsView-F5PZsX5u.js +0 -11
  52. package/dist/client/assets/NodesView-DddCS7zB.js +0 -14
  53. package/dist/client/assets/PiExtensionsManager-Ch7si-v8.js +0 -11
  54. package/dist/client/assets/PluginManager-LcTh_fHP.js +0 -1
  55. package/dist/client/assets/ResearchView-D0TY1VcX.js +0 -1
  56. package/dist/client/assets/SettingsModal-SOADcCNJ.js +0 -31
  57. package/dist/client/assets/SettingsModal-oOnIed5O.css +0 -1
  58. package/dist/client/assets/SetupWizardModal-EDYuf9Yc.js +0 -1
  59. package/dist/client/assets/index-4hC8zoTD.css +0 -1
  60. package/dist/client/assets/index-DNzA4aZ7.js +0 -1229
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fusion/pi-claude-cli",
3
- "version": "0.18.1",
3
+ "version": "0.20.0",
4
4
  "description": "Fusion vendored fork: pi coding-agent extension that routes LLM calls through the Claude Code CLI. Forked from rchern/pi-claude-cli (MIT). See UPSTREAM.md.",
5
5
  "license": "MIT",
6
6
  "private": true,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fusion-plugin-examples/dependency-graph",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "type": "module",
5
5
  "description": "Dependency graph dashboard view plugin for Fusion",
6
6
  "private": true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@runfusion/fusion",
3
- "version": "0.18.1",
3
+ "version": "0.20.0",
4
4
  "license": "MIT",
5
5
  "description": "Fusion CLI: HTTP API server, daemon, dashboard launcher, and task tooling for the Fusion AI coding agent.",
6
6
  "homepage": "https://github.com/Runfusion/Fusion#readme",
@@ -40,8 +40,8 @@
40
40
  "README.md"
41
41
  ],
42
42
  "dependencies": {
43
- "@mariozechner/pi-ai": "^0.72.1",
44
- "@mariozechner/pi-coding-agent": "^0.72.1",
43
+ "@mariozechner/pi-ai": "^0.73.0",
44
+ "@mariozechner/pi-coding-agent": "^0.73.0",
45
45
  "dockerode": "^4.0.12",
46
46
  "express": "^5.1.0",
47
47
  "ink": "^6.8.0",
@@ -78,7 +78,8 @@
78
78
  "typebox": "^1.0.0",
79
79
  "typescript": "^5.7.0",
80
80
  "vitest": "^3.1.0",
81
- "yaml": "^2.8.3"
81
+ "yaml": "^2.8.3",
82
+ "@fusion/pi-llama-cpp": "0.17.2"
82
83
  },
83
84
  "repository": {
84
85
  "type": "git",
@@ -21,9 +21,13 @@ These tools are **not** part of the user-invokable extension surface. They are i
21
21
  | `fn_research_list` | triage, executor | List recent research runs with status/summary metadata | `status?` (`pending` \| `running` \| `completed` \| `failed` \| `cancelled`), `limit?` (number) |
22
22
  | `fn_research_get` | triage, executor | Read one research run's structured findings/citations payload | `id` (string) |
23
23
  | `fn_research_cancel` | triage, executor | Cancel an active research run via orchestrator cancellation path | `id` (string) |
24
- | `fn_reflect_on_performance` | executor | Generate reflection insights from prior runs | `focus_area?` (string) |
24
+ | `fn_read_evaluations` | heartbeat | Read the current agent's rating summaries, recent comments, and reflections | none |
25
+ | `fn_update_identity` | heartbeat | Update the current agent's own `soul`, `instructionsText`, or `memory` fields | `soul?` (string), `instructionsText?` (string), `memory?` (string) |
26
+ | `fn_reflect_on_performance` | executor, heartbeat (when reflection service enabled) | Generate reflection insights from prior runs | `focus_area?` (string) |
25
27
  | `fn_list_agents` | triage, executor, heartbeat | List agents (optionally filtered) | `role?` (string), `state?` (string), `includeEphemeral?` (boolean) |
26
28
  | `fn_delegate_task` | triage, executor, heartbeat | Create and assign a new task to a specific agent | `agent_id` (string), `description` (string), `dependencies?` (string[]) |
29
+ | `fn_get_agent_config` | executor, heartbeat | Read full config for a direct-report agent | `agent_id` (string) |
30
+ | `fn_update_agent_config` | executor, heartbeat | Update config fields for a direct-report, non-ephemeral agent | `agent_id` (string), optional: `soul`, `instructions_text`, `instructions_path`, `heartbeat_procedure_path`, `heartbeat_interval_ms`, `heartbeat_timeout_ms`, `max_concurrent_runs`, `message_response_mode` |
27
31
  | `fn_send_message` | executor, heartbeat | Send inbox messages to agents/users | `to_id` (string), `content` (string), `type?` (`agent-to-agent` \| `agent-to-user`), `reply_to_message_id?` (string) |
28
32
  | `fn_read_messages` | executor, heartbeat | Read inbox messages | `unread_only?` (boolean), `limit?` (number) |
29
33
 
@@ -370,6 +370,8 @@ Start a bounded research run and optionally wait for findings.
370
370
  | Parameter | Type | Required | Description |
371
371
  |-----------|------|----------|-------------|
372
372
  | `query` | string | ✓ | Research query or question |
373
+ | `wait_for_completion` | boolean | — | Wait for the run to complete before returning (default: false) |
374
+ | `max_wait_ms` | number | — | Max wait time when wait_for_completion=true (default: 90000, capped by settings) |
373
375
 
374
376
  ### fn_research_list
375
377
 
@@ -377,7 +379,7 @@ List recent research runs.
377
379
 
378
380
  | Parameter | Type | Required | Description |
379
381
  |-----------|------|----------|-------------|
380
- | `status` | string(enum) | — | |
382
+ | `status` | string(enum) | — | Filter by run status |
381
383
  | `limit` | number | — | Max runs to return (default: 10) |
382
384
 
383
385
  ### fn_research_get
@@ -1 +0,0 @@
1
- import{r as s,j as t}from"./vendor-react-K0fH_qHe.js";import{ah as et,ai as Wt,aj as Bt,ak as Gt,al as qt,am as Vt,an as Kt,ao as Xt,ap as Jt,aq as Yt,ar as Qt,w as Zt,as as es,at as ts,au as ss,I as ns,av as as,M as pt,r as xt,S as is,a4 as ot,P as Qe,q as rs,aw as ls,ax as He,E as vt,d as wt,ay as os,az as cs,aA as ds,a2 as us,aB as hs,aC as ms,aD as ct,aE as fs,aF as gs,aG as dt,aH as ps}from"./index-DNzA4aZ7.js";import"./vendor-xterm-DzcZoU0P.js";const Ze="kb-chat-active-session";function xs(a){const i=typeof a=="string"?a.trim():"",r=i.indexOf("/");return!i||r<=0||r>=i.length-1?{}:{modelProvider:i.slice(0,r),modelId:i.slice(r+1)}}function vs(a){const i=a?.toolCalls;if(!Array.isArray(i))return;const r=i.map(c=>{if(!c||typeof c!="object")return null;const l=c,w=typeof l.toolName=="string"?l.toolName:"";if(!w)return null;const N=l.args;return{toolName:w,...N&&typeof N=="object"?{args:N}:{},isError:!!l.isError,result:l.result,status:"completed"}}).filter(c=>c!==null);return r.length>0?r:void 0}function ws(a){const i=a?.fallback;if(!i||typeof i!="object")return;const r=i,c=typeof r.primaryModel=="string"?r.primaryModel:"",l=typeof r.fallbackModel=="string"?r.fallbackModel:"",w=r.triggerPoint;if(!(!c||!l||w!=="session-creation"&&w!=="prompt-time"))return{primaryModel:c,fallbackModel:l,triggerPoint:w}}function ut(a){return{id:a.id,sessionId:a.sessionId,role:a.role,content:a.content,thinkingOutput:a.thinkingOutput,toolCalls:vs(a.metadata),fallbackInfo:ws(a.metadata),attachments:a.attachments,createdAt:a.createdAt}}function bs(a,i){const[r,c]=s.useState([]),[l,w]=s.useState(null),[N,$]=s.useState(!0),[_,b]=s.useState([]),[G,k]=s.useState(!1),[F,y]=s.useState(!1),[z,u]=s.useState(""),[C,S]=s.useState(""),[I,D]=s.useState([]),[O,Q]=s.useState(""),[U,H]=s.useState(""),[X,m]=s.useState(!0),[j,ce]=s.useState(new Map),p=s.useRef(null),se=s.useRef(!1),J=s.useRef(""),Y=s.useRef(null),Ce=s.useRef(r),Z=s.useRef(l),Me=s.useRef(F);Ce.current=r,Z.current=l,Me.current=F,s.useEffect(()=>{J.current=O},[O]);const pe=s.useRef(new Set),de=s.useRef(0),$e=s.useRef(a);$e.current!==a&&($e.current=a,de.current++),s.useEffect(()=>{const h=de.current;et(void 0,a).then(x=>{if(de.current!==h)return;const f=new Map;for(const R of x)f.set(R.id,R);ce(f)}).catch(()=>{})},[a]);const ue=s.useCallback(async()=>{$(!0);try{const x=[...(await Wt(a)).sessions].sort((f,R)=>new Date(R.updatedAt).getTime()-new Date(f.updatedAt).getTime());c(x)}catch{}finally{$(!1)}},[a]);s.useEffect(()=>{ue()},[ue]);const re=s.useRef(()=>{});s.useEffect(()=>{if(N)return;const h=Bt(Ze,a);h&&r.find(f=>f.id===h)&&re.current(h)},[N,r,a]);const ee=s.useCallback(async(h,x)=>{k(!0);try{const f=await Gt(h,{limit:50,...x},a),R=f.messages.map(ut);x?.offset&&x.offset>0?b(L=>[...R,...L]):b(R),m(f.messages.length>=50)}catch{}finally{k(!1)}},[a]),he=s.useCallback(()=>{Y.current?.(),Y.current=null,J.current="",Q(""),u(""),S(""),D([]),y(!1)},[]),le=s.useCallback((h,x)=>{p.current&&(p.current.close(),p.current=null);const f=x??r.find(R=>R.id===h);w(f||null),he(),m(!0),h?ee(h):b([]),f?.isGenerating&&(y(!0),u("")),h?qt(Ze,h,a):Vt(Ze,a)},[r,ee,a,he]);re.current=le;const be=s.useCallback(async h=>{const x=await Kt(h,a);p.current&&(p.current.close(),p.current=null);const f={id:x.session.id,title:x.session.title,agentId:x.session.agentId,status:x.session.status,modelProvider:x.session.modelProvider,modelId:x.session.modelId,createdAt:x.session.createdAt,updatedAt:x.session.updatedAt};return c(R=>R.some(L=>L.id===f.id)?R:[f,...R]),he(),le(f.id,f),b([]),f},[a,he,le]),xe=s.useCallback(async h=>{await Xt(h,{status:"archived"},a),c(x=>x.filter(f=>f.id!==h)),l?.id===h&&(w(null),b([]))},[l,a]),Se=s.useCallback(async h=>{l?.id===h&&p.current&&(p.current.close(),p.current=null),await Jt(h,a),c(x=>x.filter(f=>f.id!==h)),l?.id===h&&(w(null),b([]))},[l,a]),me=s.useCallback(async()=>{!l||!X||await ee(l.id,{offset:_.length})},[l,X,ee,_.length]),ne=s.useCallback(()=>{l&&(se.current=!0,Y.current?.(),Y.current=null,p.current?.close(),p.current=null,Yt(l.id,a).catch(()=>{}),y(!1),u(""),S(""),D([]))},[l,a]),fe=s.useCallback(()=>{J.current="",Q("")},[]),ve=s.useCallback((h,x)=>{if(!l)return;if(F){J.current=h,Q(h);return}se.current=!1,p.current&&(p.current.close(),p.current=null);const f=`temp-${Date.now()}`,R={id:f,sessionId:l.id,role:"user",content:h,createdAt:new Date().toISOString()};b(g=>[...g,R]),u(""),S(""),D([]),y(!0);let L="",oe="",V=[],ge,K=null,P=null;const E=()=>{K=null,u(L)},d=()=>{P=null,S(oe)},M=()=>{K!==null&&(cancelAnimationFrame(K),K=null),P!==null&&(cancelAnimationFrame(P),P=null)};Y.current=M;const ae={onThinking:g=>{oe+=g,P===null&&(P=requestAnimationFrame(d))},onText:g=>{L+=g,K===null&&(K=requestAnimationFrame(E))},onToolStart:g=>{V=[...V,{toolName:g.toolName,args:g.args,isError:!1,status:"running"}],D(V)},onToolEnd:g=>{const T=[...V];for(let v=T.length-1;v>=0;v--){const q=T[v];if(q?.toolName===g.toolName&&q.status==="running"){T[v]={...q,status:"completed",isError:g.isError,result:g.result},V=T,D(T);return}}V=[...T,{toolName:g.toolName,isError:g.isError,result:g.result,status:"completed"}],D(V)},onFallback:g=>{ge=g;const T=xs(g.fallbackModel);c(v=>v.map(q=>q.id===l.id?{...q,...T}:q)),w(v=>v&&v.id===l.id?{...v,...T}:v),i?.(`Primary model unavailable. Switched to fallback ${g.fallbackModel}.`,"warning")},onDone:g=>{M();const T={id:g.messageId||`msg-${Date.now()}`,sessionId:l.id,role:"assistant",content:L,thinkingOutput:oe,toolCalls:V.length>0?V:void 0,fallbackInfo:ge,createdAt:new Date().toISOString()};pe.current.add(T.id),b(q=>[...q,T]),u(""),S(""),D([]),y(!1),p.current=null,setTimeout(()=>{pe.current.delete(T.id)},1e3),ue();const v=J.current.trim();v&&(J.current="",Q(""),ve(v))},onError:g=>{if(M(),b(T=>T.filter(v=>v.id!==f)),u(""),S(""),D([]),y(!1),p.current=null,console.error("[useChat] Stream error:",g),i?.(typeof g=="string"&&g.trim()?g:"Failed to get response","error"),!se.current){const T=J.current.trim();T&&(J.current="",Q(""),ve(T))}}};p.current=Qt(l.id,h,ae,x,a)},[l,F,a,ue,i]),ke=U?r.filter(h=>h.title?.toLowerCase().includes(U.toLowerCase())||h.agentId.toLowerCase().includes(U.toLowerCase())):r;return s.useEffect(()=>{const h=de.current,x=a?`?projectId=${encodeURIComponent(a)}`:"",f=()=>de.current!==h,R=P=>{if(f())return;const E=JSON.parse(P.data);c(d=>d.some(M=>M.id===E.id)?d:[E,...d])},L=P=>{if(f())return;const E=JSON.parse(P.data);c(d=>[...d.map(ae=>ae.id===E.id?E:ae)]),Z.current?.id===E.id&&w(E)},oe=P=>{if(f())return;const{id:E}=JSON.parse(P.data);c(d=>d.filter(M=>M.id!==E)),Z.current?.id===E&&(w(null),b([]))},V=P=>{if(f())return;const E=JSON.parse(P.data),d=ut(E);if(!pe.current.has(d.id)){if(Z.current?.id===d.sessionId&&Me.current&&!p.current&&d.role==="assistant"){b(M=>M.some(ae=>ae.id===d.id)?M:[...M,d]),u(""),S(""),D([]),y(!1);return}Z.current?.id===d.sessionId&&!Me.current&&b(M=>M.some(ae=>ae.id===d.id)?M:[...M,d])}},ge=P=>{if(f())return;const{id:E}=JSON.parse(P.data);b(d=>d.filter(M=>M.id!==E))};return Zt(`/api/events${x}`,{events:{"chat:session:created":R,"chat:session:updated":L,"chat:session:deleted":oe,"chat:message:added":V,"chat:message:deleted":ge}})},[a]),s.useEffect(()=>()=>{p.current&&(p.current.close(),p.current=null)},[]),{sessions:r,activeSession:l,sessionsLoading:N,messages:_,messagesLoading:G,isStreaming:F,streamingText:z,streamingThinking:C,streamingToolCalls:I,pendingMessage:O,selectSession:le,createSession:be,archiveSession:xe,deleteSession:Se,sendMessage:ve,stopStreaming:ne,clearPendingMessage:fe,loadMoreMessages:me,hasMoreMessages:X,searchQuery:U,setSearchQuery:H,filteredSessions:ke,refreshSessions:ue,agentsMap:j}}function bt(a){const i=new Date(a),c=new Date().getTime()-i.getTime(),l=Math.floor(c/1e3),w=Math.floor(l/60),N=Math.floor(w/60),$=Math.floor(N/24);return l<60?"just now":w<60?`${w}m ago`:N<24?`${N}h ago`:$<7?`${$}d ago`:i.toLocaleDateString()}function ht(a,i){if(!a||!i)return null;const r=i.toLowerCase();if(r.includes("claude")){let l=i.replace(/^claude[- ]/i,"Claude ").replace(/sonnet[- ](\d+)[- ](\d+)/i,"Sonnet $1.$2").replace(/sonnet[- ](\d+)/i,"Sonnet $1").replace(/haiku[- ](\d+)/i,"Haiku $1").replace(/opus[- ](\d+)/i,"Opus $1").replace(/sonnet/i,"Sonnet").replace(/haiku/i,"Haiku").replace(/opus/i,"Opus").replace(/-/g," ").trim();return l=l.replace(/\s+/g," "),l.length>30?l.slice(0,30)+"…":l}if(r.includes("gpt")||r.includes("openai")){const l=i.replace(/^gpt-4-turbo$/i,"GPT-4 Turbo").replace(/^gpt-4o-mini$/i,"GPT-4o Mini").replace(/^gpt-4o$/i,"GPT-4o").replace(/^gpt-4$/i,"GPT-4").replace(/^gpt-o1-preview$/i,"GPT-o1 Preview").replace(/^gpt-o1-mini$/i,"GPT-o1 Mini").replace(/^gpt-o1$/i,"GPT-o1").replace(/^gpt/i,"GPT").trim();return l.length>30?l.slice(0,30)+"…":l}if(r.includes("gemini")){const l=i.replace(/^gemini[- ]/i,"Gemini ").replace(/pro[- ](\d+)[- ](\d+)/i,"Pro $1.$2").replace(/pro[- ](\d+)/i,"Pro $1").replace(/-/g," ").replace(/\s+/g," ").trim();return l.length>30?l.slice(0,30)+"…":l}const c=i.replace(/-/g," ").replace(/^\w/,l=>l.toUpperCase()).replace(/\s+/g," ").trim();return c.length>30?c.slice(0,30)+"…":c}function Oe(a,i){return a.length<=i?a:`${a.slice(0,i)}…`}function Ss(a){if(!a)return null;const i=Object.entries(a);return i.length===0?null:i.map(([r,c])=>{const l=typeof c=="string"?c:(()=>{try{return JSON.stringify(c)}catch{return String(c)}})();return`${r}=${Oe(l,50)}`}).join(", ")}function ks(a){if(a===void 0)return null;if(typeof a=="string")return Oe(a,200);try{return Oe(JSON.stringify(a),200)}catch{return Oe(String(a),200)}}function St(a){if(!a||a.length===0)return null;const i=(k,F)=>{const y=k.status==="running",z=k.status==="completed"&&k.isError,u=Ss(k.args),C=ks(k.result),S=y?u:C?`result: ${C}`:u?`args: ${u}`:null,I=y?"running":z?"error":"completed";return t.jsxs("details",{className:`chat-tool-call${y?" chat-tool-call--running":""}${z?" chat-tool-call--error":""}`,open:y,children:[t.jsxs("summary",{children:[t.jsx("span",{className:"chat-tool-call-status-dot","aria-hidden":"true"}),t.jsx("span",{className:"chat-tool-call-name",children:k.toolName}),S&&t.jsx("span",{className:"chat-tool-call-preview",title:S,children:S}),t.jsx("span",{className:"chat-tool-call-status-text",children:I})]}),t.jsxs("div",{className:"chat-tool-call-content",children:[u&&t.jsxs("div",{className:"chat-tool-call-row",children:[t.jsx("span",{className:"chat-tool-call-label",children:"args"}),t.jsx("span",{className:"chat-tool-call-value",children:u})]}),C&&t.jsxs("div",{className:`chat-tool-call-row${z?" chat-tool-call-row--error":""}`,children:[t.jsx("span",{className:"chat-tool-call-label",children:"result"}),t.jsx("span",{className:"chat-tool-call-value",children:C})]})]})]},`${k.toolName}-${F}`)},r="chat-tool-calls";if(a.length===1)return t.jsxs("div",{className:r,"data-testid":"chat-tool-calls",children:[t.jsxs("div",{className:"chat-tool-calls-header",children:[t.jsx(ct,{size:12,"aria-hidden":"true"}),t.jsx("span",{children:"Tool calls"})]}),i(a[0],0)]});const c=a.filter(k=>k.status==="running").length,l=a.filter(k=>k.status==="completed"&&k.isError).length,w=c>0,N=Array.from(new Set(a.map(k=>k.toolName))),$=N.slice(0,5),_=Math.max(0,N.length-$.length),b=_>0?`${$.join(", ")}, +${_} more`:$.join(", "),G=w?`(${c} running)`:l>0?`(${l} ${l===1?"error":"errors"})`:null;return t.jsx("div",{className:r,"data-testid":"chat-tool-calls",children:t.jsxs("details",{className:"chat-tool-calls-group","data-testid":"chat-tool-calls-group",open:w,children:[t.jsxs("summary",{className:"chat-tool-calls-group-summary",children:[t.jsx(ct,{size:12,"aria-hidden":"true"}),t.jsxs("span",{children:[a.length," tool calls"]}),t.jsx("span",{className:"chat-tool-calls-names",title:b,children:b}),G&&t.jsx("span",{className:"chat-tool-calls-group-status",children:G})]}),a.map((k,F)=>i(k,F))]})})}const kt={pre:({children:a,...i})=>t.jsx("pre",{...i,className:"chat-markdown-pre",children:a}),table:({children:a,...i})=>t.jsx("table",{...i,className:"chat-markdown-table",children:a})},Ue="__fn_agent__",ys=280,_e=180,ze=500,mt="fusion:chat-sidebar-width",Ns=["image/png","image/jpeg","image/gif","image/webp","text/plain","application/json","text/yaml","text/markdown","text/csv","application/xml","text/x-log"];function ft(a){const i=/(^|[\s])\/([^\s]*)$/.exec(a);if(!i)return null;const r=i[1]??"",c=i[2]??"",l=i.index+r.length;return{filter:c,start:l,end:a.length}}function js(a,i){const r=a.slice(0,i),c=/(^|[\s\n])@([\w-]*)$/.exec(r);if(!c)return null;const l=c[2]??"",w=r.length-l.length-1;return{filter:l,start:w,end:i}}function Cs({projectId:a,onClose:i,onCreate:r}){const[c,l]=s.useState("agent"),[w,N]=s.useState([]),[$,_]=s.useState(!0),[b,G]=s.useState(""),[k,F]=s.useState([]),[y,z]=s.useState(!0),[u,C]=s.useState(""),[S,I]=s.useState([]),[D,O]=s.useState([]);s.useEffect(()=>{let m=!1;return _(!0),et(void 0,a).then(j=>{m||N(j)}).catch(()=>{m||N([])}).finally(()=>{m||_(!1)}),()=>{m=!0}},[a]),s.useEffect(()=>{z(!0),gs().then(m=>{F(m.models),I(m.favoriteProviders),O(m.favoriteModels)}).catch(()=>{F([]),I([]),O([])}).finally(()=>{z(!1)})},[]);const Q=s.useCallback(async m=>{const j=S,p=j.includes(m)?j.filter(se=>se!==m):[m,...j];I(p);try{await dt({favoriteProviders:p,favoriteModels:D})}catch{I(j)}},[S,D]),U=s.useCallback(async m=>{const j=D,p=j.includes(m)?j.filter(se=>se!==m):[m,...j];O(p);try{await dt({favoriteProviders:S,favoriteModels:p})}catch{O(j)}},[D,S]),H=m=>{if(m.preventDefault(),c==="agent"){if(!b)return;r({agentId:b});return}if(!u)return;const j=u.indexOf("/");if(j<=0)return;const ce=u.slice(0,j),p=u.slice(j+1);r({agentId:Ue,modelProvider:ce,modelId:p})},X=c==="agent"?!b:!u;return t.jsx("div",{className:"chat-new-dialog-backdrop chat-view-dialog-backdrop",onClick:i,role:"dialog","aria-modal":"true",children:t.jsxs("div",{className:"chat-new-dialog chat-view-dialog",onClick:m=>m.stopPropagation(),children:[t.jsx("h3",{children:"New Chat"}),t.jsxs("div",{className:"chat-new-dialog-mode-toggle","data-testid":"chat-new-dialog-mode-toggle",children:[t.jsx("button",{type:"button",className:`chat-new-dialog-mode-btn${c==="agent"?" chat-new-dialog-mode-btn--active":""}`,"data-testid":"chat-new-dialog-mode-agent",onClick:()=>{l("agent"),C("")},children:"Agent"}),t.jsx("button",{type:"button",className:`chat-new-dialog-mode-btn${c==="model"?" chat-new-dialog-mode-btn--active":""}`,"data-testid":"chat-new-dialog-mode-model",onClick:()=>{l("model"),G("")},children:"Model"})]}),t.jsxs("form",{onSubmit:H,children:[c==="agent"&&t.jsxs("label",{className:"chat-new-dialog-model-label",children:["Agent",$?t.jsx("div",{className:"chat-new-dialog-loading",children:"Loading agents..."}):w.length===0?t.jsx("div",{className:"chat-new-dialog-empty",children:"No agents available"}):t.jsx("div",{className:"chat-new-dialog-agent-list",children:w.map(m=>t.jsxs("button",{type:"button",className:`chat-new-dialog-agent-item${b===m.id?" chat-new-dialog-agent-item--selected":""}`,onClick:()=>G(m.id),"data-testid":`agent-option-${m.id}`,children:[t.jsx(He,{size:16}),t.jsx("span",{className:"chat-new-dialog-agent-name",children:m.name}),t.jsx("span",{className:"chat-new-dialog-agent-role",children:m.role})]},m.id))})]}),c==="model"&&t.jsx("div",{className:"chat-new-dialog-model-dropdown","data-testid":"chat-new-dialog-model-section",children:y?t.jsx("div",{className:"chat-new-dialog-loading",children:"Loading models..."}):t.jsx(ps,{models:k,value:u,onChange:C,label:"Model",placeholder:"Select a model",favoriteProviders:S,onToggleFavorite:Q,favoriteModels:D,onToggleModelFavorite:U})}),t.jsxs("div",{className:"chat-new-dialog-actions",children:[t.jsx("button",{type:"button",className:"btn btn-sm",onClick:i,children:"Cancel"}),t.jsx("button",{type:"submit",className:"btn btn-sm btn-primary",disabled:X,children:"Create"})]})]})]})})}const gt=s.memo(function({message:i,forcePlain:r,agentName:c,showAssistantModelTag:l,activeModelTag:w,activeSessionId:N,mentionAgentsByName:$,onToggleRender:_}){const b=i.role==="assistant",G=s.useMemo(()=>{if(b)return null;const y=i.content,z=/@([\w-]+)/g,u=[];let C=0,S=z.exec(y);for(;S;){const[I,D=""]=S,O=S.index;O>C&&u.push(y.slice(C,O));const Q=D.replace(/_/g," ").toLowerCase(),U=$.get(Q);U?u.push(t.jsxs("span",{className:"chat-mention-chip",children:["@",U.name.replace(/\s+/g,"_")]},`${U.id}-${O}`)):u.push(I),C=O+I.length,S=z.exec(y)}return C<y.length&&u.push(y.slice(C)),u.length===0?y:u},[b,i.content,$]),k=s.useMemo(()=>{const y=i.attachments;if(!y||y.length===0||!N)return null;const z=`/api/chat/sessions/${encodeURIComponent(N)}/attachments/`;return t.jsx("div",{className:"chat-message-attachments",children:y.map(u=>{const C=u.mimeType.startsWith("image/"),S=u.id||u.filename,I=`${z}${encodeURIComponent(u.filename)}`;return C?t.jsx("a",{className:"chat-message-attachment-link","data-testid":"chat-message-attachment",href:I,target:"_blank",rel:"noopener noreferrer",children:t.jsx("img",{className:"chat-message-attachment",src:I,alt:u.originalName})},S):t.jsxs("a",{className:"chat-message-attachment-file","data-testid":"chat-message-attachment",href:I,target:"_blank",rel:"noopener noreferrer",children:[t.jsx(ms,{size:14}),t.jsx("span",{children:u.originalName})]},S)})})},[i.attachments,N]),F=s.useMemo(()=>b?r?t.jsx("div",{className:"chat-message-content chat-message-content--plain",children:i.content}):t.jsx("div",{className:"chat-message-content chat-message-content--markdown",children:t.jsx(pt,{remarkPlugins:[xt],components:kt,children:i.content})}):null,[b,r,i.content]);return t.jsxs("div",{className:`chat-message chat-message--${i.role}`,"data-testid":`chat-message-${i.id}`,children:[b&&t.jsxs("div",{className:"chat-message-avatar",children:[t.jsx(He,{size:14}),t.jsx("span",{children:c}),l&&w&&t.jsx("span",{className:"chat-model-tag",children:w}),t.jsx("button",{type:"button",className:`chat-message-render-toggle${r?" chat-message-render-toggle--plain":""}`,"data-testid":"chat-message-render-toggle","aria-label":r?"Show rendered markdown":"Show plain text",onClick:()=>_(i.id),children:r?t.jsx(vt,{size:14}):t.jsx(wt,{size:14})})]}),b?F:t.jsx("div",{className:"chat-message-content",children:G}),St(i.toolCalls),i.thinkingOutput&&t.jsxs("details",{className:"chat-message-thinking",children:[t.jsx("summary",{children:"Thinking"}),t.jsx("pre",{className:"chat-message-thinking-content",children:i.thinkingOutput})]}),k,t.jsx("div",{className:"chat-message-time",children:bt(i.createdAt)})]})});function Rs({projectId:a,addToast:i}){const{activeSession:r,sessionsLoading:c,messages:l,messagesLoading:w,isStreaming:N,streamingText:$,streamingThinking:_,streamingToolCalls:b,selectSession:G,createSession:k,archiveSession:F,deleteSession:y,sendMessage:z,stopStreaming:u,pendingMessage:C,clearPendingMessage:S,searchQuery:I,setSearchQuery:D,filteredSessions:O}=bs(a,i),[Q,U]=s.useState(!1),[H,X]=s.useState(""),[m,j]=s.useState(null),[ce,p]=s.useState(null),[se,J]=s.useState(!0),[Y,Ce]=s.useState(ys),[Z,Me]=s.useState(new Map),[pe,de]=s.useState([]),[$e,ue]=s.useState(!0),[re,ee]=s.useState(!1),[he,le]=s.useState(""),[be,xe]=s.useState(0),[Se,me]=s.useState(""),[ne,fe]=s.useState(!1),[ve,ke]=s.useState(0),[h,x]=s.useState(-1),[f,R]=s.useState(()=>new Set),[L,oe]=s.useState([]),[V,ge]=s.useState(!1),[,K]=s.useState(!1),[P,E]=s.useState({top:0,left:0}),d=es({projectId:a}),M=s.useCallback(e=>{if(!e||!d.mentionActive)return;const n=e.getBoundingClientRect();E({top:n.top-260,left:n.left+8})},[d.mentionActive]),ae=s.useRef(null),g=s.useRef(null),T=s.useRef(null),v=s.useRef(null),q=s.useRef(!1),Pe=s.useRef(!1),tt=s.useRef(null),st=s.useRef([]),Te=s.useRef(0),W=ts()==="mobile";s.useEffect(()=>{try{const e=localStorage.getItem(mt);if(!e)return;const n=Number.parseInt(e,10);if(Number.isNaN(n))return;const o=Math.max(_e,Math.min(ze,n));Ce(o)}catch{}},[]);const{keyboardOverlap:We,viewportHeight:nt,viewportOffsetTop:yt,keyboardOpen:at}=ss({enabled:W&&!!r}),Nt=at?{"--keyboard-overlap":`${We}px`,"--vv-offset-top":`${yt}px`,...nt!==null?{"--vv-height":`${nt}px`}:{}}:{},te=s.useMemo(()=>{const e=he.trim().toLowerCase();return(e?pe.filter(o=>o.name.toLowerCase().includes(e)):pe).slice(0,10)},[pe,he]),ye=s.useMemo(()=>Array.from(Z.values()),[Z]),we=s.useMemo(()=>{const e=Se.trim().toLowerCase();return e?ye.filter(n=>n.name.toLowerCase().includes(e)):ye},[ye,Se]),it=s.useMemo(()=>{const e=new Map;for(const n of ye)e.set(n.name.toLowerCase(),n);return e},[ye]);s.useEffect(()=>{xe(0)},[te]),s.useEffect(()=>{ke(0)},[Se,ne]),s.useEffect(()=>()=>{g.current!==null&&window.clearTimeout(g.current)},[]),s.useEffect(()=>{const e=T.current;e&&(e.scrollTop=e.scrollHeight)},[l,$,_,N]),s.useEffect(()=>{if(We<=0)return;const e=T.current;e&&(e.scrollTop=e.scrollHeight)},[We]),ns(W&&at),s.useEffect(()=>{const e=()=>j(null);if(m)return document.addEventListener("click",e),()=>document.removeEventListener("click",e)},[m]),s.useEffect(()=>{let e=!1;const n=a;return et(void 0,a).then(o=>{if(e||n!==a)return;const A=new Map;for(const B of o)A.set(B.id,B);Me(A)}).catch(()=>{}),()=>{e=!0}},[a]),s.useEffect(()=>{let e=!1;return ue(!0),as(a).then(n=>{e||de(n)}).catch(()=>{e||de([])}).finally(()=>{e||ue(!1)}),()=>{e=!0}},[a]),s.useEffect(()=>{st.current=L},[L]),s.useEffect(()=>()=>{for(const e of st.current)e.previewUrl&&URL.revokeObjectURL(e.previewUrl)},[]);const Ee=s.useCallback(e=>{if(!e||e.length===0)return;const n=[];for(const o of Array.from(e)){if(!Ns.includes(o.type))continue;const A=o.type.startsWith("image/");n.push({file:o,previewUrl:A?URL.createObjectURL(o):""})}n.length>0&&oe(o=>[...o,...n])},[]),jt=s.useCallback(e=>{oe(n=>{const o=n[e];return o?.previewUrl&&URL.revokeObjectURL(o.previewUrl),n.filter((A,B)=>B!==e)})},[]),Ct=s.useCallback(e=>{const n=e.clipboardData?.files;if(!n||n.length===0)return;const o=Array.from(n).filter(A=>A.type.startsWith("image/"));o.length!==0&&Ee(o)},[Ee]),Mt=s.useCallback(async e=>{try{await k(e),U(!1),W&&J(!1)}catch{i("Failed to create chat session","error")}},[k,i,W]),Be=s.useCallback(()=>{X(""),ee(!1),le(""),fe(!1),me(""),x(-1),oe(e=>{for(const n of e)n.previewUrl&&URL.revokeObjectURL(n.previewUrl);return[]})},[]),Ae=s.useCallback(()=>{const e=H.trim(),n=L.map(o=>o.file);if(!(!e&&n.length===0||!r)){if(e==="/clear"){Be(),u(),S(),k({agentId:r.agentId,modelProvider:r.modelProvider??void 0,modelId:r.modelId??void 0}).catch(()=>{i("Failed to clear conversation","error")});return}Be(),z(e,n)}},[H,L,r,Be,u,S,k,i,z]),Fe=s.useCallback(()=>{if(typeof window>"u"||window.innerWidth>768)return;const e=v.current;if(!e||e.disabled)return;const n=window.scrollX,o=window.scrollY;e.focus({preventScroll:!0}),window.requestAnimationFrame(()=>{(window.scrollX!==n||window.scrollY!==o)&&window.scrollTo(n,o)})},[]),rt=s.useCallback(()=>{typeof window>"u"||window.innerWidth>768||(q.current=!0)},[]),Ge=s.useCallback(e=>{X(n=>{const o=ft(n);if(!o)return n;const A=`/skill:${e.name} `,B=n.slice(0,o.start)+A+n.slice(o.end);return window.requestAnimationFrame(()=>{v.current&&(v.current.style.height="auto",v.current.style.height=`${Math.min(v.current.scrollHeight,120)}px`,v.current.focus())}),B}),ee(!1),le(""),xe(0)},[]),qe=s.useCallback(e=>{const n=v.current;if(!n||h<0)return;const o=n.selectionStart??Te.current,A=n.selectionEnd??o,B=Math.max(o,A),Re=Math.min(h,B),Ne=`${`@${e.name.replace(/\s+/g,"_")}`} `,Ye=H.slice(0,Re)+Ne+H.slice(B),je=Re+Ne.length;X(Ye),fe(!1),me(""),ke(0),x(-1),window.requestAnimationFrame(()=>{v.current&&(v.current.style.height="auto",v.current.style.height=`${Math.min(v.current.scrollHeight,120)}px`,v.current.focus(),v.current.setSelectionRange(je,je))})},[h,H]),Tt=s.useCallback(e=>{if(Te.current=e.currentTarget.selectionStart??Te.current,d.mentionActive&&d.files.length>0){if(d.handleKeyDown(e,H),e.key==="Enter"||e.key==="Tab"){const n=d.files[d.selectedIndex];if(n){const o=d.selectFile(n,H);X(o),d.dismissMention(),K(!1)}}return}if(ne&&e.key==="ArrowDown"){e.preventDefault(),we.length>0&&ke(n=>(n+1)%we.length);return}if(ne&&e.key==="ArrowUp"){e.preventDefault(),we.length>0&&ke(n=>n===0?we.length-1:n-1);return}if(ne&&e.key==="Enter"){e.preventDefault();const n=we[ve]??we[0];n&&qe(n);return}if(ne&&e.key==="Escape"){e.preventDefault(),fe(!1),me(""),x(-1);return}if(re&&e.key==="ArrowDown"){e.preventDefault(),te.length>0&&xe(n=>(n+1)%te.length);return}if(re&&e.key==="ArrowUp"){e.preventDefault(),te.length>0&&xe(n=>n===0?te.length-1:n-1);return}if(re&&(e.key==="Enter"||e.key==="Tab")&&te.length>0){e.preventDefault();const n=te[be]??te[0];n&&Ge(n);return}if(re&&e.key==="Escape"){e.preventDefault(),ee(!1);return}e.key==="Enter"&&!e.shiftKey&&(e.preventDefault(),Ae())},[ne,we,ve,qe,re,te,be,Ge,Ae,d,H]),Ie=s.useCallback((e,n)=>{const o=js(e,n);if(o){fe(!0),me(o.filter),x(o.start);return}fe(!1),me(""),x(-1)},[]),At=s.useCallback(e=>{const n=e.target,o=n.value,A=n.selectionStart??o.length;Te.current=A,X(o);const B=ft(o);B?(ee(!0),le(B.filter)):(ee(!1),le("")),Ie(o,A),d.detectMention(o,A),K(d.mentionActive),d.mentionActive&&M(n),n.style.height="auto",n.style.height=`${Math.min(n.scrollHeight,120)}px`},[Ie]),Ve=s.useCallback(e=>{const n=e.currentTarget,o=n.selectionStart??n.value.length;Te.current=o,Ie(n.value,o),d.detectMention(n.value,o),K(d.mentionActive),d.mentionActive&&M(n)},[Ie,d,M]),Dt=s.useCallback(e=>{e.key!=="Escape"&&Ve(e)},[Ve]),Rt=s.useCallback(()=>{if(q.current){window.requestAnimationFrame(()=>{Fe()});return}g.current!==null&&window.clearTimeout(g.current),g.current=window.setTimeout(()=>{ee(!1),fe(!1),me(""),x(-1),K(!1),d.dismissMention(),g.current=null},120)},[d,Fe]),$t=s.useCallback(()=>{g.current!==null&&(window.clearTimeout(g.current),g.current=null)},[]),Pt=s.useCallback(async e=>{j(null);try{await F(e),i("Conversation archived","success")}catch{i("Failed to archive conversation","error")}},[F,i]),Et=s.useCallback(async e=>{p(null),j(null);try{await y(e),i("Conversation deleted","success")}catch{i("Failed to delete conversation","error")}},[y,i]),De=s.useCallback(e=>{try{localStorage.setItem(mt,String(e))}catch{}},[]),Ft=s.useCallback(e=>{if(W)return;e.preventDefault(),e.stopPropagation();const n=e.currentTarget;typeof n.setPointerCapture=="function"&&n.setPointerCapture(e.pointerId);const o=e.clientX,A=Y;let B=A;document.body.style.userSelect="none";const Re=Ne=>{const Ye=Ne.clientX-o,je=Math.max(_e,Math.min(ze,A+Ye));B=je,Ce(je),De(je)},Je=Ne=>{typeof n.releasePointerCapture=="function"&&n.releasePointerCapture(Ne.pointerId),document.body.style.userSelect="",document.removeEventListener("pointermove",Re),document.removeEventListener("pointerup",Je),De(B)};document.addEventListener("pointermove",Re),document.addEventListener("pointerup",Je)},[W,De,Y]),It=s.useCallback(e=>{if(W||e.key!=="ArrowLeft"&&e.key!=="ArrowRight")return;e.preventDefault();const n=e.shiftKey?50:10,o=e.key==="ArrowLeft"?-n:n,A=Math.max(_e,Math.min(ze,Y+o));Ce(A),De(A)},[W,De,Y]),Lt=s.useCallback(e=>{G(e),W&&J(!1)},[G,W]),_t=s.useCallback(()=>{G(""),J(!0)},[G]),zt=()=>t.jsxs("div",{className:"chat-empty-state",children:[t.jsx(fs,{size:48,strokeWidth:1.5}),t.jsx("h2",{children:"Start a new conversation"}),t.jsxs("button",{className:"btn btn-primary",onClick:()=>U(!0),children:[t.jsx(Qe,{size:16}),"New Chat"]})]}),ie=ht(r?.modelProvider,r?.modelId),lt=r?.agentId===Ue?ie??"Fusion":r?.title||Z.get(r?.agentId??"")?.name||r?.agentId||"Chat",Ot=!!(ie&&ie!==lt),Le=Z.get(r?.agentId??"")?.name||(r?.agentId===Ue?ie??"Fusion":r?.agentId?.slice(0,30)??"Fusion"),Ke=!!(ie&&ie!==Le),Ut=C.length>50?`${C.slice(0,50)}…`:C,Xe=s.useCallback(e=>{R(n=>{const o=new Set(n);return o.has(e)?o.delete(e):o.add(e),o})},[]),Ht=s.useCallback((e,n=!1)=>n?t.jsx("div",{className:"chat-message-content chat-message-content--plain",children:e}):t.jsx("div",{className:"chat-message-content chat-message-content--markdown",children:t.jsx(pt,{remarkPlugins:[xt],components:kt,children:e})}),[]);return t.jsxs("div",{className:"chat-view",children:[t.jsxs("div",{className:`chat-sidebar${se?"":" chat-sidebar--hidden"}`,style:W?void 0:{width:`${Y}px`},children:[t.jsx("div",{className:"chat-sidebar-search",children:t.jsxs("div",{className:"chat-sidebar-search-wrapper",children:[t.jsx(is,{size:14,className:"chat-sidebar-search-icon"}),t.jsx("input",{type:"text",className:"chat-sidebar-search",placeholder:"Search conversations...",value:I,onChange:e=>D(e.target.value),"data-testid":"chat-search-input"})]})}),t.jsx("div",{className:"chat-session-list chat-sidebar-list",children:c?t.jsx("div",{style:{padding:"12px",color:"var(--text-secondary)",fontSize:"13px"},children:"Loading..."}):O.length===0?t.jsx("div",{style:{padding:"12px",color:"var(--text-secondary)",fontSize:"13px"},children:"No conversations yet"}):O.map(e=>t.jsxs("div",{className:`chat-session-item${r?.id===e.id?" chat-session-item--active":""}`,onClick:()=>Lt(e.id),onContextMenu:n=>{n.preventDefault(),j({sessionId:e.id,x:n.clientX,y:n.clientY})},"data-testid":`chat-session-${e.id}`,children:[t.jsx("button",{className:"chat-session-delete-btn",onClick:n=>{n.stopPropagation(),p(e.id)},"data-testid":"chat-session-delete-btn","aria-label":"Delete conversation",children:t.jsx(ot,{size:14})}),t.jsx("div",{className:"chat-session-title",children:e.title||"Untitled"}),t.jsx("div",{className:"chat-session-preview",children:e.lastMessagePreview||"No messages"}),t.jsxs("div",{className:"chat-session-meta",children:[t.jsx("span",{children:Z.get(e.agentId)?.name||(e.agentId===Ue?ht(e.modelProvider,e.modelId)??"Fusion":e.agentId.slice(0,30))}),t.jsx("span",{children:e.updatedAt?bt(e.updatedAt):""})]})]},e.id))}),t.jsx("div",{className:"chat-sidebar-footer",children:t.jsxs("button",{className:"btn btn-sm btn-primary chat-sidebar-footer-btn",onClick:()=>U(!0),"data-testid":"chat-new-btn",children:[t.jsx(Qe,{size:14}),"New Chat"]})})]}),!W&&se&&t.jsx("div",{className:"chat-sidebar-resize-handle",role:"separator","aria-orientation":"vertical","aria-valuemin":_e,"aria-valuemax":ze,"aria-valuenow":Y,"aria-label":"Resize chat sidebar",tabIndex:0,onPointerDown:Ft,onKeyDown:It}),m&&t.jsxs("div",{className:"chat-session-context-menu",style:{top:m.y,left:m.x},onClick:e=>e.stopPropagation(),children:[t.jsxs("button",{onClick:()=>Pt(m.sessionId),"data-testid":"chat-context-archive",children:[t.jsx(rs,{size:14}),"Archive"]}),t.jsxs("button",{onClick:()=>{j(null),p(m.sessionId)},"data-testid":"chat-context-delete",children:[t.jsx(ot,{size:14}),"Delete"]})]}),ce&&t.jsx("div",{className:"chat-new-dialog-backdrop chat-view-dialog-backdrop",onClick:()=>p(null),children:t.jsxs("div",{className:"chat-new-dialog chat-view-dialog",onClick:e=>e.stopPropagation(),children:[t.jsx("h3",{children:"Delete Conversation?"}),t.jsx("p",{className:"chat-view-delete-dialog-copy",children:"This action cannot be undone. All messages in this conversation will be permanently deleted."}),t.jsxs("div",{className:"chat-new-dialog-actions",children:[t.jsx("button",{className:"btn btn-sm",onClick:()=>p(null),children:"Cancel"}),t.jsx("button",{className:"btn btn-sm btn-danger",onClick:()=>void Et(ce),children:"Delete"})]})]})}),t.jsxs("div",{className:"chat-thread",style:Nt,children:[(r||!W)&&t.jsxs("div",{className:"chat-thread-header",children:[W&&r&&t.jsx("button",{className:"btn-icon",onClick:_t,"data-testid":"chat-back-btn",children:t.jsx(ls,{size:16})}),t.jsx(He,{size:16}),t.jsx("span",{className:"chat-thread-header-title",children:lt}),Ot&&t.jsx("span",{className:"chat-model-tag",children:ie}),!W&&t.jsxs("button",{className:"btn btn-sm btn-primary chat-thread-header-new-chat",onClick:()=>U(!0),"data-testid":"chat-thread-new-chat-btn",children:[t.jsx(Qe,{size:14}),"New Chat"]})]}),t.jsxs("div",{className:"chat-messages",ref:T,children:[N?t.jsxs(t.Fragment,{children:[l.map(e=>t.jsx(gt,{message:e,forcePlain:f.has(e.id),agentName:Le,showAssistantModelTag:Ke,activeModelTag:ie,activeSessionId:r?.id??null,mentionAgentsByName:it,onToggleRender:Xe},e.id)),t.jsxs("div",{className:"chat-message chat-message--assistant chat-message--streaming",children:[t.jsxs("div",{className:"chat-message-avatar",children:[t.jsx(He,{size:14}),t.jsx("span",{children:Le}),Ke&&t.jsx("span",{className:"chat-model-tag",children:ie}),t.jsx("button",{type:"button",className:`chat-message-render-toggle${f.has("__streaming__")?" chat-message-render-toggle--plain":""}`,"data-testid":"chat-message-render-toggle","aria-label":f.has("__streaming__")?"Show rendered markdown":"Show plain text",onClick:()=>Xe("__streaming__"),children:f.has("__streaming__")?t.jsx(vt,{size:14}):t.jsx(wt,{size:14})})]}),$?Ht($,f.has("__streaming__")):t.jsx("div",{className:"chat-message-content chat-message-content--waiting",children:_?"Thinking…":"Connecting…"}),St(b),_&&t.jsxs("details",{className:"chat-message-thinking",children:[t.jsx("summary",{children:"Thinking"}),t.jsx("pre",{className:"chat-message-thinking-content",children:_})]}),t.jsxs("div",{className:"chat-typing-indicator",children:[t.jsx("span",{}),t.jsx("span",{}),t.jsx("span",{})]})]})]}):w?t.jsx("div",{style:{color:"var(--text-secondary)",fontSize:"13px"},children:"Loading messages..."}):l.length===0&&!r?zt():l.length===0&&r?t.jsx("div",{style:{color:"var(--text-secondary)",fontSize:"13px"},children:"No messages yet. Start the conversation!"}):t.jsx(t.Fragment,{children:l.map(e=>t.jsx(gt,{message:e,forcePlain:f.has(e.id),agentName:Le,showAssistantModelTag:Ke,activeModelTag:ie,activeSessionId:r?.id??null,mentionAgentsByName:it,onToggleRender:Xe},e.id))}),t.jsx("div",{ref:ae})]}),r&&t.jsxs("div",{className:"chat-input-area",children:[t.jsx("input",{ref:tt,type:"file",accept:"image/*,.txt,.json,.yaml,.yml,.log,.csv,.xml,.md",multiple:!0,style:{display:"none"},onChange:e=>{Ee(e.target.files),e.target.value=""}}),re&&t.jsx("div",{className:"chat-skill-menu","data-testid":"chat-skill-menu",role:"listbox","aria-label":"Skill suggestions",children:$e?t.jsx("div",{className:"chat-skill-menu-empty",children:"Loading skills…"}):te.length===0?t.jsx("div",{className:"chat-skill-menu-empty",children:he?"No skills found":"No skills available"}):te.map((e,n)=>t.jsxs("button",{type:"button",role:"option","aria-selected":n===be,className:`chat-skill-menu-item${n===be?" chat-skill-menu-item--highlighted":""}`,onMouseDown:o=>o.preventDefault(),onMouseEnter:()=>xe(n),onClick:()=>Ge(e),children:[t.jsx("span",{className:"chat-skill-menu-item-name",children:e.name}),t.jsx("span",{className:"chat-skill-menu-item-description",title:e.relativePath,children:e.relativePath})]},e.id))}),L.length>0&&t.jsx("div",{className:"chat-attachment-previews","data-testid":"chat-attachment-previews",children:L.map((e,n)=>t.jsxs("div",{className:"chat-attachment-preview","data-testid":`chat-attachment-preview-${n}`,children:[e.previewUrl?t.jsx("img",{src:e.previewUrl,alt:e.file.name}):t.jsx("span",{className:"chat-attachment-preview-name",children:e.file.name}),t.jsx("button",{type:"button",className:"chat-attachment-remove",onClick:()=>jt(n),"data-testid":`chat-attachment-remove-${n}`,"aria-label":`Remove ${e.file.name}`,children:"×"})]},e.previewUrl||`${e.file.name}-${n}`))}),t.jsxs("div",{className:"chat-input-row",children:[t.jsx("button",{type:"button",className:"btn-icon chat-attach-btn","data-testid":"chat-attach-btn","aria-label":"Attach files",onClick:()=>tt.current?.click(),children:t.jsx(os,{size:16})}),t.jsxs("div",{className:`chat-input-wrapper${V?" chat-input-wrapper--dragover":""}`,onDragOver:e=>{e.preventDefault(),ge(!0)},onDragLeave:()=>ge(!1),onDrop:e=>{e.preventDefault(),ge(!1),Ee(e.dataTransfer.files)},children:[t.jsx("textarea",{ref:v,className:"chat-input-textarea",placeholder:"Type a message...",value:H,onChange:At,onKeyDown:Tt,onKeyUp:Dt,onClick:Ve,onBlur:Rt,onFocus:$t,onPaste:Ct,onTouchStart:e=>{typeof window>"u"||window.innerWidth>768||document.activeElement!==e.currentTarget&&(e.preventDefault(),e.currentTarget.focus({preventScroll:!0}))},rows:1,"data-testid":"chat-input"}),t.jsx(cs,{agents:ye,filter:Se,highlightedIndex:ve,visible:ne,onSelect:qe,position:"below"}),t.jsx(ds,{visible:d.mentionActive&&!ne,position:P,files:d.files,selectedIndex:d.selectedIndex,onSelect:e=>{const n=d.selectFile(e,H);X(n),d.dismissMention(),K(!1),v.current?.focus()},loading:d.loading}),C&&t.jsxs("div",{className:"chat-pending-message","data-testid":"chat-pending-indicator",children:[t.jsx("span",{children:`Queued: ${Ut}`}),t.jsx("button",{type:"button",className:"chat-pending-message-dismiss","aria-label":"Dismiss queued message","data-testid":"chat-pending-dismiss",onClick:S,children:"×"})]})]}),N?t.jsx("button",{className:"chat-input-stop",onClick:u,"aria-label":"Stop generation","data-testid":"chat-stop-btn",children:t.jsx(us,{size:14})}):t.jsx("button",{type:"button",className:"chat-input-send",onPointerDown:e=>{typeof window>"u"||window.innerWidth>768||(e.preventDefault(),e.pointerType&&e.pointerType!=="mouse"&&(Pe.current=!0,rt(),Fe(),Ae(),window.setTimeout(()=>{q.current=!1},1500)))},onTouchStart:e=>{typeof window>"u"||window.innerWidth>768||(e.preventDefault(),Pe.current=!0,rt(),Fe(),Ae(),window.setTimeout(()=>{q.current=!1},1500))},onMouseDown:e=>{typeof window>"u"||window.innerWidth>768||e.preventDefault()},onClick:()=>{if(Pe.current){Pe.current=!1;return}Ae()},disabled:!H.trim()&&L.length===0,"data-testid":"chat-send-btn",children:t.jsx(hs,{size:16})})]})]})]}),Q&&t.jsx(Cs,{projectId:a,onClose:()=>U(!1),onCreate:Mt})]})}export{Rs as ChatView};
@@ -1 +0,0 @@
1
- .insights-view{display:flex;flex-direction:column;height:100%;min-height:0;overflow:hidden}.insights-view-header{display:flex;align-items:center;justify-content:space-between;padding:var(--space-lg);border-bottom:1px solid var(--border);background:var(--surface);flex-shrink:0}.insights-view-title{display:flex;align-items:center;gap:var(--space-sm)}.insights-view-title h2{margin:0;font-size:18px;font-weight:600;display:flex;align-items:center;gap:var(--space-sm)}.insights-view-count{font-size:13px;color:var(--text-muted);font-weight:400}.insights-view-actions{display:flex;align-items:center;gap:var(--space-sm)}.insights-view-close{color:var(--text-muted)}.insights-view-close:hover{color:var(--text)}.insights-status-region{padding:var(--space-md) var(--space-lg);flex-shrink:0}.insights-status-region:empty{padding:0}.insights-status-message{display:flex;align-items:center;gap:var(--space-sm);padding:var(--space-sm) var(--space-md);border-radius:var(--radius-md);font-size:13px}.insights-status-message--success{background:color-mix(in srgb,var(--color-success) 10%,transparent);color:var(--color-success)}.insights-status-message--error{background:color-mix(in srgb,var(--color-error) 10%,transparent);color:var(--color-error)}.insights-status-message--info{background:color-mix(in srgb,var(--accent) 10%,transparent);color:var(--accent)}.insights-error-callout{display:flex;align-items:center;gap:var(--space-sm);margin:0 var(--space-lg) var(--space-md);padding:var(--space-md);background:color-mix(in srgb,var(--color-error) 10%,transparent);border:1px solid color-mix(in srgb,var(--color-error) 30%,transparent);border-radius:var(--radius-md);color:var(--color-error);font-size:13px;flex-shrink:0}.insights-run-info{padding:0 var(--space-lg) var(--space-md);flex-shrink:0}.insights-run-status{font-size:12px;color:var(--text-muted)}.insights-loading{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--space-md);padding:var(--space-2xl);color:var(--text-muted)}.insights-error{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--space-md);padding:var(--space-2xl);text-align:center}.insights-error p{color:var(--text-muted);margin:0}.insights-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--space-md);padding:var(--space-2xl);text-align:center;flex:1}.insights-empty h3{margin:0;font-size:18px;color:var(--text)}.insights-empty p{color:var(--text-muted);margin:0;max-width:400px}.insights-body{flex:1;min-height:0;display:flex;overflow:hidden}.insights-sidebar{width:240px;flex-shrink:0;border-right:1px solid var(--border);background:var(--surface);overflow-y:auto;min-height:0}.insights-category-list{list-style:none;margin:0;padding:var(--space-sm);display:flex;flex-direction:column;gap:2px}.insights-category-item{width:100%;display:flex;align-items:center;gap:var(--space-sm);padding:var(--space-sm) var(--space-md);background:transparent;border:1px solid transparent;border-radius:var(--radius-md);color:var(--text);font:inherit;font-size:13px;text-align:left;cursor:pointer;transition:background var(--transition-fast),border-color var(--transition-fast)}.insights-category-item:hover{background:var(--surface-elevated)}.insights-category-item--active{background:color-mix(in srgb,var(--accent) 12%,transparent);border-color:color-mix(in srgb,var(--accent) 35%,transparent);color:var(--accent)}.insights-category-icon{flex-shrink:0;color:var(--accent)}.insights-category-label{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:500}.insights-category-count{flex-shrink:0;font-size:12px;color:var(--text-muted);background:var(--surface-elevated);padding:2px 8px;border-radius:var(--radius-pill);border:1px solid var(--border)}.insights-category-item--active .insights-category-count{background:var(--surface);color:var(--accent);border-color:color-mix(in srgb,var(--accent) 30%,transparent)}.insights-detail{flex:1;min-width:0;min-height:0;overflow-y:auto;padding:var(--space-lg)}.insights-section{background:var(--card);border:1px solid var(--border);border-radius:var(--radius-lg);overflow:hidden}.insights-section-header{display:flex;align-items:center;justify-content:space-between;padding:var(--space-md) var(--space-lg);background:var(--surface);border-bottom:1px solid var(--border)}.insights-section-title{display:flex;align-items:center;gap:var(--space-sm)}.insights-section-title h3{margin:0;font-size:15px;font-weight:600}.insights-section-icon{color:var(--accent)}.insights-section-count{font-size:12px;color:var(--text-muted);background:var(--surface-elevated);padding:2px 8px;border-radius:var(--radius-pill);border:1px solid var(--border)}.insights-section-content{padding:var(--space-md)}.insights-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:var(--space-md)}.insight-item{padding:var(--space-md);background:var(--surface);border:1px solid var(--border);border-left:3px solid var(--accent);border-radius:var(--radius-md);transition:border-color var(--transition-fast)}.insight-item:hover{border-color:var(--accent)}.insight-item-header{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--space-sm)}.insight-item-title{margin:0;font-size:14px;font-weight:600;color:var(--text);line-height:1.4}.insight-item-actions{display:flex;align-items:center;gap:var(--space-xs);flex-shrink:0}.insight-item-action-btn{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;padding:0;background:transparent;border:none;border-radius:var(--radius-md);color:var(--text-muted);cursor:pointer;transition:background var(--transition-fast),color var(--transition-fast)}.insight-item-action-btn:hover:not(:disabled){background:var(--surface-elevated);color:var(--accent)}.insight-item-action-btn:disabled{opacity:.5;cursor:not-allowed}.insight-item-content{margin:var(--space-sm) 0 0;font-size:13px;color:var(--text-muted);line-height:1.5;white-space:pre-wrap;word-break:break-word}.insight-item-meta{display:flex;align-items:center;gap:var(--space-md);margin-top:var(--space-sm);font-size:12px;color:var(--text-muted)}.insight-item-status{padding:2px 6px;border-radius:var(--radius-sm);text-transform:capitalize;font-weight:500}.insight-item-status--generated{background:color-mix(in srgb,var(--accent) 15%,transparent);color:var(--accent)}.insight-item-status--confirmed{background:color-mix(in srgb,var(--color-success) 15%,transparent);color:var(--color-success)}.insight-item-status--stale{background:color-mix(in srgb,var(--color-warning) 15%,transparent);color:var(--color-warning)}.insight-item-status--dismissed{background:color-mix(in srgb,var(--text-dim) 15%,transparent);color:var(--text-dim)}.insight-item-date{display:flex;align-items:center;gap:4px}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.spin{animation:spin 1s linear infinite}@media(max-width:768px){.insights-view-header{flex-wrap:nowrap;gap:var(--space-sm);padding:var(--space-md)}.insights-view-title{min-width:0;flex:1 1 auto}.insights-view-title h2{font-size:16px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.insights-view-actions{flex-shrink:0;justify-content:flex-end;flex-wrap:nowrap;gap:var(--space-xs)}.insights-body{flex-direction:column}.insights-sidebar{width:100%;border-right:none;border-bottom:1px solid var(--border);overflow-x:auto;overflow-y:hidden;flex-shrink:0}.insights-category-list{flex-direction:row;flex-wrap:nowrap;padding:var(--space-sm);gap:var(--space-xs)}.insights-category-list>li{flex-shrink:0}.insights-category-item{white-space:nowrap;padding:var(--space-xs) var(--space-sm)}.insights-category-label{overflow:visible;text-overflow:clip}.insights-detail{padding:var(--space-md)}.insights-section-header{padding:var(--space-sm) var(--space-md)}.insights-section-content,.insight-item{padding:var(--space-sm)}.insight-item-title{word-break:break-word}.insight-item-header{flex-direction:column;gap:var(--space-sm)}.insight-item-meta{flex-wrap:wrap;gap:var(--space-sm)}.insight-item-actions{align-self:flex-end}.insight-item-action-btn{width:40px;height:40px}.insights-view-actions .btn{min-height:36px}.insights-view-close{min-height:36px;min-width:36px}.insights-view-count{font-size:12px}}
@@ -1,11 +0,0 @@
1
- import{r as n,j as s}from"./vendor-react-K0fH_qHe.js";import{h as Q,i as Z,j as ss,t as es,k as ts,l as is,m as f,X as q,R as w,n as V,o as T,T as B,L as ns,P as W,p as as,q as rs,s as X}from"./index-DNzA4aZ7.js";import{U as P}from"./users-Cp5TSxVm.js";import"./vendor-xterm-DzcZoU0P.js";/**
2
- * @license lucide-react v1.7.0 - ISC
3
- *
4
- * This source code is licensed under the ISC license.
5
- * See the LICENSE file in the root directory of this source tree.
6
- */const cs=[["path",{d:"M12 10h.01",key:"1nrarc"}],["path",{d:"M12 14h.01",key:"1etili"}],["path",{d:"M12 6h.01",key:"1vi96p"}],["path",{d:"M16 10h.01",key:"1m94wz"}],["path",{d:"M16 14h.01",key:"1gbofw"}],["path",{d:"M16 6h.01",key:"1x0f13"}],["path",{d:"M8 10h.01",key:"19clt8"}],["path",{d:"M8 14h.01",key:"6423bh"}],["path",{d:"M8 6h.01",key:"1dz90k"}],["path",{d:"M9 22v-3a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v3",key:"cabbwy"}],["rect",{x:"4",y:"2",width:"16",height:"20",rx:"2",key:"1uxh74"}]],ls=Q("building",cs);/**
7
- * @license lucide-react v1.7.0 - ISC
8
- *
9
- * This source code is licensed under the ISC license.
10
- * See the LICENSE file in the root directory of this source tree.
11
- */const os=[["path",{d:"M3 3v16a2 2 0 0 0 2 2h16",key:"c24i48"}],["path",{d:"m19 9-5 5-4-4-3 3",key:"2osh9i"}]],hs=Q("chart-line",os),$=["architecture","quality","workflow","performance","reliability","security","ux","testability","documentation","dependency","features","competitive_analysis","research","trends","other"],Y={quality:"Quality",performance:"Performance",architecture:"Architecture",security:"Security",reliability:"Reliability",ux:"User Experience",testability:"Testability",documentation:"Documentation",dependency:"Dependencies",workflow:"Workflow",other:"Other",features:"Features",competitive_analysis:"Competitive Analysis",research:"Research",trends:"Trends"};function ds(d){const[o,C]=n.useState(()=>$.map(t=>({category:t,label:Y[t]??t,items:[],isLoading:!1,error:null}))),[S,E]=n.useState(!0),[I,M]=n.useState(null),[g,z]=n.useState(null),[F,R]=n.useState(!1),[A,k]=n.useState(null),[D,v]=n.useState(new Map),[L,N]=n.useState(new Map),m=n.useCallback(async()=>{E(!0),M(null);try{const t=await Z({status:void 0,limit:1e3},d),e=new Map;for(const c of $)e.set(c,[]);for(const c of t.insights)if(c.status!=="dismissed"){const p=e.get(c.category)??[];e.set(c.category,[...p,c])}C($.map(c=>({category:c,label:Y[c]??c,items:e.get(c)??[],isLoading:!1,error:null})));const r=await ss(d);r.runs.length>0&&z(r.runs[0])}catch(t){const e=t instanceof Error?t.message:"Failed to fetch insights";M(e)}finally{E(!1)}},[d]),h=n.useCallback(async()=>{R(!0),k(null);try{const t=await es("manual",void 0,d);z(t),t.status==="completed"?await m():t.status==="failed"&&t.error&&k(t.error)}catch(t){const e=t instanceof Error?t.message:"Failed to generate insights";throw k(e),t}finally{R(!1)}},[d,m]),j=n.useCallback(async t=>{v(e=>{const r=new Map(e);return r.set(t,{running:!0,error:null}),r});try{await ts(t,d),C(e=>e.map(r=>({...r,items:r.items.filter(c=>c.id!==t)}))),v(e=>{const r=new Map(e);return r.set(t,{running:!1,error:null}),r})}catch(e){const r=e instanceof Error?e.message:"Failed to dismiss insight";throw v(c=>{const p=new Map(c);return p.set(t,{running:!1,error:r}),p}),e}},[d]),u=n.useCallback(async t=>{N(e=>{const r=new Map(e);return r.set(t,{running:!0,error:null}),r});try{const e=await is(t,d);return N(r=>{const c=new Map(r);return c.set(t,{running:!1,error:null}),c}),{title:e.suggestedTitle,description:e.suggestedDescription}}catch(e){const r=e instanceof Error?e.message:"Failed to create task";throw N(c=>{const p=new Map(c);return p.set(t,{running:!1,error:r}),p}),e}},[d]),x=n.useMemo(()=>o.reduce((t,e)=>t+e.items.length,0),[o]),y=n.useMemo(()=>0,[o]);return n.useEffect(()=>{m()},[m]),{sections:o,loading:S,error:I,latestRun:g,isRunInFlight:F,runError:A,refresh:m,runInsights:h,dismiss:j,createTask:u,dismissStates:D,createTaskStates:L,totalCount:x,dismissedCount:y}}const H={architecture:ls,quality:V,workflow:X,performance:B,reliability:w,security:T,ux:P,testability:rs,documentation:as,dependency:W,features:ns,competitive_analysis:P,research:hs,trends:B,other:f};function ps({projectId:d,addToast:o,onClose:C,onCreateTask:S}){const{sections:E,loading:I,error:M,latestRun:g,isRunInFlight:z,runError:F,refresh:R,runInsights:A,dismiss:k,createTask:D,dismissStates:v,createTaskStates:L,totalCount:N}=ds(d),[m,h]=n.useState(null),[j,u]=n.useState("info"),x=n.useMemo(()=>E.filter(a=>a.items.length>0),[E]),[y,t]=n.useState(null);n.useEffect(()=>{if(x.length===0){y!==null&&t(null);return}y&&x.some(i=>i.category===y)||t(x[0].category)},[x,y]);const e=n.useMemo(()=>x.find(a=>a.category===y)??x[0],[x,y]);n.useEffect(()=>{if(m){const a=setTimeout(()=>h(null),5e3);return()=>clearTimeout(a)}},[m]);const r=n.useCallback(async()=>{try{h("Generating insights..."),u("info"),await A(),h("Insight generation started"),u("success"),o("Insight generation started","success")}catch(a){const i=a instanceof Error?a.message:"Failed to start generation";h(i),u("error"),o(i,"error")}},[A,o]),c=n.useCallback(async(a,i)=>{try{h(`Dismissing "${i}"...`),u("info"),await k(a),h(`Dismissed "${i}"`),u("success"),o(`Insight dismissed: ${i}`,"success")}catch(l){const b=l instanceof Error?l.message:"Failed to dismiss insight";h(b),u("error"),o(b,"error")}},[k,o]),p=n.useCallback(async(a,i)=>{try{if(h(`Creating task from "${i}"...`),u("info"),!S)throw new Error("Task creation is unavailable in this view");const l=await D(a);if(!l)throw new Error("Failed to prepare task payload from insight");await S({insightId:a,title:l.title,description:l.description}),h(`Task created from "${i}"`),u("success"),o(`Task created: ${l.title}`,"success")}catch(l){const b=l instanceof Error?l.message:"Failed to create task";h(b),u("error"),o(b,"error")}},[D,S,o]),J=a=>{const i=H[a.category]??f,l=e?.category===a.category;return s.jsx("li",{children:s.jsxs("button",{type:"button",className:`insights-category-item${l?" insights-category-item--active":""}`,onClick:()=>t(a.category),"aria-current":l?"true":void 0,"data-testid":`insights-category-${a.category}`,children:[s.jsx(i,{size:16,className:"insights-category-icon"}),s.jsx("span",{className:"insights-category-label",children:a.label}),s.jsx("span",{className:"insights-category-count",children:a.items.length})]})},a.category)},K=()=>{if(!e)return null;const a=H[e.category]??f;return s.jsxs("section",{className:"insights-section","data-testid":`insights-section-${e.category}`,children:[s.jsx("div",{className:"insights-section-header",children:s.jsxs("div",{className:"insights-section-title",children:[s.jsx(a,{size:20,className:"insights-section-icon"}),s.jsx("h3",{children:e.label}),s.jsx("span",{className:"insights-section-count",children:e.items.length})]})}),s.jsx("div",{className:"insights-section-content",children:s.jsx("ul",{className:"insights-list",children:e.items.map(i=>{const l=v.get(i.id),b=L.get(i.id),G=l?.running??!1,_=b?.running??!1,O=e.items.some(U=>v.get(U.id)?.running||L.get(U.id)?.running);return s.jsxs("li",{className:"insight-item","data-insight-id":i.id,children:[s.jsxs("div",{className:"insight-item-header",children:[s.jsx("h4",{className:"insight-item-title",children:i.title}),s.jsxs("div",{className:"insight-item-actions",children:[s.jsx("button",{className:"insight-item-action-btn",onClick:()=>void p(i.id,i.title),disabled:_||O,title:"Create task from this insight","aria-label":"Create task from this insight","data-testid":`create-task-${i.id}`,children:_?s.jsx(w,{size:20,className:"spin"}):s.jsx(W,{size:20})}),s.jsx("button",{className:"insight-item-action-btn",onClick:()=>void c(i.id,i.title),disabled:G||O,title:"Dismiss this insight","aria-label":"Dismiss this insight","data-testid":`dismiss-${i.id}`,children:G?s.jsx(w,{size:20,className:"spin"}):s.jsx(q,{size:20})})]})]}),i.content&&s.jsx("p",{className:"insight-item-content",children:i.content}),s.jsxs("div",{className:"insight-item-meta",children:[s.jsx("span",{className:`insight-item-status insight-item-status--${i.status}`,children:i.status}),i.createdAt&&s.jsxs("span",{className:"insight-item-date",children:[s.jsx(X,{size:12}),new Date(i.createdAt).toLocaleDateString()]})]})]},i.id)})})})]})};return s.jsxs("div",{className:"insights-view","data-testid":"insights-view",children:[s.jsxs("div",{className:"insights-view-header",children:[s.jsxs("div",{className:"insights-view-title",children:[s.jsxs("h2",{children:[s.jsx(f,{size:20}),"Insights"]}),s.jsxs("span",{className:"insights-view-count",children:[N," total"]})]}),s.jsxs("div",{className:"insights-view-actions",children:[C&&s.jsx("button",{className:"btn btn-sm insights-view-close",onClick:C,"aria-label":"Close insights view",title:"Close",children:s.jsx(q,{size:16})}),s.jsxs("button",{className:"btn btn-sm",onClick:()=>void R(),disabled:I,"aria-label":"Refresh insights","data-testid":"refresh-insights",children:[s.jsx(w,{size:14,className:I?"spin":""}),"Refresh"]}),s.jsx("button",{className:"btn btn-primary btn-sm",onClick:()=>void r(),disabled:z,"aria-label":"Generate new insights","data-testid":"run-insights",children:z?s.jsxs(s.Fragment,{children:[s.jsx(w,{size:14,className:"spin"}),"Generating..."]}):s.jsxs(s.Fragment,{children:[s.jsx(f,{size:14}),"Generate Insights"]})})]})]}),s.jsx("div",{className:"insights-status-region","aria-live":"polite","data-testid":"insights-status",children:m&&s.jsxs("div",{className:`insights-status-message insights-status-message--${j}`,role:j==="error"?"alert":void 0,children:[j==="success"&&s.jsx(V,{size:16}),j==="error"&&s.jsx(T,{size:16}),j==="info"&&s.jsx(f,{size:16}),s.jsx("span",{children:m})]})}),F&&s.jsxs("div",{className:"insights-error-callout",role:"alert","data-testid":"run-error",children:[s.jsx(T,{size:16}),s.jsx("span",{children:F})]}),g&&s.jsx("div",{className:"insights-run-info","data-testid":"latest-run",children:s.jsxs("span",{className:"insights-run-status",children:["Latest run: ",g.status,g.status==="completed"&&s.jsxs(s.Fragment,{children:[" — ",g.insightsCreated," created, ",g.insightsUpdated," updated"]}),g.status==="failed"&&g.error&&s.jsxs(s.Fragment,{children:[" — ",g.error]})]})}),I?s.jsxs("div",{className:"insights-loading","data-testid":"insights-loading",children:[s.jsx(w,{size:24,className:"spin"}),s.jsx("p",{children:"Loading insights..."})]}):M?s.jsxs("div",{className:"insights-error","data-testid":"insights-error",children:[s.jsx(T,{size:24}),s.jsx("p",{children:M}),s.jsx("button",{className:"btn btn-sm",onClick:()=>void R(),children:"Retry"})]}):N===0?s.jsxs("div",{className:"insights-empty","data-testid":"insights-empty",children:[s.jsx(f,{size:48}),s.jsx("h3",{children:"No insights yet"}),s.jsx("p",{children:"Generate insights to get AI-powered recommendations for your project."}),s.jsxs("button",{className:"btn btn-primary",onClick:()=>void r(),children:[s.jsx(f,{size:14}),"Generate First Insights"]})]}):s.jsxs("div",{className:"insights-body",children:[s.jsx("aside",{className:"insights-sidebar","aria-label":"Insight categories",children:s.jsx("ul",{className:"insights-category-list",children:x.map(J)})}),s.jsx("div",{className:"insights-detail",children:K()})]})]})}export{ps as InsightsView};
@@ -1,14 +0,0 @@
1
- import{r as s,j as e}from"./vendor-react-K0fH_qHe.js";import{h as _e,Q as Be,U as He,V as qe,W as Ye,Y as ve,Z as me,_ as Ne,$ as ke,a0 as Xe,a1 as Ce,a2 as Se,a3 as Je,a4 as he,I as We,R as fe,C as we,P as oe,a5 as Me,a6 as Pe,a7 as Ge,a8 as Ze,X as re,a9 as ye,F as Qe,aa as be,ab as es,ac as ss,ad as ts,ae as as,af as ns,ag as ls}from"./index-DNzA4aZ7.js";import"./vendor-xterm-DzcZoU0P.js";/**
2
- * @license lucide-react v1.7.0 - ISC
3
- *
4
- * This source code is licensed under the ISC license.
5
- * See the LICENSE file in the root directory of this source tree.
6
- */const rs=[["path",{d:"M12 20h.01",key:"zekei9"}],["path",{d:"M8.5 16.429a5 5 0 0 1 7 0",key:"1bycff"}],["path",{d:"M5 12.859a10 10 0 0 1 5.17-2.69",key:"1dl1wf"}],["path",{d:"M19 12.859a10 10 0 0 0-2.007-1.523",key:"4k23kn"}],["path",{d:"M2 8.82a15 15 0 0 1 4.177-2.643",key:"1grhjp"}],["path",{d:"M22 8.82a15 15 0 0 0-11.288-3.764",key:"z3jwby"}],["path",{d:"m2 2 20 20",key:"1ooewy"}]],os=_e("wifi-off",rs);/**
7
- * @license lucide-react v1.7.0 - ISC
8
- *
9
- * This source code is licensed under the ISC license.
10
- * See the LICENSE file in the root directory of this source tree.
11
- */const cs=[["path",{d:"M12 20h.01",key:"zekei9"}],["path",{d:"M2 8.82a15 15 0 0 1 20 0",key:"dnpr2z"}],["path",{d:"M5 12.859a10 10 0 0 1 14 0",key:"1x1e6c"}],["path",{d:"M8.5 16.429a5 5 0 0 1 7 0",key:"1bycff"}]],is=_e("wifi",cs);function ie(t){const{lastSyncAt:n,remoteReachable:a,diff:o}=t,d=o.global.length+o.project.length;return n===null?{syncState:"never-synced",lastSyncAt:n,diffCount:0}:a?d>0?{syncState:"diff",lastSyncAt:n,diffCount:d}:{syncState:"synced",lastSyncAt:n,diffCount:0}:{syncState:"error",lastSyncAt:n,diffCount:d}}function Ee(t){if(t===null)return"Never synced";const n=new Date(t);if(Number.isNaN(n.getTime()))return"Never synced";const o=Date.now()-n.getTime(),d=Math.floor(o/1e3),f=Math.floor(d/60),r=Math.floor(f/60),x=Math.floor(r/24);return f<1?"Synced just now":f<60?`Synced ${f}m ago`:r<24?`Synced ${r}h ago`:`Synced ${x}d ago`}function ds(t){switch(t){case"synced":return"var(--color-success)";case"pending":return"var(--color-warning)";case"diff":return"var(--color-warning)";case"error":return"var(--color-error)";case"never-synced":return"var(--text-muted)"}}const us=3e4;function ms(){const[t,n]=s.useState({}),[a,o]=s.useState(!1),[d,f]=s.useState({}),[r,x]=s.useState(null),i=s.useRef(new Set),p=s.useRef(!1),_=s.useRef(null),k=s.useRef(null),j=s.useCallback(async(g,m)=>{try{const N=await Be(g);n(F=>({...F,[g]:N})),x(null)}catch(N){console.error(`Failed to fetch sync status for node ${g}:`,N),x(N instanceof Error?N.message:"Failed to fetch sync status")}},[]),c=s.useCallback(async()=>{const g=Array.from(i.current);if(g.length===0)return;_.current&&_.current.abort(),_.current=new AbortController;const m=!p.current;m&&o(!0),x(null);try{const N=await Promise.allSettled(g.map(O=>j(O,m)));p.current=!0,N.filter(O=>O.status==="rejected").length>0&&x("Some sync status requests failed")}catch(N){if(N instanceof Error&&N.name==="AbortError")return;x(N instanceof Error?N.message:"Failed to fetch sync status"),p.current=!0}finally{o(!1)}},[j]),C=s.useCallback(()=>{k.current&&clearInterval(k.current),k.current=setInterval(()=>{c()},us)},[c]),b=s.useCallback(()=>{k.current&&(clearInterval(k.current),k.current=null)},[]);s.useEffect(()=>(c(),C(),()=>{b(),_.current&&_.current.abort()}),[c,C,b]);const l=s.useCallback(g=>{i.current.has(g)||(i.current.add(g),j(g,!p.current))},[j]),u=s.useCallback(g=>{i.current.delete(g),n(m=>{const N={...m};return delete N[g],N}),i.current.size===0&&b()},[b]),y=s.useCallback(async g=>{f(m=>({...m,[g]:!0})),x(null);try{const m=await He(g);return j(g,!1),!m.success&&m.error&&x(m.error),m}catch(m){const N=m instanceof Error?m.message:"Push settings failed";throw x(N),m}finally{f(m=>{const N={...m};return delete N[g],N})}},[j]),E=s.useCallback(async g=>{f(m=>({...m,[g]:!0})),x(null);try{const m=await qe(g);return j(g,!1),!m.success&&m.error&&x(m.error),m}catch(m){const N=m instanceof Error?m.message:"Pull settings failed";throw x(N),m}finally{f(m=>{const N={...m};return delete N[g],N})}},[j]),A=s.useCallback(async g=>{f(m=>({...m,[g]:!0})),x(null);try{return await Ye(g)}catch(m){const N=m instanceof Error?m.message:"Auth sync failed";throw x(N),m}finally{f(m=>{const N={...m};return delete N[g],N})}},[]),P=s.useCallback(g=>t[g]?.authMatch,[t]),z=s.useCallback(g=>t[g]?.authDiff,[t]);return{syncStatusMap:t,loading:a,actionLoading:d,error:r,refresh:c,trackNode:l,untrackNode:u,pushSettings:y,pullSettings:E,syncAuth:A,getAuthSyncState:P,getAuthProviders:z}}function hs(t,n){return n.type==="remote"?t.nodeId===n.id:t.nodeId===n.id||t.nodeId===void 0||t.nodeId===null}function Re(t,n){return t.filter(a=>hs(a,n))}function ge(t,n){return Re(t,n).length}const le={online:{label:"Online",color:"var(--color-success)",className:"node-card__status--online"},offline:{label:"Offline",color:"var(--color-error)",className:"node-card__status--offline"},connecting:{label:"Connecting",color:"var(--color-warning)",className:"node-card__status--connecting"},error:{label:"Error",color:"var(--color-error)",className:"node-card__status--error"},creating:{label:"Creating",color:"var(--color-warning)",className:"node-card__status--creating"},recreating:{label:"Recreating",color:"var(--color-warning)",className:"node-card__status--recreating"},deleting:{label:"Deleting",color:"var(--color-error)",className:"node-card__status--deleting"},running:{label:"Running",color:"var(--color-success)",className:"node-card__status--online"},stopped:{label:"Stopped",color:"var(--color-error)",className:"node-card__status--offline"},exited:{label:"Exited",color:"var(--color-error)",className:"node-card__status--offline"}},fs={match:"var(--color-success)",differs:"var(--color-warning)","not-synced":"var(--text-muted)"};function gs(t,n){if(t==="match")return"Auth credentials match";if(t==="not-synced")return"Auth not synced";if(n&&Object.keys(n).length>0){const a=Object.entries(n).filter(([,o])=>o==="differs").map(([o])=>o);if(a.length>0)return`Auth credentials differ: ${a.join(", ")}`}return"Auth credentials differ"}function xs(t,n=42){return t.length<=n?t:`${t.slice(0,n-3)}...`}function ps(t,n){const a=t.node,o=n.node;if(a.id!==o.id||a.name!==o.name||a.type!==o.type||a.url!==o.url||a.status!==o.status||a.maxConcurrent!==o.maxConcurrent||a.updatedAt!==o.updatedAt||t.isLoading!==n.isLoading)return!1;const d=t.managedDockerNode,f=n.managedDockerNode;if(!!d!=!!f||d&&f&&(d.id!==f.id||d.status!==f.status||d.imageTag!==f.imageTag||d.updatedAt!==f.updatedAt))return!1;const r=t.syncStatus,x=n.syncStatus;if(!(!r&&!x)){if(!r||!x)return!1;if(r.syncState!==x.syncState||r.lastSyncAt!==x.lastSyncAt||r.diffCount!==x.diffCount)return!1}if(t.authSyncState!==n.authSyncState)return!1;const i=t.authSyncProviders,p=n.authSyncProviders;if(i!==p){if(!i||!p)return!1;{const j=Object.keys(i),c=Object.keys(p);if(j.length!==c.length||j.some(C=>i[C]!==p[C]))return!1}}const _=ge(t.projects,a),k=ge(n.projects,o);return _===k}function ys({node:t,projects:n,onHealthCheck:a,onEdit:o,onRemove:d,isLoading:f=!1,syncStatus:r,authSyncState:x,authSyncProviders:i,managedDockerNode:p}){const[_,k]=s.useState(!1),j=le[t.status]??le.offline,c=p?le[p.status]??le.error:null,C=p?.hostConfig.type==="remote"?`Remote: ${p.hostConfig.host??"unknown"}`:"Local Docker",b=s.useMemo(()=>ge(n,t),[n,t]),l=s.useCallback(()=>{o(t)},[o,t]),u=s.useCallback(P=>{P.stopPropagation(),a(t.id)},[a,t.id]),y=s.useCallback(P=>{P.stopPropagation(),o(t)},[o,t]),E=s.useCallback(P=>{if(P.stopPropagation(),!_){k(!0);return}d(t.id),k(!1)},[_,d,t.id]),A=s.useCallback(P=>{(P.key==="Enter"||P.key===" ")&&(P.preventDefault(),o(t))},[o,t]);return e.jsxs("article",{className:`node-card ${f?"node-card--loading":""}`,"data-node-id":t.id,role:"button",tabIndex:0,onClick:l,onKeyDown:A,children:[e.jsx("header",{className:"node-card__header",children:e.jsxs("div",{className:"node-card__title-wrap",children:[e.jsx("div",{className:"node-card__icon",children:e.jsx(ve,{size:18})}),e.jsxs("div",{children:[e.jsx("h3",{className:"node-card__name",title:t.name,children:t.name}),e.jsxs("div",{className:"node-card__meta-row",children:[e.jsx("span",{className:"node-card__type-badge",children:t.type==="local"?"Local":"Remote"}),p&&e.jsxs("span",{className:"node-card__docker-badge",title:"Managed Docker node",children:[e.jsx(me,{size:12,"aria-hidden":!0}),"Docker"]}),e.jsxs("span",{className:`node-card__status ${j.className}`,style:{color:j.color},"data-status":t.status,children:[e.jsx("span",{className:"node-card__status-indicator",style:{backgroundColor:j.color},"aria-hidden":!0}),j.label]}),p&&c&&e.jsxs("span",{className:`node-card__status ${c.className}`,style:{color:c.color},"data-status":p.status,children:[e.jsx("span",{className:"node-card__status-indicator",style:{backgroundColor:c.color},"aria-hidden":!0}),c.label]}),t.type==="remote"&&x&&e.jsx("span",{className:`node-card__auth-indicator node-card__auth-indicator--${x}`,title:gs(x,i),"aria-label":`Auth sync: ${x==="match"?"credentials match":x==="differs"?"credentials differ":"not synced"}`,style:{color:fs[x]},children:e.jsx(Ne,{size:14})})]})]})]})}),e.jsxs("div",{className:"node-card__body",children:[t.type==="remote"&&t.url&&e.jsx("div",{className:"node-card__url",title:t.url,children:xs(t.url)}),p&&e.jsxs("div",{className:"node-card__docker-meta",children:[e.jsxs("span",{title:`${p.imageName}:${p.imageTag}`,children:[p.imageName,":",p.imageTag]}),e.jsx("span",{title:C,children:C})]}),e.jsxs("div",{className:"node-card__metrics",children:[e.jsxs("div",{className:"node-card__metric",children:[e.jsx("span",{className:"node-card__metric-label",children:"Projects"}),e.jsx("span",{className:"node-card__metric-value",children:b})]}),e.jsxs("div",{className:"node-card__metric",children:[e.jsx("span",{className:"node-card__metric-label",children:"Concurrency"}),e.jsx("span",{className:"node-card__metric-value",children:t.maxConcurrent})]})]}),t.type==="remote"&&r&&e.jsxs("div",{className:"node-card__sync","data-sync-state":r.syncState,"data-testid":"node-card-sync",children:[e.jsx("span",{className:"node-card__sync-dot",style:{backgroundColor:ds(r.syncState)},"aria-hidden":!0}),e.jsx("span",{className:"node-card__sync-time",children:Ee(r.lastSyncAt)})]})]}),e.jsxs("footer",{className:"node-card__actions",children:[e.jsxs("button",{className:"btn btn-sm node-card__action",type:"button",onClick:u,disabled:f,"aria-label":"Run node health check",title:"Health Check",children:[e.jsx(ke,{size:14}),e.jsx("span",{children:"Health"})]}),e.jsxs("button",{className:"btn btn-sm node-card__action",type:"button",onClick:y,disabled:f,"aria-label":"Edit node",title:"Edit",children:[e.jsx(Xe,{size:14}),e.jsx("span",{children:"Edit"})]}),p&&e.jsxs(e.Fragment,{children:[e.jsxs("button",{className:"btn btn-sm node-card__action",type:"button",disabled:!0,"aria-label":"Start node container",title:"Available after FN-3113",children:[e.jsx(Ce,{size:14}),e.jsx("span",{children:"Start"})]}),e.jsxs("button",{className:"btn btn-sm node-card__action",type:"button",disabled:!0,"aria-label":"Stop node container",title:"Available after FN-3113",children:[e.jsx(Se,{size:14}),e.jsx("span",{children:"Stop"})]}),e.jsxs("button",{className:"btn btn-sm node-card__action",type:"button",disabled:!0,"aria-label":"Restart node container",title:"Available after FN-3113",children:[e.jsx(Je,{size:14}),e.jsx("span",{children:"Restart"})]})]}),e.jsxs("button",{className:`btn btn-sm node-card__action node-card__action--remove ${_?"btn-danger is-armed":""}`,type:"button",onClick:E,disabled:f,"aria-label":_?"Confirm remove node":"Remove node",title:_?"Confirm remove":"Remove",children:[e.jsx(he,{size:14}),e.jsx("span",{children:_?"Confirm":"Remove"})]})]})]})}const bs=s.memo(ys,ps),se={online:"var(--success, var(--color-success))",offline:"var(--text-dim)",connecting:"var(--triage)",error:"var(--color-error)"},Q=28,je=12,js=300,_s=120;function vs({nodes:t,className:n}){const a=s.useMemo(()=>t.find(i=>i.type==="local")??t[0],[t]),o=s.useMemo(()=>t.filter(i=>i.type==="remote"),[t]),d=s.useMemo(()=>{const i=js,p=Math.max(0,o.length-4)*20;return i+p},[o.length]),f=d/2,r=d/2,x=s.useMemo(()=>{if(o.length===0)return[];const i=Math.min(_s,d/2-Q-10),p=2*Math.PI/o.length,_=-Math.PI/2;return o.map((k,j)=>{const c=_+j*p;return{node:k,x:f+i*Math.cos(c),y:r+i*Math.sin(c)}})},[o,d,f,r]);return t.length===0?e.jsx("div",{className:`mesh-topology mesh-topology--empty ${n??""}`,children:e.jsx("div",{className:"mesh-topology__empty-state",children:e.jsx("p",{children:"No nodes to display"})})}):e.jsxs("div",{className:`mesh-topology ${n??""}`,children:[e.jsxs("svg",{className:"mesh-topology__svg",viewBox:`0 0 ${d} ${d}`,preserveAspectRatio:"xMidYMid meet","aria-label":"Node mesh topology visualization",children:[x.map(i=>e.jsx("line",{className:"mesh-topology__link",x1:f,y1:r,x2:i.x,y2:i.y},`link-${i.node.id}`)),a&&e.jsxs("g",{className:"mesh-topology__node",transform:`translate(${f}, ${r})`,children:[e.jsx("circle",{className:"mesh-topology__node-circle",r:Q,fill:se[a.status],"aria-label":`${a.name} (${a.status})`}),e.jsx("text",{className:"mesh-topology__node-label",y:Q+je,textAnchor:"middle",children:a.name.length>12?`${a.name.slice(0,10)}…`:a.name}),e.jsxs("g",{className:"mesh-topology__node-type",transform:`translate(0 ${-Q-10})`,children:[e.jsx("circle",{className:"mesh-topology__node-type-badge",r:"8"}),e.jsx("text",{className:"mesh-topology__node-type-text",textAnchor:"middle",dominantBaseline:"middle",children:a.type==="local"?"L":"R"})]})]}),x.map(i=>e.jsxs("g",{className:"mesh-topology__node",transform:`translate(${i.x}, ${i.y})`,children:[e.jsx("circle",{className:"mesh-topology__node-circle",r:Q,fill:se[i.node.status],"aria-label":`${i.node.name} (${i.node.status})`}),e.jsx("text",{className:"mesh-topology__node-label",y:Q+je,textAnchor:"middle",children:i.node.name.length>12?`${i.node.name.slice(0,10)}…`:i.node.name}),e.jsxs("g",{className:"mesh-topology__node-type",transform:`translate(0 ${-Q-10})`,children:[e.jsx("circle",{className:"mesh-topology__node-type-badge",r:"8"}),e.jsx("text",{className:"mesh-topology__node-type-text",textAnchor:"middle",dominantBaseline:"middle",children:i.node.type==="local"?"L":"R"})]})]},i.node.id))]}),e.jsxs("div",{className:"mesh-topology__legend",children:[e.jsxs("div",{className:"mesh-topology__legend-item",children:[e.jsx("span",{className:"mesh-topology__legend-dot",style:{background:se.online}}),e.jsx("span",{children:"Online"})]}),e.jsxs("div",{className:"mesh-topology__legend-item",children:[e.jsx("span",{className:"mesh-topology__legend-dot",style:{background:se.offline}}),e.jsx("span",{children:"Offline"})]}),e.jsxs("div",{className:"mesh-topology__legend-item",children:[e.jsx("span",{className:"mesh-topology__legend-dot",style:{background:se.connecting}}),e.jsx("span",{children:"Connecting"})]}),e.jsxs("div",{className:"mesh-topology__legend-item",children:[e.jsx("span",{className:"mesh-topology__legend-dot",style:{background:se.error}}),e.jsx("span",{children:"Error"})]})]}),e.jsx("p",{className:"mesh-topology__notice",children:"Peer-to-peer discovery data unavailable."})]})}const Ns=s.memo(vs),xe=1,pe=10;function ks(t){const n={};return t.name.trim()||(n.name="Name is required"),t.type==="remote"&&!t.url?.trim()&&(n.url="URL is required for remote nodes"),(!Number.isFinite(t.maxConcurrent)||t.maxConcurrent<xe||t.maxConcurrent>pe)&&(n.maxConcurrent=`Concurrency must be between ${xe} and ${pe}`),n}function Cs({isOpen:t,onClose:n,onSubmit:a,addToast:o}){We(t);const[d,f]=s.useState(""),[r,x]=s.useState("local"),[i,p]=s.useState(""),[_,k]=s.useState(""),[j,c]=s.useState(2),[C,b]=s.useState("auto-generate"),[l,u]=s.useState({}),[y,E]=s.useState(!1),A=s.useCallback(()=>{f(""),x("local"),p(""),k(""),c(2),b("auto-generate"),u({}),E(!1)},[]),P=s.useCallback(()=>{y||(A(),n())},[y,n,A]);s.useEffect(()=>{if(!t){A();return}const m=N=>{N.key==="Escape"&&(N.preventDefault(),P())};return document.addEventListener("keydown",m),()=>{document.removeEventListener("keydown",m)}},[P,t,A]);const z=s.useMemo(()=>({name:d.trim(),type:r,url:r==="remote"&&i.trim()||void 0,apiKey:r==="remote"&&C==="provide"&&_||void 0,maxConcurrent:j,apiKeyMode:C}),[_,C,j,d,r,i]),g=s.useCallback(async()=>{if(y)return;const m=ks(z);if(u(m),!(Object.keys(m).length>0)){E(!0);try{await a(z),o(`Node "${z.name}" registered`,"success"),P()}catch(N){const F=N instanceof Error?N.message:"Failed to register node";o(F,"error")}finally{E(!1)}}},[o,P,z,y,a]);return t?e.jsx("div",{className:"modal-overlay open",onClick:P,children:e.jsxs("div",{className:"modal modal-md add-node-modal",onClick:m=>m.stopPropagation(),role:"dialog","aria-modal":"true","aria-label":"Add Node",children:[e.jsxs("div",{className:"modal-header",children:[e.jsx("h3",{children:"Add Node"}),e.jsx("button",{className:"modal-close",onClick:P,disabled:y,"aria-label":"Close add node modal",children:"×"})]}),e.jsxs("div",{className:"modal-body add-node-modal__body",children:[e.jsx("p",{className:"add-node-modal__description",children:"Register an existing Fusion node by providing its connection details and concurrency settings."}),e.jsxs("label",{className:"add-node-modal__field",children:[e.jsx("span",{children:"Name"}),e.jsx("input",{className:"input",type:"text",value:d,onChange:m=>f(m.target.value),placeholder:"Build Machine",disabled:y,"aria-invalid":!!l.name,autoFocus:!0}),l.name&&e.jsx("span",{className:"form-error add-node-modal__error",children:l.name})]}),e.jsxs("div",{className:"add-node-modal__type-toggle",children:[e.jsx("button",{type:"button",className:`add-node-modal__type-btn ${r==="local"?"active":""}`,"data-type":"local",onClick:()=>x("local"),disabled:y,"aria-pressed":r==="local",children:"Local"}),e.jsx("button",{type:"button",className:`add-node-modal__type-btn ${r==="remote"?"active":""}`,"data-type":"remote",onClick:()=>x("remote"),disabled:y,"aria-pressed":r==="remote",children:"Remote"})]}),r==="remote"&&e.jsxs("div",{className:"add-node-modal__remote-fields","data-testid":"remote-fields-container","data-visible":!0,children:[e.jsxs("label",{className:"add-node-modal__field",children:[e.jsx("span",{children:"Reachable URL / Hostname"}),e.jsx("input",{className:"input",type:"text",value:i,onChange:m=>p(m.target.value),placeholder:"https://node.example.com",disabled:y,"aria-invalid":!!l.url}),l.url&&e.jsx("span",{className:"form-error add-node-modal__error",children:l.url})]}),e.jsxs("label",{className:"add-node-modal__field",children:[e.jsx("span",{children:"API Key Mode"}),e.jsxs("select",{className:"select",value:C,onChange:m=>b(m.target.value),disabled:y,children:[e.jsx("option",{value:"auto-generate",children:"Auto-generate"}),e.jsx("option",{value:"provide",children:"Provide key manually"})]})]}),C==="provide"&&e.jsxs("label",{className:"add-node-modal__field",children:[e.jsx("span",{children:"API Key"}),e.jsx("input",{className:"input",type:"password",value:_,onChange:m=>k(m.target.value),placeholder:"Enter node API key",disabled:y})]})]}),e.jsxs("label",{className:"add-node-modal__field",children:[e.jsx("span",{children:"Max Concurrent"}),e.jsx("input",{className:"input",type:"number",min:xe,max:pe,value:j,onChange:m=>c(Number(m.target.value)),disabled:y,"aria-invalid":!!l.maxConcurrent}),e.jsx("span",{className:"add-node-modal__hint",children:"Max simultaneous task agents (1–10)"}),l.maxConcurrent&&e.jsx("span",{className:"form-error add-node-modal__error",children:l.maxConcurrent})]})]}),e.jsxs("div",{className:"modal-actions",children:[e.jsx("button",{className:"btn btn-sm",onClick:P,disabled:y,children:"Cancel"}),e.jsx("button",{className:"btn btn-primary btn-sm","data-testid":"add-node-submit",onClick:g,disabled:y,children:y?"Adding...":"Add Node"})]})]})}):null}function Ss(){const[t,n]=s.useState([]),[a,o]=s.useState(!1),[d,f]=s.useState(null),[r,x]=s.useState(!1),[i,p]=s.useState(null),[_,k]=s.useState(!1),j=s.useCallback(async()=>{o(!0),f(null);try{const b=await fetch("/api/docker/contexts");if(!b.ok)throw new Error(`Failed to load Docker contexts (${b.status})`);const l=await b.json();return n(l),l}catch(b){const l=b instanceof Error?b.message:String(b);throw f(l),b}finally{o(!1)}},[]),c=s.useCallback(async b=>{x(!0);try{const l=await fetch("/api/docker/test-connection",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({hostConfig:b})});if(!l.ok)throw new Error(`Failed to test Docker connection (${l.status})`);const u=await l.json();return p(u),u}finally{x(!1)}},[]),C=s.useCallback(async()=>{k(!0);try{const b=await fetch("/api/docker/local-available");if(!b.ok)throw new Error(`Failed to check local Docker availability (${b.status})`);return await b.json()}finally{k(!1)}},[]);return{contexts:t,isLoadingContexts:a,contextsError:d,loadContexts:j,isTestingConnection:r,lastTestResult:i,testConnection:c,isCheckingLocal:_,checkLocalDocker:C}}function ws({value:t,onChange:n}){const[a,o]=s.useState(!!(t?.tlsCaPath||t?.tlsCertPath||t?.tlsKeyPath||t?.tlsVerify));s.useEffect(()=>{a||n({tlsVerify:void 0,tlsCaPath:void 0,tlsCertPath:void 0,tlsKeyPath:void 0})},[a,n]);const d=s.useMemo(()=>({tlsVerify:t?.tlsVerify??!0,tlsCaPath:t?.tlsCaPath??"",tlsCertPath:t?.tlsCertPath??"",tlsKeyPath:t?.tlsKeyPath??""}),[t]);return e.jsxs("div",{className:"docker-tls-config",children:[e.jsxs("label",{className:"checkbox-label",children:[e.jsx("input",{type:"checkbox",checked:a,onChange:f=>o(f.target.checked)}),"Use TLS"]}),a&&e.jsxs("div",{className:"docker-tls-config__fields",children:[e.jsxs("div",{className:"docker-tls-config__field",children:[e.jsx("label",{htmlFor:"docker-tls-ca-path",children:"CA Certificate Path"}),e.jsx("input",{id:"docker-tls-ca-path",className:"input",value:d.tlsCaPath,onChange:f=>n({...d,tlsCaPath:f.target.value}),placeholder:"/etc/docker/ca.pem"})]}),e.jsxs("div",{className:"docker-tls-config__field",children:[e.jsx("label",{htmlFor:"docker-tls-cert-path",children:"Client Certificate Path"}),e.jsx("input",{id:"docker-tls-cert-path",className:"input",value:d.tlsCertPath,onChange:f=>n({...d,tlsCertPath:f.target.value}),placeholder:"/etc/docker/cert.pem"})]}),e.jsxs("div",{className:"docker-tls-config__field",children:[e.jsx("label",{htmlFor:"docker-tls-key-path",children:"Client Key Path"}),e.jsx("input",{id:"docker-tls-key-path",className:"input",value:d.tlsKeyPath,onChange:f=>n({...d,tlsKeyPath:f.target.value}),placeholder:"/etc/docker/key.pem"})]}),e.jsxs("label",{className:"checkbox-label",children:[e.jsx("input",{type:"checkbox",checked:d.tlsVerify,onChange:f=>n({...d,tlsVerify:f.target.checked})}),"Verify TLS Certificate"]})]})]})}function Ms({value:t,onChange:n,onError:a}){const o=t?.context?"context":t?.host?"host":"local",[d,f]=s.useState(o),[r,x]=s.useState(t?.context??""),[i,p]=s.useState(t?.host??""),[_,k]=s.useState(null),{contexts:j,isLoadingContexts:c,contextsError:C,loadContexts:b,testConnection:l,isTestingConnection:u,lastTestResult:y,checkLocalDocker:E,isCheckingLocal:A}=Ss(),P=s.useMemo(()=>({tlsVerify:t?.tlsVerify,tlsCaPath:t?.tlsCaPath,tlsCertPath:t?.tlsCertPath,tlsKeyPath:t?.tlsKeyPath}),[t]);s.useEffect(()=>{if(d==="local"){n({});return}if(d==="context"){b().catch(g=>a?.(g instanceof Error?g.message:String(g))),n(r?{context:r}:{});return}n({host:i,...P})},[d]);const z=s.useCallback(g=>{d==="host"&&n({host:i,...g})},[i,d,n]);return e.jsxs("div",{className:"docker-target-selector",children:[e.jsxs("div",{className:"docker-target-selector__modes",role:"group","aria-label":"Docker target mode",children:[e.jsx("button",{type:"button",className:`btn btn-sm ${d==="local"?"docker-target-selector__mode-active":""}`,onClick:()=>{f("local"),E().then(g=>k(g.available?`Docker is available${g.version?` (${g.version})`:""}`:`Docker not found${g.error?`: ${g.error}`:""}`)).catch(g=>{const m=g instanceof Error?g.message:String(g);k(`Docker not found: ${m}`),a?.(m)})},children:"Local Docker"}),e.jsx("button",{type:"button",className:`btn btn-sm ${d==="context"?"docker-target-selector__mode-active":""}`,onClick:()=>f("context"),children:"Docker Context"}),e.jsx("button",{type:"button",className:`btn btn-sm ${d==="host"?"docker-target-selector__mode-active":""}`,onClick:()=>f("host"),children:"Remote Host"})]}),d==="local"&&_&&e.jsx("div",{className:"docker-target-selector__status",children:_}),d==="context"&&e.jsxs("div",{className:"docker-target-selector__panel",children:[e.jsxs("div",{className:"docker-target-selector__context-row",children:[e.jsxs("select",{className:"select",value:r,onChange:g=>{const m=g.target.value;x(m),n(m?{context:m}:{})},children:[e.jsx("option",{value:"",children:"Select context"}),j.map(g=>e.jsxs("option",{value:g.name,children:[g.name,g.isCurrentContext?" (current)":"",g.dockerHost?` — ${g.dockerHost}`:""]},g.name))]}),e.jsx("button",{type:"button",className:"btn btn-sm btn-icon",onClick:()=>void b(),disabled:c,"aria-label":"Refresh contexts",children:e.jsx(fe,{size:14})})]}),C&&e.jsx("div",{className:"docker-target-selector__error",children:C})]}),d==="host"&&e.jsxs("div",{className:"docker-target-selector__panel",children:[e.jsxs("div",{className:"docker-target-selector__field",children:[e.jsx("label",{htmlFor:"docker-target-selector-host",children:"Docker Host"}),e.jsx("input",{id:"docker-target-selector-host",className:"input",placeholder:"tcp://host:2376",value:i,onChange:g=>{const m=g.target.value;p(m),n({host:m,...P})}})]}),e.jsx(ws,{value:P,onChange:z})]}),e.jsx("button",{type:"button",className:"btn btn-sm",onClick:()=>void l(d==="local"?void 0:d==="context"?{context:r}:{host:i,...P}),disabled:u||A,children:u?"Testing...":"Test Connection"}),y&&e.jsx("div",{className:y.success?"docker-target-selector__success":"docker-target-selector__error",children:y.success?`Connected${y.dockerVersion?` (Docker ${y.dockerVersion})`:""}`:y.error??"Connection failed"})]})}const de="http://localhost:4040";function Ps({isOpen:t,onClose:n,onSubmit:a,addToast:o}){const[d,f]=s.useState(""),[r,x]=s.useState({}),[i,p]=s.useState(de),[_,k]=s.useState("auto"),[j,c]=s.useState(""),[C,b]=s.useState(!1),[l,u]=s.useState(!1),[y,E]=s.useState(!0),[A,P]=s.useState(4096),[z,g]=s.useState(2),[m,N]=s.useState(!1),[F,O]=s.useState("runfusion/fusion"),[R,H]=s.useState("latest"),[V,X]=s.useState([]),[J,q]=s.useState([]),[U,W]=s.useState({}),[M,T]=s.useState(!1),S=s.useCallback(()=>{f(""),x({}),p(de),k("auto"),c(""),b(!1),u(!1),E(!0),P(4096),g(2),N(!1),O("runfusion/fusion"),H("latest"),X([]),q([]),W({}),T(!1)},[]),w=s.useCallback(()=>{M||(S(),n())},[n,S,M]);s.useEffect(()=>{if(!t){S();return}const h=L=>{L.key==="Escape"&&(L.preventDefault(),w())};return document.addEventListener("keydown",h),()=>document.removeEventListener("keydown",h)},[w,t,S]);const D=s.useMemo(()=>({nodeId:null,name:d.trim(),imageName:F.trim()||"runfusion/fusion",imageTag:R.trim()||"latest",hostConfig:{context:r.context?.trim()||void 0,host:r.host?.trim()||void 0,tlsVerify:r.tlsVerify,tlsCaPath:r.tlsCaPath?.trim()||void 0,tlsCertPath:r.tlsCertPath?.trim()||void 0,tlsKeyPath:r.tlsKeyPath?.trim()||void 0},envVars:Object.fromEntries(V.map(h=>[h.key.trim(),h.value]).filter(([h])=>!!h)),volumeMounts:J.map(h=>({hostPath:h.hostPath.trim(),containerPath:h.containerPath.trim(),mode:h.mode})).filter(h=>h.hostPath&&h.containerPath),resourceSizing:{memoryMB:A,cpus:z},extraClis:[C?"claude-cli":null,l?"droid-cli":null].filter(Boolean),persistentStorage:y,reachableUrl:i.trim()||null,apiKey:_==="manual"&&j.trim()||null}),[j,_,z,r,V,F,R,C,l,A,J,d,y,i]),Y=s.useCallback(()=>{X(h=>[...h,{key:"",value:""}])},[]),G=s.useCallback((h,L)=>{X(I=>I.map((B,ne)=>ne===h?L:B))},[]),ee=s.useCallback(h=>{X(L=>L.filter((I,B)=>B!==h))},[]),K=s.useCallback(()=>{q(h=>[...h,{hostPath:"",containerPath:"",mode:"rw"}])},[]),te=s.useCallback((h,L)=>{q(I=>I.map((B,ne)=>ne===h?L:B))},[]),ae=s.useCallback(h=>{q(L=>L.filter((I,B)=>B!==h))},[]),ce=s.useCallback(async()=>{if(M)return;const h={};if((!D.name||D.name.length>64)&&(h.name="Name is required and must be 64 characters or fewer"),D.reachableUrl||(h.reachableUrl="URL is required"),A<512&&(h.memoryMB="Memory must be at least 512 MB"),z<.5&&(h.cpus="CPUs must be at least 0.5"),W(h),!(Object.keys(h).length>0)){T(!0);try{await a(D),w()}catch{}finally{T(!1)}}},[w,z,D,A,a,M]);return t?e.jsx("div",{className:"modal-overlay open",onClick:w,children:e.jsxs("div",{className:"modal docker-onboarding",role:"dialog","aria-modal":"true","aria-label":"Docker node onboarding",onClick:h=>h.stopPropagation(),children:[e.jsxs("div",{className:"modal-header",children:[e.jsx("h3",{children:"Provision Docker Node"}),e.jsx("button",{className:"modal-close",onClick:w,disabled:M,"aria-label":"Close onboarding modal",children:"×"})]}),e.jsxs("div",{className:"modal-body docker-onboarding__body",children:[e.jsxs("section",{className:"docker-onboarding__section",children:[e.jsx("h4",{className:"docker-onboarding__section-title",children:"Required Settings"}),e.jsxs("label",{className:"docker-onboarding__field",children:[e.jsx("span",{children:"Node Name"}),e.jsx("input",{className:"input",value:d,onChange:h=>f(h.target.value),disabled:M,placeholder:"my-docker-node",autoFocus:!0})]}),U.name&&e.jsx("div",{className:"form-error",children:U.name}),e.jsx(Ms,{value:r,onChange:x}),e.jsxs("label",{className:"docker-onboarding__field",children:[e.jsx("span",{children:"Reachable URL"}),e.jsx("input",{className:"input",value:i,onChange:h=>p(h.target.value),disabled:M,placeholder:de})]}),U.reachableUrl&&e.jsx("div",{className:"form-error",children:U.reachableUrl}),e.jsxs("div",{className:"docker-onboarding__radio-group",children:[e.jsxs("label",{className:"checkbox-label",children:[e.jsx("input",{type:"radio",checked:_==="auto",onChange:()=>k("auto"),disabled:M}),"Auto-generate"]}),e.jsxs("label",{className:"checkbox-label",children:[e.jsx("input",{type:"radio",checked:_==="manual",onChange:()=>k("manual"),disabled:M}),"Provide manually"]})]}),_==="manual"&&e.jsxs("label",{className:"docker-onboarding__field",children:[e.jsx("span",{children:"API Key"}),e.jsx("input",{className:"input",type:"password",value:j,onChange:h=>c(h.target.value),disabled:M,placeholder:"Enter API key"})]}),e.jsxs("div",{className:"docker-onboarding__checkbox-group",children:[e.jsxs("label",{className:"checkbox-label",children:[e.jsx("input",{type:"checkbox",checked:C,onChange:h=>b(h.target.checked),disabled:M}),"Claude CLI"]}),e.jsxs("label",{className:"checkbox-label",children:[e.jsx("input",{type:"checkbox",checked:l,onChange:h=>u(h.target.checked),disabled:M}),"Droid CLI"]}),e.jsxs("label",{className:"checkbox-label",children:[e.jsx("input",{type:"checkbox",checked:y,onChange:h=>E(h.target.checked),disabled:M}),"Keep data across container recreations"]})]}),e.jsxs("div",{className:"docker-onboarding__inline-fields",children:[e.jsxs("label",{className:"docker-onboarding__field",children:[e.jsx("span",{children:"Memory (MB)"}),e.jsx("input",{className:"input",type:"number",min:512,value:A,onChange:h=>P(Number(h.target.value)),disabled:M})]}),e.jsxs("label",{className:"docker-onboarding__field",children:[e.jsx("span",{children:"CPUs"}),e.jsx("input",{className:"input",type:"number",min:.5,step:.5,value:z,onChange:h=>g(Number(h.target.value)),disabled:M})]})]}),U.memoryMB&&e.jsx("div",{className:"form-error",children:U.memoryMB}),U.cpus&&e.jsx("div",{className:"form-error",children:U.cpus})]}),e.jsxs("section",{className:"docker-onboarding__section",children:[e.jsxs("button",{type:"button",className:`docker-onboarding__advanced-toggle ${m?"is-expanded":""}`,onClick:()=>N(h=>!h),disabled:M,children:[e.jsx("span",{children:"Advanced"}),e.jsx(we,{})]}),e.jsx("div",{className:`docker-onboarding__advanced-content ${m?"is-expanded":""}`,children:e.jsxs("div",{children:[e.jsxs("div",{className:"docker-onboarding__inline-fields",children:[e.jsxs("label",{className:"docker-onboarding__field",children:[e.jsx("span",{children:"Image"}),e.jsx("input",{className:"input",value:F,onChange:h=>O(h.target.value),disabled:M,placeholder:"runfusion/fusion"})]}),e.jsxs("label",{className:"docker-onboarding__field",children:[e.jsx("span",{children:"Tag"}),e.jsx("input",{className:"input",value:R,onChange:h=>H(h.target.value),disabled:M,placeholder:"latest"})]})]}),e.jsxs("div",{className:"docker-onboarding__kv-list",children:[e.jsx("h5",{children:"Environment Variables"}),V.map((h,L)=>e.jsxs("div",{className:"docker-onboarding__kv-row docker-onboarding__kv-row--env",children:[e.jsx("input",{className:"input",placeholder:"KEY",value:h.key,disabled:M,onChange:I=>G(L,{key:I.target.value,value:h.value})}),e.jsx("input",{className:"input",placeholder:"Value",value:h.value,disabled:M,onChange:I=>G(L,{key:h.key,value:I.target.value})}),e.jsx("button",{type:"button",className:"btn btn-icon","aria-label":"Remove environment variable",onClick:()=>ee(L),disabled:M,children:e.jsx(he,{size:14})})]},`env-${L}`)),e.jsxs("button",{type:"button",className:"btn btn-sm docker-onboarding__kv-add",onClick:Y,disabled:M,children:[e.jsx(oe,{size:14}),"Add variable"]})]}),e.jsxs("div",{className:"docker-onboarding__kv-list",children:[e.jsx("h5",{children:"Volume Mounts"}),J.map((h,L)=>e.jsxs("div",{className:"docker-onboarding__kv-row docker-onboarding__kv-row--mount",children:[e.jsx("input",{className:"input",placeholder:"Host path",value:h.hostPath,disabled:M,onChange:I=>te(L,{hostPath:I.target.value,containerPath:h.containerPath,mode:h.mode})}),e.jsx("input",{className:"input",placeholder:"Container path",value:h.containerPath,disabled:M,onChange:I=>te(L,{hostPath:h.hostPath,containerPath:I.target.value,mode:h.mode})}),e.jsxs("select",{className:"select",value:h.mode,disabled:M,onChange:I=>te(L,{hostPath:h.hostPath,containerPath:h.containerPath,mode:I.target.value==="ro"?"ro":"rw"}),children:[e.jsx("option",{value:"rw",children:"rw"}),e.jsx("option",{value:"ro",children:"ro"})]}),e.jsx("button",{type:"button",className:"btn btn-icon","aria-label":"Remove volume mount",onClick:()=>ae(L),disabled:M,children:e.jsx(he,{size:14})})]},`mount-${L}`)),e.jsxs("button",{type:"button",className:"btn btn-sm docker-onboarding__kv-add",onClick:K,disabled:M,children:[e.jsx(oe,{size:14}),"Add mount"]})]})]})})]})]}),e.jsxs("div",{className:"modal-actions",children:[e.jsx("button",{className:"btn",onClick:w,disabled:M,children:"Cancel"}),e.jsx("button",{className:"btn btn-primary",onClick:()=>void ce(),disabled:M,children:M?"Creating...":"Create Docker Node"})]})]})}):null}function Es({nodeId:t,entries:n,loading:a=!1,singleNode:o=!1}){const[d,f]=s.useState(!1),[r,x]=s.useState("all"),[i,p]=s.useState("all"),_=s.useCallback(()=>{f(l=>!l)},[]),k=s.useMemo(()=>{const l=new Set;for(const u of n)l.add(u.nodeName);return Array.from(l).sort()},[n]),j=s.useMemo(()=>{let l=[...n];return r!=="all"&&(l=l.filter(u=>u.direction===r)),!o&&i!=="all"&&(l=l.filter(u=>u.nodeName===i)),l.sort((u,y)=>{const E=new Date(u.timestamp).getTime();return new Date(y.timestamp).getTime()-E}),l},[n,r,i,o]),c=s.useCallback(l=>new Date(l).toLocaleString(),[]),C=s.useCallback(l=>{switch(l){case"success":return"settings-sync-log__badge--success";case"conflict":return"settings-sync-log__badge--conflict";case"error":return"settings-sync-log__badge--error";default:return""}},[]),b=s.useCallback(l=>{switch(l){case"success":return"Success";case"conflict":return"Conflict";case"error":return"Error";default:return l}},[]);return e.jsxs("div",{className:"settings-sync-log",children:[e.jsxs("button",{className:"settings-sync-log__header",type:"button",onClick:_,"aria-expanded":d,"data-testid":"settings-sync-log-header",children:[e.jsx(we,{size:16,className:`settings-sync-log__chevron ${d?"settings-sync-log__chevron--expanded":""}`}),e.jsxs("span",{children:[n.length," ",n.length===1?"entry":"entries"]})]}),d&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"settings-sync-log__filters",children:[e.jsxs("label",{children:["Direction:",e.jsxs("select",{value:r,onChange:l=>x(l.target.value),children:[e.jsx("option",{value:"all",children:"All"}),e.jsx("option",{value:"push",children:"Push"}),e.jsx("option",{value:"pull",children:"Pull"})]})]}),!o&&e.jsxs("label",{children:["Node:",e.jsxs("select",{value:i,onChange:l=>p(l.target.value),children:[e.jsx("option",{value:"all",children:"All Nodes"}),k.map(l=>e.jsx("option",{value:l,children:l},l))]})]})]}),a&&n.length===0?e.jsx("div",{className:"settings-sync-log__empty",children:"Loading..."}):j.length===0?e.jsx("div",{className:"settings-sync-log__empty",children:"No sync history available"}):e.jsx("div",{className:"settings-sync-log__list",children:j.map(l=>e.jsxs("div",{className:"settings-sync-log__entry",children:[e.jsx("span",{className:"settings-sync-log__entry-timestamp",children:c(l.timestamp)}),e.jsx("span",{className:"settings-sync-log__entry-direction",children:l.direction==="push"?e.jsx(Me,{size:14,"data-testid":"upload-icon"}):e.jsx(Pe,{size:14,"data-testid":"download-icon"})}),e.jsx("span",{className:`settings-sync-log__entry-result ${C(l.result)}`,children:b(l.result)}),!o&&e.jsx("span",{className:"settings-sync-log__entry-node",children:l.nodeName}),l.details&&e.jsx("span",{className:"settings-sync-log__entry-details",title:l.details,children:l.details})]},l.id))})]})]})}function Rs(t,n){const a=typeof t=="string"?t:JSON.stringify(t,null,2),o=typeof n=="string"?n:JSON.stringify(n,null,2);if(a===o)return a;const d=a.split(`
12
- `),f=o.split(`
13
- `),r=[],x=Math.max(d.length,f.length);for(let i=0;i<x;i++){const p=d[i],_=f[i];p!==void 0&&p!==_&&r.push(`- ${p}`),_!==void 0&&_!==p&&r.push(`+ ${_}`),p!==void 0&&p===_&&r.push(` ${p}`)}return r.join(`
14
- `)}function As({isOpen:t,onClose:n,onResolve:a,conflicts:o,localNodeName:d,remoteNodeName:f,addToast:r}){const[x,i]=s.useState({}),[p,_]=s.useState(!1);s.useEffect(()=>{const l={};for(const u of o)x[u.key]||(l[u.key]={resolution:"local"});Object.keys(l).length>0&&i(u=>({...u,...l}))},[o,x]),s.useEffect(()=>{if(!t)return;const l=u=>{u.key==="Escape"&&(u.preventDefault(),n())};return document.addEventListener("keydown",l),()=>document.removeEventListener("keydown",l)},[t,n]);const k=s.useCallback((l,u)=>{i(y=>{const E=y[l]??{};return u==="manual"?{...y,[l]:{resolution:"manual",manualValue:E.manualValue??JSON.stringify(o.find(A=>A.key===l)?.localValue??null,null,2)}}:{...y,[l]:{resolution:u}}})},[o]),j=s.useCallback((l,u)=>{i(y=>({...y,[l]:{...y[l],resolution:"manual",manualValue:u}}))},[]),c=s.useCallback(l=>{const u={};for(const y of o)u[y.key]={resolution:l};i(u)},[o]),C=s.useCallback(async()=>{_(!0);try{const l=o.map(u=>{const y=x[u.key]??{resolution:"local"};let E;switch(y.resolution){case"remote":E=u.remoteValue;break;case"manual":try{E=JSON.parse(y.manualValue??"null")}catch{E=y.manualValue??null}break;case"local":default:E=u.localValue;break}return{key:u.key,value:E}});await a(l),r("Settings conflicts resolved successfully","success"),n()}catch(l){const u=l instanceof Error?l.message:"Failed to resolve conflicts";r(u,"error")}finally{_(!1)}},[r,o,n,a,x]),b=s.useMemo(()=>{const l={};for(const u of o)l[u.key]=Rs(u.localValue,u.remoteValue);return l},[o]);return!t||o.length===0?null:e.jsx("div",{className:"modal-overlay open",onClick:n,children:e.jsxs("div",{className:"modal modal-lg settings-sync-conflict-modal",onClick:l=>l.stopPropagation(),role:"dialog","aria-modal":"true","aria-label":"Resolve Settings Conflicts",children:[e.jsxs("div",{className:"modal-header",children:[e.jsx("h3",{children:"Resolve Settings Conflicts"}),e.jsx("button",{className:"modal-close",onClick:n,"aria-label":"Close conflict modal",children:"×"})]}),e.jsxs("div",{className:"modal-body",children:[e.jsx("div",{className:"settings-sync-conflict-modal__conflict-list",children:o.map(l=>{const u=x[l.key]??{resolution:"local"},y=b[l.key];return e.jsxs("div",{className:"settings-sync-conflict-modal__conflict-item",children:[e.jsx("div",{className:"settings-sync-conflict-modal__key",children:l.key}),e.jsxs("div",{className:"settings-sync-conflict-modal__diff-panel",children:[e.jsxs("div",{className:"settings-sync-conflict-modal__diff-side",children:[e.jsx("div",{className:"settings-sync-conflict-modal__diff-label",children:d}),e.jsx("div",{className:"settings-sync-conflict-modal__diff-content",children:e.jsx("pre",{style:{margin:0,whiteSpace:"pre-wrap"},children:y})})]}),e.jsxs("div",{className:"settings-sync-conflict-modal__diff-side",children:[e.jsx("div",{className:"settings-sync-conflict-modal__diff-label",children:f}),e.jsx("div",{className:"settings-sync-conflict-modal__diff-content",children:e.jsx("pre",{style:{margin:0,whiteSpace:"pre-wrap"},children:y})})]})]}),e.jsxs("div",{className:"settings-sync-conflict-modal__resolution",children:[e.jsxs("label",{children:[e.jsx("input",{type:"radio",name:`resolution-${l.key}`,checked:u.resolution==="local",onChange:()=>k(l.key,"local")}),"Keep Local"]}),e.jsxs("label",{children:[e.jsx("input",{type:"radio",name:`resolution-${l.key}`,checked:u.resolution==="remote",onChange:()=>k(l.key,"remote")}),"Keep Remote"]}),e.jsxs("label",{children:[e.jsx("input",{type:"radio",name:`resolution-${l.key}`,checked:u.resolution==="manual",onChange:()=>k(l.key,"manual")}),"Merge Manually"]})]}),u.resolution==="manual"&&e.jsx("textarea",{className:"settings-sync-conflict-modal__manual-input",value:u.manualValue??"",onChange:E=>j(l.key,E.target.value),placeholder:"Enter JSON value..."})]},l.key)})}),e.jsxs("div",{className:"settings-sync-conflict-modal__bulk-actions",children:[e.jsx("button",{className:"btn btn-sm",onClick:()=>c("local"),type:"button",children:"Resolve All: Keep Local"}),e.jsx("button",{className:"btn btn-sm",onClick:()=>c("remote"),type:"button",children:"Resolve All: Keep Remote"})]})]}),e.jsxs("div",{className:"modal-actions settings-sync-conflict-modal__footer",children:[e.jsx("button",{className:"btn btn-sm",onClick:n,children:"Cancel"}),e.jsx("button",{className:"btn btn-primary btn-sm",onClick:C,disabled:p,children:p?"Resolving...":"Confirm"})]})]})})}const Ls=/(KEY|TOKEN|SECRET|PASSWORD)/i;function ue(t){if(!t)return"—";const n=new Date(t);return Number.isNaN(n.getTime())?"—":n.toLocaleString()}function $s(t){if(!t)return"—";const n=new Date(t),a=Date.now();if(Number.isNaN(n.getTime())||n.getTime()>a)return"—";const o=Math.floor((a-n.getTime())/1e3);if(o<60)return`${o}s`;const d=Math.floor(o/60);if(d<60)return`${d}m`;const f=Math.floor(d/60);return f<24?`${f}h ${d%60}m`:`${Math.floor(f/24)}d ${f%24}h`}function zs(t){switch(t){case"synced":return"node-detail-modal__sync-dot--synced";case"diff":return"node-detail-modal__sync-dot--diff";case"error":return"node-detail-modal__sync-dot--error";case"pending":return"node-detail-modal__sync-dot--pending";case"never-synced":default:return"node-detail-modal__sync-dot--never"}}function Ds(t){return t==="running"?"success":t==="creating"||t==="recreating"||t==="restarting"?"warning":"error"}function Is(t){return t?`${t.charAt(0).toUpperCase()}${t.slice(1)}`:"Unknown"}function Fs(t){if(!t)return"—";try{const n=new URL(t);return n.port?n.port:n.protocol==="https:"?"443":n.protocol==="http:"?"80":"—"}catch{return"—"}}function Ks(t,n){return Ls.test(t)?"••••••••":n}function Os({isOpen:t,onClose:n,node:a,projects:o,onUpdate:d,onHealthCheck:f,addToast:r,syncStatus:x,onPushSettings:i,onPullSettings:p,onSyncAuth:_,syncHistory:k=[],onResolveConflicts:j,managedDockerNode:c,containerStatus:C,onFetchContainerStatus:b,onFetchLogs:l}){const u=s.useRef(!0),[y,E]=s.useState(!1),[A,P]=s.useState(""),[z,g]=s.useState(""),[m,N]=s.useState(""),[F,O]=s.useState(2),[R,H]=s.useState(!1),[V,X]=s.useState(!1),[J,q]=s.useState(!1),[U,W]=s.useState(!1),[M,T]=s.useState(null),[S,w]=s.useState(!1),[D]=s.useState([]),[Y,G]=s.useState(C),[ee,K]=s.useState(!1),[te,ae]=s.useState(!1),[ce,h]=s.useState(""),[L,I]=s.useState(!1);s.useEffect(()=>(u.current=!0,()=>{u.current=!1}),[]),s.useEffect(()=>{G(C)},[C]),s.useEffect(()=>{if(!a||!t){E(!1),ae(!1),h("");return}P(a.name),g(a.url??""),N(a.apiKey??""),O(a.maxConcurrent),E(!1)},[t,a]),s.useEffect(()=>{if(!t)return;const v=$=>{$.key==="Escape"&&($.preventDefault(),n())};return document.addEventListener("keydown",v),()=>document.removeEventListener("keydown",v)},[t,n]);const B=s.useMemo(()=>a?Re(o,a):[],[a,o]),ne=s.useMemo(()=>c?c.hostConfig.type==="remote"?c.hostConfig.host??"—":"Local Docker":"—",[c]),Ae=s.useMemo(()=>!c?.resourceSizing?.cpuLimit&&!c?.resourceSizing?.memoryLimit?"Default":`${c.resourceSizing?.cpuLimit??"Default CPU"} / ${c.resourceSizing?.memoryLimit??"Default memory"}`,[c]),Le=s.useCallback(async()=>{if(a)try{if(await f(a.id),!u.current)return;r(`Health check completed for ${a.name}`,"success")}catch(v){if(!u.current)return;const $=v instanceof Error?v.message:"Health check failed";r($,"error")}},[r,a,f]),$e=s.useCallback(async()=>{if(!(!a||!i)){T(null),X(!0);try{if(await i(a.id),!u.current)return;r("Settings pushed successfully","success")}catch(v){if(!u.current)return;const $=v instanceof Error?v.message:"Push settings failed";T($),r($,"error")}finally{u.current&&X(!1)}}},[r,a,i]),ze=s.useCallback(async()=>{if(!(!a||!p)){T(null),q(!0);try{if(await p(a.id),!u.current)return;r("Settings pulled successfully","success")}catch(v){if(!u.current)return;const $=v instanceof Error?v.message:"Pull settings failed";T($),r($,"error")}finally{u.current&&q(!1)}}},[r,a,p]),De=s.useCallback(async()=>{if(!(!a||!_)){T(null),W(!0);try{if(await _(a.id),!u.current)return;r("Auth credentials synced successfully","success")}catch(v){if(!u.current)return;const $=v instanceof Error?v.message:"Auth sync failed";T($),r($,"error")}finally{u.current&&W(!1)}}},[r,a,_]),Ie=s.useCallback(()=>{T(null)},[]),Fe=s.useCallback(async()=>{if(!(!c||!b)){K(!0);try{const v=await b(c.id);if(!u.current)return;G(v)}catch(v){const $=v instanceof Error?v.message:"Failed to fetch container status";r($,"error")}finally{u.current&&K(!1)}}},[r,c,b]),Ke=s.useCallback(async()=>{if(!(!c||!l)){ae(!0),I(!0);try{const v=await l(c.id);if(!u.current)return;h(v)}catch(v){if(!u.current)return;h("");const $=v instanceof Error?v.message:"Failed to fetch container logs";r($,"error")}finally{u.current&&I(!1)}}},[r,c,l]),Oe=s.useCallback(async()=>{if(!a||R)return;const v=A.trim();if(!v){r("Name is required","error");return}if(a.type==="remote"&&!z.trim()){r("URL is required for remote nodes","error");return}if(!Number.isFinite(F)||F<1){r("Concurrency must be at least 1","error");return}H(!0);try{await d(a.id,{name:v,url:a.type==="remote"&&z.trim()||void 0,apiKey:a.type==="remote"&&m||void 0,maxConcurrent:F}),r(`Updated ${v}`,"success"),E(!1)}catch($){const Te=$ instanceof Error?$.message:"Failed to update node";r(Te,"error")}finally{H(!1)}},[r,m,R,F,A,a,d,z]),Ve=s.useCallback(()=>{a&&(P(a.name),g(a.url??""),N(a.apiKey??""),O(a.maxConcurrent),E(!1))},[a]);if(!t||!a)return null;const Z=Y?.status??c?.status,Ue=Ds(Z);return e.jsxs("div",{className:"modal-overlay open",onClick:n,children:[e.jsxs("div",{className:"modal modal-lg node-detail-modal",onClick:v=>v.stopPropagation(),role:"dialog","aria-modal":"true","aria-label":`Node details for ${a.name}`,children:[e.jsxs("div",{className:"modal-header",children:[e.jsx("h3",{children:"Node Details"}),e.jsx("button",{className:"modal-close",onClick:n,"aria-label":"Close node detail modal",children:"×"})]}),e.jsxs("div",{className:"modal-body node-detail-modal__body",children:[e.jsxs("section",{className:"node-detail-modal__section",children:[e.jsxs("div",{className:"node-detail-modal__section-header",children:[e.jsx("h4",{children:"Overview"}),!y&&e.jsxs("button",{className:"btn btn-sm",onClick:()=>E(!0),children:[e.jsx(Ge,{size:14}),"Edit"]})]}),e.jsxs("div",{className:"node-detail-modal__grid",children:[e.jsxs("label",{className:"node-detail-modal__field",children:[e.jsx("span",{children:"Name"}),y?e.jsx("input",{className:"input",value:A,onChange:v=>P(v.target.value),disabled:R}):e.jsx("strong",{children:a.name})]}),e.jsxs("div",{className:"node-detail-modal__field",children:[e.jsx("span",{children:"Type"}),e.jsx("strong",{children:a.type==="local"?"Local":"Remote"})]}),e.jsxs("div",{className:"node-detail-modal__field",children:[e.jsx("span",{children:"Status"}),e.jsx("strong",{children:a.status})]}),e.jsxs("label",{className:"node-detail-modal__field",children:[e.jsx("span",{children:"Max Concurrent"}),y?e.jsx("input",{className:"input",type:"number",min:1,max:10,value:F,onChange:v=>O(Number(v.target.value)),disabled:R}):e.jsx("strong",{children:a.maxConcurrent})]}),a.type==="remote"&&e.jsxs(e.Fragment,{children:[e.jsxs("label",{className:"node-detail-modal__field node-detail-modal__field--full",children:[e.jsx("span",{children:"URL"}),y?e.jsx("input",{className:"input",value:z,onChange:v=>g(v.target.value),disabled:R}):e.jsx("strong",{children:a.url??"—"})]}),e.jsxs("label",{className:"node-detail-modal__field node-detail-modal__field--full",children:[e.jsx("span",{children:"API Key"}),y?e.jsx("input",{className:"input",type:"password",value:m,onChange:v=>N(v.target.value),placeholder:"Leave blank to keep unchanged",disabled:R}):e.jsx("strong",{children:a.apiKey?"••••••••":"Not configured"})]})]}),e.jsxs("div",{className:"node-detail-modal__field",children:[e.jsx("span",{children:"Created"}),e.jsx("strong",{children:ue(a.createdAt)})]}),e.jsxs("div",{className:"node-detail-modal__field",children:[e.jsx("span",{children:"Updated"}),e.jsx("strong",{children:ue(a.updatedAt)})]})]}),y&&e.jsxs("div",{className:"node-detail-modal__edit-actions",children:[e.jsxs("button",{className:"btn btn-primary btn-sm",onClick:Oe,disabled:R,children:[e.jsx(Ze,{size:14}),R?"Saving...":"Save"]}),e.jsxs("button",{className:"btn btn-sm",onClick:Ve,disabled:R,children:[e.jsx(re,{size:14}),"Cancel"]})]})]}),e.jsxs("section",{className:"node-detail-modal__section",children:[e.jsxs("h4",{children:[a.type==="local"?"Projects":"Assigned Projects"," (",B.length,")"]}),B.length===0?e.jsx("p",{className:"node-detail-modal__empty",children:a.type==="local"?"No projects are running on this node.":"No projects are assigned to this node."}):e.jsx("ul",{className:"node-detail-modal__project-list",children:B.map(v=>e.jsxs("li",{className:"node-detail-modal__project-item",children:[e.jsx("span",{children:v.name}),e.jsx("code",{children:v.id})]},v.id))})]}),e.jsxs("section",{className:"node-detail-modal__section",children:[e.jsx("h4",{children:"Health"}),e.jsxs("div",{className:"node-detail-modal__health-row",children:[e.jsxs("span",{children:["Status: ",e.jsx("strong",{children:a.status})]}),e.jsxs("span",{children:["Last check: ",e.jsx("strong",{children:ue(a.updatedAt)})]})]})]}),c&&e.jsxs("section",{className:"node-detail-modal__section docker-management",children:[e.jsx("h4",{children:"Docker Management"}),e.jsxs("div",{className:"docker-management__status-card",children:[e.jsxs("div",{className:"docker-management__status-row",children:[e.jsx("span",{className:`docker-management__status-dot docker-management__status-dot--${Ue}`,"aria-hidden":!0}),e.jsx("strong",{children:Is(Z)}),(Z==="creating"||Z==="recreating"||Z==="restarting")&&e.jsx(ye,{size:14,className:"spin","aria-hidden":!0})]}),e.jsxs("div",{className:"docker-management__status-meta",children:[Z==="running"&&e.jsxs("span",{children:["Uptime: ",$s(Y?.startedAt)]}),Z!=="running"&&Y?.exitCode!==void 0&&e.jsxs("span",{children:["Exit code: ",Y.exitCode]}),(Y?.error||c.errorMessage)&&e.jsx("span",{children:Y?.error??c.errorMessage})]}),e.jsx("button",{className:"btn btn-sm",onClick:()=>void Fe(),disabled:!b||ee,children:ee?"Refreshing...":"Refresh Status"})]}),e.jsxs("div",{className:"node-detail-modal__grid docker-management__info-grid",children:[e.jsxs("div",{className:"node-detail-modal__field",children:[e.jsx("span",{children:"Image"}),e.jsx("strong",{children:e.jsxs("code",{children:[c.imageName,":",c.imageTag]})})]}),e.jsxs("div",{className:"node-detail-modal__field",children:[e.jsx("span",{children:"Container ID"}),e.jsx("strong",{children:e.jsx("code",{children:c.containerId?c.containerId.slice(0,12):"—"})})]}),e.jsxs("div",{className:"node-detail-modal__field",children:[e.jsx("span",{children:"Host"}),e.jsx("strong",{children:ne})]}),e.jsxs("div",{className:"node-detail-modal__field",children:[e.jsx("span",{children:"Persistent Storage"}),e.jsx("strong",{children:c.persistentStorage?"Yes":"No"})]}),e.jsxs("div",{className:"node-detail-modal__field",children:[e.jsx("span",{children:"Port"}),e.jsx("strong",{children:Fs(c.reachableUrl)})]}),e.jsxs("div",{className:"node-detail-modal__field",children:[e.jsx("span",{children:"Resource Sizing"}),e.jsx("strong",{children:Ae})]})]}),e.jsxs("div",{className:"docker-management__actions",children:[e.jsxs("button",{className:"btn btn-sm",disabled:!0,title:"Available after FN-3113",children:[e.jsx(Ce,{size:14}),"Start"]}),e.jsxs("button",{className:"btn btn-sm",disabled:!0,title:"Available after FN-3113",children:[e.jsx(Se,{size:14}),"Stop"]}),e.jsxs("button",{className:"btn btn-sm",disabled:!0,title:"Available after FN-3113",children:[e.jsx(ye,{size:14}),"Restart"]}),e.jsxs("button",{className:"btn btn-sm",onClick:()=>void Ke(),disabled:!l,children:[e.jsx(Qe,{size:14}),"View Logs"]})]}),te&&e.jsxs("div",{className:"docker-management__log-viewer",children:[e.jsxs("div",{className:"docker-management__log-viewer-header",children:[e.jsx("strong",{children:"Container Logs"}),e.jsx("button",{className:"btn-icon",onClick:()=>ae(!1),"aria-label":"Close logs",children:e.jsx(re,{size:14})})]}),L?e.jsx("p",{children:"Fetching logs..."}):e.jsx("pre",{children:ce.trim()||"No logs available"})]}),e.jsxs("details",{children:[e.jsx("summary",{children:"Environment Variables"}),e.jsx("dl",{className:"docker-management__env-list",children:Object.entries(c.envVars).map(([v,$])=>e.jsxs("div",{children:[e.jsx("dt",{children:v}),e.jsx("dd",{children:Ks(v,$)})]},v))})]}),e.jsxs("details",{children:[e.jsx("summary",{children:"Volume Mounts"}),e.jsx("ul",{className:"docker-management__mounts-list",children:c.volumeMounts.map(v=>e.jsxs("li",{children:[e.jsxs("span",{children:[v.hostPath," → ",v.containerPath]}),v.readOnly&&e.jsx("span",{className:"node-card__type-badge",children:"Read-only"})]},`${v.hostPath}:${v.containerPath}`))})]})]}),a.type==="remote"&&e.jsxs("section",{className:"node-detail-modal__section",children:[e.jsx("h4",{children:"Settings Sync"}),x&&e.jsxs("div",{className:"node-detail-modal__sync-status",children:[e.jsx("span",{className:`node-detail-modal__sync-dot ${zs(x.syncState)}`,"aria-hidden":!0}),e.jsxs("span",{children:["Last sync: ",e.jsx("strong",{children:x.lastSyncAt?Ee(x.lastSyncAt):"Never synced"})]}),x.diffCount>0&&e.jsxs("span",{className:"node-detail-modal__sync-diff",children:["Differences: ",e.jsx("strong",{children:x.diffCount})]})]}),e.jsxs("div",{className:"node-detail-modal__sync-actions",children:[e.jsxs("button",{className:"btn btn-sm",onClick:$e,disabled:V||!i,children:[e.jsx(Me,{size:14}),V?"Pushing...":"Push Settings"]}),e.jsxs("button",{className:"btn btn-sm",onClick:ze,disabled:J||!p,children:[e.jsx(Pe,{size:14}),J?"Pulling...":"Pull Settings"]}),e.jsxs("button",{className:"btn btn-sm",onClick:De,disabled:U||!_,children:[e.jsx(Ne,{size:14}),U?"Syncing...":"Sync Auth"]})]}),M&&e.jsxs("div",{className:"node-detail-modal__sync-error",children:[e.jsx("span",{children:M}),e.jsx("button",{className:"node-detail-modal__sync-error-dismiss",onClick:Ie,"aria-label":"Dismiss error",children:e.jsx(re,{size:14})})]})]}),a.type==="remote"&&e.jsxs("section",{className:"node-detail-modal__section",children:[e.jsx("h4",{children:"Sync History"}),e.jsx(Es,{nodeId:a.id,entries:k,singleNode:!0})]})]}),e.jsxs("div",{className:"modal-actions node-detail-modal__actions",children:[e.jsxs("button",{className:"btn btn-sm",onClick:Le,children:[e.jsx(ke,{size:14}),"Health Check"]}),e.jsx("button",{className:"btn btn-sm",onClick:n,children:"Close"})]})]}),a.type==="remote"&&e.jsx(As,{isOpen:S,onClose:()=>w(!1),onResolve:j??(async()=>{}),conflicts:D,localNodeName:"Local",remoteNodeName:a.name,addToast:r})]})}const Vs=15e3,Us=1e3;function Ts(){const[t,n]=s.useState([]),[a,o]=s.useState(!0),[d,f]=s.useState(null),r=s.useRef(null),x=s.useRef(0),i=s.useCallback(async()=>{try{f(null);const j=await be();n(j)}catch(j){f(j instanceof Error?j.message:"Failed to fetch managed Docker nodes")}},[]);s.useEffect(()=>{let j=!1;async function c(){o(!0);try{const b=await be();j||(n(b),f(null))}catch(b){j||f(b instanceof Error?b.message:"Failed to fetch managed Docker nodes")}finally{j||o(!1)}}c();const C=()=>{if(document.visibilityState!=="visible")return;const b=Date.now();b-x.current<Us||(x.current=b,i())};return document.addEventListener("visibilitychange",C),()=>{j=!0,document.removeEventListener("visibilitychange",C)}},[i]),s.useEffect(()=>{if(!a)return r.current=setInterval(()=>{i()},Vs),()=>{r.current&&(clearInterval(r.current),r.current=null)}},[a,i]);const p=s.useCallback(async j=>es(j),[]),_=s.useCallback(async(j,c)=>(await ss(j,c)).logs,[]),k=s.useCallback(async j=>{const c=await ts(j),C={...c,nodeId:c.nodeId??void 0,containerId:c.containerId??void 0,status:c.status,hostConfig:{type:c.hostConfig.host||c.hostConfig.context?"remote":"local",host:c.hostConfig.host,context:c.hostConfig.context},reachableUrl:c.reachableUrl??void 0,volumeMounts:c.volumeMounts.map(b=>({hostPath:b.hostPath,containerPath:b.containerPath,readOnly:b.mode==="ro"?!0:void 0})),persistentStorage:c.persistentStorage,resourceSizing:{cpuLimit:c.resourceSizing.cpus!==void 0?String(c.resourceSizing.cpus):void 0,memoryLimit:c.resourceSizing.memoryMB!==void 0?`${c.resourceSizing.memoryMB}MB`:void 0},errorMessage:c.errorMessage??void 0};return n(b=>[...b,C]),C},[]);return{dockerNodes:t,loading:a,error:d,refresh:i,getContainerStatus:p,getLogs:_,create:k}}function Ys({addToast:t,onClose:n}){const{nodes:a,loading:o,error:d,refresh:f,register:r,update:x,unregister:i,healthCheck:p}=as(),{projects:_}=ns(),{syncStatusMap:k,pushSettings:j,pullSettings:c,syncAuth:C,trackNode:b,getAuthSyncState:l,getAuthProviders:u}=ms(),{dockerNodes:y,loading:E,refresh:A,getContainerStatus:P,getLogs:z,create:g}=Ts(),[m,N]=s.useState(!1),[F,O]=s.useState(!1),[R,H]=s.useState(null);s.useEffect(()=>{const S=a.filter(w=>w.type==="remote");for(const w of S)b(w.id)},[a,b]),s.useEffect(()=>{if(!R)return;const S=a.find(w=>w.id===R.id)??null;H(S)},[a,R]);const V=s.useMemo(()=>{const S=a.length,w=a.filter(K=>K.status==="online").length,D=a.filter(K=>K.status==="offline"||K.status==="error").length,Y=a.filter(K=>K.type==="remote").length,G=a.filter(K=>K.type==="remote"&&k[K.id]&&ie(k[K.id]).syncState==="synced").length,ee=y.length;return{total:S,online:w,offline:D,remote:Y,synced:G,docker:ee}},[y.length,a,k]),X=s.useCallback(async S=>{await r(S)},[r]),J=s.useCallback(async S=>{try{await g(S),t(`Docker node "${S.name}" created`,"success"),O(!1)}catch(w){const D=w instanceof Error?w.message:"Failed to create Docker node";throw t(D,"error"),w}},[t,g]),q=s.useMemo(()=>{const S=new Map;for(const w of y)w.nodeId&&S.set(w.nodeId,w);return S},[y]),U=s.useCallback(async()=>{try{await Promise.all([f(),A()])}catch{t("Failed to refresh nodes","error")}},[t,f,A]),W=s.useCallback(async S=>{try{await p(S),t("Node health check complete","success")}catch(w){const D=w instanceof Error?w.message:"Health check failed";t(D,"error")}},[t,p]),M=s.useCallback(async S=>{try{await i(S),t("Node removed","success"),R?.id===S&&H(null)}catch(w){const D=w instanceof Error?w.message:"Failed to remove node";t(D,"error")}},[t,R?.id,i]),T=s.useCallback(async(S,w)=>{await x(S,w)},[x]);return e.jsxs("div",{className:"nodes-view","data-testid":"nodes-view",children:[e.jsxs("div",{className:"nodes-view-header",children:[e.jsxs("div",{className:"nodes-view-title",children:[e.jsxs("h2",{children:[e.jsx(ve,{size:20}),"Nodes"]}),e.jsxs("span",{className:"nodes-view-count",children:[a.length," registered"]})]}),e.jsxs("div",{className:"nodes-view-actions",children:[e.jsx("button",{className:"btn-icon nodes-view-close",onClick:n,"aria-label":"Close nodes view",children:e.jsx(re,{size:16})}),e.jsxs("button",{className:"btn btn-sm",onClick:()=>void U(),disabled:o||E,children:[e.jsx(fe,{size:14,className:o?"spin":""}),"Refresh"]}),e.jsxs("button",{className:"btn btn-sm",onClick:()=>N(!0),children:[e.jsx(oe,{size:14}),"Add Node"]}),e.jsxs("button",{className:"btn btn-sm",onClick:()=>O(!0),title:"Add a managed Docker node",children:[e.jsx(me,{size:14}),"Add Docker Node"]})]})]}),e.jsxs("div",{className:"nodes-view-stats",children:[e.jsxs("div",{className:"nodes-view-stat","data-testid":"nodes-stat-total",children:[e.jsx("span",{children:"Total"}),e.jsx("strong",{children:V.total})]}),e.jsxs("div",{className:"nodes-view-stat nodes-view-stat--online","data-testid":"nodes-stat-online",children:[e.jsxs("span",{children:[e.jsx(is,{size:14})," Online"]}),e.jsx("strong",{children:V.online})]}),e.jsxs("div",{className:"nodes-view-stat nodes-view-stat--offline","data-testid":"nodes-stat-offline",children:[e.jsxs("span",{children:[e.jsx(os,{size:14})," Offline"]}),e.jsx("strong",{children:V.offline})]}),e.jsxs("div",{className:"nodes-view-stat","data-testid":"nodes-stat-remote",children:[e.jsxs("span",{children:[e.jsx(ls,{size:14})," Remote"]}),e.jsx("strong",{children:V.remote})]}),e.jsxs("div",{className:"nodes-view-stat nodes-view-stat--synced","data-testid":"nodes-stat-synced",children:[e.jsxs("span",{children:[e.jsx(fe,{size:14})," Synced"]}),e.jsx("strong",{children:V.synced})]}),e.jsxs("div",{className:"nodes-view-stat","data-testid":"nodes-stat-docker",children:[e.jsxs("span",{children:[e.jsx(me,{size:14})," Docker"]}),e.jsx("strong",{children:V.docker})]})]}),d&&e.jsx("div",{className:"nodes-view-error",children:d}),!o&&a.length>0&&e.jsxs("section",{className:"nodes-view-topology","aria-label":"Mesh Topology",children:[e.jsx("h3",{className:"nodes-view-section-title",children:"Mesh Topology"}),e.jsx(Ns,{nodes:a})]}),o?e.jsx("div",{className:"nodes-view-grid",children:Array.from({length:4}).map((S,w)=>e.jsx("div",{className:"node-card node-card--loading","aria-hidden":!0},w))}):a.length===0?e.jsxs("div",{className:"nodes-view-empty",children:[e.jsx("p",{children:"No nodes are registered yet."}),e.jsxs("button",{className:"btn btn-primary",onClick:()=>N(!0),children:[e.jsx(oe,{size:14}),"Add First Node"]})]}):e.jsx("div",{className:"nodes-view-grid",children:a.map(S=>{const w=S.type==="remote"&&k[S.id]?ie(k[S.id]):void 0;return e.jsx(bs,{node:S,projects:_,onHealthCheck:D=>{W(D)},onEdit:D=>H(D),onRemove:D=>{M(D)},isLoading:o,syncStatus:w,authSyncState:S.type==="remote"?l(S.id):void 0,authSyncProviders:S.type==="remote"?u(S.id):void 0,managedDockerNode:q.get(S.id)},S.id)})}),e.jsx(Cs,{isOpen:m,onClose:()=>N(!1),onSubmit:X,addToast:t}),e.jsx(Ps,{isOpen:F,onClose:()=>O(!1),onSubmit:J,addToast:t}),e.jsx(Os,{isOpen:R!==null,onClose:()=>H(null),node:R,projects:_,onUpdate:T,onHealthCheck:W,addToast:t,syncStatus:R?.type==="remote"&&R&&k[R.id]?ie(k[R.id]):void 0,onPushSettings:j,onPullSettings:c,onSyncAuth:C,managedDockerNode:R?q.get(R.id):void 0,onFetchContainerStatus:P,onFetchLogs:z})]})}export{Ys as NodesView};
@@ -1,11 +0,0 @@
1
- import{r as l,j as e}from"./vendor-react-K0fH_qHe.js";import{h as G,d6 as J,d7 as Q,d8 as V,R as $,cZ as y,P as Y,C as T,e as ee,a4 as se,bZ as L,F as D,d9 as ae,da as te,db as _,X as ie}from"./index-DNzA4aZ7.js";import"./vendor-xterm-DzcZoU0P.js";/**
2
- * @license lucide-react v1.7.0 - ISC
3
- *
4
- * This source code is licensed under the ISC license.
5
- * See the LICENSE file in the root directory of this source tree.
6
- */const ne=[["path",{d:"M12 22a1 1 0 0 1 0-20 10 9 0 0 1 10 9 5 5 0 0 1-5 5h-2.25a1.75 1.75 0 0 0-1.4 2.8l.3.4a1.75 1.75 0 0 1-1.4 2.8z",key:"e79jfc"}],["circle",{cx:"13.5",cy:"6.5",r:".5",fill:"currentColor",key:"1okk4w"}],["circle",{cx:"17.5",cy:"10.5",r:".5",fill:"currentColor",key:"f64h9f"}],["circle",{cx:"6.5",cy:"12.5",r:".5",fill:"currentColor",key:"qy21gx"}],["circle",{cx:"8.5",cy:"7.5",r:".5",fill:"currentColor",key:"fotxhn"}]],M=G("palette",ne);/**
7
- * @license lucide-react v1.7.0 - ISC
8
- *
9
- * This source code is licensed under the ISC license.
10
- * See the LICENSE file in the root directory of this source tree.
11
- */const le=[["path",{d:"M15.39 4.39a1 1 0 0 0 1.68-.474 2.5 2.5 0 1 1 3.014 3.015 1 1 0 0 0-.474 1.68l1.683 1.682a2.414 2.414 0 0 1 0 3.414L19.61 15.39a1 1 0 0 1-1.68-.474 2.5 2.5 0 1 0-3.014 3.015 1 1 0 0 1 .474 1.68l-1.683 1.682a2.414 2.414 0 0 1-3.414 0L8.61 19.61a1 1 0 0 0-1.68.474 2.5 2.5 0 1 1-3.014-3.015 1 1 0 0 0 .474-1.68l-1.683-1.682a2.414 2.414 0 0 1 0-3.414L4.39 8.61a1 1 0 0 1 1.68.474 2.5 2.5 0 1 0 3.014-3.015 1 1 0 0 1-.474-1.68l1.683-1.682a2.414 2.414 0 0 1 3.414 0z",key:"w46dr5"}]],A=G("puzzle",le);function ce(t){return t.replace(/-/g,"-")}function re(t){return{"fusion-global":"Fusion Global","pi-global":"Pi Global","fusion-project":"Fusion Project","pi-project":"Pi Project",package:"Package"}[t]??t}function oe(t){return t.startsWith("npm:")?"npm":t.startsWith("git:")?"git":"local"}function de(t){return t.replace(/^(npm:|git:)/,"")}function he({addToast:t,projectId:x}){const[c,I]=l.useState(null),[f,P]=l.useState(!0),[N,S]=l.useState(!1),[E,w]=l.useState(!1),[h,F]=l.useState(""),[O,W]=l.useState(new Set),[p,Z]=l.useState([]),[b,C]=l.useState(!0),[q,z]=l.useState(!1),r=l.useCallback(async()=>{try{P(!0);const s=await J();I(s)}catch(s){t(`Failed to load Pi settings: ${s instanceof Error?s.message:String(s)}`,"error")}finally{P(!1)}},[t]),m=l.useCallback(async()=>{try{C(!0);const s=await Q(x);Z(s.extensions)}catch(s){t(`Failed to load extensions: ${s instanceof Error?s.message:String(s)}`,"error")}finally{C(!1)}},[t,x]),B=l.useCallback(async s=>{try{z(!0);const i=s.enabled?[...p.filter(a=>a.enabled&&a.id!==s.id).map(a=>a.id),s.id]:p.filter(a=>a.enabled&&a.id!==s.id).map(a=>a.id);await V(i,x),await m(),t(s.enabled?"Extension disabled":"Extension enabled","success")}catch(i){t(`Failed to update extension: ${i instanceof Error?i.message:String(i)}`,"error")}finally{z(!1)}},[p,x,m,t]);l.useEffect(()=>{r()},[r]),l.useEffect(()=>{m()},[m]);const K=s=>{W(i=>{const a=new Set(i);return a.has(s)?a.delete(s):a.add(s),a})},R=async()=>{if(!h.trim()){t("Please enter a package source","error");return}try{S(!0),await ae(h.trim()),t("Package installed successfully","success"),F(""),await r()}catch(s){t(`Failed to install package: ${s instanceof Error?s.message:String(s)}`,"error")}finally{S(!1)}},U=async()=>{try{w(!0),await te(x),await Promise.all([r(),m()]),t("Fusion skill reinstalled successfully","success")}catch(s){t(`Failed to reinstall Fusion skill: ${s instanceof Error?s.message:String(s)}`,"error")}finally{w(!1)}},X=async s=>{if(!c)return;const i=c.packages.filter(a=>(typeof a=="string"?a:a.source)!==s);try{await _({packages:i}),t("Package removed","success"),await r()}catch(a){t(`Failed to remove package: ${a instanceof Error?a.message:String(a)}`,"error")}},H=async(s,i)=>{if(!c)return;const a=c[s].filter(n=>n!==i);try{await _({[s]:a}),t(`${s.slice(0,-1)} removed`,"success"),await r()}catch(n){t(`Failed to update settings: ${n instanceof Error?n.message:String(n)}`,"error")}},u=(s,i,a)=>!c||c[a].length===0?null:e.jsxs("div",{className:"pi-ext-section",children:[e.jsxs("div",{className:"pi-ext-section-header",children:[e.jsx(i,{size:14}),e.jsx("span",{children:s}),e.jsx("span",{className:"pi-ext-count",children:c[a].length})]}),e.jsx("div",{className:"pi-ext-resource-list",children:c[a].map((n,g)=>e.jsxs("span",{className:"pi-ext-resource-tag",children:[e.jsx("span",{className:"pi-ext-resource-path",children:n}),e.jsx("button",{className:"btn-icon touch-target pi-ext-resource-remove",onClick:()=>H(a,n),title:`Remove ${n}`,"aria-label":`Remove ${n}`,children:e.jsx(ie,{})})]},g))})]});return e.jsxs("div",{className:"pi-ext-manager",children:[e.jsxs("div",{className:"pi-ext-manager-header",children:[e.jsx("h4",{className:"pi-ext-manager-title",children:"Pi Extensions"}),e.jsx("div",{className:"pi-ext-manager-actions",children:e.jsx("button",{className:"btn-icon",onClick:r,title:"Refresh",disabled:f,children:e.jsx($,{size:16,className:f?"spin":""})})})]}),f?e.jsx("div",{className:"loading-state",children:"Loading Pi settings…"}):c?e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"pi-ext-add-form",children:[e.jsxs("div",{className:"pi-ext-add-form-row",children:[e.jsx("input",{type:"text",className:"input",placeholder:"npm:pi-extension-name or git:https://github.com/...",value:h,onChange:s=>F(s.target.value),onKeyDown:s=>{s.key==="Enter"&&(s.preventDefault(),R())},disabled:N}),e.jsxs("button",{className:"btn btn-primary",onClick:R,disabled:N||!h.trim(),children:[e.jsx(Y,{size:14}),N?"Installing…":"Add"]})]}),e.jsx("div",{className:"pi-ext-add-form-row",children:e.jsx("button",{className:"btn",onClick:U,disabled:E,children:E?"Reinstalling Fusion…":"Reinstall Fusion skill"})})]}),c.packages.length>0?e.jsx("div",{className:"pi-ext-package-list",children:c.packages.map((s,i)=>{const a=typeof s=="string"?s:s.source,n=oe(a),g=de(a),j=typeof s=="object"&&s!==null,v=j&&(s.extensions?.length??0)>0||(s.skills?.length??0)>0||(s.prompts?.length??0)>0||(s.themes?.length??0)>0,k=O.has(i);return e.jsxs("div",{className:"pi-ext-package-card",children:[e.jsxs("div",{className:"pi-ext-package-header",children:[j&&v?e.jsx("button",{className:"pi-ext-expand-btn",onClick:()=>K(i),"aria-expanded":k,children:k?e.jsx(T,{size:14}):e.jsx(ee,{size:14})}):e.jsx("span",{className:"pi-ext-expand-placeholder"}),e.jsx("span",{className:`pi-ext-source-badge pi-ext-source-badge--${n}`,children:n}),e.jsx("span",{className:"pi-ext-package-source",children:g}),e.jsxs("div",{className:"pi-ext-package-actions",children:[j&&v&&e.jsxs("span",{className:"pi-ext-filter-hint",children:[s.extensions?.length??0," ext,"," ",s.skills?.length??0," skill,"," ",s.prompts?.length??0," prompt,"," ",s.themes?.length??0," theme"]}),e.jsx("button",{className:"btn-icon touch-target pi-ext-remove-btn",onClick:()=>X(a),title:"Remove package","aria-label":`Remove package ${g}`,children:e.jsx(se,{size:14})})]})]}),j&&v&&k&&e.jsxs("div",{className:"pi-ext-filter-list",children:[s.extensions?.length?e.jsxs("div",{className:"pi-ext-filter-section",children:[e.jsx(A,{size:12}),e.jsx("span",{className:"pi-ext-filter-label",children:"Extensions:"}),s.extensions.map((o,d)=>e.jsx("span",{className:"pi-ext-filter-tag",children:o},d))]}):null,s.skills?.length?e.jsxs("div",{className:"pi-ext-filter-section",children:[e.jsx(L,{size:12}),e.jsx("span",{className:"pi-ext-filter-label",children:"Skills:"}),s.skills.map((o,d)=>e.jsx("span",{className:"pi-ext-filter-tag",children:o},d))]}):null,s.prompts?.length?e.jsxs("div",{className:"pi-ext-filter-section",children:[e.jsx(D,{size:12}),e.jsx("span",{className:"pi-ext-filter-label",children:"Prompts:"}),s.prompts.map((o,d)=>e.jsx("span",{className:"pi-ext-filter-tag",children:o},d))]}):null,s.themes?.length?e.jsxs("div",{className:"pi-ext-filter-section",children:[e.jsx(M,{size:12}),e.jsx("span",{className:"pi-ext-filter-label",children:"Themes:"}),s.themes.map((o,d)=>e.jsx("span",{className:"pi-ext-filter-tag",children:o},d))]}):null]})]},i)})}):e.jsxs("div",{className:"empty-state",children:[e.jsx(y,{size:32,className:"text-muted"}),e.jsx("p",{children:"No packages configured."}),e.jsx("p",{className:"text-muted",children:"Add a package source above to get started."})]}),e.jsxs("div",{className:"pi-ext-top-level",children:[u("Extensions",A,"extensions"),u("Skills",L,"skills"),u("Prompts",D,"prompts"),u("Themes",M,"themes")]})]}):e.jsxs("div",{className:"empty-state",children:[e.jsx(y,{size:32,className:"text-muted"}),e.jsx("p",{children:"Failed to load Pi settings."})]}),e.jsxs("div",{className:"pi-ext-discovered-section",children:[e.jsxs("div",{className:"pi-ext-discovered-header",children:[e.jsx("h4",{children:"Discovered Extensions"}),e.jsx("button",{className:"btn-icon",onClick:m,disabled:b,title:"Refresh extensions",children:e.jsx($,{className:b?"spin":""})})]}),e.jsx("p",{className:"pi-ext-description",children:"Installed extensions resolved from packages and configured paths."}),b?e.jsx("div",{className:"loading-state",children:"Loading extensions…"}):p.length===0?e.jsxs("div",{className:"empty-state",children:[e.jsx(y,{size:32,className:"text-muted"}),e.jsx("p",{children:"No extensions discovered."})]}):e.jsx("div",{className:"pi-ext-list",children:p.map(s=>e.jsxs("div",{className:"pi-ext-item",children:[e.jsxs("div",{className:"pi-ext-item-content",children:[e.jsxs("div",{className:"pi-ext-info",children:[e.jsx("span",{className:"pi-ext-name",children:s.name}),e.jsx("span",{className:`pi-ext-source-badge pi-ext-source-badge--${ce(s.source)}`,children:re(s.source)})]}),e.jsx("span",{className:"pi-ext-path",children:s.path})]}),e.jsx("div",{className:"pi-ext-actions",children:e.jsxs("label",{className:"toggle-switch",children:[e.jsx("input",{type:"checkbox",checked:s.enabled,onChange:()=>void B(s),disabled:q,"aria-label":`Toggle ${s.name}`}),e.jsx("span",{className:"toggle-slider"})]})})]},s.id))})]})]})}export{he as PiExtensionsManager};
@@ -1 +0,0 @@
1
- import{r as o,j as s}from"./vendor-react-K0fH_qHe.js";import{aZ as T,cY as ee,w as se,X as O,p as ne,P as A,a9 as _,a4 as M,R as te,cZ as ie,a0 as ae,bO as le,c_ as re,c$ as ce,d0 as de,d1 as ue,d2 as V,bL as oe}from"./index-DNzA4aZ7.js";import{D as ge}from"./DirectoryPicker-CTZE95Fk.js";import"./vendor-xterm-DzcZoU0P.js";const me=[{id:"fusion-plugin-agent-browser-runtime",name:"Agent Browser Runtime",path:"./plugins/fusion-plugin-agent-browser-runtime",experimental:!0},{id:"fusion-plugin-hermes-runtime",name:"Hermes Runtime",path:"./plugins/fusion-plugin-hermes-runtime",experimental:!0},{id:"fusion-plugin-paperclip-runtime",name:"Paperclip Runtime",path:"./plugins/fusion-plugin-paperclip-runtime"},{id:"fusion-plugin-openclaw-runtime",name:"OpenClaw Runtime",path:"./plugins/fusion-plugin-openclaw-runtime",experimental:!0},{id:"fusion-plugin-droid-runtime",name:"Droid Runtime",path:"./plugins/fusion-plugin-droid-runtime",experimental:!0}],N={started:"var(--color-success)",loaded:"var(--color-warning)",error:"var(--color-error)",stopped:"var(--color-muted)",installed:"var(--color-info)"};function Ne({addToast:l,projectId:c}){const[x,b]=o.useState([]),[S,w]=o.useState(!0),[H,f]=o.useState(!1),[j,v]=o.useState(""),[C,P]=o.useState(!1),[h,$]=o.useState(null),[i,y]=o.useState(null),[a,p]=o.useState({}),[Z,I]=o.useState(!1),[R,E]=o.useState(null),{confirm:G}=T(),g=o.useCallback(async()=>{try{w(!0);const e=await ee(c);b(e)}catch(e){l(`Failed to load plugins: ${e instanceof Error?e.message:String(e)}`,"error")}finally{w(!1)}},[c,l]);o.useEffect(()=>{g()},[g]);const J=o.useRef([]);J.current=x,o.useEffect(()=>{const e=c?`?projectId=${encodeURIComponent(c)}`:"",n=d=>{try{const t=JSON.parse(d.data);if(c&&t.projectId&&t.projectId!==c)return;switch(t.transition){case"installing":case"enabled":case"disabled":case"settings-updated":b(u=>{const m=u.findIndex(r=>r.id===t.pluginId);if(m>=0){const r=[...u];return r[m]={...r[m],enabled:t.enabled,state:t.state,settings:t.settings,error:t.error},r}else return g(),u});break;case"uninstalled":b(u=>u.filter(m=>m.id!==t.pluginId));break;case"error":b(u=>{const m=u.findIndex(r=>r.id===t.pluginId);if(m>=0){const r=[...u];return r[m]={...r[m],state:t.state,error:t.error},r}return u});break}}catch{}};return se(`/api/events${e}`,{events:{"plugin:lifecycle":n},onReconnect:()=>{g()}})},[c,g]);const z=async()=>{if(!j.trim()){l("Please enter a plugin path","error");return}try{P(!0),await V({path:j},c),l("Plugin installed successfully","success"),f(!1),v(""),await g()}catch(e){l(`Failed to install plugin: ${e instanceof Error?e.message:String(e)}`,"error")}finally{P(!1)}},K=async e=>{try{E(e.id),await V({path:e.path},c),l(`${e.name} installed successfully`,"success"),await g()}catch(n){l(`Failed to install ${e.name}: ${n instanceof Error?n.message:String(n)}`,"error")}finally{E(null)}},B=async e=>{try{await de(e.id,c),l(`${e.name} enabled`,"success"),await g()}catch(n){l(`Failed to enable plugin: ${n instanceof Error?n.message:String(n)}`,"error")}},F=async e=>{try{await ce(e.id,c),l(`${e.name} disabled`,"success"),await g()}catch(n){l(`Failed to disable plugin: ${n instanceof Error?n.message:String(n)}`,"error")}},L=async e=>{try{$(e.id),await re(e.id,c),l(`${e.name} reloaded`,"success"),await g()}catch(n){l(`Failed to reload plugin: ${n instanceof Error?n.message:String(n)}`,"error")}finally{$(null)}},D=async e=>{if(await G({title:"Uninstall Plugin",message:`Are you sure you want to uninstall "${e.name}"?`,danger:!0}))try{await ue(e.id,c),l(`${e.name} uninstalled`,"success"),await g(),y(null)}catch(d){l(`Failed to uninstall plugin: ${d instanceof Error?d.message:String(d)}`,"error")}},U=async e=>{y(e);try{I(!0);const n=await oe(e.id,c);p(n)}catch{p({})}finally{I(!1)}},X=async()=>{if(i)try{await le(i.id,a,c),l("Settings saved","success")}catch(e){l(`Failed to save settings: ${e instanceof Error?e.message:String(e)}`,"error")}};if(i)return s.jsxs("div",{className:"plugin-manager-detail","data-testid":"plugin-manager-detail",children:[s.jsxs("div",{className:"plugin-manager-detail-header",children:[s.jsx("button",{className:"btn-icon",onClick:()=>y(null),"aria-label":"Back to plugin list",children:s.jsx(O,{size:16})}),s.jsxs("div",{className:"plugin-detail-title",children:[s.jsx("h4",{className:"plugin-detail-name",children:i.name}),s.jsx("span",{className:"plugin-state-badge",style:{color:N[i.state]||N.installed},children:i.state})]})]}),s.jsxs("div",{className:"plugin-detail-content",children:[s.jsxs("div",{className:"plugin-detail-card",children:[i.description&&s.jsx("p",{className:"plugin-description",children:i.description}),i.author&&s.jsxs("p",{className:"plugin-detail-meta-row",children:[s.jsx("span",{className:"text-muted",children:"Author:"}),i.author]}),i.homepage&&s.jsxs("p",{className:"plugin-detail-meta-row plugin-homepage",children:[s.jsx("span",{className:"text-muted",children:"Homepage:"}),s.jsxs("a",{href:i.homepage,target:"_blank",rel:"noopener noreferrer",children:[i.homepage,s.jsx(ne,{size:12})]})]}),s.jsxs("p",{className:"plugin-detail-meta-row",children:[s.jsx("span",{className:"text-muted",children:"Version:"}),i.version]})]}),s.jsxs("div",{className:"plugin-detail-card",children:[s.jsx("h5",{className:"plugin-detail-section-heading",children:"Settings"}),Z?s.jsx("p",{className:"text-muted",children:"Loading..."}):i.settingsSchema&&Object.keys(i.settingsSchema).length>0?s.jsxs("div",{className:"plugin-settings-form",children:[Object.entries(i.settingsSchema).map(([e,n])=>{const d=`setting-${e}-help`;return s.jsxs("div",{className:"form-group",children:[s.jsxs("label",{htmlFor:`setting-${e}`,children:[n.label||e,n.required&&" *"]}),n.type==="string"&&!n.multiline&&s.jsx("input",{className:"input",type:"text",id:`setting-${e}`,value:a[e]??"",onChange:t=>p({...a,[e]:t.target.value}),placeholder:n.description,"aria-describedby":n.description&&!n.required?d:void 0}),n.type==="string"&&n.multiline&&s.jsx("textarea",{className:"input",id:`setting-${e}`,rows:4,value:a[e]??"",onChange:t=>p({...a,[e]:t.target.value}),placeholder:n.description,"aria-describedby":n.description&&!n.required?d:void 0}),n.type==="password"&&s.jsx("input",{className:"input",type:"password",id:`setting-${e}`,value:a[e]??"",onChange:t=>p({...a,[e]:t.target.value}),placeholder:n.description,"aria-describedby":n.description&&!n.required?d:void 0}),n.type==="number"&&s.jsx("input",{className:"input",type:"number",id:`setting-${e}`,value:a[e]??"",onChange:t=>p({...a,[e]:Number(t.target.value)}),"aria-describedby":n.description&&!n.required?d:void 0}),n.type==="boolean"&&s.jsxs("label",{className:"checkbox-label",children:[s.jsx("input",{type:"checkbox",checked:a[e]??!1,onChange:t=>p({...a,[e]:t.target.checked})}),n.description]}),n.type==="enum"&&s.jsxs("select",{className:"select",id:`setting-${e}`,value:a[e]??"",onChange:t=>p({...a,[e]:t.target.value}),"aria-describedby":n.description&&!n.required?d:void 0,children:[s.jsx("option",{value:"",children:"Select..."}),n.enumValues?.map(t=>s.jsx("option",{value:t,children:t},t))]}),n.type==="array"&&s.jsxs("div",{className:"plugin-settings-array",children:[a[e]?.map((t,u)=>s.jsxs("div",{className:"plugin-settings-array-item",children:[s.jsx("input",{className:"input",type:n.itemType==="number"?"number":"text",value:t??"",onChange:m=>{const r=m.target.value,k=[...a[e]||[]];k[u]=n.itemType==="number"?Number(r):r,p({...a,[e]:k})}}),s.jsx("button",{className:"btn-icon",onClick:()=>{const r=[...a[e]||[]];r.splice(u,1),p({...a,[e]:r})},"aria-label":"Remove item",children:s.jsx(O,{size:14})})]},u)),s.jsxs("button",{className:"btn btn-secondary",onClick:()=>{const t=a[e]||[],u=n.itemType==="number"?0:"";p({...a,[e]:[...t,u]})},children:[s.jsx(A,{size:14})," Add Item"]})]}),n.description&&!n.required&&!n.multiline&&s.jsx("span",{id:d,className:"form-help",children:n.description})]},e)}),s.jsx("button",{className:"btn btn-primary",onClick:X,children:"Save Settings"})]}):s.jsx("p",{className:"text-muted",children:"No configurable settings."})]}),s.jsxs("div",{className:"plugin-detail-actions",children:[i.state==="started"&&s.jsxs("button",{className:"btn btn-secondary",onClick:()=>L(i),disabled:h===i.id,children:[s.jsx(_,{size:14,className:h===i.id?"spin":""}),h===i.id?"Reloading...":"Reload"]}),i.enabled?s.jsx("button",{className:"btn btn-secondary",onClick:()=>F(i),children:"Disable"}):s.jsx("button",{className:"btn btn-primary",onClick:()=>B(i),children:"Enable"}),s.jsxs("button",{className:"btn btn-danger",onClick:()=>D(i),children:[s.jsx(M,{size:14})," Uninstall"]})]})]})]});const Y=new Set(x.map(e=>e.id)),Q=new Map(x.map(e=>[e.id,e])),q=x,W=()=>s.jsxs("section",{className:"plugin-bundled-runtime-section","aria-label":"Bundled Plugins",children:[s.jsxs("div",{className:"plugin-bundled-runtime-header",children:[s.jsx("h4",{className:"plugin-bundled-runtime-heading",children:"Bundled Plugins"}),s.jsx("p",{className:"plugin-bundled-runtime-description",children:"Install Fusion's bundled plugins directly from this screen."})]}),s.jsx("div",{className:"plugin-bundled-runtime-list","aria-label":"Bundled plugin recommendations",children:me.map(e=>{const n=Y.has(e.id);return s.jsxs("div",{className:"plugin-bundled-runtime-item",children:[s.jsxs("div",{className:"plugin-bundled-runtime-meta",children:[s.jsx("span",{className:"plugin-bundled-runtime-name",children:e.name}),e.experimental&&s.jsx("span",{className:"plugin-bundled-runtime-badge",children:"Experimental"}),s.jsx("span",{className:`plugin-bundled-runtime-status ${n?"plugin-bundled-runtime-status--installed":"plugin-bundled-runtime-status--available"}`,children:n?"Installed":"Not installed"})]}),s.jsx("button",{className:`btn ${n?"btn-secondary":"btn-primary"} btn-sm`,onClick:()=>{if(n){const d=Q.get(e.id);d&&U(d);return}K(e)},disabled:R===e.id,children:n?"Manage":R===e.id?"Installing...":`Install ${e.name}`})]},e.id)})})]});return s.jsxs("div",{className:"plugin-manager","data-testid":"plugin-manager",children:[s.jsxs("div",{className:"plugin-manager-header",children:[s.jsx("span",{className:"plugin-manager-header-title",children:"Installed Plugins"}),s.jsxs("div",{className:"plugin-manager-actions",children:[s.jsxs("button",{className:"btn btn-sm",onClick:g,title:"Refresh","aria-label":"Refresh plugin list",children:[s.jsx(te,{size:14,className:S?"spin":""}),"Refresh"]}),s.jsxs("button",{className:"btn btn-primary btn-sm",onClick:()=>f(!0),children:[s.jsx(A,{size:14})," Install"]})]})]}),H&&s.jsxs("div",{className:"plugin-install-form",children:[s.jsxs("p",{className:"plugin-install-hint",children:["Browse to a plugin package root (contains ",s.jsx("code",{children:"manifest.json"}),") or a built ",s.jsx("code",{children:"dist"})," directory."]}),s.jsx(ge,{value:j,onChange:v,placeholder:"Absolute path to plugin directory or dist folder",onInputKeyDown:e=>{e.key==="Enter"&&(e.preventDefault(),z())}}),s.jsxs("div",{className:"plugin-install-actions",children:[s.jsx("button",{className:"btn btn-primary",onClick:z,disabled:C||!j.trim(),children:C?"Installing...":"Install Plugin"}),s.jsx("button",{className:"btn btn-secondary",onClick:()=>{f(!1),v("")},children:"Cancel"})]})]}),S?s.jsx("div",{className:"settings-empty-state",children:"Loading plugins..."}):s.jsxs(s.Fragment,{children:[q.length===0?s.jsxs("div",{className:"settings-empty-state",children:[s.jsx(ie,{size:32,className:"text-muted"}),s.jsx("p",{children:"No plugins installed."}),s.jsx("p",{className:"text-muted",children:"Install a plugin to get started, or use a bundled plugin below."})]}):s.jsx("div",{className:"plugin-list",children:q.map(e=>s.jsxs("div",{className:"plugin-item",children:[s.jsxs("div",{className:"plugin-info",children:[s.jsx("span",{className:"plugin-name",children:e.name}),s.jsxs("span",{className:"plugin-version text-muted",children:["v",e.version]}),s.jsx("span",{className:"plugin-state-badge",style:{color:N[e.state]||N.installed},children:e.state})]}),s.jsxs("div",{className:"plugin-actions",children:[e.state==="started"&&s.jsx("button",{className:"btn-icon",onClick:()=>L(e),disabled:h===e.id,title:"Reload",children:s.jsx(_,{size:14,className:h===e.id?"spin":""})}),s.jsxs("label",{className:"toggle-switch",children:[s.jsx("input",{type:"checkbox",checked:e.enabled,onChange:()=>e.enabled?F(e):B(e)}),s.jsx("span",{className:"toggle-slider"})]}),s.jsx("button",{className:"btn-icon",onClick:()=>U(e),title:"Settings",children:s.jsx(ae,{size:14})}),s.jsx("button",{className:"btn-icon",onClick:()=>D(e),title:"Uninstall",children:s.jsx(M,{size:14})})]})]},e.id))}),W()]})]})}export{Ne as PluginManager,N as STATE_COLORS};
@@ -1 +0,0 @@
1
- import{r as i,j as e}from"./vendor-react-K0fH_qHe.js";import{u as oe,v as de,w as ue,x as he,y as me,z as be,B as fe,D as ve,G as pe,H as xe,I as ye,J as ge,K as je,N as Re,O as Se,S as _e}from"./index-DNzA4aZ7.js";import"./vendor-xterm-DzcZoU0P.js";const O={webSearch:!0,pageFetch:!0,github:!1,localDocs:!0,llmSynthesis:!0};function X(n){const t=n?.researchGlobalDefaults,c=n?.researchSettings;return{enabled:c?.enabled??n?.researchEnabled??n?.researchGlobalEnabled??!0,searchProvider:c?.searchProvider??t?.searchProvider,synthesisProvider:c?.synthesisProvider??t?.synthesisProvider,synthesisModelId:c?.synthesisModelId??t?.synthesisModelId,enabledSources:{webSearch:c?.enabledSources?.webSearch??t?.enabledSources?.webSearch??O.webSearch,pageFetch:c?.enabledSources?.pageFetch??t?.enabledSources?.pageFetch??O.pageFetch,github:c?.enabledSources?.github??t?.enabledSources?.github??O.github,localDocs:c?.enabledSources?.localDocs??t?.enabledSources?.localDocs??O.localDocs,llmSynthesis:c?.enabledSources?.llmSynthesis??t?.enabledSources?.llmSynthesis??O.llmSynthesis},limits:{maxConcurrentRuns:c?.limits?.maxConcurrentRuns??n?.researchMaxConcurrentRuns??n?.researchGlobalMaxConcurrentRuns??3,maxSourcesPerRun:c?.limits?.maxSourcesPerRun??t?.maxSourcesPerRun??n?.researchMaxSourcesPerRun??n?.researchGlobalMaxSourcesPerRun??20,maxDurationMs:c?.limits?.maxDurationMs??n?.researchDefaultTimeout??n?.researchGlobalDefaultTimeout??3e5,requestTimeoutMs:c?.limits?.requestTimeoutMs??n?.researchFetchTimeoutMs??3e4},defaultExportFormat:t?.defaultExportFormat??"markdown"}}const we=300,Ne=4e3,ke=["queued","running","cancelling","retry_waiting"];function Z(n,t){if(n instanceof xe){const c=n;return{message:n.message,status:n.status,code:c.researchCode??"INTERNAL_ERROR",setupHint:c.setupHint,retryable:c.retryable}}return n instanceof Error?{message:n.message,code:"INTERNAL_ERROR"}:{message:t,code:"INTERNAL_ERROR"}}function Ee(n){if(!n)return{cancelable:!1,retryable:!1,isTransitioning:!1,blockingReason:"No run selected"};const t=ke.includes(n.status),c=n.status==="queued"||n.status==="running",f=n.lifecycle?.retryable,u=n.status==="failed"||n.status==="timed_out",a=!!(u&&f);let x;return!c&&t?x="Run is already transitioning":!c&&n.status==="completed"?x="Completed runs cannot be cancelled":!c&&n.status==="cancelled"?x="Run is already cancelled":!c&&n.status==="retry_exhausted"?x="Retry attempts exhausted":!c&&n.status==="failed"?x="Failed runs cannot be cancelled":!c&&n.status==="timed_out"&&(x="Timed out runs cannot be cancelled"),!a&&u&&f===!1&&(x=n.lifecycle?.errorCode==="RETRY_EXHAUSTED"?"Retry attempts exhausted":"Run is not retryable"),{cancelable:c,retryable:a,isTransitioning:t,blockingReason:x}}function Ce(n){const t=n?.projectId,[c,f]=i.useState([]),[u,a]=i.useState(null),[x,R]=i.useState(null),[g,w]=i.useState({available:!0}),[k,P]=i.useState(!0),[L,T]=i.useState(null),[M,j]=i.useState(null),[S,F]=i.useState(""),E=i.useRef(0),N=i.useRef(0),_=i.useRef(t);i.useEffect(()=>{_.current!==t&&(_.current=t,N.current++)},[t]);const v=i.useCallback(async(o=S)=>{const r=++E.current,l=t;T(null),j(null);try{const y=await oe({q:o||void 0,limit:100},l);if(r!==E.current||l!==t)return;f(y.runs),w(y.availability),u&&!y.runs.some(b=>b.id===u)&&(a(null),R(null))}catch(y){if(r!==E.current||l!==t)return;const b=Z(y,"Failed to load research runs");T(b.message),j(b)}finally{r===E.current&&P(!1)}},[t,S,u]),p=i.useCallback(async o=>{const r=await de(o,t);return R(r.run),w(r.availability),r.run},[t]);return i.useEffect(()=>{P(!0);const o=window.setTimeout(()=>{v(S)},we);return()=>window.clearTimeout(o)},[v,S]),i.useEffect(()=>{if(!u){R(null);return}p(u)},[p,u]),i.useEffect(()=>{const o=N.current,r=()=>N.current!==o,l=t?`?projectId=${encodeURIComponent(t)}`:"";let y=!0;const b=()=>{!y||r()||(v(),u&&p(u))},D=ue(`/api/events${l}`,{events:{"research:run:created":b,"research:run:updated":b,"research:run:completed":b,"research:run:failed":b,"research:run:cancelled":b},onReconnect:b}),U=window.setInterval(b,Ne);return()=>{y=!1,D(),window.clearInterval(U)}},[t,v,u,p]),{runs:c,selectedRun:x,selectedRunId:u,setSelectedRunId:a,availability:g,loading:k,error:L,searchQuery:S,setSearchQuery:F,refresh:v,createRun:o=>pe(o,t),cancelRun:async o=>{try{j(null);const r=await ve(o,t);return u===o&&R(r.run),await v(),r}catch(r){const l=Z(r,"Failed to cancel run");throw j(l),l}},retryRun:async o=>{try{j(null);const r=await fe(o,t);return u===o&&R(r.run),await v(),r}catch(r){const l=Z(r,"Failed to retry run");throw j(l),l}},exportRun:(o,r)=>be(o,r,t),createTaskFromRun:(o,r,l,y,b,D)=>me(o,{title:r,findingId:l,description:y,priority:b,attachExport:D},t),attachRunToTask:(o,r,l,y)=>he(o,{taskId:r,findingId:l,attachExport:y},t),uiError:M,runActionState:Ee(x),statusCounts:c.reduce((o,r)=>(o[r.status]+=1,o),{queued:0,running:0,cancelling:0,retry_waiting:0,completed:0,failed:0,cancelled:0,timed_out:0,retry_exhausted:0})}}function Pe({open:n,mode:t,run:c,finding:f,projectId:u,onClose:a,onConfirm:x}){ye(n);const[R,g]=i.useState(!1),[w,k]=i.useState(""),[P,L]=i.useState(""),[T,M]=i.useState("normal"),[j,S]=i.useState(""),[F,E]=i.useState([]),[N,_]=i.useState(!1),[v,p]=i.useState(!1),o=i.useMemo(()=>{const r=(f.content??"").split(/(?<=[.!?])\s+/)[0]??"";return`${f.heading||"Research finding"} — ${r}`.trim()},[f.content,f.heading]);return i.useEffect(()=>{n&&(g(!1),k(`Research: ${f.heading||c.title}`),L(o),M("normal"),S(""),t==="enrich"&&(_(!0),ge(50,0,u).then(r=>E(r.filter(l=>l.column!=="archived"))).finally(()=>_(!1))))},[n,t,u,f.heading,o,c.title]),n?e.jsx("div",{className:"modal-overlay open",role:"presentation",onClick:a,children:e.jsxs("div",{className:"modal modal-lg research-task-action-modal",role:"dialog","aria-modal":"true",onClick:r=>r.stopPropagation(),children:[e.jsxs("div",{className:"modal-header",children:[e.jsx("h3",{children:t==="create"?"Create task from finding":"Enrich existing task"}),e.jsx("button",{className:"modal-close",type:"button","aria-label":"Close",onClick:a,children:"×"})]}),e.jsxs("div",{className:"research-task-action-modal__body",children:[e.jsxs("div",{className:"card research-task-action-modal__preview",children:[e.jsxs("p",{children:[e.jsx("strong",{children:"Run:"})," ",c.id]}),e.jsxs("p",{children:[e.jsx("strong",{children:"Finding:"})," ",f.id,f.heading?` — ${f.heading}`:""]}),e.jsx("p",{children:o||"No preview available."})]}),t==="create"?e.jsxs(e.Fragment,{children:[e.jsxs("label",{className:"research-task-action-modal__field",children:["Title",e.jsx("input",{className:"input",value:w,onChange:r=>k(r.target.value)})]}),e.jsxs("label",{className:"research-task-action-modal__field",children:["Description",e.jsx("textarea",{className:"input research-task-action-modal__textarea",value:P,onChange:r=>L(r.target.value)})]}),e.jsxs("label",{className:"research-task-action-modal__field",children:["Priority",e.jsxs("select",{className:"select",value:T,onChange:r=>M(r.target.value),children:[e.jsx("option",{value:"low",children:"Low"}),e.jsx("option",{value:"normal",children:"Normal"}),e.jsx("option",{value:"high",children:"High"}),e.jsx("option",{value:"urgent",children:"Urgent"})]})]})]}):e.jsxs("label",{className:"research-task-action-modal__field",children:["Target task",e.jsx("input",{className:"input",list:"research-task-action-task-list",value:j,placeholder:N?"Loading tasks…":"Enter task ID",onChange:r=>S(r.target.value)}),e.jsx("datalist",{id:"research-task-action-task-list",children:F.map(r=>e.jsx("option",{value:r.id,children:r.title},r.id))})]}),e.jsxs("label",{className:"checkbox-label",children:[e.jsx("input",{type:"checkbox",checked:R,onChange:r=>g(r.target.checked)}),e.jsx("span",{children:"Attach markdown export artifact"})]})]}),e.jsxs("div",{className:"modal-actions",children:[e.jsx("button",{className:"btn",type:"button",onClick:a,children:"Cancel"}),e.jsx("button",{className:"btn btn-primary",type:"button",disabled:v||t==="enrich"&&!j,onClick:()=>{p(!0),x({taskId:t==="enrich"?j:void 0,title:t==="create"?w.trim():void 0,description:t==="create"?P.trim():void 0,priority:t==="create"?T:void 0,attachExport:R}).finally(()=>p(!1))},children:t==="create"?"Create Task":"Enrich Task"})]})]})}):null}const Te=["web-search","page-fetch","github","local-docs","llm-synthesis"],Ae={"web-search":"webSearch","page-fetch":"pageFetch",github:"github","local-docs":"localDocs","llm-synthesis":"llmSynthesis"},Ie={"web-search":"Web Search","page-fetch":"Page Fetch",github:"GitHub","local-docs":"Local Docs","llm-synthesis":"LLM Synthesis"};function qe({projectId:n,addToast:t,onOpenSettings:c,readinessVersion:f=0}){const{runs:u,selectedRun:a,selectedRunId:x,setSelectedRunId:R,availability:g,loading:w,error:k,searchQuery:P,setSearchQuery:L,createRun:T,cancelRun:M,retryRun:j,exportRun:S,createTaskFromRun:F,attachRunToTask:E,statusCounts:N,refresh:_,uiError:v,runActionState:p}=Ce({projectId:n}),[o,r]=i.useState(""),[l,y]=i.useState(()=>X(void 0)),[b,D]=i.useState([]),[U,z]=i.useState(!1),[ee,se]=i.useState([]),[A,$]=i.useState(null),[I,H]=i.useState(null),Q=g.supportedProviders??Te,G=s=>l.enabledSources[Ae[s]];i.useEffect(()=>{const s=Q.filter(d=>G(d));se(d=>{const m=d.filter(h=>s.includes(h));return m.length>0?m:s})},[l.enabledSources,Q]),i.useEffect(()=>{let s=!1;return Promise.all([je(n),Re().catch(()=>({providers:[]}))]).then(([d,m])=>{s||(y(X(d)),D(m.providers.filter(h=>h.type==="api_key").map(h=>({id:h.id,authenticated:h.authenticated}))))}).catch(()=>{s||y(X(void 0))}),()=>{s=!0}},[n,f]);const ie=i.useMemo(()=>a?a.status:"No run selected",[a]),ce=i.useMemo(()=>a?a.status==="queued"||a.status==="retry_waiting"?"status-dot status-dot--pending":a.status==="running"?"status-dot status-dot--connecting":a.status==="completed"?"status-dot status-dot--online":a.status==="failed"||a.status==="cancelled"?"status-dot status-dot--error":"status-dot":"status-dot",[a]),K=g.supportedExportFormats??["markdown","json","html"],V=l.searchProvider,te=l.enabledSources.webSearch&&!V,re=l.enabledSources.llmSynthesis&&(!l.synthesisProvider||!l.synthesisModelId),J=i.useMemo(()=>new Map(b.map(s=>[s.id,s.authenticated])),[b]),Y=i.useMemo(()=>{const s=new Set;return l.enabledSources.webSearch&&V&&s.add(V),l.enabledSources.llmSynthesis&&l.synthesisProvider&&s.add(l.synthesisProvider),[...s].filter(d=>J.has(d))},[l.enabledSources.llmSynthesis,l.enabledSources.webSearch,l.synthesisProvider,V,J]).find(s=>J.get(s)!==!0),q=i.useMemo(()=>g.available?l.enabled?te||re?{reason:"Research defaults are incomplete.",details:"Select the required provider/model defaults in Research settings.",settingsSection:"research-global"}:Y?{reason:`Missing API key for ${Y}.`,details:"Add provider credentials in Authentication settings.",settingsSection:"authentication"}:null:{reason:"Research is disabled for this project.",details:"Enable project research settings to create runs.",settingsSection:"research-project"}:{reason:g.reason??"Research is unavailable for this project.",details:g.setupInstructions,settingsSection:"research-project"},[g.available,g.reason,g.setupInstructions,l.enabled,Y,te,re]),B=async(s,d,m)=>{$(s);try{await d(),t?.(m,"success"),await _()}catch(h){t?.(h instanceof Error?h.message:"Action failed","error")}finally{$(null)}},W=async s=>{if(a){$(`export-${s}`);try{const d=await S(a.id,s),m=new Blob([d.content],{type:"text/plain;charset=utf-8"}),h=URL.createObjectURL(m),C=document.createElement("a");C.href=h,C.download=d.filename,document.body.appendChild(C),C.click(),C.remove(),URL.revokeObjectURL(h),t?.(`Exported ${d.filename}`,"success")}catch(d){t?.(d instanceof Error?d.message:"Export failed","error")}finally{$(null)}}},le=async()=>{if(o.trim()){z(!0);try{const s=ee.filter(m=>G(m));if(s.length===0){z(!1),t?.("No enabled research sources are available for this project.","error");return}const d=await T({query:o.trim(),providers:s});R(d.run.id),r(""),t?.("Research run created","success"),await _()}catch(s){t?.(s instanceof Error?s.message:"Failed to create run","error")}finally{z(!1)}}};return e.jsxs("section",{className:"research-view","aria-label":"Research view",children:[e.jsxs("header",{className:"research-view__header",children:[e.jsxs("div",{children:[e.jsx("h2",{className:"research-view__title",children:"Research"}),e.jsx("p",{className:"research-view__subtitle",children:"Create and track research runs with cited findings."})]}),e.jsx("button",{className:"btn",type:"button",onClick:()=>void _(),children:"Refresh"})]}),q?e.jsxs("div",{className:"research-view__state research-view__state--error card","data-testid":"research-state-unavailable",children:[e.jsx("p",{children:q.reason}),q.details&&e.jsx("p",{children:q.details}),e.jsxs("p",{children:["Current defaults: provider ",l.searchProvider??"(not set)",", max sources ",l.limits.maxSourcesPerRun]}),e.jsxs("div",{className:"research-view__actions",children:[e.jsx("button",{className:"btn",type:"button",onClick:()=>void _(),children:"Refresh"}),e.jsx("button",{className:"btn btn-primary",type:"button",onClick:()=>c?.(q.settingsSection),children:"Open Settings"})]})]}):e.jsxs("div",{className:"research-view__layout",children:[e.jsxs("aside",{className:"research-view__sidebar card",children:[e.jsxs("div",{className:"research-view__form",children:[e.jsxs("div",{className:"form-group",children:[e.jsx("label",{htmlFor:"research-query",children:"Query"}),e.jsx("textarea",{id:"research-query",className:"input research-view__textarea",value:o,onChange:s=>r(s.target.value)})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{children:"Providers"}),e.jsx("div",{className:"research-view__providers",children:Q.map(s=>e.jsxs("label",{className:"checkbox-label",children:[e.jsx("input",{type:"checkbox",checked:ee.includes(s),disabled:!G(s),onChange:()=>{G(s)&&se(d=>d.includes(s)?d.filter(m=>m!==s):[...d,s])}}),e.jsx("span",{children:Ie[s]??s})]},s))})]}),e.jsxs("button",{className:"btn btn-primary",type:"button",disabled:!o.trim()||U,onClick:()=>void le(),children:[U?e.jsx(Se,{className:"animate-spin",size:14}):null,"Create Run"]})]}),e.jsxs("div",{className:"research-view__history-header form-group",children:[e.jsx("label",{htmlFor:"research-run-search",children:"Search"}),e.jsxs("div",{className:"research-view__history-search-row",children:[e.jsx(_e,{size:14}),e.jsx("input",{id:"research-run-search",className:"input",placeholder:"Search runs",value:P,onChange:s=>L(s.target.value)})]})]}),e.jsx("div",{className:"research-view__history","data-testid":"research-state-running",children:u.map(s=>e.jsxs("button",{type:"button",className:`research-view__history-item card${x===s.id?" research-view__history-item--active":""}`,onClick:()=>R(s.id),children:[e.jsx("span",{className:"card-id",children:s.id}),e.jsx("span",{children:s.title})]},s.id))})]}),e.jsxs("div",{className:"research-view__reader card",children:[w&&e.jsx("p",{"data-testid":"research-state-loading",children:"Loading research runs…"}),!w&&k&&e.jsx("p",{"data-testid":"research-state-error",children:k}),!w&&!k&&u.length===0&&e.jsx("p",{"data-testid":"research-state-empty",children:"No research runs yet"}),a&&e.jsxs("div",{children:[e.jsxs("div",{className:"research-view__status-row",children:[e.jsx("span",{className:ce}),e.jsx("strong",{children:ie})]}),e.jsx("h3",{className:"research-view__run-title",children:a.title}),e.jsx("p",{className:"research-view__run-query",children:a.query}),e.jsx("p",{className:"research-view__run-summary","data-testid":"research-state-results",children:a.results?.summary??"No summary yet."}),e.jsxs("div",{className:"research-view__actions",children:[e.jsx("button",{className:"btn",type:"button",title:p.cancelable?void 0:p.blockingReason,disabled:A==="cancel"||A==="retry"||!p.cancelable,onClick:()=>void B("cancel",()=>M(a.id),"Run cancelled"),children:"Cancel"}),e.jsx("button",{className:"btn",type:"button",title:p.retryable?void 0:p.blockingReason,disabled:A==="cancel"||A==="retry"||!p.retryable,onClick:()=>void B("retry",()=>j(a.id),"Run retried"),children:"Retry"}),K.includes("markdown")&&e.jsx("button",{className:"btn",type:"button",disabled:A==="export-markdown",onClick:()=>void W("markdown"),children:"Export MD"}),K.includes("json")&&e.jsx("button",{className:"btn",type:"button",disabled:A==="export-json",onClick:()=>void W("json"),children:"Export JSON"}),K.includes("html")&&e.jsx("button",{className:"btn",type:"button",disabled:A==="export-html",onClick:()=>void W("html"),children:"Export HTML"})]}),a.error&&e.jsx("p",{className:"research-view__error",children:a.error}),v&&e.jsxs("div",{className:"form-error",role:"alert",children:[e.jsx("p",{children:v.message}),v.setupHint&&e.jsx("p",{children:v.setupHint}),v.code==="MISSING_CREDENTIALS"&&e.jsx("button",{className:"btn btn-sm",type:"button",onClick:()=>c?.("authentication"),children:"Open Authentication Settings"}),v.code==="FEATURE_DISABLED"&&e.jsx("button",{className:"btn btn-sm",type:"button",onClick:()=>c?.("research-project"),children:"Open Research Settings"})]}),p.blockingReason&&e.jsx("p",{className:"research-view__run-query",children:p.blockingReason}),Array.isArray(a.results?.findings)&&a.results.findings.length>0&&e.jsx("div",{className:"research-view__findings",children:a.results.findings.map((s,d)=>{const h=s.id?.trim()||`finding-${d+1}`;return e.jsxs("article",{className:"research-view__finding card",children:[e.jsx("h4",{children:s.heading}),e.jsx("p",{children:s.content}),e.jsxs("div",{className:"research-view__actions research-view__finding-actions",children:[e.jsx("button",{className:"btn btn-primary btn-sm",type:"button",onClick:()=>H({mode:"create",findingId:h}),children:"Create Task"}),e.jsx("button",{className:"btn btn-sm",type:"button",onClick:()=>H({mode:"enrich",findingId:h}),children:"Enrich Task"})]})]},h)})}),Array.isArray(a.results?.citations)&&a.results.citations.length>0&&e.jsx("ul",{className:"research-view__citations",children:a.results.citations.map(s=>e.jsx("li",{children:e.jsx("a",{href:s,target:"_blank",rel:"noreferrer",children:s})},s))}),a.events.length>0&&e.jsxs("details",{children:[e.jsx("summary",{children:"Run history"}),e.jsx("ul",{className:"research-view__events",children:a.events.map(s=>e.jsx("li",{children:s.message},s.id))})]})]}),!a&&u.length>0&&e.jsx("p",{children:"Select a run to view details."}),e.jsxs("div",{className:"research-view__stats",children:[e.jsxs("div",{className:"research-view__stat-card",children:[e.jsx("div",{className:"research-view__stat-label",children:"Running"}),e.jsx("div",{className:"research-view__stat-value",children:N.running})]}),e.jsxs("div",{className:"research-view__stat-card",children:[e.jsx("div",{className:"research-view__stat-label",children:"Completed"}),e.jsx("div",{className:"research-view__stat-value",children:N.completed})]}),e.jsxs("div",{className:"research-view__stat-card",children:[e.jsx("div",{className:"research-view__stat-label",children:"Failed"}),e.jsx("div",{className:"research-view__stat-value",children:N.failed})]})]})]})]}),a&&I&&(()=>{const s=a.results?.findings?.findIndex((m,h)=>(m.id?.trim()||`finding-${h+1}`)===I.findingId)??-1,d=s>=0?a.results.findings[s]:null;return d?e.jsx(Pe,{open:!0,mode:I.mode,run:a,finding:{id:I.findingId,heading:d.heading,content:d.content},projectId:n,onClose:()=>H(null),onConfirm:async({taskId:m,title:h,description:C,priority:ae,attachExport:ne})=>{I.mode==="create"?await B("create-task",()=>F(a.id,h,I.findingId,C,ae,ne),"Task created from research"):m&&await B("attach-task",()=>E(a.id,m,I.findingId,ne),"Task enriched from research"),H(null)}}):null})()]})}export{qe as ResearchView};