@magpiecloud/mags 1.8.6 → 1.8.7

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/API.md CHANGED
@@ -212,12 +212,17 @@ HTTP services are also available via subdomain: `https://<subdomain>.apps.magpie
212
212
  PATCH /api/v1/mags-jobs/:id
213
213
  ```
214
214
 
215
- Update a job's startup command (used when waking from sleep).
215
+ Update a job's settings. All fields are optional only include the ones you want to change.
216
216
 
217
217
  **Request:**
218
218
 
219
+ | Field | Type | Description |
220
+ |-------|------|-------------|
221
+ | `startup_command` | string | Command to run when VM wakes from sleep |
222
+ | `no_sleep` | bool | If `true`, VM never auto-sleeps. If `false`, re-enables auto-sleep. Requires persistent VM. |
223
+
219
224
  ```json
220
- { "startup_command": "python3 -m http.server 8080" }
225
+ { "no_sleep": true }
221
226
  ```
222
227
 
223
228
  **Response (200):**
package/QUICKSTART.md CHANGED
@@ -139,6 +139,7 @@ mags run -w webapp-prod "..."
139
139
  | `mags list` | List jobs | `mags list -n 20` |
140
140
  | `mags logs ID` | View job logs | `mags logs abc123` |
141
141
  | `mags status ID` | Job status | `mags status abc123` |
142
+ | `mags set ID` | Update VM settings | `mags set myvm --no-sleep` |
142
143
 
143
144
  ## CLI Flags
144
145
 
package/README.md CHANGED
@@ -107,6 +107,7 @@ mags run -p --url 'python3 -m http.server 8080'
107
107
  | `mags list` | List recent jobs |
108
108
  | `mags url <job-id> [port]` | Enable URL access for a job |
109
109
  | `mags stop <job-id>` | Stop a running job |
110
+ | `mags set <name\|id> [options]` | Update VM settings (`--no-sleep`, `--sleep`) |
110
111
 
111
112
  ### Run Options
112
113
 
package/bin/mags.js CHANGED
@@ -211,6 +211,7 @@ ${colors.bold}Commands:${colors.reset}
211
211
  url alias <sub> <workspace> Create a stable URL alias for a workspace
212
212
  url alias list List your URL aliases
213
213
  url alias remove <subdomain> Delete a URL alias
214
+ set <name|id> [options] Update VM settings
214
215
  stop <name|id> Stop a running job
215
216
  resize <workspace> --disk <GB> Resize a workspace's disk (restarts VM)
216
217
  sync <workspace|id> Sync workspace to S3 (without stopping)
@@ -829,6 +830,48 @@ async function stopJob(nameOrId) {
829
830
  }
830
831
  }
831
832
 
