2026-08-17 15:19:06 +00:00
( function ( ) {
"use strict" ;
2026-08-17 15:15:05 +00:00
const SDK = window . _ _HERMES _PLUGIN _SDK _ _ ;
2026-08-17 15:19:06 +00:00
const { React } = SDK ;
const { useState , useEffect , useCallback } = SDK . hooks ;
const { Card , CardHeader , CardTitle , CardContent , Button } = SDK . components ;
2026-08-17 15:23:40 +00:00
2026-08-19 00:00:34 +00:00
async function safeFetchJSON ( path , opts ) {
const res = await fetch ( path , opts || { } ) ;
const text = await res . text ( ) ;
try { return JSON . parse ( text ) ; } catch ( _ ) {
2026-09-03 04:21:03 +00:00
throw new Error ( "Server returned non-JSON (status " + res . status + "): " + text . slice ( 0 , 300 ) ) ;
2026-08-19 00:00:34 +00:00
}
}
2026-09-03 04:21:03 +00:00
function SSHXPage ( ) {
2026-08-17 15:15:05 +00:00
const [ link , setLink ] = useState ( null ) ;
2026-08-17 15:19:06 +00:00
const [ status , setStatus ] = useState ( "idle" ) ;
2026-08-17 15:15:05 +00:00
const [ error , setError ] = useState ( null ) ;
feat: replace sshx with ttyd - auto arch detection, no curl|sh, no dashboard restart
- __init__.py: replace curl|sh sshx install with urllib ttyd download, arch map x86_64/aarch64/arm/armhf/i686/mips*, cache to ~/.local/bin, no systemd restart, lazy warmup
- dashboard/plugin_api.py: full ttyd backend, auto-detect arch via platform.machine(), download from github releases, free port alloc, host header aware link, no _trigger_dashboard_restart, deprecated restart endpoint kept no-op
- dashboard/dist/index.js: ttyd UI with iframe embed, copy link, installing state, error handling, no restart notice
- plugin.yaml/manifest.json: bump 1.1.0, description ttyd, provides_tools ttyd_start
2026-08-28 12:47:44 +00:00
const start = useCallback ( async function ( ) {
2026-08-17 15:15:05 +00:00
setStatus ( "loading" ) ;
setError ( null ) ;
try {
2026-08-19 00:00:34 +00:00
var res = await safeFetchJSON ( "/api/plugins/sshx-link/status" ) ;
if ( res . status === "installing" ) {
setStatus ( "installing" ) ;
return ;
}
feat: replace sshx with ttyd - auto arch detection, no curl|sh, no dashboard restart
- __init__.py: replace curl|sh sshx install with urllib ttyd download, arch map x86_64/aarch64/arm/armhf/i686/mips*, cache to ~/.local/bin, no systemd restart, lazy warmup
- dashboard/plugin_api.py: full ttyd backend, auto-detect arch via platform.machine(), download from github releases, free port alloc, host header aware link, no _trigger_dashboard_restart, deprecated restart endpoint kept no-op
- dashboard/dist/index.js: ttyd UI with iframe embed, copy link, installing state, error handling, no restart notice
- plugin.yaml/manifest.json: bump 1.1.0, description ttyd, provides_tools ttyd_start
2026-08-28 12:47:44 +00:00
if ( res . status === "running" && res . link ) {
setLink ( res . link ) ;
setStatus ( "running" ) ;
return ;
}
2026-08-19 00:00:34 +00:00
res = await safeFetchJSON ( "/api/plugins/sshx-link/start" ) ;
2026-08-17 15:15:05 +00:00
if ( res . link ) {
setLink ( res . link ) ;
setStatus ( "running" ) ;
2026-09-03 04:21:03 +00:00
} else if ( res . status === "starting" ) {
setStatus ( "installing" ) ;
setError ( "sshx đang khởi động, thử lại sau 2s..." ) ;
setTimeout ( function ( ) { safeFetchJSON ( "/api/plugins/sshx-link/status" ) . then ( function ( r ) { if ( r . link ) { setLink ( r . link ) ; setStatus ( "running" ) ; setError ( null ) ; } } ) ; } , 2000 ) ;
2026-08-17 15:15:05 +00:00
} else {
setError ( res . message || "No link returned" ) ;
setStatus ( "error" ) ;
}
} catch ( err ) {
2026-09-03 04:21:03 +00:00
setError ( err . message || "Failed to start sshx" ) ;
2026-08-17 15:15:05 +00:00
setStatus ( "error" ) ;
}
} , [ ] ) ;
feat: replace sshx with ttyd - auto arch detection, no curl|sh, no dashboard restart
- __init__.py: replace curl|sh sshx install with urllib ttyd download, arch map x86_64/aarch64/arm/armhf/i686/mips*, cache to ~/.local/bin, no systemd restart, lazy warmup
- dashboard/plugin_api.py: full ttyd backend, auto-detect arch via platform.machine(), download from github releases, free port alloc, host header aware link, no _trigger_dashboard_restart, deprecated restart endpoint kept no-op
- dashboard/dist/index.js: ttyd UI with iframe embed, copy link, installing state, error handling, no restart notice
- plugin.yaml/manifest.json: bump 1.1.0, description ttyd, provides_tools ttyd_start
2026-08-28 12:47:44 +00:00
const stop = useCallback ( async function ( ) {
2026-08-17 15:15:05 +00:00
try {
2026-08-19 00:00:34 +00:00
await safeFetchJSON ( "/api/plugins/sshx-link/stop" , { method : "POST" } ) ;
2026-08-17 15:15:05 +00:00
setLink ( null ) ;
setStatus ( "idle" ) ;
2026-09-03 04:21:03 +00:00
setError ( null ) ;
2026-08-17 15:15:05 +00:00
} catch ( err ) {
setError ( err . message ) ;
}
} , [ ] ) ;
2026-08-17 15:19:06 +00:00
const checkStatus = useCallback ( async function ( ) {
2026-08-17 15:15:05 +00:00
try {
2026-08-19 00:00:34 +00:00
const res = await safeFetchJSON ( "/api/plugins/sshx-link/status" ) ;
2026-08-17 15:15:05 +00:00
if ( res . status === "running" && res . link ) {
setLink ( res . link ) ;
setStatus ( "running" ) ;
2026-09-03 04:21:03 +00:00
} else if ( res . status === "installing" || res . status === "starting" ) {
2026-08-19 00:00:34 +00:00
setStatus ( "installing" ) ;
feat: replace sshx with ttyd - auto arch detection, no curl|sh, no dashboard restart
- __init__.py: replace curl|sh sshx install with urllib ttyd download, arch map x86_64/aarch64/arm/armhf/i686/mips*, cache to ~/.local/bin, no systemd restart, lazy warmup
- dashboard/plugin_api.py: full ttyd backend, auto-detect arch via platform.machine(), download from github releases, free port alloc, host header aware link, no _trigger_dashboard_restart, deprecated restart endpoint kept no-op
- dashboard/dist/index.js: ttyd UI with iframe embed, copy link, installing state, error handling, no restart notice
- plugin.yaml/manifest.json: bump 1.1.0, description ttyd, provides_tools ttyd_start
2026-08-28 12:47:44 +00:00
} else if ( res . status === "stopped" ) {
if ( status === "running" ) {
setLink ( null ) ;
setStatus ( "idle" ) ;
}
2026-08-17 15:15:05 +00:00
}
} catch ( _ ) { }
feat: replace sshx with ttyd - auto arch detection, no curl|sh, no dashboard restart
- __init__.py: replace curl|sh sshx install with urllib ttyd download, arch map x86_64/aarch64/arm/armhf/i686/mips*, cache to ~/.local/bin, no systemd restart, lazy warmup
- dashboard/plugin_api.py: full ttyd backend, auto-detect arch via platform.machine(), download from github releases, free port alloc, host header aware link, no _trigger_dashboard_restart, deprecated restart endpoint kept no-op
- dashboard/dist/index.js: ttyd UI with iframe embed, copy link, installing state, error handling, no restart notice
- plugin.yaml/manifest.json: bump 1.1.0, description ttyd, provides_tools ttyd_start
2026-08-28 12:47:44 +00:00
} , [ status ] ) ;
2026-08-17 15:15:05 +00:00
2026-08-17 15:19:06 +00:00
useEffect ( function ( ) {
checkStatus ( ) ;
} , [ checkStatus ] ) ;
2026-08-17 15:15:05 +00:00
2026-08-19 00:00:34 +00:00
useEffect ( function ( ) {
if ( status !== "installing" ) return ;
var timer = setInterval ( function ( ) {
checkStatus ( ) ;
} , 2000 ) ;
return function ( ) { clearInterval ( timer ) ; } ;
} , [ status , checkStatus ] ) ;
if ( status === "installing" ) {
return React . createElement ( Card , null ,
React . createElement ( CardHeader , null ,
2026-09-03 04:21:03 +00:00
React . createElement ( CardTitle , null , "sshx.io Shared Terminal" )
2026-08-19 00:00:34 +00:00
) ,
React . createElement ( CardContent , null ,
React . createElement ( "p" , {
className : "text-sm text-yellow-500" ,
style : { fontWeight : 600 }
2026-09-03 04:21:03 +00:00
} , "Đang cài / khởi động sshx (auto arch detect)..." ) ,
React . createElement ( "p" , { className : "text-xs text-muted-foreground" , style : { marginTop : "0.5rem" } } , "Đang tải binary từ s3.amazonaws.com/sshx, không cần restart dashboard. Tự động thử lại sau 2s." ) ,
error && React . createElement ( "p" , { className : "text-xs text-yellow-700" , style : { marginTop : "0.5rem" } } , error )
2026-08-19 00:00:34 +00:00
)
) ;
}
2026-08-17 15:19:06 +00:00
if ( status === "running" && link ) {
return React . createElement ( Card , null ,
React . createElement ( CardHeader , null ,
2026-09-03 04:21:03 +00:00
React . createElement ( CardTitle , null , "sshx.io Shared Terminal" ) ,
React . createElement ( "p" , { className : "text-xs text-green-500" , style : { fontWeight : 600 } } , "● Running — shell đã tạo ở sshx.io" )
2026-08-17 15:19:06 +00:00
) ,
React . createElement ( CardContent , null ,
React . createElement ( "a" , {
href : link ,
target : "_blank" ,
rel : "noopener noreferrer" ,
style : {
color : "#60a5fa" ,
2026-09-03 04:21:03 +00:00
fontSize : "1.05rem" ,
2026-08-17 15:19:06 +00:00
wordBreak : "break-all" ,
feat: replace sshx with ttyd - auto arch detection, no curl|sh, no dashboard restart
- __init__.py: replace curl|sh sshx install with urllib ttyd download, arch map x86_64/aarch64/arm/armhf/i686/mips*, cache to ~/.local/bin, no systemd restart, lazy warmup
- dashboard/plugin_api.py: full ttyd backend, auto-detect arch via platform.machine(), download from github releases, free port alloc, host header aware link, no _trigger_dashboard_restart, deprecated restart endpoint kept no-op
- dashboard/dist/index.js: ttyd UI with iframe embed, copy link, installing state, error handling, no restart notice
- plugin.yaml/manifest.json: bump 1.1.0, description ttyd, provides_tools ttyd_start
2026-08-28 12:47:44 +00:00
textDecoration : "underline" ,
display : "block" ,
2026-09-03 04:21:03 +00:00
marginBottom : "0.75rem" ,
fontWeight : 600
2026-08-17 15:19:06 +00:00
}
} , link ) ,
2026-09-03 04:21:03 +00:00
React . createElement ( "div" , { style : { display : "flex" , gap : "0.5rem" , marginBottom : "1rem" , flexWrap : "wrap" } } ,
feat: replace sshx with ttyd - auto arch detection, no curl|sh, no dashboard restart
- __init__.py: replace curl|sh sshx install with urllib ttyd download, arch map x86_64/aarch64/arm/armhf/i686/mips*, cache to ~/.local/bin, no systemd restart, lazy warmup
- dashboard/plugin_api.py: full ttyd backend, auto-detect arch via platform.machine(), download from github releases, free port alloc, host header aware link, no _trigger_dashboard_restart, deprecated restart endpoint kept no-op
- dashboard/dist/index.js: ttyd UI with iframe embed, copy link, installing state, error handling, no restart notice
- plugin.yaml/manifest.json: bump 1.1.0, description ttyd, provides_tools ttyd_start
2026-08-28 12:47:44 +00:00
React . createElement ( Button , {
onClick : function ( ) { navigator . clipboard && navigator . clipboard . writeText ( link ) ; } ,
variant : "outline" ,
size : "sm"
} , "Copy Link" ) ,
2026-09-03 04:21:03 +00:00
React . createElement ( Button , {
onClick : function ( ) { window . open ( link , "_blank" ) ; } ,
variant : "outline" ,
size : "sm"
} , "Open" ) ,
2026-08-17 15:19:06 +00:00
React . createElement ( Button , {
feat: replace sshx with ttyd - auto arch detection, no curl|sh, no dashboard restart
- __init__.py: replace curl|sh sshx install with urllib ttyd download, arch map x86_64/aarch64/arm/armhf/i686/mips*, cache to ~/.local/bin, no systemd restart, lazy warmup
- dashboard/plugin_api.py: full ttyd backend, auto-detect arch via platform.machine(), download from github releases, free port alloc, host header aware link, no _trigger_dashboard_restart, deprecated restart endpoint kept no-op
- dashboard/dist/index.js: ttyd UI with iframe embed, copy link, installing state, error handling, no restart notice
- plugin.yaml/manifest.json: bump 1.1.0, description ttyd, provides_tools ttyd_start
2026-08-28 12:47:44 +00:00
onClick : stop ,
variant : "destructive" ,
size : "sm"
2026-08-17 15:19:06 +00:00
} , "Stop" )
feat: replace sshx with ttyd - auto arch detection, no curl|sh, no dashboard restart
- __init__.py: replace curl|sh sshx install with urllib ttyd download, arch map x86_64/aarch64/arm/armhf/i686/mips*, cache to ~/.local/bin, no systemd restart, lazy warmup
- dashboard/plugin_api.py: full ttyd backend, auto-detect arch via platform.machine(), download from github releases, free port alloc, host header aware link, no _trigger_dashboard_restart, deprecated restart endpoint kept no-op
- dashboard/dist/index.js: ttyd UI with iframe embed, copy link, installing state, error handling, no restart notice
- plugin.yaml/manifest.json: bump 1.1.0, description ttyd, provides_tools ttyd_start
2026-08-28 12:47:44 +00:00
) ,
React . createElement ( "div" , {
style : {
border : "1px solid #333" ,
borderRadius : "8px" ,
overflow : "hidden" ,
2026-09-03 04:21:03 +00:00
height : "560px" ,
feat: replace sshx with ttyd - auto arch detection, no curl|sh, no dashboard restart
- __init__.py: replace curl|sh sshx install with urllib ttyd download, arch map x86_64/aarch64/arm/armhf/i686/mips*, cache to ~/.local/bin, no systemd restart, lazy warmup
- dashboard/plugin_api.py: full ttyd backend, auto-detect arch via platform.machine(), download from github releases, free port alloc, host header aware link, no _trigger_dashboard_restart, deprecated restart endpoint kept no-op
- dashboard/dist/index.js: ttyd UI with iframe embed, copy link, installing state, error handling, no restart notice
- plugin.yaml/manifest.json: bump 1.1.0, description ttyd, provides_tools ttyd_start
2026-08-28 12:47:44 +00:00
background : "#000"
}
} ,
React . createElement ( "iframe" , {
src : link ,
style : { width : "100%" , height : "100%" , border : "0" } ,
2026-09-03 04:21:03 +00:00
title : "sshx Terminal" ,
allow : "clipboard-read; clipboard-write"
feat: replace sshx with ttyd - auto arch detection, no curl|sh, no dashboard restart
- __init__.py: replace curl|sh sshx install with urllib ttyd download, arch map x86_64/aarch64/arm/armhf/i686/mips*, cache to ~/.local/bin, no systemd restart, lazy warmup
- dashboard/plugin_api.py: full ttyd backend, auto-detect arch via platform.machine(), download from github releases, free port alloc, host header aware link, no _trigger_dashboard_restart, deprecated restart endpoint kept no-op
- dashboard/dist/index.js: ttyd UI with iframe embed, copy link, installing state, error handling, no restart notice
- plugin.yaml/manifest.json: bump 1.1.0, description ttyd, provides_tools ttyd_start
2026-08-28 12:47:44 +00:00
} )
) ,
React . createElement ( "p" , { className : "text-xs text-muted-foreground" , style : { marginTop : "0.5rem" } } ,
2026-09-03 04:21:03 +00:00
"Terminal nhúng ở trên (infinite canvas, cộng tác realtime). Nếu iframe bị chặn, bấm Open để mở tab mới. Link có dạng https://sshx.io/s/<id>#<key> — chia sẻ cho user là xong."
2026-08-17 15:19:06 +00:00
)
)
) ;
}
2026-08-17 15:15:05 +00:00
2026-08-17 15:19:06 +00:00
return React . createElement ( Card , null ,
React . createElement ( CardHeader , null ,
2026-09-03 04:21:03 +00:00
React . createElement ( CardTitle , null , "sshx.io Shared Terminal" ) ,
React . createElement ( "p" , { className : "text-xs text-muted-foreground" } , "Tạo shell ở sshx.io và trả link chia sẻ — auto arch, không cần restart" )
2026-08-17 15:19:06 +00:00
) ,
React . createElement ( CardContent , null ,
React . createElement ( "p" , {
className : "text-sm text-muted-foreground" ,
style : { marginBottom : "1rem" }
2026-09-03 04:21:03 +00:00
} , "Bấm Start để tạo shell cộng tác trên sshx.io. Plugin sẽ tự tải binary sshx (S3), chạy sshx và parse link https://sshx.io/s/... trả về cho user." ) ,
2026-08-17 15:19:06 +00:00
error && React . createElement ( "p" , {
className : "text-sm text-red-500" ,
feat: replace sshx with ttyd - auto arch detection, no curl|sh, no dashboard restart
- __init__.py: replace curl|sh sshx install with urllib ttyd download, arch map x86_64/aarch64/arm/armhf/i686/mips*, cache to ~/.local/bin, no systemd restart, lazy warmup
- dashboard/plugin_api.py: full ttyd backend, auto-detect arch via platform.machine(), download from github releases, free port alloc, host header aware link, no _trigger_dashboard_restart, deprecated restart endpoint kept no-op
- dashboard/dist/index.js: ttyd UI with iframe embed, copy link, installing state, error handling, no restart notice
- plugin.yaml/manifest.json: bump 1.1.0, description ttyd, provides_tools ttyd_start
2026-08-28 12:47:44 +00:00
style : { marginBottom : "1rem" , whiteSpace : "pre-wrap" }
2026-08-17 15:19:06 +00:00
} , "Error: " + error ) ,
React . createElement ( Button , {
feat: replace sshx with ttyd - auto arch detection, no curl|sh, no dashboard restart
- __init__.py: replace curl|sh sshx install with urllib ttyd download, arch map x86_64/aarch64/arm/armhf/i686/mips*, cache to ~/.local/bin, no systemd restart, lazy warmup
- dashboard/plugin_api.py: full ttyd backend, auto-detect arch via platform.machine(), download from github releases, free port alloc, host header aware link, no _trigger_dashboard_restart, deprecated restart endpoint kept no-op
- dashboard/dist/index.js: ttyd UI with iframe embed, copy link, installing state, error handling, no restart notice
- plugin.yaml/manifest.json: bump 1.1.0, description ttyd, provides_tools ttyd_start
2026-08-28 12:47:44 +00:00
onClick : start ,
2026-08-17 15:19:06 +00:00
disabled : status === "loading"
2026-09-03 04:21:03 +00:00
} , status === "loading" ? "Đang tạo shell ở sshx.io..." : "Start sshx → Lấy link" ) ,
React . createElement ( "p" , { className : "text-xs text-muted-foreground" , style : { marginTop : "0.75rem" } } , "Tương đương lệnh: curl -sSf https://sshx.io/get | sh -s run — nhưng tự động hoàn toàn trong dashboard." )
2026-08-17 15:19:06 +00:00
)
2026-08-17 15:15:05 +00:00
) ;
}
2026-09-03 04:21:03 +00:00
window . _ _HERMES _PLUGINS _ _ . register ( "sshx-link" , SSHXPage ) ;
2026-08-17 15:15:05 +00:00
} ) ( ) ;