hanoman 0.9.28 → 0.9.30

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 (35) hide show
  1. package/README.md +5 -2
  2. package/dist/build-info.json +3 -3
  3. package/dist/cli.js +360 -90
  4. package/dist/server.js +2904 -1418
  5. package/docs/agent-integration.md +100 -6
  6. package/package.json +1 -1
  7. package/prisma/migrations/20261014130000_cron_report/migration.sql +19 -0
  8. package/prisma/schema.prisma +25 -0
  9. package/scripts/vps/provision.sh +26 -3
  10. package/web/assets/{DalangHanomanScreen-C3UMPHFg.js → DalangHanomanScreen-Fd7_DcSP.js} +1 -1
  11. package/web/assets/{DocPreviewModal-Bp5stb4M.js → DocPreviewModal-SMRN2K98.js} +1 -1
  12. package/web/assets/{DocsWorkspace-C9yFxK4D.js → DocsWorkspace-pxj0N6QW.js} +1 -1
  13. package/web/assets/{IdeScreen-CRFRAP6E.js → IdeScreen-Cr9Vqdrc.js} +1 -1
  14. package/web/assets/LeadScreen-CQXpJy0y.js +1 -0
  15. package/web/assets/{ReviewScreen-CMHOlmgX.js → ReviewScreen-B7NNEjxk.js} +1 -1
  16. package/web/assets/SchedulerScreen-D3rPdS-F.js +1 -0
  17. package/web/assets/SettingsScreen-Bx13PWKQ.js +62 -0
  18. package/web/assets/{TeamScreen-D4tA34Mj.js → TeamScreen-BBAsYLpT.js} +1 -1
  19. package/web/assets/TerminalScreen-DpVp4h1n.js +2 -0
  20. package/web/assets/{TriageScreen-B8ZCexaX.js → TriageScreen-wAPnttRe.js} +1 -1
  21. package/web/assets/{VpsScreen-BCrLfZh7.js → VpsScreen-DeQVx9Jy.js} +2 -2
  22. package/web/assets/fields-qnBoIMR_.js +1 -0
  23. package/web/assets/index-BQw6xQI4.js +1012 -0
  24. package/web/assets/{index-BqAP-VDq.css → index-C3KwOJxI.css} +2 -2
  25. package/web/assets/{live-DuBdI0MZ.js → live-CONO0GTu.js} +1 -1
  26. package/web/assets/{sched-lead-shared-QqbtjoVv.js → sched-lead-shared-CDR0pOqs.js} +1 -1
  27. package/web/assets/{scheduler-CQt-VP9-.css → scheduler-D64RlGvZ.css} +1 -1
  28. package/web/assets/settings-rebase-CpaFw0Tm.js +1 -0
  29. package/web/index.html +2 -2
  30. package/web/assets/LeadScreen-DfVUawoK.js +0 -1
  31. package/web/assets/SchedulerScreen-CK5QvX5c.js +0 -1
  32. package/web/assets/SettingsScreen-D7P5JgjU.js +0 -62
  33. package/web/assets/TerminalScreen-CKySL63X.js +0 -2
  34. package/web/assets/index-BRR3JL_o.js +0 -1012
  35. package/web/assets/settings-rebase-Cbh-JGJ-.js +0 -1
