@runfusion/fusion 0.20.0 → 0.21.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 (28) hide show
  1. package/dist/bin.js +30 -3
  2. package/dist/client/assets/{AgentDetailView-C6BG7O7i.js → AgentDetailView-Dg7Qa1rG.js} +1 -1
  3. package/dist/client/assets/{ChatView-DeXUYwSY.js → ChatView-ODq-kBk6.js} +1 -1
  4. package/dist/client/assets/{DevServerView-Dariyxt_.js → DevServerView-6PS9Lvl7.js} +1 -1
  5. package/dist/client/assets/{DirectoryPicker-SchiK-Aq.js → DirectoryPicker-B3dza2Dq.js} +1 -1
  6. package/dist/client/assets/{DocumentsView-C6v-tBhG.js → DocumentsView-Bu9YYlki.js} +1 -1
  7. package/dist/client/assets/{InsightsView-Cqim12az.js → InsightsView-CqDethVs.js} +1 -1
  8. package/dist/client/assets/{MemoryView-CakLoJtY.js → MemoryView-BLIm9Vr7.js} +1 -1
  9. package/dist/client/assets/{NodesView-BxGm3poT.js → NodesView-DEXvp3WT.js} +1 -1
  10. package/dist/client/assets/{PiExtensionsManager-lJbmskyZ.js → PiExtensionsManager-C2YjI9o2.js} +1 -1
  11. package/dist/client/assets/{PluginManager-BZjNNf9m.js → PluginManager-Dnf-LhYw.js} +1 -1
  12. package/dist/client/assets/{ResearchView-Bzsr9V0y.js → ResearchView-Z0TZ7WGo.js} +1 -1
  13. package/dist/client/assets/{RoadmapsView-CeKks_OI.js → RoadmapsView-DPcfX5MS.js} +1 -1
  14. package/dist/client/assets/{SettingsModal-D-9CLguN.js → SettingsModal-B6RN9VYe.js} +3 -3
  15. package/dist/client/assets/{SettingsModal-YdeVPhRJ.js → SettingsModal-BRNAPR1u.js} +1 -1
  16. package/dist/client/assets/{SetupWizardModal-DAC04LlA.js → SetupWizardModal-BFc3xID2.js} +1 -1
  17. package/dist/client/assets/{SkillsView-CClC_5RN.js → SkillsView-CipGahOR.js} +1 -1
  18. package/dist/client/assets/index-NFptaeUQ.js +1222 -0
  19. package/dist/client/assets/{star-DxVRh9VT.js → star-B314SwLA.js} +1 -1
  20. package/dist/client/assets/{users-3SD3oNMQ.js → users-Bu_ltePs.js} +1 -1
  21. package/dist/client/index.html +1 -1
  22. package/dist/client/version.json +1 -1
  23. package/dist/droid-cli/package.json +1 -1
  24. package/dist/extension.js +18 -0
  25. package/dist/pi-claude-cli/package.json +1 -1
  26. package/dist/plugins/fusion-plugin-dependency-graph/package.json +1 -1
  27. package/package.json +2 -1
  28. package/dist/client/assets/index-CrHLf3pB.js +0 -1222
