@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,{})]}));
|
package/frontend/dist/index.html
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
<meta name="apple-mobile-web-app-title" content="NexusCrew" />
|
|
12
12
|
<link rel="manifest" href="/manifest.json" />
|
|
13
13
|
<title>NexusCrew</title>
|
|
14
|
-
<script type="module" crossorigin src="/assets/index-
|
|
14
|
+
<script type="module" crossorigin src="/assets/index-_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.
|
|
1
|
+
{"version":"0.8.57"}
|
package/lib/fleet/builtin.js
CHANGED
|
@@ -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,
|
package/lib/fleet/managed.js
CHANGED
|
@@ -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
|
|
151
|
-
|
|
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.
|
|
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
|
|
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
|
|
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
|
-
//
|
|
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
|
-
|
|
170
|
-
//
|
|
171
|
-
|
|
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
|
-
|
|
183
|
-
|
|
184
|
-
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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
|
-
|
|
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,
|