833
+ async function setJobSettings(args) {
834
+ let nameOrId = null;
835
+ let noSleep = null;
836
+
837
+ for (let i = 0; i < args.length; i++) {
838
+ if (args[i] === '--no-sleep') {
839
+ noSleep = true;
840
+ } else if (args[i] === '--sleep') {
841
+ noSleep = false;
842
+ } else if (!nameOrId) {
843
+ nameOrId = args[i];
844
+ }
845
+ }
846
+
847
+ if (!nameOrId) {
848
+ log('red', 'Error: Job name or ID required');
849
+ console.log(`\nUsage: mags set <name|id> [options]\n`);
850
+ console.log('Options:');
851
+ console.log(' --no-sleep Never auto-sleep this VM');
852
+ console.log(' --sleep Re-enable auto-sleep');
853
+ process.exit(1);
854
+ }
855
+
856
+ const payload = {};
857
+ if (noSleep !== null) payload.no_sleep = noSleep;
858
+
859
+ if (Object.keys(payload).length === 0) {
860
+ log('red', 'Error: No settings to update. Use --no-sleep or --sleep');
861
+ process.exit(1);
862
+ }
863
+
864
+ const requestId = await resolveJobId(nameOrId);
865
+ log('blue', `Updating settings for ${requestId}...`);
866
+ const resp = await request('PATCH', `/api/v1/mags-jobs/${requestId}`, payload);
867
+ if (resp.success) {
868
+ if (noSleep === true) log('green', 'VM set to never auto-sleep');
869
+ if (noSleep === false) log('green', 'VM set to auto-sleep when idle');
870
+ } else {
871
+ log('red', `Failed: ${resp.error || 'unknown error'}`);
872
+ }
873
+ }
874
+
832
875
  async function resizeVM(args) {
833
876
  let name = null;
834
877
  let diskGB = 0;
@@ -1628,7 +1671,7 @@ async function main() {
1628
1671
  break;
1629
1672
  case '--version':
1630
1673
  case '-v':
1631
- console.log('mags v1.8.5');
1674
+ console.log('mags v1.8.7');
1632
1675
  process.exit(0);
1633
1676
  break;
1634
1677
  case 'new':
@@ -1671,6 +1714,10 @@ async function main() {
1671
1714
  await requireAuth();
1672
1715
  await listJobs();
1673
1716
  break;
1717
+ case 'set':
1718
+ await requireAuth();
1719
+ await setJobSettings(args.slice(1));
1720
+ break;
1674
1721
  case 'stop':
1675
1722
  await requireAuth();
1676
1723
  await stopJob(args[1]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@magpiecloud/mags",
3
- "version": "1.8.6",
3
+ "version": "1.8.7",
4
4
  "description": "Mags CLI - Execute scripts on Magpie's instant VM infrastructure",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "magpie-mags"
7
- version = "1.3.3"
7
+ version = "1.3.4"
8
8
  description = "Mags SDK - Execute scripts on Magpie's instant VM infrastructure"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
@@ -202,11 +202,26 @@ class Mags:
202
202
  "GET", "/mags-jobs", params={"page": page, "page_size": page_size}
203
203
  )
204
204
 
205
- def update_job(self, request_id: str, *, startup_command: str) -> dict:
206
- """Update a job (e.g. set startup command for wake-from-sleep)."""
207
- return self._request(
208
- "PATCH", f"/mags-jobs/{request_id}", json={"startup_command": startup_command}
209
- )
205
+ def update_job(
206
+ self,
207
+ request_id: str,
208
+ *,
209
+ startup_command: str | None = None,
210
+ no_sleep: bool | None = None,
211
+ ) -> dict:
212
+ """Update a job's settings.
213
+
214
+ Args:
215
+ request_id: The job/workspace ID to update.
216
+ startup_command: Command to run when VM wakes from sleep.
217
+ no_sleep: If True, VM never auto-sleeps. If False, re-enables auto-sleep.
218
+ """
219
+ payload: dict = {}
220
+ if startup_command is not None:
221
+ payload["startup_command"] = startup_command
222
+ if no_sleep is not None:
223
+ payload["no_sleep"] = no_sleep
224
+ return self._request("PATCH", f"/mags-jobs/{request_id}", json=payload)
210
225
 
211
226
  def enable_access(self, request_id: str, *, port: int = 8080) -> dict:
212
227
  """Enable external access (URL or SSH) for a persistent job's VM.
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=2" />
13
+ <link rel="stylesheet" href="styles.css?v=6" />
14
14
  <script src="env.js"></script>
15
15
  <style>
16
16
  .endpoint { margin-bottom: 2.5rem; }
@@ -111,6 +111,7 @@
111
111
  <a href="index.html">Home</a>
112
112
  <a href="index.html#quickstart">Docs</a>
113
113
  <a href="cookbook.html">Cookbook</a>
114
+ <a href="claude-skill.html">Claude Skill</a>
114
115
  <a href="https://discord.gg/3avpC2nS" target="_blank" rel="noreferrer">Discord</a>
115
116
  <a href="login.html">Login</a>
116
117
  </nav>
@@ -616,29 +617,57 @@ const access = await mags.enableAccess(requestId, { port: 8080 });</code></pre>
616
617
  <span class="method patch">PATCH</span>
617
618
  <span class="url-path">/api/v1/mags-jobs/:id</span>
618
619
  </div>
619
- <p>Update a job's startup command (used when waking from sleep).</p>
620
+ <p>Update a job's settings. All fields are optional &mdash; only include the ones you want to change.</p>
620
621
 
621
622
  <p class="response-label">Request body</p>
622
- <pre><code>{ "startup_command": "python3 -m http.server 8080" }</code></pre>
623
+ <div class="ref-table-wrap">
624
+ <table class="ref-table">
625
+ <thead><tr><th>Field</th><th>Type</th><th>Description</th></tr></thead>
626
+ <tbody>
627
+ <tr><td><code>startup_command</code></td><td>string</td><td>Command to run when VM wakes from sleep</td></tr>
628
+ <tr><td><code>no_sleep</code></td><td>bool</td><td>If <code>true</code>, VM never auto-sleeps. If <code>false</code>, re-enables auto-sleep. Requires persistent VM.</td></tr>
629
+ </tbody>
630
+ </table>
631
+ </div>
632
+ <pre><code>{ "no_sleep": true }</code></pre>
623
633
 
624
634
  <div class="code-tabs tab-group">
625
635
  <p class="response-label">SDK examples</p>
626
636
  <div class="tab-bar">
627
637
  <button class="tab active" data-tab="uj-curl">curl</button>
638
+ <button class="tab" data-tab="uj-cli">CLI</button>
628
639
  <button class="tab" data-tab="uj-py">Python</button>
629
640
  <button class="tab" data-tab="uj-js">Node.js</button>
630
641
  </div>
631
642
  <div class="tab-content active" data-tab="uj-curl">
632
- <pre><code>curl -X PATCH https://api.magpiecloud.com/api/v1/mags-jobs/$ID \
643
+ <pre><code># Enable no-sleep
644
+ curl -X PATCH https://api.magpiecloud.com/api/v1/mags-jobs/$ID \
645
+ -H "Authorization: Bearer $TOKEN" \
646
+ -H "Content-Type: application/json" \
647
+ -d '{ "no_sleep": true }'
648
+
649
+ # Set startup command
650
+ curl -X PATCH https://api.magpiecloud.com/api/v1/mags-jobs/$ID \
633
651
  -H "Authorization: Bearer $TOKEN" \
634
652
  -H "Content-Type: application/json" \
635
653
  -d '{ "startup_command": "python3 -m http.server 8080" }'</code></pre>
654
+ </div>
655
+ <div class="tab-content" data-tab="uj-cli">
656
+ <pre><code># Enable no-sleep on an existing VM
657
+ mags set myvm --no-sleep
658
+
659
+ # Re-enable auto-sleep
660
+ mags set myvm --sleep</code></pre>
636
661
  </div>
637
662
  <div class="tab-content" data-tab="uj-py">
638
- <pre><code>m.update_job(request_id, startup_command="python3 -m http.server 8080")</code></pre>
663
+ <pre><code># Enable no-sleep
664
+ m.update_job(request_id, no_sleep=True)
665
+
666
+ # Set startup command
667
+ m.update_job(request_id, startup_command="python3 -m http.server 8080")</code></pre>
639
668
  </div>
640
669
  <div class="tab-content" data-tab="uj-js">
641
- <pre><code>await mags.updateJob(requestId, { startupCommand: 'python3 -m http.server 8080' });</code></pre>
670
+ <pre><code>await mags.updateJob(requestId, { noSleep: true });</code></pre>
642
671
  </div>
643
672
  </div>
644
673
  </div>
@@ -932,6 +961,6 @@ mags cron remove &lt;id&gt;</code></pre>
932
961
  </div>
933
962
  </footer>
934
963
 
935
- <script src="script.js?v=2"></script>
964
+ <script src="script.js?v=7"></script>
936
965
  </body>
937
966
  </html>
@@ -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=2" />
13
+ <link rel="stylesheet" href="styles.css?v=6" />
14
14
  <script src="env.js"></script>
15
15
  </head>
16
16
  <body>
@@ -476,6 +476,6 @@ Use workspace "monitors" so the log persists</code></pre>
476
476
  </div>
477
477
  </footer>
478
478
 
479
- <script src="script.js"></script>
479
+ <script src="script.js?v=7"></script>
480
480
  </body>
481
481
  </html>
@@ -26,6 +26,7 @@
26
26
  <a href="index.html">Home</a>
27
27
  <a href="index.html#quickstart">Docs</a>
28
28
  <a href="api.html">API</a>
29
+ <a href="claude-skill.html">Claude Skill</a>
29
30
  <a href="https://discord.gg/3avpC2nS" target="_blank" rel="noreferrer">Discord</a>
30
31
  <a href="login.html">Login</a>
31
32
  </nav>
@@ -276,6 +277,6 @@ curl -X POST https://api.magpiecloud.com/api/v1/mags-cron \
276
277
  </div>
277
278
  </footer>
278
279
 
279
- <script src="script.js"></script>
280
+ <script src="script.js?v=7"></script>
280
281
  </body>
281
282
  </html>
@@ -198,6 +198,7 @@ mags login</code></pre>
198
198
  <tr><td><code>mags status &lt;id&gt;</code></td><td>Get job status</td></tr>
199
199
  <tr><td><code>mags logs &lt;id&gt;</code></td><td>Get job output</td></tr>
200
200
  <tr><td><code>mags stop &lt;id&gt;</code></td><td>Stop a running job</td></tr>
201
+ <tr><td><code>mags set &lt;id&gt; [options]</code></td><td>Update VM settings (e.g. <code>--no-sleep</code>, <code>--sleep</code>)</td></tr>
201
202
  <tr><td><code>mags sync &lt;workspace&gt;</code></td><td>Sync workspace to the cloud now</td></tr>
202
203
  <tr><td><code>mags url &lt;id&gt; [port]</code></td><td>Enable public URL access</td></tr>
203
204
  <tr><td><code>mags workspace list</code></td><td>List persistent workspaces</td></tr>
@@ -730,7 +731,7 @@ console.log(result.logs);</code></pre>
730
731
  </div>
731
732
  </footer>
732
733
 
733
- <script src="script.js?v=5"></script>
734
+ <script src="script.js?v=7"></script>
734
735
  <script>
735
736
  (function() {
736
737
  var token = localStorage.getItem('microvm-access-token');
package/website/llms.txt CHANGED
@@ -35,6 +35,8 @@ mags run 'echo Hello World'
35
35
  - `mags logs <job-id>` — View job logs
36
36
  - `mags status <job-id>` — Check job status
37
37
  - `mags stop <job-id>` — Stop a running job
38
+ - `mags set <name|id> --no-sleep` — Never auto-sleep this VM
39
+ - `mags set <name|id> --sleep` — Re-enable auto-sleep
38
40
 
39
41
  ## Run Options
40
42
 
@@ -7,7 +7,7 @@
7
7
  <meta name="description" content="Sign in to Mags with Google." />
8
8
  <meta name="api-base" content="https://api.magpiecloud.com" />
9
9
  <meta name="auth-base" content="https://api.magpiecloud.com" />
10
- <link rel="stylesheet" href="styles.css?v=2" />
10
+ <link rel="stylesheet" href="styles.css?v=6" />
11
11
  <script src="env.js"></script>
12
12
  </head>
13
13
  <body>
@@ -64,6 +64,45 @@
64
64
  </div>
65
65
  </footer>
66
66
 
67
- <script src="script.js"></script>
67
+ <script src="script.js?v=7"></script>
68
+ <script>
69
+ (function() {
70
+ // Handle logout: clear tokens when ?logout=1 is present
71
+ var params = new URLSearchParams(window.location.search);
72
+ if (params.get('logout') === '1') {
73
+ localStorage.removeItem('microvm-access-token');
74
+ localStorage.removeItem('microvm-refresh-token');
75
+ // Clean up the URL
76
+ window.history.replaceState({}, '', 'login.html');
77
+ return;
78
+ }
79
+
80
+ // If already logged in, redirect to next or show dashboard link
81
+ var token = localStorage.getItem('microvm-access-token');
82
+ if (token) {
83
+ var next = params.get('next');
84
+ if (next && next.startsWith('/')) {
85
+ window.location.replace(next);
86
+ return;
87
+ }
88
+ var shell = document.querySelector('.auth-shell');
89
+ if (shell) {
90
+ shell.innerHTML =
91
+ '<div>' +
92
+ '<span class="pill">Logged in</span>' +
93
+ '<h1 class="auth-title">You\'re signed in.</h1>' +
94
+ '<p class="auth-subtitle">You\'re already logged in to Mags.</p>' +
95
+ '</div>' +
96
+ '<a class="button full" href="usage.html">Go to Dashboard</a>' +
97
+ '<button class="button ghost full" type="button" id="logout-btn" style="margin-top:0.75rem">Sign out</button>';
98
+ document.getElementById('logout-btn').addEventListener('click', function() {
99
+ localStorage.removeItem('microvm-access-token');
100
+ localStorage.removeItem('microvm-refresh-token');
101
+ window.location.reload();
102
+ });
103
+ }
104
+ }
105
+ })();
106
+ </script>
68
107
  </body>
69
108
  </html>
package/website/mags.md CHANGED
@@ -71,6 +71,12 @@ mags url <name-or-id> [port]
71
71
  mags stop <name-or-id>
72
72
  ```
73
73
 
74
+ ### Update VM settings
75
+ ```bash
76
+ mags set <name-or-id> --no-sleep # Never auto-sleep
77
+ mags set <name-or-id> --sleep # Re-enable auto-sleep
78
+ ```
79
+
74
80
  ### Run without workspace (ephemeral, fastest)
75
81
  ```bash
76
82
  mags run -e '<script>'
package/website/script.js CHANGED
@@ -87,6 +87,30 @@ const tokenStore = {
87
87
  },
88
88
  };
89
89
 
90
+ /* ── Extract tokens from URL after OAuth callback redirect ── */
91
+ (function () {
92
+ var params = new URLSearchParams(window.location.search);
93
+ var token = params.get('token');
94
+ var refresh = params.get('refresh');
95
+ if (token && refresh) {
96
+ tokenStore.setTokens({ accessToken: token, refreshToken: refresh });
97
+ params.delete('token');
98
+ params.delete('refresh');
99
+ var clean = window.location.pathname;
100
+ var remaining = params.toString();
101
+ if (remaining) clean += '?' + remaining;
102
+ window.history.replaceState({}, '', clean);
103
+ }
104
+ })();
105
+
106
+ /* ── Redirect to login for protected pages when not authed ── */
107
+ (function () {
108
+ if (!document.querySelector('[data-auth-required]')) return;
109
+ if (tokenStore.getAccessToken()) return;
110
+ var next = window.location.pathname + window.location.search;
111
+ window.location.replace('login.html?next=' + encodeURIComponent(next));
112
+ })();
113
+
90
114
  const refreshTokens = async () => {
91
115
  const refreshToken = tokenStore.getRefreshToken();
92
116
  if (!refreshToken) return null;
@@ -183,7 +207,10 @@ copyButtons.forEach((button) => {
183
207
  const googleLogin = document.querySelector('[data-google-login]');
184
208
  if (googleLogin) {
185
209
  googleLogin.addEventListener('click', () => {
186
- window.location.href = withBase('/auth/google', AUTH_BASE);
210
+ var url = withBase('/auth/google', AUTH_BASE);
211
+ var next = new URLSearchParams(window.location.search).get('next');
212
+ if (next) url += (url.includes('?') ? '&' : '?') + 'next=' + encodeURIComponent(next);
213
+ window.location.href = url;
187
214
  });
188
215
  }
189
216
 
@@ -223,11 +250,12 @@ if (loginForm) {
223
250
  refreshToken: data.refresh_token,
224
251
  });
225
252
  if (message) {
226
- message.textContent = 'Signed in. Redirecting to usage...';
253
+ message.textContent = 'Signed in. Redirecting...';
227
254
  }
228
255
  loginForm.reset();
256
+ var dest = new URLSearchParams(window.location.search).get('next') || 'usage.html';
229
257
  setTimeout(() => {
230
- window.location.href = 'usage.html';
258
+ window.location.href = dest;
231
259
  }, 600);
232
260
  } catch (error) {
233
261
  if (message) {
@@ -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=2" />
13
+ <link rel="stylesheet" href="styles.css?v=6" />
14
14
  <script src="env.js"></script>
15
15
  </head>
16
16
  <body>
@@ -27,10 +27,11 @@
27
27
  <a href="usage.html">Usage</a>
28
28
  <a href="api.html">API</a>
29
29
  <a href="cookbook.html">Cookbook</a>
30
+ <a href="claude-skill.html">Claude Skill</a>
30
31
  <a href="https://discord.gg/3avpC2nS" target="_blank" rel="noreferrer">Discord</a>
31
32
  </nav>
32
33
  <div class="nav-cta">
33
- <a class="button ghost" href="/api-keys">Manage tokens</a>
34
+ <a class="button ghost" href="usage.html">Usage</a>
34
35
  </div>
35
36
  </div>
36
37
  </header>
@@ -46,7 +47,7 @@
46
47
  the dashboard and store them securely.
47
48
  </p>
48
49
  <div class="hero-actions">
49
- <a class="button" href="/api-keys">Open token manager</a>
50
+ <a class="button" href="#tokens">Create a token</a>
50
51
  <a class="button ghost" href="#usage">Usage in CLI</a>
51
52
  </div>
52
53
  </div>
@@ -90,7 +91,7 @@ mags whoami</code></pre>
90
91
  <h2>Manage active tokens.</h2>
91
92
  </div>
92
93
  <div class="callout" data-auth-required>
93
- <p>Sign in to view and create tokens. Use <a data-auth-link="/auth/login" href="#">email login</a> or <a data-auth-link="/auth/google" href="#">Google sign-in</a>.</p>
94
+ <p>Sign in to view and create tokens. <a href="login.html?next=/tokens.html">Sign in with Google</a>.</p>
94
95
  </div>
95
96
  <div class="grid split" style="margin-bottom: 1.6rem;">
96
97
  <article class="panel" data-reveal>
@@ -163,6 +164,6 @@ mags whoami</code></pre>
163
164
  </div>
164
165
  </footer>
165
166
 
166
- <script src="script.js"></script>
167
+ <script src="script.js?v=7"></script>
167
168
  </body>
168
169
  </html>
@@ -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=2" />
13
+ <link rel="stylesheet" href="styles.css?v=6" />
14
14
  <script src="env.js"></script>
15
15
  </head>
16
16
  <body>
@@ -27,10 +27,11 @@
27
27
  <a href="tokens.html">Tokens</a>
28
28
  <a href="api.html">API</a>
29
29
  <a href="cookbook.html">Cookbook</a>
30
+ <a href="claude-skill.html">Claude Skill</a>
30
31
  <a href="https://discord.gg/3avpC2nS" target="_blank" rel="noreferrer">Discord</a>
31
32
  </nav>
32
33
  <div class="nav-cta">
33
- <a class="button ghost" href="/mags">Open console</a>
34
+ <a class="button ghost" href="tokens.html">Tokens</a>
34
35
  </div>
35
36
  </div>
36
37
  </header>
@@ -71,7 +72,7 @@ mags logs &lt;job-id&gt;</code></pre>
71
72
  <h2>Your most recent activity.</h2>
72
73
  </div>
73
74
  <div class="callout" data-auth-required>
74
- <p>Sign in to see usage data. Use <a data-auth-link="/auth/login" href="#">email login</a> or <a data-auth-link="/auth/google" href="#">Google sign-in</a>.</p>
75
+ <p>Sign in to see usage data. <a href="login.html?next=/usage.html">Sign in with Google</a>.</p>
75
76
  </div>
76
77
  <div class="stats-grid" data-reveal>
77
78
  <div class="stat-card">
@@ -179,6 +180,6 @@ mags cron add --name "backup" \
179
180
  </div>
180
181
  </footer>
181
182
 
182
- <script src="script.js"></script>
183
+ <script src="script.js?v=7"></script>
183
184
  </body>
184
185
  </html>