tmex-cli 0.9.2 → 0.10.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 (130) hide show
  1. package/dist/runtime/server.js +1407 -127
  2. package/package.json +1 -1
  3. package/resources/fe-dist/assets/{DevicePage-RqH-pnZX.js → DevicePage-5vkaNOjl.js} +2 -2
  4. package/resources/fe-dist/assets/DevicesPage-CKnRUGQm.js +2 -0
  5. package/resources/fe-dist/assets/FilePage-Dj0cszD4.css +1 -0
  6. package/resources/fe-dist/assets/FilePage-Uj-tzGW7.js +283 -0
  7. package/resources/fe-dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  8. package/resources/fe-dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  9. package/resources/fe-dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  10. package/resources/fe-dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  11. package/resources/fe-dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  12. package/resources/fe-dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  13. package/resources/fe-dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  14. package/resources/fe-dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  15. package/resources/fe-dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  16. package/resources/fe-dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  17. package/resources/fe-dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  18. package/resources/fe-dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  19. package/resources/fe-dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  20. package/resources/fe-dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  21. package/resources/fe-dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  22. package/resources/fe-dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  23. package/resources/fe-dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  24. package/resources/fe-dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  25. package/resources/fe-dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  26. package/resources/fe-dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  27. package/resources/fe-dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  28. package/resources/fe-dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  29. package/resources/fe-dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  30. package/resources/fe-dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  31. package/resources/fe-dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  32. package/resources/fe-dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  33. package/resources/fe-dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  34. package/resources/fe-dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  35. package/resources/fe-dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  36. package/resources/fe-dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  37. package/resources/fe-dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  38. package/resources/fe-dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  39. package/resources/fe-dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  40. package/resources/fe-dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  41. package/resources/fe-dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  42. package/resources/fe-dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  43. package/resources/fe-dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  44. package/resources/fe-dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  45. package/resources/fe-dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  46. package/resources/fe-dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  47. package/resources/fe-dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  48. package/resources/fe-dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  49. package/resources/fe-dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  50. package/resources/fe-dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  51. package/resources/fe-dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  52. package/resources/fe-dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  53. package/resources/fe-dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  54. package/resources/fe-dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  55. package/resources/fe-dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  56. package/resources/fe-dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  57. package/resources/fe-dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  58. package/resources/fe-dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  59. package/resources/fe-dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  60. package/resources/fe-dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  61. package/resources/fe-dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  62. package/resources/fe-dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  63. package/resources/fe-dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  64. package/resources/fe-dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  65. package/resources/fe-dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  66. package/resources/fe-dist/assets/SettingsPage-Cfzr_Phh.js +22 -0
  67. package/resources/fe-dist/assets/arc-Wv219fq_.js +2 -0
  68. package/resources/fe-dist/assets/architectureDiagram-3BPJPVTR-DkPPo2hY.js +37 -0
  69. package/resources/fe-dist/assets/blockDiagram-GPEHLZMM-DPAThozG.js +133 -0
  70. package/resources/fe-dist/assets/c4Diagram-AAUBKEIU-DBs_N-_p.js +11 -0
  71. package/resources/fe-dist/assets/card-Dl0HC88A.js +2 -0
  72. package/resources/fe-dist/assets/channel-DyLhDM_y.js +2 -0
  73. package/resources/fe-dist/assets/chunk-2J33WTMH-D3mrUPCp.js +2 -0
  74. package/resources/fe-dist/assets/chunk-4BX2VUAB-C0DRv58j.js +2 -0
  75. package/resources/fe-dist/assets/chunk-55IACEB6-DheUp7iQ.js +2 -0
  76. package/resources/fe-dist/assets/chunk-727SXJPM-Cvew2yIJ.js +207 -0
  77. package/resources/fe-dist/assets/chunk-AQP2D5EJ-DUoa4Wdg.js +232 -0
  78. package/resources/fe-dist/assets/chunk-FMBD7UC4-Bt9Oi52P.js +16 -0
  79. package/resources/fe-dist/assets/chunk-ND2GUHAM-DlWpyDaS.js +2 -0
  80. package/resources/fe-dist/assets/chunk-QZHKN3VN-BZtXwgRW.js +2 -0
  81. package/resources/fe-dist/assets/classDiagram-4FO5ZUOK-DA8DiM06.js +2 -0
  82. package/resources/fe-dist/assets/classDiagram-v2-Q7XG4LA2-DA8DiM06.js +2 -0
  83. package/resources/fe-dist/assets/cose-bilkent-S5V4N54A-yKy6sTY_.js +2 -0
  84. package/resources/fe-dist/assets/cytoscape.esm-DTSO7Bv0.js +332 -0
  85. package/resources/fe-dist/assets/dagre-BM42HDAG-DL4fpno6.js +5 -0
  86. package/resources/fe-dist/assets/defaultLocale-DX6XiGOO.js +2 -0
  87. package/resources/fe-dist/assets/diagram-2AECGRRQ-BueYws-9.js +44 -0
  88. package/resources/fe-dist/assets/diagram-5GNKFQAL-GQEQSUeb.js +11 -0
  89. package/resources/fe-dist/assets/diagram-KO2AKTUF-LE3yI4ed.js +4 -0
  90. package/resources/fe-dist/assets/diagram-LMA3HP47-BkHjYrU4.js +25 -0
  91. package/resources/fe-dist/assets/diagram-OG6HWLK6-DrnHic-P.js +25 -0
  92. package/resources/fe-dist/assets/erDiagram-TEJ5UH35-BCwWv-rO.js +86 -0
  93. package/resources/fe-dist/assets/flowDiagram-I6XJVG4X-DEC2Z_fh.js +163 -0
  94. package/resources/fe-dist/assets/ganttDiagram-6RSMTGT7-H1T5bCsY.js +293 -0
  95. package/resources/fe-dist/assets/gitGraphDiagram-PVQCEYII-DmZUfKfl.js +107 -0
  96. package/resources/fe-dist/assets/graph-CAnANduQ.js +2 -0
  97. package/resources/fe-dist/assets/index-OpBFduyh.js +466 -0
  98. package/resources/fe-dist/assets/index-yMgNjHUH.css +1 -0
  99. package/resources/fe-dist/assets/infoDiagram-5YYISTIA-fDOg9Qr5.js +3 -0
  100. package/resources/fe-dist/assets/init-Gi6I4Gst.js +2 -0
  101. package/resources/fe-dist/assets/ishikawaDiagram-YF4QCWOH-QIvSJI3q.js +71 -0
  102. package/resources/fe-dist/assets/journeyDiagram-JHISSGLW-Iz7u4iH8.js +140 -0
  103. package/resources/fe-dist/assets/kanban-definition-UN3LZRKU-BYiFSFgn.js +90 -0
  104. package/resources/fe-dist/assets/layout-DGIYPm2g.js +2 -0
  105. package/resources/fe-dist/assets/linear-DNHZFKop.js +2 -0
  106. package/resources/fe-dist/assets/mermaid.core-DUipsjFg.js +310 -0
  107. package/resources/fe-dist/assets/mindmap-definition-RKZ34NQL-tPbrKC3m.js +97 -0
  108. package/resources/fe-dist/assets/ordinal-BENe2yWM.js +2 -0
  109. package/resources/fe-dist/assets/pieDiagram-4H26LBE5-26o8qBzb.js +31 -0
  110. package/resources/fe-dist/assets/quadrantDiagram-W4KKPZXB-BgpGo9Ak.js +8 -0
  111. package/resources/fe-dist/assets/{refresh-cw-D0LYIwxc.js → refresh-cw-DdcimDhs.js} +3 -3
  112. package/resources/fe-dist/assets/requirementDiagram-4Y6WPE33-BEfrxsDZ.js +85 -0
  113. package/resources/fe-dist/assets/sankeyDiagram-5OEKKPKP-BuIeHyjh.js +41 -0
  114. package/resources/fe-dist/assets/sequenceDiagram-3UESZ5HK-CL0sinOn.js +163 -0
  115. package/resources/fe-dist/assets/stateDiagram-AJRCARHV-BCq5X6hO.js +2 -0
  116. package/resources/fe-dist/assets/stateDiagram-v2-BHNVJYJU-DH2ctCND.js +2 -0
  117. package/resources/fe-dist/assets/timeline-definition-PNZ67QCA-CnqqA91O.js +121 -0
  118. package/resources/fe-dist/assets/vennDiagram-CIIHVFJN-BqFG3JXB.js +35 -0
  119. package/resources/fe-dist/assets/wardley-L42UT6IY-DvfZKNwT.js +174 -0
  120. package/resources/fe-dist/assets/wardleyDiagram-YWT4CUSO-DlABpMGt.js +79 -0
  121. package/resources/fe-dist/assets/xychartDiagram-2RQKCTM6-BDiyUuus.js +8 -0
  122. package/resources/fe-dist/index.html +2 -2
  123. package/resources/gateway-drizzle/0007_fearless_pestilence.sql +8 -0
  124. package/resources/gateway-drizzle/0008_perfect_ozymandias.sql +7 -0
  125. package/resources/gateway-drizzle/meta/_journal.json +14 -0
  126. package/resources/fe-dist/assets/DevicesPage-BPLJu-5J.js +0 -2
  127. package/resources/fe-dist/assets/SettingsPage-CKP305BP.js +0 -22
  128. package/resources/fe-dist/assets/card-X35xwXzW.js +0 -2
  129. package/resources/fe-dist/assets/index-CKQEHZcV.css +0 -1
  130. package/resources/fe-dist/assets/index-O2a9149K.js +0 -400
@@ -22550,7 +22550,7 @@ loadEnv();
22550
22550
 
22551
22551
  // src/runtime/server.ts
22552
22552
  import { existsSync as existsSync5 } from "fs";
22553
- import { extname, join as join4, normalize, resolve as resolve4, sep } from "path";
22553
+ import { extname as extname2, join as join6, normalize, resolve as resolve4, sep } from "path";
22554
22554
 
22555
22555
  // ../../apps/gateway/src/crypto/errors.ts
22556
22556
  function contextLabel(context) {
@@ -22807,6 +22807,29 @@ var I18N_RESOURCES = {
22807
22807
  clearKeyConfirm: "Clear this API key? You will need to enter it again.",
22808
22808
  loadFailed: "Failed to load search settings",
22809
22809
  saveFailed: "Failed to save search settings"
22810
+ },
22811
+ files: {
22812
+ title: "Files",
22813
+ description: "Per-device directories browsable in the Files tab. Local devices read directly; SSH devices use rsync.",
22814
+ addRoot: "Add directory",
22815
+ roots: "Directories",
22816
+ empty: "No directories configured",
22817
+ missing: "Device missing",
22818
+ modalAddTitle: "Add directory",
22819
+ modalEditTitle: "Edit directory",
22820
+ device: "Device",
22821
+ devicePlaceholder: "Select a device",
22822
+ noDevices: "No devices yet \u2014 add one first",
22823
+ path: "Path",
22824
+ pathPlaceholder: "/absolute/path/to/directory",
22825
+ pathHint: "Absolute path on the selected device.",
22826
+ enabled: "Enabled",
22827
+ addFailed: "Failed to add directory",
22828
+ updateFailed: "Failed to update directory",
22829
+ deleteFailed: "Failed to remove directory",
22830
+ toggleFailed: "Failed to update directory",
22831
+ deleteTitle: "Remove directory?",
22832
+ deleteDesc: 'Remove "{{path}}" from the whitelist? Files under it will no longer be accessible.'
22810
22833
  }
22811
22834
  },
22812
22835
  telegram: {
@@ -22985,7 +23008,14 @@ Time: {{time}}`,
22985
23008
  watchFireModeInvalid: "Fire mode must be once or repeat",
22986
23009
  watchCooldownInvalid: "Cooldown seconds must be an integer >= 0",
22987
23010
  watchAssistDescriptionRequired: "Please describe what to match",
22988
- watchAssistModelUnavailable: "Model call failed: {{detail}}"
23011
+ watchAssistModelUnavailable: "Model call failed: {{detail}}",
23012
+ fileRootInvalid: "Path must be an absolute, existing directory",
23013
+ fileOutsideRoots: "Path is outside the allowed directories",
23014
+ fileNotADirectory: "Not a directory",
23015
+ fileTooLarge: "File is too large",
23016
+ fileBinary: "Binary files are not supported",
23017
+ fileRootDeviceInvalid: "Invalid or unknown device",
23018
+ fileRootDuplicate: "This directory is already added for the device"
22989
23019
  },
22990
23020
  notification: {
22991
23021
  clickToJump: "Click to jump to corresponding pane",
@@ -23275,6 +23305,54 @@ Time: {{time}}`,
23275
23305
  validation: {
23276
23306
  deviceNameRequired: "Device name is required",
23277
23307
  hostRequired: "Host is required for SSH devices"
23308
+ },
23309
+ files: {
23310
+ title: "Files",
23311
+ refresh: "Refresh file list",
23312
+ noRoots: "No accessible directories. Add one in Settings \u2192 Files.",
23313
+ emptyDir: "Empty",
23314
+ truncated: "Too many items \u2014 list truncated",
23315
+ download: "Download",
23316
+ error: {
23317
+ invalid: "Invalid request",
23318
+ outside_roots: "Path is outside the allowed directory",
23319
+ not_found: "No longer exists",
23320
+ not_a_directory: "Not a directory",
23321
+ is_directory: "This is a directory",
23322
+ too_large: "File is too large to preview",
23323
+ binary: "Binary file cannot be previewed",
23324
+ permission_denied: "Permission denied",
23325
+ device_not_found: "Device not found",
23326
+ root_not_found: "Directory entry not found",
23327
+ root_disabled: "This directory is disabled",
23328
+ connection_failed: "Failed to connect to the device",
23329
+ auth_unsupported: "Device auth method unsupported for files (use key or ssh-agent)",
23330
+ rsync_missing_local: "rsync is not installed on the server",
23331
+ rsync_missing_remote: "rsync is not installed on the remote device",
23332
+ timeout: "Timed out",
23333
+ unknown: "Failed to load"
23334
+ },
23335
+ retry: "Retry (collapse then expand)",
23336
+ install: {
23337
+ button: "Install rsync",
23338
+ scopeLocal: "server",
23339
+ scopeRemote: "remote",
23340
+ connectFailed: "Failed to connect to the device",
23341
+ windowFailed: "Failed to create a window",
23342
+ 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."
23343
+ }
23344
+ },
23345
+ file: {
23346
+ invalidRef: "Invalid file reference",
23347
+ notFound: "File no longer exists",
23348
+ accessDenied: "Access denied",
23349
+ loadFailed: "Failed to load file",
23350
+ isDirectory: "This is a directory",
23351
+ notPreviewable: "Preview is not available for this file type",
23352
+ tooLarge: "File is too large to preview",
23353
+ binary: "Binary file cannot be previewed",
23354
+ download: "Download",
23355
+ openRaw: "Open raw"
23278
23356
  }
23279
23357
  }
23280
23358
  },
