Compare commits
10 commits
dbdafcfbd1
...
8f3615c5cf
| Author | SHA1 | Date | |
|---|---|---|---|
| 8f3615c5cf | |||
| b9783cc5c8 | |||
| 9c429ce20e | |||
| bd1835f5a3 | |||
| e9bbbb8171 | |||
| 840cecfce5 | |||
| 6224c9a1e0 | |||
| e15834c179 | |||
| bd9b92c861 | |||
| a3100a872b |
6 changed files with 75 additions and 37 deletions
25
.github/workflows/ci.yml
vendored
25
.github/workflows/ci.yml
vendored
|
|
@ -120,17 +120,14 @@ jobs:
|
|||
echo "$VPS_SSH_KEY" > ~/.ssh/deploy_key
|
||||
chmod 600 ~/.ssh/deploy_key
|
||||
ssh-keyscan -H 46.225.185.232 >> ~/.ssh/known_hosts
|
||||
scp -i ~/.ssh/deploy_key \
|
||||
target/x86_64-unknown-linux-gnu/release/helios-remote-relay \
|
||||
root@46.225.185.232:/opt/helios-remote/target/release/helios-remote-relay-new
|
||||
# Also publish relay binary to download URL for self-update
|
||||
# Only publish to download URL — relay updates itself when triggered by CLI
|
||||
scp -i ~/.ssh/deploy_key \
|
||||
target/x86_64-unknown-linux-gnu/release/helios-remote-relay \
|
||||
root@46.225.185.232:/var/www/helios-remote/helios-remote-relay-linux
|
||||
ssh -i ~/.ssh/deploy_key root@46.225.185.232 \
|
||||
"mv /opt/helios-remote/target/release/helios-remote-relay-new \
|
||||
/opt/helios-remote/target/release/helios-remote-relay && \
|
||||
systemctl restart helios-remote"
|
||||
# Write version.json so CLI knows what's available
|
||||
echo "{\"commit\":\"$(git rev-parse --short HEAD)\"}" > version.json
|
||||
scp -i ~/.ssh/deploy_key version.json \
|
||||
root@46.225.185.232:/var/www/helios-remote/version.json
|
||||
|
||||
build-cli:
|
||||
runs-on: ubuntu-latest
|
||||
|
|
@ -142,10 +139,10 @@ jobs:
|
|||
- name: Install Rust (stable) + targets
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
targets: x86_64-unknown-linux-gnu,x86_64-pc-windows-gnu
|
||||
targets: x86_64-unknown-linux-gnu,x86_64-pc-windows-gnu,aarch64-unknown-linux-gnu
|
||||
|
||||
- name: Install cross-compilers
|
||||
run: sudo apt-get update && sudo apt-get install -y gcc-x86-64-linux-gnu gcc-mingw-w64-x86-64 mingw-w64-tools
|
||||
run: sudo apt-get update && sudo apt-get install -y gcc-x86-64-linux-gnu gcc-mingw-w64-x86-64 mingw-w64-tools gcc-aarch64-linux-gnu
|
||||
|
||||
- name: Cache dependencies
|
||||
uses: Swatinem/rust-cache@v2
|
||||
|
|
@ -157,6 +154,11 @@ jobs:
|
|||
env:
|
||||
CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER: x86_64-linux-gnu-gcc
|
||||
|
||||
- name: Build CLI (Linux aarch64)
|
||||
run: cargo build --release --package helios-remote-cli --target aarch64-unknown-linux-gnu
|
||||
env:
|
||||
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
|
||||
|
||||
- name: Build CLI (Windows x86_64)
|
||||
run: cargo build --release --package helios-remote-cli --target x86_64-pc-windows-gnu
|
||||
env:
|
||||
|
|
@ -188,6 +190,9 @@ jobs:
|
|||
scp -i ~/.ssh/deploy_key \
|
||||
target/x86_64-unknown-linux-gnu/release/helios-remote-cli \
|
||||
root@46.225.185.232:/var/www/helios-remote/helios-remote-cli-linux
|
||||
scp -i ~/.ssh/deploy_key \
|
||||
target/aarch64-unknown-linux-gnu/release/helios-remote-cli \
|
||||
root@46.225.185.232:/var/www/helios-remote/helios-remote-cli-linux-aarch64
|
||||
scp -i ~/.ssh/deploy_key \
|
||||
target/x86_64-pc-windows-gnu/release/helios-remote-cli.exe \
|
||||
root@46.225.185.232:/var/www/helios-remote/helios-remote-cli-windows.exe
|
||||
|
|
|
|||
18
README.md
18
README.md
|
|
@ -31,8 +31,8 @@ irm https://raw.githubusercontent.com/agent-helios/helios-remote/master/scripts/
|
|||
```
|
||||
AI Agent
|
||||
│
|
||||
▼ remote CLI
|
||||
helios-server ──WebSocket── helios-client (Windows)
|
||||
▼ helios-remote-cli
|
||||
helios-remote-relay ──WebSocket── helios-remote-client (Windows)
|
||||
```
|
||||
|
||||
1. The **Windows client** connects to the relay server via WebSocket and registers with its device label.
|
||||
|
|
@ -62,11 +62,22 @@ remote clipboard-get <device> # get clipboard text
|
|||
remote clipboard-set <device> <text> # set clipboard text
|
||||
remote upload <device> <local> <remote> # upload file to device
|
||||
remote download <device> <remote> <local> # download file from device
|
||||
remote version <device> # compare relay/helios/client commits
|
||||
remote version <device> # compare latest/relay/cli/client commits
|
||||
remote update <device> # update all components to latest version
|
||||
remote logs <device> # fetch last 20 lines of client log (default)
|
||||
remote logs <device> --lines 200 # custom line count
|
||||
```
|
||||
|
||||
### Update System
|
||||
|
||||
`remote update <device>` checks `version.json` on the download server for the latest available commit and updates any component that's behind:
|
||||
|
||||
- **Relay** — downloads new binary, replaces itself, restarts via systemd
|
||||
- **Client** — downloads new binary, replaces itself, relaunches automatically
|
||||
- **CLI** — downloads new binary, replaces itself, re-executes the update command
|
||||
|
||||
CI publishes new binaries after every push to `master` but does **not** auto-restart the relay. Updates only happen when explicitly triggered via `remote update`.
|
||||
|
||||
---
|
||||
|
||||
## Server Setup
|
||||
|
|
@ -102,3 +113,4 @@ The relay server (`helios-remote-relay`) runs on the VPS and is not distributed.
|
|||
MIT
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
14
SKILL.md
14
SKILL.md
|
|
@ -73,12 +73,16 @@ $SKILL_DIR/helios clipboard-set moritz-pc "Text for clipboard"
|
|||
$SKILL_DIR/helios upload moritz-pc /tmp/local.txt "C:\Users\Moritz\Desktop\remote.txt"
|
||||
$SKILL_DIR/helios download moritz-pc "C:\Users\Moritz\file.txt" /tmp/downloaded.txt
|
||||
|
||||
# Version: compare relay + remote + client commits (are they in sync?)
|
||||
$SKILL_DIR/helios version moritz-pc
|
||||
# Version: compare latest available vs running commits (relay / cli / client)
|
||||
$SKILL_DIR/remote version moritz-pc
|
||||
|
||||
# Client log (last 100 lines, --lines for more)
|
||||
$SKILL_DIR/helios logs moritz-pc
|
||||
$SKILL_DIR/helios logs moritz-pc --lines 200
|
||||
# Update: bring all components (relay, cli, client) to latest version
|
||||
# CI publishes new binaries but does NOT auto-restart — this triggers the actual update
|
||||
$SKILL_DIR/remote update moritz-pc
|
||||
|
||||
# Client log (last 20 lines by default, --lines for more)
|
||||
$SKILL_DIR/remote logs moritz-pc
|
||||
$SKILL_DIR/remote logs moritz-pc --lines 200
|
||||
```
|
||||
|
||||
## Typical Workflow: UI Task
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ path = "src/main.rs"
|
|||
|
||||
[dependencies]
|
||||
clap = { version = "4", features = ["derive"] }
|
||||
reqwest = { version = "0.12", features = ["blocking", "json"] }
|
||||
reqwest = { version = "0.12", features = ["blocking", "json", "rustls-tls"], default-features = false }
|
||||
base64 = "0.22"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
|
|
|
|||
|
|
@ -722,7 +722,17 @@ fn main() {
|
|||
Commands::Update { device } => {
|
||||
validate_label(&device);
|
||||
|
||||
// Fetch all three commits
|
||||
// Fetch latest available commit from version.json
|
||||
let latest_commit = match reqwest::blocking::get("https://agent-helios.me/downloads/helios-remote/version.json") {
|
||||
Ok(r) => r
|
||||
.json::<Value>()
|
||||
.ok()
|
||||
.and_then(|v| v["commit"].as_str().map(String::from))
|
||||
.unwrap_or_else(|| "?".into()),
|
||||
Err(e) => format!("error: {}", e),
|
||||
};
|
||||
|
||||
// Fetch all three running commits
|
||||
let relay_commit = match reqwest::blocking::get(&format!("{}/version", cfg.base_url)) {
|
||||
Ok(r) => r
|
||||
.json::<Value>()
|
||||
|
|
@ -739,13 +749,14 @@ fn main() {
|
|||
|
||||
let cli_commit = GIT_COMMIT;
|
||||
|
||||
println!(" latest {}", latest_commit);
|
||||
println!(" relay {}", relay_commit);
|
||||
println!(" cli {}", cli_commit);
|
||||
println!(" client {}", client_commit);
|
||||
|
||||
let all_same = relay_commit == cli_commit && cli_commit == client_commit;
|
||||
if all_same {
|
||||
println!(" ✅ Already up to date (commit: {})", cli_commit);
|
||||
let all_current = relay_commit == latest_commit && cli_commit == latest_commit && client_commit == latest_commit;
|
||||
if all_current {
|
||||
println!(" ✅ Already up to date (commit: {})", latest_commit);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -753,7 +764,7 @@ fn main() {
|
|||
let mut updated_any = false;
|
||||
|
||||
// Update relay if needed
|
||||
if relay_commit != cli_commit {
|
||||
if relay_commit != latest_commit {
|
||||
println!(" → Updating relay...");
|
||||
let data = req(&cfg, "POST", "/relay/update", None, 15);
|
||||
println!(" {}", data["message"].as_str().unwrap_or("triggered"));
|
||||
|
|
@ -761,7 +772,7 @@ fn main() {
|
|||
}
|
||||
|
||||
// Update client if needed
|
||||
if client_commit != cli_commit {
|
||||
if client_commit != latest_commit {
|
||||
println!(" → Updating client on {}...", device);
|
||||
let data = req(
|
||||
&cfg,
|
||||
|
|
@ -780,18 +791,13 @@ fn main() {
|
|||
}
|
||||
|
||||
// Self-update CLI if needed
|
||||
// (relay_commit is the "canonical" latest — if we differ from it, we're outdated)
|
||||
// Skip on non-x86_64 Linux (e.g. ARM/Pi) — CI only builds x86_64 Linux binaries
|
||||
#[cfg(all(not(target_os = "windows"), not(target_arch = "x86_64")))]
|
||||
if cli_commit != relay_commit {
|
||||
println!(" → Skipping CLI update (non-x86_64, update manually)");
|
||||
}
|
||||
#[cfg(any(target_os = "windows", target_arch = "x86_64"))]
|
||||
if cli_commit != relay_commit {
|
||||
if cli_commit != latest_commit {
|
||||
println!(" → Updating CLI...");
|
||||
#[cfg(target_os = "windows")]
|
||||
let url = "https://agent-helios.me/downloads/helios-remote/helios-remote-cli-windows.exe";
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
#[cfg(all(not(target_os = "windows"), target_arch = "aarch64"))]
|
||||
let url = "https://agent-helios.me/downloads/helios-remote/helios-remote-cli-linux-aarch64";
|
||||
#[cfg(all(not(target_os = "windows"), not(target_arch = "aarch64")))]
|
||||
let url = "https://agent-helios.me/downloads/helios-remote/helios-remote-cli-linux";
|
||||
|
||||
let bytes = match reqwest::blocking::get(url) {
|
||||
|
|
|
|||
|
|
@ -221,6 +221,13 @@ async fn main() {
|
|||
|
||||
banner();
|
||||
|
||||
// Clean up leftover .old.exe from previous self-update (Windows can't delete running exe)
|
||||
#[cfg(target_os = "windows")]
|
||||
if let Ok(exe) = std::env::current_exe() {
|
||||
let old = exe.with_extension("old.exe");
|
||||
let _ = std::fs::remove_file(&old);
|
||||
}
|
||||
|
||||
// Single instance check
|
||||
if !acquire_instance_lock() {
|
||||
display::err("❌", "Another instance of helios-remote is already running.");
|
||||
|
|
@ -712,13 +719,17 @@ async fn handle_message(
|
|||
display::cmd_done("🔄", "update", "", true, "updated — restarting");
|
||||
// Delete old binary
|
||||
let _ = std::fs::remove_file(&old);
|
||||
// Release single-instance lock so new process can start
|
||||
release_instance_lock();
|
||||
// Restart with same args (new console window on Windows)
|
||||
let args: Vec<String> = std::env::args().skip(1).collect();
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
use std::os::windows::process::CommandExt;
|
||||
const CREATE_NEW_CONSOLE: u32 = 0x00000010;
|
||||
let _ = std::process::Command::new(&exe).args(&args).creation_flags(CREATE_NEW_CONSOLE).spawn();
|
||||
// Use "start" to open a new visible console window
|
||||
let exe_str = exe.to_string_lossy();
|
||||
let _ = std::process::Command::new("cmd")
|
||||
.args(["/c", "start", "", &exe_str])
|
||||
.spawn();
|
||||
}
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
let _ = std::process::Command::new(&exe).args(&args).spawn();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue