@mmmbuto/nexuscrew 0.8.55 → 0.8.57

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
@@ -4,6 +4,88 @@ All notable changes to NexusCrew are tracked here.
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ ## 0.8.57 — 2026-08-11 — "Three Wires, One Subscription"
8
+
9
+ - **OpenCode Go is a managed provider on Claude Code, Codex-VL and Pi.** One
10
+ subscription, one environment variable (`OPENCODE_API_KEY`), three profiles —
11
+ because the gateway is not one uniform API but three: Anthropic Messages,
12
+ OpenAI Responses and Chat Completions. Each client gets the wire it actually
13
+ speaks, with `deepseek-v4-flash` as the default model on all three.
14
+
15
+ - **The model lists were measured, not copied from the docs.** The published
16
+ endpoint table assigns each model a single wire, but the gateway translates
17
+ between them, so the table understates what works and overstates it in
18
+ places. Every one of the 25 advertised model IDs was tried on all three
19
+ wires, and a second pass re-tried the failures with sane parameters to tell a
20
+ wire refusal apart from a request the gateway forwarded empty. What went into
21
+ the catalog is that matrix: 12 models on Messages, 6 on Responses, 21 on
22
+ Chat. Three IDs the live catalog still advertises are dead upstream — two
23
+ deprecated, one unavailable — and are in none of the lists.
24
+
25
+ - **The Claude profile sends the key as `x-api-key`, not as a bearer token.**
26
+ This gateway's Messages endpoint answers `401 Missing API key` to
27
+ `Authorization: Bearer`, which is the shape every other gateway in the
28
+ catalog uses. Copying the neighbouring profile would have produced a cell
29
+ that fails at first use with an authentication error and no obvious cause.
30
+ A test breaks on exactly that substitution.
31
+
32
+ - **The URL roots differ by client and both are easy to get wrong.** Claude
33
+ receives the root without `/v1`, because the client appends `/v1/messages`;
34
+ Codex-VL receives the base *with* `/v1` and appends `/responses`. A doubled
35
+ `/v1` is a 404.
36
+
37
+ - **The Pi profile requires the key instead of delegating it.** Auth delegation
38
+ belongs to the providers Pi resolves from its own login store. This one
39
+ exists only as a generated extension whose API key is an environment
40
+ reference, so delegating would have reported a cell as configured while no
41
+ key existed anywhere — a failure deferred to first use. It now fails closed
42
+ before launch, like the other extension-based provider.
43
+
44
+ - **No context window is declared for these models.** Their real limits on this
45
+ provider have not been measured, and an invented number would quietly become
46
+ the threshold at which cells compact.
47
+
48
+ - **What is not verified yet.** These profiles are proven at the protocol
49
+ level: every advertised pair was exercised against the live API. They have
50
+ not been exercised inside a running cell, so streaming, tool calls,
51
+ interleaved reasoning and resume remain unverified. The provider also does
52
+ not expose `/v1/messages/count_tokens`, which Claude Code uses for context
53
+ accounting; whether the client degrades quietly or reports an error is not
54
+ yet known.
55
+
56
+ ## 0.8.56 — 2026-08-08 — "The Catalog Learns Its Order"
57
+
58
+ - **Grok Build is a managed client (`grok.native`).** xAI's `grok` TUI joins
59
+ the engine catalog with authentication fully delegated to the CLI's own
60
+ login (browser, API key or device-code): NexusCrew reads no credential,
61
+ copies no token, and puts nothing secret on argv. The binary is resolved
62
+ from its non-standard install path (`~/.grok/bin`) before the usual
63
+ locations. Like Agy it is backfilled platform-aware on Linux and macOS
64
+ outside Termux — the official aarch64 binary is statically linked and looks
65
+ promising there, but stays out until it is actually proven on a device. A
66
+ cell set to `unsafe` maps to `grok --always-approve`, the flag the CLI
67
+ really has.
68
+
69
+ - **VL is a managed client (`vl.native`).** The Vivling runtime's inline TUI
70
+ joins the catalog as a local client: authentication belongs to the runtime
71
+ itself, so NexusCrew passes no credential at all. The CLI has no approval
72
+ flags, so the client is standard-only — an `unsafe` request has no argv
73
+ counterpart and is refused fail-closed, including through the per-cell
74
+ override path, and both directions are now pinned by tests. A cell prompt
75
+ cannot be delivered to `vl` (the CLI has no prompt surface); the limitation
76
+ is declared in code and tracked for a UI hint.
77
+
78
+ - **The catalog's order is now a contract, not an accident.** The array that
79
+ feeds the client menu, the provider menu and the fresh-install seed is
80
+ reordered deliberately and documented as contractual: clients by first
81
+ appearance (Claude, Codex-VL before Codex, Grok, VL, Pi, Agy, Kimi, Shell
82
+ last), providers inside each client by category (native, subscription,
83
+ cloud, local, custom last), legacy entries in a separate closing section.
84
+ Labels drop the redundant `Pi · ` prefix. The seed keeps the same five
85
+ defaults with `claude.native` first — what changes is their order, never
86
+ their set. Six Pi providers stay deliberately out of the UI catalog,
87
+ declared as such in place.
88
+
7
89
  ## 0.8.55 — 2026-08-08 — "The Mirror Needs No Hands"
8
90
 
9
91
  - **Building the public tree is now a pure export.** Five test fixtures existed
