hermoso 0.1.521 → 0.1.523

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.
Files changed (2) hide show
  1. package/mcp/tools.mjs +9 -5
  2. package/package.json +1 -1
package/mcp/tools.mjs CHANGED
@@ -3255,6 +3255,7 @@ const splitRef = (m, tool, word) => {
3255
3255
  // delete names the visibility operation. These run BEFORE the split rewrite, so a precise reference wins over the
3256
3256
  // generic "op / op" list.
3257
3257
  const WIDGET_PROXY_REFS = [[/\s*\/\s*fetch_social_data\b/g, ''], [/go through fetch_social_data with a handle/g, 'go through instagram_profile and search_instagram_hashtag'],
3258
+ [/through fetch_social_data's Instagram profile endpoint/g, 'through instagram_profile'], // search_instagram's local-market step (0aec0d65db4)
3258
3259
  [/, which submit_tiktok_ads_verification can reuse/g, ''], [/the code submit_tiktok_ads_verification needs/g, 'its code'],
3259
3260
  [/SECRET with update_pinterest_board\b/g, 'SECRET with set_pinterest_board_visibility']];
3260
3261
  const widgetProxyHit = (d) => WIDGET_PROXY_REFS.some(([re]) => { re.lastIndex = 0; const hit = re.test(d); re.lastIndex = 0; return hit; });
@@ -18645,13 +18646,16 @@ function buildTools(rawServer, opts = {}, sink = null) {
18645
18646
  inputSchema: {
18646
18647
  advertiserId: z.string().optional().describe('from list_tiktok_ads_accounts — TikTok scopes these lookups to an advertiser'),
18647
18648
  kind: z.enum(['location', 'interest', 'interest_keyword', 'hashtag', 'language']).optional().describe('default location. interest_keyword and hashtag both REQUIRE keyword.'),
18648
- keyword: z.string().optional().describe('narrows the lookup, e.g. "Canada", "Beauty", "skincare"'),
18649
+ keyword: z.string().optional().describe('narrows the lookup by name, e.g. "Canada" returns Canada rather than every place TikTok has; REQUIRED for interest_keyword and hashtag'),
18650
+ regionCode: z.string().optional().describe('location only: two-letter country code, e.g. CA, to list the places inside one country'),
18651
+ level: z.enum(['country', 'province', 'city', 'district']).optional().describe('location only: return one level'),
18652
+ limit: z.number().optional().describe('rows to return, default 50, max 200; total always counts every match'),
18649
18653
  },
18650
- outputSchema: { advertiserId: z.string().optional(), kind: z.string().optional(), results: z.array(z.any()).optional() },
18654
+ outputSchema: { advertiserId: z.string().optional(), kind: z.string().optional(), results: z.array(z.any()).optional(), total: z.number().optional(), returned: z.number().optional(), truncated: z.boolean().optional(), note: z.string().optional() },
18651
18655
  annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: true },
18652
18656
  }, wrap(async (a) => {
18653
18657
  const d = await apiGet('/api/tiktok-ads/targeting', a);
18654
- return ok(`${(d.results || []).length} TikTok ${d.kind || a.kind || 'location'} result(s) on advertiser ${d.advertiserId}:\n${JSON.stringify((d.results || []).slice(0, 30))}`, d);
18658
+ return ok(`${d.note || `${(d.results || []).length} TikTok ${d.kind || a.kind || 'location'} result(s).`} Advertiser ${d.advertiserId}:\n${JSON.stringify(d.results || [])}`, d);
18655
18659
  }));
18656
18660
  server.registerTool('tiktok_ads_report', {
18657
18661
  title: 'TikTok ads performance report',
@@ -19302,7 +19306,7 @@ function buildTools(rawServer, opts = {}, sink = null) {
19302
19306
  registeredArea: z.string().optional().describe('two-letter country of registration, e.g. US'),
19303
19307
  timezone: z.string().optional().describe('IANA time zone, e.g. America/New_York'),
19304
19308
  currency: z.string().optional().describe('must match the Business Center currency; defaults to it'),
19305
- promotionLink: z.string().optional().describe('company website; required for an agency Business Center'),
19309
+ promotionLink: z.string().optional().describe('company website; required for an agency Business Center. Pass the brand site when you have it: Hermoso sends it only where TikTok takes it and the reply says when it was not sent'),
19306
19310
  contactName: z.string().optional(), contactEmail: z.string().optional(), contactPhone: z.string().optional(),
19307
19311
  billingAddress: z.string().optional().describe('required for France, Brazil and Mexico'),
19308
19312
  taxId: z.string().optional().describe('VAT, tax id or ABN depending on the country'),
@@ -22631,7 +22635,7 @@ function buildTools(rawServer, opts = {}, sink = null) {
22631
22635
  image: z.string().optional().describe('the served absolute URL of the finished image'),
22632
22636
  model: z.string().optional().describe('the product-facing label of the model that rendered it'),
22633
22637
  productCheck: z.any().optional().describe('present when the brand\'s product photo was attached: {verdict: match|mismatch|unclear|absent, wordmark, issues[]} — the render compared against the real product photo. mismatch/absent means the product in the image is NOT the brand\'s product; say so, never present it as done'),
22634
- logoPlaced: z.any().optional().describe('how the real logo file went on: {applied, mode: in_scene|fix|overlay, object?, fellBack?, notALogo?}; notALogo = the saved logo is a photo, so nothing was added (ask for the logo file)'),
22638
+ logoPlaced: z.any().optional().describe('how the real logo file went on: {applied, mode: in_scene|fix|overlay, object?, fellBack?, notALogo?, asked?}; notALogo = the saved logo is a photo, so nothing was added (ask for the logo file only when the logo was asked for; asked:false means nobody asked for one, so say nothing about it)'),
22635
22639
  labelPass: z.any().optional().describe('present when the product\'s label lines were known: {status: checked (read and already right, left as rendered) | fixed (read wrong and re-printed from the photo) | left (not re-printed: label faces away, product not found, or the pass could not run) | off (fixLabel:false), read, expected[], note}. Tell the user the note.'),
22636
22640
  },
22637
22641
  annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hermoso",
3
- "version": "0.1.521",
3
+ "version": "0.1.523",
4
4
  "mcpName": "io.github.hermoso-ai/hermoso",
5
5
  "description": "AI marketing agent and AI ad generator, run from your own AI agent. 1177 tools. No markup on models on Starter and up. Publishing, scheduling, ad campaign management, comments, DMs and analytics cost no credits on any plan; Free includes 10 posts a month and every paid plan posts without a limit. 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, WordPress, Discord, Slack, Whop 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",