goatedit-mcp 1.1.11 → 1.1.13
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 +141 -11
- package/package.json +1 -1
package/bundle/goatedit-mcp.js
CHANGED
|
@@ -19841,7 +19841,7 @@ import crypto2 from "crypto";
|
|
|
19841
19841
|
import http from "http";
|
|
19842
19842
|
import fs3 from "fs";
|
|
19843
19843
|
import path3 from "path";
|
|
19844
|
-
import { execFileSync } from "child_process";
|
|
19844
|
+
import { execFile, execFileSync } from "child_process";
|
|
19845
19845
|
import os2 from "os";
|
|
19846
19846
|
import { fileURLToPath } from "url";
|
|
19847
19847
|
|
|
@@ -20055,9 +20055,18 @@ var BASE_TOOLS = [
|
|
|
20055
20055
|
},
|
|
20056
20056
|
method: "deleteSequence"
|
|
20057
20057
|
},
|
|
20058
|
+
{
|
|
20059
|
+
name: "list_projects",
|
|
20060
|
+
description: "The person's saved GoatEdit projects, newest first: id, name, when last changed, and whether a connected tab has it open. Use an id with open_project to work on a project that is not open yet. Read-only.",
|
|
20061
|
+
inputSchema: {
|
|
20062
|
+
type: "object",
|
|
20063
|
+
properties: { limit: { type: "number", description: "How many to list (default 30, at most 100)." } }
|
|
20064
|
+
},
|
|
20065
|
+
method: "listProjects"
|
|
20066
|
+
},
|
|
20058
20067
|
{
|
|
20059
20068
|
name: "list_sequences",
|
|
20060
|
-
description: "Every sequence in the project: id, name, whether it is the one open for editing, open in a tab, a nest (made by nest_clips) or top-level, its length, how many clips it holds, and the clips that play it.
|
|
20069
|
+
description: "Every sequence in the project: id, name, whether it is the one open for editing, open in a tab, a nest (made by nest_clips) or top-level, its length, how many clips it holds, and the clips that play it. Tools act on the open sequence unless they are given expectedSequenceId \u2014 pass one of these ids to read or edit another sequence without opening it (open_sequence moves the person's view; prefer expectedSequenceId).",
|
|
20061
20070
|
inputSchema: { type: "object", properties: {} },
|
|
20062
20071
|
method: "listSequences"
|
|
20063
20072
|
},
|
|
@@ -21059,7 +21068,7 @@ var BASE_TOOLS = [
|
|
|
21059
21068
|
clipId: CLIP_ID,
|
|
21060
21069
|
type: {
|
|
21061
21070
|
type: "string",
|
|
21062
|
-
description: "Effect type: blur, invert, hue, saturation, brightness, contrast, exposure, grayscale, sepia, gradientMap, vignette, filmGrain, flicker, posterizeTime, lensDistortion, chromaticAberration, lensFlare, liquidGlass, opacityFx, colorCorrection, depthMap, gradientMap, glow, pixelDissolve, motionBlur, dropShadow, reflection, colorama, outline, echo, flutedGlass, lightRays, halftone, datamosh, roughenEdges, filmStock, halation, starGlow, filmDamage, lightLeak, thermal, colorBalance, duotone, levels, monochrome, channelMixer, dither, threshold, lensBlur, directionalBlur, spinBlur, zoomBlur, sharpen, cameraShake, bulge, twirl, ripple, waveWarp, polarCoords, turbulentDisplace, elasticGrid, gridSplit, cubify, glitch, vhs, ntsc, crtScreen, ledScreen, rgbSplit, jpegGlitch, ascii, macpaint, modulation, stripe, risograph, emboss, bevel, inkBleed, paperTexture, paperCutout, crossHatch, scatter, blobTracker, edgeGlow, pageTurn, lightSweep, deepGlow, twister, fill, grid, repeater, plus transform, layer3d, model3d and showcase. Call describe_effect with a type for its parameters, their ranges and what they do before setting anything but the obvious. An unknown name comes back with the full list."
|
|
21071
|
+
description: "Effect type: blur, invert, hue, saturation, brightness, contrast, exposure, grayscale, sepia, gradientMap, vignette, filmGrain, flicker, posterizeTime, lensDistortion, chromaticAberration, lensFlare, liquidGlass, opacityFx, colorCorrection, depthMap, gradientMap, vegas, glow, pixelDissolve, motionBlur, dropShadow, reflection, colorama, outline, echo, flutedGlass, lightRays, halftone, datamosh, roughenEdges, filmStock, halation, starGlow, filmDamage, lightLeak, thermal, colorBalance, duotone, levels, monochrome, channelMixer, dither, threshold, fourColorGradient, lensBlur, boxBlur, directionalBlur, spinBlur, zoomBlur, sharpen, cameraShake, bulge, twirl, ripple, waveWarp, polarCoords, turbulentDisplace, elasticGrid, gridSplit, cubify, glitch, vhs, ntsc, crtScreen, ledScreen, rgbSplit, jpegGlitch, ascii, macpaint, modulation, stripe, risograph, emboss, bevel, inkBleed, paperTexture, paperCutout, crossHatch, scatter, blobTracker, edgeGlow, pageTurn, lightSweep, deepGlow, twister, fill, compositeOriginal, grid, repeater, plus transform, layer3d, model3d and showcase. Call describe_effect with a type for its parameters, their ranges and what they do before setting anything but the obvious. An unknown name comes back with the full list."
|
|
21063
21072
|
},
|
|
21064
21073
|
params: {
|
|
21065
21074
|
type: "object",
|
|
@@ -21575,7 +21584,7 @@ var BASE_TOOLS = [
|
|
|
21575
21584
|
},
|
|
21576
21585
|
{
|
|
21577
21586
|
name: "studio_tasks",
|
|
21578
|
-
description: 'The work GoatEdit Studio has for you in this project. Studio makes a video in stages (brief, research, script, breakdown (the script cut into parts), moodboard, styleGuide (the design language every part follows), storyboard, edit plan, combine (the parts joined into the final edit plan), timeline, mix, QC, export, plus any the user added, whose ids start "x-" and whose document is {"notes": string, "points"?: string[]}); a stage opens once the stages it reads are approved, so several are often open at once. Each task is kind "write" (write that stage\'s JSON document: follow `role` as your system prompt, read `inputs`, follow `lessons` when present (what this user has asked for before), and if `previousDraft` is there, revise it using `note` and `problems`) or kind "run" (ask the tab to do it with studio_run_stage). Open tasks in one run do not depend on each other: hand each to its own subagent and do them side by side. When a task names an `agent`, the user wants that subagent or skill of yours on it: hand the task to the subagent with that name, or use the skill with that name. In a batch of reels each run has `batch` (reel number, name, avatar); stages listed in batch.filled are filled by Studio itself (the locked script, the pilot\'s look), so leave them. For each write task: studio_claim it first (the person sees your agent working on that stage), then studio_submit the document. The reply to a submit names the stages it opened; call studio_tasks again for them. Stages waiting for the person are listed under waitingForPerson \u2014 stop there and tell the user to approve them in the Studio panel.',
|
|
21587
|
+
description: 'The work GoatEdit Studio has for you in this project. Studio makes a video in stages (brief, research, script, breakdown (the script cut into parts), moodboard, styleGuide (the design language every part follows), storyboard, edit plan, combine (the parts joined into the final edit plan), timeline, mix, QC, export, plus any the user added, whose ids start "x-" and whose document is {"notes": string, "points"?: string[]}); a stage opens once the stages it reads are approved, so several are often open at once. Each task is kind "write" (write that stage\'s JSON document: follow `role` as your system prompt, read `inputs`, follow `lessons` when present (what this user has asked for before), and if `previousDraft` is there, revise it using `note` and `problems`) or kind "run" (ask the tab to do it with studio_run_stage). Open tasks in one run do not depend on each other: hand each to its own subagent and do them side by side. When a task names an `agent`, the user wants that subagent or skill of yours on it: hand the task to the subagent with that name, or use the skill with that name. In a batch of reels each run has `batch` (reel number, name, avatar); stages listed in batch.filled are filled by Studio itself (the locked script, the pilot\'s look), so leave them. For each write task: studio_claim it first (the person sees your agent working on that stage), then studio_submit the document. The reply to a submit names the stages it opened; call studio_tasks again for them. Stages waiting for the person are listed under waitingForPerson \u2014 stop there and tell the user to approve them in the Studio panel, unless the user told you to approve them yourself (then studio_approve).',
|
|
21579
21588
|
inputSchema: {
|
|
21580
21589
|
type: "object",
|
|
21581
21590
|
properties: {
|
|
@@ -21608,12 +21617,61 @@ var BASE_TOOLS = [
|
|
|
21608
21617
|
runId: str("The run, from studio_tasks."),
|
|
21609
21618
|
stage: str("The stage id."),
|
|
21610
21619
|
document: { type: "object", description: "The stage's document, in the shape its role card gives." },
|
|
21611
|
-
agent: str("Who wrote it, as in studio_claim.")
|
|
21620
|
+
agent: str("Who wrote it, as in studio_claim."),
|
|
21621
|
+
part: str("For a stage written part by part (the task lists `parts`): the part id. The document then holds only that part's beats (storyboard) or scenes (edit plan), and the part is checked and shown in the Studio gallery on its own.")
|
|
21612
21622
|
},
|
|
21613
21623
|
required: ["runId", "stage", "document"]
|
|
21614
21624
|
},
|
|
21615
21625
|
method: "studioSubmit"
|
|
21616
21626
|
},
|
|
21627
|
+
{
|
|
21628
|
+
name: "studio_approve",
|
|
21629
|
+
description: "Approve a Studio stage that is waiting for the person (waitingForPerson in studio_tasks), on their behalf. Only when the user told you to approve it, or to run Studio on their own without stopping: otherwise tell them it is waiting for them in the Studio panel. personSaid keeps what they told you in the run's log, so the panel shows who approved it and why. A stage with rival drafts needs pick; a stage written part by part approves every part waiting. The reply names the stages that opened.",
|
|
21630
|
+
inputSchema: {
|
|
21631
|
+
type: "object",
|
|
21632
|
+
properties: {
|
|
21633
|
+
runId: str("The run, from studio_tasks."),
|
|
21634
|
+
stage: str("The stage id."),
|
|
21635
|
+
agent: str('Who is approving, shown in the log ("Claude Code").'),
|
|
21636
|
+
personSaid: str(`The user's words that let you approve it, e.g. "do everything by yourself".`),
|
|
21637
|
+
pick: num("With rival drafts: which one, 0-based.")
|
|
21638
|
+
},
|
|
21639
|
+
required: ["runId", "stage"]
|
|
21640
|
+
},
|
|
21641
|
+
method: "studioApprove"
|
|
21642
|
+
},
|
|
21643
|
+
{
|
|
21644
|
+
name: "studio_send_back",
|
|
21645
|
+
description: "Send a Studio stage in review back to whoever writes it, with what to change; it opens again with the note. Use it when a draft you are reviewing for the user is not good enough.",
|
|
21646
|
+
inputSchema: {
|
|
21647
|
+
type: "object",
|
|
21648
|
+
properties: {
|
|
21649
|
+
runId: str("The run, from studio_tasks."),
|
|
21650
|
+
stage: str("The stage id."),
|
|
21651
|
+
note: str("What to change.")
|
|
21652
|
+
},
|
|
21653
|
+
required: ["runId", "stage", "note"]
|
|
21654
|
+
},
|
|
21655
|
+
method: "studioSendBack"
|
|
21656
|
+
},
|
|
21657
|
+
{
|
|
21658
|
+
name: "studio_update_run",
|
|
21659
|
+
description: `Change a Studio run under way, for the stages still to come (approved, left-out or running stages keep theirs): who writes each stage and who approves it (the same settings as studio_save_workflow; brief, moodboard, styleGuide and export stay approved by the person), and editSequenceId: a sequence the person already edited, for the timeline and qc stages to restyle in place instead of building a new one. With editSequenceId set, timeline and qc can take writer "outside": you edit that sequence over MCP and studio_submit the stage's document. null for editSequenceId goes back to a new sequence.`,
|
|
21660
|
+
inputSchema: {
|
|
21661
|
+
type: "object",
|
|
21662
|
+
properties: {
|
|
21663
|
+
runId: str("The run, from studio_tasks."),
|
|
21664
|
+
stages: {
|
|
21665
|
+
type: "object",
|
|
21666
|
+
description: 'Stage id to { writer?, approver?: "person" | "auto", agent?, instructions?, tier?, review?, enabled? }.',
|
|
21667
|
+
additionalProperties: { type: "object" }
|
|
21668
|
+
},
|
|
21669
|
+
editSequenceId: { type: ["string", "null"], description: "A sequence id from list_sequences, or null." }
|
|
21670
|
+
},
|
|
21671
|
+
required: ["runId"]
|
|
21672
|
+
},
|
|
21673
|
+
method: "studioUpdateRun"
|
|
21674
|
+
},
|
|
21617
21675
|
{
|
|
21618
21676
|
name: "studio_run_stage",
|
|
21619
21677
|
description: `Start a Studio stage the tab does itself: "timeline" (build the edit from the approved plan) or "qc" (check it), or a stage the workflow gives to Studio's agent in the tab. Returns at once; the work goes on in the tab and the panel shows it. Poll studio_tasks to see it finish.`,
|
|
@@ -21748,8 +21806,18 @@ var SEQUENCE_EDITS = /* @__PURE__ */ new Set([
|
|
|
21748
21806
|
"setAudioMaster",
|
|
21749
21807
|
"loopClip"
|
|
21750
21808
|
]);
|
|
21809
|
+
var SEQUENCE_READS = /* @__PURE__ */ new Set([
|
|
21810
|
+
"getTimeline",
|
|
21811
|
+
"getClips",
|
|
21812
|
+
"renderFrame",
|
|
21813
|
+
"lintTimeline",
|
|
21814
|
+
"lintMotion",
|
|
21815
|
+
"describeMotion",
|
|
21816
|
+
"listCuts",
|
|
21817
|
+
"exportRange"
|
|
21818
|
+
]);
|
|
21751
21819
|
var EXPECTED_SEQUENCE = str(
|
|
21752
|
-
"Optional
|
|
21820
|
+
"Optional: the sequence id (from list_sequences) this call reads or edits. It does not need to be open: the edit lands in that sequence and the tab stays on whatever sequence the person is looking at, so several agents can each work on their own sequence at once. Without it, the call acts on the open sequence."
|
|
21753
21821
|
);
|
|
21754
21822
|
var PLACING_EDITS = /* @__PURE__ */ new Set([
|
|
21755
21823
|
"addClip",
|
|
@@ -21776,7 +21844,7 @@ var NEW_TRACK_ABOVE = str(
|
|
|
21776
21844
|
);
|
|
21777
21845
|
var NEW_TRACK_BELOW = str('With trackId "__new_track__": put the new track directly below this video track.');
|
|
21778
21846
|
var TOOLS = BASE_TOOLS.map((tool) => {
|
|
21779
|
-
if (!tool.method || !SEQUENCE_EDITS.has(tool.method)) return tool;
|
|
21847
|
+
if (!tool.method || !(SEQUENCE_EDITS.has(tool.method) || SEQUENCE_READS.has(tool.method))) return tool;
|
|
21780
21848
|
return {
|
|
21781
21849
|
...tool,
|
|
21782
21850
|
inputSchema: {
|
|
@@ -21935,6 +22003,11 @@ function withRunProject(stepArgs, projectId) {
|
|
|
21935
22003
|
if (typeof projectId !== "string" || !projectId || typeof stepArgs.projectId === "string") return stepArgs;
|
|
21936
22004
|
return { ...stepArgs, projectId };
|
|
21937
22005
|
}
|
|
22006
|
+
function withRunSequence(stepArgs, sequenceId, tool) {
|
|
22007
|
+
if (typeof sequenceId !== "string" || !sequenceId || typeof stepArgs.expectedSequenceId === "string") return stepArgs;
|
|
22008
|
+
if (!tool || !("expectedSequenceId" in (tool.inputSchema.properties ?? {}))) return stepArgs;
|
|
22009
|
+
return { ...stepArgs, expectedSequenceId: sequenceId };
|
|
22010
|
+
}
|
|
21938
22011
|
|
|
21939
22012
|
// src/tab-registry.ts
|
|
21940
22013
|
function indexTabs(reports, isOpen) {
|
|
@@ -21945,6 +22018,23 @@ function indexTabs(reports, isOpen) {
|
|
|
21945
22018
|
return index;
|
|
21946
22019
|
}
|
|
21947
22020
|
|
|
22021
|
+
// src/open-project.ts
|
|
22022
|
+
var DEFAULT_EDITOR = "https://ai.goatedit.com";
|
|
22023
|
+
function editorUrl(origin, projectId) {
|
|
22024
|
+
const url2 = new URL(origin || DEFAULT_EDITOR);
|
|
22025
|
+
url2.pathname = "/";
|
|
22026
|
+
url2.search = "";
|
|
22027
|
+
url2.hash = "";
|
|
22028
|
+
url2.searchParams.set("project", projectId);
|
|
22029
|
+
url2.searchParams.set("via", "agent");
|
|
22030
|
+
return url2.toString();
|
|
22031
|
+
}
|
|
22032
|
+
function openCommand(platform, url2) {
|
|
22033
|
+
if (platform === "darwin") return ["open", [url2]];
|
|
22034
|
+
if (platform === "win32") return ["cmd", ["/c", "start", "", url2]];
|
|
22035
|
+
return ["xdg-open", [url2]];
|
|
22036
|
+
}
|
|
22037
|
+
|
|
21948
22038
|
// node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/client.js
|
|
21949
22039
|
var ExperimentalClientTasks = class {
|
|
21950
22040
|
constructor(_client) {
|
|
@@ -24444,7 +24534,7 @@ var VERSION = (() => {
|
|
|
24444
24534
|
}
|
|
24445
24535
|
return "0.0.0";
|
|
24446
24536
|
})();
|
|
24447
|
-
var INSTRUCTIONS = `Edits a GoatEdit video project live in the user's browser tab at ai.goatedit.com. At the start of each new request from the user, call begin_request with the kind of edit, its style words and any reference videos, then get_style_profile for how this user edits; treat that style as defaults, the request wins. Call get_timeline before your first edit \u2014 clip ids change after every split, trim or delete, and a stale id is rejected. Each edit's reply carries timelineChanges (clips added, with their ids and placement; clips changed; ids removed), so take the next ids from there instead of reading the timeline again. get_timeline is lean by default; pass detail: "full" only when you need effect parameters, and trackId or from/to to read part of it. Several edits in a row go faster as one run_tools call. With more than one tab open, call list_connected_projects, then use_project to pick one. To work on several projects at once (one helper agent per video), do not use use_project \u2014 it moves every caller \u2014 but pass projectId on each call, or once on run_tools for all its steps. render_preview_frame and preview_media accept saveToDisk: true, which writes the frame to a file and returns its path instead of the image. If a tool reports the editor is not connected, ask the user to open ai.goatedit.com and switch on Local in the AI status menu.`;
|
|
24537
|
+
var INSTRUCTIONS = `Edits a GoatEdit video project live in the user's browser tab at ai.goatedit.com. At the start of each new request from the user, call begin_request with the kind of edit, its style words and any reference videos, then get_style_profile for how this user edits; treat that style as defaults, the request wins. Call get_timeline before your first edit \u2014 clip ids change after every split, trim or delete, and a stale id is rejected. Each edit's reply carries timelineChanges (clips added, with their ids and placement; clips changed; ids removed), so take the next ids from there instead of reading the timeline again. get_timeline is lean by default; pass detail: "full" only when you need effect parameters, and trackId or from/to to read part of it. Several edits in a row go faster as one run_tools call. With more than one tab open, call list_connected_projects, then use_project to pick one. To work on a project that is not open, find it with list_projects and call open_project. To work on several projects at once (one helper agent per video), do not use use_project \u2014 it moves every caller \u2014 but pass projectId on each call, or once on run_tools for all its steps. To read or edit a sequence other than the open one, do not call open_sequence \u2014 it moves the user's view \u2014 but pass expectedSequenceId on each call, or once on run_tools; the edit lands in that sequence while the user keeps working wherever they are. render_preview_frame and preview_media accept saveToDisk: true, which writes the frame to a file and returns its path instead of the image. If a tool reports the editor is not connected, ask the user to open ai.goatedit.com and switch on Local in the AI status menu.`;
|
|
24448
24538
|
var MEDIA_TYPES = {
|
|
24449
24539
|
".mp4": { mime: "video/mp4", kind: "video" },
|
|
24450
24540
|
".m4v": { mime: "video/mp4", kind: "video" },
|
|
@@ -24701,6 +24791,8 @@ wss.on("error", () => {
|
|
|
24701
24791
|
});
|
|
24702
24792
|
var tabs = /* @__PURE__ */ new Map();
|
|
24703
24793
|
var tabReports = /* @__PURE__ */ new Map();
|
|
24794
|
+
var tabOrigins = /* @__PURE__ */ new WeakMap();
|
|
24795
|
+
var lastEditorOrigin = process.env.GOATEDIT_EDITOR_URL || null;
|
|
24704
24796
|
function reindexTabs() {
|
|
24705
24797
|
tabs.clear();
|
|
24706
24798
|
for (const [pid, r] of indexTabs(tabReports.values(), (s) => s.readyState === import_websocket.default.OPEN)) {
|
|
@@ -24809,6 +24901,10 @@ wss.on("connection", (ws, req) => {
|
|
|
24809
24901
|
return;
|
|
24810
24902
|
}
|
|
24811
24903
|
console.error("[GoatEdit MCP] Browser editor connected via WebSocket");
|
|
24904
|
+
if (req.headers.origin) {
|
|
24905
|
+
tabOrigins.set(ws, req.headers.origin);
|
|
24906
|
+
lastEditorOrigin = req.headers.origin;
|
|
24907
|
+
}
|
|
24812
24908
|
ws.on("message", (data) => {
|
|
24813
24909
|
let message;
|
|
24814
24910
|
try {
|
|
@@ -24968,8 +25064,31 @@ var LOCAL_HANDLERS = {
|
|
|
24968
25064
|
list_connected_projects: async () => connectedProjects(),
|
|
24969
25065
|
list_local_assets: async (args) => handleListLocalAssets(args),
|
|
24970
25066
|
generate_voiceover: async (args, projectId) => handleGenerateVoiceover(args.text, projectId),
|
|
24971
|
-
find_local_file: async (args) => handleFindLocalFile(args)
|
|
25067
|
+
find_local_file: async (args) => handleFindLocalFile(args),
|
|
25068
|
+
open_project: async (args) => handleOpenProject(args)
|
|
24972
25069
|
};
|
|
25070
|
+
var OPEN_WAIT_MS = 45e3;
|
|
25071
|
+
async function handleOpenProject(args) {
|
|
25072
|
+
const projectId = typeof args?.projectId === "string" ? args.projectId.trim() : "";
|
|
25073
|
+
if (!projectId) throw new Error("Missing required argument: projectId (from list_projects).");
|
|
25074
|
+
const open = tabs.get(projectId);
|
|
25075
|
+
if (open && open.ws.readyState === import_websocket.default.OPEN) return { projectId, name: open.projectName, alreadyOpen: true };
|
|
25076
|
+
const origin = [...tabReports.keys()].map((ws) => tabOrigins.get(ws)).find(Boolean) ?? lastEditorOrigin;
|
|
25077
|
+
const url2 = editorUrl(origin, projectId);
|
|
25078
|
+
const [cmd, cmdArgs] = openCommand(process.platform, url2);
|
|
25079
|
+
await new Promise((resolve, reject) => {
|
|
25080
|
+
execFile(cmd, cmdArgs, (err) => err ? reject(new Error(`Could not open the browser (${cmd}): ${err.message}. Open ${url2} by hand.`)) : resolve());
|
|
25081
|
+
});
|
|
25082
|
+
const deadline = Date.now() + OPEN_WAIT_MS;
|
|
25083
|
+
while (Date.now() < deadline) {
|
|
25084
|
+
const tab = tabs.get(projectId);
|
|
25085
|
+
if (tab && tab.ws.readyState === import_websocket.default.OPEN) return { projectId, name: tab.projectName, opened: url2 };
|
|
25086
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
25087
|
+
}
|
|
25088
|
+
throw new Error(
|
|
25089
|
+
`Opened ${url2}, but no tab reported project ${projectId} within ${OPEN_WAIT_MS / 1e3}s. The person may need to sign in, or switch on Local in the AI status menu of that tab. Check list_connected_projects again in a moment.`
|
|
25090
|
+
);
|
|
25091
|
+
}
|
|
24973
25092
|
async function callLocal(method, args, projectId) {
|
|
24974
25093
|
await ensureTransport();
|
|
24975
25094
|
if (ownsPort) return LOCAL_HANDLERS[method](args, projectId ?? void 0);
|
|
@@ -24985,6 +25104,15 @@ var LOCAL_TOOLS = [
|
|
|
24985
25104
|
description: "List the GoatEdit projects open in connected browser tabs, with which one tools act on by default.",
|
|
24986
25105
|
inputSchema: { type: "object", properties: {} }
|
|
24987
25106
|
},
|
|
25107
|
+
{
|
|
25108
|
+
name: "open_project",
|
|
25109
|
+
description: "Open a saved project (id from list_projects) in a new browser tab and wait until it connects, so you can work on it \u2014 several projects at once, one tab each, addressed with projectId. A project already open is left as it is. The tab asks the person to allow its footage folder with a popup: tell them to click Allow.",
|
|
25110
|
+
inputSchema: {
|
|
25111
|
+
type: "object",
|
|
25112
|
+
properties: { projectId: { type: "string", description: "The project to open." } },
|
|
25113
|
+
required: ["projectId"]
|
|
25114
|
+
}
|
|
25115
|
+
},
|
|
24988
25116
|
{
|
|
24989
25117
|
name: "use_project",
|
|
24990
25118
|
description: "Pick which connected project every later tool call acts on, when more than one tab is open. Ids come from list_connected_projects.",
|
|
@@ -25032,7 +25160,8 @@ var LOCAL_TOOLS = [
|
|
|
25032
25160
|
},
|
|
25033
25161
|
continueOnError: { type: "boolean", description: "Run the remaining steps after one fails." },
|
|
25034
25162
|
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." },
|
|
25035
|
-
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." }
|
|
25163
|
+
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." },
|
|
25164
|
+
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." }
|
|
25036
25165
|
},
|
|
25037
25166
|
required: ["calls"]
|
|
25038
25167
|
}
|
|
@@ -25060,6 +25189,7 @@ async function callTool(name, args) {
|
|
|
25060
25189
|
case "list_connected_projects":
|
|
25061
25190
|
case "list_local_assets":
|
|
25062
25191
|
case "generate_voiceover":
|
|
25192
|
+
case "open_project":
|
|
25063
25193
|
return callLocal(name, forwarded, projectId);
|
|
25064
25194
|
case "use_project": {
|
|
25065
25195
|
const wanted = typeof forwarded.projectId === "string" ? forwarded.projectId : projectId;
|
|
@@ -25127,7 +25257,7 @@ async function runTools(args) {
|
|
|
25127
25257
|
const tool = typeof step?.tool === "string" ? step.tool : "";
|
|
25128
25258
|
try {
|
|
25129
25259
|
const stepArgs = resolveRefs(step.args && typeof step.args === "object" ? step.args : {}, refs);
|
|
25130
|
-
const raw = await callTool(tool, withRunProject(stepArgs, args.projectId));
|
|
25260
|
+
const raw = await callTool(tool, withRunSequence(withRunProject(stepArgs, args.projectId), args.expectedSequenceId, BROWSER_TOOLS_BY_NAME.get(tool)));
|
|
25131
25261
|
if (typeof step.as === "string" && step.as) {
|
|
25132
25262
|
if (raw && typeof raw === "object" && !Array.isArray(raw)) {
|
|
25133
25263
|
const { _image, _images, ...kept } = raw;
|
package/package.json
CHANGED