@jclvsh/dropspace 2.22.1 → 2.23.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 CHANGED
@@ -139,7 +139,7 @@ Add to your `.cursor/mcp.json`:
139
139
  | `dropspace_platforms` | string[] | No | Platforms to post via official dropspace accounts |
140
140
  | `media_mode` | string | No | `"images"` or `"video"` |
141
141
  | `user_platform_accounts` | object | No | Map of platform key to token_id (UUID). Simple keys: `twitter`, `reddit`, `instagram`, `tiktok`, `youtube`. LinkedIn: `linkedin:personal` or `linkedin:organization:<org_id>`. Facebook: a bare `facebook` key works when you have exactly one Page (send any connection id from `connections list` as the value); to target a specific Page among several, use `facebook:page:<page_id>` or `facebook:<page_id>`, where `page_id` is the entity_id of that Page from `connections list`; several Pages with no `page_id` returns a 400 listing them |
142
- | `platform_contents` | object | No | Per-platform content (mutually exclusive with `custom_content`). Reddit accepts `metadata.subreddits` (string[], max 10, no `r/` prefix — one post per subreddit, each retryable) and `metadata.first_comment` (max 1500) |
142
+ | `platform_contents` | object | No | Per-platform content (mutually exclusive with `custom_content`). Reddit accepts `metadata.subreddits` (string[], max 10, no `r/` prefix — one post per subreddit, each retryable) and `metadata.first_comment` (max 1500). Instagram accepts `instagram_settings.post_type`: `"feed"` (default), `"story"`, or `"carousel"` (every attached image and the video as one carousel, 2 to 10 items) |
143
143
  | `custom_content` | string \| string[] | No | Single content for all platforms, or array of tweets for twitter thread mode (mutually exclusive with `platform_contents`) |
144
144
  | `custom_content_reddit_title` | string | No | Reddit title (required with `custom_content` + reddit) |
145
145
  | `media` | object[] | No | Inline media, URL or base64 (1-10 items, mutually exclusive with `media_assets`) |
@@ -154,7 +154,7 @@ Add to your `.cursor/mcp.json`:
154
154
  | `id` | string | Yes | Launch ID |
155
155
  | `scheduled_date` | string \| null | No | ISO 8601 datetime or null to clear |
156
156
  | `status` | string | No | `"draft"`, `"manual"`, `"trigger"`, `"scheduled"`, `"cancelled"` |
157
- | `platform_contents` | object | No | Per-platform content overrides |
157
+ | `platform_contents` | object | No | Per-platform content overrides (Instagram: `instagram_settings.post_type` `"feed"`, `"story"`, or `"carousel"`) |
158
158
  | `dropspace_platforms` | string[] | No | Official dropspace account platforms |
159
159
  | `user_platform_accounts` | object | No | Map of platform key to token_id (UUID). Simple keys: `twitter`, `reddit`, `instagram`, `tiktok`, `youtube`. LinkedIn: `linkedin:personal` or `linkedin:organization:<org_id>`. Facebook: a bare `facebook` key works when you have exactly one Page (send any connection id from `connections list` as the value); to target a specific Page among several, use `facebook:page:<page_id>` or `facebook:<page_id>`, where `page_id` is the entity_id of that Page from `connections list`; several Pages with no `page_id` returns a 400 listing them |
160
160
  | `media` | object[] | No | Inline media (URL or base64, 1-10 items) |
