goatedit-mcp 1.1.22 → 1.1.24

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.
@@ -20413,7 +20413,7 @@ var BASE_TOOLS = [
20413
20413
  },
20414
20414
  {
20415
20415
  name: "update_shape_clip",
20416
- description: "Change a shape after it was made \u2014 fill, size, corners, outline, and a dashed or rounded outline \u2014 without deleting it and losing its id, keyframes and effects.",
20416
+ description: "Change a shape after it was made \u2014 fill, size, position, length, corners, outline, and a dashed or rounded outline \u2014 without deleting it and losing its id, keyframes and effects.",
20417
20417
  inputSchema: {
20418
20418
  type: "object",
20419
20419
  properties: {
@@ -20433,7 +20433,10 @@ var BASE_TOOLS = [
20433
20433
  closed: bool("Path shapes: join the last anchor back to the first."),
20434
20434
  trimStart: num("Path shapes: where along the path drawing starts, 0..1. Keyframe it as pathTrimStart."),
20435
20435
  trimEnd: num("Path shapes: where drawing stops, 0..1. 0 hides the path; keyframing pathTrimEnd 0 to 1 with set_keyframes draws it on."),
20436
- trimOffset: num("Path shapes: slides the drawn stretch along the path, degrees.")
20436
+ trimOffset: num("Path shapes: slides the drawn stretch along the path, degrees."),
20437
+ x: num("Centre across the frame, 0..1 (sets posX; keyframes on posX still win)."),
20438
+ y: num("Centre down the frame, 0..1 (sets posY)."),
20439
+ duration: num("New length in seconds, from the same start. Refused if it would run into the next clip on the track.")
20437
20440
  },
20438
20441
  required: ["clipId"]
20439
20442
  },
@@ -21174,6 +21177,7 @@ var BASE_TOOLS = [
21174
21177
  items: { type: "object" }
21175
21178
  },
21176
21179
  clear: bool("Remove this property's keyframes instead of setting them, leaving the clip's flat value in charge again."),
21180
+ offset: { description: 'With prop "position" or "scale" and no keyframes: move the animation as it is. Every existing key of both halves is shifted ([dx, dy] added to position) or scaled (a number or [sx, sy] multiplying scale), times and eases kept; a track with no keys has its resting value moved instead. The way to nudge an animated layer or a whole pile without rewriting its keys.' },
21177
21181
  relative: bool("Values are relative to where the layer rests: multiples of its scale/opacity (1.1 = 10% bigger than it is), offsets for everything else (posX +0.05, rotation +15). A punch-in on a card scaled 0.3 stays a punch-in instead of jumping to full size."),
21178
21182
  expression: {
21179
21183
  type: "string",
@@ -21434,7 +21438,9 @@ var BASE_TOOLS = [
21434
21438
  height: num("Render height in pixels. Defaults to the preset's, or the project height."),
21435
21439
  posX: num("Horizontal centre as a fraction of the frame, 0..1. 0.5 is centre."),
21436
21440
  posY: num("Vertical centre as a fraction of the frame, 0..1. 0.5 is centre."),
21437
- scale: num("Uniform scale, 1 being unchanged."),
21441
+ scale: num('Uniform scale, 1 being unchanged. With size "native", a multiplier on the native size.'),
21442
+ rotation: num("Rotation in degrees."),
21443
+ size: str(`"fit" (default): like any picture, the width x height box is fitted inside the frame, so a 600x200 card fills the frame width. "native": one authored px is one frame px, so a 600x200 card is 600x200 on screen. Use native for UI pieces authored at their real size. The result's onScreen gives the box in frame px either way. The clip's stored scale stays relative to the fitted box (onScreen.nativeScale is native size), so set_clip_transform and scale keys later take that number, not 1; set_clip_transform on an html clip replies with onScreen too.`),
21438
21444
  opacity: num("Opacity, 0..1. Defaults to 1."),
21439
21445
  name: str("Display name for the clip and its bin entry.")
21440
21446
  },
@@ -21624,10 +21630,11 @@ var BASE_TOOLS = [
21624
21630
  type: "object",
21625
21631
  properties: {
21626
21632
  clipId: CLIP_ID,
21627
- newStartTime: num("New timeline start time in seconds."),
21633
+ startTime: num("New timeline start time in seconds."),
21634
+ newStartTime: num("Same as startTime (older name)."),
21628
21635
  newTrackId: str('Track to move onto. Defaults to the clip\u2019s current track. Accepts "__new_video__" to pick a video track free across the clip\u2019s span, or "__new_track__" for a new video track on top.')
21629
21636
  },
21630
- required: ["clipId", "newStartTime"]
21637
+ required: ["clipId"]
21631
21638
  },
21632
21639
  method: "moveClip"
21633
21640
  },
@@ -25719,6 +25726,42 @@ async function importLocalFile(args, target) {
25719
25726
  );
25720
25727
  }
25721
25728
  }
