termdock 1.0.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/LICENSE +21 -0
- package/README.md +385 -0
- package/dist/client/apple-splash-default-1170x2532.png +0 -0
- package/dist/client/apple-splash-landscape-1136x640.png +0 -0
- package/dist/client/apple-splash-landscape-1334x750.png +0 -0
- package/dist/client/apple-splash-landscape-1792x828.png +0 -0
- package/dist/client/apple-splash-landscape-2048x1536.png +0 -0
- package/dist/client/apple-splash-landscape-2160x1620.png +0 -0
- package/dist/client/apple-splash-landscape-2208x1242.png +0 -0
- package/dist/client/apple-splash-landscape-2224x1668.png +0 -0
- package/dist/client/apple-splash-landscape-2266x1488.png +0 -0
- package/dist/client/apple-splash-landscape-2360x1640.png +0 -0
- package/dist/client/apple-splash-landscape-2388x1668.png +0 -0
- package/dist/client/apple-splash-landscape-2436x1125.png +0 -0
- package/dist/client/apple-splash-landscape-2532x1170.png +0 -0
- package/dist/client/apple-splash-landscape-2556x1179.png +0 -0
- package/dist/client/apple-splash-landscape-2622x1206.png +0 -0
- package/dist/client/apple-splash-landscape-2688x1242.png +0 -0
- package/dist/client/apple-splash-landscape-2732x2048.png +0 -0
- package/dist/client/apple-splash-landscape-2778x1284.png +0 -0
- package/dist/client/apple-splash-landscape-2796x1290.png +0 -0
- package/dist/client/apple-splash-landscape-2868x1320.png +0 -0
- package/dist/client/apple-splash-portrait-1125x2436.png +0 -0
- package/dist/client/apple-splash-portrait-1170x2532.png +0 -0
- package/dist/client/apple-splash-portrait-1179x2556.png +0 -0
- package/dist/client/apple-splash-portrait-1206x2622.png +0 -0
- package/dist/client/apple-splash-portrait-1242x2208.png +0 -0
- package/dist/client/apple-splash-portrait-1242x2688.png +0 -0
- package/dist/client/apple-splash-portrait-1284x2778.png +0 -0
- package/dist/client/apple-splash-portrait-1290x2796.png +0 -0
- package/dist/client/apple-splash-portrait-1320x2868.png +0 -0
- package/dist/client/apple-splash-portrait-1488x2266.png +0 -0
- package/dist/client/apple-splash-portrait-1536x2048.png +0 -0
- package/dist/client/apple-splash-portrait-1620x2160.png +0 -0
- package/dist/client/apple-splash-portrait-1640x2360.png +0 -0
- package/dist/client/apple-splash-portrait-1668x2224.png +0 -0
- package/dist/client/apple-splash-portrait-1668x2388.png +0 -0
- package/dist/client/apple-splash-portrait-2048x2732.png +0 -0
- package/dist/client/apple-splash-portrait-640x1136.png +0 -0
- package/dist/client/apple-splash-portrait-750x1334.png +0 -0
- package/dist/client/apple-splash-portrait-828x1792.png +0 -0
- package/dist/client/apple-touch-icon-180x180.png +0 -0
- package/dist/client/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/dist/client/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/dist/client/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/dist/client/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/dist/client/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/dist/client/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/dist/client/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/dist/client/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/dist/client/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/dist/client/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/dist/client/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/dist/client/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/dist/client/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/dist/client/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/dist/client/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/dist/client/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/dist/client/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/dist/client/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/dist/client/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/dist/client/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/dist/client/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/dist/client/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/dist/client/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/dist/client/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/dist/client/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/dist/client/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/dist/client/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/dist/client/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/dist/client/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/dist/client/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/dist/client/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/dist/client/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/dist/client/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/dist/client/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/dist/client/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/dist/client/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/dist/client/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/dist/client/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/dist/client/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/dist/client/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/dist/client/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/dist/client/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/dist/client/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/dist/client/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/dist/client/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/dist/client/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/dist/client/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/dist/client/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/dist/client/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/dist/client/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/dist/client/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/dist/client/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/dist/client/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/dist/client/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/dist/client/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/dist/client/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/dist/client/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/dist/client/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/dist/client/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/dist/client/assets/abnfDiagram-VRR7QNED-D0NxeSHA.js +1 -0
- package/dist/client/assets/arc-B7GoKc6u.js +1 -0
- package/dist/client/assets/architectureDiagram-ZJ3FMSHR-BQPW-wUx.js +36 -0
- package/dist/client/assets/blockDiagram-677ZJIJ3-CX_hbcgG.js +132 -0
- package/dist/client/assets/c4Diagram-LMCZKHZV-BwOMQA4x.js +10 -0
- package/dist/client/assets/channel-C2gUFcyU.js +1 -0
- package/dist/client/assets/chunk-2Q5K7J3B-BLJzEQXz.js +1 -0
- package/dist/client/assets/chunk-32BRIVSS-CjBDr_gz.js +1 -0
- package/dist/client/assets/chunk-5VM5RSS4-lddvv0x2.js +15 -0
- package/dist/client/assets/chunk-EX3LRPZG-Dtsq1Stg.js +231 -0
- package/dist/client/assets/chunk-JWPE2WC7-BG3PZx4j.js +1 -0
- package/dist/client/assets/chunk-MOJQB5TN-CMtlCuQg.js +88 -0
- package/dist/client/assets/chunk-RYQCIY6F-uplKqw64.js +1 -0
- package/dist/client/assets/chunk-V7JOEXUC-CpteLsY3.js +206 -0
- package/dist/client/assets/chunk-VR4S4FIN-1zYOJQXL.js +1 -0
- package/dist/client/assets/chunk-XXDRQBXY-C0wXH91I.js +1 -0
- package/dist/client/assets/classDiagram-OUVF2IWQ-BTOnA9HS.js +1 -0
- package/dist/client/assets/classDiagram-v2-EOCWNBFH-BTOnA9HS.js +1 -0
- package/dist/client/assets/cose-bilkent-JH36ORCC-BceT5ki2.js +1 -0
- package/dist/client/assets/cynefin-VYW2F7L2-BqCIkNeC.js +166 -0
- package/dist/client/assets/cynefinDiagram-TSTJHNR4-Dm7y-tsN.js +62 -0
- package/dist/client/assets/cytoscape.esm-D3_iZ_3b.js +321 -0
- package/dist/client/assets/dagre-VKFMJZFB-Bn8eh0lE.js +4 -0
- package/dist/client/assets/defaultLocale-CrowFXzY.js +1 -0
- package/dist/client/assets/diagram-FQU43EPY-DmZGMAsX.js +3 -0
- package/dist/client/assets/diagram-G47NLZAW-BLWSm_Rn.js +24 -0
- package/dist/client/assets/diagram-NH7WQ7WH-C2-HK8pv.js +24 -0
- package/dist/client/assets/diagram-OA4YK3LP-8Ex4XIU5.js +30 -0
- package/dist/client/assets/diagram-WEI45ONY-MRNIpBXG.js +41 -0
- package/dist/client/assets/diffWorker-B6msVyjo.js +18 -0
- package/dist/client/assets/dnd-BCFAPC0L.js +1 -0
- package/dist/client/assets/ebnfDiagram-CCIWWBDH-D7Z6wZi_.js +1 -0
- package/dist/client/assets/erDiagram-Q63AITRT-C96Q5x9y.js +85 -0
- package/dist/client/assets/flowDiagram-23GEKE2U-DzQp40QH.js +156 -0
- package/dist/client/assets/ganttDiagram-NO4QXBWP-ZzkchZJ8.js +292 -0
- package/dist/client/assets/gitGraphDiagram-IHSO6WYX-CFacEf54.js +106 -0
- package/dist/client/assets/graph-D2o_JWn5.js +1 -0
- package/dist/client/assets/index-Ca-rq7yX.js +6 -0
- package/dist/client/assets/index-Cv7q4nZR.css +1 -0
- package/dist/client/assets/index-XktPMm51.js +394 -0
- package/dist/client/assets/infoDiagram-FWYZ7A6U-CVRXs5rF.js +2 -0
- package/dist/client/assets/init-Gi6I4Gst.js +1 -0
- package/dist/client/assets/ishikawaDiagram-FXEZZL3T-B8FP_wzM.js +70 -0
- package/dist/client/assets/journeyDiagram-5HDEW3XC-BR__4Hbd.js +139 -0
- package/dist/client/assets/kanban-definition-HUTT4EX6-v39oZe6X.js +89 -0
- package/dist/client/assets/katex-55ZPZeOF.css +1 -0
- package/dist/client/assets/katex-DnlPpQZa.js +257 -0
- package/dist/client/assets/katex-HP8lGamR.js +257 -0
- package/dist/client/assets/layout-1eBIAoSl.js +1 -0
- package/dist/client/assets/linear-jlTiHqO6.js +1 -0
- package/dist/client/assets/map-BdqsVdb3.js +1 -0
- package/dist/client/assets/mermaid.core-DiiIN0EC.js +306 -0
- package/dist/client/assets/mindmap-definition-LN4V7U3C-AeUxAZeq.js +96 -0
- package/dist/client/assets/ordinal-Cboi1Yqb.js +1 -0
- package/dist/client/assets/pegDiagram-2B236MQR-Dh-bgAbv.js +1 -0
- package/dist/client/assets/pieDiagram-ENE6RG2P-De7Si7Tm.js +39 -0
- package/dist/client/assets/purify.es-CC4Brkr_.js +3 -0
- package/dist/client/assets/quadrantDiagram-ABIIQ3AL-CgWfHqy0.js +7 -0
- package/dist/client/assets/railroadDiagram-RFXS5EU6-BXnQW-pI.js +1 -0
- package/dist/client/assets/react-XDCjal2T.js +8 -0
- package/dist/client/assets/requirementDiagram-TGXJPOKE-CU1nnpUM.js +84 -0
- package/dist/client/assets/sankeyDiagram-HTMAVEWB-DFK-AXY6.js +40 -0
- package/dist/client/assets/sequenceDiagram-DBY2YBRQ-D_bVDWgq.js +162 -0
- package/dist/client/assets/sizeCapture-X5ZJPWSS-nh89ExHT.js +1 -0
- package/dist/client/assets/stateDiagram-2N3HPSRC-DUvT6Ruk.js +1 -0
- package/dist/client/assets/stateDiagram-v2-6OUMAXLB-Dz-3r-Yq.js +1 -0
- package/dist/client/assets/swimlanes-5IMT3BWC-ZYa52gjG.js +2 -0
- package/dist/client/assets/swimlanesDiagram-G3AALYLV-DXR_9lf9.js +8 -0
- package/dist/client/assets/terminal-C7X98Amf.js +10 -0
- package/dist/client/assets/timeline-definition-FHXFAJF6-Bp6A49KQ.js +120 -0
- package/dist/client/assets/vennDiagram-L72KCM5P-CDDUmLOI.js +34 -0
- package/dist/client/assets/wardleyDiagram-EHGQE667-CRc2ptu7.js +78 -0
- package/dist/client/assets/xychartDiagram-FW5EYKEG-ht_S0LUA.js +7 -0
- package/dist/client/favicon.ico +0 -0
- package/dist/client/fonts/JetBrainsMonoNL-Bold.woff2 +0 -0
- package/dist/client/fonts/JetBrainsMonoNL-BoldItalic.woff2 +0 -0
- package/dist/client/fonts/JetBrainsMonoNL-Italic.woff2 +0 -0
- package/dist/client/fonts/JetBrainsMonoNL-Regular.woff2 +0 -0
- package/dist/client/fonts/JetBrainsMonoNLNerdFontMono-Bold.ttf +0 -0
- package/dist/client/fonts/JetBrainsMonoNLNerdFontMono-BoldItalic.ttf +0 -0
- package/dist/client/fonts/JetBrainsMonoNLNerdFontMono-Italic.ttf +0 -0
- package/dist/client/fonts/JetBrainsMonoNLNerdFontMono-Regular.ttf +0 -0
- package/dist/client/fonts/NotoSansMonoCJKsc-Bold-Subset.woff2 +0 -0
- package/dist/client/fonts/NotoSansMonoCJKsc-Subset.woff2 +0 -0
- package/dist/client/fonts/NotoSansSymbols2-Subset.woff2 +0 -0
- package/dist/client/fonts/SymbolsNerdFontMono-Regular.woff2 +0 -0
- package/dist/client/fonts/TermdockStarSymbol-Subset.woff2 +0 -0
- package/dist/client/index.html +255 -0
- package/dist/client/manifest.webmanifest +1 -0
- package/dist/client/maskable-icon-512x512.png +0 -0
- package/dist/client/pwa-192x192.png +0 -0
- package/dist/client/pwa-192x192.svg +5 -0
- package/dist/client/pwa-512x512.png +0 -0
- package/dist/client/pwa-512x512.svg +5 -0
- package/dist/client/pwa-64x64.png +0 -0
- package/dist/client/registerSW.js +1 -0
- package/dist/client/robots.txt +4 -0
- package/dist/client/shell-integration/termdock.bash +107 -0
- package/dist/client/shell-integration/termdock.fish +60 -0
- package/dist/client/shell-integration/termdock.zsh +164 -0
- package/dist/client/sw-notifications.js +42 -0
- package/dist/client/sw.js +1 -0
- package/dist/client/workbox-e4022e15.js +1 -0
- package/dist/server/certificateWatcher.js +111 -0
- package/dist/server/cli.js +2534 -0
- package/dist/server/config.js +54 -0
- package/dist/server/entry.js +571 -0
- package/dist/server/onboardingServer.js +54 -0
- package/dist/server/routes/auth.js +48 -0
- package/dist/server/routes/filesystem.js +3749 -0
- package/dist/server/routes/local.js +32 -0
- package/dist/server/routes/onboarding.js +134 -0
- package/dist/server/routes/terminal.js +4879 -0
- package/dist/server/utils/authProtection.js +338 -0
- package/dist/server/utils/caffeinate.js +124 -0
- package/dist/server/utils/changeAuditStore.js +521 -0
- package/dist/server/utils/cookieSecurity.js +13 -0
- package/dist/server/utils/csrfProtection.js +112 -0
- package/dist/server/utils/localAccess.js +211 -0
- package/dist/server/utils/pathValidator.js +272 -0
- package/dist/server/utils/requestSecurity.js +103 -0
- package/dist/server/utils/serverLogger.js +57 -0
- package/dist/server/utils/settings.js +157 -0
- package/dist/server/utils/tmuxFocus.js +45 -0
- package/dist/server/utils/tmuxProgramDetection.js +148 -0
- package/package.json +125 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
# Termdock
|
|
2
|
+
|
|
3
|
+
一个面向移动端与桌面端的 Web 终端,由 tmux 持久托管会话,xterm.js + WebGL 负责渲染,Express + WebSocket 提供后端通信。
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
## 功能特性
|
|
8
|
+
|
|
9
|
+
### 终端能力
|
|
10
|
+
|
|
11
|
+
- **xterm.js + WebGL 渲染**:使用 `@xterm/addon-webgl` 加速绘制,自动处理上下文丢失与纹理刷新
|
|
12
|
+
- **tmux 持久会话**:所有会话由 tmux 托管,关闭页面/掉线后仍可恢复,支持 `detach`、`destroy`、强杀
|
|
13
|
+
- **WebSocket 双向通信**:单条持久连接同时承载输入与输出(取代旧的 SSE + POST 方案)
|
|
14
|
+
- **自动重连**:网络或后端中断后会自动尝试 attach 回原会话
|
|
15
|
+
- **鼠标支持**:完整透传 SGR 鼠标协议,vim、htop、tmux copy-mode 内的滚动/点击都按预期工作
|
|
16
|
+
- **OSC 0 CWD 嗅探**:标签页可动态显示当前进程或目录,无需轮询 `/proc`
|
|
17
|
+
|
|
18
|
+
### 多会话与标签栏
|
|
19
|
+
|
|
20
|
+
- **多会话管理**:创建、切换、重启、重命名(双击标签)、强杀
|
|
21
|
+
- **预渲染所有会话**:避免页面切换时 WebGL 上下文丢失
|
|
22
|
+
- **磁盘持久化**:会话布局与 tmux 元数据落盘,重启后自动恢复
|
|
23
|
+
|
|
24
|
+
### 移动端体验
|
|
25
|
+
|
|
26
|
+
- **Swiper 翻页**:左右滑动在多个终端之间切换,与终端内滚动手势已做冲突隔离
|
|
27
|
+
- **触摸优先的设置抽屉**:分 Tab、可滑动、长按 destroy
|
|
28
|
+
- **可定制虚拟键盘**:内置 Esc / Tab / Ctrl / Alt / Cmd / 方向键 / Enter / Backspace,并支持自定义工具条预设
|
|
29
|
+
- **手势**:点击 = 鼠标左键,长按 = 右键,捏合缩放调字号,触摸滑动 = 终端滚动
|
|
30
|
+
- **iOS 适配**:处理选择菜单、键盘弹起、翻页与会话恢复时的纹理刷新等细节
|
|
31
|
+
|
|
32
|
+
### 安全与认证
|
|
33
|
+
|
|
34
|
+
- **密码保护**(可选):通过 `termdock --set-password` 启用,登录页 + Cookie 会话
|
|
35
|
+
- **登录限流**:基于来源 IP 的指数退避,防暴力破解
|
|
36
|
+
- **CSRF 防护**:所有写入接口要求 CSRF token
|
|
37
|
+
- **WebSocket 升级鉴权**:未登录的 upgrade 请求会被 401 拒绝
|
|
38
|
+
- **路径校验**:内置 `pathValidator` 防止路径穿越
|
|
39
|
+
|
|
40
|
+
### PWA
|
|
41
|
+
|
|
42
|
+
- 自托管 JetBrains Mono NL + Symbols Nerd Font(含 Bold)
|
|
43
|
+
- 完整的 PWA 图标 / 启动屏 / manifest,可安装到主屏幕全屏运行
|
|
44
|
+
- Service Worker 缓存静态资源,支持离线打开
|
|
45
|
+
|
|
46
|
+
## 技术栈
|
|
47
|
+
|
|
48
|
+
- **前端**:React 18 + TypeScript + Vite 7
|
|
49
|
+
- **终端渲染**:`@xterm/xterm` + `@xterm/addon-webgl` + `@xterm/addon-fit`
|
|
50
|
+
- **状态管理**:Zustand
|
|
51
|
+
- **触摸滑动**:Swiper
|
|
52
|
+
- **拖拽排序**:dnd-kit
|
|
53
|
+
- **后端**:Express 5 + ws + node-pty + tmux
|
|
54
|
+
- **样式**:Tailwind CSS
|
|
55
|
+
- **图标**:Remix Icon + Nerd Fonts
|
|
56
|
+
|
|
57
|
+
## 快速开始
|
|
58
|
+
|
|
59
|
+
### 一行命令启动
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
npx termdock
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
默认监听 `0.0.0.0:9834`,并在后台运行。常用变体:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
npx termdock --host 127.0.0.1 --port 4000
|
|
69
|
+
termdock --foreground # 前台运行
|
|
70
|
+
termdock --status # 查看后台状态
|
|
71
|
+
termdock --stop # 停止后台服务
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 设置访问密码(强烈推荐)
|
|
75
|
+
|
|
76
|
+
如果服务暴露在 LAN 上,**务必先设置密码**,否则任何能访问到主机/端口的人都能执行 shell 命令:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
# 交互式设置(输入隐藏)
|
|
80
|
+
termdock --set-password
|
|
81
|
+
|
|
82
|
+
# 通过管道设置(CI / 脚本场景)
|
|
83
|
+
echo "my-secret" | termdock --set-password
|
|
84
|
+
|
|
85
|
+
# 关闭鉴权
|
|
86
|
+
termdock --clear-password
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
密码状态存放在 `~/.termdock/auth.json`(mode 0600,scrypt 哈希,不可逆)。修改密码会使所有已登录会话失效。
|
|
90
|
+
|
|
91
|
+
服务在未设置密码时启动会打印醒目的安全警告。
|
|
92
|
+
|
|
93
|
+
### 局域网 HTTPS 访问(手机 / 本机)
|
|
94
|
+
|
|
95
|
+
Termdock 可以为当前机器发布一个产品化的局域网地址:
|
|
96
|
+
|
|
97
|
+
```text
|
|
98
|
+
https://<name>.termdock.local:9834
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
`<name>` 会在首次启动时自动生成一个 4 位默认值,也可以在设置抽屉里的「本地访问」中自定义。自定义名称不做人为长度限制,但必须是合法 hostname label。
|
|
102
|
+
|
|
103
|
+
第一版仍然保留 `:9834` 端口;无端口的 `https://<name>.termdock.local` 需要后续单独引入 443 代理/Helper。
|
|
104
|
+
|
|
105
|
+
第一次直接运行 `termdock` 时,CLI 会先引导你选择 `.termdock.local` 前缀,并询问是否立刻启用 HTTPS;选择启用后会自动安装/配置 mkcert、生成证书,然后继续启动服务。
|
|
106
|
+
|
|
107
|
+
使用建议:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
# 1. 先启用密码,避免把 shell 暴露给同一内网其他人
|
|
111
|
+
termdock --set-password
|
|
112
|
+
|
|
113
|
+
# 2. 自动准备本地 HTTPS 证书
|
|
114
|
+
# 若未安装 mkcert,会自动通过 Homebrew 执行 brew install mkcert
|
|
115
|
+
termdock --setup-local-https
|
|
116
|
+
|
|
117
|
+
# 3. 正常启动;如果 ~/.termdock/certs/ 下已有证书,会自动启用 HTTPS
|
|
118
|
+
termdock
|
|
119
|
+
|
|
120
|
+
# 4. 查看正式地址和手机首次接入地址
|
|
121
|
+
termdock --status
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
该命令会生成并保存:
|
|
125
|
+
|
|
126
|
+
```text
|
|
127
|
+
~/.termdock/certs/termdock-local.pem
|
|
128
|
+
~/.termdock/certs/termdock-local-key.pem
|
|
129
|
+
~/.termdock/certs/rootCA.pem
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
也可以手动覆盖证书路径:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
termdock --https-cert <cert.pem> --https-key <key.pem> --https-ca <rootCA.pem>
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
手机首次接入时,先在同一 Wi‑Fi 下打开 `termdock --status` 或服务启动日志输出的 onboarding 地址,例如:
|
|
139
|
+
|
|
140
|
+
```text
|
|
141
|
+
http://192.168.1.23:52741/onboarding
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
该页面会提供 CA 证书下载和 iPhone / Android 安装步骤;如果只想直接下载证书,也可以打开更短的:
|
|
145
|
+
|
|
146
|
+
```text
|
|
147
|
+
http://192.168.1.23:52741/ca
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
安装并信任 CA 后,再打开正式地址:
|
|
151
|
+
|
|
152
|
+
```text
|
|
153
|
+
https://<name>.termdock.local:9834
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
注意:mDNS 依赖同一局域网的 `.local` 组播;访客 Wi‑Fi、客户端隔离、VPN 或部分企业网络可能会阻止解析。此时 `localhost` 访问仍然可用,但手机上的漂亮域名可能不可用。
|
|
157
|
+
|
|
158
|
+
### 从源码安装
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
git clone https://github.com/Jovines/termdock.git
|
|
162
|
+
cd termdock
|
|
163
|
+
./install-local.sh
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
脚本会执行 `npm install` → `npm rebuild node-pty --build-from-source` → `npm run build` → `npm install -g .`。在 macOS 上会额外检查 `node-pty` 的 `spawn-helper` 是否生成成功,若失败会提示安装 Xcode Command Line Tools。
|
|
167
|
+
|
|
168
|
+
若你开启了访问密码,并希望在自动化脚本里无交互访问(不关闭鉴权),可先尝试复用 cookie,再按需登录刷新:
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
# 首先直接尝试复用已有 cookie(推荐)
|
|
172
|
+
bash auth-login.sh
|
|
173
|
+
|
|
174
|
+
# 仅当 cookie 失效时,再提供原密码刷新登录态
|
|
175
|
+
export TERMDOCK_PASSWORD="<your-termdock-password>"
|
|
176
|
+
bash auth-login.sh
|
|
177
|
+
|
|
178
|
+
# 自动化请求统一带 cookie
|
|
179
|
+
curl -b ~/.termdock/automation.cookies http://localhost:9834/api/auth/status
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
这不会创建第二套密码,也不会关闭鉴权。
|
|
183
|
+
|
|
184
|
+
卸载:
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
./uninstall-local.sh
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### 开发模式
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
# 同时启动前后端
|
|
194
|
+
npm run dev
|
|
195
|
+
|
|
196
|
+
# 或分开启动
|
|
197
|
+
npm run dev:client # Vite 前端:9833
|
|
198
|
+
npm run dev:server # tsx watch 后端:9835
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
开发期请访问 `http://localhost:9833`,Vite 会把 API/WebSocket 代理到后端开发端口 9835。正式/本地安装服务独立使用 9834。
|
|
202
|
+
|
|
203
|
+
### 构建
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
npm run build
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
输出:
|
|
210
|
+
|
|
211
|
+
- `dist/client/`:前端静态资源
|
|
212
|
+
- `dist/server/`:Node.js 服务端 + CLI 入口
|
|
213
|
+
|
|
214
|
+
直接运行构建产物:
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
node dist/server/cli.js
|
|
218
|
+
# 或
|
|
219
|
+
npm start
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## 系统依赖
|
|
223
|
+
|
|
224
|
+
- **Node.js ≥ 18**
|
|
225
|
+
- **tmux**:会话托管必需,请确保 `tmux` 在 PATH 中
|
|
226
|
+
- **macOS**:需安装 Xcode Command Line Tools 以便 `node-pty` 编译 `spawn-helper`
|
|
227
|
+
- **Linux**:通常需要 `build-essential`、`python3` 才能编译 `node-pty`
|
|
228
|
+
|
|
229
|
+
### tmux 焦点跟踪
|
|
230
|
+
|
|
231
|
+
Termdock 复用系统默认 tmux server。每次创建、复用、切换或通过 CLI attach tmux 会话时,Termdock 会自动确保 shared tmux server 的 `focus-events` 为 `on`,并在浏览器焦点变化时把 focus in/out 事件按需转发给 tmux 内部请求了 focus tracking 的程序(例如 Claude Code、Vim、fzf 等)。这是单向增强项:Termdock 不会在会话关闭后把 `focus-events` 自动恢复为 `off`。如果你手动维护 `~/.tmux.conf`,也可以显式加入:
|
|
232
|
+
|
|
233
|
+
```tmux
|
|
234
|
+
set -g focus-events on
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## 项目结构
|
|
238
|
+
|
|
239
|
+
```
|
|
240
|
+
termdock/
|
|
241
|
+
├── src/
|
|
242
|
+
│ ├── main.tsx # 应用入口
|
|
243
|
+
│ ├── App.tsx # 根组件
|
|
244
|
+
│ ├── index.css # 全局样式
|
|
245
|
+
│ ├── lib/
|
|
246
|
+
│ │ ├── terminal/ # xterm 适配层、主题、API
|
|
247
|
+
│ │ ├── stores/ # Zustand store
|
|
248
|
+
│ │ │ ├── useTerminalStore.ts
|
|
249
|
+
│ │ │ └── useMultiSessionStore.ts
|
|
250
|
+
│ │ ├── components/
|
|
251
|
+
│ │ │ ├── MultiTerminalView.tsx # 多会话 Swiper 主视图
|
|
252
|
+
│ │ │ ├── auth/LoginScreen.tsx # 登录页
|
|
253
|
+
│ │ │ ├── terminal/ # 终端视图、错误/加载、移动键盘
|
|
254
|
+
│ │ │ ├── settings/ # 调试面板、工具条预设
|
|
255
|
+
│ │ │ ├── ui/ErrorBoundary.tsx
|
|
256
|
+
│ │ │ └── views/TerminalView.tsx
|
|
257
|
+
│ │ ├── hooks/ # 字号、滚动、断连清理、视口高度等
|
|
258
|
+
│ │ └── utils/ # 错误处理、调试
|
|
259
|
+
│ └── server/
|
|
260
|
+
│ ├── cli.ts # CLI 入口(前后台、密码管理)
|
|
261
|
+
│ ├── entry.ts # Express + WebSocket 启动
|
|
262
|
+
│ ├── config.ts # 端口配置(dev: 9833/9835,prod: 9834)
|
|
263
|
+
│ ├── routes/
|
|
264
|
+
│ │ ├── auth.ts # 登录 / 登出 / 状态
|
|
265
|
+
│ │ └── terminal.ts # 终端 + tmux 路由
|
|
266
|
+
│ └── utils/
|
|
267
|
+
│ ├── authProtection.ts # scrypt 密码哈希、会话、限流
|
|
268
|
+
│ ├── csrfProtection.ts
|
|
269
|
+
│ └── pathValidator.ts
|
|
270
|
+
├── public/ # PWA 图标、字体、manifest
|
|
271
|
+
├── install-local.sh / uninstall-local.sh
|
|
272
|
+
├── package.json
|
|
273
|
+
├── vite.config.ts
|
|
274
|
+
└── tsconfig.json
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
## 主要 API 端点
|
|
278
|
+
|
|
279
|
+
> 写入接口需要登录后获取 CSRF token,并通过 Cookie + token 一起调用。
|
|
280
|
+
|
|
281
|
+
### 鉴权
|
|
282
|
+
|
|
283
|
+
| 方法 | 端点 | 描述 |
|
|
284
|
+
|------|------|------|
|
|
285
|
+
| GET | `/api/auth/status` | 查询是否启用鉴权 / 当前 cookie 是否有效 |
|
|
286
|
+
| POST | `/api/auth/login` | 登录(限流) |
|
|
287
|
+
| POST | `/api/auth/logout` | 登出 |
|
|
288
|
+
| GET | `/api/csrf-token` | 获取 CSRF token(需登录) |
|
|
289
|
+
|
|
290
|
+
### 终端 / tmux
|
|
291
|
+
|
|
292
|
+
| 方法 | 端点 | 描述 |
|
|
293
|
+
|------|------|------|
|
|
294
|
+
| POST | `/api/terminal/create` | 创建新会话 |
|
|
295
|
+
| GET | `/api/terminal/:sessionId/ws` *(WebSocket)* | 双向通信通道 |
|
|
296
|
+
| POST | `/api/terminal/:sessionId/input` | 发送输入(HTTP 兜底) |
|
|
297
|
+
| POST | `/api/terminal/:sessionId/resize` | 调整终端尺寸 |
|
|
298
|
+
| POST | `/api/terminal/:sessionId/tmux` | 执行 tmux 控制命令 |
|
|
299
|
+
| POST | `/api/terminal/:sessionId/restart` | 重启会话 |
|
|
300
|
+
| POST | `/api/terminal/:sessionId/detach` | 断开 attach |
|
|
301
|
+
| GET | `/api/terminal/:sessionId/attach` | 重新 attach |
|
|
302
|
+
| GET | `/api/terminal/:sessionId/health` | 健康检查 |
|
|
303
|
+
| DELETE | `/api/terminal/:sessionId` | 关闭会话 |
|
|
304
|
+
| POST | `/api/terminal/force-kill` | 强制结束 |
|
|
305
|
+
| GET | `/api/terminal/tmux/sessions` | 列出所有 tmux 会话 |
|
|
306
|
+
| DELETE | `/api/terminal/tmux/sessions/:name` | 销毁指定 tmux 会话 |
|
|
307
|
+
| GET | `/api/terminal/processes` | 进程列表 |
|
|
308
|
+
|
|
309
|
+
## 主题
|
|
310
|
+
|
|
311
|
+
当前内置 **Flexoki Dark** —— 一套低对比度、暖色调的配色,长时间阅读更舒适。
|
|
312
|
+
主题定义在 `src/lib/terminal/theme.ts`,可按需扩展。
|
|
313
|
+
|
|
314
|
+
## 配置
|
|
315
|
+
|
|
316
|
+
### CLI 参数
|
|
317
|
+
|
|
318
|
+
```
|
|
319
|
+
--host <host> 绑定地址(默认 0.0.0.0)
|
|
320
|
+
--port <port> 监听端口(默认 9834)
|
|
321
|
+
--foreground 前台运行
|
|
322
|
+
--status 查看后台服务状态
|
|
323
|
+
--stop 停止后台服务
|
|
324
|
+
--set-password 设置 / 修改访问密码(交互式)
|
|
325
|
+
--clear-password 清除密码并关闭鉴权
|
|
326
|
+
-h, --help 查看帮助
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
### 环境变量
|
|
330
|
+
|
|
331
|
+
```bash
|
|
332
|
+
PORT=9834 # 正式/安装后服务端口;dev:server 使用 9835
|
|
333
|
+
HOST=0.0.0.0 # 绑定地址
|
|
334
|
+
NODE_ENV=development # 运行环境
|
|
335
|
+
TERM=xterm-256color # 终端类型
|
|
336
|
+
SHELL=/bin/zsh # 默认 shell
|
|
337
|
+
MAX_TERMINAL_SESSIONS=20 # 最大会话数
|
|
338
|
+
TERMINAL_IDLE_TIMEOUT=1800000 # 空闲超时 (毫秒)
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
### 状态目录
|
|
342
|
+
|
|
343
|
+
```
|
|
344
|
+
~/.termdock/
|
|
345
|
+
├── auth.json # 密码哈希(mode 0600,仅在启用鉴权时存在)
|
|
346
|
+
├── server.json # 后台进程 PID / 端口
|
|
347
|
+
└── server.log # 后台运行日志
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
## 移动端控制
|
|
351
|
+
|
|
352
|
+
### 虚拟按键
|
|
353
|
+
|
|
354
|
+
Esc / Tab / Ctrl / Alt / Cmd / ↑↓←→ / Enter / Backspace,并支持在设置中自定义工具条预设。
|
|
355
|
+
|
|
356
|
+
### 触摸交互
|
|
357
|
+
|
|
358
|
+
- **点击**:模拟鼠标左键
|
|
359
|
+
- **长按**:模拟鼠标右键
|
|
360
|
+
- **滑动**(终端区):滚动当前会话内容
|
|
361
|
+
- **滑动**(边缘):在多个会话之间翻页
|
|
362
|
+
- **捏合缩放**:调整字号
|
|
363
|
+
|
|
364
|
+
## 发布到 npm
|
|
365
|
+
|
|
366
|
+
```bash
|
|
367
|
+
npm publish
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
`prepublishOnly` 钩子会自动执行 `npm run build`。发布前请确认:
|
|
371
|
+
|
|
372
|
+
- npm 包名可用
|
|
373
|
+
- `repository` / `homepage` / `bugs` 字段已更新
|
|
374
|
+
- README、版本号已同步
|
|
375
|
+
|
|
376
|
+
## 浏览器支持
|
|
377
|
+
|
|
378
|
+
- Chrome 88+
|
|
379
|
+
- Firefox 79+
|
|
380
|
+
- Safari 14+(含 iOS 14+)
|
|
381
|
+
- Edge 88+
|
|
382
|
+
|
|
383
|
+
## 许可证
|
|
384
|
+
|
|
385
|
+
MIT
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|