tmex-cli 0.16.5 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/CHANGELOG.md +40 -4
  2. package/dist/runtime/server.js +702 -337
  3. package/package.json +2 -1
  4. package/resources/fe-dist/assets/DevicePage-B-4Wp5gx.js +24 -0
  5. package/resources/fe-dist/assets/{DevicesPage-XMtf7VIy.js → DevicesPage-D3GQd_MI.js} +1 -1
  6. package/resources/fe-dist/assets/{FilePage-C1_JLsEc.js → FilePage-C45pl7_F.js} +2 -2
  7. package/resources/fe-dist/assets/SettingsPage-DEkQrJzi.js +39 -0
  8. package/resources/fe-dist/assets/{agent-tab-BgvIAv35.js → agent-tab-BnKrqJP2.js} +2 -2
  9. package/resources/fe-dist/assets/api-5IhJ49aS.js +5 -0
  10. package/resources/fe-dist/assets/{arc-BX-Po9p7.js → arc-DBxiTdY2.js} +1 -1
  11. package/resources/fe-dist/assets/{architectureDiagram-3BPJPVTR-BneOtjGd.js → architectureDiagram-3BPJPVTR-Dcd70ntw.js} +1 -1
  12. package/resources/fe-dist/assets/{blockDiagram-GPEHLZMM-Dcf0shYG.js → blockDiagram-GPEHLZMM-LsFpH20h.js} +1 -1
  13. package/resources/fe-dist/assets/{c4Diagram-AAUBKEIU-Cwhji_wO.js → c4Diagram-AAUBKEIU-BswGzO6B.js} +1 -1
  14. package/resources/fe-dist/assets/{card-IkOsEv2J.js → card-Bav-X9c4.js} +1 -1
  15. package/resources/fe-dist/assets/channel-hAJp4tg-.js +1 -0
  16. package/resources/fe-dist/assets/{chunk-2J33WTMH-IFwQoyns.js → chunk-2J33WTMH-C0yl1OR1.js} +1 -1
  17. package/resources/fe-dist/assets/{chunk-4BX2VUAB-BZhwH7K2.js → chunk-4BX2VUAB-Dwo9vDDk.js} +1 -1
  18. package/resources/fe-dist/assets/{chunk-55IACEB6-pYNojBsx.js → chunk-55IACEB6-Dz9e7vav.js} +1 -1
  19. package/resources/fe-dist/assets/{chunk-727SXJPM-BwBn-X-G.js → chunk-727SXJPM-ZkqwcZ6G.js} +1 -1
  20. package/resources/fe-dist/assets/{chunk-AQP2D5EJ-Cv5U78aO.js → chunk-AQP2D5EJ-79MMuY3h.js} +1 -1
  21. package/resources/fe-dist/assets/{chunk-FMBD7UC4-DnaDXP2z.js → chunk-FMBD7UC4-Vw8e6XCy.js} +1 -1
  22. package/resources/fe-dist/assets/{chunk-ND2GUHAM-BCRcaTWl.js → chunk-ND2GUHAM-um7O2-xi.js} +1 -1
  23. package/resources/fe-dist/assets/{chunk-QZHKN3VN-1sPBtZCH.js → chunk-QZHKN3VN-D8FuV91c.js} +1 -1
  24. package/resources/fe-dist/assets/classDiagram-4FO5ZUOK-SSiS3KfC.js +1 -0
  25. package/resources/fe-dist/assets/classDiagram-v2-Q7XG4LA2-SSiS3KfC.js +1 -0
  26. package/resources/fe-dist/assets/{copy-CJIriuQt.js → copy-Cawnv2-o.js} +1 -1
  27. package/resources/fe-dist/assets/{cose-bilkent-S5V4N54A-CY6ERT7s.js → cose-bilkent-S5V4N54A-gidx-z0G.js} +1 -1
  28. package/resources/fe-dist/assets/{dagre-BM42HDAG-c_oJjVCK.js → dagre-BM42HDAG-C54CUHrk.js} +1 -1
  29. package/resources/fe-dist/assets/{diagram-2AECGRRQ-g-DJAnzv.js → diagram-2AECGRRQ-DFGI1MJu.js} +1 -1
  30. package/resources/fe-dist/assets/{diagram-5GNKFQAL-0DikWL30.js → diagram-5GNKFQAL-D7POJY8A.js} +1 -1
  31. package/resources/fe-dist/assets/{diagram-KO2AKTUF-wWVJH7kq.js → diagram-KO2AKTUF-CvV1GMLL.js} +1 -1
  32. package/resources/fe-dist/assets/{diagram-LMA3HP47-UwQ9OpsG.js → diagram-LMA3HP47-BbfJVUKI.js} +1 -1
  33. package/resources/fe-dist/assets/{diagram-OG6HWLK6-ZFNNtnbo.js → diagram-OG6HWLK6-CV6Q6IxH.js} +1 -1
  34. package/resources/fe-dist/assets/download-ZSRF6UU6.js +6 -0
  35. package/resources/fe-dist/assets/en_US-xzwBD2oK.js +1 -0
  36. package/resources/fe-dist/assets/{erDiagram-TEJ5UH35-D3na7WWE.js → erDiagram-TEJ5UH35-BPgvqV_L.js} +1 -1
  37. package/resources/fe-dist/assets/{files-tab-1FVCHULV.js → files-tab-BQhhr5Wi.js} +15 -15
  38. package/resources/fe-dist/assets/{flowDiagram-I6XJVG4X-Dsbf9z99.js → flowDiagram-I6XJVG4X-CKXjL0zg.js} +1 -1
  39. package/resources/fe-dist/assets/{ganttDiagram-6RSMTGT7-CF3CKflH.js → ganttDiagram-6RSMTGT7-D58QnW85.js} +1 -1
  40. package/resources/fe-dist/assets/{gitGraphDiagram-PVQCEYII-CRpX3WPf.js → gitGraphDiagram-PVQCEYII-BwB9zJYk.js} +1 -1
  41. package/resources/fe-dist/assets/{index-U4iZ6Kxr.js → index-CxD8veUJ.js} +16 -16
  42. package/resources/fe-dist/assets/{index-C-RSAqjj.js → index-DDvqV24J.js} +1 -1
  43. package/resources/fe-dist/assets/{infoDiagram-5YYISTIA-DMCNm7PZ.js → infoDiagram-5YYISTIA-DGZZJ51K.js} +1 -1
  44. package/resources/fe-dist/assets/{ishikawaDiagram-YF4QCWOH-CMe-J41c.js → ishikawaDiagram-YF4QCWOH-DKEV0i-O.js} +1 -1
  45. package/resources/fe-dist/assets/ja_JP-Dd1FrxOk.js +1 -0
  46. package/resources/fe-dist/assets/{journeyDiagram-JHISSGLW-CxFZDT81.js → journeyDiagram-JHISSGLW-Dvt5MIiS.js} +1 -1
  47. package/resources/fe-dist/assets/{kanban-definition-UN3LZRKU-DwBxD_Gg.js → kanban-definition-UN3LZRKU-BrLCK6I8.js} +1 -1
  48. package/resources/fe-dist/assets/{linear-CBM17AV1.js → linear-LNJ3BF_d.js} +1 -1
  49. package/resources/fe-dist/assets/{markdown-preview-CVeuDkuY.js → markdown-preview-Cqdqjc1H.js} +3 -3
  50. package/resources/fe-dist/assets/{mermaid.core-CvSv2dqw.js → mermaid.core-Cy4PFTl-.js} +5 -5
  51. package/resources/fe-dist/assets/{mindmap-definition-RKZ34NQL-DUu53RHy.js → mindmap-definition-RKZ34NQL-JOcL1ZTP.js} +1 -1
  52. package/resources/fe-dist/assets/{pieDiagram-4H26LBE5-CAbw9YBY.js → pieDiagram-4H26LBE5-_1o-TTd6.js} +1 -1
  53. package/resources/fe-dist/assets/{quadrantDiagram-W4KKPZXB-NmJUURAz.js → quadrantDiagram-W4KKPZXB-7Ggy2jhO.js} +1 -1
  54. package/resources/fe-dist/assets/{requirementDiagram-4Y6WPE33-B45iu7jV.js → requirementDiagram-4Y6WPE33-CH_udJzB.js} +1 -1
  55. package/resources/fe-dist/assets/{sankeyDiagram-5OEKKPKP-af9JvT_p.js → sankeyDiagram-5OEKKPKP-DO9ymHJb.js} +1 -1
  56. package/resources/fe-dist/assets/{send-e_FTy5nC.js → send-D0SbMcl5.js} +1 -1
  57. package/resources/fe-dist/assets/{sequenceDiagram-3UESZ5HK-CSpSOeHp.js → sequenceDiagram-3UESZ5HK-BfxbUo5S.js} +1 -1
  58. package/resources/fe-dist/assets/{stateDiagram-AJRCARHV-vM6MSoBd.js → stateDiagram-AJRCARHV-ChJ5OE86.js} +1 -1
  59. package/resources/fe-dist/assets/stateDiagram-v2-BHNVJYJU-yafZZKAc.js +1 -0
  60. package/resources/fe-dist/assets/terminal-settings-panel-CFkXHe7W.js +25 -0
  61. package/resources/fe-dist/assets/{timeline-definition-PNZ67QCA-A63tNc2d.js → timeline-definition-PNZ67QCA-CIlpfkBn.js} +1 -1
  62. package/resources/fe-dist/assets/{transfer-toast-CmSO0e95.js → transfer-toast-DvU8-v2e.js} +1 -1
  63. package/resources/fe-dist/assets/{triangle-alert-jNMwsJMj.js → triangle-alert-BI3hbdo6.js} +1 -1
  64. package/resources/fe-dist/assets/{vennDiagram-CIIHVFJN-BktPK2LC.js → vennDiagram-CIIHVFJN-NqSGMHBa.js} +1 -1
  65. package/resources/fe-dist/assets/{wardley-L42UT6IY-viU1xsE2.js → wardley-L42UT6IY-bOJt96SM.js} +1 -1
  66. package/resources/fe-dist/assets/{wardleyDiagram-YWT4CUSO-DICOr7Mv.js → wardleyDiagram-YWT4CUSO-DAgFPWOP.js} +1 -1
  67. package/resources/fe-dist/assets/{xychartDiagram-2RQKCTM6-bjue7pS9.js → xychartDiagram-2RQKCTM6-D5rVqEFB.js} +1 -1
  68. package/resources/fe-dist/assets/{zap-ClXbg92C.js → zap-D-Szn4JY.js} +1 -1
  69. package/resources/fe-dist/assets/zh_CN-DVIa9MQX.js +1 -0
  70. package/resources/fe-dist/index.html +1 -1
  71. package/resources/gateway-drizzle/0015_wise_mongu.sql +1 -0
  72. package/resources/gateway-drizzle/0016_cheerful_scarecrow.sql +17 -0
  73. package/resources/gateway-drizzle/meta/_journal.json +14 -0
  74. package/resources/fe-dist/assets/DevicePage-BIjGEtCP.js +0 -24
  75. package/resources/fe-dist/assets/SettingsPage-BAx39LyM.js +0 -39
  76. package/resources/fe-dist/assets/api-Dto6Spgl.js +0 -10
  77. package/resources/fe-dist/assets/channel-DD10rSnh.js +0 -1
  78. package/resources/fe-dist/assets/classDiagram-4FO5ZUOK-CEWAB_yV.js +0 -1
  79. package/resources/fe-dist/assets/classDiagram-v2-Q7XG4LA2-CEWAB_yV.js +0 -1
  80. package/resources/fe-dist/assets/en_US-BihUhDmr.js +0 -1
  81. package/resources/fe-dist/assets/ja_JP-f5sXmz8W.js +0 -1
  82. package/resources/fe-dist/assets/stateDiagram-v2-BHNVJYJU-8FQLtPkV.js +0 -1
  83. package/resources/fe-dist/assets/terminal-settings-panel-DU9rOuZd.js +0 -25
  84. package/resources/fe-dist/assets/zh_CN-CPdvelFW.js +0 -1