@@ -1,2 +1,2 @@
1
- import{r as a,j as e}from"./vendor-react-K0fH_qHe.js";import{u as Le}from"./SettingsModal-YdeVPhRJ.js";import{b8 as Ee,b9 as ke,ba as Ie,bb as Re,bc as qe,bd as _e,be as Pe,bf as Me,bg as we,bh as We,bi as Oe,bj as Te,bk as Ae,bl as $e,Q as Ue,bm as Qe,V as w,bn as Fe}from"./index-CrHLf3pB.js";import"./vendor-xterm-DzcZoU0P.js";const O=".fusion/memory/MEMORY.md",He=5e4,Ye="0 3 * * *",Be="0 4 * * *";function he(i){return{memoryEnabled:i.memoryEnabled!==!1,memoryAutoSummarizeEnabled:i.memoryAutoSummarizeEnabled??!1,memoryAutoSummarizeThresholdChars:i.memoryAutoSummarizeThresholdChars??He,memoryAutoSummarizeSchedule:i.memoryAutoSummarizeSchedule??Ye,memoryDreamsEnabled:i.memoryDreamsEnabled??!1,memoryDreamsSchedule:i.memoryDreamsSchedule??Be}}function De(i,t){return i.some(m=>m.path===t)?t:i.find(m=>m.path===O)?.path??i[0]?.path??O}function Ve(i={}){const{projectId:t}=i,[m,u]=a.useState(""),[C,A]=a.useState(!0),[E,k]=a.useState(!1),[b,x]=a.useState(!1),[r,p]=a.useState(null),[T,X]=a.useState(!0),[J,L]=a.useState(!1),[S,P]=a.useState(()=>he({})),[F,ee]=a.useState(!0),[ue,$]=a.useState(!1),[o,v]=a.useState([]),[se,I]=a.useState(!0),[c,M]=a.useState(O),[W,y]=a.useState(""),[d,te]=a.useState(!1),[U,f]=a.useState(!1),[ae,Q]=a.useState(!1),[ne,H]=a.useState(!1),[Y,re]=a.useState(!1),[D,z]=a.useState(null),[ye,R]=a.useState(!0),[ge,B]=a.useState(!1),[ie,V]=a.useState(!1),[le,G]=a.useState(null),{status:me,loading:Z,refresh:j}=Le({projectId:t}),be=a.useCallback(n=>{y(n),f(!0)},[]),N=a.useCallback(async n=>{te(!0);try{const{content:l}=await Ee(n,t);M(n),y(l),f(!1)}finally{te(!1)}},[t]),q=a.useCallback(async()=>{I(!0);try{const{files:n}=await ke(t);if(v(n),n.length===0){M(O),y(""),f(!1);return}const l=De(n,c);l!==c&&await N(l)}finally{I(!1)}},[t,c,N]);a.useEffect(()=>{let n=!1;async function l(){try{const s=await $e(t);n||(u(s.content),A(!1))}catch{n||(u(""),A(!1))}}return l(),()=>{n=!0}},[t]),a.useEffect(()=>{let n=!1;async function l(){try{const s=await we(t);n||(p(s.content),L(s.exists),X(!1))}catch{n||(p(null),L(!1),X(!1))}}return l(),()=>{n=!0}},[t]),a.useEffect(()=>{let n=!1;async function l(){ee(!0);try{const s=await Ue(t);n||P(he(s))}catch{n||P(he({}))}finally{n||ee(!1)}}return l(),()=>{n=!0}},[t]),a.useEffect(()=>{let n=!1;async function l(){I(!0);try{const{files:s}=await ke(t);if(n)return;if(v(s),s.length===0){M(O),y(""),f(!1);return}const h=De(s,c),{content:g}=await Ee(h,t);if(n)return;M(h),y(g),f(!1)}catch{n||(v([]),M(O),y(""),f(!1))}finally{n||I(!1)}}return l(),()=>{n=!0}},[t,c]),a.useEffect(()=>{let n=!1;async function l(){try{const s=await Me(t);n||(z(s),R(!1))}catch{n||(z(null),R(!1))}}return l(),()=>{n=!0}},[t]),a.useEffect(()=>{let n=!1;async function l(){try{const s=await Qe(t);n||G(s)}catch{n||G(null)}}return l(),()=>{n=!0}},[t]);const ce=a.useCallback(n=>{u(n),k(!0)},[]),oe=a.useCallback(async()=>{if(E){x(!0);try{await Ie(m,t),k(!1)}finally{x(!1)}}},[m,E,t]),xe=a.useCallback(async n=>{$(!0);try{const l=await Re(n,t);P(he(l))}finally{$(!1)}},[t]),pe=a.useCallback(async n=>{await N(n)},[N]),fe=a.useCallback(async()=>{if(U){Q(!0);try{await qe(c,W,t),f(!1),await q()}finally{Q(!1)}}},[W,U,c,t,q]),je=a.useCallback(async()=>{V(!0);try{const n=await _e(t);return await j(),n}finally{V(!1)}},[t,j]),Se=a.useCallback(async n=>Pe(n,t),[t]),K=a.useCallback(async()=>{try{const n=await Me(t);z(n)}catch{z(null)}},[t]),_=a.useCallback(async()=>{try{const n=await we(t);p(n.content),L(n.exists)}catch{p(null),L(!1)}},[t]),de=a.useCallback(async n=>{await We(n,t),await _()},[t,_]),ve=a.useCallback(async()=>{H(!0);try{const n=await Oe(t);return await Promise.all([_(),K()]),{success:n.success,summary:n.summary}}finally{H(!1)}},[t,_,K]),Ne=a.useCallback(async()=>{re(!0);try{return await Te(t)}finally{re(!1)}},[t]),Ce=a.useCallback(async n=>{B(!0);try{const l=n?await Ae(n,t):await Ae(t);if(n){const s=l.path??n;M(s),y(l.content),f(!1),await q();return}u(l.content),k(!0)}finally{B(!1)}},[t,q]);return{workingMemory:m,workingMemoryLoading:C,workingMemoryDirty:E,setWorkingMemory:ce,saveWorkingMemory:oe,savingWorkingMemory:b,insightsContent:r,insightsLoading:T,insightsExists:J,refreshInsights:_,saveInsights:de,memorySettings:S,settingsLoading:F,savingMemorySettings:ue,saveMemorySettings:xe,memoryFiles:o,memoryFilesLoading:se,selectedFilePath:c,selectedFileContent:W,selectedFileLoading:d,selectedFileDirty:U,setSelectedFileContent:be,selectFile:pe,saveSelectedFile:fe,savingSelectedFile:ae,reloadMemoryFiles:q,backendStatus:me,backendLoading:Z,extractInsights:ve,extracting:ne,triggerDreamNow:Ne,dreamRunning:Y,auditReport:D,auditLoading:ye,refreshAudit:K,compactMemory:Ce,compacting:ge,installQmdAction:je,installingQmd:ie,testRetrieval:Se,stats:le}}const Ge={Patterns:"pattern",Principles:"principle",Conventions:"convention",Pitfalls:"pitfall",Context:"context"},Ze={"long-term":"Long-term",daily:"Daily",dreams:"Dreams"},Ke={"long-term":"Curated durable decisions, conventions, constraints, and pitfalls promoted from dreams.",daily:"Raw daily observations, open loops, and running context for dream processing.",dreams:"Synthesized patterns and open loops promoted from daily memory."},Xe=72;function Je(i,t){if(i.length<=t)return i;const m=Math.max(1,t-1),u=Math.ceil(m/2),C=Math.floor(m/2);return`${i.slice(0,u)}…${i.slice(i.length-C)}`}function es(i){const t=`${i.label} — ${i.path}`;return Je(t,Xe)}function ss(i){if(!i)return[];const t=[],m=i.split(/(?=^## )/m);for(const u of m){const C=u.trim();if(!C)continue;const A=C.match(/^##\s+(.+?)(\n|$)/);if(A){const E=A[1].trim(),k=Ge[E]??E.toLowerCase(),b=C.slice(A[0].length).trim(),x=b.split(`
1
+ import{r as a,j as e}from"./vendor-react-K0fH_qHe.js";import{u as Le}from"./SettingsModal-BRNAPR1u.js";import{b8 as Ee,b9 as ke,ba as Ie,bb as Re,bc as qe,bd as _e,be as Pe,bf as Me,bg as we,bh as We,bi as Oe,bj as Te,bk as Ae,bl as $e,Q as Ue,bm as Qe,V as w,bn as Fe}from"./index-NFptaeUQ.js";import"./vendor-xterm-DzcZoU0P.js";const O=".fusion/memory/MEMORY.md",He=5e4,Ye="0 3 * * *",Be="0 4 * * *";function he(i){return{memoryEnabled:i.memoryEnabled!==!1,memoryAutoSummarizeEnabled:i.memoryAutoSummarizeEnabled??!1,memoryAutoSummarizeThresholdChars:i.memoryAutoSummarizeThresholdChars??He,memoryAutoSummarizeSchedule:i.memoryAutoSummarizeSchedule??Ye,memoryDreamsEnabled:i.memoryDreamsEnabled??!1,memoryDreamsSchedule:i.memoryDreamsSchedule??Be}}function De(i,t){return i.some(m=>m.path===t)?t:i.find(m=>m.path===O)?.path??i[0]?.path??O}function Ve(i={}){const{projectId:t}=i,[m,u]=a.useState(""),[C,A]=a.useState(!0),[E,k]=a.useState(!1),[b,x]=a.useState(!1),[r,p]=a.useState(null),[T,X]=a.useState(!0),[J,L]=a.useState(!1),[S,P]=a.useState(()=>he({})),[F,ee]=a.useState(!0),[ue,$]=a.useState(!1),[o,v]=a.useState([]),[se,I]=a.useState(!0),[c,M]=a.useState(O),[W,y]=a.useState(""),[d,te]=a.useState(!1),[U,f]=a.useState(!1),[ae,Q]=a.useState(!1),[ne,H]=a.useState(!1),[Y,re]=a.useState(!1),[D,z]=a.useState(null),[ye,R]=a.useState(!0),[ge,B]=a.useState(!1),[ie,V]=a.useState(!1),[le,G]=a.useState(null),{status:me,loading:Z,refresh:j}=Le({projectId:t}),be=a.useCallback(n=>{y(n),f(!0)},[]),N=a.useCallback(async n=>{te(!0);try{const{content:l}=await Ee(n,t);M(n),y(l),f(!1)}finally{te(!1)}},[t]),q=a.useCallback(async()=>{I(!0);try{const{files:n}=await ke(t);if(v(n),n.length===0){M(O),y(""),f(!1);return}const l=De(n,c);l!==c&&await N(l)}finally{I(!1)}},[t,c,N]);a.useEffect(()=>{let n=!1;async function l(){try{const s=await $e(t);n||(u(s.content),A(!1))}catch{n||(u(""),A(!1))}}return l(),()=>{n=!0}},[t]),a.useEffect(()=>{let n=!1;async function l(){try{const s=await we(t);n||(p(s.content),L(s.exists),X(!1))}catch{n||(p(null),L(!1),X(!1))}}return l(),()=>{n=!0}},[t]),a.useEffect(()=>{let n=!1;async function l(){ee(!0);try{const s=await Ue(t);n||P(he(s))}catch{n||P(he({}))}finally{n||ee(!1)}}return l(),()=>{n=!0}},[t]),a.useEffect(()=>{let n=!1;async function l(){I(!0);try{const{files:s}=await ke(t);if(n)return;if(v(s),s.length===0){M(O),y(""),f(!1);return}const h=De(s,c),{content:g}=await Ee(h,t);if(n)return;M(h),y(g),f(!1)}catch{n||(v([]),M(O),y(""),f(!1))}finally{n||I(!1)}}return l(),()=>{n=!0}},[t,c]),a.useEffect(()=>{let n=!1;async function l(){try{const s=await Me(t);n||(z(s),R(!1))}catch{n||(z(null),R(!1))}}return l(),()=>{n=!0}},[t]),a.useEffect(()=>{let n=!1;async function l(){try{const s=await Qe(t);n||G(s)}catch{n||G(null)}}return l(),()=>{n=!0}},[t]);const ce=a.useCallback(n=>{u(n),k(!0)},[]),oe=a.useCallback(async()=>{if(E){x(!0);try{await Ie(m,t),k(!1)}finally{x(!1)}}},[m,E,t]),xe=a.useCallback(async n=>{$(!0);try{const l=await Re(n,t);P(he(l))}finally{$(!1)}},[t]),pe=a.useCallback(async n=>{await N(n)},[N]),fe=a.useCallback(async()=>{if(U){Q(!0);try{await qe(c,W,t),f(!1),await q()}finally{Q(!1)}}},[W,U,c,t,q]),je=a.useCallback(async()=>{V(!0);try{const n=await _e(t);return await j(),n}finally{V(!1)}},[t,j]),Se=a.useCallback(async n=>Pe(n,t),[t]),K=a.useCallback(async()=>{try{const n=await Me(t);z(n)}catch{z(null)}},[t]),_=a.useCallback(async()=>{try{const n=await we(t);p(n.content),L(n.exists)}catch{p(null),L(!1)}},[t]),de=a.useCallback(async n=>{await We(n,t),await _()},[t,_]),ve=a.useCallback(async()=>{H(!0);try{const n=await Oe(t);return await Promise.all([_(),K()]),{success:n.success,summary:n.summary}}finally{H(!1)}},[t,_,K]),Ne=a.useCallback(async()=>{re(!0);try{return await Te(t)}finally{re(!1)}},[t]),Ce=a.useCallback(async n=>{B(!0);try{const l=n?await Ae(n,t):await Ae(t);if(n){const s=l.path??n;M(s),y(l.content),f(!1),await q();return}u(l.content),k(!0)}finally{B(!1)}},[t,q]);return{workingMemory:m,workingMemoryLoading:C,workingMemoryDirty:E,setWorkingMemory:ce,saveWorkingMemory:oe,savingWorkingMemory:b,insightsContent:r,insightsLoading:T,insightsExists:J,refreshInsights:_,saveInsights:de,memorySettings:S,settingsLoading:F,savingMemorySettings:ue,saveMemorySettings:xe,memoryFiles:o,memoryFilesLoading:se,selectedFilePath:c,selectedFileContent:W,selectedFileLoading:d,selectedFileDirty:U,setSelectedFileContent:be,selectFile:pe,saveSelectedFile:fe,savingSelectedFile:ae,reloadMemoryFiles:q,backendStatus:me,backendLoading:Z,extractInsights:ve,extracting:ne,triggerDreamNow:Ne,dreamRunning:Y,auditReport:D,auditLoading:ye,refreshAudit:K,compactMemory:Ce,compacting:ge,installQmdAction:je,installingQmd:ie,testRetrieval:Se,stats:le}}const Ge={Patterns:"pattern",Principles:"principle",Conventions:"convention",Pitfalls:"pitfall",Context:"context"},Ze={"long-term":"Long-term",daily:"Daily",dreams:"Dreams"},Ke={"long-term":"Curated durable decisions, conventions, constraints, and pitfalls promoted from dreams.",daily:"Raw daily observations, open loops, and running context for dream processing.",dreams:"Synthesized patterns and open loops promoted from daily memory."},Xe=72;function Je(i,t){if(i.length<=t)return i;const m=Math.max(1,t-1),u=Math.ceil(m/2),C=Math.floor(m/2);return`${i.slice(0,u)}…${i.slice(i.length-C)}`}function es(i){const t=`${i.label} — ${i.path}`;return Je(t,Xe)}function ss(i){if(!i)return[];const t=[],m=i.split(/(?=^## )/m);for(const u of m){const C=u.trim();if(!C)continue;const A=C.match(/^##\s+(.+?)(\n|$)/);if(A){const E=A[1].trim(),k=Ge[E]??E.toLowerCase(),b=C.slice(A[0].length).trim(),x=b.split(`
2
2
  `).map(r=>r.replace(/^-\s+/,"").trim()).filter(r=>r.length>0&&(r.startsWith("- ")||r.startsWith("* ")));(x.length>0||b.length>0)&&t.push({name:E,key:k,items:x.length>0?x:b.length>0?[b]:[],expanded:!0})}}return t}function ts(i){if(!i)return null;const t=i.match(/##\s+Last\s+Updated:\s*(\d{4}-\d{2}-\d{2})/i);return t?t[1]:null}function as(i){return i.reduce((t,m)=>t+m.items.length,0)}function ns(i){switch(i){case"file":return"File (.fusion/memory/, agent/<agent-name>/memory/)";case"readonly":return"Read-Only";case"qmd":return"QMD (Quantized Memory Distillation)";default:return i}}function rs(i){switch(i){case"healthy":return"Healthy";case"warning":return"Warning";case"issues":return"Issues Found"}}function os({projectId:i,addToast:t}){const[m,u]=a.useState("working"),[C,A]=a.useState(new Set),[E,k]=a.useState(!1),[b,x]=a.useState(null),[r,p]=a.useState({memoryEnabled:!0,memoryAutoSummarizeEnabled:!1,memoryAutoSummarizeThresholdChars:5e4,memoryAutoSummarizeSchedule:"0 3 * * *",memoryDreamsEnabled:!1,memoryDreamsSchedule:"0 4 * * *"}),[T,X]=a.useState(""),[J,L]=a.useState(!1),[S,P]=a.useState(null),{insightsContent:F,insightsLoading:ee,insightsExists:ue,saveInsights:$,memorySettings:o,settingsLoading:v,saveMemorySettings:se,savingMemorySettings:I,backendStatus:c,backendLoading:M,extractInsights:W,extracting:y,auditReport:d,auditLoading:te,refreshAudit:U,compactMemory:f,compacting:ae,installQmdAction:Q,installingQmd:ne,testRetrieval:H,memoryFiles:Y,memoryFilesLoading:re,selectedFilePath:D,selectedFileContent:z,selectedFileLoading:ye,selectedFileDirty:R,setSelectedFileContent:ge,selectFile:B,saveSelectedFile:ie,savingSelectedFile:V,reloadMemoryFiles:le,triggerDreamNow:G,dreamRunning:me}=Ve({projectId:i});a.useEffect(()=>{p(o)},[o]);const Z=a.useMemo(()=>r.memoryEnabled!==o.memoryEnabled||r.memoryAutoSummarizeEnabled!==o.memoryAutoSummarizeEnabled||r.memoryAutoSummarizeThresholdChars!==o.memoryAutoSummarizeThresholdChars||r.memoryAutoSummarizeSchedule!==o.memoryAutoSummarizeSchedule||r.memoryDreamsEnabled!==o.memoryDreamsEnabled||r.memoryDreamsSchedule!==o.memoryDreamsSchedule,[r,o]),j=a.useMemo(()=>Y.find(s=>s.path===D),[Y,D]),be=j?Ke[j.layer]:"Edits the selected memory file.",N=a.useMemo(()=>ss(F),[F]),q=a.useMemo(()=>as(N),[N]),ce=a.useMemo(()=>ts(F),[F]),oe=a.useCallback(s=>{A(h=>{const g=new Set(h);return g.has(s)?g.delete(s):g.add(s),g})},[]),xe=a.useCallback(async s=>{try{await B(s)}catch{t("Failed to load memory file","error")}},[B,t]),pe=a.useCallback(async()=>{try{await ie(),t("Memory saved","success")}catch{t("Failed to save memory","error")}},[ie,t]),fe=a.useCallback(async()=>{if(!Z)return;const s={};r.memoryEnabled!==o.memoryEnabled&&(s.memoryEnabled=r.memoryEnabled),r.memoryAutoSummarizeEnabled!==o.memoryAutoSummarizeEnabled&&(s.memoryAutoSummarizeEnabled=r.memoryAutoSummarizeEnabled),r.memoryAutoSummarizeThresholdChars!==o.memoryAutoSummarizeThresholdChars&&(s.memoryAutoSummarizeThresholdChars=r.memoryAutoSummarizeThresholdChars),r.memoryAutoSummarizeSchedule!==o.memoryAutoSummarizeSchedule&&(s.memoryAutoSummarizeSchedule=r.memoryAutoSummarizeSchedule),r.memoryDreamsEnabled!==o.memoryDreamsEnabled&&(s.memoryDreamsEnabled=r.memoryDreamsEnabled),r.memoryDreamsSchedule!==o.memoryDreamsSchedule&&(s.memoryDreamsSchedule=r.memoryDreamsSchedule);try{await se(s),t("Memory settings saved","success")}catch{t("Failed to save memory settings","error")}},[Z,r,o,se,t]),je=a.useCallback(async()=>{try{const s=await Q();t(s.qmdAvailable?"qmd installed successfully":"qmd install finished, but qmd is still unavailable",s.qmdAvailable?"success":"info")}catch{t("Failed to install qmd","error")}},[Q,t]),Se=a.useCallback(async()=>{L(!0),P(null);try{const s=await H(T);P(s),t(s.qmdAvailable?"Memory retrieval test complete":"qmd is not installed; local fallback was used",s.qmdAvailable?"success":"info")}catch{t("Failed to test memory retrieval","error")}finally{L(!1)}},[T,H,t]),K=a.useCallback(async()=>{try{await G(),t("Dream processing completed","success"),await le()}catch(s){t(s instanceof Error?s.message:"Failed to run dream processing","error")}},[G,le,t]),_=a.useCallback(async()=>{try{await f(D),t("Memory file compacted","success")}catch{t("Failed to compact memory","error")}},[f,D,t]),de=a.useCallback(async()=>{try{const s=await W();t(s.summary,"success")}catch(s){t(s instanceof Error?s.message:"Failed to extract insights","error")}},[W,t]),ve=a.useCallback(async()=>{if(b!==null)try{await $(b),k(!1),x(null),t("Insights saved","success")}catch{t("Failed to save insights","error")}},[b,$,t]),Ne=a.useCallback(()=>{x(F??""),k(!0)},[F]),Ce=a.useCallback(()=>{k(!1),x(null)},[]),n=!M&&c!==null,l=c?.capabilities?.writable??!1;return e.jsxs("div",{className:"memory-view",children:[e.jsx("div",{className:"memory-view-header",children:e.jsxs("div",{children:[e.jsx("h2",{children:"Memory"}),e.jsx("p",{className:"memory-view-description",children:"Working memory, long-term insights, and engine status"})]})}),e.jsxs("div",{className:"memory-view-tabs",role:"tablist",children:[e.jsx("button",{type:"button",role:"tab","aria-selected":m==="working",className:`memory-view-tab${m==="working"?" memory-view-tab--active":""}`,onClick:()=>u("working"),"data-testid":"memory-tab-working",children:"Working Memory"}),e.jsx("button",{type:"button",role:"tab","aria-selected":m==="insights",className:`memory-view-tab${m==="insights"?" memory-view-tab--active":""}`,onClick:()=>u("insights"),"data-testid":"memory-tab-insights",children:"Insights"}),e.jsx("button",{type:"button",role:"tab","aria-selected":m==="engines",className:`memory-view-tab${m==="engines"?" memory-view-tab--active":""}`,onClick:()=>u("engines"),"data-testid":"memory-tab-engines",children:"Engines"})]}),e.jsxs("div",{className:"memory-view-content",children:[m==="working"&&e.jsxs("div",{className:"memory-working-tab",children:[n&&!l&&e.jsx("div",{className:"memory-readonly-banner",children:"This memory backend is read-only. Changes cannot be saved."}),re||ye?e.jsxs("div",{className:"memory-empty-state",children:[e.jsx(w,{size:20,className:"animate-spin"}),e.jsx("span",{children:"Loading memory file…"})]}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"memory-editor-section",children:[e.jsxs("div",{className:"form-group",children:[e.jsx("label",{htmlFor:"memoryViewFilePath",children:"Memory File"}),e.jsx("select",{id:"memoryViewFilePath",className:"select",value:D,onChange:s=>{xe(s.target.value)},disabled:R,children:Y.map(s=>e.jsx("option",{value:s.path,title:`${s.label} — ${s.path}`,children:es(s)},s.path))}),e.jsx("small",{children:R?"Save or discard the current edits before switching files.":"Choose any project memory file to view or edit."})]}),j&&e.jsxs("div",{className:"memory-file-summary",children:[e.jsx("span",{children:Ze[j.layer]}),e.jsx("strong",{children:j.path}),e.jsxs("small",{children:[j.size.toLocaleString()," bytes · updated ",new Date(j.updatedAt).toLocaleString()]})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{children:j?.label||"Memory Editor"}),e.jsx("small",{children:be}),e.jsx("div",{className:"memory-editor-container",children:e.jsx(Fe,{content:z,onChange:ge,readOnly:!l,filePath:D})})]})]}),e.jsxs("div",{className:"memory-action-bar",children:[e.jsxs("span",{className:"memory-char-count",children:[z.length," characters"]}),e.jsx("div",{className:"memory-flex-spacer"}),l&&z.length>0&&e.jsx("button",{type:"button",className:"btn btn-secondary btn-sm",onClick:_,disabled:ae||R,children:ae?e.jsxs(e.Fragment,{children:[e.jsx(w,{size:14,className:"animate-spin"}),"Compacting…"]}):"Compact Selected File"}),R&&l&&e.jsx("button",{type:"button",className:"btn btn-primary btn-sm",onClick:pe,disabled:V,children:V?e.jsxs(e.Fragment,{children:[e.jsx(w,{size:14,className:"animate-spin"}),"Saving…"]}):"Save"})]}),e.jsxs("div",{className:"memory-config-section",children:[e.jsxs("div",{className:"memory-settings-group",children:[e.jsxs("div",{className:"form-group",children:[e.jsxs("label",{htmlFor:"memoryDreamsEnabled",className:"checkbox-label",children:[e.jsx("input",{id:"memoryDreamsEnabled",type:"checkbox",checked:r.memoryDreamsEnabled,onChange:s=>{p(h=>({...h,memoryDreamsEnabled:s.target.checked}))},disabled:!r.memoryEnabled||v}),"Process dreams from daily memory"]}),e.jsx("small",{children:"Turns daily notes into DREAMS.md and promotes reusable lessons into MEMORY.md."})]}),r.memoryEnabled&&r.memoryDreamsEnabled&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"form-group",children:[e.jsx("label",{htmlFor:"memoryDreamsSchedule",children:"Dream Schedule"}),e.jsx("input",{id:"memoryDreamsSchedule",type:"text",className:"input",value:r.memoryDreamsSchedule,onChange:s=>{p(h=>({...h,memoryDreamsSchedule:s.target.value}))},placeholder:"0 4 * * *",disabled:v}),e.jsx("small",{children:"Cron expression for dream processing."})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("button",{type:"button",className:"btn btn-sm",onClick:K,disabled:me||!r.memoryDreamsEnabled,children:me?e.jsxs(e.Fragment,{children:[e.jsx(w,{size:14,className:"animate-spin"}),"Dreaming…"]}):"Dream Now"}),e.jsx("small",{children:"Manually trigger dream processing now."})]})]})]}),e.jsxs("div",{className:"memory-settings-group",children:[e.jsxs("div",{className:"form-group",children:[e.jsxs("label",{htmlFor:"memoryAutoSummarizeEnabled",className:"checkbox-label",children:[e.jsx("input",{id:"memoryAutoSummarizeEnabled",type:"checkbox",checked:r.memoryAutoSummarizeEnabled,onChange:s=>{p(h=>({...h,memoryAutoSummarizeEnabled:s.target.checked}))},disabled:!r.memoryEnabled||v}),"Auto-Summarize Memory"]}),e.jsx("small",{children:"Automatically compact memory when it exceeds the threshold on a schedule"})]}),r.memoryEnabled&&r.memoryAutoSummarizeEnabled&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"form-group",children:[e.jsx("label",{htmlFor:"memoryAutoSummarizeThresholdChars",children:"Compaction Threshold (chars)"}),e.jsx("input",{id:"memoryAutoSummarizeThresholdChars",type:"number",className:"input",value:r.memoryAutoSummarizeThresholdChars,onChange:s=>{p(h=>({...h,memoryAutoSummarizeThresholdChars:parseInt(s.target.value,10)||5e4}))},min:1e3,disabled:v}),e.jsx("small",{children:"Memory will be compacted when it exceeds this character count"})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{htmlFor:"memoryAutoSummarizeSchedule",children:"Schedule (cron)"}),e.jsx("input",{id:"memoryAutoSummarizeSchedule",type:"text",className:"input",value:r.memoryAutoSummarizeSchedule,onChange:s=>{p(h=>({...h,memoryAutoSummarizeSchedule:s.target.value}))},placeholder:"0 3 * * *",disabled:v}),e.jsx("small",{children:"Cron expression for auto-summarize schedule (default: daily at 3 AM)"})]})]})]}),!r.memoryEnabled&&e.jsx("div",{className:"settings-empty-state memory-status-message",children:"Memory is currently disabled. Enable memory tools in Settings to edit these automations."}),Z&&e.jsx("div",{className:"memory-action-bar",children:e.jsx("button",{type:"button",className:"btn btn-primary btn-sm",onClick:fe,disabled:I||v,children:I?e.jsxs(e.Fragment,{children:[e.jsx(w,{size:14,className:"animate-spin"}),"Saving…"]}):"Save Settings"})})]})]})]}),m==="insights"&&e.jsx("div",{className:"memory-insights-tab",children:ee?e.jsxs("div",{className:"memory-empty-state",children:[e.jsx(w,{size:20,className:"animate-spin"}),e.jsx("span",{children:"Loading insights…"})]}):E?e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"memory-editor-container",children:e.jsx(Fe,{content:b??"",onChange:x,readOnly:!1,filePath:".fusion/memory/INSIGHTS.md"})}),e.jsxs("div",{className:"memory-action-bar",children:[e.jsx("button",{type:"button",className:"btn btn-secondary btn-sm",onClick:Ce,children:"Cancel"}),e.jsx("button",{type:"button",className:"btn btn-primary btn-sm",onClick:ve,children:"Save Insights"})]})]}):!ue||N.length===0?e.jsxs("div",{className:"memory-empty-state",children:[e.jsx("p",{children:"No insights extracted yet."}),e.jsx("p",{children:'Insights are automatically extracted from working memory. Click "Extract Now" to trigger extraction manually.'}),e.jsx("button",{type:"button",className:"btn btn-primary btn-sm memory-empty-extract-button",onClick:de,disabled:y,children:y?e.jsxs(e.Fragment,{children:[e.jsx(w,{size:14,className:"animate-spin"}),"Extracting…"]}):"Extract Now"})]}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"memory-stats-row",children:[e.jsxs("div",{className:"memory-stat-card",children:[e.jsx("div",{className:"memory-stat-value",children:q}),e.jsx("div",{className:"memory-stat-label",children:"Total Insights"})]}),e.jsxs("div",{className:"memory-stat-card",children:[e.jsx("div",{className:"memory-stat-value",children:N.length}),e.jsx("div",{className:"memory-stat-label",children:"Categories"})]}),ce&&e.jsxs("div",{className:"memory-stat-card",children:[e.jsx("div",{className:"memory-stat-value memory-stat-value--updated",children:ce}),e.jsx("div",{className:"memory-stat-label",children:"Last Updated"})]})]}),e.jsxs("div",{className:"memory-action-bar",children:[e.jsx("button",{type:"button",className:"btn btn-primary btn-sm",onClick:de,disabled:y,children:y?e.jsxs(e.Fragment,{children:[e.jsx(w,{size:14,className:"animate-spin"}),"Extracting…"]}):"Extract Now"}),e.jsx("button",{type:"button",className:"btn btn-secondary btn-sm",onClick:Ne,children:"Edit Raw"})]}),e.jsx("div",{className:"memory-categories-list",children:N.map(s=>{const h=!C.has(s.key);return e.jsxs("div",{className:"memory-category-section",children:[e.jsxs("div",{className:"memory-category-header",onClick:()=>oe(s.key),role:"button",tabIndex:0,onKeyDown:g=>{(g.key==="Enter"||g.key===" ")&&(g.preventDefault(),oe(s.key))},children:[e.jsx("h4",{children:s.name}),e.jsx("span",{className:"memory-category-count",children:s.items.length})]}),h&&e.jsx("div",{className:"memory-category-items",children:s.items.map((g,ze)=>e.jsx("div",{className:"memory-insight-item",children:g.replace(/^-\s+/,"").replace(/^\*\s+/,"")},ze))})]},s.key)})})]})}),m==="engines"&&e.jsx("div",{className:"memory-engines-tab",children:M||te?e.jsxs("div",{className:"memory-empty-state",children:[e.jsx(w,{size:20,className:"animate-spin"}),e.jsx("span",{children:"Loading engine status…"})]}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"memory-engine-card memory-qmd-card",children:[e.jsx("h3",{children:"QMD Integration"}),c?.qmdAvailable===!0?e.jsxs("div",{className:"memory-engine-status",children:[e.jsx("span",{className:"memory-health-badge memory-health-badge--healthy",children:"Installed"}),e.jsx("span",{className:"memory-char-count",children:"qmd is available on PATH."})]}):c?.qmdAvailable===!1?e.jsxs("div",{className:"settings-empty-state memory-status-message",children:[e.jsxs("span",{children:["qmd is not installed. Search will use local files. Install indexed retrieval: ",e.jsx("code",{children:c.qmdInstallCommand||"bun install -g @tobilu/qmd"})]}),e.jsx("button",{type:"button",className:"btn btn-secondary btn-sm",onClick:je,disabled:ne,children:ne?"Installing…":"Install qmd"})]}):e.jsxs("div",{className:"memory-engine-status",children:[e.jsx("span",{className:"memory-health-badge",children:"Checking"}),e.jsx("span",{className:"memory-char-count",children:"Checking qmd availability…"})]}),e.jsxs("div",{className:"memory-capability-row",children:[c?.capabilities?.readable&&e.jsx("span",{className:"memory-capability-badge",children:"Readable"}),c?.capabilities?.writable&&e.jsx("span",{className:"memory-capability-badge",children:"Writable"}),c?.capabilities?.supportsAtomicWrite&&e.jsx("span",{className:"memory-capability-badge",children:"Atomic Writes"}),c?.capabilities?.persistent&&e.jsx("span",{className:"memory-capability-badge",children:"Persistent"})]})]}),e.jsxs("div",{className:"memory-engine-card memory-retrieval-card",children:[e.jsx("h3",{children:"Test Memory Search"}),e.jsxs("div",{className:"memory-retrieval-input-row",children:[e.jsx("input",{type:"text",className:"input",value:T,onChange:s=>X(s.target.value),placeholder:"Search memory with qmd"}),e.jsx("button",{type:"button",className:"btn btn-secondary btn-sm",onClick:Se,disabled:J,children:J?"Testing…":"Test Retrieval"})]}),e.jsx("small",{className:"settings-muted",children:"Runs the same qmd-backed memory_search path agents use."}),S&&e.jsxs("div",{className:"memory-test-result",children:[e.jsxs("strong",{children:[S.results.length," result",S.results.length===1?"":"s"," ",'for "',S.query,'"']}),e.jsxs("small",{children:["qmd ",S.qmdAvailable?"available":"missing"," · ",S.usedFallback?"local fallback used":"qmd path used"]}),S.results.length>0?e.jsx("ul",{children:S.results.map((s,h)=>e.jsxs("li",{children:[e.jsxs("span",{children:[s.path,":",s.lineStart]}),e.jsx("p",{children:s.snippet})]},`${s.path}-${s.lineStart}-${h}`))}):e.jsx("small",{children:"No matching memory found."})]})]}),e.jsxs("div",{className:"memory-engine-card",children:[e.jsx("h3",{children:"Current Backend"}),e.jsx("div",{className:"memory-engine-status",children:e.jsx("span",{className:"memory-emphasis-text",children:ns(c?.currentBackend??"unknown")})}),e.jsxs("div",{className:"memory-capability-row",children:[c?.capabilities?.readable&&e.jsx("span",{className:"memory-capability-badge",children:"Readable"}),c?.capabilities?.writable&&e.jsx("span",{className:"memory-capability-badge",children:"Writable"}),c?.capabilities?.supportsAtomicWrite&&e.jsx("span",{className:"memory-capability-badge",children:"Atomic Writes"}),c?.capabilities?.persistent&&e.jsx("span",{className:"memory-capability-badge",children:"Persistent"})]})]}),d&&e.jsxs("div",{className:"memory-engine-card",children:[e.jsxs("div",{className:"memory-health-header",children:[e.jsx("h3",{children:"Health Status"}),e.jsx("span",{className:`memory-health-badge memory-health-badge--${d.health}`,children:rs(d.health)})]}),e.jsxs("div",{className:"memory-health-grid",children:[e.jsxs("div",{children:[e.jsx("div",{className:"memory-health-label",children:"Working Memory"}),e.jsxs("div",{className:"memory-emphasis-text",children:[d.workingMemory.size," chars"]}),e.jsxs("div",{className:"memory-health-detail",children:[d.workingMemory.sectionCount," sections"]})]}),e.jsxs("div",{children:[e.jsx("div",{className:"memory-health-label",children:"Insights Memory"}),e.jsxs("div",{className:"memory-emphasis-text",children:[d.insightsMemory.size," chars"]}),e.jsxs("div",{className:"memory-health-detail",children:[d.insightsMemory.insightCount," insights"]})]})]}),e.jsxs("div",{className:"memory-health-section",children:[e.jsx("div",{className:"memory-health-label",children:"Last Extraction"}),e.jsx("div",{className:"memory-emphasis-text",children:d.extraction.success?e.jsx("span",{className:"memory-status-text memory-status-text--success",children:"Success"}):e.jsx("span",{className:"memory-status-text memory-status-text--error",children:"Failed"})}),e.jsx("div",{className:"memory-health-detail",children:d.extraction.summary||`${d.extraction.insightCount} insights extracted`})]}),e.jsxs("div",{className:"memory-health-section",children:[e.jsx("div",{className:"memory-health-label",children:"Pruning"}),e.jsx("div",{className:"memory-emphasis-text",children:d.pruning.applied?e.jsx("span",{className:"memory-status-text memory-status-text--warning",children:"Applied"}):e.jsx("span",{className:"memory-status-text memory-status-text--muted",children:"Not needed"})}),d.pruning.applied&&e.jsx("div",{className:"memory-health-detail",children:d.pruning.reason})]})]}),d&&d.checks.length>0&&e.jsxs("div",{className:"memory-engine-card",children:[e.jsx("h3",{children:"Audit Checks"}),e.jsx("div",{children:d.checks.map(s=>e.jsxs("div",{className:"memory-audit-check",children:[e.jsx("span",{className:s.passed?"memory-audit-check-passed":"memory-audit-check-failed",children:s.passed?"✓":"✗"}),e.jsxs("div",{className:"memory-audit-check-content",children:[e.jsx("div",{className:"memory-emphasis-text",children:s.name}),e.jsx("div",{className:"memory-health-detail",children:s.details})]})]},s.id))})]}),e.jsx("div",{className:"memory-action-bar",children:e.jsx("button",{type:"button",className:"btn btn-secondary btn-sm",onClick:()=>U(),children:"Run Audit"})}),e.jsxs("div",{className:"memory-settings-note",children:[e.jsx("span",{children:"Note: Change backend type in"}),e.jsx("button",{type:"button",className:"memory-settings-note-button",onClick:()=>{t("Open Settings → Memory to change backend type","info")},children:"Settings → Memory"})]})]})})]})]})}export{os as MemoryView};
@@ -1,4 +1,4 @@
1
- import{r as s,j as e}from"./vendor-react-K0fH_qHe.js";import{h as Ie,W as os,Y as cs,Z as is,_ as ds,$ as Ve,a0 as ye,a1 as Ke,a2 as Fe,a3 as us,a4 as Oe,a5 as Ue,a6 as ms,a7 as ve,N as hs,R as _e,C as we,P as me,a8 as Be,a9 as Te,aa as fs,ab as Le,X as ue,E as gs,d as xs,ac as $e,F as ps,ad as De,ae as js,af as bs,ag as ys,ah as vs,ai as _s,aj as Ns}from"./index-CrHLf3pB.js";import"./vendor-xterm-DzcZoU0P.js";/**
1
+ import{r as s,j as e}from"./vendor-react-K0fH_qHe.js";import{h as Ie,W as os,Y as cs,Z as is,_ as ds,$ as Ve,a0 as ye,a1 as Ke,a2 as Fe,a3 as us,a4 as Oe,a5 as Ue,a6 as ms,a7 as ve,N as hs,R as _e,C as we,P as me,a8 as Be,a9 as Te,aa as fs,ab as Le,X as ue,E as gs,d as xs,ac as $e,F as ps,ad as De,ae as js,af as bs,ag as ys,ah as vs,ai as _s,aj as Ns}from"./index-NFptaeUQ.js";import"./vendor-xterm-DzcZoU0P.js";/**
2
2
  * @license lucide-react v1.7.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1,4 +1,4 @@
1
- import{r as l,j as e}from"./vendor-react-K0fH_qHe.js";import{h as Y,dT as Z,dU as H,dV as J,R as $,dK as y,P as Q,C as T,e as ee,a7 as se,dW as L,c1 as D,F as W,dX as ae,dY as te,dZ as A,X as ie}from"./index-CrHLf3pB.js";import"./vendor-xterm-DzcZoU0P.js";/**
1
+ import{r as l,j as e}from"./vendor-react-K0fH_qHe.js";import{h as Y,dT as Z,dU as H,dV as J,R as $,dK as y,P as Q,C as T,e as ee,a7 as se,dW as L,c1 as D,F as W,dX as ae,dY as te,dZ as A,X as ie}from"./index-NFptaeUQ.js";import"./vendor-xterm-DzcZoU0P.js";/**
2
2
  * @license lucide-react v1.7.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1 +1 @@
1
- import{r as o,j as n}from"./vendor-react-K0fH_qHe.js";import{b1 as T,dJ as ee,z as ne,X as O,s as se,P as A,ac as M,a7 as V,R as te,dK as ie,a3 as ae,bS as le,dL as re,dM as ce,dN as de,dO as ue,dP as _,bP as oe}from"./index-CrHLf3pB.js";import{D as ge}from"./DirectoryPicker-SchiK-Aq.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},{id:"fusion-plugin-dependency-graph",name:"Dependency Graph",path:"./plugins/fusion-plugin-dependency-graph"}],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),[G,f]=o.useState(!1),[j,v]=o.useState(""),[P,C]=o.useState(!1),[h,$]=o.useState(null),[i,y]=o.useState(null),[a,p]=o.useState({}),[H,I]=o.useState(!1),[R,E]=o.useState(null),{confirm:J}=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 K=o.useRef([]);K.current=x,o.useEffect(()=>{const e=c?`?projectId=${encodeURIComponent(c)}`:"",s=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 ne(`/api/events${e}`,{events:{"plugin:lifecycle":s},onReconnect:()=>{g()}})},[c,g]);const z=async()=>{if(!j.trim()){l("Please enter a plugin path","error");return}try{C(!0),await _({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{C(!1)}},X=async e=>{try{E(e.id),await _({path:e.path},c),l(`${e.name} installed successfully`,"success"),await g()}catch(s){l(`Failed to install ${e.name}: ${s instanceof Error?s.message:String(s)}`,"error")}finally{E(null)}},B=async e=>{try{await de(e.id,c),l(`${e.name} enabled`,"success"),await g()}catch(s){l(`Failed to enable plugin: ${s instanceof Error?s.message:String(s)}`,"error")}},F=async e=>{try{await ce(e.id,c),l(`${e.name} disabled`,"success"),await g()}catch(s){l(`Failed to disable plugin: ${s instanceof Error?s.message:String(s)}`,"error")}},L=async e=>{try{$(e.id),await re(e.id,c),l(`${e.name} reloaded`,"success"),await g()}catch(s){l(`Failed to reload plugin: ${s instanceof Error?s.message:String(s)}`,"error")}finally{$(null)}},D=async e=>{if(await J({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 s=await oe(e.id,c);p(s)}catch{p({})}finally{I(!1)}},Q=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 n.jsxs("div",{className:"plugin-manager-detail","data-testid":"plugin-manager-detail",children:[n.jsxs("div",{className:"plugin-manager-detail-header",children:[n.jsx("button",{className:"btn-icon",onClick:()=>y(null),"aria-label":"Back to plugin list",children:n.jsx(O,{size:16})}),n.jsxs("div",{className:"plugin-detail-title",children:[n.jsx("h4",{className:"plugin-detail-name",children:i.name}),n.jsx("span",{className:"plugin-state-badge",style:{color:N[i.state]||N.installed},children:i.state})]})]}),n.jsxs("div",{className:"plugin-detail-content",children:[n.jsxs("div",{className:"plugin-detail-card",children:[i.description&&n.jsx("p",{className:"plugin-description",children:i.description}),i.author&&n.jsxs("p",{className:"plugin-detail-meta-row",children:[n.jsx("span",{className:"text-muted",children:"Author:"}),i.author]}),i.homepage&&n.jsxs("p",{className:"plugin-detail-meta-row plugin-homepage",children:[n.jsx("span",{className:"text-muted",children:"Homepage:"}),n.jsxs("a",{href:i.homepage,target:"_blank",rel:"noopener noreferrer",children:[i.homepage,n.jsx(se,{size:12})]})]}),n.jsxs("p",{className:"plugin-detail-meta-row",children:[n.jsx("span",{className:"text-muted",children:"Version:"}),i.version]})]}),n.jsxs("div",{className:"plugin-detail-card",children:[n.jsx("h5",{className:"plugin-detail-section-heading",children:"Settings"}),H?n.jsx("p",{className:"text-muted",children:"Loading..."}):i.settingsSchema&&Object.keys(i.settingsSchema).length>0?n.jsxs("div",{className:"plugin-settings-form",children:[Object.entries(i.settingsSchema).map(([e,s])=>{const d=`setting-${e}-help`;return n.jsxs("div",{className:"form-group",children:[n.jsxs("label",{htmlFor:`setting-${e}`,children:[s.label||e,s.required&&" *"]}),s.type==="string"&&!s.multiline&&n.jsx("input",{className:"input",type:"text",id:`setting-${e}`,value:a[e]??"",onChange:t=>p({...a,[e]:t.target.value}),placeholder:s.description,"aria-describedby":s.description&&!s.required?d:void 0}),s.type==="string"&&s.multiline&&n.jsx("textarea",{className:"input",id:`setting-${e}`,rows:4,value:a[e]??"",onChange:t=>p({...a,[e]:t.target.value}),placeholder:s.description,"aria-describedby":s.description&&!s.required?d:void 0}),s.type==="password"&&n.jsx("input",{className:"input",type:"password",id:`setting-${e}`,value:a[e]??"",onChange:t=>p({...a,[e]:t.target.value}),placeholder:s.description,"aria-describedby":s.description&&!s.required?d:void 0}),s.type==="number"&&n.jsx("input",{className:"input",type:"number",id:`setting-${e}`,value:a[e]??"",onChange:t=>p({...a,[e]:Number(t.target.value)}),"aria-describedby":s.description&&!s.required?d:void 0}),s.type==="boolean"&&n.jsxs("label",{className:"checkbox-label",children:[n.jsx("input",{type:"checkbox",checked:a[e]??!1,onChange:t=>p({...a,[e]:t.target.checked})}),s.description]}),s.type==="enum"&&n.jsxs("select",{className:"select",id:`setting-${e}`,value:a[e]??"",onChange:t=>p({...a,[e]:t.target.value}),"aria-describedby":s.description&&!s.required?d:void 0,children:[n.jsx("option",{value:"",children:"Select..."}),s.enumValues?.map(t=>n.jsx("option",{value:t,children:t},t))]}),s.type==="array"&&n.jsxs("div",{className:"plugin-settings-array",children:[a[e]?.map((t,u)=>n.jsxs("div",{className:"plugin-settings-array-item",children:[n.jsx("input",{className:"input",type:s.itemType==="number"?"number":"text",value:t??"",onChange:m=>{const r=m.target.value,k=[...a[e]||[]];k[u]=s.itemType==="number"?Number(r):r,p({...a,[e]:k})}}),n.jsx("button",{className:"btn-icon",onClick:()=>{const r=[...a[e]||[]];r.splice(u,1),p({...a,[e]:r})},"aria-label":"Remove item",children:n.jsx(O,{size:14})})]},u)),n.jsxs("button",{className:"btn btn-secondary",onClick:()=>{const t=a[e]||[],u=s.itemType==="number"?0:"";p({...a,[e]:[...t,u]})},children:[n.jsx(A,{size:14})," Add Item"]})]}),s.description&&!s.required&&!s.multiline&&n.jsx("span",{id:d,className:"form-help",children:s.description})]},e)}),n.jsx("button",{className:"btn btn-primary",onClick:Q,children:"Save Settings"})]}):n.jsx("p",{className:"text-muted",children:"No configurable settings."})]}),n.jsxs("div",{className:"plugin-detail-actions",children:[i.state==="started"&&n.jsxs("button",{className:"btn btn-secondary",onClick:()=>L(i),disabled:h===i.id,children:[n.jsx(M,{size:14,className:h===i.id?"spin":""}),h===i.id?"Reloading...":"Reload"]}),i.enabled?n.jsx("button",{className:"btn btn-secondary",onClick:()=>F(i),children:"Disable"}):n.jsx("button",{className:"btn btn-primary",onClick:()=>B(i),children:"Enable"}),n.jsxs("button",{className:"btn btn-danger",onClick:()=>D(i),children:[n.jsx(V,{size:14})," Uninstall"]})]})]})]});const W=new Set(x.map(e=>e.id)),Y=new Map(x.map(e=>[e.id,e])),q=x,Z=()=>n.jsxs("section",{className:"plugin-bundled-runtime-section","aria-label":"Bundled Plugins",children:[n.jsxs("div",{className:"plugin-bundled-runtime-header",children:[n.jsx("h4",{className:"plugin-bundled-runtime-heading",children:"Bundled Plugins"}),n.jsx("p",{className:"plugin-bundled-runtime-description",children:"Install Fusion's bundled plugins directly from this screen."})]}),n.jsx("div",{className:"plugin-bundled-runtime-list","aria-label":"Bundled plugin recommendations",children:me.map(e=>{const s=W.has(e.id);return n.jsxs("div",{className:"plugin-bundled-runtime-item",children:[n.jsxs("div",{className:"plugin-bundled-runtime-meta",children:[n.jsx("span",{className:"plugin-bundled-runtime-name",children:e.name}),e.experimental&&n.jsx("span",{className:"plugin-bundled-runtime-badge",children:"Experimental"}),n.jsx("span",{className:`plugin-bundled-runtime-status ${s?"plugin-bundled-runtime-status--installed":"plugin-bundled-runtime-status--available"}`,children:s?"Installed":"Not installed"})]}),n.jsx("button",{className:`btn ${s?"btn-secondary":"btn-primary"} btn-sm`,onClick:()=>{if(s){const d=Y.get(e.id);d&&U(d);return}X(e)},disabled:R===e.id,children:s?"Manage":R===e.id?"Installing...":`Install ${e.name}`})]},e.id)})})]});return n.jsxs("div",{className:"plugin-manager","data-testid":"plugin-manager",children:[n.jsxs("div",{className:"plugin-manager-header",children:[n.jsx("span",{className:"plugin-manager-header-title",children:"Installed Plugins"}),n.jsxs("div",{className:"plugin-manager-actions",children:[n.jsxs("button",{className:"btn btn-sm",onClick:g,title:"Refresh","aria-label":"Refresh plugin list",children:[n.jsx(te,{size:14,className:S?"spin":""}),"Refresh"]}),n.jsxs("button",{className:"btn btn-primary btn-sm",onClick:()=>f(!0),children:[n.jsx(A,{size:14})," Install"]})]})]}),G&&n.jsxs("div",{className:"plugin-install-form",children:[n.jsxs("p",{className:"plugin-install-hint",children:["Browse to a plugin package root (contains ",n.jsx("code",{children:"manifest.json"}),") or a built ",n.jsx("code",{children:"dist"})," directory."]}),n.jsx(ge,{value:j,onChange:v,placeholder:"Absolute path to plugin directory or dist folder",onInputKeyDown:e=>{e.key==="Enter"&&(e.preventDefault(),z())}}),n.jsxs("div",{className:"plugin-install-actions",children:[n.jsx("button",{className:"btn btn-primary",onClick:z,disabled:P||!j.trim(),children:P?"Installing...":"Install Plugin"}),n.jsx("button",{className:"btn btn-secondary",onClick:()=>{f(!1),v("")},children:"Cancel"})]})]}),S?n.jsx("div",{className:"settings-empty-state",children:"Loading plugins..."}):n.jsxs(n.Fragment,{children:[q.length===0?n.jsxs("div",{className:"settings-empty-state",children:[n.jsx(ie,{size:32,className:"text-muted"}),n.jsx("p",{children:"No plugins installed."}),n.jsx("p",{className:"text-muted",children:"Install a plugin to get started, or use a bundled plugin below."})]}):n.jsx("div",{className:"plugin-list",children:q.map(e=>n.jsxs("div",{className:"plugin-item",children:[n.jsxs("div",{className:"plugin-info",children:[n.jsx("span",{className:"plugin-name",children:e.name}),n.jsxs("span",{className:"plugin-version text-muted",children:["v",e.version]}),n.jsx("span",{className:"plugin-state-badge",style:{color:N[e.state]||N.installed},children:e.state})]}),n.jsxs("div",{className:"plugin-actions",children:[e.state==="started"&&n.jsx("button",{className:"btn-icon",onClick:()=>L(e),disabled:h===e.id,title:"Reload",children:n.jsx(M,{size:14,className:h===e.id?"spin":""})}),n.jsxs("label",{className:"toggle-switch",children:[n.jsx("input",{type:"checkbox",checked:e.enabled,onChange:()=>e.enabled?F(e):B(e)}),n.jsx("span",{className:"toggle-slider"})]}),n.jsx("button",{className:"btn-icon",onClick:()=>U(e),title:"Settings",children:n.jsx(ae,{size:14})}),n.jsx("button",{className:"btn-icon",onClick:()=>D(e),title:"Uninstall",children:n.jsx(V,{size:14})})]})]},e.id))}),Z()]})]})}export{Ne as PluginManager,N as STATE_COLORS};
1
+ import{r as o,j as n}from"./vendor-react-K0fH_qHe.js";import{b1 as T,dJ as ee,z as ne,X as O,s as se,P as A,ac as M,a7 as V,R as te,dK as ie,a3 as ae,bS as le,dL as re,dM as ce,dN as de,dO as ue,dP as _,bP as oe}from"./index-NFptaeUQ.js";import{D as ge}from"./DirectoryPicker-B3dza2Dq.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},{id:"fusion-plugin-dependency-graph",name:"Dependency Graph",path:"./plugins/fusion-plugin-dependency-graph"}],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),[G,f]=o.useState(!1),[j,v]=o.useState(""),[P,C]=o.useState(!1),[h,$]=o.useState(null),[i,y]=o.useState(null),[a,p]=o.useState({}),[H,I]=o.useState(!1),[R,E]=o.useState(null),{confirm:J}=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 K=o.useRef([]);K.current=x,o.useEffect(()=>{const e=c?`?projectId=${encodeURIComponent(c)}`:"",s=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 ne(`/api/events${e}`,{events:{"plugin:lifecycle":s},onReconnect:()=>{g()}})},[c,g]);const z=async()=>{if(!j.trim()){l("Please enter a plugin path","error");return}try{C(!0),await _({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{C(!1)}},X=async e=>{try{E(e.id),await _({path:e.path},c),l(`${e.name} installed successfully`,"success"),await g()}catch(s){l(`Failed to install ${e.name}: ${s instanceof Error?s.message:String(s)}`,"error")}finally{E(null)}},B=async e=>{try{await de(e.id,c),l(`${e.name} enabled`,"success"),await g()}catch(s){l(`Failed to enable plugin: ${s instanceof Error?s.message:String(s)}`,"error")}},F=async e=>{try{await ce(e.id,c),l(`${e.name} disabled`,"success"),await g()}catch(s){l(`Failed to disable plugin: ${s instanceof Error?s.message:String(s)}`,"error")}},L=async e=>{try{$(e.id),await re(e.id,c),l(`${e.name} reloaded`,"success"),await g()}catch(s){l(`Failed to reload plugin: ${s instanceof Error?s.message:String(s)}`,"error")}finally{$(null)}},D=async e=>{if(await J({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 s=await oe(e.id,c);p(s)}catch{p({})}finally{I(!1)}},Q=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 n.jsxs("div",{className:"plugin-manager-detail","data-testid":"plugin-manager-detail",children:[n.jsxs("div",{className:"plugin-manager-detail-header",children:[n.jsx("button",{className:"btn-icon",onClick:()=>y(null),"aria-label":"Back to plugin list",children:n.jsx(O,{size:16})}),n.jsxs("div",{className:"plugin-detail-title",children:[n.jsx("h4",{className:"plugin-detail-name",children:i.name}),n.jsx("span",{className:"plugin-state-badge",style:{color:N[i.state]||N.installed},children:i.state})]})]}),n.jsxs("div",{className:"plugin-detail-content",children:[n.jsxs("div",{className:"plugin-detail-card",children:[i.description&&n.jsx("p",{className:"plugin-description",children:i.description}),i.author&&n.jsxs("p",{className:"plugin-detail-meta-row",children:[n.jsx("span",{className:"text-muted",children:"Author:"}),i.author]}),i.homepage&&n.jsxs("p",{className:"plugin-detail-meta-row plugin-homepage",children:[n.jsx("span",{className:"text-muted",children:"Homepage:"}),n.jsxs("a",{href:i.homepage,target:"_blank",rel:"noopener noreferrer",children:[i.homepage,n.jsx(se,{size:12})]})]}),n.jsxs("p",{className:"plugin-detail-meta-row",children:[n.jsx("span",{className:"text-muted",children:"Version:"}),i.version]})]}),n.jsxs("div",{className:"plugin-detail-card",children:[n.jsx("h5",{className:"plugin-detail-section-heading",children:"Settings"}),H?n.jsx("p",{className:"text-muted",children:"Loading..."}):i.settingsSchema&&Object.keys(i.settingsSchema).length>0?n.jsxs("div",{className:"plugin-settings-form",children:[Object.entries(i.settingsSchema).map(([e,s])=>{const d=`setting-${e}-help`;return n.jsxs("div",{className:"form-group",children:[n.jsxs("label",{htmlFor:`setting-${e}`,children:[s.label||e,s.required&&" *"]}),s.type==="string"&&!s.multiline&&n.jsx("input",{className:"input",type:"text",id:`setting-${e}`,value:a[e]??"",onChange:t=>p({...a,[e]:t.target.value}),placeholder:s.description,"aria-describedby":s.description&&!s.required?d:void 0}),s.type==="string"&&s.multiline&&n.jsx("textarea",{className:"input",id:`setting-${e}`,rows:4,value:a[e]??"",onChange:t=>p({...a,[e]:t.target.value}),placeholder:s.description,"aria-describedby":s.description&&!s.required?d:void 0}),s.type==="password"&&n.jsx("input",{className:"input",type:"password",id:`setting-${e}`,value:a[e]??"",onChange:t=>p({...a,[e]:t.target.value}),placeholder:s.description,"aria-describedby":s.description&&!s.required?d:void 0}),s.type==="number"&&n.jsx("input",{className:"input",type:"number",id:`setting-${e}`,value:a[e]??"",onChange:t=>p({...a,[e]:Number(t.target.value)}),"aria-describedby":s.description&&!s.required?d:void 0}),s.type==="boolean"&&n.jsxs("label",{className:"checkbox-label",children:[n.jsx("input",{type:"checkbox",checked:a[e]??!1,onChange:t=>p({...a,[e]:t.target.checked})}),s.description]}),s.type==="enum"&&n.jsxs("select",{className:"select",id:`setting-${e}`,value:a[e]??"",onChange:t=>p({...a,[e]:t.target.value}),"aria-describedby":s.description&&!s.required?d:void 0,children:[n.jsx("option",{value:"",children:"Select..."}),s.enumValues?.map(t=>n.jsx("option",{value:t,children:t},t))]}),s.type==="array"&&n.jsxs("div",{className:"plugin-settings-array",children:[a[e]?.map((t,u)=>n.jsxs("div",{className:"plugin-settings-array-item",children:[n.jsx("input",{className:"input",type:s.itemType==="number"?"number":"text",value:t??"",onChange:m=>{const r=m.target.value,k=[...a[e]||[]];k[u]=s.itemType==="number"?Number(r):r,p({...a,[e]:k})}}),n.jsx("button",{className:"btn-icon",onClick:()=>{const r=[...a[e]||[]];r.splice(u,1),p({...a,[e]:r})},"aria-label":"Remove item",children:n.jsx(O,{size:14})})]},u)),n.jsxs("button",{className:"btn btn-secondary",onClick:()=>{const t=a[e]||[],u=s.itemType==="number"?0:"";p({...a,[e]:[...t,u]})},children:[n.jsx(A,{size:14})," Add Item"]})]}),s.description&&!s.required&&!s.multiline&&n.jsx("span",{id:d,className:"form-help",children:s.description})]},e)}),n.jsx("button",{className:"btn btn-primary",onClick:Q,children:"Save Settings"})]}):n.jsx("p",{className:"text-muted",children:"No configurable settings."})]}),n.jsxs("div",{className:"plugin-detail-actions",children:[i.state==="started"&&n.jsxs("button",{className:"btn btn-secondary",onClick:()=>L(i),disabled:h===i.id,children:[n.jsx(M,{size:14,className:h===i.id?"spin":""}),h===i.id?"Reloading...":"Reload"]}),i.enabled?n.jsx("button",{className:"btn btn-secondary",onClick:()=>F(i),children:"Disable"}):n.jsx("button",{className:"btn btn-primary",onClick:()=>B(i),children:"Enable"}),n.jsxs("button",{className:"btn btn-danger",onClick:()=>D(i),children:[n.jsx(V,{size:14})," Uninstall"]})]})]})]});const W=new Set(x.map(e=>e.id)),Y=new Map(x.map(e=>[e.id,e])),q=x,Z=()=>n.jsxs("section",{className:"plugin-bundled-runtime-section","aria-label":"Bundled Plugins",children:[n.jsxs("div",{className:"plugin-bundled-runtime-header",children:[n.jsx("h4",{className:"plugin-bundled-runtime-heading",children:"Bundled Plugins"}),n.jsx("p",{className:"plugin-bundled-runtime-description",children:"Install Fusion's bundled plugins directly from this screen."})]}),n.jsx("div",{className:"plugin-bundled-runtime-list","aria-label":"Bundled plugin recommendations",children:me.map(e=>{const s=W.has(e.id);return n.jsxs("div",{className:"plugin-bundled-runtime-item",children:[n.jsxs("div",{className:"plugin-bundled-runtime-meta",children:[n.jsx("span",{className:"plugin-bundled-runtime-name",children:e.name}),e.experimental&&n.jsx("span",{className:"plugin-bundled-runtime-badge",children:"Experimental"}),n.jsx("span",{className:`plugin-bundled-runtime-status ${s?"plugin-bundled-runtime-status--installed":"plugin-bundled-runtime-status--available"}`,children:s?"Installed":"Not installed"})]}),n.jsx("button",{className:`btn ${s?"btn-secondary":"btn-primary"} btn-sm`,onClick:()=>{if(s){const d=Y.get(e.id);d&&U(d);return}X(e)},disabled:R===e.id,children:s?"Manage":R===e.id?"Installing...":`Install ${e.name}`})]},e.id)})})]});return n.jsxs("div",{className:"plugin-manager","data-testid":"plugin-manager",children:[n.jsxs("div",{className:"plugin-manager-header",children:[n.jsx("span",{className:"plugin-manager-header-title",children:"Installed Plugins"}),n.jsxs("div",{className:"plugin-manager-actions",children:[n.jsxs("button",{className:"btn btn-sm",onClick:g,title:"Refresh","aria-label":"Refresh plugin list",children:[n.jsx(te,{size:14,className:S?"spin":""}),"Refresh"]}),n.jsxs("button",{className:"btn btn-primary btn-sm",onClick:()=>f(!0),children:[n.jsx(A,{size:14})," Install"]})]})]}),G&&n.jsxs("div",{className:"plugin-install-form",children:[n.jsxs("p",{className:"plugin-install-hint",children:["Browse to a plugin package root (contains ",n.jsx("code",{children:"manifest.json"}),") or a built ",n.jsx("code",{children:"dist"})," directory."]}),n.jsx(ge,{value:j,onChange:v,placeholder:"Absolute path to plugin directory or dist folder",onInputKeyDown:e=>{e.key==="Enter"&&(e.preventDefault(),z())}}),n.jsxs("div",{className:"plugin-install-actions",children:[n.jsx("button",{className:"btn btn-primary",onClick:z,disabled:P||!j.trim(),children:P?"Installing...":"Install Plugin"}),n.jsx("button",{className:"btn btn-secondary",onClick:()=>{f(!1),v("")},children:"Cancel"})]})]}),S?n.jsx("div",{className:"settings-empty-state",children:"Loading plugins..."}):n.jsxs(n.Fragment,{children:[q.length===0?n.jsxs("div",{className:"settings-empty-state",children:[n.jsx(ie,{size:32,className:"text-muted"}),n.jsx("p",{children:"No plugins installed."}),n.jsx("p",{className:"text-muted",children:"Install a plugin to get started, or use a bundled plugin below."})]}):n.jsx("div",{className:"plugin-list",children:q.map(e=>n.jsxs("div",{className:"plugin-item",children:[n.jsxs("div",{className:"plugin-info",children:[n.jsx("span",{className:"plugin-name",children:e.name}),n.jsxs("span",{className:"plugin-version text-muted",children:["v",e.version]}),n.jsx("span",{className:"plugin-state-badge",style:{color:N[e.state]||N.installed},children:e.state})]}),n.jsxs("div",{className:"plugin-actions",children:[e.state==="started"&&n.jsx("button",{className:"btn-icon",onClick:()=>L(e),disabled:h===e.id,title:"Reload",children:n.jsx(M,{size:14,className:h===e.id?"spin":""})}),n.jsxs("label",{className:"toggle-switch",children:[n.jsx("input",{type:"checkbox",checked:e.enabled,onChange:()=>e.enabled?F(e):B(e)}),n.jsx("span",{className:"toggle-slider"})]}),n.jsx("button",{className:"btn-icon",onClick:()=>U(e),title:"Settings",children:n.jsx(ae,{size:14})}),n.jsx("button",{className:"btn-icon",onClick:()=>D(e),title:"Uninstall",children:n.jsx(V,{size:14})})]})]},e.id))}),Z()]})]})}export{Ne as PluginManager,N as STATE_COLORS};
@@ -1 +1 @@
1
- import{r as i,j as e}from"./vendor-react-K0fH_qHe.js";import{x as oe,y as de,z as ue,B as he,D as me,G as be,H as fe,I as ve,J as pe,K as xe,N as ye,O as ge,Q as je,U as Re,V as Se,S as _e}from"./index-CrHLf3pB.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?.researchGlobalFetchTimeoutMs??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,Q]=i.useState(!1),[ee,se]=i.useState([]),[A,$]=i.useState(null),[I,H]=i.useState(null),z=g.supportedProviders??Te,G=s=>l.enabledSources[Ae[s]];i.useEffect(()=>{const s=z.filter(d=>G(d));se(d=>{const m=d.filter(h=>s.includes(h));return m.length>0?m:s})},[l.enabledSources,z]),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()){Q(!0);try{const s=ee.filter(m=>G(m));if(s.length===0){Q(!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{Q(!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:z.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};
1
+ import{r as i,j as e}from"./vendor-react-K0fH_qHe.js";import{x as oe,y as de,z as ue,B as he,D as me,G as be,H as fe,I as ve,J as pe,K as xe,N as ye,O as ge,Q as je,U as Re,V as Se,S as _e}from"./index-NFptaeUQ.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?.researchGlobalFetchTimeoutMs??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,Q]=i.useState(!1),[ee,se]=i.useState([]),[A,$]=i.useState(null),[I,H]=i.useState(null),z=g.supportedProviders??Te,G=s=>l.enabledSources[Ae[s]];i.useEffect(()=>{const s=z.filter(d=>G(d));se(d=>{const m=d.filter(h=>s.includes(h));return m.length>0?m:s})},[l.enabledSources,z]),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()){Q(!0);try{const s=ee.filter(m=>G(m));if(s.length===0){Q(!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{Q(!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:z.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};
@@ -1,4 +1,4 @@
1
- import{r as a,j as e}from"./vendor-react-K0fH_qHe.js";import{h as Dt,aM as Mt,aN as Rt,aO as It,aP as $t,aQ as zt,aR as tt,aS as At,aT as Ot,aU as at,aV as Ht,aW as Pt,aX as Bt,aY as Gt,aZ as Tt,a_ as Lt,a$ as Vt,b0 as Ut,b1 as Kt,ax as Wt,P as ze,b2 as me,X as re,aa as Fe,a7 as Ge,g as Yt,n as ut,a9 as st,A as qt,b3 as Ye,b4 as Jt}from"./index-CrHLf3pB.js";import"./vendor-xterm-DzcZoU0P.js";/**
1
+ import{r as a,j as e}from"./vendor-react-K0fH_qHe.js";import{h as Dt,aM as Mt,aN as Rt,aO as It,aP as $t,aQ as zt,aR as tt,aS as At,aT as Ot,aU as at,aV as Ht,aW as Pt,aX as Bt,aY as Gt,aZ as Tt,a_ as Lt,a$ as Vt,b0 as Ut,b1 as Kt,ax as Wt,P as ze,b2 as me,X as re,aa as Fe,a7 as Ge,g as Yt,n as ut,a9 as st,A as qt,b3 as Ye,b4 as Jt}from"./index-NFptaeUQ.js";import"./vendor-xterm-DzcZoU0P.js";/**
2
2
  * @license lucide-react v1.7.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.