@pixeldojo/mcp 0.17.0 → 0.18.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.
package/dist/index.cjs CHANGED
@@ -1466,13 +1466,23 @@ async function applyCast(ctx, filmId, cast) {
1466
1466
  role: c.name,
1467
1467
  ...c.character_id ? { characterId: c.character_id } : {},
1468
1468
  ...c.image_urls ? { imageUrls: c.image_urls } : {},
1469
- ...c.prompt ? { prompt: c.prompt } : {}
1469
+ ...c.prompt ? { prompt: c.prompt } : {},
1470
+ ...c.replace ? { replace: true } : {},
1471
+ ...c.remove ? { remove: true } : {}
1470
1472
  }
1471
1473
  );
1472
- if (r.status === 200 && r.data.creditCost) charged = true;
1473
- if (r.status !== 200) return `Could not cast ${c.name}: ${r.data.error ?? r.status}`;
1474
- if (r.data.alreadyCast) return `${c.name} was already cast; nothing changed.`;
1475
- return `Cast ${c.name}${r.data.creditCost ? ` (portrait, ${r.data.creditCost} credits)` : ""}${r.data.boundShots ? `, in ${r.data.boundShots} shot(s)` : ""}.`;
1474
+ if (r.data.creditCost) charged = true;
1475
+ if (r.status !== 200) {
1476
+ const where2 = r.data.code === "cast-rendered" ? ` Storyboard: ${ctx.baseUrl}/film-studio/${filmId}` : "";
1477
+ return `Could not ${c.remove ? "remove" : c.replace ? "replace" : "cast"} ${c.name}: ${r.data.error ?? r.status}${where2}`;
1478
+ }
1479
+ if (r.data.removed) return `Removed ${c.name} from the film and every shot.`;
1480
+ if (r.data.alreadyCast) {
1481
+ return c.replace ? `${c.name} is already played by that character; nothing changed.` : `${c.name} is already cast; nothing changed. To swap who plays ${c.name}, send the entry again with replace: true.`;
1482
+ }
1483
+ const cost = r.data.creditCost ? ` (portrait, ${r.data.creditCost} credits)` : "";
1484
+ const where = r.data.boundShots ? `, in ${r.data.boundShots} shot(s)` : "";
1485
+ return r.data.replaced ? `Replaced ${r.data.replaced.name} with ${r.data.character?.name ?? "the new cast member"}${r.data.character?.id ? ` (character_id ${r.data.character.id})` : ""} as ${c.name}${cost}${where}.` : `Cast ${c.name}${cost}${where}.`;
1476
1486
  }));
1477
1487
  return { lines, charged };
1478
1488
  }
