goatedit-mcp 1.1.20 → 1.1.21
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/bundle/goatedit-mcp.js +46 -9
- package/package.json +1 -1
package/bundle/goatedit-mcp.js
CHANGED
|
@@ -20043,6 +20043,16 @@ var BASE_TOOLS = [
|
|
|
20043
20043
|
},
|
|
20044
20044
|
method: "getEditLog"
|
|
20045
20045
|
},
|
|
20046
|
+
{
|
|
20047
|
+
name: "get_operation",
|
|
20048
|
+
description: 'Where an edit stands after its call timed out or the connection dropped: queued, running, done (with its reply) or failed, by the opId the error gave. "unknown" means the tab never got it, so sending it again is safe. To retry, repeat the call with that same opId: the tab runs an opId once and answers a repeat with the first reply, so a retry never makes a clip twice.',
|
|
20049
|
+
inputSchema: {
|
|
20050
|
+
type: "object",
|
|
20051
|
+
properties: { opId: { type: "string", description: "The id from the timeout or disconnect message." } },
|
|
20052
|
+
required: ["opId"]
|
|
20053
|
+
},
|
|
20054
|
+
method: "getOperation"
|
|
20055
|
+
},
|
|
20046
20056
|
{
|
|
20047
20057
|
name: "clean_unused_sequences",
|
|
20048
20058
|
description: "Find nested sequences that no clip uses any more \u2014 left behind when a nest clip is removed or a shot is rebuilt \u2014 and optionally delete them with their bin items. Without apply it only lists them. A scene (a sequence once placed with add_sequence_clip) counts as a nest. Other top-level sequences, and nests reachable from one or open in a tab, are never touched; top-level ones nothing plays are listed under otherUnplayed for delete_sequence.",
|
|
@@ -22035,6 +22045,7 @@ var TOOLS_BY_NAME = new Map([
|
|
|
22035
22045
|
var READ_ONLY_TOOLS = /* @__PURE__ */ new Set([
|
|
22036
22046
|
"get_session_status",
|
|
22037
22047
|
"get_design_guide",
|
|
22048
|
+
"get_operation",
|
|
22038
22049
|
"get_project_state",
|
|
22039
22050
|
"get_transcript",
|
|
22040
22051
|
"render_preview_frame",
|
|
@@ -22423,6 +22434,10 @@ function withRunSequence(stepArgs, sequenceId, tool) {
|
|
|
22423
22434
|
if (!tool || !("expectedSequenceId" in (tool.inputSchema.properties ?? {}))) return stepArgs;
|
|
22424
22435
|
return { ...stepArgs, expectedSequenceId: sequenceId };
|
|
22425
22436
|
}
|
|
22437
|
+
function withRunOp(stepArgs, runOpId, index2) {
|
|
22438
|
+
if (!runOpId || typeof stepArgs.opId === "string") return stepArgs;
|
|
22439
|
+
return { ...stepArgs, opId: `${runOpId}.${index2 + 1}` };
|
|
22440
|
+
}
|
|
22426
22441
|
|
|
22427
22442
|
// src/tab-registry.ts
|
|
22428
22443
|
function indexTabs(reports, isOpen) {
|
|
@@ -25250,13 +25265,16 @@ function resolveTab(projectId) {
|
|
|
25250
25265
|
if (!id) throw new Error(notConnectedMessage());
|
|
25251
25266
|
return tabs.get(id);
|
|
25252
25267
|
}
|
|
25268
|
+
function unsettled(message) {
|
|
25269
|
+
return Object.assign(new Error(message), { unsettled: true });
|
|
25270
|
+
}
|
|
25253
25271
|
var pendingRequests = /* @__PURE__ */ new Map();
|
|
25254
25272
|
function rejectPendingOn(socket, why) {
|
|
25255
25273
|
for (const [id, pending] of pendingRequests) {
|
|
25256
25274
|
if (pending.socket !== socket) continue;
|
|
25257
25275
|
clearTimeout(pending.timeoutId);
|
|
25258
25276
|
pendingRequests.delete(id);
|
|
25259
|
-
pending.reject(
|
|
25277
|
+
pending.reject(unsettled(`${why} before ${pending.method} answered. Check the editor tab.`));
|
|
25260
25278
|
}
|
|
25261
25279
|
}
|
|
25262
25280
|
function explainTabError(error2) {
|
|
@@ -25397,7 +25415,7 @@ function failUpstream(why) {
|
|
|
25397
25415
|
for (const [id, p] of upstreamPending) {
|
|
25398
25416
|
clearTimeout(p.timeoutId);
|
|
25399
25417
|
upstreamPending.delete(id);
|
|
25400
|
-
p.reject(
|
|
25418
|
+
p.reject(unsettled(`${why} before ${p.method} answered.`));
|
|
25401
25419
|
}
|
|
25402
25420
|
}
|
|
25403
25421
|
function connectUpstream() {
|
|
@@ -25455,7 +25473,7 @@ function sendUpstream(method, params, projectId) {
|
|
|
25455
25473
|
const id = crypto2.randomUUID();
|
|
25456
25474
|
const timeoutId = setTimeout(() => {
|
|
25457
25475
|
upstreamPending.delete(id);
|
|
25458
|
-
reject(
|
|
25476
|
+
reject(unsettled(`Request timed out: ${method}`));
|
|
25459
25477
|
}, REQUEST_TIMEOUT_MS);
|
|
25460
25478
|
upstreamPending.set(id, { resolve, reject, timeoutId, method });
|
|
25461
25479
|
ws.send(JSON.stringify({ id, method, params, ...projectId ? { projectId } : {} }));
|
|
@@ -25469,7 +25487,7 @@ async function sendToBrowser(method, params = {}, projectId) {
|
|
|
25469
25487
|
const id = crypto2.randomUUID();
|
|
25470
25488
|
const timeoutId = setTimeout(() => {
|
|
25471
25489
|
pendingRequests.delete(id);
|
|
25472
|
-
reject(
|
|
25490
|
+
reject(unsettled(`Request timed out after ${REQUEST_TIMEOUT_MS / 1e3}s: ${method}.`));
|
|
25473
25491
|
}, REQUEST_TIMEOUT_MS);
|
|
25474
25492
|
pendingRequests.set(id, { resolve, reject, timeoutId, socket: tab.ws, method });
|
|
25475
25493
|
tab.ws.send(JSON.stringify({ id, method, params, projectId: tab.projectId }));
|
|
@@ -25576,7 +25594,8 @@ var LOCAL_TOOLS = [
|
|
|
25576
25594
|
continueOnError: { type: "boolean", description: "Run the remaining steps after one fails." },
|
|
25577
25595
|
rollback: { type: "boolean", description: "Take a checkpoint first and restore it if any step fails, so a run either lands whole or not at all. Cannot be combined with continueOnError." },
|
|
25578
25596
|
projectId: { type: "string", description: "Run every step on this project (from list_connected_projects). Use it when several agents edit different tabs at once; a step's own projectId wins." },
|
|
25579
|
-
expectedSequenceId: { type: "string", description: "Run every step that takes expectedSequenceId on this sequence (from list_sequences), open or not. Use it when several agents edit different sequences at once; a step's own expectedSequenceId wins." }
|
|
25597
|
+
expectedSequenceId: { type: "string", description: "Run every step that takes expectedSequenceId on this sequence (from list_sequences), open or not. Use it when several agents edit different sequences at once; a step's own expectedSequenceId wins." },
|
|
25598
|
+
opId: { type: "string", description: "Only to retry a run that failed or timed out: the opId its reply or error gave, with the same calls in the same order. Steps that already finished are answered without running again." }
|
|
25580
25599
|
},
|
|
25581
25600
|
required: ["calls"]
|
|
25582
25601
|
}
|
|
@@ -25590,6 +25609,7 @@ for (const [alias, name] of Object.entries(TOOL_ALIASES)) {
|
|
|
25590
25609
|
if (tool) BROWSER_TOOLS_BY_NAME.set(alias, tool);
|
|
25591
25610
|
}
|
|
25592
25611
|
var PROJECT_FREE_TOOLS = /* @__PURE__ */ new Set(["create_project", "begin_request", "record_choice", "set_style_brand"]);
|
|
25612
|
+
var VIEW_TOOLS = /* @__PURE__ */ new Set(["switch_project", "open_sequence", "playback_control", "set_playhead", "set_tool"]);
|
|
25593
25613
|
var SAVES_FRAMES = new Set(
|
|
25594
25614
|
BROWSER_TOOLS.filter((t) => "saveToDisk" in (t.inputSchema.properties ?? {})).map((t) => t.name)
|
|
25595
25615
|
);
|
|
@@ -25601,7 +25621,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
25601
25621
|
]
|
|
25602
25622
|
}));
|
|
25603
25623
|
async function callTool(name, args) {
|
|
25604
|
-
const { projectId: rawProjectId, ...forwarded } = args;
|
|
25624
|
+
const { projectId: rawProjectId, opId: rawOpId, ...forwarded } = args;
|
|
25605
25625
|
const projectId = typeof rawProjectId === "string" && rawProjectId ? rawProjectId : void 0;
|
|
25606
25626
|
switch (name) {
|
|
25607
25627
|
case "get_design_guide":
|
|
@@ -25631,6 +25651,7 @@ async function callTool(name, args) {
|
|
|
25631
25651
|
}
|
|
25632
25652
|
const saveToDisk = SAVES_FRAMES.has(name) && forwarded.saveToDisk !== false;
|
|
25633
25653
|
if (SAVES_FRAMES.has(name)) forwarded.saveToDisk = false;
|
|
25654
|
+
if (name === "get_operation") forwarded.opId = rawOpId;
|
|
25634
25655
|
const invalid = validateArgs(tool, forwarded);
|
|
25635
25656
|
if (invalid) throw new McpError(ErrorCode.InvalidParams, invalid);
|
|
25636
25657
|
const target = projectId ?? chosenProjectId;
|
|
@@ -25643,11 +25664,25 @@ async function callTool(name, args) {
|
|
|
25643
25664
|
);
|
|
25644
25665
|
}
|
|
25645
25666
|
}
|
|
25646
|
-
if (name
|
|
25647
|
-
|
|
25667
|
+
if (!READ_ONLY_TOOLS.has(tool.name) && !VIEW_TOOLS.has(tool.name)) {
|
|
25668
|
+
forwarded.opId = typeof rawOpId === "string" && rawOpId ? rawOpId : `op-${crypto2.randomUUID().slice(0, 8)}`;
|
|
25669
|
+
}
|
|
25670
|
+
if (name === "import_local_file") return withOpIdHint(importLocalFile(forwarded, target), forwarded.opId);
|
|
25671
|
+
const result = await withOpIdHint(sendToBrowser(tool.method, forwarded, target), forwarded.opId);
|
|
25648
25672
|
const withFile = saveFileToDisk(result);
|
|
25649
25673
|
return saveToDisk ? saveFramesToDisk(withFile, name) : withFile;
|
|
25650
25674
|
}
|
|
25675
|
+
async function withOpIdHint(call, opId) {
|
|
25676
|
+
try {
|
|
25677
|
+
return await call;
|
|
25678
|
+
} catch (err) {
|
|
25679
|
+
const message = err?.message ?? String(err);
|
|
25680
|
+
if (typeof opId !== "string" || !err?.unsettled) throw err;
|
|
25681
|
+
throw new Error(
|
|
25682
|
+
`${message} The edit may still finish. It is operation ${opId}: call get_operation with opId "${opId}" to see whether it did, or repeat this exact call with opId "${opId}" \u2014 the tab runs an opId once, so the retry cannot make anything twice.`
|
|
25683
|
+
);
|
|
25684
|
+
}
|
|
25685
|
+
}
|
|
25651
25686
|
async function importLocalFile(args, target) {
|
|
25652
25687
|
const local = await callLocal("find_local_file", { filename: args.filename }, target).catch((err) => {
|
|
25653
25688
|
if (/^Several files/.test(err?.message ?? "")) throw err;
|
|
@@ -25676,6 +25711,7 @@ async function runTools(args) {
|
|
|
25676
25711
|
const images = [];
|
|
25677
25712
|
const refs = /* @__PURE__ */ new Map();
|
|
25678
25713
|
let failed = 0;
|
|
25714
|
+
const runOpId = args.rollback ? null : typeof args.opId === "string" && args.opId ? args.opId : `op-${crypto2.randomUUID().slice(0, 8)}`;
|
|
25679
25715
|
let checkpointId;
|
|
25680
25716
|
if (args.rollback) {
|
|
25681
25717
|
const made = await callTool("create_checkpoint", withRunProject({ name: "run_tools rollback" }, args.projectId));
|
|
@@ -25686,7 +25722,7 @@ async function runTools(args) {
|
|
|
25686
25722
|
const tool = typeof step?.tool === "string" ? step.tool : "";
|
|
25687
25723
|
try {
|
|
25688
25724
|
const stepArgs = resolveRefs(step.args && typeof step.args === "object" ? step.args : {}, refs);
|
|
25689
|
-
const raw = await callTool(tool, withRunSequence(withRunProject(stepArgs, args.projectId), args.expectedSequenceId, BROWSER_TOOLS_BY_NAME.get(tool)));
|
|
25725
|
+
const raw = await callTool(tool, withRunOp(withRunSequence(withRunProject(stepArgs, args.projectId), args.expectedSequenceId, BROWSER_TOOLS_BY_NAME.get(tool)), runOpId, i));
|
|
25690
25726
|
if (typeof step.as === "string" && step.as) {
|
|
25691
25727
|
if (raw && typeof raw === "object" && !Array.isArray(raw)) {
|
|
25692
25728
|
const { _image, _images, ...kept } = raw;
|
|
@@ -25725,6 +25761,7 @@ async function runTools(args) {
|
|
|
25725
25761
|
return {
|
|
25726
25762
|
ok: failed === 0,
|
|
25727
25763
|
results,
|
|
25764
|
+
...failed && runOpId ? { opId: runOpId, retry: `Repeat this run_tools call with opId "${runOpId}": finished steps answer from the tab without running again.` } : {},
|
|
25728
25765
|
...rolledBack !== void 0 ? { rolledBack } : {},
|
|
25729
25766
|
...images.length ? { _images: images } : {}
|
|
25730
25767
|
};
|
package/package.json
CHANGED