@@ -31,7 +31,7 @@ export function registerLaunchCommands(program, client) {
31
31
  .option("--persona <id>", "persona ID for tone/style")
32
32
  .option("--dropspace-platforms <list>", "platforms for official dropspace accounts", parseList)
33
33
  .option("--media-mode <mode>", "media mode: images or video")
34
- .option("--platform-contents <json>", 'per-platform content as JSON string. reddit supports metadata.subreddits (string[], max 10, no r/ prefix — one post per subreddit) and metadata.first_comment (max 1500). e.g. \'{"reddit":{"title":"...","content":"...","metadata":{"subreddits":["SideProject"],"first_comment":"..."}}}\'')
34
+ .option("--platform-contents <json>", 'per-platform content as JSON string. reddit supports metadata.subreddits (string[], max 10, no r/ prefix — one post per subreddit) and metadata.first_comment (max 1500). instagram supports instagram_settings.post_type: feed, story, or carousel (every attached image and the video as one carousel, 2 to 10 items). e.g. \'{"reddit":{"title":"...","content":"...","metadata":{"subreddits":["SideProject"],"first_comment":"..."}}}\'')
35
35
  .option("--custom-content <text>", "single content string for all platforms")
36
36
  .option("--reddit-title <title>", "reddit title (with custom-content)")
37
37
  .option("--user-accounts <json>", 'platform→token_id map as JSON. simple key = primary account ("instagram"); composite key targets a specific account when you have several ("instagram:<account_id>", ids from `connections list`) - works for instagram/tiktok/youtube/twitter/reddit. facebook: bare "facebook" for your one Page, or "facebook:page:<page_id>" / "facebook:<page_id>" for a specific one (id from `connections list`); several Pages and no page_id returns a 400. linkedin: "linkedin:personal" or "linkedin:organization:<org_id>"')
@@ -101,7 +101,7 @@ export function registerLaunchCommands(program, client) {
101
101
  .option("--schedule <datetime>", "ISO 8601 schedule datetime (empty to clear)")
102
102
  .option("--status <status>", "status: draft, manual, trigger, scheduled, cancelled")
103
103
  .option("--persona <id>", "persona ID (empty to clear)")
104
- .option("--platform-contents <json>", 'per-platform content as JSON string. reddit supports metadata.subreddits (string[], max 10, no r/ prefix — one post per subreddit) and metadata.first_comment (max 1500). e.g. \'{"reddit":{"title":"...","content":"...","metadata":{"subreddits":["SideProject"],"first_comment":"..."}}}\'')
104
+ .option("--platform-contents <json>", 'per-platform content as JSON string. reddit supports metadata.subreddits (string[], max 10, no r/ prefix — one post per subreddit) and metadata.first_comment (max 1500). instagram supports instagram_settings.post_type: feed, story, or carousel (every attached image and the video as one carousel, 2 to 10 items). e.g. \'{"reddit":{"title":"...","content":"...","metadata":{"subreddits":["SideProject"],"first_comment":"..."}}}\'')
105
105
  .option("--dropspace-platforms <list>", "official dropspace account platforms", parseList)
106
106
  .option("--attribution-mode <mode>", 'how official-account posts credit you: "handle" (default) or "anonymous"')
107
107
  .option("--user-accounts <json>", 'platform→token_id map as JSON. simple key = primary account ("instagram"); composite key targets a specific account when you have several ("instagram:<account_id>", ids from `connections list`) - works for instagram/tiktok/youtube/twitter/reddit. facebook: bare "facebook" for your one Page, or "facebook:page:<page_id>" / "facebook:<page_id>" for a specific one (id from `connections list`); several Pages and no page_id returns a 400. linkedin: "linkedin:personal" or "linkedin:organization:<org_id>"')
@@ -110,7 +110,7 @@ export function registerLaunchTools(server, client) {
110
110
  platform_contents: z
111
111
  .record(z.string(), z.record(z.string(), z.unknown()))
112
112
  .optional()
113
- .describe('per-platform content — each value needs "content" (string). Reddit also requires "title" (max 300) and supports "metadata": { "subreddits": string[] (max 10, names without the r/ prefix — posts the launch once per subreddit, each tracked and retryable on its own; omit to post to the default community), "first_comment": string (max 1500 — posted as a comment under each reddit post once it goes live) }. for multi-account reddit, each connected account can target its own subreddits via "reddit:<account_id>" content keys (falls back to the base "reddit" block); a subreddit is posted by at most one of your accounts per launch (first wins, others skipped as SUBREDDIT_ALREADY_TARGETED). each subreddit has its own rules: many restrict or ban promotional posts and posting where the account has no history gets filtered, so target a few genuinely relevant subreddits rather than blasting. Twitter supports "thread" (string[], max 6, each ≤280 or ≤25,000 for X Premium) instead of "content". TikTok supports "tiktok_settings": { "publish_mode"?: "direct"|"draft" (default "direct"; "draft" uploads to the TikTok inbox to finish and publish in-app), "privacy_level": "PUBLIC_TO_EVERYONE"|"FOLLOWER_OF_CREATOR"|"MUTUAL_FOLLOW_FRIENDS"|"SELF_ONLY" (required before publish in direct mode; not required for draft), "allow_comments"?, "allow_duet"?, "allow_stitch"?, "is_commercial"?, "is_your_brand"?, "is_branded_content"?, "auto_add_music"? (booleans, direct mode), "cover_timestamp_ms"? (integer 0-600000 — which frame TikTok uses as the cover, in ms from the start; VIDEO posts only, photo posts take their cover by index; omit for the first frame) }. YouTube requires video and supports "title" (max 100 chars). character limits: Twitter 280/tweet (25,000 for X Premium), LinkedIn 3000, Instagram 2200, Reddit 3000, Facebook 3000, TikTok 4000, YouTube 5000 (description). X Premium status is auto-detected from the connected account. mutually exclusive with custom_content'),
113
+ .describe('per-platform content — each value needs "content" (string). Instagram takes "instagram_settings": { "post_type": "feed" (default) | "carousel" | "story" } and Facebook takes "facebook_settings": { "post_type": "feed" | "story" } - "carousel" (Instagram only) posts every attached image and the launch video as ONE carousel in media order, 2 to 10 items, where "feed" would post the video as a reel and leave the images out; "story" posts each image as a 24-hour story frame with no caption. Reddit also requires "title" (max 300) and supports "metadata": { "subreddits": string[] (max 10, names without the r/ prefix — posts the launch once per subreddit, each tracked and retryable on its own; omit to post to the default community), "first_comment": string (max 1500 — posted as a comment under each reddit post once it goes live) }. for multi-account reddit, each connected account can target its own subreddits via "reddit:<account_id>" content keys (falls back to the base "reddit" block); a subreddit is posted by at most one of your accounts per launch (first wins, others skipped as SUBREDDIT_ALREADY_TARGETED). each subreddit has its own rules: many restrict or ban promotional posts and posting where the account has no history gets filtered, so target a few genuinely relevant subreddits rather than blasting. Twitter supports "thread" (string[], max 6, each ≤280 or ≤25,000 for X Premium) instead of "content". TikTok supports "tiktok_settings": { "publish_mode"?: "direct"|"draft" (default "direct"; "draft" uploads to the TikTok inbox to finish and publish in-app), "privacy_level": "PUBLIC_TO_EVERYONE"|"FOLLOWER_OF_CREATOR"|"MUTUAL_FOLLOW_FRIENDS"|"SELF_ONLY" (required before publish in direct mode; not required for draft), "allow_comments"?, "allow_duet"?, "allow_stitch"?, "is_commercial"?, "is_your_brand"?, "is_branded_content"?, "auto_add_music"? (booleans, direct mode), "cover_timestamp_ms"? (integer 0-600000 — which frame TikTok uses as the cover, in ms from the start; VIDEO posts only, photo posts take their cover by index; omit for the first frame) }. YouTube requires video and supports "title" (max 100 chars). character limits: Twitter 280/tweet (25,000 for X Premium), LinkedIn 3000, Instagram 2200, Reddit 3000, Facebook 3000, TikTok 4000, YouTube 5000 (description). X Premium status is auto-detected from the connected account. mutually exclusive with custom_content'),
114
114
  custom_content: z
115
115
  .union([z.string().min(1), z.array(z.string()).min(1).max(6)])
116
116
  .optional()
@@ -224,7 +224,7 @@ export function registerLaunchTools(server, client) {
224
224
  platform_contents: z
225
225
  .record(z.string(), z.record(z.string(), z.unknown()))
226
226
  .optional()
227
- .describe('per-platform content update (deep-merged with existing). each value can include "content" (string). Twitter supports "thread" (string[]) instead. Reddit "title" is optional on update, and "metadata" accepts "subreddits" (string[], max 10, no r/ prefix — one post per subreddit) and "first_comment" (string, max 1500). TikTok "tiktok_settings" is deep-merged — you can update individual fields (e.g. just "privacy_level") without overwriting the rest. see create_launch for full field details'),
227
+ .describe('per-platform content update (deep-merged with existing). each value can include "content" (string). Instagram takes "instagram_settings": { "post_type": "feed" | "carousel" | "story" } ("carousel" posts every attached image and the launch video as ONE carousel, 2 to 10 items) and Facebook takes "facebook_settings": { "post_type": "feed" | "story" }. Twitter supports "thread" (string[]) instead. Reddit "title" is optional on update, and "metadata" accepts "subreddits" (string[], max 10, no r/ prefix — one post per subreddit) and "first_comment" (string, max 1500). TikTok "tiktok_settings" is deep-merged — you can update individual fields (e.g. just "privacy_level") without overwriting the rest. see create_launch for full field details'),
228
228
  dropspace_platforms: z.array(z.enum(PLATFORMS)).optional().describe("official dropspace account platforms"),
229
229
  attribution_mode: z
230
230
  .enum(["handle", "anonymous"])
@@ -381,7 +381,7 @@ export function registerLaunchTools(server, client) {
381
381
  };
382
382
  }
383
383
  });
384
- server.tool("get_launch_analytics", "get publishing analytics with per-post engagement metrics (likes, views, shares, etc.)", {
384
+ server.tool("get_launch_analytics", "get publishing analytics with per-post engagement metrics (likes, views, shares, etc.). metric fields vary by platform: facebook reports reactions, likes (mirroring reactions.total), comments and shares - it has no impressions or reach, and facebook story metrics are unavailable. an instagram story reports views, reach, replies and frames only while it is live (24 hours, no backfill); under 5 viewers it returns story_insights_withheld instead of numbers", {
385
385
  id: z.string().uuid().describe("launch ID"),
386
386
  }, async ({ id }) => {
387
387
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jclvsh/dropspace",
3
- "version": "2.22.1",
3
+ "version": "2.23.0",
4
4
  "description": "MCP server and CLI for the Dropspace API",
5
5
  "repository": {
6
6
  "type": "git",