@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.
Files changed (43) hide show
  1. package/README.md +95 -378
  2. package/bin/mags.js +196 -104
  3. package/index.js +6 -52
  4. package/package.json +22 -4
  5. package/API.md +0 -388
  6. package/Mags-API.postman_collection.json +0 -374
  7. package/QUICKSTART.md +0 -295
  8. package/deploy-page.sh +0 -171
  9. package/mags +0 -0
  10. package/mags.sh +0 -270
  11. package/nodejs/README.md +0 -197
  12. package/nodejs/bin/mags.js +0 -1146
  13. package/nodejs/index.js +0 -642
  14. package/nodejs/package.json +0 -42
  15. package/python/INTEGRATION.md +0 -800
  16. package/python/README.md +0 -161
  17. package/python/dist/magpie_mags-1.3.5-py3-none-any.whl +0 -0
  18. package/python/dist/magpie_mags-1.3.5.tar.gz +0 -0
  19. package/python/examples/demo.py +0 -181
  20. package/python/pyproject.toml +0 -39
  21. package/python/src/magpie_mags.egg-info/PKG-INFO +0 -182
  22. package/python/src/magpie_mags.egg-info/SOURCES.txt +0 -9
  23. package/python/src/magpie_mags.egg-info/dependency_links.txt +0 -1
  24. package/python/src/magpie_mags.egg-info/requires.txt +0 -1
  25. package/python/src/magpie_mags.egg-info/top_level.txt +0 -1
  26. package/python/src/mags/__init__.py +0 -6
  27. package/python/src/mags/client.py +0 -573
  28. package/python/test_sdk.py +0 -78
  29. package/skill.md +0 -153
  30. package/website/api.html +0 -1095
  31. package/website/claude-skill.html +0 -481
  32. package/website/cookbook/hn-marketing.html +0 -410
  33. package/website/cookbook/hn-marketing.sh +0 -42
  34. package/website/cookbook.html +0 -282
  35. package/website/env.js +0 -4
  36. package/website/index.html +0 -801
  37. package/website/llms.txt +0 -334
  38. package/website/login.html +0 -108
  39. package/website/mags.md +0 -210
  40. package/website/script.js +0 -453
  41. package/website/styles.css +0 -908
  42. package/website/tokens.html +0 -169
  43. package/website/usage.html +0 -185
