hermoso 0.1.465 → 0.1.466

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.
@@ -111,7 +111,14 @@ export const TOOL_PROVIDER_RULES = [
111
111
  [/onedrive/, 'microsoft_onedrive'],
112
112
  [/bluesky/, 'bluesky'],
113
113
  [/telegram/, 'telegram'],
114
- [/^post_to_tiktok$|^tiktok_|_tiktok_/, 'tiktok'],
114
+ // TIKTOK IS THREE CREDENTIALS, AND ONLY FIVE TOOLS RIDE THE POSTING ONE (2026-10-29). Until this date the bare rule sent
115
+ // every remaining tiktok name to 'tiktok', so 41 Business, analytics and creator-marketplace tools were offered by the
116
+ // POSTING login while their routes spend the TikTok Ads advertiser token or its account-holder grant: a TikTok Ads-only
117
+ // brand lost tools that work, a posting-only brand saw tools that 401. The posting family is named exactly; every
118
+ // other tiktok tool is the Ads connection (see TIKTOK_ACCOUNT_GRANT_TOOLS for the grant either row can host).
119
+ // tools/tiktok-roster-gate-check.mjs derives each tool's credential from server.js and fails when this disagrees.
120
+ [/^(post_to_tiktok|tiktok_post_status|tiktok_creator_info|tiktok_account|list_tiktok_videos)$/, 'tiktok'],
121
+ [/tiktok/, 'tiktok_ads'],
115
122
  [/^post_to_x$|^delete_x_post$|^edit_x_post$|^post_x_article$|^send_x_dm$|^list_x_dms$|^search_x$|^list_x_blocks$|^hide_x_reply$|_x_broadcast|_x_chat|^x_chat_settings$|^x_(mentions|post|account|trends|user|search_counts|follows)/, 'x'],
116
123
  [/pinterest/, 'pinterest'],
117
124
  [/reddit/, 'reddit'],
@@ -138,14 +145,13 @@ export function toolUnoffered(name) { const p = toolProvider(name); return !!p &
138
145
  // tools/multi-account-arg-check.mjs fails when the two differ, and DERIVES the tool split below from server.js.
139
146
  export const MULTI_ACCOUNT_CHANNELS = Object.freeze(new Set(['tiktok', 'x', 'youtube', 'threads', 'bluesky', 'telegram', 'reddit', 'pinterest', 'instagram']));
140
147
  // Filed under a multi-account channel, but routed through a connection that holds ONE grant per brand, so `account`
141
- // would do nothing there: every other tiktok_* tool rides the TikTok Business account-holder grant or TikTok Ads (not
142
- // the per-account posting row), and these two Pinterest reads ride the ad-account (pinterest_ads) row.
143
- const TIKTOK_PER_ACCOUNT_TOOLS = new Set(['post_to_tiktok', 'tiktok_post_status', 'tiktok_creator_info', 'tiktok_account', 'list_tiktok_videos']);
148
+ // would do nothing there: these two Pinterest reads ride the ad-account (pinterest_ads) row. (The TikTok Business and
149
+ // Ads tools are no longer filed under 'tiktok' at all — only the five posting tools are — so they need no entry.)
144
150
  const SINGLE_GRANT_TOOLS = new Set(['pinterest_targeting_analytics', 'pinterest_audience_insights']);
145
151
  export function accountScopedTool(name) {
146
152
  const p = String(toolProvider(name) || '');
147
153
  if (!MULTI_ACCOUNT_CHANNELS.has(p)) return false;
148
- return p === 'tiktok' ? TIKTOK_PER_ACCOUNT_TOOLS.has(String(name)) : !SINGLE_GRANT_TOOLS.has(String(name));
154
+ return !SINGLE_GRANT_TOOLS.has(String(name));
149
155
  }
150
156
  // The channel an account-scoped tool's `account` names, or null.
151
157
  export const accountChannelOf = (name) => (accountScopedTool(name) ? String(toolProvider(name)) : null);
@@ -183,12 +189,25 @@ export const INSTAGRAM_LOGIN_TOOLS = new Set([
183
189
  // row whose business token `waToken` resolves FIRST, with no Meta connection at all — holding its WhatsApp tools back
184
190
  // as "needs meta" would refuse a working connection. Nobody needs BOTH for one account, on either channel.
185
191
  export const isWhatsAppTool = (name) => /whatsapp/.test(String(name || ''));
192
+ // THE SAME SHAPE FOR TIKTOK'S ACCOUNT-HOLDER GRANT (2026-10-29). These tools map to 'tiktok_ads' and spend the TikTok
193
+ // ACCOUNT authorization (server.js ttAccountGrant), which lives on the TikTok Ads row when there is one and otherwise on
194
+ // the TikTok posting row (lib/tiktok-account.mjs TIKTOK_ACCOUNT_HOSTS: a personal creator with no ad account). So either
195
+ // row is enough to offer them. tools/tiktok-roster-gate-check.mjs derives this set from server.js and fails on drift.
196
+ export const TIKTOK_ACCOUNT_GRANT_TOOLS = new Set([
197
+ 'comment_on_tiktok_video', 'list_tiktok_comments', 'list_tiktok_comment_replies', 'reply_to_tiktok_comment', 'moderate_tiktok_comment', 'upload_tiktok_comment_image',
198
+ 'list_tiktok_mentions', 'get_tiktok_mention', 'list_tiktok_mention_comments', 'tiktok_mention_top_terms',
199
+ 'list_tiktok_brand_hashtags', 'list_tiktok_brand_hashtag_posts', 'manage_tiktok_brand_hashtags', 'tiktok_hashtag_suggestions',
200
+ 'get_tiktok_post_ad_authorization', 'set_tiktok_post_ad_authorization', 'extend_tiktok_post_ad_authorization', 'delete_tiktok_post_ad_authorization',
201
+ 'tiktok_account_insights', 'tiktok_account_status', 'tiktok_video_insights', 'tiktok_category_benchmark', 'tiktok_spark_recommendations', 'tiktok_trends',
202
+ ]);
186
203
  // The ONE sentence every surface appends when a 'meta'-mapped tool is held and an alternative connection exists.
187
204
  export const metaAlternativeNote = (name) => INSTAGRAM_LOGIN_TOOLS.has(String(name || ''))
188
205
  ? ' For an Instagram account with no Facebook Page, the "instagram" connection alone is enough for this tool; "meta" covers an Instagram account linked to a Page (and ads). One account never needs both.'
189
206
  : isWhatsAppTool(name)
190
207
  ? ' A WhatsApp Business Account the business already manages is ticked on the "meta" connection\'s assets step; the "whatsapp" connection sets up a number the business does not have yet. Either one is enough for this tool.'
191
- : '';
208
+ : TIKTOK_ACCOUNT_GRANT_TOOLS.has(String(name || ''))
209
+ ? ' A creator with no TikTok ad account can use the "tiktok" connection instead; either one, plus authorizing the TikTok account on its card, is enough for this tool.'
210
+ : '';
192
211
  // ── A TOOL THE SERVER WITHHOLDS FROM EVERY ROSTER (2026-09-27, owner: "why do we even allow access to creator
193
212
  // marketplace if we can't even access it ourselves?"). `withheld` rides the same /api/connectors/providers read as the
194
213
  // connected set: the server names the tools whose capability it does not offer right now (today: the Instagram
@@ -217,5 +236,6 @@ export function toolHeldBackByConnectors(name, conn) {
217
236
  const on = conn.connected instanceof Set ? conn.connected : new Set(conn.connected || []);
218
237
  if (p === 'meta' && on.has('instagram') && INSTAGRAM_LOGIN_TOOLS.has(name)) return false;
219
238
  if (p === 'meta' && on.has('whatsapp') && isWhatsAppTool(name)) return false;
239
+ if (p === 'tiktok_ads' && on.has('tiktok') && TIKTOK_ACCOUNT_GRANT_TOOLS.has(name)) return false;
220
240
  return !on.has(p);
221
241
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hermoso",
3
- "version": "0.1.465",
3
+ "version": "0.1.466",
4
4
  "mcpName": "io.github.hermoso-ai/hermoso",
5
5
  "description": "AI marketing agent and AI ad generator, run from your own AI agent. 1088 tools. No markup on models. Publishing, scheduling, ad campaign management, comments, DMs and analytics are free on every plan. AD PLATFORMS: Meta, Google Ads, TikTok Ads, LinkedIn Ads, Reddit Ads, X Ads, Pinterest Ads, Snapchat Ads, Microsoft Advertising, Apple Search Ads, ChatGPT Ads and AppLovin Ads, plus product feeds in Google Merchant Center. PUBLISHING AND SCHEDULING: Facebook, Instagram, Threads, TikTok, YouTube, X, LinkedIn, Pinterest, Bluesky, Telegram and Google Business Profile. INSTAGRAM DM AUTOMATIONS: a keyword comment, a DM, a story reply or an ig.me link gets an automatic private reply from the brand. AD RESEARCH: the Meta, Google and LinkedIn ad libraries plus organic TikTok, Instagram, YouTube, Threads and Reddit. ANALYTICS: Google Analytics 4, Google Search Console and every connected platform's own post and campaign insights. Also brand onboarding, 50+ image and video generation models, ad scoring, competitor teardowns, Google Drive and OneDrive, a CLI and installable Claude skills.",
6
6
  "type": "module",