@@ -1775,7 +1785,7 @@ async function run8(input, ctx) {
1775
1785
  if (action === "plan") return plan(input, ctx);
1776
1786
  if (!input.film_id) return { kind: "text", text: "produce/status/cast need the film_id returned by the plan step." };
1777
1787
  if (action === "cast") {
1778
- if (!input.cast?.length) return { kind: "text", text: "Pass cast: [{ name, prompt | image_urls | character_id }] to cast characters." };
1788
+ if (!input.cast?.length) return { kind: "text", text: "Pass cast: [{ name, prompt | image_urls | character_id }] to cast characters (add replace: true to swap someone already cast, or remove: true to take them off)." };
1779
1789
  const { lines } = await applyCast(ctx, input.film_id, input.cast);
1780
1790
  const uncast = await uncastRolesOf(ctx, input.film_id);
1781
1791
  return {
@@ -1808,15 +1818,17 @@ var init_film = __esm({
1808
1818
  aspect: zod.z.enum(["16:9", "9:16"]).default("16:9"),
1809
1819
  length: zod.z.enum(["30s", "60s", "2-3min", "5min"]).default("60s").describe("Target length; drives the shot count (~6/12/24/60 shots)."),
1810
1820
  film_id: zod.z.string().max(40).optional().describe("Existing film id (from a previous call) for produce/status/cast."),
1811
- action: zod.z.enum(["plan", "produce", "status", "cast"]).default("plan").describe("'plan' creates + storyboards (free). 'cast' casts characters on an existing film. 'produce' starts charged generation. 'status' advances production and reports progress; poll it every ~30s until it returns the finished film."),
1821
+ action: zod.z.enum(["plan", "produce", "status", "cast"]).default("plan").describe("'plan' creates + storyboards (free). 'cast' casts, replaces or removes characters on an existing film. 'produce' starts charged generation. 'status' advances production and reports progress; poll it every ~30s until it returns the finished film."),
1812
1822
  cast: zod.z.array(
1813
1823
  zod.z.object({
1814
1824
  name: zod.z.string().trim().min(1).max(60),
1815
1825
  image_urls: zod.z.array(zod.z.string().url().startsWith("https://").max(2048)).min(1).max(8).optional(),
1816
1826
  prompt: zod.z.string().trim().min(1).max(600).optional(),
1817
- character_id: zod.z.string().max(40).optional()
1827
+ character_id: zod.z.string().max(40).optional(),
1828
+ replace: zod.z.boolean().optional(),
1829
+ remove: zod.z.boolean().optional()
1818
1830
  })
1819
- ).max(8).optional().describe("Cast members, one per named character. Each gives image_urls (your own photos), a prompt (a portrait is generated, charged), or a character_id (a Character Studio character); with none of these the Character Studio character of that name is used."),
1831
+ ).max(8).optional().describe("Cast members, one per named character. Each gives image_urls (your own photos), a prompt (a portrait is generated, charged), or a character_id (a Character Studio character); with none of these the Character Studio character of that name is used. replace: true swaps out whoever already plays that name; remove: true takes them off the film."),
1820
1832
  soundtrack: zod.z.enum(["scene-synced", "flat", "none"]).default("scene-synced").describe("scene-synced composes one musical section per scene, pinned to the scene lengths (default). flat is a single cohesive bed. none skips music."),
1821
1833
  music_job_id: zod.z.string().max(80).optional().describe("The music_job_id from the previous status reply while the score is composing, so that score is attached. A status call without it, once all clips are ready and no score is attached, starts and charges for a new score.")
1822
1834
  });
@@ -1845,12 +1857,12 @@ var init_film = __esm({
1845
1857
  action: {
1846
1858
  type: "string",
1847
1859
  enum: ["plan", "produce", "status", "cast"],
1848
- description: "plan (default, free): writes the script and plans shots, returns film_id, a cost estimate, and any characters still to cast. cast: casts characters on an existing film (pass film_id and cast). produce (charged): starts rendering frames; refused until every named character is cast. status: advances production one step and reports progress; call it every ~30s until it returns the finished film URL."
1860
+ description: "plan (default, free): writes the script and plans shots, returns film_id, a cost estimate, and any characters still to cast. cast: casts, replaces or removes characters on an existing film (pass film_id and cast). produce (charged): starts rendering frames; refused until every named character is cast. status: advances production one step and reports progress; call it every ~30s until it returns the finished film URL."
1849
1861
  },
1850
1862
  cast: {
1851
1863
  type: "array",
1852
1864
  maxItems: 8,
1853
- description: 'Cast members, one per named character. Every named character must be cast before frames render, so faces, ages and species hold in every shot. Pass them on the plan call (the script then stars them by name) or later with action "cast" using the names the plan reports. Each entry: name, plus ONE of image_urls (your own photos of an adult, made into a character), prompt (a portrait is generated from it, charged like any image), or character_id (a Character Studio character). An entry with only a name uses your Character Studio character of that name.',
1865
+ description: 'Cast members, one per named character. Every named character must be cast before frames render, so faces, ages and species hold in every shot. Pass them on the plan call (the script then stars them by name) or later with action "cast" using the names the plan reports. Each entry: name, plus ONE of image_urls (your own photos of an adult, made into a character), prompt (a portrait is generated from it, charged like any image), or character_id (a Character Studio character). An entry with only a name uses your Character Studio character of that name. A name that is already cast is left alone unless the entry sets replace: true, which hands that part (every shot, outfit and voice) to the new cast member. remove: true with only the name takes that cast member off the film; the part then needs a new cast member before frames render. replace and remove work until the shots of that cast member are rendered; after that, recast on the storyboard, where the frames that show them can be redone.',
1854
1866
  items: {
1855
1867
  type: "object",
1856
1868
  properties: {
@@ -1860,7 +1872,15 @@ var init_film = __esm({
1860
1872
  type: "string",
1861
1873
  description: 'A description to generate the portrait from: species if not human, gender, adult age, look and outfit (e.g. "man in his late 50s, grey mustache, sunburnt, red windbreaker").'
1862
1874
  },
1863
- character_id: { type: "string", description: "A Character Studio character id." }
1875
+ character_id: { type: "string", description: "A Character Studio character id." },
1876
+ replace: {
1877
+ type: "boolean",
1878
+ description: "Swap out whoever already plays this name for the image_urls, prompt or character_id given here, before their shots are rendered. Without it, an already-cast name is left unchanged."
1879
+ },
1880
+ remove: {
1881
+ type: "boolean",
1882
+ description: "Take whoever plays this name off the film and every shot (free), before their shots are rendered. Give only the name."
1883
+ }
1864
1884
  },
1865
1885
  required: ["name"]
1866
1886
  }
@@ -1907,8 +1927,8 @@ var init_film = __esm({
1907
1927
  };
1908
1928
  filmSkill = {
1909
1929
  name: "pixeldojo_film",
1910
- description: "Make a finished short film from one idea: screenplay, storyboard frames (AI-reviewed), video clips with spoken dialogue, scene-synced soundtrack, stitched export. Or a music video: pass song_path (a local file) or song_url (your own PixelDojo upload from pixeldojo_upload, never a third-party link) with optional lyrics; the film is cut to that song, each clip lip-synced to its slice on the studio music video engine, and no score is composed: the export plays the song. Every named character must be cast (cast: your own images, a portrait prompt, or a Character Studio character) before frames render. Phased: plan is free; cast; produce starts charged generation; status advances production (poll every ~30s).",
1911
- hostedDescription: "Make a finished short film from one idea: screenplay, storyboard frames (AI-reviewed), video clips with spoken dialogue, scene-synced soundtrack, stitched export. Or a music video: pass song_url (your own PixelDojo upload made with POST /api/v1/upload, never a third-party link) with optional lyrics; the film is cut to that song, each clip lip-synced to its slice on the studio music video engine, and no score is composed: the export plays the song. Every named character must be cast (cast: your own images, a portrait prompt, or a Character Studio character) before frames render. Phased: plan is free; cast; produce starts charged generation; status advances production (poll every ~30s).",
1930
+ description: "Make a finished short film from one idea: screenplay, storyboard frames (AI-reviewed), video clips with spoken dialogue, scene-synced soundtrack, stitched export. Or a music video: pass song_path (a local file) or song_url (your own PixelDojo upload from pixeldojo_upload, never a third-party link) with optional lyrics; the film is cut to that song, each clip lip-synced to its slice on the studio music video engine, and no score is composed: the export plays the song. Every named character must be cast (cast: your own images, a portrait prompt, or a Character Studio character) before frames render; cast entries can also replace or remove someone. Phased: plan is free; cast; produce starts charged generation; status advances production (poll every ~30s).",
1931
+ hostedDescription: "Make a finished short film from one idea: screenplay, storyboard frames (AI-reviewed), video clips with spoken dialogue, scene-synced soundtrack, stitched export. Or a music video: pass song_url (your own PixelDojo upload made with POST /api/v1/upload, never a third-party link) with optional lyrics; the film is cut to that song, each clip lip-synced to its slice on the studio music video engine, and no score is composed: the export plays the song. Every named character must be cast (cast: your own images, a portrait prompt, or a Character Studio character) before frames render; cast entries can also replace or remove someone. Phased: plan is free; cast; produce starts charged generation; status advances production (poll every ~30s).",
1912
1932
  inputZod: InputSchema8,
1913
1933
  inputJsonSchema: InputJsonSchema8,
1914
1934
  allowedModels: [],
@@ -3385,7 +3405,7 @@ function makeRedactedLogger(target = console) {
3385
3405
  }
3386
3406
 
3387
3407
  // src/server.ts
3388
- var PACKAGE_VERSION = "0.17.0" ;
3408
+ var PACKAGE_VERSION = "0.18.0" ;
3389
3409
  var SERVER_INSTRUCTIONS = "PixelDojo generates images, video, audio and short films across 100+ models, billed in credits from the connected PixelDojo account. A job that runs past the 30-second wait returns a jobId to check later; check it rather than submitting again, since every new submission is charged. Generated asset URLs are deleted one hour after they are created, so download anything the user wants to keep. Finished films are the exception and stay in the account library.";
3390
3410
  function buildServer(options) {
3391
3411
  if (!options.apiKey) {