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.
- package/dist/runtime/server.js +1407 -127
- package/package.json +1 -1
- package/resources/fe-dist/assets/{DevicePage-RqH-pnZX.js → DevicePage-5vkaNOjl.js} +2 -2
- package/resources/fe-dist/assets/DevicesPage-CKnRUGQm.js +2 -0
- package/resources/fe-dist/assets/FilePage-Dj0cszD4.css +1 -0
- package/resources/fe-dist/assets/FilePage-Uj-tzGW7.js +283 -0
- package/resources/fe-dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/resources/fe-dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/resources/fe-dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/resources/fe-dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/resources/fe-dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/resources/fe-dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/resources/fe-dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/resources/fe-dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/resources/fe-dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/resources/fe-dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/resources/fe-dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/resources/fe-dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/resources/fe-dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/resources/fe-dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/resources/fe-dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/resources/fe-dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/resources/fe-dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/resources/fe-dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/resources/fe-dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/resources/fe-dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/resources/fe-dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/resources/fe-dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/resources/fe-dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/resources/fe-dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/resources/fe-dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/resources/fe-dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/resources/fe-dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/resources/fe-dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/resources/fe-dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/resources/fe-dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/resources/fe-dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/resources/fe-dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/resources/fe-dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/resources/fe-dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/resources/fe-dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/resources/fe-dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/resources/fe-dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/resources/fe-dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/resources/fe-dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/resources/fe-dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/resources/fe-dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/resources/fe-dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/resources/fe-dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/resources/fe-dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/resources/fe-dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/resources/fe-dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/resources/fe-dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/resources/fe-dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/resources/fe-dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/resources/fe-dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/resources/fe-dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/resources/fe-dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/resources/fe-dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/resources/fe-dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/resources/fe-dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/resources/fe-dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/resources/fe-dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/resources/fe-dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/resources/fe-dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/resources/fe-dist/assets/SettingsPage-Cfzr_Phh.js +22 -0
- package/resources/fe-dist/assets/arc-Wv219fq_.js +2 -0
- package/resources/fe-dist/assets/architectureDiagram-3BPJPVTR-DkPPo2hY.js +37 -0
- package/resources/fe-dist/assets/blockDiagram-GPEHLZMM-DPAThozG.js +133 -0
- package/resources/fe-dist/assets/c4Diagram-AAUBKEIU-DBs_N-_p.js +11 -0
- package/resources/fe-dist/assets/card-Dl0HC88A.js +2 -0
- package/resources/fe-dist/assets/channel-DyLhDM_y.js +2 -0
- package/resources/fe-dist/assets/chunk-2J33WTMH-D3mrUPCp.js +2 -0
- package/resources/fe-dist/assets/chunk-4BX2VUAB-C0DRv58j.js +2 -0
- package/resources/fe-dist/assets/chunk-55IACEB6-DheUp7iQ.js +2 -0
- package/resources/fe-dist/assets/chunk-727SXJPM-Cvew2yIJ.js +207 -0
- package/resources/fe-dist/assets/chunk-AQP2D5EJ-DUoa4Wdg.js +232 -0
- package/resources/fe-dist/assets/chunk-FMBD7UC4-Bt9Oi52P.js +16 -0
- package/resources/fe-dist/assets/chunk-ND2GUHAM-DlWpyDaS.js +2 -0
- package/resources/fe-dist/assets/chunk-QZHKN3VN-BZtXwgRW.js +2 -0
- package/resources/fe-dist/assets/classDiagram-4FO5ZUOK-DA8DiM06.js +2 -0
- package/resources/fe-dist/assets/classDiagram-v2-Q7XG4LA2-DA8DiM06.js +2 -0
- package/resources/fe-dist/assets/cose-bilkent-S5V4N54A-yKy6sTY_.js +2 -0
- package/resources/fe-dist/assets/cytoscape.esm-DTSO7Bv0.js +332 -0
- package/resources/fe-dist/assets/dagre-BM42HDAG-DL4fpno6.js +5 -0
- package/resources/fe-dist/assets/defaultLocale-DX6XiGOO.js +2 -0
- package/resources/fe-dist/assets/diagram-2AECGRRQ-BueYws-9.js +44 -0
- package/resources/fe-dist/assets/diagram-5GNKFQAL-GQEQSUeb.js +11 -0
- package/resources/fe-dist/assets/diagram-KO2AKTUF-LE3yI4ed.js +4 -0
- package/resources/fe-dist/assets/diagram-LMA3HP47-BkHjYrU4.js +25 -0
- package/resources/fe-dist/assets/diagram-OG6HWLK6-DrnHic-P.js +25 -0
- package/resources/fe-dist/assets/erDiagram-TEJ5UH35-BCwWv-rO.js +86 -0
- package/resources/fe-dist/assets/flowDiagram-I6XJVG4X-DEC2Z_fh.js +163 -0
- package/resources/fe-dist/assets/ganttDiagram-6RSMTGT7-H1T5bCsY.js +293 -0
- package/resources/fe-dist/assets/gitGraphDiagram-PVQCEYII-DmZUfKfl.js +107 -0
- package/resources/fe-dist/assets/graph-CAnANduQ.js +2 -0
- package/resources/fe-dist/assets/index-OpBFduyh.js +466 -0
- package/resources/fe-dist/assets/index-yMgNjHUH.css +1 -0
- package/resources/fe-dist/assets/infoDiagram-5YYISTIA-fDOg9Qr5.js +3 -0
- package/resources/fe-dist/assets/init-Gi6I4Gst.js +2 -0
- package/resources/fe-dist/assets/ishikawaDiagram-YF4QCWOH-QIvSJI3q.js +71 -0
- package/resources/fe-dist/assets/journeyDiagram-JHISSGLW-Iz7u4iH8.js +140 -0
- package/resources/fe-dist/assets/kanban-definition-UN3LZRKU-BYiFSFgn.js +90 -0
- package/resources/fe-dist/assets/layout-DGIYPm2g.js +2 -0
- package/resources/fe-dist/assets/linear-DNHZFKop.js +2 -0
- package/resources/fe-dist/assets/mermaid.core-DUipsjFg.js +310 -0
- package/resources/fe-dist/assets/mindmap-definition-RKZ34NQL-tPbrKC3m.js +97 -0
- package/resources/fe-dist/assets/ordinal-BENe2yWM.js +2 -0
- package/resources/fe-dist/assets/pieDiagram-4H26LBE5-26o8qBzb.js +31 -0
- package/resources/fe-dist/assets/quadrantDiagram-W4KKPZXB-BgpGo9Ak.js +8 -0
- package/resources/fe-dist/assets/{refresh-cw-D0LYIwxc.js → refresh-cw-DdcimDhs.js} +3 -3
- package/resources/fe-dist/assets/requirementDiagram-4Y6WPE33-BEfrxsDZ.js +85 -0
- package/resources/fe-dist/assets/sankeyDiagram-5OEKKPKP-BuIeHyjh.js +41 -0
- package/resources/fe-dist/assets/sequenceDiagram-3UESZ5HK-CL0sinOn.js +163 -0
- package/resources/fe-dist/assets/stateDiagram-AJRCARHV-BCq5X6hO.js +2 -0
- package/resources/fe-dist/assets/stateDiagram-v2-BHNVJYJU-DH2ctCND.js +2 -0
- package/resources/fe-dist/assets/timeline-definition-PNZ67QCA-CnqqA91O.js +121 -0
- package/resources/fe-dist/assets/vennDiagram-CIIHVFJN-BqFG3JXB.js +35 -0
- package/resources/fe-dist/assets/wardley-L42UT6IY-DvfZKNwT.js +174 -0
- package/resources/fe-dist/assets/wardleyDiagram-YWT4CUSO-DlABpMGt.js +79 -0
- package/resources/fe-dist/assets/xychartDiagram-2RQKCTM6-BDiyUuus.js +8 -0
- package/resources/fe-dist/index.html +2 -2
- package/resources/gateway-drizzle/0007_fearless_pestilence.sql +8 -0
- package/resources/gateway-drizzle/0008_perfect_ozymandias.sql +7 -0
- package/resources/gateway-drizzle/meta/_journal.json +14 -0
- package/resources/fe-dist/assets/DevicesPage-BPLJu-5J.js +0 -2
- package/resources/fe-dist/assets/SettingsPage-CKP305BP.js +0 -22
- package/resources/fe-dist/assets/card-X35xwXzW.js +0 -2
- package/resources/fe-dist/assets/index-CKQEHZcV.css +0 -1
- package/resources/fe-dist/assets/index-O2a9149K.js +0 -400
package/dist/runtime/server.js
CHANGED
|
@@ -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
|
|
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+
|
|
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+
|
|
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+
|
|
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+
|
|
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
|
|
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
|
|
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
|
|
103750
|
+
return json5({ error: t2("apiError.llmProviderNameRequired") }, 400);
|
|
102477
103751
|
}
|
|
102478
103752
|
if (!PROTOCOLS.includes(body.protocol)) {
|
|
102479
|
-
return
|
|
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
|
|
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
|
|
103761
|
+
return json5({ error: t2("apiError.llmProviderApiKeyRequired") }, 400);
|
|
102488
103762
|
}
|
|
102489
103763
|
if (body.enabled !== undefined && typeof body.enabled !== "boolean") {
|
|
102490
|
-
return
|
|
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
|
|
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
|
|
103779
|
+
return json5({ error: t2("apiError.llmProviderNotFound") }, 404);
|
|
102506
103780
|
}
|
|
102507
103781
|
const raw = await readJsonObjectBody2(req);
|
|
102508
103782
|
if (!raw) {
|
|
102509
|
-
return
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
103849
|
+
return json5({ error: t2("apiError.llmProviderNotFound") }, 404);
|
|
102576
103850
|
}
|
|
102577
103851
|
deleteLlmProvider(id);
|
|
102578
|
-
return
|
|
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
|
|
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
|
|
103861
|
+
return json5({ error: modelsError ?? t2("apiError.invalidRequest") }, 502);
|
|
102588
103862
|
}
|
|
102589
|
-
return
|
|
103863
|
+
return json5({ models });
|
|
102590
103864
|
}
|
|
102591
103865
|
async function handleGetSettings() {
|
|
102592
|
-
return
|
|
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
|
|
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
|
|
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
|
|
103883
|
+
return json5({ error: t2("apiError.invalidRequest") }, 400);
|
|
102610
103884
|
}
|
|
102611
103885
|
if (body.defaultProviderId !== null && !getLlmProviderById(body.defaultProviderId)) {
|
|
102612
|
-
return
|
|
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
|
|
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
|
|
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
|
|
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
|
|
103911
|
+
return json5({ settings: toSettingsDto(settings) });
|
|
102638
103912
|
}
|
|
102639
|
-
function
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
105095
|
+
return json7({ error: t2("apiError.agentDeviceRequired") }, 400);
|
|
103822
105096
|
}
|
|
103823
105097
|
if (!getDeviceById(deviceId)) {
|
|
103824
|
-
return
|
|
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
|
|
105102
|
+
return json7({ error: t2("apiError.agentPaneRequired") }, 400);
|
|
103829
105103
|
}
|
|
103830
105104
|
if (!TRIGGER_TYPES.includes(body.triggerType)) {
|
|
103831
|
-
return
|
|
105105
|
+
return json7({ error: t2("apiError.watchTriggerTypeInvalid") }, 400);
|
|
103832
105106
|
}
|
|
103833
105107
|
const parsed = parseRuleFields(raw);
|
|
103834
105108
|
if (!parsed.ok) {
|
|
103835
|
-
return
|
|
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
|
|
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
|
|
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
|
|
105150
|
+
return json7({ error: t2("apiError.watchRuleNotFound") }, 404);
|
|
103877
105151
|
}
|
|
103878
105152
|
const state = getWatchRuleState(id);
|
|
103879
|
-
return
|
|
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
|
|
105158
|
+
return json7({ error: t2("apiError.watchRuleNotFound") }, 404);
|
|
103885
105159
|
}
|
|
103886
105160
|
const raw = await readJsonObjectBody3(req);
|
|
103887
105161
|
if (!raw) {
|
|
103888
|
-
return
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
105202
|
+
return json7({ error: semanticError }, 400);
|
|
103929
105203
|
}
|
|
103930
105204
|
const rule = updateWatchRule(id, updates);
|
|
103931
105205
|
if (!rule) {
|
|
103932
|
-
return
|
|
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
|
|
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
|
|
105215
|
+
return json7({ error: t2("apiError.watchRuleNotFound") }, 404);
|
|
103942
105216
|
}
|
|
103943
105217
|
deleteWatchRule(id);
|
|
103944
105218
|
await deps.service.removeRule(id);
|
|
103945
|
-
return
|
|
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
|
|
105224
|
+
return json7({ error: t2("apiError.watchRuleNotFound") }, 404);
|
|
103951
105225
|
}
|
|
103952
105226
|
const state = getWatchRuleState(id);
|
|
103953
|
-
return
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
105524
|
+
return json8({ status: "ok", restarting: runtimeController.isRestarting() });
|
|
104245
105525
|
}
|
|
104246
|
-
return
|
|
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
|
|
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
|
|
105545
|
+
return json8({ error: t2("apiError.deviceNotFound") }, 404);
|
|
104266
105546
|
}
|
|
104267
|
-
return
|
|
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
|
|
105552
|
+
return json8({ error: t2("apiError.missingFields") }, 400);
|
|
104273
105553
|
}
|
|
104274
105554
|
if (body.type === "ssh" && !body.host && !body.sshConfigRef) {
|
|
104275
|
-
return
|
|
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
|
|
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
|
|
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
|
|
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
|
|
105617
|
+
return json8({ error: t2("apiError.invalidRequest") }, 400);
|
|
104338
105618
|
}
|
|
104339
105619
|
reorderDevices(body.deviceIds);
|
|
104340
|
-
return
|
|
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
|
|
105625
|
+
return json8({ error: t2("apiError.deviceNotFound") }, 404);
|
|
104346
105626
|
}
|
|
104347
105627
|
deleteDevice(id);
|
|
104348
105628
|
pushSupervisor.remove(id);
|
|
104349
|
-
return
|
|
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
|
|
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
|
|
105642
|
+
return json8({ settings });
|
|
104363
105643
|
} catch (err) {
|
|
104364
|
-
return
|
|
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
|
|
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
|
|
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
|
|
105663
|
+
return json8({ error: t2("apiError.botNameRequired") }, 400);
|
|
104384
105664
|
}
|
|
104385
105665
|
if (!body.token?.trim()) {
|
|
104386
|
-
return
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
105716
|
+
return json8({ error: t2("apiError.botNotFound") }, 404);
|
|
104437
105717
|
}
|
|
104438
105718
|
deleteTelegramBot(botId);
|
|
104439
105719
|
await telegramService.refresh();
|
|
104440
|
-
return
|
|
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
|
|
105725
|
+
return json8({ error: t2("apiError.botNotFound") }, 404);
|
|
104446
105726
|
}
|
|
104447
105727
|
const chats = listTelegramChatsByBot(botId);
|
|
104448
|
-
return
|
|
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
|
|
105733
|
+
return json8({ error: t2("apiError.botNotFound") }, 404);
|
|
104454
105734
|
}
|
|
104455
105735
|
const chat = approveTelegramChat(botId, chatId);
|
|
104456
105736
|
if (!chat) {
|
|
104457
|
-
return
|
|
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
|
|
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
|
|
105749
|
+
return json8({ error: t2("apiError.botNotFound") }, 404);
|
|
104470
105750
|
}
|
|
104471
105751
|
deleteTelegramChat(botId, chatId);
|
|
104472
|
-
return
|
|
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
|
|
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
|
|
105764
|
+
return json8({ success: true });
|
|
104485
105765
|
}
|
|
104486
105766
|
async function handleGetWebhooks() {
|
|
104487
105767
|
const webhooks = getAllWebhookEndpoints();
|
|
104488
|
-
return
|
|
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
|
|
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
|
|
105786
|
+
return json8({ webhook: endpoint }, 201);
|
|
104507
105787
|
}
|
|
104508
105788
|
async function handleDeleteWebhook(id) {
|
|
104509
105789
|
deleteWebhookEndpoint(id);
|
|
104510
|
-
return
|
|
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
|
|
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
|
|
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 =
|
|
106407
|
-
return
|
|
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) &&
|
|
107715
|
+
if (!existsSync5(requestedPath) && extname2(url2.pathname) !== "") {
|
|
106436
107716
|
return new Response(t3("runtime.notFound"), { status: 404 });
|
|
106437
107717
|
}
|
|
106438
|
-
const indexPath =
|
|
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 });
|