hermoso 0.1.519 → 0.1.521
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/mcp/tools.mjs +14 -6
- package/package.json +1 -1
package/mcp/tools.mjs
CHANGED
|
@@ -3400,7 +3400,10 @@ export const holdReasonText = (name, why, ctx = null) => {
|
|
|
3400
3400
|
const prov = toolProvider(name);
|
|
3401
3401
|
const isKey = Object.prototype.hasOwnProperty.call(KEY_CONNECTORS, prov);
|
|
3402
3402
|
const tpl = typeof ctx?.conn?.connectLink === 'string' && ctx.conn.connectLink.includes('{provider}') ? ctx.conn.connectLink : 'https://app.hermoso.ai/?connect={provider}';
|
|
3403
|
-
|
|
3403
|
+
// Creating a TikTok ad account (2026-11-04): the link goes on, after TikTok's sign-in, to the form that creates it.
|
|
3404
|
+
const ttCreate = name === 'create_tiktok_ads_account';
|
|
3405
|
+
const link = tpl.replace('{provider}', prov) + (ttCreate ? `${tpl.includes('?') ? '&' : '?'}next=tiktok-ad-account` : '');
|
|
3406
|
+
return `${name} needs the "${prov}" connection and this workspace has not made it.${metaAlternativeNote(name)} Connect it under Settings ▸ Connectors in the Hermoso app${isKey ? ', or right here with connect_connector if the user prefers' : `, or hand the user this one-click link: ${link} (it opens Hermoso on this profile and goes straight to the sign-in${ttCreate ? ', then to the form that creates the TikTok ad account' : ''})`}, then call again.`;
|
|
3404
3407
|
}
|
|
3405
3408
|
if (why === 'directory') return `${name} is outside what this Claude directory connection may run. Use the Hermoso app, or connect the unscoped server URL.`;
|
|
3406
3409
|
return null;
|
|
@@ -18170,16 +18173,18 @@ function buildTools(rawServer, opts = {}, sink = null) {
|
|
|
18170
18173
|
const TIKTOK_WEB_OPT_EVENTS = ['ON_WEB_DETAIL', 'ON_WEB_SEARCH', 'ON_WEB_ADD_TO_WISHLIST', 'ON_WEB_CART', 'INITIATE_ORDER', 'ADD_BILLING', 'SHOPPING', 'CONSULT', 'DOWNLOAD_START', 'FORM', 'ON_WEB_REGISTER', 'ON_WEB_SUBSCRIBE'];
|
|
18171
18174
|
server.registerTool('list_tiktok_ads_accounts', {
|
|
18172
18175
|
title: 'List TikTok advertiser accounts',
|
|
18173
|
-
description: 'List the TikTok ADVERTISER accounts this profile can act on — id, name, currency, timezone and status. Every other TikTok Ads tool needs an advertiserId, and this is where it comes from: call this first and let the USER pick when there is more than one. Read-only, free, spends nothing. Needs TikTok ADS connected (Settings > Connectors > TikTok Ads) — that is a DIFFERENT connection from the TikTok posting connector behind post_to_tiktok, so a brand that publishes to TikTok every day may still have nothing here.',
|
|
18176
|
+
description: 'List the TikTok ADVERTISER accounts this profile can act on — id, name, currency, timezone and status. Every other TikTok Ads tool needs an advertiserId, and this is where it comes from: call this first and let the USER pick when there is more than one. Read-only, free, spends nothing. Needs TikTok ADS connected (Settings > Connectors > TikTok Ads) — that is a DIFFERENT connection from the TikTok posting connector behind post_to_tiktok, so a brand that publishes to TikTok every day may still have nothing here. When nothing is shared and the user\'s TikTok login has no ad account at all, the reply says so: offer to create one with create_tiktok_ads_account.',
|
|
18174
18177
|
inputSchema: {},
|
|
18175
|
-
outputSchema: { advertisers: z.array(z.any()).optional(), count: z.number().optional(), note: z.string().optional() },
|
|
18178
|
+
outputSchema: { advertisers: z.array(z.any()).optional(), count: z.number().optional(), hasOwnAdAccounts: z.boolean().nullable().optional(), note: z.string().optional() },
|
|
18176
18179
|
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: true },
|
|
18177
18180
|
}, wrap(async () => {
|
|
18178
18181
|
// THE SHARED SET, never the roster route: one TikTok Business Center login commonly administers several
|
|
18179
18182
|
// clients' advertisers, and /api/tiktok-ads/accounts is owner-gated for exactly that reason.
|
|
18180
18183
|
const d = await apiGet('/api/tiktok-ads/shared-accounts', {});
|
|
18181
18184
|
const list = d.advertisers || [];
|
|
18182
|
-
|
|
18185
|
+
// The server says whether the user's own login has ANY ad account (d.note, lib/tiktok-ad-account.mjs ttNoAdvertiserNote):
|
|
18186
|
+
// none means the answer is create_tiktok_ads_account. The fallback names both paths for an older server.
|
|
18187
|
+
if (!list.length) return ok(d.note || 'TikTok Ads is connected but NO advertiser account is shared with this profile yet. If the user has one, ask which ones it may use: list_connector_accounts("tiktok_ads") then set_connector_accounts. If they have none, offer to create one with create_tiktok_ads_account. Do not guess an advertiserId.', d);
|
|
18183
18188
|
return ok(`${list.length} TikTok advertiser account(s) shared with this profile:\n${list.map(x => `• ${x.name} (${x.advertiserId})`).join('\n')}\nPass an advertiserId to read or build on one.`, d);
|
|
18184
18189
|
}));
|
|
18185
18190
|
server.registerTool('list_tiktok_ads_campaigns', {
|
|
@@ -19288,7 +19293,7 @@ function buildTools(rawServer, opts = {}, sink = null) {
|
|
|
19288
19293
|
}));
|
|
19289
19294
|
server.registerTool('create_tiktok_ads_account', {
|
|
19290
19295
|
title: 'Create a new TikTok ad account',
|
|
19291
|
-
description: 'Create a NEW TikTok ad account (advertiser) for the user\'s business, inside a TikTok Business Center that their own TikTok login administers. This is how someone with no TikTok ad account gets one without leaving Hermoso. It runs on the user\'s OWN TikTok Ads connection and in THEIR company name, never Hermoso\'s. TWO STEPS, ALWAYS. First call it WITHOUT confirm: that creates nothing and either lists what is still missing (with the industry list when industry is missing) or returns the exact account TikTok would create. Ask the user for every missing field and never guess one: account name, legal company name, industry (a tier-2 id from the list), registeredArea (country of registration, e.g. US) and timezone (e.g. America/New_York). Currency must match the Business Center\'s and defaults to it. Show the user the summary, then call again with confirm:true. A TikTok ad account CANNOT BE DELETED, only disabled in Business Center. It spends nothing: it has no payment method and no campaigns until the user adds billing in TikTok. Accounts registered in mainland China, Hong Kong, France, Brazil or Mexico need uploaded business documents and are refused unless qualificationId reuses a verified one. If the login has no Business Center yet, create_tiktok_ads_business_center makes one. The new account is read back from TikTok and, when the connection can already reach it, ticked on this brand so every TikTok tool can use it. Free.',
|
|
19296
|
+
description: 'Create a NEW TikTok ad account (advertiser) for the user\'s business, inside a TikTok Business Center that their own TikTok login administers. This is how someone with no TikTok ad account gets one without leaving Hermoso: when the user wants TikTok ads and has no ad account, offer to create one with this tool, and also when they ask for another one. It runs on the user\'s OWN TikTok Ads connection and in THEIR company name, never Hermoso\'s. TWO STEPS, ALWAYS. First call it WITHOUT confirm: that creates nothing and either lists what is still missing (with the industry list when industry is missing) or returns the exact account TikTok would create. Ask the user for every missing field and never guess one: account name, legal company name, industry (a tier-2 id from the list), registeredArea (country of registration, e.g. US) and timezone (e.g. America/New_York). Currency must match the Business Center\'s and defaults to it. Show the user the summary, then call again with confirm:true. A TikTok ad account CANNOT BE DELETED, only disabled in Business Center. It spends nothing: it has no payment method and no campaigns until the user adds billing in TikTok. Accounts registered in mainland China, Hong Kong, France, Brazil or Mexico need uploaded business documents and are refused unless qualificationId reuses a verified one. If the login has no Business Center yet, create_tiktok_ads_business_center makes one. The new account is read back from TikTok and, when the connection can already reach it, ticked on this brand so every TikTok tool can use it. Free.',
|
|
19292
19297
|
inputSchema: {
|
|
19293
19298
|
bcId: z.string().optional().describe('from list_tiktok_ads_business_centers; omit when the login administers exactly one'),
|
|
19294
19299
|
name: z.string().optional().describe('ad account name, up to 100 characters'),
|
|
@@ -26031,7 +26036,10 @@ function memoryNoteVerdict(text) {
|
|
|
26031
26036
|
// `pp`). Ungated, a SERVICE or APP brand acquired a "product library" from its own og:image — and brandContext
|
|
26032
26037
|
// would then print "SERVICE BUSINESS — there is NO physical product. NEVER invent a box, bottle, package…"
|
|
26033
26038
|
// directly above a populated photo library, while assembleAdRender attached that image to every render.
|
|
26034
|
-
|
|
26039
|
+
// A CREATOR'S SITE IS READ FOR PHOTOS ONLY WHEN THE DRAFT NAMED A PRODUCT (journey QA 2026-11-05, @cookingwithlynja): the
|
|
26040
|
+
// photo review is paid, and a handle draft's domain is usually a link-in-bio page. Same rule as the web (brandSellsProduct).
|
|
26041
|
+
const _creatorNoProduct = !!a.socialHandle && !(Array.isArray(p?.productNames) && p.productNames.some((x) => typeof x === 'string' && x.trim()));
|
|
26042
|
+
if (p && p.domain && p.physical_product !== false && !_creatorNoProduct) {
|
|
26035
26043
|
try {
|
|
26036
26044
|
const site = await apiGet('/api/site/images', { url: p.domain });
|
|
26037
26045
|
const imgs = [...(site?.images || [])].filter(Boolean);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hermoso",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.521",
|
|
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",
|