@posteverywhere/cli 0.1.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 ADDED
@@ -0,0 +1,27 @@
1
+ # @posteverywhere/cli
2
+
3
+ The PostEverywhere CLI for AI agents — schedule and publish to Instagram, TikTok, YouTube, LinkedIn, Facebook, X, Threads, Pinterest, Bluesky, Telegram and Discord from the command line. Every command outputs structured JSON for agents (Claude, Cursor, OpenClaw, …) to parse.
4
+
5
+ ## Quick start
6
+
7
+ ```bash
8
+ export POSTEVERYWHERE_API_KEY=pe_live_... # Settings → Developers in the dashboard
9
+
10
+ npx @posteverywhere/cli whoami # verify the key
11
+ npx @posteverywhere/cli accounts # list connected accounts (+ ids)
12
+ npx @posteverywhere/cli post -c "Hello 🚀" -a 123,456 # publish now
13
+ npx @posteverywhere/cli post -c "Later" -a 123 -s 2026-07-01T09:00:00Z # schedule (UTC)
14
+ ```
15
+
16
+ Run `npx @posteverywhere/cli help` for the full command list.
17
+
18
+ ## For AI agents
19
+
20
+ This package ships a `SKILL.md` describing the commands for agent auto-discovery. Point your agent at it, or connect via MCP instead:
21
+
22
+ - **Hosted MCP (no install):** `https://mcp.posteverywhere.ai` — see [docs](https://developers.posteverywhere.ai/integrations/mcp)
23
+ - **Local MCP:** `npx -y @posteverywhere/mcp`
24
+
25
+ ## Auth & safety
26
+
27
+ Your API key authenticates into **your PostEverywhere account** and acts only through it — the CLI never touches your social-platform credentials directly. Keep a human in the loop before publishing.
package/SKILL.md ADDED
@@ -0,0 +1,51 @@
1
+ ---
2
+ name: posteverywhere
3
+ description: Schedule and publish social media posts to Instagram, TikTok, YouTube, LinkedIn, Facebook, X, Threads, Pinterest, Bluesky, Telegram and Discord. Use when the user asks to post, schedule, draft, or analyze social media content, or to list their connected social accounts.
4
+ ---
5
+
6
+ # PostEverywhere
7
+
8
+ Manage a user's social media through the PostEverywhere CLI. Every command prints JSON.
9
+
10
+ ## Setup (once)
11
+ The user must set their API key (from posteverywhere.ai → Settings → Developers):
12
+ ```bash
13
+ export POSTEVERYWHERE_API_KEY=pe_live_...
14
+ ```
15
+ Run commands with `npx @posteverywhere/cli <command>` (or `posteverywhere <command>` if installed).
16
+
17
+ ## Always start here
18
+ 1. `posteverywhere whoami` — confirms the key works and shows the plan/quota.
19
+ 2. `posteverywhere accounts` — lists connected accounts. **You need the numeric account `id`s to post.** If empty, tell the user to connect accounts in the dashboard first.
20
+
21
+ ## Core workflow
22
+ **Publish now** to accounts 123 and 456:
23
+ ```bash
24
+ posteverywhere post -c "Launch day! 🚀" -a 123,456
25
+ ```
26
+ **Schedule** (ISO-8601 UTC; include -s):
27
+ ```bash
28
+ posteverywhere post -c "Weekly tips thread" -a 123 -s 2026-07-01T09:00:00Z
29
+ ```
30
+ **With an image** — import it first, then attach the returned `media_id`:
31
+ ```bash
32
+ posteverywhere upload https://example.com/photo.jpg # → { "media_id": "..." }
33
+ posteverywhere post -c "New drop" -a 123 -m <media_id>
34
+ ```
35
+
36
+ ## Checking results
37
+ - `posteverywhere posts --status published --limit 10` — recent posts
38
+ - `posteverywhere results <postId>` — per-platform success/failure for one post
39
+ - `posteverywhere retry <postId>` — retry any failed platforms
40
+ - `posteverywhere account:health <id>` — why an account can't post (e.g. needs reconnect)
41
+
42
+ ## Other
43
+ - `posteverywhere caption -t "summer sale" --platform instagram --tone playful` — AI captions
44
+ - `posteverywhere analytics --period month` — performance summary
45
+ - `posteverywhere campaigns` — list campaigns
46
+
47
+ ## Rules
48
+ - **Always `accounts` before `post`** — never guess account ids.
49
+ - **Always confirm content + target accounts with the user before publishing.** Keep a human in the loop.
50
+ - Times are UTC ISO-8601. Omit `-s` to publish immediately.
51
+ - On error the CLI prints `{"error": "..."}` to stderr and exits non-zero — read it and relay the cause (often: account needs reconnect, out of quota, or media not ready).
package/dist/index.js ADDED
@@ -0,0 +1,173 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * PostEverywhere CLI for AI agents (task #245, "skill" distribution).
5
+ *
6
+ * Thin wrapper over the public v1 REST API. Every command prints structured
7
+ * JSON to stdout so agents (Claude, Cursor, OpenClaw, etc.) can parse results.
8
+ * Auth: set POSTEVERYWHERE_API_KEY=pe_live_... (Settings → Developers).
9
+ *
10
+ * Same surface as the MCP server, for agents that run shell commands rather
11
+ * than speak MCP. See SKILL.md for the agent-facing command reference.
12
+ */
13
+ const BASE = (process.env.POSTEVERYWHERE_API_URL || 'https://app.posteverywhere.ai').replace(/\/$/, '');
14
+ const KEY = process.env.POSTEVERYWHERE_API_KEY || '';
15
+ function out(data) {
16
+ process.stdout.write(JSON.stringify(data, null, 2) + '\n');
17
+ }
18
+ function fail(message, code = 1) {
19
+ process.stderr.write(JSON.stringify({ error: message }) + '\n');
20
+ process.exit(code);
21
+ }
22
+ // Parse "cmd positional --flag value -f value --bool" into { _: [...], flags }.
23
+ function parseArgs(argv) {
24
+ const positional = [];
25
+ const flags = {};
26
+ for (let i = 0; i < argv.length; i++) {
27
+ const a = argv[i];
28
+ if (a.startsWith('--') || a.startsWith('-')) {
29
+ const key = a.replace(/^-+/, '');
30
+ const next = argv[i + 1];
31
+ if (next !== undefined && !next.startsWith('-')) {
32
+ flags[key] = next;
33
+ i++;
34
+ }
35
+ else
36
+ flags[key] = true;
37
+ }
38
+ else
39
+ positional.push(a);
40
+ }
41
+ return { positional, flags };
42
+ }
43
+ async function api(method, path, body) {
44
+ if (!KEY || !KEY.startsWith('pe_live_')) {
45
+ fail('Missing or invalid POSTEVERYWHERE_API_KEY (must start with pe_live_). Create one at ' + BASE + ' → Settings → Developers.');
46
+ }
47
+ let resp;
48
+ try {
49
+ resp = await fetch(`${BASE}/api/v1${path}`, {
50
+ method,
51
+ headers: { Authorization: `Bearer ${KEY}`, ...(body ? { 'Content-Type': 'application/json' } : {}) },
52
+ body: body ? JSON.stringify(body) : undefined,
53
+ });
54
+ }
55
+ catch (e) {
56
+ fail(`Network error: ${e instanceof Error ? e.message : String(e)}`);
57
+ }
58
+ const json = await resp.json().catch(() => ({ error: { message: `HTTP ${resp.status}` } }));
59
+ if (json.error)
60
+ fail(typeof json.error === 'string' ? json.error : json.error.message || 'API error');
61
+ return json.data;
62
+ }
63
+ const csv = (v) => (typeof v === 'string' ? v.split(',').map((s) => s.trim()).filter(Boolean) : []);
64
+ const num = (v) => csv(v).map(Number).filter((n) => !Number.isNaN(n));
65
+ const HELP = `PostEverywhere CLI — manage social media from the command line / AI agents.
66
+
67
+ Auth: export POSTEVERYWHERE_API_KEY=pe_live_... (Settings → Developers)
68
+
69
+ Commands:
70
+ whoami Show the authed account, quota, and scopes
71
+ accounts List connected social accounts (+ their ids/health)
72
+ account:health <id> Detailed health for one account
73
+ post -c <text> -a <ids> [-s <iso>] [-m <media_ids>]
74
+ Create/schedule a post (-a = comma account ids; omit -s = publish now)
75
+ posts [--status x] [--platform y] [--limit n]
76
+ List posts
77
+ results <postId> Per-platform publish results for a post
78
+ retry <postId> Retry failed destinations of a post
79
+ upload <imageUrl> Import an image by URL (one-call), returns media_id
80
+ caption -t <topic> [--platform x] [--tone y]
81
+ Generate AI captions
82
+ analytics [--period week|month|all]
83
+ Account analytics summary
84
+ campaigns List campaigns
85
+
86
+ All output is JSON on stdout. Errors are JSON on stderr with a non-zero exit.
87
+ Docs: https://developers.posteverywhere.ai/integrations/mcp`;
88
+ async function main() {
89
+ const [, , cmd, ...rest] = process.argv;
90
+ const { positional, flags } = parseArgs(rest);
91
+ const f = (k, alias) => (flags[k] ?? (alias ? flags[alias] : undefined));
92
+ switch (cmd) {
93
+ case undefined:
94
+ case 'help':
95
+ case '--help':
96
+ case '-h':
97
+ process.stdout.write(HELP + '\n');
98
+ return;
99
+ case 'whoami':
100
+ return out(await api('GET', '/me'));
101
+ case 'accounts':
102
+ return out(await api('GET', '/accounts'));
103
+ case 'account:health': {
104
+ const id = positional[0];
105
+ if (!id)
106
+ fail('Usage: posteverywhere account:health <accountId>');
107
+ return out(await api('GET', `/accounts/${id}/health`));
108
+ }
109
+ case 'post': {
110
+ const content = f('content', 'c');
111
+ const accounts = num(f('accounts', 'a'));
112
+ if (typeof content !== 'string' || !content)
113
+ fail('Usage: post -c "text" -a 123,456 [-s 2026-07-01T09:00:00Z] [-m mediaId1,mediaId2]');
114
+ if (!accounts.length)
115
+ fail('At least one account id is required (-a 123,456). Run `posteverywhere accounts` to list ids.');
116
+ const body = { content, account_ids: accounts };
117
+ const sched = f('schedule', 's');
118
+ if (typeof sched === 'string') {
119
+ body.scheduled_for = sched;
120
+ body.timezone = f('timezone') || 'UTC';
121
+ }
122
+ const media = csv(f('media', 'm'));
123
+ if (media.length)
124
+ body.media_ids = media;
125
+ return out(await api('POST', '/posts', body));
126
+ }
127
+ case 'posts': {
128
+ const q = new URLSearchParams();
129
+ if (typeof f('status') === 'string')
130
+ q.set('status', f('status'));
131
+ if (typeof f('platform') === 'string')
132
+ q.set('platform', f('platform'));
133
+ q.set('limit', String(f('limit') || 20));
134
+ return out(await api('GET', `/posts?${q.toString()}`));
135
+ }
136
+ case 'results': {
137
+ if (!positional[0])
138
+ fail('Usage: posteverywhere results <postId>');
139
+ return out(await api('GET', `/posts/${positional[0]}/results`));
140
+ }
141
+ case 'retry': {
142
+ if (!positional[0])
143
+ fail('Usage: posteverywhere retry <postId>');
144
+ return out(await api('POST', `/posts/${positional[0]}/retry`));
145
+ }
146
+ case 'upload': {
147
+ const url = positional[0] || f('url');
148
+ if (typeof url !== 'string')
149
+ fail('Usage: posteverywhere upload <imageUrl>');
150
+ return out(await api('POST', '/media/upload-from-url', { url }));
151
+ }
152
+ case 'caption': {
153
+ const topic = f('topic', 't');
154
+ if (typeof topic !== 'string')
155
+ fail('Usage: posteverywhere caption -t "topic" [--platform x] [--tone y]');
156
+ const body = { topic };
157
+ if (typeof f('platform') === 'string')
158
+ body.platform = f('platform');
159
+ if (typeof f('tone') === 'string')
160
+ body.tone = f('tone');
161
+ return out(await api('POST', '/ai/generate-caption', body));
162
+ }
163
+ case 'analytics': {
164
+ const period = f('period') || 'month';
165
+ return out(await api('GET', `/analytics/summary?period=${encodeURIComponent(period)}`));
166
+ }
167
+ case 'campaigns':
168
+ return out(await api('GET', '/campaigns'));
169
+ default:
170
+ fail(`Unknown command: ${cmd}. Run \`posteverywhere help\` for the command list.`);
171
+ }
172
+ }
173
+ main().catch((e) => fail(e instanceof Error ? e.message : String(e)));
package/package.json ADDED
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "@posteverywhere/cli",
3
+ "version": "0.1.0",
4
+ "description": "PostEverywhere CLI for AI agents — schedule and publish to Instagram, TikTok, YouTube, LinkedIn, Facebook, X, Threads, Pinterest, Bluesky, Telegram & Discord from the command line. Structured JSON output for Claude, Cursor, and other agents.",
5
+ "type": "module",
6
+ "bin": {
7
+ "posteverywhere": "dist/index.js"
8
+ },
9
+ "files": ["dist", "SKILL.md", "README.md"],
10
+ "engines": { "node": ">=18.0.0" },
11
+ "scripts": {
12
+ "build": "tsc",
13
+ "dev": "tsc --watch",
14
+ "prepublishOnly": "npm run build"
15
+ },
16
+ "keywords": ["social media", "cli", "ai agent", "claude", "mcp", "scheduling", "automation"],
17
+ "license": "MIT",
18
+ "devDependencies": { "typescript": "^5.6.0", "@types/node": "^20.0.0" }
19
+ }