@@ -23508,6 +23586,29 @@ Time: {{time}}`,
23508
23586
  clearKeyConfirm: "\u786E\u5B9A\u8981\u6E05\u9664\u6B64 API Key \u5417\uFF1F\u6E05\u9664\u540E\u9700\u8981\u91CD\u65B0\u586B\u5199\u3002",
23509
23587
  loadFailed: "\u52A0\u8F7D\u641C\u7D22\u8BBE\u7F6E\u5931\u8D25",
23510
23588
  saveFailed: "\u4FDD\u5B58\u641C\u7D22\u8BBE\u7F6E\u5931\u8D25"
23589
+ },
23590
+ files: {
23591
+ title: "\u6587\u4EF6",
23592
+ description: "\u914D\u7F6E\u5404\u8BBE\u5907\u4E0B\u53EF\u5728\u300C\u6587\u4EF6\u300D\u6807\u7B7E\u9875\u6D4F\u89C8\u7684\u76EE\u5F55\u3002\u672C\u5730\u8BBE\u5907\u76F4\u63A5\u8BFB\u53D6\uFF0CSSH \u8BBE\u5907\u8D70 rsync\u3002",
23593
+ addRoot: "\u6DFB\u52A0\u76EE\u5F55",
23594
+ roots: "\u76EE\u5F55",
23595
+ empty: "\u5C1A\u672A\u914D\u7F6E\u4EFB\u4F55\u76EE\u5F55",
23596
+ missing: "\u8BBE\u5907\u5DF2\u5931\u6548",
23597
+ modalAddTitle: "\u6DFB\u52A0\u76EE\u5F55",
23598
+ modalEditTitle: "\u7F16\u8F91\u76EE\u5F55",
23599
+ device: "\u8BBE\u5907",
23600
+ devicePlaceholder: "\u9009\u62E9\u8BBE\u5907",
23601
+ noDevices: "\u8FD8\u6CA1\u6709\u8BBE\u5907\uFF0C\u8BF7\u5148\u6DFB\u52A0\u8BBE\u5907",
23602
+ path: "\u8DEF\u5F84",
23603
+ pathPlaceholder: "/\u7EDD\u5BF9\u8DEF\u5F84/\u5230/\u76EE\u5F55",
23604
+ pathHint: "\u6240\u9009\u8BBE\u5907\u4E0A\u7684\u7EDD\u5BF9\u8DEF\u5F84\u3002",
23605
+ enabled: "\u542F\u7528",
23606
+ addFailed: "\u6DFB\u52A0\u76EE\u5F55\u5931\u8D25",
23607
+ updateFailed: "\u66F4\u65B0\u76EE\u5F55\u5931\u8D25",
23608
+ deleteFailed: "\u79FB\u9664\u76EE\u5F55\u5931\u8D25",
23609
+ toggleFailed: "\u66F4\u65B0\u76EE\u5F55\u5931\u8D25",
23610
+ deleteTitle: "\u79FB\u9664\u76EE\u5F55\uFF1F",
23611
+ deleteDesc: "\u5C06\u300C{{path}}\u300D\u79FB\u51FA\u767D\u540D\u5355\uFF1F\u8BE5\u76EE\u5F55\u4E0B\u7684\u6587\u4EF6\u5C06\u4E0D\u518D\u53EF\u8BBF\u95EE\u3002"
23511
23612
  }
23512
23613
  },
23513
23614
  telegram: {
@@ -23686,7 +23787,14 @@ Bot\uFF1A{{botName}}
23686
23787
  watchFireModeInvalid: "\u89E6\u53D1\u6A21\u5F0F\u5FC5\u987B\u662F once \u6216 repeat",
23687
23788
  watchCooldownInvalid: "\u51B7\u5374\u79D2\u6570\u5FC5\u987B\u662F\u4E0D\u5C0F\u4E8E 0 \u7684\u6574\u6570",
23688
23789
  watchAssistDescriptionRequired: "\u8BF7\u63CF\u8FF0\u8981\u5339\u914D\u7684\u5185\u5BB9",
23689
- watchAssistModelUnavailable: "\u6A21\u578B\u8C03\u7528\u5931\u8D25\uFF1A{{detail}}"
23790
+ watchAssistModelUnavailable: "\u6A21\u578B\u8C03\u7528\u5931\u8D25\uFF1A{{detail}}",
23791
+ fileRootInvalid: "\u8DEF\u5F84\u5FC5\u987B\u662F\u5DF2\u5B58\u5728\u7684\u7EDD\u5BF9\u76EE\u5F55",
23792
+ fileOutsideRoots: "\u8DEF\u5F84\u4E0D\u5728\u5141\u8BB8\u7684\u76EE\u5F55\u8303\u56F4\u5185",
23793
+ fileNotADirectory: "\u4E0D\u662F\u76EE\u5F55",
23794
+ fileTooLarge: "\u6587\u4EF6\u8FC7\u5927",
23795
+ fileBinary: "\u4E0D\u652F\u6301\u4E8C\u8FDB\u5236\u6587\u4EF6",
23796
+ fileRootDeviceInvalid: "\u65E0\u6548\u6216\u672A\u77E5\u7684\u8BBE\u5907",
23797
+ fileRootDuplicate: "\u8BE5\u8BBE\u5907\u4E0B\u5DF2\u6DFB\u52A0\u8FC7\u6B64\u76EE\u5F55"
23690
23798
  },
23691
23799
  notification: {
23692
23800
  clickToJump: "\u70B9\u51FB\u8DF3\u8F6C\u5230\u5BF9\u5E94 Pane",
@@ -23976,6 +24084,54 @@ Bot\uFF1A{{botName}}
23976
24084
  validation: {
23977
24085
  deviceNameRequired: "\u8BBE\u5907\u540D\u79F0\u4E3A\u5FC5\u586B\u9879",
23978
24086
  hostRequired: "SSH \u8BBE\u5907\u9700\u8981\u586B\u5199\u4E3B\u673A\u5730\u5740"
24087
+ },
24088
+ files: {
24089
+ title: "\u6587\u4EF6",
24090
+ refresh: "\u5237\u65B0\u6587\u4EF6\u5217\u8868",
24091
+ noRoots: "\u6CA1\u6709\u53EF\u8BBF\u95EE\u7684\u76EE\u5F55\u3002\u8BF7\u5728\u300C\u8BBE\u7F6E \u2192 \u6587\u4EF6\u300D\u4E2D\u6DFB\u52A0\u3002",
24092
+ emptyDir: "\u7A7A\u76EE\u5F55",
24093
+ truncated: "\u6761\u76EE\u8FC7\u591A\uFF0C\u5217\u8868\u5DF2\u622A\u65AD",
24094
+ download: "\u4E0B\u8F7D",
24095
+ error: {
24096
+ invalid: "\u65E0\u6548\u8BF7\u6C42",
24097
+ outside_roots: "\u8DEF\u5F84\u8D85\u51FA\u5141\u8BB8\u7684\u76EE\u5F55\u8303\u56F4",
24098
+ not_found: "\u5DF2\u4E0D\u5B58\u5728",
24099
+ not_a_directory: "\u4E0D\u662F\u76EE\u5F55",
24100
+ is_directory: "\u8FD9\u662F\u4E00\u4E2A\u76EE\u5F55",
24101
+ too_large: "\u6587\u4EF6\u8FC7\u5927\uFF0C\u65E0\u6CD5\u9884\u89C8",
24102
+ binary: "\u4E8C\u8FDB\u5236\u6587\u4EF6\u65E0\u6CD5\u9884\u89C8",
24103
+ permission_denied: "\u65E0\u8BBF\u95EE\u6743\u9650",
24104
+ device_not_found: "\u8BBE\u5907\u4E0D\u5B58\u5728",
24105
+ root_not_found: "\u76EE\u5F55\u9879\u4E0D\u5B58\u5728",
24106
+ root_disabled: "\u8BE5\u76EE\u5F55\u5DF2\u7981\u7528",
24107
+ connection_failed: "\u8FDE\u63A5\u8BBE\u5907\u5931\u8D25",
24108
+ auth_unsupported: "\u8BE5\u8BBE\u5907\u7684\u8BA4\u8BC1\u65B9\u5F0F\u4E0D\u652F\u6301\u6587\u4EF6\u8BBF\u95EE\uFF08\u8BF7\u7528\u5BC6\u94A5\u6216 ssh-agent\uFF09",
24109
+ rsync_missing_local: "\u670D\u52A1\u5668\u4E0A\u672A\u5B89\u88C5 rsync",
24110
+ rsync_missing_remote: "\u8FDC\u7A0B\u8BBE\u5907\u4E0A\u672A\u5B89\u88C5 rsync",
24111
+ timeout: "\u5DF2\u8D85\u65F6",
24112
+ unknown: "\u52A0\u8F7D\u5931\u8D25"
24113
+ },
24114
+ retry: "\u91CD\u8BD5\uFF08\u6536\u8D77\u540E\u518D\u5C55\u5F00\uFF09",
24115
+ install: {
24116
+ button: "\u5B89\u88C5 rsync",
24117
+ scopeLocal: "\u670D\u52A1\u5668",
24118
+ scopeRemote: "\u8FDC\u7A0B",
24119
+ connectFailed: "\u8FDE\u63A5\u8BBE\u5907\u5931\u8D25",
24120
+ windowFailed: "\u521B\u5EFA\u7A97\u53E3\u5931\u8D25",
24121
+ prompt: "\u8BBE\u5907 {{device}}\uFF08{{scope}}\uFF09\u4E0A\u672A\u68C0\u6D4B\u5230 rsync\u3002\u8BF7\u6839\u636E\u7CFB\u7EDF\u9009\u62E9\u5408\u9002\u7684\u547D\u4EE4\u5B89\u88C5 rsync\uFF08\u4F8B\u5982 `brew install rsync`\u3001`sudo apt-get install -y rsync` \u6216 `sudo yum install -y rsync`\uFF09\uFF0C\u5B89\u88C5\u5B8C\u6210\u540E\u56DE\u590D\u6211\u3002"
24122
+ }
24123
+ },
24124
+ file: {
24125
+ invalidRef: "\u65E0\u6548\u7684\u6587\u4EF6\u5F15\u7528",
24126
+ notFound: "\u6587\u4EF6\u5DF2\u4E0D\u5B58\u5728",
24127
+ accessDenied: "\u65E0\u8BBF\u95EE\u6743\u9650",
24128
+ loadFailed: "\u52A0\u8F7D\u6587\u4EF6\u5931\u8D25",
24129
+ isDirectory: "\u8FD9\u662F\u4E00\u4E2A\u76EE\u5F55",
24130
+ notPreviewable: "\u8BE5\u6587\u4EF6\u7C7B\u578B\u4E0D\u652F\u6301\u9884\u89C8",
24131
+ tooLarge: "\u6587\u4EF6\u8FC7\u5927\uFF0C\u65E0\u6CD5\u9884\u89C8",
24132
+ binary: "\u4E8C\u8FDB\u5236\u6587\u4EF6\u65E0\u6CD5\u9884\u89C8",
24133
+ download: "\u4E0B\u8F7D",
24134
+ openRaw: "\u6253\u5F00\u539F\u59CB\u6587\u4EF6"
23979
24135
  }
23980
24136
  }
23981
24137
  },
@@ -24209,6 +24365,29 @@ Bot\uFF1A{{botName}}
24209
24365
  clearKeyConfirm: "\u3053\u306E API \u30AD\u30FC\u3092\u30AF\u30EA\u30A2\u3057\u307E\u3059\u304B\uFF1F\u518D\u5EA6\u5165\u529B\u304C\u5FC5\u8981\u306B\u306A\u308A\u307E\u3059\u3002",
24210
24366
  loadFailed: "\u691C\u7D22\u8A2D\u5B9A\u306E\u8AAD\u307F\u8FBC\u307F\u306B\u5931\u6557\u3057\u307E\u3057\u305F",
24211
24367
  saveFailed: "\u691C\u7D22\u8A2D\u5B9A\u306E\u4FDD\u5B58\u306B\u5931\u6557\u3057\u307E\u3057\u305F"
24368
+ },
24369
+ files: {
24370
+ title: "\u30D5\u30A1\u30A4\u30EB",
24371
+ description: "\u300C\u30D5\u30A1\u30A4\u30EB\u300D\u30BF\u30D6\u3067\u95B2\u89A7\u3067\u304D\u308B\u30C7\u30D0\u30A4\u30B9\u3054\u3068\u306E\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u3092\u8A2D\u5B9A\u3057\u307E\u3059\u3002\u30ED\u30FC\u30AB\u30EB\u306F\u76F4\u63A5\u8AAD\u307F\u53D6\u308A\u3001SSH \u306F rsync \u3092\u4F7F\u7528\u3002",
24372
+ addRoot: "\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u3092\u8FFD\u52A0",
24373
+ roots: "\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA",
24374
+ empty: "\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u304C\u8A2D\u5B9A\u3055\u308C\u3066\u3044\u307E\u305B\u3093",
24375
+ missing: "\u30C7\u30D0\u30A4\u30B9\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093",
24376
+ modalAddTitle: "\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u3092\u8FFD\u52A0",
24377
+ modalEditTitle: "\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u3092\u7DE8\u96C6",
24378
+ device: "\u30C7\u30D0\u30A4\u30B9",
24379
+ devicePlaceholder: "\u30C7\u30D0\u30A4\u30B9\u3092\u9078\u629E",
24380
+ noDevices: "\u30C7\u30D0\u30A4\u30B9\u304C\u3042\u308A\u307E\u305B\u3093\u3002\u5148\u306B\u8FFD\u52A0\u3057\u3066\u304F\u3060\u3055\u3044",
24381
+ path: "\u30D1\u30B9",
24382
+ pathPlaceholder: "/\u7D76\u5BFE\u30D1\u30B9/\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA",
24383
+ pathHint: "\u9078\u629E\u3057\u305F\u30C7\u30D0\u30A4\u30B9\u4E0A\u306E\u7D76\u5BFE\u30D1\u30B9\u3002",
24384
+ enabled: "\u6709\u52B9",
24385
+ addFailed: "\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306E\u8FFD\u52A0\u306B\u5931\u6557\u3057\u307E\u3057\u305F",
24386
+ updateFailed: "\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306E\u66F4\u65B0\u306B\u5931\u6557\u3057\u307E\u3057\u305F",
24387
+ deleteFailed: "\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306E\u524A\u9664\u306B\u5931\u6557\u3057\u307E\u3057\u305F",
24388
+ toggleFailed: "\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306E\u66F4\u65B0\u306B\u5931\u6557\u3057\u307E\u3057\u305F",
24389
+ deleteTitle: "\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u3092\u524A\u9664\u3057\u307E\u3059\u304B\uFF1F",
24390
+ deleteDesc: "\u300C{{path}}\u300D\u3092\u30DB\u30EF\u30A4\u30C8\u30EA\u30B9\u30C8\u304B\u3089\u524A\u9664\u3057\u307E\u3059\u304B\uFF1F\u914D\u4E0B\u306E\u30D5\u30A1\u30A4\u30EB\u306B\u30A2\u30AF\u30BB\u30B9\u3067\u304D\u306A\u304F\u306A\u308A\u307E\u3059\u3002"
24212
24391
  }
24213
24392
  },
24214
24393
  telegram: {
@@ -24387,7 +24566,14 @@ Bot\uFF1A{{botName}}
24387
24566
  watchFireModeInvalid: "\u767A\u706B\u30E2\u30FC\u30C9\u306F once \u307E\u305F\u306F repeat \u3067\u3059",
24388
24567
  watchCooldownInvalid: "\u30AF\u30FC\u30EB\u30C0\u30A6\u30F3\u79D2\u6570\u306F 0 \u4EE5\u4E0A\u306E\u6574\u6570\u3067\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044",
24389
24568
  watchAssistDescriptionRequired: "\u30DE\u30C3\u30C1\u3055\u305B\u305F\u3044\u5185\u5BB9\u3092\u8A18\u8FF0\u3057\u3066\u304F\u3060\u3055\u3044",
24390
- watchAssistModelUnavailable: "\u30E2\u30C7\u30EB\u547C\u3073\u51FA\u3057\u306B\u5931\u6557\u3057\u307E\u3057\u305F\uFF1A{{detail}}"
24569
+ watchAssistModelUnavailable: "\u30E2\u30C7\u30EB\u547C\u3073\u51FA\u3057\u306B\u5931\u6557\u3057\u307E\u3057\u305F\uFF1A{{detail}}",
24570
+ fileRootInvalid: "\u7D76\u5BFE\u30D1\u30B9\u304B\u3064\u65E2\u5B58\u306E\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044",
24571
+ fileOutsideRoots: "\u8A31\u53EF\u3055\u308C\u305F\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306E\u7BC4\u56F2\u5916\u3067\u3059",
24572
+ fileNotADirectory: "\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u3067\u306F\u3042\u308A\u307E\u305B\u3093",
24573
+ fileTooLarge: "\u30D5\u30A1\u30A4\u30EB\u304C\u5927\u304D\u3059\u304E\u307E\u3059",
24574
+ fileBinary: "\u30D0\u30A4\u30CA\u30EA\u30D5\u30A1\u30A4\u30EB\u306F\u30B5\u30DD\u30FC\u30C8\u3055\u308C\u3066\u3044\u307E\u305B\u3093",
24575
+ fileRootDeviceInvalid: "\u7121\u52B9\u307E\u305F\u306F\u4E0D\u660E\u306A\u30C7\u30D0\u30A4\u30B9",
24576
+ fileRootDuplicate: "\u3053\u306E\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306F\u3053\u306E\u30C7\u30D0\u30A4\u30B9\u306B\u65E2\u306B\u8FFD\u52A0\u3055\u308C\u3066\u3044\u307E\u3059"
24391
24577
  },
24392
24578
  notification: {
24393
24579
  clickToJump: "\u5BFE\u5FDC\u3059\u308B\u30DA\u30A4\u30F3\u306B\u30B8\u30E3\u30F3\u30D7",
@@ -24677,6 +24863,54 @@ Bot\uFF1A{{botName}}
24677
24863
  validation: {
24678
24864
  deviceNameRequired: "\u30C7\u30D0\u30A4\u30B9\u540D\u306F\u5FC5\u9808\u3067\u3059",
24679
24865
  hostRequired: "SSH \u30C7\u30D0\u30A4\u30B9\u306B\u306F\u30DB\u30B9\u30C8\u30A2\u30C9\u30EC\u30B9\u304C\u5FC5\u8981\u3067\u3059"
24866
+ },
24867
+ files: {
24868
+ title: "\u30D5\u30A1\u30A4\u30EB",
24869
+ refresh: "\u30D5\u30A1\u30A4\u30EB\u4E00\u89A7\u3092\u66F4\u65B0",
24870
+ noRoots: "\u30A2\u30AF\u30BB\u30B9\u53EF\u80FD\u306A\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u304C\u3042\u308A\u307E\u305B\u3093\u3002\u300C\u8A2D\u5B9A \u2192 \u30D5\u30A1\u30A4\u30EB\u300D\u3067\u8FFD\u52A0\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
24871
+ emptyDir: "\u7A7A\u306E\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA",
24872
+ truncated: "\u9805\u76EE\u304C\u591A\u3059\u304E\u308B\u305F\u3081\u4E00\u89A7\u3092\u7701\u7565\u3057\u307E\u3057\u305F",
24873
+ download: "\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9",
24874
+ error: {
24875
+ invalid: "\u4E0D\u6B63\u306A\u30EA\u30AF\u30A8\u30B9\u30C8",
24876
+ outside_roots: "\u8A31\u53EF\u3055\u308C\u305F\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306E\u7BC4\u56F2\u5916\u3067\u3059",
24877
+ not_found: "\u3059\u3067\u306B\u5B58\u5728\u3057\u307E\u305B\u3093",
24878
+ not_a_directory: "\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u3067\u306F\u3042\u308A\u307E\u305B\u3093",
24879
+ is_directory: "\u3053\u308C\u306F\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u3067\u3059",
24880
+ too_large: "\u30D5\u30A1\u30A4\u30EB\u304C\u5927\u304D\u3059\u304E\u3066\u30D7\u30EC\u30D3\u30E5\u30FC\u3067\u304D\u307E\u305B\u3093",
24881
+ binary: "\u30D0\u30A4\u30CA\u30EA\u30D5\u30A1\u30A4\u30EB\u306F\u30D7\u30EC\u30D3\u30E5\u30FC\u3067\u304D\u307E\u305B\u3093",
24882
+ permission_denied: "\u30A2\u30AF\u30BB\u30B9\u304C\u62D2\u5426\u3055\u308C\u307E\u3057\u305F",
24883
+ device_not_found: "\u30C7\u30D0\u30A4\u30B9\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093",
24884
+ root_not_found: "\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u9805\u76EE\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093",
24885
+ root_disabled: "\u3053\u306E\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306F\u7121\u52B9\u3067\u3059",
24886
+ connection_failed: "\u30C7\u30D0\u30A4\u30B9\u3078\u306E\u63A5\u7D9A\u306B\u5931\u6557\u3057\u307E\u3057\u305F",
24887
+ auth_unsupported: "\u3053\u306E\u30C7\u30D0\u30A4\u30B9\u306E\u8A8D\u8A3C\u65B9\u5F0F\u306F\u30D5\u30A1\u30A4\u30EB\u30A2\u30AF\u30BB\u30B9\u306B\u975E\u5BFE\u5FDC\u3067\u3059\uFF08\u9375\u304B ssh-agent \u3092\u4F7F\u7528\uFF09",
24888
+ rsync_missing_local: "\u30B5\u30FC\u30D0\u30FC\u306B rsync \u304C\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u3055\u308C\u3066\u3044\u307E\u305B\u3093",
24889
+ rsync_missing_remote: "\u30EA\u30E2\u30FC\u30C8\u30C7\u30D0\u30A4\u30B9\u306B rsync \u304C\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u3055\u308C\u3066\u3044\u307E\u305B\u3093",
24890
+ timeout: "\u30BF\u30A4\u30E0\u30A2\u30A6\u30C8\u3057\u307E\u3057\u305F",
24891
+ unknown: "\u8AAD\u307F\u8FBC\u307F\u306B\u5931\u6557\u3057\u307E\u3057\u305F"
24892
+ },
24893
+ retry: "\u518D\u8A66\u884C\uFF08\u6298\u308A\u305F\u305F\u3093\u3067\u518D\u5C55\u958B\uFF09",
24894
+ install: {
24895
+ button: "rsync \u3092\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB",
24896
+ scopeLocal: "\u30B5\u30FC\u30D0\u30FC",
24897
+ scopeRemote: "\u30EA\u30E2\u30FC\u30C8",
24898
+ connectFailed: "\u30C7\u30D0\u30A4\u30B9\u3078\u306E\u63A5\u7D9A\u306B\u5931\u6557\u3057\u307E\u3057\u305F",
24899
+ windowFailed: "\u30A6\u30A3\u30F3\u30C9\u30A6\u306E\u4F5C\u6210\u306B\u5931\u6557\u3057\u307E\u3057\u305F",
24900
+ prompt: "{{device}}\uFF08{{scope}}\uFF09\u306B rsync \u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3002\u30B7\u30B9\u30C6\u30E0\u306B\u5408\u308F\u305B\u305F\u65B9\u6CD5\u3067 rsync \u3092\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u3057\uFF08\u4F8B: `brew install rsync`\u3001`sudo apt-get install -y rsync`\u3001`sudo yum install -y rsync`\uFF09\u3001\u5B8C\u4E86\u3057\u305F\u3089\u8FD4\u4FE1\u3057\u3066\u304F\u3060\u3055\u3044\u3002"
24901
+ }
24902
+ },
24903
+ file: {
24904
+ invalidRef: "\u7121\u52B9\u306A\u30D5\u30A1\u30A4\u30EB\u53C2\u7167\u3067\u3059",
24905
+ notFound: "\u30D5\u30A1\u30A4\u30EB\u306F\u5B58\u5728\u3057\u307E\u305B\u3093",
24906
+ accessDenied: "\u30A2\u30AF\u30BB\u30B9\u304C\u62D2\u5426\u3055\u308C\u307E\u3057\u305F",
24907
+ loadFailed: "\u30D5\u30A1\u30A4\u30EB\u306E\u8AAD\u307F\u8FBC\u307F\u306B\u5931\u6557\u3057\u307E\u3057\u305F",
24908
+ isDirectory: "\u3053\u308C\u306F\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u3067\u3059",
24909
+ notPreviewable: "\u3053\u306E\u30D5\u30A1\u30A4\u30EB\u5F62\u5F0F\u306F\u30D7\u30EC\u30D3\u30E5\u30FC\u3067\u304D\u307E\u305B\u3093",
24910
+ tooLarge: "\u30D5\u30A1\u30A4\u30EB\u304C\u5927\u304D\u3059\u304E\u3066\u30D7\u30EC\u30D3\u30E5\u30FC\u3067\u304D\u307E\u305B\u3093",
24911
+ binary: "\u30D0\u30A4\u30CA\u30EA\u30D5\u30A1\u30A4\u30EB\u306F\u30D7\u30EC\u30D3\u30E5\u30FC\u3067\u304D\u307E\u305B\u3093",
24912
+ download: "\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9",
24913
+ openRaw: "\u5143\u30D5\u30A1\u30A4\u30EB\u3092\u958B\u304F"
24680
24914
  }
24681
24915
  }
24682
24916
  }
@@ -32196,6 +32430,7 @@ __export(exports_schema2, {
32196
32430
  telegramBotChats: () => telegramBotChats,
32197
32431
  siteSettings: () => siteSettings,
32198
32432
  llmProviders: () => llmProviders,
32433
+ fileRoots: () => fileRoots,
32199
32434
  devices: () => devices,
32200
32435
  deviceTreeOrder: () => deviceTreeOrder,
32201
32436
  deviceRuntimeStatus: () => deviceRuntimeStatus,
@@ -32394,6 +32629,14 @@ var deviceTreeOrder = sqliteTable("device_tree_order", {
32394
32629
  panes: text("panes", { mode: "json" }).$type().notNull().default({}),
32395
32630
  updatedAt: text("updated_at").notNull()
32396
32631
  });
32632
+ var fileRoots = sqliteTable("file_roots", {
32633
+ id: text("id").primaryKey(),
32634
+ deviceId: text("device_id").notNull().references(() => devices.id, { onDelete: "cascade" }),
32635
+ path: text("path").notNull(),
32636
+ enabled: integer("enabled", { mode: "boolean" }).notNull().default(true),
32637
+ sortOrder: integer("sort_order").notNull().default(0),
32638
+ createdAt: text("created_at").notNull()
32639
+ }, (table) => [unique("file_roots_device_path_unique").on(table.deviceId, table.path)]);
32397
32640
  var telegramBotChats = sqliteTable("telegram_bot_chats", {
32398
32641
  id: text("id").primaryKey(),
32399
32642
  botId: text("bot_id").notNull().references(() => telegramBots.id, { onDelete: "cascade" }),
@@ -33154,7 +33397,7 @@ function decideAgentConfirmation(id, decision) {
33154
33397
  return updated ?? null;
33155
33398
  }
33156
33399
 
33157
- // ../../node_modules/.bun/gramio@0.4.12+cb432ad7c9c526f6/node_modules/gramio/dist/index.js
33400
+ // ../../node_modules/.bun/gramio@0.4.12+7be50f8974dcb86c/node_modules/gramio/dist/index.js
33158
33401
  var exports_dist5 = {};
33159
33402
  __export(exports_dist5, {
33160
33403
  webhookHandler: () => webhookHandler,
@@ -53088,7 +53331,7 @@ class MediaUpload {
53088
53331
  return new File([text2], filename);
53089
53332
  }
53090
53333
  }
53091
- // ../../node_modules/.bun/@gramio+format@0.3.4/node_modules/@gramio/format/dist/index.js
53334
+ // ../../node_modules/.bun/@gramio+format@0.3.4+32af5fe46ea567aa/node_modules/@gramio/format/dist/index.js
53092
53335
  var exports_dist3 = {};
53093
53336
  __export(exports_dist3, {
53094
53337
  underline: () => underline,
@@ -53553,10 +53796,10 @@ function formatSaveIndents(stringParts, ...strings) {
53553
53796
  return processRawFormat([...stringParts], strings);
53554
53797
  }
53555
53798
 
53556
- // ../../node_modules/.bun/gramio@0.4.12+cb432ad7c9c526f6/node_modules/gramio/dist/index.js
53799
+ // ../../node_modules/.bun/gramio@0.4.12+7be50f8974dcb86c/node_modules/gramio/dist/index.js
53557
53800
  var import_debug2 = __toESM(require_src2(), 1);
53558
53801
 
53559
- // ../../node_modules/.bun/gramio@0.4.12+cb432ad7c9c526f6/node_modules/gramio/dist/utils-CJfJNxc_.js
53802
+ // ../../node_modules/.bun/gramio@0.4.12+7be50f8974dcb86c/node_modules/gramio/dist/utils-CJfJNxc_.js
53560
53803
  var exports_utils_CJfJNxc_ = {};
53561
53804
  __export(exports_utils_CJfJNxc_, {
53562
53805
  w: () => withRetries,
@@ -54515,7 +54758,7 @@ class InlineQueryResult {
54515
54758
  }
54516
54759
  Symbol.metadata ??= Symbol("Symbol.metadata");
54517
54760
 
54518
- // ../../node_modules/.bun/gramio@0.4.12+cb432ad7c9c526f6/node_modules/gramio/dist/index.js
54761
+ // ../../node_modules/.bun/gramio@0.4.12+7be50f8974dcb86c/node_modules/gramio/dist/index.js
54519
54762
  class Composer2 {
54520
54763
  composer = Composer.builder();
54521
54764
  length = 0;
@@ -102370,6 +102613,1037 @@ function json3(data, status = 200) {
102370
102613
  });
102371
102614
  }
102372
102615
 
102616
+ // ../../apps/gateway/src/db/file-roots.ts
102617
+ function getFileRoots() {
102618
+ const orm = getDb();
102619
+ return orm.select().from(fileRoots).orderBy(asc(fileRoots.sortOrder), asc(fileRoots.path)).all();
102620
+ }
102621
+ function getFileRootById(id) {
102622
+ const orm = getDb();
102623
+ return orm.select().from(fileRoots).where(eq(fileRoots.id, id)).get() ?? null;
102624
+ }
102625
+ function createFileRoot(input) {
102626
+ const orm = getDb();
102627
+ const maxRow = orm.select({ value: max(fileRoots.sortOrder) }).from(fileRoots).get();
102628
+ const record2 = {
102629
+ id: v4_default(),
102630
+ deviceId: input.deviceId,
102631
+ path: input.path,
102632
+ enabled: input.enabled ?? true,
102633
+ sortOrder: (maxRow?.value ?? -1) + 1,
102634
+ createdAt: new Date().toISOString()
102635
+ };
102636
+ orm.insert(fileRoots).values(record2).run();
102637
+ return record2;
102638
+ }
102639
+ function updateFileRoot(id, updates) {
102640
+ const current = getFileRootById(id);
102641
+ if (!current)
102642
+ return null;
102643
+ const next = {
102644
+ ...current,
102645
+ path: updates.path ?? current.path,
102646
+ enabled: updates.enabled ?? current.enabled,
102647
+ sortOrder: updates.sortOrder ?? current.sortOrder
102648
+ };
102649
+ const orm = getDb();
102650
+ orm.update(fileRoots).set({ path: next.path, enabled: next.enabled, sortOrder: next.sortOrder }).where(eq(fileRoots.id, id)).run();
102651
+ return next;
102652
+ }
102653
+ function deleteFileRoot(id) {
102654
+ const orm = getDb();
102655
+ const existing = orm.select({ id: fileRoots.id }).from(fileRoots).where(eq(fileRoots.id, id)).get();
102656
+ if (!existing)
102657
+ return false;
102658
+ orm.delete(fileRoots).where(eq(fileRoots.id, id)).run();
102659
+ return true;
102660
+ }
102661
+
102662
+ // ../../apps/gateway/src/files/device-storage.ts
102663
+ import { mkdtempSync as mkdtempSync2, readFileSync as readFileSync3, realpathSync, rmSync as rmSync2 } from "fs";
102664
+ import { tmpdir as tmpdir2 } from "os";
102665
+ import { join as join5 } from "path";
102666
+
102667
+ // ../../apps/gateway/src/files/categorize.ts
102668
+ import { extname } from "path";
102669
+ var MAX_ENTRIES = 2000;
102670
+ var MAX_TEXT_BYTES = 2 * 1024 * 1024;
102671
+ var MARKDOWN_EXTS = new Set(["md", "markdown", "mdx"]);
102672
+ var IMAGE_EXTS = new Set(["png", "jpg", "jpeg", "gif", "webp", "bmp", "ico", "svg", "avif"]);
102673
+ var PDF_EXTS = new Set(["pdf"]);
102674
+ var ARCHIVE_EXTS = new Set(["zip", "tar", "gz", "tgz", "bz2", "xz", "7z", "rar", "zst"]);
102675
+ var AUDIO_EXTS = new Set(["mp3", "wav", "ogg", "flac", "m4a", "aac"]);
102676
+ var VIDEO_EXTS = new Set(["mp4", "webm", "mkv", "mov", "avi", "m4v"]);
102677
+ var TEXT_EXTS = new Set(["txt", "text", "log", "csv", "tsv", "rtf"]);
102678
+ var CODE_EXTS = new Set([
102679
+ "ts",
102680
+ "tsx",
102681
+ "js",
102682
+ "jsx",
102683
+ "mjs",
102684
+ "cjs",
102685
+ "json",
102686
+ "jsonc",
102687
+ "json5",
102688
+ "css",
102689
+ "scss",
102690
+ "sass",
102691
+ "less",
102692
+ "html",
102693
+ "htm",
102694
+ "xml",
102695
+ "vue",
102696
+ "svelte",
102697
+ "astro",
102698
+ "py",
102699
+ "pyi",
102700
+ "rb",
102701
+ "go",
102702
+ "rs",
102703
+ "java",
102704
+ "kt",
102705
+ "kts",
102706
+ "c",
102707
+ "h",
102708
+ "cpp",
102709
+ "cc",
102710
+ "cxx",
102711
+ "hpp",
102712
+ "hh",
102713
+ "cs",
102714
+ "php",
102715
+ "swift",
102716
+ "m",
102717
+ "mm",
102718
+ "sh",
102719
+ "bash",
102720
+ "zsh",
102721
+ "fish",
102722
+ "ps1",
102723
+ "bat",
102724
+ "cmd",
102725
+ "sql",
102726
+ "toml",
102727
+ "yaml",
102728
+ "yml",
102729
+ "ini",
102730
+ "cfg",
102731
+ "conf",
102732
+ "env",
102733
+ "properties",
102734
+ "gradle",
102735
+ "lua",
102736
+ "r",
102737
+ "dart",
102738
+ "scala",
102739
+ "clj",
102740
+ "cljs",
102741
+ "ex",
102742
+ "exs",
102743
+ "erl",
102744
+ "hs",
102745
+ "ml",
102746
+ "mli",
102747
+ "pl",
102748
+ "pm",
102749
+ "vim",
102750
+ "lock",
102751
+ "tf",
102752
+ "tfvars",
102753
+ "proto",
102754
+ "graphql",
102755
+ "gql",
102756
+ "prisma",
102757
+ "dockerfile",
102758
+ "makefile",
102759
+ "cmake",
102760
+ "nix",
102761
+ "zig",
102762
+ "d",
102763
+ "jl",
102764
+ "groovy",
102765
+ "patch",
102766
+ "diff"
102767
+ ]);
102768
+ var KNOWN_NOEXT = new Set([
102769
+ "makefile",
102770
+ "dockerfile",
102771
+ "license",
102772
+ "readme",
102773
+ "changelog",
102774
+ "authors",
102775
+ "copying",
102776
+ "notice",
102777
+ "procfile",
102778
+ "gemfile",
102779
+ "rakefile",
102780
+ "brewfile",
102781
+ "caddyfile",
102782
+ ".gitignore",
102783
+ ".gitattributes",
102784
+ ".gitmodules",
102785
+ ".env",
102786
+ ".editorconfig",
102787
+ ".npmrc",
102788
+ ".nvmrc",
102789
+ ".prettierrc",
102790
+ ".eslintrc",
102791
+ ".babelrc",
102792
+ ".dockerignore",
102793
+ ".zshrc",
102794
+ ".bashrc",
102795
+ ".profile"
102796
+ ]);
102797
+ var MIME_MAP = {
102798
+ png: "image/png",
102799
+ jpg: "image/jpeg",
102800
+ jpeg: "image/jpeg",
102801
+ gif: "image/gif",
102802
+ webp: "image/webp",
102803
+ bmp: "image/bmp",
102804
+ ico: "image/x-icon",
102805
+ svg: "image/svg+xml",
102806
+ avif: "image/avif",
102807
+ pdf: "application/pdf",
102808
+ mp3: "audio/mpeg",
102809
+ wav: "audio/wav",
102810
+ ogg: "audio/ogg",
102811
+ flac: "audio/flac",
102812
+ m4a: "audio/mp4",
102813
+ aac: "audio/aac",
102814
+ mp4: "video/mp4",
102815
+ webm: "video/webm",
102816
+ mkv: "video/x-matroska",
102817
+ mov: "video/quicktime",
102818
+ zip: "application/zip",
102819
+ gz: "application/gzip",
102820
+ tar: "application/x-tar",
102821
+ json: "application/json; charset=utf-8",
102822
+ txt: "text/plain; charset=utf-8"
102823
+ };
102824
+ function extOf(name24) {
102825
+ return extname(name24).slice(1).toLowerCase();
102826
+ }
102827
+ function categorize(name24) {
102828
+ const lower = name24.toLowerCase();
102829
+ const ext = extOf(lower);
102830
+ if (MARKDOWN_EXTS.has(ext))
102831
+ return "markdown";
102832
+ if (IMAGE_EXTS.has(ext))
102833
+ return "image";
102834
+ if (PDF_EXTS.has(ext))
102835
+ return "pdf";
102836
+ if (ARCHIVE_EXTS.has(ext))
102837
+ return "archive";
102838
+ if (AUDIO_EXTS.has(ext))
102839
+ return "audio";
102840
+ if (VIDEO_EXTS.has(ext))
102841
+ return "video";
102842
+ if (CODE_EXTS.has(ext))
102843
+ return "code";
102844
+ if (TEXT_EXTS.has(ext))
102845
+ return "text";
102846
+ if (!ext && KNOWN_NOEXT.has(lower))
102847
+ return "code";
102848
+ return "other";
102849
+ }
102850
+ function mimeOf(name24) {
102851
+ return MIME_MAP[extOf(name24)] ?? null;
102852
+ }
102853
+
102854
+ // ../../apps/gateway/src/files/queue.ts
102855
+ var GLOBAL_MAX_CONCURRENT = 4;
102856
+ var active = 0;
102857
+ var globalWaiters = [];
102858
+ var deviceChains = new Map;
102859
+ function acquireGlobalSlot() {
102860
+ if (active < GLOBAL_MAX_CONCURRENT) {
102861
+ active += 1;
102862
+ return Promise.resolve();
102863
+ }
102864
+ return new Promise((resolve3) => {
102865
+ globalWaiters.push(() => {
102866
+ active += 1;
102867
+ resolve3();
102868
+ });
102869
+ });
102870
+ }
102871
+ function releaseGlobalSlot() {
102872
+ active -= 1;
102873
+ const next = globalWaiters.shift();
102874
+ if (next)
102875
+ next();
102876
+ }
102877
+ function enqueueDeviceJob(deviceId, job) {
102878
+ const prev = deviceChains.get(deviceId) ?? Promise.resolve();
102879
+ const run = prev.catch(() => {
102880
+ return;
102881
+ }).then(async () => {
102882
+ await acquireGlobalSlot();
102883
+ try {
102884
+ return await job();
102885
+ } finally {
102886
+ releaseGlobalSlot();
102887
+ }
102888
+ });
102889
+ deviceChains.set(deviceId, run.then(() => {
102890
+ return;
102891
+ }, () => {
102892
+ return;
102893
+ }));
102894
+ return run;
102895
+ }
102896
+
102897
+ // ../../apps/gateway/src/files/rsync.ts
102898
+ class RsyncMissingLocalError extends Error {
102899
+ constructor(message) {
102900
+ super(message);
102901
+ this.name = "RsyncMissingLocalError";
102902
+ }
102903
+ }
102904
+ var SENSITIVE_ENV_KEYS = new Set(["DATABASE_URL", "NODE_ENV", "GATEWAY_PORT", "FE_PORT"]);
102905
+ function baseSubprocessEnv() {
102906
+ const out = {};
102907
+ for (const [k, v] of Object.entries(process.env)) {
102908
+ if (v === undefined)
102909
+ continue;
102910
+ if (k.startsWith("TMEX_"))
102911
+ continue;
102912
+ if (SENSITIVE_ENV_KEYS.has(k))
102913
+ continue;
102914
+ out[k] = v;
102915
+ }
102916
+ out.LC_ALL = "C";
102917
+ return out;
102918
+ }
102919
+ async function runRsync(argv, opts = {}) {
102920
+ const timeoutMs = opts.timeoutMs ?? 20000;
102921
+ let proc;
102922
+ try {
102923
+ proc = Bun.spawn(["rsync", ...argv], {
102924
+ env: { ...baseSubprocessEnv(), ...opts.env },
102925
+ stdout: "pipe",
102926
+ stderr: "pipe",
102927
+ stdin: "ignore"
102928
+ });
102929
+ } catch (error51) {
102930
+ throw new RsyncMissingLocalError(error51 instanceof Error ? error51.message : String(error51));
102931
+ }
102932
+ let timedOut = false;
102933
+ const killTimer = setTimeout(() => {
102934
+ timedOut = true;
102935
+ try {
102936
+ proc.kill();
102937
+ } catch {}
102938
+ }, timeoutMs);
102939
+ const onAbort = () => {
102940
+ try {
102941
+ proc.kill();
102942
+ } catch {}
102943
+ };
102944
+ opts.signal?.addEventListener("abort", onAbort, { once: true });
102945
+ try {
102946
+ const [stdout, stderr, exitCode] = await Promise.all([
102947
+ new Response(proc.stdout).text(),
102948
+ new Response(proc.stderr).text(),
102949
+ proc.exited
102950
+ ]);
102951
+ if (timedOut) {
102952
+ return { stdout, stderr: `${stderr}
102953
+ [tmex] rsync timed out`, exitCode: 124 };
102954
+ }
102955
+ return { stdout, stderr, exitCode };
102956
+ } finally {
102957
+ clearTimeout(killTimer);
102958
+ opts.signal?.removeEventListener("abort", onAbort);
102959
+ }
102960
+ }
102961
+ var LIST_RE = /^([dlspbc-][rwxsStT-]{9}[.+@]?)\s+([\d,]+)\s+(\d{4})\/(\d{2})\/(\d{2})\s+(\d{2}):(\d{2}):(\d{2})\s+(.*)$/;
102962
+ function typeFromPerms(perms) {
102963
+ switch (perms[0]) {
102964
+ case "d":
102965
+ return "dir";
102966
+ case "l":
102967
+ return "symlink";
102968
+ case "-":
102969
+ return "file";
102970
+ default:
102971
+ return "other";
102972
+ }
102973
+ }
102974
+ function parseListOnly(stdout) {
102975
+ const entries = [];
102976
+ for (const rawLine of stdout.split(`
102977
+ `)) {
102978
+ const line = rawLine.replace(/\r$/, "");
102979
+ const m = LIST_RE.exec(line);
102980
+ if (!m)
102981
+ continue;
102982
+ const type = typeFromPerms(m[1]);
102983
+ let name24 = m[9];
102984
+ if (type === "symlink") {
102985
+ const arrow = name24.indexOf(" -> ");
102986
+ if (arrow >= 0)
102987
+ name24 = name24.slice(0, arrow);
102988
+ }
102989
+ if (name24 === "" || name24 === "." || name24 === "..")
102990
+ continue;
102991
+ const sizeNum = Number.parseInt(m[2].replace(/,/g, ""), 10);
102992
+ const size = type === "dir" ? null : Number.isNaN(sizeNum) ? null : sizeNum;
102993
+ const modifiedAt = `${m[3]}-${m[4]}-${m[5]}T${m[6]}:${m[7]}:${m[8]}`;
102994
+ entries.push({ name: name24, type, size, modifiedAt });
102995
+ }
102996
+ return entries;
102997
+ }
102998
+ function classifyRsyncFailure(exitCode, stderr) {
102999
+ const s = stderr.toLowerCase();
103000
+ if (exitCode === 124)
103001
+ return "timeout";
103002
+ if (/command not found|rsync: not found|rsync error: error in rsync protocol.*\(code 127\)/.test(s)) {
103003
+ return "rsync_missing_remote";
103004
+ }
103005
+ if (/rsync: not found|exec: rsync: not found|bash: rsync/.test(s))
103006
+ return "rsync_missing_remote";
103007
+ if (/host key verification failed|could not resolve hostname|connection refused|connection timed out|no route to host|operation timed out|ssh: connect to host/.test(s)) {
103008
+ return "connection_failed";
103009
+ }
103010
+ if (/permission denied \((publickey|password|keyboard-interactive|gssapi|hostbased)/.test(s) || /too many authentication failures|authentication failed/.test(s)) {
103011
+ return "connection_failed";
103012
+ }
103013
+ if (/permission denied/.test(s))
103014
+ return "permission_denied";
103015
+ if (/no such file or directory|change_dir.*failed|link_stat.*failed|failed to stat/.test(s)) {
103016
+ return "not_found";
103017
+ }
103018
+ return "unknown";
103019
+ }
103020
+
103021
+ // ../../apps/gateway/src/files/ssh-command.ts
103022
+ import { chmodSync, mkdtempSync, rmSync, writeFileSync } from "fs";
103023
+ import { tmpdir } from "os";
103024
+ import { join as join4 } from "path";
103025
+ class RsyncAuthError extends Error {
103026
+ code;
103027
+ constructor(code2, message) {
103028
+ super(message);
103029
+ this.name = "RsyncAuthError";
103030
+ this.code = code2;
103031
+ }
103032
+ }
103033
+ var SSH_BASE_OPTS = ["-o", "StrictHostKeyChecking=accept-new", "-o", "ConnectTimeout=10"];
103034
+ function setupAskpass(secret) {
103035
+ const dir2 = mkdtempSync(join4(tmpdir(), "tmex-rsync-ap-"));
103036
+ const scriptPath = join4(dir2, "askpass.sh");
103037
+ writeFileSync(scriptPath, `#!/bin/sh
103038
+ printf '%s\\n' "$TMEX_RSYNC_SECRET"
103039
+ `, { mode: 448 });
103040
+ chmodSync(scriptPath, 448);
103041
+ return {
103042
+ env: {
103043
+ SSH_ASKPASS: scriptPath,
103044
+ SSH_ASKPASS_REQUIRE: "force",
103045
+ TMEX_RSYNC_SECRET: secret,
103046
+ DISPLAY: process.env.DISPLAY || ":0"
103047
+ },
103048
+ cleanup: () => {
103049
+ try {
103050
+ rmSync(dir2, { recursive: true, force: true });
103051
+ } catch {}
103052
+ }
103053
+ };
103054
+ }
103055
+ function writeTempKey(privateKey) {
103056
+ const dir2 = mkdtempSync(join4(tmpdir(), "tmex-rsync-key-"));
103057
+ const keyPath = join4(dir2, "id");
103058
+ writeFileSync(keyPath, privateKey, { mode: 384 });
103059
+ chmodSync(keyPath, 384);
103060
+ return {
103061
+ keyPath,
103062
+ cleanup: () => {
103063
+ try {
103064
+ rmSync(dir2, { recursive: true, force: true });
103065
+ } catch {}
103066
+ }
103067
+ };
103068
+ }
103069
+ async function buildRsyncDeviceSpec(device, decrypt2 = decryptWithContext, resolveConfig = resolveSshConnectConfig) {
103070
+ if (device.type === "local") {
103071
+ return { targetPrefix: "", rsh: undefined, env: {}, cleanup: () => {} };
103072
+ }
103073
+ if (device.authMode === "configRef" && device.sshConfigRef?.trim()) {
103074
+ const alias = device.sshConfigRef.trim();
103075
+ return {
103076
+ targetPrefix: `${alias}:`,
103077
+ rsh: ["ssh", ...SSH_BASE_OPTS, "-o", "BatchMode=yes"].join(" "),
103078
+ env: {},
103079
+ cleanup: () => {}
103080
+ };
103081
+ }
103082
+ const cfg = await resolveConfig(device, decrypt2);
103083
+ if (!cfg.host) {
103084
+ throw new RsyncAuthError("connection_failed", "SSH \u8BBE\u5907\u7F3A\u5C11 host");
103085
+ }
103086
+ const port = cfg.port ?? 22;
103087
+ const target = cfg.username ? `${cfg.username}@${cfg.host}` : cfg.host;
103088
+ const sshArgs = ["ssh", "-p", String(port), ...SSH_BASE_OPTS];
103089
+ const env = {};
103090
+ const cleanups = [];
103091
+ if (cfg.privateKey) {
103092
+ const { keyPath, cleanup } = writeTempKey(String(cfg.privateKey));
103093
+ sshArgs.push("-i", keyPath, "-o", "IdentitiesOnly=yes");
103094
+ cleanups.push(cleanup);
103095
+ if (cfg.agent) {
103096
+ env.SSH_AUTH_SOCK = String(cfg.agent);
103097
+ sshArgs.push("-o", "BatchMode=yes");
103098
+ } else if (cfg.passphrase) {
103099
+ const ap = setupAskpass(String(cfg.passphrase));
103100
+ Object.assign(env, ap.env);
103101
+ cleanups.push(ap.cleanup);
103102
+ } else {
103103
+ sshArgs.push("-o", "BatchMode=yes");
103104
+ }
103105
+ } else if (cfg.agent) {
103106
+ env.SSH_AUTH_SOCK = String(cfg.agent);
103107
+ sshArgs.push("-o", "BatchMode=yes");
103108
+ } else if (cfg.password) {
103109
+ const ap = setupAskpass(String(cfg.password));
103110
+ Object.assign(env, ap.env);
103111
+ cleanups.push(ap.cleanup);
103112
+ sshArgs.push("-o", "PreferredAuthentications=password,keyboard-interactive", "-o", "NumberOfPasswordPrompts=1");
103113
+ } else {
103114
+ throw new RsyncAuthError("auth_unsupported", "\u672A\u627E\u5230\u53EF\u7528\u4E8E rsync \u7684\u8BA4\u8BC1\u65B9\u5F0F\uFF08\u5BC6\u94A5 / ssh-agent / \u5BC6\u7801\uFF09");
103115
+ }
103116
+ return {
103117
+ targetPrefix: `${target}:`,
103118
+ rsh: sshArgs.join(" "),
103119
+ env,
103120
+ cleanup: () => {
103121
+ for (const c of cleanups)
103122
+ c();
103123
+ }
103124
+ };
103125
+ }
103126
+ function rsyncTargetArg(spec, remotePath) {
103127
+ if (!spec.targetPrefix)
103128
+ return remotePath;
103129
+ return `${spec.targetPrefix}${quoteShellArg(remotePath)}`;
103130
+ }
103131
+ function rsyncListArgs(spec, remotePath) {
103132
+ const args = ["--list-only"];
103133
+ if (spec.rsh)
103134
+ args.push("-e", spec.rsh);
103135
+ args.push(rsyncTargetArg(spec, remotePath));
103136
+ return args;
103137
+ }
103138
+ function rsyncCopyArgs(spec, remotePath, dest) {
103139
+ const args = ["-L"];
103140
+ if (spec.rsh)
103141
+ args.push("-e", spec.rsh);
103142
+ args.push(rsyncTargetArg(spec, remotePath), dest);
103143
+ return args;
103144
+ }
103145
+
103146
+ // ../../apps/gateway/src/files/device-storage.ts
103147
+ var RAW_MAX_BYTES = 50 * 1024 * 1024;
103148
+ var LIST_TIMEOUT_MS = 20000;
103149
+ var COPY_TIMEOUT_MS = 60000;
103150
+ function ok(data) {
103151
+ return { ok: true, data };
103152
+ }
103153
+ function fail(code2, detail) {
103154
+ return { ok: false, code: code2, detail };
103155
+ }
103156
+ function posixNormalize(p) {
103157
+ const isAbs = p.startsWith("/");
103158
+ const out = [];
103159
+ for (const seg of p.split("/")) {
103160
+ if (seg === "" || seg === ".")
103161
+ continue;
103162
+ if (seg === "..") {
103163
+ if (out.length && out[out.length - 1] !== "..")
103164
+ out.pop();
103165
+ else if (!isAbs)
103166
+ out.push("..");
103167
+ continue;
103168
+ }
103169
+ out.push(seg);
103170
+ }
103171
+ const joined = out.join("/");
103172
+ return isAbs ? `/${joined}` : joined;
103173
+ }
103174
+ function posixJoin(dir2, name24) {
103175
+ return dir2 === "/" ? `/${name24}` : `${dir2}/${name24}`;
103176
+ }
103177
+ function posixBasename(p) {
103178
+ const i = p.lastIndexOf("/");
103179
+ const base = i >= 0 ? p.slice(i + 1) : p;
103180
+ return base || p;
103181
+ }
103182
+ function checkAndNormalize(device, rootPath, inputPath) {
103183
+ if (!inputPath || !inputPath.startsWith("/"))
103184
+ return { ok: false, code: "invalid" };
103185
+ const normRoot = posixNormalize(rootPath);
103186
+ const normPath = posixNormalize(inputPath);
103187
+ const prefix = normRoot === "/" ? "/" : `${normRoot}/`;
103188
+ if (!(normPath === normRoot || normPath.startsWith(prefix))) {
103189
+ return { ok: false, code: "outside_roots" };
103190
+ }
103191
+ if (device.type === "local") {
103192
+ let realRoot;
103193
+ let realTarget;
103194
+ try {
103195
+ realRoot = realpathSync(normRoot);
103196
+ } catch {
103197
+ return { ok: false, code: "root_not_found" };
103198
+ }
103199
+ try {
103200
+ realTarget = realpathSync(normPath);
103201
+ } catch {
103202
+ return { ok: false, code: "not_found" };
103203
+ }
103204
+ const rPrefix = realRoot === "/" ? "/" : `${realRoot}/`;
103205
+ if (!(realTarget === realRoot || realTarget.startsWith(rPrefix))) {
103206
+ return { ok: false, code: "outside_roots" };
103207
+ }
103208
+ }
103209
+ return { ok: true, path: normPath };
103210
+ }
103211
+ function resolveContext(rootId) {
103212
+ const root = getFileRootById(rootId);
103213
+ if (!root)
103214
+ return { ok: false, code: "root_not_found" };
103215
+ if (!root.enabled)
103216
+ return { ok: false, code: "root_disabled" };
103217
+ const device = getDeviceById(root.deviceId);
103218
+ if (!device)
103219
+ return { ok: false, code: "device_not_found" };
103220
+ return { ok: true, ctx: { root, device } };
103221
+ }
103222
+ function entryToDto(entry, parentPath) {
103223
+ return {
103224
+ name: entry.name,
103225
+ path: posixJoin(parentPath, entry.name),
103226
+ type: entry.type,
103227
+ category: entry.type === "dir" ? "directory" : categorize(entry.name),
103228
+ size: entry.size,
103229
+ modifiedAt: entry.modifiedAt,
103230
+ isSymlink: entry.type === "symlink"
103231
+ };
103232
+ }
103233
+ function sortEntries(entries) {
103234
+ entries.sort((a, b3) => {
103235
+ const ad = a.type === "dir" ? 0 : 1;
103236
+ const bd = b3.type === "dir" ? 0 : 1;
103237
+ if (ad !== bd)
103238
+ return ad - bd;
103239
+ return a.name.localeCompare(b3.name, undefined, { numeric: true, sensitivity: "base" });
103240
+ });
103241
+ }
103242
+ function looksBinary(buf) {
103243
+ const len = Math.min(buf.length, 8192);
103244
+ for (let i = 0;i < len; i++) {
103245
+ if (buf[i] === 0)
103246
+ return true;
103247
+ }
103248
+ return false;
103249
+ }
103250
+ async function listDirectory(rootId, inputPath) {
103251
+ const r = resolveContext(rootId);
103252
+ if (!r.ok)
103253
+ return fail(r.code);
103254
+ const { root, device } = r.ctx;
103255
+ const norm = checkAndNormalize(device, root.path, inputPath ?? root.path);
103256
+ if (!norm.ok)
103257
+ return fail(norm.code);
103258
+ return enqueueDeviceJob(device.id, async () => {
103259
+ let spec;
103260
+ try {
103261
+ spec = await buildRsyncDeviceSpec(device);
103262
+ } catch (error51) {
103263
+ if (error51 instanceof RsyncAuthError)
103264
+ return fail(error51.code, error51.message);
103265
+ throw error51;
103266
+ }
103267
+ try {
103268
+ const listPath = norm.path.endsWith("/") ? norm.path : `${norm.path}/`;
103269
+ let res;
103270
+ try {
103271
+ res = await runRsync(rsyncListArgs(spec, listPath), {
103272
+ env: spec.env,
103273
+ timeoutMs: LIST_TIMEOUT_MS
103274
+ });
103275
+ } catch (error51) {
103276
+ if (error51 instanceof RsyncMissingLocalError)
103277
+ return fail("rsync_missing_local");
103278
+ throw error51;
103279
+ }
103280
+ if (res.exitCode !== 0)
103281
+ return fail(classifyRsyncFailure(res.exitCode, res.stderr), res.stderr);
103282
+ const parsed = parseListOnly(res.stdout);
103283
+ const truncated = parsed.length > MAX_ENTRIES;
103284
+ const slice = truncated ? parsed.slice(0, MAX_ENTRIES) : parsed;
103285
+ const entries = slice.map((e) => entryToDto(e, norm.path));
103286
+ sortEntries(entries);
103287
+ return ok({ path: norm.path, entries, truncated });
103288
+ } finally {
103289
+ spec.cleanup();
103290
+ }
103291
+ });
103292
+ }
103293
+ async function statViaRsync(spec, normPath) {
103294
+ let res;
103295
+ try {
103296
+ res = await runRsync(rsyncListArgs(spec, normPath), {
103297
+ env: spec.env,
103298
+ timeoutMs: LIST_TIMEOUT_MS
103299
+ });
103300
+ } catch (error51) {
103301
+ if (error51 instanceof RsyncMissingLocalError)
103302
+ return fail("rsync_missing_local");
103303
+ throw error51;
103304
+ }
103305
+ if (res.exitCode !== 0)
103306
+ return fail(classifyRsyncFailure(res.exitCode, res.stderr), res.stderr);
103307
+ const entry = parseListOnly(res.stdout)[0];
103308
+ if (!entry)
103309
+ return fail("not_found");
103310
+ return ok(entry);
103311
+ }
103312
+ async function statFile(rootId, inputPath) {
103313
+ const r = resolveContext(rootId);
103314
+ if (!r.ok)
103315
+ return fail(r.code);
103316
+ const { root, device } = r.ctx;
103317
+ const norm = checkAndNormalize(device, root.path, inputPath);
103318
+ if (!norm.ok)
103319
+ return fail(norm.code);
103320
+ return enqueueDeviceJob(device.id, async () => {
103321
+ let spec;
103322
+ try {
103323
+ spec = await buildRsyncDeviceSpec(device);
103324
+ } catch (error51) {
103325
+ if (error51 instanceof RsyncAuthError)
103326
+ return fail(error51.code, error51.message);
103327
+ throw error51;
103328
+ }
103329
+ try {
103330
+ const st = await statViaRsync(spec, norm.path);
103331
+ if (!st.ok)
103332
+ return st;
103333
+ const name24 = posixBasename(norm.path);
103334
+ const isDir = st.data.type === "dir";
103335
+ const type = isDir ? "dir" : st.data.type === "symlink" ? "symlink" : "file";
103336
+ return ok({
103337
+ path: norm.path,
103338
+ name: name24,
103339
+ type,
103340
+ category: isDir ? "directory" : categorize(name24),
103341
+ size: isDir ? 0 : st.data.size ?? 0,
103342
+ modifiedAt: st.data.modifiedAt,
103343
+ mime: isDir ? null : mimeOf(name24),
103344
+ isSymlink: st.data.type === "symlink"
103345
+ });
103346
+ } finally {
103347
+ spec.cleanup();
103348
+ }
103349
+ });
103350
+ }
103351
+ async function copyToBuffer(spec, normPath) {
103352
+ const dir2 = mkdtempSync2(join5(tmpdir2(), "tmex-rfile-"));
103353
+ const dest = join5(dir2, "f");
103354
+ try {
103355
+ let res;
103356
+ try {
103357
+ res = await runRsync(rsyncCopyArgs(spec, normPath, dest), {
103358
+ env: spec.env,
103359
+ timeoutMs: COPY_TIMEOUT_MS
103360
+ });
103361
+ } catch (error51) {
103362
+ if (error51 instanceof RsyncMissingLocalError)
103363
+ return fail("rsync_missing_local");
103364
+ throw error51;
103365
+ }
103366
+ if (res.exitCode !== 0)
103367
+ return fail(classifyRsyncFailure(res.exitCode, res.stderr), res.stderr);
103368
+ return ok(readFileSync3(dest));
103369
+ } finally {
103370
+ try {
103371
+ rmSync2(dir2, { recursive: true, force: true });
103372
+ } catch {}
103373
+ }
103374
+ }
103375
+ async function readTextFile(rootId, inputPath) {
103376
+ const r = resolveContext(rootId);
103377
+ if (!r.ok)
103378
+ return fail(r.code);
103379
+ const { root, device } = r.ctx;
103380
+ const norm = checkAndNormalize(device, root.path, inputPath);
103381
+ if (!norm.ok)
103382
+ return fail(norm.code);
103383
+ return enqueueDeviceJob(device.id, async () => {
103384
+ let spec;
103385
+ try {
103386
+ spec = await buildRsyncDeviceSpec(device);
103387
+ } catch (error51) {
103388
+ if (error51 instanceof RsyncAuthError)
103389
+ return fail(error51.code, error51.message);
103390
+ throw error51;
103391
+ }
103392
+ try {
103393
+ const st = await statViaRsync(spec, norm.path);
103394
+ if (!st.ok)
103395
+ return st;
103396
+ if (st.data.type === "dir")
103397
+ return fail("is_directory");
103398
+ if (st.data.size != null && st.data.size > MAX_TEXT_BYTES)
103399
+ return fail("too_large");
103400
+ const buf = await copyToBuffer(spec, norm.path);
103401
+ if (!buf.ok)
103402
+ return buf;
103403
+ if (buf.data.length > MAX_TEXT_BYTES)
103404
+ return fail("too_large");
103405
+ if (looksBinary(buf.data))
103406
+ return fail("binary");
103407
+ const name24 = posixBasename(norm.path);
103408
+ return ok({
103409
+ path: norm.path,
103410
+ name: name24,
103411
+ category: categorize(name24),
103412
+ encoding: "utf-8",
103413
+ content: buf.data.toString("utf-8"),
103414
+ size: st.data.size ?? buf.data.length,
103415
+ truncated: false
103416
+ });
103417
+ } finally {
103418
+ spec.cleanup();
103419
+ }
103420
+ });
103421
+ }
103422
+ async function readRawFile(rootId, inputPath) {
103423
+ const r = resolveContext(rootId);
103424
+ if (!r.ok)
103425
+ return fail(r.code);
103426
+ const { root, device } = r.ctx;
103427
+ const norm = checkAndNormalize(device, root.path, inputPath);
103428
+ if (!norm.ok)
103429
+ return fail(norm.code);
103430
+ return enqueueDeviceJob(device.id, async () => {
103431
+ let spec;
103432
+ try {
103433
+ spec = await buildRsyncDeviceSpec(device);
103434
+ } catch (error51) {
103435
+ if (error51 instanceof RsyncAuthError)
103436
+ return fail(error51.code, error51.message);
103437
+ throw error51;
103438
+ }
103439
+ try {
103440
+ const st = await statViaRsync(spec, norm.path);
103441
+ if (!st.ok)
103442
+ return st;
103443
+ if (st.data.type === "dir")
103444
+ return fail("is_directory");
103445
+ if (st.data.size != null && st.data.size > RAW_MAX_BYTES)
103446
+ return fail("too_large");
103447
+ const buf = await copyToBuffer(spec, norm.path);
103448
+ if (!buf.ok)
103449
+ return buf;
103450
+ if (buf.data.length > RAW_MAX_BYTES)
103451
+ return fail("too_large");
103452
+ const name24 = posixBasename(norm.path);
103453
+ return ok({ data: new Uint8Array(buf.data), name: name24, mime: mimeOf(name24) });
103454
+ } finally {
103455
+ spec.cleanup();
103456
+ }
103457
+ });
103458
+ }
103459
+
103460
+ // ../../apps/gateway/src/api/files.ts
103461
+ function json4(data, status = 200, headers = {}) {
103462
+ return new Response(JSON.stringify(data), {
103463
+ status,
103464
+ headers: { "Content-Type": "application/json", ...headers }
103465
+ });
103466
+ }
103467
+ var CODE_STATUS = {
103468
+ invalid: 400,
103469
+ outside_roots: 403,
103470
+ not_found: 404,
103471
+ not_a_directory: 400,
103472
+ is_directory: 400,
103473
+ too_large: 413,
103474
+ binary: 415,
103475
+ permission_denied: 403,
103476
+ device_not_found: 404,
103477
+ root_not_found: 404,
103478
+ root_disabled: 403,
103479
+ connection_failed: 502,
103480
+ auth_unsupported: 400,
103481
+ rsync_missing_local: 502,
103482
+ rsync_missing_remote: 502,
103483
+ timeout: 504,
103484
+ unknown: 500
103485
+ };
103486
+ function codeError(code2, detail) {
103487
+ return json4({ error: code2, code: code2, detail }, CODE_STATUS[code2]);
103488
+ }
103489
+ function rootDisplayName(p) {
103490
+ if (p === "/")
103491
+ return "/";
103492
+ const i = p.replace(/\/$/, "").lastIndexOf("/");
103493
+ const base = i >= 0 ? p.replace(/\/$/, "").slice(i + 1) : p;
103494
+ return base || p;
103495
+ }
103496
+ function toRootDto(root) {
103497
+ const device = getDeviceById(root.deviceId);
103498
+ return {
103499
+ id: root.id,
103500
+ deviceId: root.deviceId,
103501
+ deviceName: device?.name ?? null,
103502
+ deviceType: device?.type ?? null,
103503
+ path: root.path,
103504
+ name: rootDisplayName(root.path),
103505
+ enabled: root.enabled,
103506
+ sortOrder: root.sortOrder
103507
+ };
103508
+ }
103509
+ function handleListRoots() {
103510
+ return json4({ roots: getFileRoots().map(toRootDto) });
103511
+ }
103512
+ async function handleCreateRoot(req) {
103513
+ let body;
103514
+ try {
103515
+ body = await req.json();
103516
+ } catch {
103517
+ return json4({ error: t2("apiError.invalidRequest") }, 400);
103518
+ }
103519
+ const deviceId = typeof body.deviceId === "string" ? body.deviceId : "";
103520
+ const path = typeof body.path === "string" ? body.path.trim() : "";
103521
+ if (!deviceId || !getDeviceById(deviceId)) {
103522
+ return json4({ error: t2("apiError.fileRootDeviceInvalid") }, 400);
103523
+ }
103524
+ if (!path || !path.startsWith("/")) {
103525
+ return json4({ error: t2("apiError.fileRootInvalid") }, 400);
103526
+ }
103527
+ const existing = getFileRoots().find((r) => r.deviceId === deviceId && r.path === path);
103528
+ if (existing) {
103529
+ return json4({ error: t2("apiError.fileRootDuplicate") }, 400);
103530
+ }
103531
+ const record2 = createFileRoot({ deviceId, path, enabled: body.enabled ?? true });
103532
+ return json4({ root: toRootDto(record2) }, 201);
103533
+ }
103534
+ async function handleUpdateRoot(req, id) {
103535
+ const existing = getFileRootById(id);
103536
+ if (!existing)
103537
+ return json4({ error: t2("apiError.notFound") }, 404);
103538
+ let body;
103539
+ try {
103540
+ body = await req.json();
103541
+ } catch {
103542
+ return json4({ error: t2("apiError.invalidRequest") }, 400);
103543
+ }
103544
+ const updates = {};
103545
+ if (body.path !== undefined) {
103546
+ const path = typeof body.path === "string" ? body.path.trim() : "";
103547
+ if (!path || !path.startsWith("/"))
103548
+ return json4({ error: t2("apiError.fileRootInvalid") }, 400);
103549
+ const dup = getFileRoots().find((r) => r.id !== id && r.deviceId === existing.deviceId && r.path === path);
103550
+ if (dup)
103551
+ return json4({ error: t2("apiError.fileRootDuplicate") }, 400);
103552
+ updates.path = path;
103553
+ }
103554
+ if (body.enabled !== undefined) {
103555
+ if (typeof body.enabled !== "boolean")
103556
+ return json4({ error: t2("apiError.invalidRequest") }, 400);
103557
+ updates.enabled = body.enabled;
103558
+ }
103559
+ if (body.sortOrder !== undefined) {
103560
+ if (typeof body.sortOrder !== "number")
103561
+ return json4({ error: t2("apiError.invalidRequest") }, 400);
103562
+ updates.sortOrder = body.sortOrder;
103563
+ }
103564
+ const updated = updateFileRoot(id, updates);
103565
+ if (!updated)
103566
+ return json4({ error: t2("apiError.notFound") }, 404);
103567
+ return json4({ root: toRootDto(updated) });
103568
+ }
103569
+ function handleDeleteRoot(id) {
103570
+ const okDelete = deleteFileRoot(id);
103571
+ if (!okDelete)
103572
+ return json4({ error: t2("apiError.notFound") }, 404);
103573
+ return json4({ success: true });
103574
+ }
103575
+ async function handleList(url2) {
103576
+ const rootId = url2.searchParams.get("rootId");
103577
+ if (!rootId)
103578
+ return json4({ error: t2("apiError.invalidRequest") }, 400);
103579
+ const path = url2.searchParams.get("path");
103580
+ const result = await listDirectory(rootId, path);
103581
+ if (!result.ok)
103582
+ return codeError(result.code, result.detail);
103583
+ return json4(result.data);
103584
+ }
103585
+ async function handleContent(url2) {
103586
+ const rootId = url2.searchParams.get("rootId");
103587
+ const path = url2.searchParams.get("path");
103588
+ if (!rootId || !path)
103589
+ return json4({ error: t2("apiError.invalidRequest") }, 400);
103590
+ const result = await readTextFile(rootId, path);
103591
+ if (!result.ok)
103592
+ return codeError(result.code, result.detail);
103593
+ return json4(result.data);
103594
+ }
103595
+ async function handleStat(url2) {
103596
+ const rootId = url2.searchParams.get("rootId");
103597
+ const path = url2.searchParams.get("path");
103598
+ if (!rootId || !path)
103599
+ return json4({ error: t2("apiError.invalidRequest") }, 400);
103600
+ const result = await statFile(rootId, path);
103601
+ if (!result.ok)
103602
+ return codeError(result.code, result.detail);
103603
+ return json4(result.data);
103604
+ }
103605
+ async function handleRaw(url2) {
103606
+ const rootId = url2.searchParams.get("rootId");
103607
+ const path = url2.searchParams.get("path");
103608
+ if (!rootId || !path)
103609
+ return json4({ error: t2("apiError.invalidRequest") }, 400);
103610
+ const result = await readRawFile(rootId, path);
103611
+ if (!result.ok)
103612
+ return codeError(result.code, result.detail);
103613
+ const headers = {
103614
+ "Content-Type": result.data.mime ?? "application/octet-stream"
103615
+ };
103616
+ const download2 = url2.searchParams.get("download");
103617
+ if (download2 === "1" || download2 === "true") {
103618
+ const encoded = encodeURIComponent(result.data.name);
103619
+ const ascii = result.data.name.replace(/["\\\r\n]/g, "_");
103620
+ headers["Content-Disposition"] = `attachment; filename="${ascii}"; filename*=UTF-8''${encoded}`;
103621
+ }
103622
+ return new Response(result.data.data, { status: 200, headers });
103623
+ }
103624
+ function handleFilesApiRequest(req, path) {
103625
+ const url2 = new URL(req.url);
103626
+ if (path === "/api/files/roots" && req.method === "GET")
103627
+ return handleListRoots();
103628
+ if (path === "/api/files/roots" && req.method === "POST")
103629
+ return handleCreateRoot(req);
103630
+ if (path.match(/^\/api\/files\/roots\/[^/]+$/) && req.method === "PATCH") {
103631
+ return handleUpdateRoot(req, decodeURIComponent(path.split("/")[4]));
103632
+ }
103633
+ if (path.match(/^\/api\/files\/roots\/[^/]+$/) && req.method === "DELETE") {
103634
+ return handleDeleteRoot(decodeURIComponent(path.split("/")[4]));
103635
+ }
103636
+ if (path === "/api/files/list" && req.method === "GET")
103637
+ return handleList(url2);
103638
+ if (path === "/api/files/content" && req.method === "GET")
103639
+ return handleContent(url2);
103640
+ if (path === "/api/files/stat" && req.method === "GET")
103641
+ return handleStat(url2);
103642
+ if (path === "/api/files/raw" && req.method === "GET")
103643
+ return handleRaw(url2);
103644
+ return;
103645
+ }
103646
+
102373
103647
  // ../../apps/gateway/src/api/llm.ts
102374
103648
  var PROTOCOLS = ["openai-chat", "openai-responses"];
102375
103649
  var SEARCH_PROVIDERS = ["none", "tavily", "brave"];
@@ -102463,31 +103737,31 @@ async function refreshModelsCache(provider) {
102463
103737
  }
102464
103738
  async function handleListProviders() {
102465
103739
  const providers = getAllLlmProviders().map(toProviderDto);
102466
- return json4({ providers });
103740
+ return json5({ providers });
102467
103741
  }
102468
103742
  async function handleCreateProvider(req) {
102469
103743
  const raw = await readJsonObjectBody2(req);
102470
103744
  if (!raw) {
102471
- return json4({ error: t2("apiError.invalidRequest") }, 400);
103745
+ return json5({ error: t2("apiError.invalidRequest") }, 400);
102472
103746
  }
102473
103747
  const body = raw;
102474
103748
  const name24 = typeof body.name === "string" ? body.name.trim() : "";
102475
103749
  if (!name24) {
102476
- return json4({ error: t2("apiError.llmProviderNameRequired") }, 400);
103750
+ return json5({ error: t2("apiError.llmProviderNameRequired") }, 400);
102477
103751
  }
102478
103752
  if (!PROTOCOLS.includes(body.protocol)) {
102479
- return json4({ error: t2("apiError.llmProviderProtocolInvalid") }, 400);
103753
+ return json5({ error: t2("apiError.llmProviderProtocolInvalid") }, 400);
102480
103754
  }
102481
103755
  const baseUrl = typeof body.baseUrl === "string" ? body.baseUrl.trim() : "";
102482
103756
  if (!baseUrl || !isValidBaseUrl(baseUrl)) {
102483
- return json4({ error: t2("apiError.llmProviderBaseUrlInvalid") }, 400);
103757
+ return json5({ error: t2("apiError.llmProviderBaseUrlInvalid") }, 400);
102484
103758
  }
102485
103759
  const apiKey = typeof body.apiKey === "string" ? body.apiKey.trim() : "";
102486
103760
  if (!apiKey) {
102487
- return json4({ error: t2("apiError.llmProviderApiKeyRequired") }, 400);
103761
+ return json5({ error: t2("apiError.llmProviderApiKeyRequired") }, 400);
102488
103762
  }
102489
103763
  if (body.enabled !== undefined && typeof body.enabled !== "boolean") {
102490
- return json4({ error: t2("apiError.invalidRequest") }, 400);
103764
+ return json5({ error: t2("apiError.invalidRequest") }, 400);
102491
103765
  }
102492
103766
  const created = createLlmProvider({
102493
103767
  name: name24,
@@ -102497,41 +103771,41 @@ async function handleCreateProvider(req) {
102497
103771
  enabled: body.enabled ?? true
102498
103772
  });
102499
103773
  const { provider, modelsError } = await refreshModelsCache(created);
102500
- return json4({ provider: toProviderDto(provider), ...modelsError ? { modelsError } : {} }, 201);
103774
+ return json5({ provider: toProviderDto(provider), ...modelsError ? { modelsError } : {} }, 201);
102501
103775
  }
102502
103776
  async function handleUpdateProvider(req, id) {
102503
103777
  const existing = getLlmProviderById(id);
102504
103778
  if (!existing) {
102505
- return json4({ error: t2("apiError.llmProviderNotFound") }, 404);
103779
+ return json5({ error: t2("apiError.llmProviderNotFound") }, 404);
102506
103780
  }
102507
103781
  const raw = await readJsonObjectBody2(req);
102508
103782
  if (!raw) {
102509
- return json4({ error: t2("apiError.invalidRequest") }, 400);
103783
+ return json5({ error: t2("apiError.invalidRequest") }, 400);
102510
103784
  }
102511
103785
  const body = raw;
102512
103786
  const updates = {};
102513
103787
  if (body.name !== undefined) {
102514
103788
  const name24 = typeof body.name === "string" ? body.name.trim() : "";
102515
103789
  if (!name24) {
102516
- return json4({ error: t2("apiError.llmProviderNameRequired") }, 400);
103790
+ return json5({ error: t2("apiError.llmProviderNameRequired") }, 400);
102517
103791
  }
102518
103792
  updates.name = name24;
102519
103793
  }
102520
103794
  if (body.protocol !== undefined) {
102521
103795
  if (!PROTOCOLS.includes(body.protocol)) {
102522
- return json4({ error: t2("apiError.llmProviderProtocolInvalid") }, 400);
103796
+ return json5({ error: t2("apiError.llmProviderProtocolInvalid") }, 400);
102523
103797
  }
102524
103798
  updates.protocol = body.protocol;
102525
103799
  }
102526
103800
  if (body.baseUrl !== undefined) {
102527
103801
  const baseUrl = typeof body.baseUrl === "string" ? body.baseUrl.trim() : "";
102528
103802
  if (!isValidBaseUrl(baseUrl)) {
102529
- return json4({ error: t2("apiError.llmProviderBaseUrlInvalid") }, 400);
103803
+ return json5({ error: t2("apiError.llmProviderBaseUrlInvalid") }, 400);
102530
103804
  }
102531
103805
  updates.baseUrl = baseUrl;
102532
103806
  }
102533
103807
  if (body.apiKey !== undefined && typeof body.apiKey !== "string") {
102534
- return json4({ error: t2("apiError.invalidRequest") }, 400);
103808
+ return json5({ error: t2("apiError.invalidRequest") }, 400);
102535
103809
  }
102536
103810
  const apiKey = body.apiKey?.trim();
102537
103811
  if (apiKey) {
@@ -102539,26 +103813,26 @@ async function handleUpdateProvider(req, id) {
102539
103813
  }
102540
103814
  if (body.enabled !== undefined) {
102541
103815
  if (typeof body.enabled !== "boolean") {
102542
- return json4({ error: t2("apiError.invalidRequest") }, 400);
103816
+ return json5({ error: t2("apiError.invalidRequest") }, 400);
102543
103817
  }
102544
103818
  updates.enabled = body.enabled;
102545
103819
  }
102546
103820
  const isStringArray = (value) => Array.isArray(value) && value.every((item) => typeof item === "string");
102547
103821
  if (body.manualModels !== undefined) {
102548
103822
  if (!isStringArray(body.manualModels)) {
102549
- return json4({ error: t2("apiError.invalidRequest") }, 400);
103823
+ return json5({ error: t2("apiError.invalidRequest") }, 400);
102550
103824
  }
102551
103825
  updates.manualModels = [...new Set(body.manualModels.map((m) => m.trim()).filter(Boolean))];
102552
103826
  }
102553
103827
  if (body.disabledModels !== undefined) {
102554
103828
  if (!isStringArray(body.disabledModels)) {
102555
- return json4({ error: t2("apiError.invalidRequest") }, 400);
103829
+ return json5({ error: t2("apiError.invalidRequest") }, 400);
102556
103830
  }
102557
103831
  updates.disabledModels = [...new Set(body.disabledModels.map((m) => m.trim()).filter(Boolean))];
102558
103832
  }
102559
103833
  let provider = updateLlmProvider(id, updates);
102560
103834
  if (!provider) {
102561
- return json4({ error: t2("apiError.llmProviderNotFound") }, 404);
103835
+ return json5({ error: t2("apiError.llmProviderNotFound") }, 404);
102562
103836
  }
102563
103837
  const credentialsChanged = updates.baseUrl !== undefined && updates.baseUrl !== existing.baseUrl || updates.apiKeyEnc !== undefined;
102564
103838
  let modelsError;
@@ -102567,76 +103841,76 @@ async function handleUpdateProvider(req, id) {
102567
103841
  provider = refreshed.provider;
102568
103842
  modelsError = refreshed.modelsError;
102569
103843
  }
102570
- return json4({ provider: toProviderDto(provider), ...modelsError ? { modelsError } : {} });
103844
+ return json5({ provider: toProviderDto(provider), ...modelsError ? { modelsError } : {} });
102571
103845
  }
102572
103846
  async function handleDeleteProvider(id) {
102573
103847
  const existing = getLlmProviderById(id);
102574
103848
  if (!existing) {
102575
- return json4({ error: t2("apiError.llmProviderNotFound") }, 404);
103849
+ return json5({ error: t2("apiError.llmProviderNotFound") }, 404);
102576
103850
  }
102577
103851
  deleteLlmProvider(id);
102578
- return json4({ success: true });
103852
+ return json5({ success: true });
102579
103853
  }
102580
103854
  async function handleRefreshProviderModels(id) {
102581
103855
  const existing = getLlmProviderById(id);
102582
103856
  if (!existing) {
102583
- return json4({ error: t2("apiError.llmProviderNotFound") }, 404);
103857
+ return json5({ error: t2("apiError.llmProviderNotFound") }, 404);
102584
103858
  }
102585
103859
  const { models, modelsError } = await refreshModelsCache(existing);
102586
103860
  if (modelsError !== undefined || models === undefined) {
102587
- return json4({ error: modelsError ?? t2("apiError.invalidRequest") }, 502);
103861
+ return json5({ error: modelsError ?? t2("apiError.invalidRequest") }, 502);
102588
103862
  }
102589
- return json4({ models });
103863
+ return json5({ models });
102590
103864
  }
102591
103865
  async function handleGetSettings() {
102592
- return json4({ settings: toSettingsDto(getAgentSettings()) });
103866
+ return json5({ settings: toSettingsDto(getAgentSettings()) });
102593
103867
  }
102594
103868
  async function handleUpdateSettings(req) {
102595
103869
  const raw = await readJsonObjectBody2(req);
102596
103870
  if (!raw) {
102597
- return json4({ error: t2("apiError.invalidRequest") }, 400);
103871
+ return json5({ error: t2("apiError.invalidRequest") }, 400);
102598
103872
  }
102599
103873
  const body = raw;
102600
103874
  const updates = {};
102601
103875
  if (body.searchProvider !== undefined) {
102602
103876
  if (!SEARCH_PROVIDERS.includes(body.searchProvider)) {
102603
- return json4({ error: t2("apiError.llmSearchProviderInvalid") }, 400);
103877
+ return json5({ error: t2("apiError.llmSearchProviderInvalid") }, 400);
102604
103878
  }
102605
103879
  updates.searchProvider = body.searchProvider;
102606
103880
  }
102607
103881
  if (body.defaultProviderId !== undefined) {
102608
103882
  if (body.defaultProviderId !== null && typeof body.defaultProviderId !== "string") {
102609
- return json4({ error: t2("apiError.invalidRequest") }, 400);
103883
+ return json5({ error: t2("apiError.invalidRequest") }, 400);
102610
103884
  }
102611
103885
  if (body.defaultProviderId !== null && !getLlmProviderById(body.defaultProviderId)) {
102612
- return json4({ error: t2("apiError.llmDefaultProviderNotFound") }, 400);
103886
+ return json5({ error: t2("apiError.llmDefaultProviderNotFound") }, 400);
102613
103887
  }
102614
103888
  updates.defaultProviderId = body.defaultProviderId;
102615
103889
  }
102616
103890
  if (body.defaultModelId !== undefined) {
102617
103891
  if (body.defaultModelId !== null && typeof body.defaultModelId !== "string") {
102618
- return json4({ error: t2("apiError.invalidRequest") }, 400);
103892
+ return json5({ error: t2("apiError.invalidRequest") }, 400);
102619
103893
  }
102620
103894
  updates.defaultModelId = body.defaultModelId;
102621
103895
  }
102622
103896
  if (body.tavilyApiKey !== undefined) {
102623
103897
  if (typeof body.tavilyApiKey !== "string") {
102624
- return json4({ error: t2("apiError.invalidRequest") }, 400);
103898
+ return json5({ error: t2("apiError.invalidRequest") }, 400);
102625
103899
  }
102626
103900
  const value = body.tavilyApiKey.trim();
102627
103901
  updates.tavilyApiKeyEnc = value ? await encrypt(value) : null;
102628
103902
  }
102629
103903
  if (body.braveApiKey !== undefined) {
102630
103904
  if (typeof body.braveApiKey !== "string") {
102631
- return json4({ error: t2("apiError.invalidRequest") }, 400);
103905
+ return json5({ error: t2("apiError.invalidRequest") }, 400);
102632
103906
  }
102633
103907
  const value = body.braveApiKey.trim();
102634
103908
  updates.braveApiKeyEnc = value ? await encrypt(value) : null;
102635
103909
  }
102636
103910
  const settings = updateAgentSettings(updates);
102637
- return json4({ settings: toSettingsDto(settings) });
103911
+ return json5({ settings: toSettingsDto(settings) });
102638
103912
  }
102639
- function json4(data, status = 200) {
103913
+ function json5(data, status = 200) {
102640
103914
  return new Response(JSON.stringify(data), {
102641
103915
  status,
102642
103916
  headers: {
@@ -102652,7 +103926,7 @@ function inferFailurePhase(errorType) {
102652
103926
  }
102653
103927
  return "connect";
102654
103928
  }
102655
- function json5(data, status = 200) {
103929
+ function json6(data, status = 200) {
102656
103930
  return new Response(JSON.stringify(data), {
102657
103931
  status,
102658
103932
  headers: {
@@ -102671,7 +103945,7 @@ async function handleDeviceTestConnection(deviceId, inputDeps = {}) {
102671
103945
  };
102672
103946
  const device = deps.getDevice(deviceId);
102673
103947
  if (!device) {
102674
- return json5({ error: deps.translate("apiError.deviceNotFound") }, 404);
103948
+ return json6({ error: deps.translate("apiError.deviceNotFound") }, 404);
102675
103949
  }
102676
103950
  const classifyErrorResponse = (error51) => {
102677
103951
  const rawMessage = error51 instanceof Error ? error51.message : String(error51);
@@ -102684,7 +103958,7 @@ async function handleDeviceTestConnection(deviceId, inputDeps = {}) {
102684
103958
  message: deps.translate(classified.messageKey, classified.messageParams),
102685
103959
  rawMessage
102686
103960
  };
102687
- return json5(payload);
103961
+ return json6(payload);
102688
103962
  };
102689
103963
  let runtime = null;
102690
103964
  try {
@@ -102697,7 +103971,7 @@ async function handleDeviceTestConnection(deviceId, inputDeps = {}) {
102697
103971
  phase: "ready",
102698
103972
  message: deps.translate("common.success")
102699
103973
  };
102700
- return json5(payload);
103974
+ return json6(payload);
102701
103975
  } catch (error51) {
102702
103976
  return classifyErrorResponse(error51);
102703
103977
  } finally {
@@ -103804,35 +105078,35 @@ async function handleListRules(req) {
103804
105078
  if (paneId) {
103805
105079
  rules = rules.filter((rule) => rule.paneId === paneId);
103806
105080
  }
103807
- return json6({ rules: rules.map(toRuleDto) });
105081
+ return json7({ rules: rules.map(toRuleDto) });
103808
105082
  }
103809
105083
  async function handleCreateRule(req, deps) {
103810
105084
  const raw = await readJsonObjectBody3(req);
103811
105085
  if (!raw) {
103812
- return json6({ error: t2("apiError.invalidRequest") }, 400);
105086
+ return json7({ error: t2("apiError.invalidRequest") }, 400);
103813
105087
  }
103814
105088
  const body = raw;
103815
105089
  const name24 = typeof body.name === "string" ? body.name.trim() : "";
103816
105090
  if (!name24) {
103817
- return json6({ error: t2("apiError.watchNameRequired") }, 400);
105091
+ return json7({ error: t2("apiError.watchNameRequired") }, 400);
103818
105092
  }
103819
105093
  const deviceId = typeof body.deviceId === "string" ? body.deviceId.trim() : "";
103820
105094
  if (!deviceId) {
103821
- return json6({ error: t2("apiError.agentDeviceRequired") }, 400);
105095
+ return json7({ error: t2("apiError.agentDeviceRequired") }, 400);
103822
105096
  }
103823
105097
  if (!getDeviceById(deviceId)) {
103824
- return json6({ error: t2("apiError.deviceNotFound") }, 404);
105098
+ return json7({ error: t2("apiError.deviceNotFound") }, 404);
103825
105099
  }
103826
105100
  const paneId = typeof body.paneId === "string" ? body.paneId.trim() : "";
103827
105101
  if (!paneId) {
103828
- return json6({ error: t2("apiError.agentPaneRequired") }, 400);
105102
+ return json7({ error: t2("apiError.agentPaneRequired") }, 400);
103829
105103
  }
103830
105104
  if (!TRIGGER_TYPES.includes(body.triggerType)) {
103831
- return json6({ error: t2("apiError.watchTriggerTypeInvalid") }, 400);
105105
+ return json7({ error: t2("apiError.watchTriggerTypeInvalid") }, 400);
103832
105106
  }
103833
105107
  const parsed = parseRuleFields(raw);
103834
105108
  if (!parsed.ok) {
103835
- return json6({ error: parsed.error }, 400);
105109
+ return json7({ error: parsed.error }, 400);
103836
105110
  }
103837
105111
  const fields = parsed.fields;
103838
105112
  const effective = {
@@ -103845,7 +105119,7 @@ async function handleCreateRule(req, deps) {
103845
105119
  };
103846
105120
  const semanticError = validateRuleSemantics(effective);
103847
105121
  if (semanticError) {
103848
- return json6({ error: semanticError }, 400);
105122
+ return json7({ error: semanticError }, 400);
103849
105123
  }
103850
105124
  const rule = createWatchRule({
103851
105125
  name: name24,
@@ -103868,50 +105142,50 @@ async function handleCreateRule(req, deps) {
103868
105142
  cooldownSeconds: fields.cooldownSeconds
103869
105143
  });
103870
105144
  await deps.service.refreshRule(rule.id);
103871
- return json6({ rule: toRuleDto(rule), state: null }, 201);
105145
+ return json7({ rule: toRuleDto(rule), state: null }, 201);
103872
105146
  }
103873
105147
  async function handleGetRule(id) {
103874
105148
  const rule = getWatchRuleById(id);
103875
105149
  if (!rule) {
103876
- return json6({ error: t2("apiError.watchRuleNotFound") }, 404);
105150
+ return json7({ error: t2("apiError.watchRuleNotFound") }, 404);
103877
105151
  }
103878
105152
  const state = getWatchRuleState(id);
103879
- return json6({ rule: toRuleDto(rule), state: state ? toStateDto(state) : null });
105153
+ return json7({ rule: toRuleDto(rule), state: state ? toStateDto(state) : null });
103880
105154
  }
103881
105155
  async function handleUpdateRule(req, id, deps) {
103882
105156
  const existing = getWatchRuleById(id);
103883
105157
  if (!existing) {
103884
- return json6({ error: t2("apiError.watchRuleNotFound") }, 404);
105158
+ return json7({ error: t2("apiError.watchRuleNotFound") }, 404);
103885
105159
  }
103886
105160
  const raw = await readJsonObjectBody3(req);
103887
105161
  if (!raw) {
103888
- return json6({ error: t2("apiError.invalidRequest") }, 400);
105162
+ return json7({ error: t2("apiError.invalidRequest") }, 400);
103889
105163
  }
103890
105164
  const body = raw;
103891
105165
  const updates = {};
103892
105166
  if (body.name !== undefined) {
103893
105167
  const name24 = typeof body.name === "string" ? body.name.trim() : "";
103894
105168
  if (!name24) {
103895
- return json6({ error: t2("apiError.watchNameRequired") }, 400);
105169
+ return json7({ error: t2("apiError.watchNameRequired") }, 400);
103896
105170
  }
103897
105171
  updates.name = name24;
103898
105172
  }
103899
105173
  if (body.paneId !== undefined) {
103900
105174
  const paneId = typeof body.paneId === "string" ? body.paneId.trim() : "";
103901
105175
  if (!paneId) {
103902
- return json6({ error: t2("apiError.agentPaneRequired") }, 400);
105176
+ return json7({ error: t2("apiError.agentPaneRequired") }, 400);
103903
105177
  }
103904
105178
  updates.paneId = paneId;
103905
105179
  }
103906
105180
  if (body.triggerType !== undefined) {
103907
105181
  if (!TRIGGER_TYPES.includes(body.triggerType)) {
103908
- return json6({ error: t2("apiError.watchTriggerTypeInvalid") }, 400);
105182
+ return json7({ error: t2("apiError.watchTriggerTypeInvalid") }, 400);
103909
105183
  }
103910
105184
  updates.triggerType = body.triggerType;
103911
105185
  }
103912
105186
  const parsed = parseRuleFields(raw);
103913
105187
  if (!parsed.ok) {
103914
- return json6({ error: parsed.error }, 400);
105188
+ return json7({ error: parsed.error }, 400);
103915
105189
  }
103916
105190
  const fields = parsed.fields;
103917
105191
  Object.assign(updates, fields);
@@ -103925,32 +105199,32 @@ async function handleUpdateRule(req, id, deps) {
103925
105199
  };
103926
105200
  const semanticError = validateRuleSemantics(effective);
103927
105201
  if (semanticError) {
103928
- return json6({ error: semanticError }, 400);
105202
+ return json7({ error: semanticError }, 400);
103929
105203
  }
103930
105204
  const rule = updateWatchRule(id, updates);
103931
105205
  if (!rule) {
103932
- return json6({ error: t2("apiError.watchRuleNotFound") }, 404);
105206
+ return json7({ error: t2("apiError.watchRuleNotFound") }, 404);
103933
105207
  }
103934
105208
  await deps.service.refreshRule(id);
103935
105209
  const state = getWatchRuleState(id);
103936
- return json6({ rule: toRuleDto(rule), state: state ? toStateDto(state) : null });
105210
+ return json7({ rule: toRuleDto(rule), state: state ? toStateDto(state) : null });
103937
105211
  }
103938
105212
  async function handleDeleteRule(id, deps) {
103939
105213
  const existing = getWatchRuleById(id);
103940
105214
  if (!existing) {
103941
- return json6({ error: t2("apiError.watchRuleNotFound") }, 404);
105215
+ return json7({ error: t2("apiError.watchRuleNotFound") }, 404);
103942
105216
  }
103943
105217
  deleteWatchRule(id);
103944
105218
  await deps.service.removeRule(id);
103945
- return json6({ success: true });
105219
+ return json7({ success: true });
103946
105220
  }
103947
105221
  async function handleGetRuleState(id, deps) {
103948
105222
  const rule = getWatchRuleById(id);
103949
105223
  if (!rule) {
103950
- return json6({ error: t2("apiError.watchRuleNotFound") }, 404);
105224
+ return json7({ error: t2("apiError.watchRuleNotFound") }, 404);
103951
105225
  }
103952
105226
  const state = getWatchRuleState(id);
103953
- return json6({
105227
+ return json7({
103954
105228
  state: state ? toStateDto(state) : null,
103955
105229
  samples: deps.service.getSamples(id)
103956
105230
  });
@@ -103974,17 +105248,17 @@ function buildAssistPrompt(description, screen) {
103974
105248
  async function handleAssistRegex(req, deps) {
103975
105249
  const raw = await readJsonObjectBody3(req);
103976
105250
  if (!raw) {
103977
- return json6({ error: t2("apiError.invalidRequest") }, 400);
105251
+ return json7({ error: t2("apiError.invalidRequest") }, 400);
103978
105252
  }
103979
105253
  const body = raw;
103980
105254
  const description = typeof body.description === "string" ? body.description.trim() : "";
103981
105255
  if (!description) {
103982
- return json6({ error: t2("apiError.watchAssistDescriptionRequired") }, 400);
105256
+ return json7({ error: t2("apiError.watchAssistDescriptionRequired") }, 400);
103983
105257
  }
103984
105258
  let providerId = null;
103985
105259
  if (body.providerId !== undefined && body.providerId !== null) {
103986
105260
  if (typeof body.providerId !== "string" || !getLlmProviderById(body.providerId)) {
103987
- return json6({ error: t2("apiError.llmProviderNotFound") }, 400);
105261
+ return json7({ error: t2("apiError.llmProviderNotFound") }, 400);
103988
105262
  }
103989
105263
  providerId = body.providerId;
103990
105264
  }
@@ -103994,7 +105268,7 @@ async function handleAssistRegex(req, deps) {
103994
105268
  const paneId = typeof body.paneId === "string" ? body.paneId.trim() : "";
103995
105269
  if (deviceId && paneId) {
103996
105270
  if (!getDeviceById(deviceId)) {
103997
- return json6({ error: t2("apiError.deviceNotFound") }, 404);
105271
+ return json7({ error: t2("apiError.deviceNotFound") }, 404);
103998
105272
  }
103999
105273
  try {
104000
105274
  screen = await deps.captureScreen(deviceId, paneId);
@@ -104015,14 +105289,14 @@ async function handleAssistRegex(req, deps) {
104015
105289
  object3 = result.object;
104016
105290
  } catch (error51) {
104017
105291
  const detail = error51 instanceof Error ? error51.message : String(error51);
104018
- return json6({ error: t2("apiError.watchAssistModelUnavailable", { detail }) }, 502);
105292
+ return json7({ error: t2("apiError.watchAssistModelUnavailable", { detail }) }, 502);
104019
105293
  }
104020
105294
  let regex;
104021
105295
  try {
104022
105296
  regex = compileWatchPattern(object3.pattern, object3.flags);
104023
105297
  } catch (error51) {
104024
105298
  const detail = error51 instanceof Error ? error51.message : String(error51);
104025
- return json6({ error: t2("apiError.watchPatternInvalid", { detail }) }, 502);
105299
+ return json7({ error: t2("apiError.watchPatternInvalid", { detail }) }, 502);
104026
105300
  }
104027
105301
  const preview = [];
104028
105302
  if (screen) {
@@ -104036,7 +105310,7 @@ async function handleAssistRegex(req, deps) {
104036
105310
  match = regex.exec(screen);
104037
105311
  }
104038
105312
  }
104039
- return json6({
105313
+ return json7({
104040
105314
  pattern: object3.pattern,
104041
105315
  flags: object3.flags,
104042
105316
  extractGroup: object3.extractGroup >= 0 ? object3.extractGroup : 0,
@@ -104044,7 +105318,7 @@ async function handleAssistRegex(req, deps) {
104044
105318
  preview
104045
105319
  });
104046
105320
  }
104047
- function json6(data, status = 200) {
105321
+ function json7(data, status = 200) {
104048
105322
  return new Response(JSON.stringify(data), {
104049
105323
  status,
104050
105324
  headers: {
@@ -104228,6 +105502,12 @@ function handleApiRequest(req, _server) {
104228
105502
  return watchResponse;
104229
105503
  }
104230
105504
  }
105505
+ if (path.startsWith("/api/files")) {
105506
+ const filesResponse = handleFilesApiRequest(req, path);
105507
+ if (filesResponse) {
105508
+ return filesResponse;
105509
+ }
105510
+ }
104231
105511
  if (path === "/api/webhooks" && req.method === "GET") {
104232
105512
  return handleGetWebhooks();
104233
105513
  }
@@ -104241,9 +105521,9 @@ function handleApiRequest(req, _server) {
104241
105521
  return handleGetManifest(req.method);
104242
105522
  }
104243
105523
  if (path === "/healthz" && req.method === "GET") {
104244
- return json7({ status: "ok", restarting: runtimeController.isRestarting() });
105524
+ return json8({ status: "ok", restarting: runtimeController.isRestarting() });
104245
105525
  }
104246
- return json7({ error: t2("apiError.notFound") }, 404);
105526
+ return json8({ error: t2("apiError.notFound") }, 404);
104247
105527
  }
104248
105528
  function enrichDeviceWithRuntime(device) {
104249
105529
  const status = getDeviceRuntimeStatus(device.id);
@@ -104257,22 +105537,22 @@ function enrichDeviceWithRuntime(device) {
104257
105537
  }
104258
105538
  async function handleGetDevices() {
104259
105539
  const devices2 = getAllDevices().map(enrichDeviceWithRuntime);
104260
- return json7({ devices: devices2 });
105540
+ return json8({ devices: devices2 });
104261
105541
  }
104262
105542
  async function handleGetDevice(id) {
104263
105543
  const device = getDeviceById(id);
104264
105544
  if (!device) {
104265
- return json7({ error: t2("apiError.deviceNotFound") }, 404);
105545
+ return json8({ error: t2("apiError.deviceNotFound") }, 404);
104266
105546
  }
104267
- return json7({ device: enrichDeviceWithRuntime(device) });
105547
+ return json8({ device: enrichDeviceWithRuntime(device) });
104268
105548
  }
104269
105549
  async function handleCreateDevice(req) {
104270
105550
  const body = await req.json();
104271
105551
  if (!body.name || !body.type || !body.authMode) {
104272
- return json7({ error: t2("apiError.missingFields") }, 400);
105552
+ return json8({ error: t2("apiError.missingFields") }, 400);
104273
105553
  }
104274
105554
  if (body.type === "ssh" && !body.host && !body.sshConfigRef) {
104275
- return json7({ error: t2("apiError.sshRequiresHost") }, 400);
105555
+ return json8({ error: t2("apiError.sshRequiresHost") }, 400);
104276
105556
  }
104277
105557
  const now2 = new Date().toISOString();
104278
105558
  const device = {
@@ -104294,12 +105574,12 @@ async function handleCreateDevice(req) {
104294
105574
  };
104295
105575
  createDevice(device);
104296
105576
  await pushSupervisor.upsert(device.id);
104297
- return json7({ device: getDeviceById(device.id) ?? device }, 201);
105577
+ return json8({ device: getDeviceById(device.id) ?? device }, 201);
104298
105578
  }
104299
105579
  async function handleUpdateDevice(req, id) {
104300
105580
  const existing = getDeviceById(id);
104301
105581
  if (!existing) {
104302
- return json7({ error: t2("apiError.deviceNotFound") }, 404);
105582
+ return json8({ error: t2("apiError.deviceNotFound") }, 404);
104303
105583
  }
104304
105584
  const body = await req.json();
104305
105585
  const updates = {};
@@ -104329,61 +105609,61 @@ async function handleUpdateDevice(req, id) {
104329
105609
  await pushSupervisor.reconnect(id);
104330
105610
  }
104331
105611
  const device = getDeviceById(id);
104332
- return json7({ device });
105612
+ return json8({ device });
104333
105613
  }
104334
105614
  async function handleReorderDevices(req) {
104335
105615
  const body = await req.json();
104336
105616
  if (!Array.isArray(body.deviceIds) || body.deviceIds.some((id) => typeof id !== "string")) {
104337
- return json7({ error: t2("apiError.invalidRequest") }, 400);
105617
+ return json8({ error: t2("apiError.invalidRequest") }, 400);
104338
105618
  }
104339
105619
  reorderDevices(body.deviceIds);
104340
- return json7({ devices: getAllDevices().map(enrichDeviceWithRuntime) });
105620
+ return json8({ devices: getAllDevices().map(enrichDeviceWithRuntime) });
104341
105621
  }
104342
105622
  async function handleDeleteDevice(id) {
104343
105623
  const existing = getDeviceById(id);
104344
105624
  if (!existing) {
104345
- return json7({ error: t2("apiError.deviceNotFound") }, 404);
105625
+ return json8({ error: t2("apiError.deviceNotFound") }, 404);
104346
105626
  }
104347
105627
  deleteDevice(id);
104348
105628
  pushSupervisor.remove(id);
104349
- return json7({ success: true });
105629
+ return json8({ success: true });
104350
105630
  }
104351
105631
  async function handleTestConnection(id) {
104352
105632
  return handleDeviceTestConnection(id);
104353
105633
  }
104354
105634
  async function handleGetSiteSettings() {
104355
- return json7({ settings: getSiteSettings() });
105635
+ return json8({ settings: getSiteSettings() });
104356
105636
  }
104357
105637
  async function handleUpdateSiteSettings(req) {
104358
105638
  try {
104359
105639
  const body = await req.json();
104360
105640
  const updates = normalizeSiteSettingsInput(body);
104361
105641
  const settings = updateSiteSettings(updates);
104362
- return json7({ settings });
105642
+ return json8({ settings });
104363
105643
  } catch (err) {
104364
- return json7({ error: err instanceof Error ? err.message : t2("apiError.invalidRequest") }, 400);
105644
+ return json8({ error: err instanceof Error ? err.message : t2("apiError.invalidRequest") }, 400);
104365
105645
  }
104366
105646
  }
104367
105647
  async function handleRestartGateway() {
104368
105648
  setTimeout(() => {
104369
105649
  runtimeController.requestRestart();
104370
105650
  }, 50);
104371
- return json7({
105651
+ return json8({
104372
105652
  success: true,
104373
105653
  message: t2("settings.restartScheduled")
104374
105654
  });
104375
105655
  }
104376
105656
  async function handleGetTelegramBots() {
104377
105657
  const bots = getTelegramBotsWithStats();
104378
- return json7({ bots });
105658
+ return json8({ bots });
104379
105659
  }
104380
105660
  async function handleCreateTelegramBot(req) {
104381
105661
  const body = await req.json();
104382
105662
  if (!body.name?.trim()) {
104383
- return json7({ error: t2("apiError.botNameRequired") }, 400);
105663
+ return json8({ error: t2("apiError.botNameRequired") }, 400);
104384
105664
  }
104385
105665
  if (!body.token?.trim()) {
104386
- return json7({ error: t2("apiError.botTokenRequired") }, 400);
105666
+ return json8({ error: t2("apiError.botTokenRequired") }, 400);
104387
105667
  }
104388
105668
  const now2 = new Date().toISOString();
104389
105669
  createTelegramBot({
@@ -104397,26 +105677,26 @@ async function handleCreateTelegramBot(req) {
104397
105677
  updatedAt: now2
104398
105678
  });
104399
105679
  await telegramService.refresh();
104400
- return json7({ success: true }, 201);
105680
+ return json8({ success: true }, 201);
104401
105681
  }
104402
105682
  async function handleUpdateTelegramBot(req, botId) {
104403
105683
  const existing = getTelegramBotById(botId);
104404
105684
  if (!existing) {
104405
- return json7({ error: t2("apiError.botNotFound") }, 404);
105685
+ return json8({ error: t2("apiError.botNotFound") }, 404);
104406
105686
  }
104407
105687
  const body = await req.json();
104408
105688
  const updates = {};
104409
105689
  if (body.name !== undefined) {
104410
105690
  const value = body.name.trim();
104411
105691
  if (!value) {
104412
- return json7({ error: t2("apiError.botNameRequired") }, 400);
105692
+ return json8({ error: t2("apiError.botNameRequired") }, 400);
104413
105693
  }
104414
105694
  updates.name = value;
104415
105695
  }
104416
105696
  if (body.token !== undefined) {
104417
105697
  const token = body.token.trim();
104418
105698
  if (!token) {
104419
- return json7({ error: t2("apiError.botTokenRequired") }, 400);
105699
+ return json8({ error: t2("apiError.botTokenRequired") }, 400);
104420
105700
  }
104421
105701
  updates.tokenEnc = await encrypt(token);
104422
105702
  }
@@ -104428,69 +105708,69 @@ async function handleUpdateTelegramBot(req, botId) {
104428
105708
  }
104429
105709
  updateTelegramBot(botId, updates);
104430
105710
  await telegramService.refresh();
104431
- return json7({ success: true });
105711
+ return json8({ success: true });
104432
105712
  }
104433
105713
  async function handleDeleteTelegramBot(botId) {
104434
105714
  const existing = getTelegramBotById(botId);
104435
105715
  if (!existing) {
104436
- return json7({ error: t2("apiError.botNotFound") }, 404);
105716
+ return json8({ error: t2("apiError.botNotFound") }, 404);
104437
105717
  }
104438
105718
  deleteTelegramBot(botId);
104439
105719
  await telegramService.refresh();
104440
- return json7({ success: true });
105720
+ return json8({ success: true });
104441
105721
  }
104442
105722
  async function handleListTelegramChats(botId) {
104443
105723
  const existing = getTelegramBotById(botId);
104444
105724
  if (!existing) {
104445
- return json7({ error: t2("apiError.botNotFound") }, 404);
105725
+ return json8({ error: t2("apiError.botNotFound") }, 404);
104446
105726
  }
104447
105727
  const chats = listTelegramChatsByBot(botId);
104448
- return json7({ chats });
105728
+ return json8({ chats });
104449
105729
  }
104450
105730
  async function handleApproveTelegramChat(botId, chatId) {
104451
105731
  const existing = getTelegramBotById(botId);
104452
105732
  if (!existing) {
104453
- return json7({ error: t2("apiError.botNotFound") }, 404);
105733
+ return json8({ error: t2("apiError.botNotFound") }, 404);
104454
105734
  }
104455
105735
  const chat = approveTelegramChat(botId, chatId);
104456
105736
  if (!chat) {
104457
- return json7({ error: t2("apiError.chatNotFound") }, 404);
105737
+ return json8({ error: t2("apiError.chatNotFound") }, 404);
104458
105738
  }
104459
105739
  const settings = getSiteSettings();
104460
105740
  await telegramService.sendTestMessage(botId, chatId, t2("telegram.approveMessageTemplate", {
104461
105741
  botName: existing.name,
104462
105742
  time: new Date().toLocaleString(toBCP47(settings.language))
104463
105743
  }));
104464
- return json7({ chat });
105744
+ return json8({ chat });
104465
105745
  }
104466
105746
  async function handleDeleteTelegramChat(botId, chatId) {
104467
105747
  const existing = getTelegramBotById(botId);
104468
105748
  if (!existing) {
104469
- return json7({ error: t2("apiError.botNotFound") }, 404);
105749
+ return json8({ error: t2("apiError.botNotFound") }, 404);
104470
105750
  }
104471
105751
  deleteTelegramChat(botId, chatId);
104472
- return json7({ success: true });
105752
+ return json8({ success: true });
104473
105753
  }
104474
105754
  async function handleTestTelegramChat(botId, chatId) {
104475
105755
  const bot = getTelegramBotById(botId);
104476
105756
  if (!bot) {
104477
- return json7({ error: t2("apiError.botNotFound") }, 404);
105757
+ return json8({ error: t2("apiError.botNotFound") }, 404);
104478
105758
  }
104479
105759
  const settings = getSiteSettings();
104480
105760
  await telegramService.sendTestMessage(botId, chatId, t2("telegram.testMessageTemplate", {
104481
105761
  siteName: settings.siteName,
104482
105762
  time: new Date().toLocaleString(toBCP47(settings.language))
104483
105763
  }));
104484
- return json7({ success: true });
105764
+ return json8({ success: true });
104485
105765
  }
104486
105766
  async function handleGetWebhooks() {
104487
105767
  const webhooks = getAllWebhookEndpoints();
104488
- return json7({ webhooks });
105768
+ return json8({ webhooks });
104489
105769
  }
104490
105770
  async function handleCreateWebhook(req) {
104491
105771
  const body = await req.json();
104492
105772
  if (!body.url || !body.secret) {
104493
- return json7({ error: t2("apiError.urlAndSecretRequired") }, 400);
105773
+ return json8({ error: t2("apiError.urlAndSecretRequired") }, 400);
104494
105774
  }
104495
105775
  const now2 = new Date().toISOString();
104496
105776
  const endpoint = {
@@ -104503,11 +105783,11 @@ async function handleCreateWebhook(req) {
104503
105783
  updatedAt: now2
104504
105784
  };
104505
105785
  createWebhookEndpoint(endpoint);
104506
- return json7({ webhook: endpoint }, 201);
105786
+ return json8({ webhook: endpoint }, 201);
104507
105787
  }
104508
105788
  async function handleDeleteWebhook(id) {
104509
105789
  deleteWebhookEndpoint(id);
104510
- return json7({ success: true });
105790
+ return json8({ success: true });
104511
105791
  }
104512
105792
  async function handleGetManifest(method) {
104513
105793
  const settings = getSiteSettings();
@@ -104546,7 +105826,7 @@ function manifestJson(data, method) {
104546
105826
  }
104547
105827
  });
104548
105828
  }
104549
- function json7(data, status = 200, headers = {}) {
105829
+ function json8(data, status = 200, headers = {}) {
104550
105830
  return new Response(JSON.stringify(data), {
104551
105831
  status,
104552
105832
  headers: {
@@ -106387,7 +107667,7 @@ function t3(key, vars) {
106387
107667
  }
106388
107668
 
106389
107669
  // src/runtime/server.ts
106390
- var MIME_MAP = {
107670
+ var MIME_MAP2 = {
106391
107671
  ".html": "text/html; charset=utf-8",
106392
107672
  ".js": "text/javascript; charset=utf-8",
106393
107673
  ".mjs": "text/javascript; charset=utf-8",
@@ -106403,8 +107683,8 @@ var MIME_MAP = {
106403
107683
  ".map": "application/json; charset=utf-8"
106404
107684
  };
106405
107685
  function contentTypeByPath(path) {
106406
- const ext = extname(path).toLowerCase();
106407
- return MIME_MAP[ext];
107686
+ const ext = extname2(path).toLowerCase();
107687
+ return MIME_MAP2[ext];
106408
107688
  }
106409
107689
  function resolveStaticRoot() {
106410
107690
  if (process.env.TMEX_FE_DIST_DIR) {
@@ -106432,10 +107712,10 @@ async function serveFrontend(req, staticRoot) {
106432
107712
  if (!requestedPath) {
106433
107713
  return new Response(t3("runtime.forbidden"), { status: 403 });
106434
107714
  }
106435
- if (!existsSync5(requestedPath) && extname(url2.pathname) !== "") {
107715
+ if (!existsSync5(requestedPath) && extname2(url2.pathname) !== "") {
106436
107716
  return new Response(t3("runtime.notFound"), { status: 404 });
106437
107717
  }
106438
- const indexPath = join4(staticRoot, "index.html");
107718
+ const indexPath = join6(staticRoot, "index.html");
106439
107719
  const targetPath = existsSync5(requestedPath) ? requestedPath : indexPath;
106440
107720
  if (!existsSync5(targetPath)) {
106441
107721
  return new Response(t3("runtime.frontendMissing"), { status: 500 });