akashcli 4.7.4__tar.gz → 4.7.6__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.4 → akashcli-4.7.6}/PKG-INFO +1 -1
- {akashcli-4.7.4 → akashcli-4.7.6}/akashcli/cli.py +49 -23
- {akashcli-4.7.4 → akashcli-4.7.6}/akashcli.egg-info/PKG-INFO +1 -1
- {akashcli-4.7.4 → akashcli-4.7.6}/pyproject.toml +1 -1
- {akashcli-4.7.4 → akashcli-4.7.6}/README.md +0 -0
- {akashcli-4.7.4 → akashcli-4.7.6}/akashcli/__init__.py +0 -0
- {akashcli-4.7.4 → akashcli-4.7.6}/akashcli/_net.py +0 -0
- {akashcli-4.7.4 → akashcli-4.7.6}/akashcli/auth.py +0 -0
- {akashcli-4.7.4 → akashcli-4.7.6}/akashcli/client.py +0 -0
- {akashcli-4.7.4 → akashcli-4.7.6}/akashcli/config.py +0 -0
- {akashcli-4.7.4 → akashcli-4.7.6}/akashcli/crypto.py +0 -0
- {akashcli-4.7.4 → akashcli-4.7.6}/akashcli/env_manager.py +0 -0
- {akashcli-4.7.4 → akashcli-4.7.6}/akashcli/exceptions.py +0 -0
- {akashcli-4.7.4 → akashcli-4.7.6}/akashcli/exec.py +0 -0
- {akashcli-4.7.4 → akashcli-4.7.6}/akashcli/integrity.py +0 -0
- {akashcli-4.7.4 → akashcli-4.7.6}/akashcli/logger.py +0 -0
- {akashcli-4.7.4 → akashcli-4.7.6}/akashcli/models.py +0 -0
- {akashcli-4.7.4 → akashcli-4.7.6}/akashcli/p2p.py +0 -0
- {akashcli-4.7.4 → akashcli-4.7.6}/akashcli/packages.py +0 -0
- {akashcli-4.7.4 → akashcli-4.7.6}/akashcli/relay.py +0 -0
- {akashcli-4.7.4 → akashcli-4.7.6}/akashcli/restore.py +0 -0
- {akashcli-4.7.4 → akashcli-4.7.6}/akashcli/snapshot_crypto.py +0 -0
- {akashcli-4.7.4 → akashcli-4.7.6}/akashcli/storage.py +0 -0
- {akashcli-4.7.4 → akashcli-4.7.6}/akashcli/terminal.py +0 -0
- {akashcli-4.7.4 → akashcli-4.7.6}/akashcli/updater.py +0 -0
- {akashcli-4.7.4 → akashcli-4.7.6}/akashcli/uploader.py +0 -0
- {akashcli-4.7.4 → akashcli-4.7.6}/akashcli/utils.py +0 -0
- {akashcli-4.7.4 → akashcli-4.7.6}/akashcli.egg-info/SOURCES.txt +0 -0
- {akashcli-4.7.4 → akashcli-4.7.6}/akashcli.egg-info/dependency_links.txt +0 -0
- {akashcli-4.7.4 → akashcli-4.7.6}/akashcli.egg-info/entry_points.txt +0 -0
- {akashcli-4.7.4 → akashcli-4.7.6}/akashcli.egg-info/requires.txt +0 -0
- {akashcli-4.7.4 → akashcli-4.7.6}/akashcli.egg-info/top_level.txt +0 -0
- {akashcli-4.7.4 → akashcli-4.7.6}/setup.cfg +0 -0
|
@@ -47,11 +47,12 @@ def _gr(s: str) -> str: return f"{_GR}{s}{_RS}"
|
|
|
47
47
|
|
|
48
48
|
# ── Spinner (single-line, no flicker) ────────────────────────────────────────
|
|
49
49
|
class _Spin:
|
|
50
|
-
"""Minimal inline spinner with instant frame-0 rendering, smooth
|
|
50
|
+
"""Minimal inline spinner with instant frame-0 rendering, smooth visibility, and clean cleanup."""
|
|
51
51
|
_FRAMES = ("⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏")
|
|
52
52
|
|
|
53
|
-
def __init__(self, label: str, min_seconds: float = 0.35, disabled: bool = False):
|
|
53
|
+
def __init__(self, label: str, min_seconds: float = 0.35, disabled: bool = False, prefix: str = ""):
|
|
54
54
|
self._label = label
|
|
55
|
+
self._prefix = prefix
|
|
55
56
|
self._disabled = disabled or (not sys.stdout.isatty())
|
|
56
57
|
self._min_seconds = min_seconds
|
|
57
58
|
self._i = 0
|
|
@@ -65,18 +66,21 @@ class _Spin:
|
|
|
65
66
|
import threading, time
|
|
66
67
|
self._active = True
|
|
67
68
|
self._t0 = time.monotonic()
|
|
68
|
-
|
|
69
|
-
sys.stdout.write(
|
|
69
|
+
pfx = self._prefix + " " if self._prefix else " "
|
|
70
|
+
sys.stdout.write(f"\r{pfx}{_C}{self._FRAMES[0]}{_RS} {_DM}{self._label}{_RS} ")
|
|
70
71
|
sys.stdout.flush()
|
|
71
72
|
|
|
72
73
|
def _spin():
|
|
73
74
|
time.sleep(0.04)
|
|
74
75
|
while self._active:
|
|
75
76
|
f = self._FRAMES[self._i % len(self._FRAMES)]
|
|
76
|
-
|
|
77
|
+
now = time.monotonic()
|
|
78
|
+
dur = now - self._t0
|
|
79
|
+
dur_str = f" {_dim(f'({dur:.1f}s)')}" if dur >= 1.0 else ""
|
|
80
|
+
sys.stdout.write(f"\r\033[2K{pfx}{_C}{f}{_RS} {_DM}{self._label}{_RS}{dur_str} ")
|
|
77
81
|
sys.stdout.flush()
|
|
78
82
|
self._i += 1
|
|
79
|
-
time.sleep(0.
|
|
83
|
+
time.sleep(0.06)
|
|
80
84
|
|
|
81
85
|
self._thread = threading.Thread(target=_spin, daemon=True)
|
|
82
86
|
self._thread.start()
|
|
@@ -95,7 +99,7 @@ class _Spin:
|
|
|
95
99
|
self._active = False
|
|
96
100
|
if self._thread:
|
|
97
101
|
self._thread.join(timeout=0.2)
|
|
98
|
-
sys.stdout.write(
|
|
102
|
+
sys.stdout.write("\r\033[2K")
|
|
99
103
|
sys.stdout.flush()
|
|
100
104
|
|
|
101
105
|
def _resolve_client(url_override: str = None, require_key: bool = False, silent: bool = False):
|
|
@@ -2792,7 +2796,7 @@ def agent_list(raw: bool = typer.Option(False, "--json", help="Raw JSON output")
|
|
|
2792
2796
|
|
|
2793
2797
|
|
|
2794
2798
|
def _resolve_agent_id(target_id: str) -> tuple[str, str, str]:
|
|
2795
|
-
"""Resolves short Profile ID (e.g.
|
|
2799
|
+
"""Resolves short Profile ID (e.g. aa23), Client ID, suffix, or name into (profile_id, client_id, agent_name)."""
|
|
2796
2800
|
import json
|
|
2797
2801
|
from pathlib import Path
|
|
2798
2802
|
agents_file = Path.home() / ".akash" / "agents.json"
|
|
@@ -2801,15 +2805,32 @@ def _resolve_agent_id(target_id: str) -> tuple[str, str, str]:
|
|
|
2801
2805
|
try: agents = json.loads(agents_file.read_text())
|
|
2802
2806
|
except Exception: pass
|
|
2803
2807
|
|
|
2804
|
-
|
|
2808
|
+
if not target_id:
|
|
2809
|
+
if agents:
|
|
2810
|
+
first_pid = next(reversed(list(agents.keys())))
|
|
2811
|
+
return first_pid, agents[first_pid]["client_id"], agents[first_pid].get("name", "Agent")
|
|
2812
|
+
return "", "", "Agent"
|
|
2813
|
+
|
|
2814
|
+
# 1. Match by Profile ID (e.g. aa23)
|
|
2805
2815
|
if target_id in agents:
|
|
2806
2816
|
return target_id, agents[target_id]["client_id"], agents[target_id].get("name", "Agent")
|
|
2807
2817
|
|
|
2808
|
-
# 2. Match by Client ID
|
|
2818
|
+
# 2. Match by exact Client ID
|
|
2809
2819
|
for pid, d in agents.items():
|
|
2810
2820
|
if d.get("client_id") == target_id:
|
|
2811
2821
|
return pid, target_id, d.get("name", "Agent")
|
|
2812
2822
|
|
|
2823
|
+
# 3. Match by Client ID suffix (e.g. d06f) or prefix
|
|
2824
|
+
for pid, d in agents.items():
|
|
2825
|
+
cid = d.get("client_id", "")
|
|
2826
|
+
if cid.endswith(target_id) or cid.startswith(target_id) or (len(target_id) >= 4 and target_id in cid):
|
|
2827
|
+
return pid, cid, d.get("name", "Agent")
|
|
2828
|
+
|
|
2829
|
+
# 4. Match by Name (case-insensitive)
|
|
2830
|
+
for pid, d in agents.items():
|
|
2831
|
+
if d.get("name", "").lower() == target_id.lower():
|
|
2832
|
+
return pid, d.get("client_id", ""), d.get("name", "Agent")
|
|
2833
|
+
|
|
2813
2834
|
return target_id, target_id, "Agent"
|
|
2814
2835
|
|
|
2815
2836
|
|
|
@@ -3310,15 +3331,19 @@ def mcp_serve(
|
|
|
3310
3331
|
except Exception: agents = {}
|
|
3311
3332
|
|
|
3312
3333
|
if not profile_id and not client_id and agents:
|
|
3313
|
-
profile_id =
|
|
3334
|
+
profile_id = next(reversed(list(agents.keys())))
|
|
3314
3335
|
|
|
3315
|
-
|
|
3316
|
-
|
|
3336
|
+
resolved_pid, resolved_cid, pname = _resolve_agent_id(profile_id or client_id or "")
|
|
3337
|
+
cached = agents.get(resolved_pid, {})
|
|
3338
|
+
cid = client_id or resolved_cid or cached.get("client_id") or os.getenv("AKASH_CLIENT_ID")
|
|
3317
3339
|
csec = client_secret or cached.get("client_secret") or os.getenv("AKASH_CLIENT_SECRET")
|
|
3318
|
-
pname = cached.get("name",
|
|
3340
|
+
pname = cached.get("name", pname)
|
|
3341
|
+
profile_id = resolved_pid or profile_id
|
|
3319
3342
|
|
|
3320
3343
|
if not cid or not csec:
|
|
3321
|
-
|
|
3344
|
+
avail = ", ".join([f"{k} ({v.get('name', 'Agent')})" for k, v in agents.items()]) if agents else "none"
|
|
3345
|
+
_err(f"Missing credentials for '{profile_id or client_id or 'default'}'. Available profiles: {avail}")
|
|
3346
|
+
_err("Provide a valid --id <ID> or create one: akash mcp create -n Dev -r @coder")
|
|
3322
3347
|
raise typer.Exit(1)
|
|
3323
3348
|
|
|
3324
3349
|
_, base = _resolve_client(url or cached.get("url"), require_key=False, silent=True)
|
|
@@ -3399,6 +3424,7 @@ def mcp_serve(
|
|
|
3399
3424
|
args = frame.get("arguments", {})
|
|
3400
3425
|
t0 = time.monotonic()
|
|
3401
3426
|
now_str = datetime.datetime.now().strftime("%H:%M:%S")
|
|
3427
|
+
ts_pfx = f" {_GR}{now_str}{_RS}"
|
|
3402
3428
|
|
|
3403
3429
|
if t_name == "akash_exec_command":
|
|
3404
3430
|
cmd = args.get("command", "")
|
|
@@ -3406,7 +3432,7 @@ def mcp_serve(
|
|
|
3406
3432
|
|
|
3407
3433
|
is_safe, sec_reason = _sanitize_agent_command(cmd, scopes=cached.get("scopes", "*"))
|
|
3408
3434
|
if not is_safe:
|
|
3409
|
-
print(f"
|
|
3435
|
+
print(f"{ts_pfx} {_R}🚨 Blocked{_RS} -> {disp_cmd} {_dim('(' + sec_reason + ')')}")
|
|
3410
3436
|
ws.send(json.dumps({
|
|
3411
3437
|
"type": "tool_response",
|
|
3412
3438
|
"id": call_id,
|
|
@@ -3416,9 +3442,9 @@ def mcp_serve(
|
|
|
3416
3442
|
if any(k in cmd for k in ["touch", "mkdir", "mv", "cp", "sed", ">", ">>", "python", "npm", "pip"]):
|
|
3417
3443
|
_save_undo_checkpoint()
|
|
3418
3444
|
|
|
3419
|
-
# Instant frame-0 animated spinner with
|
|
3445
|
+
# Instant frame-0 animated spinner with live visibility
|
|
3420
3446
|
try:
|
|
3421
|
-
with _Spin(f"
|
|
3447
|
+
with _Spin(f"exec: {disp_cmd}", min_seconds=0.25, prefix=ts_pfx):
|
|
3422
3448
|
r = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=60)
|
|
3423
3449
|
elapsed_ms = (time.monotonic() - t0) * 1000
|
|
3424
3450
|
raw_out = r.stdout + r.stderr
|
|
@@ -3432,7 +3458,7 @@ def mcp_serve(
|
|
|
3432
3458
|
|
|
3433
3459
|
ec_color = _G if returncode == 0 else _R
|
|
3434
3460
|
ec_icon = f"{_G}✓{_RS}" if returncode == 0 else f"{_R}✗{_RS}"
|
|
3435
|
-
print(f"
|
|
3461
|
+
print(f"{ts_pfx} {ec_icon} {ec_color}exec:{_RS} {disp_cmd} {ec_color}[{returncode}]{_RS} {_dim(f'{elapsed_ms:.1f}ms')}")
|
|
3436
3462
|
|
|
3437
3463
|
ws.send(json.dumps({
|
|
3438
3464
|
"type": "tool_response",
|
|
@@ -3440,10 +3466,10 @@ def mcp_serve(
|
|
|
3440
3466
|
"result": {"content": [{"type": "text", "text": bounded_out or "(no output)"}], "isError": returncode != 0}
|
|
3441
3467
|
}))
|
|
3442
3468
|
elif t_name == "akash_undo":
|
|
3443
|
-
with _Spin("undo: reverting workspace to checkpoint", min_seconds=0.
|
|
3469
|
+
with _Spin("undo: reverting workspace to checkpoint", min_seconds=0.25, prefix=ts_pfx):
|
|
3444
3470
|
ok, msg_txt = _restore_undo_checkpoint()
|
|
3445
3471
|
icon = f"{_G}✓{_RS}" if ok else f"{_R}✗{_RS}"
|
|
3446
|
-
print(f"
|
|
3472
|
+
print(f"{ts_pfx} {icon} {(_G if ok else _R)}undo:{_RS} {_dim(msg_txt)}")
|
|
3447
3473
|
ws.send(json.dumps({
|
|
3448
3474
|
"type": "tool_response",
|
|
3449
3475
|
"id": call_id,
|
|
@@ -3453,10 +3479,10 @@ def mcp_serve(
|
|
|
3453
3479
|
elif t_name == "akash_checkpoint_create":
|
|
3454
3480
|
label = args.get("label", "agent_checkpoint")
|
|
3455
3481
|
from .terminal import build_snapshot
|
|
3456
|
-
with _Spin(f"checkpoint: {label} (packing workspace)", min_seconds=0.
|
|
3482
|
+
with _Spin(f"checkpoint: {label} (packing workspace)", min_seconds=0.25, prefix=ts_pfx):
|
|
3457
3483
|
_, manifest, _ = build_snapshot(label=label)
|
|
3458
3484
|
elapsed_ms = (time.monotonic() - t0) * 1000
|
|
3459
|
-
print(f"
|
|
3485
|
+
print(f"{ts_pfx} {_C}📸 checkpoint:{_RS} {_dim(label)} ({len(manifest.get('files', []))} files) {_dim(f'{elapsed_ms:.1f}ms')}")
|
|
3460
3486
|
ws.send(json.dumps({
|
|
3461
3487
|
"type": "tool_response",
|
|
3462
3488
|
"id": call_id,
|
|
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
|