livedesk 0.1.628 → 0.1.629
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/web/dist/app.html +4 -4
- package/web/dist/app.webmanifest +1 -1
- package/web/dist/assets/{AgentSettingsTab-C__K2qQV.js → AgentSettingsTab-Fm0pWAO5.js} +1 -1
- package/web/dist/assets/{AgentsPage-kNUZaQzS.js → AgentsPage-CV9d70zz.js} +1 -1
- package/web/dist/assets/App-jdfxW7Jf.js +171 -0
- package/web/dist/assets/{CaptureGallery-DAgqCmsl.js → CaptureGallery-CCBV6Ry2.js} +1 -1
- package/web/dist/assets/{DesktopUpdatePanel-Dqhx8RHF.js → DesktopUpdatePanel-CrprrEpT.js} +1 -1
- package/web/dist/assets/{LiveDeskApp-BJ2lcZ0L.js → LiveDeskApp-B4-OE2Pc.js} +1 -1
- package/web/dist/assets/{SettingsPage-DKgYB_Qk.js → SettingsPage-Bt1AMVk2.js} +1 -1
- package/web/dist/assets/{SettingsTabs-DW-lQk7r.js → SettingsTabs-ByTAC0pY.js} +1 -1
- package/web/dist/assets/{ShareFilesPage-BiQJlXwL.js → ShareFilesPage-B4h4r-vi.js} +1 -1
- package/web/dist/assets/{SupportPage-RZRFybKj.js → SupportPage-CZAgCvAU.js} +1 -1
- package/web/dist/assets/app-B1GIt_Z3.js +1 -0
- package/web/dist/assets/{main-BZikRV_6.js → main-CW1wp0ox.js} +2 -2
- package/web/dist/assets/{styles-p05EbHC8.css → styles-BNaoQWzp.css} +1 -1
- package/web/dist/assets/styles-pFD5jrt-.js +13 -0
- package/web/dist/index.html +3 -3
- package/web/dist/livedesk-build-evidence.json +49 -49
- package/web/dist/sw.js +1 -1
- package/web/dist/assets/App-C_ZHf8nK.js +0 -169
- package/web/dist/assets/app-BRHIRWNu.js +0 -1
- package/web/dist/assets/styles-DG6GXN90.js +0 -13
package/package.json
CHANGED
package/web/dist/app.html
CHANGED
|
@@ -52,13 +52,13 @@
|
|
|
52
52
|
.vuvodesk-static-boot button[hidden] { display: none; }
|
|
53
53
|
@keyframes vuvodesk-static-boot-spin { to { transform: rotate(360deg); } }
|
|
54
54
|
</style>
|
|
55
|
-
<script type="module" crossorigin src="/assets/app-
|
|
55
|
+
<script type="module" crossorigin src="/assets/app-B1GIt_Z3.js"></script>
|
|
56
56
|
<link rel="modulepreload" crossorigin href="/assets/icons-C9gCrfh8.js">
|
|
57
57
|
<link rel="modulepreload" crossorigin href="/assets/react-CzpJ4iNd.js">
|
|
58
|
-
<link rel="modulepreload" crossorigin href="/assets/styles-
|
|
58
|
+
<link rel="modulepreload" crossorigin href="/assets/styles-pFD5jrt-.js">
|
|
59
59
|
<link rel="modulepreload" crossorigin href="/assets/supabase-C7qjtLN3.js">
|
|
60
|
-
<link rel="modulepreload" crossorigin href="/assets/App-
|
|
61
|
-
<link rel="stylesheet" crossorigin href="/assets/styles-
|
|
60
|
+
<link rel="modulepreload" crossorigin href="/assets/App-jdfxW7Jf.js">
|
|
61
|
+
<link rel="stylesheet" crossorigin href="/assets/styles-BNaoQWzp.css">
|
|
62
62
|
<link rel="stylesheet" crossorigin href="/assets/App-CD73TEql.css">
|
|
63
63
|
</head>
|
|
64
64
|
<body>
|
package/web/dist/app.webmanifest
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{h as x,j as t}from"./styles-
|
|
1
|
+
import{h as x,j as t}from"./styles-pFD5jrt-.js";import{a as c,k as D,a5 as q,a6 as I,a7 as L}from"./icons-C9gCrfh8.js";import"./react-CzpJ4iNd.js";const A={enabled:!1};function w(i){return{enabled:i?.enabled===!0}}async function M(i,p,h){let l=null;for(let s=0;s<2;s+=1){const d=await x("/api/settings",{signal:h},p);if(d.settings.agent?.enabled===i)return;try{await x("/api/settings",{method:"PATCH",signal:h,body:JSON.stringify({revision:d.revision,agent:{enabled:i}})},p);return}catch(a){if(l=a,s!==0||!String(a instanceof Error?a.message:a).startsWith("409 "))throw a}}throw l}function F({hubUrl:i,showToast:p}){const[h,l]=c.useState(A),[s,d]=c.useState(null),[a,m]=c.useState(""),[j,v]=c.useState(""),[y,g]=c.useState(""),b=c.useRef(0),u=c.useRef(null);c.useEffect(()=>{let e=!0;u.current?.abort();const n=new AbortController;u.current=n;const f=++b.current;return d(null),l(A),m(""),g(""),v(""),x("/api/settings/agent",{signal:n.signal},i).then(o=>{!e||n.signal.aborted||f!==b.current||(d(o.settings),l(w(o.settings)))}).catch(o=>{e&&!n.signal.aborted&&f===b.current&&g(o instanceof Error?o.message:String(o))}),()=>{e=!1,n.abort(),u.current===n&&(u.current=null)}},[i]);const E=(e,n)=>l(f=>({...f,[e]:n})),C=e=>{d(e),l(w(e))},S=()=>({generation:b.current,controller:u.current}),r=e=>e.generation===b.current&&e.controller!==null&&e.controller===u.current&&!e.controller.signal.aborted,R=async()=>{if(!s){g("Agent settings are not available yet.");return}const e=S();if(r(e)){m("save"),g(""),v("");try{if(await M(h.enabled,i,e.controller.signal),!r(e))return;const n=await x("/api/settings/agent",{signal:e.controller.signal},i);if(!r(e))return;C(n.settings),v("Codex Agent settings saved.")}catch(n){r(e)&&g(n instanceof Error?n.message:String(n))}finally{r(e)&&m("")}}},k=async()=>{const e=S();if(r(e)){m("test"),g(""),v("");try{const n=await x("/api/settings/agent/test",{method:"POST",signal:e.controller.signal,body:JSON.stringify({})},i);if(!r(e))return;const f=await x("/api/settings/agent",{signal:e.controller.signal},i);if(!r(e))return;C(f.settings);const o=Number.isFinite(n.connection?.latencyMs)?Math.max(0,Math.round(n.connection.latencyMs)):null;p(`Codex Agent connection verified${o!==null?` in ${o} ms.`:"."}`,"success")}catch(n){r(e)&&g(n instanceof Error?n.message:String(n))}finally{r(e)&&m("")}}},T=s?.codexInstallation==="installed"&&s.codexAuth==="signed-in",N=s!==null;return t.jsxs("div",{className:"settings-tab-content agent-settings-content",children:[t.jsx("section",{className:"settings-section-card agent-enable-card",children:t.jsxs("label",{className:"settings-toggle agent-enable-toggle",children:[t.jsx("input",{type:"checkbox",checked:h.enabled,onChange:e=>E("enabled",e.target.checked),disabled:!N||a!==""}),t.jsx("span",{children:"Enable Codex Agent"})]})}),y&&t.jsx("div",{className:"agent-settings-alert error",role:"alert",children:y}),j&&t.jsx("div",{className:"agent-settings-alert success",role:"status",children:j}),t.jsxs("section",{className:"settings-section-card",children:[t.jsxs("div",{className:"settings-section-heading",children:[t.jsxs("div",{children:[t.jsx("span",{children:"Connection"}),t.jsx("h3",{children:"Codex SDK / CLI"})]}),t.jsx(D,{size:20})]}),t.jsxs("div",{className:"agent-connection-row",children:[t.jsx("span",{className:`agent-connection-dot ${T?"connected":s?.codexAuth==="not-signed-in"?"unavailable":""}`}),t.jsx("span",{children:s?.codexInstallation==="not-installed"?"Codex SDK not installed":s?.codexAuth==="signed-in"?"Codex CLI signed in":s?.codexAuth==="not-signed-in"?"Codex CLI sign-in required":"Codex status not tested"}),t.jsxs("button",{className:"settings-reset",onClick:()=>{k()},disabled:a!=="",type:"button",children:[t.jsx(q,{size:15})," ",a==="test"?"Testing":"Test connection"]})]}),t.jsxs("p",{className:"settings-help",children:[t.jsx(I,{size:12})," The Hub uses the installed Codex SDK / CLI to plan approved commands and run them through VuvoDesk Agent tools on selected computers."]})]}),t.jsx("div",{className:"settings-action-row agent-settings-actions",children:t.jsxs("button",{className:"text-button primary",onClick:()=>{R()},disabled:!N||a!=="",type:"button",children:[t.jsx(L,{size:15})," ",a==="save"?"Saving":"Save Agent settings"]})})]})}export{F as AgentSettingsTab};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{j as t,f as ot,h as U}from"./styles-DG6GXN90.js";import{a as c,m as lt,n as xe,o as ct,l as ee,X as Ce,p as ut,q as dt,s as He,B as pt,t as gt,u as je,S as V,v as mt,w as ft,x as Me,b as ht,y as yt,k as _e,z as vt,N as wt,F as kt,H as bt,I as xt,J as Ct,U as ue,c as Ve}from"./icons-C9gCrfh8.js";import"./react-CzpJ4iNd.js";const jt=c.forwardRef(function({value:s,onChange:n,onSubmit:a,onOpenSuggestedTasks:u,suggestedOpen:h=!1,suggestedTaskCount:d,disabled:v=!1,placeholder:j="Ask VuvoDesk to work across your machines...",compact:g=!1},C){return t.jsxs("form",{className:"agents-composer",onSubmit:w=>{w.preventDefault(),a()},children:[t.jsx("button",{className:`agents-suggested-trigger ${h?"active":""}`,type:"button","aria-label":d===void 0?"Open Suggested tasks":`Open Suggested tasks (${d} available)`,"aria-expanded":h,onClick:u,disabled:v,children:t.jsx(lt,{size:17})}),t.jsx("textarea",{ref:C,value:s,onChange:w=>n(w.target.value.slice(0,4e3)),placeholder:j,"aria-label":"Ask VuvoDesk",rows:g?1:2,disabled:v}),t.jsxs("button",{className:"agents-run-button",type:"submit",disabled:v||!s.trim(),children:[v?t.jsx(xe,{className:"spin",size:16}):t.jsx(ct,{size:16}),v?"Running":"Run"]})]})}),St=["read","processControl","serviceControl","applicationControl","fileRead","fileWrite","fileDelete","shell","script","softwareInstall","network","systemPower","systemConfiguration","userAccount"];function de(e){return e.deviceName?.trim()||e.hostname?.trim()||e.deviceId}function pe(e){return e.connected!==!0?!1:e.synthetic===!0?!0:!e.channels||e.channels.control===!0}function At(e){return e==="running"||e==="completed"||e==="failed"||e==="cancelled"?e:"queued"}function Rt(e){switch(e){case"process.list":return"Process list";case"system.health":return"System health";case"gpu.status":return"GPU status";case"disk.status":return"Disk status";case"service.status":return"Service status";case"diagnostics.collect":return"Diagnostics";case"process.control":return"Process control";case"service.control":return"Service control";case"application.launch":return"Launch application";case"application.close":return"Close application";case"file.read":return"Read file";case"file.write":return"Write file";case"file.delete":return"Delete file";case"file.list":return"List directory";case"command.run":return"Run command";case"script.run":return"Run script";case"software.install":return"Install software";case"network.status":return"Network status";case"system.power":return"Power action";case"system.configure":return"System configuration";case"logs.collect":return"Collect logs"}}function Pt(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:null}function D(e){return typeof e=="number"&&Number.isFinite(e)?e:null}function le(e){const s=D(e);return s===null?"":s<1024**2?`${Math.round(s/1024)}K`:s<1024**3?`${(s/1024**2).toFixed(0)}M`:`${(s/1024**3).toFixed(1)}G`}function De(e){const s=D(e);return s===null?"":`${Math.round((s<=1?s:s/100)*100)}%`}function Nt(e){return!e||/^(?:[\w .-]+ )?collected(?:\.)?$/i.test(e.trim())?"":e.trim()}function ge(e,s){if(s.error)return s.error;const n=Pt(s.data),a=Nt(s.result||"");if(!n)return a||s.stage||s.status;if(e==="system.health"){const u=typeof n.machine=="string"?n.machine:"",h=De(n.cpuUsageRatio),d=D(n.cores),v=le(n.freeMemoryBytes),j=le(n.totalMemoryBytes),g=D(n.totalMemoryBytes)&&D(n.freeMemoryBytes)!==null?`${Math.round(D(n.freeMemoryBytes)/D(n.totalMemoryBytes)*100)}% RAM free`:"";return[u,h&&`CPU ${h}`,d!==null&&`${Math.round(d)} cores`,v&&j?`RAM ${v}/${j}`:"",g,typeof n.platform=="string"?n.platform:""].filter(Boolean).join(" · ")||a||s.status}if(e==="disk.status"){const u=typeof n.root=="string"?n.root:"",h=le(n.freeBytes),d=D(n.totalBytes)&&D(n.freeBytes)!==null?`${Math.round(D(n.freeBytes)/D(n.totalBytes)*100)}% free`:"";return[u,h&&`${h} free`,d].filter(Boolean).join(" · ")||a||s.status}if(e==="gpu.status"){const u=typeof n.name=="string"&&n.name?n.name:"No GPU detected",h=De(n.usageRatio),d=D(n.temperatureC)!==null?`${Math.round(D(n.temperatureC))}°C`:"",v=le(n.freeMemoryBytes);return[u,h&&`GPU ${h}`,d,v&&`${v} free`].filter(Boolean).join(" · ")||a||s.status}if(e==="process.list"){const u=D(n.count);return u!==null?`${u} matching process${u===1?"":"es"}`:a||s.status}if(e==="network.status"){const u=Array.isArray(n.adapters)?n.adapters.length:null;return u!==null?`${u} active adapter${u===1?"":"s"}`:a||s.status}return a||s.stage||s.status}function qe(e,s){const n=ge(e,s);return s.status==="failed"||s.status==="cancelled"||/\b(?:warning|failed|error|offline|not running|low|timeout|timed out)\b/i.test(`${s.result||""} ${n}`)}function It({state:e,operation:s}){const n=e.status==="completed"?ee:e.status==="failed"||e.status==="cancelled"?Ce:e.status==="running"?xe:ut,a=e.status==="running"?e.stage||"Working":e.status==="completed"?s?ge(s,e):e.result||"Completed":e.status==="failed"?e.error||"Failed":e.status==="cancelled"?"Cancelled":"Queued";return t.jsxs("div",{className:`agent-target-row status-${e.status}`,"data-agent-target-id":e.deviceId,children:[t.jsx("span",{className:"agent-target-status","aria-hidden":"true",children:t.jsx(n,{size:15})}),t.jsx("strong",{children:e.deviceName}),t.jsx("span",{className:"agent-target-state",children:e.status[0].toUpperCase()+e.status.slice(1)}),t.jsx("small",{children:a})]})}function Tt({operation:e,states:s,status:n,onCancel:a,onRetry:u,busy:h=!1}){const d=["running","queued"].includes(n),[v,j]=c.useState(!1),[g,C]=c.useState("all"),w=c.useMemo(()=>({total:s.length,completed:s.filter(p=>p.status==="completed").length,failed:s.filter(p=>p.status==="failed").length,running:s.filter(p=>p.status==="running").length,queued:s.filter(p=>p.status==="queued").length,cancelled:s.filter(p=>p.status==="cancelled").length}),[s]),R=s.filter(p=>qe(e,p)),b=R.filter(p=>p.status==="completed").length,T=w.failed>0,k=R.length>0,x=s.filter(p=>g==="issues"?qe(e,p):g==="running"?p.status==="running"||p.status==="queued":g==="completed"?p.status==="completed":g==="failed"?p.status==="failed":!0),q=k&&!d||n==="completed-with-failures"?"Completed with issues":n[0]?.toUpperCase()+n.slice(1),E=s.filter(p=>p.status==="completed").map(p=>ge(e,p)).filter(Boolean).filter((p,$,P)=>P.indexOf(p)===$).slice(0,2);return t.jsxs("section",{className:"agent-task-block","aria-label":"Task execution",children:[t.jsxs("div",{className:"agent-task-head",children:[t.jsxs("div",{children:[t.jsx("span",{children:"VuvoDesk Agent"}),t.jsx("strong",{children:Rt(e)})]}),t.jsx("span",{className:`agent-task-status status-${k?"completed-with-failures":n}`,children:q})]}),t.jsxs("div",{className:"agent-task-summary","aria-label":"Task summary",children:[t.jsxs("strong",{children:[w.total," targets"]}),t.jsxs("span",{className:"summary-completed",children:[w.completed," completed"]}),w.running>0&&t.jsxs("span",{className:"summary-running",children:[w.running," running"]}),w.queued>0&&t.jsxs("span",{children:[w.queued," queued"]}),T&&t.jsxs("span",{className:"summary-failed",children:[w.failed," failed"]}),b>0&&t.jsxs("span",{className:"summary-cancelled",children:[b," warning"]}),w.cancelled>0&&t.jsxs("span",{className:"summary-cancelled",children:[w.cancelled," cancelled"]})]}),E.length>0&&t.jsxs("div",{className:"agent-task-result-preview",title:E.join(" · "),children:[t.jsx("span",{children:"Result"}),E.join(" · ")]}),t.jsx("div",{className:"agent-target-chips","aria-label":"Target status overview",children:s.map((p,$)=>{const P=p.status==="completed"?"✓":p.status==="failed"?"×":p.status==="cancelled"?"!":p.status==="running"?"…":"·";return t.jsxs("span",{className:`agent-target-chip status-${p.status}`,title:`${p.deviceName}: ${ge(e,p)}`,"aria-label":`${$+1}. ${p.deviceName}: ${p.status}`,children:[t.jsx("b",{children:String($+1).padStart(2,"0")}),t.jsx("span",{children:P})]},p.deviceId)})}),s.length>0&&t.jsx("div",{className:"agent-task-details-toggle",children:t.jsxs("button",{type:"button",onClick:()=>j(p=>!p),"aria-expanded":v,children:[v?t.jsx(dt,{size:14}):t.jsx(He,{size:14}),v?"Hide details":"Show details"]})}),v&&t.jsxs("div",{className:"agent-task-details",children:[t.jsx("div",{className:"agent-task-filters",role:"tablist","aria-label":"Task result filter",children:["all","issues","running","completed","failed"].map(p=>t.jsx("button",{className:g===p?"active":"",onClick:()=>C(p),role:"tab","aria-selected":g===p,type:"button",children:p==="all"?"All":p==="issues"?"Issues only":p[0].toUpperCase()+p.slice(1)},p))}),t.jsx("div",{className:"agent-task-rows",children:x.length>0?x.map(p=>t.jsx(It,{operation:e,state:p},p.deviceId)):t.jsx("small",{className:"agent-task-no-results",children:"No targets match this filter."})})]}),(d||T)&&t.jsxs("div",{className:"agent-task-actions",children:[d&&a&&t.jsxs("button",{onClick:a,disabled:h,type:"button",children:[t.jsx(pt,{size:14})," Cancel"]}),!d&&T&&u&&t.jsxs("button",{onClick:u,disabled:h,type:"button",children:[t.jsx(gt,{size:14})," Retry failed"]})]})]})}function Ot(e){try{return JSON.stringify(e,null,2).slice(0,6e3)}catch{return"{}"}}function Et({approval:e,busy:s=!1,onApprove:n,onReject:a}){return t.jsxs("article",{className:"agent-approval-card","aria-label":"Agent approval required",children:[t.jsxs("div",{className:"agent-approval-head",children:[t.jsxs("div",{children:[t.jsx("span",{children:"Approval required"}),t.jsx("strong",{children:e.toolName})]}),t.jsx("span",{className:`agent-approval-risk risk-${e.risk}`,children:e.risk})]}),t.jsx("p",{children:e.description}),t.jsx("pre",{children:Ot(e.arguments)}),t.jsxs("small",{children:["Permission: ",e.permissionMode," · Scope: selected devices only · Expires in 5 minutes"]}),t.jsxs("div",{className:"agent-approval-actions",children:[t.jsxs("button",{className:"reject",disabled:s,onClick:a,type:"button",children:[t.jsx(Ce,{size:14})," Reject"]}),t.jsxs("button",{disabled:s,onClick:()=>n("once"),type:"button",children:[t.jsx(ee,{size:14})," Once"]}),t.jsx("button",{disabled:s,onClick:()=>n("same-action-this-run"),type:"button",children:"Allow same action"}),t.jsx("button",{disabled:s,onClick:()=>n("category-this-run"),type:"button",children:"Allow category"})]}),t.jsxs("div",{className:"agent-approval-scope",children:[t.jsx(je,{size:13})," Approval is bound to this run, tool, arguments, selected devices, and policy hash."]})]})}function $t(e){return e==="queued"?"Request queued":e==="checking-codex"?"Checking Codex":e==="preparing-tools"?"Preparing tools":e==="thinking"?"Preparing answer":e==="tool-running"?"Working on computers":e==="recovering"?"Retrying safely":e==="waiting-approval"?"Waiting for approval":"Working"}function Ft({items:e,onCancel:s,onRetry:n,busyBatchId:a,approvals:u,onApprove:h,onReject:d,busyApprovalId:v,progress:j,emptyTitle:g="Ask VuvoDesk to work across your machines.",emptyBody:C="Start with a read-only request such as “현재 대상에서 CPU와 메모리 상태를 확인해줘”."}){const w=c.useRef(null),R=c.useRef(!0),b=c.useRef(""),T=e[e.length-1];return c.useLayoutEffect(()=>{const k=w.current;k&&(T?.type==="user"&&T.id!==b.current&&(R.current=!0),b.current=T?.id||"",R.current&&(k.scrollTop=k.scrollHeight))},[u,e,T?.id,T?.type,j?.message,j?.stage]),t.jsxs("section",{className:"agents-conversation","aria-live":"polite",ref:w,onScroll:k=>{const x=k.currentTarget;R.current=x.scrollHeight-x.scrollTop-x.clientHeight<72},children:[u.filter(k=>k.status==="pending").map(k=>t.jsx(Et,{approval:k,busy:v===k.approvalId,onApprove:x=>h(k,x),onReject:()=>d(k)},k.approvalId)),e.length===0&&t.jsxs("div",{className:"agents-empty-conversation",children:[t.jsx("strong",{children:g}),t.jsx("span",{children:C})]}),e.map(k=>{if(k.type==="task"){const x=k;return t.jsx(Tt,{operation:x.operation,states:x.states,status:x.status,onCancel:()=>s(x.batchId,x.agentRunId),onRetry:()=>n(x.batchId),busy:a===x.batchId},x.id)}return t.jsxs("article",{className:`agents-message ${k.type}`,children:[t.jsx("span",{children:k.type==="user"?"You":"VuvoDesk Agent"}),t.jsx("p",{children:k.text})]},k.id)}),j&&t.jsxs("article",{className:"agents-message agent agents-progress-message",role:"status",children:[t.jsxs("span",{children:[t.jsx(xe,{"aria-hidden":"true",size:15}),$t(j.stage)]}),t.jsx("p",{children:j.message})]})]})}const ze=["Recommended","Health & capacity","Processes & services","Files & configuration","Software & automation","Network & connectivity","Power & maintenance","Troubleshooting & recovery"],A=["windows","macos","linux"],B={"system.health":{label:"system health",permissionCategory:"read",readOnly:!0,risk:"low",supportedPlatforms:A},"gpu.status":{label:"GPU status",permissionCategory:"read",readOnly:!0,risk:"low",supportedPlatforms:A},"disk.status":{label:"disk status",permissionCategory:"read",readOnly:!0,risk:"low",supportedPlatforms:A},"process.list":{label:"process inspection",permissionCategory:"read",readOnly:!0,risk:"low",supportedPlatforms:A},"service.status":{label:"service inspection",permissionCategory:"read",readOnly:!0,risk:"low",supportedPlatforms:A},"diagnostics.collect":{label:"diagnostics collection",permissionCategory:"read",readOnly:!0,risk:"low",supportedPlatforms:A},"process.control":{label:"process control",permissionCategory:"processControl",readOnly:!1,risk:"high",supportedPlatforms:A},"service.control":{label:"service control",permissionCategory:"serviceControl",readOnly:!1,risk:"high",supportedPlatforms:["windows","linux"]},"application.launch":{label:"application launch",permissionCategory:"applicationControl",readOnly:!1,risk:"medium",supportedPlatforms:A},"application.close":{label:"application close",permissionCategory:"applicationControl",readOnly:!1,risk:"medium",supportedPlatforms:A},"file.read":{label:"file reading",permissionCategory:"fileRead",readOnly:!0,risk:"low",supportedPlatforms:A},"file.write":{label:"file writing",permissionCategory:"fileWrite",readOnly:!1,risk:"high",supportedPlatforms:A},"file.delete":{label:"file deletion",permissionCategory:"fileDelete",readOnly:!1,risk:"critical",supportedPlatforms:A},"file.list":{label:"directory listing",permissionCategory:"fileRead",readOnly:!0,risk:"low",supportedPlatforms:A},"file.search":{label:"file name search",permissionCategory:"fileRead",readOnly:!0,risk:"low",supportedPlatforms:A},"directory.create":{label:"directory creation",permissionCategory:"fileWrite",readOnly:!1,risk:"medium",supportedPlatforms:A},"command.run":{label:"command execution",permissionCategory:"shell",readOnly:!1,risk:"critical",supportedPlatforms:A},"script.run":{label:"script execution",permissionCategory:"script",readOnly:!1,risk:"high",supportedPlatforms:A},"software.install":{label:"software installation",permissionCategory:"softwareInstall",readOnly:!1,risk:"high",supportedPlatforms:A},"network.status":{label:"network inspection",permissionCategory:"network",readOnly:!0,risk:"low",supportedPlatforms:A},"system.power":{label:"power control",permissionCategory:"systemPower",readOnly:!1,risk:"critical",supportedPlatforms:A},"system.configure":{label:"system configuration",permissionCategory:"systemConfiguration",readOnly:!1,risk:"critical",supportedPlatforms:A},"logs.collect":{label:"log collection",permissionCategory:"read",readOnly:!0,risk:"low",supportedPlatforms:A}};new Set(Object.keys(B));const Mt={Recommended:["recommended","overview","fleet","요약","추천"],"Health & capacity":["health","capacity","performance","상태","성능","용량"],"Processes & services":["process","service","application","프로세스","서비스","앱"],"Files & configuration":["file","config","directory","파일","설정","폴더"],"Software & automation":["software","install","automation","프로그램","설치","자동화"],"Network & connectivity":["network","connection","adapter","네트워크","연결","어댑터"],"Power & maintenance":["power","maintenance","restart","전원","유지보수","재시작"],"Troubleshooting & recovery":["troubleshooting","recovery","incident","문제해결","복구","장애"]},Ue=["low","medium","high","critical"];function Dt(e){return e.reduce((s,n)=>{const a=B[n].risk;return Ue.indexOf(a)>Ue.indexOf(s)?a:s},"low")}function qt(e){return A.filter(s=>e.every(n=>B[n].supportedPlatforms.includes(s)))}function o(e,s,n,a,u,h,d={}){const v=d.description||a,j=u.flatMap(C=>C.split(".")),g=[...new Set([...Mt[s],...h,...j])];return{id:e,category:s,title:n,prompt:a,description:v,requiredOperations:u,risk:d.risk||Dt(u),targetSupport:d.targetSupport||"single-or-multiple",supportedPlatforms:d.supportedPlatforms||qt(u),keywords:g,recommended:d.recommended??!1,enabled:!0}}const We=[o("recommended-fleet-health","Recommended","Summarize current target health","Summarize system health, GPU, and disk capacity for the current target Clients.",["system.health","gpu.status","disk.status"],["summary","overview"],{recommended:!0}),o("recommended-attention","Recommended","Find targets needing attention","Identify current targets with high resource use, low disk space, or service warnings.",["system.health","disk.status","service.status"],["attention","warning","monitor"],{recommended:!0}),o("recommended-performance-compare","Recommended","Compare selected performance","Compare CPU, memory, disk, and GPU capacity across the current targets.",["system.health","disk.status","gpu.status"],["compare","benchmark"],{recommended:!0}),o("recommended-gpu-vram","Recommended","Review GPU and VRAM availability","Show GPU temperature, utilization, and VRAM availability for the current targets.",["gpu.status"],["graphics","temperature","utilization"],{recommended:!0}),o("recommended-low-disk","Recommended","Locate low disk capacity","Find current targets with low free disk capacity and report the affected volumes.",["disk.status"],["storage","free space","capacity"],{recommended:!0}),o("recommended-process-services","Recommended","Review processes and services","Review running processes and service state for warnings on the current targets.",["process.list","service.status"],["process","service","warning"],{recommended:!0}),o("recommended-recover-application","Recommended","Recover a stopped application","Check a named application or service, relaunch its registered entry when stopped, and verify the result.",["process.list","application.launch","service.status"],["recover","start","application"],{targetSupport:"single",recommended:!0}),o("recommended-incident-diagnostics","Recommended","Collect an incident diagnostic bundle","Collect health, service, network, and recent log diagnostics for the current targets.",["diagnostics.collect","logs.collect","system.health","network.status"],["incident","report","evidence"],{recommended:!0}),o("health-cpu-memory","Health & capacity","Check high CPU and memory use","Find current targets with unusually high CPU or memory usage.",["system.health"],["cpu","memory","load","높은 사용량"]),o("health-uptime","Health & capacity","Review Client uptime","Show uptime, boot time, and current system health for the target Clients.",["system.health"],["uptime","boot","가동시간"]),o("health-gpu-temperature","Health & capacity","Check GPU temperature","Check GPU temperature and thermal warnings on the current targets.",["gpu.status"],["thermal","temperature","발열"]),o("health-vram-usage","Health & capacity","Check VRAM usage","Report GPU memory usage and remaining VRAM on the current targets.",["gpu.status"],["vram","gpu memory","video memory"]),o("health-low-disk","Health & capacity","Find low disk space","Find volumes below a safe free-space threshold on the current targets.",["disk.status"],["disk","storage","free space","디스크"]),o("health-gpu-compare","Health & capacity","Compare GPU capacity","Compare GPU model, memory, temperature, and utilization across the current targets.",["gpu.status"],["compare","graphics","capacity"]),o("health-system-warnings","Health & capacity","Collect system warnings","Review health, disk, and network status for warnings that need attention.",["system.health","disk.status","network.status"],["warnings","alerts","경고"]),o("health-capacity-report","Health & capacity","Build a capacity report","Create a concise capacity report covering CPU, memory, GPU, disk, and network status.",["system.health","gpu.status","disk.status","network.status"],["report","capacity","inventory"]),o("process-find-name","Processes & services","Find a running process by name","Find process named [process name] on the current targets.",["process.list"],["find","running","name","실행 중"]),o("process-resource-heavy","Processes & services","Find resource-heavy processes","List the processes using the most CPU or memory on the current targets.",["process.list","system.health"],["top","cpu","memory","resource"]),o("process-stop-named","Processes & services","Stop a named process","Stop process named [process name] on the target Client after checking its current state.",["process.list","process.control"],["stop","terminate","종료"],{targetSupport:"single"}),o("process-restart-named","Processes & services","Restart a named process","Check process named [process name] and restart it with its registered launch details when available.",["process.list","process.control"],["restart","relaunch","재시작"],{targetSupport:"single"}),o("process-launch-app","Processes & services","Launch a registered application","Launch the registered application [application] on the target Client with [arguments].",["application.launch"],["launch","open","실행"],{targetSupport:"single"}),o("process-close-app","Processes & services","Close an application","Close application [application] on the target Client and report whether it exited cleanly.",["application.close","process.list"],["close","exit","앱 종료"],{targetSupport:"single"}),o("service-status-name","Processes & services","Check a service status","Check service [service name] and report its state on the current targets.",["service.status"],["service","status","서비스 상태"]),o("service-restart-name","Processes & services","Restart a service safely","Check service [service name], stop it, wait for it to stop, then start it and verify the result.",["service.status","service.control"],["restart","start","stop","서비스 재시작"],{targetSupport:"single"}),o("files-list-directory","Files & configuration","List a directory","List files and folders under [path] on the target Client.",["file.list"],["directory","folder","list","목록"],{targetSupport:"single"}),o("files-search-name","Files & configuration","Search files by name","Search for files or folders containing [name] under [path] on the target Client.",["file.search"],["search","find","filename","파일 찾기"],{targetSupport:"single"}),o("files-create-directory","Files & configuration","Create a directory","Create directory [path] on the target Client and report the final path.",["directory.create"],["create","directory","folder","폴더 만들기"],{targetSupport:"single"}),o("files-read-config","Files & configuration","Read a configuration file","Read the relevant settings from configuration file [path] on the target Client.",["file.read"],["config","settings","read","구성"]),o("files-recent-logs","Files & configuration","Find recent log files","List recent log files under [path] and summarize the latest entries.",["file.list","file.read"],["logs","recent","tail"]),o("files-update-config","Files & configuration","Update a configuration value","Read configuration file [path], update [change], and report the exact change made.",["file.read","file.write"],["edit","update","설정 변경"],{targetSupport:"single"}),o("files-delete-temp","Files & configuration","Delete temporary files","Find temporary files under [path], delete only the requested matches, and report the freed space.",["file.list","file.delete","disk.status"],["cleanup","temp","delete","정리"],{targetSupport:"single"}),o("files-compare-config","Files & configuration","Compare configuration files","Read configuration file [path] on the target Client and compare it with [reference path].",["file.read"],["compare","diff","configuration"]),o("files-set-environment","Files & configuration","Set an environment variable","Set environment variable [name] to [value] for the target Client and verify the resulting configuration.",["system.configure","file.read"],["environment","variable","env","환경변수"],{targetSupport:"single"}),o("files-archive-diagnostics","Files & configuration","Write a diagnostic manifest","Collect selected diagnostics and write a manifest file to [path] on the target Client.",["diagnostics.collect","file.write"],["manifest","export","diagnostic file"],{targetSupport:"single"}),o("software-winget-install","Software & automation","Install software with winget","Install package [package name] with winget on the Windows target Client, then verify it.",["software.install","process.list"],["winget","windows","install","설치"],{targetSupport:"single",supportedPlatforms:["windows"]}),o("software-apt-install","Software & automation","Install software with apt","Install package [package name] with apt on the Linux target Client, then verify it.",["software.install","process.list"],["apt","linux","package","설치"],{targetSupport:"single",supportedPlatforms:["linux"]}),o("software-brew-install","Software & automation","Install software with Homebrew","Install package [package name] with brew on the macOS target Client, then verify it.",["software.install","process.list"],["brew","homebrew","macos","설치"],{targetSupport:"single",supportedPlatforms:["macos"]}),o("software-npm-install","Software & automation","Install an npm package","Install npm package [package name] on the target Client and verify the installed version.",["software.install","command.run"],["npm","node","package"],{targetSupport:"single"}),o("software-run-script","Software & automation","Run a registered script","Run the registered script [script path] on the target Client and report its result.",["script.run"],["script","automation","registered"],{targetSupport:"single"}),o("software-run-command","Software & automation","Run a shell command on one target","Run [command] with [PowerShell, cmd, bash, zsh, sh, or pwsh] on the target Client and return its exit status, duration, and output.",["command.run"],["command","powershell","shell","terminal"],{targetSupport:"single"}),o("software-verify-install","Software & automation","Verify an installed tool","Check whether [application] is installed, running, and available on the PATH of the current targets.",["process.list","system.health"],["verify","installed","path"]),o("software-toolchain-setup","Software & automation","Set up a toolchain","Install the requested package [package name], configure [change], and verify the toolchain on the target Client.",["software.install","system.configure","process.list"],["toolchain","setup","developer"],{targetSupport:"single"}),o("network-adapter-status","Network & connectivity","Check network adapters","Show adapter state, address, and link information for the current targets.",["network.status"],["adapter","ethernet","wifi","네트워크 상태"]),o("network-disconnected","Network & connectivity","Find disconnected targets","Find current targets with disconnected or degraded network adapters.",["network.status"],["disconnected","offline","연결 끊김"]),o("network-link-speed","Network & connectivity","Check link speed","Report network link speed and duplex information for the current targets.",["network.status"],["speed","bandwidth","duplex"]),o("network-warnings","Network & connectivity","Review network warnings","Review network status and recent logs for connectivity warnings on the current targets.",["network.status","logs.collect"],["warning","latency","packet loss"]),o("network-diagnostics","Network & connectivity","Collect network diagnostics","Collect network status, system diagnostics, and relevant logs for the current targets.",["network.status","diagnostics.collect","logs.collect"],["diagnostics","incident","connectivity"]),o("network-service-failures","Network & connectivity","Find network service failures","Check network status and relevant service states on the current targets.",["network.status","service.status"],["service","failure","dns"]),o("network-compare","Network & connectivity","Compare target connectivity","Compare adapter state, addresses, and link speed across the current targets.",["network.status"],["compare","inventory","connectivity"]),o("network-intermittent","Network & connectivity","Investigate intermittent connectivity","Investigate intermittent connectivity using network status, service state, and diagnostics evidence.",["network.status","service.status","diagnostics.collect"],["intermittent","unstable","recovery"]),o("power-lock","Power & maintenance","Lock the Client","Lock the target Client and report the resulting power action status.",["system.power"],["lock","security","잠금"],{targetSupport:"single",risk:"critical"}),o("power-logoff","Power & maintenance","Log off the Client","Log off the target Client after warning that interactive sessions will close.",["system.power"],["logoff","session","로그오프"],{targetSupport:"single",risk:"critical"}),o("power-sleep","Power & maintenance","Put the Client to sleep","Put the target Client to sleep after confirming the requested delay of [delay].",["system.power"],["sleep","suspend","절전"],{targetSupport:"single",risk:"critical"}),o("power-restart","Power & maintenance","Restart the Client","Restart the target Client after confirming that active work may be interrupted.",["system.power"],["restart","reboot","재부팅"],{targetSupport:"single",risk:"critical"}),o("power-shutdown","Power & maintenance","Shut down the Client","Shut down the target Client after confirming that active work may be interrupted.",["system.power"],["shutdown","power off","종료"],{targetSupport:"single",risk:"critical"}),o("power-maintenance-restart","Power & maintenance","Restart after maintenance","Check the target Client, restart it after maintenance, and verify that it returns online.",["system.health","system.power","network.status"],["maintenance","reboot","verify"],{targetSupport:"single",risk:"critical"}),o("power-timezone","Power & maintenance","Set the Client timezone","Set the target Client timezone to [timezone] and verify the resulting system configuration.",["system.configure"],["timezone","clock","시간대"],{targetSupport:"single",risk:"critical"}),o("power-persistent-environment","Power & maintenance","Persist an environment variable","Persist environment variable [name] with value [value] for the target Client and verify it.",["system.configure"],["environment","persistent","환경변수"],{targetSupport:"single",risk:"critical"}),o("recovery-app-wont-start","Troubleshooting & recovery","Investigate an app that will not start","Inspect [application], review its logs, launch the registered application, and verify the process.",["process.list","application.launch","logs.collect"],["app failure","start","실행 오류"],{targetSupport:"single"}),o("recovery-failed-service","Troubleshooting & recovery","Recover a failed service","Inspect service [service name], collect logs, restart it safely, and verify its running state.",["service.status","logs.collect","service.control"],["service failure","recover","서비스 복구"],{targetSupport:"single"}),o("recovery-repeated-process","Troubleshooting & recovery","Investigate a repeatedly stopping process","Inspect process [process name], collect diagnostics, stop stale instances, and relaunch the registered process.",["process.list","diagnostics.collect","process.control","application.launch"],["crash loop","process","반복 종료"],{targetSupport:"single"}),o("recovery-low-disk","Troubleshooting & recovery","Recover from low disk space","Inspect disk capacity, find temporary files, remove only the requested files, and verify free space.",["disk.status","file.list","file.delete"],["disk full","cleanup","저장공간 부족"],{targetSupport:"single"}),o("recovery-gpu-overheating","Troubleshooting & recovery","Investigate GPU overheating","Inspect GPU temperature and processes, then close the specified workload if it is causing the thermal warning.",["gpu.status","process.list","application.close"],["overheating","thermal","GPU 발열"],{targetSupport:"single"}),o("recovery-high-vram","Troubleshooting & recovery","Recover high VRAM usage","Inspect VRAM usage and GPU processes, then stop the specified stale workload if necessary.",["gpu.status","process.list","process.control"],["vram","memory pressure","VRAM 부족"],{targetSupport:"single"}),o("recovery-network-instability","Troubleshooting & recovery","Recover network instability","Collect network diagnostics, inspect network services, and report the safest recovery action for the target Client.",["network.status","service.status","diagnostics.collect"],["network","unstable","네트워크 복구"],{targetSupport:"single"}),o("recovery-incident-report","Troubleshooting & recovery","Create a full incident report","Create a full incident report from health, process, service, network, and log evidence for the current targets.",["system.health","process.list","service.status","network.status","logs.collect"],["incident","report","장애 보고서"])],ye={read:"allow",processControl:"allow",serviceControl:"allow",applicationControl:"ask",fileRead:"allow",fileWrite:"allow",fileDelete:"ask",shell:"ask",script:"ask",softwareInstall:"ask",network:"allow",systemPower:"ask",systemConfiguration:"ask",userAccount:"deny"};function zt(e,s){return e==="safe-auto"?ye:e==="full-access"?{...ye,processControl:"allow",serviceControl:"allow",applicationControl:"allow",fileDelete:"allow",shell:"allow",script:"allow",softwareInstall:"allow",systemPower:"allow",systemConfiguration:"allow"}:e==="custom"&&s?s:{...ye,processControl:"ask",serviceControl:"ask",applicationControl:"ask",fileWrite:"ask",network:"ask"}}function Ut(e,s,n){const a=zt(s,n),u=e.requiredOperations.map(h=>a[B[h].permissionCategory]);if(u.includes("deny")){const h=e.requiredOperations.find(d=>a[B[d].permissionCategory]==="deny");return{state:"blocked",label:"Blocked",reason:`This task requires ${B[h].label}, which is blocked by the current permission policy.`}}return u.includes("ask")?{state:"approval",label:"Approval required",reason:"This task requires approval before the requested changes can reach a Client."}:e.requiredOperations.every(h=>B[h].readOnly)?{state:"read-only",label:"Read only"}:s==="full-access"?{state:"full-access",label:"Full Access"}:{state:"auto",label:"Auto allowed"}}function Lt(e){const s=String(e||"").trim().toLowerCase();return s==="windows"||s==="win32"||s==="win32nt"?"windows":s==="macos"||s==="macosx"||s==="darwin"||s==="osx"?"macos":s==="linux"?"linux":null}function Bt(e,s,n){const a=new Set(n);return e.filter(u=>u.connected&&(s==="all"||s==="auto"||a.has(u.deviceId)))}function Gt(e,s){const n=Lt(e.platform);if(!n||!s.supportedPlatforms.includes(n))return!1;const a=e.capabilities?.agentTools;return!Array.isArray(a)||a.length===0?s.requiredOperations.every(u=>B[u].readOnly):s.requiredOperations.every(u=>a.includes(u))}function Je(e,s,n,a,u,h){const d=Ut(e,u,h),v=Bt(s,n,a),j=v.map(b=>b.deviceId),g={...d,available:!1,availableDeviceIds:[],unsupportedDeviceIds:j,risk:e.risk,supportedPlatforms:e.supportedPlatforms};if(v.length===0)return{...g,reason:"Select at least one connected Client."};if(e.targetSupport==="single"&&v.length!==1)return{...g,reason:"This task supports one Client at a time."};if(d.state==="blocked")return g;const C=v.filter(b=>Gt(b,e)),w=C.map(b=>b.deviceId),R=j.filter(b=>!w.includes(b));return C.length===0?{...g,unsupportedDeviceIds:R,reason:"No current target supports the required platform and client capabilities."}:{...g,available:!0,availableDeviceIds:w,unsupportedDeviceIds:R}}function Ht(e,s,n,a,u,h){return e.filter(d=>d.enabled&&Je(d,s,n,a,u,h).available).length}const ve="livedesk.agentPromptRecent",we="livedesk.agentPromptFavorites",_t={Recommended:V,"Health & capacity":Ct,"Processes & services":xt,"Files & configuration":bt,"Software & automation":kt,"Network & connectivity":wt,"Power & maintenance":_e,"Troubleshooting & recovery":vt};function Le(e){if(typeof window>"u")return[];try{const s=JSON.parse(window.localStorage.getItem(e)||"[]");return Array.isArray(s)?s.filter(n=>typeof n=="string"):[]}catch{return[]}}function ce(e,s){try{window.localStorage.setItem(e,JSON.stringify(s))}catch{}}function ke(e){return e==="all"?"All tasks":e==="recent"?"Recent":e==="favorites"?"Favorites":e==="read-only"?"Read only":e==="auto"?"Auto allowed":e==="approval"?"Approval required":e==="full-access"?"Full Access":e==="available"?"Available":e==="unavailable"?"Unavailable":e}function Vt(e){return e==="all"?"All":e==="recent"?"Recent":e==="favorites"?"Favorites":e==="read-only"?"Read only":e==="auto"?"Auto":e==="approval"?"Approval":e==="full-access"?"Full access":e==="available"?"Available":e==="unavailable"?"Unavailable":{Recommended:"Recommended","Health & capacity":"Health","Processes & services":"Processes","Files & configuration":"Files","Software & automation":"Software","Network & connectivity":"Network","Power & maintenance":"Power","Troubleshooting & recovery":"Recovery"}[e]}function Wt(e,s,n){if(!n.trim())return!0;const a=n.trim().toLowerCase();return[e.title,e.prompt,e.description,e.category,e.risk,s.label,...e.keywords,...e.requiredOperations,...e.supportedPlatforms].join(" ").toLowerCase().includes(a)}function Jt(e){return`permission-${e}`}function Kt(e){return e==="low"?"Low risk":e==="medium"?"Medium risk":e==="high"?"High risk":"Critical risk"}function Yt(e){return e==="windows"?"Windows":e==="macos"?"macOS":"Linux"}function Qt({devices:e,targetMode:s,selectedIds:n,permissionMode:a,customCategories:u,onSelectPrompt:h,onClose:d}){const[v,j]=c.useState(""),[g,C]=c.useState("all"),[w,R]=c.useState(()=>Le(ve)),[b,T]=c.useState(()=>Le(we)),[k,x]=c.useState(0),[q,E]=c.useState(""),p=c.useRef(null),$=c.useRef(null),P=c.useMemo(()=>We.filter(i=>i.enabled),[]),N=c.useMemo(()=>new Map(P.map(i=>[i.id,Je(i,e,s,n,a,u)])),[u,e,a,n,s,P]),G=c.useMemo(()=>[...N.values()].filter(i=>i.available).length,[N]),te=c.useMemo(()=>e.filter(i=>i.connected&&(s==="all"||s==="auto"||n.includes(i.deviceId))).length,[e,n,s]),F=c.useMemo(()=>{const i=P.filter(f=>Wt(f,N.get(f.id),v));return g==="recent"?w.map(f=>i.find(S=>S.id===f)).filter(f=>!!f):g==="favorites"?b.map(f=>i.find(S=>S.id===f)).filter(f=>!!f):g==="all"?i:i.filter(f=>{const S=N.get(f.id);return g==="read-only"?S.state==="read-only":g==="auto"?S.state==="auto":g==="approval"?S.state==="approval":g==="full-access"?S.state==="full-access":g==="available"?S.available:g==="unavailable"?!S.available:f.category===g})},[N,b,g,w,v,P]),me=c.useMemo(()=>g!=="all"?[{category:ke(g),templates:F}]:ze.map(i=>({category:i,templates:F.filter(f=>f.category===i)})).filter(i=>i.templates.length>0),[g,F]);c.useEffect(()=>{x(i=>Math.min(i,Math.max(0,F.length-1)))},[F.length]),c.useEffect(()=>{ce(ve,w)},[w]),c.useEffect(()=>{ce(we,b)},[b]),c.useEffect(()=>{$.current?.focus();const i=S=>{S.target instanceof Node&&!p.current?.contains(S.target)&&d()},f=S=>{S.key==="Escape"&&(S.preventDefault(),d())};return document.addEventListener("pointerdown",i),document.addEventListener("keydown",f),()=>{document.removeEventListener("pointerdown",i),document.removeEventListener("keydown",f)}},[d]);const se=i=>{const f=N.get(i.id);if(!f.available){E(f.reason||"This task is not available for the current targets and permission policy.");return}const S=[i.id,...w.filter(z=>z!==i.id)].slice(0,10);R(S),ce(ve,S),h(i.prompt),d()},Y=i=>{T(f=>{const S=f.includes(i)?f.filter(z=>z!==i):[i,...f];return ce(we,S),S})},fe=i=>{i.key==="ArrowDown"?(i.preventDefault(),x(f=>Math.min(f+1,Math.max(0,F.length-1)))):i.key==="ArrowUp"?(i.preventDefault(),x(f=>Math.max(f-1,0))):i.key==="Enter"&&F[k]&&(i.preventDefault(),se(F[k]))};let H=-1;return t.jsxs("section",{className:"agents-suggested-tasks",ref:p,"aria-label":"Suggested tasks",children:[t.jsxs("header",{className:"agents-suggested-header",children:[t.jsxs("div",{children:[t.jsxs("span",{className:"agents-suggested-title",children:[t.jsx(V,{size:15})," Suggested tasks"]}),t.jsxs("small",{children:[G," available · ",P.length," total. Choose a task, edit it, then run it."]})]}),t.jsx("button",{className:"agents-suggested-close",type:"button","aria-label":"Close suggested tasks",onClick:d,children:t.jsx(Ce,{size:16})})]}),t.jsxs("label",{className:"agents-suggested-search",children:[t.jsx(mt,{size:15,"aria-hidden":"true"}),t.jsx("input",{ref:$,value:v,onChange:i=>j(i.target.value),onKeyDown:fe,placeholder:"Search tasks...","aria-label":"Search suggested tasks"})]}),t.jsx("div",{className:"agents-suggested-filters","aria-label":"Task categories and availability filters",children:["all","recent","favorites","read-only","auto","approval","full-access","available","unavailable",...ze].map(i=>{const f=i==="recent"?ft:i==="favorites"?Me:i==="all"?V:i==="available"?ht:i==="unavailable"?yt:i==="read-only"||i==="auto"||i==="approval"||i==="full-access"?_e:_t[i];return t.jsxs("button",{className:g===i?"active":"",type:"button",title:ke(i),"aria-label":ke(i),"aria-pressed":g===i,onClick:()=>{C(i),x(0),E("")},children:[t.jsx(f,{size:12})," ",Vt(i)]},i)})}),q&&t.jsx("div",{className:"agents-suggested-notice",role:"status",children:q}),t.jsxs("div",{className:"agents-suggested-list",role:"listbox","aria-label":"Suggested tasks",children:[me.map(i=>t.jsxs("div",{className:"agents-suggested-group",children:[t.jsx("strong",{children:i.category}),i.templates.map(f=>{H+=1;const S=H===k,z=b.includes(f.id),M=N.get(f.id),W=M.availableDeviceIds.length+M.unsupportedDeviceIds.length||te,ne=M.available?`Available on ${M.availableDeviceIds.length} of ${W} target${W===1?"":"s"}`:`Unavailable: ${M.reason||"not supported by the current targets"}`;return t.jsxs("div",{className:`agents-suggested-item ${S?"active":""} ${M.available?"":"unavailable"}`,children:[t.jsxs("button",{className:"agents-suggested-prompt",type:"button",role:"option","aria-selected":S,"aria-disabled":!M.available,onClick:()=>se(f),children:[t.jsx("span",{children:f.title}),t.jsx("small",{className:"agents-suggested-description",children:f.description}),t.jsxs("span",{className:"agents-suggested-meta",children:[t.jsx("em",{children:f.category}),t.jsx("em",{className:Jt(M.state),children:M.label}),t.jsx("em",{className:`risk-${f.risk}`,children:Kt(f.risk)}),t.jsx("em",{children:f.supportedPlatforms.map(Yt).join(" · ")}),t.jsx("em",{className:M.available?"availability-ok":"availability-unavailable",children:ne}),M.available&&M.unsupportedDeviceIds.length>0&&t.jsxs("em",{className:"availability-warning",children:["Unsupported on ",M.unsupportedDeviceIds.length]})]})]}),t.jsx("button",{className:`agents-suggested-favorite ${z?"favorite":""}`,type:"button","aria-label":z?`Remove ${f.title} from favorites`:`Add ${f.title} to favorites`,"aria-pressed":z,onClick:()=>Y(f.id),children:t.jsx(Me,{size:14,fill:z?"currentColor":"none"})})]},f.id)})]},i.category)),F.length===0&&t.jsx("p",{className:"agents-suggested-empty",children:"No tasks match this search or current filter."})]})]})}function Xt({devices:e,mode:s,selectedIds:n,onModeChange:a,onToggle:u,permissionMode:h,onPermissionModeChange:d}){const v=e.filter(pe),j=n.filter(g=>v.some(C=>C.deviceId===g)).length;return t.jsxs("section",{className:"agents-target-picker","aria-label":"Agent targets",children:[t.jsxs("div",{className:"agents-target-toolbar",children:[t.jsx("span",{className:"agents-section-label",children:"Targets"}),t.jsxs("div",{className:"agents-target-modes",children:[t.jsxs("button",{className:s==="all"?"active":"",onClick:()=>a("all"),type:"button",children:[t.jsx(ue,{size:14})," All connected ",t.jsx("small",{children:v.length})]}),t.jsxs("button",{className:s==="selected"?"active":"",onClick:()=>a("selected"),type:"button",children:[t.jsx(ee,{size:14})," Selected ",j]}),t.jsxs("button",{className:s==="auto"?"active":"",onClick:()=>a("auto"),type:"button",children:[t.jsx(V,{size:14})," Auto"]}),t.jsxs("button",{type:"button",disabled:!0,title:"Saved Client groups are coming next.",children:[t.jsx(ue,{size:14})," Group ",t.jsx("small",{children:"Soon"})]})]}),t.jsxs("label",{className:`agents-permission-picker permission-${h}`,children:[t.jsx(je,{size:14}),t.jsx("span",{children:"Permission"}),t.jsxs("select",{value:h,onChange:g=>d(g.target.value),"aria-label":"Agent permission mode",children:[t.jsx("option",{value:"ask",children:"Ask"}),t.jsx("option",{value:"safe-auto",children:"Safe Auto"}),t.jsx("option",{value:"full-access",children:"Full Access"}),t.jsx("option",{value:"custom",children:"Custom"})]}),t.jsx(He,{size:13,"aria-hidden":"true"})]})]}),t.jsx("div",{className:"agents-target-list",children:e.length===0?t.jsx("span",{className:"agents-target-empty",children:"No Clients discovered."}):e.map(g=>{const C=pe(g),w=s==="all"||s==="auto"?C:n.includes(g.deviceId);return t.jsxs("label",{className:`agents-target-option ${w?"selected":""} ${C?"":"offline"}`,children:[t.jsx("input",{type:"checkbox",checked:w,disabled:!C||s!=="selected",onChange:()=>u(g.deviceId)}),t.jsx("span",{className:"agents-target-icon",children:t.jsx(Ve,{size:15})}),t.jsxs("span",{children:[t.jsx("strong",{children:de(g)}),t.jsx("small",{children:C?"Ready":g.connected?"Agent reconnecting":"Offline"})]}),w&&t.jsx(ee,{className:"agents-target-check",size:15,"aria-hidden":"true"})]},g.deviceId)})})]})}const Zt=800,Be=5e3;function es(){return typeof document>"u"||document.visibilityState==="visible"}function ts(e){return typeof document>"u"?()=>{}:(document.addEventListener("visibilitychange",e),()=>document.removeEventListener("visibilitychange",e))}function Ge({poll:e,onResult:s,onError:n,intervalMs:a=Zt,isVisible:u=es,subscribeVisibility:h=ts,setTimeoutImpl:d=globalThis.setTimeout.bind(globalThis),clearTimeoutImpl:v=globalThis.clearTimeout.bind(globalThis),createAbortController:j=()=>new AbortController}){if(typeof e!="function")throw new TypeError("Agent polling requires a poll function.");const g={current:null};let C=!0,w=0,R=null,b=null;const T=()=>{R!==null&&(v(R),R=null)},k=()=>{!C||!u()||R!==null||g.current||(R=d(()=>{R=null,x()},a))},x=()=>{if(!C||!u()||g.current)return g.current;const $=++w,P=j();b=P;const N=ot(g,()=>e(P.signal));return N.then(G=>{C&&$===w&&!P.signal.aborted&&s?.(G)},G=>{C&&$===w&&!P.signal.aborted&&n?.(G)}).finally(()=>{b===P&&(b=null),C&&u()&&k()}).catch(()=>{}),N},q=async()=>{if(!C)throw new Error("VuvoDesk Agent polling owner is closed.");T(),w+=1;const $=g.current;if(b&&!b.signal.aborted&&b.abort(new Error("VuvoDesk Agent polling was superseded by an explicit refresh.")),$)try{await $}catch{}if(!(!C||!u()))return T(),x()},p=h(()=>{if(T(),!u()){w+=1,b&&!b.signal.aborted&&b.abort(new Error("VuvoDesk Agent polling paused while hidden."));return}x()});return x(),{refresh:q,stop(){C&&(C=!1,w+=1,T(),p?.(),b&&!b.signal.aborted&&b.abort(new Error("VuvoDesk Agent polling owner closed.")))}}}async function ss(e,s){return U("/api/settings/agent/run",{method:"POST",body:JSON.stringify(s)},e)}async function ns(e,s,n={}){return U(`/api/settings/agent/runs/${encodeURIComponent(s)}`,n,e)}async function rs(e,s){return U(`/api/settings/agent/runs/${encodeURIComponent(s)}/cancel`,{method:"POST",body:JSON.stringify({})},e)}async function as(e){return U("/api/settings/agent/runs/cancel-all",{method:"POST",body:JSON.stringify({})},e)}async function is(e,s,n,a){return U(`/api/settings/agent/runs/${encodeURIComponent(s)}/approvals/${encodeURIComponent(n)}/approve`,{method:"POST",body:JSON.stringify({scope:a})},e)}async function os(e,s,n,a="User rejected this action."){return U(`/api/settings/agent/runs/${encodeURIComponent(s)}/approvals/${encodeURIComponent(n)}/reject`,{method:"POST",body:JSON.stringify({reason:a})},e)}async function ls(e,s,n){return U(`/api/settings/agent/policies/${encodeURIComponent(s)}`,{method:"PUT",body:JSON.stringify({categories:n})},e)}async function cs(e,s,n={}){return U(`/api/remote/tasks/${encodeURIComponent(s)}`,n,e)}async function us(e,s){return U(`/api/remote/tasks/${encodeURIComponent(s)}/cancel`,{method:"POST",body:JSON.stringify({})},e)}async function ds(e,s){return U(`/api/remote/tasks/${encodeURIComponent(s)}/retry`,{method:"POST",body:JSON.stringify({failedOnly:!0})},e)}function Z(e){return`${e}-${Date.now()}-${Math.random().toString(36).slice(2,8)}`}function be(e,s){const n=new Map(s.map(a=>[a.deviceId,de(a)]));return e.results.map(a=>({deviceId:a.deviceId,deviceName:a.deviceName||n.get(a.deviceId)||a.deviceId,status:At(a.status),stage:a.stage||(a.status==="running"?"Checking processes":void 0),result:a.result,data:a.data,error:a.error,sequence:Number.isSafeInteger(a.sequence)?a.sequence:0}))}function ps(e,s){const n=new Map(s.map(a=>[a.deviceId,a]));return e.map(a=>{const u=n.get(a.deviceId);return!u||u.sequence<=a.sequence?a:u})}const gs={read:"allow",processControl:"ask",serviceControl:"ask",applicationControl:"ask",fileRead:"ask",fileWrite:"ask",fileDelete:"ask",shell:"ask",script:"ask",softwareInstall:"ask",network:"ask",systemPower:"ask",systemConfiguration:"ask",userAccount:"deny"};function ms(e){return e==="safe-auto"?"Safe Auto":e==="full-access"?"Full Access":e==="custom"?"Custom":"Ask"}function fs(e){return e.replace(/([A-Z])/g," $1").replace(/^./,s=>s.toUpperCase())}function hs(e){const s=e instanceof Error?e.message:String(e);return/agent-disabled/i.test(s)?"Enable Codex Agent in Settings before running commands.":/agent-no-target-devices|agent-target-not-connected|device-not-connected/i.test(s)?"The selected Client is reconnecting. Wait until its Agent status is Ready and try again.":/codex-auth-required/i.test(s)?"Codex sign-in is required on the Hub. Open Settings > Agent and test the Codex connection.":s}function ks({hubUrl:e,devices:s,launchRequest:n,variant:a="page",selectedDeviceIds:u=[]}){const h=a==="dock",[d,v]=c.useState(h?u.length>0?"selected":"auto":"all"),[j,g]=c.useState(u),[C,w]=c.useState("auto"),[R,b]=c.useState(""),[T,k]=c.useState([]),[x,q]=c.useState(""),[E,p]=c.useState(""),[$,P]=c.useState(""),[N,G]=c.useState("safe-auto"),[te]=c.useState("custom-default"),[F,me]=c.useState(gs),[se,Y]=c.useState([]),[fe,H]=c.useState(""),[i,f]=c.useState(!1),[S,z]=c.useState(null),[M,W]=c.useState(!1),[ne,L]=c.useState(""),[Se,Q]=c.useState(!1),[Ae,X]=c.useState(null),re=c.useRef(null),J=c.useRef(null),ae=c.useRef(null),Re=c.useRef(new Set),Pe=c.useRef(new Set),he=c.useMemo(()=>s.filter(pe).map(r=>r.deviceId),[s]),Ke=c.useMemo(()=>Ht(We,s,d,j,N,F),[F,s,N,j,d]);c.useEffect(()=>{h&&g(u)},[h,u]),c.useEffect(()=>{n?.deviceId&&(v("selected"),g([n.deviceId]),b(n.instruction),Q(!1),window.requestAnimationFrame(()=>{re.current?.focus(),re.current?.setSelectionRange(n.instruction.length,n.instruction.length)}))},[n]);const K=c.useCallback(r=>{const l=be(r,s);k(y=>y.map(m=>m.type==="task"&&m.batchId===r.batchId?{...m,states:ps(m.states,l),status:r.status}:m)),["running","queued"].includes(r.status)||q(y=>y===r.batchId?"":y)},[s]),Ne=c.useCallback((r,l)=>{Pe.current.has(r.batchId)||(Pe.current.add(r.batchId),k(y=>[...y,{type:"task",id:Z("task"),batchId:r.batchId,agentRunId:l,operation:r.operation||"diagnostics.collect",instruction:r.instructionPreview,states:be(r,s),status:r.status}])),K(r)},[s,K]),Ie=c.useCallback((r,l)=>{for(const m of l.taskBatches||[])Ne(m,r);Y(l.approvals||[]);const y=["running","queued","waiting-approval"].includes(l.status);if(X(y?{runId:r,stage:l.stage||l.status,message:l.progressMessage||(l.status==="waiting-approval"?"Review the requested action to continue.":"Codex is preparing the answer.")}:m=>m?.runId===r?null:m),!y&&!Re.current.has(r)){Re.current.add(r);const m=[l.error,l.errorMessage].filter(Boolean).join(" — "),I=l.finalResponse?.trim()||(l.status==="cancelled"?"Codex 작업을 취소했습니다.":m?`Codex 작업이 완료되지 않았습니다: ${m}`:"Codex 작업이 완료되었습니다.");k($e=>[...$e,{type:l.status==="failed"?"error":"agent",id:Z("agent-run-result"),text:I}])}},[Ne]),Te=c.useCallback(async r=>{const l=J.current;if(!(!l||l.id!==r))try{return await l.owner.refresh()}catch(y){if(J.current!==l)return;throw y}},[]);c.useEffect(()=>{if(!E){J.current=null;return}const r=E,l=Ge({poll:m=>ns(e,r,{signal:m,timeoutMs:Be}),onResult:m=>{Ie(r,m),["running","queued","waiting-approval"].includes(m.status)||(p(I=>I===r?"":I),W(!1))},onError:m=>{L(m instanceof Error?m.message:String(m))}}),y={id:r,owner:l};return J.current=y,()=>{l.stop(),J.current===y&&(J.current=null)}},[E,e,Ie]),c.useEffect(()=>{if(!x){ae.current=null;return}const r=x,l=Ge({poll:m=>cs(e,r,{signal:m,timeoutMs:Be}),onResult:m=>{K(m),["running","queued"].includes(m.status)||q(I=>I===r?"":I)},onError:m=>{L(m instanceof Error?m.message:String(m))}}),y={id:r,owner:l};return ae.current=y,()=>{l.stop(),ae.current===y&&(ae.current=null)}},[x,e,K]);const Oe=async(r="",l,y=!1)=>{const m=(r||R).trim();if(!m||x||E)return;const I=l||(d==="all"||d==="auto"?he:j.filter(O=>he.includes(O)));if(I.length===0){L("Select at least one connected Client.");return}if(N==="full-access"&&!M&&!y){z({instruction:m,targetIds:I});return}if(k(O=>[...O,{type:"user",id:Z("user"),text:m}]),b(""),Q(!1),L(""),I.length===0){k(O=>[...O,{type:"error",id:Z("no-targets"),text:"연결된 대상 장비를 하나 이상 선택해 주세요."}]);return}const Fe=C==="ask"?`Read-only request. Inspect and answer without changing Client state.
|
|
1
|
+
import{j as t,f as ot,h as U}from"./styles-pFD5jrt-.js";import{a as c,m as lt,n as xe,o as ct,l as ee,X as Ce,p as ut,q as dt,s as He,B as pt,t as gt,u as je,S as V,v as mt,w as ft,x as Me,b as ht,y as yt,k as _e,z as vt,N as wt,F as kt,H as bt,I as xt,J as Ct,U as ue,c as Ve}from"./icons-C9gCrfh8.js";import"./react-CzpJ4iNd.js";const jt=c.forwardRef(function({value:s,onChange:n,onSubmit:a,onOpenSuggestedTasks:u,suggestedOpen:h=!1,suggestedTaskCount:d,disabled:v=!1,placeholder:j="Ask VuvoDesk to work across your machines...",compact:g=!1},C){return t.jsxs("form",{className:"agents-composer",onSubmit:w=>{w.preventDefault(),a()},children:[t.jsx("button",{className:`agents-suggested-trigger ${h?"active":""}`,type:"button","aria-label":d===void 0?"Open Suggested tasks":`Open Suggested tasks (${d} available)`,"aria-expanded":h,onClick:u,disabled:v,children:t.jsx(lt,{size:17})}),t.jsx("textarea",{ref:C,value:s,onChange:w=>n(w.target.value.slice(0,4e3)),placeholder:j,"aria-label":"Ask VuvoDesk",rows:g?1:2,disabled:v}),t.jsxs("button",{className:"agents-run-button",type:"submit",disabled:v||!s.trim(),children:[v?t.jsx(xe,{className:"spin",size:16}):t.jsx(ct,{size:16}),v?"Running":"Run"]})]})}),St=["read","processControl","serviceControl","applicationControl","fileRead","fileWrite","fileDelete","shell","script","softwareInstall","network","systemPower","systemConfiguration","userAccount"];function de(e){return e.deviceName?.trim()||e.hostname?.trim()||e.deviceId}function pe(e){return e.connected!==!0?!1:e.synthetic===!0?!0:!e.channels||e.channels.control===!0}function At(e){return e==="running"||e==="completed"||e==="failed"||e==="cancelled"?e:"queued"}function Rt(e){switch(e){case"process.list":return"Process list";case"system.health":return"System health";case"gpu.status":return"GPU status";case"disk.status":return"Disk status";case"service.status":return"Service status";case"diagnostics.collect":return"Diagnostics";case"process.control":return"Process control";case"service.control":return"Service control";case"application.launch":return"Launch application";case"application.close":return"Close application";case"file.read":return"Read file";case"file.write":return"Write file";case"file.delete":return"Delete file";case"file.list":return"List directory";case"command.run":return"Run command";case"script.run":return"Run script";case"software.install":return"Install software";case"network.status":return"Network status";case"system.power":return"Power action";case"system.configure":return"System configuration";case"logs.collect":return"Collect logs"}}function Pt(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:null}function D(e){return typeof e=="number"&&Number.isFinite(e)?e:null}function le(e){const s=D(e);return s===null?"":s<1024**2?`${Math.round(s/1024)}K`:s<1024**3?`${(s/1024**2).toFixed(0)}M`:`${(s/1024**3).toFixed(1)}G`}function De(e){const s=D(e);return s===null?"":`${Math.round((s<=1?s:s/100)*100)}%`}function Nt(e){return!e||/^(?:[\w .-]+ )?collected(?:\.)?$/i.test(e.trim())?"":e.trim()}function ge(e,s){if(s.error)return s.error;const n=Pt(s.data),a=Nt(s.result||"");if(!n)return a||s.stage||s.status;if(e==="system.health"){const u=typeof n.machine=="string"?n.machine:"",h=De(n.cpuUsageRatio),d=D(n.cores),v=le(n.freeMemoryBytes),j=le(n.totalMemoryBytes),g=D(n.totalMemoryBytes)&&D(n.freeMemoryBytes)!==null?`${Math.round(D(n.freeMemoryBytes)/D(n.totalMemoryBytes)*100)}% RAM free`:"";return[u,h&&`CPU ${h}`,d!==null&&`${Math.round(d)} cores`,v&&j?`RAM ${v}/${j}`:"",g,typeof n.platform=="string"?n.platform:""].filter(Boolean).join(" · ")||a||s.status}if(e==="disk.status"){const u=typeof n.root=="string"?n.root:"",h=le(n.freeBytes),d=D(n.totalBytes)&&D(n.freeBytes)!==null?`${Math.round(D(n.freeBytes)/D(n.totalBytes)*100)}% free`:"";return[u,h&&`${h} free`,d].filter(Boolean).join(" · ")||a||s.status}if(e==="gpu.status"){const u=typeof n.name=="string"&&n.name?n.name:"No GPU detected",h=De(n.usageRatio),d=D(n.temperatureC)!==null?`${Math.round(D(n.temperatureC))}°C`:"",v=le(n.freeMemoryBytes);return[u,h&&`GPU ${h}`,d,v&&`${v} free`].filter(Boolean).join(" · ")||a||s.status}if(e==="process.list"){const u=D(n.count);return u!==null?`${u} matching process${u===1?"":"es"}`:a||s.status}if(e==="network.status"){const u=Array.isArray(n.adapters)?n.adapters.length:null;return u!==null?`${u} active adapter${u===1?"":"s"}`:a||s.status}return a||s.stage||s.status}function qe(e,s){const n=ge(e,s);return s.status==="failed"||s.status==="cancelled"||/\b(?:warning|failed|error|offline|not running|low|timeout|timed out)\b/i.test(`${s.result||""} ${n}`)}function It({state:e,operation:s}){const n=e.status==="completed"?ee:e.status==="failed"||e.status==="cancelled"?Ce:e.status==="running"?xe:ut,a=e.status==="running"?e.stage||"Working":e.status==="completed"?s?ge(s,e):e.result||"Completed":e.status==="failed"?e.error||"Failed":e.status==="cancelled"?"Cancelled":"Queued";return t.jsxs("div",{className:`agent-target-row status-${e.status}`,"data-agent-target-id":e.deviceId,children:[t.jsx("span",{className:"agent-target-status","aria-hidden":"true",children:t.jsx(n,{size:15})}),t.jsx("strong",{children:e.deviceName}),t.jsx("span",{className:"agent-target-state",children:e.status[0].toUpperCase()+e.status.slice(1)}),t.jsx("small",{children:a})]})}function Tt({operation:e,states:s,status:n,onCancel:a,onRetry:u,busy:h=!1}){const d=["running","queued"].includes(n),[v,j]=c.useState(!1),[g,C]=c.useState("all"),w=c.useMemo(()=>({total:s.length,completed:s.filter(p=>p.status==="completed").length,failed:s.filter(p=>p.status==="failed").length,running:s.filter(p=>p.status==="running").length,queued:s.filter(p=>p.status==="queued").length,cancelled:s.filter(p=>p.status==="cancelled").length}),[s]),R=s.filter(p=>qe(e,p)),b=R.filter(p=>p.status==="completed").length,T=w.failed>0,k=R.length>0,x=s.filter(p=>g==="issues"?qe(e,p):g==="running"?p.status==="running"||p.status==="queued":g==="completed"?p.status==="completed":g==="failed"?p.status==="failed":!0),q=k&&!d||n==="completed-with-failures"?"Completed with issues":n[0]?.toUpperCase()+n.slice(1),E=s.filter(p=>p.status==="completed").map(p=>ge(e,p)).filter(Boolean).filter((p,$,P)=>P.indexOf(p)===$).slice(0,2);return t.jsxs("section",{className:"agent-task-block","aria-label":"Task execution",children:[t.jsxs("div",{className:"agent-task-head",children:[t.jsxs("div",{children:[t.jsx("span",{children:"VuvoDesk Agent"}),t.jsx("strong",{children:Rt(e)})]}),t.jsx("span",{className:`agent-task-status status-${k?"completed-with-failures":n}`,children:q})]}),t.jsxs("div",{className:"agent-task-summary","aria-label":"Task summary",children:[t.jsxs("strong",{children:[w.total," targets"]}),t.jsxs("span",{className:"summary-completed",children:[w.completed," completed"]}),w.running>0&&t.jsxs("span",{className:"summary-running",children:[w.running," running"]}),w.queued>0&&t.jsxs("span",{children:[w.queued," queued"]}),T&&t.jsxs("span",{className:"summary-failed",children:[w.failed," failed"]}),b>0&&t.jsxs("span",{className:"summary-cancelled",children:[b," warning"]}),w.cancelled>0&&t.jsxs("span",{className:"summary-cancelled",children:[w.cancelled," cancelled"]})]}),E.length>0&&t.jsxs("div",{className:"agent-task-result-preview",title:E.join(" · "),children:[t.jsx("span",{children:"Result"}),E.join(" · ")]}),t.jsx("div",{className:"agent-target-chips","aria-label":"Target status overview",children:s.map((p,$)=>{const P=p.status==="completed"?"✓":p.status==="failed"?"×":p.status==="cancelled"?"!":p.status==="running"?"…":"·";return t.jsxs("span",{className:`agent-target-chip status-${p.status}`,title:`${p.deviceName}: ${ge(e,p)}`,"aria-label":`${$+1}. ${p.deviceName}: ${p.status}`,children:[t.jsx("b",{children:String($+1).padStart(2,"0")}),t.jsx("span",{children:P})]},p.deviceId)})}),s.length>0&&t.jsx("div",{className:"agent-task-details-toggle",children:t.jsxs("button",{type:"button",onClick:()=>j(p=>!p),"aria-expanded":v,children:[v?t.jsx(dt,{size:14}):t.jsx(He,{size:14}),v?"Hide details":"Show details"]})}),v&&t.jsxs("div",{className:"agent-task-details",children:[t.jsx("div",{className:"agent-task-filters",role:"tablist","aria-label":"Task result filter",children:["all","issues","running","completed","failed"].map(p=>t.jsx("button",{className:g===p?"active":"",onClick:()=>C(p),role:"tab","aria-selected":g===p,type:"button",children:p==="all"?"All":p==="issues"?"Issues only":p[0].toUpperCase()+p.slice(1)},p))}),t.jsx("div",{className:"agent-task-rows",children:x.length>0?x.map(p=>t.jsx(It,{operation:e,state:p},p.deviceId)):t.jsx("small",{className:"agent-task-no-results",children:"No targets match this filter."})})]}),(d||T)&&t.jsxs("div",{className:"agent-task-actions",children:[d&&a&&t.jsxs("button",{onClick:a,disabled:h,type:"button",children:[t.jsx(pt,{size:14})," Cancel"]}),!d&&T&&u&&t.jsxs("button",{onClick:u,disabled:h,type:"button",children:[t.jsx(gt,{size:14})," Retry failed"]})]})]})}function Ot(e){try{return JSON.stringify(e,null,2).slice(0,6e3)}catch{return"{}"}}function Et({approval:e,busy:s=!1,onApprove:n,onReject:a}){return t.jsxs("article",{className:"agent-approval-card","aria-label":"Agent approval required",children:[t.jsxs("div",{className:"agent-approval-head",children:[t.jsxs("div",{children:[t.jsx("span",{children:"Approval required"}),t.jsx("strong",{children:e.toolName})]}),t.jsx("span",{className:`agent-approval-risk risk-${e.risk}`,children:e.risk})]}),t.jsx("p",{children:e.description}),t.jsx("pre",{children:Ot(e.arguments)}),t.jsxs("small",{children:["Permission: ",e.permissionMode," · Scope: selected devices only · Expires in 5 minutes"]}),t.jsxs("div",{className:"agent-approval-actions",children:[t.jsxs("button",{className:"reject",disabled:s,onClick:a,type:"button",children:[t.jsx(Ce,{size:14})," Reject"]}),t.jsxs("button",{disabled:s,onClick:()=>n("once"),type:"button",children:[t.jsx(ee,{size:14})," Once"]}),t.jsx("button",{disabled:s,onClick:()=>n("same-action-this-run"),type:"button",children:"Allow same action"}),t.jsx("button",{disabled:s,onClick:()=>n("category-this-run"),type:"button",children:"Allow category"})]}),t.jsxs("div",{className:"agent-approval-scope",children:[t.jsx(je,{size:13})," Approval is bound to this run, tool, arguments, selected devices, and policy hash."]})]})}function $t(e){return e==="queued"?"Request queued":e==="checking-codex"?"Checking Codex":e==="preparing-tools"?"Preparing tools":e==="thinking"?"Preparing answer":e==="tool-running"?"Working on computers":e==="recovering"?"Retrying safely":e==="waiting-approval"?"Waiting for approval":"Working"}function Ft({items:e,onCancel:s,onRetry:n,busyBatchId:a,approvals:u,onApprove:h,onReject:d,busyApprovalId:v,progress:j,emptyTitle:g="Ask VuvoDesk to work across your machines.",emptyBody:C="Start with a read-only request such as “현재 대상에서 CPU와 메모리 상태를 확인해줘”."}){const w=c.useRef(null),R=c.useRef(!0),b=c.useRef(""),T=e[e.length-1];return c.useLayoutEffect(()=>{const k=w.current;k&&(T?.type==="user"&&T.id!==b.current&&(R.current=!0),b.current=T?.id||"",R.current&&(k.scrollTop=k.scrollHeight))},[u,e,T?.id,T?.type,j?.message,j?.stage]),t.jsxs("section",{className:"agents-conversation","aria-live":"polite",ref:w,onScroll:k=>{const x=k.currentTarget;R.current=x.scrollHeight-x.scrollTop-x.clientHeight<72},children:[u.filter(k=>k.status==="pending").map(k=>t.jsx(Et,{approval:k,busy:v===k.approvalId,onApprove:x=>h(k,x),onReject:()=>d(k)},k.approvalId)),e.length===0&&t.jsxs("div",{className:"agents-empty-conversation",children:[t.jsx("strong",{children:g}),t.jsx("span",{children:C})]}),e.map(k=>{if(k.type==="task"){const x=k;return t.jsx(Tt,{operation:x.operation,states:x.states,status:x.status,onCancel:()=>s(x.batchId,x.agentRunId),onRetry:()=>n(x.batchId),busy:a===x.batchId},x.id)}return t.jsxs("article",{className:`agents-message ${k.type}`,children:[t.jsx("span",{children:k.type==="user"?"You":"VuvoDesk Agent"}),t.jsx("p",{children:k.text})]},k.id)}),j&&t.jsxs("article",{className:"agents-message agent agents-progress-message",role:"status",children:[t.jsxs("span",{children:[t.jsx(xe,{"aria-hidden":"true",size:15}),$t(j.stage)]}),t.jsx("p",{children:j.message})]})]})}const ze=["Recommended","Health & capacity","Processes & services","Files & configuration","Software & automation","Network & connectivity","Power & maintenance","Troubleshooting & recovery"],A=["windows","macos","linux"],B={"system.health":{label:"system health",permissionCategory:"read",readOnly:!0,risk:"low",supportedPlatforms:A},"gpu.status":{label:"GPU status",permissionCategory:"read",readOnly:!0,risk:"low",supportedPlatforms:A},"disk.status":{label:"disk status",permissionCategory:"read",readOnly:!0,risk:"low",supportedPlatforms:A},"process.list":{label:"process inspection",permissionCategory:"read",readOnly:!0,risk:"low",supportedPlatforms:A},"service.status":{label:"service inspection",permissionCategory:"read",readOnly:!0,risk:"low",supportedPlatforms:A},"diagnostics.collect":{label:"diagnostics collection",permissionCategory:"read",readOnly:!0,risk:"low",supportedPlatforms:A},"process.control":{label:"process control",permissionCategory:"processControl",readOnly:!1,risk:"high",supportedPlatforms:A},"service.control":{label:"service control",permissionCategory:"serviceControl",readOnly:!1,risk:"high",supportedPlatforms:["windows","linux"]},"application.launch":{label:"application launch",permissionCategory:"applicationControl",readOnly:!1,risk:"medium",supportedPlatforms:A},"application.close":{label:"application close",permissionCategory:"applicationControl",readOnly:!1,risk:"medium",supportedPlatforms:A},"file.read":{label:"file reading",permissionCategory:"fileRead",readOnly:!0,risk:"low",supportedPlatforms:A},"file.write":{label:"file writing",permissionCategory:"fileWrite",readOnly:!1,risk:"high",supportedPlatforms:A},"file.delete":{label:"file deletion",permissionCategory:"fileDelete",readOnly:!1,risk:"critical",supportedPlatforms:A},"file.list":{label:"directory listing",permissionCategory:"fileRead",readOnly:!0,risk:"low",supportedPlatforms:A},"file.search":{label:"file name search",permissionCategory:"fileRead",readOnly:!0,risk:"low",supportedPlatforms:A},"directory.create":{label:"directory creation",permissionCategory:"fileWrite",readOnly:!1,risk:"medium",supportedPlatforms:A},"command.run":{label:"command execution",permissionCategory:"shell",readOnly:!1,risk:"critical",supportedPlatforms:A},"script.run":{label:"script execution",permissionCategory:"script",readOnly:!1,risk:"high",supportedPlatforms:A},"software.install":{label:"software installation",permissionCategory:"softwareInstall",readOnly:!1,risk:"high",supportedPlatforms:A},"network.status":{label:"network inspection",permissionCategory:"network",readOnly:!0,risk:"low",supportedPlatforms:A},"system.power":{label:"power control",permissionCategory:"systemPower",readOnly:!1,risk:"critical",supportedPlatforms:A},"system.configure":{label:"system configuration",permissionCategory:"systemConfiguration",readOnly:!1,risk:"critical",supportedPlatforms:A},"logs.collect":{label:"log collection",permissionCategory:"read",readOnly:!0,risk:"low",supportedPlatforms:A}};new Set(Object.keys(B));const Mt={Recommended:["recommended","overview","fleet","요약","추천"],"Health & capacity":["health","capacity","performance","상태","성능","용량"],"Processes & services":["process","service","application","프로세스","서비스","앱"],"Files & configuration":["file","config","directory","파일","설정","폴더"],"Software & automation":["software","install","automation","프로그램","설치","자동화"],"Network & connectivity":["network","connection","adapter","네트워크","연결","어댑터"],"Power & maintenance":["power","maintenance","restart","전원","유지보수","재시작"],"Troubleshooting & recovery":["troubleshooting","recovery","incident","문제해결","복구","장애"]},Ue=["low","medium","high","critical"];function Dt(e){return e.reduce((s,n)=>{const a=B[n].risk;return Ue.indexOf(a)>Ue.indexOf(s)?a:s},"low")}function qt(e){return A.filter(s=>e.every(n=>B[n].supportedPlatforms.includes(s)))}function o(e,s,n,a,u,h,d={}){const v=d.description||a,j=u.flatMap(C=>C.split(".")),g=[...new Set([...Mt[s],...h,...j])];return{id:e,category:s,title:n,prompt:a,description:v,requiredOperations:u,risk:d.risk||Dt(u),targetSupport:d.targetSupport||"single-or-multiple",supportedPlatforms:d.supportedPlatforms||qt(u),keywords:g,recommended:d.recommended??!1,enabled:!0}}const We=[o("recommended-fleet-health","Recommended","Summarize current target health","Summarize system health, GPU, and disk capacity for the current target Clients.",["system.health","gpu.status","disk.status"],["summary","overview"],{recommended:!0}),o("recommended-attention","Recommended","Find targets needing attention","Identify current targets with high resource use, low disk space, or service warnings.",["system.health","disk.status","service.status"],["attention","warning","monitor"],{recommended:!0}),o("recommended-performance-compare","Recommended","Compare selected performance","Compare CPU, memory, disk, and GPU capacity across the current targets.",["system.health","disk.status","gpu.status"],["compare","benchmark"],{recommended:!0}),o("recommended-gpu-vram","Recommended","Review GPU and VRAM availability","Show GPU temperature, utilization, and VRAM availability for the current targets.",["gpu.status"],["graphics","temperature","utilization"],{recommended:!0}),o("recommended-low-disk","Recommended","Locate low disk capacity","Find current targets with low free disk capacity and report the affected volumes.",["disk.status"],["storage","free space","capacity"],{recommended:!0}),o("recommended-process-services","Recommended","Review processes and services","Review running processes and service state for warnings on the current targets.",["process.list","service.status"],["process","service","warning"],{recommended:!0}),o("recommended-recover-application","Recommended","Recover a stopped application","Check a named application or service, relaunch its registered entry when stopped, and verify the result.",["process.list","application.launch","service.status"],["recover","start","application"],{targetSupport:"single",recommended:!0}),o("recommended-incident-diagnostics","Recommended","Collect an incident diagnostic bundle","Collect health, service, network, and recent log diagnostics for the current targets.",["diagnostics.collect","logs.collect","system.health","network.status"],["incident","report","evidence"],{recommended:!0}),o("health-cpu-memory","Health & capacity","Check high CPU and memory use","Find current targets with unusually high CPU or memory usage.",["system.health"],["cpu","memory","load","높은 사용량"]),o("health-uptime","Health & capacity","Review Client uptime","Show uptime, boot time, and current system health for the target Clients.",["system.health"],["uptime","boot","가동시간"]),o("health-gpu-temperature","Health & capacity","Check GPU temperature","Check GPU temperature and thermal warnings on the current targets.",["gpu.status"],["thermal","temperature","발열"]),o("health-vram-usage","Health & capacity","Check VRAM usage","Report GPU memory usage and remaining VRAM on the current targets.",["gpu.status"],["vram","gpu memory","video memory"]),o("health-low-disk","Health & capacity","Find low disk space","Find volumes below a safe free-space threshold on the current targets.",["disk.status"],["disk","storage","free space","디스크"]),o("health-gpu-compare","Health & capacity","Compare GPU capacity","Compare GPU model, memory, temperature, and utilization across the current targets.",["gpu.status"],["compare","graphics","capacity"]),o("health-system-warnings","Health & capacity","Collect system warnings","Review health, disk, and network status for warnings that need attention.",["system.health","disk.status","network.status"],["warnings","alerts","경고"]),o("health-capacity-report","Health & capacity","Build a capacity report","Create a concise capacity report covering CPU, memory, GPU, disk, and network status.",["system.health","gpu.status","disk.status","network.status"],["report","capacity","inventory"]),o("process-find-name","Processes & services","Find a running process by name","Find process named [process name] on the current targets.",["process.list"],["find","running","name","실행 중"]),o("process-resource-heavy","Processes & services","Find resource-heavy processes","List the processes using the most CPU or memory on the current targets.",["process.list","system.health"],["top","cpu","memory","resource"]),o("process-stop-named","Processes & services","Stop a named process","Stop process named [process name] on the target Client after checking its current state.",["process.list","process.control"],["stop","terminate","종료"],{targetSupport:"single"}),o("process-restart-named","Processes & services","Restart a named process","Check process named [process name] and restart it with its registered launch details when available.",["process.list","process.control"],["restart","relaunch","재시작"],{targetSupport:"single"}),o("process-launch-app","Processes & services","Launch a registered application","Launch the registered application [application] on the target Client with [arguments].",["application.launch"],["launch","open","실행"],{targetSupport:"single"}),o("process-close-app","Processes & services","Close an application","Close application [application] on the target Client and report whether it exited cleanly.",["application.close","process.list"],["close","exit","앱 종료"],{targetSupport:"single"}),o("service-status-name","Processes & services","Check a service status","Check service [service name] and report its state on the current targets.",["service.status"],["service","status","서비스 상태"]),o("service-restart-name","Processes & services","Restart a service safely","Check service [service name], stop it, wait for it to stop, then start it and verify the result.",["service.status","service.control"],["restart","start","stop","서비스 재시작"],{targetSupport:"single"}),o("files-list-directory","Files & configuration","List a directory","List files and folders under [path] on the target Client.",["file.list"],["directory","folder","list","목록"],{targetSupport:"single"}),o("files-search-name","Files & configuration","Search files by name","Search for files or folders containing [name] under [path] on the target Client.",["file.search"],["search","find","filename","파일 찾기"],{targetSupport:"single"}),o("files-create-directory","Files & configuration","Create a directory","Create directory [path] on the target Client and report the final path.",["directory.create"],["create","directory","folder","폴더 만들기"],{targetSupport:"single"}),o("files-read-config","Files & configuration","Read a configuration file","Read the relevant settings from configuration file [path] on the target Client.",["file.read"],["config","settings","read","구성"]),o("files-recent-logs","Files & configuration","Find recent log files","List recent log files under [path] and summarize the latest entries.",["file.list","file.read"],["logs","recent","tail"]),o("files-update-config","Files & configuration","Update a configuration value","Read configuration file [path], update [change], and report the exact change made.",["file.read","file.write"],["edit","update","설정 변경"],{targetSupport:"single"}),o("files-delete-temp","Files & configuration","Delete temporary files","Find temporary files under [path], delete only the requested matches, and report the freed space.",["file.list","file.delete","disk.status"],["cleanup","temp","delete","정리"],{targetSupport:"single"}),o("files-compare-config","Files & configuration","Compare configuration files","Read configuration file [path] on the target Client and compare it with [reference path].",["file.read"],["compare","diff","configuration"]),o("files-set-environment","Files & configuration","Set an environment variable","Set environment variable [name] to [value] for the target Client and verify the resulting configuration.",["system.configure","file.read"],["environment","variable","env","환경변수"],{targetSupport:"single"}),o("files-archive-diagnostics","Files & configuration","Write a diagnostic manifest","Collect selected diagnostics and write a manifest file to [path] on the target Client.",["diagnostics.collect","file.write"],["manifest","export","diagnostic file"],{targetSupport:"single"}),o("software-winget-install","Software & automation","Install software with winget","Install package [package name] with winget on the Windows target Client, then verify it.",["software.install","process.list"],["winget","windows","install","설치"],{targetSupport:"single",supportedPlatforms:["windows"]}),o("software-apt-install","Software & automation","Install software with apt","Install package [package name] with apt on the Linux target Client, then verify it.",["software.install","process.list"],["apt","linux","package","설치"],{targetSupport:"single",supportedPlatforms:["linux"]}),o("software-brew-install","Software & automation","Install software with Homebrew","Install package [package name] with brew on the macOS target Client, then verify it.",["software.install","process.list"],["brew","homebrew","macos","설치"],{targetSupport:"single",supportedPlatforms:["macos"]}),o("software-npm-install","Software & automation","Install an npm package","Install npm package [package name] on the target Client and verify the installed version.",["software.install","command.run"],["npm","node","package"],{targetSupport:"single"}),o("software-run-script","Software & automation","Run a registered script","Run the registered script [script path] on the target Client and report its result.",["script.run"],["script","automation","registered"],{targetSupport:"single"}),o("software-run-command","Software & automation","Run a shell command on one target","Run [command] with [PowerShell, cmd, bash, zsh, sh, or pwsh] on the target Client and return its exit status, duration, and output.",["command.run"],["command","powershell","shell","terminal"],{targetSupport:"single"}),o("software-verify-install","Software & automation","Verify an installed tool","Check whether [application] is installed, running, and available on the PATH of the current targets.",["process.list","system.health"],["verify","installed","path"]),o("software-toolchain-setup","Software & automation","Set up a toolchain","Install the requested package [package name], configure [change], and verify the toolchain on the target Client.",["software.install","system.configure","process.list"],["toolchain","setup","developer"],{targetSupport:"single"}),o("network-adapter-status","Network & connectivity","Check network adapters","Show adapter state, address, and link information for the current targets.",["network.status"],["adapter","ethernet","wifi","네트워크 상태"]),o("network-disconnected","Network & connectivity","Find disconnected targets","Find current targets with disconnected or degraded network adapters.",["network.status"],["disconnected","offline","연결 끊김"]),o("network-link-speed","Network & connectivity","Check link speed","Report network link speed and duplex information for the current targets.",["network.status"],["speed","bandwidth","duplex"]),o("network-warnings","Network & connectivity","Review network warnings","Review network status and recent logs for connectivity warnings on the current targets.",["network.status","logs.collect"],["warning","latency","packet loss"]),o("network-diagnostics","Network & connectivity","Collect network diagnostics","Collect network status, system diagnostics, and relevant logs for the current targets.",["network.status","diagnostics.collect","logs.collect"],["diagnostics","incident","connectivity"]),o("network-service-failures","Network & connectivity","Find network service failures","Check network status and relevant service states on the current targets.",["network.status","service.status"],["service","failure","dns"]),o("network-compare","Network & connectivity","Compare target connectivity","Compare adapter state, addresses, and link speed across the current targets.",["network.status"],["compare","inventory","connectivity"]),o("network-intermittent","Network & connectivity","Investigate intermittent connectivity","Investigate intermittent connectivity using network status, service state, and diagnostics evidence.",["network.status","service.status","diagnostics.collect"],["intermittent","unstable","recovery"]),o("power-lock","Power & maintenance","Lock the Client","Lock the target Client and report the resulting power action status.",["system.power"],["lock","security","잠금"],{targetSupport:"single",risk:"critical"}),o("power-logoff","Power & maintenance","Log off the Client","Log off the target Client after warning that interactive sessions will close.",["system.power"],["logoff","session","로그오프"],{targetSupport:"single",risk:"critical"}),o("power-sleep","Power & maintenance","Put the Client to sleep","Put the target Client to sleep after confirming the requested delay of [delay].",["system.power"],["sleep","suspend","절전"],{targetSupport:"single",risk:"critical"}),o("power-restart","Power & maintenance","Restart the Client","Restart the target Client after confirming that active work may be interrupted.",["system.power"],["restart","reboot","재부팅"],{targetSupport:"single",risk:"critical"}),o("power-shutdown","Power & maintenance","Shut down the Client","Shut down the target Client after confirming that active work may be interrupted.",["system.power"],["shutdown","power off","종료"],{targetSupport:"single",risk:"critical"}),o("power-maintenance-restart","Power & maintenance","Restart after maintenance","Check the target Client, restart it after maintenance, and verify that it returns online.",["system.health","system.power","network.status"],["maintenance","reboot","verify"],{targetSupport:"single",risk:"critical"}),o("power-timezone","Power & maintenance","Set the Client timezone","Set the target Client timezone to [timezone] and verify the resulting system configuration.",["system.configure"],["timezone","clock","시간대"],{targetSupport:"single",risk:"critical"}),o("power-persistent-environment","Power & maintenance","Persist an environment variable","Persist environment variable [name] with value [value] for the target Client and verify it.",["system.configure"],["environment","persistent","환경변수"],{targetSupport:"single",risk:"critical"}),o("recovery-app-wont-start","Troubleshooting & recovery","Investigate an app that will not start","Inspect [application], review its logs, launch the registered application, and verify the process.",["process.list","application.launch","logs.collect"],["app failure","start","실행 오류"],{targetSupport:"single"}),o("recovery-failed-service","Troubleshooting & recovery","Recover a failed service","Inspect service [service name], collect logs, restart it safely, and verify its running state.",["service.status","logs.collect","service.control"],["service failure","recover","서비스 복구"],{targetSupport:"single"}),o("recovery-repeated-process","Troubleshooting & recovery","Investigate a repeatedly stopping process","Inspect process [process name], collect diagnostics, stop stale instances, and relaunch the registered process.",["process.list","diagnostics.collect","process.control","application.launch"],["crash loop","process","반복 종료"],{targetSupport:"single"}),o("recovery-low-disk","Troubleshooting & recovery","Recover from low disk space","Inspect disk capacity, find temporary files, remove only the requested files, and verify free space.",["disk.status","file.list","file.delete"],["disk full","cleanup","저장공간 부족"],{targetSupport:"single"}),o("recovery-gpu-overheating","Troubleshooting & recovery","Investigate GPU overheating","Inspect GPU temperature and processes, then close the specified workload if it is causing the thermal warning.",["gpu.status","process.list","application.close"],["overheating","thermal","GPU 발열"],{targetSupport:"single"}),o("recovery-high-vram","Troubleshooting & recovery","Recover high VRAM usage","Inspect VRAM usage and GPU processes, then stop the specified stale workload if necessary.",["gpu.status","process.list","process.control"],["vram","memory pressure","VRAM 부족"],{targetSupport:"single"}),o("recovery-network-instability","Troubleshooting & recovery","Recover network instability","Collect network diagnostics, inspect network services, and report the safest recovery action for the target Client.",["network.status","service.status","diagnostics.collect"],["network","unstable","네트워크 복구"],{targetSupport:"single"}),o("recovery-incident-report","Troubleshooting & recovery","Create a full incident report","Create a full incident report from health, process, service, network, and log evidence for the current targets.",["system.health","process.list","service.status","network.status","logs.collect"],["incident","report","장애 보고서"])],ye={read:"allow",processControl:"allow",serviceControl:"allow",applicationControl:"ask",fileRead:"allow",fileWrite:"allow",fileDelete:"ask",shell:"ask",script:"ask",softwareInstall:"ask",network:"allow",systemPower:"ask",systemConfiguration:"ask",userAccount:"deny"};function zt(e,s){return e==="safe-auto"?ye:e==="full-access"?{...ye,processControl:"allow",serviceControl:"allow",applicationControl:"allow",fileDelete:"allow",shell:"allow",script:"allow",softwareInstall:"allow",systemPower:"allow",systemConfiguration:"allow"}:e==="custom"&&s?s:{...ye,processControl:"ask",serviceControl:"ask",applicationControl:"ask",fileWrite:"ask",network:"ask"}}function Ut(e,s,n){const a=zt(s,n),u=e.requiredOperations.map(h=>a[B[h].permissionCategory]);if(u.includes("deny")){const h=e.requiredOperations.find(d=>a[B[d].permissionCategory]==="deny");return{state:"blocked",label:"Blocked",reason:`This task requires ${B[h].label}, which is blocked by the current permission policy.`}}return u.includes("ask")?{state:"approval",label:"Approval required",reason:"This task requires approval before the requested changes can reach a Client."}:e.requiredOperations.every(h=>B[h].readOnly)?{state:"read-only",label:"Read only"}:s==="full-access"?{state:"full-access",label:"Full Access"}:{state:"auto",label:"Auto allowed"}}function Lt(e){const s=String(e||"").trim().toLowerCase();return s==="windows"||s==="win32"||s==="win32nt"?"windows":s==="macos"||s==="macosx"||s==="darwin"||s==="osx"?"macos":s==="linux"?"linux":null}function Bt(e,s,n){const a=new Set(n);return e.filter(u=>u.connected&&(s==="all"||s==="auto"||a.has(u.deviceId)))}function Gt(e,s){const n=Lt(e.platform);if(!n||!s.supportedPlatforms.includes(n))return!1;const a=e.capabilities?.agentTools;return!Array.isArray(a)||a.length===0?s.requiredOperations.every(u=>B[u].readOnly):s.requiredOperations.every(u=>a.includes(u))}function Je(e,s,n,a,u,h){const d=Ut(e,u,h),v=Bt(s,n,a),j=v.map(b=>b.deviceId),g={...d,available:!1,availableDeviceIds:[],unsupportedDeviceIds:j,risk:e.risk,supportedPlatforms:e.supportedPlatforms};if(v.length===0)return{...g,reason:"Select at least one connected Client."};if(e.targetSupport==="single"&&v.length!==1)return{...g,reason:"This task supports one Client at a time."};if(d.state==="blocked")return g;const C=v.filter(b=>Gt(b,e)),w=C.map(b=>b.deviceId),R=j.filter(b=>!w.includes(b));return C.length===0?{...g,unsupportedDeviceIds:R,reason:"No current target supports the required platform and client capabilities."}:{...g,available:!0,availableDeviceIds:w,unsupportedDeviceIds:R}}function Ht(e,s,n,a,u,h){return e.filter(d=>d.enabled&&Je(d,s,n,a,u,h).available).length}const ve="livedesk.agentPromptRecent",we="livedesk.agentPromptFavorites",_t={Recommended:V,"Health & capacity":Ct,"Processes & services":xt,"Files & configuration":bt,"Software & automation":kt,"Network & connectivity":wt,"Power & maintenance":_e,"Troubleshooting & recovery":vt};function Le(e){if(typeof window>"u")return[];try{const s=JSON.parse(window.localStorage.getItem(e)||"[]");return Array.isArray(s)?s.filter(n=>typeof n=="string"):[]}catch{return[]}}function ce(e,s){try{window.localStorage.setItem(e,JSON.stringify(s))}catch{}}function ke(e){return e==="all"?"All tasks":e==="recent"?"Recent":e==="favorites"?"Favorites":e==="read-only"?"Read only":e==="auto"?"Auto allowed":e==="approval"?"Approval required":e==="full-access"?"Full Access":e==="available"?"Available":e==="unavailable"?"Unavailable":e}function Vt(e){return e==="all"?"All":e==="recent"?"Recent":e==="favorites"?"Favorites":e==="read-only"?"Read only":e==="auto"?"Auto":e==="approval"?"Approval":e==="full-access"?"Full access":e==="available"?"Available":e==="unavailable"?"Unavailable":{Recommended:"Recommended","Health & capacity":"Health","Processes & services":"Processes","Files & configuration":"Files","Software & automation":"Software","Network & connectivity":"Network","Power & maintenance":"Power","Troubleshooting & recovery":"Recovery"}[e]}function Wt(e,s,n){if(!n.trim())return!0;const a=n.trim().toLowerCase();return[e.title,e.prompt,e.description,e.category,e.risk,s.label,...e.keywords,...e.requiredOperations,...e.supportedPlatforms].join(" ").toLowerCase().includes(a)}function Jt(e){return`permission-${e}`}function Kt(e){return e==="low"?"Low risk":e==="medium"?"Medium risk":e==="high"?"High risk":"Critical risk"}function Yt(e){return e==="windows"?"Windows":e==="macos"?"macOS":"Linux"}function Qt({devices:e,targetMode:s,selectedIds:n,permissionMode:a,customCategories:u,onSelectPrompt:h,onClose:d}){const[v,j]=c.useState(""),[g,C]=c.useState("all"),[w,R]=c.useState(()=>Le(ve)),[b,T]=c.useState(()=>Le(we)),[k,x]=c.useState(0),[q,E]=c.useState(""),p=c.useRef(null),$=c.useRef(null),P=c.useMemo(()=>We.filter(i=>i.enabled),[]),N=c.useMemo(()=>new Map(P.map(i=>[i.id,Je(i,e,s,n,a,u)])),[u,e,a,n,s,P]),G=c.useMemo(()=>[...N.values()].filter(i=>i.available).length,[N]),te=c.useMemo(()=>e.filter(i=>i.connected&&(s==="all"||s==="auto"||n.includes(i.deviceId))).length,[e,n,s]),F=c.useMemo(()=>{const i=P.filter(f=>Wt(f,N.get(f.id),v));return g==="recent"?w.map(f=>i.find(S=>S.id===f)).filter(f=>!!f):g==="favorites"?b.map(f=>i.find(S=>S.id===f)).filter(f=>!!f):g==="all"?i:i.filter(f=>{const S=N.get(f.id);return g==="read-only"?S.state==="read-only":g==="auto"?S.state==="auto":g==="approval"?S.state==="approval":g==="full-access"?S.state==="full-access":g==="available"?S.available:g==="unavailable"?!S.available:f.category===g})},[N,b,g,w,v,P]),me=c.useMemo(()=>g!=="all"?[{category:ke(g),templates:F}]:ze.map(i=>({category:i,templates:F.filter(f=>f.category===i)})).filter(i=>i.templates.length>0),[g,F]);c.useEffect(()=>{x(i=>Math.min(i,Math.max(0,F.length-1)))},[F.length]),c.useEffect(()=>{ce(ve,w)},[w]),c.useEffect(()=>{ce(we,b)},[b]),c.useEffect(()=>{$.current?.focus();const i=S=>{S.target instanceof Node&&!p.current?.contains(S.target)&&d()},f=S=>{S.key==="Escape"&&(S.preventDefault(),d())};return document.addEventListener("pointerdown",i),document.addEventListener("keydown",f),()=>{document.removeEventListener("pointerdown",i),document.removeEventListener("keydown",f)}},[d]);const se=i=>{const f=N.get(i.id);if(!f.available){E(f.reason||"This task is not available for the current targets and permission policy.");return}const S=[i.id,...w.filter(z=>z!==i.id)].slice(0,10);R(S),ce(ve,S),h(i.prompt),d()},Y=i=>{T(f=>{const S=f.includes(i)?f.filter(z=>z!==i):[i,...f];return ce(we,S),S})},fe=i=>{i.key==="ArrowDown"?(i.preventDefault(),x(f=>Math.min(f+1,Math.max(0,F.length-1)))):i.key==="ArrowUp"?(i.preventDefault(),x(f=>Math.max(f-1,0))):i.key==="Enter"&&F[k]&&(i.preventDefault(),se(F[k]))};let H=-1;return t.jsxs("section",{className:"agents-suggested-tasks",ref:p,"aria-label":"Suggested tasks",children:[t.jsxs("header",{className:"agents-suggested-header",children:[t.jsxs("div",{children:[t.jsxs("span",{className:"agents-suggested-title",children:[t.jsx(V,{size:15})," Suggested tasks"]}),t.jsxs("small",{children:[G," available · ",P.length," total. Choose a task, edit it, then run it."]})]}),t.jsx("button",{className:"agents-suggested-close",type:"button","aria-label":"Close suggested tasks",onClick:d,children:t.jsx(Ce,{size:16})})]}),t.jsxs("label",{className:"agents-suggested-search",children:[t.jsx(mt,{size:15,"aria-hidden":"true"}),t.jsx("input",{ref:$,value:v,onChange:i=>j(i.target.value),onKeyDown:fe,placeholder:"Search tasks...","aria-label":"Search suggested tasks"})]}),t.jsx("div",{className:"agents-suggested-filters","aria-label":"Task categories and availability filters",children:["all","recent","favorites","read-only","auto","approval","full-access","available","unavailable",...ze].map(i=>{const f=i==="recent"?ft:i==="favorites"?Me:i==="all"?V:i==="available"?ht:i==="unavailable"?yt:i==="read-only"||i==="auto"||i==="approval"||i==="full-access"?_e:_t[i];return t.jsxs("button",{className:g===i?"active":"",type:"button",title:ke(i),"aria-label":ke(i),"aria-pressed":g===i,onClick:()=>{C(i),x(0),E("")},children:[t.jsx(f,{size:12})," ",Vt(i)]},i)})}),q&&t.jsx("div",{className:"agents-suggested-notice",role:"status",children:q}),t.jsxs("div",{className:"agents-suggested-list",role:"listbox","aria-label":"Suggested tasks",children:[me.map(i=>t.jsxs("div",{className:"agents-suggested-group",children:[t.jsx("strong",{children:i.category}),i.templates.map(f=>{H+=1;const S=H===k,z=b.includes(f.id),M=N.get(f.id),W=M.availableDeviceIds.length+M.unsupportedDeviceIds.length||te,ne=M.available?`Available on ${M.availableDeviceIds.length} of ${W} target${W===1?"":"s"}`:`Unavailable: ${M.reason||"not supported by the current targets"}`;return t.jsxs("div",{className:`agents-suggested-item ${S?"active":""} ${M.available?"":"unavailable"}`,children:[t.jsxs("button",{className:"agents-suggested-prompt",type:"button",role:"option","aria-selected":S,"aria-disabled":!M.available,onClick:()=>se(f),children:[t.jsx("span",{children:f.title}),t.jsx("small",{className:"agents-suggested-description",children:f.description}),t.jsxs("span",{className:"agents-suggested-meta",children:[t.jsx("em",{children:f.category}),t.jsx("em",{className:Jt(M.state),children:M.label}),t.jsx("em",{className:`risk-${f.risk}`,children:Kt(f.risk)}),t.jsx("em",{children:f.supportedPlatforms.map(Yt).join(" · ")}),t.jsx("em",{className:M.available?"availability-ok":"availability-unavailable",children:ne}),M.available&&M.unsupportedDeviceIds.length>0&&t.jsxs("em",{className:"availability-warning",children:["Unsupported on ",M.unsupportedDeviceIds.length]})]})]}),t.jsx("button",{className:`agents-suggested-favorite ${z?"favorite":""}`,type:"button","aria-label":z?`Remove ${f.title} from favorites`:`Add ${f.title} to favorites`,"aria-pressed":z,onClick:()=>Y(f.id),children:t.jsx(Me,{size:14,fill:z?"currentColor":"none"})})]},f.id)})]},i.category)),F.length===0&&t.jsx("p",{className:"agents-suggested-empty",children:"No tasks match this search or current filter."})]})]})}function Xt({devices:e,mode:s,selectedIds:n,onModeChange:a,onToggle:u,permissionMode:h,onPermissionModeChange:d}){const v=e.filter(pe),j=n.filter(g=>v.some(C=>C.deviceId===g)).length;return t.jsxs("section",{className:"agents-target-picker","aria-label":"Agent targets",children:[t.jsxs("div",{className:"agents-target-toolbar",children:[t.jsx("span",{className:"agents-section-label",children:"Targets"}),t.jsxs("div",{className:"agents-target-modes",children:[t.jsxs("button",{className:s==="all"?"active":"",onClick:()=>a("all"),type:"button",children:[t.jsx(ue,{size:14})," All connected ",t.jsx("small",{children:v.length})]}),t.jsxs("button",{className:s==="selected"?"active":"",onClick:()=>a("selected"),type:"button",children:[t.jsx(ee,{size:14})," Selected ",j]}),t.jsxs("button",{className:s==="auto"?"active":"",onClick:()=>a("auto"),type:"button",children:[t.jsx(V,{size:14})," Auto"]}),t.jsxs("button",{type:"button",disabled:!0,title:"Saved Client groups are coming next.",children:[t.jsx(ue,{size:14})," Group ",t.jsx("small",{children:"Soon"})]})]}),t.jsxs("label",{className:`agents-permission-picker permission-${h}`,children:[t.jsx(je,{size:14}),t.jsx("span",{children:"Permission"}),t.jsxs("select",{value:h,onChange:g=>d(g.target.value),"aria-label":"Agent permission mode",children:[t.jsx("option",{value:"ask",children:"Ask"}),t.jsx("option",{value:"safe-auto",children:"Safe Auto"}),t.jsx("option",{value:"full-access",children:"Full Access"}),t.jsx("option",{value:"custom",children:"Custom"})]}),t.jsx(He,{size:13,"aria-hidden":"true"})]})]}),t.jsx("div",{className:"agents-target-list",children:e.length===0?t.jsx("span",{className:"agents-target-empty",children:"No Clients discovered."}):e.map(g=>{const C=pe(g),w=s==="all"||s==="auto"?C:n.includes(g.deviceId);return t.jsxs("label",{className:`agents-target-option ${w?"selected":""} ${C?"":"offline"}`,children:[t.jsx("input",{type:"checkbox",checked:w,disabled:!C||s!=="selected",onChange:()=>u(g.deviceId)}),t.jsx("span",{className:"agents-target-icon",children:t.jsx(Ve,{size:15})}),t.jsxs("span",{children:[t.jsx("strong",{children:de(g)}),t.jsx("small",{children:C?"Ready":g.connected?"Agent reconnecting":"Offline"})]}),w&&t.jsx(ee,{className:"agents-target-check",size:15,"aria-hidden":"true"})]},g.deviceId)})})]})}const Zt=800,Be=5e3;function es(){return typeof document>"u"||document.visibilityState==="visible"}function ts(e){return typeof document>"u"?()=>{}:(document.addEventListener("visibilitychange",e),()=>document.removeEventListener("visibilitychange",e))}function Ge({poll:e,onResult:s,onError:n,intervalMs:a=Zt,isVisible:u=es,subscribeVisibility:h=ts,setTimeoutImpl:d=globalThis.setTimeout.bind(globalThis),clearTimeoutImpl:v=globalThis.clearTimeout.bind(globalThis),createAbortController:j=()=>new AbortController}){if(typeof e!="function")throw new TypeError("Agent polling requires a poll function.");const g={current:null};let C=!0,w=0,R=null,b=null;const T=()=>{R!==null&&(v(R),R=null)},k=()=>{!C||!u()||R!==null||g.current||(R=d(()=>{R=null,x()},a))},x=()=>{if(!C||!u()||g.current)return g.current;const $=++w,P=j();b=P;const N=ot(g,()=>e(P.signal));return N.then(G=>{C&&$===w&&!P.signal.aborted&&s?.(G)},G=>{C&&$===w&&!P.signal.aborted&&n?.(G)}).finally(()=>{b===P&&(b=null),C&&u()&&k()}).catch(()=>{}),N},q=async()=>{if(!C)throw new Error("VuvoDesk Agent polling owner is closed.");T(),w+=1;const $=g.current;if(b&&!b.signal.aborted&&b.abort(new Error("VuvoDesk Agent polling was superseded by an explicit refresh.")),$)try{await $}catch{}if(!(!C||!u()))return T(),x()},p=h(()=>{if(T(),!u()){w+=1,b&&!b.signal.aborted&&b.abort(new Error("VuvoDesk Agent polling paused while hidden."));return}x()});return x(),{refresh:q,stop(){C&&(C=!1,w+=1,T(),p?.(),b&&!b.signal.aborted&&b.abort(new Error("VuvoDesk Agent polling owner closed.")))}}}async function ss(e,s){return U("/api/settings/agent/run",{method:"POST",body:JSON.stringify(s)},e)}async function ns(e,s,n={}){return U(`/api/settings/agent/runs/${encodeURIComponent(s)}`,n,e)}async function rs(e,s){return U(`/api/settings/agent/runs/${encodeURIComponent(s)}/cancel`,{method:"POST",body:JSON.stringify({})},e)}async function as(e){return U("/api/settings/agent/runs/cancel-all",{method:"POST",body:JSON.stringify({})},e)}async function is(e,s,n,a){return U(`/api/settings/agent/runs/${encodeURIComponent(s)}/approvals/${encodeURIComponent(n)}/approve`,{method:"POST",body:JSON.stringify({scope:a})},e)}async function os(e,s,n,a="User rejected this action."){return U(`/api/settings/agent/runs/${encodeURIComponent(s)}/approvals/${encodeURIComponent(n)}/reject`,{method:"POST",body:JSON.stringify({reason:a})},e)}async function ls(e,s,n){return U(`/api/settings/agent/policies/${encodeURIComponent(s)}`,{method:"PUT",body:JSON.stringify({categories:n})},e)}async function cs(e,s,n={}){return U(`/api/remote/tasks/${encodeURIComponent(s)}`,n,e)}async function us(e,s){return U(`/api/remote/tasks/${encodeURIComponent(s)}/cancel`,{method:"POST",body:JSON.stringify({})},e)}async function ds(e,s){return U(`/api/remote/tasks/${encodeURIComponent(s)}/retry`,{method:"POST",body:JSON.stringify({failedOnly:!0})},e)}function Z(e){return`${e}-${Date.now()}-${Math.random().toString(36).slice(2,8)}`}function be(e,s){const n=new Map(s.map(a=>[a.deviceId,de(a)]));return e.results.map(a=>({deviceId:a.deviceId,deviceName:a.deviceName||n.get(a.deviceId)||a.deviceId,status:At(a.status),stage:a.stage||(a.status==="running"?"Checking processes":void 0),result:a.result,data:a.data,error:a.error,sequence:Number.isSafeInteger(a.sequence)?a.sequence:0}))}function ps(e,s){const n=new Map(s.map(a=>[a.deviceId,a]));return e.map(a=>{const u=n.get(a.deviceId);return!u||u.sequence<=a.sequence?a:u})}const gs={read:"allow",processControl:"ask",serviceControl:"ask",applicationControl:"ask",fileRead:"ask",fileWrite:"ask",fileDelete:"ask",shell:"ask",script:"ask",softwareInstall:"ask",network:"ask",systemPower:"ask",systemConfiguration:"ask",userAccount:"deny"};function ms(e){return e==="safe-auto"?"Safe Auto":e==="full-access"?"Full Access":e==="custom"?"Custom":"Ask"}function fs(e){return e.replace(/([A-Z])/g," $1").replace(/^./,s=>s.toUpperCase())}function hs(e){const s=e instanceof Error?e.message:String(e);return/agent-disabled/i.test(s)?"Enable Codex Agent in Settings before running commands.":/agent-no-target-devices|agent-target-not-connected|device-not-connected/i.test(s)?"The selected Client is reconnecting. Wait until its Agent status is Ready and try again.":/codex-auth-required/i.test(s)?"Codex sign-in is required on the Hub. Open Settings > Agent and test the Codex connection.":s}function ks({hubUrl:e,devices:s,launchRequest:n,variant:a="page",selectedDeviceIds:u=[]}){const h=a==="dock",[d,v]=c.useState(h?u.length>0?"selected":"auto":"all"),[j,g]=c.useState(u),[C,w]=c.useState("auto"),[R,b]=c.useState(""),[T,k]=c.useState([]),[x,q]=c.useState(""),[E,p]=c.useState(""),[$,P]=c.useState(""),[N,G]=c.useState("safe-auto"),[te]=c.useState("custom-default"),[F,me]=c.useState(gs),[se,Y]=c.useState([]),[fe,H]=c.useState(""),[i,f]=c.useState(!1),[S,z]=c.useState(null),[M,W]=c.useState(!1),[ne,L]=c.useState(""),[Se,Q]=c.useState(!1),[Ae,X]=c.useState(null),re=c.useRef(null),J=c.useRef(null),ae=c.useRef(null),Re=c.useRef(new Set),Pe=c.useRef(new Set),he=c.useMemo(()=>s.filter(pe).map(r=>r.deviceId),[s]),Ke=c.useMemo(()=>Ht(We,s,d,j,N,F),[F,s,N,j,d]);c.useEffect(()=>{h&&g(u)},[h,u]),c.useEffect(()=>{n?.deviceId&&(v("selected"),g([n.deviceId]),b(n.instruction),Q(!1),window.requestAnimationFrame(()=>{re.current?.focus(),re.current?.setSelectionRange(n.instruction.length,n.instruction.length)}))},[n]);const K=c.useCallback(r=>{const l=be(r,s);k(y=>y.map(m=>m.type==="task"&&m.batchId===r.batchId?{...m,states:ps(m.states,l),status:r.status}:m)),["running","queued"].includes(r.status)||q(y=>y===r.batchId?"":y)},[s]),Ne=c.useCallback((r,l)=>{Pe.current.has(r.batchId)||(Pe.current.add(r.batchId),k(y=>[...y,{type:"task",id:Z("task"),batchId:r.batchId,agentRunId:l,operation:r.operation||"diagnostics.collect",instruction:r.instructionPreview,states:be(r,s),status:r.status}])),K(r)},[s,K]),Ie=c.useCallback((r,l)=>{for(const m of l.taskBatches||[])Ne(m,r);Y(l.approvals||[]);const y=["running","queued","waiting-approval"].includes(l.status);if(X(y?{runId:r,stage:l.stage||l.status,message:l.progressMessage||(l.status==="waiting-approval"?"Review the requested action to continue.":"Codex is preparing the answer.")}:m=>m?.runId===r?null:m),!y&&!Re.current.has(r)){Re.current.add(r);const m=[l.error,l.errorMessage].filter(Boolean).join(" — "),I=l.finalResponse?.trim()||(l.status==="cancelled"?"Codex 작업을 취소했습니다.":m?`Codex 작업이 완료되지 않았습니다: ${m}`:"Codex 작업이 완료되었습니다.");k($e=>[...$e,{type:l.status==="failed"?"error":"agent",id:Z("agent-run-result"),text:I}])}},[Ne]),Te=c.useCallback(async r=>{const l=J.current;if(!(!l||l.id!==r))try{return await l.owner.refresh()}catch(y){if(J.current!==l)return;throw y}},[]);c.useEffect(()=>{if(!E){J.current=null;return}const r=E,l=Ge({poll:m=>ns(e,r,{signal:m,timeoutMs:Be}),onResult:m=>{Ie(r,m),["running","queued","waiting-approval"].includes(m.status)||(p(I=>I===r?"":I),W(!1))},onError:m=>{L(m instanceof Error?m.message:String(m))}}),y={id:r,owner:l};return J.current=y,()=>{l.stop(),J.current===y&&(J.current=null)}},[E,e,Ie]),c.useEffect(()=>{if(!x){ae.current=null;return}const r=x,l=Ge({poll:m=>cs(e,r,{signal:m,timeoutMs:Be}),onResult:m=>{K(m),["running","queued"].includes(m.status)||q(I=>I===r?"":I)},onError:m=>{L(m instanceof Error?m.message:String(m))}}),y={id:r,owner:l};return ae.current=y,()=>{l.stop(),ae.current===y&&(ae.current=null)}},[x,e,K]);const Oe=async(r="",l,y=!1)=>{const m=(r||R).trim();if(!m||x||E)return;const I=l||(d==="all"||d==="auto"?he:j.filter(O=>he.includes(O)));if(I.length===0){L("Select at least one connected Client.");return}if(N==="full-access"&&!M&&!y){z({instruction:m,targetIds:I});return}if(k(O=>[...O,{type:"user",id:Z("user"),text:m}]),b(""),Q(!1),L(""),I.length===0){k(O=>[...O,{type:"error",id:Z("no-targets"),text:"연결된 대상 장비를 하나 이상 선택해 주세요."}]);return}const Fe=C==="ask"?`Read-only request. Inspect and answer without changing Client state.
|
|
2
2
|
|
|
3
3
|
${m}`:C==="plan"?`Plan only. Produce a safe execution plan, but do not change Client state.
|
|
4
4
|
|