@pixeldojo/mcp 0.15.0 → 0.15.1

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/cli.cjs CHANGED
@@ -1410,13 +1410,13 @@ function progressLine(f) {
1410
1410
  const rendering = all.filter((sh) => sh.status === "clip-generating").length;
1411
1411
  return `frames ${frames}/${all.length}, clips ${clips}/${all.length}${rendering > 0 ? ` (${rendering} rendering)` : ""}`;
1412
1412
  }
1413
- async function runPlanner(ctx, filmId, path, body) {
1413
+ async function runPlanner(ctx, filmId, path, body, maxPolls = PLANNER_MAX_POLLS) {
1414
1414
  const submit = await filmApi(ctx, "POST", path, body);
1415
1415
  if (submit.data.film) return { film: submit.data.film };
1416
1416
  const jobId = submit.data.jobId;
1417
1417
  if (!jobId) return { error: submit.data.error ?? `HTTP ${submit.status}` };
1418
1418
  const sleep = ctx.pollOverrides?.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
1419
- for (let i = 0; i < PLANNER_MAX_POLLS; i += 1) {
1419
+ for (let i = 0; i < maxPolls; i += 1) {
1420
1420
  await sleep(PLANNER_POLL_MS);
1421
1421
  const { data } = await filmApi(ctx, "GET", `/api/films/${filmId}`);
1422
1422
  const job = data.film?.llmJob;
@@ -1485,7 +1485,7 @@ ${input.lyrics.trim()}` : ""].filter(Boolean).join("\n\n");
1485
1485
  let script = input.script?.trim() ?? "";
1486
1486
  if (!script) {
1487
1487
  const wrote = await runPlanner(ctx, id, `/api/films/${id}/script`, { idea: input.idea.trim() });
1488
- if ("pending" in wrote) return { kind: "text", text: stillPlanningText(id) };
1488
+ if ("pending" in wrote) return { kind: "text", text: stillPlanningText(id, "script") };
1489
1489
  if ("error" in wrote) return { kind: "text", text: `Script writing failed: ${wrote.error}` };
1490
1490
  script = wrote.film.script ?? "";
1491
1491
  if (!script) return { kind: "text", text: "Script writing failed: the studio returned an empty script." };
@@ -1505,12 +1505,14 @@ ${err} Call action "status" to retry the cut.` };
1505
1505
  }
1506
1506
  async function resumePlanning(film, ctx) {
1507
1507
  if (film.scenes.length > 0 && film.llmJob?.status !== "running") return null;
1508
- if (film.llmJob?.status === "running") return { kind: "text", text: stillPlanningText(film.id) };
1508
+ if (film.llmJob?.status === "running") {
1509
+ return { kind: "text", text: stillPlanningText(film.id, film.llmJob.kind === "script" ? "script" : "plan") };
1510
+ }
1509
1511
  const prior = film.llmJob?.status === "error" ? `The last planning run failed (${film.llmJob.error ?? "unknown"}). ` : "";
1510
1512
  if (!film.script?.trim()) {
1511
1513
  return { kind: "text", text: `${prior}This film has nothing to plan from. Start a new one with action "plan".` };
1512
1514
  }
1513
- const planned = await runPlanner(ctx, film.id, `/api/films/${film.id}/plan`, { script: film.script });
1515
+ const planned = await runPlanner(ctx, film.id, `/api/films/${film.id}/plan`, { script: film.script }, 0);
1514
1516
  if ("pending" in planned) return { kind: "text", text: `${prior}${stillPlanningText(film.id)}` };
1515
1517
  if ("error" in planned) return { kind: "text", text: `Shot planning failed: ${planned.error} Call action "status" to retry.` };
1516
1518
  if (needsSlice(planned.film)) {
@@ -1596,6 +1598,9 @@ It is saved in the Library folder "Film: ${film.title}".`
1596
1598
  if (err) return { kind: "text", text: `${err} Poll again with action "status" to retry.` };
1597
1599
  return { kind: "text", text: `Song cut into one slice per shot. Poll again with {"film_id": "${filmId}", "action": "status"} to keep production moving.` };
1598
1600
  }
1601
+ if (shots(film).length > 0 && shots(film).every((sh) => sh.status === "idle")) {
1602
+ return { kind: "text", text: plannedText(film, ctx) };
1603
+ }
1599
1604
  const idleFrames = all.filter((sh) => sh.status === "idle");
1600
1605
  for (const sh of idleFrames.slice(0, 6)) {
1601
1606
  await filmApi(ctx, "POST", `/api/films/${filmId}/shots/${sh.id}/generate`, { kind: "frame" });
@@ -1721,7 +1726,7 @@ var init_film = __esm({
1721
1726
  PLANNER_MAX_POLLS = 8;
1722
1727
  isMusicVideo = (f) => f.musicVideoMode === true;
1723
1728
  needsSlice = (f) => isMusicVideo(f) && shots(f).length > 0 && !shots(f).some((sh) => sh.musicChunkUrl);
1724
- stillPlanningText = (filmId) => `Planning is still running (film_id: ${filmId}). Nothing has been charged. Call pixeldojo_film with {"film_id": "${filmId}", "action": "status"} in ~30s; it returns the plan once it is ready.`;
1729
+ stillPlanningText = (filmId, stage = "plan") => `${stage === "script" ? "Still writing the script" : "Still planning the shots"} for film_id ${filmId}. Nothing has been charged. Call pixeldojo_film with {"film_id": "${filmId}", "action": "status"} in ~30s; it returns the plan once it is ready.`;
1725
1730
  LOOK_MUSIC = {
1726
1731
  "live-action": "modern cinematic underscore, warm strings and soft felt piano, subtle rhythmic pulse, slow emotional build",
1727
1732
  anime: "sweeping anime film score, lush strings and piano, taiko drum accents, soaring heartfelt theme",
@@ -3185,7 +3190,7 @@ function makeRedactedLogger(target = console) {
3185
3190
  }
3186
3191
 
3187
3192
  // src/server.ts
3188
- var PACKAGE_VERSION = "0.14.0" ;
3193
+ var PACKAGE_VERSION = "0.15.1" ;
3189
3194
  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.";
3190
3195
  function buildServer(options) {
3191
3196
  if (!options.apiKey) {