livedesk 0.1.657 → 0.1.658

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/package.json +1 -1
  2. package/web/dist/app.html +5 -11
  3. package/web/dist/app.webmanifest +1 -1
  4. package/web/dist/assets/AgentSettingsTab-8WnOGkVa.js +1 -0
  5. package/web/dist/assets/{AgentsPage-DcUy7xPU.js → AgentsPage-CCO7AwAO.js} +6 -6
  6. package/web/dist/assets/CaptureGallery-7NXD-vaQ.js +1 -0
  7. package/web/dist/assets/DesktopUpdatePanel-CiGXFhqj.js +1 -0
  8. package/web/dist/assets/{App-ARrqCA9B.js → HubApp-AhKLyz3K.js} +13 -13
  9. package/web/dist/assets/MonitorStackIcon-DBuXI_Oa.js +8 -0
  10. package/web/dist/assets/SettingsPage-DnOdy3MQ.js +1 -0
  11. package/web/dist/assets/SettingsTabs-DfjoCvK4.js +1 -0
  12. package/web/dist/assets/{ShareFilesPage-C9vhKzGp.js → ShareFilesPage-C3Jv7EII.js} +3 -3
  13. package/web/dist/assets/SupportPage-B16Jl8Jq.js +2 -0
  14. package/web/dist/assets/VuvoDeskApp-CU4N6t3c.js +1 -0
  15. package/web/dist/assets/app--miKlon3.js +2 -0
  16. package/web/dist/assets/client-8jUbxy3j.js +1 -0
  17. package/web/dist/assets/icons-CuXJn-Hz.js +1 -0
  18. package/web/dist/assets/main-DVNv6hc-.js +2 -0
  19. package/web/dist/assets/preload-helper-DD1OZmLC.js +1 -0
  20. package/web/dist/assets/pwa-bootstrap-BCid3CYk.js +1 -0
  21. package/web/dist/assets/pwa-startup-xxamnV7P.js +1 -0
  22. package/web/dist/assets/react-rvm9rmed.js +9 -0
  23. package/web/dist/index.html +11 -7
  24. package/web/dist/sw.js +14 -4
  25. package/web/dist/vuvodesk-build-evidence.json +89 -69
  26. package/web/dist/assets/AgentSettingsTab-CU3kHssT.js +0 -1
  27. package/web/dist/assets/CaptureGallery-BPKKxPej.js +0 -1
  28. package/web/dist/assets/DesktopUpdatePanel-C5wDB5zf.js +0 -1
  29. package/web/dist/assets/SettingsPage-ChNfBaQo.js +0 -1
  30. package/web/dist/assets/SettingsTabs-B-uMhvwn.js +0 -1
  31. package/web/dist/assets/SupportPage-C-uQ-RTX.js +0 -2
  32. package/web/dist/assets/VuvoDeskApp-BeeOb_MQ.js +0 -1
  33. package/web/dist/assets/app-DhbXrOFp.js +0 -1
  34. package/web/dist/assets/icons-CacEbnZu.js +0 -1
  35. package/web/dist/assets/main-BTb7f--C.js +0 -2
  36. package/web/dist/assets/react-Cfedt3N5.js +0 -1
  37. package/web/dist/assets/styles-eZ2IzXEL.js +0 -16
  38. /package/web/dist/assets/{App-DFLBNvIi.css → HubApp-DFLBNvIi.css} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "livedesk",
3
- "version": "0.1.657",
3
+ "version": "0.1.658",
4
4
  "livedeskClientVersion": "0.1.271",
5
5
  "buildFlavor": "production",
6
6
  "description": "VuvoDesk Hub and client launcher",