@@ -90,4 +90,4 @@ Minimum version required to store current data is: `+H+`.
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 fs({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,m=()=>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(w=>w.offsetParent!==null),v=requestAnimationFrame(()=>{var w;return(w=m()[0]||p)==null?void 0:w.focus({preventScroll:!0})}),y=w=>{var x;if(w.key==="Escape"){w.preventDefault(),(x=u.current)==null||x.call(u);return}if(w.key!=="Tab")return;const b=m();if(!b.length){w.preventDefault(),p==null||p.focus();return}const S=b[0],C=b[b.length-1];w.shiftKey&&document.activeElement===S?(w.preventDefault(),C.focus()):!w.shiftKey&&document.activeElement===C&&(w.preventDefault(),S.focus())};return document.addEventListener("keydown",y),()=>{cancelAnimationFrame(v),document.removeEventListener("keydown",y),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]),l.jsx("div",{className:"nc-fleet-modal",role:"presentation",onMouseDown:h=>{h.target===h.currentTarget&&t()},children:l.jsxs("div",{ref:o,className:"nc-fleet-modal-dialog",role:"dialog","aria-modal":"true","aria-label":n||f("settings"),tabIndex:-1,children:[e,s&&l.jsx("div",{ref:a,className:"nc-err nc-fleet-modal-error",role:"alert","aria-live":"assertive",children:s})]})})}function $d({token:e,targets:t=[],readonly:n=!1,onPower:s,onImport:o}){const[a,u]=N.useState([]),[h,p]=N.useState(0);N.useEffect(()=>{let x=!0;async function R(){const $=[{route:[],label:f("local")}].concat((t||[]).map(K=>({route:Array.isArray(K.route)?K.route:[],label:K.label||(K.route||[]).join(" › ")}))),B=await Promise.all($.map(async K=>{const V={...K,available:!1,readonly:!1,capabilities:[],provider:null,cells:[],unmanaged:[],err:""};try{const Y=await bs(e,K.route);V.available=!!Y.available,V.capabilities=Y.capabilities||[],V.provider=Y.provider||null,V.cells=(Y.cells||[]).map(te=>({...te,route:K.route}));try{V.readonly=!!(await ef(e,K.route)).readonlyDefault}catch{}try{const te=await Zh(e,K.route),Q=new Set(V.cells.map(J=>J.tmuxSession).filter(Boolean));V.unmanaged=(te.sessions||[]).filter(J=>J&&!Q.has(J.name))}catch{}}catch(Y){V.err=String(Y&&Y.message||Y)}return V}));x&&u(B)}R();const E=setInterval(R,6e3);return()=>{x=!1,clearInterval(E)}},[e,t,h]);const m=(x,R)=>Array.isArray(x.capabilities)&&x.capabilities.includes(R)&&!n&&!x.readonly,v=()=>p(x=>x+1),y=(x,R)=>{s&&s({...x,route:R})},w=(x,R)=>{s&&s({...x,route:R})},b=async(x,R)=>{try{await $o(e,x.cell,R)}catch{}v()},S=async(x,R)=>{if(window.confirm(f("fleet-remove-cell").replace("{id}",x.cell))){try{await ey(e,x.cell,!0,R)}catch{}v()}},C=async(x,R)=>{if(window.confirm(f("terminate-confirm").replace("{name}",x.name))){try{await Qh(e,x.name,R)}catch{}v()}};return l.jsxs("div",{className:"nc-fleet-inventory",children:[l.jsxs("div",{className:"nc-fleet-section-head",children:[l.jsx("b",{children:f("fleet-inventory")}),l.jsx("small",{children:f("fleet-inventory-help")})]}),a.map(x=>{const R=x.route.length?x.route.join("/"):"local";return l.jsxs("div",{className:"nc-fleet-pos",children:[l.jsxs("div",{className:"nc-fleet-pos-title",children:[l.jsx("span",{className:`dot ${x.available?"on":"warn"}`}),l.jsx("b",{children:x.label}),l.jsx("small",{children:x.available?`${x.cells.length} ${f("fleet-cells")} · ${x.unmanaged.length} ${f("fleet-tmux")}`:x.err||f("fleet-not-available")})]}),x.cells.map(E=>l.jsxs("div",{className:"nc-fleet-item nc-fleet-cell",children:[l.jsxs("span",{children:[l.jsx("b",{children:E.cell}),l.jsx("small",{children:`${E.engine||""}${E.key?`·${E.key}`:""}${E.active?"":` · ${f("cell-off")}`}`})]}),l.jsxs("span",{className:"nc-fleet-cell-actions",children:[E.active&&m(x,"down")&&l.jsx("button",{className:"nc-btn ghost",title:f("power-off"),onClick:()=>w(E,x.route),children:f("stop")}),!E.active&&m(x,"up")&&l.jsx("button",{className:"nc-btn ghost",title:f("power-on"),onClick:()=>y(E,x.route),children:f("start")}),m(x,"restart")&&E.active&&l.jsx("button",{className:"nc-btn ghost",title:f("restart"),onClick:()=>b(E,x.route),children:f("restart")}),m(x,"remove")&&l.jsx("button",{className:"nc-btn danger",title:f("delete"),onClick:()=>S(E,x.route),children:"×"})]})]},`${R}:${E.cell}`)),x.unmanaged.map(E=>l.jsxs("div",{className:"nc-fleet-item nc-fleet-unmanaged",children:[l.jsxs("span",{children:[l.jsx("b",{children:E.name}),l.jsx("small",{children:f("fleet-tmux")})]}),l.jsxs("span",{className:"nc-fleet-cell-actions",children:[m(x,"import")&&o&&l.jsx("button",{className:"nc-btn ghost",title:f("import-as-cell"),onClick:()=>o(E,x.route),children:f("import-as-cell")}),l.jsx("button",{className:"nc-btn danger",title:f("terminate"),onClick:()=>C(E,x.route),children:"×"})]})]},`${R}:u:${E.name}`)),x.available&&x.cells.length===0&&x.unmanaged.length===0&&l.jsx("div",{className:"nc-empty",children:f("fleet-inventory-empty")})]},R)})]})}function aj({cells:e=[],engines:t=[],models:n=[],busy:s,canRestore:o=!1,onRestore:a,onClose:u}){const[h,p]=N.useState("export"),[m,v]=N.useState([]),[y,w]=N.useState(()=>new Set(e.map(T=>T.id))),[b,S]=N.useState(()=>new Set(t.map(T=>T.id))),[C,x]=N.useState([]),[R,E]=N.useState([]),[$,B]=N.useState(""),K=new Set(t.map(T=>T.id)),V=new Set(e.map(T=>T.id)),Y=(T,F)=>T(k=>{const I=new Set(k);return I.has(F)?I.delete(F):I.add(F),I}),te=()=>{const T=ej(e,y,t,b,new Date,n);if(T.ok===!1){B(f(`fleet-backup-${T.error}`));return}const F=e.filter(W=>y.has(W.id)).length,k=t.filter(W=>b.has(W.id)).length;if(T.cells.length!==F){B(f("fleet-backup-invalid-cell"));return}if(T.engines.length!==k){B(f("fleet-backup-invalid-engine"));return}if(!T.cells.length&&!T.engines.length){B(f("fleet-backup-select-one"));return}const I=new Blob([`${JSON.stringify(T,null,2)}
91
91
  `],{type:"application/json"}),D=URL.createObjectURL(I),M=document.createElement("a");M.href=D,M.download=`nexuscrew-fleet-${new Date().toISOString().slice(0,10)}.json`,document.body.appendChild(M),M.click(),M.remove(),setTimeout(()=>URL.revokeObjectURL(D),0),B("")},Q=async T=>{if(B(""),x([]),E([]),!!T){if(T.size>1024*1024){B(f("fleet-backup-too-large"));return}try{const F=tj(await T.text());if(!F.ok){B(f(`fleet-backup-${F.error}`));return}v(Array.isArray(F.models)?F.models:[]);const k=new Set(F.engines.map(I=>I.id));E(F.engines.map(I=>({engine:I,exists:K.has(I.id),selected:!K.has(I.id)}))),x(F.cells.map(I=>{const D=K.has(I.engine)||k.has(I.engine),M=V.has(I.id);return{cell:I,engine:D?I.engine:"",selected:D&&!M,exists:M}}))}catch(F){B(String(F.message||F))}}},J=(T,F)=>x(k=>k.map((I,D)=>D===T?{...I,...F}:I)),H=(T,F)=>E(k=>k.map((I,D)=>D===T?{...I,...F}:I)),L=new Set([...K,...R.filter(T=>T.selected).map(T=>T.engine.id)]),A=C.filter(T=>T.selected&&T.engine&&L.has(T.engine)),z=R.filter(T=>T.selected),O=[...new Map([...t.map(T=>[T.id,T.label||T.id]),...R.filter(T=>T.selected).map(T=>[T.engine.id,T.engine.label||T.engine.id])]).entries()];return l.jsxs("div",{className:"nc-set-form nc-fleet-form nc-backup-dialog",children:[l.jsx("b",{children:f("fleet-backup")}),l.jsx("small",{children:f("fleet-backup-help")}),l.jsxs("div",{className:"nc-set-tabs nc-backup-tabs",children:[l.jsx("button",{type:"button",className:`nc-set-tabbtn${h==="export"?" on":""}`,onClick:()=>{p("export"),B("")},children:f("fleet-backup-export")}),l.jsx("button",{type:"button",className:`nc-set-tabbtn${h==="import"?" on":""}`,disabled:!o,title:o?"":f("fleet-backup-restore-unavailable"),onClick:()=>{p("import"),B("")},children:f("fleet-backup-import")})]}),h==="export"?l.jsxs(l.Fragment,{children:[l.jsxs("div",{className:"nc-set-row",children:[l.jsx("button",{type:"button",className:"nc-btn ghost",onClick:()=>{w(new Set(e.map(T=>T.id))),S(new Set(t.map(T=>T.id)))},children:f("select-all")}),l.jsx("button",{type:"button",className:"nc-btn ghost",onClick:()=>{w(new Set),S(new Set)},children:f("select-none")})]}),l.jsxs("div",{className:"nc-backup-list",children:[l.jsx("b",{children:f("fleet-engines")}),t.map(T=>{var F;return l.jsxs("label",{className:"nc-check nc-backup-row",children:[l.jsx("input",{type:"checkbox",checked:b.has(T.id),onChange:()=>Y(S,T.id)}),l.jsxs("span",{children:[l.jsx("b",{children:T.label||T.id}),l.jsxs("small",{children:[T.id,(F=T.envKeys)!=null&&F.length?` · ${T.envKeys.length} ${f("fleet-backup-env-names")}`:""]})]})]},T.id)}),l.jsx("b",{children:f("fleet-cells")}),e.map(T=>l.jsxs("label",{className:"nc-check nc-backup-row",children:[l.jsx("input",{type:"checkbox",checked:y.has(T.id),onChange:()=>Y(w,T.id)}),l.jsxs("span",{children:[l.jsx("b",{children:T.id}),l.jsxs("small",{children:[T.engine," · ",f("fleet-system-prompt")," ",(T.prompt||"").length," ",f("characters")]})]})]},T.id)),!e.length&&!t.length&&l.jsx("div",{className:"nc-empty",children:f("fleet-backup-empty")})]}),l.jsxs("div",{className:"nc-sheet-actions",children:[l.jsx("button",{type:"button",className:"nc-btn ghost",onClick:u,children:f("cancel")}),l.jsx("button",{type:"button",className:"nc-btn primary",disabled:!y.size&&!b.size,onClick:te,children:f("fleet-backup-download")})]})]}):l.jsxs(l.Fragment,{children:[l.jsx("input",{type:"file",accept:"application/json,.json",disabled:s,onChange:T=>Q(T.target.files&&T.target.files[0])}),l.jsx("small",{children:f("fleet-backup-import-help")}),!!(C.length||R.length)&&l.jsxs("div",{className:"nc-set-row",children:[l.jsx("button",{type:"button",className:"nc-btn ghost",onClick:()=>{E(T=>T.map(F=>({...F,selected:!0}))),x(T=>T.map(F=>({...F,selected:!!F.engine})))},children:f("select-all")}),l.jsx("button",{type:"button",className:"nc-btn ghost",onClick:()=>{E(T=>T.map(F=>({...F,selected:!1}))),x(T=>T.map(F=>({...F,selected:!1})))},children:f("select-none")})]}),l.jsxs("div",{className:"nc-backup-list",children:[!!R.length&&l.jsx("b",{children:f("fleet-engines")}),R.map((T,F)=>{var k;return l.jsx("div",{className:"nc-backup-import-row",children:l.jsxs("label",{className:"nc-check",children:[l.jsx("input",{type:"checkbox",checked:T.selected,onChange:I=>H(F,{selected:I.target.checked})}),l.jsxs("span",{children:[l.jsx("b",{children:T.engine.label||T.engine.id}),l.jsxs("small",{children:[T.engine.id," · ",T.exists?f("fleet-backup-overwrite"):f("fleet-backup-new"),(k=T.engine.envKeys)!=null&&k.length?` · ${f("fleet-backup-env-values-required")}`:""]})]})]})},T.engine.id)}),!!C.length&&l.jsx("b",{children:f("fleet-cells")}),C.map((T,F)=>l.jsxs("div",{className:"nc-backup-import-row",children:[l.jsxs("label",{className:"nc-check",children:[l.jsx("input",{type:"checkbox",checked:T.selected,disabled:!T.engine||!L.has(T.engine),onChange:k=>J(F,{selected:k.target.checked})}),l.jsxs("span",{children:[l.jsx("b",{children:T.cell.id}),l.jsxs("small",{children:[T.exists?f("fleet-backup-overwrite"):f("fleet-backup-new")," · ",f("fleet-system-prompt")," ",T.cell.systemPrompt.length," ",f("characters")]})]})]}),l.jsxs("select",{value:T.engine,onChange:k=>J(F,{engine:k.target.value,selected:!!k.target.value}),children:[l.jsx("option",{value:"",children:f("fleet-backup-engine-missing")}),O.map(([k,I])=>l.jsx("option",{value:k,children:I},k))]})]},T.cell.id))]}),l.jsxs("div",{className:"nc-sheet-actions",children:[l.jsx("button",{type:"button",className:"nc-btn ghost",onClick:u,children:f("cancel")}),l.jsx("button",{type:"button",className:"nc-btn primary",disabled:s||!A.length&&!z.length,onClick:()=>a({engineRows:R,cellRows:C,models:m}),children:f("fleet-backup-restore")})]})]}),$&&l.jsx("div",{className:"nc-err",children:$})]})}function lj({state:e,setState:t,busy:n,onSave:s,catalog:o}){var R;const a=e.form,u=E=>t({...e,form:{...a,...E}}),h=a.envRows||[],p=[...new Map(o.map(E=>[E.client,E.clientLabel||E.client])).entries()],m=o.filter(E=>E.client===a.client),v=Zo(o,a),y=typeof(v==null?void 0:v.credentialEnv)=="string"?v.credentialEnv:"",w=Array.isArray(v==null?void 0:v.credentialUsedBy)?v.credentialUsedBy:[],b=(v==null?void 0:v.credentialSource)||"missing",S=!!(v!=null&&v.credentialEnv)||a.credentialProfile==="a"||a.credentialProfile==="p",C=!!y&&e.mode==="new"&&(v==null?void 0:v.authConfigured)!==!0&&!a.credentialValue&&!a.allowMissingCredential,x=E=>{E&&u({client:E.client,provider:E.provider,credentialProfile:E.credentialProfile||"",managedModel:E.model||"",protocol:E.protocol||"",permissionPolicy:E.permissionPolicyDefault||"standard",credentialSourcePolicy:"auto",rc:!!E.rc,displayName:E.custom?f("fleet-custom-provider-default"):"",baseUrl:E.custom?"":E.endpoint||"",envKey:E.defaultEnvKey||"",providerId:"nexuscrew-custom",credentialValue:"",credentialReveal:!1,allowMissingCredential:!1,...e.mode==="new"?{id:E.id,label:""}:{}})};return l.jsxs("div",{className:"nc-set-form nc-fleet-form",children:[l.jsx("b",{children:e.mode==="new"?f("fleet-new-engine"):`${f("edit")} ${a.id}`}),l.jsx("input",{value:a.id,disabled:e.mode!=="new",placeholder:"id",onChange:E=>u({id:E.target.value})}),l.jsx("input",{value:a.label,placeholder:f("label"),onChange:E=>u({label:E.target.value})}),l.jsxs("select",{value:a.kind,disabled:e.mode!=="new",onChange:E=>u({kind:E.target.value}),children:[l.jsx("option",{value:"managed",children:f("fleet-managed")}),l.jsx("option",{value:"custom",children:f("fleet-custom")})]}),a.kind==="managed"?l.jsxs(l.Fragment,{children:[l.jsxs("div",{className:"nc-fleet-pair",children:[l.jsx("select",{value:a.client,disabled:e.mode!=="new",onChange:E=>x(o.find($=>$.client===E.target.value&&$.default)||o.find($=>$.client===E.target.value)),children:p.map(([E,$])=>l.jsx("option",{value:E,children:$},E))}),l.jsx("select",{value:((R=Zo(o,a))==null?void 0:R.id)||"",disabled:e.mode!=="new",onChange:E=>x(o.find($=>$.id===E.target.value)),children:m.map(E=>l.jsx("option",{value:E.id,children:E.label},E.id))})]}),a.client!=="shell"&&l.jsxs(l.Fragment,{children:[l.jsx("input",{value:a.managedModel,list:"nc-managed-models",placeholder:f(v!=null&&v.requiresModel?"fleet-model-required":"fleet-model-default"),onChange:E=>u({managedModel:E.target.value})}),l.jsx("datalist",{id:"nc-managed-models",children:[...(v==null?void 0:v.models)||[],...a.modelOptions||[]].filter((E,$,B)=>E&&B.indexOf(E)===$).map(E=>l.jsx("option",{value:E},E))})]}),v!=null&&v.supportsUnsafe?l.jsxs("select",{value:a.permissionPolicy,onChange:E=>u({permissionPolicy:E.target.value}),children:[l.jsx("option",{value:"standard",children:f("fleet-standard-permissions")}),l.jsx("option",{value:"unsafe",children:f("fleet-unsafe-permissions")})]}):l.jsx("small",{children:f("fleet-standard-permissions")}),(v==null?void 0:v.supportsUnsafe)&&a.permissionPolicy==="unsafe"&&l.jsx("small",{className:"nc-err",children:f("fleet-unsafe-warning")}),S&&l.jsxs("select",{"aria-label":f("fleet-credential-source-policy"),value:a.credentialSourcePolicy||"auto",onChange:E=>u({credentialSourcePolicy:E.target.value}),children:[l.jsx("option",{value:"auto",children:f("fleet-credential-source-policy-auto")}),l.jsx("option",{value:"nexuscrew-store",children:f("fleet-credential-source-policy-nexuscrew-store")}),l.jsx("option",{value:"environment",children:f("fleet-credential-source-policy-environment")})]}),(v==null?void 0:v.credentialEnv)===!0&&l.jsxs(l.Fragment,{children:[l.jsx("input",{value:a.envKey,placeholder:f("fleet-api-key-env"),onChange:E=>u({envKey:E.target.value})}),l.jsx("small",{children:f("fleet-custom-secret-help")})]}),y&&l.jsxs("section",{className:"nc-fleet-key","aria-label":f("fleet-key-section"),children:[l.jsxs("div",{className:"nc-fleet-key-head",children:[l.jsx("b",{children:f("fleet-key-section")}),l.jsx("span",{children:f(`fleet-credential-source-${b}`)})]}),l.jsxs("label",{className:"nc-field",children:[f("fleet-key-variable"),l.jsx("input",{value:y,readOnly:!0,"aria-label":f("fleet-key-variable")})]}),l.jsx("small",{children:w.length?f("fleet-key-used-by").replace("{engines}",w.join(", ")):f("fleet-key-used-by-none")}),w.length>0&&l.jsx("small",{children:f("fleet-key-shared-impact").replace("{key}",y).replace("{engines}",w.join(", "))}),l.jsxs("div",{className:"nc-fleet-key-input",children:[l.jsx("input",{type:a.credentialReveal?"text":"password",value:a.credentialValue||"","aria-label":f("fleet-key-value").replace("{key}",y),autoComplete:"new-password",spellCheck:!1,autoCapitalize:"none",autoCorrect:"off",placeholder:v!=null&&v.authConfigured||e.mode==="edit"?f("fleet-key-blank-keeps"):f("fleet-key-enter"),onChange:E=>u({credentialValue:E.target.value,allowMissingCredential:E.target.value?!1:a.allowMissingCredential})}),l.jsx("button",{type:"button",className:"nc-btn ghost","aria-label":f(a.credentialReveal?"fleet-key-hide":"fleet-key-reveal"),onClick:()=>u({credentialReveal:!a.credentialReveal}),children:f(a.credentialReveal?"fleet-key-hide":"fleet-key-reveal")})]}),l.jsx("small",{children:f("fleet-key-local-help")}),e.mode==="new"&&(v==null?void 0:v.authConfigured)!==!0&&!a.credentialValue&&l.jsxs("label",{className:"nc-check nc-fleet-key-missing",children:[l.jsx("input",{type:"checkbox",checked:!!a.allowMissingCredential,onChange:E=>u({allowMissingCredential:E.target.checked})}),f("fleet-key-create-missing")]}),(v==null?void 0:v.notice)&&l.jsx("small",{className:"nc-fleet-provider-notice",children:f(`fleet-provider-notice-${v.notice}`)})]}),(v==null?void 0:v.notice)&&!y&&l.jsx("small",{className:"nc-fleet-provider-notice",children:f(`fleet-provider-notice-${v.notice}`)}),a.provider==="custom"&&l.jsxs(l.Fragment,{children:[l.jsx("input",{value:a.displayName,placeholder:f("fleet-provider-display"),onChange:E=>u({displayName:E.target.value})}),l.jsx("input",{value:a.baseUrl,placeholder:"https://api.example.com/v1",onChange:E=>u({baseUrl:E.target.value})}),((v==null?void 0:v.protocols)||[]).length>1&&l.jsx("select",{value:a.protocol,onChange:E=>u({protocol:E.target.value}),children:v.protocols.map(E=>l.jsx("option",{value:E,children:E},E))}),l.jsxs("div",{className:"nc-fleet-pair",children:[l.jsx("input",{value:a.envKey,placeholder:f("fleet-api-key-env"),onChange:E=>u({envKey:E.target.value})}),l.jsx("input",{value:a.providerId,placeholder:f("fleet-provider-id"),onChange:E=>u({providerId:E.target.value})})]}),l.jsxs("small",{children:[a.protocol," · ",f("fleet-custom-secret-help")]})]}),l.jsx("small",{children:f(a.client==="shell"?"fleet-shell-engine-help":"fleet-managed-help")})]}):l.jsxs(l.Fragment,{children:[l.jsx("input",{value:a.command,placeholder:f("command-path"),onChange:E=>u({command:E.target.value})}),l.jsx("textarea",{value:a.argsText,placeholder:f("args-lines"),onChange:E=>u({argsText:E.target.value})}),l.jsxs("label",{className:"nc-check",children:[l.jsx("input",{type:"checkbox",checked:a.rc,onChange:E=>u({rc:E.target.checked})})," ",f("fleet-remote-control")]}),l.jsxs("select",{value:a.promptMode,onChange:E=>u({promptMode:E.target.value}),children:[l.jsx("option",{value:"send-keys",children:"send-keys"}),l.jsx("option",{value:"flag",children:"flag"})]}),a.promptMode==="flag"&&l.jsx("input",{value:a.promptFlag,placeholder:"prompt flag",onChange:E=>u({promptFlag:E.target.value})}),l.jsxs("div",{className:"nc-fleet-pair",children:[l.jsx("input",{value:a.modelFlag,placeholder:"model flag",onChange:E=>u({modelFlag:E.target.value})}),l.jsx("input",{value:a.modelValue,placeholder:"model default",onChange:E=>u({modelValue:E.target.value})})]}),l.jsx("small",{children:f("env-write-only")}),h.map((E,$)=>l.jsxs("div",{className:"nc-fleet-env",children:[l.jsx("input",{value:E.key,disabled:E.configured,placeholder:"ENV_KEY",onChange:B=>{const K=h.slice();K[$]={...E,key:B.target.value},u({envRows:K})}}),l.jsx("input",{type:"password",value:E.value,placeholder:E.configured?"•••••• (unchanged)":"value",onChange:B=>{const K=h.slice();K[$]={...E,value:B.target.value},u({envRows:K})}}),l.jsx("button",{className:"nc-btn danger",onClick:()=>u({envRows:h.filter((B,K)=>K!==$)}),children:"×"})]},`${E.key}-${$}`)),l.jsx("button",{className:"nc-btn ghost",onClick:()=>u({envRows:[...h,{key:"",value:"",configured:!1}]}),children:"+ env"})]}),l.jsxs("div",{className:"nc-sheet-actions",children:[l.jsx("button",{className:"nc-btn ghost",onClick:()=>t(null),children:f("cancel")}),l.jsx("button",{className:"nc-btn primary",disabled:n||!a.id||C||a.kind==="custom"&&!a.command||a.kind==="managed"&&(v==null?void 0:v.requiresModel)&&!a.managedModel||a.kind==="managed"&&(v==null?void 0:v.credentialEnv)===!0&&!a.envKey||a.kind==="managed"&&a.provider==="custom"&&(!a.displayName||!a.baseUrl||!a.envKey||!a.providerId),onClick:s,children:f("save")})]})]})}function cj({state:e,setState:t,busy:n,onSave:s,onTest:o,profiles:a=[],canTest:u=!0}){const[h,p]=N.useState(null),[m,v]=N.useState(!1),y=e.form,w=x=>t({...e,form:{...y,...x}}),b=/^[^\x00-\x1f\x7f]{1,128}$/.test(y.id||""),S=!!(y.id||"").trim()&&!!(y.engine||"").trim()&&b,C=async()=>{p(null),v(!0);try{p(await o(y.engine,y.id))}catch(x){p({outcome:"unverified",detail:String(x&&x.message||x)})}v(!1)};return l.jsxs("div",{className:"nc-fleet-form",children:[l.jsxs("label",{className:"nc-field",children:[f("model-editor-engine"),l.jsxs("select",{value:y.engine||"",disabled:n||e.mode==="edit",onChange:x=>{p(null),w({engine:x.target.value})},children:[l.jsx("option",{value:"",children:"—"}),a.map(x=>l.jsx("option",{value:x.id,children:x.label?`${x.id} · ${x.label}`:x.id},x.id))]})]}),l.jsxs("label",{className:"nc-field",children:[f("model-editor-id"),l.jsx("input",{value:y.id||"",disabled:n||e.mode==="edit",placeholder:"qwen3.9-max",onChange:x=>{p(null),w({id:x.target.value})}})]}),l.jsx("small",{className:"nc-set-hint",children:f("model-editor-id-help")}),l.jsxs("label",{className:"nc-field",children:[f("model-editor-context"),l.jsx("input",{inputMode:"numeric",value:y.contextWindow||"",disabled:n,onChange:x=>w({contextWindow:x.target.value.replace(/[^0-9]/g,"").slice(0,9)})})]}),l.jsxs("label",{className:"nc-field",children:[f("model-editor-max-tokens"),l.jsx("input",{inputMode:"numeric",value:y.maxTokens||"",disabled:n,onChange:x=>w({maxTokens:x.target.value.replace(/[^0-9]/g,"").slice(0,9)})})]}),l.jsxs("label",{className:"nc-check",children:[l.jsx("input",{type:"checkbox",checked:y.reasoning===!0,disabled:n,onChange:x=>w({reasoning:x.target.checked})})," ",f("model-editor-reasoning")]}),l.jsxs("div",{className:"nc-set-row",children:[u&&l.jsx("button",{type:"button",className:"nc-btn ghost",disabled:n||m||!S,onClick:C,children:f(m?"model-test-running":"model-test")}),h&&l.jsxs("span",{className:`nc-model-test ${h.outcome}`,children:[f(`model-test-${h.outcome}`),h.outcome==="ok"&&Number.isInteger(h.latencyMs)?` · ${h.latencyMs}ms`:""]})]}),h&&h.detail&&l.jsx("small",{className:"nc-set-hint",children:h.detail}),h&&h.outcome==="unverified"&&l.jsx("small",{className:"nc-set-hint",children:f("model-test-unverified-help")}),l.jsxs("div",{className:"nc-sheet-actions",children:[l.jsx("button",{type:"button",className:"nc-btn ghost",onClick:()=>t(null),children:f("cancel")}),l.jsx("button",{type:"button",className:"nc-btn primary",disabled:n||!S,onClick:()=>s(y),children:f("save")})]})]})}function uj({token:e,route:t,targets:n=[],location:s,setLocation:o,state:a,setState:u,engines:h,mcpServers:p=[],busy:m,onSave:v}){var H;const[y,w]=N.useState(null),[b,S]=N.useState(""),C=a.form,x=L=>u({...a,form:{...C,...L}}),R=h.find(L=>L.id===C.engine),E=((H=R==null?void 0:R.managed)==null?void 0:H.client)==="shell",$=L=>{var O,T,F,k;const A=h.find(I=>I.id===L),z={...C.commands||{}};((O=R==null?void 0:R.managed)==null?void 0:O.client)==="shell"&&(C.command?z[C.engine]=C.command:delete z[C.engine]),x({engine:L,model:((T=C.models)==null?void 0:T[L])||((F=A==null?void 0:A.managed)==null?void 0:F.model)||((k=A==null?void 0:A.model)==null?void 0:k.value)||"",commands:z,command:z[L]||""})},B=L=>{const A={...C.commands||{}};L?A[C.engine]=L:delete A[C.engine],x({command:L,commands:A})},K=E&&/[|&;<>()`$*?{}\[\]~]/.test(C.command||""),V=[...new Set([...p||[],...Array.isArray(C.mcp)?C.mcp:[]])].sort(),Y=Array.isArray(C.mcp)?C.mcp.length?"some":"none":"all",te=L=>{var A;return x({mcp:L==="all"?void 0:L==="none"?[]:(A=C.mcp)!=null&&A.length?C.mcp:[...V]})},Q=L=>{const A=Array.isArray(C.mcp)?C.mcp:[];x({mcp:A.includes(L)?A.filter(z=>z!==L):[...A,L].sort()})},J=async L=>{try{const A=await Jh(e,L,t);w(A),x({cwd:A.path}),S("")}catch(A){S(String(A.message||A))}};return l.jsxs("div",{className:"nc-set-form nc-fleet-form",children:[l.jsx("b",{children:a.mode==="new"?f("fleet-new-cell"):`${f("edit")} ${C.id}`}),a.mode==="new"&&l.jsxs("label",{className:"nc-field",children:[f("location"),l.jsx("span",{className:"nc-req",children:" *"}),l.jsxs("select",{value:s,onChange:L=>{o(L.target.value),x({engine:""})},children:[l.jsx("option",{value:"",children:f("local")}),n.map(L=>l.jsxs("option",{value:L.route.join("/"),disabled:L.status&&L.status!=="up",children:[L.label,L.status&&L.status!=="up"?` · ${f("node-offline")}`:""]},L.route.join("/")))]})]}),l.jsx("input",{value:C.id,disabled:a.mode!=="new",placeholder:"id",onChange:L=>x({id:L.target.value})}),l.jsx("input",{value:C.label||"",maxLength:64,placeholder:f("fleet-cell-label"),onChange:L=>x({label:L.target.value})}),l.jsxs("div",{className:"nc-fleet-pair",children:[l.jsx("input",{value:C.cwd,placeholder:f("cwd"),onChange:L=>x({cwd:L.target.value})}),l.jsx("button",{className:"nc-btn ghost",onClick:()=>y?w(null):J(C.cwd),children:f("browse")})]}),y&&l.jsxs("div",{className:"nc-fs",children:[l.jsx("div",{className:"nc-fs-path",children:y.path}),l.jsxs("div",{className:"nc-fs-list",children:[y.parent&&l.jsxs("button",{className:"nc-fs-item nc-fs-nav",onClick:()=>J(y.parent),children:["↑ ",f("fs-parent")]}),(y.dirs||[]).map(L=>l.jsxs("button",{className:"nc-fs-item",onClick:()=>J(`${y.path.replace(/\/$/,"")}/${L}`),children:["📁 ",L]},L))]})]}),b&&l.jsx("div",{className:"nc-err",children:b}),l.jsx("select",{value:C.engine,onChange:L=>$(L.target.value),children:h.map(L=>l.jsx("option",{value:L.id,children:L.label},L.id))}),l.jsxs("label",{className:"nc-check",children:[l.jsx("input",{type:"checkbox",checked:!!C.boot,onChange:L=>x({boot:L.target.checked})})," ",f("fleet-boot")]}),E?l.jsxs(l.Fragment,{children:[l.jsx("input",{value:C.command||"",maxLength:4096,placeholder:f("fleet-shell-command-placeholder"),onChange:L=>B(L.target.value)}),l.jsx("small",{children:C.command?f("fleet-shell-command-help"):f("fleet-shell-interactive")}),K&&l.jsx("small",{className:"nc-note",children:f("fleet-shell-command-metachar")})]}):l.jsxs(l.Fragment,{children:[l.jsx("input",{value:C.model||"",list:"nc-cell-models",placeholder:f("fleet-model-override"),onChange:L=>x({model:L.target.value})}),l.jsx("datalist",{id:"nc-cell-models",children:((R==null?void 0:R.availableModels)||[]).map(L=>l.jsx("option",{value:L},L))}),l.jsx("textarea",{value:C.prompt||"",placeholder:f("cell-prompt"),onChange:L=>x({prompt:L.target.value})}),l.jsx("small",{children:f("cell-prompt-help")}),l.jsxs("label",{className:"nc-field",children:[f("cell-mcp"),l.jsxs("select",{value:Y,onChange:L=>te(L.target.value),children:[l.jsx("option",{value:"all",children:f("cell-mcp-all")}),l.jsx("option",{value:"none",children:f("cell-mcp-none")}),l.jsx("option",{value:"some",children:f("cell-mcp-some")})]})]}),Y==="some"&&l.jsx("div",{className:"nc-fleet-mcp-list",children:V.map(L=>l.jsxs("label",{className:"nc-check",children:[l.jsx("input",{type:"checkbox",checked:(C.mcp||[]).includes(L),onChange:()=>Q(L)})," ",L]},L))}),l.jsx("small",{children:f("cell-mcp-help")})]}),l.jsxs("div",{className:"nc-sheet-actions",children:[l.jsx("button",{className:"nc-btn ghost",onClick:()=>u(null),children:f("cancel")}),l.jsx("button",{className:"nc-btn primary",disabled:m||!C.id||!C.cwd||!C.engine,onClick:v,children:f("save")})]})]})}function B_({token:e,route:t=[],state:n,setState:s,busy:o,onSave:a}){const[u,h]=N.useState(null),[p,m]=N.useState([]),[v,y]=N.useState(""),w=Array.isArray(t)?t.join("/"):"";N.useEffect(()=>{let R=!0;return Jl(e,w?w.split("/"):[]).then(E=>{R&&(m(E.engines||[]),y(""))}).catch(E=>{R&&(m([]),y(String(E.message||E)))}),()=>{R=!1}},[e,w]);const b=n.form,S=R=>s({...n,form:{...b,...R}}),C=async R=>{try{const E=await Jh(e,R,t);h(E),S({cwd:E.path})}catch{}},x=!b.id&&b.tmuxSession?b.tmuxSession.replace(/[^A-Za-z0-9._-]+/g,"-").replace(/^-+|-+$/g,"").slice(0,32):b.id;return l.jsxs("div",{className:"nc-set-form nc-fleet-form",children:[l.jsxs("b",{children:[f("import-as-cell")," · ",b.tmuxSession]}),l.jsx("small",{children:f("import-help")}),l.jsx("input",{value:b.tmuxSession,disabled:!0,placeholder:"tmux session",readOnly:!0}),l.jsx("input",{value:b.id,placeholder:f("name"),onChange:R=>S({id:R.target.value})}),l.jsxs("div",{className:"nc-fleet-pair",children:[l.jsx("input",{value:b.cwd,placeholder:f("cwd"),onChange:R=>S({cwd:R.target.value})}),l.jsx("button",{className:"nc-btn ghost",type:"button",onClick:()=>u?h(null):C(b.cwd),children:f("browse")})]}),u&&l.jsxs("div",{className:"nc-fs",children:[l.jsx("div",{className:"nc-fs-path",children:u.path}),l.jsxs("div",{className:"nc-fs-list",children:[u.parent&&l.jsxs("button",{className:"nc-fs-item nc-fs-nav",onClick:()=>C(u.parent),children:["↑ ",f("fs-parent")]}),(u.dirs||[]).map(R=>l.jsxs("button",{className:"nc-fs-item",onClick:()=>C(`${u.path.replace(/\/$/,"")}/${R}`),children:["📁 ",R]},R))]})]}),l.jsxs("select",{value:b.engine,onChange:R=>S({engine:R.target.value}),children:[l.jsx("option",{value:"",children:f("import-engine-required")}),p.map(R=>l.jsx("option",{value:R.id,children:R.label},R.id))]}),l.jsxs("label",{className:"nc-check",children:[l.jsx("input",{type:"checkbox",checked:!!b.boot,onChange:R=>S({boot:R.target.checked})})," ",f("fleet-boot")]}),(n.err||v)&&l.jsx("div",{className:"nc-err",children:n.err||v}),l.jsxs("div",{className:"nc-sheet-actions",children:[l.jsx("button",{className:"nc-btn ghost",onClick:()=>s(null),children:f("cancel")}),l.jsx("button",{className:"nc-btn primary",disabled:o||!b.tmuxSession||!b.engine||!p.length,onClick:a,children:f(x?"import-as-cell":"save")})]})]})}function El(e){const t=Ks(e);return t===null?`~/${e}`:t?`~/${t}`:"~"}function dj(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 hj({token:e,route:t,cell:n,busy:s=!1,onSaved:o,onClose:a}){const[u,h]=N.useState(""),[p,m]=N.useState(null),[v,y]=N.useState(!1),[w,b]=N.useState(""),S=typeof(n==null?void 0:n.cwdSuggestion)=="string"&&Ks(n.cwdSuggestion)!==null?Ks(n.cwdSuggestion):null,[C,x]=N.useState(S),R=n==null?void 0:n.id,E=s||v,$=async Q=>{const J=Ks(Q);if(J===null){m({rel:"",dirs:[],loading:!1,err:f("fleet-cwd-repair-invalid")});return}m({rel:J,dirs:[],loading:!0,err:""});try{const H=await Jh(e,J,t),L=dj(H);m({rel:L,dirs:Array.isArray(H.dirs)?H.dirs:[],loading:!1,err:""})}catch(H){m({rel:J,dirs:[],loading:!1,err:String(H&&H.message||H)})}},B=Q=>{if(!p)return;const J=p.rel?`${p.rel}/${Q}`:Q;$(J)},K=()=>{p!=null&&p.rel&&$(p.rel.split("/").slice(0,-1).join("/"))},V=()=>{p&&(h(p.rel||""),m(null),b(""),x(null))},Y=()=>{C!==null&&(h(C),x(null),b(""))},te=async()=>{if(E)return;const Q=Ks(u);if(Q===null){b(f("fleet-cwd-repair-invalid"));return}const J=El(Q);let H=!0;try{H=window.confirm(f("fleet-cwd-repair-confirm").replace("{id}",String(R||"")).replace("{path}",J))}catch{H=!1}if(H){y(!0),b(""),x(null);try{const L=await Z_(e,R,{cwdRel:Q},t);o==null||o(L)}catch(L){const A=L&&L.data||{};if(A.code==="unportable-cwd"){b(f("fleet-cwd-repair-unportable"));const z=Array.isArray(A.cells)?A.cells.find(T=>T&&T.id===R):null,O=z&&typeof z.suggestion=="string"?z.suggestion:null;O!==null&&Ks(O)!==null&&x(O)}else b(String(L&&L.message||L))}finally{y(!1)}}};return l.jsxs("div",{className:"nc-set-form nc-fleet-form nc-cwd-repair",children:[l.jsx("b",{children:f("fleet-cwd-repair-title").replace("{id}",String(R||""))}),l.jsx("small",{className:"nc-set-info",children:f("fleet-cwd-repair-help")}),l.jsx("small",{className:"nc-cwd-no-source",children:f("fleet-cwd-repair-no-source-path")}),l.jsxs("label",{className:"nc-field",children:[f("cwd"),l.jsxs("div",{className:"nc-cwd-rel-row",children:[l.jsx("span",{className:"nc-cwd-rel-prefix",children:"~/"}),l.jsx("input",{value:u,placeholder:f("fleet-cwd-repair-placeholder"),autoComplete:"off",spellCheck:"false",autoCapitalize:"none",onChange:Q=>h(Q.target.value)}),l.jsx("button",{type:"button",className:"nc-btn ghost",disabled:E,onClick:()=>p?m(null):$(""),children:f(p?"close":"fleet-cwd-repair-browse")})]})]}),l.jsx("div",{className:"nc-cwd-preview",children:f("fleet-cwd-repair-preview").replace("{path}",El(u))}),p&&l.jsxs("div",{className:"nc-fs",children:[l.jsx("div",{className:"nc-fs-path",children:El(p.rel)}),l.jsxs("div",{className:"nc-fs-list",children:[p.rel&&l.jsxs("button",{type:"button",className:"nc-fs-item nc-fs-nav",onClick:K,children:["↑ ",f("fs-parent")]}),p.loading&&l.jsx("div",{className:"nc-fs-empty",children:"…"}),!p.loading&&p.dirs.length===0&&l.jsx("div",{className:"nc-fs-empty",children:f("fleet-cwd-repair-fs-empty")}),!p.loading&&p.dirs.map(Q=>l.jsxs("button",{type:"button",className:"nc-fs-item",onClick:()=>B(Q),children:["📁 ",Q]},Q))]}),p.err&&l.jsx("div",{className:"nc-err",children:p.err}),l.jsx("div",{className:"nc-sheet-actions",children:l.jsx("button",{type:"button",className:"nc-btn primary",disabled:E||p.loading||!!p.err,onClick:V,children:f("fleet-cwd-repair-use-current")})})]}),w&&l.jsx("div",{className:"nc-err",role:"alert",children:w}),C!==null&&l.jsxs("div",{className:"nc-cwd-suggestion",role:"status",children:[l.jsx("span",{children:f("fleet-cwd-repair-suggestion")}),l.jsx("button",{type:"button",className:"nc-btn ghost",onClick:Y,children:f("fleet-cwd-repair-use-suggestion").replace("{path}",El(C))})]}),l.jsxs("div",{className:"nc-sheet-actions",children:[l.jsx("button",{type:"button",className:"nc-btn ghost",disabled:v,onClick:a,children:f("cancel")}),l.jsx("button",{type:"button",className:"nc-btn primary",disabled:E,onClick:te,children:v?"…":f("save")})]})]})}function fj({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:[]}),[m,v]=N.useState(!1),[y,w]=N.useState(null),[b,S]=N.useState(null),[C,x]=N.useState({}),[R,E]=N.useState(null),[$,B]=N.useState(!1),[K,V]=N.useState(""),[Y,te]=N.useState(""),[Q,J]=N.useState(o),[H,L]=N.useState(!1),[A,z]=N.useState(null),[O,T]=N.useState(null),[F,k]=N.useState(null),[I,D]=N.useState(!1),[M,W]=N.useState([]),[G,ue]=N.useState(null),[le,he]=N.useState("manage"),we=N.useRef(!1),re=Q?Q.split("/"):[],_e=N.useCallback(async()=>{try{const j=await bs(e,re);p(j);try{const X=await ef(e,re);L(!!X.readonlyDefault)}catch{L(!1)}if(j.provider==="builtin"&&(j.capabilities||[]).includes("definitions")){const X=await Jl(e,re),ie=new Map((j.engines||[]).map(pe=>[pe.id,pe]));if(X.engines=(X.engines||[]).map(pe=>{var ke;return{...pe,availableModels:((ke=ie.get(pe.id))==null?void 0:ke.models)||[]}}),u(X),(j.capabilities||[]).includes("credentials"))try{W((await v0(e,re)).credentials||[])}catch{W([])}else W([])}V("")}catch(j){V(String(j.message||j))}finally{v(!0)}},[e,Q]);N.useEffect(()=>{_e();const j=setInterval(_e,5e3);return()=>clearInterval(j)},[_e]);const ze=new Set((h.cells||[]).filter(j=>j.active).map(j=>j.cell)),ut=h.provider==="builtin"&&(h.capabilities||[]).includes("edit"),nt=(h.capabilities||[]).includes("restore");N.useEffect(()=>{!s||we.current||!ut||!a.engines.length||(we.current=!0,E({mode:"new",form:O_(a.engines[0].id)}))},[s,ut,a.engines]);const Ne=async j=>{B(!0),V(""),te("");try{await j(),await _e()}catch(X){V(String(X.message||X))}B(!1)},jt=async(j,X)=>{const ie=await k0(e,j,X,re);return x(pe=>({...pe,[`${j}::${X}`]:ie})),ie},tn=j=>Ne(async()=>{const X={id:String(j.id||"").trim(),engine:String(j.engine||"").trim()};for(const ie of["contextWindow","maxTokens"]){const pe=String(j[ie]||"").trim();pe&&(X[ie]=Number(pe))}j.reasoning===!0&&(X.reasoning=!0),await S0(e,X,re),S(null),await _e()}),De=()=>Ne(async()=>{var Xe;const j=y.mode==="new",X=y.form,ie=a.managedCatalog||[],pe=X.kind==="managed"?Zo(ie,X):null,ke=typeof(pe==null?void 0:pe.credentialEnv)=="string"?pe.credentialEnv:"",me=ke&&X.credentialValue||"",xe=oj(X,j,ie);!j&&y.form.kind==="custom"&&!y.form.modelFlag&&(xe.model=null),!j&&y.form.kind==="custom"&&y.form.promptMode!=="flag"&&(xe.promptFlag=null);let We;if(j)We=await y0(e,xe,re);else{const je=y.original,_t=new Set(y.form.envRows.filter(Rt=>!Rt.remove).map(Rt=>Rt.key)),Sn=(je.envKeys||[]).filter(Rt=>!_t.has(Rt)),Rn=Object.fromEntries(y.form.envRows.filter(Rt=>!Rt.remove&&Rt.key&&(!Rt.configured||Rt.value!=="")).map(Rt=>[Rt.key,Rt.value]));We=await w0(e,je.id,xe,y.form.kind==="custom"?{set:Rn,remove:Sn}:void 0,re)}let lt=null;if(ke&&me)try{lt=await wg(e,ke,me,re),W(lt.credentials||[])}catch{throw await _e(),j&&w({mode:"edit",original:{...xe,id:X.id},form:{...X,credentialReveal:!1}}),new Error(f(j?"fleet-key-partial-create":"fleet-key-partial-edit"))}await _e(),w(null),te(f("fleet-saved"));const Ke=((Xe=((lt==null?void 0:lt.credentials)||[]).find(je=>je.envKey===ke))==null?void 0:Xe.activeCells)||[],pt=[...new Set([...(We==null?void 0:We.activeCells)||[],...Ke])];if(pt.length&&window.confirm(f("fleet-restart-confirm").replace("{cells}",pt.join(", "))))for(const je of pt)await $o(e,je,re)}),Tt=()=>Ne(async()=>{var lt,Ke,pt,Xe,je,_t;const j=R.mode==="new",X=R.form,ie={...j?{id:X.id}:{},cwd:X.cwd,engine:X.engine,boot:!!X.boot},pe={...X.commands||{}},ke=a.engines.find(Sn=>Sn.id===X.engine);((lt=ke==null?void 0:ke.managed)==null?void 0:lt.client)==="shell"&&typeof X.command=="string"&&X.command.length?pe[X.engine]=X.command:((Ke=ke==null?void 0:ke.managed)==null?void 0:Ke.client)==="shell"&&delete pe[X.engine],(Object.keys(pe).length||!j)&&(ie.commands=pe);const me=(X.label||"").trim();j?me&&(ie.label=me):ie.label=me||null,j?Array.isArray(X.mcp)&&(ie.mcp=X.mcp):ie.mcp=Array.isArray(X.mcp)?X.mcp:null,j?(((pt=ke==null?void 0:ke.managed)==null?void 0:pt.client)!=="shell"&&X.model&&(ie.model=X.model),((Xe=ke==null?void 0:ke.managed)==null?void 0:Xe.client)!=="shell"&&X.prompt&&(ie.prompt=X.prompt)):(ie.model=((je=ke==null?void 0:ke.managed)==null?void 0:je.client)==="shell"?null:X.model||null,((_t=ke==null?void 0:ke.managed)==null?void 0:_t.client)!=="shell"&&(ie.prompt=X.prompt||null));const xe=j?await C0(e,ie,re):await Z_(e,R.original.id,ie,re),We=j?X.id:R.original.id;E(null),te(f("fleet-saved")),!j&&(xe!=null&&xe.active)&&window.confirm(f("fleet-restart-confirm").replace("{cells}",We))&&await $o(e,We,re)}),Qe=t||H,vt=h.capabilities||[],mt=re.length>0&&Qe,it=j=>M.find(X=>{var ie;return(ie=X.engines)==null?void 0:ie.includes(j.id)})||null,dt=()=>Ne(async()=>{var ie;const j=await wg(e,G.envKey,G.value,re);W(j.credentials||[]),ue(null),te(f("fleet-credential-saved"));const X=((ie=(j.credentials||[]).find(pe=>pe.envKey===G.envKey))==null?void 0:ie.activeCells)||[];if(X.length&&window.confirm(f("fleet-restart-confirm").replace("{cells}",X.join(", "))))for(const pe of X)await $o(e,pe,re)}),ot=j=>Ne(async()=>{if(!window.confirm(f("fleet-credential-remove-confirm").replace("{key}",j.envKey)))return;const X=await _0(e,j.envKey,re);W(X.credentials||[]),te(f("fleet-credential-removed"))}),ht=j=>z({...j,route:Array.isArray(j==null?void 0:j.route)?j.route:re}),st=async j=>{if(!A)return;const X=A.cell||A.id,ie=Array.isArray(A.route)?A.route:re;if(j.action==="up"){const pe=await Xh(e,{cell:X,boot:!!j.boot,...j.engine?{engine:j.engine}:{},...j.model!==void 0?{model:j.model}:{},...j.permissionPolicy?{permissionPolicy:j.permissionPolicy}:{}},ie),ke=df(pe);ke&&te(ke.text)}else await Il(e,{cell:X,boot:!!j.boot},ie)},ft=(j,X)=>{V(""),T({mode:"new",route:Array.isArray(X)?X:re,form:{tmuxSession:j.name,id:"",engine:"",cwd:"",boot:!1},err:""})},be=()=>Ne(async()=>{const j=O.form;if(!j.engine){T({...O,err:f("import-engine-required")});return}await E0(e,{tmuxSession:j.tmuxSession,id:j.id||void 0,engine:j.engine,cwd:j.cwd||void 0,boot:!!j.boot},j.route||re),T(null),te(f("fleet-saved"))}),ce=({engineRows:j=[],cellRows:X=[],models:ie=[]})=>Ne(async()=>{const pe=j.filter(je=>je.selected),ke=pe.map(je=>ob(je.engine));if(ke.some(je=>!je))throw new Error(f("fleet-backup-invalid-engine"));const me=pe.filter(je=>je.exists).map(je=>je.engine.id);if(me.length&&!window.confirm(f("fleet-backup-confirm-engine-overwrite").replace("{engines}",me.join(", "))))return;const xe=[...new Set([...a.engines.map(je=>je.id),...ke.map(je=>je.id)])],We=[];for(const je of X.filter(_t=>_t.selected)){const _t=nj(je.cell,je.engine,xe);if(!_t)throw new Error(`${je.cell.id}: ${f("fleet-backup-engine-missing")}`);We.push(_t)}const lt=X.filter(je=>je.selected&&je.exists).map(je=>je.cell.id);if(lt.length&&!window.confirm(f("fleet-backup-confirm-overwrite").replace("{cells}",lt.join(", "))))return;const Ke=ke.length?await j0(e,ke,me.length>0,re,ie):{needsRestart:[]},pt=We.length?await N0(e,We,re):{needsRestart:[]},Xe=[...new Set([...Ke.needsRestart||[],...pt.needsRestart||[]])];D(!1),te(`${f("fleet-backup-restored").replace("{n}",String(We.length))}${ke.length?` · ${ke.length} ${f("fleet-engines").toLowerCase()}`:""}${Xe.length?` · ${f("fleet-backup-needs-restart").replace("{cells}",Xe.join(", "))}`:""}`)}),U=l.jsxs("label",{className:"nc-field",children:[f("location"),l.jsxs("select",{value:Q,onChange:j=>{J(j.target.value),w(null),E(null),V(""),te(""),L(!1),v(!1),p({available:!1,capabilities:[]}),u({engines:[],cells:[],managedCatalog:[]}),W([]),ue(null)},children:[l.jsx("option",{value:"",children:f("local")}),n.map(j=>l.jsxs("option",{value:j.route.join("/"),disabled:j.status&&j.status!=="up",children:[j.label,j.status&&j.status!=="up"?` · ${f("node-offline")}`:""]},j.route.join("/")))]})]}),ne=l.jsxs("div",{className:"nc-fleet-view-tabs",role:"tablist","aria-label":f("tab-fleet"),children:[l.jsx("button",{type:"button",role:"tab","aria-selected":le==="manage",className:`nc-set-tabbtn${le==="manage"?" on":""}`,onClick:()=>he("manage"),children:f("fleet-manage-location")}),l.jsx("button",{type:"button",role:"tab","aria-selected":le==="overview",className:`nc-set-tabbtn${le==="overview"?" on":""}`,onClick:()=>he("overview"),children:f("fleet-network-overview")})]});return m?ut?l.jsxs("div",{className:"nc-set-tab nc-fleet-editor",children:[ne,le==="overview"?l.jsxs(l.Fragment,{children:[l.jsx("div",{className:"nc-set-info",children:f("fleet-overview-help")}),l.jsx($d,{token:e,targets:n,readonly:t,onPower:ht,onImport:ft})]}):l.jsxs(l.Fragment,{children:[l.jsx("div",{className:"nc-set-info",children:f("fleet-manage-help")}),U,l.jsxs("div",{className:"nc-set-row nc-fleet-backup-actions",children:[l.jsx("button",{className:"nc-btn ghost",disabled:Qe||$,onClick:()=>{V(""),D(!0)},children:f("fleet-backup")}),l.jsx("small",{children:f("fleet-backup-help")})]}),l.jsxs("div",{className:"nc-fleet-section-head",children:[l.jsx("b",{children:f("fleet-cells")}),l.jsx("span",{className:"nc-fleet-head-actions",children:l.jsxs("button",{className:"nc-btn primary",disabled:Qe||$||!a.engines.length,onClick:()=>{var j;V(""),E({mode:"new",form:O_((j=a.engines[0])==null?void 0:j.id)})},children:["+ ",f("add")]})})]}),a.cells.map(j=>{const X=ze.has(j.id),ie=j.needsRepair===!0;return l.jsxs("div",{className:"nc-fleet-item",children:[l.jsxs("span",{children:[l.jsx("b",{children:j.id}),j.label?l.jsxs("small",{className:"nc-fleet-label",children:[" ",j.label]}):null,l.jsxs("small",{children:[j.engine," · ",ie?l.jsx("span",{className:"nc-fleet-tag nc-fleet-tag-warn",children:f("fleet-cwd-needs-repair")}):j.cwd,X?` · ${f("service-active")}`:` · ${f("cell-off")}`]})]}),l.jsxs("span",{children:[X&&vt.includes("down")&&l.jsx("button",{className:"nc-btn ghost",disabled:Qe||$,onClick:()=>Ne(()=>Il(e,{cell:j.id},re)),children:f("stop")}),!X&&vt.includes("up")&&l.jsx("button",{className:"nc-btn primary",disabled:Qe||$,onClick:()=>ht({cell:j.id,id:j.id,engine:j.engine,model:j.model,models:j.models,permissionPolicies:j.permissionPolicies,active:!1,boot:j.boot}),children:f("start")}),X&&vt.includes("restart")&&l.jsx("button",{className:"nc-btn ghost",disabled:Qe||$,onClick:()=>Ne(()=>$o(e,j.id,re)),children:f("restart")}),ie?l.jsx("button",{className:"nc-btn ghost",disabled:Qe||$,onClick:()=>{V(""),k(j)},children:f("fleet-cwd-repair")}):l.jsx("button",{className:"nc-btn ghost",disabled:Qe||$,onClick:()=>{var pe;V(""),E({mode:"edit",original:j,form:{...j,commands:{...j.commands||{}},command:((pe=j.commands)==null?void 0:pe[j.engine])||""}})},children:f("edit")}),l.jsx("button",{className:"nc-btn danger",disabled:Qe||$,onClick:()=>Ne(async()=>{window.confirm(f("fleet-remove-cell").replace("{id}",j.id))&&await ey(e,j.id,!0,re)}),children:"×"})]})]},j.id)}),l.jsxs("div",{className:"nc-fleet-section-head",children:[l.jsx("b",{children:f("fleet-engines")}),l.jsxs("button",{className:"nc-btn primary",disabled:Qe||$,onClick:()=>{V(""),w({mode:"new",form:ij()})},children:["+ ",f("add")]})]}),a.engines.map(j=>{var ie,pe;const X=it(j);return l.jsxs("div",{className:"nc-fleet-item",children:[l.jsxs("span",{children:[l.jsx("b",{children:j.label}),l.jsx("small",{children:j.managed?`${j.id} · ${j.managed.client} / ${j.managed.provider} · ${(ie=j.managedInfo)!=null&&ie.configured?f("fleet-ready"):((pe=j.managedInfo)==null?void 0:pe.reason)||f("fleet-not-ready")}`:`${j.id} · ${j.command}`}),X&&l.jsxs("small",{children:[X.envKey," · ",f(`fleet-credential-source-${X.source||"missing"}`)]})]}),l.jsxs("span",{children:[X&&l.jsx("button",{className:"nc-btn ghost",disabled:Qe||$,onClick:()=>{V(""),ue({envKey:X.envKey,value:""})},children:X.configured?f("fleet-credential-change"):f("fleet-credential-set")}),(X==null?void 0:X.source)==="local"&&l.jsx("button",{className:"nc-btn danger",disabled:Qe||$,onClick:()=>ot(X),children:f("fleet-credential-forget")}),l.jsx("button",{className:"nc-btn ghost",disabled:Qe||$,onClick:()=>{V(""),w({mode:"edit",original:j,form:rj(j)})},children:f("edit")}),l.jsx("button",{className:"nc-btn danger",disabled:Qe||$,onClick:()=>Ne(async()=>{window.confirm(f("fleet-remove-engine").replace("{id}",j.id))&&await b0(e,j.id,re)}),children:"×"})]})]},j.id)}),l.jsxs("div",{className:"nc-fleet-section-head",children:[l.jsx("b",{children:f("fleet-models")}),l.jsxs("button",{className:"nc-btn primary",disabled:Qe||$,onClick:()=>{V(""),S({mode:"new",form:{id:"",engine:""}})},children:["+ ",f("add")]})]}),!(a.models||[]).length&&l.jsx("small",{className:"nc-set-hint",children:f("fleet-no-models")}),(a.models||[]).map(j=>{const X=`${j.engine}::${j.id}`,ie=C[X],pe=(a.engines||[]).some(ke=>ke.managed&&ke.managed.model===j.id);return l.jsxs("div",{className:"nc-fleet-item",children:[l.jsxs("span",{children:[l.jsx("b",{children:j.id}),l.jsxs("small",{children:[j.engine,j.contextWindow?` · ${j.contextWindow}`:"",pe?` · ${f("model-in-use")}`:""]}),ie&&l.jsxs("small",{className:`nc-model-test ${ie.outcome}`,children:[f(`model-test-${ie.outcome}`),ie.outcome==="ok"&&Number.isInteger(ie.latencyMs)?` · ${ie.latencyMs}ms`:""]})]}),l.jsxs("span",{children:[vt.includes("model-test")&&l.jsx("button",{className:"nc-btn ghost",disabled:$||mt,onClick:()=>Ne(()=>jt(j.engine,j.id)),children:f("model-test")}),l.jsx("button",{className:"nc-btn danger",disabled:Qe||$,onClick:()=>Ne(()=>x0(e,j.id,j.engine,re)),children:"×"})]})]},X)})]}),b&&l.jsx(fs,{onClose:()=>S(null),label:f("fleet-models"),error:K,children:l.jsx(cj,{state:b,setState:S,busy:$,onSave:tn,onTest:jt,profiles:a.managedCatalog||[],canTest:vt.includes("model-test")&&!mt})}),y&&l.jsx(fs,{onClose:()=>w(null),label:f("fleet-new-engine"),error:K,children:l.jsx(lj,{state:y,setState:w,busy:$,onSave:De,catalog:a.managedCatalog||[]})}),R&&l.jsx(fs,{onClose:()=>E(null),label:f("fleet-new-cell"),error:K,children:l.jsx(uj,{token:e,route:re,targets:n,location:Q,setLocation:J,state:R,setState:E,engines:a.engines,mcpServers:a.mcpServers||[],busy:$,onSave:Tt})}),F&&l.jsx(fs,{onClose:()=>k(null),label:f("fleet-cwd-repair-title").replace("{id}",F.id),error:"",children:l.jsx(hj,{token:e,route:re,cell:F,busy:$,onSaved:async()=>{k(null),te(f("fleet-cwd-repaired")),await _e()},onClose:()=>k(null)})}),Y&&l.jsx("div",{className:"nc-set-note",children:Y}),K&&l.jsx("div",{className:"nc-err",children:K}),I&&l.jsx(fs,{onClose:()=>D(!1),label:f("fleet-backup"),error:K,children:l.jsx(aj,{cells:a.cells,engines:a.engines,models:a.models||[],busy:$,canRestore:nt,onRestore:ce,onClose:()=>D(!1)})}),G&&l.jsx(fs,{onClose:()=>ue(null),label:f("fleet-credential-title"),error:K,children:l.jsxs("div",{className:"nc-fleet-form nc-credential-form",children:[l.jsx("b",{children:f("fleet-credential-title")}),l.jsx("small",{children:f("fleet-credential-help")}),l.jsxs("label",{className:"nc-field",children:[G.envKey,l.jsx("input",{type:"password",autoComplete:"off",spellCheck:"false",autoCapitalize:"none",value:G.value,onChange:j=>ue({...G,value:j.target.value})})]}),l.jsxs("div",{className:"nc-sheet-actions",children:[l.jsx("button",{className:"nc-btn ghost",onClick:()=>ue(null),children:f("cancel")}),l.jsx("button",{className:"nc-btn primary",disabled:$||!G.value,onClick:dt,children:f("save")})]})]})}),O&&l.jsx(fs,{onClose:()=>T(null),label:f("import-as-cell"),error:K,children:l.jsx(B_,{token:e,route:O.route||re,state:O,setState:T,busy:$,onSave:be})}),A&&l.jsx(Bl,{cell:A,token:e,route:Array.isArray(A.route)?A.route:re,onConfirm:async j=>{try{await st(j)}finally{await _e()}},onClose:()=>z(null)})]}):l.jsxs("div",{className:"nc-set-tab",children:[ne,le==="overview"?l.jsxs(l.Fragment,{children:[l.jsx("div",{className:"nc-set-info",children:f("fleet-overview-help")}),l.jsx($d,{token:e,targets:n,readonly:t,onPower:ht,onImport:ft})]}):l.jsxs(l.Fragment,{children:[U,l.jsxs("div",{className:"nc-set-info",children:[f(K?"fleet-editor-load-error":"fleet-editor-unavailable"),!K&&h.reason?` ${h.reason}`:""]})]}),K&&l.jsx("div",{className:"nc-err",children:K}),O&&l.jsx(fs,{onClose:()=>T(null),label:f("import-as-cell"),error:K,children:l.jsx(B_,{token:e,route:O.route||re,state:O,setState:T,busy:$,onSave:be})}),A&&l.jsx(Bl,{cell:A,token:e,route:Array.isArray(A.route)?A.route:re,onConfirm:async j=>{try{await st(j)}finally{await _e()}},onClose:()=>z(null)})]}):l.jsxs("div",{className:"nc-set-tab",children:[ne,le==="overview"?l.jsxs(l.Fragment,{children:[l.jsx("div",{className:"nc-set-info",children:f("fleet-overview-help")}),l.jsx($d,{token:e,targets:n,readonly:t,onPower:ht,onImport:ft})]}):l.jsxs(l.Fragment,{children:[U,l.jsx("div",{className:"nc-set-info",children:f("fleet-editor-loading")})]})]})}const Bf="nc_notification_speech_v1",Nl="nc-notification-speech",Hh="nc-notification-speech-preview",pj=320,mj=2,gj=3e4,vj=1e4,_j=6e4,yj=64,z_=Object.freeze({enabled:!1}),wj=Object.freeze({it:"it-IT",en:"en-US",es:"es-ES"}),bj=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"])}),zf=new WeakSet;function $f(e){return{enabled:(e&&typeof e=="object"&&!Array.isArray(e)?e:{}).enabled===!0}}function lb(){try{return typeof localStorage<"u"?localStorage:null}catch{return null}}function $_(e=lb()){if(!e)return{...z_};try{return $f(JSON.parse(e.getItem(Bf)||"null"))}catch{return{...z_}}}function Sj(e,t=lb()){const n=$f(e);if(t)try{t.setItem(Bf,JSON.stringify(n))}catch{}return n}function Ur(){try{return typeof window<"u"?window:null}catch{return null}}function ea(e=Ur()){try{return!!(e&&e.speechSynthesis&&typeof e.speechSynthesis.speak=="function"&&typeof e.SpeechSynthesisUtterance=="function")}catch{return!1}}function cb(e=Ur()){return!!(e&&(typeof e=="object"||typeof e=="function")&&zf.has(e))}function Wh(e=Ur()){e&&(typeof e=="object"||typeof e=="function")&&zf.delete(e)}function Tr(e){const t=String(e||"").trim().toLowerCase().split("-")[0];return wj[t]||""}function uc(e){return String(e||"").normalize("NFC").replace(/[\p{Cc}\p{Cf}]+/gu," ").replace(/\s+/g," ").trim()}function xj(e){const t=uc(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(bj).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 kj(e,t){const n=Tr(e&&e.lang);return n||Tr(xj(e&&e.body))||Tr(t)}function ub(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 db(e,t){const n=Tr(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 F_(e){return uc(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 Cj(e,t=pj){const n=F_(e&&e.title),s=F_(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 Ej(e){try{return!!(e&&e.visibilityState==="visible"&&typeof e.hasFocus=="function"&&e.hasFocus())}catch{return!1}}function hb(e=Ur()){if(!ea(e))return!1;try{return e.speechSynthesis.cancel(),!0}catch{return!1}}function Nj(e){try{e&&typeof e.dispatchEvent=="function"&&typeof e.Event=="function"&&e.dispatchEvent(new e.Event(Hh))}catch{}}function jj(e,t,n=Ur(),s={}){var m;if(Wh(n),!ea(n))return Promise.resolve(!1);const o=uc(e);if(!o||(m=s.signal)!=null&&m.aborted)return Promise.resolve(!1);const a=Number.isFinite(s.timeoutMs)&&s.timeoutMs>0?s.timeoutMs:vj,u=s.setTimer||((v,y)=>setTimeout(v,y)),h=s.clearTimer||(v=>clearTimeout(v)),p=s.signal;return Nj(n),new Promise(v=>{let y=!1,w=!1,b=null,S=null;const C=x=>{if(!y){if(y=!0,p&&S&&p.removeEventListener("abort",S),b!==null&&h(b),x)zf.add(n);else try{n.speechSynthesis.cancel()}catch{}v(x)}};S=()=>C(!1),p&&p.addEventListener("abort",S,{once:!0});try{n.speechSynthesis.cancel();const x=new n.SpeechSynthesisUtterance(o);x.lang=Tr(t);const R=db(ub(n),x.lang);R&&(x.voice=R),x.onstart=()=>{w=!0},x.onend=()=>C(w),x.onerror=()=>C(!1),b=u(()=>C(!1),a),n.speechSynthesis.speak(x)}catch{C(!1)}})}function Rj(e={}){const t=e.scope||Ur(),n=e.document||t&&t.document,s=Number.isInteger(e.maxPending)&&e.maxPending>=0?e.maxPending:mj,o=Number.isFinite(e.watchdogMs)&&e.watchdogMs>0?e.watchdogMs:gj,a=Number.isFinite(e.dedupWindowMs)&&e.dedupWindowMs>0?e.dedupWindowMs:_j,u=Number.isInteger(e.maxDedup)&&e.maxDedup>0?e.maxDedup:yj,h=e.now||Date.now,p=e.setTimer||((H,L)=>setTimeout(H,L)),m=e.clearTimer||(H=>clearTimeout(H)),v=e.isPrimed||(()=>cb(t)),y=t&&t.speechSynthesis;let w=null,b=null,S=[],C=[],x=()=>{};const R=new Map,E=()=>{C=ub(t)};if(E(),y&&typeof y.addEventListener=="function")y.addEventListener("voiceschanged",E),x=()=>y.removeEventListener("voiceschanged",E);else if(y&&"onvoiceschanged"in y){const H=y.onvoiceschanged,L=(...A)=>{E(),typeof H=="function"&&H.apply(y,A)};y.onvoiceschanged=L,x=()=>{y.onvoiceschanged===L&&(y.onvoiceschanged=H)}}const $=H=>{if(H&&typeof H.id=="string"&&H.id)return`id:${H.id}`;const L=Number(H&&H.ts),A=uc(H&&H.title);return Number.isFinite(L)&&A?`frame:${L}:${A}`:""},B=H=>{if(!H)return!0;const L=h();for(const[A,z]of R)L-z>=a&&R.delete(A);if(R.has(H))return!1;for(R.set(H,L);R.size>u;)R.delete(R.keys().next().value);return!0},K=()=>{b!==null&&m(b),b=null},V=()=>{K(),w&&(w.onend=null,w.onerror=null,w=null),hb(t)},Y=H=>{if(!ea(t))return S=[],"unsupported";let L;try{L=new t.SpeechSynthesisUtterance(H.text),L.lang=Tr(H.lang);const z=db(C,L.lang);z&&(L.voice=z)}catch{return S=[],"error"}w=L;const A=()=>{if(w!==L)return;K(),w=null,L.onend=null,L.onerror=null;const z=S.shift();z&&Y(z)};L.onend=A,L.onerror=A;try{return b=p(()=>{if(w!==L)return;w=null,L.onend=null,L.onerror=null;try{t.speechSynthesis.cancel()}catch{}K();const z=S.shift();z&&Y(z)},o),t.speechSynthesis.speak(L),"speaking"}catch{return A(),"error"}},te=(H,L)=>{if(!ea(t))return"unsupported";const A=Cj(H);if(!A)return"empty";if(!B($(H)))return"duplicate";if(!Ej(n))return"inactive";if(!v())return"unprimed";const z={text:A,lang:L};return H&&H.urgency==="high"?(S=[],V(),Y(z)):w?s===0?"dropped":(S.length>=s&&S.shift(),S.push(z),"queued"):Y(z)},Q=()=>{S=[],V()};return{enqueue:te,stop:Q,dispose:()=>{Q(),x(),x=()=>{}}}}function fb(){const[e,t]=N.useState($_);N.useEffect(()=>{const s=o=>{if((o==null?void 0:o.type)==="storage"&&o.key!==Bf&&o.key!==null)return;const a=(o==null?void 0:o.type)===Nl?$f(o.detail):$_();t(a)};return window.addEventListener(Nl,s),window.addEventListener("storage",s),()=>{window.removeEventListener(Nl,s),window.removeEventListener("storage",s)}},[]);const n=N.useCallback(s=>{const o=Sj({enabled:s===!0});return t(o),window.dispatchEvent(new CustomEvent(Nl,{detail:o})),o.enabled},[]);return[e.enabled,n]}function Pj({text:e}){const[t,n]=N.useState(!1),s=async()=>{try{await navigator.clipboard.writeText(e),n(!0),setTimeout(()=>n(!1),1500)}catch{}};return l.jsxs("div",{className:"nc-set-copyline",children:[l.jsx("code",{children:e}),l.jsxs("button",{type:"button",className:"nc-btn ghost",onClick:s,children:[l.jsx(Ge,{name:"copy",size:14})," ",f(t?"copied":"copy")]})]})}function Aj({value:e}){const[t,n]=N.useState("");return N.useEffect(()=>{let s=!0;return a2.toDataURL(e,{margin:1,width:220}).then(o=>{s&&n(o)}).catch(()=>{}),()=>{s=!1}},[e]),t?l.jsx("img",{src:t,width:"220",height:"220",alt:"NexusCrew pairing QR"}):null}function Lj({token:e,nodes:t,roster:n,settings:s,readonly:o,refresh:a,refreshAliases:u,vlUnavailable:h=[]}){const[p,m]=N.useState(null),[v,y]=N.useState(null),[w,b]=N.useState(null),[S,C]=N.useState({ssh:"",sshPort:"",name:""}),[x,R]=N.useState(""),[E,$]=N.useState(""),[B,K]=N.useState(!1),[V,Y]=N.useState(null),te=Date.now(),Q=s&&s.deviceName||"",J=(t||[]).filter(k=>k&&k.direction==="outbound"&&k.name&&k.ssh),H=J.find(k=>k.name===x)||J[0]||null,L=H?Xd(H.tunnel,te):null,A=H!=null&&H.shared?L!=null&&L.up?"share-local-active":"share-local-pending":L!=null&&L.up?"share-local-private":"share-local-private-down",z=[{key:"peer-group-hubs",rows:(t||[]).filter(k=>k.kind!=="transitive"&&k.kind!=="vl"&&k.relation!=="client")},{key:"peer-group-clients",rows:(t||[]).filter(k=>k.kind!=="transitive"&&k.kind!=="vl"&&k.relation==="client")},{key:"peer-group-routed",rows:(t||[]).filter(k=>k.kind==="transitive")},{key:"peer-group-vl",rows:(t||[]).filter(k=>k.kind==="vl")}],O=V&&(t||[]).find(k=>`${k.kind||"direct"}:${k.nodeId||k.name}`===V)||null,T=async k=>{if(H){m(null),y(`${H.name}:share`);try{const I=await B0(e,H.name,k);await a(),I&&I.reversePoolPending===!0&&m(`${H.name}: ${f("share-reverse-pool-pending")}`)}catch(I){const D=I!=null&&I.data&&I.data.shared===!1?I.data:null;if(D)try{await a()}catch{}const M=I!=null&&I.data&&typeof I.data.hint=="string"?I.data.hint:"",W=(D==null?void 0:D.revoked)===!0&&(D==null?void 0:D.localReconcilePending)===!0?f("share-off-local-reconcile-pending"):(D==null?void 0:D.revoked)===!1&&(D==null?void 0:D.reconcilePending)===!0?f("share-off-hub-reconcile-pending"):"",G=I!=null&&I.data&&I.data.reversePoolPending===!0?f("share-reverse-pool-pending"):"",ue=I!=null&&I.data&&typeof I.data.code=="string"?I.data.code:"",le=I!=null&&I.data&&typeof I.data.detail=="string"?I.data.detail.trim():"",he=le&&le!==String(I.message||"")?le:"";m(`${H.name}: ${String(I.message||I)}${ue?` [${ue}]`:""}${he?` — ${he}`:""}${M?` — ${M}`:""}${W?` — ${W}`:""}${G?` — ${G}`:""}`)}y(null)}},F=async()=>{m(null);const k=_s(S.name||E||Q||"NexusCrew"),I=Fx({name:k,ssh:S.ssh,sshPort:S.sshPort});if(!I.ok){m(f(I.error));return}y("invite");try{b(await M0(e,{...E||Q?{label:E||Q}:{},name:k,ssh:I.value.ssh,...I.value.sshPort?{sshPort:I.value.sshPort}:{}}))}catch(D){m(String(D.message||D))}y(null)};return l.jsxs("div",{className:"nc-set-tab",children:[l.jsx("div",{className:"nc-sheet-label",children:f("peer-inventory-title")}),(t||[]).length===0&&l.jsx("div",{className:"nc-empty",children:f("no-nodes")}),z.map(k=>k.rows.length>0&&l.jsxs("div",{className:"nc-peer-group",children:[l.jsxs("div",{className:"nc-peer-group-title",children:[f(k.key)," ",l.jsx("span",{children:k.rows.length})]}),k.rows.map(I=>{const D=y2(I);if(!D)return null;const M=`${I.kind||"direct"}:${I.nodeId||I.name}`,W=D.routed?{up:D.reach.up,since:null}:Xd(I.tunnel,te);return l.jsxs("button",{type:"button",className:`nc-set-node nc-node-row${D.routed?" routed":""}`,"aria-label":`${D.title} — ${f("node-detail-open")}`,onClick:()=>Y(M),children:[l.jsx("span",{className:`nc-dot ${D.reach.up?"on":""}`}),l.jsxs("span",{className:"nc-node-row-text",children:[l.jsx("b",{children:D.title}),l.jsxs("small",{children:[D.routed?D.routeLabel:`${D.subtitle} · ${f(D.exposure.shortKey)}`,!D.routed&&D.exposure.shortKey==="visibility-selected"?` (${D.exposure.count})`:""]})]}),l.jsxs("span",{className:`nc-set-tunnel${D.reach.up?" up":""}`,children:[f(D.reach.key),W.since?` · ${W.since}`:""]}),l.jsx("span",{className:"nc-node-row-more",children:l.jsx(Ge,{name:"chevronDown",size:14})})]},M)})]},k.key)),h.length>0&&l.jsxs("div",{className:"nc-err",children:[f("vl-owners-unavailable"),": ",h.map(k=>k.label||k.route.join("/")).join(", ")]}),O&&l.jsx(M2,{node:O,nodes:t||[],token:e,readonly:o,refresh:a,onClose:()=>Y(null)}),(n||[]).some(k=>!k.direct&&k.instanceId)&&l.jsxs("div",{className:"nc-set-form",children:[l.jsx("div",{className:"nc-sheet-label",children:f("routed-node-aliases")}),l.jsx("small",{className:"nc-set-hint",children:f("routed-node-aliases-help")}),(n||[]).filter(k=>!k.direct&&k.instanceId).map(k=>l.jsxs("div",{className:"nc-set-node",children:[l.jsxs("div",{className:"nc-set-node-head",children:[l.jsx("span",{className:`nc-dot ${k.status==="up"?"on":""}`}),l.jsx("b",{children:k.label||k.name}),l.jsx("small",{children:(k.route||[]).join(" › ")})]}),l.jsxs("div",{className:"nc-set-node-actions",children:[l.jsx("button",{type:"button",className:"nc-btn ghost",disabled:o||!!v,onClick:async()=>{const I=window.prompt(f("node-local-alias"),k.alias||"");if(I!=null){if(I.trim()&&!Ir(I.normalize("NFC"))){m(f("err-label"));return}y(`${k.instanceId}:alias`),m(null);try{I.trim()?await I0(e,k.instanceId,I):await xg(e,k.instanceId),u()}catch(D){m(String(D.message||D))}y(null)}},children:f("alias-on-device")}),k.alias&&l.jsx("button",{type:"button",className:"nc-btn ghost",disabled:o||!!v,onClick:async()=>{y(`${k.instanceId}:alias-reset`),m(null);try{await xg(e,k.instanceId),u()}catch(I){m(String(I.message||I))}y(null)},children:f("reset-alias")})]})]},k.instanceId))]}),H&&l.jsxs("div",{className:"nc-set-form nc-local-share",children:[l.jsx("div",{className:"nc-sheet-label",children:f("share-local-heading")}),J.length>1&&l.jsxs("label",{className:"nc-field",children:[f("share-local-hub"),l.jsx("select",{value:H.name,disabled:o||!!v,onChange:k=>R(k.target.value),children:J.map(k=>l.jsx("option",{value:k.name,children:k.label||k.name},k.name))})]}),l.jsxs("label",{className:"nc-check nc-node-share",children:[l.jsx("input",{type:"checkbox",checked:H.shared===!0,disabled:o||!!v,onChange:k=>T(k.target.checked)}),l.jsxs("span",{children:[l.jsx("b",{children:f("share-local-through").replace("{device}",Q||f("local")).replace("{hub}",H.label||H.name)}),l.jsx("small",{children:f(H.shared?"share-node-on-desc":"share-node-off-desc")})]})]}),l.jsx("div",{className:`nc-set-test${H.shared&&(L!=null&&L.up)?" ok":L!=null&&L.up?"":" ko"}`,children:f(A)}),!(L!=null&&L.up)&&l.jsx("button",{type:"button",className:"nc-btn ghost",disabled:o||!!v,onClick:()=>T(H.shared===!0),children:f("share-local-reconnect")})]}),l.jsx(Xw,{token:e,deviceDefault:Q,localNodeId:s&&s.nodeId||"",localNameDefault:s&&s.localName||"",readonly:o,onSuccess:a}),l.jsxs("div",{className:"nc-set-form",children:[l.jsx("div",{className:"nc-sheet-label",children:f("invite-node")}),l.jsx("small",{className:"nc-set-hint",children:f("invite-v2-hint")}),l.jsxs("div",{className:"nc-set-info nc-invite-endpoint",children:[f("invite-target-local"),": ",l.jsx("b",{children:Q||f("invite-target-this")})]}),l.jsxs("label",{className:"nc-field",children:[f("invite-endpoint-label"),l.jsx("input",{placeholder:"user@host",value:S.ssh,disabled:o,onChange:k=>C({...S,ssh:k.target.value})}),l.jsx("small",{className:"nc-set-hint",children:f("invite-endpoint-needed")})]}),J.length>0&&l.jsx("small",{className:"nc-set-hint nc-invite-hub-hint",children:f("invite-hub-only")}),B&&l.jsxs("div",{className:"nc-invite-advanced",children:[l.jsxs("label",{className:"nc-field",children:[f("node-ssh-port-label"),l.jsx("input",{inputMode:"numeric",placeholder:"22",value:S.sshPort,disabled:o,onChange:k=>C({...S,sshPort:k.target.value.replace(/[^0-9]/g,"").slice(0,5)})})]}),l.jsxs("label",{className:"nc-field",children:[f("device-name-label"),l.jsx("input",{placeholder:Q||"NexusCrew",value:E,disabled:o,onChange:k=>$(k.target.value)}),l.jsx("small",{className:"nc-set-hint",children:f("device-name-hint")})]}),l.jsxs("label",{className:"nc-field",children:[f("node-name-label"),l.jsx("input",{placeholder:_s(E||Q||f("node-name-ph")),value:S.name,disabled:o,onChange:k=>C({...S,name:k.target.value?_s(k.target.value):""})})]})]}),l.jsxs("div",{className:"nc-set-row nc-invite-actions",children:[l.jsx("button",{type:"button",className:"nc-btn primary",disabled:o||!!v||!S.ssh.trim(),onClick:F,children:f("create-pairing-link")}),l.jsxs("button",{type:"button",className:"nc-btn ghost",disabled:!!v,onClick:()=>K(k=>!k),children:[B?"▾":"▸"," ",f("pair-advanced")]})]}),w&&l.jsxs(l.Fragment,{children:[l.jsx(Aj,{value:w.pairingUrl}),l.jsx(Pj,{text:w.pairingUrl}),l.jsx("div",{className:"nc-set-info",children:f("invite-next-steps")})]})]}),p&&l.jsx("div",{className:"nc-err",children:p})]})}function Tj({token:e,readonly:t}){const[n,s]=N.useState("idle"),[o,a]=N.useState(!1),[u,h]=N.useState(null);N.useEffect(()=>{let m=!1;return I2().then(v=>{m||s(v)}),()=>{m=!0}},[]);const p=async()=>{h(null),a(!0);try{n==="subscribed"?(await B2(e),s("idle")):(await O2(e),s("subscribed"))}catch(m){const v=String(m.message||m);v==="push-denied"?(s("denied"),h(f("push-denied"))):v==="push-unsupported"?(s("unsupported"),h(f("push-unsupported"))):h(v)}a(!1)};return n==="unsupported"?l.jsx("div",{className:"nc-set-info",children:f("push-unsupported")}):l.jsxs(l.Fragment,{children:[l.jsxs("div",{className:"nc-set-row",children:[l.jsx("button",{type:"button",className:"nc-btn ghost",disabled:t||o||n==="denied",title:t?f("settings-readonly"):"",onClick:p,children:f(n==="subscribed"?"push-disable":"push-enable")}),l.jsx("span",{className:"nc-set-info",children:f(n==="subscribed"?"push-on":n==="denied"?"push-denied":"push-off")})]}),u&&l.jsx("div",{className:"nc-err",children:u})]})}function Mj(){const[e,t]=fb(),[n,s]=N.useState(""),[o,a]=N.useState(""),[u,h]=N.useState(!1),[p,m]=N.useState(cb),v=N.useRef(0),y=N.useRef(!1),w=N.useRef(null),b=ea();N.useEffect(()=>()=>{var x;v.current+=1,y.current&&((x=w.current)==null||x.abort(),w.current=null,y.current=!1,Wh())},[]);const S=async()=>{const x=v.current+=1,R=typeof AbortController=="function"?new AbortController:null;s(""),a(""),h(!0),m(!1),y.current=!0,w.current=R;const E=await jj(f("notification-speech-preview"),Ol(),void 0,R?{signal:R.signal}:{});return x!==v.current||(w.current=null,y.current=!1,h(!1),m(E),E?a(f("notification-speech-preview-ok")):s(f("notification-speech-preview-failed"))),E},C=x=>{var R;if(t(x),s(""),a(""),x)S();else{v.current+=1;const E=y.current;(R=w.current)==null||R.abort(),w.current=null,y.current=!1,h(!1),m(!1),Wh(),E||hb()}};return l.jsxs("div",{className:"nc-set-form",children:[l.jsxs("label",{className:"nc-check",children:[l.jsx("input",{type:"checkbox","aria-label":f("notification-speech-enable"),checked:e,disabled:!b,onChange:x=>C(x.target.checked)}),l.jsxs("span",{children:[l.jsx("b",{children:f("notification-speech-enable")}),l.jsx("small",{children:f("notification-speech-help")})]})]}),b?l.jsx("div",{className:"nc-set-row",children:l.jsx("button",{type:"button",className:"nc-btn ghost",disabled:!e||u,onClick:()=>{S()},children:f(u?"notification-speech-testing":"notification-speech-test")})}):l.jsx("div",{className:"nc-set-info",children:f("notification-speech-unsupported")}),e&&!p&&!u&&!n&&l.jsx("div",{className:"nc-set-info",children:f("notification-speech-needs-test")}),o&&l.jsx("div",{className:"nc-set-info",role:"status",children:o}),n&&l.jsx("div",{className:"nc-err",children:n})]})}function Dj({token:e,readonly:t,nodes:n=[],settings:s=null}){const[o,a]=N.useState(null),[u,h]=N.useState([]),[p,m]=N.useState({name:"",mode:"primary-failover",targets:[]}),[v,y]=N.useState(null),[w,b]=N.useState(!1),[S,C]=N.useState(null),[x,R]=N.useState(""),E=N.useCallback(async()=>{try{const[F,k]=await Promise.all([$0(e),U0(e)]);a(F),h(Array.isArray(k==null?void 0:k.groups)?k.groups:[]),R("")}catch(F){R(String(F.message||F))}},[e]);N.useEffect(()=>{E()},[E]);const $=async F=>{b(!0),C(null),R("");try{a(await F0(e,F))}catch(k){R(String(k.message||k))}b(!1)},B=async()=>{b(!0),C(null),R("");try{C({kind:"test",...await H0(e)})}catch(F){R(String(F.message||F))}b(!1)},K=async()=>{b(!0),C(null),R("");try{C({kind:"stop",...await W0(e)})}catch(F){R(String(F.message||F))}b(!1)},V=[],Y=new Set,te=(F,k)=>{const I=typeof F=="string"?F.toLowerCase():"";!/^[a-f0-9]{32}$/.test(I)||Y.has(I)||(Y.add(I),V.push({id:I,label:k||I}))};te(s==null?void 0:s.nodeId,f("audio-group-local"));for(const F of n||[])te((F==null?void 0:F.nodeId)||(F==null?void 0:F.instanceId),(F==null?void 0:F.label)||(F==null?void 0:F.name)||(F==null?void 0:F.nodeId));for(const F of p.targets)te(F,`${F} (${f("audio-group-unavailable-target")})`);const Q=(F=null)=>{R(""),F?(y(F.name),m({name:F.name,mode:F.mode,targets:[...F.targets||[]]})):(y(null),m({name:"",mode:"primary-failover",targets:[]}))},J=(F,k)=>m(I=>({...I,targets:k?[...new Set([...I.targets,F])]:I.targets.filter(D=>D!==F)})),H=async()=>{const F=p.name.trim().toLowerCase();if(!/^[a-z0-9][a-z0-9-]{0,31}$/.test(F)||p.targets.length<1){R(f("audio-group-invalid"));return}b(!0),R("");try{const k=await K0(e,F,{targets:p.targets,mode:p.mode}),I=k==null?void 0:k.group;if(!I||!I.name)throw new Error(f("audio-group-save-failed"));h(D=>[...D.filter(M=>M.name!==I.name),I].sort((M,W)=>M.name.localeCompare(W.name))),Q(null)}catch(k){R(String(k.message||k))}b(!1)},L=async F=>{b(!0),R("");try{await q0(e,F),h(k=>k.filter(I=>I.name!==F)),v===F&&Q(null)}catch(k){R(String(k.message||k))}b(!1)},A=(o==null?void 0:o.installed)===!0,z=(o==null?void 0:o.liveness)==="ready",O=(o==null?void 0:o.consent)===!0&&A&&z,T=S?S.kind==="stop"?f(S.stopped?"audio-stop-stopped":"audio-stop-idle"):S.status==="accepted"||S.status==="spoken"?f("audio-test-accepted"):S.status==="unknown"?f("audio-test-unknown"):`${f("audio-test-refused")}${S.reason?` (${S.reason})`:""}`:"";return l.jsxs("div",{className:"nc-set-tab nc-audio-settings",children:[l.jsxs("div",{className:"nc-set-info",children:[l.jsx("b",{children:f("audio-title")}),l.jsx("br",{}),f("audio-help")]}),o?l.jsxs(l.Fragment,{children:[l.jsxs("label",{className:"nc-check",children:[l.jsx("input",{type:"checkbox","aria-label":f("audio-consent"),checked:o.consent===!0,disabled:t||w,onChange:F=>{$(F.target.checked)}}),l.jsxs("span",{children:[l.jsx("b",{children:f("audio-consent")}),l.jsx("small",{children:f("audio-consent-help")})]})]}),l.jsxs("div",{className:"nc-set-form",children:[l.jsx("div",{className:"nc-sheet-label",children:f("audio-capability")}),l.jsxs("div",{className:"nc-set-info",children:[f("audio-adapter"),": ",o.adapter||f("audio-adapter-none"),l.jsx("br",{}),f("audio-installed"),": ",f(A?"audio-installed-yes":"audio-installed-no"),l.jsx("br",{}),f("audio-liveness"),": ",f(z?"audio-liveness-ready":"audio-liveness-unavailable"),Array.isArray(o.languages)&&o.languages.length>0&&l.jsxs(l.Fragment,{children:[l.jsx("br",{}),f("audio-languages"),": ",o.languages.join(", ")]})]}),o.limits&&l.jsxs("small",{className:"nc-set-hint",children:[f("audio-limits"),": ",o.limits]})]}),!o.consent&&l.jsx("div",{className:"nc-set-info",children:f("audio-test-needs-consent")}),!A&&l.jsx("div",{className:"nc-set-info",children:f("audio-unavailable")}),l.jsxs("div",{className:"nc-set-row",children:[l.jsx("button",{type:"button",className:"nc-btn primary",disabled:t||w||!O,title:t?f("settings-readonly"):"",onClick:()=>{B()},children:f(w?"audio-testing":"audio-test")}),l.jsx("button",{type:"button",className:"nc-btn ghost",disabled:w,onClick:()=>{K()},children:f(w?"audio-stopping":"audio-stop")}),l.jsx("button",{type:"button",className:"nc-btn ghost",disabled:w,onClick:()=>{E()},children:f("refresh")})]}),l.jsxs("div",{className:"nc-set-form",children:[l.jsx("div",{className:"nc-sheet-label",children:f("audio-groups-title")}),l.jsx("small",{className:"nc-set-hint",children:f("audio-groups-help")}),u.length===0&&l.jsx("div",{className:"nc-set-info",children:f("audio-groups-empty")}),u.map(F=>{var k;return l.jsxs("div",{className:"nc-set-row",children:[l.jsxs("span",{children:[l.jsx("b",{children:F.name})," ",l.jsxs("small",{children:["· ",F.mode==="fanout"?f("audio-group-fanout"):f("audio-group-primary")," · ",((k=F.targets)==null?void 0:k.length)||0]})]}),l.jsx("button",{type:"button",className:"nc-btn ghost",disabled:t||w,onClick:()=>Q(F),children:f("audio-group-edit")}),l.jsx("button",{type:"button",className:"nc-btn ghost",disabled:t||w,onClick:()=>{L(F.name)},children:f("audio-group-delete")})]},F.name)}),l.jsx("div",{className:"nc-set-row",children:l.jsx("button",{type:"button",className:"nc-btn ghost",disabled:t||w,onClick:()=>Q(null),children:f("audio-group-new")})}),l.jsxs("label",{className:"nc-field",children:[f("audio-group-name"),l.jsx("input",{"aria-label":f("audio-group-name"),value:p.name,maxLength:"32",disabled:t||w,onChange:F=>m(k=>({...k,name:F.target.value}))})]}),l.jsxs("label",{className:"nc-field",children:[f("audio-group-mode"),l.jsxs("select",{"aria-label":f("audio-group-mode"),value:p.mode,disabled:t||w,onChange:F=>m(k=>({...k,mode:F.target.value})),children:[l.jsx("option",{value:"primary-failover",children:f("audio-group-primary")}),l.jsx("option",{value:"fanout",children:f("audio-group-fanout")})]})]}),l.jsx("div",{className:"nc-set-info",children:f("audio-group-targets")}),V.length===0?l.jsx("small",{className:"nc-set-hint",children:f("audio-group-no-targets")}):V.map(F=>l.jsxs("label",{className:"nc-check",children:[l.jsx("input",{type:"checkbox",checked:p.targets.includes(F.id),disabled:t||w,onChange:k=>J(F.id,k.target.checked)}),l.jsxs("span",{children:[F.label,l.jsx("small",{children:F.id})]})]},F.id)),l.jsxs("div",{className:"nc-set-row",children:[l.jsx("button",{type:"button",className:"nc-btn primary",disabled:t||w,onClick:()=>{H()},children:f("audio-group-save")}),v&&l.jsx("button",{type:"button",className:"nc-btn ghost",disabled:w,onClick:()=>Q(null),children:f("audio-group-cancel")})]})]})]}):l.jsx("div",{className:"nc-set-info",children:f("audio-loading")}),T&&l.jsx("div",{className:"nc-set-note",role:"status",children:T}),x&&l.jsx("div",{className:"nc-err",children:x})]})}function Ij(){const[e,t]=Cf();return l.jsxs("div",{className:"nc-set-tab nc-input-settings",children:[l.jsx("div",{className:"nc-set-info",children:f("input-settings-local")}),l.jsxs("div",{className:"nc-set-form",children:[l.jsxs("label",{className:"nc-field",children:[f("terminal-keyboard-gesture"),l.jsx("select",{"aria-label":f("terminal-keyboard-gesture"),value:e.terminalKeyboardGesture,onChange:n=>t({terminalKeyboardGesture:n.target.value}),children:jw.map(n=>l.jsx("option",{value:n,children:f(`terminal-keyboard-${n}`)},n))}),l.jsx("small",{children:f("terminal-keyboard-gesture-help")})]}),l.jsxs("label",{className:"nc-field",children:[f("keybar-layout"),l.jsx("select",{"aria-label":f("keybar-layout"),value:e.keybarLayout,onChange:n=>t({keybarLayout:n.target.value}),children:Rw.map(n=>l.jsx("option",{value:n,children:f(`keybar-layout-${n}`)},n))}),l.jsx("small",{children:f("keybar-layout-help")})]})]}),l.jsxs("label",{className:"nc-check",children:[l.jsx("input",{type:"checkbox",checked:e.keybarKeepsKeyboardClosed,onChange:n=>t({keybarKeepsKeyboardClosed:n.target.checked})}),l.jsxs("span",{children:[l.jsx("b",{children:f("keybar-ime-lock")}),l.jsx("small",{children:f("keybar-ime-lock-help")})]})]}),l.jsxs("label",{className:"nc-check",children:[l.jsx("input",{type:"checkbox",checked:e.voiceKeepsKeyboardClosed,onChange:n=>t({voiceKeepsKeyboardClosed:n.target.checked})}),l.jsxs("span",{children:[l.jsx("b",{children:f("voice-ime-lock")}),l.jsx("small",{children:f("voice-ime-lock-help")})]})]}),l.jsxs("label",{className:"nc-check",children:[l.jsx("input",{type:"checkbox",checked:e.showKeybarEnter,onChange:n=>t({showKeybarEnter:n.target.checked})}),l.jsxs("span",{children:[l.jsx("b",{children:f("keybar-enter-show")}),l.jsx("small",{children:f("keybar-enter-show-help")})]})]}),l.jsx("div",{className:"nc-set-row",children:l.jsx("button",{type:"button",className:"nc-btn ghost",onClick:()=>t(ms),children:f("input-settings-reset")})})]})}function Oj({token:e,roster:t=[],readonly:n}){const s=[{key:"local",route:[],label:f("diagnostics-local"),status:"up"},...t.filter(O=>Array.isArray(O.route)&&O.route.length).map(O=>({key:O.route.join("/"),route:O.route,label:O.label||O.name,status:O.status}))],[o,a]=N.useState("local"),u=s.find(O=>O.key===o)||s[0],[h,p]=N.useState(null),[m,v]=N.useState([]),[y,w]=N.useState(""),[b,S]=N.useState(!1),[C,x]=N.useState(!0),[R,E]=N.useState(900),[$,B]=N.useState("all"),[K,V]=N.useState(""),Y=N.useRef(0),te=N.useRef(null),Q=N.useCallback(async()=>{try{const O=await X0(e,u.route);if(p(O),w(""),!b){const T=await Q0(e,{after:Y.current,limit:200},u.route);Array.isArray(T.records)&&T.records.length&&(Y.current=T.cursor,v(F=>[...F,...T.records].slice(-500)))}}catch(O){w(O&&O.status===404?f("diagnostics-unsupported"):String(O.message||O))}},[e,u.key,b]);N.useEffect(()=>{Y.current=0,v([]),p(null),w("")},[u.key]),N.useEffect(()=>{let O=null,T=!0;const F=()=>{!T||document.visibilityState==="hidden"||Q()},k=()=>{O&&clearInterval(O),O=document.visibilityState==="hidden"?null:setInterval(F,2e3),document.visibilityState!=="hidden"&&F()};return document.addEventListener("visibilitychange",k),k(),()=>{T=!1,O&&clearInterval(O),document.removeEventListener("visibilitychange",k)}},[Q]),N.useEffect(()=>{C&&te.current&&(te.current.scrollTop=te.current.scrollHeight)},[m,C]);const J=m.filter(O=>($==="all"||O.level===$)&&(!K||String(O.component||"").toLowerCase().includes(K.toLowerCase()))),H=J.map(O=>`${O.ts} ${O.level.toUpperCase()} ${O.component} ${O.code} ${O.message}${Object.keys(O.meta||{}).length?` ${JSON.stringify(O.meta)}`:""}`).join(`
92
92
  `),L=async O=>{w("");try{const T=await O();p(T),await Q()}catch(T){w(String(T.message||T))}},A=async()=>{try{await navigator.clipboard.writeText(H)}catch{w(f("copy-manual"))}},z=()=>{try{const O=new Blob([`${JSON.stringify(J,null,2)}
93
- `],{type:"application/json"}),T=URL.createObjectURL(O),F=document.createElement("a");F.href=T,F.download="nexuscrew-diagnostics.json",F.click(),URL.revokeObjectURL(T)}catch{w(f("diagnostics-export-failed"))}};return l.jsxs("div",{className:"nc-set-tab nc-diagnostics",children:[l.jsxs("label",{className:"nc-field",children:[f("diagnostics-target"),l.jsx("select",{value:u.key,onChange:O=>a(O.target.value),children:s.map(O=>l.jsxs("option",{value:O.key,children:[O.label,O.status!=="up"?` · ${O.status}`:""]},O.key))})]}),l.jsxs("div",{className:"nc-set-form nc-diag-controls",children:[l.jsx("div",{className:"nc-sheet-label",children:f("diagnostics-verbose")}),l.jsxs("div",{className:"nc-set-row",children:[l.jsx("select",{"aria-label":f("diagnostics-duration"),value:R,onChange:O=>E(Number(O.target.value)),disabled:n,children:[300,900,1800,3600].map(O=>l.jsxs("option",{value:O,children:[O/60," min"]},O))}),l.jsx("button",{type:"button",className:"nc-btn primary",disabled:n||(h==null?void 0:h.verbose)===!0,onClick:()=>L(()=>Cg(e,!0,R,u.route)),children:f("enable")}),l.jsx("button",{type:"button",className:"nc-btn ghost",disabled:n||(h==null?void 0:h.verbose)!==!0,onClick:()=>L(()=>Cg(e,!1,R,u.route)),children:f("stop")})]}),l.jsx("small",{className:"nc-set-hint",children:h!=null&&h.verbose?f("diagnostics-expires").replace("{time}",new Date(h.expiresAt).toLocaleTimeString()):f("diagnostics-off")})]}),l.jsxs("div",{className:"nc-diag-filters",children:[l.jsxs("select",{"aria-label":f("diagnostics-level"),value:$,onChange:O=>B(O.target.value),children:[l.jsx("option",{value:"all",children:f("diagnostics-all-levels")}),["debug","info","warn","error"].map(O=>l.jsx("option",{value:O,children:O},O))]}),l.jsx("input",{"aria-label":f("diagnostics-component"),placeholder:f("diagnostics-component"),value:K,onChange:O=>V(O.target.value)})]}),l.jsxs("div",{className:"nc-set-row",children:[l.jsxs("label",{className:"nc-check",children:[l.jsx("input",{type:"checkbox",checked:b,onChange:O=>S(O.target.checked)})," ",f("diagnostics-pause")]}),l.jsxs("label",{className:"nc-check",children:[l.jsx("input",{type:"checkbox",checked:C,onChange:O=>x(O.target.checked)})," ",f("diagnostics-autoscroll")]})]}),l.jsx("pre",{ref:te,className:"nc-diag-log","aria-label":f("diagnostics-log"),children:H||f("diagnostics-empty")}),l.jsxs("div",{className:"nc-set-row",children:[l.jsx("button",{type:"button",className:"nc-btn ghost",onClick:A,children:f("copy")}),l.jsx("button",{type:"button",className:"nc-btn ghost",onClick:z,children:f("diagnostics-export")}),l.jsx("button",{type:"button",className:"nc-btn danger",disabled:n,onClick:()=>{window.confirm(f("diagnostics-clear-confirm"))&&L(async()=>{const O=await J0(e,u.route);return Y.current=0,v([]),O})},children:f("diagnostics-clear")})]}),y&&l.jsx("div",{className:"nc-err",children:y})]})}function Bj({token:e,settings:t,readonly:n,refresh:s,roster:o,section:a,setSection:u}){const[h,p]=N.useState(null),[m,v]=N.useState(null),[y,w]=N.useState(!1),[b,S]=N.useState(!1),[C,x]=N.useState(null),[R,E]=N.useState(!0),[$,B]=N.useState(!1);N.useEffect(()=>{x(t&&t.update||null),E(!t||t.autoUpdate!==!1),B(!!(t&&t.alternateScreen))},[t]);const K=async()=>{p(null),v(null),S(!0);try{const A=await L0(e);v(A.note||"ok"),w(!1)}catch(A){p(String(A.message||A))}S(!1)},V=async()=>{p(null),v(null),S(!0);try{const A=await V0(e);v(`${A.note||"ok"}${A.target?` (${A.target})`:""}`)}catch(A){p(String(A.message||A))}S(!1)},Y=async A=>{p(null),v(null),S(!0);try{await Kd(e,{autoUpdate:A}),E(A),s&&await s()}catch(z){p(String(z.message||z))}S(!1)},te=async A=>{p(null),v(null),S(!0);try{await Kd(e,{alternateScreen:A}),B(A),s&&await s()}catch(z){p(String(z.message||z))}S(!1)},Q=async()=>{p(null),v(null),S(!0);try{x(await Y0(e))}catch(A){p(String(A.message||A))}S(!1)},J=async()=>{p(null),v(null),S(!0);try{const A=await G0(e);x(A),v(f("npm-update-restarting"))}catch(A){p(String(A.message||A))}S(!1)},H=()=>{window.confirm(f("composer-clear-confirm"))&&(p(null),XE()?(window.dispatchEvent(new Event(Ih)),v(f("composer-clear-done"))):p(f("composer-clear-failed")))},L=t&&t.service;return l.jsxs("div",{className:"nc-set-tab",children:[l.jsx("div",{className:"nc-system-tabs",role:"tablist","aria-label":f("tab-system"),children:["general","diagnostics"].map(A=>l.jsx("button",{type:"button",role:"tab","aria-selected":a===A,className:`nc-set-tabbtn${a===A?" on":""}`,onClick:()=>u(A),children:f(`system-${A}`)},A))}),a==="general"&&l.jsxs(l.Fragment,{children:[l.jsxs("section",{className:"nc-system-group",children:[l.jsx("h3",{children:f("system-this-node")}),t&&l.jsxs("div",{className:"nc-set-info",children:["v",t.version," · ",t.platform," · :",t.port,l.jsx("br",{}),L&&L.installed?f("service-installed"):f("service-missing"),L&&L.installed?` · ${L.active?f("service-active"):f("service-inactive")}`:"",L?` · boot ${L.boot?"on":"off"}`:""]}),l.jsx("div",{className:"nc-set-row",children:l.jsx("button",{type:"button",className:"nc-btn ghost",disabled:n||b,title:n?f("settings-readonly"):"",onClick:V,children:f("service-regenerate")})}),l.jsx(Tj,{token:e,readonly:n}),l.jsx(Mj,{})]}),l.jsxs("section",{className:"nc-system-group",children:[l.jsx("h3",{children:f("system-updates")}),l.jsxs("div",{className:"nc-set-form nc-update-settings",children:[l.jsxs("label",{className:"nc-check",children:[l.jsx("input",{type:"checkbox",checked:R,disabled:n||b||C&&!C.supported,onChange:A=>Y(A.target.checked)}),l.jsxs("span",{children:[l.jsx("b",{children:f("npm-auto-update")}),l.jsx("small",{children:f("npm-auto-update-help")})]})]}),C&&l.jsxs("div",{className:"nc-set-info",children:[f("npm-update-current")," v",C.current,C.latest?` · ${f("npm-update-latest")} v${C.latest}`:""," · ",f(`npm-update-${C.supported?C.phase:"unsupported"}`)]}),l.jsxs("div",{className:"nc-set-row",children:[l.jsx("button",{type:"button",className:"nc-btn ghost",disabled:n||b||!C||!C.supported,onClick:Q,children:f("npm-update-check")}),C&&C.available&&l.jsx("button",{type:"button",className:"nc-btn primary",disabled:n||b||C.phase==="installing",onClick:J,children:f("npm-update-install")})]}),C&&C.lastError&&l.jsx("div",{className:"nc-err",children:C.lastError})]})]}),l.jsxs("section",{className:"nc-system-group",children:[l.jsx("h3",{children:f("system-security")}),l.jsx("div",{className:"nc-set-row",children:l.jsx("button",{type:"button",className:"nc-btn ghost",disabled:n||b,title:n?f("settings-readonly"):"",onClick:()=>{p(null),v(null),w(!0)},children:f("token-rotate")})})]}),l.jsxs("section",{className:"nc-system-group",children:[l.jsx("h3",{children:f("system-local-data")}),l.jsxs("div",{className:"nc-set-form",children:[l.jsx("div",{className:"nc-sheet-label",children:f("composer-clear-data")}),l.jsx("small",{className:"nc-set-hint",children:f("composer-clear-data-help")}),l.jsx("div",{className:"nc-set-row",children:l.jsx("button",{type:"button",className:"nc-btn ghost",onClick:H,children:f("composer-clear-data")})})]})]})]}),a==="diagnostics"&&l.jsxs("section",{className:"nc-system-group nc-system-diagnostics",children:[l.jsx("h3",{children:f("system-diagnostics")}),l.jsxs("div",{className:"nc-set-form nc-alternate-screen-settings",children:[l.jsx("div",{className:"nc-sheet-label",children:f("system-terminal")}),l.jsxs("label",{className:"nc-check",children:[l.jsx("input",{type:"checkbox","aria-label":f("alternate-screen"),checked:$,disabled:n||b,onChange:A=>te(A.target.checked)}),l.jsxs("span",{children:[l.jsx("b",{children:f("alternate-screen")}),l.jsx("small",{children:f("alternate-screen-help")})]})]})]}),l.jsx(Oj,{token:e,roster:o,readonly:n})]}),y&&l.jsxs("div",{className:"nc-set-confirm",children:[l.jsx("div",{children:f("token-rotate-explain")}),l.jsxs("div",{className:"nc-sheet-actions",children:[l.jsx("button",{type:"button",className:"nc-btn ghost",disabled:b,onClick:()=>w(!1),children:f("cancel")}),l.jsx("button",{type:"button",className:"nc-btn primary",disabled:b,onClick:K,children:f("confirm")})]})]}),m&&l.jsx("div",{className:"nc-set-note",children:m}),h&&l.jsx("div",{className:"nc-err",children:h})]})}function zj({token:e,onClose:t,initialTab:n="nodes",initialLocation:s="",startNewCell:o=!1}){En();const a=n==="diagnostics"?"diagnostics":"general",[u,h]=N.useState(n==="diagnostics"?"system":n),p=N.useRef(null),m=N.useRef(null),[v,y]=N.useState({start:!1,end:!1}),[w,b]=N.useState(a),[S,C]=N.useState(null),[x,R]=N.useState([]),[E,$]=N.useState([]),[B,K]=N.useState(!1),[V,Y]=N.useState(null),[te,Q]=N.useState(0),J=sf(e,!0,te),H=N.useCallback(()=>{const A=p.current;if(!A)return;const z=A.scrollWidth>A.clientWidth+1,O={start:z&&A.scrollLeft>1,end:z&&A.scrollLeft+A.clientWidth<A.scrollWidth-1};y(T=>T.start===O.start&&T.end===O.end?T:O)},[]);N.useEffect(()=>{const A=p.current;if(!A)return;const z=typeof ResizeObserver=="function"?new ResizeObserver(H):null;return z==null||z.observe(A),window.addEventListener("resize",H),H(),()=>{z==null||z.disconnect(),window.removeEventListener("resize",H)}},[H]),N.useEffect(()=>{var z,O;(O=(z=m.current)==null?void 0:z.scrollIntoView)==null||O.call(z,{behavior:"smooth",block:"nearest",inline:"nearest"});const A=window.requestAnimationFrame?window.requestAnimationFrame(H):setTimeout(H,0);return()=>{window.cancelAnimationFrame?window.cancelAnimationFrame(A):clearTimeout(A)}},[u,H]);const L=N.useCallback(async()=>{var A;try{const z=await ny(e);C(z),Y(null)}catch(z){Y(String(z.message||z))}try{const O=(await P0(e)).peers||[];let T=[],F=[];try{const[k,I]=await Promise.all([Ut("/api/config",e).then(G=>G.json()).catch(()=>null),sy(e).catch(()=>null)]),D=k&&typeof k.instanceId=="string"?k.instanceId:"",M=[{instanceId:D||null,route:[],label:null},...fy(I,D)],W=await Promise.all(M.map(async G=>{try{return{ok:!0,peers:((await iy(e,G.route)).nodes||[]).map(he=>hy(he,G)).filter(Boolean)}}catch(ue){return{ok:!1,owner:G,error:ue}}}));for(const G of W){if(G.ok){T.push(...G.peers);continue}G.owner.route.length!==0&&F.push({instanceId:G.owner.instanceId,label:G.owner.label,route:G.owner.route,failure:/timeout/i.test(String(((A=G.error)==null?void 0:A.message)||G.error))?"timeout":"unreachable"})}}catch{}$(F),R([...O,...T])}catch(z){Y(String(z.message||z))}},[e]);return N.useEffect(()=>{L();const A=setInterval(L,5e3);return()=>clearInterval(A)},[L]),N.useEffect(()=>{let A=!1;return Ut("/api/config",e).then(z=>z.json()).then(z=>{A||K(!!z.readonlyDefault)}).catch(()=>{}),()=>{A=!0}},[e]),l.jsx("div",{className:"nc-set-overlay",onClick:t,children:l.jsxs("div",{className:"nc-set-panel",onClick:A=>A.stopPropagation(),children:[l.jsxs("div",{className:"nc-set-head",children:[l.jsx(Ge,{name:"gear",size:18}),l.jsx("b",{children:f("settings")}),l.jsx("button",{type:"button",className:"nc-set-close",onClick:t,title:f("close"),children:l.jsx(Ge,{name:"x",size:18})})]}),B&&l.jsx("div",{className:"nc-set-readonly",children:f("settings-readonly")}),V&&l.jsx("div",{className:"nc-err",children:V}),l.jsx("div",{className:`nc-set-tabs-wrap${v.start?" has-start-overflow":""}${v.end?" has-end-overflow":""}`,children:l.jsx("div",{className:"nc-set-tabs",ref:p,onScroll:H,children:["nodes","fleet","audio","input","system"].map(A=>l.jsx("button",{ref:u===A?m:null,type:"button",className:`nc-set-tabbtn${u===A?" on":""}`,onClick:()=>h(A),children:f(`tab-${A}`)},A))})}),l.jsxs("div",{className:"nc-set-body",children:[u==="nodes"&&l.jsx(Lj,{token:e,nodes:x,roster:J,settings:S,readonly:B,vlUnavailable:E,refresh:L,refreshAliases:()=>Q(A=>A+1)}),u==="fleet"&&l.jsx(fj,{token:e,readonly:B,startNewCell:o,initialLocation:s,targets:J.map(A=>({route:A.route,label:A.label||A.name,status:A.status}))}),u==="audio"&&l.jsx(Dj,{token:e,readonly:B,nodes:x,settings:S}),u==="input"&&l.jsx(Ij,{}),u==="system"&&l.jsx(Bj,{token:e,settings:S,readonly:B,refresh:L,roster:J,section:w,setSection:b})]})]})})}function $j({token:e,initialPair:t,deviceDefault:n="",localNodeId:s="",localNameDefault:o="",onPairDone:a,onDone:u}){En();const[h,p]=N.useState(t?"pair":"welcome"),[m,v]=N.useState(!1),[y,w]=N.useState(null),b=async()=>{v(!0),w(null);try{await Kd(e,{wizardDone:!0}),a&&a(),u()}catch(S){w(String(S.message||S)),v(!1)}};return l.jsx("div",{className:"nc-wiz-overlay",children:l.jsxs("div",{className:"nc-wiz",children:[l.jsxs("div",{className:"nc-wiz-head",children:[l.jsx("b",{children:f("wizard-title")}),l.jsx("small",{children:f("hydra-simple")})]}),h==="welcome"&&l.jsxs("div",{className:"nc-wiz-body",children:[l.jsx("div",{className:"nc-wiz-done",children:f("local-ready")}),l.jsxs("div",{className:"nc-sheet-actions",children:[l.jsx("button",{className:"nc-btn ghost",disabled:m,onClick:b,children:f("local-only")}),l.jsx("button",{className:"nc-btn primary",disabled:m,onClick:()=>p("pair"),children:f("add-node")})]})]}),h==="pair"&&l.jsxs("div",{className:"nc-wiz-body",children:[l.jsx(Xw,{token:e,initial:t||"",autoStart:!!t,deviceDefault:n,localNodeId:s,localNameDefault:o,onBusyChange:v,onSuccess:async()=>{a&&a(),p("done")}}),l.jsx("div",{className:"nc-sheet-actions",children:l.jsx("button",{className:"nc-btn ghost",disabled:m,onClick:()=>{a&&a(),p("welcome")},children:f("back")})})]}),h==="done"&&l.jsxs("div",{className:"nc-wiz-body",children:[l.jsx("div",{className:"nc-wiz-done",children:f("node-connected")}),l.jsx("div",{className:"nc-sheet-actions",children:l.jsx("button",{className:"nc-btn primary",disabled:m,onClick:b,children:f("finish")})})]}),y&&l.jsx("div",{className:"nc-err",children:y})]})})}function Fj(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 Hj=6e3,Wj=12e3;function Uj({n:e,onClose:t}){return l.jsxs("div",{className:`nc-ntf-toast${e.urgency==="high"?" high":""}`,role:"status","aria-live":"polite",children:[l.jsxs("div",{className:"nc-ntf-toast-txt",children:[l.jsx("b",{children:e.title}),e.body&&l.jsx("small",{children:e.body}),e.session&&l.jsx("span",{className:"nc-ntf-from",children:e.session})]}),l.jsx("button",{type:"button",className:"nc-ntf-x",onClick:t,title:f("close"),children:l.jsx(Ge,{name:"x",size:14})})]})}function Kj({ask:e,token:t,onAnswered:n,onDismiss:s}){const[o,a]=N.useState(""),[u,h]=N.useState(!1),[p,m]=N.useState(null),[v,y]=N.useState(!1),w=async S=>{const C=String(S||"").trim();if(!(!C||u)){m(null),h(!0);try{await ex(t,e.id,C),n(e.id)}catch(x){m(String(x.message||x))}h(!1)}},b=async()=>{if(!v){y(!0);try{await tx(t,e.id),s(e.id)}catch{y(!1)}}};return l.jsxs("div",{className:"nc-ask-card",children:[l.jsxs("div",{className:"nc-ask-head",children:[l.jsx("span",{className:"nc-ntf-from",children:e.session}),l.jsxs("code",{className:"nc-ask-id",children:["#",e.id]}),l.jsx("button",{type:"button",className:"nc-ask-dismiss",title:f("ask-dismiss"),"aria-label":f("ask-dismiss"),disabled:v,onClick:b,children:l.jsx(Ge,{name:"x",size:14})})]}),l.jsx("div",{className:"nc-ask-q",children:e.question}),Array.isArray(e.options)&&e.options.length>0&&l.jsx("div",{className:"nc-ask-opts",children:e.options.map(S=>l.jsx("button",{type:"button",className:"nc-btn ghost",disabled:u,onClick:()=>w(S),children:S},S))}),l.jsxs("div",{className:"nc-ask-reply",children:[l.jsx("textarea",{rows:2,placeholder:f("ask-reply-ph"),value:o,disabled:u,onChange:S=>a(S.target.value)}),l.jsx("button",{type:"button",className:"nc-btn primary",disabled:u||!o.trim(),onClick:()=>w(o),children:f("send")})]}),p&&l.jsx("div",{className:"nc-err",children:p})]})}function qj({token:e}){const[t]=En(),[n]=fb(),[s,o]=N.useState([]),[a,u]=N.useState([]),[h,p]=N.useState(()=>{try{return/(?:^|[#&])ask=/.test(location.hash)}catch{return!1}}),m=N.useRef(0),v=N.useRef(null);v.current||(v.current=Rj());const y=N.useRef({enabled:n,lang:t});y.current={enabled:n,lang:t};const w=N.useCallback(x=>{o(R=>R.filter(E=>E.key!==x))},[]),b=N.useCallback(x=>{const R=`t${m.current+=1}`;o($=>[...$.slice(-3),{...x,key:R}]),setTimeout(()=>w(R),x.urgency==="high"?Wj:Hj);const E=y.current;if(E.enabled)try{v.current.enqueue(x,kj(x,E.lang))}catch{}},[w]);N.useEffect(()=>{n||v.current.stop()},[n]),N.useEffect(()=>{const x=()=>{(document.visibilityState!=="visible"||!document.hasFocus())&&v.current.stop()},R=()=>v.current.stop();return document.addEventListener("visibilitychange",x),window.addEventListener("blur",x),window.addEventListener(Hh,R),()=>{document.removeEventListener("visibilitychange",x),window.removeEventListener("blur",x),window.removeEventListener(Hh,R),typeof v.current.dispose=="function"?v.current.dispose():v.current.stop()}},[]),N.useEffect(()=>{if(!e)return;let x=!1;Z0(e).then(E=>{x||u(E.asks||[])}).catch(()=>{});const R=Fj(e,E=>{E.type==="notify"?b(E):E.type==="ask"&&E.ask&&E.ask.id?u($=>$.some(B=>B.id===E.ask.id)?$:[...$,E.ask]):E.type==="ask-answered"&&E.id?u($=>$.filter(B=>B.id!==E.id)):E.type==="ask-dismissed"&&E.id&&u($=>$.filter(B=>B.id!==E.id))});return()=>{x=!0,R()}},[e,b]);const S=x=>u(R=>R.filter(E=>E.id!==x)),C=x=>u(R=>R.filter(E=>E.id!==x));return l.jsxs(l.Fragment,{children:[s.length>0&&l.jsx("div",{className:"nc-ntf-toasts",children:s.map(x=>l.jsx(Uj,{n:x,onClose:()=>w(x.key)},x.key))}),a.length>0&&!h&&l.jsxs("button",{type:"button",className:"nc-ask-badge",onClick:()=>p(!0),title:f("asks-title"),children:["? ",l.jsx("span",{className:"nc-ask-count",children:a.length})]}),a.length>0&&h&&l.jsxs("div",{className:"nc-ask-panel",children:[l.jsxs("div",{className:"nc-ask-panel-head",children:[l.jsx("b",{children:f("asks-title")}),l.jsx("span",{className:"nc-ask-count",children:a.length}),l.jsx("button",{type:"button",className:"nc-ntf-x",onClick:()=>p(!1),title:f("close"),children:l.jsx(Ge,{name:"x",size:16})})]}),l.jsx("div",{className:"nc-ask-panel-body",children:a.map(x=>l.jsx(Kj,{ask:x,token:e,onAnswered:S,onDismiss:C},x.id))})]})]})}const Vj=4e3;async function Yj(e){const t=await Ut("/api/sessions",e);if((t==null?void 0:t.ok)===!1)throw new Error(`HTTP ${t.status}`);const n=await t.json();if(!Array.isArray(n==null?void 0:n.sessions))throw new Error("invalid sessions payload");return n.sessions}async function Fd(e,t=[]){var h;const[n,s]=await Promise.allSettled([t.length?Zh(e,t):Yj(e),bs(e,t)]),o=n.status==="fulfilled"&&Array.isArray((h=n.value)==null?void 0:h.sessions)?n.value.sessions:Array.isArray(n.value)?n.value:null,a=s.status==="fulfilled"?s.value:null,u=(a==null?void 0:a.available)===!0&&Array.isArray(a.cells)?a.cells:null;return{sessions:o,cells:u,fresh:Array.isArray(o)&&Array.isArray(u)}}function pb(e,t,n){return n===!0&&(e==null?void 0:e.degraded)!==!0&&(e==null?void 0:e.active)===!0&&e.tmux!==!1&&!!e.tmuxSession&&(t||[]).some(s=>(s==null?void 0:s.name)===e.tmuxSession)}function Gj(e){const t=new Map((e.sessions||[]).map(o=>[o.name,o])),n=[],s=(o,a,u,h=[],p="")=>{const m=new Map((a||[]).map(v=>[v.name,v]));for(const v of o||[]){const y=m.get(v.tmuxSession)||{},w=af(v,y),b=pb(v,a,u);n.push({key:Go(h,v.tmuxSession||v.cell),session:v.tmuxSession,route:h,cellName:v.cell,label:v.cell,node:h.length?h.join("/"):"",nodeLabel:p,live:b,selectable:b,verified:u===!0,working:w.working,degraded:!!v.degraded,active:v.active===!0,activity:y.activity||v.activity||0,subtitle:w.subtitle})}};s(e.cells,[...t.values()],e.localFresh===!0);for(const o of e.nodeGroups||[]){const a=Array.isArray(o.route)?o.route:[];o.kind==="vl"||!a.length||s(o.cells,o.sessions,o.switcherFresh===!0,a,o.label||o.name||"")}return n}function Xj(e){const t=new Map,n=Array.isArray(e.sessions)?e.sessions:[],s=Array.isArray(e.cells)?e.cells:[],o=new Map(n.map(u=>[u.name,u])),a=new Set(s.map(u=>u.tmuxSession).filter(Boolean));t.set("local",lf(s,n.filter(u=>!a.has(u.name)),o));for(const u of e.nodeGroups||[]){const h=Array.isArray(u.route)?u.route:[];if(u.kind==="vl"||!h.length)continue;const p=Array.isArray(u.cells)?u.cells:[],m=Array.isArray(u.sessions)?u.sessions:[],v=new Set(p.map(y=>y.tmuxSession).filter(Boolean));t.set(h.join("/"),$l({...u,route:h,cells:p,sessions:m,unmanaged:m.filter(y=>!v.has(y.name))}).rawItems)}return t}function Qj(e,t,n,s){return[...new Set(e.map(a=>a.node||"local"))].flatMap(a=>{const u=e.filter(v=>(v.node||"local")===a),h=new Map((t.get(a)||[]).map(v=>[v.key,v])),p=new Map(u.map(v=>[v.key,v])),m=u.map(v=>{const y=h.get(v.key);return{...v,label:(y==null?void 0:y.label)||v.label,live:(y==null?void 0:y.live)??v.live,fresh:(y==null?void 0:y.fresh)===!0,activity:(y==null?void 0:y.activity)??v.activity}});return vs(m,n,"all",$i(s,a)).map(v=>p.get(v.key))})}function Jj({token:e,current:t,onPick:n,onClose:s}){const[o,a]=N.useState(Bg),[u,h]=N.useState(!1),[p,m]=N.useState(!1),[v,y]=N.useState(""),[w,b]=N.useState(""),[S,C]=N.useState(""),x=N.useRef(null),R=N.useRef(null),E=N.useMemo(()=>Gj(o),[o]),$=N.useMemo(()=>Xj(o),[o]),{pins:B,orders:K,canMoveRoster:V,moveRoster:Y,stepRoster:te}=of(),Q=N.useMemo(()=>Qj(E,$,B,K),[E,$,B,K]),J=N.useMemo(()=>u?Q:Q.filter(O=>O.selectable||O.degraded&&O.active),[Q,u]),H=N.useMemo(()=>E.find(O=>O.key===w&&O.selectable),[E,w]);N.useEffect(()=>{var F;const O=document.activeElement;(F=R.current)==null||F.focus();const T=k=>{k.key==="Escape"&&s()};return document.addEventListener("keydown",T),()=>{var k;document.removeEventListener("keydown",T),(k=O==null?void 0:O.focus)==null||k.call(O)}},[s]),N.useEffect(()=>{let O=!0,T=!1;const F=async()=>{if(T)return;T=!0;const I=Bg(),D=Array.isArray(I.nodeGroups)?I.nodeGroups:[],M=Fd(e),W=re=>re.kind!=="vl"&&Array.isArray(re.route)&&re.route.length>0,G=await Promise.all(D.filter(W).map(async re=>({group:re,result:await Fd(e,re.route)}))),ue=await M;if(!O)return;const le=new Map(G.map(({group:re,result:_e})=>[JSON.stringify(re.route||[]),_e])),he=D.map(re=>{if(!W(re))return{...re,switcherFresh:!1};const _e=le.get(JSON.stringify(re.route||[]));return _e?{...re,sessions:_e.sessions||re.sessions||[],cells:_e.cells||re.cells||[],switcherFresh:_e.fresh}:{...re,switcherFresh:!1}}),we=xy({...I,sessions:ue.sessions||I.sessions||[],cells:ue.cells||I.cells||[],localFresh:ue.fresh,nodeGroups:he,refreshedAt:Date.now()});a(we),m(!0),T=!1};F();const k=setInterval(F,Vj);return()=>{O=!1,clearInterval(k)}},[e]);const L=O=>O.degraded?f("cell-degraded"):O.verified?O.selectable?O.working?f("cell-working"):f("cell-idle"):f("cell-off"):f("cell-switcher-not-confirmed"),A=O=>{if(y(""),!O.selectable){y(f("cell-switcher-not-active"));return}b(O.key)},z=async()=>{const O=H;if(!O){y(f("cell-switcher-select"));return}y(""),C(O.key);try{const T=await Fd(e,O.route),F=(T.cells||[]).find(k=>(k==null?void 0:k.cell)===O.cellName&&(k==null?void 0:k.tmuxSession)===O.session);if(!pb(F,T.sessions,T.fresh)){y(f("cell-switcher-not-active"));return}n({session:O.session,...O.node?{node:O.node}:{},cellName:O.cellName}),s()}catch{y(f("cell-switcher-not-active"))}finally{C("")}};return l.jsx("div",{className:"nc-cell-switcher-backdrop",onClick:s,children:l.jsxs("aside",{ref:x,className:"nc-cell-switcher",role:"dialog","aria-label":f("fleet-cells"),tabIndex:-1,onClick:O=>O.stopPropagation(),children:[l.jsxs("div",{className:"nc-cell-switcher-list",children:[!p&&l.jsx("div",{className:"nc-empty",role:"status",children:f("cell-switcher-refreshing")}),p&&J.length===0&&l.jsx("div",{className:"nc-empty",role:"status",children:f("cell-switcher-empty-active")}),J.map(O=>{const T=(t==null?void 0:t.session)===O.session&&((t==null?void 0:t.node)||"")===O.node,F=w===O.key,k=L(O),I=O.node||"local",D=$.get(I)||E.filter(M=>(M.node||"local")===I);return l.jsxs("div",{className:`nc-cell-switcher-row${T?" current":""}${F?" selected":""}${O.selectable?"":" off"}`,"data-roster-key":O.key,"data-position":I,children:[l.jsx(bi,{position:I,itemKey:O.key,label:O.cellName,canMove:V,onMove:(M,W)=>Y(I,M,W,D),onStep:M=>te(I,O.key,M,D)}),l.jsxs("button",{type:"button",className:"nc-cell-switcher-row-select","aria-current":T?"true":void 0,"aria-pressed":F,"aria-disabled":!O.selectable,disabled:S===O.key,onClick:()=>A(O),children:[l.jsx("span",{className:`nc-cell-switcher-dot${O.degraded?" warn":O.live?` on${O.working?" working":""}`:""}`}),l.jsxs("span",{className:"nc-cell-switcher-copy",children:[l.jsx("b",{children:O.cellName}),l.jsx("small",{className:"nc-cell-switcher-state",children:k}),l.jsx("small",{children:[O.nodeLabel,O.subtitle].filter(Boolean).join(" · ")})]})]})]},O.key)})]}),v&&l.jsx("div",{className:"nc-cell-switcher-notice",role:"status",children:v}),l.jsx("div",{className:"nc-cell-switcher-actions",children:l.jsx("button",{type:"button",className:"nc-cell-switcher-open",disabled:!H||!!S,onClick:z,children:H?`${f("cell-switcher-open")}: ${H.cellName}`:f("cell-switcher-select")})}),l.jsxs("div",{className:"nc-cell-switcher-controls",children:[l.jsx("b",{children:f("fleet-cells")}),l.jsx("button",{type:"button",className:"nc-cell-switcher-filter","aria-pressed":u,onClick:()=>{y(""),h(O=>!O)},children:f(u?"cell-switcher-show-active":"cell-switcher-show-all")}),l.jsx("button",{ref:R,type:"button",className:"nc-cell-switcher-close","aria-label":f("cell-switcher-close"),title:f("cell-switcher-close"),onClick:s,children:"×"})]})]})})}const Zj=2e3;function eR(e){if(e.kind==="gap")return`${f("vl-events-gap")} ${e.count||"?"}`;if(e.kind==="truncate")return f("vl-events-truncated");if(e.kind==="turn_end")return f("vl-events-turn-end");if(e.kind==="done")return f("vl-events-done");if(e.kind==="writer_epoch")return f("vl-events-writer-epoch");if(e.kind==="tool_start")return`${f("vl-events-tool")} ${e.name||""}`.trim();if(e.kind==="tool_end"){const t=e.isError?f("vl-events-tool-failed"):f("vl-events-tool-ok");return`${f("vl-events-tool")} ${e.name||""} — ${t}`.trim()}return e.kind==="usage"?e.text||f("vl-events-usage"):e.text||""}function tR({token:e,nodeId:t,route:n=[]}){const[s,o]=N.useState([]),[a,u]=N.useState(!1),h=N.useRef(0),p=N.useRef(!1);return N.useEffect(()=>{let m=!0;h.current=0,p.current=!1,o([]);const v=async()=>{if(!p.current){p.current=!0;try{const b=await A0(e,t,h.current,n);if(!m)return;u(!1);const C=(Array.isArray(b==null?void 0:b.events)?b.events:[]).filter(x=>Number.isSafeInteger(x==null?void 0:x.seq)&&x.seq>h.current);C.length&&(o(x=>x.concat(C).slice(-500)),h.current=C[C.length-1].seq),Number.isSafeInteger(b==null?void 0:b.cursor)&&b.cursor>h.current&&(h.current=b.cursor)}catch{m&&u(!0)}finally{p.current=!1}}},y=()=>{v().catch(()=>{})};y();const w=setInterval(y,Zj);return()=>{m=!1,clearInterval(w)}},[e,t,JSON.stringify(n)]),l.jsxs("div",{className:"nc-vl-events",children:[a&&l.jsx("div",{className:"nc-set-hint nc-vl-events-stale",children:f("vl-events-stale")}),s.length===0&&!a&&l.jsx("small",{className:"nc-set-hint","data-testid":"vl-events-empty",children:f("vl-events-empty")}),s.length>0&&l.jsx("ol",{className:"nc-vl-events-list",children:s.map(m=>l.jsx("li",{"data-testid":`vl-ev-${m.seq}`,className:`nc-vl-ev nc-vl-ev-${m.kind}${m.isError?" error":""}${m.kind==="gap"?" gap":""}`,children:eR(m)},`${m.seq}-${m.kind}`))})]})}function H_({peer:e,token:t,onBack:n}){var s;return En(),e?l.jsxs("section",{className:"nc-vl-session-view",children:[l.jsxs("header",{className:"nc-bar nc-bar-single",children:[l.jsxs("button",{onClick:n,title:f("back"),children:[l.jsx(Ge,{name:"chevronLeft",size:18}),l.jsx("span",{className:"nc-bar-label",children:f("back")})]}),l.jsxs("span",{className:"nc-bar-center",children:[l.jsx("b",{title:e.label,children:e.label}),((s=e.session)==null?void 0:s.profile)&&l.jsxs("small",{className:"nc-bar-sub",children:[e.session.profile," · ",f("vl-events-title")]})]}),l.jsx("span",{className:"nc-bar-right"})]}),l.jsx("div",{className:"nc-vl-session-body",children:l.jsx(tR,{token:t,nodeId:e.nodeId,route:e.route||[]})})]}):null}const Hd=e=>ki(Ys(e)).length===0,Wd=e=>Array.isArray(e)?e.join("/"):"";function nR(e){const t=new Set,n=[];for(const s of Array.isArray(e)?e:[])!s||!Kn.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 zo(e){return{instanceId:e.ownerId,route:e.ownerRoute||[],label:e.ownerLabel,status:e.available===!1?"offline":"up"}}function Hs(e,t,n,s=!1,o=!0){const a=t.instanceId;return{...e,id:Lr(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:Bh(e.layout,a,n)}}function iR(e,t,n,s,o=[]){const[a,u]=N.useState([]),[h,p]=N.useState(!1),[m,v]=N.useState("idle"),[y,w]=N.useState(""),[b,S]=N.useState(""),C=N.useRef([]),x=N.useRef([]),R=N.useRef(""),E=N.useRef(t),$=N.useRef(n),B=N.useRef(!1),K=N.useRef(!0),V=N.useRef(""),Y=N.useMemo(()=>nR(o),[o]),te=Y.map(D=>`${D.instanceId}:${Wd(D.route)}:${D.status}:${D.label}`).join("|");x.current=Y,$.current=n,E.current=t,C.current=a;const Q=N.useCallback(D=>zh(D.layout,R.current,x.current),[]),J=N.useCallback((D,M=!0,W=E.current)=>{const G=Yv(D,xl()),ue=C.current.some(he=>he.id===W);C.current=G,u(G);const le=G.find(he=>he.id===W);if(M&&le){K.current=!0;const he=Q(le);s(he),le.local&&wN(le.name,he)}else ue&&!le&&(K.current=!0,s(Ar()),w("deck non più condiviso dal nodo owner"));gN(G.filter(he=>he.local).map(he=>he.name))},[s,Q]),H=N.useCallback(async D=>{let M=await pl(e);const W=M.decks.find(G=>G.name==="main");if(M.decks.length===1&&W&&W.revision===0&&Hd(W.layout)){const G=mN(),ue=Ys($h("main")||Ar());if(!Hd(ue)){const le=Bh(ue,D,[]);M.decks[0]=await ml(e,"main",le,0,[])}for(const le of G.filter(he=>he!=="main"))try{let he=await Eg(e,le,[]);const we=Ys($h(le)||Ar());Hd(we)||(he=await ml(e,le,Bh(we,D,[]),he.revision,[]))}catch{}M=await pl(e)}return M},[e]),L=N.useCallback(async({migrate:D=!1}={})=>{const M=await ef(e,[]),W=Kn.test(String(M.instanceId||""))?M.instanceId:"";if(!W)throw new Error("instanceId locale non disponibile");R.current=W,S(W);const[G,ue]=await Promise.all([D?H(W):pl(e),Sg(e,[]).catch(()=>({nodes:[]}))]),le={instanceId:W,route:[],label:"Local"},he=G.decks.map(re=>Hs(re,le,ue.nodes,!0,!0)),we=C.current;return await Promise.all(x.current.map(async re=>{if(re.status!=="up"){he.push(...we.filter(_e=>!_e.local&&_e.ownerId===re.instanceId).map(_e=>({..._e,ownerRoute:[...re.route],ownerLabel:re.label,available:!1})));return}try{const[_e,ze]=await Promise.all([pl(e,re.route),Sg(e,re.route).catch(()=>({nodes:[]}))]);he.push(..._e.decks.map(ut=>Hs(ut,re,ze.nodes,!1,!0)))}catch{he.push(...we.filter(ze=>!ze.local&&ze.ownerId===re.instanceId).map(ze=>({...ze,ownerRoute:[...re.route],ownerLabel:re.label,available:!1})))}})),he.sort((re,_e)=>re.local===_e.local?re.ownerLabel.localeCompare(_e.ownerLabel)||(re.name==="main"?-1:_e.name==="main"?1:re.name.localeCompare(_e.name)):re.local?-1:1),he},[e,H,te]);N.useEffect(()=>{if(!e)return;let D=!1;const M=V.current!==e;return V.current=e,L({migrate:M}).then(W=>{if(D)return;const G=C.current.find(he=>he.id===E.current),ue=W.find(he=>he.id===E.current),le=ue&&(!G||ue.revision>G.revision||G.available!==ue.available||Wd(G.ownerRoute)!==Wd(ue.ownerRoute));J(W,M||!!le&&!B.current),p(!0),ue&&w("")}).catch(W=>{D||(p(!0),w(String(W.message||W)))}),()=>{D=!0}},[J,L,te,e]);const A=N.useCallback(async(D=E.current)=>{if(!h||!B.current)return!0;const M=C.current.find(W=>W.id===D);if(!M)return w(`deck inesistente: ${D}`),!1;if(M.available===!1)return w(`nodo owner offline: ${M.ownerLabel}`),!1;v("saving");try{const W=qv(Ys($.current),M.ownerId,M.ownerTopology),G=await ml(e,M.name,W,M.revision,M.ownerRoute),ue=Hs(G,zo(M),M.ownerTopology,M.local,!0);return J(C.current.map(le=>le.id===D?ue:le),!1),B.current=!1,v("saved"),w(""),setTimeout(()=>v("idle"),1500),!0}catch(W){if(v("error"),w(String(W.message||W)),W.status===409&&W.data&&W.data.current){const G=C.current.find(le=>le.id===D),ue=Hs(W.data.current,zo(G),G.ownerTopology,G.local,!0);J(C.current.map(le=>le.id===D?ue:le),!1)}return!1}},[h,e,J]);return N.useEffect(()=>{if(!h)return;if(K.current){K.current=!1;return}B.current=!0,v("saving");const D=setTimeout(A,650);return()=>clearTimeout(D)},[n,h,A]),N.useEffect(()=>{if(!h)return;const D=setInterval(async()=>{try{const M=await L(),W=C.current.find(le=>le.id===E.current),G=M.find(le=>le.id===E.current),ue=G&&(!W||G.revision>W.revision||W.available!==G.available);J(M,ue&&!B.current)}catch{}},5e3);return()=>clearInterval(D)},[h,L,J]),{decks:a,records:a,localNodeId:b,ready:h,saveState:m,error:y,setError:w,saveNow:A,select:async D=>{if(B.current&&!await A(E.current))throw new Error("salvataggio del deck corrente fallito: cambio annullato");const M=C.current.find(W=>W.id===D);if(!M)throw new Error(`deck inesistente: ${D}`);return B.current=!1,K.current=!0,Q(M)},add:async(D,M=null)=>{const W=M===Si?C.current.find(le=>le.local):M?C.current.find(le=>le.ownerId===M):null;if(!W||W.available===!1)throw new Error("nodo owner non disponibile");const G=await Eg(e,D,W.ownerRoute),ue=Hs(G,zo(W),W.ownerTopology,W.local,!0);return J([...C.current,ue],!1),ue},rename:async(D,M)=>{const W=C.current.find(we=>we.id===D);if(!W)throw new Error("deck inesistente");if(D===E.current&&B.current&&!await A(D))throw new Error(`salvataggio di "${W.name}" fallito: rinomina annullata`);const G=C.current.find(we=>we.id===D);if(!G)throw new Error("deck inesistente");const ue=await nx(e,G.name,M,G.revision,G.ownerRoute),le=Hs(ue,zo(G),G.ownerTopology,G.local,!0),he=G.local?Si:G.ownerId;return md(_N(xl(),he,D,le.id)),J(C.current.map(we=>we.id===D?le:we),!1),le},remove:async D=>{const M=C.current.find(G=>G.id===D);if(!M)throw new Error("deck inesistente");D===E.current&&(B.current=!1),await ix(e,M.name,M.revision,M.ownerRoute);const W=M.local?Si:M.ownerId;md(yN(xl(),W,D)),J(C.current.filter(G=>G.id!==D),!1)},reorder:(D,M)=>{const W=C.current.find(re=>re.id===D),G=C.current.find(re=>re.id===M);if(!W||!G)return!1;const ue=W.local?Si:W.ownerId,le=G.local?Si:G.ownerId;if(ue!==le)return!1;const he=C.current.filter(re=>(re.local?Si:re.ownerId)===ue).map(re=>re.id),we=md(vN(xl(),ue,D,M,he));return J(Yv(C.current,we),!1),!0},addTileTo:async(D,M)=>{const W=C.current.find(re=>re.id===D);if(!W)throw new Error("deck inesistente");if(W.available===!1)throw new Error(`nodo owner offline: ${W.ownerLabel}`);const G=Lw(M,R.current,x.current);if(!G)throw new Error("riferimento sessione non valido");const ue=Q(W),le=qv(wy(ue,G),W.ownerId,W.ownerTopology),he=await ml(e,W.name,le,W.revision,W.ownerRoute),we=Hs(he,zo(W),W.ownerTopology,W.local,!0);return J(C.current.map(re=>re.id===D?we:re),!1),we},localMainId:Lr(null,"main"),parseDeckId:rc}}const sR="/sw.js",Uh="nc-sw-update";let Kh=null,qh=!1,Vh=null,mb=Object.freeze({needed:!1,kind:null,version:""}),gb=!1;function vb(){typeof window<"u"&&window.dispatchEvent(new Event(Uh))}function _b(){const e=Vh||(qh?{kind:"reload",version:""}:null);mb=Object.freeze({needed:!!e,kind:(e==null?void 0:e.kind)||null,version:(e==null?void 0:e.version)||""})}function W_(){return mb}function rR(e){return typeof window>"u"?()=>{}:(window.addEventListener(Uh,e),()=>window.removeEventListener(Uh,e))}function Ff(e){qh!==e&&(qh=e,_b(),vb())}const Ud="nc-auto-reload";function oR(){try{return typeof sessionStorage<"u"?sessionStorage:null}catch{return null}}function aR(e,t,n,s={}){let o=null;e&&t&&e!==t?o={kind:"install",version:e}:t&&n&&t!==n&&(o={kind:"reload",version:t});const a=JSON.stringify(o)===JSON.stringify(Vh);Vh=o,_b(),a||vb();const u=s.storage===void 0?oR():s.storage;if(!o){try{u&&u.removeItem(Ud)}catch{}return}if(o.kind!=="reload"||!u)return;const h=`${t}|${n}`;try{if(u.getItem(Ud)===h)return;u.setItem(Ud,h)}catch{return}(s.applyImpl||yb)()}function lR(e){e.addEventListener("statechange",()=>{e.state==="installed"&&navigator.serviceWorker.controller&&Ff(!0)})}function cR(){typeof navigator>"u"||!("serviceWorker"in navigator)||(navigator.serviceWorker.addEventListener("controllerchange",()=>{gb&&location.reload()}),navigator.serviceWorker.register(sR).then(e=>{Kh=e,e.waiting&&Ff(!0),e.addEventListener("updatefound",()=>{const t=e.installing;t&&lR(t)}),setInterval(()=>{e.update().catch(()=>{})},3600*1e3)}).catch(()=>{}))}function yb(){gb=!0,Ff(!1);const e=Kh&&Kh.waiting;e?(e.postMessage({type:"SKIP_WAITING"}),setTimeout(()=>location.reload(),4e3)):location.reload()}function uR({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")||"",m=p?`${t||""}${n||""}#pair=${p}`:"";return{token:h,pair:m,nextUrl:a}}const wb=9,bb=24,Sb="nc_side_w",U_="nc_side_min",dR=240,K_="(min-width:1024px) and (pointer:fine)";function hR(){const e=Number(localStorage.getItem(Sb));return e>=180&&e<=480?e:dR}function fR(){const e=Number(localStorage.getItem("nc_fontsize"));return e>=wb&&e<=bb?e:13}function pR(){const e={token:"",pair:""};try{const{token:t,pair:n,nextUrl:s}=uR({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 mR(e){try{return Ys($h(e))}catch{return Ar()}}function q_(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 gR(){const[e,t]=N.useState(()=>window.matchMedia(K_).matches);return N.useEffect(()=>{const n=window.matchMedia(K_),s=o=>t(o.matches);return n.addEventListener("change",s),()=>n.removeEventListener("change",s)},[]),e}function V_({session:e,node:t,ownerId:n,cellName:s,token:o,readonly:a=!1,onBack:u,onCellSwitcher:h,cellSwitcherOpen:p=!1}){En();const[m]=Cf(),[v,y]=N.useState(!1),[w,b]=N.useState(()=>window.matchMedia("(pointer: coarse)").matches),[S,C]=N.useState(null),[x,R]=N.useState(fR),[E,$]=N.useState(s||e),[B,K]=N.useState(""),V=T=>R(F=>{const k=Math.max(wb,Math.min(bb,F+T));return localStorage.setItem("nc_fontsize",String(k)),k}),Y=N.useRef(()=>{}),te=N.useRef(()=>!1),Q=N.useRef(()=>{}),J=N.useRef(!1),[H,L]=N.useState(!1),[A,z]=N.useState(!1),O=()=>{J.current=!J.current,L(J.current)};return N.useEffect(()=>{$(s||e)},[s,e]),N.useEffect(()=>{let T=!0;const F=t?t.split("/"):[],k=t?`/api/route/${t.split("/").map(encodeURIComponent).join("/")}/_`:"/api";async function I(){let M=null,W=null;try{const le=await(await Ut(`${k}/sessions`,o)).json();Array.isArray(le.sessions)&&(M=le.sessions.find(he=>he.name===e))}catch{}try{const ue=await bs(o,F);ue.available&&Array.isArray(ue.cells)&&(W=ue.cells.find(le=>le.tmuxSession===e))}catch{}if(!T)return;$(Ef({session:e,cell:W||(s?{cell:s}:null)}));let G="";W?G=`${W.engine}${W.key?`·${W.key}`:""}`:M&&(G=M.attached?`attached · ${q_(M.activity)}`:M.activity?q_(M.activity):""),K(G)}I();const D=setInterval(I,4e3);return()=>{T=!1,clearInterval(D)}},[e,t,o]),l.jsxs("div",{className:"nc-app",children:[l.jsxs("header",{className:"nc-bar nc-bar-single",children:[l.jsxs("button",{onClick:u,title:f("sessions"),children:[l.jsx(Ge,{name:"chevronLeft",size:18}),l.jsx("span",{className:"nc-bar-label",children:f("sessions")})]}),l.jsxs("span",{className:"nc-bar-center",children:[l.jsx("b",{title:t?`${E} · ${t}`:E,children:E}),B&&l.jsx("small",{className:"nc-bar-sub",children:B})]}),l.jsxs("span",{className:"nc-bar-right",children:[l.jsx("button",{onClick:()=>V(-1),title:f("zoom-out"),children:l.jsx(Ge,{name:"zoomOut",size:18})}),l.jsx("button",{onClick:()=>V(1),title:f("zoom-in"),children:l.jsx(Ge,{name:"zoomIn",size:18})}),l.jsx("button",{onClick:()=>b(T=>!T),title:f("composer"),children:l.jsx(Ge,{name:"keyboard",size:20})}),l.jsx("button",{onClick:()=>y(T=>!T),title:f("files"),children:l.jsx(Ge,{name:"folder",size:20})})]})]}),l.jsx("div",{className:"nc-termwrap",children:l.jsx(vw,{session:e,node:t,token:o,readonly:a,takeSize:!0,sendRef:Y,composerRef:te,actionRef:Q,ctrlRef:J,setCtrlArmed:L,onFiles:C,fontSize:x,selectionMode:A,onSelectionModeChange:z,keyboardGesture:m.terminalKeyboardGesture})}),l.jsx(zE,{onKeyboard:()=>b(T=>!T),onCellSwitcher:h,cellSwitcherOpen:p,send:T=>Y.current(T),action:T=>Q.current(T),ctrlArmed:H,onCtrl:O,selectionMode:A,onSelectionMode:z,keepKeyboardClosed:m.keybarKeepsKeyboardClosed,showEnter:m.showKeybarEnter,keybarLayout:m.keybarLayout}),w&&l.jsx(Nw,{submitText:T=>te.current(T),token:o,session:e,node:t,ownerId:n,keepKeyboardClosedOnVoice:m.voiceKeepsKeyboardClosed}),v&&l.jsx(_w,{session:e,node:t,token:o,filesEvent:S,onClose:()=>y(!1)})]})}function vR(){En();const[e]=N.useState(pR),[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=gR(),[m]=N.useState(()=>pN(typeof location<"u"?location.pathname:"/")),[v,y]=N.useState(m.id),w=v===Lr(null,qn),[b,S]=N.useState(null),C=de=>{const Re=ws(de);S(Re?{...Re,...typeof(de==null?void 0:de.cellName)=="string"&&de.cellName?{cellName:de.cellName}:{}}:null)},[x,R]=N.useState([]),[E,$]=N.useState([]),[B,K]=N.useState([]),[V,Y]=N.useState(()=>m.ownerId?Ar():mR(m.name)),[te,Q]=N.useState(null),[J,H]=N.useState(null),L=de=>H(ws(de)),[A,z]=N.useState(null),O=sf(t,p),T=N.useMemo(()=>(O||[]).filter(de=>de.instanceId).map(de=>({instanceId:de.instanceId,route:de.route,label:de.label,status:de.status})),[O]),F=iR(t,v,V,Y,T),k=F.decks;N.useEffect(()=>{const de=new Map;for(const Re of O||[]){const $e=(Re.route||[Re.name]).join("/"),rt=new Set((Re.sessions||[]).map(wt=>wt.name));for(const wt of Re.cells||[])!wt.cell||!wt.tmuxSession||wt.cell===wt.tmuxSession||rt.has(wt.cell)||de.set(`${$e}:${wt.cell}`,`${$e}:${wt.tmuxSession}`)}Y(Re=>Lx(Re,de))},[O]),N.useEffect(()=>{F.localNodeId&&Y(de=>{const Re=zh(de,F.localNodeId,T);return JSON.stringify(Re)===JSON.stringify(de)?de:Re})},[T,F.localNodeId]);const[I,D]=N.useState(null),[M,W]=N.useState(null),G=N.useRef(0),[ue,le]=N.useState(!1),[he,we]=N.useState(hR),[re,_e]=N.useState(!w),[ze,ut]=N.useState(()=>w?localStorage.getItem(U_)==="1":!0),[nt,Ne]=N.useState(!1),[jt,tn]=N.useState("nodes"),[De,Tt]=N.useState(!1),[Qe,vt]=N.useState(""),[mt,it]=N.useState(!1),dt=(de="nodes",Re=!1,$e="")=>{tn(de),Tt(Re),vt($e),Ne(!0)},[ot,ht]=N.useState(!1),[st,ft]=N.useState({deviceDefault:"",localNodeId:"",localNameDefault:""}),[be,ce]=N.useState(!1);N.useEffect(()=>{try{localStorage.setItem(Sb,String(he))}catch{}},[he]),N.useEffect(()=>{try{localStorage.setItem(U_,ze?"1":"")}catch{}},[ze]),N.useEffect(()=>{if(!t)return;let de=!1;return Promise.all([ny(t),Ut("/api/config",t).then(Re=>Re.json())]).then(([Re,$e])=>{de||(ft({deviceDefault:Re.deviceName||"",localNodeId:Re.nodeId||"",localNameDefault:Re.localName||""}),ce(!!$e.readonlyDefault),(Re.firstRun===!0&&!$e.readonlyDefault||s)&&ht(!0))}).catch(()=>{}),()=>{de=!0}},[t,s]);const U=N.useCallback(async()=>{try{const Re=await(await Ut("/api/sessions",t)).json();Re.error||R(Re.sessions||[])}catch{}try{const de=await bs(t);$(de.available?de.cells||[]:[]),K(de.available?de.capabilities||[]:[])}catch{$([]),K([])}},[t]);N.useEffect(()=>{if(!p)return;U();const de=setInterval(U,4e3);return()=>clearInterval(de)},[p,U]),N.useEffect(()=>{let de=!1;const Re=()=>{Ut("/api/config",t).then(rt=>rt.json()).then(rt=>{de||aR(rt.version,rt.uiVersion,"0.8.55")}).catch(()=>{})};Re();const $e=setInterval(Re,6e4);return()=>{de=!0,clearInterval($e)}},[t]);const ne=new Set([...x.map(de=>de.name),...O.flatMap(de=>de.sessions.map(Re=>Re.key))]),j=ki(V),X=de=>Y(Re=>{const $e=Lw(de,F.localNodeId,T)||de,rt=wy(Re,$e);return rt===Re&&ki(Re).length>=9&&F.setError(f("grid-full")),rt}),ie=async(de,Re=[])=>{try{await Qh(t,de,Re)}catch{return}const $e=Re.length?`${Re.join("/")}:${de}`:de;Y(rt=>Hl(rt,$e)),U()},pe=async(de,Re,$e=[])=>{try{await ty(t,de,Re,$e)}catch{return}U()},ke=async(de,Re,$e=[])=>{await J_(t,{cell:de,enabled:!!Re},$e),U()},me=async de=>{if(!I)return;const{cell:Re}=I,$e=Array.isArray(I.route)?I.route:[];if(de.action==="up"){const wt=await Xh(t,{cell:Re,boot:!!de.boot,...de.engine?{engine:de.engine}:{},...de.model!==void 0?{model:de.model}:{},...de.permissionPolicy?{permissionPolicy:de.permissionPolicy}:{}},$e),Ss=df(wt);Ss&&F.setError(Ss.text)}else await Il(t,{cell:Re,boot:!!de.boot},$e);const rt=de.action==="up"?!!de.boot:de.boot?!1:!!I.boot;W({id:++G.current,cell:Re,route:$e,enabled:rt}),U()},xe=N.useCallback(de=>{W(Re=>(Re==null?void 0:Re.id)===de?null:Re)},[]),We=async de=>{if(!(!(de!=null&&de.direct)||ue)){le(!0);try{await tf(t,de.name,de.tunnelStatus==="up"?"down":"up")}finally{le(!1)}}},lt=async(de,Re)=>{const $e=String(Re||"").trim();return!(de!=null&&de.direct)||!Ir($e)?!1:(await ry(t,de.name,$e),!0)},Ke=de=>{const Re=k.find($e=>$e.id===de);if(!Re)return!1;try{const $e=window.open(pd(Re,t),"_blank");return $e&&($e.opener=null),!!$e}catch{return!1}},pt=async de=>{if(!de||de===v)return;const Re=await F.select(de),$e=F.records.find(rt=>rt.id===de);y(de),Y(Re),Q(null),H(null);try{history.replaceState(null,"",pd($e||de,null))}catch{}},Xe=async(de,Re)=>{const $e=await F.add(de,Re);await pt($e.id)},je=async(de,Re)=>{const $e=await F.rename(de,Re);if(de===v){y($e.id),Y(zh($e.layout,F.localNodeId,T)),Q(null),H(null);try{history.replaceState(null,"",pd($e,null))}catch{}}},_t=async de=>{await F.remove(de),de===v&&await pt(F.localMainId)},Sn=async(de,Re)=>{!Re||Re===v||(await F.addTileTo(Re,de),Y($e=>Hl($e,de)))};if(!t)return l.jsxs("div",{className:"nc-auth",children:[l.jsx("p",{children:f("auth-prompt")}),l.jsx("input",{onChange:de=>n(de.target.value.trim()),placeholder:"token"}),l.jsxs("label",{children:[l.jsx("input",{type:"checkbox",checked:u,onChange:de=>h(de.target.checked)})," ",f("remember-device")]}),l.jsx("button",{onClick:()=>{(u?localStorage:sessionStorage).setItem("nc_token",t)},children:"ok"})]});const Rn=l.jsxs(l.Fragment,{children:[nt&&l.jsx(zj,{token:t,initialTab:jt,initialLocation:Qe,startNewCell:De,onClose:()=>{Ne(!1),Tt(!1),vt("")}}),ot&&l.jsx($j,{token:t,initialPair:s,...st,onPairDone:a,onDone:()=>ht(!1)}),l.jsx(qj,{token:t})]});if(!p)return A?l.jsxs(l.Fragment,{children:[l.jsx("div",{className:"nc-single-overlay",children:l.jsx(H_,{peer:A,token:t,onBack:()=>z(null)})}),Rn]}):b?l.jsxs(l.Fragment,{children:[l.jsx(V_,{session:b.session,node:b.node,ownerId:b.ownerId,cellName:b.cellName,token:t,readonly:be,onBack:()=>S(null),onCellSwitcher:()=>it(!0),cellSwitcherOpen:mt}),mt&&l.jsx(Jj,{token:t,current:b,onPick:de=>{C(de),it(!1)},onClose:()=>it(!1)}),Rn]}):l.jsxs(l.Fragment,{children:[l.jsx(Xx,{onPick:C,token:t,onSettings:dt,onOpenVlSession:z}),Rn]});const Rt=w||!re;return l.jsxs("div",{className:"nc-workspace",children:[Rt&&l.jsx(nN,{sessions:x,cells:E,activeSessions:j,nodeGroups:O,fleetCapabilities:B,bootSettlement:M,onBootSettlementApplied:xe,localNodeId:F.localNodeId,onPick:L,onAddTile:X,onPower:D,onBoot:ke,onBootError:de=>F.setError(String((de==null?void 0:de.message)||de)),onNodePower:We,onNodeRename:lt,onKill:ie,onVisibility:pe,onNew:()=>dt("fleet",!0),onSettings:dt,onOpenVlSession:z,width:he,collapsed:ze,onResize:we,onToggleCollapse:()=>ut(de=>!de)}),l.jsxs("div",{className:"nc-workspace-main",children:[l.jsx(ON,{decks:k,currentDeck:v,onCreate:Xe,onRename:je,onDelete:_t,onReorder:F.reorder,onOpenWindow:Ke,onNavigate:pt,saveState:F.saveState,error:F.error,sidebarVisible:Rt,onToggleSidebar:w?null:()=>_e(de=>!de)}),l.jsx(cN,{layout:V,onLayoutChange:Y,token:t,readonly:be,sessionsAlive:ne,focusSession:te,onFocus:Q,onOpenSingle:L,decks:k,currentDeck:v,onSendToDeck:Sn,cells:E,nodeGroups:O})]}),A&&l.jsx("div",{className:"nc-single-overlay",children:l.jsx(H_,{peer:A,token:t,onBack:()=>z(null)})}),J&&l.jsx("div",{className:"nc-single-overlay",children:l.jsx(V_,{session:J.session,node:J.node,ownerId:J.ownerId,cellName:Ef({session:J.session,node:J.node,ownerId:J.ownerId,cells:E,nodeGroups:O}),token:t,readonly:be,onBack:()=>H(null)})}),I&&l.jsx(Bl,{cell:I,token:t,route:Array.isArray(I.route)?I.route:[],onConfirm:me,onClose:()=>D(null)}),Rn]})}function _R(){En();const e=N.useSyncExternalStore(rR,W_,W_);if(!e.needed)return null;const t=e.kind==="install"?f("install-version-mismatch").replace("{v}",e.version):f("update-available").replace("{v}",e.version).replace(" "," ").trim();return l.jsxs("div",{className:"nc-update",role:"status","aria-live":"polite",children:[l.jsx("span",{className:"nc-update-msg",children:t}),e.kind==="reload"&&l.jsx("button",{className:"nc-update-btn",onClick:yb,children:f("reload")})]})}cR();g0.createRoot(document.getElementById("root")).render(l.jsxs(c0.StrictMode,{children:[l.jsx(vR,{}),l.jsx(_R,{})]}));
93
+ `],{type:"application/json"}),T=URL.createObjectURL(O),F=document.createElement("a");F.href=T,F.download="nexuscrew-diagnostics.json",F.click(),URL.revokeObjectURL(T)}catch{w(f("diagnostics-export-failed"))}};return l.jsxs("div",{className:"nc-set-tab nc-diagnostics",children:[l.jsxs("label",{className:"nc-field",children:[f("diagnostics-target"),l.jsx("select",{value:u.key,onChange:O=>a(O.target.value),children:s.map(O=>l.jsxs("option",{value:O.key,children:[O.label,O.status!=="up"?` · ${O.status}`:""]},O.key))})]}),l.jsxs("div",{className:"nc-set-form nc-diag-controls",children:[l.jsx("div",{className:"nc-sheet-label",children:f("diagnostics-verbose")}),l.jsxs("div",{className:"nc-set-row",children:[l.jsx("select",{"aria-label":f("diagnostics-duration"),value:R,onChange:O=>E(Number(O.target.value)),disabled:n,children:[300,900,1800,3600].map(O=>l.jsxs("option",{value:O,children:[O/60," min"]},O))}),l.jsx("button",{type:"button",className:"nc-btn primary",disabled:n||(h==null?void 0:h.verbose)===!0,onClick:()=>L(()=>Cg(e,!0,R,u.route)),children:f("enable")}),l.jsx("button",{type:"button",className:"nc-btn ghost",disabled:n||(h==null?void 0:h.verbose)!==!0,onClick:()=>L(()=>Cg(e,!1,R,u.route)),children:f("stop")})]}),l.jsx("small",{className:"nc-set-hint",children:h!=null&&h.verbose?f("diagnostics-expires").replace("{time}",new Date(h.expiresAt).toLocaleTimeString()):f("diagnostics-off")})]}),l.jsxs("div",{className:"nc-diag-filters",children:[l.jsxs("select",{"aria-label":f("diagnostics-level"),value:$,onChange:O=>B(O.target.value),children:[l.jsx("option",{value:"all",children:f("diagnostics-all-levels")}),["debug","info","warn","error"].map(O=>l.jsx("option",{value:O,children:O},O))]}),l.jsx("input",{"aria-label":f("diagnostics-component"),placeholder:f("diagnostics-component"),value:K,onChange:O=>V(O.target.value)})]}),l.jsxs("div",{className:"nc-set-row",children:[l.jsxs("label",{className:"nc-check",children:[l.jsx("input",{type:"checkbox",checked:b,onChange:O=>S(O.target.checked)})," ",f("diagnostics-pause")]}),l.jsxs("label",{className:"nc-check",children:[l.jsx("input",{type:"checkbox",checked:C,onChange:O=>x(O.target.checked)})," ",f("diagnostics-autoscroll")]})]}),l.jsx("pre",{ref:te,className:"nc-diag-log","aria-label":f("diagnostics-log"),children:H||f("diagnostics-empty")}),l.jsxs("div",{className:"nc-set-row",children:[l.jsx("button",{type:"button",className:"nc-btn ghost",onClick:A,children:f("copy")}),l.jsx("button",{type:"button",className:"nc-btn ghost",onClick:z,children:f("diagnostics-export")}),l.jsx("button",{type:"button",className:"nc-btn danger",disabled:n,onClick:()=>{window.confirm(f("diagnostics-clear-confirm"))&&L(async()=>{const O=await J0(e,u.route);return Y.current=0,v([]),O})},children:f("diagnostics-clear")})]}),y&&l.jsx("div",{className:"nc-err",children:y})]})}function Bj({token:e,settings:t,readonly:n,refresh:s,roster:o,section:a,setSection:u}){const[h,p]=N.useState(null),[m,v]=N.useState(null),[y,w]=N.useState(!1),[b,S]=N.useState(!1),[C,x]=N.useState(null),[R,E]=N.useState(!0),[$,B]=N.useState(!1);N.useEffect(()=>{x(t&&t.update||null),E(!t||t.autoUpdate!==!1),B(!!(t&&t.alternateScreen))},[t]);const K=async()=>{p(null),v(null),S(!0);try{const A=await L0(e);v(A.note||"ok"),w(!1)}catch(A){p(String(A.message||A))}S(!1)},V=async()=>{p(null),v(null),S(!0);try{const A=await V0(e);v(`${A.note||"ok"}${A.target?` (${A.target})`:""}`)}catch(A){p(String(A.message||A))}S(!1)},Y=async A=>{p(null),v(null),S(!0);try{await Kd(e,{autoUpdate:A}),E(A),s&&await s()}catch(z){p(String(z.message||z))}S(!1)},te=async A=>{p(null),v(null),S(!0);try{await Kd(e,{alternateScreen:A}),B(A),s&&await s()}catch(z){p(String(z.message||z))}S(!1)},Q=async()=>{p(null),v(null),S(!0);try{x(await Y0(e))}catch(A){p(String(A.message||A))}S(!1)},J=async()=>{p(null),v(null),S(!0);try{const A=await G0(e);x(A),v(f("npm-update-restarting"))}catch(A){p(String(A.message||A))}S(!1)},H=()=>{window.confirm(f("composer-clear-confirm"))&&(p(null),XE()?(window.dispatchEvent(new Event(Ih)),v(f("composer-clear-done"))):p(f("composer-clear-failed")))},L=t&&t.service;return l.jsxs("div",{className:"nc-set-tab",children:[l.jsx("div",{className:"nc-system-tabs",role:"tablist","aria-label":f("tab-system"),children:["general","diagnostics"].map(A=>l.jsx("button",{type:"button",role:"tab","aria-selected":a===A,className:`nc-set-tabbtn${a===A?" on":""}`,onClick:()=>u(A),children:f(`system-${A}`)},A))}),a==="general"&&l.jsxs(l.Fragment,{children:[l.jsxs("section",{className:"nc-system-group",children:[l.jsx("h3",{children:f("system-this-node")}),t&&l.jsxs("div",{className:"nc-set-info",children:["v",t.version," · ",t.platform," · :",t.port,l.jsx("br",{}),L&&L.installed?f("service-installed"):f("service-missing"),L&&L.installed?` · ${L.active?f("service-active"):f("service-inactive")}`:"",L?` · boot ${L.boot?"on":"off"}`:""]}),l.jsx("div",{className:"nc-set-row",children:l.jsx("button",{type:"button",className:"nc-btn ghost",disabled:n||b,title:n?f("settings-readonly"):"",onClick:V,children:f("service-regenerate")})}),l.jsx(Tj,{token:e,readonly:n}),l.jsx(Mj,{})]}),l.jsxs("section",{className:"nc-system-group",children:[l.jsx("h3",{children:f("system-updates")}),l.jsxs("div",{className:"nc-set-form nc-update-settings",children:[l.jsxs("label",{className:"nc-check",children:[l.jsx("input",{type:"checkbox",checked:R,disabled:n||b||C&&!C.supported,onChange:A=>Y(A.target.checked)}),l.jsxs("span",{children:[l.jsx("b",{children:f("npm-auto-update")}),l.jsx("small",{children:f("npm-auto-update-help")})]})]}),C&&l.jsxs("div",{className:"nc-set-info",children:[f("npm-update-current")," v",C.current,C.latest?` · ${f("npm-update-latest")} v${C.latest}`:""," · ",f(`npm-update-${C.supported?C.phase:"unsupported"}`)]}),l.jsxs("div",{className:"nc-set-row",children:[l.jsx("button",{type:"button",className:"nc-btn ghost",disabled:n||b||!C||!C.supported,onClick:Q,children:f("npm-update-check")}),C&&C.available&&l.jsx("button",{type:"button",className:"nc-btn primary",disabled:n||b||C.phase==="installing",onClick:J,children:f("npm-update-install")})]}),C&&C.lastError&&l.jsx("div",{className:"nc-err",children:C.lastError})]})]}),l.jsxs("section",{className:"nc-system-group",children:[l.jsx("h3",{children:f("system-security")}),l.jsx("div",{className:"nc-set-row",children:l.jsx("button",{type:"button",className:"nc-btn ghost",disabled:n||b,title:n?f("settings-readonly"):"",onClick:()=>{p(null),v(null),w(!0)},children:f("token-rotate")})})]}),l.jsxs("section",{className:"nc-system-group",children:[l.jsx("h3",{children:f("system-local-data")}),l.jsxs("div",{className:"nc-set-form",children:[l.jsx("div",{className:"nc-sheet-label",children:f("composer-clear-data")}),l.jsx("small",{className:"nc-set-hint",children:f("composer-clear-data-help")}),l.jsx("div",{className:"nc-set-row",children:l.jsx("button",{type:"button",className:"nc-btn ghost",onClick:H,children:f("composer-clear-data")})})]})]})]}),a==="diagnostics"&&l.jsxs("section",{className:"nc-system-group nc-system-diagnostics",children:[l.jsx("h3",{children:f("system-diagnostics")}),l.jsxs("div",{className:"nc-set-form nc-alternate-screen-settings",children:[l.jsx("div",{className:"nc-sheet-label",children:f("system-terminal")}),l.jsxs("label",{className:"nc-check",children:[l.jsx("input",{type:"checkbox","aria-label":f("alternate-screen"),checked:$,disabled:n||b,onChange:A=>te(A.target.checked)}),l.jsxs("span",{children:[l.jsx("b",{children:f("alternate-screen")}),l.jsx("small",{children:f("alternate-screen-help")})]})]})]}),l.jsx(Oj,{token:e,roster:o,readonly:n})]}),y&&l.jsxs("div",{className:"nc-set-confirm",children:[l.jsx("div",{children:f("token-rotate-explain")}),l.jsxs("div",{className:"nc-sheet-actions",children:[l.jsx("button",{type:"button",className:"nc-btn ghost",disabled:b,onClick:()=>w(!1),children:f("cancel")}),l.jsx("button",{type:"button",className:"nc-btn primary",disabled:b,onClick:K,children:f("confirm")})]})]}),m&&l.jsx("div",{className:"nc-set-note",children:m}),h&&l.jsx("div",{className:"nc-err",children:h})]})}function zj({token:e,onClose:t,initialTab:n="nodes",initialLocation:s="",startNewCell:o=!1}){En();const a=n==="diagnostics"?"diagnostics":"general",[u,h]=N.useState(n==="diagnostics"?"system":n),p=N.useRef(null),m=N.useRef(null),[v,y]=N.useState({start:!1,end:!1}),[w,b]=N.useState(a),[S,C]=N.useState(null),[x,R]=N.useState([]),[E,$]=N.useState([]),[B,K]=N.useState(!1),[V,Y]=N.useState(null),[te,Q]=N.useState(0),J=sf(e,!0,te),H=N.useCallback(()=>{const A=p.current;if(!A)return;const z=A.scrollWidth>A.clientWidth+1,O={start:z&&A.scrollLeft>1,end:z&&A.scrollLeft+A.clientWidth<A.scrollWidth-1};y(T=>T.start===O.start&&T.end===O.end?T:O)},[]);N.useEffect(()=>{const A=p.current;if(!A)return;const z=typeof ResizeObserver=="function"?new ResizeObserver(H):null;return z==null||z.observe(A),window.addEventListener("resize",H),H(),()=>{z==null||z.disconnect(),window.removeEventListener("resize",H)}},[H]),N.useEffect(()=>{var z,O;(O=(z=m.current)==null?void 0:z.scrollIntoView)==null||O.call(z,{behavior:"smooth",block:"nearest",inline:"nearest"});const A=window.requestAnimationFrame?window.requestAnimationFrame(H):setTimeout(H,0);return()=>{window.cancelAnimationFrame?window.cancelAnimationFrame(A):clearTimeout(A)}},[u,H]);const L=N.useCallback(async()=>{var A;try{const z=await ny(e);C(z),Y(null)}catch(z){Y(String(z.message||z))}try{const O=(await P0(e)).peers||[];let T=[],F=[];try{const[k,I]=await Promise.all([Ut("/api/config",e).then(G=>G.json()).catch(()=>null),sy(e).catch(()=>null)]),D=k&&typeof k.instanceId=="string"?k.instanceId:"",M=[{instanceId:D||null,route:[],label:null},...fy(I,D)],W=await Promise.all(M.map(async G=>{try{return{ok:!0,peers:((await iy(e,G.route)).nodes||[]).map(he=>hy(he,G)).filter(Boolean)}}catch(ue){return{ok:!1,owner:G,error:ue}}}));for(const G of W){if(G.ok){T.push(...G.peers);continue}G.owner.route.length!==0&&F.push({instanceId:G.owner.instanceId,label:G.owner.label,route:G.owner.route,failure:/timeout/i.test(String(((A=G.error)==null?void 0:A.message)||G.error))?"timeout":"unreachable"})}}catch{}$(F),R([...O,...T])}catch(z){Y(String(z.message||z))}},[e]);return N.useEffect(()=>{L();const A=setInterval(L,5e3);return()=>clearInterval(A)},[L]),N.useEffect(()=>{let A=!1;return Ut("/api/config",e).then(z=>z.json()).then(z=>{A||K(!!z.readonlyDefault)}).catch(()=>{}),()=>{A=!0}},[e]),l.jsx("div",{className:"nc-set-overlay",onClick:t,children:l.jsxs("div",{className:"nc-set-panel",onClick:A=>A.stopPropagation(),children:[l.jsxs("div",{className:"nc-set-head",children:[l.jsx(Ge,{name:"gear",size:18}),l.jsx("b",{children:f("settings")}),l.jsx("button",{type:"button",className:"nc-set-close",onClick:t,title:f("close"),children:l.jsx(Ge,{name:"x",size:18})})]}),B&&l.jsx("div",{className:"nc-set-readonly",children:f("settings-readonly")}),V&&l.jsx("div",{className:"nc-err",children:V}),l.jsx("div",{className:`nc-set-tabs-wrap${v.start?" has-start-overflow":""}${v.end?" has-end-overflow":""}`,children:l.jsx("div",{className:"nc-set-tabs",ref:p,onScroll:H,children:["nodes","fleet","audio","input","system"].map(A=>l.jsx("button",{ref:u===A?m:null,type:"button",className:`nc-set-tabbtn${u===A?" on":""}`,onClick:()=>h(A),children:f(`tab-${A}`)},A))})}),l.jsxs("div",{className:"nc-set-body",children:[u==="nodes"&&l.jsx(Lj,{token:e,nodes:x,roster:J,settings:S,readonly:B,vlUnavailable:E,refresh:L,refreshAliases:()=>Q(A=>A+1)}),u==="fleet"&&l.jsx(fj,{token:e,readonly:B,startNewCell:o,initialLocation:s,targets:J.map(A=>({route:A.route,label:A.label||A.name,status:A.status}))}),u==="audio"&&l.jsx(Dj,{token:e,readonly:B,nodes:x,settings:S}),u==="input"&&l.jsx(Ij,{}),u==="system"&&l.jsx(Bj,{token:e,settings:S,readonly:B,refresh:L,roster:J,section:w,setSection:b})]})]})})}function $j({token:e,initialPair:t,deviceDefault:n="",localNodeId:s="",localNameDefault:o="",onPairDone:a,onDone:u}){En();const[h,p]=N.useState(t?"pair":"welcome"),[m,v]=N.useState(!1),[y,w]=N.useState(null),b=async()=>{v(!0),w(null);try{await Kd(e,{wizardDone:!0}),a&&a(),u()}catch(S){w(String(S.message||S)),v(!1)}};return l.jsx("div",{className:"nc-wiz-overlay",children:l.jsxs("div",{className:"nc-wiz",children:[l.jsxs("div",{className:"nc-wiz-head",children:[l.jsx("b",{children:f("wizard-title")}),l.jsx("small",{children:f("hydra-simple")})]}),h==="welcome"&&l.jsxs("div",{className:"nc-wiz-body",children:[l.jsx("div",{className:"nc-wiz-done",children:f("local-ready")}),l.jsxs("div",{className:"nc-sheet-actions",children:[l.jsx("button",{className:"nc-btn ghost",disabled:m,onClick:b,children:f("local-only")}),l.jsx("button",{className:"nc-btn primary",disabled:m,onClick:()=>p("pair"),children:f("add-node")})]})]}),h==="pair"&&l.jsxs("div",{className:"nc-wiz-body",children:[l.jsx(Xw,{token:e,initial:t||"",autoStart:!!t,deviceDefault:n,localNodeId:s,localNameDefault:o,onBusyChange:v,onSuccess:async()=>{a&&a(),p("done")}}),l.jsx("div",{className:"nc-sheet-actions",children:l.jsx("button",{className:"nc-btn ghost",disabled:m,onClick:()=>{a&&a(),p("welcome")},children:f("back")})})]}),h==="done"&&l.jsxs("div",{className:"nc-wiz-body",children:[l.jsx("div",{className:"nc-wiz-done",children:f("node-connected")}),l.jsx("div",{className:"nc-sheet-actions",children:l.jsx("button",{className:"nc-btn primary",disabled:m,onClick:b,children:f("finish")})})]}),y&&l.jsx("div",{className:"nc-err",children:y})]})})}function Fj(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 Hj=6e3,Wj=12e3;function Uj({n:e,onClose:t}){return l.jsxs("div",{className:`nc-ntf-toast${e.urgency==="high"?" high":""}`,role:"status","aria-live":"polite",children:[l.jsxs("div",{className:"nc-ntf-toast-txt",children:[l.jsx("b",{children:e.title}),e.body&&l.jsx("small",{children:e.body}),e.session&&l.jsx("span",{className:"nc-ntf-from",children:e.session})]}),l.jsx("button",{type:"button",className:"nc-ntf-x",onClick:t,title:f("close"),children:l.jsx(Ge,{name:"x",size:14})})]})}function Kj({ask:e,token:t,onAnswered:n,onDismiss:s}){const[o,a]=N.useState(""),[u,h]=N.useState(!1),[p,m]=N.useState(null),[v,y]=N.useState(!1),w=async S=>{const C=String(S||"").trim();if(!(!C||u)){m(null),h(!0);try{await ex(t,e.id,C),n(e.id)}catch(x){m(String(x.message||x))}h(!1)}},b=async()=>{if(!v){y(!0);try{await tx(t,e.id),s(e.id)}catch{y(!1)}}};return l.jsxs("div",{className:"nc-ask-card",children:[l.jsxs("div",{className:"nc-ask-head",children:[l.jsx("span",{className:"nc-ntf-from",children:e.session}),l.jsxs("code",{className:"nc-ask-id",children:["#",e.id]}),l.jsx("button",{type:"button",className:"nc-ask-dismiss",title:f("ask-dismiss"),"aria-label":f("ask-dismiss"),disabled:v,onClick:b,children:l.jsx(Ge,{name:"x",size:14})})]}),l.jsx("div",{className:"nc-ask-q",children:e.question}),Array.isArray(e.options)&&e.options.length>0&&l.jsx("div",{className:"nc-ask-opts",children:e.options.map(S=>l.jsx("button",{type:"button",className:"nc-btn ghost",disabled:u,onClick:()=>w(S),children:S},S))}),l.jsxs("div",{className:"nc-ask-reply",children:[l.jsx("textarea",{rows:2,placeholder:f("ask-reply-ph"),value:o,disabled:u,onChange:S=>a(S.target.value)}),l.jsx("button",{type:"button",className:"nc-btn primary",disabled:u||!o.trim(),onClick:()=>w(o),children:f("send")})]}),p&&l.jsx("div",{className:"nc-err",children:p})]})}function qj({token:e}){const[t]=En(),[n]=fb(),[s,o]=N.useState([]),[a,u]=N.useState([]),[h,p]=N.useState(()=>{try{return/(?:^|[#&])ask=/.test(location.hash)}catch{return!1}}),m=N.useRef(0),v=N.useRef(null);v.current||(v.current=Rj());const y=N.useRef({enabled:n,lang:t});y.current={enabled:n,lang:t};const w=N.useCallback(x=>{o(R=>R.filter(E=>E.key!==x))},[]),b=N.useCallback(x=>{const R=`t${m.current+=1}`;o($=>[...$.slice(-3),{...x,key:R}]),setTimeout(()=>w(R),x.urgency==="high"?Wj:Hj);const E=y.current;if(E.enabled)try{v.current.enqueue(x,kj(x,E.lang))}catch{}},[w]);N.useEffect(()=>{n||v.current.stop()},[n]),N.useEffect(()=>{const x=()=>{(document.visibilityState!=="visible"||!document.hasFocus())&&v.current.stop()},R=()=>v.current.stop();return document.addEventListener("visibilitychange",x),window.addEventListener("blur",x),window.addEventListener(Hh,R),()=>{document.removeEventListener("visibilitychange",x),window.removeEventListener("blur",x),window.removeEventListener(Hh,R),typeof v.current.dispose=="function"?v.current.dispose():v.current.stop()}},[]),N.useEffect(()=>{if(!e)return;let x=!1;Z0(e).then(E=>{x||u(E.asks||[])}).catch(()=>{});const R=Fj(e,E=>{E.type==="notify"?b(E):E.type==="ask"&&E.ask&&E.ask.id?u($=>$.some(B=>B.id===E.ask.id)?$:[...$,E.ask]):E.type==="ask-answered"&&E.id?u($=>$.filter(B=>B.id!==E.id)):E.type==="ask-dismissed"&&E.id&&u($=>$.filter(B=>B.id!==E.id))});return()=>{x=!0,R()}},[e,b]);const S=x=>u(R=>R.filter(E=>E.id!==x)),C=x=>u(R=>R.filter(E=>E.id!==x));return l.jsxs(l.Fragment,{children:[s.length>0&&l.jsx("div",{className:"nc-ntf-toasts",children:s.map(x=>l.jsx(Uj,{n:x,onClose:()=>w(x.key)},x.key))}),a.length>0&&!h&&l.jsxs("button",{type:"button",className:"nc-ask-badge",onClick:()=>p(!0),title:f("asks-title"),children:["? ",l.jsx("span",{className:"nc-ask-count",children:a.length})]}),a.length>0&&h&&l.jsxs("div",{className:"nc-ask-panel",children:[l.jsxs("div",{className:"nc-ask-panel-head",children:[l.jsx("b",{children:f("asks-title")}),l.jsx("span",{className:"nc-ask-count",children:a.length}),l.jsx("button",{type:"button",className:"nc-ntf-x",onClick:()=>p(!1),title:f("close"),children:l.jsx(Ge,{name:"x",size:16})})]}),l.jsx("div",{className:"nc-ask-panel-body",children:a.map(x=>l.jsx(Kj,{ask:x,token:e,onAnswered:S,onDismiss:C},x.id))})]})]})}const Vj=4e3;async function Yj(e){const t=await Ut("/api/sessions",e);if((t==null?void 0:t.ok)===!1)throw new Error(`HTTP ${t.status}`);const n=await t.json();if(!Array.isArray(n==null?void 0:n.sessions))throw new Error("invalid sessions payload");return n.sessions}async function Fd(e,t=[]){var h;const[n,s]=await Promise.allSettled([t.length?Zh(e,t):Yj(e),bs(e,t)]),o=n.status==="fulfilled"&&Array.isArray((h=n.value)==null?void 0:h.sessions)?n.value.sessions:Array.isArray(n.value)?n.value:null,a=s.status==="fulfilled"?s.value:null,u=(a==null?void 0:a.available)===!0&&Array.isArray(a.cells)?a.cells:null;return{sessions:o,cells:u,fresh:Array.isArray(o)&&Array.isArray(u)}}function pb(e,t,n){return n===!0&&(e==null?void 0:e.degraded)!==!0&&(e==null?void 0:e.active)===!0&&e.tmux!==!1&&!!e.tmuxSession&&(t||[]).some(s=>(s==null?void 0:s.name)===e.tmuxSession)}function Gj(e){const t=new Map((e.sessions||[]).map(o=>[o.name,o])),n=[],s=(o,a,u,h=[],p="")=>{const m=new Map((a||[]).map(v=>[v.name,v]));for(const v of o||[]){const y=m.get(v.tmuxSession)||{},w=af(v,y),b=pb(v,a,u);n.push({key:Go(h,v.tmuxSession||v.cell),session:v.tmuxSession,route:h,cellName:v.cell,label:v.cell,node:h.length?h.join("/"):"",nodeLabel:p,live:b,selectable:b,verified:u===!0,working:w.working,degraded:!!v.degraded,active:v.active===!0,activity:y.activity||v.activity||0,subtitle:w.subtitle})}};s(e.cells,[...t.values()],e.localFresh===!0);for(const o of e.nodeGroups||[]){const a=Array.isArray(o.route)?o.route:[];o.kind==="vl"||!a.length||s(o.cells,o.sessions,o.switcherFresh===!0,a,o.label||o.name||"")}return n}function Xj(e){const t=new Map,n=Array.isArray(e.sessions)?e.sessions:[],s=Array.isArray(e.cells)?e.cells:[],o=new Map(n.map(u=>[u.name,u])),a=new Set(s.map(u=>u.tmuxSession).filter(Boolean));t.set("local",lf(s,n.filter(u=>!a.has(u.name)),o));for(const u of e.nodeGroups||[]){const h=Array.isArray(u.route)?u.route:[];if(u.kind==="vl"||!h.length)continue;const p=Array.isArray(u.cells)?u.cells:[],m=Array.isArray(u.sessions)?u.sessions:[],v=new Set(p.map(y=>y.tmuxSession).filter(Boolean));t.set(h.join("/"),$l({...u,route:h,cells:p,sessions:m,unmanaged:m.filter(y=>!v.has(y.name))}).rawItems)}return t}function Qj(e,t,n,s){return[...new Set(e.map(a=>a.node||"local"))].flatMap(a=>{const u=e.filter(v=>(v.node||"local")===a),h=new Map((t.get(a)||[]).map(v=>[v.key,v])),p=new Map(u.map(v=>[v.key,v])),m=u.map(v=>{const y=h.get(v.key);return{...v,label:(y==null?void 0:y.label)||v.label,live:(y==null?void 0:y.live)??v.live,fresh:(y==null?void 0:y.fresh)===!0,activity:(y==null?void 0:y.activity)??v.activity}});return vs(m,n,"all",$i(s,a)).map(v=>p.get(v.key))})}function Jj({token:e,current:t,onPick:n,onClose:s}){const[o,a]=N.useState(Bg),[u,h]=N.useState(!1),[p,m]=N.useState(!1),[v,y]=N.useState(""),[w,b]=N.useState(""),[S,C]=N.useState(""),x=N.useRef(null),R=N.useRef(null),E=N.useMemo(()=>Gj(o),[o]),$=N.useMemo(()=>Xj(o),[o]),{pins:B,orders:K,canMoveRoster:V,moveRoster:Y,stepRoster:te}=of(),Q=N.useMemo(()=>Qj(E,$,B,K),[E,$,B,K]),J=N.useMemo(()=>u?Q:Q.filter(O=>O.selectable||O.degraded&&O.active),[Q,u]),H=N.useMemo(()=>E.find(O=>O.key===w&&O.selectable),[E,w]);N.useEffect(()=>{var F;const O=document.activeElement;(F=R.current)==null||F.focus();const T=k=>{k.key==="Escape"&&s()};return document.addEventListener("keydown",T),()=>{var k;document.removeEventListener("keydown",T),(k=O==null?void 0:O.focus)==null||k.call(O)}},[s]),N.useEffect(()=>{let O=!0,T=!1;const F=async()=>{if(T)return;T=!0;const I=Bg(),D=Array.isArray(I.nodeGroups)?I.nodeGroups:[],M=Fd(e),W=re=>re.kind!=="vl"&&Array.isArray(re.route)&&re.route.length>0,G=await Promise.all(D.filter(W).map(async re=>({group:re,result:await Fd(e,re.route)}))),ue=await M;if(!O)return;const le=new Map(G.map(({group:re,result:_e})=>[JSON.stringify(re.route||[]),_e])),he=D.map(re=>{if(!W(re))return{...re,switcherFresh:!1};const _e=le.get(JSON.stringify(re.route||[]));return _e?{...re,sessions:_e.sessions||re.sessions||[],cells:_e.cells||re.cells||[],switcherFresh:_e.fresh}:{...re,switcherFresh:!1}}),we=xy({...I,sessions:ue.sessions||I.sessions||[],cells:ue.cells||I.cells||[],localFresh:ue.fresh,nodeGroups:he,refreshedAt:Date.now()});a(we),m(!0),T=!1};F();const k=setInterval(F,Vj);return()=>{O=!1,clearInterval(k)}},[e]);const L=O=>O.degraded?f("cell-degraded"):O.verified?O.selectable?O.working?f("cell-working"):f("cell-idle"):f("cell-off"):f("cell-switcher-not-confirmed"),A=O=>{if(y(""),!O.selectable){y(f("cell-switcher-not-active"));return}b(O.key)},z=async()=>{const O=H;if(!O){y(f("cell-switcher-select"));return}y(""),C(O.key);try{const T=await Fd(e,O.route),F=(T.cells||[]).find(k=>(k==null?void 0:k.cell)===O.cellName&&(k==null?void 0:k.tmuxSession)===O.session);if(!pb(F,T.sessions,T.fresh)){y(f("cell-switcher-not-active"));return}n({session:O.session,...O.node?{node:O.node}:{},cellName:O.cellName}),s()}catch{y(f("cell-switcher-not-active"))}finally{C("")}};return l.jsx("div",{className:"nc-cell-switcher-backdrop",onClick:s,children:l.jsxs("aside",{ref:x,className:"nc-cell-switcher",role:"dialog","aria-label":f("fleet-cells"),tabIndex:-1,onClick:O=>O.stopPropagation(),children:[l.jsxs("div",{className:"nc-cell-switcher-list",children:[!p&&l.jsx("div",{className:"nc-empty",role:"status",children:f("cell-switcher-refreshing")}),p&&J.length===0&&l.jsx("div",{className:"nc-empty",role:"status",children:f("cell-switcher-empty-active")}),J.map(O=>{const T=(t==null?void 0:t.session)===O.session&&((t==null?void 0:t.node)||"")===O.node,F=w===O.key,k=L(O),I=O.node||"local",D=$.get(I)||E.filter(M=>(M.node||"local")===I);return l.jsxs("div",{className:`nc-cell-switcher-row${T?" current":""}${F?" selected":""}${O.selectable?"":" off"}`,"data-roster-key":O.key,"data-position":I,children:[l.jsx(bi,{position:I,itemKey:O.key,label:O.cellName,canMove:V,onMove:(M,W)=>Y(I,M,W,D),onStep:M=>te(I,O.key,M,D)}),l.jsxs("button",{type:"button",className:"nc-cell-switcher-row-select","aria-current":T?"true":void 0,"aria-pressed":F,"aria-disabled":!O.selectable,disabled:S===O.key,onClick:()=>A(O),children:[l.jsx("span",{className:`nc-cell-switcher-dot${O.degraded?" warn":O.live?` on${O.working?" working":""}`:""}`}),l.jsxs("span",{className:"nc-cell-switcher-copy",children:[l.jsx("b",{children:O.cellName}),l.jsx("small",{className:"nc-cell-switcher-state",children:k}),l.jsx("small",{children:[O.nodeLabel,O.subtitle].filter(Boolean).join(" · ")})]})]})]},O.key)})]}),v&&l.jsx("div",{className:"nc-cell-switcher-notice",role:"status",children:v}),l.jsx("div",{className:"nc-cell-switcher-actions",children:l.jsx("button",{type:"button",className:"nc-cell-switcher-open",disabled:!H||!!S,onClick:z,children:H?`${f("cell-switcher-open")}: ${H.cellName}`:f("cell-switcher-select")})}),l.jsxs("div",{className:"nc-cell-switcher-controls",children:[l.jsx("b",{children:f("fleet-cells")}),l.jsx("button",{type:"button",className:"nc-cell-switcher-filter","aria-pressed":u,onClick:()=>{y(""),h(O=>!O)},children:f(u?"cell-switcher-show-active":"cell-switcher-show-all")}),l.jsx("button",{ref:R,type:"button",className:"nc-cell-switcher-close","aria-label":f("cell-switcher-close"),title:f("cell-switcher-close"),onClick:s,children:"×"})]})]})})}const Zj=2e3;function eR(e){if(e.kind==="gap")return`${f("vl-events-gap")} ${e.count||"?"}`;if(e.kind==="truncate")return f("vl-events-truncated");if(e.kind==="turn_end")return f("vl-events-turn-end");if(e.kind==="done")return f("vl-events-done");if(e.kind==="writer_epoch")return f("vl-events-writer-epoch");if(e.kind==="tool_start")return`${f("vl-events-tool")} ${e.name||""}`.trim();if(e.kind==="tool_end"){const t=e.isError?f("vl-events-tool-failed"):f("vl-events-tool-ok");return`${f("vl-events-tool")} ${e.name||""} — ${t}`.trim()}return e.kind==="usage"?e.text||f("vl-events-usage"):e.text||""}function tR({token:e,nodeId:t,route:n=[]}){const[s,o]=N.useState([]),[a,u]=N.useState(!1),h=N.useRef(0),p=N.useRef(!1);return N.useEffect(()=>{let m=!0;h.current=0,p.current=!1,o([]);const v=async()=>{if(!p.current){p.current=!0;try{const b=await A0(e,t,h.current,n);if(!m)return;u(!1);const C=(Array.isArray(b==null?void 0:b.events)?b.events:[]).filter(x=>Number.isSafeInteger(x==null?void 0:x.seq)&&x.seq>h.current);C.length&&(o(x=>x.concat(C).slice(-500)),h.current=C[C.length-1].seq),Number.isSafeInteger(b==null?void 0:b.cursor)&&b.cursor>h.current&&(h.current=b.cursor)}catch{m&&u(!0)}finally{p.current=!1}}},y=()=>{v().catch(()=>{})};y();const w=setInterval(y,Zj);return()=>{m=!1,clearInterval(w)}},[e,t,JSON.stringify(n)]),l.jsxs("div",{className:"nc-vl-events",children:[a&&l.jsx("div",{className:"nc-set-hint nc-vl-events-stale",children:f("vl-events-stale")}),s.length===0&&!a&&l.jsx("small",{className:"nc-set-hint","data-testid":"vl-events-empty",children:f("vl-events-empty")}),s.length>0&&l.jsx("ol",{className:"nc-vl-events-list",children:s.map(m=>l.jsx("li",{"data-testid":`vl-ev-${m.seq}`,className:`nc-vl-ev nc-vl-ev-${m.kind}${m.isError?" error":""}${m.kind==="gap"?" gap":""}`,children:eR(m)},`${m.seq}-${m.kind}`))})]})}function H_({peer:e,token:t,onBack:n}){var s;return En(),e?l.jsxs("section",{className:"nc-vl-session-view",children:[l.jsxs("header",{className:"nc-bar nc-bar-single",children:[l.jsxs("button",{onClick:n,title:f("back"),children:[l.jsx(Ge,{name:"chevronLeft",size:18}),l.jsx("span",{className:"nc-bar-label",children:f("back")})]}),l.jsxs("span",{className:"nc-bar-center",children:[l.jsx("b",{title:e.label,children:e.label}),((s=e.session)==null?void 0:s.profile)&&l.jsxs("small",{className:"nc-bar-sub",children:[e.session.profile," · ",f("vl-events-title")]})]}),l.jsx("span",{className:"nc-bar-right"})]}),l.jsx("div",{className:"nc-vl-session-body",children:l.jsx(tR,{token:t,nodeId:e.nodeId,route:e.route||[]})})]}):null}const Hd=e=>ki(Ys(e)).length===0,Wd=e=>Array.isArray(e)?e.join("/"):"";function nR(e){const t=new Set,n=[];for(const s of Array.isArray(e)?e:[])!s||!Kn.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 zo(e){return{instanceId:e.ownerId,route:e.ownerRoute||[],label:e.ownerLabel,status:e.available===!1?"offline":"up"}}function Hs(e,t,n,s=!1,o=!0){const a=t.instanceId;return{...e,id:Lr(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:Bh(e.layout,a,n)}}function iR(e,t,n,s,o=[]){const[a,u]=N.useState([]),[h,p]=N.useState(!1),[m,v]=N.useState("idle"),[y,w]=N.useState(""),[b,S]=N.useState(""),C=N.useRef([]),x=N.useRef([]),R=N.useRef(""),E=N.useRef(t),$=N.useRef(n),B=N.useRef(!1),K=N.useRef(!0),V=N.useRef(""),Y=N.useMemo(()=>nR(o),[o]),te=Y.map(D=>`${D.instanceId}:${Wd(D.route)}:${D.status}:${D.label}`).join("|");x.current=Y,$.current=n,E.current=t,C.current=a;const Q=N.useCallback(D=>zh(D.layout,R.current,x.current),[]),J=N.useCallback((D,M=!0,W=E.current)=>{const G=Yv(D,xl()),ue=C.current.some(he=>he.id===W);C.current=G,u(G);const le=G.find(he=>he.id===W);if(M&&le){K.current=!0;const he=Q(le);s(he),le.local&&wN(le.name,he)}else ue&&!le&&(K.current=!0,s(Ar()),w("deck non più condiviso dal nodo owner"));gN(G.filter(he=>he.local).map(he=>he.name))},[s,Q]),H=N.useCallback(async D=>{let M=await pl(e);const W=M.decks.find(G=>G.name==="main");if(M.decks.length===1&&W&&W.revision===0&&Hd(W.layout)){const G=mN(),ue=Ys($h("main")||Ar());if(!Hd(ue)){const le=Bh(ue,D,[]);M.decks[0]=await ml(e,"main",le,0,[])}for(const le of G.filter(he=>he!=="main"))try{let he=await Eg(e,le,[]);const we=Ys($h(le)||Ar());Hd(we)||(he=await ml(e,le,Bh(we,D,[]),he.revision,[]))}catch{}M=await pl(e)}return M},[e]),L=N.useCallback(async({migrate:D=!1}={})=>{const M=await ef(e,[]),W=Kn.test(String(M.instanceId||""))?M.instanceId:"";if(!W)throw new Error("instanceId locale non disponibile");R.current=W,S(W);const[G,ue]=await Promise.all([D?H(W):pl(e),Sg(e,[]).catch(()=>({nodes:[]}))]),le={instanceId:W,route:[],label:"Local"},he=G.decks.map(re=>Hs(re,le,ue.nodes,!0,!0)),we=C.current;return await Promise.all(x.current.map(async re=>{if(re.status!=="up"){he.push(...we.filter(_e=>!_e.local&&_e.ownerId===re.instanceId).map(_e=>({..._e,ownerRoute:[...re.route],ownerLabel:re.label,available:!1})));return}try{const[_e,ze]=await Promise.all([pl(e,re.route),Sg(e,re.route).catch(()=>({nodes:[]}))]);he.push(..._e.decks.map(ut=>Hs(ut,re,ze.nodes,!1,!0)))}catch{he.push(...we.filter(ze=>!ze.local&&ze.ownerId===re.instanceId).map(ze=>({...ze,ownerRoute:[...re.route],ownerLabel:re.label,available:!1})))}})),he.sort((re,_e)=>re.local===_e.local?re.ownerLabel.localeCompare(_e.ownerLabel)||(re.name==="main"?-1:_e.name==="main"?1:re.name.localeCompare(_e.name)):re.local?-1:1),he},[e,H,te]);N.useEffect(()=>{if(!e)return;let D=!1;const M=V.current!==e;return V.current=e,L({migrate:M}).then(W=>{if(D)return;const G=C.current.find(he=>he.id===E.current),ue=W.find(he=>he.id===E.current),le=ue&&(!G||ue.revision>G.revision||G.available!==ue.available||Wd(G.ownerRoute)!==Wd(ue.ownerRoute));J(W,M||!!le&&!B.current),p(!0),ue&&w("")}).catch(W=>{D||(p(!0),w(String(W.message||W)))}),()=>{D=!0}},[J,L,te,e]);const A=N.useCallback(async(D=E.current)=>{if(!h||!B.current)return!0;const M=C.current.find(W=>W.id===D);if(!M)return w(`deck inesistente: ${D}`),!1;if(M.available===!1)return w(`nodo owner offline: ${M.ownerLabel}`),!1;v("saving");try{const W=qv(Ys($.current),M.ownerId,M.ownerTopology),G=await ml(e,M.name,W,M.revision,M.ownerRoute),ue=Hs(G,zo(M),M.ownerTopology,M.local,!0);return J(C.current.map(le=>le.id===D?ue:le),!1),B.current=!1,v("saved"),w(""),setTimeout(()=>v("idle"),1500),!0}catch(W){if(v("error"),w(String(W.message||W)),W.status===409&&W.data&&W.data.current){const G=C.current.find(le=>le.id===D),ue=Hs(W.data.current,zo(G),G.ownerTopology,G.local,!0);J(C.current.map(le=>le.id===D?ue:le),!1)}return!1}},[h,e,J]);return N.useEffect(()=>{if(!h)return;if(K.current){K.current=!1;return}B.current=!0,v("saving");const D=setTimeout(A,650);return()=>clearTimeout(D)},[n,h,A]),N.useEffect(()=>{if(!h)return;const D=setInterval(async()=>{try{const M=await L(),W=C.current.find(le=>le.id===E.current),G=M.find(le=>le.id===E.current),ue=G&&(!W||G.revision>W.revision||W.available!==G.available);J(M,ue&&!B.current)}catch{}},5e3);return()=>clearInterval(D)},[h,L,J]),{decks:a,records:a,localNodeId:b,ready:h,saveState:m,error:y,setError:w,saveNow:A,select:async D=>{if(B.current&&!await A(E.current))throw new Error("salvataggio del deck corrente fallito: cambio annullato");const M=C.current.find(W=>W.id===D);if(!M)throw new Error(`deck inesistente: ${D}`);return B.current=!1,K.current=!0,Q(M)},add:async(D,M=null)=>{const W=M===Si?C.current.find(le=>le.local):M?C.current.find(le=>le.ownerId===M):null;if(!W||W.available===!1)throw new Error("nodo owner non disponibile");const G=await Eg(e,D,W.ownerRoute),ue=Hs(G,zo(W),W.ownerTopology,W.local,!0);return J([...C.current,ue],!1),ue},rename:async(D,M)=>{const W=C.current.find(we=>we.id===D);if(!W)throw new Error("deck inesistente");if(D===E.current&&B.current&&!await A(D))throw new Error(`salvataggio di "${W.name}" fallito: rinomina annullata`);const G=C.current.find(we=>we.id===D);if(!G)throw new Error("deck inesistente");const ue=await nx(e,G.name,M,G.revision,G.ownerRoute),le=Hs(ue,zo(G),G.ownerTopology,G.local,!0),he=G.local?Si:G.ownerId;return md(_N(xl(),he,D,le.id)),J(C.current.map(we=>we.id===D?le:we),!1),le},remove:async D=>{const M=C.current.find(G=>G.id===D);if(!M)throw new Error("deck inesistente");D===E.current&&(B.current=!1),await ix(e,M.name,M.revision,M.ownerRoute);const W=M.local?Si:M.ownerId;md(yN(xl(),W,D)),J(C.current.filter(G=>G.id!==D),!1)},reorder:(D,M)=>{const W=C.current.find(re=>re.id===D),G=C.current.find(re=>re.id===M);if(!W||!G)return!1;const ue=W.local?Si:W.ownerId,le=G.local?Si:G.ownerId;if(ue!==le)return!1;const he=C.current.filter(re=>(re.local?Si:re.ownerId)===ue).map(re=>re.id),we=md(vN(xl(),ue,D,M,he));return J(Yv(C.current,we),!1),!0},addTileTo:async(D,M)=>{const W=C.current.find(re=>re.id===D);if(!W)throw new Error("deck inesistente");if(W.available===!1)throw new Error(`nodo owner offline: ${W.ownerLabel}`);const G=Lw(M,R.current,x.current);if(!G)throw new Error("riferimento sessione non valido");const ue=Q(W),le=qv(wy(ue,G),W.ownerId,W.ownerTopology),he=await ml(e,W.name,le,W.revision,W.ownerRoute),we=Hs(he,zo(W),W.ownerTopology,W.local,!0);return J(C.current.map(re=>re.id===D?we:re),!1),we},localMainId:Lr(null,"main"),parseDeckId:rc}}const sR="/sw.js",Uh="nc-sw-update";let Kh=null,qh=!1,Vh=null,mb=Object.freeze({needed:!1,kind:null,version:""}),gb=!1;function vb(){typeof window<"u"&&window.dispatchEvent(new Event(Uh))}function _b(){const e=Vh||(qh?{kind:"reload",version:""}:null);mb=Object.freeze({needed:!!e,kind:(e==null?void 0:e.kind)||null,version:(e==null?void 0:e.version)||""})}function W_(){return mb}function rR(e){return typeof window>"u"?()=>{}:(window.addEventListener(Uh,e),()=>window.removeEventListener(Uh,e))}function Ff(e){qh!==e&&(qh=e,_b(),vb())}const Ud="nc-auto-reload";function oR(){try{return typeof sessionStorage<"u"?sessionStorage:null}catch{return null}}function aR(e,t,n,s={}){let o=null;e&&t&&e!==t?o={kind:"install",version:e}:t&&n&&t!==n&&(o={kind:"reload",version:t});const a=JSON.stringify(o)===JSON.stringify(Vh);Vh=o,_b(),a||vb();const u=s.storage===void 0?oR():s.storage;if(!o){try{u&&u.removeItem(Ud)}catch{}return}if(o.kind!=="reload"||!u)return;const h=`${t}|${n}`;try{if(u.getItem(Ud)===h)return;u.setItem(Ud,h)}catch{return}(s.applyImpl||yb)()}function lR(e){e.addEventListener("statechange",()=>{e.state==="installed"&&navigator.serviceWorker.controller&&Ff(!0)})}function cR(){typeof navigator>"u"||!("serviceWorker"in navigator)||(navigator.serviceWorker.addEventListener("controllerchange",()=>{gb&&location.reload()}),navigator.serviceWorker.register(sR).then(e=>{Kh=e,e.waiting&&Ff(!0),e.addEventListener("updatefound",()=>{const t=e.installing;t&&lR(t)}),setInterval(()=>{e.update().catch(()=>{})},3600*1e3)}).catch(()=>{}))}function yb(){gb=!0,Ff(!1);const e=Kh&&Kh.waiting;e?(e.postMessage({type:"SKIP_WAITING"}),setTimeout(()=>location.reload(),4e3)):location.reload()}function uR({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")||"",m=p?`${t||""}${n||""}#pair=${p}`:"";return{token:h,pair:m,nextUrl:a}}const wb=9,bb=24,Sb="nc_side_w",U_="nc_side_min",dR=240,K_="(min-width:1024px) and (pointer:fine)";function hR(){const e=Number(localStorage.getItem(Sb));return e>=180&&e<=480?e:dR}function fR(){const e=Number(localStorage.getItem("nc_fontsize"));return e>=wb&&e<=bb?e:13}function pR(){const e={token:"",pair:""};try{const{token:t,pair:n,nextUrl:s}=uR({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 mR(e){try{return Ys($h(e))}catch{return Ar()}}function q_(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 gR(){const[e,t]=N.useState(()=>window.matchMedia(K_).matches);return N.useEffect(()=>{const n=window.matchMedia(K_),s=o=>t(o.matches);return n.addEventListener("change",s),()=>n.removeEventListener("change",s)},[]),e}function V_({session:e,node:t,ownerId:n,cellName:s,token:o,readonly:a=!1,onBack:u,onCellSwitcher:h,cellSwitcherOpen:p=!1}){En();const[m]=Cf(),[v,y]=N.useState(!1),[w,b]=N.useState(()=>window.matchMedia("(pointer: coarse)").matches),[S,C]=N.useState(null),[x,R]=N.useState(fR),[E,$]=N.useState(s||e),[B,K]=N.useState(""),V=T=>R(F=>{const k=Math.max(wb,Math.min(bb,F+T));return localStorage.setItem("nc_fontsize",String(k)),k}),Y=N.useRef(()=>{}),te=N.useRef(()=>!1),Q=N.useRef(()=>{}),J=N.useRef(!1),[H,L]=N.useState(!1),[A,z]=N.useState(!1),O=()=>{J.current=!J.current,L(J.current)};return N.useEffect(()=>{$(s||e)},[s,e]),N.useEffect(()=>{let T=!0;const F=t?t.split("/"):[],k=t?`/api/route/${t.split("/").map(encodeURIComponent).join("/")}/_`:"/api";async function I(){let M=null,W=null;try{const le=await(await Ut(`${k}/sessions`,o)).json();Array.isArray(le.sessions)&&(M=le.sessions.find(he=>he.name===e))}catch{}try{const ue=await bs(o,F);ue.available&&Array.isArray(ue.cells)&&(W=ue.cells.find(le=>le.tmuxSession===e))}catch{}if(!T)return;$(Ef({session:e,cell:W||(s?{cell:s}:null)}));let G="";W?G=`${W.engine}${W.key?`·${W.key}`:""}`:M&&(G=M.attached?`attached · ${q_(M.activity)}`:M.activity?q_(M.activity):""),K(G)}I();const D=setInterval(I,4e3);return()=>{T=!1,clearInterval(D)}},[e,t,o]),l.jsxs("div",{className:"nc-app",children:[l.jsxs("header",{className:"nc-bar nc-bar-single",children:[l.jsxs("button",{onClick:u,title:f("sessions"),children:[l.jsx(Ge,{name:"chevronLeft",size:18}),l.jsx("span",{className:"nc-bar-label",children:f("sessions")})]}),l.jsxs("span",{className:"nc-bar-center",children:[l.jsx("b",{title:t?`${E} · ${t}`:E,children:E}),B&&l.jsx("small",{className:"nc-bar-sub",children:B})]}),l.jsxs("span",{className:"nc-bar-right",children:[l.jsx("button",{onClick:()=>V(-1),title:f("zoom-out"),children:l.jsx(Ge,{name:"zoomOut",size:18})}),l.jsx("button",{onClick:()=>V(1),title:f("zoom-in"),children:l.jsx(Ge,{name:"zoomIn",size:18})}),l.jsx("button",{onClick:()=>b(T=>!T),title:f("composer"),children:l.jsx(Ge,{name:"keyboard",size:20})}),l.jsx("button",{onClick:()=>y(T=>!T),title:f("files"),children:l.jsx(Ge,{name:"folder",size:20})})]})]}),l.jsx("div",{className:"nc-termwrap",children:l.jsx(vw,{session:e,node:t,token:o,readonly:a,takeSize:!0,sendRef:Y,composerRef:te,actionRef:Q,ctrlRef:J,setCtrlArmed:L,onFiles:C,fontSize:x,selectionMode:A,onSelectionModeChange:z,keyboardGesture:m.terminalKeyboardGesture})}),l.jsx(zE,{onKeyboard:()=>b(T=>!T),onCellSwitcher:h,cellSwitcherOpen:p,send:T=>Y.current(T),action:T=>Q.current(T),ctrlArmed:H,onCtrl:O,selectionMode:A,onSelectionMode:z,keepKeyboardClosed:m.keybarKeepsKeyboardClosed,showEnter:m.showKeybarEnter,keybarLayout:m.keybarLayout}),w&&l.jsx(Nw,{submitText:T=>te.current(T),token:o,session:e,node:t,ownerId:n,keepKeyboardClosedOnVoice:m.voiceKeepsKeyboardClosed}),v&&l.jsx(_w,{session:e,node:t,token:o,filesEvent:S,onClose:()=>y(!1)})]})}function vR(){En();const[e]=N.useState(pR),[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=gR(),[m]=N.useState(()=>pN(typeof location<"u"?location.pathname:"/")),[v,y]=N.useState(m.id),w=v===Lr(null,qn),[b,S]=N.useState(null),C=de=>{const Re=ws(de);S(Re?{...Re,...typeof(de==null?void 0:de.cellName)=="string"&&de.cellName?{cellName:de.cellName}:{}}:null)},[x,R]=N.useState([]),[E,$]=N.useState([]),[B,K]=N.useState([]),[V,Y]=N.useState(()=>m.ownerId?Ar():mR(m.name)),[te,Q]=N.useState(null),[J,H]=N.useState(null),L=de=>H(ws(de)),[A,z]=N.useState(null),O=sf(t,p),T=N.useMemo(()=>(O||[]).filter(de=>de.instanceId).map(de=>({instanceId:de.instanceId,route:de.route,label:de.label,status:de.status})),[O]),F=iR(t,v,V,Y,T),k=F.decks;N.useEffect(()=>{const de=new Map;for(const Re of O||[]){const $e=(Re.route||[Re.name]).join("/"),rt=new Set((Re.sessions||[]).map(wt=>wt.name));for(const wt of Re.cells||[])!wt.cell||!wt.tmuxSession||wt.cell===wt.tmuxSession||rt.has(wt.cell)||de.set(`${$e}:${wt.cell}`,`${$e}:${wt.tmuxSession}`)}Y(Re=>Lx(Re,de))},[O]),N.useEffect(()=>{F.localNodeId&&Y(de=>{const Re=zh(de,F.localNodeId,T);return JSON.stringify(Re)===JSON.stringify(de)?de:Re})},[T,F.localNodeId]);const[I,D]=N.useState(null),[M,W]=N.useState(null),G=N.useRef(0),[ue,le]=N.useState(!1),[he,we]=N.useState(hR),[re,_e]=N.useState(!w),[ze,ut]=N.useState(()=>w?localStorage.getItem(U_)==="1":!0),[nt,Ne]=N.useState(!1),[jt,tn]=N.useState("nodes"),[De,Tt]=N.useState(!1),[Qe,vt]=N.useState(""),[mt,it]=N.useState(!1),dt=(de="nodes",Re=!1,$e="")=>{tn(de),Tt(Re),vt($e),Ne(!0)},[ot,ht]=N.useState(!1),[st,ft]=N.useState({deviceDefault:"",localNodeId:"",localNameDefault:""}),[be,ce]=N.useState(!1);N.useEffect(()=>{try{localStorage.setItem(Sb,String(he))}catch{}},[he]),N.useEffect(()=>{try{localStorage.setItem(U_,ze?"1":"")}catch{}},[ze]),N.useEffect(()=>{if(!t)return;let de=!1;return Promise.all([ny(t),Ut("/api/config",t).then(Re=>Re.json())]).then(([Re,$e])=>{de||(ft({deviceDefault:Re.deviceName||"",localNodeId:Re.nodeId||"",localNameDefault:Re.localName||""}),ce(!!$e.readonlyDefault),(Re.firstRun===!0&&!$e.readonlyDefault||s)&&ht(!0))}).catch(()=>{}),()=>{de=!0}},[t,s]);const U=N.useCallback(async()=>{try{const Re=await(await Ut("/api/sessions",t)).json();Re.error||R(Re.sessions||[])}catch{}try{const de=await bs(t);$(de.available?de.cells||[]:[]),K(de.available?de.capabilities||[]:[])}catch{$([]),K([])}},[t]);N.useEffect(()=>{if(!p)return;U();const de=setInterval(U,4e3);return()=>clearInterval(de)},[p,U]),N.useEffect(()=>{let de=!1;const Re=()=>{Ut("/api/config",t).then(rt=>rt.json()).then(rt=>{de||aR(rt.version,rt.uiVersion,"0.8.57")}).catch(()=>{})};Re();const $e=setInterval(Re,6e4);return()=>{de=!0,clearInterval($e)}},[t]);const ne=new Set([...x.map(de=>de.name),...O.flatMap(de=>de.sessions.map(Re=>Re.key))]),j=ki(V),X=de=>Y(Re=>{const $e=Lw(de,F.localNodeId,T)||de,rt=wy(Re,$e);return rt===Re&&ki(Re).length>=9&&F.setError(f("grid-full")),rt}),ie=async(de,Re=[])=>{try{await Qh(t,de,Re)}catch{return}const $e=Re.length?`${Re.join("/")}:${de}`:de;Y(rt=>Hl(rt,$e)),U()},pe=async(de,Re,$e=[])=>{try{await ty(t,de,Re,$e)}catch{return}U()},ke=async(de,Re,$e=[])=>{await J_(t,{cell:de,enabled:!!Re},$e),U()},me=async de=>{if(!I)return;const{cell:Re}=I,$e=Array.isArray(I.route)?I.route:[];if(de.action==="up"){const wt=await Xh(t,{cell:Re,boot:!!de.boot,...de.engine?{engine:de.engine}:{},...de.model!==void 0?{model:de.model}:{},...de.permissionPolicy?{permissionPolicy:de.permissionPolicy}:{}},$e),Ss=df(wt);Ss&&F.setError(Ss.text)}else await Il(t,{cell:Re,boot:!!de.boot},$e);const rt=de.action==="up"?!!de.boot:de.boot?!1:!!I.boot;W({id:++G.current,cell:Re,route:$e,enabled:rt}),U()},xe=N.useCallback(de=>{W(Re=>(Re==null?void 0:Re.id)===de?null:Re)},[]),We=async de=>{if(!(!(de!=null&&de.direct)||ue)){le(!0);try{await tf(t,de.name,de.tunnelStatus==="up"?"down":"up")}finally{le(!1)}}},lt=async(de,Re)=>{const $e=String(Re||"").trim();return!(de!=null&&de.direct)||!Ir($e)?!1:(await ry(t,de.name,$e),!0)},Ke=de=>{const Re=k.find($e=>$e.id===de);if(!Re)return!1;try{const $e=window.open(pd(Re,t),"_blank");return $e&&($e.opener=null),!!$e}catch{return!1}},pt=async de=>{if(!de||de===v)return;const Re=await F.select(de),$e=F.records.find(rt=>rt.id===de);y(de),Y(Re),Q(null),H(null);try{history.replaceState(null,"",pd($e||de,null))}catch{}},Xe=async(de,Re)=>{const $e=await F.add(de,Re);await pt($e.id)},je=async(de,Re)=>{const $e=await F.rename(de,Re);if(de===v){y($e.id),Y(zh($e.layout,F.localNodeId,T)),Q(null),H(null);try{history.replaceState(null,"",pd($e,null))}catch{}}},_t=async de=>{await F.remove(de),de===v&&await pt(F.localMainId)},Sn=async(de,Re)=>{!Re||Re===v||(await F.addTileTo(Re,de),Y($e=>Hl($e,de)))};if(!t)return l.jsxs("div",{className:"nc-auth",children:[l.jsx("p",{children:f("auth-prompt")}),l.jsx("input",{onChange:de=>n(de.target.value.trim()),placeholder:"token"}),l.jsxs("label",{children:[l.jsx("input",{type:"checkbox",checked:u,onChange:de=>h(de.target.checked)})," ",f("remember-device")]}),l.jsx("button",{onClick:()=>{(u?localStorage:sessionStorage).setItem("nc_token",t)},children:"ok"})]});const Rn=l.jsxs(l.Fragment,{children:[nt&&l.jsx(zj,{token:t,initialTab:jt,initialLocation:Qe,startNewCell:De,onClose:()=>{Ne(!1),Tt(!1),vt("")}}),ot&&l.jsx($j,{token:t,initialPair:s,...st,onPairDone:a,onDone:()=>ht(!1)}),l.jsx(qj,{token:t})]});if(!p)return A?l.jsxs(l.Fragment,{children:[l.jsx("div",{className:"nc-single-overlay",children:l.jsx(H_,{peer:A,token:t,onBack:()=>z(null)})}),Rn]}):b?l.jsxs(l.Fragment,{children:[l.jsx(V_,{session:b.session,node:b.node,ownerId:b.ownerId,cellName:b.cellName,token:t,readonly:be,onBack:()=>S(null),onCellSwitcher:()=>it(!0),cellSwitcherOpen:mt}),mt&&l.jsx(Jj,{token:t,current:b,onPick:de=>{C(de),it(!1)},onClose:()=>it(!1)}),Rn]}):l.jsxs(l.Fragment,{children:[l.jsx(Xx,{onPick:C,token:t,onSettings:dt,onOpenVlSession:z}),Rn]});const Rt=w||!re;return l.jsxs("div",{className:"nc-workspace",children:[Rt&&l.jsx(nN,{sessions:x,cells:E,activeSessions:j,nodeGroups:O,fleetCapabilities:B,bootSettlement:M,onBootSettlementApplied:xe,localNodeId:F.localNodeId,onPick:L,onAddTile:X,onPower:D,onBoot:ke,onBootError:de=>F.setError(String((de==null?void 0:de.message)||de)),onNodePower:We,onNodeRename:lt,onKill:ie,onVisibility:pe,onNew:()=>dt("fleet",!0),onSettings:dt,onOpenVlSession:z,width:he,collapsed:ze,onResize:we,onToggleCollapse:()=>ut(de=>!de)}),l.jsxs("div",{className:"nc-workspace-main",children:[l.jsx(ON,{decks:k,currentDeck:v,onCreate:Xe,onRename:je,onDelete:_t,onReorder:F.reorder,onOpenWindow:Ke,onNavigate:pt,saveState:F.saveState,error:F.error,sidebarVisible:Rt,onToggleSidebar:w?null:()=>_e(de=>!de)}),l.jsx(cN,{layout:V,onLayoutChange:Y,token:t,readonly:be,sessionsAlive:ne,focusSession:te,onFocus:Q,onOpenSingle:L,decks:k,currentDeck:v,onSendToDeck:Sn,cells:E,nodeGroups:O})]}),A&&l.jsx("div",{className:"nc-single-overlay",children:l.jsx(H_,{peer:A,token:t,onBack:()=>z(null)})}),J&&l.jsx("div",{className:"nc-single-overlay",children:l.jsx(V_,{session:J.session,node:J.node,ownerId:J.ownerId,cellName:Ef({session:J.session,node:J.node,ownerId:J.ownerId,cells:E,nodeGroups:O}),token:t,readonly:be,onBack:()=>H(null)})}),I&&l.jsx(Bl,{cell:I,token:t,route:Array.isArray(I.route)?I.route:[],onConfirm:me,onClose:()=>D(null)}),Rn]})}function _R(){En();const e=N.useSyncExternalStore(rR,W_,W_);if(!e.needed)return null;const t=e.kind==="install"?f("install-version-mismatch").replace("{v}",e.version):f("update-available").replace("{v}",e.version).replace(" "," ").trim();return l.jsxs("div",{className:"nc-update",role:"status","aria-live":"polite",children:[l.jsx("span",{className:"nc-update-msg",children:t}),e.kind==="reload"&&l.jsx("button",{className:"nc-update-btn",onClick:yb,children:f("reload")})]})}cR();g0.createRoot(document.getElementById("root")).render(l.jsxs(c0.StrictMode,{children:[l.jsx(vR,{}),l.jsx(_R,{})]}));
@@ -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-BWY4VRTb.js"></script>
14
+ <script type="module" crossorigin src="/assets/index-_c-1_3iR.js"></script>
15
15
  <link rel="stylesheet" crossorigin href="/assets/index-CYi_lhCg.css">
16
16
  </head>
17
17
  <body>
@@ -1 +1 @@
1
- {"version":"0.8.55"}
1
+ {"version":"0.8.57"}
@@ -34,7 +34,7 @@ const {
34
34
  resolveCwd, normalizeCwdRel, deriveCwdRel,
35
35
  } = require('./definitions.js');
36
36
  const {
37
- publicCatalog, describeManaged, describeCatalogCredential, defaultShellEngine, defaultAgyEngine, defaultKimiEngine,
37
+ publicCatalog, describeManaged, describeCatalogCredential, defaultShellEngine, defaultAgyEngine, defaultKimiEngine, defaultGrokEngine, defaultVlEngine,
38
38
  CATALOG, credential: resolveProfileCredential, extraModelsFrom, knownMcpServerNames,
39
39
  } = require('./managed.js');
40
40
  const { probeModel } = require('./model-probe.js');
@@ -132,6 +132,41 @@ function backfillKimiEngine(defsPath, defs) {
132
132
  try { return atomicWrite(defsPath, draft); } catch (_) { return defs; }
133
133
  }
134
134
 
135
+ // Backfill platform-aware dell'engine Grok Build (grok.native): come Agy,
136
+ // installazioni esistenti su Linux/macOS non-Termux ricevono grok.native in
137
+ // modo idempotente e non distruttivo. Su altre piattaforme (Termux/Windows) e'
138
+ // un no-op: grok-build non e' un client primario supportato li'. Idempotente
139
+ // (gia' presente -> skip), NON sovrascrive un id 'grok.native' gia' scelto
140
+ // dall'utente per altro (collisione -> skip, store invariato), rispetta il cap
141
+ // MAX_ENGINES. Non tocca CELLE.
142
+ function backfillGrokEngine(defsPath, defs, cfg = {}) {
143
+ if (!defs) return defs;
144
+ const platform = cfg.platform || process.platform;
145
+ const termux = platform === 'android'
146
+ || termuxRuntimePaths(cfg.env || process.env, { platform, home: cfg.home }) !== null;
147
+ if (termux || (platform !== 'linux' && platform !== 'darwin')) return defs;
148
+ if (defs.engines.some((engine) => engine.managed?.client === 'grok')) return defs;
149
+ if (defs.engines.some((engine) => engine.id === 'grok.native')) return defs;
150
+ if (defs.engines.length >= CAPS.MAX_ENGINES) return defs;
151
+ const draft = draftFrom(defs);
152
+ draft.engines.push(defaultGrokEngine());
153
+ try { return atomicWrite(defsPath, draft); } catch (_) { return defs; }
154
+ }
155
+
156
+ // Backfill dell'engine VL/Vivling (vl.native): come Kimi, NESSUN platform gate
157
+ // (il runtime e' musl-friendly ovunque giri Node). Idempotente (gia' presente
158
+ // -> skip), NON sovrascrive un id 'vl.native' gia' scelto dall'utente per altro
159
+ // (collisione -> skip, store invariato), rispetta il cap MAX_ENGINES. Non tocca
160
+ // CELLE.
161
+ function backfillVlEngine(defsPath, defs) {
162
+ if (!defs || defs.engines.some((engine) => engine.managed?.client === 'vl')) return defs;
163
+ if (defs.engines.some((engine) => engine.id === 'vl.native')) return defs;
164
+ if (defs.engines.length >= CAPS.MAX_ENGINES) return defs;
165
+ const draft = draftFrom(defs);
166
+ draft.engines.push(defaultVlEngine());
167
+ try { return atomicWrite(defsPath, draft); } catch (_) { return defs; }
168
+ }
169
+
135
170
  // Applica engine + modello + policy come un'unica transizione. Ogni engine ricorda
136
171
  // il proprio ultimo modello E l'ultima policy; passando a un altro engine né
137
172
  // l'uno né l'altra attraversano il confine. La policy e' PER-CELL PER-ENGINE:
@@ -301,6 +336,8 @@ async function createBuiltinFleet(cfg = {}) {
301
336
  boot = backfillShellEngine(defsPath, boot);
302
337
  boot = backfillAgyEngine(defsPath, boot, cfg);
303
338
  boot = backfillKimiEngine(defsPath, boot);
339
+ boot = backfillGrokEngine(defsPath, boot, cfg);
340
+ boot = backfillVlEngine(defsPath, boot);
304
341
  }
305
342
 
306
343
  // Adopt or create the shared server before exposing a mutable Fleet. Reapply
@@ -906,7 +943,7 @@ async function createBuiltinFleet(cfg = {}) {
906
943
  rc: { type: 'boolean', required: false, default: false },
907
944
  managed: {
908
945
  type: 'object', requiredFor: 'managed',
909
- client: { type: 'enum', values: ['claude', 'codex', 'codex-vl', 'pi', 'agy', 'kimi', 'shell'] },
946
+ client: { type: 'enum', values: ['claude', 'codex', 'codex-vl', 'grok', 'vl', 'pi', 'agy', 'kimi', 'shell'] },
910
947
  provider: { type: 'catalog', source: 'managedCatalog' },
911
948
  credentialProfile: { type: 'string', required: false, max: 32 },
912
949
  model: { type: 'string', required: false, max: CAPS.MAX_MODEL_VAL_LEN },
@@ -1021,6 +1058,8 @@ module.exports = {
1021
1058
  backfillShellEngine,
1022
1059
  backfillAgyEngine,
1023
1060
  backfillKimiEngine,
1061
+ backfillGrokEngine,
1062
+ backfillVlEngine,
1024
1063
  resolveCellCwd,
1025
1064
  composeLaunchArgv,
1026
1065
  composeClientInvocation,
@@ -112,13 +112,48 @@ const ALIBABA_PI_MODELS = Object.freeze([
112
112
  }),
113
113
  ]);
114
114
 
115
+ // OpenCode Go: un abbonamento unico dietro TRE wire, non un provider uniforme.
116
+ //
117
+ // La documentazione ufficiale assegna a ciascun modello un solo endpoint, ma il
118
+ // gateway traduce: gli elenchi qui sotto sono MISURATI coppia per coppia il
119
+ // 2026-08-11 (25 ID live x 3 wire, piu' una seconda passata sulle celle fallite
120
+ // per distinguere il rifiuto di wire dal payload perso in traduzione).
121
+ //
122
+ // Cosa NON e' in elenco, e perche' non e' una svista:
123
+ // - kimi-*, deepseek-v4-pro, mimo-v2.5*, hy3 fuori da Messages/Responses: il
124
+ // gateway inoltra un payload vuoto e l'upstream risponde "messages must not
125
+ // be empty". E' un difetto loro, reversibile senza preavviso: se un giorno
126
+ // rispondono, l'id si dichiara per quell'engine senza toccare il codice.
127
+ // - mimo-v2-pro e mimo-v2-omni: deprecati dall'upstream ("migrate to
128
+ // xiaomi/mimo-v2.5*"). hy3-preview: "Model is unavailable".
129
+ // Il catalogo live li pubblicizza comunque; qui non entrano.
130
+ // - grok-4.5 solo su Responses: su Chat risponde 503 e Messages lo rifiuta
131
+ // esplicitamente ("not supported for format anthropic").
132
+ const OPENCODE_GO_MESSAGES_MODELS = Object.freeze([
133
+ 'deepseek-v4-flash', 'glm-5.2', 'glm-5.1', 'glm-5',
134
+ 'minimax-m3', 'minimax-m2.7', 'minimax-m2.5',
135
+ 'qwen3.8-max', 'qwen3.7-max', 'qwen3.7-plus', 'qwen3.6-plus', 'qwen3.5-plus',
136
+ ]);
137
+ const OPENCODE_GO_RESPONSES_MODELS = Object.freeze([
138
+ 'deepseek-v4-flash', 'gpt-5.6-luna', 'grok-4.5', 'glm-5.2', 'glm-5.1', 'glm-5',
139
+ ]);
140
+ const OPENCODE_GO_CHAT_MODELS = Object.freeze([
141
+ 'deepseek-v4-flash', 'deepseek-v4-pro', 'glm-5.2', 'glm-5.1', 'glm-5',
142
+ 'kimi-k3', 'kimi-k2.7-code', 'kimi-k2.6', 'kimi-k2.5',
143
+ 'minimax-m3', 'minimax-m2.7', 'minimax-m2.5',
144
+ 'qwen3.8-max', 'qwen3.7-max', 'qwen3.7-plus', 'qwen3.6-plus', 'qwen3.5-plus',
145
+ 'mimo-v2.5', 'mimo-v2.5-pro', 'hy3', 'gpt-5.6-luna',
146
+ ]);
147
+ const OPENCODE_GO_ANTHROPIC_ROOT = 'https://opencode.ai/zen/go';
148
+ const OPENCODE_GO_API_BASE = 'https://opencode.ai/zen/go/v1';
149
+
115
150
  const CUSTOM_KEYS = ['displayName', 'protocol', 'baseUrl', 'envKey', 'providerId'];
116
151
  const MANAGED_KEYS = new Set(['client', 'provider', 'credentialProfile', 'model', 'permissionPolicy', 'credentialSourcePolicy', ...CUSTOM_KEYS]);
117
152
  // Explicit credential source policy. Default 'auto' preserves the legacy
118
153
  // resolution order (runtime -> store -> shell -> key files -> legacy) so a
119
154
  // pre-WP1 fleet.json migrates no-op: no existing cell changes resolution.
120
155
  const CREDENTIAL_SOURCES = Object.freeze(['environment', 'nexuscrew-store', 'auto']);
121
- const CLIENT_LABELS = Object.freeze({ claude: 'Claude Code', codex: 'Codex', 'codex-vl': 'Codex-VL', pi: 'Pi', agy: 'Agy', kimi: 'Kimi Code CLI', shell: 'Shell' });
156
+ const CLIENT_LABELS = Object.freeze({ claude: 'Claude Code', codex: 'Codex', 'codex-vl': 'Codex-VL', grok: 'Grok', vl: 'VL', pi: 'Pi', agy: 'Agy', kimi: 'Kimi Code CLI', shell: 'Shell' });
122
157
  const PROVIDER_ID_RE = /^[a-z][a-z0-9_-]{0,31}$/;
123
158
 
124
159
  function validBaseUrl(value) {
@@ -131,59 +166,108 @@ function validBaseUrl(value) {
131
166
  }
132
167
 
133
168
  const CATALOG = Object.freeze([
169
+ // L'ordine di questo array e' semantica contrattuale, non estetica: guida il
170
+ // menu client (prima apparizione di ogni client) e il menu provider dentro un
171
+ // client (ordine dell'array), entrambi via publicCatalog che preserva l'ordine.
172
+ // Ordine client: claude -> codex-vl -> codex -> grok -> vl -> pi -> agy -> kimi
173
+ // -> shell. Dentro ogni client: native/login -> subscription (alibaba-token-
174
+ // plan, kimi-code, zai) -> cloud (openrouter, ollama-cloud, bedrock, vertex,
175
+ // foundry) -> local (ollama, lmstudio) -> custom. Le voci legacy chiudono
176
+ // l'array in una sezione separata. claude.native resta il primo default.
177
+
134
178
  // Claude Code
135
179
  { id: 'claude.native', client: 'claude', provider: 'native', label: 'Anthropic / Claude account', auth: 'login', endpoint: 'Anthropic account', protocol: 'anthropic_messages', rc: true, default: true, core: true },
136
180
  { id: 'claude.alibaba-token-plan', client: 'claude', provider: 'alibaba-token-plan', label: 'Alibaba Token Plan Personal', auth: 'ALIBABA_CODE_API_KEY', endpoint: 'https://token-plan.ap-southeast-1.maas.aliyuncs.com/apps/anthropic', protocol: 'anthropic_messages', model: 'qwen3.8-max', models: ALIBABA_TOKEN_PLAN_MODELS, strictModels: true, core: true, notice: 'alibaba-token-plan' },
137
- { id: 'claude.openrouter', client: 'claude', provider: 'openrouter', label: 'OpenRouter', auth: 'OPENROUTER_API_KEY', endpoint: 'https://openrouter.ai/api', protocol: 'anthropic_messages', requiresModel: true, core: true, notice: 'claude-openrouter' },
138
181
  { id: 'claude.kimi-code', client: 'claude', provider: 'kimi-code', label: 'Kimi Code', auth: 'KIMI_API_KEY', endpoint: 'https://api.kimi.com/coding/', protocol: 'anthropic_messages', model: 'k3[1m]', models: ['k3', 'k3[1m]', 'kimi-for-coding', 'kimi-for-coding-highspeed'], strictModels: true, core: true, notice: 'claude-kimi-code' },
182
+ { id: 'claude.zai', client: 'claude', provider: 'zai', label: 'Z.AI', auth: 'dynamic', credentialEnv: true, defaultEnvKey: 'ZAI_API_KEY', endpoint: 'https://api.z.ai/api/anthropic', protocol: 'anthropic_messages', model: 'glm-5.2[1m]', models: ['glm-5.2[1m]'], core: true },
183
+ // OpenCode Go su Claude parla Anthropic Messages, e la wire accetta SOLO
184
+ // `x-api-key`: con `Authorization: Bearer` risponde 401 AuthError. Per questo
185
+ // l'endpoint e' la root senza `/v1` (il client aggiunge `/v1/messages`) e il
186
+ // launch valorizza ANTHROPIC_API_KEY, non ANTHROPIC_AUTH_TOKEN come Z.AI.
187
+ { id: 'claude.opencode-go', client: 'claude', provider: 'opencode-go', label: 'OpenCode Go', auth: 'OPENCODE_API_KEY', endpoint: OPENCODE_GO_ANTHROPIC_ROOT, protocol: 'anthropic_messages', model: 'deepseek-v4-flash', models: OPENCODE_GO_MESSAGES_MODELS, strictModels: true, core: true },
188
+ { id: 'claude.openrouter', client: 'claude', provider: 'openrouter', label: 'OpenRouter', auth: 'OPENROUTER_API_KEY', endpoint: 'https://openrouter.ai/api', protocol: 'anthropic_messages', requiresModel: true, core: true, notice: 'claude-openrouter' },
189
+ { id: 'claude.ollama-cloud', client: 'claude', provider: 'ollama-cloud', label: 'Ollama Cloud', auth: 'OLLAMA_API_KEY', endpoint: 'https://ollama.com', protocol: 'anthropic_messages', model: 'glm-5.2', models: OLLAMA_CLOUD_MODELS, legacySecrets: true, core: true },
139
190
  { id: 'claude.bedrock', client: 'claude', provider: 'bedrock', label: 'Amazon Bedrock', auth: 'login', endpoint: 'AWS Bedrock', protocol: 'anthropic_messages', core: true, providerEnv: { CLAUDE_CODE_USE_BEDROCK: '1' } },
140
191
  { id: 'claude.vertex', client: 'claude', provider: 'vertex', label: 'Google Vertex AI', auth: 'login', endpoint: 'Google Vertex AI', protocol: 'anthropic_messages', core: true, providerEnv: { CLAUDE_CODE_USE_VERTEX: '1' } },
141
192
  { id: 'claude.foundry', client: 'claude', provider: 'foundry', label: 'Microsoft Foundry', auth: 'login', endpoint: 'Microsoft Foundry', protocol: 'anthropic_messages', core: true, providerEnv: { CLAUDE_CODE_USE_FOUNDRY: '1' } },
142
- { id: 'claude.ollama-cloud', client: 'claude', provider: 'ollama-cloud', label: 'Ollama Cloud', auth: 'OLLAMA_API_KEY', endpoint: 'https://ollama.com', protocol: 'anthropic_messages', model: 'glm-5.2', models: OLLAMA_CLOUD_MODELS, legacySecrets: true, core: true },
143
193
  { id: 'claude.ollama', client: 'claude', provider: 'ollama', label: 'Ollama local', auth: 'none', endpoint: 'http://127.0.0.1:11434', protocol: 'anthropic_messages', core: true },
144
- { id: 'claude.zai', client: 'claude', provider: 'zai', label: 'Z.AI', auth: 'dynamic', credentialEnv: true, defaultEnvKey: 'ZAI_API_KEY', endpoint: 'https://api.z.ai/api/anthropic', protocol: 'anthropic_messages', model: 'glm-5.2[1m]', models: ['glm-5.2[1m]'], core: true },
145
- // Compatibilità sola lettura/launch per configurazioni 0.8.0: mai nel catalogo UI.
146
- { id: 'claude.zai-a', client: 'claude', provider: 'zai', credentialProfile: 'a', label: 'Z.AI legacy profile', auth: 'ZAI_API_KEY_A', endpoint: 'https://api.z.ai/api/anthropic', protocol: 'anthropic_messages', model: 'glm-5.2[1m]', models: ['glm-5.2[1m]'], legacySecrets: true, legacyProvider: 'zai-a', legacy: true },
147
- { id: 'claude.zai-p', client: 'claude', provider: 'zai', credentialProfile: 'p', label: 'Z.AI legacy profile', auth: 'ZAI_API_KEY_P', endpoint: 'https://api.z.ai/api/anthropic', protocol: 'anthropic_messages', model: 'glm-5.2[1m]', models: ['glm-5.2[1m]'], legacySecrets: true, legacyProvider: 'zai-p', legacy: true },
148
194
  { id: 'claude.custom', client: 'claude', provider: 'custom', label: 'Custom Anthropic-compatible', auth: 'dynamic', protocol: 'anthropic_messages', protocols: ['anthropic_messages'], custom: true, core: true },
149
195
 
150
- // Codex family. OpenAI Responses is the only remote custom wire API.
151
- { id: 'codex.native', client: 'codex', provider: 'native', label: 'OpenAI / ChatGPT account', auth: 'login', endpoint: 'OpenAI account', protocol: 'openai_responses', default: true, core: true },
196
+ // Codex-VL (fork Vivling, Responses). OpenAI Responses e' l'unica wire API
197
+ // remota custom. Ora precede codex (client primario del fork) in prima
198
+ // apparizione: il seed cambia ordine (non insieme) rispetto a 0.8.55.
152
199
  { id: 'codex-vl.native', client: 'codex-vl', provider: 'native', label: 'OpenAI / ChatGPT account', auth: 'login', endpoint: 'OpenAI account', protocol: 'openai_responses', default: true, core: true },
153
200
  { id: 'codex-vl.alibaba-token-plan', client: 'codex-vl', provider: 'alibaba-token-plan', label: 'Alibaba Token Plan Personal', auth: 'ALIBABA_CODE_API_KEY', endpoint: 'https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1', protocol: 'openai_responses', model: 'qwen3.8-max', models: ALIBABA_CODEX_MODELS, strictModels: true, core: true, notice: 'alibaba-token-plan' },
154
- { id: 'codex.openai-api', client: 'codex', provider: 'openai-api', label: 'OpenAI API', auth: 'OPENAI_API_KEY', endpoint: 'https://api.openai.com/v1', protocol: 'openai_responses', core: true },
155
- { id: 'codex-vl.openai-api', client: 'codex-vl', provider: 'openai-api', label: 'OpenAI API', auth: 'OPENAI_API_KEY', endpoint: 'https://api.openai.com/v1', protocol: 'openai_responses', core: true },
201
+ { id: 'codex-vl.opencode-go', client: 'codex-vl', provider: 'opencode-go', label: 'OpenCode Go', auth: 'OPENCODE_API_KEY', endpoint: OPENCODE_GO_API_BASE, protocol: 'openai_responses', model: 'deepseek-v4-flash', models: OPENCODE_GO_RESPONSES_MODELS, strictModels: true, core: true },
156
202
  { id: 'codex-vl.openrouter', client: 'codex-vl', provider: 'openrouter', label: 'OpenRouter', auth: 'OPENROUTER_API_KEY', endpoint: 'https://openrouter.ai/api/v1', protocol: 'openai_responses', requiresModel: true, core: true, notice: 'codex-openrouter' },
157
- { id: 'codex.ollama', client: 'codex', provider: 'ollama', label: 'Ollama local', auth: 'none', endpoint: 'local provider', protocol: 'openai_responses', localProvider: 'ollama', core: true },
203
+ { id: 'codex-vl.ollama-cloud', client: 'codex-vl', provider: 'ollama-cloud', label: 'Ollama Cloud', auth: 'OLLAMA_API_KEY', endpoint: 'https://ollama.com/v1', protocol: 'openai_responses', model: 'glm-5.2', models: OLLAMA_CLOUD_MODELS, legacySecrets: true, core: true },
204
+ { id: 'codex-vl.openai-api', client: 'codex-vl', provider: 'openai-api', label: 'OpenAI API', auth: 'OPENAI_API_KEY', endpoint: 'https://api.openai.com/v1', protocol: 'openai_responses', core: true },
158
205
  { id: 'codex-vl.ollama', client: 'codex-vl', provider: 'ollama', label: 'Ollama local', auth: 'none', endpoint: 'local provider', protocol: 'openai_responses', localProvider: 'ollama', core: true },
159
- { id: 'codex.lmstudio', client: 'codex', provider: 'lmstudio', label: 'LM Studio', auth: 'none', endpoint: 'local provider', protocol: 'openai_responses', localProvider: 'lmstudio', core: true },
160
206
  { id: 'codex-vl.lmstudio', client: 'codex-vl', provider: 'lmstudio', label: 'LM Studio', auth: 'none', endpoint: 'local provider', protocol: 'openai_responses', localProvider: 'lmstudio', core: true },
207
+ { id: 'codex-vl.custom', client: 'codex-vl', provider: 'custom', label: 'Custom Responses endpoint', auth: 'dynamic', protocol: 'openai_responses', protocols: ['openai_responses'], custom: true, core: true },
208
+
209
+ // Codex (upstream OpenAI, Responses).
210
+ { id: 'codex.native', client: 'codex', provider: 'native', label: 'OpenAI / ChatGPT account', auth: 'login', endpoint: 'OpenAI account', protocol: 'openai_responses', default: true, core: true },
211
+ { id: 'codex.openai-api', client: 'codex', provider: 'openai-api', label: 'OpenAI API', auth: 'OPENAI_API_KEY', endpoint: 'https://api.openai.com/v1', protocol: 'openai_responses', core: true },
161
212
  { id: 'codex.ollama-cloud', client: 'codex', provider: 'ollama-cloud', label: 'Ollama Cloud', auth: 'OLLAMA_API_KEY', endpoint: 'https://ollama.com/v1', protocol: 'openai_responses', model: 'glm-5.2', models: OLLAMA_CLOUD_MODELS, legacySecrets: true, core: true },
162
- { id: 'codex-vl.ollama-cloud', client: 'codex-vl', provider: 'ollama-cloud', label: 'Ollama Cloud', auth: 'OLLAMA_API_KEY', endpoint: 'https://ollama.com/v1', protocol: 'openai_responses', model: 'glm-5.2', models: OLLAMA_CLOUD_MODELS, legacySecrets: true, core: true },
213
+ { id: 'codex.ollama', client: 'codex', provider: 'ollama', label: 'Ollama local', auth: 'none', endpoint: 'local provider', protocol: 'openai_responses', localProvider: 'ollama', core: true },
214
+ { id: 'codex.lmstudio', client: 'codex', provider: 'lmstudio', label: 'LM Studio', auth: 'none', endpoint: 'local provider', protocol: 'openai_responses', localProvider: 'lmstudio', core: true },
163
215
  { id: 'codex.custom', client: 'codex', provider: 'custom', label: 'Custom Responses endpoint', auth: 'dynamic', protocol: 'openai_responses', protocols: ['openai_responses'], custom: true, core: true },
164
- { id: 'codex-vl.custom', client: 'codex-vl', provider: 'custom', label: 'Custom Responses endpoint', auth: 'dynamic', protocol: 'openai_responses', protocols: ['openai_responses'], custom: true, core: true },
165
216
 
166
- // Pi uses its real provider IDs directly. OAuth providers do not need env keys.
217
+ // Grok Build (xai-org/grok-build): Rust TUI, auth delegata al login del CLI
218
+ // (browser/API key/device-code). NexusCrew NON legge ne' copia credenziali:
219
+ // auth 'login', nessun env provider, nessun token su argv. Come Agy/Kimi non
220
+ // e' un default seed: backfill platform-aware (builtin.js) su Linux/macOS
221
+ // non-Termux; su Termux resta fuori finche' non c'e' uno smoke sul device
222
+ // (il binario aarch64 ufficiale e' statico, promettente ma non provato).
223
+ // Nessun remote-control NexusCrew (rc assente), come agy/kimi. permission
224
+ // default 'standard'; unsafe -> --always-approve (flag reale di `grok`).
225
+ { id: 'grok.native', client: 'grok', provider: 'native', label: 'Grok account (CLI login)', auth: 'login', protocol: 'grok_native', core: true },
226
+
227
+ // VL/Vivling (~/Dev/20_ai-labs/vl): runtime TUI locale. Auth propria del
228
+ // runtime (default local Ollama, o VL_API_KEY/--profile in config.toml):
229
+ // NexusCrew non legge ne' copia credenziali (auth 'none'). Il CLI non ha flag
230
+ // prompt, --model ne' di approvazione (`vl [OPTIONS]`): lancia la TUI senza
231
+ // argomenti, standard-only. Backfill idempotente pattern Kimi (NESSUN platform
232
+ // gate: musl-friendly ovunque); binario assente -> describeManaged non
233
+ // configurato. Non e' un default seed; nessun remote-control (rc assente).
234
+ { id: 'vl.native', client: 'vl', provider: 'native', label: 'VL', auth: 'none', protocol: 'vl_native', core: true },
235
+
236
+ // Pi usa i suoi provider ID reali direttamente. I provider OAuth non
237
+ // richiedono env key.
167
238
  { id: 'pi.native', client: 'pi', provider: 'native', label: 'Pi configured default', auth: 'login', protocol: 'pi_native', default: true, core: true },
168
239
  { id: 'pi.alibaba-token-plan', client: 'pi', provider: 'alibaba-token-plan', label: 'Alibaba Token Plan Personal', auth: 'ALIBABA_CODE_API_KEY', endpoint: 'https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1', protocol: 'openai-completions', model: 'qwen3.8-max', models: ALIBABA_TOKEN_PLAN_MODELS, strictModels: true, piProvider: 'alibaba-token-plan', piExtension: { baseUrl: 'https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1', models: ALIBABA_PI_MODELS }, delegatePiAuth: false, core: true, notice: 'alibaba-token-plan' },
169
- // Device-local shell. Kept after the established default clients so adding
170
- // it does not change the preselected engine for a newly-created cell.
171
- { id: 'shell.local', client: 'shell', provider: 'local', label: 'Shell', auth: 'none', protocol: 'shell', default: true, core: true },
240
+ { id: 'pi.zai', client: 'pi', provider: 'zai', label: 'Z.AI', auth: 'ZAI_API_KEY', protocol: 'pi_native', piProvider: 'zai', core: true },
241
+ // Su Pi la wire e' Chat Completions, la piu' ampia delle tre: e' l'unico
242
+ // percorso verso Kimi, DeepSeek Pro, MiMo e Hy3, che da Claude e Codex-VL
243
+ // oggi non sono raggiungibili. Il contextWindow dei modelli non e' misurato:
244
+ // l'estensione generata usa il default conservativo finche' non esiste lo
245
+ // snapshot models.dev.
246
+ //
247
+ // `delegatePiAuth: false` come per alibaba-token-plan, e per la stessa
248
+ // ragione: la delega vale per i provider che Pi conosce nativamente e
249
+ // risolve dal proprio store di login. OpenCode Go non e' fra quelli — esiste
250
+ // solo come estensione generata il cui apiKey e' `$OPENCODE_API_KEY`, che
251
+ // senza NexusCrew non e' valorizzato. Delegando, la cella risulterebbe
252
+ // configurata senza chiave e fallirebbe al primo uso.
253
+ { id: 'pi.opencode-go', client: 'pi', provider: 'opencode-go', label: 'OpenCode Go', auth: 'OPENCODE_API_KEY', endpoint: OPENCODE_GO_API_BASE, protocol: 'openai-completions', model: 'deepseek-v4-flash', models: OPENCODE_GO_CHAT_MODELS, strictModels: true, piProvider: 'opencode-go', piExtension: { baseUrl: OPENCODE_GO_API_BASE }, delegatePiAuth: false, core: true },
172
254
  { id: 'pi.anthropic', client: 'pi', provider: 'anthropic', label: 'Anthropic', auth: 'ANTHROPIC_API_KEY', protocol: 'pi_native', piProvider: 'anthropic', core: true },
173
255
  { id: 'pi.openai', client: 'pi', provider: 'openai', label: 'OpenAI API', auth: 'OPENAI_API_KEY', protocol: 'pi_native', piProvider: 'openai', core: true },
174
256
  { id: 'pi.openai-codex', client: 'pi', provider: 'openai-codex', label: 'OpenAI Codex OAuth', auth: 'login', protocol: 'pi_native', piProvider: 'openai-codex', core: true },
175
257
  { id: 'pi.google', client: 'pi', provider: 'google', label: 'Google Gemini', auth: 'GEMINI_API_KEY', protocol: 'pi_native', piProvider: 'google', core: true },
176
258
  { id: 'pi.openrouter', client: 'pi', provider: 'openrouter', label: 'OpenRouter', auth: 'OPENROUTER_API_KEY', protocol: 'pi_native', piProvider: 'openrouter', core: true },
177
259
  { id: 'pi.github-copilot', client: 'pi', provider: 'github-copilot', label: 'GitHub Copilot', auth: 'login', protocol: 'pi_native', piProvider: 'github-copilot', core: true },
178
- { id: 'pi.fireworks', client: 'pi', provider: 'fireworks', label: 'Pi · Fireworks AI', auth: 'FIREWORKS_API_KEY', protocol: 'pi_native', piProvider: 'fireworks' },
179
- { id: 'pi.huggingface', client: 'pi', provider: 'huggingface', label: 'Pi · Hugging Face', auth: 'HF_TOKEN', protocol: 'pi_native', piProvider: 'huggingface' },
180
- { id: 'pi.minimax', client: 'pi', provider: 'minimax', label: 'Pi · MiniMax', auth: 'MINIMAX_API_KEY', protocol: 'pi_native', piProvider: 'minimax' },
181
260
  { id: 'pi.deepseek', client: 'pi', provider: 'deepseek', label: 'DeepSeek', auth: 'DEEPSEEK_API_KEY', protocol: 'pi_native', piProvider: 'deepseek', core: true },
182
- { id: 'pi.kimi-coding', client: 'pi', provider: 'kimi-coding', label: 'Pi · Kimi For Coding', auth: 'KIMI_API_KEY', protocol: 'pi_native', piProvider: 'kimi-coding' },
183
- { id: 'pi.mistral', client: 'pi', provider: 'mistral', label: 'Pi · Mistral', auth: 'MISTRAL_API_KEY', protocol: 'pi_native', piProvider: 'mistral' },
184
- { id: 'pi.together', client: 'pi', provider: 'together', label: 'Pi · Together AI', auth: 'TOGETHER_API_KEY', protocol: 'pi_native', piProvider: 'together' },
261
+ // Provider Pi NON core: restano fuori dal catalogo UI (publicCatalog filtra
262
+ // core/default/custom), in attesa di decisione DAG. Vengono risolti solo da
263
+ // configurazione esistente via profileFor. Etichette senza prefisso "Pi · ".
264
+ { id: 'pi.fireworks', client: 'pi', provider: 'fireworks', label: 'Fireworks AI', auth: 'FIREWORKS_API_KEY', protocol: 'pi_native', piProvider: 'fireworks' },
265
+ { id: 'pi.huggingface', client: 'pi', provider: 'huggingface', label: 'Hugging Face', auth: 'HF_TOKEN', protocol: 'pi_native', piProvider: 'huggingface' },
266
+ { id: 'pi.minimax', client: 'pi', provider: 'minimax', label: 'MiniMax', auth: 'MINIMAX_API_KEY', protocol: 'pi_native', piProvider: 'minimax' },
267
+ { id: 'pi.kimi-coding', client: 'pi', provider: 'kimi-coding', label: 'Kimi For Coding', auth: 'KIMI_API_KEY', protocol: 'pi_native', piProvider: 'kimi-coding' },
268
+ { id: 'pi.mistral', client: 'pi', provider: 'mistral', label: 'Mistral', auth: 'MISTRAL_API_KEY', protocol: 'pi_native', piProvider: 'mistral' },
269
+ { id: 'pi.together', client: 'pi', provider: 'together', label: 'Together AI', auth: 'TOGETHER_API_KEY', protocol: 'pi_native', piProvider: 'together' },
185
270
  { id: 'pi.ollama', client: 'pi', provider: 'ollama', label: 'Ollama local', auth: 'none', protocol: 'openai-completions', piProvider: 'ollama', requiresModel: true, core: true, piExtension: { baseUrl: 'http://127.0.0.1:11434/v1', apiKey: 'ollama' } },
186
- { id: 'pi.zai', client: 'pi', provider: 'zai', label: 'Z.AI', auth: 'ZAI_API_KEY', protocol: 'pi_native', piProvider: 'zai', core: true },
187
271
  { id: 'pi.custom', client: 'pi', provider: 'custom', label: 'Custom provider', auth: 'dynamic', protocol: 'openai-responses', protocols: ['openai-responses', 'anthropic-messages', 'openai-completions', 'google-generative-ai'], custom: true, core: true },
188
272
 
189
273
  // Agy: client gestito primario (Linux/macOS non-Termux). Auth delegata al
@@ -205,6 +289,17 @@ const CATALOG = Object.freeze([
205
289
  // senza platform gate (il CLI gira ovunque giri Node; su Termux il resolver
206
290
  // applica gia' il workaround shebang needsExplicitNode).
207
291
  { id: 'kimi.native', client: 'kimi', provider: 'native', label: 'Kimi account (CLI login)', auth: 'login', protocol: 'kimi_native', core: true, notice: 'kimi-native' },
292
+
293
+ // Device-local shell. Resta l'ultimo client (anche fra i default): il seed la
294
+ // preseleziona come engine di fallback, mai come primaria, e cosi' non sposta
295
+ // l'engine preselezionato per una cella appena creata (claude.native primo).
296
+ { id: 'shell.local', client: 'shell', provider: 'local', label: 'Shell', auth: 'none', protocol: 'shell', default: true, core: true },
297
+
298
+ // --- Sezione legacy --------------------------------------------------------
299
+ // Compatibilita' sola lettura/launch per configurazioni 0.8.0: mai nel catalogo
300
+ // UI (publicCatalog filtra `legacy`). Risolti solo da profileFor/normalizeManagedSpec.
301
+ { id: 'claude.zai-a', client: 'claude', provider: 'zai', credentialProfile: 'a', label: 'Z.AI legacy profile', auth: 'ZAI_API_KEY_A', endpoint: 'https://api.z.ai/api/anthropic', protocol: 'anthropic_messages', model: 'glm-5.2[1m]', models: ['glm-5.2[1m]'], legacySecrets: true, legacyProvider: 'zai-a', legacy: true },
302
+ { id: 'claude.zai-p', client: 'claude', provider: 'zai', credentialProfile: 'p', label: 'Z.AI legacy profile', auth: 'ZAI_API_KEY_P', endpoint: 'https://api.z.ai/api/anthropic', protocol: 'anthropic_messages', model: 'glm-5.2[1m]', models: ['glm-5.2[1m]'], legacySecrets: true, legacyProvider: 'zai-p', legacy: true },
208
303
  ]);
209
304
 
210
305
  function profileFor(client, provider, credentialProfile) {
@@ -245,7 +340,9 @@ function normalizeManagedSpec(value, { extraModels = null } = {}) {
245
340
  && !declaredFor(extraModels, profile.id, model)) return null;
246
341
  const permissionPolicy = value.permissionPolicy === undefined ? (profile.client === 'claude' ? 'unsafe' : 'standard') : value.permissionPolicy;
247
342
  if (permissionPolicy !== 'standard' && permissionPolicy !== 'unsafe') return null;
248
- if ((value.client === 'pi' || value.client === 'shell') && permissionPolicy !== 'standard') return null;
343
+ // vl e' standard-only: il CLI Vivling non ha flag di approvazione, quindi
344
+ // 'unsafe' non ha controparte argv e va rifiutato (fail-closed), come pi/shell.
345
+ if ((value.client === 'pi' || value.client === 'shell' || value.client === 'vl') && permissionPolicy !== 'standard') return null;
249
346
  const credentialSourcePolicy = value.credentialSourcePolicy === undefined ? 'auto' : value.credentialSourcePolicy;
250
347
  if (!CREDENTIAL_SOURCES.includes(credentialSourcePolicy)) return null;
251
348
  const out = { client: profile.client, provider: profile.provider, model, permissionPolicy };
@@ -321,6 +418,32 @@ function defaultKimiEngine() {
321
418
  };
322
419
  }
323
420
 
421
+ // Engine Grok Build per il backfill platform-aware (builtin.js): standard di
422
+ // default, auth delegata al login locale del CLI, niente remote-control. Non e'
423
+ // un default seed (come Agy).
424
+ function defaultGrokEngine() {
425
+ const profile = CATALOG.find((entry) => entry.id === 'grok.native');
426
+ return {
427
+ id: profile.id,
428
+ label: CLIENT_LABELS.grok,
429
+ rc: false,
430
+ managed: { client: 'grok', provider: 'native', model: '', permissionPolicy: 'standard' },
431
+ };
432
+ }
433
+
434
+ // Engine VL/Vivling per il backfill (builtin.js, pattern Kimi senza platform
435
+ // gate): runtime locale standard-only, auth propria del runtime, niente
436
+ // remote-control. Non e' un default seed.
437
+ function defaultVlEngine() {
438
+ const profile = CATALOG.find((entry) => entry.id === 'vl.native');
439
+ return {
440
+ id: profile.id,
441
+ label: CLIENT_LABELS.vl,
442
+ rc: false,
443
+ managed: { client: 'vl', provider: 'native', model: '', permissionPolicy: 'standard' },
444
+ };
445
+ }
446
+
324
447
  function parseAssignments(raw) {
325
448
  const out = {};
326
449
  for (const line of raw.split(/\r?\n/)) {
@@ -383,7 +506,11 @@ function parseProviderShellFile(file) {
383
506
  function binaryCandidates(client, home) {
384
507
  const prefix = process.env.PREFIX || '';
385
508
  const bin = client;
509
+ // grok-build installa in ~/.grok/bin (path non standard): cercato prima dei
510
+ // soliti PATH, poi fallback sui path generici (es. symlink in ~/.local/bin).
511
+ const extra = client === 'grok' ? [path.join(home, '.grok', 'bin', bin)] : [];
386
512
  return [...new Set([
513
+ ...extra,
387
514
  path.join(home, '.local', 'bin', bin), path.join(path.dirname(process.execPath), bin),
388
515
  `/usr/local/bin/${bin}`, `/opt/homebrew/bin/${bin}`,
389
516
  prefix && path.join(prefix, 'bin', bin),
@@ -670,15 +797,15 @@ function describeManaged(spec, cfg = {}) {
670
797
  let reason = !binary ? `client ${profile.client} not found` : (!authConfigured
671
798
  ? `credential ${cred.envKey} missing — set it on this device`
672
799
  : 'ready');
673
- // Agy e' un client primario supportato solo su Linux/macOS non-Termux.
800
+ // Agy e grok sono client primari supportati solo su Linux/macOS non-Termux.
674
801
  // Rilevazione Termux via termuxRuntimePaths (non solo process.platform): un
675
802
  // Node che riporta 'linux' sotto proot/Termux viene comunque intercettato.
676
- if (normalized.client === 'agy') {
803
+ if (normalized.client === 'agy' || normalized.client === 'grok') {
677
804
  const platform = cfg.platform || process.platform;
678
805
  const termux = platform === 'android' || termuxRuntimePaths(cfg.env || process.env, { platform, home }) !== null;
679
806
  if (termux || (platform !== 'linux' && platform !== 'darwin')) {
680
807
  configured = false;
681
- reason = 'agy non supportato su questa piattaforma (usa shell.local con command agy)';
808
+ reason = `${normalized.client} non supportato su questa piattaforma (usa shell.local con command ${normalized.client})`;
682
809
  }
683
810
  }
684
811
  return {
@@ -978,11 +1105,14 @@ function resolveManagedEngine(engine, cell, cfg = {}) {
978
1105
  let effectivePolicy = (override === 'standard' || override === 'unsafe') ? override : spec.permissionPolicy;
979
1106
  // Pi resta sempre 'standard': normalizeManagedSpec rifiuta gia' unsafe nello spec
980
1107
  // dell'engine, ma l'override PER-CELL bypasserebbe quel check -> clamp esplicito.
981
- if (spec.client === 'pi' || spec.client === 'shell') effectivePolicy = 'standard';
1108
+ if (spec.client === 'pi' || spec.client === 'shell' || spec.client === 'vl') effectivePolicy = 'standard';
982
1109
  info.permissionPolicy = effectivePolicy;
983
1110
  if (effectivePolicy === 'unsafe') {
984
1111
  if (spec.client === 'claude' || spec.client === 'agy') args.push('--dangerously-skip-permissions');
985
1112
  if (spec.client === 'codex' || spec.client === 'codex-vl') args.push('--dangerously-bypass-approvals-and-sandbox');
1113
+ // Grok Build: unsafe -> --always-approve (flag reale di `grok`, "Auto-approve
1114
+ // all tool executions"; verificato su `grok --help`).
1115
+ if (spec.client === 'grok') args.push('--always-approve');
986
1116
  // Kimi Code CLI: unsafe mappa su --yolo (auto-approva le chiamate tool
987
1117
  // ordinarie ma l'agente puo' ancora fare domande). --auto (fully
988
1118
  // autonomous, nessuna domanda) NON e' mappato: il contratto NexusCrew
@@ -1025,6 +1155,26 @@ function resolveManagedEngine(engine, cell, cfg = {}) {
1025
1155
  env.CLAUDE_CODE_EFFORT_LEVEL = 'max';
1026
1156
  env.CLAUDE_CODE_ALWAYS_ENABLE_EFFORT = '1';
1027
1157
  }
1158
+ } else if (spec.provider === 'opencode-go') {
1159
+ // Misurato il 2026-08-11: `POST /v1/messages` con `Authorization: Bearer`
1160
+ // risponde `401 AuthError: Missing API key`, con `x-api-key` risponde 200.
1161
+ // ANTHROPIC_API_KEY e' cio' che Claude Code manda come `x-api-key`, quindi
1162
+ // qui NON si usa la forma a token degli altri gateway.
1163
+ //
1164
+ // Nessun CLAUDE_CODE_MAX_CONTEXT_TOKENS: il context window reale di questi
1165
+ // modelli su OpenCode Go non e' misurato, e un numero inventato qui
1166
+ // diventerebbe la configurazione con cui le celle compattano.
1167
+ Object.assign(env, {
1168
+ ANTHROPIC_BASE_URL: profile.endpoint,
1169
+ ANTHROPIC_API_KEY: cred.value,
1170
+ ANTHROPIC_MODEL: model,
1171
+ ANTHROPIC_DEFAULT_FABLE_MODEL: model,
1172
+ ANTHROPIC_DEFAULT_OPUS_MODEL: model,
1173
+ ANTHROPIC_DEFAULT_SONNET_MODEL: model,
1174
+ ANTHROPIC_DEFAULT_HAIKU_MODEL: model,
1175
+ CLAUDE_CODE_SUBAGENT_MODEL: model,
1176
+ API_TIMEOUT_MS: '3000000',
1177
+ });
1028
1178
  } else if (spec.provider === 'alibaba-token-plan') {
1029
1179
  privateProfile = true;
1030
1180
  const qwen38 = model === 'qwen3.8-max';
@@ -1104,6 +1254,14 @@ function resolveManagedEngine(engine, cell, cfg = {}) {
1104
1254
  args.push('-c', `model_catalog_json=${JSON.stringify(localCatalog)}`);
1105
1255
  args.push('-c', `model_context_window=${ALIBABA_TOKEN_PLAN_CONTEXT}`);
1106
1256
  }
1257
+ } else if (spec.provider === 'opencode-go') {
1258
+ // Wire Responses nativa: il gateway espone `/v1/responses` e Codex-VL vi
1259
+ // aggiunge il path, quindi qui l'endpoint include gia' `/v1`. Nessun
1260
+ // model_context_window: non e' misurato, e il default del client e' piu'
1261
+ // onesto di una costante inventata.
1262
+ env.OPENCODE_API_KEY = cred.value;
1263
+ args.push(...codexProviderArgs('opencode_go', 'OpenCode Go', profile.endpoint, 'OPENCODE_API_KEY'));
1264
+ args.push('-c', 'model_providers.opencode_go.stream_idle_timeout_ms=600000');
1107
1265
  } else if (spec.provider === 'custom') {
1108
1266
  env[spec.envKey] = cred.value;
1109
1267
  args.push(...codexProviderArgs(spec.providerId, spec.displayName, spec.baseUrl, spec.envKey));
@@ -1127,6 +1285,17 @@ function resolveManagedEngine(engine, cell, cfg = {}) {
1127
1285
  // dal push generico qui sotto). Senza prompt parte il TUI interattivo `agy`.
1128
1286
  if (model) args.push('--model', model);
1129
1287
  if (cell?.prompt) args.push('--prompt-interactive');
1288
+ } else if (spec.client === 'grok') {
1289
+ // Grok Build delega l'autenticazione al proprio login locale (auth 'login'):
1290
+ // niente env provider, niente credenziali su argv. `--model` prima del
1291
+ // prompt; il prompt e' bare posizionale (`grok [OPTIONS] [PROMPT]`), accodato
1292
+ // dal push generico qui sotto come ultimo argomento. Senza prompt parte il
1293
+ // TUI interattivo nella cwd della cella.
1294
+ if (model) args.push('--model', model);
1295
+ } else if (spec.client === 'vl') {
1296
+ // VL/Vivling runtime TUI: auth e modello gestiti dal runtime (config.toml /
1297
+ // env VL_*), niente credenziali su argv. `vl [OPTIONS]` non accetta ne'
1298
+ // --model ne' un prompt: lancia la TUI senza argomenti nella cwd della cella.
1130
1299
  } else if (spec.client === 'kimi') {
1131
1300
  // Kimi Code CLI nativo: auth e provider gestiti dal CLI (login device-code,
1132
1301
  // config.toml): niente env provider, niente credenziali su argv. Il CLI non
@@ -1145,7 +1314,11 @@ function resolveManagedEngine(engine, cell, cfg = {}) {
1145
1314
  // (finding separato, fuori da questa patch).
1146
1315
  const promptViaDelivery = spec.client === 'kimi'
1147
1316
  || (spec.client === 'claude' && spec.provider === 'kimi-code');
1148
- if (spec.client !== 'shell' && !promptViaDelivery && cell?.prompt) args.push(cell.prompt);
1317
+ // vl e' una TUI senza superficie prompt (`vl [OPTIONS]`, nessun flag prompt):
1318
+ // non riceve mai il prompt di cella su argv (lo snippet di interazione e'
1319
+ // demandato all'utente nella TUI). send-keys non si applica: il classifier di
1320
+ // deliverBootstrapPrompt copre solo kimi/claude, e vl parte subito senza attese.
1321
+ if (spec.client !== 'shell' && spec.client !== 'vl' && !promptViaDelivery && cell?.prompt) args.push(cell.prompt);
1149
1322
  // nexuscrew-store source: neutralize the profile's env set in the composed
1150
1323
  // child env (unset, never empty), so the runtime cannot leak credentials that
1151
1324
  // the local store is meant to own.
@@ -1167,7 +1340,7 @@ function publicCatalog() {
1167
1340
  id: p.id, client: p.client, clientLabel: CLIENT_LABELS[p.client], provider: p.provider,
1168
1341
  credentialProfile: p.credentialProfile || '', label: p.label, protocol: p.protocol,
1169
1342
  auth: p.auth, endpoint: p.endpoint || '', model: p.model || '', models: [...(p.models || [])],
1170
- protocols: [...(p.protocols || [p.protocol])], supportsUnsafe: !['pi', 'shell'].includes(p.client), requiresModel: !!p.requiresModel || !!p.custom,
1343
+ protocols: [...(p.protocols || [p.protocol])], supportsUnsafe: !['pi', 'shell', 'vl'].includes(p.client), requiresModel: !!p.requiresModel || !!p.custom,
1171
1344
  permissionPolicyDefault: p.client === 'claude' ? 'unsafe' : 'standard',
1172
1345
  rc: !!p.rc, custom: !!p.custom, default: !!p.default, notice: p.notice || '',
1173
1346
  // 'login'/'none' non sono variabili d'ambiente: nessuna KEY section per gli
@@ -1182,8 +1355,10 @@ module.exports = {
1182
1355
  knownMcpServerNames,
1183
1356
  CATALOG, OLLAMA_CLOUD_MODELS, OLLAMA_CONTEXT, ALIBABA_TOKEN_PLAN_MODELS,
1184
1357
  ALIBABA_CODEX_MODELS, ALIBABA_TOKEN_PLAN_CONTEXT, ALIBABA_PI_MODELS,
1358
+ OPENCODE_GO_MESSAGES_MODELS, OPENCODE_GO_RESPONSES_MODELS, OPENCODE_GO_CHAT_MODELS,
1359
+ OPENCODE_GO_ANTHROPIC_ROOT, OPENCODE_GO_API_BASE,
1185
1360
  CLIENT_LABELS, normalizeManagedSpec, profileFor,
1186
- defaultDefinitions, defaultShellEngine, defaultAgyEngine, defaultKimiEngine, describeManaged, describeCatalogCredential, discoverOllamaModels, resolveManagedEngine, needsExplicitNode,
1361
+ defaultDefinitions, defaultShellEngine, defaultAgyEngine, defaultKimiEngine, defaultGrokEngine, defaultVlEngine, describeManaged, describeCatalogCredential, discoverOllamaModels, resolveManagedEngine, needsExplicitNode,
1187
1362
  discoverPiModels, EXTERNAL_DISCOVERY_TIMEOUT_MS, parseEnvFile, parseProviderShellFile, findBinary, publicCatalog, writePiProviderExtension,
1188
1363
  extraModelsFrom,
1189
1364
  providerKeyPaths, parseProviderKeyFiles, credentialSources, credential,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mmmbuto/nexuscrew",
3
- "version": "0.8.55",
3
+ "version": "0.8.57",
4
4
  "description": "Faithful browser tmux client — attach to live sessions over a real PTY, localhost-only, mobile-easy",
5
5
  "main": "lib/server.js",
6
6
  "bin": {