@productmaker/mcp 8.7.0 → 8.8.0

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.
Files changed (3) hide show
  1. package/dist/http.js +223 -87
  2. package/dist/stdio.js +223 -87
  3. package/package.json +1 -1
package/dist/http.js CHANGED
@@ -1998,6 +1998,28 @@ var CreativeGeneratorJob = z14.object({
1998
1998
  referenceVersionId: z14.string().uuid().optional(),
1999
1999
  cleanImagesWaitAttempt: z14.number().int().nonnegative().optional()
2000
2000
  });
2001
+ var ImageCreativeEditStatus = z14.enum([
2002
+ "queued",
2003
+ "processing",
2004
+ "published",
2005
+ "failed"
2006
+ ]);
2007
+ var ImageCreativeRegenerateRequest = z14.object({
2008
+ variantIndex: z14.number().int().nonnegative(),
2009
+ comment: z14.string().trim().min(1).max(1e3),
2010
+ clientRequestId: z14.string().trim().min(1).max(160).optional()
2011
+ });
2012
+ var ImageCreativeEditStatusResponse = z14.object({
2013
+ ok: z14.literal(true),
2014
+ operationId: z14.string().uuid(),
2015
+ taskId: z14.string().uuid(),
2016
+ variantIndex: z14.number().int().nonnegative(),
2017
+ status: ImageCreativeEditStatus,
2018
+ assetKey: z14.string().optional(),
2019
+ assetUrl: z14.string().url().optional(),
2020
+ degraded: z14.boolean(),
2021
+ error: z14.string().nullable()
2022
+ });
2001
2023
 
2002
2024
  // ../../packages/types/src/product-label.ts
2003
2025
  import { z as z15 } from "zod";
