gcli-control 0.12.2__tar.gz → 0.12.4__tar.gz
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.
- {gcli_control-0.12.2 → gcli_control-0.12.4}/PKG-INFO +1 -1
- {gcli_control-0.12.2 → gcli_control-0.12.4}/gcli/__init__.py +1 -1
- {gcli_control-0.12.2 → gcli_control-0.12.4}/gcli/client.py +86 -2
- {gcli_control-0.12.2 → gcli_control-0.12.4}/gcli/host.py +3 -2
- {gcli_control-0.12.2 → gcli_control-0.12.4}/gcli/npoint.py +1 -1
- {gcli_control-0.12.2 → gcli_control-0.12.4}/gcli_control.egg-info/PKG-INFO +1 -1
- {gcli_control-0.12.2 → gcli_control-0.12.4}/pyproject.toml +1 -1
- {gcli_control-0.12.2 → gcli_control-0.12.4}/README.md +0 -0
- {gcli_control-0.12.2 → gcli_control-0.12.4}/gcli/__main__.py +0 -0
- {gcli_control-0.12.2 → gcli_control-0.12.4}/gcli/aliases.py +0 -0
- {gcli_control-0.12.2 → gcli_control-0.12.4}/gcli/audio.py +0 -0
- {gcli_control-0.12.2 → gcli_control-0.12.4}/gcli/automation.py +0 -0
- {gcli_control-0.12.2 → gcli_control-0.12.4}/gcli/bluetooth.py +0 -0
- {gcli_control-0.12.2 → gcli_control-0.12.4}/gcli/browser.py +0 -0
- {gcli_control-0.12.2 → gcli_control-0.12.4}/gcli/clipboard.py +0 -0
- {gcli_control-0.12.2 → gcli_control-0.12.4}/gcli/colors.py +0 -0
- {gcli_control-0.12.2 → gcli_control-0.12.4}/gcli/crypto.py +0 -0
- {gcli_control-0.12.2 → gcli_control-0.12.4}/gcli/desktop.py +0 -0
- {gcli_control-0.12.2 → gcli_control-0.12.4}/gcli/elevator.py +0 -0
- {gcli_control-0.12.2 → gcli_control-0.12.4}/gcli/encrypt.py +0 -0
- {gcli_control-0.12.2 → gcli_control-0.12.4}/gcli/fileops.py +0 -0
- {gcli_control-0.12.2 → gcli_control-0.12.4}/gcli/forensics.py +0 -0
- {gcli_control-0.12.2 → gcli_control-0.12.4}/gcli/hardware.py +0 -0
- {gcli_control-0.12.2 → gcli_control-0.12.4}/gcli/hosts_config.py +0 -0
- {gcli_control-0.12.2 → gcli_control-0.12.4}/gcli/keylog.py +0 -0
- {gcli_control-0.12.2 → gcli_control-0.12.4}/gcli/monitoring.py +0 -0
- {gcli_control-0.12.2 → gcli_control-0.12.4}/gcli/netutils.py +0 -0
- {gcli_control-0.12.2 → gcli_control-0.12.4}/gcli/network_config.py +0 -0
- {gcli_control-0.12.2 → gcli_control-0.12.4}/gcli/output.py +0 -0
- {gcli_control-0.12.2 → gcli_control-0.12.4}/gcli/persistence.py +0 -0
- {gcli_control-0.12.2 → gcli_control-0.12.4}/gcli/power.py +0 -0
- {gcli_control-0.12.2 → gcli_control-0.12.4}/gcli/processes.py +0 -0
- {gcli_control-0.12.2 → gcli_control-0.12.4}/gcli/protocol.py +0 -0
- {gcli_control-0.12.2 → gcli_control-0.12.4}/gcli/registry.py +0 -0
- {gcli_control-0.12.2 → gcli_control-0.12.4}/gcli/security.py +0 -0
- {gcli_control-0.12.2 → gcli_control-0.12.4}/gcli/session.py +0 -0
- {gcli_control-0.12.2 → gcli_control-0.12.4}/gcli/system.py +0 -0
- {gcli_control-0.12.2 → gcli_control-0.12.4}/gcli/transfer.py +0 -0
- {gcli_control-0.12.2 → gcli_control-0.12.4}/gcli/users.py +0 -0
- {gcli_control-0.12.2 → gcli_control-0.12.4}/gcli/utils.py +0 -0
- {gcli_control-0.12.2 → gcli_control-0.12.4}/gcli/webcam.py +0 -0
- {gcli_control-0.12.2 → gcli_control-0.12.4}/gcli/wifi.py +0 -0
- {gcli_control-0.12.2 → gcli_control-0.12.4}/gcli_control.egg-info/SOURCES.txt +0 -0
- {gcli_control-0.12.2 → gcli_control-0.12.4}/gcli_control.egg-info/dependency_links.txt +0 -0
- {gcli_control-0.12.2 → gcli_control-0.12.4}/gcli_control.egg-info/entry_points.txt +0 -0
- {gcli_control-0.12.2 → gcli_control-0.12.4}/gcli_control.egg-info/requires.txt +0 -0
- {gcli_control-0.12.2 → gcli_control-0.12.4}/gcli_control.egg-info/top_level.txt +0 -0
- {gcli_control-0.12.2 → gcli_control-0.12.4}/setup.cfg +0 -0
- {gcli_control-0.12.2 → gcli_control-0.12.4}/tests/test_integration.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gcli-control
|
|
3
|
-
Version: 0.12.
|
|
3
|
+
Version: 0.12.4
|
|
4
4
|
Summary: Remote access tool via npoint.io - encrypted relay with 200+ commands, auto-reconnection, dashboard, session stats, rate limiting, and full desktop/system control. v0.12.2 fixes SSH connection timeout.
|
|
5
5
|
Author: gcli contributors
|
|
6
6
|
License-Expression: MIT
|
|
@@ -177,6 +177,8 @@ BUILTIN_COMMANDS = [
|
|
|
177
177
|
# Quick commands
|
|
178
178
|
":q",
|
|
179
179
|
":exit",
|
|
180
|
+
# Update
|
|
181
|
+
":update",
|
|
180
182
|
]
|
|
181
183
|
|
|
182
184
|
|
|
@@ -276,7 +278,8 @@ class SSHSession:
|
|
|
276
278
|
# Always try to claim — don't skip on host_alive.
|
|
277
279
|
result = claim_results(doc, self.password, cmd_id, self.seen_results)
|
|
278
280
|
if result and result.get("pong"):
|
|
279
|
-
|
|
281
|
+
host_version = result.get("version", "unknown")
|
|
282
|
+
print(success(f"[gcli] Host responded! Connected. (host v{host_version})"))
|
|
280
283
|
self.connected = True
|
|
281
284
|
return True
|
|
282
285
|
# Re-send the ping if we haven't heard back after a while.
|
|
@@ -1017,6 +1020,9 @@ class SSHSession:
|
|
|
1017
1020
|
elif line == ":q":
|
|
1018
1021
|
self._send_disconnect()
|
|
1019
1022
|
self.connected = False
|
|
1023
|
+
# Update
|
|
1024
|
+
elif line == ":update":
|
|
1025
|
+
self._do_update()
|
|
1020
1026
|
# Session stats
|
|
1021
1027
|
elif line == ":stats":
|
|
1022
1028
|
self._do_stats()
|
|
@@ -1259,6 +1265,7 @@ class SSHSession:
|
|
|
1259
1265
|
print(f" {Style.GREEN}:dashboard{Style.RESET} Combined system overview")
|
|
1260
1266
|
print(f" {Style.GREEN}:jobs{Style.RESET} List running background jobs")
|
|
1261
1267
|
print(f" {Style.GREEN}:killjob <id>{Style.RESET} Kill a background job")
|
|
1268
|
+
print(f" {Style.GREEN}:update{Style.RESET} Update gcli on remote host")
|
|
1262
1269
|
print(f" {Style.GREEN}:q{Style.RESET} Quick disconnect")
|
|
1263
1270
|
print(f"\n {Style.GREEN}:exit{Style.RESET} Disconnect")
|
|
1264
1271
|
print(f"{Style.CYAN}{Style.BOLD}{'=' * 40}{Style.RESET}\n")
|
|
@@ -1348,10 +1355,87 @@ class SSHSession:
|
|
|
1348
1355
|
result = self._poll_result(cmd_id)
|
|
1349
1356
|
if result and result.get("pong"):
|
|
1350
1357
|
latency = (time.time() - t0) * 1000
|
|
1351
|
-
|
|
1358
|
+
host_version = result.get("version", "unknown")
|
|
1359
|
+
print(success(f"[gcli] Pong! Round-trip: {latency:.0f}ms (host v{host_version})"))
|
|
1352
1360
|
else:
|
|
1353
1361
|
print(error("[gcli] No pong received"))
|
|
1354
1362
|
|
|
1363
|
+
def _do_update(self) -> None:
|
|
1364
|
+
"""
|
|
1365
|
+
Update gcli-control on the remote host.
|
|
1366
|
+
1. Get current host version
|
|
1367
|
+
2. pip install latest from PyPI
|
|
1368
|
+
3. Disconnect host (watchdog restarts with new version)
|
|
1369
|
+
4. Wait and re-ping to verify
|
|
1370
|
+
"""
|
|
1371
|
+
from . import __version__ as local_version
|
|
1372
|
+
|
|
1373
|
+
# --- Step 1: Check current host version ---
|
|
1374
|
+
print(info("[gcli] Checking current host version..."))
|
|
1375
|
+
t0 = time.time()
|
|
1376
|
+
cmd_id = self._send("ping", {"type": "ping"})
|
|
1377
|
+
result = self._poll_result(cmd_id, timeout=10.0)
|
|
1378
|
+
if result and result.get("pong"):
|
|
1379
|
+
host_version = result.get("version", "unknown")
|
|
1380
|
+
print(info(f"[gcli] Host version: {host_version} (your client: v{local_version})"))
|
|
1381
|
+
else:
|
|
1382
|
+
print(warn("[gcli] Could not ping host. It may be offline."))
|
|
1383
|
+
return
|
|
1384
|
+
|
|
1385
|
+
if host_version == local_version:
|
|
1386
|
+
print(success(f"[gcli] Host is already up to date (v{local_version})"))
|
|
1387
|
+
return
|
|
1388
|
+
|
|
1389
|
+
# --- Step 2: pip install latest ---
|
|
1390
|
+
print(info("[gcli] Installing latest gcli-control on remote host..."))
|
|
1391
|
+
install_cmd = (
|
|
1392
|
+
"pip install --user --break-system-packages "
|
|
1393
|
+
"--upgrade gcli-control 2>&1 | tail -5"
|
|
1394
|
+
)
|
|
1395
|
+
cmd_id = self._send("exec", {"type": "exec", "cmd": install_cmd, "timeout": 120})
|
|
1396
|
+
result = self._poll_result(cmd_id, timeout=130.0)
|
|
1397
|
+
if result:
|
|
1398
|
+
stdout = result.get("stdout", "").strip()
|
|
1399
|
+
if result.get("rc") == 0 or "Successfully installed" in stdout:
|
|
1400
|
+
print(success(f"[gcli] pip install output:\n{stdout}"))
|
|
1401
|
+
else:
|
|
1402
|
+
print(warn(f"[gcli] pip install may have issues:\n{stdout}"))
|
|
1403
|
+
stderr = result.get("stderr", "").strip()
|
|
1404
|
+
if stderr:
|
|
1405
|
+
print(warn(f"[gcli] stderr: {stderr[:300]}"))
|
|
1406
|
+
# Continue anyway — the watchdog restart might pick it up
|
|
1407
|
+
else:
|
|
1408
|
+
print(warn("[gcli] pip install timed out. Trying to continue..."))
|
|
1409
|
+
|
|
1410
|
+
# --- Step 3: Disconnect host so watchdog restarts with new version ---
|
|
1411
|
+
print(info("[gcli] Disconnecting host (watchdog will restart with new version)..."))
|
|
1412
|
+
cmd_id = self._send("disconnect", {"type": "disconnect"})
|
|
1413
|
+
self._poll_result(cmd_id, timeout=5.0)
|
|
1414
|
+
|
|
1415
|
+
# --- Step 4: Wait for host to come back ---
|
|
1416
|
+
print(info("[gcli] Waiting for host to restart (up to 90s)..."))
|
|
1417
|
+
for attempt in range(18):
|
|
1418
|
+
time.sleep(5)
|
|
1419
|
+
try:
|
|
1420
|
+
cmd_id = self._send("ping", {"type": "ping"})
|
|
1421
|
+
result = self._poll_result(cmd_id, timeout=8.0)
|
|
1422
|
+
if result and result.get("pong"):
|
|
1423
|
+
new_version = result.get("version", "unknown")
|
|
1424
|
+
latency = 0 # already measured
|
|
1425
|
+
print(success(f"[gcli] Host is back! Version: {new_version}"))
|
|
1426
|
+
if new_version == local_version:
|
|
1427
|
+
print(success(f"[gcli] Update successful: {host_version} -> {new_version}"))
|
|
1428
|
+
else:
|
|
1429
|
+
print(warn(f"[gcli] Expected v{local_version}, got v{new_version}"))
|
|
1430
|
+
self.connected = True
|
|
1431
|
+
return
|
|
1432
|
+
except Exception:
|
|
1433
|
+
pass
|
|
1434
|
+
print(info(f"[gcli] Waiting... ({5 * (attempt + 1)}s)"))
|
|
1435
|
+
|
|
1436
|
+
print(error("[gcli] Host did not come back within 90s. Check watchdog manually."))
|
|
1437
|
+
self.connected = False
|
|
1438
|
+
|
|
1355
1439
|
def _do_host_status(self) -> None:
|
|
1356
1440
|
"""Show current host status including last_seen time."""
|
|
1357
1441
|
try:
|
|
@@ -504,8 +504,9 @@ class Daemon:
|
|
|
504
504
|
self._respond(cmd_id, {"ok": True, **info})
|
|
505
505
|
|
|
506
506
|
def _handle_ping(self, cmd_id: str) -> None:
|
|
507
|
-
"""Respond to a ping."""
|
|
508
|
-
|
|
507
|
+
"""Respond to a ping, including the host version."""
|
|
508
|
+
from . import __version__
|
|
509
|
+
self._respond(cmd_id, {"ok": True, "pong": True, "time": time.time(), "version": __version__})
|
|
509
510
|
|
|
510
511
|
def _handle_disconnect(self, cmd_id: str) -> None:
|
|
511
512
|
"""Gracefully shut down the daemon."""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gcli-control
|
|
3
|
-
Version: 0.12.
|
|
3
|
+
Version: 0.12.4
|
|
4
4
|
Summary: Remote access tool via npoint.io - encrypted relay with 200+ commands, auto-reconnection, dashboard, session stats, rate limiting, and full desktop/system control. v0.12.2 fixes SSH connection timeout.
|
|
5
5
|
Author: gcli contributors
|
|
6
6
|
License-Expression: MIT
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "gcli-control"
|
|
7
|
-
version = "0.12.
|
|
7
|
+
version = "0.12.4"
|
|
8
8
|
description = "Remote access tool via npoint.io - encrypted relay with 200+ commands, auto-reconnection, dashboard, session stats, rate limiting, and full desktop/system control. v0.12.2 fixes SSH connection timeout."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|