25729
+ var RUN_STEP_COMMON_ARGS = /* @__PURE__ */ new Set(["projectId", "expectedSequenceId", "opId"]);
25730
+ function preflightSteps(calls) {
25731
+ const errors = [], warnings = [];
25732
+ calls.forEach((raw, i) => {
25733
+ const step = raw;
25734
+ const n = i + 1;
25735
+ const tool = typeof step?.tool === "string" ? step.tool : "";
25736
+ if (!tool) {
25737
+ errors.push(`step ${n}: no tool name.`);
25738
+ return;
25739
+ }
25740
+ if (tool === "run_tools") {
25741
+ errors.push(`step ${n}: run_tools cannot be nested.`);
25742
+ return;
25743
+ }
25744
+ const def = BROWSER_TOOLS_BY_NAME.get(tool);
25745
+ if (!def) return;
25746
+ const args = step.args && typeof step.args === "object" ? step.args : {};
25747
+ const props = def.inputSchema?.properties ?? {};
25748
+ for (const key of def.inputSchema?.required ?? []) {
25749
+ if (args[key] === void 0) errors.push(`step ${n} (${tool}): missing required "${key}".`);
25750
+ }
25751
+ for (const [key, value] of Object.entries(args)) {
25752
+ const spec = props[key];
25753
+ if (!spec) {
25754
+ if (!RUN_STEP_COMMON_ARGS.has(key)) warnings.push(`step ${n} (${tool}): "${key}" is not an argument of ${tool} and is ignored. It takes: ${Object.keys(props).join(", ")}.`);
25755
+ continue;
25756
+ }
25757
+ if (typeof value === "string" && value.startsWith("$")) continue;
25758
+ const want = spec.type;
25759
+ const ok = !want || value === null || (want === "number" || want === "integer" ? typeof value === "number" : want === "string" ? typeof value === "string" : want === "boolean" ? typeof value === "boolean" : want === "array" ? Array.isArray(value) : want === "object" ? typeof value === "object" && !Array.isArray(value) : true);
25760
+ if (!ok) errors.push(`step ${n} (${tool}): "${key}" should be ${want}, got ${Array.isArray(value) ? "array" : typeof value}.`);
25761
+ }
25762
+ });
25763
+ return { errors, warnings };
25764
+ }
25722
25765
  async function runTools(args) {
25723
25766
  const calls = args.calls;
25724
25767
  if (!Array.isArray(calls) || !calls.length) {
@@ -25727,6 +25770,16 @@ async function runTools(args) {
25727
25770
  if (args.rollback && args.continueOnError) {
25728
25771
  throw new McpError(ErrorCode.InvalidParams, "rollback and continueOnError cannot be combined: a run that keeps going after a failure has nothing to roll back to.");
25729
25772
  }
25773
+ const check = preflightSteps(calls);
25774
+ if (check.errors.length) {
25775
+ return {
25776
+ ok: false,
25777
+ ran: 0,
25778
+ errors: check.errors,
25779
+ note: "Nothing ran: fix these and send the run again.",
25780
+ ...check.warnings.length ? { warnings: check.warnings } : {}
25781
+ };
25782
+ }
25730
25783
  const results = [];
25731
25784
  const images = [];
25732
25785
  const refs = /* @__PURE__ */ new Map();
@@ -25781,6 +25834,8 @@ async function runTools(args) {
25781
25834
  return {
25782
25835
  ok: failed === 0,
25783
25836
  results,
25837
+ ...check.warnings.length ? { warnings: check.warnings } : {},
25838
+ ...failed && !args.continueOnError && !args.rollback ? { hint: "One failing step skips the rest. Pass continueOnError: true to run the other steps anyway." } : {},
25784
25839
  ...failed && runOpId ? { opId: runOpId, retry: `Repeat this run_tools call with opId "${runOpId}": finished steps answer from the tab without running again.` } : {},
25785
25840
  ...rolledBack !== void 0 ? { rolledBack } : {},
25786
25841
  ...images.length ? { _images: images } : {}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "goatedit-mcp",
3
- "version": "1.1.22",
3
+ "version": "1.1.24",
4
4
  "description": "Local MCP server for the GoatEdit video editor: drive your open editor tab from Claude Code or any MCP client",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",