hanoman 0.9.7 → 0.9.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build-info.json +3 -3
- package/dist/cli.js +556 -117
- package/dist/server.js +1365 -482
- package/package.json +1 -1
- package/prisma/migrations/20260925120000_spec_project_notification_created_idx/migration.sql +6 -0
- package/prisma/schema.prisma +8 -0
- package/web/assets/{ChangelogScreen-C-C71Zn_.js → ChangelogScreen-BzuBQwxY.js} +1 -1
- package/web/assets/{DalangHanomanScreen-Go6ETy3r.js → DalangHanomanScreen-6Z1RoINb.js} +1 -1
- package/web/assets/{DocPreviewModal-CZ4rZ_h-.js → DocPreviewModal-CIDz4ZzG.js} +1 -1
- package/web/assets/{DocsWorkspace-BDfP0ML1.js → DocsWorkspace-CQ_EsxYz.js} +1 -1
- package/web/assets/{IdeScreen-DFRme37j.js → IdeScreen-C0dHzGLc.js} +1 -1
- package/web/assets/{LeadScreen-ASzNKRLX.js → LeadScreen-BHU9MYR1.js} +1 -1
- package/web/assets/{ReviewScreen-CyFWhxL1.js → ReviewScreen-DZi2r33C.js} +1 -1
- package/web/assets/SchedulerScreen-B5IdNK-B.js +1 -0
- package/web/assets/{SettingsScreen-siSgzEnH.js → SettingsScreen-CCGup_hQ.js} +1 -1
- package/web/assets/{TeamScreen-DzKZHKyR.js → TeamScreen-DV6IwXuC.js} +1 -1
- package/web/assets/{TerminalScreen-mLiyHYQV.js → TerminalScreen-DFnBKKa2.js} +1 -1
- package/web/assets/{TriageScreen-D5iyoK-3.js → TriageScreen-DoHczdu8.js} +1 -1
- package/web/assets/{VpsScreen-BhjULQaT.js → VpsScreen-CghVzou6.js} +1 -1
- package/web/assets/index-B3niUZnk.js +1014 -0
- package/web/assets/{live-Jy46oHWQ.js → live-fPTkukus.js} +1 -1
- package/web/index.html +1 -1
- package/web/assets/SchedulerScreen-Bii5m-K1.js +0 -1
- package/web/assets/index-CCJTT5hd.js +0 -1005
|
@@ -1 +1 @@
|
|
|
1
|
-
import{aM as i,j as u,B as f}from"./index-
|
|
1
|
+
import{aM as i,j as u,B as f}from"./index-B3niUZnk.js";import{R as s}from"./react-DfGhg7ZW.js";const w=6e3;function d({className:o="",style:a={}}){const e=i(),n=!e.connected&&!e.paused,[r,t]=s.useState(()=>Date.now());return s.useEffect(()=>{if(!n)return;t(Date.now());const c=setInterval(()=>t(Date.now()),1e3);return()=>clearInterval(c)},[n,e.since]),!n||r-e.since<w?null:u.jsx(f,{tone:"warn",variant:"soft",icon:"wifi-off",className:o,style:a,children:"koneksi terputus · menyambung ulang…"})}export{d as L};
|
package/web/index.html
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
7
7
|
<title>hanoman</title>
|
|
8
|
-
<script type="module" crossorigin src="/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-B3niUZnk.js"></script>
|
|
9
9
|
<link rel="modulepreload" crossorigin href="/assets/react-DfGhg7ZW.js">
|
|
10
10
|
<link rel="modulepreload" crossorigin href="/assets/markdown-CWEY34jk.js">
|
|
11
11
|
<link rel="modulepreload" crossorigin href="/assets/xterm-3VOAfa_q.js">
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{h as $,p as le,y as ie,e as v,aD as U,aE as se,j as e,aq as w,I as T,a as g,B as P,aF as oe,M as de,c as C,d as z,S as I,aG as ue,H as ce,aH as Q,V as pe,aI as O,aJ as me,aK as M,x as V,w as Y,D as X,q as Z,f as _,z as xe,aL as he}from"./index-CCJTT5hd.js";import{R as x}from"./react-DfGhg7ZW.js";import{L as ge}from"./live-Jy46oHWQ.js";import"./markdown-CWEY34jk.js";import"./xterm-3VOAfa_q.js";const J=10,G=a=>String(a).padStart(2,"0"),B=a=>a?new Date(a).toLocaleString("id-ID",{dateStyle:"medium",timeStyle:"short"}):"—",K=a=>{const i={name:(a==null?void 0:a.name)??"",prompt:(a==null?void 0:a.prompt)??"",enabled:(a==null?void 0:a.enabled)??!1,kind:"lanjutan",time:"07:00",weekday:1,everyHours:6,expr:(a==null?void 0:a.expr)??"0 7 * * *",agent:(a==null?void 0:a.agent)??"",model:(a==null?void 0:a.model)??"",effort:(a==null?void 0:a.effort)??""},l=a?me(a.expr):{kind:"harian",hour:7,minute:0};if(!l)return i;if(l.kind==="tiap-n-jam")return{...i,kind:l.kind,everyHours:l.everyHours,time:`00:${G(l.minute)}`};const t=`${G(l.hour)}:${G(l.minute)}`;return l.kind==="mingguan"?{...i,kind:l.kind,time:t,weekday:l.weekday}:{...i,kind:l.kind,time:t}},fe=a=>{if(a.kind==="lanjutan")return a.expr.trim();const[i,l]=a.time.split(":").map(Number);switch(a.kind){case"harian":return M({kind:"harian",hour:i,minute:l});case"hari-kerja":return M({kind:"hari-kerja",hour:i,minute:l});case"mingguan":return M({kind:"mingguan",hour:i,minute:l,weekday:a.weekday});case"tiap-n-jam":return M({kind:"tiap-n-jam",everyHours:a.everyHours,minute:l})}},be={launched:"ok",queued:"neutral",skipped:"warn",failed:"err"},je={launched:"berjalan",queued:"menunggu",skipped:"dilewati",failed:"gagal"};function ve({cronId:a}){const[i,l]=x.useState([]),[t,p]=x.useState(0),[u,f]=$("scheduler","cronRunsPage",1,V);x.useEffect(()=>{let o=!0;return v.listCronRuns(a,{page:u,limit:J}).then(n=>{o&&(l(n.items),p(n.total))}).catch(()=>{o&&(l([]),p(0))}),()=>{o=!1}},[a,u]);const m=X(t,u,J);return t===0?e.jsx("div",{style:{fontSize:"var(--text-sm)",color:"var(--text-subtle)"},children:"Belum ada eksekusi."}):e.jsxs(e.Fragment,{children:[i.map(o=>e.jsxs("div",{className:"hn-dense-row",style:{display:"flex",alignItems:"center",gap:10,padding:"8px 10px",border:"1px solid var(--border-hair)",borderRadius:"var(--radius-sm)",marginBottom:6},children:[e.jsx(P,{tone:be[o.status]??"neutral",size:"sm",children:je[o.status]??o.status}),e.jsxs("span",{style:{flex:1,minWidth:0,fontSize:"var(--text-xs)",color:"var(--text-muted)"},children:["jatuh tempo ",B(o.dueAt),o.startedAt?` · mulai ${B(o.startedAt)}`:"",o.sessionId?` · sesi ${o.sessionId}`:"",o.manual?" · uji coba":"",o.note?` · ${o.note}`:""]})]},o.id)),e.jsx(Y,{page:m.page,pageCount:m.pageCount,total:t,from:m.from,to:m.to,onPage:f,unit:"run"})]})}function ye({projects:a,onProjectChanged:i,onToast:l}){var F;const[t,p]=$("scheduler","cronProject",((F=a[0])==null?void 0:F.id)??"",le),[u,f]=x.useState([]),[m,o]=x.useState(void 0),[n,d]=x.useState(K()),[j,k]=$("scheduler","cronOpenRuns",null,ie),[h,y]=x.useState(!1),D=a.find(r=>r.id===t),S=x.useCallback(()=>{if(!t){f([]);return}v.listCrons({projectId:t,page:1,limit:100}).then(r=>f(r.items)).catch(()=>f([]))},[t]);x.useEffect(()=>{S()},[S]);const s=r=>{o(r??null),d(K(r))},b=fe(n),A=U(b)?se(b,new Date):null,L=async()=>{var r;if(!U(b)){l("Cron expression tak sah","err","x-circle");return}y(!0);try{m?await v.patchCron(m.id,{name:n.name,expr:b,prompt:n.prompt,enabled:n.enabled,agent:n.agent||null,model:n.model||null,effort:n.effort||null}):await v.createCron({project:t,name:n.name,expr:b,prompt:n.prompt,enabled:n.enabled,agent:n.agent||void 0,model:n.model||void 0,effort:n.effort||void 0}),l("Cron tersimpan","ok","save"),o(void 0),S()}catch(c){l(((r=c.detail)==null?void 0:r.error)??"Gagal menyimpan cron","err","x-circle")}finally{y(!1)}},ae=async r=>{var c;y(!0);try{await v.runCronNow(r),l("Uji coba diantrekan — sesi terbuka di tick berikutnya","ok","play")}catch(re){l(((c=re.detail)==null?void 0:c.error)??"Gagal menjalankan cron","err","x-circle")}finally{y(!1),S()}},te=async r=>{y(!0);try{await v.deleteCron(r),l("Cron dihapus","ok","trash")}catch{l("Gagal menghapus cron","err","x-circle")}finally{y(!1),S()}},ne=async()=>{if(t)try{await v.updateProject(t,{schedulerOptIn:!0}),await i(t),l("Project di-opt-in","ok")}catch{l("Gagal mengubah opt-in","err","x-circle")}},N=n.agent||"claude";return e.jsxs(w,{eyebrow:"scheduler · cronjob",title:"Pengecekan rutin per project",actions:e.jsxs("div",{style:{display:"flex",gap:8,alignItems:"center"},children:[e.jsx(I,{value:t,"aria-label":"Project",onChange:r=>p(r.target.value),options:a.map(r=>({value:r.id,label:r.name}))}),e.jsx(g,{size:"sm",leftIcon:"plus",disabled:!t,onClick:()=>s(),children:"Cron baru"})]}),children:[D&&!D.schedulerOptIn&&e.jsxs("div",{className:"hn-dense-row",style:{display:"flex",alignItems:"center",gap:10,marginBottom:12,padding:"10px 12px",border:"1px solid var(--border-hair)",borderRadius:"var(--radius-sm)",background:"var(--surface-sunken)"},children:[e.jsx(T,{name:"alert-triangle",size:16,color:"var(--clay-500)"}),e.jsx("span",{style:{flex:1,fontSize:"var(--text-xs)",color:"var(--text-muted)"},children:"Project ini belum di-opt-in scheduler — cron-nya tak akan pernah dijalankan."}),e.jsx(g,{size:"sm",leftIcon:"check",onClick:()=>void ne(),children:"Aktifkan scheduler di project ini"})]}),u.length===0?e.jsx("div",{style:{fontSize:"var(--text-sm)",color:"var(--text-subtle)"},children:"Belum ada cron di project ini."}):u.map(r=>e.jsxs("div",{style:{padding:"10px 12px",marginBottom:6,border:"1px solid var(--border-hair)",borderRadius:"var(--radius-sm)",background:"var(--surface-card)"},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:10,flexWrap:"wrap"},children:[e.jsx("span",{style:{color:"var(--text-strong)",fontWeight:500},children:r.name}),e.jsx(P,{tone:r.enabled?"ok":"neutral",size:"sm",children:r.enabled?"aktif":"nonaktif"}),e.jsx("span",{style:{flex:1}}),e.jsx(g,{size:"sm",variant:"ghost",leftIcon:"play",disabled:h,onClick:()=>void ae(r.id),children:"Jalankan sekarang"}),e.jsx(g,{size:"sm",variant:"ghost",leftIcon:"list",onClick:()=>k(j===r.id?null:r.id),children:"Riwayat"}),e.jsx(g,{size:"sm",variant:"ghost",leftIcon:"pencil",onClick:()=>s(r),children:"Ubah"}),e.jsx(g,{size:"sm",variant:"ghost",leftIcon:"trash",disabled:h,onClick:()=>void te(r.id),children:"Hapus"})]}),e.jsxs("div",{style:{marginTop:4,fontSize:"var(--text-xs)",color:"var(--text-subtle)"},children:[oe(r.expr)," · terakhir ",B(r.lastRunAt)," · berikutnya ",B(r.nextRunAt)]}),j===r.id&&e.jsx("div",{style:{marginTop:10},children:e.jsx(ve,{cronId:r.id})})]},r.id)),e.jsxs(de,{open:m!==void 0,title:m?"Ubah cron":"Cron baru",eyebrow:"scheduler",onClose:()=>o(void 0),width:620,footer:e.jsxs("div",{style:{display:"flex",gap:8,justifyContent:"flex-end"},children:[e.jsx(g,{size:"sm",variant:"ghost",onClick:()=>o(void 0),children:"Batal"}),e.jsx(g,{size:"sm",leftIcon:"save",disabled:h,onClick:()=>void L(),children:"Simpan"})]}),children:[e.jsx(C,{label:"Nama cron",children:e.jsx(z,{"aria-label":"Nama cron",placeholder:"Cek error produksi pagi",value:n.name,onChange:r=>d(c=>({...c,name:r.target.value}))})}),e.jsxs("div",{className:"hn-grid-mobile",style:{display:"grid",gridTemplateColumns:"repeat(3, minmax(0,1fr))",gap:10},children:[e.jsx(C,{label:"Preset jadwal",children:e.jsx(I,{"aria-label":"Preset jadwal",value:n.kind,onChange:r=>d(c=>({...c,kind:r.target.value})),options:[{value:"harian",label:"Setiap hari"},{value:"hari-kerja",label:"Hari kerja"},{value:"mingguan",label:"Mingguan"},{value:"tiap-n-jam",label:"Tiap N jam"},{value:"lanjutan",label:"Lanjutan (cron expression)"}]})}),n.kind!=="lanjutan"&&e.jsx(C,{label:n.kind==="tiap-n-jam"?"Menit (dari jam)":"Jam",children:e.jsx(z,{type:"time","aria-label":"Jam",value:n.time,onChange:r=>d(c=>({...c,time:r.target.value}))})}),n.kind==="mingguan"&&e.jsx(C,{label:"Hari",children:e.jsx(I,{"aria-label":"Hari",value:String(n.weekday),onChange:r=>d(c=>({...c,weekday:Number(r.target.value)})),options:ue.map((r,c)=>({value:String(c),label:r}))})}),n.kind==="tiap-n-jam"&&e.jsx(C,{label:"Tiap berapa jam",children:e.jsx(z,{type:"number",min:1,max:23,"aria-label":"Tiap berapa jam",placeholder:"mis. 6",value:String(n.everyHours),onChange:r=>d(c=>({...c,everyHours:Math.min(23,Math.max(1,Number(r.target.value)||1))}))})})]}),n.kind==="lanjutan"&&e.jsx(C,{label:"Cron expression",hint:"Lima field: menit jam tanggal bulan hari-pekan — zona waktu server.",children:e.jsx(z,{"aria-label":"Cron expression",placeholder:"0 7 * * 1-5",value:n.expr,onChange:r=>d(c=>({...c,expr:r.target.value}))})}),e.jsx("div",{"data-testid":"cron-next-preview",style:{marginBottom:14,fontSize:"var(--text-xs)",color:A?"var(--text-muted)":"var(--clay-500)"},children:A?`Jalan berikutnya: ${B(A.toISOString())} (waktu lokal)`:"Jadwal tak sah — tak ada jalan berikutnya"}),e.jsx(C,{label:"Prompt",hint:"Instruksi bebas untuk agen. Temuan sebaiknya difilekan sebagai backlog lewat POST /api/specs.",children:e.jsx(ce,{"aria-label":"Prompt",rows:6,placeholder:"mis. Periksa error 5xx sejak kemarin, lalu filekan temuannya sebagai QA finding.",value:n.prompt,onChange:r=>d(c=>({...c,prompt:r.target.value}))})}),e.jsxs("div",{className:"hn-grid-mobile",style:{display:"grid",gridTemplateColumns:"repeat(3, minmax(0,1fr))",gap:10},children:[e.jsx(C,{label:"Runtime",children:e.jsx(I,{"aria-label":"Runtime",value:n.agent,onChange:r=>d(c=>({...c,agent:r.target.value,model:"",effort:""})),options:[{value:"",label:"Warisi default sesi"},{value:"claude",label:"Claude Code"},{value:"codex",label:"Codex CLI"}]})}),e.jsx(C,{label:"Model",children:e.jsx(I,{"aria-label":"Model",value:n.model,disabled:!n.agent,onChange:r=>d(c=>({...c,model:r.target.value,effort:""})),options:[{value:"",label:"Warisi"},...Q(N).map(r=>({value:r.id,label:r.label}))]})}),e.jsx(C,{label:"Effort",children:e.jsx(I,{"aria-label":"Effort",value:n.effort,disabled:!n.agent,onChange:r=>d(c=>({...c,effort:r.target.value})),options:[{value:"",label:"Warisi"},...pe(N,n.model||Q(N)[0].id).map(r=>({value:r,label:r}))]})})]}),e.jsx(O,{label:"Aktif",checked:n.enabled,onChange:r=>d(c=>({...c,enabled:r}))})]})]})}const q=5e3,H=10;function ee(a,i=Date.now()){if(!a)return"—";const l=Math.max(0,i-new Date(a).getTime()),t=Math.floor(l/6e4);if(t<1)return"baru saja";if(t<60)return`${t}m`;const p=Math.floor(t/60);return p<24?`${p}j`:`${Math.floor(p/24)}h`}function ke(a,i=Date.now()){if(!a)return"—";const l=new Date(a).getTime()-i;if(l<=0)return"jatuh tempo";const t=Math.ceil(l/6e4);return t<60?`${t}m lagi`:`${Math.ceil(t/60)}j lagi`}const Ce={tinggi:"err",sedang:"warn",rendah:"neutral"};function E(a,i){var l;return((l=i.find(t=>t.id===a))==null?void 0:l.title)??a}function Se({s:a}){return e.jsxs("div",{style:{padding:"12px 14px",border:"1px solid var(--border-hair)",borderRadius:"var(--radius-md)",background:"var(--surface-card)",display:"flex",flexDirection:"column",gap:6,flex:1,minWidth:180},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8},children:[e.jsx("span",{style:{fontFamily:"var(--font-mono)",fontWeight:600,color:"var(--text-strong)"},children:a.id}),e.jsx(P,{tone:a.enabled?"ok":"neutral",size:"sm",children:a.enabled?"aktif":"nonaktif"})]}),e.jsxs("div",{style:{fontSize:"var(--text-xs)",color:"var(--text-subtle)"},children:["tiap ",a.everyMin,"m"]}),e.jsxs("div",{style:{fontSize:"var(--text-xs)",color:"var(--text-muted)"},children:["terakhir ",ee(a.lastRunAt)," · berikutnya ",ke(a.nextRunAt)]})]})}function R({children:a}){return e.jsx("div",{className:"hn-dense-row",style:{display:"flex",alignItems:"center",gap:10,padding:"10px 12px",border:"1px solid var(--border-hair)",borderRadius:"var(--radius-sm)",background:"var(--surface-card)",marginBottom:6},children:a})}function we({q:a,backlog:i,onCancel:l,busy:t}){return e.jsxs(R,{children:[e.jsxs("span",{style:{flex:1,minWidth:0},children:[e.jsx("span",{style:{color:"var(--text-strong)",fontWeight:500},children:E(a.specId,i)}),e.jsxs("span",{style:{display:"block",fontSize:"var(--text-xs)",color:"var(--text-subtle)"},children:[a.projectId," · ",a.source,a.note?` · ${a.note}`:""]})]}),e.jsx(P,{tone:Ce[a.priority]??"neutral",size:"sm",children:a.priority}),e.jsx(g,{size:"sm",variant:"ghost",leftIcon:"ban",disabled:t,onClick:()=>l(a.id),children:"Batalkan"})]})}function Ie({q:a,backlog:i,onRequeue:l,busy:t}){return e.jsxs(R,{children:[e.jsx(T,{name:"ban",size:16,color:"var(--text-subtle)"}),e.jsxs("span",{style:{flex:1,minWidth:0},children:[e.jsx("span",{style:{color:"var(--text-strong)",fontWeight:500},children:E(a.specId,i)}),e.jsxs("span",{style:{display:"block",fontSize:"var(--text-xs)",color:"var(--text-subtle)"},children:[a.projectId," · ",a.source," · ",a.note??"dibatalkan"]})]}),e.jsx(g,{size:"sm",variant:"ghost",leftIcon:"rotate-ccw",disabled:t,onClick:()=>l(a.id),children:"Antre lagi"})]})}function ze({s:a,backlog:i,onGotoTerminal:l}){return e.jsxs(R,{children:[e.jsxs("span",{style:{flex:1,minWidth:0},children:[e.jsx("span",{style:{color:"var(--text-strong)",fontWeight:500},children:E(a.specId,i)}),e.jsxs("span",{style:{display:"block",fontSize:"var(--text-xs)",color:"var(--text-subtle)"},children:[a.projectId,a.flow?` · ${a.flow}`:""]})]}),a.decision&&e.jsx(P,{tone:"warn",icon:"bell",size:"sm",children:"menunggu keputusan"}),e.jsx(g,{size:"sm",variant:"ghost",leftIcon:"terminal",onClick:()=>l(a.id),children:"Buka terminal"})]})}function Pe({q:a,backlog:i,onToast:l}){const t=xe(a.specId);return e.jsxs(R,{children:[e.jsxs("span",{style:{flex:1,minWidth:0},children:[e.jsx("span",{style:{color:"var(--text-strong)",fontWeight:500},children:E(a.specId,i)}),e.jsxs("span",{style:{display:"block",fontSize:"var(--text-xs)",color:"var(--text-subtle)"},children:[a.projectId," · ",a.source," · ",a.launchedAt?`selesai ${ee(a.launchedAt)}`:a.note??"tak diluncurkan",a.sessionId?` · hanoman/${a.sessionId}`:""]})]}),e.jsx(g,{size:"sm",variant:"ghost",leftIcon:"external-link",onClick:()=>window.open(t,"_blank","noreferrer"),children:"Buka review"}),e.jsx(g,{size:"sm",variant:"ghost",leftIcon:"copy",onClick:()=>{var p;(p=navigator.clipboard)==null||p.writeText(t),l("Link review disalin","ok","copy")},children:"Salin"})]})}function Re({q:a,backlog:i}){return e.jsxs(R,{children:[e.jsx(T,{name:"x-circle",size:16,color:"var(--clay-500)"}),e.jsxs("span",{style:{flex:1,minWidth:0},children:[e.jsx("span",{style:{color:"var(--text-strong)",fontWeight:500},children:E(a.specId,i)}),e.jsxs("span",{style:{display:"block",fontSize:"var(--text-xs)",color:"var(--text-subtle)"},children:[a.projectId," · ",a.note??"gagal tanpa alasan tercatat"]})]})]})}function Ae({title:a,count:i,empty:l,children:t}){return e.jsx(w,{eyebrow:"scheduler",title:`${a}${i?` · ${i}`:""}`,children:i===0?e.jsx("div",{style:{fontSize:"var(--text-sm)",color:"var(--text-subtle)"},children:l}):t})}function W({title:a,status:i,count:l,empty:t,render:p}){const[u,f]=x.useState([]),[m,o]=x.useState(0),[n,d]=$("scheduler",`queue-${i}-page`,1,V),j=x.useCallback(()=>{let h=!0;return v.getSchedulerQueue({status:i,page:n,limit:H}).then(y=>{h&&(f(y.items),o(y.total))}).catch(()=>{h&&(f([]),o(0))}),()=>{h=!1}},[i,n]);x.useEffect(()=>j(),[j]),Z({topic:"schedulerQueue",params:{status:i,page:n,limit:H},apply:h=>{f(h.data.items),o(h.data.total)},refetch:()=>{j()},pollMs:q});const k=X(m,n,H);return e.jsx(w,{eyebrow:"scheduler",title:`${a}${l?` · ${l}`:""}`,children:l===0?e.jsx("div",{style:{fontSize:"var(--text-sm)",color:"var(--text-subtle)"},children:t}):e.jsxs(e.Fragment,{children:[u.map(h=>p(h)),e.jsx(Y,{page:k.page,pageCount:k.pageCount,total:m,from:k.from,to:k.to,onPage:d,unit:"item"})]})})}function Le({cfg:a,cap:i,liveCount:l,onWrite:t,busy:p}){const u=!a.enabled,f=u?"neutral":a.paused?"warn":"ok",m=u?"berhenti":a.paused?"dijeda":"aktif";return e.jsx(w,{eyebrow:"scheduler · rem darurat",title:"Kendali",children:e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:12,flexWrap:"wrap"},children:[e.jsx(P,{tone:f,children:m}),e.jsxs("span",{style:{fontSize:"var(--text-sm)",color:"var(--text-muted)"},children:[l," / ",i," sesi hidup"]}),e.jsx(ge,{}),e.jsx("span",{style:{flex:1}}),a.enabled&&e.jsx(g,{size:"sm",variant:"secondary",leftIcon:a.paused?"play":"pause",disabled:p,onClick:()=>t({...a,paused:!a.paused}),children:a.paused?"Lanjutkan":"Pause"}),a.enabled?e.jsx(g,{size:"sm",variant:"ghost",leftIcon:"square",disabled:p,onClick:()=>t({...a,enabled:!1}),children:"Stop"}):e.jsx(g,{size:"sm",leftIcon:"play",disabled:p,onClick:()=>t({...a,enabled:!0}),children:"Aktifkan"})]})})}function Be({status:a}){return e.jsx(w,{eyebrow:"host · peluncuran agen",title:"Gerbang peluncuran",children:e.jsxs("div",{"aria-label":"Status gerbang peluncuran",style:{fontSize:"var(--text-sm)",color:"var(--text-muted)",lineHeight:1.6},children:[e.jsxs("div",{children:["Gerbang ",a.enabled?"aktif":"nonaktif"," · ",a.liveCount," sesi hidup · ",a.liveAgentCount," agen terstruktur · cap ",a.maxConcurrent]}),e.jsxs("div",{children:["Load per core: ",a.loadStatus==="available"&&a.loadPerCore!==null?a.loadPerCore.toFixed(2):"tidak tersedia",a.loadStatus==="unsupported"?" (tidak didukung platform)":""," · ambang ",a.maxLoadPerCore]}),e.jsx("div",{style:{fontSize:"var(--text-xs)",marginTop:6},children:"Berlaku juga saat scheduler berhenti. Terminal dan shell tetap bisa dibuka; keduanya ikut mengisi cap."})]})})}function Ee({cfg:a,onWrite:i,busy:l}){const[t,p]=x.useState(a);x.useEffect(()=>{p(a)},[a]);const u=(n,d)=>p(j=>({...j,sources:{...j.sources,[n]:{...j.sources[n],...d}}})),f=(n,d=1)=>Math.max(d,Number(n)||d),m=t.launchGuard??he.launchGuard,o=Number.isFinite(m.maxLoadPerCore)&&m.maxLoadPerCore>0;return e.jsxs(w,{eyebrow:"scheduler · setelan",title:"Konfigurasi",actions:e.jsx(g,{size:"sm",leftIcon:"save",disabled:l||!o,onClick:()=>i({...t,launchGuard:m}),children:"Simpan setelan"}),children:[e.jsxs("div",{className:"hn-grid-mobile",style:{display:"grid",gridTemplateColumns:"repeat(2, minmax(0,1fr))",gap:14},children:[e.jsxs("label",{style:{display:"flex",flexDirection:"column",gap:4},children:[e.jsx("span",{className:"hn-eyebrow",children:"Cap concurrent"}),e.jsx(z,{type:"number",min:1,value:String(t.maxConcurrent),"aria-label":"Cap concurrent",placeholder:"6",onChange:n=>p(d=>({...d,maxConcurrent:f(n.target.value)}))})]}),e.jsxs("label",{style:{display:"flex",flexDirection:"column",gap:4},children:[e.jsx("span",{className:"hn-eyebrow",children:"Autonomy"}),e.jsx(I,{value:t.autonomy,"aria-label":"Autonomy",onChange:n=>p(d=>({...d,autonomy:n.target.value})),options:[{value:"butuh-keputusan",label:"butuh-keputusan"},{value:"full-control",label:"full-control"}]})]})]}),e.jsxs("div",{style:{marginTop:14,padding:"10px 12px",border:"1px solid var(--border-hair)",borderRadius:"var(--radius-sm)"},children:[e.jsx(O,{label:"Gerbang peluncuran",checked:m.enabled,onChange:n=>p(d=>({...d,launchGuard:{...m,enabled:n}}))}),e.jsx("p",{style:{fontSize:"var(--text-xs)",color:"var(--text-muted)",lineHeight:1.5},children:"Membatasi peluncuran agen menurut cap sesi dan beban host, termasuk peluncuran manual. Mematikannya melewati kedua pemeriksaan. Terpisah dari sakelar scheduler dan source."}),e.jsxs("label",{style:{display:"flex",flexDirection:"column",gap:4},children:[e.jsx("span",{className:"hn-eyebrow",children:"Ambang load per core"}),e.jsx(z,{type:"number",min:0,step:"any",value:String(m.maxLoadPerCore),"aria-label":"Ambang load per core","aria-invalid":!o,placeholder:"2.5",onChange:n=>p(d=>({...d,launchGuard:{...m,maxLoadPerCore:Number(n.target.value)}}))}),!o&&e.jsx("span",{style:{fontSize:"var(--text-xs)",color:"var(--clay-500)"},children:"Isi angka lebih besar dari nol."})]})]}),e.jsx("div",{style:{marginTop:14,display:"flex",flexDirection:"column",gap:10},children:["backlog","triase"].map(n=>e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:12,flexWrap:"wrap",padding:"10px 12px",border:"1px solid var(--border-hair)",borderRadius:"var(--radius-sm)"},children:[e.jsx(O,{label:n,checked:t.sources[n].enabled,onChange:d=>u(n,{enabled:d})}),e.jsx("span",{style:{flex:1}}),e.jsxs("label",{style:{display:"flex",alignItems:"center",gap:6,fontSize:"var(--text-xs)"},children:["tiap",e.jsx(z,{type:"number",min:1,style:{width:84},"aria-label":`cadence ${n}`,placeholder:"30",value:String(t.sources[n].everyMin),onChange:d=>u(n,{everyMin:f(d.target.value)})}),"menit"]})]},n))})]})}function De({projects:a,onToggle:i,busyId:l}){return e.jsxs(w,{eyebrow:"scheduler · opt-in project",title:"Project yang diizinkan",children:[e.jsx("div",{style:{fontSize:"var(--text-xs)",color:"var(--text-subtle)",marginBottom:10},children:"Scheduler hanya menyentuh project yang di-opt-in. Default mati."}),a.length===0?e.jsx("div",{style:{fontSize:"var(--text-sm)",color:"var(--text-subtle)"},children:"Belum ada project."}):a.map(t=>e.jsxs(R,{children:[e.jsx("span",{style:{flex:1,minWidth:0,color:"var(--text-strong)",fontWeight:500},children:t.name}),e.jsx(P,{tone:t.schedulerOptIn?"ok":"neutral",size:"sm",children:t.schedulerOptIn?"opt-in":"mati"}),t.schedulerOptIn?e.jsx(g,{size:"sm",variant:"ghost",leftIcon:"ban",disabled:l===t.id,onClick:()=>i(t.id,!1),children:"Cabut opt-in"}):e.jsx(g,{size:"sm",leftIcon:"check",disabled:l===t.id,onClick:()=>i(t.id,!0),children:"Opt-in"})]},t.id))]})}function He({projects:a,backlog:i,onProjectChanged:l,onToast:t,onGotoTerminal:p}){const[u,f]=x.useState(null),[m,o]=x.useState("loading"),[n,d]=x.useState(!1),[j,k]=x.useState(null),h=x.useCallback((s=!1)=>{s||o("loading"),v.getSchedulerState().then(b=>{f(b),o("ready")}).catch(()=>{s||o("error")})},[]);x.useEffect(()=>{h()},[h]),Z({topic:"schedulerState",params:{},apply:s=>{f(s.state),o("ready")},refetch:()=>h(!0),pollMs:q});const y=x.useCallback(async s=>{d(!0);try{await v.putSchedulerConfig(s),t("Setelan scheduler tersimpan","ok","save"),h(!0)}catch{t("Gagal menyimpan setelan","err","x-circle")}finally{d(!1)}},[h,t]),D=x.useCallback(async(s,b)=>{k(s);try{await v.updateProject(s,{schedulerOptIn:b}),await l(s),t(b?"Project di-opt-in":"Opt-in dicabut","ok")}catch{t("Gagal mengubah opt-in","err","x-circle")}finally{k(null)}},[l,t]),S=x.useCallback(async(s,b)=>{k(s);try{b==="cancel"?(await v.cancelSchedulerQueueItem(s),t("Item antrean dibatalkan","ok","ban")):(await v.requeueSchedulerQueueItem(s),t("Item dikembalikan ke antrean","ok","rotate-ccw"))}catch(A){const L=A.detail;t((L==null?void 0:L.error)??"Gagal mengubah item antrean","err","x-circle")}finally{k(null),h(!0)}},[h,t]);return m==="loading"?e.jsx(_,{kind:"loading"}):m==="error"||!u?e.jsx(_,{kind:"error",hint:"Gagal memuat state scheduler.",action:()=>h(),actionLabel:"Coba lagi"}):e.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:16,minHeight:0},children:[e.jsx(Le,{cfg:u.config,cap:u.cap,liveCount:u.liveCount,onWrite:y,busy:n}),u.admission&&e.jsx(Be,{status:u.admission}),e.jsx(w,{eyebrow:"scheduler · observabilitas",title:"Status per source",children:e.jsx("div",{style:{display:"flex",gap:10,flexWrap:"wrap"},children:u.sources.map(s=>e.jsx(Se,{s},s.id))})}),e.jsx(ye,{projects:a,onProjectChanged:l,onToast:t}),e.jsx(W,{title:"Antrean",status:"queued",count:u.queueCounts.queued,empty:"Antrean kosong.",render:s=>e.jsx(we,{q:s,backlog:i,onCancel:b=>void S(b,"cancel"),busy:j===s.id},s.id)}),e.jsx(W,{title:"Dibatalkan",status:"canceled",count:u.queueCounts.canceled,empty:"Tak ada item yang dibatalkan.",render:s=>e.jsx(Ie,{q:s,backlog:i,onRequeue:b=>void S(b,"requeue"),busy:j===s.id},s.id)}),e.jsx(Ae,{title:"Sesi berjalan",count:u.sessions.length,empty:"Tak ada sesi scheduler berjalan.",children:u.sessions.map(s=>e.jsx(ze,{s,backlog:i,onGotoTerminal:p},s.id))}),e.jsx(W,{title:"Selesai (done)",status:"done",count:u.queueCounts.done,empty:"Belum ada hasil selesai.",render:s=>e.jsx(Pe,{q:s,backlog:i,onToast:t},s.id)}),e.jsx(W,{title:"Gagal",status:"failed",count:u.queueCounts.failed,empty:"Tak ada sesi gagal.",render:s=>e.jsx(Re,{q:s,backlog:i},s.id)}),e.jsx(Ee,{cfg:u.config,onWrite:y,busy:n}),e.jsx(De,{projects:a,onToggle:D,busyId:j})]})}export{He as SchedulerScreen};
|