@productmaker/mcp 3.4.1 → 3.4.2

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/http.js CHANGED
@@ -3692,6 +3692,32 @@ var StatusResponse = z24.object({
3692
3692
  requiresAction: z24.boolean().optional(),
3693
3693
  /** True when the task needs the user's attention rather than passive progress. */
3694
3694
  needsReview: z24.boolean().optional(),
3695
+ /**
3696
+ * THE answer to "does this task still owe the seller a question — now OR later
3697
+ * in this run?". The chat leaves for /tasks/:id only on an explicit `false`,
3698
+ * and /tasks/:id bounces her back on `true`. ONE field drives BOTH directions
3699
+ * on purpose: deciding them on two different facts is what looped
3700
+ * /tasks/:id ↔ wizard before (see apps/web/lib/task-routing.ts).
3701
+ *
3702
+ * STRICTLY WIDER THAN `needsReview`, and the difference is the whole point:
3703
+ * · `needsReview` answers "is a gate open RIGHT NOW", and it under-reports —
3704
+ * `buildPendingUserAction` only serves the reference-grouping question when
3705
+ * it is RENDERABLE, so an unconfirmed target reports `false` while
3706
+ * `angles.worker` will still pause at the END of the angles stage.
3707
+ * · this field adds the gates that are GUARANTEED to open: both pause flags,
3708
+ * plus that same worker prediction, through the one shared helper.
3709
+ *
3710
+ * Absent (undefined) means "an older API that cannot answer" — the client must
3711
+ * treat that as `true` and stay put. Uncertainty resolves to staying: a false
3712
+ * positive costs her a wait, a false negative strands her on a screen that
3713
+ * cannot render the gate (prod bd4d0bb1 / 52dc15a7, both refunded and
3714
+ * undelivered).
3715
+ *
3716
+ * ALWAYS false on a terminal task. `pauseForAngleReview` SURVIVES on completed
3717
+ * tasks, so without that guard a finished landing would report `true` forever
3718
+ * and get bounced into a chat with nothing left to ask.
3719
+ */
3720
+ willAskAgain: z24.boolean().optional(),
3695
3721
  /** True when an open gate exists that somebody can actually ANSWER. A strictly
3696
3722
  * narrower fact than `needsReview` — see the identical field on `TaskSummary`
3697
3723
  * below for why conflating the two produced a call to action that led nowhere. */
@@ -3826,6 +3852,9 @@ var CostEstimationType = z25.enum([
3826
3852
  "landing-regenerate",
3827
3853
  "landing-creative",
3828
3854
  "campaign-copy",
3855
+ "brand-extract",
3856
+ "persona-suggest",
3857
+ "chat-parse",
3829
3858
  "service-creative",
3830
3859
  "actor-grid"
3831
3860
  ]);
@@ -3991,11 +4020,14 @@ var LandingCreativeEstimationOptions = z25.object({
3991
4020
  landingStrategy: LandingStrategySchema.optional()
3992
4021
  });
3993
4022
  var CampaignCopyEstimationOptions = z25.object({
3994
- /** Number of creatives to generate copy for (1-4) */
3995
- nCreatives: z25.number().int().min(1).max(4),
3996
- /** Number of image creatives that will use vision analysis (0-4) */
3997
- nImages: z25.number().int().min(0).max(4).default(0)
3998
- });
4023
+ /** Number of creatives in the one copy-completion request (1-10). */
4024
+ nCreatives: z25.number().int().min(1).max(10),
4025
+ /** Number of image creatives that can each use one vision analysis (0-10). */
4026
+ nImages: z25.number().int().min(0).max(10).default(0)
4027
+ });
4028
+ var BrandExtractEstimationOptions = z25.object({}).strict();
4029
+ var PersonaSuggestEstimationOptions = z25.object({}).strict();
4030
+ var ChatParseEstimationOptions = z25.object({}).strict();
3999
4031
  var ServiceCreativeEstimationOptions = z25.object({
4000
4032
  mediaAssetCount: z25.number().int().min(0).max(8).optional(),
4001
4033
  uploadedVideoDurationSeconds: z25.number().min(0).max(240).optional()
@@ -4034,6 +4066,18 @@ var CostEstimationRequest = z25.discriminatedUnion("type", [
4034
4066
  type: z25.literal("campaign-copy"),
4035
4067
  options: CampaignCopyEstimationOptions
4036
4068
  }),
4069
+ z25.object({
4070
+ type: z25.literal("brand-extract"),
4071
+ options: BrandExtractEstimationOptions
4072
+ }),
4073
+ z25.object({
4074
+ type: z25.literal("persona-suggest"),
4075
+ options: PersonaSuggestEstimationOptions
4076
+ }),
4077
+ z25.object({
4078
+ type: z25.literal("chat-parse"),
4079
+ options: ChatParseEstimationOptions
4080
+ }),
4037
4081
  z25.object({
4038
4082
  type: z25.literal("service-creative"),
4039
4083
  options: ServiceCreativeEstimationOptions
@@ -4533,6 +4577,9 @@ var VideoMixQaJobSchema = z30.object({
4533
4577
  });
4534
4578
  var BrandExtractJobSchema = z30.object({
4535
4579
  brandId: z30.string().uuid(),
4580
+ // Generation is part of the durable paid-spend identity. Default 1 keeps
4581
+ // pre-migration BullMQ payloads parseable; their DB state fails safe.
4582
+ generation: z30.number().int().positive().default(1),
4536
4583
  url: z30.string().url().refine((value) => {
4537
4584
  const protocol = new URL(value).protocol;
4538
4585
  return protocol === "http:" || protocol === "https:";
@@ -11631,7 +11678,7 @@ var ApiClient = class {
11631
11678
  };
11632
11679
 
11633
11680
  // src/index.ts
11634
- var MCP_VERSION = "3.4.1";
11681
+ var MCP_VERSION = "3.4.2";
11635
11682
 
11636
11683
  // src/meta-upload-app.ts
11637
11684
  import { readFileSync } from "fs";
@@ -11943,6 +11990,7 @@ __name(resolveOne, "resolveOne");
11943
11990
 
11944
11991
  // src/status-poller.ts
11945
11992
  var TERMINAL = /* @__PURE__ */ new Set([
11993
+ "done",
11946
11994
  "complete",
11947
11995
  "error"
11948
11996
  ]);
@@ -12618,6 +12666,7 @@ var McpErrorCode = {
12618
12666
  REVOKED_API_KEY: "REVOKED_API_KEY",
12619
12667
  // Rate limit / quota
12620
12668
  RATE_LIMITED: "RATE_LIMITED",
12669
+ CREDIT_ADMISSION_UNAVAILABLE: "CREDIT_ADMISSION_UNAVAILABLE",
12621
12670
  // Input
12622
12671
  INVALID_INPUT: "INVALID_INPUT",
12623
12672
  INSUFFICIENT_CREDITS: "INSUFFICIENT_CREDITS",
@@ -12806,6 +12855,7 @@ var CODE_MESSAGES = {
12806
12855
  REVOKED_API_KEY: "API key revoked. Generate a new one at https://productmaker.app/account/api-keys.",
12807
12856
  // Rate
12808
12857
  RATE_LIMITED: "Too many requests. Wait a few seconds.",
12858
+ CREDIT_ADMISSION_UNAVAILABLE: "Credit admission is temporarily unavailable. Do not retry a paid action until ProductMaker can verify the balance.",
12809
12859
  INSUFFICIENT_CREDITS: "Insufficient credits for this action. Check your balance and add credits at https://productmaker.app before retrying.",
12810
12860
  TASK_QUOTA_EXCEEDED: "You reached the active-task limit. Wait for a task to finish before creating another variant.",
12811
12861
  // Generic
@@ -12900,6 +12950,7 @@ var INVALID_PARAM_CODES = /* @__PURE__ */ new Set([
12900
12950
  McpErrorCode.NO_META_AD_ACCOUNTS
12901
12951
  ]);
12902
12952
  var PASSTHROUGH_CODES = /* @__PURE__ */ new Set([
12953
+ McpErrorCode.CREDIT_ADMISSION_UNAVAILABLE,
12903
12954
  McpErrorCode.INSUFFICIENT_CREDITS,
12904
12955
  McpErrorCode.TASK_QUOTA_EXCEEDED,
12905
12956
  McpErrorCode.DROPSHIPPING_PROJECT_NOT_FOUND,
@@ -12998,6 +13049,7 @@ __name(looksLikeMeaningfulBackendMessage, "looksLikeMeaningfulBackendMessage");
12998
13049
  function resolveMessage(code, backendMessage) {
12999
13050
  const mapped = CODE_MESSAGES[code];
13000
13051
  const backend = typeof backendMessage === "string" ? backendMessage.trim() : "";
13052
+ if (code === McpErrorCode.CREDIT_ADMISSION_UNAVAILABLE && mapped) return mapped;
13001
13053
  if (mapped && backend && looksLikeMeaningfulBackendMessage(backend, mapped)) {
13002
13054
  return `${mapped} (Detail: ${backend})`;
13003
13055
  }
package/dist/stdio.js CHANGED
@@ -264,7 +264,7 @@ var ApiClient = class {
264
264
  };
265
265
 
266
266
  // src/index.ts
267
- var MCP_VERSION = "3.4.1";
267
+ var MCP_VERSION = "3.4.2";
268
268
 
269
269
  // src/meta-upload-app.ts
270
270
  import { readFileSync } from "fs";
@@ -576,6 +576,7 @@ __name(resolveOne, "resolveOne");
576
576
 
577
577
  // src/status-poller.ts
578
578
  var TERMINAL = /* @__PURE__ */ new Set([
579
+ "done",
579
580
  "complete",
580
581
  "error"
581
582
  ]);
@@ -4313,6 +4314,32 @@ var StatusResponse = z24.object({
4313
4314
  requiresAction: z24.boolean().optional(),
4314
4315
  /** True when the task needs the user's attention rather than passive progress. */
4315
4316
  needsReview: z24.boolean().optional(),
4317
+ /**
4318
+ * THE answer to "does this task still owe the seller a question — now OR later
4319
+ * in this run?". The chat leaves for /tasks/:id only on an explicit `false`,
4320
+ * and /tasks/:id bounces her back on `true`. ONE field drives BOTH directions
4321
+ * on purpose: deciding them on two different facts is what looped
4322
+ * /tasks/:id ↔ wizard before (see apps/web/lib/task-routing.ts).
4323
+ *
4324
+ * STRICTLY WIDER THAN `needsReview`, and the difference is the whole point:
4325
+ * · `needsReview` answers "is a gate open RIGHT NOW", and it under-reports —
4326
+ * `buildPendingUserAction` only serves the reference-grouping question when
4327
+ * it is RENDERABLE, so an unconfirmed target reports `false` while
4328
+ * `angles.worker` will still pause at the END of the angles stage.
4329
+ * · this field adds the gates that are GUARANTEED to open: both pause flags,
4330
+ * plus that same worker prediction, through the one shared helper.
4331
+ *
4332
+ * Absent (undefined) means "an older API that cannot answer" — the client must
4333
+ * treat that as `true` and stay put. Uncertainty resolves to staying: a false
4334
+ * positive costs her a wait, a false negative strands her on a screen that
4335
+ * cannot render the gate (prod bd4d0bb1 / 52dc15a7, both refunded and
4336
+ * undelivered).
4337
+ *
4338
+ * ALWAYS false on a terminal task. `pauseForAngleReview` SURVIVES on completed
4339
+ * tasks, so without that guard a finished landing would report `true` forever
4340
+ * and get bounced into a chat with nothing left to ask.
4341
+ */
4342
+ willAskAgain: z24.boolean().optional(),
4316
4343
  /** True when an open gate exists that somebody can actually ANSWER. A strictly
4317
4344
  * narrower fact than `needsReview` — see the identical field on `TaskSummary`
4318
4345
  * below for why conflating the two produced a call to action that led nowhere. */
@@ -4447,6 +4474,9 @@ var CostEstimationType = z25.enum([
4447
4474
  "landing-regenerate",
4448
4475
  "landing-creative",
4449
4476
  "campaign-copy",
4477
+ "brand-extract",
4478
+ "persona-suggest",
4479
+ "chat-parse",
4450
4480
  "service-creative",
4451
4481
  "actor-grid"
4452
4482
  ]);
@@ -4612,11 +4642,14 @@ var LandingCreativeEstimationOptions = z25.object({
4612
4642
  landingStrategy: LandingStrategySchema.optional()
4613
4643
  });
4614
4644
  var CampaignCopyEstimationOptions = z25.object({
4615
- /** Number of creatives to generate copy for (1-4) */
4616
- nCreatives: z25.number().int().min(1).max(4),
4617
- /** Number of image creatives that will use vision analysis (0-4) */
4618
- nImages: z25.number().int().min(0).max(4).default(0)
4619
- });
4645
+ /** Number of creatives in the one copy-completion request (1-10). */
4646
+ nCreatives: z25.number().int().min(1).max(10),
4647
+ /** Number of image creatives that can each use one vision analysis (0-10). */
4648
+ nImages: z25.number().int().min(0).max(10).default(0)
4649
+ });
4650
+ var BrandExtractEstimationOptions = z25.object({}).strict();
4651
+ var PersonaSuggestEstimationOptions = z25.object({}).strict();
4652
+ var ChatParseEstimationOptions = z25.object({}).strict();
4620
4653
  var ServiceCreativeEstimationOptions = z25.object({
4621
4654
  mediaAssetCount: z25.number().int().min(0).max(8).optional(),
4622
4655
  uploadedVideoDurationSeconds: z25.number().min(0).max(240).optional()
@@ -4655,6 +4688,18 @@ var CostEstimationRequest = z25.discriminatedUnion("type", [
4655
4688
  type: z25.literal("campaign-copy"),
4656
4689
  options: CampaignCopyEstimationOptions
4657
4690
  }),
4691
+ z25.object({
4692
+ type: z25.literal("brand-extract"),
4693
+ options: BrandExtractEstimationOptions
4694
+ }),
4695
+ z25.object({
4696
+ type: z25.literal("persona-suggest"),
4697
+ options: PersonaSuggestEstimationOptions
4698
+ }),
4699
+ z25.object({
4700
+ type: z25.literal("chat-parse"),
4701
+ options: ChatParseEstimationOptions
4702
+ }),
4658
4703
  z25.object({
4659
4704
  type: z25.literal("service-creative"),
4660
4705
  options: ServiceCreativeEstimationOptions
@@ -5154,6 +5199,9 @@ var VideoMixQaJobSchema = z30.object({
5154
5199
  });
5155
5200
  var BrandExtractJobSchema = z30.object({
5156
5201
  brandId: z30.string().uuid(),
5202
+ // Generation is part of the durable paid-spend identity. Default 1 keeps
5203
+ // pre-migration BullMQ payloads parseable; their DB state fails safe.
5204
+ generation: z30.number().int().positive().default(1),
5157
5205
  url: z30.string().url().refine((value) => {
5158
5206
  const protocol = new URL(value).protocol;
5159
5207
  return protocol === "http:" || protocol === "https:";
@@ -11367,6 +11415,7 @@ var McpErrorCode = {
11367
11415
  REVOKED_API_KEY: "REVOKED_API_KEY",
11368
11416
  // Rate limit / quota
11369
11417
  RATE_LIMITED: "RATE_LIMITED",
11418
+ CREDIT_ADMISSION_UNAVAILABLE: "CREDIT_ADMISSION_UNAVAILABLE",
11370
11419
  // Input
11371
11420
  INVALID_INPUT: "INVALID_INPUT",
11372
11421
  INSUFFICIENT_CREDITS: "INSUFFICIENT_CREDITS",
@@ -11555,6 +11604,7 @@ var CODE_MESSAGES = {
11555
11604
  REVOKED_API_KEY: "API key revoked. Generate a new one at https://productmaker.app/account/api-keys.",
11556
11605
  // Rate
11557
11606
  RATE_LIMITED: "Too many requests. Wait a few seconds.",
11607
+ CREDIT_ADMISSION_UNAVAILABLE: "Credit admission is temporarily unavailable. Do not retry a paid action until ProductMaker can verify the balance.",
11558
11608
  INSUFFICIENT_CREDITS: "Insufficient credits for this action. Check your balance and add credits at https://productmaker.app before retrying.",
11559
11609
  TASK_QUOTA_EXCEEDED: "You reached the active-task limit. Wait for a task to finish before creating another variant.",
11560
11610
  // Generic
@@ -11649,6 +11699,7 @@ var INVALID_PARAM_CODES = /* @__PURE__ */ new Set([
11649
11699
  McpErrorCode.NO_META_AD_ACCOUNTS
11650
11700
  ]);
11651
11701
  var PASSTHROUGH_CODES = /* @__PURE__ */ new Set([
11702
+ McpErrorCode.CREDIT_ADMISSION_UNAVAILABLE,
11652
11703
  McpErrorCode.INSUFFICIENT_CREDITS,
11653
11704
  McpErrorCode.TASK_QUOTA_EXCEEDED,
11654
11705
  McpErrorCode.DROPSHIPPING_PROJECT_NOT_FOUND,
@@ -11747,6 +11798,7 @@ __name(looksLikeMeaningfulBackendMessage, "looksLikeMeaningfulBackendMessage");
11747
11798
  function resolveMessage(code, backendMessage) {
11748
11799
  const mapped = CODE_MESSAGES[code];
11749
11800
  const backend = typeof backendMessage === "string" ? backendMessage.trim() : "";
11801
+ if (code === McpErrorCode.CREDIT_ADMISSION_UNAVAILABLE && mapped) return mapped;
11750
11802
  if (mapped && backend && looksLikeMeaningfulBackendMessage(backend, mapped)) {
11751
11803
  return `${mapped} (Detail: ${backend})`;
11752
11804
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@productmaker/mcp",
3
- "version": "3.4.1",
3
+ "version": "3.4.2",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "description": "Product Maker MCP server — cost products, generate dropshipping landing pages, UGC videos, and ad creatives, and publish to Shopify and Meta Ads from Claude, ChatGPT, or Gemini.",