forkfeed-mcp 1.3.5 → 1.3.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/dist/guide-content.js +15 -16
- package/dist/index.js +23 -23
- package/package.json +1 -1
package/dist/guide-content.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
export const GUIDE_CONTENT = `
|
|
7
7
|
# Forkfeed Content Guide - "The Fuck I Pushed"
|
|
8
8
|
|
|
9
|
-
Turn GitHub commits into swipeable card content. One fork per repo, one feed per commit,
|
|
9
|
+
Turn GitHub commits into swipeable card content. One fork per repo, one feed per commit, 6 cards per feed.
|
|
10
10
|
|
|
11
11
|
**Process exactly ONE commit at a time, never multiple.**
|
|
12
12
|
|
|
@@ -55,15 +55,15 @@ Only 5 fields + cards. Everything else is auto-populated.
|
|
|
55
55
|
| \`{ "code": "const x = 1", "lang": "typescript" }\` | CONTENT_CODE | Real code from diff, 5-20 lines, strip +/- prefixes |
|
|
56
56
|
| \`{ "subtext": "Pro tip..." }\` | CONTENT_SUBTEXT | Aside or protip |
|
|
57
57
|
| \`{ "name": "Chad", "subtitle": "10x Engineer", "avatar": "img98", "source": "linkedin" }\` | CONTENT_SOCIAL | Card 2 only. avatar can be image ID or URL. source: x, linkedin, threads, etc. |
|
|
58
|
-
| \`{ "question": "What does X do?", "options": [{"label": "A", "correct": false}, {"label": "B", "correct": true}], "explanation": "Because..." }\` | CONTENT_QUIZ | Card
|
|
59
|
-
| \`{ "label": "Google it", "action": "url", "target": "https://google.com/search?q=topic" }\` | CONTENT_BUTTON | Card
|
|
58
|
+
| \`{ "question": "What does X do?", "options": [{"label": "A", "correct": false}, {"label": "B", "correct": true}], "explanation": "Because..." }\` | CONTENT_QUIZ | Card 5 only. 4 options recommended, min 2, one correct, always include explanation |
|
|
59
|
+
| \`{ "label": "Google it", "action": "url", "target": "https://google.com/search?q=topic" }\` | CONTENT_BUTTON | Card 3 only, MUST be last block in every detail variant |
|
|
60
60
|
|
|
61
61
|
### What the builder does automatically
|
|
62
62
|
- Detects repo owner/name from git remote
|
|
63
63
|
- Generates fork/feed IDs from convention (tfip-{owner}-{repo}-{sha})
|
|
64
64
|
- Constructs GitHub action URL
|
|
65
65
|
- Fetches existing feed IDs from server (for incremental updates)
|
|
66
|
-
- Assigns
|
|
66
|
+
- Assigns 6 unique card backgrounds from preference table + commit tags
|
|
67
67
|
- Generates UUID v4 for each card ID
|
|
68
68
|
- Resolves short image IDs (img47, bg10) to full CDN URLs
|
|
69
69
|
- Adds FULL_IMAGE cover variant with fixed title/subtitle per card type
|
|
@@ -71,13 +71,13 @@ Only 5 fields + cards. Everything else is auto-populated.
|
|
|
71
71
|
- Validates the assembled manifest before pushing
|
|
72
72
|
|
|
73
73
|
### Optional overrides
|
|
74
|
-
- \`bgOverride\`: array of
|
|
75
|
-
- \`coverOverride\`: array of
|
|
74
|
+
- \`bgOverride\`: array of 6 background IDs to override auto-assignment
|
|
75
|
+
- \`coverOverride\`: array of 6 cover image IDs (defaults to backgrounds)
|
|
76
76
|
- \`cwd\`: working directory if not process.cwd()
|
|
77
77
|
|
|
78
78
|
---
|
|
79
79
|
|
|
80
|
-
## The
|
|
80
|
+
## The 6 cards
|
|
81
81
|
|
|
82
82
|
Each card = array of detail variants (cover is auto-generated). Provide 1+ variants per card. Quality over quantity: pick only the most impactful, funny, or educational content.
|
|
83
83
|
|
|
@@ -86,10 +86,9 @@ Each card = array of detail variants (cover is auto-generated). Provide 1+ varia
|
|
|
86
86
|
| 0 | Explain like I'm 5 | 2-3 | img -> title -> text | Playful, zero jargon |
|
|
87
87
|
| 1 | The roast | 2-3 | img -> title -> text, optional subtext | Maximum cheekiness, swearing ok |
|
|
88
88
|
| 2 | The LinkedIn post | 2-3 | social -> title -> text | Peak LinkedIn parody |
|
|
89
|
-
| 3 |
|
|
90
|
-
| 4 |
|
|
91
|
-
| 5 |
|
|
92
|
-
| 6 | Quiz | 4-6 | title -> quiz (no img blocks) | Quiz show energy |
|
|
89
|
+
| 3 | Learning moment | 2-3 | img -> title -> text -> optional code -> button(last) | Teach with personality |
|
|
90
|
+
| 4 | Alternatives | 2-3 | img -> title -> text -> optional code | Constructive snark |
|
|
91
|
+
| 5 | Quiz | 4-6 | title -> quiz (no img blocks) | Quiz show energy |
|
|
93
92
|
|
|
94
93
|
### Card 2 personas (LinkedIn)
|
|
95
94
|
- Chad Gitpush: "10x Engineer | Building in Public | DMs Open"
|
|
@@ -100,13 +99,13 @@ Each card = array of detail variants (cover is auto-generated). Provide 1+ varia
|
|
|
100
99
|
|
|
101
100
|
## Key rules
|
|
102
101
|
|
|
103
|
-
- Exactly
|
|
102
|
+
- Exactly 6 cards in the cards array (one per section above)
|
|
104
103
|
- Use short image IDs from forkfeed_commits output (img47, not full URLs)
|
|
105
104
|
- 8-12 unique scene images (img*) across the feed, no duplicate within same card
|
|
106
|
-
- Cards 0-
|
|
107
|
-
- Card
|
|
108
|
-
- Card
|
|
109
|
-
- Card
|
|
105
|
+
- Cards 0-3: code must be REAL from the diff (never fabricated)
|
|
106
|
+
- Card 4: synthesized code IS allowed
|
|
107
|
+
- Card 5: no img blocks, quiz blocks only (with title per variant)
|
|
108
|
+
- Card 3: every detail variant MUST end with a button block
|
|
110
109
|
- Card 2: first block should be social (not img), no engagement metrics subtext (reactions, comments, reposts)
|
|
111
110
|
- CONTENT_QUIZ: 4 options recommended (min 2), exactly one correct, always include explanation
|
|
112
111
|
- No em dashes, smart quotes, or non-ASCII characters
|
package/dist/index.js
CHANGED
|
@@ -219,12 +219,11 @@ const BG_PREFS = [
|
|
|
219
219
|
['bg10', 'bg27'], // 0: ELI5
|
|
220
220
|
['bg11', 'bg1'], // 1: Roast
|
|
221
221
|
['bg25', 'bg24'], // 2: LinkedIn
|
|
222
|
-
['
|
|
223
|
-
['
|
|
224
|
-
['
|
|
225
|
-
['bg18', 'bg5'], // 6: Quiz
|
|
222
|
+
['bg12', 'bg13', 'bg14', 'bg15', 'bg17'], // 3: Learning (tech-match)
|
|
223
|
+
['bg25', 'bg30'], // 4: Alternatives
|
|
224
|
+
['bg18', 'bg5'], // 5: Quiz
|
|
226
225
|
];
|
|
227
|
-
// Map language tags to preferred Learning card (index
|
|
226
|
+
// Map language tags to preferred Learning card (index 3) backgrounds
|
|
228
227
|
const LANG_BG = {
|
|
229
228
|
javascript: 'bg12', typescript: 'bg12',
|
|
230
229
|
python: 'bg13',
|
|
@@ -234,8 +233,8 @@ const LANG_BG = {
|
|
|
234
233
|
};
|
|
235
234
|
function assignBackgrounds(tags) {
|
|
236
235
|
const used = new Set();
|
|
237
|
-
// For card
|
|
238
|
-
const learningPrefs = [...BG_PREFS[
|
|
236
|
+
// For card 3 (Learning), reorder prefs based on detected language tags
|
|
237
|
+
const learningPrefs = [...BG_PREFS[3]];
|
|
239
238
|
for (const tag of tags) {
|
|
240
239
|
const preferred = LANG_BG[tag];
|
|
241
240
|
if (preferred && learningPrefs.includes(preferred)) {
|
|
@@ -246,7 +245,7 @@ function assignBackgrounds(tags) {
|
|
|
246
245
|
}
|
|
247
246
|
}
|
|
248
247
|
return BG_PREFS.map((prefs, i) => {
|
|
249
|
-
const candidates = i ===
|
|
248
|
+
const candidates = i === 3 ? learningPrefs : prefs;
|
|
250
249
|
const pick = candidates.find((bg) => !used.has(bg)) || candidates[0];
|
|
251
250
|
used.add(pick);
|
|
252
251
|
return pick;
|
|
@@ -283,13 +282,12 @@ async function fetchStatusData() {
|
|
|
283
282
|
}
|
|
284
283
|
// ── Cover titles (fixed per card index) ──────────────────────────────
|
|
285
284
|
const COVERS = [
|
|
286
|
-
{ title: "Explain Like I'm 5", subtitle: "Hopefully now you'll understand what you pushed" },
|
|
287
|
-
{ title: "The Roast", subtitle: "Your code had it coming" },
|
|
288
|
-
{ title: "The LinkedIn Post", subtitle: "Mass cringe, freshly generated" },
|
|
289
|
-
{ title: "
|
|
290
|
-
{ title: "
|
|
291
|
-
{ title: "
|
|
292
|
-
{ title: "Quiz", subtitle: "Let's see if you even understand your own code" },
|
|
285
|
+
{ title: "🧒 Explain Like I'm 5", subtitle: "Hopefully now you'll understand what you pushed" },
|
|
286
|
+
{ title: "🔥 The Roast", subtitle: "Your code had it coming" },
|
|
287
|
+
{ title: "💼 The LinkedIn Post", subtitle: "Mass cringe, freshly generated" },
|
|
288
|
+
{ title: "💡 Learning Moment", subtitle: "Something useful buried in your chaos" },
|
|
289
|
+
{ title: "🔀 Alternatives", subtitle: "What you could have done instead" },
|
|
290
|
+
{ title: "🧠 Quiz", subtitle: "Let's see if you even understand your own code" },
|
|
293
291
|
];
|
|
294
292
|
// ── Simplified block inference ───────────────────────────────────────
|
|
295
293
|
function inferBlock(block) {
|
|
@@ -356,10 +354,10 @@ const buildInputSchema = z.object({
|
|
|
356
354
|
variants: z.array(z.object({
|
|
357
355
|
blocks: z.array(z.record(z.string(), z.unknown())).min(1),
|
|
358
356
|
})).min(1),
|
|
359
|
-
})).length(
|
|
357
|
+
})).length(6),
|
|
360
358
|
cwd: z.string().optional().describe('Working directory (defaults to process.cwd())'),
|
|
361
|
-
bgOverride: z.array(z.string()).length(
|
|
362
|
-
coverOverride: z.array(z.string()).length(
|
|
359
|
+
bgOverride: z.array(z.string()).length(6).optional().describe('Override auto-assigned background IDs'),
|
|
360
|
+
coverOverride: z.array(z.string()).length(6).optional().describe('Override cover image IDs (defaults to backgrounds)'),
|
|
363
361
|
});
|
|
364
362
|
// ── Manifest builder ─────────────────────────────────────────────────
|
|
365
363
|
async function buildManifest(input) {
|
|
@@ -475,9 +473,11 @@ async function pushManifestToServer(manifest) {
|
|
|
475
473
|
const forkSummary = data.forks
|
|
476
474
|
?.map((f) => ` - ${f.title} (${f.feeds} feeds)`)
|
|
477
475
|
.join('\n');
|
|
476
|
+
// Use the real MongoDB ObjectId returned by the server, not the manifest slug
|
|
477
|
+
const realForkId = data.forks?.[0]?.forkId || forkId;
|
|
478
478
|
let qrBlock = '';
|
|
479
|
-
if (
|
|
480
|
-
const url = `https://forkfeed.link/fork/${
|
|
479
|
+
if (realForkId) {
|
|
480
|
+
const url = `https://forkfeed.link/fork/${realForkId}`;
|
|
481
481
|
try {
|
|
482
482
|
const qr = await QRCode.toString(url, { type: 'utf8', errorCorrectionLevel: 'L' });
|
|
483
483
|
qrBlock = ['', 'Scan to open in forkfeed:', '', qr].join('\n');
|
|
@@ -646,7 +646,7 @@ server.tool('forkfeed_push', 'Push a generated manifest (forks, feeds, cards) to
|
|
|
646
646
|
});
|
|
647
647
|
// ── Tool: forkfeed_build ──────────────────────────────────────────────
|
|
648
648
|
server.tool('forkfeed_build', 'Build a forkfeed manifest from simplified content and push it. Auto-detects repo info, assigns backgrounds, fetches existing feeds. Use this instead of forkfeed_push.', {
|
|
649
|
-
content: buildInputSchema.describe('Simplified content: sha, titles, descriptions, and
|
|
649
|
+
content: buildInputSchema.describe('Simplified content: sha, titles, descriptions, and 6 cards with blocks'),
|
|
650
650
|
push: z.boolean().optional().describe('Push immediately after building (default: true)'),
|
|
651
651
|
}, async ({ content, push }) => {
|
|
652
652
|
const shouldPush = push !== false;
|
|
@@ -742,7 +742,7 @@ server.tool('forkfeed_status', 'Check your current forkfeed content: which forks
|
|
|
742
742
|
}
|
|
743
743
|
});
|
|
744
744
|
// ── Prompt: /forkfeed ──────────────────────────────────────────────────
|
|
745
|
-
server.prompt('forkfeed', 'Turn GitHub commits into swipeable forkfeed content. Analyzes your repo, generates
|
|
745
|
+
server.prompt('forkfeed', 'Turn GitHub commits into swipeable forkfeed content. Analyzes your repo, generates 6-card feeds, and pushes them live.', async () => ({
|
|
746
746
|
messages: [
|
|
747
747
|
{
|
|
748
748
|
role: 'user',
|
|
@@ -753,7 +753,7 @@ server.prompt('forkfeed', 'Turn GitHub commits into swipeable forkfeed content.
|
|
|
753
753
|
1. Call **forkfeed_guide** and **forkfeed_commits()** in parallel (no arguments for commits = list mode).
|
|
754
754
|
2. Show the commits table from forkfeed_commits. It already indicates which commits have published feeds. Ask which ONE commit to process. One commit at a time, never more. Do NOT ask about image style.
|
|
755
755
|
3. Call **forkfeed_commits** with the selected commit SHA. This returns the diff, file stats, and suggested scene images. Do NOT run git commands yourself.
|
|
756
|
-
4. Generate the simplified content JSON: sha, feedTitle, feedDescription, forkTitle, forkDescription, and
|
|
756
|
+
4. Generate the simplified content JSON: sha, feedTitle, feedDescription, forkTitle, forkDescription, and 6 cards with blocks. Use short image IDs (img47) for inline images. Do NOT provide owner, repo, backgrounds, existingFeedIds, UUIDs, covers, or type wrappers. The builder auto-detects and generates all of that.
|
|
757
757
|
5. Call **forkfeed_build** with the simplified content (push defaults to true).
|
|
758
758
|
6. Display the QR code block from the push result exactly as returned, so the user can scan it.
|
|
759
759
|
|