@@ -5189,8 +5211,10 @@ var VideoGenerator = z27.object({
5189
5211
  // `result.ts`. Write-side caps (angle.ts, wizard.ts, task-creative-variants.ts)
5190
5212
  // intentionally stay at 360.
5191
5213
  buyerPersona: z27.string().min(1).max(1200).optional(),
5192
- script: z27.string().min(1),
5193
- prompt: z27.string().min(1),
5214
+ // Read contract: pending/pre-plan failed rows have no authored text yet.
5215
+ // Preserve their empty fields and outcome; successful rows are checked below.
5216
+ script: z27.string(),
5217
+ prompt: z27.string(),
5194
5218
  // Empty string allowed: Pro pipeline pauses for script review BEFORE the grid
5195
5219
  // extraction that produces the Frame A URL; imageUrl stays '' until then.
5196
5220
  imageUrl: z27.string().url().or(z27.literal("")),
@@ -5216,11 +5240,29 @@ var VideoGenerator = z27.object({
5216
5240
  execution: VideoExecutionContract.optional(),
5217
5241
  adCopy: z27.string().optional(),
5218
5242
  /** TRUE when the seller APPROVED a script for this angle that the plan path
5219
- * could not honor, so a fresh script was re-authored and rendered instead
5220
- * (PR #1470). The angle still delivered — nothing was lost and nothing is
5221
- * refundable — but the video is NOT the script they signed off on, and the
5222
- * UI must say so. Absent (never `false`) on every honest delivery. */
5243
+ * could not honor, so a fresh script was re-authored and rendered instead
5244
+ * (PR #1470). The angle still delivered — nothing was lost and nothing is
5245
+ * refundable — but the video is NOT the script they signed off on, and the
5246
+ * UI must say so. Absent (never `false`) on every honest delivery. */
5223
5247
  scriptRewritten: z27.boolean().optional()
5248
+ }).superRefine((record, ctx) => {
5249
+ if (record.status !== "success") return;
5250
+ for (const field of [
5251
+ "script",
5252
+ "prompt"
5253
+ ]) {
5254
+ if (record[field].length > 0) continue;
5255
+ ctx.addIssue({
5256
+ code: z27.ZodIssueCode.too_small,
5257
+ minimum: 1,
5258
+ type: "string",
5259
+ inclusive: true,
5260
+ path: [
5261
+ field
5262
+ ],
5263
+ message: "Successful video results require authored text"
5264
+ });
5265
+ }
5224
5266
  });
5225
5267
  var VideoScriptSceneForReview = z27.object({
5226
5268
  index: z27.number().int().nonnegative(),
@@ -6451,7 +6493,10 @@ var MVPResult = z35.object({
6451
6493
  landing: z35.object({
6452
6494
  // Allow legacy data (10 sections × 2 variants) and new data (7 sections × 2)
6453
6495
  images: z35.array(LandingImageReadable).max(MAX_LANDING_IMAGES),
6454
- manifestVersion: z35.literal("v1")
6496
+ manifestVersion: z35.literal("v1"),
6497
+ // Landing-scoped on purpose: the regeneration dialog warns that provider
6498
+ // policy can block edits for licensed-character products.
6499
+ licensedCharacter: z35.boolean().optional()
6455
6500
  }),
6456
6501
  videoGenerators: z35.array(VideoGenerator).min(1).optional(),
6457
6502
  videoStructure: VideoStructure.optional(),
@@ -9624,12 +9669,12 @@ var DEFAULT_PRICING = {
9624
9669
  ourCostCents: 0.2,
9625
9670
  userPriceCents: 0.4
9626
9671
  },
9627
- // Landing image QA (gemini-3.8-flash since 2026-08-01, 1-2 images). Anatomy/text/background cutoff.
9628
- // 1.88¢ = the post-model-swap steady state at prod averages (11,109 prompt / 928 completion
9629
- // tokens) WITH the prompt-cache breakpoint; without caching it would be ~2.36¢.
9672
+ // Landing image QA (Qwen-2.5-VL-72B since 2026-10-02, 1-2 images). Anatomy/text/background cutoff.
9673
+ // Measured on owner corpus with Qwen-2.5-VL-72B: ~1,500 prompt tokens + 150 completion ≈ $0.00135 (0.135¢ our cost).
9674
+ // 0.25¢ ourCost keeps ~80% headroom; 2x house markup.
9630
9675
  "openrouter:landing-image-qa": {
9631
- ourCostCents: 1.88,
9632
- userPriceCents: 3.76
9676
+ ourCostCents: 0.25,
9677
+ userPriceCents: 0.5
9633
9678
  },
9634
9679
  // Usage decider (role `usage-decider`: Gemini 3.8 Flash effort:'high' since
9635
9680
  // 05f543eae, ≤6 images + seller text, temperature 0 json_object, once per
@@ -9706,9 +9751,10 @@ var DEFAULT_PRICING = {
9706
9751
  ourCostCents: 0.82,
9707
9752
  userPriceCents: 1.64
9708
9753
  },
9754
+ // Creative image anatomy QA (Qwen-2.5-VL-72B since 2026-10-02). Sized identically to landing-image-qa.
9709
9755
  "openrouter:creative-image-anatomy-qa": {
9710
- ourCostCents: 1.88,
9711
- userPriceCents: 3.76
9756
+ ourCostCents: 0.25,
9757
+ userPriceCents: 0.5
9712
9758
  },
9713
9759
  // Anatomy check (Gemini 3 Flash Preview, 1 image). Standalone anatomy verification.
9714
9760
  "openrouter:anatomy-check": {
@@ -9954,24 +10000,19 @@ var DEFAULT_PRICING = {
9954
10000
  userPriceCents: 4.5
9955
10001
  },
9956
10002
  // (d) DENSE anatomy detector (the default anatomy detector since 2026-09-26;
9957
- // QA_ANATOMY_DETECTOR=frame_judge reverts): gemini-3.1-pro judges every extracted
9958
- // frame at 1 fps, 5 frames per call, each call billing its frame count — the rate is
10003
+ // QA_ANATOMY_DETECTOR=frame_judge reverts): Qwen-2.5-VL-72B judges extracted
10004
+ // frames at 1 fps, 5 frames per call, each call billing its frame count — the rate is
9959
10005
  // PER FRAME like (b) and scales with QA_DENSE_DETECTOR_MAX_FRAMES. Measured on the
9960
10006
  // owner corpus with the shipped config (reasoning=low, grouped): $1.062 / 296 frames
9961
- // ≈ 0.36c/frame; 0.5c keeps ~40% headroom. The old 3.0c fallback was the 2026-09-22
9962
- // one-still-per-call spike at default reasoning (~1.95c/frame) and would have quoted
9963
- // QA ~10x its cost. Re-derive from 30d BillingEntry once live.
10007
+ // ≈ 0.36c/frame; 0.5c keeps ~40% headroom. Preserved to protect the 30d video credit gate
10008
+ // ceiling until 30d of live Qwen volume is recorded. Re-derive from 30d BillingEntry once live.
9964
10009
  "openrouter:video-qa-anatomy-dense-detector": {
9965
10010
  ourCostCents: 0.5,
9966
10011
  userPriceCents: 1
9967
10012
  },
9968
- // (e) Dense-mode tracing confirmation: the SAME confirmer call as (c) but routed
9969
- // to gemini-3.1-pro — flash measured 3/11 recall confirming dense stills, so
9970
- // dense findings never confirm on the gate model. PER CALL.
9971
- // Spike measured $2.22/80 ≈ 2.8c/call; the 2026-09-26 A/B measured 2.6c/flag.
9972
- // 3.0c keeps it above both. (The former 5.0c/10.0c, times the old 4-confirmation cap,
9973
- // inflated the credit gate's `max` by up to ~12,600 credits on a 30 s multi-scene.)
9974
- // Re-derive from 30d BillingEntry once live.
10013
+ // (e) Dense-mode tracing confirmation: Qwen-2.5-VL-72B evaluates 3 frames (t-1, t, t+1)
10014
+ // per flagged finding. Preserved to protect the 30d video credit gate ceiling
10015
+ // until 30d of live Qwen volume is recorded. Re-derive from 30d BillingEntry once live.
9975
10016
  "openrouter:video-qa-anatomy-dense-confirm": {
9976
10017
  ourCostCents: 3,
9977
10018
  userPriceCents: 6
@@ -10946,71 +10987,106 @@ var MixAxes = z51.object({
10946
10987
  person: z51.boolean(),
10947
10988
  setting: z51.boolean()
10948
10989
  });
10949
- var MixReferences = z51.object({
10950
- product: z51.array(PublicHttpsUrl).max(3, "at most 3 product references"),
10951
- person: z51.array(PublicHttpsUrl).max(3, "at most 3 person references"),
10952
- setting: z51.array(PublicHttpsUrl).max(3, "at most 3 setting references")
10953
- });
10990
+ function createMixReferences(url) {
10991
+ return z51.object({
10992
+ product: z51.array(url).max(3, "at most 3 product references"),
10993
+ person: z51.array(url).max(3, "at most 3 person references"),
10994
+ setting: z51.array(url).max(3, "at most 3 setting references")
10995
+ });
10996
+ }
10997
+ __name(createMixReferences, "createMixReferences");
10998
+ var MixReferences = createMixReferences(PublicHttpsUrl);
10999
+ var MAX_VIDEO_MIX_REFERENCE_IMAGES = 5;
11000
+ function countGeneratedVideoMixReferences(axes, references) {
11001
+ return Number(axes.person && references.person.length === 0) + Number(axes.setting && references.setting.length === 0);
11002
+ }
11003
+ __name(countGeneratedVideoMixReferences, "countGeneratedVideoMixReferences");
11004
+ function countVideoMixReferenceImages(axes, references) {
11005
+ return (axes.product ? references.product.length : 0) + (axes.person ? references.person.length : 0) + (axes.setting ? references.setting.length : 0) + countGeneratedVideoMixReferences(axes, references);
11006
+ }
11007
+ __name(countVideoMixReferenceImages, "countVideoMixReferenceImages");
10954
11008
  var MixImageEdit = z51.object({
10955
11009
  instruction: z51.string().min(1).max(600),
10956
11010
  imageUrls: z51.array(MixImageUrl).min(1).max(3)
10957
11011
  });
10958
- var MixRequest = z51.object({
10959
- mediaType: z51.enum(MEDIA_TYPES),
10960
- originalUrl: z51.union([
10961
- PublicHttpsUrl,
10962
- InternalAssetPath
10963
- ]),
10964
- axes: MixAxes,
10965
- references: MixReferences,
10966
- personText: z51.string().max(500).optional(),
10967
- settingText: z51.string().max(500).optional(),
10968
- /**
10969
- * Optional public URL of a user-uploaded audio file (mp3/wav). Wan Video
10970
- * Edit has no audio input and the mix never lipsyncs: the Wan output is
10971
- * muted and, when this is set, the assemble worker mux'es THIS audio
10972
- * (instead of the original video's track) into the final concatenated mp4
10973
- * (mute + overlay). No per-scene slicing, no `reference_audio_urls`.
10974
- */
10975
- audioUrl: PublicHttpsUrl.optional(),
10976
- resolution: z51.enum(RESOLUTIONS).default("720p"),
10977
- originalDurationSec: z51.number().positive().max(600).optional(),
10978
- image: MixImageEdit.optional(),
10979
- sourceTaskId: z51.string().max(64).optional(),
10980
- sourceCreativeId: z51.string().max(64).optional()
10981
- }).superRefine((req, ctx) => {
10982
- if (req.mediaType === "image") {
10983
- if (!req.image) {
11012
+ function createMixRequestSchema(allowAdditionalUrl) {
11013
+ const acceptsUrl = /* @__PURE__ */ __name((url) => isPublicHttpsUrl(url) || Boolean(allowAdditionalUrl?.(url)), "acceptsUrl");
11014
+ const acceptedUrl = z51.string().url().refine(acceptsUrl, {
11015
+ message: "must be a public HTTPS URL"
11016
+ });
11017
+ return z51.object({
11018
+ mediaType: z51.enum(MEDIA_TYPES),
11019
+ originalUrl: z51.union([
11020
+ acceptedUrl,
11021
+ InternalAssetPath
11022
+ ]),
11023
+ axes: MixAxes,
11024
+ references: createMixReferences(acceptedUrl),
11025
+ personText: z51.string().max(500).optional(),
11026
+ settingText: z51.string().max(500).optional(),
11027
+ /**
11028
+ * Optional public URL of a user-uploaded audio file (mp3/wav). Wan Video
11029
+ * Edit has no audio input and the mix never lipsyncs: the Wan output is
11030
+ * muted and, when this is set, the assemble worker mux'es THIS audio
11031
+ * (instead of the original video's track) into the final concatenated mp4
11032
+ * (mute + overlay). No per-scene slicing, no `reference_audio_urls`.
11033
+ */
11034
+ audioUrl: acceptedUrl.optional(),
11035
+ resolution: z51.enum(RESOLUTIONS).default("720p"),
11036
+ originalDurationSec: z51.number().positive().max(600).optional(),
11037
+ image: MixImageEdit.extend({
11038
+ imageUrls: z51.array(z51.union([
11039
+ acceptedUrl,
11040
+ InternalAssetPath
11041
+ ])).min(1).max(3)
11042
+ }).optional(),
11043
+ sourceTaskId: z51.string().max(64).optional(),
11044
+ sourceCreativeId: z51.string().max(64).optional()
11045
+ }).superRefine((req, ctx) => {
11046
+ if (req.mediaType === "image") {
11047
+ if (!req.image) {
11048
+ ctx.addIssue({
11049
+ code: "custom",
11050
+ message: "image mix requires an image edit (instruction + 1-3 images)"
11051
+ });
11052
+ }
11053
+ return;
11054
+ }
11055
+ if (!acceptsUrl(req.originalUrl)) {
10984
11056
  ctx.addIssue({
10985
11057
  code: "custom",
10986
- message: "image mix requires an image edit (instruction + 1-3 images)"
11058
+ path: [
11059
+ "originalUrl"
11060
+ ],
11061
+ message: "must be a public HTTPS URL"
10987
11062
  });
10988
11063
  }
10989
- return;
10990
- }
10991
- if (!isPublicHttpsUrl(req.originalUrl)) {
10992
- ctx.addIssue({
10993
- code: "custom",
10994
- path: [
10995
- "originalUrl"
10996
- ],
10997
- message: "must be a public HTTPS URL"
10998
- });
10999
- }
11000
- if (req.axes.product && req.references.product.length === 0) {
11001
- ctx.addIssue({
11002
- code: "custom",
11003
- message: "product references required when product axis active"
11004
- });
11005
- }
11006
- const anyAxis = req.axes.product || req.axes.person || req.axes.setting;
11007
- if (!anyAxis && !req.audioUrl) {
11008
- ctx.addIssue({
11009
- code: "custom",
11010
- message: "mix requires at least one axis to swap or a user audio"
11011
- });
11012
- }
11013
- });
11064
+ if (req.axes.product && req.references.product.length === 0) {
11065
+ ctx.addIssue({
11066
+ code: "custom",
11067
+ message: "product references required when product axis active"
11068
+ });
11069
+ }
11070
+ if (countVideoMixReferenceImages(req.axes, req.references) > MAX_VIDEO_MIX_REFERENCE_IMAGES) {
11071
+ ctx.addIssue({
11072
+ code: "custom",
11073
+ path: [
11074
+ "references"
11075
+ ],
11076
+ message: `video mix accepts at most ${MAX_VIDEO_MIX_REFERENCE_IMAGES} reference images, including generated axes`
11077
+ });
11078
+ }
11079
+ const anyAxis = req.axes.product || req.axes.person || req.axes.setting;
11080
+ if (!anyAxis && !req.audioUrl) {
11081
+ ctx.addIssue({
11082
+ code: "custom",
11083
+ message: "mix requires at least one axis to swap or a user audio"
11084
+ });
11085
+ }
11086
+ });
11087
+ }
11088
+ __name(createMixRequestSchema, "createMixRequestSchema");
11089
+ var MixRequest = createMixRequestSchema();
11014
11090
  var ReferenceMap = z51.object({
11015
11091
  product: z51.object({
11016
11092
  start: z51.number().int(),
@@ -11110,6 +11186,7 @@ var MixResult = z51.object({
11110
11186
  });
11111
11187
 
11112
11188
  // ../../packages/types/src/mix-cost.ts
11189
+ var IMAGE_GEN_USER_PRICE_CENTS = DEFAULT_PRICING["kie:image-generation:gpt-image-2-5-sunburst-text-to-image"].userPriceCents;
11113
11190
  var MAX_QA_RETRIES_PER_SCENE_UPPER_BOUND = 1;
11114
11191
  var MAX_BILLABLE_GENERATIONS_PER_BLOCK = 1 + MAX_QA_RETRIES_PER_SCENE_UPPER_BOUND;
11115
11192
 
@@ -11349,6 +11426,13 @@ var RegenerateLandingRoleResponse = z55.object({
11349
11426
  promptIndex: z55.number().int().nonnegative(),
11350
11427
  operationId: z55.string().min(1)
11351
11428
  });
11429
+ var LandingRegenerationFailureCode = z55.enum([
11430
+ "licensed_character_blocked",
11431
+ "provider_policy_blocked",
11432
+ "qa_rejected",
11433
+ "superseded",
11434
+ "provider_error"
11435
+ ]);
11352
11436
  var LandingRegenerationStatusResponse = z55.object({
11353
11437
  ok: z55.literal(true),
11354
11438
  operationId: z55.string().min(1),
@@ -11356,6 +11440,7 @@ var LandingRegenerationStatusResponse = z55.object({
11356
11440
  status: LandingRegenerationStatus,
11357
11441
  refunded: z55.boolean(),
11358
11442
  failureReason: z55.string().nullable(),
11443
+ failureCode: LandingRegenerationFailureCode.nullable().optional(),
11359
11444
  publishedAssetKey: z55.string().nullable(),
11360
11445
  updatedAt: z55.string().datetime()
11361
11446
  });
@@ -12313,6 +12398,23 @@ var CAPABILITY_MODEL_GUIDANCE = {
12313
12398
  "es trabajo pagado y requiere confirmaci\xF3n expl\xEDcita"
12314
12399
  ]
12315
12400
  },
12401
+ get_image_edit_status: {
12402
+ summary: "Consulta s\xF3lo el estado durable de una correcci\xF3n aceptada y su imagen entregada. No genera ni reintenta im\xE1genes; Task.done no significa que esta correcci\xF3n haya terminado.",
12403
+ useWhen: [
12404
+ "una correcci\xF3n de imagen ya devolvi\xF3 su operaci\xF3n aceptada",
12405
+ "la persona consulta el resultado de esa correcci\xF3n"
12406
+ ],
12407
+ avoidWhen: [
12408
+ "todav\xEDa no existe una operaci\xF3n aceptada"
12409
+ ],
12410
+ defaults: [
12411
+ "consulta la misma operaci\xF3n hasta su publicaci\xF3n o fallo durable",
12412
+ "un fallo al consultar no autoriza otra correcci\xF3n pagada"
12413
+ ],
12414
+ disclosures: [
12415
+ "la consulta no consume cr\xE9ditos ni inicia trabajo"
12416
+ ]
12417
+ },
12316
12418
  edit_task_draft: {
12317
12419
  summary: "Edita el draft de un angle de marketing antes de la generaci\xF3n.",
12318
12420
  useWhen: [
@@ -14268,7 +14370,7 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
14268
14370
  "task",
14269
14371
  "video"
14270
14372
  ]),
14271
- defineCapability("edit_image_creative", "ce0abba871436850bd1db0ea4bcdade9ef35420ebd83833e2d5c2dcf70378ec0", "credit_consuming", "creative", [
14373
+ defineCapability("edit_image_creative", "50eca473829328dfb63b9cbae03a9835b79c510e29528563e09b7eb3e5e9bca4", "credit_consuming", "creative", [
14272
14374
  "credit_consuming",
14273
14375
  "state_change"
14274
14376
  ], [
@@ -14278,12 +14380,27 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
14278
14380
  ]),
14279
14381
  slot("edit_instruction", true, [
14280
14382
  "instruction"
14281
- ])
14383
+ ]),
14384
+ slot("client_request", false, [
14385
+ "clientRequestId"
14386
+ ], [], "server")
14282
14387
  ], [
14283
14388
  "creative"
14284
14389
  ], [
14285
14390
  "creative"
14286
14391
  ]),
14392
+ defineCapability("get_image_edit_status", "fe59aefd433afe7e5a2d8b4a81084583750c1447c877b6bce698340326665141", "none", "read_only", [
14393
+ "read"
14394
+ ], [
14395
+ slot("creative_operation", true, [
14396
+ "taskId",
14397
+ "operationId"
14398
+ ], [], "server")
14399
+ ], [
14400
+ "creative_edit_operation"
14401
+ ], [
14402
+ "creative_edit_status"
14403
+ ], MCP_ONLY_CHANNEL_EXPOSURE),
14287
14404
  defineCapability("edit_task_draft", "1c9343bdce51aac36ec6254557c8a904037746523168527f012b4c5b6361e98e", "state_change", "creative", [
14288
14405
  "state_change"
14289
14406
  ], [
@@ -18628,7 +18745,7 @@ var ApiClient = class {
18628
18745
  };
18629
18746
 
18630
18747
  // src/index.ts
18631
- var MCP_VERSION = "8.7.0";
18748
+ var MCP_VERSION = "8.8.0";
18632
18749
 
18633
18750
  // src/meta-upload-app.ts
18634
18751
  import { readFileSync } from "fs";
@@ -22260,6 +22377,7 @@ import { z as z83 } from "zod";
22260
22377
  var generateFreeVideoGuidance = getProductMakerCapabilityModelGuidance("generate_free_video");
22261
22378
  var generateVideoCreativeGuidance = getProductMakerCapabilityModelGuidance("generate_video_creative");
22262
22379
  var generateImageCreativesGuidance = getProductMakerCapabilityModelGuidance("generate_image_creatives");
22380
+ var imageEditStatusGuidance = getProductMakerCapabilityModelGuidance("get_image_edit_status");
22263
22381
  var editImageCreativeGuidance = getProductMakerCapabilityModelGuidance("edit_image_creative");
22264
22382
  var generateLandingGuidance = getProductMakerCapabilityModelGuidance("generate_landing");
22265
22383
  var CreativeRefs = {
@@ -22481,6 +22599,7 @@ var ImageInput = z83.object({
22481
22599
  var EditImageCreativeInput = z83.object({
22482
22600
  taskId: z83.string().uuid().describe("ID de la tarea de imagen ya finalizada."),
22483
22601
  variantIndex: z83.number().int().min(0).max(10).describe("\xCDndice de la variante a corregir (0 = primera imagen)."),
22602
+ clientRequestId: z83.string().min(1).max(160).optional().describe("Identidad estable de esta correcci\xF3n; reutil\xEDzala al reconciliar una respuesta perdida, no para otra instrucci\xF3n."),
22484
22603
  instruction: z83.string().min(1).max(1e3).describe('Qu\xE9 cambiar en esa imagen. Ej. "quita el badge de env\xEDo gratis", "cambia el fondo a blanco".')
22485
22604
  });
22486
22605
  var LandingInput = z83.object({
@@ -22755,13 +22874,30 @@ function registerCreativeTools(server, api, { transport = "http" } = {}) {
22755
22874
  await requirePaidCreativeConfirmation(server, `Correcci\xF3n pagada de la imagen ${input.variantIndex + 1}.`);
22756
22875
  const r = await api.postJson(`/v1/creatives/images/${encodeURIComponent(input.taskId)}/regenerate`, {
22757
22876
  comment: input.instruction,
22758
- variantIndex: input.variantIndex
22877
+ variantIndex: input.variantIndex,
22878
+ ...input.clientRequestId ? {
22879
+ clientRequestId: input.clientRequestId
22880
+ } : {}
22759
22881
  });
22760
22882
  return asText(r);
22761
22883
  } catch (e) {
22762
22884
  throw translateError(e);
22763
22885
  }
22764
22886
  });
22887
+ server.registerTool("get_image_edit_status", {
22888
+ description: imageEditStatusGuidance.summary,
22889
+ inputSchema: {
22890
+ taskId: z83.string().uuid(),
22891
+ operationId: z83.string().uuid()
22892
+ },
22893
+ annotations: READS_INTERNAL
22894
+ }, async (input) => {
22895
+ try {
22896
+ return asText(await api.getJson(`/v1/creatives/images/${encodeURIComponent(input.taskId)}/operations/${encodeURIComponent(input.operationId)}`));
22897
+ } catch (error) {
22898
+ throw translateError(error);
22899
+ }
22900
+ });
22765
22901
  server.registerTool("generate_landing", {
22766
22902
  description: generateLandingGuidance.summary + " No expone landing editable/code mientras siga siendo admin-only. Devuelve un taskId. Esta solicitud es directa: nunca busques, reutilices ni menciones un DropshippingProject.\n\nREQUERIDOS: images (1-5 fotos), language, country y creativeSetup. Ante \u201Ccrea una landing con este producto\u201D y una foto local, llama primero `request_media_upload` y usa los assetId. Pregunta price, offer y compareAtPrice cuando aplique; no asumas country/language.\n\nCONFIGURACI\xD3N: usa guided salvo delegaci\xF3n total expl\xEDcita. Presenta UN checklist compacto \u2014no preguntas seriales\u2014 con estrategia, formato, competencia, m\xE9todos de pago, contexto, direcci\xF3n creativa y headline/subheadline exactos opcionales. Prop\xF3n defaults recomendados; null significa que el usuario deleg\xF3 esa decisi\xF3n concreta, nunca que el agente la olvid\xF3.\n\nANTES de invocar, muestra el resumen y espera confirmaci\xF3n expl\xEDcita porque inicia trabajo pagado. guided pausa para revisar el \xE1ngulo; automatic equivale al toggle web \u201CDejar que la IA decida todo\u201D y omite la review.",
22767
22903
  inputSchema: LandingInput.shape,
package/dist/stdio.js CHANGED
@@ -2020,6 +2020,28 @@ var CreativeGeneratorJob = z14.object({
2020
2020
  referenceVersionId: z14.string().uuid().optional(),
2021
2021
  cleanImagesWaitAttempt: z14.number().int().nonnegative().optional()
2022
2022
  });
2023
+ var ImageCreativeEditStatus = z14.enum([
2024
+ "queued",
2025
+ "processing",
2026
+ "published",
2027
+ "failed"
2028
+ ]);
2029
+ var ImageCreativeRegenerateRequest = z14.object({
2030
+ variantIndex: z14.number().int().nonnegative(),
2031
+ comment: z14.string().trim().min(1).max(1e3),
2032
+ clientRequestId: z14.string().trim().min(1).max(160).optional()
2033
+ });
2034
+ var ImageCreativeEditStatusResponse = z14.object({
2035
+ ok: z14.literal(true),
2036
+ operationId: z14.string().uuid(),
2037
+ taskId: z14.string().uuid(),
2038
+ variantIndex: z14.number().int().nonnegative(),
2039
+ status: ImageCreativeEditStatus,
2040
+ assetKey: z14.string().optional(),
2041
+ assetUrl: z14.string().url().optional(),
2042
+ degraded: z14.boolean(),
2043
+ error: z14.string().nullable()
2044
+ });
2023
2045
 
2024
2046
  // ../../packages/types/src/product-label.ts
2025
2047
  import { z as z15 } from "zod";
@@ -5211,8 +5233,10 @@ var VideoGenerator = z27.object({
5211
5233
  // `result.ts`. Write-side caps (angle.ts, wizard.ts, task-creative-variants.ts)
5212
5234
  // intentionally stay at 360.
5213
5235
  buyerPersona: z27.string().min(1).max(1200).optional(),
5214
- script: z27.string().min(1),
5215
- prompt: z27.string().min(1),
5236
+ // Read contract: pending/pre-plan failed rows have no authored text yet.
5237
+ // Preserve their empty fields and outcome; successful rows are checked below.
5238
+ script: z27.string(),
5239
+ prompt: z27.string(),
5216
5240
  // Empty string allowed: Pro pipeline pauses for script review BEFORE the grid
5217
5241
  // extraction that produces the Frame A URL; imageUrl stays '' until then.
5218
5242
  imageUrl: z27.string().url().or(z27.literal("")),
@@ -5238,11 +5262,29 @@ var VideoGenerator = z27.object({
5238
5262
  execution: VideoExecutionContract.optional(),
5239
5263
  adCopy: z27.string().optional(),
5240
5264
  /** TRUE when the seller APPROVED a script for this angle that the plan path
5241
- * could not honor, so a fresh script was re-authored and rendered instead
5242
- * (PR #1470). The angle still delivered — nothing was lost and nothing is
5243
- * refundable — but the video is NOT the script they signed off on, and the
5244
- * UI must say so. Absent (never `false`) on every honest delivery. */
5265
+ * could not honor, so a fresh script was re-authored and rendered instead
5266
+ * (PR #1470). The angle still delivered — nothing was lost and nothing is
5267
+ * refundable — but the video is NOT the script they signed off on, and the
5268
+ * UI must say so. Absent (never `false`) on every honest delivery. */
5245
5269
  scriptRewritten: z27.boolean().optional()
5270
+ }).superRefine((record, ctx) => {
5271
+ if (record.status !== "success") return;
5272
+ for (const field of [
5273
+ "script",
5274
+ "prompt"
5275
+ ]) {
5276
+ if (record[field].length > 0) continue;
5277
+ ctx.addIssue({
5278
+ code: z27.ZodIssueCode.too_small,
5279
+ minimum: 1,
5280
+ type: "string",
5281
+ inclusive: true,
5282
+ path: [
5283
+ field
5284
+ ],
5285
+ message: "Successful video results require authored text"
5286
+ });
5287
+ }
5246
5288
  });
5247
5289
  var VideoScriptSceneForReview = z27.object({
5248
5290
  index: z27.number().int().nonnegative(),
@@ -6473,7 +6515,10 @@ var MVPResult = z35.object({
6473
6515
  landing: z35.object({
6474
6516
  // Allow legacy data (10 sections × 2 variants) and new data (7 sections × 2)
6475
6517
  images: z35.array(LandingImageReadable).max(MAX_LANDING_IMAGES),
6476
- manifestVersion: z35.literal("v1")
6518
+ manifestVersion: z35.literal("v1"),
6519
+ // Landing-scoped on purpose: the regeneration dialog warns that provider
6520
+ // policy can block edits for licensed-character products.
6521
+ licensedCharacter: z35.boolean().optional()
6477
6522
  }),
6478
6523
  videoGenerators: z35.array(VideoGenerator).min(1).optional(),
6479
6524
  videoStructure: VideoStructure.optional(),
@@ -9646,12 +9691,12 @@ var DEFAULT_PRICING = {
9646
9691
  ourCostCents: 0.2,
9647
9692
  userPriceCents: 0.4
9648
9693
  },
9649
- // Landing image QA (gemini-3.8-flash since 2026-08-01, 1-2 images). Anatomy/text/background cutoff.
9650
- // 1.88¢ = the post-model-swap steady state at prod averages (11,109 prompt / 928 completion
9651
- // tokens) WITH the prompt-cache breakpoint; without caching it would be ~2.36¢.
9694
+ // Landing image QA (Qwen-2.5-VL-72B since 2026-10-02, 1-2 images). Anatomy/text/background cutoff.
9695
+ // Measured on owner corpus with Qwen-2.5-VL-72B: ~1,500 prompt tokens + 150 completion ≈ $0.00135 (0.135¢ our cost).
9696
+ // 0.25¢ ourCost keeps ~80% headroom; 2x house markup.
9652
9697
  "openrouter:landing-image-qa": {
9653
- ourCostCents: 1.88,
9654
- userPriceCents: 3.76
9698
+ ourCostCents: 0.25,
9699
+ userPriceCents: 0.5
9655
9700
  },
9656
9701
  // Usage decider (role `usage-decider`: Gemini 3.8 Flash effort:'high' since
9657
9702
  // 05f543eae, ≤6 images + seller text, temperature 0 json_object, once per
@@ -9728,9 +9773,10 @@ var DEFAULT_PRICING = {
9728
9773
  ourCostCents: 0.82,
9729
9774
  userPriceCents: 1.64
9730
9775
  },
9776
+ // Creative image anatomy QA (Qwen-2.5-VL-72B since 2026-10-02). Sized identically to landing-image-qa.
9731
9777
  "openrouter:creative-image-anatomy-qa": {
9732
- ourCostCents: 1.88,
9733
- userPriceCents: 3.76
9778
+ ourCostCents: 0.25,
9779
+ userPriceCents: 0.5
9734
9780
  },
9735
9781
  // Anatomy check (Gemini 3 Flash Preview, 1 image). Standalone anatomy verification.
9736
9782
  "openrouter:anatomy-check": {
@@ -9976,24 +10022,19 @@ var DEFAULT_PRICING = {
9976
10022
  userPriceCents: 4.5
9977
10023
  },
9978
10024
  // (d) DENSE anatomy detector (the default anatomy detector since 2026-09-26;
9979
- // QA_ANATOMY_DETECTOR=frame_judge reverts): gemini-3.1-pro judges every extracted
9980
- // frame at 1 fps, 5 frames per call, each call billing its frame count — the rate is
10025
+ // QA_ANATOMY_DETECTOR=frame_judge reverts): Qwen-2.5-VL-72B judges extracted
10026
+ // frames at 1 fps, 5 frames per call, each call billing its frame count — the rate is
9981
10027
  // PER FRAME like (b) and scales with QA_DENSE_DETECTOR_MAX_FRAMES. Measured on the
9982
10028
  // owner corpus with the shipped config (reasoning=low, grouped): $1.062 / 296 frames
9983
- // ≈ 0.36c/frame; 0.5c keeps ~40% headroom. The old 3.0c fallback was the 2026-09-22
9984
- // one-still-per-call spike at default reasoning (~1.95c/frame) and would have quoted
9985
- // QA ~10x its cost. Re-derive from 30d BillingEntry once live.
10029
+ // ≈ 0.36c/frame; 0.5c keeps ~40% headroom. Preserved to protect the 30d video credit gate
10030
+ // ceiling until 30d of live Qwen volume is recorded. Re-derive from 30d BillingEntry once live.
9986
10031
  "openrouter:video-qa-anatomy-dense-detector": {
9987
10032
  ourCostCents: 0.5,
9988
10033
  userPriceCents: 1
9989
10034
  },
9990
- // (e) Dense-mode tracing confirmation: the SAME confirmer call as (c) but routed
9991
- // to gemini-3.1-pro — flash measured 3/11 recall confirming dense stills, so
9992
- // dense findings never confirm on the gate model. PER CALL.
9993
- // Spike measured $2.22/80 ≈ 2.8c/call; the 2026-09-26 A/B measured 2.6c/flag.
9994
- // 3.0c keeps it above both. (The former 5.0c/10.0c, times the old 4-confirmation cap,
9995
- // inflated the credit gate's `max` by up to ~12,600 credits on a 30 s multi-scene.)
9996
- // Re-derive from 30d BillingEntry once live.
10035
+ // (e) Dense-mode tracing confirmation: Qwen-2.5-VL-72B evaluates 3 frames (t-1, t, t+1)
10036
+ // per flagged finding. Preserved to protect the 30d video credit gate ceiling
10037
+ // until 30d of live Qwen volume is recorded. Re-derive from 30d BillingEntry once live.
9997
10038
  "openrouter:video-qa-anatomy-dense-confirm": {
9998
10039
  ourCostCents: 3,
9999
10040
  userPriceCents: 6
@@ -10968,71 +11009,106 @@ var MixAxes = z51.object({
10968
11009
  person: z51.boolean(),
10969
11010
  setting: z51.boolean()
10970
11011
  });
10971
- var MixReferences = z51.object({
10972
- product: z51.array(PublicHttpsUrl).max(3, "at most 3 product references"),
10973
- person: z51.array(PublicHttpsUrl).max(3, "at most 3 person references"),
10974
- setting: z51.array(PublicHttpsUrl).max(3, "at most 3 setting references")
10975
- });
11012
+ function createMixReferences(url) {
11013
+ return z51.object({
11014
+ product: z51.array(url).max(3, "at most 3 product references"),
11015
+ person: z51.array(url).max(3, "at most 3 person references"),
11016
+ setting: z51.array(url).max(3, "at most 3 setting references")
11017
+ });
11018
+ }
11019
+ __name(createMixReferences, "createMixReferences");
11020
+ var MixReferences = createMixReferences(PublicHttpsUrl);
11021
+ var MAX_VIDEO_MIX_REFERENCE_IMAGES = 5;
11022
+ function countGeneratedVideoMixReferences(axes, references) {
11023
+ return Number(axes.person && references.person.length === 0) + Number(axes.setting && references.setting.length === 0);
11024
+ }
11025
+ __name(countGeneratedVideoMixReferences, "countGeneratedVideoMixReferences");
11026
+ function countVideoMixReferenceImages(axes, references) {
11027
+ return (axes.product ? references.product.length : 0) + (axes.person ? references.person.length : 0) + (axes.setting ? references.setting.length : 0) + countGeneratedVideoMixReferences(axes, references);
11028
+ }
11029
+ __name(countVideoMixReferenceImages, "countVideoMixReferenceImages");
10976
11030
  var MixImageEdit = z51.object({
10977
11031
  instruction: z51.string().min(1).max(600),
10978
11032
  imageUrls: z51.array(MixImageUrl).min(1).max(3)
10979
11033
  });
10980
- var MixRequest = z51.object({
10981
- mediaType: z51.enum(MEDIA_TYPES),
10982
- originalUrl: z51.union([
10983
- PublicHttpsUrl,
10984
- InternalAssetPath
10985
- ]),
10986
- axes: MixAxes,
10987
- references: MixReferences,
10988
- personText: z51.string().max(500).optional(),
10989
- settingText: z51.string().max(500).optional(),
10990
- /**
10991
- * Optional public URL of a user-uploaded audio file (mp3/wav). Wan Video
10992
- * Edit has no audio input and the mix never lipsyncs: the Wan output is
10993
- * muted and, when this is set, the assemble worker mux'es THIS audio
10994
- * (instead of the original video's track) into the final concatenated mp4
10995
- * (mute + overlay). No per-scene slicing, no `reference_audio_urls`.
10996
- */
10997
- audioUrl: PublicHttpsUrl.optional(),
10998
- resolution: z51.enum(RESOLUTIONS).default("720p"),
10999
- originalDurationSec: z51.number().positive().max(600).optional(),
11000
- image: MixImageEdit.optional(),
11001
- sourceTaskId: z51.string().max(64).optional(),
11002
- sourceCreativeId: z51.string().max(64).optional()
11003
- }).superRefine((req, ctx) => {
11004
- if (req.mediaType === "image") {
11005
- if (!req.image) {
11034
+ function createMixRequestSchema(allowAdditionalUrl) {
11035
+ const acceptsUrl = /* @__PURE__ */ __name((url) => isPublicHttpsUrl(url) || Boolean(allowAdditionalUrl?.(url)), "acceptsUrl");
11036
+ const acceptedUrl = z51.string().url().refine(acceptsUrl, {
11037
+ message: "must be a public HTTPS URL"
11038
+ });
11039
+ return z51.object({
11040
+ mediaType: z51.enum(MEDIA_TYPES),
11041
+ originalUrl: z51.union([
11042
+ acceptedUrl,
11043
+ InternalAssetPath
11044
+ ]),
11045
+ axes: MixAxes,
11046
+ references: createMixReferences(acceptedUrl),
11047
+ personText: z51.string().max(500).optional(),
11048
+ settingText: z51.string().max(500).optional(),
11049
+ /**
11050
+ * Optional public URL of a user-uploaded audio file (mp3/wav). Wan Video
11051
+ * Edit has no audio input and the mix never lipsyncs: the Wan output is
11052
+ * muted and, when this is set, the assemble worker mux'es THIS audio
11053
+ * (instead of the original video's track) into the final concatenated mp4
11054
+ * (mute + overlay). No per-scene slicing, no `reference_audio_urls`.
11055
+ */
11056
+ audioUrl: acceptedUrl.optional(),
11057
+ resolution: z51.enum(RESOLUTIONS).default("720p"),
11058
+ originalDurationSec: z51.number().positive().max(600).optional(),
11059
+ image: MixImageEdit.extend({
11060
+ imageUrls: z51.array(z51.union([
11061
+ acceptedUrl,
11062
+ InternalAssetPath
11063
+ ])).min(1).max(3)
11064
+ }).optional(),
11065
+ sourceTaskId: z51.string().max(64).optional(),
11066
+ sourceCreativeId: z51.string().max(64).optional()
11067
+ }).superRefine((req, ctx) => {
11068
+ if (req.mediaType === "image") {
11069
+ if (!req.image) {
11070
+ ctx.addIssue({
11071
+ code: "custom",
11072
+ message: "image mix requires an image edit (instruction + 1-3 images)"
11073
+ });
11074
+ }
11075
+ return;
11076
+ }
11077
+ if (!acceptsUrl(req.originalUrl)) {
11006
11078
  ctx.addIssue({
11007
11079
  code: "custom",
11008
- message: "image mix requires an image edit (instruction + 1-3 images)"
11080
+ path: [
11081
+ "originalUrl"
11082
+ ],
11083
+ message: "must be a public HTTPS URL"
11009
11084
  });
11010
11085
  }
11011
- return;
11012
- }
11013
- if (!isPublicHttpsUrl(req.originalUrl)) {
11014
- ctx.addIssue({
11015
- code: "custom",
11016
- path: [
11017
- "originalUrl"
11018
- ],
11019
- message: "must be a public HTTPS URL"
11020
- });
11021
- }
11022
- if (req.axes.product && req.references.product.length === 0) {
11023
- ctx.addIssue({
11024
- code: "custom",
11025
- message: "product references required when product axis active"
11026
- });
11027
- }
11028
- const anyAxis = req.axes.product || req.axes.person || req.axes.setting;
11029
- if (!anyAxis && !req.audioUrl) {
11030
- ctx.addIssue({
11031
- code: "custom",
11032
- message: "mix requires at least one axis to swap or a user audio"
11033
- });
11034
- }
11035
- });
11086
+ if (req.axes.product && req.references.product.length === 0) {
11087
+ ctx.addIssue({
11088
+ code: "custom",
11089
+ message: "product references required when product axis active"
11090
+ });
11091
+ }
11092
+ if (countVideoMixReferenceImages(req.axes, req.references) > MAX_VIDEO_MIX_REFERENCE_IMAGES) {
11093
+ ctx.addIssue({
11094
+ code: "custom",
11095
+ path: [
11096
+ "references"
11097
+ ],
11098
+ message: `video mix accepts at most ${MAX_VIDEO_MIX_REFERENCE_IMAGES} reference images, including generated axes`
11099
+ });
11100
+ }
11101
+ const anyAxis = req.axes.product || req.axes.person || req.axes.setting;
11102
+ if (!anyAxis && !req.audioUrl) {
11103
+ ctx.addIssue({
11104
+ code: "custom",
11105
+ message: "mix requires at least one axis to swap or a user audio"
11106
+ });
11107
+ }
11108
+ });
11109
+ }
11110
+ __name(createMixRequestSchema, "createMixRequestSchema");
11111
+ var MixRequest = createMixRequestSchema();
11036
11112
  var ReferenceMap = z51.object({
11037
11113
  product: z51.object({
11038
11114
  start: z51.number().int(),
@@ -11132,6 +11208,7 @@ var MixResult = z51.object({
11132
11208
  });
11133
11209
 
11134
11210
  // ../../packages/types/src/mix-cost.ts
11211
+ var IMAGE_GEN_USER_PRICE_CENTS = DEFAULT_PRICING["kie:image-generation:gpt-image-2-5-sunburst-text-to-image"].userPriceCents;
11135
11212
  var MAX_QA_RETRIES_PER_SCENE_UPPER_BOUND = 1;
11136
11213
  var MAX_BILLABLE_GENERATIONS_PER_BLOCK = 1 + MAX_QA_RETRIES_PER_SCENE_UPPER_BOUND;
11137
11214
 
@@ -11371,6 +11448,13 @@ var RegenerateLandingRoleResponse = z55.object({
11371
11448
  promptIndex: z55.number().int().nonnegative(),
11372
11449
  operationId: z55.string().min(1)
11373
11450
  });
11451
+ var LandingRegenerationFailureCode = z55.enum([
11452
+ "licensed_character_blocked",
11453
+ "provider_policy_blocked",
11454
+ "qa_rejected",
11455
+ "superseded",
11456
+ "provider_error"
11457
+ ]);
11374
11458
  var LandingRegenerationStatusResponse = z55.object({
11375
11459
  ok: z55.literal(true),
11376
11460
  operationId: z55.string().min(1),
@@ -11378,6 +11462,7 @@ var LandingRegenerationStatusResponse = z55.object({
11378
11462
  status: LandingRegenerationStatus,
11379
11463
  refunded: z55.boolean(),
11380
11464
  failureReason: z55.string().nullable(),
11465
+ failureCode: LandingRegenerationFailureCode.nullable().optional(),
11381
11466
  publishedAssetKey: z55.string().nullable(),
11382
11467
  updatedAt: z55.string().datetime()
11383
11468
  });
@@ -12335,6 +12420,23 @@ var CAPABILITY_MODEL_GUIDANCE = {
12335
12420
  "es trabajo pagado y requiere confirmaci\xF3n expl\xEDcita"
12336
12421
  ]
12337
12422
  },
12423
+ get_image_edit_status: {
12424
+ summary: "Consulta s\xF3lo el estado durable de una correcci\xF3n aceptada y su imagen entregada. No genera ni reintenta im\xE1genes; Task.done no significa que esta correcci\xF3n haya terminado.",
12425
+ useWhen: [
12426
+ "una correcci\xF3n de imagen ya devolvi\xF3 su operaci\xF3n aceptada",
12427
+ "la persona consulta el resultado de esa correcci\xF3n"
12428
+ ],
12429
+ avoidWhen: [
12430
+ "todav\xEDa no existe una operaci\xF3n aceptada"
12431
+ ],
12432
+ defaults: [
12433
+ "consulta la misma operaci\xF3n hasta su publicaci\xF3n o fallo durable",
12434
+ "un fallo al consultar no autoriza otra correcci\xF3n pagada"
12435
+ ],
12436
+ disclosures: [
12437
+ "la consulta no consume cr\xE9ditos ni inicia trabajo"
12438
+ ]
12439
+ },
12338
12440
  edit_task_draft: {
12339
12441
  summary: "Edita el draft de un angle de marketing antes de la generaci\xF3n.",
12340
12442
  useWhen: [
@@ -14290,7 +14392,7 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
14290
14392
  "task",
14291
14393
  "video"
14292
14394
  ]),
14293
- defineCapability("edit_image_creative", "ce0abba871436850bd1db0ea4bcdade9ef35420ebd83833e2d5c2dcf70378ec0", "credit_consuming", "creative", [
14395
+ defineCapability("edit_image_creative", "50eca473829328dfb63b9cbae03a9835b79c510e29528563e09b7eb3e5e9bca4", "credit_consuming", "creative", [
14294
14396
  "credit_consuming",
14295
14397
  "state_change"
14296
14398
  ], [
@@ -14300,12 +14402,27 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
14300
14402
  ]),
14301
14403
  slot("edit_instruction", true, [
14302
14404
  "instruction"
14303
- ])
14405
+ ]),
14406
+ slot("client_request", false, [
14407
+ "clientRequestId"
14408
+ ], [], "server")
14304
14409
  ], [
14305
14410
  "creative"
14306
14411
  ], [
14307
14412
  "creative"
14308
14413
  ]),
14414
+ defineCapability("get_image_edit_status", "fe59aefd433afe7e5a2d8b4a81084583750c1447c877b6bce698340326665141", "none", "read_only", [
14415
+ "read"
14416
+ ], [
14417
+ slot("creative_operation", true, [
14418
+ "taskId",
14419
+ "operationId"
14420
+ ], [], "server")
14421
+ ], [
14422
+ "creative_edit_operation"
14423
+ ], [
14424
+ "creative_edit_status"
14425
+ ], MCP_ONLY_CHANNEL_EXPOSURE),
14309
14426
  defineCapability("edit_task_draft", "1c9343bdce51aac36ec6254557c8a904037746523168527f012b4c5b6361e98e", "state_change", "creative", [
14310
14427
  "state_change"
14311
14428
  ], [
@@ -16960,7 +17077,7 @@ var ApiClient = class {
16960
17077
  };
16961
17078
 
16962
17079
  // src/index.ts
16963
- var MCP_VERSION = "8.7.0";
17080
+ var MCP_VERSION = "8.8.0";
16964
17081
 
16965
17082
  // src/meta-upload-app.ts
16966
17083
  import { readFileSync } from "fs";
@@ -20645,6 +20762,7 @@ import { z as z82 } from "zod";
20645
20762
  var generateFreeVideoGuidance = getProductMakerCapabilityModelGuidance("generate_free_video");
20646
20763
  var generateVideoCreativeGuidance = getProductMakerCapabilityModelGuidance("generate_video_creative");
20647
20764
  var generateImageCreativesGuidance = getProductMakerCapabilityModelGuidance("generate_image_creatives");
20765
+ var imageEditStatusGuidance = getProductMakerCapabilityModelGuidance("get_image_edit_status");
20648
20766
  var editImageCreativeGuidance = getProductMakerCapabilityModelGuidance("edit_image_creative");
20649
20767
  var generateLandingGuidance = getProductMakerCapabilityModelGuidance("generate_landing");
20650
20768
  var CreativeRefs = {
@@ -20866,6 +20984,7 @@ var ImageInput = z82.object({
20866
20984
  var EditImageCreativeInput = z82.object({
20867
20985
  taskId: z82.string().uuid().describe("ID de la tarea de imagen ya finalizada."),
20868
20986
  variantIndex: z82.number().int().min(0).max(10).describe("\xCDndice de la variante a corregir (0 = primera imagen)."),
20987
+ clientRequestId: z82.string().min(1).max(160).optional().describe("Identidad estable de esta correcci\xF3n; reutil\xEDzala al reconciliar una respuesta perdida, no para otra instrucci\xF3n."),
20869
20988
  instruction: z82.string().min(1).max(1e3).describe('Qu\xE9 cambiar en esa imagen. Ej. "quita el badge de env\xEDo gratis", "cambia el fondo a blanco".')
20870
20989
  });
20871
20990
  var LandingInput = z82.object({
@@ -21140,13 +21259,30 @@ function registerCreativeTools(server, api, { transport = "http" } = {}) {
21140
21259
  await requirePaidCreativeConfirmation(server, `Correcci\xF3n pagada de la imagen ${input.variantIndex + 1}.`);
21141
21260
  const r = await api.postJson(`/v1/creatives/images/${encodeURIComponent(input.taskId)}/regenerate`, {
21142
21261
  comment: input.instruction,
21143
- variantIndex: input.variantIndex
21262
+ variantIndex: input.variantIndex,
21263
+ ...input.clientRequestId ? {
21264
+ clientRequestId: input.clientRequestId
21265
+ } : {}
21144
21266
  });
21145
21267
  return asText(r);
21146
21268
  } catch (e) {
21147
21269
  throw translateError(e);
21148
21270
  }
21149
21271
  });
21272
+ server.registerTool("get_image_edit_status", {
21273
+ description: imageEditStatusGuidance.summary,
21274
+ inputSchema: {
21275
+ taskId: z82.string().uuid(),
21276
+ operationId: z82.string().uuid()
21277
+ },
21278
+ annotations: READS_INTERNAL
21279
+ }, async (input) => {
21280
+ try {
21281
+ return asText(await api.getJson(`/v1/creatives/images/${encodeURIComponent(input.taskId)}/operations/${encodeURIComponent(input.operationId)}`));
21282
+ } catch (error) {
21283
+ throw translateError(error);
21284
+ }
21285
+ });
21150
21286
  server.registerTool("generate_landing", {
21151
21287
  description: generateLandingGuidance.summary + " No expone landing editable/code mientras siga siendo admin-only. Devuelve un taskId. Esta solicitud es directa: nunca busques, reutilices ni menciones un DropshippingProject.\n\nREQUERIDOS: images (1-5 fotos), language, country y creativeSetup. Ante \u201Ccrea una landing con este producto\u201D y una foto local, llama primero `request_media_upload` y usa los assetId. Pregunta price, offer y compareAtPrice cuando aplique; no asumas country/language.\n\nCONFIGURACI\xD3N: usa guided salvo delegaci\xF3n total expl\xEDcita. Presenta UN checklist compacto \u2014no preguntas seriales\u2014 con estrategia, formato, competencia, m\xE9todos de pago, contexto, direcci\xF3n creativa y headline/subheadline exactos opcionales. Prop\xF3n defaults recomendados; null significa que el usuario deleg\xF3 esa decisi\xF3n concreta, nunca que el agente la olvid\xF3.\n\nANTES de invocar, muestra el resumen y espera confirmaci\xF3n expl\xEDcita porque inicia trabajo pagado. guided pausa para revisar el \xE1ngulo; automatic equivale al toggle web \u201CDejar que la IA decida todo\u201D y omite la review.",
21152
21288
  inputSchema: LandingInput.shape,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@productmaker/mcp",
3
- "version": "8.7.0",
3
+ "version": "8.8.0",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "description": "ProductMaker MCP server — cost products, generate landing pages, UGC videos, and ad creatives, and publish to Shopify, Meta Ads, and TikTok Ads.",