@magpiecloud/mags 1.8.13 → 1.8.15
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/README.md +95 -378
- package/bin/mags.js +196 -104
- package/index.js +6 -52
- package/package.json +22 -4
- package/API.md +0 -388
- package/Mags-API.postman_collection.json +0 -374
- package/QUICKSTART.md +0 -295
- package/deploy-page.sh +0 -171
- package/mags +0 -0
- package/mags.sh +0 -270
- package/nodejs/README.md +0 -197
- package/nodejs/bin/mags.js +0 -1146
- package/nodejs/index.js +0 -642
- package/nodejs/package.json +0 -42
- package/python/INTEGRATION.md +0 -800
- package/python/README.md +0 -161
- package/python/dist/magpie_mags-1.3.5-py3-none-any.whl +0 -0
- package/python/dist/magpie_mags-1.3.5.tar.gz +0 -0
- package/python/examples/demo.py +0 -181
- package/python/pyproject.toml +0 -39
- package/python/src/magpie_mags.egg-info/PKG-INFO +0 -182
- package/python/src/magpie_mags.egg-info/SOURCES.txt +0 -9
- package/python/src/magpie_mags.egg-info/dependency_links.txt +0 -1
- package/python/src/magpie_mags.egg-info/requires.txt +0 -1
- package/python/src/magpie_mags.egg-info/top_level.txt +0 -1
- package/python/src/mags/__init__.py +0 -6
- package/python/src/mags/client.py +0 -573
- package/python/test_sdk.py +0 -78
- package/skill.md +0 -153
- package/website/api.html +0 -1095
- package/website/claude-skill.html +0 -481
- package/website/cookbook/hn-marketing.html +0 -410
- package/website/cookbook/hn-marketing.sh +0 -42
- package/website/cookbook.html +0 -282
- package/website/env.js +0 -4
- package/website/index.html +0 -801
- package/website/llms.txt +0 -334
- package/website/login.html +0 -108
- package/website/mags.md +0 -210
- package/website/script.js +0 -453
- package/website/styles.css +0 -908
- package/website/tokens.html +0 -169
- package/website/usage.html +0 -185
|
@@ -1,374 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"info": {
|
|
3
|
-
"_postman_id": "mags-api-collection",
|
|
4
|
-
"name": "Mags API",
|
|
5
|
-
"description": "Magpie's instant VM execution API. Execute scripts on microVMs with <100ms warm start times.",
|
|
6
|
-
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
|
|
7
|
-
},
|
|
8
|
-
"auth": {
|
|
9
|
-
"type": "bearer",
|
|
10
|
-
"bearer": [
|
|
11
|
-
{
|
|
12
|
-
"key": "token",
|
|
13
|
-
"value": "{{MAGS_API_TOKEN}}",
|
|
14
|
-
"type": "string"
|
|
15
|
-
}
|
|
16
|
-
]
|
|
17
|
-
},
|
|
18
|
-
"variable": [
|
|
19
|
-
{
|
|
20
|
-
"key": "BASE_URL",
|
|
21
|
-
"value": "https://api.magpiecloud.com",
|
|
22
|
-
"type": "string"
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
"key": "MAGS_API_TOKEN",
|
|
26
|
-
"value": "e1e90cc27dfe6a50cc28699cdcb937ef8c443567b62cf064a063f9b34af0b91b",
|
|
27
|
-
"type": "string"
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
"key": "REQUEST_ID",
|
|
31
|
-
"value": "",
|
|
32
|
-
"type": "string"
|
|
33
|
-
}
|
|
34
|
-
],
|
|
35
|
-
"item": [
|
|
36
|
-
{
|
|
37
|
-
"name": "Jobs",
|
|
38
|
-
"item": [
|
|
39
|
-
{
|
|
40
|
-
"name": "Submit Job",
|
|
41
|
-
"event": [
|
|
42
|
-
{
|
|
43
|
-
"listen": "test",
|
|
44
|
-
"script": {
|
|
45
|
-
"exec": [
|
|
46
|
-
"var jsonData = pm.response.json();",
|
|
47
|
-
"if (jsonData.request_id) {",
|
|
48
|
-
" pm.collectionVariables.set('REQUEST_ID', jsonData.request_id);",
|
|
49
|
-
" console.log('Saved REQUEST_ID:', jsonData.request_id);",
|
|
50
|
-
"}",
|
|
51
|
-
"",
|
|
52
|
-
"pm.test('Job submitted successfully', function () {",
|
|
53
|
-
" pm.response.to.have.status(202);",
|
|
54
|
-
" pm.expect(jsonData.status).to.eql('accepted');",
|
|
55
|
-
"});"
|
|
56
|
-
],
|
|
57
|
-
"type": "text/javascript"
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
],
|
|
61
|
-
"request": {
|
|
62
|
-
"method": "POST",
|
|
63
|
-
"header": [
|
|
64
|
-
{
|
|
65
|
-
"key": "Content-Type",
|
|
66
|
-
"value": "application/json"
|
|
67
|
-
}
|
|
68
|
-
],
|
|
69
|
-
"body": {
|
|
70
|
-
"mode": "raw",
|
|
71
|
-
"raw": "{\n \"script\": \"echo 'Hello from Mags!'\\necho 'Current time:' $(date)\\necho 'Hostname:' $(hostname)\",\n \"type\": \"inline\",\n \"name\": \"hello-world\"\n}"
|
|
72
|
-
},
|
|
73
|
-
"url": {
|
|
74
|
-
"raw": "{{BASE_URL}}/api/v1/mags-jobs",
|
|
75
|
-
"host": ["{{BASE_URL}}"],
|
|
76
|
-
"path": ["api", "v1", "mags-jobs"]
|
|
77
|
-
},
|
|
78
|
-
"description": "Submit a new mags job for execution."
|
|
79
|
-
},
|
|
80
|
-
"response": []
|
|
81
|
-
},
|
|
82
|
-
{
|
|
83
|
-
"name": "Submit Job with Environment",
|
|
84
|
-
"event": [
|
|
85
|
-
{
|
|
86
|
-
"listen": "test",
|
|
87
|
-
"script": {
|
|
88
|
-
"exec": [
|
|
89
|
-
"var jsonData = pm.response.json();",
|
|
90
|
-
"if (jsonData.request_id) {",
|
|
91
|
-
" pm.collectionVariables.set('REQUEST_ID', jsonData.request_id);",
|
|
92
|
-
"}",
|
|
93
|
-
"",
|
|
94
|
-
"pm.test('Job submitted successfully', function () {",
|
|
95
|
-
" pm.response.to.have.status(202);",
|
|
96
|
-
"});"
|
|
97
|
-
],
|
|
98
|
-
"type": "text/javascript"
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
],
|
|
102
|
-
"request": {
|
|
103
|
-
"method": "POST",
|
|
104
|
-
"header": [
|
|
105
|
-
{
|
|
106
|
-
"key": "Content-Type",
|
|
107
|
-
"value": "application/json"
|
|
108
|
-
}
|
|
109
|
-
],
|
|
110
|
-
"body": {
|
|
111
|
-
"mode": "raw",
|
|
112
|
-
"raw": "{\n \"script\": \"echo \\\"MY_VAR = $MY_VAR\\\"\\necho \\\"GREETING = $GREETING\\\"\",\n \"type\": \"inline\",\n \"name\": \"env-vars-test\",\n \"environment\": {\n \"MY_VAR\": \"hello-mags\",\n \"GREETING\": \"Welcome to fast execution!\"\n }\n}"
|
|
113
|
-
},
|
|
114
|
-
"url": {
|
|
115
|
-
"raw": "{{BASE_URL}}/api/v1/mags-jobs",
|
|
116
|
-
"host": ["{{BASE_URL}}"],
|
|
117
|
-
"path": ["api", "v1", "mags-jobs"]
|
|
118
|
-
},
|
|
119
|
-
"description": "Submit a job with custom environment variables."
|
|
120
|
-
},
|
|
121
|
-
"response": []
|
|
122
|
-
},
|
|
123
|
-
{
|
|
124
|
-
"name": "Submit Persistent Job (Web Server)",
|
|
125
|
-
"event": [
|
|
126
|
-
{
|
|
127
|
-
"listen": "test",
|
|
128
|
-
"script": {
|
|
129
|
-
"exec": [
|
|
130
|
-
"var jsonData = pm.response.json();",
|
|
131
|
-
"if (jsonData.request_id) {",
|
|
132
|
-
" pm.collectionVariables.set('REQUEST_ID', jsonData.request_id);",
|
|
133
|
-
"}",
|
|
134
|
-
"",
|
|
135
|
-
"pm.test('Persistent job submitted', function () {",
|
|
136
|
-
" pm.response.to.have.status(202);",
|
|
137
|
-
"});"
|
|
138
|
-
],
|
|
139
|
-
"type": "text/javascript"
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
],
|
|
143
|
-
"request": {
|
|
144
|
-
"method": "POST",
|
|
145
|
-
"header": [
|
|
146
|
-
{
|
|
147
|
-
"key": "Content-Type",
|
|
148
|
-
"value": "application/json"
|
|
149
|
-
}
|
|
150
|
-
],
|
|
151
|
-
"body": {
|
|
152
|
-
"mode": "raw",
|
|
153
|
-
"raw": "{\n \"script\": \"cd /tmp && echo '<h1>Hello from Mags!</h1>' > index.html && python3 -m http.server 8080\",\n \"type\": \"inline\",\n \"name\": \"web-server\",\n \"persistent\": true\n}"
|
|
154
|
-
},
|
|
155
|
-
"url": {
|
|
156
|
-
"raw": "{{BASE_URL}}/api/v1/mags-jobs",
|
|
157
|
-
"host": ["{{BASE_URL}}"],
|
|
158
|
-
"path": ["api", "v1", "mags-jobs"]
|
|
159
|
-
},
|
|
160
|
-
"description": "Submit a persistent job that keeps the VM alive. Returns a URL for web access."
|
|
161
|
-
},
|
|
162
|
-
"response": []
|
|
163
|
-
},
|
|
164
|
-
{
|
|
165
|
-
"name": "Get Job Status",
|
|
166
|
-
"event": [
|
|
167
|
-
{
|
|
168
|
-
"listen": "test",
|
|
169
|
-
"script": {
|
|
170
|
-
"exec": [
|
|
171
|
-
"pm.test('Status retrieved', function () {",
|
|
172
|
-
" pm.response.to.have.status(200);",
|
|
173
|
-
" var jsonData = pm.response.json();",
|
|
174
|
-
" pm.expect(jsonData.request_id).to.exist;",
|
|
175
|
-
" pm.expect(jsonData.status).to.be.oneOf(['pending', 'running', 'sleeping', 'completed', 'error']);",
|
|
176
|
-
"});"
|
|
177
|
-
],
|
|
178
|
-
"type": "text/javascript"
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
],
|
|
182
|
-
"request": {
|
|
183
|
-
"method": "GET",
|
|
184
|
-
"header": [],
|
|
185
|
-
"url": {
|
|
186
|
-
"raw": "{{BASE_URL}}/api/v1/mags-jobs/{{REQUEST_ID}}/status",
|
|
187
|
-
"host": ["{{BASE_URL}}"],
|
|
188
|
-
"path": ["api", "v1", "mags-jobs", "{{REQUEST_ID}}", "status"]
|
|
189
|
-
},
|
|
190
|
-
"description": "Get the current status of a mags job."
|
|
191
|
-
},
|
|
192
|
-
"response": []
|
|
193
|
-
},
|
|
194
|
-
{
|
|
195
|
-
"name": "Get Job Logs",
|
|
196
|
-
"event": [
|
|
197
|
-
{
|
|
198
|
-
"listen": "test",
|
|
199
|
-
"script": {
|
|
200
|
-
"exec": [
|
|
201
|
-
"pm.test('Logs retrieved', function () {",
|
|
202
|
-
" pm.response.to.have.status(200);",
|
|
203
|
-
" var jsonData = pm.response.json();",
|
|
204
|
-
" pm.expect(jsonData.logs).to.be.an('array');",
|
|
205
|
-
"});"
|
|
206
|
-
],
|
|
207
|
-
"type": "text/javascript"
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
],
|
|
211
|
-
"request": {
|
|
212
|
-
"method": "GET",
|
|
213
|
-
"header": [],
|
|
214
|
-
"url": {
|
|
215
|
-
"raw": "{{BASE_URL}}/api/v1/mags-jobs/{{REQUEST_ID}}/logs",
|
|
216
|
-
"host": ["{{BASE_URL}}"],
|
|
217
|
-
"path": ["api", "v1", "mags-jobs", "{{REQUEST_ID}}", "logs"]
|
|
218
|
-
},
|
|
219
|
-
"description": "Get logs from a mags job execution."
|
|
220
|
-
},
|
|
221
|
-
"response": []
|
|
222
|
-
},
|
|
223
|
-
{
|
|
224
|
-
"name": "List Jobs",
|
|
225
|
-
"event": [
|
|
226
|
-
{
|
|
227
|
-
"listen": "test",
|
|
228
|
-
"script": {
|
|
229
|
-
"exec": [
|
|
230
|
-
"pm.test('Jobs listed', function () {",
|
|
231
|
-
" pm.response.to.have.status(200);",
|
|
232
|
-
" var jsonData = pm.response.json();",
|
|
233
|
-
" pm.expect(jsonData.jobs).to.be.an('array');",
|
|
234
|
-
" pm.expect(jsonData.total).to.be.a('number');",
|
|
235
|
-
"});"
|
|
236
|
-
],
|
|
237
|
-
"type": "text/javascript"
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
],
|
|
241
|
-
"request": {
|
|
242
|
-
"method": "GET",
|
|
243
|
-
"header": [],
|
|
244
|
-
"url": {
|
|
245
|
-
"raw": "{{BASE_URL}}/api/v1/mags-jobs?page=1&page_size=10",
|
|
246
|
-
"host": ["{{BASE_URL}}"],
|
|
247
|
-
"path": ["api", "v1", "mags-jobs"],
|
|
248
|
-
"query": [
|
|
249
|
-
{
|
|
250
|
-
"key": "page",
|
|
251
|
-
"value": "1"
|
|
252
|
-
},
|
|
253
|
-
{
|
|
254
|
-
"key": "page_size",
|
|
255
|
-
"value": "10"
|
|
256
|
-
}
|
|
257
|
-
]
|
|
258
|
-
},
|
|
259
|
-
"description": "List mags jobs with pagination."
|
|
260
|
-
},
|
|
261
|
-
"response": []
|
|
262
|
-
},
|
|
263
|
-
{
|
|
264
|
-
"name": "Update Job",
|
|
265
|
-
"request": {
|
|
266
|
-
"method": "PATCH",
|
|
267
|
-
"header": [
|
|
268
|
-
{
|
|
269
|
-
"key": "Content-Type",
|
|
270
|
-
"value": "application/json"
|
|
271
|
-
}
|
|
272
|
-
],
|
|
273
|
-
"body": {
|
|
274
|
-
"mode": "raw",
|
|
275
|
-
"raw": "{\n \"name\": \"updated-job-name\"\n}"
|
|
276
|
-
},
|
|
277
|
-
"url": {
|
|
278
|
-
"raw": "{{BASE_URL}}/api/v1/mags-jobs/{{REQUEST_ID}}",
|
|
279
|
-
"host": ["{{BASE_URL}}"],
|
|
280
|
-
"path": ["api", "v1", "mags-jobs", "{{REQUEST_ID}}"]
|
|
281
|
-
},
|
|
282
|
-
"description": "Update a mags job's properties."
|
|
283
|
-
},
|
|
284
|
-
"response": []
|
|
285
|
-
}
|
|
286
|
-
]
|
|
287
|
-
},
|
|
288
|
-
{
|
|
289
|
-
"name": "Access",
|
|
290
|
-
"item": [
|
|
291
|
-
{
|
|
292
|
-
"name": "Enable SSH Access",
|
|
293
|
-
"request": {
|
|
294
|
-
"method": "POST",
|
|
295
|
-
"header": [
|
|
296
|
-
{
|
|
297
|
-
"key": "Content-Type",
|
|
298
|
-
"value": "application/json"
|
|
299
|
-
}
|
|
300
|
-
],
|
|
301
|
-
"body": {
|
|
302
|
-
"mode": "raw",
|
|
303
|
-
"raw": "{\n \"access_type\": \"ssh\"\n}"
|
|
304
|
-
},
|
|
305
|
-
"url": {
|
|
306
|
-
"raw": "{{BASE_URL}}/api/v1/mags-jobs/{{REQUEST_ID}}/access",
|
|
307
|
-
"host": ["{{BASE_URL}}"],
|
|
308
|
-
"path": ["api", "v1", "mags-jobs", "{{REQUEST_ID}}", "access"]
|
|
309
|
-
},
|
|
310
|
-
"description": "Enable SSH proxy access to a running mags VM."
|
|
311
|
-
},
|
|
312
|
-
"response": []
|
|
313
|
-
},
|
|
314
|
-
{
|
|
315
|
-
"name": "Enable URL Access",
|
|
316
|
-
"request": {
|
|
317
|
-
"method": "POST",
|
|
318
|
-
"header": [
|
|
319
|
-
{
|
|
320
|
-
"key": "Content-Type",
|
|
321
|
-
"value": "application/json"
|
|
322
|
-
}
|
|
323
|
-
],
|
|
324
|
-
"body": {
|
|
325
|
-
"mode": "raw",
|
|
326
|
-
"raw": "{\n \"access_type\": \"url\",\n \"port\": 8080\n}"
|
|
327
|
-
},
|
|
328
|
-
"url": {
|
|
329
|
-
"raw": "{{BASE_URL}}/api/v1/mags-jobs/{{REQUEST_ID}}/access",
|
|
330
|
-
"host": ["{{BASE_URL}}"],
|
|
331
|
-
"path": ["api", "v1", "mags-jobs", "{{REQUEST_ID}}", "access"]
|
|
332
|
-
},
|
|
333
|
-
"description": "Enable URL access to a running mags VM on a specific port."
|
|
334
|
-
},
|
|
335
|
-
"response": []
|
|
336
|
-
}
|
|
337
|
-
]
|
|
338
|
-
},
|
|
339
|
-
{
|
|
340
|
-
"name": "Health",
|
|
341
|
-
"item": [
|
|
342
|
-
{
|
|
343
|
-
"name": "Health Check",
|
|
344
|
-
"event": [
|
|
345
|
-
{
|
|
346
|
-
"listen": "test",
|
|
347
|
-
"script": {
|
|
348
|
-
"exec": [
|
|
349
|
-
"pm.test('API is healthy', function () {",
|
|
350
|
-
" pm.response.to.have.status(200);",
|
|
351
|
-
" var jsonData = pm.response.json();",
|
|
352
|
-
" pm.expect(jsonData.status).to.eql('ok');",
|
|
353
|
-
"});"
|
|
354
|
-
],
|
|
355
|
-
"type": "text/javascript"
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
],
|
|
359
|
-
"request": {
|
|
360
|
-
"method": "GET",
|
|
361
|
-
"header": [],
|
|
362
|
-
"url": {
|
|
363
|
-
"raw": "{{BASE_URL}}/api/v1/health",
|
|
364
|
-
"host": ["{{BASE_URL}}"],
|
|
365
|
-
"path": ["api", "v1", "health"]
|
|
366
|
-
},
|
|
367
|
-
"description": "Check API health status."
|
|
368
|
-
},
|
|
369
|
-
"response": []
|
|
370
|
-
}
|
|
371
|
-
]
|
|
372
|
-
}
|
|
373
|
-
]
|
|
374
|
-
}
|
package/QUICKSTART.md
DELETED
|
@@ -1,295 +0,0 @@
|
|
|
1
|
-
# Mags Quickstart Guide
|
|
2
|
-
|
|
3
|
-
Mags lets you run code in ephemeral VMs with persistent filesystems. Your files, packages, and configs persist across runs - but processes don't.
|
|
4
|
-
|
|
5
|
-
## Getting Access
|
|
6
|
-
|
|
7
|
-
### 1. Get an API Token
|
|
8
|
-
|
|
9
|
-
Contact your admin or generate a token from the Magpie dashboard:
|
|
10
|
-
```
|
|
11
|
-
https://magpiecloud.com/dashboard/tokens
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
### 2. Set Environment Variable
|
|
15
|
-
|
|
16
|
-
```bash
|
|
17
|
-
export MAGS_API_TOKEN="your-api-token-here"
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
Add to your shell profile (`~/.bashrc`, `~/.zshrc`) to persist:
|
|
21
|
-
```bash
|
|
22
|
-
echo 'export MAGS_API_TOKEN="your-api-token-here"' >> ~/.zshrc
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
## Installing the CLI
|
|
26
|
-
|
|
27
|
-
### Option 1: Download Binary
|
|
28
|
-
|
|
29
|
-
```bash
|
|
30
|
-
# macOS (Apple Silicon)
|
|
31
|
-
curl -L https://releases.magpiecloud.com/mags/latest/mags-darwin-arm64 -o mags
|
|
32
|
-
chmod +x mags
|
|
33
|
-
sudo mv mags /usr/local/bin/
|
|
34
|
-
|
|
35
|
-
# macOS (Intel)
|
|
36
|
-
curl -L https://releases.magpiecloud.com/mags/latest/mags-darwin-amd64 -o mags
|
|
37
|
-
chmod +x mags
|
|
38
|
-
sudo mv mags /usr/local/bin/
|
|
39
|
-
|
|
40
|
-
# Linux
|
|
41
|
-
curl -L https://releases.magpiecloud.com/mags/latest/mags-linux-amd64 -o mags
|
|
42
|
-
chmod +x mags
|
|
43
|
-
sudo mv mags /usr/local/bin/
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
### Option 2: Build from Source
|
|
47
|
-
|
|
48
|
-
```bash
|
|
49
|
-
git clone https://github.com/magpie/magpie-api-layer.git
|
|
50
|
-
cd magpie-api-layer
|
|
51
|
-
go build -o mags ./cmd/mags/
|
|
52
|
-
sudo mv mags /usr/local/bin/
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
### Verify Installation
|
|
56
|
-
|
|
57
|
-
```bash
|
|
58
|
-
mags --help
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
## Quick Examples
|
|
62
|
-
|
|
63
|
-
### Run a Simple Command
|
|
64
|
-
|
|
65
|
-
```bash
|
|
66
|
-
mags run "echo hello world"
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
### Use a Persistent Workspace
|
|
70
|
-
|
|
71
|
-
```bash
|
|
72
|
-
# First run - install Node.js (persists!)
|
|
73
|
-
mags run -w my-project "apk add nodejs npm"
|
|
74
|
-
|
|
75
|
-
# Second run - Node.js is already there
|
|
76
|
-
mags run -w my-project "node --version"
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
### Deploy a Web Server with Public URL
|
|
80
|
-
|
|
81
|
-
```bash
|
|
82
|
-
# Deploy with --url flag to get a public URL
|
|
83
|
-
mags run -w webapp -p --url "python3 -m http.server 8080"
|
|
84
|
-
# Output: https://abc123.apps.magpiecloud.com
|
|
85
|
-
|
|
86
|
-
# With startup command (runs when VM wakes from sleep)
|
|
87
|
-
mags run -w webapp -p --url --startup-command "npm start" "npm install && npm start"
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
### SSH into a VM
|
|
91
|
-
|
|
92
|
-
```bash
|
|
93
|
-
mags ssh my-project
|
|
94
|
-
# Now you're in an interactive shell
|
|
95
|
-
# All changes persist to 'my-project' workspace
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
### List Recent Jobs
|
|
99
|
-
|
|
100
|
-
```bash
|
|
101
|
-
mags list
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
## Workspaces
|
|
105
|
-
|
|
106
|
-
A **workspace** is a persistent filesystem stored in S3. Everything you do in a workspace persists:
|
|
107
|
-
|
|
108
|
-
| Persists | Does NOT Persist |
|
|
109
|
-
|----------|------------------|
|
|
110
|
-
| Files & directories | Running processes |
|
|
111
|
-
| Installed packages | In-memory state |
|
|
112
|
-
| Config files | Network connections |
|
|
113
|
-
| Environment customizations | Open ports |
|
|
114
|
-
|
|
115
|
-
### Workspace Naming
|
|
116
|
-
|
|
117
|
-
```bash
|
|
118
|
-
# Good workspace names
|
|
119
|
-
mags run -w my-project "..."
|
|
120
|
-
mags run -w user-123-dev "..."
|
|
121
|
-
mags run -w webapp-prod "..."
|
|
122
|
-
|
|
123
|
-
# Workspace names should be:
|
|
124
|
-
# - Lowercase alphanumeric with hyphens
|
|
125
|
-
# - Unique per user/project
|
|
126
|
-
# - Descriptive
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
## Command Reference
|
|
130
|
-
|
|
131
|
-
| Command | Description | Example |
|
|
132
|
-
|---------|-------------|---------|
|
|
133
|
-
| `mags run` | Run a script | `mags run "npm test"` |
|
|
134
|
-
| `mags run -w NAME` | Run with workspace | `mags run -w proj "npm test"` |
|
|
135
|
-
| `mags run -p --url` | Run with public URL | `mags run -w app -p --url "python3 -m http.server 8080"` |
|
|
136
|
-
| `mags exec` | Quick command in workspace | `mags exec proj "ls -la"` |
|
|
137
|
-
| `mags ssh` | Interactive SSH | `mags ssh proj` |
|
|
138
|
-
| `mags url ID` | Enable URL for job | `mags url abc123 --port 3000` |
|
|
139
|
-
| `mags list` | List jobs | `mags list -n 20` |
|
|
140
|
-
| `mags logs ID` | View job logs | `mags logs abc123` |
|
|
141
|
-
| `mags status ID` | Job status | `mags status abc123` |
|
|
142
|
-
| `mags set ID` | Update VM settings | `mags set myvm --no-sleep` |
|
|
143
|
-
|
|
144
|
-
## CLI Flags
|
|
145
|
-
|
|
146
|
-
| Flag | Description | Default |
|
|
147
|
-
|------|-------------|---------|
|
|
148
|
-
| `-w, --workspace` | Workspace ID for persistent storage | auto-generated |
|
|
149
|
-
| `-p, --persistent` | Keep VM alive for URL/SSH access | false |
|
|
150
|
-
| `--url` | Enable public URL access (requires -p) | false |
|
|
151
|
-
| `--port` | Port to expose for URL access | 8080 |
|
|
152
|
-
| `--no-sleep` | Keep VM always running, never auto-sleep (requires -p) | false |
|
|
153
|
-
| `--startup-command` | Command when VM wakes from sleep | none |
|
|
154
|
-
| `-e, --ephemeral` | No S3 sync (faster, truly ephemeral) | false |
|
|
155
|
-
| `-t, --timeout` | Timeout in seconds | 300 |
|
|
156
|
-
|
|
157
|
-
## Common Workflows
|
|
158
|
-
|
|
159
|
-
### Web Development
|
|
160
|
-
|
|
161
|
-
```bash
|
|
162
|
-
# Set up project with public URL
|
|
163
|
-
mags run -w webapp -p --url "apk add nodejs npm && npm init -y && npm install express"
|
|
164
|
-
|
|
165
|
-
# Your app is now at https://xyz123.apps.magpiecloud.com
|
|
166
|
-
|
|
167
|
-
# Update code and restart
|
|
168
|
-
mags run -w webapp -p --url "npm start"
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
### Python Development
|
|
172
|
-
|
|
173
|
-
```bash
|
|
174
|
-
# Set up Python environment
|
|
175
|
-
mags run -w pyproject "apk add python3 py3-pip"
|
|
176
|
-
|
|
177
|
-
# Install packages (persists!)
|
|
178
|
-
mags run -w pyproject "pip install flask requests"
|
|
179
|
-
|
|
180
|
-
# Run script
|
|
181
|
-
mags run -w pyproject "python app.py"
|
|
182
|
-
|
|
183
|
-
# Deploy with URL
|
|
184
|
-
mags run -w pyproject -p --url "flask run --host=0.0.0.0 --port=8080"
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
### CI/CD Jobs
|
|
188
|
-
|
|
189
|
-
```bash
|
|
190
|
-
# Run tests with timeout
|
|
191
|
-
mags run -w myapp -t 600 "npm ci && npm test"
|
|
192
|
-
|
|
193
|
-
# Build project
|
|
194
|
-
mags run -w myapp -t 600 "npm run build"
|
|
195
|
-
|
|
196
|
-
# Check results
|
|
197
|
-
mags logs <job-id>
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
### Deploy a Persistent Web App
|
|
201
|
-
|
|
202
|
-
```bash
|
|
203
|
-
# Deploy with auto-wake (VM sleeps when idle, wakes on request)
|
|
204
|
-
mags run -w myapp -p --url --startup-command "npm start" "npm install && npm start"
|
|
205
|
-
|
|
206
|
-
# Get a URL like: https://abc123.apps.magpiecloud.com
|
|
207
|
-
# The app wakes automatically when someone visits the URL!
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
### Always-On Server (Never Sleeps)
|
|
211
|
-
|
|
212
|
-
```bash
|
|
213
|
-
# Deploy a server that stays running 24/7
|
|
214
|
-
mags run -w my-api -p --no-sleep --url --port 3000 "npm start"
|
|
215
|
-
|
|
216
|
-
# VM never auto-sleeps, even when idle
|
|
217
|
-
# Auto-recovers if the host goes down
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
## Timeouts
|
|
221
|
-
|
|
222
|
-
| Command | Default | Max | Flag |
|
|
223
|
-
|---------|---------|-----|------|
|
|
224
|
-
| `run` | 5 min | configurable | `-t 600` |
|
|
225
|
-
| `exec` | 1 min | configurable | `-t 120` |
|
|
226
|
-
| `ssh` | 1 hour | 1 hour | - |
|
|
227
|
-
|
|
228
|
-
## Environment Variables
|
|
229
|
-
|
|
230
|
-
| Variable | Description |
|
|
231
|
-
|----------|-------------|
|
|
232
|
-
| `MAGS_API_TOKEN` | API token (required) |
|
|
233
|
-
| `MAGS_API_URL` | Custom API URL (optional) |
|
|
234
|
-
|
|
235
|
-
## API Access
|
|
236
|
-
|
|
237
|
-
You can also use the REST API directly:
|
|
238
|
-
|
|
239
|
-
```bash
|
|
240
|
-
# Submit a job
|
|
241
|
-
curl -X POST https://api.magpiecloud.com/api/v1/mags-jobs \
|
|
242
|
-
-H "Authorization: Bearer $MAGS_API_TOKEN" \
|
|
243
|
-
-H "Content-Type: application/json" \
|
|
244
|
-
-d '{
|
|
245
|
-
"script": "echo hello",
|
|
246
|
-
"type": "inline",
|
|
247
|
-
"workspace_id": "my-workspace",
|
|
248
|
-
"persistent": true
|
|
249
|
-
}'
|
|
250
|
-
|
|
251
|
-
# Check status
|
|
252
|
-
curl https://api.magpiecloud.com/api/v1/mags-jobs/{job-id}/status \
|
|
253
|
-
-H "Authorization: Bearer $MAGS_API_TOKEN"
|
|
254
|
-
|
|
255
|
-
# Get logs
|
|
256
|
-
curl https://api.magpiecloud.com/api/v1/mags-jobs/{job-id}/logs \
|
|
257
|
-
-H "Authorization: Bearer $MAGS_API_TOKEN"
|
|
258
|
-
|
|
259
|
-
# Enable URL access
|
|
260
|
-
curl -X POST https://api.magpiecloud.com/api/v1/mags-jobs/{job-id}/access \
|
|
261
|
-
-H "Authorization: Bearer $MAGS_API_TOKEN" \
|
|
262
|
-
-H "Content-Type: application/json" \
|
|
263
|
-
-d '{"port": 8080}'
|
|
264
|
-
```
|
|
265
|
-
|
|
266
|
-
## Troubleshooting
|
|
267
|
-
|
|
268
|
-
### "API token required"
|
|
269
|
-
```bash
|
|
270
|
-
export MAGS_API_TOKEN="your-token"
|
|
271
|
-
```
|
|
272
|
-
|
|
273
|
-
### "invalid or expired token"
|
|
274
|
-
Get a new token from the dashboard.
|
|
275
|
-
|
|
276
|
-
### Job timeout
|
|
277
|
-
Increase timeout: `mags run -t 600 -w proj "long-command"`
|
|
278
|
-
|
|
279
|
-
### Workspace not persisting
|
|
280
|
-
Ensure you use the same `-w` name across runs.
|
|
281
|
-
|
|
282
|
-
### URL not working
|
|
283
|
-
Make sure you used `--url` flag: `mags run -w app -p --url "..."`
|
|
284
|
-
|
|
285
|
-
Or enable it after: `mags url <job-id>`
|
|
286
|
-
|
|
287
|
-
## Getting Help
|
|
288
|
-
|
|
289
|
-
```bash
|
|
290
|
-
mags --help
|
|
291
|
-
mags run --help
|
|
292
|
-
mags url --help
|
|
293
|
-
```
|
|
294
|
-
|
|
295
|
-
For issues: https://github.com/magpie/magpie-api-layer/issues
|