akashcli 4.8.4__tar.gz → 4.8.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.8.4 → akashcli-4.8.6}/PKG-INFO +41 -5
- {akashcli-4.8.4 → akashcli-4.8.6}/README.md +40 -4
- {akashcli-4.8.4 → akashcli-4.8.6}/akashcli/__init__.py +1 -1
- {akashcli-4.8.4 → akashcli-4.8.6}/akashcli/cli.py +140 -138
- {akashcli-4.8.4 → akashcli-4.8.6}/akashcli/client.py +1 -1
- {akashcli-4.8.4 → akashcli-4.8.6}/akashcli/storage.py +4 -0
- {akashcli-4.8.4 → akashcli-4.8.6}/akashcli/uploader.py +11 -1
- {akashcli-4.8.4 → akashcli-4.8.6}/akashcli.egg-info/PKG-INFO +41 -5
- {akashcli-4.8.4 → akashcli-4.8.6}/pyproject.toml +1 -1
- {akashcli-4.8.4 → akashcli-4.8.6}/akashcli/_net.py +0 -0
- {akashcli-4.8.4 → akashcli-4.8.6}/akashcli/auth.py +0 -0
- {akashcli-4.8.4 → akashcli-4.8.6}/akashcli/config.py +0 -0
- {akashcli-4.8.4 → akashcli-4.8.6}/akashcli/crypto.py +0 -0
- {akashcli-4.8.4 → akashcli-4.8.6}/akashcli/env_manager.py +0 -0
- {akashcli-4.8.4 → akashcli-4.8.6}/akashcli/exceptions.py +0 -0
- {akashcli-4.8.4 → akashcli-4.8.6}/akashcli/exec.py +0 -0
- {akashcli-4.8.4 → akashcli-4.8.6}/akashcli/integrity.py +0 -0
- {akashcli-4.8.4 → akashcli-4.8.6}/akashcli/logger.py +0 -0
- {akashcli-4.8.4 → akashcli-4.8.6}/akashcli/models.py +0 -0
- {akashcli-4.8.4 → akashcli-4.8.6}/akashcli/p2p.py +0 -0
- {akashcli-4.8.4 → akashcli-4.8.6}/akashcli/packages.py +0 -0
- {akashcli-4.8.4 → akashcli-4.8.6}/akashcli/relay.py +0 -0
- {akashcli-4.8.4 → akashcli-4.8.6}/akashcli/restore.py +0 -0
- {akashcli-4.8.4 → akashcli-4.8.6}/akashcli/snapshot_crypto.py +0 -0
- {akashcli-4.8.4 → akashcli-4.8.6}/akashcli/terminal.py +0 -0
- {akashcli-4.8.4 → akashcli-4.8.6}/akashcli/updater.py +0 -0
- {akashcli-4.8.4 → akashcli-4.8.6}/akashcli/utils.py +0 -0
- {akashcli-4.8.4 → akashcli-4.8.6}/akashcli.egg-info/SOURCES.txt +0 -0
- {akashcli-4.8.4 → akashcli-4.8.6}/akashcli.egg-info/dependency_links.txt +0 -0
- {akashcli-4.8.4 → akashcli-4.8.6}/akashcli.egg-info/entry_points.txt +0 -0
- {akashcli-4.8.4 → akashcli-4.8.6}/akashcli.egg-info/requires.txt +0 -0
- {akashcli-4.8.4 → akashcli-4.8.6}/akashcli.egg-info/top_level.txt +0 -0
- {akashcli-4.8.4 → akashcli-4.8.6}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: akashcli
|
|
3
|
-
Version: 4.8.
|
|
3
|
+
Version: 4.8.6
|
|
4
4
|
Summary: Akash CLI — secure remote shell relay, file vault, and device management
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
Keywords: akash,cli,relay,remote-shell,vault
|
|
@@ -35,6 +35,7 @@ Requires-Dist: websockets
|
|
|
35
35
|
[Quickstart](#-quickstart-in-60-seconds) •
|
|
36
36
|
[Core Features](#-core-features) •
|
|
37
37
|
[Zero-Login Guest Mode](#-zero-login-guest-mode) •
|
|
38
|
+
[💖 Sponsoring](#-sponsorship--restoring-storage-services) •
|
|
38
39
|
[Documentation](#-in-depth-documentation-guides) •
|
|
39
40
|
[Command Matrix](#-command-matrix)
|
|
40
41
|
|
|
@@ -42,6 +43,14 @@ Requires-Dist: websockets
|
|
|
42
43
|
|
|
43
44
|
</div>
|
|
44
45
|
|
|
46
|
+
> [!WARNING]
|
|
47
|
+
> ### ⚠️ Cloud Storage & Upload Services Discontinued Due to Lack of Funding
|
|
48
|
+
> **Notice:** Public cloud file uploading and storage hosting services (`akash upload`, `akash cloud upload`, `akash cloud bulk`, `akash pipe`) have been **discontinued due to infrastructure hosting costs and lack of funding**.
|
|
49
|
+
>
|
|
50
|
+
> All terminal features (**remote shell relays, 1-click guest pairing, environment snapshots, local .env management, and AI MCP agent bridges**) remain **100% active and free**.
|
|
51
|
+
>
|
|
52
|
+
> 💖 **Help us bring back community storage infrastructure:** Please consider [Sponsoring the Project](#-sponsorship--restoring-storage-services) or running `akash sponsor`.
|
|
53
|
+
|
|
45
54
|
## 🌟 Why Akash CLI?
|
|
46
55
|
|
|
47
56
|
Modern developer workflows demand flexibility across multiple machines — laptops, cloud servers, and mobile environments like Android Termux. Akash CLI solves daily pain points with a unified, secure toolkit:
|
|
@@ -175,8 +184,16 @@ akash env push prod --burn
|
|
|
175
184
|
akash env pull eX481p prod
|
|
176
185
|
```
|
|
177
186
|
|
|
178
|
-
### 6.
|
|
187
|
+
### 6. AI Agent Gateway (MCP) & Guard Console
|
|
179
188
|
Supercharge Cursor and Claude Desktop with local terminal execution, protected by real-time human approval:
|
|
189
|
+
|
|
190
|
+
```
|
|
191
|
+
╭─────╮
|
|
192
|
+
╭──╯ ╰──╮ AKASH MCP
|
|
193
|
+
( M C P ) Model Context Protocol · Claude · Cursor · Codex
|
|
194
|
+
╰───────────╯
|
|
195
|
+
```
|
|
196
|
+
|
|
180
197
|
```bash
|
|
181
198
|
# 1. Create agent profile with safe role preset:
|
|
182
199
|
akash agent create --name "Cursor" --role @coder
|
|
@@ -215,6 +232,7 @@ Explore comprehensive guides in the [`docs/`](docs/) directory:
|
|
|
215
232
|
|
|
216
233
|
```text
|
|
217
234
|
akash
|
|
235
|
+
├── sponsor 💖 Information on sponsoring & bringing back storage nodes
|
|
218
236
|
├── login Connect API key with hardware binding
|
|
219
237
|
├── whoami Account quota & device fingerprint
|
|
220
238
|
├── backup Save terminal environment to cloud or local archive
|
|
@@ -225,12 +243,12 @@ akash
|
|
|
225
243
|
├── serve Make device reachable (--daemon, --share for guest mode)
|
|
226
244
|
├── devices List, authorize, or revoke enrolled machines
|
|
227
245
|
├── cloud
|
|
228
|
-
│ ├── upload Upload file
|
|
246
|
+
│ ├── upload [DISCONTINUED] Upload file (run 'akash sponsor' for details)
|
|
229
247
|
│ ├── files List vault files
|
|
230
248
|
│ ├── stream Direct streaming link or launch in VLC
|
|
231
|
-
│ ├── bulk Recursively upload directory
|
|
249
|
+
│ ├── bulk [DISCONTINUED] Recursively upload directory
|
|
232
250
|
│ └── delete Purge file permanently
|
|
233
|
-
├── pipe Upload stdin
|
|
251
|
+
├── pipe [DISCONTINUED] Upload stdin directly to cloud
|
|
234
252
|
├── send End-to-end encrypted P2P transfer to user public key
|
|
235
253
|
├── inbox Receive and decrypt incoming P2P files
|
|
236
254
|
├── id View or export P2P identity key and manage contacts
|
|
@@ -267,6 +285,24 @@ Akash CLI enforces security at every layer:
|
|
|
267
285
|
|
|
268
286
|
---
|
|
269
287
|
|
|
288
|
+
## 💖 Sponsorship & Restoring Storage Services
|
|
289
|
+
|
|
290
|
+
Akash CLI is an independent, community-driven open-source project. We previously provided free, high-speed public file uploading, sharing, and native media streaming. However, due to mounting NVMe cloud server expenses, bandwidth costs, and **a lack of operational funding**, public storage and uploading services had to be discontinued.
|
|
291
|
+
|
|
292
|
+
### How Your Sponsorship Helps
|
|
293
|
+
Your financial contribution directly funds:
|
|
294
|
+
* 💽 **Dedicated NVMe Storage Nodes**: Restoring community cloud vault storage for backups and files.
|
|
295
|
+
* 🌐 **High-Bandwidth Network Transit**: Low-latency global relay clusters for terminal sessions and fast file retrieval.
|
|
296
|
+
* 🛡️ **Long-Term Open Source Maintenance**: Ongoing development for Termux, Linux, macOS, and Windows.
|
|
297
|
+
|
|
298
|
+
### Ways to Sponsor & Donate
|
|
299
|
+
* **GitHub Sponsors**: [https://github.com/sponsors/juniorsir](https://github.com/sponsors/juniorsir)
|
|
300
|
+
* **Telegram Channel / Support**: [@EveryDL_bot](https://t.me/EveryDL_bot)
|
|
301
|
+
* **Direct / UPI / Crypto Support**: Reach out to maintainers via Telegram ([@EveryDL_bot](https://t.me/EveryDL_bot))
|
|
302
|
+
* **Console Command**: Run `akash sponsor` directly from your terminal to view sponsorship details.
|
|
303
|
+
|
|
304
|
+
---
|
|
305
|
+
|
|
270
306
|
## 📄 License
|
|
271
307
|
|
|
272
308
|
Distributed under the MIT License. See [LICENSE](LICENSE) for details.
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
[Quickstart](#-quickstart-in-60-seconds) •
|
|
17
17
|
[Core Features](#-core-features) •
|
|
18
18
|
[Zero-Login Guest Mode](#-zero-login-guest-mode) •
|
|
19
|
+
[💖 Sponsoring](#-sponsorship--restoring-storage-services) •
|
|
19
20
|
[Documentation](#-in-depth-documentation-guides) •
|
|
20
21
|
[Command Matrix](#-command-matrix)
|
|
21
22
|
|
|
@@ -23,6 +24,14 @@
|
|
|
23
24
|
|
|
24
25
|
</div>
|
|
25
26
|
|
|
27
|
+
> [!WARNING]
|
|
28
|
+
> ### ⚠️ Cloud Storage & Upload Services Discontinued Due to Lack of Funding
|
|
29
|
+
> **Notice:** Public cloud file uploading and storage hosting services (`akash upload`, `akash cloud upload`, `akash cloud bulk`, `akash pipe`) have been **discontinued due to infrastructure hosting costs and lack of funding**.
|
|
30
|
+
>
|
|
31
|
+
> All terminal features (**remote shell relays, 1-click guest pairing, environment snapshots, local .env management, and AI MCP agent bridges**) remain **100% active and free**.
|
|
32
|
+
>
|
|
33
|
+
> 💖 **Help us bring back community storage infrastructure:** Please consider [Sponsoring the Project](#-sponsorship--restoring-storage-services) or running `akash sponsor`.
|
|
34
|
+
|
|
26
35
|
## 🌟 Why Akash CLI?
|
|
27
36
|
|
|
28
37
|
Modern developer workflows demand flexibility across multiple machines — laptops, cloud servers, and mobile environments like Android Termux. Akash CLI solves daily pain points with a unified, secure toolkit:
|
|
@@ -156,8 +165,16 @@ akash env push prod --burn
|
|
|
156
165
|
akash env pull eX481p prod
|
|
157
166
|
```
|
|
158
167
|
|
|
159
|
-
### 6.
|
|
168
|
+
### 6. AI Agent Gateway (MCP) & Guard Console
|
|
160
169
|
Supercharge Cursor and Claude Desktop with local terminal execution, protected by real-time human approval:
|
|
170
|
+
|
|
171
|
+
```
|
|
172
|
+
╭─────╮
|
|
173
|
+
╭──╯ ╰──╮ AKASH MCP
|
|
174
|
+
( M C P ) Model Context Protocol · Claude · Cursor · Codex
|
|
175
|
+
╰───────────╯
|
|
176
|
+
```
|
|
177
|
+
|
|
161
178
|
```bash
|
|
162
179
|
# 1. Create agent profile with safe role preset:
|
|
163
180
|
akash agent create --name "Cursor" --role @coder
|
|
@@ -196,6 +213,7 @@ Explore comprehensive guides in the [`docs/`](docs/) directory:
|
|
|
196
213
|
|
|
197
214
|
```text
|
|
198
215
|
akash
|
|
216
|
+
├── sponsor 💖 Information on sponsoring & bringing back storage nodes
|
|
199
217
|
├── login Connect API key with hardware binding
|
|
200
218
|
├── whoami Account quota & device fingerprint
|
|
201
219
|
├── backup Save terminal environment to cloud or local archive
|
|
@@ -206,12 +224,12 @@ akash
|
|
|
206
224
|
├── serve Make device reachable (--daemon, --share for guest mode)
|
|
207
225
|
├── devices List, authorize, or revoke enrolled machines
|
|
208
226
|
├── cloud
|
|
209
|
-
│ ├── upload Upload file
|
|
227
|
+
│ ├── upload [DISCONTINUED] Upload file (run 'akash sponsor' for details)
|
|
210
228
|
│ ├── files List vault files
|
|
211
229
|
│ ├── stream Direct streaming link or launch in VLC
|
|
212
|
-
│ ├── bulk Recursively upload directory
|
|
230
|
+
│ ├── bulk [DISCONTINUED] Recursively upload directory
|
|
213
231
|
│ └── delete Purge file permanently
|
|
214
|
-
├── pipe Upload stdin
|
|
232
|
+
├── pipe [DISCONTINUED] Upload stdin directly to cloud
|
|
215
233
|
├── send End-to-end encrypted P2P transfer to user public key
|
|
216
234
|
├── inbox Receive and decrypt incoming P2P files
|
|
217
235
|
├── id View or export P2P identity key and manage contacts
|
|
@@ -248,6 +266,24 @@ Akash CLI enforces security at every layer:
|
|
|
248
266
|
|
|
249
267
|
---
|
|
250
268
|
|
|
269
|
+
## 💖 Sponsorship & Restoring Storage Services
|
|
270
|
+
|
|
271
|
+
Akash CLI is an independent, community-driven open-source project. We previously provided free, high-speed public file uploading, sharing, and native media streaming. However, due to mounting NVMe cloud server expenses, bandwidth costs, and **a lack of operational funding**, public storage and uploading services had to be discontinued.
|
|
272
|
+
|
|
273
|
+
### How Your Sponsorship Helps
|
|
274
|
+
Your financial contribution directly funds:
|
|
275
|
+
* 💽 **Dedicated NVMe Storage Nodes**: Restoring community cloud vault storage for backups and files.
|
|
276
|
+
* 🌐 **High-Bandwidth Network Transit**: Low-latency global relay clusters for terminal sessions and fast file retrieval.
|
|
277
|
+
* 🛡️ **Long-Term Open Source Maintenance**: Ongoing development for Termux, Linux, macOS, and Windows.
|
|
278
|
+
|
|
279
|
+
### Ways to Sponsor & Donate
|
|
280
|
+
* **GitHub Sponsors**: [https://github.com/sponsors/juniorsir](https://github.com/sponsors/juniorsir)
|
|
281
|
+
* **Telegram Channel / Support**: [@EveryDL_bot](https://t.me/EveryDL_bot)
|
|
282
|
+
* **Direct / UPI / Crypto Support**: Reach out to maintainers via Telegram ([@EveryDL_bot](https://t.me/EveryDL_bot))
|
|
283
|
+
* **Console Command**: Run `akash sponsor` directly from your terminal to view sponsorship details.
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
251
287
|
## 📄 License
|
|
252
288
|
|
|
253
289
|
Distributed under the MIT License. See [LICENSE](LICENSE) for details.
|
|
@@ -423,6 +423,8 @@ def whoami():
|
|
|
423
423
|
_err(str(e))
|
|
424
424
|
raise typer.Exit(1)
|
|
425
425
|
|
|
426
|
+
|
|
427
|
+
|
|
426
428
|
@app.command("url")
|
|
427
429
|
@cloud_app.command("url")
|
|
428
430
|
def cmd_url(
|
|
@@ -461,43 +463,59 @@ def cmd_url(
|
|
|
461
463
|
_info("To switch URL : akash url <NEW_URL> (e.g. akash url https://jstore.2bd.net)")
|
|
462
464
|
_info("To reset URL : akash url --reset")
|
|
463
465
|
_p()
|
|
466
|
+
def _storage_discontinued_notice():
|
|
467
|
+
print(f"\n{_R}⚠️ [SERVICE DISCONTINUED] Cloud storage & upload services are disabled.{_RS}")
|
|
468
|
+
print(f" {_DM}Public cloud uploading has been discontinued due to lack of funds and hosting costs.{_RS}")
|
|
469
|
+
print(f" {_DM}We are actively seeking sponsors to help restore community storage infrastructure.{_RS}\n")
|
|
470
|
+
print(f" {_C}💖 Sponsoring the project:{_RS}")
|
|
471
|
+
print(f" Run {_YE}akash sponsor{_RS} or visit {_CY}https://github.com/juniorsir/akashcli#sponsorship{_RS}\n")
|
|
472
|
+
raise typer.Exit(1)
|
|
473
|
+
|
|
474
|
+
|
|
475
|
+
@app.command("sponsor")
|
|
476
|
+
def cmd_sponsor():
|
|
477
|
+
"""Information on sponsoring Akash CLI to restore storage services."""
|
|
478
|
+
print(f"\n{_C}╔═══════════════════════════════════════════════════════════════╗{_RS}")
|
|
479
|
+
print(f"{_C}║ 💖 SPONSOR AKASH CLI INFRASTRUCTURE ║{_RS}")
|
|
480
|
+
print(f"{_C}╚═══════════════════════════════════════════════════════════════╝{_RS}\n")
|
|
481
|
+
print(f" {_B}Status Update:{_RS}")
|
|
482
|
+
print(f" Public cloud storage and file uploading services have been")
|
|
483
|
+
print(f" discontinued due to infrastructure costs and lack of funding.\n")
|
|
484
|
+
print(f" {_B}Why We Need Sponsors:{_RS}")
|
|
485
|
+
print(f" • High-performance NVMe storage nodes for community vaulting")
|
|
486
|
+
print(f" • Global high-bandwidth relays for low-latency PTY terminals")
|
|
487
|
+
print(f" • Free open-source developer tooling & automated backups\n")
|
|
488
|
+
print(f" {_B}How You Can Sponsor & Help:{_RS}")
|
|
489
|
+
print(f" • GitHub Sponsors : {_YE}https://github.com/sponsors/juniorsir{_RS}")
|
|
490
|
+
print(f" • Telegram Channel: {_YE}https://t.me/EveryDL_bot{_RS}")
|
|
491
|
+
print(f" • Direct / UPI : Contact via Telegram (@EveryDL_bot)\n")
|
|
492
|
+
print(f" {_DM}Every contribution helps bring back community storage services!{_RS}\n")
|
|
493
|
+
|
|
494
|
+
|
|
464
495
|
@cloud_app.command("upload")
|
|
465
496
|
def cloud_upload(
|
|
466
|
-
path: Optional[Path] = typer.Argument(None, help="File to upload"),
|
|
467
|
-
text: Optional[str] = typer.Option(None, "--text", "-t", help="Upload raw text"),
|
|
497
|
+
path: Optional[Path] = typer.Argument(None, help="File to upload (DISCONTINUED)"),
|
|
498
|
+
text: Optional[str] = typer.Option(None, "--text", "-t", help="Upload raw text (DISCONTINUED)"),
|
|
468
499
|
name: Optional[str] = typer.Option(None, "--name", "-n", help="Custom filename"),
|
|
469
500
|
burn: bool = typer.Option(False, "--burn", help="Delete after first download"),
|
|
470
501
|
expiry: int = typer.Option(0, "--expiry","-e",help="Expire in N days (0 = never)"),
|
|
471
502
|
password: Optional[str] = typer.Option(None, "--pass", "-p", help="Password-protect"),
|
|
472
503
|
):
|
|
473
|
-
"""Upload a file or text snippet."""
|
|
474
|
-
|
|
475
|
-
client = AkashClient()
|
|
504
|
+
"""[DISCONTINUED] Upload a file or text snippet (Service retired due to lack of funds)."""
|
|
505
|
+
_storage_discontinued_notice()
|
|
476
506
|
|
|
477
|
-
def _cb(done, total):
|
|
478
|
-
bar = _progress_bar(done, total)
|
|
479
|
-
sys.stdout.write(f"\r {_C}↑{_RS} {bar} ")
|
|
480
|
-
sys.stdout.flush()
|
|
481
507
|
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
_ok(f"{label} code={_ye(res.file_code)}")
|
|
494
|
-
_info(f"link {res.embed_url}")
|
|
495
|
-
except typer.Exit:
|
|
496
|
-
raise
|
|
497
|
-
except Exception as e:
|
|
498
|
-
sys.stdout.write(chr(13) + chr(27) + "[2K"); sys.stdout.flush()
|
|
499
|
-
_err(f"upload failed: {e}")
|
|
500
|
-
raise typer.Exit(1)
|
|
508
|
+
@app.command("upload")
|
|
509
|
+
def app_upload(
|
|
510
|
+
path: Optional[Path] = typer.Argument(None, help="File to upload (DISCONTINUED)"),
|
|
511
|
+
text: Optional[str] = typer.Option(None, "--text", "-t", help="Upload raw text (DISCONTINUED)"),
|
|
512
|
+
name: Optional[str] = typer.Option(None, "--name", "-n", help="Custom filename"),
|
|
513
|
+
burn: bool = typer.Option(False, "--burn", help="Delete after first download"),
|
|
514
|
+
expiry: int = typer.Option(0, "--expiry","-e",help="Expire in N days (0 = never)"),
|
|
515
|
+
password: Optional[str] = typer.Option(None, "--pass", "-p", help="Password-protect"),
|
|
516
|
+
):
|
|
517
|
+
"""[DISCONTINUED] Upload a file or text snippet (Service retired due to lack of funds)."""
|
|
518
|
+
_storage_discontinued_notice()
|
|
501
519
|
|
|
502
520
|
|
|
503
521
|
# ── akash cloud files ─────────────────────────────────────────────────────────
|
|
@@ -603,22 +621,8 @@ def cloud_manage(
|
|
|
603
621
|
|
|
604
622
|
@cloud_app.command("bulk")
|
|
605
623
|
def cloud_bulk(path: Path):
|
|
606
|
-
"""Recursively upload every file in a folder."""
|
|
607
|
-
|
|
608
|
-
client = AkashClient()
|
|
609
|
-
uploader = VaultUploader(client)
|
|
610
|
-
all_files = [p for p in path.glob("**/*") if p.is_file() and not p.name.startswith(".")]
|
|
611
|
-
for i, file in enumerate(all_files, 1):
|
|
612
|
-
sys.stdout.write(f"\r {_C}↑{_RS} [{i}/{len(all_files)}] {_DM}{file.name}{_RS} ")
|
|
613
|
-
sys.stdout.flush()
|
|
614
|
-
uploader.upload(file_path=str(file))
|
|
615
|
-
sys.stdout.write(chr(13) + chr(27) + "[2K"); sys.stdout.flush()
|
|
616
|
-
sys.stdout.flush()
|
|
617
|
-
_ok(f"uploaded {len(all_files)} files")
|
|
618
|
-
except Exception as e:
|
|
619
|
-
sys.stdout.write(chr(13) + chr(27) + "[2K"); sys.stdout.flush()
|
|
620
|
-
_err(str(e))
|
|
621
|
-
raise typer.Exit(1)
|
|
624
|
+
"""[DISCONTINUED] Recursively upload every file in a folder."""
|
|
625
|
+
_storage_discontinued_notice()
|
|
622
626
|
|
|
623
627
|
|
|
624
628
|
# ── Helpers for backup/restore output ────────────────────────────────────────
|
|
@@ -2008,8 +2012,14 @@ def send(
|
|
|
2008
2012
|
_ok(f"encrypted {_dim(f'{size_kb:.1f} KB → {enc_kb:.1f} KB')}")
|
|
2009
2013
|
|
|
2010
2014
|
# ── 4. Upload envelope ────────────────────────────────────────────────────
|
|
2015
|
+
api_key, base = _resolve_client(require_key=False, silent=True)
|
|
2016
|
+
if not api_key:
|
|
2017
|
+
_err("Not logged in. You must be logged in to send files.")
|
|
2018
|
+
print(f" {_DM}Run {_C}akash login{_RS}{_DM} to log in, or set {_C}AKASH_API_KEY{_RS}{_DM}.{_RS}")
|
|
2019
|
+
raise typer.Exit(1)
|
|
2020
|
+
|
|
2011
2021
|
try:
|
|
2012
|
-
client = AkashClient()
|
|
2022
|
+
client = AkashClient(api_key=api_key, api_url=base)
|
|
2013
2023
|
except Exception as e:
|
|
2014
2024
|
_err(f"not logged in: {e}")
|
|
2015
2025
|
raise typer.Exit(1)
|
|
@@ -2086,8 +2096,14 @@ def inbox(
|
|
|
2086
2096
|
_err(f"failed to load identity: {e}")
|
|
2087
2097
|
raise typer.Exit(1)
|
|
2088
2098
|
|
|
2099
|
+
api_key, base = _resolve_client(require_key=False, silent=True)
|
|
2100
|
+
if not api_key:
|
|
2101
|
+
_err("Not logged in. You must be logged in to view your inbox.")
|
|
2102
|
+
print(f" {_DM}Run {_C}akash login{_RS}{_DM} to log in, or set {_C}AKASH_API_KEY{_RS}{_DM}.{_RS}")
|
|
2103
|
+
raise typer.Exit(1)
|
|
2104
|
+
|
|
2089
2105
|
try:
|
|
2090
|
-
client = AkashClient()
|
|
2106
|
+
client = AkashClient(api_key=api_key, api_url=base)
|
|
2091
2107
|
except Exception as e:
|
|
2092
2108
|
_err(f"not logged in: {e}")
|
|
2093
2109
|
raise typer.Exit(1)
|
|
@@ -2246,93 +2262,15 @@ def _decrypt_one(code: str, ident: dict, client, out: Optional[Path],
|
|
|
2246
2262
|
# ── akash pipe ────────────────────────────────────────────────────────────────
|
|
2247
2263
|
|
|
2248
2264
|
@app.command()
|
|
2249
|
-
@cloud_app.command("pipe", help="Upload stdin or a command's output")
|
|
2265
|
+
@cloud_app.command("pipe", help="[DISCONTINUED] Upload stdin or a command's output")
|
|
2250
2266
|
def pipe(
|
|
2251
2267
|
name: Optional[str] = typer.Option(None, "--name", "-n", help="Filename for the cloud snippet"),
|
|
2252
2268
|
burn: bool = typer.Option(False, "--burn", help="Delete after first download"),
|
|
2253
2269
|
expiry: int = typer.Option(0, "--expiry","-e", help="Expire in N days (0 = never)"),
|
|
2254
2270
|
command: Optional[str] = typer.Option(None, "--run", "-c", help="Run a command and pipe its output"),
|
|
2255
2271
|
):
|
|
2256
|
-
"""Pipe stdin (or a command's output) to the cloud.
|
|
2257
|
-
|
|
2258
|
-
Examples:
|
|
2259
|
-
echo "hello" | akash pipe
|
|
2260
|
-
cat debug.log | akash pipe --name debug.log
|
|
2261
|
-
akash pipe --run "df -h" --name disk-report.txt
|
|
2262
|
-
git log --oneline | akash pipe --burn --name git-log.txt
|
|
2263
|
-
"""
|
|
2264
|
-
from .logger import log_op
|
|
2265
|
-
import io
|
|
2266
|
-
|
|
2267
|
-
try:
|
|
2268
|
-
client = AkashClient()
|
|
2269
|
-
except Exception as e:
|
|
2270
|
-
_err(f"not logged in: {e}")
|
|
2271
|
-
raise typer.Exit(1)
|
|
2272
|
-
|
|
2273
|
-
# ── Gather bytes ──────────────────────────────────────────────────────────
|
|
2274
|
-
if command:
|
|
2275
|
-
import subprocess as _sp
|
|
2276
|
-
_info(f"running: {command}")
|
|
2277
|
-
try:
|
|
2278
|
-
result = _sp.run(command, shell=True, capture_output=True)
|
|
2279
|
-
data = result.stdout + result.stderr
|
|
2280
|
-
except Exception as e:
|
|
2281
|
-
_err(f"command failed: {e}")
|
|
2282
|
-
raise typer.Exit(1)
|
|
2283
|
-
else:
|
|
2284
|
-
import sys as _sys
|
|
2285
|
-
if _sys.stdin.isatty():
|
|
2286
|
-
_err("nothing to pipe - use --run or pipe stdin: echo 'hello' | akash pipe")
|
|
2287
|
-
raise typer.Exit(1)
|
|
2288
|
-
data = _sys.stdin.buffer.read()
|
|
2289
|
-
|
|
2290
|
-
if not data:
|
|
2291
|
-
_err("empty input - nothing to upload")
|
|
2292
|
-
raise typer.Exit(1)
|
|
2293
|
-
|
|
2294
|
-
size_kb = len(data) / 1024
|
|
2295
|
-
filename = name or f"pipe_{__import__('time').strftime('%Y%m%d_%H%M%S')}.txt"
|
|
2296
|
-
|
|
2297
|
-
# ── Upload ────────────────────────────────────────────────────────────────
|
|
2298
|
-
import tempfile as _tf
|
|
2299
|
-
with _tf.NamedTemporaryFile(suffix=".txt", prefix="akash_pipe_", delete=False) as tmp:
|
|
2300
|
-
tmp.write(data)
|
|
2301
|
-
tmp_path = tmp.name
|
|
2302
|
-
|
|
2303
|
-
try:
|
|
2304
|
-
def _cb(done, total):
|
|
2305
|
-
bar = _progress_bar(done, total)
|
|
2306
|
-
sys.stdout.write(f"\r {_C}↑{_RS} {bar} ")
|
|
2307
|
-
sys.stdout.flush()
|
|
2308
|
-
|
|
2309
|
-
# rename the tmp file so the server picks up the right name
|
|
2310
|
-
import os as _os
|
|
2311
|
-
named_path = _os.path.join(_os.path.dirname(tmp_path), filename)
|
|
2312
|
-
_os.rename(tmp_path, named_path)
|
|
2313
|
-
|
|
2314
|
-
result = client.upload_file(named_path, burn=burn, expiry=expiry, progress_callback=_cb)
|
|
2315
|
-
sys.stdout.write(chr(13) + chr(27) + "[2K"); sys.stdout.flush()
|
|
2316
|
-
except Exception as e:
|
|
2317
|
-
sys.stdout.write(chr(13) + chr(27) + "[2K"); sys.stdout.flush()
|
|
2318
|
-
_err(f"upload failed: {e}")
|
|
2319
|
-
log_op("pipe", ok=False, error=str(e))
|
|
2320
|
-
raise typer.Exit(1)
|
|
2321
|
-
finally:
|
|
2322
|
-
try:
|
|
2323
|
-
import os as _os2
|
|
2324
|
-
_os2.unlink(named_path)
|
|
2325
|
-
except Exception:
|
|
2326
|
-
pass
|
|
2327
|
-
|
|
2328
|
-
log_op("pipe", ok=True, code=result.file_code, filename=filename, size=len(data))
|
|
2329
|
-
_p()
|
|
2330
|
-
_ok(f"uploaded {_cy(filename)} {_dim(f'{size_kb:.1f} KB')}")
|
|
2331
|
-
_info(f"code {_ye(result.file_code)}")
|
|
2332
|
-
_info(f"link {result.embed_url}")
|
|
2333
|
-
if burn:
|
|
2334
|
-
_info("burns after first download")
|
|
2335
|
-
_p()
|
|
2272
|
+
"""[DISCONTINUED] Pipe stdin (or a command's output) to the cloud."""
|
|
2273
|
+
_storage_discontinued_notice()
|
|
2336
2274
|
|
|
2337
2275
|
|
|
2338
2276
|
# ── akash log (+ --stats) ─────────────────────────────────────────────────────
|
|
@@ -2644,8 +2582,14 @@ def env_push(
|
|
|
2644
2582
|
from .logger import log_op
|
|
2645
2583
|
import tempfile as _tf
|
|
2646
2584
|
|
|
2585
|
+
api_key, base = _resolve_client(require_key=False, silent=True)
|
|
2586
|
+
if not api_key:
|
|
2587
|
+
_err("Not logged in. You must be logged in to push environment variables.")
|
|
2588
|
+
print(f" {_DM}Run {_C}akash login{_RS}{_DM} to log in, or set {_C}AKASH_API_KEY{_RS}{_DM}.{_RS}")
|
|
2589
|
+
raise typer.Exit(1)
|
|
2590
|
+
|
|
2647
2591
|
try:
|
|
2648
|
-
client = AkashClient()
|
|
2592
|
+
client = AkashClient(api_key=api_key, api_url=base)
|
|
2649
2593
|
except Exception as e:
|
|
2650
2594
|
_err(f"not logged in: {e}")
|
|
2651
2595
|
raise typer.Exit(1)
|
|
@@ -2708,8 +2652,14 @@ def env_pull(
|
|
|
2708
2652
|
from .env_manager import env_save_blob
|
|
2709
2653
|
from .logger import log_op
|
|
2710
2654
|
|
|
2655
|
+
api_key, base = _resolve_client(require_key=False, silent=True)
|
|
2656
|
+
if not api_key:
|
|
2657
|
+
_err("Not logged in. You must be logged in to pull environment variables.")
|
|
2658
|
+
print(f" {_DM}Run {_C}akash login{_RS}{_DM} to log in, or set {_C}AKASH_API_KEY{_RS}{_DM}.{_RS}")
|
|
2659
|
+
raise typer.Exit(1)
|
|
2660
|
+
|
|
2711
2661
|
try:
|
|
2712
|
-
client = AkashClient()
|
|
2662
|
+
client = AkashClient(api_key=api_key, api_url=base)
|
|
2713
2663
|
except Exception as e:
|
|
2714
2664
|
_err(f"not logged in: {e}")
|
|
2715
2665
|
raise typer.Exit(1)
|
|
@@ -2773,6 +2723,43 @@ def _render_inspection_card(r: dict) -> None:
|
|
|
2773
2723
|
print(f" {_C}╰────────────────────────────────────────────────────────────────────{_RS}")
|
|
2774
2724
|
|
|
2775
2725
|
|
|
2726
|
+
def _print_mcp_cloud_logo(title: str = "Akash MCP", subtitle: str = "Model Context Protocol · Claude · Cursor · Codex"):
|
|
2727
|
+
"""Renders the clean cloud icon logo for Akash MCP commands."""
|
|
2728
|
+
C, W, DM, RS = _C, _W, _DM, _RS
|
|
2729
|
+
print(f" {C} ╭─────╮{RS}")
|
|
2730
|
+
print(f" {C} ╭──╯ ╰──╮{RS} {W}{title}{RS}")
|
|
2731
|
+
print(f" {C} ( M C P ){RS} {DM}{subtitle}{RS}")
|
|
2732
|
+
print(f" {C} ╰───────────╯{RS}")
|
|
2733
|
+
|
|
2734
|
+
|
|
2735
|
+
def _print_cmd_tree_output(raw_out: str, max_lines: int = 5, indent: str = " "):
|
|
2736
|
+
"""Prints tool/command output in gray with tree-based branching (├─, └─)."""
|
|
2737
|
+
if not raw_out or not str(raw_out).strip():
|
|
2738
|
+
print(f"{indent}{_GR}└─{_RS} {_GR}{_DM}(no output){_RS}")
|
|
2739
|
+
return
|
|
2740
|
+
|
|
2741
|
+
clean_text = re.sub(r"\x1b\[[0-9;]*[a-zA-Z]", "", str(raw_out))
|
|
2742
|
+
lines = [ln.strip() for ln in clean_text.splitlines() if ln.strip()]
|
|
2743
|
+
|
|
2744
|
+
if not lines:
|
|
2745
|
+
print(f"{indent}{_GR}└─{_RS} {_GR}{_DM}(no output){_RS}")
|
|
2746
|
+
return
|
|
2747
|
+
|
|
2748
|
+
show_lines = lines[:max_lines]
|
|
2749
|
+
has_more = len(lines) > max_lines
|
|
2750
|
+
|
|
2751
|
+
for i, line in enumerate(show_lines):
|
|
2752
|
+
if len(line) > 85:
|
|
2753
|
+
line = line[:82] + "…"
|
|
2754
|
+
is_last = (i == len(show_lines) - 1) and not has_more
|
|
2755
|
+
branch = "└─" if is_last else "├─"
|
|
2756
|
+
print(f"{indent}{_GR}{branch}{_RS} {_GR}{_DM}{line}{_RS}")
|
|
2757
|
+
|
|
2758
|
+
if has_more:
|
|
2759
|
+
more_count = len(lines) - max_lines
|
|
2760
|
+
print(f"{indent}{_GR}└─{_RS} {_GR}{_DM}… ({more_count} more lines){_RS}")
|
|
2761
|
+
|
|
2762
|
+
|
|
2776
2763
|
@agent_app.command("list")
|
|
2777
2764
|
@agent_app.command("ls", hidden=True)
|
|
2778
2765
|
@agent_app.command("ids", hidden=True)
|
|
@@ -2808,7 +2795,7 @@ def agent_list(raw: bool = typer.Option(False, "--json", help="Raw JSON output")
|
|
|
2808
2795
|
default_pid = next(reversed(list(agents.keys())))
|
|
2809
2796
|
|
|
2810
2797
|
_p()
|
|
2811
|
-
|
|
2798
|
+
_print_mcp_cloud_logo("Akash MCP Profiles & Agent IDs", f"{len(agents)} configured · Claude · Cursor · Codex")
|
|
2812
2799
|
print(f" {_GR}{'─'*76}{_RS}")
|
|
2813
2800
|
|
|
2814
2801
|
hdr_status = f"{'STATUS':<11}"
|
|
@@ -3345,7 +3332,8 @@ def agent_create(
|
|
|
3345
3332
|
gemini_mcp_url = f"{base}/mcp"
|
|
3346
3333
|
|
|
3347
3334
|
_p()
|
|
3348
|
-
|
|
3335
|
+
_print_mcp_cloud_logo("Akash MCP Profile Created", f"Credentials Issued for {_cy(name)}")
|
|
3336
|
+
print(" " + _GR + "──────────────────────────────────────────────────" + _RS)
|
|
3349
3337
|
print(f" {_DM}Profile ID :{_RS} {_C}{profile_id}{_RS}")
|
|
3350
3338
|
print(f" {_DM}Client ID :{_RS} {_ye(cid)}")
|
|
3351
3339
|
print(f" {_DM}Client Secret :{_RS} {_W}{csec}{_RS}")
|
|
@@ -3827,7 +3815,7 @@ def mcp_serve(
|
|
|
3827
3815
|
worker_ws_url = f"{ws_base}/api/agent/mcp/worker?client_id={cid}&client_secret={csec}&device_fp={dev_fp}"
|
|
3828
3816
|
|
|
3829
3817
|
_p()
|
|
3830
|
-
|
|
3818
|
+
_print_mcp_cloud_logo("Akash MCP Worker · Online", "Model Context Protocol Execution Host")
|
|
3831
3819
|
print(" " + _GR + "──────────────────────────────────────────────────" + _RS)
|
|
3832
3820
|
print(" " + _DM + "Workspace : " + _RS + _cy(str(Path.cwd())))
|
|
3833
3821
|
print(" " + _DM + "Gateway : " + _RS + _dim(base))
|
|
@@ -3914,7 +3902,8 @@ def mcp_serve(
|
|
|
3914
3902
|
|
|
3915
3903
|
is_safe, sec_reason = _sanitize_agent_command(cmd, scopes=cached.get("scopes", "*"))
|
|
3916
3904
|
if not is_safe:
|
|
3917
|
-
print(f"{ts_pfx} {_R}
|
|
3905
|
+
print(f"{ts_pfx} {_R}✗ Blocked:{_RS} {disp_cmd}")
|
|
3906
|
+
_print_cmd_tree_output(f"Security Policy Block: {sec_reason}")
|
|
3918
3907
|
ws.send(json.dumps({
|
|
3919
3908
|
"type": "tool_response",
|
|
3920
3909
|
"id": call_id,
|
|
@@ -3980,6 +3969,7 @@ def mcp_serve(
|
|
|
3980
3969
|
ec_color = _G if returncode == 0 else _R
|
|
3981
3970
|
ec_icon = f"{_G}✓{_RS}" if returncode == 0 else f"{_R}✗{_RS}"
|
|
3982
3971
|
print(f"{ts_pfx} {ec_icon} {ec_color}exec:{_RS} {disp_cmd} {ec_color}[{returncode}]{_RS} {_dim(f'{elapsed_ms:.1f}ms')}")
|
|
3972
|
+
_print_cmd_tree_output(raw_out)
|
|
3983
3973
|
|
|
3984
3974
|
if returncode != 0:
|
|
3985
3975
|
res_content = bounded_out or f"Command exited with status code {returncode} (no output)"
|
|
@@ -3998,6 +3988,7 @@ def mcp_serve(
|
|
|
3998
3988
|
ok, msg_txt = _restore_undo_checkpoint()
|
|
3999
3989
|
icon = f"{_G}✓{_RS}" if ok else f"{_R}✗{_RS}"
|
|
4000
3990
|
print(f"{ts_pfx} {icon} {(_G if ok else _R)}undo:{_RS} {_dim(msg_txt)}")
|
|
3991
|
+
_print_cmd_tree_output(msg_txt, max_lines=1)
|
|
4001
3992
|
ws.send(json.dumps({
|
|
4002
3993
|
"type": "tool_response",
|
|
4003
3994
|
"id": call_id,
|
|
@@ -4010,7 +4001,8 @@ def mcp_serve(
|
|
|
4010
4001
|
with _Spin(f"checkpoint: {label} (packing workspace)", min_seconds=0.25, prefix=ts_pfx):
|
|
4011
4002
|
_, manifest, _ = build_snapshot(label=label)
|
|
4012
4003
|
elapsed_ms = (time.monotonic() - t0) * 1000
|
|
4013
|
-
print(f"{ts_pfx} {_C}
|
|
4004
|
+
print(f"{ts_pfx} {_C}● checkpoint:{_RS} {_dim(label)} ({len(manifest.get('files', []))} files) {_dim(f'{elapsed_ms:.1f}ms')}")
|
|
4005
|
+
_print_cmd_tree_output(f"Checkpoint '{label}' created ({len(manifest.get('files', []))} files tracked)", max_lines=1)
|
|
4014
4006
|
ws.send(json.dumps({
|
|
4015
4007
|
"type": "tool_response",
|
|
4016
4008
|
"id": call_id,
|
|
@@ -4026,6 +4018,12 @@ def mcp_serve(
|
|
|
4026
4018
|
elapsed_ms = (time.monotonic() - t0) * 1000
|
|
4027
4019
|
icon = f"{_G}✓{_RS}" if not is_err else f"{_R}✗{_RS}"
|
|
4028
4020
|
print(f"{ts_pfx} {icon} {(_G if not is_err else _R)}read:{_RS} {disp_f} {_dim(f'{elapsed_ms:.1f}ms')}")
|
|
4021
|
+
if is_err:
|
|
4022
|
+
_print_cmd_tree_output(res_text, max_lines=2)
|
|
4023
|
+
else:
|
|
4024
|
+
char_count = len(res_text)
|
|
4025
|
+
line_count = len(res_text.splitlines())
|
|
4026
|
+
_print_cmd_tree_output(f"{char_count} bytes, {line_count} lines", max_lines=1)
|
|
4029
4027
|
ws.send(json.dumps({
|
|
4030
4028
|
"type": "tool_response",
|
|
4031
4029
|
"id": call_id,
|
|
@@ -4042,6 +4040,7 @@ def mcp_serve(
|
|
|
4042
4040
|
elapsed_ms = (time.monotonic() - t0) * 1000
|
|
4043
4041
|
icon = f"{_G}✓{_RS}" if not is_err else f"{_R}✗{_RS}"
|
|
4044
4042
|
print(f"{ts_pfx} {icon} {(_G if not is_err else _R)}write:{_RS} {disp_f} {_dim(f'{elapsed_ms:.1f}ms')}")
|
|
4043
|
+
_print_cmd_tree_output(res_text, max_lines=2)
|
|
4045
4044
|
ws.send(json.dumps({
|
|
4046
4045
|
"type": "tool_response",
|
|
4047
4046
|
"id": call_id,
|
|
@@ -4057,6 +4056,7 @@ def mcp_serve(
|
|
|
4057
4056
|
elapsed_ms = (time.monotonic() - t0) * 1000
|
|
4058
4057
|
icon = f"{_G}✓{_RS}" if not is_err else f"{_R}✗{_RS}"
|
|
4059
4058
|
print(f"{ts_pfx} {icon} {(_G if not is_err else _R)}list:{_RS} {disp_d} {_dim(f'{elapsed_ms:.1f}ms')}")
|
|
4059
|
+
_print_cmd_tree_output(res_text, max_lines=3)
|
|
4060
4060
|
ws.send(json.dumps({
|
|
4061
4061
|
"type": "tool_response",
|
|
4062
4062
|
"id": call_id,
|
|
@@ -4067,7 +4067,8 @@ def mcp_serve(
|
|
|
4067
4067
|
with _Spin("inspecting scopes…", min_seconds=0.15, prefix=ts_pfx):
|
|
4068
4068
|
res_text, is_err = _handle_tool_scope_details(cached.get("scopes", "*"), pname, profile_id)
|
|
4069
4069
|
elapsed_ms = (time.monotonic() - t0) * 1000
|
|
4070
|
-
print(f"{ts_pfx} {_C}
|
|
4070
|
+
print(f"{ts_pfx} {_C}● scopes:{_RS} {_dim(pname)} {_dim(f'{elapsed_ms:.1f}ms')}")
|
|
4071
|
+
_print_cmd_tree_output(cached.get("scopes", "*") or "@coder", max_lines=2)
|
|
4071
4072
|
ws.send(json.dumps({
|
|
4072
4073
|
"type": "tool_response",
|
|
4073
4074
|
"id": call_id,
|
|
@@ -4237,7 +4238,7 @@ def mcp_share(
|
|
|
4237
4238
|
mode_label = "Permanent Small & Secure"
|
|
4238
4239
|
|
|
4239
4240
|
_p()
|
|
4240
|
-
|
|
4241
|
+
_print_mcp_cloud_logo("Akash MCP · Quick Connect", "AI Assistant Setup (Cursor, Claude Desktop, Gemini)")
|
|
4241
4242
|
print(" " + _GR + "──────────────────────────────────────────────────" + _RS)
|
|
4242
4243
|
print(" " + _DM + "Agent : " + _RS + _ye(name) + " " + _dim("(" + pid + ")"))
|
|
4243
4244
|
print(" " + _DM + "Mode : " + _RS + _C + mode_label + _RS)
|
|
@@ -4272,10 +4273,11 @@ def mcp_share(
|
|
|
4272
4273
|
_p()
|
|
4273
4274
|
|
|
4274
4275
|
if show_all or claude:
|
|
4275
|
-
print(" " + _C + "For Claude Desktop
|
|
4276
|
+
print(" " + _C + "For Claude Desktop, Cursor & Cline" + _RS + " " + _dim("(config.json / settings.json)") + ":")
|
|
4276
4277
|
claude_cfg = json.dumps({"mcpServers": {"akash": {"url": local_url}}}, indent=2)
|
|
4277
4278
|
for c_line in claude_cfg.splitlines():
|
|
4278
4279
|
print(" " + c_line)
|
|
4280
|
+
print(" " + _DM + " Logo / Icon: Clean Cloud Icon delivered automatically via MCP handshake" + _RS)
|
|
4279
4281
|
print(" " + _GR + "──────────────────────────────────────────────────" + _RS)
|
|
4280
4282
|
_p()
|
|
4281
4283
|
|
|
@@ -4306,7 +4308,7 @@ def mcp_status(
|
|
|
4306
4308
|
_, base = _resolve_client(url or profile.get("url"), require_key=False, silent=True)
|
|
4307
4309
|
|
|
4308
4310
|
_p()
|
|
4309
|
-
|
|
4311
|
+
_print_mcp_cloud_logo("Akash MCP · Health Check", "Gateway & Tools Verification")
|
|
4310
4312
|
print(" " + _GR + "──────────────────────────────────────────────────" + _RS)
|
|
4311
4313
|
|
|
4312
4314
|
try:
|
|
@@ -20,7 +20,7 @@ class AkashClient:
|
|
|
20
20
|
_patch_dns(_up(self.base_url).hostname or "")
|
|
21
21
|
|
|
22
22
|
if not self.api_key:
|
|
23
|
-
raise AuthenticationError("
|
|
23
|
+
raise AuthenticationError("User is not logged in. An API key is required. Run 'akash login' or set AKASH_API_KEY env var.")
|
|
24
24
|
|
|
25
25
|
def _get_headers(self, custom: dict = None):
|
|
26
26
|
h = {"x-api-key": self.api_key, "Origin": "https://akash.cli"}
|
|
@@ -379,6 +379,10 @@ def upload_large_file(
|
|
|
379
379
|
progress_cb: Optional[Callable[[int, int], None]] = None,
|
|
380
380
|
) -> dict:
|
|
381
381
|
from .uploader import VaultUploader
|
|
382
|
+
from .exceptions import AuthenticationError
|
|
383
|
+
|
|
384
|
+
if not getattr(client, "api_key", None):
|
|
385
|
+
raise AuthenticationError("User is not logged in. An API key is required to upload files. Run 'akash login'.")
|
|
382
386
|
|
|
383
387
|
size = path.stat().st_size
|
|
384
388
|
digest = sha256_file(path)
|
|
@@ -6,7 +6,7 @@ from pathlib import Path
|
|
|
6
6
|
from typing import Optional, Callable, List
|
|
7
7
|
from concurrent.futures import ThreadPoolExecutor
|
|
8
8
|
from .models import UploadResult
|
|
9
|
-
from .exceptions import UploadFailed, QuotaExceeded
|
|
9
|
+
from .exceptions import UploadFailed, QuotaExceeded, AuthenticationError
|
|
10
10
|
|
|
11
11
|
class VaultUploader:
|
|
12
12
|
def __init__(self, client):
|
|
@@ -26,6 +26,11 @@ class VaultUploader:
|
|
|
26
26
|
Standardizes both File and Text uploads into a single stream.
|
|
27
27
|
progress_callback signature: (bytes_read, total_bytes)
|
|
28
28
|
"""
|
|
29
|
+
raise UploadFailed(
|
|
30
|
+
"Cloud storage & upload services have been discontinued due to lack of funding. "
|
|
31
|
+
"Please consider sponsoring the project to help bring back storage nodes: "
|
|
32
|
+
"https://github.com/juniorsir/akashcli#sponsorship"
|
|
33
|
+
)
|
|
29
34
|
|
|
30
35
|
# 1. Prepare Headers based on V3 Power-Control Specs
|
|
31
36
|
headers = {
|
|
@@ -220,6 +225,11 @@ class VaultUploader:
|
|
|
220
225
|
|
|
221
226
|
def upload_directory(self, folder_path: str, max_workers: int = 3) -> List[UploadResult]:
|
|
222
227
|
"""Recursively uploads all files in a folder using a thread pool."""
|
|
228
|
+
raise UploadFailed(
|
|
229
|
+
"Cloud storage & upload services have been discontinued due to lack of funding. "
|
|
230
|
+
"Please consider sponsoring the project to help bring back storage nodes: "
|
|
231
|
+
"https://github.com/juniorsir/akashcli#sponsorship"
|
|
232
|
+
)
|
|
223
233
|
# Convert string path to Path object
|
|
224
234
|
root = Path(folder_path)
|
|
225
235
|
if not root.is_dir():
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: akashcli
|
|
3
|
-
Version: 4.8.
|
|
3
|
+
Version: 4.8.6
|
|
4
4
|
Summary: Akash CLI — secure remote shell relay, file vault, and device management
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
Keywords: akash,cli,relay,remote-shell,vault
|
|
@@ -35,6 +35,7 @@ Requires-Dist: websockets
|
|
|
35
35
|
[Quickstart](#-quickstart-in-60-seconds) •
|
|
36
36
|
[Core Features](#-core-features) •
|
|
37
37
|
[Zero-Login Guest Mode](#-zero-login-guest-mode) •
|
|
38
|
+
[💖 Sponsoring](#-sponsorship--restoring-storage-services) •
|
|
38
39
|
[Documentation](#-in-depth-documentation-guides) •
|
|
39
40
|
[Command Matrix](#-command-matrix)
|
|
40
41
|
|
|
@@ -42,6 +43,14 @@ Requires-Dist: websockets
|
|
|
42
43
|
|
|
43
44
|
</div>
|
|
44
45
|
|
|
46
|
+
> [!WARNING]
|
|
47
|
+
> ### ⚠️ Cloud Storage & Upload Services Discontinued Due to Lack of Funding
|
|
48
|
+
> **Notice:** Public cloud file uploading and storage hosting services (`akash upload`, `akash cloud upload`, `akash cloud bulk`, `akash pipe`) have been **discontinued due to infrastructure hosting costs and lack of funding**.
|
|
49
|
+
>
|
|
50
|
+
> All terminal features (**remote shell relays, 1-click guest pairing, environment snapshots, local .env management, and AI MCP agent bridges**) remain **100% active and free**.
|
|
51
|
+
>
|
|
52
|
+
> 💖 **Help us bring back community storage infrastructure:** Please consider [Sponsoring the Project](#-sponsorship--restoring-storage-services) or running `akash sponsor`.
|
|
53
|
+
|
|
45
54
|
## 🌟 Why Akash CLI?
|
|
46
55
|
|
|
47
56
|
Modern developer workflows demand flexibility across multiple machines — laptops, cloud servers, and mobile environments like Android Termux. Akash CLI solves daily pain points with a unified, secure toolkit:
|
|
@@ -175,8 +184,16 @@ akash env push prod --burn
|
|
|
175
184
|
akash env pull eX481p prod
|
|
176
185
|
```
|
|
177
186
|
|
|
178
|
-
### 6.
|
|
187
|
+
### 6. AI Agent Gateway (MCP) & Guard Console
|
|
179
188
|
Supercharge Cursor and Claude Desktop with local terminal execution, protected by real-time human approval:
|
|
189
|
+
|
|
190
|
+
```
|
|
191
|
+
╭─────╮
|
|
192
|
+
╭──╯ ╰──╮ AKASH MCP
|
|
193
|
+
( M C P ) Model Context Protocol · Claude · Cursor · Codex
|
|
194
|
+
╰───────────╯
|
|
195
|
+
```
|
|
196
|
+
|
|
180
197
|
```bash
|
|
181
198
|
# 1. Create agent profile with safe role preset:
|
|
182
199
|
akash agent create --name "Cursor" --role @coder
|
|
@@ -215,6 +232,7 @@ Explore comprehensive guides in the [`docs/`](docs/) directory:
|
|
|
215
232
|
|
|
216
233
|
```text
|
|
217
234
|
akash
|
|
235
|
+
├── sponsor 💖 Information on sponsoring & bringing back storage nodes
|
|
218
236
|
├── login Connect API key with hardware binding
|
|
219
237
|
├── whoami Account quota & device fingerprint
|
|
220
238
|
├── backup Save terminal environment to cloud or local archive
|
|
@@ -225,12 +243,12 @@ akash
|
|
|
225
243
|
├── serve Make device reachable (--daemon, --share for guest mode)
|
|
226
244
|
├── devices List, authorize, or revoke enrolled machines
|
|
227
245
|
├── cloud
|
|
228
|
-
│ ├── upload Upload file
|
|
246
|
+
│ ├── upload [DISCONTINUED] Upload file (run 'akash sponsor' for details)
|
|
229
247
|
│ ├── files List vault files
|
|
230
248
|
│ ├── stream Direct streaming link or launch in VLC
|
|
231
|
-
│ ├── bulk Recursively upload directory
|
|
249
|
+
│ ├── bulk [DISCONTINUED] Recursively upload directory
|
|
232
250
|
│ └── delete Purge file permanently
|
|
233
|
-
├── pipe Upload stdin
|
|
251
|
+
├── pipe [DISCONTINUED] Upload stdin directly to cloud
|
|
234
252
|
├── send End-to-end encrypted P2P transfer to user public key
|
|
235
253
|
├── inbox Receive and decrypt incoming P2P files
|
|
236
254
|
├── id View or export P2P identity key and manage contacts
|
|
@@ -267,6 +285,24 @@ Akash CLI enforces security at every layer:
|
|
|
267
285
|
|
|
268
286
|
---
|
|
269
287
|
|
|
288
|
+
## 💖 Sponsorship & Restoring Storage Services
|
|
289
|
+
|
|
290
|
+
Akash CLI is an independent, community-driven open-source project. We previously provided free, high-speed public file uploading, sharing, and native media streaming. However, due to mounting NVMe cloud server expenses, bandwidth costs, and **a lack of operational funding**, public storage and uploading services had to be discontinued.
|
|
291
|
+
|
|
292
|
+
### How Your Sponsorship Helps
|
|
293
|
+
Your financial contribution directly funds:
|
|
294
|
+
* 💽 **Dedicated NVMe Storage Nodes**: Restoring community cloud vault storage for backups and files.
|
|
295
|
+
* 🌐 **High-Bandwidth Network Transit**: Low-latency global relay clusters for terminal sessions and fast file retrieval.
|
|
296
|
+
* 🛡️ **Long-Term Open Source Maintenance**: Ongoing development for Termux, Linux, macOS, and Windows.
|
|
297
|
+
|
|
298
|
+
### Ways to Sponsor & Donate
|
|
299
|
+
* **GitHub Sponsors**: [https://github.com/sponsors/juniorsir](https://github.com/sponsors/juniorsir)
|
|
300
|
+
* **Telegram Channel / Support**: [@EveryDL_bot](https://t.me/EveryDL_bot)
|
|
301
|
+
* **Direct / UPI / Crypto Support**: Reach out to maintainers via Telegram ([@EveryDL_bot](https://t.me/EveryDL_bot))
|
|
302
|
+
* **Console Command**: Run `akash sponsor` directly from your terminal to view sponsorship details.
|
|
303
|
+
|
|
304
|
+
---
|
|
305
|
+
|
|
270
306
|
## 📄 License
|
|
271
307
|
|
|
272
308
|
Distributed under the MIT License. See [LICENSE](LICENSE) for details.
|
|
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
|