@mmmbuto/nexuscrew 0.8.38 → 0.8.39
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/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to NexusCrew are tracked here.
|
|
4
4
|
|
|
5
|
+
## 0.8.39 — 2026-07-25 — "Honest Peer"
|
|
6
|
+
|
|
7
|
+
- Fixes `nexuscrew nodes test` and `nexuscrew nodes doctor` falsely reporting a
|
|
8
|
+
broken pairing for healthy outbound peers. The commands no longer present a
|
|
9
|
+
per-peer federation credential to `/api/config`, which correctly accepts only
|
|
10
|
+
the remote browser/UI token and therefore returned a misleading `401`.
|
|
11
|
+
- Probes the authenticated `/federation/health` endpoint instead, matching the
|
|
12
|
+
live topology health path and binding a successful response to the expected
|
|
13
|
+
peer instance ID. A real federation `401` remains an actionable `token-ko`;
|
|
14
|
+
transport, payload and identity failures remain distinct health failures.
|
|
15
|
+
- Keeps the diagnostic read-only, never returns or logs the peer credential,
|
|
16
|
+
and preserves the existing inbound, tunnel-down and missing-token behavior.
|
|
17
|
+
- Gate: **1,068 isolated Node tests** (1,067 pass / 1 platform skip),
|
|
18
|
+
**300/300 frontend tests**, production PWA build and zero production
|
|
19
|
+
dependency vulnerabilities in both dependency trees.
|
|
20
|
+
|
|
5
21
|
## 0.8.38 — 2026-07-25 — "Right Voice"
|
|
6
22
|
|
|
7
23
|
- Adds an optional, validated `lang` field to `nc_notify` and carries it through
|
|
@@ -90,4 +90,4 @@ Minimum version required to store current data is: `+F+`.
|
|
|
90
90
|
`).filter(o=>o!==""),promptMode:e.promptMode};return e.modelFlag&&(s.model={flag:e.modelFlag,value:e.modelValue||""}),e.promptMode==="flag"&&(s.promptFlag=e.promptFlag),t&&(s.env=Object.fromEntries(e.envRows.filter(o=>!o.remove&&o.key).map(o=>[o.key,o.value]))),s}function Nr({children:e,onClose:t,label:n,error:s=""}){const o=N.useRef(null),a=N.useRef(null),u=N.useRef(t);return u.current=t,N.useEffect(()=>{const h=document.activeElement,p=o.current,f=()=>Array.from((p==null?void 0:p.querySelectorAll('button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [href], [tabindex]:not([tabindex="-1"])'))||[]).filter(y=>y.offsetParent!==null),_=requestAnimationFrame(()=>{var y;return(y=f()[0]||p)==null?void 0:y.focus({preventScroll:!0})}),b=y=>{var C;if(y.key==="Escape"){y.preventDefault(),(C=u.current)==null||C.call(u);return}if(y.key!=="Tab")return;const S=f();if(!S.length){y.preventDefault(),p==null||p.focus();return}const w=S[0],x=S[S.length-1];y.shiftKey&&document.activeElement===w?(y.preventDefault(),x.focus()):!y.shiftKey&&document.activeElement===x&&(y.preventDefault(),w.focus())};return document.addEventListener("keydown",b),()=>{cancelAnimationFrame(_),document.removeEventListener("keydown",b),h&&h.isConnected&&typeof h.focus=="function"&&h.focus({preventScroll:!0})}},[]),N.useEffect(()=>{s&&requestAnimationFrame(()=>{var h;return(h=a.current)==null?void 0:h.scrollIntoView({block:"nearest"})})},[s]),c.jsx("div",{className:"nc-fleet-modal",role:"presentation",onMouseDown:h=>{h.target===h.currentTarget&&t()},children:c.jsxs("div",{ref:o,className:"nc-fleet-modal-dialog",role:"dialog","aria-modal":"true","aria-label":n||g("settings"),tabIndex:-1,children:[e,s&&c.jsx("div",{ref:a,className:"nc-err nc-fleet-modal-error",role:"alert","aria-live":"assertive",children:s})]})})}function yd({token:e,targets:t=[],readonly:n=!1,onPower:s,onImport:o}){const[a,u]=N.useState([]),[h,p]=N.useState(0);N.useEffect(()=>{let C=!0;async function k(){const B=[{route:[],label:g("local")}].concat((t||[]).map(Y=>({route:Array.isArray(Y.route)?Y.route:[],label:Y.label||(Y.route||[]).join(" › ")}))),M=await Promise.all(B.map(async Y=>{const K={...Y,available:!1,readonly:!1,capabilities:[],provider:null,cells:[],unmanaged:[],err:""};try{const A=await zr(e,Y.route);K.available=!!A.available,K.capabilities=A.capabilities||[],K.provider=A.provider||null,K.cells=(A.cells||[]).map(ee=>({...ee,route:Y.route}));try{K.readonly=!!(await Ph(e,Y.route)).readonlyDefault}catch{}try{const ee=await M_(e,Y.route),U=new Set(K.cells.map(Z=>Z.tmuxSession).filter(Boolean));K.unmanaged=(ee.sessions||[]).filter(Z=>Z&&!U.has(Z.name))}catch{}}catch(A){K.err=String(A&&A.message||A)}return K}));C&&u(M)}k();const P=setInterval(k,6e3);return()=>{C=!1,clearInterval(P)}},[e,t,h]);const f=(C,k)=>Array.isArray(C.capabilities)&&C.capabilities.includes(k)&&!n&&!C.readonly,_=()=>p(C=>C+1),b=(C,k)=>{s&&s({...C,route:k})},y=(C,k)=>{s&&s({...C,route:k})},S=async(C,k)=>{try{await bo(e,C.cell,k)}catch{}_()},w=async(C,k)=>{if(window.confirm(g("fleet-remove-cell").replace("{id}",C.cell))){try{await L_(e,C.cell,!0,k)}catch{}_()}},x=async(C,k)=>{if(window.confirm(g("terminate-confirm").replace("{name}",C.name))){try{await Nh(e,C.name,k)}catch{}_()}};return c.jsxs("div",{className:"nc-fleet-inventory",children:[c.jsxs("div",{className:"nc-fleet-section-head",children:[c.jsx("b",{children:g("fleet-inventory")}),c.jsx("small",{children:g("fleet-inventory-help")})]}),a.map(C=>{const k=C.route.length?C.route.join("/"):"local";return c.jsxs("div",{className:"nc-fleet-pos",children:[c.jsxs("div",{className:"nc-fleet-pos-title",children:[c.jsx("span",{className:`dot ${C.available?"on":"warn"}`}),c.jsx("b",{children:C.label}),c.jsx("small",{children:C.available?`${C.cells.length} ${g("fleet-cells")} · ${C.unmanaged.length} ${g("fleet-tmux")}`:C.err||g("fleet-not-available")})]}),C.cells.map(P=>c.jsxs("div",{className:"nc-fleet-item nc-fleet-cell",children:[c.jsxs("span",{children:[c.jsx("b",{children:P.cell}),c.jsx("small",{children:`${P.engine||""}${P.key?`·${P.key}`:""}${P.active?"":` · ${g("cell-off")}`}`})]}),c.jsxs("span",{className:"nc-fleet-cell-actions",children:[P.active&&f(C,"down")&&c.jsx("button",{className:"nc-btn ghost",title:g("power-off"),onClick:()=>y(P,C.route),children:g("stop")}),!P.active&&f(C,"up")&&c.jsx("button",{className:"nc-btn ghost",title:g("power-on"),onClick:()=>b(P,C.route),children:g("start")}),f(C,"restart")&&P.active&&c.jsx("button",{className:"nc-btn ghost",title:g("restart"),onClick:()=>S(P,C.route),children:g("restart")}),f(C,"remove")&&c.jsx("button",{className:"nc-btn danger",title:g("delete"),onClick:()=>w(P,C.route),children:"×"})]})]},`${k}:${P.cell}`)),C.unmanaged.map(P=>c.jsxs("div",{className:"nc-fleet-item nc-fleet-unmanaged",children:[c.jsxs("span",{children:[c.jsx("b",{children:P.name}),c.jsx("small",{children:g("fleet-tmux")})]}),c.jsxs("span",{className:"nc-fleet-cell-actions",children:[f(C,"import")&&o&&c.jsx("button",{className:"nc-btn ghost",title:g("import-as-cell"),onClick:()=>o(P,C.route),children:g("import-as-cell")}),c.jsx("button",{className:"nc-btn danger",title:g("terminate"),onClick:()=>x(P,C.route),children:"×"})]})]},`${k}:u:${P.name}`)),C.available&&C.cells.length===0&&C.unmanaged.length===0&&c.jsx("div",{className:"nc-empty",children:g("fleet-inventory-empty")})]},k)})]})}function eN({cells:e=[],engines:t=[],busy:n,canRestore:s=!1,onRestore:o,onClose:a}){const[u,h]=N.useState("export"),[p,f]=N.useState(()=>new Set(e.map(j=>j.id))),[_,b]=N.useState(()=>new Set(t.map(j=>j.id))),[y,S]=N.useState([]),[w,x]=N.useState([]),[C,k]=N.useState(""),P=new Set(t.map(j=>j.id)),B=new Set(e.map(j=>j.id)),M=(j,R)=>j(T=>{const H=new Set(T);return H.has(R)?H.delete(R):H.add(R),H}),Y=()=>{const j=V2(e,p,t,_);if(j.ok===!1){k(g(`fleet-backup-${j.error}`));return}const R=e.filter(ie=>p.has(ie.id)).length,T=t.filter(ie=>_.has(ie.id)).length;if(j.cells.length!==R){k(g("fleet-backup-invalid-cell"));return}if(j.engines.length!==T){k(g("fleet-backup-invalid-engine"));return}if(!j.cells.length&&!j.engines.length){k(g("fleet-backup-select-one"));return}const H=new Blob([`${JSON.stringify(j,null,2)}
|
|
91
91
|
`],{type:"application/json"}),te=URL.createObjectURL(H),D=document.createElement("a");D.href=te,D.download=`nexuscrew-fleet-${new Date().toISOString().slice(0,10)}.json`,document.body.appendChild(D),D.click(),D.remove(),setTimeout(()=>URL.revokeObjectURL(te),0),k("")},K=async j=>{if(k(""),S([]),x([]),!!j){if(j.size>1024*1024){k(g("fleet-backup-too-large"));return}try{const R=Y2(await j.text());if(!R.ok){k(g(`fleet-backup-${R.error}`));return}const T=new Set(R.engines.map(H=>H.id));x(R.engines.map(H=>({engine:H,exists:P.has(H.id),selected:!P.has(H.id)}))),S(R.cells.map(H=>{const te=P.has(H.engine)||T.has(H.engine),D=B.has(H.id);return{cell:H,engine:te?H.engine:"",selected:te&&!D,exists:D}}))}catch(R){k(String(R.message||R))}}},A=(j,R)=>S(T=>T.map((H,te)=>te===j?{...H,...R}:H)),ee=(j,R)=>x(T=>T.map((H,te)=>te===j?{...H,...R}:H)),U=new Set([...P,...w.filter(j=>j.selected).map(j=>j.engine.id)]),Z=y.filter(j=>j.selected&&j.engine&&U.has(j.engine)),F=w.filter(j=>j.selected),I=[...new Map([...t.map(j=>[j.id,j.label||j.id]),...w.filter(j=>j.selected).map(j=>[j.engine.id,j.engine.label||j.engine.id])]).entries()];return c.jsxs("div",{className:"nc-set-form nc-fleet-form nc-backup-dialog",children:[c.jsx("b",{children:g("fleet-backup")}),c.jsx("small",{children:g("fleet-backup-help")}),c.jsxs("div",{className:"nc-set-tabs nc-backup-tabs",children:[c.jsx("button",{type:"button",className:`nc-set-tabbtn${u==="export"?" on":""}`,onClick:()=>{h("export"),k("")},children:g("fleet-backup-export")}),c.jsx("button",{type:"button",className:`nc-set-tabbtn${u==="import"?" on":""}`,disabled:!s,title:s?"":g("fleet-backup-restore-unavailable"),onClick:()=>{h("import"),k("")},children:g("fleet-backup-import")})]}),u==="export"?c.jsxs(c.Fragment,{children:[c.jsxs("div",{className:"nc-set-row",children:[c.jsx("button",{type:"button",className:"nc-btn ghost",onClick:()=>{f(new Set(e.map(j=>j.id))),b(new Set(t.map(j=>j.id)))},children:g("select-all")}),c.jsx("button",{type:"button",className:"nc-btn ghost",onClick:()=>{f(new Set),b(new Set)},children:g("select-none")})]}),c.jsxs("div",{className:"nc-backup-list",children:[c.jsx("b",{children:g("fleet-engines")}),t.map(j=>{var R;return c.jsxs("label",{className:"nc-check nc-backup-row",children:[c.jsx("input",{type:"checkbox",checked:_.has(j.id),onChange:()=>M(b,j.id)}),c.jsxs("span",{children:[c.jsx("b",{children:j.label||j.id}),c.jsxs("small",{children:[j.id,(R=j.envKeys)!=null&&R.length?` · ${j.envKeys.length} ${g("fleet-backup-env-names")}`:""]})]})]},j.id)}),c.jsx("b",{children:g("fleet-cells")}),e.map(j=>c.jsxs("label",{className:"nc-check nc-backup-row",children:[c.jsx("input",{type:"checkbox",checked:p.has(j.id),onChange:()=>M(f,j.id)}),c.jsxs("span",{children:[c.jsx("b",{children:j.id}),c.jsxs("small",{children:[j.engine," · ",g("fleet-system-prompt")," ",(j.prompt||"").length," ",g("characters")]})]})]},j.id)),!e.length&&!t.length&&c.jsx("div",{className:"nc-empty",children:g("fleet-backup-empty")})]}),c.jsxs("div",{className:"nc-sheet-actions",children:[c.jsx("button",{type:"button",className:"nc-btn ghost",onClick:a,children:g("cancel")}),c.jsx("button",{type:"button",className:"nc-btn primary",disabled:!p.size&&!_.size,onClick:Y,children:g("fleet-backup-download")})]})]}):c.jsxs(c.Fragment,{children:[c.jsx("input",{type:"file",accept:"application/json,.json",disabled:n,onChange:j=>K(j.target.files&&j.target.files[0])}),c.jsx("small",{children:g("fleet-backup-import-help")}),!!(y.length||w.length)&&c.jsxs("div",{className:"nc-set-row",children:[c.jsx("button",{type:"button",className:"nc-btn ghost",onClick:()=>{x(j=>j.map(R=>({...R,selected:!0}))),S(j=>j.map(R=>({...R,selected:!!R.engine})))},children:g("select-all")}),c.jsx("button",{type:"button",className:"nc-btn ghost",onClick:()=>{x(j=>j.map(R=>({...R,selected:!1}))),S(j=>j.map(R=>({...R,selected:!1})))},children:g("select-none")})]}),c.jsxs("div",{className:"nc-backup-list",children:[!!w.length&&c.jsx("b",{children:g("fleet-engines")}),w.map((j,R)=>{var T;return c.jsx("div",{className:"nc-backup-import-row",children:c.jsxs("label",{className:"nc-check",children:[c.jsx("input",{type:"checkbox",checked:j.selected,onChange:H=>ee(R,{selected:H.target.checked})}),c.jsxs("span",{children:[c.jsx("b",{children:j.engine.label||j.engine.id}),c.jsxs("small",{children:[j.engine.id," · ",j.exists?g("fleet-backup-overwrite"):g("fleet-backup-new"),(T=j.engine.envKeys)!=null&&T.length?` · ${g("fleet-backup-env-values-required")}`:""]})]})]})},j.engine.id)}),!!y.length&&c.jsx("b",{children:g("fleet-cells")}),y.map((j,R)=>c.jsxs("div",{className:"nc-backup-import-row",children:[c.jsxs("label",{className:"nc-check",children:[c.jsx("input",{type:"checkbox",checked:j.selected,disabled:!j.engine||!U.has(j.engine),onChange:T=>A(R,{selected:T.target.checked})}),c.jsxs("span",{children:[c.jsx("b",{children:j.cell.id}),c.jsxs("small",{children:[j.exists?g("fleet-backup-overwrite"):g("fleet-backup-new")," · ",g("fleet-system-prompt")," ",j.cell.systemPrompt.length," ",g("characters")]})]})]}),c.jsxs("select",{value:j.engine,onChange:T=>A(R,{engine:T.target.value,selected:!!T.target.value}),children:[c.jsx("option",{value:"",children:g("fleet-backup-engine-missing")}),I.map(([T,H])=>c.jsx("option",{value:T,children:H},T))]})]},j.cell.id))]}),c.jsxs("div",{className:"nc-sheet-actions",children:[c.jsx("button",{type:"button",className:"nc-btn ghost",onClick:a,children:g("cancel")}),c.jsx("button",{type:"button",className:"nc-btn primary",disabled:n||!Z.length&&!F.length,onClick:()=>o({engineRows:w,cellRows:y}),children:g("fleet-backup-restore")})]})]}),C&&c.jsx("div",{className:"nc-err",children:C})]})}function tN({state:e,setState:t,busy:n,onSave:s,catalog:o}){var C;const a=e.form,u=k=>t({...e,form:{...a,...k}}),h=a.envRows||[],p=[...new Map(o.map(k=>[k.client,k.clientLabel||k.client])).entries()],f=o.filter(k=>k.client===a.client),_=To(o,a),b=typeof(_==null?void 0:_.credentialEnv)=="string"?_.credentialEnv:"",y=Array.isArray(_==null?void 0:_.credentialUsedBy)?_.credentialUsedBy:[],S=(_==null?void 0:_.credentialSource)||"missing",w=!!b&&e.mode==="new"&&(_==null?void 0:_.authConfigured)!==!0&&!a.credentialValue&&!a.allowMissingCredential,x=k=>{k&&u({client:k.client,provider:k.provider,credentialProfile:k.credentialProfile||"",managedModel:k.model||"",protocol:k.protocol||"",permissionPolicy:k.permissionPolicyDefault||"standard",rc:!!k.rc,displayName:k.custom?g("fleet-custom-provider-default"):"",baseUrl:k.custom?"":k.endpoint||"",envKey:k.defaultEnvKey||"",providerId:"nexuscrew-custom",credentialValue:"",credentialReveal:!1,allowMissingCredential:!1,...e.mode==="new"?{id:k.id,label:""}:{}})};return c.jsxs("div",{className:"nc-set-form nc-fleet-form",children:[c.jsx("b",{children:e.mode==="new"?g("fleet-new-engine"):`${g("edit")} ${a.id}`}),c.jsx("input",{value:a.id,disabled:e.mode!=="new",placeholder:"id",onChange:k=>u({id:k.target.value})}),c.jsx("input",{value:a.label,placeholder:g("label"),onChange:k=>u({label:k.target.value})}),c.jsxs("select",{value:a.kind,disabled:e.mode!=="new",onChange:k=>u({kind:k.target.value}),children:[c.jsx("option",{value:"managed",children:g("fleet-managed")}),c.jsx("option",{value:"custom",children:g("fleet-custom")})]}),a.kind==="managed"?c.jsxs(c.Fragment,{children:[c.jsxs("div",{className:"nc-fleet-pair",children:[c.jsx("select",{value:a.client,disabled:e.mode!=="new",onChange:k=>x(o.find(P=>P.client===k.target.value&&P.default)||o.find(P=>P.client===k.target.value)),children:p.map(([k,P])=>c.jsx("option",{value:k,children:P},k))}),c.jsx("select",{value:((C=To(o,a))==null?void 0:C.id)||"",disabled:e.mode!=="new",onChange:k=>x(o.find(P=>P.id===k.target.value)),children:f.map(k=>c.jsx("option",{value:k.id,children:k.label},k.id))})]}),a.client!=="shell"&&c.jsxs(c.Fragment,{children:[c.jsx("input",{value:a.managedModel,list:"nc-managed-models",placeholder:g(_!=null&&_.requiresModel?"fleet-model-required":"fleet-model-default"),onChange:k=>u({managedModel:k.target.value})}),c.jsx("datalist",{id:"nc-managed-models",children:[...(_==null?void 0:_.models)||[],...a.modelOptions||[]].filter((k,P,B)=>k&&B.indexOf(k)===P).map(k=>c.jsx("option",{value:k},k))})]}),_!=null&&_.supportsUnsafe?c.jsxs("select",{value:a.permissionPolicy,onChange:k=>u({permissionPolicy:k.target.value}),children:[c.jsx("option",{value:"standard",children:g("fleet-standard-permissions")}),c.jsx("option",{value:"unsafe",children:g("fleet-unsafe-permissions")})]}):c.jsx("small",{children:g("fleet-standard-permissions")}),(_==null?void 0:_.supportsUnsafe)&&a.permissionPolicy==="unsafe"&&c.jsx("small",{className:"nc-err",children:g("fleet-unsafe-warning")}),(_==null?void 0:_.credentialEnv)===!0&&c.jsxs(c.Fragment,{children:[c.jsx("input",{value:a.envKey,placeholder:g("fleet-api-key-env"),onChange:k=>u({envKey:k.target.value})}),c.jsx("small",{children:g("fleet-custom-secret-help")})]}),b&&c.jsxs("section",{className:"nc-fleet-key","aria-label":g("fleet-key-section"),children:[c.jsxs("div",{className:"nc-fleet-key-head",children:[c.jsx("b",{children:g("fleet-key-section")}),c.jsx("span",{children:g(`fleet-credential-source-${S}`)})]}),c.jsxs("label",{className:"nc-field",children:[g("fleet-key-variable"),c.jsx("input",{value:b,readOnly:!0,"aria-label":g("fleet-key-variable")})]}),c.jsx("small",{children:y.length?g("fleet-key-used-by").replace("{engines}",y.join(", ")):g("fleet-key-used-by-none")}),y.length>0&&c.jsx("small",{children:g("fleet-key-shared-impact").replace("{key}",b).replace("{engines}",y.join(", "))}),c.jsxs("div",{className:"nc-fleet-key-input",children:[c.jsx("input",{type:a.credentialReveal?"text":"password",value:a.credentialValue||"","aria-label":g("fleet-key-value").replace("{key}",b),autoComplete:"new-password",spellCheck:!1,autoCapitalize:"none",autoCorrect:"off",placeholder:_!=null&&_.authConfigured||e.mode==="edit"?g("fleet-key-blank-keeps"):g("fleet-key-enter"),onChange:k=>u({credentialValue:k.target.value,allowMissingCredential:k.target.value?!1:a.allowMissingCredential})}),c.jsx("button",{type:"button",className:"nc-btn ghost","aria-label":g(a.credentialReveal?"fleet-key-hide":"fleet-key-reveal"),onClick:()=>u({credentialReveal:!a.credentialReveal}),children:g(a.credentialReveal?"fleet-key-hide":"fleet-key-reveal")})]}),c.jsx("small",{children:g("fleet-key-local-help")}),e.mode==="new"&&(_==null?void 0:_.authConfigured)!==!0&&!a.credentialValue&&c.jsxs("label",{className:"nc-check nc-fleet-key-missing",children:[c.jsx("input",{type:"checkbox",checked:!!a.allowMissingCredential,onChange:k=>u({allowMissingCredential:k.target.checked})}),g("fleet-key-create-missing")]}),(_==null?void 0:_.notice)&&c.jsx("small",{className:"nc-fleet-provider-notice",children:g(`fleet-provider-notice-${_.notice}`)})]}),a.provider==="custom"&&c.jsxs(c.Fragment,{children:[c.jsx("input",{value:a.displayName,placeholder:g("fleet-provider-display"),onChange:k=>u({displayName:k.target.value})}),c.jsx("input",{value:a.baseUrl,placeholder:"https://api.example.com/v1",onChange:k=>u({baseUrl:k.target.value})}),((_==null?void 0:_.protocols)||[]).length>1&&c.jsx("select",{value:a.protocol,onChange:k=>u({protocol:k.target.value}),children:_.protocols.map(k=>c.jsx("option",{value:k,children:k},k))}),c.jsxs("div",{className:"nc-fleet-pair",children:[c.jsx("input",{value:a.envKey,placeholder:g("fleet-api-key-env"),onChange:k=>u({envKey:k.target.value})}),c.jsx("input",{value:a.providerId,placeholder:g("fleet-provider-id"),onChange:k=>u({providerId:k.target.value})})]}),c.jsxs("small",{children:[a.protocol," · ",g("fleet-custom-secret-help")]})]}),c.jsx("small",{children:g(a.client==="shell"?"fleet-shell-engine-help":"fleet-managed-help")})]}):c.jsxs(c.Fragment,{children:[c.jsx("input",{value:a.command,placeholder:g("command-path"),onChange:k=>u({command:k.target.value})}),c.jsx("textarea",{value:a.argsText,placeholder:g("args-lines"),onChange:k=>u({argsText:k.target.value})}),c.jsxs("label",{className:"nc-check",children:[c.jsx("input",{type:"checkbox",checked:a.rc,onChange:k=>u({rc:k.target.checked})})," remote control"]}),c.jsxs("select",{value:a.promptMode,onChange:k=>u({promptMode:k.target.value}),children:[c.jsx("option",{value:"send-keys",children:"send-keys"}),c.jsx("option",{value:"flag",children:"flag"})]}),a.promptMode==="flag"&&c.jsx("input",{value:a.promptFlag,placeholder:"prompt flag",onChange:k=>u({promptFlag:k.target.value})}),c.jsxs("div",{className:"nc-fleet-pair",children:[c.jsx("input",{value:a.modelFlag,placeholder:"model flag",onChange:k=>u({modelFlag:k.target.value})}),c.jsx("input",{value:a.modelValue,placeholder:"model default",onChange:k=>u({modelValue:k.target.value})})]}),c.jsx("small",{children:g("env-write-only")}),h.map((k,P)=>c.jsxs("div",{className:"nc-fleet-env",children:[c.jsx("input",{value:k.key,disabled:k.configured,placeholder:"ENV_KEY",onChange:B=>{const M=h.slice();M[P]={...k,key:B.target.value},u({envRows:M})}}),c.jsx("input",{type:"password",value:k.value,placeholder:k.configured?"•••••• (unchanged)":"value",onChange:B=>{const M=h.slice();M[P]={...k,value:B.target.value},u({envRows:M})}}),c.jsx("button",{className:"nc-btn danger",onClick:()=>u({envRows:h.filter((B,M)=>M!==P)}),children:"×"})]},`${k.key}-${P}`)),c.jsx("button",{className:"nc-btn ghost",onClick:()=>u({envRows:[...h,{key:"",value:"",configured:!1}]}),children:"+ env"})]}),c.jsxs("div",{className:"nc-sheet-actions",children:[c.jsx("button",{className:"nc-btn ghost",onClick:()=>t(null),children:g("cancel")}),c.jsx("button",{className:"nc-btn primary",disabled:n||!a.id||w||a.kind==="custom"&&!a.command||a.kind==="managed"&&(_==null?void 0:_.requiresModel)&&!a.managedModel||a.kind==="managed"&&(_==null?void 0:_.credentialEnv)===!0&&!a.envKey||a.kind==="managed"&&a.provider==="custom"&&(!a.displayName||!a.baseUrl||!a.envKey||!a.providerId),onClick:s,children:g("save")})]})]})}function nN({token:e,route:t,targets:n=[],location:s,setLocation:o,state:a,setState:u,engines:h,busy:p,onSave:f}){var K;const[_,b]=N.useState(null),[y,S]=N.useState(""),w=a.form,x=A=>u({...a,form:{...w,...A}}),C=h.find(A=>A.id===w.engine),k=((K=C==null?void 0:C.managed)==null?void 0:K.client)==="shell",P=A=>{var Z,F,I,j;const ee=h.find(R=>R.id===A),U={...w.commands||{}};((Z=C==null?void 0:C.managed)==null?void 0:Z.client)==="shell"&&(w.command?U[w.engine]=w.command:delete U[w.engine]),x({engine:A,model:((F=w.models)==null?void 0:F[A])||((I=ee==null?void 0:ee.managed)==null?void 0:I.model)||((j=ee==null?void 0:ee.model)==null?void 0:j.value)||"",commands:U,command:U[A]||""})},B=A=>{const ee={...w.commands||{}};A?ee[w.engine]=A:delete ee[w.engine],x({command:A,commands:ee})},M=k&&/[|&;<>()`$*?{}\[\]~]/.test(w.command||""),Y=async A=>{try{const ee=await Rh(e,A,t);b(ee),x({cwd:ee.path}),S("")}catch(ee){S(String(ee.message||ee))}};return c.jsxs("div",{className:"nc-set-form nc-fleet-form",children:[c.jsx("b",{children:a.mode==="new"?g("fleet-new-cell"):`${g("edit")} ${w.id}`}),a.mode==="new"&&c.jsxs("label",{className:"nc-field",children:[g("location"),c.jsx("span",{className:"nc-req",children:" *"}),c.jsxs("select",{value:s,onChange:A=>{o(A.target.value),x({engine:""})},children:[c.jsx("option",{value:"",children:g("local")}),n.map(A=>c.jsxs("option",{value:A.route.join("/"),disabled:A.status&&A.status!=="up",children:[A.label,A.status&&A.status!=="up"?` · ${g("node-offline")}`:""]},A.route.join("/")))]})]}),c.jsx("input",{value:w.id,disabled:a.mode!=="new",placeholder:"id",onChange:A=>x({id:A.target.value})}),c.jsxs("div",{className:"nc-fleet-pair",children:[c.jsx("input",{value:w.cwd,placeholder:g("cwd"),onChange:A=>x({cwd:A.target.value})}),c.jsx("button",{className:"nc-btn ghost",onClick:()=>_?b(null):Y(w.cwd),children:g("browse")})]}),_&&c.jsxs("div",{className:"nc-fs",children:[c.jsx("div",{className:"nc-fs-path",children:_.path}),c.jsxs("div",{className:"nc-fs-list",children:[_.parent&&c.jsxs("button",{className:"nc-fs-item nc-fs-nav",onClick:()=>Y(_.parent),children:["↑ ",g("fs-parent")]}),(_.dirs||[]).map(A=>c.jsxs("button",{className:"nc-fs-item",onClick:()=>Y(`${_.path.replace(/\/$/,"")}/${A}`),children:["📁 ",A]},A))]})]}),y&&c.jsx("div",{className:"nc-err",children:y}),c.jsx("select",{value:w.engine,onChange:A=>P(A.target.value),children:h.map(A=>c.jsx("option",{value:A.id,children:A.label},A.id))}),c.jsxs("label",{className:"nc-check",children:[c.jsx("input",{type:"checkbox",checked:!!w.boot,onChange:A=>x({boot:A.target.checked})})," boot"]}),k?c.jsxs(c.Fragment,{children:[c.jsx("input",{value:w.command||"",maxLength:4096,placeholder:g("fleet-shell-command-placeholder"),onChange:A=>B(A.target.value)}),c.jsx("small",{children:w.command?g("fleet-shell-command-help"):g("fleet-shell-interactive")}),M&&c.jsx("small",{className:"nc-note",children:g("fleet-shell-command-metachar")})]}):c.jsxs(c.Fragment,{children:[c.jsx("input",{value:w.model||"",list:"nc-cell-models",placeholder:g("fleet-model-override"),onChange:A=>x({model:A.target.value})}),c.jsx("datalist",{id:"nc-cell-models",children:((C==null?void 0:C.availableModels)||[]).map(A=>c.jsx("option",{value:A},A))}),c.jsx("textarea",{value:w.prompt||"",placeholder:"prompt",onChange:A=>x({prompt:A.target.value})})]}),c.jsxs("div",{className:"nc-sheet-actions",children:[c.jsx("button",{className:"nc-btn ghost",onClick:()=>u(null),children:g("cancel")}),c.jsx("button",{className:"nc-btn primary",disabled:p||!w.id||!w.cwd||!w.engine,onClick:f,children:g("save")})]})]})}function g_({token:e,route:t=[],state:n,setState:s,busy:o,onSave:a}){const[u,h]=N.useState(null),[p,f]=N.useState([]),[_,b]=N.useState(""),y=Array.isArray(t)?t.join("/"):"";N.useEffect(()=>{let k=!0;return Eh(e,y?y.split("/"):[]).then(P=>{k&&(f(P.engines||[]),b(""))}).catch(P=>{k&&(f([]),b(String(P.message||P)))}),()=>{k=!1}},[e,y]);const S=n.form,w=k=>s({...n,form:{...S,...k}}),x=async k=>{try{const P=await Rh(e,k,t);h(P),w({cwd:P.path})}catch{}},C=!S.id&&S.tmuxSession?S.tmuxSession.replace(/[^A-Za-z0-9._-]+/g,"-").replace(/^-+|-+$/g,"").slice(0,32):S.id;return c.jsxs("div",{className:"nc-set-form nc-fleet-form",children:[c.jsxs("b",{children:[g("import-as-cell")," · ",S.tmuxSession]}),c.jsx("small",{children:g("import-help")}),c.jsx("input",{value:S.tmuxSession,disabled:!0,placeholder:"tmux session",readOnly:!0}),c.jsx("input",{value:S.id,placeholder:g("name"),onChange:k=>w({id:k.target.value})}),c.jsxs("div",{className:"nc-fleet-pair",children:[c.jsx("input",{value:S.cwd,placeholder:g("cwd"),onChange:k=>w({cwd:k.target.value})}),c.jsx("button",{className:"nc-btn ghost",type:"button",onClick:()=>u?h(null):x(S.cwd),children:g("browse")})]}),u&&c.jsxs("div",{className:"nc-fs",children:[c.jsx("div",{className:"nc-fs-path",children:u.path}),c.jsxs("div",{className:"nc-fs-list",children:[u.parent&&c.jsxs("button",{className:"nc-fs-item nc-fs-nav",onClick:()=>x(u.parent),children:["↑ ",g("fs-parent")]}),(u.dirs||[]).map(k=>c.jsxs("button",{className:"nc-fs-item",onClick:()=>x(`${u.path.replace(/\/$/,"")}/${k}`),children:["📁 ",k]},k))]})]}),c.jsxs("select",{value:S.engine,onChange:k=>w({engine:k.target.value}),children:[c.jsx("option",{value:"",children:g("import-engine-required")}),p.map(k=>c.jsx("option",{value:k.id,children:k.label},k.id))]}),c.jsxs("label",{className:"nc-check",children:[c.jsx("input",{type:"checkbox",checked:!!S.boot,onChange:k=>w({boot:k.target.checked})})," boot"]}),(n.err||_)&&c.jsx("div",{className:"nc-err",children:n.err||_}),c.jsxs("div",{className:"nc-sheet-actions",children:[c.jsx("button",{className:"nc-btn ghost",onClick:()=>s(null),children:g("cancel")}),c.jsx("button",{className:"nc-btn primary",disabled:o||!S.tmuxSession||!S.engine||!p.length,onClick:a,children:g(C?"import-as-cell":"save")})]})]})}function al(e){const t=Lr(e);return t===null?`~/${e}`:t?`~/${t}`:"~"}function iN(e){if(!e||typeof e.path!="string"||typeof e.home!="string")return"";const{path:t,home:n}=e;return!n||t===n||!t.startsWith(n+"/")?"":t.slice(n.length+1).replace(/\/+$/,"")}function rN({token:e,route:t,cell:n,busy:s=!1,onSaved:o,onClose:a}){const[u,h]=N.useState(""),[p,f]=N.useState(null),[_,b]=N.useState(!1),[y,S]=N.useState(""),w=typeof(n==null?void 0:n.cwdSuggestion)=="string"&&Lr(n.cwdSuggestion)!==null?Lr(n.cwdSuggestion):null,[x,C]=N.useState(w),k=n==null?void 0:n.id,P=s||_,B=async U=>{const Z=Lr(U);if(Z===null){f({rel:"",dirs:[],loading:!1,err:g("fleet-cwd-repair-invalid")});return}f({rel:Z,dirs:[],loading:!0,err:""});try{const F=await Rh(e,Z,t),I=iN(F);f({rel:I,dirs:Array.isArray(F.dirs)?F.dirs:[],loading:!1,err:""})}catch(F){f({rel:Z,dirs:[],loading:!1,err:String(F&&F.message||F)})}},M=U=>{if(!p)return;const Z=p.rel?`${p.rel}/${U}`:U;B(Z)},Y=()=>{p!=null&&p.rel&&B(p.rel.split("/").slice(0,-1).join("/"))},K=()=>{p&&(h(p.rel||""),f(null),S(""),C(null))},A=()=>{x!==null&&(h(x),C(null),S(""))},ee=async()=>{if(P)return;const U=Lr(u);if(U===null){S(g("fleet-cwd-repair-invalid"));return}const Z=al(U);let F=!0;try{F=window.confirm(g("fleet-cwd-repair-confirm").replace("{id}",String(k||"")).replace("{path}",Z))}catch{F=!1}if(F){b(!0),S(""),C(null);try{const I=await j_(e,k,{cwdRel:U},t);o==null||o(I)}catch(I){const j=I&&I.data||{};if(j.code==="unportable-cwd"){S(g("fleet-cwd-repair-unportable"));const R=Array.isArray(j.cells)?j.cells.find(H=>H&&H.id===k):null,T=R&&typeof R.suggestion=="string"?R.suggestion:null;T!==null&&Lr(T)!==null&&C(T)}else S(String(I&&I.message||I))}finally{b(!1)}}};return c.jsxs("div",{className:"nc-set-form nc-fleet-form nc-cwd-repair",children:[c.jsx("b",{children:g("fleet-cwd-repair-title").replace("{id}",String(k||""))}),c.jsx("small",{className:"nc-set-info",children:g("fleet-cwd-repair-help")}),c.jsx("small",{className:"nc-cwd-no-source",children:g("fleet-cwd-repair-no-source-path")}),c.jsxs("label",{className:"nc-field",children:[g("cwd"),c.jsxs("div",{className:"nc-cwd-rel-row",children:[c.jsx("span",{className:"nc-cwd-rel-prefix",children:"~/"}),c.jsx("input",{value:u,placeholder:g("fleet-cwd-repair-placeholder"),autoComplete:"off",spellCheck:"false",autoCapitalize:"none",onChange:U=>h(U.target.value)}),c.jsx("button",{type:"button",className:"nc-btn ghost",disabled:P,onClick:()=>p?f(null):B(""),children:g(p?"close":"fleet-cwd-repair-browse")})]})]}),c.jsx("div",{className:"nc-cwd-preview",children:g("fleet-cwd-repair-preview").replace("{path}",al(u))}),p&&c.jsxs("div",{className:"nc-fs",children:[c.jsx("div",{className:"nc-fs-path",children:al(p.rel)}),c.jsxs("div",{className:"nc-fs-list",children:[p.rel&&c.jsxs("button",{type:"button",className:"nc-fs-item nc-fs-nav",onClick:Y,children:["↑ ",g("fs-parent")]}),p.loading&&c.jsx("div",{className:"nc-fs-empty",children:"…"}),!p.loading&&p.dirs.length===0&&c.jsx("div",{className:"nc-fs-empty",children:g("fleet-cwd-repair-fs-empty")}),!p.loading&&p.dirs.map(U=>c.jsxs("button",{type:"button",className:"nc-fs-item",onClick:()=>M(U),children:["📁 ",U]},U))]}),p.err&&c.jsx("div",{className:"nc-err",children:p.err}),c.jsx("div",{className:"nc-sheet-actions",children:c.jsx("button",{type:"button",className:"nc-btn primary",disabled:P||p.loading||!!p.err,onClick:K,children:g("fleet-cwd-repair-use-current")})})]}),y&&c.jsx("div",{className:"nc-err",role:"alert",children:y}),x!==null&&c.jsxs("div",{className:"nc-cwd-suggestion",role:"status",children:[c.jsx("span",{children:g("fleet-cwd-repair-suggestion")}),c.jsx("button",{type:"button",className:"nc-btn ghost",onClick:A,children:g("fleet-cwd-repair-use-suggestion").replace("{path}",al(x))})]}),c.jsxs("div",{className:"nc-sheet-actions",children:[c.jsx("button",{type:"button",className:"nc-btn ghost",disabled:_,onClick:a,children:g("cancel")}),c.jsx("button",{type:"button",className:"nc-btn primary",disabled:P,onClick:ee,children:_?"…":g("save")})]})]})}function sN({token:e,readonly:t,targets:n=[],startNewCell:s=!1,initialLocation:o=""}){const[a,u]=N.useState({engines:[],cells:[],managedCatalog:[]}),[h,p]=N.useState({available:!1,capabilities:[]}),[f,_]=N.useState(!1),[b,y]=N.useState(null),[S,w]=N.useState(null),[x,C]=N.useState(!1),[k,P]=N.useState(""),[B,M]=N.useState(""),[Y,K]=N.useState(o),[A,ee]=N.useState(!1),[U,Z]=N.useState(null),[F,I]=N.useState(null),[j,R]=N.useState(null),[T,H]=N.useState(!1),[te,D]=N.useState([]),[ie,O]=N.useState(null),[L,$]=N.useState("manage"),X=N.useRef(!1),ae=Y?Y.split("/"):[],ue=N.useCallback(async()=>{try{const le=await zr(e,ae);p(le);try{const be=await Ph(e,ae);ee(!!be.readonlyDefault)}catch{ee(!1)}if(le.provider==="builtin"&&(le.capabilities||[]).includes("definitions")){const be=await Eh(e,ae),Be=new Map((le.engines||[]).map($e=>[$e.id,$e]));if(be.engines=(be.engines||[]).map($e=>{var he;return{...$e,availableModels:((he=Be.get($e.id))==null?void 0:he.models)||[]}}),u(be),(le.capabilities||[]).includes("credentials"))try{D((await Jb(e,ae)).credentials||[])}catch{D([])}else D([])}P("")}catch(le){P(String(le.message||le))}finally{_(!0)}},[e,Y]);N.useEffect(()=>{ue();const le=setInterval(ue,5e3);return()=>clearInterval(le)},[ue]);const ge=new Set((h.cells||[]).filter(le=>le.active).map(le=>le.cell)),Q=h.provider==="builtin"&&(h.capabilities||[]).includes("edit"),q=(h.capabilities||[]).includes("restore");N.useEffect(()=>{!s||X.current||!Q||!a.engines.length||(X.current=!0,w({mode:"new",form:m_(a.engines[0].id)}))},[s,Q,a.engines]);const fe=async le=>{C(!0),P(""),M("");try{await le(),await ue()}catch(be){P(String(be.message||be))}C(!1)},Ie=()=>fe(async()=>{var Ne;const le=b.mode==="new",be=b.form,Be=a.managedCatalog||[],$e=be.kind==="managed"?To(Be,be):null,he=typeof($e==null?void 0:$e.credentialEnv)=="string"?$e.credentialEnv:"",V=he&&be.credentialValue||"",ne=Z2(be,le,Be);!le&&b.form.kind==="custom"&&!b.form.modelFlag&&(ne.model=null),!le&&b.form.kind==="custom"&&b.form.promptMode!=="flag"&&(ne.promptFlag=null);let z;if(le)z=await Zb(e,ne,ae);else{const we=b.original,Re=new Set(b.form.envRows.filter(Me=>!Me.remove).map(Me=>Me.key)),Je=(we.envKeys||[]).filter(Me=>!Re.has(Me)),Tt=Object.fromEntries(b.form.envRows.filter(Me=>!Me.remove&&Me.key&&(!Me.configured||Me.value!=="")).map(Me=>[Me.key,Me.value]));z=await e0(e,we.id,ne,b.form.kind==="custom"?{set:Tt,remove:Je}:void 0,ae)}let se=null;if(he&&V)try{se=await Qm(e,he,V,ae),D(se.credentials||[])}catch{throw await ue(),le&&y({mode:"edit",original:{...ne,id:be.id},form:{...be,credentialReveal:!1}}),new Error(g(le?"fleet-key-partial-create":"fleet-key-partial-edit"))}await ue(),y(null),M(g("fleet-saved"));const me=((Ne=((se==null?void 0:se.credentials)||[]).find(we=>we.envKey===he))==null?void 0:Ne.activeCells)||[],ke=[...new Set([...(z==null?void 0:z.activeCells)||[],...me])];if(ke.length&&window.confirm(g("fleet-restart-confirm").replace("{cells}",ke.join(", "))))for(const we of ke)await bo(e,we,ae)}),et=()=>fe(async()=>{var z,se,me,ke,Ne,we;const le=S.mode==="new",be=S.form,Be={...le?{id:be.id}:{},cwd:be.cwd,engine:be.engine,boot:!!be.boot},$e={...be.commands||{}},he=a.engines.find(Re=>Re.id===be.engine);((z=he==null?void 0:he.managed)==null?void 0:z.client)==="shell"&&typeof be.command=="string"&&be.command.length?$e[be.engine]=be.command:((se=he==null?void 0:he.managed)==null?void 0:se.client)==="shell"&&delete $e[be.engine],(Object.keys($e).length||!le)&&(Be.commands=$e),le?(((me=he==null?void 0:he.managed)==null?void 0:me.client)!=="shell"&&be.model&&(Be.model=be.model),((ke=he==null?void 0:he.managed)==null?void 0:ke.client)!=="shell"&&be.prompt&&(Be.prompt=be.prompt)):(Be.model=((Ne=he==null?void 0:he.managed)==null?void 0:Ne.client)==="shell"?null:be.model||null,((we=he==null?void 0:he.managed)==null?void 0:we.client)!=="shell"&&(Be.prompt=be.prompt||null));const V=le?await n0(e,Be,ae):await j_(e,S.original.id,Be,ae),ne=le?be.id:S.original.id;w(null),M(g("fleet-saved")),!le&&(V!=null&&V.active)&&window.confirm(g("fleet-restart-confirm").replace("{cells}",ne))&&await bo(e,ne,ae)}),ze=t||A,Fe=le=>te.find(be=>{var Be;return(Be=be.engines)==null?void 0:Be.includes(le.id)})||null,Ct=()=>fe(async()=>{var Be;const le=await Qm(e,ie.envKey,ie.value,ae);D(le.credentials||[]),O(null),M(g("fleet-credential-saved"));const be=((Be=(le.credentials||[]).find($e=>$e.envKey===ie.envKey))==null?void 0:Be.activeCells)||[];if(be.length&&window.confirm(g("fleet-restart-confirm").replace("{cells}",be.join(", "))))for(const $e of be)await bo(e,$e,ae)}),Ge=le=>fe(async()=>{if(!window.confirm(g("fleet-credential-remove-confirm").replace("{key}",le.envKey)))return;const be=await Qb(e,le.envKey,ae);D(be.credentials||[]),M(g("fleet-credential-removed"))}),rt=le=>Z({...le,route:Array.isArray(le==null?void 0:le.route)?le.route:ae}),ut=async le=>{if(!U)return;const be=U.cell||U.id,Be=Array.isArray(U.route)?U.route:ae;le.action==="up"?await Ch(e,{cell:be,boot:!!le.boot,...le.engine?{engine:le.engine}:{},...le.model!==void 0?{model:le.model}:{},...le.permissionPolicy?{permissionPolicy:le.permissionPolicy}:{}},Be):await vl(e,{cell:be,boot:!!le.boot},Be)},ct=(le,be)=>{P(""),I({mode:"new",route:Array.isArray(be)?be:ae,form:{tmuxSession:le.name,id:"",engine:"",cwd:"",boot:!1},err:""})},vt=()=>fe(async()=>{const le=F.form;if(!le.engine){I({...F,err:g("import-engine-required")});return}await i0(e,{tmuxSession:le.tmuxSession,id:le.id||void 0,engine:le.engine,cwd:le.cwd||void 0,boot:!!le.boot},le.route||ae),I(null),M(g("fleet-saved"))}),it=({engineRows:le=[],cellRows:be=[]})=>fe(async()=>{const Be=le.filter(Ne=>Ne.selected),$e=Be.map(Ne=>Aw(Ne.engine));if($e.some(Ne=>!Ne))throw new Error(g("fleet-backup-invalid-engine"));const he=Be.filter(Ne=>Ne.exists).map(Ne=>Ne.engine.id);if(he.length&&!window.confirm(g("fleet-backup-confirm-engine-overwrite").replace("{engines}",he.join(", "))))return;const V=[...new Set([...a.engines.map(Ne=>Ne.id),...$e.map(Ne=>Ne.id)])],ne=[];for(const Ne of be.filter(we=>we.selected)){const we=G2(Ne.cell,Ne.engine,V);if(!we)throw new Error(`${Ne.cell.id}: ${g("fleet-backup-engine-missing")}`);ne.push(we)}const z=be.filter(Ne=>Ne.selected&&Ne.exists).map(Ne=>Ne.cell.id);if(z.length&&!window.confirm(g("fleet-backup-confirm-overwrite").replace("{cells}",z.join(", "))))return;const se=$e.length?await s0(e,$e,he.length>0,ae):{needsRestart:[]},me=ne.length?await r0(e,ne,ae):{needsRestart:[]},ke=[...new Set([...se.needsRestart||[],...me.needsRestart||[]])];H(!1),M(`${g("fleet-backup-restored").replace("{n}",String(ne.length))}${$e.length?` · ${$e.length} ${g("fleet-engines").toLowerCase()}`:""}${ke.length?` · ${g("fleet-backup-needs-restart").replace("{cells}",ke.join(", "))}`:""}`)}),lt=c.jsxs("label",{className:"nc-field",children:[g("location"),c.jsxs("select",{value:Y,onChange:le=>{K(le.target.value),y(null),w(null),P(""),M(""),ee(!1),_(!1),p({available:!1,capabilities:[]}),u({engines:[],cells:[],managedCatalog:[]}),D([]),O(null)},children:[c.jsx("option",{value:"",children:g("local")}),n.map(le=>c.jsxs("option",{value:le.route.join("/"),disabled:le.status&&le.status!=="up",children:[le.label,le.status&&le.status!=="up"?` · ${g("node-offline")}`:""]},le.route.join("/")))]})]}),mt=c.jsxs("div",{className:"nc-fleet-view-tabs",role:"tablist","aria-label":g("tab-fleet"),children:[c.jsx("button",{type:"button",role:"tab","aria-selected":L==="manage",className:`nc-set-tabbtn${L==="manage"?" on":""}`,onClick:()=>$("manage"),children:g("fleet-manage-location")}),c.jsx("button",{type:"button",role:"tab","aria-selected":L==="overview",className:`nc-set-tabbtn${L==="overview"?" on":""}`,onClick:()=>$("overview"),children:g("fleet-network-overview")})]});return f?Q?c.jsxs("div",{className:"nc-set-tab nc-fleet-editor",children:[mt,L==="overview"?c.jsxs(c.Fragment,{children:[c.jsx("div",{className:"nc-set-info",children:g("fleet-overview-help")}),c.jsx(yd,{token:e,targets:n,readonly:t,onPower:rt,onImport:ct})]}):c.jsxs(c.Fragment,{children:[c.jsx("div",{className:"nc-set-info",children:g("fleet-manage-help")}),lt,c.jsxs("div",{className:"nc-set-row nc-fleet-backup-actions",children:[c.jsx("button",{className:"nc-btn ghost",disabled:ze||x,onClick:()=>{P(""),H(!0)},children:g("fleet-backup")}),c.jsx("small",{children:g("fleet-backup-help")})]}),c.jsxs("div",{className:"nc-fleet-section-head",children:[c.jsx("b",{children:g("fleet-cells")}),c.jsx("span",{className:"nc-fleet-head-actions",children:c.jsxs("button",{className:"nc-btn primary",disabled:ze||x||!a.engines.length,onClick:()=>{var le;P(""),w({mode:"new",form:m_((le=a.engines[0])==null?void 0:le.id)})},children:["+ ",g("add")]})})]}),a.cells.map(le=>{const be=ge.has(le.id),Be=h.capabilities||[],$e=le.needsRepair===!0;return c.jsxs("div",{className:"nc-fleet-item",children:[c.jsxs("span",{children:[c.jsx("b",{children:le.id}),c.jsxs("small",{children:[le.engine," · ",$e?c.jsx("span",{className:"nc-fleet-tag nc-fleet-tag-warn",children:g("fleet-cwd-needs-repair")}):le.cwd,be?` · ${g("service-active")}`:` · ${g("cell-off")}`]})]}),c.jsxs("span",{children:[be&&Be.includes("down")&&c.jsx("button",{className:"nc-btn ghost",disabled:ze||x,onClick:()=>fe(()=>vl(e,{cell:le.id},ae)),children:g("stop")}),!be&&Be.includes("up")&&c.jsx("button",{className:"nc-btn primary",disabled:ze||x,onClick:()=>rt({cell:le.id,id:le.id,engine:le.engine,model:le.model,models:le.models,permissionPolicies:le.permissionPolicies,active:!1,boot:le.boot}),children:g("start")}),be&&Be.includes("restart")&&c.jsx("button",{className:"nc-btn ghost",disabled:ze||x,onClick:()=>fe(()=>bo(e,le.id,ae)),children:g("restart")}),$e?c.jsx("button",{className:"nc-btn ghost",disabled:ze||x,onClick:()=>{P(""),R(le)},children:g("fleet-cwd-repair")}):c.jsx("button",{className:"nc-btn ghost",disabled:ze||x,onClick:()=>{var he;P(""),w({mode:"edit",original:le,form:{...le,commands:{...le.commands||{}},command:((he=le.commands)==null?void 0:he[le.engine])||""}})},children:g("edit")}),c.jsx("button",{className:"nc-btn danger",disabled:ze||x,onClick:()=>fe(async()=>{window.confirm(g("fleet-remove-cell").replace("{id}",le.id))&&await L_(e,le.id,!0,ae)}),children:"×"})]})]},le.id)}),c.jsxs("div",{className:"nc-fleet-section-head",children:[c.jsx("b",{children:g("fleet-engines")}),c.jsxs("button",{className:"nc-btn primary",disabled:ze||x,onClick:()=>{P(""),y({mode:"new",form:X2()})},children:["+ ",g("add")]})]}),a.engines.map(le=>{var Be,$e;const be=Fe(le);return c.jsxs("div",{className:"nc-fleet-item",children:[c.jsxs("span",{children:[c.jsx("b",{children:le.label}),c.jsx("small",{children:le.managed?`${le.id} · ${le.managed.client} / ${le.managed.provider} · ${(Be=le.managedInfo)!=null&&Be.configured?g("fleet-ready"):(($e=le.managedInfo)==null?void 0:$e.reason)||g("fleet-not-ready")}`:`${le.id} · ${le.command}`}),be&&c.jsxs("small",{children:[be.envKey," · ",g(`fleet-credential-source-${be.source||"missing"}`)]})]}),c.jsxs("span",{children:[be&&c.jsx("button",{className:"nc-btn ghost",disabled:ze||x,onClick:()=>{P(""),O({envKey:be.envKey,value:""})},children:be.configured?g("fleet-credential-change"):g("fleet-credential-set")}),(be==null?void 0:be.source)==="local"&&c.jsx("button",{className:"nc-btn danger",disabled:ze||x,onClick:()=>Ge(be),children:g("fleet-credential-forget")}),c.jsx("button",{className:"nc-btn ghost",disabled:ze||x,onClick:()=>{P(""),y({mode:"edit",original:le,form:Q2(le)})},children:g("edit")}),c.jsx("button",{className:"nc-btn danger",disabled:ze||x,onClick:()=>fe(async()=>{window.confirm(g("fleet-remove-engine").replace("{id}",le.id))&&await t0(e,le.id,ae)}),children:"×"})]})]},le.id)})]}),b&&c.jsx(Nr,{onClose:()=>y(null),label:g("fleet-new-engine"),error:k,children:c.jsx(tN,{state:b,setState:y,busy:x,onSave:Ie,catalog:a.managedCatalog||[]})}),S&&c.jsx(Nr,{onClose:()=>w(null),label:g("fleet-new-cell"),error:k,children:c.jsx(nN,{token:e,route:ae,targets:n,location:Y,setLocation:K,state:S,setState:w,engines:a.engines,busy:x,onSave:et})}),j&&c.jsx(Nr,{onClose:()=>R(null),label:g("fleet-cwd-repair-title").replace("{id}",j.id),error:"",children:c.jsx(rN,{token:e,route:ae,cell:j,busy:x,onSaved:async()=>{R(null),M(g("fleet-cwd-repaired")),await ue()},onClose:()=>R(null)})}),B&&c.jsx("div",{className:"nc-set-note",children:B}),k&&c.jsx("div",{className:"nc-err",children:k}),T&&c.jsx(Nr,{onClose:()=>H(!1),label:g("fleet-backup"),error:k,children:c.jsx(eN,{cells:a.cells,engines:a.engines,busy:x,canRestore:q,onRestore:it,onClose:()=>H(!1)})}),ie&&c.jsx(Nr,{onClose:()=>O(null),label:g("fleet-credential-title"),error:k,children:c.jsxs("div",{className:"nc-fleet-form nc-credential-form",children:[c.jsx("b",{children:g("fleet-credential-title")}),c.jsx("small",{children:g("fleet-credential-help")}),c.jsxs("label",{className:"nc-field",children:[ie.envKey,c.jsx("input",{type:"password",autoComplete:"off",spellCheck:"false",autoCapitalize:"none",value:ie.value,onChange:le=>O({...ie,value:le.target.value})})]}),c.jsxs("div",{className:"nc-sheet-actions",children:[c.jsx("button",{className:"nc-btn ghost",onClick:()=>O(null),children:g("cancel")}),c.jsx("button",{className:"nc-btn primary",disabled:x||!ie.value,onClick:Ct,children:g("save")})]})]})}),F&&c.jsx(Nr,{onClose:()=>I(null),label:g("import-as-cell"),error:k,children:c.jsx(g_,{token:e,route:F.route||ae,state:F,setState:I,busy:x,onSave:vt})}),U&&c.jsx(yl,{cell:U,token:e,route:Array.isArray(U.route)?U.route:ae,onConfirm:async le=>{try{await ut(le)}finally{await ue()}},onClose:()=>Z(null)})]}):c.jsxs("div",{className:"nc-set-tab",children:[mt,L==="overview"?c.jsxs(c.Fragment,{children:[c.jsx("div",{className:"nc-set-info",children:g("fleet-overview-help")}),c.jsx(yd,{token:e,targets:n,readonly:t,onPower:rt,onImport:ct})]}):c.jsxs(c.Fragment,{children:[lt,c.jsxs("div",{className:"nc-set-info",children:[g(k?"fleet-editor-load-error":"fleet-editor-unavailable"),!k&&h.reason?` ${h.reason}`:""]})]}),k&&c.jsx("div",{className:"nc-err",children:k}),F&&c.jsx(Nr,{onClose:()=>I(null),label:g("import-as-cell"),error:k,children:c.jsx(g_,{token:e,route:F.route||ae,state:F,setState:I,busy:x,onSave:vt})}),U&&c.jsx(yl,{cell:U,token:e,route:Array.isArray(U.route)?U.route:ae,onConfirm:async le=>{try{await ut(le)}finally{await ue()}},onClose:()=>Z(null)})]}):c.jsxs("div",{className:"nc-set-tab",children:[mt,L==="overview"?c.jsxs(c.Fragment,{children:[c.jsx("div",{className:"nc-set-info",children:g("fleet-overview-help")}),c.jsx(yd,{token:e,targets:n,readonly:t,onPower:rt,onImport:ct})]}):c.jsxs(c.Fragment,{children:[lt,c.jsx("div",{className:"nc-set-info",children:g("fleet-editor-loading")})]})]})}const lf="nc_notification_speech_v1",ll="nc-notification-speech",vh="nc-notification-speech-preview",oN=320,aN=2,lN=3e4,cN=1e4,uN=6e4,dN=64,v_=Object.freeze({enabled:!1}),hN=Object.freeze({it:"it-IT",en:"en-US",es:"es-ES"}),fN=Object.freeze({it:new Set(["che","con","correzione","della","delle","difetto","il","lavoro","nessun","non","per","pronto","pubblicata","pubblicato","rilascio","sono","stato","tutti","verificata","verificato","versione","completata","completato","riepilogo"]),en:new Set(["all","and","completed","fix","for","issue","no","published","ready","release","summary","the","verified","version","with","work"]),es:new Set(["con","correccion","defecto","el","esta","para","publicada","publicado","resumen","sin","todos","trabajo","verificada","verificado","version","y"])}),cf=new WeakSet;function uf(e){return{enabled:(e&&typeof e=="object"&&!Array.isArray(e)?e:{}).enabled===!0}}function Bw(){try{return typeof localStorage<"u"?localStorage:null}catch{return null}}function __(e=Bw()){if(!e)return{...v_};try{return uf(JSON.parse(e.getItem(lf)||"null"))}catch{return{...v_}}}function pN(e,t=Bw()){const n=uf(e);if(t)try{t.setItem(lf,JSON.stringify(n))}catch{}return n}function Ls(){try{return typeof window<"u"?window:null}catch{return null}}function Mo(e=Ls()){try{return!!(e&&e.speechSynthesis&&typeof e.speechSynthesis.speak=="function"&&typeof e.SpeechSynthesisUtterance=="function")}catch{return!1}}function Ow(e=Ls()){return!!(e&&(typeof e=="object"||typeof e=="function")&&cf.has(e))}function _h(e=Ls()){e&&(typeof e=="object"||typeof e=="function")&&cf.delete(e)}function ws(e){const t=String(e||"").trim().toLowerCase().split("-")[0];return hN[t]||""}function Kl(e){return String(e||"").normalize("NFC").replace(/[\p{Cc}\p{Cf}]+/gu," ").replace(/\s+/g," ").trim()}function mN(e){const t=Kl(e).normalize("NFD").replace(new RegExp("\\p{M}+","gu"),"").toLowerCase(),n=new Set(t.match(new RegExp("\\p{L}+","gu"))||[]);if(n.size<4)return"";const s=Object.entries(fN).map(([o,a])=>({lang:o,score:[...n].reduce((u,h)=>u+(a.has(h)?1:0),0)})).sort((o,a)=>a.score-o.score);return s[0].score>=3&&s[0].score-s[1].score>=2?s[0].lang:""}function gN(e,t){const n=ws(e&&e.lang);return n||ws(mN(e&&e.body))||ws(t)}function zw(e){try{const t=e&&e.speechSynthesis&&e.speechSynthesis.getVoices;return typeof t=="function"?Array.from(t.call(e.speechSynthesis)||[]).filter(Boolean):[]}catch{return[]}}function Fw(e,t){const n=ws(t);if(!n)return null;const s=Array.from(e||[]).filter(h=>h&&typeof h.lang=="string"&&h.lang.trim()),o=s.filter(h=>h.lang.trim().toLowerCase()===n.toLowerCase()),a=n.slice(0,2).toLowerCase(),u=s.filter(h=>h.lang.trim().toLowerCase().split("-")[0]===a);return o.find(h=>h.default===!0)||o[0]||u.find(h=>h.default===!0)||u[0]||null}function y_(e){return Kl(e).replace(/\bBearer\s+\S+/gi,"Bearer [redacted]").replace(/\b(?:sk|hf|zai|xox[baprs]|gh[pousr]|npm)[_-][A-Za-z0-9._-]{8,}\b/gi,"[redacted]").replace(/\b(?:token|password|secret|credential|api[_-]?key)\s*[=:]\s*(?:"[^"]*"|'[^']*'|\S+)/gi,"[redacted]").replace(/\b[A-Z][A-Z0-9_]{2,}\s*=\s*(?:"[^"]*"|'[^']*'|\S+)/g,"[redacted]").replace(/(?:\/home\/[^/\s]+|\/Users\/[^/\s]+|\/data\/(?:data|user\/\d+)\/[^/\s]+)(?:\/[^\s]*)?/g,"[private path]").replace(/\b[A-Za-z]:\\Users\\[^\\\s]+(?:\\[^\s]*)?/g,"[private path]")}function vN(e,t=oN){const n=y_(e&&e.title),s=y_(e&&e.body),o=[n,s&&s!==n?s:""].filter(Boolean).join(". "),a=Array.from(o);return a.length<=t?o:`${a.slice(0,Math.max(0,t-1)).join("").trimEnd()}…`}function _N(e){try{return!!(e&&e.visibilityState==="visible"&&typeof e.hasFocus=="function"&&e.hasFocus())}catch{return!1}}function $w(e=Ls()){if(!Mo(e))return!1;try{return e.speechSynthesis.cancel(),!0}catch{return!1}}function yN(e){try{e&&typeof e.dispatchEvent=="function"&&typeof e.Event=="function"&&e.dispatchEvent(new e.Event(vh))}catch{}}function wN(e,t,n=Ls(),s={}){var f;if(_h(n),!Mo(n))return Promise.resolve(!1);const o=Kl(e);if(!o||(f=s.signal)!=null&&f.aborted)return Promise.resolve(!1);const a=Number.isFinite(s.timeoutMs)&&s.timeoutMs>0?s.timeoutMs:cN,u=s.setTimer||((_,b)=>setTimeout(_,b)),h=s.clearTimer||(_=>clearTimeout(_)),p=s.signal;return yN(n),new Promise(_=>{let b=!1,y=!1,S=null,w=null;const x=C=>{if(!b){if(b=!0,p&&w&&p.removeEventListener("abort",w),S!==null&&h(S),C)cf.add(n);else try{n.speechSynthesis.cancel()}catch{}_(C)}};w=()=>x(!1),p&&p.addEventListener("abort",w,{once:!0});try{n.speechSynthesis.cancel();const C=new n.SpeechSynthesisUtterance(o);C.lang=ws(t);const k=Fw(zw(n),C.lang);k&&(C.voice=k),C.onstart=()=>{y=!0},C.onend=()=>x(y),C.onerror=()=>x(!1),S=u(()=>x(!1),a),n.speechSynthesis.speak(C)}catch{x(!1)}})}function SN(e={}){const t=e.scope||Ls(),n=e.document||t&&t.document,s=Number.isInteger(e.maxPending)&&e.maxPending>=0?e.maxPending:aN,o=Number.isFinite(e.watchdogMs)&&e.watchdogMs>0?e.watchdogMs:lN,a=Number.isFinite(e.dedupWindowMs)&&e.dedupWindowMs>0?e.dedupWindowMs:uN,u=Number.isInteger(e.maxDedup)&&e.maxDedup>0?e.maxDedup:dN,h=e.now||Date.now,p=e.setTimer||((F,I)=>setTimeout(F,I)),f=e.clearTimer||(F=>clearTimeout(F)),_=e.isPrimed||(()=>Ow(t)),b=t&&t.speechSynthesis;let y=null,S=null,w=[],x=[],C=()=>{};const k=new Map,P=()=>{x=zw(t)};if(P(),b&&typeof b.addEventListener=="function")b.addEventListener("voiceschanged",P),C=()=>b.removeEventListener("voiceschanged",P);else if(b&&"onvoiceschanged"in b){const F=b.onvoiceschanged,I=(...j)=>{P(),typeof F=="function"&&F.apply(b,j)};b.onvoiceschanged=I,C=()=>{b.onvoiceschanged===I&&(b.onvoiceschanged=F)}}const B=F=>{if(F&&typeof F.id=="string"&&F.id)return`id:${F.id}`;const I=Number(F&&F.ts),j=Kl(F&&F.title);return Number.isFinite(I)&&j?`frame:${I}:${j}`:""},M=F=>{if(!F)return!0;const I=h();for(const[j,R]of k)I-R>=a&&k.delete(j);if(k.has(F))return!1;for(k.set(F,I);k.size>u;)k.delete(k.keys().next().value);return!0},Y=()=>{S!==null&&f(S),S=null},K=()=>{Y(),y&&(y.onend=null,y.onerror=null,y=null),$w(t)},A=F=>{if(!Mo(t))return w=[],"unsupported";let I;try{I=new t.SpeechSynthesisUtterance(F.text),I.lang=ws(F.lang);const R=Fw(x,I.lang);R&&(I.voice=R)}catch{return w=[],"error"}y=I;const j=()=>{if(y!==I)return;Y(),y=null,I.onend=null,I.onerror=null;const R=w.shift();R&&A(R)};I.onend=j,I.onerror=j;try{return S=p(()=>{if(y!==I)return;y=null,I.onend=null,I.onerror=null;try{t.speechSynthesis.cancel()}catch{}Y();const R=w.shift();R&&A(R)},o),t.speechSynthesis.speak(I),"speaking"}catch{return j(),"error"}},ee=(F,I)=>{if(!Mo(t))return"unsupported";const j=vN(F);if(!j)return"empty";if(!M(B(F)))return"duplicate";if(!_N(n))return"inactive";if(!_())return"unprimed";const R={text:j,lang:I};return F&&F.urgency==="high"?(w=[],K(),A(R)):y?s===0?"dropped":(w.length>=s&&w.shift(),w.push(R),"queued"):A(R)},U=()=>{w=[],K()};return{enqueue:ee,stop:U,dispose:()=>{U(),C(),C=()=>{}}}}function Hw(){const[e,t]=N.useState(__);N.useEffect(()=>{const s=o=>{if((o==null?void 0:o.type)==="storage"&&o.key!==lf&&o.key!==null)return;const a=(o==null?void 0:o.type)===ll?uf(o.detail):__();t(a)};return window.addEventListener(ll,s),window.addEventListener("storage",s),()=>{window.removeEventListener(ll,s),window.removeEventListener("storage",s)}},[]);const n=N.useCallback(s=>{const o=pN({enabled:s===!0});return t(o),window.dispatchEvent(new CustomEvent(ll,{detail:o})),o.enabled},[]);return[e.enabled,n]}function bN({text:e}){const[t,n]=N.useState(!1),s=async()=>{try{await navigator.clipboard.writeText(e),n(!0),setTimeout(()=>n(!1),1500)}catch{}};return c.jsxs("div",{className:"nc-set-copyline",children:[c.jsx("code",{children:e}),c.jsxs("button",{type:"button",className:"nc-btn ghost",onClick:s,children:[c.jsx(nt,{name:"copy",size:14})," ",g(t?"copied":"copy")]})]})}function kN({value:e}){const[t,n]=N.useState("");return N.useEffect(()=>{let s=!0;return y2.toDataURL(e,{margin:1,width:220}).then(o=>{s&&n(o)}).catch(()=>{}),()=>{s=!1}},[e]),t?c.jsx("img",{src:t,width:"220",height:"220",alt:"NexusCrew pairing QR"}):null}function xN({token:e,nodes:t,roster:n,settings:s,readonly:o,refresh:a,refreshAliases:u}){const[h,p]=N.useState(null),[f,_]=N.useState(null),[b,y]=N.useState({}),[S,w]=N.useState(null),[x,C]=N.useState({ssh:"",sshPort:"",name:""}),[k,P]=N.useState(""),[B,M]=N.useState(""),[Y,K]=N.useState(""),[A,ee]=N.useState(!1),[U,Z]=N.useState(null),[F,I]=N.useState(null),j=Date.now(),R=s&&s.deviceName||"",T=(t||[]).filter(Q=>Q&&Q.direction==="outbound"&&Q.name&&Q.ssh),H=T.find(Q=>Q.name===k)||T[0]||null,te=T.find(Q=>Q.name===B)||T[0]||null,D=te?vg(te.tunnel,j):null,ie=te!=null&&te.shared?D!=null&&D.up?"share-local-active":"share-local-pending":D!=null&&D.up?"share-local-private":"share-local-private-down",O=[{key:"peer-group-hubs",rows:(t||[]).filter(Q=>Q.kind!=="transitive"&&Q.relation!=="client")},{key:"peer-group-clients",rows:(t||[]).filter(Q=>Q.kind!=="transitive"&&Q.relation==="client")},{key:"peer-group-routed",rows:(t||[]).filter(Q=>Q.kind==="transitive")}],L=async(Q,q)=>{p(null),_(`${Q}:${q}`);try{const fe=await jh(e,Q,q);q==="test"&&y(Ie=>({...Ie,[Q]:fe})),await a()}catch(fe){p(`${Q}: ${String(fe.message||fe)}`)}_(null)},$=async Q=>{p(null),_(`${Q}:remove`);try{await p0(e,Q),I(null),await a()}catch(q){p(`${Q}: ${String(q.message||q)}`)}_(null)},X=Q=>Z({name:Q.name,direction:Q.direction,label:Q.label||Q.name,ssh:Q.ssh||"",sshPort:Q.sshPort?String(Q.sshPort):"",autostart:Q.autostart===!0,visibility:Q.visibility||"network",selected:[...Q.selected||[]]}),ae=async()=>{if(!U||!ks(U.label)){p(g("err-label"));return}const Q=U.direction==="inbound"?{label:U.label,visibility:U.visibility,selected:U.visibility==="selected"?U.selected:[]}:{label:U.label,ssh:U.ssh,autostart:U.autostart,...U.sshPort?{sshPort:Number(U.sshPort)}:{}};p(null),_(`${U.name}:edit`);try{await f0(e,U.name,Q),Z(null),await a()}catch(q){p(`${U.name}: ${String(q.message||q)}`)}_(null)},ue=async Q=>{if(te){p(null),_(`${te.name}:share`);try{await m0(e,te.name,Q),await a()}catch(q){const fe=q!=null&&q.data&&q.data.shared===!1?q.data:null;if(fe)try{await a()}catch{}const Ie=q!=null&&q.data&&typeof q.data.hint=="string"?q.data.hint:"",et=(fe==null?void 0:fe.revoked)===!0&&(fe==null?void 0:fe.localReconcilePending)===!0?g("share-off-local-reconcile-pending"):(fe==null?void 0:fe.revoked)===!1&&(fe==null?void 0:fe.reconcilePending)===!0?g("share-off-hub-reconcile-pending"):"";p(`${te.name}: ${String(q.message||q)}${Ie?` — ${Ie}`:""}${et?` — ${et}`:""}`)}_(null)}},ge=async()=>{if(p(null),H){const fe=gg({name:H.name,ssh:H.ssh,sshPort:H.sshPort||""});if(!fe.ok){p(g(fe.error));return}_("invite");try{w(await eg(e,{ssh:fe.value.ssh,...fe.value.sshPort?{sshPort:fe.value.sshPort}:{}},[H.name]))}catch(Ie){p(String(Ie.message||Ie))}_(null);return}const Q=dr(x.name||Y||R||"NexusCrew"),q=gg({name:Q,ssh:x.ssh,sshPort:x.sshPort});if(!q.ok){p(g(q.error));return}_("invite");try{w(await eg(e,{...Y||R?{label:Y||R}:{},name:Q,ssh:q.value.ssh,...q.value.sshPort?{sshPort:q.value.sshPort}:{}}))}catch(fe){p(String(fe.message||fe))}_(null)};return c.jsxs("div",{className:"nc-set-tab",children:[c.jsx("div",{className:"nc-sheet-label",children:g("peer-inventory-title")}),(t||[]).length===0&&c.jsx("div",{className:"nc-empty",children:g("no-nodes")}),O.map(Q=>Q.rows.length>0&&c.jsxs("div",{className:"nc-peer-group",children:[c.jsxs("div",{className:"nc-peer-group-title",children:[g(Q.key)," ",c.jsx("span",{children:Q.rows.length})]}),Q.rows.map(q=>{var Fe,Ct;const fe=q.kind==="transitive",Ie=fe?{up:q.stale!==!0,label:q.stale===!0?"peer-routed-stale":"peer-routed"}:vg(q.tunnel,j),et=b[q.name],ze=q.actions||{};return c.jsxs("div",{className:`nc-set-node${fe?" routed":""}`,children:[c.jsxs("div",{className:"nc-set-node-head",children:[c.jsx("span",{className:`nc-dot ${Ie.up?"on":""}`}),c.jsx("b",{children:q.label||q.name}),c.jsxs("small",{children:[q.name,fe?` · ${q.route.join(" → ")}`:q.direction==="outbound"?` · SSH ${q.ssh||""}`:` · ${g("node-connected-client")}`,(Fe=q.tunnel)!=null&&Fe.transport?` · ${q.tunnel.transport} ${g("transport-used")}`:""]}),c.jsxs("span",{className:`nc-set-tunnel${Ie.up?" up":""}`,children:[g(Ie.label),Ie.since?` · ${Ie.since}`:""]})]}),!fe&&q.direction==="inbound"&&c.jsx("div",{className:"nc-set-info",children:g(q.shared?"peer-shared":"peer-private")}),ze.visibility&&q.shared&&c.jsxs(c.Fragment,{children:[c.jsxs("select",{value:q.visibility||"network",disabled:o||!!f,onChange:async Ge=>{_(`${q.name}:visibility`);try{await ng(e,q.name,Ge.target.value),await a()}catch(rt){p(String(rt.message||rt))}_(null)},children:[c.jsx("option",{value:"network",children:g("visibility-network")}),c.jsx("option",{value:"relay-only",children:g("visibility-relay")}),c.jsx("option",{value:"selected",children:g("visibility-selected")})]}),q.visibility==="selected"&&c.jsx("div",{className:"nc-set-row",children:(t||[]).filter(Ge=>Ge.name!==q.name&&Ge.nodeId).map(Ge=>{const rt=(q.selected||[]).includes(Ge.nodeId);return c.jsxs("label",{className:"nc-check",children:[c.jsx("input",{type:"checkbox",checked:rt,disabled:o||!!f,onChange:async ut=>{const ct=ut.target.checked?[...q.selected||[],Ge.nodeId]:(q.selected||[]).filter(vt=>vt!==Ge.nodeId);_(`${q.name}:visibility`);try{await ng(e,q.name,"selected",ct),await a()}catch(vt){p(String(vt.message||vt))}_(null)}})," ",Ge.label||Ge.name]},Ge.nodeId)})})]}),c.jsxs("div",{className:"nc-set-node-actions",children:[ze.edit&&c.jsx("button",{type:"button",className:"nc-btn ghost",disabled:o||!!f,onClick:()=>X(q),children:g("edit")}),ze.test&&c.jsx("button",{type:"button",className:"nc-btn ghost",disabled:!!f,onClick:()=>L(q.name,"test"),children:g("node-test")}),ze.disconnect&&Ie.up&&c.jsx("button",{type:"button",className:"nc-btn ghost",disabled:o||!!f,onClick:()=>L(q.name,"down"),children:g("tunnel-stop")}),ze.connect&&!Ie.up&&c.jsx("button",{type:"button",className:"nc-btn ghost",disabled:o||!!f,onClick:()=>L(q.name,"up"),children:g("tunnel-start")}),ze.restart&&c.jsx("button",{type:"button",className:"nc-btn ghost",disabled:o||!!f,onClick:()=>L(q.name,"restart"),children:g("tunnel-restart")}),ze.remove&&c.jsxs("button",{type:"button",className:"nc-btn danger",disabled:o||!!f,title:g(o?"settings-readonly":"delete"),onClick:()=>I(q.name),children:[c.jsx(nt,{name:"trash",size:14})," ",g("delete")]})]}),(U==null?void 0:U.name)===q.name&&c.jsxs("div",{className:"nc-set-form nc-node-editor",children:[c.jsxs("label",{className:"nc-field",children:[g("node-display-label"),c.jsx("input",{value:U.label,disabled:!!f,onChange:Ge=>Z({...U,label:Ge.target.value})})]}),U.direction==="outbound"?c.jsxs(c.Fragment,{children:[c.jsxs("label",{className:"nc-field",children:[g("node-ssh-label"),c.jsx("input",{value:U.ssh,disabled:!!f,onChange:Ge=>Z({...U,ssh:Ge.target.value})})]}),c.jsxs("label",{className:"nc-field",children:[g("node-ssh-port-label"),c.jsx("input",{inputMode:"numeric",value:U.sshPort,disabled:!!f,onChange:Ge=>Z({...U,sshPort:Ge.target.value.replace(/[^0-9]/g,"").slice(0,5)})})]}),c.jsxs("label",{className:"nc-check",children:[c.jsx("input",{type:"checkbox",checked:U.autostart,disabled:!!f,onChange:Ge=>Z({...U,autostart:Ge.target.checked})})," ",g("boot-persist")]})]}):c.jsxs("label",{className:"nc-field",children:[g("peer-visibility"),c.jsxs("select",{value:U.visibility,disabled:!!f,onChange:Ge=>Z({...U,visibility:Ge.target.value}),children:[c.jsx("option",{value:"network",children:g("visibility-network")}),c.jsx("option",{value:"relay-only",children:g("visibility-relay")}),c.jsx("option",{value:"selected",children:g("visibility-selected")})]})]}),c.jsxs("div",{className:"nc-set-row",children:[c.jsx("button",{type:"button",className:"nc-btn primary",disabled:!!f,onClick:ae,children:g("save")}),c.jsx("button",{type:"button",className:"nc-btn ghost",disabled:!!f,onClick:()=>Z(null),children:g("cancel")})]})]}),F===q.name&&c.jsxs("div",{className:"nc-set-confirm",children:[c.jsx("b",{children:g("node-remove-confirm").replace("{name}",q.label||q.name)}),c.jsx("small",{children:g("node-remove-warning")}),c.jsxs("div",{className:"nc-set-row",children:[c.jsx("button",{type:"button",className:"nc-btn danger",disabled:!!f,onClick:()=>$(q.name),children:g("delete")}),c.jsx("button",{type:"button",className:"nc-btn ghost",disabled:!!f,onClick:()=>I(null),children:g("cancel")})]})]}),((Ct=q.health)==null?void 0:Ct.detail)&&c.jsx("div",{className:`nc-set-test${q.health.status==="healthy"?" ok":q.health.status==="passive"?"":" ko"}`,children:q.health.detail}),et&&c.jsxs("div",{className:`nc-set-test${et.ok?" ok":" ko"}`,children:[et.result,et.detail?` — ${et.detail}`:""]})]},`${q.kind||"direct"}:${q.nodeId||q.name}`)})]},Q.key)),(n||[]).some(Q=>!Q.direct&&Q.instanceId)&&c.jsxs("div",{className:"nc-set-form",children:[c.jsx("div",{className:"nc-sheet-label",children:g("routed-node-aliases")}),c.jsx("small",{className:"nc-set-hint",children:g("routed-node-aliases-help")}),(n||[]).filter(Q=>!Q.direct&&Q.instanceId).map(Q=>c.jsxs("div",{className:"nc-set-node",children:[c.jsxs("div",{className:"nc-set-node-head",children:[c.jsx("span",{className:`nc-dot ${Q.status==="up"?"on":""}`}),c.jsx("b",{children:Q.label||Q.name}),c.jsx("small",{children:(Q.route||[]).join(" › ")})]}),c.jsxs("div",{className:"nc-set-node-actions",children:[c.jsx("button",{type:"button",className:"nc-btn ghost",disabled:o||!!f,onClick:async()=>{const q=window.prompt(g("node-local-alias"),Q.alias||"");if(q!=null){if(q.trim()&&!ks(q.normalize("NFC"))){p(g("err-label"));return}_(`${Q.instanceId}:alias`),p(null);try{q.trim()?await h0(e,Q.instanceId,q):await tg(e,Q.instanceId),u()}catch(fe){p(String(fe.message||fe))}_(null)}},children:g("alias-on-device")}),Q.alias&&c.jsx("button",{type:"button",className:"nc-btn ghost",disabled:o||!!f,onClick:async()=>{_(`${Q.instanceId}:alias-reset`),p(null);try{await tg(e,Q.instanceId),u()}catch(q){p(String(q.message||q))}_(null)},children:g("reset-alias")})]})]},Q.instanceId))]}),te&&c.jsxs("div",{className:"nc-set-form nc-local-share",children:[c.jsx("div",{className:"nc-sheet-label",children:g("share-local-heading")}),T.length>1&&c.jsxs("label",{className:"nc-field",children:[g("share-local-hub"),c.jsx("select",{value:te.name,disabled:o||!!f,onChange:Q=>M(Q.target.value),children:T.map(Q=>c.jsx("option",{value:Q.name,children:Q.label||Q.name},Q.name))})]}),c.jsxs("label",{className:"nc-check nc-node-share",children:[c.jsx("input",{type:"checkbox",checked:te.shared===!0,disabled:o||!!f,onChange:Q=>ue(Q.target.checked)}),c.jsxs("span",{children:[c.jsx("b",{children:g("share-local-through").replace("{device}",R||g("local")).replace("{hub}",te.label||te.name)}),c.jsx("small",{children:g(te.shared?"share-node-on-desc":"share-node-off-desc")})]})]}),c.jsx("div",{className:`nc-set-test${te.shared&&(D!=null&&D.up)?" ok":D!=null&&D.up?"":" ko"}`,children:g(ie)}),!(D!=null&&D.up)&&c.jsx("button",{type:"button",className:"nc-btn ghost",disabled:o||!!f,onClick:()=>ue(te.shared===!0),children:g("share-local-reconnect")})]}),c.jsx(Nw,{token:e,deviceDefault:R,localNodeId:s&&s.nodeId||"",localNameDefault:s&&s.localName||"",readonly:o,onSuccess:a}),c.jsxs("div",{className:"nc-set-form",children:[c.jsx("div",{className:"nc-sheet-label",children:g("invite-node")}),c.jsx("small",{className:"nc-set-hint",children:g(H?"invite-network-hint":"invite-v2-hint")}),H?c.jsxs(c.Fragment,{children:[T.length>1&&c.jsxs("label",{className:"nc-field",children:[g("invite-network-label"),c.jsx("select",{value:H.name,disabled:o||!!f,onChange:Q=>{P(Q.target.value),w(null)},children:T.map(Q=>c.jsx("option",{value:Q.name,children:Q.label||Q.name},Q.name))})]}),c.jsxs("div",{className:"nc-set-info nc-invite-endpoint",children:[g("invite-network-via"),": ",c.jsx("b",{children:H.label||H.name})," · ",H.ssh,H.sshPort?`:${H.sshPort}`:""]}),c.jsx("small",{className:"nc-set-hint",children:g("invite-network-route")})]}):c.jsxs("label",{className:"nc-field",children:[g("invite-endpoint-label"),c.jsx("input",{placeholder:"user@host",value:x.ssh,disabled:o,onChange:Q=>C({...x,ssh:Q.target.value})}),c.jsx("small",{className:"nc-set-hint",children:g("invite-endpoint-needed")})]}),!H&&A&&c.jsxs("div",{className:"nc-invite-advanced",children:[c.jsxs("label",{className:"nc-field",children:[g("node-ssh-port-label"),c.jsx("input",{inputMode:"numeric",placeholder:"22",value:x.sshPort,disabled:o,onChange:Q=>C({...x,sshPort:Q.target.value.replace(/[^0-9]/g,"").slice(0,5)})})]}),c.jsxs("label",{className:"nc-field",children:[g("device-name-label"),c.jsx("input",{placeholder:R||"NexusCrew",value:Y,disabled:o,onChange:Q=>K(Q.target.value)}),c.jsx("small",{className:"nc-set-hint",children:g("device-name-hint")})]}),c.jsxs("label",{className:"nc-field",children:[g("node-name-label"),c.jsx("input",{placeholder:dr(Y||R||g("node-name-ph")),value:x.name,disabled:o,onChange:Q=>C({...x,name:Q.target.value?dr(Q.target.value):""})})]})]}),c.jsxs("div",{className:"nc-set-row nc-invite-actions",children:[c.jsx("button",{type:"button",className:"nc-btn primary",disabled:o||!!f||!H&&!x.ssh.trim(),onClick:ge,children:g("create-pairing-link")}),!H&&c.jsxs("button",{type:"button",className:"nc-btn ghost",disabled:!!f,onClick:()=>ee(Q=>!Q),children:[A?"▾":"▸"," ",g("pair-advanced")]})]}),S&&c.jsxs(c.Fragment,{children:[c.jsx(kN,{value:S.pairingUrl}),c.jsx(bN,{text:S.pairingUrl}),c.jsx("div",{className:"nc-set-info",children:g("invite-next-steps")})]})]}),h&&c.jsx("div",{className:"nc-err",children:h})]})}function CN({token:e,readonly:t}){const[n,s]=N.useState("idle"),[o,a]=N.useState(!1),[u,h]=N.useState(null);N.useEffect(()=>{let f=!1;return L2().then(_=>{f||s(_)}),()=>{f=!0}},[]);const p=async()=>{h(null),a(!0);try{n==="subscribed"?(await T2(e),s("idle")):(await D2(e),s("subscribed"))}catch(f){const _=String(f.message||f);_==="push-denied"?(s("denied"),h(g("push-denied"))):_==="push-unsupported"?(s("unsupported"),h(g("push-unsupported"))):h(_)}a(!1)};return n==="unsupported"?c.jsx("div",{className:"nc-set-info",children:g("push-unsupported")}):c.jsxs(c.Fragment,{children:[c.jsxs("div",{className:"nc-set-row",children:[c.jsx("button",{type:"button",className:"nc-btn ghost",disabled:t||o||n==="denied",title:t?g("settings-readonly"):"",onClick:p,children:g(n==="subscribed"?"push-disable":"push-enable")}),c.jsx("span",{className:"nc-set-info",children:g(n==="subscribed"?"push-on":n==="denied"?"push-denied":"push-off")})]}),u&&c.jsx("div",{className:"nc-err",children:u})]})}function EN(){const[e,t]=Hw(),[n,s]=N.useState(""),[o,a]=N.useState(""),[u,h]=N.useState(!1),[p,f]=N.useState(Ow),_=N.useRef(0),b=N.useRef(!1),y=N.useRef(null),S=Mo();N.useEffect(()=>()=>{var C;_.current+=1,b.current&&((C=y.current)==null||C.abort(),y.current=null,b.current=!1,_h())},[]);const w=async()=>{const C=_.current+=1,k=typeof AbortController=="function"?new AbortController:null;s(""),a(""),h(!0),f(!1),b.current=!0,y.current=k;const P=await wN(g("notification-speech-preview"),_l(),void 0,k?{signal:k.signal}:{});return C!==_.current||(y.current=null,b.current=!1,h(!1),f(P),P?a(g("notification-speech-preview-ok")):s(g("notification-speech-preview-failed"))),P},x=C=>{var k;if(t(C),s(""),a(""),C)w();else{_.current+=1;const P=b.current;(k=y.current)==null||k.abort(),y.current=null,b.current=!1,h(!1),f(!1),_h(),P||$w()}};return c.jsxs("div",{className:"nc-set-form",children:[c.jsxs("label",{className:"nc-check",children:[c.jsx("input",{type:"checkbox","aria-label":g("notification-speech-enable"),checked:e,disabled:!S,onChange:C=>x(C.target.checked)}),c.jsxs("span",{children:[c.jsx("b",{children:g("notification-speech-enable")}),c.jsx("small",{children:g("notification-speech-help")})]})]}),S?c.jsx("div",{className:"nc-set-row",children:c.jsx("button",{type:"button",className:"nc-btn ghost",disabled:!e||u,onClick:()=>{w()},children:g(u?"notification-speech-testing":"notification-speech-test")})}):c.jsx("div",{className:"nc-set-info",children:g("notification-speech-unsupported")}),e&&!p&&!u&&!n&&c.jsx("div",{className:"nc-set-info",children:g("notification-speech-needs-test")}),o&&c.jsx("div",{className:"nc-set-info",role:"status",children:o}),n&&c.jsx("div",{className:"nc-err",children:n})]})}function NN(){const[e,t]=Gh();return c.jsxs("div",{className:"nc-set-tab nc-input-settings",children:[c.jsx("div",{className:"nc-set-info",children:g("input-settings-local")}),c.jsxs("div",{className:"nc-set-form",children:[c.jsxs("label",{className:"nc-field",children:[g("terminal-keyboard-gesture"),c.jsx("select",{"aria-label":g("terminal-keyboard-gesture"),value:e.terminalKeyboardGesture,onChange:n=>t({terminalKeyboardGesture:n.target.value}),children:sw.map(n=>c.jsx("option",{value:n,children:g(`terminal-keyboard-${n}`)},n))}),c.jsx("small",{children:g("terminal-keyboard-gesture-help")})]}),c.jsxs("label",{className:"nc-field",children:[g("keybar-layout"),c.jsx("select",{"aria-label":g("keybar-layout"),value:e.keybarLayout,onChange:n=>t({keybarLayout:n.target.value}),children:ow.map(n=>c.jsx("option",{value:n,children:g(`keybar-layout-${n}`)},n))}),c.jsx("small",{children:g("keybar-layout-help")})]})]}),c.jsxs("label",{className:"nc-check",children:[c.jsx("input",{type:"checkbox",checked:e.keybarKeepsKeyboardClosed,onChange:n=>t({keybarKeepsKeyboardClosed:n.target.checked})}),c.jsxs("span",{children:[c.jsx("b",{children:g("keybar-ime-lock")}),c.jsx("small",{children:g("keybar-ime-lock-help")})]})]}),c.jsxs("label",{className:"nc-check",children:[c.jsx("input",{type:"checkbox",checked:e.voiceKeepsKeyboardClosed,onChange:n=>t({voiceKeepsKeyboardClosed:n.target.checked})}),c.jsxs("span",{children:[c.jsx("b",{children:g("voice-ime-lock")}),c.jsx("small",{children:g("voice-ime-lock-help")})]})]}),c.jsxs("label",{className:"nc-check",children:[c.jsx("input",{type:"checkbox",checked:e.showKeybarEnter,onChange:n=>t({showKeybarEnter:n.target.checked})}),c.jsxs("span",{children:[c.jsx("b",{children:g("keybar-enter-show")}),c.jsx("small",{children:g("keybar-enter-show-help")})]})]}),c.jsx("div",{className:"nc-set-row",children:c.jsx("button",{type:"button",className:"nc-btn ghost",onClick:()=>t(lr),children:g("input-settings-reset")})})]})}function RN({token:e,roster:t=[],readonly:n}){const s=[{key:"local",route:[],label:g("diagnostics-local"),status:"up"},...t.filter(T=>Array.isArray(T.route)&&T.route.length).map(T=>({key:T.route.join("/"),route:T.route,label:T.label||T.name,status:T.status}))],[o,a]=N.useState("local"),u=s.find(T=>T.key===o)||s[0],[h,p]=N.useState(null),[f,_]=N.useState([]),[b,y]=N.useState(""),[S,w]=N.useState(!1),[x,C]=N.useState(!0),[k,P]=N.useState(900),[B,M]=N.useState("all"),[Y,K]=N.useState(""),A=N.useRef(0),ee=N.useRef(null),U=N.useCallback(async()=>{try{const T=await y0(e,u.route);if(p(T),y(""),!S){const H=await w0(e,{after:A.current,limit:200},u.route);Array.isArray(H.records)&&H.records.length&&(A.current=H.cursor,_(te=>[...te,...H.records].slice(-500)))}}catch(T){y(T&&T.status===404?g("diagnostics-unsupported"):String(T.message||T))}},[e,u.key,S]);N.useEffect(()=>{A.current=0,_([]),p(null),y("")},[u.key]),N.useEffect(()=>{let T=null,H=!0;const te=()=>{!H||document.visibilityState==="hidden"||U()},D=()=>{T&&clearInterval(T),T=document.visibilityState==="hidden"?null:setInterval(te,2e3),document.visibilityState!=="hidden"&&te()};return document.addEventListener("visibilitychange",D),D(),()=>{H=!1,T&&clearInterval(T),document.removeEventListener("visibilitychange",D)}},[U]),N.useEffect(()=>{x&&ee.current&&(ee.current.scrollTop=ee.current.scrollHeight)},[f,x]);const Z=f.filter(T=>(B==="all"||T.level===B)&&(!Y||String(T.component||"").toLowerCase().includes(Y.toLowerCase()))),F=Z.map(T=>`${T.ts} ${T.level.toUpperCase()} ${T.component} ${T.code} ${T.message}${Object.keys(T.meta||{}).length?` ${JSON.stringify(T.meta)}`:""}`).join(`
|
|
92
92
|
`),I=async T=>{y("");try{const H=await T();p(H),await U()}catch(H){y(String(H.message||H))}},j=async()=>{try{await navigator.clipboard.writeText(F)}catch{y(g("copy-manual"))}},R=()=>{try{const T=new Blob([`${JSON.stringify(Z,null,2)}
|
|
93
|
-
`],{type:"application/json"}),H=URL.createObjectURL(T),te=document.createElement("a");te.href=H,te.download="nexuscrew-diagnostics.json",te.click(),URL.revokeObjectURL(H)}catch{y(g("diagnostics-export-failed"))}};return c.jsxs("div",{className:"nc-set-tab nc-diagnostics",children:[c.jsxs("label",{className:"nc-field",children:[g("diagnostics-target"),c.jsx("select",{value:u.key,onChange:T=>a(T.target.value),children:s.map(T=>c.jsxs("option",{value:T.key,children:[T.label,T.status!=="up"?` · ${T.status}`:""]},T.key))})]}),c.jsxs("div",{className:"nc-set-form nc-diag-controls",children:[c.jsx("div",{className:"nc-sheet-label",children:g("diagnostics-verbose")}),c.jsxs("div",{className:"nc-set-row",children:[c.jsx("select",{"aria-label":g("diagnostics-duration"),value:k,onChange:T=>P(Number(T.target.value)),disabled:n,children:[300,900,1800,3600].map(T=>c.jsxs("option",{value:T,children:[T/60," min"]},T))}),c.jsx("button",{type:"button",className:"nc-btn primary",disabled:n||(h==null?void 0:h.verbose)===!0,onClick:()=>I(()=>ig(e,!0,k,u.route)),children:g("enable")}),c.jsx("button",{type:"button",className:"nc-btn ghost",disabled:n||(h==null?void 0:h.verbose)!==!0,onClick:()=>I(()=>ig(e,!1,k,u.route)),children:g("stop")})]}),c.jsx("small",{className:"nc-set-hint",children:h!=null&&h.verbose?g("diagnostics-expires").replace("{time}",new Date(h.expiresAt).toLocaleTimeString()):g("diagnostics-off")})]}),c.jsxs("div",{className:"nc-diag-filters",children:[c.jsxs("select",{"aria-label":g("diagnostics-level"),value:B,onChange:T=>M(T.target.value),children:[c.jsx("option",{value:"all",children:g("diagnostics-all-levels")}),["debug","info","warn","error"].map(T=>c.jsx("option",{value:T,children:T},T))]}),c.jsx("input",{"aria-label":g("diagnostics-component"),placeholder:g("diagnostics-component"),value:Y,onChange:T=>K(T.target.value)})]}),c.jsxs("div",{className:"nc-set-row",children:[c.jsxs("label",{className:"nc-check",children:[c.jsx("input",{type:"checkbox",checked:S,onChange:T=>w(T.target.checked)})," ",g("diagnostics-pause")]}),c.jsxs("label",{className:"nc-check",children:[c.jsx("input",{type:"checkbox",checked:x,onChange:T=>C(T.target.checked)})," ",g("diagnostics-autoscroll")]})]}),c.jsx("pre",{ref:ee,className:"nc-diag-log","aria-label":g("diagnostics-log"),children:F||g("diagnostics-empty")}),c.jsxs("div",{className:"nc-set-row",children:[c.jsx("button",{type:"button",className:"nc-btn ghost",onClick:j,children:g("copy")}),c.jsx("button",{type:"button",className:"nc-btn ghost",onClick:R,children:g("diagnostics-export")}),c.jsx("button",{type:"button",className:"nc-btn danger",disabled:n,onClick:()=>{window.confirm(g("diagnostics-clear-confirm"))&&I(async()=>{const T=await S0(e,u.route);return A.current=0,_([]),T})},children:g("diagnostics-clear")})]}),b&&c.jsx("div",{className:"nc-err",children:b})]})}function PN({token:e,settings:t,readonly:n,refresh:s}){const[o,a]=N.useState(null),[u,h]=N.useState(null),[p,f]=N.useState(!1),[_,b]=N.useState(!1),[y,S]=N.useState(null),[w,x]=N.useState(!0);N.useEffect(()=>{S(t&&t.update||null),x(!t||t.autoUpdate!==!1)},[t]);const C=async()=>{a(null),h(null),b(!0);try{const A=await c0(e);h(A.note||"ok"),f(!1)}catch(A){a(String(A.message||A))}b(!1)},k=async()=>{a(null),h(null),b(!0);try{const A=await g0(e);h(`${A.note||"ok"}${A.target?` (${A.target})`:""}`)}catch(A){a(String(A.message||A))}b(!1)},P=async A=>{a(null),h(null),b(!0);try{await A_(e,{autoUpdate:A}),x(A),s&&await s()}catch(ee){a(String(ee.message||ee))}b(!1)},B=async()=>{a(null),h(null),b(!0);try{S(await v0(e))}catch(A){a(String(A.message||A))}b(!1)},M=async()=>{a(null),h(null),b(!0);try{const A=await _0(e);S(A),h(g("npm-update-restarting"))}catch(A){a(String(A.message||A))}b(!1)},Y=()=>{window.confirm(g("composer-clear-confirm"))&&(a(null),lE()?(window.dispatchEvent(new Event(dh)),h(g("composer-clear-done"))):a(g("composer-clear-failed")))},K=t&&t.service;return c.jsxs("div",{className:"nc-set-tab",children:[t&&c.jsxs("div",{className:"nc-set-info",children:["v",t.version," · ",t.platform," · :",t.port,c.jsx("br",{}),K&&K.installed?g("service-installed"):g("service-missing"),K&&K.installed?` · ${K.active?g("service-active"):g("service-inactive")}`:"",K?` · boot ${K.boot?"on":"off"}`:""]}),c.jsxs("div",{className:"nc-set-row",children:[c.jsx("button",{type:"button",className:"nc-btn ghost",disabled:n||_,title:n?g("settings-readonly"):"",onClick:()=>{a(null),h(null),f(!0)},children:g("token-rotate")}),c.jsx("button",{type:"button",className:"nc-btn ghost",disabled:n||_,title:n?g("settings-readonly"):"",onClick:k,children:g("service-regenerate")})]}),c.jsxs("div",{className:"nc-set-form nc-update-settings",children:[c.jsxs("label",{className:"nc-check",children:[c.jsx("input",{type:"checkbox",checked:w,disabled:n||_||y&&!y.supported,onChange:A=>P(A.target.checked)}),c.jsxs("span",{children:[c.jsx("b",{children:g("npm-auto-update")}),c.jsx("small",{children:g("npm-auto-update-help")})]})]}),y&&c.jsxs("div",{className:"nc-set-info",children:[g("npm-update-current")," v",y.current,y.latest?` · ${g("npm-update-latest")} v${y.latest}`:""," · ",g(`npm-update-${y.supported?y.phase:"unsupported"}`)]}),c.jsxs("div",{className:"nc-set-row",children:[c.jsx("button",{type:"button",className:"nc-btn ghost",disabled:n||_||!y||!y.supported,onClick:B,children:g("npm-update-check")}),y&&y.available&&c.jsx("button",{type:"button",className:"nc-btn primary",disabled:n||_||y.phase==="installing",onClick:M,children:g("npm-update-install")})]}),y&&y.lastError&&c.jsx("div",{className:"nc-err",children:y.lastError})]}),c.jsx(CN,{token:e,readonly:n}),c.jsx(EN,{}),c.jsxs("div",{className:"nc-set-form",children:[c.jsx("div",{className:"nc-sheet-label",children:g("composer-clear-data")}),c.jsx("small",{className:"nc-set-hint",children:g("composer-clear-data-help")}),c.jsx("div",{className:"nc-set-row",children:c.jsx("button",{type:"button",className:"nc-btn ghost",onClick:Y,children:g("composer-clear-data")})})]}),p&&c.jsxs("div",{className:"nc-set-confirm",children:[c.jsx("div",{children:g("token-rotate-explain")}),c.jsxs("div",{className:"nc-sheet-actions",children:[c.jsx("button",{type:"button",className:"nc-btn ghost",disabled:_,onClick:()=>f(!1),children:g("cancel")}),c.jsx("button",{type:"button",className:"nc-btn primary",disabled:_,onClick:C,children:g("confirm")})]})]}),u&&c.jsx("div",{className:"nc-set-note",children:u}),o&&c.jsx("div",{className:"nc-err",children:o})]})}function jN({token:e,onClose:t,initialTab:n="nodes",initialLocation:s="",startNewCell:o=!1}){zn();const[a,u]=N.useState(n),[h,p]=N.useState(null),[f,_]=N.useState([]),[b,y]=N.useState(!1),[S,w]=N.useState(null),[x,C]=N.useState(0),k=Dh(e,!0,x),P=N.useCallback(async()=>{try{const B=await T_(e);p(B),w(null)}catch(B){w(String(B.message||B))}try{const B=await a0(e);_(B.peers||[])}catch(B){w(String(B.message||B))}},[e]);return N.useEffect(()=>{P();const B=setInterval(P,5e3);return()=>clearInterval(B)},[P]),N.useEffect(()=>{let B=!1;return tn("/api/config",e).then(M=>M.json()).then(M=>{B||y(!!M.readonlyDefault)}).catch(()=>{}),()=>{B=!0}},[e]),c.jsx("div",{className:"nc-set-overlay",onClick:t,children:c.jsxs("div",{className:"nc-set-panel",onClick:B=>B.stopPropagation(),children:[c.jsxs("div",{className:"nc-set-head",children:[c.jsx(nt,{name:"gear",size:18}),c.jsx("b",{children:g("settings")}),c.jsx("button",{type:"button",className:"nc-set-close",onClick:t,title:g("close"),children:c.jsx(nt,{name:"x",size:18})})]}),b&&c.jsx("div",{className:"nc-set-readonly",children:g("settings-readonly")}),S&&c.jsx("div",{className:"nc-err",children:S}),c.jsx("div",{className:"nc-set-tabs",children:["nodes","fleet","input","diagnostics","system"].map(B=>c.jsx("button",{type:"button",className:`nc-set-tabbtn${a===B?" on":""}`,onClick:()=>u(B),children:g(`tab-${B}`)},B))}),c.jsxs("div",{className:"nc-set-body",children:[a==="nodes"&&c.jsx(xN,{token:e,nodes:f,roster:k,settings:h,readonly:b,refresh:P,refreshAliases:()=>C(B=>B+1)}),a==="fleet"&&c.jsx(sN,{token:e,readonly:b,startNewCell:o,initialLocation:s,targets:k.map(B=>({route:B.route,label:B.label||B.name,status:B.status}))}),a==="input"&&c.jsx(NN,{}),a==="diagnostics"&&c.jsx(RN,{token:e,roster:k,readonly:b}),a==="system"&&c.jsx(PN,{token:e,settings:h,readonly:b,refresh:P})]})]})})}function LN({token:e,initialPair:t,deviceDefault:n="",localNodeId:s="",localNameDefault:o="",onPairDone:a,onDone:u}){zn();const[h,p]=N.useState(t?"pair":"welcome"),[f,_]=N.useState(!1),[b,y]=N.useState(null),S=async()=>{_(!0),y(null);try{await A_(e,{wizardDone:!0}),a&&a(),u()}catch(w){y(String(w.message||w)),_(!1)}};return c.jsx("div",{className:"nc-wiz-overlay",children:c.jsxs("div",{className:"nc-wiz",children:[c.jsxs("div",{className:"nc-wiz-head",children:[c.jsx("b",{children:g("wizard-title")}),c.jsx("small",{children:g("hydra-simple")})]}),h==="welcome"&&c.jsxs("div",{className:"nc-wiz-body",children:[c.jsx("div",{className:"nc-wiz-done",children:g("local-ready")}),c.jsxs("div",{className:"nc-sheet-actions",children:[c.jsx("button",{className:"nc-btn ghost",disabled:f,onClick:S,children:g("local-only")}),c.jsx("button",{className:"nc-btn primary",disabled:f,onClick:()=>p("pair"),children:g("add-node")})]})]}),h==="pair"&&c.jsxs("div",{className:"nc-wiz-body",children:[c.jsx(Nw,{token:e,initial:t||"",autoStart:!!t,deviceDefault:n,localNodeId:s,localNameDefault:o,onBusyChange:_,onSuccess:async()=>{a&&a(),p("done")}}),c.jsx("div",{className:"nc-sheet-actions",children:c.jsx("button",{className:"nc-btn ghost",disabled:f,onClick:()=>{a&&a(),p("welcome")},children:g("back")})})]}),h==="done"&&c.jsxs("div",{className:"nc-wiz-body",children:[c.jsx("div",{className:"nc-wiz-done",children:g("node-connected")}),c.jsx("div",{className:"nc-sheet-actions",children:c.jsx("button",{className:"nc-btn primary",disabled:f,onClick:S,children:g("finish")})})]}),b&&c.jsx("div",{className:"nc-err",children:b})]})})}function DN(e,t){if(typeof EventSource>"u"||!e)return()=>{};const n=new EventSource(`/api/events?token=${encodeURIComponent(e)}`);return n.onmessage=s=>{try{const o=JSON.parse(s.data);o&&typeof o=="object"&&typeof o.type=="string"&&t(o)}catch{}},()=>{try{n.close()}catch{}}}const TN=6e3,MN=12e3;function AN({n:e,onClose:t}){return c.jsxs("div",{className:`nc-ntf-toast${e.urgency==="high"?" high":""}`,role:"status","aria-live":"polite",children:[c.jsxs("div",{className:"nc-ntf-toast-txt",children:[c.jsx("b",{children:e.title}),e.body&&c.jsx("small",{children:e.body}),e.session&&c.jsx("span",{className:"nc-ntf-from",children:e.session})]}),c.jsx("button",{type:"button",className:"nc-ntf-x",onClick:t,title:g("close"),children:c.jsx(nt,{name:"x",size:14})})]})}function IN({ask:e,token:t,onAnswered:n}){const[s,o]=N.useState(""),[a,u]=N.useState(!1),[h,p]=N.useState(null),f=async _=>{const b=String(_||"").trim();if(!(!b||a)){p(null),u(!0);try{await k0(t,e.id,b),n(e.id)}catch(y){p(String(y.message||y))}u(!1)}};return c.jsxs("div",{className:"nc-ask-card",children:[c.jsxs("div",{className:"nc-ask-head",children:[c.jsx("span",{className:"nc-ntf-from",children:e.session}),c.jsxs("code",{className:"nc-ask-id",children:["#",e.id]})]}),c.jsx("div",{className:"nc-ask-q",children:e.question}),Array.isArray(e.options)&&e.options.length>0&&c.jsx("div",{className:"nc-ask-opts",children:e.options.map(_=>c.jsx("button",{type:"button",className:"nc-btn ghost",disabled:a,onClick:()=>f(_),children:_},_))}),c.jsxs("div",{className:"nc-ask-reply",children:[c.jsx("textarea",{rows:2,placeholder:g("ask-reply-ph"),value:s,disabled:a,onChange:_=>o(_.target.value)}),c.jsx("button",{type:"button",className:"nc-btn primary",disabled:a||!s.trim(),onClick:()=>f(s),children:g("send")})]}),h&&c.jsx("div",{className:"nc-err",children:h})]})}function BN({token:e}){const[t]=zn(),[n]=Hw(),[s,o]=N.useState([]),[a,u]=N.useState([]),[h,p]=N.useState(()=>{try{return/(?:^|[#&])ask=/.test(location.hash)}catch{return!1}}),f=N.useRef(0),_=N.useRef(null);_.current||(_.current=SN());const b=N.useRef({enabled:n,lang:t});b.current={enabled:n,lang:t};const y=N.useCallback(x=>{o(C=>C.filter(k=>k.key!==x))},[]),S=N.useCallback(x=>{const C=`t${f.current+=1}`;o(P=>[...P.slice(-3),{...x,key:C}]),setTimeout(()=>y(C),x.urgency==="high"?MN:TN);const k=b.current;if(k.enabled)try{_.current.enqueue(x,gN(x,k.lang))}catch{}},[y]);N.useEffect(()=>{n||_.current.stop()},[n]),N.useEffect(()=>{const x=()=>{(document.visibilityState!=="visible"||!document.hasFocus())&&_.current.stop()},C=()=>_.current.stop();return document.addEventListener("visibilitychange",x),window.addEventListener("blur",x),window.addEventListener(vh,C),()=>{document.removeEventListener("visibilitychange",x),window.removeEventListener("blur",x),window.removeEventListener(vh,C),typeof _.current.dispose=="function"?_.current.dispose():_.current.stop()}},[]),N.useEffect(()=>{if(!e)return;let x=!1;b0(e).then(k=>{x||u(k.asks||[])}).catch(()=>{});const C=DN(e,k=>{k.type==="notify"?S(k):k.type==="ask"&&k.ask&&k.ask.id?u(P=>P.some(B=>B.id===k.ask.id)?P:[...P,k.ask]):k.type==="ask-answered"&&k.id&&u(P=>P.filter(B=>B.id!==k.id))});return()=>{x=!0,C()}},[e,S]);const w=x=>u(C=>C.filter(k=>k.id!==x));return c.jsxs(c.Fragment,{children:[s.length>0&&c.jsx("div",{className:"nc-ntf-toasts",children:s.map(x=>c.jsx(AN,{n:x,onClose:()=>y(x.key)},x.key))}),a.length>0&&!h&&c.jsxs("button",{type:"button",className:"nc-ask-badge",onClick:()=>p(!0),title:g("asks-title"),children:["? ",c.jsx("span",{className:"nc-ask-count",children:a.length})]}),a.length>0&&h&&c.jsxs("div",{className:"nc-ask-panel",children:[c.jsxs("div",{className:"nc-ask-panel-head",children:[c.jsx("b",{children:g("asks-title")}),c.jsx("span",{className:"nc-ask-count",children:a.length}),c.jsx("button",{type:"button",className:"nc-ntf-x",onClick:()=>p(!1),title:g("close"),children:c.jsx(nt,{name:"x",size:16})})]}),c.jsx("div",{className:"nc-ask-panel-body",children:a.map(x=>c.jsx(IN,{ask:x,token:e,onAnswered:w},x.id))})]})]})}const wd=e=>vi(Ar(e)).length===0,Sd=e=>Array.isArray(e)?e.join("/"):"";function ON(e){const t=new Set,n=[];for(const s of Array.isArray(e)?e:[])!s||!Bn.test(String(s.instanceId||""))||!Array.isArray(s.route)||!s.route.length||t.has(s.instanceId)||(t.add(s.instanceId),n.push({instanceId:s.instanceId,route:[...s.route],label:String(s.label||s.name||s.route.join(" › ")),status:s.status||"offline"}));return n.sort((s,o)=>s.label.localeCompare(o.label))}function So(e){return{instanceId:e.ownerId,route:e.ownerRoute||[],label:e.ownerLabel,status:e.available===!1?"offline":"up"}}function Rr(e,t,n,s=!1,o=!0){const a=t.instanceId;return{...e,id:ys(s?null:a,e.name),ownerId:a,ownerRoute:s?[]:[...t.route],ownerLabel:s?"Local":t.label,local:s,available:o,ownerTopology:Array.isArray(n)?n:[],layout:fh(e.layout,a,n)}}function zN(e,t,n,s,o=[]){const[a,u]=N.useState([]),[h,p]=N.useState(!1),[f,_]=N.useState("idle"),[b,y]=N.useState(""),[S,w]=N.useState(""),x=N.useRef([]),C=N.useRef([]),k=N.useRef(""),P=N.useRef(t),B=N.useRef(n),M=N.useRef(!1),Y=N.useRef(!0),K=N.useRef(""),A=N.useMemo(()=>ON(o),[o]),ee=A.map(O=>`${O.instanceId}:${Sd(O.route)}:${O.status}:${O.label}`).join("|");C.current=A,B.current=n,P.current=t,x.current=a;const U=N.useCallback(O=>ph(O.layout,k.current,C.current),[]),Z=N.useCallback((O,L=!0,$=P.current)=>{const X=Pv(O,rl()),ae=x.current.some(ge=>ge.id===$);x.current=X,u(X);const ue=X.find(ge=>ge.id===$);if(L&&ue){Y.current=!0;const ge=U(ue);s(ge),ue.local&&DE(ue.name,ge)}else ae&&!ue&&(Y.current=!0,s(_s()),y("deck non più condiviso dal nodo owner"));RE(X.filter(ge=>ge.local).map(ge=>ge.name))},[s,U]),F=N.useCallback(async O=>{let L=await Ga(e);const $=L.decks.find(X=>X.name==="main");if(L.decks.length===1&&$&&$.revision===0&&wd($.layout)){const X=NE(),ae=Ar(mh("main")||_s());if(!wd(ae)){const ue=fh(ae,O,[]);L.decks[0]=await Xa(e,"main",ue,0,[])}for(const ue of X.filter(ge=>ge!=="main"))try{let ge=await rg(e,ue,[]);const Q=Ar(mh(ue)||_s());wd(Q)||(ge=await Xa(e,ue,fh(Q,O,[]),ge.revision,[]))}catch{}L=await Ga(e)}return L},[e]),I=N.useCallback(async({migrate:O=!1}={})=>{const L=await Ph(e,[]),$=Bn.test(String(L.instanceId||""))?L.instanceId:"";if(!$)throw new Error("instanceId locale non disponibile");k.current=$,w($);const[X,ae]=await Promise.all([O?F($):Ga(e),Zm(e,[]).catch(()=>({nodes:[]}))]),ue={instanceId:$,route:[],label:"Local"},ge=X.decks.map(q=>Rr(q,ue,ae.nodes,!0,!0)),Q=x.current;return await Promise.all(C.current.map(async q=>{if(q.status!=="up"){ge.push(...Q.filter(fe=>!fe.local&&fe.ownerId===q.instanceId).map(fe=>({...fe,ownerRoute:[...q.route],ownerLabel:q.label,available:!1})));return}try{const[fe,Ie]=await Promise.all([Ga(e,q.route),Zm(e,q.route).catch(()=>({nodes:[]}))]);ge.push(...fe.decks.map(et=>Rr(et,q,Ie.nodes,!1,!0)))}catch{ge.push(...Q.filter(Ie=>!Ie.local&&Ie.ownerId===q.instanceId).map(Ie=>({...Ie,ownerRoute:[...q.route],ownerLabel:q.label,available:!1})))}})),ge.sort((q,fe)=>q.local===fe.local?q.ownerLabel.localeCompare(fe.ownerLabel)||(q.name==="main"?-1:fe.name==="main"?1:q.name.localeCompare(fe.name)):q.local?-1:1),ge},[e,F,ee]);N.useEffect(()=>{if(!e)return;let O=!1;const L=K.current!==e;return K.current=e,I({migrate:L}).then($=>{if(O)return;const X=x.current.find(ge=>ge.id===P.current),ae=$.find(ge=>ge.id===P.current),ue=ae&&(!X||ae.revision>X.revision||X.available!==ae.available||Sd(X.ownerRoute)!==Sd(ae.ownerRoute));Z($,L||!!ue&&!M.current),p(!0),ae&&y("")}).catch($=>{O||(p(!0),y(String($.message||$)))}),()=>{O=!0}},[Z,I,ee,e]);const j=N.useCallback(async(O=P.current)=>{if(!h||!M.current)return!0;const L=x.current.find($=>$.id===O);if(!L)return y(`deck inesistente: ${O}`),!1;if(L.available===!1)return y(`nodo owner offline: ${L.ownerLabel}`),!1;_("saving");try{const $=Nv(Ar(B.current),L.ownerId,L.ownerTopology),X=await Xa(e,L.name,$,L.revision,L.ownerRoute),ae=Rr(X,So(L),L.ownerTopology,L.local,!0);return Z(x.current.map(ue=>ue.id===O?ae:ue),!1),M.current=!1,_("saved"),y(""),setTimeout(()=>_("idle"),1500),!0}catch($){if(_("error"),y(String($.message||$)),$.status===409&&$.data&&$.data.current){const X=x.current.find(ue=>ue.id===O),ae=Rr($.data.current,So(X),X.ownerTopology,X.local,!0);Z(x.current.map(ue=>ue.id===O?ae:ue),!1)}return!1}},[h,e,Z]);return N.useEffect(()=>{if(!h)return;if(Y.current){Y.current=!1;return}M.current=!0,_("saving");const O=setTimeout(j,650);return()=>clearTimeout(O)},[n,h,j]),N.useEffect(()=>{if(!h)return;const O=setInterval(async()=>{try{const L=await I(),$=x.current.find(ue=>ue.id===P.current),X=L.find(ue=>ue.id===P.current),ae=X&&(!$||X.revision>$.revision||$.available!==X.available);Z(L,ae&&!M.current)}catch{}},5e3);return()=>clearInterval(O)},[h,I,Z]),{decks:a,records:a,localNodeId:S,ready:h,saveState:f,error:b,setError:y,saveNow:j,select:async O=>{if(M.current&&!await j(P.current))throw new Error("salvataggio del deck corrente fallito: cambio annullato");const L=x.current.find($=>$.id===O);if(!L)throw new Error(`deck inesistente: ${O}`);return M.current=!1,Y.current=!0,U(L)},add:async(O,L=null)=>{const $=L===mi?x.current.find(ue=>ue.local):L?x.current.find(ue=>ue.ownerId===L):null;if(!$||$.available===!1)throw new Error("nodo owner non disponibile");const X=await rg(e,O,$.ownerRoute),ae=Rr(X,So($),$.ownerTopology,$.local,!0);return Z([...x.current,ae],!1),ae},rename:async(O,L)=>{const $=x.current.find(Q=>Q.id===O);if(!$)throw new Error("deck inesistente");if(O===P.current&&M.current&&!await j(O))throw new Error(`salvataggio di "${$.name}" fallito: rinomina annullata`);const X=x.current.find(Q=>Q.id===O);if(!X)throw new Error("deck inesistente");const ae=await x0(e,X.name,L,X.revision,X.ownerRoute),ue=Rr(ae,So(X),X.ownerTopology,X.local,!0),ge=X.local?mi:X.ownerId;return Yu(jE(rl(),ge,O,ue.id)),Z(x.current.map(Q=>Q.id===O?ue:Q),!1),ue},remove:async O=>{const L=x.current.find(X=>X.id===O);if(!L)throw new Error("deck inesistente");O===P.current&&(M.current=!1),await C0(e,L.name,L.revision,L.ownerRoute);const $=L.local?mi:L.ownerId;Yu(LE(rl(),$,O)),Z(x.current.filter(X=>X.id!==O),!1)},reorder:(O,L)=>{const $=x.current.find(q=>q.id===O),X=x.current.find(q=>q.id===L);if(!$||!X)return!1;const ae=$.local?mi:$.ownerId,ue=X.local?mi:X.ownerId;if(ae!==ue)return!1;const ge=x.current.filter(q=>(q.local?mi:q.ownerId)===ae).map(q=>q.id),Q=Yu(PE(rl(),ae,O,L,ge));return Z(Pv(x.current,Q),!1),!0},addTileTo:async(O,L)=>{const $=x.current.find(q=>q.id===O);if(!$)throw new Error("deck inesistente");if($.available===!1)throw new Error(`nodo owner offline: ${$.ownerLabel}`);const X=cw(L,k.current,C.current);if(!X)throw new Error("riferimento sessione non valido");const ae=U($),ue=Nv(Q_(ae,X),$.ownerId,$.ownerTopology),ge=await Xa(e,$.name,ue,$.revision,$.ownerRoute),Q=Rr(ge,So($),$.ownerTopology,$.local,!0);return Z(x.current.map(q=>q.id===O?Q:q),!1),Q},localMainId:ys(null,"main"),parseDeckId:Fl}}const FN="/sw.js",yh="nc-sw-update";let wh=null,Sh=!1,bh=null,Ww=Object.freeze({needed:!1,kind:null,version:""}),Uw=!1;function Kw(){typeof window<"u"&&window.dispatchEvent(new Event(yh))}function qw(){const e=bh||(Sh?{kind:"reload",version:""}:null);Ww=Object.freeze({needed:!!e,kind:(e==null?void 0:e.kind)||null,version:(e==null?void 0:e.version)||""})}function w_(){return Ww}function $N(e){return typeof window>"u"?()=>{}:(window.addEventListener(yh,e),()=>window.removeEventListener(yh,e))}function df(e){Sh!==e&&(Sh=e,qw(),Kw())}function HN(e,t,n){let s=null;e&&t&&e!==t?s={kind:"install",version:e}:t&&n&&t!==n&&(s={kind:"reload",version:t});const o=JSON.stringify(s)===JSON.stringify(bh);bh=s,qw(),o||Kw()}function WN(e){e.addEventListener("statechange",()=>{e.state==="installed"&&navigator.serviceWorker.controller&&df(!0)})}function UN(){typeof navigator>"u"||!("serviceWorker"in navigator)||(navigator.serviceWorker.addEventListener("controllerchange",()=>{Uw&&location.reload()}),navigator.serviceWorker.register(FN).then(e=>{wh=e,e.waiting&&df(!0),e.addEventListener("updatefound",()=>{const t=e.installing;t&&WN(t)}),setInterval(()=>{e.update().catch(()=>{})},3600*1e3)}).catch(()=>{}))}function KN(){Uw=!0,df(!1);const e=wh&&wh.waiting;e?(e.postMessage({type:"SKIP_WAITING"}),setTimeout(()=>location.reload(),4e3)):location.reload()}function qN({hash:e="",origin:t="",pathname:n="",search:s=""}={}){const o=String(e||"").replace(/^#/,""),a=`${n||""}${s||""}`;if(!o)return{token:"",pair:"",nextUrl:a};const u=new URLSearchParams(o),h=u.get("token")||"",p=u.get("pair")||"",f=p?`${t||""}${n||""}#pair=${p}`:"";return{token:h,pair:f,nextUrl:a}}const Vw=9,Yw=24,Gw="nc_side_w",S_="nc_side_min",VN=240,b_="(min-width:1024px) and (pointer:fine)";function YN(){const e=Number(localStorage.getItem(Gw));return e>=180&&e<=480?e:VN}function GN(){const e=Number(localStorage.getItem("nc_fontsize"));return e>=Vw&&e<=Yw?e:13}function XN(){const e={token:"",pair:""};try{const{token:t,pair:n,nextUrl:s}=qN({hash:location.hash,origin:location.origin,pathname:location.pathname,search:location.search});if(t){e.token=t;try{localStorage.setItem("nc_token",t)}catch{}}if(n){e.pair=n;try{sessionStorage.setItem("nc_pair",n)}catch{}}if(location.hash)try{history.replaceState(null,"",s)}catch{}}catch{}if(e.token||(e.token=sessionStorage.getItem("nc_token")||localStorage.getItem("nc_token")||""),!e.pair){const t=sessionStorage.getItem("nc_pair");t&&(e.pair=t)}return e}function JN(e){try{return Ar(mh(e))}catch{return _s()}}function k_(e){if(!e)return"";const t=Math.floor(Date.now()/1e3)-e;return t<0||t<60?"ora":t<3600?`${Math.floor(t/60)}m`:t<86400?`${Math.floor(t/3600)}h`:`${Math.floor(t/86400)}g`}function QN(){const[e,t]=N.useState(()=>window.matchMedia(b_).matches);return N.useEffect(()=>{const n=window.matchMedia(b_),s=o=>t(o.matches);return n.addEventListener("change",s),()=>n.removeEventListener("change",s)},[]),e}function x_({session:e,node:t,ownerId:n,cellName:s,token:o,readonly:a=!1,onBack:u}){zn();const[h]=Gh(),[p,f]=N.useState(!1),[_,b]=N.useState(()=>window.matchMedia("(pointer: coarse)").matches),[y,S]=N.useState(null),[w,x]=N.useState(GN),[C,k]=N.useState(s||e),[P,B]=N.useState(""),M=R=>x(T=>{const H=Math.max(Vw,Math.min(Yw,T+R));return localStorage.setItem("nc_fontsize",String(H)),H}),Y=N.useRef(()=>{}),K=N.useRef(()=>!1),A=N.useRef(()=>{}),ee=N.useRef(!1),[U,Z]=N.useState(!1),[F,I]=N.useState(!1),j=()=>{ee.current=!ee.current,Z(ee.current)};return N.useEffect(()=>{k(s||e)},[s,e]),N.useEffect(()=>{let R=!0;const T=t?t.split("/"):[],H=t?`/api/route/${t.split("/").map(encodeURIComponent).join("/")}/_`:"/api";async function te(){let ie=null,O=null;try{const X=await(await tn(`${H}/sessions`,o)).json();Array.isArray(X.sessions)&&(ie=X.sessions.find(ae=>ae.name===e))}catch{}try{const $=await zr(o,T);$.available&&Array.isArray($.cells)&&(O=$.cells.find(X=>X.tmuxSession===e))}catch{}if(!R)return;k(Xh({session:e,cell:O||(s?{cell:s}:null)}));let L="";O?L=`${O.engine}${O.key?`·${O.key}`:""}`:ie&&(L=ie.attached?`attached · ${k_(ie.activity)}`:ie.activity?k_(ie.activity):""),B(L)}te();const D=setInterval(te,4e3);return()=>{R=!1,clearInterval(D)}},[e,t,o]),c.jsxs("div",{className:"nc-app",children:[c.jsxs("header",{className:"nc-bar nc-bar-single",children:[c.jsxs("button",{onClick:u,title:g("sessions"),children:[c.jsx(nt,{name:"chevronLeft",size:18}),c.jsx("span",{className:"nc-bar-label",children:g("sessions")})]}),c.jsxs("span",{className:"nc-bar-center",children:[c.jsx("b",{title:t?`${C} · ${t}`:C,children:C}),P&&c.jsx("small",{className:"nc-bar-sub",children:P})]}),c.jsxs("span",{className:"nc-bar-right",children:[c.jsx("button",{onClick:()=>M(-1),title:g("zoom-out"),children:c.jsx(nt,{name:"zoomOut",size:18})}),c.jsx("button",{onClick:()=>M(1),title:g("zoom-in"),children:c.jsx(nt,{name:"zoomIn",size:18})}),c.jsx("button",{onClick:()=>b(R=>!R),title:g("composer"),children:c.jsx(nt,{name:"keyboard",size:20})}),c.jsx("button",{onClick:()=>f(R=>!R),title:g("files"),children:c.jsx(nt,{name:"folder",size:20})})]})]}),c.jsx("div",{className:"nc-termwrap",children:c.jsx(Yy,{session:e,node:t,token:o,readonly:a,takeSize:!0,sendRef:Y,composerRef:K,actionRef:A,ctrlRef:ee,setCtrlArmed:Z,onFiles:S,fontSize:w,selectionMode:F,onSelectionModeChange:I,keyboardGesture:h.terminalKeyboardGesture})}),c.jsx(JC,{onKeyboard:()=>b(R=>!R),send:R=>Y.current(R),action:R=>A.current(R),ctrlArmed:U,onCtrl:j,selectionMode:F,onSelectionMode:I,keepKeyboardClosed:h.keybarKeepsKeyboardClosed,showEnter:h.showKeybarEnter,keybarLayout:h.keybarLayout}),_&&c.jsx(rw,{submitText:R=>K.current(R),token:o,session:e,node:t,ownerId:n,keepKeyboardClosedOnVoice:h.voiceKeepsKeyboardClosed}),p&&c.jsx(Gy,{session:e,node:t,token:o,filesEvent:y,onClose:()=>f(!1)})]})}function ZN(){zn();const[e]=N.useState(XN),[t,n]=N.useState(e.token),[s,o]=N.useState(e.pair||""),a=N.useCallback(()=>{o("");try{sessionStorage.removeItem("nc_pair")}catch{}},[]),[u,h]=N.useState(!1),p=QN(),[f]=N.useState(()=>EE(typeof location<"u"?location.pathname:"/")),[_,b]=N.useState(f.id),y=_===ys(null,On),[S,w]=N.useState(null),x=de=>{const Ee=fr(de);w(Ee?{...Ee,...typeof(de==null?void 0:de.cellName)=="string"&&de.cellName?{cellName:de.cellName}:{}}:null)},[C,k]=N.useState([]),[P,B]=N.useState([]),[M,Y]=N.useState([]),[K,A]=N.useState(()=>f.ownerId?_s():JN(f.name)),[ee,U]=N.useState(null),[Z,F]=N.useState(null),I=de=>F(fr(de)),j=Dh(t,p),R=N.useMemo(()=>(j||[]).filter(de=>de.instanceId).map(de=>({instanceId:de.instanceId,route:de.route,label:de.label,status:de.status})),[j]),T=zN(t,_,K,A,R),H=T.decks;N.useEffect(()=>{const de=new Map;for(const Ee of j||[]){const Ue=(Ee.route||[Ee.name]).join("/"),_t=new Set((Ee.sessions||[]).map(dt=>dt.name));for(const dt of Ee.cells||[])!dt.cell||!dt.tmuxSession||dt.cell===dt.tmuxSession||_t.has(dt.cell)||de.set(`${Ue}:${dt.cell}`,`${Ue}:${dt.tmuxSession}`)}A(Ee=>Z0(Ee,de))},[j]),N.useEffect(()=>{T.localNodeId&&A(de=>{const Ee=ph(de,T.localNodeId,R);return JSON.stringify(Ee)===JSON.stringify(de)?de:Ee})},[R,T.localNodeId]);const[te,D]=N.useState(null),[ie,O]=N.useState(null),L=N.useRef(0),[$,X]=N.useState(!1),[ae,ue]=N.useState(YN),[ge,Q]=N.useState(!y),[q,fe]=N.useState(()=>y?localStorage.getItem(S_)==="1":!0),[Ie,et]=N.useState(!1),[ze,Fe]=N.useState("nodes"),[Ct,Ge]=N.useState(!1),[rt,ut]=N.useState(""),ct=(de="nodes",Ee=!1,Ue="")=>{Fe(de),Ge(Ee),ut(Ue),et(!0)},[vt,it]=N.useState(!1),[lt,mt]=N.useState({deviceDefault:"",localNodeId:"",localNameDefault:""}),[le,be]=N.useState(!1);N.useEffect(()=>{try{localStorage.setItem(Gw,String(ae))}catch{}},[ae]),N.useEffect(()=>{try{localStorage.setItem(S_,q?"1":"")}catch{}},[q]),N.useEffect(()=>{if(!t)return;let de=!1;return Promise.all([T_(t),tn("/api/config",t).then(Ee=>Ee.json())]).then(([Ee,Ue])=>{de||(mt({deviceDefault:Ee.deviceName||"",localNodeId:Ee.nodeId||"",localNameDefault:Ee.localName||""}),be(!!Ue.readonlyDefault),(Ee.firstRun===!0&&!Ue.readonlyDefault||s)&&it(!0))}).catch(()=>{}),()=>{de=!0}},[t,s]);const Be=N.useCallback(async()=>{try{const Ee=await(await tn("/api/sessions",t)).json();Ee.error||k(Ee.sessions||[])}catch{}try{const de=await zr(t);B(de.available?de.cells||[]:[]),Y(de.available?de.capabilities||[]:[])}catch{B([]),Y([])}},[t]);N.useEffect(()=>{if(!p)return;Be();const de=setInterval(Be,4e3);return()=>clearInterval(de)},[p,Be]),N.useEffect(()=>{let de=!1;return tn("/api/config",t).then(Ee=>Ee.json()).then(Ee=>{de||HN(Ee.version,Ee.uiVersion,"0.8.38")}).catch(()=>{}),()=>{de=!0}},[t]);const $e=new Set([...C.map(de=>de.name),...j.flatMap(de=>de.sessions.map(Ee=>Ee.key))]),he=vi(K),V=de=>A(Ee=>{const Ue=cw(de,T.localNodeId,R)||de,_t=Q_(Ee,Ue);return _t===Ee&&vi(Ee).length>=9&&T.setError(g("grid-full")),_t}),ne=async(de,Ee=[])=>{try{await Nh(t,de,Ee)}catch{return}const Ue=Ee.length?`${Ee.join("/")}:${de}`:de;A(_t=>xl(_t,Ue)),Be()},z=async(de,Ee,Ue=[])=>{try{await D_(t,de,Ee,Ue)}catch{return}Be()},se=async(de,Ee,Ue=[])=>{await P_(t,{cell:de,enabled:!!Ee},Ue),Be()},me=async de=>{if(!te)return;const{cell:Ee}=te,Ue=Array.isArray(te.route)?te.route:[];de.action==="up"?await Ch(t,{cell:Ee,boot:!!de.boot,...de.engine?{engine:de.engine}:{},...de.model!==void 0?{model:de.model}:{},...de.permissionPolicy?{permissionPolicy:de.permissionPolicy}:{}},Ue):await vl(t,{cell:Ee,boot:!!de.boot},Ue);const _t=de.action==="up"?!!de.boot:de.boot?!1:!!te.boot;O({id:++L.current,cell:Ee,route:Ue,enabled:_t}),Be()},ke=N.useCallback(de=>{O(Ee=>(Ee==null?void 0:Ee.id)===de?null:Ee)},[]),Ne=async de=>{if(!(!(de!=null&&de.direct)||$)){X(!0);try{await jh(t,de.name,de.tunnelStatus==="up"?"down":"up")}finally{X(!1)}}},we=async(de,Ee)=>{const Ue=String(Ee||"").trim();return!(de!=null&&de.direct)||!ks(Ue)?!1:(await I_(t,de.name,Ue),!0)},Re=de=>{const Ee=H.find(Ue=>Ue.id===de);if(!Ee)return!1;try{const Ue=window.open(Vu(Ee,t),"_blank");return Ue&&(Ue.opener=null),!!Ue}catch{return!1}},Je=async de=>{if(!de||de===_)return;const Ee=await T.select(de),Ue=T.records.find(_t=>_t.id===de);b(de),A(Ee),U(null),F(null);try{history.replaceState(null,"",Vu(Ue||de,null))}catch{}},Tt=async(de,Ee)=>{const Ue=await T.add(de,Ee);await Je(Ue.id)},Me=async(de,Ee)=>{const Ue=await T.rename(de,Ee);if(de===_){b(Ue.id),A(ph(Ue.layout,T.localNodeId,R)),U(null),F(null);try{history.replaceState(null,"",Vu(Ue,null))}catch{}}},pn=async de=>{await T.remove(de),de===_&&await Je(T.localMainId)},bt=async(de,Ee)=>{!Ee||Ee===_||(await T.addTileTo(Ee,de),A(Ue=>xl(Ue,de)))};if(!t)return c.jsxs("div",{className:"nc-auth",children:[c.jsx("p",{children:g("auth-prompt")}),c.jsx("input",{onChange:de=>n(de.target.value.trim()),placeholder:"token"}),c.jsxs("label",{children:[c.jsx("input",{type:"checkbox",checked:u,onChange:de=>h(de.target.checked)})," ",g("remember-device")]}),c.jsx("button",{onClick:()=>{(u?localStorage:sessionStorage).setItem("nc_token",t)},children:"ok"})]});const Ke=c.jsxs(c.Fragment,{children:[Ie&&c.jsx(jN,{token:t,initialTab:ze,initialLocation:rt,startNewCell:Ct,onClose:()=>{et(!1),Ge(!1),ut("")}}),vt&&c.jsx(LN,{token:t,initialPair:s,...lt,onPairDone:a,onDone:()=>it(!1)}),c.jsx(BN,{token:t})]});if(!p)return S?c.jsxs(c.Fragment,{children:[c.jsx(x_,{session:S.session,node:S.node,ownerId:S.ownerId,cellName:S.cellName,token:t,readonly:le,onBack:()=>w(null)}),Ke]}):c.jsxs(c.Fragment,{children:[c.jsx(p1,{onPick:x,token:t,onSettings:ct}),Ke]});const $t=y||!ge;return c.jsxs("div",{className:"nc-workspace",children:[$t&&c.jsx(pE,{sessions:C,cells:P,activeSessions:he,nodeGroups:j,fleetCapabilities:M,bootSettlement:ie,onBootSettlementApplied:ke,localNodeId:T.localNodeId,onPick:I,onAddTile:V,onPower:D,onBoot:se,onBootError:de=>T.setError(String((de==null?void 0:de.message)||de)),onNodePower:Ne,onNodeRename:we,onKill:ne,onVisibility:z,onNew:()=>ct("fleet",!0),onSettings:ct,width:ae,collapsed:q,onResize:ue,onToggleCollapse:()=>fe(de=>!de)}),c.jsxs("div",{className:"nc-workspace-main",children:[c.jsx(GE,{decks:H,currentDeck:_,onCreate:Tt,onRename:Me,onDelete:pn,onReorder:T.reorder,onOpenWindow:Re,onNavigate:Je,saveState:T.saveState,error:T.error,sidebarVisible:$t,onToggleSidebar:y?null:()=>Q(de=>!de)}),c.jsx(SE,{layout:K,onLayoutChange:A,token:t,readonly:le,sessionsAlive:$e,focusSession:ee,onFocus:U,onOpenSingle:I,decks:H,currentDeck:_,onSendToDeck:bt,cells:P,nodeGroups:j})]}),Z&&c.jsx("div",{className:"nc-single-overlay",children:c.jsx(x_,{session:Z.session,node:Z.node,ownerId:Z.ownerId,cellName:Xh({session:Z.session,node:Z.node,ownerId:Z.ownerId,cells:P,nodeGroups:j}),token:t,readonly:le,onBack:()=>F(null)})}),te&&c.jsx(yl,{cell:te,token:t,route:Array.isArray(te.route)?te.route:[],onConfirm:me,onClose:()=>D(null)}),Ke]})}function eR(){zn();const e=N.useSyncExternalStore($N,w_,w_);if(!e.needed)return null;const t=e.kind==="install"?g("install-version-mismatch").replace("{v}",e.version):g("update-available").replace("{v}",e.version).replace(" "," ").trim();return c.jsxs("div",{className:"nc-update",role:"status","aria-live":"polite",children:[c.jsx("span",{className:"nc-update-msg",children:t}),e.kind==="reload"&&c.jsx("button",{className:"nc-update-btn",onClick:KN,children:g("reload")})]})}UN();Xb.createRoot(document.getElementById("root")).render(c.jsxs(Wb.StrictMode,{children:[c.jsx(ZN,{}),c.jsx(eR,{})]}));
|
|
93
|
+
`],{type:"application/json"}),H=URL.createObjectURL(T),te=document.createElement("a");te.href=H,te.download="nexuscrew-diagnostics.json",te.click(),URL.revokeObjectURL(H)}catch{y(g("diagnostics-export-failed"))}};return c.jsxs("div",{className:"nc-set-tab nc-diagnostics",children:[c.jsxs("label",{className:"nc-field",children:[g("diagnostics-target"),c.jsx("select",{value:u.key,onChange:T=>a(T.target.value),children:s.map(T=>c.jsxs("option",{value:T.key,children:[T.label,T.status!=="up"?` · ${T.status}`:""]},T.key))})]}),c.jsxs("div",{className:"nc-set-form nc-diag-controls",children:[c.jsx("div",{className:"nc-sheet-label",children:g("diagnostics-verbose")}),c.jsxs("div",{className:"nc-set-row",children:[c.jsx("select",{"aria-label":g("diagnostics-duration"),value:k,onChange:T=>P(Number(T.target.value)),disabled:n,children:[300,900,1800,3600].map(T=>c.jsxs("option",{value:T,children:[T/60," min"]},T))}),c.jsx("button",{type:"button",className:"nc-btn primary",disabled:n||(h==null?void 0:h.verbose)===!0,onClick:()=>I(()=>ig(e,!0,k,u.route)),children:g("enable")}),c.jsx("button",{type:"button",className:"nc-btn ghost",disabled:n||(h==null?void 0:h.verbose)!==!0,onClick:()=>I(()=>ig(e,!1,k,u.route)),children:g("stop")})]}),c.jsx("small",{className:"nc-set-hint",children:h!=null&&h.verbose?g("diagnostics-expires").replace("{time}",new Date(h.expiresAt).toLocaleTimeString()):g("diagnostics-off")})]}),c.jsxs("div",{className:"nc-diag-filters",children:[c.jsxs("select",{"aria-label":g("diagnostics-level"),value:B,onChange:T=>M(T.target.value),children:[c.jsx("option",{value:"all",children:g("diagnostics-all-levels")}),["debug","info","warn","error"].map(T=>c.jsx("option",{value:T,children:T},T))]}),c.jsx("input",{"aria-label":g("diagnostics-component"),placeholder:g("diagnostics-component"),value:Y,onChange:T=>K(T.target.value)})]}),c.jsxs("div",{className:"nc-set-row",children:[c.jsxs("label",{className:"nc-check",children:[c.jsx("input",{type:"checkbox",checked:S,onChange:T=>w(T.target.checked)})," ",g("diagnostics-pause")]}),c.jsxs("label",{className:"nc-check",children:[c.jsx("input",{type:"checkbox",checked:x,onChange:T=>C(T.target.checked)})," ",g("diagnostics-autoscroll")]})]}),c.jsx("pre",{ref:ee,className:"nc-diag-log","aria-label":g("diagnostics-log"),children:F||g("diagnostics-empty")}),c.jsxs("div",{className:"nc-set-row",children:[c.jsx("button",{type:"button",className:"nc-btn ghost",onClick:j,children:g("copy")}),c.jsx("button",{type:"button",className:"nc-btn ghost",onClick:R,children:g("diagnostics-export")}),c.jsx("button",{type:"button",className:"nc-btn danger",disabled:n,onClick:()=>{window.confirm(g("diagnostics-clear-confirm"))&&I(async()=>{const T=await S0(e,u.route);return A.current=0,_([]),T})},children:g("diagnostics-clear")})]}),b&&c.jsx("div",{className:"nc-err",children:b})]})}function PN({token:e,settings:t,readonly:n,refresh:s}){const[o,a]=N.useState(null),[u,h]=N.useState(null),[p,f]=N.useState(!1),[_,b]=N.useState(!1),[y,S]=N.useState(null),[w,x]=N.useState(!0);N.useEffect(()=>{S(t&&t.update||null),x(!t||t.autoUpdate!==!1)},[t]);const C=async()=>{a(null),h(null),b(!0);try{const A=await c0(e);h(A.note||"ok"),f(!1)}catch(A){a(String(A.message||A))}b(!1)},k=async()=>{a(null),h(null),b(!0);try{const A=await g0(e);h(`${A.note||"ok"}${A.target?` (${A.target})`:""}`)}catch(A){a(String(A.message||A))}b(!1)},P=async A=>{a(null),h(null),b(!0);try{await A_(e,{autoUpdate:A}),x(A),s&&await s()}catch(ee){a(String(ee.message||ee))}b(!1)},B=async()=>{a(null),h(null),b(!0);try{S(await v0(e))}catch(A){a(String(A.message||A))}b(!1)},M=async()=>{a(null),h(null),b(!0);try{const A=await _0(e);S(A),h(g("npm-update-restarting"))}catch(A){a(String(A.message||A))}b(!1)},Y=()=>{window.confirm(g("composer-clear-confirm"))&&(a(null),lE()?(window.dispatchEvent(new Event(dh)),h(g("composer-clear-done"))):a(g("composer-clear-failed")))},K=t&&t.service;return c.jsxs("div",{className:"nc-set-tab",children:[t&&c.jsxs("div",{className:"nc-set-info",children:["v",t.version," · ",t.platform," · :",t.port,c.jsx("br",{}),K&&K.installed?g("service-installed"):g("service-missing"),K&&K.installed?` · ${K.active?g("service-active"):g("service-inactive")}`:"",K?` · boot ${K.boot?"on":"off"}`:""]}),c.jsxs("div",{className:"nc-set-row",children:[c.jsx("button",{type:"button",className:"nc-btn ghost",disabled:n||_,title:n?g("settings-readonly"):"",onClick:()=>{a(null),h(null),f(!0)},children:g("token-rotate")}),c.jsx("button",{type:"button",className:"nc-btn ghost",disabled:n||_,title:n?g("settings-readonly"):"",onClick:k,children:g("service-regenerate")})]}),c.jsxs("div",{className:"nc-set-form nc-update-settings",children:[c.jsxs("label",{className:"nc-check",children:[c.jsx("input",{type:"checkbox",checked:w,disabled:n||_||y&&!y.supported,onChange:A=>P(A.target.checked)}),c.jsxs("span",{children:[c.jsx("b",{children:g("npm-auto-update")}),c.jsx("small",{children:g("npm-auto-update-help")})]})]}),y&&c.jsxs("div",{className:"nc-set-info",children:[g("npm-update-current")," v",y.current,y.latest?` · ${g("npm-update-latest")} v${y.latest}`:""," · ",g(`npm-update-${y.supported?y.phase:"unsupported"}`)]}),c.jsxs("div",{className:"nc-set-row",children:[c.jsx("button",{type:"button",className:"nc-btn ghost",disabled:n||_||!y||!y.supported,onClick:B,children:g("npm-update-check")}),y&&y.available&&c.jsx("button",{type:"button",className:"nc-btn primary",disabled:n||_||y.phase==="installing",onClick:M,children:g("npm-update-install")})]}),y&&y.lastError&&c.jsx("div",{className:"nc-err",children:y.lastError})]}),c.jsx(CN,{token:e,readonly:n}),c.jsx(EN,{}),c.jsxs("div",{className:"nc-set-form",children:[c.jsx("div",{className:"nc-sheet-label",children:g("composer-clear-data")}),c.jsx("small",{className:"nc-set-hint",children:g("composer-clear-data-help")}),c.jsx("div",{className:"nc-set-row",children:c.jsx("button",{type:"button",className:"nc-btn ghost",onClick:Y,children:g("composer-clear-data")})})]}),p&&c.jsxs("div",{className:"nc-set-confirm",children:[c.jsx("div",{children:g("token-rotate-explain")}),c.jsxs("div",{className:"nc-sheet-actions",children:[c.jsx("button",{type:"button",className:"nc-btn ghost",disabled:_,onClick:()=>f(!1),children:g("cancel")}),c.jsx("button",{type:"button",className:"nc-btn primary",disabled:_,onClick:C,children:g("confirm")})]})]}),u&&c.jsx("div",{className:"nc-set-note",children:u}),o&&c.jsx("div",{className:"nc-err",children:o})]})}function jN({token:e,onClose:t,initialTab:n="nodes",initialLocation:s="",startNewCell:o=!1}){zn();const[a,u]=N.useState(n),[h,p]=N.useState(null),[f,_]=N.useState([]),[b,y]=N.useState(!1),[S,w]=N.useState(null),[x,C]=N.useState(0),k=Dh(e,!0,x),P=N.useCallback(async()=>{try{const B=await T_(e);p(B),w(null)}catch(B){w(String(B.message||B))}try{const B=await a0(e);_(B.peers||[])}catch(B){w(String(B.message||B))}},[e]);return N.useEffect(()=>{P();const B=setInterval(P,5e3);return()=>clearInterval(B)},[P]),N.useEffect(()=>{let B=!1;return tn("/api/config",e).then(M=>M.json()).then(M=>{B||y(!!M.readonlyDefault)}).catch(()=>{}),()=>{B=!0}},[e]),c.jsx("div",{className:"nc-set-overlay",onClick:t,children:c.jsxs("div",{className:"nc-set-panel",onClick:B=>B.stopPropagation(),children:[c.jsxs("div",{className:"nc-set-head",children:[c.jsx(nt,{name:"gear",size:18}),c.jsx("b",{children:g("settings")}),c.jsx("button",{type:"button",className:"nc-set-close",onClick:t,title:g("close"),children:c.jsx(nt,{name:"x",size:18})})]}),b&&c.jsx("div",{className:"nc-set-readonly",children:g("settings-readonly")}),S&&c.jsx("div",{className:"nc-err",children:S}),c.jsx("div",{className:"nc-set-tabs",children:["nodes","fleet","input","diagnostics","system"].map(B=>c.jsx("button",{type:"button",className:`nc-set-tabbtn${a===B?" on":""}`,onClick:()=>u(B),children:g(`tab-${B}`)},B))}),c.jsxs("div",{className:"nc-set-body",children:[a==="nodes"&&c.jsx(xN,{token:e,nodes:f,roster:k,settings:h,readonly:b,refresh:P,refreshAliases:()=>C(B=>B+1)}),a==="fleet"&&c.jsx(sN,{token:e,readonly:b,startNewCell:o,initialLocation:s,targets:k.map(B=>({route:B.route,label:B.label||B.name,status:B.status}))}),a==="input"&&c.jsx(NN,{}),a==="diagnostics"&&c.jsx(RN,{token:e,roster:k,readonly:b}),a==="system"&&c.jsx(PN,{token:e,settings:h,readonly:b,refresh:P})]})]})})}function LN({token:e,initialPair:t,deviceDefault:n="",localNodeId:s="",localNameDefault:o="",onPairDone:a,onDone:u}){zn();const[h,p]=N.useState(t?"pair":"welcome"),[f,_]=N.useState(!1),[b,y]=N.useState(null),S=async()=>{_(!0),y(null);try{await A_(e,{wizardDone:!0}),a&&a(),u()}catch(w){y(String(w.message||w)),_(!1)}};return c.jsx("div",{className:"nc-wiz-overlay",children:c.jsxs("div",{className:"nc-wiz",children:[c.jsxs("div",{className:"nc-wiz-head",children:[c.jsx("b",{children:g("wizard-title")}),c.jsx("small",{children:g("hydra-simple")})]}),h==="welcome"&&c.jsxs("div",{className:"nc-wiz-body",children:[c.jsx("div",{className:"nc-wiz-done",children:g("local-ready")}),c.jsxs("div",{className:"nc-sheet-actions",children:[c.jsx("button",{className:"nc-btn ghost",disabled:f,onClick:S,children:g("local-only")}),c.jsx("button",{className:"nc-btn primary",disabled:f,onClick:()=>p("pair"),children:g("add-node")})]})]}),h==="pair"&&c.jsxs("div",{className:"nc-wiz-body",children:[c.jsx(Nw,{token:e,initial:t||"",autoStart:!!t,deviceDefault:n,localNodeId:s,localNameDefault:o,onBusyChange:_,onSuccess:async()=>{a&&a(),p("done")}}),c.jsx("div",{className:"nc-sheet-actions",children:c.jsx("button",{className:"nc-btn ghost",disabled:f,onClick:()=>{a&&a(),p("welcome")},children:g("back")})})]}),h==="done"&&c.jsxs("div",{className:"nc-wiz-body",children:[c.jsx("div",{className:"nc-wiz-done",children:g("node-connected")}),c.jsx("div",{className:"nc-sheet-actions",children:c.jsx("button",{className:"nc-btn primary",disabled:f,onClick:S,children:g("finish")})})]}),b&&c.jsx("div",{className:"nc-err",children:b})]})})}function DN(e,t){if(typeof EventSource>"u"||!e)return()=>{};const n=new EventSource(`/api/events?token=${encodeURIComponent(e)}`);return n.onmessage=s=>{try{const o=JSON.parse(s.data);o&&typeof o=="object"&&typeof o.type=="string"&&t(o)}catch{}},()=>{try{n.close()}catch{}}}const TN=6e3,MN=12e3;function AN({n:e,onClose:t}){return c.jsxs("div",{className:`nc-ntf-toast${e.urgency==="high"?" high":""}`,role:"status","aria-live":"polite",children:[c.jsxs("div",{className:"nc-ntf-toast-txt",children:[c.jsx("b",{children:e.title}),e.body&&c.jsx("small",{children:e.body}),e.session&&c.jsx("span",{className:"nc-ntf-from",children:e.session})]}),c.jsx("button",{type:"button",className:"nc-ntf-x",onClick:t,title:g("close"),children:c.jsx(nt,{name:"x",size:14})})]})}function IN({ask:e,token:t,onAnswered:n}){const[s,o]=N.useState(""),[a,u]=N.useState(!1),[h,p]=N.useState(null),f=async _=>{const b=String(_||"").trim();if(!(!b||a)){p(null),u(!0);try{await k0(t,e.id,b),n(e.id)}catch(y){p(String(y.message||y))}u(!1)}};return c.jsxs("div",{className:"nc-ask-card",children:[c.jsxs("div",{className:"nc-ask-head",children:[c.jsx("span",{className:"nc-ntf-from",children:e.session}),c.jsxs("code",{className:"nc-ask-id",children:["#",e.id]})]}),c.jsx("div",{className:"nc-ask-q",children:e.question}),Array.isArray(e.options)&&e.options.length>0&&c.jsx("div",{className:"nc-ask-opts",children:e.options.map(_=>c.jsx("button",{type:"button",className:"nc-btn ghost",disabled:a,onClick:()=>f(_),children:_},_))}),c.jsxs("div",{className:"nc-ask-reply",children:[c.jsx("textarea",{rows:2,placeholder:g("ask-reply-ph"),value:s,disabled:a,onChange:_=>o(_.target.value)}),c.jsx("button",{type:"button",className:"nc-btn primary",disabled:a||!s.trim(),onClick:()=>f(s),children:g("send")})]}),h&&c.jsx("div",{className:"nc-err",children:h})]})}function BN({token:e}){const[t]=zn(),[n]=Hw(),[s,o]=N.useState([]),[a,u]=N.useState([]),[h,p]=N.useState(()=>{try{return/(?:^|[#&])ask=/.test(location.hash)}catch{return!1}}),f=N.useRef(0),_=N.useRef(null);_.current||(_.current=SN());const b=N.useRef({enabled:n,lang:t});b.current={enabled:n,lang:t};const y=N.useCallback(x=>{o(C=>C.filter(k=>k.key!==x))},[]),S=N.useCallback(x=>{const C=`t${f.current+=1}`;o(P=>[...P.slice(-3),{...x,key:C}]),setTimeout(()=>y(C),x.urgency==="high"?MN:TN);const k=b.current;if(k.enabled)try{_.current.enqueue(x,gN(x,k.lang))}catch{}},[y]);N.useEffect(()=>{n||_.current.stop()},[n]),N.useEffect(()=>{const x=()=>{(document.visibilityState!=="visible"||!document.hasFocus())&&_.current.stop()},C=()=>_.current.stop();return document.addEventListener("visibilitychange",x),window.addEventListener("blur",x),window.addEventListener(vh,C),()=>{document.removeEventListener("visibilitychange",x),window.removeEventListener("blur",x),window.removeEventListener(vh,C),typeof _.current.dispose=="function"?_.current.dispose():_.current.stop()}},[]),N.useEffect(()=>{if(!e)return;let x=!1;b0(e).then(k=>{x||u(k.asks||[])}).catch(()=>{});const C=DN(e,k=>{k.type==="notify"?S(k):k.type==="ask"&&k.ask&&k.ask.id?u(P=>P.some(B=>B.id===k.ask.id)?P:[...P,k.ask]):k.type==="ask-answered"&&k.id&&u(P=>P.filter(B=>B.id!==k.id))});return()=>{x=!0,C()}},[e,S]);const w=x=>u(C=>C.filter(k=>k.id!==x));return c.jsxs(c.Fragment,{children:[s.length>0&&c.jsx("div",{className:"nc-ntf-toasts",children:s.map(x=>c.jsx(AN,{n:x,onClose:()=>y(x.key)},x.key))}),a.length>0&&!h&&c.jsxs("button",{type:"button",className:"nc-ask-badge",onClick:()=>p(!0),title:g("asks-title"),children:["? ",c.jsx("span",{className:"nc-ask-count",children:a.length})]}),a.length>0&&h&&c.jsxs("div",{className:"nc-ask-panel",children:[c.jsxs("div",{className:"nc-ask-panel-head",children:[c.jsx("b",{children:g("asks-title")}),c.jsx("span",{className:"nc-ask-count",children:a.length}),c.jsx("button",{type:"button",className:"nc-ntf-x",onClick:()=>p(!1),title:g("close"),children:c.jsx(nt,{name:"x",size:16})})]}),c.jsx("div",{className:"nc-ask-panel-body",children:a.map(x=>c.jsx(IN,{ask:x,token:e,onAnswered:w},x.id))})]})]})}const wd=e=>vi(Ar(e)).length===0,Sd=e=>Array.isArray(e)?e.join("/"):"";function ON(e){const t=new Set,n=[];for(const s of Array.isArray(e)?e:[])!s||!Bn.test(String(s.instanceId||""))||!Array.isArray(s.route)||!s.route.length||t.has(s.instanceId)||(t.add(s.instanceId),n.push({instanceId:s.instanceId,route:[...s.route],label:String(s.label||s.name||s.route.join(" › ")),status:s.status||"offline"}));return n.sort((s,o)=>s.label.localeCompare(o.label))}function So(e){return{instanceId:e.ownerId,route:e.ownerRoute||[],label:e.ownerLabel,status:e.available===!1?"offline":"up"}}function Rr(e,t,n,s=!1,o=!0){const a=t.instanceId;return{...e,id:ys(s?null:a,e.name),ownerId:a,ownerRoute:s?[]:[...t.route],ownerLabel:s?"Local":t.label,local:s,available:o,ownerTopology:Array.isArray(n)?n:[],layout:fh(e.layout,a,n)}}function zN(e,t,n,s,o=[]){const[a,u]=N.useState([]),[h,p]=N.useState(!1),[f,_]=N.useState("idle"),[b,y]=N.useState(""),[S,w]=N.useState(""),x=N.useRef([]),C=N.useRef([]),k=N.useRef(""),P=N.useRef(t),B=N.useRef(n),M=N.useRef(!1),Y=N.useRef(!0),K=N.useRef(""),A=N.useMemo(()=>ON(o),[o]),ee=A.map(O=>`${O.instanceId}:${Sd(O.route)}:${O.status}:${O.label}`).join("|");C.current=A,B.current=n,P.current=t,x.current=a;const U=N.useCallback(O=>ph(O.layout,k.current,C.current),[]),Z=N.useCallback((O,L=!0,$=P.current)=>{const X=Pv(O,rl()),ae=x.current.some(ge=>ge.id===$);x.current=X,u(X);const ue=X.find(ge=>ge.id===$);if(L&&ue){Y.current=!0;const ge=U(ue);s(ge),ue.local&&DE(ue.name,ge)}else ae&&!ue&&(Y.current=!0,s(_s()),y("deck non più condiviso dal nodo owner"));RE(X.filter(ge=>ge.local).map(ge=>ge.name))},[s,U]),F=N.useCallback(async O=>{let L=await Ga(e);const $=L.decks.find(X=>X.name==="main");if(L.decks.length===1&&$&&$.revision===0&&wd($.layout)){const X=NE(),ae=Ar(mh("main")||_s());if(!wd(ae)){const ue=fh(ae,O,[]);L.decks[0]=await Xa(e,"main",ue,0,[])}for(const ue of X.filter(ge=>ge!=="main"))try{let ge=await rg(e,ue,[]);const Q=Ar(mh(ue)||_s());wd(Q)||(ge=await Xa(e,ue,fh(Q,O,[]),ge.revision,[]))}catch{}L=await Ga(e)}return L},[e]),I=N.useCallback(async({migrate:O=!1}={})=>{const L=await Ph(e,[]),$=Bn.test(String(L.instanceId||""))?L.instanceId:"";if(!$)throw new Error("instanceId locale non disponibile");k.current=$,w($);const[X,ae]=await Promise.all([O?F($):Ga(e),Zm(e,[]).catch(()=>({nodes:[]}))]),ue={instanceId:$,route:[],label:"Local"},ge=X.decks.map(q=>Rr(q,ue,ae.nodes,!0,!0)),Q=x.current;return await Promise.all(C.current.map(async q=>{if(q.status!=="up"){ge.push(...Q.filter(fe=>!fe.local&&fe.ownerId===q.instanceId).map(fe=>({...fe,ownerRoute:[...q.route],ownerLabel:q.label,available:!1})));return}try{const[fe,Ie]=await Promise.all([Ga(e,q.route),Zm(e,q.route).catch(()=>({nodes:[]}))]);ge.push(...fe.decks.map(et=>Rr(et,q,Ie.nodes,!1,!0)))}catch{ge.push(...Q.filter(Ie=>!Ie.local&&Ie.ownerId===q.instanceId).map(Ie=>({...Ie,ownerRoute:[...q.route],ownerLabel:q.label,available:!1})))}})),ge.sort((q,fe)=>q.local===fe.local?q.ownerLabel.localeCompare(fe.ownerLabel)||(q.name==="main"?-1:fe.name==="main"?1:q.name.localeCompare(fe.name)):q.local?-1:1),ge},[e,F,ee]);N.useEffect(()=>{if(!e)return;let O=!1;const L=K.current!==e;return K.current=e,I({migrate:L}).then($=>{if(O)return;const X=x.current.find(ge=>ge.id===P.current),ae=$.find(ge=>ge.id===P.current),ue=ae&&(!X||ae.revision>X.revision||X.available!==ae.available||Sd(X.ownerRoute)!==Sd(ae.ownerRoute));Z($,L||!!ue&&!M.current),p(!0),ae&&y("")}).catch($=>{O||(p(!0),y(String($.message||$)))}),()=>{O=!0}},[Z,I,ee,e]);const j=N.useCallback(async(O=P.current)=>{if(!h||!M.current)return!0;const L=x.current.find($=>$.id===O);if(!L)return y(`deck inesistente: ${O}`),!1;if(L.available===!1)return y(`nodo owner offline: ${L.ownerLabel}`),!1;_("saving");try{const $=Nv(Ar(B.current),L.ownerId,L.ownerTopology),X=await Xa(e,L.name,$,L.revision,L.ownerRoute),ae=Rr(X,So(L),L.ownerTopology,L.local,!0);return Z(x.current.map(ue=>ue.id===O?ae:ue),!1),M.current=!1,_("saved"),y(""),setTimeout(()=>_("idle"),1500),!0}catch($){if(_("error"),y(String($.message||$)),$.status===409&&$.data&&$.data.current){const X=x.current.find(ue=>ue.id===O),ae=Rr($.data.current,So(X),X.ownerTopology,X.local,!0);Z(x.current.map(ue=>ue.id===O?ae:ue),!1)}return!1}},[h,e,Z]);return N.useEffect(()=>{if(!h)return;if(Y.current){Y.current=!1;return}M.current=!0,_("saving");const O=setTimeout(j,650);return()=>clearTimeout(O)},[n,h,j]),N.useEffect(()=>{if(!h)return;const O=setInterval(async()=>{try{const L=await I(),$=x.current.find(ue=>ue.id===P.current),X=L.find(ue=>ue.id===P.current),ae=X&&(!$||X.revision>$.revision||$.available!==X.available);Z(L,ae&&!M.current)}catch{}},5e3);return()=>clearInterval(O)},[h,I,Z]),{decks:a,records:a,localNodeId:S,ready:h,saveState:f,error:b,setError:y,saveNow:j,select:async O=>{if(M.current&&!await j(P.current))throw new Error("salvataggio del deck corrente fallito: cambio annullato");const L=x.current.find($=>$.id===O);if(!L)throw new Error(`deck inesistente: ${O}`);return M.current=!1,Y.current=!0,U(L)},add:async(O,L=null)=>{const $=L===mi?x.current.find(ue=>ue.local):L?x.current.find(ue=>ue.ownerId===L):null;if(!$||$.available===!1)throw new Error("nodo owner non disponibile");const X=await rg(e,O,$.ownerRoute),ae=Rr(X,So($),$.ownerTopology,$.local,!0);return Z([...x.current,ae],!1),ae},rename:async(O,L)=>{const $=x.current.find(Q=>Q.id===O);if(!$)throw new Error("deck inesistente");if(O===P.current&&M.current&&!await j(O))throw new Error(`salvataggio di "${$.name}" fallito: rinomina annullata`);const X=x.current.find(Q=>Q.id===O);if(!X)throw new Error("deck inesistente");const ae=await x0(e,X.name,L,X.revision,X.ownerRoute),ue=Rr(ae,So(X),X.ownerTopology,X.local,!0),ge=X.local?mi:X.ownerId;return Yu(jE(rl(),ge,O,ue.id)),Z(x.current.map(Q=>Q.id===O?ue:Q),!1),ue},remove:async O=>{const L=x.current.find(X=>X.id===O);if(!L)throw new Error("deck inesistente");O===P.current&&(M.current=!1),await C0(e,L.name,L.revision,L.ownerRoute);const $=L.local?mi:L.ownerId;Yu(LE(rl(),$,O)),Z(x.current.filter(X=>X.id!==O),!1)},reorder:(O,L)=>{const $=x.current.find(q=>q.id===O),X=x.current.find(q=>q.id===L);if(!$||!X)return!1;const ae=$.local?mi:$.ownerId,ue=X.local?mi:X.ownerId;if(ae!==ue)return!1;const ge=x.current.filter(q=>(q.local?mi:q.ownerId)===ae).map(q=>q.id),Q=Yu(PE(rl(),ae,O,L,ge));return Z(Pv(x.current,Q),!1),!0},addTileTo:async(O,L)=>{const $=x.current.find(q=>q.id===O);if(!$)throw new Error("deck inesistente");if($.available===!1)throw new Error(`nodo owner offline: ${$.ownerLabel}`);const X=cw(L,k.current,C.current);if(!X)throw new Error("riferimento sessione non valido");const ae=U($),ue=Nv(Q_(ae,X),$.ownerId,$.ownerTopology),ge=await Xa(e,$.name,ue,$.revision,$.ownerRoute),Q=Rr(ge,So($),$.ownerTopology,$.local,!0);return Z(x.current.map(q=>q.id===O?Q:q),!1),Q},localMainId:ys(null,"main"),parseDeckId:Fl}}const FN="/sw.js",yh="nc-sw-update";let wh=null,Sh=!1,bh=null,Ww=Object.freeze({needed:!1,kind:null,version:""}),Uw=!1;function Kw(){typeof window<"u"&&window.dispatchEvent(new Event(yh))}function qw(){const e=bh||(Sh?{kind:"reload",version:""}:null);Ww=Object.freeze({needed:!!e,kind:(e==null?void 0:e.kind)||null,version:(e==null?void 0:e.version)||""})}function w_(){return Ww}function $N(e){return typeof window>"u"?()=>{}:(window.addEventListener(yh,e),()=>window.removeEventListener(yh,e))}function df(e){Sh!==e&&(Sh=e,qw(),Kw())}function HN(e,t,n){let s=null;e&&t&&e!==t?s={kind:"install",version:e}:t&&n&&t!==n&&(s={kind:"reload",version:t});const o=JSON.stringify(s)===JSON.stringify(bh);bh=s,qw(),o||Kw()}function WN(e){e.addEventListener("statechange",()=>{e.state==="installed"&&navigator.serviceWorker.controller&&df(!0)})}function UN(){typeof navigator>"u"||!("serviceWorker"in navigator)||(navigator.serviceWorker.addEventListener("controllerchange",()=>{Uw&&location.reload()}),navigator.serviceWorker.register(FN).then(e=>{wh=e,e.waiting&&df(!0),e.addEventListener("updatefound",()=>{const t=e.installing;t&&WN(t)}),setInterval(()=>{e.update().catch(()=>{})},3600*1e3)}).catch(()=>{}))}function KN(){Uw=!0,df(!1);const e=wh&&wh.waiting;e?(e.postMessage({type:"SKIP_WAITING"}),setTimeout(()=>location.reload(),4e3)):location.reload()}function qN({hash:e="",origin:t="",pathname:n="",search:s=""}={}){const o=String(e||"").replace(/^#/,""),a=`${n||""}${s||""}`;if(!o)return{token:"",pair:"",nextUrl:a};const u=new URLSearchParams(o),h=u.get("token")||"",p=u.get("pair")||"",f=p?`${t||""}${n||""}#pair=${p}`:"";return{token:h,pair:f,nextUrl:a}}const Vw=9,Yw=24,Gw="nc_side_w",S_="nc_side_min",VN=240,b_="(min-width:1024px) and (pointer:fine)";function YN(){const e=Number(localStorage.getItem(Gw));return e>=180&&e<=480?e:VN}function GN(){const e=Number(localStorage.getItem("nc_fontsize"));return e>=Vw&&e<=Yw?e:13}function XN(){const e={token:"",pair:""};try{const{token:t,pair:n,nextUrl:s}=qN({hash:location.hash,origin:location.origin,pathname:location.pathname,search:location.search});if(t){e.token=t;try{localStorage.setItem("nc_token",t)}catch{}}if(n){e.pair=n;try{sessionStorage.setItem("nc_pair",n)}catch{}}if(location.hash)try{history.replaceState(null,"",s)}catch{}}catch{}if(e.token||(e.token=sessionStorage.getItem("nc_token")||localStorage.getItem("nc_token")||""),!e.pair){const t=sessionStorage.getItem("nc_pair");t&&(e.pair=t)}return e}function JN(e){try{return Ar(mh(e))}catch{return _s()}}function k_(e){if(!e)return"";const t=Math.floor(Date.now()/1e3)-e;return t<0||t<60?"ora":t<3600?`${Math.floor(t/60)}m`:t<86400?`${Math.floor(t/3600)}h`:`${Math.floor(t/86400)}g`}function QN(){const[e,t]=N.useState(()=>window.matchMedia(b_).matches);return N.useEffect(()=>{const n=window.matchMedia(b_),s=o=>t(o.matches);return n.addEventListener("change",s),()=>n.removeEventListener("change",s)},[]),e}function x_({session:e,node:t,ownerId:n,cellName:s,token:o,readonly:a=!1,onBack:u}){zn();const[h]=Gh(),[p,f]=N.useState(!1),[_,b]=N.useState(()=>window.matchMedia("(pointer: coarse)").matches),[y,S]=N.useState(null),[w,x]=N.useState(GN),[C,k]=N.useState(s||e),[P,B]=N.useState(""),M=R=>x(T=>{const H=Math.max(Vw,Math.min(Yw,T+R));return localStorage.setItem("nc_fontsize",String(H)),H}),Y=N.useRef(()=>{}),K=N.useRef(()=>!1),A=N.useRef(()=>{}),ee=N.useRef(!1),[U,Z]=N.useState(!1),[F,I]=N.useState(!1),j=()=>{ee.current=!ee.current,Z(ee.current)};return N.useEffect(()=>{k(s||e)},[s,e]),N.useEffect(()=>{let R=!0;const T=t?t.split("/"):[],H=t?`/api/route/${t.split("/").map(encodeURIComponent).join("/")}/_`:"/api";async function te(){let ie=null,O=null;try{const X=await(await tn(`${H}/sessions`,o)).json();Array.isArray(X.sessions)&&(ie=X.sessions.find(ae=>ae.name===e))}catch{}try{const $=await zr(o,T);$.available&&Array.isArray($.cells)&&(O=$.cells.find(X=>X.tmuxSession===e))}catch{}if(!R)return;k(Xh({session:e,cell:O||(s?{cell:s}:null)}));let L="";O?L=`${O.engine}${O.key?`·${O.key}`:""}`:ie&&(L=ie.attached?`attached · ${k_(ie.activity)}`:ie.activity?k_(ie.activity):""),B(L)}te();const D=setInterval(te,4e3);return()=>{R=!1,clearInterval(D)}},[e,t,o]),c.jsxs("div",{className:"nc-app",children:[c.jsxs("header",{className:"nc-bar nc-bar-single",children:[c.jsxs("button",{onClick:u,title:g("sessions"),children:[c.jsx(nt,{name:"chevronLeft",size:18}),c.jsx("span",{className:"nc-bar-label",children:g("sessions")})]}),c.jsxs("span",{className:"nc-bar-center",children:[c.jsx("b",{title:t?`${C} · ${t}`:C,children:C}),P&&c.jsx("small",{className:"nc-bar-sub",children:P})]}),c.jsxs("span",{className:"nc-bar-right",children:[c.jsx("button",{onClick:()=>M(-1),title:g("zoom-out"),children:c.jsx(nt,{name:"zoomOut",size:18})}),c.jsx("button",{onClick:()=>M(1),title:g("zoom-in"),children:c.jsx(nt,{name:"zoomIn",size:18})}),c.jsx("button",{onClick:()=>b(R=>!R),title:g("composer"),children:c.jsx(nt,{name:"keyboard",size:20})}),c.jsx("button",{onClick:()=>f(R=>!R),title:g("files"),children:c.jsx(nt,{name:"folder",size:20})})]})]}),c.jsx("div",{className:"nc-termwrap",children:c.jsx(Yy,{session:e,node:t,token:o,readonly:a,takeSize:!0,sendRef:Y,composerRef:K,actionRef:A,ctrlRef:ee,setCtrlArmed:Z,onFiles:S,fontSize:w,selectionMode:F,onSelectionModeChange:I,keyboardGesture:h.terminalKeyboardGesture})}),c.jsx(JC,{onKeyboard:()=>b(R=>!R),send:R=>Y.current(R),action:R=>A.current(R),ctrlArmed:U,onCtrl:j,selectionMode:F,onSelectionMode:I,keepKeyboardClosed:h.keybarKeepsKeyboardClosed,showEnter:h.showKeybarEnter,keybarLayout:h.keybarLayout}),_&&c.jsx(rw,{submitText:R=>K.current(R),token:o,session:e,node:t,ownerId:n,keepKeyboardClosedOnVoice:h.voiceKeepsKeyboardClosed}),p&&c.jsx(Gy,{session:e,node:t,token:o,filesEvent:y,onClose:()=>f(!1)})]})}function ZN(){zn();const[e]=N.useState(XN),[t,n]=N.useState(e.token),[s,o]=N.useState(e.pair||""),a=N.useCallback(()=>{o("");try{sessionStorage.removeItem("nc_pair")}catch{}},[]),[u,h]=N.useState(!1),p=QN(),[f]=N.useState(()=>EE(typeof location<"u"?location.pathname:"/")),[_,b]=N.useState(f.id),y=_===ys(null,On),[S,w]=N.useState(null),x=de=>{const Ee=fr(de);w(Ee?{...Ee,...typeof(de==null?void 0:de.cellName)=="string"&&de.cellName?{cellName:de.cellName}:{}}:null)},[C,k]=N.useState([]),[P,B]=N.useState([]),[M,Y]=N.useState([]),[K,A]=N.useState(()=>f.ownerId?_s():JN(f.name)),[ee,U]=N.useState(null),[Z,F]=N.useState(null),I=de=>F(fr(de)),j=Dh(t,p),R=N.useMemo(()=>(j||[]).filter(de=>de.instanceId).map(de=>({instanceId:de.instanceId,route:de.route,label:de.label,status:de.status})),[j]),T=zN(t,_,K,A,R),H=T.decks;N.useEffect(()=>{const de=new Map;for(const Ee of j||[]){const Ue=(Ee.route||[Ee.name]).join("/"),_t=new Set((Ee.sessions||[]).map(dt=>dt.name));for(const dt of Ee.cells||[])!dt.cell||!dt.tmuxSession||dt.cell===dt.tmuxSession||_t.has(dt.cell)||de.set(`${Ue}:${dt.cell}`,`${Ue}:${dt.tmuxSession}`)}A(Ee=>Z0(Ee,de))},[j]),N.useEffect(()=>{T.localNodeId&&A(de=>{const Ee=ph(de,T.localNodeId,R);return JSON.stringify(Ee)===JSON.stringify(de)?de:Ee})},[R,T.localNodeId]);const[te,D]=N.useState(null),[ie,O]=N.useState(null),L=N.useRef(0),[$,X]=N.useState(!1),[ae,ue]=N.useState(YN),[ge,Q]=N.useState(!y),[q,fe]=N.useState(()=>y?localStorage.getItem(S_)==="1":!0),[Ie,et]=N.useState(!1),[ze,Fe]=N.useState("nodes"),[Ct,Ge]=N.useState(!1),[rt,ut]=N.useState(""),ct=(de="nodes",Ee=!1,Ue="")=>{Fe(de),Ge(Ee),ut(Ue),et(!0)},[vt,it]=N.useState(!1),[lt,mt]=N.useState({deviceDefault:"",localNodeId:"",localNameDefault:""}),[le,be]=N.useState(!1);N.useEffect(()=>{try{localStorage.setItem(Gw,String(ae))}catch{}},[ae]),N.useEffect(()=>{try{localStorage.setItem(S_,q?"1":"")}catch{}},[q]),N.useEffect(()=>{if(!t)return;let de=!1;return Promise.all([T_(t),tn("/api/config",t).then(Ee=>Ee.json())]).then(([Ee,Ue])=>{de||(mt({deviceDefault:Ee.deviceName||"",localNodeId:Ee.nodeId||"",localNameDefault:Ee.localName||""}),be(!!Ue.readonlyDefault),(Ee.firstRun===!0&&!Ue.readonlyDefault||s)&&it(!0))}).catch(()=>{}),()=>{de=!0}},[t,s]);const Be=N.useCallback(async()=>{try{const Ee=await(await tn("/api/sessions",t)).json();Ee.error||k(Ee.sessions||[])}catch{}try{const de=await zr(t);B(de.available?de.cells||[]:[]),Y(de.available?de.capabilities||[]:[])}catch{B([]),Y([])}},[t]);N.useEffect(()=>{if(!p)return;Be();const de=setInterval(Be,4e3);return()=>clearInterval(de)},[p,Be]),N.useEffect(()=>{let de=!1;return tn("/api/config",t).then(Ee=>Ee.json()).then(Ee=>{de||HN(Ee.version,Ee.uiVersion,"0.8.39")}).catch(()=>{}),()=>{de=!0}},[t]);const $e=new Set([...C.map(de=>de.name),...j.flatMap(de=>de.sessions.map(Ee=>Ee.key))]),he=vi(K),V=de=>A(Ee=>{const Ue=cw(de,T.localNodeId,R)||de,_t=Q_(Ee,Ue);return _t===Ee&&vi(Ee).length>=9&&T.setError(g("grid-full")),_t}),ne=async(de,Ee=[])=>{try{await Nh(t,de,Ee)}catch{return}const Ue=Ee.length?`${Ee.join("/")}:${de}`:de;A(_t=>xl(_t,Ue)),Be()},z=async(de,Ee,Ue=[])=>{try{await D_(t,de,Ee,Ue)}catch{return}Be()},se=async(de,Ee,Ue=[])=>{await P_(t,{cell:de,enabled:!!Ee},Ue),Be()},me=async de=>{if(!te)return;const{cell:Ee}=te,Ue=Array.isArray(te.route)?te.route:[];de.action==="up"?await Ch(t,{cell:Ee,boot:!!de.boot,...de.engine?{engine:de.engine}:{},...de.model!==void 0?{model:de.model}:{},...de.permissionPolicy?{permissionPolicy:de.permissionPolicy}:{}},Ue):await vl(t,{cell:Ee,boot:!!de.boot},Ue);const _t=de.action==="up"?!!de.boot:de.boot?!1:!!te.boot;O({id:++L.current,cell:Ee,route:Ue,enabled:_t}),Be()},ke=N.useCallback(de=>{O(Ee=>(Ee==null?void 0:Ee.id)===de?null:Ee)},[]),Ne=async de=>{if(!(!(de!=null&&de.direct)||$)){X(!0);try{await jh(t,de.name,de.tunnelStatus==="up"?"down":"up")}finally{X(!1)}}},we=async(de,Ee)=>{const Ue=String(Ee||"").trim();return!(de!=null&&de.direct)||!ks(Ue)?!1:(await I_(t,de.name,Ue),!0)},Re=de=>{const Ee=H.find(Ue=>Ue.id===de);if(!Ee)return!1;try{const Ue=window.open(Vu(Ee,t),"_blank");return Ue&&(Ue.opener=null),!!Ue}catch{return!1}},Je=async de=>{if(!de||de===_)return;const Ee=await T.select(de),Ue=T.records.find(_t=>_t.id===de);b(de),A(Ee),U(null),F(null);try{history.replaceState(null,"",Vu(Ue||de,null))}catch{}},Tt=async(de,Ee)=>{const Ue=await T.add(de,Ee);await Je(Ue.id)},Me=async(de,Ee)=>{const Ue=await T.rename(de,Ee);if(de===_){b(Ue.id),A(ph(Ue.layout,T.localNodeId,R)),U(null),F(null);try{history.replaceState(null,"",Vu(Ue,null))}catch{}}},pn=async de=>{await T.remove(de),de===_&&await Je(T.localMainId)},bt=async(de,Ee)=>{!Ee||Ee===_||(await T.addTileTo(Ee,de),A(Ue=>xl(Ue,de)))};if(!t)return c.jsxs("div",{className:"nc-auth",children:[c.jsx("p",{children:g("auth-prompt")}),c.jsx("input",{onChange:de=>n(de.target.value.trim()),placeholder:"token"}),c.jsxs("label",{children:[c.jsx("input",{type:"checkbox",checked:u,onChange:de=>h(de.target.checked)})," ",g("remember-device")]}),c.jsx("button",{onClick:()=>{(u?localStorage:sessionStorage).setItem("nc_token",t)},children:"ok"})]});const Ke=c.jsxs(c.Fragment,{children:[Ie&&c.jsx(jN,{token:t,initialTab:ze,initialLocation:rt,startNewCell:Ct,onClose:()=>{et(!1),Ge(!1),ut("")}}),vt&&c.jsx(LN,{token:t,initialPair:s,...lt,onPairDone:a,onDone:()=>it(!1)}),c.jsx(BN,{token:t})]});if(!p)return S?c.jsxs(c.Fragment,{children:[c.jsx(x_,{session:S.session,node:S.node,ownerId:S.ownerId,cellName:S.cellName,token:t,readonly:le,onBack:()=>w(null)}),Ke]}):c.jsxs(c.Fragment,{children:[c.jsx(p1,{onPick:x,token:t,onSettings:ct}),Ke]});const $t=y||!ge;return c.jsxs("div",{className:"nc-workspace",children:[$t&&c.jsx(pE,{sessions:C,cells:P,activeSessions:he,nodeGroups:j,fleetCapabilities:M,bootSettlement:ie,onBootSettlementApplied:ke,localNodeId:T.localNodeId,onPick:I,onAddTile:V,onPower:D,onBoot:se,onBootError:de=>T.setError(String((de==null?void 0:de.message)||de)),onNodePower:Ne,onNodeRename:we,onKill:ne,onVisibility:z,onNew:()=>ct("fleet",!0),onSettings:ct,width:ae,collapsed:q,onResize:ue,onToggleCollapse:()=>fe(de=>!de)}),c.jsxs("div",{className:"nc-workspace-main",children:[c.jsx(GE,{decks:H,currentDeck:_,onCreate:Tt,onRename:Me,onDelete:pn,onReorder:T.reorder,onOpenWindow:Re,onNavigate:Je,saveState:T.saveState,error:T.error,sidebarVisible:$t,onToggleSidebar:y?null:()=>Q(de=>!de)}),c.jsx(SE,{layout:K,onLayoutChange:A,token:t,readonly:le,sessionsAlive:$e,focusSession:ee,onFocus:U,onOpenSingle:I,decks:H,currentDeck:_,onSendToDeck:bt,cells:P,nodeGroups:j})]}),Z&&c.jsx("div",{className:"nc-single-overlay",children:c.jsx(x_,{session:Z.session,node:Z.node,ownerId:Z.ownerId,cellName:Xh({session:Z.session,node:Z.node,ownerId:Z.ownerId,cells:P,nodeGroups:j}),token:t,readonly:le,onBack:()=>F(null)})}),te&&c.jsx(yl,{cell:te,token:t,route:Array.isArray(te.route)?te.route:[],onConfirm:me,onClose:()=>D(null)}),Ke]})}function eR(){zn();const e=N.useSyncExternalStore($N,w_,w_);if(!e.needed)return null;const t=e.kind==="install"?g("install-version-mismatch").replace("{v}",e.version):g("update-available").replace("{v}",e.version).replace(" "," ").trim();return c.jsxs("div",{className:"nc-update",role:"status","aria-live":"polite",children:[c.jsx("span",{className:"nc-update-msg",children:t}),e.kind==="reload"&&c.jsx("button",{className:"nc-update-btn",onClick:KN,children:g("reload")})]})}UN();Xb.createRoot(document.getElementById("root")).render(c.jsxs(Wb.StrictMode,{children:[c.jsx(ZN,{}),c.jsx(eR,{})]}));
|
package/frontend/dist/index.html
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
<meta name="apple-mobile-web-app-title" content="NexusCrew" />
|
|
12
12
|
<link rel="manifest" href="/manifest.json" />
|
|
13
13
|
<title>NexusCrew</title>
|
|
14
|
-
<script type="module" crossorigin src="/assets/index-
|
|
14
|
+
<script type="module" crossorigin src="/assets/index-D0MBXlAl.js"></script>
|
|
15
15
|
<link rel="stylesheet" crossorigin href="/assets/index-5PMZjYKR.css">
|
|
16
16
|
</head>
|
|
17
17
|
<body>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"0.8.
|
|
1
|
+
{"version":"0.8.39"}
|
package/lib/nodes/commands.js
CHANGED
|
@@ -416,36 +416,46 @@ async function nodesTest(opts) {
|
|
|
416
416
|
return { code: 1, result: 'tunnel-down', diagnostic };
|
|
417
417
|
}
|
|
418
418
|
|
|
419
|
-
const httpProbe = opts.httpProbe || defaultHttpProbe;
|
|
420
|
-
const base = `http://127.0.0.1:${node.localPort}`;
|
|
421
|
-
|
|
422
|
-
// health: GET / non autenticato -> 2xx significa "server remoto raggiungibile via tunnel".
|
|
423
|
-
let health;
|
|
424
|
-
try { health = await httpProbe(`${base}/`, {}); }
|
|
425
|
-
catch (e) { health = { ok: false, error: e && e.message }; }
|
|
426
|
-
if (!health || !health.ok) {
|
|
427
|
-
const diagnostic = tunnel.diagnoseTunnel(home, node);
|
|
428
|
-
const realCause = diagnostic.code !== 'transport-ready' ? diagnostic.detail : ((health && health.error) || 'server HTTP non raggiungibile');
|
|
429
|
-
log(`nodes test [${name}]: HEALTH KO — ${realCause}${diagnostic.hint ? ` · ${diagnostic.hint}` : ''}`);
|
|
430
|
-
return { code: 1, result: 'health-ko', diagnostic: diagnostic.code === 'transport-ready'
|
|
431
|
-
? { stage: 'http', code: 'peer-http-unreachable', detail: realCause, hint: 'verifica la porta NexusCrew contenuta nel link' }
|
|
432
|
-
: diagnostic };
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
// token: GET /api/config con Bearer del nodo -> 200 ok, 401 token KO.
|
|
436
419
|
if (!node.token) {
|
|
437
420
|
log(`nodes test [${name}]: ASSOCIAZIONE INCOMPLETA — rimuovi il nodo e ripeti il pairing dalla PWA`);
|
|
438
421
|
return { code: 1, result: 'token-missing' };
|
|
439
422
|
}
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
423
|
+
|
|
424
|
+
// The per-peer token is a federation credential accepted by the remote
|
|
425
|
+
// peer's acceptToken. It is deliberately NOT the remote browser/UI token,
|
|
426
|
+
// so probing /api/config with it always returns a misleading 401. Use the
|
|
427
|
+
// same authenticated, identity-bound health endpoint as the live topology.
|
|
428
|
+
const probe = opts.federationProbe || federation.probeHealth;
|
|
429
|
+
let health;
|
|
430
|
+
try {
|
|
431
|
+
health = await probe({
|
|
432
|
+
port: node.localPort, token: node.token, expectedInstanceId: node.nodeId || null,
|
|
433
|
+
fetchImpl: opts.fetchImpl, timeoutMs: opts.timeoutMs,
|
|
434
|
+
});
|
|
435
|
+
} catch (_) {
|
|
436
|
+
health = {
|
|
437
|
+
transport: 'down', auth: 'unknown', reachability: 'unknown',
|
|
438
|
+
status: 'down', detail: 'peer non raggiungibile',
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
if (health && health.status === 'healthy') {
|
|
442
|
+
log(`nodes test [${name}]: OK — tunnel e federation autenticati`);
|
|
443
|
+
return { code: 0, result: 'ok', health };
|
|
446
444
|
}
|
|
447
|
-
|
|
448
|
-
|
|
445
|
+
if (health && health.auth === 'failed') {
|
|
446
|
+
log(`nodes test [${name}]: CREDENZIALE KO — ${health.detail || 'federation 401'}; ripeti il pairing dalla PWA`);
|
|
447
|
+
return { code: 1, result: 'token-ko', health };
|
|
448
|
+
}
|
|
449
|
+
const diagnostic = tunnel.diagnoseTunnel(home, node);
|
|
450
|
+
const detail = (health && health.detail)
|
|
451
|
+
|| (diagnostic.code !== 'transport-ready' ? diagnostic.detail : 'peer federation non raggiungibile');
|
|
452
|
+
log(`nodes test [${name}]: HEALTH KO — ${detail}${diagnostic.hint ? ` · ${diagnostic.hint}` : ''}`);
|
|
453
|
+
return {
|
|
454
|
+
code: 1, result: 'health-ko', health,
|
|
455
|
+
diagnostic: diagnostic.code === 'transport-ready'
|
|
456
|
+
? { stage: 'http', code: 'peer-federation-unreachable', detail, hint: 'verifica il tunnel e la porta NexusCrew contenuta nel link' }
|
|
457
|
+
: diagnostic,
|
|
458
|
+
};
|
|
449
459
|
}
|
|
450
460
|
|
|
451
461
|
// probe HTTP di default (fetch built-in, Node >=18). Ritorna {ok, status}.
|
package/lib/settings/routes.js
CHANGED
|
@@ -184,7 +184,8 @@ function settingsRoutes(deps = {}) {
|
|
|
184
184
|
home, configDir, configPath, nodesPath, log: cap.log,
|
|
185
185
|
keygen: seams.keygen, execFileImpl: seams.execFileImpl,
|
|
186
186
|
spawnImpl: seams.spawnImpl, sshBin: seams.sshBin, logFd: seams.logFd,
|
|
187
|
-
httpProbe: seams.httpProbe,
|
|
187
|
+
httpProbe: seams.httpProbe, federationProbe: seams.federationProbe,
|
|
188
|
+
fetchImpl: seams.fetchImpl, sshVersion: seams.sshVersion,
|
|
188
189
|
spawnSyncImpl: seams.spawnSyncImpl,
|
|
189
190
|
localAppPort: runtimePort(),
|
|
190
191
|
});
|