@@ -1,2 +1,2 @@
1
- import{a1 as be,h as g,v as fe,d as me,aU as E,aV as Y,j as e,M as ye,c as Oe,aW as ie,aS as ue,m as F,I as ne,x as Re,B as y,i as T,q as Se,r as Me,aX as Ue,aI as _e,e as G,f as X,aY as He,l as Fe,ap as Ke,R as We,X as qe,O as Ge,W as Xe}from"./index-BRR3JL_o.js";import{R as c}from"./react-DfGhg7ZW.js";import"./markdown-CWEY34jk.js";import"./xterm-3VOAfa_q.js";const Ye=10*6e4,we=(s,t)=>!!s.lastSeenAt&&t-new Date(s.lastSeenAt).getTime()<Ye;function he(s,t=Date.now()){const l=s.lastSeenAt?we(s,t)?{state:"done",text:"terhubung"}:{state:"gagal",text:"tidak terjangkau"}:{state:"todo",text:"belum terhubung"},o=s.lastAuditAt?{state:"done",text:`diaudit ${be(s.lastAuditAt,t)||"—"}`}:{state:"todo",text:"belum diaudit"},m=s.lastAuditAt&&s.hardened?{state:"done",text:"diperkuat"}:{state:"todo",text:"belum diperkuat"};return[{key:"terhubung",label:"Terhubung",...l},{key:"diaudit",label:"Diaudit",...o},{key:"diperkuat",label:"Diperkuat",...m}]}const Qe=(s,t)=>{const l=new Set(s);return l.size===new Set(t).size&&t.every(o=>l.has(o))};function ke(s,t){return s.length>0&&t!==null&&Qe(s,t)}const Je=s=>s==null?"Skor —":`Skor ${s}%`,Ze={pass:"check",fail:"x",warn:"alert-triangle",na:"minus",unknown:"circle"},es={pass:"var(--leaf-600)",fail:"var(--clay-600)",warn:"var(--status-warn)",na:"var(--text-subtle)",unknown:"var(--text-subtle)"},ss={critical:"var(--clay-600)",high:"var(--status-warn)",medium:"var(--text-subtle)",low:"var(--text-subtle)"},te={AUTO:"Otomatis",AUDIT:"Audit",INFO:"Info"};function re({text:s,color:t}){return e.jsx("span",{className:"vps-badge",style:{color:t,borderColor:t},children:s})}function Ne({score:s}){const t=s>=90?"vps-tone-ok":s>=50?"vps-tone-warn":"vps-tone-bad";return e.jsxs("div",{className:"vps-bar-wrap",children:[e.jsx("div",{className:"vps-bar",children:e.jsx("div",{className:`vps-bar-fill ${t}`,style:{width:`${s}%`}})}),e.jsxs("span",{className:"vps-bar-num",children:[s,"%"]})]})}function as({item:s,busy:t,selected:l,onToggle:o,onNa:m,onAttest:h}){const u=s.mode==="AUTO"&&!s.na,x=s.status==="fail"||s.status==="warn"||!!s.drifted;return e.jsxs("div",{"data-testid":`item-${s.id}`,title:`${te[s.mode]} · ${Y[s.severity]}`,className:`vps-item${s.na?" vps-item-na":""}`,children:[u?e.jsx("span",{className:"vps-touch",children:e.jsx("input",{type:"checkbox","aria-label":`Pilih ${s.title}`,checked:l,onChange:()=>o(s)})}):e.jsx("span",{className:"vps-item-gap"}),e.jsx(ne,{name:Ze[s.status],size:14,color:es[s.status]}),e.jsx("span",{className:"vps-item-title",children:s.title}),s.drifted&&e.jsx(re,{text:"drift",color:"var(--clay-600)"}),x&&e.jsx(re,{text:Y[s.severity],color:ss[s.severity]}),s.mode==="INFO"&&!s.attested&&e.jsx(y,{size:"sm",variant:"ghost",leftIcon:"check-circle",loading:t,onClick:()=>h(s),children:"Tandai terpenuhi"}),e.jsx(y,{size:"sm",variant:"ghost",leftIcon:s.na?"rotate-ccw":"minus-circle",loading:t,onClick:()=>m(s,!s.na),children:s.na?"Batal N/A":"N/A"})]})}const ce={section:"",mode:"",status:"",severity:""};function le({value:s,onChange:t,options:l,label:o}){return e.jsxs("select",{"aria-label":o,value:s,onChange:m=>t(m.target.value),className:"vps-select vps-touch-select",children:[e.jsxs("option",{value:"",children:[o,": semua"]}),l.map(([m,h])=>e.jsx("option",{value:m,children:h},m))]})}function ts(s){let t=0,l=0,o=0,m=0;for(const x of s)x.status==="fail"?t++:x.status==="warn"?l++:x.status==="unknown"&&o++,x.drifted&&m++;const h=x=>x.charAt(0).toLowerCase()+x.slice(1),u=[t&&`${t} ${h(E.fail)}`,l&&`${l} ${h(E.warn)}`,o&&`${o} ${h(E.unknown)}`].filter(Boolean);return{text:u.length?u.join(" · "):`semua ${h(E.pass)}`,drift:m}}function ns({section:s,items:t,expanded:l,onToggle:o,busy:m,selected:h,onToggleItem:u,onNa:x,onAttest:b,onSectionNa:j}){const p=ts(s.items),f=!!s.suggestion&&!s.suggestion.applicable;return e.jsxs("div",{className:"vps-section",children:[e.jsxs("button",{"data-testid":`section-${s.id}`,"aria-expanded":l,onClick:()=>o(s.id),className:`vps-section-head${l?" vps-section-open":""}`,children:[e.jsx(ne,{name:l?"chevron-down":"chevron-right",size:15,color:"var(--text-subtle)"}),e.jsx("span",{className:"vps-section-icon",children:s.icon}),e.jsx("span",{className:"vps-section-title",children:s.title}),e.jsx("span",{className:"vps-section-sum",children:p.text}),p.drift>0&&e.jsx(re,{text:"drift",color:"var(--clay-600)"}),f&&e.jsx(re,{text:"saran N/A",color:"var(--brass-700)"}),e.jsx(Ne,{score:s.score})]}),l&&e.jsxs("div",{className:"vps-section-body",children:[f&&e.jsxs("div",{"data-testid":`suggestion-${s.id}`,className:"vps-suggest",children:[e.jsx(ne,{name:"info",size:13,color:"var(--brass-700)"}),e.jsxs("span",{className:"vps-suggest-text",children:["Stack tak terdeteksi (",s.suggestion.detail,") — kemungkinan N/A. Cek Docker manual bila ragu."]}),e.jsx(y,{size:"sm",variant:"ghost",leftIcon:"minus-circle",loading:m===`section:${s.id}`,onClick:()=>j(s),children:"Tandai seksi N/A"})]}),t.map(S=>e.jsx(as,{item:S,busy:m===S.id,selected:h.has(S.id),onToggle:u,onNa:x,onAttest:b},S.id))]})]})}function is({vpsId:s,vpsName:t,lastAuditAt:l,health:o,summary:m,provisioning:h,access:u,onScore:x,onClose:b,onToast:j}){const[p,f]=c.useState(null),[S,L]=c.useState("loading"),[A,B]=c.useState(""),[N,R]=c.useState("ringkasan"),[d,z]=c.useState(ce),[K,W]=c.useState(""),[Q,q]=c.useState(new Set),[M,$]=c.useState(null),[C,O]=c.useState(new Set),[D,U]=c.useState(null),[J,a]=c.useState(""),v=c.useRef(x);v.current=x;const I=c.useCallback(()=>{L("loading"),g.vpsChecklist(s).then(i=>{var k;f(i),L("ready"),(k=v.current)==null||k.call(v,i.scoreTotal)}).catch(i=>{B(fe(i,"tak diketahui")),L("error")})},[s]);c.useEffect(()=>{I(),O(new Set),U(null),q(new Set),W(""),z(ce)},[I]);const Z=i=>{U(null),O(k=>{const r=new Set(k);return r.has(i.id)?r.delete(i.id):r.add(i.id),r})},_=()=>{O(new Set),U(null)},ee=i=>q(k=>{const r=new Set(k);return r.has(i)?r.delete(i):r.add(i),r}),{confirm:se,dialog:n}=me(),w=(D==null?void 0:D.forIds)??null,V=ke([...C],w);async function Ce(){const i=[...C];a("preview");try{U({steps:(await g.remediatePreview(s,i)).steps,forIds:i})}catch(k){j(T("membuat pratinjau remediasi",k),"err","x-circle")}finally{a("")}}async function Pe(){const i=[...C];if(!ke(i,w))return;const r=((p==null?void 0:p.sections.flatMap(P=>P.items))??[]).filter(P=>C.has(P.id));if(await se({title:`Terapkan ${i.length} item AUTO ke VPS ini?`,message:"Remediasi dijalankan langsung di server yang terdaftar.",impact:[...r.map(P=>`${P.id} · ${P.title}`),"Langkahnya idempoten dan anti-lockout.","Checklist diaudit ulang setelah selesai."],confirmLabel:"Terapkan",icon:"shield"})){a("apply");try{await g.remediate(s,i),_(),I(),j("Remediasi diterapkan · audit ulang","ok","shield")}catch(P){j(T("menerapkan remediasi",P),"err","x-circle")}finally{a("")}}}async function pe(i,k,r){$(i.id);try{await k(),I(),j(r,"ok","shield")}catch(P){j(T(`memperbarui ${i.id}`,P),"err","x-circle")}finally{$(null)}}const Ae=(i,k)=>pe(i,()=>g.markNa(s,i.id,k,k?"ditandai dari checklist":void 0),k?`${i.id} ditandai N/A`:`${i.id} kembali applicable`),Ie=i=>pe(i,()=>g.attestItem(s,i.id),`${i.id} ditandai terpenuhi`);async function Le(i){const k=i.items.map(r=>r.id);if(await se({title:`Tandai ${k.length} item seksi "${i.title}" sebagai N/A?`,message:"Stack-nya tak terdeteksi — cek Docker manual bila ragu.",confirmLabel:"Tandai N/A",icon:"shield"})){$(`section:${i.id}`);try{await g.markNaBulk(s,k,!0,"app-layer: stack tak terdeteksi"),I(),j(`Seksi ${i.title} ditandai N/A`,"ok","shield")}catch(r){j(T(`menandai seksi ${i.title} sebagai N/A`,r),"err","x-circle")}finally{$(null)}}}const ae=K.trim().toLowerCase(),oe=!!(d.section||d.mode||d.status||d.severity)||ae!=="",Ve=i=>(!d.section||i.section===d.section)&&(!d.mode||i.mode===d.mode)&&(!d.status||i.status===d.status)&&(!d.severity||i.severity===d.severity)&&(!ae||i.title.toLowerCase().includes(ae)||i.id.toLowerCase().includes(ae)||(i.code??"").toLowerCase().includes(ae)),H=i=>k=>z(r=>({...r,[i]:k})),Te=i=>{var k;return((k=p==null?void 0:p.sections.find(r=>r.id===i))==null?void 0:k.title)??i},De=[...d.section?[{key:"section",label:`Seksi: ${Te(d.section)}`,onRemove:()=>H("section")("")}]:[],...d.mode?[{key:"mode",label:`Mode: ${te[d.mode]}`,onRemove:()=>H("mode")("")}]:[],...d.status?[{key:"status",label:`Status: ${E[d.status]}`,onRemove:()=>H("status")("")}]:[],...d.severity?[{key:"severity",label:`Severity: ${Y[d.severity]}`,onRemove:()=>H("severity")("")}]:[]],Be=()=>{z(ce),W("")};function ze(){if(S==="loading")return e.jsx(F,{kind:"loading",compact:!0,title:"Memuat checklist…"});if(S==="error"||!p)return e.jsx(F,{kind:"error",compact:!0,title:"Gagal memuat checklist",hint:A,action:I});const i=p.sections.reduce((r,P)=>r+P.items.filter(Ee=>Ee.drifted).length,0),k=p.sections.map(r=>({section:r,matched:r.items.filter(Ve)})).filter(r=>!oe||r.matched.length>0);return e.jsxs("div",{children:[e.jsxs("div",{className:"vps-check-head",children:[e.jsxs("div",{className:"vps-check-score",children:[e.jsxs("span",{"data-testid":"score-total",className:"vps-check-score-num",children:[p.scoreTotal,"%"]}),e.jsx("div",{className:"vps-check-score-bar",children:e.jsx(Ne,{score:p.scoreTotal})}),e.jsx(ue,{size:11,tone:"subtle",children:"skor kepatuhan"})]}),i>0&&e.jsxs("div",{"data-testid":"drift-summary",className:"vps-drift",children:[e.jsx(ne,{name:"alert-triangle",size:14,color:"var(--clay-600)"}),i," item drift (regresi) sejak audit sebelumnya"]}),e.jsx(Re,{label:"Filter checklist",search:{value:K,onChange:W,label:"cari item",placeholder:"mis. ssh atau 5.2.1"},chips:De,filtersLabel:"Filter",onReset:Be,filters:e.jsxs("div",{className:"vps-filter-fields",children:[e.jsx(le,{label:"seksi",value:d.section,onChange:H("section"),options:p.sections.map(r=>[r.id,r.title])}),e.jsx(le,{label:"mode",value:d.mode,onChange:H("mode"),options:[["AUTO",te.AUTO],["AUDIT",te.AUDIT],["INFO",te.INFO]]}),e.jsx(le,{label:"status",value:d.status,onChange:H("status"),options:[["pass",E.pass],["fail",E.fail],["warn",E.warn],["na",E.na],["unknown",E.unknown]]}),e.jsx(le,{label:"severity",value:d.severity,onChange:H("severity"),options:[["critical",Y.critical],["high",Y.high],["medium",Y.medium],["low",Y.low]]})]})}),C.size>0&&e.jsxs("div",{className:"vps-remedi",role:"group","aria-label":"Alur perbaikan",children:[e.jsxs("ol",{className:"vps-remedi-steps",children:[e.jsxs("li",{"data-state":"done",children:["1 Pilih · ",C.size," item AUTO"]}),e.jsx("li",{"data-state":D?"done":"active",children:"2 Pratinjau"}),e.jsx("li",{"data-state":V?"active":"todo",children:"3 Terapkan"})]}),e.jsxs("div",{className:"vps-remedi-actions",children:[e.jsx(y,{size:"sm",variant:"secondary",leftIcon:"eye",loading:J==="preview",onClick:Ce,children:"Pratinjau"}),e.jsx(y,{size:"sm",leftIcon:"shield",loading:J==="apply",disabled:!V,onClick:Pe,children:"Terapkan"}),e.jsx(y,{size:"sm",variant:"ghost",onClick:_,children:"Batal"})]}),!V&&e.jsx("div",{className:"vps-remedi-hint",children:"Buat pratinjau dulu. Terapkan hanya memakai pratinjau untuk pilihan ini."})]}),D&&e.jsxs("div",{"data-testid":"remediate-preview",className:"vps-preview",children:[e.jsx("div",{className:"vps-preview-title",children:"Pratinjau (dry-run) — belum diterapkan. Mengubah pilihan membatalkannya."}),D.steps.map(r=>e.jsxs("div",{className:"vps-preview-line",children:[r.item," · ",r.status," ",r.detail]},r.item))]})]}),k.length===0?e.jsx(F,{kind:"empty",compact:!0,title:"Tidak ada item cocok",hint:"Ubah kata kunci atau reset filter."}):k.map(({section:r,matched:P})=>e.jsx(ns,{section:r,items:oe?P:r.items,expanded:oe?!0:Q.has(r.id),onToggle:ee,busy:M,selected:C,onToggleItem:Z,onNa:Ae,onAttest:Ie,onSectionNa:Le},r.id))]})}return e.jsxs(ye,{open:!0,width:960,icon:"clipboard-list",eyebrow:"Detail server",title:t??"VPS",onClose:b,children:[e.jsxs(Oe,{"aria-label":"Bagian detail VPS",value:N,className:"vps-tabs",tabs:[{value:"ringkasan",label:"Ringkasan"},{value:"checklist",label:"Checklist"},{value:"pemasangan",label:"Pemasangan"},{value:"akses",label:"Akses"}],onChange:i=>R(i),children:[e.jsx(ie,{value:"ringkasan",children:e.jsxs("div",{className:"vps-summary",children:[e.jsxs("div",{"data-testid":"vps-detail",className:"vps-detail-meta",children:[l?`Audit terakhir ${be(l)||"—"}`:"Belum pernah diaudit",o&&` · disk ${o.disk} · mem ${o.mem} · load ${o.load}`]}),p&&e.jsxs("div",{className:"vps-summary-score",children:[e.jsx(ue,{size:12,tone:"muted",children:"Skor kepatuhan"}),e.jsxs("span",{"data-testid":"ringkasan-score",className:"vps-summary-score-num",children:[p.scoreTotal,"%"]})]}),m]})}),e.jsx(ie,{value:"checklist",children:ze()}),e.jsx(ie,{value:"pemasangan",children:e.jsx("div",{"data-testid":"vps-provisioning",children:h??e.jsx(F,{kind:"empty",compact:!0,title:"Pemasangan belum tersedia"})})}),e.jsx(ie,{value:"akses",children:u??e.jsx(F,{kind:"empty",compact:!0,title:"Akses belum tersedia"})})]}),n]})}const xe=He;function ls(s,t){if(t.status==="partial"&&t.detail.startsWith("not-logged-in"))return`${s} · belum login`;if(t.status==="partial")return`${s} · ${t.detail||xe.partial}`;const l=t.status==="ok"&&t.detail?` ${t.detail}`:"";return`${s} · ${Fe(xe,t.status)}${l}`}const rs={lab:"Uji coba: komponen dipasang langsung di host ini.",production:"Produksi: agen dipasang ke dalam image terisolasi; sebagian komponen tak tersedia di profil ini."};function os({status:s,children:t,title:l}){return e.jsxs("span",{title:l,className:"vps-prov-chip",children:[e.jsx("span",{"aria-hidden":!0,className:"vps-prov-dot","data-status":s}),t]})}function $e({components:s,checkedAt:t}){return!s||!t?e.jsx("span",{className:"vps-prov-hint",children:"Komponen belum diperiksa"}):e.jsxs("div",{className:"vps-prov-badges",children:[Object.entries(s).map(([l,o])=>e.jsx(os,{status:o.status,children:ls(l,o)},l)),e.jsxs("span",{className:"vps-prov-hint",children:["diperiksa ",new Date(t).toLocaleString("id-ID")]})]})}function cs(s,t,l){const o=new Map(t.map(u=>[u.id,u])),m=new Set,h=u=>{var x;if(!m.has(u)){m.add(u);for(const b of((x=o.get(u))==null?void 0:x.requires[l])??[])h(b)}};for(const u of s)h(u);return m}function ds({vps:s,onToast:t,onGotoTerminal:l}){const[o,m]=c.useState([]),[h,u]=Se("vps",`provisionProfile@${s.id}`,"lab",Me("lab","production")),[x,b]=c.useState(new Set),[j,p]=c.useState(""),[f,S]=c.useState(null),[L,A]=c.useState(null),[B,N]=c.useState(null),[R,d]=c.useState(null),[z,K]=c.useState(!1),{confirm:W,dialog:Q}=me();c.useEffect(()=>{g.listVpsComponents().then(n=>m(n.components)).catch(()=>m([]))},[]);const q=o.filter(n=>n.profiles.includes(h)),M=cs(x,o,h),$=[...M],C=$.some(n=>{var w;return(w=o.find(V=>V.id===n))==null?void 0:w.needsDomain}),O=$.length>0&&(!C||j.trim().length>0),D=$.length===0?"Pilih minimal satu komponen.":C&&!j.trim()?"Isi domain dulu — komponen yang dipilih membutuhkannya.":null;function U(n){b(w=>{const V=new Set(w);return V.has(n)?V.delete(n):V.add(n),V})}async function J(){d("probe");try{A(await g.probeVps(s.id)),t("Komponen diperiksa","ok","server")}catch(n){t(T("memeriksa komponen",n),"err","x-circle")}finally{d(null)}}async function a(){d("preview");try{S((await g.provisionPreview(s.id,{items:$,profile:h,domain:j||void 0})).steps)}catch(n){t(T("membuat pratinjau",n),"err","x-circle")}finally{d(null)}}async function v(){if(await W({title:`Pasang ${$.length} komponen di "${s.name}"?`,message:`Profil ${h}. Langkah dijalankan lewat SSH dan bisa memakan beberapa menit.`,impact:$.map(n=>{var w;return((w=o.find(V=>V.id===n))==null?void 0:w.label)??n}),confirmLabel:"Pasang",icon:"server"})){d("apply");try{const n=await g.provisionVps(s.id,{items:$,profile:h,domain:j||void 0,confirm:!0});S(n.steps),A({components:n.components,checkedAt:n.checkedAt}),N(n.setup),t("Provisioning selesai","ok","server")}catch(n){t(T("memasang komponen",n),"err","x-circle")}finally{d(null)}}}const I=async()=>{try{const{id:n}=await g.vpsConsole(s.id);l(n)}catch(n){t(T("membuka console",n),"err","x-circle")}},Z=async n=>{if(!navigator.clipboard){t("Salin tak tersedia di browser ini. Pilih tautannya lalu salin manual.","err","x-circle");return}try{await navigator.clipboard.writeText(n),K(!0),window.setTimeout(()=>K(!1),2e3)}catch(w){t(T("menyalin tautan",w),"err","x-circle")}},_=L?Object.fromEntries(L.components.map(n=>[n.id,{status:n.status,detail:n.detail}])):s.components??null,ee=(L==null?void 0:L.checkedAt)??s.componentsCheckedAt??null,se=_?Object.entries(_).filter(([,n])=>n.status==="partial"&&n.detail.startsWith("not-logged-in")):[];return e.jsxs("div",{className:"vps-prov",children:[e.jsxs("div",{className:"vps-prov-row",children:[e.jsx($e,{components:_,checkedAt:ee}),e.jsx(y,{size:"sm",variant:"ghost",onClick:J,disabled:R!==null,children:"Periksa"})]}),e.jsxs("fieldset",{className:"vps-prov-fieldset",children:[e.jsx("legend",{className:"vps-prov-legend",children:"Profil"}),e.jsx("div",{className:"vps-prov-profiles",children:["lab","production"].map(n=>e.jsxs("div",{children:[e.jsx(Ue,{"aria-label":n,label:n,checked:h===n,onChange:()=>u(n)}),e.jsx("div",{className:"vps-prov-profile-hint",children:rs[n]})]},n))})]}),e.jsx("div",{className:"vps-prov-items",children:q.map(n=>{const w=M.has(n.id)&&!x.has(n.id);return e.jsxs("div",{className:"vps-prov-item",children:[e.jsx(_e,{"aria-label":n.label,label:n.label,checked:M.has(n.id),disabled:w,onChange:()=>U(n.id)}),w&&e.jsx("span",{className:"vps-prov-tag",children:"prasyarat"})]},n.id)})}),C&&e.jsx(G,{label:"Domain",hint:"A record harus sudah menunjuk ke IP VPS ini",children:e.jsx(X,{"aria-label":"Domain",value:j,onChange:n=>p(n.currentTarget.value),placeholder:"hanoman.contoh.id"})}),e.jsxs("div",{className:"vps-prov-row",children:[e.jsx(y,{variant:"ghost",onClick:a,disabled:!O||R!==null,children:"Pratinjau"}),e.jsx(y,{onClick:v,disabled:!O||R!==null,children:"Pasang"}),!O&&D&&e.jsx("span",{className:"vps-prov-reason",children:D})]}),e.jsx("div",{"aria-live":"polite",children:f&&e.jsx("pre",{tabIndex:0,"aria-label":"Hasil langkah provisioning",className:"vps-prov-steps",children:f.map(n=>`${n.item.padEnd(14)} ${n.status.padEnd(6)} ${n.detail}`).join(`
2
- `)})}),B&&e.jsxs("div",{className:"vps-prov-setup",children:[e.jsx("strong",{className:"vps-prov-setup-title",children:"Buat admin pertama"}),e.jsx("a",{href:B.url,target:"_blank",rel:"noreferrer",className:"vps-prov-setup-link",children:B.url}),e.jsxs("span",{className:"vps-prov-hint",children:["berlaku sampai ",new Date(B.expiresAt).toLocaleTimeString("id-ID")]}),e.jsx("div",{children:e.jsx(y,{size:"sm",variant:"ghost",onClick:()=>void Z(B.url),children:z?"Tersalin":"Salin"})})]}),se.length>0&&e.jsxs("div",{className:"vps-prov-pending",children:[e.jsx(ne,{name:"alert-triangle"}),e.jsxs("span",{children:[se.map(([n])=>n).join(", ")," terpasang tapi belum login."]}),e.jsx(y,{size:"sm",variant:"ghost",onClick:I,children:"Login lewat Console"})]}),Q]})}const js=(s,t=Date.now())=>we(s,t),gs=s=>s.lastAuditAt?s.hardened?"hardened":"belum":"unknown";function ve(s){const t={name:s.name.trim(),host:s.host.trim(),user:s.user.trim(),port:Number(s.port)||22};return s.keyPath.trim()&&(t.keyPath=s.keyPath.trim()),s.password&&(t.password=s.password),t}const us="opsional — dipakai sekali untuk memasang key hanoman, tidak disimpan";function de({open:s,title:t,submitLabel:l,initial:o,onClose:m,onSubmit:h}){const[u,x]=c.useState(o);c.useEffect(()=>{s&&x(o)},[s,o]);const b=p=>f=>x(S=>({...S,[p]:f.target.value})),j=!!(u.name.trim()&&u.host.trim()&&u.user.trim());return e.jsxs(ye,{open:s,onClose:m,icon:"server",eyebrow:"infra",title:t,footer:e.jsxs(e.Fragment,{children:[e.jsx(y,{variant:"ghost",size:"sm",onClick:m,children:"Batal"}),e.jsx(y,{size:"sm",leftIcon:"check",onClick:()=>j&&h(u),children:l})]}),children:[e.jsx(G,{label:"Nama",children:e.jsx(X,{value:u.name,onChange:b("name"),placeholder:"mis. web-1",style:{width:"100%"}})}),e.jsx(G,{label:"Host",hint:"hostname atau IP — tanpa user@",children:e.jsx(X,{value:u.host,onChange:b("host"),mono:!0,placeholder:"203.0.113.10",style:{width:"100%"}})}),e.jsxs("div",{className:"hn-grid-mobile vps-form-pair",children:[e.jsx(G,{label:"User SSH",hint:"root atau user ber-passwordless-sudo",children:e.jsx(X,{value:u.user,onChange:b("user"),mono:!0,placeholder:"deploy",style:{width:"100%"}})}),e.jsx(G,{label:"Port",children:e.jsx(X,{value:u.port,onChange:b("port"),mono:!0,placeholder:"22",style:{width:"100%"}})})]}),e.jsx(G,{label:"Password SSH",hint:us,children:e.jsx(X,{type:"password",value:u.password,onChange:b("password"),placeholder:"••••••••",style:{width:"100%"}})}),e.jsx(G,{label:"Key path",hint:"kosongkan bila memakai password di atas, atau key default mesin server",children:e.jsx(X,{value:u.keyPath,onChange:b("keyPath"),mono:!0,placeholder:"~/.ssh/id_ed25519",style:{width:"100%"}})})]})}const je={name:"",host:"",user:"",port:"22",keyPath:"",password:""},ms=s=>({name:s.name,host:s.host,user:s.user,port:String(s.port),keyPath:s.keyPath??"",password:""});function ge({steps:s,name:t}){return e.jsx("ol",{className:"vps-stepper","aria-label":`Kemajuan ${t}`,children:s.map(l=>e.jsxs("li",{className:`vps-step vps-step-${l.state}`,children:[e.jsx("span",{className:"vps-step-label",children:l.label}),e.jsx("span",{className:"vps-step-text",children:l.text})]},l.key))})}function bs({onToast:s,onGotoTerminal:t}){const[l,o]=c.useState([]),[m,h]=c.useState("loading"),[u,x]=c.useState(""),[b,j]=c.useState(null),[p,f]=c.useState(null),[S,L]=Se("vps","detailId",null,Xe),A=c.useMemo(()=>l.find(a=>a.id===S)??null,[l,S]),B=c.useCallback(a=>L(a?a.id:null),[L]),N=c.useCallback(()=>{g.listVps().then(a=>{o(a),h("ready")}).catch(a=>{x(fe(a,"tak diketahui")),h("error")})},[]);c.useEffect(()=>(N(),Ke(a=>{a.t==="vps"&&(o(a.vps),h("ready"))})),[N]);const{confirm:R,dialog:d}=me();async function z(a,v,I,Z,_){j(`${a}:${v}`);try{await I(),N(),s(Z,"ok","server")}catch(ee){s(T(_,ee),"err","x-circle")}finally{j(null)}}const K=async a=>{j(`audit:${a.id}`);try{await g.auditVps(a.id),N(),s(`${a.name} · audit selesai`,"ok","server")}catch(v){s(T("menjalankan audit",v),"err","x-circle")}finally{j(null)}};async function W(a){await R({title:`Harden "${a.name}"?`,message:"Pastikan akses key SSH non-password kamu sudah bekerja sebelum melanjutkan.",impact:[`Firewall: izinkan ${a.port}/80/443.`,"fail2ban & auto security update dipasang.","PermitRootLogin & PasswordAuthentication dimatikan.","NTP disinkronkan."],confirmLabel:"Harden",icon:"shield"})&&z("harden",a.id,()=>g.hardenVps(a.id),`${a.name} · harden selesai`,"menjalankan harden")}const Q=a=>z("sesi",a.id,async()=>{const{id:v}=await g.vpsSession(a.id);t(v)},`${a.name} · sesi Claude dibuka`,"membuka sesi Claude"),q=a=>z("test",a.id,async()=>{const v=await g.testVps(a.id);if(!v.ok)throw new Error(v.out)},`${a.name} · koneksi ok`,"tes koneksi"),M=a=>z("console",a.id,async()=>{const{id:v}=await g.vpsConsole(a.id);t(v)},`${a.name} · console dibuka`,"membuka console");async function $(a){try{if(!await R({title:`Hapus registrasi VPS "${a.name}"?`,message:"Server-nya sendiri tak disentuh — hanya pendaftarannya di dashboard ini yang dihapus.",confirmLabel:"Hapus registrasi",run:()=>g.deleteVps(a.id)}))return;N(),s(`${a.name} dihapus dari daftar`,"ok","check")}catch(v){s(T("menghapus registrasi VPS",v),"err","x-circle")}}async function C(a){try{const v=await g.createVps(ve(a));f(null),N(),s(a.password?`${v.name} terdaftar · key hanoman terpasang · password dibuang`:`${v.name} terdaftar · jalankan audit`,"ok","server")}catch{s("Gagal mendaftarkan VPS — cek host/user, atau password SSH-nya","err","x-circle")}}async function O(a,v){try{const I=await g.updateVps(a.id,ve(v));f(null),N(),s(v.password?`${I.name} diperbarui · key hanoman terpasang · password dibuang`:`${I.name} diperbarui`,"ok","server")}catch{s("Gagal memperbarui VPS","err","x-circle")}}const D=a=>[{key:"tes",label:"Tes koneksi",icon:"plug-zap",onSelect:()=>void q(a)},{key:"console",label:"Buka console",icon:"terminal-square",onSelect:()=>void M(a)},{key:"sesi",label:"Sesi Claude",icon:"terminal",onSelect:()=>void Q(a)},{key:"edit",label:"Edit",icon:"pencil",onSelect:()=>f(a)},{key:"harden",label:"Harden",icon:"shield",tone:"danger",onSelect:()=>void W(a)},{key:"hapus",label:"Hapus registrasi",icon:"trash-2",tone:"danger",onSelect:()=>void $(a)}],U=a=>e.jsxs(e.Fragment,{children:[e.jsx(ge,{steps:he(a),name:a.name}),e.jsx("div",{className:"vps-summary-comp",children:e.jsx($e,{components:a.components??null,checkedAt:a.componentsCheckedAt??null})})]}),J=a=>e.jsxs("div",{className:"vps-access",children:[e.jsxs("dl",{className:"vps-access-list",children:[e.jsxs("div",{children:[e.jsx("dt",{children:"Host"}),e.jsx("dd",{children:a.host})]}),e.jsxs("div",{children:[e.jsx("dt",{children:"User SSH"}),e.jsx("dd",{children:a.user})]}),e.jsxs("div",{children:[e.jsx("dt",{children:"Port"}),e.jsx("dd",{children:a.port})]}),e.jsxs("div",{children:[e.jsx("dt",{children:"Key"}),e.jsx("dd",{children:a.keyPath??"key default mesin server"})]})]}),e.jsxs("div",{className:"vps-access-actions",children:[e.jsx(y,{size:"sm",variant:"secondary",leftIcon:"plug-zap",loading:b===`test:${a.id}`,onClick:()=>void q(a),children:"Tes koneksi"}),e.jsx(y,{size:"sm",variant:"secondary",leftIcon:"terminal-square",loading:b===`console:${a.id}`,onClick:()=>void M(a),children:"Buka console"}),e.jsx(y,{size:"sm",variant:"secondary",leftIcon:"terminal",loading:b===`sesi:${a.id}`,onClick:()=>void Q(a),children:"Sesi Claude"}),e.jsx(y,{size:"sm",variant:"ghost",leftIcon:"pencil",onClick:()=>f(a),children:"Edit"})]})]});return m==="loading"?e.jsx(F,{kind:"loading",title:"Memuat daftar VPS…"}):m==="error"?e.jsx(F,{kind:"error",title:"Gagal memuat daftar VPS",hint:`Alasan: ${u}. Pastikan server hanoman berjalan.`,action:N}):l.length===0?e.jsxs(e.Fragment,{children:[e.jsx(F,{kind:"empty",icon:"server",title:"Belum ada VPS",hint:"Daftarkan VPS untuk mulai audit & hardening.",action:()=>f("new"),actionLabel:"Daftarkan VPS"}),e.jsx(de,{open:p==="new",title:"Daftarkan VPS",submitLabel:"Daftarkan",initial:je,onClose:()=>f(null),onSubmit:C})]}):e.jsxs("div",{className:"vps-screen",children:[e.jsxs("div",{className:"vps-toolbar",children:[e.jsxs(ue,{size:12,tone:"muted",children:[l.length," VPS terdaftar"]}),e.jsx(y,{size:"sm",leftIcon:"plus",onClick:()=>f("new"),children:"Daftarkan VPS"})]}),e.jsx(We,{label:"Daftar VPS",children:l.map(a=>e.jsx(qe,{actions:e.jsxs(e.Fragment,{children:[e.jsx(y,{size:"sm",leftIcon:"radar",loading:b===`audit:${a.id}`,onClick:()=>void K(a),children:"Periksa"}),e.jsx(Ge,{label:`Aksi lain untuk ${a.name}`,title:a.name,items:D(a)})]}),children:e.jsxs("div",{className:"vps-row",children:[e.jsxs("button",{type:"button","aria-label":`Buka detail ${a.name}`,className:"vps-row-open",onClick:()=>B(a),children:[e.jsx("span",{className:"vps-row-name",children:a.name}),e.jsxs("span",{className:"vps-row-addr",children:[a.user,"@",a.host,a.port!==22?`:${a.port}`:""]})]}),e.jsx(ge,{steps:he(a),name:a.name}),e.jsx("span",{className:"vps-row-score",children:Je(a.scoreTotal)})]})},a.id))}),A&&e.jsx(is,{vpsId:A.id,vpsName:A.name,lastAuditAt:A.lastAuditAt,health:A.health,summary:U(A),provisioning:e.jsx(ds,{vps:A,onToast:s,onGotoTerminal:t}),access:J(A),onScore:()=>N(),onClose:()=>{B(null),N()},onToast:s}),e.jsx(de,{open:p==="new",title:"Daftarkan VPS",submitLabel:"Daftarkan",initial:je,onClose:()=>f(null),onSubmit:C}),p&&p!=="new"&&e.jsx(de,{open:!0,title:`Edit ${p.name}`,submitLabel:"Simpan",initial:ms(p),onClose:()=>f(null),onSubmit:a=>O(p,a)}),d]})}export{bs as VpsScreen,ge as VpsStepper,gs as hardenedLabel,js as isReachable,ve as vpsFormToBody};
1
+ import{a1 as be,h as g,v as fe,d as me,aV as E,aW as Y,j as e,M as ye,c as Oe,aX as ie,aT as ue,m as F,I as ne,x as Re,B as y,i as T,q as Se,r as Me,aY as Ue,aJ as _e,e as G,f as X,aZ as He,l as Fe,aq as Ke,R as We,X as qe,O as Ge,W as Xe}from"./index-BQw6xQI4.js";import{R as c}from"./react-DfGhg7ZW.js";import"./markdown-CWEY34jk.js";import"./xterm-3VOAfa_q.js";const Ye=10*6e4,we=(s,t)=>!!s.lastSeenAt&&t-new Date(s.lastSeenAt).getTime()<Ye;function he(s,t=Date.now()){const l=s.lastSeenAt?we(s,t)?{state:"done",text:"terhubung"}:{state:"gagal",text:"tidak terjangkau"}:{state:"todo",text:"belum terhubung"},o=s.lastAuditAt?{state:"done",text:`diaudit ${be(s.lastAuditAt,t)||"—"}`}:{state:"todo",text:"belum diaudit"},m=s.lastAuditAt&&s.hardened?{state:"done",text:"diperkuat"}:{state:"todo",text:"belum diperkuat"};return[{key:"terhubung",label:"Terhubung",...l},{key:"diaudit",label:"Diaudit",...o},{key:"diperkuat",label:"Diperkuat",...m}]}const Je=(s,t)=>{const l=new Set(s);return l.size===new Set(t).size&&t.every(o=>l.has(o))};function ke(s,t){return s.length>0&&t!==null&&Je(s,t)}const Qe=s=>s==null?"Skor —":`Skor ${s}%`,Ze={pass:"check",fail:"x",warn:"alert-triangle",na:"minus",unknown:"circle"},es={pass:"var(--leaf-600)",fail:"var(--clay-600)",warn:"var(--status-warn)",na:"var(--text-subtle)",unknown:"var(--text-subtle)"},ss={critical:"var(--clay-600)",high:"var(--status-warn)",medium:"var(--text-subtle)",low:"var(--text-subtle)"},te={AUTO:"Otomatis",AUDIT:"Audit",INFO:"Info"};function re({text:s,color:t}){return e.jsx("span",{className:"vps-badge",style:{color:t,borderColor:t},children:s})}function Ne({score:s}){const t=s>=90?"vps-tone-ok":s>=50?"vps-tone-warn":"vps-tone-bad";return e.jsxs("div",{className:"vps-bar-wrap",children:[e.jsx("div",{className:"vps-bar",children:e.jsx("div",{className:`vps-bar-fill ${t}`,style:{width:`${s}%`}})}),e.jsxs("span",{className:"vps-bar-num",children:[s,"%"]})]})}function as({item:s,busy:t,selected:l,onToggle:o,onNa:m,onAttest:h}){const u=s.mode==="AUTO"&&!s.na,x=s.status==="fail"||s.status==="warn"||!!s.drifted;return e.jsxs("div",{"data-testid":`item-${s.id}`,title:`${te[s.mode]} · ${Y[s.severity]}`,className:`vps-item${s.na?" vps-item-na":""}`,children:[u?e.jsx("span",{className:"vps-touch",children:e.jsx("input",{type:"checkbox","aria-label":`Pilih ${s.title}`,checked:l,onChange:()=>o(s)})}):e.jsx("span",{className:"vps-item-gap"}),e.jsx(ne,{name:Ze[s.status],size:14,color:es[s.status]}),e.jsx("span",{className:"vps-item-title",children:s.title}),s.drifted&&e.jsx(re,{text:"drift",color:"var(--clay-600)"}),x&&e.jsx(re,{text:Y[s.severity],color:ss[s.severity]}),s.mode==="INFO"&&!s.attested&&e.jsx(y,{size:"sm",variant:"ghost",leftIcon:"check-circle",loading:t,onClick:()=>h(s),children:"Tandai terpenuhi"}),e.jsx(y,{size:"sm",variant:"ghost",leftIcon:s.na?"rotate-ccw":"minus-circle",loading:t,onClick:()=>m(s,!s.na),children:s.na?"Batal N/A":"N/A"})]})}const ce={section:"",mode:"",status:"",severity:""};function le({value:s,onChange:t,options:l,label:o}){return e.jsxs("select",{"aria-label":o,value:s,onChange:m=>t(m.target.value),className:"vps-select vps-touch-select",children:[e.jsxs("option",{value:"",children:[o,": semua"]}),l.map(([m,h])=>e.jsx("option",{value:m,children:h},m))]})}function ts(s){let t=0,l=0,o=0,m=0;for(const x of s)x.status==="fail"?t++:x.status==="warn"?l++:x.status==="unknown"&&o++,x.drifted&&m++;const h=x=>x.charAt(0).toLowerCase()+x.slice(1),u=[t&&`${t} ${h(E.fail)}`,l&&`${l} ${h(E.warn)}`,o&&`${o} ${h(E.unknown)}`].filter(Boolean);return{text:u.length?u.join(" · "):`semua ${h(E.pass)}`,drift:m}}function ns({section:s,items:t,expanded:l,onToggle:o,busy:m,selected:h,onToggleItem:u,onNa:x,onAttest:b,onSectionNa:j}){const p=ts(s.items),f=!!s.suggestion&&!s.suggestion.applicable;return e.jsxs("div",{className:"vps-section",children:[e.jsxs("button",{"data-testid":`section-${s.id}`,"aria-expanded":l,onClick:()=>o(s.id),className:`vps-section-head${l?" vps-section-open":""}`,children:[e.jsx(ne,{name:l?"chevron-down":"chevron-right",size:15,color:"var(--text-subtle)"}),e.jsx("span",{className:"vps-section-icon",children:s.icon}),e.jsx("span",{className:"vps-section-title",children:s.title}),e.jsx("span",{className:"vps-section-sum",children:p.text}),p.drift>0&&e.jsx(re,{text:"drift",color:"var(--clay-600)"}),f&&e.jsx(re,{text:"saran N/A",color:"var(--brass-700)"}),e.jsx(Ne,{score:s.score})]}),l&&e.jsxs("div",{className:"vps-section-body",children:[f&&e.jsxs("div",{"data-testid":`suggestion-${s.id}`,className:"vps-suggest",children:[e.jsx(ne,{name:"info",size:13,color:"var(--brass-700)"}),e.jsxs("span",{className:"vps-suggest-text",children:["Stack tak terdeteksi (",s.suggestion.detail,") — kemungkinan N/A. Cek Docker manual bila ragu."]}),e.jsx(y,{size:"sm",variant:"ghost",leftIcon:"minus-circle",loading:m===`section:${s.id}`,onClick:()=>j(s),children:"Tandai seksi N/A"})]}),t.map(S=>e.jsx(as,{item:S,busy:m===S.id,selected:h.has(S.id),onToggle:u,onNa:x,onAttest:b},S.id))]})]})}function is({vpsId:s,vpsName:t,lastAuditAt:l,health:o,summary:m,provisioning:h,access:u,onScore:x,onClose:b,onToast:j}){const[p,f]=c.useState(null),[S,L]=c.useState("loading"),[A,B]=c.useState(""),[N,R]=c.useState("ringkasan"),[d,z]=c.useState(ce),[K,W]=c.useState(""),[J,q]=c.useState(new Set),[M,$]=c.useState(null),[C,O]=c.useState(new Set),[D,U]=c.useState(null),[Q,a]=c.useState(""),v=c.useRef(x);v.current=x;const I=c.useCallback(()=>{L("loading"),g.vpsChecklist(s).then(i=>{var k;f(i),L("ready"),(k=v.current)==null||k.call(v,i.scoreTotal)}).catch(i=>{B(fe(i,"tak diketahui")),L("error")})},[s]);c.useEffect(()=>{I(),O(new Set),U(null),q(new Set),W(""),z(ce)},[I]);const Z=i=>{U(null),O(k=>{const r=new Set(k);return r.has(i.id)?r.delete(i.id):r.add(i.id),r})},_=()=>{O(new Set),U(null)},ee=i=>q(k=>{const r=new Set(k);return r.has(i)?r.delete(i):r.add(i),r}),{confirm:se,dialog:n}=me(),w=(D==null?void 0:D.forIds)??null,V=ke([...C],w);async function Ce(){const i=[...C];a("preview");try{U({steps:(await g.remediatePreview(s,i)).steps,forIds:i})}catch(k){j(T("membuat pratinjau remediasi",k),"err","x-circle")}finally{a("")}}async function Pe(){const i=[...C];if(!ke(i,w))return;const r=((p==null?void 0:p.sections.flatMap(P=>P.items))??[]).filter(P=>C.has(P.id));if(await se({title:`Terapkan ${i.length} item AUTO ke VPS ini?`,message:"Remediasi dijalankan langsung di server yang terdaftar.",impact:[...r.map(P=>`${P.id} · ${P.title}`),"Langkahnya idempoten dan anti-lockout.","Checklist diaudit ulang setelah selesai."],confirmLabel:"Terapkan",icon:"shield"})){a("apply");try{await g.remediate(s,i),_(),I(),j("Remediasi diterapkan · audit ulang","ok","shield")}catch(P){j(T("menerapkan remediasi",P),"err","x-circle")}finally{a("")}}}async function pe(i,k,r){$(i.id);try{await k(),I(),j(r,"ok","shield")}catch(P){j(T(`memperbarui ${i.id}`,P),"err","x-circle")}finally{$(null)}}const Ae=(i,k)=>pe(i,()=>g.markNa(s,i.id,k,k?"ditandai dari checklist":void 0),k?`${i.id} ditandai N/A`:`${i.id} kembali applicable`),Ie=i=>pe(i,()=>g.attestItem(s,i.id),`${i.id} ditandai terpenuhi`);async function Le(i){const k=i.items.map(r=>r.id);if(await se({title:`Tandai ${k.length} item seksi "${i.title}" sebagai N/A?`,message:"Stack-nya tak terdeteksi — cek Docker manual bila ragu.",confirmLabel:"Tandai N/A",icon:"shield"})){$(`section:${i.id}`);try{await g.markNaBulk(s,k,!0,"app-layer: stack tak terdeteksi"),I(),j(`Seksi ${i.title} ditandai N/A`,"ok","shield")}catch(r){j(T(`menandai seksi ${i.title} sebagai N/A`,r),"err","x-circle")}finally{$(null)}}}const ae=K.trim().toLowerCase(),oe=!!(d.section||d.mode||d.status||d.severity)||ae!=="",Ve=i=>(!d.section||i.section===d.section)&&(!d.mode||i.mode===d.mode)&&(!d.status||i.status===d.status)&&(!d.severity||i.severity===d.severity)&&(!ae||i.title.toLowerCase().includes(ae)||i.id.toLowerCase().includes(ae)||(i.code??"").toLowerCase().includes(ae)),H=i=>k=>z(r=>({...r,[i]:k})),Te=i=>{var k;return((k=p==null?void 0:p.sections.find(r=>r.id===i))==null?void 0:k.title)??i},De=[...d.section?[{key:"section",label:`Seksi: ${Te(d.section)}`,onRemove:()=>H("section")("")}]:[],...d.mode?[{key:"mode",label:`Mode: ${te[d.mode]}`,onRemove:()=>H("mode")("")}]:[],...d.status?[{key:"status",label:`Status: ${E[d.status]}`,onRemove:()=>H("status")("")}]:[],...d.severity?[{key:"severity",label:`Severity: ${Y[d.severity]}`,onRemove:()=>H("severity")("")}]:[]],Be=()=>{z(ce),W("")};function ze(){if(S==="loading")return e.jsx(F,{kind:"loading",compact:!0,title:"Memuat checklist…"});if(S==="error"||!p)return e.jsx(F,{kind:"error",compact:!0,title:"Gagal memuat checklist",hint:A,action:I});const i=p.sections.reduce((r,P)=>r+P.items.filter(Ee=>Ee.drifted).length,0),k=p.sections.map(r=>({section:r,matched:r.items.filter(Ve)})).filter(r=>!oe||r.matched.length>0);return e.jsxs("div",{children:[e.jsxs("div",{className:"vps-check-head",children:[e.jsxs("div",{className:"vps-check-score",children:[e.jsxs("span",{"data-testid":"score-total",className:"vps-check-score-num",children:[p.scoreTotal,"%"]}),e.jsx("div",{className:"vps-check-score-bar",children:e.jsx(Ne,{score:p.scoreTotal})}),e.jsx(ue,{size:11,tone:"subtle",children:"skor kepatuhan"})]}),i>0&&e.jsxs("div",{"data-testid":"drift-summary",className:"vps-drift",children:[e.jsx(ne,{name:"alert-triangle",size:14,color:"var(--clay-600)"}),i," item drift (regresi) sejak audit sebelumnya"]}),e.jsx(Re,{label:"Filter checklist",search:{value:K,onChange:W,label:"cari item",placeholder:"mis. ssh atau 5.2.1"},chips:De,filtersLabel:"Filter",onReset:Be,filters:e.jsxs("div",{className:"vps-filter-fields",children:[e.jsx(le,{label:"seksi",value:d.section,onChange:H("section"),options:p.sections.map(r=>[r.id,r.title])}),e.jsx(le,{label:"mode",value:d.mode,onChange:H("mode"),options:[["AUTO",te.AUTO],["AUDIT",te.AUDIT],["INFO",te.INFO]]}),e.jsx(le,{label:"status",value:d.status,onChange:H("status"),options:[["pass",E.pass],["fail",E.fail],["warn",E.warn],["na",E.na],["unknown",E.unknown]]}),e.jsx(le,{label:"severity",value:d.severity,onChange:H("severity"),options:[["critical",Y.critical],["high",Y.high],["medium",Y.medium],["low",Y.low]]})]})}),C.size>0&&e.jsxs("div",{className:"vps-remedi",role:"group","aria-label":"Alur perbaikan",children:[e.jsxs("ol",{className:"vps-remedi-steps",children:[e.jsxs("li",{"data-state":"done",children:["1 Pilih · ",C.size," item AUTO"]}),e.jsx("li",{"data-state":D?"done":"active",children:"2 Pratinjau"}),e.jsx("li",{"data-state":V?"active":"todo",children:"3 Terapkan"})]}),e.jsxs("div",{className:"vps-remedi-actions",children:[e.jsx(y,{size:"sm",variant:"secondary",leftIcon:"eye",loading:Q==="preview",onClick:Ce,children:"Pratinjau"}),e.jsx(y,{size:"sm",leftIcon:"shield",loading:Q==="apply",disabled:!V,onClick:Pe,children:"Terapkan"}),e.jsx(y,{size:"sm",variant:"ghost",onClick:_,children:"Batal"})]}),!V&&e.jsx("div",{className:"vps-remedi-hint",children:"Buat pratinjau dulu. Terapkan hanya memakai pratinjau untuk pilihan ini."})]}),D&&e.jsxs("div",{"data-testid":"remediate-preview",className:"vps-preview",children:[e.jsx("div",{className:"vps-preview-title",children:"Pratinjau (dry-run) — belum diterapkan. Mengubah pilihan membatalkannya."}),D.steps.map(r=>e.jsxs("div",{className:"vps-preview-line",children:[r.item," · ",r.status," ",r.detail]},r.item))]})]}),k.length===0?e.jsx(F,{kind:"empty",compact:!0,title:"Tidak ada item cocok",hint:"Ubah kata kunci atau reset filter."}):k.map(({section:r,matched:P})=>e.jsx(ns,{section:r,items:oe?P:r.items,expanded:oe?!0:J.has(r.id),onToggle:ee,busy:M,selected:C,onToggleItem:Z,onNa:Ae,onAttest:Ie,onSectionNa:Le},r.id))]})}return e.jsxs(ye,{open:!0,width:960,icon:"clipboard-list",eyebrow:"Detail server",title:t??"VPS",onClose:b,children:[e.jsxs(Oe,{"aria-label":"Bagian detail VPS",value:N,className:"vps-tabs",tabs:[{value:"ringkasan",label:"Ringkasan"},{value:"checklist",label:"Checklist"},{value:"pemasangan",label:"Pemasangan"},{value:"akses",label:"Akses"}],onChange:i=>R(i),children:[e.jsx(ie,{value:"ringkasan",children:e.jsxs("div",{className:"vps-summary",children:[e.jsxs("div",{"data-testid":"vps-detail",className:"vps-detail-meta",children:[l?`Audit terakhir ${be(l)||"—"}`:"Belum pernah diaudit",o&&` · disk ${o.disk} · mem ${o.mem} · load ${o.load}`]}),p&&e.jsxs("div",{className:"vps-summary-score",children:[e.jsx(ue,{size:12,tone:"muted",children:"Skor kepatuhan"}),e.jsxs("span",{"data-testid":"ringkasan-score",className:"vps-summary-score-num",children:[p.scoreTotal,"%"]})]}),m]})}),e.jsx(ie,{value:"checklist",children:ze()}),e.jsx(ie,{value:"pemasangan",children:e.jsx("div",{"data-testid":"vps-provisioning",children:h??e.jsx(F,{kind:"empty",compact:!0,title:"Pemasangan belum tersedia"})})}),e.jsx(ie,{value:"akses",children:u??e.jsx(F,{kind:"empty",compact:!0,title:"Akses belum tersedia"})})]}),n]})}const xe=He;function ls(s,t){if(t.status==="partial"&&t.detail.startsWith("not-logged-in"))return`${s} · belum login`;if(t.status==="partial")return`${s} · ${t.detail||xe.partial}`;const l=t.status==="ok"&&t.detail?` ${t.detail}`:"";return`${s} · ${Fe(xe,t.status)}${l}`}const rs={lab:"Uji coba: komponen dipasang langsung di host ini.",production:"Produksi: agen dipasang ke dalam image terisolasi; sebagian komponen tak tersedia di profil ini."};function os({status:s,children:t,title:l}){return e.jsxs("span",{title:l,className:"vps-prov-chip",children:[e.jsx("span",{"aria-hidden":!0,className:"vps-prov-dot","data-status":s}),t]})}function $e({components:s,checkedAt:t}){return!s||!t?e.jsx("span",{className:"vps-prov-hint",children:"Komponen belum diperiksa"}):e.jsxs("div",{className:"vps-prov-badges",children:[Object.entries(s).map(([l,o])=>e.jsx(os,{status:o.status,children:ls(l,o)},l)),e.jsxs("span",{className:"vps-prov-hint",children:["diperiksa ",new Date(t).toLocaleString("id-ID")]})]})}function cs(s,t,l){const o=new Map(t.map(u=>[u.id,u])),m=new Set,h=u=>{var x;if(!m.has(u)){m.add(u);for(const b of((x=o.get(u))==null?void 0:x.requires[l])??[])h(b)}};for(const u of s)h(u);return m}function ds({vps:s,onToast:t,onGotoTerminal:l}){const[o,m]=c.useState([]),[h,u]=Se("vps",`provisionProfile@${s.id}`,"lab",Me("lab","production")),[x,b]=c.useState(new Set),[j,p]=c.useState(""),[f,S]=c.useState(null),[L,A]=c.useState(null),[B,N]=c.useState(null),[R,d]=c.useState(null),[z,K]=c.useState(!1),{confirm:W,dialog:J}=me();c.useEffect(()=>{g.listVpsComponents().then(n=>m(n.components)).catch(()=>m([]))},[]);const q=o.filter(n=>n.profiles.includes(h)),M=cs(x,o,h),$=[...M],C=$.some(n=>{var w;return(w=o.find(V=>V.id===n))==null?void 0:w.needsDomain}),O=$.length>0&&(!C||j.trim().length>0),D=$.length===0?"Pilih minimal satu komponen.":C&&!j.trim()?"Isi domain dulu — komponen yang dipilih membutuhkannya.":null;function U(n){b(w=>{const V=new Set(w);return V.has(n)?V.delete(n):V.add(n),V})}async function Q(){d("probe");try{A(await g.probeVps(s.id)),t("Komponen diperiksa","ok","server")}catch(n){t(T("memeriksa komponen",n),"err","x-circle")}finally{d(null)}}async function a(){d("preview");try{S((await g.provisionPreview(s.id,{items:$,profile:h,domain:j||void 0})).steps)}catch(n){t(T("membuat pratinjau",n),"err","x-circle")}finally{d(null)}}async function v(){if(await W({title:`Pasang ${$.length} komponen di "${s.name}"?`,message:`Profil ${h}. Langkah dijalankan lewat SSH dan bisa memakan beberapa menit.`,impact:$.map(n=>{var w;return((w=o.find(V=>V.id===n))==null?void 0:w.label)??n}),confirmLabel:"Pasang",icon:"server"})){d("apply");try{const n=await g.provisionVps(s.id,{items:$,profile:h,domain:j||void 0,confirm:!0});S(n.steps),A({components:n.components,checkedAt:n.checkedAt}),N(n.setup),t("Provisioning selesai","ok","server")}catch(n){t(T("memasang komponen",n),"err","x-circle")}finally{d(null)}}}const I=async()=>{try{const{id:n}=await g.vpsConsole(s.id);l(n)}catch(n){t(T("membuka console",n),"err","x-circle")}},Z=async n=>{if(!navigator.clipboard){t("Salin tak tersedia di browser ini. Pilih tautannya lalu salin manual.","err","x-circle");return}try{await navigator.clipboard.writeText(n),K(!0),window.setTimeout(()=>K(!1),2e3)}catch(w){t(T("menyalin tautan",w),"err","x-circle")}},_=L?Object.fromEntries(L.components.map(n=>[n.id,{status:n.status,detail:n.detail}])):s.components??null,ee=(L==null?void 0:L.checkedAt)??s.componentsCheckedAt??null,se=_?Object.entries(_).filter(([,n])=>n.status==="partial"&&n.detail.startsWith("not-logged-in")):[];return e.jsxs("div",{className:"vps-prov",children:[e.jsxs("div",{className:"vps-prov-row",children:[e.jsx($e,{components:_,checkedAt:ee}),e.jsx(y,{size:"sm",variant:"ghost",onClick:Q,disabled:R!==null,children:"Periksa"})]}),e.jsxs("fieldset",{className:"vps-prov-fieldset",children:[e.jsx("legend",{className:"vps-prov-legend",children:"Profil"}),e.jsx("div",{className:"vps-prov-profiles",children:["lab","production"].map(n=>e.jsxs("div",{children:[e.jsx(Ue,{"aria-label":n,label:n,checked:h===n,onChange:()=>u(n)}),e.jsx("div",{className:"vps-prov-profile-hint",children:rs[n]})]},n))})]}),e.jsx("div",{className:"vps-prov-items",children:q.map(n=>{const w=M.has(n.id)&&!x.has(n.id);return e.jsxs("div",{className:"vps-prov-item",children:[e.jsx(_e,{"aria-label":n.label,label:n.label,checked:M.has(n.id),disabled:w,onChange:()=>U(n.id)}),w&&e.jsx("span",{className:"vps-prov-tag",children:"prasyarat"})]},n.id)})}),C&&e.jsx(G,{label:"Domain",hint:"A record harus sudah menunjuk ke IP VPS ini",children:e.jsx(X,{"aria-label":"Domain",value:j,onChange:n=>p(n.currentTarget.value),placeholder:"hanoman.contoh.id"})}),e.jsxs("div",{className:"vps-prov-row",children:[e.jsx(y,{variant:"ghost",onClick:a,disabled:!O||R!==null,children:"Pratinjau"}),e.jsx(y,{onClick:v,disabled:!O||R!==null,children:"Pasang"}),!O&&D&&e.jsx("span",{className:"vps-prov-reason",children:D})]}),e.jsx("div",{"aria-live":"polite",children:f&&e.jsx("pre",{tabIndex:0,"aria-label":"Hasil langkah provisioning",className:"vps-prov-steps",children:f.map(n=>`${n.item.padEnd(14)} ${n.status.padEnd(6)} ${n.detail}`).join(`
2
+ `)})}),B&&e.jsxs("div",{className:"vps-prov-setup",children:[e.jsx("strong",{className:"vps-prov-setup-title",children:"Buat admin pertama"}),e.jsx("a",{href:B.url,target:"_blank",rel:"noreferrer",className:"vps-prov-setup-link",children:B.url}),e.jsxs("span",{className:"vps-prov-hint",children:["berlaku sampai ",new Date(B.expiresAt).toLocaleTimeString("id-ID")]}),e.jsx("div",{children:e.jsx(y,{size:"sm",variant:"ghost",onClick:()=>void Z(B.url),children:z?"Tersalin":"Salin"})})]}),se.length>0&&e.jsxs("div",{className:"vps-prov-pending",children:[e.jsx(ne,{name:"alert-triangle"}),e.jsxs("span",{children:[se.map(([n])=>n).join(", ")," terpasang tapi belum login."]}),e.jsx(y,{size:"sm",variant:"ghost",onClick:I,children:"Login lewat Console"})]}),J]})}const js=(s,t=Date.now())=>we(s,t),gs=s=>s.lastAuditAt?s.hardened?"hardened":"belum":"unknown";function ve(s){const t={name:s.name.trim(),host:s.host.trim(),user:s.user.trim(),port:Number(s.port)||22};return s.keyPath.trim()&&(t.keyPath=s.keyPath.trim()),s.password&&(t.password=s.password),t}const us="opsional — dipakai sekali untuk memasang key hanoman, tidak disimpan";function de({open:s,title:t,submitLabel:l,initial:o,onClose:m,onSubmit:h}){const[u,x]=c.useState(o);c.useEffect(()=>{s&&x(o)},[s,o]);const b=p=>f=>x(S=>({...S,[p]:f.target.value})),j=!!(u.name.trim()&&u.host.trim()&&u.user.trim());return e.jsxs(ye,{open:s,onClose:m,icon:"server",eyebrow:"infra",title:t,footer:e.jsxs(e.Fragment,{children:[e.jsx(y,{variant:"ghost",size:"sm",onClick:m,children:"Batal"}),e.jsx(y,{size:"sm",leftIcon:"check",onClick:()=>j&&h(u),children:l})]}),children:[e.jsx(G,{label:"Nama",children:e.jsx(X,{value:u.name,onChange:b("name"),placeholder:"mis. web-1",style:{width:"100%"}})}),e.jsx(G,{label:"Host",hint:"hostname atau IP — tanpa user@",children:e.jsx(X,{value:u.host,onChange:b("host"),mono:!0,placeholder:"203.0.113.10",style:{width:"100%"}})}),e.jsxs("div",{className:"hn-grid-mobile vps-form-pair",children:[e.jsx(G,{label:"User SSH",hint:"root atau user ber-passwordless-sudo",children:e.jsx(X,{value:u.user,onChange:b("user"),mono:!0,placeholder:"deploy",style:{width:"100%"}})}),e.jsx(G,{label:"Port",children:e.jsx(X,{value:u.port,onChange:b("port"),mono:!0,placeholder:"22",style:{width:"100%"}})})]}),e.jsx(G,{label:"Password SSH",hint:us,children:e.jsx(X,{type:"password",value:u.password,onChange:b("password"),placeholder:"••••••••",style:{width:"100%"}})}),e.jsx(G,{label:"Key path",hint:"kosongkan bila memakai password di atas, atau key default mesin server",children:e.jsx(X,{value:u.keyPath,onChange:b("keyPath"),mono:!0,placeholder:"~/.ssh/id_ed25519",style:{width:"100%"}})})]})}const je={name:"",host:"",user:"",port:"22",keyPath:"",password:""},ms=s=>({name:s.name,host:s.host,user:s.user,port:String(s.port),keyPath:s.keyPath??"",password:""});function ge({steps:s,name:t}){return e.jsx("ol",{className:"vps-stepper","aria-label":`Kemajuan ${t}`,children:s.map(l=>e.jsxs("li",{className:`vps-step vps-step-${l.state}`,children:[e.jsx("span",{className:"vps-step-label",children:l.label}),e.jsx("span",{className:"vps-step-text",children:l.text})]},l.key))})}function bs({onToast:s,onGotoTerminal:t}){const[l,o]=c.useState([]),[m,h]=c.useState("loading"),[u,x]=c.useState(""),[b,j]=c.useState(null),[p,f]=c.useState(null),[S,L]=Se("vps","detailId",null,Xe),A=c.useMemo(()=>l.find(a=>a.id===S)??null,[l,S]),B=c.useCallback(a=>L(a?a.id:null),[L]),N=c.useCallback(()=>{g.listVps().then(a=>{o(a),h("ready")}).catch(a=>{x(fe(a,"tak diketahui")),h("error")})},[]);c.useEffect(()=>(N(),Ke(a=>{a.t==="vps"&&(o(a.vps),h("ready"))})),[N]);const{confirm:R,dialog:d}=me();async function z(a,v,I,Z,_){j(`${a}:${v}`);try{await I(),N(),s(Z,"ok","server")}catch(ee){s(T(_,ee),"err","x-circle")}finally{j(null)}}const K=async a=>{j(`audit:${a.id}`);try{await g.auditVps(a.id),N(),s(`${a.name} · audit selesai`,"ok","server")}catch(v){s(T("menjalankan audit",v),"err","x-circle")}finally{j(null)}};async function W(a){await R({title:`Harden "${a.name}"?`,message:"Pastikan akses key SSH non-password kamu sudah bekerja sebelum melanjutkan.",impact:[`Firewall: izinkan ${a.port}/80/443.`,"fail2ban & auto security update dipasang.","PermitRootLogin & PasswordAuthentication dimatikan.","NTP disinkronkan."],confirmLabel:"Harden",icon:"shield"})&&z("harden",a.id,()=>g.hardenVps(a.id),`${a.name} · harden selesai`,"menjalankan harden")}const J=a=>z("sesi",a.id,async()=>{const{id:v}=await g.vpsSession(a.id);t(v)},`${a.name} · sesi Claude dibuka`,"membuka sesi Claude"),q=a=>z("test",a.id,async()=>{const v=await g.testVps(a.id);if(!v.ok)throw new Error(v.out)},`${a.name} · koneksi ok`,"tes koneksi"),M=a=>z("console",a.id,async()=>{const{id:v}=await g.vpsConsole(a.id);t(v)},`${a.name} · console dibuka`,"membuka console");async function $(a){try{if(!await R({title:`Hapus registrasi VPS "${a.name}"?`,message:"Server-nya sendiri tak disentuh — hanya pendaftarannya di dashboard ini yang dihapus.",confirmLabel:"Hapus registrasi",run:()=>g.deleteVps(a.id)}))return;N(),s(`${a.name} dihapus dari daftar`,"ok","check")}catch(v){s(T("menghapus registrasi VPS",v),"err","x-circle")}}async function C(a){try{const v=await g.createVps(ve(a));f(null),N(),s(a.password?`${v.name} terdaftar · key hanoman terpasang · password dibuang`:`${v.name} terdaftar · jalankan audit`,"ok","server")}catch{s("Gagal mendaftarkan VPS — cek host/user, atau password SSH-nya","err","x-circle")}}async function O(a,v){try{const I=await g.updateVps(a.id,ve(v));f(null),N(),s(v.password?`${I.name} diperbarui · key hanoman terpasang · password dibuang`:`${I.name} diperbarui`,"ok","server")}catch{s("Gagal memperbarui VPS","err","x-circle")}}const D=a=>[{key:"tes",label:"Tes koneksi",icon:"plug-zap",onSelect:()=>void q(a)},{key:"console",label:"Buka console",icon:"terminal-square",onSelect:()=>void M(a)},{key:"sesi",label:"Sesi Claude",icon:"terminal",onSelect:()=>void J(a)},{key:"edit",label:"Edit",icon:"pencil",onSelect:()=>f(a)},{key:"harden",label:"Harden",icon:"shield",tone:"danger",onSelect:()=>void W(a)},{key:"hapus",label:"Hapus registrasi",icon:"trash-2",tone:"danger",onSelect:()=>void $(a)}],U=a=>e.jsxs(e.Fragment,{children:[e.jsx(ge,{steps:he(a),name:a.name}),e.jsx("div",{className:"vps-summary-comp",children:e.jsx($e,{components:a.components??null,checkedAt:a.componentsCheckedAt??null})})]}),Q=a=>e.jsxs("div",{className:"vps-access",children:[e.jsxs("dl",{className:"vps-access-list",children:[e.jsxs("div",{children:[e.jsx("dt",{children:"Host"}),e.jsx("dd",{children:a.host})]}),e.jsxs("div",{children:[e.jsx("dt",{children:"User SSH"}),e.jsx("dd",{children:a.user})]}),e.jsxs("div",{children:[e.jsx("dt",{children:"Port"}),e.jsx("dd",{children:a.port})]}),e.jsxs("div",{children:[e.jsx("dt",{children:"Key"}),e.jsx("dd",{children:a.keyPath??"key default mesin server"})]})]}),e.jsxs("div",{className:"vps-access-actions",children:[e.jsx(y,{size:"sm",variant:"secondary",leftIcon:"plug-zap",loading:b===`test:${a.id}`,onClick:()=>void q(a),children:"Tes koneksi"}),e.jsx(y,{size:"sm",variant:"secondary",leftIcon:"terminal-square",loading:b===`console:${a.id}`,onClick:()=>void M(a),children:"Buka console"}),e.jsx(y,{size:"sm",variant:"secondary",leftIcon:"terminal",loading:b===`sesi:${a.id}`,onClick:()=>void J(a),children:"Sesi Claude"}),e.jsx(y,{size:"sm",variant:"ghost",leftIcon:"pencil",onClick:()=>f(a),children:"Edit"})]})]});return m==="loading"?e.jsx(F,{kind:"loading",title:"Memuat daftar VPS…"}):m==="error"?e.jsx(F,{kind:"error",title:"Gagal memuat daftar VPS",hint:`Alasan: ${u}. Pastikan server hanoman berjalan.`,action:N}):l.length===0?e.jsxs(e.Fragment,{children:[e.jsx(F,{kind:"empty",icon:"server",title:"Belum ada VPS",hint:"Daftarkan VPS untuk mulai audit & hardening.",action:()=>f("new"),actionLabel:"Daftarkan VPS"}),e.jsx(de,{open:p==="new",title:"Daftarkan VPS",submitLabel:"Daftarkan",initial:je,onClose:()=>f(null),onSubmit:C})]}):e.jsxs("div",{className:"vps-screen",children:[e.jsxs("div",{className:"vps-toolbar",children:[e.jsxs(ue,{size:12,tone:"muted",children:[l.length," VPS terdaftar"]}),e.jsx(y,{size:"sm",leftIcon:"plus",onClick:()=>f("new"),children:"Daftarkan VPS"})]}),e.jsx(We,{label:"Daftar VPS",children:l.map(a=>e.jsx(qe,{actions:e.jsxs(e.Fragment,{children:[e.jsx(y,{size:"sm",leftIcon:"radar",loading:b===`audit:${a.id}`,onClick:()=>void K(a),children:"Periksa"}),e.jsx(Ge,{label:`Aksi lain untuk ${a.name}`,title:a.name,items:D(a)})]}),children:e.jsxs("div",{className:"vps-row",children:[e.jsxs("button",{type:"button","aria-label":`Buka detail ${a.name}`,className:"vps-row-open",onClick:()=>B(a),children:[e.jsx("span",{className:"vps-row-name",children:a.name}),e.jsxs("span",{className:"vps-row-addr",children:[a.user,"@",a.host,a.port!==22?`:${a.port}`:""]})]}),e.jsx(ge,{steps:he(a),name:a.name}),e.jsx("span",{className:"vps-row-score",children:Qe(a.scoreTotal)})]})},a.id))}),A&&e.jsx(is,{vpsId:A.id,vpsName:A.name,lastAuditAt:A.lastAuditAt,health:A.health,summary:U(A),provisioning:e.jsx(ds,{vps:A,onToast:s,onGotoTerminal:t}),access:Q(A),onScore:()=>N(),onClose:()=>{B(null),N()},onToast:s}),e.jsx(de,{open:p==="new",title:"Daftarkan VPS",submitLabel:"Daftarkan",initial:je,onClose:()=>f(null),onSubmit:C}),p&&p!=="new"&&e.jsx(de,{open:!0,title:`Edit ${p.name}`,submitLabel:"Simpan",initial:ms(p),onClose:()=>f(null),onSubmit:a=>O(p,a)}),d]})}export{bs as VpsScreen,ge as VpsStepper,gs as hardenedLabel,js as isReachable,ve as vpsFormToBody};
@@ -0,0 +1 @@
1
+ import{cg as R,ch as F,ci as I,cj as O,ck as M,cl as U,bZ as $,bW as P,bX as B,bY as G,cm as z,a6 as H,a7 as K,cn as V,bc as Y,co as q,bR as W,cp as X,cq as Z,j as a,B as J,h as Q,aI as ee,b2 as te,ae as T,g as A,a9 as ae,aa as se,ab as ne,ac as re,ad as ie,f as le}from"./index-BQw6xQI4.js";import{R as f}from"./react-DfGhg7ZW.js";import"./markdown-CWEY34jk.js";const xe=R,S=[{key:"sesi",label:"Sesi harian",icon:"bell",sections:[{key:"sesi",label:"Sesi harian",icon:"bell",keywords:"notifikasi suara selesai keputusan gagal full-auto scaffold agen model default effort goal kondisi verifikasi scope metode workflow"}]},{key:"model",label:"Agen & model",icon:"cpu",sections:[{key:"model",label:"Agen & model",icon:"cpu",keywords:"override konflik rebase merge lead operator obrolan portal jatah orkestrasi fase effort model runtime"}]},{key:"integrasi",label:"Integrasi & akses",icon:"webhook",sections:[{key:"agent",label:"Akses AI Agent",icon:"bot",keywords:"token agent capability mcp master switch"},{key:"telegram",label:"Telegram",icon:"send",keywords:"bot token chat allowlist gateway operator agen progress uji koneksi"},{key:"webhook",label:"Webhook",icon:"webhook",keywords:"endpoint secret peristiwa pengiriman dokumentasi"},{key:"akses-klien",label:"Akses klien",icon:"user-check",keywords:"portal klien grant lihat tulis mulai sesi"},{key:"perangkat",label:"Perangkat",icon:"key-round",keywords:"token perangkat sinkron server pusat"},{key:"kendali-jarak-jauh",label:"Kendali jarak jauh",icon:"shield",keywords:"izin server pusat perangkat kendali"}]},{key:"lanjutan",label:"Lanjutan",icon:"sliders-horizontal",collapsible:!0,sections:[{key:"akun",label:"Akun",icon:"user-round",keywords:"password email logout ganti masuk"},{key:"users",label:"Pengguna",icon:"users",keywords:"undang hapus pengguna email password"},{key:"setup",label:"Setup awal",icon:"shield",keywords:"peruntukan hardening setup ulang"},{key:"konfigurasi",label:"Konfigurasi",icon:"sliders-horizontal",keywords:"env rahasia bootstrap sinkron runtime variabel"},{key:"aktivitas",label:"Log aktivitas",icon:"activity",keywords:"log sesi project hasil commit pr hapus"},{key:"custom-agent",label:"Custom agent",icon:"bot",keywords:"persona agen mention katalog"},{key:"zona-bahaya",label:"Zona bahaya",icon:"alert-triangle",keywords:"reset default kembalikan semua setelan"}]}],L="sesi",oe=S.flatMap(e=>e.sections.map(t=>t.key)),D=e=>oe.includes(e),ue=new Map([["umum","sesi"],["orkestrasi","model"]]);function je(e){if(typeof e!="string")return L;const t=ue.get(e)??e;return D(t)?t:L}function ce(e){return S.find(t=>t.sections.some(n=>n.key===e))??S[0]}function de(e){return S.flatMap(n=>n.sections).find(n=>n.key===e)??S[0].sections[0]}function Ne(e){const t=ce(e);return t.sections.length>1?`${t.label} · ${de(e).label}`:t.label}function Ae(e){const t=new URLSearchParams(e.replace(/^#/,"")).get("bagian");return t&&D(t)?t:null}const we=e=>Z(e).map(t=>({value:t,label:t==="xhigh"?"x-high":t})),Te=e=>W(X,e),fe=(e,t)=>{const n=q(e,t);return n===t?{}:{effort:n}},Le=[{value:"blip",label:"Blip · 0.1s"},{value:"pop",label:"Pop · 0.1s"},{value:"short",label:"Short · 0.15s"},{value:"ping",label:"Ping · 0.2s"},{value:"coin",label:"Coin · 0.3s"},{value:"alert",label:"Alert · 0.3s"},{value:"medium",label:"Medium · 0.4s"},{value:"chime",label:"Chime · 0.4s"},{value:"success",label:"Success · 0.4s"},{value:"bell",label:"Bell · 0.5s"},{value:"marimba",label:"Marimba · 0.6s"},{value:"long",label:"Long · 0.8s"},{value:"fanfare",label:"Fanfare · 0.9s"},{value:"off",label:"Senyap"}],De={model:"sonnet",effort:"medium",autoDefault:!0,autoScaffold:!0,notifyFail:!0,notifyDone:!0,notifySound:"short",notifyDecision:!0,notifyDecisionSound:"alert",agentAccessEnabled:!1,scheduler:Y,goal:V,agent:"claude",codex:K,antigravity:H,verifyScope:"changed",method:z,conflict:G,lead:B,telegram:P,portalChat:$,orchestration:U,remoteControl:M,logShipping:O,logRetention:I,builtinAgents:{},builtinAgentPolicies:{},builtinRuntimeDefaults:F};function ge({save:e}){if(e.status==="idle")return null;if(e.status==="error")return a.jsxs("span",{className:"hn-set-save hn-set-save--err",role:"status","data-testid":"save-status",children:["Gagal — coba lagi",a.jsx(J,{size:"sm",variant:"ghost",leftIcon:"refresh-cw",onClick:e.retry,children:"Coba lagi"})]});const t=e.status==="saved"?"Tersimpan":"Menyimpan…",n=e.status==="saved"?"hn-set-save--ok":"hn-set-save--pending";return a.jsx("span",{className:`hn-set-save ${n}`,role:"status","data-testid":"save-status",children:t})}function he({text:e}){return a.jsx(a.Fragment,{children:e.split(/`([^`]+)`/).map((t,n)=>n%2===1?a.jsx("code",{className:"hn-set-mono hn-set-codeinline",children:t},n):t)})}function x({title:e,desc:t,children:n,last:r,save:c,search:o}){return a.jsxs("div",{className:`hn-setting-row hn-set-row${r?" hn-set-row--last":""}`,"data-setting-row":!0,"data-search":`${e} ${t??""} ${o??""}`,children:[a.jsxs("div",{className:"hn-set-row-text",children:[a.jsx("div",{className:"hn-set-row-title",children:e}),t&&a.jsx("div",{className:"hn-set-row-desc",children:a.jsx(he,{text:t})}),c&&a.jsx(ge,{save:c})]}),a.jsx("div",{className:"hn-setting-control hn-set-row-control",children:n})]})}function Ce({id:e,text:t}){return t?a.jsx("div",{id:e,className:"hn-set-hint",children:t}):null}function _e({children:e}){return a.jsx("div",{className:"hn-set-note",children:e})}function me({children:e}){return a.jsx("div",{className:"hn-set-prose",children:e})}const ke=400,ve=1800;function y(e){const t=f.useRef(e);t.current=e;const[n,r]=f.useState(null),c=f.useRef(e.value),[o,l]=f.useState("idle"),u=f.useRef(0),g=f.useRef(null),s=f.useRef(null),h=f.useRef(null),m=f.useRef(null),d=f.useRef(!1),k=f.useRef(0),v=()=>{s.current&&(clearTimeout(s.current),s.current=null)},j=()=>{h.current&&(clearTimeout(h.current),h.current=null)},N=(i,p)=>{if(v(),k.current===0&&Object.is(i,t.current.value)){p===u.current&&(g.current=null,r(null),l("idle"));return}k.current++,l("saving"),Promise.resolve(t.current.save(i)).then(E=>{k.current--,!(!d.current||p!==u.current)&&(g.current=null,E?(m.current=null,r({v:i,settled:!0}),l("saved"),j(),h.current=setTimeout(()=>{h.current=null,d.current&&l(b=>b==="saved"?"idle":b)},ve)):(m.current={v:i},r(null),l("error")))})},w=i=>{const p=++u.current;g.current={v:i,id:p},m.current=null,j(),r({v:i,settled:!1}),v();const E=t.current.delayMs??ke;if(E<=0){N(i,p);return}l("pending"),s.current=setTimeout(()=>{s.current=null;const b=g.current;b&&N(b.v,b.id)},E)};f.useEffect(()=>{Object.is(c.current,e.value)||(c.current=e.value,r(i=>i&&i.settled?null:i))},[e.value]);const C=()=>{const i=g.current;!s.current||!i||N(i.v,i.id)},_=()=>{const i=m.current;i&&w(i.v)};return f.useEffect(()=>(d.current=!0,()=>{d.current=!1;const i=g.current;s.current&&i&&(v(),Promise.resolve(t.current.save(i.v))),j()}),[]),{value:n?n.v:e.value,set:w,flush:C,status:o,retry:_}}function be({model:e,codexVer:t}){var r;const n=(t==null?void 0:t.version)??null;return re(e,n)?a.jsxs("div",{"data-testid":"codex-version-note",className:"hn-set-codex-note",children:["Codex CLI terpasang ",a.jsx("b",{children:n}),", sedangkan ",a.jsx("b",{children:e})," butuh ",a.jsx("b",{children:(r=ie(e))==null?void 0:r.minClient}),". Sesi tetap boleh dijalankan, tapi modelnya belum tentu dikenali CLI ini. Perbarui dengan ",a.jsx("code",{children:"npm i -g @openai/codex@latest"}),"."]}):null}function Re({id:e,label:t,active:n}){return a.jsxs("div",{className:"hn-set-agent-head",children:[a.jsx("div",{className:"hn-set-agent-name",children:t}),a.jsx("span",{"data-testid":`agent-badge-${e}`,className:`hn-set-agent-badge${n?" hn-set-agent-badge--on":""}`,children:n?"dipakai sesi baru":"tidak dipakai sekarang"})]})}function Fe({engine:e,labels:t,defaults:n,codexVer:r,save:c}){const o=y({value:e.agent,delayMs:0,save:s=>{const h=n[s];return c({agent:s,model:h.model,effort:s==="claude"?h.effort:T(s,h.model,h.effort)},`${t.msg.agent} → ${s}`)}}),l=y({value:e.model,delayMs:0,save:s=>c({model:s,...e.agent==="claude"?fe(s,e.effort):{effort:T(e.agent,s,e.effort)}},`${t.msg.model} → ${s}`)}),u=y({value:e.effort,delayMs:0,save:s=>c({effort:s},`${t.msg.effort} → ${s}`)}),g=o.value==="codex";return a.jsxs(a.Fragment,{children:[a.jsx(x,{title:t.agentTitle,desc:t.agentDesc,save:o,children:a.jsx(A,{size:"sm","aria-label":t.aria.agent,value:o.value,className:"hn-set-w-sm",options:ae,onChange:s=>o.set(s.target.value)})}),g&&a.jsx(be,{model:l.value,codexVer:r}),o.value==="antigravity"&&a.jsx(pe,{}),a.jsx(x,{title:"Model",save:l,children:a.jsx(A,{size:"sm","aria-label":t.aria.model,value:l.value,className:"hn-set-w-sm",options:se(o.value,l.value),onChange:s=>l.set(s.target.value)})}),a.jsx(x,{title:"Effort",desc:t.effortDesc,last:!0,save:u,children:a.jsx(A,{size:"sm","aria-label":t.aria.effort,value:u.value,className:"hn-set-w-xs",options:ne(o.value,l.value).map(s=>({value:s,label:s==="xhigh"?"x-high":s})),onChange:s=>u.set(s.target.value)})})]})}function Ie({eyebrow:e,title:t,desc:n,toggleTitle:r="Pakai setelan sendiri",toggleDesc:c,toggleAria:o,enabled:l,onToggle:u,inherited:g,inheritedTestId:s,children:h}){const m=y({value:l,delayMs:0,save:d=>u(d)});return a.jsxs(ee,{eyebrow:e,title:t,"data-setting-card":!0,"data-search":`${t} ${e}`,children:[a.jsx(me,{children:n}),a.jsx(x,{title:r,desc:c,save:m,last:!m.value,children:a.jsx(te,{"aria-label":o,checked:m.value,onChange:d=>m.set(d)})}),m.value?h:g?a.jsx("div",{"data-testid":s,className:"hn-set-inherited",children:g}):null]})}function Oe({label:e,value:t,min:n,max:r,placeholder:c,width:o,onCommit:l,onToast:u}){const[g,s]=f.useState(String(t));f.useEffect(()=>s(String(t)),[t]);const h=y({value:t,delayMs:0,save:d=>l(d)}),m=()=>{const d=g.trim(),k=d===""?NaN:Math.floor(Number(d));if(!Number.isFinite(k)||k<n){u==null||u(`${e}: isi angka ${n} atau lebih. Nilai sebelumnya dipertahankan.`,"warn","alert-triangle"),s(String(t));return}const v=Math.min(k,r);v!==k&&(u==null||u(`${e} dibatasi ke ${r}.`,"warn","alert-triangle"),s(String(v))),v!==t&&h.set(v)};return a.jsx(le,{"aria-label":e,type:"number",min:n,max:r,placeholder:c,className:o??"hn-set-w-xs",value:g,onChange:d=>s(d.target.value),onBlur:m,onKeyDown:d=>{d.key==="Enter"&&m()}})}function pe({info:e}){const[t,n]=f.useState(null);f.useEffect(()=>{var o,l;if(e!==void 0)return;let c=!0;return(l=(o=Q).getAntigravityVersion)==null||l.call(o).then(u=>{c&&n(u)}).catch(()=>{c&&n({version:null,error:"Versi Antigravity tidak dapat diperiksa."})}),()=>{c=!1}},[e]);const r=e===void 0?t:e;return a.jsxs("div",{role:"status","data-testid":"antigravity-version-note",className:"hn-set-codex-note",children:["Antigravity CLI · versi ",(r==null?void 0:r.version)??"tak terdeteksi",". ",r==null?void 0:r.error,a.jsx("p",{children:"Host/lab saja; sandbox belum didukung. Mode goal native belum didukung. Telemetri native tidak diketahui."}),a.jsx("a",{href:"https://antigravity.google/docs/cli",target:"_blank",rel:"noreferrer",children:"Panduan pemasangan dan login resmi"})]})}export{pe as A,Ce as B,be as C,L as D,Fe as E,Ie as F,Oe as N,me as P,S,x as a,Le as b,fe as c,Re as d,xe as e,Te as f,we as g,_e as h,De as i,ce as j,je as n,Ae as r,Ne as s,y as u};