@wisewandtools/mcp-server 2.2.0 → 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 CHANGED
@@ -1169,6 +1169,63 @@ var HealthChecker = class {
1169
1169
 
1170
1170
  // src/handlers/tools/ArticleToolHandler.ts
1171
1171
  import { z as z2 } from "zod";
1172
+
1173
+ // src/utils/tool-helpers.ts
1174
+ var UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
1175
+ var ToolInputError = class extends Error {
1176
+ static {
1177
+ __name(this, "ToolInputError");
1178
+ }
1179
+ constructor(message) {
1180
+ super(message);
1181
+ this.name = "ToolInputError";
1182
+ }
1183
+ };
1184
+ function resolveId(args, ...fallbackKeys) {
1185
+ const value = args.id ?? args.Id ?? args.ID;
1186
+ if (value !== void 0 && value !== null) {
1187
+ return validateUuid(value);
1188
+ }
1189
+ for (const key of fallbackKeys) {
1190
+ if (args[key] !== void 0 && args[key] !== null) {
1191
+ return validateUuid(args[key]);
1192
+ }
1193
+ }
1194
+ const tried = ["id", ...fallbackKeys].join(", ");
1195
+ throw new ToolInputError(`Missing required ID. Provide one of: ${tried}`);
1196
+ }
1197
+ __name(resolveId, "resolveId");
1198
+ function validateUuid(value) {
1199
+ const str = String(value);
1200
+ if (!UUID_REGEX.test(str)) {
1201
+ throw new ToolInputError(`Invalid ID format: "${str}" is not a valid UUID`);
1202
+ }
1203
+ return str;
1204
+ }
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");
1227
+
1228
+ // src/handlers/tools/ArticleToolHandler.ts
1172
1229
  var boolField = z2.union([z2.boolean(), z2.string()]).transform(
1173
1230
  (val) => typeof val === "string" ? val === "true" : val
1174
1231
  ).optional().default(false);
@@ -1465,7 +1522,7 @@ var ArticleToolHandler = class {
1465
1522
  publishwordpress_date: { type: "string", description: "WordPress publish date (ISO 8601)" },
1466
1523
  publishwordpress_status: { type: "string", enum: ["draft", "publish", "future"], description: "WordPress post status", default: "draft" },
1467
1524
  publishwordpress_category: { type: "number", description: "WordPress category ID" },
1468
- 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." },
1469
1526
  publishwordpress_connection: { type: "string", format: "uuid", description: "WordPress connection ID" },
1470
1527
  // Shopify Publishing
1471
1528
  use_publishshopify: { type: "boolean", description: "Automatically publish to Shopify" },
@@ -1537,21 +1594,38 @@ var ArticleToolHandler = class {
1537
1594
  const validated = CreateArticleSchema.parse(args);
1538
1595
  const apiInput = this.buildApiInput(validated);
1539
1596
  const article = await this.apiClient.createArticle(apiInput);
1540
- await this.cache.set(`article:${article.id}`, article, 300);
1541
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
+ }
1542
1625
  return {
1543
1626
  content: [{
1544
1627
  type: "text",
1545
- text: JSON.stringify({
1546
- success: true,
1547
- article_id: article.id,
1548
- title: article.title || "Article created",
1549
- message: `Article "${article.title || validated.subject}" created successfully.`,
1550
- next_steps: [
1551
- `Use 'generate_article' with article_id: ${article.id} to start content generation`,
1552
- `Use 'get_article' with article_id: ${article.id} to check status`
1553
- ]
1554
- }, null, 2)
1628
+ text: JSON.stringify(response, null, 2)
1555
1629
  }]
1556
1630
  };
1557
1631
  } catch (error) {
@@ -1572,15 +1646,16 @@ var ArticleToolHandler = class {
1572
1646
  inputSchema: {
1573
1647
  type: "object",
1574
1648
  properties: {
1575
- article_id: { type: "string", format: "uuid", description: "ID of the article to generate" },
1649
+ id: { type: "string", format: "uuid", description: "ID of the article to generate" },
1576
1650
  wait_for_completion: { type: "boolean", description: "Wait for generation to complete (may take several minutes)", default: true },
1577
1651
  max_wait_time: { type: "number", description: "Maximum time to wait in seconds", default: 300, maximum: 600 }
1578
1652
  },
1579
- required: ["article_id"]
1653
+ required: ["id"]
1580
1654
  },
1581
1655
  handler: /* @__PURE__ */ __name(async (args) => {
1582
1656
  try {
1583
- const { article_id, wait_for_completion = true, max_wait_time = 300 } = args;
1657
+ const article_id = resolveId(args, "article_id");
1658
+ const { wait_for_completion = true, max_wait_time = 300 } = args;
1584
1659
  await this.apiClient.runArticleGeneration(article_id);
1585
1660
  if (!wait_for_completion) {
1586
1661
  return { content: [{ type: "text", text: JSON.stringify({ success: true, message: "Article generation started", article_id, next_step: `Use 'get_article' or 'get_article_output' to check status` }, null, 2) }] };
@@ -1618,6 +1693,22 @@ var ArticleToolHandler = class {
1618
1693
  }
1619
1694
  throw new Error(`Generation timeout after ${max_wait_time} seconds`);
1620
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
+ }
1621
1712
  logger.error("Failed to generate article", { error: error.message });
1622
1713
  this.metrics.recordAPICall("generate_article", "error");
1623
1714
  return { content: [{ type: "text", text: JSON.stringify({ error: true, message: error.message || "Failed to generate article" }, null, 2) }], isError: true };
@@ -1631,12 +1722,12 @@ var ArticleToolHandler = class {
1631
1722
  description: "Get article details and status",
1632
1723
  inputSchema: {
1633
1724
  type: "object",
1634
- properties: { article_id: { type: "string", format: "uuid", description: "ID of the article to retrieve" } },
1635
- required: ["article_id"]
1725
+ properties: { id: { type: "string", format: "uuid", description: "ID of the article to retrieve" } },
1726
+ required: ["id"]
1636
1727
  },
1637
1728
  handler: /* @__PURE__ */ __name(async (args) => {
1638
1729
  try {
1639
- const { article_id } = args;
1730
+ const article_id = resolveId(args, "article_id");
1640
1731
  const cached = await this.cache.get(`article:${article_id}`);
1641
1732
  if (cached) {
1642
1733
  return { content: [{ type: "text", text: JSON.stringify({ success: true, article: cached, from_cache: true }, null, 2) }] };
@@ -1662,8 +1753,7 @@ var ArticleToolHandler = class {
1662
1753
  properties: {
1663
1754
  search: { type: "string", description: "Search term to filter articles" },
1664
1755
  status: { type: "string", description: "Filter by status" },
1665
- projectId: { type: "string", format: "uuid", description: "Filter by project (camelCase as per API)" },
1666
- project_id: { type: "string", format: "uuid", description: "Filter by project (alias)" },
1756
+ project_id: { type: "string", format: "uuid", description: "Filter by project" },
1667
1757
  maker: { type: "string", description: "Filter by maker" },
1668
1758
  persona: { type: "string", description: "Filter by persona" },
1669
1759
  author: { type: "string", description: "Filter by author" },
@@ -1677,7 +1767,12 @@ var ArticleToolHandler = class {
1677
1767
  },
1678
1768
  handler: /* @__PURE__ */ __name(async (args) => {
1679
1769
  try {
1680
- const result2 = await this.apiClient.listArticles(args);
1770
+ const apiParams = { ...args };
1771
+ if (apiParams.project_id) {
1772
+ apiParams.projectId = apiParams.project_id;
1773
+ delete apiParams.project_id;
1774
+ }
1775
+ const result2 = await this.apiClient.listArticles(apiParams);
1681
1776
  this.metrics.recordAPICall("list_articles", "success");
1682
1777
  return {
1683
1778
  content: [{
@@ -1686,7 +1781,17 @@ var ArticleToolHandler = class {
1686
1781
  success: true,
1687
1782
  total: result2.total,
1688
1783
  count: result2.items.length,
1689
- articles: result2.items.map((a) => ({ id: a.id, title: a.title, status: a.status, created_at: a.created_at, type: a.data?.input?.type })),
1784
+ articles: result2.items.map((a) => ({
1785
+ id: a.id,
1786
+ title: a.title,
1787
+ status: a.status,
1788
+ created_at: a.created_at,
1789
+ type: a.data?.input?.type,
1790
+ project_id: a.data?.input?.project_id,
1791
+ target_keyword: a.data?.input?.target_keyword,
1792
+ lang: a.data?.input?.lang,
1793
+ subject: a.data?.input?.subject
1794
+ })),
1690
1795
  pagination: { skip: result2.skip, take: result2.take, has_more: result2.skip + result2.take < result2.total }
1691
1796
  }, null, 2)
1692
1797
  }]
@@ -1706,18 +1811,19 @@ var ArticleToolHandler = class {
1706
1811
  inputSchema: {
1707
1812
  type: "object",
1708
1813
  properties: {
1709
- article_id: { type: "string", format: "uuid", description: "ID of the article to update" },
1814
+ id: { type: "string", format: "uuid", description: "ID of the article to update" },
1710
1815
  updates: {
1711
1816
  type: "object",
1712
1817
  description: "Fields to update (supports all create_article parameters)",
1713
1818
  properties: this.buildArticleInputSchema()
1714
1819
  }
1715
1820
  },
1716
- required: ["article_id", "updates"]
1821
+ required: ["id", "updates"]
1717
1822
  },
1718
1823
  handler: /* @__PURE__ */ __name(async (args) => {
1719
1824
  try {
1720
- const { article_id, updates } = args;
1825
+ const article_id = resolveId(args, "article_id");
1826
+ const { updates } = args;
1721
1827
  await this.apiClient.updateArticle(article_id, updates);
1722
1828
  await this.cache.delete(`article:${article_id}`);
1723
1829
  this.metrics.recordAPICall("update_article", "success");
@@ -1739,14 +1845,15 @@ var ArticleToolHandler = class {
1739
1845
  inputSchema: {
1740
1846
  type: "object",
1741
1847
  properties: {
1742
- article_id: { type: "string", format: "uuid", description: "ID of the article" },
1848
+ id: { type: "string", format: "uuid", description: "ID of the article" },
1743
1849
  format: { type: "string", enum: ["full", "html", "markdown", "summary"], description: "Output format", default: "full" }
1744
1850
  },
1745
- required: ["article_id"]
1851
+ required: ["id"]
1746
1852
  },
1747
1853
  handler: /* @__PURE__ */ __name(async (args) => {
1748
1854
  try {
1749
- const { article_id, format = "full" } = args;
1855
+ const article_id = resolveId(args, "article_id");
1856
+ const { format = "full" } = args;
1750
1857
  const cacheKey = `article:output:${article_id}`;
1751
1858
  const cached = await this.cache.get(cacheKey);
1752
1859
  const output = cached || await this.apiClient.getArticleOutput(article_id);
@@ -1754,19 +1861,30 @@ var ArticleToolHandler = class {
1754
1861
  await this.cache.set(cacheKey, output, 600);
1755
1862
  }
1756
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 || {}) });
1757
1867
  let formattedOutput;
1758
1868
  switch (format) {
1759
- case "html":
1760
- formattedOutput = { html: output.html_content, title: output.title };
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)" };
1761
1873
  break;
1874
+ }
1762
1875
  case "markdown":
1763
- formattedOutput = { content: output.content, title: output.title };
1876
+ formattedOutput = { content: normalizedOutput?.content ?? normalizedOutput?.markdown ?? null, title: normalizedOutput?.title ?? null };
1764
1877
  break;
1765
- case "summary":
1766
- formattedOutput = { title: output.title, excerpt: output.excerpt, word_count: output.word_count, seo_score: output.seo_score };
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)" };
1767
1884
  break;
1885
+ }
1768
1886
  default:
1769
- formattedOutput = output;
1887
+ formattedOutput = normalizedOutput;
1770
1888
  }
1771
1889
  return { content: [{ type: "text", text: JSON.stringify({ success: true, article_id, format, output: formattedOutput, from_cache: !!cached }, null, 2) }] };
1772
1890
  } catch (error) {
@@ -1784,15 +1902,16 @@ var ArticleToolHandler = class {
1784
1902
  inputSchema: {
1785
1903
  type: "object",
1786
1904
  properties: {
1787
- article_id: { type: "string", format: "uuid", description: "ID of the article" },
1905
+ id: { type: "string", format: "uuid", description: "ID of the article" },
1788
1906
  output_id: { type: "string", format: "uuid", description: "ID of the output to update" },
1789
1907
  updates: { type: "object", description: "Fields to update in the output" }
1790
1908
  },
1791
- required: ["article_id", "output_id", "updates"]
1909
+ required: ["id", "output_id", "updates"]
1792
1910
  },
1793
1911
  handler: /* @__PURE__ */ __name(async (args) => {
1794
1912
  try {
1795
- const { article_id, output_id, updates } = args;
1913
+ const article_id = resolveId(args, "article_id");
1914
+ const { output_id, updates } = args;
1796
1915
  const result2 = await this.apiClient.updateArticleOutput(article_id, output_id, updates);
1797
1916
  await this.cache.delete(`article:output:${article_id}`);
1798
1917
  this.metrics.recordAPICall("update_article_output", "success");
@@ -1947,18 +2066,18 @@ var ProjectToolHandler = class {
1947
2066
  inputSchema: {
1948
2067
  type: "object",
1949
2068
  properties: {
1950
- project_id: {
2069
+ id: {
1951
2070
  type: "string",
1952
2071
  format: "uuid",
1953
2072
  description: "Project ID"
1954
2073
  }
1955
2074
  },
1956
- required: ["project_id"]
2075
+ required: ["id"]
1957
2076
  },
1958
2077
  handler: /* @__PURE__ */ __name(async (args) => {
1959
2078
  try {
1960
- const { project_id } = args;
1961
- const cached = await this.cache.get(`project:${project_id}`);
2079
+ const id = resolveId(args, "project_id");
2080
+ const cached = await this.cache.get(`project:${id}`);
1962
2081
  if (cached) {
1963
2082
  return {
1964
2083
  content: [
@@ -1973,8 +2092,8 @@ var ProjectToolHandler = class {
1973
2092
  ]
1974
2093
  };
1975
2094
  }
1976
- const project = await this.apiClient.getProject(project_id);
1977
- await this.cache.set(`project:${project_id}`, project, 600);
2095
+ const project = await this.apiClient.getProject(id);
2096
+ await this.cache.set(`project:${id}`, project, 600);
1978
2097
  this.metrics.recordAPICall("get_project", "success");
1979
2098
  return {
1980
2099
  content: [
@@ -2042,12 +2161,7 @@ var ProjectToolHandler = class {
2042
2161
  success: true,
2043
2162
  total: result2.total,
2044
2163
  count: result2.items.length,
2045
- projects: result2.items.map((p) => ({
2046
- id: p.id,
2047
- name: p.name,
2048
- website_url: p.website_url,
2049
- created_at: p.created_at
2050
- }))
2164
+ projects: result2.items
2051
2165
  }, null, 2)
2052
2166
  }
2053
2167
  ]
@@ -2078,7 +2192,7 @@ var ProjectToolHandler = class {
2078
2192
  inputSchema: {
2079
2193
  type: "object",
2080
2194
  properties: {
2081
- project_id: {
2195
+ id: {
2082
2196
  type: "string",
2083
2197
  format: "uuid",
2084
2198
  description: "Project ID"
@@ -2095,13 +2209,14 @@ var ProjectToolHandler = class {
2095
2209
  }
2096
2210
  }
2097
2211
  },
2098
- required: ["project_id", "updates"]
2212
+ required: ["id", "updates"]
2099
2213
  },
2100
2214
  handler: /* @__PURE__ */ __name(async (args) => {
2101
2215
  try {
2102
- const { project_id, updates } = args;
2103
- await this.apiClient.updateProject(project_id, updates);
2104
- await this.cache.delete(`project:${project_id}`);
2216
+ const id = resolveId(args, "project_id");
2217
+ const { updates } = args;
2218
+ await this.apiClient.updateProject(id, updates);
2219
+ await this.cache.delete(`project:${id}`);
2105
2220
  this.metrics.recordAPICall("update_project", "success");
2106
2221
  return {
2107
2222
  content: [
@@ -2110,7 +2225,7 @@ var ProjectToolHandler = class {
2110
2225
  text: JSON.stringify({
2111
2226
  success: true,
2112
2227
  message: "Project updated successfully",
2113
- project_id,
2228
+ project_id: id,
2114
2229
  updated_fields: Object.keys(updates)
2115
2230
  }, null, 2)
2116
2231
  }
@@ -2142,7 +2257,7 @@ var ProjectToolHandler = class {
2142
2257
  inputSchema: {
2143
2258
  type: "object",
2144
2259
  properties: {
2145
- project_id: {
2260
+ id: {
2146
2261
  type: "string",
2147
2262
  format: "uuid",
2148
2263
  description: "Project ID to delete"
@@ -2153,11 +2268,12 @@ var ProjectToolHandler = class {
2153
2268
  const: true
2154
2269
  }
2155
2270
  },
2156
- required: ["project_id", "confirm"]
2271
+ required: ["id", "confirm"]
2157
2272
  },
2158
2273
  handler: /* @__PURE__ */ __name(async (args) => {
2159
2274
  try {
2160
- const { project_id, confirm } = args;
2275
+ const id = resolveId(args, "project_id");
2276
+ const { confirm } = args;
2161
2277
  if (!confirm) {
2162
2278
  return {
2163
2279
  content: [
@@ -2172,8 +2288,8 @@ var ProjectToolHandler = class {
2172
2288
  isError: true
2173
2289
  };
2174
2290
  }
2175
- await this.apiClient.deleteProject(project_id);
2176
- await this.cache.delete(`project:${project_id}`);
2291
+ await this.apiClient.deleteProject(id);
2292
+ await this.cache.delete(`project:${id}`);
2177
2293
  this.metrics.recordAPICall("delete_project", "success");
2178
2294
  return {
2179
2295
  content: [
@@ -2182,7 +2298,7 @@ var ProjectToolHandler = class {
2182
2298
  text: JSON.stringify({
2183
2299
  success: true,
2184
2300
  message: "Project deleted successfully",
2185
- project_id
2301
+ project_id: id
2186
2302
  }, null, 2)
2187
2303
  }
2188
2304
  ]
@@ -2229,33 +2345,104 @@ var PublishingToolHandler = class {
2229
2345
  publishToWordPressTool() {
2230
2346
  return {
2231
2347
  name: "publish_to_wordpress",
2232
- description: "Publish content to WordPress",
2348
+ description: "Publish content to WordPress. connection_id must reference a WordPress connection with sufficient permissions.",
2233
2349
  inputSchema: {
2234
2350
  type: "object",
2235
2351
  properties: {
2236
2352
  entity_id: { type: "string", format: "uuid", description: "ID of the article/content to publish" },
2237
2353
  status: { type: "string", enum: ["draft", "publish", "future"], description: "Publishing status", default: "draft" },
2238
- schedule_date: { type: "string", format: "date-time", description: "Schedule date for future publishing (ISO 8601)" },
2354
+ date: { type: "string", format: "date-time", description: 'Publication date (ISO 8601). Required when status is "future".' },
2239
2355
  category_id: { type: "number", description: "WordPress category ID" },
2240
- author_id: { type: "number", description: "WordPress author ID" },
2241
- 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 }
2242
2359
  },
2243
- required: ["entity_id"]
2360
+ required: ["entity_id", "connection_id"]
2244
2361
  },
2245
2362
  handler: /* @__PURE__ */ __name(async (args) => {
2246
2363
  try {
2247
- const { entity_id, ...options } = args;
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;
2248
2420
  const result2 = await this.apiClient.publishToWordPress(entity_id, options);
2249
2421
  this.metrics.recordAPICall("publish_wordpress", result2.success ? "success" : "error");
2250
2422
  if (result2.success) {
2251
- return { content: [{ type: "text", text: JSON.stringify({ success: true, message: "Content published to WordPress successfully", entity_id, wordpress_url: result2.url, status: options.status || "draft" }, null, 2) }] };
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) }] };
2252
2432
  } else {
2253
2433
  throw new Error(result2.error || "Publishing failed");
2254
2434
  }
2255
2435
  } catch (error) {
2256
2436
  logger.error("Failed to publish to WordPress", { error: error.message });
2257
2437
  this.metrics.recordAPICall("publish_wordpress", "error");
2258
- return { content: [{ type: "text", text: JSON.stringify({ error: true, message: error.message || "Failed to publish to WordPress" }, null, 2) }], isError: true };
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 };
2259
2446
  }
2260
2447
  }, "handler")
2261
2448
  };
@@ -2496,18 +2683,18 @@ var PersonaToolHandler = class {
2496
2683
  inputSchema: {
2497
2684
  type: "object",
2498
2685
  properties: {
2499
- persona_id: {
2686
+ id: {
2500
2687
  type: "string",
2501
2688
  format: "uuid",
2502
2689
  description: "Persona ID"
2503
2690
  }
2504
2691
  },
2505
- required: ["persona_id"]
2692
+ required: ["id"]
2506
2693
  },
2507
2694
  handler: /* @__PURE__ */ __name(async (args) => {
2508
2695
  try {
2509
- const { persona_id } = args;
2510
- const cached = await this.cache.get(`persona:${persona_id}`);
2696
+ const id = resolveId(args, "persona_id");
2697
+ const cached = await this.cache.get(`persona:${id}`);
2511
2698
  if (cached) {
2512
2699
  return {
2513
2700
  content: [
@@ -2522,8 +2709,8 @@ var PersonaToolHandler = class {
2522
2709
  ]
2523
2710
  };
2524
2711
  }
2525
- const persona = await this.apiClient.getPersona(persona_id);
2526
- await this.cache.set(`persona:${persona_id}`, persona, 600);
2712
+ const persona = await this.apiClient.getPersona(id);
2713
+ await this.cache.set(`persona:${id}`, persona, 600);
2527
2714
  this.metrics.recordAPICall("get_persona", "success");
2528
2715
  return {
2529
2716
  content: [
@@ -2628,7 +2815,7 @@ var PersonaToolHandler = class {
2628
2815
  inputSchema: {
2629
2816
  type: "object",
2630
2817
  properties: {
2631
- persona_id: {
2818
+ id: {
2632
2819
  type: "string",
2633
2820
  format: "uuid",
2634
2821
  description: "Persona ID"
@@ -2649,13 +2836,14 @@ var PersonaToolHandler = class {
2649
2836
  }
2650
2837
  }
2651
2838
  },
2652
- required: ["persona_id", "updates"]
2839
+ required: ["id", "updates"]
2653
2840
  },
2654
2841
  handler: /* @__PURE__ */ __name(async (args) => {
2655
2842
  try {
2656
- const { persona_id, updates } = args;
2657
- await this.apiClient.updatePersona(persona_id, updates);
2658
- await this.cache.delete(`persona:${persona_id}`);
2843
+ const id = resolveId(args, "persona_id");
2844
+ const { updates } = args;
2845
+ await this.apiClient.updatePersona(id, updates);
2846
+ await this.cache.delete(`persona:${id}`);
2659
2847
  this.metrics.recordAPICall("update_persona", "success");
2660
2848
  return {
2661
2849
  content: [
@@ -2664,7 +2852,7 @@ var PersonaToolHandler = class {
2664
2852
  text: JSON.stringify({
2665
2853
  success: true,
2666
2854
  message: "Persona updated successfully",
2667
- persona_id,
2855
+ persona_id: id,
2668
2856
  updated_fields: Object.keys(updates)
2669
2857
  }, null, 2)
2670
2858
  }
@@ -2696,7 +2884,7 @@ var PersonaToolHandler = class {
2696
2884
  inputSchema: {
2697
2885
  type: "object",
2698
2886
  properties: {
2699
- persona_id: {
2887
+ id: {
2700
2888
  type: "string",
2701
2889
  format: "uuid",
2702
2890
  description: "Persona ID to delete"
@@ -2707,11 +2895,12 @@ var PersonaToolHandler = class {
2707
2895
  const: true
2708
2896
  }
2709
2897
  },
2710
- required: ["persona_id", "confirm"]
2898
+ required: ["id", "confirm"]
2711
2899
  },
2712
2900
  handler: /* @__PURE__ */ __name(async (args) => {
2713
2901
  try {
2714
- const { persona_id, confirm } = args;
2902
+ const id = resolveId(args, "persona_id");
2903
+ const { confirm } = args;
2715
2904
  if (!confirm) {
2716
2905
  return {
2717
2906
  content: [
@@ -2726,8 +2915,8 @@ var PersonaToolHandler = class {
2726
2915
  isError: true
2727
2916
  };
2728
2917
  }
2729
- await this.apiClient.deletePersona(persona_id);
2730
- await this.cache.delete(`persona:${persona_id}`);
2918
+ await this.apiClient.deletePersona(id);
2919
+ await this.cache.delete(`persona:${id}`);
2731
2920
  this.metrics.recordAPICall("delete_persona", "success");
2732
2921
  return {
2733
2922
  content: [
@@ -2736,7 +2925,7 @@ var PersonaToolHandler = class {
2736
2925
  text: JSON.stringify({
2737
2926
  success: true,
2738
2927
  message: "Persona deleted successfully",
2739
- persona_id
2928
+ persona_id: id
2740
2929
  }, null, 2)
2741
2930
  }
2742
2931
  ]
@@ -2818,16 +3007,8 @@ var BulkOperationsToolHandler = class {
2818
3007
  },
2819
3008
  handler: /* @__PURE__ */ __name(async (args) => {
2820
3009
  try {
2821
- let processedArgs = { ...args };
2822
- if (typeof args.articles === "string") {
2823
- logger.info("Converting articles from string to array");
2824
- try {
2825
- processedArgs.articles = JSON.parse(args.articles);
2826
- } catch (error) {
2827
- throw new Error("Invalid articles format: expected array or JSON string");
2828
- }
2829
- }
2830
- const { articles, auto_generate = false } = processedArgs;
3010
+ const articles = resolveArray(args, "articles");
3011
+ const auto_generate = args.auto_generate ?? false;
2831
3012
  logger.info("Validating and transforming article data types", { count: articles.length });
2832
3013
  const validatedArticles = articles.map((article, index) => {
2833
3014
  try {
@@ -2941,17 +3122,24 @@ var BulkOperationsToolHandler = class {
2941
3122
  },
2942
3123
  handler: /* @__PURE__ */ __name(async (args) => {
2943
3124
  try {
2944
- let processedArgs = { ...args };
2945
- if (typeof args.articles === "string") {
2946
- logger.info("Converting articles from string to array (bulk cost estimate)");
2947
- try {
2948
- processedArgs.articles = JSON.parse(args.articles);
2949
- } catch (error) {
2950
- throw new Error("Invalid articles format: expected array or JSON string");
2951
- }
2952
- }
2953
- const { articles } = processedArgs;
3125
+ const articles = resolveArray(args, "articles");
2954
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
+ }
2955
3143
  this.metrics.recordAPICall("bulk_estimate_cost", "success");
2956
3144
  return {
2957
3145
  content: [
@@ -2960,16 +3148,15 @@ var BulkOperationsToolHandler = class {
2960
3148
  text: JSON.stringify({
2961
3149
  success: true,
2962
3150
  total_cost: {
2963
- credits: result2.total,
2964
- usd: (result2.total * 0.01).toFixed(2)
2965
- // Assuming 1 credit = $0.01
3151
+ credits: total,
3152
+ usd: (total * 0.01).toFixed(2)
2966
3153
  },
2967
3154
  article_count: articles.length,
2968
3155
  average_cost_per_article: {
2969
- credits: Math.round(result2.total / articles.length),
2970
- usd: (result2.total / articles.length * 0.01).toFixed(2)
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"
2971
3158
  },
2972
- breakdown: result2.breakdown
3159
+ breakdown
2973
3160
  }, null, 2)
2974
3161
  }
2975
3162
  ]
@@ -3093,18 +3280,18 @@ var ConnectionsToolHandler = class {
3093
3280
  inputSchema: {
3094
3281
  type: "object",
3095
3282
  properties: {
3096
- connection_id: {
3283
+ id: {
3097
3284
  type: "string",
3098
3285
  format: "uuid",
3099
3286
  description: "Connection ID"
3100
3287
  }
3101
3288
  },
3102
- required: ["connection_id"]
3289
+ required: ["id"]
3103
3290
  },
3104
3291
  handler: /* @__PURE__ */ __name(async (args) => {
3105
3292
  try {
3106
- const { connection_id } = args;
3107
- const cached = await this.cache.get(`connection:${connection_id}`);
3293
+ const id = resolveId(args, "connection_id");
3294
+ const cached = await this.cache.get(`connection:${id}`);
3108
3295
  if (cached) {
3109
3296
  return {
3110
3297
  content: [
@@ -3119,8 +3306,8 @@ var ConnectionsToolHandler = class {
3119
3306
  ]
3120
3307
  };
3121
3308
  }
3122
- const connection = await this.apiClient.getConnection(connection_id);
3123
- await this.cache.set(`connection:${connection_id}`, connection, 600);
3309
+ const connection = await this.apiClient.getConnection(id);
3310
+ await this.cache.set(`connection:${id}`, connection, 600);
3124
3311
  this.metrics.recordAPICall("get_connection", "success");
3125
3312
  return {
3126
3313
  content: [
@@ -3223,7 +3410,7 @@ var ConnectionsToolHandler = class {
3223
3410
  inputSchema: {
3224
3411
  type: "object",
3225
3412
  properties: {
3226
- connection_id: {
3413
+ id: {
3227
3414
  type: "string",
3228
3415
  format: "uuid",
3229
3416
  description: "Connection ID"
@@ -3236,13 +3423,14 @@ var ConnectionsToolHandler = class {
3236
3423
  }
3237
3424
  }
3238
3425
  },
3239
- required: ["connection_id", "updates"]
3426
+ required: ["id", "updates"]
3240
3427
  },
3241
3428
  handler: /* @__PURE__ */ __name(async (args) => {
3242
3429
  try {
3243
- const { connection_id, updates } = args;
3244
- await this.apiClient.updateConnection(connection_id, updates);
3245
- await this.cache.delete(`connection:${connection_id}`);
3430
+ const id = resolveId(args, "connection_id");
3431
+ const { updates } = args;
3432
+ await this.apiClient.updateConnection(id, updates);
3433
+ await this.cache.delete(`connection:${id}`);
3246
3434
  this.metrics.recordAPICall("update_connection", "success");
3247
3435
  return {
3248
3436
  content: [
@@ -3251,7 +3439,7 @@ var ConnectionsToolHandler = class {
3251
3439
  text: JSON.stringify({
3252
3440
  success: true,
3253
3441
  message: "Connection updated successfully",
3254
- connection_id
3442
+ connection_id: id
3255
3443
  }, null, 2)
3256
3444
  }
3257
3445
  ]
@@ -3282,7 +3470,7 @@ var ConnectionsToolHandler = class {
3282
3470
  inputSchema: {
3283
3471
  type: "object",
3284
3472
  properties: {
3285
- connection_id: {
3473
+ id: {
3286
3474
  type: "string",
3287
3475
  format: "uuid",
3288
3476
  description: "Connection ID to delete"
@@ -3293,11 +3481,12 @@ var ConnectionsToolHandler = class {
3293
3481
  const: true
3294
3482
  }
3295
3483
  },
3296
- required: ["connection_id", "confirm"]
3484
+ required: ["id", "confirm"]
3297
3485
  },
3298
3486
  handler: /* @__PURE__ */ __name(async (args) => {
3299
3487
  try {
3300
- const { connection_id, confirm } = args;
3488
+ const id = resolveId(args, "connection_id");
3489
+ const { confirm } = args;
3301
3490
  if (!confirm) {
3302
3491
  return {
3303
3492
  content: [
@@ -3312,8 +3501,8 @@ var ConnectionsToolHandler = class {
3312
3501
  isError: true
3313
3502
  };
3314
3503
  }
3315
- await this.apiClient.deleteConnection(connection_id);
3316
- await this.cache.delete(`connection:${connection_id}`);
3504
+ await this.apiClient.deleteConnection(id);
3505
+ await this.cache.delete(`connection:${id}`);
3317
3506
  this.metrics.recordAPICall("delete_connection", "success");
3318
3507
  return {
3319
3508
  content: [
@@ -3322,7 +3511,7 @@ var ConnectionsToolHandler = class {
3322
3511
  text: JSON.stringify({
3323
3512
  success: true,
3324
3513
  message: "Connection deleted successfully",
3325
- connection_id
3514
+ connection_id: id
3326
3515
  }, null, 2)
3327
3516
  }
3328
3517
  ]
@@ -3592,7 +3781,7 @@ var CategoryPagesToolHandler = class {
3592
3781
  country: { type: "string", enum: [...COUNTRY_ENUM2], description: "Target country for localization" },
3593
3782
  project_id: { type: "string", format: "uuid", description: "Project UUID" },
3594
3783
  persona_id: { type: "string", format: "uuid", description: "Persona UUID" },
3595
- 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 },
3596
3785
  use_faq: { type: "boolean", description: "Generate FAQ section", default: false },
3597
3786
  use_toc: { type: "boolean", description: "Generate table of contents", default: false },
3598
3787
  use_image: { type: "boolean", description: "Generate featured image", default: false },
@@ -3605,7 +3794,7 @@ var CategoryPagesToolHandler = class {
3605
3794
  publishwordpress_date: { type: "string", description: "Publication date (ISO 8601 or WordPress format)" },
3606
3795
  publishwordpress_status: { type: "string", enum: ["draft", "publish", "future"], description: "WordPress post status" },
3607
3796
  publishwordpress_category: { type: "number", description: "WordPress category ID" },
3608
- 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." },
3609
3798
  publishwordpress_connection: { type: "string", format: "uuid", description: "WordPress connection UUID" }
3610
3799
  },
3611
3800
  required: ["name", "subject"]
@@ -3613,9 +3802,21 @@ var CategoryPagesToolHandler = class {
3613
3802
  handler: /* @__PURE__ */ __name(async (args) => {
3614
3803
  try {
3615
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
+ }
3616
3818
  const input = this.buildApiInput(validated);
3617
3819
  const categoryPage = await this.apiClient.createCategoryPage(input);
3618
- await this.cache.set(`category_page:${categoryPage.id}`, categoryPage, 300);
3619
3820
  this.metrics.recordAPICall("create_category_page", "success");
3620
3821
  const displayName = categoryPage.name || validated.name || args.name || "Unnamed";
3621
3822
  return {
@@ -3636,7 +3837,7 @@ var CategoryPagesToolHandler = class {
3636
3837
  inputSchema: { type: "object", properties: { id: { type: "string", format: "uuid", description: "ID of the category page" } }, required: ["id"] },
3637
3838
  handler: /* @__PURE__ */ __name(async (args) => {
3638
3839
  try {
3639
- const { id } = args;
3840
+ const id = resolveId(args);
3640
3841
  const cached = await this.cache.get(`category_page:${id}`);
3641
3842
  if (cached) {
3642
3843
  return { content: [{ type: "text", text: JSON.stringify({ success: true, category_page: cached, from_cache: true }, null, 2) }] };
@@ -3696,7 +3897,8 @@ var CategoryPagesToolHandler = class {
3696
3897
  },
3697
3898
  handler: /* @__PURE__ */ __name(async (args) => {
3698
3899
  try {
3699
- const { id, updates } = args;
3900
+ const id = resolveId(args);
3901
+ const { updates } = args;
3700
3902
  await this.apiClient.updateCategoryPage(id, updates);
3701
3903
  await this.cache.delete(`category_page:${id}`);
3702
3904
  this.metrics.recordAPICall("update_category_page", "success");
@@ -3724,7 +3926,8 @@ var CategoryPagesToolHandler = class {
3724
3926
  },
3725
3927
  handler: /* @__PURE__ */ __name(async (args) => {
3726
3928
  try {
3727
- const { id, wait_for_completion = true, max_wait_time = 300 } = args;
3929
+ const id = resolveId(args);
3930
+ const { wait_for_completion = true, max_wait_time = 300 } = args;
3728
3931
  await this.apiClient.runCategoryPageGeneration(id);
3729
3932
  if (!wait_for_completion) {
3730
3933
  return { content: [{ type: "text", text: JSON.stringify({ success: true, message: "Category page generation started", category_page_id: id }, null, 2) }] };
@@ -3760,7 +3963,7 @@ var CategoryPagesToolHandler = class {
3760
3963
  inputSchema: { type: "object", properties: { id: { type: "string", format: "uuid", description: "ID of the category page" } }, required: ["id"] },
3761
3964
  handler: /* @__PURE__ */ __name(async (args) => {
3762
3965
  try {
3763
- const { id } = args;
3966
+ const id = resolveId(args);
3764
3967
  const cacheKey = `category_page:output:${id}`;
3765
3968
  const cached = await this.cache.get(cacheKey);
3766
3969
  const output = cached || await this.apiClient.getCategoryPageOutput(id);
@@ -3781,10 +3984,19 @@ var CategoryPagesToolHandler = class {
3781
3984
  return {
3782
3985
  name: "estimate_category_page_cost",
3783
3986
  description: "Estimate the cost of generating a category page",
3784
- inputSchema: { type: "object", properties: { data: { type: "object", description: "Category page configuration for cost estimation" } }, required: ["data"] },
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
+ },
3785
3996
  handler: /* @__PURE__ */ __name(async (args) => {
3786
3997
  try {
3787
- const cost = await this.apiClient.calculateCategoryPageCost(args);
3998
+ const costInput = args.data || args;
3999
+ const cost = await this.apiClient.calculateCategoryPageCost(costInput);
3788
4000
  this.metrics.recordAPICall("estimate_category_page_cost", "success");
3789
4001
  return { content: [{ type: "text", text: JSON.stringify({ success: true, cost_estimate: cost }, null, 2) }] };
3790
4002
  } catch (error) {
@@ -3802,7 +4014,7 @@ var CategoryPagesToolHandler = class {
3802
4014
  inputSchema: { type: "object", properties: { items: { type: "array", items: { type: "object" }, description: "Array of category page configurations" } }, required: ["items"] },
3803
4015
  handler: /* @__PURE__ */ __name(async (args) => {
3804
4016
  try {
3805
- const { items } = args;
4017
+ const items = resolveArray(args, "items");
3806
4018
  const result2 = await this.apiClient.createBulkCategoryPages(items);
3807
4019
  this.metrics.recordAPICall("bulk_create_category_pages", "success");
3808
4020
  return { content: [{ type: "text", text: JSON.stringify({ success: true, message: `Bulk created ${items.length} category pages`, result: result2 }, null, 2) }] };
@@ -3906,7 +4118,7 @@ var ProductPagesToolHandler = class {
3906
4118
  country: { type: "string", enum: [...COUNTRY_ENUM3], description: "Target country for localization" },
3907
4119
  project_id: { type: "string", format: "uuid", description: "Project UUID" },
3908
4120
  persona_id: { type: "string", format: "uuid", description: "Persona UUID" },
3909
- 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 },
3910
4122
  use_faq: { type: "boolean", description: "Generate FAQ section", default: false },
3911
4123
  use_toc: { type: "boolean", description: "Generate table of contents", default: false },
3912
4124
  use_image: { type: "boolean", description: "Generate featured image", default: false },
@@ -3919,7 +4131,7 @@ var ProductPagesToolHandler = class {
3919
4131
  publishwordpress_date: { type: "string", description: "Publication date (ISO 8601 or WordPress format)" },
3920
4132
  publishwordpress_status: { type: "string", enum: ["draft", "publish", "future"], description: "WordPress post status" },
3921
4133
  publishwordpress_category: { type: "number", description: "WordPress category ID" },
3922
- 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." },
3923
4135
  publishwordpress_connection: { type: "string", format: "uuid", description: "WordPress connection UUID" }
3924
4136
  },
3925
4137
  required: ["name", "subject"]
@@ -3927,9 +4139,21 @@ var ProductPagesToolHandler = class {
3927
4139
  handler: /* @__PURE__ */ __name(async (args) => {
3928
4140
  try {
3929
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
+ }
3930
4155
  const input = this.buildApiInput(validated);
3931
4156
  const productPage = await this.apiClient.createProductPage(input);
3932
- await this.cache.set(`product_page:${productPage.id}`, productPage, 300);
3933
4157
  this.metrics.recordAPICall("create_product_page", "success");
3934
4158
  const displayName = productPage.name || validated.name || args.name || "Unnamed";
3935
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) }] };
@@ -3948,7 +4172,7 @@ var ProductPagesToolHandler = class {
3948
4172
  inputSchema: { type: "object", properties: { id: { type: "string", format: "uuid", description: "ID of the product page" } }, required: ["id"] },
3949
4173
  handler: /* @__PURE__ */ __name(async (args) => {
3950
4174
  try {
3951
- const { id } = args;
4175
+ const id = resolveId(args);
3952
4176
  const cached = await this.cache.get(`product_page:${id}`);
3953
4177
  if (cached) {
3954
4178
  return { content: [{ type: "text", text: JSON.stringify({ success: true, product_page: cached, from_cache: true }, null, 2) }] };
@@ -3999,7 +4223,8 @@ var ProductPagesToolHandler = class {
3999
4223
  inputSchema: { type: "object", properties: { id: { type: "string", format: "uuid", description: "ID of the product page to update" }, updates: { type: "object", description: "Fields to update" } }, required: ["id", "updates"] },
4000
4224
  handler: /* @__PURE__ */ __name(async (args) => {
4001
4225
  try {
4002
- const { id, updates } = args;
4226
+ const id = resolveId(args);
4227
+ const { updates } = args;
4003
4228
  await this.apiClient.updateProductPage(id, updates);
4004
4229
  await this.cache.delete(`product_page:${id}`);
4005
4230
  this.metrics.recordAPICall("update_product_page", "success");
@@ -4019,7 +4244,8 @@ var ProductPagesToolHandler = class {
4019
4244
  inputSchema: { type: "object", properties: { id: { type: "string", format: "uuid" }, wait_for_completion: { type: "boolean", default: true }, max_wait_time: { type: "number", default: 300, maximum: 600 } }, required: ["id"] },
4020
4245
  handler: /* @__PURE__ */ __name(async (args) => {
4021
4246
  try {
4022
- const { id, wait_for_completion = true, max_wait_time = 300 } = args;
4247
+ const id = resolveId(args);
4248
+ const { wait_for_completion = true, max_wait_time = 300 } = args;
4023
4249
  await this.apiClient.runProductPageGeneration(id);
4024
4250
  if (!wait_for_completion) {
4025
4251
  return { content: [{ type: "text", text: JSON.stringify({ success: true, message: "Product page generation started", product_page_id: id }, null, 2) }] };
@@ -4055,7 +4281,7 @@ var ProductPagesToolHandler = class {
4055
4281
  inputSchema: { type: "object", properties: { id: { type: "string", format: "uuid" } }, required: ["id"] },
4056
4282
  handler: /* @__PURE__ */ __name(async (args) => {
4057
4283
  try {
4058
- const { id } = args;
4284
+ const id = resolveId(args);
4059
4285
  const cacheKey = `product_page:output:${id}`;
4060
4286
  const cached = await this.cache.get(cacheKey);
4061
4287
  const output = cached || await this.apiClient.getProductPageOutput(id);
@@ -4076,10 +4302,19 @@ var ProductPagesToolHandler = class {
4076
4302
  return {
4077
4303
  name: "estimate_product_page_cost",
4078
4304
  description: "Estimate the cost of generating a product page",
4079
- inputSchema: { type: "object", properties: { data: { type: "object", description: "Product page configuration for cost estimation" } }, required: ["data"] },
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
+ },
4080
4314
  handler: /* @__PURE__ */ __name(async (args) => {
4081
4315
  try {
4082
- const cost = await this.apiClient.calculateProductPageCost(args);
4316
+ const costInput = args.data || args;
4317
+ const cost = await this.apiClient.calculateProductPageCost(costInput);
4083
4318
  this.metrics.recordAPICall("estimate_product_page_cost", "success");
4084
4319
  return { content: [{ type: "text", text: JSON.stringify({ success: true, cost_estimate: cost }, null, 2) }] };
4085
4320
  } catch (error) {
@@ -4097,7 +4332,7 @@ var ProductPagesToolHandler = class {
4097
4332
  inputSchema: { type: "object", properties: { items: { type: "array", items: { type: "object" }, description: "Array of product page configurations" } }, required: ["items"] },
4098
4333
  handler: /* @__PURE__ */ __name(async (args) => {
4099
4334
  try {
4100
- const { items } = args;
4335
+ const items = resolveArray(args, "items");
4101
4336
  const result2 = await this.apiClient.createBulkProductPages(items);
4102
4337
  this.metrics.recordAPICall("bulk_create_product_pages", "success");
4103
4338
  return { content: [{ type: "text", text: JSON.stringify({ success: true, message: `Bulk created ${items.length} product pages`, result: result2 }, null, 2) }] };
@@ -4218,7 +4453,7 @@ var DiscoverToolHandler = class {
4218
4453
  keywords_secondary: { type: "string", description: "Secondary keywords" },
4219
4454
  project_id: { type: "string", format: "uuid", description: "Project UUID" },
4220
4455
  persona_id: { type: "string", format: "uuid", description: "Persona UUID" },
4221
- 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 },
4222
4457
  lang: { type: "string", enum: ["fr", "en"], description: "Language code" },
4223
4458
  country: { type: "string", enum: ["fr", "be", "ch", "ca", "us", "gb"], description: "Country code" },
4224
4459
  length: { description: 'Number (max 2000) or "auto"' },
@@ -4260,7 +4495,7 @@ var DiscoverToolHandler = class {
4260
4495
  publishwordpress_date: { type: "string", description: "WordPress publish date" },
4261
4496
  publishwordpress_status: { type: "string", enum: ["draft", "publish", "future"], description: "WordPress post status" },
4262
4497
  publishwordpress_category: { type: "number", description: "WordPress category ID" },
4263
- 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." },
4264
4499
  publishwordpress_connection: { type: "string", description: "WordPress connection ID" },
4265
4500
  // Additional features
4266
4501
  use_infotable: { type: "boolean", description: "Add info table" },
@@ -4285,6 +4520,19 @@ var DiscoverToolHandler = class {
4285
4520
  apply_project_brief_config_raw_type: typeof args.apply_project_brief_config
4286
4521
  });
4287
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
+ }
4288
4536
  logger.info("discover_content VALIDATED (after boolField transform)", {
4289
4537
  apply_project_brief_config: validated.apply_project_brief_config,
4290
4538
  apply_project_brief_config_type: typeof validated.apply_project_brief_config,
@@ -4304,7 +4552,6 @@ var DiscoverToolHandler = class {
4304
4552
  apply_project_brief_config_value: cleanedInput.apply_project_brief_config
4305
4553
  });
4306
4554
  const discovery = await this.apiClient.discoverArticles(cleanedInput);
4307
- await this.cache.set(`discover:${discovery.id}`, discovery, 300);
4308
4555
  this.metrics.recordAPICall("discover_content", "success");
4309
4556
  return {
4310
4557
  content: [{
@@ -4335,7 +4582,7 @@ var DiscoverToolHandler = class {
4335
4582
  inputSchema: { type: "object", properties: { id: { type: "string", format: "uuid" } }, required: ["id"] },
4336
4583
  handler: /* @__PURE__ */ __name(async (args) => {
4337
4584
  try {
4338
- const { id } = args;
4585
+ const id = resolveId(args);
4339
4586
  const cached = await this.cache.get(`discover:${id}`);
4340
4587
  if (cached) {
4341
4588
  return { content: [{ type: "text", text: JSON.stringify({ success: true, discovery: cached, from_cache: true }, null, 2) }] };
@@ -4386,7 +4633,8 @@ var DiscoverToolHandler = class {
4386
4633
  inputSchema: { type: "object", properties: { id: { type: "string", format: "uuid" }, updates: { type: "object", description: "Fields to update" } }, required: ["id", "updates"] },
4387
4634
  handler: /* @__PURE__ */ __name(async (args) => {
4388
4635
  try {
4389
- const { id, updates } = args;
4636
+ const id = resolveId(args);
4637
+ const { updates } = args;
4390
4638
  await this.apiClient.updateDiscoverArticle(id, updates);
4391
4639
  await this.cache.delete(`discover:${id}`);
4392
4640
  this.metrics.recordAPICall("update_discover_article", "success");
@@ -4406,7 +4654,7 @@ var DiscoverToolHandler = class {
4406
4654
  inputSchema: { type: "object", properties: { id: { type: "string", format: "uuid" } }, required: ["id"] },
4407
4655
  handler: /* @__PURE__ */ __name(async (args) => {
4408
4656
  try {
4409
- const { id } = args;
4657
+ const id = resolveId(args);
4410
4658
  await this.apiClient.runDiscovery(id);
4411
4659
  await this.cache.delete(`discover:${id}`);
4412
4660
  this.metrics.recordAPICall("run_discovery", "success");
@@ -4426,7 +4674,7 @@ var DiscoverToolHandler = class {
4426
4674
  inputSchema: { type: "object", properties: { id: { type: "string", format: "uuid" } }, required: ["id"] },
4427
4675
  handler: /* @__PURE__ */ __name(async (args) => {
4428
4676
  try {
4429
- const { id } = args;
4677
+ const id = resolveId(args);
4430
4678
  const cacheKey = `discover:output:${id}`;
4431
4679
  const cached = await this.cache.get(cacheKey);
4432
4680
  const output = cached || await this.apiClient.getDiscoverArticleOutput(id);
@@ -4447,10 +4695,19 @@ var DiscoverToolHandler = class {
4447
4695
  return {
4448
4696
  name: "estimate_discover_cost",
4449
4697
  description: "Estimate the cost of a discover article",
4450
- inputSchema: { type: "object", properties: { data: { type: "object", description: "Discovery configuration for cost estimation" } }, required: ["data"] },
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
+ },
4451
4707
  handler: /* @__PURE__ */ __name(async (args) => {
4452
4708
  try {
4453
- const cost = await this.apiClient.calculateDiscoverCost(args);
4709
+ const costInput = args.data || args;
4710
+ const cost = await this.apiClient.calculateDiscoverCost(costInput);
4454
4711
  this.metrics.recordAPICall("estimate_discover_cost", "success");
4455
4712
  return { content: [{ type: "text", text: JSON.stringify({ success: true, cost_estimate: cost }, null, 2) }] };
4456
4713
  } catch (error) {
@@ -4468,7 +4725,7 @@ var DiscoverToolHandler = class {
4468
4725
  inputSchema: { type: "object", properties: { items: { type: "array", items: { type: "object" }, description: "Array of discover article configurations" } }, required: ["items"] },
4469
4726
  handler: /* @__PURE__ */ __name(async (args) => {
4470
4727
  try {
4471
- const { items } = args;
4728
+ const items = resolveArray(args, "items");
4472
4729
  const result2 = await this.apiClient.createBulkDiscoverArticles(items);
4473
4730
  this.metrics.recordAPICall("bulk_create_discover_articles", "success");
4474
4731
  return { content: [{ type: "text", text: JSON.stringify({ success: true, message: `Bulk created ${items.length} discover articles`, result: result2 }, null, 2) }] };
@@ -4561,8 +4818,10 @@ var RSSToolHandler = class {
4561
4818
  } catch (error) {
4562
4819
  logger.error("Failed to create feed", { error: error.message });
4563
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.";
4564
4823
  return {
4565
- content: [{ type: "text", text: JSON.stringify({ error: true, message: error.message || "Failed to create feed", details: error.issues || void 0 }, null, 2) }],
4824
+ content: [{ type: "text", text: JSON.stringify({ error: true, message: errorMessage, guidance, details: error.issues || void 0 }, null, 2) }],
4566
4825
  isError: true
4567
4826
  };
4568
4827
  }
@@ -4582,7 +4841,7 @@ var RSSToolHandler = class {
4582
4841
  },
4583
4842
  handler: /* @__PURE__ */ __name(async (args) => {
4584
4843
  try {
4585
- const { id } = args;
4844
+ const id = resolveId(args);
4586
4845
  const cached = await this.cache.get(`feed:${id}`);
4587
4846
  if (cached) {
4588
4847
  return { content: [{ type: "text", text: JSON.stringify({ success: true, feed: cached, from_cache: true }, null, 2) }] };
@@ -4672,7 +4931,8 @@ var RSSToolHandler = class {
4672
4931
  },
4673
4932
  handler: /* @__PURE__ */ __name(async (args) => {
4674
4933
  try {
4675
- const { id, updates } = args;
4934
+ const id = resolveId(args);
4935
+ const { updates } = args;
4676
4936
  await this.apiClient.updateFeed(id, updates);
4677
4937
  await this.cache.delete(`feed:${id}`);
4678
4938
  this.metrics.recordAPICall("update_feed", "success");
@@ -4698,7 +4958,7 @@ var RSSToolHandler = class {
4698
4958
  },
4699
4959
  handler: /* @__PURE__ */ __name(async (args) => {
4700
4960
  try {
4701
- const { id } = args;
4961
+ const id = resolveId(args);
4702
4962
  await this.apiClient.deleteFeed(id);
4703
4963
  await this.cache.delete(`feed:${id}`);
4704
4964
  this.metrics.recordAPICall("delete_feed", "success");
@@ -4820,7 +5080,7 @@ var JobsToolHandler = class {
4820
5080
  },
4821
5081
  handler: /* @__PURE__ */ __name(async (args) => {
4822
5082
  try {
4823
- const { id } = args;
5083
+ const id = resolveId(args);
4824
5084
  const job = await this.apiClient.getJob(id);
4825
5085
  this.metrics.recordAPICall("get_job", "success");
4826
5086
  return {