@wisewandtools/mcp-server 2.2.1 → 2.2.3
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/dist/index.js +270 -71
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1203,6 +1203,27 @@ function validateUuid(value) {
|
|
|
1203
1203
|
return str;
|
|
1204
1204
|
}
|
|
1205
1205
|
__name(validateUuid, "validateUuid");
|
|
1206
|
+
function resolveArray(args, key) {
|
|
1207
|
+
let value = args[key];
|
|
1208
|
+
if (value === void 0 || value === null) {
|
|
1209
|
+
throw new ToolInputError(`Missing required parameter: ${key}`);
|
|
1210
|
+
}
|
|
1211
|
+
if (typeof value === "string") {
|
|
1212
|
+
try {
|
|
1213
|
+
value = JSON.parse(value);
|
|
1214
|
+
} catch {
|
|
1215
|
+
throw new ToolInputError(`Invalid ${key} format: expected JSON array`);
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
if (!Array.isArray(value)) {
|
|
1219
|
+
throw new ToolInputError(`Invalid ${key} format: expected array, got ${typeof value}`);
|
|
1220
|
+
}
|
|
1221
|
+
if (value.length === 0) {
|
|
1222
|
+
throw new ToolInputError(`${key} must not be empty`);
|
|
1223
|
+
}
|
|
1224
|
+
return value;
|
|
1225
|
+
}
|
|
1226
|
+
__name(resolveArray, "resolveArray");
|
|
1206
1227
|
|
|
1207
1228
|
// src/handlers/tools/ArticleToolHandler.ts
|
|
1208
1229
|
var boolField = z2.union([z2.boolean(), z2.string()]).transform(
|
|
@@ -1501,7 +1522,7 @@ var ArticleToolHandler = class {
|
|
|
1501
1522
|
publishwordpress_date: { type: "string", description: "WordPress publish date (ISO 8601)" },
|
|
1502
1523
|
publishwordpress_status: { type: "string", enum: ["draft", "publish", "future"], description: "WordPress post status", default: "draft" },
|
|
1503
1524
|
publishwordpress_category: { type: "number", description: "WordPress category ID" },
|
|
1504
|
-
publishwordpress_author: { type: "number", description: "WordPress author ID" },
|
|
1525
|
+
publishwordpress_author: { type: "number", description: "WordPress author ID. CAUTION: If the WP connection user lacks edit_others_posts capability, setting this will cause publishing to fail with rest_cannot_edit_others. Omit unless the WP user has admin/editor role." },
|
|
1505
1526
|
publishwordpress_connection: { type: "string", format: "uuid", description: "WordPress connection ID" },
|
|
1506
1527
|
// Shopify Publishing
|
|
1507
1528
|
use_publishshopify: { type: "boolean", description: "Automatically publish to Shopify" },
|
|
@@ -1573,21 +1594,38 @@ var ArticleToolHandler = class {
|
|
|
1573
1594
|
const validated = CreateArticleSchema.parse(args);
|
|
1574
1595
|
const apiInput = this.buildApiInput(validated);
|
|
1575
1596
|
const article = await this.apiClient.createArticle(apiInput);
|
|
1576
|
-
await this.cache.set(`article:${article.id}`, article, 300);
|
|
1577
1597
|
this.metrics.recordAPICall("create_article", "success");
|
|
1598
|
+
const warnings = [];
|
|
1599
|
+
if (validated.use_publishwordpress && !validated.publishwordpress_connection) {
|
|
1600
|
+
warnings.push("Warning: use_publishwordpress is true but publishwordpress_connection is not set. The article may not be published to WordPress. Provide a publishwordpress_connection UUID.");
|
|
1601
|
+
}
|
|
1602
|
+
if (validated.publishwordpress_author) {
|
|
1603
|
+
warnings.push(
|
|
1604
|
+
'Warning: publishwordpress_author is set. If the WP connection user lacks edit_others_posts capability, auto-publish will silently fail with "rest_cannot_edit_others". Omit publishwordpress_author unless the WP user has admin/editor role.'
|
|
1605
|
+
);
|
|
1606
|
+
}
|
|
1607
|
+
const hasAutoPublish = validated.use_publishwordpress || validated.use_publishshopify || validated.use_publishprestashop || validated.use_publishwoocommerce;
|
|
1608
|
+
const next_steps = hasAutoPublish ? [
|
|
1609
|
+
`Generation auto-triggered. Use 'get_article' with id: ${article.id} to check progress`,
|
|
1610
|
+
`Use 'get_article_output' with id: ${article.id} to get content once ready`
|
|
1611
|
+
] : [
|
|
1612
|
+
`Use 'generate_article' with id: ${article.id} to start content generation`,
|
|
1613
|
+
`Use 'get_article' with id: ${article.id} to check status`
|
|
1614
|
+
];
|
|
1615
|
+
const response = {
|
|
1616
|
+
success: true,
|
|
1617
|
+
article_id: article.id,
|
|
1618
|
+
title: article.title || "Article created",
|
|
1619
|
+
message: `Article "${article.title || validated.subject}" created successfully.`,
|
|
1620
|
+
next_steps
|
|
1621
|
+
};
|
|
1622
|
+
if (warnings.length > 0) {
|
|
1623
|
+
response.warnings = warnings;
|
|
1624
|
+
}
|
|
1578
1625
|
return {
|
|
1579
1626
|
content: [{
|
|
1580
1627
|
type: "text",
|
|
1581
|
-
text: JSON.stringify(
|
|
1582
|
-
success: true,
|
|
1583
|
-
article_id: article.id,
|
|
1584
|
-
title: article.title || "Article created",
|
|
1585
|
-
message: `Article "${article.title || validated.subject}" created successfully.`,
|
|
1586
|
-
next_steps: [
|
|
1587
|
-
`Use 'generate_article' with id: ${article.id} to start content generation`,
|
|
1588
|
-
`Use 'get_article' with id: ${article.id} to check status`
|
|
1589
|
-
]
|
|
1590
|
-
}, null, 2)
|
|
1628
|
+
text: JSON.stringify(response, null, 2)
|
|
1591
1629
|
}]
|
|
1592
1630
|
};
|
|
1593
1631
|
} catch (error) {
|
|
@@ -1655,6 +1693,22 @@ var ArticleToolHandler = class {
|
|
|
1655
1693
|
}
|
|
1656
1694
|
throw new Error(`Generation timeout after ${max_wait_time} seconds`);
|
|
1657
1695
|
} catch (error) {
|
|
1696
|
+
const errorMsg = (error.message || "").toLowerCase();
|
|
1697
|
+
if (errorMsg.includes("already running") || errorMsg.includes("in queue") || errorMsg.includes("already in progress")) {
|
|
1698
|
+
const article_id = args.id || args.article_id;
|
|
1699
|
+
return {
|
|
1700
|
+
content: [{
|
|
1701
|
+
type: "text",
|
|
1702
|
+
text: JSON.stringify({
|
|
1703
|
+
success: true,
|
|
1704
|
+
article_id,
|
|
1705
|
+
status: "already_running",
|
|
1706
|
+
message: "Article generation is already in progress. Use get_article to check status.",
|
|
1707
|
+
next_steps: [`Use 'get_article' with id: ${article_id} to check progress`]
|
|
1708
|
+
}, null, 2)
|
|
1709
|
+
}]
|
|
1710
|
+
};
|
|
1711
|
+
}
|
|
1658
1712
|
logger.error("Failed to generate article", { error: error.message });
|
|
1659
1713
|
this.metrics.recordAPICall("generate_article", "error");
|
|
1660
1714
|
return { content: [{ type: "text", text: JSON.stringify({ error: true, message: error.message || "Failed to generate article" }, null, 2) }], isError: true };
|
|
@@ -1807,19 +1861,30 @@ var ArticleToolHandler = class {
|
|
|
1807
1861
|
await this.cache.set(cacheKey, output, 600);
|
|
1808
1862
|
}
|
|
1809
1863
|
this.metrics.recordAPICall("get_article_output", "success");
|
|
1864
|
+
const rawOutput = output;
|
|
1865
|
+
const normalizedOutput = rawOutput?.data?.output ?? rawOutput?.data ?? rawOutput?.output ?? rawOutput;
|
|
1866
|
+
logger.debug("get_article_output raw response keys", { keys: Object.keys(rawOutput || {}), normalizedKeys: Object.keys(normalizedOutput || {}) });
|
|
1810
1867
|
let formattedOutput;
|
|
1811
1868
|
switch (format) {
|
|
1812
|
-
case "html":
|
|
1813
|
-
|
|
1869
|
+
case "html": {
|
|
1870
|
+
const html = normalizedOutput?.html_content ?? normalizedOutput?.content ?? null;
|
|
1871
|
+
const title = normalizedOutput?.title ?? null;
|
|
1872
|
+
formattedOutput = html || title ? { html, title } : { ...normalizedOutput, _note: "Fields not found at expected paths (html_content, title)" };
|
|
1814
1873
|
break;
|
|
1874
|
+
}
|
|
1815
1875
|
case "markdown":
|
|
1816
|
-
formattedOutput = { content:
|
|
1876
|
+
formattedOutput = { content: normalizedOutput?.content ?? normalizedOutput?.markdown ?? null, title: normalizedOutput?.title ?? null };
|
|
1817
1877
|
break;
|
|
1818
|
-
case "summary":
|
|
1819
|
-
|
|
1878
|
+
case "summary": {
|
|
1879
|
+
const title = normalizedOutput?.title ?? null;
|
|
1880
|
+
const excerpt = normalizedOutput?.excerpt ?? null;
|
|
1881
|
+
const word_count = normalizedOutput?.word_count ?? null;
|
|
1882
|
+
const seo_score = normalizedOutput?.seo_score ?? null;
|
|
1883
|
+
formattedOutput = title || excerpt ? { title, excerpt, word_count, seo_score } : { ...normalizedOutput, _note: "Fields not found at expected paths (title, excerpt)" };
|
|
1820
1884
|
break;
|
|
1885
|
+
}
|
|
1821
1886
|
default:
|
|
1822
|
-
formattedOutput =
|
|
1887
|
+
formattedOutput = normalizedOutput;
|
|
1823
1888
|
}
|
|
1824
1889
|
return { content: [{ type: "text", text: JSON.stringify({ success: true, article_id, format, output: formattedOutput, from_cache: !!cached }, null, 2) }] };
|
|
1825
1890
|
} catch (error) {
|
|
@@ -2280,33 +2345,104 @@ var PublishingToolHandler = class {
|
|
|
2280
2345
|
publishToWordPressTool() {
|
|
2281
2346
|
return {
|
|
2282
2347
|
name: "publish_to_wordpress",
|
|
2283
|
-
description: "Publish content to WordPress",
|
|
2348
|
+
description: "Publish content to WordPress. connection_id must reference a WordPress connection with sufficient permissions.",
|
|
2284
2349
|
inputSchema: {
|
|
2285
2350
|
type: "object",
|
|
2286
2351
|
properties: {
|
|
2287
2352
|
entity_id: { type: "string", format: "uuid", description: "ID of the article/content to publish" },
|
|
2288
2353
|
status: { type: "string", enum: ["draft", "publish", "future"], description: "Publishing status", default: "draft" },
|
|
2289
|
-
|
|
2354
|
+
date: { type: "string", format: "date-time", description: 'Publication date (ISO 8601). Required when status is "future".' },
|
|
2290
2355
|
category_id: { type: "number", description: "WordPress category ID" },
|
|
2291
|
-
author_id: { type: "number", description: "WordPress author ID" },
|
|
2292
|
-
connection_id: { type: "string", format: "uuid", description: "WordPress connection ID" }
|
|
2356
|
+
author_id: { type: "number", description: "WordPress author ID. CAUTION: If the WP connection user lacks edit_others_posts capability, setting this will cause publishing to fail with rest_cannot_edit_others. Omit unless the WP user has admin/editor role." },
|
|
2357
|
+
connection_id: { type: "string", format: "uuid", description: "WordPress connection ID (must have sufficient WP permissions)" },
|
|
2358
|
+
clear_author: { type: "boolean", description: 'Clear the stored publishwordpress_author from article config before publishing. Use this to prevent "rest_cannot_edit_others" errors.', default: false }
|
|
2293
2359
|
},
|
|
2294
|
-
required: ["entity_id"]
|
|
2360
|
+
required: ["entity_id", "connection_id"]
|
|
2295
2361
|
},
|
|
2296
2362
|
handler: /* @__PURE__ */ __name(async (args) => {
|
|
2297
2363
|
try {
|
|
2298
|
-
const
|
|
2364
|
+
const entity_id = resolveId(args, "entity_id");
|
|
2365
|
+
const { connection_id, status, date, category_id, author_id } = args;
|
|
2366
|
+
const clear_author = args.clear_author ?? false;
|
|
2367
|
+
const warnings = [];
|
|
2368
|
+
try {
|
|
2369
|
+
const article = await this.apiClient.getArticle(entity_id);
|
|
2370
|
+
const articleStatus = article.status || "unknown";
|
|
2371
|
+
if (articleStatus !== "completed" && articleStatus !== "success") {
|
|
2372
|
+
const statusMessages = {
|
|
2373
|
+
draft: "Article has not been generated yet.",
|
|
2374
|
+
pending: "Article generation is still pending.",
|
|
2375
|
+
processing: "Article is currently being generated.",
|
|
2376
|
+
failed: "Article generation failed previously.",
|
|
2377
|
+
error: "Article encountered an error during generation."
|
|
2378
|
+
};
|
|
2379
|
+
return {
|
|
2380
|
+
content: [{
|
|
2381
|
+
type: "text",
|
|
2382
|
+
text: JSON.stringify({
|
|
2383
|
+
error: true,
|
|
2384
|
+
message: statusMessages[articleStatus] || `Article status is "${articleStatus}" \u2014 content must be generated before publishing.`,
|
|
2385
|
+
article_status: articleStatus,
|
|
2386
|
+
entity_id,
|
|
2387
|
+
next_steps: [
|
|
2388
|
+
`Use 'generate_article' with id: ${entity_id} to generate content first`,
|
|
2389
|
+
`Use 'get_article' with id: ${entity_id} to check current status`
|
|
2390
|
+
]
|
|
2391
|
+
}, null, 2)
|
|
2392
|
+
}],
|
|
2393
|
+
isError: true
|
|
2394
|
+
};
|
|
2395
|
+
}
|
|
2396
|
+
const storedAuthor = article.data?.input?.publishwordpress_author;
|
|
2397
|
+
if (storedAuthor && !author_id) {
|
|
2398
|
+
if (clear_author) {
|
|
2399
|
+
try {
|
|
2400
|
+
await this.apiClient.updateArticle(entity_id, { publishwordpress_author: void 0 });
|
|
2401
|
+
logger.info("Cleared stored publishwordpress_author before publishing", { entity_id, cleared_author: storedAuthor });
|
|
2402
|
+
} catch (clearError) {
|
|
2403
|
+
logger.warn("Failed to clear publishwordpress_author", { error: clearError.message });
|
|
2404
|
+
warnings.push(`Could not clear stored publishwordpress_author (${storedAuthor}). Publishing may fail if the WP connection user lacks edit_others_posts.`);
|
|
2405
|
+
}
|
|
2406
|
+
} else {
|
|
2407
|
+
warnings.push(
|
|
2408
|
+
`Article has stored publishwordpress_author=${storedAuthor}. If the WP connection user lacks edit_others_posts capability, publishing will fail with "rest_cannot_edit_others". Use clear_author: true to clear it before publishing.`
|
|
2409
|
+
);
|
|
2410
|
+
}
|
|
2411
|
+
}
|
|
2412
|
+
} catch (fetchError) {
|
|
2413
|
+
logger.warn("Could not pre-validate article before publishing", { entity_id, error: fetchError.message });
|
|
2414
|
+
}
|
|
2415
|
+
const options = { connection_id };
|
|
2416
|
+
if (status) options.status = status;
|
|
2417
|
+
if (date) options.date = date;
|
|
2418
|
+
if (category_id) options.category_id = category_id;
|
|
2419
|
+
if (author_id) options.author_id = author_id;
|
|
2299
2420
|
const result2 = await this.apiClient.publishToWordPress(entity_id, options);
|
|
2300
2421
|
this.metrics.recordAPICall("publish_wordpress", result2.success ? "success" : "error");
|
|
2301
2422
|
if (result2.success) {
|
|
2302
|
-
|
|
2423
|
+
const response = {
|
|
2424
|
+
success: true,
|
|
2425
|
+
message: "Content published to WordPress successfully",
|
|
2426
|
+
entity_id,
|
|
2427
|
+
wordpress_url: result2.url,
|
|
2428
|
+
status: status || "draft"
|
|
2429
|
+
};
|
|
2430
|
+
if (warnings.length > 0) response.warnings = warnings;
|
|
2431
|
+
return { content: [{ type: "text", text: JSON.stringify(response, null, 2) }] };
|
|
2303
2432
|
} else {
|
|
2304
2433
|
throw new Error(result2.error || "Publishing failed");
|
|
2305
2434
|
}
|
|
2306
2435
|
} catch (error) {
|
|
2307
2436
|
logger.error("Failed to publish to WordPress", { error: error.message });
|
|
2308
2437
|
this.metrics.recordAPICall("publish_wordpress", "error");
|
|
2309
|
-
|
|
2438
|
+
const errorMsg = (error.message || "").toLowerCase();
|
|
2439
|
+
const hints = [];
|
|
2440
|
+
if (errorMsg.includes("rest_cannot_edit_others") || errorMsg.includes("403") || errorMsg.includes("cannot edit others")) {
|
|
2441
|
+
hints.push("This error is likely caused by a stored publishwordpress_author value. Try again with clear_author: true to clear it before publishing.");
|
|
2442
|
+
}
|
|
2443
|
+
const response = { error: true, message: error.message || "Failed to publish to WordPress" };
|
|
2444
|
+
if (hints.length > 0) response.hints = hints;
|
|
2445
|
+
return { content: [{ type: "text", text: JSON.stringify(response, null, 2) }], isError: true };
|
|
2310
2446
|
}
|
|
2311
2447
|
}, "handler")
|
|
2312
2448
|
};
|
|
@@ -2871,16 +3007,8 @@ var BulkOperationsToolHandler = class {
|
|
|
2871
3007
|
},
|
|
2872
3008
|
handler: /* @__PURE__ */ __name(async (args) => {
|
|
2873
3009
|
try {
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
logger.info("Converting articles from string to array");
|
|
2877
|
-
try {
|
|
2878
|
-
processedArgs.articles = JSON.parse(args.articles);
|
|
2879
|
-
} catch (error) {
|
|
2880
|
-
throw new Error("Invalid articles format: expected array or JSON string");
|
|
2881
|
-
}
|
|
2882
|
-
}
|
|
2883
|
-
const { articles, auto_generate = false } = processedArgs;
|
|
3010
|
+
const articles = resolveArray(args, "articles");
|
|
3011
|
+
const auto_generate = args.auto_generate ?? false;
|
|
2884
3012
|
logger.info("Validating and transforming article data types", { count: articles.length });
|
|
2885
3013
|
const validatedArticles = articles.map((article, index) => {
|
|
2886
3014
|
try {
|
|
@@ -2994,17 +3122,24 @@ var BulkOperationsToolHandler = class {
|
|
|
2994
3122
|
},
|
|
2995
3123
|
handler: /* @__PURE__ */ __name(async (args) => {
|
|
2996
3124
|
try {
|
|
2997
|
-
|
|
2998
|
-
if (typeof args.articles === "string") {
|
|
2999
|
-
logger.info("Converting articles from string to array (bulk cost estimate)");
|
|
3000
|
-
try {
|
|
3001
|
-
processedArgs.articles = JSON.parse(args.articles);
|
|
3002
|
-
} catch (error) {
|
|
3003
|
-
throw new Error("Invalid articles format: expected array or JSON string");
|
|
3004
|
-
}
|
|
3005
|
-
}
|
|
3006
|
-
const { articles } = processedArgs;
|
|
3125
|
+
const articles = resolveArray(args, "articles");
|
|
3007
3126
|
const result2 = await this.apiClient.calculateBulkCost(articles);
|
|
3127
|
+
logger.debug("bulk_estimate_cost raw API response keys", { keys: Object.keys(result2 || {}) });
|
|
3128
|
+
const breakdown = result2?.breakdown ?? result2?.items ?? result2?.estimates ?? [];
|
|
3129
|
+
let total;
|
|
3130
|
+
if (typeof result2?.total === "number" && !isNaN(result2.total)) {
|
|
3131
|
+
total = result2.total;
|
|
3132
|
+
} else if (typeof result2?.credits === "number" && !isNaN(result2.credits)) {
|
|
3133
|
+
total = result2.credits;
|
|
3134
|
+
} else if (typeof result2?.cost === "number" && !isNaN(result2.cost)) {
|
|
3135
|
+
total = result2.cost;
|
|
3136
|
+
} else if (Array.isArray(breakdown) && breakdown.length > 0) {
|
|
3137
|
+
total = breakdown.reduce((sum, item) => sum + (item?.credits ?? item?.cost ?? 0), 0);
|
|
3138
|
+
logger.info("bulk_estimate_cost: total derived from breakdown sum", { total });
|
|
3139
|
+
} else {
|
|
3140
|
+
total = 0;
|
|
3141
|
+
logger.warn("bulk_estimate_cost: could not extract total from API response, defaulting to 0", { resultKeys: Object.keys(result2 || {}) });
|
|
3142
|
+
}
|
|
3008
3143
|
this.metrics.recordAPICall("bulk_estimate_cost", "success");
|
|
3009
3144
|
return {
|
|
3010
3145
|
content: [
|
|
@@ -3013,16 +3148,15 @@ var BulkOperationsToolHandler = class {
|
|
|
3013
3148
|
text: JSON.stringify({
|
|
3014
3149
|
success: true,
|
|
3015
3150
|
total_cost: {
|
|
3016
|
-
credits:
|
|
3017
|
-
usd: (
|
|
3018
|
-
// Assuming 1 credit = $0.01
|
|
3151
|
+
credits: total,
|
|
3152
|
+
usd: (total * 0.01).toFixed(2)
|
|
3019
3153
|
},
|
|
3020
3154
|
article_count: articles.length,
|
|
3021
3155
|
average_cost_per_article: {
|
|
3022
|
-
credits: Math.round(
|
|
3023
|
-
usd: (
|
|
3156
|
+
credits: articles.length > 0 ? Math.round(total / articles.length) : 0,
|
|
3157
|
+
usd: articles.length > 0 ? (total / articles.length * 0.01).toFixed(2) : "0.00"
|
|
3024
3158
|
},
|
|
3025
|
-
breakdown
|
|
3159
|
+
breakdown
|
|
3026
3160
|
}, null, 2)
|
|
3027
3161
|
}
|
|
3028
3162
|
]
|
|
@@ -3647,7 +3781,7 @@ var CategoryPagesToolHandler = class {
|
|
|
3647
3781
|
country: { type: "string", enum: [...COUNTRY_ENUM2], description: "Target country for localization" },
|
|
3648
3782
|
project_id: { type: "string", format: "uuid", description: "Project UUID" },
|
|
3649
3783
|
persona_id: { type: "string", format: "uuid", description: "Persona UUID" },
|
|
3650
|
-
apply_project_brief_config: { type: "boolean", description: "Apply project configuration", default: false },
|
|
3784
|
+
apply_project_brief_config: { type: "boolean", description: "Apply project configuration. When true with a project_id, lang/country will be inherited from the project if not explicitly provided.", default: false },
|
|
3651
3785
|
use_faq: { type: "boolean", description: "Generate FAQ section", default: false },
|
|
3652
3786
|
use_toc: { type: "boolean", description: "Generate table of contents", default: false },
|
|
3653
3787
|
use_image: { type: "boolean", description: "Generate featured image", default: false },
|
|
@@ -3660,7 +3794,7 @@ var CategoryPagesToolHandler = class {
|
|
|
3660
3794
|
publishwordpress_date: { type: "string", description: "Publication date (ISO 8601 or WordPress format)" },
|
|
3661
3795
|
publishwordpress_status: { type: "string", enum: ["draft", "publish", "future"], description: "WordPress post status" },
|
|
3662
3796
|
publishwordpress_category: { type: "number", description: "WordPress category ID" },
|
|
3663
|
-
publishwordpress_author: { type: "number", description: "WordPress author ID" },
|
|
3797
|
+
publishwordpress_author: { type: "number", description: "WordPress author ID. CAUTION: If the WP connection user lacks edit_others_posts capability, setting this will cause publishing to fail with rest_cannot_edit_others. Omit unless the WP user has admin/editor role." },
|
|
3664
3798
|
publishwordpress_connection: { type: "string", format: "uuid", description: "WordPress connection UUID" }
|
|
3665
3799
|
},
|
|
3666
3800
|
required: ["name", "subject"]
|
|
@@ -3668,9 +3802,21 @@ var CategoryPagesToolHandler = class {
|
|
|
3668
3802
|
handler: /* @__PURE__ */ __name(async (args) => {
|
|
3669
3803
|
try {
|
|
3670
3804
|
const validated = CreateCategoryPageSchema.parse(args);
|
|
3805
|
+
if (validated.apply_project_brief_config && validated.project_id && (!validated.lang || !validated.country)) {
|
|
3806
|
+
try {
|
|
3807
|
+
const project = await this.apiClient.getProject(validated.project_id);
|
|
3808
|
+
if (!validated.lang && project.default_lang) {
|
|
3809
|
+
validated.lang = project.default_lang;
|
|
3810
|
+
}
|
|
3811
|
+
if (!validated.country && project.default_country) {
|
|
3812
|
+
validated.country = project.default_country;
|
|
3813
|
+
}
|
|
3814
|
+
} catch (e) {
|
|
3815
|
+
logger.warn("Could not fetch project for lang/country defaults", { error: e.message });
|
|
3816
|
+
}
|
|
3817
|
+
}
|
|
3671
3818
|
const input = this.buildApiInput(validated);
|
|
3672
3819
|
const categoryPage = await this.apiClient.createCategoryPage(input);
|
|
3673
|
-
await this.cache.set(`category_page:${categoryPage.id}`, categoryPage, 300);
|
|
3674
3820
|
this.metrics.recordAPICall("create_category_page", "success");
|
|
3675
3821
|
const displayName = categoryPage.name || validated.name || args.name || "Unnamed";
|
|
3676
3822
|
return {
|
|
@@ -3838,10 +3984,19 @@ var CategoryPagesToolHandler = class {
|
|
|
3838
3984
|
return {
|
|
3839
3985
|
name: "estimate_category_page_cost",
|
|
3840
3986
|
description: "Estimate the cost of generating a category page",
|
|
3841
|
-
inputSchema: {
|
|
3987
|
+
inputSchema: {
|
|
3988
|
+
type: "object",
|
|
3989
|
+
properties: {
|
|
3990
|
+
subject: { type: "string", description: "Category page subject", minLength: 1 },
|
|
3991
|
+
length: { oneOf: [{ type: "number", maximum: 5e3 }, { type: "string", const: "auto" }], default: "auto" },
|
|
3992
|
+
use_image: { type: "boolean", default: false }
|
|
3993
|
+
},
|
|
3994
|
+
required: ["subject"]
|
|
3995
|
+
},
|
|
3842
3996
|
handler: /* @__PURE__ */ __name(async (args) => {
|
|
3843
3997
|
try {
|
|
3844
|
-
const
|
|
3998
|
+
const costInput = args.data || args;
|
|
3999
|
+
const cost = await this.apiClient.calculateCategoryPageCost(costInput);
|
|
3845
4000
|
this.metrics.recordAPICall("estimate_category_page_cost", "success");
|
|
3846
4001
|
return { content: [{ type: "text", text: JSON.stringify({ success: true, cost_estimate: cost }, null, 2) }] };
|
|
3847
4002
|
} catch (error) {
|
|
@@ -3859,7 +4014,7 @@ var CategoryPagesToolHandler = class {
|
|
|
3859
4014
|
inputSchema: { type: "object", properties: { items: { type: "array", items: { type: "object" }, description: "Array of category page configurations" } }, required: ["items"] },
|
|
3860
4015
|
handler: /* @__PURE__ */ __name(async (args) => {
|
|
3861
4016
|
try {
|
|
3862
|
-
const
|
|
4017
|
+
const items = resolveArray(args, "items");
|
|
3863
4018
|
const result2 = await this.apiClient.createBulkCategoryPages(items);
|
|
3864
4019
|
this.metrics.recordAPICall("bulk_create_category_pages", "success");
|
|
3865
4020
|
return { content: [{ type: "text", text: JSON.stringify({ success: true, message: `Bulk created ${items.length} category pages`, result: result2 }, null, 2) }] };
|
|
@@ -3963,7 +4118,7 @@ var ProductPagesToolHandler = class {
|
|
|
3963
4118
|
country: { type: "string", enum: [...COUNTRY_ENUM3], description: "Target country for localization" },
|
|
3964
4119
|
project_id: { type: "string", format: "uuid", description: "Project UUID" },
|
|
3965
4120
|
persona_id: { type: "string", format: "uuid", description: "Persona UUID" },
|
|
3966
|
-
apply_project_brief_config: { type: "boolean", description: "Apply project configuration", default: false },
|
|
4121
|
+
apply_project_brief_config: { type: "boolean", description: "Apply project configuration. When true with a project_id, lang/country will be inherited from the project if not explicitly provided.", default: false },
|
|
3967
4122
|
use_faq: { type: "boolean", description: "Generate FAQ section", default: false },
|
|
3968
4123
|
use_toc: { type: "boolean", description: "Generate table of contents", default: false },
|
|
3969
4124
|
use_image: { type: "boolean", description: "Generate featured image", default: false },
|
|
@@ -3976,7 +4131,7 @@ var ProductPagesToolHandler = class {
|
|
|
3976
4131
|
publishwordpress_date: { type: "string", description: "Publication date (ISO 8601 or WordPress format)" },
|
|
3977
4132
|
publishwordpress_status: { type: "string", enum: ["draft", "publish", "future"], description: "WordPress post status" },
|
|
3978
4133
|
publishwordpress_category: { type: "number", description: "WordPress category ID" },
|
|
3979
|
-
publishwordpress_author: { type: "number", description: "WordPress author ID" },
|
|
4134
|
+
publishwordpress_author: { type: "number", description: "WordPress author ID. CAUTION: If the WP connection user lacks edit_others_posts capability, setting this will cause publishing to fail with rest_cannot_edit_others. Omit unless the WP user has admin/editor role." },
|
|
3980
4135
|
publishwordpress_connection: { type: "string", format: "uuid", description: "WordPress connection UUID" }
|
|
3981
4136
|
},
|
|
3982
4137
|
required: ["name", "subject"]
|
|
@@ -3984,9 +4139,21 @@ var ProductPagesToolHandler = class {
|
|
|
3984
4139
|
handler: /* @__PURE__ */ __name(async (args) => {
|
|
3985
4140
|
try {
|
|
3986
4141
|
const validated = CreateProductPageSchema.parse(args);
|
|
4142
|
+
if (validated.apply_project_brief_config && validated.project_id && (!validated.lang || !validated.country)) {
|
|
4143
|
+
try {
|
|
4144
|
+
const project = await this.apiClient.getProject(validated.project_id);
|
|
4145
|
+
if (!validated.lang && project.default_lang) {
|
|
4146
|
+
validated.lang = project.default_lang;
|
|
4147
|
+
}
|
|
4148
|
+
if (!validated.country && project.default_country) {
|
|
4149
|
+
validated.country = project.default_country;
|
|
4150
|
+
}
|
|
4151
|
+
} catch (e) {
|
|
4152
|
+
logger.warn("Could not fetch project for lang/country defaults", { error: e.message });
|
|
4153
|
+
}
|
|
4154
|
+
}
|
|
3987
4155
|
const input = this.buildApiInput(validated);
|
|
3988
4156
|
const productPage = await this.apiClient.createProductPage(input);
|
|
3989
|
-
await this.cache.set(`product_page:${productPage.id}`, productPage, 300);
|
|
3990
4157
|
this.metrics.recordAPICall("create_product_page", "success");
|
|
3991
4158
|
const displayName = productPage.name || validated.name || args.name || "Unnamed";
|
|
3992
4159
|
return { content: [{ type: "text", text: JSON.stringify({ success: true, product_page_id: productPage.id, name: displayName, message: `Product page "${displayName}" created successfully`, next_steps: [`Use 'generate_product_page' with id: ${productPage.id}`, `Use 'get_product_page' with id: ${productPage.id}`] }, null, 2) }] };
|
|
@@ -4135,10 +4302,19 @@ var ProductPagesToolHandler = class {
|
|
|
4135
4302
|
return {
|
|
4136
4303
|
name: "estimate_product_page_cost",
|
|
4137
4304
|
description: "Estimate the cost of generating a product page",
|
|
4138
|
-
inputSchema: {
|
|
4305
|
+
inputSchema: {
|
|
4306
|
+
type: "object",
|
|
4307
|
+
properties: {
|
|
4308
|
+
subject: { type: "string", description: "Product page subject", minLength: 1 },
|
|
4309
|
+
length: { oneOf: [{ type: "number", maximum: 5e3 }, { type: "string", const: "auto" }], default: "auto" },
|
|
4310
|
+
use_image: { type: "boolean", default: false }
|
|
4311
|
+
},
|
|
4312
|
+
required: ["subject"]
|
|
4313
|
+
},
|
|
4139
4314
|
handler: /* @__PURE__ */ __name(async (args) => {
|
|
4140
4315
|
try {
|
|
4141
|
-
const
|
|
4316
|
+
const costInput = args.data || args;
|
|
4317
|
+
const cost = await this.apiClient.calculateProductPageCost(costInput);
|
|
4142
4318
|
this.metrics.recordAPICall("estimate_product_page_cost", "success");
|
|
4143
4319
|
return { content: [{ type: "text", text: JSON.stringify({ success: true, cost_estimate: cost }, null, 2) }] };
|
|
4144
4320
|
} catch (error) {
|
|
@@ -4156,7 +4332,7 @@ var ProductPagesToolHandler = class {
|
|
|
4156
4332
|
inputSchema: { type: "object", properties: { items: { type: "array", items: { type: "object" }, description: "Array of product page configurations" } }, required: ["items"] },
|
|
4157
4333
|
handler: /* @__PURE__ */ __name(async (args) => {
|
|
4158
4334
|
try {
|
|
4159
|
-
const
|
|
4335
|
+
const items = resolveArray(args, "items");
|
|
4160
4336
|
const result2 = await this.apiClient.createBulkProductPages(items);
|
|
4161
4337
|
this.metrics.recordAPICall("bulk_create_product_pages", "success");
|
|
4162
4338
|
return { content: [{ type: "text", text: JSON.stringify({ success: true, message: `Bulk created ${items.length} product pages`, result: result2 }, null, 2) }] };
|
|
@@ -4277,7 +4453,7 @@ var DiscoverToolHandler = class {
|
|
|
4277
4453
|
keywords_secondary: { type: "string", description: "Secondary keywords" },
|
|
4278
4454
|
project_id: { type: "string", format: "uuid", description: "Project UUID" },
|
|
4279
4455
|
persona_id: { type: "string", format: "uuid", description: "Persona UUID" },
|
|
4280
|
-
apply_project_brief_config: { type: "boolean", description: "Apply project brief configuration settings. When true, inherits all feature flags and settings from the project brief (use_faq, use_toc, use_inline_images, internal links, etc.). Recommended for consistency.", default: false },
|
|
4456
|
+
apply_project_brief_config: { type: "boolean", description: "Apply project brief configuration settings. When true, inherits all feature flags and settings from the project brief (use_faq, use_toc, use_inline_images, internal links, etc.). When true with a project_id, lang/country will be inherited from the project if not explicitly provided. Recommended for consistency.", default: false },
|
|
4281
4457
|
lang: { type: "string", enum: ["fr", "en"], description: "Language code" },
|
|
4282
4458
|
country: { type: "string", enum: ["fr", "be", "ch", "ca", "us", "gb"], description: "Country code" },
|
|
4283
4459
|
length: { description: 'Number (max 2000) or "auto"' },
|
|
@@ -4319,7 +4495,7 @@ var DiscoverToolHandler = class {
|
|
|
4319
4495
|
publishwordpress_date: { type: "string", description: "WordPress publish date" },
|
|
4320
4496
|
publishwordpress_status: { type: "string", enum: ["draft", "publish", "future"], description: "WordPress post status" },
|
|
4321
4497
|
publishwordpress_category: { type: "number", description: "WordPress category ID" },
|
|
4322
|
-
publishwordpress_author: { type: "number", description: "WordPress author ID" },
|
|
4498
|
+
publishwordpress_author: { type: "number", description: "WordPress author ID. CAUTION: If the WP connection user lacks edit_others_posts capability, setting this will cause publishing to fail with rest_cannot_edit_others. Omit unless the WP user has admin/editor role." },
|
|
4323
4499
|
publishwordpress_connection: { type: "string", description: "WordPress connection ID" },
|
|
4324
4500
|
// Additional features
|
|
4325
4501
|
use_infotable: { type: "boolean", description: "Add info table" },
|
|
@@ -4344,6 +4520,19 @@ var DiscoverToolHandler = class {
|
|
|
4344
4520
|
apply_project_brief_config_raw_type: typeof args.apply_project_brief_config
|
|
4345
4521
|
});
|
|
4346
4522
|
const validated = DiscoverContentSchema.parse(args);
|
|
4523
|
+
if (validated.apply_project_brief_config && validated.project_id && (!validated.lang || !validated.country)) {
|
|
4524
|
+
try {
|
|
4525
|
+
const project = await this.apiClient.getProject(validated.project_id);
|
|
4526
|
+
if (!validated.lang && project.default_lang) {
|
|
4527
|
+
validated.lang = project.default_lang;
|
|
4528
|
+
}
|
|
4529
|
+
if (!validated.country && project.default_country) {
|
|
4530
|
+
validated.country = project.default_country;
|
|
4531
|
+
}
|
|
4532
|
+
} catch (e) {
|
|
4533
|
+
logger.warn("Could not fetch project for lang/country defaults", { error: e.message });
|
|
4534
|
+
}
|
|
4535
|
+
}
|
|
4347
4536
|
logger.info("discover_content VALIDATED (after boolField transform)", {
|
|
4348
4537
|
apply_project_brief_config: validated.apply_project_brief_config,
|
|
4349
4538
|
apply_project_brief_config_type: typeof validated.apply_project_brief_config,
|
|
@@ -4363,7 +4552,6 @@ var DiscoverToolHandler = class {
|
|
|
4363
4552
|
apply_project_brief_config_value: cleanedInput.apply_project_brief_config
|
|
4364
4553
|
});
|
|
4365
4554
|
const discovery = await this.apiClient.discoverArticles(cleanedInput);
|
|
4366
|
-
await this.cache.set(`discover:${discovery.id}`, discovery, 300);
|
|
4367
4555
|
this.metrics.recordAPICall("discover_content", "success");
|
|
4368
4556
|
return {
|
|
4369
4557
|
content: [{
|
|
@@ -4507,10 +4695,19 @@ var DiscoverToolHandler = class {
|
|
|
4507
4695
|
return {
|
|
4508
4696
|
name: "estimate_discover_cost",
|
|
4509
4697
|
description: "Estimate the cost of a discover article",
|
|
4510
|
-
inputSchema: {
|
|
4698
|
+
inputSchema: {
|
|
4699
|
+
type: "object",
|
|
4700
|
+
properties: {
|
|
4701
|
+
subject: { type: "string", description: "Discover article subject", minLength: 1 },
|
|
4702
|
+
length: { oneOf: [{ type: "number", maximum: 2e3 }, { type: "string", const: "auto" }], default: "auto" },
|
|
4703
|
+
use_image: { type: "boolean", default: false }
|
|
4704
|
+
},
|
|
4705
|
+
required: ["subject"]
|
|
4706
|
+
},
|
|
4511
4707
|
handler: /* @__PURE__ */ __name(async (args) => {
|
|
4512
4708
|
try {
|
|
4513
|
-
const
|
|
4709
|
+
const costInput = args.data || args;
|
|
4710
|
+
const cost = await this.apiClient.calculateDiscoverCost(costInput);
|
|
4514
4711
|
this.metrics.recordAPICall("estimate_discover_cost", "success");
|
|
4515
4712
|
return { content: [{ type: "text", text: JSON.stringify({ success: true, cost_estimate: cost }, null, 2) }] };
|
|
4516
4713
|
} catch (error) {
|
|
@@ -4528,7 +4725,7 @@ var DiscoverToolHandler = class {
|
|
|
4528
4725
|
inputSchema: { type: "object", properties: { items: { type: "array", items: { type: "object" }, description: "Array of discover article configurations" } }, required: ["items"] },
|
|
4529
4726
|
handler: /* @__PURE__ */ __name(async (args) => {
|
|
4530
4727
|
try {
|
|
4531
|
-
const
|
|
4728
|
+
const items = resolveArray(args, "items");
|
|
4532
4729
|
const result2 = await this.apiClient.createBulkDiscoverArticles(items);
|
|
4533
4730
|
this.metrics.recordAPICall("bulk_create_discover_articles", "success");
|
|
4534
4731
|
return { content: [{ type: "text", text: JSON.stringify({ success: true, message: `Bulk created ${items.length} discover articles`, result: result2 }, null, 2) }] };
|
|
@@ -4621,8 +4818,10 @@ var RSSToolHandler = class {
|
|
|
4621
4818
|
} catch (error) {
|
|
4622
4819
|
logger.error("Failed to create feed", { error: error.message });
|
|
4623
4820
|
this.metrics.recordAPICall("create_feed", "error");
|
|
4821
|
+
const errorMessage = error.message || "Failed to create feed";
|
|
4822
|
+
const guidance = "Please verify the feed URL is a valid RSS/Atom feed and is accessible. If the URL is correct, this may be a temporary Wisewand service issue \u2014 try again later.";
|
|
4624
4823
|
return {
|
|
4625
|
-
content: [{ type: "text", text: JSON.stringify({ error: true, message:
|
|
4824
|
+
content: [{ type: "text", text: JSON.stringify({ error: true, message: errorMessage, guidance, details: error.issues || void 0 }, null, 2) }],
|
|
4626
4825
|
isError: true
|
|
4627
4826
|
};
|
|
4628
4827
|
}
|