@@ -1,39 +0,0 @@
1
- import{Y as ce,u as F,j as e,L as Pt,M as Ye,z as Ft,r as y,c as K,B as k,P as xe,a as O,e as M,o as b,a2 as _,v as Oe,T as te,A as fe,f as pe,g as we,h as At,i as ye,k as je,l as ve,m as be,n as Ne,C as ae,F as ne,H as ie,I as re,J as Ce,N as Ee,O as ke,Q as Se,R as Me,U as le,K as D,W as de,aq as Q,G as Tt,x as dt,at as Rt,b as ge,t as Xe,bt as $,X as mt,af as It,bu as Lt,bv as $t,aB as Dt,bw as Ot,bx as Bt,by as _t,bz as zt,bA as et,Z as qt}from"./index-U4iZ6Kxr.js";import{C as U,b as G,c as W,d as ut,a as H}from"./card-IkOsEv2J.js";import{e as Kt,h as ht,F as He,i as Qt,j as Ut,D as Ht}from"./api-Dto6Spgl.js";import{R as Ze,T as Vt,b as Gt,d as Wt}from"./terminal-settings-panel-DU9rOuZd.js";import{S as gt}from"./send-e_FTy5nC.js";import{M as Jt}from"./markdown-preview-CVeuDkuY.js";import{T as xt}from"./triangle-alert-jNMwsJMj.js";import"./selection-clipboard-D3gUQQ7L.js";import"./index-C-RSAqjj.js";/**
2
- * @license lucide-react v0.564.0 - ISC
3
- *
4
- * This source code is licensed under the ISC license.
5
- * See the LICENSE file in the root directory of this source tree.
6
- */const Yt=[["path",{d:"M2.97 12.92A2 2 0 0 0 2 14.63v3.24a2 2 0 0 0 .97 1.71l3 1.8a2 2 0 0 0 2.06 0L12 19v-5.5l-5-3-4.03 2.42Z",key:"lc1i9w"}],["path",{d:"m7 16.5-4.74-2.85",key:"1o9zyk"}],["path",{d:"m7 16.5 5-3",key:"va8pkn"}],["path",{d:"M7 16.5v5.17",key:"jnp8gn"}],["path",{d:"M12 13.5V19l3.97 2.38a2 2 0 0 0 2.06 0l3-1.8a2 2 0 0 0 .97-1.71v-3.24a2 2 0 0 0-.97-1.71L17 10.5l-5 3Z",key:"8zsnat"}],["path",{d:"m17 16.5-5-3",key:"8arw3v"}],["path",{d:"m17 16.5 4.74-2.85",key:"8rfmw"}],["path",{d:"M17 16.5v5.17",key:"k6z78m"}],["path",{d:"M7.97 4.42A2 2 0 0 0 7 6.13v4.37l5 3 5-3V6.13a2 2 0 0 0-.97-1.71l-3-1.8a2 2 0 0 0-2.06 0l-3 1.8Z",key:"1xygjf"}],["path",{d:"M12 8 7.26 5.15",key:"1vbdud"}],["path",{d:"m12 8 4.74-2.85",key:"3rx089"}],["path",{d:"M12 13.5V8",key:"1io7kd"}]],Xt=ce("boxes",Yt);/**
7
- * @license lucide-react v0.564.0 - ISC
8
- *
9
- * This source code is licensed under the ISC license.
10
- * See the LICENSE file in the root directory of this source tree.
11
- */const Zt=[["rect",{width:"5",height:"5",x:"3",y:"3",rx:"1",key:"1tu5fj"}],["rect",{width:"5",height:"5",x:"16",y:"3",rx:"1",key:"1v8r4q"}],["rect",{width:"5",height:"5",x:"3",y:"16",rx:"1",key:"1x03jg"}],["path",{d:"M21 16h-3a2 2 0 0 0-2 2v3",key:"177gqh"}],["path",{d:"M21 21v.01",key:"ents32"}],["path",{d:"M12 7v3a2 2 0 0 1-2 2H7",key:"8crl2c"}],["path",{d:"M3 12h.01",key:"nlz23k"}],["path",{d:"M12 3h.01",key:"n36tog"}],["path",{d:"M12 16v.01",key:"133mhm"}],["path",{d:"M16 12h1",key:"1slzba"}],["path",{d:"M21 12v.01",key:"1lwtk9"}],["path",{d:"M12 21v-1",key:"1880an"}]],Ve=ce("qr-code",Zt);/**
12
- * @license lucide-react v0.564.0 - ISC
13
- *
14
- * This source code is licensed under the ISC license.
15
- * See the LICENSE file in the root directory of this source tree.
16
- */const es=[["path",{d:"M15.2 3a2 2 0 0 1 1.4.6l3.8 3.8a2 2 0 0 1 .6 1.4V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2z",key:"1c8476"}],["path",{d:"M17 21v-7a1 1 0 0 0-1-1H8a1 1 0 0 0-1 1v7",key:"1ydtos"}],["path",{d:"M7 3v4a1 1 0 0 0 1 1h7",key:"t51u73"}]],ee=ce("save",es);/**
17
- * @license lucide-react v0.564.0 - ISC
18
- *
19
- * This source code is licensed under the ISC license.
20
- * See the LICENSE file in the root directory of this source tree.
21
- */const ts=[["rect",{width:"20",height:"8",x:"2",y:"2",rx:"2",ry:"2",key:"ngkwjq"}],["rect",{width:"20",height:"8",x:"2",y:"14",rx:"2",ry:"2",key:"iecqi9"}],["line",{x1:"6",x2:"6.01",y1:"6",y2:"6",key:"16zg32"}],["line",{x1:"6",x2:"6.01",y1:"18",y2:"18",key:"nzw8ys"}]],ss=ce("server",ts);/**
22
- * @license lucide-react v0.564.0 - ISC
23
- *
24
- * This source code is licensed under the ISC license.
25
- * See the LICENSE file in the root directory of this source tree.
26
- */const as=[["path",{d:"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z",key:"oel41y"}]],tt=ce("shield",as);/**
27
- * @license lucide-react v0.564.0 - ISC
28
- *
29
- * This source code is licensed under the ISC license.
30
- * See the LICENSE file in the root directory of this source tree.
31
- */const ns=[["path",{d:"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2",key:"1yyitq"}],["path",{d:"M16 3.128a4 4 0 0 1 0 7.744",key:"16gr8j"}],["path",{d:"M22 21v-2a4 4 0 0 0-3-3.87",key:"kshegd"}],["circle",{cx:"9",cy:"7",r:"4",key:"nufk8"}]],is=ce("users",ns);function rs(){const{t}=F();return e.jsxs(U,{className:"border-0 ring-0",children:[e.jsxs(G,{children:[e.jsx(W,{children:t("settings.deviceManagement.title")}),e.jsx(ut,{children:t("settings.deviceManagement.description")})]}),e.jsx(H,{children:e.jsxs(Pt,{to:"/devices","data-testid":"settings-device-management-link",className:Ft({variant:"secondary"}),children:[e.jsx(Ye,{className:"h-4 w-4"}),t("settings.deviceManagement.openButton")]})})]})}function $e({type:t,className:o}){return t==="ssh"?e.jsx(Tt,{className:o}):e.jsx(Ye,{className:o})}function os(){var r,m;const{t}=F(),[o,s]=y.useState(!1),[l,c]=y.useState(void 0),h=K({queryKey:["files","roots"],queryFn:Kt}),p=K({queryKey:["devices"],queryFn:async()=>{const d=await fetch("/api/devices");if(!d.ok)throw new Error(`HTTP ${d.status}`);return await d.json()},throwOnError:!1}),f=((r=h.data)==null?void 0:r.roots)??[],a=((m=p.data)==null?void 0:m.devices)??[],n=()=>{c(void 0),s(!0)},i=d=>{c(d),s(!0)};return e.jsxs(e.Fragment,{children:[e.jsxs(U,{className:"border-0 ring-0","data-testid":"settings-files-section",children:[e.jsxs(G,{className:"flex flex-row items-center justify-between gap-2",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx(W,{children:t("settings.files.title")}),e.jsx("p",{className:"text-sm text-muted-foreground",children:t("settings.files.description")})]}),e.jsxs(k,{variant:"secondary","data-testid":"settings-files-root-add",onClick:n,children:[e.jsx(xe,{className:"h-4 w-4"}),t("settings.files.addRoot")]})]}),e.jsxs(H,{className:"space-y-3",children:[h.isLoading&&e.jsx("div",{className:"text-sm text-muted-foreground",children:t("common.loading")}),!h.isLoading&&f.length===0&&e.jsx("div",{className:"text-sm text-muted-foreground","data-testid":"settings-files-empty",children:t("settings.files.empty")}),f.map(d=>e.jsx(ls,{root:d,onEdit:i},d.id))]})]}),e.jsx(cs,{open:o,onOpenChange:s,root:l,devices:a})]})}function ls({root:t,onEdit:o}){const{t:s}=F(),l=O(),[c,h]=y.useState(!1),p=M({mutationFn:({id:a,enabled:n})=>ht(a,{enabled:n}),onSuccess:async()=>{await l.invalidateQueries({queryKey:["files"]})},onError:()=>{b.error(s("settings.files.toggleFailed"))}}),f=M({mutationFn:a=>Qt(a),onSuccess:async()=>{await l.invalidateQueries({queryKey:["files"]}),b.success(s("common.success"))},onError:a=>{const n=a instanceof He?a.message:s("settings.files.deleteFailed");b.error(n)}});return e.jsxs("div",{className:"flex items-center gap-3 rounded-lg border border-border p-3","data-testid":`settings-files-root-${t.id}`,children:[e.jsx(_,{checked:t.enabled,disabled:p.isPending,onCheckedChange:a=>p.mutate({id:t.id,enabled:!!a}),"data-testid":`settings-files-root-enabled-${t.id}`}),e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsxs("div",{className:"flex items-center gap-1.5 text-xs text-muted-foreground",children:[e.jsx($e,{type:t.deviceType,className:"h-3.5 w-3.5 shrink-0"}),t.deviceName===null?e.jsx("span",{className:"text-destructive",children:s("settings.files.missing")}):e.jsx("span",{className:"truncate",children:t.deviceName})]}),e.jsx("div",{className:"truncate font-mono text-xs",children:t.path}),e.jsx("div",{className:"truncate text-xs text-muted-foreground",children:t.name})]}),e.jsxs("div",{className:"flex shrink-0 items-center gap-1",children:[e.jsx(k,{variant:"ghost",size:"icon-sm",title:s("common.edit"),"data-testid":`settings-files-root-edit-${t.id}`,onClick:()=>o(t),children:e.jsx(Oe,{className:"h-4 w-4"})}),e.jsx(k,{variant:"ghost",size:"icon-sm",title:s("common.delete"),"data-testid":`settings-files-root-delete-${t.id}`,onClick:()=>h(!0),disabled:f.isPending,children:e.jsx(te,{className:"h-4 w-4 text-destructive"})})]}),e.jsx(fe,{open:c,onOpenChange:h,children:e.jsxs(pe,{children:[e.jsxs(we,{children:[e.jsx(At,{className:"bg-destructive/10",children:e.jsx(te,{className:"h-5 w-5 text-destructive"})}),e.jsx(ye,{children:s("settings.files.deleteTitle")}),e.jsx(je,{children:s("settings.files.deleteDesc",{path:t.path})})]}),e.jsxs(ve,{children:[e.jsx(be,{children:s("common.cancel")}),e.jsx(Ne,{variant:"destructive","data-testid":`settings-files-root-delete-confirm-${t.id}`,onClick:()=>{f.mutate(t.id),h(!1)},children:s("common.delete")})]})]})})]})}const st="h-9 w-full";function cs({open:t,onOpenChange:o,root:s,devices:l}){const{t:c}=F(),h=O(),p=!!s,[f,a]=y.useState(""),[n,i]=y.useState(""),[r,m]=y.useState(!0);y.useEffect(()=>{t&&(a((s==null?void 0:s.deviceId)??""),i((s==null?void 0:s.path)??""),m((s==null?void 0:s.enabled)??!0))},[t,s]);const d=M({mutationFn:()=>{const E={deviceId:f,path:n.trim(),enabled:r};return Ut(E)},onSuccess:async()=>{await h.invalidateQueries({queryKey:["files"]}),b.success(c("common.success")),o(!1)},onError:E=>{const z=E instanceof He?E.message:c("settings.files.addFailed");b.error(z)}}),u=M({mutationFn:()=>{if(!s)throw new Error(c("settings.files.updateFailed"));const E={path:n.trim(),enabled:r};return ht(s.id,E)},onSuccess:async()=>{await h.invalidateQueries({queryKey:["files"]}),b.success(c("common.success")),o(!1)},onError:E=>{const z=E instanceof He?E.message:c("settings.files.updateFailed");b.error(z)}}),w=d.isPending||u.isPending,C=n.trim().startsWith("/")&&(p||f.length>0),x=()=>{!C||w||(p?u.mutate():d.mutate())},N=l.find(E=>E.id===f);return e.jsx(ae,{open:t,onOpenChange:o,children:e.jsxs(ne,{className:"sm:max-w-lg","data-testid":p?`settings-files-edit-modal-${s==null?void 0:s.id}`:"settings-files-add-modal",children:[e.jsxs(ie,{children:[e.jsx(re,{children:c(p?"settings.files.modalEditTitle":"settings.files.modalAddTitle")}),e.jsx(Ce,{children:c("settings.files.description")})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"space-y-1.5",children:[e.jsx("label",{className:"block text-sm font-medium",htmlFor:"files-form-device",children:c("settings.files.device")}),p?e.jsxs("div",{className:"flex h-9 items-center gap-1.5 rounded-lg border border-input bg-muted/30 px-2.5 text-sm",children:[e.jsx($e,{type:(s==null?void 0:s.deviceType)??null,className:"h-4 w-4 shrink-0"}),e.jsx("span",{className:"truncate",children:(s==null?void 0:s.deviceName)??c("settings.files.missing")})]}):e.jsxs(Ee,{value:f,onValueChange:E=>{E&&a(E)},children:[e.jsx(ke,{id:"files-form-device","data-testid":"settings-files-device-select",className:st,disabled:l.length===0,children:e.jsx(Se,{children:N?e.jsxs("span",{className:"flex items-center gap-1.5",children:[e.jsx($e,{type:N.type,className:"h-4 w-4 shrink-0"}),N.name]}):e.jsx("span",{className:"text-muted-foreground",children:c("settings.files.devicePlaceholder")})})}),e.jsx(Me,{children:l.map(E=>e.jsxs(le,{value:E.id,children:[e.jsx($e,{type:E.type,className:"h-4 w-4 shrink-0"}),E.name]},E.id))})]}),!p&&l.length===0&&e.jsx("p",{className:"text-xs text-destructive",children:c("settings.files.noDevices")})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx("label",{className:"block text-sm font-medium",htmlFor:"files-form-path",children:c("settings.files.path")}),e.jsx(D,{id:"files-form-path","data-testid":"settings-files-path-input",value:n,onChange:E=>i(E.target.value),placeholder:c("settings.files.pathPlaceholder"),className:`${st} font-mono`}),e.jsx("p",{className:"text-xs text-muted-foreground",children:c("settings.files.pathHint")})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(_,{checked:r,onCheckedChange:E=>m(!!E),"data-testid":"settings-files-enabled-switch"}),e.jsx("label",{className:"text-sm font-medium",htmlFor:"settings-files-enabled-switch",children:c("settings.files.enabled")})]})]}),e.jsxs(de,{children:[e.jsx(k,{variant:"outline",onClick:()=>o(!1),disabled:w,children:c("common.cancel")}),e.jsxs(k,{variant:"secondary","data-testid":"settings-files-form-submit",onClick:x,disabled:!C||w,children:[w?e.jsx(Q,{className:"h-4 w-4 animate-spin"}):e.jsx(ee,{className:"h-4 w-4"}),c("common.save")]})]})]})})}async function Z(t,o){try{return(await t.json()).error??o}catch{return o}}const ds=["openai-chat","openai-responses"],Re="h-9 w-full";function ms({open:t,onOpenChange:o,provider:s}){const{t:l}=F(),c=O(),h=!!s,[p,f]=y.useState(""),[a,n]=y.useState(""),[i,r]=y.useState("openai-chat"),[m,d]=y.useState("");y.useEffect(()=>{t&&(f((s==null?void 0:s.name)??""),n((s==null?void 0:s.baseUrl)??""),r((s==null?void 0:s.protocol)??"openai-chat"),d(""))},[t,s]);const u=M({mutationFn:async()=>{const x={name:p.trim(),protocol:i,baseUrl:a.trim(),apiKey:m.trim(),enabled:!0},N=await fetch("/api/llm/providers",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(x)});if(!N.ok)throw new Error(await Z(N,l("settings.llm.createFailed")));return await N.json()},onSuccess:async x=>{await c.invalidateQueries({queryKey:["llm-providers"]}),x.modelsError?b.warning(l("settings.llm.modelsFetchFailed",{error:x.modelsError})):b.success(l("common.success")),o(!1)},onError:x=>{b.error(x instanceof Error?x.message:l("common.error"))}}),w=M({mutationFn:async()=>{if(!s)throw new Error(l("settings.llm.updateFailed"));const x={name:p.trim(),baseUrl:a.trim(),protocol:i};m.trim()&&(x.apiKey=m.trim());const N=await fetch(`/api/llm/providers/${s.id}`,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify(x)});if(!N.ok)throw new Error(await Z(N,l("settings.llm.updateFailed")));return await N.json()},onSuccess:async x=>{await c.invalidateQueries({queryKey:["llm-providers"]}),x.modelsError?b.warning(l("settings.llm.modelsFetchFailed",{error:x.modelsError})):b.success(l("common.success")),o(!1)},onError:x=>{b.error(x instanceof Error?x.message:l("common.error"))}}),j=u.isPending||w.isPending,g=p.trim().length>0&&a.trim().length>0&&(h||m.trim().length>0),C=()=>{!g||j||(h?w.mutate():u.mutate())};return e.jsx(ae,{open:t,onOpenChange:o,children:e.jsxs(ne,{className:"sm:max-w-lg","data-testid":h?`llm-provider-edit-modal-${s==null?void 0:s.id}`:"llm-provider-add-modal",children:[e.jsxs(ie,{children:[e.jsx(re,{children:l(h?"settings.llm.editProvider":"settings.llm.addProvider")}),e.jsx(Ce,{children:l("settings.llm.formHint")})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"space-y-1.5",children:[e.jsx("label",{className:"block text-sm font-medium",htmlFor:"llm-form-name",children:l("settings.llm.name")}),e.jsx(D,{id:"llm-form-name","data-testid":"llm-provider-name-input",value:p,onChange:x=>f(x.target.value),placeholder:l("settings.llm.namePlaceholder"),className:Re})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx("label",{className:"block text-sm font-medium",htmlFor:"llm-form-baseurl",children:l("settings.llm.baseUrl")}),e.jsx(D,{id:"llm-form-baseurl","data-testid":"llm-provider-baseurl-input",value:a,onChange:x=>n(x.target.value),placeholder:l("settings.llm.baseUrlPlaceholder"),className:Re}),e.jsx("p",{className:"text-xs text-muted-foreground",children:l("settings.llm.baseUrlHint")})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx("label",{className:"block text-sm font-medium",htmlFor:"llm-form-protocol",children:l("settings.llm.protocol")}),e.jsxs(Ee,{value:i,onValueChange:x=>{x&&r(x)},children:[e.jsx(ke,{id:"llm-form-protocol","data-testid":"llm-provider-protocol-select",className:Re,children:e.jsx(Se,{})}),e.jsx(Me,{children:ds.map(x=>e.jsx(le,{value:x,children:x},x))})]})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx("label",{className:"block text-sm font-medium",htmlFor:"llm-form-apikey",children:l("settings.llm.apiKey")}),e.jsx(D,{id:"llm-form-apikey","data-testid":"llm-provider-apikey-input","data-key-set":s!=null&&s.hasApiKey?"true":"false",type:"password",value:m,onChange:x=>d(x.target.value),placeholder:s!=null&&s.hasApiKey?l("settings.llm.apiKeySetPlaceholder"):l("settings.llm.apiKeyPlaceholder"),className:Re})]})]}),e.jsxs(de,{children:[e.jsx(k,{variant:"outline",onClick:()=>o(!1),disabled:j,children:l("common.cancel")}),e.jsxs(k,{variant:"secondary","data-testid":"llm-provider-form-submit",onClick:C,disabled:!g||j,children:[j?e.jsx(Q,{className:"h-4 w-4 animate-spin"}):e.jsx(ee,{className:"h-4 w-4"}),l("common.save")]})]})]})})}function us({models:t,onChange:o}){const{t:s}=F(),[l,c]=y.useState(""),h=(a,n)=>{o(t.map(i=>i.id===a?{...i,enabled:n}:i))},p=a=>{o(t.filter(n=>n.id!==a))},f=()=>{const a=l.trim();if(a){if(t.some(n=>n.id===a)){c("");return}o([...t,{id:a,source:"manual",enabled:!0}]),c("")}};return e.jsxs("div",{className:"space-y-3","data-testid":"llm-provider-models",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(D,{value:l,onChange:a=>c(a.target.value),onKeyDown:a=>{a.key==="Enter"&&(a.preventDefault(),f())},placeholder:s("settings.llm.addModelPlaceholder"),className:"h-9","data-testid":"llm-provider-add-model-input"}),e.jsxs(k,{type:"button",variant:"outline",size:"lg",onClick:f,disabled:!l.trim(),"data-testid":"llm-provider-add-model",children:[e.jsx(xe,{className:"h-4 w-4"}),s("common.add")]})]}),t.length===0?e.jsx("p",{className:"text-xs text-muted-foreground",children:s("settings.llm.modelsNotFetched")}):e.jsx("ul",{className:"max-h-56 space-y-1 overflow-y-auto rounded-lg border border-border bg-background p-2",children:t.map(a=>e.jsxs("li",{className:"flex items-center justify-between gap-2 rounded-md px-2 py-1.5","data-testid":`llm-provider-model-${a.id}`,children:[e.jsxs("div",{className:"flex min-w-0 items-center gap-2",children:[e.jsx(_,{checked:a.enabled,onCheckedChange:n=>h(a.id,!!n),"data-testid":`llm-provider-model-toggle-${a.id}`}),e.jsx("span",{className:"truncate font-mono text-xs",children:a.id}),a.source==="manual"&&e.jsx(dt,{variant:"secondary",children:s("settings.llm.modelManual")})]}),a.source==="manual"&&e.jsx(k,{type:"button",variant:"ghost",size:"icon-sm",onClick:()=>p(a.id),"data-testid":`llm-provider-model-remove-${a.id}`,children:e.jsx(Rt,{className:"h-4 w-4"})})]},a.id))})]})}function hs(t){return t.modelDetails.map(o=>({id:o.id,source:o.source,enabled:o.enabled}))}function gs({open:t,onOpenChange:o,provider:s}){const{t:l}=F(),c=O(),[h,p]=y.useState([]);y.useEffect(()=>{t&&p(hs(s))},[t,s]);const f=M({mutationFn:async()=>{const a=h.filter(m=>m.source==="manual").map(m=>m.id),n=h.filter(m=>!m.enabled).map(m=>m.id),i={manualModels:a,disabledModels:n},r=await fetch(`/api/llm/providers/${s.id}`,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)});if(!r.ok)throw new Error(await Z(r,l("settings.llm.updateFailed")));return await r.json()},onSuccess:async a=>{await c.invalidateQueries({queryKey:["llm-providers"]}),a.modelsError?b.warning(l("settings.llm.modelsFetchFailed",{error:a.modelsError})):b.success(l("common.success")),o(!1)},onError:a=>{b.error(a instanceof Error?a.message:l("common.error"))}});return e.jsx(ae,{open:t,onOpenChange:o,children:e.jsxs(ne,{className:"sm:max-w-lg","data-testid":`llm-provider-models-modal-${s.id}`,children:[e.jsxs(ie,{children:[e.jsx(re,{children:l("settings.llm.modelsTitle",{name:s.name})}),e.jsx(Ce,{children:l("settings.llm.modelsHint")})]}),e.jsx(us,{models:h,onChange:p}),e.jsxs(de,{children:[e.jsx(k,{variant:"outline",onClick:()=>o(!1),disabled:f.isPending,children:l("common.cancel")}),e.jsxs(k,{variant:"secondary","data-testid":`llm-provider-models-save-${s.id}`,onClick:()=>f.mutate(),disabled:f.isPending,children:[f.isPending?e.jsx(Q,{className:"h-4 w-4 animate-spin"}):e.jsx(ee,{className:"h-4 w-4"}),l("common.save")]})]})]})})}function xs(t){try{const o=new URL(t);return`${o.protocol}//${o.host}${o.pathname==="/"?"":o.pathname}`}catch{return t}}function fs({provider:t,onEdit:o}){const{t:s}=F(),l=O(),[c,h]=y.useState(!1),[p,f]=y.useState(!1),a=M({mutationFn:async r=>{const m=await fetch(`/api/llm/providers/${t.id}`,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({enabled:r})});if(!m.ok)throw new Error(await Z(m,s("settings.llm.updateFailed")))},onSuccess:async()=>{await l.invalidateQueries({queryKey:["llm-providers"]})},onError:r=>{b.error(r instanceof Error?r.message:s("common.error"))}}),n=M({mutationFn:async()=>{const r=await fetch(`/api/llm/providers/${t.id}/refresh-models`,{method:"POST"});if(!r.ok)throw new Error(await Z(r,s("settings.llm.refreshModelsFailed")))},onSuccess:async()=>{await l.invalidateQueries({queryKey:["llm-providers"]}),b.success(s("common.success"))},onError:r=>{b.error(r instanceof Error?r.message:s("common.error"))}}),i=M({mutationFn:async()=>{const r=await fetch(`/api/llm/providers/${t.id}`,{method:"DELETE"});if(!r.ok)throw new Error(await Z(r,s("settings.llm.deleteFailed")))},onSuccess:async()=>{await l.invalidateQueries({queryKey:["llm-providers"]}),await l.invalidateQueries({queryKey:["llm-settings"]}),b.success(s("common.success"))},onError:r=>{b.error(r instanceof Error?r.message:s("common.error"))}});return e.jsxs("div",{className:"flex flex-col gap-3 rounded-lg border border-border bg-card p-3 sm:flex-row sm:items-center sm:justify-between","data-testid":`llm-provider-row-${t.id}`,"data-provider-name":t.name,children:[e.jsxs("div",{className:"flex min-w-0 items-center gap-3",children:[e.jsx(_,{checked:t.enabled,disabled:a.isPending,onCheckedChange:r=>a.mutate(!!r),"data-testid":`llm-provider-enabled-${t.id}`}),e.jsxs("div",{className:"min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"truncate font-medium",children:t.name}),e.jsx(dt,{variant:"outline",children:t.protocol})]}),e.jsxs("div",{className:"flex items-center gap-2 text-xs text-muted-foreground",children:[e.jsx("span",{className:"truncate font-mono",children:xs(t.baseUrl)}),e.jsx("span",{"aria-hidden":!0,children:"·"}),e.jsx("span",{className:"whitespace-nowrap",children:s("settings.llm.modelsCount",{total:t.models.length})})]})]})]}),e.jsxs("div",{className:"flex shrink-0 items-center gap-1",children:[e.jsx(k,{variant:"ghost",size:"icon-sm",title:s("settings.llm.refreshModels"),"data-testid":`llm-provider-refresh-models-${t.id}`,onClick:()=>n.mutate(),disabled:n.isPending,children:n.isPending?e.jsx(Q,{className:"h-4 w-4 animate-spin"}):e.jsx(Ze,{className:"h-4 w-4"})}),e.jsx(k,{variant:"ghost",size:"icon-sm",title:s("settings.llm.models"),"data-testid":`llm-provider-models-${t.id}`,onClick:()=>f(!0),children:e.jsx(Xt,{className:"h-4 w-4"})}),e.jsx(k,{variant:"ghost",size:"icon-sm",title:s("common.edit"),"data-testid":`llm-provider-edit-${t.id}`,onClick:()=>o(t),children:e.jsx(Oe,{className:"h-4 w-4"})}),e.jsx(k,{variant:"ghost",size:"icon-sm",title:s("common.delete"),"data-testid":`llm-provider-delete-${t.id}`,onClick:()=>h(!0),disabled:i.isPending,children:e.jsx(te,{className:"h-4 w-4 text-destructive"})})]}),e.jsx(gs,{open:p,onOpenChange:f,provider:t}),e.jsx(fe,{open:c,onOpenChange:h,children:e.jsxs(pe,{children:[e.jsxs(we,{children:[e.jsx(ye,{children:s("settings.llm.deleteProvider")}),e.jsx(je,{children:s("settings.llm.deleteConfirm",{name:t.name})})]}),e.jsxs(ve,{children:[e.jsx(be,{onClick:()=>h(!1),children:s("common.cancel")}),e.jsx(Ne,{variant:"destructive","data-testid":`llm-provider-delete-confirm-${t.id}`,onClick:()=>{i.mutate(),h(!1)},children:s("common.confirm")})]})]})})]})}function ps(){var n;const{t}=F(),[o,s]=y.useState(!1),[l,c]=y.useState(void 0),h=K({queryKey:["llm-providers"],queryFn:async()=>{const i=await fetch("/api/llm/providers");if(!i.ok)throw new Error(await Z(i,t("settings.llm.loadFailed")));return await i.json()}}),p=((n=h.data)==null?void 0:n.providers)??[],f=()=>{c(void 0),s(!0)},a=i=>{c(i),s(!0)};return e.jsxs(e.Fragment,{children:[e.jsxs(U,{className:"border-0 ring-0","data-testid":"llm-providers-section",children:[e.jsxs(G,{className:"flex flex-row items-center justify-between gap-2",children:[e.jsx(W,{children:t("settings.llm.title")}),e.jsxs(k,{variant:"secondary","data-testid":"llm-provider-add",onClick:f,children:[e.jsx(xe,{className:"h-4 w-4"}),t("settings.llm.addProvider")]})]}),e.jsxs(H,{className:"space-y-3",children:[h.isLoading&&e.jsx("div",{className:"text-sm text-muted-foreground",children:t("common.loading")}),!h.isLoading&&p.length===0&&e.jsx("div",{className:"text-sm text-muted-foreground","data-testid":"llm-providers-empty",children:t("settings.llm.empty")}),p.map(i=>e.jsx(fs,{provider:i,onEdit:a},i.id))]})]}),e.jsx(ms,{open:o,onOpenChange:s,provider:l}),e.jsx(ws,{providers:p})]})}const Be="__none__";function ws({providers:t}){var w,j;const{t:o}=F(),s=O(),[l,c]=y.useState(null),[h,p]=y.useState(""),f=K({queryKey:["llm-settings"],queryFn:async()=>{const g=await fetch("/api/llm/settings");if(!g.ok)throw new Error(await Z(g,o("settings.llm.settingsLoadFailed")));return await g.json()}}),a=((w=f.data)==null?void 0:w.settings.defaultProviderId)??null,n=((j=f.data)==null?void 0:j.settings.defaultModelId)??"",i=!!f.data;y.useEffect(()=>{i&&(c(a),p(n))},[i,a,n]);const r=M({mutationFn:async()=>{const g={defaultProviderId:l,defaultModelId:h.trim()||null},C=await fetch("/api/llm/settings",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify(g)});if(!C.ok)throw new Error(await Z(C,o("settings.llm.settingsSaveFailed")))},onSuccess:async()=>{await s.invalidateQueries({queryKey:["llm-settings"]}),b.success(o("common.success"))},onError:g=>{b.error(g instanceof Error?g.message:o("common.error"))}}),m=t.filter(g=>g.enabled),d=t.find(g=>g.id===l),u=(d==null?void 0:d.models)??[];return e.jsxs(U,{className:"border-0 ring-0","data-testid":"llm-defaults-section",children:[e.jsx(G,{children:e.jsx(W,{children:o("settings.llm.defaults")})}),e.jsxs(H,{className:"space-y-6",children:[e.jsxs("div",{className:"grid grid-cols-1 gap-4 md:grid-cols-2",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx("label",{className:"block text-sm font-medium",htmlFor:"llm-default-provider-select",children:o("settings.llm.defaultProvider")}),e.jsxs(Ee,{value:l??Be,onValueChange:g=>{g&&c(g===Be?null:g)},children:[e.jsx(ke,{id:"llm-default-provider-select","data-testid":"llm-default-provider-select",className:"h-9 w-full",children:e.jsx(Se,{children:(d==null?void 0:d.name)??o("settings.llm.defaultProviderNone")})}),e.jsxs(Me,{children:[e.jsx(le,{value:Be,children:o("settings.llm.defaultProviderNone")}),m.map(g=>e.jsx(le,{value:g.id,children:g.name},g.id))]})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx("label",{className:"block text-sm font-medium",htmlFor:"llm-default-model-input",children:o("settings.llm.defaultModel")}),e.jsx(D,{id:"llm-default-model-input","data-testid":"llm-default-model-input",list:"llm-default-model-options",value:h,onChange:g=>p(g.target.value),placeholder:o("settings.llm.defaultModelPlaceholder"),className:"h-9"}),e.jsx("datalist",{id:"llm-default-model-options",children:u.map(g=>e.jsx("option",{value:g},g))})]})]}),e.jsx("div",{className:"flex justify-end",children:e.jsxs(k,{variant:"secondary","data-testid":"llm-defaults-save",onClick:()=>r.mutate(),disabled:r.isPending||f.isLoading,className:"w-full sm:w-auto",children:[r.isPending?e.jsx(Q,{className:"h-4 w-4 animate-spin"}):e.jsx(ee,{className:"h-4 w-4"}),o("settings.llm.saveDefaults")]})})]})]})}const ys=["none","tavily","brave"];async function _e(t,o){try{return(await t.json()).error??o}catch{return o}}function js(){var j;const{t}=F(),o=O(),[s,l]=y.useState("none"),[c,h]=y.useState(""),[p,f]=y.useState(""),[a,n]=y.useState(null),i=K({queryKey:["llm-settings"],queryFn:async()=>{const g=await fetch("/api/llm/settings");if(!g.ok)throw new Error(await _e(g,t("settings.search.loadFailed")));return await g.json()}}),r=(j=i.data)==null?void 0:j.settings,m=r==null?void 0:r.searchProvider;y.useEffect(()=>{m&&l(m)},[m]);const d=M({mutationFn:async()=>{const g={searchProvider:s};c.trim()&&(g.tavilyApiKey=c.trim()),p.trim()&&(g.braveApiKey=p.trim());const C=await fetch("/api/llm/settings",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify(g)});if(!C.ok)throw new Error(await _e(C,t("settings.search.saveFailed")))},onSuccess:async()=>{h(""),f(""),await o.invalidateQueries({queryKey:["llm-settings"]}),b.success(t("common.success"))},onError:g=>{b.error(g instanceof Error?g.message:t("common.error"))}}),u=M({mutationFn:async g=>{const C={[g]:""},x=await fetch("/api/llm/settings",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify(C)});if(!x.ok)throw new Error(await _e(x,t("settings.search.saveFailed")))},onSuccess:async()=>{await o.invalidateQueries({queryKey:["llm-settings"]}),b.success(t("common.success"))},onError:g=>{b.error(g instanceof Error?g.message:t("common.error"))}}),w=g=>g==="none"?t("settings.search.providerNone"):g==="tavily"?"Tavily":"Brave";return e.jsxs(U,{className:"border-0 ring-0","data-testid":"settings-search-section",children:[e.jsx(G,{children:e.jsx(W,{children:t("settings.search.title")})}),e.jsxs(H,{className:"space-y-6",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx("label",{className:"block text-sm font-medium",htmlFor:"search-provider-select",children:t("settings.search.provider")}),e.jsxs(Ee,{value:s,onValueChange:g=>{g&&l(g)},children:[e.jsx(ke,{id:"search-provider-select","data-testid":"settings-search-provider-select",className:"w-full min-h-10",children:e.jsx(Se,{children:w(s)})}),e.jsx(Me,{children:ys.map(g=>e.jsx(le,{value:g,children:w(g)},g))})]}),e.jsx("p",{className:"text-xs text-muted-foreground",children:t("settings.search.responsesApiHint")})]}),e.jsx(at,{id:"search-tavily-key-input",testId:"settings-search-tavily",label:t("settings.search.tavilyApiKey"),value:c,hasKey:(r==null?void 0:r.hasTavilyApiKey)??!1,onChange:h,onClear:()=>n("tavilyApiKey"),clearing:u.isPending&&u.variables==="tavilyApiKey"}),e.jsx(at,{id:"search-brave-key-input",testId:"settings-search-brave",label:t("settings.search.braveApiKey"),value:p,hasKey:(r==null?void 0:r.hasBraveApiKey)??!1,onChange:f,onClear:()=>n("braveApiKey"),clearing:u.isPending&&u.variables==="braveApiKey"}),e.jsx(fe,{open:a!==null,onOpenChange:g=>{g||n(null)},children:e.jsxs(pe,{children:[e.jsxs(we,{children:[e.jsx(ye,{children:t("settings.search.clearKey")}),e.jsx(je,{children:t("settings.search.clearKeyConfirm")})]}),e.jsxs(ve,{children:[e.jsx(be,{children:t("common.cancel")}),e.jsx(Ne,{"data-testid":"settings-search-clear-confirm",onClick:()=>{a&&u.mutate(a),n(null)},children:t("settings.search.clearKey")})]})]})}),e.jsx("div",{className:"flex justify-end",children:e.jsxs(k,{variant:"secondary","data-testid":"settings-search-save",onClick:()=>d.mutate(),disabled:d.isPending||i.isLoading,className:"w-full sm:w-auto",children:[d.isPending?e.jsx(Q,{className:"h-4 w-4 animate-spin"}):e.jsx(ee,{className:"h-4 w-4"}),t("common.save")]})})]})]})}function at({id:t,testId:o,label:s,value:l,hasKey:c,onChange:h,onClear:p,clearing:f}){const{t:a}=F();return e.jsxs("div",{className:"space-y-2",children:[e.jsx("label",{className:"block text-sm font-medium",htmlFor:t,children:s}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(D,{id:t,"data-testid":`${o}-input`,"data-key-set":c?"true":"false",type:"password",value:l,onChange:n=>h(n.target.value),placeholder:a(c?"settings.search.keySetPlaceholder":"settings.search.keyPlaceholder"),className:"min-h-10"}),c&&e.jsxs(k,{variant:"outline",size:"sm","data-testid":`${o}-clear`,onClick:p,disabled:f,className:"shrink-0",children:[e.jsx(te,{className:"h-4 w-4"}),a("settings.search.clearKey")]})]})]})}const nt="min-h-10";async function it(t,o){try{return(await t.json()).error??o}catch{return o}}function vs({open:t,onOpenChange:o,bot:s}){const{t:l}=F(),c=O(),h=!!s,[p,f]=y.useState(""),[a,n]=y.useState(""),[i,r]=y.useState(!0);y.useEffect(()=>{t&&(f((s==null?void 0:s.name)??""),n(""),r((s==null?void 0:s.allowAuthRequests)??!0))},[t,s]);const m=M({mutationFn:async()=>{const g=await fetch("/api/settings/telegram/bots",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:p.trim(),token:a.trim(),enabled:!0,allowAuthRequests:i})});if(!g.ok)throw new Error(await it(g,l("telegram.createFailed")))},onSuccess:async()=>{await c.invalidateQueries({queryKey:["telegram-bots"]}),b.success(l("common.success")),o(!1)},onError:g=>{b.error(g instanceof Error?g.message:l("common.error"))}}),d=M({mutationFn:async()=>{if(!s)throw new Error(l("telegram.updateFailed"));const g={name:p.trim(),allowAuthRequests:i};a.trim()&&(g.token=a.trim());const C=await fetch(`/api/settings/telegram/bots/${s.id}`,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify(g)});if(!C.ok)throw new Error(await it(C,l("telegram.updateFailed")))},onSuccess:async()=>{await c.invalidateQueries({queryKey:["telegram-bots"]}),b.success(l("common.success")),o(!1)},onError:g=>{b.error(g instanceof Error?g.message:l("common.error"))}}),u=m.isPending||d.isPending,w=p.trim().length>0&&(h||a.trim().length>0),j=()=>{!w||u||(h?d.mutate():m.mutate())};return e.jsx(ae,{open:t,onOpenChange:o,children:e.jsxs(ne,{className:"sm:max-w-lg","data-testid":h?`telegram-bot-edit-modal-${s==null?void 0:s.id}`:"telegram-bot-add-modal",children:[e.jsx(ie,{children:e.jsx(re,{children:l(h?"telegram.editBot":"telegram.addBot")})}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"space-y-1.5",children:[e.jsx("label",{className:"block text-sm font-medium",htmlFor:"telegram-bot-name",children:l("telegram.botName")}),e.jsx(D,{id:"telegram-bot-name","data-testid":"telegram-bot-name-input",value:p,onChange:g=>f(g.target.value),placeholder:l("telegram.botNamePlaceholder"),className:nt})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx("label",{className:"block text-sm font-medium",htmlFor:"telegram-bot-token",children:l("telegram.botToken")}),e.jsx(D,{id:"telegram-bot-token","data-testid":"telegram-bot-token-input",type:"password",value:a,onChange:g=>n(g.target.value),placeholder:l(h?"telegram.tokenPlaceholder":"telegram.botTokenPlaceholder"),className:nt})]}),e.jsxs("div",{className:"flex min-h-10 items-center justify-between gap-3 rounded-lg border border-border bg-background px-3 py-2.5",children:[e.jsx("span",{className:"text-sm font-medium",children:l("telegram.allowAuthRequests")}),e.jsx(_,{checked:i,"data-testid":"telegram-bot-allow-auth",onCheckedChange:g=>r(!!g)})]})]}),e.jsxs(de,{children:[e.jsx(k,{variant:"outline",onClick:()=>o(!1),disabled:u,children:l("common.cancel")}),e.jsxs(k,{variant:"secondary","data-testid":"telegram-bot-form-submit",onClick:j,disabled:!w||u,children:[u?e.jsx(Q,{className:"h-4 w-4 animate-spin"}):e.jsx(ee,{className:"h-4 w-4"}),l("common.save")]})]})]})})}async function Ie(t,o){try{return(await t.json()).error??o}catch{return o}}function bs({open:t,onOpenChange:o,botId:s,botName:l}){var m;const{t:c}=F(),h=O(),p=K({queryKey:["telegram-bot-chats",s],enabled:t,queryFn:async()=>{const d=await fetch(`/api/settings/telegram/bots/${s}/chats`);if(!d.ok)throw new Error(await Ie(d,c("telegram.loadChatsFailed")));return await d.json()}}),f=y.useMemo(()=>{var u;const d=((u=p.data)==null?void 0:u.chats)??[];return{pending:d.filter(w=>w.status==="pending"),authorized:d.filter(w=>w.status==="authorized")}},[(m=p.data)==null?void 0:m.chats]),a=async()=>{await Promise.all([h.invalidateQueries({queryKey:["telegram-bots"]}),h.invalidateQueries({queryKey:["telegram-bot-chats",s]})])},n=M({mutationFn:async d=>{const u=await fetch(`/api/settings/telegram/bots/${s}/chats/${encodeURIComponent(d)}/approve`,{method:"POST"});if(!u.ok)throw new Error(await Ie(u,c("telegram.approveFailed")))},onSuccess:async()=>{await a(),b.success(c("common.success"))},onError:d=>{b.error(d instanceof Error?d.message:c("common.error"))}}),i=M({mutationFn:async d=>{const u=await fetch(`/api/settings/telegram/bots/${s}/chats/${encodeURIComponent(d)}`,{method:"DELETE"});if(!u.ok)throw new Error(await Ie(u,c("telegram.removeFailed")))},onSuccess:async()=>{await a(),b.success(c("common.success"))},onError:d=>{b.error(d instanceof Error?d.message:c("common.error"))}}),r=M({mutationFn:async d=>{const u=await fetch(`/api/settings/telegram/bots/${s}/chats/${encodeURIComponent(d)}/test`,{method:"POST"});if(!u.ok)throw new Error(await Ie(u,c("telegram.testMessageFailed")))},onSuccess:()=>{b.success(c("common.success"))},onError:d=>{b.error(d instanceof Error?d.message:c("common.error"))}});return e.jsx(ae,{open:t,onOpenChange:o,children:e.jsxs(ne,{className:"sm:max-w-2xl","data-testid":`telegram-bot-chats-modal-${s}`,children:[e.jsxs(ie,{children:[e.jsx(re,{children:c("telegram.chats")}),e.jsx(Ce,{children:l})]}),e.jsxs("div",{className:"grid grid-cols-1 gap-4 lg:grid-cols-2",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsxs("h3",{className:"flex items-center gap-1 text-sm font-semibold",children:[e.jsx(tt,{className:"h-4 w-4"}),c("telegram.pendingChats")]}),f.pending.length===0&&e.jsx("div",{className:"text-xs text-muted-foreground",children:c("telegram.noPendingChats")}),f.pending.map(d=>e.jsx(rt,{chat:d,pending:!0,onApprove:()=>n.mutate(d.chatId),onDelete:()=>i.mutate(d.chatId)},`${d.botId}-${d.chatId}`))]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs("h3",{className:"flex items-center gap-1 text-sm font-semibold",children:[e.jsx(tt,{className:"h-4 w-4"}),c("telegram.chats")]}),f.authorized.length===0&&e.jsx("div",{className:"text-xs text-muted-foreground",children:c("telegram.noAuthorizedChats")}),f.authorized.map(d=>e.jsx(rt,{chat:d,pending:!1,onTest:()=>r.mutate(d.chatId),onDelete:()=>i.mutate(d.chatId)},`${d.botId}-${d.chatId}`))]}),p.isLoading&&e.jsx("div",{className:"text-xs text-muted-foreground lg:col-span-2",children:c("common.loading")})]})]})})}function rt({chat:t,pending:o,onApprove:s,onDelete:l,onTest:c}){const{t:h}=F(),p=ge(f=>{var a;return((a=f.settings)==null?void 0:a.language)??"en_US"});return e.jsxs("div",{className:"space-y-2 rounded border-0 bg-background p-3",children:[e.jsx("div",{className:"truncate text-sm font-medium",title:t.displayName,children:t.displayName}),e.jsxs("div",{className:"text-xs text-muted-foreground",children:[h("telegram.chatId"),":",t.chatId]}),e.jsx("div",{className:"text-xs text-muted-foreground",children:new Date(t.appliedAt).toLocaleString(Xe(p))}),e.jsx("div",{className:"flex items-center justify-end gap-2 pt-1",children:o?e.jsxs(e.Fragment,{children:[e.jsx(k,{variant:"outline",size:"sm",onClick:l,children:h("telegram.reject")}),e.jsx(k,{variant:"secondary",size:"sm",onClick:s,children:h("telegram.authorize")})]}):e.jsxs(e.Fragment,{children:[e.jsxs(k,{variant:"secondary",size:"sm",onClick:c,children:[e.jsx(gt,{className:"h-3.5 w-3.5"}),h("telegram.sendTestMessage")]}),e.jsx(k,{variant:"destructive",size:"sm",onClick:l,children:h("common.delete")})]})})]})}async function ot(t,o){try{return(await t.json()).error??o}catch{return o}}function Ns({bot:t,onEdit:o}){const{t:s}=F(),l=O(),[c,h]=y.useState(!1),p=M({mutationFn:async a=>{const n=await fetch(`/api/settings/telegram/bots/${t.id}`,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({enabled:a})});if(!n.ok)throw new Error(await ot(n,s("telegram.updateFailed")))},onSuccess:async()=>{await l.invalidateQueries({queryKey:["telegram-bots"]})},onError:a=>{b.error(a instanceof Error?a.message:s("common.error"))}}),f=M({mutationFn:async()=>{const a=await fetch(`/api/settings/telegram/bots/${t.id}`,{method:"DELETE"});if(!a.ok)throw new Error(await ot(a,s("telegram.deleteFailed")))},onSuccess:async()=>{await l.invalidateQueries({queryKey:["telegram-bots"]}),b.success(s("common.success"))},onError:a=>{b.error(a instanceof Error?a.message:s("common.error"))}});return e.jsxs("div",{className:"flex flex-col gap-3 rounded-lg border border-border bg-card p-3 sm:flex-row sm:items-center sm:justify-between","data-testid":`telegram-bot-card-${t.id}`,"data-bot-name":t.name,children:[e.jsxs("div",{className:"flex min-w-0 items-center gap-3",children:[e.jsx(_,{checked:t.enabled,disabled:p.isPending,onCheckedChange:a=>p.mutate(!!a),"data-testid":`telegram-bot-enabled-${t.id}`}),e.jsxs("div",{className:"min-w-0",children:[e.jsx("div",{className:"truncate font-medium",children:t.name}),e.jsx("div",{className:"text-xs text-muted-foreground",children:s("telegram.authCount",{authorized:t.authorizedCount,pending:t.pendingCount})})]})]}),e.jsxs("div",{className:"flex shrink-0 items-center gap-1",children:[e.jsx(k,{variant:"ghost",size:"icon-sm",title:s("telegram.chats"),"data-testid":`telegram-bot-chats-${t.id}`,onClick:()=>h(!0),children:e.jsx(is,{className:"h-4 w-4"})}),e.jsx(k,{variant:"ghost",size:"icon-sm",title:s("common.edit"),"data-testid":`telegram-bot-edit-${t.id}`,onClick:()=>o(t),children:e.jsx(Oe,{className:"h-4 w-4"})}),e.jsx(k,{variant:"ghost",size:"icon-sm",title:s("telegram.deleteBot"),"data-testid":`telegram-bot-delete-${t.id}`,onClick:()=>f.mutate(),disabled:f.isPending,children:e.jsx(te,{className:"h-4 w-4 text-destructive"})})]}),e.jsx(bs,{open:c,onOpenChange:h,botId:t.id,botName:t.name})]})}async function Cs(t,o){try{return(await t.json()).error??o}catch{return o}}function Es(){var n;const{t}=F(),[o,s]=y.useState(!1),[l,c]=y.useState(void 0),h=K({queryKey:["telegram-bots"],queryFn:async()=>{const i=await fetch("/api/settings/telegram/bots");if(!i.ok)throw new Error(await Cs(i,t("telegram.loadBotsFailed")));return await i.json()}}),p=((n=h.data)==null?void 0:n.bots)??[],f=()=>{c(void 0),s(!0)},a=i=>{c(i),s(!0)};return e.jsxs(e.Fragment,{children:[e.jsxs(U,{className:"border-0 ring-0",children:[e.jsxs(G,{className:"flex flex-row items-center justify-between gap-2",children:[e.jsx(W,{children:t("telegram.title")}),e.jsxs(k,{variant:"secondary","data-testid":"telegram-add-bot",onClick:f,children:[e.jsx(xe,{className:"h-4 w-4"}),t("telegram.addBot")]})]}),e.jsxs(H,{className:"space-y-3",children:[h.isLoading&&e.jsx("div",{className:"text-sm text-muted-foreground",children:t("common.loading")}),!h.isLoading&&p.length===0&&e.jsx("div",{className:"text-sm text-muted-foreground",children:t("telegram.noBots")}),p.map(i=>e.jsx(Ns,{bot:i,onEdit:a},i.id))]})]}),e.jsx(vs,{open:o,onOpenChange:s,bot:l})]})}function ks(){const{t}=F();return e.jsxs("div",{className:"space-y-4",children:[e.jsxs(U,{className:"border-0 ring-0",children:[e.jsx(G,{children:e.jsx(W,{children:t("settings.terminal.title")})}),e.jsx(H,{children:e.jsx(Vt,{showShortcuts:!1})})]}),e.jsxs(U,{className:"border-0 ring-0",children:[e.jsxs(G,{children:[e.jsx(W,{children:t("settings.terminal.shortcuts.title")}),e.jsx(ut,{children:t("settings.terminal.shortcuts.savedOnServer")})]}),e.jsx(H,{children:e.jsx(Gt,{})})]})]})}async function ze(t,o){try{return(await t.json()).error??o}catch{return o}}function qe({label:t,value:o}){return e.jsxs("div",{className:"flex min-h-10 items-center justify-between gap-4 rounded-lg border border-border bg-card px-4 py-2.5",children:[e.jsx("div",{className:"min-w-0 pr-2 text-sm font-medium",children:t}),e.jsx("div",{className:"min-w-0 truncate text-right text-sm text-muted-foreground",children:o})]})}function Ss(){const{t}=F(),o=O(),s=ge(x=>{var N;return((N=x.settings)==null?void 0:N.language)??"en_US"}),[l,c]=y.useState(!1),[h,p]=y.useState(!1),f=y.useRef(!1),n=K({queryKey:["system-info"],queryFn:async()=>{const x=await fetch("/api/system/info");if(!x.ok)throw new Error(await ze(x,t("settings.loadFailed")));return await x.json()}}).data,i=K({queryKey:["system-update-check"],enabled:!1,gcTime:0,queryFn:async()=>{const x=await fetch("/api/system/update-check");if(!x.ok)throw new Error(await ze(x,t("settings.version.checkFailed")));return await x.json()}}),r=i.data,d=K({queryKey:["system-upgrade-status"],enabled:h,refetchInterval:x=>{var E;const N=(E=x.state.data)==null?void 0:E.state;return h||N&&N!=="idle"?2e3:!1},retry:!0,queryFn:async()=>{const x=await fetch("/api/system/upgrade");if(!x.ok)throw new Error("status");return await x.json()}}).data;y.useEffect(()=>{if(!h)return;const x=d==null?void 0:d.state;x&&x!=="idle"?f.current=!0:x==="idle"&&(d!=null&&d.error)?(f.current=!1,p(!1),b.error(d.error)):x==="idle"&&f.current&&(f.current=!1,p(!1),o.invalidateQueries({queryKey:["system-info"]}),o.removeQueries({queryKey:["system-update-check"]}),b.success(t("common.success")))},[h,d,o,t]);const u=M({mutationFn:async x=>{const N=await fetch("/api/system/upgrade",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({version:x})});if(!N.ok)throw new Error(await ze(N,t("common.error")));return await N.json()},onSuccess:x=>{f.current=!1,p(!0),o.setQueryData(["system-upgrade-status"],x),b.success(t("settings.version.upgradeStarted"))},onError:x=>{b.error(x instanceof Error?x.message:t("common.error"))}}),w=x=>t(x==="launchd"?"settings.version.deploymentLaunchd":x==="systemd"?"settings.version.deploymentSystemd":"settings.version.deploymentNone"),j=h&&(d==null?void 0:d.state)!==void 0,g=(d==null?void 0:d.state)==="downloading"?t("settings.version.stateDownloading"):(d==null?void 0:d.state)==="executing"?t("settings.version.stateExecuting"):null,C=n!=null&&n.canSelfUpdate?null:n!=null&&n.isProd?n!=null&&n.installedViaCli?null:t("settings.version.upgradeDisabledNonCli"):t("settings.version.upgradeDisabledDev");return e.jsxs(U,{className:"border-0 ring-0",children:[e.jsx(G,{children:e.jsx(W,{children:t("settings.version.title")})}),e.jsxs(H,{className:"space-y-6",children:[e.jsxs("div",{className:"space-y-3",children:[e.jsx(qe,{label:t("settings.version.currentVersion"),value:e.jsx("span",{"data-testid":"settings-version-current",className:"font-mono",children:n?n.version:t("common.loading")})}),e.jsx(qe,{label:t("settings.version.installMethod"),value:n?n.installedViaCli?t("settings.version.installMethodCli"):t("settings.version.installMethodNonCli"):"-"}),e.jsx(qe,{label:t("settings.version.deployment"),value:n?w(n.deployment):"-"})]}),e.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[e.jsxs(k,{variant:"outline","data-testid":"settings-version-check",onClick:()=>i.refetch(),disabled:i.isFetching||j,children:[i.isFetching?e.jsx(Q,{className:"h-4 w-4 animate-spin"}):e.jsx(Ze,{className:"h-4 w-4"}),i.isFetching?t("settings.version.checking"):t("settings.version.checkUpdate")]}),r&&e.jsxs("span",{className:"text-sm text-muted-foreground","data-testid":"settings-version-latest",children:[r.hasUpdate&&r.latestVersion?t("settings.version.updateAvailable",{version:r.latestVersion}):t("settings.version.upToDate"),r.publishedAt?` · ${t("settings.version.publishedAt",{date:new Date(r.publishedAt).toLocaleDateString(Xe(s))})}`:""]})]}),i.isError&&e.jsx("div",{className:"text-sm text-destructive",children:t("settings.version.checkFailed")}),(r==null?void 0:r.hasUpdate)&&e.jsxs("div",{className:"space-y-3",children:[e.jsx("div",{className:"text-sm font-semibold",children:t("settings.version.changelog")}),e.jsx("div",{className:"rounded-lg border border-border bg-card px-4 py-3",children:r.changelog?e.jsx(Jt,{source:r.changelog,basePath:"/"}):e.jsx("div",{className:"text-sm text-muted-foreground",children:t("settings.version.changelogUnavailable")})}),n!=null&&n.canSelfUpdate?e.jsxs(k,{variant:"secondary","data-testid":"settings-version-upgrade",disabled:j||u.isPending,onClick:()=>c(!0),children:[j?e.jsx(Q,{className:"h-4 w-4 animate-spin"}):e.jsx(Ht,{className:"h-4 w-4"}),t("settings.version.upgrade")]}):e.jsxs("div",{className:"space-y-1",children:[C&&e.jsx("div",{className:"text-sm text-muted-foreground",children:C}),e.jsx("div",{className:"text-xs text-muted-foreground font-mono",children:t("settings.version.terminalHint")})]})]}),j&&g&&e.jsxs("div",{className:"flex items-start gap-2 rounded-lg border border-border bg-card px-4 py-3","data-testid":"settings-version-upgrade-status",children:[e.jsx(Q,{className:"mt-0.5 h-4 w-4 shrink-0 animate-spin text-primary"}),e.jsxs("div",{className:"space-y-1",children:[e.jsx("div",{className:"text-sm font-medium",children:g}),e.jsx("div",{className:"text-xs text-muted-foreground",children:t("settings.version.interruptNotice")})]})]})]}),e.jsx(fe,{open:l,onOpenChange:c,children:e.jsxs(pe,{children:[e.jsxs(we,{children:[e.jsxs(ye,{className:"flex items-center gap-2",children:[e.jsx(xt,{className:"h-5 w-5 text-destructive"}),t("settings.version.upgradeWarningTitle")]}),e.jsx(je,{children:t("settings.version.upgradeWarningBody")})]}),e.jsxs(ve,{children:[e.jsx(be,{onClick:()=>c(!1),children:t("common.cancel")}),e.jsx(Ne,{variant:"destructive","data-testid":"settings-version-upgrade-confirm",onClick:()=>{c(!1),r!=null&&r.latestVersion&&u.mutate(r.latestVersion)},children:t("settings.version.upgrade")})]})]})})]})}const Ke=["terminal_bell","terminal_notification","tmux_window_close","tmux_pane_close","device_tmux_missing","device_disconnect","session_created","session_closed","agent_confirmation_pending","agent_turn_finished","agent_error","watch_triggered","watch_model_unavailable","watch_rule_error"];async function Qe(t,o){try{return(await t.json()).error??o}catch{return o}}function Ms(){var d;const{t}=F(),o=O(),s=ge(u=>{var w;return((w=u.settings)==null?void 0:w.language)??"en_US"}),[l,c]=y.useState(""),[h,p]=y.useState(""),[f,a]=y.useState(Ke),n=K({queryKey:["webhooks"],queryFn:async()=>{const u=await fetch("/api/webhooks");if(!u.ok)throw new Error(await Qe(u,t("webhook.loadFailed")));return await u.json()}}),i=M({mutationFn:async()=>{const u=await fetch("/api/webhooks",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({url:l,secret:h,eventMask:f})});if(!u.ok)throw new Error(await Qe(u,t("webhook.createFailed")))},onSuccess:async()=>{c(""),p(""),a(Ke),await o.invalidateQueries({queryKey:["webhooks"]}),b.success(t("common.success"))},onError:u=>{b.error(u instanceof Error?u.message:t("common.error"))}}),r=M({mutationFn:async u=>{const w=await fetch(`/api/webhooks/${u}`,{method:"DELETE"});if(!w.ok)throw new Error(await Qe(w,t("webhook.deleteFailed")))},onSuccess:async()=>{await o.invalidateQueries({queryKey:["webhooks"]}),b.success(t("common.success"))},onError:u=>{b.error(u instanceof Error?u.message:t("common.error"))}}),m=((d=n.data)==null?void 0:d.webhooks)??[];return e.jsxs(U,{className:"border-0 ring-0",children:[e.jsx(G,{children:e.jsx(W,{children:t("webhook.title")})}),e.jsxs(H,{className:"space-y-6",children:[e.jsxs("div",{className:"grid grid-cols-1 gap-4 md:grid-cols-12 md:items-end",children:[e.jsxs("div",{className:"md:col-span-6 space-y-2",children:[e.jsx("label",{className:"block text-sm font-medium",htmlFor:"webhook-url-input",children:t("webhook.url")}),e.jsx(D,{id:"webhook-url-input","data-testid":"webhook-url-input",value:l,onChange:u=>c(u.target.value),placeholder:"https://example.com/webhook",className:"min-h-10"})]}),e.jsxs("div",{className:"md:col-span-4 space-y-2",children:[e.jsx("label",{className:"block text-sm font-medium",htmlFor:"webhook-secret-input",children:t("webhook.secret")}),e.jsx(D,{id:"webhook-secret-input","data-testid":"webhook-secret-input",value:h,onChange:u=>p(u.target.value),placeholder:t("webhook.secretPlaceholder"),className:"min-h-10"})]}),e.jsx("div",{className:"md:col-span-2",children:e.jsxs(k,{variant:"secondary",className:"w-full md:w-auto","data-testid":"webhook-add",onClick:()=>i.mutate(),disabled:i.isPending||!l.trim()||!h.trim()||f.length===0,children:[i.isPending?e.jsx(Q,{className:"h-4 w-4 animate-spin"}):e.jsx(ee,{className:"h-4 w-4"}),t("webhook.add")]})})]}),e.jsxs("div",{className:"space-y-3 rounded-lg border border-border bg-card px-4 py-3",children:[e.jsx("div",{className:"text-sm font-medium",children:t("webhook.eventMask")}),e.jsx("div",{className:"grid grid-cols-1 gap-3 sm:grid-cols-2",children:Ke.map(u=>{const w=f.includes(u);return e.jsxs("div",{className:"flex min-h-10 items-center justify-between gap-4 rounded-lg border border-border bg-background px-3 py-2",children:[e.jsx("div",{className:"min-w-0 pr-2 text-sm font-medium",children:t(`notification.eventType.${u}`)}),e.jsx(_,{checked:w,"data-testid":`webhook-event-${u}`,onCheckedChange:j=>{a(g=>j?g.includes(u)?g:[...g,u]:g.filter(C=>C!==u))}})]},u)})})]}),e.jsxs("div",{className:"space-y-2",children:[n.isLoading&&e.jsx("div",{className:"text-sm text-muted-foreground",children:t("common.loading")}),!n.isLoading&&m.length===0&&e.jsx("div",{className:"text-sm text-muted-foreground",children:t("webhook.empty")}),m.map(u=>e.jsxs("div",{"data-testid":"webhook-item","data-webhook-url":u.url,className:"flex items-center justify-between gap-3 rounded-lg border border-border bg-card px-4 py-2.5",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("div",{className:"truncate text-sm font-medium",children:u.url}),e.jsx("div",{className:"text-xs text-muted-foreground",children:new Date(u.createdAt).toLocaleString(Xe(s))})]}),e.jsx(k,{variant:"ghost",size:"icon-sm","data-testid":"webhook-delete",onClick:()=>r.mutate(u.id),disabled:r.isPending,"aria-label":t("common.delete"),title:t("common.delete"),children:e.jsx(te,{className:"h-4 w-4"})})]},u.id))]})]})]})}var Ps=Object.defineProperty,De=Object.getOwnPropertySymbols,ft=Object.prototype.hasOwnProperty,pt=Object.prototype.propertyIsEnumerable,lt=(t,o,s)=>o in t?Ps(t,o,{enumerable:!0,configurable:!0,writable:!0,value:s}):t[o]=s,Ge=(t,o)=>{for(var s in o||(o={}))ft.call(o,s)&&lt(t,s,o[s]);if(De)for(var s of De(o))pt.call(o,s)&&lt(t,s,o[s]);return t},We=(t,o)=>{var s={};for(var l in t)ft.call(t,l)&&o.indexOf(l)<0&&(s[l]=t[l]);if(t!=null&&De)for(var l of De(t))o.indexOf(l)<0&&pt.call(t,l)&&(s[l]=t[l]);return s};/**
32
- * @license QR Code generator library (TypeScript)
33
- * Copyright (c) Project Nayuki.
34
- * SPDX-License-Identifier: MIT
35
- */var se;(t=>{const o=class S{constructor(a,n,i,r){if(this.version=a,this.errorCorrectionLevel=n,this.modules=[],this.isFunction=[],a<S.MIN_VERSION||a>S.MAX_VERSION)throw new RangeError("Version value out of range");if(r<-1||r>7)throw new RangeError("Mask value out of range");this.size=a*4+17;let m=[];for(let u=0;u<this.size;u++)m.push(!1);for(let u=0;u<this.size;u++)this.modules.push(m.slice()),this.isFunction.push(m.slice());this.drawFunctionPatterns();const d=this.addEccAndInterleave(i);if(this.drawCodewords(d),r==-1){let u=1e9;for(let w=0;w<8;w++){this.applyMask(w),this.drawFormatBits(w);const j=this.getPenaltyScore();j<u&&(r=w,u=j),this.applyMask(w)}}c(0<=r&&r<=7),this.mask=r,this.applyMask(r),this.drawFormatBits(r),this.isFunction=[]}static encodeText(a,n){const i=t.QrSegment.makeSegments(a);return S.encodeSegments(i,n)}static encodeBinary(a,n){const i=t.QrSegment.makeBytes(a);return S.encodeSegments([i],n)}static encodeSegments(a,n,i=1,r=40,m=-1,d=!0){if(!(S.MIN_VERSION<=i&&i<=r&&r<=S.MAX_VERSION)||m<-1||m>7)throw new RangeError("Invalid value");let u,w;for(u=i;;u++){const x=S.getNumDataCodewords(u,n)*8,N=p.getTotalBits(a,u);if(N<=x){w=N;break}if(u>=r)throw new RangeError("Data too long")}for(const x of[S.Ecc.MEDIUM,S.Ecc.QUARTILE,S.Ecc.HIGH])d&&w<=S.getNumDataCodewords(u,x)*8&&(n=x);let j=[];for(const x of a){s(x.mode.modeBits,4,j),s(x.numChars,x.mode.numCharCountBits(u),j);for(const N of x.getData())j.push(N)}c(j.length==w);const g=S.getNumDataCodewords(u,n)*8;c(j.length<=g),s(0,Math.min(4,g-j.length),j),s(0,(8-j.length%8)%8,j),c(j.length%8==0);for(let x=236;j.length<g;x^=253)s(x,8,j);let C=[];for(;C.length*8<j.length;)C.push(0);return j.forEach((x,N)=>C[N>>>3]|=x<<7-(N&7)),new S(u,n,C,m)}getModule(a,n){return 0<=a&&a<this.size&&0<=n&&n<this.size&&this.modules[n][a]}getModules(){return this.modules}drawFunctionPatterns(){for(let i=0;i<this.size;i++)this.setFunctionModule(6,i,i%2==0),this.setFunctionModule(i,6,i%2==0);this.drawFinderPattern(3,3),this.drawFinderPattern(this.size-4,3),this.drawFinderPattern(3,this.size-4);const a=this.getAlignmentPatternPositions(),n=a.length;for(let i=0;i<n;i++)for(let r=0;r<n;r++)i==0&&r==0||i==0&&r==n-1||i==n-1&&r==0||this.drawAlignmentPattern(a[i],a[r]);this.drawFormatBits(0),this.drawVersion()}drawFormatBits(a){const n=this.errorCorrectionLevel.formatBits<<3|a;let i=n;for(let m=0;m<10;m++)i=i<<1^(i>>>9)*1335;const r=(n<<10|i)^21522;c(r>>>15==0);for(let m=0;m<=5;m++)this.setFunctionModule(8,m,l(r,m));this.setFunctionModule(8,7,l(r,6)),this.setFunctionModule(8,8,l(r,7)),this.setFunctionModule(7,8,l(r,8));for(let m=9;m<15;m++)this.setFunctionModule(14-m,8,l(r,m));for(let m=0;m<8;m++)this.setFunctionModule(this.size-1-m,8,l(r,m));for(let m=8;m<15;m++)this.setFunctionModule(8,this.size-15+m,l(r,m));this.setFunctionModule(8,this.size-8,!0)}drawVersion(){if(this.version<7)return;let a=this.version;for(let i=0;i<12;i++)a=a<<1^(a>>>11)*7973;const n=this.version<<12|a;c(n>>>18==0);for(let i=0;i<18;i++){const r=l(n,i),m=this.size-11+i%3,d=Math.floor(i/3);this.setFunctionModule(m,d,r),this.setFunctionModule(d,m,r)}}drawFinderPattern(a,n){for(let i=-4;i<=4;i++)for(let r=-4;r<=4;r++){const m=Math.max(Math.abs(r),Math.abs(i)),d=a+r,u=n+i;0<=d&&d<this.size&&0<=u&&u<this.size&&this.setFunctionModule(d,u,m!=2&&m!=4)}}drawAlignmentPattern(a,n){for(let i=-2;i<=2;i++)for(let r=-2;r<=2;r++)this.setFunctionModule(a+r,n+i,Math.max(Math.abs(r),Math.abs(i))!=1)}setFunctionModule(a,n,i){this.modules[n][a]=i,this.isFunction[n][a]=!0}addEccAndInterleave(a){const n=this.version,i=this.errorCorrectionLevel;if(a.length!=S.getNumDataCodewords(n,i))throw new RangeError("Invalid argument");const r=S.NUM_ERROR_CORRECTION_BLOCKS[i.ordinal][n],m=S.ECC_CODEWORDS_PER_BLOCK[i.ordinal][n],d=Math.floor(S.getNumRawDataModules(n)/8),u=r-d%r,w=Math.floor(d/r);let j=[];const g=S.reedSolomonComputeDivisor(m);for(let x=0,N=0;x<r;x++){let E=a.slice(N,N+w-m+(x<u?0:1));N+=E.length;const z=S.reedSolomonComputeRemainder(E,g);x<u&&E.push(0),j.push(E.concat(z))}let C=[];for(let x=0;x<j[0].length;x++)j.forEach((N,E)=>{(x!=w-m||E>=u)&&C.push(N[x])});return c(C.length==d),C}drawCodewords(a){if(a.length!=Math.floor(S.getNumRawDataModules(this.version)/8))throw new RangeError("Invalid argument");let n=0;for(let i=this.size-1;i>=1;i-=2){i==6&&(i=5);for(let r=0;r<this.size;r++)for(let m=0;m<2;m++){const d=i-m,w=(i+1&2)==0?this.size-1-r:r;!this.isFunction[w][d]&&n<a.length*8&&(this.modules[w][d]=l(a[n>>>3],7-(n&7)),n++)}}c(n==a.length*8)}applyMask(a){if(a<0||a>7)throw new RangeError("Mask value out of range");for(let n=0;n<this.size;n++)for(let i=0;i<this.size;i++){let r;switch(a){case 0:r=(i+n)%2==0;break;case 1:r=n%2==0;break;case 2:r=i%3==0;break;case 3:r=(i+n)%3==0;break;case 4:r=(Math.floor(i/3)+Math.floor(n/2))%2==0;break;case 5:r=i*n%2+i*n%3==0;break;case 6:r=(i*n%2+i*n%3)%2==0;break;case 7:r=((i+n)%2+i*n%3)%2==0;break;default:throw new Error("Unreachable")}!this.isFunction[n][i]&&r&&(this.modules[n][i]=!this.modules[n][i])}}getPenaltyScore(){let a=0;for(let m=0;m<this.size;m++){let d=!1,u=0,w=[0,0,0,0,0,0,0];for(let j=0;j<this.size;j++)this.modules[m][j]==d?(u++,u==5?a+=S.PENALTY_N1:u>5&&a++):(this.finderPenaltyAddHistory(u,w),d||(a+=this.finderPenaltyCountPatterns(w)*S.PENALTY_N3),d=this.modules[m][j],u=1);a+=this.finderPenaltyTerminateAndCount(d,u,w)*S.PENALTY_N3}for(let m=0;m<this.size;m++){let d=!1,u=0,w=[0,0,0,0,0,0,0];for(let j=0;j<this.size;j++)this.modules[j][m]==d?(u++,u==5?a+=S.PENALTY_N1:u>5&&a++):(this.finderPenaltyAddHistory(u,w),d||(a+=this.finderPenaltyCountPatterns(w)*S.PENALTY_N3),d=this.modules[j][m],u=1);a+=this.finderPenaltyTerminateAndCount(d,u,w)*S.PENALTY_N3}for(let m=0;m<this.size-1;m++)for(let d=0;d<this.size-1;d++){const u=this.modules[m][d];u==this.modules[m][d+1]&&u==this.modules[m+1][d]&&u==this.modules[m+1][d+1]&&(a+=S.PENALTY_N2)}let n=0;for(const m of this.modules)n=m.reduce((d,u)=>d+(u?1:0),n);const i=this.size*this.size,r=Math.ceil(Math.abs(n*20-i*10)/i)-1;return c(0<=r&&r<=9),a+=r*S.PENALTY_N4,c(0<=a&&a<=2568888),a}getAlignmentPatternPositions(){if(this.version==1)return[];{const a=Math.floor(this.version/7)+2,n=this.version==32?26:Math.ceil((this.version*4+4)/(a*2-2))*2;let i=[6];for(let r=this.size-7;i.length<a;r-=n)i.splice(1,0,r);return i}}static getNumRawDataModules(a){if(a<S.MIN_VERSION||a>S.MAX_VERSION)throw new RangeError("Version number out of range");let n=(16*a+128)*a+64;if(a>=2){const i=Math.floor(a/7)+2;n-=(25*i-10)*i-55,a>=7&&(n-=36)}return c(208<=n&&n<=29648),n}static getNumDataCodewords(a,n){return Math.floor(S.getNumRawDataModules(a)/8)-S.ECC_CODEWORDS_PER_BLOCK[n.ordinal][a]*S.NUM_ERROR_CORRECTION_BLOCKS[n.ordinal][a]}static reedSolomonComputeDivisor(a){if(a<1||a>255)throw new RangeError("Degree out of range");let n=[];for(let r=0;r<a-1;r++)n.push(0);n.push(1);let i=1;for(let r=0;r<a;r++){for(let m=0;m<n.length;m++)n[m]=S.reedSolomonMultiply(n[m],i),m+1<n.length&&(n[m]^=n[m+1]);i=S.reedSolomonMultiply(i,2)}return n}static reedSolomonComputeRemainder(a,n){let i=n.map(r=>0);for(const r of a){const m=r^i.shift();i.push(0),n.forEach((d,u)=>i[u]^=S.reedSolomonMultiply(d,m))}return i}static reedSolomonMultiply(a,n){if(a>>>8||n>>>8)throw new RangeError("Byte out of range");let i=0;for(let r=7;r>=0;r--)i=i<<1^(i>>>7)*285,i^=(n>>>r&1)*a;return c(i>>>8==0),i}finderPenaltyCountPatterns(a){const n=a[1];c(n<=this.size*3);const i=n>0&&a[2]==n&&a[3]==n*3&&a[4]==n&&a[5]==n;return(i&&a[0]>=n*4&&a[6]>=n?1:0)+(i&&a[6]>=n*4&&a[0]>=n?1:0)}finderPenaltyTerminateAndCount(a,n,i){return a&&(this.finderPenaltyAddHistory(n,i),n=0),n+=this.size,this.finderPenaltyAddHistory(n,i),this.finderPenaltyCountPatterns(i)}finderPenaltyAddHistory(a,n){n[0]==0&&(a+=this.size),n.pop(),n.unshift(a)}};o.MIN_VERSION=1,o.MAX_VERSION=40,o.PENALTY_N1=3,o.PENALTY_N2=3,o.PENALTY_N3=40,o.PENALTY_N4=10,o.ECC_CODEWORDS_PER_BLOCK=[[-1,7,10,15,20,26,18,20,24,30,18,20,24,26,30,22,24,28,30,28,28,28,28,30,30,26,28,30,30,30,30,30,30,30,30,30,30,30,30,30,30],[-1,10,16,26,18,24,16,18,22,22,26,30,22,22,24,24,28,28,26,26,26,26,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28],[-1,13,22,18,26,18,24,18,22,20,24,28,26,24,20,30,24,28,28,26,30,28,30,30,30,30,28,30,30,30,30,30,30,30,30,30,30,30,30,30,30],[-1,17,28,22,16,22,28,26,26,24,28,24,28,22,24,24,30,28,28,26,28,30,24,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30]],o.NUM_ERROR_CORRECTION_BLOCKS=[[-1,1,1,1,1,1,2,2,2,2,4,4,4,4,4,6,6,6,6,7,8,8,9,9,10,12,12,12,13,14,15,16,17,18,19,19,20,21,22,24,25],[-1,1,1,1,2,2,4,4,4,5,5,5,8,9,9,10,10,11,13,14,16,17,17,18,20,21,23,25,26,28,29,31,33,35,37,38,40,43,45,47,49],[-1,1,1,2,2,4,4,6,6,8,8,8,10,12,16,12,17,16,18,21,20,23,23,25,27,29,34,34,35,38,40,43,45,48,51,53,56,59,62,65,68],[-1,1,1,2,4,4,4,5,6,8,8,11,11,16,16,18,16,19,21,25,25,25,34,30,32,35,37,40,42,45,48,51,54,57,60,63,66,70,74,77,81]],t.QrCode=o;function s(f,a,n){if(a<0||a>31||f>>>a)throw new RangeError("Value out of range");for(let i=a-1;i>=0;i--)n.push(f>>>i&1)}function l(f,a){return(f>>>a&1)!=0}function c(f){if(!f)throw new Error("Assertion error")}const h=class R{constructor(a,n,i){if(this.mode=a,this.numChars=n,this.bitData=i,n<0)throw new RangeError("Invalid argument");this.bitData=i.slice()}static makeBytes(a){let n=[];for(const i of a)s(i,8,n);return new R(R.Mode.BYTE,a.length,n)}static makeNumeric(a){if(!R.isNumeric(a))throw new RangeError("String contains non-numeric characters");let n=[];for(let i=0;i<a.length;){const r=Math.min(a.length-i,3);s(parseInt(a.substring(i,i+r),10),r*3+1,n),i+=r}return new R(R.Mode.NUMERIC,a.length,n)}static makeAlphanumeric(a){if(!R.isAlphanumeric(a))throw new RangeError("String contains unencodable characters in alphanumeric mode");let n=[],i;for(i=0;i+2<=a.length;i+=2){let r=R.ALPHANUMERIC_CHARSET.indexOf(a.charAt(i))*45;r+=R.ALPHANUMERIC_CHARSET.indexOf(a.charAt(i+1)),s(r,11,n)}return i<a.length&&s(R.ALPHANUMERIC_CHARSET.indexOf(a.charAt(i)),6,n),new R(R.Mode.ALPHANUMERIC,a.length,n)}static makeSegments(a){return a==""?[]:R.isNumeric(a)?[R.makeNumeric(a)]:R.isAlphanumeric(a)?[R.makeAlphanumeric(a)]:[R.makeBytes(R.toUtf8ByteArray(a))]}static makeEci(a){let n=[];if(a<0)throw new RangeError("ECI assignment value out of range");if(a<128)s(a,8,n);else if(a<16384)s(2,2,n),s(a,14,n);else if(a<1e6)s(6,3,n),s(a,21,n);else throw new RangeError("ECI assignment value out of range");return new R(R.Mode.ECI,0,n)}static isNumeric(a){return R.NUMERIC_REGEX.test(a)}static isAlphanumeric(a){return R.ALPHANUMERIC_REGEX.test(a)}getData(){return this.bitData.slice()}static getTotalBits(a,n){let i=0;for(const r of a){const m=r.mode.numCharCountBits(n);if(r.numChars>=1<<m)return 1/0;i+=4+m+r.bitData.length}return i}static toUtf8ByteArray(a){a=encodeURI(a);let n=[];for(let i=0;i<a.length;i++)a.charAt(i)!="%"?n.push(a.charCodeAt(i)):(n.push(parseInt(a.substring(i+1,i+3),16)),i+=2);return n}};h.NUMERIC_REGEX=/^[0-9]*$/,h.ALPHANUMERIC_REGEX=/^[A-Z0-9 $%*+.\/:-]*$/,h.ALPHANUMERIC_CHARSET="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:";let p=h;t.QrSegment=h})(se||(se={}));(t=>{(o=>{const s=class{constructor(c,h){this.ordinal=c,this.formatBits=h}};s.LOW=new s(0,1),s.MEDIUM=new s(1,0),s.QUARTILE=new s(2,3),s.HIGH=new s(3,2),o.Ecc=s})(t.QrCode||(t.QrCode={}))})(se||(se={}));(t=>{(o=>{const s=class{constructor(c,h){this.modeBits=c,this.numBitsCharCount=h}numCharCountBits(c){return this.numBitsCharCount[Math.floor((c+7)/17)]}};s.NUMERIC=new s(1,[10,12,14]),s.ALPHANUMERIC=new s(2,[9,11,13]),s.BYTE=new s(4,[8,16,16]),s.KANJI=new s(8,[8,10,12]),s.ECI=new s(7,[0,0,0]),o.Mode=s})(t.QrSegment||(t.QrSegment={}))})(se||(se={}));var oe=se;/**
36
- * @license qrcode.react
37
- * Copyright (c) Paul O'Shannessy
38
- * SPDX-License-Identifier: ISC
39
- */var Fs={L:oe.QrCode.Ecc.LOW,M:oe.QrCode.Ecc.MEDIUM,Q:oe.QrCode.Ecc.QUARTILE,H:oe.QrCode.Ecc.HIGH},wt=128,yt="L",jt="#FFFFFF",vt="#000000",bt=!1,Nt=1,As=4,Ts=0,Rs=.1;function Ct(t,o=0){const s=[];return t.forEach(function(l,c){let h=null;l.forEach(function(p,f){if(!p&&h!==null){s.push(`M${h+o} ${c+o}h${f-h}v1H${h+o}z`),h=null;return}if(f===l.length-1){if(!p)return;h===null?s.push(`M${f+o},${c+o} h1v1H${f+o}z`):s.push(`M${h+o},${c+o} h${f+1-h}v1H${h+o}z`);return}p&&h===null&&(h=f)})}),s.join("")}function Et(t,o){return t.slice().map((s,l)=>l<o.y||l>=o.y+o.h?s:s.map((c,h)=>h<o.x||h>=o.x+o.w?c:!1))}function Is(t,o,s,l){if(l==null)return null;const c=t.length+s*2,h=Math.floor(o*Rs),p=c/o,f=(l.width||h)*p,a=(l.height||h)*p,n=l.x==null?t.length/2-f/2:l.x*p,i=l.y==null?t.length/2-a/2:l.y*p,r=l.opacity==null?1:l.opacity;let m=null;if(l.excavate){let u=Math.floor(n),w=Math.floor(i),j=Math.ceil(f+n-u),g=Math.ceil(a+i-w);m={x:u,y:w,w:j,h:g}}const d=l.crossOrigin;return{x:n,y:i,h:a,w:f,excavation:m,opacity:r,crossOrigin:d}}function Ls(t,o){return o!=null?Math.max(Math.floor(o),0):t?As:Ts}function kt({value:t,level:o,minVersion:s,includeMargin:l,marginSize:c,imageSettings:h,size:p,boostLevel:f}){let a=$.useMemo(()=>{const u=(Array.isArray(t)?t:[t]).reduce((w,j)=>(w.push(...oe.QrSegment.makeSegments(j)),w),[]);return oe.QrCode.encodeSegments(u,Fs[o],s,void 0,void 0,f)},[t,o,s,f]);const{cells:n,margin:i,numCells:r,calculatedImageSettings:m}=$.useMemo(()=>{let d=a.getModules();const u=Ls(l,c),w=d.length+u*2,j=Is(d,p,u,h);return{cells:d,margin:u,numCells:w,calculatedImageSettings:j}},[a,p,h,l,c]);return{qrcode:a,margin:i,cells:n,numCells:r,calculatedImageSettings:m}}var $s=(function(){try{new Path2D().addPath(new Path2D)}catch{return!1}return!0})(),Ds=$.forwardRef(function(o,s){const l=o,{value:c,size:h=wt,level:p=yt,bgColor:f=jt,fgColor:a=vt,includeMargin:n=bt,minVersion:i=Nt,boostLevel:r,marginSize:m,imageSettings:d}=l,w=We(l,["value","size","level","bgColor","fgColor","includeMargin","minVersion","boostLevel","marginSize","imageSettings"]),{style:j}=w,g=We(w,["style"]),C=d==null?void 0:d.src,x=$.useRef(null),N=$.useRef(null),E=$.useCallback(V=>{x.current=V,typeof s=="function"?s(V):s&&(s.current=V)},[s]),[z,P]=$.useState(!1),{margin:A,cells:T,numCells:I,calculatedImageSettings:L}=kt({value:c,level:p,minVersion:i,boostLevel:r,includeMargin:n,marginSize:m,imageSettings:d,size:h});$.useEffect(()=>{if(x.current!=null){const V=x.current,J=V.getContext("2d");if(!J)return;let Pe=T;const X=N.current,me=L!=null&&X!==null&&X.complete&&X.naturalHeight!==0&&X.naturalWidth!==0;me&&L.excavation!=null&&(Pe=Et(T,L.excavation));const Fe=window.devicePixelRatio||1;V.height=V.width=h*Fe;const ue=h/I*Fe;J.scale(ue,ue),J.fillStyle=f,J.fillRect(0,0,I,I),J.fillStyle=a,$s?J.fill(new Path2D(Ct(Pe,A))):T.forEach(function(Ae,Te){Ae.forEach(function(v,B){v&&J.fillRect(B+A,Te+A,1,1)})}),L&&(J.globalAlpha=L.opacity),me&&J.drawImage(X,L.x+A,L.y+A,L.w,L.h)}}),$.useEffect(()=>{P(!1)},[C]);const Y=Ge({height:h,width:h},j);let q=null;return C!=null&&(q=$.createElement("img",{src:C,key:C,style:{display:"none"},onLoad:()=>{P(!0)},ref:N,crossOrigin:L==null?void 0:L.crossOrigin})),$.createElement($.Fragment,null,$.createElement("canvas",Ge({style:Y,height:h,width:h,ref:E,role:"img"},g)),q)});Ds.displayName="QRCodeCanvas";var St=$.forwardRef(function(o,s){const l=o,{value:c,size:h=wt,level:p=yt,bgColor:f=jt,fgColor:a=vt,includeMargin:n=bt,minVersion:i=Nt,boostLevel:r,title:m,marginSize:d,imageSettings:u}=l,w=We(l,["value","size","level","bgColor","fgColor","includeMargin","minVersion","boostLevel","title","marginSize","imageSettings"]),{margin:j,cells:g,numCells:C,calculatedImageSettings:x}=kt({value:c,level:p,minVersion:i,boostLevel:r,includeMargin:n,marginSize:d,imageSettings:u,size:h});let N=g,E=null;u!=null&&x!=null&&(x.excavation!=null&&(N=Et(g,x.excavation)),E=$.createElement("image",{href:u.src,height:x.h,width:x.w,x:x.x+j,y:x.y+j,preserveAspectRatio:"none",opacity:x.opacity,crossOrigin:x.crossOrigin}));const z=Ct(N,j);return $.createElement("svg",Ge({height:h,width:h,viewBox:`0 0 ${C} ${C}`,ref:s,role:"img"},w),!!m&&$.createElement("title",null,m),$.createElement("path",{fill:f,d:`M0,0 h${C}v${C}H0z`,shapeRendering:"crispEdges"}),$.createElement("path",{fill:a,d:z,shapeRendering:"crispEdges"}),E)});St.displayName="QRCodeSVG";const Le=1500;async function he(t,o){try{return(await t.json()).error??o}catch{return o}}function Mt({open:t,onOpenChange:o,accountId:s,accountName:l}){const{t:c}=F(),h=O(),[p,f]=y.useState(null),[a,n]=y.useState("starting"),[i,r]=y.useState(null),m=y.useRef(null),d=y.useRef(0),u=y.useRef(null),w=y.useCallback(()=>{m.current!==null&&(clearTimeout(m.current),m.current=null)},[]),j=y.useCallback(()=>{var P;w(),(P=u.current)==null||P.abort(),u.current=null,d.current+=1},[w]),g=y.useCallback(async()=>{j(),await h.invalidateQueries({queryKey:["weixin-accounts"]}),b.success(c("weixin.bindSuccess")),o(!1)},[j,o,h,c]),C=y.useCallback(async(P,A,T)=>{try{const I=await fetch(`/api/settings/weixin/accounts/${s}/users`,{signal:A});if(d.current!==P)return;if(!I.ok)throw new Error(await he(I,c("weixin.loginFailed")));const L=await I.json();if(d.current!==P)return;const Y=L.users.find(q=>!T.has(q.userId)||q.lastInboundAt!==T.get(q.userId));if(Y){if(n("binding"),r(c("weixin.bindingInProgress")),Y.status==="pending"){const q=await fetch(`/api/settings/weixin/accounts/${s}/users/${encodeURIComponent(Y.userId)}/approve`,{method:"POST",signal:A});if(d.current!==P)return;if(!q.ok)throw new Error(await he(q,c("weixin.approveFailed")))}await g();return}m.current=setTimeout(()=>void C(P,A,T),Le)}catch(I){if(A.aborted||d.current!==P)return;n("error"),r(I instanceof Error?I.message:c("weixin.loginFailed"))}},[s,g,c]),x=y.useCallback(async(P,A)=>{try{const T=await fetch(`/api/settings/weixin/accounts/${s}/login/status`,{signal:A});if(d.current!==P)return;if(!T.ok)throw new Error(await he(T,c("weixin.loginFailed")));const I=await T.json();if(d.current!==P)return;if(I.status==="expired"){n("expired"),r(c("weixin.loginExpired"));return}if(I.status==="error"){n("error"),r(c("weixin.loginError",{message:I.message??""}));return}if(I.loggedIn||I.status==="confirmed"){const L=await fetch(`/api/settings/weixin/accounts/${s}/users`,{signal:A});if(d.current!==P)return;if(!L.ok)throw new Error(await he(L,c("weixin.loginFailed")));const Y=await L.json();if(d.current!==P)return;const q=new Map(Y.users.map(V=>[V.userId,V.lastInboundAt]));n("awaitMessage"),r(c("weixin.scanConfirmedSendHint")),m.current=setTimeout(()=>void C(P,A,q),Le);return}n("scanning"),r(c("weixin.scanQrcodeHint")),m.current=setTimeout(()=>void x(P,A),Le)}catch(T){if(A.aborted||d.current!==P)return;n("error"),r(T instanceof Error?T.message:c("weixin.loginFailed"))}},[s,C,c]),N=y.useCallback(async()=>{j();const P=d.current,A=new AbortController;u.current=A,n("starting"),r(null),f(null);try{const T=await fetch(`/api/settings/weixin/accounts/${s}/login/start`,{method:"POST",signal:A.signal});if(d.current!==P)return;if(!T.ok)throw new Error(await he(T,c("weixin.loginFailed")));const I=await T.json();if(d.current!==P)return;f(I.qrcodeUrl),n("scanning"),r(c("weixin.scanQrcodeHint")),m.current=setTimeout(()=>void x(P,A.signal),Le)}catch(T){if(A.signal.aborted||d.current!==P)return;n("error"),r(T instanceof Error?T.message:c("weixin.loginFailed"))}},[s,j,x,c]);y.useEffect(()=>{if(!t){j();return}return N(),j},[t,s]);const E=a==="starting",z=a==="expired"||a==="error";return e.jsx(ae,{open:t,onOpenChange:o,children:e.jsxs(ne,{className:"sm:max-w-sm","data-testid":`weixin-account-login-modal-${s}`,children:[e.jsxs(ie,{children:[e.jsx(re,{children:c("weixin.scanToLogin")}),e.jsx(Ce,{children:l})]}),e.jsxs("div",{className:"flex flex-col items-center gap-3 py-2",children:[e.jsxs("div",{className:"flex h-56 w-56 items-center justify-center rounded-lg border border-border bg-white",children:[E&&e.jsx(Q,{className:"h-8 w-8 animate-spin text-muted-foreground"}),!E&&p&&e.jsx(St,{value:p,size:208,marginSize:3,"data-testid":`weixin-account-login-qrcode-${s}`}),!E&&!p&&e.jsx(Ve,{className:"h-10 w-10 text-muted-foreground"})]}),i&&e.jsx("p",{className:"text-center text-sm font-medium","data-testid":`weixin-account-login-status-${s}`,children:i})]}),e.jsxs(de,{children:[z&&e.jsxs(k,{variant:"secondary","data-testid":"weixin-account-login-refresh",onClick:()=>void N(),children:[e.jsx(Ze,{className:"h-4 w-4"}),c("weixin.refreshQrcode")]}),e.jsx(k,{variant:"outline",onClick:()=>o(!1),children:c("weixin.closeLogin")})]})]})})}const Os="min-h-10";async function ct(t,o){try{return(await t.json()).error??o}catch{return o}}function Bs({open:t,onOpenChange:o,account:s}){const{t:l}=F(),c=O(),h=!!s,[p,f]=y.useState(""),[a,n]=y.useState(!0),[i,r]=y.useState(null);y.useEffect(()=>{t&&(f((s==null?void 0:s.name)??""),n((s==null?void 0:s.enabled)??!0))},[t,s]);const m=M({mutationFn:async()=>{const g=await fetch("/api/settings/weixin/accounts",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:p.trim(),enabled:a,allowAuthRequests:!0})});if(!g.ok)throw new Error(await ct(g,l("weixin.createFailed")));return await g.json()},onSuccess:async g=>{await c.invalidateQueries({queryKey:["weixin-accounts"]}),b.success(l("weixin.accountCreated")),o(!1),r({id:g.accountId,name:p.trim()})},onError:g=>{b.error(g instanceof Error?g.message:l("common.error"))}}),d=M({mutationFn:async()=>{if(!s)throw new Error(l("weixin.updateFailed"));const g=await fetch(`/api/settings/weixin/accounts/${s.id}`,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:p.trim(),enabled:a})});if(!g.ok)throw new Error(await ct(g,l("weixin.updateFailed")))},onSuccess:async()=>{await c.invalidateQueries({queryKey:["weixin-accounts"]}),b.success(l("weixin.accountUpdated")),o(!1)},onError:g=>{b.error(g instanceof Error?g.message:l("common.error"))}}),u=m.isPending||d.isPending,w=p.trim().length>0,j=()=>{!w||u||(h?d.mutate():m.mutate())};return e.jsxs(e.Fragment,{children:[e.jsx(ae,{open:t,onOpenChange:o,children:e.jsxs(ne,{className:"sm:max-w-lg","data-testid":h?`weixin-account-edit-modal-${s==null?void 0:s.id}`:"weixin-account-add-modal",children:[e.jsx(ie,{children:e.jsx(re,{children:l(h?"weixin.editAccount":"weixin.addAccount")})}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"space-y-1.5",children:[e.jsx("label",{className:"block text-sm font-medium",htmlFor:"weixin-account-name",children:l("weixin.accountName")}),e.jsx(D,{id:"weixin-account-name","data-testid":"weixin-account-name-input",value:p,onChange:g=>f(g.target.value),placeholder:l("weixin.accountNamePlaceholder"),className:Os})]}),e.jsxs("div",{className:"flex min-h-10 items-center justify-between gap-3 rounded-lg border border-border bg-background px-3 py-2.5",children:[e.jsx("span",{className:"text-sm font-medium",children:l("weixin.enableAccount")}),e.jsx(_,{checked:a,"data-testid":"weixin-account-enabled",onCheckedChange:g=>n(!!g)})]})]}),e.jsxs(de,{children:[e.jsx(k,{variant:"outline",onClick:()=>o(!1),disabled:u,children:l("common.cancel")}),e.jsxs(k,{variant:"secondary","data-testid":"weixin-account-form-submit",onClick:j,disabled:!w||u,children:[u?e.jsx(Q,{className:"h-4 w-4 animate-spin"}):e.jsx(ee,{className:"h-4 w-4"}),l("common.save")]})]})]})}),i&&e.jsx(Mt,{open:!!i,onOpenChange:g=>{g||r(null)},accountId:i.id,accountName:i.name})]})}async function Ue(t,o){try{return(await t.json()).error??o}catch{return o}}function _s({account:t,onEdit:o}){const{t:s}=F(),l=O(),[c,h]=y.useState(!1),p=t.loggedIn&&t.authorizedCount>0,f=M({mutationFn:async r=>{const m=await fetch(`/api/settings/weixin/accounts/${t.id}`,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({enabled:r})});if(!m.ok)throw new Error(await Ue(m,s("weixin.updateFailed")))},onSuccess:async()=>{await l.invalidateQueries({queryKey:["weixin-accounts"]})},onError:r=>{b.error(r instanceof Error?r.message:s("common.error"))}}),a=M({mutationFn:async()=>{const r=await fetch(`/api/settings/weixin/accounts/${t.id}/test`,{method:"POST"});if(!r.ok)throw new Error(await Ue(r,s("weixin.testMessageFailed")))},onSuccess:()=>{b.success(s("weixin.testMessageSent"))},onError:r=>{b.error(r instanceof Error?r.message:s("weixin.testMessageFailed"))}}),n=M({mutationFn:async()=>{const r=await fetch(`/api/settings/weixin/accounts/${t.id}`,{method:"DELETE"});if(!r.ok)throw new Error(await Ue(r,s("weixin.deleteFailed")))},onSuccess:async()=>{await l.invalidateQueries({queryKey:["weixin-accounts"]}),b.success(s("weixin.accountDeleted"))},onError:r=>{b.error(r instanceof Error?r.message:s("common.error"))}}),i=t.loggedIn?p?{label:s("weixin.bound"),tone:"success"}:{label:s("weixin.unbound"),tone:"muted"}:{label:s("weixin.notLoggedIn"),tone:"muted"};return e.jsxs("div",{className:"flex flex-col gap-3 rounded-lg border border-border bg-card p-3 sm:flex-row sm:items-center sm:justify-between","data-testid":`weixin-account-card-${t.id}`,"data-account-name":t.name,children:[e.jsxs("div",{className:"flex min-w-0 items-center gap-3",children:[e.jsx(_,{checked:t.enabled,disabled:f.isPending,onCheckedChange:r=>f.mutate(!!r),"data-testid":`weixin-account-enabled-${t.id}`}),e.jsxs("div",{className:"min-w-0",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("span",{className:"truncate font-medium",children:t.name}),e.jsx("span",{className:mt("shrink-0 rounded px-1.5 py-0.5 text-xs font-medium",i.tone==="success"?"bg-emerald-500/15 text-emerald-600 dark:text-emerald-400":"bg-muted text-muted-foreground"),"data-testid":`weixin-account-login-state-${t.id}`,children:i.label}),p&&t.needsReactivationCount>0&&e.jsxs("span",{className:"flex shrink-0 items-center gap-1 rounded bg-destructive/15 px-1.5 py-0.5 text-xs font-medium text-destructive",title:s("weixin.reactivationHint"),"data-testid":`weixin-account-needs-reactivation-${t.id}`,children:[e.jsx(xt,{className:"h-3.5 w-3.5"}),s("weixin.needsReactivation")]})]}),p&&t.needsReactivationCount>0&&e.jsx("div",{className:"mt-0.5 text-xs text-muted-foreground",children:s("weixin.reactivationHint")})]})]}),e.jsxs("div",{className:"flex shrink-0 flex-wrap items-center justify-end gap-1",children:[p?e.jsxs(e.Fragment,{children:[e.jsxs(k,{variant:"ghost",size:"sm","data-testid":`weixin-account-relogin-${t.id}`,onClick:()=>h(!0),children:[e.jsx(Ve,{className:"h-4 w-4"}),s("weixin.relogin")]}),e.jsxs(k,{variant:"ghost",size:"sm","data-testid":`weixin-account-test-${t.id}`,onClick:()=>a.mutate(),disabled:a.isPending,children:[e.jsx(gt,{className:"h-4 w-4"}),s("weixin.testMessage")]})]}):e.jsxs(k,{variant:"secondary",size:"sm","data-testid":`weixin-account-login-${t.id}`,onClick:()=>h(!0),children:[e.jsx(Ve,{className:"h-4 w-4"}),s("weixin.bindAction")]}),e.jsx(k,{variant:"ghost",size:"icon-sm",title:s("common.edit"),"data-testid":`weixin-account-edit-${t.id}`,onClick:()=>o(t),children:e.jsx(Oe,{className:"h-4 w-4"})}),e.jsx(k,{variant:"ghost",size:"icon-sm",title:s("weixin.deleteAccount"),"data-testid":`weixin-account-delete-${t.id}`,onClick:()=>n.mutate(),disabled:n.isPending,children:e.jsx(te,{className:"h-4 w-4 text-destructive"})})]}),e.jsx(Mt,{open:c,onOpenChange:h,accountId:t.id,accountName:t.name})]})}async function zs(t,o){try{return(await t.json()).error??o}catch{return o}}function qs(){var n;const{t}=F(),[o,s]=y.useState(!1),[l,c]=y.useState(void 0),h=K({queryKey:["weixin-accounts"],queryFn:async()=>{const i=await fetch("/api/settings/weixin/accounts");if(!i.ok)throw new Error(await zs(i,t("weixin.loadAccountsFailed")));return await i.json()}}),p=((n=h.data)==null?void 0:n.accounts)??[],f=()=>{c(void 0),s(!0)},a=i=>{c(i),s(!0)};return e.jsxs(e.Fragment,{children:[e.jsxs(U,{className:"border-0 ring-0",children:[e.jsxs(G,{className:"flex flex-row items-start justify-between gap-2",children:[e.jsxs("div",{className:"min-w-0 space-y-1",children:[e.jsx(W,{children:t("weixin.title")}),e.jsx("p",{className:"text-sm text-muted-foreground",children:t("weixin.subtitle")})]}),e.jsxs(k,{variant:"secondary","data-testid":"weixin-add-account",onClick:f,children:[e.jsx(xe,{className:"h-4 w-4"}),t("weixin.addAccount")]})]}),e.jsxs(H,{className:"space-y-3",children:[e.jsx("p",{className:"rounded-lg border border-border bg-muted/40 p-3 text-xs text-muted-foreground",children:t("weixin.replyOnlyNotice")}),h.isLoading&&e.jsx("div",{className:"text-sm text-muted-foreground",children:t("common.loading")}),!h.isLoading&&p.length===0&&e.jsx("div",{className:"text-sm text-muted-foreground",children:t("weixin.noAccounts")}),p.map(i=>e.jsx(_s,{account:i,onEdit:a},i.id))]})]}),e.jsx(Bs,{open:o,onOpenChange:s,account:l})]})}async function Je(t,o){try{return(await t.json()).error??o}catch{return o}}function ea(){var Ae,Te;const{t}=F(),o=O(),{refreshSettings:s}=ge(),[l,c]=y.useState("general"),h=It(v=>v.theme),p=ge(v=>v.updateTheme),f=h==="dark",[a,n]=y.useState("tmex"),[i,r]=y.useState(window.location.origin),[m,d]=y.useState("en_US"),[u,w]=y.useState(6),[j,g]=y.useState(3),[C,x]=y.useState(!0),[N,E]=y.useState(!0),[z,P]=y.useState(!0),[A,T]=y.useState(!0),[I,L]=y.useState(2),[Y,q]=y.useState(10),[V,J]=y.useState(!1),Pe=v=>{const B=v?"dark":"light";p(B),document.documentElement.classList.toggle("dark",B==="dark")},X=K({queryKey:["site-settings"],queryFn:async()=>{const v=await fetch("/api/settings/site");if(!v.ok)throw new Error(await Je(v,t("settings.loadFailed")));return await v.json()}});y.useEffect(()=>{var B;const v=(B=X.data)==null?void 0:B.settings;v&&(n(v.siteName),r(v.siteUrl),d(v.language??"en_US"),w(v.bellThrottleSeconds),g(v.notificationThrottleSeconds??3),x(v.enableBrowserNotificationToast??!0),E(v.enableNotificationPush??!0),P(v.enableBellPush??!0),T(v.enableBellSound??!0))},[(Ae=X.data)==null?void 0:Ae.settings]);const me=M({mutationFn:async()=>{const B=await fetch("/api/settings/site",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({siteName:a,siteUrl:i,language:m,bellThrottleSeconds:u,notificationThrottleSeconds:j,enableBrowserNotificationToast:C,enableNotificationPush:N,enableBellPush:z,enableBellSound:A,sshReconnectMaxRetries:I,sshReconnectDelaySeconds:Y})});if(!B.ok)throw new Error(await Je(B,t("settings.saveFailed")))},onSuccess:async()=>{var v,B;await Promise.all([o.invalidateQueries({queryKey:["site-settings"]}),s()]),b.success(t("settings.settingsSaved")),((B=(v=X.data)==null?void 0:v.settings)==null?void 0:B.language)!==m&&(qt.changeLanguage(m),J(!0))},onError:v=>{b.error(v instanceof Error?v.message:t("common.error"))}}),Fe=[{value:"general",label:t("settings.tabGroup.general"),icon:Lt,testId:"settings-tab-general"},{value:"terminal",label:t("settings.tabGroup.terminal"),icon:Ye,testId:"settings-tab-terminal"},{value:"devicesAndFiles",label:t("settings.tabGroup.devicesAndFiles"),icon:ss,testId:"settings-tab-devicesAndFiles"},{value:"notifications",label:t("settings.tabGroup.notifications"),icon:$t,testId:"settings-tab-notifications"},{value:"ai",label:t("settings.tabGroup.ai"),icon:Dt,testId:"settings-tab-ai"}],ue=e.jsx("div",{className:"flex justify-end pt-2",children:e.jsxs(k,{variant:"secondary","data-testid":"settings-save",onClick:()=>me.mutate(),disabled:me.isPending,className:"w-full sm:w-auto",children:[e.jsx(ee,{className:"h-4 w-4"}),t("common.save")]})});return e.jsxs("div",{className:"mx-auto flex w-full max-w-6xl flex-col gap-4 p-3 pb-[calc(2rem+env(safe-area-inset-bottom))] sm:gap-6 sm:p-5","data-testid":"settings-page",children:[e.jsx(Ot,{value:l,onValueChange:v=>c(v),children:e.jsx(Bt,{className:"w-full gap-1 !justify-start overflow-x-auto rounded-xl border border-border/60 p-1.5 group-data-horizontal/tabs:h-12 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",children:Fe.map(v=>{const B=v.icon;return e.jsxs(_t,{value:v.value,"data-testid":v.testId,className:mt(zt,"min-w-max gap-2 px-3.5"),children:[e.jsx(B,{}),v.label]},v.value)})})}),l==="general"&&e.jsxs(e.Fragment,{children:[e.jsxs(U,{className:"border-0 ring-0",children:[e.jsx(G,{children:e.jsx(W,{children:t("settings.siteSettings")})}),e.jsxs(H,{className:"space-y-6",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx("label",{className:"block text-sm font-medium",htmlFor:"site-name-input",children:t("settings.siteName")}),e.jsx(D,{id:"site-name-input",value:a,onChange:v=>n(v.target.value),placeholder:t("settings.siteNamePlaceholder"),className:"min-h-10"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx("label",{className:"block text-sm font-medium",htmlFor:"site-url-input",children:t("settings.siteUrl")}),e.jsx(D,{id:"site-url-input",value:i,onChange:v=>r(v.target.value),placeholder:t("settings.siteUrlPlaceholder"),className:"min-h-10"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx("label",{className:"block text-sm font-medium",htmlFor:"language-select",children:t("settings.language")}),e.jsxs(Ee,{value:m,onValueChange:v=>{v&&d(v)},children:[e.jsx(ke,{id:"language-select","data-testid":"settings-language-select",className:"w-full min-h-10",children:e.jsx(Se,{placeholder:t("settings.language"),children:((Te=et.locales.find(v=>v.code===m))==null?void 0:Te.nativeName)??m})}),e.jsx(Me,{className:"max-h-[var(--tmex-viewport-height)]",children:et.locales.map(v=>e.jsx(le,{value:v.code,children:v.nativeName},v.code))})]}),V&&e.jsx("p",{className:"mt-1 text-xs text-primary","data-testid":"settings-refresh-notice",children:t("settings.refreshToApply")})]}),e.jsx("div",{className:"space-y-3",children:e.jsxs("div",{className:"flex min-h-10 items-center justify-between gap-4 rounded-lg border border-border bg-card px-4 py-2.5",children:[e.jsx("div",{className:"min-w-0 pr-2",children:e.jsx("div",{className:"text-sm font-medium",children:t("settings.theme")})}),e.jsx(_,{checked:f,onCheckedChange:v=>Pe(!!v),"data-testid":"settings-theme-toggle"})]})}),ue]})]}),e.jsx(Ss,{})]}),l==="devicesAndFiles"&&e.jsxs(e.Fragment,{children:[e.jsx(rs,{}),e.jsx(os,{})]}),l==="notifications"&&e.jsxs(e.Fragment,{children:[e.jsx(U,{className:"border-0 ring-0",children:e.jsxs(H,{className:"space-y-6 pt-6",children:[e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{className:"flex min-h-10 items-center justify-between gap-4 rounded-lg border border-border bg-card px-4 py-2.5",children:[e.jsx("div",{className:"min-w-0 pr-2",children:e.jsx("div",{className:"text-sm font-medium",children:t("settings.enableNotificationPush")})}),e.jsx(_,{checked:N,onCheckedChange:v=>E(!!v),"data-testid":"settings-enable-notification-push"})]}),e.jsxs("div",{className:"flex min-h-10 items-center justify-between gap-4 rounded-lg border border-border bg-card px-4 py-2.5",children:[e.jsx("div",{className:"min-w-0 pr-2",children:e.jsx("div",{className:"text-sm font-medium",children:t("settings.enableBellPush")})}),e.jsx(_,{checked:z,onCheckedChange:v=>P(!!v),"data-testid":"settings-enable-bell-push"})]}),e.jsxs("div",{className:"flex min-h-10 items-center justify-between gap-4 rounded-lg border border-border bg-card px-4 py-2.5",children:[e.jsx("div",{className:"min-w-0 pr-2",children:e.jsx("div",{className:"text-sm font-medium",children:t("settings.enableBellSound")})}),e.jsx(_,{checked:A,onCheckedChange:v=>T(!!v),"data-testid":"settings-enable-bell-sound"})]}),e.jsxs("div",{className:"flex min-h-10 items-center justify-between gap-4 rounded-lg border border-border bg-card px-4 py-2.5",children:[e.jsx("div",{className:"min-w-0 pr-2",children:e.jsx("div",{className:"text-sm font-medium",children:t("settings.enableBrowserNotificationToast")})}),e.jsx(_,{checked:C,onCheckedChange:v=>x(!!v),"data-testid":"settings-enable-browser-notification-toast"})]})]}),e.jsxs("div",{className:"grid grid-cols-1 gap-4 sm:grid-cols-3",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx("label",{className:"block text-sm font-medium",htmlFor:"bell-throttle-input",children:t("settings.bellThrottle")}),e.jsx(D,{id:"bell-throttle-input",type:"number",value:u,min:0,max:300,onChange:v=>w(Number(v.target.value)),className:"min-h-10"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx("label",{className:"block text-sm font-medium",htmlFor:"notification-throttle-input",children:t("settings.notificationThrottle")}),e.jsx(D,{id:"notification-throttle-input",type:"number",value:j,min:0,max:300,onChange:v=>g(Number(v.target.value)),className:"min-h-10"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx("label",{className:"block text-sm font-medium",htmlFor:"ssh-reconnect-retries-input",children:t("settings.sshReconnectMaxRetries")}),e.jsx(D,{id:"ssh-reconnect-retries-input",type:"number",value:I,min:0,max:20,onChange:v=>L(Number(v.target.value)),className:"min-h-10"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx("label",{className:"block text-sm font-medium",htmlFor:"ssh-reconnect-delay-input",children:t("settings.sshReconnectDelay")}),e.jsx(D,{id:"ssh-reconnect-delay-input",type:"number",value:Y,min:1,max:300,onChange:v=>q(Number(v.target.value)),className:"min-h-10"})]})]}),ue]})}),e.jsx(Es,{}),e.jsx(qs,{}),e.jsx(Ms,{})]}),l==="ai"&&e.jsxs(e.Fragment,{children:[e.jsx(ps,{}),e.jsx(js,{})]}),l==="terminal"&&e.jsx(ks,{})]})}function ta(){const{t}=F();return e.jsx(e.Fragment,{children:t("sidebar.settings")})}function sa(){const{t}=F(),[o,s]=y.useState(!1),l=M({mutationFn:async()=>{const c=await fetch("/api/settings/restart",{method:"POST"});if(!c.ok)throw new Error(await Je(c,t("settings.restartFailed")))},onSuccess:()=>{b.success(t("settings.restartScheduled"))},onError:c=>{b.error(c instanceof Error?c.message:t("common.error"))}});return e.jsxs(e.Fragment,{children:[e.jsx(k,{variant:"ghost",size:"icon-sm",onClick:()=>s(!0),disabled:l.isPending,"aria-label":t("settings.restartGateway"),title:t("settings.restartGateway"),className:"text-destructive hover:text-destructive hover:bg-destructive/10",children:e.jsx(Wt,{className:"h-4 w-4"})}),e.jsx(fe,{open:o,onOpenChange:s,children:e.jsxs(pe,{children:[e.jsxs(we,{children:[e.jsx(ye,{children:t("settings.restartGateway")}),e.jsx(je,{children:t("settings.restartConfirm")})]}),e.jsxs(ve,{children:[e.jsx(be,{onClick:()=>s(!1),children:t("common.cancel")}),e.jsx(Ne,{variant:"destructive",onClick:()=>{l.mutate(),s(!1)},children:t("common.confirm")})]})]})})]})}export{sa as PageActions,ta as PageTitle,ea as default};
@@ -1,10 +0,0 @@
1
- var N=Object.defineProperty;var P=(t,e,o)=>e in t?N(t,e,{enumerable:!0,configurable:!0,writable:!0,value:o}):t[e]=o;var O=(t,e,o)=>P(t,typeof e!="symbol"?e+"":e,o);import{Y as x}from"./index-U4iZ6Kxr.js";/**
2
- * @license lucide-react v0.564.0 - ISC
3
- *
4
- * This source code is licensed under the ISC license.
5
- * See the LICENSE file in the root directory of this source tree.
6
- */const B=[["path",{d:"M12 15V3",key:"m9g1x1"}],["path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4",key:"ih7n3h"}],["path",{d:"m7 10 5 5 5-5",key:"brsn70"}]],H=x("download",B);function g(t){const e=new TextEncoder().encode(t);let o="";for(const n of e)o+=String.fromCharCode(n);return btoa(o).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}function I(t){const e=t.replace(/-/g,"+").replace(/_/g,"/"),o=e.length%4===0?"":"=".repeat(4-e.length%4),n=atob(e+o),a=new Uint8Array(n.length);for(let s=0;s<n.length;s++)a[s]=n.charCodeAt(s);return new TextDecoder().decode(a)}function M(t,e){return g(`${t}
7
- ${e}`)}function K(t){try{const e=I(t),o=e.indexOf(`
8
- `);return o<0?null:{rootId:e.slice(0,o),path:e.slice(o+1)}}catch{return null}}function G(t,e){return`/file/${M(t,e)}`}function v(t,e,o){const n=new URLSearchParams({rootId:e});return o!=null&&n.set("path",o),`/api/files/${t}?${n.toString()}`}function V(t,e,o=!1){const n=new URLSearchParams({rootId:t,path:e});return o&&n.set("download","1"),`/api/files/raw?${n.toString()}`}function W(t,e){return`/api/files/download?${new URLSearchParams({rootId:t,path:e}).toString()}`}function u(t){if(!Number.isFinite(t)||t<0)return"0 B";if(t<1024)return`${t} B`;const e=["KB","MB","GB","TB"];let o=t/1024,n=0;for(;o>=1024&&n<e.length-1;)o/=1024,n+=1;const a=o>=100?0:o>=10?1:2;return`${o.toFixed(a)} ${e[n]}`}function D(t){return`${u(t)}/s`}class j extends Error{constructor(o,n,a){super(n);O(this,"status");O(this,"code");this.name="FileApiError",this.status=o,this.code=a}}async function l(t){let e=`HTTP ${t.status}`,o;try{const n=await t.json();n.error&&(e=n.error),o=n.code}catch{}return new j(t.status,e,o)}async function Y(){const t=await fetch("/api/files/roots");if(!t.ok)throw await l(t);return await t.json()}async function q(t){const e=await fetch("/api/files/roots",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)});if(!e.ok)throw await l(e);return await e.json()}async function Q(t,e){const o=await fetch(`/api/files/roots/${encodeURIComponent(t)}`,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!o.ok)throw await l(o);return await o.json()}async function X(t){const e=await fetch(`/api/files/roots/${encodeURIComponent(t)}`,{method:"DELETE"});if(!e.ok)throw await l(e)}async function Z(t,e){const o=await fetch(v("list",t,e));if(!o.ok)throw await l(o);return await o.json()}async function L(t,e){const o=await fetch(v("stat",t,e));if(!o.ok)throw await l(o);return await o.json()}async function tt(t,e){const o=await fetch(v("content",t,e));if(!o.ok)throw await l(o);return await o.json()}const J=8*1024*1024;async function et(t,e,o,n={}){const{onLeg:a,signal:s}=n,k=()=>{if(s!=null&&s.aborted)throw new DOMException("Aborted","AbortError")},w=o.size,y=c=>`${u(c)} / ${u(w)}`,E={rootId:t,path:e,name:o.name,size:w},m=await fetch("/api/files/upload/init",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(E),signal:s});if(!m.ok)throw await l(m);const{uploadId:h,chunkSize:F}=await m.json(),U=F>0?F:J;try{a==null||a(1,{pct:w===0?100:0,detail:y(0)});const c=performance.now();let i=0;for(;i<w;){k();const S=Math.min(i+U,w),$=await fetch(`/api/files/upload/${h}?offset=${i}`,{method:"PUT",body:o.slice(i,S),signal:s});if(!$.ok)throw await l($);i=S;const p=(performance.now()-c)/1e3;a==null||a(1,{pct:Math.round(i/w*100),rate:p>0?D(i/p):void 0,detail:y(i)})}a==null||a(1,{pct:100,detail:y(w)}),k(),a==null||a(2,{pct:0,detail:y(0)});const f=await fetch(`/api/files/upload/${h}/commit`,{method:"POST",signal:s});if(!f.ok||!f.body)throw await l(f);const R=f.body.getReader(),r=new TextDecoder;let b="",C=!1;for(;;){const{done:S,value:$}=await R.read();if(S)break;b+=r.decode($,{stream:!0});const p=b.split(`
9
- `);b=p.pop()??"";for(const T of p){if(!T.trim())continue;const d=JSON.parse(T);if(d.type==="progress")a==null||a(2,{pct:d.pct,rate:d.rate,detail:y(d.transferred)});else if(d.type==="done")C=!0;else if(d.type==="error")throw new j(500,d.detail??d.code,d.code)}}if(!C)throw new j(500,"unknown","unknown");a==null||a(2,{pct:100,detail:y(w)})}catch(c){try{await fetch(`/api/files/upload/${h}`,{method:"DELETE"})}catch{}throw c}}async function ot(t,e,o,n={}){const{onLeg:a,signal:s}=n;a==null||a(1,{pct:0});const k=await fetch("/api/files/download/prepare",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({rootId:t,path:e}),signal:s});if(!k.ok||!k.body)throw await l(k);const w=k.body.getReader(),y=new TextDecoder;let E="",m="",h=0,F=o,U=null;for(;;){const{done:c,value:i}=await w.read();if(c)break;E+=y.decode(i,{stream:!0});const f=E.split(`
10
- `);E=f.pop()??"";for(const R of f){if(!R.trim())continue;const r=JSON.parse(R);r.type==="progress"?a==null||a(1,{pct:r.pct??0,rate:r.rate,detail:r.transferred!=null?u(r.transferred):void 0}):r.type==="done"?(m=r.downloadId??"",h=r.size??0,F=r.name??o):r.type==="error"&&(U=new j(500,r.detail??r.code??"unknown",r.code))}}if(U)throw U;if(!m)throw new j(500,"unknown","unknown");a==null||a(1,{pct:100,detail:u(h)});try{const c=T=>`${u(T)} / ${u(h)}`;a==null||a(2,{pct:0,detail:c(0)});const i=await fetch(`/api/files/download/${m}/content`,{signal:s});if(!i.ok||!i.body)throw await l(i);const f=Number(i.headers.get("Content-Length")??String(h)),R=i.body.getReader(),r=[];let b=0;const C=performance.now();for(;;){const{done:T,value:d}=await R.read();if(T)break;r.push(d),b+=d.byteLength;const A=(performance.now()-C)/1e3;a==null||a(2,{pct:f>0?Math.round(b/f*100):0,rate:A>0?D(b/A):void 0,detail:`${u(b)} / ${u(f)}`})}const S=new Blob(r),$=URL.createObjectURL(S),p=document.createElement("a");p.href=$,p.download=F,document.body.appendChild(p),p.click(),p.remove(),URL.revokeObjectURL($),a==null||a(2,{pct:100,detail:c(h)})}catch(c){try{await fetch(`/api/files/download/${m}`,{method:"DELETE"})}catch{}throw c}}export{H as D,j as F,W as a,G as b,ot as c,K as d,Y as e,u as f,Z as g,Q as h,X as i,q as j,L as k,V as l,tt as m,et as u};
@@ -1 +0,0 @@
1
- import{ai as o,aj as n}from"./mermaid.core-CvSv2dqw.js";const t=(a,r)=>o.lang.round(n.parse(a)[r]);export{t as c};
@@ -1 +0,0 @@
1
- import{s as a,c as s,a as e,C as t}from"./chunk-727SXJPM-BwBn-X-G.js";import{_ as i}from"./mermaid.core-CvSv2dqw.js";import"./chunk-FMBD7UC4-DnaDXP2z.js";import"./chunk-ND2GUHAM-BCRcaTWl.js";import"./chunk-55IACEB6-pYNojBsx.js";import"./chunk-2J33WTMH-IFwQoyns.js";import"./index-U4iZ6Kxr.js";var n={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{n as diagram};
@@ -1 +0,0 @@
1
- import{s as a,c as s,a as e,C as t}from"./chunk-727SXJPM-BwBn-X-G.js";import{_ as i}from"./mermaid.core-CvSv2dqw.js";import"./chunk-FMBD7UC4-DnaDXP2z.js";import"./chunk-ND2GUHAM-BCRcaTWl.js";import"./chunk-55IACEB6-pYNojBsx.js";import"./chunk-2J33WTMH-IFwQoyns.js";import"./index-U4iZ6Kxr.js";var n={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{n as diagram};
@@ -1 +0,0 @@
1
- const e=JSON.parse('{"common":{"loading":"Loading...","save":"Save","saving":"Saving...","cancel":"Cancel","add":"Add","delete":"Delete","edit":"Edit","confirm":"Confirm","close":"Close","expand":"Expand","collapse":"Collapse","refresh":"Refresh","test":"Test","send":"Send","success":"Success","error":"Error","warning":"Warning","info":"Info","yes":"Yes","no":"No","enabled":"Enabled","disabled":"Disabled","pending":"Pending","authorized":"Authorized","unknown":"Unknown","empty":"Empty","none":"None","default":"Default","optional":"Optional","required":"Required","pwaInstallTitle":"Install as app","pwaInstallHintIOSSafari":"iOS Safari does not show an automatic install prompt. Tap Share, then \\"Add to Home Screen\\".","pwaInstallHintIOSChrome":"iOS Chrome does not show an automatic install prompt. Tap Share, then \\"Add to Home Screen\\"."},"nav":{"manageDevices":"Manage Devices","settings":"Settings","sidebarExpand":"Expand Sidebar","sidebarCollapse":"Collapse Sidebar","openSidebar":"Open Sidebar","closeSidebar":"Close Sidebar","jumpToLatest":"Jump to Latest","switchToEditor":"Switch to Editor Input","switchToDirect":"Switch to Direct Input","refreshPage":"Refresh Page","refreshPageConfirm":"Are you sure you want to refresh the page? Unsaved content will be lost."},"device":{"title":"Device Management","devices":"Devices","addDevice":"Add Device","addDeviceDescription":"Fill in device details and choose a connection method","addFirstDevice":"Add First Device","editDevice":"Edit Device","editDeviceDescription":"Update device configuration","sectionBasic":"Basic Info","sectionConnection":"Connection","sectionAuth":"Authentication","noDevices":"No Devices","noDevicesDescription":"Add a local or SSH device to get started","name":"Device Name","namePlaceholder":"e.g., My Server","type":"Type","typeLocal":"Local Device","typeSSH":"SSH Remote Device","typeSSHBadge":"SSH","host":"Host","hostPlaceholder":"example.com","port":"Port","username":"Username","usernamePlaceholder":"root","session":"Tmux Session Name","sessionPlaceholder":"tmex","sessionHint":"Leave empty to use default \\"tmex\\"","defaultWorkingDir":"Default Working Directory","defaultWorkingDirPlaceholder":"Leave empty for user home directory","authMode":"Authentication Mode","authPassword":"Password","authKey":"Private Key","authAgent":"SSH Agent","authConfigRef":"SSH Config","sshConfigRefPlaceholder":"Host alias, e.g. my-server","sshConfigRefHint":"A Host alias from your ssh config, resolved via `ssh -G`. Not the path to the config file.","password":"Password","privateKey":"Private Key","privateKeyPlaceholder":"-----BEGIN OPENSSH PRIVATE KEY-----","privateKeyPassphrase":"Private Key Passphrase (Optional)","passphrase":"Passphrase","connect":"Connect","connected":"Connected","disconnect":"Disconnect","disconnected":"Disconnected","connecting":"Connecting...","dragHandle":"Drag to reorder device","reorderFailed":"Failed to reorder devices","deleteConfirm":"Delete this device?","deleteDescription":"Device \\"{{name}}\\" will be permanently removed. This action cannot be undone.","deleteSuccess":"Device deleted","createSuccess":"Device created","updateSuccess":"Device updated","deleteFailed":"Failed to delete device","createFailed":"Failed to create device","updateFailed":"Failed to update device","loadFailed":"Failed to load devices","localDevice":"Local Device","subtitle":"{{username}}@{{host}}:{{port}}","modify":"Modify Device","delete":"Delete"},"terminal":{"keyboardBehavior":{"title":"Keyboard Behavior","description":"How the page makes room for the on-screen keyboard","modeLift":"Shift page","modeLiftDesc":"Move the whole page up; terminal size stays the same","modeResize":"Resize terminal","modeResizeDesc":"Shrink the terminal to fit above the keyboard (changes the remote window size)","modeFollow":"Follow cursor","modeFollowDesc":"Shift just enough to keep the cursor right above the keyboard; terminal size stays the same"},"initializing":"Initializing terminal...","connecting":"Connecting to device...","initFailed":"Terminal initialization failed","inputPlaceholder":"Type command here...","clear":"Clear","deviceError":"Device Error","deviceErrorWithType":"[{{type}}] Device Error","noDeviceSelected":"No device selected","windowClosed":"Current window has been closed, please select a window from the sidebar.","paneClosed":"Current pane has been closed, please select a pane from the sidebar.","bellNotification":"Terminal Bell","bellDescriptionWithTitle":"Window {{window}} · {{paneLabel}}","bellFallback":"Received tmux bell","notificationFallbackTitle":"Terminal Notification","notificationSourceLabel":"From {{source}}","notificationFallbackDetail":"Terminal notification","paneTitle":"Pane {{index}}","activePane":"Current Pane","activeWindow":"Current Window","editorPlaceholder":"Enter commands here...","editorClear":"Clear","editorSendWithEnter":"Send with Enter","editorSendLineByLine":"Send Line by Line","editorSend":"Send","sendShortcut":"Send {{key}}","inputModeDirect":"Direct Input","inputModeEditor":"Editor","newWindow":"New Window","closeWindow":"Close Window","closePane":"Close Pane","copy":"Copy","paste":"Paste","copied":"Copied to clipboard","copyFailed":"Copy failed","pasteFailed":"Could not read clipboard, check browser permissions","clearSelection":"Dismiss selection"},"settings":{"title":"System Settings","siteSettings":"Site Settings","siteName":"Site Name","siteNamePlaceholder":"tmex","siteUrl":"Site URL","siteUrlPlaceholder":"http://localhost:3000","bellThrottle":"Bell Throttle (seconds)","notificationThrottle":"Notification Throttle (seconds)","enableBrowserNotificationToast":"Enable Browser Notification Toast","enableNotificationPush":"Enable Notification Push","enableBellPush":"Enable Bell Push","enableBellSound":"Enable Bell Sound","sshReconnectRetries":"SSH Reconnect Retries","sshReconnectDelay":"SSH Reconnect Delay (seconds)","language":"Language","languagePlaceholder":"Select language","language_en_US":"English","language_zh_CN":"简体中文","language_ja_JP":"日本語","theme":"Dark Mode","themeLight":"Light","themeDark":"Dark","siteTab":"Site","notificationsTab":"Notifications","tabGroup":{"general":"General","devicesAndFiles":"Devices & Files","notifications":"Notifications","ai":"AI","terminal":"Terminal"},"terminal":{"title":"Terminal Settings","description":"Adjust the terminal font size, line height, family, and mobile keyboard avoidance. The font family applies to all monospaced text across the app.","fontSize":"Font Size","lineHeight":"Line Height","fontFamily":"Font","preview":"Preview","savedInBrowser":"These settings are saved in this browser only.","shortcuts":{"title":"Custom Shortcuts","savedOnServer":"Saved on the server and shared across all your browsers — changes take effect after you click Save.","preview":"Preview","useIcons":"Show keys as icons","useIconsDesc":"Replace key names like Ctrl/Shift/Enter with Apple-style symbols (⌃⇧⏎).","dragHandle":"Drag to reorder","delete":"Delete","labelPlaceholder":"Label","payloadPlaceholder":"Sequence, e.g. \\\\x1b[A","addShortcut":"Add shortcut","capturePrompt":"Press any key combination…","captureHint":"Click here, then press a key to capture","advanced":"Advanced: enter sequence manually","add":"Add","reset":"Reset to default","save":"Save","saved":"Shortcuts saved","saveFailed":"Failed to save shortcuts","loading":"Loading…","action":{"paste":"Paste","toggleKeyboard":"Toggle text input / keyboard","newAgentSession":"New Agent session","scrollToBottom":"Scroll terminal to bottom"},"loadFailed":"Failed to load shortcuts","retry":"Retry"}},"deviceManagement":{"title":"Device Management","description":"Add, edit, and connect to your local and SSH devices.","openButton":"Open Device Management"},"refreshToApply":"Refresh to apply language change","saveSettings":"Save Settings","settingsSaved":"Settings saved","saveFailed":"Failed to save settings","loadFailed":"Failed to load settings","restartGateway":"Restart Gateway","restartScheduled":"Gateway restart scheduled","restartConfirm":"Are you sure you want to restart Gateway? This will interrupt all active connections.","restartFailed":"Failed to restart gateway","sshReconnectMaxRetries":"SSH Reconnect Retries","llm":{"title":"LLM Providers","name":"Name","namePlaceholder":"e.g. OpenAI","baseUrl":"Base URL","baseUrlPlaceholder":"https://api.openai.com","baseUrlHint":"Adds /v1 automatically; end with / to keep the path as-is","protocol":"Protocol","apiKey":"API Key","apiKeyPlaceholder":"Enter API key","apiKeySetPlaceholder":"Already set, leave blank to keep","addProvider":"Add Provider","editProvider":"Edit Provider","formHint":"Configure the provider connection","models":"Models","modelsTitle":"Models for {{name}}","modelsHint":"Manage the available models for this provider: toggle and add manually","modelManual":"Manual","addModelPlaceholder":"Add a model ID","empty":"No providers yet","refreshModels":"Refresh Models","modelsCount":"{{total}} models","modelsNotFetched":"Models not fetched yet","modelsFetchFailed":"Failed to fetch models: {{error}}","deleteProvider":"Delete Provider","deleteConfirm":"Delete provider \\"{{name}}\\"?","defaults":"Global Defaults","defaultProvider":"Default Provider","defaultProviderNone":"Not set","defaultModel":"Default Model","defaultModelPlaceholder":"Type or pick a model ID","saveDefaults":"Save Defaults","loadFailed":"Failed to load LLM providers","createFailed":"Failed to create provider","updateFailed":"Failed to update provider","deleteFailed":"Failed to delete provider","refreshModelsFailed":"Failed to refresh models","settingsLoadFailed":"Failed to load LLM settings","settingsSaveFailed":"Failed to save LLM settings"},"search":{"title":"Search","provider":"Search Provider","responsesApiHint":"If your LLM provider uses the OpenAI Responses API protocol, it can use that API\'s built-in hosted search tool; the third-party search below is an optional supplement.","providerNone":"Disabled","tavilyApiKey":"Tavily API Key","braveApiKey":"Brave API Key","keyPlaceholder":"Enter API key","keySetPlaceholder":"Already set, leave blank to keep","clearKey":"Clear","clearKeyConfirm":"Clear this API key? You will need to enter it again.","loadFailed":"Failed to load search settings","saveFailed":"Failed to save search settings"},"files":{"title":"Files","description":"Per-device directories browsable in the Files tab. Local devices read directly; SSH devices use rsync.","addRoot":"Add directory","roots":"Directories","empty":"No directories configured","missing":"Device missing","modalAddTitle":"Add directory","modalEditTitle":"Edit directory","device":"Device","devicePlaceholder":"Select a device","noDevices":"No devices yet — add one first","path":"Path","pathPlaceholder":"/absolute/path/to/directory","pathHint":"Absolute path on the selected device.","enabled":"Enabled","addFailed":"Failed to add directory","updateFailed":"Failed to update directory","deleteFailed":"Failed to remove directory","toggleFailed":"Failed to update directory","deleteTitle":"Remove directory?","deleteDesc":"Remove \\"{{path}}\\" from the whitelist? Files under it will no longer be accessible."},"version":{"title":"Version & Updates","currentVersion":"Current version","installMethod":"Install method","installMethodCli":"Installed via CLI","installMethodNonCli":"Not installed via CLI","deployment":"Deployment","deploymentLaunchd":"launchd (macOS)","deploymentSystemd":"systemd (Linux)","deploymentNone":"None","checkUpdate":"Check for updates","checking":"Checking…","upToDate":"You are on the latest version.","updateAvailable":"Update available: {{version}}","changelog":"Changelog","changelogUnavailable":"No changelog available for this version.","publishedAt":"Published {{date}}","upgrade":"Upgrade now","upgradeDisabledDev":"In-app update is disabled outside the production environment.","upgradeDisabledNonCli":"In-app update is only available for CLI installations.","upgradeWarningTitle":"Confirm upgrade","upgradeWarningBody":"Upgrading restarts the service and will interrupt your current session. It may also affect the survival of tmux processes managed by the service. Continue?","upgradeStarted":"Upgrade started","stateDownloading":"Downloading the new version…","stateExecuting":"Applying the upgrade, the service is restarting…","interruptNotice":"The connection will drop while the service restarts; it will recover shortly.","checkFailed":"Failed to check for updates","terminalHint":"Or upgrade from a terminal: npx tmex-cli@<version> upgrade"}},"telegram":{"title":"Telegram Bot Management","botName":"Bot Name","botNamePlaceholder":"e.g., ops-bot","botToken":"Bot Token","botTokenPlaceholder":"123456:AA...","addBot":"Add Bot","editBot":"Edit Bot","enableBot":"Enable Bot","allowAuthRequests":"Allow Authorization Requests","pendingChats":"Pending Authorization","chats":"Authorized Chats","authorizedChats":"Authorized","noPendingChats":"No pending chats","noAuthorizedChats":"No authorized chats","approve":"Approve","authorize":"Authorize","reject":"Reject","revokeAuth":"Revoke Authorization","testMessage":"Test Message","sendTestMessage":"Send Test Message","deleteBot":"Delete Bot","tokenOptional":"Token (leave empty to keep unchanged)","tokenPlaceholder":"Enter new token","botCreated":"Bot created","botUpdated":"Bot updated","botDeleted":"Bot deleted","authApproved":"Authorization approved","chatRemoved":"Chat removed","testMessageSent":"Test message sent","createFailed":"Failed to create bot","updateFailed":"Failed to update bot","deleteFailed":"Failed to delete bot","approveFailed":"Failed to approve authorization","removeFailed":"Failed to remove chat","testMessageFailed":"Failed to send test message","loadBotsFailed":"Failed to load bot list","loadChatsFailed":"Failed to load chat list","noBots":"No bots yet, add one first.","expand":"Expand","collapse":"Collapse","authCount":"{{authorized}} authorized / {{pending}} pending (max 8)","chatId":"Chat ID","applyTime":"Application Time","gatewayOnline":"🟢 Gateway online @ {{siteName}}","deviceConnectionError":"🔴 {{siteName}}: Connection error on device \\"{{deviceName}}\\" ({{host}}) [{{category}}]\\n{{error}}","agentCredentialWarning":"⚠️ {{siteName}}: A message in agent session \\"{{sessionTitle}}\\" appears to contain credentials ({{types}}). It will be sent to the LLM and stored — risk of leakage.","authSuccess":"✅ Authorized. You will now receive notifications.","authPending":"⏳ Authorization request received. Please approve in tmex settings.","authFailed":"❌ Authorization request failed. Please contact administrator.","testMessageTemplate":"🧪 Test Message\\nSite: {{siteName}}\\nTime: {{time}}","approveMessageTemplate":"✅ Authorized via tmex.\\nBot: {{botName}}\\nTime: {{time}}","botNotFound":"Bot not found or unavailable","botNotRunning":"Bot is not running or unavailable"},"weixin":{"title":"WeChat (ClawBot) Management","subtitle":"Push tmex alerts to your personal WeChat via the iLink bot protocol.","replyOnlyNotice":"iLink can only reply inside an active conversation window — message the bot first to activate; alerts then reuse that session. If it goes quiet too long the session expires; message the bot again to re-activate.","accountName":"Account Name","accountNamePlaceholder":"e.g., my-wechat","addAccount":"Add Account","editAccount":"Edit Account","enableAccount":"Enable Account","allowAuthRequests":"Allow Authorization Requests","scanToLogin":"Scan to Log In","relogin":"Re-login (Re-scan)","loggedIn":"Logged in","notLoggedIn":"Not logged in","scanQrcodeHint":"Open WeChat, scan the QR code, and confirm on your phone.","loginPending":"Waiting for scan…","loginConfirmed":"Login confirmed.","loginExpired":"QR code expired. Please retry.","loginError":"Login failed: {{message}}","loginFailed":"Login failed","refreshQrcode":"Refresh QR Code","closeLogin":"Close","pendingUsers":"Pending Authorization","authorizedUsers":"Authorized Users","noPendingUsers":"No pending users","noAuthorizedUsers":"No authorized users","needsReactivation":"Session expired","reactivationHint":"Ask this user to send the bot any message to re-activate alerts.","approve":"Approve","revokeAuth":"Revoke","removeUser":"Remove","testMessage":"Test Message","sendTestMessage":"Send Test Message","deleteAccount":"Delete Account","accountCreated":"Account created","accountUpdated":"Account updated","accountDeleted":"Account deleted","authApproved":"Authorization approved","userRemoved":"User removed","testMessageSent":"Test message sent","createFailed":"Failed to create account","updateFailed":"Failed to update account","deleteFailed":"Failed to delete account","approveFailed":"Failed to approve","removeFailed":"Failed to remove user","testMessageFailed":"Failed to send test message","loadAccountsFailed":"Failed to load accounts","loadUsersFailed":"Failed to load users","noAccounts":"No accounts yet, add one first.","userCount":"{{authorized}} authorized / {{pending}} pending (max 16)","userId":"WeChat User ID","applyTime":"First Contact","expand":"Expand","collapse":"Collapse","accountNameRequired":"Account name is required","accountNotFound":"Account not found or unavailable","accountNotRunning":"Account is not logged in or not running","userNotFound":"User not found","authSuccess":"✅ Authorized. You will now receive notifications.","authPending":"⏳ Authorization request received. Please approve in tmex settings.","testMessageTemplate":"🧪 Test Message\\nSite: {{siteName}}\\nTime: {{time}}","approveMessageTemplate":"✅ Authorized via tmex.\\nAccount: {{accountName}}\\nTime: {{time}}","keepalivePrompt":"【tmex】To keep notifications flowing, just reply with anything to keep the session alive 🙏","scanConfirmedSendHint":"Scan confirmed! Now send any message to this bot in WeChat to finish binding.","bindingInProgress":"Message received, finishing binding…","bindSuccess":"WeChat bound. You will now receive notifications.","bound":"Bound","unbound":"Not bound","bindAction":"Bind (scan)","gatewayOnline":"🟢 tmex online @ {{siteName}}"},"webhook":{"title":"Webhooks","url":"Webhook URL","secret":"Secret","secretPlaceholder":"Used to sign payloads (HMAC-SHA256)","enabled":"Enabled","eventMask":"Events","add":"Add Webhook","empty":"No webhooks yet.","createFailed":"Failed to create webhook","deleteFailed":"Failed to delete webhook","loadFailed":"Failed to load webhooks"},"sshError":{"sshConfigRefNotSupported":"SSH Config reference is not supported in this version. Please use host + username with Agent/Key/Password authentication.","configRefNotSupported":"SSH Config reference is not supported in this version. Please use host + username with Agent/Key/Password authentication.","agentUnavailable":"SSH Agent unavailable: SSH_AUTH_SOCK not detected. Please check agent environment.","agentNoIdentity":"SSH Agent has no available keys. Please run ssh-add first.","agentNoIdentities":"SSH Agent has no available keys. Please run ssh-add first.","authFailed":"Authentication failed: incorrect username, password, or key. Please check device configuration.","authFailedGeneric":"Authentication failed: incorrect username, password, or key. Please check device configuration.","networkUnreachable":"Network unreachable: Please check routing, firewall, or VPN configuration.","connectionRefused":"Connection refused: Unable to connect to target host. Please check host address and port.","timeout":"Connection timeout: Unable to connect to device. Please check network or firewall settings.","connectionTimeout":"Connection timeout: Unable to connect to device. Please check network or firewall settings.","hostNotFound":"Host not found: Unable to resolve hostname. Please check DNS or hostname configuration.","handshakeFailed":"Handshake failed: Unable to establish secure connection. Possibly incompatible key exchange algorithm.","tmuxUnavailable":"Remote tmux unavailable or failed to start. Please ensure tmux is installed and available in the remote shell PATH.","connectionClosed":"Connection closed, attempting to reconnect","unknown":"Connection failed: {{message}}","reconnecting":"Connection interrupted, reconnecting in {{delay}} seconds ({{attempt}}/{{maxRetries}})","reconnectFailed":"Auto-reconnect failed, please retry manually","reconnected":"Device reconnected automatically"},"deviceStatus":{"reconnecting":"Reconnecting {{delay}}s","offline":"Offline","errorBadge":{"authFailed":"Auth failed","agentUnavailable":"Agent unavailable","agentNoIdentity":"Agent has no keys","configRefNotSupported":"SSH Config unsupported","networkUnreachable":"Network unreachable","connectionRefused":"Refused","timeout":"Timeout","hostNotFound":"Host not found","handshakeFailed":"Handshake failed","tmuxUnavailable":"Tmux unavailable","connectionClosed":"Disconnected","unknown":"Connection error"}},"websocket":{"error":"WebSocket connection error","checkGateway":"Please check Gateway status","upgradeFailed":"Upgrade failed","invalidMessage":"Invalid message format","reconnecting":"Reconnecting","reconnect":"Reconnect"},"wsError":{"checkGateway":"Please check Gateway status"},"apiError":{"siteNameRequired":"Site name cannot be empty","siteUrlInvalid":"Site URL must start with http:// or https://","bellThrottleInvalid":"Bell throttle seconds must be between 0-300","sshRetriesInvalid":"SSH reconnect retries must be between 0-20","sshDelayInvalid":"SSH reconnect delay must be between 1-300 seconds","languageInvalid":"Language must be one of the supported locales","botNameRequired":"Bot name cannot be empty","botTokenRequired":"Bot token cannot be empty","missingFields":"Missing required fields","sshRequiresHost":"SSH device requires host or sshConfigRef","invalidRequest":"Invalid request","deviceNotFound":"Device not found","botNotFound":"Bot not found","chatNotFound":"Chat not found","urlAndSecretRequired":"URL and secret are required","notFound":"Not found","llmProviderNameRequired":"Provider name cannot be empty","llmProviderProtocolInvalid":"Protocol must be openai-chat or openai-responses","llmProviderBaseUrlInvalid":"Base URL must start with http:// or https://","llmProviderApiKeyRequired":"API key cannot be empty","llmProviderNotFound":"LLM provider not found","llmProviderDisabled":"LLM provider {{name}} is disabled","llmNoDefaultProvider":"No LLM provider specified and no default provider configured","llmNoDefaultModel":"No model specified and no default model configured","llmDefaultProviderNotFound":"Default provider does not exist","llmSearchProviderInvalid":"Search provider must be none, tavily or brave","llmFetchModelsFailed":"Failed to fetch model list: {{detail}}","agentSessionNotFound":"Agent session not found","agentSessionBusy":"Agent session is currently running, stop it or wait for completion","agentSessionAwaitingConfirmation":"Agent session has pending confirmations, resolve them first","agentDeviceRequired":"Device is required","agentPaneRequired":"Terminal pane is required","agentWriteModeInvalid":"Write mode must be confirm or auto","agentMaxStepsInvalid":"Max steps per turn must be between 1 and 100","agentProviderWebSearchRequiresResponses":"Provider built-in web search requires the openai-responses protocol","agentHostedToolUnknown":"Unknown hosted tool: {{name}}","agentHostedToolRequiresResponses":"Provider hosted tools require the openai-responses protocol","agentSessionOrphaned":"This agent session is orphaned (its terminal is gone) and is read-only","agentQueuedMessageNotFound":"Queued message not found","agentConfirmationNotFound":"Confirmation not found","agentConfirmationAlreadyDecided":"Confirmation has already been decided","agentMessageTextRequired":"Message text is required","watchRuleNotFound":"Watch rule not found","watchNameRequired":"Rule name is required","watchTriggerTypeInvalid":"Trigger type must be match, unchanged or llm","watchPatternRequired":"match/unchanged rules require a regular expression","watchPatternInvalid":"Invalid regular expression: {{detail}}","watchUnchangedMinutesInvalid":"unchanged rules require unchangedMinutes greater than 0","watchExtractGroupInvalid":"Capture group index must be an integer >= 0","watchConditionPromptRequired":"llm rules require a condition prompt","watchIntervalInvalid":"Sampling interval must be at least {{min}} seconds","watchNoMatchBehaviorInvalid":"No-match behavior must be reset or ignore","watchFireModeInvalid":"Fire mode must be once or repeat","watchCooldownInvalid":"Cooldown seconds must be an integer >= 0","watchAssistDescriptionRequired":"Please describe what to match","watchAssistModelUnavailable":"Model call failed: {{detail}}","fileRootInvalid":"Path must be an absolute, existing directory","fileOutsideRoots":"Path is outside the allowed directories","fileNotADirectory":"Not a directory","fileTooLarge":"File is too large","fileBinary":"Binary files are not supported","fileRootDeviceInvalid":"Invalid or unknown device","fileRootDuplicate":"This directory is already added for the device","upgradeNotAllowed":"In-app update is not available for this installation.","upgradeInProgress":"An upgrade is already in progress.","upgradeVersionRequired":"Target version is required.","updateCheckFailed":"Failed to query the npm registry.","terminalShortcutsTooMany":"Too many shortcuts","terminalShortcutInvalid":"Invalid shortcut configuration"},"notification":{"clickToJump":"Click to jump to corresponding pane","eventType":{"terminal_bell":"🔔 Terminal Bell","terminal_notification":"🔔 Terminal Notification","tmux_window_close":"🪟 Window Closed","tmux_pane_close":"📱 Pane Closed","device_tmux_missing":"⚠️ Tmux Missing","device_disconnect":"🔌 Device Disconnected","session_created":"🆕 Session Created","session_closed":"🚪 Session Closed","agent_confirmation_pending":"🤖 Agent Confirmation Pending","agent_turn_finished":"🤖 Agent Turn Finished","agent_error":"🤖 Agent Error","watch_triggered":"👁️ Watch Rule Triggered","watch_model_unavailable":"👁️ Watch Model Unavailable","watch_rule_error":"👁️ Watch Rule Error"},"site":"Site","device":"Device","window":"Window","pane":"Pane","time":"Time","directLink":"Direct Link","message":"Message","paneTitle":"Title","process":"Process","telegramBell":{"title":"🔔 Bell from {{siteName}}: {{terminalTopbarLabel}}","viewLink":"Click to view","terminalTopbarLabel":"Window {{window}} · Pane {{pane}} @ {{device}}"},"telegramNotification":{},"agent":{"confirmationPending":"Agent \\"{{title}}\\" requests to run tool {{toolName}}, awaiting confirmation","turnFinished":"Agent \\"{{title}}\\" turn finished","error":"Agent \\"{{title}}\\" error: {{message}}"},"watch":{"matchTriggered":"Watch \\"{{name}}\\" matched: {{text}}","unchangedTriggered":"Watch \\"{{name}}\\" value \\"{{value}}\\" has been unchanged for {{minutes}} minutes","llmTriggered":"Watch \\"{{name}}\\" condition met: {{reason}}","summaryTriggered":"Watch \\"{{name}}\\": {{summary}}","unconfirmedSuffix":" (model unavailable, not LLM-confirmed)","modelUnavailable":"Watch \\"{{name}}\\" model call failed: {{message}}","ruleError":"Watch \\"{{name}}\\" failed {{count}} times in a row and has been disabled: {{message}}","paneGone":"Watch \\"{{name}}\\" pane ({{paneId}}) was destroyed; the rule has been removed"}},"sidebar":{"noWindows":"No windows","noDevices":"No devices","addDeviceLink":"Add Device","openSettingsLink":"Open Settings","openSettings":"Open Settings","manageDevices":"Manage Devices","settings":"Settings","currentWindow":"Current Window","currentPane":"Current Pane","newWindow":"Create Window","closeWindow":"Close Window","closePane":"Close Pane","addDevice":"Add Device","tab":{"panes":"Panes","agent":"Agent","files":"Files"},"orphanedSessions":"Orphaned sessions"},"agent":{"error":{"streamStalled":"The model stopped responding (upstream stream stalled). Please retry."},"model":{"select":"Select model","placeholder":"Model","noProviders":"No models — configure a provider in Settings"},"queue":{"title":"Queued ({{count}})","steer":"Steer now","steerHint":"Interrupt the current step and inject the queue now","withdraw":"Withdraw"},"orphan":{"readonly":"This session is orphaned (its terminal is gone) — read-only","title":"Orphaned","process":"Process","startedAt":"Started"},"files":{"comingSoon":"Coming Soon"},"panel":{"title":"Agent","empty":"Select or create a session","inputPlaceholder":"Type a message…","send":"Send","stop":"Stop","retry":"Retry","scrollToBottom":"Scroll to bottom"},"welcome":{"title":"New Agent chat","subtitle":"Describe your task to start working in the selected terminal"},"session":{"none":"No session selected","new":"New agent session","switch":"Switch session","selectPaneHint":"Select a pane in the Panes tab to start a session","noSessions":"No sessions yet","showAll":"Show all sessions","rename":"Rename session","renameTitle":"Rename session","renamePlaceholder":"Session title","save":"Save","cancel":"Cancel","delete":"Delete session","deleteTitle":"Delete this session?","deleteDesc":"\\"{{title}}\\" and all its messages will be permanently deleted.","deleteConfirm":"Delete","createDisabledNoPane":"Open a terminal pane to create a session","privacyNotice":"Sessions send terminal screen content to the configured LLM service."},"binding":{"invalid":"Pane unavailable","mismatchTitle":"This session is bound to a different pane","goTo":"Go to pane","rebind":"Rebind here"},"writeMode":{"confirm":"Confirm writes","auto":"Auto execute"},"confirm":{"title":"Approval required","approve":"Allow","deny":"Deny"},"tool":{"input":"Input","details":"Details","close":"Close","result":"Result","screen":"Screen capture","send_input":"Send input","read_screen":"Read screen","web_search":"Web search","fetch_url":"Fetch URL","get_pane_info":"Get pane info","run_command":"Run command","denied":"Denied"},"paneBadge":{"bound":"Agent bound","generating":"Agent generating"},"controlChars":{"label":"Control chars","hint":"Allow the agent to send raw control characters (C0) via send_input. Off by default; enable only when necessary."},"reasoning":{"title":"Reasoning"},"toast":{"errorTitle":"Agent \\"{{title}}\\" error","credentialWarningTitle":"Message may contain credentials","credentialWarningDescription":"Detected {{types}}. The content is not modified, but it will be sent to the LLM and stored — risk of leakage."}},"window":{"noWindows":"No windows","new":"New Window","newInCwd":"New window here","close":"Close window","closePane":"Close pane","closeConfirmTitle":"Close this window?","closePaneConfirmTitle":"Close this pane?","closeConfirmDesc":"Processes running in \\"{{name}}\\" will be terminated. This action cannot be undone.","menu":"Window actions","dragHandle":"Drag to reorder window","dragHandlePane":"Drag to reorder pane","rename":"Rename window","renamePlaceholder":"Enter a name","renameDesc":"The custom name overrides the title set by the terminal and is kept until the gateway restarts.","renameReset":"Use automatic name","switchPane":"Switch pane","splitRight":"Split right","splitDown":"Split down","paneCount":"{{count}} panes","pane":"Pane","moveToWindow":"Move into this window","breakToWindow":"Break into new window"},"watch":{"title":"Watch rules","dialogDesc":"Monitor this pane\'s screen and get notified when conditions are met","openMonitor":"Watch this pane","rules":{"empty":"No watch rules for this pane yet","addRule":"New rule","edit":"Edit","delete":"Delete","viewState":"Status","lastTriggered":"Last triggered: {{time}}","neverTriggered":"Never triggered","deleteTitle":"Delete this rule?","deleteDesc":"\\"{{name}}\\" will be permanently deleted.","deleteConfirm":"Delete"},"type":{"match":"Match","unchanged":"Stuck","llm":"LLM"},"typeDesc":{"match":"Trigger when a regex matches the screen","unchanged":"Trigger when an extracted value stays unchanged for N minutes (e.g. stalled download)","llm":"An LLM periodically checks the screen against a natural-language condition"},"form":{"createTitle":"New watch rule","editTitle":"Edit watch rule","name":"Rule name","namePlaceholder":"e.g. Download stalled","triggerType":"Trigger type","pattern":"Regular expression","patternPlaceholder":"e.g. (\\\\d+)%","flags":"Flags","flagsPlaceholder":"e.g. i","extractGroup":"Capture group index","extractGroupHint":"0 = whole match; the group value is tracked over time","unchangedMinutes":"Unchanged for (minutes)","noMatchBehavior":"When nothing matches","noMatchReset":"Reset timer (progress line gone = task done)","noMatchIgnore":"Ignore (keep last value)","conditionPrompt":"Condition (natural language)","conditionPromptPlaceholder":"e.g. The build has failed with a compile error","model":"Model","followGlobalDefault":"Follow global default","modelPlaceholder":"Model ID","modelRequiredHint":"This rule calls an LLM. Make sure the selected (or global default) model is available.","confirmWithLlm":"LLM double-check before notifying","confirmWithLlmDesc":"Reduce false positives; fails open if the model is unavailable","summarizeWithLlm":"LLM notification summary","summarizeWithLlmDesc":"Summarize the screen into the notification text","intervalSeconds":"Sampling interval (seconds)","intervalHint":"Minimum {{min}}s","fireMode":"Fire mode","fireOnce":"Once (auto-disable after firing)","fireRepeat":"Repeat","cooldownSeconds":"Cooldown (seconds)","enabled":"Enabled","assistLabel":"Generate regex from a description","assistPlaceholder":"e.g. match the download progress percentage","assistButton":"Generate","assistExplanation":"Explanation","assistPreview":"Matches on current screen","assistPreviewEmpty":"No matches on the current screen sample","create":"Create","save":"Save","providerUnavailable":"Original provider unavailable","providerDisabled":"disabled"},"validation":{"nameRequired":"Rule name is required","patternRequired":"Regular expression is required","patternInvalid":"Invalid regular expression: {{detail}}","unchangedMinutesInvalid":"Unchanged minutes must be greater than 0","conditionPromptRequired":"Condition prompt is required","intervalMin":"Sampling interval must be at least {{min}} seconds"},"state":{"title":"Rule status","back":"Back","lastSampledAt":"Last sampled","lastValue":"Last value","lastValueChangedAt":"Value last changed","lastTriggeredAt":"Last triggered","consecutiveErrors":"Consecutive errors","lastError":"Last error","samples":"Recent samples","samplesEmpty":"No samples yet","hit":"hit","none":"—"},"toast":{"created":"Watch rule created","updated":"Watch rule updated","deleted":"Watch rule deleted","triggeredTitle":"Watch triggered","openTerminal":"Open terminal","modelUnavailableTitle":"Watch model unavailable","modelUnavailableHint":"The rule keeps running with degraded behavior.","ruleErrorTitle":"Watch rule auto-disabled"},"notifPermission":{"title":"Enable browser notifications?","desc":"Get notified when watch rules trigger, even when this tab is in the background.","enable":"Enable","dismiss":"Not now"}},"validation":{"deviceNameRequired":"Device name is required","hostRequired":"Host is required for SSH devices","portRequired":"A valid port is required for SSH devices","usernameRequired":"Username is required for SSH devices","sshConfigRequired":"SSH config path is required for SSH devices"},"files":{"title":"Files","refresh":"Refresh file list","noRoots":"No accessible directories. Add one in Settings → Files.","emptyDir":"Empty","truncated":"Too many items — list truncated","download":"Download","error":{"invalid":"Invalid request","outside_roots":"Path is outside the allowed directory","not_found":"No longer exists","not_a_directory":"Not a directory","is_directory":"This is a directory","too_large":"File is too large to preview","binary":"Binary file cannot be previewed","permission_denied":"Permission denied","device_not_found":"Device not found","root_not_found":"Directory entry not found","root_disabled":"This directory is disabled","connection_failed":"Failed to connect to the device","auth_unsupported":"Device auth method unsupported for files (use key or ssh-agent)","rsync_missing_local":"rsync is not installed on the server","rsync_missing_remote":"rsync is not installed on the remote device","timeout":"Timed out","unknown":"Failed to load"},"retry":"Retry (collapse then expand)","menu":{"copyAbsolute":"Copy absolute path","copyRelative":"Copy relative path","sendToAgent":"Send to Agent","expand":"Expand","collapse":"Collapse","upload":"Upload files here","open":"Open"},"copied":"Copied to clipboard","copyFailed":"Copy failed","sendToAgent":{"prompt":"Please work with this path: `{{path}}`"},"upload":{"uploading":"Uploading {{name}}…","success":"Uploaded {{name}}","fail":"Failed to upload {{name}}"},"transfer":{"legUserToTmex":"Browser → tmex","legTmexToServer":"tmex → Server","legServerToTmex":"Server → tmex","legTmexToUser":"tmex → Browser","cancel":"Cancel","canceled":"Canceled {{name}}","downloaded":"Downloaded {{name}}","downloadFailed":"Failed to download {{name}}","dragDownloadStarted":"Started downloading {{name}} (handled by browser)","tooLarge":"{{name}} exceeds the size limit ({{max}})"},"agentLaunch":{"connectFailed":"Failed to connect to the device","windowFailed":"Failed to create a window"},"install":{"button":"Install rsync","scopeLocal":"server","scopeRemote":"remote","prompt":"rsync is not installed on {{device}} ({{scope}}). Please install rsync using the appropriate command for this system (e.g. `brew install rsync`, `sudo apt-get install -y rsync`, or `sudo yum install -y rsync`), then reply once it is done."}},"file":{"invalidRef":"Invalid file reference","notFound":"File no longer exists","accessDenied":"Access denied","loadFailed":"Failed to load file","isDirectory":"This is a directory","notPreviewable":"Preview is not available for this file type","tooLarge":"File is too large to preview","binary":"Binary file cannot be previewed","download":"Download","openRaw":"Open raw"}}'),t={translation:e};export{t as default,e as translation};