akashcli 4.7.6__tar.gz → 4.7.8__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.
- {akashcli-4.7.6 → akashcli-4.7.8}/PKG-INFO +1 -1
- {akashcli-4.7.6 → akashcli-4.7.8}/akashcli/cli.py +62 -13
- {akashcli-4.7.6 → akashcli-4.7.8}/akashcli.egg-info/PKG-INFO +1 -1
- {akashcli-4.7.6 → akashcli-4.7.8}/pyproject.toml +1 -1
- {akashcli-4.7.6 → akashcli-4.7.8}/README.md +0 -0
- {akashcli-4.7.6 → akashcli-4.7.8}/akashcli/__init__.py +0 -0
- {akashcli-4.7.6 → akashcli-4.7.8}/akashcli/_net.py +0 -0
- {akashcli-4.7.6 → akashcli-4.7.8}/akashcli/auth.py +0 -0
- {akashcli-4.7.6 → akashcli-4.7.8}/akashcli/client.py +0 -0
- {akashcli-4.7.6 → akashcli-4.7.8}/akashcli/config.py +0 -0
- {akashcli-4.7.6 → akashcli-4.7.8}/akashcli/crypto.py +0 -0
- {akashcli-4.7.6 → akashcli-4.7.8}/akashcli/env_manager.py +0 -0
- {akashcli-4.7.6 → akashcli-4.7.8}/akashcli/exceptions.py +0 -0
- {akashcli-4.7.6 → akashcli-4.7.8}/akashcli/exec.py +0 -0
- {akashcli-4.7.6 → akashcli-4.7.8}/akashcli/integrity.py +0 -0
- {akashcli-4.7.6 → akashcli-4.7.8}/akashcli/logger.py +0 -0
- {akashcli-4.7.6 → akashcli-4.7.8}/akashcli/models.py +0 -0
- {akashcli-4.7.6 → akashcli-4.7.8}/akashcli/p2p.py +0 -0
- {akashcli-4.7.6 → akashcli-4.7.8}/akashcli/packages.py +0 -0
- {akashcli-4.7.6 → akashcli-4.7.8}/akashcli/relay.py +0 -0
- {akashcli-4.7.6 → akashcli-4.7.8}/akashcli/restore.py +0 -0
- {akashcli-4.7.6 → akashcli-4.7.8}/akashcli/snapshot_crypto.py +0 -0
- {akashcli-4.7.6 → akashcli-4.7.8}/akashcli/storage.py +0 -0
- {akashcli-4.7.6 → akashcli-4.7.8}/akashcli/terminal.py +0 -0
- {akashcli-4.7.6 → akashcli-4.7.8}/akashcli/updater.py +0 -0
- {akashcli-4.7.6 → akashcli-4.7.8}/akashcli/uploader.py +0 -0
- {akashcli-4.7.6 → akashcli-4.7.8}/akashcli/utils.py +0 -0
- {akashcli-4.7.6 → akashcli-4.7.8}/akashcli.egg-info/SOURCES.txt +0 -0
- {akashcli-4.7.6 → akashcli-4.7.8}/akashcli.egg-info/dependency_links.txt +0 -0
- {akashcli-4.7.6 → akashcli-4.7.8}/akashcli.egg-info/entry_points.txt +0 -0
- {akashcli-4.7.6 → akashcli-4.7.8}/akashcli.egg-info/requires.txt +0 -0
- {akashcli-4.7.6 → akashcli-4.7.8}/akashcli.egg-info/top_level.txt +0 -0
- {akashcli-4.7.6 → akashcli-4.7.8}/setup.cfg +0 -0
|
@@ -62,6 +62,9 @@ class _Spin:
|
|
|
62
62
|
|
|
63
63
|
def __enter__(self):
|
|
64
64
|
if self._disabled:
|
|
65
|
+
pfx = self._prefix + " " if self._prefix else " "
|
|
66
|
+
sys.stdout.write(f"{pfx}{_C}▶{_RS} {_DM}{self._label}…{_RS}\n")
|
|
67
|
+
sys.stdout.flush()
|
|
65
68
|
return self
|
|
66
69
|
import threading, time
|
|
67
70
|
self._active = True
|
|
@@ -76,7 +79,7 @@ class _Spin:
|
|
|
76
79
|
f = self._FRAMES[self._i % len(self._FRAMES)]
|
|
77
80
|
now = time.monotonic()
|
|
78
81
|
dur = now - self._t0
|
|
79
|
-
dur_str = f" {_dim(f'({dur:.1f}s)')}" if dur >=
|
|
82
|
+
dur_str = f" {_dim(f'({dur:.1f}s)')}" if dur >= 0.8 else ""
|
|
80
83
|
sys.stdout.write(f"\r\033[2K{pfx}{_C}{f}{_RS} {_DM}{self._label}{_RS}{dur_str} ")
|
|
81
84
|
sys.stdout.flush()
|
|
82
85
|
self._i += 1
|
|
@@ -93,12 +96,12 @@ class _Spin:
|
|
|
93
96
|
if self._disabled:
|
|
94
97
|
return
|
|
95
98
|
import time
|
|
99
|
+
self._active = False
|
|
100
|
+
if self._thread:
|
|
101
|
+
self._thread.join(timeout=0.3)
|
|
96
102
|
elapsed = time.monotonic() - self._t0
|
|
97
103
|
if elapsed < self._min_seconds:
|
|
98
104
|
time.sleep(self._min_seconds - elapsed)
|
|
99
|
-
self._active = False
|
|
100
|
-
if self._thread:
|
|
101
|
-
self._thread.join(timeout=0.2)
|
|
102
105
|
sys.stdout.write("\r\033[2K")
|
|
103
106
|
sys.stdout.flush()
|
|
104
107
|
|
|
@@ -3251,6 +3254,18 @@ def _sanitize_agent_command(cmd: str, scopes: str = "*") -> tuple[bool, str]:
|
|
|
3251
3254
|
if not cmd or not cmd.strip(): return False, "Empty command."
|
|
3252
3255
|
clean_cmd = cmd.strip()
|
|
3253
3256
|
|
|
3257
|
+
# Guard against interactive commands that hang waiting for human input in automated agents
|
|
3258
|
+
interactive_patterns = (
|
|
3259
|
+
r"^\s*(nano|vi|vim|htop|top|less|more|man)\b",
|
|
3260
|
+
r"\bgit\s+commit\s*$",
|
|
3261
|
+
r"^\s*python[0-9.]*\s*$",
|
|
3262
|
+
r"^\s*node\s*$",
|
|
3263
|
+
r"^\s*cat\s*$"
|
|
3264
|
+
)
|
|
3265
|
+
for pat in interactive_patterns:
|
|
3266
|
+
if re.search(pat, clean_cmd):
|
|
3267
|
+
return False, "Interactive command requiring terminal input is not supported in automated execution."
|
|
3268
|
+
|
|
3254
3269
|
# Unconditional critical security guard (Always enforced regardless of scopes)
|
|
3255
3270
|
for pat, reason in CRITICAL_DENY_PATTERNS:
|
|
3256
3271
|
if re.search(pat, clean_cmd):
|
|
@@ -3442,17 +3457,51 @@ def mcp_serve(
|
|
|
3442
3457
|
if any(k in cmd for k in ["touch", "mkdir", "mv", "cp", "sed", ">", ">>", "python", "npm", "pip"]):
|
|
3443
3458
|
_save_undo_checkpoint()
|
|
3444
3459
|
|
|
3445
|
-
#
|
|
3460
|
+
# Auto-add non-interactive flags if missing
|
|
3461
|
+
exec_cmd = cmd
|
|
3462
|
+
if re.search(r"\bping\s+", exec_cmd) and "-c" not in exec_cmd:
|
|
3463
|
+
exec_cmd += " -c 4"
|
|
3464
|
+
if re.search(r"\bapt(-get)?\s+(install|upgrade|remove)\b", exec_cmd) and "-y" not in exec_cmd:
|
|
3465
|
+
exec_cmd += " -y"
|
|
3466
|
+
if re.search(r"\bdu\b", exec_cmd) and "-x" not in exec_cmd:
|
|
3467
|
+
exec_cmd = re.sub(r"\bdu\b", "du -x", exec_cmd)
|
|
3468
|
+
|
|
3469
|
+
# Process-group-isolated runner: immune to pipe deadlocks & orphaned subshells
|
|
3470
|
+
import os, signal
|
|
3446
3471
|
try:
|
|
3447
3472
|
with _Spin(f"exec: {disp_cmd}", min_seconds=0.25, prefix=ts_pfx):
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3473
|
+
proc = subprocess.Popen(
|
|
3474
|
+
exec_cmd,
|
|
3475
|
+
shell=True,
|
|
3476
|
+
stdout=subprocess.PIPE,
|
|
3477
|
+
stderr=subprocess.PIPE,
|
|
3478
|
+
stdin=subprocess.DEVNULL,
|
|
3479
|
+
text=True,
|
|
3480
|
+
start_new_session=True,
|
|
3481
|
+
errors="replace"
|
|
3482
|
+
)
|
|
3483
|
+
try:
|
|
3484
|
+
out, err = proc.communicate(timeout=25)
|
|
3485
|
+
returncode = proc.returncode
|
|
3486
|
+
raw_out = (out or "") + (err or "")
|
|
3487
|
+
elapsed_ms = (time.monotonic() - t0) * 1000
|
|
3488
|
+
except subprocess.TimeoutExpired:
|
|
3489
|
+
try:
|
|
3490
|
+
os.killpg(os.getpgid(proc.pid), signal.SIGKILL)
|
|
3491
|
+
except Exception:
|
|
3492
|
+
pass
|
|
3493
|
+
try:
|
|
3494
|
+
out, err = proc.communicate(timeout=2)
|
|
3495
|
+
raw_out = (out or "") + (err or "")
|
|
3496
|
+
except Exception:
|
|
3497
|
+
raw_out = ""
|
|
3498
|
+
elapsed_ms = 25000.0
|
|
3499
|
+
raw_out = raw_out or "⛔ Command timed out after 25 seconds."
|
|
3500
|
+
returncode = 124
|
|
3501
|
+
except Exception as cmd_err:
|
|
3502
|
+
elapsed_ms = (time.monotonic() - t0) * 1000
|
|
3503
|
+
raw_out = f"⛔ Command execution error: {cmd_err}"
|
|
3504
|
+
returncode = 1
|
|
3456
3505
|
|
|
3457
3506
|
bounded_out = _smart_truncate_output(raw_out)
|
|
3458
3507
|
|
|
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
|