@neopress/mcp 1.5.0 → 1.6.1
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 +15 -2
- package/dist/bin.cjs +344 -20
- package/dist/http-bin.cjs +344 -20
- package/dist/index.d.ts +131 -0
- package/dist/index.js +344 -20
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -22,8 +22,13 @@ Stdio MCP can use `neopress_asset_upload_file` because it runs on the same
|
|
|
22
22
|
machine as the agent and can read local file paths.
|
|
23
23
|
|
|
24
24
|
The tool surface includes site/layout/page/collection/entry/form/asset/publish
|
|
25
|
-
operations plus
|
|
26
|
-
and
|
|
25
|
+
operations plus analytics queries and saved event/funnel configuration. Use
|
|
26
|
+
`neopress_analytics_event_update` with `eventId` and `name` to rename an existing
|
|
27
|
+
event without changing its historical tracking behavior; display changes use a
|
|
28
|
+
separate call. Create a new event when tracking conditions need to change. Use
|
|
29
|
+
`neopress_analytics_targets_list` before creating an event to discover valid
|
|
30
|
+
page and form targets. Event and funnel creation accepts the same camelCase
|
|
31
|
+
definition inputs as the dashboard; reads preserve stored snake_case fields.
|
|
27
32
|
|
|
28
33
|
## Remote HTTP
|
|
29
34
|
|
|
@@ -178,3 +183,11 @@ pnpm dlx @anthropic-ai/mcpb pack packages/mcp/dist/mcpb/neopress
|
|
|
178
183
|
|
|
179
184
|
Do not submit the remote connector drafts until the production MCP origin,
|
|
180
185
|
support URL, review workspace, and real client OAuth scans are verified.
|
|
186
|
+
|
|
187
|
+
## Localization
|
|
188
|
+
|
|
189
|
+
Page tools expose draft/production public languages; `draftPublicLocales: null` means only the site's default language and `[]` means no public languages. Publish the site to apply the draft list. Translation dictionaries and global page visibility are separate state.
|
|
190
|
+
|
|
191
|
+
`neopress_entry_create_translation` takes `entryId` and `locale`, returning an existing linked locale row or a source-content copy as a draft. It does not perform machine translation or publish content. Update and publish the returned entry separately. Collections share schemas with localized option labels; forms share schemas with flat `draftI18n.translations[textKey][locale]` dictionaries.
|
|
192
|
+
|
|
193
|
+
Partial update tools preserve omitted fields, including page/form i18n and metadata. Use explicit null only to clear nullable fields.
|
package/dist/bin.cjs
CHANGED
|
@@ -19671,6 +19671,10 @@ var EntriesEndpoint = class {
|
|
|
19671
19671
|
collectionId
|
|
19672
19672
|
})).data;
|
|
19673
19673
|
}
|
|
19674
|
+
/** Copy source content into a linked locale draft, or return its existing translation. */
|
|
19675
|
+
async createTranslation(entryId, locale) {
|
|
19676
|
+
return (await this.client.post(`${this.basePath}/${entryId}/translations`, { locale })).data;
|
|
19677
|
+
}
|
|
19674
19678
|
async update(entryId, data) {
|
|
19675
19679
|
const payload = {};
|
|
19676
19680
|
for (const key of UPDATE_PASSTHROUGH_FIELDS) if (key in data) payload[key] = data[key];
|
|
@@ -19948,8 +19952,12 @@ function appendCommonAnalyticsParams(qs, params) {
|
|
|
19948
19952
|
}
|
|
19949
19953
|
var AnalyticsEndpoint = class {
|
|
19950
19954
|
client;
|
|
19955
|
+
events;
|
|
19956
|
+
funnels;
|
|
19951
19957
|
constructor(client) {
|
|
19952
19958
|
this.client = client;
|
|
19959
|
+
this.events = new AnalyticsEventsEndpoint(client);
|
|
19960
|
+
this.funnels = new AnalyticsFunnelsEndpoint(client);
|
|
19953
19961
|
}
|
|
19954
19962
|
get basePath() {
|
|
19955
19963
|
return `${this.client.siteBasePath}/analytics`;
|
|
@@ -20006,6 +20014,58 @@ var AnalyticsEndpoint = class {
|
|
|
20006
20014
|
if (params.rowLimit) qs.set("row_limit", String(params.rowLimit));
|
|
20007
20015
|
return (await this.client.get(`${this.basePath}/search-console?${qs.toString()}`)).data;
|
|
20008
20016
|
}
|
|
20017
|
+
/** Page/form targets that can be referenced by an event definition. */
|
|
20018
|
+
async targets() {
|
|
20019
|
+
return (await this.client.get(`${this.basePath}/targets`)).data;
|
|
20020
|
+
}
|
|
20021
|
+
};
|
|
20022
|
+
var AnalyticsEventsEndpoint = class {
|
|
20023
|
+
client;
|
|
20024
|
+
constructor(client) {
|
|
20025
|
+
this.client = client;
|
|
20026
|
+
}
|
|
20027
|
+
get basePath() {
|
|
20028
|
+
return `${this.client.siteBasePath}/analytics/events`;
|
|
20029
|
+
}
|
|
20030
|
+
async list() {
|
|
20031
|
+
return (await this.client.get(this.basePath)).data;
|
|
20032
|
+
}
|
|
20033
|
+
async get(eventId) {
|
|
20034
|
+
return (await this.client.get(`${this.basePath}/${eventId}`)).data.event;
|
|
20035
|
+
}
|
|
20036
|
+
async create(data) {
|
|
20037
|
+
return (await this.client.post(this.basePath, data)).data.event;
|
|
20038
|
+
}
|
|
20039
|
+
async update(eventId, data) {
|
|
20040
|
+
return (await this.client.patch(`${this.basePath}/${eventId}`, data)).data.event;
|
|
20041
|
+
}
|
|
20042
|
+
async delete(eventId) {
|
|
20043
|
+
await this.client.delete(`${this.basePath}/${eventId}`);
|
|
20044
|
+
}
|
|
20045
|
+
};
|
|
20046
|
+
var AnalyticsFunnelsEndpoint = class {
|
|
20047
|
+
client;
|
|
20048
|
+
constructor(client) {
|
|
20049
|
+
this.client = client;
|
|
20050
|
+
}
|
|
20051
|
+
get basePath() {
|
|
20052
|
+
return `${this.client.siteBasePath}/analytics/funnels`;
|
|
20053
|
+
}
|
|
20054
|
+
async list() {
|
|
20055
|
+
return (await this.client.get(this.basePath)).data;
|
|
20056
|
+
}
|
|
20057
|
+
async get(funnelId) {
|
|
20058
|
+
return (await this.client.get(`${this.basePath}/${funnelId}`)).data.funnel;
|
|
20059
|
+
}
|
|
20060
|
+
async create(data) {
|
|
20061
|
+
return (await this.client.post(this.basePath, data)).data.funnel;
|
|
20062
|
+
}
|
|
20063
|
+
async update(funnelId, data) {
|
|
20064
|
+
return (await this.client.patch(`${this.basePath}/${funnelId}`, data)).data.funnel;
|
|
20065
|
+
}
|
|
20066
|
+
async delete(funnelId) {
|
|
20067
|
+
await this.client.delete(`${this.basePath}/${funnelId}`);
|
|
20068
|
+
}
|
|
20009
20069
|
};
|
|
20010
20070
|
//#endregion
|
|
20011
20071
|
//#region ../sdk/src/endpoints/templates.ts
|
|
@@ -20361,9 +20421,8 @@ Use these rules before generating pages, collection schemas, entries, forms, or
|
|
|
20361
20421
|
|
|
20362
20422
|
## Operating boundary
|
|
20363
20423
|
|
|
20364
|
-
-
|
|
20365
|
-
-
|
|
20366
|
-
- MCP is available as local stdio and remote Streamable HTTP over the first-party SDK/API.
|
|
20424
|
+
- Connect the remote MCP server and sign in with your Neopress account through OAuth.
|
|
20425
|
+
- MCP is available on Launch and above. Your site role controls which actions you can perform.
|
|
20367
20426
|
- MCP is a Neopress contract adapter, not a reference crawler or managed page generator.
|
|
20368
20427
|
- The host coding agent should perform \`r.jina.ai\` markdown fetches, browser screenshots, DOM/CSS/SVG/background-image extraction, reference analysis, and TSX authoring with its own tools and tokens.
|
|
20369
20428
|
- Use MCP to read/write Neopress resources, upload or register assets, compile, publish, and verify. Do not expect MCP to spend Neopress server-side LLM tokens for reference analysis or page generation.
|
|
@@ -20377,9 +20436,9 @@ Use these rules before generating pages, collection schemas, entries, forms, or
|
|
|
20377
20436
|
|
|
20378
20437
|
## Cache
|
|
20379
20438
|
|
|
20380
|
-
- Site publish invalidates site/layout/collection reader cache tags in the
|
|
20439
|
+
- Site publish invalidates site/layout/collection reader cache tags in the environment connected to MCP.
|
|
20381
20440
|
- Entry publish/unpublish invalidates entry reader cache when production visibility changes.
|
|
20382
|
-
- A localhost publish does not invalidate production reader cache. For production validation, publish through the production
|
|
20441
|
+
- A localhost publish does not invalidate production reader cache. For production validation, publish through the production MCP server and verify the live URL.
|
|
20383
20442
|
|
|
20384
20443
|
## Analytics and autopilot
|
|
20385
20444
|
|
|
@@ -20392,7 +20451,7 @@ Use these rules before generating pages, collection schemas, entries, forms, or
|
|
|
20392
20451
|
|
|
20393
20452
|
- Layout owns header, footer, global CSS, and 404. Page TSX starts at page content.
|
|
20394
20453
|
- Generated page TSX is sandboxed. Do not import Supabase, create API clients, read env vars, use filesystem/process APIs, or assume arbitrary npm packages.
|
|
20395
|
-
- Use allowed runtime packages only: React/Next basics, react-dom (createPortal), shadcn UI imports, lucide-react, @base-ui/react/drawer, @base-ui/react/dialog, @base-ui/react/accordion, @base-ui/react/switch, @base-ui/react/tabs, @base-ui/react/select, @neopress/youtube, @neopress/map, clsx, class-variance-authority, tailwind-merge, motion/react (never \`framer-motion\` — old package name, not on the allowlist), motion-plus/react (Motion+ premium components: Ticker, Carousel, Cursor, AnimateNumber, AnimateText, Typewriter, ScrambleText, Curtains), @paper-design/shaders-react, gsap (including \`gsap/ScrollTrigger\`, driven via \`@gsap/react\`'s \`useGSAP\`), react-hook-form, zod, @hookform/resolvers, @hookform/resolvers/zod, @neopress/content, @neopress/routing, @neopress/i18n, and @neopress/forms.
|
|
20454
|
+
- Use allowed runtime packages only: React/Next basics, react-dom (createPortal), shadcn UI imports, lucide-react, @base-ui/react/drawer, @base-ui/react/dialog, @base-ui/react/accordion, @base-ui/react/switch, @base-ui/react/tabs, @base-ui/react/select, @neopress/youtube, @neopress/map, clsx, class-variance-authority, tailwind-merge, motion/react (never \`framer-motion\` — old package name, not on the allowlist), motion-plus/react (Motion+ premium components: Ticker, Carousel, Cursor, AnimateNumber, AnimateText, Typewriter, ScrambleText, Curtains), @paper-design/shaders-react, gsap (including \`gsap/ScrollTrigger\`, driven via \`@gsap/react\`'s \`useGSAP\`), react-hook-form, zod, @hookform/resolvers, @hookform/resolvers/zod, @neopress/content, @neopress/routing, @neopress/i18n, @neopress/responsive (MobileOnly with deferred desktop/mobile callbacks), and @neopress/forms.
|
|
20396
20455
|
- For dates, render an existing \`displayDate\` field directly when available. For raw timestamps, use \`Intl.DateTimeFormat\` or \`Date#toLocaleDateString\` with an explicit locale and \`timeZone\` so server rendering and hydration agree; use the site's required zone, or \`UTC\` when none is specified.
|
|
20397
20456
|
- @base-ui/react/select is an accessible listbox/dropdown (replaces a native \`<select>\`, whose popup is unstyled OS chrome). Compose its parts directly in page TSX; a \`<Select.Item value>\` is a string or the documented \`null\` sentinel (unlike Radix, an empty string is not banned); the \`Select.Popup\` portals to \`document.body\`, so give it an explicit z-index and an opaque background; match the trigger width with \`min-w-[var(--anchor-width)]\` (from \`Select.Positioner\`), cap the list with \`max-h-[var(--available-height)]\`, and set \`alignItemWithTrigger={false}\` for standard below-trigger placement. @base-ui/react/drawer is the gesture mobile sheet; @base-ui/react/dialog the non-gesture modal — both portal to \`document.body\`, need an opaque Popup background + z-index, and take \`modal\` for focus-trap.
|
|
20398
20457
|
- react-dom is for \`createPortal\` — portal full-viewport overlays (mobile drawer, modal) to \`document.body\` so a \`backdrop-filter\`/\`transform\` ancestor can't trap their \`position: fixed\` inside its box. ALWAYS render the portal behind an open-state guard (\`{open && createPortal(…, document.body)}\`): an unguarded \`document\` reference throws during SSR.
|
|
@@ -20414,7 +20473,9 @@ Use these rules before generating pages, collection schemas, entries, forms, or
|
|
|
20414
20473
|
- \`queryConfig\` is stored in page \`draftMeta.queryConfig\`.
|
|
20415
20474
|
- Query labels become React props. Entry query results are flattened, so use \`post.body\` instead of \`post.data.body\`.
|
|
20416
20475
|
- A query may include \`collectionWindow\` on an \`entries\` query for a dynamic detail route. Its label receives \`{ before, after, items }\`; each is a flattened-entry array around the current entry, and \`items\` combines both directions. Windows use \`published_at DESC, id DESC\`, allow 0–20 entries per direction, and may only declare that exact order. Use the exact configured label, never a guessed prop name. Optional \`matchFields\` compare raw anchor-snapshot fields only when the source field has a value.
|
|
20417
|
-
- Initial CMS data arrives through those injected query props. \`entryClient\`, when injected in reader/preview for a site handle, is only a client-side auxiliary for load-more/filter/get/create interactions after the initial render; do not use it for initial render or server data loading.
|
|
20476
|
+
- Initial CMS data arrives through those injected query props. \`entryClient\`, when injected in reader/preview for a site handle, is only a client-side auxiliary for load-more/filter/get/create interactions after the initial render; do not use it for initial render or server data loading. Its entries come back flattened like injected props, ordered \`published_at DESC, id DESC\`.
|
|
20477
|
+
- Server-side binding is the default because injected props are server-rendered and crawlable; \`entryClient\` is for after-hydration needs only (large-collection load-more, a read that depends on visitor input such as search text or a chosen filter, or an explicit client-side request).
|
|
20478
|
+
- Load-more pagination: give the list query a \`limit\` (first page injected server-side), then append \`entryClient.more(propLabel, { offset: shown.length, filters? })\` — the server re-runs that page's stored binding query from the offset, so the page restates nothing; \`filters\` is equality on scalar schema fields (\`{ category: "TECH" }\`), applied to the same published data. \`entryClient.list({ collectionId, offset, limit, filters? })\` is only for reads whose query depends on visitor input or that are too large to inject; a light, fixed set revealed on click is a bound query instead. Judge "light" by what the query injects into the page, not by how much the UI shows: a query without a \`limit\` ships every entry with every field. Without a \`limit\` a list query injects every entry, so paginate by slicing the prop instead.
|
|
20418
20479
|
- Use numeric \`collection_id\` filters. Runtime controls site, status, locale, deleted state, and published snapshots.
|
|
20419
20480
|
|
|
20420
20481
|
## Collections and entries
|
|
@@ -20428,7 +20489,7 @@ Use these rules before generating pages, collection schemas, entries, forms, or
|
|
|
20428
20489
|
|
|
20429
20490
|
- Reference fields require a schema field with \`type: "references"\` and target \`collection_id\`.
|
|
20430
20491
|
- Links live in \`entry_references\`, not only in raw entry \`data\`.
|
|
20431
|
-
- \`includeReferences\` fetches arrays keyed by the includeReferences alias or field key, and parent entry \`id\` must be selected. With an alias, the alias prop remains an array of referenced entries. Without an alias, if the field key matches a raw numeric reference field in \`entry.data\`, flattening unwraps that array to one
|
|
20492
|
+
- \`includeReferences\` fetches arrays keyed by the includeReferences alias or field key, and parent entry \`id\` must be selected. With an alias, the alias prop remains an array of referenced entries. Without an alias, if the field key matches a raw numeric reference field in \`entry.data\`, flattening unwraps that array to one object or null; references linked only through \`entry_references\` stay arrays. Every referenced entry is flattened like the parent (\`ref.<fieldId>\`; \`ref.data\` kept for backward compatibility), one level deep.
|
|
20432
20493
|
- After changing references, publish the source entry again.
|
|
20433
20494
|
|
|
20434
20495
|
## Forms
|
|
@@ -20441,7 +20502,7 @@ Use these rules before generating pages, collection schemas, entries, forms, or
|
|
|
20441
20502
|
## Unsupported visitor features
|
|
20442
20503
|
|
|
20443
20504
|
Generated Neopress pages do not support visitor login/accounts, member areas, carts, checkout, payments, subscriptions, or order management.`;
|
|
20444
|
-
const SERVER_INSTRUCTIONS = `Use Neopress MCP tools to manage a selected Neopress site through
|
|
20505
|
+
const SERVER_INSTRUCTIONS = `Use Neopress MCP tools to manage a selected Neopress site through an authenticated MCP connection.
|
|
20445
20506
|
|
|
20446
20507
|
Before generating TSX or schema-backed pages, call neopress_get_runtime_contract or read neopress://runtime-contract.
|
|
20447
20508
|
Use numeric IDs returned by tools. Publish entries separately from site publish. Use read-only analytics tools before autopilot recommendations. Verify production URLs after production publish.
|
|
@@ -20731,6 +20792,11 @@ const READ_ONLY_TOOLS = /* @__PURE__ */ new Set([
|
|
|
20731
20792
|
"neopress_analytics_traffic_sources",
|
|
20732
20793
|
"neopress_analytics_forms",
|
|
20733
20794
|
"neopress_analytics_crawler_summary",
|
|
20795
|
+
"neopress_analytics_events_list",
|
|
20796
|
+
"neopress_analytics_event_get",
|
|
20797
|
+
"neopress_analytics_funnels_list",
|
|
20798
|
+
"neopress_analytics_funnel_get",
|
|
20799
|
+
"neopress_analytics_targets_list",
|
|
20734
20800
|
"neopress_search_console_query",
|
|
20735
20801
|
"neopress_assets_list",
|
|
20736
20802
|
"neopress_asset_get",
|
|
@@ -20754,7 +20820,13 @@ const DESTRUCTIVE_TOOLS = /* @__PURE__ */ new Set([
|
|
|
20754
20820
|
"neopress_form_delete",
|
|
20755
20821
|
"neopress_asset_delete",
|
|
20756
20822
|
"neopress_template_mark",
|
|
20757
|
-
"neopress_publish_site"
|
|
20823
|
+
"neopress_publish_site",
|
|
20824
|
+
"neopress_analytics_event_create",
|
|
20825
|
+
"neopress_analytics_event_update",
|
|
20826
|
+
"neopress_analytics_event_delete",
|
|
20827
|
+
"neopress_analytics_funnel_create",
|
|
20828
|
+
"neopress_analytics_funnel_update",
|
|
20829
|
+
"neopress_analytics_funnel_delete"
|
|
20758
20830
|
]);
|
|
20759
20831
|
const PUBLICATION_TOOLS = /* @__PURE__ */ new Set([
|
|
20760
20832
|
"neopress_entry_publish",
|
|
@@ -20795,6 +20867,12 @@ function asOptionalNumber(input, key) {
|
|
|
20795
20867
|
function asOptionalString(input, key) {
|
|
20796
20868
|
return input[key];
|
|
20797
20869
|
}
|
|
20870
|
+
function asOptionalBoolean(input, key) {
|
|
20871
|
+
return input[key];
|
|
20872
|
+
}
|
|
20873
|
+
function omitUndefined(value) {
|
|
20874
|
+
return Object.fromEntries(Object.entries(value).filter(([, item]) => item !== void 0));
|
|
20875
|
+
}
|
|
20798
20876
|
function siteId(input) {
|
|
20799
20877
|
return asOptionalNumber(input, "siteId");
|
|
20800
20878
|
}
|
|
@@ -20847,7 +20925,7 @@ const toolDefinitions = [
|
|
|
20847
20925
|
{
|
|
20848
20926
|
name: "neopress_site_select",
|
|
20849
20927
|
title: "Select Active Site",
|
|
20850
|
-
description: "Verify access to a site and store it as the active site for future MCP
|
|
20928
|
+
description: "Verify access to a site and store it as the active site for future MCP operations.",
|
|
20851
20929
|
inputSchema: { siteId: number().int().positive() },
|
|
20852
20930
|
handler: async (input, context, extra) => {
|
|
20853
20931
|
const selectedSiteId = asNumber(input, "siteId");
|
|
@@ -21021,10 +21099,11 @@ const toolDefinitions = [
|
|
|
21021
21099
|
title: string().optional(),
|
|
21022
21100
|
type: _enum(["static", "dynamic"]).optional(),
|
|
21023
21101
|
status: _enum(["draft", "published"]).optional(),
|
|
21102
|
+
visibility: _enum(["public", "hidden"]).optional(),
|
|
21024
21103
|
collectionId: number().int().positive().optional(),
|
|
21025
21104
|
draftTsx: string().optional(),
|
|
21026
21105
|
draftI18n: optionalJsonSchema,
|
|
21027
|
-
draftPublicLocales: array(string()).nullable().optional(),
|
|
21106
|
+
draftPublicLocales: array(string()).nullable().optional().describe("Draft public languages. null means default language only; [] means none. Publish to apply."),
|
|
21028
21107
|
draftMeta: optionalJsonSchema,
|
|
21029
21108
|
queryConfig: optionalJsonSchema,
|
|
21030
21109
|
metadata: optionalJsonSchema
|
|
@@ -21035,6 +21114,7 @@ const toolDefinitions = [
|
|
|
21035
21114
|
title: asOptionalString(input, "title"),
|
|
21036
21115
|
type: input.type,
|
|
21037
21116
|
status: input.status,
|
|
21117
|
+
visibility: input.visibility,
|
|
21038
21118
|
collectionId: asOptionalNumber(input, "collectionId"),
|
|
21039
21119
|
draftTsx: asOptionalString(input, "draftTsx"),
|
|
21040
21120
|
draftI18n: input.draftI18n,
|
|
@@ -21055,27 +21135,29 @@ const toolDefinitions = [
|
|
|
21055
21135
|
title: string().optional(),
|
|
21056
21136
|
type: _enum(["static", "dynamic"]).optional(),
|
|
21057
21137
|
status: string().optional(),
|
|
21138
|
+
visibility: _enum(["public", "hidden"]).optional(),
|
|
21058
21139
|
collectionId: number().int().positive().optional(),
|
|
21059
21140
|
draftTsx: string().optional(),
|
|
21060
21141
|
draftI18n: optionalJsonSchema,
|
|
21061
|
-
draftPublicLocales: array(string()).nullable().optional(),
|
|
21142
|
+
draftPublicLocales: array(string()).nullable().optional().describe("Draft public languages. null means default language only; [] means none. Publish to apply."),
|
|
21062
21143
|
draftMeta: optionalJsonSchema,
|
|
21063
21144
|
queryConfig: optionalJsonSchema,
|
|
21064
21145
|
metadata: optionalJsonSchema
|
|
21065
21146
|
},
|
|
21066
21147
|
handler: async (input, context, extra) => {
|
|
21067
|
-
return (await context.createClient({ siteId: siteId(input) }, extra)).pages.update(asNumber(input, "pageId"), {
|
|
21148
|
+
return (await context.createClient({ siteId: siteId(input) }, extra)).pages.update(asNumber(input, "pageId"), omitUndefined({
|
|
21068
21149
|
path: asOptionalString(input, "path"),
|
|
21069
21150
|
title: asOptionalString(input, "title"),
|
|
21070
21151
|
type: asOptionalString(input, "type"),
|
|
21071
21152
|
status: asOptionalString(input, "status"),
|
|
21153
|
+
visibility: input.visibility,
|
|
21072
21154
|
collectionId: asOptionalNumber(input, "collectionId"),
|
|
21073
21155
|
draftTsx: asOptionalString(input, "draftTsx"),
|
|
21074
21156
|
draftI18n: input.draftI18n,
|
|
21075
21157
|
draftPublicLocales: input.draftPublicLocales,
|
|
21076
21158
|
draftMeta: mergeDraftMeta(input.draftMeta, input.queryConfig),
|
|
21077
21159
|
metadata: input.metadata
|
|
21078
|
-
});
|
|
21160
|
+
}));
|
|
21079
21161
|
}
|
|
21080
21162
|
},
|
|
21081
21163
|
{
|
|
@@ -21231,6 +21313,19 @@ const toolDefinitions = [
|
|
|
21231
21313
|
return entry;
|
|
21232
21314
|
}
|
|
21233
21315
|
},
|
|
21316
|
+
{
|
|
21317
|
+
name: "neopress_entry_create_translation",
|
|
21318
|
+
title: "Create Entry Translation Draft",
|
|
21319
|
+
description: "Create or return a linked locale row in the source entry's translation group. New drafts copy source content; translate the returned entry with entry_update, then publish it. Existing translations are preserved.",
|
|
21320
|
+
inputSchema: {
|
|
21321
|
+
...siteIdShape,
|
|
21322
|
+
entryId: number().int().positive(),
|
|
21323
|
+
locale: string().min(1)
|
|
21324
|
+
},
|
|
21325
|
+
handler: async (input, context, extra) => {
|
|
21326
|
+
return (await context.createClient({ siteId: siteId(input) }, extra)).entries.createTranslation(asNumber(input, "entryId"), asString(input, "locale"));
|
|
21327
|
+
}
|
|
21328
|
+
},
|
|
21234
21329
|
{
|
|
21235
21330
|
name: "neopress_entry_update",
|
|
21236
21331
|
title: "Update Entry",
|
|
@@ -21247,14 +21342,14 @@ const toolDefinitions = [
|
|
|
21247
21342
|
},
|
|
21248
21343
|
handler: async (input, context, extra) => {
|
|
21249
21344
|
const client = await context.createClient({ siteId: siteId(input) }, extra);
|
|
21250
|
-
const entry = await client.entries.update(asNumber(input, "entryId"), {
|
|
21345
|
+
const entry = await client.entries.update(asNumber(input, "entryId"), omitUndefined({
|
|
21251
21346
|
slug: asOptionalString(input, "slug"),
|
|
21252
21347
|
title: asOptionalString(input, "title"),
|
|
21253
21348
|
locale: asOptionalString(input, "locale"),
|
|
21254
21349
|
data: input.data,
|
|
21255
21350
|
metadata: input.metadata,
|
|
21256
21351
|
status: asOptionalString(input, "status")
|
|
21257
|
-
});
|
|
21352
|
+
}));
|
|
21258
21353
|
await client.entries.revalidateReaderCache(asNumber(input, "entryId"));
|
|
21259
21354
|
return entry;
|
|
21260
21355
|
}
|
|
@@ -21419,14 +21514,14 @@ const toolDefinitions = [
|
|
|
21419
21514
|
settings: optionalJsonSchema
|
|
21420
21515
|
},
|
|
21421
21516
|
handler: async (input, context, extra) => {
|
|
21422
|
-
return (await context.createClient({ siteId: siteId(input) }, extra)).forms.update(asNumber(input, "formId"), {
|
|
21517
|
+
return (await context.createClient({ siteId: siteId(input) }, extra)).forms.update(asNumber(input, "formId"), omitUndefined({
|
|
21423
21518
|
name: asOptionalString(input, "name"),
|
|
21424
|
-
draftSchema: input.draftSchema
|
|
21519
|
+
draftSchema: input.draftSchema !== void 0 ? input.draftSchema : input.schema,
|
|
21425
21520
|
draftLayout: input.draftLayout,
|
|
21426
21521
|
draftStyle: input.draftStyle,
|
|
21427
21522
|
draftI18n: input.draftI18n,
|
|
21428
21523
|
settings: input.settings
|
|
21429
|
-
});
|
|
21524
|
+
}));
|
|
21430
21525
|
}
|
|
21431
21526
|
},
|
|
21432
21527
|
{
|
|
@@ -21470,6 +21565,235 @@ const toolDefinitions = [
|
|
|
21470
21565
|
});
|
|
21471
21566
|
}
|
|
21472
21567
|
},
|
|
21568
|
+
{
|
|
21569
|
+
name: "neopress_analytics_events_list",
|
|
21570
|
+
title: "List Analytics Events",
|
|
21571
|
+
description: "List saved analytics event definitions for the active site.",
|
|
21572
|
+
inputSchema: siteIdShape,
|
|
21573
|
+
handler: async (input, context, extra) => {
|
|
21574
|
+
return (await context.createClient({ siteId: siteId(input) }, extra)).analytics.events.list();
|
|
21575
|
+
}
|
|
21576
|
+
},
|
|
21577
|
+
{
|
|
21578
|
+
name: "neopress_analytics_event_get",
|
|
21579
|
+
title: "Get Analytics Event",
|
|
21580
|
+
description: "Get a saved analytics event definition by UUID.",
|
|
21581
|
+
inputSchema: {
|
|
21582
|
+
...siteIdShape,
|
|
21583
|
+
eventId: string().uuid()
|
|
21584
|
+
},
|
|
21585
|
+
handler: async (input, context, extra) => {
|
|
21586
|
+
return (await context.createClient({ siteId: siteId(input) }, extra)).analytics.events.get(asString(input, "eventId"));
|
|
21587
|
+
}
|
|
21588
|
+
},
|
|
21589
|
+
{
|
|
21590
|
+
name: "neopress_analytics_event_create",
|
|
21591
|
+
title: "Create Analytics Event",
|
|
21592
|
+
description: "Create a saved analytics event definition over raw analytics signals. Discover page and form IDs with neopress_analytics_targets_list. Click targets use an observed href:<absolute-url> or selector:<fingerprint> key; outbound counts external-link clicks site-wide. Built-in events start collecting without editing or republishing page TSX. Optional id is a client UUID: reuse the same id and payload after an uncertain response.",
|
|
21593
|
+
inputSchema: {
|
|
21594
|
+
...siteIdShape,
|
|
21595
|
+
id: string().uuid().optional(),
|
|
21596
|
+
name: string(),
|
|
21597
|
+
eventType: _enum([
|
|
21598
|
+
"custom",
|
|
21599
|
+
"page",
|
|
21600
|
+
"click",
|
|
21601
|
+
"form",
|
|
21602
|
+
"scroll",
|
|
21603
|
+
"dwell",
|
|
21604
|
+
"outbound"
|
|
21605
|
+
]),
|
|
21606
|
+
eventName: string().optional(),
|
|
21607
|
+
path: string().optional(),
|
|
21608
|
+
selector: string().optional(),
|
|
21609
|
+
formId: string().optional(),
|
|
21610
|
+
scrollDepth: number().int().optional(),
|
|
21611
|
+
dwellSeconds: number().int().optional()
|
|
21612
|
+
},
|
|
21613
|
+
handler: async (input, context, extra) => {
|
|
21614
|
+
return (await context.createClient({ siteId: siteId(input) }, extra)).analytics.events.create({
|
|
21615
|
+
id: asOptionalString(input, "id"),
|
|
21616
|
+
name: asString(input, "name"),
|
|
21617
|
+
eventType: input.eventType,
|
|
21618
|
+
eventName: asOptionalString(input, "eventName"),
|
|
21619
|
+
path: asOptionalString(input, "path"),
|
|
21620
|
+
selector: asOptionalString(input, "selector"),
|
|
21621
|
+
formId: asOptionalString(input, "formId"),
|
|
21622
|
+
scrollDepth: asOptionalNumber(input, "scrollDepth"),
|
|
21623
|
+
dwellSeconds: asOptionalNumber(input, "dwellSeconds")
|
|
21624
|
+
});
|
|
21625
|
+
}
|
|
21626
|
+
},
|
|
21627
|
+
{
|
|
21628
|
+
name: "neopress_analytics_event_update",
|
|
21629
|
+
title: "Update Analytics Event",
|
|
21630
|
+
description: "Rename an analytics event with {name} while preserving tracking behavior, or update its display settings separately. Tracking identity cannot be changed after creation.",
|
|
21631
|
+
inputSchema: {
|
|
21632
|
+
...siteIdShape,
|
|
21633
|
+
eventId: string().uuid(),
|
|
21634
|
+
name: string().optional(),
|
|
21635
|
+
eventType: _enum([
|
|
21636
|
+
"custom",
|
|
21637
|
+
"page",
|
|
21638
|
+
"click",
|
|
21639
|
+
"form",
|
|
21640
|
+
"scroll",
|
|
21641
|
+
"dwell",
|
|
21642
|
+
"outbound"
|
|
21643
|
+
]).optional(),
|
|
21644
|
+
eventName: string().optional(),
|
|
21645
|
+
path: string().optional(),
|
|
21646
|
+
selector: string().optional(),
|
|
21647
|
+
formId: string().optional(),
|
|
21648
|
+
scrollDepth: number().int().optional(),
|
|
21649
|
+
dwellSeconds: number().int().optional(),
|
|
21650
|
+
chartVisible: boolean().optional(),
|
|
21651
|
+
pinned: boolean().optional(),
|
|
21652
|
+
chartColor: string().optional()
|
|
21653
|
+
},
|
|
21654
|
+
handler: async (input, context, extra) => {
|
|
21655
|
+
const client = await context.createClient({ siteId: siteId(input) }, extra);
|
|
21656
|
+
if ([
|
|
21657
|
+
"chartVisible",
|
|
21658
|
+
"pinned",
|
|
21659
|
+
"chartColor"
|
|
21660
|
+
].some((key) => key in input)) {
|
|
21661
|
+
if ([
|
|
21662
|
+
"name",
|
|
21663
|
+
"eventType",
|
|
21664
|
+
"eventName",
|
|
21665
|
+
"path",
|
|
21666
|
+
"selector",
|
|
21667
|
+
"formId",
|
|
21668
|
+
"scrollDepth",
|
|
21669
|
+
"dwellSeconds"
|
|
21670
|
+
].some((key) => input[key] !== void 0)) throw new Error("Update the definition and display settings in separate calls.");
|
|
21671
|
+
return client.analytics.events.update(asString(input, "eventId"), { display: {
|
|
21672
|
+
chartVisible: asOptionalBoolean(input, "chartVisible"),
|
|
21673
|
+
pinned: asOptionalBoolean(input, "pinned"),
|
|
21674
|
+
chartColor: asOptionalString(input, "chartColor")
|
|
21675
|
+
} });
|
|
21676
|
+
}
|
|
21677
|
+
const definition = {
|
|
21678
|
+
name: asString(input, "name"),
|
|
21679
|
+
...input.eventType !== void 0 ? { eventType: input.eventType } : {},
|
|
21680
|
+
eventName: asOptionalString(input, "eventName"),
|
|
21681
|
+
path: asOptionalString(input, "path"),
|
|
21682
|
+
selector: asOptionalString(input, "selector"),
|
|
21683
|
+
formId: asOptionalString(input, "formId"),
|
|
21684
|
+
scrollDepth: asOptionalNumber(input, "scrollDepth"),
|
|
21685
|
+
dwellSeconds: asOptionalNumber(input, "dwellSeconds")
|
|
21686
|
+
};
|
|
21687
|
+
return client.analytics.events.update(asString(input, "eventId"), definition);
|
|
21688
|
+
}
|
|
21689
|
+
},
|
|
21690
|
+
{
|
|
21691
|
+
name: "neopress_analytics_event_delete",
|
|
21692
|
+
title: "Delete Analytics Event",
|
|
21693
|
+
description: "Permanently delete a saved analytics event. Events referenced by a funnel cannot be deleted.",
|
|
21694
|
+
inputSchema: {
|
|
21695
|
+
...siteIdShape,
|
|
21696
|
+
eventId: string().uuid()
|
|
21697
|
+
},
|
|
21698
|
+
handler: async (input, context, extra) => {
|
|
21699
|
+
await (await context.createClient({ siteId: siteId(input) }, extra)).analytics.events.delete(asString(input, "eventId"));
|
|
21700
|
+
return { ok: true };
|
|
21701
|
+
}
|
|
21702
|
+
},
|
|
21703
|
+
{
|
|
21704
|
+
name: "neopress_analytics_funnels_list",
|
|
21705
|
+
title: "List Analytics Funnels",
|
|
21706
|
+
description: "List saved analytics funnel definitions for the active site.",
|
|
21707
|
+
inputSchema: siteIdShape,
|
|
21708
|
+
handler: async (input, context, extra) => {
|
|
21709
|
+
return (await context.createClient({ siteId: siteId(input) }, extra)).analytics.funnels.list();
|
|
21710
|
+
}
|
|
21711
|
+
},
|
|
21712
|
+
{
|
|
21713
|
+
name: "neopress_analytics_funnel_get",
|
|
21714
|
+
title: "Get Analytics Funnel",
|
|
21715
|
+
description: "Get a saved analytics funnel definition by UUID.",
|
|
21716
|
+
inputSchema: {
|
|
21717
|
+
...siteIdShape,
|
|
21718
|
+
funnelId: string().uuid()
|
|
21719
|
+
},
|
|
21720
|
+
handler: async (input, context, extra) => {
|
|
21721
|
+
return (await context.createClient({ siteId: siteId(input) }, extra)).analytics.funnels.get(asString(input, "funnelId"));
|
|
21722
|
+
}
|
|
21723
|
+
},
|
|
21724
|
+
{
|
|
21725
|
+
name: "neopress_analytics_funnel_create",
|
|
21726
|
+
title: "Create Analytics Funnel",
|
|
21727
|
+
description: "Create a funnel with 2 to 5 ordered saved event UUIDs. Optional id is a client UUID; reuse it and the same payload after an uncertain response. Step filter is {version:1,root:{kind:'group',op:'and'|'or',children:[groups or {kind:'condition',field,operator,value?,key?}]}}. Fields: event.path/url/referrer/referrer_source/property; session.referrer/referrer_source/traffic_category/utm_source/utm_medium/utm_campaign/utm_content/utm_term. event.property requires key. Operators: eq,neq,contains,not_contains,starts_with,ends_with,exists,not_exists; property also supports gt,gte,lt,lte. Server validates bounds and grouping.",
|
|
21728
|
+
inputSchema: {
|
|
21729
|
+
...siteIdShape,
|
|
21730
|
+
id: string().uuid().optional(),
|
|
21731
|
+
name: string(),
|
|
21732
|
+
steps: array(object$1({
|
|
21733
|
+
eventId: string().uuid(),
|
|
21734
|
+
path: string().optional(),
|
|
21735
|
+
filter: unknown().optional()
|
|
21736
|
+
})),
|
|
21737
|
+
windowMode: _enum(["session", "time"]),
|
|
21738
|
+
windowHours: number().int().nonnegative().optional()
|
|
21739
|
+
},
|
|
21740
|
+
handler: async (input, context, extra) => {
|
|
21741
|
+
return (await context.createClient({ siteId: siteId(input) }, extra)).analytics.funnels.create({
|
|
21742
|
+
id: asOptionalString(input, "id"),
|
|
21743
|
+
name: asString(input, "name"),
|
|
21744
|
+
steps: input.steps,
|
|
21745
|
+
windowMode: input.windowMode,
|
|
21746
|
+
windowHours: asOptionalNumber(input, "windowHours")
|
|
21747
|
+
});
|
|
21748
|
+
}
|
|
21749
|
+
},
|
|
21750
|
+
{
|
|
21751
|
+
name: "neopress_analytics_funnel_update",
|
|
21752
|
+
title: "Update Analytics Funnel",
|
|
21753
|
+
description: "Replace a saved funnel definition with its ordered event steps and window semantics.",
|
|
21754
|
+
inputSchema: {
|
|
21755
|
+
...siteIdShape,
|
|
21756
|
+
funnelId: string().uuid(),
|
|
21757
|
+
name: string(),
|
|
21758
|
+
steps: array(object$1({
|
|
21759
|
+
eventId: string().uuid(),
|
|
21760
|
+
path: string().optional(),
|
|
21761
|
+
filter: unknown().optional()
|
|
21762
|
+
})),
|
|
21763
|
+
windowMode: _enum(["session", "time"]),
|
|
21764
|
+
windowHours: number().int().nonnegative().optional()
|
|
21765
|
+
},
|
|
21766
|
+
handler: async (input, context, extra) => {
|
|
21767
|
+
return (await context.createClient({ siteId: siteId(input) }, extra)).analytics.funnels.update(asString(input, "funnelId"), {
|
|
21768
|
+
name: asString(input, "name"),
|
|
21769
|
+
steps: input.steps,
|
|
21770
|
+
windowMode: input.windowMode,
|
|
21771
|
+
windowHours: asOptionalNumber(input, "windowHours")
|
|
21772
|
+
});
|
|
21773
|
+
}
|
|
21774
|
+
},
|
|
21775
|
+
{
|
|
21776
|
+
name: "neopress_analytics_funnel_delete",
|
|
21777
|
+
title: "Delete Analytics Funnel",
|
|
21778
|
+
description: "Permanently delete a saved analytics funnel.",
|
|
21779
|
+
inputSchema: {
|
|
21780
|
+
...siteIdShape,
|
|
21781
|
+
funnelId: string().uuid()
|
|
21782
|
+
},
|
|
21783
|
+
handler: async (input, context, extra) => {
|
|
21784
|
+
await (await context.createClient({ siteId: siteId(input) }, extra)).analytics.funnels.delete(asString(input, "funnelId"));
|
|
21785
|
+
return { ok: true };
|
|
21786
|
+
}
|
|
21787
|
+
},
|
|
21788
|
+
{
|
|
21789
|
+
name: "neopress_analytics_targets_list",
|
|
21790
|
+
title: "List Analytics Event Targets",
|
|
21791
|
+
description: "List site pages and forms available as analytics event targets.",
|
|
21792
|
+
inputSchema: siteIdShape,
|
|
21793
|
+
handler: async (input, context, extra) => {
|
|
21794
|
+
return (await context.createClient({ siteId: siteId(input) }, extra)).analytics.targets();
|
|
21795
|
+
}
|
|
21796
|
+
},
|
|
21473
21797
|
{
|
|
21474
21798
|
name: "neopress_analytics_query",
|
|
21475
21799
|
title: "Query Analytics Pipe",
|