clipbait 1.7.0 → 1.9.0
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 +4 -1
- package/index.js +64 -33
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -22,7 +22,7 @@ Opens Clipbait so you can copy your key, then installs a `/clipbait` slash comma
|
|
|
22
22
|
### Claude Code
|
|
23
23
|
|
|
24
24
|
```bash
|
|
25
|
-
claude mcp add --transport http clipbait https://app.clipbait.ai/api/mcp
|
|
25
|
+
claude mcp add --transport http clipbait https://app.clipbait.ai/api/mcp --header "X-API-Key: cbk_live_your_key_here"
|
|
26
26
|
```
|
|
27
27
|
|
|
28
28
|
### Cursor / Cline / Windsurf / manual
|
|
@@ -56,6 +56,9 @@ Seven tools are available to any agent:
|
|
|
56
56
|
| `start_live_autoclip` | Auto-clip a **live** Twitch stream continuously (`channelUrl`, optional `cadenceMin`). Pro plan. |
|
|
57
57
|
| `probe_video` | Get a video's duration before clipping (`url`). |
|
|
58
58
|
| `download_clip` | Save a finished clip to your `~/Downloads/` folder and return the path (`jobId`, `clipIndex` 1-based). Max 500 MB. |
|
|
59
|
+
| `list_social_accounts` | Show which accounts are connected for posting (X, TikTok, YouTube, Facebook). |
|
|
60
|
+
| `schedule_post` | Schedule a clip to post on connected socials at a future time (`clipUrl`, `platforms`, `scheduledTime`, `caption`). |
|
|
61
|
+
| `list_scheduled_posts` / `cancel_scheduled_post` | Review or cancel scheduled posts. |
|
|
59
62
|
|
|
60
63
|
## Terminal usage
|
|
61
64
|
|
package/index.js
CHANGED
|
@@ -13,6 +13,7 @@ const path = require("path");
|
|
|
13
13
|
const CFG = path.join(os.homedir(), ".clipbait.json");
|
|
14
14
|
const BASE = (process.env.CLIPBAIT_API_URL || "https://app.clipbait.ai/api").replace(/\/$/, "");
|
|
15
15
|
const KEY_PAGE = "https://app.clipbait.ai/me";
|
|
16
|
+
const MCP_URL = "https://app.clipbait.ai/api/mcp";
|
|
16
17
|
|
|
17
18
|
// Shown whenever there's no usable key. Written so an AI agent can relay it
|
|
18
19
|
// verbatim to the user and they'll know exactly what to do.
|
|
@@ -74,12 +75,14 @@ function prompt(question) {
|
|
|
74
75
|
// reads MCP servers from ~/.claude.json under projects[cwd].mcpServers (local
|
|
75
76
|
// scope) and, when present, a top-level mcpServers (user scope) — we write
|
|
76
77
|
// both so it shows up regardless of which directory Claude opens in.
|
|
77
|
-
function writeMcpConfig(
|
|
78
|
+
function writeMcpConfig(key) {
|
|
78
79
|
const cfgPath = path.join(os.homedir(), ".claude.json");
|
|
79
80
|
let cfg;
|
|
80
81
|
try { cfg = JSON.parse(fs.readFileSync(cfgPath, "utf8")); }
|
|
81
82
|
catch { return false; } // no/unreadable config → caller prints manual steps
|
|
82
|
-
|
|
83
|
+
// Key travels in an X-API-Key header, not the URL path — keeps it out of the
|
|
84
|
+
// URL (and request logs). It still lives in the config file, same as any MCP.
|
|
85
|
+
const entry = { type: "http", url: MCP_URL, headers: { "X-API-Key": key } };
|
|
83
86
|
cfg.mcpServers = cfg.mcpServers || {};
|
|
84
87
|
cfg.mcpServers.clipbait = entry;
|
|
85
88
|
const cwd = process.cwd();
|
|
@@ -104,14 +107,18 @@ argument-hint: <video-url> [what you want]
|
|
|
104
107
|
---
|
|
105
108
|
You have the \`clipbait\` MCP tools connected. The user's request: $ARGUMENTS
|
|
106
109
|
|
|
107
|
-
|
|
108
|
-
1.
|
|
109
|
-
2.
|
|
110
|
-
-
|
|
111
|
-
-
|
|
112
|
-
3. Call \`generate_clips\`, then poll \`get_job\` with the returned jobId every 30 seconds until status is "complete". Report progress between polls.
|
|
113
|
-
4. When complete, list each finished clip as a numbered list:
|
|
114
|
-
5. Then offer
|
|
110
|
+
Guide them like a friendly assistant, conversationally and fast:
|
|
111
|
+
1. Need a video URL — if none was given, ask for one (YouTube, Twitch VOD, Rumble, or Ganjing World).
|
|
112
|
+
2. Set params for \`generate_clips\` from their intent (offer the choice if unclear, don't over-ask):
|
|
113
|
+
- aspect ratio: 9:16 (vertical / TikTok / Reels) is the default; 16:9 for YouTube / landscape.
|
|
114
|
+
- number of clips: use a number if they mention one (1–20), otherwise 9.
|
|
115
|
+
3. Call \`generate_clips\`, then poll \`get_job\` with the returned jobId every ~30 seconds until status is "complete". Report progress between polls.
|
|
116
|
+
4. When complete, list each finished clip as a numbered list: hook and URL.
|
|
117
|
+
5. Then offer next steps and act on them by calling the tools:
|
|
118
|
+
- \`download_clip\` — save a clip to ~/Downloads.
|
|
119
|
+
- Post to social: call \`list_social_accounts\` to see connected platforms, then ask which platform(s), when to post (offer Today / Tomorrow / This weekend / a specific time), and the caption (offer to draft one). Show the plan (clip · platform · time · caption) and CONFIRM before calling \`schedule_post\` for each clip. Use \`list_scheduled_posts\` / \`cancel_scheduled_post\` to review or undo.
|
|
120
|
+
- Regenerate at a different aspect ratio, pull more clips, or \`probe_video\` another URL.
|
|
121
|
+
Keep it snappy. Don't ask for confirmation to start clipping unless the URL is missing — but always confirm before posting to social.
|
|
115
122
|
`;
|
|
116
123
|
|
|
117
124
|
// Claude Desktop config path per-OS.
|
|
@@ -143,55 +150,66 @@ function writeDesktopConfig(key) {
|
|
|
143
150
|
// Interactive one-command setup. Grabs the key (from arg / saved / by opening
|
|
144
151
|
// the browser and prompting), installs the /clipbait command, and connects the
|
|
145
152
|
// MCP server to Claude Code and Claude Desktop.
|
|
153
|
+
// Print the exact config for the user/agent to apply, WITHOUT touching any
|
|
154
|
+
// files. Used in non-interactive contexts (an agent ran this): silently
|
|
155
|
+
// rewriting global AI-tool config there reads as a supply-chain attack, so we
|
|
156
|
+
// stay transparent and let the caller apply it with full visibility.
|
|
157
|
+
function printManualConfig(key) {
|
|
158
|
+
console.log("\nTo connect Clipbait, apply one of these (nothing was written — you're not in an interactive terminal):\n");
|
|
159
|
+
console.log("Claude Code:");
|
|
160
|
+
console.log(` claude mcp add --transport http clipbait ${MCP_URL} --header "X-API-Key: ${key}"\n`);
|
|
161
|
+
console.log("Claude Desktop / Cursor / Cline / Windsurf — add to the MCP config:");
|
|
162
|
+
console.log(` ${JSON.stringify({ mcpServers: { clipbait: { command: "npx", args: ["-y", "clipbait@latest", "mcp"], env: { CLIPBAIT_API_KEY: key } } } })}\n`);
|
|
163
|
+
console.log(`Tip: run \`npx clipbait@latest\` in a real terminal to apply this automatically.\n`);
|
|
164
|
+
}
|
|
165
|
+
|
|
146
166
|
async function runSetup(providedKey) {
|
|
167
|
+
const interactive = !!process.stdin.isTTY;
|
|
147
168
|
let key = providedKey && providedKey.startsWith("cbk_") ? providedKey : loadKey();
|
|
148
169
|
|
|
149
170
|
if (!key) {
|
|
171
|
+
if (!interactive) { console.error(NEED_KEY); process.exit(1); }
|
|
150
172
|
console.log("\n⚡ Let's connect Clipbait to Claude.");
|
|
151
|
-
if (!process.stdin.isTTY) {
|
|
152
|
-
// No interactive terminal (e.g. an AI agent ran this). Print the full
|
|
153
|
-
// guidance so the agent can pass it straight to the user.
|
|
154
|
-
console.error(NEED_KEY);
|
|
155
|
-
process.exit(1);
|
|
156
|
-
}
|
|
157
173
|
console.log(`\nOpening ${KEY_PAGE} so you can copy your API key…`);
|
|
158
174
|
openBrowser(KEY_PAGE);
|
|
159
175
|
key = (await prompt("\nPaste your API key (starts with cbk_) and press Enter:\n> ")).trim();
|
|
160
176
|
}
|
|
177
|
+
if (!key || !key.startsWith("cbk_")) { console.error(NEED_KEY); process.exit(1); }
|
|
161
178
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
179
|
+
// Non-interactive (agent / pipe): don't silently modify global config. Print
|
|
180
|
+
// it and let the caller apply it with consent.
|
|
181
|
+
if (!interactive) { printManualConfig(key); return; }
|
|
182
|
+
|
|
183
|
+
// Interactive: announce exactly what will change BEFORE writing anything, so
|
|
184
|
+
// it never looks like a package quietly registering itself.
|
|
185
|
+
console.log("\n⚡ Clipbait setup will make these changes on this machine:");
|
|
186
|
+
console.log(" • save your API key to ~/.clipbait.json");
|
|
187
|
+
console.log(" • install a /clipbait slash command (~/.claude/commands/clipbait.md)");
|
|
188
|
+
console.log(" • register the Clipbait MCP server in Claude Code (~/.claude.json)");
|
|
189
|
+
console.log(" • register it in Claude Desktop, if installed\n");
|
|
166
190
|
|
|
167
191
|
fs.writeFileSync(CFG, JSON.stringify({ apiKey: key }, null, 2));
|
|
168
|
-
const mcpUrl = "https://app.clipbait.ai/api/mcp/" + key;
|
|
169
192
|
|
|
170
|
-
// 1) Install the /clipbait slash command for Claude Code.
|
|
171
193
|
const cmdDir = path.join(os.homedir(), ".claude", "commands");
|
|
172
194
|
fs.mkdirSync(cmdDir, { recursive: true });
|
|
173
195
|
fs.writeFileSync(path.join(cmdDir, "clipbait.md"), SLASH_COMMAND);
|
|
174
196
|
console.log("✓ Installed the /clipbait command for Claude Code");
|
|
175
197
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
// printing manual steps.
|
|
179
|
-
if (writeMcpConfig(mcpUrl)) {
|
|
180
|
-
console.log("✓ Connected the Clipbait MCP server to Claude Code");
|
|
198
|
+
if (writeMcpConfig(key)) {
|
|
199
|
+
console.log("✓ Registered the Clipbait MCP server in Claude Code");
|
|
181
200
|
} else {
|
|
182
201
|
const { spawnSync } = require("child_process");
|
|
183
|
-
const r = spawnSync("claude", ["mcp", "add", "--transport", "http", "clipbait",
|
|
202
|
+
const r = spawnSync("claude", ["mcp", "add", "--transport", "http", "clipbait", MCP_URL, "--header", `X-API-Key: ${key}`], { stdio: "ignore" });
|
|
184
203
|
if (!r.error && r.status === 0) {
|
|
185
|
-
console.log("✓
|
|
204
|
+
console.log("✓ Registered the Clipbait MCP server in Claude Code");
|
|
186
205
|
} else {
|
|
187
|
-
console.log("• Couldn't auto-
|
|
188
|
-
console.log(
|
|
206
|
+
console.log("• Couldn't auto-register the MCP server. Add it manually:");
|
|
207
|
+
console.log(` claude mcp add --transport http clipbait ${MCP_URL} --header "X-API-Key: ${key}"`);
|
|
189
208
|
}
|
|
190
209
|
}
|
|
191
210
|
|
|
192
|
-
// 3) Also configure Claude Desktop if installed (stdio server → download_clip).
|
|
193
211
|
if (writeDesktopConfig(key)) {
|
|
194
|
-
console.log("✓
|
|
212
|
+
console.log("✓ Registered Clipbait in Claude Desktop (quit + reopen it to load)");
|
|
195
213
|
}
|
|
196
214
|
|
|
197
215
|
console.log("\n🎬 Done! Restart Claude Code, then type:\n /clipbait https://youtube.com/watch?v=…\n");
|
|
@@ -261,6 +279,19 @@ async function runMcpServer() {
|
|
|
261
279
|
} catch (e) { return fail(e); }
|
|
262
280
|
});
|
|
263
281
|
|
|
282
|
+
server.tool("list_social_accounts", "List which social accounts are connected for posting (X, TikTok, YouTube, Facebook). Check before scheduling.", {},
|
|
283
|
+
async () => { try { const d = await api("GET", "/auth/social/status"); const map = { twitter: "x", tiktok: "tiktok", youtube: "youtube", facebook: "facebook" }; const c = Object.entries(d || {}).filter(([, v]) => v && v.connected).map(([k]) => map[k] || k); return ok(c.length ? `Connected for posting: ${c.join(", ")}` : "No social accounts connected yet. Connect them at https://app.clipbait.ai/me."); } catch (e) { return fail(e); } });
|
|
284
|
+
|
|
285
|
+
server.tool("schedule_post", "Schedule a finished clip to post on connected social accounts at a future time. Get clip URLs from get_job first; confirm the platform is connected via list_social_accounts.",
|
|
286
|
+
{ clipUrl: z.string(), platforms: z.array(z.enum(["x", "tiktok", "youtube", "facebook"])).min(1), scheduledTime: z.string().describe("Future ISO 8601 time"), caption: z.string().optional(), clipTitle: z.string().optional(), clipJobId: z.string().optional(), clipIndex: z.number().int().optional() },
|
|
287
|
+
async (a) => { try { const d = await api("POST", "/scheduled-posts", { clipUrl: a.clipUrl, platforms: a.platforms, scheduledTime: a.scheduledTime, caption: a.caption || "", clipTitle: a.clipTitle, clipJobId: a.clipJobId, clipIndex: a.clipIndex }); return ok(`Scheduled to ${a.platforms.join(", ")} for ${a.scheduledTime} (post ${d.scheduledPost?._id || "?"}).`); } catch (e) { return fail(e); } });
|
|
288
|
+
|
|
289
|
+
server.tool("list_scheduled_posts", "List the user's scheduled/posted social posts.", { status: z.enum(["pending", "posted", "failed", "cancelled"]).optional() },
|
|
290
|
+
async (a) => { try { const d = await api("GET", "/scheduled-posts" + (a.status ? `?status=${a.status}` : "")); const posts = (d.posts || []).slice(0, 20).map((p) => `${p._id} · ${p.status} · ${(p.platforms || []).map((x) => x.name).join(",")} · ${new Date(p.scheduledTime).toISOString()} · ${p.clipTitle || ""}`).join("\n"); return ok(posts || "No scheduled posts."); } catch (e) { return fail(e); } });
|
|
291
|
+
|
|
292
|
+
server.tool("cancel_scheduled_post", "Cancel a scheduled post before it goes live.", { postId: z.string() },
|
|
293
|
+
async (a) => { try { await api("DELETE", "/scheduled-posts/" + a.postId); return ok(`Cancelled scheduled post ${a.postId}.`); } catch (e) { return fail(e); } });
|
|
294
|
+
|
|
264
295
|
await server.connect(new StdioServerTransport());
|
|
265
296
|
}
|
|
266
297
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clipbait",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.9.0",
|
|
4
4
|
"description": "Clipbait CLI + MCP server — turn any video into viral clips, and auto-clip live streams, from your terminal or any AI agent.",
|
|
5
5
|
"bin": { "clipbait": "index.js" },
|
|
6
6
|
"type": "commonjs",
|