hermoso 0.1.233 → 0.1.235
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 +2 -2
- package/mcp/client.mjs +6 -2
- package/mcp/tools.mjs +232 -64
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@ scripts. Research the ads already winning in a market, generate finished image &
|
|
|
5
5
|
composited in, copy + CTA included), publish them to your own social channels, and build & manage the ad
|
|
6
6
|
campaigns behind them — all over [MCP](https://modelcontextprotocol.io) tools, a CLI, or installable Claude skills.
|
|
7
7
|
|
|
8
|
-
**
|
|
8
|
+
**828 tools.** `tools/list` is always the authoritative set; `hermoso_capabilities` (free) returns the live model
|
|
9
9
|
catalog with exact per-render credit costs plus the full capability map.
|
|
10
10
|
|
|
11
11
|
**What it connects to.** Ad platforms: Meta, Google Ads, TikTok Ads, LinkedIn Ads, Reddit Ads, X Ads,
|
|
@@ -171,7 +171,7 @@ block entirely if you signed in above; it is there for CI, where the process can
|
|
|
171
171
|
|
|
172
172
|
Then ask your agent: *“Generate an image ad with Hermoso.”*
|
|
173
173
|
|
|
174
|
-
### What the
|
|
174
|
+
### What the 828 tools cover
|
|
175
175
|
|
|
176
176
|
**Ad spy / research** — `find_competitors`, `competitor_teardown`, `pull_competitor_ads`, `research_ads`; the
|
|
177
177
|
Meta / Google / LinkedIn ad libraries (`search_meta_ads`, `search_google_ads`, `search_linkedin_ads`); organic
|
package/mcp/client.mjs
CHANGED
|
@@ -106,7 +106,8 @@ async function unwrap(res) {
|
|
|
106
106
|
// `_viaApi` MARKS AN ERROR THAT ALREADY REACHED THE SERVER, so route() has already recorded it in the error
|
|
107
107
|
// ledger with the tool name off x-hermoso-tool. wrap() reports ONLY the errors that lack this marker — a local
|
|
108
108
|
// throw, a schema rejection, a socket reset — which is what stops the twins double-counting every 4xx.
|
|
109
|
-
|
|
109
|
+
// `connectUrl` rides a not-connected 401 with the brand already in it, so a hint never rebuilds the link.
|
|
110
|
+
throw Object.assign(new Error(msg), { status: res.status, _viaApi: true, ...(body?.connector ? { connector: body.connector } : {}), ...(typeof body?.connectUrl === 'string' ? { connectUrl: body.connectUrl } : {}) });
|
|
110
111
|
}
|
|
111
112
|
return body && Object.prototype.hasOwnProperty.call(body, 'data') ? body.data : body;
|
|
112
113
|
}
|
|
@@ -307,7 +308,10 @@ export async function connectedProviders() {
|
|
|
307
308
|
if (!list) return { connected: new Set(), readOk: false }; // a shape we do not recognise is a failed read
|
|
308
309
|
const offered = Array.isArray(r?.offered) ? new Set(r.offered.filter((p) => typeof p === 'string' && p)) : null; // null = server predates the field → fail open
|
|
309
310
|
const gated = r?.gated && typeof r.gated === 'object' ? r.gated : {};
|
|
310
|
-
|
|
311
|
+
// connectLink: the app deep link for THIS brand with a {provider} slot, so a tool held back for a missing
|
|
312
|
+
// connection can hand the user the one-click link instead of only naming the Connectors page.
|
|
313
|
+
const connectLink = typeof r?.connectLink === 'string' && r.connectLink.includes('{provider}') ? r.connectLink : '';
|
|
314
|
+
return { connected: new Set(list.filter((p) => typeof p === 'string' && p)), readOk: true, offered, gated, connectLink };
|
|
311
315
|
} catch { return { connected: new Set(), readOk: false }; }
|
|
312
316
|
}
|
|
313
317
|
// Upload raw file BYTES to /api/upload (150MB, persists → returns {url,kind,bytes}). Overrides the JSON content-type so
|