@@ -1,410 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1" />
6
- <title>HN Marketing Digest - Mags Cookbook</title>
7
- <meta
8
- name="description"
9
- content="Auto-updated marketing news from Hacker News, powered by a Mags cron job."
10
- />
11
- <meta name="api-base" content="https://api.magpiecloud.com" />
12
- <meta name="auth-base" content="https://api.magpiecloud.com" />
13
- <link rel="stylesheet" href="../styles.css" />
14
- <script src="../env.js"></script>
15
- <style>
16
- .hn-feed {
17
- display: grid;
18
- gap: 1rem;
19
- }
20
- .hn-story {
21
- background: var(--surface);
22
- border: 1px solid var(--border);
23
- border-radius: var(--radius-sm);
24
- padding: 1.2rem 1.4rem;
25
- box-shadow: var(--shadow);
26
- transition: transform 0.2s ease, box-shadow 0.2s ease;
27
- }
28
- .hn-story:hover {
29
- transform: translateY(-2px);
30
- }
31
- .hn-story h4 {
32
- margin: 0 0 0.5rem;
33
- font-size: 1rem;
34
- line-height: 1.4;
35
- }
36
- .hn-story h4 a {
37
- color: var(--text);
38
- }
39
- .hn-story h4 a:hover {
40
- color: var(--accent-strong);
41
- }
42
- .hn-meta {
43
- display: flex;
44
- gap: 1.2rem;
45
- font-size: 0.85rem;
46
- color: var(--text-muted);
47
- flex-wrap: wrap;
48
- }
49
- .hn-meta a {
50
- color: var(--accent-strong);
51
- font-weight: 600;
52
- }
53
- .hn-status-bar {
54
- display: flex;
55
- align-items: center;
56
- justify-content: space-between;
57
- gap: 1rem;
58
- margin-bottom: 1.4rem;
59
- flex-wrap: wrap;
60
- }
61
- .hn-status-bar .last-checked {
62
- font-size: 0.85rem;
63
- color: var(--text-muted);
64
- }
65
- .refresh-btn {
66
- display: inline-flex;
67
- align-items: center;
68
- gap: 0.4rem;
69
- padding: 0.5rem 1rem;
70
- border-radius: 999px;
71
- border: 1px solid var(--border);
72
- background: #ffffff;
73
- color: var(--text-muted);
74
- font-size: 0.85rem;
75
- font-family: var(--sans);
76
- cursor: pointer;
77
- transition: border-color 0.2s ease, color 0.2s ease, transform 0.2s ease;
78
- }
79
- .refresh-btn:hover {
80
- border-color: var(--accent);
81
- color: var(--accent-strong);
82
- transform: translateY(-1px);
83
- }
84
- .refresh-btn:disabled {
85
- opacity: 0.5;
86
- cursor: not-allowed;
87
- transform: none;
88
- }
89
- .hn-empty {
90
- text-align: center;
91
- padding: 2.5rem 1rem;
92
- color: var(--text-muted);
93
- background: var(--surface-muted);
94
- border-radius: var(--radius-sm);
95
- border: 1px solid var(--border);
96
- }
97
- .hn-loading {
98
- text-align: center;
99
- padding: 2.5rem 1rem;
100
- color: var(--text-muted);
101
- }
102
- .step-number {
103
- display: inline-flex;
104
- align-items: center;
105
- justify-content: center;
106
- width: 1.6rem;
107
- height: 1.6rem;
108
- border-radius: 50%;
109
- background: var(--accent);
110
- color: #fff;
111
- font-size: 0.75rem;
112
- font-weight: 700;
113
- margin-right: 0.5rem;
114
- flex-shrink: 0;
115
- }
116
- .step-item {
117
- margin-bottom: 1.8rem;
118
- }
119
- .step-item h3 {
120
- display: flex;
121
- align-items: center;
122
- margin: 0 0 0.6rem;
123
- font-size: 1.05rem;
124
- }
125
- </style>
126
- </head>
127
- <body>
128
- <div class="backdrop"></div>
129
-
130
- <header class="site-header">
131
- <div class="container nav">
132
- <div class="brand">
133
- <span class="logo">Mags</span>
134
- <span class="tag">HN Marketing Digest</span>
135
- </div>
136
- <nav class="nav-links">
137
- <a href="../index.html">Home</a>
138
- <a href="../index.html#quickstart">Quickstart</a>
139
- <a href="../index.html#cli">CLI</a>
140
- <a href="../index.html#api">API</a>
141
- <a href="../login.html">Login</a>
142
- <a href="../usage.html">Usage</a>
143
- <a href="../tokens.html">Tokens</a>
144
- <a href="../cookbook.html">Cookbook</a>
145
- </nav>
146
- <div class="nav-cta">
147
- <a class="button ghost" href="../cookbook.html">Back to Cookbook</a>
148
- </div>
149
- </div>
150
- </header>
151
-
152
- <main>
153
- <section class="hero">
154
- <div class="container hero-grid">
155
- <div class="hero-copy">
156
- <span class="pill">Cron</span>
157
- <h1>HN Marketing Digest</h1>
158
- <p class="lead">
159
- Automatically fetch and filter Hacker News for marketing-related stories.
160
- Run it as a cron job in a Mags sandbox, or check the live feed below.
161
- </p>
162
- <div class="hero-actions">
163
- <a class="button" href="#recipe">Setup recipe</a>
164
- <a class="button ghost" href="#live-feed">Live feed</a>
165
- </div>
166
- </div>
167
- <div class="hero-card">
168
- <div class="card-header">
169
- <span>Preview</span>
170
- <span class="chip">Shell</span>
171
- </div>
172
- <pre><code>$ sh hn-marketing.sh
173
- === HN Marketing Digest ===
174
- Fetching top stories from Hacker News...
175
-
176
- [1] Why SEO is dead in 2025
177
- Score: 342 | Link: https://...
178
- HN: https://news.ycombinator.com/...
179
-
180
- Found 3 marketing-related stories.</code></pre>
181
- <p class="card-note">Runs with just <code>curl</code> and <code>jq</code> on Alpine.</p>
182
- </div>
183
- </div>
184
- </section>
185
-
186
- <section class="section" id="recipe">
187
- <div class="container">
188
- <div class="section-title">
189
- <p>Recipe</p>
190
- <h2>Set up the cron job in 3 steps.</h2>
191
- </div>
192
-
193
- <div class="step-item" data-reveal>
194
- <h3><span class="step-number">1</span> Upload script and install dependencies</h3>
195
- <p class="label">Upload the shell script to a persistent workspace and install <code>curl</code> + <code>jq</code>.</p>
196
- <pre><code>mags run -f cookbook/hn-marketing.sh -w hn-digest \
197
- 'cp hn-marketing.sh /root/ && chmod +x /root/hn-marketing.sh && apk add -q curl jq && echo "Setup complete"'</code></pre>
198
- </div>
199
-
200
- <div class="step-item" data-reveal>
201
- <h3><span class="step-number">2</span> Test run it manually</h3>
202
- <p class="label">Verify the script works before scheduling.</p>
203
- <pre><code>mags run -w hn-digest 'sh /root/hn-marketing.sh'</code></pre>
204
- </div>
205
-
206
- <div class="step-item" data-reveal>
207
- <h3><span class="step-number">3</span> Activate the cron job</h3>
208
- <p class="label">Schedule the digest to run every 2 hours.</p>
209
- <pre><code>mags cron add --name "hn-marketing" --schedule "0 */2 * * *" -w hn-digest \
210
- 'sh /root/hn-marketing.sh'</code></pre>
211
- </div>
212
-
213
- <div class="callout" data-reveal>
214
- <p>Check cron status any time with <code>mags cron list</code>.</p>
215
- </div>
216
- </div>
217
- </section>
218
-
219
- <section class="section">
220
- <div class="container">
221
- <div class="section-title">
222
- <p>Script</p>
223
- <h2>The full shell script.</h2>
224
- </div>
225
- <article class="panel" data-reveal>
226
- <h3>hn-marketing.sh</h3>
227
- <pre><code>#!/bin/sh
228
- # hn-marketing.sh — Fetch top HN stories and filter for marketing-related content
229
- # Dependencies: curl, jq (install with: apk add -q curl jq)
230
-
231
- set -e
232
-
233
- KEYWORDS='marketing|growth hack|SEO|advertising|branding|brand strategy|content strategy|content marketing|acquisition|retention|funnel|conversion|GTM|go-to-market|product.led|newsletter|copywriting|social media|influencer|public relations|DTC|B2B marketing|B2C|demand gen|lead gen|campaign'
234
-
235
- echo "=== HN Marketing Digest ==="
236
- echo "Fetching top stories from Hacker News..."
237
- echo ""
238
-
239
- IDS=$(curl -sf "https://hacker-news.firebaseio.com/v0/topstories.json" | jq -r '.[0:100] | .[]')
240
-
241
- if [ -z "$IDS" ]; then
242
- echo "Error: could not fetch story IDs"
243
- exit 1
244
- fi
245
-
246
- COUNT=0
247
-
248
- for ID in $IDS; do
249
- ITEM=$(curl -sf "https://hacker-news.firebaseio.com/v0/item/${ID}.json")
250
- TITLE=$(echo "$ITEM" | jq -r '.title // empty')
251
-
252
- if [ -z "$TITLE" ]; then
253
- continue
254
- fi
255
-
256
- MATCH=$(echo "$TITLE" | grep -iE "$KEYWORDS" || true)
257
-
258
- if [ -n "$MATCH" ]; then
259
- URL=$(echo "$ITEM" | jq -r '.url // "https://news.ycombinator.com/item?id='"$ID"'"')
260
- SCORE=$(echo "$ITEM" | jq -r '.score // 0')
261
- TIME=$(echo "$ITEM" | jq -r '.time // 0')
262
- COUNT=$((COUNT + 1))
263
-
264
- echo "[$COUNT] $TITLE"
265
- echo " Score: $SCORE | Link: $URL"
266
- echo " HN: https://news.ycombinator.com/item?id=$ID"
267
- echo ""
268
- fi
269
- done
270
-
271
- if [ "$COUNT" -eq 0 ]; then
272
- echo "No marketing-related stories found in the current top 100."
273
- else
274
- echo "---"
275
- echo "Found $COUNT marketing-related stories."
276
- fi</code></pre>
277
- </article>
278
- </div>
279
- </section>
280
-
281
- <section class="section" id="live-feed">
282
- <div class="container">
283
- <div class="section-title">
284
- <p>Live feed</p>
285
- <h2>Marketing stories on HN right now.</h2>
286
- </div>
287
-
288
- <div class="hn-status-bar">
289
- <span class="last-checked" id="hn-last-checked">Loading...</span>
290
- <button class="refresh-btn" id="hn-refresh" type="button">Refresh</button>
291
- </div>
292
-
293
- <div class="hn-feed" id="hn-feed">
294
- <div class="hn-loading">Fetching stories from Hacker News...</div>
295
- </div>
296
- </div>
297
- </section>
298
- </main>
299
-
300
- <footer class="site-footer">
301
- <div class="container footer-grid">
302
- <div>
303
- <div class="brand">
304
- <span class="logo">Mags</span>
305
- <span class="tag">Instant sandboxes and runtime environments</span>
306
- </div>
307
- <p>Build, test, and run from clean microVMs whenever you need them.</p>
308
- </div>
309
- <div class="footer-links">
310
- <a href="../index.html">Home</a>
311
- <a href="../login.html">Login</a>
312
- <a href="../usage.html">Usage</a>
313
- <a href="../tokens.html">Tokens</a>
314
- <a href="../cookbook.html">Cookbook</a>
315
- <a href="../claude-skill.html">Claude Skill</a>
316
- <a href="https://magpiecloud.com/docs/mags" rel="noreferrer">Documentation</a>
317
- </div>
318
- </div>
319
- </footer>
320
-
321
- <script src="../script.js"></script>
322
- <script>
323
- (function () {
324
- var HN_API = 'https://hacker-news.firebaseio.com/v0';
325
- var KEYWORDS = /marketing|growth hack|seo|advertising|branding|brand strategy|content strategy|content marketing|acquisition|retention|funnel|conversion|gtm|go-to-market|product.led|newsletter|copywriting|social media|influencer|public relations|dtc|b2b marketing|b2c|demand gen|lead gen|campaign/i;
326
-
327
- var feedEl = document.getElementById('hn-feed');
328
- var lastCheckedEl = document.getElementById('hn-last-checked');
329
- var refreshBtn = document.getElementById('hn-refresh');
330
-
331
- function timeAgo(unixSeconds) {
332
- var diff = Math.floor(Date.now() / 1000) - unixSeconds;
333
- if (diff < 60) return diff + 's ago';
334
- if (diff < 3600) return Math.floor(diff / 60) + 'm ago';
335
- if (diff < 86400) return Math.floor(diff / 3600) + 'h ago';
336
- return Math.floor(diff / 86400) + 'd ago';
337
- }
338
-
339
- function renderStories(stories) {
340
- feedEl.innerHTML = '';
341
-
342
- if (!stories.length) {
343
- feedEl.innerHTML = '<div class="hn-empty"><p>No marketing-related stories in the current top 100.</p><p>Check back later — the feed updates with every refresh.</p></div>';
344
- return;
345
- }
346
-
347
- stories.forEach(function (story) {
348
- var card = document.createElement('div');
349
- card.className = 'hn-story';
350
-
351
- var link = story.url || ('https://news.ycombinator.com/item?id=' + story.id);
352
- var hnLink = 'https://news.ycombinator.com/item?id=' + story.id;
353
- var age = story.time ? timeAgo(story.time) : '';
354
-
355
- card.innerHTML =
356
- '<h4><a href="' + link + '" target="_blank" rel="noreferrer">' + escapeHtml(story.title) + '</a></h4>' +
357
- '<div class="hn-meta">' +
358
- '<span>' + (story.score || 0) + ' points</span>' +
359
- '<span>' + age + '</span>' +
360
- '<a href="' + hnLink + '" target="_blank" rel="noreferrer">Comments</a>' +
361
- '</div>';
362
-
363
- feedEl.appendChild(card);
364
- });
365
- }
366
-
367
- function escapeHtml(text) {
368
- var el = document.createElement('span');
369
- el.textContent = text;
370
- return el.innerHTML;
371
- }
372
-
373
- function fetchFeed() {
374
- refreshBtn.disabled = true;
375
- refreshBtn.textContent = 'Loading...';
376
- feedEl.innerHTML = '<div class="hn-loading">Fetching stories from Hacker News...</div>';
377
-
378
- fetch(HN_API + '/topstories.json')
379
- .then(function (res) { return res.json(); })
380
- .then(function (ids) {
381
- var first100 = ids.slice(0, 100);
382
- var fetches = first100.map(function (id) {
383
- return fetch(HN_API + '/item/' + id + '.json').then(function (r) { return r.json(); });
384
- });
385
- return Promise.all(fetches);
386
- })
387
- .then(function (items) {
388
- var matches = items.filter(function (item) {
389
- return item && item.title && KEYWORDS.test(item.title);
390
- });
391
- matches.sort(function (a, b) { return (b.score || 0) - (a.score || 0); });
392
- renderStories(matches);
393
- lastCheckedEl.textContent = 'Last checked: ' + new Date().toLocaleTimeString();
394
- })
395
- .catch(function (err) {
396
- feedEl.innerHTML = '<div class="hn-empty"><p>Failed to fetch stories. Check your connection and try again.</p></div>';
397
- lastCheckedEl.textContent = 'Error loading feed';
398
- })
399
- .finally(function () {
400
- refreshBtn.disabled = false;
401
- refreshBtn.textContent = 'Refresh';
402
- });
403
- }
404
-
405
- refreshBtn.addEventListener('click', fetchFeed);
406
- fetchFeed();
407
- })();
408
- </script>
409
- </body>
410
- </html>
@@ -1,42 +0,0 @@
1
- #!/bin/sh
2
- # hn-marketing.sh — Fetch top 10 HN stories and save to CSV
3
- # Dependencies: curl, jq (install with: apk add -q curl jq)
4
-
5
- set -e
6
-
7
- CSV="${HN_CSV:-./hn-top10.csv}"
8
- TIMESTAMP=$(date -u +"%Y-%m-%d %H:%M:%S UTC")
9
-
10
- # Write CSV header if file doesn't exist
11
- if [ ! -f "$CSV" ]; then
12
- echo "timestamp,rank,score,title,url,hn_link" > "$CSV"
13
- fi
14
-
15
- echo "=== HN Top 10 ==="
16
- echo "Fetched at: $TIMESTAMP"
17
- echo ""
18
-
19
- # Get top 10 story IDs
20
- IDS=$(curl -sf "https://hacker-news.firebaseio.com/v0/topstories.json" | jq -r '.[0:10] | .[]')
21
-
22
- RANK=0
23
- for ID in $IDS; do
24
- RANK=$((RANK + 1))
25
- ITEM=$(curl -sf "https://hacker-news.firebaseio.com/v0/item/${ID}.json")
26
-
27
- TITLE=$(echo "$ITEM" | jq -r '.title // "untitled"' | tr -d '\n\r' | sed 's/,/;/g')
28
- URL=$(echo "$ITEM" | jq -r '.url // ""' | tr -d '\n\r')
29
- SCORE=$(echo "$ITEM" | jq -r '.score // 0')
30
- HN_LINK="https://news.ycombinator.com/item?id=$ID"
31
-
32
- [ -z "$URL" ] && URL="$HN_LINK"
33
-
34
- echo "[$RANK] $TITLE"
35
- echo " Score: $SCORE | $URL"
36
- echo ""
37
-
38
- echo "$TIMESTAMP,$RANK,$SCORE,$TITLE,$URL,$HN_LINK" >> "$CSV"
39
- done
40
-
41
- echo "---"
42
- echo "Saved to $CSV"