hermoso 0.1.258 → 0.1.260

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/http.mjs CHANGED
@@ -243,12 +243,12 @@ const inflightNameOf = (body) => { const msgs = Array.isArray(body) ? body : [bo
243
243
  // `?tools=research,create` narrows the roster this connection advertises (see registerTools). Read here rather
244
244
  // than inside registerTools so BOTH the anonymous discovery handshake and a real session honour the same query,
245
245
  // and so an unknown group is refused at the door with the valid list instead of silently serving every group.
246
- // ABSENT, an authenticated session resolves to `defaultToolGroups` in tools.mjs, which is the FULL roster unless
247
- // this process sets MCP_CORE_FIRST=1 — and production does not set it (measured 2026-09-20 off the Cloud Run
248
- // service env). This comment used to say an authenticated session "resolves to the CORE-FIRST default" in one
249
- // sentence and "the default is the full roster" in the next; the second one is the true one. When core-first IS
250
- // on, the list is the core tools plus a few that make the connection drivable, with everything else held out of
251
- // the LIST on size and reachable through find_tools + call_tool. `?tools=all` restores the full roster for one
246
+ // ABSENT, an authenticated session resolves to `defaultToolGroups` in tools.mjs: the FULL roster unless this
247
+ // process sets MCP_CORE_FIRST=1. PRODUCTION SETS IT (since 2026-09-20, read off the Cloud Run service env; for the
248
+ // three weeks before, this comment claimed core-first was the default while the variable was absent). With it on,
249
+ // the list is the core tools, the few that make the connection drivable and the headline verb of each area
250
+ // (CORE_FIRST_HEADLINE), with everything else held out of the LIST on size and reachable through find_tools +
251
+ // call_tool. `?tools=all` restores the full roster for one
252
252
  // connection. The anonymous discovery path above is
253
253
  // deliberately NOT core-first — see the comment on its registerTools call.
254
254
  // The scope fixed here is the STARTING roster, not a cage: `enable_tools` widens it mid-session and the SDK
package/mcp/tools.mjs CHANGED
@@ -1936,7 +1936,27 @@ export const coreFirstRoster = (env = process.env) => CORE_FIRST_ENV.some((k) =>
1936
1936
  // every existing caller and every per-group count the site and the docs derive. tools/core-first-roster-check.mjs
1937
1937
  // asserts each name is registered and that NONE of them is connector-gated (one that were would be listed and
1938
1938
  // then answer 401, which is the thing the connector gate exists to prevent).
1939
- export const CORE_FIRST_EXTRA = Object.freeze(['get_brand', 'get_job', 'list_jobs', 'list_connectors', 'list_scheduled']);
1939
+ // THE SHORT LIST HAS TO LOOK LIKE THE PRODUCT (2026-09-20, Dave: "we dont want to degrade quality or make it look like
1940
+ // there's less capability"). The first core-first list was the `core` group plus the five above, and read live off
1941
+ // production it was: enable_tools, find_tools, call_tool, hermoso_capabilities, hermoso_credits, buy_credits,
1942
+ // report_bug, request_feature, billing_status, upgrade_plan, set_auto_reload, list_brands, use_brand, create_brand,
1943
+ // delete_brand … — a billing utility. Not one listed tool made an ad, researched a competitor or published a post, so
1944
+ // a person scanning the connector in Claude, ChatGPT or Cursor saw no marketing product, and a client that does not
1945
+ // reliably search (`find_tools` is an instruction, and weaker hosts skip instructions) had no way to discover one.
1946
+ // So the HEADLINE VERBS of each area ride in the list: research, create, the variant tools, publish, measure. Every
1947
+ // name here is un-gated (listed with nothing connected and never answering 401), and everything else is still one
1948
+ // find_tools + call_tool away. The weight this costs is measured in tools/roster-weight-check.mjs.
1949
+ export const CORE_FIRST_HEADLINE = Object.freeze([
1950
+ // research
1951
+ 'find_competitors', 'pull_competitor_ads', 'competitor_teardown', 'research_ads', 'mine_angles',
1952
+ // create
1953
+ 'draft_brand', 'plan_ad', 'render_ad', 'generate_image', 'generate_video', 'clone_video', 'clone_static', 'make_template_ad',
1954
+ // variants of a finished ad
1955
+ 'edit_image', 'headline_variants', 'hook_variants', 'multiply_ad',
1956
+ // publish, files, measure
1957
+ 'schedule_post', 'list_library', 'upload_file', 'post_performance', 'analyze_campaigns',
1958
+ ]);
1959
+ export const CORE_FIRST_EXTRA = Object.freeze(['get_brand', 'get_job', 'list_jobs', 'list_connectors', 'list_scheduled', ...CORE_FIRST_HEADLINE]);
1940
1960
  export function defaultToolGroups(env = process.env) { return coreFirstRoster(env) ? ['core'] : [...DEFAULT_TOOL_GROUPS]; }
1941
1961
 
1942
1962
  // Parse a `tools=` scope. Returns {groups} or {error} — an unknown name is REFUSED BY NAME rather than dropped,
@@ -5378,7 +5398,7 @@ function buildTools(rawServer, opts = {}, sink = null) {
5378
5398
  slideText: z.array(z.object({ title: z.string().optional(), description: z.string().optional(), link: z.string().optional() })).optional().describe('PINTEREST CAROUSEL ONLY \u2014 per-slide title, description and destination LINK, one object per slide in slide order. This is the ONLY genuine per-slide caption on any channel Hermoso publishes to: slide 4 can send people to the product ON slide 4, where every other platform gives a carousel one shared caption. Omit any field to leave it unset; the Pin\u2019s own title/description/link still describe the Pin as a whole. Pinterest publishes no length limit on these, so nothing is truncated. More entries than slides is refused rather than dropped.'),
5379
5399
  coverImageUrl: z.string().optional().describe('video Pins only — a render to use as the cover frame'),
5380
5400
  boardSectionId: z.string().optional().describe('optional section within the board'),
5381
- platformCover: z.boolean().optional().describe('VIDEO COVER. Omit it (the default) and Hermoso sets the video\u2019s best frame \u2014 the same frame as its Library thumbnail \u2014 as the cover (Pinterest\u2019s cover key frame, to the whole second). true = send no cover and let the platform pick (usually the first frame). A cover you pass yourself always wins.'),
5401
+ platformCover: z.boolean().optional().describe('VIDEO COVER. Omit it (the default) and Hermoso sets the video\u2019s best frame \u2014 the same frame as its Library thumbnail \u2014 as the cover (on Pinterest the frame rides as the cover image). true = send no cover and let the platform pick (usually the first frame). A cover you pass yourself always wins.'),
5382
5402
  },
5383
5403
  outputSchema: { ok: z.boolean().optional(), id: z.string().nullable().optional(), url: z.string().nullable().optional(), boardId: z.string().optional(), title: z.string().optional(), kind: z.string().optional() },
5384
5404
  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.258",
3
+ "version": "0.1.260",
4
4
  "mcpName": "io.github.hermoso-ai/hermoso",
5
5
  "description": "Marketing on autopilot, run from your own AI agent. 847 tools. Publishing, scheduling, ad campaign management, comments, DMs and analytics cost no credits on every plan; credits are only for generating creative and for Ad Spy research. AD PLATFORMS: Meta, Google Ads, TikTok Ads, LinkedIn Ads, Reddit Ads, X Ads, Pinterest Ads, Snapchat Ads, Microsoft Advertising, Apple Search Ads and ChatGPT Ads, plus product feeds in Google Merchant Center. PUBLISHING AND SCHEDULING: Facebook, Instagram, Threads, TikTok, YouTube, X, LinkedIn, Pinterest, Bluesky and Telegram. 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",