@magpiecloud/mags 1.8.13 → 1.8.14
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.
- package/bin/mags.js +196 -104
- package/index.js +6 -52
- package/nodejs/index.js +6 -52
- package/package.json +4 -1
- package/python/dist/{magpie_mags-1.3.5-py3-none-any.whl → magpie_mags-1.3.6-py3-none-any.whl} +0 -0
- package/python/dist/magpie_mags-1.3.6.tar.gz +0 -0
- package/python/pyproject.toml +1 -1
- package/python/src/magpie_mags.egg-info/PKG-INFO +7 -3
- package/python/src/mags/client.py +12 -62
- package/website/api.html +6 -6
- package/website/claude-skill.html +2 -2
- package/website/cookbook/hn-marketing.html +1 -1
- package/website/cookbook.html +3 -3
- package/website/docs.html +677 -0
- package/website/index.html +3 -3
- package/website/login.html +2 -2
- package/website/styles.css +206 -39
- package/website/tokens.html +1 -1
- package/website/usage.html +1 -1
- package/python/dist/magpie_mags-1.3.5.tar.gz +0 -0
|
@@ -3,8 +3,6 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import os
|
|
6
|
-
import subprocess
|
|
7
|
-
import tempfile
|
|
8
6
|
import time
|
|
9
7
|
from pathlib import Path
|
|
10
8
|
from typing import Any, Dict, List, Optional
|
|
@@ -355,11 +353,11 @@ class Mags:
|
|
|
355
353
|
return resp
|
|
356
354
|
|
|
357
355
|
def exec(self, name_or_id: str, command: str, *, timeout: int = 30) -> dict:
|
|
358
|
-
"""Execute a command on an existing running/sleeping sandbox
|
|
356
|
+
"""Execute a command on an existing running/sleeping sandbox.
|
|
359
357
|
|
|
360
358
|
Equivalent to ``mags exec <workspace> '<command>'``.
|
|
361
359
|
|
|
362
|
-
Returns ``{"exit_code": int, "output": str}``.
|
|
360
|
+
Returns ``{"exit_code": int, "output": str, "stderr": str}``.
|
|
363
361
|
"""
|
|
364
362
|
job = self.find_job(name_or_id)
|
|
365
363
|
if not job:
|
|
@@ -370,65 +368,17 @@ class Mags:
|
|
|
370
368
|
)
|
|
371
369
|
|
|
372
370
|
request_id = job.get("request_id") or job.get("id")
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
raise MagsError(
|
|
379
|
-
f"Failed to enable SSH access: {access.get('error', 'unknown error')}"
|
|
380
|
-
)
|
|
381
|
-
|
|
382
|
-
ssh_host = access["ssh_host"]
|
|
383
|
-
ssh_port = str(access["ssh_port"])
|
|
384
|
-
ssh_key = access.get("ssh_private_key", "")
|
|
385
|
-
|
|
386
|
-
# Wrap command to handle chroot overlay, same as CLI
|
|
387
|
-
escaped = command.replace("'", "'\\''")
|
|
388
|
-
wrapped = (
|
|
389
|
-
f"if [ -d /overlay/bin ]; then "
|
|
390
|
-
f"chroot /overlay /bin/sh -l -c 'cd /root 2>/dev/null; {escaped}'; "
|
|
391
|
-
f"else cd /root 2>/dev/null; {escaped}; fi"
|
|
371
|
+
resp = self._request(
|
|
372
|
+
"POST",
|
|
373
|
+
f"/mags-jobs/{request_id}/exec",
|
|
374
|
+
json={"command": command, "timeout": timeout},
|
|
375
|
+
timeout=timeout + 10, # HTTP timeout > command timeout
|
|
392
376
|
)
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
"-o", "StrictHostKeyChecking=no",
|
|
399
|
-
"-o", "UserKnownHostsFile=/dev/null",
|
|
400
|
-
"-o", "LogLevel=ERROR",
|
|
401
|
-
"-p", ssh_port,
|
|
402
|
-
]
|
|
403
|
-
if ssh_key:
|
|
404
|
-
fd, key_file = tempfile.mkstemp(prefix="mags_ssh_")
|
|
405
|
-
os.write(fd, ssh_key.encode())
|
|
406
|
-
os.close(fd)
|
|
407
|
-
os.chmod(key_file, 0o600)
|
|
408
|
-
ssh_args.extend(["-i", key_file])
|
|
409
|
-
|
|
410
|
-
ssh_args.append(f"root@{ssh_host}")
|
|
411
|
-
ssh_args.append(wrapped)
|
|
412
|
-
|
|
413
|
-
proc = subprocess.run(
|
|
414
|
-
ssh_args,
|
|
415
|
-
capture_output=True,
|
|
416
|
-
text=True,
|
|
417
|
-
timeout=timeout,
|
|
418
|
-
)
|
|
419
|
-
return {
|
|
420
|
-
"exit_code": proc.returncode,
|
|
421
|
-
"output": proc.stdout,
|
|
422
|
-
"stderr": proc.stderr,
|
|
423
|
-
}
|
|
424
|
-
except subprocess.TimeoutExpired:
|
|
425
|
-
raise MagsError(f"Command timed out after {timeout}s")
|
|
426
|
-
finally:
|
|
427
|
-
if key_file:
|
|
428
|
-
try:
|
|
429
|
-
os.unlink(key_file)
|
|
430
|
-
except OSError:
|
|
431
|
-
pass
|
|
377
|
+
return {
|
|
378
|
+
"exit_code": resp.get("exit_code", -1),
|
|
379
|
+
"output": resp.get("stdout", ""),
|
|
380
|
+
"stderr": resp.get("stderr", ""),
|
|
381
|
+
}
|
|
432
382
|
|
|
433
383
|
def usage(self, *, window_days: int = 30) -> dict:
|
|
434
384
|
"""Get aggregated usage summary."""
|
package/website/api.html
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
/>
|
|
11
11
|
<meta name="api-base" content="https://api.magpiecloud.com" />
|
|
12
12
|
<meta name="auth-base" content="https://api.magpiecloud.com" />
|
|
13
|
-
<link rel="stylesheet" href="styles.css?v=
|
|
13
|
+
<link rel="stylesheet" href="styles.css?v=8" />
|
|
14
14
|
<script src="env.js"></script>
|
|
15
15
|
<style>
|
|
16
16
|
.endpoint { margin-bottom: 2.5rem; }
|
|
@@ -30,10 +30,10 @@
|
|
|
30
30
|
font-weight: 600;
|
|
31
31
|
text-transform: uppercase;
|
|
32
32
|
}
|
|
33
|
-
.method.post { background: rgba(47,
|
|
34
|
-
.method.get { background: rgba(59, 130, 246, 0.
|
|
35
|
-
.method.patch { background: rgba(245, 158, 11, 0.
|
|
36
|
-
.method.delete { background: rgba(239, 68, 68, 0.
|
|
33
|
+
.method.post { background: rgba(47, 155, 102, 0.2); color: #3dbd7e; }
|
|
34
|
+
.method.get { background: rgba(59, 130, 246, 0.2); color: #60a5fa; }
|
|
35
|
+
.method.patch { background: rgba(245, 158, 11, 0.2); color: #fbbf24; }
|
|
36
|
+
.method.delete { background: rgba(239, 68, 68, 0.2); color: #f87171; }
|
|
37
37
|
.url-path {
|
|
38
38
|
font-family: var(--mono);
|
|
39
39
|
font-size: 0.95rem;
|
|
@@ -109,7 +109,7 @@
|
|
|
109
109
|
</div>
|
|
110
110
|
<nav class="nav-links">
|
|
111
111
|
<a href="index.html">Home</a>
|
|
112
|
-
<a href="
|
|
112
|
+
<a href="docs.html">Docs</a>
|
|
113
113
|
<a href="cookbook.html">Cookbook</a>
|
|
114
114
|
<a href="claude-skill.html">Claude Skill</a>
|
|
115
115
|
<a href="https://discord.gg/3avpC2nS" target="_blank" rel="noreferrer">Discord</a>
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
/>
|
|
11
11
|
<meta name="api-base" content="https://api.magpiecloud.com" />
|
|
12
12
|
<meta name="auth-base" content="https://api.magpiecloud.com" />
|
|
13
|
-
<link rel="stylesheet" href="styles.css?v=
|
|
13
|
+
<link rel="stylesheet" href="styles.css?v=8" />
|
|
14
14
|
<script src="env.js"></script>
|
|
15
15
|
</head>
|
|
16
16
|
<body>
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
</div>
|
|
25
25
|
<nav class="nav-links">
|
|
26
26
|
<a href="index.html">Home</a>
|
|
27
|
-
<a href="
|
|
27
|
+
<a href="docs.html">Docs</a>
|
|
28
28
|
<a href="api.html">API</a>
|
|
29
29
|
<a href="cookbook.html">Cookbook</a>
|
|
30
30
|
<a href="https://discord.gg/3avpC2nS" target="_blank" rel="noreferrer">Discord</a>
|
package/website/cookbook.html
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
/>
|
|
11
11
|
<meta name="api-base" content="https://api.magpiecloud.com" />
|
|
12
12
|
<meta name="auth-base" content="https://api.magpiecloud.com" />
|
|
13
|
-
<link rel="stylesheet" href="styles.css?v=
|
|
13
|
+
<link rel="stylesheet" href="styles.css?v=8" />
|
|
14
14
|
<script src="env.js"></script>
|
|
15
15
|
</head>
|
|
16
16
|
<body>
|
|
@@ -24,14 +24,14 @@
|
|
|
24
24
|
</div>
|
|
25
25
|
<nav class="nav-links">
|
|
26
26
|
<a href="index.html">Home</a>
|
|
27
|
-
<a href="
|
|
27
|
+
<a href="docs.html">Docs</a>
|
|
28
28
|
<a href="api.html">API</a>
|
|
29
29
|
<a href="claude-skill.html">Claude Skill</a>
|
|
30
30
|
<a href="https://discord.gg/3avpC2nS" target="_blank" rel="noreferrer">Discord</a>
|
|
31
31
|
<a href="login.html">Login</a>
|
|
32
32
|
</nav>
|
|
33
33
|
<div class="nav-cta">
|
|
34
|
-
<a class="button ghost" href="
|
|
34
|
+
<a class="button ghost" href="docs.html#quickstart">Get started</a>
|
|
35
35
|
</div>
|
|
36
36
|
</div>
|
|
37
37
|
</header>
|