package/web/dist/app.html CHANGED
@@ -52,22 +52,16 @@
52
52
  .vuvodesk-static-boot [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-DhbXrOFp.js" data-vuvodesk-entry></script>
56
- <link rel="modulepreload" crossorigin href="/assets/icons-CacEbnZu.js">
57
- <link rel="modulepreload" crossorigin href="/assets/react-Cfedt3N5.js">
58
- <link rel="modulepreload" crossorigin href="/assets/styles-eZ2IzXEL.js">
59
- <link rel="modulepreload" crossorigin href="/assets/supabase-C7qjtLN3.js">
60
- <link rel="modulepreload" crossorigin href="/assets/frame-lifecycle-esOdP-EY.js">
61
- <link rel="modulepreload" crossorigin href="/assets/App-ARrqCA9B.js">
62
- <link rel="stylesheet" crossorigin href="/assets/styles-DDKP4MTD.css">
63
- <link rel="stylesheet" crossorigin href="/assets/App-DFLBNvIi.css">
55
+ <script type="module" crossorigin src="/assets/app--miKlon3.js" data-vuvodesk-entry></script>
56
+ <link rel="modulepreload" crossorigin href="/assets/preload-helper-DD1OZmLC.js">
57
+ <link rel="modulepreload" crossorigin href="/assets/pwa-bootstrap-BCid3CYk.js">
64
58
  </head>
65
59
  <body>
66
60
  <div id="root">
67
61
  <main class="vuvodesk-static-boot" data-vuvodesk-static-boot aria-label="Starting VuvoDesk" aria-busy="true">
68
62
  <span class="vuvodesk-static-boot-mark" aria-hidden="true"></span>
69
- <strong data-vuvodesk-static-boot-title hidden></strong>
70
- <p data-vuvodesk-static-boot-detail hidden></p>
63
+ <strong data-vuvodesk-static-boot-title>VuvoDesk</strong>
64
+ <p data-vuvodesk-static-boot-detail>Opening your workspace...</p>
71
65
  <button type="button" data-vuvodesk-static-boot-retry hidden>Try again</button>
72
66
  </main>
73
67
  </div>
@@ -4,7 +4,7 @@
4
4
  "short_name": "VuvoDesk",
5
5
  "description": "Monitor and control your VuvoDesk computers from your phone.",
6
6
  "lang": "en",
7
- "start_url": "/app?pwa=0.1.657",
7
+ "start_url": "/app?pwa=0.1.658",
8
8
  "scope": "/",
9
9
  "display": "standalone",
10
10
  "orientation": "any",
@@ -0,0 +1 @@
1
+ import{j as t}from"./pwa-startup-xxamnV7P.js";import{r as c,d as A,S as q,T as I,e as z}from"./icons-CuXJn-Hz.js";import{h as x}from"./MonitorStackIcon-DBuXI_Oa.js";import"./pwa-bootstrap-BCid3CYk.js";const E={enabled:!0};function w(i){return{enabled:i?.enabled===!0}}async function L(i,p,f){let l=null;for(let s=0;s<2;s+=1){const g=await x("/api/settings",{signal:f},p);if(g.settings.agent?.enabled===i)return;try{await x("/api/settings",{method:"PATCH",signal:f,body:JSON.stringify({revision:g.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 H({hubUrl:i,showToast:p}){const[f,l]=c.useState(E),[s,g]=c.useState(null),[a,m]=c.useState(""),[j,v]=c.useState(""),[y,d]=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 h=++b.current;return g(null),l(E),m(""),d(""),v(""),x("/api/settings/agent",{signal:n.signal},i).then(o=>{!e||n.signal.aborted||h!==b.current||(g(o.settings),l(w(o.settings)))}).catch(o=>{e&&!n.signal.aborted&&h===b.current&&d(o instanceof Error?o.message:String(o))}),()=>{e=!1,n.abort(),u.current===n&&(u.current=null)}},[i]);const k=(e,n)=>l(h=>({...h,[e]:n})),C=e=>{g(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){d("Agent settings are not available yet.");return}const e=S();if(r(e)){m("save"),d(""),v("");try{if(await L(f.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)&&d(n instanceof Error?n.message:String(n))}finally{r(e)&&m("")}}},T=async()=>{const e=S();if(r(e)){m("test"),d(""),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 h=await x("/api/settings/agent",{signal:e.controller.signal},i);if(!r(e))return;C(h.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)&&d(n instanceof Error?n.message:String(n))}finally{r(e)&&m("")}}},D=s?.codexInstallation==="installed"&&s.codexAuth==="signed-in",N=s!==null;return t.jsxs("div",{className:"settings-tab-content agent-settings-content",children:[t.jsxs("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:f.enabled,onChange:e=>k("enabled",e.target.checked),disabled:!N||a!==""}),t.jsx("span",{children:"Enable Codex Agent"})]}),t.jsxs("p",{className:"settings-help",children:[t.jsx(A,{size:12})," Enabled by default. Agent commands use only the Codex account signed in on this Hub."]})]}),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(q,{size:20})]}),t.jsxs("div",{className:"agent-connection-row",children:[t.jsx("span",{className:`agent-connection-dot ${D?"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:()=>{T()},disabled:a!=="",type:"button",children:[t.jsx(I,{size:15})," ",a==="test"?"Testing":"Test connection"]})]}),t.jsxs("p",{className:"settings-help",children:[t.jsx(A,{size:12})," The Hub uses the installed Codex SDK / CLI to plan approved commands and run them through VuvoDesk Agent tools on selected computers. VuvoDesk never asks for separate credentials."]})]}),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(z,{size:15})," ",a==="save"?"Saving":"Save Agent settings"]})})]})}export{H as AgentSettingsTab};
@@ -1,9 +1,9 @@
1
- import{j as t,e as ht,h as F}from"./styles-eZ2IzXEL.js";import{a as d,m as yt,n as Ce,o as vt,l as ee,X as xe,p as wt,q as kt,s as Je,B as bt,t as Ct,u as Se,S as H,v as xt,w as St,x as _e,b as jt,y as At,k as Ze,z as Rt,N as Nt,F as Pt,H as It,I as Tt,J as Et,U as ue,c as Xe}from"./icons-CacEbnZu.js";import"./react-Cfedt3N5.js";const Ot=d.forwardRef(function({value:s,onChange:n,onSubmit:r,onOpenSuggestedTasks:i,suggestedOpen:f=!1,suggestedTaskCount:c,disabled:v=!1,placeholder:S="Ask VuvoDesk to work across your machines...",compact:g=!1},x){return t.jsxs("form",{className:"agents-composer",onSubmit:w=>{w.preventDefault(),r()},children:[t.jsx("button",{className:`agents-suggested-trigger ${f?"active":""}`,type:"button","aria-label":c===void 0?"Open Suggested tasks":`Open Suggested tasks (${c} available)`,"aria-expanded":f,onClick:i,disabled:v,children:t.jsx(yt,{size:17})}),t.jsx("textarea",{ref:x,value:s,onChange:w=>n(w.target.value.slice(0,4e3)),placeholder:S,"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(Ce,{className:"spin",size:16}):t.jsx(vt,{size:16}),v?"Running":"Run"]})]})}),$t=["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 Dt(e){return e==="running"||e==="completed"||e==="failed"||e==="cancelled"?e:"queued"}function _t(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"}}const zt=64*1024,ze="[Earlier log output hidden by PWA display limit.]",Qe=new TextEncoder,Mt=new TextDecoder("utf-8",{fatal:!0}),Me=16*1024,Lt=200,Le="(?:access[_-]?(?:token|key)|refresh[_-]?token|id[_-]?token|pair[_-]?(?:token|key)|authorization|api[_-]?key|private[_-]?key|connection[_-]?string|credential|password|passwd|secret|cookie|set-cookie)",Ft="(?:access[_-]?(?:token|key)|refresh[_-]?token|id[_-]?token|pair[_-]?(?:token|key)|token|authorization|api[_-]?key|private[_-]?key|connection[_-]?string|credential|password|passwd|secret|cookie|set-cookie)",Bt="(?:access[_-]?(?:token|key)|refresh[_-]?token|id[_-]?token|pair[_-]?(?:token|key)|token|authorization|api[_-]?key|credential|password|secret|cookie)",Ut=/\b(?:sk-(?:proj-|ant-)?[A-Za-z0-9_-]{8,}|gh[pousr]_[A-Za-z0-9]{8,}|github_pat_[A-Za-z0-9_]{8,}|(?:AKIA|ASIA)[A-Z0-9]{16}|AIza[A-Za-z0-9_-]{35}|npm_[A-Za-z0-9]{8,}|xox[a-z]-[A-Za-z0-9-]{8,}|(?:sk|rk)_(?:live|test)_[A-Za-z0-9]{8,})\b/g;function qt(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:null}function Fe(e){return Qe.encode(e).byteLength}function Be(e,s){const n=Qe.encode(e);if(n.byteLength<=s)return{value:e,truncated:!1};let r=n.byteLength-s;for(;r<n.byteLength&&(n[r]&192)===128;)r+=1;let i=Mt.decode(n.subarray(r));const f=i.indexOf(`
2
- `);return f>=0&&f<i.length-1&&(i=i.slice(f+1)),{value:i,truncated:!0}}function et(e){return e.replace(/-----BEGIN [^-\r\n]*PRIVATE KEY-----[\s\S]*?-----END [^-\r\n]*PRIVATE KEY-----/gi,"[REDACTED PRIVATE KEY]").replace(/\b(?:proxy-)?authorization\s*[:=]\s*[^\r\n]*|\b(?:set-)?cookie\s*[:=]\s*[^\r\n]*/gi,"credential-header=[REDACTED]").replace(/\bBearer\s+(?:"[^"]*"|'[^']*'|[^\s,;]+)/gi,"Bearer [REDACTED]").replace(new RegExp(`("${Le}"\\s*:\\s*")[^"\\r\\n]*(")`,"gi"),"$1[REDACTED]$2").replace(new RegExp(`('${Le}'\\s*:\\s*')[^'\\r\\n]*(')`,"gi"),"$1[REDACTED]$2").replace(new RegExp(`((?:[A-Za-z0-9.-]+[_-])?${Ft}\\s*[:=]\\s*)(?!\\[REDACTED\\])[^\\s,;&]+`,"gi"),"$1[REDACTED]").replace(new RegExp(`([?&]${Bt}=)[^&\\s]+`,"gi"),"$1[REDACTED]").replace(/\b(?:eyJ|[A-Za-z0-9_-]{8,}\.)[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g,"[REDACTED TOKEN]").replace(Ut,"[REDACTED KEY]")}function Gt(e){return typeof e!="string"?"source unknown":et(e).replace(/[\u0000-\u001f\u007f]/g," ").trim().slice(0,64)||"source unknown"}function Ue(e){return typeof e=="number"&&Number.isSafeInteger(e)&&e>=0?Math.floor(e):null}function Vt(e){if(typeof e!="string"||e.length===0)return{output:"",displayTruncated:!1};const s=Be(e.replace(/\r\n?/g,`
3
- `),zt);let n=et(s.value).replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/g," ").trim(),r=s.truncated;const i=n?n.split(`
1
+ import{j as t}from"./pwa-startup-xxamnV7P.js";import{r as d,ae as ht,af as Ce,z as yt,G as ee,X as xe,ag as vt,ah as wt,ai as Ze,aj as kt,ak as bt,al as Se,b as H,am as Ct,p as xt,an as _e,o as St,ao as jt,S as Je,ap as At,a9 as Rt,c as Nt,aq as Pt,ar as It,A as Tt,as as ue,M as Xe}from"./icons-CuXJn-Hz.js";import{r as Et,h as F}from"./MonitorStackIcon-DBuXI_Oa.js";import"./pwa-bootstrap-BCid3CYk.js";const Ot=d.forwardRef(function({value:s,onChange:n,onSubmit:r,onOpenSuggestedTasks:i,suggestedOpen:f=!1,suggestedTaskCount:c,disabled:v=!1,placeholder:S="Ask VuvoDesk to work across your machines...",compact:g=!1},x){return t.jsxs("form",{className:"agents-composer",onSubmit:w=>{w.preventDefault(),r()},children:[t.jsx("button",{className:`agents-suggested-trigger ${f?"active":""}`,type:"button","aria-label":c===void 0?"Open Suggested tasks":`Open Suggested tasks (${c} available)`,"aria-expanded":f,onClick:i,disabled:v,children:t.jsx(ht,{size:17})}),t.jsx("textarea",{ref:x,value:s,onChange:w=>n(w.target.value.slice(0,4e3)),placeholder:S,"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(Ce,{className:"spin",size:16}):t.jsx(yt,{size:16}),v?"Running":"Run"]})]})}),$t=["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 Dt(e){return e==="running"||e==="completed"||e==="failed"||e==="cancelled"?e:"queued"}function _t(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"}}const Mt=64*1024,Me="[Earlier log output hidden by PWA display limit.]",Qe=new TextEncoder,zt=new TextDecoder("utf-8",{fatal:!0}),ze=16*1024,Lt=200,Le="(?:access[_-]?(?:token|key)|refresh[_-]?token|id[_-]?token|pair[_-]?(?:token|key)|authorization|api[_-]?key|private[_-]?key|connection[_-]?string|credential|password|passwd|secret|cookie|set-cookie)",Ft="(?:access[_-]?(?:token|key)|refresh[_-]?token|id[_-]?token|pair[_-]?(?:token|key)|token|authorization|api[_-]?key|private[_-]?key|connection[_-]?string|credential|password|passwd|secret|cookie|set-cookie)",Bt="(?:access[_-]?(?:token|key)|refresh[_-]?token|id[_-]?token|pair[_-]?(?:token|key)|token|authorization|api[_-]?key|credential|password|secret|cookie)",qt=/\b(?:sk-(?:proj-|ant-)?[A-Za-z0-9_-]{8,}|gh[pousr]_[A-Za-z0-9]{8,}|github_pat_[A-Za-z0-9_]{8,}|(?:AKIA|ASIA)[A-Z0-9]{16}|AIza[A-Za-z0-9_-]{35}|npm_[A-Za-z0-9]{8,}|xox[a-z]-[A-Za-z0-9-]{8,}|(?:sk|rk)_(?:live|test)_[A-Za-z0-9]{8,})\b/g;function Ut(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:null}function Fe(e){return Qe.encode(e).byteLength}function Be(e,s){const n=Qe.encode(e);if(n.byteLength<=s)return{value:e,truncated:!1};let r=n.byteLength-s;for(;r<n.byteLength&&(n[r]&192)===128;)r+=1;let i=zt.decode(n.subarray(r));const f=i.indexOf(`
2
+ `);return f>=0&&f<i.length-1&&(i=i.slice(f+1)),{value:i,truncated:!0}}function et(e){return e.replace(/-----BEGIN [^-\r\n]*PRIVATE KEY-----[\s\S]*?-----END [^-\r\n]*PRIVATE KEY-----/gi,"[REDACTED PRIVATE KEY]").replace(/\b(?:proxy-)?authorization\s*[:=]\s*[^\r\n]*|\b(?:set-)?cookie\s*[:=]\s*[^\r\n]*/gi,"credential-header=[REDACTED]").replace(/\bBearer\s+(?:"[^"]*"|'[^']*'|[^\s,;]+)/gi,"Bearer [REDACTED]").replace(new RegExp(`("${Le}"\\s*:\\s*")[^"\\r\\n]*(")`,"gi"),"$1[REDACTED]$2").replace(new RegExp(`('${Le}'\\s*:\\s*')[^'\\r\\n]*(')`,"gi"),"$1[REDACTED]$2").replace(new RegExp(`((?:[A-Za-z0-9.-]+[_-])?${Ft}\\s*[:=]\\s*)(?!\\[REDACTED\\])[^\\s,;&]+`,"gi"),"$1[REDACTED]").replace(new RegExp(`([?&]${Bt}=)[^&\\s]+`,"gi"),"$1[REDACTED]").replace(/\b(?:eyJ|[A-Za-z0-9_-]{8,}\.)[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g,"[REDACTED TOKEN]").replace(qt,"[REDACTED KEY]")}function Gt(e){return typeof e!="string"?"source unknown":et(e).replace(/[\u0000-\u001f\u007f]/g," ").trim().slice(0,64)||"source unknown"}function qe(e){return typeof e=="number"&&Number.isSafeInteger(e)&&e>=0?Math.floor(e):null}function Vt(e){if(typeof e!="string"||e.length===0)return{output:"",displayTruncated:!1};const s=Be(e.replace(/\r\n?/g,`
3
+ `),Mt);let n=et(s.value).replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/g," ").trim(),r=s.truncated;const i=n?n.split(`
4
4
  `):[];if(i.length>Lt-1&&(n=i.slice(-199).join(`
5
- `),r=!0),r||=Fe(n)>Me,r){const f=Fe(ze),c=Math.max(0,Me-f-1);n=Be(n,c).value,n=`${ze}${n?`
6
- ${n}`:""}`}return{output:n,displayTruncated:r}}function tt(e){const s=qt(e);if(!s)return null;const n=Vt(s.output),r=Ue(s.returnedCount)??Ue(s.returnedLines),i=typeof s.truncated=="boolean"?s.truncated:null,f=Gt(s.source),c=r===null?"line count unknown":`${r} line${r===1?"":"s"} returned`,S=[f,c,i===!0?"source truncated":i===!1?"source complete":"source truncation unknown",n.displayTruncated?"display limited":""].filter(Boolean).join(" · ");return{source:f,returnedCount:r,truncated:i,output:n.output,displayTruncated:n.displayTruncated,summary:S}}function Ht(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:null}function z(e){return typeof e=="number"&&Number.isFinite(e)?e:null}function le(e){const s=z(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 qe(e){const s=z(e);return s===null?"":`${Math.round((s<=1?s:s/100)*100)}%`}function Wt(e){return!e||/^(?:[\w .-]+ )?collected(?:\.)?$/i.test(e.trim())?"":e.trim()}function ge(e,s){if(s.error)return s.error;const n=Ht(s.data),r=Wt(s.result||"");if(!n)return r||s.stage||s.status;if(e==="system.health"){const i=typeof n.machine=="string"?n.machine:"",f=qe(n.cpuUsageRatio),c=z(n.cores),v=le(n.freeMemoryBytes),S=le(n.totalMemoryBytes),g=z(n.totalMemoryBytes)&&z(n.freeMemoryBytes)!==null?`${Math.round(z(n.freeMemoryBytes)/z(n.totalMemoryBytes)*100)}% RAM free`:"";return[i,f&&`CPU ${f}`,c!==null&&`${Math.round(c)} cores`,v&&S?`RAM ${v}/${S}`:"",g,typeof n.platform=="string"?n.platform:""].filter(Boolean).join(" · ")||r||s.status}if(e==="disk.status"){const i=typeof n.root=="string"?n.root:"",f=le(n.freeBytes),c=z(n.totalBytes)&&z(n.freeBytes)!==null?`${Math.round(z(n.freeBytes)/z(n.totalBytes)*100)}% free`:"";return[i,f&&`${f} free`,c].filter(Boolean).join(" · ")||r||s.status}if(e==="gpu.status"){const i=typeof n.name=="string"&&n.name?n.name:"No GPU detected",f=qe(n.usageRatio),c=z(n.temperatureC)!==null?`${Math.round(z(n.temperatureC))}°C`:"",v=le(n.freeMemoryBytes);return[i,f&&`GPU ${f}`,c,v&&`${v} free`].filter(Boolean).join(" · ")||r||s.status}if(e==="process.list"){const i=z(n.count);return i!==null?`${i} matching process${i===1?"":"es"}`:r||s.status}if(e==="network.status"){const i=Array.isArray(n.adapters)?n.adapters.length:null;return i!==null?`${i} active adapter${i===1?"":"s"}`:r||s.status}return e==="logs.collect"?tt(n)?.summary||r||s.status:r||s.stage||s.status}function Ge(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 Kt({state:e,operation:s}){const n=e.status==="completed"?ee:e.status==="failed"||e.status==="cancelled"?xe:e.status==="running"?Ce:wt,r=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",i=s==="logs.collect"&&e.status==="completed"?tt(e.data):null;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:r}),i&&t.jsxs("details",{className:"agent-log-detail",children:[t.jsx("summary",{children:"Redacted log output"}),t.jsx("pre",{"aria-label":`${e.deviceName} redacted log output`,children:i.output||"Log output unavailable."})]})]})}function Yt({operation:e,states:s,status:n,onCancel:r,onRetry:i,busy:f=!1}){const c=["running","queued"].includes(n),[v,S]=d.useState(!1),[g,x]=d.useState("all"),w=d.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=>Ge(e,p)),b=R.filter(p=>p.status==="completed").length,T=w.failed>0,k=R.length>0,C=s.filter(p=>g==="issues"?Ge(e,p):g==="running"?p.status==="running"||p.status==="queued":g==="completed"?p.status==="completed":g==="failed"?p.status==="failed":!0),M=k&&!c||n==="completed-with-failures"?"Completed with issues":n[0]?.toUpperCase()+n.slice(1),O=s.filter(p=>p.status==="completed").map(p=>ge(e,p)).filter(Boolean).filter((p,$,N)=>N.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:_t(e)})]}),t.jsx("span",{className:`agent-task-status status-${k?"completed-with-failures":n}`,children:M})]}),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"]})]}),O.length>0&&t.jsxs("div",{className:"agent-task-result-preview",title:O.join(" · "),children:[t.jsx("span",{children:"Result"}),O.join(" · ")]}),t.jsx("div",{className:"agent-target-chips","aria-label":"Target status overview",children:s.map((p,$)=>{const N=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:N})]},p.deviceId)})}),s.length>0&&t.jsx("div",{className:"agent-task-details-toggle",children:t.jsxs("button",{type:"button",onClick:()=>S(p=>!p),"aria-expanded":v,children:[v?t.jsx(kt,{size:14}):t.jsx(Je,{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:()=>x(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:C.length>0?C.map(p=>t.jsx(Kt,{operation:e,state:p},p.deviceId)):t.jsx("small",{className:"agent-task-no-results",children:"No targets match this filter."})})]}),(c||T)&&t.jsxs("div",{className:"agent-task-actions",children:[c&&r&&t.jsxs("button",{onClick:r,disabled:f,type:"button",children:[t.jsx(bt,{size:14})," Cancel"]}),!c&&T&&i&&t.jsxs("button",{onClick:i,disabled:f,type:"button",children:[t.jsx(Ct,{size:14})," Retry failed"]})]})]})}function Jt(e){try{return JSON.stringify(e,null,2).slice(0,6e3)}catch{return"{}"}}function Zt({approval:e,busy:s=!1,onApprove:n,onReject:r}){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:Jt(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:r,type:"button",children:[t.jsx(xe,{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(Se,{size:13})," Approval is bound to this run, tool, arguments, selected devices, and policy hash."]})]})}function Xt(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 Qt({items:e,onCancel:s,onRetry:n,busyBatchId:r,approvals:i,onApprove:f,onReject:c,busyApprovalId:v,progress:S,emptyTitle:g="Ask VuvoDesk to work across your machines.",emptyBody:x="Start with a read-only request such as “현재 대상에서 CPU와 메모리 상태를 확인해줘”."}){const w=d.useRef(null),R=d.useRef(!0),b=d.useRef(""),T=e[e.length-1];return d.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))},[i,e,T?.id,T?.type,S?.message,S?.stage]),t.jsxs("section",{className:"agents-conversation","aria-live":"polite",ref:w,onScroll:k=>{const C=k.currentTarget;R.current=C.scrollHeight-C.scrollTop-C.clientHeight<72},children:[i.filter(k=>k.status==="pending").map(k=>t.jsx(Zt,{approval:k,busy:v===k.approvalId,onApprove:C=>f(k,C),onReject:()=>c(k)},k.approvalId)),e.length===0&&t.jsxs("div",{className:"agents-empty-conversation",children:[t.jsx("strong",{children:g}),t.jsx("span",{children:x})]}),e.map(k=>{if(k.type==="task"){const C=k;return t.jsx(Yt,{operation:C.operation,states:C.states,status:C.status,onCancel:()=>s(C.batchId,C.agentRunId),onRetry:()=>n(C.batchId),busy:r===C.batchId},C.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)}),S&&t.jsxs("article",{className:"agents-message agent agents-progress-message",role:"status",children:[t.jsxs("span",{children:[t.jsx(Ce,{"aria-hidden":"true",size:15}),Xt(S.stage)]}),t.jsx("p",{children:S.message})]})]})}const Ve=["Recommended","Health & capacity","Processes & services","Files & configuration","Software & automation","Network & connectivity","Power & maintenance","Troubleshooting & recovery"],A=["windows","macos","linux"],U={"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(U));const es={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","문제해결","복구","장애"]},He=["low","medium","high","critical"];function ts(e){return e.reduce((s,n)=>{const r=U[n].risk;return He.indexOf(r)>He.indexOf(s)?r:s},"low")}function ss(e){return A.filter(s=>e.every(n=>U[n].supportedPlatforms.includes(s)))}function l(e,s,n,r,i,f,c={}){const v=c.description||r,S=i.flatMap(x=>x.split(".")),g=[...new Set([...es[s],...f,...S])];return{id:e,category:s,title:n,prompt:r,description:v,requiredOperations:i,risk:c.risk||ts(i),targetSupport:c.targetSupport||"single-or-multiple",supportedPlatforms:c.supportedPlatforms||ss(i),keywords:g,recommended:c.recommended??!1,enabled:!0}}const st=[l("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}),l("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}),l("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}),l("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}),l("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}),l("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}),l("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}),l("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}),l("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","높은 사용량"]),l("health-uptime","Health & capacity","Review Client uptime","Show uptime, boot time, and current system health for the target Clients.",["system.health"],["uptime","boot","가동시간"]),l("health-gpu-temperature","Health & capacity","Check GPU temperature","Check GPU temperature and thermal warnings on the current targets.",["gpu.status"],["thermal","temperature","발열"]),l("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"]),l("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","디스크"]),l("health-gpu-compare","Health & capacity","Compare GPU capacity","Compare GPU model, memory, temperature, and utilization across the current targets.",["gpu.status"],["compare","graphics","capacity"]),l("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","경고"]),l("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"]),l("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","실행 중"]),l("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"]),l("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"}),l("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"}),l("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"}),l("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"}),l("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","서비스 상태"]),l("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"}),l("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"}),l("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"}),l("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"}),l("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","구성"]),l("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"]),l("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"}),l("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"}),l("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"]),l("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"}),l("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"}),l("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"]}),l("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"]}),l("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"]}),l("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"}),l("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"}),l("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"}),l("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"]),l("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"}),l("network-adapter-status","Network & connectivity","Check network adapters","Show adapter state, address, and link information for the current targets.",["network.status"],["adapter","ethernet","wifi","네트워크 상태"]),l("network-disconnected","Network & connectivity","Find disconnected targets","Find current targets with disconnected or degraded network adapters.",["network.status"],["disconnected","offline","연결 끊김"]),l("network-link-speed","Network & connectivity","Check link speed","Report network link speed and duplex information for the current targets.",["network.status"],["speed","bandwidth","duplex"]),l("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"]),l("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"]),l("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"]),l("network-compare","Network & connectivity","Compare target connectivity","Compare adapter state, addresses, and link speed across the current targets.",["network.status"],["compare","inventory","connectivity"]),l("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"]),l("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"}),l("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"}),l("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"}),l("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"}),l("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"}),l("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"}),l("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"}),l("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"}),l("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"}),l("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"}),l("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"}),l("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"}),l("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"}),l("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"}),l("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"}),l("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 ns(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 rs(e,s,n){const r=ns(s,n),i=e.requiredOperations.map(f=>r[U[f].permissionCategory]);if(i.includes("deny")){const f=e.requiredOperations.find(c=>r[U[c].permissionCategory]==="deny");return{state:"blocked",label:"Blocked",reason:`This task requires ${U[f].label}, which is blocked by the current permission policy.`}}return i.includes("ask")?{state:"approval",label:"Approval required",reason:"This task requires approval before the requested changes can reach a Client."}:e.requiredOperations.every(f=>U[f].readOnly)?{state:"read-only",label:"Read only"}:s==="full-access"?{state:"full-access",label:"Full Access"}:{state:"auto",label:"Auto allowed"}}function as(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 is(e,s,n){const r=new Set(n);return e.filter(i=>i.connected&&(s==="all"||s==="auto"||r.has(i.deviceId)))}function os(e,s){const n=as(e.platform);if(!n||!s.supportedPlatforms.includes(n))return!1;const r=e.capabilities?.agentTools;return!Array.isArray(r)||r.length===0?s.requiredOperations.every(i=>U[i].readOnly):s.requiredOperations.every(i=>r.includes(i))}function nt(e,s,n,r,i,f){const c=rs(e,i,f),v=is(s,n,r),S=v.map(b=>b.deviceId),g={...c,available:!1,availableDeviceIds:[],unsupportedDeviceIds:S,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(c.state==="blocked")return g;const x=v.filter(b=>os(b,e)),w=x.map(b=>b.deviceId),R=S.filter(b=>!w.includes(b));return x.length===0?{...g,unsupportedDeviceIds:R,reason:"No current target supports the required platform and client capabilities."}:{...g,available:!0,availableDeviceIds:w,unsupportedDeviceIds:R}}function ls(e,s,n,r,i,f){return e.filter(c=>c.enabled&&nt(c,s,n,r,i,f).available).length}const ve="livedesk.agentPromptRecent",we="livedesk.agentPromptFavorites",cs={Recommended:H,"Health & capacity":Et,"Processes & services":Tt,"Files & configuration":It,"Software & automation":Pt,"Network & connectivity":Nt,"Power & maintenance":Ze,"Troubleshooting & recovery":Rt};function We(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 us(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 ds(e,s,n){if(!n.trim())return!0;const r=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(r)}function ps(e){return`permission-${e}`}function gs(e){return e==="low"?"Low risk":e==="medium"?"Medium risk":e==="high"?"High risk":"Critical risk"}function fs(e){return e==="windows"?"Windows":e==="macos"?"macOS":"Linux"}function ms({devices:e,targetMode:s,selectedIds:n,permissionMode:r,customCategories:i,onSelectPrompt:f,onClose:c}){const[v,S]=d.useState(""),[g,x]=d.useState("all"),[w,R]=d.useState(()=>We(ve)),[b,T]=d.useState(()=>We(we)),[k,C]=d.useState(0),[M,O]=d.useState(""),p=d.useRef(null),$=d.useRef(null),N=d.useMemo(()=>st.filter(o=>o.enabled),[]),P=d.useMemo(()=>new Map(N.map(o=>[o.id,nt(o,e,s,n,r,i)])),[i,e,r,n,s,N]),q=d.useMemo(()=>[...P.values()].filter(o=>o.available).length,[P]),te=d.useMemo(()=>e.filter(o=>o.connected&&(s==="all"||s==="auto"||n.includes(o.deviceId))).length,[e,n,s]),D=d.useMemo(()=>{const o=N.filter(h=>ds(h,P.get(h.id),v));return g==="recent"?w.map(h=>o.find(j=>j.id===h)).filter(h=>!!h):g==="favorites"?b.map(h=>o.find(j=>j.id===h)).filter(h=>!!h):g==="all"?o:o.filter(h=>{const j=P.get(h.id);return g==="read-only"?j.state==="read-only":g==="auto"?j.state==="auto":g==="approval"?j.state==="approval":g==="full-access"?j.state==="full-access":g==="available"?j.available:g==="unavailable"?!j.available:h.category===g})},[P,b,g,w,v,N]),fe=d.useMemo(()=>g!=="all"?[{category:ke(g),templates:D}]:Ve.map(o=>({category:o,templates:D.filter(h=>h.category===o)})).filter(o=>o.templates.length>0),[g,D]);d.useEffect(()=>{C(o=>Math.min(o,Math.max(0,D.length-1)))},[D.length]),d.useEffect(()=>{ce(ve,w)},[w]),d.useEffect(()=>{ce(we,b)},[b]),d.useEffect(()=>{$.current?.focus();const o=j=>{j.target instanceof Node&&!p.current?.contains(j.target)&&c()},h=j=>{j.key==="Escape"&&(j.preventDefault(),c())};return document.addEventListener("pointerdown",o),document.addEventListener("keydown",h),()=>{document.removeEventListener("pointerdown",o),document.removeEventListener("keydown",h)}},[c]);const se=o=>{const h=P.get(o.id);if(!h.available){O(h.reason||"This task is not available for the current targets and permission policy.");return}const j=[o.id,...w.filter(L=>L!==o.id)].slice(0,10);R(j),ce(ve,j),f(o.prompt),c()},J=o=>{T(h=>{const j=h.includes(o)?h.filter(L=>L!==o):[o,...h];return ce(we,j),j})},me=o=>{o.key==="ArrowDown"?(o.preventDefault(),C(h=>Math.min(h+1,Math.max(0,D.length-1)))):o.key==="ArrowUp"?(o.preventDefault(),C(h=>Math.max(h-1,0))):o.key==="Enter"&&D[k]&&(o.preventDefault(),se(D[k]))};let G=-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(H,{size:15})," Suggested tasks"]}),t.jsxs("small",{children:[q," available · ",N.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:c,children:t.jsx(xe,{size:16})})]}),t.jsxs("label",{className:"agents-suggested-search",children:[t.jsx(xt,{size:15,"aria-hidden":"true"}),t.jsx("input",{ref:$,value:v,onChange:o=>S(o.target.value),onKeyDown:me,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",...Ve].map(o=>{const h=o==="recent"?St:o==="favorites"?_e:o==="all"?H:o==="available"?jt:o==="unavailable"?At:o==="read-only"||o==="auto"||o==="approval"||o==="full-access"?Ze:cs[o];return t.jsxs("button",{className:g===o?"active":"",type:"button",title:ke(o),"aria-label":ke(o),"aria-pressed":g===o,onClick:()=>{x(o),C(0),O("")},children:[t.jsx(h,{size:12})," ",us(o)]},o)})}),M&&t.jsx("div",{className:"agents-suggested-notice",role:"status",children:M}),t.jsxs("div",{className:"agents-suggested-list",role:"listbox","aria-label":"Suggested tasks",children:[fe.map(o=>t.jsxs("div",{className:"agents-suggested-group",children:[t.jsx("strong",{children:o.category}),o.templates.map(h=>{G+=1;const j=G===k,L=b.includes(h.id),_=P.get(h.id),W=_.availableDeviceIds.length+_.unsupportedDeviceIds.length||te,ne=_.available?`Available on ${_.availableDeviceIds.length} of ${W} target${W===1?"":"s"}`:`Unavailable: ${_.reason||"not supported by the current targets"}`;return t.jsxs("div",{className:`agents-suggested-item ${j?"active":""} ${_.available?"":"unavailable"}`,children:[t.jsxs("button",{className:"agents-suggested-prompt",type:"button",role:"option","aria-selected":j,"aria-disabled":!_.available,onClick:()=>se(h),children:[t.jsx("span",{children:h.title}),t.jsx("small",{className:"agents-suggested-description",children:h.description}),t.jsxs("span",{className:"agents-suggested-meta",children:[t.jsx("em",{children:h.category}),t.jsx("em",{className:ps(_.state),children:_.label}),t.jsx("em",{className:`risk-${h.risk}`,children:gs(h.risk)}),t.jsx("em",{children:h.supportedPlatforms.map(fs).join(" · ")}),t.jsx("em",{className:_.available?"availability-ok":"availability-unavailable",children:ne}),_.available&&_.unsupportedDeviceIds.length>0&&t.jsxs("em",{className:"availability-warning",children:["Unsupported on ",_.unsupportedDeviceIds.length]})]})]}),t.jsx("button",{className:`agents-suggested-favorite ${L?"favorite":""}`,type:"button","aria-label":L?`Remove ${h.title} from favorites`:`Add ${h.title} to favorites`,"aria-pressed":L,onClick:()=>J(h.id),children:t.jsx(_e,{size:14,fill:L?"currentColor":"none"})})]},h.id)})]},o.category)),D.length===0&&t.jsx("p",{className:"agents-suggested-empty",children:"No tasks match this search or current filter."})]})]})}function hs({devices:e,mode:s,selectedIds:n,onModeChange:r,onToggle:i,permissionMode:f,onPermissionModeChange:c}){const v=e.filter(pe),S=n.filter(g=>v.some(x=>x.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:()=>r("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:()=>r("selected"),type:"button",children:[t.jsx(ee,{size:14})," Selected ",S]}),t.jsxs("button",{className:s==="auto"?"active":"",onClick:()=>r("auto"),type:"button",children:[t.jsx(H,{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-${f}`,children:[t.jsx(Se,{size:14}),t.jsx("span",{children:"Permission"}),t.jsxs("select",{value:f,onChange:g=>c(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(Je,{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 x=pe(g),w=s==="all"||s==="auto"?x:n.includes(g.deviceId);return t.jsxs("label",{className:`agents-target-option ${w?"selected":""} ${x?"":"offline"}`,children:[t.jsx("input",{type:"checkbox",checked:w,disabled:!x||s!=="selected",onChange:()=>i(g.deviceId)}),t.jsx("span",{className:"agents-target-icon",children:t.jsx(Xe,{size:15})}),t.jsxs("span",{children:[t.jsx("strong",{children:de(g)}),t.jsx("small",{children:x?"Ready":g.connected?"Agent reconnecting":"Offline"})]}),w&&t.jsx(ee,{className:"agents-target-check",size:15,"aria-hidden":"true"})]},g.deviceId)})})]})}const ys=800,Ke=5e3;function vs(){return typeof document>"u"||document.visibilityState==="visible"}function ws(e){return typeof document>"u"?()=>{}:(document.addEventListener("visibilitychange",e),()=>document.removeEventListener("visibilitychange",e))}function Ye({poll:e,onResult:s,onError:n,intervalMs:r=ys,isVisible:i=vs,subscribeVisibility:f=ws,setTimeoutImpl:c=globalThis.setTimeout.bind(globalThis),clearTimeoutImpl:v=globalThis.clearTimeout.bind(globalThis),createAbortController:S=()=>new AbortController}){if(typeof e!="function")throw new TypeError("Agent polling requires a poll function.");const g={current:null};let x=!0,w=0,R=null,b=null;const T=()=>{R!==null&&(v(R),R=null)},k=()=>{!x||!i()||R!==null||g.current||(R=c(()=>{R=null,C()},r))},C=()=>{if(!x||!i()||g.current)return g.current;const $=++w,N=S();b=N;const P=ht(g,()=>e(N.signal));return P.then(q=>{x&&$===w&&!N.signal.aborted&&s?.(q)},q=>{x&&$===w&&!N.signal.aborted&&n?.(q)}).finally(()=>{b===N&&(b=null),x&&i()&&k()}).catch(()=>{}),P},M=async()=>{if(!x)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(!(!x||!i()))return T(),C()},p=f(()=>{if(T(),!i()){w+=1,b&&!b.signal.aborted&&b.abort(new Error("VuvoDesk Agent polling paused while hidden."));return}C()});return C(),{refresh:M,stop(){x&&(x=!1,w+=1,T(),p?.(),b&&!b.signal.aborted&&b.abort(new Error("VuvoDesk Agent polling owner closed.")))}}}async function ks(e,s){return F("/api/settings/agent/run",{method:"POST",body:JSON.stringify(s)},e)}async function bs(e,s,n={}){return F(`/api/settings/agent/runs/${encodeURIComponent(s)}`,n,e)}async function Cs(e,s){return F(`/api/settings/agent/runs/${encodeURIComponent(s)}/cancel`,{method:"POST",body:JSON.stringify({})},e)}async function xs(e){return F("/api/settings/agent/runs/cancel-all",{method:"POST",body:JSON.stringify({})},e)}async function Ss(e,s,n,r){return F(`/api/settings/agent/runs/${encodeURIComponent(s)}/approvals/${encodeURIComponent(n)}/approve`,{method:"POST",body:JSON.stringify({scope:r})},e)}async function js(e,s,n,r="User rejected this action."){return F(`/api/settings/agent/runs/${encodeURIComponent(s)}/approvals/${encodeURIComponent(n)}/reject`,{method:"POST",body:JSON.stringify({reason:r})},e)}async function As(e,s,n){return F(`/api/settings/agent/policies/${encodeURIComponent(s)}`,{method:"PUT",body:JSON.stringify({categories:n})},e)}async function Rs(e,s,n={}){return F(`/api/remote/tasks/${encodeURIComponent(s)}`,n,e)}async function Ns(e,s){return F(`/api/remote/tasks/${encodeURIComponent(s)}/cancel`,{method:"POST",body:JSON.stringify({})},e)}async function Ps(e,s){return F(`/api/remote/tasks/${encodeURIComponent(s)}/retry`,{method:"POST",body:JSON.stringify({failedOnly:!0})},e)}function Q(e){return`${e}-${Date.now()}-${Math.random().toString(36).slice(2,8)}`}function be(e,s){const n=new Map(s.map(r=>[r.deviceId,de(r)]));return e.results.map(r=>({deviceId:r.deviceId,deviceName:r.deviceName||n.get(r.deviceId)||r.deviceId,status:Dt(r.status),stage:r.stage||(r.status==="running"?"Checking processes":void 0),result:r.result,data:r.data,error:r.error,sequence:Number.isSafeInteger(r.sequence)?r.sequence:0}))}function Is(e,s){const n=new Map(s.map(r=>[r.deviceId,r]));return e.map(r=>{const i=n.get(r.deviceId);return!i||i.sequence<=r.sequence?r:i})}const Ts={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 Es(e){return e==="safe-auto"?"Safe Auto":e==="full-access"?"Full Access":e==="custom"?"Custom":"Ask"}function Os(e){return e.replace(/([A-Z])/g," $1").replace(/^./,s=>s.toUpperCase())}function $s(e){const s=e instanceof Error?e.message:String(e);return/agent-disabled/i.test(s)?"Codex Agent was explicitly turned off in Settings.":/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 Ms({hubUrl:e,devices:s,launchRequest:n,variant:r="page",selectedDeviceIds:i=[]}){const f=r==="dock",[c,v]=d.useState(f?i.length>0?"selected":"auto":"all"),[S,g]=d.useState(i),[x,w]=d.useState("auto"),[R,b]=d.useState(""),[T,k]=d.useState([]),[C,M]=d.useState(""),[O,p]=d.useState(""),[$,N]=d.useState(""),[P,q]=d.useState("safe-auto"),[te]=d.useState("custom-default"),[D,fe]=d.useState(Ts),[se,J]=d.useState([]),[me,G]=d.useState(""),[o,h]=d.useState(!1),[j,L]=d.useState(null),[_,W]=d.useState(!1),[ne,B]=d.useState(""),[je,Z]=d.useState(!1),[Ae,X]=d.useState(null),re=d.useRef(null),K=d.useRef(null),ae=d.useRef(null),Re=d.useRef(new Set),Ne=d.useRef(new Set),he=d.useMemo(()=>s.filter(pe).map(a=>a.deviceId),[s]),rt=d.useMemo(()=>ls(st,s,c,S,P,D),[D,s,P,S,c]);d.useEffect(()=>{f&&g(i)},[f,i]),d.useEffect(()=>{n?.deviceId&&(v("selected"),g([n.deviceId]),b(n.instruction),Z(!1),window.requestAnimationFrame(()=>{re.current?.focus(),re.current?.setSelectionRange(n.instruction.length,n.instruction.length)}))},[n]);const Y=d.useCallback(a=>{const u=be(a,s);k(y=>y.map(m=>m.type==="task"&&m.batchId===a.batchId?{...m,states:Is(m.states,u),status:a.status}:m)),["running","queued"].includes(a.status)||M(y=>y===a.batchId?"":y)},[s]),Pe=d.useCallback((a,u)=>{Ne.current.has(a.batchId)||(Ne.current.add(a.batchId),k(y=>[...y,{type:"task",id:Q("task"),batchId:a.batchId,agentRunId:u,operation:a.operation||"diagnostics.collect",instruction:a.instructionPreview,states:be(a,s),status:a.status}])),Y(a)},[s,Y]),Ie=d.useCallback((a,u)=>{for(const m of u.taskBatches||[])Pe(m,a);J(u.approvals||[]);const y=["running","queued","waiting-approval"].includes(u.status);if(X(y?{runId:a,stage:u.stage||u.status,message:u.progressMessage||(u.status==="waiting-approval"?"Review the requested action to continue.":"Codex is preparing the answer.")}:m=>m?.runId===a?null:m),!y&&!Re.current.has(a)){Re.current.add(a);const m=[u.error,u.errorMessage].filter(Boolean).join(" — "),I=u.finalResponse?.trim()||(u.status==="cancelled"?"Codex 작업을 취소했습니다.":m?`Codex 작업이 완료되지 않았습니다: ${m}`:"Codex 작업이 완료되었습니다.");k($e=>[...$e,{type:u.status==="failed"?"error":"agent",id:Q("agent-run-result"),text:I}])}},[Pe]),Te=d.useCallback(async a=>{const u=K.current;if(!(!u||u.id!==a))try{return await u.owner.refresh()}catch(y){if(K.current!==u)return;throw y}},[]);d.useEffect(()=>{if(!O){K.current=null;return}const a=O,u=Ye({poll:m=>bs(e,a,{signal:m,timeoutMs:Ke}),onResult:m=>{Ie(a,m),["running","queued","waiting-approval"].includes(m.status)||(p(I=>I===a?"":I),W(!1))},onError:m=>{B(m instanceof Error?m.message:String(m))}}),y={id:a,owner:u};return K.current=y,()=>{u.stop(),K.current===y&&(K.current=null)}},[O,e,Ie]),d.useEffect(()=>{if(!C){ae.current=null;return}const a=C,u=Ye({poll:m=>Rs(e,a,{signal:m,timeoutMs:Ke}),onResult:m=>{Y(m),["running","queued"].includes(m.status)||M(I=>I===a?"":I)},onError:m=>{B(m instanceof Error?m.message:String(m))}}),y={id:a,owner:u};return ae.current=y,()=>{u.stop(),ae.current===y&&(ae.current=null)}},[C,e,Y]);const Ee=async(a="",u,y=!1)=>{const m=(a||R).trim();if(!m||C||O)return;const I=u||(c==="all"||c==="auto"?he:S.filter(E=>he.includes(E)));if(I.length===0){B("Select at least one connected Client.");return}if(P==="full-access"&&!_&&!y){L({instruction:m,targetIds:I});return}if(k(E=>[...E,{type:"user",id:Q("user"),text:m}]),b(""),Z(!1),B(""),I.length===0){k(E=>[...E,{type:"error",id:Q("no-targets"),text:"연결된 대상 장비를 하나 이상 선택해 주세요."}]);return}const De=x==="ask"?`Read-only request. Inspect and answer without changing Client state.
5
+ `),r=!0),r||=Fe(n)>ze,r){const f=Fe(Me),c=Math.max(0,ze-f-1);n=Be(n,c).value,n=`${Me}${n?`
6
+ ${n}`:""}`}return{output:n,displayTruncated:r}}function tt(e){const s=Ut(e);if(!s)return null;const n=Vt(s.output),r=qe(s.returnedCount)??qe(s.returnedLines),i=typeof s.truncated=="boolean"?s.truncated:null,f=Gt(s.source),c=r===null?"line count unknown":`${r} line${r===1?"":"s"} returned`,S=[f,c,i===!0?"source truncated":i===!1?"source complete":"source truncation unknown",n.displayTruncated?"display limited":""].filter(Boolean).join(" · ");return{source:f,returnedCount:r,truncated:i,output:n.output,displayTruncated:n.displayTruncated,summary:S}}function Ht(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:null}function M(e){return typeof e=="number"&&Number.isFinite(e)?e:null}function le(e){const s=M(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 Ue(e){const s=M(e);return s===null?"":`${Math.round((s<=1?s:s/100)*100)}%`}function Wt(e){return!e||/^(?:[\w .-]+ )?collected(?:\.)?$/i.test(e.trim())?"":e.trim()}function ge(e,s){if(s.error)return s.error;const n=Ht(s.data),r=Wt(s.result||"");if(!n)return r||s.stage||s.status;if(e==="system.health"){const i=typeof n.machine=="string"?n.machine:"",f=Ue(n.cpuUsageRatio),c=M(n.cores),v=le(n.freeMemoryBytes),S=le(n.totalMemoryBytes),g=M(n.totalMemoryBytes)&&M(n.freeMemoryBytes)!==null?`${Math.round(M(n.freeMemoryBytes)/M(n.totalMemoryBytes)*100)}% RAM free`:"";return[i,f&&`CPU ${f}`,c!==null&&`${Math.round(c)} cores`,v&&S?`RAM ${v}/${S}`:"",g,typeof n.platform=="string"?n.platform:""].filter(Boolean).join(" · ")||r||s.status}if(e==="disk.status"){const i=typeof n.root=="string"?n.root:"",f=le(n.freeBytes),c=M(n.totalBytes)&&M(n.freeBytes)!==null?`${Math.round(M(n.freeBytes)/M(n.totalBytes)*100)}% free`:"";return[i,f&&`${f} free`,c].filter(Boolean).join(" · ")||r||s.status}if(e==="gpu.status"){const i=typeof n.name=="string"&&n.name?n.name:"No GPU detected",f=Ue(n.usageRatio),c=M(n.temperatureC)!==null?`${Math.round(M(n.temperatureC))}°C`:"",v=le(n.freeMemoryBytes);return[i,f&&`GPU ${f}`,c,v&&`${v} free`].filter(Boolean).join(" · ")||r||s.status}if(e==="process.list"){const i=M(n.count);return i!==null?`${i} matching process${i===1?"":"es"}`:r||s.status}if(e==="network.status"){const i=Array.isArray(n.adapters)?n.adapters.length:null;return i!==null?`${i} active adapter${i===1?"":"s"}`:r||s.status}return e==="logs.collect"?tt(n)?.summary||r||s.status:r||s.stage||s.status}function Ge(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 Kt({state:e,operation:s}){const n=e.status==="completed"?ee:e.status==="failed"||e.status==="cancelled"?xe:e.status==="running"?Ce:vt,r=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",i=s==="logs.collect"&&e.status==="completed"?tt(e.data):null;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:r}),i&&t.jsxs("details",{className:"agent-log-detail",children:[t.jsx("summary",{children:"Redacted log output"}),t.jsx("pre",{"aria-label":`${e.deviceName} redacted log output`,children:i.output||"Log output unavailable."})]})]})}function Yt({operation:e,states:s,status:n,onCancel:r,onRetry:i,busy:f=!1}){const c=["running","queued"].includes(n),[v,S]=d.useState(!1),[g,x]=d.useState("all"),w=d.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=>Ge(e,p)),b=R.filter(p=>p.status==="completed").length,T=w.failed>0,k=R.length>0,C=s.filter(p=>g==="issues"?Ge(e,p):g==="running"?p.status==="running"||p.status==="queued":g==="completed"?p.status==="completed":g==="failed"?p.status==="failed":!0),z=k&&!c||n==="completed-with-failures"?"Completed with issues":n[0]?.toUpperCase()+n.slice(1),O=s.filter(p=>p.status==="completed").map(p=>ge(e,p)).filter(Boolean).filter((p,$,N)=>N.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:_t(e)})]}),t.jsx("span",{className:`agent-task-status status-${k?"completed-with-failures":n}`,children:z})]}),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"]})]}),O.length>0&&t.jsxs("div",{className:"agent-task-result-preview",title:O.join(" · "),children:[t.jsx("span",{children:"Result"}),O.join(" · ")]}),t.jsx("div",{className:"agent-target-chips","aria-label":"Target status overview",children:s.map((p,$)=>{const N=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:N})]},p.deviceId)})}),s.length>0&&t.jsx("div",{className:"agent-task-details-toggle",children:t.jsxs("button",{type:"button",onClick:()=>S(p=>!p),"aria-expanded":v,children:[v?t.jsx(wt,{size:14}):t.jsx(Ze,{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:()=>x(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:C.length>0?C.map(p=>t.jsx(Kt,{operation:e,state:p},p.deviceId)):t.jsx("small",{className:"agent-task-no-results",children:"No targets match this filter."})})]}),(c||T)&&t.jsxs("div",{className:"agent-task-actions",children:[c&&r&&t.jsxs("button",{onClick:r,disabled:f,type:"button",children:[t.jsx(kt,{size:14})," Cancel"]}),!c&&T&&i&&t.jsxs("button",{onClick:i,disabled:f,type:"button",children:[t.jsx(bt,{size:14})," Retry failed"]})]})]})}function Zt(e){try{return JSON.stringify(e,null,2).slice(0,6e3)}catch{return"{}"}}function Jt({approval:e,busy:s=!1,onApprove:n,onReject:r}){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:Zt(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:r,type:"button",children:[t.jsx(xe,{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(Se,{size:13})," Approval is bound to this run, tool, arguments, selected devices, and policy hash."]})]})}function Xt(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 Qt({items:e,onCancel:s,onRetry:n,busyBatchId:r,approvals:i,onApprove:f,onReject:c,busyApprovalId:v,progress:S,emptyTitle:g="Ask VuvoDesk to work across your machines.",emptyBody:x="Start with a read-only request such as “현재 대상에서 CPU와 메모리 상태를 확인해줘”."}){const w=d.useRef(null),R=d.useRef(!0),b=d.useRef(""),T=e[e.length-1];return d.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))},[i,e,T?.id,T?.type,S?.message,S?.stage]),t.jsxs("section",{className:"agents-conversation","aria-live":"polite",ref:w,onScroll:k=>{const C=k.currentTarget;R.current=C.scrollHeight-C.scrollTop-C.clientHeight<72},children:[i.filter(k=>k.status==="pending").map(k=>t.jsx(Jt,{approval:k,busy:v===k.approvalId,onApprove:C=>f(k,C),onReject:()=>c(k)},k.approvalId)),e.length===0&&t.jsxs("div",{className:"agents-empty-conversation",children:[t.jsx("strong",{children:g}),t.jsx("span",{children:x})]}),e.map(k=>{if(k.type==="task"){const C=k;return t.jsx(Yt,{operation:C.operation,states:C.states,status:C.status,onCancel:()=>s(C.batchId,C.agentRunId),onRetry:()=>n(C.batchId),busy:r===C.batchId},C.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)}),S&&t.jsxs("article",{className:"agents-message agent agents-progress-message",role:"status",children:[t.jsxs("span",{children:[t.jsx(Ce,{"aria-hidden":"true",size:15}),Xt(S.stage)]}),t.jsx("p",{children:S.message})]})]})}const Ve=["Recommended","Health & capacity","Processes & services","Files & configuration","Software & automation","Network & connectivity","Power & maintenance","Troubleshooting & recovery"],A=["windows","macos","linux"],q={"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(q));const es={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","문제해결","복구","장애"]},He=["low","medium","high","critical"];function ts(e){return e.reduce((s,n)=>{const r=q[n].risk;return He.indexOf(r)>He.indexOf(s)?r:s},"low")}function ss(e){return A.filter(s=>e.every(n=>q[n].supportedPlatforms.includes(s)))}function l(e,s,n,r,i,f,c={}){const v=c.description||r,S=i.flatMap(x=>x.split(".")),g=[...new Set([...es[s],...f,...S])];return{id:e,category:s,title:n,prompt:r,description:v,requiredOperations:i,risk:c.risk||ts(i),targetSupport:c.targetSupport||"single-or-multiple",supportedPlatforms:c.supportedPlatforms||ss(i),keywords:g,recommended:c.recommended??!1,enabled:!0}}const st=[l("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}),l("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}),l("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}),l("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}),l("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}),l("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}),l("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}),l("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}),l("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","높은 사용량"]),l("health-uptime","Health & capacity","Review Client uptime","Show uptime, boot time, and current system health for the target Clients.",["system.health"],["uptime","boot","가동시간"]),l("health-gpu-temperature","Health & capacity","Check GPU temperature","Check GPU temperature and thermal warnings on the current targets.",["gpu.status"],["thermal","temperature","발열"]),l("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"]),l("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","디스크"]),l("health-gpu-compare","Health & capacity","Compare GPU capacity","Compare GPU model, memory, temperature, and utilization across the current targets.",["gpu.status"],["compare","graphics","capacity"]),l("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","경고"]),l("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"]),l("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","실행 중"]),l("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"]),l("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"}),l("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"}),l("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"}),l("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"}),l("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","서비스 상태"]),l("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"}),l("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"}),l("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"}),l("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"}),l("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","구성"]),l("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"]),l("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"}),l("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"}),l("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"]),l("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"}),l("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"}),l("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"]}),l("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"]}),l("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"]}),l("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"}),l("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"}),l("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"}),l("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"]),l("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"}),l("network-adapter-status","Network & connectivity","Check network adapters","Show adapter state, address, and link information for the current targets.",["network.status"],["adapter","ethernet","wifi","네트워크 상태"]),l("network-disconnected","Network & connectivity","Find disconnected targets","Find current targets with disconnected or degraded network adapters.",["network.status"],["disconnected","offline","연결 끊김"]),l("network-link-speed","Network & connectivity","Check link speed","Report network link speed and duplex information for the current targets.",["network.status"],["speed","bandwidth","duplex"]),l("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"]),l("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"]),l("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"]),l("network-compare","Network & connectivity","Compare target connectivity","Compare adapter state, addresses, and link speed across the current targets.",["network.status"],["compare","inventory","connectivity"]),l("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"]),l("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"}),l("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"}),l("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"}),l("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"}),l("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"}),l("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"}),l("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"}),l("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"}),l("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"}),l("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"}),l("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"}),l("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"}),l("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"}),l("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"}),l("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"}),l("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 ns(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 rs(e,s,n){const r=ns(s,n),i=e.requiredOperations.map(f=>r[q[f].permissionCategory]);if(i.includes("deny")){const f=e.requiredOperations.find(c=>r[q[c].permissionCategory]==="deny");return{state:"blocked",label:"Blocked",reason:`This task requires ${q[f].label}, which is blocked by the current permission policy.`}}return i.includes("ask")?{state:"approval",label:"Approval required",reason:"This task requires approval before the requested changes can reach a Client."}:e.requiredOperations.every(f=>q[f].readOnly)?{state:"read-only",label:"Read only"}:s==="full-access"?{state:"full-access",label:"Full Access"}:{state:"auto",label:"Auto allowed"}}function as(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 is(e,s,n){const r=new Set(n);return e.filter(i=>i.connected&&(s==="all"||s==="auto"||r.has(i.deviceId)))}function os(e,s){const n=as(e.platform);if(!n||!s.supportedPlatforms.includes(n))return!1;const r=e.capabilities?.agentTools;return!Array.isArray(r)||r.length===0?s.requiredOperations.every(i=>q[i].readOnly):s.requiredOperations.every(i=>r.includes(i))}function nt(e,s,n,r,i,f){const c=rs(e,i,f),v=is(s,n,r),S=v.map(b=>b.deviceId),g={...c,available:!1,availableDeviceIds:[],unsupportedDeviceIds:S,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(c.state==="blocked")return g;const x=v.filter(b=>os(b,e)),w=x.map(b=>b.deviceId),R=S.filter(b=>!w.includes(b));return x.length===0?{...g,unsupportedDeviceIds:R,reason:"No current target supports the required platform and client capabilities."}:{...g,available:!0,availableDeviceIds:w,unsupportedDeviceIds:R}}function ls(e,s,n,r,i,f){return e.filter(c=>c.enabled&&nt(c,s,n,r,i,f).available).length}const ve="livedesk.agentPromptRecent",we="livedesk.agentPromptFavorites",cs={Recommended:H,"Health & capacity":Tt,"Processes & services":It,"Files & configuration":Pt,"Software & automation":Nt,"Network & connectivity":Rt,"Power & maintenance":Je,"Troubleshooting & recovery":At};function We(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 us(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 ds(e,s,n){if(!n.trim())return!0;const r=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(r)}function ps(e){return`permission-${e}`}function gs(e){return e==="low"?"Low risk":e==="medium"?"Medium risk":e==="high"?"High risk":"Critical risk"}function fs(e){return e==="windows"?"Windows":e==="macos"?"macOS":"Linux"}function ms({devices:e,targetMode:s,selectedIds:n,permissionMode:r,customCategories:i,onSelectPrompt:f,onClose:c}){const[v,S]=d.useState(""),[g,x]=d.useState("all"),[w,R]=d.useState(()=>We(ve)),[b,T]=d.useState(()=>We(we)),[k,C]=d.useState(0),[z,O]=d.useState(""),p=d.useRef(null),$=d.useRef(null),N=d.useMemo(()=>st.filter(o=>o.enabled),[]),P=d.useMemo(()=>new Map(N.map(o=>[o.id,nt(o,e,s,n,r,i)])),[i,e,r,n,s,N]),U=d.useMemo(()=>[...P.values()].filter(o=>o.available).length,[P]),te=d.useMemo(()=>e.filter(o=>o.connected&&(s==="all"||s==="auto"||n.includes(o.deviceId))).length,[e,n,s]),D=d.useMemo(()=>{const o=N.filter(h=>ds(h,P.get(h.id),v));return g==="recent"?w.map(h=>o.find(j=>j.id===h)).filter(h=>!!h):g==="favorites"?b.map(h=>o.find(j=>j.id===h)).filter(h=>!!h):g==="all"?o:o.filter(h=>{const j=P.get(h.id);return g==="read-only"?j.state==="read-only":g==="auto"?j.state==="auto":g==="approval"?j.state==="approval":g==="full-access"?j.state==="full-access":g==="available"?j.available:g==="unavailable"?!j.available:h.category===g})},[P,b,g,w,v,N]),fe=d.useMemo(()=>g!=="all"?[{category:ke(g),templates:D}]:Ve.map(o=>({category:o,templates:D.filter(h=>h.category===o)})).filter(o=>o.templates.length>0),[g,D]);d.useEffect(()=>{C(o=>Math.min(o,Math.max(0,D.length-1)))},[D.length]),d.useEffect(()=>{ce(ve,w)},[w]),d.useEffect(()=>{ce(we,b)},[b]),d.useEffect(()=>{$.current?.focus();const o=j=>{j.target instanceof Node&&!p.current?.contains(j.target)&&c()},h=j=>{j.key==="Escape"&&(j.preventDefault(),c())};return document.addEventListener("pointerdown",o),document.addEventListener("keydown",h),()=>{document.removeEventListener("pointerdown",o),document.removeEventListener("keydown",h)}},[c]);const se=o=>{const h=P.get(o.id);if(!h.available){O(h.reason||"This task is not available for the current targets and permission policy.");return}const j=[o.id,...w.filter(L=>L!==o.id)].slice(0,10);R(j),ce(ve,j),f(o.prompt),c()},Z=o=>{T(h=>{const j=h.includes(o)?h.filter(L=>L!==o):[o,...h];return ce(we,j),j})},me=o=>{o.key==="ArrowDown"?(o.preventDefault(),C(h=>Math.min(h+1,Math.max(0,D.length-1)))):o.key==="ArrowUp"?(o.preventDefault(),C(h=>Math.max(h-1,0))):o.key==="Enter"&&D[k]&&(o.preventDefault(),se(D[k]))};let G=-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(H,{size:15})," Suggested tasks"]}),t.jsxs("small",{children:[U," available · ",N.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:c,children:t.jsx(xe,{size:16})})]}),t.jsxs("label",{className:"agents-suggested-search",children:[t.jsx(Ct,{size:15,"aria-hidden":"true"}),t.jsx("input",{ref:$,value:v,onChange:o=>S(o.target.value),onKeyDown:me,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",...Ve].map(o=>{const h=o==="recent"?xt:o==="favorites"?_e:o==="all"?H:o==="available"?St:o==="unavailable"?jt:o==="read-only"||o==="auto"||o==="approval"||o==="full-access"?Je:cs[o];return t.jsxs("button",{className:g===o?"active":"",type:"button",title:ke(o),"aria-label":ke(o),"aria-pressed":g===o,onClick:()=>{x(o),C(0),O("")},children:[t.jsx(h,{size:12})," ",us(o)]},o)})}),z&&t.jsx("div",{className:"agents-suggested-notice",role:"status",children:z}),t.jsxs("div",{className:"agents-suggested-list",role:"listbox","aria-label":"Suggested tasks",children:[fe.map(o=>t.jsxs("div",{className:"agents-suggested-group",children:[t.jsx("strong",{children:o.category}),o.templates.map(h=>{G+=1;const j=G===k,L=b.includes(h.id),_=P.get(h.id),W=_.availableDeviceIds.length+_.unsupportedDeviceIds.length||te,ne=_.available?`Available on ${_.availableDeviceIds.length} of ${W} target${W===1?"":"s"}`:`Unavailable: ${_.reason||"not supported by the current targets"}`;return t.jsxs("div",{className:`agents-suggested-item ${j?"active":""} ${_.available?"":"unavailable"}`,children:[t.jsxs("button",{className:"agents-suggested-prompt",type:"button",role:"option","aria-selected":j,"aria-disabled":!_.available,onClick:()=>se(h),children:[t.jsx("span",{children:h.title}),t.jsx("small",{className:"agents-suggested-description",children:h.description}),t.jsxs("span",{className:"agents-suggested-meta",children:[t.jsx("em",{children:h.category}),t.jsx("em",{className:ps(_.state),children:_.label}),t.jsx("em",{className:`risk-${h.risk}`,children:gs(h.risk)}),t.jsx("em",{children:h.supportedPlatforms.map(fs).join(" · ")}),t.jsx("em",{className:_.available?"availability-ok":"availability-unavailable",children:ne}),_.available&&_.unsupportedDeviceIds.length>0&&t.jsxs("em",{className:"availability-warning",children:["Unsupported on ",_.unsupportedDeviceIds.length]})]})]}),t.jsx("button",{className:`agents-suggested-favorite ${L?"favorite":""}`,type:"button","aria-label":L?`Remove ${h.title} from favorites`:`Add ${h.title} to favorites`,"aria-pressed":L,onClick:()=>Z(h.id),children:t.jsx(_e,{size:14,fill:L?"currentColor":"none"})})]},h.id)})]},o.category)),D.length===0&&t.jsx("p",{className:"agents-suggested-empty",children:"No tasks match this search or current filter."})]})]})}function hs({devices:e,mode:s,selectedIds:n,onModeChange:r,onToggle:i,permissionMode:f,onPermissionModeChange:c}){const v=e.filter(pe),S=n.filter(g=>v.some(x=>x.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:()=>r("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:()=>r("selected"),type:"button",children:[t.jsx(ee,{size:14})," Selected ",S]}),t.jsxs("button",{className:s==="auto"?"active":"",onClick:()=>r("auto"),type:"button",children:[t.jsx(H,{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-${f}`,children:[t.jsx(Se,{size:14}),t.jsx("span",{children:"Permission"}),t.jsxs("select",{value:f,onChange:g=>c(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(Ze,{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 x=pe(g),w=s==="all"||s==="auto"?x:n.includes(g.deviceId);return t.jsxs("label",{className:`agents-target-option ${w?"selected":""} ${x?"":"offline"}`,children:[t.jsx("input",{type:"checkbox",checked:w,disabled:!x||s!=="selected",onChange:()=>i(g.deviceId)}),t.jsx("span",{className:"agents-target-icon",children:t.jsx(Xe,{size:15})}),t.jsxs("span",{children:[t.jsx("strong",{children:de(g)}),t.jsx("small",{children:x?"Ready":g.connected?"Agent reconnecting":"Offline"})]}),w&&t.jsx(ee,{className:"agents-target-check",size:15,"aria-hidden":"true"})]},g.deviceId)})})]})}const ys=800,Ke=5e3;function vs(){return typeof document>"u"||document.visibilityState==="visible"}function ws(e){return typeof document>"u"?()=>{}:(document.addEventListener("visibilitychange",e),()=>document.removeEventListener("visibilitychange",e))}function Ye({poll:e,onResult:s,onError:n,intervalMs:r=ys,isVisible:i=vs,subscribeVisibility:f=ws,setTimeoutImpl:c=globalThis.setTimeout.bind(globalThis),clearTimeoutImpl:v=globalThis.clearTimeout.bind(globalThis),createAbortController:S=()=>new AbortController}){if(typeof e!="function")throw new TypeError("Agent polling requires a poll function.");const g={current:null};let x=!0,w=0,R=null,b=null;const T=()=>{R!==null&&(v(R),R=null)},k=()=>{!x||!i()||R!==null||g.current||(R=c(()=>{R=null,C()},r))},C=()=>{if(!x||!i()||g.current)return g.current;const $=++w,N=S();b=N;const P=Et(g,()=>e(N.signal));return P.then(U=>{x&&$===w&&!N.signal.aborted&&s?.(U)},U=>{x&&$===w&&!N.signal.aborted&&n?.(U)}).finally(()=>{b===N&&(b=null),x&&i()&&k()}).catch(()=>{}),P},z=async()=>{if(!x)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(!(!x||!i()))return T(),C()},p=f(()=>{if(T(),!i()){w+=1,b&&!b.signal.aborted&&b.abort(new Error("VuvoDesk Agent polling paused while hidden."));return}C()});return C(),{refresh:z,stop(){x&&(x=!1,w+=1,T(),p?.(),b&&!b.signal.aborted&&b.abort(new Error("VuvoDesk Agent polling owner closed.")))}}}async function ks(e,s){return F("/api/settings/agent/run",{method:"POST",body:JSON.stringify(s)},e)}async function bs(e,s,n={}){return F(`/api/settings/agent/runs/${encodeURIComponent(s)}`,n,e)}async function Cs(e,s){return F(`/api/settings/agent/runs/${encodeURIComponent(s)}/cancel`,{method:"POST",body:JSON.stringify({})},e)}async function xs(e){return F("/api/settings/agent/runs/cancel-all",{method:"POST",body:JSON.stringify({})},e)}async function Ss(e,s,n,r){return F(`/api/settings/agent/runs/${encodeURIComponent(s)}/approvals/${encodeURIComponent(n)}/approve`,{method:"POST",body:JSON.stringify({scope:r})},e)}async function js(e,s,n,r="User rejected this action."){return F(`/api/settings/agent/runs/${encodeURIComponent(s)}/approvals/${encodeURIComponent(n)}/reject`,{method:"POST",body:JSON.stringify({reason:r})},e)}async function As(e,s,n){return F(`/api/settings/agent/policies/${encodeURIComponent(s)}`,{method:"PUT",body:JSON.stringify({categories:n})},e)}async function Rs(e,s,n={}){return F(`/api/remote/tasks/${encodeURIComponent(s)}`,n,e)}async function Ns(e,s){return F(`/api/remote/tasks/${encodeURIComponent(s)}/cancel`,{method:"POST",body:JSON.stringify({})},e)}async function Ps(e,s){return F(`/api/remote/tasks/${encodeURIComponent(s)}/retry`,{method:"POST",body:JSON.stringify({failedOnly:!0})},e)}function Q(e){return`${e}-${Date.now()}-${Math.random().toString(36).slice(2,8)}`}function be(e,s){const n=new Map(s.map(r=>[r.deviceId,de(r)]));return e.results.map(r=>({deviceId:r.deviceId,deviceName:r.deviceName||n.get(r.deviceId)||r.deviceId,status:Dt(r.status),stage:r.stage||(r.status==="running"?"Checking processes":void 0),result:r.result,data:r.data,error:r.error,sequence:Number.isSafeInteger(r.sequence)?r.sequence:0}))}function Is(e,s){const n=new Map(s.map(r=>[r.deviceId,r]));return e.map(r=>{const i=n.get(r.deviceId);return!i||i.sequence<=r.sequence?r:i})}const Ts={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 Es(e){return e==="safe-auto"?"Safe Auto":e==="full-access"?"Full Access":e==="custom"?"Custom":"Ask"}function Os(e){return e.replace(/([A-Z])/g," $1").replace(/^./,s=>s.toUpperCase())}function $s(e){const s=e instanceof Error?e.message:String(e);return/agent-disabled/i.test(s)?"Codex Agent was explicitly turned off in Settings.":/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 Ls({hubUrl:e,devices:s,launchRequest:n,variant:r="page",selectedDeviceIds:i=[]}){const f=r==="dock",[c,v]=d.useState(f?i.length>0?"selected":"auto":"all"),[S,g]=d.useState(i),[x,w]=d.useState("auto"),[R,b]=d.useState(""),[T,k]=d.useState([]),[C,z]=d.useState(""),[O,p]=d.useState(""),[$,N]=d.useState(""),[P,U]=d.useState("safe-auto"),[te]=d.useState("custom-default"),[D,fe]=d.useState(Ts),[se,Z]=d.useState([]),[me,G]=d.useState(""),[o,h]=d.useState(!1),[j,L]=d.useState(null),[_,W]=d.useState(!1),[ne,B]=d.useState(""),[je,J]=d.useState(!1),[Ae,X]=d.useState(null),re=d.useRef(null),K=d.useRef(null),ae=d.useRef(null),Re=d.useRef(new Set),Ne=d.useRef(new Set),he=d.useMemo(()=>s.filter(pe).map(a=>a.deviceId),[s]),rt=d.useMemo(()=>ls(st,s,c,S,P,D),[D,s,P,S,c]);d.useEffect(()=>{f&&g(i)},[f,i]),d.useEffect(()=>{n?.deviceId&&(v("selected"),g([n.deviceId]),b(n.instruction),J(!1),window.requestAnimationFrame(()=>{re.current?.focus(),re.current?.setSelectionRange(n.instruction.length,n.instruction.length)}))},[n]);const Y=d.useCallback(a=>{const u=be(a,s);k(y=>y.map(m=>m.type==="task"&&m.batchId===a.batchId?{...m,states:Is(m.states,u),status:a.status}:m)),["running","queued"].includes(a.status)||z(y=>y===a.batchId?"":y)},[s]),Pe=d.useCallback((a,u)=>{Ne.current.has(a.batchId)||(Ne.current.add(a.batchId),k(y=>[...y,{type:"task",id:Q("task"),batchId:a.batchId,agentRunId:u,operation:a.operation||"diagnostics.collect",instruction:a.instructionPreview,states:be(a,s),status:a.status}])),Y(a)},[s,Y]),Ie=d.useCallback((a,u)=>{for(const m of u.taskBatches||[])Pe(m,a);Z(u.approvals||[]);const y=["running","queued","waiting-approval"].includes(u.status);if(X(y?{runId:a,stage:u.stage||u.status,message:u.progressMessage||(u.status==="waiting-approval"?"Review the requested action to continue.":"Codex is preparing the answer.")}:m=>m?.runId===a?null:m),!y&&!Re.current.has(a)){Re.current.add(a);const m=[u.error,u.errorMessage].filter(Boolean).join(" — "),I=u.finalResponse?.trim()||(u.status==="cancelled"?"Codex 작업을 취소했습니다.":m?`Codex 작업이 완료되지 않았습니다: ${m}`:"Codex 작업이 완료되었습니다.");k($e=>[...$e,{type:u.status==="failed"?"error":"agent",id:Q("agent-run-result"),text:I}])}},[Pe]),Te=d.useCallback(async a=>{const u=K.current;if(!(!u||u.id!==a))try{return await u.owner.refresh()}catch(y){if(K.current!==u)return;throw y}},[]);d.useEffect(()=>{if(!O){K.current=null;return}const a=O,u=Ye({poll:m=>bs(e,a,{signal:m,timeoutMs:Ke}),onResult:m=>{Ie(a,m),["running","queued","waiting-approval"].includes(m.status)||(p(I=>I===a?"":I),W(!1))},onError:m=>{B(m instanceof Error?m.message:String(m))}}),y={id:a,owner:u};return K.current=y,()=>{u.stop(),K.current===y&&(K.current=null)}},[O,e,Ie]),d.useEffect(()=>{if(!C){ae.current=null;return}const a=C,u=Ye({poll:m=>Rs(e,a,{signal:m,timeoutMs:Ke}),onResult:m=>{Y(m),["running","queued"].includes(m.status)||z(I=>I===a?"":I)},onError:m=>{B(m instanceof Error?m.message:String(m))}}),y={id:a,owner:u};return ae.current=y,()=>{u.stop(),ae.current===y&&(ae.current=null)}},[C,e,Y]);const Ee=async(a="",u,y=!1)=>{const m=(a||R).trim();if(!m||C||O)return;const I=u||(c==="all"||c==="auto"?he:S.filter(E=>he.includes(E)));if(I.length===0){B("Select at least one connected Client.");return}if(P==="full-access"&&!_&&!y){L({instruction:m,targetIds:I});return}if(k(E=>[...E,{type:"user",id:Q("user"),text:m}]),b(""),J(!1),B(""),I.length===0){k(E=>[...E,{type:"error",id:Q("no-targets"),text:"연결된 대상 장비를 하나 이상 선택해 주세요."}]);return}const De=x==="ask"?`Read-only request. Inspect and answer without changing Client state.
7
7
 
8
8
  ${m}`:x==="plan"?`Plan only. Produce a safe execution plan, but do not change Client state.
9
9
 
@@ -11,4 +11,4 @@ ${m}`:x==="execute"?`Execute this request within the configured VuvoDesk approva
11
11
 
12
12
  ${m}`:m,mt=c==="auto"?`Auto target selection is enabled. Inspect the allowed Clients and use only the most suitable target or targets for this request.
13
13
 
14
- ${De}`:De;try{if(P==="custom"){const oe=await As(e,te,D);if(!oe.ok)throw new Error(oe.error||"Custom Agent policy could not be saved.")}const E=await ks(e,{instruction:mt,deviceIds:I,permissionMode:P,customPolicyId:te});if(!E.ok||!E.runId)throw new Error(E.error||"Codex Agent run could not be started.");J(E.approvals||[]),X({runId:E.runId,stage:E.stage||E.status||"queued",message:E.progressMessage||"Codex request queued on the Hub."}),p(E.runId)}catch(E){k(oe=>[...oe,{type:"error",id:Q("codex-run-error"),text:$s(E)}])}},at=async(a,u)=>{G(a.approvalId);try{const y=await Ss(e,a.runId,a.approvalId,u);if(!y.ok)throw new Error(y.error||"Agent approval could not be applied.");await Te(a.runId)}catch(y){B(y instanceof Error?y.message:String(y))}finally{G("")}},it=async a=>{G(a.approvalId);try{const u=await js(e,a.runId,a.approvalId);if(!u.ok)throw new Error(u.error||"Agent approval could not be rejected.");await Te(a.runId)}catch(u){B(u instanceof Error?u.message:String(u))}finally{G("")}},ot=async(a,u)=>{N(a);try{if(u){const m=await Cs(e,u);for(const I of m.taskBatches||[])Y(I);p(I=>I===u?"":I),X(I=>I?.runId===u?null:I);return}const y=await Ns(e,a);Y(y),M(m=>m===a?"":m)}catch(y){B(y instanceof Error?y.message:String(y))}finally{N("")}},lt=async()=>{if(!(o||!C&&!O)){h(!0);try{const a=await xs(e);if(!a.ok)throw new Error(a.error||"모든 Agent 작업을 취소하지 못했습니다.");M(""),p(""),X(null),J([]),k(u=>u.map(y=>y.type==="task"&&["queued","running"].includes(y.status)?{...y,status:"cancelled",states:y.states.map(m=>["queued","running"].includes(m.status)?{...m,status:"cancelled",stage:"Cancelled",error:"Cancelled by user."}:m)}:y))}catch(a){B(a instanceof Error?a.message:String(a))}finally{h(!1)}}},ct=async a=>{N(a);try{const u=await Ps(e,a);if(!u.ok||!u.batch||!u.batchId)throw new Error(u.error||"재시도하지 못했습니다.");k(y=>y.map(m=>m.type==="task"&&m.batchId===a?{...m,batchId:u.batchId,states:be(u.batch,s),status:u.batch.status}:m)),M(u.batchId)}catch(u){B(u instanceof Error?u.message:String(u))}finally{N("")}},Oe=a=>{b(a),Z(!1),window.requestAnimationFrame(()=>re.current?.focus())},ie=d.useMemo(()=>s.filter(pe),[s]),V=d.useMemo(()=>ie.filter(a=>S.includes(a.deviceId)),[ie,S]),ut=c==="auto"?`Auto · ${ie.length} available`:c==="all"?`All ${ie.length} computers`:V.length===1?de(V[0]):`${V.length} selected`,dt=c==="auto"?"VuvoDesk chooses the best computer for each task.":c==="all"?"The Agent may coordinate every connected computer.":V.length>0?V.map(de).join(" · "):"Select one or more computers on the Wall.",pt=c==="selected"&&V.length===1?["Diagnose this computer","Analyze recent errors","Summarize running applications","Check disk and GPU capacity"]:c==="all"?["Compare all computer health","Find the busiest computer","Check disk capacity everywhere","Divide a task across computers"]:["Use the fastest computer","Find an idle computer","Choose the best GPU","Check all computer health"],gt=c==="selected"?V.length>0?"What should this computer do?":"Choose a computer or use Auto.":c==="all"?"Use all your computers together.":"What should VuvoDesk handle?",ft=c==="auto"?"The Hub Codex Agent can inspect the available computers and choose the best target.":"Describe the outcome. The Hub Codex Agent will plan approved commands and show progress per computer.";return t.jsxs("section",{className:`agents-page ${f?"agents-dock-console":""}`,children:[f&&t.jsxs("header",{className:"agent-console-header",children:[t.jsxs("div",{className:"agent-console-title",children:[t.jsx("span",{className:"agent-console-mark",children:t.jsx(H,{size:16})}),t.jsxs("div",{children:[t.jsx("small",{children:"Hub Codex Agent"}),t.jsx("strong",{children:"Command Console"})]}),t.jsx("i",{children:"Ready"})]}),t.jsxs("section",{className:"agent-console-target","aria-label":"Agent target scope",children:[t.jsxs("div",{children:[t.jsx("span",{children:"Target"}),t.jsx("strong",{children:ut}),t.jsx("small",{children:dt})]}),t.jsxs("div",{className:"agent-console-target-modes",children:[t.jsxs("button",{className:c==="selected"?"active":"",onClick:()=>v("selected"),type:"button",children:[t.jsx(ee,{size:12})," Selected"]}),t.jsxs("button",{className:c==="all"?"active":"",onClick:()=>v("all"),type:"button",children:[t.jsx(ue,{size:12})," All"]}),t.jsxs("button",{type:"button",disabled:!0,title:"Saved Client groups are coming next.",children:[t.jsx(ue,{size:12})," Group"]}),t.jsxs("button",{className:c==="auto"?"active":"",onClick:()=>v("auto"),type:"button",children:[t.jsx(H,{size:12})," Auto"]})]})]}),t.jsx("div",{className:"agent-console-interaction-modes","aria-label":"Agent interaction mode",children:["auto","ask","plan","execute"].map(a=>t.jsxs("button",{className:x===a?"active":"",onClick:()=>w(a),type:"button",children:[a==="auto"?t.jsx(H,{size:12}):a==="execute"?t.jsx(Xe,{size:12}):null,a[0].toUpperCase()+a.slice(1)]},a))})]}),t.jsxs("div",{className:"agents-workspace",children:[(C||O)&&t.jsxs("div",{className:"agents-page-status",children:[t.jsxs("span",{children:[he.length," Clients · ",Es(P)]}),t.jsx("button",{type:"button",className:"agents-stop-all",onClick:()=>{lt()},disabled:o,children:o?"Stopping…":"Stop all"})]}),j&&t.jsx("div",{className:"agents-permission-modal-backdrop",role:"presentation",children:t.jsxs("section",{className:"agents-permission-modal",role:"dialog","aria-modal":"true","aria-labelledby":"full-access-title",children:[t.jsx("span",{className:"agents-permission-modal-icon",children:t.jsx(Se,{size:20})}),t.jsx("h3",{id:"full-access-title",children:"Confirm Full Access"}),t.jsx("p",{children:"Codex may change files, run commands, manage applications, and modify system state on the selected Clients. This run is still limited to the selected devices, the fixed policy, and the tool budget."}),t.jsxs("div",{className:"agents-permission-modal-actions",children:[t.jsx("button",{type:"button",onClick:()=>L(null),children:"Cancel"}),t.jsx("button",{type:"button",className:"danger",onClick:()=>{const a=j;L(null),W(!0),Ee(a.instruction,a.targetIds,!0)},children:"Run with Full Access"})]})]})}),ne&&t.jsx("div",{className:"agents-error",role:"alert",children:ne}),t.jsx(Qt,{items:T,onCancel:ot,onRetry:ct,busyBatchId:$,approvals:se,onApprove:at,onReject:it,busyApprovalId:me,progress:Ae,emptyTitle:f?gt:void 0,emptyBody:f?ft:void 0}),f&&T.length===0&&!Ae&&t.jsx("div",{className:"agent-console-suggestions","aria-label":"Suggested Agent commands",children:pt.map(a=>t.jsx("button",{type:"button",onClick:()=>Oe(a),children:a},a))}),t.jsxs("div",{className:"agents-composer-shell",children:[je&&t.jsx(ms,{devices:s,targetMode:c,selectedIds:S,permissionMode:P,customCategories:D,onSelectPrompt:Oe,onClose:()=>Z(!1)}),t.jsx(Ot,{ref:re,value:R,onChange:b,onSubmit:()=>{Ee()},onOpenSuggestedTasks:()=>Z(a=>!a),suggestedOpen:je,suggestedTaskCount:rt,disabled:!!C||!!O,placeholder:f?"Tell VuvoDesk what outcome you want...":void 0,compact:f})]})]}),!f&&t.jsxs("aside",{className:"agents-target-sidebar","aria-label":"Agent targets and permissions",children:[t.jsx(hs,{devices:s,mode:c,selectedIds:S,onModeChange:v,onToggle:a=>g(u=>u.includes(a)?u.filter(y=>y!==a):[...u,a]),permissionMode:P,onPermissionModeChange:a=>{q(a),a!=="full-access"&&W(!1)}}),P==="custom"&&t.jsxs("section",{className:"agents-custom-policy","aria-label":"Custom Agent permissions",children:[t.jsxs("div",{className:"agents-custom-policy-head",children:[t.jsxs("div",{children:[t.jsx("span",{className:"agents-section-label",children:"Custom policy"}),t.jsx("strong",{children:"Choose what Codex may do automatically."})]}),t.jsx("span",{children:"Denied actions never reach a device."})]}),t.jsx("div",{className:"agents-custom-policy-grid",children:$t.map(a=>t.jsxs("label",{children:[t.jsx("span",{children:Os(a)}),t.jsxs("select",{value:D[a],onChange:u=>fe(y=>({...y,[a]:u.target.value})),children:[t.jsx("option",{value:"allow",children:"Allow automatically"}),t.jsx("option",{value:"ask",children:"Ask every time"}),t.jsx("option",{value:"deny",children:"Deny"})]})]},a))})]})]})]})}export{Ms as AgentsPage};
14
+ ${De}`:De;try{if(P==="custom"){const oe=await As(e,te,D);if(!oe.ok)throw new Error(oe.error||"Custom Agent policy could not be saved.")}const E=await ks(e,{instruction:mt,deviceIds:I,permissionMode:P,customPolicyId:te});if(!E.ok||!E.runId)throw new Error(E.error||"Codex Agent run could not be started.");Z(E.approvals||[]),X({runId:E.runId,stage:E.stage||E.status||"queued",message:E.progressMessage||"Codex request queued on the Hub."}),p(E.runId)}catch(E){k(oe=>[...oe,{type:"error",id:Q("codex-run-error"),text:$s(E)}])}},at=async(a,u)=>{G(a.approvalId);try{const y=await Ss(e,a.runId,a.approvalId,u);if(!y.ok)throw new Error(y.error||"Agent approval could not be applied.");await Te(a.runId)}catch(y){B(y instanceof Error?y.message:String(y))}finally{G("")}},it=async a=>{G(a.approvalId);try{const u=await js(e,a.runId,a.approvalId);if(!u.ok)throw new Error(u.error||"Agent approval could not be rejected.");await Te(a.runId)}catch(u){B(u instanceof Error?u.message:String(u))}finally{G("")}},ot=async(a,u)=>{N(a);try{if(u){const m=await Cs(e,u);for(const I of m.taskBatches||[])Y(I);p(I=>I===u?"":I),X(I=>I?.runId===u?null:I);return}const y=await Ns(e,a);Y(y),z(m=>m===a?"":m)}catch(y){B(y instanceof Error?y.message:String(y))}finally{N("")}},lt=async()=>{if(!(o||!C&&!O)){h(!0);try{const a=await xs(e);if(!a.ok)throw new Error(a.error||"모든 Agent 작업을 취소하지 못했습니다.");z(""),p(""),X(null),Z([]),k(u=>u.map(y=>y.type==="task"&&["queued","running"].includes(y.status)?{...y,status:"cancelled",states:y.states.map(m=>["queued","running"].includes(m.status)?{...m,status:"cancelled",stage:"Cancelled",error:"Cancelled by user."}:m)}:y))}catch(a){B(a instanceof Error?a.message:String(a))}finally{h(!1)}}},ct=async a=>{N(a);try{const u=await Ps(e,a);if(!u.ok||!u.batch||!u.batchId)throw new Error(u.error||"재시도하지 못했습니다.");k(y=>y.map(m=>m.type==="task"&&m.batchId===a?{...m,batchId:u.batchId,states:be(u.batch,s),status:u.batch.status}:m)),z(u.batchId)}catch(u){B(u instanceof Error?u.message:String(u))}finally{N("")}},Oe=a=>{b(a),J(!1),window.requestAnimationFrame(()=>re.current?.focus())},ie=d.useMemo(()=>s.filter(pe),[s]),V=d.useMemo(()=>ie.filter(a=>S.includes(a.deviceId)),[ie,S]),ut=c==="auto"?`Auto · ${ie.length} available`:c==="all"?`All ${ie.length} computers`:V.length===1?de(V[0]):`${V.length} selected`,dt=c==="auto"?"VuvoDesk chooses the best computer for each task.":c==="all"?"The Agent may coordinate every connected computer.":V.length>0?V.map(de).join(" · "):"Select one or more computers on the Wall.",pt=c==="selected"&&V.length===1?["Diagnose this computer","Analyze recent errors","Summarize running applications","Check disk and GPU capacity"]:c==="all"?["Compare all computer health","Find the busiest computer","Check disk capacity everywhere","Divide a task across computers"]:["Use the fastest computer","Find an idle computer","Choose the best GPU","Check all computer health"],gt=c==="selected"?V.length>0?"What should this computer do?":"Choose a computer or use Auto.":c==="all"?"Use all your computers together.":"What should VuvoDesk handle?",ft=c==="auto"?"The Hub Codex Agent can inspect the available computers and choose the best target.":"Describe the outcome. The Hub Codex Agent will plan approved commands and show progress per computer.";return t.jsxs("section",{className:`agents-page ${f?"agents-dock-console":""}`,children:[f&&t.jsxs("header",{className:"agent-console-header",children:[t.jsxs("div",{className:"agent-console-title",children:[t.jsx("span",{className:"agent-console-mark",children:t.jsx(H,{size:16})}),t.jsxs("div",{children:[t.jsx("small",{children:"Hub Codex Agent"}),t.jsx("strong",{children:"Command Console"})]}),t.jsx("i",{children:"Ready"})]}),t.jsxs("section",{className:"agent-console-target","aria-label":"Agent target scope",children:[t.jsxs("div",{children:[t.jsx("span",{children:"Target"}),t.jsx("strong",{children:ut}),t.jsx("small",{children:dt})]}),t.jsxs("div",{className:"agent-console-target-modes",children:[t.jsxs("button",{className:c==="selected"?"active":"",onClick:()=>v("selected"),type:"button",children:[t.jsx(ee,{size:12})," Selected"]}),t.jsxs("button",{className:c==="all"?"active":"",onClick:()=>v("all"),type:"button",children:[t.jsx(ue,{size:12})," All"]}),t.jsxs("button",{type:"button",disabled:!0,title:"Saved Client groups are coming next.",children:[t.jsx(ue,{size:12})," Group"]}),t.jsxs("button",{className:c==="auto"?"active":"",onClick:()=>v("auto"),type:"button",children:[t.jsx(H,{size:12})," Auto"]})]})]}),t.jsx("div",{className:"agent-console-interaction-modes","aria-label":"Agent interaction mode",children:["auto","ask","plan","execute"].map(a=>t.jsxs("button",{className:x===a?"active":"",onClick:()=>w(a),type:"button",children:[a==="auto"?t.jsx(H,{size:12}):a==="execute"?t.jsx(Xe,{size:12}):null,a[0].toUpperCase()+a.slice(1)]},a))})]}),t.jsxs("div",{className:"agents-workspace",children:[(C||O)&&t.jsxs("div",{className:"agents-page-status",children:[t.jsxs("span",{children:[he.length," Clients · ",Es(P)]}),t.jsx("button",{type:"button",className:"agents-stop-all",onClick:()=>{lt()},disabled:o,children:o?"Stopping…":"Stop all"})]}),j&&t.jsx("div",{className:"agents-permission-modal-backdrop",role:"presentation",children:t.jsxs("section",{className:"agents-permission-modal",role:"dialog","aria-modal":"true","aria-labelledby":"full-access-title",children:[t.jsx("span",{className:"agents-permission-modal-icon",children:t.jsx(Se,{size:20})}),t.jsx("h3",{id:"full-access-title",children:"Confirm Full Access"}),t.jsx("p",{children:"Codex may change files, run commands, manage applications, and modify system state on the selected Clients. This run is still limited to the selected devices, the fixed policy, and the tool budget."}),t.jsxs("div",{className:"agents-permission-modal-actions",children:[t.jsx("button",{type:"button",onClick:()=>L(null),children:"Cancel"}),t.jsx("button",{type:"button",className:"danger",onClick:()=>{const a=j;L(null),W(!0),Ee(a.instruction,a.targetIds,!0)},children:"Run with Full Access"})]})]})}),ne&&t.jsx("div",{className:"agents-error",role:"alert",children:ne}),t.jsx(Qt,{items:T,onCancel:ot,onRetry:ct,busyBatchId:$,approvals:se,onApprove:at,onReject:it,busyApprovalId:me,progress:Ae,emptyTitle:f?gt:void 0,emptyBody:f?ft:void 0}),f&&T.length===0&&!Ae&&t.jsx("div",{className:"agent-console-suggestions","aria-label":"Suggested Agent commands",children:pt.map(a=>t.jsx("button",{type:"button",onClick:()=>Oe(a),children:a},a))}),t.jsxs("div",{className:"agents-composer-shell",children:[je&&t.jsx(ms,{devices:s,targetMode:c,selectedIds:S,permissionMode:P,customCategories:D,onSelectPrompt:Oe,onClose:()=>J(!1)}),t.jsx(Ot,{ref:re,value:R,onChange:b,onSubmit:()=>{Ee()},onOpenSuggestedTasks:()=>J(a=>!a),suggestedOpen:je,suggestedTaskCount:rt,disabled:!!C||!!O,placeholder:f?"Tell VuvoDesk what outcome you want...":void 0,compact:f})]})]}),!f&&t.jsxs("aside",{className:"agents-target-sidebar","aria-label":"Agent targets and permissions",children:[t.jsx(hs,{devices:s,mode:c,selectedIds:S,onModeChange:v,onToggle:a=>g(u=>u.includes(a)?u.filter(y=>y!==a):[...u,a]),permissionMode:P,onPermissionModeChange:a=>{U(a),a!=="full-access"&&W(!1)}}),P==="custom"&&t.jsxs("section",{className:"agents-custom-policy","aria-label":"Custom Agent permissions",children:[t.jsxs("div",{className:"agents-custom-policy-head",children:[t.jsxs("div",{children:[t.jsx("span",{className:"agents-section-label",children:"Custom policy"}),t.jsx("strong",{children:"Choose what Codex may do automatically."})]}),t.jsx("span",{children:"Denied actions never reach a device."})]}),t.jsx("div",{className:"agents-custom-policy-grid",children:$t.map(a=>t.jsxs("label",{children:[t.jsx("span",{children:Os(a)}),t.jsxs("select",{value:D[a],onChange:u=>fe(y=>({...y,[a]:u.target.value})),children:[t.jsx("option",{value:"allow",children:"Allow automatically"}),t.jsx("option",{value:"ask",children:"Ask every time"}),t.jsx("option",{value:"deny",children:"Deny"})]})]},a))})]})]})]})}export{Ls as AgentsPage};
@@ -0,0 +1 @@
1
+ import{j as e}from"./pwa-startup-xxamnV7P.js";import{r as i,R as x,E as j,D as u,f as g,h as f}from"./icons-CuXJn-Hz.js";import{l as b,c as d,d as y}from"./HubApp-AhKLyz3K.js";import"./pwa-bootstrap-BCid3CYk.js";import"./preload-helper-DD1OZmLC.js";import"./MonitorStackIcon-DBuXI_Oa.js";import"./supabase-C7qjtLN3.js";import"./frame-lifecycle-esOdP-EY.js";function z({hubUrl:s,onToast:n}){const[o,m]=i.useState([]),[h,c]=i.useState(!0),r=i.useCallback(async()=>{c(!0);try{m((await b(s)).captures||[])}catch(t){n(t instanceof Error?t.message:String(t))}finally{c(!1)}},[s,n]);i.useEffect(()=>{r()},[r]);const p=async t=>{const a=d(t.id,s);if(navigator.share)try{await navigator.share({title:t.fileName,url:a});return}catch{}window.open(a,"_blank","noopener,noreferrer")};return e.jsxs("section",{className:"capture-gallery",children:[e.jsxs("header",{children:[e.jsxs("div",{children:[e.jsx("span",{className:"settings-eyebrow",children:"Capture Gallery"}),e.jsx("h2",{children:"Saved captures"})]}),e.jsxs("button",{className:"text-button",onClick:()=>{r()},type:"button",children:[e.jsx(x,{size:15})," Refresh"]})]}),h?e.jsx("p",{className:"settings-help",children:"Loading captures..."}):o.length===0?e.jsx("p",{className:"settings-help",children:"No captures saved yet."}):e.jsx("div",{className:"capture-gallery-grid",children:o.map(t=>{const a=d(t.id,s);return e.jsxs("article",{className:"capture-gallery-card",children:[t.mimeType.startsWith("image/")?e.jsx("img",{src:a,alt:t.target.label}):e.jsx("video",{src:a,controls:!0,preload:"metadata"}),e.jsxs("div",{className:"capture-gallery-card-body",children:[e.jsx("strong",{children:t.fileName}),e.jsxs("small",{children:[t.target.label," · ",new Date(t.createdAt).toLocaleString()," · ",Math.ceil(t.sizeBytes/1024)," KB"]}),e.jsxs("div",{children:[e.jsx("button",{className:"icon-button",title:"Open","aria-label":"Open",onClick:()=>window.open(a,"_blank","noopener,noreferrer"),type:"button",children:e.jsx(j,{size:15})}),e.jsx("a",{className:"icon-button",title:"Download","aria-label":"Download",href:`${a}?download=1`,download:t.fileName,children:e.jsx(u,{size:15})}),e.jsx("button",{className:"icon-button",title:"Share","aria-label":"Share",onClick:()=>{p(t)},type:"button",children:e.jsx(g,{size:15})}),e.jsx("button",{className:"icon-button danger",title:"Delete","aria-label":"Delete",onClick:()=>{window.confirm(`Delete ${t.fileName}?`)&&y(t.id,s).then(()=>r()).catch(l=>n(l instanceof Error?l.message:String(l)))},type:"button",children:e.jsx(f,{size:15})})]})]})]},t.id)})})]})}export{z as CaptureGallery};
@@ -0,0 +1 @@
1
+ import{j as e}from"./pwa-startup-xxamnV7P.js";import{r,D as y,P as j,R as b}from"./icons-CuXJn-Hz.js";import"./pwa-bootstrap-BCid3CYk.js";function D(t){if(!t)return"Reading the installed version...";const n=String(t.errorCode||t.error||"");switch(t.state){case"checking":return"Checking for a newer VuvoDesk version...";case"available":return`Version ${t.availableVersion||""} is available.`;case"downloading":return`Downloading version ${t.availableVersion||""} (${Math.round(t.progress||0)}%).`;case"downloaded":return`Version ${t.availableVersion||""} is ready. Restart to install it.`;case"installing":return"Closing VuvoDesk safely and starting the update...";case"current":return"This computer has the latest VuvoDesk version.";case"error":return/runtime-recovery-failed/i.test(n)?"The local VuvoDesk service could not restart. Quit VuvoDesk completely and reopen it.":/owner-cleanup-stuck|owner-reset-failed/i.test(n)?"The Windows update service could not reset. Quit VuvoDesk completely, reopen it, and check again.":/installer-launch-failed/i.test(n)?"The installer could not start. VuvoDesk restored its local service so you can retry.":/version-mismatch/i.test(n)?"The downloaded update did not match the expected version. VuvoDesk will retry safely.":/stalled|timed-out/i.test(n)?"The update connection stopped responding. VuvoDesk will retry automatically.":"The update server could not be reached. VuvoDesk will retry automatically.";case"development":return"Desktop updates are available in an installed VuvoDesk build.";case"unavailable":return"Updates are not available for this desktop build.";default:return"VuvoDesk checks once when the desktop app starts."}}function R(){const t=window.liveDesk?.updates,n=window.liveDesk?.app,[s,i]=r.useState(null),[f,u]=r.useState(!1),[o,p]=r.useState(null),[g,h]=r.useState(!1);if(r.useEffect(()=>{if(!t)return;let a=!0;t.getStatus?.().then(c=>{a&&i(c)});const d=t.onStatus?.(c=>{a&&i(c)});return()=>{a=!1,d?.()}},[t]),r.useEffect(()=>{if(!n?.getAutoStart)return;let a=!0;return n.getAutoStart().then(d=>{a&&p(d)}),()=>{a=!1}},[n]),!t)return null;const v=s?.state==="downloaded"||s?.downloaded===!0,k=!!s?.reopenRequired||/runtime-recovery-failed|owner-cleanup-stuck|owner-reset-failed/i.test(String(s?.errorCode||"")),l=f||s?.state==="checking"||s?.state==="downloading"||s?.state==="installing",m=s?.channel==="dev"?"Development":s?.channel==="stable"?"Stable":s?.channel||"Unknown",x=async()=>{u(!0);try{const a=v?await t.install?.():await t.check?.();a&&i(a)}finally{u(!1)}},w=async a=>{if(n?.setAutoStart){h(!0);try{p(await n.setAutoStart(a))}finally{h(!1)}}};return e.jsxs("section",{className:"settings-section-card desktop-update-card",children:[e.jsxs("div",{className:"settings-section-heading",children:[e.jsxs("div",{children:[e.jsx("span",{children:"Desktop app"}),e.jsx("h3",{children:"VuvoDesk updates"})]}),e.jsx(y,{size:20})]}),e.jsx("p",{className:"settings-help","aria-live":"polite",children:D(s)}),e.jsxs("div",{className:"desktop-update-meta",children:[e.jsx("span",{children:"Installed"}),e.jsx("strong",{children:s?.currentVersion||"Unknown"}),e.jsx("span",{children:"Channel"}),e.jsx("strong",{children:m}),s?.availableVersion&&e.jsxs(e.Fragment,{children:[e.jsx("span",{children:"Available"}),e.jsx("strong",{children:s.availableVersion})]})]}),n?.getAutoStart&&e.jsxs("div",{className:"desktop-auto-start-setting",children:[e.jsxs("div",{className:"desktop-auto-start-copy",children:[e.jsx(j,{size:18}),e.jsxs("span",{children:[e.jsx("strong",{children:"Start automatically after sign-in"}),e.jsx("small",{children:"Reconnect this computer quietly after Windows, macOS, or Linux sign-in."})]})]}),e.jsxs("label",{className:"settings-toggle desktop-auto-start-toggle",children:[e.jsx("input",{type:"checkbox",checked:o?.enabled??!0,onChange:a=>{w(a.target.checked)},disabled:!o?.supported||g}),e.jsx("span",{children:o?.enabled===!1?"Off":"On"})]}),o?.error&&e.jsx("p",{className:"desktop-auto-start-error",role:"alert",children:"Automatic start could not be updated. VuvoDesk will retry next time it opens."})]}),e.jsxs("button",{className:"settings-reset desktop-update-action",onClick:()=>{x()},disabled:l||k,type:"button",children:[e.jsx(b,{size:15,className:l?"desktop-update-spin":""}),k?"Reopen VuvoDesk":v?"Restart and update":l?"Updating...":"Check for updates"]})]})}export{R as DesktopUpdatePanel};